diff options
author | Henning Brauer <henning@cvs.openbsd.org> | 2014-04-22 11:43:08 +0000 |
---|---|---|
committer | Henning Brauer <henning@cvs.openbsd.org> | 2014-04-22 11:43:08 +0000 |
commit | c95c9b9f82d8cc3a427ad8bc37629bb19cfd6ac0 (patch) | |
tree | 8873b9bd849e5074b65331005e8f729bc6d7127b /sys/net | |
parent | 8f4df1fbfc932a752f11d5cd4a6817aee51ea31f (diff) |
we used to handle the vlan tag etc insertion very very very late,
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@
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if_ethersubr.c | 40 | ||||
-rw-r--r-- | sys/net/if_vlan.c | 47 |
2 files changed, 51 insertions, 36 deletions
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 09fb772a4fa..1a473cc6571 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -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 diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index 274364993b1..2c9bb1284cf 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -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) { @@ -208,36 +223,6 @@ vlan_start(struct ifnet *ifp) #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. */ |