ifq.c revision 1.49
1/*	$OpenBSD: ifq.c,v 1.49 2023/01/09 03:39:14 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 */
43unsigned int	 priq_idx(unsigned int, const struct mbuf *);
44struct mbuf	*priq_enq(struct ifqueue *, struct mbuf *);
45struct mbuf	*priq_deq_begin(struct ifqueue *, void **);
46void		 priq_deq_commit(struct ifqueue *, struct mbuf *, void *);
47void		 priq_purge(struct ifqueue *, struct mbuf_list *);
48
49void		*priq_alloc(unsigned int, void *);
50void		 priq_free(unsigned int, void *);
51
52const 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
62const struct ifq_ops * const ifq_priq_ops = &priq_ops;
63
64/*
65 * priq internal structures
66 */
67
68struct priq {
69	struct mbuf_list	 pq_lists[IFQ_NQUEUES];
70};
71
72/*
73 * ifqueue serialiser
74 */
75
76void	ifq_start_task(void *);
77void	ifq_restart_task(void *);
78void	ifq_barrier_task(void *);
79void	ifq_bundle_task(void *);
80
81static inline void
82ifq_run_start(struct ifqueue *ifq)
83{
84	ifq_serialize(ifq, &ifq->ifq_start);
85}
86
87void
88ifq_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
121int
122ifq_is_serialized(struct ifqueue *ifq)
123{
124	return (ifq->ifq_serializer == curcpu());
125}
126
127void
128ifq_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
137void
138ifq_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
150void
151ifq_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
160void
161ifq_bundle_task(void *p)
162{
163	struct ifqueue *ifq = p;
164
165	ifq_run_start(ifq);
166}
167
168void
169ifq_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
184void
185ifq_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
197struct 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
207static 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
223int
224ifq_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
242void
243ifq_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
290void
291ifq_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
326void
327ifq_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
347void
348ifq_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
359int
360ifq_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
385static inline void
386ifq_deq_enter(struct ifqueue *ifq)
387{
388	mtx_enter(&ifq->ifq_mtx);
389}
390
391static inline void
392ifq_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
405struct mbuf *
406ifq_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
423void
424ifq_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
436void
437ifq_deq_rollback(struct ifqueue *ifq, struct mbuf *m)
438{
439	KASSERT(m != NULL);
440
441	ifq_deq_leave(ifq);
442}
443
444struct mbuf *
445ifq_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
458int
459ifq_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 = EIO;
488				break;
489			}
490		}
491	}
492	ifq_deq_leave(ifq);
493
494	return (error);
495}
496
497int
498ifq_hdatalen(struct ifqueue *ifq)
499{
500	struct mbuf *m;
501	int len = 0;
502
503	if (ifq_empty(ifq))
504		return (0);
505
506	m = ifq_deq_begin(ifq);
507	if (m != NULL) {
508		len = m->m_pkthdr.len;
509		ifq_deq_rollback(ifq, m);
510	}
511
512	return (len);
513}
514
515unsigned int
516ifq_purge(struct ifqueue *ifq)
517{
518	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
519	unsigned int rv;
520
521	mtx_enter(&ifq->ifq_mtx);
522	ifq->ifq_ops->ifqop_purge(ifq, &ml);
523	rv = ifq->ifq_len;
524	ifq->ifq_len = 0;
525	ifq->ifq_qdrops += rv;
526	mtx_leave(&ifq->ifq_mtx);
527
528	KASSERT(rv == ml_len(&ml));
529
530	ml_purge(&ml);
531
532	return (rv);
533}
534
535void *
536ifq_q_enter(struct ifqueue *ifq, const struct ifq_ops *ops)
537{
538	mtx_enter(&ifq->ifq_mtx);
539	if (ifq->ifq_ops == ops)
540		return (ifq->ifq_q);
541
542	mtx_leave(&ifq->ifq_mtx);
543
544	return (NULL);
545}
546
547void
548ifq_q_leave(struct ifqueue *ifq, void *q)
549{
550	KASSERT(q == ifq->ifq_q);
551	mtx_leave(&ifq->ifq_mtx);
552}
553
554void
555ifq_mfreem(struct ifqueue *ifq, struct mbuf *m)
556{
557	MUTEX_ASSERT_LOCKED(&ifq->ifq_mtx);
558
559	ifq->ifq_len--;
560	ifq->ifq_qdrops++;
561	ml_enqueue(&ifq->ifq_free, m);
562}
563
564void
565ifq_mfreeml(struct ifqueue *ifq, struct mbuf_list *ml)
566{
567	MUTEX_ASSERT_LOCKED(&ifq->ifq_mtx);
568
569	ifq->ifq_len -= ml_len(ml);
570	ifq->ifq_qdrops += ml_len(ml);
571	ml_enlist(&ifq->ifq_free, ml);
572}
573
574/*
575 * ifiq
576 */
577
578#if NKSTAT > 0
579struct ifiq_kstat_data {
580	struct kstat_kv kd_packets;
581	struct kstat_kv kd_bytes;
582	struct kstat_kv kd_fdrops;
583	struct kstat_kv kd_qdrops;
584	struct kstat_kv kd_errors;
585	struct kstat_kv kd_qlen;
586
587	struct kstat_kv kd_enqueues;
588	struct kstat_kv kd_dequeues;
589};
590
591static const struct ifiq_kstat_data ifiq_kstat_tpl = {
592	KSTAT_KV_UNIT_INITIALIZER("packets",
593	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
594	KSTAT_KV_UNIT_INITIALIZER("bytes",
595	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES),
596	KSTAT_KV_UNIT_INITIALIZER("fdrops",
597	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
598	KSTAT_KV_UNIT_INITIALIZER("qdrops",
599	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
600	KSTAT_KV_UNIT_INITIALIZER("errors",
601	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS),
602	KSTAT_KV_UNIT_INITIALIZER("qlen",
603	    KSTAT_KV_T_UINT32, KSTAT_KV_U_PACKETS),
604
605	KSTAT_KV_INITIALIZER("enqueues",
606	    KSTAT_KV_T_COUNTER64),
607	KSTAT_KV_INITIALIZER("dequeues",
608	    KSTAT_KV_T_COUNTER64),
609};
610
611int
612ifiq_kstat_copy(struct kstat *ks, void *dst)
613{
614	struct ifiqueue *ifiq = ks->ks_softc;
615	struct ifiq_kstat_data *kd = dst;
616
617	*kd = ifiq_kstat_tpl;
618	kstat_kv_u64(&kd->kd_packets) = ifiq->ifiq_packets;
619	kstat_kv_u64(&kd->kd_bytes) = ifiq->ifiq_bytes;
620	kstat_kv_u64(&kd->kd_fdrops) = ifiq->ifiq_fdrops;
621	kstat_kv_u64(&kd->kd_qdrops) = ifiq->ifiq_qdrops;
622	kstat_kv_u64(&kd->kd_errors) = ifiq->ifiq_errors;
623	kstat_kv_u32(&kd->kd_qlen) = ml_len(&ifiq->ifiq_ml);
624
625	kstat_kv_u64(&kd->kd_enqueues) = ifiq->ifiq_enqueues;
626	kstat_kv_u64(&kd->kd_dequeues) = ifiq->ifiq_dequeues;
627
628	return (0);
629}
630#endif
631
632static void	ifiq_process(void *);
633
634void
635ifiq_init(struct ifiqueue *ifiq, struct ifnet *ifp, unsigned int idx)
636{
637	ifiq->ifiq_if = ifp;
638	ifiq->ifiq_softnet = net_tq(ifp->if_index + idx);
639	ifiq->ifiq_softc = NULL;
640
641	mtx_init(&ifiq->ifiq_mtx, IPL_NET);
642	ml_init(&ifiq->ifiq_ml);
643	task_set(&ifiq->ifiq_task, ifiq_process, ifiq);
644	ifiq->ifiq_pressure = 0;
645
646	ifiq->ifiq_packets = 0;
647	ifiq->ifiq_bytes = 0;
648	ifiq->ifiq_fdrops = 0;
649	ifiq->ifiq_qdrops = 0;
650	ifiq->ifiq_errors = 0;
651
652	ifiq->ifiq_idx = idx;
653
654#if NKSTAT > 0
655	/* XXX xname vs driver name and unit */
656	ifiq->ifiq_kstat = kstat_create(ifp->if_xname, 0,
657	    "rxq", ifiq->ifiq_idx, KSTAT_T_KV, 0);
658	KASSERT(ifiq->ifiq_kstat != NULL);
659	kstat_set_mutex(ifiq->ifiq_kstat, &ifiq->ifiq_mtx);
660	ifiq->ifiq_kstat->ks_softc = ifiq;
661	ifiq->ifiq_kstat->ks_datalen = sizeof(ifiq_kstat_tpl);
662	ifiq->ifiq_kstat->ks_copy = ifiq_kstat_copy;
663	kstat_install(ifiq->ifiq_kstat);
664#endif
665}
666
667void
668ifiq_destroy(struct ifiqueue *ifiq)
669{
670#if NKSTAT > 0
671	kstat_destroy(ifiq->ifiq_kstat);
672#endif
673
674	NET_ASSERT_UNLOCKED();
675	if (!task_del(ifiq->ifiq_softnet, &ifiq->ifiq_task))
676		taskq_barrier(ifiq->ifiq_softnet);
677
678	/* don't need to lock because this is the last use of the ifiq */
679	ml_purge(&ifiq->ifiq_ml);
680}
681
682unsigned int ifiq_maxlen_drop = 2048 * 5;
683unsigned int ifiq_maxlen_return = 2048 * 3;
684
685int
686ifiq_input(struct ifiqueue *ifiq, struct mbuf_list *ml)
687{
688	struct ifnet *ifp = ifiq->ifiq_if;
689	struct mbuf *m;
690	uint64_t packets;
691	uint64_t bytes = 0;
692	uint64_t fdrops = 0;
693	unsigned int len;
694#if NBPFILTER > 0
695	caddr_t if_bpf;
696#endif
697
698	if (ml_empty(ml))
699		return (0);
700
701	MBUF_LIST_FOREACH(ml, m) {
702		m->m_pkthdr.ph_ifidx = ifp->if_index;
703		m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
704		bytes += m->m_pkthdr.len;
705	}
706	packets = ml_len(ml);
707
708#if NBPFILTER > 0
709	if_bpf = ifp->if_bpf;
710	if (if_bpf) {
711		struct mbuf_list ml0 = *ml;
712
713		ml_init(ml);
714
715		while ((m = ml_dequeue(&ml0)) != NULL) {
716			if ((*ifp->if_bpf_mtap)(if_bpf, m, BPF_DIRECTION_IN)) {
717				m_freem(m);
718				fdrops++;
719			} else
720				ml_enqueue(ml, m);
721		}
722
723		if (ml_empty(ml)) {
724			mtx_enter(&ifiq->ifiq_mtx);
725			ifiq->ifiq_packets += packets;
726			ifiq->ifiq_bytes += bytes;
727			ifiq->ifiq_fdrops += fdrops;
728			mtx_leave(&ifiq->ifiq_mtx);
729
730			return (0);
731		}
732	}
733#endif
734
735	mtx_enter(&ifiq->ifiq_mtx);
736	ifiq->ifiq_packets += packets;
737	ifiq->ifiq_bytes += bytes;
738	ifiq->ifiq_fdrops += fdrops;
739
740	len = ml_len(&ifiq->ifiq_ml);
741	if (__predict_true(!ISSET(ifp->if_xflags, IFXF_MONITOR))) {
742		if (len > ifiq_maxlen_drop)
743			ifiq->ifiq_qdrops += ml_len(ml);
744		else {
745			ifiq->ifiq_enqueues++;
746			ml_enlist(&ifiq->ifiq_ml, ml);
747		}
748	}
749	mtx_leave(&ifiq->ifiq_mtx);
750
751	if (ml_empty(ml))
752		task_add(ifiq->ifiq_softnet, &ifiq->ifiq_task);
753	else
754		ml_purge(ml);
755
756	return (len > ifiq_maxlen_return);
757}
758
759void
760ifiq_add_data(struct ifiqueue *ifiq, struct if_data *data)
761{
762	mtx_enter(&ifiq->ifiq_mtx);
763	data->ifi_ipackets += ifiq->ifiq_packets;
764	data->ifi_ibytes += ifiq->ifiq_bytes;
765	data->ifi_iqdrops += ifiq->ifiq_qdrops;
766	mtx_leave(&ifiq->ifiq_mtx);
767}
768
769int
770ifiq_enqueue(struct ifiqueue *ifiq, struct mbuf *m)
771{
772	struct ifnet *ifp = ifiq->ifiq_if;
773#if NBPFILTER > 0
774	caddr_t if_bpf = ifp->if_bpf;
775#endif
776
777	m->m_pkthdr.ph_ifidx = ifp->if_index;
778	m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
779
780#if NBPFILTER > 0
781	if_bpf = ifp->if_bpf;
782	if (if_bpf) {
783		if ((*ifp->if_bpf_mtap)(if_bpf, m, BPF_DIRECTION_IN)) {
784			mtx_enter(&ifiq->ifiq_mtx);
785			ifiq->ifiq_packets++;
786			ifiq->ifiq_bytes += m->m_pkthdr.len;
787			ifiq->ifiq_fdrops++;
788			mtx_leave(&ifiq->ifiq_mtx);
789
790			m_freem(m);
791			return (0);
792		}
793	}
794#endif
795
796	mtx_enter(&ifiq->ifiq_mtx);
797	ifiq->ifiq_packets++;
798	ifiq->ifiq_bytes += m->m_pkthdr.len;
799	ifiq->ifiq_enqueues++;
800	ml_enqueue(&ifiq->ifiq_ml, m);
801	mtx_leave(&ifiq->ifiq_mtx);
802
803	task_add(ifiq->ifiq_softnet, &ifiq->ifiq_task);
804
805	return (0);
806}
807
808static void
809ifiq_process(void *arg)
810{
811	struct ifiqueue *ifiq = arg;
812	struct mbuf_list ml;
813
814	if (ifiq_empty(ifiq))
815		return;
816
817	mtx_enter(&ifiq->ifiq_mtx);
818	ifiq->ifiq_dequeues++;
819	ml = ifiq->ifiq_ml;
820	ml_init(&ifiq->ifiq_ml);
821	mtx_leave(&ifiq->ifiq_mtx);
822
823	if_input_process(ifiq->ifiq_if, &ml);
824}
825
826int
827net_ifiq_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
828    void *newp, size_t newlen)
829{
830	int error = EOPNOTSUPP;
831/* pressure is disabled for 6.6-release */
832#if 0
833	int val;
834
835	if (namelen != 1)
836		return (EISDIR);
837
838	switch (name[0]) {
839	case NET_LINK_IFRXQ_PRESSURE_RETURN:
840		val = ifiq_pressure_return;
841		error = sysctl_int(oldp, oldlenp, newp, newlen, &val);
842		if (error != 0)
843			return (error);
844		if (val < 1 || val > ifiq_pressure_drop)
845			return (EINVAL);
846		ifiq_pressure_return = val;
847		break;
848	case NET_LINK_IFRXQ_PRESSURE_DROP:
849		val = ifiq_pressure_drop;
850		error = sysctl_int(oldp, oldlenp, newp, newlen, &val);
851		if (error != 0)
852			return (error);
853		if (ifiq_pressure_return > val)
854			return (EINVAL);
855		ifiq_pressure_drop = val;
856		break;
857	default:
858		error = EOPNOTSUPP;
859		break;
860	}
861#endif
862
863	return (error);
864}
865
866/*
867 * priq implementation
868 */
869
870unsigned int
871priq_idx(unsigned int nqueues, const struct mbuf *m)
872{
873	unsigned int flow = 0;
874
875	if (ISSET(m->m_pkthdr.csum_flags, M_FLOWID))
876		flow = m->m_pkthdr.ph_flowid;
877
878	return (flow % nqueues);
879}
880
881void *
882priq_alloc(unsigned int idx, void *null)
883{
884	struct priq *pq;
885	int i;
886
887	pq = malloc(sizeof(struct priq), M_DEVBUF, M_WAITOK);
888	for (i = 0; i < IFQ_NQUEUES; i++)
889		ml_init(&pq->pq_lists[i]);
890	return (pq);
891}
892
893void
894priq_free(unsigned int idx, void *pq)
895{
896	free(pq, M_DEVBUF, sizeof(struct priq));
897}
898
899struct mbuf *
900priq_enq(struct ifqueue *ifq, struct mbuf *m)
901{
902	struct priq *pq;
903	struct mbuf_list *pl;
904	struct mbuf *n = NULL;
905	unsigned int prio;
906
907	pq = ifq->ifq_q;
908	KASSERT(m->m_pkthdr.pf.prio <= IFQ_MAXPRIO);
909
910	/* Find a lower priority queue to drop from */
911	if (ifq_len(ifq) >= ifq->ifq_maxlen) {
912		for (prio = 0; prio < m->m_pkthdr.pf.prio; prio++) {
913			pl = &pq->pq_lists[prio];
914			if (ml_len(pl) > 0) {
915				n = ml_dequeue(pl);
916				goto enqueue;
917			}
918		}
919		/*
920		 * There's no lower priority queue that we can
921		 * drop from so don't enqueue this one.
922		 */
923		return (m);
924	}
925
926 enqueue:
927	pl = &pq->pq_lists[m->m_pkthdr.pf.prio];
928	ml_enqueue(pl, m);
929
930	return (n);
931}
932
933struct mbuf *
934priq_deq_begin(struct ifqueue *ifq, void **cookiep)
935{
936	struct priq *pq = ifq->ifq_q;
937	struct mbuf_list *pl;
938	unsigned int prio = nitems(pq->pq_lists);
939	struct mbuf *m;
940
941	do {
942		pl = &pq->pq_lists[--prio];
943		m = MBUF_LIST_FIRST(pl);
944		if (m != NULL) {
945			*cookiep = pl;
946			return (m);
947		}
948	} while (prio > 0);
949
950	return (NULL);
951}
952
953void
954priq_deq_commit(struct ifqueue *ifq, struct mbuf *m, void *cookie)
955{
956	struct mbuf_list *pl = cookie;
957
958	KASSERT(MBUF_LIST_FIRST(pl) == m);
959
960	ml_dequeue(pl);
961}
962
963void
964priq_purge(struct ifqueue *ifq, struct mbuf_list *ml)
965{
966	struct priq *pq = ifq->ifq_q;
967	struct mbuf_list *pl;
968	unsigned int prio = nitems(pq->pq_lists);
969
970	do {
971		pl = &pq->pq_lists[--prio];
972		ml_enlist(ml, pl);
973	} while (prio > 0);
974}
975