Page MenuHomeFreeBSD

D51260.id158331.diff
No OneTemporary

D51260.id158331.diff

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
@@ -2715,7 +2715,6 @@
struct ifnet *src_if, *dst_if, *ifp;
struct ether_header *eh;
uint8_t *dst;
- int error;
ether_vlanid_t vlan;
NET_EPOCH_ASSERT();
@@ -2734,18 +2733,6 @@
eh = mtod(m, struct ether_header *);
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 ((sbif->bif_flags & IFBIF_STP) != 0 &&
sbif->bif_stp.bp_state == BSTP_IFSTATE_LEARNING)
goto drop;
@@ -2856,6 +2843,147 @@
m_freem(m);
}
+/*
+ * Handle a frame which is destined for the host. If a non-NULL mbuf is
+ * returned, it should be passed back to ether_input().
+ */
+static struct mbuf *
+bridge_handle_for_host(struct bridge_softc *sc, struct ifnet *ifp,
+ struct mbuf *m)
+{
+ struct ifnet *bifp;
+ ether_vlanid_t vlan;
+
+ NET_EPOCH_ASSERT();
+
+ bifp = sc->sc_ifp;
+ vlan = VLANTAGOF(m);
+
+ /* Tap the frame on the bridge interface. */
+ ETHER_BPF_MTAP(bifp, m);
+
+ if_inc_counter(bifp, IFCOUNTER_IPACKETS, 1);
+ if_inc_counter(bifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
+
+#ifdef DEV_NETMAP
+ /* Hand the packet over to netmap if necessary. */
+ if ((if_getcapenable(ifp) & IFCAP_NETMAP) != 0 &&
+ ((m)->m_flags & M_BRIDGE_INJECT) == 0) {
+ (ifp)->if_input(ifp, m);
+ return (NULL);
+ }
+#endif
+
+ /*
+ * If the packet has a VLAN tag and there's a VLAN trunk configured
+ * on the bridge, this packet is intended for an SVI, so pass it to
+ * vlan_input() to handle.
+ */
+ if (vlan != 0) {
+ if (bifp->if_vlantrunk == NULL) {
+ m_freem(m);
+ return (NULL);
+ }
+
+ (*vlan_input_p)(ifp, m);
+ return (NULL);
+ }
+
+ /*
+ * Return the frame to ether_input().
+ */
+ return (m);
+}
+
+/*
+ * Given an mbuf and the incoming interface, determine if this frame should be
+ * handler locally, and if so, handle it. Returns true if the frame was local.
+ */
+static bool
+bridge_try_local_if(struct bridge_softc *sc, struct ifnet *iface,
+ struct mbuf **mp)
+{
+ struct ether_header *eh;
+ bool local_dst, local_src;
+
+ NET_EPOCH_ASSERT();
+
+ /*
+ * Frames received on a gif(4) interface are never considered local.
+ * XXX: Why not?
+ */
+ if (iface->if_type == IFT_GIF)
+ return (false);
+
+ eh = mtod(*mp, struct ether_header *);
+
+ /* See if this frame is destined for the given interface. */
+ if (memcmp(IF_LLADDR(iface), eh->ether_dhost, ETHER_ADDR_LEN) == 0)
+ local_dst = true;
+#if defined(INET) || defined(INET6)
+ else if (iface->if_carp && (*carp_forus_p)(iface, eh->ether_dhost))
+ local_dst = true;
+#endif
+ else
+ local_dst = false;
+
+ if (local_dst) {
+ (*mp)->m_pkthdr.rcvif = iface;
+ *mp = bridge_handle_for_host(sc, iface, *mp);
+ return true;
+ }
+
+ /* See if this frame was sent from the given interface. */
+ if (memcmp(IF_LLADDR(iface), eh->ether_shost, ETHER_ADDR_LEN) == 0)
+ local_src = true;
+#if defined(INET) || defined(INET6)
+ else if (iface->if_carp && (*carp_forus_p)(iface, eh->ether_shost))
+ local_src = true;
+#endif
+ else
+ local_src = false;
+
+ if (local_src) {
+ m_freem(*mp);
+ *mp = NULL;
+ return true;
+ }
+
+ return (false);
+}
+
+/*
+ * Try to handle this as a local packet by checking all the interfaces it
+ * might be local for.
+ */
+static bool
+bridge_try_local(struct bridge_softc *sc, struct ifnet *iface,
+ struct mbuf **mp)
+{
+ struct bridge_iflist *bif;
+
+ /* Check the bridge interface itself first. */
+ if (bridge_try_local_if(sc, sc->sc_ifp, mp))
+ return (true);
+
+ /* If member_ifaddrs is disabled, that's it; it's not local. */
+ if (!V_member_ifaddrs)
+ return (false);
+
+ /* Check the interface the frame arrived on. */
+ if (bridge_try_local_if(sc, iface, mp))
+ return (true);
+
+ /* Check the other bridge members. */
+ CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
+ if (bridge_try_local_if(sc, bif->bif_ifp, mp))
+ return (true);
+ }
+
+ /* It's not local. */
+ return (false);
+}
+
/*
* bridge_input:
*
@@ -2866,15 +2994,27 @@
bridge_input(struct ifnet *ifp, struct mbuf *m)
{
struct bridge_softc *sc = NULL;
- struct bridge_iflist *bif, *bif2;
+ struct bridge_iflist *bif;
struct ifnet *bifp;
struct ether_header *eh;
struct mbuf *mc, *mc2;
ether_vlanid_t vlan;
- int error;
NET_EPOCH_ASSERT();
+ vlan = VLANTAGOF(m);
+
+ /*
+ * If this frame has a VLAN tag, and it was not received on a bridge
+ * interface, and the receiving interface has a vlan(4) trunk, then
+ * it is is destined for vlan(4), not for us. This means if vlan(4)
+ * and bridge(4) are configured on the same interface, vlan(4) is
+ * preferred, which is what users typically expect.
+ */
+ if (vlan != 0 && ifp->if_type != IFT_BRIDGE &&
+ ifp->if_vlantrunk != NULL)
+ return (m);
+
/* We need the Ethernet header later, so make sure we have it now. */
if (m->m_len < ETHER_HDR_LEN) {
m = m_pullup(m, ETHER_HDR_LEN);
@@ -2886,7 +3026,6 @@
}
eh = mtod(m, struct ether_header *);
- vlan = VLANTAGOF(m);
bif = ifp->if_bridge;
if (bif)
@@ -2910,6 +3049,7 @@
}
m->m_pkthdr.rcvif = ifp;
}
+
bifp = sc->sc_ifp;
if ((bifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
return (m);
@@ -2938,8 +3078,44 @@
/* bridge_vfilter_in() may add a tag */
vlan = VLANTAGOF(m);
+ /* Pass this frame to our span ports */
bridge_span(sc, m);
+ /*
+ * Filter on the physical interface. Do this early so that we don't
+ * do any other processing (like address learning) for filtered
+ * packets.
+ */
+ if (V_pfil_local_phys && PFIL_HOOKED_IN_46) {
+ int error = bridge_pfil(&m, NULL, ifp, PFIL_IN);
+ if (error != 0 || m == NULL) {
+ if (m != NULL)
+ m_freem(m);
+ return (NULL);
+ }
+ }
+
+ /* Learn the source address of this frame */
+ if (bif->bif_flags & IFBIF_LEARNING) {
+ int error;
+
+ error = bridge_rtupdate(sc, eh->ether_shost, vlan, bif, 0,
+ IFBAF_DYNAMIC);
+
+ /*
+ * Ignore errors, unless the error was caused by the port
+ * exceeding its address limit, in which case the frame should
+ * be dropped because this is a security policy violation.
+ */
+ if (error && bif->bif_addrmax) {
+ m_freem(m);
+ return (NULL);
+ }
+ }
+
+ /*
+ * Handle broadcast and multicast frames.
+ */
if (m->m_flags & (M_BCAST|M_MCAST)) {
/* Tap off 802.1D packets; they do not get forwarded. */
if (memcmp(eh->ether_dhost, bstp_etheraddr,
@@ -2950,7 +3126,8 @@
if ((bif->bif_flags & IFBIF_STP) &&
bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
- return (m);
+ m_freem(m);
+ return (NULL);
}
/*
@@ -3004,112 +3181,13 @@
if ((bif->bif_flags & IFBIF_STP) &&
bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
- return (m);
- }
-
-#if defined(INET) || defined(INET6)
-#define CARP_CHECK_WE_ARE_DST(iface) \
- ((iface)->if_carp && (*carp_forus_p)((iface), eh->ether_dhost))
-#define CARP_CHECK_WE_ARE_SRC(iface) \
- ((iface)->if_carp && (*carp_forus_p)((iface), eh->ether_shost))
-#else
-#define CARP_CHECK_WE_ARE_DST(iface) false
-#define CARP_CHECK_WE_ARE_SRC(iface) false
-#endif
-
-#ifdef DEV_NETMAP
-#define GRAB_FOR_NETMAP(ifp, m) do { \
- if ((if_getcapenable(ifp) & IFCAP_NETMAP) != 0 && \
- ((m)->m_flags & M_BRIDGE_INJECT) == 0) { \
- (ifp)->if_input(ifp, m); \
- return (NULL); \
- } \
-} while (0)
-#else
-#define GRAB_FOR_NETMAP(ifp, m)
-#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);\
- /* Hand the packet over to netmap if necessary. */ \
- GRAB_FOR_NETMAP(bifp, m); \
- /* Filter on the physical interface. */ \
- if (V_pfil_local_phys && PFIL_HOOKED_IN_46) { \
- if (bridge_pfil(&m, NULL, ifp, \
- PFIL_IN) != 0 || m == NULL) { \
- return (NULL); \
- } \
- } \
- if ((iface) != bifp) \
- ETHER_BPF_MTAP(iface, m); \
- /* Pass tagged packets to if_vlan, if it's loaded */ \
- if (VLANTAGOF(m) != 0) { \
- if (bifp->if_vlantrunk == NULL) { \
- m_freem(m); \
- return (NULL); \
- } \
- (*vlan_input_p)(bifp, m); \
- return (NULL); \
- } \
- 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); \
- }
-
- /*
- * Unicast. Make sure it's not for the bridge.
- */
- do { GRAB_OUR_PACKETS(bifp) } while (0);
-
- /*
- * Check the interface the packet arrived on. For tagged frames,
- * we need to do this even if member_ifaddrs is disabled because
- * vlan(4) might need to handle the traffic.
- */
- if (V_member_ifaddrs || (vlan && ifp->if_vlantrunk))
- do { GRAB_OUR_PACKETS(ifp) } while (0);
-
- /*
- * We only need to check other members interface if member_ifaddrs
- * is enabled; otherwise we should have never traffic destined for
- * a member's lladdr.
- */
- if (V_member_ifaddrs) {
- CK_LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) {
- GRAB_OUR_PACKETS(bif2->bif_ifp)
- }
+ m_freem(m);
+ return (NULL);
}
-#undef CARP_CHECK_WE_ARE_DST
-#undef CARP_CHECK_WE_ARE_SRC
-#undef GRAB_FOR_NETMAP
-#undef GRAB_OUR_PACKETS
+ /* See if this packet should be handled locally. */
+ if (bridge_try_local(sc, ifp, &m))
+ return (m);
/* Perform the bridge forwarding function. */
bridge_forward(sc, bif, m);

File Metadata

Mime Type
text/plain
Expires
Sun, Feb 8, 8:37 PM (21 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28495652
Default Alt Text
D51260.id158331.diff (10 KB)

Event Timeline