altq_cdnr.c revision 1.3.4.1 1 /* $NetBSD: altq_cdnr.c,v 1.3.4.1 2001/10/10 11:55:47 fvdl Exp $ */
2 /* $KAME: altq_cdnr.c,v 1.8 2000/12/14 08:12:45 thorpej Exp $ */
3
4 /*
5 * Copyright (C) 1999-2000
6 * Sony Computer Science Laboratories Inc. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
16 *
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
27 * SUCH DAMAGE.
28 */
29
30 #if defined(__FreeBSD__) || defined(__NetBSD__)
31 #include "opt_altq.h"
32 #if (__FreeBSD__ != 2)
33 #include "opt_inet.h"
34 #ifdef __FreeBSD__
35 #include "opt_inet6.h"
36 #endif
37 #endif
38 #endif /* __FreeBSD__ || __NetBSD__ */
39
40 #include <sys/param.h>
41 #include <sys/malloc.h>
42 #include <sys/mbuf.h>
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45 #include <sys/systm.h>
46 #include <sys/proc.h>
47 #include <sys/errno.h>
48 #include <sys/kernel.h>
49 #include <sys/queue.h>
50 #include <sys/vnode.h>
51
52 #include <net/if.h>
53 #include <net/if_types.h>
54 #include <netinet/in.h>
55 #include <netinet/in_systm.h>
56 #include <netinet/ip.h>
57 #ifdef INET6
58 #include <netinet/ip6.h>
59 #endif
60
61 #include <altq/altq.h>
62 #include <altq/altq_conf.h>
63 #include <altq/altq_cdnr.h>
64
65 /*
66 * diffserv traffic conditioning module
67 */
68
69 int altq_cdnr_enabled = 0;
70
71 /* traffic conditioner is enabled by ALTQ_CDNR option in opt_altq.h */
72 #ifdef ALTQ_CDNR
73
74 /* cdnr_list keeps all cdnr's allocated. */
75 static LIST_HEAD(, top_cdnr) tcb_list;
76
77 static int altq_cdnr_input __P((struct mbuf *, int));
78 static struct top_cdnr *tcb_lookup __P((char *ifname));
79 static struct cdnr_block *cdnr_handle2cb __P((u_long));
80 static u_long cdnr_cb2handle __P((struct cdnr_block *));
81 static void *cdnr_cballoc __P((struct top_cdnr *, int,
82 struct tc_action *(*)(struct cdnr_block *, struct cdnr_pktinfo *)));
83 static void cdnr_cbdestroy __P((void *));
84 static int tca_verify_action __P((struct tc_action *));
85 static void tca_import_action __P((struct tc_action *, struct tc_action *));
86 static void tca_invalidate_action __P((struct tc_action *));
87
88 static int generic_element_destroy __P((struct cdnr_block *));
89 static struct top_cdnr *top_create __P((struct ifaltq *));
90 static int top_destroy __P((struct top_cdnr *));
91 static struct cdnr_block *element_create __P((struct top_cdnr *,
92 struct tc_action *));
93 static int element_destroy __P((struct cdnr_block *));
94 static void tb_import_profile __P((struct tbe *, struct tb_profile *));
95 static struct tbmeter *tbm_create __P((struct top_cdnr *, struct tb_profile *,
96 struct tc_action *, struct tc_action *));
97 static int tbm_destroy __P((struct tbmeter *));
98 static struct tc_action *tbm_input __P((struct cdnr_block *,
99 struct cdnr_pktinfo *));
100 static struct trtcm *trtcm_create __P((struct top_cdnr *,
101 struct tb_profile *, struct tb_profile *,
102 struct tc_action *, struct tc_action *, struct tc_action *,
103 int));
104 static int trtcm_destroy __P((struct trtcm *));
105 static struct tc_action *trtcm_input __P((struct cdnr_block *,
106 struct cdnr_pktinfo *));
107 static struct tswtcm *tswtcm_create __P((struct top_cdnr *,
108 u_int32_t, u_int32_t, u_int32_t,
109 struct tc_action *, struct tc_action *, struct tc_action *));
110 static int tswtcm_destroy __P((struct tswtcm *));
111 static struct tc_action *tswtcm_input __P((struct cdnr_block *,
112 struct cdnr_pktinfo *));
113
114 static int cdnrcmd_if_attach __P((char *));
115 static int cdnrcmd_if_detach __P((char *));
116 static int cdnrcmd_add_element __P((struct cdnr_add_element *));
117 static int cdnrcmd_delete_element __P((struct cdnr_delete_element *));
118 static int cdnrcmd_add_filter __P((struct cdnr_add_filter *));
119 static int cdnrcmd_delete_filter __P((struct cdnr_delete_filter *));
120 static int cdnrcmd_add_tbm __P((struct cdnr_add_tbmeter *));
121 static int cdnrcmd_modify_tbm __P((struct cdnr_modify_tbmeter *));
122 static int cdnrcmd_tbm_stats __P((struct cdnr_tbmeter_stats *));
123 static int cdnrcmd_add_trtcm __P((struct cdnr_add_trtcm *));
124 static int cdnrcmd_modify_trtcm __P((struct cdnr_modify_trtcm *));
125 static int cdnrcmd_tcm_stats __P((struct cdnr_tcm_stats *));
126 static int cdnrcmd_add_tswtcm __P((struct cdnr_add_tswtcm *));
127 static int cdnrcmd_modify_tswtcm __P((struct cdnr_modify_tswtcm *));
128 static int cdnrcmd_get_stats __P((struct cdnr_get_stats *));
129
130 /*
131 * top level input function called from ip_input.
132 * should be called before converting header fields to host-byte-order.
133 */
134 int
135 altq_cdnr_input(m, af)
136 struct mbuf *m;
137 int af; /* address family */
138 {
139 struct ifnet *ifp;
140 struct ip *ip;
141 struct top_cdnr *top;
142 struct tc_action *tca;
143 struct cdnr_block *cb;
144 struct cdnr_pktinfo pktinfo;
145
146 ifp = m->m_pkthdr.rcvif;
147 if (!ALTQ_IS_CNDTNING(&ifp->if_snd))
148 /* traffic conditioner is not enabled on this interface */
149 return (1);
150
151 top = ifp->if_snd.altq_cdnr;
152
153 ip = mtod(m, struct ip *);
154 #ifdef INET6
155 if (af == AF_INET6) {
156 u_int32_t flowlabel;
157
158 flowlabel = ((struct ip6_hdr *)ip)->ip6_flow;
159 pktinfo.pkt_dscp = (ntohl(flowlabel) >> 20) & DSCP_MASK;
160 } else
161 #endif
162 pktinfo.pkt_dscp = ip->ip_tos & DSCP_MASK;
163 pktinfo.pkt_len = m_pktlen(m);
164
165 tca = NULL;
166
167 cb = acc_classify(&top->tc_classifier, m, af);
168 if (cb != NULL)
169 tca = &cb->cb_action;
170
171 if (tca == NULL)
172 tca = &top->tc_block.cb_action;
173
174 while (1) {
175 PKTCNTR_ADD(&top->tc_cnts[tca->tca_code], pktinfo.pkt_len);
176
177 switch (tca->tca_code) {
178 case TCACODE_PASS:
179 return (1);
180 case TCACODE_DROP:
181 m_freem(m);
182 return (0);
183 case TCACODE_RETURN:
184 return (0);
185 case TCACODE_MARK:
186 #ifdef INET6
187 if (af == AF_INET6) {
188 struct ip6_hdr *ip6 = (struct ip6_hdr *)ip;
189 u_int32_t flowlabel;
190
191 flowlabel = ntohl(ip6->ip6_flow);
192 flowlabel = (tca->tca_dscp << 20) |
193 (flowlabel & ~(DSCP_MASK << 20));
194 ip6->ip6_flow = htonl(flowlabel);
195 } else
196 #endif
197 ip->ip_tos = tca->tca_dscp |
198 (ip->ip_tos & DSCP_CUMASK);
199 return (1);
200 case TCACODE_NEXT:
201 cb = tca->tca_next;
202 tca = (*cb->cb_input)(cb, &pktinfo);
203 break;
204 case TCACODE_NONE:
205 default:
206 return (1);
207 }
208 }
209 }
210
211 static struct top_cdnr *
212 tcb_lookup(ifname)
213 char *ifname;
214 {
215 struct top_cdnr *top;
216 struct ifnet *ifp;
217
218 if ((ifp = ifunit(ifname)) != NULL)
219 LIST_FOREACH(top, &tcb_list, tc_next)
220 if (top->tc_ifq->altq_ifp == ifp)
221 return (top);
222 return (NULL);
223 }
224
225 static struct cdnr_block *
226 cdnr_handle2cb(handle)
227 u_long handle;
228 {
229 struct cdnr_block *cb;
230
231 cb = (struct cdnr_block *)handle;
232 if (handle != ALIGN(cb))
233 return (NULL);
234
235 if (cb == NULL || cb->cb_handle != handle)
236 return (NULL);
237 return (cb);
238 }
239
240 static u_long
241 cdnr_cb2handle(cb)
242 struct cdnr_block *cb;
243 {
244 return (cb->cb_handle);
245 }
246
247 static void *
248 cdnr_cballoc(top, type, input_func)
249 struct top_cdnr *top;
250 int type;
251 struct tc_action *(*input_func)(struct cdnr_block *,
252 struct cdnr_pktinfo *);
253 {
254 struct cdnr_block *cb;
255 int size;
256
257 switch (type) {
258 case TCETYPE_TOP:
259 size = sizeof(struct top_cdnr);
260 break;
261 case TCETYPE_ELEMENT:
262 size = sizeof(struct cdnr_block);
263 break;
264 case TCETYPE_TBMETER:
265 size = sizeof(struct tbmeter);
266 break;
267 case TCETYPE_TRTCM:
268 size = sizeof(struct trtcm);
269 break;
270 case TCETYPE_TSWTCM:
271 size = sizeof(struct tswtcm);
272 break;
273 default:
274 return (NULL);
275 }
276
277 MALLOC(cb, struct cdnr_block *, size, M_DEVBUF, M_WAITOK);
278 if (cb == NULL)
279 return (NULL);
280 bzero(cb, size);
281
282 cb->cb_len = size;
283 cb->cb_type = type;
284 cb->cb_ref = 0;
285 cb->cb_handle = (u_long)cb;
286 if (top == NULL)
287 cb->cb_top = (struct top_cdnr *)cb;
288 else
289 cb->cb_top = top;
290
291 if (input_func != NULL) {
292 /*
293 * if this cdnr has an action function,
294 * make tc_action to call itself.
295 */
296 cb->cb_action.tca_code = TCACODE_NEXT;
297 cb->cb_action.tca_next = cb;
298 cb->cb_input = input_func;
299 } else
300 cb->cb_action.tca_code = TCACODE_NONE;
301
302 /* if this isn't top, register the element to the top level cdnr */
303 if (top != NULL)
304 LIST_INSERT_HEAD(&top->tc_elements, cb, cb_next);
305
306 return ((void *)cb);
307 }
308
309 static void
310 cdnr_cbdestroy(cblock)
311 void *cblock;
312 {
313 struct cdnr_block *cb = cblock;
314
315 /* delete filters belonging to this cdnr */
316 acc_discard_filters(&cb->cb_top->tc_classifier, cb, 0);
317
318 /* remove from the top level cdnr */
319 if (cb->cb_top != cblock)
320 LIST_REMOVE(cb, cb_next);
321
322 FREE(cb, M_DEVBUF);
323 }
324
325 /*
326 * conditioner common destroy routine
327 */
328 static int
329 generic_element_destroy(cb)
330 struct cdnr_block *cb;
331 {
332 int error = 0;
333
334 switch (cb->cb_type) {
335 case TCETYPE_TOP:
336 error = top_destroy((struct top_cdnr *)cb);
337 break;
338 case TCETYPE_ELEMENT:
339 error = element_destroy(cb);
340 break;
341 case TCETYPE_TBMETER:
342 error = tbm_destroy((struct tbmeter *)cb);
343 break;
344 case TCETYPE_TRTCM:
345 error = trtcm_destroy((struct trtcm *)cb);
346 break;
347 case TCETYPE_TSWTCM:
348 error = tswtcm_destroy((struct tswtcm *)cb);
349 break;
350 default:
351 error = EINVAL;
352 }
353 return (error);
354 }
355
356 static int
357 tca_verify_action(utca)
358 struct tc_action *utca;
359 {
360 switch (utca->tca_code) {
361 case TCACODE_PASS:
362 case TCACODE_DROP:
363 case TCACODE_MARK:
364 /* these are ok */
365 break;
366
367 case TCACODE_HANDLE:
368 /* verify handle value */
369 if (cdnr_handle2cb(utca->tca_handle) == NULL)
370 return (-1);
371 break;
372
373 case TCACODE_NONE:
374 case TCACODE_RETURN:
375 case TCACODE_NEXT:
376 default:
377 /* should not be passed from a user */
378 return (-1);
379 }
380 return (0);
381 }
382
383 static void
384 tca_import_action(ktca, utca)
385 struct tc_action *ktca, *utca;
386 {
387 struct cdnr_block *cb;
388
389 *ktca = *utca;
390 if (ktca->tca_code == TCACODE_HANDLE) {
391 cb = cdnr_handle2cb(ktca->tca_handle);
392 if (cb == NULL) {
393 ktca->tca_code = TCACODE_NONE;
394 return;
395 }
396 ktca->tca_code = TCACODE_NEXT;
397 ktca->tca_next = cb;
398 cb->cb_ref++;
399 } else if (ktca->tca_code == TCACODE_MARK) {
400 ktca->tca_dscp &= DSCP_MASK;
401 }
402 return;
403 }
404
405 static void
406 tca_invalidate_action(tca)
407 struct tc_action *tca;
408 {
409 struct cdnr_block *cb;
410
411 if (tca->tca_code == TCACODE_NEXT) {
412 cb = tca->tca_next;
413 if (cb == NULL)
414 return;
415 cb->cb_ref--;
416 }
417 tca->tca_code = TCACODE_NONE;
418 }
419
420 /*
421 * top level traffic conditioner
422 */
423 static struct top_cdnr *
424 top_create(ifq)
425 struct ifaltq *ifq;
426 {
427 struct top_cdnr *top;
428
429 if ((top = cdnr_cballoc(NULL, TCETYPE_TOP, NULL)) == NULL)
430 return (NULL);
431
432 top->tc_ifq = ifq;
433 /* set default action for the top level conditioner */
434 top->tc_block.cb_action.tca_code = TCACODE_PASS;
435
436 LIST_INSERT_HEAD(&tcb_list, top, tc_next);
437
438 ifq->altq_cdnr = top;
439
440 return (top);
441 }
442
443 static int
444 top_destroy(top)
445 struct top_cdnr *top;
446 {
447 struct cdnr_block *cb;
448
449 if (ALTQ_IS_CNDTNING(top->tc_ifq))
450 ALTQ_CLEAR_CNDTNING(top->tc_ifq);
451 top->tc_ifq->altq_cdnr = NULL;
452
453 /*
454 * destroy all the conditioner elements belonging to this interface
455 */
456 while ((cb = LIST_FIRST(&top->tc_elements)) != NULL) {
457 while (cb != NULL && cb->cb_ref > 0)
458 cb = LIST_NEXT(cb, cb_next);
459 if (cb != NULL)
460 generic_element_destroy(cb);
461 }
462
463 LIST_REMOVE(top, tc_next);
464
465 cdnr_cbdestroy(top);
466
467 /* if there is no active conditioner, remove the input hook */
468 if (altq_input != NULL) {
469 LIST_FOREACH(top, &tcb_list, tc_next)
470 if (ALTQ_IS_CNDTNING(top->tc_ifq))
471 break;
472 if (top == NULL)
473 altq_input = NULL;
474 }
475
476 return (0);
477 }
478
479 /*
480 * simple tc elements without input function (e.g., dropper and makers).
481 */
482 static struct cdnr_block *
483 element_create(top, action)
484 struct top_cdnr *top;
485 struct tc_action *action;
486 {
487 struct cdnr_block *cb;
488
489 if (tca_verify_action(action) < 0)
490 return (NULL);
491
492 if ((cb = cdnr_cballoc(top, TCETYPE_ELEMENT, NULL)) == NULL)
493 return (NULL);
494
495 tca_import_action(&cb->cb_action, action);
496
497 return (cb);
498 }
499
500 static int
501 element_destroy(cb)
502 struct cdnr_block *cb;
503 {
504 if (cb->cb_ref > 0)
505 return (EBUSY);
506
507 tca_invalidate_action(&cb->cb_action);
508
509 cdnr_cbdestroy(cb);
510 return (0);
511 }
512
513 /*
514 * internal representation of token bucket parameters
515 * rate: byte_per_unittime << 32
516 * (((bits_per_sec) / 8) << 32) / machclk_freq
517 * depth: byte << 32
518 *
519 */
520 #define TB_SHIFT 32
521 #define TB_SCALE(x) ((u_int64_t)(x) << TB_SHIFT)
522 #define TB_UNSCALE(x) ((x) >> TB_SHIFT)
523
524 static void
525 tb_import_profile(tb, profile)
526 struct tbe *tb;
527 struct tb_profile *profile;
528 {
529 tb->rate = TB_SCALE(profile->rate / 8) / machclk_freq;
530 tb->depth = TB_SCALE(profile->depth);
531 if (tb->rate > 0)
532 tb->filluptime = tb->depth / tb->rate;
533 else
534 tb->filluptime = 0xffffffffffffffffLL;
535 tb->token = tb->depth;
536 tb->last = read_machclk();
537 }
538
539 /*
540 * simple token bucket meter
541 */
542 static struct tbmeter *
543 tbm_create(top, profile, in_action, out_action)
544 struct top_cdnr *top;
545 struct tb_profile *profile;
546 struct tc_action *in_action, *out_action;
547 {
548 struct tbmeter *tbm = NULL;
549
550 if (tca_verify_action(in_action) < 0
551 || tca_verify_action(out_action) < 0)
552 return (NULL);
553
554 if ((tbm = cdnr_cballoc(top, TCETYPE_TBMETER,
555 tbm_input)) == NULL)
556 return (NULL);
557
558 tb_import_profile(&tbm->tb, profile);
559
560 tca_import_action(&tbm->in_action, in_action);
561 tca_import_action(&tbm->out_action, out_action);
562
563 return (tbm);
564 }
565
566 static int
567 tbm_destroy(tbm)
568 struct tbmeter *tbm;
569 {
570 if (tbm->cdnrblk.cb_ref > 0)
571 return (EBUSY);
572
573 tca_invalidate_action(&tbm->in_action);
574 tca_invalidate_action(&tbm->out_action);
575
576 cdnr_cbdestroy(tbm);
577 return (0);
578 }
579
580 static struct tc_action *
581 tbm_input(cb, pktinfo)
582 struct cdnr_block *cb;
583 struct cdnr_pktinfo *pktinfo;
584 {
585 struct tbmeter *tbm = (struct tbmeter *)cb;
586 u_int64_t len;
587 u_int64_t interval, now;
588
589 len = TB_SCALE(pktinfo->pkt_len);
590
591 if (tbm->tb.token < len) {
592 now = read_machclk();
593 interval = now - tbm->tb.last;
594 if (interval >= tbm->tb.filluptime)
595 tbm->tb.token = tbm->tb.depth;
596 else {
597 tbm->tb.token += interval * tbm->tb.rate;
598 if (tbm->tb.token > tbm->tb.depth)
599 tbm->tb.token = tbm->tb.depth;
600 }
601 tbm->tb.last = now;
602 }
603
604 if (tbm->tb.token < len) {
605 PKTCNTR_ADD(&tbm->out_cnt, pktinfo->pkt_len);
606 return (&tbm->out_action);
607 }
608
609 tbm->tb.token -= len;
610 PKTCNTR_ADD(&tbm->in_cnt, pktinfo->pkt_len);
611 return (&tbm->in_action);
612 }
613
614 /*
615 * two rate three color marker
616 * as described in draft-heinanen-diffserv-trtcm-01.txt
617 */
618 static struct trtcm *
619 trtcm_create(top, cmtd_profile, peak_profile,
620 green_action, yellow_action, red_action, coloraware)
621 struct top_cdnr *top;
622 struct tb_profile *cmtd_profile, *peak_profile;
623 struct tc_action *green_action, *yellow_action, *red_action;
624 int coloraware;
625 {
626 struct trtcm *tcm = NULL;
627
628 if (tca_verify_action(green_action) < 0
629 || tca_verify_action(yellow_action) < 0
630 || tca_verify_action(red_action) < 0)
631 return (NULL);
632
633 if ((tcm = cdnr_cballoc(top, TCETYPE_TRTCM,
634 trtcm_input)) == NULL)
635 return (NULL);
636
637 tb_import_profile(&tcm->cmtd_tb, cmtd_profile);
638 tb_import_profile(&tcm->peak_tb, peak_profile);
639
640 tca_import_action(&tcm->green_action, green_action);
641 tca_import_action(&tcm->yellow_action, yellow_action);
642 tca_import_action(&tcm->red_action, red_action);
643
644 /* set dscps to use */
645 if (tcm->green_action.tca_code == TCACODE_MARK)
646 tcm->green_dscp = tcm->green_action.tca_dscp & DSCP_MASK;
647 else
648 tcm->green_dscp = DSCP_AF11;
649 if (tcm->yellow_action.tca_code == TCACODE_MARK)
650 tcm->yellow_dscp = tcm->yellow_action.tca_dscp & DSCP_MASK;
651 else
652 tcm->yellow_dscp = DSCP_AF12;
653 if (tcm->red_action.tca_code == TCACODE_MARK)
654 tcm->red_dscp = tcm->red_action.tca_dscp & DSCP_MASK;
655 else
656 tcm->red_dscp = DSCP_AF13;
657
658 tcm->coloraware = coloraware;
659
660 return (tcm);
661 }
662
663 static int
664 trtcm_destroy(tcm)
665 struct trtcm *tcm;
666 {
667 if (tcm->cdnrblk.cb_ref > 0)
668 return (EBUSY);
669
670 tca_invalidate_action(&tcm->green_action);
671 tca_invalidate_action(&tcm->yellow_action);
672 tca_invalidate_action(&tcm->red_action);
673
674 cdnr_cbdestroy(tcm);
675 return (0);
676 }
677
678 static struct tc_action *
679 trtcm_input(cb, pktinfo)
680 struct cdnr_block *cb;
681 struct cdnr_pktinfo *pktinfo;
682 {
683 struct trtcm *tcm = (struct trtcm *)cb;
684 u_int64_t len;
685 u_int64_t interval, now;
686 u_int8_t color;
687
688 len = TB_SCALE(pktinfo->pkt_len);
689 if (tcm->coloraware) {
690 color = pktinfo->pkt_dscp;
691 if (color != tcm->yellow_dscp && color != tcm->red_dscp)
692 color = tcm->green_dscp;
693 } else {
694 /* if color-blind, precolor it as green */
695 color = tcm->green_dscp;
696 }
697
698 now = read_machclk();
699 if (tcm->cmtd_tb.token < len) {
700 interval = now - tcm->cmtd_tb.last;
701 if (interval >= tcm->cmtd_tb.filluptime)
702 tcm->cmtd_tb.token = tcm->cmtd_tb.depth;
703 else {
704 tcm->cmtd_tb.token += interval * tcm->cmtd_tb.rate;
705 if (tcm->cmtd_tb.token > tcm->cmtd_tb.depth)
706 tcm->cmtd_tb.token = tcm->cmtd_tb.depth;
707 }
708 tcm->cmtd_tb.last = now;
709 }
710 if (tcm->peak_tb.token < len) {
711 interval = now - tcm->peak_tb.last;
712 if (interval >= tcm->peak_tb.filluptime)
713 tcm->peak_tb.token = tcm->peak_tb.depth;
714 else {
715 tcm->peak_tb.token += interval * tcm->peak_tb.rate;
716 if (tcm->peak_tb.token > tcm->peak_tb.depth)
717 tcm->peak_tb.token = tcm->peak_tb.depth;
718 }
719 tcm->peak_tb.last = now;
720 }
721
722 if (color == tcm->red_dscp || tcm->peak_tb.token < len) {
723 pktinfo->pkt_dscp = tcm->red_dscp;
724 PKTCNTR_ADD(&tcm->red_cnt, pktinfo->pkt_len);
725 return (&tcm->red_action);
726 }
727
728 if (color == tcm->yellow_dscp || tcm->cmtd_tb.token < len) {
729 pktinfo->pkt_dscp = tcm->yellow_dscp;
730 tcm->peak_tb.token -= len;
731 PKTCNTR_ADD(&tcm->yellow_cnt, pktinfo->pkt_len);
732 return (&tcm->yellow_action);
733 }
734
735 pktinfo->pkt_dscp = tcm->green_dscp;
736 tcm->cmtd_tb.token -= len;
737 tcm->peak_tb.token -= len;
738 PKTCNTR_ADD(&tcm->green_cnt, pktinfo->pkt_len);
739 return (&tcm->green_action);
740 }
741
742 /*
743 * time sliding window three color marker
744 * as described in draft-fang-diffserv-tc-tswtcm-00.txt
745 */
746 static struct tswtcm *
747 tswtcm_create(top, cmtd_rate, peak_rate, avg_interval,
748 green_action, yellow_action, red_action)
749 struct top_cdnr *top;
750 u_int32_t cmtd_rate, peak_rate, avg_interval;
751 struct tc_action *green_action, *yellow_action, *red_action;
752 {
753 struct tswtcm *tsw;
754
755 if (tca_verify_action(green_action) < 0
756 || tca_verify_action(yellow_action) < 0
757 || tca_verify_action(red_action) < 0)
758 return (NULL);
759
760 if ((tsw = cdnr_cballoc(top, TCETYPE_TSWTCM,
761 tswtcm_input)) == NULL)
762 return (NULL);
763
764 tca_import_action(&tsw->green_action, green_action);
765 tca_import_action(&tsw->yellow_action, yellow_action);
766 tca_import_action(&tsw->red_action, red_action);
767
768 /* set dscps to use */
769 if (tsw->green_action.tca_code == TCACODE_MARK)
770 tsw->green_dscp = tsw->green_action.tca_dscp & DSCP_MASK;
771 else
772 tsw->green_dscp = DSCP_AF11;
773 if (tsw->yellow_action.tca_code == TCACODE_MARK)
774 tsw->yellow_dscp = tsw->yellow_action.tca_dscp & DSCP_MASK;
775 else
776 tsw->yellow_dscp = DSCP_AF12;
777 if (tsw->red_action.tca_code == TCACODE_MARK)
778 tsw->red_dscp = tsw->red_action.tca_dscp & DSCP_MASK;
779 else
780 tsw->red_dscp = DSCP_AF13;
781
782 /* convert rates from bits/sec to bytes/sec */
783 tsw->cmtd_rate = cmtd_rate / 8;
784 tsw->peak_rate = peak_rate / 8;
785 tsw->avg_rate = 0;
786
787 /* timewin is converted from msec to machine clock unit */
788 tsw->timewin = (u_int64_t)machclk_freq * avg_interval / 1000;
789
790 return (tsw);
791 }
792
793 static int
794 tswtcm_destroy(tsw)
795 struct tswtcm *tsw;
796 {
797 if (tsw->cdnrblk.cb_ref > 0)
798 return (EBUSY);
799
800 tca_invalidate_action(&tsw->green_action);
801 tca_invalidate_action(&tsw->yellow_action);
802 tca_invalidate_action(&tsw->red_action);
803
804 cdnr_cbdestroy(tsw);
805 return (0);
806 }
807
808 static struct tc_action *
809 tswtcm_input(cb, pktinfo)
810 struct cdnr_block *cb;
811 struct cdnr_pktinfo *pktinfo;
812 {
813 struct tswtcm *tsw = (struct tswtcm *)cb;
814 int len;
815 u_int32_t avg_rate;
816 u_int64_t interval, now, tmp;
817
818 /*
819 * rate estimator
820 */
821 len = pktinfo->pkt_len;
822 now = read_machclk();
823
824 interval = now - tsw->t_front;
825 /*
826 * calculate average rate:
827 * avg = (avg * timewin + pkt_len)/(timewin + interval)
828 * pkt_len needs to be multiplied by machclk_freq in order to
829 * get (bytes/sec).
830 * note: when avg_rate (bytes/sec) and timewin (machclk unit) are
831 * less than 32 bits, the following 64-bit operation has enough
832 * precision.
833 */
834 tmp = ((u_int64_t)tsw->avg_rate * tsw->timewin
835 + (u_int64_t)len * machclk_freq) / (tsw->timewin + interval);
836 tsw->avg_rate = avg_rate = (u_int32_t)tmp;
837 tsw->t_front = now;
838
839 /*
840 * marker
841 */
842 if (avg_rate > tsw->cmtd_rate) {
843 u_int32_t randval = random() % avg_rate;
844
845 if (avg_rate > tsw->peak_rate) {
846 if (randval < avg_rate - tsw->peak_rate) {
847 /* mark red */
848 pktinfo->pkt_dscp = tsw->red_dscp;
849 PKTCNTR_ADD(&tsw->red_cnt, len);
850 return (&tsw->red_action);
851 } else if (randval < avg_rate - tsw->cmtd_rate)
852 goto mark_yellow;
853 } else {
854 /* peak_rate >= avg_rate > cmtd_rate */
855 if (randval < avg_rate - tsw->cmtd_rate) {
856 mark_yellow:
857 pktinfo->pkt_dscp = tsw->yellow_dscp;
858 PKTCNTR_ADD(&tsw->yellow_cnt, len);
859 return (&tsw->yellow_action);
860 }
861 }
862 }
863
864 /* mark green */
865 pktinfo->pkt_dscp = tsw->green_dscp;
866 PKTCNTR_ADD(&tsw->green_cnt, len);
867 return (&tsw->green_action);
868 }
869
870 /*
871 * ioctl requests
872 */
873 static int
874 cdnrcmd_if_attach(ifname)
875 char *ifname;
876 {
877 struct ifnet *ifp;
878 struct top_cdnr *top;
879
880 if ((ifp = ifunit(ifname)) == NULL)
881 return (EBADF);
882
883 if (ifp->if_snd.altq_cdnr != NULL)
884 return (EBUSY);
885
886 if ((top = top_create(&ifp->if_snd)) == NULL)
887 return (ENOMEM);
888 return (0);
889 }
890
891 static int
892 cdnrcmd_if_detach(ifname)
893 char *ifname;
894 {
895 struct top_cdnr *top;
896
897 if ((top = tcb_lookup(ifname)) == NULL)
898 return (EBADF);
899
900 return top_destroy(top);
901 }
902
903 static int
904 cdnrcmd_add_element(ap)
905 struct cdnr_add_element *ap;
906 {
907 struct top_cdnr *top;
908 struct cdnr_block *cb;
909
910 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
911 return (EBADF);
912
913 cb = element_create(top, &ap->action);
914 if (cb == NULL)
915 return (EINVAL);
916 /* return a class handle to the user */
917 ap->cdnr_handle = cdnr_cb2handle(cb);
918 return (0);
919 }
920
921 static int
922 cdnrcmd_delete_element(ap)
923 struct cdnr_delete_element *ap;
924 {
925 struct top_cdnr *top;
926 struct cdnr_block *cb;
927
928 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
929 return (EBADF);
930
931 if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
932 return (EINVAL);
933
934 if (cb->cb_type != TCETYPE_ELEMENT)
935 return generic_element_destroy(cb);
936
937 return element_destroy(cb);
938 }
939
940 static int
941 cdnrcmd_add_filter(ap)
942 struct cdnr_add_filter *ap;
943 {
944 struct top_cdnr *top;
945 struct cdnr_block *cb;
946
947 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
948 return (EBADF);
949
950 if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
951 return (EINVAL);
952
953 return acc_add_filter(&top->tc_classifier, &ap->filter,
954 cb, &ap->filter_handle);
955 }
956
957 static int
958 cdnrcmd_delete_filter(ap)
959 struct cdnr_delete_filter *ap;
960 {
961 struct top_cdnr *top;
962
963 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
964 return (EBADF);
965
966 return acc_delete_filter(&top->tc_classifier, ap->filter_handle);
967 }
968
969 static int
970 cdnrcmd_add_tbm(ap)
971 struct cdnr_add_tbmeter *ap;
972 {
973 struct top_cdnr *top;
974 struct tbmeter *tbm;
975
976 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
977 return (EBADF);
978
979 tbm = tbm_create(top, &ap->profile, &ap->in_action, &ap->out_action);
980 if (tbm == NULL)
981 return (EINVAL);
982 /* return a class handle to the user */
983 ap->cdnr_handle = cdnr_cb2handle(&tbm->cdnrblk);
984 return (0);
985 }
986
987 static int
988 cdnrcmd_modify_tbm(ap)
989 struct cdnr_modify_tbmeter *ap;
990 {
991 struct tbmeter *tbm;
992
993 if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
994 return (EINVAL);
995
996 tb_import_profile(&tbm->tb, &ap->profile);
997
998 return (0);
999 }
1000
1001 static int
1002 cdnrcmd_tbm_stats(ap)
1003 struct cdnr_tbmeter_stats *ap;
1004 {
1005 struct tbmeter *tbm;
1006
1007 if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1008 return (EINVAL);
1009
1010 ap->in_cnt = tbm->in_cnt;
1011 ap->out_cnt = tbm->out_cnt;
1012
1013 return (0);
1014 }
1015
1016 static int
1017 cdnrcmd_add_trtcm(ap)
1018 struct cdnr_add_trtcm *ap;
1019 {
1020 struct top_cdnr *top;
1021 struct trtcm *tcm;
1022
1023 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
1024 return (EBADF);
1025
1026 tcm = trtcm_create(top, &ap->cmtd_profile, &ap->peak_profile,
1027 &ap->green_action, &ap->yellow_action,
1028 &ap->red_action, ap->coloraware);
1029 if (tcm == NULL)
1030 return (EINVAL);
1031
1032 /* return a class handle to the user */
1033 ap->cdnr_handle = cdnr_cb2handle(&tcm->cdnrblk);
1034 return (0);
1035 }
1036
1037 static int
1038 cdnrcmd_modify_trtcm(ap)
1039 struct cdnr_modify_trtcm *ap;
1040 {
1041 struct trtcm *tcm;
1042
1043 if ((tcm = (struct trtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1044 return (EINVAL);
1045
1046 tb_import_profile(&tcm->cmtd_tb, &ap->cmtd_profile);
1047 tb_import_profile(&tcm->peak_tb, &ap->peak_profile);
1048
1049 return (0);
1050 }
1051
1052 static int
1053 cdnrcmd_tcm_stats(ap)
1054 struct cdnr_tcm_stats *ap;
1055 {
1056 struct cdnr_block *cb;
1057
1058 if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1059 return (EINVAL);
1060
1061 if (cb->cb_type == TCETYPE_TRTCM) {
1062 struct trtcm *tcm = (struct trtcm *)cb;
1063
1064 ap->green_cnt = tcm->green_cnt;
1065 ap->yellow_cnt = tcm->yellow_cnt;
1066 ap->red_cnt = tcm->red_cnt;
1067 } else if (cb->cb_type == TCETYPE_TSWTCM) {
1068 struct tswtcm *tsw = (struct tswtcm *)cb;
1069
1070 ap->green_cnt = tsw->green_cnt;
1071 ap->yellow_cnt = tsw->yellow_cnt;
1072 ap->red_cnt = tsw->red_cnt;
1073 } else
1074 return (EINVAL);
1075
1076 return (0);
1077 }
1078
1079 static int
1080 cdnrcmd_add_tswtcm(ap)
1081 struct cdnr_add_tswtcm *ap;
1082 {
1083 struct top_cdnr *top;
1084 struct tswtcm *tsw;
1085
1086 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
1087 return (EBADF);
1088
1089 if (ap->cmtd_rate > ap->peak_rate)
1090 return (EINVAL);
1091
1092 tsw = tswtcm_create(top, ap->cmtd_rate, ap->peak_rate,
1093 ap->avg_interval, &ap->green_action,
1094 &ap->yellow_action, &ap->red_action);
1095 if (tsw == NULL)
1096 return (EINVAL);
1097
1098 /* return a class handle to the user */
1099 ap->cdnr_handle = cdnr_cb2handle(&tsw->cdnrblk);
1100 return (0);
1101 }
1102
1103 static int
1104 cdnrcmd_modify_tswtcm(ap)
1105 struct cdnr_modify_tswtcm *ap;
1106 {
1107 struct tswtcm *tsw;
1108
1109 if ((tsw = (struct tswtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1110 return (EINVAL);
1111
1112 if (ap->cmtd_rate > ap->peak_rate)
1113 return (EINVAL);
1114
1115 /* convert rates from bits/sec to bytes/sec */
1116 tsw->cmtd_rate = ap->cmtd_rate / 8;
1117 tsw->peak_rate = ap->peak_rate / 8;
1118 tsw->avg_rate = 0;
1119
1120 /* timewin is converted from msec to machine clock unit */
1121 tsw->timewin = (u_int64_t)machclk_freq * ap->avg_interval / 1000;
1122
1123 return (0);
1124 }
1125
1126 static int
1127 cdnrcmd_get_stats(ap)
1128 struct cdnr_get_stats *ap;
1129 {
1130 struct top_cdnr *top;
1131 struct cdnr_block *cb;
1132 struct tbmeter *tbm;
1133 struct trtcm *tcm;
1134 struct tswtcm *tsw;
1135 struct tce_stats tce, *usp;
1136 int error, n, nskip, nelements;
1137
1138 if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
1139 return (EBADF);
1140
1141 /* copy action stats */
1142 bcopy(top->tc_cnts, ap->cnts, sizeof(ap->cnts));
1143
1144 /* stats for each element */
1145 nelements = ap->nelements;
1146 usp = ap->tce_stats;
1147 if (nelements <= 0 || usp == NULL)
1148 return (0);
1149
1150 nskip = ap->nskip;
1151 n = 0;
1152 LIST_FOREACH(cb, &top->tc_elements, cb_next) {
1153 if (nskip > 0) {
1154 nskip--;
1155 continue;
1156 }
1157
1158 bzero(&tce, sizeof(tce));
1159 tce.tce_handle = cb->cb_handle;
1160 tce.tce_type = cb->cb_type;
1161 switch (cb->cb_type) {
1162 case TCETYPE_TBMETER:
1163 tbm = (struct tbmeter *)cb;
1164 tce.tce_cnts[0] = tbm->in_cnt;
1165 tce.tce_cnts[1] = tbm->out_cnt;
1166 break;
1167 case TCETYPE_TRTCM:
1168 tcm = (struct trtcm *)cb;
1169 tce.tce_cnts[0] = tcm->green_cnt;
1170 tce.tce_cnts[1] = tcm->yellow_cnt;
1171 tce.tce_cnts[2] = tcm->red_cnt;
1172 break;
1173 case TCETYPE_TSWTCM:
1174 tsw = (struct tswtcm *)cb;
1175 tce.tce_cnts[0] = tsw->green_cnt;
1176 tce.tce_cnts[1] = tsw->yellow_cnt;
1177 tce.tce_cnts[2] = tsw->red_cnt;
1178 break;
1179 default:
1180 continue;
1181 }
1182
1183 if ((error = copyout((caddr_t)&tce, (caddr_t)usp++,
1184 sizeof(tce))) != 0)
1185 return (error);
1186
1187 if (++n == nelements)
1188 break;
1189 }
1190 ap->nelements = n;
1191
1192 return (0);
1193 }
1194
1195 /*
1196 * conditioner device interface
1197 */
1198 int
1199 cdnropen(devvp, flag, fmt, p)
1200 struct vnode *devvp;
1201 int flag, fmt;
1202 struct proc *p;
1203 {
1204 if (machclk_freq == 0)
1205 init_machclk();
1206
1207 if (machclk_freq == 0) {
1208 printf("cdnr: no cpu clock available!\n");
1209 return (ENXIO);
1210 }
1211
1212 /* everything will be done when the queueing scheme is attached. */
1213 return 0;
1214 }
1215
1216 int
1217 cdnrclose(devvp, flag, fmt, p)
1218 struct vnode *devvp;
1219 int flag, fmt;
1220 struct proc *p;
1221 {
1222 struct top_cdnr *top;
1223 int err, error = 0;
1224
1225 while ((top = LIST_FIRST(&tcb_list)) != NULL) {
1226 /* destroy all */
1227 err = top_destroy(top);
1228 if (err != 0 && error == 0)
1229 error = err;
1230 }
1231 altq_input = NULL;
1232
1233 return (error);
1234 }
1235
1236 int
1237 cdnrioctl(devvp, cmd, addr, flag, p)
1238 struct vnode *devvp;
1239 ioctlcmd_t cmd;
1240 caddr_t addr;
1241 int flag;
1242 struct proc *p;
1243 {
1244 struct top_cdnr *top;
1245 struct cdnr_interface *ifacep;
1246 int s, error = 0;
1247
1248 /* check super-user privilege */
1249 switch (cmd) {
1250 case CDNR_GETSTATS:
1251 break;
1252 default:
1253 #if (__FreeBSD_version > 400000)
1254 if ((error = suser(p)) != 0)
1255 #else
1256 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1257 #endif
1258 return (error);
1259 break;
1260 }
1261
1262 s = splnet();
1263 switch (cmd) {
1264
1265 case CDNR_IF_ATTACH:
1266 ifacep = (struct cdnr_interface *)addr;
1267 error = cdnrcmd_if_attach(ifacep->cdnr_ifname);
1268 break;
1269
1270 case CDNR_IF_DETACH:
1271 ifacep = (struct cdnr_interface *)addr;
1272 error = cdnrcmd_if_detach(ifacep->cdnr_ifname);
1273 break;
1274
1275 case CDNR_ENABLE:
1276 case CDNR_DISABLE:
1277 ifacep = (struct cdnr_interface *)addr;
1278 if ((top = tcb_lookup(ifacep->cdnr_ifname)) == NULL) {
1279 error = EBADF;
1280 break;
1281 }
1282
1283 switch (cmd) {
1284
1285 case CDNR_ENABLE:
1286 ALTQ_SET_CNDTNING(top->tc_ifq);
1287 if (altq_input == NULL)
1288 altq_input = altq_cdnr_input;
1289 break;
1290
1291 case CDNR_DISABLE:
1292 ALTQ_CLEAR_CNDTNING(top->tc_ifq);
1293 LIST_FOREACH(top, &tcb_list, tc_next)
1294 if (ALTQ_IS_CNDTNING(top->tc_ifq))
1295 break;
1296 if (top == NULL)
1297 altq_input = NULL;
1298 break;
1299 }
1300 break;
1301
1302 case CDNR_ADD_ELEM:
1303 error = cdnrcmd_add_element((struct cdnr_add_element *)addr);
1304 break;
1305
1306 case CDNR_DEL_ELEM:
1307 error = cdnrcmd_delete_element((struct cdnr_delete_element *)addr);
1308 break;
1309
1310 case CDNR_ADD_TBM:
1311 error = cdnrcmd_add_tbm((struct cdnr_add_tbmeter *)addr);
1312 break;
1313
1314 case CDNR_MOD_TBM:
1315 error = cdnrcmd_modify_tbm((struct cdnr_modify_tbmeter *)addr);
1316 break;
1317
1318 case CDNR_TBM_STATS:
1319 error = cdnrcmd_tbm_stats((struct cdnr_tbmeter_stats *)addr);
1320 break;
1321
1322 case CDNR_ADD_TCM:
1323 error = cdnrcmd_add_trtcm((struct cdnr_add_trtcm *)addr);
1324 break;
1325
1326 case CDNR_MOD_TCM:
1327 error = cdnrcmd_modify_trtcm((struct cdnr_modify_trtcm *)addr);
1328 break;
1329
1330 case CDNR_TCM_STATS:
1331 error = cdnrcmd_tcm_stats((struct cdnr_tcm_stats *)addr);
1332 break;
1333
1334 case CDNR_ADD_FILTER:
1335 error = cdnrcmd_add_filter((struct cdnr_add_filter *)addr);
1336 break;
1337
1338 case CDNR_DEL_FILTER:
1339 error = cdnrcmd_delete_filter((struct cdnr_delete_filter *)addr);
1340 break;
1341
1342 case CDNR_GETSTATS:
1343 error = cdnrcmd_get_stats((struct cdnr_get_stats *)addr);
1344 break;
1345
1346 case CDNR_ADD_TSW:
1347 error = cdnrcmd_add_tswtcm((struct cdnr_add_tswtcm *)addr);
1348 break;
1349
1350 case CDNR_MOD_TSW:
1351 error = cdnrcmd_modify_tswtcm((struct cdnr_modify_tswtcm *)addr);
1352 break;
1353
1354 default:
1355 error = EINVAL;
1356 break;
1357 }
1358 splx(s);
1359
1360 return error;
1361 }
1362
1363 #ifdef KLD_MODULE
1364
1365 static struct altqsw cdnr_sw =
1366 {"cdnr", cdnropen, cdnrclose, cdnrioctl};
1367
1368 ALTQ_MODULE(altq_cdnr, ALTQT_CDNR, &cdnr_sw);
1369
1370 #endif /* KLD_MODULE */
1371
1372 #endif /* ALTQ_CDNR */
1373