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