198c230c8SBjoern A. Zeeb /*- 298c230c8SBjoern A. Zeeb * Copyright (c) 2008 The FreeBSD Foundation 3d0ea4743SBjoern A. Zeeb * Copyright (c) 2009 Bjoern A. Zeeb <bz@FreeBSD.org> 498c230c8SBjoern A. Zeeb * All rights reserved. 598c230c8SBjoern A. Zeeb * 698c230c8SBjoern A. Zeeb * This software was developed by CK Software GmbH under sponsorship 798c230c8SBjoern A. Zeeb * from the FreeBSD Foundation. 898c230c8SBjoern A. Zeeb * 998c230c8SBjoern A. Zeeb * Redistribution and use in source and binary forms, with or without 1098c230c8SBjoern A. Zeeb * modification, are permitted provided that the following conditions 1198c230c8SBjoern A. Zeeb * are met: 1298c230c8SBjoern A. Zeeb * 1. Redistributions of source code must retain the above copyright 1398c230c8SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer. 1498c230c8SBjoern A. Zeeb * 2. Redistributions in binary form must reproduce the above copyright 1598c230c8SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer in the 1698c230c8SBjoern A. Zeeb * documentation and/or other materials provided with the distribution. 1798c230c8SBjoern A. Zeeb * 1898c230c8SBjoern A. Zeeb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1998c230c8SBjoern A. Zeeb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2098c230c8SBjoern A. Zeeb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2198c230c8SBjoern A. Zeeb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2298c230c8SBjoern A. Zeeb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2398c230c8SBjoern A. Zeeb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2498c230c8SBjoern A. Zeeb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2598c230c8SBjoern A. Zeeb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2698c230c8SBjoern A. Zeeb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2798c230c8SBjoern A. Zeeb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2898c230c8SBjoern A. Zeeb * SUCH DAMAGE. 2998c230c8SBjoern A. Zeeb */ 3098c230c8SBjoern A. Zeeb 3198c230c8SBjoern A. Zeeb /* 32d0ea4743SBjoern A. Zeeb * A pair of virtual back-to-back connected ethernet like interfaces 33d0ea4743SBjoern A. Zeeb * (``two interfaces with a virtual cross-over cable''). 34d0ea4743SBjoern A. Zeeb * 3598c230c8SBjoern A. Zeeb * This is mostly intended to be used to provide connectivity between 3698c230c8SBjoern A. Zeeb * different virtual network stack instances. 3798c230c8SBjoern A. Zeeb */ 3898c230c8SBjoern A. Zeeb /* 3998c230c8SBjoern A. Zeeb * Things to re-think once we have more experience: 40d0ea4743SBjoern A. Zeeb * - ifp->if_reassign function once we can test with vimage. Depending on 41d0ea4743SBjoern A. Zeeb * how if_vomve() is going to be improved. 42d0ea4743SBjoern A. Zeeb * - Real random etheraddrs that are checked to be uniquish; we would need 43d0ea4743SBjoern A. Zeeb * to re-do them in case we move the interface between network stacks 44d0ea4743SBjoern A. Zeeb * in a private if_reassign function. 45d0ea4743SBjoern A. Zeeb * In case we bridge to a real interface/network or between indepedent 46d0ea4743SBjoern A. Zeeb * epairs on multiple stacks/machines, we may need this. 47d0ea4743SBjoern A. Zeeb * For now let the user handle that case. 4898c230c8SBjoern A. Zeeb */ 4998c230c8SBjoern A. Zeeb 5098c230c8SBjoern A. Zeeb #include <sys/cdefs.h> 5198c230c8SBjoern A. Zeeb __FBSDID("$FreeBSD$"); 5298c230c8SBjoern A. Zeeb 5398c230c8SBjoern A. Zeeb #include <sys/param.h> 5498c230c8SBjoern A. Zeeb #include <sys/kernel.h> 5598c230c8SBjoern A. Zeeb #include <sys/mbuf.h> 5698c230c8SBjoern A. Zeeb #include <sys/module.h> 5798c230c8SBjoern A. Zeeb #include <sys/refcount.h> 5898c230c8SBjoern A. Zeeb #include <sys/queue.h> 59d0ea4743SBjoern A. Zeeb #include <sys/smp.h> 6098c230c8SBjoern A. Zeeb #include <sys/socket.h> 6198c230c8SBjoern A. Zeeb #include <sys/sockio.h> 6298c230c8SBjoern A. Zeeb #include <sys/sysctl.h> 6398c230c8SBjoern A. Zeeb #include <sys/types.h> 6498c230c8SBjoern A. Zeeb #include <sys/vimage.h> 6598c230c8SBjoern A. Zeeb 6698c230c8SBjoern A. Zeeb #include <net/bpf.h> 6798c230c8SBjoern A. Zeeb #include <net/ethernet.h> 6898c230c8SBjoern A. Zeeb #include <net/if.h> 6998c230c8SBjoern A. Zeeb #include <net/if_clone.h> 7098c230c8SBjoern A. Zeeb #include <net/if_var.h> 7198c230c8SBjoern A. Zeeb #include <net/if_types.h> 7298c230c8SBjoern A. Zeeb #include <net/netisr.h> 7398c230c8SBjoern A. Zeeb 7498c230c8SBjoern A. Zeeb #define EPAIRNAME "epair" 7598c230c8SBjoern A. Zeeb 7698c230c8SBjoern A. Zeeb SYSCTL_DECL(_net_link); 7798c230c8SBjoern A. Zeeb SYSCTL_NODE(_net_link, OID_AUTO, epair, CTLFLAG_RW, 0, "epair sysctl"); 78d0ea4743SBjoern A. Zeeb 79d0ea4743SBjoern A. Zeeb #ifdef EPAIR_DEBUG 80d0ea4743SBjoern A. Zeeb static int epair_debug = 0; 8198c230c8SBjoern A. Zeeb SYSCTL_XINT(_net_link_epair, OID_AUTO, epair_debug, CTLFLAG_RW, 8298c230c8SBjoern A. Zeeb &epair_debug, 0, "if_epair(4) debugging."); 83d0ea4743SBjoern A. Zeeb #define DPRINTF(fmt, arg...) \ 84d0ea4743SBjoern A. Zeeb if (epair_debug) \ 8598c230c8SBjoern A. Zeeb printf("[%s:%d] " fmt, __func__, __LINE__, ##arg) 8698c230c8SBjoern A. Zeeb #else 8798c230c8SBjoern A. Zeeb #define DPRINTF(fmt, arg...) 8898c230c8SBjoern A. Zeeb #endif 8998c230c8SBjoern A. Zeeb 90d0ea4743SBjoern A. Zeeb static void epair_nh_sintr(struct mbuf *); 91d0ea4743SBjoern A. Zeeb static struct mbuf *epair_nh_m2cpuid(struct mbuf *, uintptr_t, u_int *); 92d0ea4743SBjoern A. Zeeb static void epair_nh_drainedcpu(u_int); 9398c230c8SBjoern A. Zeeb 94d0ea4743SBjoern A. Zeeb static void epair_start_locked(struct ifnet *); 9598c230c8SBjoern A. Zeeb 9698c230c8SBjoern A. Zeeb static int epair_clone_match(struct if_clone *, const char *); 9798c230c8SBjoern A. Zeeb static int epair_clone_create(struct if_clone *, char *, size_t, caddr_t); 9898c230c8SBjoern A. Zeeb static int epair_clone_destroy(struct if_clone *, struct ifnet *); 9998c230c8SBjoern A. Zeeb 100d0ea4743SBjoern A. Zeeb /* Netisr realted definitions and sysctl. */ 101d0ea4743SBjoern A. Zeeb static struct netisr_handler epair_nh = { 102d0ea4743SBjoern A. Zeeb .nh_name = EPAIRNAME, 103d0ea4743SBjoern A. Zeeb .nh_proto = NETISR_EPAIR, 104d0ea4743SBjoern A. Zeeb .nh_policy = NETISR_POLICY_CPU, 105d0ea4743SBjoern A. Zeeb .nh_handler = epair_nh_sintr, 106d0ea4743SBjoern A. Zeeb .nh_m2cpuid = epair_nh_m2cpuid, 107d0ea4743SBjoern A. Zeeb .nh_drainedcpu = epair_nh_drainedcpu, 108d0ea4743SBjoern A. Zeeb }; 109d0ea4743SBjoern A. Zeeb 110d0ea4743SBjoern A. Zeeb static int 111d0ea4743SBjoern A. Zeeb sysctl_epair_netisr_maxqlen(SYSCTL_HANDLER_ARGS) 112d0ea4743SBjoern A. Zeeb { 113d0ea4743SBjoern A. Zeeb int error, qlimit; 114d0ea4743SBjoern A. Zeeb 115d0ea4743SBjoern A. Zeeb netisr_getqlimit(&epair_nh, &qlimit); 116d0ea4743SBjoern A. Zeeb error = sysctl_handle_int(oidp, &qlimit, 0, req); 117d0ea4743SBjoern A. Zeeb if (error || !req->newptr) 118d0ea4743SBjoern A. Zeeb return (error); 119d0ea4743SBjoern A. Zeeb if (qlimit < 1) 120d0ea4743SBjoern A. Zeeb return (EINVAL); 121d0ea4743SBjoern A. Zeeb return (netisr_setqlimit(&epair_nh, qlimit)); 122d0ea4743SBjoern A. Zeeb } 123d0ea4743SBjoern A. Zeeb SYSCTL_PROC(_net_link_epair, OID_AUTO, netisr_maxqlen, CTLTYPE_INT|CTLFLAG_RW, 124d0ea4743SBjoern A. Zeeb 0, 0, sysctl_epair_netisr_maxqlen, "I", 125d0ea4743SBjoern A. Zeeb "Maximum if_epair(4) netisr \"hw\" queue length"); 126d0ea4743SBjoern A. Zeeb 127d0ea4743SBjoern A. Zeeb struct epair_softc { 128d0ea4743SBjoern A. Zeeb struct ifnet *ifp; /* This ifp. */ 129d0ea4743SBjoern A. Zeeb struct ifnet *oifp; /* other ifp of pair. */ 130d0ea4743SBjoern A. Zeeb u_int refcount; /* # of mbufs in flight. */ 131d0ea4743SBjoern A. Zeeb u_int cpuid; /* CPU ID assigned upon creation. */ 132d0ea4743SBjoern A. Zeeb void (*if_qflush)(struct ifnet *); 133d0ea4743SBjoern A. Zeeb /* Original if_qflush routine. */ 134d0ea4743SBjoern A. Zeeb }; 135d0ea4743SBjoern A. Zeeb 136d0ea4743SBjoern A. Zeeb /* 137d0ea4743SBjoern A. Zeeb * Per-CPU list of ifps with data in the ifq that needs to be flushed 138d0ea4743SBjoern A. Zeeb * to the netisr ``hw'' queue before we allow any further direct queuing 139d0ea4743SBjoern A. Zeeb * to the ``hw'' queue. 140d0ea4743SBjoern A. Zeeb */ 141d0ea4743SBjoern A. Zeeb struct epair_ifp_drain { 142d0ea4743SBjoern A. Zeeb STAILQ_ENTRY(epair_ifp_drain) ifp_next; 143d0ea4743SBjoern A. Zeeb struct ifnet *ifp; 144d0ea4743SBjoern A. Zeeb }; 145d0ea4743SBjoern A. Zeeb STAILQ_HEAD(eid_list, epair_ifp_drain); 146d0ea4743SBjoern A. Zeeb 147d0ea4743SBjoern A. Zeeb #define EPAIR_LOCK_INIT(dpcpu) mtx_init(&(dpcpu)->if_epair_mtx, \ 148d0ea4743SBjoern A. Zeeb "if_epair", NULL, MTX_DEF) 149d0ea4743SBjoern A. Zeeb #define EPAIR_LOCK_DESTROY(dpcpu) mtx_destroy(&(dpcpu)->if_epair_mtx) 150d0ea4743SBjoern A. Zeeb #define EPAIR_LOCK_ASSERT(dpcpu) mtx_assert(&(dpcpu)->if_epair_mtx, \ 151d0ea4743SBjoern A. Zeeb MA_OWNED) 152d0ea4743SBjoern A. Zeeb #define EPAIR_LOCK(dpcpu) mtx_lock(&(dpcpu)->if_epair_mtx) 153d0ea4743SBjoern A. Zeeb #define EPAIR_UNLOCK(dpcpu) mtx_unlock(&(dpcpu)->if_epair_mtx) 154d0ea4743SBjoern A. Zeeb 155d0ea4743SBjoern A. Zeeb #ifdef INVARIANTS 156d0ea4743SBjoern A. Zeeb #define EPAIR_REFCOUNT_INIT(r, v) refcount_init((r), (v)) 157d0ea4743SBjoern A. Zeeb #define EPAIR_REFCOUNT_AQUIRE(r) refcount_acquire((r)) 158d0ea4743SBjoern A. Zeeb #define EPAIR_REFCOUNT_RELEASE(r) refcount_release((r)) 159d0ea4743SBjoern A. Zeeb #define EPAIR_REFCOUNT_ASSERT(a, p) KASSERT(a, p) 160d0ea4743SBjoern A. Zeeb #else 161d0ea4743SBjoern A. Zeeb #define EPAIR_REFCOUNT_INIT(r, v) 162d0ea4743SBjoern A. Zeeb #define EPAIR_REFCOUNT_AQUIRE(r) 163d0ea4743SBjoern A. Zeeb #define EPAIR_REFCOUNT_RELEASE(r) 164d0ea4743SBjoern A. Zeeb #define EPAIR_REFCOUNT_ASSERT(a, p) 165d0ea4743SBjoern A. Zeeb #endif 166d0ea4743SBjoern A. Zeeb 167d0ea4743SBjoern A. Zeeb static MALLOC_DEFINE(M_EPAIR, EPAIRNAME, 168d0ea4743SBjoern A. Zeeb "Pair of virtual cross-over connected Ethernet-like interfaces"); 16998c230c8SBjoern A. Zeeb 17098c230c8SBjoern A. Zeeb static struct if_clone epair_cloner = IFC_CLONE_INITIALIZER( 17198c230c8SBjoern A. Zeeb EPAIRNAME, NULL, IF_MAXUNIT, 17298c230c8SBjoern A. Zeeb NULL, epair_clone_match, epair_clone_create, epair_clone_destroy); 17398c230c8SBjoern A. Zeeb 174d0ea4743SBjoern A. Zeeb /* 175d0ea4743SBjoern A. Zeeb * DPCPU area and functions. 176d0ea4743SBjoern A. Zeeb */ 177d0ea4743SBjoern A. Zeeb struct epair_dpcpu { 178d0ea4743SBjoern A. Zeeb struct mtx if_epair_mtx; /* Per-CPU locking. */ 179d0ea4743SBjoern A. Zeeb int epair_drv_flags; /* Per-CPU ``hw'' drv flags. */ 180d0ea4743SBjoern A. Zeeb struct eid_list epair_ifp_drain_list; /* Per-CPU list of ifps with 181d0ea4743SBjoern A. Zeeb * data in the ifq. */ 182d0ea4743SBjoern A. Zeeb }; 183d0ea4743SBjoern A. Zeeb DPCPU_DEFINE(struct epair_dpcpu, epair_dpcpu); 184d0ea4743SBjoern A. Zeeb 185d0ea4743SBjoern A. Zeeb static void 186d0ea4743SBjoern A. Zeeb epair_dpcpu_init(void) 187d0ea4743SBjoern A. Zeeb { 188d0ea4743SBjoern A. Zeeb struct epair_dpcpu *epair_dpcpu; 189d0ea4743SBjoern A. Zeeb struct eid_list *s; 190d0ea4743SBjoern A. Zeeb u_int cpuid; 191d0ea4743SBjoern A. Zeeb 192d0ea4743SBjoern A. Zeeb for (cpuid = 0; cpuid <= mp_maxid; cpuid++) { 193d0ea4743SBjoern A. Zeeb if (CPU_ABSENT(cpuid)) 194d0ea4743SBjoern A. Zeeb continue; 195d0ea4743SBjoern A. Zeeb 196d0ea4743SBjoern A. Zeeb epair_dpcpu = DPCPU_ID_PTR(cpuid, epair_dpcpu); 197d0ea4743SBjoern A. Zeeb 198d0ea4743SBjoern A. Zeeb /* Initialize per-cpu lock. */ 199d0ea4743SBjoern A. Zeeb EPAIR_LOCK_INIT(epair_dpcpu); 200d0ea4743SBjoern A. Zeeb 201d0ea4743SBjoern A. Zeeb /* Driver flags are per-cpu as are our netisr "hw" queues. */ 202d0ea4743SBjoern A. Zeeb epair_dpcpu->epair_drv_flags = 0; 203d0ea4743SBjoern A. Zeeb 204d0ea4743SBjoern A. Zeeb /* 205d0ea4743SBjoern A. Zeeb * Initialize per-cpu drain list. 206d0ea4743SBjoern A. Zeeb * Manually do what STAILQ_HEAD_INITIALIZER would do. 207d0ea4743SBjoern A. Zeeb */ 208d0ea4743SBjoern A. Zeeb s = &epair_dpcpu->epair_ifp_drain_list; 209d0ea4743SBjoern A. Zeeb s->stqh_first = NULL; 210d0ea4743SBjoern A. Zeeb s->stqh_last = &s->stqh_first; 211d0ea4743SBjoern A. Zeeb } 212d0ea4743SBjoern A. Zeeb } 213d0ea4743SBjoern A. Zeeb 214d0ea4743SBjoern A. Zeeb static void 215d0ea4743SBjoern A. Zeeb epair_dpcpu_detach(void) 216d0ea4743SBjoern A. Zeeb { 217d0ea4743SBjoern A. Zeeb struct epair_dpcpu *epair_dpcpu; 218d0ea4743SBjoern A. Zeeb u_int cpuid; 219d0ea4743SBjoern A. Zeeb 220d0ea4743SBjoern A. Zeeb for (cpuid = 0; cpuid <= mp_maxid; cpuid++) { 221d0ea4743SBjoern A. Zeeb if (CPU_ABSENT(cpuid)) 222d0ea4743SBjoern A. Zeeb continue; 223d0ea4743SBjoern A. Zeeb 224d0ea4743SBjoern A. Zeeb epair_dpcpu = DPCPU_ID_PTR(cpuid, epair_dpcpu); 225d0ea4743SBjoern A. Zeeb 226d0ea4743SBjoern A. Zeeb /* Destroy per-cpu lock. */ 227d0ea4743SBjoern A. Zeeb EPAIR_LOCK_DESTROY(epair_dpcpu); 228d0ea4743SBjoern A. Zeeb } 229d0ea4743SBjoern A. Zeeb } 230d0ea4743SBjoern A. Zeeb 231d0ea4743SBjoern A. Zeeb /* 232d0ea4743SBjoern A. Zeeb * Helper functions. 233d0ea4743SBjoern A. Zeeb */ 234d0ea4743SBjoern A. Zeeb static u_int 235d0ea4743SBjoern A. Zeeb cpuid_from_ifp(struct ifnet *ifp) 236d0ea4743SBjoern A. Zeeb { 237d0ea4743SBjoern A. Zeeb struct epair_softc *sc; 238d0ea4743SBjoern A. Zeeb 239d0ea4743SBjoern A. Zeeb if (ifp == NULL) 240d0ea4743SBjoern A. Zeeb return (0); 241d0ea4743SBjoern A. Zeeb sc = ifp->if_softc; 242d0ea4743SBjoern A. Zeeb 243d0ea4743SBjoern A. Zeeb return (sc->cpuid); 244d0ea4743SBjoern A. Zeeb } 24598c230c8SBjoern A. Zeeb 24698c230c8SBjoern A. Zeeb /* 24798c230c8SBjoern A. Zeeb * Netisr handler functions. 24898c230c8SBjoern A. Zeeb */ 24998c230c8SBjoern A. Zeeb static void 250d0ea4743SBjoern A. Zeeb epair_nh_sintr(struct mbuf *m) 25198c230c8SBjoern A. Zeeb { 25298c230c8SBjoern A. Zeeb struct ifnet *ifp; 25398c230c8SBjoern A. Zeeb struct epair_softc *sc; 25498c230c8SBjoern A. Zeeb 25598c230c8SBjoern A. Zeeb ifp = m->m_pkthdr.rcvif; 25698c230c8SBjoern A. Zeeb (*ifp->if_input)(ifp, m); 25798c230c8SBjoern A. Zeeb sc = ifp->if_softc; 258d0ea4743SBjoern A. Zeeb EPAIR_REFCOUNT_RELEASE(&sc->refcount); 25998c230c8SBjoern A. Zeeb DPRINTF("ifp=%p refcount=%u\n", ifp, sc->refcount); 26098c230c8SBjoern A. Zeeb } 26198c230c8SBjoern A. Zeeb 262d0ea4743SBjoern A. Zeeb static struct mbuf * 263d0ea4743SBjoern A. Zeeb epair_nh_m2cpuid(struct mbuf *m, uintptr_t source, u_int *cpuid) 26498c230c8SBjoern A. Zeeb { 265d0ea4743SBjoern A. Zeeb 266d0ea4743SBjoern A. Zeeb *cpuid = cpuid_from_ifp(m->m_pkthdr.rcvif); 267d0ea4743SBjoern A. Zeeb 268d0ea4743SBjoern A. Zeeb return (m); 269d0ea4743SBjoern A. Zeeb } 270d0ea4743SBjoern A. Zeeb 271d0ea4743SBjoern A. Zeeb static void 272d0ea4743SBjoern A. Zeeb epair_nh_drainedcpu(u_int cpuid) 273d0ea4743SBjoern A. Zeeb { 274d0ea4743SBjoern A. Zeeb struct epair_dpcpu *epair_dpcpu; 27598c230c8SBjoern A. Zeeb struct epair_ifp_drain *elm, *tvar; 27698c230c8SBjoern A. Zeeb struct ifnet *ifp; 27798c230c8SBjoern A. Zeeb 278d0ea4743SBjoern A. Zeeb epair_dpcpu = DPCPU_ID_PTR(cpuid, epair_dpcpu); 279d0ea4743SBjoern A. Zeeb EPAIR_LOCK(epair_dpcpu); 28098c230c8SBjoern A. Zeeb /* 28198c230c8SBjoern A. Zeeb * Assume our "hw" queue and possibly ifq will be emptied 28298c230c8SBjoern A. Zeeb * again. In case we will overflow the "hw" queue while 28398c230c8SBjoern A. Zeeb * draining, epair_start_locked will set IFF_DRV_OACTIVE 28498c230c8SBjoern A. Zeeb * again and we will stop and return. 28598c230c8SBjoern A. Zeeb */ 286d0ea4743SBjoern A. Zeeb STAILQ_FOREACH_SAFE(elm, &epair_dpcpu->epair_ifp_drain_list, 287d0ea4743SBjoern A. Zeeb ifp_next, tvar) { 28898c230c8SBjoern A. Zeeb ifp = elm->ifp; 289d0ea4743SBjoern A. Zeeb epair_dpcpu->epair_drv_flags &= ~IFF_DRV_OACTIVE; 29098c230c8SBjoern A. Zeeb ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 29198c230c8SBjoern A. Zeeb epair_start_locked(ifp); 29298c230c8SBjoern A. Zeeb 29398c230c8SBjoern A. Zeeb IFQ_LOCK(&ifp->if_snd); 29498c230c8SBjoern A. Zeeb if (IFQ_IS_EMPTY(&ifp->if_snd)) { 295d0ea4743SBjoern A. Zeeb STAILQ_REMOVE(&epair_dpcpu->epair_ifp_drain_list, 296d0ea4743SBjoern A. Zeeb elm, epair_ifp_drain, ifp_next); 29798c230c8SBjoern A. Zeeb free(elm, M_EPAIR); 29898c230c8SBjoern A. Zeeb } 29998c230c8SBjoern A. Zeeb IFQ_UNLOCK(&ifp->if_snd); 30098c230c8SBjoern A. Zeeb 30198c230c8SBjoern A. Zeeb if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) != 0) { 30298c230c8SBjoern A. Zeeb /* Our "hw"q overflew again. */ 303d0ea4743SBjoern A. Zeeb epair_dpcpu->epair_drv_flags |= IFF_DRV_OACTIVE 30498c230c8SBjoern A. Zeeb DPRINTF("hw queue length overflow at %u\n", 305d0ea4743SBjoern A. Zeeb epair_nh.nh_qlimit); 30698c230c8SBjoern A. Zeeb break; 30798c230c8SBjoern A. Zeeb } 30898c230c8SBjoern A. Zeeb } 309d0ea4743SBjoern A. Zeeb EPAIR_UNLOCK(epair_dpcpu); 31098c230c8SBjoern A. Zeeb } 31198c230c8SBjoern A. Zeeb 31298c230c8SBjoern A. Zeeb /* 31398c230c8SBjoern A. Zeeb * Network interface (`if') related functions. 31498c230c8SBjoern A. Zeeb */ 315d0ea4743SBjoern A. Zeeb static int 316d0ea4743SBjoern A. Zeeb epair_add_ifp_for_draining(struct ifnet *ifp) 317d0ea4743SBjoern A. Zeeb { 318d0ea4743SBjoern A. Zeeb struct epair_dpcpu *epair_dpcpu; 319d0ea4743SBjoern A. Zeeb struct epair_softc *sc = sc = ifp->if_softc; 320d0ea4743SBjoern A. Zeeb struct epair_ifp_drain *elm = NULL; 321d0ea4743SBjoern A. Zeeb 322d0ea4743SBjoern A. Zeeb epair_dpcpu = DPCPU_ID_PTR(sc->cpuid, epair_dpcpu); 323d0ea4743SBjoern A. Zeeb STAILQ_FOREACH(elm, &epair_dpcpu->epair_ifp_drain_list, ifp_next) 324d0ea4743SBjoern A. Zeeb if (elm->ifp == ifp) 325d0ea4743SBjoern A. Zeeb break; 326d0ea4743SBjoern A. Zeeb /* If the ipf is there already, return success. */ 327d0ea4743SBjoern A. Zeeb if (elm != NULL) 328d0ea4743SBjoern A. Zeeb return (0); 329d0ea4743SBjoern A. Zeeb 330d0ea4743SBjoern A. Zeeb elm = malloc(sizeof(struct epair_ifp_drain), M_EPAIR, M_NOWAIT|M_ZERO); 331d0ea4743SBjoern A. Zeeb if (elm == NULL) 332d0ea4743SBjoern A. Zeeb return (ENOMEM); 333d0ea4743SBjoern A. Zeeb 334d0ea4743SBjoern A. Zeeb elm->ifp = ifp; 335d0ea4743SBjoern A. Zeeb STAILQ_INSERT_TAIL(&epair_dpcpu->epair_ifp_drain_list, elm, ifp_next); 336d0ea4743SBjoern A. Zeeb 337d0ea4743SBjoern A. Zeeb return (0); 338d0ea4743SBjoern A. Zeeb } 339d0ea4743SBjoern A. Zeeb 34098c230c8SBjoern A. Zeeb static void 34198c230c8SBjoern A. Zeeb epair_start_locked(struct ifnet *ifp) 34298c230c8SBjoern A. Zeeb { 343d0ea4743SBjoern A. Zeeb struct epair_dpcpu *epair_dpcpu; 34498c230c8SBjoern A. Zeeb struct mbuf *m; 34598c230c8SBjoern A. Zeeb struct epair_softc *sc; 34698c230c8SBjoern A. Zeeb struct ifnet *oifp; 34798c230c8SBjoern A. Zeeb int error; 34898c230c8SBjoern A. Zeeb 34998c230c8SBjoern A. Zeeb DPRINTF("ifp=%p\n", ifp); 350d0ea4743SBjoern A. Zeeb sc = ifp->if_softc; 351d0ea4743SBjoern A. Zeeb epair_dpcpu = DPCPU_ID_PTR(sc->cpuid, epair_dpcpu); 352d0ea4743SBjoern A. Zeeb EPAIR_LOCK_ASSERT(epair_dpcpu); 35398c230c8SBjoern A. Zeeb 35498c230c8SBjoern A. Zeeb if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 35598c230c8SBjoern A. Zeeb return; 35698c230c8SBjoern A. Zeeb if ((ifp->if_flags & IFF_UP) == 0) 35798c230c8SBjoern A. Zeeb return; 35898c230c8SBjoern A. Zeeb 35998c230c8SBjoern A. Zeeb /* 36098c230c8SBjoern A. Zeeb * We get patckets here from ether_output via if_handoff() 36198c230c8SBjoern A. Zeeb * and ned to put them into the input queue of the oifp 36298c230c8SBjoern A. Zeeb * and call oifp->if_input() via netisr/epair_sintr(). 36398c230c8SBjoern A. Zeeb */ 36498c230c8SBjoern A. Zeeb oifp = sc->oifp; 36598c230c8SBjoern A. Zeeb sc = oifp->if_softc; 36698c230c8SBjoern A. Zeeb for (;;) { 36798c230c8SBjoern A. Zeeb IFQ_DEQUEUE(&ifp->if_snd, m); 36898c230c8SBjoern A. Zeeb if (m == NULL) 36998c230c8SBjoern A. Zeeb break; 37098c230c8SBjoern A. Zeeb BPF_MTAP(ifp, m); 37198c230c8SBjoern A. Zeeb 37298c230c8SBjoern A. Zeeb /* 37398c230c8SBjoern A. Zeeb * In case the outgoing interface is not usable, 37498c230c8SBjoern A. Zeeb * drop the packet. 37598c230c8SBjoern A. Zeeb */ 37698c230c8SBjoern A. Zeeb if ((oifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 37798c230c8SBjoern A. Zeeb (oifp->if_flags & IFF_UP) ==0) { 37898c230c8SBjoern A. Zeeb ifp->if_oerrors++; 37998c230c8SBjoern A. Zeeb m_freem(m); 38098c230c8SBjoern A. Zeeb continue; 38198c230c8SBjoern A. Zeeb } 38298c230c8SBjoern A. Zeeb DPRINTF("packet %s -> %s\n", ifp->if_xname, oifp->if_xname); 38398c230c8SBjoern A. Zeeb 38498c230c8SBjoern A. Zeeb /* 38598c230c8SBjoern A. Zeeb * Add a reference so the interface cannot go while the 38698c230c8SBjoern A. Zeeb * packet is in transit as we rely on rcvif to stay valid. 38798c230c8SBjoern A. Zeeb */ 388d0ea4743SBjoern A. Zeeb EPAIR_REFCOUNT_AQUIRE(&sc->refcount); 38998c230c8SBjoern A. Zeeb m->m_pkthdr.rcvif = oifp; 39098c230c8SBjoern A. Zeeb CURVNET_SET_QUIET(oifp->if_vnet); 39198c230c8SBjoern A. Zeeb error = netisr_queue(NETISR_EPAIR, m); 39298c230c8SBjoern A. Zeeb CURVNET_RESTORE(); 39398c230c8SBjoern A. Zeeb if (!error) { 39498c230c8SBjoern A. Zeeb ifp->if_opackets++; 39598c230c8SBjoern A. Zeeb /* Someone else received the packet. */ 39698c230c8SBjoern A. Zeeb oifp->if_ipackets++; 39798c230c8SBjoern A. Zeeb } else { 398d0ea4743SBjoern A. Zeeb epair_dpcpu->epair_drv_flags |= IFF_DRV_OACTIVE; 39998c230c8SBjoern A. Zeeb ifp->if_drv_flags |= IFF_DRV_OACTIVE; 400d0ea4743SBjoern A. Zeeb if (epair_add_ifp_for_draining(ifp)) { 401d0ea4743SBjoern A. Zeeb ifp->if_oerrors++; 402d0ea4743SBjoern A. Zeeb m_freem(m); 403d0ea4743SBjoern A. Zeeb } 404d0ea4743SBjoern A. Zeeb EPAIR_REFCOUNT_RELEASE(&sc->refcount); 40598c230c8SBjoern A. Zeeb } 40698c230c8SBjoern A. Zeeb } 40798c230c8SBjoern A. Zeeb } 40898c230c8SBjoern A. Zeeb 40998c230c8SBjoern A. Zeeb static void 41098c230c8SBjoern A. Zeeb epair_start(struct ifnet *ifp) 41198c230c8SBjoern A. Zeeb { 412d0ea4743SBjoern A. Zeeb struct epair_dpcpu *epair_dpcpu; 41398c230c8SBjoern A. Zeeb 414d0ea4743SBjoern A. Zeeb epair_dpcpu = DPCPU_ID_PTR(cpuid_from_ifp(ifp), epair_dpcpu); 415d0ea4743SBjoern A. Zeeb EPAIR_LOCK(epair_dpcpu); 41698c230c8SBjoern A. Zeeb epair_start_locked(ifp); 417d0ea4743SBjoern A. Zeeb EPAIR_UNLOCK(epair_dpcpu); 41898c230c8SBjoern A. Zeeb } 41998c230c8SBjoern A. Zeeb 42098c230c8SBjoern A. Zeeb static int 42198c230c8SBjoern A. Zeeb epair_transmit_locked(struct ifnet *ifp, struct mbuf *m) 42298c230c8SBjoern A. Zeeb { 423d0ea4743SBjoern A. Zeeb struct epair_dpcpu *epair_dpcpu; 42498c230c8SBjoern A. Zeeb struct epair_softc *sc; 42598c230c8SBjoern A. Zeeb struct ifnet *oifp; 42698c230c8SBjoern A. Zeeb int error, len; 42798c230c8SBjoern A. Zeeb short mflags; 42898c230c8SBjoern A. Zeeb 42998c230c8SBjoern A. Zeeb DPRINTF("ifp=%p m=%p\n", ifp, m); 430d0ea4743SBjoern A. Zeeb sc = ifp->if_softc; 431d0ea4743SBjoern A. Zeeb epair_dpcpu = DPCPU_ID_PTR(sc->cpuid, epair_dpcpu); 432d0ea4743SBjoern A. Zeeb EPAIR_LOCK_ASSERT(epair_dpcpu); 43398c230c8SBjoern A. Zeeb 43498c230c8SBjoern A. Zeeb if (m == NULL) 43598c230c8SBjoern A. Zeeb return (0); 43698c230c8SBjoern A. Zeeb 43798c230c8SBjoern A. Zeeb /* 43898c230c8SBjoern A. Zeeb * We are not going to use the interface en/dequeue mechanism 43998c230c8SBjoern A. Zeeb * on the TX side. We are called from ether_output_frame() 44098c230c8SBjoern A. Zeeb * and will put the packet into the incoming queue of the 44198c230c8SBjoern A. Zeeb * other interface of our pair via the netsir. 44298c230c8SBjoern A. Zeeb */ 44398c230c8SBjoern A. Zeeb if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 44498c230c8SBjoern A. Zeeb m_freem(m); 44598c230c8SBjoern A. Zeeb return (ENXIO); 44698c230c8SBjoern A. Zeeb } 44798c230c8SBjoern A. Zeeb if ((ifp->if_flags & IFF_UP) == 0) { 44898c230c8SBjoern A. Zeeb m_freem(m); 44998c230c8SBjoern A. Zeeb return (ENETDOWN); 45098c230c8SBjoern A. Zeeb } 45198c230c8SBjoern A. Zeeb 45298c230c8SBjoern A. Zeeb BPF_MTAP(ifp, m); 45398c230c8SBjoern A. Zeeb 45498c230c8SBjoern A. Zeeb /* 45598c230c8SBjoern A. Zeeb * In case the outgoing interface is not usable, 45698c230c8SBjoern A. Zeeb * drop the packet. 45798c230c8SBjoern A. Zeeb */ 45898c230c8SBjoern A. Zeeb oifp = sc->oifp; 45998c230c8SBjoern A. Zeeb if ((oifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || 46098c230c8SBjoern A. Zeeb (oifp->if_flags & IFF_UP) ==0) { 46198c230c8SBjoern A. Zeeb ifp->if_oerrors++; 46298c230c8SBjoern A. Zeeb m_freem(m); 46398c230c8SBjoern A. Zeeb return (0); 46498c230c8SBjoern A. Zeeb } 46598c230c8SBjoern A. Zeeb len = m->m_pkthdr.len; 46698c230c8SBjoern A. Zeeb mflags = m->m_flags; 46798c230c8SBjoern A. Zeeb DPRINTF("packet %s -> %s\n", ifp->if_xname, oifp->if_xname); 46898c230c8SBjoern A. Zeeb 46998c230c8SBjoern A. Zeeb #ifdef ALTQ 47098c230c8SBjoern A. Zeeb /* Support ALTQ via the clasic if_start() path. */ 47198c230c8SBjoern A. Zeeb IF_LOCK(&ifp->if_snd); 47298c230c8SBjoern A. Zeeb if (ALTQ_IS_ENABLED(&ifp->if_snd)) { 47398c230c8SBjoern A. Zeeb ALTQ_ENQUEUE(&ifp->if_snd, m, NULL, error); 47498c230c8SBjoern A. Zeeb if (error) 47598c230c8SBjoern A. Zeeb ifp->if_snd.ifq_drops++; 47698c230c8SBjoern A. Zeeb IF_UNLOCK(&ifp->if_snd); 47798c230c8SBjoern A. Zeeb if (!error) { 47898c230c8SBjoern A. Zeeb ifp->if_obytes += len; 47998c230c8SBjoern A. Zeeb if (mflags & (M_BCAST|M_MCAST)) 48098c230c8SBjoern A. Zeeb ifp->if_omcasts++; 48198c230c8SBjoern A. Zeeb 48298c230c8SBjoern A. Zeeb if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) 48398c230c8SBjoern A. Zeeb epair_start_locked(ifp); 48498c230c8SBjoern A. Zeeb else 485d0ea4743SBjoern A. Zeeb (void)epair_add_ifp_for_draining(ifp); 48698c230c8SBjoern A. Zeeb } 48798c230c8SBjoern A. Zeeb return (error); 48898c230c8SBjoern A. Zeeb } 48998c230c8SBjoern A. Zeeb IF_UNLOCK(&ifp->if_snd); 49098c230c8SBjoern A. Zeeb #endif 49198c230c8SBjoern A. Zeeb 492d0ea4743SBjoern A. Zeeb if ((epair_dpcpu->epair_drv_flags & IFF_DRV_OACTIVE) != 0) { 49398c230c8SBjoern A. Zeeb /* 49498c230c8SBjoern A. Zeeb * Our hardware queue is full, try to fall back 49598c230c8SBjoern A. Zeeb * queuing to the ifq but do not call ifp->if_start. 49698c230c8SBjoern A. Zeeb * Either we are lucky or the packet is gone. 49798c230c8SBjoern A. Zeeb */ 49898c230c8SBjoern A. Zeeb IFQ_ENQUEUE(&ifp->if_snd, m, error); 49998c230c8SBjoern A. Zeeb if (!error) 500d0ea4743SBjoern A. Zeeb (void)epair_add_ifp_for_draining(ifp); 50198c230c8SBjoern A. Zeeb return (error); 50298c230c8SBjoern A. Zeeb } 50398c230c8SBjoern A. Zeeb sc = oifp->if_softc; 50498c230c8SBjoern A. Zeeb /* 50598c230c8SBjoern A. Zeeb * Add a reference so the interface cannot go while the 50698c230c8SBjoern A. Zeeb * packet is in transit as we rely on rcvif to stay valid. 50798c230c8SBjoern A. Zeeb */ 508d0ea4743SBjoern A. Zeeb EPAIR_REFCOUNT_AQUIRE(&sc->refcount); 50998c230c8SBjoern A. Zeeb m->m_pkthdr.rcvif = oifp; 51098c230c8SBjoern A. Zeeb CURVNET_SET_QUIET(oifp->if_vnet); 51198c230c8SBjoern A. Zeeb error = netisr_queue(NETISR_EPAIR, m); 51298c230c8SBjoern A. Zeeb CURVNET_RESTORE(); 51398c230c8SBjoern A. Zeeb if (!error) { 51498c230c8SBjoern A. Zeeb ifp->if_opackets++; 51598c230c8SBjoern A. Zeeb /* 51698c230c8SBjoern A. Zeeb * IFQ_HANDOFF_ADJ/ip_handoff() update statistics, 51798c230c8SBjoern A. Zeeb * but as we bypass all this we have to duplicate 51898c230c8SBjoern A. Zeeb * the logic another time. 51998c230c8SBjoern A. Zeeb */ 52098c230c8SBjoern A. Zeeb ifp->if_obytes += len; 52198c230c8SBjoern A. Zeeb if (mflags & (M_BCAST|M_MCAST)) 52298c230c8SBjoern A. Zeeb ifp->if_omcasts++; 52398c230c8SBjoern A. Zeeb /* Someone else received the packet. */ 52498c230c8SBjoern A. Zeeb oifp->if_ipackets++; 52598c230c8SBjoern A. Zeeb } else { 52698c230c8SBjoern A. Zeeb /* The packet was freed already. */ 527d0ea4743SBjoern A. Zeeb EPAIR_REFCOUNT_RELEASE(&sc->refcount); 528d0ea4743SBjoern A. Zeeb epair_dpcpu->epair_drv_flags |= IFF_DRV_OACTIVE; 52998c230c8SBjoern A. Zeeb ifp->if_drv_flags |= IFF_DRV_OACTIVE; 53098c230c8SBjoern A. Zeeb } 53198c230c8SBjoern A. Zeeb 53298c230c8SBjoern A. Zeeb return (error); 53398c230c8SBjoern A. Zeeb } 53498c230c8SBjoern A. Zeeb 53598c230c8SBjoern A. Zeeb static int 53698c230c8SBjoern A. Zeeb epair_transmit(struct ifnet *ifp, struct mbuf *m) 53798c230c8SBjoern A. Zeeb { 538d0ea4743SBjoern A. Zeeb struct epair_dpcpu *epair_dpcpu; 53998c230c8SBjoern A. Zeeb int error; 54098c230c8SBjoern A. Zeeb 541d0ea4743SBjoern A. Zeeb epair_dpcpu = DPCPU_ID_PTR(cpuid_from_ifp(ifp), epair_dpcpu); 542d0ea4743SBjoern A. Zeeb EPAIR_LOCK(epair_dpcpu); 54398c230c8SBjoern A. Zeeb error = epair_transmit_locked(ifp, m); 544d0ea4743SBjoern A. Zeeb EPAIR_UNLOCK(epair_dpcpu); 54598c230c8SBjoern A. Zeeb return (error); 54698c230c8SBjoern A. Zeeb } 54798c230c8SBjoern A. Zeeb 54898c230c8SBjoern A. Zeeb static void 54998c230c8SBjoern A. Zeeb epair_qflush(struct ifnet *ifp) 55098c230c8SBjoern A. Zeeb { 551d0ea4743SBjoern A. Zeeb struct epair_dpcpu *epair_dpcpu; 55298c230c8SBjoern A. Zeeb struct epair_softc *sc; 55398c230c8SBjoern A. Zeeb struct ifaltq *ifq; 55498c230c8SBjoern A. Zeeb 55598c230c8SBjoern A. Zeeb sc = ifp->if_softc; 556d0ea4743SBjoern A. Zeeb epair_dpcpu = DPCPU_ID_PTR(sc->cpuid, epair_dpcpu); 557d0ea4743SBjoern A. Zeeb EPAIR_LOCK(epair_dpcpu); 55898c230c8SBjoern A. Zeeb ifq = &ifp->if_snd; 55998c230c8SBjoern A. Zeeb DPRINTF("ifp=%p sc refcnt=%u ifq_len=%u\n", 56098c230c8SBjoern A. Zeeb ifp, sc->refcount, ifq->ifq_len); 56198c230c8SBjoern A. Zeeb /* 562d0ea4743SBjoern A. Zeeb * Instead of calling EPAIR_REFCOUNT_RELEASE(&sc->refcount); 56398c230c8SBjoern A. Zeeb * n times, just subtract for the cleanup. 56498c230c8SBjoern A. Zeeb */ 56598c230c8SBjoern A. Zeeb sc->refcount -= ifq->ifq_len; 566d0ea4743SBjoern A. Zeeb EPAIR_UNLOCK(epair_dpcpu); 56798c230c8SBjoern A. Zeeb if (sc->if_qflush) 56898c230c8SBjoern A. Zeeb sc->if_qflush(ifp); 56998c230c8SBjoern A. Zeeb } 57098c230c8SBjoern A. Zeeb 57198c230c8SBjoern A. Zeeb static int 57298c230c8SBjoern A. Zeeb epair_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 57398c230c8SBjoern A. Zeeb { 57498c230c8SBjoern A. Zeeb struct ifreq *ifr; 57598c230c8SBjoern A. Zeeb int error; 57698c230c8SBjoern A. Zeeb 57798c230c8SBjoern A. Zeeb ifr = (struct ifreq *)data; 57898c230c8SBjoern A. Zeeb switch (cmd) { 57998c230c8SBjoern A. Zeeb case SIOCSIFFLAGS: 58098c230c8SBjoern A. Zeeb case SIOCADDMULTI: 58198c230c8SBjoern A. Zeeb case SIOCDELMULTI: 58298c230c8SBjoern A. Zeeb error = 0; 58398c230c8SBjoern A. Zeeb break; 58498c230c8SBjoern A. Zeeb 585d0ea4743SBjoern A. Zeeb case SIOCSIFMTU: 586d0ea4743SBjoern A. Zeeb /* We basically allow all kinds of MTUs. */ 587d0ea4743SBjoern A. Zeeb ifp->if_mtu = ifr->ifr_mtu; 588d0ea4743SBjoern A. Zeeb error = 0; 589d0ea4743SBjoern A. Zeeb break; 590d0ea4743SBjoern A. Zeeb 59198c230c8SBjoern A. Zeeb default: 59298c230c8SBjoern A. Zeeb /* Let the common ethernet handler process this. */ 59398c230c8SBjoern A. Zeeb error = ether_ioctl(ifp, cmd, data); 59498c230c8SBjoern A. Zeeb break; 59598c230c8SBjoern A. Zeeb } 59698c230c8SBjoern A. Zeeb 59798c230c8SBjoern A. Zeeb return (error); 59898c230c8SBjoern A. Zeeb } 59998c230c8SBjoern A. Zeeb 60098c230c8SBjoern A. Zeeb static void 60198c230c8SBjoern A. Zeeb epair_init(void *dummy __unused) 60298c230c8SBjoern A. Zeeb { 60398c230c8SBjoern A. Zeeb } 60498c230c8SBjoern A. Zeeb 60598c230c8SBjoern A. Zeeb 60698c230c8SBjoern A. Zeeb /* 60798c230c8SBjoern A. Zeeb * Interface cloning functions. 60898c230c8SBjoern A. Zeeb * We use our private ones so that we can create/destroy our secondary 60998c230c8SBjoern A. Zeeb * device along with the primary one. 61098c230c8SBjoern A. Zeeb */ 61198c230c8SBjoern A. Zeeb static int 61298c230c8SBjoern A. Zeeb epair_clone_match(struct if_clone *ifc, const char *name) 61398c230c8SBjoern A. Zeeb { 61498c230c8SBjoern A. Zeeb const char *cp; 61598c230c8SBjoern A. Zeeb 61698c230c8SBjoern A. Zeeb DPRINTF("name='%s'\n", name); 61798c230c8SBjoern A. Zeeb 61898c230c8SBjoern A. Zeeb /* 61998c230c8SBjoern A. Zeeb * Our base name is epair. 62098c230c8SBjoern A. Zeeb * Our interfaces will be named epair<n>[ab]. 62198c230c8SBjoern A. Zeeb * So accept anything of the following list: 62298c230c8SBjoern A. Zeeb * - epair 62398c230c8SBjoern A. Zeeb * - epair<n> 62498c230c8SBjoern A. Zeeb * but not the epair<n>[ab] versions. 62598c230c8SBjoern A. Zeeb */ 62698c230c8SBjoern A. Zeeb if (strncmp(EPAIRNAME, name, sizeof(EPAIRNAME)-1) != 0) 62798c230c8SBjoern A. Zeeb return (0); 62898c230c8SBjoern A. Zeeb 62998c230c8SBjoern A. Zeeb for (cp = name + sizeof(EPAIRNAME) - 1; *cp != '\0'; cp++) { 63098c230c8SBjoern A. Zeeb if (*cp < '0' || *cp > '9') 63198c230c8SBjoern A. Zeeb return (0); 63298c230c8SBjoern A. Zeeb } 63398c230c8SBjoern A. Zeeb 63498c230c8SBjoern A. Zeeb return (1); 63598c230c8SBjoern A. Zeeb } 63698c230c8SBjoern A. Zeeb 63798c230c8SBjoern A. Zeeb static int 63898c230c8SBjoern A. Zeeb epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) 63998c230c8SBjoern A. Zeeb { 64098c230c8SBjoern A. Zeeb struct epair_softc *sca, *scb; 64198c230c8SBjoern A. Zeeb struct ifnet *ifp; 64298c230c8SBjoern A. Zeeb char *dp; 64398c230c8SBjoern A. Zeeb int error, unit, wildcard; 64498c230c8SBjoern A. Zeeb uint8_t eaddr[ETHER_ADDR_LEN]; /* 00:00:00:00:00:00 */ 64598c230c8SBjoern A. Zeeb 64698c230c8SBjoern A. Zeeb /* 64798c230c8SBjoern A. Zeeb * We are abusing params to create our second interface. 64898c230c8SBjoern A. Zeeb * Actually we already created it and called if_clone_createif() 64998c230c8SBjoern A. Zeeb * for it to do the official insertion procedure the moment we knew 65098c230c8SBjoern A. Zeeb * it cannot fail anymore. So just do attach it here. 65198c230c8SBjoern A. Zeeb */ 65298c230c8SBjoern A. Zeeb if (params) { 65398c230c8SBjoern A. Zeeb scb = (struct epair_softc *)params; 65498c230c8SBjoern A. Zeeb ifp = scb->ifp; 65598c230c8SBjoern A. Zeeb /* Assign a hopefully unique, locally administered etheraddr. */ 65698c230c8SBjoern A. Zeeb eaddr[0] = 0x02; 65798c230c8SBjoern A. Zeeb eaddr[3] = (ifp->if_index >> 8) & 0xff; 65898c230c8SBjoern A. Zeeb eaddr[4] = ifp->if_index & 0xff; 65998c230c8SBjoern A. Zeeb eaddr[5] = 0x0b; 66098c230c8SBjoern A. Zeeb ether_ifattach(ifp, eaddr); 66198c230c8SBjoern A. Zeeb /* Correctly set the name for the cloner list. */ 66298c230c8SBjoern A. Zeeb strlcpy(name, scb->ifp->if_xname, len); 66398c230c8SBjoern A. Zeeb return (0); 66498c230c8SBjoern A. Zeeb } 66598c230c8SBjoern A. Zeeb 66698c230c8SBjoern A. Zeeb /* Try to see if a special unit was requested. */ 66798c230c8SBjoern A. Zeeb error = ifc_name2unit(name, &unit); 66898c230c8SBjoern A. Zeeb if (error != 0) 66998c230c8SBjoern A. Zeeb return (error); 67098c230c8SBjoern A. Zeeb wildcard = (unit < 0); 67198c230c8SBjoern A. Zeeb 67298c230c8SBjoern A. Zeeb error = ifc_alloc_unit(ifc, &unit); 67398c230c8SBjoern A. Zeeb if (error != 0) 67498c230c8SBjoern A. Zeeb return (error); 67598c230c8SBjoern A. Zeeb 67698c230c8SBjoern A. Zeeb /* 67798c230c8SBjoern A. Zeeb * If no unit had been given, we need to adjust the ifName. 67898c230c8SBjoern A. Zeeb * Also make sure there is space for our extra [ab] suffix. 67998c230c8SBjoern A. Zeeb */ 68098c230c8SBjoern A. Zeeb for (dp = name; *dp != '\0'; dp++); 68198c230c8SBjoern A. Zeeb if (wildcard) { 68298c230c8SBjoern A. Zeeb error = snprintf(dp, len - (dp - name), "%d", unit); 68398c230c8SBjoern A. Zeeb if (error > len - (dp - name) - 1) { 68498c230c8SBjoern A. Zeeb /* ifName too long. */ 68598c230c8SBjoern A. Zeeb ifc_free_unit(ifc, unit); 68698c230c8SBjoern A. Zeeb return (ENOSPC); 68798c230c8SBjoern A. Zeeb } 68898c230c8SBjoern A. Zeeb dp += error; 68998c230c8SBjoern A. Zeeb } 69098c230c8SBjoern A. Zeeb if (len - (dp - name) - 1 < 1) { 69198c230c8SBjoern A. Zeeb /* No space left for our [ab] suffix. */ 69298c230c8SBjoern A. Zeeb ifc_free_unit(ifc, unit); 69398c230c8SBjoern A. Zeeb return (ENOSPC); 69498c230c8SBjoern A. Zeeb } 69598c230c8SBjoern A. Zeeb *dp = 'a'; 69698c230c8SBjoern A. Zeeb /* Must not change dp so we can replace 'a' by 'b' later. */ 69798c230c8SBjoern A. Zeeb *(dp+1) = '\0'; 69898c230c8SBjoern A. Zeeb 69998c230c8SBjoern A. Zeeb /* Allocate memory for both [ab] interfaces */ 70098c230c8SBjoern A. Zeeb sca = malloc(sizeof(struct epair_softc), M_EPAIR, M_WAITOK | M_ZERO); 701d0ea4743SBjoern A. Zeeb EPAIR_REFCOUNT_INIT(&sca->refcount, 1); 70298c230c8SBjoern A. Zeeb sca->ifp = if_alloc(IFT_ETHER); 70398c230c8SBjoern A. Zeeb if (sca->ifp == NULL) { 70498c230c8SBjoern A. Zeeb free(sca, M_EPAIR); 70598c230c8SBjoern A. Zeeb ifc_free_unit(ifc, unit); 70698c230c8SBjoern A. Zeeb return (ENOSPC); 70798c230c8SBjoern A. Zeeb } 70898c230c8SBjoern A. Zeeb 70998c230c8SBjoern A. Zeeb scb = malloc(sizeof(struct epair_softc), M_EPAIR, M_WAITOK | M_ZERO); 710d0ea4743SBjoern A. Zeeb EPAIR_REFCOUNT_INIT(&scb->refcount, 1); 71198c230c8SBjoern A. Zeeb scb->ifp = if_alloc(IFT_ETHER); 71298c230c8SBjoern A. Zeeb if (scb->ifp == NULL) { 71398c230c8SBjoern A. Zeeb free(scb, M_EPAIR); 71498c230c8SBjoern A. Zeeb if_free(sca->ifp); 71598c230c8SBjoern A. Zeeb free(sca, M_EPAIR); 71698c230c8SBjoern A. Zeeb ifc_free_unit(ifc, unit); 71798c230c8SBjoern A. Zeeb return (ENOSPC); 71898c230c8SBjoern A. Zeeb } 71998c230c8SBjoern A. Zeeb 72098c230c8SBjoern A. Zeeb /* 72198c230c8SBjoern A. Zeeb * Cross-reference the interfaces so we will be able to free both. 72298c230c8SBjoern A. Zeeb */ 72398c230c8SBjoern A. Zeeb sca->oifp = scb->ifp; 72498c230c8SBjoern A. Zeeb scb->oifp = sca->ifp; 72598c230c8SBjoern A. Zeeb 726d0ea4743SBjoern A. Zeeb /* 727d0ea4743SBjoern A. Zeeb * Calculate the cpuid for netisr queueing based on the 728d0ea4743SBjoern A. Zeeb * ifIndex of the interfaces. As long as we cannot configure 729d0ea4743SBjoern A. Zeeb * this or use cpuset information easily we cannot guarantee 730d0ea4743SBjoern A. Zeeb * cache locality but we can at least allow parallelism. 731d0ea4743SBjoern A. Zeeb */ 732d0ea4743SBjoern A. Zeeb sca->cpuid = 733d0ea4743SBjoern A. Zeeb netisr_get_cpuid(sca->ifp->if_index % netisr_get_cpucount()); 734d0ea4743SBjoern A. Zeeb scb->cpuid = 735d0ea4743SBjoern A. Zeeb netisr_get_cpuid(scb->ifp->if_index % netisr_get_cpucount()); 736d0ea4743SBjoern A. Zeeb 73798c230c8SBjoern A. Zeeb /* Finish initialization of interface <n>a. */ 73898c230c8SBjoern A. Zeeb ifp = sca->ifp; 73998c230c8SBjoern A. Zeeb ifp->if_softc = sca; 74098c230c8SBjoern A. Zeeb strlcpy(ifp->if_xname, name, IFNAMSIZ); 74198c230c8SBjoern A. Zeeb ifp->if_dname = ifc->ifc_name; 74298c230c8SBjoern A. Zeeb ifp->if_dunit = unit; 74398c230c8SBjoern A. Zeeb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 74498c230c8SBjoern A. Zeeb ifp->if_start = epair_start; 74598c230c8SBjoern A. Zeeb ifp->if_ioctl = epair_ioctl; 74698c230c8SBjoern A. Zeeb ifp->if_init = epair_init; 74798c230c8SBjoern A. Zeeb ifp->if_snd.ifq_maxlen = ifqmaxlen; 74898c230c8SBjoern A. Zeeb /* Assign a hopefully unique, locally administered etheraddr. */ 74998c230c8SBjoern A. Zeeb eaddr[0] = 0x02; 75098c230c8SBjoern A. Zeeb eaddr[3] = (ifp->if_index >> 8) & 0xff; 75198c230c8SBjoern A. Zeeb eaddr[4] = ifp->if_index & 0xff; 75298c230c8SBjoern A. Zeeb eaddr[5] = 0x0a; 75398c230c8SBjoern A. Zeeb ether_ifattach(ifp, eaddr); 75498c230c8SBjoern A. Zeeb sca->if_qflush = ifp->if_qflush; 75598c230c8SBjoern A. Zeeb ifp->if_qflush = epair_qflush; 75698c230c8SBjoern A. Zeeb ifp->if_transmit = epair_transmit; 75798c230c8SBjoern A. Zeeb ifp->if_baudrate = IF_Gbps(10UL); /* arbitrary maximum */ 75898c230c8SBjoern A. Zeeb 75998c230c8SBjoern A. Zeeb /* Swap the name and finish initialization of interface <n>b. */ 76098c230c8SBjoern A. Zeeb *dp = 'b'; 76198c230c8SBjoern A. Zeeb 76298c230c8SBjoern A. Zeeb ifp = scb->ifp; 76398c230c8SBjoern A. Zeeb ifp->if_softc = scb; 76498c230c8SBjoern A. Zeeb strlcpy(ifp->if_xname, name, IFNAMSIZ); 76598c230c8SBjoern A. Zeeb ifp->if_dname = ifc->ifc_name; 76698c230c8SBjoern A. Zeeb ifp->if_dunit = unit; 76798c230c8SBjoern A. Zeeb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 76898c230c8SBjoern A. Zeeb ifp->if_start = epair_start; 76998c230c8SBjoern A. Zeeb ifp->if_ioctl = epair_ioctl; 77098c230c8SBjoern A. Zeeb ifp->if_init = epair_init; 77198c230c8SBjoern A. Zeeb ifp->if_snd.ifq_maxlen = ifqmaxlen; 77298c230c8SBjoern A. Zeeb /* We need to play some tricks here for the second interface. */ 77398c230c8SBjoern A. Zeeb strlcpy(name, EPAIRNAME, len); 77498c230c8SBjoern A. Zeeb error = if_clone_create(name, len, (caddr_t)scb); 77598c230c8SBjoern A. Zeeb if (error) 77698c230c8SBjoern A. Zeeb panic("%s: if_clone_createif() for our 2nd iface failed: %d", 77798c230c8SBjoern A. Zeeb __func__, error); 77898c230c8SBjoern A. Zeeb scb->if_qflush = ifp->if_qflush; 77998c230c8SBjoern A. Zeeb ifp->if_qflush = epair_qflush; 78098c230c8SBjoern A. Zeeb ifp->if_transmit = epair_transmit; 78198c230c8SBjoern A. Zeeb ifp->if_baudrate = IF_Gbps(10UL); /* arbitrary maximum */ 78298c230c8SBjoern A. Zeeb 78398c230c8SBjoern A. Zeeb /* 78498c230c8SBjoern A. Zeeb * Restore name to <n>a as the ifp for this will go into the 78598c230c8SBjoern A. Zeeb * cloner list for the initial call. 78698c230c8SBjoern A. Zeeb */ 78798c230c8SBjoern A. Zeeb strlcpy(name, sca->ifp->if_xname, len); 78898c230c8SBjoern A. Zeeb DPRINTF("name='%s/%db' created sca=%p scb=%p\n", name, unit, sca, scb); 78998c230c8SBjoern A. Zeeb 79098c230c8SBjoern A. Zeeb /* Tell the world, that we are ready to rock. */ 79198c230c8SBjoern A. Zeeb sca->ifp->if_drv_flags |= IFF_DRV_RUNNING; 79298c230c8SBjoern A. Zeeb scb->ifp->if_drv_flags |= IFF_DRV_RUNNING; 79398c230c8SBjoern A. Zeeb 79498c230c8SBjoern A. Zeeb return (0); 79598c230c8SBjoern A. Zeeb } 79698c230c8SBjoern A. Zeeb 79798c230c8SBjoern A. Zeeb static int 79898c230c8SBjoern A. Zeeb epair_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) 79998c230c8SBjoern A. Zeeb { 80098c230c8SBjoern A. Zeeb struct ifnet *oifp; 80198c230c8SBjoern A. Zeeb struct epair_softc *sca, *scb; 80298c230c8SBjoern A. Zeeb int unit, error; 80398c230c8SBjoern A. Zeeb 80498c230c8SBjoern A. Zeeb DPRINTF("ifp=%p\n", ifp); 80598c230c8SBjoern A. Zeeb 80698c230c8SBjoern A. Zeeb /* 80798c230c8SBjoern A. Zeeb * In case we called into if_clone_destroyif() ourselves 80898c230c8SBjoern A. Zeeb * again to remove the second interface, the softc will be 80998c230c8SBjoern A. Zeeb * NULL. In that case so not do anything but return success. 81098c230c8SBjoern A. Zeeb */ 81198c230c8SBjoern A. Zeeb if (ifp->if_softc == NULL) 81298c230c8SBjoern A. Zeeb return (0); 81398c230c8SBjoern A. Zeeb 81498c230c8SBjoern A. Zeeb unit = ifp->if_dunit; 81598c230c8SBjoern A. Zeeb sca = ifp->if_softc; 81698c230c8SBjoern A. Zeeb oifp = sca->oifp; 81798c230c8SBjoern A. Zeeb scb = oifp->if_softc; 81898c230c8SBjoern A. Zeeb 81998c230c8SBjoern A. Zeeb DPRINTF("ifp=%p oifp=%p\n", ifp, oifp); 82098c230c8SBjoern A. Zeeb ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 82198c230c8SBjoern A. Zeeb oifp->if_drv_flags &= ~IFF_DRV_RUNNING; 82298c230c8SBjoern A. Zeeb ether_ifdetach(oifp); 82398c230c8SBjoern A. Zeeb ether_ifdetach(ifp); 82498c230c8SBjoern A. Zeeb /* 82598c230c8SBjoern A. Zeeb * Wait for all packets to be dispatched to if_input. 82698c230c8SBjoern A. Zeeb * The numbers can only go down as the interfaces are 82798c230c8SBjoern A. Zeeb * detached so there is no need to use atomics. 82898c230c8SBjoern A. Zeeb */ 82998c230c8SBjoern A. Zeeb DPRINTF("sca refcnt=%u scb refcnt=%u\n", sca->refcount, scb->refcount); 830d0ea4743SBjoern A. Zeeb EPAIR_REFCOUNT_ASSERT(sca->refcount == 1 && scb->refcount == 1, 83198c230c8SBjoern A. Zeeb ("%s: sca->refcount!=1: %d || scb->refcount!=1: %d", 83298c230c8SBjoern A. Zeeb __func__, sca->refcount, scb->refcount)); 83398c230c8SBjoern A. Zeeb 83498c230c8SBjoern A. Zeeb /* 83598c230c8SBjoern A. Zeeb * Get rid of our second half. 83698c230c8SBjoern A. Zeeb */ 83798c230c8SBjoern A. Zeeb oifp->if_softc = NULL; 83898c230c8SBjoern A. Zeeb error = if_clone_destroyif(ifc, oifp); 83998c230c8SBjoern A. Zeeb if (error) 84098c230c8SBjoern A. Zeeb panic("%s: if_clone_destroyif() for our 2nd iface failed: %d", 84198c230c8SBjoern A. Zeeb __func__, error); 84298c230c8SBjoern A. Zeeb 843d0ea4743SBjoern A. Zeeb /* 844d0ea4743SBjoern A. Zeeb * Finish cleaning up. Free them and release the unit. 845d0ea4743SBjoern A. Zeeb * As the other of the two interfaces my reside in a different vnet, 846d0ea4743SBjoern A. Zeeb * we need to switch before freeing them. 847d0ea4743SBjoern A. Zeeb */ 848d0ea4743SBjoern A. Zeeb CURVNET_SET_QUIET(oifp->if_vnet); 84998c230c8SBjoern A. Zeeb if_free_type(oifp, IFT_ETHER); 850d0ea4743SBjoern A. Zeeb CURVNET_RESTORE(); 85198c230c8SBjoern A. Zeeb if_free_type(ifp, IFT_ETHER); 85298c230c8SBjoern A. Zeeb free(scb, M_EPAIR); 85398c230c8SBjoern A. Zeeb free(sca, M_EPAIR); 85498c230c8SBjoern A. Zeeb ifc_free_unit(ifc, unit); 85598c230c8SBjoern A. Zeeb 85698c230c8SBjoern A. Zeeb return (0); 85798c230c8SBjoern A. Zeeb } 85898c230c8SBjoern A. Zeeb 85998c230c8SBjoern A. Zeeb static int 86098c230c8SBjoern A. Zeeb epair_modevent(module_t mod, int type, void *data) 86198c230c8SBjoern A. Zeeb { 862d0ea4743SBjoern A. Zeeb int qlimit; 86398c230c8SBjoern A. Zeeb 86498c230c8SBjoern A. Zeeb switch (type) { 86598c230c8SBjoern A. Zeeb case MOD_LOAD: 86698c230c8SBjoern A. Zeeb /* For now limit us to one global mutex and one inq. */ 867d0ea4743SBjoern A. Zeeb epair_dpcpu_init(); 868d0ea4743SBjoern A. Zeeb epair_nh.nh_qlimit = 42 * ifqmaxlen; /* 42 shall be the number. */ 869d0ea4743SBjoern A. Zeeb if (TUNABLE_INT_FETCH("net.link.epair.netisr_maxqlen", &qlimit)) 870d0ea4743SBjoern A. Zeeb epair_nh.nh_qlimit = qlimit; 871d0ea4743SBjoern A. Zeeb netisr_register(&epair_nh); 87298c230c8SBjoern A. Zeeb if_clone_attach(&epair_cloner); 87398c230c8SBjoern A. Zeeb if (bootverbose) 87498c230c8SBjoern A. Zeeb printf("%s initialized.\n", EPAIRNAME); 87598c230c8SBjoern A. Zeeb break; 87698c230c8SBjoern A. Zeeb case MOD_UNLOAD: 87798c230c8SBjoern A. Zeeb if_clone_detach(&epair_cloner); 878d0ea4743SBjoern A. Zeeb netisr_unregister(&epair_nh); 879d0ea4743SBjoern A. Zeeb epair_dpcpu_detach(); 88098c230c8SBjoern A. Zeeb if (bootverbose) 88198c230c8SBjoern A. Zeeb printf("%s unloaded.\n", EPAIRNAME); 88298c230c8SBjoern A. Zeeb break; 88398c230c8SBjoern A. Zeeb default: 88498c230c8SBjoern A. Zeeb return (EOPNOTSUPP); 88598c230c8SBjoern A. Zeeb } 88698c230c8SBjoern A. Zeeb return (0); 88798c230c8SBjoern A. Zeeb } 88898c230c8SBjoern A. Zeeb 88998c230c8SBjoern A. Zeeb static moduledata_t epair_mod = { 89098c230c8SBjoern A. Zeeb "if_epair", 89198c230c8SBjoern A. Zeeb epair_modevent, 89298c230c8SBjoern A. Zeeb 0 89398c230c8SBjoern A. Zeeb }; 89498c230c8SBjoern A. Zeeb 89598c230c8SBjoern A. Zeeb DECLARE_MODULE(if_epair, epair_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 89698c230c8SBjoern A. Zeeb MODULE_VERSION(if_epair, 1); 897