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