Page MenuHomeFreeBSD

D38066.id116645.diff
No OneTemporary

D38066.id116645.diff

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

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)

Event Timeline