altq_priq.c revision 1.1 1 /* $KAME: altq_priq.c,v 1.1 2000/10/18 09:15:23 kjc Exp $ */
2 /*
3 * Copyright (C) 2000
4 * Sony Computer Science Laboratories Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27 /*
28 * priority queue
29 */
30
31 #if defined(__FreeBSD__) || defined(__NetBSD__)
32 #include "opt_altq.h"
33 #if (__FreeBSD__ != 2)
34 #include "opt_inet.h"
35 #ifdef __FreeBSD__
36 #include "opt_inet6.h"
37 #endif
38 #endif
39 #endif /* __FreeBSD__ || __NetBSD__ */
40
41 #ifdef ALTQ_PRIQ /* priq is enabled by ALTQ_PRIQ option in opt_altq.h */
42
43 #include <sys/param.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
48 #include <sys/systm.h>
49 #include <sys/proc.h>
50 #include <sys/errno.h>
51 #include <sys/kernel.h>
52 #include <sys/queue.h>
53
54 #include <net/if.h>
55 #include <net/if_types.h>
56
57 #include <altq/altq.h>
58 #include <altq/altq_conf.h>
59 #include <altq/altq_priq.h>
60
61 /*
62 * function prototypes
63 */
64 static struct priq_if *priq_attach __P((struct ifaltq *, u_int));
65 static int priq_detach __P((struct priq_if *));
66 static int priq_clear_interface __P((struct priq_if *));
67 static int priq_request __P((struct ifaltq *, int, void *));
68 static void priq_purge __P((struct priq_if *));
69 static struct priq_class *priq_class_create __P((struct priq_if *,
70 int, int, int));
71 static int priq_class_destroy __P((struct priq_class *));
72 static int priq_enqueue __P((struct ifaltq *, struct mbuf *,
73 struct altq_pktattr *));
74 static struct mbuf *priq_dequeue __P((struct ifaltq *, int));
75
76 static int priq_addq __P((struct priq_class *, struct mbuf *));
77 static struct mbuf *priq_getq __P((struct priq_class *));
78 static struct mbuf *priq_pollq __P((struct priq_class *));
79 static void priq_purgeq __P((struct priq_class *));
80
81 int priqopen __P((dev_t, int, int, struct proc *));
82 int priqclose __P((dev_t, int, int, struct proc *));
83 int priqioctl __P((dev_t, ioctlcmd_t, caddr_t, int, struct proc *));
84 static int priqcmd_if_attach __P((struct priq_interface *));
85 static int priqcmd_if_detach __P((struct priq_interface *));
86 static int priqcmd_add_class __P((struct priq_add_class *));
87 static int priqcmd_delete_class __P((struct priq_delete_class *));
88 static int priqcmd_modify_class __P((struct priq_modify_class *));
89 static int priqcmd_add_filter __P((struct priq_add_filter *));
90 static int priqcmd_delete_filter __P((struct priq_delete_filter *));
91 static int priqcmd_class_stats __P((struct priq_class_stats *));
92 static void get_class_stats __P((struct class_stats *, struct priq_class *));
93 static struct priq_class *clh_to_clp __P((struct priq_if *, u_long));
94 static u_long clp_to_clh __P((struct priq_class *));
95
96 /* pif_list keeps all priq_if's allocated. */
97 static struct priq_if *pif_list = NULL;
98
99 static struct priq_if *
100 priq_attach(ifq, bandwidth)
101 struct ifaltq *ifq;
102 u_int bandwidth;
103 {
104 struct priq_if *pif;
105
106 MALLOC(pif, struct priq_if *, sizeof(struct priq_if),
107 M_DEVBUF, M_WAITOK);
108 if (pif == NULL)
109 return (NULL);
110 bzero(pif, sizeof(struct priq_if));
111 pif->pif_bandwidth = bandwidth;
112 pif->pif_maxpri = -1;
113 pif->pif_ifq = ifq;
114
115 /* add this state to the priq list */
116 pif->pif_next = pif_list;
117 pif_list = pif;
118
119 return (pif);
120 }
121
122 static int
123 priq_detach(pif)
124 struct priq_if *pif;
125 {
126 (void)priq_clear_interface(pif);
127
128 /* remove this interface from the pif list */
129 if (pif_list == pif)
130 pif_list = pif->pif_next;
131 else {
132 struct priq_if *p;
133
134 for (p = pif_list; p != NULL; p = p->pif_next)
135 if (p->pif_next == pif) {
136 p->pif_next = pif->pif_next;
137 break;
138 }
139 ASSERT(p != NULL);
140 }
141
142 FREE(pif, M_DEVBUF);
143 return (0);
144 }
145
146 /*
147 * bring the interface back to the initial state by discarding
148 * all the filters and classes.
149 */
150 static int
151 priq_clear_interface(pif)
152 struct priq_if *pif;
153 {
154 struct priq_class *cl;
155 int pri;
156
157 /* free the filters for this interface */
158 acc_discard_filters(&pif->pif_classifier, NULL, 1);
159
160 /* clear out the classes */
161 for (pri = 0; pri <= pif->pif_maxpri; pri++)
162 if ((cl = pif->pif_classes[pri]) != NULL)
163 priq_class_destroy(cl);
164
165 return (0);
166 }
167
168 static int
169 priq_request(ifq, req, arg)
170 struct ifaltq *ifq;
171 int req;
172 void *arg;
173 {
174 struct priq_if *pif = (struct priq_if *)ifq->altq_disc;
175
176 switch (req) {
177 case ALTRQ_PURGE:
178 priq_purge(pif);
179 break;
180 }
181 return (0);
182 }
183
184 /* discard all the queued packets on the interface */
185 static void
186 priq_purge(pif)
187 struct priq_if *pif;
188 {
189 struct priq_class *cl;
190 int pri;
191
192 for (pri = 0; pri <= pif->pif_maxpri; pri++) {
193 if ((cl = pif->pif_classes[pri]) != NULL && !qempty(cl->cl_q))
194 priq_purgeq(cl);
195 }
196 if (ALTQ_IS_ENABLED(pif->pif_ifq))
197 pif->pif_ifq->ifq_len = 0;
198 }
199
200 static struct priq_class *
201 priq_class_create(pif, pri, qlimit, flags)
202 struct priq_if *pif;
203 int pri, qlimit, flags;
204 {
205 struct priq_class *cl;
206 int s;
207
208 #ifndef ALTQ_RED
209 if (flags & PRCF_RED) {
210 printf("priq_class_create: RED not configured for PRIQ!\n");
211 return (NULL);
212 }
213 #endif
214
215 if ((cl = pif->pif_classes[pri]) != NULL) {
216 /* modify the class instead of creating a new one */
217 s = splimp();
218 if (!qempty(cl->cl_q))
219 priq_purgeq(cl);
220 splx(s);
221 #ifdef ALTQ_RIO
222 if (q_is_rio(cl->cl_q))
223 rio_destroy((rio_t *)cl->cl_red);
224 #endif
225 #ifdef ALTQ_RED
226 if (q_is_red(cl->cl_q))
227 red_destroy(cl->cl_red);
228 #endif
229 } else {
230 MALLOC(cl, struct priq_class *, sizeof(struct priq_class),
231 M_DEVBUF, M_WAITOK);
232 if (cl == NULL)
233 return (NULL);
234 bzero(cl, sizeof(struct priq_class));
235
236 MALLOC(cl->cl_q, class_queue_t *, sizeof(class_queue_t),
237 M_DEVBUF, M_WAITOK);
238 if (cl->cl_q == NULL)
239 goto err_ret;
240 bzero(cl->cl_q, sizeof(class_queue_t));
241 }
242
243 pif->pif_classes[pri] = cl;
244 if (flags & PRCF_DEFAULTCLASS)
245 pif->pif_default = cl;
246 if (qlimit == 0)
247 qlimit = 50; /* use default */
248 qlimit(cl->cl_q) = qlimit;
249 qtype(cl->cl_q) = Q_DROPTAIL;
250 qlen(cl->cl_q) = 0;
251 cl->cl_flags = flags;
252 cl->cl_pri = pri;
253 if (pri > pif->pif_maxpri)
254 pif->pif_maxpri = pri;
255 cl->cl_pif = pif;
256 cl->cl_handle = (u_long)cl; /* XXX: just a pointer to this class */
257
258 #ifdef ALTQ_RED
259 if (flags & (PRCF_RED|PRCF_RIO)) {
260 int red_flags, red_pkttime;
261
262 red_flags = 0;
263 if (flags & PRCF_ECN)
264 red_flags |= REDF_ECN;
265 #ifdef ALTQ_RIO
266 if (flags & PRCF_CLEARDSCP)
267 red_flags |= RIOF_CLEARDSCP;
268 #endif
269 if (pif->pif_bandwidth == 0)
270 red_pkttime = 1000 * 1000 * 1000; /* 1 sec */
271 else
272 red_pkttime = (int64_t)pif->pif_ifq->altq_ifp->if_mtu
273 * 1000 * 1000 * 1000 / (pif->pif_bandwidth / 8);
274 #ifdef ALTQ_RIO
275 if (flags & PRCF_RIO) {
276 cl->cl_red = (red_t *)rio_alloc(0, NULL,
277 red_flags, red_pkttime);
278 if (cl->cl_red != NULL)
279 qtype(cl->cl_q) = Q_RIO;
280 } else
281 #endif
282 if (flags & PRCF_RED) {
283 cl->cl_red = red_alloc(0, 0, 0, 0,
284 red_flags, red_pkttime);
285 if (cl->cl_red != NULL)
286 qtype(cl->cl_q) = Q_RED;
287 }
288 }
289 #endif /* ALTQ_RED */
290
291 return (cl);
292
293 err_ret:
294 if (cl->cl_red != NULL) {
295 #ifdef ALTQ_RIO
296 if (q_is_rio(cl->cl_q))
297 rio_destroy((rio_t *)cl->cl_red);
298 #endif
299 #ifdef ALTQ_RED
300 if (q_is_red(cl->cl_q))
301 red_destroy(cl->cl_red);
302 #endif
303 }
304 if (cl->cl_q != NULL)
305 FREE(cl->cl_q, M_DEVBUF);
306 FREE(cl, M_DEVBUF);
307 return (NULL);
308 }
309
310 static int
311 priq_class_destroy(cl)
312 struct priq_class *cl;
313 {
314 struct priq_if *pif;
315 int s, pri;
316
317 s = splimp();
318
319 /* delete filters referencing to this class */
320 acc_discard_filters(&cl->cl_pif->pif_classifier, cl, 0);
321
322 if (!qempty(cl->cl_q))
323 priq_purgeq(cl);
324
325 pif = cl->cl_pif;
326 pif->pif_classes[cl->cl_pri] = NULL;
327 if (pif->pif_maxpri == cl->cl_pri) {
328 for (pri = cl->cl_pri; pri >= 0; pri--)
329 if (pif->pif_classes[pri] != NULL) {
330 pif->pif_maxpri = pri;
331 break;
332 }
333 if (pri < 0)
334 pif->pif_maxpri = -1;
335 }
336 splx(s);
337
338 if (cl->cl_red != NULL) {
339 #ifdef ALTQ_RIO
340 if (q_is_rio(cl->cl_q))
341 rio_destroy((rio_t *)cl->cl_red);
342 #endif
343 #ifdef ALTQ_RED
344 if (q_is_red(cl->cl_q))
345 red_destroy(cl->cl_red);
346 #endif
347 }
348 FREE(cl->cl_q, M_DEVBUF);
349 FREE(cl, M_DEVBUF);
350 return (0);
351 }
352
353 /*
354 * priq_enqueue is an enqueue function to be registered to
355 * (*altq_enqueue) in struct ifaltq.
356 */
357 static int
358 priq_enqueue(ifq, m, pktattr)
359 struct ifaltq *ifq;
360 struct mbuf *m;
361 struct altq_pktattr *pktattr;
362 {
363 struct priq_if *pif = (struct priq_if *)ifq->altq_disc;
364 struct priq_class *cl;
365 int len;
366
367 /* grab class set by classifier */
368 if (pktattr == NULL || (cl = pktattr->pattr_class) == NULL)
369 cl = pif->pif_default;
370 cl->cl_pktattr = pktattr; /* save proto hdr used by ECN */
371
372 len = m_pktlen(m);
373 if (priq_addq(cl, m) != 0) {
374 /* drop occurred. mbuf was freed in priq_addq. */
375 PKTCNTR_ADD(&cl->cl_dropcnt, len);
376 return (ENOBUFS);
377 }
378 IFQ_INC_LEN(ifq);
379
380 /* successfully queued. */
381 return (0);
382 }
383
384 /*
385 * priq_dequeue is a dequeue function to be registered to
386 * (*altq_dequeue) in struct ifaltq.
387 *
388 * note: ALTDQ_POLL returns the next packet without removing the packet
389 * from the queue. ALTDQ_REMOVE is a normal dequeue operation.
390 * ALTDQ_REMOVE must return the same packet if called immediately
391 * after ALTDQ_POLL.
392 */
393 static struct mbuf *
394 priq_dequeue(ifq, op)
395 struct ifaltq *ifq;
396 int op;
397 {
398 struct priq_if *pif = (struct priq_if *)ifq->altq_disc;
399 struct priq_class *cl;
400 struct mbuf *m;
401 int pri;
402
403 if (IFQ_IS_EMPTY(ifq))
404 /* no packet in the queue */
405 return (NULL);
406
407 for (pri = pif->pif_maxpri; pri >= 0; pri--) {
408 if ((cl = pif->pif_classes[pri]) != NULL &&
409 !qempty(cl->cl_q)) {
410 if (op == ALTDQ_POLL)
411 return (priq_pollq(cl));
412
413 m = priq_getq(cl);
414 if (m != NULL) {
415 IFQ_DEC_LEN(ifq);
416 if (qempty(cl->cl_q))
417 cl->cl_period++;
418 PKTCNTR_ADD(&cl->cl_xmitcnt, m_pktlen(m));
419 }
420 return (m);
421 }
422 }
423 return (NULL);
424 }
425
426 static int
427 priq_addq(cl, m)
428 struct priq_class *cl;
429 struct mbuf *m;
430 {
431
432 #ifdef ALTQ_RIO
433 if (q_is_rio(cl->cl_q))
434 return rio_addq((rio_t *)cl->cl_red, cl->cl_q, m,
435 cl->cl_pktattr);
436 #endif
437 #ifdef ALTQ_RED
438 if (q_is_red(cl->cl_q))
439 return red_addq(cl->cl_red, cl->cl_q, m, cl->cl_pktattr);
440 #endif
441 if (qlen(cl->cl_q) >= qlimit(cl->cl_q)) {
442 m_freem(m);
443 return (-1);
444 }
445
446 if (cl->cl_flags & PRCF_CLEARDSCP)
447 write_dsfield(m, cl->cl_pktattr, 0);
448
449 _addq(cl->cl_q, m);
450
451 return (0);
452 }
453
454 static struct mbuf *
455 priq_getq(cl)
456 struct priq_class *cl;
457 {
458 #ifdef ALTQ_RIO
459 if (q_is_rio(cl->cl_q))
460 return rio_getq((rio_t *)cl->cl_red, cl->cl_q);
461 #endif
462 #ifdef ALTQ_RED
463 if (q_is_red(cl->cl_q))
464 return red_getq(cl->cl_red, cl->cl_q);
465 #endif
466 return _getq(cl->cl_q);
467 }
468
469 static struct mbuf *
470 priq_pollq(cl)
471 struct priq_class *cl;
472 {
473 return qhead(cl->cl_q);
474 }
475
476 static void
477 priq_purgeq(cl)
478 struct priq_class *cl;
479 {
480 struct mbuf *m;
481
482 if (qempty(cl->cl_q))
483 return;
484
485 while ((m = _getq(cl->cl_q)) != NULL) {
486 PKTCNTR_ADD(&cl->cl_dropcnt, m_pktlen(m));
487 m_freem(m);
488 }
489 ASSERT(qlen(cl->cl_q) == 0);
490 }
491
492 /*
493 * priq device interface
494 */
495 int
496 priqopen(dev, flag, fmt, p)
497 dev_t dev;
498 int flag, fmt;
499 struct proc *p;
500 {
501 /* everything will be done when the queueing scheme is attached. */
502 return 0;
503 }
504
505 int
506 priqclose(dev, flag, fmt, p)
507 dev_t dev;
508 int flag, fmt;
509 struct proc *p;
510 {
511 struct priq_if *pif;
512 int err, error = 0;
513
514 while ((pif = pif_list) != NULL) {
515 /* destroy all */
516 if (ALTQ_IS_ENABLED(pif->pif_ifq))
517 altq_disable(pif->pif_ifq);
518
519 err = altq_detach(pif->pif_ifq);
520 if (err == 0)
521 err = priq_detach(pif);
522 if (err != 0 && error == 0)
523 error = err;
524 }
525
526 return error;
527 }
528
529 int
530 priqioctl(dev, cmd, addr, flag, p)
531 dev_t dev;
532 ioctlcmd_t cmd;
533 caddr_t addr;
534 int flag;
535 struct proc *p;
536 {
537 struct priq_if *pif;
538 struct priq_interface *ifacep;
539 int error = 0;
540
541 /* check super-user privilege */
542 switch (cmd) {
543 case PRIQ_GETSTATS:
544 break;
545 default:
546 #if (__FreeBSD_version > 400000)
547 if ((error = suser(p)) != 0)
548 return (error);
549 #else
550 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
551 return (error);
552 #endif
553 break;
554 }
555
556 switch (cmd) {
557
558 case PRIQ_IF_ATTACH:
559 error = priqcmd_if_attach((struct priq_interface *)addr);
560 break;
561
562 case PRIQ_IF_DETACH:
563 error = priqcmd_if_detach((struct priq_interface *)addr);
564 break;
565
566 case PRIQ_ENABLE:
567 case PRIQ_DISABLE:
568 case PRIQ_CLEAR:
569 ifacep = (struct priq_interface *)addr;
570 if ((pif = altq_lookup(ifacep->ifname,
571 ALTQT_PRIQ)) == NULL) {
572 error = EBADF;
573 break;
574 }
575
576 switch (cmd) {
577 case PRIQ_ENABLE:
578 if (pif->pif_default == NULL) {
579 #if 1
580 printf("priq: no default class\n");
581 #endif
582 error = EINVAL;
583 break;
584 }
585 error = altq_enable(pif->pif_ifq);
586 break;
587
588 case PRIQ_DISABLE:
589 error = altq_disable(pif->pif_ifq);
590 break;
591
592 case PRIQ_CLEAR:
593 priq_clear_interface(pif);
594 break;
595 }
596 break;
597
598 case PRIQ_ADD_CLASS:
599 error = priqcmd_add_class((struct priq_add_class *)addr);
600 break;
601
602 case PRIQ_DEL_CLASS:
603 error = priqcmd_delete_class((struct priq_delete_class *)addr);
604 break;
605
606 case PRIQ_MOD_CLASS:
607 error = priqcmd_modify_class((struct priq_modify_class *)addr);
608 break;
609
610 case PRIQ_ADD_FILTER:
611 error = priqcmd_add_filter((struct priq_add_filter *)addr);
612 break;
613
614 case PRIQ_DEL_FILTER:
615 error = priqcmd_delete_filter((struct priq_delete_filter *)addr);
616 break;
617
618 case PRIQ_GETSTATS:
619 error = priqcmd_class_stats((struct priq_class_stats *)addr);
620 break;
621
622 default:
623 error = EINVAL;
624 break;
625 }
626 return error;
627 }
628
629 static int
630 priqcmd_if_attach(ap)
631 struct priq_interface *ap;
632 {
633 struct priq_if *pif;
634 struct ifnet *ifp;
635 int error;
636
637 if ((ifp = ifunit(ap->ifname)) == NULL)
638 return (ENXIO);
639
640 if ((pif = priq_attach(&ifp->if_snd, ap->arg)) == NULL)
641 return (ENOMEM);
642
643 /*
644 * set PRIQ to this ifnet structure.
645 */
646 if ((error = altq_attach(&ifp->if_snd, ALTQT_PRIQ, pif,
647 priq_enqueue, priq_dequeue, priq_request,
648 &pif->pif_classifier, acc_classify)) != 0)
649 (void)priq_detach(pif);
650
651 return (error);
652 }
653
654 static int
655 priqcmd_if_detach(ap)
656 struct priq_interface *ap;
657 {
658 struct priq_if *pif;
659 int error;
660
661 if ((pif = altq_lookup(ap->ifname, ALTQT_PRIQ)) == NULL)
662 return (EBADF);
663
664 if (ALTQ_IS_ENABLED(pif->pif_ifq))
665 altq_disable(pif->pif_ifq);
666
667 if ((error = altq_detach(pif->pif_ifq)))
668 return (error);
669
670 return priq_detach(pif);
671 }
672
673 static int
674 priqcmd_add_class(ap)
675 struct priq_add_class *ap;
676 {
677 struct priq_if *pif;
678 struct priq_class *cl;
679
680 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
681 return (EBADF);
682
683 if (ap->pri < 0 || ap->pri >= PRIQ_MAXPRI)
684 return (EINVAL);
685
686 if ((cl = priq_class_create(pif, ap->pri,
687 ap->qlimit, ap->flags)) == NULL)
688 return (ENOMEM);
689
690 /* return a class handle to the user */
691 ap->class_handle = clp_to_clh(cl);
692 return (0);
693 }
694
695 static int
696 priqcmd_delete_class(ap)
697 struct priq_delete_class *ap;
698 {
699 struct priq_if *pif;
700 struct priq_class *cl;
701
702 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
703 return (EBADF);
704
705 if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL)
706 return (EINVAL);
707
708 return priq_class_destroy(cl);
709 }
710
711 static int
712 priqcmd_modify_class(ap)
713 struct priq_modify_class *ap;
714 {
715 struct priq_if *pif;
716 struct priq_class *cl;
717
718 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
719 return (EBADF);
720
721 if (ap->pri < 0 || ap->pri >= PRIQ_MAXPRI)
722 return (EINVAL);
723
724 if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL)
725 return (EINVAL);
726
727 /*
728 * if priority is changed, move the class to the new priority
729 */
730 if (pif->pif_classes[ap->pri] != cl) {
731 if (pif->pif_classes[ap->pri] != NULL)
732 return (EEXIST);
733 pif->pif_classes[cl->cl_pri] = NULL;
734 pif->pif_classes[ap->pri] = cl;
735 cl->cl_pri = ap->pri;
736 }
737
738 /* call priq_class_create to change class parameters */
739 if ((cl = priq_class_create(pif, ap->pri,
740 ap->qlimit, ap->flags)) == NULL)
741 return (ENOMEM);
742 return 0;
743 }
744
745 static int
746 priqcmd_add_filter(ap)
747 struct priq_add_filter *ap;
748 {
749 struct priq_if *pif;
750 struct priq_class *cl;
751
752 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
753 return (EBADF);
754
755 if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL)
756 return (EINVAL);
757
758 return acc_add_filter(&pif->pif_classifier, &ap->filter,
759 cl, &ap->filter_handle);
760 }
761
762 static int
763 priqcmd_delete_filter(ap)
764 struct priq_delete_filter *ap;
765 {
766 struct priq_if *pif;
767
768 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
769 return (EBADF);
770
771 return acc_delete_filter(&pif->pif_classifier,
772 ap->filter_handle);
773 }
774
775 static int
776 priqcmd_class_stats(ap)
777 struct priq_class_stats *ap;
778 {
779 struct priq_if *pif;
780 struct priq_class *cl;
781 struct class_stats stats, *usp;
782 int pri, error;
783
784 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
785 return (EBADF);
786
787 ap->maxpri = pif->pif_maxpri;
788
789 /* then, read the next N classes in the tree */
790 usp = ap->stats;
791 for (pri = 0; pri <= pif->pif_maxpri; pri++) {
792 cl = pif->pif_classes[pri];
793 if (cl != NULL)
794 get_class_stats(&stats, cl);
795 else
796 bzero(&stats, sizeof(stats));
797 if ((error = copyout((caddr_t)&stats, (caddr_t)usp++,
798 sizeof(stats))) != 0)
799 return (error);
800 }
801 return (0);
802 }
803
804 static void get_class_stats(sp, cl)
805 struct class_stats *sp;
806 struct priq_class *cl;
807 {
808 sp->class_handle = clp_to_clh(cl);
809
810 sp->qlength = qlen(cl->cl_q);
811 sp->period = cl->cl_period;
812 sp->xmitcnt = cl->cl_xmitcnt;
813 sp->dropcnt = cl->cl_dropcnt;
814
815 sp->qtype = qtype(cl->cl_q);
816 #ifdef ALTQ_RED
817 if (q_is_red(cl->cl_q))
818 red_getstats(cl->cl_red, &sp->red[0]);
819 #endif
820 #ifdef ALTQ_RIO
821 if (q_is_rio(cl->cl_q))
822 rio_getstats((rio_t *)cl->cl_red, &sp->red[0]);
823 #endif
824
825 }
826
827 /* convert a class handle to the corresponding class pointer */
828 static struct priq_class *
829 clh_to_clp(pif, chandle)
830 struct priq_if *pif;
831 u_long chandle;
832 {
833 struct priq_class *cl;
834
835 cl = (struct priq_class *)chandle;
836 if (chandle != ALIGN(cl)) {
837 #if 1
838 printf("clh_to_cl: unaligned pointer %p\n", cl);
839 #endif
840 return (NULL);
841 }
842
843 if (cl == NULL || cl->cl_handle != chandle || cl->cl_pif != pif)
844 return (NULL);
845 return (cl);
846 }
847
848 /* convert a class pointer to the corresponding class handle */
849 static u_long
850 clp_to_clh(cl)
851 struct priq_class *cl;
852 {
853 return (cl->cl_handle);
854 }
855
856 #ifdef KLD_MODULE
857
858 static struct altqsw priq_sw =
859 {"priq", priqopen, priqclose, priqioctl};
860
861 ALTQ_MODULE(altq_priq, ALTQT_PRIQ, &priq_sw);
862
863 #endif /* KLD_MODULE */
864
865 #endif /* ALTQ_PRIQ */
866