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