From 10c5c9874c7dec1a5147783005934d9e6a5d4ad6 Mon Sep 17 00:00:00 2001 From: ozaki-r Date: Wed, 18 Jun 2014 10:51:03 +0000 Subject: [PATCH] Restructure bridge_input and bridge_broadcast There are two changes: - Assemble the places calling pktq_enqueue (bridge_forward) for unicast and {b,m}cast frames into one - Receive {b,m}cast frames in bridge_broadcast, not in bridge_input The changes make the code clear and readable. bridge_input now doesn't need to take care of {b,m}cast frames; bridge_forward and bridge_broadcast have the responsibility. The changes are based on a patch of Lloyd Parkes submitted in PR 48104, but don't fix its issue yet. --- sys/net/if_bridge.c | 97 +++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 56 deletions(-) diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 2d5b6430c85b..42c01248ffe7 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_bridge.c,v 1.82 2014/06/18 09:20:46 ozaki-r Exp $ */ +/* $NetBSD: if_bridge.c,v 1.83 2014/06/18 10:51:03 ozaki-r Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. @@ -80,7 +80,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.82 2014/06/18 09:20:46 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_bridge.c,v 1.83 2014/06/18 10:51:03 ozaki-r Exp $"); #ifdef _KERNEL_OPT #include "opt_bridge_ipf.h" @@ -1612,7 +1612,6 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) struct bridge_softc *sc = ifp->if_bridge; struct bridge_iflist *bif; struct ether_header *eh; - struct mbuf *mc; if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) { ether_input(ifp, m); @@ -1635,68 +1634,50 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) m->m_flags |= M_MCAST; } - if (m->m_flags & (M_BCAST|M_MCAST)) { - if (bif->bif_flags & IFBIF_STP) { - /* Tap off 802.1D packets; they do not get forwarded. */ - if (memcmp(eh->ether_dhost, bstp_etheraddr, - ETHER_ADDR_LEN) == 0) { - bstp_input(sc, bif, m); + /* + * A 'fast' path for packets addressed to interfaces that are + * part of this bridge. + */ + if (!(m->m_flags & (M_BCAST|M_MCAST)) && + !bstp_state_before_learning(bif)) { + struct bridge_iflist *_bif; + + LIST_FOREACH(_bif, &sc->sc_iflist, bif_next) { + /* It is destined for us. */ + if (bridge_ourether(_bif, eh, 0)) { + if (_bif->bif_flags & IFBIF_LEARNING) + (void) bridge_rtupdate(sc, + eh->ether_shost, ifp, 0, IFBAF_DYNAMIC); + m->m_pkthdr.rcvif = _bif->bif_ifp; + ether_input(_bif->bif_ifp, m); return; } - if (bstp_state_before_learning(bif)) { - ether_input(ifp, m); + /* We just received a packet that we sent out. */ + if (bridge_ourether(_bif, eh, 1)) { + m_freem(m); return; } } + } - /* - * Make a deep copy of the packet and enqueue the copy - * for bridge processing; return the original packet for - * local processing. - */ - mc = m_dup(m, 0, M_COPYALL, M_NOWAIT); - if (mc == NULL) { - ether_input(ifp, m); - return; - } - - /* Perform the bridge forwarding function with the copy. */ - if (__predict_false(!pktq_enqueue(sc->sc_fwd_pktq, mc, 0))) - m_freem(mc); - - /* For local processing. */ - ether_input(ifp, m); + /* Tap off 802.1D packets; they do not get forwarded. */ + if (bif->bif_flags & IFBIF_STP && + memcmp(eh->ether_dhost, bstp_etheraddr, ETHER_ADDR_LEN) == 0) { + bstp_input(sc, bif, m); return; } + /* + * A normal switch would discard the packet here, but that's not what + * we've done historically. This also prevents some obnoxious behaviour. + */ if (bstp_state_before_learning(bif)) { ether_input(ifp, m); return; } - /* - * Unicast. Make sure it's not for us. - */ - LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { - /* It is destined for us. */ - if (bridge_ourether(bif, eh, 0)) { - if (bif->bif_flags & IFBIF_LEARNING) - (void) bridge_rtupdate(sc, - eh->ether_shost, ifp, 0, IFBAF_DYNAMIC); - m->m_pkthdr.rcvif = bif->bif_ifp; - ether_input(bif->bif_ifp, m); - return; - } - - /* We just received a packet that we sent out. */ - if (bridge_ourether(bif, eh, 1)) { - m_freem(m); - return; - } - } - - /* Perform the bridge forwarding function. */ + /* Queue the packet for bridge forwarding. */ if (__predict_false(!pktq_enqueue(sc->sc_fwd_pktq, m, 0))) m_freem(m); } @@ -1715,7 +1696,9 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, struct bridge_iflist *bif; struct mbuf *mc; struct ifnet *dst_if; - int used = 0; + bool used, bmcast; + + used = bmcast = m->m_flags & (M_BCAST|M_MCAST); LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { dst_if = bif->bif_ifp; @@ -1730,16 +1713,15 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, } } - if ((bif->bif_flags & IFBIF_DISCOVER) == 0 && - (m->m_flags & (M_BCAST|M_MCAST)) == 0) + if ((bif->bif_flags & IFBIF_DISCOVER) == 0 && !bmcast) continue; if ((dst_if->if_flags & IFF_RUNNING) == 0) continue; - if (LIST_NEXT(bif, bif_next) == NULL) { + if (!used && LIST_NEXT(bif, bif_next) == NULL) { mc = m; - used = 1; + used = true; } else { mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT); if (mc == NULL) { @@ -1750,7 +1732,10 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, bridge_enqueue(sc, dst_if, mc, 1); } - if (used == 0) + + if (bmcast) + ether_input(src_if, m); + else if (!used) m_freem(m); }