Line data Source code
1 : /* $OpenBSD: ifq.c,v 1.22 2018/01/25 14:04:36 mpi 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 :
21 : #include <sys/param.h>
22 : #include <sys/systm.h>
23 : #include <sys/socket.h>
24 : #include <sys/mbuf.h>
25 : #include <sys/proc.h>
26 :
27 : #include <net/if.h>
28 : #include <net/if_var.h>
29 :
30 : #if NBPFILTER > 0
31 : #include <net/bpf.h>
32 : #endif
33 :
34 : /*
35 : * priq glue
36 : */
37 : unsigned int priq_idx(unsigned int, const struct mbuf *);
38 : struct mbuf *priq_enq(struct ifqueue *, struct mbuf *);
39 : struct mbuf *priq_deq_begin(struct ifqueue *, void **);
40 : void priq_deq_commit(struct ifqueue *, struct mbuf *, void *);
41 : void priq_purge(struct ifqueue *, struct mbuf_list *);
42 :
43 : void *priq_alloc(unsigned int, void *);
44 : void priq_free(unsigned int, void *);
45 :
46 : const struct ifq_ops priq_ops = {
47 : priq_idx,
48 : priq_enq,
49 : priq_deq_begin,
50 : priq_deq_commit,
51 : priq_purge,
52 : priq_alloc,
53 : priq_free,
54 : };
55 :
56 : const struct ifq_ops * const ifq_priq_ops = &priq_ops;
57 :
58 : /*
59 : * priq internal structures
60 : */
61 :
62 : struct priq {
63 : struct mbuf_list pq_lists[IFQ_NQUEUES];
64 : };
65 :
66 : /*
67 : * ifqueue serialiser
68 : */
69 :
70 : void ifq_start_task(void *);
71 : void ifq_restart_task(void *);
72 : void ifq_barrier_task(void *);
73 :
74 : #define TASK_ONQUEUE 0x1
75 :
76 : void
77 0 : ifq_serialize(struct ifqueue *ifq, struct task *t)
78 : {
79 0 : struct task work;
80 :
81 0 : if (ISSET(t->t_flags, TASK_ONQUEUE))
82 0 : return;
83 :
84 0 : mtx_enter(&ifq->ifq_task_mtx);
85 0 : if (!ISSET(t->t_flags, TASK_ONQUEUE)) {
86 0 : SET(t->t_flags, TASK_ONQUEUE);
87 0 : TAILQ_INSERT_TAIL(&ifq->ifq_task_list, t, t_entry);
88 0 : }
89 :
90 0 : if (ifq->ifq_serializer == NULL) {
91 0 : ifq->ifq_serializer = curcpu();
92 :
93 0 : while ((t = TAILQ_FIRST(&ifq->ifq_task_list)) != NULL) {
94 0 : TAILQ_REMOVE(&ifq->ifq_task_list, t, t_entry);
95 0 : CLR(t->t_flags, TASK_ONQUEUE);
96 0 : work = *t; /* copy to caller to avoid races */
97 :
98 0 : mtx_leave(&ifq->ifq_task_mtx);
99 :
100 0 : (*work.t_func)(work.t_arg);
101 :
102 0 : mtx_enter(&ifq->ifq_task_mtx);
103 : }
104 :
105 0 : ifq->ifq_serializer = NULL;
106 0 : }
107 0 : mtx_leave(&ifq->ifq_task_mtx);
108 0 : }
109 :
110 : int
111 0 : ifq_is_serialized(struct ifqueue *ifq)
112 : {
113 0 : return (ifq->ifq_serializer == curcpu());
114 : }
115 :
116 : void
117 0 : ifq_start_task(void *p)
118 : {
119 0 : struct ifqueue *ifq = p;
120 0 : struct ifnet *ifp = ifq->ifq_if;
121 :
122 0 : if (!ISSET(ifp->if_flags, IFF_RUNNING) ||
123 0 : ifq_empty(ifq) || ifq_is_oactive(ifq))
124 0 : return;
125 :
126 0 : ifp->if_qstart(ifq);
127 0 : }
128 :
129 : void
130 0 : ifq_restart_task(void *p)
131 : {
132 0 : struct ifqueue *ifq = p;
133 0 : struct ifnet *ifp = ifq->ifq_if;
134 :
135 0 : ifq_clr_oactive(ifq);
136 0 : ifp->if_qstart(ifq);
137 0 : }
138 :
139 : void
140 0 : ifq_barrier(struct ifqueue *ifq)
141 : {
142 0 : struct cond c = COND_INITIALIZER();
143 0 : struct task t = TASK_INITIALIZER(ifq_barrier_task, &c);
144 :
145 0 : if (ifq->ifq_serializer == NULL)
146 0 : return;
147 :
148 0 : ifq_serialize(ifq, &t);
149 :
150 0 : cond_wait(&c, "ifqbar");
151 0 : }
152 :
153 : void
154 0 : ifq_barrier_task(void *p)
155 : {
156 0 : struct cond *c = p;
157 :
158 0 : cond_signal(c);
159 0 : }
160 :
161 : /*
162 : * ifqueue mbuf queue API
163 : */
164 :
165 : void
166 0 : ifq_init(struct ifqueue *ifq, struct ifnet *ifp, unsigned int idx)
167 : {
168 0 : ifq->ifq_if = ifp;
169 0 : ifq->ifq_softc = NULL;
170 :
171 0 : mtx_init(&ifq->ifq_mtx, IPL_NET);
172 0 : ifq->ifq_qdrops = 0;
173 :
174 : /* default to priq */
175 0 : ifq->ifq_ops = &priq_ops;
176 0 : ifq->ifq_q = priq_ops.ifqop_alloc(idx, NULL);
177 :
178 0 : ml_init(&ifq->ifq_free);
179 0 : ifq->ifq_len = 0;
180 :
181 0 : ifq->ifq_packets = 0;
182 0 : ifq->ifq_bytes = 0;
183 0 : ifq->ifq_qdrops = 0;
184 0 : ifq->ifq_errors = 0;
185 0 : ifq->ifq_mcasts = 0;
186 :
187 0 : mtx_init(&ifq->ifq_task_mtx, IPL_NET);
188 0 : TAILQ_INIT(&ifq->ifq_task_list);
189 0 : ifq->ifq_serializer = NULL;
190 :
191 0 : task_set(&ifq->ifq_start, ifq_start_task, ifq);
192 0 : task_set(&ifq->ifq_restart, ifq_restart_task, ifq);
193 :
194 0 : if (ifq->ifq_maxlen == 0)
195 0 : ifq_set_maxlen(ifq, IFQ_MAXLEN);
196 :
197 0 : ifq->ifq_idx = idx;
198 0 : }
199 :
200 : void
201 0 : ifq_attach(struct ifqueue *ifq, const struct ifq_ops *newops, void *opsarg)
202 : {
203 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
204 0 : struct mbuf_list free_ml = MBUF_LIST_INITIALIZER();
205 : struct mbuf *m;
206 : const struct ifq_ops *oldops;
207 : void *newq, *oldq;
208 :
209 0 : newq = newops->ifqop_alloc(ifq->ifq_idx, opsarg);
210 :
211 0 : mtx_enter(&ifq->ifq_mtx);
212 0 : ifq->ifq_ops->ifqop_purge(ifq, &ml);
213 0 : ifq->ifq_len = 0;
214 :
215 0 : oldops = ifq->ifq_ops;
216 0 : oldq = ifq->ifq_q;
217 :
218 0 : ifq->ifq_ops = newops;
219 0 : ifq->ifq_q = newq;
220 :
221 0 : while ((m = ml_dequeue(&ml)) != NULL) {
222 0 : m = ifq->ifq_ops->ifqop_enq(ifq, m);
223 0 : if (m != NULL) {
224 0 : ifq->ifq_qdrops++;
225 0 : ml_enqueue(&free_ml, m);
226 0 : } else
227 0 : ifq->ifq_len++;
228 : }
229 0 : mtx_leave(&ifq->ifq_mtx);
230 :
231 0 : oldops->ifqop_free(ifq->ifq_idx, oldq);
232 :
233 0 : ml_purge(&free_ml);
234 0 : }
235 :
236 : void
237 0 : ifq_destroy(struct ifqueue *ifq)
238 : {
239 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
240 :
241 : /* don't need to lock because this is the last use of the ifq */
242 :
243 0 : ifq->ifq_ops->ifqop_purge(ifq, &ml);
244 0 : ifq->ifq_ops->ifqop_free(ifq->ifq_idx, ifq->ifq_q);
245 :
246 0 : ml_purge(&ml);
247 0 : }
248 :
249 : void
250 0 : ifq_add_data(struct ifqueue *ifq, struct if_data *data)
251 : {
252 0 : mtx_enter(&ifq->ifq_mtx);
253 0 : data->ifi_opackets += ifq->ifq_packets;
254 0 : data->ifi_obytes += ifq->ifq_bytes;
255 0 : data->ifi_oqdrops += ifq->ifq_qdrops;
256 0 : data->ifi_omcasts += ifq->ifq_mcasts;
257 : /* ifp->if_data.ifi_oerrors */
258 0 : mtx_leave(&ifq->ifq_mtx);
259 0 : }
260 :
261 : int
262 0 : ifq_enqueue(struct ifqueue *ifq, struct mbuf *m)
263 : {
264 : struct mbuf *dm;
265 :
266 0 : mtx_enter(&ifq->ifq_mtx);
267 0 : dm = ifq->ifq_ops->ifqop_enq(ifq, m);
268 0 : if (dm != m) {
269 0 : ifq->ifq_packets++;
270 0 : ifq->ifq_bytes += m->m_pkthdr.len;
271 0 : if (ISSET(m->m_flags, M_MCAST))
272 0 : ifq->ifq_mcasts++;
273 : }
274 :
275 0 : if (dm == NULL)
276 0 : ifq->ifq_len++;
277 : else
278 0 : ifq->ifq_qdrops++;
279 0 : mtx_leave(&ifq->ifq_mtx);
280 :
281 0 : if (dm != NULL)
282 0 : m_freem(dm);
283 :
284 0 : return (dm == m ? ENOBUFS : 0);
285 : }
286 :
287 : static inline void
288 0 : ifq_deq_enter(struct ifqueue *ifq)
289 : {
290 0 : mtx_enter(&ifq->ifq_mtx);
291 0 : }
292 :
293 : static inline void
294 0 : ifq_deq_leave(struct ifqueue *ifq)
295 : {
296 0 : struct mbuf_list ml;
297 :
298 0 : ml = ifq->ifq_free;
299 0 : ml_init(&ifq->ifq_free);
300 :
301 0 : mtx_leave(&ifq->ifq_mtx);
302 :
303 0 : if (!ml_empty(&ml))
304 0 : ml_purge(&ml);
305 0 : }
306 :
307 : struct mbuf *
308 0 : ifq_deq_begin(struct ifqueue *ifq)
309 : {
310 : struct mbuf *m = NULL;
311 0 : void *cookie;
312 :
313 0 : ifq_deq_enter(ifq);
314 0 : if (ifq->ifq_len == 0 ||
315 0 : (m = ifq->ifq_ops->ifqop_deq_begin(ifq, &cookie)) == NULL) {
316 0 : ifq_deq_leave(ifq);
317 0 : return (NULL);
318 : }
319 :
320 0 : m->m_pkthdr.ph_cookie = cookie;
321 :
322 0 : return (m);
323 0 : }
324 :
325 : void
326 0 : ifq_deq_commit(struct ifqueue *ifq, struct mbuf *m)
327 : {
328 : void *cookie;
329 :
330 0 : KASSERT(m != NULL);
331 0 : cookie = m->m_pkthdr.ph_cookie;
332 :
333 0 : ifq->ifq_ops->ifqop_deq_commit(ifq, m, cookie);
334 0 : ifq->ifq_len--;
335 0 : ifq_deq_leave(ifq);
336 0 : }
337 :
338 : void
339 0 : ifq_deq_rollback(struct ifqueue *ifq, struct mbuf *m)
340 : {
341 0 : KASSERT(m != NULL);
342 :
343 0 : ifq_deq_leave(ifq);
344 0 : }
345 :
346 : struct mbuf *
347 0 : ifq_dequeue(struct ifqueue *ifq)
348 : {
349 : struct mbuf *m;
350 :
351 0 : m = ifq_deq_begin(ifq);
352 0 : if (m == NULL)
353 0 : return (NULL);
354 :
355 0 : ifq_deq_commit(ifq, m);
356 :
357 0 : return (m);
358 0 : }
359 :
360 : unsigned int
361 0 : ifq_purge(struct ifqueue *ifq)
362 : {
363 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
364 : unsigned int rv;
365 :
366 0 : mtx_enter(&ifq->ifq_mtx);
367 0 : ifq->ifq_ops->ifqop_purge(ifq, &ml);
368 0 : rv = ifq->ifq_len;
369 0 : ifq->ifq_len = 0;
370 0 : ifq->ifq_qdrops += rv;
371 0 : mtx_leave(&ifq->ifq_mtx);
372 :
373 0 : KASSERT(rv == ml_len(&ml));
374 :
375 0 : ml_purge(&ml);
376 :
377 0 : return (rv);
378 0 : }
379 :
380 : void *
381 0 : ifq_q_enter(struct ifqueue *ifq, const struct ifq_ops *ops)
382 : {
383 0 : mtx_enter(&ifq->ifq_mtx);
384 0 : if (ifq->ifq_ops == ops)
385 0 : return (ifq->ifq_q);
386 :
387 0 : mtx_leave(&ifq->ifq_mtx);
388 :
389 0 : return (NULL);
390 0 : }
391 :
392 : void
393 0 : ifq_q_leave(struct ifqueue *ifq, void *q)
394 : {
395 0 : KASSERT(q == ifq->ifq_q);
396 0 : mtx_leave(&ifq->ifq_mtx);
397 0 : }
398 :
399 : void
400 0 : ifq_mfreem(struct ifqueue *ifq, struct mbuf *m)
401 : {
402 0 : MUTEX_ASSERT_LOCKED(&ifq->ifq_mtx);
403 :
404 0 : ifq->ifq_len--;
405 0 : ifq->ifq_qdrops++;
406 0 : ml_enqueue(&ifq->ifq_free, m);
407 0 : }
408 :
409 : void
410 0 : ifq_mfreeml(struct ifqueue *ifq, struct mbuf_list *ml)
411 : {
412 0 : MUTEX_ASSERT_LOCKED(&ifq->ifq_mtx);
413 :
414 0 : ifq->ifq_len -= ml_len(ml);
415 0 : ifq->ifq_qdrops += ml_len(ml);
416 0 : ml_enlist(&ifq->ifq_free, ml);
417 0 : }
418 :
419 : /*
420 : * ifiq
421 : */
422 :
423 : static void ifiq_process(void *);
424 :
425 : void
426 0 : ifiq_init(struct ifiqueue *ifiq, struct ifnet *ifp, unsigned int idx)
427 : {
428 0 : ifiq->ifiq_if = ifp;
429 0 : ifiq->ifiq_softnet = net_tq(ifp->if_index); /* + idx */
430 0 : ifiq->ifiq_softc = NULL;
431 :
432 0 : mtx_init(&ifiq->ifiq_mtx, IPL_NET);
433 0 : ml_init(&ifiq->ifiq_ml);
434 0 : task_set(&ifiq->ifiq_task, ifiq_process, ifiq);
435 :
436 0 : ifiq->ifiq_qdrops = 0;
437 0 : ifiq->ifiq_packets = 0;
438 0 : ifiq->ifiq_bytes = 0;
439 0 : ifiq->ifiq_qdrops = 0;
440 0 : ifiq->ifiq_errors = 0;
441 :
442 0 : ifiq->ifiq_idx = idx;
443 0 : }
444 :
445 : void
446 0 : ifiq_destroy(struct ifiqueue *ifiq)
447 : {
448 0 : if (!task_del(ifiq->ifiq_softnet, &ifiq->ifiq_task)) {
449 0 : NET_ASSERT_UNLOCKED();
450 0 : taskq_barrier(ifiq->ifiq_softnet);
451 0 : }
452 :
453 : /* don't need to lock because this is the last use of the ifiq */
454 0 : ml_purge(&ifiq->ifiq_ml);
455 0 : }
456 :
457 : int
458 0 : ifiq_input(struct ifiqueue *ifiq, struct mbuf_list *ml, unsigned int cwm)
459 : {
460 0 : struct ifnet *ifp = ifiq->ifiq_if;
461 : struct mbuf *m;
462 : uint64_t packets;
463 : uint64_t bytes = 0;
464 : #if NBPFILTER > 0
465 : caddr_t if_bpf;
466 : #endif
467 : int rv = 1;
468 :
469 0 : if (ml_empty(ml))
470 0 : return (0);
471 :
472 0 : MBUF_LIST_FOREACH(ml, m) {
473 0 : m->m_pkthdr.ph_ifidx = ifp->if_index;
474 0 : m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
475 0 : bytes += m->m_pkthdr.len;
476 : }
477 0 : packets = ml_len(ml);
478 :
479 : #if NBPFILTER > 0
480 0 : if_bpf = ifp->if_bpf;
481 0 : if (if_bpf) {
482 0 : struct mbuf_list ml0 = *ml;
483 :
484 0 : ml_init(ml);
485 :
486 0 : while ((m = ml_dequeue(&ml0)) != NULL) {
487 0 : if (bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_IN))
488 0 : m_freem(m);
489 : else
490 0 : ml_enqueue(ml, m);
491 : }
492 :
493 0 : if (ml_empty(ml)) {
494 0 : mtx_enter(&ifiq->ifiq_mtx);
495 0 : ifiq->ifiq_packets += packets;
496 0 : ifiq->ifiq_bytes += bytes;
497 0 : mtx_leave(&ifiq->ifiq_mtx);
498 :
499 0 : return (0);
500 : }
501 0 : }
502 : #endif
503 :
504 0 : mtx_enter(&ifiq->ifiq_mtx);
505 0 : ifiq->ifiq_packets += packets;
506 0 : ifiq->ifiq_bytes += bytes;
507 :
508 0 : if (ifiq_len(ifiq) >= cwm * 5)
509 0 : ifiq->ifiq_qdrops += ml_len(ml);
510 : else {
511 0 : rv = (ifiq_len(ifiq) >= cwm * 3);
512 0 : ml_enlist(&ifiq->ifiq_ml, ml);
513 : }
514 0 : mtx_leave(&ifiq->ifiq_mtx);
515 :
516 0 : if (ml_empty(ml))
517 0 : task_add(ifiq->ifiq_softnet, &ifiq->ifiq_task);
518 : else
519 0 : ml_purge(ml);
520 :
521 0 : return (rv);
522 0 : }
523 :
524 : void
525 0 : ifiq_add_data(struct ifiqueue *ifiq, struct if_data *data)
526 : {
527 0 : mtx_enter(&ifiq->ifiq_mtx);
528 0 : data->ifi_ipackets += ifiq->ifiq_packets;
529 0 : data->ifi_ibytes += ifiq->ifiq_bytes;
530 0 : data->ifi_iqdrops += ifiq->ifiq_qdrops;
531 0 : mtx_leave(&ifiq->ifiq_mtx);
532 0 : }
533 :
534 : void
535 0 : ifiq_barrier(struct ifiqueue *ifiq)
536 : {
537 0 : if (!task_del(ifiq->ifiq_softnet, &ifiq->ifiq_task))
538 0 : taskq_barrier(ifiq->ifiq_softnet);
539 0 : }
540 :
541 : int
542 0 : ifiq_enqueue(struct ifiqueue *ifiq, struct mbuf *m)
543 : {
544 0 : mtx_enter(&ifiq->ifiq_mtx);
545 0 : ml_enqueue(&ifiq->ifiq_ml, m);
546 0 : mtx_leave(&ifiq->ifiq_mtx);
547 :
548 0 : task_add(ifiq->ifiq_softnet, &ifiq->ifiq_task);
549 :
550 0 : return (0);
551 : }
552 :
553 : static void
554 0 : ifiq_process(void *arg)
555 : {
556 0 : struct ifiqueue *ifiq = arg;
557 0 : struct mbuf_list ml;
558 :
559 0 : if (ifiq_empty(ifiq))
560 0 : return;
561 :
562 0 : mtx_enter(&ifiq->ifiq_mtx);
563 0 : ml = ifiq->ifiq_ml;
564 0 : ml_init(&ifiq->ifiq_ml);
565 0 : mtx_leave(&ifiq->ifiq_mtx);
566 :
567 0 : if_input_process(ifiq->ifiq_if, &ml);
568 0 : }
569 :
570 : /*
571 : * priq implementation
572 : */
573 :
574 : unsigned int
575 0 : priq_idx(unsigned int nqueues, const struct mbuf *m)
576 : {
577 : unsigned int flow = 0;
578 :
579 0 : if (ISSET(m->m_pkthdr.ph_flowid, M_FLOWID_VALID))
580 0 : flow = m->m_pkthdr.ph_flowid & M_FLOWID_MASK;
581 :
582 0 : return (flow % nqueues);
583 : }
584 :
585 : void *
586 0 : priq_alloc(unsigned int idx, void *null)
587 : {
588 : struct priq *pq;
589 : int i;
590 :
591 0 : pq = malloc(sizeof(struct priq), M_DEVBUF, M_WAITOK);
592 0 : for (i = 0; i < IFQ_NQUEUES; i++)
593 0 : ml_init(&pq->pq_lists[i]);
594 0 : return (pq);
595 : }
596 :
597 : void
598 0 : priq_free(unsigned int idx, void *pq)
599 : {
600 0 : free(pq, M_DEVBUF, sizeof(struct priq));
601 0 : }
602 :
603 : struct mbuf *
604 0 : priq_enq(struct ifqueue *ifq, struct mbuf *m)
605 : {
606 : struct priq *pq;
607 : struct mbuf_list *pl;
608 : struct mbuf *n = NULL;
609 : unsigned int prio;
610 :
611 0 : pq = ifq->ifq_q;
612 0 : KASSERT(m->m_pkthdr.pf.prio <= IFQ_MAXPRIO);
613 :
614 : /* Find a lower priority queue to drop from */
615 0 : if (ifq_len(ifq) >= ifq->ifq_maxlen) {
616 0 : for (prio = 0; prio < m->m_pkthdr.pf.prio; prio++) {
617 0 : pl = &pq->pq_lists[prio];
618 0 : if (ml_len(pl) > 0) {
619 0 : n = ml_dequeue(pl);
620 0 : goto enqueue;
621 : }
622 : }
623 : /*
624 : * There's no lower priority queue that we can
625 : * drop from so don't enqueue this one.
626 : */
627 0 : return (m);
628 : }
629 :
630 : enqueue:
631 0 : pl = &pq->pq_lists[m->m_pkthdr.pf.prio];
632 0 : ml_enqueue(pl, m);
633 :
634 0 : return (n);
635 0 : }
636 :
637 : struct mbuf *
638 0 : priq_deq_begin(struct ifqueue *ifq, void **cookiep)
639 : {
640 0 : struct priq *pq = ifq->ifq_q;
641 : struct mbuf_list *pl;
642 : unsigned int prio = nitems(pq->pq_lists);
643 : struct mbuf *m;
644 :
645 0 : do {
646 0 : pl = &pq->pq_lists[--prio];
647 0 : m = MBUF_LIST_FIRST(pl);
648 0 : if (m != NULL) {
649 0 : *cookiep = pl;
650 0 : return (m);
651 : }
652 0 : } while (prio > 0);
653 :
654 0 : return (NULL);
655 0 : }
656 :
657 : void
658 0 : priq_deq_commit(struct ifqueue *ifq, struct mbuf *m, void *cookie)
659 : {
660 0 : struct mbuf_list *pl = cookie;
661 :
662 0 : KASSERT(MBUF_LIST_FIRST(pl) == m);
663 :
664 0 : ml_dequeue(pl);
665 0 : }
666 :
667 : void
668 0 : priq_purge(struct ifqueue *ifq, struct mbuf_list *ml)
669 : {
670 0 : struct priq *pq = ifq->ifq_q;
671 : struct mbuf_list *pl;
672 : unsigned int prio = nitems(pq->pq_lists);
673 :
674 0 : do {
675 0 : pl = &pq->pq_lists[--prio];
676 0 : ml_enlist(ml, pl);
677 0 : } while (prio > 0);
678 0 : }
|