xref: /openbsd-src/sys/net/ifq.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /*	$OpenBSD: ifq.c,v 1.41 2020/07/07 00:00:03 dlg Exp $ */
2 
3 /*
4  * Copyright (c) 2015 David Gwynne <dlg@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include "bpfilter.h"
20 #include "kstat.h"
21 
22 #include <sys/param.h>
23 #include <sys/systm.h>
24 #include <sys/socket.h>
25 #include <sys/mbuf.h>
26 #include <sys/proc.h>
27 #include <sys/sysctl.h>
28 
29 #include <net/if.h>
30 #include <net/if_var.h>
31 
32 #if NBPFILTER > 0
33 #include <net/bpf.h>
34 #endif
35 
36 #if NKSTAT > 0
37 #include <sys/kstat.h>
38 #endif
39 
40 /*
41  * priq glue
42  */
43 unsigned int	 priq_idx(unsigned int, const struct mbuf *);
44 struct mbuf	*priq_enq(struct ifqueue *, struct mbuf *);
45 struct mbuf	*priq_deq_begin(struct ifqueue *, void **);
46 void		 priq_deq_commit(struct ifqueue *, struct mbuf *, void *);
47 void		 priq_purge(struct ifqueue *, struct mbuf_list *);
48 
49 void		*priq_alloc(unsigned int, void *);
50 void		 priq_free(unsigned int, void *);
51 
52 const struct ifq_ops priq_ops = {
53 	priq_idx,
54 	priq_enq,
55 	priq_deq_begin,
56 	priq_deq_commit,
57 	priq_purge,
58 	priq_alloc,
59 	priq_free,
60 };
61 
62 const struct ifq_ops * const ifq_priq_ops = &priq_ops;
63 
64 /*
65  * priq internal structures
66  */
67 
68 struct priq {
69 	struct mbuf_list	 pq_lists[IFQ_NQUEUES];
70 };
71 
72 /*
73  * ifqueue serialiser
74  */
75 
76 void	ifq_start_task(void *);
77 void	ifq_restart_task(void *);
78 void	ifq_barrier_task(void *);
79 void	ifq_bundle_task(void *);
80 
81 static inline void
82 ifq_run_start(struct ifqueue *ifq)
83 {
84 	ifq_serialize(ifq, &ifq->ifq_start);
85 }
86 
87 void
88 ifq_serialize(struct ifqueue *ifq, struct task *t)
89 {
90 	struct task work;
91 
92 	if (ISSET(t->t_flags, TASK_ONQUEUE))
93 		return;
94 
95 	mtx_enter(&ifq->ifq_task_mtx);
96 	if (!ISSET(t->t_flags, TASK_ONQUEUE)) {
97 		SET(t->t_flags, TASK_ONQUEUE);
98 		TAILQ_INSERT_TAIL(&ifq->ifq_task_list, t, t_entry);
99 	}
100 
101 	if (ifq->ifq_serializer == NULL) {
102 		ifq->ifq_serializer = curcpu();
103 
104 		while ((t = TAILQ_FIRST(&ifq->ifq_task_list)) != NULL) {
105 			TAILQ_REMOVE(&ifq->ifq_task_list, t, t_entry);
106 			CLR(t->t_flags, TASK_ONQUEUE);
107 			work = *t; /* copy to caller to avoid races */
108 
109 			mtx_leave(&ifq->ifq_task_mtx);
110 
111 			(*work.t_func)(work.t_arg);
112 
113 			mtx_enter(&ifq->ifq_task_mtx);
114 		}
115 
116 		ifq->ifq_serializer = NULL;
117 	}
118 	mtx_leave(&ifq->ifq_task_mtx);
119 }
120 
121 int
122 ifq_is_serialized(struct ifqueue *ifq)
123 {
124 	return (ifq->ifq_serializer == curcpu());
125 }
126 
127 void
128 ifq_start(struct ifqueue *ifq)
129 {
130 	if (ifq_len(ifq) >= min(ifq->ifq_if->if_txmit, ifq->ifq_maxlen)) {
131 		task_del(ifq->ifq_softnet, &ifq->ifq_bundle);
132 		ifq_run_start(ifq);
133 	} else
134 		task_add(ifq->ifq_softnet, &ifq->ifq_bundle);
135 }
136 
137 void
138 ifq_start_task(void *p)
139 {
140 	struct ifqueue *ifq = p;
141 	struct ifnet *ifp = ifq->ifq_if;
142 
143 	if (!ISSET(ifp->if_flags, IFF_RUNNING) ||
144 	    ifq_empty(ifq) || ifq_is_oactive(ifq))
145 		return;
146 
147 	ifp->if_qstart(ifq);
148 }
149 
150 void
151 ifq_restart_task(void *p)
152 {
153 	struct ifqueue *ifq = p;
154 	struct ifnet *ifp = ifq->ifq_if;
155 
156 	ifq_clr_oactive(ifq);
157 	ifp->if_qstart(ifq);
158 }
159 
160 void
161 ifq_bundle_task(void *p)
162 {
163 	struct ifqueue *ifq = p;
164 
165 	ifq_run_start(ifq);
166 }
167 
168 void
169 ifq_barrier(struct ifqueue *ifq)
170 {
171 	struct cond c = COND_INITIALIZER();
172 	struct task t = TASK_INITIALIZER(ifq_barrier_task, &c);
173 
174 	task_del(ifq->ifq_softnet, &ifq->ifq_bundle);
175 
176 	if (ifq->ifq_serializer == NULL)
177 		return;
178 
179 	ifq_serialize(ifq, &t);
180 
181 	cond_wait(&c, "ifqbar");
182 }
183 
184 void
185 ifq_barrier_task(void *p)
186 {
187 	struct cond *c = p;
188 
189 	cond_signal(c);
190 }
191 
192 /*
193  * ifqueue mbuf queue API
194  */
195 
196 #if NKSTAT > 0
197 struct ifq_kstat_data {
198 	struct kstat_kv kd_packets;
199 	struct kstat_kv kd_bytes;
200 	struct kstat_kv kd_qdrops;
201 	struct kstat_kv kd_errors;
202 	struct kstat_kv kd_qlen;
203 	struct kstat_kv kd_maxqlen;
204 	struct kstat_kv kd_oactive;
205 };
206 
207 static const struct ifq_kstat_data ifq_kstat_tpl = {
208 	KSTAT_KV_UNIT_INITIALIZER("packets",
209 	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
210 	KSTAT_KV_UNIT_INITIALIZER("bytes",
211 	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES),
212 	KSTAT_KV_UNIT_INITIALIZER("qdrops",
213 	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
214 	KSTAT_KV_UNIT_INITIALIZER("errors",
215 	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
216 	KSTAT_KV_UNIT_INITIALIZER("qlen",
217 	    KSTAT_KV_T_UINT32, KSTAT_KV_U_PACKETS),
218 	KSTAT_KV_UNIT_INITIALIZER("maxqlen",
219 	    KSTAT_KV_T_UINT32, KSTAT_KV_U_PACKETS),
220 	KSTAT_KV_INITIALIZER("oactive", KSTAT_KV_T_BOOL),
221 };
222 
223 int
224 ifq_kstat_copy(struct kstat *ks, void *dst)
225 {
226 	struct ifqueue *ifq = ks->ks_softc;
227 	struct ifq_kstat_data *kd = dst;
228 
229 	*kd = ifq_kstat_tpl;
230 	kstat_kv_u64(&kd->kd_packets) = ifq->ifq_packets;
231 	kstat_kv_u64(&kd->kd_bytes) = ifq->ifq_bytes;
232 	kstat_kv_u64(&kd->kd_qdrops) = ifq->ifq_qdrops;
233 	kstat_kv_u64(&kd->kd_errors) = ifq->ifq_errors;
234 	kstat_kv_u32(&kd->kd_qlen) = ifq->ifq_len;
235 	kstat_kv_u32(&kd->kd_maxqlen) = ifq->ifq_maxlen;
236 	kstat_kv_bool(&kd->kd_oactive) = ifq->ifq_oactive;
237 
238 	return (0);
239 }
240 #endif
241 
242 void
243 ifq_init(struct ifqueue *ifq, struct ifnet *ifp, unsigned int idx)
244 {
245 	ifq->ifq_if = ifp;
246 	ifq->ifq_softnet = net_tq(ifp->if_index); /* + idx */
247 	ifq->ifq_softc = NULL;
248 
249 	mtx_init(&ifq->ifq_mtx, IPL_NET);
250 
251 	/* default to priq */
252 	ifq->ifq_ops = &priq_ops;
253 	ifq->ifq_q = priq_ops.ifqop_alloc(idx, NULL);
254 
255 	ml_init(&ifq->ifq_free);
256 	ifq->ifq_len = 0;
257 
258 	ifq->ifq_packets = 0;
259 	ifq->ifq_bytes = 0;
260 	ifq->ifq_qdrops = 0;
261 	ifq->ifq_errors = 0;
262 	ifq->ifq_mcasts = 0;
263 
264 	mtx_init(&ifq->ifq_task_mtx, IPL_NET);
265 	TAILQ_INIT(&ifq->ifq_task_list);
266 	ifq->ifq_serializer = NULL;
267 	task_set(&ifq->ifq_bundle, ifq_bundle_task, ifq);
268 
269 	task_set(&ifq->ifq_start, ifq_start_task, ifq);
270 	task_set(&ifq->ifq_restart, ifq_restart_task, ifq);
271 
272 	if (ifq->ifq_maxlen == 0)
273 		ifq_set_maxlen(ifq, IFQ_MAXLEN);
274 
275 	ifq->ifq_idx = idx;
276 
277 #if NKSTAT > 0
278 	/* XXX xname vs driver name and unit */
279 	ifq->ifq_kstat = kstat_create(ifp->if_xname, 0,
280 	    "txq", ifq->ifq_idx, KSTAT_T_KV, 0);
281 	KASSERT(ifq->ifq_kstat != NULL);
282 	kstat_set_mutex(ifq->ifq_kstat, &ifq->ifq_mtx);
283 	ifq->ifq_kstat->ks_softc = ifq;
284 	ifq->ifq_kstat->ks_datalen = sizeof(ifq_kstat_tpl);
285 	ifq->ifq_kstat->ks_copy = ifq_kstat_copy;
286 	kstat_install(ifq->ifq_kstat);
287 #endif
288 }
289 
290 void
291 ifq_attach(struct ifqueue *ifq, const struct ifq_ops *newops, void *opsarg)
292 {
293 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
294 	struct mbuf_list free_ml = MBUF_LIST_INITIALIZER();
295 	struct mbuf *m;
296 	const struct ifq_ops *oldops;
297 	void *newq, *oldq;
298 
299 	newq = newops->ifqop_alloc(ifq->ifq_idx, opsarg);
300 
301 	mtx_enter(&ifq->ifq_mtx);
302 	ifq->ifq_ops->ifqop_purge(ifq, &ml);
303 	ifq->ifq_len = 0;
304 
305 	oldops = ifq->ifq_ops;
306 	oldq = ifq->ifq_q;
307 
308 	ifq->ifq_ops = newops;
309 	ifq->ifq_q = newq;
310 
311 	while ((m = ml_dequeue(&ml)) != NULL) {
312 		m = ifq->ifq_ops->ifqop_enq(ifq, m);
313 		if (m != NULL) {
314 			ifq->ifq_qdrops++;
315 			ml_enqueue(&free_ml, m);
316 		} else
317 			ifq->ifq_len++;
318 	}
319 	mtx_leave(&ifq->ifq_mtx);
320 
321 	oldops->ifqop_free(ifq->ifq_idx, oldq);
322 
323 	ml_purge(&free_ml);
324 }
325 
326 void
327 ifq_destroy(struct ifqueue *ifq)
328 {
329 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
330 
331 #if NKSTAT > 0
332 	kstat_destroy(ifq->ifq_kstat);
333 #endif
334 
335 	NET_ASSERT_UNLOCKED();
336 	if (!task_del(ifq->ifq_softnet, &ifq->ifq_bundle))
337 		taskq_barrier(ifq->ifq_softnet);
338 
339 	/* don't need to lock because this is the last use of the ifq */
340 
341 	ifq->ifq_ops->ifqop_purge(ifq, &ml);
342 	ifq->ifq_ops->ifqop_free(ifq->ifq_idx, ifq->ifq_q);
343 
344 	ml_purge(&ml);
345 }
346 
347 void
348 ifq_add_data(struct ifqueue *ifq, struct if_data *data)
349 {
350 	mtx_enter(&ifq->ifq_mtx);
351 	data->ifi_opackets += ifq->ifq_packets;
352 	data->ifi_obytes += ifq->ifq_bytes;
353 	data->ifi_oqdrops += ifq->ifq_qdrops;
354 	data->ifi_omcasts += ifq->ifq_mcasts;
355 	/* ifp->if_data.ifi_oerrors */
356 	mtx_leave(&ifq->ifq_mtx);
357 }
358 
359 int
360 ifq_enqueue(struct ifqueue *ifq, struct mbuf *m)
361 {
362 	struct mbuf *dm;
363 
364 	mtx_enter(&ifq->ifq_mtx);
365 	dm = ifq->ifq_ops->ifqop_enq(ifq, m);
366 	if (dm != m) {
367 		ifq->ifq_packets++;
368 		ifq->ifq_bytes += m->m_pkthdr.len;
369 		if (ISSET(m->m_flags, M_MCAST))
370 			ifq->ifq_mcasts++;
371 	}
372 
373 	if (dm == NULL)
374 		ifq->ifq_len++;
375 	else
376 		ifq->ifq_qdrops++;
377 	mtx_leave(&ifq->ifq_mtx);
378 
379 	if (dm != NULL)
380 		m_freem(dm);
381 
382 	return (dm == m ? ENOBUFS : 0);
383 }
384 
385 static inline void
386 ifq_deq_enter(struct ifqueue *ifq)
387 {
388 	mtx_enter(&ifq->ifq_mtx);
389 }
390 
391 static inline void
392 ifq_deq_leave(struct ifqueue *ifq)
393 {
394 	struct mbuf_list ml;
395 
396 	ml = ifq->ifq_free;
397 	ml_init(&ifq->ifq_free);
398 
399 	mtx_leave(&ifq->ifq_mtx);
400 
401 	if (!ml_empty(&ml))
402 		ml_purge(&ml);
403 }
404 
405 struct mbuf *
406 ifq_deq_begin(struct ifqueue *ifq)
407 {
408 	struct mbuf *m = NULL;
409 	void *cookie;
410 
411 	ifq_deq_enter(ifq);
412 	if (ifq->ifq_len == 0 ||
413 	    (m = ifq->ifq_ops->ifqop_deq_begin(ifq, &cookie)) == NULL) {
414 		ifq_deq_leave(ifq);
415 		return (NULL);
416 	}
417 
418 	m->m_pkthdr.ph_cookie = cookie;
419 
420 	return (m);
421 }
422 
423 void
424 ifq_deq_commit(struct ifqueue *ifq, struct mbuf *m)
425 {
426 	void *cookie;
427 
428 	KASSERT(m != NULL);
429 	cookie = m->m_pkthdr.ph_cookie;
430 
431 	ifq->ifq_ops->ifqop_deq_commit(ifq, m, cookie);
432 	ifq->ifq_len--;
433 	ifq_deq_leave(ifq);
434 }
435 
436 void
437 ifq_deq_rollback(struct ifqueue *ifq, struct mbuf *m)
438 {
439 	KASSERT(m != NULL);
440 
441 	ifq_deq_leave(ifq);
442 }
443 
444 struct mbuf *
445 ifq_dequeue(struct ifqueue *ifq)
446 {
447 	struct mbuf *m;
448 
449 	m = ifq_deq_begin(ifq);
450 	if (m == NULL)
451 		return (NULL);
452 
453 	ifq_deq_commit(ifq, m);
454 
455 	return (m);
456 }
457 
458 int
459 ifq_deq_sleep(struct ifqueue *ifq, struct mbuf **mp, int nbio, int priority,
460     const char *wmesg, volatile unsigned int *sleeping,
461     volatile unsigned int *alive)
462 {
463 	struct mbuf *m;
464 	void *cookie;
465 	int error = 0;
466 
467 	ifq_deq_enter(ifq);
468 	if (ifq->ifq_len == 0 && nbio)
469 		error = EWOULDBLOCK;
470 	else {
471 		for (;;) {
472 			m = ifq->ifq_ops->ifqop_deq_begin(ifq, &cookie);
473 			if (m != NULL) {
474 				ifq->ifq_ops->ifqop_deq_commit(ifq, m, cookie);
475 				ifq->ifq_len--;
476 				*mp = m;
477 				break;
478 			}
479 
480 			(*sleeping)++;
481 			error = msleep_nsec(ifq, &ifq->ifq_mtx,
482 			    priority, wmesg, INFSLP);
483 			(*sleeping)--;
484 			if (error != 0)
485 				break;
486 			if (!(*alive)) {
487 				error = ENXIO;
488 				break;
489 			}
490 		}
491 	}
492 	ifq_deq_leave(ifq);
493 
494 	return (error);
495 }
496 
497 int
498 ifq_hdatalen(struct ifqueue *ifq)
499 {
500 	struct mbuf *m;
501 	int len = 0;
502 
503 	m = ifq_deq_begin(ifq);
504 	if (m != NULL) {
505 		len = m->m_pkthdr.len;
506 		ifq_deq_rollback(ifq, m);
507 	}
508 
509 	return (len);
510 }
511 
512 unsigned int
513 ifq_purge(struct ifqueue *ifq)
514 {
515 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
516 	unsigned int rv;
517 
518 	mtx_enter(&ifq->ifq_mtx);
519 	ifq->ifq_ops->ifqop_purge(ifq, &ml);
520 	rv = ifq->ifq_len;
521 	ifq->ifq_len = 0;
522 	ifq->ifq_qdrops += rv;
523 	mtx_leave(&ifq->ifq_mtx);
524 
525 	KASSERT(rv == ml_len(&ml));
526 
527 	ml_purge(&ml);
528 
529 	return (rv);
530 }
531 
532 void *
533 ifq_q_enter(struct ifqueue *ifq, const struct ifq_ops *ops)
534 {
535 	mtx_enter(&ifq->ifq_mtx);
536 	if (ifq->ifq_ops == ops)
537 		return (ifq->ifq_q);
538 
539 	mtx_leave(&ifq->ifq_mtx);
540 
541 	return (NULL);
542 }
543 
544 void
545 ifq_q_leave(struct ifqueue *ifq, void *q)
546 {
547 	KASSERT(q == ifq->ifq_q);
548 	mtx_leave(&ifq->ifq_mtx);
549 }
550 
551 void
552 ifq_mfreem(struct ifqueue *ifq, struct mbuf *m)
553 {
554 	MUTEX_ASSERT_LOCKED(&ifq->ifq_mtx);
555 
556 	ifq->ifq_len--;
557 	ifq->ifq_qdrops++;
558 	ml_enqueue(&ifq->ifq_free, m);
559 }
560 
561 void
562 ifq_mfreeml(struct ifqueue *ifq, struct mbuf_list *ml)
563 {
564 	MUTEX_ASSERT_LOCKED(&ifq->ifq_mtx);
565 
566 	ifq->ifq_len -= ml_len(ml);
567 	ifq->ifq_qdrops += ml_len(ml);
568 	ml_enlist(&ifq->ifq_free, ml);
569 }
570 
571 /*
572  * ifiq
573  */
574 
575 #if NKSTAT > 0
576 struct ifiq_kstat_data {
577 	struct kstat_kv kd_packets;
578 	struct kstat_kv kd_bytes;
579 	struct kstat_kv kd_qdrops;
580 	struct kstat_kv kd_errors;
581 	struct kstat_kv kd_qlen;
582 };
583 
584 static const struct ifiq_kstat_data ifiq_kstat_tpl = {
585 	KSTAT_KV_UNIT_INITIALIZER("packets",
586 	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
587 	KSTAT_KV_UNIT_INITIALIZER("bytes",
588 	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES),
589 	KSTAT_KV_UNIT_INITIALIZER("qdrops",
590 	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
591 	KSTAT_KV_UNIT_INITIALIZER("errors",
592 	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
593 	KSTAT_KV_UNIT_INITIALIZER("qlen",
594 	    KSTAT_KV_T_UINT32, KSTAT_KV_U_PACKETS),
595 };
596 
597 int
598 ifiq_kstat_copy(struct kstat *ks, void *dst)
599 {
600 	struct ifiqueue *ifiq = ks->ks_softc;
601 	struct ifiq_kstat_data *kd = dst;
602 
603 	*kd = ifiq_kstat_tpl;
604 	kstat_kv_u64(&kd->kd_packets) = ifiq->ifiq_packets;
605 	kstat_kv_u64(&kd->kd_bytes) = ifiq->ifiq_bytes;
606 	kstat_kv_u64(&kd->kd_qdrops) = ifiq->ifiq_qdrops;
607 	kstat_kv_u64(&kd->kd_errors) = ifiq->ifiq_errors;
608 	kstat_kv_u32(&kd->kd_qlen) = ml_len(&ifiq->ifiq_ml);
609 
610 	return (0);
611 }
612 #endif
613 
614 static void	ifiq_process(void *);
615 
616 void
617 ifiq_init(struct ifiqueue *ifiq, struct ifnet *ifp, unsigned int idx)
618 {
619 	ifiq->ifiq_if = ifp;
620 	ifiq->ifiq_softnet = net_tq(ifp->if_index); /* + idx */
621 	ifiq->ifiq_softc = NULL;
622 
623 	mtx_init(&ifiq->ifiq_mtx, IPL_NET);
624 	ml_init(&ifiq->ifiq_ml);
625 	task_set(&ifiq->ifiq_task, ifiq_process, ifiq);
626 	ifiq->ifiq_pressure = 0;
627 
628 	ifiq->ifiq_packets = 0;
629 	ifiq->ifiq_bytes = 0;
630 	ifiq->ifiq_qdrops = 0;
631 	ifiq->ifiq_errors = 0;
632 
633 	ifiq->ifiq_idx = idx;
634 
635 #if NKSTAT > 0
636 	/* XXX xname vs driver name and unit */
637 	ifiq->ifiq_kstat = kstat_create(ifp->if_xname, 0,
638 	    "rxq", ifiq->ifiq_idx, KSTAT_T_KV, 0);
639 	KASSERT(ifiq->ifiq_kstat != NULL);
640 	kstat_set_mutex(ifiq->ifiq_kstat, &ifiq->ifiq_mtx);
641 	ifiq->ifiq_kstat->ks_softc = ifiq;
642 	ifiq->ifiq_kstat->ks_datalen = sizeof(ifiq_kstat_tpl);
643 	ifiq->ifiq_kstat->ks_copy = ifiq_kstat_copy;
644 	kstat_install(ifiq->ifiq_kstat);
645 #endif
646 }
647 
648 void
649 ifiq_destroy(struct ifiqueue *ifiq)
650 {
651 #if NKSTAT > 0
652 	kstat_destroy(ifiq->ifiq_kstat);
653 #endif
654 
655 	NET_ASSERT_UNLOCKED();
656 	if (!task_del(ifiq->ifiq_softnet, &ifiq->ifiq_task))
657 		taskq_barrier(ifiq->ifiq_softnet);
658 
659 	/* don't need to lock because this is the last use of the ifiq */
660 	ml_purge(&ifiq->ifiq_ml);
661 }
662 
663 unsigned int ifiq_maxlen_drop = 2048 * 5;
664 unsigned int ifiq_maxlen_return = 2048 * 3;
665 
666 int
667 ifiq_input(struct ifiqueue *ifiq, struct mbuf_list *ml)
668 {
669 	struct ifnet *ifp = ifiq->ifiq_if;
670 	struct mbuf *m;
671 	uint64_t packets;
672 	uint64_t bytes = 0;
673 	unsigned int len;
674 #if NBPFILTER > 0
675 	caddr_t if_bpf;
676 #endif
677 
678 	if (ml_empty(ml))
679 		return (0);
680 
681 	MBUF_LIST_FOREACH(ml, m) {
682 		m->m_pkthdr.ph_ifidx = ifp->if_index;
683 		m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
684 		bytes += m->m_pkthdr.len;
685 	}
686 	packets = ml_len(ml);
687 
688 #if NBPFILTER > 0
689 	if_bpf = ifp->if_bpf;
690 	if (if_bpf) {
691 		struct mbuf_list ml0 = *ml;
692 
693 		ml_init(ml);
694 
695 		while ((m = ml_dequeue(&ml0)) != NULL) {
696 			if (bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_IN))
697 				m_freem(m);
698 			else
699 				ml_enqueue(ml, m);
700 		}
701 
702 		if (ml_empty(ml)) {
703 			mtx_enter(&ifiq->ifiq_mtx);
704 			ifiq->ifiq_packets += packets;
705 			ifiq->ifiq_bytes += bytes;
706 			mtx_leave(&ifiq->ifiq_mtx);
707 
708 			return (0);
709 		}
710 	}
711 #endif
712 
713 	mtx_enter(&ifiq->ifiq_mtx);
714 	ifiq->ifiq_packets += packets;
715 	ifiq->ifiq_bytes += bytes;
716 
717 	len = ml_len(&ifiq->ifiq_ml);
718 	if (len > ifiq_maxlen_drop)
719 		ifiq->ifiq_qdrops += ml_len(ml);
720 	else
721 		ml_enlist(&ifiq->ifiq_ml, ml);
722 	mtx_leave(&ifiq->ifiq_mtx);
723 
724 	if (ml_empty(ml))
725 		task_add(ifiq->ifiq_softnet, &ifiq->ifiq_task);
726 	else
727 		ml_purge(ml);
728 
729 	return (len > ifiq_maxlen_return);
730 }
731 
732 void
733 ifiq_add_data(struct ifiqueue *ifiq, struct if_data *data)
734 {
735 	mtx_enter(&ifiq->ifiq_mtx);
736 	data->ifi_ipackets += ifiq->ifiq_packets;
737 	data->ifi_ibytes += ifiq->ifiq_bytes;
738 	data->ifi_iqdrops += ifiq->ifiq_qdrops;
739 	mtx_leave(&ifiq->ifiq_mtx);
740 }
741 
742 int
743 ifiq_enqueue(struct ifiqueue *ifiq, struct mbuf *m)
744 {
745 	mtx_enter(&ifiq->ifiq_mtx);
746 	ml_enqueue(&ifiq->ifiq_ml, m);
747 	mtx_leave(&ifiq->ifiq_mtx);
748 
749 	task_add(ifiq->ifiq_softnet, &ifiq->ifiq_task);
750 
751 	return (0);
752 }
753 
754 static void
755 ifiq_process(void *arg)
756 {
757 	struct ifiqueue *ifiq = arg;
758 	struct mbuf_list ml;
759 
760 	if (ifiq_empty(ifiq))
761 		return;
762 
763 	mtx_enter(&ifiq->ifiq_mtx);
764 	ml = ifiq->ifiq_ml;
765 	ml_init(&ifiq->ifiq_ml);
766 	mtx_leave(&ifiq->ifiq_mtx);
767 
768 	if_input_process(ifiq->ifiq_if, &ml);
769 }
770 
771 int
772 net_ifiq_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
773     void *newp, size_t newlen)
774 {
775 	int error = EOPNOTSUPP;
776 /* pressure is disabled for 6.6-release */
777 #if 0
778 	int val;
779 
780 	if (namelen != 1)
781 		return (EISDIR);
782 
783 	switch (name[0]) {
784 	case NET_LINK_IFRXQ_PRESSURE_RETURN:
785 		val = ifiq_pressure_return;
786 		error = sysctl_int(oldp, oldlenp, newp, newlen, &val);
787 		if (error != 0)
788 			return (error);
789 		if (val < 1 || val > ifiq_pressure_drop)
790 			return (EINVAL);
791 		ifiq_pressure_return = val;
792 		break;
793 	case NET_LINK_IFRXQ_PRESSURE_DROP:
794 		val = ifiq_pressure_drop;
795 		error = sysctl_int(oldp, oldlenp, newp, newlen, &val);
796 		if (error != 0)
797 			return (error);
798 		if (ifiq_pressure_return > val)
799 			return (EINVAL);
800 		ifiq_pressure_drop = val;
801 		break;
802 	default:
803 		error = EOPNOTSUPP;
804 		break;
805 	}
806 #endif
807 
808 	return (error);
809 }
810 
811 /*
812  * priq implementation
813  */
814 
815 unsigned int
816 priq_idx(unsigned int nqueues, const struct mbuf *m)
817 {
818 	unsigned int flow = 0;
819 
820 	if (ISSET(m->m_pkthdr.csum_flags, M_FLOWID))
821 		flow = m->m_pkthdr.ph_flowid;
822 
823 	return (flow % nqueues);
824 }
825 
826 void *
827 priq_alloc(unsigned int idx, void *null)
828 {
829 	struct priq *pq;
830 	int i;
831 
832 	pq = malloc(sizeof(struct priq), M_DEVBUF, M_WAITOK);
833 	for (i = 0; i < IFQ_NQUEUES; i++)
834 		ml_init(&pq->pq_lists[i]);
835 	return (pq);
836 }
837 
838 void
839 priq_free(unsigned int idx, void *pq)
840 {
841 	free(pq, M_DEVBUF, sizeof(struct priq));
842 }
843 
844 struct mbuf *
845 priq_enq(struct ifqueue *ifq, struct mbuf *m)
846 {
847 	struct priq *pq;
848 	struct mbuf_list *pl;
849 	struct mbuf *n = NULL;
850 	unsigned int prio;
851 
852 	pq = ifq->ifq_q;
853 	KASSERT(m->m_pkthdr.pf.prio <= IFQ_MAXPRIO);
854 
855 	/* Find a lower priority queue to drop from */
856 	if (ifq_len(ifq) >= ifq->ifq_maxlen) {
857 		for (prio = 0; prio < m->m_pkthdr.pf.prio; prio++) {
858 			pl = &pq->pq_lists[prio];
859 			if (ml_len(pl) > 0) {
860 				n = ml_dequeue(pl);
861 				goto enqueue;
862 			}
863 		}
864 		/*
865 		 * There's no lower priority queue that we can
866 		 * drop from so don't enqueue this one.
867 		 */
868 		return (m);
869 	}
870 
871  enqueue:
872 	pl = &pq->pq_lists[m->m_pkthdr.pf.prio];
873 	ml_enqueue(pl, m);
874 
875 	return (n);
876 }
877 
878 struct mbuf *
879 priq_deq_begin(struct ifqueue *ifq, void **cookiep)
880 {
881 	struct priq *pq = ifq->ifq_q;
882 	struct mbuf_list *pl;
883 	unsigned int prio = nitems(pq->pq_lists);
884 	struct mbuf *m;
885 
886 	do {
887 		pl = &pq->pq_lists[--prio];
888 		m = MBUF_LIST_FIRST(pl);
889 		if (m != NULL) {
890 			*cookiep = pl;
891 			return (m);
892 		}
893 	} while (prio > 0);
894 
895 	return (NULL);
896 }
897 
898 void
899 priq_deq_commit(struct ifqueue *ifq, struct mbuf *m, void *cookie)
900 {
901 	struct mbuf_list *pl = cookie;
902 
903 	KASSERT(MBUF_LIST_FIRST(pl) == m);
904 
905 	ml_dequeue(pl);
906 }
907 
908 void
909 priq_purge(struct ifqueue *ifq, struct mbuf_list *ml)
910 {
911 	struct priq *pq = ifq->ifq_q;
912 	struct mbuf_list *pl;
913 	unsigned int prio = nitems(pq->pq_lists);
914 
915 	do {
916 		pl = &pq->pq_lists[--prio];
917 		ml_enlist(ml, pl);
918 	} while (prio > 0);
919 }
920