1 /* $KAME: qop.c,v 1.6 2000/10/18 09:15:18 kjc Exp $ */ 2 /* 3 * Copyright (C) 1999-2000 4 * Sony Computer Science Laboratories, Inc. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/socket.h> 30 #include <sys/sockio.h> 31 #include <sys/ioctl.h> 32 #include <sys/fcntl.h> 33 #include <sys/stat.h> 34 #if defined(__FreeBSD__) && (__FreeBSD_version > 300000) 35 #include <sys/linker.h> 36 #endif 37 38 #include <net/if.h> 39 #include <netinet/in.h> 40 #include <arpa/inet.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <unistd.h> 44 #include <stddef.h> 45 #include <string.h> 46 #include <ctype.h> 47 #include <errno.h> 48 #include <err.h> 49 #include <syslog.h> 50 51 #include <altq/altq.h> 52 #include <altq/altq_red.h> 53 #include <altq/altq_rio.h> 54 #include <altq/altq_cdnr.h> 55 #include "altq_qop.h" 56 #include "qop_cdnr.h" 57 58 #define ALTQ_DEVICE "/dev/altq/altq" 59 #define RED_DEVICE "/dev/altq/red" 60 #define RIO_DEVICE "/dev/altq/rio" 61 #define CDNR_DEVICE "/dev/altq/cdnr" 62 63 #ifndef LIST_HEAD_INITIALIZER 64 #define LIST_HEAD_INITIALIZER(head) { NULL } 65 #endif 66 67 /* 68 * token bucket regulator information 69 */ 70 struct tbrinfo { 71 LIST_ENTRY(tbrinfo) link; 72 char ifname[IFNAMSIZ]; /* if name, e.g. "en0" */ 73 struct tb_profile tb_prof, otb_prof; 74 int installed; 75 }; 76 77 /* 78 * Static globals 79 */ 80 /* a list of configured interfaces */ 81 LIST_HEAD(qop_iflist, ifinfo) qop_iflist = LIST_HEAD_INITIALIZER(&iflist); 82 /* a list of configured token bucket regulators */ 83 LIST_HEAD(tbr_list, tbrinfo) tbr_list = LIST_HEAD_INITIALIZER(&tbr_list); 84 int Debug_mode = 0; /* nosched (dummy mode) */ 85 86 /* 87 * internal functions 88 */ 89 static int get_ifmtu(const char *ifname); 90 static void tbr_install(const char *ifname); 91 static void tbr_deinstall(const char *ifname); 92 static int add_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo, 93 struct fltrinfo **conflict); 94 static int remove_filter_rule(struct ifinfo *ifinfo, 95 struct fltrinfo *fltrinfo); 96 static int filt_check_relation(struct flow_filter *front, 97 struct flow_filter *back); 98 static int filt_disjoint(struct flow_filter *front, struct flow_filter *back); 99 static int filt_subset(struct flow_filter *front, struct flow_filter *back); 100 101 /* 102 * QCMD (Queue Command) API 103 */ 104 int 105 qcmd_init(void) 106 { 107 int error; 108 109 /* read config file and execute commands */ 110 error = qcmd_config(); 111 112 if (error == 0) 113 error = qcmd_enableall(); 114 115 if (error != 0) 116 LOG(LOG_ERR, errno, "%s: qcmd_init failed.\n", 117 qoperror(error)); 118 return (error); 119 } 120 121 int 122 qcmd_enable(const char *ifname) 123 { 124 struct ifinfo *ifinfo; 125 int error = 0; 126 127 if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 128 error = QOPERR_BADIF; 129 130 if (error == 0) 131 error = qop_enable(ifinfo); 132 133 if (error == 0) { 134 LOG(LOG_INFO, 0, "%s enabled on interface %s (mtu:%d)\n", 135 ifinfo->qdisc->qname, ifname, ifinfo->ifmtu); 136 } else 137 LOG(LOG_ERR, errno, "%s: enable failed!\n", qoperror(error)); 138 return (error); 139 } 140 141 int 142 qcmd_disable(const char *ifname) 143 { 144 struct ifinfo *ifinfo; 145 int error = 0; 146 147 if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 148 error = QOPERR_BADIF; 149 150 if (error == 0) 151 error = qop_disable(ifinfo); 152 153 if (error != 0) 154 LOG(LOG_ERR, errno, "%s: disable failed!\n", qoperror(error)); 155 return (error); 156 } 157 158 int 159 qcmd_enableall() 160 { 161 struct ifinfo *ifinfo; 162 int error; 163 164 LIST_FOREACH(ifinfo, &qop_iflist, next) { 165 if ((error = qop_enable(ifinfo)) != 0) 166 return (error); 167 LOG(LOG_INFO, 0, "%s enabled on interface %s (mtu:%d)\n", 168 ifinfo->qdisc->qname, ifinfo->ifname, ifinfo->ifmtu); 169 } 170 return (0); 171 } 172 173 int 174 qcmd_disableall() 175 { 176 struct ifinfo *ifinfo; 177 int err, error = 0; 178 179 LIST_FOREACH(ifinfo, &qop_iflist, next) 180 if ((err = qop_disable(ifinfo)) != 0) 181 if (error == 0) 182 error = err; 183 return (error); 184 } 185 186 int 187 qcmd_clear(const char *ifname) 188 { 189 struct ifinfo *ifinfo; 190 int error = 0; 191 192 if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 193 error = QOPERR_BADIF; 194 195 if (error == 0) 196 error = qop_clear(ifinfo); 197 if (error != 0) 198 LOG(LOG_ERR, errno, "%s: clear failed!\n", qoperror(error)); 199 return (error); 200 } 201 202 int 203 qcmd_destroyall(void) 204 { 205 while (!LIST_EMPTY(&qop_iflist)) 206 (void)qop_delete_if(LIST_FIRST(&qop_iflist)); 207 return (0); 208 } 209 210 int 211 qcmd_restart(void) 212 { 213 qcmd_destroyall(); 214 return qcmd_init(); 215 } 216 217 int 218 qcmd_delete_class(const char *ifname, const char *clname) 219 { 220 struct ifinfo *ifinfo; 221 struct classinfo *clinfo; 222 int error = 0; 223 224 if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 225 error = QOPERR_BADIF; 226 227 if (error == 0 && 228 (clinfo = clname2clinfo(ifinfo, clname)) == NULL) 229 error = QOPERR_BADCLASS; 230 231 if (error == 0) 232 error = qop_delete_class(clinfo); 233 if (error != 0) 234 LOG(LOG_ERR, errno, "%s: delete_class failed\n", 235 qoperror(error)); 236 return (error); 237 } 238 239 int 240 qcmd_add_filter(const char *ifname, const char *clname, const char *flname, 241 const struct flow_filter *fltr) 242 { 243 struct ifinfo *ifinfo; 244 struct classinfo *clinfo; 245 int error = 0; 246 247 if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 248 error = QOPERR_BADIF; 249 250 if (error == 0 && 251 (clinfo = clname2clinfo(ifinfo, clname)) == NULL) { 252 /* 253 * there is no matching class. 254 * check if it is for a traffic conditioner 255 */ 256 if ((ifinfo = input_ifname2ifinfo(ifname)) == NULL || 257 (clinfo = clname2clinfo(ifinfo, clname)) == NULL) 258 error = QOPERR_BADCLASS; 259 } 260 261 if (error == 0) 262 error = qop_add_filter(NULL, clinfo, flname, fltr, NULL); 263 264 if (error != 0) 265 LOG(LOG_ERR, errno, "%s: add filter failed!\n", 266 qoperror(error)); 267 else if (IsDebug(DEBUG_ALTQ)) { 268 LOG(LOG_DEBUG, 0, "%s: add a filter %s to class %s\n", 269 ifname, flname ? flname : "(null)", 270 clname ? clname : "(null)"); 271 print_filter(fltr); 272 } 273 return (error); 274 } 275 276 int 277 qcmd_delete_filter(const char *ifname, const char *clname, const char *flname) 278 { 279 struct ifinfo *ifinfo; 280 struct classinfo *clinfo; 281 struct fltrinfo *fltrinfo; 282 int error = 0; 283 284 if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 285 error = QOPERR_BADIF; 286 287 if (error == 0 && 288 (clinfo = clname2clinfo(ifinfo, clname)) == NULL) { 289 /* 290 * there is no matching class. 291 * check if it is for a traffic conditioner 292 */ 293 if ((ifinfo = input_ifname2ifinfo(ifname)) == NULL || 294 (clinfo = clname2clinfo(ifinfo, clname)) == NULL) 295 error = QOPERR_BADCLASS; 296 } 297 298 if (error == 0 && 299 (fltrinfo = flname2flinfo(clinfo, flname)) == NULL) 300 error = QOPERR_BADFILTER; 301 302 if (error == 0) 303 error = qop_delete_filter(fltrinfo); 304 if (error != 0) 305 LOG(LOG_ERR, errno, "%s: delete filter failed!\n", 306 qoperror(error)); 307 return (error); 308 } 309 310 int 311 qcmd_tbr_register(const char *ifname, u_int rate, u_int size) 312 { 313 struct tbrinfo *info; 314 315 if ((info = calloc(1, sizeof(struct tbrinfo))) == NULL) 316 return (QOPERR_NOMEM); 317 318 strcpy(info->ifname, ifname); 319 info->tb_prof.rate = rate; 320 info->tb_prof.depth = size; 321 info->installed = 0; 322 LIST_INSERT_HEAD(&tbr_list, info, link); 323 return (0); 324 } 325 326 /* 327 * QOP (Queue Operation) API 328 */ 329 330 int 331 qop_add_if(struct ifinfo **rp, const char *ifname, u_int bandwidth, 332 struct qdisc_ops *qdisc_ops, void *if_private) 333 { 334 struct ifinfo *ifinfo; 335 int error; 336 337 if (ifname2ifinfo(ifname) != NULL) { 338 LOG(LOG_ERR, 0, "qop_add_if: %s already exists!\n", ifname); 339 return (QOPERR_BADIF); 340 } 341 342 if ((ifinfo = calloc(1, sizeof(struct ifinfo))) == NULL) 343 return (QOPERR_NOMEM); 344 ifinfo->ifname = strdup(ifname); 345 ifinfo->bandwidth = bandwidth; 346 ifinfo->enabled = 0; 347 if (ifname[0] == '_') 348 /* input interface */ 349 ifname += 1; 350 ifinfo->ifindex = get_ifindex(ifname); 351 ifinfo->ifmtu = get_ifmtu(ifname); 352 if (qdisc_ops == NULL || Debug_mode) 353 ifinfo->qdisc = &nop_qdisc; /* replace syscalls by nops */ 354 else 355 ifinfo->qdisc = qdisc_ops; 356 ifinfo->private = if_private; 357 LIST_INIT(&ifinfo->cllist); 358 LIST_INIT(&ifinfo->fltr_rules); 359 360 /* Link the interface info structure */ 361 LIST_INSERT_HEAD(&qop_iflist, ifinfo, next); 362 363 /* install token bucket regulator, if necessary */ 364 tbr_install(ifname); 365 366 /* attach the discipline to the interface */ 367 if ((error = (*ifinfo->qdisc->attach)(ifinfo)) != 0) 368 goto err_ret; 369 370 /* disable and clear the interface */ 371 if (ifinfo->qdisc->disable != NULL) 372 if ((error = (*ifinfo->qdisc->disable)(ifinfo)) != 0) 373 goto err_ret; 374 if (ifinfo->qdisc->clear != NULL) 375 if ((error = (*ifinfo->qdisc->clear)(ifinfo)) != 0) 376 goto err_ret; 377 378 if (rp != NULL) 379 *rp = ifinfo; 380 return (0); 381 382 err_ret: 383 if (ifinfo != NULL) { 384 LIST_REMOVE(ifinfo, next); 385 if (ifinfo->ifname != NULL) 386 free(ifinfo->ifname); 387 free(ifinfo); 388 } 389 return (error); 390 } 391 392 int 393 qop_delete_if(struct ifinfo *ifinfo) 394 { 395 (void)qop_disable(ifinfo); 396 (void)qop_clear(ifinfo); 397 398 if (ifinfo->delete_hook != NULL) 399 (*ifinfo->delete_hook)(ifinfo); 400 401 /* remove this entry from qop_iflist */ 402 LIST_REMOVE(ifinfo, next); 403 404 (void)(*ifinfo->qdisc->detach)(ifinfo); 405 406 /* deinstall token bucket regulator, if necessary */ 407 tbr_deinstall(ifinfo->ifname); 408 409 if (ifinfo->private != NULL) 410 free(ifinfo->private); 411 if (ifinfo->ifname != NULL) 412 free(ifinfo->ifname); 413 free(ifinfo); 414 return (0); 415 } 416 417 int 418 qop_enable(struct ifinfo *ifinfo) 419 { 420 int error; 421 422 if (ifinfo->enable_hook != NULL) 423 if ((error = (*ifinfo->enable_hook)(ifinfo)) != 0) 424 return (error); 425 426 if (ifinfo->qdisc->enable != NULL) 427 if ((error = (*ifinfo->qdisc->enable)(ifinfo)) != 0) 428 return (error); 429 ifinfo->enabled = 1; 430 return (0); 431 } 432 433 int 434 qop_disable(struct ifinfo *ifinfo) 435 { 436 int error; 437 438 if (ifinfo->qdisc->disable != NULL) 439 if ((error = (*ifinfo->qdisc->disable)(ifinfo)) != 0) 440 return (error); 441 ifinfo->enabled = 0; 442 return (0); 443 } 444 445 int 446 qop_clear(struct ifinfo *ifinfo) 447 { 448 struct classinfo *clinfo; 449 450 /* free all classes and filters */ 451 if (ifinfo->ifname[0] != '_') { 452 /* output interface. delete from leaf classes */ 453 while (!LIST_EMPTY(&ifinfo->cllist)) { 454 LIST_FOREACH(clinfo, &ifinfo->cllist, next) { 455 if (clinfo->child != NULL) 456 continue; 457 qop_delete_class(clinfo); 458 /* 459 * the list has been changed, 460 * restart from the head 461 */ 462 break; 463 } 464 } 465 } else { 466 /* input interface. delete from parents */ 467 struct classinfo *root = get_rootclass(ifinfo); 468 469 while (!LIST_EMPTY(&ifinfo->cllist)) { 470 LIST_FOREACH(clinfo, &ifinfo->cllist, next) 471 if (clinfo->parent == root) { 472 qop_delete_cdnr(clinfo); 473 break; 474 } 475 if (root->child == NULL) 476 qop_delete_class(root); 477 } 478 } 479 480 /* clear the interface */ 481 if (ifinfo->qdisc->clear != NULL) 482 return (*ifinfo->qdisc->clear)(ifinfo); 483 return (0); 484 } 485 486 int 487 qop_add_class(struct classinfo **rp, const char *clname, 488 struct ifinfo *ifinfo, struct classinfo *parent, 489 void *class_private) 490 { 491 struct classinfo *clinfo; 492 int error; 493 494 if ((clinfo = calloc(1, sizeof(*clinfo))) == NULL) 495 return (QOPERR_NOMEM); 496 497 if (clname != NULL) 498 clinfo->clname = strdup(clname); 499 else 500 clinfo->clname = strdup("(null)"); /* dummy name */ 501 clinfo->ifinfo = ifinfo; 502 clinfo->private = class_private; 503 clinfo->parent = parent; 504 clinfo->child = NULL; 505 LIST_INIT(&clinfo->fltrlist); 506 507 if ((error = (*ifinfo->qdisc->add_class)(clinfo)) != 0) 508 goto err_ret; 509 510 /* link classinfo in lists */ 511 LIST_INSERT_HEAD(&ifinfo->cllist, clinfo, next); 512 513 if (parent != NULL) { 514 clinfo->sibling = parent->child; 515 clinfo->parent->child = clinfo; 516 } 517 518 if (rp != NULL) 519 *rp = clinfo; 520 return (0); 521 522 err_ret: 523 if (clinfo != NULL) { 524 if (clinfo->clname != NULL) 525 free(clinfo->clname); 526 free(clinfo); 527 } 528 return (error); 529 } 530 531 int 532 qop_modify_class(struct classinfo *clinfo, void *arg) 533 { 534 return (*clinfo->ifinfo->qdisc->modify_class)(clinfo, arg); 535 } 536 537 int 538 qop_delete_class(struct classinfo *clinfo) 539 { 540 struct ifinfo *ifinfo = clinfo->ifinfo; 541 struct classinfo *prev; 542 int error; 543 544 /* a class to be removed should not have a child */ 545 if (clinfo->child != NULL) 546 return (QOPERR_CLASS_PERM); 547 548 /* remove filters associated to this class */ 549 while (!LIST_EMPTY(&clinfo->fltrlist)) 550 (void)qop_delete_filter(LIST_FIRST(&clinfo->fltrlist)); 551 552 if (clinfo->delete_hook != NULL) 553 (*clinfo->delete_hook)(clinfo); 554 555 /* remove class info from the interface */ 556 LIST_REMOVE(clinfo, next); 557 558 /* remove this class from the child list */ 559 if (clinfo->parent != NULL) { 560 if (clinfo->parent->child == clinfo) 561 clinfo->parent->child = clinfo->sibling; 562 else for (prev = clinfo->parent->child; prev->sibling != NULL; 563 prev = prev->sibling) 564 if (prev->sibling == clinfo) { 565 prev->sibling = clinfo->sibling; 566 break; 567 } 568 } 569 570 /* delete class from kernel */ 571 if ((error = (*ifinfo->qdisc->delete_class)(clinfo)) != 0) 572 return (error); 573 574 if (clinfo->private != NULL) 575 free(clinfo->private); 576 if (clinfo->clname != NULL) 577 free(clinfo->clname); 578 free(clinfo); 579 return (0); 580 } 581 582 int 583 qop_add_filter(struct fltrinfo **rp, struct classinfo *clinfo, 584 const char *flname, const struct flow_filter *fltr, 585 struct fltrinfo **conflict) 586 { 587 struct ifinfo *ifinfo; 588 struct fltrinfo *fltrinfo; 589 int error; 590 591 if ((fltrinfo = calloc(1, sizeof(*fltrinfo))) == NULL) 592 return (QOPERR_NOMEM); 593 594 fltrinfo->clinfo = clinfo; 595 fltrinfo->fltr = *fltr; 596 #if 1 597 /* fix this */ 598 fltrinfo->line_no = line_no; /* XXX */ 599 fltrinfo->dontwarn = filter_dontwarn; /* XXX */ 600 #endif 601 if (flname != NULL) 602 fltrinfo->flname = strdup(flname); 603 else 604 fltrinfo->flname = strdup("(null)"); /* dummy name */ 605 606 /* check and save the filter */ 607 ifinfo = clinfo->ifinfo; 608 if ((error = add_filter_rule(ifinfo, fltrinfo, conflict)) != 0) 609 goto err_ret; 610 611 /* install the filter to the kernel */ 612 if ((error = (*ifinfo->qdisc->add_filter)(fltrinfo)) != 0) { 613 remove_filter_rule(ifinfo, fltrinfo); 614 goto err_ret; 615 } 616 617 /* link fltrinfo onto fltrlist of the class */ 618 LIST_INSERT_HEAD(&clinfo->fltrlist, fltrinfo, next); 619 620 if (rp != NULL) 621 *rp = fltrinfo; 622 return (0); 623 624 err_ret: 625 if (fltrinfo != NULL) { 626 if (fltrinfo->flname != NULL) 627 free(fltrinfo->flname); 628 free(fltrinfo); 629 } 630 return (error); 631 } 632 633 int 634 qop_delete_filter(struct fltrinfo *fltrinfo) 635 { 636 struct ifinfo *ifinfo; 637 struct classinfo *clinfo; 638 int error; 639 640 /* remove filter info from the class */ 641 clinfo = fltrinfo->clinfo; 642 ifinfo = clinfo->ifinfo; 643 644 645 /* remove the entry from fltrlist of the class */ 646 LIST_REMOVE(fltrinfo, next); 647 648 remove_filter_rule(ifinfo, fltrinfo); 649 650 /* delete filter from kernel */ 651 if ((error = (*ifinfo->qdisc->delete_filter)(fltrinfo)) != 0) 652 return (error); 653 654 if (fltrinfo->flname) 655 free(fltrinfo->flname); 656 free(fltrinfo); 657 return (0); 658 } 659 660 const char * 661 qoperror(int qoperrno) 662 { 663 static char buf[64]; 664 665 if (qoperrno <= QOPERR_MAX) 666 return (qop_errlist[qoperrno]); 667 sprintf(buf, "unknown error %d", qoperrno); 668 return (buf); 669 } 670 671 /* 672 * misc functions 673 */ 674 struct ifinfo * 675 ifname2ifinfo(const char *ifname) 676 { 677 struct ifinfo *ifinfo; 678 679 LIST_FOREACH(ifinfo, &qop_iflist, next) 680 if (ifinfo->ifname != NULL && 681 strcmp(ifinfo->ifname, ifname) == 0) 682 return (ifinfo); 683 return (NULL); 684 } 685 686 struct ifinfo * 687 input_ifname2ifinfo(const char *ifname) 688 { 689 struct ifinfo *ifinfo; 690 691 LIST_FOREACH(ifinfo, &qop_iflist, next) 692 if (ifinfo->ifname[0] == '_' && 693 strcmp(ifinfo->ifname+1, ifname) == 0) 694 return (ifinfo); 695 return (NULL); 696 } 697 698 struct classinfo * 699 clname2clinfo(const struct ifinfo *ifinfo, const char *clname) 700 { 701 struct classinfo *clinfo; 702 703 LIST_FOREACH(clinfo, &ifinfo->cllist, next) 704 if (clinfo->clname != NULL && 705 strcmp(clinfo->clname, clname) == 0) 706 return (clinfo); 707 return (NULL); 708 } 709 710 struct classinfo * 711 clhandle2clinfo(struct ifinfo *ifinfo, u_long handle) 712 { 713 struct classinfo *clinfo; 714 715 LIST_FOREACH(clinfo, &ifinfo->cllist, next) 716 if (clinfo->handle == handle) 717 return (clinfo); 718 return (NULL); 719 } 720 721 struct fltrinfo * 722 flname2flinfo(const struct classinfo *clinfo, const char *flname) 723 { 724 struct fltrinfo *fltrinfo; 725 726 LIST_FOREACH(fltrinfo, &clinfo->fltrlist, next) 727 if (fltrinfo->flname != NULL && 728 strcmp(fltrinfo->flname, flname) == 0) 729 return (fltrinfo); 730 return (NULL); 731 } 732 733 struct fltrinfo * 734 flhandle2fltrinfo(struct ifinfo *ifinfo, u_long handle) 735 { 736 struct fltrinfo *fltrinfo; 737 738 LIST_FOREACH(fltrinfo, &ifinfo->fltr_rules, nextrule) 739 if (fltrinfo->handle == handle) 740 return (fltrinfo); 741 return (NULL); 742 } 743 744 int 745 is_q_enabled(const char *ifname) 746 { 747 struct ifinfo *ifinfo; 748 749 if ((ifinfo = ifname2ifinfo(ifname)) == NULL) 750 return (0); 751 return (ifinfo->enabled); 752 } 753 754 /* 755 * functions to walk through a class tree: 756 * 757 * for (clinfo = get_rootclass(ifinfo); 758 * clinfo != NULL; clinfo = get_nextclass(clinfo)) { 759 * do_something; 760 * } 761 */ 762 struct classinfo *get_rootclass(struct ifinfo *ifinfo) 763 { 764 struct classinfo *clinfo; 765 766 /* find a class without parent */ 767 LIST_FOREACH(clinfo, &ifinfo->cllist, next) 768 if (clinfo->parent == NULL) 769 return (clinfo); 770 return (NULL); 771 } 772 773 /* return next class in the tree */ 774 struct classinfo *get_nextclass(struct classinfo *clinfo) 775 { 776 struct classinfo *next; 777 778 if (clinfo->child != NULL) 779 next = clinfo->child; 780 else if (clinfo->sibling != NULL) 781 next = clinfo->sibling; 782 else { 783 next = clinfo; 784 while ((next = next->parent) != NULL) 785 if (next->sibling) { 786 next = next->sibling; 787 break; 788 } 789 } 790 return (next); 791 } 792 793 u_long 794 atobps(const char *s) 795 { 796 u_long bandwidth; 797 char *cp; 798 799 bandwidth = strtoul(s, &cp, 0); 800 if (cp != NULL) { 801 if (*cp == 'K' || *cp == 'k') 802 bandwidth *= 1000; 803 else if (*cp == 'M' || *cp == 'm') 804 bandwidth *= 1000000; 805 else if (*cp == 'G' || *cp == 'g') 806 bandwidth *= 1000000000; 807 } 808 return (bandwidth); 809 } 810 811 u_long 812 atobytes(const char *s) 813 { 814 u_long bytes; 815 char *cp; 816 817 bytes = strtoul(s, &cp, 0); 818 if (cp != NULL) { 819 if (*cp == 'K' || *cp == 'k') 820 bytes *= 1024; 821 else if (*cp == 'M' || *cp == 'm') 822 bytes *= 1024 * 1024; 823 else if (*cp == 'G' || *cp == 'g') 824 bytes *= 1024 * 1024 * 1024; 825 } 826 return (bytes); 827 } 828 829 static int 830 get_ifmtu(const char *ifname) 831 { 832 int s, mtu; 833 struct ifreq ifr; 834 #ifdef __OpenBSD__ 835 struct if_data ifdata; 836 #endif 837 838 mtu = 512; /* default MTU */ 839 840 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 841 return (mtu); 842 strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name); 843 #ifdef __OpenBSD__ 844 ifr.ifr_data = (caddr_t)&ifdata; 845 if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == 0) 846 mtu = ifdata.ifi_mtu; 847 #else 848 if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0) 849 mtu = ifr.ifr_mtu; 850 #endif 851 close(s); 852 return (mtu); 853 } 854 855 static void 856 tbr_install(const char *ifname) 857 { 858 struct tbrinfo *info; 859 struct tbrreq req; 860 int fd; 861 862 LIST_FOREACH(info, &tbr_list, link) 863 if (strcmp(info->ifname, ifname) == 0) 864 break; 865 if (info == NULL) 866 return; 867 if (info->tb_prof.rate == 0 || info->installed) 868 return; 869 870 /* get the current token bucket regulator */ 871 if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0) 872 err(1, "can't open altq device"); 873 strncpy(req.ifname, ifname, IFNAMSIZ-1); 874 if (ioctl(fd, ALTQTBRGET, &req) < 0) 875 err(1, "ALTQTBRGET for interface %s", req.ifname); 876 877 /* save the current values */ 878 info->otb_prof.rate = req.tb_prof.rate; 879 info->otb_prof.depth = req.tb_prof.depth; 880 881 /* 882 * if tbr is not specified in the config file and tbr is already 883 * configured, do not change. 884 */ 885 if (req.tb_prof.rate != 0) { 886 LOG(LOG_INFO, 0, 887 "tbr is already installed on %s,\n" 888 " using the current setting (rate:%.2fM size:%.2fK).\n", 889 info->ifname, 890 (double)req.tb_prof.rate/1000000.0, 891 (double)req.tb_prof.depth/1024.0); 892 close (fd); 893 return; 894 } 895 896 /* if the new size is not specified, use heuristics */ 897 if (info->tb_prof.depth == 0) { 898 u_int rate, size; 899 900 rate = info->tb_prof.rate; 901 if (rate <= 1*1000*1000) 902 size = 1; 903 else if (rate <= 10*1000*1000) 904 size = 4; 905 else if (rate <= 200*1000*1000) 906 size = 8; 907 else 908 size = 24; 909 size = size * 1500; /* assume the default mtu is 1500 */ 910 info->tb_prof.depth = size; 911 } 912 913 /* install the new tbr */ 914 strncpy(req.ifname, ifname, IFNAMSIZ-1); 915 req.tb_prof.rate = info->tb_prof.rate; 916 req.tb_prof.depth = info->tb_prof.depth; 917 if (ioctl(fd, ALTQTBRSET, &req) < 0) 918 err(1, "ALTQTBRSET for interface %s", req.ifname); 919 LOG(LOG_INFO, 0, 920 "tbr installed on %s (rate:%.2fM size:%.2fK)\n", 921 info->ifname, 922 (double)info->tb_prof.rate/1000000.0, 923 (double)info->tb_prof.depth/1024.0); 924 close(fd); 925 info->installed = 1; 926 } 927 928 static void 929 tbr_deinstall(const char *ifname) 930 { 931 struct tbrinfo *info; 932 struct tbrreq req; 933 int fd; 934 935 LIST_FOREACH(info, &tbr_list, link) 936 if (strcmp(info->ifname, ifname) == 0) 937 break; 938 if (info == NULL) 939 return; 940 941 /* if we installed tbr, restore the old values */ 942 if (info->installed != 0) { 943 strncpy(req.ifname, ifname, IFNAMSIZ-1); 944 req.tb_prof.rate = info->otb_prof.rate; 945 req.tb_prof.depth = info->otb_prof.depth; 946 if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0) 947 err(1, "can't open altq device"); 948 if (ioctl(fd, ALTQTBRSET, &req) < 0) 949 err(1, "ALTQTBRSET for interface %s", req.ifname); 950 close(fd); 951 } 952 LIST_REMOVE(info, link); 953 free(info); 954 } 955 956 void 957 print_filter(const struct flow_filter *filt) 958 { 959 if (filt->ff_flow.fi_family == AF_INET) { 960 struct in_addr in_addr; 961 962 in_addr.s_addr = filt->ff_flow.fi_dst.s_addr; 963 LOG(LOG_DEBUG, 0, 964 " Filter Dest Addr: %s (mask %#x) Port: %d\n", 965 inet_ntoa(in_addr), ntoh32(filt->ff_mask.mask_dst.s_addr), 966 ntoh16(filt->ff_flow.fi_dport)); 967 in_addr.s_addr = filt->ff_flow.fi_src.s_addr; 968 LOG(LOG_DEBUG, 0, 969 " Src Addr: %s (mask %#x) Port: %d\n", 970 inet_ntoa(in_addr), ntoh32(filt->ff_mask.mask_src.s_addr), 971 ntoh16(filt->ff_flow.fi_sport)); 972 LOG(LOG_DEBUG, 0, " Protocol: %d TOS %#x (mask %#x)\n", 973 filt->ff_flow.fi_proto, filt->ff_flow.fi_tos, 974 filt->ff_mask.mask_tos); 975 } 976 #ifdef INET6 977 else if (filt->ff_flow.fi_family == AF_INET6) { 978 char str1[INET6_ADDRSTRLEN], str2[INET6_ADDRSTRLEN]; 979 const struct flow_filter6 *sfilt6; 980 981 sfilt6 = (const struct flow_filter6 *)filt; 982 LOG(LOG_DEBUG, 0, "Filter6 Dest Addr: %s (mask %s) Port: %d", 983 inet_ntop(AF_INET6, &sfilt6->ff_flow6.fi6_dst, 984 str1, sizeof(str1)), 985 inet_ntop(AF_INET6, &sfilt6->ff_mask6.mask6_dst, 986 str2, sizeof(str2)), 987 ntoh16(sfilt6->ff_flow6.fi6_dport)); 988 LOG(LOG_DEBUG, 0, " Src Addr: %s (mask %s) Port: %d", 989 inet_ntop(AF_INET6, &sfilt6->ff_flow6.fi6_src, 990 str1, sizeof(str1)), 991 inet_ntop(AF_INET6, &sfilt6->ff_mask6.mask6_src, 992 str2, sizeof(str2)), 993 ntoh16(sfilt6->ff_flow6.fi6_sport)); 994 LOG(LOG_DEBUG, 0, " Protocol: %d TCLASS %#x (mask %#x)\n", 995 sfilt6->ff_flow6.fi6_proto, sfilt6->ff_flow6.fi6_tclass, 996 sfilt6->ff_mask6.mask6_tclass); 997 } 998 #endif /* INET6 */ 999 } 1000 1001 /* 1002 * functions to check the filter-rules. 1003 * when a new filter is added, we check the relation to the existing filters 1004 * and if some inconsistency is found, produce an error or a warning message. 1005 * 1006 * filter matching is performed from the head of the list. 1007 * let 1008 * S: a set of packets that filter s matches 1009 * T: a set of packets that filter t matches 1010 * filter relations are: 1011 * disjoint: S ^ T = empty 1012 * subset: S <= T 1013 * intersect: S ^ T = not empty 1014 * 1015 * a new filter is disjoint or subset of the existing filters --> ok 1016 * a new filter is superset of an existing filter --> order problem 1017 * a new filter intersect an existing filter --> warning 1018 * 1019 * port-intersect: a special case we don't make warning 1020 * - intersection is only port numbers 1021 * - one specifies src port and the other specifies dst port 1022 * there must be no packet with well-known port numbers in 1023 * both src and dst ports. so this is ok. 1024 */ 1025 1026 #define FILT_DISJOINT 1 1027 #define FILT_SUBSET 2 1028 #define FILT_SUPERSET 3 1029 #define FILT_INTERSECT 4 1030 #define FILT_PORTINTERSECT 5 1031 1032 static int 1033 add_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo, 1034 struct fltrinfo **conflict) 1035 { 1036 struct fltrinfo *fp, *front, *back, *prev = NULL; 1037 int relation; 1038 1039 LIST_FOREACH(fp, &ifinfo->fltr_rules, nextrule) { 1040 if (fp->fltr.ff_ruleno > fltrinfo->fltr.ff_ruleno) { 1041 front = fp; 1042 back = fltrinfo; 1043 prev = fp; 1044 } else { 1045 front = fltrinfo; 1046 back = fp; 1047 } 1048 1049 relation = filt_check_relation(&front->fltr, &back->fltr); 1050 1051 switch (relation) { 1052 case FILT_SUBSET: 1053 case FILT_DISJOINT: 1054 /* OK */ 1055 break; 1056 case FILT_SUPERSET: 1057 if (front->dontwarn == 0 && back->dontwarn == 0) 1058 LOG(LOG_ERR, 0, 1059 "filters for \"%s\" at line %d and for \"%s\" at line %d has an order problem!\n", 1060 front->clinfo->clname, front->line_no, 1061 back->clinfo->clname, back->line_no); 1062 1063 if (conflict != NULL) 1064 *conflict = fp; 1065 return (QOPERR_FILTER_SHADOW); 1066 case FILT_PORTINTERSECT: 1067 break; 1068 case FILT_INTERSECT: 1069 /* 1070 * if the intersecting two filters beloging to the 1071 * same class, it's ok. 1072 */ 1073 if (front->clinfo == back->clinfo) 1074 break; 1075 if (front->dontwarn == 0 && back->dontwarn == 0) 1076 LOG(LOG_WARNING, 0, 1077 "warning: filter for \"%s\" at line %d could override filter for \"%s\" at line %d\n", 1078 front->clinfo->clname, front->line_no, 1079 back->clinfo->clname, back->line_no); 1080 break; 1081 } 1082 } 1083 1084 if (prev == NULL) 1085 LIST_INSERT_HEAD(&ifinfo->fltr_rules, fltrinfo, nextrule); 1086 else 1087 LIST_INSERT_AFTER(prev, fltrinfo, nextrule); 1088 return (0); 1089 } 1090 1091 static int 1092 remove_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo) 1093 { 1094 LIST_REMOVE(fltrinfo, nextrule); 1095 return (0); 1096 } 1097 1098 static int 1099 filt_check_relation(struct flow_filter *front, struct flow_filter *back) 1100 { 1101 int rval; 1102 1103 if (front->ff_flow.fi_family != back->ff_flow.fi_family) 1104 return (FILT_DISJOINT); 1105 1106 if (filt_disjoint(front, back)) 1107 return (FILT_DISJOINT); 1108 1109 if ((rval = filt_subset(front, back)) == 1) 1110 return (FILT_SUBSET); 1111 1112 if (filt_subset(back, front) == 1) 1113 return (FILT_SUPERSET); 1114 1115 if (rval == 2) 1116 return (FILT_PORTINTERSECT); 1117 1118 return (FILT_INTERSECT); 1119 } 1120 1121 static int 1122 filt_disjoint(struct flow_filter *front, struct flow_filter *back) 1123 { 1124 u_int32_t mask; 1125 u_int8_t tosmask; 1126 1127 if (front->ff_flow.fi_family == AF_INET) { 1128 if (front->ff_flow.fi_proto != 0 && back->ff_flow.fi_proto != 0 1129 && front->ff_flow.fi_proto != back->ff_flow.fi_proto) 1130 return (1); 1131 if (front->ff_flow.fi_sport != 0 && back->ff_flow.fi_sport != 0 1132 && front->ff_flow.fi_sport != back->ff_flow.fi_sport) 1133 return (1); 1134 if (front->ff_flow.fi_dport != 0 && back->ff_flow.fi_dport != 0 1135 && front->ff_flow.fi_dport != back->ff_flow.fi_dport) 1136 return (1); 1137 if (front->ff_flow.fi_gpi != 0 && back->ff_flow.fi_gpi != 0 1138 && front->ff_flow.fi_gpi != back->ff_flow.fi_gpi) 1139 return (1); 1140 if (front->ff_flow.fi_src.s_addr != 0 && 1141 back->ff_flow.fi_src.s_addr != 0) { 1142 mask = front->ff_mask.mask_src.s_addr & 1143 back->ff_mask.mask_src.s_addr; 1144 if ((front->ff_flow.fi_src.s_addr & mask) != 1145 (back->ff_flow.fi_src.s_addr & mask)) 1146 return (1); 1147 } 1148 if (front->ff_flow.fi_dst.s_addr != 0 && 1149 back->ff_flow.fi_dst.s_addr != 0) { 1150 mask = front->ff_mask.mask_dst.s_addr & 1151 back->ff_mask.mask_dst.s_addr; 1152 if ((front->ff_flow.fi_dst.s_addr & mask) != 1153 (back->ff_flow.fi_dst.s_addr & mask)) 1154 return (1); 1155 } 1156 if (front->ff_flow.fi_tos != 0 && back->ff_flow.fi_tos != 0) { 1157 tosmask = front->ff_mask.mask_tos & 1158 back->ff_mask.mask_tos; 1159 if ((front->ff_flow.fi_tos & tosmask) != 1160 (back->ff_flow.fi_tos & tosmask)) 1161 return (1); 1162 } 1163 return (0); 1164 } 1165 #ifdef INET6 1166 else if (front->ff_flow.fi_family == AF_INET6) { 1167 struct flow_filter6 *front6, *back6; 1168 int i; 1169 1170 front6 = (struct flow_filter6 *)front; 1171 back6 = (struct flow_filter6 *)back; 1172 1173 if (front6->ff_flow6.fi6_proto != 0 && 1174 back6->ff_flow6.fi6_proto != 0 && 1175 front6->ff_flow6.fi6_proto != back6->ff_flow6.fi6_proto) 1176 return (1); 1177 if (front6->ff_flow6.fi6_flowlabel != 0 && 1178 back6->ff_flow6.fi6_flowlabel != 0 && 1179 front6->ff_flow6.fi6_flowlabel != 1180 back6->ff_flow6.fi6_flowlabel) 1181 return (1); 1182 if (front6->ff_flow6.fi6_sport != 0 && 1183 back6->ff_flow6.fi6_sport != 0 && 1184 front6->ff_flow6.fi6_sport != back6->ff_flow6.fi6_sport) 1185 return (1); 1186 if (front6->ff_flow6.fi6_dport != 0 && 1187 back6->ff_flow6.fi6_dport != 0 && 1188 front6->ff_flow6.fi6_dport != back6->ff_flow6.fi6_dport) 1189 return (1); 1190 if (front6->ff_flow6.fi6_gpi != 0 && 1191 back6->ff_flow6.fi6_gpi != 0 && 1192 front6->ff_flow6.fi6_gpi != back6->ff_flow6.fi6_gpi) 1193 return (1); 1194 if (!IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_src) && 1195 !IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) { 1196 for (i=0; i<4; i++) { 1197 mask = IN6ADDR32(&front6->ff_mask6.mask6_src, i) 1198 & IN6ADDR32(&back6->ff_mask6.mask6_src, i); 1199 if ((IN6ADDR32(&front6->ff_flow6.fi6_src, i) & mask) != 1200 (IN6ADDR32(&back6->ff_flow6.fi6_src, i) & mask)) 1201 return (1); 1202 } 1203 } 1204 if (!IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_dst) && 1205 !IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) { 1206 for (i=0; i<4; i++) { 1207 mask = IN6ADDR32(&front6->ff_mask6.mask6_dst, i) 1208 & IN6ADDR32(&back6->ff_mask6.mask6_dst, i); 1209 if ((IN6ADDR32(&front6->ff_flow6.fi6_dst, i) & mask) != 1210 (IN6ADDR32(&back6->ff_flow6.fi6_dst, i) & mask)) 1211 return (1); 1212 } 1213 } 1214 if (front6->ff_flow6.fi6_tclass != 0 && 1215 back6->ff_flow6.fi6_tclass != 0) { 1216 tosmask = front6->ff_mask6.mask6_tclass & 1217 back6->ff_mask6.mask6_tclass; 1218 if ((front6->ff_flow6.fi6_tclass & tosmask) != 1219 (back6->ff_flow6.fi6_tclass & tosmask)) 1220 return (1); 1221 } 1222 return (0); 1223 } 1224 #endif /* INET6 */ 1225 return (0); 1226 } 1227 1228 /* 1229 * check if "front" is a subset of "back". assumes they are not disjoint 1230 * return value 0: not a subset 1231 * 1: subset 1232 * 2: subset except src & dst ports 1233 * (possible port-intersect) 1234 */ 1235 static int 1236 filt_subset(struct flow_filter *front, struct flow_filter *back) 1237 { 1238 u_int16_t srcport, dstport; 1239 1240 if (front->ff_flow.fi_family == AF_INET) { 1241 if (front->ff_flow.fi_proto == 0 && 1242 back->ff_flow.fi_proto != 0) 1243 return (0); 1244 if (front->ff_flow.fi_gpi == 0 && back->ff_flow.fi_gpi != 0) 1245 return (0); 1246 if (front->ff_flow.fi_src.s_addr == 0) { 1247 if (back->ff_flow.fi_src.s_addr != 0) 1248 return (0); 1249 } else if (back->ff_flow.fi_src.s_addr != 0 && 1250 (~front->ff_mask.mask_src.s_addr & 1251 back->ff_mask.mask_src.s_addr)) 1252 return (0); 1253 if (front->ff_flow.fi_dst.s_addr == 0) { 1254 if (back->ff_flow.fi_dst.s_addr != 0) 1255 return (0); 1256 } else if (back->ff_flow.fi_dst.s_addr != 0 && 1257 (~front->ff_mask.mask_dst.s_addr & 1258 back->ff_mask.mask_dst.s_addr)) 1259 return (0); 1260 if (~front->ff_mask.mask_tos & back->ff_mask.mask_tos) 1261 return (0); 1262 1263 if (front->ff_flow.fi_sport == 0 && 1264 back->ff_flow.fi_sport != 0) { 1265 srcport = ntohs(back->ff_flow.fi_sport); 1266 dstport = ntohs(front->ff_flow.fi_dport); 1267 if (dstport > 0 /* && dstport < 1024 */ && 1268 srcport > 0 /* && srcport < 1024 */) 1269 return (2); 1270 return (0); 1271 } 1272 if (front->ff_flow.fi_dport == 0 && 1273 back->ff_flow.fi_dport != 0) { 1274 dstport = ntohs(back->ff_flow.fi_dport); 1275 srcport = ntohs(front->ff_flow.fi_sport); 1276 if (srcport > 0 /* && srcport < 1024 */ && 1277 dstport > 0 /* && dstport < 1024 */) 1278 return (2); 1279 return (0); 1280 } 1281 1282 return (1); 1283 } 1284 #ifdef INET6 1285 else if (front->ff_flow.fi_family == AF_INET6) { 1286 struct flow_filter6 *front6, *back6; 1287 int i; 1288 1289 front6 = (struct flow_filter6 *)front; 1290 back6 = (struct flow_filter6 *)back; 1291 1292 if (front6->ff_flow6.fi6_proto == 0 && 1293 back6->ff_flow6.fi6_proto != 0) 1294 return (0); 1295 if (front6->ff_flow6.fi6_flowlabel == 0 && 1296 back6->ff_flow6.fi6_flowlabel != 0) 1297 return (0); 1298 if (front6->ff_flow6.fi6_gpi == 0 && 1299 back6->ff_flow6.fi6_gpi != 0) 1300 return (0); 1301 1302 if (IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_src)) { 1303 if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) 1304 return (0); 1305 } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) 1306 for (i=0; i<4; i++) 1307 if (~IN6ADDR32(&front6->ff_mask6.mask6_src, i) & 1308 IN6ADDR32(&back6->ff_mask6.mask6_src, i)) 1309 return (0); 1310 if (IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_dst)) { 1311 if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) 1312 return (0); 1313 } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) 1314 for (i=0; i<4; i++) 1315 if (~IN6ADDR32(&front6->ff_mask6.mask6_dst, i) & 1316 IN6ADDR32(&back6->ff_mask6.mask6_dst, i)) 1317 return (0); 1318 1319 if (~front6->ff_mask6.mask6_tclass & 1320 back6->ff_mask6.mask6_tclass) 1321 return (0); 1322 1323 if (front6->ff_flow6.fi6_sport == 0 && 1324 back6->ff_flow6.fi6_sport != 0) { 1325 srcport = ntohs(back6->ff_flow6.fi6_sport); 1326 dstport = ntohs(front6->ff_flow6.fi6_dport); 1327 if (dstport > 0 /* && dstport < 1024 */ && 1328 srcport > 0 /* && srcport < 1024 */) 1329 return (2); 1330 return (0); 1331 } 1332 if (front6->ff_flow6.fi6_dport == 0 && 1333 back6->ff_flow6.fi6_dport != 0) { 1334 dstport = ntohs(back6->ff_flow6.fi6_dport); 1335 srcport = ntohs(front6->ff_flow6.fi6_sport); 1336 if (srcport > 0 /* && srcport < 1024 */ && 1337 dstport > 0 /* && dstport < 1024 */) 1338 return (2); 1339 return (0); 1340 } 1341 } 1342 #endif /* INET6 */ 1343 return (1); 1344 } 1345 1346 1347 /* 1348 * setting RED or RIO default parameters 1349 */ 1350 int 1351 qop_red_set_defaults(int th_min, int th_max, int inv_pmax) 1352 { 1353 struct redparams params; 1354 int fd; 1355 1356 if ((fd = open(RED_DEVICE, O_RDWR)) < 0) { 1357 LOG(LOG_ERR, errno, "RED open\n"); 1358 return (QOPERR_SYSCALL); 1359 } 1360 1361 params.th_min = th_min; 1362 params.th_max = th_max; 1363 params.inv_pmax = inv_pmax; 1364 1365 if (ioctl(fd, RED_SETDEFAULTS, ¶ms) < 0) { 1366 LOG(LOG_ERR, errno, "RED_SETDEFAULTS\n"); 1367 return (QOPERR_SYSCALL); 1368 } 1369 1370 (void)close(fd); 1371 return (0); 1372 } 1373 1374 int 1375 qop_rio_set_defaults(struct redparams *params) 1376 { 1377 int i, fd; 1378 1379 /* sanity check */ 1380 for (i = 1; i < RIO_NDROPPREC; i++) { 1381 if (params[i].th_max > params[i-1].th_min) 1382 LOG(LOG_WARNING, 0, 1383 "warning: overlap found in RIO thresholds\n"); 1384 } 1385 1386 if ((fd = open(RIO_DEVICE, O_RDWR)) < 0) { 1387 LOG(LOG_ERR, errno, "RIO open\n"); 1388 return (QOPERR_SYSCALL); 1389 } 1390 1391 if (ioctl(fd, RIO_SETDEFAULTS, params) < 0) { 1392 LOG(LOG_ERR, errno, "RIO_SETDEFAULTS\n"); 1393 return (QOPERR_SYSCALL); 1394 } 1395 1396 (void)close(fd); 1397 return (0); 1398 } 1399 1400 /* 1401 * try to load and open KLD module 1402 */ 1403 int 1404 open_module(const char *devname, int flags) 1405 { 1406 #if defined(__FreeBSD__) && (__FreeBSD_version > 300000) 1407 char modname[64], filename[256], *cp; 1408 int fd; 1409 struct stat sbuf; 1410 1411 /* turn discipline name into module name */ 1412 strcpy(modname, "altq_"); 1413 if ((cp = strrchr(devname, '/')) == NULL) 1414 return (-1); 1415 strcat(modname, cp+1); 1416 1417 /* check if the kld module exists */ 1418 sprintf(filename, "/modules/%s.ko", modname); 1419 if (stat(filename, &sbuf) < 0) { 1420 /* module file doesn't exist */ 1421 return (-1); 1422 } 1423 1424 if (kldload(modname) < 0) { 1425 LOG(LOG_ERR, errno, "kldload %s failed!\n", modname); 1426 return (-1); 1427 } 1428 1429 /* successfully loaded, open the device */ 1430 LOG(LOG_INFO, 0, "kld module %s loaded\n", modname); 1431 fd = open(devname, flags); 1432 return (fd); 1433 #else 1434 return (-1); 1435 #endif 1436 } 1437 1438