1 /* $NetBSD: qop.c,v 1.5 2002/03/05 04:11:53 itojun Exp $ */ 2 /* $KAME: qop.c,v 1.11 2001/10/26 04:57:59 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 double bandwidth; 796 char *cp; 797 798 bandwidth = strtod(s, &cp); 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 if (bandwidth < 0) 808 bandwidth = 0; 809 return ((u_long)bandwidth); 810 } 811 812 u_long 813 atobytes(const char *s) 814 { 815 double bytes; 816 char *cp; 817 818 bytes = strtod(s, &cp); 819 if (cp != NULL) { 820 if (*cp == 'K' || *cp == 'k') 821 bytes *= 1024; 822 else if (*cp == 'M' || *cp == 'm') 823 bytes *= 1024 * 1024; 824 else if (*cp == 'G' || *cp == 'g') 825 bytes *= 1024 * 1024 * 1024; 826 } 827 if (bytes < 0) 828 bytes = 0; 829 return ((u_long)bytes); 830 } 831 832 static int 833 get_ifmtu(const char *ifname) 834 { 835 int s, mtu; 836 struct ifreq ifr; 837 #ifdef __OpenBSD__ 838 struct if_data ifdata; 839 #endif 840 841 mtu = 512; /* default MTU */ 842 843 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 844 return (mtu); 845 strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name); 846 #ifdef __OpenBSD__ 847 ifr.ifr_data = (caddr_t)&ifdata; 848 if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == 0) 849 mtu = ifdata.ifi_mtu; 850 #else 851 if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0) 852 mtu = ifr.ifr_mtu; 853 #endif 854 close(s); 855 return (mtu); 856 } 857 858 static void 859 tbr_install(const char *ifname) 860 { 861 struct tbrinfo *info; 862 struct tbrreq req; 863 int fd; 864 865 LIST_FOREACH(info, &tbr_list, link) 866 if (strcmp(info->ifname, ifname) == 0) 867 break; 868 if (info == NULL) 869 return; 870 if (info->tb_prof.rate == 0 || info->installed) 871 return; 872 873 /* get the current token bucket regulator */ 874 if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0) 875 err(1, "can't open altq device"); 876 strncpy(req.ifname, ifname, IFNAMSIZ-1); 877 if (ioctl(fd, ALTQTBRGET, &req) < 0) 878 err(1, "ALTQTBRGET for interface %s", req.ifname); 879 880 /* save the current values */ 881 info->otb_prof.rate = req.tb_prof.rate; 882 info->otb_prof.depth = req.tb_prof.depth; 883 884 /* 885 * if tbr is not specified in the config file and tbr is already 886 * configured, do not change. 887 */ 888 if (req.tb_prof.rate != 0) { 889 LOG(LOG_INFO, 0, 890 "tbr is already installed on %s,\n" 891 " using the current setting (rate:%.2fM size:%.2fK).", 892 info->ifname, 893 (double)req.tb_prof.rate/1000000.0, 894 (double)req.tb_prof.depth/1024.0); 895 close (fd); 896 return; 897 } 898 899 /* if the new size is not specified, use heuristics */ 900 if (info->tb_prof.depth == 0) { 901 u_int rate, size; 902 903 rate = info->tb_prof.rate; 904 if (rate <= 1*1000*1000) 905 size = 1; 906 else if (rate <= 10*1000*1000) 907 size = 4; 908 else if (rate <= 200*1000*1000) 909 size = 8; 910 else 911 size = 24; 912 size = size * 1500; /* assume the default mtu is 1500 */ 913 info->tb_prof.depth = size; 914 } 915 916 /* install the new tbr */ 917 strncpy(req.ifname, ifname, IFNAMSIZ-1); 918 req.tb_prof.rate = info->tb_prof.rate; 919 req.tb_prof.depth = info->tb_prof.depth; 920 if (ioctl(fd, ALTQTBRSET, &req) < 0) 921 err(1, "ALTQTBRSET for interface %s", req.ifname); 922 LOG(LOG_INFO, 0, 923 "tbr installed on %s (rate:%.2fM size:%.2fK)", 924 info->ifname, 925 (double)info->tb_prof.rate/1000000.0, 926 (double)info->tb_prof.depth/1024.0); 927 close(fd); 928 info->installed = 1; 929 } 930 931 static void 932 tbr_deinstall(const char *ifname) 933 { 934 struct tbrinfo *info; 935 struct tbrreq req; 936 int fd; 937 938 LIST_FOREACH(info, &tbr_list, link) 939 if (strcmp(info->ifname, ifname) == 0) 940 break; 941 if (info == NULL) 942 return; 943 944 /* if we installed tbr, restore the old values */ 945 if (info->installed != 0) { 946 strncpy(req.ifname, ifname, IFNAMSIZ-1); 947 req.tb_prof.rate = info->otb_prof.rate; 948 req.tb_prof.depth = info->otb_prof.depth; 949 if ((fd = open(ALTQ_DEVICE, O_RDWR)) < 0) 950 err(1, "can't open altq device"); 951 if (ioctl(fd, ALTQTBRSET, &req) < 0) 952 err(1, "ALTQTBRSET for interface %s", req.ifname); 953 close(fd); 954 } 955 LIST_REMOVE(info, link); 956 free(info); 957 } 958 959 void 960 print_filter(const struct flow_filter *filt) 961 { 962 if (filt->ff_flow.fi_family == AF_INET) { 963 struct in_addr in_addr; 964 965 in_addr.s_addr = filt->ff_flow.fi_dst.s_addr; 966 LOG(LOG_DEBUG, 0, 967 " Filter Dest Addr: %s (mask %#x) Port: %d", 968 inet_ntoa(in_addr), ntoh32(filt->ff_mask.mask_dst.s_addr), 969 ntoh16(filt->ff_flow.fi_dport)); 970 in_addr.s_addr = filt->ff_flow.fi_src.s_addr; 971 LOG(LOG_DEBUG, 0, 972 " Src Addr: %s (mask %#x) Port: %d", 973 inet_ntoa(in_addr), ntoh32(filt->ff_mask.mask_src.s_addr), 974 ntoh16(filt->ff_flow.fi_sport)); 975 LOG(LOG_DEBUG, 0, " Protocol: %d TOS %#x (mask %#x)", 976 filt->ff_flow.fi_proto, filt->ff_flow.fi_tos, 977 filt->ff_mask.mask_tos); 978 } 979 #ifdef INET6 980 else if (filt->ff_flow.fi_family == AF_INET6) { 981 char str1[INET6_ADDRSTRLEN], str2[INET6_ADDRSTRLEN]; 982 const struct flow_filter6 *sfilt6; 983 984 sfilt6 = (const struct flow_filter6 *)filt; 985 LOG(LOG_DEBUG, 0, "Filter6 Dest Addr: %s (mask %s) Port: %d", 986 inet_ntop(AF_INET6, &sfilt6->ff_flow6.fi6_dst, 987 str1, sizeof(str1)), 988 inet_ntop(AF_INET6, &sfilt6->ff_mask6.mask6_dst, 989 str2, sizeof(str2)), 990 ntoh16(sfilt6->ff_flow6.fi6_dport)); 991 LOG(LOG_DEBUG, 0, " Src Addr: %s (mask %s) Port: %d", 992 inet_ntop(AF_INET6, &sfilt6->ff_flow6.fi6_src, 993 str1, sizeof(str1)), 994 inet_ntop(AF_INET6, &sfilt6->ff_mask6.mask6_src, 995 str2, sizeof(str2)), 996 ntoh16(sfilt6->ff_flow6.fi6_sport)); 997 LOG(LOG_DEBUG, 0, " Protocol: %d TCLASS %#x (mask %#x)", 998 sfilt6->ff_flow6.fi6_proto, sfilt6->ff_flow6.fi6_tclass, 999 sfilt6->ff_mask6.mask6_tclass); 1000 } 1001 #endif /* INET6 */ 1002 } 1003 1004 /* 1005 * functions to check the filter-rules. 1006 * when a new filter is added, we check the relation to the existing filters 1007 * and if some inconsistency is found, produce an error or a warning message. 1008 * 1009 * filter matching is performed from the head of the list. 1010 * let 1011 * S: a set of packets that filter s matches 1012 * T: a set of packets that filter t matches 1013 * filter relations are: 1014 * disjoint: S ^ T = empty 1015 * subset: S <= T 1016 * intersect: S ^ T = not empty 1017 * 1018 * a new filter is disjoint or subset of the existing filters --> ok 1019 * a new filter is superset of an existing filter --> order problem 1020 * a new filter intersect an existing filter --> warning 1021 * 1022 * port-intersect: a special case we don't make warning 1023 * - intersection is only port numbers 1024 * - one specifies src port and the other specifies dst port 1025 * there must be no packet with well-known port numbers in 1026 * both src and dst ports. so this is ok. 1027 */ 1028 1029 #define FILT_DISJOINT 1 1030 #define FILT_SUBSET 2 1031 #define FILT_SUPERSET 3 1032 #define FILT_INTERSECT 4 1033 #define FILT_PORTINTERSECT 5 1034 1035 static int 1036 add_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo, 1037 struct fltrinfo **conflict) 1038 { 1039 struct fltrinfo *fp, *front, *back, *prev = NULL; 1040 int relation; 1041 1042 LIST_FOREACH(fp, &ifinfo->fltr_rules, nextrule) { 1043 if (fp->fltr.ff_ruleno > fltrinfo->fltr.ff_ruleno) { 1044 front = fp; 1045 back = fltrinfo; 1046 prev = fp; 1047 } else { 1048 front = fltrinfo; 1049 back = fp; 1050 } 1051 1052 relation = filt_check_relation(&front->fltr, &back->fltr); 1053 1054 switch (relation) { 1055 case FILT_SUBSET: 1056 case FILT_DISJOINT: 1057 /* OK */ 1058 break; 1059 case FILT_SUPERSET: 1060 if (front->dontwarn == 0 && back->dontwarn == 0) 1061 LOG(LOG_ERR, 0, 1062 "filters for \"%s\" at line %d and for \"%s\" at line %d has an order problem!", 1063 front->clinfo->clname, front->line_no, 1064 back->clinfo->clname, back->line_no); 1065 1066 if (conflict != NULL) 1067 *conflict = fp; 1068 return (QOPERR_FILTER_SHADOW); 1069 case FILT_PORTINTERSECT: 1070 break; 1071 case FILT_INTERSECT: 1072 /* 1073 * if the intersecting two filters beloging to the 1074 * same class, it's ok. 1075 */ 1076 if (front->clinfo == back->clinfo) 1077 break; 1078 if (front->dontwarn == 0 && back->dontwarn == 0) 1079 LOG(LOG_WARNING, 0, 1080 "warning: filter for \"%s\" at line %d could override filter for \"%s\" at line %d", 1081 front->clinfo->clname, front->line_no, 1082 back->clinfo->clname, back->line_no); 1083 break; 1084 } 1085 } 1086 1087 if (prev == NULL) 1088 LIST_INSERT_HEAD(&ifinfo->fltr_rules, fltrinfo, nextrule); 1089 else 1090 LIST_INSERT_AFTER(prev, fltrinfo, nextrule); 1091 return (0); 1092 } 1093 1094 static int 1095 remove_filter_rule(struct ifinfo *ifinfo, struct fltrinfo *fltrinfo) 1096 { 1097 LIST_REMOVE(fltrinfo, nextrule); 1098 return (0); 1099 } 1100 1101 static int 1102 filt_check_relation(struct flow_filter *front, struct flow_filter *back) 1103 { 1104 int rval; 1105 1106 if (front->ff_flow.fi_family != back->ff_flow.fi_family) 1107 return (FILT_DISJOINT); 1108 1109 if (filt_disjoint(front, back)) 1110 return (FILT_DISJOINT); 1111 1112 if ((rval = filt_subset(front, back)) == 1) 1113 return (FILT_SUBSET); 1114 1115 if (filt_subset(back, front) == 1) 1116 return (FILT_SUPERSET); 1117 1118 if (rval == 2) 1119 return (FILT_PORTINTERSECT); 1120 1121 return (FILT_INTERSECT); 1122 } 1123 1124 static int 1125 filt_disjoint(struct flow_filter *front, struct flow_filter *back) 1126 { 1127 u_int32_t mask; 1128 u_int8_t tosmask; 1129 1130 if (front->ff_flow.fi_family == AF_INET) { 1131 if (front->ff_flow.fi_proto != 0 && back->ff_flow.fi_proto != 0 1132 && front->ff_flow.fi_proto != back->ff_flow.fi_proto) 1133 return (1); 1134 if (front->ff_flow.fi_sport != 0 && back->ff_flow.fi_sport != 0 1135 && front->ff_flow.fi_sport != back->ff_flow.fi_sport) 1136 return (1); 1137 if (front->ff_flow.fi_dport != 0 && back->ff_flow.fi_dport != 0 1138 && front->ff_flow.fi_dport != back->ff_flow.fi_dport) 1139 return (1); 1140 if (front->ff_flow.fi_gpi != 0 && back->ff_flow.fi_gpi != 0 1141 && front->ff_flow.fi_gpi != back->ff_flow.fi_gpi) 1142 return (1); 1143 if (front->ff_flow.fi_src.s_addr != 0 && 1144 back->ff_flow.fi_src.s_addr != 0) { 1145 mask = front->ff_mask.mask_src.s_addr & 1146 back->ff_mask.mask_src.s_addr; 1147 if ((front->ff_flow.fi_src.s_addr & mask) != 1148 (back->ff_flow.fi_src.s_addr & mask)) 1149 return (1); 1150 } 1151 if (front->ff_flow.fi_dst.s_addr != 0 && 1152 back->ff_flow.fi_dst.s_addr != 0) { 1153 mask = front->ff_mask.mask_dst.s_addr & 1154 back->ff_mask.mask_dst.s_addr; 1155 if ((front->ff_flow.fi_dst.s_addr & mask) != 1156 (back->ff_flow.fi_dst.s_addr & mask)) 1157 return (1); 1158 } 1159 if (front->ff_flow.fi_tos != 0 && back->ff_flow.fi_tos != 0) { 1160 tosmask = front->ff_mask.mask_tos & 1161 back->ff_mask.mask_tos; 1162 if ((front->ff_flow.fi_tos & tosmask) != 1163 (back->ff_flow.fi_tos & tosmask)) 1164 return (1); 1165 } 1166 return (0); 1167 } 1168 #ifdef INET6 1169 else if (front->ff_flow.fi_family == AF_INET6) { 1170 struct flow_filter6 *front6, *back6; 1171 int i; 1172 1173 front6 = (struct flow_filter6 *)front; 1174 back6 = (struct flow_filter6 *)back; 1175 1176 if (front6->ff_flow6.fi6_proto != 0 && 1177 back6->ff_flow6.fi6_proto != 0 && 1178 front6->ff_flow6.fi6_proto != back6->ff_flow6.fi6_proto) 1179 return (1); 1180 if (front6->ff_flow6.fi6_flowlabel != 0 && 1181 back6->ff_flow6.fi6_flowlabel != 0 && 1182 front6->ff_flow6.fi6_flowlabel != 1183 back6->ff_flow6.fi6_flowlabel) 1184 return (1); 1185 if (front6->ff_flow6.fi6_sport != 0 && 1186 back6->ff_flow6.fi6_sport != 0 && 1187 front6->ff_flow6.fi6_sport != back6->ff_flow6.fi6_sport) 1188 return (1); 1189 if (front6->ff_flow6.fi6_dport != 0 && 1190 back6->ff_flow6.fi6_dport != 0 && 1191 front6->ff_flow6.fi6_dport != back6->ff_flow6.fi6_dport) 1192 return (1); 1193 if (front6->ff_flow6.fi6_gpi != 0 && 1194 back6->ff_flow6.fi6_gpi != 0 && 1195 front6->ff_flow6.fi6_gpi != back6->ff_flow6.fi6_gpi) 1196 return (1); 1197 if (!IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_src) && 1198 !IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) { 1199 for (i=0; i<4; i++) { 1200 mask = IN6ADDR32(&front6->ff_mask6.mask6_src, i) 1201 & IN6ADDR32(&back6->ff_mask6.mask6_src, i); 1202 if ((IN6ADDR32(&front6->ff_flow6.fi6_src, i) & mask) != 1203 (IN6ADDR32(&back6->ff_flow6.fi6_src, i) & mask)) 1204 return (1); 1205 } 1206 } 1207 if (!IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_dst) && 1208 !IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) { 1209 for (i=0; i<4; i++) { 1210 mask = IN6ADDR32(&front6->ff_mask6.mask6_dst, i) 1211 & IN6ADDR32(&back6->ff_mask6.mask6_dst, i); 1212 if ((IN6ADDR32(&front6->ff_flow6.fi6_dst, i) & mask) != 1213 (IN6ADDR32(&back6->ff_flow6.fi6_dst, i) & mask)) 1214 return (1); 1215 } 1216 } 1217 if (front6->ff_flow6.fi6_tclass != 0 && 1218 back6->ff_flow6.fi6_tclass != 0) { 1219 tosmask = front6->ff_mask6.mask6_tclass & 1220 back6->ff_mask6.mask6_tclass; 1221 if ((front6->ff_flow6.fi6_tclass & tosmask) != 1222 (back6->ff_flow6.fi6_tclass & tosmask)) 1223 return (1); 1224 } 1225 return (0); 1226 } 1227 #endif /* INET6 */ 1228 return (0); 1229 } 1230 1231 /* 1232 * check if "front" is a subset of "back". assumes they are not disjoint 1233 * return value 0: not a subset 1234 * 1: subset 1235 * 2: subset except src & dst ports 1236 * (possible port-intersect) 1237 */ 1238 static int 1239 filt_subset(struct flow_filter *front, struct flow_filter *back) 1240 { 1241 u_int16_t srcport, dstport; 1242 1243 if (front->ff_flow.fi_family == AF_INET) { 1244 if (front->ff_flow.fi_proto == 0 && 1245 back->ff_flow.fi_proto != 0) 1246 return (0); 1247 if (front->ff_flow.fi_gpi == 0 && back->ff_flow.fi_gpi != 0) 1248 return (0); 1249 if (front->ff_flow.fi_src.s_addr == 0) { 1250 if (back->ff_flow.fi_src.s_addr != 0) 1251 return (0); 1252 } else if (back->ff_flow.fi_src.s_addr != 0 && 1253 (~front->ff_mask.mask_src.s_addr & 1254 back->ff_mask.mask_src.s_addr)) 1255 return (0); 1256 if (front->ff_flow.fi_dst.s_addr == 0) { 1257 if (back->ff_flow.fi_dst.s_addr != 0) 1258 return (0); 1259 } else if (back->ff_flow.fi_dst.s_addr != 0 && 1260 (~front->ff_mask.mask_dst.s_addr & 1261 back->ff_mask.mask_dst.s_addr)) 1262 return (0); 1263 if (~front->ff_mask.mask_tos & back->ff_mask.mask_tos) 1264 return (0); 1265 1266 if (front->ff_flow.fi_sport == 0 && 1267 back->ff_flow.fi_sport != 0) { 1268 srcport = ntohs(back->ff_flow.fi_sport); 1269 dstport = ntohs(front->ff_flow.fi_dport); 1270 if (dstport > 0 /* && dstport < 1024 */ && 1271 srcport > 0 /* && srcport < 1024 */) 1272 return (2); 1273 return (0); 1274 } 1275 if (front->ff_flow.fi_dport == 0 && 1276 back->ff_flow.fi_dport != 0) { 1277 dstport = ntohs(back->ff_flow.fi_dport); 1278 srcport = ntohs(front->ff_flow.fi_sport); 1279 if (srcport > 0 /* && srcport < 1024 */ && 1280 dstport > 0 /* && dstport < 1024 */) 1281 return (2); 1282 return (0); 1283 } 1284 1285 return (1); 1286 } 1287 #ifdef INET6 1288 else if (front->ff_flow.fi_family == AF_INET6) { 1289 struct flow_filter6 *front6, *back6; 1290 int i; 1291 1292 front6 = (struct flow_filter6 *)front; 1293 back6 = (struct flow_filter6 *)back; 1294 1295 if (front6->ff_flow6.fi6_proto == 0 && 1296 back6->ff_flow6.fi6_proto != 0) 1297 return (0); 1298 if (front6->ff_flow6.fi6_flowlabel == 0 && 1299 back6->ff_flow6.fi6_flowlabel != 0) 1300 return (0); 1301 if (front6->ff_flow6.fi6_gpi == 0 && 1302 back6->ff_flow6.fi6_gpi != 0) 1303 return (0); 1304 1305 if (IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_src)) { 1306 if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) 1307 return (0); 1308 } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_src)) 1309 for (i=0; i<4; i++) 1310 if (~IN6ADDR32(&front6->ff_mask6.mask6_src, i) & 1311 IN6ADDR32(&back6->ff_mask6.mask6_src, i)) 1312 return (0); 1313 if (IN6_IS_ADDR_UNSPECIFIED(&front6->ff_flow6.fi6_dst)) { 1314 if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) 1315 return (0); 1316 } else if (!IN6_IS_ADDR_UNSPECIFIED(&back6->ff_flow6.fi6_dst)) 1317 for (i=0; i<4; i++) 1318 if (~IN6ADDR32(&front6->ff_mask6.mask6_dst, i) & 1319 IN6ADDR32(&back6->ff_mask6.mask6_dst, i)) 1320 return (0); 1321 1322 if (~front6->ff_mask6.mask6_tclass & 1323 back6->ff_mask6.mask6_tclass) 1324 return (0); 1325 1326 if (front6->ff_flow6.fi6_sport == 0 && 1327 back6->ff_flow6.fi6_sport != 0) { 1328 srcport = ntohs(back6->ff_flow6.fi6_sport); 1329 dstport = ntohs(front6->ff_flow6.fi6_dport); 1330 if (dstport > 0 /* && dstport < 1024 */ && 1331 srcport > 0 /* && srcport < 1024 */) 1332 return (2); 1333 return (0); 1334 } 1335 if (front6->ff_flow6.fi6_dport == 0 && 1336 back6->ff_flow6.fi6_dport != 0) { 1337 dstport = ntohs(back6->ff_flow6.fi6_dport); 1338 srcport = ntohs(front6->ff_flow6.fi6_sport); 1339 if (srcport > 0 /* && srcport < 1024 */ && 1340 dstport > 0 /* && dstport < 1024 */) 1341 return (2); 1342 return (0); 1343 } 1344 } 1345 #endif /* INET6 */ 1346 return (1); 1347 } 1348 1349 1350 /* 1351 * setting RED or RIO default parameters 1352 */ 1353 int 1354 qop_red_set_defaults(int th_min, int th_max, int inv_pmax) 1355 { 1356 struct redparams params; 1357 int fd; 1358 1359 if ((fd = open(RED_DEVICE, O_RDWR)) < 0) { 1360 LOG(LOG_ERR, errno, "RED open"); 1361 return (QOPERR_SYSCALL); 1362 } 1363 1364 params.th_min = th_min; 1365 params.th_max = th_max; 1366 params.inv_pmax = inv_pmax; 1367 1368 if (ioctl(fd, RED_SETDEFAULTS, ¶ms) < 0) { 1369 LOG(LOG_ERR, errno, "RED_SETDEFAULTS"); 1370 return (QOPERR_SYSCALL); 1371 } 1372 1373 (void)close(fd); 1374 return (0); 1375 } 1376 1377 int 1378 qop_rio_set_defaults(struct redparams *params) 1379 { 1380 int i, fd; 1381 1382 /* sanity check */ 1383 for (i = 1; i < RIO_NDROPPREC; i++) { 1384 if (params[i].th_max > params[i-1].th_min) 1385 LOG(LOG_WARNING, 0, 1386 "warning: overlap found in RIO thresholds"); 1387 } 1388 1389 if ((fd = open(RIO_DEVICE, O_RDWR)) < 0) { 1390 LOG(LOG_ERR, errno, "RIO open"); 1391 return (QOPERR_SYSCALL); 1392 } 1393 1394 if (ioctl(fd, RIO_SETDEFAULTS, params) < 0) { 1395 LOG(LOG_ERR, errno, "RIO_SETDEFAULTS"); 1396 return (QOPERR_SYSCALL); 1397 } 1398 1399 (void)close(fd); 1400 return (0); 1401 } 1402 1403 /* 1404 * try to load and open KLD module 1405 * (also check the altq device file) 1406 */ 1407 int 1408 open_module(const char *devname, int flags) 1409 { 1410 #if defined(__FreeBSD__) && (__FreeBSD_version > 300000) 1411 char modname[64], filename[MAXPATHLEN], *cp; 1412 int fd; 1413 #endif 1414 struct stat sbuf; 1415 1416 /* check if the altq device exists */ 1417 if (stat(devname, &sbuf) < 0) { 1418 LOG(LOG_ERR, errno, "can't access %s!", devname); 1419 return (-1); 1420 } 1421 1422 #if defined(__FreeBSD__) && (__FreeBSD_version > 300000) 1423 /* turn discipline name into module name */ 1424 strlcpy(modname, "altq_", sizeof(modname)); 1425 if ((cp = strrchr(devname, '/')) == NULL) 1426 return (-1); 1427 strlcat(modname, cp + 1, sizeof(modname)); 1428 1429 /* check if the kld module exists */ 1430 snprintf(filename, sizeof(filename), "/modules/%s.ko", modname); 1431 if (stat(filename, &sbuf) < 0) { 1432 /* module file doesn't exist */ 1433 return (-1); 1434 } 1435 1436 if (kldload(modname) < 0) { 1437 LOG(LOG_ERR, errno, "kldload %s failed!", modname); 1438 return (-1); 1439 } 1440 1441 /* successfully loaded, open the device */ 1442 LOG(LOG_INFO, 0, "kld module %s loaded", modname); 1443 fd = open(devname, flags); 1444 return (fd); 1445 #else 1446 return (-1); 1447 #endif 1448 } 1449