summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2015-05-19 11:09:25 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2015-05-19 11:09:25 +0000
commit762fb384b3ade352fe9721a3a9c2df8a82d9cb59 (patch)
tree9353e3ea93d0be7455f748b6c8c713fcfdcc2b0c /sys
parent60802832c250260ccded740af949b4a849a1a29e (diff)
Take vlan(4) out of ether_input().
To keep the list of input handlers short, multiple vlans share the same ifih. if_input_process() now looks if the interface of a mbuf changed to make sure the corresponding handlers are executed. This is a hack and will be improved later. ok dlg@
Diffstat (limited to 'sys')
-rw-r--r--sys/net/if.c11
-rw-r--r--sys/net/if_ethersubr.c14
-rw-r--r--sys/net/if_var.h3
-rw-r--r--sys/net/if_vlan.c105
-rw-r--r--sys/net/if_vlan_var.h4
5 files changed, 83 insertions, 54 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 6fca91012a2..81461ef6054 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if.c,v 1.331 2015/05/15 10:15:13 mpi Exp $ */
+/* $OpenBSD: if.c,v 1.332 2015/05/19 11:09:24 mpi Exp $ */
/* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */
/*
@@ -530,10 +530,19 @@ if_input_process(void *xmq)
if ((++mit & 0x1f) == 0)
yield();
+again:
+ /*
+ * Pass this mbuf to all input handlers of its
+ * interface until it is consumed.
+ */
ifp = m->m_pkthdr.rcvif;
SLIST_FOREACH(ifih, &ifp->if_inputs, ifih_next) {
if ((*ifih->ifih_input)(m, NULL))
break;
+
+ /* Pseudo-drivers might be stacked. */
+ if (ifp != m->m_pkthdr.rcvif)
+ goto again;
}
}
splx(s);
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 1cf0d1cc37c..1d023091a48 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ethersubr.c,v 1.198 2015/05/15 10:15:13 mpi Exp $ */
+/* $OpenBSD: if_ethersubr.c,v 1.199 2015/05/19 11:09:24 mpi Exp $ */
/* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */
/*
@@ -426,7 +426,7 @@ bad:
int
ether_input(struct mbuf *m, void *hdr)
{
- struct ifnet *ifp0, *ifp;
+ struct ifnet *ifp;
struct ether_header *eh = hdr;
struct niqueue *inq;
u_int16_t etype;
@@ -439,7 +439,7 @@ ether_input(struct mbuf *m, void *hdr)
/* mark incoming routing table */
- ifp = ifp0 = m->m_pkthdr.rcvif;
+ ifp = m->m_pkthdr.rcvif;
m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
if (eh == NULL) {
@@ -481,12 +481,6 @@ ether_input(struct mbuf *m, void *hdr)
atomic_setbits_int(&netisr, (1 << NETISR_RND_DONE));
}
-#if NVLAN > 0
- if (((m->m_flags & M_VLANTAG) || etype == ETHERTYPE_VLAN ||
- etype == ETHERTYPE_QINQ) && (vlan_input(eh, m) == 0))
- return (1);
-#endif
-
#if NBRIDGE > 0
/*
* Tap the packet off here for a bridge, if configured and
@@ -535,7 +529,7 @@ ether_input(struct mbuf *m, void *hdr)
* is for us. Drop otherwise.
*/
if ((m->m_flags & (M_BCAST|M_MCAST)) == 0 &&
- ((ifp->if_flags & IFF_PROMISC) || (ifp0->if_flags & IFF_PROMISC))) {
+ (ifp->if_flags & IFF_PROMISC)) {
if (memcmp(ac->ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN)) {
m_freem(m);
return (1);
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index 8529152ba27..a775c65a117 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_var.h,v 1.28 2015/05/18 13:32:28 reyk Exp $ */
+/* $OpenBSD: if_var.h,v 1.29 2015/05/19 11:09:24 mpi Exp $ */
/* $NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $ */
/*
@@ -115,6 +115,7 @@ struct ifqueue {
struct ifih {
SLIST_ENTRY(ifih) ifih_next;
int (*ifih_input)(struct mbuf *, void *);
+ int ifih_refcnt;
};
/*
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 825c36d90ab..55544842a01 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_vlan.c,v 1.119 2015/05/15 10:15:13 mpi Exp $ */
+/* $OpenBSD: if_vlan.c,v 1.120 2015/05/19 11:09:24 mpi Exp $ */
/*
* Copyright 1998 Massachusetts Institute of Technology
@@ -79,6 +79,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_input(struct mbuf *, void *);
int vlan_output(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
void vlan_start(struct ifnet *ifp);
@@ -255,32 +257,44 @@ vlan_start(struct ifnet *ifp)
}
/*
- * vlan_input() returns 0 if it has consumed the packet, 1 otherwise.
+ * vlan_input() returns 1 if it has consumed the packet, 0 otherwise.
*/
int
-vlan_input(struct ether_header *eh, struct mbuf *m)
+vlan_input(struct mbuf *m, void *hdr)
{
- struct ifvlan *ifv;
- struct ifnet *ifp = m->m_pkthdr.rcvif;
- struct vlan_taghash *tagh;
- u_int tag;
- u_int16_t etype;
- struct ether_header *eh1;
+ struct ifvlan *ifv;
+ struct ifnet *ifp;
+ struct ether_vlan_header *evl;
+ struct ether_header *eh;
+ struct vlan_taghash *tagh;
+ u_int tag;
+ u_int16_t etype;
+
+ ifp = m->m_pkthdr.rcvif;
+ eh = mtod(m, struct ether_header *);
+
+ etype = ntohs(eh->ether_type);
if (m->m_flags & M_VLANTAG) {
etype = ETHERTYPE_VLAN;
tagh = vlan_tagh;
- } else {
+ } else if ((etype == ETHERTYPE_VLAN) || (etype == ETHERTYPE_QINQ)) {
if (m->m_len < EVL_ENCAPLEN &&
(m = m_pullup(m, EVL_ENCAPLEN)) == NULL) {
ifp->if_ierrors++;
- return (0);
+ return (1);
}
- etype = ntohs(eh->ether_type);
+ evl = mtod(m, struct ether_vlan_header *);
+ m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag);
tagh = etype == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
- m->m_pkthdr.ether_vtag = ntohs(*mtod(m, u_int16_t *));
+ } else {
+ /* Skip non-VLAN packets. */
+ return (0);
}
+
+ ifp->if_ibytes += m->m_pkthdr.len;
+
/* From now on ether_vtag is fine */
tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
m->m_pkthdr.pf.prio = EVL_PRIOFTAG(m->m_pkthdr.ether_vtag);
@@ -290,7 +304,7 @@ vlan_input(struct ether_header *eh, struct mbuf *m)
m->m_pkthdr.pf.prio = !m->m_pkthdr.pf.prio;
LIST_FOREACH(ifv, &tagh[TAG_HASH(tag)], ifv_list) {
- if (m->m_pkthdr.rcvif == ifv->ifv_p && tag == ifv->ifv_tag &&
+ if (ifp == ifv->ifv_p && tag == ifv->ifv_tag &&
etype == ifv->ifv_type)
break;
}
@@ -302,40 +316,35 @@ vlan_input(struct ether_header *eh, struct mbuf *m)
* it a chance.
*/
if (ifp->if_bridgeport && (m->m_flags & M_PROTO1) == 0)
- return (1);
+ return (0);
#endif
ifp->if_noproto++;
m_freem(m);
- return (0);
+ return (1);
}
if ((ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
(IFF_UP|IFF_RUNNING)) {
m_freem(m);
- return (0);
+ return (1);
}
/*
* Having found a valid vlan interface corresponding to
* the given source interface and vlan tag, remove the
- * encapsulation, and run the real packet through
- * ether_input() a second time (it had better be
- * reentrant!).
+ * encapsulation.
*/
- m->m_pkthdr.rcvif = &ifv->ifv_if;
if (m->m_flags & M_VLANTAG) {
m->m_flags &= ~M_VLANTAG;
} else {
- eh->ether_type = mtod(m, u_int16_t *)[1];
- m->m_len -= EVL_ENCAPLEN;
- m->m_data += EVL_ENCAPLEN;
- m->m_pkthdr.len -= EVL_ENCAPLEN;
+ eh->ether_type = evl->evl_proto;
+ memmove((char *)eh + EVL_ENCAPLEN, eh, sizeof(*eh));
+ m_adj(m, EVL_ENCAPLEN);
}
#if NBPFILTER > 0
if (ifv->ifv_if.if_bpf)
- bpf_mtap_hdr(ifv->ifv_if.if_bpf, (char *)eh, ETHER_HDR_LEN, m,
- BPF_DIRECTION_IN, NULL);
+ bpf_mtap_ether(ifv->ifv_if.if_bpf, m, BPF_DIRECTION_IN);
#endif
/*
@@ -348,25 +357,19 @@ vlan_input(struct ether_header *eh, struct mbuf *m)
if (bcmp(&ifv->ifv_ac.ac_enaddr, eh->ether_dhost,
ETHER_ADDR_LEN)) {
m_freem(m);
- return (0);
+ return (1);
}
}
- M_PREPEND(m, sizeof(*eh1), M_DONTWAIT);
- if (m == NULL)
- return (-1);
- eh1 = mtod(m, struct ether_header *);
- memmove(eh1, eh, sizeof(*eh1));
-
ifv->ifv_if.if_ipackets++;
- ether_input_mbuf(&ifv->ifv_if, m);
-
+ m->m_pkthdr.rcvif = &ifv->ifv_if;
return (0);
}
int
vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag)
{
+ struct ifih *vlan_ifih;
struct sockaddr_dl *sdl1, *sdl2;
struct vlan_taghash *tagh;
u_int flags;
@@ -377,6 +380,16 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag)
if (ifv->ifv_p == p && ifv->ifv_tag == tag) /* noop */
return (0);
+ /* Share an ifih between multiple vlan(4) instances. */
+ vlan_ifih = SLIST_FIRST(&p->if_inputs);
+ if (vlan_ifih->ifih_input != vlan_input) {
+ vlan_ifih = malloc(sizeof(*vlan_ifih), M_DEVBUF, M_NOWAIT);
+ if (vlan_ifih == NULL)
+ return (ENOMEM);
+ vlan_ifih->ifih_input = vlan_input;
+ vlan_ifih->ifih_refcnt = 0;
+ }
+
/* Remember existing interface flags and reset the interface */
flags = ifv->ifv_flags;
vlan_unconfig(&ifv->ifv_if, p);
@@ -428,9 +441,10 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag)
bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
ifv->ifv_tag = tag;
- s = splnet();
- tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
- LIST_INSERT_HEAD(&tagh[TAG_HASH(tag)], ifv, ifv_list);
+
+ /* Change input handler of the physical interface. */
+ if (++vlan_ifih->ifih_refcnt == 1)
+ SLIST_INSERT_HEAD(&p->if_inputs, vlan_ifih, ifih_next);
/* Register callback for physical link state changes */
ifv->lh_cookie = hook_establish(p->if_linkstatehooks, 1,
@@ -441,6 +455,10 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag)
vlan_ifdetach, ifv);
vlan_vlandev_state(ifv);
+
+ tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
+ s = splnet();
+ LIST_INSERT_HEAD(&tagh[TAG_HASH(tag)], ifv, ifv_list);
splx(s);
return (0);
@@ -449,6 +467,7 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag)
int
vlan_unconfig(struct ifnet *ifp, struct ifnet *newp)
{
+ struct ifih *vlan_ifih;
struct sockaddr_dl *sdl;
struct ifvlan *ifv;
struct ifnet *p;
@@ -476,6 +495,14 @@ vlan_unconfig(struct ifnet *ifp, struct ifnet *newp)
if_link_state_change(ifp);
}
+ /* Restore previous input handler. */
+ vlan_ifih = SLIST_FIRST(&p->if_inputs);
+ KASSERT(vlan_ifih->ifih_input == vlan_input);
+ if (--vlan_ifih->ifih_refcnt == 0) {
+ SLIST_REMOVE_HEAD(&p->if_inputs, ifih_next);
+ free(vlan_ifih, M_DEVBUF, sizeof(*vlan_ifih));
+ }
+
/*
* Since the interface is being unconfigured, we need to
* empty the list of multicast groups that we may have joined
diff --git a/sys/net/if_vlan_var.h b/sys/net/if_vlan_var.h
index 65a079d2a45..f02540d42b9 100644
--- a/sys/net/if_vlan_var.h
+++ b/sys/net/if_vlan_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_vlan_var.h,v 1.24 2013/10/24 11:14:33 deraadt Exp $ */
+/* $OpenBSD: if_vlan_var.h,v 1.25 2015/05/19 11:09:24 mpi Exp $ */
/*
* Copyright 1998 Massachusetts Institute of Technology
@@ -94,8 +94,6 @@ struct ifvlan {
#define ifv_prio ifv_mib.ifvm_prio
#define ifv_type ifv_mib.ifvm_type
#define IFVF_PROMISC 0x01
-
-extern int vlan_input(struct ether_header *eh, struct mbuf *m);
#endif /* _KERNEL */
#endif /* _NET_IF_VLAN_VAR_H_ */