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.
This commit is contained in:
ozaki-r 2014-06-18 10:51:03 +00:00
parent 55d6e53ccb
commit 10c5c9874c
1 changed files with 41 additions and 56 deletions

View File

@ -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 <sys/cdefs.h>
__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);
}