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: stable/11/sbin/pfctl/pfctl_altq.c 360674 2020-05-05 20:56:41Z dim $");
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
41281613Sglebius#include <net/altq/altq.h>
42281613Sglebius#include <net/altq/altq_cbq.h>
43287009Sloos#include <net/altq/altq_codel.h>
44281613Sglebius#include <net/altq/altq_priq.h>
45281613Sglebius#include <net/altq/altq_hfsc.h>
46284777Seri#include <net/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
64287009Sloosstatic int	print_codel_opts(const struct pf_altq *,
65287009Sloos		    const struct node_queue_opt *);
66287009Sloos
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
76284777Seristatic int	eval_pfqueue_fairq(struct pfctl *, struct pf_altq *);
77284777Seristatic int	print_fairq_opts(const struct pf_altq *,
78284777Seri		    const struct node_queue_opt *);
79284777Seristatic int	check_commit_fairq(int, int, struct pf_altq *);
80284777Seri
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 *);
101284777Serivoid		 print_fairq_sc(const char *, u_int, u_int, u_int,
102284777Seri		     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;
188284777Seri	case ALTQT_FAIRQ:
189284777Seri		if (!print_fairq_opts(a, qopts))
190284777Seri			printf("fairq ");
191284777Seri		break;
192287009Sloos	case ALTQT_CODEL:
193287009Sloos		if (!print_codel_opts(a, qopts))
194287009Sloos			printf("codel ");
195287009Sloos		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);
226284777Seri	if (a->scheduler == ALTQT_CBQ || a->scheduler == ALTQT_HFSC ||
227284777Seri		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;
248284777Seri	case ALTQT_FAIRQ:
249284777Seri		print_fairq_opts(a, qopts);
250284777Seri		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;
321284777Seri			case ALTQT_FAIRQ:
322284777Seri				error = check_commit_fairq(dev, opts, altq);
323284777Seri				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
372284777Seri	if (pa->scheduler == ALTQT_CBQ || pa->scheduler == ALTQT_HFSC ||
373284777Seri		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;
419284777Seri	case ALTQT_FAIRQ:
420284777Seri		error = eval_pfqueue_fairq(pf, pa);
421284777Seri		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		 */
500360674Sdim		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);
506360674Sdim		}
507126353Smlaier		nsPerByte = (double)(INT_MAX / opts->maxpktsize);
508126353Smlaier	}
509126353Smlaier
510126353Smlaier	if (maxburst == 0) {  /* use default */
511126353Smlaier		if (cptime > 10.0 * 1000000)
512126353Smlaier			maxburst = 4;
513126353Smlaier		else
514126353Smlaier			maxburst = 16;
515126353Smlaier	}
516126353Smlaier	if (minburst == 0)  /* use default */
517126353Smlaier		minburst = 2;
518126353Smlaier	if (minburst > maxburst)
519126353Smlaier		minburst = maxburst;
520126353Smlaier
521126353Smlaier	z = (double)(1 << RM_FILTER_GAIN);
522126353Smlaier	g = (1.0 - 1.0 / z);
523126353Smlaier	gton = pow(g, (double)maxburst);
524126353Smlaier	gtom = pow(g, (double)(minburst-1));
525126353Smlaier	maxidle = ((1.0 / f - 1.0) * ((1.0 - gton) / gton));
526126353Smlaier	maxidle_s = (1.0 - g);
527126353Smlaier	if (maxidle > maxidle_s)
528126353Smlaier		maxidle = ptime * maxidle;
529126353Smlaier	else
530126353Smlaier		maxidle = ptime * maxidle_s;
531171172Smlaier	offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom);
532126353Smlaier	minidle = -((double)opts->maxpktsize * (double)nsPerByte);
533126353Smlaier
534126353Smlaier	/* scale parameters */
535130617Smlaier	maxidle = ((maxidle * 8.0) / nsPerByte) *
536130617Smlaier	    pow(2.0, (double)RM_FILTER_GAIN);
537130617Smlaier	offtime = (offtime * 8.0) / nsPerByte *
538130617Smlaier	    pow(2.0, (double)RM_FILTER_GAIN);
539130617Smlaier	minidle = ((minidle * 8.0) / nsPerByte) *
540130617Smlaier	    pow(2.0, (double)RM_FILTER_GAIN);
541126353Smlaier
542126353Smlaier	maxidle = maxidle / 1000.0;
543126353Smlaier	offtime = offtime / 1000.0;
544126353Smlaier	minidle = minidle / 1000.0;
545126353Smlaier
546126353Smlaier	opts->minburst = minburst;
547126353Smlaier	opts->maxburst = maxburst;
548130617Smlaier	opts->ns_per_byte = (u_int)nsPerByte;
549130617Smlaier	opts->maxidle = (u_int)fabs(maxidle);
550126353Smlaier	opts->minidle = (int)minidle;
551130617Smlaier	opts->offtime = (u_int)fabs(offtime);
552126353Smlaier
553126353Smlaier	return (0);
554126353Smlaier}
555126353Smlaier
556126353Smlaierstatic int
557126353Smlaiercheck_commit_cbq(int dev, int opts, struct pf_altq *pa)
558126353Smlaier{
559126353Smlaier	struct pf_altq	*altq;
560126353Smlaier	int		 root_class, default_class;
561126353Smlaier	int		 error = 0;
562126353Smlaier
563126353Smlaier	/*
564126353Smlaier	 * check if cbq has one root queue and one default queue
565126353Smlaier	 * for this interface
566126353Smlaier	 */
567126353Smlaier	root_class = default_class = 0;
568126353Smlaier	TAILQ_FOREACH(altq, &altqs, entries) {
569126353Smlaier		if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
570126353Smlaier			continue;
571126353Smlaier		if (altq->qname[0] == 0)  /* this is for interface */
572126353Smlaier			continue;
573126353Smlaier		if (altq->pq_u.cbq_opts.flags & CBQCLF_ROOTCLASS)
574126353Smlaier			root_class++;
575126353Smlaier		if (altq->pq_u.cbq_opts.flags & CBQCLF_DEFCLASS)
576126353Smlaier			default_class++;
577126353Smlaier	}
578126353Smlaier	if (root_class != 1) {
579126353Smlaier		warnx("should have one root queue on %s", pa->ifname);
580126353Smlaier		error++;
581126353Smlaier	}
582126353Smlaier	if (default_class != 1) {
583126353Smlaier		warnx("should have one default queue on %s", pa->ifname);
584126353Smlaier		error++;
585126353Smlaier	}
586126353Smlaier	return (error);
587126353Smlaier}
588126353Smlaier
589126353Smlaierstatic int
590126353Smlaierprint_cbq_opts(const struct pf_altq *a)
591126353Smlaier{
592126353Smlaier	const struct cbq_opts	*opts;
593126353Smlaier
594126353Smlaier	opts = &a->pq_u.cbq_opts;
595126353Smlaier	if (opts->flags) {
596126353Smlaier		printf("cbq(");
597126353Smlaier		if (opts->flags & CBQCLF_RED)
598126353Smlaier			printf(" red");
599126353Smlaier		if (opts->flags & CBQCLF_ECN)
600126353Smlaier			printf(" ecn");
601126353Smlaier		if (opts->flags & CBQCLF_RIO)
602126353Smlaier			printf(" rio");
603287009Sloos		if (opts->flags & CBQCLF_CODEL)
604287009Sloos			printf(" codel");
605126353Smlaier		if (opts->flags & CBQCLF_CLEARDSCP)
606126353Smlaier			printf(" cleardscp");
607126353Smlaier		if (opts->flags & CBQCLF_FLOWVALVE)
608126353Smlaier			printf(" flowvalve");
609126353Smlaier		if (opts->flags & CBQCLF_BORROW)
610126353Smlaier			printf(" borrow");
611126353Smlaier		if (opts->flags & CBQCLF_WRR)
612126353Smlaier			printf(" wrr");
613126353Smlaier		if (opts->flags & CBQCLF_EFFICIENT)
614126353Smlaier			printf(" efficient");
615126353Smlaier		if (opts->flags & CBQCLF_ROOTCLASS)
616126353Smlaier			printf(" root");
617126353Smlaier		if (opts->flags & CBQCLF_DEFCLASS)
618126353Smlaier			printf(" default");
619126353Smlaier		printf(" ) ");
620126353Smlaier
621126353Smlaier		return (1);
622126353Smlaier	} else
623126353Smlaier		return (0);
624126353Smlaier}
625126353Smlaier
626126353Smlaier/*
627126353Smlaier * PRIQ support functions
628126353Smlaier */
629126353Smlaierstatic int
630126353Smlaiereval_pfqueue_priq(struct pfctl *pf, struct pf_altq *pa)
631126353Smlaier{
632126353Smlaier	struct pf_altq	*altq;
633126353Smlaier
634126353Smlaier	if (pa->priority >= PRIQ_MAXPRI) {
635126353Smlaier		warnx("priority out of range: max %d", PRIQ_MAXPRI - 1);
636126353Smlaier		return (-1);
637126353Smlaier	}
638126353Smlaier	/* the priority should be unique for the interface */
639126353Smlaier	TAILQ_FOREACH(altq, &altqs, entries) {
640126353Smlaier		if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) == 0 &&
641126353Smlaier		    altq->qname[0] != 0 && altq->priority == pa->priority) {
642126353Smlaier			warnx("%s and %s have the same priority",
643126353Smlaier			    altq->qname, pa->qname);
644126353Smlaier			return (-1);
645126353Smlaier		}
646126353Smlaier	}
647126353Smlaier
648126353Smlaier	return (0);
649126353Smlaier}
650126353Smlaier
651126353Smlaierstatic int
652126353Smlaiercheck_commit_priq(int dev, int opts, struct pf_altq *pa)
653126353Smlaier{
654126353Smlaier	struct pf_altq	*altq;
655126353Smlaier	int		 default_class;
656126353Smlaier	int		 error = 0;
657126353Smlaier
658126353Smlaier	/*
659126353Smlaier	 * check if priq has one default class for this interface
660126353Smlaier	 */
661126353Smlaier	default_class = 0;
662126353Smlaier	TAILQ_FOREACH(altq, &altqs, entries) {
663126353Smlaier		if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
664126353Smlaier			continue;
665126353Smlaier		if (altq->qname[0] == 0)  /* this is for interface */
666126353Smlaier			continue;
667126353Smlaier		if (altq->pq_u.priq_opts.flags & PRCF_DEFAULTCLASS)
668126353Smlaier			default_class++;
669126353Smlaier	}
670126353Smlaier	if (default_class != 1) {
671126353Smlaier		warnx("should have one default queue on %s", pa->ifname);
672126353Smlaier		error++;
673126353Smlaier	}
674126353Smlaier	return (error);
675126353Smlaier}
676126353Smlaier
677126353Smlaierstatic int
678126353Smlaierprint_priq_opts(const struct pf_altq *a)
679126353Smlaier{
680126353Smlaier	const struct priq_opts	*opts;
681126353Smlaier
682126353Smlaier	opts = &a->pq_u.priq_opts;
683126353Smlaier
684126353Smlaier	if (opts->flags) {
685126353Smlaier		printf("priq(");
686126353Smlaier		if (opts->flags & PRCF_RED)
687126353Smlaier			printf(" red");
688126353Smlaier		if (opts->flags & PRCF_ECN)
689126353Smlaier			printf(" ecn");
690126353Smlaier		if (opts->flags & PRCF_RIO)
691126353Smlaier			printf(" rio");
692287009Sloos		if (opts->flags & PRCF_CODEL)
693287009Sloos			printf(" codel");
694126353Smlaier		if (opts->flags & PRCF_CLEARDSCP)
695126353Smlaier			printf(" cleardscp");
696126353Smlaier		if (opts->flags & PRCF_DEFAULTCLASS)
697126353Smlaier			printf(" default");
698126353Smlaier		printf(" ) ");
699126353Smlaier
700126353Smlaier		return (1);
701126353Smlaier	} else
702126353Smlaier		return (0);
703126353Smlaier}
704126353Smlaier
705126353Smlaier/*
706126353Smlaier * HFSC support functions
707126353Smlaier */
708126353Smlaierstatic int
709126353Smlaiereval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa)
710126353Smlaier{
711126353Smlaier	struct pf_altq		*altq, *parent;
712126353Smlaier	struct hfsc_opts	*opts;
713126353Smlaier	struct service_curve	 sc;
714126353Smlaier
715126353Smlaier	opts = &pa->pq_u.hfsc_opts;
716126353Smlaier
717126353Smlaier	if (pa->parent[0] == 0) {
718126353Smlaier		/* root queue */
719126353Smlaier		opts->lssc_m1 = pa->ifbandwidth;
720126353Smlaier		opts->lssc_m2 = pa->ifbandwidth;
721126353Smlaier		opts->lssc_d = 0;
722126353Smlaier		return (0);
723130617Smlaier	}
724126353Smlaier
725126353Smlaier	LIST_INIT(&rtsc);
726126353Smlaier	LIST_INIT(&lssc);
727126353Smlaier
728126353Smlaier	/* if link_share is not specified, use bandwidth */
729126353Smlaier	if (opts->lssc_m2 == 0)
730126353Smlaier		opts->lssc_m2 = pa->bandwidth;
731126353Smlaier
732126353Smlaier	if ((opts->rtsc_m1 > 0 && opts->rtsc_m2 == 0) ||
733126353Smlaier	    (opts->lssc_m1 > 0 && opts->lssc_m2 == 0) ||
734126353Smlaier	    (opts->ulsc_m1 > 0 && opts->ulsc_m2 == 0)) {
735126353Smlaier		warnx("m2 is zero for %s", pa->qname);
736126353Smlaier		return (-1);
737126353Smlaier	}
738126353Smlaier
739126353Smlaier	if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) ||
740164775Smlaier	    (opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) ||
741164775Smlaier	    (opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) {
742126353Smlaier		warnx("m1 must be zero for convex curve: %s", pa->qname);
743126353Smlaier		return (-1);
744126353Smlaier	}
745126353Smlaier
746126353Smlaier	/*
747126353Smlaier	 * admission control:
748126353Smlaier	 * for the real-time service curve, the sum of the service curves
749126353Smlaier	 * should not exceed 80% of the interface bandwidth.  20% is reserved
750126353Smlaier	 * not to over-commit the actual interface bandwidth.
751145840Smlaier	 * for the linkshare service curve, the sum of the child service
752126353Smlaier	 * curve should not exceed the parent service curve.
753126353Smlaier	 * for the upper-limit service curve, the assigned bandwidth should
754126353Smlaier	 * be smaller than the interface bandwidth, and the upper-limit should
755126353Smlaier	 * be larger than the real-time service curve when both are defined.
756126353Smlaier	 */
757126353Smlaier	parent = qname_to_pfaltq(pa->parent, pa->ifname);
758126353Smlaier	if (parent == NULL)
759126353Smlaier		errx(1, "parent %s not found for %s", pa->parent, pa->qname);
760126353Smlaier
761126353Smlaier	TAILQ_FOREACH(altq, &altqs, entries) {
762126353Smlaier		if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
763126353Smlaier			continue;
764126353Smlaier		if (altq->qname[0] == 0)  /* this is for interface */
765126353Smlaier			continue;
766126353Smlaier
767126353Smlaier		/* if the class has a real-time service curve, add it. */
768126353Smlaier		if (opts->rtsc_m2 != 0 && altq->pq_u.hfsc_opts.rtsc_m2 != 0) {
769126353Smlaier			sc.m1 = altq->pq_u.hfsc_opts.rtsc_m1;
770130617Smlaier			sc.d = altq->pq_u.hfsc_opts.rtsc_d;
771126353Smlaier			sc.m2 = altq->pq_u.hfsc_opts.rtsc_m2;
772126353Smlaier			gsc_add_sc(&rtsc, &sc);
773126353Smlaier		}
774126353Smlaier
775126353Smlaier		if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0)
776126353Smlaier			continue;
777126353Smlaier
778145840Smlaier		/* if the class has a linkshare service curve, add it. */
779126353Smlaier		if (opts->lssc_m2 != 0 && altq->pq_u.hfsc_opts.lssc_m2 != 0) {
780126353Smlaier			sc.m1 = altq->pq_u.hfsc_opts.lssc_m1;
781130617Smlaier			sc.d = altq->pq_u.hfsc_opts.lssc_d;
782126353Smlaier			sc.m2 = altq->pq_u.hfsc_opts.lssc_m2;
783126353Smlaier			gsc_add_sc(&lssc, &sc);
784126353Smlaier		}
785126353Smlaier	}
786126353Smlaier
787126353Smlaier	/* check the real-time service curve.  reserve 20% of interface bw */
788126353Smlaier	if (opts->rtsc_m2 != 0) {
789145840Smlaier		/* add this queue to the sum */
790145840Smlaier		sc.m1 = opts->rtsc_m1;
791145840Smlaier		sc.d = opts->rtsc_d;
792145840Smlaier		sc.m2 = opts->rtsc_m2;
793145840Smlaier		gsc_add_sc(&rtsc, &sc);
794145840Smlaier		/* compare the sum with 80% of the interface */
795126353Smlaier		sc.m1 = 0;
796130617Smlaier		sc.d = 0;
797126353Smlaier		sc.m2 = pa->ifbandwidth / 100 * 80;
798126353Smlaier		if (!is_gsc_under_sc(&rtsc, &sc)) {
799145840Smlaier			warnx("real-time sc exceeds 80%% of the interface "
800145840Smlaier			    "bandwidth (%s)", rate2str((double)sc.m2));
801126353Smlaier			goto err_ret;
802126353Smlaier		}
803126353Smlaier	}
804126353Smlaier
805145840Smlaier	/* check the linkshare service curve. */
806126353Smlaier	if (opts->lssc_m2 != 0) {
807145840Smlaier		/* add this queue to the child sum */
808145840Smlaier		sc.m1 = opts->lssc_m1;
809145840Smlaier		sc.d = opts->lssc_d;
810145840Smlaier		sc.m2 = opts->lssc_m2;
811145840Smlaier		gsc_add_sc(&lssc, &sc);
812145840Smlaier		/* compare the sum of the children with parent's sc */
813126353Smlaier		sc.m1 = parent->pq_u.hfsc_opts.lssc_m1;
814130617Smlaier		sc.d = parent->pq_u.hfsc_opts.lssc_d;
815126353Smlaier		sc.m2 = parent->pq_u.hfsc_opts.lssc_m2;
816126353Smlaier		if (!is_gsc_under_sc(&lssc, &sc)) {
817145840Smlaier			warnx("linkshare sc exceeds parent's sc");
818126353Smlaier			goto err_ret;
819126353Smlaier		}
820126353Smlaier	}
821126353Smlaier
822126353Smlaier	/* check the upper-limit service curve. */
823126353Smlaier	if (opts->ulsc_m2 != 0) {
824126353Smlaier		if (opts->ulsc_m1 > pa->ifbandwidth ||
825126353Smlaier		    opts->ulsc_m2 > pa->ifbandwidth) {
826126353Smlaier			warnx("upper-limit larger than interface bandwidth");
827126353Smlaier			goto err_ret;
828126353Smlaier		}
829126353Smlaier		if (opts->rtsc_m2 != 0 && opts->rtsc_m2 > opts->ulsc_m2) {
830126353Smlaier			warnx("upper-limit sc smaller than real-time sc");
831126353Smlaier			goto err_ret;
832126353Smlaier		}
833126353Smlaier	}
834126353Smlaier
835126353Smlaier	gsc_destroy(&rtsc);
836126353Smlaier	gsc_destroy(&lssc);
837126353Smlaier
838126353Smlaier	return (0);
839126353Smlaier
840126353Smlaiererr_ret:
841126353Smlaier	gsc_destroy(&rtsc);
842126353Smlaier	gsc_destroy(&lssc);
843126353Smlaier	return (-1);
844126353Smlaier}
845126353Smlaier
846284777Seri/*
847284777Seri * FAIRQ support functions
848284777Seri */
849126353Smlaierstatic int
850284777Serieval_pfqueue_fairq(struct pfctl *pf __unused, struct pf_altq *pa)
851284777Seri{
852284777Seri	struct pf_altq		*altq, *parent;
853284777Seri	struct fairq_opts	*opts;
854284777Seri	struct service_curve	 sc;
855284777Seri
856284777Seri	opts = &pa->pq_u.fairq_opts;
857284777Seri
858284777Seri	if (pa->parent[0] == 0) {
859284777Seri		/* root queue */
860284777Seri		opts->lssc_m1 = pa->ifbandwidth;
861284777Seri		opts->lssc_m2 = pa->ifbandwidth;
862284777Seri		opts->lssc_d = 0;
863284777Seri		return (0);
864284777Seri	}
865284777Seri
866284777Seri	LIST_INIT(&lssc);
867284777Seri
868284777Seri	/* if link_share is not specified, use bandwidth */
869284777Seri	if (opts->lssc_m2 == 0)
870284777Seri		opts->lssc_m2 = pa->bandwidth;
871284777Seri
872284777Seri	/*
873284777Seri	 * admission control:
874284777Seri	 * for the real-time service curve, the sum of the service curves
875284777Seri	 * should not exceed 80% of the interface bandwidth.  20% is reserved
876284777Seri	 * not to over-commit the actual interface bandwidth.
877284777Seri	 * for the link-sharing service curve, the sum of the child service
878284777Seri	 * curve should not exceed the parent service curve.
879284777Seri	 * for the upper-limit service curve, the assigned bandwidth should
880284777Seri	 * be smaller than the interface bandwidth, and the upper-limit should
881284777Seri	 * be larger than the real-time service curve when both are defined.
882284777Seri	 */
883284777Seri	parent = qname_to_pfaltq(pa->parent, pa->ifname);
884284777Seri	if (parent == NULL)
885284777Seri		errx(1, "parent %s not found for %s", pa->parent, pa->qname);
886284777Seri
887284777Seri	TAILQ_FOREACH(altq, &altqs, entries) {
888284777Seri		if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
889284777Seri			continue;
890284777Seri		if (altq->qname[0] == 0)  /* this is for interface */
891284777Seri			continue;
892284777Seri
893284777Seri		if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0)
894284777Seri			continue;
895284777Seri
896284777Seri		/* if the class has a link-sharing service curve, add it. */
897284777Seri		if (opts->lssc_m2 != 0 && altq->pq_u.fairq_opts.lssc_m2 != 0) {
898284777Seri			sc.m1 = altq->pq_u.fairq_opts.lssc_m1;
899284777Seri			sc.d = altq->pq_u.fairq_opts.lssc_d;
900284777Seri			sc.m2 = altq->pq_u.fairq_opts.lssc_m2;
901284777Seri			gsc_add_sc(&lssc, &sc);
902284777Seri		}
903284777Seri	}
904284777Seri
905284777Seri	/* check the link-sharing service curve. */
906284777Seri	if (opts->lssc_m2 != 0) {
907284777Seri		sc.m1 = parent->pq_u.fairq_opts.lssc_m1;
908284777Seri		sc.d = parent->pq_u.fairq_opts.lssc_d;
909284777Seri		sc.m2 = parent->pq_u.fairq_opts.lssc_m2;
910284777Seri		if (!is_gsc_under_sc(&lssc, &sc)) {
911284777Seri			warnx("link-sharing sc exceeds parent's sc");
912284777Seri			goto err_ret;
913284777Seri		}
914284777Seri	}
915284777Seri
916284777Seri	gsc_destroy(&lssc);
917284777Seri
918284777Seri	return (0);
919284777Seri
920284777Serierr_ret:
921284777Seri	gsc_destroy(&lssc);
922284777Seri	return (-1);
923284777Seri}
924284777Seri
925284777Seristatic int
926126353Smlaiercheck_commit_hfsc(int dev, int opts, struct pf_altq *pa)
927126353Smlaier{
928126353Smlaier	struct pf_altq	*altq, *def = NULL;
929126353Smlaier	int		 default_class;
930126353Smlaier	int		 error = 0;
931126353Smlaier
932126353Smlaier	/* check if hfsc has one default queue for this interface */
933126353Smlaier	default_class = 0;
934126353Smlaier	TAILQ_FOREACH(altq, &altqs, entries) {
935126353Smlaier		if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
936126353Smlaier			continue;
937126353Smlaier		if (altq->qname[0] == 0)  /* this is for interface */
938126353Smlaier			continue;
939126353Smlaier		if (altq->parent[0] == 0)  /* dummy root */
940126353Smlaier			continue;
941126353Smlaier		if (altq->pq_u.hfsc_opts.flags & HFCF_DEFAULTCLASS) {
942126353Smlaier			default_class++;
943126353Smlaier			def = altq;
944126353Smlaier		}
945126353Smlaier	}
946126353Smlaier	if (default_class != 1) {
947126353Smlaier		warnx("should have one default queue on %s", pa->ifname);
948126353Smlaier		return (1);
949126353Smlaier	}
950126353Smlaier	/* make sure the default queue is a leaf */
951126353Smlaier	TAILQ_FOREACH(altq, &altqs, entries) {
952126353Smlaier		if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
953126353Smlaier			continue;
954126353Smlaier		if (altq->qname[0] == 0)  /* this is for interface */
955126353Smlaier			continue;
956126353Smlaier		if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) {
957126353Smlaier			warnx("default queue is not a leaf");
958126353Smlaier			error++;
959126353Smlaier		}
960126353Smlaier	}
961126353Smlaier	return (error);
962126353Smlaier}
963126353Smlaier
964126353Smlaierstatic int
965284777Sericheck_commit_fairq(int dev __unused, int opts __unused, struct pf_altq *pa)
966284777Seri{
967284777Seri	struct pf_altq	*altq, *def = NULL;
968284777Seri	int		 default_class;
969284777Seri	int		 error = 0;
970284777Seri
971284777Seri	/* check if fairq has one default queue for this interface */
972284777Seri	default_class = 0;
973284777Seri	TAILQ_FOREACH(altq, &altqs, entries) {
974284777Seri		if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
975284777Seri			continue;
976284777Seri		if (altq->qname[0] == 0)  /* this is for interface */
977284777Seri			continue;
978284777Seri		if (altq->pq_u.fairq_opts.flags & FARF_DEFAULTCLASS) {
979284777Seri			default_class++;
980284777Seri			def = altq;
981284777Seri		}
982284777Seri	}
983284777Seri	if (default_class != 1) {
984284777Seri		warnx("should have one default queue on %s", pa->ifname);
985284777Seri		return (1);
986284777Seri	}
987284777Seri	/* make sure the default queue is a leaf */
988284777Seri	TAILQ_FOREACH(altq, &altqs, entries) {
989284777Seri		if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
990284777Seri			continue;
991284777Seri		if (altq->qname[0] == 0)  /* this is for interface */
992284777Seri			continue;
993284777Seri		if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) {
994284777Seri			warnx("default queue is not a leaf");
995284777Seri			error++;
996284777Seri		}
997284777Seri	}
998284777Seri	return (error);
999284777Seri}
1000284777Seri
1001284777Seristatic int
1002126353Smlaierprint_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
1003126353Smlaier{
1004126353Smlaier	const struct hfsc_opts		*opts;
1005126353Smlaier	const struct node_hfsc_sc	*rtsc, *lssc, *ulsc;
1006126353Smlaier
1007126353Smlaier	opts = &a->pq_u.hfsc_opts;
1008126353Smlaier	if (qopts == NULL)
1009126353Smlaier		rtsc = lssc = ulsc = NULL;
1010126353Smlaier	else {
1011126353Smlaier		rtsc = &qopts->data.hfsc_opts.realtime;
1012126353Smlaier		lssc = &qopts->data.hfsc_opts.linkshare;
1013126353Smlaier		ulsc = &qopts->data.hfsc_opts.upperlimit;
1014126353Smlaier	}
1015126353Smlaier
1016126353Smlaier	if (opts->flags || opts->rtsc_m2 != 0 || opts->ulsc_m2 != 0 ||
1017126353Smlaier	    (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
1018126353Smlaier	    opts->lssc_d != 0))) {
1019126353Smlaier		printf("hfsc(");
1020126353Smlaier		if (opts->flags & HFCF_RED)
1021126353Smlaier			printf(" red");
1022126353Smlaier		if (opts->flags & HFCF_ECN)
1023126353Smlaier			printf(" ecn");
1024126353Smlaier		if (opts->flags & HFCF_RIO)
1025126353Smlaier			printf(" rio");
1026287009Sloos		if (opts->flags & HFCF_CODEL)
1027287009Sloos			printf(" codel");
1028126353Smlaier		if (opts->flags & HFCF_CLEARDSCP)
1029126353Smlaier			printf(" cleardscp");
1030126353Smlaier		if (opts->flags & HFCF_DEFAULTCLASS)
1031126353Smlaier			printf(" default");
1032126353Smlaier		if (opts->rtsc_m2 != 0)
1033126353Smlaier			print_hfsc_sc("realtime", opts->rtsc_m1, opts->rtsc_d,
1034126353Smlaier			    opts->rtsc_m2, rtsc);
1035126353Smlaier		if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
1036126353Smlaier		    opts->lssc_d != 0))
1037126353Smlaier			print_hfsc_sc("linkshare", opts->lssc_m1, opts->lssc_d,
1038126353Smlaier			    opts->lssc_m2, lssc);
1039126353Smlaier		if (opts->ulsc_m2 != 0)
1040126353Smlaier			print_hfsc_sc("upperlimit", opts->ulsc_m1, opts->ulsc_d,
1041126353Smlaier			    opts->ulsc_m2, ulsc);
1042126353Smlaier		printf(" ) ");
1043126353Smlaier
1044126353Smlaier		return (1);
1045126353Smlaier	} else
1046126353Smlaier		return (0);
1047126353Smlaier}
1048126353Smlaier
1049284777Seristatic int
1050287009Sloosprint_codel_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
1051287009Sloos{
1052287009Sloos	const struct codel_opts *opts;
1053287009Sloos
1054287009Sloos	opts = &a->pq_u.codel_opts;
1055287009Sloos	if (opts->target || opts->interval || opts->ecn) {
1056287009Sloos		printf("codel(");
1057287009Sloos		if (opts->target)
1058287009Sloos			printf(" target %d", opts->target);
1059287009Sloos		if (opts->interval)
1060287009Sloos			printf(" interval %d", opts->interval);
1061287009Sloos		if (opts->ecn)
1062287009Sloos			printf("ecn");
1063287009Sloos		printf(" ) ");
1064287009Sloos
1065287009Sloos		return (1);
1066287009Sloos	}
1067287009Sloos
1068287009Sloos	return (0);
1069287009Sloos}
1070287009Sloos
1071287009Sloosstatic int
1072284777Seriprint_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
1073284777Seri{
1074284777Seri	const struct fairq_opts		*opts;
1075284777Seri	const struct node_fairq_sc	*loc_lssc;
1076284777Seri
1077284777Seri	opts = &a->pq_u.fairq_opts;
1078284777Seri	if (qopts == NULL)
1079284777Seri		loc_lssc = NULL;
1080284777Seri	else
1081284777Seri		loc_lssc = &qopts->data.fairq_opts.linkshare;
1082284777Seri
1083284777Seri	if (opts->flags ||
1084284777Seri	    (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
1085284777Seri	    opts->lssc_d != 0))) {
1086284777Seri		printf("fairq(");
1087284777Seri		if (opts->flags & FARF_RED)
1088284777Seri			printf(" red");
1089284777Seri		if (opts->flags & FARF_ECN)
1090284777Seri			printf(" ecn");
1091284777Seri		if (opts->flags & FARF_RIO)
1092284777Seri			printf(" rio");
1093287009Sloos		if (opts->flags & FARF_CODEL)
1094287009Sloos			printf(" codel");
1095284777Seri		if (opts->flags & FARF_CLEARDSCP)
1096284777Seri			printf(" cleardscp");
1097284777Seri		if (opts->flags & FARF_DEFAULTCLASS)
1098284777Seri			printf(" default");
1099284777Seri		if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
1100284777Seri		    opts->lssc_d != 0))
1101284777Seri			print_fairq_sc("linkshare", opts->lssc_m1, opts->lssc_d,
1102284777Seri			    opts->lssc_m2, loc_lssc);
1103284777Seri		printf(" ) ");
1104284777Seri
1105284777Seri		return (1);
1106284777Seri	} else
1107284777Seri		return (0);
1108284777Seri}
1109284777Seri
1110126353Smlaier/*
1111126353Smlaier * admission control using generalized service curve
1112126353Smlaier */
1113126353Smlaier
1114126353Smlaier/* add a new service curve to a generalized service curve */
1115126353Smlaierstatic void
1116126353Smlaiergsc_add_sc(struct gen_sc *gsc, struct service_curve *sc)
1117126353Smlaier{
1118126353Smlaier	if (is_sc_null(sc))
1119126353Smlaier		return;
1120126353Smlaier	if (sc->d != 0)
1121126353Smlaier		gsc_add_seg(gsc, 0.0, 0.0, (double)sc->d, (double)sc->m1);
1122126353Smlaier	gsc_add_seg(gsc, (double)sc->d, 0.0, INFINITY, (double)sc->m2);
1123126353Smlaier}
1124126353Smlaier
1125126353Smlaier/*
1126126353Smlaier * check whether all points of a generalized service curve have
1127126353Smlaier * their y-coordinates no larger than a given two-piece linear
1128126353Smlaier * service curve.
1129126353Smlaier */
1130126353Smlaierstatic int
1131126353Smlaieris_gsc_under_sc(struct gen_sc *gsc, struct service_curve *sc)
1132126353Smlaier{
1133126353Smlaier	struct segment	*s, *last, *end;
1134126353Smlaier	double		 y;
1135126353Smlaier
1136126353Smlaier	if (is_sc_null(sc)) {
1137126353Smlaier		if (LIST_EMPTY(gsc))
1138126353Smlaier			return (1);
1139126353Smlaier		LIST_FOREACH(s, gsc, _next) {
1140126353Smlaier			if (s->m != 0)
1141126353Smlaier				return (0);
1142126353Smlaier		}
1143126353Smlaier		return (1);
1144126353Smlaier	}
1145126353Smlaier	/*
1146126353Smlaier	 * gsc has a dummy entry at the end with x = INFINITY.
1147126353Smlaier	 * loop through up to this dummy entry.
1148126353Smlaier	 */
1149126353Smlaier	end = gsc_getentry(gsc, INFINITY);
1150126353Smlaier	if (end == NULL)
1151126353Smlaier		return (1);
1152126353Smlaier	last = NULL;
1153126353Smlaier	for (s = LIST_FIRST(gsc); s != end; s = LIST_NEXT(s, _next)) {
1154126353Smlaier		if (s->y > sc_x2y(sc, s->x))
1155126353Smlaier			return (0);
1156126353Smlaier		last = s;
1157126353Smlaier	}
1158126353Smlaier	/* last now holds the real last segment */
1159126353Smlaier	if (last == NULL)
1160126353Smlaier		return (1);
1161126353Smlaier	if (last->m > sc->m2)
1162126353Smlaier		return (0);
1163126353Smlaier	if (last->x < sc->d && last->m > sc->m1) {
1164126353Smlaier		y = last->y + (sc->d - last->x) * last->m;
1165126353Smlaier		if (y > sc_x2y(sc, sc->d))
1166126353Smlaier			return (0);
1167126353Smlaier	}
1168126353Smlaier	return (1);
1169126353Smlaier}
1170126353Smlaier
1171126353Smlaierstatic void
1172126353Smlaiergsc_destroy(struct gen_sc *gsc)
1173126353Smlaier{
1174126353Smlaier	struct segment	*s;
1175126353Smlaier
1176126353Smlaier	while ((s = LIST_FIRST(gsc)) != NULL) {
1177126353Smlaier		LIST_REMOVE(s, _next);
1178126353Smlaier		free(s);
1179126353Smlaier	}
1180126353Smlaier}
1181126353Smlaier
1182126353Smlaier/*
1183126353Smlaier * return a segment entry starting at x.
1184126353Smlaier * if gsc has no entry starting at x, a new entry is created at x.
1185126353Smlaier */
1186126353Smlaierstatic struct segment *
1187126353Smlaiergsc_getentry(struct gen_sc *gsc, double x)
1188126353Smlaier{
1189126353Smlaier	struct segment	*new, *prev, *s;
1190126353Smlaier
1191126353Smlaier	prev = NULL;
1192126353Smlaier	LIST_FOREACH(s, gsc, _next) {
1193126353Smlaier		if (s->x == x)
1194126353Smlaier			return (s);	/* matching entry found */
1195126353Smlaier		else if (s->x < x)
1196126353Smlaier			prev = s;
1197126353Smlaier		else
1198126353Smlaier			break;
1199126353Smlaier	}
1200126353Smlaier
1201126353Smlaier	/* we have to create a new entry */
1202126353Smlaier	if ((new = calloc(1, sizeof(struct segment))) == NULL)
1203126353Smlaier		return (NULL);
1204126353Smlaier
1205126353Smlaier	new->x = x;
1206126353Smlaier	if (x == INFINITY || s == NULL)
1207126353Smlaier		new->d = 0;
1208126353Smlaier	else if (s->x == INFINITY)
1209126353Smlaier		new->d = INFINITY;
1210126353Smlaier	else
1211126353Smlaier		new->d = s->x - x;
1212126353Smlaier	if (prev == NULL) {
1213126353Smlaier		/* insert the new entry at the head of the list */
1214126353Smlaier		new->y = 0;
1215126353Smlaier		new->m = 0;
1216126353Smlaier		LIST_INSERT_HEAD(gsc, new, _next);
1217126353Smlaier	} else {
1218126353Smlaier		/*
1219126353Smlaier		 * the start point intersects with the segment pointed by
1220126353Smlaier		 * prev.  divide prev into 2 segments
1221126353Smlaier		 */
1222126353Smlaier		if (x == INFINITY) {
1223126353Smlaier			prev->d = INFINITY;
1224126353Smlaier			if (prev->m == 0)
1225126353Smlaier				new->y = prev->y;
1226126353Smlaier			else
1227126353Smlaier				new->y = INFINITY;
1228126353Smlaier		} else {
1229126353Smlaier			prev->d = x - prev->x;
1230126353Smlaier			new->y = prev->d * prev->m + prev->y;
1231126353Smlaier		}
1232126353Smlaier		new->m = prev->m;
1233126353Smlaier		LIST_INSERT_AFTER(prev, new, _next);
1234126353Smlaier	}
1235126353Smlaier	return (new);
1236126353Smlaier}
1237126353Smlaier
1238126353Smlaier/* add a segment to a generalized service curve */
1239126353Smlaierstatic int
1240126353Smlaiergsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m)
1241126353Smlaier{
1242126353Smlaier	struct segment	*start, *end, *s;
1243126353Smlaier	double		 x2;
1244126353Smlaier
1245126353Smlaier	if (d == INFINITY)
1246126353Smlaier		x2 = INFINITY;
1247126353Smlaier	else
1248126353Smlaier		x2 = x + d;
1249126353Smlaier	start = gsc_getentry(gsc, x);
1250130617Smlaier	end = gsc_getentry(gsc, x2);
1251126353Smlaier	if (start == NULL || end == NULL)
1252126353Smlaier		return (-1);
1253126353Smlaier
1254126353Smlaier	for (s = start; s != end; s = LIST_NEXT(s, _next)) {
1255126353Smlaier		s->m += m;
1256126353Smlaier		s->y += y + (s->x - x) * m;
1257126353Smlaier	}
1258126353Smlaier
1259126353Smlaier	end = gsc_getentry(gsc, INFINITY);
1260126353Smlaier	for (; s != end; s = LIST_NEXT(s, _next)) {
1261126353Smlaier		s->y += m * d;
1262126353Smlaier	}
1263126353Smlaier
1264126353Smlaier	return (0);
1265126353Smlaier}
1266126353Smlaier
1267126353Smlaier/* get y-projection of a service curve */
1268126353Smlaierstatic double
1269126353Smlaiersc_x2y(struct service_curve *sc, double x)
1270126353Smlaier{
1271126353Smlaier	double	y;
1272126353Smlaier
1273126353Smlaier	if (x <= (double)sc->d)
1274126353Smlaier		/* y belongs to the 1st segment */
1275126353Smlaier		y = x * (double)sc->m1;
1276126353Smlaier	else
1277126353Smlaier		/* y belongs to the 2nd segment */
1278126353Smlaier		y = (double)sc->d * (double)sc->m1
1279126353Smlaier			+ (x - (double)sc->d) * (double)sc->m2;
1280126353Smlaier	return (y);
1281126353Smlaier}
1282126353Smlaier
1283126353Smlaier/*
1284126353Smlaier * misc utilities
1285126353Smlaier */
1286126353Smlaier#define	R2S_BUFS	8
1287126353Smlaier#define	RATESTR_MAX	16
1288126353Smlaier
1289126353Smlaierchar *
1290126353Smlaierrate2str(double rate)
1291126353Smlaier{
1292126353Smlaier	char		*buf;
1293126353Smlaier	static char	 r2sbuf[R2S_BUFS][RATESTR_MAX];  /* ring bufer */
1294126353Smlaier	static int	 idx = 0;
1295126353Smlaier	int		 i;
1296126353Smlaier	static const char unit[] = " KMG";
1297126353Smlaier
1298126353Smlaier	buf = r2sbuf[idx++];
1299126353Smlaier	if (idx == R2S_BUFS)
1300126353Smlaier		idx = 0;
1301126353Smlaier
1302126353Smlaier	for (i = 0; rate >= 1000 && i <= 3; i++)
1303126353Smlaier		rate /= 1000;
1304126353Smlaier
1305126353Smlaier	if ((int)(rate * 100) % 100)
1306126353Smlaier		snprintf(buf, RATESTR_MAX, "%.2f%cb", rate, unit[i]);
1307126353Smlaier	else
1308126353Smlaier		snprintf(buf, RATESTR_MAX, "%d%cb", (int)rate, unit[i]);
1309126353Smlaier
1310126353Smlaier	return (buf);
1311126353Smlaier}
1312126353Smlaier
1313127024Smlaier#ifdef __FreeBSD__
1314126355Smlaier/*
1315126355Smlaier * XXX
1316127024Smlaier * FreeBSD does not have SIOCGIFDATA.
1317126355Smlaier * To emulate this, DIOCGIFSPEED ioctl added to pf.
1318126355Smlaier */
1319126353Smlaieru_int32_t
1320126355Smlaiergetifspeed(int pfdev, char *ifname)
1321126355Smlaier{
1322126355Smlaier	struct pf_ifspeed io;
1323126355Smlaier
1324126355Smlaier	bzero(&io, sizeof io);
1325126355Smlaier	if (strlcpy(io.ifname, ifname, IFNAMSIZ) >=
1326126355Smlaier	    sizeof(io.ifname))
1327126355Smlaier		errx(1, "getifspeed: strlcpy");
1328126355Smlaier	if (ioctl(pfdev, DIOCGIFSPEED, &io) == -1)
1329126355Smlaier		err(1, "DIOCGIFSPEED");
1330126355Smlaier	return ((u_int32_t)io.baudrate);
1331126355Smlaier}
1332126355Smlaier#else
1333126355Smlaieru_int32_t
1334126353Smlaiergetifspeed(char *ifname)
1335126353Smlaier{
1336126353Smlaier	int		s;
1337126353Smlaier	struct ifreq	ifr;
1338126353Smlaier	struct if_data	ifrdat;
1339126353Smlaier
1340259916Sbz	if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0)
1341126353Smlaier		err(1, "socket");
1342145840Smlaier	bzero(&ifr, sizeof(ifr));
1343126353Smlaier	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
1344126353Smlaier	    sizeof(ifr.ifr_name))
1345126353Smlaier		errx(1, "getifspeed: strlcpy");
1346126353Smlaier	ifr.ifr_data = (caddr_t)&ifrdat;
1347126353Smlaier	if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
1348126353Smlaier		err(1, "SIOCGIFDATA");
1349126353Smlaier	if (close(s))
1350126353Smlaier		err(1, "close");
1351126353Smlaier	return ((u_int32_t)ifrdat.ifi_baudrate);
1352126353Smlaier}
1353126355Smlaier#endif
1354126353Smlaier
1355126353Smlaieru_long
1356126353Smlaiergetifmtu(char *ifname)
1357126353Smlaier{
1358126353Smlaier	int		s;
1359126353Smlaier	struct ifreq	ifr;
1360126353Smlaier
1361259916Sbz	if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0)
1362126353Smlaier		err(1, "socket");
1363145840Smlaier	bzero(&ifr, sizeof(ifr));
1364126353Smlaier	if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
1365126353Smlaier	    sizeof(ifr.ifr_name))
1366126353Smlaier		errx(1, "getifmtu: strlcpy");
1367126353Smlaier	if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == -1)
1368177700Smlaier#ifdef __FreeBSD__
1369177700Smlaier		ifr.ifr_mtu = 1500;
1370177700Smlaier#else
1371126353Smlaier		err(1, "SIOCGIFMTU");
1372177700Smlaier#endif
1373126353Smlaier	if (close(s))
1374126353Smlaier		err(1, "close");
1375126353Smlaier	if (ifr.ifr_mtu > 0)
1376126353Smlaier		return (ifr.ifr_mtu);
1377126353Smlaier	else {
1378126353Smlaier		warnx("could not get mtu for %s, assuming 1500", ifname);
1379126353Smlaier		return (1500);
1380126353Smlaier	}
1381126353Smlaier}
1382126353Smlaier
1383126353Smlaierint
1384126353Smlaiereval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts,
1385126353Smlaier    u_int32_t ref_bw)
1386126353Smlaier{
1387126353Smlaier	int	errors = 0;
1388126353Smlaier
1389126353Smlaier	switch (pa->scheduler) {
1390126353Smlaier	case ALTQT_CBQ:
1391126353Smlaier		pa->pq_u.cbq_opts = opts->data.cbq_opts;
1392126353Smlaier		break;
1393126353Smlaier	case ALTQT_PRIQ:
1394126353Smlaier		pa->pq_u.priq_opts = opts->data.priq_opts;
1395126353Smlaier		break;
1396126353Smlaier	case ALTQT_HFSC:
1397126353Smlaier		pa->pq_u.hfsc_opts.flags = opts->data.hfsc_opts.flags;
1398126353Smlaier		if (opts->data.hfsc_opts.linkshare.used) {
1399126353Smlaier			pa->pq_u.hfsc_opts.lssc_m1 =
1400126353Smlaier			    eval_bwspec(&opts->data.hfsc_opts.linkshare.m1,
1401126353Smlaier			    ref_bw);
1402126353Smlaier			pa->pq_u.hfsc_opts.lssc_m2 =
1403126353Smlaier			    eval_bwspec(&opts->data.hfsc_opts.linkshare.m2,
1404126353Smlaier			    ref_bw);
1405126353Smlaier			pa->pq_u.hfsc_opts.lssc_d =
1406126353Smlaier			    opts->data.hfsc_opts.linkshare.d;
1407126353Smlaier		}
1408126353Smlaier		if (opts->data.hfsc_opts.realtime.used) {
1409126353Smlaier			pa->pq_u.hfsc_opts.rtsc_m1 =
1410126353Smlaier			    eval_bwspec(&opts->data.hfsc_opts.realtime.m1,
1411126353Smlaier			    ref_bw);
1412126353Smlaier			pa->pq_u.hfsc_opts.rtsc_m2 =
1413126353Smlaier			    eval_bwspec(&opts->data.hfsc_opts.realtime.m2,
1414126353Smlaier			    ref_bw);
1415126353Smlaier			pa->pq_u.hfsc_opts.rtsc_d =
1416126353Smlaier			    opts->data.hfsc_opts.realtime.d;
1417126353Smlaier		}
1418126353Smlaier		if (opts->data.hfsc_opts.upperlimit.used) {
1419126353Smlaier			pa->pq_u.hfsc_opts.ulsc_m1 =
1420126353Smlaier			    eval_bwspec(&opts->data.hfsc_opts.upperlimit.m1,
1421126353Smlaier			    ref_bw);
1422126353Smlaier			pa->pq_u.hfsc_opts.ulsc_m2 =
1423126353Smlaier			    eval_bwspec(&opts->data.hfsc_opts.upperlimit.m2,
1424126353Smlaier			    ref_bw);
1425126353Smlaier			pa->pq_u.hfsc_opts.ulsc_d =
1426126353Smlaier			    opts->data.hfsc_opts.upperlimit.d;
1427126353Smlaier		}
1428126353Smlaier		break;
1429284777Seri	case ALTQT_FAIRQ:
1430284777Seri		pa->pq_u.fairq_opts.flags = opts->data.fairq_opts.flags;
1431284777Seri		pa->pq_u.fairq_opts.nbuckets = opts->data.fairq_opts.nbuckets;
1432284777Seri		pa->pq_u.fairq_opts.hogs_m1 =
1433284777Seri			eval_bwspec(&opts->data.fairq_opts.hogs_bw, ref_bw);
1434284777Seri
1435284777Seri		if (opts->data.fairq_opts.linkshare.used) {
1436284777Seri			pa->pq_u.fairq_opts.lssc_m1 =
1437284777Seri			    eval_bwspec(&opts->data.fairq_opts.linkshare.m1,
1438284777Seri			    ref_bw);
1439284777Seri			pa->pq_u.fairq_opts.lssc_m2 =
1440284777Seri			    eval_bwspec(&opts->data.fairq_opts.linkshare.m2,
1441284777Seri			    ref_bw);
1442284777Seri			pa->pq_u.fairq_opts.lssc_d =
1443284777Seri			    opts->data.fairq_opts.linkshare.d;
1444284777Seri		}
1445284777Seri		break;
1446287009Sloos	case ALTQT_CODEL:
1447287009Sloos		pa->pq_u.codel_opts.target = opts->data.codel_opts.target;
1448287009Sloos		pa->pq_u.codel_opts.interval = opts->data.codel_opts.interval;
1449287009Sloos		pa->pq_u.codel_opts.ecn = opts->data.codel_opts.ecn;
1450287009Sloos		break;
1451126353Smlaier	default:
1452126353Smlaier		warnx("eval_queue_opts: unknown scheduler type %u",
1453126353Smlaier		    opts->qtype);
1454126353Smlaier		errors++;
1455126353Smlaier		break;
1456126353Smlaier	}
1457126353Smlaier
1458126353Smlaier	return (errors);
1459126353Smlaier}
1460126353Smlaier
1461126353Smlaieru_int32_t
1462126353Smlaiereval_bwspec(struct node_queue_bw *bw, u_int32_t ref_bw)
1463126353Smlaier{
1464126353Smlaier	if (bw->bw_absolute > 0)
1465126353Smlaier		return (bw->bw_absolute);
1466126353Smlaier
1467126353Smlaier	if (bw->bw_percent > 0)
1468126353Smlaier		return (ref_bw / 100 * bw->bw_percent);
1469126353Smlaier
1470126353Smlaier	return (0);
1471126353Smlaier}
1472126353Smlaier
1473126353Smlaiervoid
1474126353Smlaierprint_hfsc_sc(const char *scname, u_int m1, u_int d, u_int m2,
1475126353Smlaier    const struct node_hfsc_sc *sc)
1476126353Smlaier{
1477126353Smlaier	printf(" %s", scname);
1478126353Smlaier
1479126353Smlaier	if (d != 0) {
1480126353Smlaier		printf("(");
1481126353Smlaier		if (sc != NULL && sc->m1.bw_percent > 0)
1482126353Smlaier			printf("%u%%", sc->m1.bw_percent);
1483126353Smlaier		else
1484126353Smlaier			printf("%s", rate2str((double)m1));
1485126353Smlaier		printf(" %u", d);
1486126353Smlaier	}
1487126353Smlaier
1488126353Smlaier	if (sc != NULL && sc->m2.bw_percent > 0)
1489126353Smlaier		printf(" %u%%", sc->m2.bw_percent);
1490126353Smlaier	else
1491126353Smlaier		printf(" %s", rate2str((double)m2));
1492126353Smlaier
1493126353Smlaier	if (d != 0)
1494126353Smlaier		printf(")");
1495126353Smlaier}
1496284777Seri
1497284777Serivoid
1498284777Seriprint_fairq_sc(const char *scname, u_int m1, u_int d, u_int m2,
1499284777Seri    const struct node_fairq_sc *sc)
1500284777Seri{
1501284777Seri	printf(" %s", scname);
1502284777Seri
1503284777Seri	if (d != 0) {
1504284777Seri		printf("(");
1505284777Seri		if (sc != NULL && sc->m1.bw_percent > 0)
1506284777Seri			printf("%u%%", sc->m1.bw_percent);
1507284777Seri		else
1508284777Seri			printf("%s", rate2str((double)m1));
1509284777Seri		printf(" %u", d);
1510284777Seri	}
1511284777Seri
1512284777Seri	if (sc != NULL && sc->m2.bw_percent > 0)
1513284777Seri		printf(" %u%%", sc->m2.bw_percent);
1514284777Seri	else
1515284777Seri		printf(" %s", rate2str((double)m2));
1516284777Seri
1517284777Seri	if (d != 0)
1518284777Seri		printf(")");
1519284777Seri}
1520