diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -2302,6 +2302,32 @@ { } +static bool +bridge_learn(struct bridge_softc *sc, struct bridge_iflist *sbif, + const struct ether_header *eh, uint16_t vlan) +{ + if ((sbif->bif_flags & IFBIF_LEARNING) != 0) { + int error; + + error = bridge_rtupdate(sc, eh->ether_shost, vlan, sbif, 0, + IFBAF_DYNAMIC); + + /* + * If the interface has addresses limits then deny any source + * that is not already in the cache. + */ + if (error != 0 && sbif->bif_addrmax != 0) + return (false); + } + return (true); +} + +#ifdef INET6 +#define PFIL_HOOKED_INET6 PFIL_HOOKED_IN(V_inet6_pfil_head) +#else +#define PFIL_HOOKED_INET6 false +#endif + /* * bridge_forward: * @@ -2318,7 +2344,6 @@ struct ether_header *eh; uint16_t vlan; uint8_t *dst; - int error; NET_EPOCH_ASSERT(); @@ -2337,16 +2362,8 @@ dst = eh->ether_dhost; /* If the interface is learning, record the address. */ - if (sbif->bif_flags & IFBIF_LEARNING) { - error = bridge_rtupdate(sc, eh->ether_shost, vlan, - sbif, 0, IFBAF_DYNAMIC); - /* - * If the interface has addresses limits then deny any source - * that is not in the cache. - */ - if (error && sbif->bif_addrmax) - goto drop; - } + if (!bridge_learn(sc, sbif, eh, vlan)) + goto drop; if ((sbif->bif_flags & IFBIF_STP) != 0 && sbif->bif_stp.bp_state == BSTP_IFSTATE_LEARNING) @@ -2395,11 +2412,7 @@ ETHER_BPF_MTAP(ifp, m); /* run the packet filter */ - if (PFIL_HOOKED_IN(V_inet_pfil_head) -#ifdef INET6 - || PFIL_HOOKED_IN(V_inet6_pfil_head) -#endif - ) { + if (PFIL_HOOKED_IN(V_inet_pfil_head) || PFIL_HOOKED_INET6) { if (bridge_pfil(&m, ifp, src_if, PFIL_IN) != 0) return; if (m == NULL) @@ -2431,11 +2444,7 @@ dbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) goto drop; - if (PFIL_HOOKED_OUT(V_inet_pfil_head) -#ifdef INET6 - || PFIL_HOOKED_OUT(V_inet6_pfil_head) -#endif - ) { + if (PFIL_HOOKED_OUT(V_inet_pfil_head) || PFIL_HOOKED_INET6) { if (bridge_pfil(&m, ifp, dst_if, PFIL_OUT) != 0) return; if (m == NULL) @@ -2449,6 +2458,46 @@ m_freem(m); } +/* + * Consume the input packet from sifp destined to ifp. + */ +static inline struct mbuf * +bridge_grab(struct bridge_softc *sc, struct ifnet *sifp, struct ifnet *ifp, + struct bridge_iflist *sbif, struct mbuf *m, uint16_t vlan) +{ + struct ifnet *bifp; + + if (!bridge_learn(sc, sbif, mtod(m, struct ether_header *), vlan)) { + m_freem(m); + return (NULL); + } + m->m_pkthdr.rcvif = ifp; + if (sifp == ifp) { + /* Skip bridge processing... src == dest */ + return (m); + } + + /* It's passing over or to the bridge, locally. */ + bifp = sc->sc_ifp; + ETHER_BPF_MTAP(bifp, m); + if_inc_counter(bifp, IFCOUNTER_IPACKETS, 1); + if_inc_counter(bifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); + + /* Filter on the physical interface. */ + if (V_pfil_local_phys && (PFIL_HOOKED_IN(V_inet_pfil_head) || + PFIL_HOOKED_INET6)) { + if (bridge_pfil(&m, NULL, ifp, PFIL_IN) != 0 || + m == NULL) { + return (NULL); + } + } + if (sifp != bifp) + ETHER_BPF_MTAP(sifp, m); + return (m); +} + +#undef PFIL_HOOKED_INET6 + /* * bridge_input: * @@ -2464,7 +2513,6 @@ struct ether_header *eh; struct mbuf *mc, *mc2; uint16_t vlan; - int error; NET_EPOCH_ASSERT(); @@ -2561,78 +2609,58 @@ #define CARP_CHECK_WE_ARE_SRC(iface) false #endif -#ifdef INET6 -#define PFIL_HOOKED_INET6 PFIL_HOOKED_IN(V_inet6_pfil_head) -#else -#define PFIL_HOOKED_INET6 false -#endif - -#define GRAB_OUR_PACKETS(iface) \ - if ((iface)->if_type == IFT_GIF) \ - continue; \ - /* It is destined for us. */ \ - if (memcmp(IF_LLADDR(iface), eh->ether_dhost, ETHER_ADDR_LEN) == 0 || \ - CARP_CHECK_WE_ARE_DST(iface)) { \ - if (bif->bif_flags & IFBIF_LEARNING) { \ - error = bridge_rtupdate(sc, eh->ether_shost, \ - vlan, bif, 0, IFBAF_DYNAMIC); \ - if (error && bif->bif_addrmax) { \ - m_freem(m); \ - return (NULL); \ - } \ - } \ - m->m_pkthdr.rcvif = iface; \ - if ((iface) == ifp) { \ - /* Skip bridge processing... src == dest */ \ - return (m); \ - } \ - /* It's passing over or to the bridge, locally. */ \ - ETHER_BPF_MTAP(bifp, m); \ - if_inc_counter(bifp, IFCOUNTER_IPACKETS, 1); \ - if_inc_counter(bifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); \ - /* Filter on the physical interface. */ \ - if (V_pfil_local_phys && (PFIL_HOOKED_IN(V_inet_pfil_head) || \ - PFIL_HOOKED_INET6)) { \ - if (bridge_pfil(&m, NULL, ifp, \ - PFIL_IN) != 0 || m == NULL) { \ - return (NULL); \ - } \ - } \ - if ((iface) != bifp) \ - ETHER_BPF_MTAP(iface, m); \ - return (m); \ - } \ - \ - /* We just received a packet that we sent out. */ \ - if (memcmp(IF_LLADDR(iface), eh->ether_shost, ETHER_ADDR_LEN) == 0 || \ - CARP_CHECK_WE_ARE_SRC(iface)) { \ - m_freem(m); \ - return (NULL); \ - } +#define PACKET_IS_FOR(iface) \ + (memcmp(if_getlladdr(iface), eh->ether_dhost, ETHER_ADDR_LEN) == 0 || \ + CARP_CHECK_WE_ARE_DST(iface)) +#define PACKET_IS_FROM(iface) \ + (memcmp(if_getlladdr(iface), eh->ether_shost, ETHER_ADDR_LEN) == 0 || \ + CARP_CHECK_WE_ARE_SRC(iface)) /* * Unicast. Make sure it's not for the bridge. */ - do { GRAB_OUR_PACKETS(bifp) } while (0); + if (PACKET_IS_FOR(bifp)) + return (bridge_grab(sc, ifp, bifp, bif, m, vlan)); + if (PACKET_IS_FROM(bifp)) { + m_freem(m); + return (NULL); + } /* - * Give a chance for ifp at first priority. This will help when the - * packet comes through the interface like VLAN's with the same MACs - * on several interfaces from the same bridge. This also will save - * some CPU cycles in case the destination interface and the input - * interface (eq ifp) are the same. + * Give a chance for ifp (the source interface) at first priority. This + * will help when the packet comes through the interface like VLAN's + * with the same MACs on several interfaces from the same bridge. This + * also will save some CPU cycles in case the destination interface and + * the input interface (eq ifp) are the same. */ - do { GRAB_OUR_PACKETS(ifp) } while (0); + if (if_gettype(ifp) != IFT_GIF) { + if (PACKET_IS_FOR(ifp)) + return (bridge_grab(sc, ifp, ifp, bif, m, vlan)); + if (PACKET_IS_FROM(ifp)) { + m_freem(m); + return (NULL); + } + } /* Now check the all bridge members. */ CK_LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) { - GRAB_OUR_PACKETS(bif2->bif_ifp) + struct ifnet *mifp; + + mifp = bif2->bif_ifp; + if (if_gettype(mifp) == IFT_GIF) + continue; + if (PACKET_IS_FOR(bif2->bif_ifp)) + return (bridge_grab(sc, ifp, mifp, bif, m, vlan)); + if (PACKET_IS_FROM(mifp)) { + m_freem(m); + return (NULL); + } } -#undef OR_CARP_CHECK_WE_ARE_DST -#undef OR_CARP_CHECK_WE_ARE_SRC -#undef OR_PFIL_HOOKED_INET6 -#undef GRAB_OUR_PACKETS +#undef CARP_CHECK_WE_ARE_DST +#undef CARP_CHECK_WE_ARE_SRC +#undef PACKET_IS_FOR +#undef PACKET_IS_FROM /* Perform the bridge forwarding function. */ bridge_forward(sc, bif, m);