so, on vlan, to insert the vlan tag, we right now: -copy (most of) the existing ethernet header into a ether_vlan_header on the stack -fill the extra fields (tag, inside ether type) 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. now it turns out it is trivial 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. you need a very current src tree to test this, relies on the code shuffling in if_ethersubr.c I did a few hours ago. Index: net/if_ethersubr.c =================================================================== RCS file: /cvs/src/sys/net/if_ethersubr.c,v retrieving revision 1.168 diff -u -p -r1.168 if_ethersubr.c --- net/if_ethersubr.c 20 Apr 2014 15:29:52 -0000 1.168 +++ net/if_ethersubr.c 20 Apr 2014 16:21:46 -0000 @@ -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 ar } 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 (ifp->if_type == IFT_L2VLAN) { + 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); + (*m)->m_flags |= M_VLANTAG; + /* 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)); + return (0); + } + } +#endif + M_PREPEND(*m, ETHER_HDR_LEN, M_DONTWAIT); if (*m == 0) return (-1); @@ -366,7 +396,7 @@ ether_output(struct ifnet *ifp0, struct 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: net/if_vlan.c =================================================================== RCS file: /cvs/src/sys/net/if_vlan.c,v retrieving revision 1.102 diff -u -p -r1.102 if_vlan.c --- net/if_vlan.c 10 Mar 2014 12:21:35 -0000 1.102 +++ net/if_vlan.c 20 Apr 2014 16:21:46 -0000 @@ -206,36 +206,6 @@ vlan_start(struct ifnet *ifp) if (ifp->if_bpf) 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. -- Henning Brauer, h...@bsws.de, henn...@openbsd.org BS Web Services GmbH, http://bsws.de, Full-Service ISP Secure Hosting, Mail and DNS Services. Dedicated Servers, Root to Fully Managed Henning Brauer Consulting, http://henningbrauer.com/