On Sun, Apr 20, 2014 at 06:45:46PM +0200, Henning Brauer wrote: > 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 *); >
__inline is dead long live inline. > 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 Would it make sense to put this into a vlan_encap function so that we can reduce the amount of layer violation here? #if NVLAN > 0 if (ifp->if_type == IFT_L2VLAN) return vlan_encap(ifp, m); #endif We could also add a ifp->if_encap function pointer but if it is just for vlan(4) I see no point in it. -- :wq Claudio