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