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