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