Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144318502
D51260.id158328.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D51260.id158328.diff
View Options
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
@@ -2856,6 +2856,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 +3007,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 +3039,6 @@
}
eh = mtod(m, struct ether_header *);
- vlan = VLANTAGOF(m);
bif = ifp->if_bridge;
if (bif)
@@ -2910,6 +3062,7 @@
}
m->m_pkthdr.rcvif = ifp;
}
+
bifp = sc->sc_ifp;
if ((bifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
return (m);
@@ -2938,8 +3091,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 +3139,8 @@
if ((bif->bif_flags & IFBIF_STP) &&
bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) {
- return (m);
+ m_freem(m);
+ return (NULL);
}
/*
@@ -3004,112 +3194,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
Details
Attached
Mime Type
text/plain
Expires
Sun, Feb 8, 8:03 PM (21 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28491664
Default Alt Text
D51260.id158328.diff (9 KB)
Attached To
Mode
D51260: bridge: refactor local packet handling
Attached
Detach File
Event Timeline
Log In to Comment