11cafed39SJonathan Lemon /*- 21cafed39SJonathan Lemon * Copyright (c) 2001,2002,2003 Jonathan Lemon <jlemon@FreeBSD.org> 3e3b6e33cSJake Burkholder * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 4e3b6e33cSJake Burkholder * All rights reserved. 5e3b6e33cSJake Burkholder * 6e3b6e33cSJake Burkholder * Redistribution and use in source and binary forms, with or without 7e3b6e33cSJake Burkholder * modification, are permitted provided that the following conditions 8e3b6e33cSJake Burkholder * are met: 9e3b6e33cSJake Burkholder * 1. Redistributions of source code must retain the above copyright 101cafed39SJonathan Lemon * notice, this list of conditions and the following disclaimer. 11e3b6e33cSJake Burkholder * 2. Redistributions in binary form must reproduce the above copyright 12e3b6e33cSJake Burkholder * notice, this list of conditions and the following disclaimer in the 13e3b6e33cSJake Burkholder * documentation and/or other materials provided with the distribution. 14e3b6e33cSJake Burkholder * 151cafed39SJonathan Lemon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 161cafed39SJonathan Lemon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 171cafed39SJonathan Lemon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 181cafed39SJonathan Lemon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 191cafed39SJonathan Lemon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 201cafed39SJonathan Lemon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 211cafed39SJonathan Lemon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 221cafed39SJonathan Lemon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 231cafed39SJonathan Lemon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 241cafed39SJonathan Lemon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 251cafed39SJonathan Lemon * SUCH DAMAGE. 26e3b6e33cSJake Burkholder * 27e3b6e33cSJake Burkholder * $FreeBSD$ 28e3b6e33cSJake Burkholder */ 29e3b6e33cSJake Burkholder 30e3b6e33cSJake Burkholder #include <sys/param.h> 31e3b6e33cSJake Burkholder #include <sys/bus.h> 321cafed39SJonathan Lemon #include <sys/rtprio.h> 331cafed39SJonathan Lemon #include <sys/systm.h> 34e3b6e33cSJake Burkholder #include <sys/interrupt.h> 35e3b6e33cSJake Burkholder #include <sys/kernel.h> 361cafed39SJonathan Lemon #include <sys/kthread.h> 371cafed39SJonathan Lemon #include <sys/lock.h> 381cafed39SJonathan Lemon #include <sys/malloc.h> 391cafed39SJonathan Lemon #include <sys/proc.h> 401cafed39SJonathan Lemon #include <sys/random.h> 411cafed39SJonathan Lemon #include <sys/resourcevar.h> 421cafed39SJonathan Lemon #include <sys/sysctl.h> 431cafed39SJonathan Lemon #include <sys/unistd.h> 441cafed39SJonathan Lemon #include <machine/atomic.h> 451cafed39SJonathan Lemon #include <machine/cpu.h> 461cafed39SJonathan Lemon #include <machine/stdarg.h> 47e3b6e33cSJake Burkholder 481cafed39SJonathan Lemon #include <sys/mbuf.h> 491cafed39SJonathan Lemon #include <sys/socket.h> 501cafed39SJonathan Lemon 511cafed39SJonathan Lemon #include <net/if.h> 521cafed39SJonathan Lemon #include <net/if_types.h> 531cafed39SJonathan Lemon #include <net/if_var.h> 54e3b6e33cSJake Burkholder #include <net/netisr.h> 55e3b6e33cSJake Burkholder 56d3be1471SSam Leffler /* 57d3be1471SSam Leffler * XXX this is a temporary measure to allow folks to 58d3be1471SSam Leffler * XXX disable Giant locking in the network code without 59d3be1471SSam Leffler * XXX recompiling--in case of problems. 60d3be1471SSam Leffler */ 61d3be1471SSam Leffler int debug_mpsafenet = 0; 62d3be1471SSam Leffler TUNABLE_INT("debug.mpsafenet", &debug_mpsafenet); 63d3be1471SSam Leffler SYSCTL_INT(_debug, OID_AUTO, mpsafenet, CTLFLAG_RD, &debug_mpsafenet, 0, 64d3be1471SSam Leffler "Enable/disable MPSAFE network support"); 65d3be1471SSam Leffler 661cafed39SJonathan Lemon volatile unsigned int netisr; /* scheduling bits for network */ 67e3b6e33cSJake Burkholder 681cafed39SJonathan Lemon struct netisr { 691cafed39SJonathan Lemon netisr_t *ni_handler; 701cafed39SJonathan Lemon struct ifqueue *ni_queue; 717902224cSSam Leffler int ni_flags; 721cafed39SJonathan Lemon } netisrs[32]; 731cafed39SJonathan Lemon 741cafed39SJonathan Lemon static void *net_ih; 75e3b6e33cSJake Burkholder 76e3b6e33cSJake Burkholder void 77e3b6e33cSJake Burkholder legacy_setsoftnet(void) 78e3b6e33cSJake Burkholder { 79e3b6e33cSJake Burkholder swi_sched(net_ih, 0); 80e3b6e33cSJake Burkholder } 81e3b6e33cSJake Burkholder 821cafed39SJonathan Lemon void 837902224cSSam Leffler netisr_register(int num, netisr_t *handler, struct ifqueue *inq, int flags) 84e3b6e33cSJake Burkholder { 85e3b6e33cSJake Burkholder 861cafed39SJonathan Lemon KASSERT(!(num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs))), 871cafed39SJonathan Lemon ("bad isr %d", num)); 881cafed39SJonathan Lemon netisrs[num].ni_handler = handler; 891cafed39SJonathan Lemon netisrs[num].ni_queue = inq; 907902224cSSam Leffler if ((flags & NETISR_MPSAFE) && !debug_mpsafenet) 917902224cSSam Leffler flags &= ~NETISR_MPSAFE; 927902224cSSam Leffler netisrs[num].ni_flags = flags; 93e3b6e33cSJake Burkholder } 94e3b6e33cSJake Burkholder 951cafed39SJonathan Lemon void 961cafed39SJonathan Lemon netisr_unregister(int num) 97e3b6e33cSJake Burkholder { 981cafed39SJonathan Lemon struct netisr *ni; 99e3b6e33cSJake Burkholder 1001cafed39SJonathan Lemon KASSERT(!(num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs))), 1011cafed39SJonathan Lemon ("bad isr %d", num)); 1021cafed39SJonathan Lemon ni = &netisrs[num]; 1031cafed39SJonathan Lemon ni->ni_handler = NULL; 1047902224cSSam Leffler if (ni->ni_queue != NULL) 1051cafed39SJonathan Lemon IF_DRAIN(ni->ni_queue); 1061cafed39SJonathan Lemon } 1071cafed39SJonathan Lemon 1081cafed39SJonathan Lemon struct isrstat { 1091cafed39SJonathan Lemon int isrs_count; /* dispatch count */ 1107902224cSSam Leffler int isrs_directed; /* ...directly dispatched */ 1111cafed39SJonathan Lemon int isrs_deferred; /* ...queued instead */ 1121cafed39SJonathan Lemon int isrs_queued; /* intentionally queueued */ 1137902224cSSam Leffler int isrs_drop; /* dropped 'cuz no handler */ 1141cafed39SJonathan Lemon int isrs_swi_count; /* swi_net handlers called */ 1151cafed39SJonathan Lemon }; 1161cafed39SJonathan Lemon static struct isrstat isrstat; 1171cafed39SJonathan Lemon 1181cafed39SJonathan Lemon SYSCTL_NODE(_net, OID_AUTO, isr, CTLFLAG_RW, 0, "netisr counters"); 1191cafed39SJonathan Lemon 1203164565dSRobert Watson static int netisr_enable = 0; 1211cafed39SJonathan Lemon SYSCTL_INT(_net_isr, OID_AUTO, enable, CTLFLAG_RW, 1221cafed39SJonathan Lemon &netisr_enable, 0, "enable direct dispatch"); 123e590eca2SRobert Watson TUNABLE_INT("net.isr.enable", &netisr_enable); 1241cafed39SJonathan Lemon 1251cafed39SJonathan Lemon SYSCTL_INT(_net_isr, OID_AUTO, count, CTLFLAG_RD, 1261cafed39SJonathan Lemon &isrstat.isrs_count, 0, ""); 1271cafed39SJonathan Lemon SYSCTL_INT(_net_isr, OID_AUTO, directed, CTLFLAG_RD, 1281cafed39SJonathan Lemon &isrstat.isrs_directed, 0, ""); 1291cafed39SJonathan Lemon SYSCTL_INT(_net_isr, OID_AUTO, deferred, CTLFLAG_RD, 1301cafed39SJonathan Lemon &isrstat.isrs_deferred, 0, ""); 1311cafed39SJonathan Lemon SYSCTL_INT(_net_isr, OID_AUTO, queued, CTLFLAG_RD, 1321cafed39SJonathan Lemon &isrstat.isrs_queued, 0, ""); 1337902224cSSam Leffler SYSCTL_INT(_net_isr, OID_AUTO, drop, CTLFLAG_RD, 1347902224cSSam Leffler &isrstat.isrs_drop, 0, ""); 1351cafed39SJonathan Lemon SYSCTL_INT(_net_isr, OID_AUTO, swi_count, CTLFLAG_RD, 1361cafed39SJonathan Lemon &isrstat.isrs_swi_count, 0, ""); 1371cafed39SJonathan Lemon 1381cafed39SJonathan Lemon /* 1395fd04e38SRobert Watson * Process all packets currently present in a netisr queue. Used to 1405fd04e38SRobert Watson * drain an existing set of packets waiting for processing when we 1415fd04e38SRobert Watson * begin direct dispatch, to avoid processing packets out of order. 1425fd04e38SRobert Watson */ 1435fd04e38SRobert Watson static void 1445fd04e38SRobert Watson netisr_processqueue(struct netisr *ni) 1455fd04e38SRobert Watson { 1465fd04e38SRobert Watson struct mbuf *m; 1475fd04e38SRobert Watson 1485fd04e38SRobert Watson for (;;) { 1495fd04e38SRobert Watson IF_DEQUEUE(ni->ni_queue, m); 1505fd04e38SRobert Watson if (m == NULL) 1515fd04e38SRobert Watson break; 1525fd04e38SRobert Watson ni->ni_handler(m); 1535fd04e38SRobert Watson } 1545fd04e38SRobert Watson } 1555fd04e38SRobert Watson 1565fd04e38SRobert Watson /* 1571cafed39SJonathan Lemon * Call the netisr directly instead of queueing the packet, if possible. 1581cafed39SJonathan Lemon */ 1591cafed39SJonathan Lemon void 1601cafed39SJonathan Lemon netisr_dispatch(int num, struct mbuf *m) 1611cafed39SJonathan Lemon { 1621cafed39SJonathan Lemon struct netisr *ni; 1631cafed39SJonathan Lemon 1647902224cSSam Leffler isrstat.isrs_count++; /* XXX redundant */ 1651cafed39SJonathan Lemon KASSERT(!(num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs))), 1661cafed39SJonathan Lemon ("bad isr %d", num)); 1671cafed39SJonathan Lemon ni = &netisrs[num]; 168fb68148fSJonathan Lemon if (ni->ni_queue == NULL) { 1697902224cSSam Leffler isrstat.isrs_drop++; 170fb68148fSJonathan Lemon m_freem(m); 171fb68148fSJonathan Lemon return; 172fb68148fSJonathan Lemon } 1737902224cSSam Leffler /* 1747902224cSSam Leffler * Do direct dispatch only for MPSAFE netisrs (and 1757902224cSSam Leffler * only when enabled). Note that when a netisr is 1767902224cSSam Leffler * marked MPSAFE we permit multiple concurrent instances 1777902224cSSam Leffler * to run. We guarantee only the order in which 1787902224cSSam Leffler * packets are processed for each "dispatch point" in 1797902224cSSam Leffler * the system (i.e. call to netisr_dispatch or 1807902224cSSam Leffler * netisr_queue). This insures ordering of packets 1817902224cSSam Leffler * from an interface but does not guarantee ordering 1827902224cSSam Leffler * between multiple places in the system (e.g. IP 1837902224cSSam Leffler * dispatched from interfaces vs. IP queued from IPSec). 1847902224cSSam Leffler */ 1857902224cSSam Leffler if (netisr_enable && (ni->ni_flags & NETISR_MPSAFE)) { 1861cafed39SJonathan Lemon isrstat.isrs_directed++; 1871cafed39SJonathan Lemon /* 1887902224cSSam Leffler * NB: We used to drain the queue before handling 1897902224cSSam Leffler * the packet but now do not. Doing so here will 1907902224cSSam Leffler * not preserve ordering so instead we fallback to 1917902224cSSam Leffler * guaranteeing order only from dispatch points 1927902224cSSam Leffler * in the system (see above). 1931cafed39SJonathan Lemon */ 1941cafed39SJonathan Lemon ni->ni_handler(m); 1951cafed39SJonathan Lemon } else { 1961cafed39SJonathan Lemon isrstat.isrs_deferred++; 1971cafed39SJonathan Lemon if (IF_HANDOFF(ni->ni_queue, m, NULL)) 1981cafed39SJonathan Lemon schednetisr(num); 1991cafed39SJonathan Lemon } 2001cafed39SJonathan Lemon } 2011cafed39SJonathan Lemon 2021cafed39SJonathan Lemon /* 2031cafed39SJonathan Lemon * Same as above, but always queue. 2041cafed39SJonathan Lemon * This is either used in places where we are not confident that 2051cafed39SJonathan Lemon * direct dispatch is possible, or where queueing is required. 2061cafed39SJonathan Lemon */ 2071cafed39SJonathan Lemon int 2081cafed39SJonathan Lemon netisr_queue(int num, struct mbuf *m) 2091cafed39SJonathan Lemon { 2101cafed39SJonathan Lemon struct netisr *ni; 2111cafed39SJonathan Lemon 2121cafed39SJonathan Lemon KASSERT(!(num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs))), 2131cafed39SJonathan Lemon ("bad isr %d", num)); 2141cafed39SJonathan Lemon ni = &netisrs[num]; 215fb68148fSJonathan Lemon if (ni->ni_queue == NULL) { 2167902224cSSam Leffler isrstat.isrs_drop++; 217fb68148fSJonathan Lemon m_freem(m); 218fb68148fSJonathan Lemon return (1); 219fb68148fSJonathan Lemon } 2201cafed39SJonathan Lemon isrstat.isrs_queued++; 2211cafed39SJonathan Lemon if (!IF_HANDOFF(ni->ni_queue, m, NULL)) 222e3b6e33cSJake Burkholder return (0); 2231cafed39SJonathan Lemon schednetisr(num); 2241cafed39SJonathan Lemon return (1); 225e3b6e33cSJake Burkholder } 226e3b6e33cSJake Burkholder 227e3b6e33cSJake Burkholder static void 228e3b6e33cSJake Burkholder swi_net(void *dummy) 229e3b6e33cSJake Burkholder { 2301cafed39SJonathan Lemon struct netisr *ni; 231e3b6e33cSJake Burkholder u_int bits; 232e3b6e33cSJake Burkholder int i; 2331cafed39SJonathan Lemon #ifdef DEVICE_POLLING 2341cafed39SJonathan Lemon const int polling = 1; 2351cafed39SJonathan Lemon #else 2361cafed39SJonathan Lemon const int polling = 0; 2371cafed39SJonathan Lemon #endif 238e3b6e33cSJake Burkholder 2391cafed39SJonathan Lemon do { 240e3b6e33cSJake Burkholder bits = atomic_readandclear_int(&netisr); 241e3b6e33cSJake Burkholder if (bits == 0) 2421cafed39SJonathan Lemon break; 243e3b6e33cSJake Burkholder while ((i = ffs(bits)) != 0) { 2441cafed39SJonathan Lemon isrstat.isrs_swi_count++; 245e3b6e33cSJake Burkholder i--; 246e3b6e33cSJake Burkholder bits &= ~(1 << i); 2471cafed39SJonathan Lemon ni = &netisrs[i]; 2481cafed39SJonathan Lemon if (ni->ni_handler == NULL) { 2491cafed39SJonathan Lemon printf("swi_net: unregistered isr %d.\n", i); 2501cafed39SJonathan Lemon continue; 251e3b6e33cSJake Burkholder } 2527902224cSSam Leffler if ((ni->ni_flags & NETISR_MPSAFE) == 0) { 2537902224cSSam Leffler mtx_lock(&Giant); 2547902224cSSam Leffler if (ni->ni_queue == NULL) 2557902224cSSam Leffler ni->ni_handler(NULL); 2567902224cSSam Leffler else 2577902224cSSam Leffler netisr_processqueue(ni); 2587902224cSSam Leffler mtx_unlock(&Giant); 2597902224cSSam Leffler } else { 2601cafed39SJonathan Lemon if (ni->ni_queue == NULL) 2611cafed39SJonathan Lemon ni->ni_handler(NULL); 2621cafed39SJonathan Lemon else 2635fd04e38SRobert Watson netisr_processqueue(ni); 2641cafed39SJonathan Lemon } 2657902224cSSam Leffler } 2661cafed39SJonathan Lemon } while (polling); 267e3b6e33cSJake Burkholder } 268e3b6e33cSJake Burkholder 269e3b6e33cSJake Burkholder static void 270e3b6e33cSJake Burkholder start_netisr(void *dummy) 271e3b6e33cSJake Burkholder { 272e3b6e33cSJake Burkholder 2737902224cSSam Leffler if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, INTR_MPSAFE, &net_ih)) 274e3b6e33cSJake Burkholder panic("start_netisr"); 275e3b6e33cSJake Burkholder } 276e3b6e33cSJake Burkholder SYSINIT(start_netisr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_netisr, NULL) 277