1 /* $NetBSD: altq_cbq.c,v 1.25 2008/06/18 09:06:27 yamt Exp $ */
2 /* $KAME: altq_cbq.c,v 1.21 2005/04/13 03:44:24 suz Exp $ */
5 * Copyright (c) Sun Microsystems, Inc. 1993-1998 All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the SMCC Technology
21 * Development Group at Sun Microsystems, Inc.
23 * 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or
24 * promote products derived from this software without specific prior
27 * SUN MICROSYSTEMS DOES NOT CLAIM MERCHANTABILITY OF THIS SOFTWARE OR THE
28 * SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE. The software is
29 * provided "as is" without express or implied warranty of any kind.
31 * These notices must be retained in any copies of any part of this software.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: altq_cbq.c,v 1.25 2008/06/18 09:06:27 yamt Exp $");
43 #ifdef ALTQ_CBQ /* cbq is enabled by ALTQ_CBQ option in opt_altq.h */
45 #include <sys/param.h>
46 #include <sys/malloc.h>
48 #include <sys/socket.h>
49 #include <sys/systm.h>
51 #include <sys/errno.h>
55 #include <sys/kernel.h>
57 #include <sys/kauth.h>
60 #include <netinet/in.h>
63 #include <net/pfvar.h>
65 #include <altq/altq.h>
66 #include <altq/altq_cbq.h>
68 #include <altq/altq_conf.h>
73 * Local Data structures.
75 static cbq_state_t
*cbq_list
= NULL
;
79 * Forward Declarations.
81 static int cbq_class_destroy(cbq_state_t
*, struct rm_class
*);
82 static struct rm_class
*clh_to_clp(cbq_state_t
*, u_int32_t
);
83 static int cbq_clear_interface(cbq_state_t
*);
84 static int cbq_request(struct ifaltq
*, int, void *);
85 static int cbq_enqueue(struct ifaltq
*, struct mbuf
*,
86 struct altq_pktattr
*);
87 static struct mbuf
*cbq_dequeue(struct ifaltq
*, int);
88 static void cbqrestart(struct ifaltq
*);
89 static void get_class_stats(class_stats_t
*, struct rm_class
*);
90 static void cbq_purge(cbq_state_t
*);
92 static int cbq_add_class(struct cbq_add_class
*);
93 static int cbq_delete_class(struct cbq_delete_class
*);
94 static int cbq_modify_class(struct cbq_modify_class
*);
95 static int cbq_class_create(cbq_state_t
*, struct cbq_add_class
*,
96 struct rm_class
*, struct rm_class
*);
97 static int cbq_clear_hierarchy(struct cbq_interface
*);
98 static int cbq_set_enable(struct cbq_interface
*, int);
99 static int cbq_ifattach(struct cbq_interface
*);
100 static int cbq_ifdetach(struct cbq_interface
*);
101 static int cbq_getstats(struct cbq_getstats
*);
103 static int cbq_add_filter(struct cbq_add_filter
*);
104 static int cbq_delete_filter(struct cbq_delete_filter
*);
105 #endif /* ALTQ3_COMPAT */
109 * cbq_class_destroy(cbq_mod_state_t *, struct rm_class *) - This
110 * function destroys a given traffic class. Before destroying
111 * the class, all traffic for that class is released.
114 cbq_class_destroy(cbq_state_t
*cbqp
, struct rm_class
*cl
)
118 /* delete the class */
119 rmc_delete_class(&cbqp
->ifnp
, cl
);
122 * free the class handle
124 for (i
= 0; i
< CBQ_MAX_CLASSES
; i
++)
125 if (cbqp
->cbq_class_tbl
[i
] == cl
)
126 cbqp
->cbq_class_tbl
[i
] = NULL
;
128 if (cl
== cbqp
->ifnp
.root_
)
129 cbqp
->ifnp
.root_
= NULL
;
130 if (cl
== cbqp
->ifnp
.default_
)
131 cbqp
->ifnp
.default_
= NULL
;
133 if (cl
== cbqp
->ifnp
.ctl_
)
134 cbqp
->ifnp
.ctl_
= NULL
;
139 /* convert class handle to class pointer */
140 static struct rm_class
*
141 clh_to_clp(cbq_state_t
*cbqp
, u_int32_t chandle
)
149 * first, try optimistically the slot matching the lower bits of
150 * the handle. if it fails, do the linear table search.
152 i
= chandle
% CBQ_MAX_CLASSES
;
153 if ((cl
= cbqp
->cbq_class_tbl
[i
]) != NULL
&&
154 cl
->stats_
.handle
== chandle
)
156 for (i
= 0; i
< CBQ_MAX_CLASSES
; i
++)
157 if ((cl
= cbqp
->cbq_class_tbl
[i
]) != NULL
&&
158 cl
->stats_
.handle
== chandle
)
164 cbq_clear_interface(cbq_state_t
*cbqp
)
169 #ifdef ALTQ3_CLFIER_COMPAT
170 /* free the filters for this interface */
171 acc_discard_filters(&cbqp
->cbq_classifier
, NULL
, 1);
174 /* clear out the classes now */
177 for (i
= 0; i
< CBQ_MAX_CLASSES
; i
++) {
178 if ((cl
= cbqp
->cbq_class_tbl
[i
]) != NULL
) {
179 if (is_a_parent_class(cl
))
182 cbq_class_destroy(cbqp
, cl
);
183 cbqp
->cbq_class_tbl
[i
] = NULL
;
184 if (cl
== cbqp
->ifnp
.root_
)
185 cbqp
->ifnp
.root_
= NULL
;
186 if (cl
== cbqp
->ifnp
.default_
)
187 cbqp
->ifnp
.default_
= NULL
;
189 if (cl
== cbqp
->ifnp
.ctl_
)
190 cbqp
->ifnp
.ctl_
= NULL
;
201 cbq_request(struct ifaltq
*ifq
, int req
, void *arg
)
203 cbq_state_t
*cbqp
= (cbq_state_t
*)ifq
->altq_disc
;
213 /* copy the stats info in rm_class to class_states_t */
215 get_class_stats(class_stats_t
*statsp
, struct rm_class
*cl
)
217 statsp
->xmit_cnt
= cl
->stats_
.xmit_cnt
;
218 statsp
->drop_cnt
= cl
->stats_
.drop_cnt
;
219 statsp
->over
= cl
->stats_
.over
;
220 statsp
->borrows
= cl
->stats_
.borrows
;
221 statsp
->overactions
= cl
->stats_
.overactions
;
222 statsp
->delays
= cl
->stats_
.delays
;
224 statsp
->depth
= cl
->depth_
;
225 statsp
->priority
= cl
->pri_
;
226 statsp
->maxidle
= cl
->maxidle_
;
227 statsp
->minidle
= cl
->minidle_
;
228 statsp
->offtime
= cl
->offtime_
;
229 statsp
->qmax
= qlimit(cl
->q_
);
230 statsp
->ns_per_byte
= cl
->ns_per_byte_
;
231 statsp
->wrr_allot
= cl
->w_allotment_
;
232 statsp
->qcnt
= qlen(cl
->q_
);
233 statsp
->avgidle
= cl
->avgidle_
;
235 statsp
->qtype
= qtype(cl
->q_
);
237 if (q_is_red(cl
->q_
))
238 red_getstats(cl
->red_
, &statsp
->red
[0]);
241 if (q_is_rio(cl
->q_
))
242 rio_getstats((rio_t
*)cl
->red_
, &statsp
->red
[0]);
248 cbq_pfattach(struct pf_altq
*a
)
253 if ((ifp
= ifunit(a
->ifname
)) == NULL
|| a
->altq_disc
== NULL
)
256 error
= altq_attach(&ifp
->if_snd
, ALTQT_CBQ
, a
->altq_disc
,
257 cbq_enqueue
, cbq_dequeue
, cbq_request
, NULL
, NULL
);
263 cbq_add_altq(struct pf_altq
*a
)
268 if ((ifp
= ifunit(a
->ifname
)) == NULL
)
270 if (!ALTQ_IS_READY(&ifp
->if_snd
))
273 /* allocate and initialize cbq_state_t */
274 cbqp
= malloc(sizeof(cbq_state_t
), M_DEVBUF
, M_WAITOK
|M_ZERO
);
277 (void)memset(cbqp
, 0, sizeof(cbq_state_t
));
278 CALLOUT_INIT(&cbqp
->cbq_callout
);
280 cbqp
->ifnp
.ifq_
= &ifp
->if_snd
; /* keep the ifq */
282 /* keep the state in pf_altq */
289 cbq_remove_altq(struct pf_altq
*a
)
293 if ((cbqp
= a
->altq_disc
) == NULL
)
297 cbq_clear_interface(cbqp
);
299 if (cbqp
->ifnp
.default_
)
300 cbq_class_destroy(cbqp
, cbqp
->ifnp
.default_
);
301 if (cbqp
->ifnp
.root_
)
302 cbq_class_destroy(cbqp
, cbqp
->ifnp
.root_
);
304 /* deallocate cbq_state_t */
305 free(cbqp
, M_DEVBUF
);
311 cbq_add_queue(struct pf_altq
*a
)
313 struct rm_class
*borrow
, *parent
;
316 struct cbq_opts
*opts
;
319 if ((cbqp
= a
->altq_disc
) == NULL
)
325 * find a free slot in the class table. if the slot matching
326 * the lower bits of qid is free, use this slot. otherwise,
327 * use the first free slot.
329 i
= a
->qid
% CBQ_MAX_CLASSES
;
330 if (cbqp
->cbq_class_tbl
[i
] != NULL
) {
331 for (i
= 0; i
< CBQ_MAX_CLASSES
; i
++)
332 if (cbqp
->cbq_class_tbl
[i
] == NULL
)
334 if (i
== CBQ_MAX_CLASSES
)
338 opts
= &a
->pq_u
.cbq_opts
;
339 /* check parameters */
340 if (a
->priority
>= CBQ_MAXPRI
)
343 /* Get pointers to parent and borrow classes. */
344 parent
= clh_to_clp(cbqp
, a
->parent_qid
);
345 if (opts
->flags
& CBQCLF_BORROW
)
351 * A class must borrow from it's parent or it can not
352 * borrow at all. Hence, borrow can be null.
354 if (parent
== NULL
&& (opts
->flags
& CBQCLF_ROOTCLASS
) == 0) {
355 printf("cbq_add_queue: no parent class!\n");
359 if ((borrow
!= parent
) && (borrow
!= NULL
)) {
360 printf("cbq_add_class: borrow class != parent\n");
367 switch (opts
->flags
& CBQCLF_CLASSMASK
) {
368 case CBQCLF_ROOTCLASS
:
371 if (cbqp
->ifnp
.root_
)
374 case CBQCLF_DEFCLASS
:
375 if (cbqp
->ifnp
.default_
)
383 /* more than two flags bits set */
388 * create a class. if this is a root class, initialize the
391 if ((opts
->flags
& CBQCLF_CLASSMASK
) == CBQCLF_ROOTCLASS
) {
392 error
= rmc_init(cbqp
->ifnp
.ifq_
, &cbqp
->ifnp
,
393 opts
->ns_per_byte
, cbqrestart
, a
->qlimit
, RM_MAXQUEUED
,
394 opts
->maxidle
, opts
->minidle
, opts
->offtime
,
398 cl
= cbqp
->ifnp
.root_
;
400 cl
= rmc_newclass(a
->priority
,
401 &cbqp
->ifnp
, opts
->ns_per_byte
,
402 rmc_delay_action
, a
->qlimit
, parent
, borrow
,
403 opts
->maxidle
, opts
->minidle
, opts
->offtime
,
404 opts
->pktsize
, opts
->flags
);
409 /* return handle to user space. */
410 cl
->stats_
.handle
= a
->qid
;
411 cl
->stats_
.depth
= cl
->depth_
;
413 /* save the allocated class */
414 cbqp
->cbq_class_tbl
[i
] = cl
;
416 if ((opts
->flags
& CBQCLF_CLASSMASK
) == CBQCLF_DEFCLASS
)
417 cbqp
->ifnp
.default_
= cl
;
423 cbq_remove_queue(struct pf_altq
*a
)
429 if ((cbqp
= a
->altq_disc
) == NULL
)
432 if ((cl
= clh_to_clp(cbqp
, a
->qid
)) == NULL
)
435 /* if we are a parent class, then return an error. */
436 if (is_a_parent_class(cl
))
439 /* delete the class */
440 rmc_delete_class(&cbqp
->ifnp
, cl
);
443 * free the class handle
445 for (i
= 0; i
< CBQ_MAX_CLASSES
; i
++)
446 if (cbqp
->cbq_class_tbl
[i
] == cl
) {
447 cbqp
->cbq_class_tbl
[i
] = NULL
;
448 if (cl
== cbqp
->ifnp
.root_
)
449 cbqp
->ifnp
.root_
= NULL
;
450 if (cl
== cbqp
->ifnp
.default_
)
451 cbqp
->ifnp
.default_
= NULL
;
459 cbq_getqstats(struct pf_altq
*a
, void *ubuf
, int *nbytes
)
466 if ((cbqp
= altq_lookup(a
->ifname
, ALTQT_CBQ
)) == NULL
)
469 if ((cl
= clh_to_clp(cbqp
, a
->qid
)) == NULL
)
472 if (*nbytes
< sizeof(stats
))
475 get_class_stats(&stats
, cl
);
477 if ((error
= copyout((void *)&stats
, ubuf
, sizeof(stats
))) != 0)
479 *nbytes
= sizeof(stats
);
486 * cbq_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pattr)
487 * - Queue data packets.
489 * cbq_enqueue is set to ifp->if_altqenqueue and called by an upper
490 * layer (e.g. ether_output). cbq_enqueue queues the given packet
491 * to the cbq, then invokes the driver's start routine.
493 * Assumptions: called in splnet
494 * Returns: 0 if the queueing is successful.
495 * ENOBUFS if a packet dropping occurred as a result of
500 cbq_enqueue(struct ifaltq
*ifq
, struct mbuf
*m
, struct altq_pktattr
*pktattr
)
502 cbq_state_t
*cbqp
= (cbq_state_t
*)ifq
->altq_disc
;
507 /* grab class set by classifier */
508 if ((m
->m_flags
& M_PKTHDR
) == 0) {
509 /* should not happen */
510 printf("altq: packet for %s does not have pkthdr\n",
511 ifq
->altq_ifp
->if_xname
);
516 if ((t
= m_tag_find(m
, PACKET_TAG_ALTQ_QID
, NULL
)) != NULL
)
517 cl
= clh_to_clp(cbqp
, ((struct altq_tag
*)(t
+1))->qid
);
519 else if ((ifq
->altq_flags
& ALTQF_CLASSIFY
) && pktattr
!= NULL
)
520 cl
= pktattr
->pattr_class
;
523 cl
= cbqp
->ifnp
.default_
;
531 cl
->pktattr_
= pktattr
; /* save proto hdr used by ECN */
536 if (rmc_queue_packet(cl
, m
) != 0) {
537 /* drop occurred. some mbuf was freed in rmc_queue_packet. */
538 PKTCNTR_ADD(&cl
->stats_
.drop_cnt
, len
);
542 /* successfully queued. */
549 cbq_dequeue(struct ifaltq
*ifq
, int op
)
551 cbq_state_t
*cbqp
= (cbq_state_t
*)ifq
->altq_disc
;
554 m
= rmc_dequeue_next(&cbqp
->ifnp
, op
);
556 if (m
&& op
== ALTDQ_REMOVE
) {
557 --cbqp
->cbq_qlen
; /* decrement # of packets in cbq */
560 /* Update the class. */
561 rmc_update_class_util(&cbqp
->ifnp
);
568 * cbqrestart(queue_t *) - Restart sending of data.
569 * called from rmc_restart in splnet via timeout after waking up
575 cbqrestart(struct ifaltq
*ifq
)
580 if (!ALTQ_IS_ENABLED(ifq
))
581 /* cbq must have been detached */
584 if ((cbqp
= (cbq_state_t
*)ifq
->altq_disc
) == NULL
)
585 /* should not happen */
590 cbqp
->cbq_qlen
> 0 && (ifp
->if_flags
& IFF_OACTIVE
) == 0)
591 (*ifp
->if_start
)(ifp
);
595 cbq_purge(cbq_state_t
*cbqp
)
600 for (i
= 0; i
< CBQ_MAX_CLASSES
; i
++)
601 if ((cl
= cbqp
->cbq_class_tbl
[i
]) != NULL
)
603 if (ALTQ_IS_ENABLED(cbqp
->ifnp
.ifq_
))
604 cbqp
->ifnp
.ifq_
->ifq_len
= 0;
609 cbq_add_class(struct cbq_add_class
*acp
)
612 struct rm_class
*borrow
, *parent
;
615 ifacename
= acp
->cbq_iface
.cbq_ifacename
;
616 if ((cbqp
= altq_lookup(ifacename
, ALTQT_CBQ
)) == NULL
)
619 /* check parameters */
620 if (acp
->cbq_class
.priority
>= CBQ_MAXPRI
||
621 acp
->cbq_class
.maxq
> CBQ_MAXQSIZE
)
624 /* Get pointers to parent and borrow classes. */
625 parent
= clh_to_clp(cbqp
, acp
->cbq_class
.parent_class_handle
);
626 borrow
= clh_to_clp(cbqp
, acp
->cbq_class
.borrow_class_handle
);
629 * A class must borrow from it's parent or it can not
630 * borrow at all. Hence, borrow can be null.
632 if (parent
== NULL
&& (acp
->cbq_class
.flags
& CBQCLF_ROOTCLASS
) == 0) {
633 printf("cbq_add_class: no parent class!\n");
637 if ((borrow
!= parent
) && (borrow
!= NULL
)) {
638 printf("cbq_add_class: borrow class != parent\n");
642 return cbq_class_create(cbqp
, acp
, parent
, borrow
);
646 cbq_delete_class(struct cbq_delete_class
*dcp
)
652 ifacename
= dcp
->cbq_iface
.cbq_ifacename
;
653 if ((cbqp
= altq_lookup(ifacename
, ALTQT_CBQ
)) == NULL
)
656 if ((cl
= clh_to_clp(cbqp
, dcp
->cbq_class_handle
)) == NULL
)
659 /* if we are a parent class, then return an error. */
660 if (is_a_parent_class(cl
))
663 /* if a filter has a reference to this class delete the filter */
664 acc_discard_filters(&cbqp
->cbq_classifier
, cl
, 0);
666 return cbq_class_destroy(cbqp
, cl
);
670 cbq_modify_class(struct cbq_modify_class
*acp
)
676 ifacename
= acp
->cbq_iface
.cbq_ifacename
;
677 if ((cbqp
= altq_lookup(ifacename
, ALTQT_CBQ
)) == NULL
)
680 /* Get pointer to this class */
681 if ((cl
= clh_to_clp(cbqp
, acp
->cbq_class_handle
)) == NULL
)
684 if (rmc_modclass(cl
, acp
->cbq_class
.nano_sec_per_byte
,
685 acp
->cbq_class
.maxq
, acp
->cbq_class
.maxidle
,
686 acp
->cbq_class
.minidle
, acp
->cbq_class
.offtime
,
687 acp
->cbq_class
.pktsize
) < 0)
694 * cbq_class_create(cbq_mod_state_t *cbqp, struct cbq_add_class *acp,
695 * struct rm_class *parent, struct rm_class *borrow)
697 * This function create a new traffic class in the CBQ class hierarchy of
698 * given paramters. The class that created is either the root, default,
699 * or a new dynamic class. If CBQ is not initilaized, the root class
703 cbq_class_create(cbq_state_t
*cbqp
, struct cbq_add_class
*acp
,
704 struct rm_class
*parent
, struct rm_class
*borrow
)
707 cbq_class_spec_t
*spec
= &acp
->cbq_class
;
712 * allocate class handle
714 for (i
= 1; i
< CBQ_MAX_CLASSES
; i
++)
715 if (cbqp
->cbq_class_tbl
[i
] == NULL
)
717 if (i
== CBQ_MAX_CLASSES
)
719 chandle
= i
; /* use the slot number as class handle */
722 * create a class. if this is a root class, initialize the
725 if ((spec
->flags
& CBQCLF_CLASSMASK
) == CBQCLF_ROOTCLASS
) {
726 error
= rmc_init(cbqp
->ifnp
.ifq_
, &cbqp
->ifnp
,
727 spec
->nano_sec_per_byte
, cbqrestart
, spec
->maxq
,
728 RM_MAXQUEUED
, spec
->maxidle
, spec
->minidle
, spec
->offtime
,
732 cl
= cbqp
->ifnp
.root_
;
734 cl
= rmc_newclass(spec
->priority
,
735 &cbqp
->ifnp
, spec
->nano_sec_per_byte
,
736 rmc_delay_action
, spec
->maxq
, parent
, borrow
,
737 spec
->maxidle
, spec
->minidle
, spec
->offtime
,
738 spec
->pktsize
, spec
->flags
);
743 /* return handle to user space. */
744 acp
->cbq_class_handle
= chandle
;
746 cl
->stats_
.handle
= chandle
;
747 cl
->stats_
.depth
= cl
->depth_
;
749 /* save the allocated class */
750 cbqp
->cbq_class_tbl
[i
] = cl
;
752 if ((spec
->flags
& CBQCLF_CLASSMASK
) == CBQCLF_DEFCLASS
)
753 cbqp
->ifnp
.default_
= cl
;
754 if ((spec
->flags
& CBQCLF_CLASSMASK
) == CBQCLF_CTLCLASS
)
755 cbqp
->ifnp
.ctl_
= cl
;
761 cbq_add_filter(struct cbq_add_filter
*afp
)
767 ifacename
= afp
->cbq_iface
.cbq_ifacename
;
768 if ((cbqp
= altq_lookup(ifacename
, ALTQT_CBQ
)) == NULL
)
771 /* Get the pointer to class. */
772 if ((cl
= clh_to_clp(cbqp
, afp
->cbq_class_handle
)) == NULL
)
775 return acc_add_filter(&cbqp
->cbq_classifier
, &afp
->cbq_filter
,
776 cl
, &afp
->cbq_filter_handle
);
780 cbq_delete_filter(struct cbq_delete_filter
*dfp
)
785 ifacename
= dfp
->cbq_iface
.cbq_ifacename
;
786 if ((cbqp
= altq_lookup(ifacename
, ALTQT_CBQ
)) == NULL
)
789 return acc_delete_filter(&cbqp
->cbq_classifier
,
790 dfp
->cbq_filter_handle
);
794 * cbq_clear_hierarchy deletes all classes and their filters on the
798 cbq_clear_hierarchy(struct cbq_interface
*ifacep
)
803 ifacename
= ifacep
->cbq_ifacename
;
804 if ((cbqp
= altq_lookup(ifacename
, ALTQT_CBQ
)) == NULL
)
807 return cbq_clear_interface(cbqp
);
812 * cbq_set_enable(struct cbq_enable *ep) - this function processed the
813 * ioctl request to enable class based queueing. It searches the list
814 * of interfaces for the specified interface and then enables CBQ on
817 * Returns: 0, for no error.
818 * EBADF, for specified inteface not found.
822 cbq_set_enable(struct cbq_interface
*ep
, int enable
)
828 ifacename
= ep
->cbq_ifacename
;
829 if ((cbqp
= altq_lookup(ifacename
, ALTQT_CBQ
)) == NULL
)
834 if (cbqp
->ifnp
.root_
== NULL
|| cbqp
->ifnp
.default_
== NULL
||
835 cbqp
->ifnp
.ctl_
== NULL
) {
836 if (cbqp
->ifnp
.root_
== NULL
)
837 printf("No Root Class for %s\n", ifacename
);
838 if (cbqp
->ifnp
.default_
== NULL
)
839 printf("No Default Class for %s\n", ifacename
);
840 if (cbqp
->ifnp
.ctl_
== NULL
)
841 printf("No Control Class for %s\n", ifacename
);
843 } else if ((error
= altq_enable(cbqp
->ifnp
.ifq_
)) == 0) {
849 error
= altq_disable(cbqp
->ifnp
.ifq_
);
856 cbq_getstats(struct cbq_getstats
*gsp
)
862 class_stats_t stats
, *usp
;
865 ifacename
= gsp
->iface
.cbq_ifacename
;
866 nclasses
= gsp
->nclasses
;
869 if ((cbqp
= altq_lookup(ifacename
, ALTQT_CBQ
)) == NULL
)
874 for (n
= 0, i
= 0; n
< nclasses
&& i
< CBQ_MAX_CLASSES
; n
++, i
++) {
875 while ((cl
= cbqp
->cbq_class_tbl
[i
]) == NULL
)
876 if (++i
>= CBQ_MAX_CLASSES
)
879 get_class_stats(&stats
, cl
);
880 stats
.handle
= cl
->stats_
.handle
;
882 if ((error
= copyout((void *)&stats
, (void *)usp
++,
883 sizeof(stats
))) != 0)
893 cbq_ifattach(struct cbq_interface
*ifacep
)
897 cbq_state_t
*new_cbqp
;
900 ifacename
= ifacep
->cbq_ifacename
;
901 if ((ifp
= ifunit(ifacename
)) == NULL
)
903 if (!ALTQ_IS_READY(&ifp
->if_snd
))
906 /* allocate and initialize cbq_state_t */
907 new_cbqp
= malloc(sizeof(cbq_state_t
), M_DEVBUF
, M_WAITOK
|M_ZERO
);
908 if (new_cbqp
== NULL
)
910 CALLOUT_INIT(&new_cbqp
->cbq_callout
);
912 new_cbqp
->cbq_qlen
= 0;
913 new_cbqp
->ifnp
.ifq_
= &ifp
->if_snd
; /* keep the ifq */
916 * set CBQ to this ifnet structure.
918 error
= altq_attach(&ifp
->if_snd
, ALTQT_CBQ
, new_cbqp
,
919 cbq_enqueue
, cbq_dequeue
, cbq_request
,
920 &new_cbqp
->cbq_classifier
, acc_classify
);
922 free(new_cbqp
, M_DEVBUF
);
926 /* prepend to the list of cbq_state_t's. */
927 new_cbqp
->cbq_next
= cbq_list
;
934 cbq_ifdetach(struct cbq_interface
*ifacep
)
939 ifacename
= ifacep
->cbq_ifacename
;
940 if ((cbqp
= altq_lookup(ifacename
, ALTQT_CBQ
)) == NULL
)
943 (void)cbq_set_enable(ifacep
, DISABLE
);
945 cbq_clear_interface(cbqp
);
947 /* remove CBQ from the ifnet structure. */
948 (void)altq_detach(cbqp
->ifnp
.ifq_
);
950 /* remove from the list of cbq_state_t's. */
951 if (cbq_list
== cbqp
)
952 cbq_list
= cbqp
->cbq_next
;
956 for (cp
= cbq_list
; cp
!= NULL
; cp
= cp
->cbq_next
)
957 if (cp
->cbq_next
== cbqp
) {
958 cp
->cbq_next
= cbqp
->cbq_next
;
964 /* deallocate cbq_state_t */
965 free(cbqp
, M_DEVBUF
);
971 * cbq device interface
977 cbqopen(dev_t dev
, int flag
, int fmt
,
984 cbqclose(dev_t dev
, int flag
, int fmt
,
988 struct cbq_interface iface
;
992 ifp
= cbq_list
->ifnp
.ifq_
->altq_ifp
;
993 sprintf(iface
.cbq_ifacename
, "%s", ifp
->if_xname
);
994 err
= cbq_ifdetach(&iface
);
995 if (err
!= 0 && error
== 0)
1003 cbqioctl(dev_t dev
, ioctlcmd_t cmd
, void *addr
, int flag
,
1008 /* check cmd for superuser only */
1011 /* currently only command that an ordinary user can call */
1014 #if (__FreeBSD_version > 400000)
1017 error
= kauth_authorize_network(l
->l_cred
, KAUTH_NETWORK_ALTQ
,
1018 KAUTH_REQ_NETWORK_ALTQ_CBQ
, NULL
, NULL
, NULL
);
1028 error
= cbq_set_enable((struct cbq_interface
*)addr
, ENABLE
);
1032 error
= cbq_set_enable((struct cbq_interface
*)addr
, DISABLE
);
1035 case CBQ_ADD_FILTER
:
1036 error
= cbq_add_filter((struct cbq_add_filter
*)addr
);
1039 case CBQ_DEL_FILTER
:
1040 error
= cbq_delete_filter((struct cbq_delete_filter
*)addr
);
1044 error
= cbq_add_class((struct cbq_add_class
*)addr
);
1048 error
= cbq_delete_class((struct cbq_delete_class
*)addr
);
1051 case CBQ_MODIFY_CLASS
:
1052 error
= cbq_modify_class((struct cbq_modify_class
*)addr
);
1055 case CBQ_CLEAR_HIERARCHY
:
1056 error
= cbq_clear_hierarchy((struct cbq_interface
*)addr
);
1060 error
= cbq_ifattach((struct cbq_interface
*)addr
);
1064 error
= cbq_ifdetach((struct cbq_interface
*)addr
);
1068 error
= cbq_getstats((struct cbq_getstats
*)addr
);
1081 static void cbq_class_dump(int);
1084 cbq_class_dump(int i
)
1086 struct rm_class
*cl
;
1087 rm_class_stats_t
*s
;
1088 struct _class_queue_
*q
;
1090 if (cbq_list
== NULL
) {
1091 printf("cbq_class_dump: no cbq_state found\n");
1094 cl
= cbq_list
->cbq_class_tbl
[i
];
1096 printf("class %d cl=%p\n", i
, cl
);
1101 printf("pri=%d, depth=%d, maxrate=%d, allotment=%d\n",
1102 cl
->pri_
, cl
->depth_
, cl
->maxrate_
, cl
->allotment_
);
1103 printf("w_allotment=%d, bytes_alloc=%d, avgidle=%d, maxidle=%d\n",
1104 cl
->w_allotment_
, cl
->bytes_alloc_
, cl
->avgidle_
,
1106 printf("minidle=%d, offtime=%d, sleeping=%d, leaf=%d\n",
1107 cl
->minidle_
, cl
->offtime_
, cl
->sleeping_
, cl
->leaf_
);
1108 printf("handle=%d, depth=%d, packets=%d, bytes=%d\n",
1109 s
->handle
, s
->depth
,
1110 (int)s
->xmit_cnt
.packets
, (int)s
->xmit_cnt
.bytes
);
1111 printf("over=%d\n, borrows=%d, drops=%d, overactions=%d, delays=%d\n",
1112 s
->over
, s
->borrows
, (int)s
->drop_cnt
.packets
,
1113 s
->overactions
, s
->delays
);
1114 printf("tail=%p, head=%p, qlen=%d, qlim=%d, qthresh=%d,qtype=%d\n",
1115 q
->tail_
, q
->head_
, q
->qlen_
, q
->qlim_
,
1116 q
->qthresh_
, q
->qtype_
);
1123 static struct altqsw cbq_sw
=
1124 {"cbq", cbqopen
, cbqclose
, cbqioctl
};
1126 ALTQ_MODULE(altq_cbq
, ALTQT_CBQ
, &cbq_sw
);
1127 MODULE_DEPEND(altq_cbq
, altq_red
, 1, 1, 1);
1128 MODULE_DEPEND(altq_cbq
, altq_rio
, 1, 1, 1);
1130 #endif /* KLD_MODULE */
1131 #endif /* ALTQ3_COMPAT */
1133 #endif /* ALTQ_CBQ */