summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorHenning Brauer <henning@cvs.openbsd.org>2014-04-22 11:43:08 +0000
committerHenning Brauer <henning@cvs.openbsd.org>2014-04-22 11:43:08 +0000
commitc95c9b9f82d8cc3a427ad8bc37629bb19cfd6ac0 (patch)
tree8873b9bd849e5074b65331005e8f729bc6d7127b /sys/net
parent8f4df1fbfc932a752f11d5cd4a6817aee51ea31f (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.c40
-rw-r--r--sys/net/if_vlan.c47
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.
*/