right now we add vlan_input as a possible input handler on the parent
interface, and if the packet is for a vlan we take it and pretend we
received it on the vlan interface by calling if_input against that mbuf.

as mpi notes, the if input queue stuff looks like a lot of work,
especially for a single packet. my opinion is that we got away with
the if input stuff we've done to try and encourage an mpsafe network
stack because we amortised the cost of it over many packets off the
hardware ring. vlan does it a packet at a time.

this moves the handling of vlan packets back into ether_input by
calling vlan_input directly on packets that are either marked as vlan
tagged or have a vlan ethertype. note that we have to do that anyway,
this just makes it explicit.

vlan_input is then tweaked to implement all the important bits of if
input. part of what if input does is count the packets. because vlan
already has per cpu counters for bypassing queues on output, we can use
them again for input from any cpu. if i ever get round to making a
driver handle multiple rx rings this means we can rx vlan packets
concurrently, they don't get serialised to a single if input q.

finally, hrvoje popovski has tested this diff and get's a significant
bump with it. on a machine that can forward 1100Kpps without vlan, it
goes from 790Kpps with vlan to 870Kpps. On a box that can do 730Kpps
without vlans, it goes from 550Kpps with vlan to 840Kpps. We're
still trying to figure that last one out, but it does appear to be
faster.

thoughts? ok?

i would like to apply this style of tweak to the other ethernet magic
pseudo interfaces like trunk, bridge, switch and bpe  after this
with the intention of making if_input a single function pointer again.

Index: if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.571
diff -u -p -r1.571 if.c
--- if.c        9 Jan 2019 01:14:21 -0000       1.571
+++ if.c        21 Feb 2019 04:03:44 -0000
@@ -895,11 +895,29 @@ if_ih_remove(struct ifnet *ifp, int (*in
 }
 
 void
-if_input_process(struct ifnet *ifp, struct mbuf_list *ml)
+if_input_one(struct ifnet *ifp, struct mbuf *m)
 {
-       struct mbuf *m;
        struct ifih *ifih;
        struct srp_ref sr;
+
+       /*
+        * Pass this mbuf to all input handlers of its
+        * interface until it is consumed.
+        */
+       SRPL_FOREACH(ifih, &sr, &ifp->if_inputs, ifih_next) {
+               if ((*ifih->ifih_input)(ifp, m, ifih->ifih_cookie))
+                       break;
+       }
+       SRPL_LEAVE(&sr);
+
+       if (ifih == NULL)
+               m_freem(m);
+}
+
+void
+if_input_process(struct ifnet *ifp, struct mbuf_list *ml)
+{
+       struct mbuf *m;
        int s;
 
        if (ml_empty(ml))
@@ -922,20 +940,8 @@ if_input_process(struct ifnet *ifp, stru
         */
        NET_RLOCK();
        s = splnet();
-       while ((m = ml_dequeue(ml)) != NULL) {
-               /*
-                * Pass this mbuf to all input handlers of its
-                * interface until it is consumed.
-                */
-               SRPL_FOREACH(ifih, &sr, &ifp->if_inputs, ifih_next) {
-                       if ((*ifih->ifih_input)(ifp, m, ifih->ifih_cookie))
-                               break;
-               }
-               SRPL_LEAVE(&sr);
-
-               if (ifih == NULL)
-                       m_freem(m);
-       }
+       while ((m = ml_dequeue(ml)) != NULL)
+               if_input_one(ifp, m);
        splx(s);
        NET_RUNLOCK();
 }
Index: if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.258
diff -u -p -r1.258 if_ethersubr.c
--- if_ethersubr.c      18 Feb 2019 03:41:21 -0000      1.258
+++ if_ethersubr.c      21 Feb 2019 04:03:44 -0000
@@ -74,6 +74,7 @@ didn't get a copy, you may request one f
 */
 
 #include "bpfilter.h"
+#include "vlan.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -103,6 +104,10 @@ didn't get a copy, you may request one f
 #include <net/bpf.h>
 #endif
 
+#if NVLAN > 0
+#include <net/if_vlan_var.h>
+#endif
+
 #include "pppoe.h"
 #if NPPPOE > 0
 #include <net/if_pppoe.h>
@@ -362,6 +367,17 @@ ether_input(struct ifnet *ifp, struct mb
 
        ac = (struct arpcom *)ifp;
        eh = mtod(m, struct ether_header *);
+       etype = ntohs(eh->ether_type);
+
+       if (ISSET(m->m_flags, M_VLANTAG) ||
+           etype == ETHERTYPE_VLAN || etype == ETHERTYPE_QINQ) {
+#if NVLAN > 0
+               m = vlan_input(ifp, m);
+               if (m == NULL)
+                       return (1);
+#endif
+               goto dropanyway;
+       }
 
        /* Is the packet for us? */
        if (memcmp(ac->ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN) != 0) {
@@ -387,15 +403,6 @@ ether_input(struct ifnet *ifp, struct mb
                        m->m_flags |= M_MCAST;
                ifp->if_imcasts++;
        }
-
-       /*
-        * HW vlan tagged packets that were not collected by vlan(4) must
-        * be dropped now.
-        */
-       if (m->m_flags & M_VLANTAG)
-               goto dropanyway;
-
-       etype = ntohs(eh->ether_type);
 
        switch (etype) {
        case ETHERTYPE_IP:
Index: if_var.h
===================================================================
RCS file: /cvs/src/sys/net/if_var.h,v
retrieving revision 1.94
diff -u -p -r1.94 if_var.h
--- if_var.h    9 Jan 2019 01:14:21 -0000       1.94
+++ if_var.h    21 Feb 2019 04:03:44 -0000
@@ -334,6 +334,7 @@ void        if_start(struct ifnet *);
 int    if_enqueue(struct ifnet *, struct mbuf *);
 int    if_enqueue_ifq(struct ifnet *, struct mbuf *);
 void   if_input(struct ifnet *, struct mbuf_list *);
+void   if_input_one(struct ifnet *, struct mbuf *);
 void   if_input_process(struct ifnet *, struct mbuf_list *);
 int    if_input_local(struct ifnet *, struct mbuf *, sa_family_t);
 int    if_output_local(struct ifnet *, struct mbuf *, sa_family_t);
Index: if_vlan.c
===================================================================
RCS file: /cvs/src/sys/net/if_vlan.c,v
retrieving revision 1.183
diff -u -p -r1.183 if_vlan.c
--- if_vlan.c   15 Feb 2019 13:00:51 -0000      1.183
+++ if_vlan.c   21 Feb 2019 04:03:44 -0000
@@ -83,7 +83,6 @@ void  vlanattach(int count);
 int    vlan_clone_create(struct if_clone *, int);
 int    vlan_clone_destroy(struct ifnet *);
 
-int    vlan_input(struct ifnet *, struct mbuf *, void *);
 int    vlan_enqueue(struct ifnet *, struct mbuf *);
 void   vlan_start(struct ifqueue *ifq);
 int    vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
@@ -335,88 +334,94 @@ vlan_inject(struct mbuf *m, uint16_t typ
        return (m);
  }
 
-/*
- * vlan_input() returns 1 if it has consumed the packet, 0 otherwise.
- */
-int
-vlan_input(struct ifnet *ifp0, struct mbuf *m, void *cookie)
+struct mbuf *
+vlan_input(struct ifnet *ifp0, struct mbuf *m)
 {
        struct ifvlan                   *ifv;
+       struct ifnet                    *ifp;
        struct ether_vlan_header        *evl;
-       struct ether_header             *eh;
        SRPL_HEAD(, ifvlan)             *tagh, *list;
        struct srp_ref                   sr;
        u_int                            tag;
-       struct mbuf_list                 ml = MBUF_LIST_INITIALIZER();
        u_int16_t                        etype;
+#if NBPFILTER > 0
+       caddr_t                          if_bpf;
+#endif
 
-       eh = mtod(m, struct ether_header *);
-       etype = ntohs(eh->ether_type);
-
-       if (m->m_flags & M_VLANTAG) {
+       if (ISSET(m->m_flags, M_VLANTAG)) {
                etype = ETHERTYPE_VLAN;
                tagh = vlan_tagh;
-       } else if ((etype == ETHERTYPE_VLAN) || (etype == ETHERTYPE_QINQ)) {
-               if (m->m_len < sizeof(*evl) &&
-                   (m = m_pullup(m, sizeof(*evl))) == NULL) {
-                       ifp0->if_ierrors++;
-                       return (1);
+       } else {
+               if (m->m_len < sizeof(*evl)) {
+                       m = m_pullup(m, sizeof(*evl));
+                       if (m == NULL)
+                               return (NULL);
                }
 
                evl = mtod(m, struct ether_vlan_header *);
-               m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag);
+               etype = ntohs(evl->evl_encap_proto);
                tagh = etype == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
-       } else {
-               /* Skip non-VLAN packets. */
-               return (0);
+               m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag);
        }
 
        /* From now on ether_vtag is fine */
        tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
-       m->m_pkthdr.pf.prio = EVL_PRIOFTAG(m->m_pkthdr.ether_vtag);
-
-       /* IEEE 802.1p has prio 0 and 1 swapped */
-       if (m->m_pkthdr.pf.prio <= 1)
-               m->m_pkthdr.pf.prio = !m->m_pkthdr.pf.prio;
-
        list = &tagh[TAG_HASH(tag)];
        SRPL_FOREACH(ifv, &sr, list, ifv_list) {
-               if (ifp0->if_index == ifv->ifv_ifidx0 && tag == ifv->ifv_tag &&
+               if (ifp0->if_index == ifv->ifv_ifidx0 &&
+                   tag == ifv->ifv_tag &&
                    etype == ifv->ifv_type)
                        break;
        }
 
-       if (ifv == NULL) {
-               ifp0->if_noproto++;
-               goto drop;
-       }
+       if (ifv == NULL || !ISSET(ifv->ifv_if.if_flags, IFF_RUNNING))
+               goto decline;
 
-       if ((ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
-           (IFF_UP|IFF_RUNNING))
-               goto drop;
+       /* The packet is ours now */
+
+       m->m_pkthdr.pf.prio = EVL_PRIOFTAG(m->m_pkthdr.ether_vtag);
+       /* IEEE 802.1p has prio 0 and 1 swapped */
+       if (m->m_pkthdr.pf.prio <= 1)
+               m->m_pkthdr.pf.prio = !m->m_pkthdr.pf.prio;
 
        /*
         * Having found a valid vlan interface corresponding to
         * the given source interface and vlan tag, remove the
         * encapsulation.
         */
-       if (m->m_flags & M_VLANTAG) {
-               m->m_flags &= ~M_VLANTAG;
+       if (ISSET(m->m_flags, M_VLANTAG)) {
+               CLR(m->m_flags, M_VLANTAG);
        } else {
-               eh->ether_type = evl->evl_proto;
-               memmove((char *)eh + EVL_ENCAPLEN, eh, sizeof(*eh));
+               memmove((char *)evl + EVL_ENCAPLEN, evl,
+                   offsetof(struct ether_vlan_header, evl_encap_proto));
                m_adj(m, EVL_ENCAPLEN);
        }
 
-       ml_enqueue(&ml, m);
-       if_input(&ifv->ifv_if, &ml);
+       ifp = &ifv->ifv_if;
+       counters_pkt(ifp->if_counters,
+           ifc_ipackets, ifc_ibytes, m->m_pkthdr.len);
+
+       m->m_pkthdr.ph_ifidx = ifp->if_index;
+       m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
+
+#if NBPFILTER > 0
+       if_bpf = ifp->if_bpf;
+       if (if_bpf) {
+               if (bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_OUT)) {
+                       m_freem(m);
+                       goto leave;
+               }
+       }
+#endif
+
+       if_input_one(ifp, m);
+leave:
        SRPL_LEAVE(&sr);
-       return (1);
+       return (NULL);
 
-drop:
+decline:
        SRPL_LEAVE(&sr);
-       m_freem(m);
-       return (1);
+       return (m);
 }
 
 int
@@ -440,8 +445,6 @@ vlan_parent_up(struct ifvlan *ifv, struc
 
        vlan_multi_apply(ifv, ifp0, SIOCADDMULTI);
 
-       if_ih_insert(ifp0, vlan_input, NULL);
-
        return (0);
 }
 
@@ -560,7 +563,6 @@ vlan_down(struct ifvlan *ifv)
 
        ifp0 = if_get(ifv->ifv_ifidx0);
        if (ifp0 != NULL) {
-               if_ih_remove(ifp0, vlan_input, NULL);
                if (ISSET(ifv->ifv_flags, IFVF_PROMISC))
                        ifpromisc(ifp0, 0);
                vlan_multi_apply(ifv, ifp0, SIOCDELMULTI);
Index: if_vlan_var.h
===================================================================
RCS file: /cvs/src/sys/net/if_vlan_var.h,v
retrieving revision 1.39
diff -u -p -r1.39 if_vlan_var.h
--- if_vlan_var.h       15 Feb 2019 13:00:51 -0000      1.39
+++ if_vlan_var.h       21 Feb 2019 04:03:44 -0000
@@ -85,6 +85,7 @@ struct        ifvlan {
 #define        IFVF_LLADDR     0x02    /* don't inherit the parents mac */
 
 struct mbuf    *vlan_inject(struct mbuf *, uint16_t, uint16_t);
+struct mbuf    *vlan_input(struct ifnet *, struct mbuf *);
 #endif /* _KERNEL */
 
 #endif /* _NET_IF_VLAN_VAR_H_ */

Reply via email to