diff options
author | 2019-01-09 01:17:09 +0000 | |
---|---|---|
committer | 2019-01-09 01:17:09 +0000 | |
commit | eae94ed9eb20340a7671c85fe8b740c016831614 (patch) | |
tree | 976d200a845a19d168e0f58dd7d44fe7fb40c249 | |
parent | split if_enqueue up so drivers can replace ifq handling if needed (diff) | |
download | wireguard-openbsd-eae94ed9eb20340a7671c85fe8b740c016831614.tar.xz wireguard-openbsd-eae94ed9eb20340a7671c85fe8b740c016831614.zip |
implement an if_enqueue handler for vlan(4)
this allows vlan packets to bypass the ifq handling, which allows
packets to be encapsulated concurrently by any context. the code
falls back to ifqs if hfsc is enabled on the vlan interface, otherwise
it encaps the packet immedate and enqueues it on the parent interface.
hrove popovski has seen a performance bump in certain configurations
from this change.
ok mpi@
no objections claudio@
-rw-r--r-- | sys/net/if_vlan.c | 138 |
1 files changed, 85 insertions, 53 deletions
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index 9a6b1d20909..9b1b1981b41 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vlan.c,v 1.179 2018/11/16 08:43:08 dlg Exp $ */ +/* $OpenBSD: if_vlan.c,v 1.180 2019/01/09 01:17:09 dlg Exp $ */ /* * Copyright 1998 Massachusetts Institute of Technology @@ -58,6 +58,7 @@ #include <sys/sockio.h> #include <sys/systm.h> #include <sys/rwlock.h> +#include <sys/percpu.h> #include <net/if.h> #include <net/if_dl.h> @@ -85,6 +86,7 @@ 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); @@ -178,9 +180,12 @@ vlan_clone_create(struct if_clone *ifc, int unit) ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST; ifp->if_xflags = IFXF_CLONED|IFXF_MPSAFE; ifp->if_qstart = vlan_start; + ifp->if_enqueue = vlan_enqueue; ifp->if_ioctl = vlan_ioctl; ifp->if_hardmtu = 0xffff; ifp->if_link_state = LINK_STATE_DOWN; + + if_counters_alloc(ifp); if_attach(ifp); ether_ifattach(ifp); ifp->if_hdrlen = EVL_ENCAPLEN; @@ -240,70 +245,97 @@ vlan_mplstunnel(int ifidx) } void -vlan_start(struct ifqueue *ifq) +vlan_transmit(struct ifvlan *ifv, struct ifnet *ifp0, struct mbuf *m) { - struct ifnet *ifp = ifq->ifq_if; - struct ifvlan *ifv; - struct ifnet *ifp0; - struct mbuf *m; - int txprio; - uint8_t prio; - - ifv = ifp->if_softc; - ifp0 = if_get(ifv->ifv_ifp0); - if (ifp0 == NULL || (ifp0->if_flags & (IFF_UP|IFF_RUNNING)) != - (IFF_UP|IFF_RUNNING)) { - ifq_purge(ifq); - goto leave; - } - - txprio = ifv->ifv_prio; + struct ifnet *ifp = &ifv->ifv_if; + int txprio = ifv->ifv_prio; + uint8_t prio; - while ((m = ifq_dequeue(ifq)) != NULL) { #if NBPFILTER > 0 - if (ifp->if_bpf) - bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT); + if (ifp->if_bpf) + bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT); #endif /* NBPFILTER > 0 */ - prio = (txprio == IF_HDRPRIO_PACKET) ? - m->m_pkthdr.pf.prio : txprio; + prio = (txprio == IF_HDRPRIO_PACKET) ? + m->m_pkthdr.pf.prio : txprio; - /* IEEE 802.1p has prio 0 and 1 swapped */ - if (prio <= 1) - prio = !prio; + /* IEEE 802.1p has prio 0 and 1 swapped */ + if (prio <= 1) + prio = !prio; - /* - * If this packet came from a pseudowire it means it already - * has all tags it needs, so just output it. - */ - if (vlan_mplstunnel(m->m_pkthdr.ph_ifidx)) { - /* NOTHING */ + /* + * If this packet came from a pseudowire it means it already + * has all tags it needs, so just output it. + */ + if (vlan_mplstunnel(m->m_pkthdr.ph_ifidx)) { + /* NOTHING */ - /* - * If the underlying interface cannot do VLAN tag insertion - * itself, create an encapsulation header. - */ - } else if ((ifp0->if_capabilities & IFCAP_VLAN_HWTAGGING) && - (ifv->ifv_type == ETHERTYPE_VLAN)) { - m->m_pkthdr.ether_vtag = ifv->ifv_tag + - (prio << EVL_PRIO_BITS); - m->m_flags |= M_VLANTAG; - } else { - m = vlan_inject(m, ifv->ifv_type, ifv->ifv_tag | - (prio << EVL_PRIO_BITS)); - if (m == NULL) { - ifp->if_oerrors++; - continue; - } + /* + * If the underlying interface cannot do VLAN tag insertion + * itself, create an encapsulation header. + */ + } else if ((ifp0->if_capabilities & IFCAP_VLAN_HWTAGGING) && + (ifv->ifv_type == ETHERTYPE_VLAN)) { + m->m_pkthdr.ether_vtag = ifv->ifv_tag + + (prio << EVL_PRIO_BITS); + m->m_flags |= M_VLANTAG; + } else { + m = vlan_inject(m, ifv->ifv_type, ifv->ifv_tag | + (prio << EVL_PRIO_BITS)); + if (m == NULL) { + counters_inc(ifp->if_counters, ifc_oerrors); + return; } + } - if (if_enqueue(ifp0, m)) { - ifp->if_oerrors++; - ifq->ifq_errors++; - continue; - } + if (if_enqueue(ifp0, m)) + counters_inc(ifp->if_counters, ifc_oerrors); +} + +int +vlan_enqueue(struct ifnet *ifp, struct mbuf *m) +{ + struct ifnet *ifp0; + struct ifvlan *ifv; + int error = 0; + + if (!ifq_is_priq(&ifp->if_snd)) + return (if_enqueue_ifq(ifp, m)); + + ifv = ifp->if_softc; + ifp0 = if_get(ifv->ifv_ifp0); + + if (ifp0 == NULL || !ISSET(ifp0->if_flags, IFF_RUNNING)) { + m_freem(m); + error = ENETDOWN; + } else { + counters_pkt(ifp->if_counters, + ifc_opackets, ifc_obytes, m->m_pkthdr.len); + vlan_transmit(ifv, ifp0, m); + } + + if_put(ifp0); + + return (error); +} + +void +vlan_start(struct ifqueue *ifq) +{ + struct ifnet *ifp = ifq->ifq_if; + struct ifvlan *ifv = ifp->if_softc; + struct ifnet *ifp0; + struct mbuf *m; + + ifp0 = if_get(ifv->ifv_ifp0); + if (ifp0 == NULL || !ISSET(ifp0->if_flags, IFF_RUNNING)) { + ifq_purge(ifq); + goto leave; } + while ((m = ifq_dequeue(ifq)) != NULL) + vlan_transmit(ifv, ifp0, m); + leave: if_put(ifp0); } |