we used to handle the vlan tag etc insertion very very very late,
authorhenning <henning@openbsd.org>
Tue, 22 Apr 2014 11:43:07 +0000 (11:43 +0000)
committerhenning <henning@openbsd.org>
Tue, 22 Apr 2014 11:43:07 +0000 (11:43 +0000)
on al already ass embed ethernet frame, which meant:
-copy (most of) the existing ethernet header into a ether_vlan_header
on the stack
-fill the extra fields in ether_vlan_header
-set the ether type
-m_adj() to make room for the extra space ether_vlan_header needs
-m_copyback the ether_vlan_header into the mbuf
that involves moving data around, which isn't all that cheap.
cleaner & easier to have ether_output prepend the ether_vlan_header instead
of the regular ethernet header, which makes the vlan tagging essentially
free in most cases.
help & ok reyk, naddy; waste of time bikeshedding tech@

sys/net/if_ethersubr.c
sys/net/if_vlan.c

index 09fb772..1a473cc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_ethersubr.c,v 1.170 2014/04/21 18:52:25 henning Exp $      */
+/*     $OpenBSD: if_ethersubr.c,v 1.171 2014/04/22 11:43:07 henning Exp $      */
 /*     $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $        */
 
 /*
@@ -155,8 +155,8 @@ u_char etherbroadcastaddr[ETHER_ADDR_LEN] =
     { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 #define senderr(e) { error = (e); goto bad;}
 
-static inline int    ether_addheader(struct mbuf **, u_int16_t, u_char *,
-                          u_char *);
+static inline int      ether_addheader(struct mbuf **, struct ifnet *,
+                          u_int16_t, u_char *, u_char *);
 
 int
 ether_ioctl(struct ifnet *ifp, struct arpcom *arp, u_long cmd, caddr_t data)
@@ -193,10 +193,40 @@ ether_ioctl(struct ifnet *ifp, struct arpcom *arp, u_long cmd, caddr_t data)
 }
 
 static inline int
-ether_addheader(struct mbuf **m, u_int16_t etype, u_char *esrc, u_char *edst)
+ether_addheader(struct mbuf **m, struct ifnet *ifp, u_int16_t etype,
+    u_char *esrc, u_char *edst)
 {
        struct ether_header *eh;
 
+#if NVLAN > 0
+       if ((*m)->m_flags & M_VLANTAG) {
+               struct ifvlan   *ifv = ifp->if_softc;
+               struct ifnet    *p = ifv->ifv_p;
+
+               /* should we use the tx tagging hw offload at all? */
+               if ((p->if_capabilities & IFCAP_VLAN_HWTAGGING) &&
+                   (ifv->ifv_type == ETHERTYPE_VLAN)) {
+                       (*m)->m_pkthdr.ether_vtag = ifv->ifv_tag +
+                           ((*m)->m_pkthdr.pf.prio << EVL_PRIO_BITS);
+                       /* don't return, need to add regular ethernet header */
+               } else {
+                       struct ether_vlan_header        *evh;
+
+                       M_PREPEND(*m, sizeof(*evh), M_DONTWAIT);
+                       if (*m == 0)
+                               return (-1);
+                       evh = mtod(*m, struct ether_vlan_header *);
+                       memcpy(evh->evl_dhost, edst, sizeof(evh->evl_dhost));
+                       memcpy(evh->evl_shost, esrc, sizeof(evh->evl_shost));
+                       evh->evl_proto = etype;
+                       evh->evl_encap_proto = htons(ifv->ifv_type);
+                       evh->evl_tag = htons(ifv->ifv_tag +
+                           ((*m)->m_pkthdr.pf.prio << EVL_PRIO_BITS));
+                       (*m)->m_flags &= ~M_VLANTAG;
+                       return (0);
+               }
+       }
+#endif /* NVLAN > 0 */
        M_PREPEND(*m, ETHER_HDR_LEN, M_DONTWAIT);
        if (*m == 0)
                return (-1);
@@ -364,7 +394,7 @@ ether_output(struct ifnet *ifp0, struct mbuf *m0, struct sockaddr *dst,
                esrc = carp_get_srclladdr(ifp0, esrc);
 #endif
 
-       if (ether_addheader(&m, etype, esrc, edst) == -1)
+       if (ether_addheader(&m, ifp, etype, esrc, edst) == -1)
                senderr(ENOBUFS);
 
 #if NBRIDGE > 0
index 2743649..2c9bb12 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_vlan.c,v 1.102 2014/03/10 12:21:35 mpi Exp $       */
+/*     $OpenBSD: if_vlan.c,v 1.103 2014/04/22 11:43:07 henning Exp $   */
 
 /*
  * Copyright 1998 Massachusetts Institute of Technology
@@ -80,6 +80,8 @@ u_long vlan_tagmask, svlan_tagmask;
 #define TAG_HASH(tag)          (tag & vlan_tagmask)
 LIST_HEAD(vlan_taghash, ifvlan)        *vlan_tagh, *svlan_tagh;
 
+int    vlan_output(struct ifnet *, struct mbuf *, struct sockaddr *,
+           struct rtentry *);
 void   vlan_start(struct ifnet *ifp);
 int    vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
 int    vlan_unconfig(struct ifnet *ifp, struct ifnet *newp);
@@ -152,6 +154,7 @@ vlan_clone_create(struct if_clone *ifc, int unit)
        /* Now undo some of the damage... */
        ifp->if_type = IFT_L2VLAN;
        ifp->if_hdrlen = EVL_ENCAPLEN;
+       ifp->if_output = vlan_output;
 
        return (0);
 }
@@ -177,6 +180,18 @@ vlan_ifdetach(void *ptr)
        vlan_clone_destroy(&ifv->ifv_if);
 }
 
+int
+vlan_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
+    struct rtentry *rt)
+{
+       /*
+        * we have to use a custom output function because ether_output
+        * can't figure out ifp is a vlan in a reasonable way
+        */
+       m->m_flags |= M_VLANTAG;
+       return (ether_output(ifp, m, dst, rt));
+}
+
 void
 vlan_start(struct ifnet *ifp)
 {
@@ -207,36 +222,6 @@ vlan_start(struct ifnet *ifp)
                        bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
 #endif
 
-               /*
-                * If the IFCAP_VLAN_HWTAGGING capability is set on the parent,
-                * it can do VLAN tag insertion itself and doesn't require us
-                * to create a special header for it. In this case, we just pass
-                * the packet along.
-                */
-               if ((p->if_capabilities & IFCAP_VLAN_HWTAGGING) &&
-                   (ifv->ifv_type == ETHERTYPE_VLAN)) {
-                       m->m_pkthdr.ether_vtag = ifv->ifv_tag +
-                           (m->m_pkthdr.pf.prio << EVL_PRIO_BITS);
-                       m->m_flags |= M_VLANTAG;
-               } else {
-                       struct ether_vlan_header evh;
-
-                       m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&evh);
-                       evh.evl_proto = evh.evl_encap_proto;
-                       evh.evl_encap_proto = htons(ifv->ifv_type);
-                       evh.evl_tag = htons(ifv->ifv_tag +
-                           (m->m_pkthdr.pf.prio << EVL_PRIO_BITS));
-
-                       m_adj(m, ETHER_HDR_LEN);
-                       M_PREPEND(m, sizeof(evh), M_DONTWAIT);
-                       if (m == NULL) {
-                               ifp->if_oerrors++;
-                               continue;
-                       }
-
-                       m_copyback(m, 0, sizeof(evh), &evh, M_NOWAIT);
-               }
-
                /*
                 * Send it, precisely as ether_output() would have.
                 * We are already running at splnet.