11cafed39SJonathan Lemon /*- 2fe267a55SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3fe267a55SPedro F. Giffuni * 4d4b5cae4SRobert Watson * Copyright (c) 2007-2009 Robert N. M. Watson 5f2d2d694SRobert Watson * Copyright (c) 2010-2011 Juniper Networks, Inc. 6e3b6e33cSJake Burkholder * All rights reserved. 7e3b6e33cSJake Burkholder * 82d22f334SRobert Watson * This software was developed by Robert N. M. Watson under contract 92d22f334SRobert Watson * to Juniper Networks, Inc. 102d22f334SRobert Watson * 11e3b6e33cSJake Burkholder * Redistribution and use in source and binary forms, with or without 12e3b6e33cSJake Burkholder * modification, are permitted provided that the following conditions 13e3b6e33cSJake Burkholder * are met: 14e3b6e33cSJake Burkholder * 1. Redistributions of source code must retain the above copyright 151cafed39SJonathan Lemon * notice, this list of conditions and the following disclaimer. 16e3b6e33cSJake Burkholder * 2. Redistributions in binary form must reproduce the above copyright 17e3b6e33cSJake Burkholder * notice, this list of conditions and the following disclaimer in the 18e3b6e33cSJake Burkholder * documentation and/or other materials provided with the distribution. 19e3b6e33cSJake Burkholder * 201cafed39SJonathan Lemon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 211cafed39SJonathan Lemon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221cafed39SJonathan Lemon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231cafed39SJonathan Lemon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 241cafed39SJonathan Lemon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251cafed39SJonathan Lemon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261cafed39SJonathan Lemon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271cafed39SJonathan Lemon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281cafed39SJonathan Lemon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291cafed39SJonathan Lemon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301cafed39SJonathan Lemon * SUCH DAMAGE. 31e3b6e33cSJake Burkholder */ 32e3b6e33cSJake Burkholder 33d4b5cae4SRobert Watson #include <sys/cdefs.h> 34d4b5cae4SRobert Watson __FBSDID("$FreeBSD$"); 35d4b5cae4SRobert Watson 36d4b5cae4SRobert Watson /* 37d4b5cae4SRobert Watson * netisr is a packet dispatch service, allowing synchronous (directly 38d4b5cae4SRobert Watson * dispatched) and asynchronous (deferred dispatch) processing of packets by 39d4b5cae4SRobert Watson * registered protocol handlers. Callers pass a protocol identifier and 40d4b5cae4SRobert Watson * packet to netisr, along with a direct dispatch hint, and work will either 410a32e29fSRobert Watson * be immediately processed by the registered handler, or passed to a 420a32e29fSRobert Watson * software interrupt (SWI) thread for deferred dispatch. Callers will 430a32e29fSRobert Watson * generally select one or the other based on: 44d4b5cae4SRobert Watson * 450a32e29fSRobert Watson * - Whether directly dispatching a netisr handler lead to code reentrance or 46d4b5cae4SRobert Watson * lock recursion, such as entering the socket code from the socket code. 470a32e29fSRobert Watson * - Whether directly dispatching a netisr handler lead to recursive 48d4b5cae4SRobert Watson * processing, such as when decapsulating several wrapped layers of tunnel 49d4b5cae4SRobert Watson * information (IPSEC within IPSEC within ...). 50d4b5cae4SRobert Watson * 51d4b5cae4SRobert Watson * Maintaining ordering for protocol streams is a critical design concern. 52d4b5cae4SRobert Watson * Enforcing ordering limits the opportunity for concurrency, but maintains 53d4b5cae4SRobert Watson * the strong ordering requirements found in some protocols, such as TCP. Of 54d4b5cae4SRobert Watson * related concern is CPU affinity--it is desirable to process all data 55d4b5cae4SRobert Watson * associated with a particular stream on the same CPU over time in order to 56d4b5cae4SRobert Watson * avoid acquiring locks associated with the connection on different CPUs, 57d4b5cae4SRobert Watson * keep connection data in one cache, and to generally encourage associated 58d4b5cae4SRobert Watson * user threads to live on the same CPU as the stream. It's also desirable 59d4b5cae4SRobert Watson * to avoid lock migration and contention where locks are associated with 60d4b5cae4SRobert Watson * more than one flow. 61d4b5cae4SRobert Watson * 62d4b5cae4SRobert Watson * netisr supports several policy variations, represented by the 630a32e29fSRobert Watson * NETISR_POLICY_* constants, allowing protocols to play various roles in 64d4b5cae4SRobert Watson * identifying flows, assigning work to CPUs, etc. These are described in 650a32e29fSRobert Watson * netisr.h. 66d4b5cae4SRobert Watson */ 67d4b5cae4SRobert Watson 68d4b5cae4SRobert Watson #include "opt_ddb.h" 69f0796cd2SGleb Smirnoff #include "opt_device_polling.h" 701d8cd39eSRobert Watson 71e3b6e33cSJake Burkholder #include <sys/param.h> 72e3b6e33cSJake Burkholder #include <sys/bus.h> 73e3b6e33cSJake Burkholder #include <sys/kernel.h> 741cafed39SJonathan Lemon #include <sys/kthread.h> 758ec07310SGleb Smirnoff #include <sys/malloc.h> 76d4b5cae4SRobert Watson #include <sys/interrupt.h> 771cafed39SJonathan Lemon #include <sys/lock.h> 781cafed39SJonathan Lemon #include <sys/mbuf.h> 79d4b5cae4SRobert Watson #include <sys/mutex.h> 8053402767SRobert Watson #include <sys/pcpu.h> 81d4b5cae4SRobert Watson #include <sys/proc.h> 82d4b5cae4SRobert Watson #include <sys/rmlock.h> 83d4b5cae4SRobert Watson #include <sys/sched.h> 84d4b5cae4SRobert Watson #include <sys/smp.h> 851cafed39SJonathan Lemon #include <sys/socket.h> 86d4b5cae4SRobert Watson #include <sys/sysctl.h> 87d4b5cae4SRobert Watson #include <sys/systm.h> 88d4b5cae4SRobert Watson 89d4b5cae4SRobert Watson #ifdef DDB 90d4b5cae4SRobert Watson #include <ddb/ddb.h> 91d4b5cae4SRobert Watson #endif 921cafed39SJonathan Lemon 93938448cdSRobert Watson #define _WANT_NETISR_INTERNAL /* Enable definitions from netisr_internal.h */ 941cafed39SJonathan Lemon #include <net/if.h> 951cafed39SJonathan Lemon #include <net/if_var.h> 96*2c2b37adSJustin Hibbits #include <net/if_private.h> 97e3b6e33cSJake Burkholder #include <net/netisr.h> 98938448cdSRobert Watson #include <net/netisr_internal.h> 99530c0060SRobert Watson #include <net/vnet.h> 100e3b6e33cSJake Burkholder 101d4b5cae4SRobert Watson /*- 102d4b5cae4SRobert Watson * Synchronize use and modification of the registered netisr data structures; 103d4b5cae4SRobert Watson * acquire a read lock while modifying the set of registered protocols to 104d4b5cae4SRobert Watson * prevent partially registered or unregistered protocols from being run. 105d4b5cae4SRobert Watson * 106d4b5cae4SRobert Watson * The following data structures and fields are protected by this lock: 107d4b5cae4SRobert Watson * 108938448cdSRobert Watson * - The netisr_proto array, including all fields of struct netisr_proto. 109d4b5cae4SRobert Watson * - The nws array, including all fields of struct netisr_worker. 110d4b5cae4SRobert Watson * - The nws_array array. 111d4b5cae4SRobert Watson * 112d4b5cae4SRobert Watson * Note: the NETISR_LOCKING define controls whether read locks are acquired 113d4b5cae4SRobert Watson * in packet processing paths requiring netisr registration stability. This 1140a32e29fSRobert Watson * is disabled by default as it can lead to measurable performance 115d4b5cae4SRobert Watson * degradation even with rmlocks (3%-6% for loopback ping-pong traffic), and 116d4b5cae4SRobert Watson * because netisr registration and unregistration is extremely rare at 117d4b5cae4SRobert Watson * runtime. If it becomes more common, this decision should be revisited. 118d4b5cae4SRobert Watson * 119d4b5cae4SRobert Watson * XXXRW: rmlocks don't support assertions. 120d4b5cae4SRobert Watson */ 121d4b5cae4SRobert Watson static struct rmlock netisr_rmlock; 122d4b5cae4SRobert Watson #define NETISR_LOCK_INIT() rm_init_flags(&netisr_rmlock, "netisr", \ 123d4b5cae4SRobert Watson RM_NOWITNESS) 124d4b5cae4SRobert Watson #define NETISR_LOCK_ASSERT() 125d4b5cae4SRobert Watson #define NETISR_RLOCK(tracker) rm_rlock(&netisr_rmlock, (tracker)) 126d4b5cae4SRobert Watson #define NETISR_RUNLOCK(tracker) rm_runlock(&netisr_rmlock, (tracker)) 127d4b5cae4SRobert Watson #define NETISR_WLOCK() rm_wlock(&netisr_rmlock) 128d4b5cae4SRobert Watson #define NETISR_WUNLOCK() rm_wunlock(&netisr_rmlock) 129d4b5cae4SRobert Watson /* #define NETISR_LOCKING */ 130e3b6e33cSJake Burkholder 1317029da5cSPawel Biernacki static SYSCTL_NODE(_net, OID_AUTO, isr, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1327029da5cSPawel Biernacki "netisr"); 1331cafed39SJonathan Lemon 134d4b5cae4SRobert Watson /*- 135f2d2d694SRobert Watson * Three global direct dispatch policies are supported: 136d4b5cae4SRobert Watson * 137da162ca8SSergey Kandaurov * NETISR_DISPATCH_DEFERRED: All work is deferred for a netisr, regardless of 138028ecc7aSGordon Bergling * context (may be overridden by protocols). 139d4b5cae4SRobert Watson * 140f2d2d694SRobert Watson * NETISR_DISPATCH_HYBRID: If the executing context allows direct dispatch, 141f2d2d694SRobert Watson * and we're running on the CPU the work would be performed on, then direct 142f2d2d694SRobert Watson * dispatch it if it wouldn't violate ordering constraints on the workstream. 143d4b5cae4SRobert Watson * 144f2d2d694SRobert Watson * NETISR_DISPATCH_DIRECT: If the executing context allows direct dispatch, 145f2d2d694SRobert Watson * always direct dispatch. (The default.) 146d4b5cae4SRobert Watson * 147d4b5cae4SRobert Watson * Notice that changing the global policy could lead to short periods of 148d4b5cae4SRobert Watson * misordered processing, but this is considered acceptable as compared to 149f2d2d694SRobert Watson * the complexity of enforcing ordering during policy changes. Protocols can 150f2d2d694SRobert Watson * override the global policy (when they're not doing that, they select 151f2d2d694SRobert Watson * NETISR_DISPATCH_DEFAULT). 152d4b5cae4SRobert Watson */ 153f2d2d694SRobert Watson #define NETISR_DISPATCH_POLICY_DEFAULT NETISR_DISPATCH_DIRECT 154f2d2d694SRobert Watson #define NETISR_DISPATCH_POLICY_MAXSTR 20 /* Used for temporary buffers. */ 155f2d2d694SRobert Watson static u_int netisr_dispatch_policy = NETISR_DISPATCH_POLICY_DEFAULT; 156f2d2d694SRobert Watson static int sysctl_netisr_dispatch_policy(SYSCTL_HANDLER_ARGS); 1577029da5cSPawel Biernacki SYSCTL_PROC(_net_isr, OID_AUTO, dispatch, 1587029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 159af3b2549SHans Petter Selasky 0, 0, sysctl_netisr_dispatch_policy, "A", 160f2d2d694SRobert Watson "netisr dispatch policy"); 161e3b6e33cSJake Burkholder 162f2d2d694SRobert Watson /* 163d4b5cae4SRobert Watson * Allow the administrator to limit the number of threads (CPUs) to use for 164d4b5cae4SRobert Watson * netisr. We don't check netisr_maxthreads before creating the thread for 165a9467c3cSHiren Panchasara * CPU 0. This must be set at boot. We will create at most one thread per CPU. 166a9467c3cSHiren Panchasara * By default we initialize this to 1 which would assign just 1 cpu (cpu0) and 167a9467c3cSHiren Panchasara * therefore only 1 workstream. If set to -1, netisr would use all cpus 168a9467c3cSHiren Panchasara * (mp_ncpus) and therefore would have those many workstreams. One workstream 169a9467c3cSHiren Panchasara * per thread (CPU). 1705fd04e38SRobert Watson */ 171a9467c3cSHiren Panchasara static int netisr_maxthreads = 1; /* Max number of threads. */ 17278494902SPawel Jakub Dawidek SYSCTL_INT(_net_isr, OID_AUTO, maxthreads, CTLFLAG_RDTUN, 173d4b5cae4SRobert Watson &netisr_maxthreads, 0, 174d4b5cae4SRobert Watson "Use at most this many CPUs for netisr processing"); 1755fd04e38SRobert Watson 176d4b5cae4SRobert Watson static int netisr_bindthreads = 0; /* Bind threads to CPUs. */ 17778494902SPawel Jakub Dawidek SYSCTL_INT(_net_isr, OID_AUTO, bindthreads, CTLFLAG_RDTUN, 178d4b5cae4SRobert Watson &netisr_bindthreads, 0, "Bind netisr threads to CPUs."); 179d4b5cae4SRobert Watson 180d4b5cae4SRobert Watson /* 1810a32e29fSRobert Watson * Limit per-workstream mbuf queue limits s to at most net.isr.maxqlimit, 1820a32e29fSRobert Watson * both for initial configuration and later modification using 1830a32e29fSRobert Watson * netisr_setqlimit(). 184d4b5cae4SRobert Watson */ 185d4b5cae4SRobert Watson #define NETISR_DEFAULT_MAXQLIMIT 10240 186d4b5cae4SRobert Watson static u_int netisr_maxqlimit = NETISR_DEFAULT_MAXQLIMIT; 187f88910cdSMatthew D Fleming SYSCTL_UINT(_net_isr, OID_AUTO, maxqlimit, CTLFLAG_RDTUN, 188d4b5cae4SRobert Watson &netisr_maxqlimit, 0, 189d4b5cae4SRobert Watson "Maximum netisr per-protocol, per-CPU queue depth."); 190d4b5cae4SRobert Watson 191d4b5cae4SRobert Watson /* 1920a32e29fSRobert Watson * The default per-workstream mbuf queue limit for protocols that don't 1930a32e29fSRobert Watson * initialize the nh_qlimit field of their struct netisr_handler. If this is 1940a32e29fSRobert Watson * set above netisr_maxqlimit, we truncate it to the maximum during boot. 195d4b5cae4SRobert Watson */ 196d4b5cae4SRobert Watson #define NETISR_DEFAULT_DEFAULTQLIMIT 256 197d4b5cae4SRobert Watson static u_int netisr_defaultqlimit = NETISR_DEFAULT_DEFAULTQLIMIT; 198f88910cdSMatthew D Fleming SYSCTL_UINT(_net_isr, OID_AUTO, defaultqlimit, CTLFLAG_RDTUN, 199d4b5cae4SRobert Watson &netisr_defaultqlimit, 0, 200d4b5cae4SRobert Watson "Default netisr per-protocol, per-CPU queue limit if not set by protocol"); 201d4b5cae4SRobert Watson 202d4b5cae4SRobert Watson /* 203938448cdSRobert Watson * Store and export the compile-time constant NETISR_MAXPROT limit on the 204938448cdSRobert Watson * number of protocols that can register with netisr at a time. This is 205938448cdSRobert Watson * required for crashdump analysis, as it sizes netisr_proto[]. 206d4b5cae4SRobert Watson */ 207938448cdSRobert Watson static u_int netisr_maxprot = NETISR_MAXPROT; 208f88910cdSMatthew D Fleming SYSCTL_UINT(_net_isr, OID_AUTO, maxprot, CTLFLAG_RD, 209938448cdSRobert Watson &netisr_maxprot, 0, 210938448cdSRobert Watson "Compile-time limit on the number of protocols supported by netisr."); 211d4b5cae4SRobert Watson 212d4b5cae4SRobert Watson /* 213938448cdSRobert Watson * The netisr_proto array describes all registered protocols, indexed by 214938448cdSRobert Watson * protocol number. See netisr_internal.h for more details. 215d4b5cae4SRobert Watson */ 216938448cdSRobert Watson static struct netisr_proto netisr_proto[NETISR_MAXPROT]; 217d4b5cae4SRobert Watson 218484149deSBjoern A. Zeeb #ifdef VIMAGE 219484149deSBjoern A. Zeeb /* 220484149deSBjoern A. Zeeb * The netisr_enable array describes a per-VNET flag for registered 221484149deSBjoern A. Zeeb * protocols on whether this netisr is active in this VNET or not. 222484149deSBjoern A. Zeeb * netisr_register() will automatically enable the netisr for the 223484149deSBjoern A. Zeeb * default VNET and all currently active instances. 224484149deSBjoern A. Zeeb * netisr_unregister() will disable all active VNETs, including vnet0. 225484149deSBjoern A. Zeeb * Individual network stack instances can be enabled/disabled by the 226484149deSBjoern A. Zeeb * netisr_(un)register _vnet() functions. 227484149deSBjoern A. Zeeb * With this we keep the one netisr_proto per protocol but add a 228484149deSBjoern A. Zeeb * mechanism to stop netisr processing for vnet teardown. 229484149deSBjoern A. Zeeb * Apart from that we expect a VNET to always be enabled. 230484149deSBjoern A. Zeeb */ 2315f901c92SAndrew Turner VNET_DEFINE_STATIC(u_int, netisr_enable[NETISR_MAXPROT]); 232484149deSBjoern A. Zeeb #define V_netisr_enable VNET(netisr_enable) 233484149deSBjoern A. Zeeb #endif 234484149deSBjoern A. Zeeb 235d4b5cae4SRobert Watson /* 236938448cdSRobert Watson * Per-CPU workstream data. See netisr_internal.h for more details. 237d4b5cae4SRobert Watson */ 23853402767SRobert Watson DPCPU_DEFINE(struct netisr_workstream, nws); 239d4b5cae4SRobert Watson 240d4b5cae4SRobert Watson /* 241d4b5cae4SRobert Watson * Map contiguous values between 0 and nws_count into CPU IDs appropriate for 24253402767SRobert Watson * accessing workstreams. This allows constructions of the form 24353402767SRobert Watson * DPCPU_ID_GET(nws_array[arbitraryvalue % nws_count], nws). 244d4b5cae4SRobert Watson */ 245d4b5cae4SRobert Watson static u_int nws_array[MAXCPU]; 246d4b5cae4SRobert Watson 247d4b5cae4SRobert Watson /* 248d4b5cae4SRobert Watson * Number of registered workstreams. Will be at most the number of running 249d4b5cae4SRobert Watson * CPUs once fully started. 250d4b5cae4SRobert Watson */ 251d4b5cae4SRobert Watson static u_int nws_count; 252f88910cdSMatthew D Fleming SYSCTL_UINT(_net_isr, OID_AUTO, numthreads, CTLFLAG_RD, 253d4b5cae4SRobert Watson &nws_count, 0, "Number of extant netisr threads."); 254d4b5cae4SRobert Watson 255d4b5cae4SRobert Watson /* 256d4b5cae4SRobert Watson * Synchronization for each workstream: a mutex protects all mutable fields 257d4b5cae4SRobert Watson * in each stream, including per-protocol state (mbuf queues). The SWI is 258d4b5cae4SRobert Watson * woken up if asynchronous dispatch is required. 259d4b5cae4SRobert Watson */ 260d4b5cae4SRobert Watson #define NWS_LOCK(s) mtx_lock(&(s)->nws_mtx) 261d4b5cae4SRobert Watson #define NWS_LOCK_ASSERT(s) mtx_assert(&(s)->nws_mtx, MA_OWNED) 262d4b5cae4SRobert Watson #define NWS_UNLOCK(s) mtx_unlock(&(s)->nws_mtx) 263d4b5cae4SRobert Watson #define NWS_SIGNAL(s) swi_sched((s)->nws_swi_cookie, 0) 264d4b5cae4SRobert Watson 265d4b5cae4SRobert Watson /* 266d4b5cae4SRobert Watson * Utility routines for protocols that implement their own mapping of flows 267d4b5cae4SRobert Watson * to CPUs. 268d4b5cae4SRobert Watson */ 269d4b5cae4SRobert Watson u_int 270d4b5cae4SRobert Watson netisr_get_cpucount(void) 271d4b5cae4SRobert Watson { 272d4b5cae4SRobert Watson 273d4b5cae4SRobert Watson return (nws_count); 2745fd04e38SRobert Watson } 275d4b5cae4SRobert Watson 276d4b5cae4SRobert Watson u_int 277d4b5cae4SRobert Watson netisr_get_cpuid(u_int cpunumber) 278d4b5cae4SRobert Watson { 279d4b5cae4SRobert Watson 280fdf95c0bSAndrey V. Elsukov return (nws_array[cpunumber % nws_count]); 2815fd04e38SRobert Watson } 2825fd04e38SRobert Watson 2835fd04e38SRobert Watson /* 2840a32e29fSRobert Watson * The default implementation of flow -> CPU ID mapping. 285d4b5cae4SRobert Watson * 286d4b5cae4SRobert Watson * Non-static so that protocols can use it to map their own work to specific 287d4b5cae4SRobert Watson * CPUs in a manner consistent to netisr for affinity purposes. 288d4b5cae4SRobert Watson */ 289d4b5cae4SRobert Watson u_int 290d4b5cae4SRobert Watson netisr_default_flow2cpu(u_int flowid) 291d4b5cae4SRobert Watson { 292d4b5cae4SRobert Watson 293d4b5cae4SRobert Watson return (nws_array[flowid % nws_count]); 294d4b5cae4SRobert Watson } 295d4b5cae4SRobert Watson 296d4b5cae4SRobert Watson /* 297f2d2d694SRobert Watson * Dispatch tunable and sysctl configuration. 298f2d2d694SRobert Watson */ 299f2d2d694SRobert Watson struct netisr_dispatch_table_entry { 300f2d2d694SRobert Watson u_int ndte_policy; 301f2d2d694SRobert Watson const char *ndte_policy_str; 302f2d2d694SRobert Watson }; 303f2d2d694SRobert Watson static const struct netisr_dispatch_table_entry netisr_dispatch_table[] = { 304f2d2d694SRobert Watson { NETISR_DISPATCH_DEFAULT, "default" }, 305f2d2d694SRobert Watson { NETISR_DISPATCH_DEFERRED, "deferred" }, 306f2d2d694SRobert Watson { NETISR_DISPATCH_HYBRID, "hybrid" }, 307f2d2d694SRobert Watson { NETISR_DISPATCH_DIRECT, "direct" }, 308f2d2d694SRobert Watson }; 309f2d2d694SRobert Watson 310f2d2d694SRobert Watson static void 311f2d2d694SRobert Watson netisr_dispatch_policy_to_str(u_int dispatch_policy, char *buffer, 312f2d2d694SRobert Watson u_int buflen) 313f2d2d694SRobert Watson { 314f2d2d694SRobert Watson const struct netisr_dispatch_table_entry *ndtep; 315f2d2d694SRobert Watson const char *str; 316f2d2d694SRobert Watson u_int i; 317f2d2d694SRobert Watson 318f2d2d694SRobert Watson str = "unknown"; 3198dfea464SPedro F. Giffuni for (i = 0; i < nitems(netisr_dispatch_table); i++) { 320f2d2d694SRobert Watson ndtep = &netisr_dispatch_table[i]; 321f2d2d694SRobert Watson if (ndtep->ndte_policy == dispatch_policy) { 322f2d2d694SRobert Watson str = ndtep->ndte_policy_str; 323f2d2d694SRobert Watson break; 324f2d2d694SRobert Watson } 325f2d2d694SRobert Watson } 326f2d2d694SRobert Watson snprintf(buffer, buflen, "%s", str); 327f2d2d694SRobert Watson } 328f2d2d694SRobert Watson 329f2d2d694SRobert Watson static int 330f2d2d694SRobert Watson netisr_dispatch_policy_from_str(const char *str, u_int *dispatch_policyp) 331f2d2d694SRobert Watson { 332f2d2d694SRobert Watson const struct netisr_dispatch_table_entry *ndtep; 333f2d2d694SRobert Watson u_int i; 334f2d2d694SRobert Watson 3358dfea464SPedro F. Giffuni for (i = 0; i < nitems(netisr_dispatch_table); i++) { 336f2d2d694SRobert Watson ndtep = &netisr_dispatch_table[i]; 337f2d2d694SRobert Watson if (strcmp(ndtep->ndte_policy_str, str) == 0) { 338f2d2d694SRobert Watson *dispatch_policyp = ndtep->ndte_policy; 339f2d2d694SRobert Watson return (0); 340f2d2d694SRobert Watson } 341f2d2d694SRobert Watson } 342f2d2d694SRobert Watson return (EINVAL); 343f2d2d694SRobert Watson } 344f2d2d694SRobert Watson 345f2d2d694SRobert Watson static int 346f2d2d694SRobert Watson sysctl_netisr_dispatch_policy(SYSCTL_HANDLER_ARGS) 347f2d2d694SRobert Watson { 348f2d2d694SRobert Watson char tmp[NETISR_DISPATCH_POLICY_MAXSTR]; 3499033ad5fSPawel Biernacki size_t len; 350f2d2d694SRobert Watson u_int dispatch_policy; 351f2d2d694SRobert Watson int error; 352f2d2d694SRobert Watson 353f2d2d694SRobert Watson netisr_dispatch_policy_to_str(netisr_dispatch_policy, tmp, 354f2d2d694SRobert Watson sizeof(tmp)); 3559033ad5fSPawel Biernacki /* 3569033ad5fSPawel Biernacki * netisr is initialised very early during the boot when malloc isn't 3579033ad5fSPawel Biernacki * available yet so we can't use sysctl_handle_string() to process 3589033ad5fSPawel Biernacki * any non-default value that was potentially set via loader. 3599033ad5fSPawel Biernacki */ 3609033ad5fSPawel Biernacki if (req->newptr != NULL) { 3619033ad5fSPawel Biernacki len = req->newlen - req->newidx; 3629033ad5fSPawel Biernacki if (len >= NETISR_DISPATCH_POLICY_MAXSTR) 3639033ad5fSPawel Biernacki return (EINVAL); 3649033ad5fSPawel Biernacki error = SYSCTL_IN(req, tmp, len); 3659033ad5fSPawel Biernacki if (error == 0) { 3669033ad5fSPawel Biernacki tmp[len] = '\0'; 367f2d2d694SRobert Watson error = netisr_dispatch_policy_from_str(tmp, 368f2d2d694SRobert Watson &dispatch_policy); 3699033ad5fSPawel Biernacki if (error == 0 && 3709033ad5fSPawel Biernacki dispatch_policy == NETISR_DISPATCH_DEFAULT) 371f2d2d694SRobert Watson error = EINVAL; 372933e681dSDavide Italiano if (error == 0) 373f2d2d694SRobert Watson netisr_dispatch_policy = dispatch_policy; 374f2d2d694SRobert Watson } 3759033ad5fSPawel Biernacki } else { 3769033ad5fSPawel Biernacki error = sysctl_handle_string(oidp, tmp, sizeof(tmp), req); 3779033ad5fSPawel Biernacki } 378f2d2d694SRobert Watson return (error); 379f2d2d694SRobert Watson } 380f2d2d694SRobert Watson 381f2d2d694SRobert Watson /* 382d4b5cae4SRobert Watson * Register a new netisr handler, which requires initializing per-protocol 383d4b5cae4SRobert Watson * fields for each workstream. All netisr work is briefly suspended while 384d4b5cae4SRobert Watson * the protocol is installed. 3851cafed39SJonathan Lemon */ 3861cafed39SJonathan Lemon void 387d4b5cae4SRobert Watson netisr_register(const struct netisr_handler *nhp) 3881cafed39SJonathan Lemon { 389484149deSBjoern A. Zeeb VNET_ITERATOR_DECL(vnet_iter); 390d4b5cae4SRobert Watson struct netisr_work *npwp; 391d4b5cae4SRobert Watson const char *name; 392d4b5cae4SRobert Watson u_int i, proto; 3931cafed39SJonathan Lemon 394d4b5cae4SRobert Watson proto = nhp->nh_proto; 395d4b5cae4SRobert Watson name = nhp->nh_name; 39659dd72d0SRobert Watson 3977902224cSSam Leffler /* 398d4b5cae4SRobert Watson * Test that the requested registration is valid. 3997902224cSSam Leffler */ 400d4b5cae4SRobert Watson KASSERT(nhp->nh_name != NULL, 401d4b5cae4SRobert Watson ("%s: nh_name NULL for %u", __func__, proto)); 402d4b5cae4SRobert Watson KASSERT(nhp->nh_handler != NULL, 403d4b5cae4SRobert Watson ("%s: nh_handler NULL for %s", __func__, name)); 404d4b5cae4SRobert Watson KASSERT(nhp->nh_policy == NETISR_POLICY_SOURCE || 405d4b5cae4SRobert Watson nhp->nh_policy == NETISR_POLICY_FLOW || 406d4b5cae4SRobert Watson nhp->nh_policy == NETISR_POLICY_CPU, 407d4b5cae4SRobert Watson ("%s: unsupported nh_policy %u for %s", __func__, 408d4b5cae4SRobert Watson nhp->nh_policy, name)); 409d4b5cae4SRobert Watson KASSERT(nhp->nh_policy == NETISR_POLICY_FLOW || 410d4b5cae4SRobert Watson nhp->nh_m2flow == NULL, 411d4b5cae4SRobert Watson ("%s: nh_policy != FLOW but m2flow defined for %s", __func__, 412d4b5cae4SRobert Watson name)); 413d4b5cae4SRobert Watson KASSERT(nhp->nh_policy == NETISR_POLICY_CPU || nhp->nh_m2cpuid == NULL, 414d4b5cae4SRobert Watson ("%s: nh_policy != CPU but m2cpuid defined for %s", __func__, 415d4b5cae4SRobert Watson name)); 416d4b5cae4SRobert Watson KASSERT(nhp->nh_policy != NETISR_POLICY_CPU || nhp->nh_m2cpuid != NULL, 417d4b5cae4SRobert Watson ("%s: nh_policy == CPU but m2cpuid not defined for %s", __func__, 418d4b5cae4SRobert Watson name)); 419f2d2d694SRobert Watson KASSERT(nhp->nh_dispatch == NETISR_DISPATCH_DEFAULT || 420f2d2d694SRobert Watson nhp->nh_dispatch == NETISR_DISPATCH_DEFERRED || 421f2d2d694SRobert Watson nhp->nh_dispatch == NETISR_DISPATCH_HYBRID || 422f2d2d694SRobert Watson nhp->nh_dispatch == NETISR_DISPATCH_DIRECT, 423f2d2d694SRobert Watson ("%s: invalid nh_dispatch (%u)", __func__, nhp->nh_dispatch)); 424f2d2d694SRobert Watson 425d4b5cae4SRobert Watson KASSERT(proto < NETISR_MAXPROT, 426d4b5cae4SRobert Watson ("%s(%u, %s): protocol too big", __func__, proto, name)); 427d4b5cae4SRobert Watson 428d4b5cae4SRobert Watson /* 429d4b5cae4SRobert Watson * Test that no existing registration exists for this protocol. 430d4b5cae4SRobert Watson */ 431d4b5cae4SRobert Watson NETISR_WLOCK(); 432938448cdSRobert Watson KASSERT(netisr_proto[proto].np_name == NULL, 433d4b5cae4SRobert Watson ("%s(%u, %s): name present", __func__, proto, name)); 434938448cdSRobert Watson KASSERT(netisr_proto[proto].np_handler == NULL, 435d4b5cae4SRobert Watson ("%s(%u, %s): handler present", __func__, proto, name)); 436d4b5cae4SRobert Watson 437938448cdSRobert Watson netisr_proto[proto].np_name = name; 438938448cdSRobert Watson netisr_proto[proto].np_handler = nhp->nh_handler; 439938448cdSRobert Watson netisr_proto[proto].np_m2flow = nhp->nh_m2flow; 440938448cdSRobert Watson netisr_proto[proto].np_m2cpuid = nhp->nh_m2cpuid; 441938448cdSRobert Watson netisr_proto[proto].np_drainedcpu = nhp->nh_drainedcpu; 442d4b5cae4SRobert Watson if (nhp->nh_qlimit == 0) 443938448cdSRobert Watson netisr_proto[proto].np_qlimit = netisr_defaultqlimit; 444d4b5cae4SRobert Watson else if (nhp->nh_qlimit > netisr_maxqlimit) { 445d4b5cae4SRobert Watson printf("%s: %s requested queue limit %u capped to " 446d4b5cae4SRobert Watson "net.isr.maxqlimit %u\n", __func__, name, nhp->nh_qlimit, 447d4b5cae4SRobert Watson netisr_maxqlimit); 448938448cdSRobert Watson netisr_proto[proto].np_qlimit = netisr_maxqlimit; 449d4b5cae4SRobert Watson } else 450938448cdSRobert Watson netisr_proto[proto].np_qlimit = nhp->nh_qlimit; 451938448cdSRobert Watson netisr_proto[proto].np_policy = nhp->nh_policy; 452f2d2d694SRobert Watson netisr_proto[proto].np_dispatch = nhp->nh_dispatch; 4533aa6d94eSJohn Baldwin CPU_FOREACH(i) { 45453402767SRobert Watson npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto]; 455d4b5cae4SRobert Watson bzero(npwp, sizeof(*npwp)); 456938448cdSRobert Watson npwp->nw_qlimit = netisr_proto[proto].np_qlimit; 4571cafed39SJonathan Lemon } 458484149deSBjoern A. Zeeb 459484149deSBjoern A. Zeeb #ifdef VIMAGE 460484149deSBjoern A. Zeeb /* 461484149deSBjoern A. Zeeb * Test that we are in vnet0 and have a curvnet set. 462484149deSBjoern A. Zeeb */ 463484149deSBjoern A. Zeeb KASSERT(curvnet != NULL, ("%s: curvnet is NULL", __func__)); 464484149deSBjoern A. Zeeb KASSERT(IS_DEFAULT_VNET(curvnet), ("%s: curvnet %p is not vnet0 %p", 465484149deSBjoern A. Zeeb __func__, curvnet, vnet0)); 466484149deSBjoern A. Zeeb VNET_LIST_RLOCK_NOSLEEP(); 467484149deSBjoern A. Zeeb VNET_FOREACH(vnet_iter) { 468484149deSBjoern A. Zeeb CURVNET_SET(vnet_iter); 469484149deSBjoern A. Zeeb V_netisr_enable[proto] = 1; 470484149deSBjoern A. Zeeb CURVNET_RESTORE(); 471484149deSBjoern A. Zeeb } 472484149deSBjoern A. Zeeb VNET_LIST_RUNLOCK_NOSLEEP(); 473484149deSBjoern A. Zeeb #endif 474d4b5cae4SRobert Watson NETISR_WUNLOCK(); 4751cafed39SJonathan Lemon } 4761cafed39SJonathan Lemon 4771cafed39SJonathan Lemon /* 478d4b5cae4SRobert Watson * Clear drop counters across all workstreams for a protocol. 479d4b5cae4SRobert Watson */ 480d4b5cae4SRobert Watson void 481d4b5cae4SRobert Watson netisr_clearqdrops(const struct netisr_handler *nhp) 482d4b5cae4SRobert Watson { 483d4b5cae4SRobert Watson struct netisr_work *npwp; 484d4b5cae4SRobert Watson #ifdef INVARIANTS 485d4b5cae4SRobert Watson const char *name; 486d4b5cae4SRobert Watson #endif 487d4b5cae4SRobert Watson u_int i, proto; 488d4b5cae4SRobert Watson 489d4b5cae4SRobert Watson proto = nhp->nh_proto; 490d4b5cae4SRobert Watson #ifdef INVARIANTS 491d4b5cae4SRobert Watson name = nhp->nh_name; 492d4b5cae4SRobert Watson #endif 493d4b5cae4SRobert Watson KASSERT(proto < NETISR_MAXPROT, 494d4b5cae4SRobert Watson ("%s(%u): protocol too big for %s", __func__, proto, name)); 495d4b5cae4SRobert Watson 496d4b5cae4SRobert Watson NETISR_WLOCK(); 497938448cdSRobert Watson KASSERT(netisr_proto[proto].np_handler != NULL, 498d4b5cae4SRobert Watson ("%s(%u): protocol not registered for %s", __func__, proto, 499d4b5cae4SRobert Watson name)); 500d4b5cae4SRobert Watson 5013aa6d94eSJohn Baldwin CPU_FOREACH(i) { 50253402767SRobert Watson npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto]; 503d4b5cae4SRobert Watson npwp->nw_qdrops = 0; 504d4b5cae4SRobert Watson } 505d4b5cae4SRobert Watson NETISR_WUNLOCK(); 506d4b5cae4SRobert Watson } 507d4b5cae4SRobert Watson 508d4b5cae4SRobert Watson /* 5090a32e29fSRobert Watson * Query current drop counters across all workstreams for a protocol. 510d4b5cae4SRobert Watson */ 511d4b5cae4SRobert Watson void 512d4b5cae4SRobert Watson netisr_getqdrops(const struct netisr_handler *nhp, u_int64_t *qdropp) 513d4b5cae4SRobert Watson { 514d4b5cae4SRobert Watson struct netisr_work *npwp; 515d4b5cae4SRobert Watson struct rm_priotracker tracker; 516d4b5cae4SRobert Watson #ifdef INVARIANTS 517d4b5cae4SRobert Watson const char *name; 518d4b5cae4SRobert Watson #endif 519d4b5cae4SRobert Watson u_int i, proto; 520d4b5cae4SRobert Watson 521d4b5cae4SRobert Watson *qdropp = 0; 522d4b5cae4SRobert Watson proto = nhp->nh_proto; 523d4b5cae4SRobert Watson #ifdef INVARIANTS 524d4b5cae4SRobert Watson name = nhp->nh_name; 525d4b5cae4SRobert Watson #endif 526d4b5cae4SRobert Watson KASSERT(proto < NETISR_MAXPROT, 527d4b5cae4SRobert Watson ("%s(%u): protocol too big for %s", __func__, proto, name)); 528d4b5cae4SRobert Watson 529d4b5cae4SRobert Watson NETISR_RLOCK(&tracker); 530938448cdSRobert Watson KASSERT(netisr_proto[proto].np_handler != NULL, 531d4b5cae4SRobert Watson ("%s(%u): protocol not registered for %s", __func__, proto, 532d4b5cae4SRobert Watson name)); 533d4b5cae4SRobert Watson 5343aa6d94eSJohn Baldwin CPU_FOREACH(i) { 53553402767SRobert Watson npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto]; 536d4b5cae4SRobert Watson *qdropp += npwp->nw_qdrops; 537d4b5cae4SRobert Watson } 538d4b5cae4SRobert Watson NETISR_RUNLOCK(&tracker); 539d4b5cae4SRobert Watson } 540d4b5cae4SRobert Watson 541d4b5cae4SRobert Watson /* 5420a32e29fSRobert Watson * Query current per-workstream queue limit for a protocol. 543d4b5cae4SRobert Watson */ 544d4b5cae4SRobert Watson void 545d4b5cae4SRobert Watson netisr_getqlimit(const struct netisr_handler *nhp, u_int *qlimitp) 546d4b5cae4SRobert Watson { 547d4b5cae4SRobert Watson struct rm_priotracker tracker; 548d4b5cae4SRobert Watson #ifdef INVARIANTS 549d4b5cae4SRobert Watson const char *name; 550d4b5cae4SRobert Watson #endif 551d4b5cae4SRobert Watson u_int proto; 552d4b5cae4SRobert Watson 553d4b5cae4SRobert Watson proto = nhp->nh_proto; 554d4b5cae4SRobert Watson #ifdef INVARIANTS 555d4b5cae4SRobert Watson name = nhp->nh_name; 556d4b5cae4SRobert Watson #endif 557d4b5cae4SRobert Watson KASSERT(proto < NETISR_MAXPROT, 558d4b5cae4SRobert Watson ("%s(%u): protocol too big for %s", __func__, proto, name)); 559d4b5cae4SRobert Watson 560d4b5cae4SRobert Watson NETISR_RLOCK(&tracker); 561938448cdSRobert Watson KASSERT(netisr_proto[proto].np_handler != NULL, 562d4b5cae4SRobert Watson ("%s(%u): protocol not registered for %s", __func__, proto, 563d4b5cae4SRobert Watson name)); 564938448cdSRobert Watson *qlimitp = netisr_proto[proto].np_qlimit; 565d4b5cae4SRobert Watson NETISR_RUNLOCK(&tracker); 566d4b5cae4SRobert Watson } 567d4b5cae4SRobert Watson 568d4b5cae4SRobert Watson /* 569d4b5cae4SRobert Watson * Update the queue limit across per-workstream queues for a protocol. We 570d4b5cae4SRobert Watson * simply change the limits, and don't drain overflowed packets as they will 571d4b5cae4SRobert Watson * (hopefully) take care of themselves shortly. 5721cafed39SJonathan Lemon */ 5731cafed39SJonathan Lemon int 574d4b5cae4SRobert Watson netisr_setqlimit(const struct netisr_handler *nhp, u_int qlimit) 5751cafed39SJonathan Lemon { 576d4b5cae4SRobert Watson struct netisr_work *npwp; 577d4b5cae4SRobert Watson #ifdef INVARIANTS 578d4b5cae4SRobert Watson const char *name; 579d4b5cae4SRobert Watson #endif 580d4b5cae4SRobert Watson u_int i, proto; 5811cafed39SJonathan Lemon 582d4b5cae4SRobert Watson if (qlimit > netisr_maxqlimit) 583d4b5cae4SRobert Watson return (EINVAL); 584d4b5cae4SRobert Watson 585d4b5cae4SRobert Watson proto = nhp->nh_proto; 586d4b5cae4SRobert Watson #ifdef INVARIANTS 587d4b5cae4SRobert Watson name = nhp->nh_name; 588d4b5cae4SRobert Watson #endif 589d4b5cae4SRobert Watson KASSERT(proto < NETISR_MAXPROT, 590d4b5cae4SRobert Watson ("%s(%u): protocol too big for %s", __func__, proto, name)); 591d4b5cae4SRobert Watson 592d4b5cae4SRobert Watson NETISR_WLOCK(); 593938448cdSRobert Watson KASSERT(netisr_proto[proto].np_handler != NULL, 594d4b5cae4SRobert Watson ("%s(%u): protocol not registered for %s", __func__, proto, 595d4b5cae4SRobert Watson name)); 596d4b5cae4SRobert Watson 597938448cdSRobert Watson netisr_proto[proto].np_qlimit = qlimit; 5983aa6d94eSJohn Baldwin CPU_FOREACH(i) { 59953402767SRobert Watson npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto]; 600d4b5cae4SRobert Watson npwp->nw_qlimit = qlimit; 601fb68148fSJonathan Lemon } 602d4b5cae4SRobert Watson NETISR_WUNLOCK(); 6033161f583SAndre Oppermann return (0); 604e3b6e33cSJake Burkholder } 605e3b6e33cSJake Burkholder 606d4b5cae4SRobert Watson /* 607d4b5cae4SRobert Watson * Drain all packets currently held in a particular protocol work queue. 608d4b5cae4SRobert Watson */ 609e3b6e33cSJake Burkholder static void 610d4b5cae4SRobert Watson netisr_drain_proto(struct netisr_work *npwp) 611e3b6e33cSJake Burkholder { 612d4b5cae4SRobert Watson struct mbuf *m; 613d4b5cae4SRobert Watson 614d4b5cae4SRobert Watson /* 615d4b5cae4SRobert Watson * We would assert the lock on the workstream but it's not passed in. 616d4b5cae4SRobert Watson */ 617d4b5cae4SRobert Watson while ((m = npwp->nw_head) != NULL) { 618d4b5cae4SRobert Watson npwp->nw_head = m->m_nextpkt; 619d4b5cae4SRobert Watson m->m_nextpkt = NULL; 620d4b5cae4SRobert Watson if (npwp->nw_head == NULL) 621d4b5cae4SRobert Watson npwp->nw_tail = NULL; 622d4b5cae4SRobert Watson npwp->nw_len--; 623d4b5cae4SRobert Watson m_freem(m); 624d4b5cae4SRobert Watson } 625d4b5cae4SRobert Watson KASSERT(npwp->nw_tail == NULL, ("%s: tail", __func__)); 626d4b5cae4SRobert Watson KASSERT(npwp->nw_len == 0, ("%s: len", __func__)); 627d4b5cae4SRobert Watson } 628d4b5cae4SRobert Watson 629d4b5cae4SRobert Watson /* 630d4b5cae4SRobert Watson * Remove the registration of a network protocol, which requires clearing 631d4b5cae4SRobert Watson * per-protocol fields across all workstreams, including freeing all mbufs in 632d4b5cae4SRobert Watson * the queues at time of unregister. All work in netisr is briefly suspended 633d4b5cae4SRobert Watson * while this takes place. 634d4b5cae4SRobert Watson */ 635d4b5cae4SRobert Watson void 636d4b5cae4SRobert Watson netisr_unregister(const struct netisr_handler *nhp) 637d4b5cae4SRobert Watson { 638484149deSBjoern A. Zeeb VNET_ITERATOR_DECL(vnet_iter); 639d4b5cae4SRobert Watson struct netisr_work *npwp; 640d4b5cae4SRobert Watson #ifdef INVARIANTS 641d4b5cae4SRobert Watson const char *name; 642d4b5cae4SRobert Watson #endif 643d4b5cae4SRobert Watson u_int i, proto; 644d4b5cae4SRobert Watson 645d4b5cae4SRobert Watson proto = nhp->nh_proto; 646d4b5cae4SRobert Watson #ifdef INVARIANTS 647d4b5cae4SRobert Watson name = nhp->nh_name; 648d4b5cae4SRobert Watson #endif 649d4b5cae4SRobert Watson KASSERT(proto < NETISR_MAXPROT, 650d4b5cae4SRobert Watson ("%s(%u): protocol too big for %s", __func__, proto, name)); 651d4b5cae4SRobert Watson 652d4b5cae4SRobert Watson NETISR_WLOCK(); 653938448cdSRobert Watson KASSERT(netisr_proto[proto].np_handler != NULL, 654d4b5cae4SRobert Watson ("%s(%u): protocol not registered for %s", __func__, proto, 655d4b5cae4SRobert Watson name)); 656d4b5cae4SRobert Watson 657484149deSBjoern A. Zeeb #ifdef VIMAGE 658484149deSBjoern A. Zeeb VNET_LIST_RLOCK_NOSLEEP(); 659484149deSBjoern A. Zeeb VNET_FOREACH(vnet_iter) { 660484149deSBjoern A. Zeeb CURVNET_SET(vnet_iter); 661484149deSBjoern A. Zeeb V_netisr_enable[proto] = 0; 662484149deSBjoern A. Zeeb CURVNET_RESTORE(); 663484149deSBjoern A. Zeeb } 664484149deSBjoern A. Zeeb VNET_LIST_RUNLOCK_NOSLEEP(); 665484149deSBjoern A. Zeeb #endif 666484149deSBjoern A. Zeeb 667938448cdSRobert Watson netisr_proto[proto].np_name = NULL; 668938448cdSRobert Watson netisr_proto[proto].np_handler = NULL; 669938448cdSRobert Watson netisr_proto[proto].np_m2flow = NULL; 670938448cdSRobert Watson netisr_proto[proto].np_m2cpuid = NULL; 671938448cdSRobert Watson netisr_proto[proto].np_qlimit = 0; 672938448cdSRobert Watson netisr_proto[proto].np_policy = 0; 6733aa6d94eSJohn Baldwin CPU_FOREACH(i) { 67453402767SRobert Watson npwp = &(DPCPU_ID_PTR(i, nws))->nws_work[proto]; 675d4b5cae4SRobert Watson netisr_drain_proto(npwp); 676d4b5cae4SRobert Watson bzero(npwp, sizeof(*npwp)); 677d4b5cae4SRobert Watson } 678d4b5cae4SRobert Watson NETISR_WUNLOCK(); 679d4b5cae4SRobert Watson } 680d4b5cae4SRobert Watson 681484149deSBjoern A. Zeeb #ifdef VIMAGE 682484149deSBjoern A. Zeeb void 683484149deSBjoern A. Zeeb netisr_register_vnet(const struct netisr_handler *nhp) 684484149deSBjoern A. Zeeb { 685484149deSBjoern A. Zeeb u_int proto; 686484149deSBjoern A. Zeeb 687484149deSBjoern A. Zeeb proto = nhp->nh_proto; 688484149deSBjoern A. Zeeb 689484149deSBjoern A. Zeeb KASSERT(curvnet != NULL, ("%s: curvnet is NULL", __func__)); 690484149deSBjoern A. Zeeb KASSERT(proto < NETISR_MAXPROT, 691484149deSBjoern A. Zeeb ("%s(%u): protocol too big for %s", __func__, proto, nhp->nh_name)); 692484149deSBjoern A. Zeeb NETISR_WLOCK(); 693484149deSBjoern A. Zeeb KASSERT(netisr_proto[proto].np_handler != NULL, 694484149deSBjoern A. Zeeb ("%s(%u): protocol not registered for %s", __func__, proto, 695484149deSBjoern A. Zeeb nhp->nh_name)); 696484149deSBjoern A. Zeeb 697484149deSBjoern A. Zeeb V_netisr_enable[proto] = 1; 698484149deSBjoern A. Zeeb NETISR_WUNLOCK(); 699484149deSBjoern A. Zeeb } 700484149deSBjoern A. Zeeb 701484149deSBjoern A. Zeeb static void 702484149deSBjoern A. Zeeb netisr_drain_proto_vnet(struct vnet *vnet, u_int proto) 703484149deSBjoern A. Zeeb { 70451f798e7SGleb Smirnoff struct epoch_tracker et; 705484149deSBjoern A. Zeeb struct netisr_workstream *nwsp; 706484149deSBjoern A. Zeeb struct netisr_work *npwp; 707484149deSBjoern A. Zeeb struct mbuf *m, *mp, *n, *ne; 70851f798e7SGleb Smirnoff struct ifnet *ifp; 709484149deSBjoern A. Zeeb u_int i; 710484149deSBjoern A. Zeeb 711484149deSBjoern A. Zeeb KASSERT(vnet != NULL, ("%s: vnet is NULL", __func__)); 712484149deSBjoern A. Zeeb NETISR_LOCK_ASSERT(); 713484149deSBjoern A. Zeeb 714484149deSBjoern A. Zeeb CPU_FOREACH(i) { 715484149deSBjoern A. Zeeb nwsp = DPCPU_ID_PTR(i, nws); 716484149deSBjoern A. Zeeb if (nwsp->nws_intr_event == NULL) 717484149deSBjoern A. Zeeb continue; 718484149deSBjoern A. Zeeb npwp = &nwsp->nws_work[proto]; 719484149deSBjoern A. Zeeb NWS_LOCK(nwsp); 720484149deSBjoern A. Zeeb 721484149deSBjoern A. Zeeb /* 722484149deSBjoern A. Zeeb * Rather than dissecting and removing mbufs from the middle 723484149deSBjoern A. Zeeb * of the chain, we build a new chain if the packet stays and 724484149deSBjoern A. Zeeb * update the head and tail pointers at the end. All packets 725484149deSBjoern A. Zeeb * matching the given vnet are freed. 726484149deSBjoern A. Zeeb */ 727484149deSBjoern A. Zeeb m = npwp->nw_head; 728484149deSBjoern A. Zeeb n = ne = NULL; 72951f798e7SGleb Smirnoff NET_EPOCH_ENTER(et); 730484149deSBjoern A. Zeeb while (m != NULL) { 731484149deSBjoern A. Zeeb mp = m; 732484149deSBjoern A. Zeeb m = m->m_nextpkt; 733484149deSBjoern A. Zeeb mp->m_nextpkt = NULL; 73451f798e7SGleb Smirnoff if ((ifp = ifnet_byindexgen(mp->m_pkthdr.rcvidx, 73551f798e7SGleb Smirnoff mp->m_pkthdr.rcvgen)) != NULL && 73651f798e7SGleb Smirnoff ifp->if_vnet != vnet) { 737484149deSBjoern A. Zeeb if (n == NULL) { 738484149deSBjoern A. Zeeb n = ne = mp; 739484149deSBjoern A. Zeeb } else { 740484149deSBjoern A. Zeeb ne->m_nextpkt = mp; 741484149deSBjoern A. Zeeb ne = mp; 742484149deSBjoern A. Zeeb } 743484149deSBjoern A. Zeeb continue; 744484149deSBjoern A. Zeeb } 74551f798e7SGleb Smirnoff /* This is a packet in the selected vnet, or belongs 74651f798e7SGleb Smirnoff to destroyed interface. Free it. */ 747484149deSBjoern A. Zeeb npwp->nw_len--; 748484149deSBjoern A. Zeeb m_freem(mp); 749484149deSBjoern A. Zeeb } 75051f798e7SGleb Smirnoff NET_EPOCH_EXIT(et); 751484149deSBjoern A. Zeeb npwp->nw_head = n; 752484149deSBjoern A. Zeeb npwp->nw_tail = ne; 753484149deSBjoern A. Zeeb NWS_UNLOCK(nwsp); 754484149deSBjoern A. Zeeb } 755484149deSBjoern A. Zeeb } 756484149deSBjoern A. Zeeb 757484149deSBjoern A. Zeeb void 758484149deSBjoern A. Zeeb netisr_unregister_vnet(const struct netisr_handler *nhp) 759484149deSBjoern A. Zeeb { 760484149deSBjoern A. Zeeb u_int proto; 761484149deSBjoern A. Zeeb 762484149deSBjoern A. Zeeb proto = nhp->nh_proto; 763484149deSBjoern A. Zeeb 764484149deSBjoern A. Zeeb KASSERT(curvnet != NULL, ("%s: curvnet is NULL", __func__)); 765484149deSBjoern A. Zeeb KASSERT(proto < NETISR_MAXPROT, 766484149deSBjoern A. Zeeb ("%s(%u): protocol too big for %s", __func__, proto, nhp->nh_name)); 767484149deSBjoern A. Zeeb NETISR_WLOCK(); 768484149deSBjoern A. Zeeb KASSERT(netisr_proto[proto].np_handler != NULL, 769484149deSBjoern A. Zeeb ("%s(%u): protocol not registered for %s", __func__, proto, 770484149deSBjoern A. Zeeb nhp->nh_name)); 771484149deSBjoern A. Zeeb 772484149deSBjoern A. Zeeb V_netisr_enable[proto] = 0; 773484149deSBjoern A. Zeeb 774484149deSBjoern A. Zeeb netisr_drain_proto_vnet(curvnet, proto); 775484149deSBjoern A. Zeeb NETISR_WUNLOCK(); 776484149deSBjoern A. Zeeb } 777484149deSBjoern A. Zeeb #endif 778484149deSBjoern A. Zeeb 779d4b5cae4SRobert Watson /* 780f2d2d694SRobert Watson * Compose the global and per-protocol policies on dispatch, and return the 781f2d2d694SRobert Watson * dispatch policy to use. 782f2d2d694SRobert Watson */ 783f2d2d694SRobert Watson static u_int 784f2d2d694SRobert Watson netisr_get_dispatch(struct netisr_proto *npp) 785f2d2d694SRobert Watson { 786f2d2d694SRobert Watson 787f2d2d694SRobert Watson /* 788f2d2d694SRobert Watson * Protocol-specific configuration overrides the global default. 789f2d2d694SRobert Watson */ 790f2d2d694SRobert Watson if (npp->np_dispatch != NETISR_DISPATCH_DEFAULT) 791f2d2d694SRobert Watson return (npp->np_dispatch); 792f2d2d694SRobert Watson return (netisr_dispatch_policy); 793f2d2d694SRobert Watson } 794f2d2d694SRobert Watson 795f2d2d694SRobert Watson /* 796d4b5cae4SRobert Watson * Look up the workstream given a packet and source identifier. Do this by 797d4b5cae4SRobert Watson * checking the protocol's policy, and optionally call out to the protocol 798d4b5cae4SRobert Watson * for assistance if required. 799d4b5cae4SRobert Watson */ 800d4b5cae4SRobert Watson static struct mbuf * 801f2d2d694SRobert Watson netisr_select_cpuid(struct netisr_proto *npp, u_int dispatch_policy, 802f2d2d694SRobert Watson uintptr_t source, struct mbuf *m, u_int *cpuidp) 803d4b5cae4SRobert Watson { 804d4b5cae4SRobert Watson struct ifnet *ifp; 805f2d2d694SRobert Watson u_int policy; 806d4b5cae4SRobert Watson 807d4b5cae4SRobert Watson NETISR_LOCK_ASSERT(); 808d4b5cae4SRobert Watson 809d4b5cae4SRobert Watson /* 810d4b5cae4SRobert Watson * In the event we have only one worker, shortcut and deliver to it 811d4b5cae4SRobert Watson * without further ado. 812d4b5cae4SRobert Watson */ 813d4b5cae4SRobert Watson if (nws_count == 1) { 814d4b5cae4SRobert Watson *cpuidp = nws_array[0]; 815d4b5cae4SRobert Watson return (m); 816d4b5cae4SRobert Watson } 817d4b5cae4SRobert Watson 818d4b5cae4SRobert Watson /* 819d4b5cae4SRobert Watson * What happens next depends on the policy selected by the protocol. 820d4b5cae4SRobert Watson * If we want to support per-interface policies, we should do that 821d4b5cae4SRobert Watson * here first. 822d4b5cae4SRobert Watson */ 823f2d2d694SRobert Watson policy = npp->np_policy; 824f2d2d694SRobert Watson if (policy == NETISR_POLICY_CPU) { 825f2d2d694SRobert Watson m = npp->np_m2cpuid(m, source, cpuidp); 826f2d2d694SRobert Watson if (m == NULL) 827f2d2d694SRobert Watson return (NULL); 828d4b5cae4SRobert Watson 829f2d2d694SRobert Watson /* 830f2d2d694SRobert Watson * It's possible for a protocol not to have a good idea about 831f2d2d694SRobert Watson * where to process a packet, in which case we fall back on 832f2d2d694SRobert Watson * the netisr code to decide. In the hybrid case, return the 833f2d2d694SRobert Watson * current CPU ID, which will force an immediate direct 834f2d2d694SRobert Watson * dispatch. In the queued case, fall back on the SOURCE 835f2d2d694SRobert Watson * policy. 836f2d2d694SRobert Watson */ 837fdf95c0bSAndrey V. Elsukov if (*cpuidp != NETISR_CPUID_NONE) { 838fdf95c0bSAndrey V. Elsukov *cpuidp = netisr_get_cpuid(*cpuidp); 839f2d2d694SRobert Watson return (m); 840fdf95c0bSAndrey V. Elsukov } 841f2d2d694SRobert Watson if (dispatch_policy == NETISR_DISPATCH_HYBRID) { 842fdf95c0bSAndrey V. Elsukov *cpuidp = netisr_get_cpuid(curcpu); 843f2d2d694SRobert Watson return (m); 844f2d2d694SRobert Watson } 845f2d2d694SRobert Watson policy = NETISR_POLICY_SOURCE; 846f2d2d694SRobert Watson } 847f2d2d694SRobert Watson 848f2d2d694SRobert Watson if (policy == NETISR_POLICY_FLOW) { 849c2529042SHans Petter Selasky if (M_HASHTYPE_GET(m) == M_HASHTYPE_NONE && 850c2529042SHans Petter Selasky npp->np_m2flow != NULL) { 851d4b5cae4SRobert Watson m = npp->np_m2flow(m, source); 852d4b5cae4SRobert Watson if (m == NULL) 853d4b5cae4SRobert Watson return (NULL); 854d4b5cae4SRobert Watson } 855c2529042SHans Petter Selasky if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { 856d4b5cae4SRobert Watson *cpuidp = 857d4b5cae4SRobert Watson netisr_default_flow2cpu(m->m_pkthdr.flowid); 858d4b5cae4SRobert Watson return (m); 859d4b5cae4SRobert Watson } 860f2d2d694SRobert Watson policy = NETISR_POLICY_SOURCE; 861f2d2d694SRobert Watson } 862d4b5cae4SRobert Watson 863f2d2d694SRobert Watson KASSERT(policy == NETISR_POLICY_SOURCE, 864f2d2d694SRobert Watson ("%s: invalid policy %u for %s", __func__, npp->np_policy, 865f2d2d694SRobert Watson npp->np_name)); 866f2d2d694SRobert Watson 867fb3bc596SJohn Baldwin MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0); 868d4b5cae4SRobert Watson ifp = m->m_pkthdr.rcvif; 869d4b5cae4SRobert Watson if (ifp != NULL) 870f2d2d694SRobert Watson *cpuidp = nws_array[(ifp->if_index + source) % nws_count]; 871d4b5cae4SRobert Watson else 872d4b5cae4SRobert Watson *cpuidp = nws_array[source % nws_count]; 873d4b5cae4SRobert Watson return (m); 874d4b5cae4SRobert Watson } 875d4b5cae4SRobert Watson 876d4b5cae4SRobert Watson /* 877d4b5cae4SRobert Watson * Process packets associated with a workstream and protocol. For reasons of 878d4b5cae4SRobert Watson * fairness, we process up to one complete netisr queue at a time, moving the 879d4b5cae4SRobert Watson * queue to a stack-local queue for processing, but do not loop refreshing 880d4b5cae4SRobert Watson * from the global queue. The caller is responsible for deciding whether to 881d4b5cae4SRobert Watson * loop, and for setting the NWS_RUNNING flag. The passed workstream will be 882d4b5cae4SRobert Watson * locked on entry and relocked before return, but will be released while 883d4b5cae4SRobert Watson * processing. The number of packets processed is returned. 884d4b5cae4SRobert Watson */ 885d4b5cae4SRobert Watson static u_int 886d4b5cae4SRobert Watson netisr_process_workstream_proto(struct netisr_workstream *nwsp, u_int proto) 887d4b5cae4SRobert Watson { 888d4b5cae4SRobert Watson struct netisr_work local_npw, *npwp; 889d4b5cae4SRobert Watson u_int handled; 890d4b5cae4SRobert Watson struct mbuf *m; 891d4b5cae4SRobert Watson 892d4b5cae4SRobert Watson NETISR_LOCK_ASSERT(); 893d4b5cae4SRobert Watson NWS_LOCK_ASSERT(nwsp); 894d4b5cae4SRobert Watson 895d4b5cae4SRobert Watson KASSERT(nwsp->nws_flags & NWS_RUNNING, 896d4b5cae4SRobert Watson ("%s(%u): not running", __func__, proto)); 897d4b5cae4SRobert Watson KASSERT(proto >= 0 && proto < NETISR_MAXPROT, 898d4b5cae4SRobert Watson ("%s(%u): invalid proto\n", __func__, proto)); 899d4b5cae4SRobert Watson 900d4b5cae4SRobert Watson npwp = &nwsp->nws_work[proto]; 901d4b5cae4SRobert Watson if (npwp->nw_len == 0) 902d4b5cae4SRobert Watson return (0); 903d4b5cae4SRobert Watson 904d4b5cae4SRobert Watson /* 905d4b5cae4SRobert Watson * Move the global work queue to a thread-local work queue. 906d4b5cae4SRobert Watson * 907d4b5cae4SRobert Watson * Notice that this means the effective maximum length of the queue 908d4b5cae4SRobert Watson * is actually twice that of the maximum queue length specified in 909d4b5cae4SRobert Watson * the protocol registration call. 910d4b5cae4SRobert Watson */ 911d4b5cae4SRobert Watson handled = npwp->nw_len; 912d4b5cae4SRobert Watson local_npw = *npwp; 913d4b5cae4SRobert Watson npwp->nw_head = NULL; 914d4b5cae4SRobert Watson npwp->nw_tail = NULL; 915d4b5cae4SRobert Watson npwp->nw_len = 0; 916d4b5cae4SRobert Watson nwsp->nws_pendingbits &= ~(1 << proto); 917d4b5cae4SRobert Watson NWS_UNLOCK(nwsp); 918d4b5cae4SRobert Watson while ((m = local_npw.nw_head) != NULL) { 919d4b5cae4SRobert Watson local_npw.nw_head = m->m_nextpkt; 920d4b5cae4SRobert Watson m->m_nextpkt = NULL; 921d4b5cae4SRobert Watson if (local_npw.nw_head == NULL) 922d4b5cae4SRobert Watson local_npw.nw_tail = NULL; 923d4b5cae4SRobert Watson local_npw.nw_len--; 92451f798e7SGleb Smirnoff if (__predict_false(m_rcvif_restore(m) == NULL)) { 92551f798e7SGleb Smirnoff m_freem(m); 92651f798e7SGleb Smirnoff continue; 92751f798e7SGleb Smirnoff } 928d4b5cae4SRobert Watson CURVNET_SET(m->m_pkthdr.rcvif->if_vnet); 929938448cdSRobert Watson netisr_proto[proto].np_handler(m); 930d4b5cae4SRobert Watson CURVNET_RESTORE(); 931d4b5cae4SRobert Watson } 932d4b5cae4SRobert Watson KASSERT(local_npw.nw_len == 0, 933d4b5cae4SRobert Watson ("%s(%u): len %u", __func__, proto, local_npw.nw_len)); 934938448cdSRobert Watson if (netisr_proto[proto].np_drainedcpu) 935938448cdSRobert Watson netisr_proto[proto].np_drainedcpu(nwsp->nws_cpu); 936d4b5cae4SRobert Watson NWS_LOCK(nwsp); 937d4b5cae4SRobert Watson npwp->nw_handled += handled; 938d4b5cae4SRobert Watson return (handled); 939d4b5cae4SRobert Watson } 940d4b5cae4SRobert Watson 941d4b5cae4SRobert Watson /* 9420a32e29fSRobert Watson * SWI handler for netisr -- processes packets in a set of workstreams that 943d4b5cae4SRobert Watson * it owns, woken up by calls to NWS_SIGNAL(). If this workstream is already 944d4b5cae4SRobert Watson * being direct dispatched, go back to sleep and wait for the dispatching 945d4b5cae4SRobert Watson * thread to wake us up again. 946d4b5cae4SRobert Watson */ 947d4b5cae4SRobert Watson static void 948d4b5cae4SRobert Watson swi_net(void *arg) 949d4b5cae4SRobert Watson { 950d4b5cae4SRobert Watson #ifdef NETISR_LOCKING 951d4b5cae4SRobert Watson struct rm_priotracker tracker; 952d4b5cae4SRobert Watson #endif 953d4b5cae4SRobert Watson struct netisr_workstream *nwsp; 954d4b5cae4SRobert Watson u_int bits, prot; 955d4b5cae4SRobert Watson 956d4b5cae4SRobert Watson nwsp = arg; 957d4b5cae4SRobert Watson 9581cafed39SJonathan Lemon #ifdef DEVICE_POLLING 959d4b5cae4SRobert Watson KASSERT(nws_count == 1, 960d4b5cae4SRobert Watson ("%s: device_polling but nws_count != 1", __func__)); 961d4b5cae4SRobert Watson netisr_poll(); 962d4b5cae4SRobert Watson #endif 963d4b5cae4SRobert Watson #ifdef NETISR_LOCKING 964d4b5cae4SRobert Watson NETISR_RLOCK(&tracker); 965d4b5cae4SRobert Watson #endif 966d4b5cae4SRobert Watson NWS_LOCK(nwsp); 967d4b5cae4SRobert Watson KASSERT(!(nwsp->nws_flags & NWS_RUNNING), ("swi_net: running")); 968d4b5cae4SRobert Watson if (nwsp->nws_flags & NWS_DISPATCHING) 969d4b5cae4SRobert Watson goto out; 970d4b5cae4SRobert Watson nwsp->nws_flags |= NWS_RUNNING; 971d4b5cae4SRobert Watson nwsp->nws_flags &= ~NWS_SCHEDULED; 972d4b5cae4SRobert Watson while ((bits = nwsp->nws_pendingbits) != 0) { 973d4b5cae4SRobert Watson while ((prot = ffs(bits)) != 0) { 974d4b5cae4SRobert Watson prot--; 975d4b5cae4SRobert Watson bits &= ~(1 << prot); 976d4b5cae4SRobert Watson (void)netisr_process_workstream_proto(nwsp, prot); 977d4b5cae4SRobert Watson } 978d4b5cae4SRobert Watson } 979d4b5cae4SRobert Watson nwsp->nws_flags &= ~NWS_RUNNING; 980d4b5cae4SRobert Watson out: 981d4b5cae4SRobert Watson NWS_UNLOCK(nwsp); 982d4b5cae4SRobert Watson #ifdef NETISR_LOCKING 983d4b5cae4SRobert Watson NETISR_RUNLOCK(&tracker); 984d4b5cae4SRobert Watson #endif 985d4b5cae4SRobert Watson #ifdef DEVICE_POLLING 986d4b5cae4SRobert Watson netisr_pollmore(); 987d4b5cae4SRobert Watson #endif 988d4b5cae4SRobert Watson } 989d4b5cae4SRobert Watson 990d4b5cae4SRobert Watson static int 991d4b5cae4SRobert Watson netisr_queue_workstream(struct netisr_workstream *nwsp, u_int proto, 992d4b5cae4SRobert Watson struct netisr_work *npwp, struct mbuf *m, int *dosignalp) 993d4b5cae4SRobert Watson { 994d4b5cae4SRobert Watson 995d4b5cae4SRobert Watson NWS_LOCK_ASSERT(nwsp); 996d4b5cae4SRobert Watson 997d4b5cae4SRobert Watson *dosignalp = 0; 998d4b5cae4SRobert Watson if (npwp->nw_len < npwp->nw_qlimit) { 99951f798e7SGleb Smirnoff m_rcvif_serialize(m); 1000d4b5cae4SRobert Watson m->m_nextpkt = NULL; 1001d4b5cae4SRobert Watson if (npwp->nw_head == NULL) { 1002d4b5cae4SRobert Watson npwp->nw_head = m; 1003d4b5cae4SRobert Watson npwp->nw_tail = m; 1004d4b5cae4SRobert Watson } else { 1005d4b5cae4SRobert Watson npwp->nw_tail->m_nextpkt = m; 1006d4b5cae4SRobert Watson npwp->nw_tail = m; 1007d4b5cae4SRobert Watson } 1008d4b5cae4SRobert Watson npwp->nw_len++; 1009d4b5cae4SRobert Watson if (npwp->nw_len > npwp->nw_watermark) 1010d4b5cae4SRobert Watson npwp->nw_watermark = npwp->nw_len; 10110a32e29fSRobert Watson 10120a32e29fSRobert Watson /* 10130a32e29fSRobert Watson * We must set the bit regardless of NWS_RUNNING, so that 10140a32e29fSRobert Watson * swi_net() keeps calling netisr_process_workstream_proto(). 10150a32e29fSRobert Watson */ 1016d4b5cae4SRobert Watson nwsp->nws_pendingbits |= (1 << proto); 1017d4b5cae4SRobert Watson if (!(nwsp->nws_flags & 1018d4b5cae4SRobert Watson (NWS_RUNNING | NWS_DISPATCHING | NWS_SCHEDULED))) { 1019d4b5cae4SRobert Watson nwsp->nws_flags |= NWS_SCHEDULED; 1020d4b5cae4SRobert Watson *dosignalp = 1; /* Defer until unlocked. */ 1021d4b5cae4SRobert Watson } 1022d4b5cae4SRobert Watson npwp->nw_queued++; 1023d4b5cae4SRobert Watson return (0); 1024d4b5cae4SRobert Watson } else { 1025ba3b25b3SBjoern A. Zeeb m_freem(m); 1026d4b5cae4SRobert Watson npwp->nw_qdrops++; 1027d4b5cae4SRobert Watson return (ENOBUFS); 1028d4b5cae4SRobert Watson } 1029d4b5cae4SRobert Watson } 1030d4b5cae4SRobert Watson 1031d4b5cae4SRobert Watson static int 1032d4b5cae4SRobert Watson netisr_queue_internal(u_int proto, struct mbuf *m, u_int cpuid) 1033d4b5cae4SRobert Watson { 1034d4b5cae4SRobert Watson struct netisr_workstream *nwsp; 1035d4b5cae4SRobert Watson struct netisr_work *npwp; 1036d4b5cae4SRobert Watson int dosignal, error; 1037d4b5cae4SRobert Watson 1038d4b5cae4SRobert Watson #ifdef NETISR_LOCKING 1039d4b5cae4SRobert Watson NETISR_LOCK_ASSERT(); 1040d4b5cae4SRobert Watson #endif 10419e6e01ebSRobert Watson KASSERT(cpuid <= mp_maxid, ("%s: cpuid too big (%u, %u)", __func__, 10429e6e01ebSRobert Watson cpuid, mp_maxid)); 104353402767SRobert Watson KASSERT(!CPU_ABSENT(cpuid), ("%s: CPU %u absent", __func__, cpuid)); 1044d4b5cae4SRobert Watson 1045d4b5cae4SRobert Watson dosignal = 0; 1046d4b5cae4SRobert Watson error = 0; 104753402767SRobert Watson nwsp = DPCPU_ID_PTR(cpuid, nws); 1048d4b5cae4SRobert Watson npwp = &nwsp->nws_work[proto]; 1049d4b5cae4SRobert Watson NWS_LOCK(nwsp); 1050d4b5cae4SRobert Watson error = netisr_queue_workstream(nwsp, proto, npwp, m, &dosignal); 1051d4b5cae4SRobert Watson NWS_UNLOCK(nwsp); 1052d4b5cae4SRobert Watson if (dosignal) 1053d4b5cae4SRobert Watson NWS_SIGNAL(nwsp); 1054d4b5cae4SRobert Watson return (error); 1055d4b5cae4SRobert Watson } 1056d4b5cae4SRobert Watson 1057d4b5cae4SRobert Watson int 1058d4b5cae4SRobert Watson netisr_queue_src(u_int proto, uintptr_t source, struct mbuf *m) 1059d4b5cae4SRobert Watson { 1060d4b5cae4SRobert Watson #ifdef NETISR_LOCKING 1061d4b5cae4SRobert Watson struct rm_priotracker tracker; 1062d4b5cae4SRobert Watson #endif 1063d4b5cae4SRobert Watson u_int cpuid; 1064d4b5cae4SRobert Watson int error; 1065d4b5cae4SRobert Watson 1066d4b5cae4SRobert Watson KASSERT(proto < NETISR_MAXPROT, 1067d4b5cae4SRobert Watson ("%s: invalid proto %u", __func__, proto)); 1068d4b5cae4SRobert Watson 1069d4b5cae4SRobert Watson #ifdef NETISR_LOCKING 1070d4b5cae4SRobert Watson NETISR_RLOCK(&tracker); 1071d4b5cae4SRobert Watson #endif 1072938448cdSRobert Watson KASSERT(netisr_proto[proto].np_handler != NULL, 1073d4b5cae4SRobert Watson ("%s: invalid proto %u", __func__, proto)); 1074d4b5cae4SRobert Watson 1075484149deSBjoern A. Zeeb #ifdef VIMAGE 1076484149deSBjoern A. Zeeb if (V_netisr_enable[proto] == 0) { 1077484149deSBjoern A. Zeeb m_freem(m); 1078484149deSBjoern A. Zeeb return (ENOPROTOOPT); 1079484149deSBjoern A. Zeeb } 1080484149deSBjoern A. Zeeb #endif 1081484149deSBjoern A. Zeeb 1082f2d2d694SRobert Watson m = netisr_select_cpuid(&netisr_proto[proto], NETISR_DISPATCH_DEFERRED, 1083f2d2d694SRobert Watson source, m, &cpuid); 108453402767SRobert Watson if (m != NULL) { 108553402767SRobert Watson KASSERT(!CPU_ABSENT(cpuid), ("%s: CPU %u absent", __func__, 108653402767SRobert Watson cpuid)); 1087bacb11c9SHans Petter Selasky VNET_ASSERT(m->m_pkthdr.rcvif != NULL, 1088bacb11c9SHans Petter Selasky ("%s:%d rcvif == NULL: m=%p", __func__, __LINE__, m)); 1089d4b5cae4SRobert Watson error = netisr_queue_internal(proto, m, cpuid); 109053402767SRobert Watson } else 1091d4b5cae4SRobert Watson error = ENOBUFS; 1092d4b5cae4SRobert Watson #ifdef NETISR_LOCKING 1093d4b5cae4SRobert Watson NETISR_RUNLOCK(&tracker); 1094d4b5cae4SRobert Watson #endif 1095d4b5cae4SRobert Watson return (error); 1096d4b5cae4SRobert Watson } 1097d4b5cae4SRobert Watson 1098d4b5cae4SRobert Watson int 1099d4b5cae4SRobert Watson netisr_queue(u_int proto, struct mbuf *m) 1100d4b5cae4SRobert Watson { 1101d4b5cae4SRobert Watson 1102d4b5cae4SRobert Watson return (netisr_queue_src(proto, 0, m)); 1103d4b5cae4SRobert Watson } 1104d4b5cae4SRobert Watson 1105d4b5cae4SRobert Watson /* 11060a32e29fSRobert Watson * Dispatch a packet for netisr processing; direct dispatch is permitted by 1107d4b5cae4SRobert Watson * calling context. 1108d4b5cae4SRobert Watson */ 1109d4b5cae4SRobert Watson int 1110d4b5cae4SRobert Watson netisr_dispatch_src(u_int proto, uintptr_t source, struct mbuf *m) 1111d4b5cae4SRobert Watson { 1112d4b5cae4SRobert Watson #ifdef NETISR_LOCKING 1113d4b5cae4SRobert Watson struct rm_priotracker tracker; 1114d4b5cae4SRobert Watson #endif 1115d4b5cae4SRobert Watson struct netisr_workstream *nwsp; 1116f2d2d694SRobert Watson struct netisr_proto *npp; 1117d4b5cae4SRobert Watson struct netisr_work *npwp; 1118d4b5cae4SRobert Watson int dosignal, error; 1119f2d2d694SRobert Watson u_int cpuid, dispatch_policy; 1120d4b5cae4SRobert Watson 1121b8a6e03fSGleb Smirnoff NET_EPOCH_ASSERT(); 1122d4b5cae4SRobert Watson KASSERT(proto < NETISR_MAXPROT, 1123d4b5cae4SRobert Watson ("%s: invalid proto %u", __func__, proto)); 1124d4b5cae4SRobert Watson #ifdef NETISR_LOCKING 1125d4b5cae4SRobert Watson NETISR_RLOCK(&tracker); 1126d4b5cae4SRobert Watson #endif 1127f2d2d694SRobert Watson npp = &netisr_proto[proto]; 1128f2d2d694SRobert Watson KASSERT(npp->np_handler != NULL, ("%s: invalid proto %u", __func__, 1129f2d2d694SRobert Watson proto)); 1130f2d2d694SRobert Watson 1131484149deSBjoern A. Zeeb #ifdef VIMAGE 1132484149deSBjoern A. Zeeb if (V_netisr_enable[proto] == 0) { 1133484149deSBjoern A. Zeeb m_freem(m); 1134484149deSBjoern A. Zeeb return (ENOPROTOOPT); 1135484149deSBjoern A. Zeeb } 1136484149deSBjoern A. Zeeb #endif 1137484149deSBjoern A. Zeeb 1138f2d2d694SRobert Watson dispatch_policy = netisr_get_dispatch(npp); 1139f2d2d694SRobert Watson if (dispatch_policy == NETISR_DISPATCH_DEFERRED) 1140f2d2d694SRobert Watson return (netisr_queue_src(proto, source, m)); 1141d4b5cae4SRobert Watson 1142d4b5cae4SRobert Watson /* 1143d4b5cae4SRobert Watson * If direct dispatch is forced, then unconditionally dispatch 1144d4b5cae4SRobert Watson * without a formal CPU selection. Borrow the current CPU's stats, 1145d4b5cae4SRobert Watson * even if there's no worker on it. In this case we don't update 1146d4b5cae4SRobert Watson * nws_flags because all netisr processing will be source ordered due 1147d4b5cae4SRobert Watson * to always being forced to directly dispatch. 1148d4b5cae4SRobert Watson */ 1149f2d2d694SRobert Watson if (dispatch_policy == NETISR_DISPATCH_DIRECT) { 115053402767SRobert Watson nwsp = DPCPU_PTR(nws); 1151d4b5cae4SRobert Watson npwp = &nwsp->nws_work[proto]; 1152d4b5cae4SRobert Watson npwp->nw_dispatched++; 1153d4b5cae4SRobert Watson npwp->nw_handled++; 1154938448cdSRobert Watson netisr_proto[proto].np_handler(m); 1155d4b5cae4SRobert Watson error = 0; 1156d4b5cae4SRobert Watson goto out_unlock; 1157d4b5cae4SRobert Watson } 1158d4b5cae4SRobert Watson 1159f2d2d694SRobert Watson KASSERT(dispatch_policy == NETISR_DISPATCH_HYBRID, 1160f2d2d694SRobert Watson ("%s: unknown dispatch policy (%u)", __func__, dispatch_policy)); 1161f2d2d694SRobert Watson 1162d4b5cae4SRobert Watson /* 1163d4b5cae4SRobert Watson * Otherwise, we execute in a hybrid mode where we will try to direct 1164d4b5cae4SRobert Watson * dispatch if we're on the right CPU and the netisr worker isn't 1165d4b5cae4SRobert Watson * already running. 1166d4b5cae4SRobert Watson */ 1167f2d2d694SRobert Watson sched_pin(); 1168f2d2d694SRobert Watson m = netisr_select_cpuid(&netisr_proto[proto], NETISR_DISPATCH_HYBRID, 1169f2d2d694SRobert Watson source, m, &cpuid); 1170d4b5cae4SRobert Watson if (m == NULL) { 1171d4b5cae4SRobert Watson error = ENOBUFS; 1172f2d2d694SRobert Watson goto out_unpin; 1173d4b5cae4SRobert Watson } 117453402767SRobert Watson KASSERT(!CPU_ABSENT(cpuid), ("%s: CPU %u absent", __func__, cpuid)); 1175d4b5cae4SRobert Watson if (cpuid != curcpu) 1176d4b5cae4SRobert Watson goto queue_fallback; 117753402767SRobert Watson nwsp = DPCPU_PTR(nws); 1178d4b5cae4SRobert Watson npwp = &nwsp->nws_work[proto]; 1179d4b5cae4SRobert Watson 1180d4b5cae4SRobert Watson /*- 1181d4b5cae4SRobert Watson * We are willing to direct dispatch only if three conditions hold: 1182d4b5cae4SRobert Watson * 1183d4b5cae4SRobert Watson * (1) The netisr worker isn't already running, 1184d4b5cae4SRobert Watson * (2) Another thread isn't already directly dispatching, and 1185d4b5cae4SRobert Watson * (3) The netisr hasn't already been woken up. 1186d4b5cae4SRobert Watson */ 1187d4b5cae4SRobert Watson NWS_LOCK(nwsp); 1188d4b5cae4SRobert Watson if (nwsp->nws_flags & (NWS_RUNNING | NWS_DISPATCHING | NWS_SCHEDULED)) { 1189d4b5cae4SRobert Watson error = netisr_queue_workstream(nwsp, proto, npwp, m, 1190d4b5cae4SRobert Watson &dosignal); 119153402767SRobert Watson NWS_UNLOCK(nwsp); 1192d4b5cae4SRobert Watson if (dosignal) 1193d4b5cae4SRobert Watson NWS_SIGNAL(nwsp); 1194d4b5cae4SRobert Watson goto out_unpin; 1195d4b5cae4SRobert Watson } 1196d4b5cae4SRobert Watson 1197d4b5cae4SRobert Watson /* 1198d4b5cae4SRobert Watson * The current thread is now effectively the netisr worker, so set 1199d4b5cae4SRobert Watson * the dispatching flag to prevent concurrent processing of the 1200d4b5cae4SRobert Watson * stream from another thread (even the netisr worker), which could 1201d4b5cae4SRobert Watson * otherwise lead to effective misordering of the stream. 1202d4b5cae4SRobert Watson */ 1203d4b5cae4SRobert Watson nwsp->nws_flags |= NWS_DISPATCHING; 1204d4b5cae4SRobert Watson NWS_UNLOCK(nwsp); 1205938448cdSRobert Watson netisr_proto[proto].np_handler(m); 1206d4b5cae4SRobert Watson NWS_LOCK(nwsp); 1207d4b5cae4SRobert Watson nwsp->nws_flags &= ~NWS_DISPATCHING; 1208d4b5cae4SRobert Watson npwp->nw_handled++; 1209d4b5cae4SRobert Watson npwp->nw_hybrid_dispatched++; 1210d4b5cae4SRobert Watson 1211d4b5cae4SRobert Watson /* 1212d4b5cae4SRobert Watson * If other work was enqueued by another thread while we were direct 1213d4b5cae4SRobert Watson * dispatching, we need to signal the netisr worker to do that work. 1214d4b5cae4SRobert Watson * In the future, we might want to do some of that work in the 1215d4b5cae4SRobert Watson * current thread, rather than trigger further context switches. If 1216d4b5cae4SRobert Watson * so, we'll want to establish a reasonable bound on the work done in 1217d4b5cae4SRobert Watson * the "borrowed" context. 1218d4b5cae4SRobert Watson */ 1219d4b5cae4SRobert Watson if (nwsp->nws_pendingbits != 0) { 1220d4b5cae4SRobert Watson nwsp->nws_flags |= NWS_SCHEDULED; 1221d4b5cae4SRobert Watson dosignal = 1; 1222d4b5cae4SRobert Watson } else 1223d4b5cae4SRobert Watson dosignal = 0; 1224d4b5cae4SRobert Watson NWS_UNLOCK(nwsp); 1225d4b5cae4SRobert Watson if (dosignal) 1226d4b5cae4SRobert Watson NWS_SIGNAL(nwsp); 1227d4b5cae4SRobert Watson error = 0; 1228d4b5cae4SRobert Watson goto out_unpin; 1229d4b5cae4SRobert Watson 1230d4b5cae4SRobert Watson queue_fallback: 1231d4b5cae4SRobert Watson error = netisr_queue_internal(proto, m, cpuid); 1232d4b5cae4SRobert Watson out_unpin: 1233d4b5cae4SRobert Watson sched_unpin(); 1234d4b5cae4SRobert Watson out_unlock: 1235d4b5cae4SRobert Watson #ifdef NETISR_LOCKING 1236d4b5cae4SRobert Watson NETISR_RUNLOCK(&tracker); 1237d4b5cae4SRobert Watson #endif 1238d4b5cae4SRobert Watson return (error); 1239d4b5cae4SRobert Watson } 1240d4b5cae4SRobert Watson 1241d4b5cae4SRobert Watson int 1242d4b5cae4SRobert Watson netisr_dispatch(u_int proto, struct mbuf *m) 1243d4b5cae4SRobert Watson { 1244d4b5cae4SRobert Watson 1245d4b5cae4SRobert Watson return (netisr_dispatch_src(proto, 0, m)); 1246d4b5cae4SRobert Watson } 1247d4b5cae4SRobert Watson 1248d4b5cae4SRobert Watson #ifdef DEVICE_POLLING 1249d4b5cae4SRobert Watson /* 1250d4b5cae4SRobert Watson * Kernel polling borrows a netisr thread to run interface polling in; this 1251d4b5cae4SRobert Watson * function allows kernel polling to request that the netisr thread be 1252d4b5cae4SRobert Watson * scheduled even if no packets are pending for protocols. 1253d4b5cae4SRobert Watson */ 1254d4b5cae4SRobert Watson void 1255d4b5cae4SRobert Watson netisr_sched_poll(void) 1256d4b5cae4SRobert Watson { 1257d4b5cae4SRobert Watson struct netisr_workstream *nwsp; 1258d4b5cae4SRobert Watson 125953402767SRobert Watson nwsp = DPCPU_ID_PTR(nws_array[0], nws); 1260d4b5cae4SRobert Watson NWS_SIGNAL(nwsp); 1261d4b5cae4SRobert Watson } 12621cafed39SJonathan Lemon #endif 1263e3b6e33cSJake Burkholder 1264d4b5cae4SRobert Watson static void 1265d4b5cae4SRobert Watson netisr_start_swi(u_int cpuid, struct pcpu *pc) 1266d4b5cae4SRobert Watson { 1267d4b5cae4SRobert Watson char swiname[12]; 1268d4b5cae4SRobert Watson struct netisr_workstream *nwsp; 1269d4b5cae4SRobert Watson int error; 1270d4b5cae4SRobert Watson 127153402767SRobert Watson KASSERT(!CPU_ABSENT(cpuid), ("%s: CPU %u absent", __func__, cpuid)); 127253402767SRobert Watson 127353402767SRobert Watson nwsp = DPCPU_ID_PTR(cpuid, nws); 1274d4b5cae4SRobert Watson mtx_init(&nwsp->nws_mtx, "netisr_mtx", NULL, MTX_DEF); 1275d4b5cae4SRobert Watson nwsp->nws_cpu = cpuid; 1276d4b5cae4SRobert Watson snprintf(swiname, sizeof(swiname), "netisr %u", cpuid); 1277d4b5cae4SRobert Watson error = swi_add(&nwsp->nws_intr_event, swiname, swi_net, nwsp, 12786ed3e187SGleb Smirnoff SWI_NET, INTR_TYPE_NET | INTR_MPSAFE, &nwsp->nws_swi_cookie); 1279d4b5cae4SRobert Watson if (error) 1280d4b5cae4SRobert Watson panic("%s: swi_add %d", __func__, error); 1281d4b5cae4SRobert Watson pc->pc_netisr = nwsp->nws_intr_event; 1282d4b5cae4SRobert Watson if (netisr_bindthreads) { 1283d4b5cae4SRobert Watson error = intr_event_bind(nwsp->nws_intr_event, cpuid); 1284d4b5cae4SRobert Watson if (error != 0) 1285d4b5cae4SRobert Watson printf("%s: cpu %u: intr_event_bind: %d", __func__, 1286d4b5cae4SRobert Watson cpuid, error); 1287e3b6e33cSJake Burkholder } 1288d4b5cae4SRobert Watson NETISR_WLOCK(); 1289d4b5cae4SRobert Watson nws_array[nws_count] = nwsp->nws_cpu; 1290d4b5cae4SRobert Watson nws_count++; 1291d4b5cae4SRobert Watson NETISR_WUNLOCK(); 1292e3b6e33cSJake Burkholder } 1293e3b6e33cSJake Burkholder 1294d4b5cae4SRobert Watson /* 1295d4b5cae4SRobert Watson * Initialize the netisr subsystem. We rely on BSS and static initialization 1296d4b5cae4SRobert Watson * of most fields in global data structures. 1297d4b5cae4SRobert Watson * 1298d4b5cae4SRobert Watson * Start a worker thread for the boot CPU so that we can support network 1299d4b5cae4SRobert Watson * traffic immediately in case the network stack is used before additional 1300d4b5cae4SRobert Watson * CPUs are started (for example, diskless boot). 1301d4b5cae4SRobert Watson */ 1302e3b6e33cSJake Burkholder static void 1303d4b5cae4SRobert Watson netisr_init(void *arg) 1304e3b6e33cSJake Burkholder { 1305fdce57a0SJohn Baldwin struct pcpu *pc; 1306fdce57a0SJohn Baldwin 1307d4b5cae4SRobert Watson NETISR_LOCK_INIT(); 1308a9467c3cSHiren Panchasara if (netisr_maxthreads == 0 || netisr_maxthreads < -1 ) 1309a9467c3cSHiren Panchasara netisr_maxthreads = 1; /* default behavior */ 1310a9467c3cSHiren Panchasara else if (netisr_maxthreads == -1) 1311a9467c3cSHiren Panchasara netisr_maxthreads = mp_ncpus; /* use max cpus */ 13129e6e01ebSRobert Watson if (netisr_maxthreads > mp_ncpus) { 1313912f6323SRobert Watson printf("netisr_init: forcing maxthreads from %d to %d\n", 13149e6e01ebSRobert Watson netisr_maxthreads, mp_ncpus); 13159e6e01ebSRobert Watson netisr_maxthreads = mp_ncpus; 1316ed54411cSRobert Watson } 1317ed54411cSRobert Watson if (netisr_defaultqlimit > netisr_maxqlimit) { 1318912f6323SRobert Watson printf("netisr_init: forcing defaultqlimit from %d to %d\n", 13199e6e01ebSRobert Watson netisr_defaultqlimit, netisr_maxqlimit); 1320d4b5cae4SRobert Watson netisr_defaultqlimit = netisr_maxqlimit; 1321ed54411cSRobert Watson } 1322d4b5cae4SRobert Watson #ifdef DEVICE_POLLING 1323d4b5cae4SRobert Watson /* 1324d4b5cae4SRobert Watson * The device polling code is not yet aware of how to deal with 1325d4b5cae4SRobert Watson * multiple netisr threads, so for the time being compiling in device 1326d4b5cae4SRobert Watson * polling disables parallel netisr workers. 1327d4b5cae4SRobert Watson */ 132851d4054eSGeorge V. Neville-Neil if (netisr_maxthreads != 1 || netisr_bindthreads != 0) { 1329912f6323SRobert Watson printf("netisr_init: forcing maxthreads to 1 and " 1330912f6323SRobert Watson "bindthreads to 0 for device polling\n"); 1331d4b5cae4SRobert Watson netisr_maxthreads = 1; 1332d4b5cae4SRobert Watson netisr_bindthreads = 0; 1333ed54411cSRobert Watson } 1334d4b5cae4SRobert Watson #endif 1335fdce57a0SJohn Baldwin 1336fdce57a0SJohn Baldwin #ifdef EARLY_AP_STARTUP 1337fdce57a0SJohn Baldwin STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) { 1338fdce57a0SJohn Baldwin if (nws_count >= netisr_maxthreads) 1339fdce57a0SJohn Baldwin break; 1340fdce57a0SJohn Baldwin netisr_start_swi(pc->pc_cpuid, pc); 1341fdce57a0SJohn Baldwin } 1342fdce57a0SJohn Baldwin #else 1343e2a8d178SJason A. Harmening pc = get_pcpu(); 1344e2a8d178SJason A. Harmening netisr_start_swi(pc->pc_cpuid, pc); 1345fdce57a0SJohn Baldwin #endif 1346e3b6e33cSJake Burkholder } 1347d4b5cae4SRobert Watson SYSINIT(netisr_init, SI_SUB_SOFTINTR, SI_ORDER_FIRST, netisr_init, NULL); 1348d4b5cae4SRobert Watson 1349fdce57a0SJohn Baldwin #ifndef EARLY_AP_STARTUP 1350d4b5cae4SRobert Watson /* 1351d4b5cae4SRobert Watson * Start worker threads for additional CPUs. No attempt to gracefully handle 1352d4b5cae4SRobert Watson * work reassignment, we don't yet support dynamic reconfiguration. 1353d4b5cae4SRobert Watson */ 1354d4b5cae4SRobert Watson static void 1355d4b5cae4SRobert Watson netisr_start(void *arg) 1356d4b5cae4SRobert Watson { 1357d4b5cae4SRobert Watson struct pcpu *pc; 1358d4b5cae4SRobert Watson 1359d098f930SNathan Whitehorn STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) { 1360d4b5cae4SRobert Watson if (nws_count >= netisr_maxthreads) 1361d4b5cae4SRobert Watson break; 1362d4b5cae4SRobert Watson /* Worker will already be present for boot CPU. */ 1363d4b5cae4SRobert Watson if (pc->pc_netisr != NULL) 1364d4b5cae4SRobert Watson continue; 1365d4b5cae4SRobert Watson netisr_start_swi(pc->pc_cpuid, pc); 1366d4b5cae4SRobert Watson } 1367d4b5cae4SRobert Watson } 1368d4b5cae4SRobert Watson SYSINIT(netisr_start, SI_SUB_SMP, SI_ORDER_MIDDLE, netisr_start, NULL); 1369fdce57a0SJohn Baldwin #endif 1370d4b5cae4SRobert Watson 13712d22f334SRobert Watson /* 13722d22f334SRobert Watson * Sysctl monitoring for netisr: query a list of registered protocols. 13732d22f334SRobert Watson */ 13742d22f334SRobert Watson static int 13752d22f334SRobert Watson sysctl_netisr_proto(SYSCTL_HANDLER_ARGS) 13762d22f334SRobert Watson { 13772d22f334SRobert Watson struct rm_priotracker tracker; 13782d22f334SRobert Watson struct sysctl_netisr_proto *snpp, *snp_array; 13792d22f334SRobert Watson struct netisr_proto *npp; 13802d22f334SRobert Watson u_int counter, proto; 13812d22f334SRobert Watson int error; 13822d22f334SRobert Watson 13832d22f334SRobert Watson if (req->newptr != NULL) 13842d22f334SRobert Watson return (EINVAL); 13852d22f334SRobert Watson snp_array = malloc(sizeof(*snp_array) * NETISR_MAXPROT, M_TEMP, 13862d22f334SRobert Watson M_ZERO | M_WAITOK); 13872d22f334SRobert Watson counter = 0; 13882d22f334SRobert Watson NETISR_RLOCK(&tracker); 13892d22f334SRobert Watson for (proto = 0; proto < NETISR_MAXPROT; proto++) { 1390938448cdSRobert Watson npp = &netisr_proto[proto]; 13912d22f334SRobert Watson if (npp->np_name == NULL) 13922d22f334SRobert Watson continue; 13932d22f334SRobert Watson snpp = &snp_array[counter]; 13942d22f334SRobert Watson snpp->snp_version = sizeof(*snpp); 13952d22f334SRobert Watson strlcpy(snpp->snp_name, npp->np_name, NETISR_NAMEMAXLEN); 13962d22f334SRobert Watson snpp->snp_proto = proto; 13972d22f334SRobert Watson snpp->snp_qlimit = npp->np_qlimit; 13982d22f334SRobert Watson snpp->snp_policy = npp->np_policy; 1399f2d2d694SRobert Watson snpp->snp_dispatch = npp->np_dispatch; 14002d22f334SRobert Watson if (npp->np_m2flow != NULL) 14012d22f334SRobert Watson snpp->snp_flags |= NETISR_SNP_FLAGS_M2FLOW; 14022d22f334SRobert Watson if (npp->np_m2cpuid != NULL) 14032d22f334SRobert Watson snpp->snp_flags |= NETISR_SNP_FLAGS_M2CPUID; 14042d22f334SRobert Watson if (npp->np_drainedcpu != NULL) 14052d22f334SRobert Watson snpp->snp_flags |= NETISR_SNP_FLAGS_DRAINEDCPU; 14062d22f334SRobert Watson counter++; 14072d22f334SRobert Watson } 14082d22f334SRobert Watson NETISR_RUNLOCK(&tracker); 14097f450febSRobert Watson KASSERT(counter <= NETISR_MAXPROT, 14102d22f334SRobert Watson ("sysctl_netisr_proto: counter too big (%d)", counter)); 14112d22f334SRobert Watson error = SYSCTL_OUT(req, snp_array, sizeof(*snp_array) * counter); 14122d22f334SRobert Watson free(snp_array, M_TEMP); 14132d22f334SRobert Watson return (error); 14142d22f334SRobert Watson } 14152d22f334SRobert Watson 14162d22f334SRobert Watson SYSCTL_PROC(_net_isr, OID_AUTO, proto, 14172d22f334SRobert Watson CTLFLAG_RD|CTLTYPE_STRUCT|CTLFLAG_MPSAFE, 0, 0, sysctl_netisr_proto, 14182d22f334SRobert Watson "S,sysctl_netisr_proto", 14192d22f334SRobert Watson "Return list of protocols registered with netisr"); 14202d22f334SRobert Watson 14212d22f334SRobert Watson /* 14222d22f334SRobert Watson * Sysctl monitoring for netisr: query a list of workstreams. 14232d22f334SRobert Watson */ 14242d22f334SRobert Watson static int 14252d22f334SRobert Watson sysctl_netisr_workstream(SYSCTL_HANDLER_ARGS) 14262d22f334SRobert Watson { 14272d22f334SRobert Watson struct rm_priotracker tracker; 14282d22f334SRobert Watson struct sysctl_netisr_workstream *snwsp, *snws_array; 14292d22f334SRobert Watson struct netisr_workstream *nwsp; 14302d22f334SRobert Watson u_int counter, cpuid; 14312d22f334SRobert Watson int error; 14322d22f334SRobert Watson 14332d22f334SRobert Watson if (req->newptr != NULL) 14342d22f334SRobert Watson return (EINVAL); 14352d22f334SRobert Watson snws_array = malloc(sizeof(*snws_array) * MAXCPU, M_TEMP, 14362d22f334SRobert Watson M_ZERO | M_WAITOK); 14372d22f334SRobert Watson counter = 0; 14382d22f334SRobert Watson NETISR_RLOCK(&tracker); 14393aa6d94eSJohn Baldwin CPU_FOREACH(cpuid) { 14402d22f334SRobert Watson nwsp = DPCPU_ID_PTR(cpuid, nws); 14412d22f334SRobert Watson if (nwsp->nws_intr_event == NULL) 14422d22f334SRobert Watson continue; 14432d22f334SRobert Watson NWS_LOCK(nwsp); 14442d22f334SRobert Watson snwsp = &snws_array[counter]; 14452d22f334SRobert Watson snwsp->snws_version = sizeof(*snwsp); 14462d22f334SRobert Watson 14472d22f334SRobert Watson /* 14482d22f334SRobert Watson * For now, we equate workstream IDs and CPU IDs in the 14492d22f334SRobert Watson * kernel, but expose them independently to userspace in case 14502d22f334SRobert Watson * that assumption changes in the future. 14512d22f334SRobert Watson */ 14522d22f334SRobert Watson snwsp->snws_wsid = cpuid; 14532d22f334SRobert Watson snwsp->snws_cpu = cpuid; 14542d22f334SRobert Watson if (nwsp->nws_intr_event != NULL) 14552d22f334SRobert Watson snwsp->snws_flags |= NETISR_SNWS_FLAGS_INTR; 14562d22f334SRobert Watson NWS_UNLOCK(nwsp); 14572d22f334SRobert Watson counter++; 14582d22f334SRobert Watson } 14592d22f334SRobert Watson NETISR_RUNLOCK(&tracker); 14607f450febSRobert Watson KASSERT(counter <= MAXCPU, 14612d22f334SRobert Watson ("sysctl_netisr_workstream: counter too big (%d)", counter)); 14622d22f334SRobert Watson error = SYSCTL_OUT(req, snws_array, sizeof(*snws_array) * counter); 14632d22f334SRobert Watson free(snws_array, M_TEMP); 14642d22f334SRobert Watson return (error); 14652d22f334SRobert Watson } 14662d22f334SRobert Watson 14672d22f334SRobert Watson SYSCTL_PROC(_net_isr, OID_AUTO, workstream, 14682d22f334SRobert Watson CTLFLAG_RD|CTLTYPE_STRUCT|CTLFLAG_MPSAFE, 0, 0, sysctl_netisr_workstream, 14692d22f334SRobert Watson "S,sysctl_netisr_workstream", 14702d22f334SRobert Watson "Return list of workstreams implemented by netisr"); 14712d22f334SRobert Watson 14722d22f334SRobert Watson /* 14732d22f334SRobert Watson * Sysctl monitoring for netisr: query per-protocol data across all 14742d22f334SRobert Watson * workstreams. 14752d22f334SRobert Watson */ 14762d22f334SRobert Watson static int 14772d22f334SRobert Watson sysctl_netisr_work(SYSCTL_HANDLER_ARGS) 14782d22f334SRobert Watson { 14792d22f334SRobert Watson struct rm_priotracker tracker; 14802d22f334SRobert Watson struct sysctl_netisr_work *snwp, *snw_array; 14812d22f334SRobert Watson struct netisr_workstream *nwsp; 14822d22f334SRobert Watson struct netisr_proto *npp; 14832d22f334SRobert Watson struct netisr_work *nwp; 14842d22f334SRobert Watson u_int counter, cpuid, proto; 14852d22f334SRobert Watson int error; 14862d22f334SRobert Watson 14872d22f334SRobert Watson if (req->newptr != NULL) 14882d22f334SRobert Watson return (EINVAL); 14892d22f334SRobert Watson snw_array = malloc(sizeof(*snw_array) * MAXCPU * NETISR_MAXPROT, 14902d22f334SRobert Watson M_TEMP, M_ZERO | M_WAITOK); 14912d22f334SRobert Watson counter = 0; 14922d22f334SRobert Watson NETISR_RLOCK(&tracker); 14933aa6d94eSJohn Baldwin CPU_FOREACH(cpuid) { 14942d22f334SRobert Watson nwsp = DPCPU_ID_PTR(cpuid, nws); 14952d22f334SRobert Watson if (nwsp->nws_intr_event == NULL) 14962d22f334SRobert Watson continue; 14972d22f334SRobert Watson NWS_LOCK(nwsp); 14982d22f334SRobert Watson for (proto = 0; proto < NETISR_MAXPROT; proto++) { 1499938448cdSRobert Watson npp = &netisr_proto[proto]; 15002d22f334SRobert Watson if (npp->np_name == NULL) 15012d22f334SRobert Watson continue; 15022d22f334SRobert Watson nwp = &nwsp->nws_work[proto]; 15032d22f334SRobert Watson snwp = &snw_array[counter]; 15042d22f334SRobert Watson snwp->snw_version = sizeof(*snwp); 15052d22f334SRobert Watson snwp->snw_wsid = cpuid; /* See comment above. */ 15062d22f334SRobert Watson snwp->snw_proto = proto; 15072d22f334SRobert Watson snwp->snw_len = nwp->nw_len; 15082d22f334SRobert Watson snwp->snw_watermark = nwp->nw_watermark; 15092d22f334SRobert Watson snwp->snw_dispatched = nwp->nw_dispatched; 15102d22f334SRobert Watson snwp->snw_hybrid_dispatched = 15112d22f334SRobert Watson nwp->nw_hybrid_dispatched; 15122d22f334SRobert Watson snwp->snw_qdrops = nwp->nw_qdrops; 15132d22f334SRobert Watson snwp->snw_queued = nwp->nw_queued; 15142d22f334SRobert Watson snwp->snw_handled = nwp->nw_handled; 15152d22f334SRobert Watson counter++; 15162d22f334SRobert Watson } 15172d22f334SRobert Watson NWS_UNLOCK(nwsp); 15182d22f334SRobert Watson } 15197f450febSRobert Watson KASSERT(counter <= MAXCPU * NETISR_MAXPROT, 15202d22f334SRobert Watson ("sysctl_netisr_work: counter too big (%d)", counter)); 15212d22f334SRobert Watson NETISR_RUNLOCK(&tracker); 15222d22f334SRobert Watson error = SYSCTL_OUT(req, snw_array, sizeof(*snw_array) * counter); 15232d22f334SRobert Watson free(snw_array, M_TEMP); 15242d22f334SRobert Watson return (error); 15252d22f334SRobert Watson } 15262d22f334SRobert Watson 15272d22f334SRobert Watson SYSCTL_PROC(_net_isr, OID_AUTO, work, 15282d22f334SRobert Watson CTLFLAG_RD|CTLTYPE_STRUCT|CTLFLAG_MPSAFE, 0, 0, sysctl_netisr_work, 15292d22f334SRobert Watson "S,sysctl_netisr_work", 15302d22f334SRobert Watson "Return list of per-workstream, per-protocol work in netisr"); 15312d22f334SRobert Watson 1532d4b5cae4SRobert Watson #ifdef DDB 1533d4b5cae4SRobert Watson DB_SHOW_COMMAND(netisr, db_show_netisr) 1534d4b5cae4SRobert Watson { 1535d4b5cae4SRobert Watson struct netisr_workstream *nwsp; 1536d4b5cae4SRobert Watson struct netisr_work *nwp; 1537d4b5cae4SRobert Watson int first, proto; 153853402767SRobert Watson u_int cpuid; 1539d4b5cae4SRobert Watson 1540d4b5cae4SRobert Watson db_printf("%3s %6s %5s %5s %5s %8s %8s %8s %8s\n", "CPU", "Proto", 1541d4b5cae4SRobert Watson "Len", "WMark", "Max", "Disp", "HDisp", "Drop", "Queue"); 15423aa6d94eSJohn Baldwin CPU_FOREACH(cpuid) { 154353402767SRobert Watson nwsp = DPCPU_ID_PTR(cpuid, nws); 1544d4b5cae4SRobert Watson if (nwsp->nws_intr_event == NULL) 1545d4b5cae4SRobert Watson continue; 1546d4b5cae4SRobert Watson first = 1; 1547d4b5cae4SRobert Watson for (proto = 0; proto < NETISR_MAXPROT; proto++) { 1548938448cdSRobert Watson if (netisr_proto[proto].np_handler == NULL) 1549d4b5cae4SRobert Watson continue; 1550d4b5cae4SRobert Watson nwp = &nwsp->nws_work[proto]; 1551d4b5cae4SRobert Watson if (first) { 155253402767SRobert Watson db_printf("%3d ", cpuid); 1553d4b5cae4SRobert Watson first = 0; 1554d4b5cae4SRobert Watson } else 1555d4b5cae4SRobert Watson db_printf("%3s ", ""); 1556d4b5cae4SRobert Watson db_printf( 1557d4b5cae4SRobert Watson "%6s %5d %5d %5d %8ju %8ju %8ju %8ju\n", 1558938448cdSRobert Watson netisr_proto[proto].np_name, nwp->nw_len, 1559d4b5cae4SRobert Watson nwp->nw_watermark, nwp->nw_qlimit, 1560d4b5cae4SRobert Watson nwp->nw_dispatched, nwp->nw_hybrid_dispatched, 1561d4b5cae4SRobert Watson nwp->nw_qdrops, nwp->nw_queued); 1562d4b5cae4SRobert Watson } 1563d4b5cae4SRobert Watson } 1564d4b5cae4SRobert Watson } 1565d4b5cae4SRobert Watson #endif 1566