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