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, [email protected], [email protected]
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/