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