xref: /freebsd/sys/net/netisr.c (revision 7902224c6bf05f57bba57a72b6d11d4023a84883)
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