This source file includes following definitions.
- LIST_HEAD
- altq_cdnr_input
- tcb_lookup
- cdnr_handle2cb
- cdnr_cb2handle
- cdnr_cballoc
- cdnr_cbdestroy
- generic_element_destroy
- tca_verify_action
- tca_import_action
- tca_invalidate_action
- top_create
- top_destroy
- element_create
- element_destroy
- tb_import_profile
- tbm_create
- tbm_destroy
- tbm_input
- trtcm_create
- trtcm_destroy
- trtcm_input
- tswtcm_create
- tswtcm_destroy
- tswtcm_input
- cdnrcmd_if_attach
- cdnrcmd_if_detach
- cdnrcmd_add_element
- cdnrcmd_delete_element
- cdnrcmd_add_tbm
- cdnrcmd_modify_tbm
- cdnrcmd_tbm_stats
- cdnrcmd_add_trtcm
- cdnrcmd_modify_trtcm
- cdnrcmd_tcm_stats
- cdnrcmd_add_tswtcm
- cdnrcmd_modify_tswtcm
- cdnrcmd_get_stats
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
54
55
56 int altq_cdnr_enabled = 0;
57
58
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
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
140
141
142 int
143 altq_cdnr_input(m, af)
144 struct mbuf *m;
145 int af;
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
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
304
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
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
326 if (cb->cb_top != cblock)
327 LIST_REMOVE(cb, cb_next);
328
329 FREE(cb, M_DEVBUF);
330 }
331
332
333
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
372 break;
373
374 case TCACODE_HANDLE:
375
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
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
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
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
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
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
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
522
523
524
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
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
623
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
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
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
751
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
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
790 tsw->cmtd_rate = cmtd_rate / 8;
791 tsw->peak_rate = peak_rate / 8;
792 tsw->avg_rate = 0;
793
794
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
827
828 len = pktinfo->pkt_len;
829 now = read_machclk();
830
831 interval = now - tsw->t_front;
832
833
834
835
836
837
838
839
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
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
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
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
872 pktinfo->pkt_dscp = tsw->green_dscp;
873 PKTCNTR_ADD(&tsw->green_cnt, len);
874 return (&tsw->green_action);
875 }
876
877
878
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
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
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
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
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
1094 tsw->cmtd_rate = ap->cmtd_rate / 8;
1095 tsw->peak_rate = ap->peak_rate / 8;
1096 tsw->avg_rate = 0;
1097
1098
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
1120 bcopy(top->tc_cnts, ap->cnts, sizeof(ap->cnts));
1121
1122
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 }