svn commit: r228089 - head/sys/net

John Baldwin jhb at FreeBSD.org
Mon Nov 28 19:35:08 UTC 2011


Author: jhb
Date: Mon Nov 28 19:35:08 2011
New Revision: 228089
URL: http://svn.freebsd.org/changeset/base/228089

Log:
  Change the if_vlan driver to use if_transmit for forwarding packets to the
  parent interface.  This avoids the overhead of queueing a packet to an IFQ
  only to immediately dequeue it again.
  
  Suggested by:	np
  Reviewed by:	brooks
  MFC after:	1 month

Modified:
  head/sys/net/if_vlan.c

Modified: head/sys/net/if_vlan.c
==============================================================================
--- head/sys/net/if_vlan.c	Mon Nov 28 19:28:29 2011	(r228088)
+++ head/sys/net/if_vlan.c	Mon Nov 28 19:35:08 2011	(r228089)
@@ -34,9 +34,8 @@
  * we need to pretend to be enough of an Ethernet implementation
  * to make arp work.  The way we do this is by telling everyone
  * that we are an Ethernet, and then catch the packets that
- * ether_output() left on our output queue when it calls
- * if_start(), rewrite them for use by the real outgoing interface,
- * and ask it to send them.
+ * ether_output() sends to us via if_transmit(), rewrite them for
+ * use by the real outgoing interface, and ask it to send them.
  */
 
 #include <sys/cdefs.h>
@@ -183,14 +182,15 @@ static __inline struct ifvlan * vlan_get
 #endif
 static	void trunk_destroy(struct ifvlantrunk *trunk);
 
-static	void vlan_start(struct ifnet *ifp);
 static	void vlan_init(void *foo);
 static	void vlan_input(struct ifnet *ifp, struct mbuf *m);
 static	int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
+static	void vlan_qflush(struct ifnet *ifp);
 static	int vlan_setflag(struct ifnet *ifp, int flag, int status,
     int (*func)(struct ifnet *, int));
 static	int vlan_setflags(struct ifnet *ifp, int status);
 static	int vlan_setmulti(struct ifnet *ifp);
+static	int vlan_transmit(struct ifnet *ifp, struct mbuf *m);
 static	void vlan_unconfig(struct ifnet *ifp);
 static	void vlan_unconfig_locked(struct ifnet *ifp);
 static	int vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag);
@@ -944,9 +944,9 @@ vlan_clone_create(struct if_clone *ifc, 
 	/* NB: mtu is not set here */
 
 	ifp->if_init = vlan_init;
-	ifp->if_start = vlan_start;
+	ifp->if_transmit = vlan_transmit;
+	ifp->if_qflush = vlan_qflush;
 	ifp->if_ioctl = vlan_ioctl;
-	ifp->if_snd.ifq_maxlen = ifqmaxlen;
 	ifp->if_flags = VLAN_IFFLAGS;
 	ether_ifattach(ifp, eaddr);
 	/* Now undo some of the damage... */
@@ -1005,99 +1005,95 @@ vlan_init(void *foo __unused)
 }
 
 /*
- * The if_start method for vlan(4) interface. It doesn't
- * raises the IFF_DRV_OACTIVE flag, since it is called
- * only from IFQ_HANDOFF() macro in ether_output_frame().
- * If the interface queue is full, and vlan_start() is
- * not called, the queue would never get emptied and
- * interface would stall forever.
+ * The if_transmit method for vlan(4) interface.
  */
-static void
-vlan_start(struct ifnet *ifp)
+static int
+vlan_transmit(struct ifnet *ifp, struct mbuf *m)
 {
 	struct ifvlan *ifv;
 	struct ifnet *p;
-	struct mbuf *m;
 	int error;
 
 	ifv = ifp->if_softc;
 	p = PARENT(ifv);
 
-	for (;;) {
-		IF_DEQUEUE(&ifp->if_snd, m);
-		if (m == NULL)
-			break;
-		BPF_MTAP(ifp, m);
+	BPF_MTAP(ifp, m);
 
-		/*
-		 * Do not run parent's if_start() if the parent is not up,
-		 * or parent's driver will cause a system crash.
-		 */
-		if (!UP_AND_RUNNING(p)) {
-			m_freem(m);
-			ifp->if_collisions++;
-			continue;
-		}
+	/*
+	 * Do not run parent's if_transmit() if the parent is not up,
+	 * or parent's driver will cause a system crash.
+	 */
+	if (!UP_AND_RUNNING(p)) {
+		m_freem(m);
+		ifp->if_collisions++;
+		return (0);
+	}
 
-		/*
-		 * Pad the frame to the minimum size allowed if told to.
-		 * This option is in accord with IEEE Std 802.1Q, 2003 Ed.,
-		 * paragraph C.4.4.3.b.  It can help to work around buggy
-		 * bridges that violate paragraph C.4.4.3.a from the same
-		 * document, i.e., fail to pad short frames after untagging.
-		 * E.g., a tagged frame 66 bytes long (incl. FCS) is OK, but
-		 * untagging it will produce a 62-byte frame, which is a runt
-		 * and requires padding.  There are VLAN-enabled network
-		 * devices that just discard such runts instead or mishandle
-		 * them somehow.
-		 */
-		if (soft_pad && p->if_type == IFT_ETHER) {
-			static char pad[8];	/* just zeros */
-			int n;
-
-			for (n = ETHERMIN + ETHER_HDR_LEN - m->m_pkthdr.len;
-			     n > 0; n -= sizeof(pad))
-				if (!m_append(m, min(n, sizeof(pad)), pad))
-					break;
-
-			if (n > 0) {
-				if_printf(ifp, "cannot pad short frame\n");
-				ifp->if_oerrors++;
-				m_freem(m);
-				continue;
-			}
-		}
+	/*
+	 * Pad the frame to the minimum size allowed if told to.
+	 * This option is in accord with IEEE Std 802.1Q, 2003 Ed.,
+	 * paragraph C.4.4.3.b.  It can help to work around buggy
+	 * bridges that violate paragraph C.4.4.3.a from the same
+	 * document, i.e., fail to pad short frames after untagging.
+	 * E.g., a tagged frame 66 bytes long (incl. FCS) is OK, but
+	 * untagging it will produce a 62-byte frame, which is a runt
+	 * and requires padding.  There are VLAN-enabled network
+	 * devices that just discard such runts instead or mishandle
+	 * them somehow.
+	 */
+	if (soft_pad && p->if_type == IFT_ETHER) {
+		static char pad[8];	/* just zeros */
+		int n;
+
+		for (n = ETHERMIN + ETHER_HDR_LEN - m->m_pkthdr.len;
+		     n > 0; n -= sizeof(pad))
+			if (!m_append(m, min(n, sizeof(pad)), pad))
+				break;
 
-		/*
-		 * If underlying interface can do VLAN tag insertion itself,
-		 * just pass the packet along. However, we need some way to
-		 * tell the interface where the packet came from so that it
-		 * knows how to find the VLAN tag to use, so we attach a
-		 * packet tag that holds it.
-		 */
-		if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
-			m->m_pkthdr.ether_vtag = ifv->ifv_tag;
-			m->m_flags |= M_VLANTAG;
-		} else {
-			m = ether_vlanencap(m, ifv->ifv_tag);
-			if (m == NULL) {
-				if_printf(ifp,
-				    "unable to prepend VLAN header\n");
-				ifp->if_oerrors++;
-				continue;
-			}
+		if (n > 0) {
+			if_printf(ifp, "cannot pad short frame\n");
+			ifp->if_oerrors++;
+			m_freem(m);
+			return (0);
 		}
+	}
 
-		/*
-		 * Send it, precisely as ether_output() would have.
-		 * We are already running at splimp.
-		 */
-		error = (p->if_transmit)(p, m);
-		if (!error)
-			ifp->if_opackets++;
-		else
+	/*
+	 * If underlying interface can do VLAN tag insertion itself,
+	 * just pass the packet along. However, we need some way to
+	 * tell the interface where the packet came from so that it
+	 * knows how to find the VLAN tag to use, so we attach a
+	 * packet tag that holds it.
+	 */
+	if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
+		m->m_pkthdr.ether_vtag = ifv->ifv_tag;
+		m->m_flags |= M_VLANTAG;
+	} else {
+		m = ether_vlanencap(m, ifv->ifv_tag);
+		if (m == NULL) {
+			if_printf(ifp, "unable to prepend VLAN header\n");
 			ifp->if_oerrors++;
+			return (0);
+		}
 	}
+
+	/*
+	 * Send it, precisely as ether_output() would have.
+	 */
+	error = (p->if_transmit)(p, m);
+	if (!error)
+		ifp->if_opackets++;
+	else
+		ifp->if_oerrors++;
+	return (error);
+}
+
+/*
+ * The ifp->if_qflush entry point for vlan(4) is a no-op.
+ */
+static void
+vlan_qflush(struct ifnet *ifp __unused)
+{
 }
 
 static void


More information about the svn-src-head mailing list