altq_priq.c revision 1.10 1 /* $NetBSD: altq_priq.c,v 1.10 2006/04/23 06:46:40 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.10 2006/04/23 06:46:40 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
58 #include <net/if.h>
59 #include <net/if_types.h>
60
61 #include <altq/altq.h>
62 #include <altq/altq_conf.h>
63 #include <altq/altq_priq.h>
64
65 /*
66 * function prototypes
67 */
68 static struct priq_if *priq_attach __P((struct ifaltq *, u_int));
69 static int priq_detach __P((struct priq_if *));
70 static int priq_clear_interface __P((struct priq_if *));
71 static int priq_request __P((struct ifaltq *, int, void *));
72 static void priq_purge __P((struct priq_if *));
73 static struct priq_class *priq_class_create __P((struct priq_if *,
74 int, int, int));
75 static int priq_class_destroy __P((struct priq_class *));
76 static int priq_enqueue __P((struct ifaltq *, struct mbuf *,
77 struct altq_pktattr *));
78 static struct mbuf *priq_dequeue __P((struct ifaltq *, int));
79
80 static int priq_addq __P((struct priq_class *, struct mbuf *));
81 static struct mbuf *priq_getq __P((struct priq_class *));
82 static struct mbuf *priq_pollq __P((struct priq_class *));
83 static void priq_purgeq __P((struct priq_class *));
84
85 int priqopen __P((dev_t, int, int, struct lwp *));
86 int priqclose __P((dev_t, int, int, struct lwp *));
87 int priqioctl __P((dev_t, ioctlcmd_t, caddr_t, int, struct lwp *));
88 static int priqcmd_if_attach __P((struct priq_interface *));
89 static int priqcmd_if_detach __P((struct priq_interface *));
90 static int priqcmd_add_class __P((struct priq_add_class *));
91 static int priqcmd_delete_class __P((struct priq_delete_class *));
92 static int priqcmd_modify_class __P((struct priq_modify_class *));
93 static int priqcmd_add_filter __P((struct priq_add_filter *));
94 static int priqcmd_delete_filter __P((struct priq_delete_filter *));
95 static int priqcmd_class_stats __P((struct priq_class_stats *));
96 static void get_class_stats __P((struct priq_basic_class_stats *,
97 struct priq_class *));
98 static struct priq_class *clh_to_clp __P((struct priq_if *, u_long));
99 static u_long clp_to_clh __P((struct priq_class *));
100
101 /* pif_list keeps all priq_if's allocated. */
102 static struct priq_if *pif_list = NULL;
103
104 static struct priq_if *
105 priq_attach(ifq, bandwidth)
106 struct ifaltq *ifq;
107 u_int bandwidth;
108 {
109 struct priq_if *pif;
110
111 pif = malloc(sizeof(struct priq_if), M_DEVBUF, M_WAITOK|M_ZERO);
112 if (pif == NULL)
113 return (NULL);
114 pif->pif_bandwidth = bandwidth;
115 pif->pif_maxpri = -1;
116 pif->pif_ifq = ifq;
117
118 /* add this state to the priq list */
119 pif->pif_next = pif_list;
120 pif_list = pif;
121
122 return (pif);
123 }
124
125 static int
126 priq_detach(pif)
127 struct priq_if *pif;
128 {
129 (void)priq_clear_interface(pif);
130
131 /* remove this interface from the pif list */
132 if (pif_list == pif)
133 pif_list = pif->pif_next;
134 else {
135 struct priq_if *p;
136
137 for (p = pif_list; p != NULL; p = p->pif_next)
138 if (p->pif_next == pif) {
139 p->pif_next = pif->pif_next;
140 break;
141 }
142 ASSERT(p != NULL);
143 }
144
145 free(pif, M_DEVBUF);
146 return (0);
147 }
148
149 /*
150 * bring the interface back to the initial state by discarding
151 * all the filters and classes.
152 */
153 static int
154 priq_clear_interface(pif)
155 struct priq_if *pif;
156 {
157 struct priq_class *cl;
158 int pri;
159
160 /* free the filters for this interface */
161 acc_discard_filters(&pif->pif_classifier, NULL, 1);
162
163 /* clear out the classes */
164 for (pri = 0; pri <= pif->pif_maxpri; pri++)
165 if ((cl = pif->pif_classes[pri]) != NULL)
166 priq_class_destroy(cl);
167
168 return (0);
169 }
170
171 static int
172 priq_request(ifq, req, arg)
173 struct ifaltq *ifq;
174 int req;
175 void *arg;
176 {
177 struct priq_if *pif = (struct priq_if *)ifq->altq_disc;
178
179 switch (req) {
180 case ALTRQ_PURGE:
181 priq_purge(pif);
182 break;
183 }
184 return (0);
185 }
186
187 /* discard all the queued packets on the interface */
188 static void
189 priq_purge(pif)
190 struct priq_if *pif;
191 {
192 struct priq_class *cl;
193 int pri;
194
195 for (pri = 0; pri <= pif->pif_maxpri; pri++) {
196 if ((cl = pif->pif_classes[pri]) != NULL && !qempty(cl->cl_q))
197 priq_purgeq(cl);
198 }
199 if (ALTQ_IS_ENABLED(pif->pif_ifq))
200 pif->pif_ifq->ifq_len = 0;
201 }
202
203 static struct priq_class *
204 priq_class_create(pif, pri, qlimit, flags)
205 struct priq_if *pif;
206 int pri, qlimit, flags;
207 {
208 struct priq_class *cl;
209 int s;
210
211 #ifndef ALTQ_RED
212 if (flags & PRCF_RED) {
213 printf("priq_class_create: RED not configured for PRIQ!\n");
214 return (NULL);
215 }
216 #endif
217
218 if ((cl = pif->pif_classes[pri]) != NULL) {
219 /* modify the class instead of creating a new one */
220 s = splnet();
221 if (!qempty(cl->cl_q))
222 priq_purgeq(cl);
223 splx(s);
224 #ifdef ALTQ_RIO
225 if (q_is_rio(cl->cl_q))
226 rio_destroy((rio_t *)cl->cl_red);
227 #endif
228 #ifdef ALTQ_RED
229 if (q_is_red(cl->cl_q))
230 red_destroy(cl->cl_red);
231 #endif
232 } else {
233 cl = malloc(sizeof(struct priq_class), M_DEVBUF,
234 M_WAITOK|M_ZERO);
235 if (cl == NULL)
236 return (NULL);
237
238 cl->cl_q = malloc(sizeof(class_queue_t), M_DEVBUF,
239 M_WAITOK|M_ZERO);
240 if (cl->cl_q == NULL)
241 goto err_ret;
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, l)
498 dev_t dev;
499 int flag, fmt;
500 struct lwp *l;
501 {
502 /* everything will be done when the queueing scheme is attached. */
503 return 0;
504 }
505
506 int
507 priqclose(dev, flag, fmt, l)
508 dev_t dev;
509 int flag, fmt;
510 struct lwp *l;
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, l)
532 dev_t dev;
533 ioctlcmd_t cmd;
534 caddr_t addr;
535 int flag;
536 struct lwp *l;
537 {
538 struct priq_if *pif;
539 struct priq_interface *ifacep;
540 struct proc *p = l->l_proc;
541 int error = 0;
542
543 /* check super-user privilege */
544 switch (cmd) {
545 case PRIQ_GETSTATS:
546 break;
547 default:
548 #if (__FreeBSD_version > 400000)
549 if ((error = suser(p)) != 0)
550 return (error);
551 #else
552 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
553 return (error);
554 #endif
555 break;
556 }
557
558 switch (cmd) {
559
560 case PRIQ_IF_ATTACH:
561 error = priqcmd_if_attach((struct priq_interface *)addr);
562 break;
563
564 case PRIQ_IF_DETACH:
565 error = priqcmd_if_detach((struct priq_interface *)addr);
566 break;
567
568 case PRIQ_ENABLE:
569 case PRIQ_DISABLE:
570 case PRIQ_CLEAR:
571 ifacep = (struct priq_interface *)addr;
572 if ((pif = altq_lookup(ifacep->ifname,
573 ALTQT_PRIQ)) == NULL) {
574 error = EBADF;
575 break;
576 }
577
578 switch (cmd) {
579 case PRIQ_ENABLE:
580 if (pif->pif_default == NULL) {
581 #if 1
582 printf("priq: no default class\n");
583 #endif
584 error = EINVAL;
585 break;
586 }
587 error = altq_enable(pif->pif_ifq);
588 break;
589
590 case PRIQ_DISABLE:
591 error = altq_disable(pif->pif_ifq);
592 break;
593
594 case PRIQ_CLEAR:
595 priq_clear_interface(pif);
596 break;
597 }
598 break;
599
600 case PRIQ_ADD_CLASS:
601 error = priqcmd_add_class((struct priq_add_class *)addr);
602 break;
603
604 case PRIQ_DEL_CLASS:
605 error = priqcmd_delete_class((struct priq_delete_class *)addr);
606 break;
607
608 case PRIQ_MOD_CLASS:
609 error = priqcmd_modify_class((struct priq_modify_class *)addr);
610 break;
611
612 case PRIQ_ADD_FILTER:
613 error = priqcmd_add_filter((struct priq_add_filter *)addr);
614 break;
615
616 case PRIQ_DEL_FILTER:
617 error = priqcmd_delete_filter((struct priq_delete_filter *)addr);
618 break;
619
620 case PRIQ_GETSTATS:
621 error = priqcmd_class_stats((struct priq_class_stats *)addr);
622 break;
623
624 default:
625 error = EINVAL;
626 break;
627 }
628 return error;
629 }
630
631 static int
632 priqcmd_if_attach(ap)
633 struct priq_interface *ap;
634 {
635 struct priq_if *pif;
636 struct ifnet *ifp;
637 int error;
638
639 if ((ifp = ifunit(ap->ifname)) == NULL)
640 return (ENXIO);
641
642 if ((pif = priq_attach(&ifp->if_snd, ap->arg)) == NULL)
643 return (ENOMEM);
644
645 /*
646 * set PRIQ to this ifnet structure.
647 */
648 if ((error = altq_attach(&ifp->if_snd, ALTQT_PRIQ, pif,
649 priq_enqueue, priq_dequeue, priq_request,
650 &pif->pif_classifier, acc_classify)) != 0)
651 (void)priq_detach(pif);
652
653 return (error);
654 }
655
656 static int
657 priqcmd_if_detach(ap)
658 struct priq_interface *ap;
659 {
660 struct priq_if *pif;
661 int error;
662
663 if ((pif = altq_lookup(ap->ifname, ALTQT_PRIQ)) == NULL)
664 return (EBADF);
665
666 if (ALTQ_IS_ENABLED(pif->pif_ifq))
667 altq_disable(pif->pif_ifq);
668
669 if ((error = altq_detach(pif->pif_ifq)))
670 return (error);
671
672 return priq_detach(pif);
673 }
674
675 static int
676 priqcmd_add_class(ap)
677 struct priq_add_class *ap;
678 {
679 struct priq_if *pif;
680 struct priq_class *cl;
681
682 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
683 return (EBADF);
684
685 if (ap->pri < 0 || ap->pri >= PRIQ_MAXPRI)
686 return (EINVAL);
687
688 if ((cl = priq_class_create(pif, ap->pri,
689 ap->qlimit, ap->flags)) == NULL)
690 return (ENOMEM);
691
692 /* return a class handle to the user */
693 ap->class_handle = clp_to_clh(cl);
694 return (0);
695 }
696
697 static int
698 priqcmd_delete_class(ap)
699 struct priq_delete_class *ap;
700 {
701 struct priq_if *pif;
702 struct priq_class *cl;
703
704 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
705 return (EBADF);
706
707 if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL)
708 return (EINVAL);
709
710 return priq_class_destroy(cl);
711 }
712
713 static int
714 priqcmd_modify_class(ap)
715 struct priq_modify_class *ap;
716 {
717 struct priq_if *pif;
718 struct priq_class *cl;
719
720 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
721 return (EBADF);
722
723 if (ap->pri < 0 || ap->pri >= PRIQ_MAXPRI)
724 return (EINVAL);
725
726 if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL)
727 return (EINVAL);
728
729 /*
730 * if priority is changed, move the class to the new priority
731 */
732 if (pif->pif_classes[ap->pri] != cl) {
733 if (pif->pif_classes[ap->pri] != NULL)
734 return (EEXIST);
735 pif->pif_classes[cl->cl_pri] = NULL;
736 pif->pif_classes[ap->pri] = cl;
737 cl->cl_pri = ap->pri;
738 }
739
740 /* call priq_class_create to change class parameters */
741 if ((cl = priq_class_create(pif, ap->pri,
742 ap->qlimit, ap->flags)) == NULL)
743 return (ENOMEM);
744 return 0;
745 }
746
747 static int
748 priqcmd_add_filter(ap)
749 struct priq_add_filter *ap;
750 {
751 struct priq_if *pif;
752 struct priq_class *cl;
753
754 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
755 return (EBADF);
756
757 if ((cl = clh_to_clp(pif, ap->class_handle)) == NULL)
758 return (EINVAL);
759
760 return acc_add_filter(&pif->pif_classifier, &ap->filter,
761 cl, &ap->filter_handle);
762 }
763
764 static int
765 priqcmd_delete_filter(ap)
766 struct priq_delete_filter *ap;
767 {
768 struct priq_if *pif;
769
770 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
771 return (EBADF);
772
773 return acc_delete_filter(&pif->pif_classifier,
774 ap->filter_handle);
775 }
776
777 static int
778 priqcmd_class_stats(ap)
779 struct priq_class_stats *ap;
780 {
781 struct priq_if *pif;
782 struct priq_class *cl;
783 struct priq_basic_class_stats stats, *usp;
784 int pri, error;
785
786 if ((pif = altq_lookup(ap->iface.ifname, ALTQT_PRIQ)) == NULL)
787 return (EBADF);
788
789 ap->maxpri = pif->pif_maxpri;
790
791 /* then, read the next N classes in the tree */
792 usp = ap->stats;
793 for (pri = 0; pri <= pif->pif_maxpri; pri++) {
794 cl = pif->pif_classes[pri];
795 if (cl != NULL)
796 get_class_stats(&stats, cl);
797 else
798 (void)memset(&stats, 0, sizeof(stats));
799 if ((error = copyout((caddr_t)&stats, (caddr_t)usp++,
800 sizeof(stats))) != 0)
801 return (error);
802 }
803 return (0);
804 }
805
806 static void get_class_stats(sp, cl)
807 struct priq_basic_class_stats *sp;
808 struct priq_class *cl;
809 {
810 sp->class_handle = clp_to_clh(cl);
811
812 sp->qlength = qlen(cl->cl_q);
813 sp->period = cl->cl_period;
814 sp->xmitcnt = cl->cl_xmitcnt;
815 sp->dropcnt = cl->cl_dropcnt;
816
817 sp->qtype = qtype(cl->cl_q);
818 #ifdef ALTQ_RED
819 if (q_is_red(cl->cl_q))
820 red_getstats(cl->cl_red, &sp->red[0]);
821 #endif
822 #ifdef ALTQ_RIO
823 if (q_is_rio(cl->cl_q))
824 rio_getstats((rio_t *)cl->cl_red, &sp->red[0]);
825 #endif
826
827 }
828
829 /* convert a class handle to the corresponding class pointer */
830 static struct priq_class *
831 clh_to_clp(pif, chandle)
832 struct priq_if *pif;
833 u_long chandle;
834 {
835 struct priq_class *cl;
836
837 cl = (struct priq_class *)chandle;
838 if (chandle != ALIGN(cl)) {
839 #if 1
840 printf("clh_to_cl: unaligned pointer %p\n", cl);
841 #endif
842 return (NULL);
843 }
844
845 if (cl == NULL || cl->cl_handle != chandle || cl->cl_pif != pif)
846 return (NULL);
847 return (cl);
848 }
849
850 /* convert a class pointer to the corresponding class handle */
851 static u_long
852 clp_to_clh(cl)
853 struct priq_class *cl;
854 {
855 return (cl->cl_handle);
856 }
857
858 #ifdef KLD_MODULE
859
860 static struct altqsw priq_sw =
861 {"priq", priqopen, priqclose, priqioctl};
862
863 ALTQ_MODULE(altq_priq, ALTQT_PRIQ, &priq_sw);
864
865 #endif /* KLD_MODULE */
866
867 #endif /* ALTQ_PRIQ */
868