1/* $NetBSD: qop_cdnr.c,v 1.3 2001/08/16 07:48:13 itojun Exp $ */ 2/* $KAME: qop_cdnr.c,v 1.9 2001/08/16 10:39:14 kjc Exp $ */ 3/* 4 * Copyright (C) 1999-2000 5 * Sony Computer Science Laboratories, Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/param.h> 30#include <sys/socket.h> 31#include <sys/sockio.h> 32#include <sys/ioctl.h> 33#include <sys/fcntl.h> 34#include <net/if.h> 35#include <netinet/in.h> 36#include <arpa/inet.h> 37 38#include <stdio.h> 39#include <stdlib.h> 40#include <unistd.h> 41#include <stddef.h> 42#include <string.h> 43#include <ctype.h> 44#include <errno.h> 45#include <syslog.h> 46#include <netdb.h> 47 48#include <altq/altq.h> 49#include <altq/altq_cdnr.h> 50#include "altq_qop.h" 51#include "qop_cdnr.h" 52/* 53 * diffserve traffic conditioner support 54 * 55 * we use the existing qop interface to support conditioner. 56 */ 57 58static struct ifinfo *cdnr_ifname2ifinfo(const char *); 59static int cdnr_attach(struct ifinfo *); 60static int cdnr_detach(struct ifinfo *); 61static int cdnr_enable(struct ifinfo *); 62static int cdnr_disable(struct ifinfo *); 63static int cdnr_add_class(struct classinfo *); 64static int cdnr_modify_class(struct classinfo *, void *); 65static int cdnr_delete_class(struct classinfo *); 66static int cdnr_add_filter(struct fltrinfo *); 67static int cdnr_delete_filter(struct fltrinfo *); 68static int verify_tbprofile(struct tb_profile *, const char *); 69 70#define CDNR_DEVICE "/dev/altq/cdnr" 71 72static int cdnr_fd = -1; 73static int cdnr_refcount = 0; 74 75static struct qdisc_ops cdnr_qdisc = { 76 ALTQT_CDNR, 77 "cdnr", 78 cdnr_attach, 79 cdnr_detach, 80 NULL, /* clear */ 81 cdnr_enable, 82 cdnr_disable, 83 cdnr_add_class, 84 cdnr_modify_class, 85 cdnr_delete_class, 86 cdnr_add_filter, 87 cdnr_delete_filter, 88}; 89 90u_long 91cdnr_name2handle(const char *ifname, const char *cdnr_name) 92{ 93 struct ifinfo *ifinfo; 94 struct classinfo *clinfo; 95 96 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL) 97 return (CDNR_NULL_HANDLE); 98 99 if ((clinfo = clname2clinfo(ifinfo, cdnr_name)) == NULL) 100 return (CDNR_NULL_HANDLE); 101 102 return (clinfo->handle); 103} 104 105static struct ifinfo * 106cdnr_ifname2ifinfo(const char *ifname) 107{ 108 struct ifinfo *ifinfo; 109 char input_ifname[64]; 110 111 /* 112 * search for an existing input interface 113 */ 114 if ((ifinfo = input_ifname2ifinfo(ifname)) != NULL) 115 return (ifinfo); 116 117 /* 118 * if there is a corresponding output interface, 119 * create an input interface by prepending "_" to 120 * its name. 121 */ 122 if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 123 return (NULL); 124 125 input_ifname[0] = '_'; 126 strlcpy(input_ifname+1, ifname, sizeof(input_ifname)-1); 127 if (qop_add_if(&ifinfo, input_ifname, 0, &cdnr_qdisc, NULL) != 0) { 128 LOG(LOG_ERR, errno, 129 "cdnr_ifname2ifinfo: can't add a input interface %s", 130 ifname); 131 return (NULL); 132 } 133 return (ifinfo); 134} 135 136int 137qcmd_cdnr_add_element(struct tc_action *rp, const char *ifname, 138 const char *cdnr_name, struct tc_action *action) 139{ 140 struct ifinfo *ifinfo; 141 struct classinfo *clinfo; 142 int error; 143 144 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL) 145 return (QOPERR_BADIF); 146 147 if ((error = qop_cdnr_add_element(&clinfo, cdnr_name, ifinfo, 148 action)) != 0) { 149 LOG(LOG_ERR, errno, "%s: add element failed!", 150 qoperror(error)); 151 return (error); 152 } 153 154 if (rp != NULL) { 155 rp->tca_code = TCACODE_HANDLE; 156 rp->tca_handle = clinfo->handle; 157 } 158 return (0); 159} 160 161int 162qcmd_cdnr_add_tbmeter(struct tc_action *rp, const char *ifname, 163 const char *cdnr_name, 164 struct tb_profile *profile, 165 struct tc_action *in_action, 166 struct tc_action *out_action) 167{ 168 struct ifinfo *ifinfo; 169 struct classinfo *clinfo; 170 int error; 171 172 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL) 173 return (QOPERR_BADIF); 174 175 verify_tbprofile(profile, cdnr_name); 176 177 if ((error = qop_cdnr_add_tbmeter(&clinfo, cdnr_name, ifinfo, 178 profile, in_action, out_action)) != 0) { 179 LOG(LOG_ERR, errno, "%s: add tbmeter failed!", 180 qoperror(error)); 181 return (error); 182 } 183 184 if (rp != NULL) { 185 rp->tca_code = TCACODE_HANDLE; 186 rp->tca_handle = clinfo->handle; 187 } 188 return (0); 189} 190 191int 192qcmd_cdnr_add_trtcm(struct tc_action *rp, const char *ifname, 193 const char *cdnr_name, 194 struct tb_profile *cmtd_profile, 195 struct tb_profile *peak_profile, 196 struct tc_action *green_action, 197 struct tc_action *yellow_action, 198 struct tc_action *red_action, int coloraware) 199{ 200 struct ifinfo *ifinfo; 201 struct classinfo *clinfo; 202 int error; 203 204 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL) 205 return (QOPERR_BADIF); 206 207 verify_tbprofile(cmtd_profile, cdnr_name); 208 verify_tbprofile(peak_profile, cdnr_name); 209 210 if ((error = qop_cdnr_add_trtcm(&clinfo, cdnr_name, ifinfo, 211 cmtd_profile, peak_profile, 212 green_action, yellow_action, red_action, 213 coloraware)) != 0) { 214 LOG(LOG_ERR, errno, "%s: add trtcm failed!", 215 qoperror(error)); 216 return (error); 217 } 218 219 if (rp != NULL) { 220 rp->tca_code = TCACODE_HANDLE; 221 rp->tca_handle = clinfo->handle; 222 } 223 return (0); 224} 225 226int 227qcmd_cdnr_add_tswtcm(struct tc_action *rp, const char *ifname, 228 const char *cdnr_name, const u_int32_t cmtd_rate, 229 const u_int32_t peak_rate, const u_int32_t avg_interval, 230 struct tc_action *green_action, 231 struct tc_action *yellow_action, 232 struct tc_action *red_action) 233{ 234 struct ifinfo *ifinfo; 235 struct classinfo *clinfo; 236 int error; 237 238 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL) 239 return (QOPERR_BADIF); 240 241 if (cmtd_rate > peak_rate) { 242 LOG(LOG_ERR, 0, 243 "add tswtcm: cmtd_rate larger than peak_rate!"); 244 return (QOPERR_INVAL); 245 } 246 247 if ((error = qop_cdnr_add_tswtcm(&clinfo, cdnr_name, ifinfo, 248 cmtd_rate, peak_rate, avg_interval, 249 green_action, yellow_action, 250 red_action)) != 0) { 251 LOG(LOG_ERR, errno, "%s: add tswtcm failed!", 252 qoperror(error)); 253 return (error); 254 } 255 256 if (rp != NULL) { 257 rp->tca_code = TCACODE_HANDLE; 258 rp->tca_handle = clinfo->handle; 259 } 260 return (0); 261} 262 263int 264qcmd_cdnr_delete(const char *ifname, const char *cdnr_name) 265{ 266 struct ifinfo *ifinfo; 267 struct classinfo *clinfo; 268 269 if ((ifinfo = cdnr_ifname2ifinfo(ifname)) == NULL) 270 return (QOPERR_BADIF); 271 272 if ((clinfo = clname2clinfo(ifinfo, cdnr_name)) == NULL) 273 return (QOPERR_BADCLASS); 274 275 return qop_delete_cdnr(clinfo); 276} 277 278/* 279 * class operations: 280 * class structure is used to hold conditioners. 281 * XXX 282 * conditioners has dependencies in the reverse order; parent nodes 283 * refere to child nodes, and thus, a child is created first and 284 * parents should be removed first. 285 * qop_add_cdnr() and qop_delete_cdnr() are wrapper functions 286 * of qop_add_class() and qop_delete_class(), and takes care 287 * of dependencies. 288 * 1. when adding a conditioner, it is created as a child of a 289 * dummy root class. then, the child conditioners are made 290 * as its children. 291 * 2. when deleting a conditioner, its child conditioners are made 292 * as children of the dummy root class. then, the conditioner 293 * is deleted. 294 */ 295 296int 297qop_add_cdnr(struct classinfo **rp, const char *cdnr_name, 298 struct ifinfo *ifinfo, struct classinfo **childlist, 299 void *cdnr_private) 300{ 301 struct classinfo *clinfo, *root, *cl, *prev; 302 int error; 303 304 /* 305 * if there is no root cdnr, create one. 306 */ 307 if ((root = get_rootclass(ifinfo)) == NULL) { 308 if ((error = qop_add_class(&root, "cdnr_root", 309 ifinfo, NULL, NULL)) != 0) { 310 LOG(LOG_ERR, errno, 311 "cdnr: %s: can't create dummy root cdnr on %s!", 312 qoperror(error), ifinfo->ifname); 313 return (QOPERR_CLASS); 314 } 315 } 316 317 /* 318 * create a class as a child of a root class. 319 */ 320 if ((error = qop_add_class(&clinfo, cdnr_name, 321 ifinfo, root, cdnr_private)) != 0) 322 return (error); 323 /* 324 * move child nodes 325 */ 326 for (cl = *childlist; cl != NULL; cl = *++childlist) { 327 if (cl->parent != root) { 328 /* 329 * this conditioner already has a non-root parent. 330 * we can't track down a multi-parent node by a 331 * tree structure; leave it as it is. 332 * (we need a mechanism similar to a symbolic link 333 * in a file system) 334 */ 335 continue; 336 } 337 /* remove this child from the root */ 338 if (root->child == cl) 339 root->child = cl->sibling; 340 else for (prev = root->child; 341 prev->sibling != NULL; prev = prev->sibling) 342 if (prev->sibling == cl) { 343 prev->sibling = cl->sibling; 344 break; 345 } 346 347 /* add as a child */ 348 cl->sibling = clinfo->child; 349 clinfo->child = cl; 350 cl->parent = clinfo; 351 } 352 353 if (rp != NULL) 354 *rp = clinfo; 355 return (0); 356} 357 358int 359qop_delete_cdnr(struct classinfo *clinfo) 360{ 361 struct classinfo *cl, *root; 362 int error; 363 364 if ((root = get_rootclass(clinfo->ifinfo)) == NULL) { 365 LOG(LOG_ERR, 0, "qop_delete_cdnr: no root cdnr!"); 366 return (QOPERR_CLASS); 367 } 368 369 if (clinfo->parent != root) 370 return (QOPERR_CLASS_PERM); 371 372 if ((cl = clinfo->child) != NULL) { 373 /* change child's parent to root, find the last child */ 374 while (cl->sibling != NULL) { 375 cl->parent = root; 376 cl = cl->sibling; 377 } 378 cl->parent = root; 379 380 /* move children to siblings */ 381 cl->sibling = clinfo->sibling; 382 clinfo->sibling = cl; 383 clinfo->child = NULL; 384 } 385 386 error = qop_delete_class(clinfo); 387 388 if (error) { 389 /* ick! restore the class tree */ 390 if (cl != NULL) { 391 clinfo->child = clinfo->sibling; 392 clinfo->sibling = cl->sibling; 393 cl->sibling = NULL; 394 /* restore parent field */ 395 for (cl = clinfo->child; cl != NULL; cl = cl->sibling) 396 cl->parent = clinfo; 397 } 398 } 399 return (error); 400} 401 402int 403qop_cdnr_add_element(struct classinfo **rp, const char *cdnr_name, 404 struct ifinfo *ifinfo, struct tc_action *action) 405{ 406 struct classinfo *clinfo, *clist[2]; 407 struct cdnrinfo *cdnrinfo = NULL; 408 int error; 409 410 if (action->tca_code == TCACODE_HANDLE) { 411 clinfo = clhandle2clinfo(ifinfo, action->tca_handle); 412 if (clinfo == NULL) 413 return (QOPERR_BADCLASS); 414 clist[0] = clinfo; 415 clist[1] = NULL; 416#if 1 417 /* 418 * if the conditioner referred to doesn't have a name, 419 * this is called just to add a name to it. 420 * we can simply add the name to the existing conditioner 421 * and return it. 422 */ 423 if (cdnr_name != NULL && 424 strcmp(clinfo->clname, "(null)") == 0) { 425 free(clinfo->clname); 426 clinfo->clname = strdup(cdnr_name); 427 if (rp != NULL) 428 *rp = clinfo; 429 return (0); 430 } 431#endif 432 } else 433 clist[0] = NULL; 434 435 if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL) 436 return (QOPERR_NOMEM); 437 438 cdnrinfo->tce_type = TCETYPE_ELEMENT; 439 cdnrinfo->tce_un.element.action = *action; 440 441 if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist, 442 cdnrinfo)) != 0) 443 goto err_ret; 444 445 if (rp != NULL) 446 *rp = clinfo; 447 return (0); 448 449 err_ret: 450 if (cdnrinfo != NULL) 451 free(cdnrinfo); 452 return (error); 453} 454 455int 456qop_cdnr_add_tbmeter(struct classinfo **rp, const char *cdnr_name, 457 struct ifinfo *ifinfo, 458 struct tb_profile *profile, 459 struct tc_action *in_action, 460 struct tc_action *out_action) 461{ 462 struct classinfo *clinfo, *clist[3]; 463 struct cdnrinfo *cdnrinfo = NULL; 464 int n, error; 465 466 n = 0; 467 if (in_action->tca_code == TCACODE_HANDLE) { 468 clist[n] = clhandle2clinfo(ifinfo, in_action->tca_handle); 469 if (clist[n] == NULL) 470 return (QOPERR_BADCLASS); 471 n++; 472 } 473 if (out_action->tca_code == TCACODE_HANDLE) { 474 clist[n] = clhandle2clinfo(ifinfo, out_action->tca_handle); 475 if (clist[n] == NULL) 476 return (QOPERR_BADCLASS); 477 n++; 478 } 479 clist[n] = NULL; 480 481 if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL) 482 return (QOPERR_NOMEM); 483 484 cdnrinfo->tce_type = TCETYPE_TBMETER; 485 cdnrinfo->tce_un.tbmeter.profile = *profile; 486 cdnrinfo->tce_un.tbmeter.in_action = *in_action; 487 cdnrinfo->tce_un.tbmeter.out_action = *out_action; 488 489 if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist, 490 cdnrinfo)) != 0) 491 goto err_ret; 492 493 if (rp != NULL) 494 *rp = clinfo; 495 return (0); 496 497 err_ret: 498 if (cdnrinfo != NULL) 499 free(cdnrinfo); 500 return (error); 501} 502 503int 504qop_cdnr_modify_tbmeter(struct classinfo *clinfo, struct tb_profile *profile) 505{ 506 struct cdnrinfo *cdnrinfo = clinfo->private; 507 508 if (cdnrinfo->tce_type != TCETYPE_TBMETER) 509 return (QOPERR_CLASS_INVAL); 510 cdnrinfo->tce_un.tbmeter.profile = *profile; 511 512 return qop_modify_class(clinfo, NULL); 513} 514 515int 516qop_cdnr_add_trtcm(struct classinfo **rp, const char *cdnr_name, 517 struct ifinfo *ifinfo, 518 struct tb_profile *cmtd_profile, 519 struct tb_profile *peak_profile, 520 struct tc_action *green_action, 521 struct tc_action *yellow_action, 522 struct tc_action *red_action, int coloraware) 523{ 524 struct classinfo *clinfo, *clist[4]; 525 struct cdnrinfo *cdnrinfo = NULL; 526 int n, error; 527 528 n = 0; 529 if (green_action->tca_code == TCACODE_HANDLE) { 530 clist[n] = clhandle2clinfo(ifinfo, green_action->tca_handle); 531 if (clist[n] == NULL) 532 return (QOPERR_BADCLASS); 533 n++; 534 } 535 if (yellow_action->tca_code == TCACODE_HANDLE) { 536 clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle); 537 if (clist[n] == NULL) 538 return (QOPERR_BADCLASS); 539 n++; 540 } 541 if (red_action->tca_code == TCACODE_HANDLE) { 542 clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle); 543 if (clist[n] == NULL) 544 return (QOPERR_BADCLASS); 545 n++; 546 } 547 clist[n] = NULL; 548 549 if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL) 550 return (QOPERR_NOMEM); 551 552 cdnrinfo->tce_type = TCETYPE_TRTCM; 553 cdnrinfo->tce_un.trtcm.cmtd_profile = *cmtd_profile; 554 cdnrinfo->tce_un.trtcm.peak_profile = *peak_profile; 555 cdnrinfo->tce_un.trtcm.green_action = *green_action; 556 cdnrinfo->tce_un.trtcm.yellow_action = *yellow_action; 557 cdnrinfo->tce_un.trtcm.red_action = *red_action; 558 cdnrinfo->tce_un.trtcm.coloraware = coloraware; 559 560 if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist, 561 cdnrinfo)) != 0) 562 goto err_ret; 563 564 if (rp != NULL) 565 *rp = clinfo; 566 return (0); 567 568 err_ret: 569 if (cdnrinfo != NULL) 570 free(cdnrinfo); 571 return (error); 572} 573 574int 575qop_cdnr_modify_trtcm(struct classinfo *clinfo, 576 struct tb_profile *cmtd_profile, 577 struct tb_profile *peak_profile, int coloraware) 578{ 579 struct cdnrinfo *cdnrinfo = clinfo->private; 580 581 if (cdnrinfo->tce_type != TCETYPE_TRTCM) 582 return (QOPERR_CLASS_INVAL); 583 cdnrinfo->tce_un.trtcm.cmtd_profile = *cmtd_profile; 584 cdnrinfo->tce_un.trtcm.peak_profile = *peak_profile; 585 cdnrinfo->tce_un.trtcm.coloraware = coloraware; 586 587 return qop_modify_class(clinfo, NULL); 588} 589 590int 591qop_cdnr_add_tswtcm(struct classinfo **rp, const char *cdnr_name, 592 struct ifinfo *ifinfo, const u_int32_t cmtd_rate, 593 const u_int32_t peak_rate, const u_int32_t avg_interval, 594 struct tc_action *green_action, 595 struct tc_action *yellow_action, 596 struct tc_action *red_action) 597{ 598 struct classinfo *clinfo, *clist[4]; 599 struct cdnrinfo *cdnrinfo = NULL; 600 int n, error; 601 602 n = 0; 603 if (green_action->tca_code == TCACODE_HANDLE) { 604 clist[n] = clhandle2clinfo(ifinfo, green_action->tca_handle); 605 if (clist[n] == NULL) 606 return (QOPERR_BADCLASS); 607 n++; 608 } 609 if (yellow_action->tca_code == TCACODE_HANDLE) { 610 clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle); 611 if (clist[n] == NULL) 612 return (QOPERR_BADCLASS); 613 n++; 614 } 615 if (red_action->tca_code == TCACODE_HANDLE) { 616 clist[n] = clhandle2clinfo(ifinfo, yellow_action->tca_handle); 617 if (clist[n] == NULL) 618 return (QOPERR_BADCLASS); 619 n++; 620 } 621 clist[n] = NULL; 622 623 if ((cdnrinfo = calloc(1, sizeof(*cdnrinfo))) == NULL) 624 return (QOPERR_NOMEM); 625 626 cdnrinfo->tce_type = TCETYPE_TSWTCM; 627 cdnrinfo->tce_un.tswtcm.cmtd_rate = cmtd_rate; 628 cdnrinfo->tce_un.tswtcm.peak_rate = peak_rate; 629 cdnrinfo->tce_un.tswtcm.avg_interval = avg_interval; 630 cdnrinfo->tce_un.tswtcm.green_action = *green_action; 631 cdnrinfo->tce_un.tswtcm.yellow_action = *yellow_action; 632 cdnrinfo->tce_un.tswtcm.red_action = *red_action; 633 634 if ((error = qop_add_cdnr(&clinfo, cdnr_name, ifinfo, clist, 635 cdnrinfo)) != 0) 636 goto err_ret; 637 638 if (rp != NULL) 639 *rp = clinfo; 640 return (0); 641 642 err_ret: 643 if (cdnrinfo != NULL) 644 free(cdnrinfo); 645 return (error); 646} 647 648int 649qop_cdnr_modify_tswtcm(struct classinfo *clinfo, const u_int32_t cmtd_rate, 650 const u_int32_t peak_rate, const u_int32_t avg_interval) 651{ 652 struct cdnrinfo *cdnrinfo = clinfo->private; 653 654 if (cdnrinfo->tce_type != TCETYPE_TSWTCM) 655 return (QOPERR_CLASS_INVAL); 656 cdnrinfo->tce_un.tswtcm.cmtd_rate = cmtd_rate; 657 cdnrinfo->tce_un.tswtcm.peak_rate = peak_rate; 658 cdnrinfo->tce_un.tswtcm.avg_interval = avg_interval; 659 660 return qop_modify_class(clinfo, NULL); 661} 662 663/* 664 * system call interfaces for qdisc_ops 665 */ 666static int 667cdnr_attach(struct ifinfo *ifinfo) 668{ 669 struct cdnr_interface iface; 670 671 if (cdnr_fd < 0 && 672 (cdnr_fd = open(CDNR_DEVICE, O_RDWR)) < 0 && 673 (cdnr_fd = open_module(CDNR_DEVICE, O_RDWR)) < 0) { 674 LOG(LOG_ERR, errno, "CDNR open"); 675 return (QOPERR_SYSCALL); 676 } 677 678 cdnr_refcount++; 679 memset(&iface, 0, sizeof(iface)); 680 strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ); 681 682 if (ioctl(cdnr_fd, CDNR_IF_ATTACH, &iface) < 0) 683 return (QOPERR_SYSCALL); 684#if 1 685 LOG(LOG_INFO, 0, "conditioner attached to %s", iface.cdnr_ifname); 686#endif 687 return (0); 688} 689 690static int 691cdnr_detach(struct ifinfo *ifinfo) 692{ 693 struct cdnr_interface iface; 694 695 memset(&iface, 0, sizeof(iface)); 696 strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ); 697 698 if (ioctl(cdnr_fd, CDNR_IF_DETACH, &iface) < 0) 699 return (QOPERR_SYSCALL); 700 701 if (--cdnr_refcount == 0) { 702 close(cdnr_fd); 703 cdnr_fd = -1; 704 } 705 return (0); 706} 707 708static int 709cdnr_enable(struct ifinfo *ifinfo) 710{ 711 struct cdnr_interface iface; 712 713 memset(&iface, 0, sizeof(iface)); 714 strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ); 715 716 if (ioctl(cdnr_fd, CDNR_ENABLE, &iface) < 0) 717 return (QOPERR_SYSCALL); 718 return (0); 719} 720 721static int 722cdnr_disable(struct ifinfo *ifinfo) 723{ 724 struct cdnr_interface iface; 725 726 memset(&iface, 0, sizeof(iface)); 727 strncpy(iface.cdnr_ifname, ifinfo->ifname+1, IFNAMSIZ); 728 729 if (ioctl(cdnr_fd, CDNR_DISABLE, &iface) < 0) 730 return (QOPERR_SYSCALL); 731 return (0); 732} 733 734static int 735cdnr_add_class(struct classinfo *clinfo) 736{ 737 struct cdnr_add_element element_add; 738 struct cdnr_add_tbmeter tbmeter_add; 739 struct cdnr_add_trtcm trtcm_add; 740 struct cdnr_add_tswtcm tswtcm_add; 741 struct cdnrinfo *cdnrinfo; 742 743 cdnrinfo = clinfo->private; 744 745 /* root class is a dummy class */ 746 if (clinfo->parent == NULL) { 747 clinfo->handle = 0; 748 return (0); 749 } 750 751 switch (cdnrinfo->tce_type) { 752 case TCETYPE_ELEMENT: 753 memset(&element_add, 0, sizeof(element_add)); 754 strncpy(element_add.iface.cdnr_ifname, 755 clinfo->ifinfo->ifname+1, IFNAMSIZ); 756 element_add.action = cdnrinfo->tce_un.element.action; 757 if (ioctl(cdnr_fd, CDNR_ADD_ELEM, &element_add) < 0) { 758 clinfo->handle = CDNR_NULL_HANDLE; 759 return (QOPERR_SYSCALL); 760 } 761 clinfo->handle = element_add.cdnr_handle; 762 break; 763 764 case TCETYPE_TBMETER: 765 memset(&tbmeter_add, 0, sizeof(tbmeter_add)); 766 strncpy(tbmeter_add.iface.cdnr_ifname, 767 clinfo->ifinfo->ifname+1, IFNAMSIZ); 768 tbmeter_add.profile = cdnrinfo->tce_un.tbmeter.profile; 769 tbmeter_add.in_action = cdnrinfo->tce_un.tbmeter.in_action; 770 tbmeter_add.out_action = cdnrinfo->tce_un.tbmeter.out_action; 771 if (ioctl(cdnr_fd, CDNR_ADD_TBM, &tbmeter_add) < 0) { 772 clinfo->handle = CDNR_NULL_HANDLE; 773 return (QOPERR_SYSCALL); 774 } 775 clinfo->handle = tbmeter_add.cdnr_handle; 776 break; 777 778 case TCETYPE_TRTCM: 779 memset(&trtcm_add, 0, sizeof(trtcm_add)); 780 strncpy(trtcm_add.iface.cdnr_ifname, 781 clinfo->ifinfo->ifname+1, IFNAMSIZ); 782 trtcm_add.cmtd_profile = cdnrinfo->tce_un.trtcm.cmtd_profile; 783 trtcm_add.peak_profile = cdnrinfo->tce_un.trtcm.peak_profile; 784 trtcm_add.green_action = cdnrinfo->tce_un.trtcm.green_action; 785 trtcm_add.yellow_action = cdnrinfo->tce_un.trtcm.yellow_action; 786 trtcm_add.red_action = cdnrinfo->tce_un.trtcm.red_action; 787 trtcm_add.coloraware = cdnrinfo->tce_un.trtcm.coloraware; 788 if (ioctl(cdnr_fd, CDNR_ADD_TCM, &trtcm_add) < 0) { 789 clinfo->handle = CDNR_NULL_HANDLE; 790 return (QOPERR_SYSCALL); 791 } 792 clinfo->handle = trtcm_add.cdnr_handle; 793 break; 794 795 case TCETYPE_TSWTCM: 796 memset(&tswtcm_add, 0, sizeof(tswtcm_add)); 797 strncpy(tswtcm_add.iface.cdnr_ifname, 798 clinfo->ifinfo->ifname+1, IFNAMSIZ); 799 tswtcm_add.cmtd_rate = cdnrinfo->tce_un.tswtcm.cmtd_rate; 800 tswtcm_add.peak_rate = cdnrinfo->tce_un.tswtcm.peak_rate; 801 tswtcm_add.avg_interval = cdnrinfo->tce_un.tswtcm.avg_interval; 802 tswtcm_add.green_action = cdnrinfo->tce_un.tswtcm.green_action; 803 tswtcm_add.yellow_action = cdnrinfo->tce_un.tswtcm.yellow_action; 804 tswtcm_add.red_action = cdnrinfo->tce_un.tswtcm.red_action; 805 if (ioctl(cdnr_fd, CDNR_ADD_TSW, &tswtcm_add) < 0) { 806 clinfo->handle = CDNR_NULL_HANDLE; 807 return (QOPERR_SYSCALL); 808 } 809 clinfo->handle = tswtcm_add.cdnr_handle; 810 break; 811 812 default: 813 return (QOPERR_CLASS_INVAL); 814 } 815 return (0); 816} 817 818static int 819cdnr_modify_class(struct classinfo *clinfo, void *arg) 820{ 821 struct cdnr_modify_tbmeter tbmeter_modify; 822 struct cdnr_modify_trtcm trtcm_modify; 823 struct cdnr_modify_tswtcm tswtcm_modify; 824 struct cdnrinfo *cdnrinfo; 825 826 cdnrinfo = clinfo->private; 827 828 switch (cdnrinfo->tce_type) { 829 case TCETYPE_TBMETER: 830 memset(&tbmeter_modify, 0, sizeof(tbmeter_modify)); 831 strncpy(tbmeter_modify.iface.cdnr_ifname, 832 clinfo->ifinfo->ifname+1, IFNAMSIZ); 833 tbmeter_modify.cdnr_handle = clinfo->handle; 834 tbmeter_modify.profile = cdnrinfo->tce_un.tbmeter.profile; 835 if (ioctl(cdnr_fd, CDNR_MOD_TBM, &tbmeter_modify) < 0) 836 return (QOPERR_SYSCALL); 837 break; 838 839 case TCETYPE_TRTCM: 840 memset(&trtcm_modify, 0, sizeof(trtcm_modify)); 841 strncpy(trtcm_modify.iface.cdnr_ifname, 842 clinfo->ifinfo->ifname+1, IFNAMSIZ); 843 trtcm_modify.cdnr_handle = clinfo->handle; 844 trtcm_modify.cmtd_profile = 845 cdnrinfo->tce_un.trtcm.cmtd_profile; 846 trtcm_modify.peak_profile = 847 cdnrinfo->tce_un.trtcm.peak_profile; 848 trtcm_modify.coloraware = cdnrinfo->tce_un.trtcm.coloraware; 849 if (ioctl(cdnr_fd, CDNR_MOD_TCM, &trtcm_modify) < 0) 850 return (QOPERR_SYSCALL); 851 break; 852 853 case TCETYPE_TSWTCM: 854 memset(&tswtcm_modify, 0, sizeof(tswtcm_modify)); 855 strncpy(tswtcm_modify.iface.cdnr_ifname, 856 clinfo->ifinfo->ifname+1, IFNAMSIZ); 857 tswtcm_modify.cdnr_handle = clinfo->handle; 858 tswtcm_modify.cmtd_rate = cdnrinfo->tce_un.tswtcm.cmtd_rate; 859 tswtcm_modify.peak_rate = cdnrinfo->tce_un.tswtcm.peak_rate; 860 tswtcm_modify.avg_interval = cdnrinfo->tce_un.tswtcm.avg_interval; 861 if (ioctl(cdnr_fd, CDNR_MOD_TSW, &tswtcm_modify) < 0) 862 return (QOPERR_SYSCALL); 863 break; 864 865 default: 866 return (QOPERR_CLASS_INVAL); 867 } 868 return (0); 869} 870 871static int 872cdnr_delete_class(struct classinfo *clinfo) 873{ 874 struct cdnr_delete_element element_delete; 875 876 if (clinfo->handle == CDNR_NULL_HANDLE) 877 return (0); 878 879 memset(&element_delete, 0, sizeof(element_delete)); 880 strncpy(element_delete.iface.cdnr_ifname, clinfo->ifinfo->ifname+1, 881 IFNAMSIZ); 882 element_delete.cdnr_handle = clinfo->handle; 883 884 if (ioctl(cdnr_fd, CDNR_DEL_ELEM, &element_delete) < 0) 885 return (QOPERR_SYSCALL); 886 return (0); 887} 888 889static int 890cdnr_add_filter(struct fltrinfo *fltrinfo) 891{ 892 struct cdnr_add_filter fltr_add; 893 894 memset(&fltr_add, 0, sizeof(fltr_add)); 895 strncpy(fltr_add.iface.cdnr_ifname, 896 fltrinfo->clinfo->ifinfo->ifname+1, IFNAMSIZ); 897 fltr_add.cdnr_handle = fltrinfo->clinfo->handle; 898 fltr_add.filter = fltrinfo->fltr; 899 900 if (ioctl(cdnr_fd, CDNR_ADD_FILTER, &fltr_add) < 0) 901 return (QOPERR_SYSCALL); 902 fltrinfo->handle = fltr_add.filter_handle; 903 return (0); 904} 905 906static int 907cdnr_delete_filter(struct fltrinfo *fltrinfo) 908{ 909 struct cdnr_delete_filter fltr_del; 910 911 memset(&fltr_del, 0, sizeof(fltr_del)); 912 strncpy(fltr_del.iface.cdnr_ifname, 913 fltrinfo->clinfo->ifinfo->ifname+1, IFNAMSIZ); 914 fltr_del.filter_handle = fltrinfo->handle; 915 916 if (ioctl(cdnr_fd, CDNR_DEL_FILTER, &fltr_del) < 0) 917 return (QOPERR_SYSCALL); 918 return (0); 919} 920 921 922static int 923verify_tbprofile(struct tb_profile *profile, const char *cdnr_name) 924{ 925 if (profile->depth < 1500) { 926 LOG(LOG_WARNING, 0, 927 "warning: token bucket depth for %s is too small (%d)", 928 cdnr_name, profile->depth); 929 return (-1); 930 } 931 return (0); 932} 933 934