1223637Sbz/* $OpenBSD: pfctl_altq.c,v 1.93 2007/10/15 02:16:35 deraadt Exp $ */ 2126353Smlaier 3126353Smlaier/* 4126353Smlaier * Copyright (c) 2002 5126353Smlaier * Sony Computer Science Laboratories Inc. 6126353Smlaier * Copyright (c) 2002, 2003 Henning Brauer <henning@openbsd.org> 7126353Smlaier * 8126353Smlaier * Permission to use, copy, modify, and distribute this software for any 9126353Smlaier * purpose with or without fee is hereby granted, provided that the above 10126353Smlaier * copyright notice and this permission notice appear in all copies. 11126353Smlaier * 12126353Smlaier * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13126353Smlaier * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14126353Smlaier * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15126353Smlaier * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16126353Smlaier * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17126353Smlaier * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18126353Smlaier * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19126353Smlaier */ 20126353Smlaier 21127082Sobrien#include <sys/cdefs.h> 22127082Sobrien__FBSDID("$FreeBSD$"); 23127082Sobrien 24223637Sbz#include <sys/types.h> 25126353Smlaier#include <sys/ioctl.h> 26126353Smlaier#include <sys/socket.h> 27126353Smlaier 28126353Smlaier#include <net/if.h> 29126353Smlaier#include <netinet/in.h> 30126353Smlaier#include <net/pfvar.h> 31126353Smlaier 32126353Smlaier#include <err.h> 33126353Smlaier#include <errno.h> 34127024Smlaier#include <limits.h> 35126353Smlaier#include <math.h> 36126353Smlaier#include <stdio.h> 37126353Smlaier#include <stdlib.h> 38126353Smlaier#include <string.h> 39126353Smlaier#include <unistd.h> 40126353Smlaier 41126353Smlaier#include <altq/altq.h> 42126353Smlaier#include <altq/altq_cbq.h> 43298133Sloos#include <altq/altq_codel.h> 44126353Smlaier#include <altq/altq_priq.h> 45126353Smlaier#include <altq/altq_hfsc.h> 46298115Sloos#include <altq/altq_fairq.h> 47126353Smlaier 48126353Smlaier#include "pfctl_parser.h" 49126353Smlaier#include "pfctl.h" 50126353Smlaier 51126353Smlaier#define is_sc_null(sc) (((sc) == NULL) || ((sc)->m1 == 0 && (sc)->m2 == 0)) 52126353Smlaier 53126353SmlaierTAILQ_HEAD(altqs, pf_altq) altqs = TAILQ_HEAD_INITIALIZER(altqs); 54126353SmlaierLIST_HEAD(gen_sc, segment) rtsc, lssc; 55126353Smlaier 56126353Smlaierstruct pf_altq *qname_to_pfaltq(const char *, const char *); 57126353Smlaieru_int32_t qname_to_qid(const char *); 58126353Smlaier 59126353Smlaierstatic int eval_pfqueue_cbq(struct pfctl *, struct pf_altq *); 60126353Smlaierstatic int cbq_compute_idletime(struct pfctl *, struct pf_altq *); 61126353Smlaierstatic int check_commit_cbq(int, int, struct pf_altq *); 62126353Smlaierstatic int print_cbq_opts(const struct pf_altq *); 63126353Smlaier 64298133Sloosstatic int print_codel_opts(const struct pf_altq *, 65298133Sloos const struct node_queue_opt *); 66298133Sloos 67126353Smlaierstatic int eval_pfqueue_priq(struct pfctl *, struct pf_altq *); 68126353Smlaierstatic int check_commit_priq(int, int, struct pf_altq *); 69126353Smlaierstatic int print_priq_opts(const struct pf_altq *); 70126353Smlaier 71126353Smlaierstatic int eval_pfqueue_hfsc(struct pfctl *, struct pf_altq *); 72126353Smlaierstatic int check_commit_hfsc(int, int, struct pf_altq *); 73126353Smlaierstatic int print_hfsc_opts(const struct pf_altq *, 74126353Smlaier const struct node_queue_opt *); 75126353Smlaier 76298091Sloosstatic int eval_pfqueue_fairq(struct pfctl *, struct pf_altq *); 77298091Sloosstatic int print_fairq_opts(const struct pf_altq *, 78298091Sloos const struct node_queue_opt *); 79298091Sloosstatic int check_commit_fairq(int, int, struct pf_altq *); 80298091Sloos 81126353Smlaierstatic void gsc_add_sc(struct gen_sc *, struct service_curve *); 82126353Smlaierstatic int is_gsc_under_sc(struct gen_sc *, 83126353Smlaier struct service_curve *); 84126353Smlaierstatic void gsc_destroy(struct gen_sc *); 85126353Smlaierstatic struct segment *gsc_getentry(struct gen_sc *, double); 86126353Smlaierstatic int gsc_add_seg(struct gen_sc *, double, double, double, 87126353Smlaier double); 88126353Smlaierstatic double sc_x2y(struct service_curve *, double); 89126353Smlaier 90127024Smlaier#ifdef __FreeBSD__ 91223637Sbzu_int32_t getifspeed(int, char *); 92126355Smlaier#else 93126353Smlaieru_int32_t getifspeed(char *); 94126355Smlaier#endif 95126353Smlaieru_long getifmtu(char *); 96126353Smlaierint eval_queue_opts(struct pf_altq *, struct node_queue_opt *, 97126353Smlaier u_int32_t); 98126353Smlaieru_int32_t eval_bwspec(struct node_queue_bw *, u_int32_t); 99126353Smlaiervoid print_hfsc_sc(const char *, u_int, u_int, u_int, 100126353Smlaier const struct node_hfsc_sc *); 101298091Sloosvoid print_fairq_sc(const char *, u_int, u_int, u_int, 102298091Sloos const struct node_fairq_sc *); 103126353Smlaier 104126353Smlaiervoid 105126353Smlaierpfaltq_store(struct pf_altq *a) 106126353Smlaier{ 107126353Smlaier struct pf_altq *altq; 108126353Smlaier 109126353Smlaier if ((altq = malloc(sizeof(*altq))) == NULL) 110126353Smlaier err(1, "malloc"); 111126353Smlaier memcpy(altq, a, sizeof(struct pf_altq)); 112126353Smlaier TAILQ_INSERT_TAIL(&altqs, altq, entries); 113126353Smlaier} 114126353Smlaier 115126353Smlaierstruct pf_altq * 116126353Smlaierpfaltq_lookup(const char *ifname) 117126353Smlaier{ 118126353Smlaier struct pf_altq *altq; 119126353Smlaier 120126353Smlaier TAILQ_FOREACH(altq, &altqs, entries) { 121126353Smlaier if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 && 122126353Smlaier altq->qname[0] == 0) 123126353Smlaier return (altq); 124126353Smlaier } 125126353Smlaier return (NULL); 126126353Smlaier} 127126353Smlaier 128126353Smlaierstruct pf_altq * 129126353Smlaierqname_to_pfaltq(const char *qname, const char *ifname) 130126353Smlaier{ 131126353Smlaier struct pf_altq *altq; 132126353Smlaier 133126353Smlaier TAILQ_FOREACH(altq, &altqs, entries) { 134126353Smlaier if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 && 135126353Smlaier strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0) 136126353Smlaier return (altq); 137126353Smlaier } 138126353Smlaier return (NULL); 139126353Smlaier} 140126353Smlaier 141126353Smlaieru_int32_t 142126353Smlaierqname_to_qid(const char *qname) 143126353Smlaier{ 144126353Smlaier struct pf_altq *altq; 145126353Smlaier 146126353Smlaier /* 147126353Smlaier * We guarantee that same named queues on different interfaces 148126353Smlaier * have the same qid, so we do NOT need to limit matching on 149126353Smlaier * one interface! 150126353Smlaier */ 151126353Smlaier 152126353Smlaier TAILQ_FOREACH(altq, &altqs, entries) { 153126353Smlaier if (strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0) 154126353Smlaier return (altq->qid); 155126353Smlaier } 156126353Smlaier return (0); 157126353Smlaier} 158126353Smlaier 159126353Smlaiervoid 160223637Sbzprint_altq(const struct pf_altq *a, unsigned int level, 161223637Sbz struct node_queue_bw *bw, struct node_queue_opt *qopts) 162126353Smlaier{ 163130617Smlaier if (a->qname[0] != 0) { 164171172Smlaier print_queue(a, level, bw, 1, qopts); 165126353Smlaier return; 166126353Smlaier } 167126353Smlaier 168177700Smlaier#ifdef __FreeBSD__ 169177700Smlaier if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) 170177700Smlaier printf("INACTIVE "); 171177700Smlaier#endif 172223637Sbz 173126353Smlaier printf("altq on %s ", a->ifname); 174126353Smlaier 175130617Smlaier switch (a->scheduler) { 176126353Smlaier case ALTQT_CBQ: 177126353Smlaier if (!print_cbq_opts(a)) 178126353Smlaier printf("cbq "); 179126353Smlaier break; 180126353Smlaier case ALTQT_PRIQ: 181126353Smlaier if (!print_priq_opts(a)) 182126353Smlaier printf("priq "); 183126353Smlaier break; 184126353Smlaier case ALTQT_HFSC: 185126353Smlaier if (!print_hfsc_opts(a, qopts)) 186126353Smlaier printf("hfsc "); 187126353Smlaier break; 188298091Sloos case ALTQT_FAIRQ: 189298091Sloos if (!print_fairq_opts(a, qopts)) 190298091Sloos printf("fairq "); 191298091Sloos break; 192298133Sloos case ALTQT_CODEL: 193298133Sloos if (!print_codel_opts(a, qopts)) 194298133Sloos printf("codel "); 195298133Sloos break; 196126353Smlaier } 197126353Smlaier 198126353Smlaier if (bw != NULL && bw->bw_percent > 0) { 199126353Smlaier if (bw->bw_percent < 100) 200126353Smlaier printf("bandwidth %u%% ", bw->bw_percent); 201126353Smlaier } else 202126353Smlaier printf("bandwidth %s ", rate2str((double)a->ifbandwidth)); 203126353Smlaier 204126353Smlaier if (a->qlimit != DEFAULT_QLIMIT) 205126353Smlaier printf("qlimit %u ", a->qlimit); 206126353Smlaier printf("tbrsize %u ", a->tbrsize); 207126353Smlaier} 208126353Smlaier 209126353Smlaiervoid 210223637Sbzprint_queue(const struct pf_altq *a, unsigned int level, 211223637Sbz struct node_queue_bw *bw, int print_interface, 212223637Sbz struct node_queue_opt *qopts) 213126353Smlaier{ 214223637Sbz unsigned int i; 215126353Smlaier 216177700Smlaier#ifdef __FreeBSD__ 217177700Smlaier if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) 218177700Smlaier printf("INACTIVE "); 219177700Smlaier#endif 220126353Smlaier printf("queue "); 221126353Smlaier for (i = 0; i < level; ++i) 222126353Smlaier printf(" "); 223126353Smlaier printf("%s ", a->qname); 224126353Smlaier if (print_interface) 225126353Smlaier printf("on %s ", a->ifname); 226298091Sloos if (a->scheduler == ALTQT_CBQ || a->scheduler == ALTQT_HFSC || 227298091Sloos a->scheduler == ALTQT_FAIRQ) { 228126353Smlaier if (bw != NULL && bw->bw_percent > 0) { 229126353Smlaier if (bw->bw_percent < 100) 230126353Smlaier printf("bandwidth %u%% ", bw->bw_percent); 231126353Smlaier } else 232126353Smlaier printf("bandwidth %s ", rate2str((double)a->bandwidth)); 233126353Smlaier } 234126353Smlaier if (a->priority != DEFAULT_PRIORITY) 235126353Smlaier printf("priority %u ", a->priority); 236126353Smlaier if (a->qlimit != DEFAULT_QLIMIT) 237126353Smlaier printf("qlimit %u ", a->qlimit); 238126353Smlaier switch (a->scheduler) { 239126353Smlaier case ALTQT_CBQ: 240126353Smlaier print_cbq_opts(a); 241126353Smlaier break; 242126353Smlaier case ALTQT_PRIQ: 243126353Smlaier print_priq_opts(a); 244126353Smlaier break; 245126353Smlaier case ALTQT_HFSC: 246126353Smlaier print_hfsc_opts(a, qopts); 247126353Smlaier break; 248298091Sloos case ALTQT_FAIRQ: 249298091Sloos print_fairq_opts(a, qopts); 250298091Sloos break; 251126353Smlaier } 252126353Smlaier} 253126353Smlaier 254126353Smlaier/* 255126353Smlaier * eval_pfaltq computes the discipline parameters. 256126353Smlaier */ 257126353Smlaierint 258126353Smlaiereval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw, 259126353Smlaier struct node_queue_opt *opts) 260126353Smlaier{ 261126353Smlaier u_int rate, size, errors = 0; 262126353Smlaier 263126353Smlaier if (bw->bw_absolute > 0) 264126353Smlaier pa->ifbandwidth = bw->bw_absolute; 265126353Smlaier else 266127024Smlaier#ifdef __FreeBSD__ 267126355Smlaier if ((rate = getifspeed(pf->dev, pa->ifname)) == 0) { 268126355Smlaier#else 269126353Smlaier if ((rate = getifspeed(pa->ifname)) == 0) { 270126355Smlaier#endif 271171172Smlaier fprintf(stderr, "interface %s does not know its bandwidth, " 272171172Smlaier "please specify an absolute bandwidth\n", 273126353Smlaier pa->ifname); 274126353Smlaier errors++; 275126353Smlaier } else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0) 276126353Smlaier pa->ifbandwidth = rate; 277126353Smlaier 278126353Smlaier errors += eval_queue_opts(pa, opts, pa->ifbandwidth); 279126353Smlaier 280126353Smlaier /* if tbrsize is not specified, use heuristics */ 281126353Smlaier if (pa->tbrsize == 0) { 282126353Smlaier rate = pa->ifbandwidth; 283126353Smlaier if (rate <= 1 * 1000 * 1000) 284126353Smlaier size = 1; 285126353Smlaier else if (rate <= 10 * 1000 * 1000) 286126353Smlaier size = 4; 287126353Smlaier else if (rate <= 200 * 1000 * 1000) 288126353Smlaier size = 8; 289126353Smlaier else 290126353Smlaier size = 24; 291126353Smlaier size = size * getifmtu(pa->ifname); 292130617Smlaier if (size > 0xffff) 293130617Smlaier size = 0xffff; 294126353Smlaier pa->tbrsize = size; 295126353Smlaier } 296126353Smlaier return (errors); 297126353Smlaier} 298126353Smlaier 299126353Smlaier/* 300126353Smlaier * check_commit_altq does consistency check for each interface 301126353Smlaier */ 302126353Smlaierint 303126353Smlaiercheck_commit_altq(int dev, int opts) 304126353Smlaier{ 305126353Smlaier struct pf_altq *altq; 306126353Smlaier int error = 0; 307126353Smlaier 308126353Smlaier /* call the discipline check for each interface. */ 309126353Smlaier TAILQ_FOREACH(altq, &altqs, entries) { 310126353Smlaier if (altq->qname[0] == 0) { 311126353Smlaier switch (altq->scheduler) { 312126353Smlaier case ALTQT_CBQ: 313126353Smlaier error = check_commit_cbq(dev, opts, altq); 314126353Smlaier break; 315126353Smlaier case ALTQT_PRIQ: 316126353Smlaier error = check_commit_priq(dev, opts, altq); 317126353Smlaier break; 318126353Smlaier case ALTQT_HFSC: 319126353Smlaier error = check_commit_hfsc(dev, opts, altq); 320126353Smlaier break; 321298091Sloos case ALTQT_FAIRQ: 322298091Sloos error = check_commit_fairq(dev, opts, altq); 323298091Sloos break; 324126353Smlaier default: 325126353Smlaier break; 326126353Smlaier } 327126353Smlaier } 328126353Smlaier } 329126353Smlaier return (error); 330126353Smlaier} 331126353Smlaier 332126353Smlaier/* 333126353Smlaier * eval_pfqueue computes the queue parameters. 334126353Smlaier */ 335126353Smlaierint 336126353Smlaiereval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw, 337126353Smlaier struct node_queue_opt *opts) 338126353Smlaier{ 339126353Smlaier /* should be merged with expand_queue */ 340145840Smlaier struct pf_altq *if_pa, *parent, *altq; 341145840Smlaier u_int32_t bwsum; 342126353Smlaier int error = 0; 343126353Smlaier 344126353Smlaier /* find the corresponding interface and copy fields used by queues */ 345126353Smlaier if ((if_pa = pfaltq_lookup(pa->ifname)) == NULL) { 346126353Smlaier fprintf(stderr, "altq not defined on %s\n", pa->ifname); 347126353Smlaier return (1); 348126353Smlaier } 349126353Smlaier pa->scheduler = if_pa->scheduler; 350126353Smlaier pa->ifbandwidth = if_pa->ifbandwidth; 351126353Smlaier 352126353Smlaier if (qname_to_pfaltq(pa->qname, pa->ifname) != NULL) { 353126353Smlaier fprintf(stderr, "queue %s already exists on interface %s\n", 354126353Smlaier pa->qname, pa->ifname); 355126353Smlaier return (1); 356126353Smlaier } 357126353Smlaier pa->qid = qname_to_qid(pa->qname); 358126353Smlaier 359126353Smlaier parent = NULL; 360126353Smlaier if (pa->parent[0] != 0) { 361126353Smlaier parent = qname_to_pfaltq(pa->parent, pa->ifname); 362126353Smlaier if (parent == NULL) { 363126353Smlaier fprintf(stderr, "parent %s not found for %s\n", 364126353Smlaier pa->parent, pa->qname); 365126353Smlaier return (1); 366126353Smlaier } 367126353Smlaier pa->parent_qid = parent->qid; 368126353Smlaier } 369126353Smlaier if (pa->qlimit == 0) 370126353Smlaier pa->qlimit = DEFAULT_QLIMIT; 371126353Smlaier 372298091Sloos if (pa->scheduler == ALTQT_CBQ || pa->scheduler == ALTQT_HFSC || 373298091Sloos pa->scheduler == ALTQT_FAIRQ) { 374145840Smlaier pa->bandwidth = eval_bwspec(bw, 375145840Smlaier parent == NULL ? 0 : parent->bandwidth); 376126353Smlaier 377126353Smlaier if (pa->bandwidth > pa->ifbandwidth) { 378126353Smlaier fprintf(stderr, "bandwidth for %s higher than " 379126353Smlaier "interface\n", pa->qname); 380126353Smlaier return (1); 381126353Smlaier } 382145840Smlaier /* check the sum of the child bandwidth is under parent's */ 383145840Smlaier if (parent != NULL) { 384145840Smlaier if (pa->bandwidth > parent->bandwidth) { 385145840Smlaier warnx("bandwidth for %s higher than parent", 386145840Smlaier pa->qname); 387145840Smlaier return (1); 388145840Smlaier } 389145840Smlaier bwsum = 0; 390145840Smlaier TAILQ_FOREACH(altq, &altqs, entries) { 391145840Smlaier if (strncmp(altq->ifname, pa->ifname, 392145840Smlaier IFNAMSIZ) == 0 && 393145840Smlaier altq->qname[0] != 0 && 394145840Smlaier strncmp(altq->parent, pa->parent, 395145840Smlaier PF_QNAME_SIZE) == 0) 396145840Smlaier bwsum += altq->bandwidth; 397145840Smlaier } 398145840Smlaier bwsum += pa->bandwidth; 399145840Smlaier if (bwsum > parent->bandwidth) { 400145840Smlaier warnx("the sum of the child bandwidth higher" 401145840Smlaier " than parent \"%s\"", parent->qname); 402145840Smlaier } 403126353Smlaier } 404126353Smlaier } 405126353Smlaier 406126353Smlaier if (eval_queue_opts(pa, opts, parent == NULL? 0 : parent->bandwidth)) 407126353Smlaier return (1); 408126353Smlaier 409126353Smlaier switch (pa->scheduler) { 410126353Smlaier case ALTQT_CBQ: 411126353Smlaier error = eval_pfqueue_cbq(pf, pa); 412126353Smlaier break; 413126353Smlaier case ALTQT_PRIQ: 414126353Smlaier error = eval_pfqueue_priq(pf, pa); 415126353Smlaier break; 416126353Smlaier case ALTQT_HFSC: 417126353Smlaier error = eval_pfqueue_hfsc(pf, pa); 418126353Smlaier break; 419298091Sloos case ALTQT_FAIRQ: 420298091Sloos error = eval_pfqueue_fairq(pf, pa); 421298091Sloos break; 422126353Smlaier default: 423126353Smlaier break; 424126353Smlaier } 425126353Smlaier return (error); 426126353Smlaier} 427126353Smlaier 428126353Smlaier/* 429126353Smlaier * CBQ support functions 430126353Smlaier */ 431126353Smlaier#define RM_FILTER_GAIN 5 /* log2 of gain, e.g., 5 => 31/32 */ 432126353Smlaier#define RM_NS_PER_SEC (1000000000) 433126353Smlaier 434126353Smlaierstatic int 435126353Smlaiereval_pfqueue_cbq(struct pfctl *pf, struct pf_altq *pa) 436126353Smlaier{ 437126353Smlaier struct cbq_opts *opts; 438126353Smlaier u_int ifmtu; 439126353Smlaier 440126353Smlaier if (pa->priority >= CBQ_MAXPRI) { 441126353Smlaier warnx("priority out of range: max %d", CBQ_MAXPRI - 1); 442126353Smlaier return (-1); 443126353Smlaier } 444126353Smlaier 445126353Smlaier ifmtu = getifmtu(pa->ifname); 446126353Smlaier opts = &pa->pq_u.cbq_opts; 447126353Smlaier 448126353Smlaier if (opts->pktsize == 0) { /* use default */ 449126353Smlaier opts->pktsize = ifmtu; 450126353Smlaier if (opts->pktsize > MCLBYTES) /* do what TCP does */ 451126353Smlaier opts->pktsize &= ~MCLBYTES; 452126353Smlaier } else if (opts->pktsize > ifmtu) 453126353Smlaier opts->pktsize = ifmtu; 454126353Smlaier if (opts->maxpktsize == 0) /* use default */ 455126353Smlaier opts->maxpktsize = ifmtu; 456126353Smlaier else if (opts->maxpktsize > ifmtu) 457126353Smlaier opts->pktsize = ifmtu; 458126353Smlaier 459126353Smlaier if (opts->pktsize > opts->maxpktsize) 460126353Smlaier opts->pktsize = opts->maxpktsize; 461126353Smlaier 462126353Smlaier if (pa->parent[0] == 0) 463126353Smlaier opts->flags |= (CBQCLF_ROOTCLASS | CBQCLF_WRR); 464126353Smlaier 465126353Smlaier cbq_compute_idletime(pf, pa); 466126353Smlaier return (0); 467126353Smlaier} 468126353Smlaier 469126353Smlaier/* 470126353Smlaier * compute ns_per_byte, maxidle, minidle, and offtime 471126353Smlaier */ 472126353Smlaierstatic int 473126353Smlaiercbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa) 474126353Smlaier{ 475126353Smlaier struct cbq_opts *opts; 476126353Smlaier double maxidle_s, maxidle, minidle; 477126353Smlaier double offtime, nsPerByte, ifnsPerByte, ptime, cptime; 478126353Smlaier double z, g, f, gton, gtom; 479126353Smlaier u_int minburst, maxburst; 480126353Smlaier 481126353Smlaier opts = &pa->pq_u.cbq_opts; 482126353Smlaier ifnsPerByte = (1.0 / (double)pa->ifbandwidth) * RM_NS_PER_SEC * 8; 483126353Smlaier minburst = opts->minburst; 484126353Smlaier maxburst = opts->maxburst; 485126353Smlaier 486126353Smlaier if (pa->bandwidth == 0) 487126353Smlaier f = 0.0001; /* small enough? */ 488126353Smlaier else 489126353Smlaier f = ((double) pa->bandwidth / (double) pa->ifbandwidth); 490126353Smlaier 491126353Smlaier nsPerByte = ifnsPerByte / f; 492126353Smlaier ptime = (double)opts->pktsize * ifnsPerByte; 493126353Smlaier cptime = ptime * (1.0 - f) / f; 494126353Smlaier 495126353Smlaier if (nsPerByte * (double)opts->maxpktsize > (double)INT_MAX) { 496126353Smlaier /* 497126353Smlaier * this causes integer overflow in kernel! 498126353Smlaier * (bandwidth < 6Kbps when max_pkt_size=1500) 499126353Smlaier */ 500126353Smlaier if (pa->bandwidth != 0 && (pf->opts & PF_OPT_QUIET) == 0) 501126353Smlaier warnx("queue bandwidth must be larger than %s", 502126353Smlaier rate2str(ifnsPerByte * (double)opts->maxpktsize / 503126353Smlaier (double)INT_MAX * (double)pa->ifbandwidth)); 504126353Smlaier fprintf(stderr, "cbq: queue %s is too slow!\n", 505126353Smlaier pa->qname); 506126353Smlaier nsPerByte = (double)(INT_MAX / opts->maxpktsize); 507126353Smlaier } 508126353Smlaier 509126353Smlaier if (maxburst == 0) { /* use default */ 510126353Smlaier if (cptime > 10.0 * 1000000) 511126353Smlaier maxburst = 4; 512126353Smlaier else 513126353Smlaier maxburst = 16; 514126353Smlaier } 515126353Smlaier if (minburst == 0) /* use default */ 516126353Smlaier minburst = 2; 517126353Smlaier if (minburst > maxburst) 518126353Smlaier minburst = maxburst; 519126353Smlaier 520126353Smlaier z = (double)(1 << RM_FILTER_GAIN); 521126353Smlaier g = (1.0 - 1.0 / z); 522126353Smlaier gton = pow(g, (double)maxburst); 523126353Smlaier gtom = pow(g, (double)(minburst-1)); 524126353Smlaier maxidle = ((1.0 / f - 1.0) * ((1.0 - gton) / gton)); 525126353Smlaier maxidle_s = (1.0 - g); 526126353Smlaier if (maxidle > maxidle_s) 527126353Smlaier maxidle = ptime * maxidle; 528126353Smlaier else 529126353Smlaier maxidle = ptime * maxidle_s; 530171172Smlaier offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom); 531126353Smlaier minidle = -((double)opts->maxpktsize * (double)nsPerByte); 532126353Smlaier 533126353Smlaier /* scale parameters */ 534130617Smlaier maxidle = ((maxidle * 8.0) / nsPerByte) * 535130617Smlaier pow(2.0, (double)RM_FILTER_GAIN); 536130617Smlaier offtime = (offtime * 8.0) / nsPerByte * 537130617Smlaier pow(2.0, (double)RM_FILTER_GAIN); 538130617Smlaier minidle = ((minidle * 8.0) / nsPerByte) * 539130617Smlaier pow(2.0, (double)RM_FILTER_GAIN); 540126353Smlaier 541126353Smlaier maxidle = maxidle / 1000.0; 542126353Smlaier offtime = offtime / 1000.0; 543126353Smlaier minidle = minidle / 1000.0; 544126353Smlaier 545126353Smlaier opts->minburst = minburst; 546126353Smlaier opts->maxburst = maxburst; 547130617Smlaier opts->ns_per_byte = (u_int)nsPerByte; 548130617Smlaier opts->maxidle = (u_int)fabs(maxidle); 549126353Smlaier opts->minidle = (int)minidle; 550130617Smlaier opts->offtime = (u_int)fabs(offtime); 551126353Smlaier 552126353Smlaier return (0); 553126353Smlaier} 554126353Smlaier 555126353Smlaierstatic int 556126353Smlaiercheck_commit_cbq(int dev, int opts, struct pf_altq *pa) 557126353Smlaier{ 558126353Smlaier struct pf_altq *altq; 559126353Smlaier int root_class, default_class; 560126353Smlaier int error = 0; 561126353Smlaier 562126353Smlaier /* 563126353Smlaier * check if cbq has one root queue and one default queue 564126353Smlaier * for this interface 565126353Smlaier */ 566126353Smlaier root_class = default_class = 0; 567126353Smlaier TAILQ_FOREACH(altq, &altqs, entries) { 568126353Smlaier if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 569126353Smlaier continue; 570126353Smlaier if (altq->qname[0] == 0) /* this is for interface */ 571126353Smlaier continue; 572126353Smlaier if (altq->pq_u.cbq_opts.flags & CBQCLF_ROOTCLASS) 573126353Smlaier root_class++; 574126353Smlaier if (altq->pq_u.cbq_opts.flags & CBQCLF_DEFCLASS) 575126353Smlaier default_class++; 576126353Smlaier } 577126353Smlaier if (root_class != 1) { 578126353Smlaier warnx("should have one root queue on %s", pa->ifname); 579126353Smlaier error++; 580126353Smlaier } 581126353Smlaier if (default_class != 1) { 582126353Smlaier warnx("should have one default queue on %s", pa->ifname); 583126353Smlaier error++; 584126353Smlaier } 585126353Smlaier return (error); 586126353Smlaier} 587126353Smlaier 588126353Smlaierstatic int 589126353Smlaierprint_cbq_opts(const struct pf_altq *a) 590126353Smlaier{ 591126353Smlaier const struct cbq_opts *opts; 592126353Smlaier 593126353Smlaier opts = &a->pq_u.cbq_opts; 594126353Smlaier if (opts->flags) { 595126353Smlaier printf("cbq("); 596126353Smlaier if (opts->flags & CBQCLF_RED) 597126353Smlaier printf(" red"); 598126353Smlaier if (opts->flags & CBQCLF_ECN) 599126353Smlaier printf(" ecn"); 600126353Smlaier if (opts->flags & CBQCLF_RIO) 601126353Smlaier printf(" rio"); 602298133Sloos if (opts->flags & CBQCLF_CODEL) 603298133Sloos printf(" codel"); 604126353Smlaier if (opts->flags & CBQCLF_CLEARDSCP) 605126353Smlaier printf(" cleardscp"); 606126353Smlaier if (opts->flags & CBQCLF_FLOWVALVE) 607126353Smlaier printf(" flowvalve"); 608126353Smlaier if (opts->flags & CBQCLF_BORROW) 609126353Smlaier printf(" borrow"); 610126353Smlaier if (opts->flags & CBQCLF_WRR) 611126353Smlaier printf(" wrr"); 612126353Smlaier if (opts->flags & CBQCLF_EFFICIENT) 613126353Smlaier printf(" efficient"); 614126353Smlaier if (opts->flags & CBQCLF_ROOTCLASS) 615126353Smlaier printf(" root"); 616126353Smlaier if (opts->flags & CBQCLF_DEFCLASS) 617126353Smlaier printf(" default"); 618126353Smlaier printf(" ) "); 619126353Smlaier 620126353Smlaier return (1); 621126353Smlaier } else 622126353Smlaier return (0); 623126353Smlaier} 624126353Smlaier 625126353Smlaier/* 626126353Smlaier * PRIQ support functions 627126353Smlaier */ 628126353Smlaierstatic int 629126353Smlaiereval_pfqueue_priq(struct pfctl *pf, struct pf_altq *pa) 630126353Smlaier{ 631126353Smlaier struct pf_altq *altq; 632126353Smlaier 633126353Smlaier if (pa->priority >= PRIQ_MAXPRI) { 634126353Smlaier warnx("priority out of range: max %d", PRIQ_MAXPRI - 1); 635126353Smlaier return (-1); 636126353Smlaier } 637126353Smlaier /* the priority should be unique for the interface */ 638126353Smlaier TAILQ_FOREACH(altq, &altqs, entries) { 639126353Smlaier if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) == 0 && 640126353Smlaier altq->qname[0] != 0 && altq->priority == pa->priority) { 641126353Smlaier warnx("%s and %s have the same priority", 642126353Smlaier altq->qname, pa->qname); 643126353Smlaier return (-1); 644126353Smlaier } 645126353Smlaier } 646126353Smlaier 647126353Smlaier return (0); 648126353Smlaier} 649126353Smlaier 650126353Smlaierstatic int 651126353Smlaiercheck_commit_priq(int dev, int opts, struct pf_altq *pa) 652126353Smlaier{ 653126353Smlaier struct pf_altq *altq; 654126353Smlaier int default_class; 655126353Smlaier int error = 0; 656126353Smlaier 657126353Smlaier /* 658126353Smlaier * check if priq has one default class for this interface 659126353Smlaier */ 660126353Smlaier default_class = 0; 661126353Smlaier TAILQ_FOREACH(altq, &altqs, entries) { 662126353Smlaier if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 663126353Smlaier continue; 664126353Smlaier if (altq->qname[0] == 0) /* this is for interface */ 665126353Smlaier continue; 666126353Smlaier if (altq->pq_u.priq_opts.flags & PRCF_DEFAULTCLASS) 667126353Smlaier default_class++; 668126353Smlaier } 669126353Smlaier if (default_class != 1) { 670126353Smlaier warnx("should have one default queue on %s", pa->ifname); 671126353Smlaier error++; 672126353Smlaier } 673126353Smlaier return (error); 674126353Smlaier} 675126353Smlaier 676126353Smlaierstatic int 677126353Smlaierprint_priq_opts(const struct pf_altq *a) 678126353Smlaier{ 679126353Smlaier const struct priq_opts *opts; 680126353Smlaier 681126353Smlaier opts = &a->pq_u.priq_opts; 682126353Smlaier 683126353Smlaier if (opts->flags) { 684126353Smlaier printf("priq("); 685126353Smlaier if (opts->flags & PRCF_RED) 686126353Smlaier printf(" red"); 687126353Smlaier if (opts->flags & PRCF_ECN) 688126353Smlaier printf(" ecn"); 689126353Smlaier if (opts->flags & PRCF_RIO) 690126353Smlaier printf(" rio"); 691298133Sloos if (opts->flags & PRCF_CODEL) 692298133Sloos printf(" codel"); 693126353Smlaier if (opts->flags & PRCF_CLEARDSCP) 694126353Smlaier printf(" cleardscp"); 695126353Smlaier if (opts->flags & PRCF_DEFAULTCLASS) 696126353Smlaier printf(" default"); 697126353Smlaier printf(" ) "); 698126353Smlaier 699126353Smlaier return (1); 700126353Smlaier } else 701126353Smlaier return (0); 702126353Smlaier} 703126353Smlaier 704126353Smlaier/* 705126353Smlaier * HFSC support functions 706126353Smlaier */ 707126353Smlaierstatic int 708126353Smlaiereval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa) 709126353Smlaier{ 710126353Smlaier struct pf_altq *altq, *parent; 711126353Smlaier struct hfsc_opts *opts; 712126353Smlaier struct service_curve sc; 713126353Smlaier 714126353Smlaier opts = &pa->pq_u.hfsc_opts; 715126353Smlaier 716126353Smlaier if (pa->parent[0] == 0) { 717126353Smlaier /* root queue */ 718126353Smlaier opts->lssc_m1 = pa->ifbandwidth; 719126353Smlaier opts->lssc_m2 = pa->ifbandwidth; 720126353Smlaier opts->lssc_d = 0; 721126353Smlaier return (0); 722130617Smlaier } 723126353Smlaier 724126353Smlaier LIST_INIT(&rtsc); 725126353Smlaier LIST_INIT(&lssc); 726126353Smlaier 727126353Smlaier /* if link_share is not specified, use bandwidth */ 728126353Smlaier if (opts->lssc_m2 == 0) 729126353Smlaier opts->lssc_m2 = pa->bandwidth; 730126353Smlaier 731126353Smlaier if ((opts->rtsc_m1 > 0 && opts->rtsc_m2 == 0) || 732126353Smlaier (opts->lssc_m1 > 0 && opts->lssc_m2 == 0) || 733126353Smlaier (opts->ulsc_m1 > 0 && opts->ulsc_m2 == 0)) { 734126353Smlaier warnx("m2 is zero for %s", pa->qname); 735126353Smlaier return (-1); 736126353Smlaier } 737126353Smlaier 738126353Smlaier if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) || 739164775Smlaier (opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) || 740164775Smlaier (opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) { 741126353Smlaier warnx("m1 must be zero for convex curve: %s", pa->qname); 742126353Smlaier return (-1); 743126353Smlaier } 744126353Smlaier 745126353Smlaier /* 746126353Smlaier * admission control: 747126353Smlaier * for the real-time service curve, the sum of the service curves 748126353Smlaier * should not exceed 80% of the interface bandwidth. 20% is reserved 749126353Smlaier * not to over-commit the actual interface bandwidth. 750145840Smlaier * for the linkshare service curve, the sum of the child service 751126353Smlaier * curve should not exceed the parent service curve. 752126353Smlaier * for the upper-limit service curve, the assigned bandwidth should 753126353Smlaier * be smaller than the interface bandwidth, and the upper-limit should 754126353Smlaier * be larger than the real-time service curve when both are defined. 755126353Smlaier */ 756126353Smlaier parent = qname_to_pfaltq(pa->parent, pa->ifname); 757126353Smlaier if (parent == NULL) 758126353Smlaier errx(1, "parent %s not found for %s", pa->parent, pa->qname); 759126353Smlaier 760126353Smlaier TAILQ_FOREACH(altq, &altqs, entries) { 761126353Smlaier if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 762126353Smlaier continue; 763126353Smlaier if (altq->qname[0] == 0) /* this is for interface */ 764126353Smlaier continue; 765126353Smlaier 766126353Smlaier /* if the class has a real-time service curve, add it. */ 767126353Smlaier if (opts->rtsc_m2 != 0 && altq->pq_u.hfsc_opts.rtsc_m2 != 0) { 768126353Smlaier sc.m1 = altq->pq_u.hfsc_opts.rtsc_m1; 769130617Smlaier sc.d = altq->pq_u.hfsc_opts.rtsc_d; 770126353Smlaier sc.m2 = altq->pq_u.hfsc_opts.rtsc_m2; 771126353Smlaier gsc_add_sc(&rtsc, &sc); 772126353Smlaier } 773126353Smlaier 774126353Smlaier if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0) 775126353Smlaier continue; 776126353Smlaier 777145840Smlaier /* if the class has a linkshare service curve, add it. */ 778126353Smlaier if (opts->lssc_m2 != 0 && altq->pq_u.hfsc_opts.lssc_m2 != 0) { 779126353Smlaier sc.m1 = altq->pq_u.hfsc_opts.lssc_m1; 780130617Smlaier sc.d = altq->pq_u.hfsc_opts.lssc_d; 781126353Smlaier sc.m2 = altq->pq_u.hfsc_opts.lssc_m2; 782126353Smlaier gsc_add_sc(&lssc, &sc); 783126353Smlaier } 784126353Smlaier } 785126353Smlaier 786126353Smlaier /* check the real-time service curve. reserve 20% of interface bw */ 787126353Smlaier if (opts->rtsc_m2 != 0) { 788145840Smlaier /* add this queue to the sum */ 789145840Smlaier sc.m1 = opts->rtsc_m1; 790145840Smlaier sc.d = opts->rtsc_d; 791145840Smlaier sc.m2 = opts->rtsc_m2; 792145840Smlaier gsc_add_sc(&rtsc, &sc); 793145840Smlaier /* compare the sum with 80% of the interface */ 794126353Smlaier sc.m1 = 0; 795130617Smlaier sc.d = 0; 796126353Smlaier sc.m2 = pa->ifbandwidth / 100 * 80; 797126353Smlaier if (!is_gsc_under_sc(&rtsc, &sc)) { 798145840Smlaier warnx("real-time sc exceeds 80%% of the interface " 799145840Smlaier "bandwidth (%s)", rate2str((double)sc.m2)); 800126353Smlaier goto err_ret; 801126353Smlaier } 802126353Smlaier } 803126353Smlaier 804145840Smlaier /* check the linkshare service curve. */ 805126353Smlaier if (opts->lssc_m2 != 0) { 806145840Smlaier /* add this queue to the child sum */ 807145840Smlaier sc.m1 = opts->lssc_m1; 808145840Smlaier sc.d = opts->lssc_d; 809145840Smlaier sc.m2 = opts->lssc_m2; 810145840Smlaier gsc_add_sc(&lssc, &sc); 811145840Smlaier /* compare the sum of the children with parent's sc */ 812126353Smlaier sc.m1 = parent->pq_u.hfsc_opts.lssc_m1; 813130617Smlaier sc.d = parent->pq_u.hfsc_opts.lssc_d; 814126353Smlaier sc.m2 = parent->pq_u.hfsc_opts.lssc_m2; 815126353Smlaier if (!is_gsc_under_sc(&lssc, &sc)) { 816145840Smlaier warnx("linkshare sc exceeds parent's sc"); 817126353Smlaier goto err_ret; 818126353Smlaier } 819126353Smlaier } 820126353Smlaier 821126353Smlaier /* check the upper-limit service curve. */ 822126353Smlaier if (opts->ulsc_m2 != 0) { 823126353Smlaier if (opts->ulsc_m1 > pa->ifbandwidth || 824126353Smlaier opts->ulsc_m2 > pa->ifbandwidth) { 825126353Smlaier warnx("upper-limit larger than interface bandwidth"); 826126353Smlaier goto err_ret; 827126353Smlaier } 828126353Smlaier if (opts->rtsc_m2 != 0 && opts->rtsc_m2 > opts->ulsc_m2) { 829126353Smlaier warnx("upper-limit sc smaller than real-time sc"); 830126353Smlaier goto err_ret; 831126353Smlaier } 832126353Smlaier } 833126353Smlaier 834126353Smlaier gsc_destroy(&rtsc); 835126353Smlaier gsc_destroy(&lssc); 836126353Smlaier 837126353Smlaier return (0); 838126353Smlaier 839126353Smlaiererr_ret: 840126353Smlaier gsc_destroy(&rtsc); 841126353Smlaier gsc_destroy(&lssc); 842126353Smlaier return (-1); 843126353Smlaier} 844126353Smlaier 845298091Sloos/* 846298091Sloos * FAIRQ support functions 847298091Sloos */ 848126353Smlaierstatic int 849298091Slooseval_pfqueue_fairq(struct pfctl *pf __unused, struct pf_altq *pa) 850298091Sloos{ 851298091Sloos struct pf_altq *altq, *parent; 852298091Sloos struct fairq_opts *opts; 853298091Sloos struct service_curve sc; 854298091Sloos 855298091Sloos opts = &pa->pq_u.fairq_opts; 856298091Sloos 857298091Sloos if (pa->parent[0] == 0) { 858298091Sloos /* root queue */ 859298091Sloos opts->lssc_m1 = pa->ifbandwidth; 860298091Sloos opts->lssc_m2 = pa->ifbandwidth; 861298091Sloos opts->lssc_d = 0; 862298091Sloos return (0); 863298091Sloos } 864298091Sloos 865298091Sloos LIST_INIT(&lssc); 866298091Sloos 867298091Sloos /* if link_share is not specified, use bandwidth */ 868298091Sloos if (opts->lssc_m2 == 0) 869298091Sloos opts->lssc_m2 = pa->bandwidth; 870298091Sloos 871298091Sloos /* 872298091Sloos * admission control: 873298091Sloos * for the real-time service curve, the sum of the service curves 874298091Sloos * should not exceed 80% of the interface bandwidth. 20% is reserved 875298091Sloos * not to over-commit the actual interface bandwidth. 876298091Sloos * for the link-sharing service curve, the sum of the child service 877298091Sloos * curve should not exceed the parent service curve. 878298091Sloos * for the upper-limit service curve, the assigned bandwidth should 879298091Sloos * be smaller than the interface bandwidth, and the upper-limit should 880298091Sloos * be larger than the real-time service curve when both are defined. 881298091Sloos */ 882298091Sloos parent = qname_to_pfaltq(pa->parent, pa->ifname); 883298091Sloos if (parent == NULL) 884298091Sloos errx(1, "parent %s not found for %s", pa->parent, pa->qname); 885298091Sloos 886298091Sloos TAILQ_FOREACH(altq, &altqs, entries) { 887298091Sloos if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 888298091Sloos continue; 889298091Sloos if (altq->qname[0] == 0) /* this is for interface */ 890298091Sloos continue; 891298091Sloos 892298091Sloos if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0) 893298091Sloos continue; 894298091Sloos 895298091Sloos /* if the class has a link-sharing service curve, add it. */ 896298091Sloos if (opts->lssc_m2 != 0 && altq->pq_u.fairq_opts.lssc_m2 != 0) { 897298091Sloos sc.m1 = altq->pq_u.fairq_opts.lssc_m1; 898298091Sloos sc.d = altq->pq_u.fairq_opts.lssc_d; 899298091Sloos sc.m2 = altq->pq_u.fairq_opts.lssc_m2; 900298091Sloos gsc_add_sc(&lssc, &sc); 901298091Sloos } 902298091Sloos } 903298091Sloos 904298091Sloos /* check the link-sharing service curve. */ 905298091Sloos if (opts->lssc_m2 != 0) { 906298091Sloos sc.m1 = parent->pq_u.fairq_opts.lssc_m1; 907298091Sloos sc.d = parent->pq_u.fairq_opts.lssc_d; 908298091Sloos sc.m2 = parent->pq_u.fairq_opts.lssc_m2; 909298091Sloos if (!is_gsc_under_sc(&lssc, &sc)) { 910298091Sloos warnx("link-sharing sc exceeds parent's sc"); 911298091Sloos goto err_ret; 912298091Sloos } 913298091Sloos } 914298091Sloos 915298091Sloos gsc_destroy(&lssc); 916298091Sloos 917298091Sloos return (0); 918298091Sloos 919298091Slooserr_ret: 920298091Sloos gsc_destroy(&lssc); 921298091Sloos return (-1); 922298091Sloos} 923298091Sloos 924298091Sloosstatic int 925126353Smlaiercheck_commit_hfsc(int dev, int opts, struct pf_altq *pa) 926126353Smlaier{ 927126353Smlaier struct pf_altq *altq, *def = NULL; 928126353Smlaier int default_class; 929126353Smlaier int error = 0; 930126353Smlaier 931126353Smlaier /* check if hfsc has one default queue for this interface */ 932126353Smlaier default_class = 0; 933126353Smlaier TAILQ_FOREACH(altq, &altqs, entries) { 934126353Smlaier if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 935126353Smlaier continue; 936126353Smlaier if (altq->qname[0] == 0) /* this is for interface */ 937126353Smlaier continue; 938126353Smlaier if (altq->parent[0] == 0) /* dummy root */ 939126353Smlaier continue; 940126353Smlaier if (altq->pq_u.hfsc_opts.flags & HFCF_DEFAULTCLASS) { 941126353Smlaier default_class++; 942126353Smlaier def = altq; 943126353Smlaier } 944126353Smlaier } 945126353Smlaier if (default_class != 1) { 946126353Smlaier warnx("should have one default queue on %s", pa->ifname); 947126353Smlaier return (1); 948126353Smlaier } 949126353Smlaier /* make sure the default queue is a leaf */ 950126353Smlaier TAILQ_FOREACH(altq, &altqs, entries) { 951126353Smlaier if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 952126353Smlaier continue; 953126353Smlaier if (altq->qname[0] == 0) /* this is for interface */ 954126353Smlaier continue; 955126353Smlaier if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) { 956126353Smlaier warnx("default queue is not a leaf"); 957126353Smlaier error++; 958126353Smlaier } 959126353Smlaier } 960126353Smlaier return (error); 961126353Smlaier} 962126353Smlaier 963126353Smlaierstatic int 964298091Slooscheck_commit_fairq(int dev __unused, int opts __unused, struct pf_altq *pa) 965298091Sloos{ 966298091Sloos struct pf_altq *altq, *def = NULL; 967298091Sloos int default_class; 968298091Sloos int error = 0; 969298091Sloos 970298091Sloos /* check if fairq has one default queue for this interface */ 971298091Sloos default_class = 0; 972298091Sloos TAILQ_FOREACH(altq, &altqs, entries) { 973298091Sloos if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 974298091Sloos continue; 975298091Sloos if (altq->qname[0] == 0) /* this is for interface */ 976298091Sloos continue; 977298091Sloos if (altq->pq_u.fairq_opts.flags & FARF_DEFAULTCLASS) { 978298091Sloos default_class++; 979298091Sloos def = altq; 980298091Sloos } 981298091Sloos } 982298091Sloos if (default_class != 1) { 983298091Sloos warnx("should have one default queue on %s", pa->ifname); 984298091Sloos return (1); 985298091Sloos } 986298091Sloos /* make sure the default queue is a leaf */ 987298091Sloos TAILQ_FOREACH(altq, &altqs, entries) { 988298091Sloos if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) 989298091Sloos continue; 990298091Sloos if (altq->qname[0] == 0) /* this is for interface */ 991298091Sloos continue; 992298091Sloos if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) { 993298091Sloos warnx("default queue is not a leaf"); 994298091Sloos error++; 995298091Sloos } 996298091Sloos } 997298091Sloos return (error); 998298091Sloos} 999298091Sloos 1000298091Sloosstatic int 1001126353Smlaierprint_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) 1002126353Smlaier{ 1003126353Smlaier const struct hfsc_opts *opts; 1004126353Smlaier const struct node_hfsc_sc *rtsc, *lssc, *ulsc; 1005126353Smlaier 1006126353Smlaier opts = &a->pq_u.hfsc_opts; 1007126353Smlaier if (qopts == NULL) 1008126353Smlaier rtsc = lssc = ulsc = NULL; 1009126353Smlaier else { 1010126353Smlaier rtsc = &qopts->data.hfsc_opts.realtime; 1011126353Smlaier lssc = &qopts->data.hfsc_opts.linkshare; 1012126353Smlaier ulsc = &qopts->data.hfsc_opts.upperlimit; 1013126353Smlaier } 1014126353Smlaier 1015126353Smlaier if (opts->flags || opts->rtsc_m2 != 0 || opts->ulsc_m2 != 0 || 1016126353Smlaier (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || 1017126353Smlaier opts->lssc_d != 0))) { 1018126353Smlaier printf("hfsc("); 1019126353Smlaier if (opts->flags & HFCF_RED) 1020126353Smlaier printf(" red"); 1021126353Smlaier if (opts->flags & HFCF_ECN) 1022126353Smlaier printf(" ecn"); 1023126353Smlaier if (opts->flags & HFCF_RIO) 1024126353Smlaier printf(" rio"); 1025298133Sloos if (opts->flags & HFCF_CODEL) 1026298133Sloos printf(" codel"); 1027126353Smlaier if (opts->flags & HFCF_CLEARDSCP) 1028126353Smlaier printf(" cleardscp"); 1029126353Smlaier if (opts->flags & HFCF_DEFAULTCLASS) 1030126353Smlaier printf(" default"); 1031126353Smlaier if (opts->rtsc_m2 != 0) 1032126353Smlaier print_hfsc_sc("realtime", opts->rtsc_m1, opts->rtsc_d, 1033126353Smlaier opts->rtsc_m2, rtsc); 1034126353Smlaier if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || 1035126353Smlaier opts->lssc_d != 0)) 1036126353Smlaier print_hfsc_sc("linkshare", opts->lssc_m1, opts->lssc_d, 1037126353Smlaier opts->lssc_m2, lssc); 1038126353Smlaier if (opts->ulsc_m2 != 0) 1039126353Smlaier print_hfsc_sc("upperlimit", opts->ulsc_m1, opts->ulsc_d, 1040126353Smlaier opts->ulsc_m2, ulsc); 1041126353Smlaier printf(" ) "); 1042126353Smlaier 1043126353Smlaier return (1); 1044126353Smlaier } else 1045126353Smlaier return (0); 1046126353Smlaier} 1047126353Smlaier 1048298091Sloosstatic int 1049298133Sloosprint_codel_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) 1050298133Sloos{ 1051298133Sloos const struct codel_opts *opts; 1052298133Sloos 1053298133Sloos opts = &a->pq_u.codel_opts; 1054298133Sloos if (opts->target || opts->interval || opts->ecn) { 1055298133Sloos printf("codel("); 1056298133Sloos if (opts->target) 1057298133Sloos printf(" target %d", opts->target); 1058298133Sloos if (opts->interval) 1059298133Sloos printf(" interval %d", opts->interval); 1060298133Sloos if (opts->ecn) 1061298133Sloos printf("ecn"); 1062298133Sloos printf(" ) "); 1063298133Sloos 1064298133Sloos return (1); 1065298133Sloos } 1066298133Sloos 1067298133Sloos return (0); 1068298133Sloos} 1069298133Sloos 1070298133Sloosstatic int 1071298091Sloosprint_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) 1072298091Sloos{ 1073298091Sloos const struct fairq_opts *opts; 1074298091Sloos const struct node_fairq_sc *loc_lssc; 1075298091Sloos 1076298091Sloos opts = &a->pq_u.fairq_opts; 1077298091Sloos if (qopts == NULL) 1078298091Sloos loc_lssc = NULL; 1079298091Sloos else 1080298091Sloos loc_lssc = &qopts->data.fairq_opts.linkshare; 1081298091Sloos 1082298091Sloos if (opts->flags || 1083298091Sloos (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || 1084298091Sloos opts->lssc_d != 0))) { 1085298091Sloos printf("fairq("); 1086298091Sloos if (opts->flags & FARF_RED) 1087298091Sloos printf(" red"); 1088298091Sloos if (opts->flags & FARF_ECN) 1089298091Sloos printf(" ecn"); 1090298091Sloos if (opts->flags & FARF_RIO) 1091298091Sloos printf(" rio"); 1092298133Sloos if (opts->flags & FARF_CODEL) 1093298133Sloos printf(" codel"); 1094298091Sloos if (opts->flags & FARF_CLEARDSCP) 1095298091Sloos printf(" cleardscp"); 1096298091Sloos if (opts->flags & FARF_DEFAULTCLASS) 1097298091Sloos printf(" default"); 1098298091Sloos if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || 1099298091Sloos opts->lssc_d != 0)) 1100298091Sloos print_fairq_sc("linkshare", opts->lssc_m1, opts->lssc_d, 1101298091Sloos opts->lssc_m2, loc_lssc); 1102298091Sloos printf(" ) "); 1103298091Sloos 1104298091Sloos return (1); 1105298091Sloos } else 1106298091Sloos return (0); 1107298091Sloos} 1108298091Sloos 1109126353Smlaier/* 1110126353Smlaier * admission control using generalized service curve 1111126353Smlaier */ 1112126353Smlaier 1113126353Smlaier/* add a new service curve to a generalized service curve */ 1114126353Smlaierstatic void 1115126353Smlaiergsc_add_sc(struct gen_sc *gsc, struct service_curve *sc) 1116126353Smlaier{ 1117126353Smlaier if (is_sc_null(sc)) 1118126353Smlaier return; 1119126353Smlaier if (sc->d != 0) 1120126353Smlaier gsc_add_seg(gsc, 0.0, 0.0, (double)sc->d, (double)sc->m1); 1121126353Smlaier gsc_add_seg(gsc, (double)sc->d, 0.0, INFINITY, (double)sc->m2); 1122126353Smlaier} 1123126353Smlaier 1124126353Smlaier/* 1125126353Smlaier * check whether all points of a generalized service curve have 1126126353Smlaier * their y-coordinates no larger than a given two-piece linear 1127126353Smlaier * service curve. 1128126353Smlaier */ 1129126353Smlaierstatic int 1130126353Smlaieris_gsc_under_sc(struct gen_sc *gsc, struct service_curve *sc) 1131126353Smlaier{ 1132126353Smlaier struct segment *s, *last, *end; 1133126353Smlaier double y; 1134126353Smlaier 1135126353Smlaier if (is_sc_null(sc)) { 1136126353Smlaier if (LIST_EMPTY(gsc)) 1137126353Smlaier return (1); 1138126353Smlaier LIST_FOREACH(s, gsc, _next) { 1139126353Smlaier if (s->m != 0) 1140126353Smlaier return (0); 1141126353Smlaier } 1142126353Smlaier return (1); 1143126353Smlaier } 1144126353Smlaier /* 1145126353Smlaier * gsc has a dummy entry at the end with x = INFINITY. 1146126353Smlaier * loop through up to this dummy entry. 1147126353Smlaier */ 1148126353Smlaier end = gsc_getentry(gsc, INFINITY); 1149126353Smlaier if (end == NULL) 1150126353Smlaier return (1); 1151126353Smlaier last = NULL; 1152126353Smlaier for (s = LIST_FIRST(gsc); s != end; s = LIST_NEXT(s, _next)) { 1153126353Smlaier if (s->y > sc_x2y(sc, s->x)) 1154126353Smlaier return (0); 1155126353Smlaier last = s; 1156126353Smlaier } 1157126353Smlaier /* last now holds the real last segment */ 1158126353Smlaier if (last == NULL) 1159126353Smlaier return (1); 1160126353Smlaier if (last->m > sc->m2) 1161126353Smlaier return (0); 1162126353Smlaier if (last->x < sc->d && last->m > sc->m1) { 1163126353Smlaier y = last->y + (sc->d - last->x) * last->m; 1164126353Smlaier if (y > sc_x2y(sc, sc->d)) 1165126353Smlaier return (0); 1166126353Smlaier } 1167126353Smlaier return (1); 1168126353Smlaier} 1169126353Smlaier 1170126353Smlaierstatic void 1171126353Smlaiergsc_destroy(struct gen_sc *gsc) 1172126353Smlaier{ 1173126353Smlaier struct segment *s; 1174126353Smlaier 1175126353Smlaier while ((s = LIST_FIRST(gsc)) != NULL) { 1176126353Smlaier LIST_REMOVE(s, _next); 1177126353Smlaier free(s); 1178126353Smlaier } 1179126353Smlaier} 1180126353Smlaier 1181126353Smlaier/* 1182126353Smlaier * return a segment entry starting at x. 1183126353Smlaier * if gsc has no entry starting at x, a new entry is created at x. 1184126353Smlaier */ 1185126353Smlaierstatic struct segment * 1186126353Smlaiergsc_getentry(struct gen_sc *gsc, double x) 1187126353Smlaier{ 1188126353Smlaier struct segment *new, *prev, *s; 1189126353Smlaier 1190126353Smlaier prev = NULL; 1191126353Smlaier LIST_FOREACH(s, gsc, _next) { 1192126353Smlaier if (s->x == x) 1193126353Smlaier return (s); /* matching entry found */ 1194126353Smlaier else if (s->x < x) 1195126353Smlaier prev = s; 1196126353Smlaier else 1197126353Smlaier break; 1198126353Smlaier } 1199126353Smlaier 1200126353Smlaier /* we have to create a new entry */ 1201126353Smlaier if ((new = calloc(1, sizeof(struct segment))) == NULL) 1202126353Smlaier return (NULL); 1203126353Smlaier 1204126353Smlaier new->x = x; 1205126353Smlaier if (x == INFINITY || s == NULL) 1206126353Smlaier new->d = 0; 1207126353Smlaier else if (s->x == INFINITY) 1208126353Smlaier new->d = INFINITY; 1209126353Smlaier else 1210126353Smlaier new->d = s->x - x; 1211126353Smlaier if (prev == NULL) { 1212126353Smlaier /* insert the new entry at the head of the list */ 1213126353Smlaier new->y = 0; 1214126353Smlaier new->m = 0; 1215126353Smlaier LIST_INSERT_HEAD(gsc, new, _next); 1216126353Smlaier } else { 1217126353Smlaier /* 1218126353Smlaier * the start point intersects with the segment pointed by 1219126353Smlaier * prev. divide prev into 2 segments 1220126353Smlaier */ 1221126353Smlaier if (x == INFINITY) { 1222126353Smlaier prev->d = INFINITY; 1223126353Smlaier if (prev->m == 0) 1224126353Smlaier new->y = prev->y; 1225126353Smlaier else 1226126353Smlaier new->y = INFINITY; 1227126353Smlaier } else { 1228126353Smlaier prev->d = x - prev->x; 1229126353Smlaier new->y = prev->d * prev->m + prev->y; 1230126353Smlaier } 1231126353Smlaier new->m = prev->m; 1232126353Smlaier LIST_INSERT_AFTER(prev, new, _next); 1233126353Smlaier } 1234126353Smlaier return (new); 1235126353Smlaier} 1236126353Smlaier 1237126353Smlaier/* add a segment to a generalized service curve */ 1238126353Smlaierstatic int 1239126353Smlaiergsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m) 1240126353Smlaier{ 1241126353Smlaier struct segment *start, *end, *s; 1242126353Smlaier double x2; 1243126353Smlaier 1244126353Smlaier if (d == INFINITY) 1245126353Smlaier x2 = INFINITY; 1246126353Smlaier else 1247126353Smlaier x2 = x + d; 1248126353Smlaier start = gsc_getentry(gsc, x); 1249130617Smlaier end = gsc_getentry(gsc, x2); 1250126353Smlaier if (start == NULL || end == NULL) 1251126353Smlaier return (-1); 1252126353Smlaier 1253126353Smlaier for (s = start; s != end; s = LIST_NEXT(s, _next)) { 1254126353Smlaier s->m += m; 1255126353Smlaier s->y += y + (s->x - x) * m; 1256126353Smlaier } 1257126353Smlaier 1258126353Smlaier end = gsc_getentry(gsc, INFINITY); 1259126353Smlaier for (; s != end; s = LIST_NEXT(s, _next)) { 1260126353Smlaier s->y += m * d; 1261126353Smlaier } 1262126353Smlaier 1263126353Smlaier return (0); 1264126353Smlaier} 1265126353Smlaier 1266126353Smlaier/* get y-projection of a service curve */ 1267126353Smlaierstatic double 1268126353Smlaiersc_x2y(struct service_curve *sc, double x) 1269126353Smlaier{ 1270126353Smlaier double y; 1271126353Smlaier 1272126353Smlaier if (x <= (double)sc->d) 1273126353Smlaier /* y belongs to the 1st segment */ 1274126353Smlaier y = x * (double)sc->m1; 1275126353Smlaier else 1276126353Smlaier /* y belongs to the 2nd segment */ 1277126353Smlaier y = (double)sc->d * (double)sc->m1 1278126353Smlaier + (x - (double)sc->d) * (double)sc->m2; 1279126353Smlaier return (y); 1280126353Smlaier} 1281126353Smlaier 1282126353Smlaier/* 1283126353Smlaier * misc utilities 1284126353Smlaier */ 1285126353Smlaier#define R2S_BUFS 8 1286126353Smlaier#define RATESTR_MAX 16 1287126353Smlaier 1288126353Smlaierchar * 1289126353Smlaierrate2str(double rate) 1290126353Smlaier{ 1291126353Smlaier char *buf; 1292126353Smlaier static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */ 1293126353Smlaier static int idx = 0; 1294126353Smlaier int i; 1295126353Smlaier static const char unit[] = " KMG"; 1296126353Smlaier 1297126353Smlaier buf = r2sbuf[idx++]; 1298126353Smlaier if (idx == R2S_BUFS) 1299126353Smlaier idx = 0; 1300126353Smlaier 1301126353Smlaier for (i = 0; rate >= 1000 && i <= 3; i++) 1302126353Smlaier rate /= 1000; 1303126353Smlaier 1304126353Smlaier if ((int)(rate * 100) % 100) 1305126353Smlaier snprintf(buf, RATESTR_MAX, "%.2f%cb", rate, unit[i]); 1306126353Smlaier else 1307126353Smlaier snprintf(buf, RATESTR_MAX, "%d%cb", (int)rate, unit[i]); 1308126353Smlaier 1309126353Smlaier return (buf); 1310126353Smlaier} 1311126353Smlaier 1312127024Smlaier#ifdef __FreeBSD__ 1313126355Smlaier/* 1314126355Smlaier * XXX 1315127024Smlaier * FreeBSD does not have SIOCGIFDATA. 1316126355Smlaier * To emulate this, DIOCGIFSPEED ioctl added to pf. 1317126355Smlaier */ 1318126353Smlaieru_int32_t 1319126355Smlaiergetifspeed(int pfdev, char *ifname) 1320126355Smlaier{ 1321126355Smlaier struct pf_ifspeed io; 1322126355Smlaier 1323126355Smlaier bzero(&io, sizeof io); 1324126355Smlaier if (strlcpy(io.ifname, ifname, IFNAMSIZ) >= 1325126355Smlaier sizeof(io.ifname)) 1326126355Smlaier errx(1, "getifspeed: strlcpy"); 1327126355Smlaier if (ioctl(pfdev, DIOCGIFSPEED, &io) == -1) 1328126355Smlaier err(1, "DIOCGIFSPEED"); 1329126355Smlaier return ((u_int32_t)io.baudrate); 1330126355Smlaier} 1331126355Smlaier#else 1332126355Smlaieru_int32_t 1333126353Smlaiergetifspeed(char *ifname) 1334126353Smlaier{ 1335126353Smlaier int s; 1336126353Smlaier struct ifreq ifr; 1337126353Smlaier struct if_data ifrdat; 1338126353Smlaier 1339270047Sbz if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0) 1340126353Smlaier err(1, "socket"); 1341145840Smlaier bzero(&ifr, sizeof(ifr)); 1342126353Smlaier if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= 1343126353Smlaier sizeof(ifr.ifr_name)) 1344126353Smlaier errx(1, "getifspeed: strlcpy"); 1345126353Smlaier ifr.ifr_data = (caddr_t)&ifrdat; 1346126353Smlaier if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1) 1347126353Smlaier err(1, "SIOCGIFDATA"); 1348126353Smlaier if (close(s)) 1349126353Smlaier err(1, "close"); 1350126353Smlaier return ((u_int32_t)ifrdat.ifi_baudrate); 1351126353Smlaier} 1352126355Smlaier#endif 1353126353Smlaier 1354126353Smlaieru_long 1355126353Smlaiergetifmtu(char *ifname) 1356126353Smlaier{ 1357126353Smlaier int s; 1358126353Smlaier struct ifreq ifr; 1359126353Smlaier 1360270047Sbz if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0) 1361126353Smlaier err(1, "socket"); 1362145840Smlaier bzero(&ifr, sizeof(ifr)); 1363126353Smlaier if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= 1364126353Smlaier sizeof(ifr.ifr_name)) 1365126353Smlaier errx(1, "getifmtu: strlcpy"); 1366126353Smlaier if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == -1) 1367177700Smlaier#ifdef __FreeBSD__ 1368177700Smlaier ifr.ifr_mtu = 1500; 1369177700Smlaier#else 1370126353Smlaier err(1, "SIOCGIFMTU"); 1371177700Smlaier#endif 1372126353Smlaier if (close(s)) 1373126353Smlaier err(1, "close"); 1374126353Smlaier if (ifr.ifr_mtu > 0) 1375126353Smlaier return (ifr.ifr_mtu); 1376126353Smlaier else { 1377126353Smlaier warnx("could not get mtu for %s, assuming 1500", ifname); 1378126353Smlaier return (1500); 1379126353Smlaier } 1380126353Smlaier} 1381126353Smlaier 1382126353Smlaierint 1383126353Smlaiereval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts, 1384126353Smlaier u_int32_t ref_bw) 1385126353Smlaier{ 1386126353Smlaier int errors = 0; 1387126353Smlaier 1388126353Smlaier switch (pa->scheduler) { 1389126353Smlaier case ALTQT_CBQ: 1390126353Smlaier pa->pq_u.cbq_opts = opts->data.cbq_opts; 1391126353Smlaier break; 1392126353Smlaier case ALTQT_PRIQ: 1393126353Smlaier pa->pq_u.priq_opts = opts->data.priq_opts; 1394126353Smlaier break; 1395126353Smlaier case ALTQT_HFSC: 1396126353Smlaier pa->pq_u.hfsc_opts.flags = opts->data.hfsc_opts.flags; 1397126353Smlaier if (opts->data.hfsc_opts.linkshare.used) { 1398126353Smlaier pa->pq_u.hfsc_opts.lssc_m1 = 1399126353Smlaier eval_bwspec(&opts->data.hfsc_opts.linkshare.m1, 1400126353Smlaier ref_bw); 1401126353Smlaier pa->pq_u.hfsc_opts.lssc_m2 = 1402126353Smlaier eval_bwspec(&opts->data.hfsc_opts.linkshare.m2, 1403126353Smlaier ref_bw); 1404126353Smlaier pa->pq_u.hfsc_opts.lssc_d = 1405126353Smlaier opts->data.hfsc_opts.linkshare.d; 1406126353Smlaier } 1407126353Smlaier if (opts->data.hfsc_opts.realtime.used) { 1408126353Smlaier pa->pq_u.hfsc_opts.rtsc_m1 = 1409126353Smlaier eval_bwspec(&opts->data.hfsc_opts.realtime.m1, 1410126353Smlaier ref_bw); 1411126353Smlaier pa->pq_u.hfsc_opts.rtsc_m2 = 1412126353Smlaier eval_bwspec(&opts->data.hfsc_opts.realtime.m2, 1413126353Smlaier ref_bw); 1414126353Smlaier pa->pq_u.hfsc_opts.rtsc_d = 1415126353Smlaier opts->data.hfsc_opts.realtime.d; 1416126353Smlaier } 1417126353Smlaier if (opts->data.hfsc_opts.upperlimit.used) { 1418126353Smlaier pa->pq_u.hfsc_opts.ulsc_m1 = 1419126353Smlaier eval_bwspec(&opts->data.hfsc_opts.upperlimit.m1, 1420126353Smlaier ref_bw); 1421126353Smlaier pa->pq_u.hfsc_opts.ulsc_m2 = 1422126353Smlaier eval_bwspec(&opts->data.hfsc_opts.upperlimit.m2, 1423126353Smlaier ref_bw); 1424126353Smlaier pa->pq_u.hfsc_opts.ulsc_d = 1425126353Smlaier opts->data.hfsc_opts.upperlimit.d; 1426126353Smlaier } 1427126353Smlaier break; 1428298091Sloos case ALTQT_FAIRQ: 1429298091Sloos pa->pq_u.fairq_opts.flags = opts->data.fairq_opts.flags; 1430298091Sloos pa->pq_u.fairq_opts.nbuckets = opts->data.fairq_opts.nbuckets; 1431298091Sloos pa->pq_u.fairq_opts.hogs_m1 = 1432298091Sloos eval_bwspec(&opts->data.fairq_opts.hogs_bw, ref_bw); 1433298091Sloos 1434298091Sloos if (opts->data.fairq_opts.linkshare.used) { 1435298091Sloos pa->pq_u.fairq_opts.lssc_m1 = 1436298091Sloos eval_bwspec(&opts->data.fairq_opts.linkshare.m1, 1437298091Sloos ref_bw); 1438298091Sloos pa->pq_u.fairq_opts.lssc_m2 = 1439298091Sloos eval_bwspec(&opts->data.fairq_opts.linkshare.m2, 1440298091Sloos ref_bw); 1441298091Sloos pa->pq_u.fairq_opts.lssc_d = 1442298091Sloos opts->data.fairq_opts.linkshare.d; 1443298091Sloos } 1444298091Sloos break; 1445298133Sloos case ALTQT_CODEL: 1446298133Sloos pa->pq_u.codel_opts.target = opts->data.codel_opts.target; 1447298133Sloos pa->pq_u.codel_opts.interval = opts->data.codel_opts.interval; 1448298133Sloos pa->pq_u.codel_opts.ecn = opts->data.codel_opts.ecn; 1449298133Sloos break; 1450126353Smlaier default: 1451126353Smlaier warnx("eval_queue_opts: unknown scheduler type %u", 1452126353Smlaier opts->qtype); 1453126353Smlaier errors++; 1454126353Smlaier break; 1455126353Smlaier } 1456126353Smlaier 1457126353Smlaier return (errors); 1458126353Smlaier} 1459126353Smlaier 1460126353Smlaieru_int32_t 1461126353Smlaiereval_bwspec(struct node_queue_bw *bw, u_int32_t ref_bw) 1462126353Smlaier{ 1463126353Smlaier if (bw->bw_absolute > 0) 1464126353Smlaier return (bw->bw_absolute); 1465126353Smlaier 1466126353Smlaier if (bw->bw_percent > 0) 1467126353Smlaier return (ref_bw / 100 * bw->bw_percent); 1468126353Smlaier 1469126353Smlaier return (0); 1470126353Smlaier} 1471126353Smlaier 1472126353Smlaiervoid 1473126353Smlaierprint_hfsc_sc(const char *scname, u_int m1, u_int d, u_int m2, 1474126353Smlaier const struct node_hfsc_sc *sc) 1475126353Smlaier{ 1476126353Smlaier printf(" %s", scname); 1477126353Smlaier 1478126353Smlaier if (d != 0) { 1479126353Smlaier printf("("); 1480126353Smlaier if (sc != NULL && sc->m1.bw_percent > 0) 1481126353Smlaier printf("%u%%", sc->m1.bw_percent); 1482126353Smlaier else 1483126353Smlaier printf("%s", rate2str((double)m1)); 1484126353Smlaier printf(" %u", d); 1485126353Smlaier } 1486126353Smlaier 1487126353Smlaier if (sc != NULL && sc->m2.bw_percent > 0) 1488126353Smlaier printf(" %u%%", sc->m2.bw_percent); 1489126353Smlaier else 1490126353Smlaier printf(" %s", rate2str((double)m2)); 1491126353Smlaier 1492126353Smlaier if (d != 0) 1493126353Smlaier printf(")"); 1494126353Smlaier} 1495298091Sloos 1496298091Sloosvoid 1497298091Sloosprint_fairq_sc(const char *scname, u_int m1, u_int d, u_int m2, 1498298091Sloos const struct node_fairq_sc *sc) 1499298091Sloos{ 1500298091Sloos printf(" %s", scname); 1501298091Sloos 1502298091Sloos if (d != 0) { 1503298091Sloos printf("("); 1504298091Sloos if (sc != NULL && sc->m1.bw_percent > 0) 1505298091Sloos printf("%u%%", sc->m1.bw_percent); 1506298091Sloos else 1507298091Sloos printf("%s", rate2str((double)m1)); 1508298091Sloos printf(" %u", d); 1509298091Sloos } 1510298091Sloos 1511298091Sloos if (sc != NULL && sc->m2.bw_percent > 0) 1512298091Sloos printf(" %u%%", sc->m2.bw_percent); 1513298091Sloos else 1514298091Sloos printf(" %s", rate2str((double)m2)); 1515298091Sloos 1516298091Sloos if (d != 0) 1517298091Sloos printf(")"); 1518298091Sloos} 1519