diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2020-07-22 01:30:55 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2020-07-22 01:30:55 +0000 |
commit | e38c7eb467620d279f738451e80d8ce868b9a3ca (patch) | |
tree | 1719bf088286c23236d4f6af0b96ae4cbb1b2e8a /sys/net | |
parent | 22ad5c772ea0eaf700df338e6b8d9f1e244ee4c7 (diff) |
move vlan_input into ether_input, instead of via an input handler.
this means there's a consistent order of processing of service
delimited (vlan and svlan) packets and bridging of packets. vlan
and svlan get to look at a packet first. it's only if they decline
a packet that a bridge can handle it. this allows operators to slice
vlans out for processing separate to the "native" vlan handling if
they want.
while here, this fixes up a bug in vlan_input if m_pullup needed
to prepend an mbuf.
this has been in snaps as part of a larger diff for over a week.
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if_ethersubr.c | 46 | ||||
-rw-r--r-- | sys/net/if_vlan.c | 74 | ||||
-rw-r--r-- | sys/net/if_vlan_var.h | 3 |
3 files changed, 75 insertions, 48 deletions
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 942261e88ea..041cc259c05 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ethersubr.c,v 1.263 2020/07/22 00:37:24 dlg Exp $ */ +/* $OpenBSD: if_ethersubr.c,v 1.264 2020/07/22 01:30:54 dlg Exp $ */ /* $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $ */ /* @@ -104,6 +104,11 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>. #include <net/bpf.h> #endif +#include "vlan.h" +#if NVLAN > 0 +#include <net/if_vlan_var.h> +#endif + #include "pppoe.h" #if NPPPOE > 0 #include <net/if_pppoe.h> @@ -357,12 +362,34 @@ ether_input(struct ifnet *ifp, struct mbuf *m, void *cookie) u_int16_t etype; struct arpcom *ac; const struct ether_brport *eb; + unsigned int sdelim = 0; /* Drop short frames */ if (m->m_len < ETHER_HDR_LEN) goto dropanyway; /* + * Let vlan(4) and svlan(4) look at "service delimited" + * packets. If a virtual interface does not exist to take + * those packets, they're returned to ether_input() so a + * bridge can have a go at forwarding them. + */ + + eh = mtod(m, struct ether_header *); + etype = ntohs(eh->ether_type); + + if (ISSET(m->m_flags, M_VLANTAG) || + etype == ETHERTYPE_VLAN || etype == ETHERTYPE_QINQ) { +#if NVLAN > 0 + m = vlan_input(ifp, m); + if (m == NULL) + return (1); +#endif /* NVLAN > 0 */ + + sdelim = 1; + } + + /* * Give the packet to a bridge interface, ie, bridge(4), * switch(4), or tpmr(4), if it is configured. A bridge * may take the packet and forward it to another port, or it @@ -383,6 +410,14 @@ ether_input(struct ifnet *ifp, struct mbuf *m, void *cookie) } smr_read_leave(); + /* + * If the packet has a tag, and a bridge didn't want it, + * it's not for this port. + */ + + if (sdelim) + goto dropanyway; + eh = mtod(m, struct ether_header *); /* Is the packet for us? */ @@ -409,15 +444,6 @@ ether_input(struct ifnet *ifp, struct mbuf *m, void *cookie) ifp->if_imcasts++; } - /* - * HW vlan tagged packets that were not collected by vlan(4) must - * be dropped now. - */ - if (m->m_flags & M_VLANTAG) - goto dropanyway; - - etype = ntohs(eh->ether_type); - switch (etype) { case ETHERTYPE_IP: input = ipv4_input; diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index 577b9d1f0b1..c5a08e63950 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vlan.c,v 1.203 2020/02/01 10:27:40 jmatthew Exp $ */ +/* $OpenBSD: if_vlan.c,v 1.204 2020/07/22 01:30:54 dlg Exp $ */ /* * Copyright 1998 Massachusetts Institute of Technology @@ -119,7 +119,6 @@ void vlanattach(int count); int vlan_clone_create(struct if_clone *, int); int vlan_clone_destroy(struct ifnet *); -int vlan_input(struct ifnet *, struct mbuf *, void *); int vlan_enqueue(struct ifnet *, struct mbuf *); void vlan_start(struct ifqueue *ifq); int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr); @@ -358,44 +357,45 @@ vlan_inject(struct mbuf *m, uint16_t type, uint16_t tag) return (m); } -/* - * vlan_input() returns 1 if it has consumed the packet, 0 otherwise. - */ -int -vlan_input(struct ifnet *ifp0, struct mbuf *m, void *cookie) +struct mbuf * +vlan_input(struct ifnet *ifp0, struct mbuf *m) { struct vlan_softc *sc; + struct ifnet *ifp; struct ether_vlan_header *evl; - struct ether_header *eh; struct vlan_list *tagh, *list; - uint16_t tag; + uint16_t vtag, tag; uint16_t etype; int rxprio; - eh = mtod(m, struct ether_header *); - etype = ntohs(eh->ether_type); - if (m->m_flags & M_VLANTAG) { + vtag = m->m_pkthdr.ether_vtag; etype = ETHERTYPE_VLAN; tagh = vlan_tagh; - } else if ((etype == ETHERTYPE_VLAN) || (etype == ETHERTYPE_QINQ)) { - if (m->m_len < sizeof(*evl) && - (m = m_pullup(m, sizeof(*evl))) == NULL) { - ifp0->if_ierrors++; - return (1); + } else { + if (m->m_len < sizeof(*evl)) { + m = m_pullup(m, sizeof(*evl)); + if (m == NULL) + return (NULL); } evl = mtod(m, struct ether_vlan_header *); - m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag); - tagh = etype == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh; - } else { - /* Skip non-VLAN packets. */ - return (0); + vtag = bemtoh16(&evl->evl_tag); + etype = bemtoh16(&evl->evl_encap_proto); + switch (etype) { + case ETHERTYPE_VLAN: + tagh = vlan_tagh; + break; + case ETHERTYPE_QINQ: + tagh = svlan_tagh; + break; + default: + panic("%s: unexpected etype 0x%04x", __func__, etype); + /* NOTREACHED */ + } } - /* From now on ether_vtag is fine */ - tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); - + tag = EVL_VLANOFTAG(vtag); list = &tagh[TAG_HASH(tag)]; smr_read_enter(); SMR_SLIST_FOREACH(sc, list, sc_list) { @@ -407,7 +407,11 @@ vlan_input(struct ifnet *ifp0, struct mbuf *m, void *cookie) } smr_read_leave(); - if (sc == NULL || !ISSET(sc->sc_if.if_flags, IFF_RUNNING)) { + if (sc == NULL) + return (m); /* decline, let bridge have a go */ + + ifp = &sc->sc_if; + if (!ISSET(ifp->if_flags, IFF_RUNNING)) { m_freem(m); goto leave; } @@ -417,11 +421,11 @@ vlan_input(struct ifnet *ifp0, struct mbuf *m, void *cookie) * the given source interface and vlan tag, remove the * encapsulation. */ - if (m->m_flags & M_VLANTAG) { - m->m_flags &= ~M_VLANTAG; + if (ISSET(m->m_flags, M_VLANTAG)) { + CLR(m->m_flags, M_VLANTAG); } else { - eh->ether_type = evl->evl_proto; - memmove((char *)eh + EVL_ENCAPLEN, eh, sizeof(*eh)); + memmove((caddr_t)evl + EVL_ENCAPLEN, evl, + offsetof(struct ether_vlan_header, evl_encap_proto)); m_adj(m, EVL_ENCAPLEN); } @@ -440,11 +444,10 @@ vlan_input(struct ifnet *ifp0, struct mbuf *m, void *cookie) break; } - if_vinput(&sc->sc_if, m); + if_vinput(ifp, m); leave: - if (sc != NULL) - refcnt_rele_wake(&sc->sc_refcnt); - return (1); + refcnt_rele_wake(&sc->sc_refcnt); + return (NULL); } int @@ -530,8 +533,6 @@ vlan_up(struct vlan_softc *sc) /* configure the parent to handle packets for this vlan */ vlan_multi_apply(sc, ifp0, SIOCADDMULTI); - if_ih_insert(ifp0, vlan_input, NULL); - /* we're running now */ SET(ifp->if_flags, IFF_RUNNING); vlan_link_state(sc, ifp0->if_link_state, ifp0->if_baudrate); @@ -574,7 +575,6 @@ vlan_down(struct vlan_softc *sc) ifp0 = if_get(sc->sc_ifidx0); if (ifp0 != NULL) { - if_ih_remove(ifp0, vlan_input, NULL); if (ISSET(sc->sc_flags, IFVF_PROMISC)) ifpromisc(ifp0, 0); vlan_multi_apply(sc, ifp0, SIOCDELMULTI); diff --git a/sys/net/if_vlan_var.h b/sys/net/if_vlan_var.h index 57c7e519f86..006ff2a822c 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.41 2019/04/27 04:46:03 dlg Exp $ */ +/* $OpenBSD: if_vlan_var.h,v 1.42 2020/07/22 01:30:54 dlg Exp $ */ /* * Copyright 1998 Massachusetts Institute of Technology @@ -47,6 +47,7 @@ struct vlanreq { }; #ifdef _KERNEL +struct mbuf *vlan_input(struct ifnet *, struct mbuf *); struct mbuf *vlan_inject(struct mbuf *, uint16_t, uint16_t); #endif /* _KERNEL */ |