Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F145468917
D38066.id116645.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D38066.id116645.diff
View Options
diff --git a/share/man/man4/bridge.4 b/share/man/man4/bridge.4
--- a/share/man/man4/bridge.4
+++ b/share/man/man4/bridge.4
@@ -35,7 +35,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 7, 2022
+.Dd February 3, 2023
.Dt IF_BRIDGE 4
.Os
.Sh NAME
@@ -412,6 +412,34 @@
Enabling
.Va net.link.bridge.pfil_local_phys
will let you do the additional filtering on the physical interface.
+.Sh NETMAP
+.Xr netmap 4
+applications may open a bridge interface in emulated mode.
+By default, the netmap application will receive all locally destined packets,
+that is, all unicast packets destined to the bridge itself, or a bridge member
+port.
+The kernel will otherwise forward received packets normally.
+If, however, the bridge interface is in promiscuous mode, all packets that
+would otherwise be forwarded or broadcast are shunted to
+.Xr netmap 4 .
+STP packets are handled entirely by
+.Nm
+and are not passed to
+.Xr netmap 4 .
+.Pp
+When the
+.Xr netmap 4
+application transmits packets to the host stack via the bridge interface,
+.Nm
+receives them and attempts to determine their
+.Ql source
+port by looking up the source MAC address in the interface's learning tables.
+Packets for which no matching source port is found are dropped.
+If a source port is found,
+.Nm
+treats the packet as though it was received from the corresponding interface
+and handles it normally without passing the packet back to
+.Xr netmap 4 .
.Sh EXAMPLES
The following when placed in the file
.Pa /etc/rc.conf
@@ -486,6 +514,7 @@
.Xr gif 4 ,
.Xr ipf 4 ,
.Xr ipfw 4 ,
+.Xr netmap 4 ,
.Xr pf 4 ,
.Xr ifconfig 8
.Sh HISTORY
diff --git a/sys/net/ethernet.h b/sys/net/ethernet.h
--- a/sys/net/ethernet.h
+++ b/sys/net/ethernet.h
@@ -43,6 +43,7 @@
* Ethernet-specific mbuf flags.
*/
#define M_HASFCS M_PROTO5 /* FCS included at end of frame */
+#define M_BRIDGE_INJECT M_PROTO6 /* if_bridge-injected frame */
/*
* Ethernet CRC32 polynomials (big- and little-endian versions).
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
@@ -275,6 +275,7 @@
uint32_t sc_brtexceeded; /* # of cache drops */
struct ifnet *sc_ifaddr; /* member mac copied from */
struct ether_addr sc_defaddr; /* Default MAC address */
+ if_input_fn_t sc_if_input; /* Saved copy of if_input */
struct epoch_context sc_epoch_ctx;
};
@@ -306,6 +307,7 @@
#endif
static void bridge_qflush(struct ifnet *);
static struct mbuf *bridge_input(struct ifnet *, struct mbuf *);
+static void bridge_inject(struct ifnet *, struct mbuf *);
static int bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
static int bridge_enqueue(struct bridge_softc *, struct ifnet *,
@@ -761,6 +763,14 @@
#ifdef VIMAGE
ifp->if_reassign = bridge_reassign;
#endif
+ sc->sc_if_input = ifp->if_input;
+ ifp->if_input = bridge_inject;
+
+ /*
+ * Allow BRIDGE_INPUT() to pass in packets originating from the bridge
+ * itself. This is required for netmap but otherwise has no effect.
+ */
+ ifp->if_bridge_input = bridge_input;
BRIDGE_LIST_LOCK();
LIST_INSERT_HEAD(&V_bridge_list, sc, sc_list);
@@ -2329,10 +2339,6 @@
if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
vlan = VLANTAGOF(m);
- if ((sbif->bif_flags & IFBIF_STP) &&
- sbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING)
- goto drop;
-
eh = mtod(m, struct ether_header *);
dst = eh->ether_dhost;
@@ -2352,6 +2358,21 @@
sbif->bif_stp.bp_state == BSTP_IFSTATE_LEARNING)
goto drop;
+#ifdef DEV_NETMAP
+ /*
+ * If the packet wasn't injected by netmap itself, and the netmap
+ * application opted into receiving forwarded packets by putting the
+ * interface into promiscuous mode, pass it down.
+ */
+ if ((m->m_flags & M_BRIDGE_INJECT) == 0 &&
+ (if_getflags(ifp) & IFF_PROMISC) != 0 &&
+ (if_getcapenable(ifp) & IFCAP_NETMAP) != 0) {
+ ifp->if_input(ifp, m);
+ return;
+ }
+ m->m_flags &= ~M_BRIDGE_INJECT;
+#endif
+
/*
* At this point, the port either doesn't participate
* in spanning tree or it is in the forwarding state.
@@ -2458,7 +2479,7 @@
static struct mbuf *
bridge_input(struct ifnet *ifp, struct mbuf *m)
{
- struct bridge_softc *sc = ifp->if_bridge;
+ struct bridge_softc *sc;
struct bridge_iflist *bif, *bif2;
struct ifnet *bifp;
struct ether_header *eh;
@@ -2468,11 +2489,31 @@
NET_EPOCH_ASSERT();
- if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
- return (m);
+ eh = mtod(m, struct ether_header *);
+ vlan = VLANTAGOF(m);
+ sc = ifp->if_bridge;
+ if (sc == NULL) {
+ /*
+ * This packet originated from the bridge itself, so it must
+ * have been transmitted by netmap. Derive the "source"
+ * interface from the source address and drop the packet if the
+ * source address isn't known.
+ */
+ KASSERT((m->m_flags & M_BRIDGE_INJECT) != 0,
+ ("%s: ifnet %p missing a bridge softc", __func__, ifp));
+ sc = if_getsoftc(ifp);
+ ifp = bridge_rtlookup(sc, eh->ether_shost, vlan);
+ if (ifp == NULL) {
+ if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1);
+ m_freem(m);
+ return (NULL);
+ }
+ m->m_pkthdr.rcvif = ifp;
+ }
bifp = sc->sc_ifp;
- vlan = VLANTAGOF(m);
+ if ((bifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+ return (m);
/*
* Implement support for bridge monitoring. If this flag has been
@@ -2493,8 +2534,6 @@
return (m);
}
- eh = mtod(m, struct ether_header *);
-
bridge_span(sc, m);
if (m->m_flags & (M_BCAST|M_MCAST)) {
@@ -2539,7 +2578,8 @@
}
if (mc2 != NULL) {
mc2->m_pkthdr.rcvif = bifp;
- (*bifp->if_input)(bifp, mc2);
+ mc2->m_flags &= ~M_BRIDGE_INJECT;
+ sc->sc_if_input(bifp, mc2);
}
/* Return the original packet for local processing. */
@@ -2567,6 +2607,18 @@
#define PFIL_HOOKED_INET6 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; \
@@ -2589,7 +2641,9 @@
/* 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); \
+ 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(V_inet_pfil_head) || \
PFIL_HOOKED_INET6)) { \
@@ -2632,6 +2686,7 @@
#undef OR_CARP_CHECK_WE_ARE_DST
#undef OR_CARP_CHECK_WE_ARE_SRC
#undef OR_PFIL_HOOKED_INET6
+#undef GRAB_FOR_NETMAP
#undef GRAB_OUR_PACKETS
/* Perform the bridge forwarding function. */
@@ -2640,6 +2695,22 @@
return (NULL);
}
+static void
+bridge_inject(struct ifnet *ifp, struct mbuf *m)
+{
+ struct bridge_softc *sc;
+
+#ifdef DEV_NETMAP
+ if ((if_getcapenable(ifp) & IFCAP_NETMAP) != 0) {
+ KASSERT((m->m_flags & M_BRIDGE_INJECT) == 0,
+ ("%s: mbuf %p has M_BRIDGE_INJECT set", __func__, m));
+ m->m_flags |= M_BRIDGE_INJECT;
+ }
+#endif
+ sc = if_getsoftc(ifp);
+ sc->sc_if_input(ifp, m);
+}
+
/*
* bridge_broadcast:
*
diff --git a/sys/net/if_bridgevar.h b/sys/net/if_bridgevar.h
--- a/sys/net/if_bridgevar.h
+++ b/sys/net/if_bridgevar.h
@@ -309,8 +309,10 @@
KASSERT((_ifp)->if_bridge_input != NULL, \
("%s: if_bridge not loaded!", __func__)); \
_m = (*(_ifp)->if_bridge_input)(_ifp, _m); \
- if (_m != NULL) \
+ if (_m != NULL) { \
_ifp = _m->m_pkthdr.rcvif; \
+ m->m_flags &= ~M_BRIDGE_INJECT; \
+ } \
} while (0)
#define BRIDGE_OUTPUT(_ifp, _m, _err) do { \
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -671,7 +671,7 @@
* The BRIDGE_INPUT() macro will update ifp if the bridge changed it
* and the frame should be delivered locally.
*/
- if (ifp->if_bridge != NULL) {
+ if (ifp->if_bridge != NULL || (m->m_flags & M_BRIDGE_INJECT) != 0) {
m->m_flags &= ~M_PROMISC;
BRIDGE_INPUT(ifp, m);
if (m == NULL) {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Feb 21, 6:54 AM (20 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28913408
Default Alt Text
D38066.id116645.diff (8 KB)
Attached To
Mode
D38066: bridge: Add support for emulated netmap mode
Attached
Detach File
Event Timeline
Log In to Comment