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 nsPerByte = (double)(INT_MAX / opts->maxpktsize); 481 } 482 483 if (maxburst == 0) { /* use default */ 484 if (cptime > 10.0 * 1000000) 485 maxburst = 4; 486 else 487 maxburst = 16; 488 } 489 if (minburst == 0) /* use default */ 490 minburst = 2; 491 if (minburst > maxburst) 492 minburst = maxburst; 493 494 z = (double)(1 << RM_FILTER_GAIN); 495 g = (1.0 - 1.0 / z); 496 gton = pow(g, (double)maxburst); 497 gtom = pow(g, (double)(minburst-1)); 498 maxidle = ((1.0 / f - 1.0) * ((1.0 - gton) / gton)); 499 maxidle_s = (1.0 - g); 500 if (maxidle > maxidle_s) 501 maxidle = ptime * maxidle; 502 else 503 maxidle = ptime * maxidle_s; 504 offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom); 505 minidle = -((double)opts->maxpktsize * (double)nsPerByte); 506 507 /* scale parameters */ 508 maxidle = ((maxidle * 8.0) / nsPerByte) * 509 pow(2.0, (double)RM_FILTER_GAIN); 510 offtime = (offtime * 8.0) / nsPerByte * 511 pow(2.0, (double)RM_FILTER_GAIN); 512 minidle = ((minidle * 8.0) / nsPerByte) * 513 pow(2.0, (double)RM_FILTER_GAIN); 514 515 maxidle = maxidle / 1000.0; 516 offtime = offtime / 1000.0; 517 minidle = minidle / 1000.0; 518 519 opts->minburst = minburst; 520 opts->maxburst = maxburst; 521 opts->ns_per_byte = (u_int)nsPerByte; 522 opts->maxidle = (u_int)fabs(maxidle); 523 opts->minidle = (int)minidle; 524 opts->offtime = (u_int)fabs(offtime); 525 526 return (0); 527 } 528 529 static int 530 check_commit_cbq(int dev __unused, int opts __unused, struct pf_altq *pa) 531 { 532 struct pf_altq *altq; 533 int root_class, default_class; 534 int error = 0; 535 536 /* 537 * check if cbq has one root queue and one default queue 538 * for this interface 539 */ 540 root_class = default_class = 0; 541 TAILQ_FOREACH(altq, &altqs, entries) { 542 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 543 continue; 544 if (altq->qname[0] == 0) /* this is for interface */ 545 continue; 546 if (altq->pq_u.cbq_opts.flags & CBQCLF_ROOTCLASS) 547 root_class++; 548 if (altq->pq_u.cbq_opts.flags & CBQCLF_DEFCLASS) 549 default_class++; 550 } 551 if (root_class != 1) { 552 warnx("should have one root queue on %s", pa->ifname); 553 error++; 554 } 555 if (default_class != 1) { 556 warnx("should have one default queue on %s", pa->ifname); 557 error++; 558 } 559 return (error); 560 } 561 562 static int 563 print_cbq_opts(const struct pf_altq *a) 564 { 565 const struct cbq_opts *opts; 566 567 opts = &a->pq_u.cbq_opts; 568 if (opts->flags) { 569 printf("cbq("); 570 if (opts->flags & CBQCLF_RED) 571 printf(" red"); 572 if (opts->flags & CBQCLF_ECN) 573 printf(" ecn"); 574 if (opts->flags & CBQCLF_RIO) 575 printf(" rio"); 576 if (opts->flags & CBQCLF_CLEARDSCP) 577 printf(" cleardscp"); 578 if (opts->flags & CBQCLF_BORROW) 579 printf(" borrow"); 580 if (opts->flags & CBQCLF_WRR) 581 printf(" wrr"); 582 if (opts->flags & CBQCLF_EFFICIENT) 583 printf(" efficient"); 584 if (opts->flags & CBQCLF_ROOTCLASS) 585 printf(" root"); 586 if (opts->flags & CBQCLF_DEFCLASS) 587 printf(" default"); 588 printf(" ) "); 589 590 return (1); 591 } else 592 return (0); 593 } 594 595 /* 596 * PRIQ support functions 597 */ 598 static int 599 eval_pfqueue_priq(struct pfctl *pf __unused, struct pf_altq *pa) 600 { 601 struct pf_altq *altq; 602 603 if (pa->priority >= PRIQ_MAXPRI) { 604 warnx("priority out of range: max %d", PRIQ_MAXPRI - 1); 605 return (-1); 606 } 607 /* the priority should be unique for the interface */ 608 TAILQ_FOREACH(altq, &altqs, entries) { 609 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) == 0 && 610 altq->qname[0] != 0 && altq->priority == pa->priority) { 611 warnx("%s and %s have the same priority", 612 altq->qname, pa->qname); 613 return (-1); 614 } 615 } 616 617 return (0); 618 } 619 620 static int 621 check_commit_priq(int dev __unused, int opts __unused, struct pf_altq *pa) 622 { 623 struct pf_altq *altq; 624 int default_class; 625 int error = 0; 626 627 /* 628 * check if priq has one default class for this interface 629 */ 630 default_class = 0; 631 TAILQ_FOREACH(altq, &altqs, entries) { 632 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 633 continue; 634 if (altq->qname[0] == 0) /* this is for interface */ 635 continue; 636 if (altq->pq_u.priq_opts.flags & PRCF_DEFAULTCLASS) 637 default_class++; 638 } 639 if (default_class != 1) { 640 warnx("should have one default queue on %s", pa->ifname); 641 error++; 642 } 643 return (error); 644 } 645 646 static int 647 print_priq_opts(const struct pf_altq *a) 648 { 649 const struct priq_opts *opts; 650 651 opts = &a->pq_u.priq_opts; 652 653 if (opts->flags) { 654 printf("priq("); 655 if (opts->flags & PRCF_RED) 656 printf(" red"); 657 if (opts->flags & PRCF_ECN) 658 printf(" ecn"); 659 if (opts->flags & PRCF_RIO) 660 printf(" rio"); 661 if (opts->flags & PRCF_CLEARDSCP) 662 printf(" cleardscp"); 663 if (opts->flags & PRCF_DEFAULTCLASS) 664 printf(" default"); 665 printf(" ) "); 666 667 return (1); 668 } else 669 return (0); 670 } 671 672 /* 673 * HFSC support functions 674 */ 675 static int 676 eval_pfqueue_hfsc(struct pfctl *pf __unused, struct pf_altq *pa) 677 { 678 struct pf_altq *altq, *parent; 679 struct hfsc_opts *opts; 680 struct service_curve sc; 681 682 opts = &pa->pq_u.hfsc_opts; 683 684 if (pa->parent[0] == 0) { 685 /* root queue */ 686 opts->lssc_m1 = pa->ifbandwidth; 687 opts->lssc_m2 = pa->ifbandwidth; 688 opts->lssc_d = 0; 689 return (0); 690 } 691 692 LIST_INIT(&rtsc); 693 LIST_INIT(&lssc); 694 695 /* if link_share is not specified, use bandwidth */ 696 if (opts->lssc_m2 == 0) 697 opts->lssc_m2 = pa->bandwidth; 698 699 if ((opts->rtsc_m1 > 0 && opts->rtsc_m2 == 0) || 700 (opts->lssc_m1 > 0 && opts->lssc_m2 == 0) || 701 (opts->ulsc_m1 > 0 && opts->ulsc_m2 == 0)) { 702 warnx("m2 is zero for %s", pa->qname); 703 return (-1); 704 } 705 706 if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) || 707 (opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) || 708 (opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) { 709 warnx("m1 must be zero for convex curve: %s", pa->qname); 710 return (-1); 711 } 712 713 /* 714 * admission control: 715 * for the real-time service curve, the sum of the service curves 716 * should not exceed 80% of the interface bandwidth. 20% is reserved 717 * not to over-commit the actual interface bandwidth. 718 * for the linkshare service curve, the sum of the child service 719 * curve should not exceed the parent service curve. 720 * for the upper-limit service curve, the assigned bandwidth should 721 * be smaller than the interface bandwidth, and the upper-limit should 722 * be larger than the real-time service curve when both are defined. 723 */ 724 parent = qname_to_pfaltq(pa->parent, pa->ifname); 725 if (parent == NULL) 726 errx(1, "parent %s not found for %s", pa->parent, pa->qname); 727 728 TAILQ_FOREACH(altq, &altqs, entries) { 729 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 730 continue; 731 if (altq->qname[0] == 0) /* this is for interface */ 732 continue; 733 734 /* if the class has a real-time service curve, add it. */ 735 if (opts->rtsc_m2 != 0 && altq->pq_u.hfsc_opts.rtsc_m2 != 0) { 736 sc.m1 = altq->pq_u.hfsc_opts.rtsc_m1; 737 sc.d = altq->pq_u.hfsc_opts.rtsc_d; 738 sc.m2 = altq->pq_u.hfsc_opts.rtsc_m2; 739 gsc_add_sc(&rtsc, &sc); 740 } 741 742 if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0) 743 continue; 744 745 /* if the class has a linkshare service curve, add it. */ 746 if (opts->lssc_m2 != 0 && altq->pq_u.hfsc_opts.lssc_m2 != 0) { 747 sc.m1 = altq->pq_u.hfsc_opts.lssc_m1; 748 sc.d = altq->pq_u.hfsc_opts.lssc_d; 749 sc.m2 = altq->pq_u.hfsc_opts.lssc_m2; 750 gsc_add_sc(&lssc, &sc); 751 } 752 } 753 754 /* check the real-time service curve. reserve 20% of interface bw */ 755 if (opts->rtsc_m2 != 0) { 756 /* add this queue to the sum */ 757 sc.m1 = opts->rtsc_m1; 758 sc.d = opts->rtsc_d; 759 sc.m2 = opts->rtsc_m2; 760 gsc_add_sc(&rtsc, &sc); 761 /* compare the sum with 80% of the interface */ 762 sc.m1 = 0; 763 sc.d = 0; 764 sc.m2 = pa->ifbandwidth / 100 * 80; 765 if (!is_gsc_under_sc(&rtsc, &sc)) { 766 warnx("real-time sc exceeds 80%% of the interface " 767 "bandwidth (%s)", rate2str((double)sc.m2)); 768 goto err_ret; 769 } 770 } 771 772 /* check the linkshare service curve. */ 773 if (opts->lssc_m2 != 0) { 774 /* add this queue to the child sum */ 775 sc.m1 = opts->lssc_m1; 776 sc.d = opts->lssc_d; 777 sc.m2 = opts->lssc_m2; 778 gsc_add_sc(&lssc, &sc); 779 /* compare the sum of the children with parent's sc */ 780 sc.m1 = parent->pq_u.hfsc_opts.lssc_m1; 781 sc.d = parent->pq_u.hfsc_opts.lssc_d; 782 sc.m2 = parent->pq_u.hfsc_opts.lssc_m2; 783 if (!is_gsc_under_sc(&lssc, &sc)) { 784 warnx("linkshare sc exceeds parent's sc"); 785 goto err_ret; 786 } 787 } 788 789 /* check the upper-limit service curve. */ 790 if (opts->ulsc_m2 != 0) { 791 if (opts->ulsc_m1 > pa->ifbandwidth || 792 opts->ulsc_m2 > pa->ifbandwidth) { 793 warnx("upper-limit larger than interface bandwidth"); 794 goto err_ret; 795 } 796 if (opts->rtsc_m2 != 0 && opts->rtsc_m2 > opts->ulsc_m2) { 797 warnx("upper-limit sc smaller than real-time sc"); 798 goto err_ret; 799 } 800 } 801 802 gsc_destroy(&rtsc); 803 gsc_destroy(&lssc); 804 805 return (0); 806 807 err_ret: 808 gsc_destroy(&rtsc); 809 gsc_destroy(&lssc); 810 return (-1); 811 } 812 813 /* 814 * FAIRQ support functions 815 */ 816 static int 817 eval_pfqueue_fairq(struct pfctl *pf __unused, struct pf_altq *pa) 818 { 819 struct pf_altq *altq, *parent; 820 struct fairq_opts *opts; 821 struct service_curve sc; 822 823 opts = &pa->pq_u.fairq_opts; 824 825 if (pa->parent[0] == 0) { 826 /* root queue */ 827 opts->lssc_m1 = pa->ifbandwidth; 828 opts->lssc_m2 = pa->ifbandwidth; 829 opts->lssc_d = 0; 830 return (0); 831 } 832 833 LIST_INIT(&lssc); 834 835 /* if link_share is not specified, use bandwidth */ 836 if (opts->lssc_m2 == 0) 837 opts->lssc_m2 = pa->bandwidth; 838 839 /* 840 * admission control: 841 * for the real-time service curve, the sum of the service curves 842 * should not exceed 80% of the interface bandwidth. 20% is reserved 843 * not to over-commit the actual interface bandwidth. 844 * for the link-sharing service curve, the sum of the child service 845 * curve should not exceed the parent service curve. 846 * for the upper-limit service curve, the assigned bandwidth should 847 * be smaller than the interface bandwidth, and the upper-limit should 848 * be larger than the real-time service curve when both are defined. 849 */ 850 parent = qname_to_pfaltq(pa->parent, pa->ifname); 851 if (parent == NULL) 852 errx(1, "parent %s not found for %s", pa->parent, pa->qname); 853 854 TAILQ_FOREACH(altq, &altqs, entries) { 855 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 856 continue; 857 if (altq->qname[0] == 0) /* this is for interface */ 858 continue; 859 860 if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0) 861 continue; 862 863 /* if the class has a link-sharing service curve, add it. */ 864 if (opts->lssc_m2 != 0 && altq->pq_u.fairq_opts.lssc_m2 != 0) { 865 sc.m1 = altq->pq_u.fairq_opts.lssc_m1; 866 sc.d = altq->pq_u.fairq_opts.lssc_d; 867 sc.m2 = altq->pq_u.fairq_opts.lssc_m2; 868 gsc_add_sc(&lssc, &sc); 869 } 870 } 871 872 /* check the link-sharing service curve. */ 873 if (opts->lssc_m2 != 0) { 874 sc.m1 = parent->pq_u.fairq_opts.lssc_m1; 875 sc.d = parent->pq_u.fairq_opts.lssc_d; 876 sc.m2 = parent->pq_u.fairq_opts.lssc_m2; 877 if (!is_gsc_under_sc(&lssc, &sc)) { 878 warnx("link-sharing sc exceeds parent's sc"); 879 goto err_ret; 880 } 881 } 882 883 gsc_destroy(&lssc); 884 885 return (0); 886 887 err_ret: 888 gsc_destroy(&lssc); 889 return (-1); 890 } 891 892 static int 893 check_commit_hfsc(int dev __unused, int opts __unused, struct pf_altq *pa) 894 { 895 struct pf_altq *altq, *def = NULL; 896 int default_class; 897 int error = 0; 898 899 /* check if hfsc has one default queue for this interface */ 900 default_class = 0; 901 TAILQ_FOREACH(altq, &altqs, entries) { 902 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 903 continue; 904 if (altq->qname[0] == 0) /* this is for interface */ 905 continue; 906 if (altq->parent[0] == 0) /* dummy root */ 907 continue; 908 if (altq->pq_u.hfsc_opts.flags & HFCF_DEFAULTCLASS) { 909 default_class++; 910 def = altq; 911 } 912 } 913 if (default_class != 1) { 914 warnx("should have one default queue on %s", pa->ifname); 915 return (1); 916 } 917 /* make sure the default queue is a leaf */ 918 TAILQ_FOREACH(altq, &altqs, entries) { 919 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 920 continue; 921 if (altq->qname[0] == 0) /* this is for interface */ 922 continue; 923 if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) { 924 warnx("default queue is not a leaf"); 925 error++; 926 } 927 } 928 return (error); 929 } 930 931 static int 932 check_commit_fairq(int dev __unused, int opts __unused, struct pf_altq *pa) 933 { 934 struct pf_altq *altq, *def = NULL; 935 int default_class; 936 int error = 0; 937 938 /* check if fairq has one default queue for this interface */ 939 default_class = 0; 940 TAILQ_FOREACH(altq, &altqs, entries) { 941 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 942 continue; 943 if (altq->qname[0] == 0) /* this is for interface */ 944 continue; 945 if (altq->pq_u.fairq_opts.flags & FARF_DEFAULTCLASS) { 946 default_class++; 947 def = altq; 948 } 949 } 950 if (default_class != 1) { 951 warnx("should have one default queue on %s", pa->ifname); 952 return (1); 953 } 954 /* make sure the default queue is a leaf */ 955 TAILQ_FOREACH(altq, &altqs, entries) { 956 if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 957 continue; 958 if (altq->qname[0] == 0) /* this is for interface */ 959 continue; 960 if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) { 961 warnx("default queue is not a leaf"); 962 error++; 963 } 964 } 965 return (error); 966 } 967 968 static int 969 print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) 970 { 971 const struct hfsc_opts *opts; 972 const struct node_hfsc_sc *loc_rtsc, *loc_lssc, *ulsc; 973 974 opts = &a->pq_u.hfsc_opts; 975 if (qopts == NULL) 976 loc_rtsc = loc_lssc = ulsc = NULL; 977 else { 978 loc_rtsc = &qopts->data.hfsc_opts.realtime; 979 loc_lssc = &qopts->data.hfsc_opts.linkshare; 980 ulsc = &qopts->data.hfsc_opts.upperlimit; 981 } 982 983 if (opts->flags || opts->rtsc_m2 != 0 || opts->ulsc_m2 != 0 || 984 (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || 985 opts->lssc_d != 0))) { 986 printf("hfsc("); 987 if (opts->flags & HFCF_RED) 988 printf(" red"); 989 if (opts->flags & HFCF_ECN) 990 printf(" ecn"); 991 if (opts->flags & HFCF_RIO) 992 printf(" rio"); 993 if (opts->flags & HFCF_CLEARDSCP) 994 printf(" cleardscp"); 995 if (opts->flags & HFCF_DEFAULTCLASS) 996 printf(" default"); 997 if (opts->rtsc_m2 != 0) 998 print_hfsc_sc("realtime", opts->rtsc_m1, opts->rtsc_d, 999 opts->rtsc_m2, loc_rtsc); 1000 if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || 1001 opts->lssc_d != 0)) 1002 print_hfsc_sc("linkshare", opts->lssc_m1, opts->lssc_d, 1003 opts->lssc_m2, loc_lssc); 1004 if (opts->ulsc_m2 != 0) 1005 print_hfsc_sc("upperlimit", opts->ulsc_m1, opts->ulsc_d, 1006 opts->ulsc_m2, ulsc); 1007 printf(" ) "); 1008 1009 return (1); 1010 } else 1011 return (0); 1012 } 1013 1014 static int 1015 print_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) 1016 { 1017 const struct fairq_opts *opts; 1018 const struct node_fairq_sc *loc_lssc; 1019 1020 opts = &a->pq_u.fairq_opts; 1021 if (qopts == NULL) 1022 loc_lssc = NULL; 1023 else 1024 loc_lssc = &qopts->data.fairq_opts.linkshare; 1025 1026 if (opts->flags || 1027 (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || 1028 opts->lssc_d != 0))) { 1029 printf("fairq("); 1030 if (opts->flags & FARF_RED) 1031 printf(" red"); 1032 if (opts->flags & FARF_ECN) 1033 printf(" ecn"); 1034 if (opts->flags & FARF_RIO) 1035 printf(" rio"); 1036 if (opts->flags & FARF_CLEARDSCP) 1037 printf(" cleardscp"); 1038 if (opts->flags & FARF_DEFAULTCLASS) 1039 printf(" default"); 1040 if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || 1041 opts->lssc_d != 0)) 1042 print_fairq_sc("linkshare", opts->lssc_m1, opts->lssc_d, 1043 opts->lssc_m2, loc_lssc); 1044 printf(" ) "); 1045 1046 return (1); 1047 } else 1048 return (0); 1049 } 1050 1051 /* 1052 * admission control using generalized service curve 1053 */ 1054 1055 /* add a new service curve to a generalized service curve */ 1056 static void 1057 gsc_add_sc(struct gen_sc *gsc, struct service_curve *sc) 1058 { 1059 if (is_sc_null(sc)) 1060 return; 1061 if (sc->d != 0) 1062 gsc_add_seg(gsc, 0.0, 0.0, (double)sc->d, (double)sc->m1); 1063 gsc_add_seg(gsc, (double)sc->d, 0.0, INFINITY, (double)sc->m2); 1064 } 1065 1066 /* 1067 * check whether all points of a generalized service curve have 1068 * their y-coordinates no larger than a given two-piece linear 1069 * service curve. 1070 */ 1071 static int 1072 is_gsc_under_sc(struct gen_sc *gsc, struct service_curve *sc) 1073 { 1074 struct segment *s, *last, *end; 1075 double y; 1076 1077 if (is_sc_null(sc)) { 1078 if (LIST_EMPTY(gsc)) 1079 return (1); 1080 LIST_FOREACH(s, gsc, _next) { 1081 if (s->m != 0) 1082 return (0); 1083 } 1084 return (1); 1085 } 1086 /* 1087 * gsc has a dummy entry at the end with x = INFINITY. 1088 * loop through up to this dummy entry. 1089 */ 1090 end = gsc_getentry(gsc, INFINITY); 1091 if (end == NULL) 1092 return (1); 1093 last = NULL; 1094 for (s = LIST_FIRST(gsc); s != end; s = LIST_NEXT(s, _next)) { 1095 if (s->y > sc_x2y(sc, s->x)) 1096 return (0); 1097 last = s; 1098 } 1099 /* last now holds the real last segment */ 1100 if (last == NULL) 1101 return (1); 1102 if (last->m > sc->m2) 1103 return (0); 1104 if (last->x < sc->d && last->m > sc->m1) { 1105 y = last->y + (sc->d - last->x) * last->m; 1106 if (y > sc_x2y(sc, sc->d)) 1107 return (0); 1108 } 1109 return (1); 1110 } 1111 1112 static void 1113 gsc_destroy(struct gen_sc *gsc) 1114 { 1115 struct segment *s; 1116 1117 while ((s = LIST_FIRST(gsc)) != NULL) { 1118 LIST_REMOVE(s, _next); 1119 free(s); 1120 } 1121 } 1122 1123 /* 1124 * return a segment entry starting at x. 1125 * if gsc has no entry starting at x, a new entry is created at x. 1126 */ 1127 static struct segment * 1128 gsc_getentry(struct gen_sc *gsc, double x) 1129 { 1130 struct segment *new, *prev, *s; 1131 1132 prev = NULL; 1133 LIST_FOREACH(s, gsc, _next) { 1134 if (s->x == x) 1135 return (s); /* matching entry found */ 1136 else if (s->x < x) 1137 prev = s; 1138 else 1139 break; 1140 } 1141 1142 /* we have to create a new entry */ 1143 if ((new = calloc(1, sizeof(struct segment))) == NULL) 1144 return (NULL); 1145 1146 new->x = x; 1147 if (x == INFINITY || s == NULL) 1148 new->d = 0; 1149 else if (s->x == INFINITY) 1150 new->d = INFINITY; 1151 else 1152 new->d = s->x - x; 1153 if (prev == NULL) { 1154 /* insert the new entry at the head of the list */ 1155 new->y = 0; 1156 new->m = 0; 1157 LIST_INSERT_HEAD(gsc, new, _next); 1158 } else { 1159 /* 1160 * the start point intersects with the segment pointed by 1161 * prev. divide prev into 2 segments 1162 */ 1163 if (x == INFINITY) { 1164 prev->d = INFINITY; 1165 if (prev->m == 0) 1166 new->y = prev->y; 1167 else 1168 new->y = INFINITY; 1169 } else { 1170 prev->d = x - prev->x; 1171 new->y = prev->d * prev->m + prev->y; 1172 } 1173 new->m = prev->m; 1174 LIST_INSERT_AFTER(prev, new, _next); 1175 } 1176 return (new); 1177 } 1178 1179 /* add a segment to a generalized service curve */ 1180 static int 1181 gsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m) 1182 { 1183 struct segment *start, *end, *s; 1184 double x2; 1185 1186 if (d == INFINITY) 1187 x2 = INFINITY; 1188 else 1189 x2 = x + d; 1190 start = gsc_getentry(gsc, x); 1191 end = gsc_getentry(gsc, x2); 1192 if (start == NULL || end == NULL) 1193 return (-1); 1194 1195 for (s = start; s != end; s = LIST_NEXT(s, _next)) { 1196 s->m += m; 1197 s->y += y + (s->x - x) * m; 1198 } 1199 1200 end = gsc_getentry(gsc, INFINITY); 1201 for (; s != end; s = LIST_NEXT(s, _next)) { 1202 s->y += m * d; 1203 } 1204 1205 return (0); 1206 } 1207 1208 /* get y-projection of a service curve */ 1209 static double 1210 sc_x2y(struct service_curve *sc, double x) 1211 { 1212 double y; 1213 1214 if (x <= (double)sc->d) 1215 /* y belongs to the 1st segment */ 1216 y = x * (double)sc->m1; 1217 else 1218 /* y belongs to the 2nd segment */ 1219 y = (double)sc->d * (double)sc->m1 1220 + (x - (double)sc->d) * (double)sc->m2; 1221 return (y); 1222 } 1223 1224 /* 1225 * misc utilities 1226 */ 1227 #define R2S_BUFS 8 1228 #define RATESTR_MAX 16 1229 1230 char * 1231 rate2str(double rate) 1232 { 1233 char *buf; 1234 static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */ 1235 static int idx = 0; 1236 int i; 1237 static const char unit[] = " KMG"; 1238 1239 buf = r2sbuf[idx++]; 1240 if (idx == R2S_BUFS) 1241 idx = 0; 1242 1243 for (i = 0; rate >= 1000 && i <= 3; i++) 1244 rate /= 1000; 1245 1246 if ((int)(rate * 100) % 100) 1247 snprintf(buf, RATESTR_MAX, "%.2f%cb", rate, unit[i]); 1248 else 1249 snprintf(buf, RATESTR_MAX, "%d%cb", (int)rate, unit[i]); 1250 1251 return (buf); 1252 } 1253 1254 u_int32_t 1255 getifspeed(const char *ifname) 1256 { 1257 size_t datalen; 1258 int idx; 1259 struct ifmibdata data; 1260 int name[] = { 1261 CTL_NET, 1262 PF_LINK, 1263 NETLINK_GENERIC, 1264 IFMIB_IFDATA, 1265 0, 1266 IFDATA_GENERAL 1267 }; 1268 1269 if ((idx = (int)if_nametoindex(ifname)) == 0) 1270 err(1, "getifspeed: if_nametoindex"); 1271 name[4] = idx; 1272 1273 datalen = sizeof(data); 1274 if (sysctl(name, 6, &data, &datalen, NULL, 0)) 1275 err(1, "getifspeed: sysctl"); 1276 1277 return(data.ifmd_data.ifi_baudrate); 1278 } 1279 1280 u_long 1281 getifmtu(char *ifname) 1282 { 1283 int s; 1284 struct ifreq ifr; 1285 1286 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 1287 err(1, "socket"); 1288 bzero(&ifr, sizeof(ifr)); 1289 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= 1290 sizeof(ifr.ifr_name)) 1291 errx(1, "getifmtu: strlcpy"); 1292 if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == -1) 1293 err(1, "SIOCGIFMTU"); 1294 if (close(s)) 1295 err(1, "close"); 1296 if (ifr.ifr_mtu > 0) 1297 return (ifr.ifr_mtu); 1298 else { 1299 warnx("could not get mtu for %s, assuming 1500", ifname); 1300 return (1500); 1301 } 1302 } 1303 1304 int 1305 eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts, 1306 u_int32_t ref_bw) 1307 { 1308 int errors = 0; 1309 1310 switch (pa->scheduler) { 1311 case ALTQT_CBQ: 1312 pa->pq_u.cbq_opts = opts->data.cbq_opts; 1313 break; 1314 case ALTQT_PRIQ: 1315 pa->pq_u.priq_opts = opts->data.priq_opts; 1316 break; 1317 case ALTQT_HFSC: 1318 pa->pq_u.hfsc_opts.flags = opts->data.hfsc_opts.flags; 1319 if (opts->data.hfsc_opts.linkshare.used) { 1320 pa->pq_u.hfsc_opts.lssc_m1 = 1321 eval_bwspec(&opts->data.hfsc_opts.linkshare.m1, 1322 ref_bw); 1323 pa->pq_u.hfsc_opts.lssc_m2 = 1324 eval_bwspec(&opts->data.hfsc_opts.linkshare.m2, 1325 ref_bw); 1326 pa->pq_u.hfsc_opts.lssc_d = 1327 opts->data.hfsc_opts.linkshare.d; 1328 } 1329 if (opts->data.hfsc_opts.realtime.used) { 1330 pa->pq_u.hfsc_opts.rtsc_m1 = 1331 eval_bwspec(&opts->data.hfsc_opts.realtime.m1, 1332 ref_bw); 1333 pa->pq_u.hfsc_opts.rtsc_m2 = 1334 eval_bwspec(&opts->data.hfsc_opts.realtime.m2, 1335 ref_bw); 1336 pa->pq_u.hfsc_opts.rtsc_d = 1337 opts->data.hfsc_opts.realtime.d; 1338 } 1339 if (opts->data.hfsc_opts.upperlimit.used) { 1340 pa->pq_u.hfsc_opts.ulsc_m1 = 1341 eval_bwspec(&opts->data.hfsc_opts.upperlimit.m1, 1342 ref_bw); 1343 pa->pq_u.hfsc_opts.ulsc_m2 = 1344 eval_bwspec(&opts->data.hfsc_opts.upperlimit.m2, 1345 ref_bw); 1346 pa->pq_u.hfsc_opts.ulsc_d = 1347 opts->data.hfsc_opts.upperlimit.d; 1348 } 1349 break; 1350 case ALTQT_FAIRQ: 1351 pa->pq_u.fairq_opts.flags = opts->data.fairq_opts.flags; 1352 pa->pq_u.fairq_opts.nbuckets = opts->data.fairq_opts.nbuckets; 1353 pa->pq_u.fairq_opts.hogs_m1 = 1354 eval_bwspec(&opts->data.fairq_opts.hogs_bw, ref_bw); 1355 1356 if (opts->data.fairq_opts.linkshare.used) { 1357 pa->pq_u.fairq_opts.lssc_m1 = 1358 eval_bwspec(&opts->data.fairq_opts.linkshare.m1, 1359 ref_bw); 1360 pa->pq_u.fairq_opts.lssc_m2 = 1361 eval_bwspec(&opts->data.fairq_opts.linkshare.m2, 1362 ref_bw); 1363 pa->pq_u.fairq_opts.lssc_d = 1364 opts->data.fairq_opts.linkshare.d; 1365 } 1366 break; 1367 default: 1368 warnx("eval_queue_opts: unknown scheduler type %u", 1369 opts->qtype); 1370 errors++; 1371 break; 1372 } 1373 1374 return (errors); 1375 } 1376 1377 u_int32_t 1378 eval_bwspec(struct node_queue_bw *bw, u_int32_t ref_bw) 1379 { 1380 if (bw->bw_absolute > 0) 1381 return (bw->bw_absolute); 1382 1383 if (bw->bw_percent > 0) 1384 return (ref_bw / 100 * bw->bw_percent); 1385 1386 return (0); 1387 } 1388 1389 void 1390 print_hfsc_sc(const char *scname, u_int m1, u_int d, u_int m2, 1391 const struct node_hfsc_sc *sc) 1392 { 1393 printf(" %s", scname); 1394 1395 if (d != 0) { 1396 printf("("); 1397 if (sc != NULL && sc->m1.bw_percent > 0) 1398 printf("%u%%", sc->m1.bw_percent); 1399 else 1400 printf("%s", rate2str((double)m1)); 1401 printf(" %u", d); 1402 } 1403 1404 if (sc != NULL && sc->m2.bw_percent > 0) 1405 printf(" %u%%", sc->m2.bw_percent); 1406 else 1407 printf(" %s", rate2str((double)m2)); 1408 1409 if (d != 0) 1410 printf(")"); 1411 } 1412 1413 void 1414 print_fairq_sc(const char *scname, u_int m1, u_int d, u_int m2, 1415 const struct node_fairq_sc *sc) 1416 { 1417 printf(" %s", scname); 1418 1419 if (d != 0) { 1420 printf("("); 1421 if (sc != NULL && sc->m1.bw_percent > 0) 1422 printf("%u%%", sc->m1.bw_percent); 1423 else 1424 printf("%s", rate2str((double)m1)); 1425 printf(" %u", d); 1426 } 1427 1428 if (sc != NULL && sc->m2.bw_percent > 0) 1429 printf(" %u%%", sc->m2.bw_percent); 1430 else 1431 printf(" %s", rate2str((double)m2)); 1432 1433 if (d != 0) 1434 printf(")"); 1435 } 1436 1437