netisr.c revision 191816
138494Sobrien/*-
238494Sobrien * Copyright (c) 2001,2002,2003 Jonathan Lemon <jlemon@FreeBSD.org>
338494Sobrien * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
438494Sobrien * All rights reserved.
5174294Sobrien *
638494Sobrien * Redistribution and use in source and binary forms, with or without
738494Sobrien * modification, are permitted provided that the following conditions
838494Sobrien * are met:
938494Sobrien * 1. Redistributions of source code must retain the above copyright
1038494Sobrien *    notice, this list of conditions and the following disclaimer.
1138494Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1238494Sobrien *    notice, this list of conditions and the following disclaimer in the
1338494Sobrien *    documentation and/or other materials provided with the distribution.
1438494Sobrien *
1582794Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1638494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1738494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1838494Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1938494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2038494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2138494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2238494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2338494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2438494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2538494Sobrien * SUCH DAMAGE.
2638494Sobrien *
2738494Sobrien * $FreeBSD: head/sys/net/netisr.c 191816 2009-05-05 10:56:12Z zec $
2838494Sobrien */
2982794Sobrien
3038494Sobrien#include "opt_device_polling.h"
3138494Sobrien
3238494Sobrien#include <sys/param.h>
3338494Sobrien#include <sys/bus.h>
3438494Sobrien#include <sys/rtprio.h>
3538494Sobrien#include <sys/systm.h>
3638494Sobrien#include <sys/interrupt.h>
3738494Sobrien#include <sys/kernel.h>
3838494Sobrien#include <sys/kthread.h>
3938494Sobrien#include <sys/lock.h>
4038494Sobrien#include <sys/malloc.h>
4138494Sobrien#include <sys/proc.h>
4238494Sobrien#include <sys/random.h>
4338494Sobrien#include <sys/resourcevar.h>
4438494Sobrien#include <sys/sysctl.h>
4538494Sobrien#include <sys/unistd.h>
4638494Sobrien#include <sys/vimage.h>
4738494Sobrien#include <machine/atomic.h>
4838494Sobrien#include <machine/cpu.h>
4938494Sobrien#include <machine/stdarg.h>
5082794Sobrien
5182794Sobrien#include <sys/mbuf.h>
5282794Sobrien#include <sys/socket.h>
5338494Sobrien
54#include <net/if.h>
55#include <net/if_types.h>
56#include <net/if_var.h>
57#include <net/netisr.h>
58
59volatile unsigned int	netisr;	/* scheduling bits for network */
60
61struct netisr {
62	netisr_t	*ni_handler;
63	struct ifqueue	*ni_queue;
64	int		ni_flags;
65} netisrs[32];
66
67static void *net_ih;
68
69void
70legacy_setsoftnet(void)
71{
72	swi_sched(net_ih, 0);
73}
74
75void
76netisr_register(int num, netisr_t *handler, struct ifqueue *inq, int flags)
77{
78
79	KASSERT(!(num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs))),
80	    ("bad isr %d", num));
81	KASSERT(flags == 0 || flags == NETISR_FORCEQUEUE,
82	    ("netisr_register: bad flags 0x%x\n", flags));
83	netisrs[num].ni_handler = handler;
84	netisrs[num].ni_queue = inq;
85	netisrs[num].ni_flags = flags;
86}
87
88void
89netisr_unregister(int num)
90{
91	struct netisr *ni;
92
93	KASSERT(!(num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs))),
94	    ("bad isr %d", num));
95	ni = &netisrs[num];
96	ni->ni_handler = NULL;
97	if (ni->ni_queue != NULL)
98		IF_DRAIN(ni->ni_queue);
99	ni->ni_queue = NULL;
100}
101
102struct isrstat {
103	int	isrs_count;			/* dispatch count */
104	int	isrs_directed;			/* ...directly dispatched */
105	int	isrs_deferred;			/* ...queued instead */
106	int	isrs_queued;			/* intentionally queueued */
107	int	isrs_drop;			/* dropped 'cuz no handler */
108	int	isrs_swi_count;			/* swi_net handlers called */
109};
110static struct isrstat isrstat;
111
112SYSCTL_NODE(_net, OID_AUTO, isr, CTLFLAG_RW, 0, "netisr counters");
113
114static int	netisr_direct = 1;
115SYSCTL_INT(_net_isr, OID_AUTO, direct, CTLFLAG_RW,
116    &netisr_direct, 0, "enable direct dispatch");
117TUNABLE_INT("net.isr.direct", &netisr_direct);
118
119SYSCTL_INT(_net_isr, OID_AUTO, count, CTLFLAG_RD,
120    &isrstat.isrs_count, 0, "");
121SYSCTL_INT(_net_isr, OID_AUTO, directed, CTLFLAG_RD,
122    &isrstat.isrs_directed, 0, "");
123SYSCTL_INT(_net_isr, OID_AUTO, deferred, CTLFLAG_RD,
124    &isrstat.isrs_deferred, 0, "");
125SYSCTL_INT(_net_isr, OID_AUTO, queued, CTLFLAG_RD,
126    &isrstat.isrs_queued, 0, "");
127SYSCTL_INT(_net_isr, OID_AUTO, drop, CTLFLAG_RD,
128    &isrstat.isrs_drop, 0, "");
129SYSCTL_INT(_net_isr, OID_AUTO, swi_count, CTLFLAG_RD,
130    &isrstat.isrs_swi_count, 0, "");
131
132/*
133 * Process all packets currently present in a netisr queue.  Used to
134 * drain an existing set of packets waiting for processing when we
135 * begin direct dispatch, to avoid processing packets out of order.
136 */
137static void
138netisr_processqueue(struct netisr *ni)
139{
140	struct mbuf *m;
141
142	for (;;) {
143		IF_DEQUEUE(ni->ni_queue, m);
144		if (m == NULL)
145			break;
146		VNET_ASSERT(m->m_pkthdr.rcvif != NULL);
147		CURVNET_SET(m->m_pkthdr.rcvif->if_vnet);
148		ni->ni_handler(m);
149		CURVNET_RESTORE();
150	}
151}
152
153/*
154 * Call the netisr directly instead of queueing the packet, if possible.
155 */
156void
157netisr_dispatch(int num, struct mbuf *m)
158{
159	struct netisr *ni;
160
161	isrstat.isrs_count++;		/* XXX redundant */
162	KASSERT(!(num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs))),
163	    ("bad isr %d", num));
164	ni = &netisrs[num];
165	if (ni->ni_queue == NULL) {
166		isrstat.isrs_drop++;
167		m_freem(m);
168		return;
169	}
170
171	/*
172	 * Unless NETISR_FORCEQUEUE is set on the netisr (generally
173	 * indicating that the handler still requires Giant, which cannot be
174	 * acquired in arbitrary order with respect to a caller), directly
175	 * dispatch handling of this packet.  Source ordering is maintained
176	 * by virtue of callers consistently calling one of queued or direct
177	 * dispatch, and the forcequeue flag being immutable after
178	 * registration.
179	 */
180	if (netisr_direct && !(ni->ni_flags & NETISR_FORCEQUEUE)) {
181		isrstat.isrs_directed++;
182		ni->ni_handler(m);
183	} else {
184		isrstat.isrs_deferred++;
185		if (IF_HANDOFF(ni->ni_queue, m, NULL))
186			schednetisr(num);
187	}
188}
189
190/*
191 * Same as above, but always queue.
192 * This is either used in places where we are not confident that
193 * direct dispatch is possible, or where queueing is required.
194 * It returns (0) on success and ERRNO on failure.  On failure the
195 * mbuf has been free'd.
196 */
197int
198netisr_queue(int num, struct mbuf *m)
199{
200	struct netisr *ni;
201
202	KASSERT(!(num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs))),
203	    ("bad isr %d", num));
204	ni = &netisrs[num];
205	if (ni->ni_queue == NULL) {
206		isrstat.isrs_drop++;
207		m_freem(m);
208		return (ENXIO);
209	}
210	isrstat.isrs_queued++;
211	if (!IF_HANDOFF(ni->ni_queue, m, NULL))
212		return (ENOBUFS);	/* IF_HANDOFF has free'd the mbuf */
213	schednetisr(num);
214	return (0);
215}
216
217static void
218swi_net(void *dummy)
219{
220	struct netisr *ni;
221	u_int bits;
222	int i;
223#ifdef DEVICE_POLLING
224	const int polling = 1;
225#else
226	const int polling = 0;
227#endif
228
229	do {
230		bits = atomic_readandclear_int(&netisr);
231		if (bits == 0)
232			break;
233		while ((i = ffs(bits)) != 0) {
234			isrstat.isrs_swi_count++;
235			i--;
236			bits &= ~(1 << i);
237			ni = &netisrs[i];
238			if (ni->ni_handler == NULL) {
239				printf("swi_net: unregistered isr %d.\n", i);
240				continue;
241			}
242			if (ni->ni_queue == NULL)
243				ni->ni_handler(NULL);
244			else
245				netisr_processqueue(ni);
246		}
247	} while (polling);
248}
249
250static void
251start_netisr(void *dummy)
252{
253
254	if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, INTR_MPSAFE, &net_ih))
255		panic("start_netisr");
256}
257SYSINIT(start_netisr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_netisr, NULL);
258