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