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