bridge(4) input path fixing

Sepherosa Ziehau sepherosa at gmail.com
Mon Jun 11 04:42:07 PDT 2007


On 6/11/07, Matthew Dillon <dillon at apollo.backplane.com> wrote:
:Hi all,
:
:Following patch fixes bridge serializer coverage problem and possible
:serializer ordering problem:
:http://leaf.dragonflybsd.org/~sephe/bridge.diff
:
:cpuN's msgport is used.
:
:Please review/test it.
:
:Best Regards,
:sephe
    I'm not sure tags can be ignored that way.   Tags are usually not
    allocated (I could be wrong, but that is what I remember)... instead
    they are often declared as stack variables in the calling procedure
    so they have to be stripped by the callee before returning, because
    their memory may go poof.
Ah, :) Patch regenerated.

Best Regards,
sephe
--
Live Free or Die
Index: netisr.h
===================================================================
RCS file: /opt/df_cvs/src/sys/net/netisr.h,v
retrieving revision 1.26
diff -u -p -r1.26 netisr.h
--- netisr.h	23 May 2007 08:57:10 -0000	1.26
+++ netisr.h	11 Jun 2007 11:17:02 -0000
@@ -217,6 +217,7 @@ struct netisr {
 #ifdef _KERNEL
 
 extern lwkt_port netisr_afree_rport;
+extern lwkt_port netisr_apanic_rport;
 
 lwkt_port_t	cpu0_portfn(struct mbuf **mptr);
 lwkt_port_t	cpu_portfn(int cpu);
Index: bridge/if_bridge.c
===================================================================
RCS file: /opt/df_cvs/src/sys/net/bridge/if_bridge.c,v
retrieving revision 1.24
diff -u -p -r1.24 if_bridge.c
--- bridge/if_bridge.c	6 Jun 2007 13:10:39 -0000	1.24
+++ bridge/if_bridge.c	11 Jun 2007 11:17:02 -0000
@@ -124,6 +124,7 @@
 #include <netinet/if_ether.h> /* for struct arpcom */
 #include <net/bridge/if_bridgevar.h>
 #include <net/if_llc.h>
+#include <net/netmsg2.h>
 
 #include <net/route.h>
 #include <sys/in_cksum.h>
@@ -265,6 +266,13 @@ static int	bridge_ip6_checkbasic(struct 
 #endif /* INET6 */
 static int	bridge_fragment(struct ifnet *, struct mbuf *,
 		    struct ether_header *, int, struct llc *);
+static void	bridge_enqueue_internal(struct ifnet *, struct mbuf *m,
+					netisr_fn_t);
+static void	bridge_enqueue_handler(struct netmsg *);
+static void	bridge_pfil_enqueue_handler(struct netmsg *);
+static void	bridge_pfil_enqueue(struct ifnet *, struct mbuf *, int);
+static void	bridge_handoff_notags(struct ifnet *, struct mbuf *);
+static void	bridge_handoff(struct ifnet *, struct mbuf *);
 
 SYSCTL_DECL(_net_link);
 SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW, 0, "Bridge");
@@ -367,7 +375,6 @@ struct if_clone bridge_cloner = IF_CLONE
 static int
 bridge_modevent(module_t mod, int type, void *data)
 {
-
 	switch (type) {
 	case MOD_LOAD:
 		LIST_INIT(&bridge_list);
@@ -1348,37 +1355,56 @@ bridge_stop(struct ifnet *ifp)
 	ifp->if_flags &= ~IFF_RUNNING;
 }
 
-/*
- * bridge_enqueue:
- *
- *	Enqueue a packet on a bridge member interface.
- *
- */
-void
-bridge_enqueue(struct ifnet *dst_ifp, struct mbuf *m)
+static void
+bridge_enqueue_internal(struct ifnet *dst_ifp, struct mbuf *m,
+			netisr_fn_t handler)
 {
-	struct altq_pktattr pktattr;
-	struct mbuf *m0;
+	struct netmsg_packet *nmp;
+	lwkt_port_t port;
+	int cpu = mycpu->gd_cpuid;
 
 	while (m->m_type == MT_TAG) {
 		/* XXX see ether_output_frame for full rules check */
 		m = m->m_next;
 	}
 
-	lwkt_serialize_enter(dst_ifp->if_serializer);
+	nmp = &m->m_hdr.mh_netmsg;
+	netmsg_init(&nmp->nm_netmsg, &netisr_apanic_rport, 0, handler);
+	nmp->nm_packet = m;
+	nmp->nm_netmsg.nm_lmsg.u.ms_resultp = dst_ifp;
 
-	/* We may be sending a fragment so traverse the mbuf */
-	for (; m; m = m0) {
-		m0 = m->m_nextpkt;
-		m->m_nextpkt = NULL;
+	port = cpu_portfn(cpu);
+	lwkt_sendmsg(port, &nmp->nm_netmsg.nm_lmsg);
+}
 
-		if (ifq_is_enabled(&dst_ifp->if_snd))
-			altq_etherclassify(&dst_ifp->if_snd, m, &pktattr);
+static void
+bridge_pfil_enqueue(struct ifnet *dst_ifp, struct mbuf *m,
+		    int runfilt)
+{
+	netisr_fn_t handler;
 
-		ifq_handoff(dst_ifp, m, &pktattr);
+	if (runfilt && (inet_pfil_hook.ph_hashooks > 0
+#ifdef INET6
+	    || inet6_pfil_hook.ph_hashooks > 0
+#endif
+	    )) {
+		handler = bridge_pfil_enqueue_handler;
+	} else {
+		handler = bridge_enqueue_handler;
 	}
+	bridge_enqueue_internal(dst_ifp, m, handler);
+}
 
-	lwkt_serialize_exit(dst_ifp->if_serializer);
+/*
+ * bridge_enqueue:
+ *
+ *	Enqueue a packet on a bridge member interface.
+ *
+ */
+void
+bridge_enqueue(struct ifnet *dst_ifp, struct mbuf *m)
+{
+	bridge_enqueue_internal(dst_ifp, m, bridge_enqueue_handler);
 }
 
 /*
@@ -1474,9 +1500,7 @@ bridge_output_serialized(struct ifnet *i
 					continue;
 				}
 			}
-			lwkt_serialize_exit(sc->sc_ifp->if_serializer);
 			bridge_enqueue(dst_if, mc);
-			lwkt_serialize_enter(sc->sc_ifp->if_serializer);
 		}
 		if (used == 0)
 			m_freem(m);
@@ -1564,8 +1588,8 @@ bridge_forward(struct bridge_softc *sc, 
 
 	ASSERT_SERIALIZED(ifp->if_serializer);
 
-	sc->sc_ifp->if_ipackets++;
-	sc->sc_ifp->if_ibytes += m->m_pkthdr.len;
+	ifp->if_ipackets++;
+	ifp->if_ibytes += m->m_pkthdr.len;
 
 	/*
 	 * Look up the bridge_iflist.
@@ -1590,12 +1614,6 @@ bridge_forward(struct bridge_softc *sc, 
 	eh = mtod(m, struct ether_header *);
 
 	/*
-	 * Various ifp's are used below, release the serializer for
-	 * the bridge ifp so other ifp serializers can be acquired.
-	 */
-	lwkt_serialize_exit(ifp->if_serializer);
-
-	/*
 	 * If the interface is learning, and the source
 	 * address is valid and not multicast, record
 	 * the address.
@@ -1614,7 +1632,7 @@ bridge_forward(struct bridge_softc *sc, 
 	if ((bif->bif_flags & IFBIF_STP) != 0 &&
 	    bif->bif_state == BSTP_IFSTATE_LEARNING) {
 		m_freem(m);
-		goto done;
+		return;
 	}
 
 	/*
@@ -1630,7 +1648,7 @@ bridge_forward(struct bridge_softc *sc, 
 		dst_if = bridge_rtlookup(sc, eh->ether_dhost);
 		if (src_if == dst_if) {
 			m_freem(m);
-			goto done;
+			return;
 		}
 	} else {
 		/* ...forward it to all interfaces. */
@@ -1638,21 +1656,9 @@ bridge_forward(struct bridge_softc *sc, 
 		dst_if = NULL;
 	}
 
-	/* run the packet filter */
-	if (inet_pfil_hook.ph_hashooks > 0
-#ifdef INET6
-	    || inet6_pfil_hook.ph_hashooks > 0
-#endif
-	    ) {
-		if (bridge_pfil(&m, ifp, src_if, PFIL_IN) != 0)
-			goto done;
-		if (m == NULL)
-			goto done;
-	}
-
 	if (dst_if == NULL) {
 		bridge_broadcast(sc, src_if, m, 1);
-		goto done;
+		return;
 	}
 
 	/*
@@ -1661,13 +1667,13 @@ bridge_forward(struct bridge_softc *sc, 
 	 */
 	if ((dst_if->if_flags & IFF_RUNNING) == 0) {
 		m_freem(m);
-		goto done;
+		return;
 	}
 	bif = bridge_lookup_member_if(sc, dst_if);
 	if (bif == NULL) {
 		/* Not a member of the bridge (anymore?) */
 		m_freem(m);
-		goto done;
+		return;
 	}
 
 	if (bif->bif_flags & IFBIF_STP) {
@@ -1675,21 +1681,29 @@ bridge_forward(struct bridge_softc *sc, 
 		case BSTP_IFSTATE_DISABLED:
 		case BSTP_IFSTATE_BLOCKING:
 			m_freem(m);
-			goto done;
+			return;
 		}
 	}
 
+	lwkt_serialize_exit(ifp->if_serializer);
+
+	/* run the packet filter */
 	if (inet_pfil_hook.ph_hashooks > 0
 #ifdef INET6
 	    || inet6_pfil_hook.ph_hashooks > 0
 #endif
 	    ) {
-		if (bridge_pfil(&m, sc->sc_ifp, dst_if, PFIL_OUT) != 0)
+		if (bridge_pfil(&m, ifp, src_if, PFIL_IN) != 0)
+			goto done;
+		if (m == NULL)
+			goto done;
+
+		if (bridge_pfil(&m, ifp, dst_if, PFIL_OUT) != 0)
 			goto done;
 		if (m == NULL)
 			goto done;
 	}
-	bridge_enqueue(dst_if, m);
+	bridge_handoff(dst_if, m);
 
 	/*
 	 * ifp's serializer was held on entry and is expected to be held
@@ -1852,8 +1866,11 @@ bridge_input(struct ifnet *ifp, struct m
 				    eh->ether_shost, ifp, 0, IFBAF_DYNAMIC);
 			}
 
-			m->m_flags |= M_PROTO1;	/* XXX loop prevention */
-			new_ifp = bif->bif_ifp;
+			if (bif->bif_ifp != ifp) {
+				/* XXX loop prevention */
+				m->m_flags |= M_PROTO1;
+				new_ifp = bif->bif_ifp;
+			}
 			goto out;
 		}
 
@@ -1898,17 +1915,32 @@ bridge_broadcast(struct bridge_softc *sc
 {
 	struct bridge_iflist *bif;
 	struct mbuf *mc;
-	struct ifnet *dst_if;
+	struct ifnet *dst_if, *bifp;
 	int used = 0;
 
-	/* Filter on the bridge interface before broadcasting */
+	bifp = sc->sc_ifp;
+
+	ASSERT_SERIALIZED(bifp->if_serializer);
+
+	/* run the packet filter */
 	if (runfilt && (inet_pfil_hook.ph_hashooks > 0
 #ifdef INET6
 	    || inet6_pfil_hook.ph_hashooks > 0
 #endif
 	    )) {
-		if (bridge_pfil(&m, sc->sc_ifp, NULL, PFIL_OUT) != 0)
-			return;
+		lwkt_serialize_exit(bifp->if_serializer);
+
+		/* Filter on the bridge interface before broadcasting */
+
+		if (bridge_pfil(&m, bifp, src_if, PFIL_IN) != 0)
+			goto filt;
+		if (m == NULL)
+			goto filt;
+
+		if (bridge_pfil(&m, bifp, NULL, PFIL_OUT) != 0)
+			m = NULL;
+filt:
+		lwkt_serialize_enter(bifp->if_serializer);
 		if (m == NULL)
 			return;
 	}
@@ -1943,24 +1975,7 @@ bridge_broadcast(struct bridge_softc *sc
 				continue;
 			}
 		}
-
-		/*
-		 * Filter on the output interface. Pass a NULL bridge interface
-		 * pointer so we do not redundantly filter on the bridge for
-		 * each interface we broadcast on.
-		 */
-		if (runfilt && (inet_pfil_hook.ph_hashooks > 0
-#ifdef INET6
-		    || inet6_pfil_hook.ph_hashooks > 0
-#endif
-		    )) {
-			if (bridge_pfil(&mc, NULL, dst_if, PFIL_OUT) != 0)
-				continue;
-			if (mc == NULL)
-				continue;
-		}
-
-		bridge_enqueue(dst_if, mc);
+		bridge_pfil_enqueue(dst_if, mc, runfilt);
 	}
 	if (used == 0)
 		m_freem(m);
@@ -2813,3 +2828,81 @@ out:
 		m_freem(m);
 	return (error);
 }
+
+static void
+bridge_enqueue_handler(struct netmsg *nmsg)
+{
+	struct netmsg_packet *nmp;
+	struct ifnet *dst_ifp;
+	struct mbuf *m;
+
+	nmp = (struct netmsg_packet *)nmsg;
+	m = nmp->nm_packet;
+	dst_ifp = nmp->nm_netmsg.nm_lmsg.u.ms_resultp;
+
+	bridge_handoff_notags(dst_ifp, m);
+}
+
+static void
+bridge_pfil_enqueue_handler(struct netmsg *nmsg)
+{
+	struct netmsg_packet *nmp;
+	struct ifnet *dst_ifp;
+	struct mbuf *m;
+
+	nmp = (struct netmsg_packet *)nmsg;
+	m = nmp->nm_packet;
+	dst_ifp = nmp->nm_netmsg.nm_lmsg.u.ms_resultp;
+
+	/*
+	 * Filter on the output interface. Pass a NULL bridge interface
+	 * pointer so we do not redundantly filter on the bridge for
+	 * each interface we broadcast on.
+	 */
+	if (inet_pfil_hook.ph_hashooks > 0
+#ifdef INET6
+	    || inet6_pfil_hook.ph_hashooks > 0
+#endif
+	    ) {
+		if (bridge_pfil(&m, NULL, dst_ifp, PFIL_OUT) != 0)
+			return;
+		if (m == NULL)
+			return;
+	}
+	bridge_handoff_notags(dst_ifp, m);
+}
+
+static void
+bridge_handoff(struct ifnet *dst_ifp, struct mbuf *m)
+{
+	while (m->m_type == MT_TAG) {
+		/* XXX see ether_output_frame for full rules check */
+		m = m->m_next;
+	}
+	bridge_handoff_notags(dst_ifp, m);
+}
+
+static void
+bridge_handoff_notags(struct ifnet *dst_ifp, struct mbuf *m)
+{
+	struct mbuf *m0;
+
+	KKASSERT(m->m_type != MT_TAG);
+
+	lwkt_serialize_enter(dst_ifp->if_serializer);
+
+	/* We may be sending a fragment so traverse the mbuf */
+	for (; m; m = m0) {
+		struct altq_pktattr pktattr;
+
+		m0 = m->m_nextpkt;
+		m->m_nextpkt = NULL;
+
+		if (ifq_is_enabled(&dst_ifp->if_snd))
+			altq_etherclassify(&dst_ifp->if_snd, m, &pktattr);
+
+		ifq_handoff(dst_ifp, m, &pktattr);
+	}
+
+	lwkt_serialize_exit(dst_ifp->if_serializer);
+}




More information about the Submit mailing list