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