1 /* $OpenBSD: pfctl_altq.c,v 1.93 2007/10/15 02:16:35 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2002 5 * Sony Computer Science Laboratories Inc. 6 * Copyright (c) 2002, 2003 Henning Brauer <henning@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/cdefs.h> 22 __FBSDID("$FreeBSD$"); 23 24 #include <sys/types.h> 25 #include <sys/ioctl.h> 26 #include <sys/socket.h> 27 28 #include <net/if.h> 29 #include <netinet/in.h> 30 #include <net/pfvar.h> 31 32 #include <err.h> 33 #include <errno.h> 34 #include <limits.h> 35 #include <math.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #include <net/altq/altq.h> 42 #include <net/altq/altq_cbq.h> 43 #include <net/altq/altq_codel.h> 44 #include <net/altq/altq_priq.h> 45 #include <net/altq/altq_hfsc.h> 46 #include <net/altq/altq_fairq.h> 47 48 #include "pfctl_parser.h" 49 #include "pfctl.h" 50 51 #define is_sc_null(sc) (((sc) == NULL) || ((sc)->m1 == 0 && (sc)->m2 == 0)) 52 53 static TAILQ_HEAD(altqs, pf_altq) altqs = TAILQ_HEAD_INITIALIZER(altqs); 54 static LIST_HEAD(gen_sc, segment) rtsc, lssc; 55 56 struct pf_altq *qname_to_pfaltq(const char *, const char *); 57 u_int32_t qname_to_qid(const char *); 58 59 static int eval_pfqueue_cbq(struct pfctl *, struct pf_altq *); 60 static int cbq_compute_idletime(struct pfctl *, struct pf_altq *); 61 static int check_commit_cbq(int, int, struct pf_altq *); 62 static int print_cbq_opts(const struct pf_altq *); 63 64 static int print_codel_opts(const struct pf_altq *, 65 const struct node_queue_opt *); 66 67 static int eval_pfqueue_priq(struct pfctl *, struct pf_altq *); 68 static int check_commit_priq(int, int, struct pf_altq *); 69 static int print_priq_opts(const struct pf_altq *); 70 71 static int eval_pfqueue_hfsc(struct pfctl *, struct pf_altq *); 72 static int check_commit_hfsc(int, int, struct pf_altq *); 73 static int print_hfsc_opts(const struct pf_altq *, 74 const struct node_queue_opt *); 75 76 static int eval_pfqueue_fairq(struct pfctl *, struct pf_altq *); 77 static int print_fairq_opts(const struct pf_altq *, 78 const struct node_queue_opt *); 79 static int check_commit_fairq(int, int, struct pf_altq *); 80 81 static void gsc_add_sc(struct gen_sc *, struct service_curve *); 82 static int is_gsc_under_sc(struct gen_sc *, 83 struct service_curve *); 84 static void gsc_destroy(struct gen_sc *); 85 static struct segment *gsc_getentry(struct gen_sc *, double); 86 static int gsc_add_seg(struct gen_sc *, double, double, double, 87 double); 88 static double sc_x2y(struct service_curve *, double); 89 90 #ifdef __FreeBSD__ 91 u_int32_t getifspeed(int, char *); 92 #else 93 u_int32_t getifspeed(char *); 94 #endif 95 u_long getifmtu(char *); 96 int eval_queue_opts(struct pf_altq *, struct node_queue_opt *, 97 u_int32_t); 98 u_int32_t eval_bwspec(struct node_queue_bw *, u_int32_t); 99 void print_hfsc_sc(const char *, u_int, u_int, u_int, 100 const struct node_hfsc_sc *); 101 void print_fairq_sc(const char *, u_int, u_int, u_int, 102 const struct node_fairq_sc *); 103 104 void 105 pfaltq_store(struct pf_altq *a) 106 { 107 struct pf_altq *altq; 108 109 if ((altq = malloc(sizeof(*altq))) == NULL) 110 err(1, "malloc"); 111 memcpy(altq, a, sizeof(struct pf_altq)); 112 TAILQ_INSERT_TAIL(&altqs, altq, entries); 113 } 114 115 struct pf_altq * 116 pfaltq_lookup(const char *ifname) 117 { 118 struct pf_altq *altq; 119 120 TAILQ_FOREACH(altq, &altqs, entries) { 121 if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 && 122 altq->qname[0] == 0) 123 return (altq); 124 } 125 return (NULL); 126 } 127 128 struct pf_altq * 129 qname_to_pfaltq(const char *qname, const char *ifname) 130 { 131 struct pf_altq *altq; 132 133 TAILQ_FOREACH(altq, &altqs, entries) { 134 if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 && 135 strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0) 136 return (altq); 137 } 138 return (NULL); 139 } 140 141 u_int32_t 142 qname_to_qid(const char *qname) 143 { 144 struct pf_altq *altq; 145 146 /* 147 * We guarantee that same named queues on different interfaces 148 * have the same qid, so we do NOT need to limit matching on 149 * one interface! 150 */ 151 152 TAILQ_FOREACH(altq, &altqs, entries) { 153 if (strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0) 154 return (altq->qid); 155 } 156 return (0); 157 } 158 159 void 160 print_altq(const struct pf_altq *a, unsigned int level, 161 struct node_queue_bw *bw, struct node_queue_opt *qopts) 162 { 163 if (a->qname[0] != 0) { 164 print_queue(a, level, bw, 1, qopts); 165 return; 166 } 167 168 #ifdef __FreeBSD__ 169 if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) 170 printf("INACTIVE "); 171 #endif 172 173 printf("altq on %s ", a->ifname); 174 175 switch (a->scheduler) { 176 case ALTQT_CBQ: 177 if (!print_cbq_opts(a)) 178 printf("cbq "); 179 break; 180 case ALTQT_PRIQ: 181 if (!print_priq_opts(a)) 182 printf("priq "); 183 break; 184 case ALTQT_HFSC: 185 if (!print_hfsc_opts(a, qopts)) 186 printf("hfsc "); 187 break; 188 case ALTQT_FAIRQ: 189 if (!print_fairq_opts(a, qopts)) 190 printf("fairq "); 191 break; 192 case ALTQT_CODEL: 193 if (!print_codel_opts(a, qopts)) 194 printf("codel "); 195 break; 196 } 197 198 if (bw != NULL && bw->bw_percent > 0) { 199 if (bw->bw_percent < 100) 200 printf("bandwidth %u%% ", bw->bw_percent); 201 } else 202 printf("bandwidth %s ", rate2str((double)a->ifbandwidth)); 203 204 if (a->qlimit != DEFAULT_QLIMIT) 205 printf("qlimit %u ", a->qlimit); 206 printf("tbrsize %u ", a->tbrsize); 207 } 208 209 void 210 print_queue(const struct pf_altq *a, unsigned int level, 211 struct node_queue_bw *bw, int print_interface, 212 struct node_queue_opt *qopts) 213 { 214 unsigned int i; 215 216 #ifdef __FreeBSD__ 217 if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) 218 printf("INACTIVE "); 219 #endif 220 printf("queue "); 221 for (i = 0; i < level; ++i) 222 printf(" "); 223 printf("%s ", a->qname); 224 if (print_interface) 225 printf("on %s ", a->ifname); 226 if (a->scheduler == ALTQT_CBQ || a->scheduler == ALTQT_HFSC || 227 a->scheduler == ALTQT_FAIRQ) { 228 if (bw != NULL && bw->bw_percent > 0) { 229 if (bw->bw_percent < 100) 230 printf("bandwidth %u%% ", bw->bw_percent); 231 } else 232 printf("bandwidth %s ", rate2str((double)a->bandwidth)); 233 } 234 if (a->priority != DEFAULT_PRIORITY) 235 printf("priority %u ", a->priority); 236 if (a->qlimit != DEFAULT_QLIMIT) 237 printf("qlimit %u ", a->qlimit); 238 switch (a->scheduler) { 239 case ALTQT_CBQ: 240 print_cbq_opts(a); 241 break; 242 case ALTQT_PRIQ: 243 print_priq_opts(a); 244 break; 245 case ALTQT_HFSC: 246 print_hfsc_opts(a, qopts); 247 break; 248 case ALTQT_FAIRQ: 249 print_fairq_opts(a, qopts); 250 break; 251 } 252 } 253 254 /* 255 * eval_pfaltq computes the discipline parameters. 256 */ 257 int 258 eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw, 259 struct node_queue_opt *opts) 260 { 261 u_int rate, size, errors = 0; 262 263 if (bw->bw_absolute > 0) 264 pa->ifbandwidth = bw->bw_absolute; 265 else 266 #ifdef __FreeBSD__ 267 if ((rate = getifspeed(pf->dev, pa->ifname)) == 0) { 268 #else 269 if ((rate = getifspeed(pa->ifname)) == 0) { 270 #endif 271 fprintf(stderr, "interface %s does not know its bandwidth, " 272 "please specify an absolute bandwidth\n", 273 pa->ifname); 274 errors++; 275 } else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0) 276 pa->ifbandwidth = rate; 277 278 errors += eval_queue_opts(pa, opts, pa->ifbandwidth); 279 280 /* if tbrsize is not specified, use heuristics */ 281 if (pa->tbrsize == 0) { 282 rate = pa->ifbandwidth; 283 if (rate <= 1 * 1000 * 1000) 284 size = 1; 285 else if (rate <= 10 * 1000 * 1000) 286 size = 4; 287 else if (rate <= 200 * 1000 * 1000) 288 size = 8; 289 else 290 size = 24; 291 size = size * getifmtu(pa->ifname); 292 if (size > 0xffff) 293 size = 0xffff; 294 pa->tbrsize = size; 295 } 296 return (errors); 297 } 298 299 /* 300 * check_commit_altq does consistency check for each interface 301 */ 302 int 303 check_commit_altq(int dev, int opts) 304 { 305 struct pf_altq *altq; 306 int error = 0; 307 308 /* call the discipline check for each interface. */ 309 TAILQ_FOREACH(altq, &altqs, entries) { 310 if (altq->qname[0] == 0) { 311 switch (altq->scheduler) { 312 case ALTQT_CBQ: 313 error = check_commit_cbq(dev, opts, altq); 314 break; 315 case ALTQT_PRIQ: 316 error = check_commit_priq(dev, opts, altq); 317 break; 318 case ALTQT_HFSC: 319 error = check_commit_hfsc(dev, opts, altq); 320 break; 321 case ALTQT_FAIRQ: 322 error = check_commit_fairq(dev, opts, altq); 323 break; 324 default: 325 break; 326 } 327 } 328 } 329 return (error); 330 } 331 332 /* 333 * eval_pfqueue computes the queue parameters. 334 */ 335 int 336 eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw, 337 struct node_queue_opt *opts) 338 { 339 /* should be merged with expand_queue */ 340 struct pf_altq *if_pa, *parent, *altq; 341 u_int32_t bwsum; 342 int error = 0; 343 344 /* find the corresponding interface and copy fields used by queues */ 345 if ((if_pa = pfaltq_lookup(pa->ifname)) == NULL) { 346 fprintf(stderr, "altq not defined on %s\n", pa->ifname); 347 return (1); 348 } 349 pa->scheduler = if_pa->scheduler; 350 pa->ifbandwidth = if_pa->ifbandwidth; 351 352 if (qname_to_pfaltq(pa->qname, pa->ifname) != NULL) { 353 fprintf(stderr, "queue %s already exists on interface %s\n", 354 pa->qname, pa->ifname); 355 return (1); 356 } 357 pa->qid = qname_to_qid(pa->qname); 358 359 parent = NULL; 360 if (pa->parent[0] != 0) { 361 parent = qname_to_pfaltq(pa->parent, pa->ifname); 362 if (parent == NULL) { 363 fprintf(stderr, "parent %s not found for %s\n", 364 pa->parent, pa->qname); 365 return (1); 366 } 367 pa->parent_qid = parent->qid; 368 } 369 if (pa->qlimit == 0) 370 pa->qlimit = DEFAULT_QLIMIT; 371 372 if (pa->scheduler == ALTQT_CBQ || pa->scheduler == ALTQT_HFSC || 373 pa->scheduler == ALTQT_FAIRQ) { 374 pa->bandwidth = eval_bwspec(bw, 375 parent == NULL ? 0 : parent->bandwidth); 376 377 if (pa->bandwidth > pa->ifbandwidth) { 378 fprintf(stderr, "bandwidth for %s higher than " 379 "interface\n", pa->qname); 380 return (1); 381 } 382 /* check the sum of the child bandwidth is under parent's */ 383 if (parent != NULL) { 384 if (pa->bandwidth > parent->bandwidth) { 385 warnx("bandwidth for %s higher than parent", 386 pa->qname); 387 return (1); 388 } 389 bwsum = 0; 390 TAILQ_FOREACH(altq, &altqs, entries) { 391 if (strncmp(altq->ifname, pa->ifname, 392 IFNAMSIZ) == 0 && 393 altq->qname[0] != 0 && 394 strncmp(altq->parent, pa->parent, 395 PF_QNAME_SIZE) == 0) 396 bwsum += altq->bandwidth; 397 } 398 bwsum += pa->bandwidth; 399 if (bwsum > parent->bandwidth) { 400 warnx("the sum of the child bandwidth higher" 401 " than parent \"%s\"", parent->qname); 402 } 403 } 404 } 405 406 if (eval_queue_opts(pa, opts, parent == NULL? 0 : parent->bandwidth)) 407 return (1); 408 409 switch (pa->scheduler) { 410 case ALTQT_CBQ: 411 error = eval_pfqueue_cbq(pf, pa); 412 break; 413 case ALTQT_PRIQ: 414 error = eval_pfqueue_priq(pf, pa); 415 break; 416 case ALTQT_HFSC: 417 error = eval_pfqueue_hfsc(pf, pa); 418 break; 419 case ALTQT_FAIRQ: 420 error = eval_pfqueue_fairq(pf, pa); 421 break; 422 default: 423 break; 424 } 425 return (error); 426 } 427 428 /* 429 * CBQ support functions 430 */ 431 #define RM_FILTER_GAIN 5 /* log2 of gain, e.g., 5 => 31/32 */ 432 #define RM_NS_PER_SEC (1000000000) 433 434 static int 435 eval_pfqueue_cbq(struct pfctl *pf, struct pf_altq *pa) 436 { 437 struct cbq_opts *opts; 438 u_int ifmtu; 439 440 if (pa->priority >= CBQ_MAXPRI) { 441 warnx("priority out of range: max %d", CBQ_MAXPRI - 1); 442 return (-1); 443 } 444 445 ifmtu = getifmtu(pa->ifname); 446 opts = &pa->pq_u.cbq_opts; 447 448 if (opts->pktsize == 0) { /* use default */ 449 opts->pktsize = ifmtu; 450 if (opts->pktsize > MCLBYTES) /* do what TCP does */ 451 opts->pktsize &= ~MCLBYTES; 452 } else if (opts->pktsize > ifmtu) 453 opts->pktsize = ifmtu; 454 if (opts->maxpktsize == 0) /* use default */ 455 opts->maxpktsize = ifmtu; 456 else if (opts->maxpktsize > ifmtu) 457 opts->pktsize = ifmtu; 458 459 if (opts->pktsize > opts->maxpktsize) 460 opts->pktsize = opts->maxpktsize; 461 462 if (pa->parent[0] == 0) 463 opts->flags |= (CBQCLF_ROOTCLASS | CBQCLF_WRR); 464 465 cbq_compute_idletime(pf, pa); 466 return (0); 467 } 468 469 /* 470 * compute ns_per_byte, maxidle, minidle, and offtime 471 */ 472 static int 473 cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa) 474 { 475 struct cbq_opts *opts; 476 double maxidle_s, maxidle, minidle; 477 double offtime, nsPerByte, ifnsPerByte, ptime, cptime; 478 double z, g, f, gton, gtom; 479 u_int minburst, maxburst; 480 481 opts = &pa->pq_u.cbq_opts; 482 ifnsPerByte = (1.0 / (double)pa->ifbandwidth) * RM_NS_PER_SEC * 8; 483 minburst = opts->minburst; 484 maxburst = opts->maxburst; 485 486 if (pa->bandwidth == 0) 487 f = 0.0001; /* small enough? */ 488 else 489 f = ((double) pa->bandwidth / (double) pa->ifbandwidth); 490 491 nsPerByte = ifnsPerByte / f; 492 ptime = (double)opts->pktsize * ifnsPerByte; 493 cptime = ptime * (1.0 - f) / f; 494 495 if (nsPerByte * (double)opts->maxpktsize > (double)INT_MAX) { 496 /* 497 * this causes integer overflow in kernel! 498 * (bandwidth < 6Kbps when max_pkt_size=1500) 499 */ 500 if (pa->bandwidth != 0 && (pf->opts & PF_OPT_QUIET) == 0) { 501 warnx("queue bandwidth must be larger than %s", 502 rate2str(ifnsPerByte * (double)opts->maxpktsize / 503 (double)INT_MAX * (double)pa->ifbandwidth)); 504 fprintf(stderr, "cbq: queue %s is too slow!\n", 505 pa->qname); 506 } 507 nsPerByte = (double)(INT_MAX / opts->maxpktsize); 508 } 509 510 if (maxburst == 0) { /* use default */ 511 if (cptime > 10.0 * 1000000) 512 maxburst = 4; 513 else 514 maxburst = 16; 515 } 516 if (minburst == 0) /* use default */ 517 minburst = 2; 518 if (minburst > maxburst) 519 minburst = maxburst; 520 521 z = (double)(1 << RM_FILTER_GAIN); 522 g = (1.0 - 1.0 / z); 523 gton = pow(g, (double)maxburst); 524 gtom = pow(g, (double)(minburst-1)); 525 maxidle = ((1.0 / f - 1.0) * ((1.0 - gton) / gton)); 526 maxidle_s = (1.0 - g); 527 if (maxidle > maxidle_s) 528 maxidle = ptime * maxidle; 529 else 530 maxidle = ptime * maxidle_s; 531 offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom); 532 minidle = -((double)opts->maxpktsize * (double)nsPerByte); 533 534 /* scale parameters */ 535 maxidle = ((maxidle * 8.0) / nsPerByte) * 536 pow(2.0, (double)RM_FILTER_GAIN); 537 offtime = (offtime * 8.0) / nsPerByte * 538 pow(2.0, (double)RM_FILTER_GAIN); 539 minidle = ((minidle * 8.0) / nsPerByte) * 540 pow(2.0, (double)RM_FILTER_GAIN); 541 542 maxidle = maxidle / 1000.0; 543 offtime = offtime / 1000.0; 544 minidle = minidle / 1000.0; 545 546 opts->minburst = minburst; 547 opts->maxburst = maxburst; 548 opts->ns_per_byte = (u_int)nsPerByte; 549 opts->maxidle = (u_int)fabs(maxidle); 550 opts->minidle = (int)minidle; 551 opts->offtime = (u_int)fabs(offtime); 552 553 return (0); 554 } 555 556 static int 557 check_commit_cbq(int dev, int opts, struct pf_altq *pa) 558 { 559 struct pf_altq *altq; 560 int root_class, default_class; 561 int error = 0; 562 563 /* 564 * check if cbq has one root queue and one default queue 565 * for this interface 566 */ 567 root_class = default_class = 0; 568 TAILQ_FOREACH(altq, &altqs, entries) { 569 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 570 continue; 571 if (altq->qname[0] == 0) /* this is for interface */ 572 continue; 573 if (altq->pq_u.cbq_opts.flags & CBQCLF_ROOTCLASS) 574 root_class++; 575 if (altq->pq_u.cbq_opts.flags & CBQCLF_DEFCLASS) 576 default_class++; 577 } 578 if (root_class != 1) { 579 warnx("should have one root queue on %s", pa->ifname); 580 error++; 581 } 582 if (default_class != 1) { 583 warnx("should have one default queue on %s", pa->ifname); 584 error++; 585 } 586 return (error); 587 } 588 589 static int 590 print_cbq_opts(const struct pf_altq *a) 591 { 592 const struct cbq_opts *opts; 593 594 opts = &a->pq_u.cbq_opts; 595 if (opts->flags) { 596 printf("cbq("); 597 if (opts->flags & CBQCLF_RED) 598 printf(" red"); 599 if (opts->flags & CBQCLF_ECN) 600 printf(" ecn"); 601 if (opts->flags & CBQCLF_RIO) 602 printf(" rio"); 603 if (opts->flags & CBQCLF_CODEL) 604 printf(" codel"); 605 if (opts->flags & CBQCLF_CLEARDSCP) 606 printf(" cleardscp"); 607 if (opts->flags & CBQCLF_FLOWVALVE) 608 printf(" flowvalve"); 609 if (opts->flags & CBQCLF_BORROW) 610 printf(" borrow"); 611 if (opts->flags & CBQCLF_WRR) 612 printf(" wrr"); 613 if (opts->flags & CBQCLF_EFFICIENT) 614 printf(" efficient"); 615 if (opts->flags & CBQCLF_ROOTCLASS) 616 printf(" root"); 617 if (opts->flags & CBQCLF_DEFCLASS) 618 printf(" default"); 619 printf(" ) "); 620 621 return (1); 622 } else 623 return (0); 624 } 625 626 /* 627 * PRIQ support functions 628 */ 629 static int 630 eval_pfqueue_priq(struct pfctl *pf, struct pf_altq *pa) 631 { 632 struct pf_altq *altq; 633 634 if (pa->priority >= PRIQ_MAXPRI) { 635 warnx("priority out of range: max %d", PRIQ_MAXPRI - 1); 636 return (-1); 637 } 638 /* the priority should be unique for the interface */ 639 TAILQ_FOREACH(altq, &altqs, entries) { 640 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) == 0 && 641 altq->qname[0] != 0 && altq->priority == pa->priority) { 642 warnx("%s and %s have the same priority", 643 altq->qname, pa->qname); 644 return (-1); 645 } 646 } 647 648 return (0); 649 } 650 651 static int 652 check_commit_priq(int dev, int opts, struct pf_altq *pa) 653 { 654 struct pf_altq *altq; 655 int default_class; 656 int error = 0; 657 658 /* 659 * check if priq has one default class for this interface 660 */ 661 default_class = 0; 662 TAILQ_FOREACH(altq, &altqs, entries) { 663 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 664 continue; 665 if (altq->qname[0] == 0) /* this is for interface */ 666 continue; 667 if (altq->pq_u.priq_opts.flags & PRCF_DEFAULTCLASS) 668 default_class++; 669 } 670 if (default_class != 1) { 671 warnx("should have one default queue on %s", pa->ifname); 672 error++; 673 } 674 return (error); 675 } 676 677 static int 678 print_priq_opts(const struct pf_altq *a) 679 { 680 const struct priq_opts *opts; 681 682 opts = &a->pq_u.priq_opts; 683 684 if (opts->flags) { 685 printf("priq("); 686 if (opts->flags & PRCF_RED) 687 printf(" red"); 688 if (opts->flags & PRCF_ECN) 689 printf(" ecn"); 690 if (opts->flags & PRCF_RIO) 691 printf(" rio"); 692 if (opts->flags & PRCF_CODEL) 693 printf(" codel"); 694 if (opts->flags & PRCF_CLEARDSCP) 695 printf(" cleardscp"); 696 if (opts->flags & PRCF_DEFAULTCLASS) 697 printf(" default"); 698 printf(" ) "); 699 700 return (1); 701 } else 702 return (0); 703 } 704 705 /* 706 * HFSC support functions 707 */ 708 static int 709 eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa) 710 { 711 struct pf_altq *altq, *parent; 712 struct hfsc_opts *opts; 713 struct service_curve sc; 714 715 opts = &pa->pq_u.hfsc_opts; 716 717 if (pa->parent[0] == 0) { 718 /* root queue */ 719 opts->lssc_m1 = pa->ifbandwidth; 720 opts->lssc_m2 = pa->ifbandwidth; 721 opts->lssc_d = 0; 722 return (0); 723 } 724 725 LIST_INIT(&rtsc); 726 LIST_INIT(&lssc); 727 728 /* if link_share is not specified, use bandwidth */ 729 if (opts->lssc_m2 == 0) 730 opts->lssc_m2 = pa->bandwidth; 731 732 if ((opts->rtsc_m1 > 0 && opts->rtsc_m2 == 0) || 733 (opts->lssc_m1 > 0 && opts->lssc_m2 == 0) || 734 (opts->ulsc_m1 > 0 && opts->ulsc_m2 == 0)) { 735 warnx("m2 is zero for %s", pa->qname); 736 return (-1); 737 } 738 739 if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) || 740 (opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) || 741 (opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) { 742 warnx("m1 must be zero for convex curve: %s", pa->qname); 743 return (-1); 744 } 745 746 /* 747 * admission control: 748 * for the real-time service curve, the sum of the service curves 749 * should not exceed 80% of the interface bandwidth. 20% is reserved 750 * not to over-commit the actual interface bandwidth. 751 * for the linkshare service curve, the sum of the child service 752 * curve should not exceed the parent service curve. 753 * for the upper-limit service curve, the assigned bandwidth should 754 * be smaller than the interface bandwidth, and the upper-limit should 755 * be larger than the real-time service curve when both are defined. 756 */ 757 parent = qname_to_pfaltq(pa->parent, pa->ifname); 758 if (parent == NULL) 759 errx(1, "parent %s not found for %s", pa->parent, pa->qname); 760 761 TAILQ_FOREACH(altq, &altqs, entries) { 762 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 763 continue; 764 if (altq->qname[0] == 0) /* this is for interface */ 765 continue; 766 767 /* if the class has a real-time service curve, add it. */ 768 if (opts->rtsc_m2 != 0 && altq->pq_u.hfsc_opts.rtsc_m2 != 0) { 769 sc.m1 = altq->pq_u.hfsc_opts.rtsc_m1; 770 sc.d = altq->pq_u.hfsc_opts.rtsc_d; 771 sc.m2 = altq->pq_u.hfsc_opts.rtsc_m2; 772 gsc_add_sc(&rtsc, &sc); 773 } 774 775 if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0) 776 continue; 777 778 /* if the class has a linkshare service curve, add it. */ 779 if (opts->lssc_m2 != 0 && altq->pq_u.hfsc_opts.lssc_m2 != 0) { 780 sc.m1 = altq->pq_u.hfsc_opts.lssc_m1; 781 sc.d = altq->pq_u.hfsc_opts.lssc_d; 782 sc.m2 = altq->pq_u.hfsc_opts.lssc_m2; 783 gsc_add_sc(&lssc, &sc); 784 } 785 } 786 787 /* check the real-time service curve. reserve 20% of interface bw */ 788 if (opts->rtsc_m2 != 0) { 789 /* add this queue to the sum */ 790 sc.m1 = opts->rtsc_m1; 791 sc.d = opts->rtsc_d; 792 sc.m2 = opts->rtsc_m2; 793 gsc_add_sc(&rtsc, &sc); 794 /* compare the sum with 80% of the interface */ 795 sc.m1 = 0; 796 sc.d = 0; 797 sc.m2 = pa->ifbandwidth / 100 * 80; 798 if (!is_gsc_under_sc(&rtsc, &sc)) { 799 warnx("real-time sc exceeds 80%% of the interface " 800 "bandwidth (%s)", rate2str((double)sc.m2)); 801 goto err_ret; 802 } 803 } 804 805 /* check the linkshare service curve. */ 806 if (opts->lssc_m2 != 0) { 807 /* add this queue to the child sum */ 808 sc.m1 = opts->lssc_m1; 809 sc.d = opts->lssc_d; 810 sc.m2 = opts->lssc_m2; 811 gsc_add_sc(&lssc, &sc); 812 /* compare the sum of the children with parent's sc */ 813 sc.m1 = parent->pq_u.hfsc_opts.lssc_m1; 814 sc.d = parent->pq_u.hfsc_opts.lssc_d; 815 sc.m2 = parent->pq_u.hfsc_opts.lssc_m2; 816 if (!is_gsc_under_sc(&lssc, &sc)) { 817 warnx("linkshare sc exceeds parent's sc"); 818 goto err_ret; 819 } 820 } 821 822 /* check the upper-limit service curve. */ 823 if (opts->ulsc_m2 != 0) { 824 if (opts->ulsc_m1 > pa->ifbandwidth || 825 opts->ulsc_m2 > pa->ifbandwidth) { 826 warnx("upper-limit larger than interface bandwidth"); 827 goto err_ret; 828 } 829 if (opts->rtsc_m2 != 0 && opts->rtsc_m2 > opts->ulsc_m2) { 830 warnx("upper-limit sc smaller than real-time sc"); 831 goto err_ret; 832 } 833 } 834 835 gsc_destroy(&rtsc); 836 gsc_destroy(&lssc); 837 838 return (0); 839 840 err_ret: 841 gsc_destroy(&rtsc); 842 gsc_destroy(&lssc); 843 return (-1); 844 } 845 846 /* 847 * FAIRQ support functions 848 */ 849 static int 850 eval_pfqueue_fairq(struct pfctl *pf __unused, struct pf_altq *pa) 851 { 852 struct pf_altq *altq, *parent; 853 struct fairq_opts *opts; 854 struct service_curve sc; 855 856 opts = &pa->pq_u.fairq_opts; 857 858 if (pa->parent[0] == 0) { 859 /* root queue */ 860 opts->lssc_m1 = pa->ifbandwidth; 861 opts->lssc_m2 = pa->ifbandwidth; 862 opts->lssc_d = 0; 863 return (0); 864 } 865 866 LIST_INIT(&lssc); 867 868 /* if link_share is not specified, use bandwidth */ 869 if (opts->lssc_m2 == 0) 870 opts->lssc_m2 = pa->bandwidth; 871 872 /* 873 * admission control: 874 * for the real-time service curve, the sum of the service curves 875 * should not exceed 80% of the interface bandwidth. 20% is reserved 876 * not to over-commit the actual interface bandwidth. 877 * for the link-sharing service curve, the sum of the child service 878 * curve should not exceed the parent service curve. 879 * for the upper-limit service curve, the assigned bandwidth should 880 * be smaller than the interface bandwidth, and the upper-limit should 881 * be larger than the real-time service curve when both are defined. 882 */ 883 parent = qname_to_pfaltq(pa->parent, pa->ifname); 884 if (parent == NULL) 885 errx(1, "parent %s not found for %s", pa->parent, pa->qname); 886 887 TAILQ_FOREACH(altq, &altqs, entries) { 888 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 889 continue; 890 if (altq->qname[0] == 0) /* this is for interface */ 891 continue; 892 893 if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0) 894 continue; 895 896 /* if the class has a link-sharing service curve, add it. */ 897 if (opts->lssc_m2 != 0 && altq->pq_u.fairq_opts.lssc_m2 != 0) { 898 sc.m1 = altq->pq_u.fairq_opts.lssc_m1; 899 sc.d = altq->pq_u.fairq_opts.lssc_d; 900 sc.m2 = altq->pq_u.fairq_opts.lssc_m2; 901 gsc_add_sc(&lssc, &sc); 902 } 903 } 904 905 /* check the link-sharing service curve. */ 906 if (opts->lssc_m2 != 0) { 907 sc.m1 = parent->pq_u.fairq_opts.lssc_m1; 908 sc.d = parent->pq_u.fairq_opts.lssc_d; 909 sc.m2 = parent->pq_u.fairq_opts.lssc_m2; 910 if (!is_gsc_under_sc(&lssc, &sc)) { 911 warnx("link-sharing sc exceeds parent's sc"); 912 goto err_ret; 913 } 914 } 915 916 gsc_destroy(&lssc); 917 918 return (0); 919 920 err_ret: 921 gsc_destroy(&lssc); 922 return (-1); 923 } 924 925 static int 926 check_commit_hfsc(int dev, int opts, struct pf_altq *pa) 927 { 928 struct pf_altq *altq, *def = NULL; 929 int default_class; 930 int error = 0; 931 932 /* check if hfsc has one default queue for this interface */ 933 default_class = 0; 934 TAILQ_FOREACH(altq, &altqs, entries) { 935 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 936 continue; 937 if (altq->qname[0] == 0) /* this is for interface */ 938 continue; 939 if (altq->parent[0] == 0) /* dummy root */ 940 continue; 941 if (altq->pq_u.hfsc_opts.flags & HFCF_DEFAULTCLASS) { 942 default_class++; 943 def = altq; 944 } 945 } 946 if (default_class != 1) { 947 warnx("should have one default queue on %s", pa->ifname); 948 return (1); 949 } 950 /* make sure the default queue is a leaf */ 951 TAILQ_FOREACH(altq, &altqs, entries) { 952 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 953 continue; 954 if (altq->qname[0] == 0) /* this is for interface */ 955 continue; 956 if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) { 957 warnx("default queue is not a leaf"); 958 error++; 959 } 960 } 961 return (error); 962 } 963 964 static int 965 check_commit_fairq(int dev __unused, int opts __unused, struct pf_altq *pa) 966 { 967 struct pf_altq *altq, *def = NULL; 968 int default_class; 969 int error = 0; 970 971 /* check if fairq has one default queue for this interface */ 972 default_class = 0; 973 TAILQ_FOREACH(altq, &altqs, entries) { 974 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 975 continue; 976 if (altq->qname[0] == 0) /* this is for interface */ 977 continue; 978 if (altq->pq_u.fairq_opts.flags & FARF_DEFAULTCLASS) { 979 default_class++; 980 def = altq; 981 } 982 } 983 if (default_class != 1) { 984 warnx("should have one default queue on %s", pa->ifname); 985 return (1); 986 } 987 /* make sure the default queue is a leaf */ 988 TAILQ_FOREACH(altq, &altqs, entries) { 989 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 990 continue; 991 if (altq->qname[0] == 0) /* this is for interface */ 992 continue; 993 if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) { 994 warnx("default queue is not a leaf"); 995 error++; 996 } 997 } 998 return (error); 999 } 1000 1001 static int 1002 print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) 1003 { 1004 const struct hfsc_opts *opts; 1005 const struct node_hfsc_sc *rtsc, *lssc, *ulsc; 1006 1007 opts = &a->pq_u.hfsc_opts; 1008 if (qopts == NULL) 1009 rtsc = lssc = ulsc = NULL; 1010 else { 1011 rtsc = &qopts->data.hfsc_opts.realtime; 1012 lssc = &qopts->data.hfsc_opts.linkshare; 1013 ulsc = &qopts->data.hfsc_opts.upperlimit; 1014 } 1015 1016 if (opts->flags || opts->rtsc_m2 != 0 || opts->ulsc_m2 != 0 || 1017 (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || 1018 opts->lssc_d != 0))) { 1019 printf("hfsc("); 1020 if (opts->flags & HFCF_RED) 1021 printf(" red"); 1022 if (opts->flags & HFCF_ECN) 1023 printf(" ecn"); 1024 if (opts->flags & HFCF_RIO) 1025 printf(" rio"); 1026 if (opts->flags & HFCF_CODEL) 1027 printf(" codel"); 1028 if (opts->flags & HFCF_CLEARDSCP) 1029 printf(" cleardscp"); 1030 if (opts->flags & HFCF_DEFAULTCLASS) 1031 printf(" default"); 1032 if (opts->rtsc_m2 != 0) 1033 print_hfsc_sc("realtime", opts->rtsc_m1, opts->rtsc_d, 1034 opts->rtsc_m2, rtsc); 1035 if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || 1036 opts->lssc_d != 0)) 1037 print_hfsc_sc("linkshare", opts->lssc_m1, opts->lssc_d, 1038 opts->lssc_m2, lssc); 1039 if (opts->ulsc_m2 != 0) 1040 print_hfsc_sc("upperlimit", opts->ulsc_m1, opts->ulsc_d, 1041 opts->ulsc_m2, ulsc); 1042 printf(" ) "); 1043 1044 return (1); 1045 } else 1046 return (0); 1047 } 1048 1049 static int 1050 print_codel_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) 1051 { 1052 const struct codel_opts *opts; 1053 1054 opts = &a->pq_u.codel_opts; 1055 if (opts->target || opts->interval || opts->ecn) { 1056 printf("codel("); 1057 if (opts->target) 1058 printf(" target %d", opts->target); 1059 if (opts->interval) 1060 printf(" interval %d", opts->interval); 1061 if (opts->ecn) 1062 printf("ecn"); 1063 printf(" ) "); 1064 1065 return (1); 1066 } 1067 1068 return (0); 1069 } 1070 1071 static int 1072 print_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) 1073 { 1074 const struct fairq_opts *opts; 1075 const struct node_fairq_sc *loc_lssc; 1076 1077 opts = &a->pq_u.fairq_opts; 1078 if (qopts == NULL) 1079 loc_lssc = NULL; 1080 else 1081 loc_lssc = &qopts->data.fairq_opts.linkshare; 1082 1083 if (opts->flags || 1084 (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || 1085 opts->lssc_d != 0))) { 1086 printf("fairq("); 1087 if (opts->flags & FARF_RED) 1088 printf(" red"); 1089 if (opts->flags & FARF_ECN) 1090 printf(" ecn"); 1091 if (opts->flags & FARF_RIO) 1092 printf(" rio"); 1093 if (opts->flags & FARF_CODEL) 1094 printf(" codel"); 1095 if (opts->flags & FARF_CLEARDSCP) 1096 printf(" cleardscp"); 1097 if (opts->flags & FARF_DEFAULTCLASS) 1098 printf(" default"); 1099 if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || 1100 opts->lssc_d != 0)) 1101 print_fairq_sc("linkshare", opts->lssc_m1, opts->lssc_d, 1102 opts->lssc_m2, loc_lssc); 1103 printf(" ) "); 1104 1105 return (1); 1106 } else 1107 return (0); 1108 } 1109 1110 /* 1111 * admission control using generalized service curve 1112 */ 1113 1114 /* add a new service curve to a generalized service curve */ 1115 static void 1116 gsc_add_sc(struct gen_sc *gsc, struct service_curve *sc) 1117 { 1118 if (is_sc_null(sc)) 1119 return; 1120 if (sc->d != 0) 1121 gsc_add_seg(gsc, 0.0, 0.0, (double)sc->d, (double)sc->m1); 1122 gsc_add_seg(gsc, (double)sc->d, 0.0, INFINITY, (double)sc->m2); 1123 } 1124 1125 /* 1126 * check whether all points of a generalized service curve have 1127 * their y-coordinates no larger than a given two-piece linear 1128 * service curve. 1129 */ 1130 static int 1131 is_gsc_under_sc(struct gen_sc *gsc, struct service_curve *sc) 1132 { 1133 struct segment *s, *last, *end; 1134 double y; 1135 1136 if (is_sc_null(sc)) { 1137 if (LIST_EMPTY(gsc)) 1138 return (1); 1139 LIST_FOREACH(s, gsc, _next) { 1140 if (s->m != 0) 1141 return (0); 1142 } 1143 return (1); 1144 } 1145 /* 1146 * gsc has a dummy entry at the end with x = INFINITY. 1147 * loop through up to this dummy entry. 1148 */ 1149 end = gsc_getentry(gsc, INFINITY); 1150 if (end == NULL) 1151 return (1); 1152 last = NULL; 1153 for (s = LIST_FIRST(gsc); s != end; s = LIST_NEXT(s, _next)) { 1154 if (s->y > sc_x2y(sc, s->x)) 1155 return (0); 1156 last = s; 1157 } 1158 /* last now holds the real last segment */ 1159 if (last == NULL) 1160 return (1); 1161 if (last->m > sc->m2) 1162 return (0); 1163 if (last->x < sc->d && last->m > sc->m1) { 1164 y = last->y + (sc->d - last->x) * last->m; 1165 if (y > sc_x2y(sc, sc->d)) 1166 return (0); 1167 } 1168 return (1); 1169 } 1170 1171 static void 1172 gsc_destroy(struct gen_sc *gsc) 1173 { 1174 struct segment *s; 1175 1176 while ((s = LIST_FIRST(gsc)) != NULL) { 1177 LIST_REMOVE(s, _next); 1178 free(s); 1179 } 1180 } 1181 1182 /* 1183 * return a segment entry starting at x. 1184 * if gsc has no entry starting at x, a new entry is created at x. 1185 */ 1186 static struct segment * 1187 gsc_getentry(struct gen_sc *gsc, double x) 1188 { 1189 struct segment *new, *prev, *s; 1190 1191 prev = NULL; 1192 LIST_FOREACH(s, gsc, _next) { 1193 if (s->x == x) 1194 return (s); /* matching entry found */ 1195 else if (s->x < x) 1196 prev = s; 1197 else 1198 break; 1199 } 1200 1201 /* we have to create a new entry */ 1202 if ((new = calloc(1, sizeof(struct segment))) == NULL) 1203 return (NULL); 1204 1205 new->x = x; 1206 if (x == INFINITY || s == NULL) 1207 new->d = 0; 1208 else if (s->x == INFINITY) 1209 new->d = INFINITY; 1210 else 1211 new->d = s->x - x; 1212 if (prev == NULL) { 1213 /* insert the new entry at the head of the list */ 1214 new->y = 0; 1215 new->m = 0; 1216 LIST_INSERT_HEAD(gsc, new, _next); 1217 } else { 1218 /* 1219 * the start point intersects with the segment pointed by 1220 * prev. divide prev into 2 segments 1221 */ 1222 if (x == INFINITY) { 1223 prev->d = INFINITY; 1224 if (prev->m == 0) 1225 new->y = prev->y; 1226 else 1227 new->y = INFINITY; 1228 } else { 1229 prev->d = x - prev->x; 1230 new->y = prev->d * prev->m + prev->y; 1231 } 1232 new->m = prev->m; 1233 LIST_INSERT_AFTER(prev, new, _next); 1234 } 1235 return (new); 1236 } 1237 1238 /* add a segment to a generalized service curve */ 1239 static int 1240 gsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m) 1241 { 1242 struct segment *start, *end, *s; 1243 double x2; 1244 1245 if (d == INFINITY) 1246 x2 = INFINITY; 1247 else 1248 x2 = x + d; 1249 start = gsc_getentry(gsc, x); 1250 end = gsc_getentry(gsc, x2); 1251 if (start == NULL || end == NULL) 1252 return (-1); 1253 1254 for (s = start; s != end; s = LIST_NEXT(s, _next)) { 1255 s->m += m; 1256 s->y += y + (s->x - x) * m; 1257 } 1258 1259 end = gsc_getentry(gsc, INFINITY); 1260 for (; s != end; s = LIST_NEXT(s, _next)) { 1261 s->y += m * d; 1262 } 1263 1264 return (0); 1265 } 1266 1267 /* get y-projection of a service curve */ 1268 static double 1269 sc_x2y(struct service_curve *sc, double x) 1270 { 1271 double y; 1272 1273 if (x <= (double)sc->d) 1274 /* y belongs to the 1st segment */ 1275 y = x * (double)sc->m1; 1276 else 1277 /* y belongs to the 2nd segment */ 1278 y = (double)sc->d * (double)sc->m1 1279 + (x - (double)sc->d) * (double)sc->m2; 1280 return (y); 1281 } 1282 1283 /* 1284 * misc utilities 1285 */ 1286 #define R2S_BUFS 8 1287 #define RATESTR_MAX 16 1288 1289 char * 1290 rate2str(double rate) 1291 { 1292 char *buf; 1293 static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */ 1294 static int idx = 0; 1295 int i; 1296 static const char unit[] = " KMG"; 1297 1298 buf = r2sbuf[idx++]; 1299 if (idx == R2S_BUFS) 1300 idx = 0; 1301 1302 for (i = 0; rate >= 1000 && i <= 3; i++) 1303 rate /= 1000; 1304 1305 if ((int)(rate * 100) % 100) 1306 snprintf(buf, RATESTR_MAX, "%.2f%cb", rate, unit[i]); 1307 else 1308 snprintf(buf, RATESTR_MAX, "%d%cb", (int)rate, unit[i]); 1309 1310 return (buf); 1311 } 1312 1313 #ifdef __FreeBSD__ 1314 /* 1315 * XXX 1316 * FreeBSD does not have SIOCGIFDATA. 1317 * To emulate this, DIOCGIFSPEED ioctl added to pf. 1318 */ 1319 u_int32_t 1320 getifspeed(int pfdev, char *ifname) 1321 { 1322 struct pf_ifspeed io; 1323 1324 bzero(&io, sizeof io); 1325 if (strlcpy(io.ifname, ifname, IFNAMSIZ) >= 1326 sizeof(io.ifname)) 1327 errx(1, "getifspeed: strlcpy"); 1328 if (ioctl(pfdev, DIOCGIFSPEED, &io) == -1) 1329 err(1, "DIOCGIFSPEED"); 1330 return ((u_int32_t)io.baudrate); 1331 } 1332 #else 1333 u_int32_t 1334 getifspeed(char *ifname) 1335 { 1336 int s; 1337 struct ifreq ifr; 1338 struct if_data ifrdat; 1339 1340 if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0) 1341 err(1, "socket"); 1342 bzero(&ifr, sizeof(ifr)); 1343 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= 1344 sizeof(ifr.ifr_name)) 1345 errx(1, "getifspeed: strlcpy"); 1346 ifr.ifr_data = (caddr_t)&ifrdat; 1347 if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1) 1348 err(1, "SIOCGIFDATA"); 1349 if (close(s)) 1350 err(1, "close"); 1351 return ((u_int32_t)ifrdat.ifi_baudrate); 1352 } 1353 #endif 1354 1355 u_long 1356 getifmtu(char *ifname) 1357 { 1358 int s; 1359 struct ifreq ifr; 1360 1361 if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0) 1362 err(1, "socket"); 1363 bzero(&ifr, sizeof(ifr)); 1364 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= 1365 sizeof(ifr.ifr_name)) 1366 errx(1, "getifmtu: strlcpy"); 1367 if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == -1) 1368 #ifdef __FreeBSD__ 1369 ifr.ifr_mtu = 1500; 1370 #else 1371 err(1, "SIOCGIFMTU"); 1372 #endif 1373 if (close(s)) 1374 err(1, "close"); 1375 if (ifr.ifr_mtu > 0) 1376 return (ifr.ifr_mtu); 1377 else { 1378 warnx("could not get mtu for %s, assuming 1500", ifname); 1379 return (1500); 1380 } 1381 } 1382 1383 int 1384 eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts, 1385 u_int32_t ref_bw) 1386 { 1387 int errors = 0; 1388 1389 switch (pa->scheduler) { 1390 case ALTQT_CBQ: 1391 pa->pq_u.cbq_opts = opts->data.cbq_opts; 1392 break; 1393 case ALTQT_PRIQ: 1394 pa->pq_u.priq_opts = opts->data.priq_opts; 1395 break; 1396 case ALTQT_HFSC: 1397 pa->pq_u.hfsc_opts.flags = opts->data.hfsc_opts.flags; 1398 if (opts->data.hfsc_opts.linkshare.used) { 1399 pa->pq_u.hfsc_opts.lssc_m1 = 1400 eval_bwspec(&opts->data.hfsc_opts.linkshare.m1, 1401 ref_bw); 1402 pa->pq_u.hfsc_opts.lssc_m2 = 1403 eval_bwspec(&opts->data.hfsc_opts.linkshare.m2, 1404 ref_bw); 1405 pa->pq_u.hfsc_opts.lssc_d = 1406 opts->data.hfsc_opts.linkshare.d; 1407 } 1408 if (opts->data.hfsc_opts.realtime.used) { 1409 pa->pq_u.hfsc_opts.rtsc_m1 = 1410 eval_bwspec(&opts->data.hfsc_opts.realtime.m1, 1411 ref_bw); 1412 pa->pq_u.hfsc_opts.rtsc_m2 = 1413 eval_bwspec(&opts->data.hfsc_opts.realtime.m2, 1414 ref_bw); 1415 pa->pq_u.hfsc_opts.rtsc_d = 1416 opts->data.hfsc_opts.realtime.d; 1417 } 1418 if (opts->data.hfsc_opts.upperlimit.used) { 1419 pa->pq_u.hfsc_opts.ulsc_m1 = 1420 eval_bwspec(&opts->data.hfsc_opts.upperlimit.m1, 1421 ref_bw); 1422 pa->pq_u.hfsc_opts.ulsc_m2 = 1423 eval_bwspec(&opts->data.hfsc_opts.upperlimit.m2, 1424 ref_bw); 1425 pa->pq_u.hfsc_opts.ulsc_d = 1426 opts->data.hfsc_opts.upperlimit.d; 1427 } 1428 break; 1429 case ALTQT_FAIRQ: 1430 pa->pq_u.fairq_opts.flags = opts->data.fairq_opts.flags; 1431 pa->pq_u.fairq_opts.nbuckets = opts->data.fairq_opts.nbuckets; 1432 pa->pq_u.fairq_opts.hogs_m1 = 1433 eval_bwspec(&opts->data.fairq_opts.hogs_bw, ref_bw); 1434 1435 if (opts->data.fairq_opts.linkshare.used) { 1436 pa->pq_u.fairq_opts.lssc_m1 = 1437 eval_bwspec(&opts->data.fairq_opts.linkshare.m1, 1438 ref_bw); 1439 pa->pq_u.fairq_opts.lssc_m2 = 1440 eval_bwspec(&opts->data.fairq_opts.linkshare.m2, 1441 ref_bw); 1442 pa->pq_u.fairq_opts.lssc_d = 1443 opts->data.fairq_opts.linkshare.d; 1444 } 1445 break; 1446 case ALTQT_CODEL: 1447 pa->pq_u.codel_opts.target = opts->data.codel_opts.target; 1448 pa->pq_u.codel_opts.interval = opts->data.codel_opts.interval; 1449 pa->pq_u.codel_opts.ecn = opts->data.codel_opts.ecn; 1450 break; 1451 default: 1452 warnx("eval_queue_opts: unknown scheduler type %u", 1453 opts->qtype); 1454 errors++; 1455 break; 1456 } 1457 1458 return (errors); 1459 } 1460 1461 u_int32_t 1462 eval_bwspec(struct node_queue_bw *bw, u_int32_t ref_bw) 1463 { 1464 if (bw->bw_absolute > 0) 1465 return (bw->bw_absolute); 1466 1467 if (bw->bw_percent > 0) 1468 return (ref_bw / 100 * bw->bw_percent); 1469 1470 return (0); 1471 } 1472 1473 void 1474 print_hfsc_sc(const char *scname, u_int m1, u_int d, u_int m2, 1475 const struct node_hfsc_sc *sc) 1476 { 1477 printf(" %s", scname); 1478 1479 if (d != 0) { 1480 printf("("); 1481 if (sc != NULL && sc->m1.bw_percent > 0) 1482 printf("%u%%", sc->m1.bw_percent); 1483 else 1484 printf("%s", rate2str((double)m1)); 1485 printf(" %u", d); 1486 } 1487 1488 if (sc != NULL && sc->m2.bw_percent > 0) 1489 printf(" %u%%", sc->m2.bw_percent); 1490 else 1491 printf(" %s", rate2str((double)m2)); 1492 1493 if (d != 0) 1494 printf(")"); 1495 } 1496 1497 void 1498 print_fairq_sc(const char *scname, u_int m1, u_int d, u_int m2, 1499 const struct node_fairq_sc *sc) 1500 { 1501 printf(" %s", scname); 1502 1503 if (d != 0) { 1504 printf("("); 1505 if (sc != NULL && sc->m1.bw_percent > 0) 1506 printf("%u%%", sc->m1.bw_percent); 1507 else 1508 printf("%s", rate2str((double)m1)); 1509 printf(" %u", d); 1510 } 1511 1512 if (sc != NULL && sc->m2.bw_percent > 0) 1513 printf(" %u%%", sc->m2.bw_percent); 1514 else 1515 printf(" %s", rate2str((double)m2)); 1516 1517 if (d != 0) 1518 printf(")"); 1519 } 1520