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 #if defined(__FreeBSD__) || defined(__NetBSD__)
34 #include "opt_inet6.h"
36 #endif /* __FreeBSD__ || __NetBSD__ */
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>
50 #include <net/if_types.h>
51 #include <netinet/in.h>
52 #include <netinet/in_systm.h>
53 #include <netinet/ip.h>
55 #include <netinet/ip6.h>
58 #include <altq/altq.h>
60 #include <altq/altq_conf.h>
62 #include <altq/altq_cdnr.h>
66 * diffserv traffic conditioning module
69 int altq_cdnr_enabled = 0;
71 /* traffic conditioner is enabled by ALTQ_CDNR option in opt_altq.h */
74 /* cdnr_list keeps all cdnr's allocated. */
75 static LIST_HEAD(, top_cdnr) tcb_list;
77 static int altq_cdnr_input(struct mbuf *, int);
78 static struct top_cdnr *tcb_lookup(char *ifname);
79 static struct cdnr_block *cdnr_handle2cb(u_long);
80 static u_long cdnr_cb2handle(struct cdnr_block *);
81 static void *cdnr_cballoc(struct top_cdnr *, int,
82 struct tc_action *(*)(struct cdnr_block *, struct cdnr_pktinfo *));
83 static void cdnr_cbdestroy(void *);
84 static int tca_verify_action(struct tc_action *);
85 static void tca_import_action(struct tc_action *, struct tc_action *);
86 static void tca_invalidate_action(struct tc_action *);
88 static int generic_element_destroy(struct cdnr_block *);
89 static struct top_cdnr *top_create(struct ifaltq *);
90 static int top_destroy(struct top_cdnr *);
91 static struct cdnr_block *element_create(struct top_cdnr *, struct tc_action *);
92 static int element_destroy(struct cdnr_block *);
93 static void tb_import_profile(struct tbe *, struct tb_profile *);
94 static struct tbmeter *tbm_create(struct top_cdnr *, struct tb_profile *,
95 struct tc_action *, struct tc_action *);
96 static int tbm_destroy(struct tbmeter *);
97 static struct tc_action *tbm_input(struct cdnr_block *, struct cdnr_pktinfo *);
98 static struct trtcm *trtcm_create(struct top_cdnr *,
99 struct tb_profile *, struct tb_profile *,
100 struct tc_action *, struct tc_action *, struct tc_action *,
102 static int trtcm_destroy(struct trtcm *);
103 static struct tc_action *trtcm_input(struct cdnr_block *, struct cdnr_pktinfo *);
104 static struct tswtcm *tswtcm_create(struct top_cdnr *,
105 u_int32_t, u_int32_t, u_int32_t,
106 struct tc_action *, struct tc_action *, struct tc_action *);
107 static int tswtcm_destroy(struct tswtcm *);
108 static struct tc_action *tswtcm_input(struct cdnr_block *, struct cdnr_pktinfo *);
110 static int cdnrcmd_if_attach(char *);
111 static int cdnrcmd_if_detach(char *);
112 static int cdnrcmd_add_element(struct cdnr_add_element *);
113 static int cdnrcmd_delete_element(struct cdnr_delete_element *);
114 static int cdnrcmd_add_filter(struct cdnr_add_filter *);
115 static int cdnrcmd_delete_filter(struct cdnr_delete_filter *);
116 static int cdnrcmd_add_tbm(struct cdnr_add_tbmeter *);
117 static int cdnrcmd_modify_tbm(struct cdnr_modify_tbmeter *);
118 static int cdnrcmd_tbm_stats(struct cdnr_tbmeter_stats *);
119 static int cdnrcmd_add_trtcm(struct cdnr_add_trtcm *);
120 static int cdnrcmd_modify_trtcm(struct cdnr_modify_trtcm *);
121 static int cdnrcmd_tcm_stats(struct cdnr_tcm_stats *);
122 static int cdnrcmd_add_tswtcm(struct cdnr_add_tswtcm *);
123 static int cdnrcmd_modify_tswtcm(struct cdnr_modify_tswtcm *);
124 static int cdnrcmd_get_stats(struct cdnr_get_stats *);
129 * top level input function called from ip_input.
130 * should be called before converting header fields to host-byte-order.
133 altq_cdnr_input(m, af)
135 int af; /* address family */
139 struct top_cdnr *top;
140 struct tc_action *tca;
141 struct cdnr_block *cb;
142 struct cdnr_pktinfo pktinfo;
144 ifp = m->m_pkthdr.rcvif;
145 if (!ALTQ_IS_CNDTNING(&ifp->if_snd))
146 /* traffic conditioner is not enabled on this interface */
149 top = ifp->if_snd.altq_cdnr;
151 ip = mtod(m, struct ip *);
153 if (af == AF_INET6) {
156 flowlabel = ((struct ip6_hdr *)ip)->ip6_flow;
157 pktinfo.pkt_dscp = (ntohl(flowlabel) >> 20) & DSCP_MASK;
160 pktinfo.pkt_dscp = ip->ip_tos & DSCP_MASK;
161 pktinfo.pkt_len = m_pktlen(m);
165 cb = acc_classify(&top->tc_classifier, m, af);
167 tca = &cb->cb_action;
170 tca = &top->tc_block.cb_action;
173 PKTCNTR_ADD(&top->tc_cnts[tca->tca_code], pktinfo.pkt_len);
175 switch (tca->tca_code) {
185 if (af == AF_INET6) {
186 struct ip6_hdr *ip6 = (struct ip6_hdr *)ip;
189 flowlabel = ntohl(ip6->ip6_flow);
190 flowlabel = (tca->tca_dscp << 20) |
191 (flowlabel & ~(DSCP_MASK << 20));
192 ip6->ip6_flow = htonl(flowlabel);
195 ip->ip_tos = tca->tca_dscp |
196 (ip->ip_tos & DSCP_CUMASK);
200 tca = (*cb->cb_input)(cb, &pktinfo);
209 static struct top_cdnr *
213 struct top_cdnr *top;
216 if ((ifp = ifunit(ifname)) != NULL)
217 LIST_FOREACH(top, &tcb_list, tc_next)
218 if (top->tc_ifq->altq_ifp == ifp)
223 static struct cdnr_block *
224 cdnr_handle2cb(handle)
227 struct cdnr_block *cb;
229 cb = (struct cdnr_block *)handle;
230 if (handle != ALIGN(cb))
233 if (cb == NULL || cb->cb_handle != handle)
240 struct cdnr_block *cb;
242 return (cb->cb_handle);
246 cdnr_cballoc(top, type, input_func)
247 struct top_cdnr *top;
249 struct tc_action *(*input_func)(struct cdnr_block *,
250 struct cdnr_pktinfo *);
252 struct cdnr_block *cb;
257 size = sizeof(struct top_cdnr);
259 case TCETYPE_ELEMENT:
260 size = sizeof(struct cdnr_block);
262 case TCETYPE_TBMETER:
263 size = sizeof(struct tbmeter);
266 size = sizeof(struct trtcm);
269 size = sizeof(struct tswtcm);
275 cb = malloc(size, M_DEVBUF, M_WAITOK);
283 cb->cb_handle = (u_long)cb;
285 cb->cb_top = (struct top_cdnr *)cb;
289 if (input_func != NULL) {
291 * if this cdnr has an action function,
292 * make tc_action to call itself.
294 cb->cb_action.tca_code = TCACODE_NEXT;
295 cb->cb_action.tca_next = cb;
296 cb->cb_input = input_func;
298 cb->cb_action.tca_code = TCACODE_NONE;
300 /* if this isn't top, register the element to the top level cdnr */
302 LIST_INSERT_HEAD(&top->tc_elements, cb, cb_next);
308 cdnr_cbdestroy(cblock)
311 struct cdnr_block *cb = cblock;
313 /* delete filters belonging to this cdnr */
314 acc_discard_filters(&cb->cb_top->tc_classifier, cb, 0);
316 /* remove from the top level cdnr */
317 if (cb->cb_top != cblock)
318 LIST_REMOVE(cb, cb_next);
324 * conditioner common destroy routine
327 generic_element_destroy(cb)
328 struct cdnr_block *cb;
332 switch (cb->cb_type) {
334 error = top_destroy((struct top_cdnr *)cb);
336 case TCETYPE_ELEMENT:
337 error = element_destroy(cb);
339 case TCETYPE_TBMETER:
340 error = tbm_destroy((struct tbmeter *)cb);
343 error = trtcm_destroy((struct trtcm *)cb);
346 error = tswtcm_destroy((struct tswtcm *)cb);
355 tca_verify_action(utca)
356 struct tc_action *utca;
358 switch (utca->tca_code) {
366 /* verify handle value */
367 if (cdnr_handle2cb(utca->tca_handle) == NULL)
375 /* should not be passed from a user */
382 tca_import_action(ktca, utca)
383 struct tc_action *ktca, *utca;
385 struct cdnr_block *cb;
388 if (ktca->tca_code == TCACODE_HANDLE) {
389 cb = cdnr_handle2cb(ktca->tca_handle);
391 ktca->tca_code = TCACODE_NONE;
394 ktca->tca_code = TCACODE_NEXT;
397 } else if (ktca->tca_code == TCACODE_MARK) {
398 ktca->tca_dscp &= DSCP_MASK;
404 tca_invalidate_action(tca)
405 struct tc_action *tca;
407 struct cdnr_block *cb;
409 if (tca->tca_code == TCACODE_NEXT) {
415 tca->tca_code = TCACODE_NONE;
419 * top level traffic conditioner
421 static struct top_cdnr *
425 struct top_cdnr *top;
427 if ((top = cdnr_cballoc(NULL, TCETYPE_TOP, NULL)) == NULL)
431 /* set default action for the top level conditioner */
432 top->tc_block.cb_action.tca_code = TCACODE_PASS;
434 LIST_INSERT_HEAD(&tcb_list, top, tc_next);
436 ifq->altq_cdnr = top;
443 struct top_cdnr *top;
445 struct cdnr_block *cb;
447 if (ALTQ_IS_CNDTNING(top->tc_ifq))
448 ALTQ_CLEAR_CNDTNING(top->tc_ifq);
449 top->tc_ifq->altq_cdnr = NULL;
452 * destroy all the conditioner elements belonging to this interface
454 while ((cb = LIST_FIRST(&top->tc_elements)) != NULL) {
455 while (cb != NULL && cb->cb_ref > 0)
456 cb = LIST_NEXT(cb, cb_next);
458 generic_element_destroy(cb);
461 LIST_REMOVE(top, tc_next);
465 /* if there is no active conditioner, remove the input hook */
466 if (altq_input != NULL) {
467 LIST_FOREACH(top, &tcb_list, tc_next)
468 if (ALTQ_IS_CNDTNING(top->tc_ifq))
478 * simple tc elements without input function (e.g., dropper and makers).
480 static struct cdnr_block *
481 element_create(top, action)
482 struct top_cdnr *top;
483 struct tc_action *action;
485 struct cdnr_block *cb;
487 if (tca_verify_action(action) < 0)
490 if ((cb = cdnr_cballoc(top, TCETYPE_ELEMENT, NULL)) == NULL)
493 tca_import_action(&cb->cb_action, action);
500 struct cdnr_block *cb;
505 tca_invalidate_action(&cb->cb_action);
512 * internal representation of token bucket parameters
513 * rate: byte_per_unittime << 32
514 * (((bits_per_sec) / 8) << 32) / machclk_freq
519 #define TB_SCALE(x) ((u_int64_t)(x) << TB_SHIFT)
520 #define TB_UNSCALE(x) ((x) >> TB_SHIFT)
523 tb_import_profile(tb, profile)
525 struct tb_profile *profile;
527 tb->rate = TB_SCALE(profile->rate / 8) / machclk_freq;
528 tb->depth = TB_SCALE(profile->depth);
530 tb->filluptime = tb->depth / tb->rate;
532 tb->filluptime = 0xffffffffffffffffLL;
533 tb->token = tb->depth;
534 tb->last = read_machclk();
538 * simple token bucket meter
540 static struct tbmeter *
541 tbm_create(top, profile, in_action, out_action)
542 struct top_cdnr *top;
543 struct tb_profile *profile;
544 struct tc_action *in_action, *out_action;
546 struct tbmeter *tbm = NULL;
548 if (tca_verify_action(in_action) < 0
549 || tca_verify_action(out_action) < 0)
552 if ((tbm = cdnr_cballoc(top, TCETYPE_TBMETER,
556 tb_import_profile(&tbm->tb, profile);
558 tca_import_action(&tbm->in_action, in_action);
559 tca_import_action(&tbm->out_action, out_action);
568 if (tbm->cdnrblk.cb_ref > 0)
571 tca_invalidate_action(&tbm->in_action);
572 tca_invalidate_action(&tbm->out_action);
578 static struct tc_action *
579 tbm_input(cb, pktinfo)
580 struct cdnr_block *cb;
581 struct cdnr_pktinfo *pktinfo;
583 struct tbmeter *tbm = (struct tbmeter *)cb;
585 u_int64_t interval, now;
587 len = TB_SCALE(pktinfo->pkt_len);
589 if (tbm->tb.token < len) {
590 now = read_machclk();
591 interval = now - tbm->tb.last;
592 if (interval >= tbm->tb.filluptime)
593 tbm->tb.token = tbm->tb.depth;
595 tbm->tb.token += interval * tbm->tb.rate;
596 if (tbm->tb.token > tbm->tb.depth)
597 tbm->tb.token = tbm->tb.depth;
602 if (tbm->tb.token < len) {
603 PKTCNTR_ADD(&tbm->out_cnt, pktinfo->pkt_len);
604 return (&tbm->out_action);
607 tbm->tb.token -= len;
608 PKTCNTR_ADD(&tbm->in_cnt, pktinfo->pkt_len);
609 return (&tbm->in_action);
613 * two rate three color marker
614 * as described in draft-heinanen-diffserv-trtcm-01.txt
616 static struct trtcm *
617 trtcm_create(top, cmtd_profile, peak_profile,
618 green_action, yellow_action, red_action, coloraware)
619 struct top_cdnr *top;
620 struct tb_profile *cmtd_profile, *peak_profile;
621 struct tc_action *green_action, *yellow_action, *red_action;
624 struct trtcm *tcm = NULL;
626 if (tca_verify_action(green_action) < 0
627 || tca_verify_action(yellow_action) < 0
628 || tca_verify_action(red_action) < 0)
631 if ((tcm = cdnr_cballoc(top, TCETYPE_TRTCM,
632 trtcm_input)) == NULL)
635 tb_import_profile(&tcm->cmtd_tb, cmtd_profile);
636 tb_import_profile(&tcm->peak_tb, peak_profile);
638 tca_import_action(&tcm->green_action, green_action);
639 tca_import_action(&tcm->yellow_action, yellow_action);
640 tca_import_action(&tcm->red_action, red_action);
642 /* set dscps to use */
643 if (tcm->green_action.tca_code == TCACODE_MARK)
644 tcm->green_dscp = tcm->green_action.tca_dscp & DSCP_MASK;
646 tcm->green_dscp = DSCP_AF11;
647 if (tcm->yellow_action.tca_code == TCACODE_MARK)
648 tcm->yellow_dscp = tcm->yellow_action.tca_dscp & DSCP_MASK;
650 tcm->yellow_dscp = DSCP_AF12;
651 if (tcm->red_action.tca_code == TCACODE_MARK)
652 tcm->red_dscp = tcm->red_action.tca_dscp & DSCP_MASK;
654 tcm->red_dscp = DSCP_AF13;
656 tcm->coloraware = coloraware;
665 if (tcm->cdnrblk.cb_ref > 0)
668 tca_invalidate_action(&tcm->green_action);
669 tca_invalidate_action(&tcm->yellow_action);
670 tca_invalidate_action(&tcm->red_action);
676 static struct tc_action *
677 trtcm_input(cb, pktinfo)
678 struct cdnr_block *cb;
679 struct cdnr_pktinfo *pktinfo;
681 struct trtcm *tcm = (struct trtcm *)cb;
683 u_int64_t interval, now;
686 len = TB_SCALE(pktinfo->pkt_len);
687 if (tcm->coloraware) {
688 color = pktinfo->pkt_dscp;
689 if (color != tcm->yellow_dscp && color != tcm->red_dscp)
690 color = tcm->green_dscp;
692 /* if color-blind, precolor it as green */
693 color = tcm->green_dscp;
696 now = read_machclk();
697 if (tcm->cmtd_tb.token < len) {
698 interval = now - tcm->cmtd_tb.last;
699 if (interval >= tcm->cmtd_tb.filluptime)
700 tcm->cmtd_tb.token = tcm->cmtd_tb.depth;
702 tcm->cmtd_tb.token += interval * tcm->cmtd_tb.rate;
703 if (tcm->cmtd_tb.token > tcm->cmtd_tb.depth)
704 tcm->cmtd_tb.token = tcm->cmtd_tb.depth;
706 tcm->cmtd_tb.last = now;
708 if (tcm->peak_tb.token < len) {
709 interval = now - tcm->peak_tb.last;
710 if (interval >= tcm->peak_tb.filluptime)
711 tcm->peak_tb.token = tcm->peak_tb.depth;
713 tcm->peak_tb.token += interval * tcm->peak_tb.rate;
714 if (tcm->peak_tb.token > tcm->peak_tb.depth)
715 tcm->peak_tb.token = tcm->peak_tb.depth;
717 tcm->peak_tb.last = now;
720 if (color == tcm->red_dscp || tcm->peak_tb.token < len) {
721 pktinfo->pkt_dscp = tcm->red_dscp;
722 PKTCNTR_ADD(&tcm->red_cnt, pktinfo->pkt_len);
723 return (&tcm->red_action);
726 if (color == tcm->yellow_dscp || tcm->cmtd_tb.token < len) {
727 pktinfo->pkt_dscp = tcm->yellow_dscp;
728 tcm->peak_tb.token -= len;
729 PKTCNTR_ADD(&tcm->yellow_cnt, pktinfo->pkt_len);
730 return (&tcm->yellow_action);
733 pktinfo->pkt_dscp = tcm->green_dscp;
734 tcm->cmtd_tb.token -= len;
735 tcm->peak_tb.token -= len;
736 PKTCNTR_ADD(&tcm->green_cnt, pktinfo->pkt_len);
737 return (&tcm->green_action);
741 * time sliding window three color marker
742 * as described in draft-fang-diffserv-tc-tswtcm-00.txt
744 static struct tswtcm *
745 tswtcm_create(top, cmtd_rate, peak_rate, avg_interval,
746 green_action, yellow_action, red_action)
747 struct top_cdnr *top;
748 u_int32_t cmtd_rate, peak_rate, avg_interval;
749 struct tc_action *green_action, *yellow_action, *red_action;
753 if (tca_verify_action(green_action) < 0
754 || tca_verify_action(yellow_action) < 0
755 || tca_verify_action(red_action) < 0)
758 if ((tsw = cdnr_cballoc(top, TCETYPE_TSWTCM,
759 tswtcm_input)) == NULL)
762 tca_import_action(&tsw->green_action, green_action);
763 tca_import_action(&tsw->yellow_action, yellow_action);
764 tca_import_action(&tsw->red_action, red_action);
766 /* set dscps to use */
767 if (tsw->green_action.tca_code == TCACODE_MARK)
768 tsw->green_dscp = tsw->green_action.tca_dscp & DSCP_MASK;
770 tsw->green_dscp = DSCP_AF11;
771 if (tsw->yellow_action.tca_code == TCACODE_MARK)
772 tsw->yellow_dscp = tsw->yellow_action.tca_dscp & DSCP_MASK;
774 tsw->yellow_dscp = DSCP_AF12;
775 if (tsw->red_action.tca_code == TCACODE_MARK)
776 tsw->red_dscp = tsw->red_action.tca_dscp & DSCP_MASK;
778 tsw->red_dscp = DSCP_AF13;
780 /* convert rates from bits/sec to bytes/sec */
781 tsw->cmtd_rate = cmtd_rate / 8;
782 tsw->peak_rate = peak_rate / 8;
785 /* timewin is converted from msec to machine clock unit */
786 tsw->timewin = (u_int64_t)machclk_freq * avg_interval / 1000;
795 if (tsw->cdnrblk.cb_ref > 0)
798 tca_invalidate_action(&tsw->green_action);
799 tca_invalidate_action(&tsw->yellow_action);
800 tca_invalidate_action(&tsw->red_action);
806 static struct tc_action *
807 tswtcm_input(cb, pktinfo)
808 struct cdnr_block *cb;
809 struct cdnr_pktinfo *pktinfo;
811 struct tswtcm *tsw = (struct tswtcm *)cb;
814 u_int64_t interval, now, tmp;
819 len = pktinfo->pkt_len;
820 now = read_machclk();
822 interval = now - tsw->t_front;
824 * calculate average rate:
825 * avg = (avg * timewin + pkt_len)/(timewin + interval)
826 * pkt_len needs to be multiplied by machclk_freq in order to
828 * note: when avg_rate (bytes/sec) and timewin (machclk unit) are
829 * less than 32 bits, the following 64-bit operation has enough
832 tmp = ((u_int64_t)tsw->avg_rate * tsw->timewin
833 + (u_int64_t)len * machclk_freq) / (tsw->timewin + interval);
834 tsw->avg_rate = avg_rate = (u_int32_t)tmp;
840 if (avg_rate > tsw->cmtd_rate) {
841 u_int32_t randval = arc4random() % avg_rate;
843 if (avg_rate > tsw->peak_rate) {
844 if (randval < avg_rate - tsw->peak_rate) {
846 pktinfo->pkt_dscp = tsw->red_dscp;
847 PKTCNTR_ADD(&tsw->red_cnt, len);
848 return (&tsw->red_action);
849 } else if (randval < avg_rate - tsw->cmtd_rate)
852 /* peak_rate >= avg_rate > cmtd_rate */
853 if (randval < avg_rate - tsw->cmtd_rate) {
855 pktinfo->pkt_dscp = tsw->yellow_dscp;
856 PKTCNTR_ADD(&tsw->yellow_cnt, len);
857 return (&tsw->yellow_action);
863 pktinfo->pkt_dscp = tsw->green_dscp;
864 PKTCNTR_ADD(&tsw->green_cnt, len);
865 return (&tsw->green_action);
872 cdnrcmd_if_attach(ifname)
876 struct top_cdnr *top;
878 if ((ifp = ifunit(ifname)) == NULL)
881 if (ifp->if_snd.altq_cdnr != NULL)
884 if ((top = top_create(&ifp->if_snd)) == NULL)
890 cdnrcmd_if_detach(ifname)
893 struct top_cdnr *top;
895 if ((top = tcb_lookup(ifname)) == NULL)
898 return top_destroy(top);
902 cdnrcmd_add_element(ap)
903 struct cdnr_add_element *ap;
905 struct top_cdnr *top;
906 struct cdnr_block *cb;
908 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
911 cb = element_create(top, &ap->action);
914 /* return a class handle to the user */
915 ap->cdnr_handle = cdnr_cb2handle(cb);
920 cdnrcmd_delete_element(ap)
921 struct cdnr_delete_element *ap;
923 struct top_cdnr *top;
924 struct cdnr_block *cb;
926 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
929 if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
932 if (cb->cb_type != TCETYPE_ELEMENT)
933 return generic_element_destroy(cb);
935 return element_destroy(cb);
939 cdnrcmd_add_filter(ap)
940 struct cdnr_add_filter *ap;
942 struct top_cdnr *top;
943 struct cdnr_block *cb;
945 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
948 if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
951 return acc_add_filter(&top->tc_classifier, &ap->filter,
952 cb, &ap->filter_handle);
956 cdnrcmd_delete_filter(ap)
957 struct cdnr_delete_filter *ap;
959 struct top_cdnr *top;
961 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
964 return acc_delete_filter(&top->tc_classifier, ap->filter_handle);
969 struct cdnr_add_tbmeter *ap;
971 struct top_cdnr *top;
974 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
977 tbm = tbm_create(top, &ap->profile, &ap->in_action, &ap->out_action);
980 /* return a class handle to the user */
981 ap->cdnr_handle = cdnr_cb2handle(&tbm->cdnrblk);
986 cdnrcmd_modify_tbm(ap)
987 struct cdnr_modify_tbmeter *ap;
991 if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
994 tb_import_profile(&tbm->tb, &ap->profile);
1000 cdnrcmd_tbm_stats(ap)
1001 struct cdnr_tbmeter_stats *ap;
1003 struct tbmeter *tbm;
1005 if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1008 ap->in_cnt = tbm->in_cnt;
1009 ap->out_cnt = tbm->out_cnt;
1015 cdnrcmd_add_trtcm(ap)
1016 struct cdnr_add_trtcm *ap;
1018 struct top_cdnr *top;
1021 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
1024 tcm = trtcm_create(top, &ap->cmtd_profile, &ap->peak_profile,
1025 &ap->green_action, &ap->yellow_action,
1026 &ap->red_action, ap->coloraware);
1030 /* return a class handle to the user */
1031 ap->cdnr_handle = cdnr_cb2handle(&tcm->cdnrblk);
1036 cdnrcmd_modify_trtcm(ap)
1037 struct cdnr_modify_trtcm *ap;
1041 if ((tcm = (struct trtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1044 tb_import_profile(&tcm->cmtd_tb, &ap->cmtd_profile);
1045 tb_import_profile(&tcm->peak_tb, &ap->peak_profile);
1051 cdnrcmd_tcm_stats(ap)
1052 struct cdnr_tcm_stats *ap;
1054 struct cdnr_block *cb;
1056 if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1059 if (cb->cb_type == TCETYPE_TRTCM) {
1060 struct trtcm *tcm = (struct trtcm *)cb;
1062 ap->green_cnt = tcm->green_cnt;
1063 ap->yellow_cnt = tcm->yellow_cnt;
1064 ap->red_cnt = tcm->red_cnt;
1065 } else if (cb->cb_type == TCETYPE_TSWTCM) {
1066 struct tswtcm *tsw = (struct tswtcm *)cb;
1068 ap->green_cnt = tsw->green_cnt;
1069 ap->yellow_cnt = tsw->yellow_cnt;
1070 ap->red_cnt = tsw->red_cnt;
1078 cdnrcmd_add_tswtcm(ap)
1079 struct cdnr_add_tswtcm *ap;
1081 struct top_cdnr *top;
1084 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
1087 if (ap->cmtd_rate > ap->peak_rate)
1090 tsw = tswtcm_create(top, ap->cmtd_rate, ap->peak_rate,
1091 ap->avg_interval, &ap->green_action,
1092 &ap->yellow_action, &ap->red_action);
1096 /* return a class handle to the user */
1097 ap->cdnr_handle = cdnr_cb2handle(&tsw->cdnrblk);
1102 cdnrcmd_modify_tswtcm(ap)
1103 struct cdnr_modify_tswtcm *ap;
1107 if ((tsw = (struct tswtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1110 if (ap->cmtd_rate > ap->peak_rate)
1113 /* convert rates from bits/sec to bytes/sec */
1114 tsw->cmtd_rate = ap->cmtd_rate / 8;
1115 tsw->peak_rate = ap->peak_rate / 8;
1118 /* timewin is converted from msec to machine clock unit */
1119 tsw->timewin = (u_int64_t)machclk_freq * ap->avg_interval / 1000;
1125 cdnrcmd_get_stats(ap)
1126 struct cdnr_get_stats *ap;
1128 struct top_cdnr *top;
1129 struct cdnr_block *cb;
1130 struct tbmeter *tbm;
1133 struct tce_stats tce, *usp;
1134 int error, n, nskip, nelements;
1136 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
1139 /* copy action stats */
1140 bcopy(top->tc_cnts, ap->cnts, sizeof(ap->cnts));
1142 /* stats for each element */
1143 nelements = ap->nelements;
1144 usp = ap->tce_stats;
1145 if (nelements <= 0 || usp == NULL)
1150 LIST_FOREACH(cb, &top->tc_elements, cb_next) {
1156 bzero(&tce, sizeof(tce));
1157 tce.tce_handle = cb->cb_handle;
1158 tce.tce_type = cb->cb_type;
1159 switch (cb->cb_type) {
1160 case TCETYPE_TBMETER:
1161 tbm = (struct tbmeter *)cb;
1162 tce.tce_cnts[0] = tbm->in_cnt;
1163 tce.tce_cnts[1] = tbm->out_cnt;
1166 tcm = (struct trtcm *)cb;
1167 tce.tce_cnts[0] = tcm->green_cnt;
1168 tce.tce_cnts[1] = tcm->yellow_cnt;
1169 tce.tce_cnts[2] = tcm->red_cnt;
1171 case TCETYPE_TSWTCM:
1172 tsw = (struct tswtcm *)cb;
1173 tce.tce_cnts[0] = tsw->green_cnt;
1174 tce.tce_cnts[1] = tsw->yellow_cnt;
1175 tce.tce_cnts[2] = tsw->red_cnt;
1181 if ((error = copyout((caddr_t)&tce, (caddr_t)usp++,
1185 if (++n == nelements)
1194 * conditioner device interface
1197 cdnropen(dev, flag, fmt, p)
1200 #if (__FreeBSD_version > 500000)
1206 if (machclk_freq == 0)
1209 if (machclk_freq == 0) {
1210 printf("cdnr: no cpu clock available!\n");
1214 /* everything will be done when the queueing scheme is attached. */
1219 cdnrclose(dev, flag, fmt, p)
1222 #if (__FreeBSD_version > 500000)
1228 struct top_cdnr *top;
1231 while ((top = LIST_FIRST(&tcb_list)) != NULL) {
1233 err = top_destroy(top);
1234 if (err != 0 && error == 0)
1243 cdnrioctl(dev, cmd, addr, flag, p)
1248 #if (__FreeBSD_version > 500000)
1254 struct top_cdnr *top;
1255 struct cdnr_interface *ifacep;
1258 /* check super-user privilege */
1263 #if (__FreeBSD_version > 700000)
1264 if ((error = priv_check(p, PRIV_ALTQ_MANAGE)) != 0)
1265 #elsif (__FreeBSD_version > 400000)
1266 if ((error = suser(p)) != 0)
1268 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1281 case CDNR_IF_ATTACH:
1282 ifacep = (struct cdnr_interface *)addr;
1283 error = cdnrcmd_if_attach(ifacep->cdnr_ifname);
1286 case CDNR_IF_DETACH:
1287 ifacep = (struct cdnr_interface *)addr;
1288 error = cdnrcmd_if_detach(ifacep->cdnr_ifname);
1293 ifacep = (struct cdnr_interface *)addr;
1294 if ((top = tcb_lookup(ifacep->cdnr_ifname)) == NULL) {
1302 ALTQ_SET_CNDTNING(top->tc_ifq);
1303 if (altq_input == NULL)
1304 altq_input = altq_cdnr_input;
1308 ALTQ_CLEAR_CNDTNING(top->tc_ifq);
1309 LIST_FOREACH(top, &tcb_list, tc_next)
1310 if (ALTQ_IS_CNDTNING(top->tc_ifq))
1319 error = cdnrcmd_add_element((struct cdnr_add_element *)addr);
1323 error = cdnrcmd_delete_element((struct cdnr_delete_element *)addr);
1327 error = cdnrcmd_add_tbm((struct cdnr_add_tbmeter *)addr);
1331 error = cdnrcmd_modify_tbm((struct cdnr_modify_tbmeter *)addr);
1334 case CDNR_TBM_STATS:
1335 error = cdnrcmd_tbm_stats((struct cdnr_tbmeter_stats *)addr);
1339 error = cdnrcmd_add_trtcm((struct cdnr_add_trtcm *)addr);
1343 error = cdnrcmd_modify_trtcm((struct cdnr_modify_trtcm *)addr);
1346 case CDNR_TCM_STATS:
1347 error = cdnrcmd_tcm_stats((struct cdnr_tcm_stats *)addr);
1350 case CDNR_ADD_FILTER:
1351 error = cdnrcmd_add_filter((struct cdnr_add_filter *)addr);
1354 case CDNR_DEL_FILTER:
1355 error = cdnrcmd_delete_filter((struct cdnr_delete_filter *)addr);
1359 error = cdnrcmd_get_stats((struct cdnr_get_stats *)addr);
1363 error = cdnrcmd_add_tswtcm((struct cdnr_add_tswtcm *)addr);
1367 error = cdnrcmd_modify_tswtcm((struct cdnr_modify_tswtcm *)addr);
1381 static struct altqsw cdnr_sw =
1382 {"cdnr", cdnropen, cdnrclose, cdnrioctl};
1384 ALTQ_MODULE(altq_cdnr, ALTQT_CDNR, &cdnr_sw);
1386 #endif /* KLD_MODULE */
1388 #endif /* ALTQ3_COMPAT */
1389 #endif /* ALTQ_CDNR */