2 * Copyright (C) 1999-2002
3 * Sony Computer Science Laboratories Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $KAME: altq_cdnr.c,v 1.15 2005/04/13 03:44:24 suz Exp $
32 #include "opt_inet6.h"
34 #include <sys/param.h>
35 #include <sys/malloc.h>
37 #include <sys/socket.h>
38 #include <sys/sockio.h>
39 #include <sys/systm.h>
41 #include <sys/errno.h>
42 #include <sys/kernel.h>
43 #include <sys/queue.h>
46 #include <net/if_types.h>
47 #include <netinet/in.h>
48 #include <netinet/in_systm.h>
49 #include <netinet/ip.h>
51 #include <netinet/ip6.h>
54 #include <net/altq/if_altq.h>
55 #include <net/altq/altq.h>
57 #include <net/altq/altq_conf.h>
59 #include <net/altq/altq_cdnr.h>
63 * diffserv traffic conditioning module
66 int altq_cdnr_enabled = 0;
68 /* traffic conditioner is enabled by ALTQ_CDNR option in opt_altq.h */
71 /* cdnr_list keeps all cdnr's allocated. */
72 static LIST_HEAD(, top_cdnr) tcb_list;
74 static int altq_cdnr_input(struct mbuf *, int);
75 static struct top_cdnr *tcb_lookup(char *ifname);
76 static struct cdnr_block *cdnr_handle2cb(u_long);
77 static u_long cdnr_cb2handle(struct cdnr_block *);
78 static void *cdnr_cballoc(struct top_cdnr *, int,
79 struct tc_action *(*)(struct cdnr_block *, struct cdnr_pktinfo *));
80 static void cdnr_cbdestroy(void *);
81 static int tca_verify_action(struct tc_action *);
82 static void tca_import_action(struct tc_action *, struct tc_action *);
83 static void tca_invalidate_action(struct tc_action *);
85 static int generic_element_destroy(struct cdnr_block *);
86 static struct top_cdnr *top_create(struct ifaltq *);
87 static int top_destroy(struct top_cdnr *);
88 static struct cdnr_block *element_create(struct top_cdnr *, struct tc_action *);
89 static int element_destroy(struct cdnr_block *);
90 static void tb_import_profile(struct tbe *, struct tb_profile *);
91 static struct tbmeter *tbm_create(struct top_cdnr *, struct tb_profile *,
92 struct tc_action *, struct tc_action *);
93 static int tbm_destroy(struct tbmeter *);
94 static struct tc_action *tbm_input(struct cdnr_block *, struct cdnr_pktinfo *);
95 static struct trtcm *trtcm_create(struct top_cdnr *,
96 struct tb_profile *, struct tb_profile *,
97 struct tc_action *, struct tc_action *, struct tc_action *,
99 static int trtcm_destroy(struct trtcm *);
100 static struct tc_action *trtcm_input(struct cdnr_block *, struct cdnr_pktinfo *);
101 static struct tswtcm *tswtcm_create(struct top_cdnr *,
102 u_int32_t, u_int32_t, u_int32_t,
103 struct tc_action *, struct tc_action *, struct tc_action *);
104 static int tswtcm_destroy(struct tswtcm *);
105 static struct tc_action *tswtcm_input(struct cdnr_block *, struct cdnr_pktinfo *);
107 static int cdnrcmd_if_attach(char *);
108 static int cdnrcmd_if_detach(char *);
109 static int cdnrcmd_add_element(struct cdnr_add_element *);
110 static int cdnrcmd_delete_element(struct cdnr_delete_element *);
111 static int cdnrcmd_add_filter(struct cdnr_add_filter *);
112 static int cdnrcmd_delete_filter(struct cdnr_delete_filter *);
113 static int cdnrcmd_add_tbm(struct cdnr_add_tbmeter *);
114 static int cdnrcmd_modify_tbm(struct cdnr_modify_tbmeter *);
115 static int cdnrcmd_tbm_stats(struct cdnr_tbmeter_stats *);
116 static int cdnrcmd_add_trtcm(struct cdnr_add_trtcm *);
117 static int cdnrcmd_modify_trtcm(struct cdnr_modify_trtcm *);
118 static int cdnrcmd_tcm_stats(struct cdnr_tcm_stats *);
119 static int cdnrcmd_add_tswtcm(struct cdnr_add_tswtcm *);
120 static int cdnrcmd_modify_tswtcm(struct cdnr_modify_tswtcm *);
121 static int cdnrcmd_get_stats(struct cdnr_get_stats *);
126 * top level input function called from ip_input.
127 * should be called before converting header fields to host-byte-order.
130 altq_cdnr_input(m, af)
132 int af; /* address family */
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 *
210 struct top_cdnr *top;
213 if ((ifp = ifunit(ifname)) != NULL)
214 LIST_FOREACH(top, &tcb_list, tc_next)
215 if (top->tc_ifq->altq_ifp == ifp)
220 static struct cdnr_block *
221 cdnr_handle2cb(handle)
224 struct cdnr_block *cb;
226 cb = (struct cdnr_block *)handle;
227 if (handle != ALIGN(cb))
230 if (cb == NULL || cb->cb_handle != handle)
237 struct cdnr_block *cb;
239 return (cb->cb_handle);
243 cdnr_cballoc(top, type, input_func)
244 struct top_cdnr *top;
246 struct tc_action *(*input_func)(struct cdnr_block *,
247 struct cdnr_pktinfo *);
249 struct cdnr_block *cb;
254 size = sizeof(struct top_cdnr);
256 case TCETYPE_ELEMENT:
257 size = sizeof(struct cdnr_block);
259 case TCETYPE_TBMETER:
260 size = sizeof(struct tbmeter);
263 size = sizeof(struct trtcm);
266 size = sizeof(struct tswtcm);
272 cb = malloc(size, M_DEVBUF, M_WAITOK);
280 cb->cb_handle = (u_long)cb;
282 cb->cb_top = (struct top_cdnr *)cb;
286 if (input_func != NULL) {
288 * if this cdnr has an action function,
289 * make tc_action to call itself.
291 cb->cb_action.tca_code = TCACODE_NEXT;
292 cb->cb_action.tca_next = cb;
293 cb->cb_input = input_func;
295 cb->cb_action.tca_code = TCACODE_NONE;
297 /* if this isn't top, register the element to the top level cdnr */
299 LIST_INSERT_HEAD(&top->tc_elements, cb, cb_next);
305 cdnr_cbdestroy(cblock)
308 struct cdnr_block *cb = cblock;
310 /* delete filters belonging to this cdnr */
311 acc_discard_filters(&cb->cb_top->tc_classifier, cb, 0);
313 /* remove from the top level cdnr */
314 if (cb->cb_top != cblock)
315 LIST_REMOVE(cb, cb_next);
321 * conditioner common destroy routine
324 generic_element_destroy(cb)
325 struct cdnr_block *cb;
329 switch (cb->cb_type) {
331 error = top_destroy((struct top_cdnr *)cb);
333 case TCETYPE_ELEMENT:
334 error = element_destroy(cb);
336 case TCETYPE_TBMETER:
337 error = tbm_destroy((struct tbmeter *)cb);
340 error = trtcm_destroy((struct trtcm *)cb);
343 error = tswtcm_destroy((struct tswtcm *)cb);
352 tca_verify_action(utca)
353 struct tc_action *utca;
355 switch (utca->tca_code) {
363 /* verify handle value */
364 if (cdnr_handle2cb(utca->tca_handle) == NULL)
372 /* should not be passed from a user */
379 tca_import_action(ktca, utca)
380 struct tc_action *ktca, *utca;
382 struct cdnr_block *cb;
385 if (ktca->tca_code == TCACODE_HANDLE) {
386 cb = cdnr_handle2cb(ktca->tca_handle);
388 ktca->tca_code = TCACODE_NONE;
391 ktca->tca_code = TCACODE_NEXT;
394 } else if (ktca->tca_code == TCACODE_MARK) {
395 ktca->tca_dscp &= DSCP_MASK;
401 tca_invalidate_action(tca)
402 struct tc_action *tca;
404 struct cdnr_block *cb;
406 if (tca->tca_code == TCACODE_NEXT) {
412 tca->tca_code = TCACODE_NONE;
416 * top level traffic conditioner
418 static struct top_cdnr *
422 struct top_cdnr *top;
424 if ((top = cdnr_cballoc(NULL, TCETYPE_TOP, NULL)) == NULL)
428 /* set default action for the top level conditioner */
429 top->tc_block.cb_action.tca_code = TCACODE_PASS;
431 LIST_INSERT_HEAD(&tcb_list, top, tc_next);
433 ifq->altq_cdnr = top;
440 struct top_cdnr *top;
442 struct cdnr_block *cb;
444 if (ALTQ_IS_CNDTNING(top->tc_ifq))
445 ALTQ_CLEAR_CNDTNING(top->tc_ifq);
446 top->tc_ifq->altq_cdnr = NULL;
449 * destroy all the conditioner elements belonging to this interface
451 while ((cb = LIST_FIRST(&top->tc_elements)) != NULL) {
452 while (cb != NULL && cb->cb_ref > 0)
453 cb = LIST_NEXT(cb, cb_next);
455 generic_element_destroy(cb);
458 LIST_REMOVE(top, tc_next);
462 /* if there is no active conditioner, remove the input hook */
463 if (altq_input != NULL) {
464 LIST_FOREACH(top, &tcb_list, tc_next)
465 if (ALTQ_IS_CNDTNING(top->tc_ifq))
475 * simple tc elements without input function (e.g., dropper and makers).
477 static struct cdnr_block *
478 element_create(top, action)
479 struct top_cdnr *top;
480 struct tc_action *action;
482 struct cdnr_block *cb;
484 if (tca_verify_action(action) < 0)
487 if ((cb = cdnr_cballoc(top, TCETYPE_ELEMENT, NULL)) == NULL)
490 tca_import_action(&cb->cb_action, action);
497 struct cdnr_block *cb;
502 tca_invalidate_action(&cb->cb_action);
509 * internal representation of token bucket parameters
510 * rate: byte_per_unittime << 32
511 * (((bits_per_sec) / 8) << 32) / machclk_freq
516 #define TB_SCALE(x) ((u_int64_t)(x) << TB_SHIFT)
517 #define TB_UNSCALE(x) ((x) >> TB_SHIFT)
520 tb_import_profile(tb, profile)
522 struct tb_profile *profile;
524 tb->rate = TB_SCALE(profile->rate / 8) / machclk_freq;
525 tb->depth = TB_SCALE(profile->depth);
527 tb->filluptime = tb->depth / tb->rate;
529 tb->filluptime = 0xffffffffffffffffLL;
530 tb->token = tb->depth;
531 tb->last = read_machclk();
535 * simple token bucket meter
537 static struct tbmeter *
538 tbm_create(top, profile, in_action, out_action)
539 struct top_cdnr *top;
540 struct tb_profile *profile;
541 struct tc_action *in_action, *out_action;
543 struct tbmeter *tbm = NULL;
545 if (tca_verify_action(in_action) < 0
546 || tca_verify_action(out_action) < 0)
549 if ((tbm = cdnr_cballoc(top, TCETYPE_TBMETER,
553 tb_import_profile(&tbm->tb, profile);
555 tca_import_action(&tbm->in_action, in_action);
556 tca_import_action(&tbm->out_action, out_action);
565 if (tbm->cdnrblk.cb_ref > 0)
568 tca_invalidate_action(&tbm->in_action);
569 tca_invalidate_action(&tbm->out_action);
575 static struct tc_action *
576 tbm_input(cb, pktinfo)
577 struct cdnr_block *cb;
578 struct cdnr_pktinfo *pktinfo;
580 struct tbmeter *tbm = (struct tbmeter *)cb;
582 u_int64_t interval, now;
584 len = TB_SCALE(pktinfo->pkt_len);
586 if (tbm->tb.token < len) {
587 now = read_machclk();
588 interval = now - tbm->tb.last;
589 if (interval >= tbm->tb.filluptime)
590 tbm->tb.token = tbm->tb.depth;
592 tbm->tb.token += interval * tbm->tb.rate;
593 if (tbm->tb.token > tbm->tb.depth)
594 tbm->tb.token = tbm->tb.depth;
599 if (tbm->tb.token < len) {
600 PKTCNTR_ADD(&tbm->out_cnt, pktinfo->pkt_len);
601 return (&tbm->out_action);
604 tbm->tb.token -= len;
605 PKTCNTR_ADD(&tbm->in_cnt, pktinfo->pkt_len);
606 return (&tbm->in_action);
610 * two rate three color marker
611 * as described in draft-heinanen-diffserv-trtcm-01.txt
613 static struct trtcm *
614 trtcm_create(top, cmtd_profile, peak_profile,
615 green_action, yellow_action, red_action, coloraware)
616 struct top_cdnr *top;
617 struct tb_profile *cmtd_profile, *peak_profile;
618 struct tc_action *green_action, *yellow_action, *red_action;
621 struct trtcm *tcm = NULL;
623 if (tca_verify_action(green_action) < 0
624 || tca_verify_action(yellow_action) < 0
625 || tca_verify_action(red_action) < 0)
628 if ((tcm = cdnr_cballoc(top, TCETYPE_TRTCM,
629 trtcm_input)) == NULL)
632 tb_import_profile(&tcm->cmtd_tb, cmtd_profile);
633 tb_import_profile(&tcm->peak_tb, peak_profile);
635 tca_import_action(&tcm->green_action, green_action);
636 tca_import_action(&tcm->yellow_action, yellow_action);
637 tca_import_action(&tcm->red_action, red_action);
639 /* set dscps to use */
640 if (tcm->green_action.tca_code == TCACODE_MARK)
641 tcm->green_dscp = tcm->green_action.tca_dscp & DSCP_MASK;
643 tcm->green_dscp = DSCP_AF11;
644 if (tcm->yellow_action.tca_code == TCACODE_MARK)
645 tcm->yellow_dscp = tcm->yellow_action.tca_dscp & DSCP_MASK;
647 tcm->yellow_dscp = DSCP_AF12;
648 if (tcm->red_action.tca_code == TCACODE_MARK)
649 tcm->red_dscp = tcm->red_action.tca_dscp & DSCP_MASK;
651 tcm->red_dscp = DSCP_AF13;
653 tcm->coloraware = coloraware;
662 if (tcm->cdnrblk.cb_ref > 0)
665 tca_invalidate_action(&tcm->green_action);
666 tca_invalidate_action(&tcm->yellow_action);
667 tca_invalidate_action(&tcm->red_action);
673 static struct tc_action *
674 trtcm_input(cb, pktinfo)
675 struct cdnr_block *cb;
676 struct cdnr_pktinfo *pktinfo;
678 struct trtcm *tcm = (struct trtcm *)cb;
680 u_int64_t interval, now;
683 len = TB_SCALE(pktinfo->pkt_len);
684 if (tcm->coloraware) {
685 color = pktinfo->pkt_dscp;
686 if (color != tcm->yellow_dscp && color != tcm->red_dscp)
687 color = tcm->green_dscp;
689 /* if color-blind, precolor it as green */
690 color = tcm->green_dscp;
693 now = read_machclk();
694 if (tcm->cmtd_tb.token < len) {
695 interval = now - tcm->cmtd_tb.last;
696 if (interval >= tcm->cmtd_tb.filluptime)
697 tcm->cmtd_tb.token = tcm->cmtd_tb.depth;
699 tcm->cmtd_tb.token += interval * tcm->cmtd_tb.rate;
700 if (tcm->cmtd_tb.token > tcm->cmtd_tb.depth)
701 tcm->cmtd_tb.token = tcm->cmtd_tb.depth;
703 tcm->cmtd_tb.last = now;
705 if (tcm->peak_tb.token < len) {
706 interval = now - tcm->peak_tb.last;
707 if (interval >= tcm->peak_tb.filluptime)
708 tcm->peak_tb.token = tcm->peak_tb.depth;
710 tcm->peak_tb.token += interval * tcm->peak_tb.rate;
711 if (tcm->peak_tb.token > tcm->peak_tb.depth)
712 tcm->peak_tb.token = tcm->peak_tb.depth;
714 tcm->peak_tb.last = now;
717 if (color == tcm->red_dscp || tcm->peak_tb.token < len) {
718 pktinfo->pkt_dscp = tcm->red_dscp;
719 PKTCNTR_ADD(&tcm->red_cnt, pktinfo->pkt_len);
720 return (&tcm->red_action);
723 if (color == tcm->yellow_dscp || tcm->cmtd_tb.token < len) {
724 pktinfo->pkt_dscp = tcm->yellow_dscp;
725 tcm->peak_tb.token -= len;
726 PKTCNTR_ADD(&tcm->yellow_cnt, pktinfo->pkt_len);
727 return (&tcm->yellow_action);
730 pktinfo->pkt_dscp = tcm->green_dscp;
731 tcm->cmtd_tb.token -= len;
732 tcm->peak_tb.token -= len;
733 PKTCNTR_ADD(&tcm->green_cnt, pktinfo->pkt_len);
734 return (&tcm->green_action);
738 * time sliding window three color marker
739 * as described in draft-fang-diffserv-tc-tswtcm-00.txt
741 static struct tswtcm *
742 tswtcm_create(top, cmtd_rate, peak_rate, avg_interval,
743 green_action, yellow_action, red_action)
744 struct top_cdnr *top;
745 u_int32_t cmtd_rate, peak_rate, avg_interval;
746 struct tc_action *green_action, *yellow_action, *red_action;
750 if (tca_verify_action(green_action) < 0
751 || tca_verify_action(yellow_action) < 0
752 || tca_verify_action(red_action) < 0)
755 if ((tsw = cdnr_cballoc(top, TCETYPE_TSWTCM,
756 tswtcm_input)) == NULL)
759 tca_import_action(&tsw->green_action, green_action);
760 tca_import_action(&tsw->yellow_action, yellow_action);
761 tca_import_action(&tsw->red_action, red_action);
763 /* set dscps to use */
764 if (tsw->green_action.tca_code == TCACODE_MARK)
765 tsw->green_dscp = tsw->green_action.tca_dscp & DSCP_MASK;
767 tsw->green_dscp = DSCP_AF11;
768 if (tsw->yellow_action.tca_code == TCACODE_MARK)
769 tsw->yellow_dscp = tsw->yellow_action.tca_dscp & DSCP_MASK;
771 tsw->yellow_dscp = DSCP_AF12;
772 if (tsw->red_action.tca_code == TCACODE_MARK)
773 tsw->red_dscp = tsw->red_action.tca_dscp & DSCP_MASK;
775 tsw->red_dscp = DSCP_AF13;
777 /* convert rates from bits/sec to bytes/sec */
778 tsw->cmtd_rate = cmtd_rate / 8;
779 tsw->peak_rate = peak_rate / 8;
782 /* timewin is converted from msec to machine clock unit */
783 tsw->timewin = (u_int64_t)machclk_freq * avg_interval / 1000;
792 if (tsw->cdnrblk.cb_ref > 0)
795 tca_invalidate_action(&tsw->green_action);
796 tca_invalidate_action(&tsw->yellow_action);
797 tca_invalidate_action(&tsw->red_action);
803 static struct tc_action *
804 tswtcm_input(cb, pktinfo)
805 struct cdnr_block *cb;
806 struct cdnr_pktinfo *pktinfo;
808 struct tswtcm *tsw = (struct tswtcm *)cb;
811 u_int64_t interval, now, tmp;
816 len = pktinfo->pkt_len;
817 now = read_machclk();
819 interval = now - tsw->t_front;
821 * calculate average rate:
822 * avg = (avg * timewin + pkt_len)/(timewin + interval)
823 * pkt_len needs to be multiplied by machclk_freq in order to
825 * note: when avg_rate (bytes/sec) and timewin (machclk unit) are
826 * less than 32 bits, the following 64-bit operation has enough
829 tmp = ((u_int64_t)tsw->avg_rate * tsw->timewin
830 + (u_int64_t)len * machclk_freq) / (tsw->timewin + interval);
831 tsw->avg_rate = avg_rate = (u_int32_t)tmp;
837 if (avg_rate > tsw->cmtd_rate) {
838 u_int32_t randval = arc4random() % avg_rate;
840 if (avg_rate > tsw->peak_rate) {
841 if (randval < avg_rate - tsw->peak_rate) {
843 pktinfo->pkt_dscp = tsw->red_dscp;
844 PKTCNTR_ADD(&tsw->red_cnt, len);
845 return (&tsw->red_action);
846 } else if (randval < avg_rate - tsw->cmtd_rate)
849 /* peak_rate >= avg_rate > cmtd_rate */
850 if (randval < avg_rate - tsw->cmtd_rate) {
852 pktinfo->pkt_dscp = tsw->yellow_dscp;
853 PKTCNTR_ADD(&tsw->yellow_cnt, len);
854 return (&tsw->yellow_action);
860 pktinfo->pkt_dscp = tsw->green_dscp;
861 PKTCNTR_ADD(&tsw->green_cnt, len);
862 return (&tsw->green_action);
869 cdnrcmd_if_attach(ifname)
873 struct top_cdnr *top;
875 if ((ifp = ifunit(ifname)) == NULL)
878 if (ifp->if_snd.altq_cdnr != NULL)
881 if ((top = top_create(&ifp->if_snd)) == NULL)
887 cdnrcmd_if_detach(ifname)
890 struct top_cdnr *top;
892 if ((top = tcb_lookup(ifname)) == NULL)
895 return top_destroy(top);
899 cdnrcmd_add_element(ap)
900 struct cdnr_add_element *ap;
902 struct top_cdnr *top;
903 struct cdnr_block *cb;
905 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
908 cb = element_create(top, &ap->action);
911 /* return a class handle to the user */
912 ap->cdnr_handle = cdnr_cb2handle(cb);
917 cdnrcmd_delete_element(ap)
918 struct cdnr_delete_element *ap;
920 struct top_cdnr *top;
921 struct cdnr_block *cb;
923 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
926 if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
929 if (cb->cb_type != TCETYPE_ELEMENT)
930 return generic_element_destroy(cb);
932 return element_destroy(cb);
936 cdnrcmd_add_filter(ap)
937 struct cdnr_add_filter *ap;
939 struct top_cdnr *top;
940 struct cdnr_block *cb;
942 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
945 if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
948 return acc_add_filter(&top->tc_classifier, &ap->filter,
949 cb, &ap->filter_handle);
953 cdnrcmd_delete_filter(ap)
954 struct cdnr_delete_filter *ap;
956 struct top_cdnr *top;
958 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
961 return acc_delete_filter(&top->tc_classifier, ap->filter_handle);
966 struct cdnr_add_tbmeter *ap;
968 struct top_cdnr *top;
971 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
974 tbm = tbm_create(top, &ap->profile, &ap->in_action, &ap->out_action);
977 /* return a class handle to the user */
978 ap->cdnr_handle = cdnr_cb2handle(&tbm->cdnrblk);
983 cdnrcmd_modify_tbm(ap)
984 struct cdnr_modify_tbmeter *ap;
988 if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
991 tb_import_profile(&tbm->tb, &ap->profile);
997 cdnrcmd_tbm_stats(ap)
998 struct cdnr_tbmeter_stats *ap;
1000 struct tbmeter *tbm;
1002 if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1005 ap->in_cnt = tbm->in_cnt;
1006 ap->out_cnt = tbm->out_cnt;
1012 cdnrcmd_add_trtcm(ap)
1013 struct cdnr_add_trtcm *ap;
1015 struct top_cdnr *top;
1018 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
1021 tcm = trtcm_create(top, &ap->cmtd_profile, &ap->peak_profile,
1022 &ap->green_action, &ap->yellow_action,
1023 &ap->red_action, ap->coloraware);
1027 /* return a class handle to the user */
1028 ap->cdnr_handle = cdnr_cb2handle(&tcm->cdnrblk);
1033 cdnrcmd_modify_trtcm(ap)
1034 struct cdnr_modify_trtcm *ap;
1038 if ((tcm = (struct trtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1041 tb_import_profile(&tcm->cmtd_tb, &ap->cmtd_profile);
1042 tb_import_profile(&tcm->peak_tb, &ap->peak_profile);
1048 cdnrcmd_tcm_stats(ap)
1049 struct cdnr_tcm_stats *ap;
1051 struct cdnr_block *cb;
1053 if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1056 if (cb->cb_type == TCETYPE_TRTCM) {
1057 struct trtcm *tcm = (struct trtcm *)cb;
1059 ap->green_cnt = tcm->green_cnt;
1060 ap->yellow_cnt = tcm->yellow_cnt;
1061 ap->red_cnt = tcm->red_cnt;
1062 } else if (cb->cb_type == TCETYPE_TSWTCM) {
1063 struct tswtcm *tsw = (struct tswtcm *)cb;
1065 ap->green_cnt = tsw->green_cnt;
1066 ap->yellow_cnt = tsw->yellow_cnt;
1067 ap->red_cnt = tsw->red_cnt;
1075 cdnrcmd_add_tswtcm(ap)
1076 struct cdnr_add_tswtcm *ap;
1078 struct top_cdnr *top;
1081 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
1084 if (ap->cmtd_rate > ap->peak_rate)
1087 tsw = tswtcm_create(top, ap->cmtd_rate, ap->peak_rate,
1088 ap->avg_interval, &ap->green_action,
1089 &ap->yellow_action, &ap->red_action);
1093 /* return a class handle to the user */
1094 ap->cdnr_handle = cdnr_cb2handle(&tsw->cdnrblk);
1099 cdnrcmd_modify_tswtcm(ap)
1100 struct cdnr_modify_tswtcm *ap;
1104 if ((tsw = (struct tswtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1107 if (ap->cmtd_rate > ap->peak_rate)
1110 /* convert rates from bits/sec to bytes/sec */
1111 tsw->cmtd_rate = ap->cmtd_rate / 8;
1112 tsw->peak_rate = ap->peak_rate / 8;
1115 /* timewin is converted from msec to machine clock unit */
1116 tsw->timewin = (u_int64_t)machclk_freq * ap->avg_interval / 1000;
1122 cdnrcmd_get_stats(ap)
1123 struct cdnr_get_stats *ap;
1125 struct top_cdnr *top;
1126 struct cdnr_block *cb;
1127 struct tbmeter *tbm;
1130 struct tce_stats tce, *usp;
1131 int error, n, nskip, nelements;
1133 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
1136 /* copy action stats */
1137 bcopy(top->tc_cnts, ap->cnts, sizeof(ap->cnts));
1139 /* stats for each element */
1140 nelements = ap->nelements;
1141 usp = ap->tce_stats;
1142 if (nelements <= 0 || usp == NULL)
1147 LIST_FOREACH(cb, &top->tc_elements, cb_next) {
1153 bzero(&tce, sizeof(tce));
1154 tce.tce_handle = cb->cb_handle;
1155 tce.tce_type = cb->cb_type;
1156 switch (cb->cb_type) {
1157 case TCETYPE_TBMETER:
1158 tbm = (struct tbmeter *)cb;
1159 tce.tce_cnts[0] = tbm->in_cnt;
1160 tce.tce_cnts[1] = tbm->out_cnt;
1163 tcm = (struct trtcm *)cb;
1164 tce.tce_cnts[0] = tcm->green_cnt;
1165 tce.tce_cnts[1] = tcm->yellow_cnt;
1166 tce.tce_cnts[2] = tcm->red_cnt;
1168 case TCETYPE_TSWTCM:
1169 tsw = (struct tswtcm *)cb;
1170 tce.tce_cnts[0] = tsw->green_cnt;
1171 tce.tce_cnts[1] = tsw->yellow_cnt;
1172 tce.tce_cnts[2] = tsw->red_cnt;
1178 if ((error = copyout((caddr_t)&tce, (caddr_t)usp++,
1182 if (++n == nelements)
1191 * conditioner device interface
1194 cdnropen(dev, flag, fmt, p)
1197 #if (__FreeBSD_version > 500000)
1203 if (machclk_freq == 0)
1206 if (machclk_freq == 0) {
1207 printf("cdnr: no cpu clock available!\n");
1211 /* everything will be done when the queueing scheme is attached. */
1216 cdnrclose(dev, flag, fmt, p)
1219 #if (__FreeBSD_version > 500000)
1225 struct top_cdnr *top;
1228 while ((top = LIST_FIRST(&tcb_list)) != NULL) {
1230 err = top_destroy(top);
1231 if (err != 0 && error == 0)
1240 cdnrioctl(dev, cmd, addr, flag, p)
1245 #if (__FreeBSD_version > 500000)
1251 struct top_cdnr *top;
1252 struct cdnr_interface *ifacep;
1255 /* check super-user privilege */
1260 #if (__FreeBSD_version > 700000)
1261 if ((error = priv_check(p, PRIV_ALTQ_MANAGE)) != 0)
1262 #elsif (__FreeBSD_version > 400000)
1263 if ((error = suser(p)) != 0)
1265 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1274 case CDNR_IF_ATTACH:
1275 ifacep = (struct cdnr_interface *)addr;
1276 error = cdnrcmd_if_attach(ifacep->cdnr_ifname);
1279 case CDNR_IF_DETACH:
1280 ifacep = (struct cdnr_interface *)addr;
1281 error = cdnrcmd_if_detach(ifacep->cdnr_ifname);
1286 ifacep = (struct cdnr_interface *)addr;
1287 if ((top = tcb_lookup(ifacep->cdnr_ifname)) == NULL) {
1295 ALTQ_SET_CNDTNING(top->tc_ifq);
1296 if (altq_input == NULL)
1297 altq_input = altq_cdnr_input;
1301 ALTQ_CLEAR_CNDTNING(top->tc_ifq);
1302 LIST_FOREACH(top, &tcb_list, tc_next)
1303 if (ALTQ_IS_CNDTNING(top->tc_ifq))
1312 error = cdnrcmd_add_element((struct cdnr_add_element *)addr);
1316 error = cdnrcmd_delete_element((struct cdnr_delete_element *)addr);
1320 error = cdnrcmd_add_tbm((struct cdnr_add_tbmeter *)addr);
1324 error = cdnrcmd_modify_tbm((struct cdnr_modify_tbmeter *)addr);
1327 case CDNR_TBM_STATS:
1328 error = cdnrcmd_tbm_stats((struct cdnr_tbmeter_stats *)addr);
1332 error = cdnrcmd_add_trtcm((struct cdnr_add_trtcm *)addr);
1336 error = cdnrcmd_modify_trtcm((struct cdnr_modify_trtcm *)addr);
1339 case CDNR_TCM_STATS:
1340 error = cdnrcmd_tcm_stats((struct cdnr_tcm_stats *)addr);
1343 case CDNR_ADD_FILTER:
1344 error = cdnrcmd_add_filter((struct cdnr_add_filter *)addr);
1347 case CDNR_DEL_FILTER:
1348 error = cdnrcmd_delete_filter((struct cdnr_delete_filter *)addr);
1352 error = cdnrcmd_get_stats((struct cdnr_get_stats *)addr);
1356 error = cdnrcmd_add_tswtcm((struct cdnr_add_tswtcm *)addr);
1360 error = cdnrcmd_modify_tswtcm((struct cdnr_modify_tswtcm *)addr);
1374 static struct altqsw cdnr_sw =
1375 {"cdnr", cdnropen, cdnrclose, cdnrioctl};
1377 ALTQ_MODULE(altq_cdnr, ALTQT_CDNR, &cdnr_sw);
1379 #endif /* KLD_MODULE */
1381 #endif /* ALTQ3_COMPAT */
1382 #endif /* ALTQ_CDNR */