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