Author: jhb
Date: Thu Jan  5 19:50:47 2012
New Revision: 229634
URL: http://svn.freebsd.org/changeset/base/229634

Log:
  MFC 228089:
  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.

Modified:
  stable/8/sys/net/if_vlan.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/net/if_vlan.c
==============================================================================
--- stable/8/sys/net/if_vlan.c  Thu Jan  5 19:50:12 2012        (r229633)
+++ stable/8/sys/net/if_vlan.c  Thu Jan  5 19:50:47 2012        (r229634)
@@ -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>
@@ -179,14 +178,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);
@@ -807,9 +807,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... */
@@ -865,99 +865,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) {
-                       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) {
+               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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to