Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102830417
D38066.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.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
@@ -421,6 +421,29 @@
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.
+The netmap application will receive all packets which arrive from member
+interfaces.
+In particular, packets which would otherwise be forwarded to another
+member interface will be received by the netmap application.
+.Pp
+When the
+.Xr netmap 4
+application transmits a packet to the host stack via the bridge interface,
+.Nm
+receive it and attempts to determine its
+.Ql source
+interface by looking up the source MAC address in the interface's learning
+tables.
+Packets for which no matching source interface is found are dropped and the
+input error counter is incremented.
+If a matching source interface 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
@@ -495,6 +518,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
@@ -267,6 +267,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;
};
@@ -298,6 +299,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 *,
@@ -768,6 +770,15 @@
#ifdef VIMAGE
ifp->if_reassign = bridge_reassign;
#endif
+ sc->sc_if_input = ifp->if_input; /* ether_input */
+ ifp->if_input = bridge_inject;
+
+ /*
+ * Allow BRIDGE_INPUT() to pass in packets originating from the bridge
+ * itself via bridge_inject(). 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);
@@ -2355,6 +2366,19 @@
sbif->bif_stp.bp_state == BSTP_IFSTATE_LEARNING)
goto drop;
+#ifdef DEV_NETMAP
+ /*
+ * Hand the packet to netmap only if it wasn't injected by netmap
+ * itself.
+ */
+ if ((m->m_flags & M_BRIDGE_INJECT) == 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.
@@ -2461,7 +2485,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;
@@ -2471,11 +2495,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
@@ -2496,8 +2540,6 @@
return (m);
}
- eh = mtod(m, struct ether_header *);
-
bridge_span(sc, m);
if (m->m_flags & (M_BCAST|M_MCAST)) {
@@ -2526,6 +2568,18 @@
/* Perform the bridge forwarding function with the copy. */
bridge_forward(sc, bif, mc);
+#ifdef DEV_NETMAP
+ /*
+ * If netmap is enabled and has not already seen this packet,
+ * then it will be consumed by bridge_forward().
+ */
+ if ((if_getcapenable(bifp) & IFCAP_NETMAP) != 0 &&
+ (m->m_flags & M_BRIDGE_INJECT) == 0) {
+ m_freem(m);
+ return (NULL);
+ }
+#endif
+
/*
* Reinject the mbuf as arriving on the bridge so we have a
* chance at claiming multicast packets. We can not loop back
@@ -2542,7 +2596,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. */
@@ -2570,6 +2625,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; \
@@ -2592,7 +2659,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)) { \
@@ -2635,6 +2704,7 @@
#undef CARP_CHECK_WE_ARE_DST
#undef CARP_CHECK_WE_ARE_SRC
#undef PFIL_HOOKED_INET6
+#undef GRAB_FOR_NETMAP
#undef GRAB_OUR_PACKETS
/* Perform the bridge forwarding function. */
@@ -2643,6 +2713,28 @@
return (NULL);
}
+/*
+ * Inject a packet back into the host ethernet stack. This will generally only
+ * be used by netmap when an application writes to the host TX ring. The
+ * M_BRIDGE_INJECT flag ensures that the packet is re-routed to the bridge
+ * interface after ethernet processing.
+ */
+static void
+bridge_inject(struct ifnet *ifp, struct mbuf *m)
+{
+ struct bridge_softc *sc;
+
+ KASSERT((if_getcapenable(ifp) & IFCAP_NETMAP) != 0,
+ ("%s: iface %s is not running in netmap mode",
+ __func__, if_name(ifp)));
+ KASSERT((m->m_flags & M_BRIDGE_INJECT) == 0,
+ ("%s: mbuf %p has M_BRIDGE_INJECT set", __func__, m));
+
+ m->m_flags |= M_BRIDGE_INJECT;
+ 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
@@ -667,10 +667,15 @@
/*
* Allow if_bridge(4) to claim this frame.
+ *
* The BRIDGE_INPUT() macro will update ifp if the bridge changed it
* and the frame should be delivered locally.
+ *
+ * If M_BRIDGE_INJECT is set, the packet was received directly by the
+ * bridge via netmap, so "ifp" is the bridge itself and the packet
+ * should be re-examined.
*/
- 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
Mon, Nov 18, 5:50 PM (19 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14701947
Default Alt Text
D38066.diff (8 KB)
Attached To
Mode
D38066: bridge: Add support for emulated netmap mode
Attached
Detach File
Event Timeline
Log In to Comment