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