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