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