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

Reply via email to