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