1 /* $NetBSD: altq_cdnr.c,v 1.18 2006/11/16 01:32:37 christos Exp $ */
2 /* $KAME: altq_cdnr.c,v 1.15 2005/04/13 03:44:24 suz Exp $ */
5 * Copyright (C) 1999-2002
6 * Sony Computer Science Laboratories Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * 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.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: altq_cdnr.c,v 1.18 2006/11/16 01:32:37 christos Exp $");
38 #include <sys/param.h>
39 #include <sys/malloc.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <sys/systm.h>
45 #include <sys/errno.h>
46 #include <sys/kernel.h>
47 #include <sys/queue.h>
48 #include <sys/kauth.h>
51 #include <net/if_types.h>
52 #include <netinet/in.h>
53 #include <netinet/in_systm.h>
54 #include <netinet/ip.h>
56 #include <netinet/ip6.h>
59 #include <altq/altq.h>
60 #include <altq/altq_conf.h>
61 #include <altq/altq_cdnr.h>
65 * diffserv traffic conditioning module
68 int altq_cdnr_enabled
= 0;
70 /* traffic conditioner is enabled by ALTQ_CDNR option in opt_altq.h */
73 /* cdnr_list keeps all cdnr's allocated. */
74 static LIST_HEAD(, top_cdnr
) tcb_list
;
76 static int altq_cdnr_input(struct mbuf
*, int);
77 static struct top_cdnr
*tcb_lookup(char *ifname
);
78 static struct cdnr_block
*cdnr_handle2cb(u_long
);
79 static u_long
cdnr_cb2handle(struct cdnr_block
*);
80 static void *cdnr_cballoc(struct top_cdnr
*, int,
81 struct tc_action
*(*)(struct cdnr_block
*, struct cdnr_pktinfo
*));
82 static void cdnr_cbdestroy(void *);
83 static int tca_verify_action(struct tc_action
*);
84 static void tca_import_action(struct tc_action
*, struct tc_action
*);
85 static void tca_invalidate_action(struct tc_action
*);
87 static int generic_element_destroy(struct cdnr_block
*);
88 static struct top_cdnr
*top_create(struct ifaltq
*);
89 static int top_destroy(struct top_cdnr
*);
90 static struct cdnr_block
*element_create(struct top_cdnr
*, struct tc_action
*);
91 static int element_destroy(struct cdnr_block
*);
92 static void tb_import_profile(struct tbe
*, struct tb_profile
*);
93 static struct tbmeter
*tbm_create(struct top_cdnr
*, struct tb_profile
*,
94 struct tc_action
*, struct tc_action
*);
95 static int tbm_destroy(struct tbmeter
*);
96 static struct tc_action
*tbm_input(struct cdnr_block
*, struct cdnr_pktinfo
*);
97 static struct trtcm
*trtcm_create(struct top_cdnr
*,
98 struct tb_profile
*, struct tb_profile
*,
99 struct tc_action
*, struct tc_action
*, struct tc_action
*,
101 static int trtcm_destroy(struct trtcm
*);
102 static struct tc_action
*trtcm_input(struct cdnr_block
*, struct cdnr_pktinfo
*);
103 static struct tswtcm
*tswtcm_create(struct top_cdnr
*,
104 u_int32_t
, u_int32_t
, u_int32_t
,
105 struct tc_action
*, struct tc_action
*, struct tc_action
*);
106 static int tswtcm_destroy(struct tswtcm
*);
107 static struct tc_action
*tswtcm_input(struct cdnr_block
*, struct cdnr_pktinfo
*);
109 static int cdnrcmd_if_attach(char *);
110 static int cdnrcmd_if_detach(char *);
111 static int cdnrcmd_add_element(struct cdnr_add_element
*);
112 static int cdnrcmd_delete_element(struct cdnr_delete_element
*);
113 static int cdnrcmd_add_filter(struct cdnr_add_filter
*);
114 static int cdnrcmd_delete_filter(struct cdnr_delete_filter
*);
115 static int cdnrcmd_add_tbm(struct cdnr_add_tbmeter
*);
116 static int cdnrcmd_modify_tbm(struct cdnr_modify_tbmeter
*);
117 static int cdnrcmd_tbm_stats(struct cdnr_tbmeter_stats
*);
118 static int cdnrcmd_add_trtcm(struct cdnr_add_trtcm
*);
119 static int cdnrcmd_modify_trtcm(struct cdnr_modify_trtcm
*);
120 static int cdnrcmd_tcm_stats(struct cdnr_tcm_stats
*);
121 static int cdnrcmd_add_tswtcm(struct cdnr_add_tswtcm
*);
122 static int cdnrcmd_modify_tswtcm(struct cdnr_modify_tswtcm
*);
123 static int cdnrcmd_get_stats(struct cdnr_get_stats
*);
128 * top level input function called from ip_input.
129 * should be called before converting header fields to host-byte-order.
132 altq_cdnr_input(struct mbuf
*m
, int af
)
136 struct top_cdnr
*top
;
137 struct tc_action
*tca
;
138 struct cdnr_block
*cb
;
139 struct cdnr_pktinfo pktinfo
;
141 ifp
= m
->m_pkthdr
.rcvif
;
142 if (!ALTQ_IS_CNDTNING(&ifp
->if_snd
))
143 /* traffic conditioner is not enabled on this interface */
146 top
= ifp
->if_snd
.altq_cdnr
;
148 ip
= mtod(m
, struct ip
*);
150 if (af
== AF_INET6
) {
153 flowlabel
= ((struct ip6_hdr
*)ip
)->ip6_flow
;
154 pktinfo
.pkt_dscp
= (ntohl(flowlabel
) >> 20) & DSCP_MASK
;
157 pktinfo
.pkt_dscp
= ip
->ip_tos
& DSCP_MASK
;
158 pktinfo
.pkt_len
= m_pktlen(m
);
162 cb
= acc_classify(&top
->tc_classifier
, m
, af
);
164 tca
= &cb
->cb_action
;
167 tca
= &top
->tc_block
.cb_action
;
170 PKTCNTR_ADD(&top
->tc_cnts
[tca
->tca_code
], pktinfo
.pkt_len
);
172 switch (tca
->tca_code
) {
182 if (af
== AF_INET6
) {
183 struct ip6_hdr
*ip6
= (struct ip6_hdr
*)ip
;
186 flowlabel
= ntohl(ip6
->ip6_flow
);
187 flowlabel
= (tca
->tca_dscp
<< 20) |
188 (flowlabel
& ~(DSCP_MASK
<< 20));
189 ip6
->ip6_flow
= htonl(flowlabel
);
192 ip
->ip_tos
= tca
->tca_dscp
|
193 (ip
->ip_tos
& DSCP_CUMASK
);
197 tca
= (*cb
->cb_input
)(cb
, &pktinfo
);
206 static struct top_cdnr
*
207 tcb_lookup(char *ifname
)
209 struct top_cdnr
*top
;
212 if ((ifp
= ifunit(ifname
)) != NULL
)
213 LIST_FOREACH(top
, &tcb_list
, tc_next
)
214 if (top
->tc_ifq
->altq_ifp
== ifp
)
219 static struct cdnr_block
*
220 cdnr_handle2cb(u_long handle
)
222 struct cdnr_block
*cb
;
224 cb
= (struct cdnr_block
*)handle
;
225 if (handle
!= ALIGN(cb
))
228 if (cb
== NULL
|| cb
->cb_handle
!= handle
)
234 cdnr_cb2handle(struct cdnr_block
*cb
)
236 return (cb
->cb_handle
);
240 cdnr_cballoc(struct top_cdnr
*top
, int type
, struct tc_action
*(*input_func
)(
241 struct cdnr_block
*, struct cdnr_pktinfo
*))
243 struct cdnr_block
*cb
;
248 size
= sizeof(struct top_cdnr
);
250 case TCETYPE_ELEMENT
:
251 size
= sizeof(struct cdnr_block
);
253 case TCETYPE_TBMETER
:
254 size
= sizeof(struct tbmeter
);
257 size
= sizeof(struct trtcm
);
260 size
= sizeof(struct tswtcm
);
266 cb
= malloc(size
, M_DEVBUF
, M_WAITOK
|M_ZERO
);
273 cb
->cb_handle
= (u_long
)cb
;
275 cb
->cb_top
= (struct top_cdnr
*)cb
;
279 if (input_func
!= NULL
) {
281 * if this cdnr has an action function,
282 * make tc_action to call itself.
284 cb
->cb_action
.tca_code
= TCACODE_NEXT
;
285 cb
->cb_action
.tca_next
= cb
;
286 cb
->cb_input
= input_func
;
288 cb
->cb_action
.tca_code
= TCACODE_NONE
;
290 /* if this isn't top, register the element to the top level cdnr */
292 LIST_INSERT_HEAD(&top
->tc_elements
, cb
, cb_next
);
298 cdnr_cbdestroy(void *cblock
)
300 struct cdnr_block
*cb
= cblock
;
302 /* delete filters belonging to this cdnr */
303 acc_discard_filters(&cb
->cb_top
->tc_classifier
, cb
, 0);
305 /* remove from the top level cdnr */
306 if (cb
->cb_top
!= cblock
)
307 LIST_REMOVE(cb
, cb_next
);
313 * conditioner common destroy routine
316 generic_element_destroy(struct cdnr_block
*cb
)
320 switch (cb
->cb_type
) {
322 error
= top_destroy((struct top_cdnr
*)cb
);
324 case TCETYPE_ELEMENT
:
325 error
= element_destroy(cb
);
327 case TCETYPE_TBMETER
:
328 error
= tbm_destroy((struct tbmeter
*)cb
);
331 error
= trtcm_destroy((struct trtcm
*)cb
);
334 error
= tswtcm_destroy((struct tswtcm
*)cb
);
343 tca_verify_action(struct tc_action
*utca
)
345 switch (utca
->tca_code
) {
353 /* verify handle value */
354 if (cdnr_handle2cb(utca
->tca_handle
) == NULL
)
362 /* should not be passed from a user */
369 tca_import_action(struct tc_action
*ktca
, struct tc_action
*utca
)
371 struct cdnr_block
*cb
;
374 if (ktca
->tca_code
== TCACODE_HANDLE
) {
375 cb
= cdnr_handle2cb(ktca
->tca_handle
);
377 ktca
->tca_code
= TCACODE_NONE
;
380 ktca
->tca_code
= TCACODE_NEXT
;
383 } else if (ktca
->tca_code
== TCACODE_MARK
) {
384 ktca
->tca_dscp
&= DSCP_MASK
;
390 tca_invalidate_action(struct tc_action
*tca
)
392 struct cdnr_block
*cb
;
394 if (tca
->tca_code
== TCACODE_NEXT
) {
400 tca
->tca_code
= TCACODE_NONE
;
404 * top level traffic conditioner
406 static struct top_cdnr
*
407 top_create(struct ifaltq
*ifq
)
409 struct top_cdnr
*top
;
411 if ((top
= cdnr_cballoc(NULL
, TCETYPE_TOP
, NULL
)) == NULL
)
415 /* set default action for the top level conditioner */
416 top
->tc_block
.cb_action
.tca_code
= TCACODE_PASS
;
418 LIST_INSERT_HEAD(&tcb_list
, top
, tc_next
);
420 ifq
->altq_cdnr
= top
;
426 top_destroy(struct top_cdnr
*top
)
428 struct cdnr_block
*cb
;
430 if (ALTQ_IS_CNDTNING(top
->tc_ifq
))
431 ALTQ_CLEAR_CNDTNING(top
->tc_ifq
);
432 top
->tc_ifq
->altq_cdnr
= NULL
;
435 * destroy all the conditioner elements belonging to this interface
437 while ((cb
= LIST_FIRST(&top
->tc_elements
)) != NULL
) {
438 while (cb
!= NULL
&& cb
->cb_ref
> 0)
439 cb
= LIST_NEXT(cb
, cb_next
);
441 generic_element_destroy(cb
);
444 LIST_REMOVE(top
, tc_next
);
448 /* if there is no active conditioner, remove the input hook */
449 if (altq_input
!= NULL
) {
450 LIST_FOREACH(top
, &tcb_list
, tc_next
)
451 if (ALTQ_IS_CNDTNING(top
->tc_ifq
))
461 * simple tc elements without input function (e.g., dropper and makers).
463 static struct cdnr_block
*
464 element_create(struct top_cdnr
*top
, struct tc_action
*action
)
466 struct cdnr_block
*cb
;
468 if (tca_verify_action(action
) < 0)
471 if ((cb
= cdnr_cballoc(top
, TCETYPE_ELEMENT
, NULL
)) == NULL
)
474 tca_import_action(&cb
->cb_action
, action
);
480 element_destroy(struct cdnr_block
*cb
)
485 tca_invalidate_action(&cb
->cb_action
);
492 * internal representation of token bucket parameters
493 * rate: byte_per_unittime << 32
494 * (((bits_per_sec) / 8) << 32) / machclk_freq
499 #define TB_SCALE(x) ((u_int64_t)(x) << TB_SHIFT)
500 #define TB_UNSCALE(x) ((x) >> TB_SHIFT)
503 tb_import_profile(struct tbe
*tb
, struct tb_profile
*profile
)
505 tb
->rate
= TB_SCALE(profile
->rate
/ 8) / machclk_freq
;
506 tb
->depth
= TB_SCALE(profile
->depth
);
508 tb
->filluptime
= tb
->depth
/ tb
->rate
;
510 tb
->filluptime
= 0xffffffffffffffffLL
;
511 tb
->token
= tb
->depth
;
512 tb
->last
= read_machclk();
516 * simple token bucket meter
518 static struct tbmeter
*
519 tbm_create(struct top_cdnr
*top
, struct tb_profile
*profile
,
520 struct tc_action
*in_action
, struct tc_action
*out_action
)
522 struct tbmeter
*tbm
= NULL
;
524 if (tca_verify_action(in_action
) < 0
525 || tca_verify_action(out_action
) < 0)
528 if ((tbm
= cdnr_cballoc(top
, TCETYPE_TBMETER
,
532 tb_import_profile(&tbm
->tb
, profile
);
534 tca_import_action(&tbm
->in_action
, in_action
);
535 tca_import_action(&tbm
->out_action
, out_action
);
541 tbm_destroy(struct tbmeter
*tbm
)
543 if (tbm
->cdnrblk
.cb_ref
> 0)
546 tca_invalidate_action(&tbm
->in_action
);
547 tca_invalidate_action(&tbm
->out_action
);
553 static struct tc_action
*
554 tbm_input(struct cdnr_block
*cb
, struct cdnr_pktinfo
*pktinfo
)
556 struct tbmeter
*tbm
= (struct tbmeter
*)cb
;
558 u_int64_t interval
, now
;
560 len
= TB_SCALE(pktinfo
->pkt_len
);
562 if (tbm
->tb
.token
< len
) {
563 now
= read_machclk();
564 interval
= now
- tbm
->tb
.last
;
565 if (interval
>= tbm
->tb
.filluptime
)
566 tbm
->tb
.token
= tbm
->tb
.depth
;
568 tbm
->tb
.token
+= interval
* tbm
->tb
.rate
;
569 if (tbm
->tb
.token
> tbm
->tb
.depth
)
570 tbm
->tb
.token
= tbm
->tb
.depth
;
575 if (tbm
->tb
.token
< len
) {
576 PKTCNTR_ADD(&tbm
->out_cnt
, pktinfo
->pkt_len
);
577 return (&tbm
->out_action
);
580 tbm
->tb
.token
-= len
;
581 PKTCNTR_ADD(&tbm
->in_cnt
, pktinfo
->pkt_len
);
582 return (&tbm
->in_action
);
586 * two rate three color marker
587 * as described in draft-heinanen-diffserv-trtcm-01.txt
589 static struct trtcm
*
590 trtcm_create(struct top_cdnr
*top
, struct tb_profile
*cmtd_profile
,
591 struct tb_profile
*peak_profile
, struct tc_action
*green_action
,
592 struct tc_action
*yellow_action
, struct tc_action
*red_action
,
595 struct trtcm
*tcm
= NULL
;
597 if (tca_verify_action(green_action
) < 0
598 || tca_verify_action(yellow_action
) < 0
599 || tca_verify_action(red_action
) < 0)
602 if ((tcm
= cdnr_cballoc(top
, TCETYPE_TRTCM
,
603 trtcm_input
)) == NULL
)
606 tb_import_profile(&tcm
->cmtd_tb
, cmtd_profile
);
607 tb_import_profile(&tcm
->peak_tb
, peak_profile
);
609 tca_import_action(&tcm
->green_action
, green_action
);
610 tca_import_action(&tcm
->yellow_action
, yellow_action
);
611 tca_import_action(&tcm
->red_action
, red_action
);
613 /* set dscps to use */
614 if (tcm
->green_action
.tca_code
== TCACODE_MARK
)
615 tcm
->green_dscp
= tcm
->green_action
.tca_dscp
& DSCP_MASK
;
617 tcm
->green_dscp
= DSCP_AF11
;
618 if (tcm
->yellow_action
.tca_code
== TCACODE_MARK
)
619 tcm
->yellow_dscp
= tcm
->yellow_action
.tca_dscp
& DSCP_MASK
;
621 tcm
->yellow_dscp
= DSCP_AF12
;
622 if (tcm
->red_action
.tca_code
== TCACODE_MARK
)
623 tcm
->red_dscp
= tcm
->red_action
.tca_dscp
& DSCP_MASK
;
625 tcm
->red_dscp
= DSCP_AF13
;
627 tcm
->coloraware
= coloraware
;
633 trtcm_destroy(struct trtcm
*tcm
)
635 if (tcm
->cdnrblk
.cb_ref
> 0)
638 tca_invalidate_action(&tcm
->green_action
);
639 tca_invalidate_action(&tcm
->yellow_action
);
640 tca_invalidate_action(&tcm
->red_action
);
646 static struct tc_action
*
647 trtcm_input(struct cdnr_block
*cb
, struct cdnr_pktinfo
*pktinfo
)
649 struct trtcm
*tcm
= (struct trtcm
*)cb
;
651 u_int64_t interval
, now
;
654 len
= TB_SCALE(pktinfo
->pkt_len
);
655 if (tcm
->coloraware
) {
656 color
= pktinfo
->pkt_dscp
;
657 if (color
!= tcm
->yellow_dscp
&& color
!= tcm
->red_dscp
)
658 color
= tcm
->green_dscp
;
660 /* if color-blind, precolor it as green */
661 color
= tcm
->green_dscp
;
664 now
= read_machclk();
665 if (tcm
->cmtd_tb
.token
< len
) {
666 interval
= now
- tcm
->cmtd_tb
.last
;
667 if (interval
>= tcm
->cmtd_tb
.filluptime
)
668 tcm
->cmtd_tb
.token
= tcm
->cmtd_tb
.depth
;
670 tcm
->cmtd_tb
.token
+= interval
* tcm
->cmtd_tb
.rate
;
671 if (tcm
->cmtd_tb
.token
> tcm
->cmtd_tb
.depth
)
672 tcm
->cmtd_tb
.token
= tcm
->cmtd_tb
.depth
;
674 tcm
->cmtd_tb
.last
= now
;
676 if (tcm
->peak_tb
.token
< len
) {
677 interval
= now
- tcm
->peak_tb
.last
;
678 if (interval
>= tcm
->peak_tb
.filluptime
)
679 tcm
->peak_tb
.token
= tcm
->peak_tb
.depth
;
681 tcm
->peak_tb
.token
+= interval
* tcm
->peak_tb
.rate
;
682 if (tcm
->peak_tb
.token
> tcm
->peak_tb
.depth
)
683 tcm
->peak_tb
.token
= tcm
->peak_tb
.depth
;
685 tcm
->peak_tb
.last
= now
;
688 if (color
== tcm
->red_dscp
|| tcm
->peak_tb
.token
< len
) {
689 pktinfo
->pkt_dscp
= tcm
->red_dscp
;
690 PKTCNTR_ADD(&tcm
->red_cnt
, pktinfo
->pkt_len
);
691 return (&tcm
->red_action
);
694 if (color
== tcm
->yellow_dscp
|| tcm
->cmtd_tb
.token
< len
) {
695 pktinfo
->pkt_dscp
= tcm
->yellow_dscp
;
696 tcm
->peak_tb
.token
-= len
;
697 PKTCNTR_ADD(&tcm
->yellow_cnt
, pktinfo
->pkt_len
);
698 return (&tcm
->yellow_action
);
701 pktinfo
->pkt_dscp
= tcm
->green_dscp
;
702 tcm
->cmtd_tb
.token
-= len
;
703 tcm
->peak_tb
.token
-= len
;
704 PKTCNTR_ADD(&tcm
->green_cnt
, pktinfo
->pkt_len
);
705 return (&tcm
->green_action
);
709 * time sliding window three color marker
710 * as described in draft-fang-diffserv-tc-tswtcm-00.txt
712 static struct tswtcm
*
713 tswtcm_create(struct top_cdnr
*top
, u_int32_t cmtd_rate
, u_int32_t peak_rate
,
714 u_int32_t avg_interval
, struct tc_action
*green_action
,
715 struct tc_action
*yellow_action
, struct tc_action
*red_action
)
719 if (tca_verify_action(green_action
) < 0
720 || tca_verify_action(yellow_action
) < 0
721 || tca_verify_action(red_action
) < 0)
724 if ((tsw
= cdnr_cballoc(top
, TCETYPE_TSWTCM
,
725 tswtcm_input
)) == NULL
)
728 tca_import_action(&tsw
->green_action
, green_action
);
729 tca_import_action(&tsw
->yellow_action
, yellow_action
);
730 tca_import_action(&tsw
->red_action
, red_action
);
732 /* set dscps to use */
733 if (tsw
->green_action
.tca_code
== TCACODE_MARK
)
734 tsw
->green_dscp
= tsw
->green_action
.tca_dscp
& DSCP_MASK
;
736 tsw
->green_dscp
= DSCP_AF11
;
737 if (tsw
->yellow_action
.tca_code
== TCACODE_MARK
)
738 tsw
->yellow_dscp
= tsw
->yellow_action
.tca_dscp
& DSCP_MASK
;
740 tsw
->yellow_dscp
= DSCP_AF12
;
741 if (tsw
->red_action
.tca_code
== TCACODE_MARK
)
742 tsw
->red_dscp
= tsw
->red_action
.tca_dscp
& DSCP_MASK
;
744 tsw
->red_dscp
= DSCP_AF13
;
746 /* convert rates from bits/sec to bytes/sec */
747 tsw
->cmtd_rate
= cmtd_rate
/ 8;
748 tsw
->peak_rate
= peak_rate
/ 8;
751 /* timewin is converted from msec to machine clock unit */
752 tsw
->timewin
= (u_int64_t
)machclk_freq
* avg_interval
/ 1000;
758 tswtcm_destroy(struct tswtcm
*tsw
)
760 if (tsw
->cdnrblk
.cb_ref
> 0)
763 tca_invalidate_action(&tsw
->green_action
);
764 tca_invalidate_action(&tsw
->yellow_action
);
765 tca_invalidate_action(&tsw
->red_action
);
771 static struct tc_action
*
772 tswtcm_input(struct cdnr_block
*cb
, struct cdnr_pktinfo
*pktinfo
)
774 struct tswtcm
*tsw
= (struct tswtcm
*)cb
;
777 u_int64_t interval
, now
, tmp
;
782 len
= pktinfo
->pkt_len
;
783 now
= read_machclk();
785 interval
= now
- tsw
->t_front
;
787 * calculate average rate:
788 * avg = (avg * timewin + pkt_len)/(timewin + interval)
789 * pkt_len needs to be multiplied by machclk_freq in order to
791 * note: when avg_rate (bytes/sec) and timewin (machclk unit) are
792 * less than 32 bits, the following 64-bit operation has enough
795 tmp
= ((u_int64_t
)tsw
->avg_rate
* tsw
->timewin
796 + (u_int64_t
)len
* machclk_freq
) / (tsw
->timewin
+ interval
);
797 tsw
->avg_rate
= avg_rate
= (u_int32_t
)tmp
;
803 if (avg_rate
> tsw
->cmtd_rate
) {
804 u_int32_t randval
= arc4random() % avg_rate
;
806 if (avg_rate
> tsw
->peak_rate
) {
807 if (randval
< avg_rate
- tsw
->peak_rate
) {
809 pktinfo
->pkt_dscp
= tsw
->red_dscp
;
810 PKTCNTR_ADD(&tsw
->red_cnt
, len
);
811 return (&tsw
->red_action
);
812 } else if (randval
< avg_rate
- tsw
->cmtd_rate
)
815 /* peak_rate >= avg_rate > cmtd_rate */
816 if (randval
< avg_rate
- tsw
->cmtd_rate
) {
818 pktinfo
->pkt_dscp
= tsw
->yellow_dscp
;
819 PKTCNTR_ADD(&tsw
->yellow_cnt
, len
);
820 return (&tsw
->yellow_action
);
826 pktinfo
->pkt_dscp
= tsw
->green_dscp
;
827 PKTCNTR_ADD(&tsw
->green_cnt
, len
);
828 return (&tsw
->green_action
);
835 cdnrcmd_if_attach(char *ifname
)
838 struct top_cdnr
*top
;
840 if ((ifp
= ifunit(ifname
)) == NULL
)
843 if (ifp
->if_snd
.altq_cdnr
!= NULL
)
846 if ((top
= top_create(&ifp
->if_snd
)) == NULL
)
852 cdnrcmd_if_detach(char *ifname
)
854 struct top_cdnr
*top
;
856 if ((top
= tcb_lookup(ifname
)) == NULL
)
859 return top_destroy(top
);
863 cdnrcmd_add_element(struct cdnr_add_element
*ap
)
865 struct top_cdnr
*top
;
866 struct cdnr_block
*cb
;
868 if ((top
= tcb_lookup(ap
->iface
.cdnr_ifname
)) == NULL
)
871 cb
= element_create(top
, &ap
->action
);
874 /* return a class handle to the user */
875 ap
->cdnr_handle
= cdnr_cb2handle(cb
);
880 cdnrcmd_delete_element(struct cdnr_delete_element
*ap
)
882 struct top_cdnr
*top
;
883 struct cdnr_block
*cb
;
885 if ((top
= tcb_lookup(ap
->iface
.cdnr_ifname
)) == NULL
)
888 if ((cb
= cdnr_handle2cb(ap
->cdnr_handle
)) == NULL
)
891 if (cb
->cb_type
!= TCETYPE_ELEMENT
)
892 return generic_element_destroy(cb
);
894 return element_destroy(cb
);
898 cdnrcmd_add_filter(struct cdnr_add_filter
*ap
)
900 struct top_cdnr
*top
;
901 struct cdnr_block
*cb
;
903 if ((top
= tcb_lookup(ap
->iface
.cdnr_ifname
)) == NULL
)
906 if ((cb
= cdnr_handle2cb(ap
->cdnr_handle
)) == NULL
)
909 return acc_add_filter(&top
->tc_classifier
, &ap
->filter
,
910 cb
, &ap
->filter_handle
);
914 cdnrcmd_delete_filter(struct cdnr_delete_filter
*ap
)
916 struct top_cdnr
*top
;
918 if ((top
= tcb_lookup(ap
->iface
.cdnr_ifname
)) == NULL
)
921 return acc_delete_filter(&top
->tc_classifier
, ap
->filter_handle
);
925 cdnrcmd_add_tbm(struct cdnr_add_tbmeter
*ap
)
927 struct top_cdnr
*top
;
930 if ((top
= tcb_lookup(ap
->iface
.cdnr_ifname
)) == NULL
)
933 tbm
= tbm_create(top
, &ap
->profile
, &ap
->in_action
, &ap
->out_action
);
936 /* return a class handle to the user */
937 ap
->cdnr_handle
= cdnr_cb2handle(&tbm
->cdnrblk
);
942 cdnrcmd_modify_tbm(struct cdnr_modify_tbmeter
*ap
)
946 if ((tbm
= (struct tbmeter
*)cdnr_handle2cb(ap
->cdnr_handle
)) == NULL
)
949 tb_import_profile(&tbm
->tb
, &ap
->profile
);
955 cdnrcmd_tbm_stats(struct cdnr_tbmeter_stats
*ap
)
959 if ((tbm
= (struct tbmeter
*)cdnr_handle2cb(ap
->cdnr_handle
)) == NULL
)
962 ap
->in_cnt
= tbm
->in_cnt
;
963 ap
->out_cnt
= tbm
->out_cnt
;
969 cdnrcmd_add_trtcm(struct cdnr_add_trtcm
*ap
)
971 struct top_cdnr
*top
;
974 if ((top
= tcb_lookup(ap
->iface
.cdnr_ifname
)) == NULL
)
977 tcm
= trtcm_create(top
, &ap
->cmtd_profile
, &ap
->peak_profile
,
978 &ap
->green_action
, &ap
->yellow_action
,
979 &ap
->red_action
, ap
->coloraware
);
983 /* return a class handle to the user */
984 ap
->cdnr_handle
= cdnr_cb2handle(&tcm
->cdnrblk
);
989 cdnrcmd_modify_trtcm(struct cdnr_modify_trtcm
*ap
)
993 if ((tcm
= (struct trtcm
*)cdnr_handle2cb(ap
->cdnr_handle
)) == NULL
)
996 tb_import_profile(&tcm
->cmtd_tb
, &ap
->cmtd_profile
);
997 tb_import_profile(&tcm
->peak_tb
, &ap
->peak_profile
);
1003 cdnrcmd_tcm_stats(struct cdnr_tcm_stats
*ap
)
1005 struct cdnr_block
*cb
;
1007 if ((cb
= cdnr_handle2cb(ap
->cdnr_handle
)) == NULL
)
1010 if (cb
->cb_type
== TCETYPE_TRTCM
) {
1011 struct trtcm
*tcm
= (struct trtcm
*)cb
;
1013 ap
->green_cnt
= tcm
->green_cnt
;
1014 ap
->yellow_cnt
= tcm
->yellow_cnt
;
1015 ap
->red_cnt
= tcm
->red_cnt
;
1016 } else if (cb
->cb_type
== TCETYPE_TSWTCM
) {
1017 struct tswtcm
*tsw
= (struct tswtcm
*)cb
;
1019 ap
->green_cnt
= tsw
->green_cnt
;
1020 ap
->yellow_cnt
= tsw
->yellow_cnt
;
1021 ap
->red_cnt
= tsw
->red_cnt
;
1029 cdnrcmd_add_tswtcm(struct cdnr_add_tswtcm
*ap
)
1031 struct top_cdnr
*top
;
1034 if ((top
= tcb_lookup(ap
->iface
.cdnr_ifname
)) == NULL
)
1037 if (ap
->cmtd_rate
> ap
->peak_rate
)
1040 tsw
= tswtcm_create(top
, ap
->cmtd_rate
, ap
->peak_rate
,
1041 ap
->avg_interval
, &ap
->green_action
,
1042 &ap
->yellow_action
, &ap
->red_action
);
1046 /* return a class handle to the user */
1047 ap
->cdnr_handle
= cdnr_cb2handle(&tsw
->cdnrblk
);
1052 cdnrcmd_modify_tswtcm(struct cdnr_modify_tswtcm
*ap
)
1056 if ((tsw
= (struct tswtcm
*)cdnr_handle2cb(ap
->cdnr_handle
)) == NULL
)
1059 if (ap
->cmtd_rate
> ap
->peak_rate
)
1062 /* convert rates from bits/sec to bytes/sec */
1063 tsw
->cmtd_rate
= ap
->cmtd_rate
/ 8;
1064 tsw
->peak_rate
= ap
->peak_rate
/ 8;
1067 /* timewin is converted from msec to machine clock unit */
1068 tsw
->timewin
= (u_int64_t
)machclk_freq
* ap
->avg_interval
/ 1000;
1074 cdnrcmd_get_stats(struct cdnr_get_stats
*ap
)
1076 struct top_cdnr
*top
;
1077 struct cdnr_block
*cb
;
1078 struct tbmeter
*tbm
;
1081 struct tce_stats tce
, *usp
;
1082 int error
, n
, nskip
, nelements
;
1084 if ((top
= tcb_lookup(ap
->iface
.cdnr_ifname
)) == NULL
)
1087 /* copy action stats */
1088 (void)memcpy(ap
->cnts
, top
->tc_cnts
, sizeof(ap
->cnts
));
1090 /* stats for each element */
1091 nelements
= ap
->nelements
;
1092 usp
= ap
->tce_stats
;
1093 if (nelements
<= 0 || usp
== NULL
)
1098 LIST_FOREACH(cb
, &top
->tc_elements
, cb_next
) {
1104 (void)memset(&tce
, 0, sizeof(tce
));
1105 tce
.tce_handle
= cb
->cb_handle
;
1106 tce
.tce_type
= cb
->cb_type
;
1107 switch (cb
->cb_type
) {
1108 case TCETYPE_TBMETER
:
1109 tbm
= (struct tbmeter
*)cb
;
1110 tce
.tce_cnts
[0] = tbm
->in_cnt
;
1111 tce
.tce_cnts
[1] = tbm
->out_cnt
;
1114 tcm
= (struct trtcm
*)cb
;
1115 tce
.tce_cnts
[0] = tcm
->green_cnt
;
1116 tce
.tce_cnts
[1] = tcm
->yellow_cnt
;
1117 tce
.tce_cnts
[2] = tcm
->red_cnt
;
1119 case TCETYPE_TSWTCM
:
1120 tsw
= (struct tswtcm
*)cb
;
1121 tce
.tce_cnts
[0] = tsw
->green_cnt
;
1122 tce
.tce_cnts
[1] = tsw
->yellow_cnt
;
1123 tce
.tce_cnts
[2] = tsw
->red_cnt
;
1129 if ((error
= copyout((void *)&tce
, (void *)usp
++,
1133 if (++n
== nelements
)
1142 * conditioner device interface
1145 cdnropen(dev_t dev
, int flag
, int fmt
,
1148 if (machclk_freq
== 0)
1151 if (machclk_freq
== 0) {
1152 printf("cdnr: no CPU clock available!\n");
1156 /* everything will be done when the queueing scheme is attached. */
1161 cdnrclose(dev_t dev
, int flag
, int fmt
,
1164 struct top_cdnr
*top
;
1167 while ((top
= LIST_FIRST(&tcb_list
)) != NULL
) {
1169 err
= top_destroy(top
);
1170 if (err
!= 0 && error
== 0)
1179 cdnrioctl(dev_t dev
, ioctlcmd_t cmd
, void *addr
, int flag
,
1182 struct top_cdnr
*top
;
1183 struct cdnr_interface
*ifacep
;
1186 /* check super-user privilege */
1191 #if (__FreeBSD_version > 400000)
1192 if ((error
= suser(p
)) != 0)
1194 if ((error
= kauth_authorize_network(l
->l_cred
,
1195 KAUTH_NETWORK_ALTQ
, KAUTH_REQ_NETWORK_ALTQ_CDNR
, NULL
,
1205 case CDNR_IF_ATTACH
:
1206 ifacep
= (struct cdnr_interface
*)addr
;
1207 error
= cdnrcmd_if_attach(ifacep
->cdnr_ifname
);
1210 case CDNR_IF_DETACH
:
1211 ifacep
= (struct cdnr_interface
*)addr
;
1212 error
= cdnrcmd_if_detach(ifacep
->cdnr_ifname
);
1217 ifacep
= (struct cdnr_interface
*)addr
;
1218 if ((top
= tcb_lookup(ifacep
->cdnr_ifname
)) == NULL
) {
1226 ALTQ_SET_CNDTNING(top
->tc_ifq
);
1227 if (altq_input
== NULL
)
1228 altq_input
= altq_cdnr_input
;
1232 ALTQ_CLEAR_CNDTNING(top
->tc_ifq
);
1233 LIST_FOREACH(top
, &tcb_list
, tc_next
)
1234 if (ALTQ_IS_CNDTNING(top
->tc_ifq
))
1243 error
= cdnrcmd_add_element((struct cdnr_add_element
*)addr
);
1247 error
= cdnrcmd_delete_element((struct cdnr_delete_element
*)addr
);
1251 error
= cdnrcmd_add_tbm((struct cdnr_add_tbmeter
*)addr
);
1255 error
= cdnrcmd_modify_tbm((struct cdnr_modify_tbmeter
*)addr
);
1258 case CDNR_TBM_STATS
:
1259 error
= cdnrcmd_tbm_stats((struct cdnr_tbmeter_stats
*)addr
);
1263 error
= cdnrcmd_add_trtcm((struct cdnr_add_trtcm
*)addr
);
1267 error
= cdnrcmd_modify_trtcm((struct cdnr_modify_trtcm
*)addr
);
1270 case CDNR_TCM_STATS
:
1271 error
= cdnrcmd_tcm_stats((struct cdnr_tcm_stats
*)addr
);
1274 case CDNR_ADD_FILTER
:
1275 error
= cdnrcmd_add_filter((struct cdnr_add_filter
*)addr
);
1278 case CDNR_DEL_FILTER
:
1279 error
= cdnrcmd_delete_filter((struct cdnr_delete_filter
*)addr
);
1283 error
= cdnrcmd_get_stats((struct cdnr_get_stats
*)addr
);
1287 error
= cdnrcmd_add_tswtcm((struct cdnr_add_tswtcm
*)addr
);
1291 error
= cdnrcmd_modify_tswtcm((struct cdnr_modify_tswtcm
*)addr
);
1305 static struct altqsw cdnr_sw
=
1306 {"cdnr", cdnropen
, cdnrclose
, cdnrioctl
};
1308 ALTQ_MODULE(altq_cdnr
, ALTQT_CDNR
, &cdnr_sw
);
1310 #endif /* KLD_MODULE */
1312 #endif /* ALTQ3_COMPAT */
1313 #endif /* ALTQ_CDNR */