diff options
Diffstat (limited to 'usr/src/uts/common/io/bridge.c')
-rw-r--r-- | usr/src/uts/common/io/bridge.c | 192 |
1 files changed, 149 insertions, 43 deletions
diff --git a/usr/src/uts/common/io/bridge.c b/usr/src/uts/common/io/bridge.c index bc54527515..375d166972 100644 --- a/usr/src/uts/common/io/bridge.c +++ b/usr/src/uts/common/io/bridge.c @@ -23,6 +23,7 @@ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright (c) 2016 by Delphix. All rights reserved. + * Copyright 2018 Joyent, Inc. */ /* @@ -41,6 +42,7 @@ #include <sys/modctl.h> #include <sys/note.h> #include <sys/param.h> +#include <sys/pattr.h> #include <sys/policy.h> #include <sys/sdt.h> #include <sys/stat.h> @@ -1693,7 +1695,8 @@ bridge_learn(bridge_link_t *blp, const uint8_t *saddr, uint16_t ingress_nick, * The passed-in tci is the "impossible" value 0xFFFF when no tag is present. */ static mblk_t * -reform_vlan_header(mblk_t *mp, uint16_t vlanid, uint16_t tci, uint16_t pvid) +reform_vlan_header(mblk_t *mp, uint16_t vlanid, uint16_t tci, uint16_t pvid, + boolean_t keep_flags) { boolean_t source_has_tag = (tci != 0xFFFF); mblk_t *mpcopy; @@ -1705,8 +1708,13 @@ reform_vlan_header(mblk_t *mp, uint16_t vlanid, uint16_t tci, uint16_t pvid) if (mp == NULL) return (mp); - /* No forwarded packet can have hardware checksum enabled */ - DB_CKSUMFLAGS(mp) = 0; + /* + * A forwarded packet cannot have HW offloads enabled unless + * the destination is known to be local to the host and HW + * offloads haven't been emulated. + */ + if (!keep_flags) + DB_CKSUMFLAGS(mp) = 0; /* Get the no-modification cases out of the way first */ if (!source_has_tag && vlanid == pvid) /* 1a */ @@ -1907,17 +1915,46 @@ bridge_forward(bridge_link_t *blp, mac_header_info_t *hdr_info, mblk_t *mp, blp->bl_trillthreads++; mutex_exit(&blp->bl_trilllock); update_header(mp, hdr_info, B_FALSE); - if (is_xmit) - mp = mac_fix_cksum(mp); - /* all trill data frames have Inner.VLAN */ - mp = reform_vlan_header(mp, vlanid, tci, 0); - if (mp == NULL) { - KIINCR(bki_drops); - fwd_unref(bfp); - return (NULL); + + if (is_xmit) { + mac_hw_emul(&mp, NULL, NULL, + MAC_HWCKSUM_EMUL | MAC_LSO_EMUL); + + if (mp == NULL) { + KIINCR(bki_drops); + goto done; + } } - trill_encap_fn(tdp, blp, hdr_info, mp, - bfp->bf_trill_nick); + + while (mp != NULL) { + mblk_t *next = mp->b_next; + + mp->b_next = NULL; + + /* + * All trill data frames have + * Inner.VLAN. + */ + mp = reform_vlan_header(mp, vlanid, tci, + 0, B_FALSE); + + if (mp == NULL) { + /* + * Make sure to free + * any remaining + * segments. + */ + freemsgchain(next); + KIINCR(bki_drops); + goto done; + } + + trill_encap_fn(tdp, blp, hdr_info, mp, + bfp->bf_trill_nick); + mp = next; + } + +done: mutex_enter(&blp->bl_trilllock); if (--blp->bl_trillthreads == 0 && blp->bl_trilldata == NULL) @@ -1959,31 +1996,68 @@ bridge_forward(bridge_link_t *blp, mac_header_info_t *hdr_info, mblk_t *mp, mpsend = copymsg(mp); } - if (!from_trill && is_xmit) - mpsend = mac_fix_cksum(mpsend); + /* + * If the destination is not local to the host + * then we need to emulate HW offloads because + * we can't guarantee the forwarding + * destination provides them. + */ + if (!from_trill && is_xmit && + !(bfp->bf_flags & BFF_LOCALADDR)) { + mac_hw_emul(&mpsend, NULL, NULL, + MAC_HWCKSUM_EMUL | MAC_LSO_EMUL); - mpsend = reform_vlan_header(mpsend, vlanid, tci, - blpsend->bl_pvid); - if (mpsend == NULL) { - KIINCR(bki_drops); - continue; + if (mpsend == NULL) { + KIINCR(bki_drops); + continue; + } + } + + /* + * The HW emulation above may have segmented + * an LSO mblk. + */ + while ((mpsend != NULL) && + !(bfp->bf_flags & BFF_LOCALADDR)) { + mblk_t *next = mpsend->b_next; + + mpsend->b_next = NULL; + mpsend = reform_vlan_header(mpsend, vlanid, tci, + blpsend->bl_pvid, B_FALSE); + + if (mpsend == NULL) { + KIINCR(bki_drops); + mpsend = next; + continue; + } + + KIINCR(bki_forwards); + KLPINCR(blpsend, bkl_xmit); + MAC_RING_TX(blpsend->bl_mh, NULL, mpsend, + mpsend); + freemsg(mpsend); + mpsend = next; } - KIINCR(bki_forwards); /* * No need to bump up the link reference count, as * the forwarding entry itself holds a reference to * the link. */ if (bfp->bf_flags & BFF_LOCALADDR) { + mpsend = reform_vlan_header(mpsend, vlanid, tci, + blpsend->bl_pvid, B_TRUE); + + if (mpsend == NULL) { + KIINCR(bki_drops); + continue; + } + + KIINCR(bki_forwards); mac_rx_common(blpsend->bl_mh, NULL, mpsend); - } else { - KLPINCR(blpsend, bkl_xmit); - MAC_RING_TX(blpsend->bl_mh, NULL, mpsend, - mpsend); - freemsg(mpsend); } } + /* * Handle a special case: if we're transmitting to the original * link, then check whether the localaddr flag is set. If it @@ -2019,7 +2093,7 @@ bridge_forward(bridge_link_t *blp, mac_header_info_t *hdr_info, mblk_t *mp, * Inner.VLAN */ mpsend = reform_vlan_header(mpsend, - vlanid, tci, 0); + vlanid, tci, 0, B_FALSE); if (mpsend == NULL) { KIINCR(bki_drops); } else { @@ -2070,25 +2144,57 @@ bridge_forward(bridge_link_t *blp, mac_header_info_t *hdr_info, mblk_t *mp, mpsend = copymsg(mp); } - if (!from_trill && is_xmit) - mpsend = mac_fix_cksum(mpsend); + /* + * In this case, send to all links connected + * to the bridge. Some of these destinations + * may not provide HW offload -- so just + * emulate it here. + */ + if (!from_trill && is_xmit) { + mac_hw_emul(&mpsend, NULL, NULL, + MAC_HWCKSUM_EMUL | MAC_LSO_EMUL); - mpsend = reform_vlan_header(mpsend, vlanid, tci, - blpsend->bl_pvid); - if (mpsend == NULL) { - KIINCR(bki_drops); - continue; + if (mpsend == NULL) { + KIINCR(bki_drops); + continue; + } + } + + /* + * The HW emulation above may have segmented + * an LSO mblk. + */ + while (mpsend != NULL) { + mblk_t *next = mpsend->b_next; + + mpsend->b_next = NULL; + mpsend = reform_vlan_header(mpsend, vlanid, tci, + blpsend->bl_pvid, B_FALSE); + + if (mpsend == NULL) { + KIINCR(bki_drops); + mpsend = next; + continue; + } + + if (hdr_info->mhi_dsttype == + MAC_ADDRTYPE_UNICAST) + KIINCR(bki_unknown); + else + KIINCR(bki_mbcast); + + KLPINCR(blpsend, bkl_xmit); + if ((mpcopy = copymsg(mpsend)) != NULL) { + mac_rx_common(blpsend->bl_mh, NULL, + mpcopy); + } + + MAC_RING_TX(blpsend->bl_mh, NULL, mpsend, + mpsend); + freemsg(mpsend); + mpsend = next; } - if (hdr_info->mhi_dsttype == MAC_ADDRTYPE_UNICAST) - KIINCR(bki_unknown); - else - KIINCR(bki_mbcast); - KLPINCR(blpsend, bkl_xmit); - if ((mpcopy = copymsg(mpsend)) != NULL) - mac_rx_common(blpsend->bl_mh, NULL, mpcopy); - MAC_RING_TX(blpsend->bl_mh, NULL, mpsend, mpsend); - freemsg(mpsend); link_unref(blpsend); } } |