13b3a8eb9SGleb Smirnoff /* $OpenBSD: pfctl_altq.c,v 1.93 2007/10/15 02:16:35 deraadt Exp $ */
23b3a8eb9SGleb Smirnoff
33b3a8eb9SGleb Smirnoff /*
43b3a8eb9SGleb Smirnoff * Copyright (c) 2002
53b3a8eb9SGleb Smirnoff * Sony Computer Science Laboratories Inc.
63b3a8eb9SGleb Smirnoff * Copyright (c) 2002, 2003 Henning Brauer <henning@openbsd.org>
73b3a8eb9SGleb Smirnoff *
83b3a8eb9SGleb Smirnoff * Permission to use, copy, modify, and distribute this software for any
93b3a8eb9SGleb Smirnoff * purpose with or without fee is hereby granted, provided that the above
103b3a8eb9SGleb Smirnoff * copyright notice and this permission notice appear in all copies.
113b3a8eb9SGleb Smirnoff *
123b3a8eb9SGleb Smirnoff * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
133b3a8eb9SGleb Smirnoff * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
143b3a8eb9SGleb Smirnoff * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
153b3a8eb9SGleb Smirnoff * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
163b3a8eb9SGleb Smirnoff * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
173b3a8eb9SGleb Smirnoff * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
183b3a8eb9SGleb Smirnoff * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
193b3a8eb9SGleb Smirnoff */
203b3a8eb9SGleb Smirnoff
213b3a8eb9SGleb Smirnoff #include <sys/cdefs.h>
22249cc75fSPatrick Kelsey #define PFIOC_USE_LATEST
235e04571cSStefan Eßer #define _WANT_FREEBSD_BITSET
24249cc75fSPatrick Kelsey
253b3a8eb9SGleb Smirnoff #include <sys/types.h>
261d34c9daSPatrick Kelsey #include <sys/bitset.h>
273b3a8eb9SGleb Smirnoff #include <sys/ioctl.h>
283b3a8eb9SGleb Smirnoff #include <sys/socket.h>
293b3a8eb9SGleb Smirnoff
303b3a8eb9SGleb Smirnoff #include <net/if.h>
313b3a8eb9SGleb Smirnoff #include <netinet/in.h>
323b3a8eb9SGleb Smirnoff #include <net/pfvar.h>
333b3a8eb9SGleb Smirnoff
343b3a8eb9SGleb Smirnoff #include <err.h>
353b3a8eb9SGleb Smirnoff #include <errno.h>
36249cc75fSPatrick Kelsey #include <inttypes.h>
373b3a8eb9SGleb Smirnoff #include <limits.h>
383b3a8eb9SGleb Smirnoff #include <math.h>
391d34c9daSPatrick Kelsey #include <search.h>
403b3a8eb9SGleb Smirnoff #include <stdio.h>
413b3a8eb9SGleb Smirnoff #include <stdlib.h>
423b3a8eb9SGleb Smirnoff #include <string.h>
433b3a8eb9SGleb Smirnoff #include <unistd.h>
443b3a8eb9SGleb Smirnoff
45772e66a6SGleb Smirnoff #include <net/altq/altq.h>
46772e66a6SGleb Smirnoff #include <net/altq/altq_cbq.h>
470a70aaf8SLuiz Otavio O Souza #include <net/altq/altq_codel.h>
48772e66a6SGleb Smirnoff #include <net/altq/altq_priq.h>
49772e66a6SGleb Smirnoff #include <net/altq/altq_hfsc.h>
50a5b789f6SErmal Luçi #include <net/altq/altq_fairq.h>
513b3a8eb9SGleb Smirnoff
523b3a8eb9SGleb Smirnoff #include "pfctl_parser.h"
533b3a8eb9SGleb Smirnoff #include "pfctl.h"
543b3a8eb9SGleb Smirnoff
553b3a8eb9SGleb Smirnoff #define is_sc_null(sc) (((sc) == NULL) || ((sc)->m1 == 0 && (sc)->m2 == 0))
563b3a8eb9SGleb Smirnoff
571d34c9daSPatrick Kelsey static STAILQ_HEAD(interfaces, pfctl_altq) interfaces = STAILQ_HEAD_INITIALIZER(interfaces);
581d34c9daSPatrick Kelsey static struct hsearch_data queue_map;
591d34c9daSPatrick Kelsey static struct hsearch_data if_map;
601d34c9daSPatrick Kelsey static struct hsearch_data qid_map;
613b3a8eb9SGleb Smirnoff
621d34c9daSPatrick Kelsey static struct pfctl_altq *pfaltq_lookup(char *ifname);
631d34c9daSPatrick Kelsey static struct pfctl_altq *qname_to_pfaltq(const char *, const char *);
641d34c9daSPatrick Kelsey static u_int32_t qname_to_qid(char *);
653b3a8eb9SGleb Smirnoff
661d34c9daSPatrick Kelsey static int eval_pfqueue_cbq(struct pfctl *, struct pf_altq *,
671d34c9daSPatrick Kelsey struct pfctl_altq *);
683b3a8eb9SGleb Smirnoff static int cbq_compute_idletime(struct pfctl *, struct pf_altq *);
691d34c9daSPatrick Kelsey static int check_commit_cbq(int, int, struct pfctl_altq *);
703b3a8eb9SGleb Smirnoff static int print_cbq_opts(const struct pf_altq *);
713b3a8eb9SGleb Smirnoff
720a70aaf8SLuiz Otavio O Souza static int print_codel_opts(const struct pf_altq *,
730a70aaf8SLuiz Otavio O Souza const struct node_queue_opt *);
740a70aaf8SLuiz Otavio O Souza
751d34c9daSPatrick Kelsey static int eval_pfqueue_priq(struct pfctl *, struct pf_altq *,
761d34c9daSPatrick Kelsey struct pfctl_altq *);
771d34c9daSPatrick Kelsey static int check_commit_priq(int, int, struct pfctl_altq *);
783b3a8eb9SGleb Smirnoff static int print_priq_opts(const struct pf_altq *);
793b3a8eb9SGleb Smirnoff
801d34c9daSPatrick Kelsey static int eval_pfqueue_hfsc(struct pfctl *, struct pf_altq *,
811d34c9daSPatrick Kelsey struct pfctl_altq *, struct pfctl_altq *);
821d34c9daSPatrick Kelsey static int check_commit_hfsc(int, int, struct pfctl_altq *);
833b3a8eb9SGleb Smirnoff static int print_hfsc_opts(const struct pf_altq *,
843b3a8eb9SGleb Smirnoff const struct node_queue_opt *);
853b3a8eb9SGleb Smirnoff
861d34c9daSPatrick Kelsey static int eval_pfqueue_fairq(struct pfctl *, struct pf_altq *,
871d34c9daSPatrick Kelsey struct pfctl_altq *, struct pfctl_altq *);
88a5b789f6SErmal Luçi static int print_fairq_opts(const struct pf_altq *,
89a5b789f6SErmal Luçi const struct node_queue_opt *);
901d34c9daSPatrick Kelsey static int check_commit_fairq(int, int, struct pfctl_altq *);
91a5b789f6SErmal Luçi
923b3a8eb9SGleb Smirnoff static void gsc_add_sc(struct gen_sc *, struct service_curve *);
933b3a8eb9SGleb Smirnoff static int is_gsc_under_sc(struct gen_sc *,
943b3a8eb9SGleb Smirnoff struct service_curve *);
953b3a8eb9SGleb Smirnoff static struct segment *gsc_getentry(struct gen_sc *, double);
963b3a8eb9SGleb Smirnoff static int gsc_add_seg(struct gen_sc *, double, double, double,
973b3a8eb9SGleb Smirnoff double);
983b3a8eb9SGleb Smirnoff static double sc_x2y(struct service_curve *, double);
993b3a8eb9SGleb Smirnoff
1003b3a8eb9SGleb Smirnoff u_int32_t getifspeed(char *);
1013b3a8eb9SGleb Smirnoff u_long getifmtu(char *);
1023b3a8eb9SGleb Smirnoff int eval_queue_opts(struct pf_altq *, struct node_queue_opt *,
103249cc75fSPatrick Kelsey u_int64_t);
104249cc75fSPatrick Kelsey u_int64_t eval_bwspec(struct node_queue_bw *, u_int64_t);
1053b3a8eb9SGleb Smirnoff void print_hfsc_sc(const char *, u_int, u_int, u_int,
1063b3a8eb9SGleb Smirnoff const struct node_hfsc_sc *);
107a5b789f6SErmal Luçi void print_fairq_sc(const char *, u_int, u_int, u_int,
108a5b789f6SErmal Luçi const struct node_fairq_sc *);
1093b3a8eb9SGleb Smirnoff
1101d34c9daSPatrick Kelsey static __attribute__((constructor)) void
pfctl_altq_init(void)1111d34c9daSPatrick Kelsey pfctl_altq_init(void)
1121d34c9daSPatrick Kelsey {
1131d34c9daSPatrick Kelsey /*
1141d34c9daSPatrick Kelsey * As hdestroy() will never be called on these tables, it will be
1151d34c9daSPatrick Kelsey * safe to use references into the stored data as keys.
1161d34c9daSPatrick Kelsey */
1171d34c9daSPatrick Kelsey if (hcreate_r(0, &queue_map) == 0)
1181d34c9daSPatrick Kelsey err(1, "Failed to create altq queue map");
1191d34c9daSPatrick Kelsey if (hcreate_r(0, &if_map) == 0)
1201d34c9daSPatrick Kelsey err(1, "Failed to create altq interface map");
1211d34c9daSPatrick Kelsey if (hcreate_r(0, &qid_map) == 0)
1221d34c9daSPatrick Kelsey err(1, "Failed to create altq queue id map");
1231d34c9daSPatrick Kelsey }
1241d34c9daSPatrick Kelsey
1253b3a8eb9SGleb Smirnoff void
pfaltq_store(struct pf_altq * a)1263b3a8eb9SGleb Smirnoff pfaltq_store(struct pf_altq *a)
1273b3a8eb9SGleb Smirnoff {
1281d34c9daSPatrick Kelsey struct pfctl_altq *altq;
1291d34c9daSPatrick Kelsey ENTRY item;
1301d34c9daSPatrick Kelsey ENTRY *ret_item;
1311d34c9daSPatrick Kelsey size_t key_size;
1323b3a8eb9SGleb Smirnoff
1333b3a8eb9SGleb Smirnoff if ((altq = malloc(sizeof(*altq))) == NULL)
1341d34c9daSPatrick Kelsey err(1, "queue malloc");
1351d34c9daSPatrick Kelsey memcpy(&altq->pa, a, sizeof(struct pf_altq));
1361d34c9daSPatrick Kelsey memset(&altq->meta, 0, sizeof(altq->meta));
1371d34c9daSPatrick Kelsey
1381d34c9daSPatrick Kelsey if (a->qname[0] == 0) {
1391d34c9daSPatrick Kelsey item.key = altq->pa.ifname;
1401d34c9daSPatrick Kelsey item.data = altq;
1411d34c9daSPatrick Kelsey if (hsearch_r(item, ENTER, &ret_item, &if_map) == 0)
1421d34c9daSPatrick Kelsey err(1, "interface map insert");
1431d34c9daSPatrick Kelsey STAILQ_INSERT_TAIL(&interfaces, altq, meta.link);
1441d34c9daSPatrick Kelsey } else {
1451d34c9daSPatrick Kelsey key_size = sizeof(a->ifname) + sizeof(a->qname);
1461d34c9daSPatrick Kelsey if ((item.key = malloc(key_size)) == NULL)
1471d34c9daSPatrick Kelsey err(1, "queue map key malloc");
1481d34c9daSPatrick Kelsey snprintf(item.key, key_size, "%s:%s", a->ifname, a->qname);
1491d34c9daSPatrick Kelsey item.data = altq;
1501d34c9daSPatrick Kelsey if (hsearch_r(item, ENTER, &ret_item, &queue_map) == 0)
1511d34c9daSPatrick Kelsey err(1, "queue map insert");
1521d34c9daSPatrick Kelsey
1531d34c9daSPatrick Kelsey item.key = altq->pa.qname;
1541d34c9daSPatrick Kelsey item.data = &altq->pa.qid;
1551d34c9daSPatrick Kelsey if (hsearch_r(item, ENTER, &ret_item, &qid_map) == 0)
1561d34c9daSPatrick Kelsey err(1, "qid map insert");
1571d34c9daSPatrick Kelsey }
1583b3a8eb9SGleb Smirnoff }
1593b3a8eb9SGleb Smirnoff
1601d34c9daSPatrick Kelsey static struct pfctl_altq *
pfaltq_lookup(char * ifname)1611d34c9daSPatrick Kelsey pfaltq_lookup(char *ifname)
1623b3a8eb9SGleb Smirnoff {
1631d34c9daSPatrick Kelsey ENTRY item;
1641d34c9daSPatrick Kelsey ENTRY *ret_item;
1653b3a8eb9SGleb Smirnoff
1661d34c9daSPatrick Kelsey item.key = ifname;
1671d34c9daSPatrick Kelsey if (hsearch_r(item, FIND, &ret_item, &if_map) == 0)
1683b3a8eb9SGleb Smirnoff return (NULL);
1691d34c9daSPatrick Kelsey
1701d34c9daSPatrick Kelsey return (ret_item->data);
1713b3a8eb9SGleb Smirnoff }
1723b3a8eb9SGleb Smirnoff
1731d34c9daSPatrick Kelsey static struct pfctl_altq *
qname_to_pfaltq(const char * qname,const char * ifname)1743b3a8eb9SGleb Smirnoff qname_to_pfaltq(const char *qname, const char *ifname)
1753b3a8eb9SGleb Smirnoff {
1761d34c9daSPatrick Kelsey ENTRY item;
1771d34c9daSPatrick Kelsey ENTRY *ret_item;
1781d34c9daSPatrick Kelsey char key[IFNAMSIZ + PF_QNAME_SIZE];
1793b3a8eb9SGleb Smirnoff
1801d34c9daSPatrick Kelsey item.key = key;
1811d34c9daSPatrick Kelsey snprintf(item.key, sizeof(key), "%s:%s", ifname, qname);
1821d34c9daSPatrick Kelsey if (hsearch_r(item, FIND, &ret_item, &queue_map) == 0)
1833b3a8eb9SGleb Smirnoff return (NULL);
1841d34c9daSPatrick Kelsey
1851d34c9daSPatrick Kelsey return (ret_item->data);
1863b3a8eb9SGleb Smirnoff }
1873b3a8eb9SGleb Smirnoff
1881d34c9daSPatrick Kelsey static u_int32_t
qname_to_qid(char * qname)1891d34c9daSPatrick Kelsey qname_to_qid(char *qname)
1903b3a8eb9SGleb Smirnoff {
1911d34c9daSPatrick Kelsey ENTRY item;
1921d34c9daSPatrick Kelsey ENTRY *ret_item;
1931d34c9daSPatrick Kelsey uint32_t qid;
1943b3a8eb9SGleb Smirnoff
1953b3a8eb9SGleb Smirnoff /*
1963b3a8eb9SGleb Smirnoff * We guarantee that same named queues on different interfaces
1971d34c9daSPatrick Kelsey * have the same qid.
1983b3a8eb9SGleb Smirnoff */
1991d34c9daSPatrick Kelsey item.key = qname;
2001d34c9daSPatrick Kelsey if (hsearch_r(item, FIND, &ret_item, &qid_map) == 0)
2013b3a8eb9SGleb Smirnoff return (0);
2021d34c9daSPatrick Kelsey
2031d34c9daSPatrick Kelsey qid = *(uint32_t *)ret_item->data;
2041d34c9daSPatrick Kelsey return (qid);
2053b3a8eb9SGleb Smirnoff }
2063b3a8eb9SGleb Smirnoff
2073b3a8eb9SGleb Smirnoff void
print_altq(const struct pf_altq * a,unsigned int level,struct node_queue_bw * bw,struct node_queue_opt * qopts)2083b3a8eb9SGleb Smirnoff print_altq(const struct pf_altq *a, unsigned int level,
2093b3a8eb9SGleb Smirnoff struct node_queue_bw *bw, struct node_queue_opt *qopts)
2103b3a8eb9SGleb Smirnoff {
2113b3a8eb9SGleb Smirnoff if (a->qname[0] != 0) {
2123b3a8eb9SGleb Smirnoff print_queue(a, level, bw, 1, qopts);
2133b3a8eb9SGleb Smirnoff return;
2143b3a8eb9SGleb Smirnoff }
2153b3a8eb9SGleb Smirnoff
2163b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
2173b3a8eb9SGleb Smirnoff if (a->local_flags & PFALTQ_FLAG_IF_REMOVED)
2183b3a8eb9SGleb Smirnoff printf("INACTIVE ");
2193b3a8eb9SGleb Smirnoff #endif
2203b3a8eb9SGleb Smirnoff
2213b3a8eb9SGleb Smirnoff printf("altq on %s ", a->ifname);
2223b3a8eb9SGleb Smirnoff
2233b3a8eb9SGleb Smirnoff switch (a->scheduler) {
2243b3a8eb9SGleb Smirnoff case ALTQT_CBQ:
2253b3a8eb9SGleb Smirnoff if (!print_cbq_opts(a))
2263b3a8eb9SGleb Smirnoff printf("cbq ");
2273b3a8eb9SGleb Smirnoff break;
2283b3a8eb9SGleb Smirnoff case ALTQT_PRIQ:
2293b3a8eb9SGleb Smirnoff if (!print_priq_opts(a))
2303b3a8eb9SGleb Smirnoff printf("priq ");
2313b3a8eb9SGleb Smirnoff break;
2323b3a8eb9SGleb Smirnoff case ALTQT_HFSC:
2333b3a8eb9SGleb Smirnoff if (!print_hfsc_opts(a, qopts))
2343b3a8eb9SGleb Smirnoff printf("hfsc ");
2353b3a8eb9SGleb Smirnoff break;
236a5b789f6SErmal Luçi case ALTQT_FAIRQ:
237a5b789f6SErmal Luçi if (!print_fairq_opts(a, qopts))
238a5b789f6SErmal Luçi printf("fairq ");
239a5b789f6SErmal Luçi break;
2400a70aaf8SLuiz Otavio O Souza case ALTQT_CODEL:
2410a70aaf8SLuiz Otavio O Souza if (!print_codel_opts(a, qopts))
2420a70aaf8SLuiz Otavio O Souza printf("codel ");
2430a70aaf8SLuiz Otavio O Souza break;
2443b3a8eb9SGleb Smirnoff }
2453b3a8eb9SGleb Smirnoff
2463b3a8eb9SGleb Smirnoff if (bw != NULL && bw->bw_percent > 0) {
2473b3a8eb9SGleb Smirnoff if (bw->bw_percent < 100)
2483b3a8eb9SGleb Smirnoff printf("bandwidth %u%% ", bw->bw_percent);
2493b3a8eb9SGleb Smirnoff } else
2503b3a8eb9SGleb Smirnoff printf("bandwidth %s ", rate2str((double)a->ifbandwidth));
2513b3a8eb9SGleb Smirnoff
2523b3a8eb9SGleb Smirnoff if (a->qlimit != DEFAULT_QLIMIT)
2533b3a8eb9SGleb Smirnoff printf("qlimit %u ", a->qlimit);
2543b3a8eb9SGleb Smirnoff printf("tbrsize %u ", a->tbrsize);
2553b3a8eb9SGleb Smirnoff }
2563b3a8eb9SGleb Smirnoff
2573b3a8eb9SGleb Smirnoff void
print_queue(const struct pf_altq * a,unsigned int level,struct node_queue_bw * bw,int print_interface,struct node_queue_opt * qopts)2583b3a8eb9SGleb Smirnoff print_queue(const struct pf_altq *a, unsigned int level,
2593b3a8eb9SGleb Smirnoff struct node_queue_bw *bw, int print_interface,
2603b3a8eb9SGleb Smirnoff struct node_queue_opt *qopts)
2613b3a8eb9SGleb Smirnoff {
2623b3a8eb9SGleb Smirnoff unsigned int i;
2633b3a8eb9SGleb Smirnoff
2643b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
2653b3a8eb9SGleb Smirnoff if (a->local_flags & PFALTQ_FLAG_IF_REMOVED)
2663b3a8eb9SGleb Smirnoff printf("INACTIVE ");
2673b3a8eb9SGleb Smirnoff #endif
2683b3a8eb9SGleb Smirnoff printf("queue ");
2693b3a8eb9SGleb Smirnoff for (i = 0; i < level; ++i)
2703b3a8eb9SGleb Smirnoff printf(" ");
2713b3a8eb9SGleb Smirnoff printf("%s ", a->qname);
2723b3a8eb9SGleb Smirnoff if (print_interface)
2733b3a8eb9SGleb Smirnoff printf("on %s ", a->ifname);
274a5b789f6SErmal Luçi if (a->scheduler == ALTQT_CBQ || a->scheduler == ALTQT_HFSC ||
275a5b789f6SErmal Luçi a->scheduler == ALTQT_FAIRQ) {
2763b3a8eb9SGleb Smirnoff if (bw != NULL && bw->bw_percent > 0) {
2773b3a8eb9SGleb Smirnoff if (bw->bw_percent < 100)
2783b3a8eb9SGleb Smirnoff printf("bandwidth %u%% ", bw->bw_percent);
2793b3a8eb9SGleb Smirnoff } else
2803b3a8eb9SGleb Smirnoff printf("bandwidth %s ", rate2str((double)a->bandwidth));
2813b3a8eb9SGleb Smirnoff }
2823b3a8eb9SGleb Smirnoff if (a->priority != DEFAULT_PRIORITY)
2833b3a8eb9SGleb Smirnoff printf("priority %u ", a->priority);
2843b3a8eb9SGleb Smirnoff if (a->qlimit != DEFAULT_QLIMIT)
2853b3a8eb9SGleb Smirnoff printf("qlimit %u ", a->qlimit);
2863b3a8eb9SGleb Smirnoff switch (a->scheduler) {
2873b3a8eb9SGleb Smirnoff case ALTQT_CBQ:
2883b3a8eb9SGleb Smirnoff print_cbq_opts(a);
2893b3a8eb9SGleb Smirnoff break;
2903b3a8eb9SGleb Smirnoff case ALTQT_PRIQ:
2913b3a8eb9SGleb Smirnoff print_priq_opts(a);
2923b3a8eb9SGleb Smirnoff break;
2933b3a8eb9SGleb Smirnoff case ALTQT_HFSC:
2943b3a8eb9SGleb Smirnoff print_hfsc_opts(a, qopts);
2953b3a8eb9SGleb Smirnoff break;
296a5b789f6SErmal Luçi case ALTQT_FAIRQ:
297a5b789f6SErmal Luçi print_fairq_opts(a, qopts);
298a5b789f6SErmal Luçi break;
2993b3a8eb9SGleb Smirnoff }
3003b3a8eb9SGleb Smirnoff }
3013b3a8eb9SGleb Smirnoff
3023b3a8eb9SGleb Smirnoff /*
3033b3a8eb9SGleb Smirnoff * eval_pfaltq computes the discipline parameters.
3043b3a8eb9SGleb Smirnoff */
3053b3a8eb9SGleb Smirnoff int
eval_pfaltq(struct pfctl * pf,struct pf_altq * pa,struct node_queue_bw * bw,struct node_queue_opt * opts)3063b3a8eb9SGleb Smirnoff eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
3073b3a8eb9SGleb Smirnoff struct node_queue_opt *opts)
3083b3a8eb9SGleb Smirnoff {
309249cc75fSPatrick Kelsey u_int64_t rate;
310249cc75fSPatrick Kelsey u_int size, errors = 0;
3113b3a8eb9SGleb Smirnoff
3123b3a8eb9SGleb Smirnoff if (bw->bw_absolute > 0)
3133b3a8eb9SGleb Smirnoff pa->ifbandwidth = bw->bw_absolute;
3143b3a8eb9SGleb Smirnoff else
3153b3a8eb9SGleb Smirnoff if ((rate = getifspeed(pa->ifname)) == 0) {
3163b3a8eb9SGleb Smirnoff fprintf(stderr, "interface %s does not know its bandwidth, "
3173b3a8eb9SGleb Smirnoff "please specify an absolute bandwidth\n",
3183b3a8eb9SGleb Smirnoff pa->ifname);
3193b3a8eb9SGleb Smirnoff errors++;
3203b3a8eb9SGleb Smirnoff } else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0)
3213b3a8eb9SGleb Smirnoff pa->ifbandwidth = rate;
3223b3a8eb9SGleb Smirnoff
323249cc75fSPatrick Kelsey /*
324249cc75fSPatrick Kelsey * Limit bandwidth to UINT_MAX for schedulers that aren't 64-bit ready.
325249cc75fSPatrick Kelsey */
326249cc75fSPatrick Kelsey if ((pa->scheduler != ALTQT_HFSC) && (pa->ifbandwidth > UINT_MAX)) {
327249cc75fSPatrick Kelsey pa->ifbandwidth = UINT_MAX;
328249cc75fSPatrick Kelsey warnx("interface %s bandwidth limited to %" PRIu64 " bps "
329249cc75fSPatrick Kelsey "because selected scheduler is 32-bit limited\n", pa->ifname,
330249cc75fSPatrick Kelsey pa->ifbandwidth);
331249cc75fSPatrick Kelsey }
3323b3a8eb9SGleb Smirnoff errors += eval_queue_opts(pa, opts, pa->ifbandwidth);
3333b3a8eb9SGleb Smirnoff
3343b3a8eb9SGleb Smirnoff /* if tbrsize is not specified, use heuristics */
3353b3a8eb9SGleb Smirnoff if (pa->tbrsize == 0) {
3363b3a8eb9SGleb Smirnoff rate = pa->ifbandwidth;
3373b3a8eb9SGleb Smirnoff if (rate <= 1 * 1000 * 1000)
3383b3a8eb9SGleb Smirnoff size = 1;
3393b3a8eb9SGleb Smirnoff else if (rate <= 10 * 1000 * 1000)
3403b3a8eb9SGleb Smirnoff size = 4;
3413b3a8eb9SGleb Smirnoff else if (rate <= 200 * 1000 * 1000)
3423b3a8eb9SGleb Smirnoff size = 8;
343ef9afde4SPatrick Kelsey else if (rate <= 2500 * 1000 * 1000ULL)
3443b3a8eb9SGleb Smirnoff size = 24;
345ff7b3f73SPatrick Kelsey else
346ff7b3f73SPatrick Kelsey size = 128;
3473b3a8eb9SGleb Smirnoff size = size * getifmtu(pa->ifname);
3483b3a8eb9SGleb Smirnoff pa->tbrsize = size;
3493b3a8eb9SGleb Smirnoff }
3503b3a8eb9SGleb Smirnoff return (errors);
3513b3a8eb9SGleb Smirnoff }
3523b3a8eb9SGleb Smirnoff
3533b3a8eb9SGleb Smirnoff /*
3543b3a8eb9SGleb Smirnoff * check_commit_altq does consistency check for each interface
3553b3a8eb9SGleb Smirnoff */
3563b3a8eb9SGleb Smirnoff int
check_commit_altq(int dev,int opts)3573b3a8eb9SGleb Smirnoff check_commit_altq(int dev, int opts)
3583b3a8eb9SGleb Smirnoff {
3591d34c9daSPatrick Kelsey struct pfctl_altq *if_ppa;
3603b3a8eb9SGleb Smirnoff int error = 0;
3613b3a8eb9SGleb Smirnoff
3623b3a8eb9SGleb Smirnoff /* call the discipline check for each interface. */
3631d34c9daSPatrick Kelsey STAILQ_FOREACH(if_ppa, &interfaces, meta.link) {
3641d34c9daSPatrick Kelsey switch (if_ppa->pa.scheduler) {
3653b3a8eb9SGleb Smirnoff case ALTQT_CBQ:
3661d34c9daSPatrick Kelsey error = check_commit_cbq(dev, opts, if_ppa);
3673b3a8eb9SGleb Smirnoff break;
3683b3a8eb9SGleb Smirnoff case ALTQT_PRIQ:
3691d34c9daSPatrick Kelsey error = check_commit_priq(dev, opts, if_ppa);
3703b3a8eb9SGleb Smirnoff break;
3713b3a8eb9SGleb Smirnoff case ALTQT_HFSC:
3721d34c9daSPatrick Kelsey error = check_commit_hfsc(dev, opts, if_ppa);
3733b3a8eb9SGleb Smirnoff break;
374a5b789f6SErmal Luçi case ALTQT_FAIRQ:
3751d34c9daSPatrick Kelsey error = check_commit_fairq(dev, opts, if_ppa);
376a5b789f6SErmal Luçi break;
3773b3a8eb9SGleb Smirnoff default:
3783b3a8eb9SGleb Smirnoff break;
3793b3a8eb9SGleb Smirnoff }
3803b3a8eb9SGleb Smirnoff }
3813b3a8eb9SGleb Smirnoff return (error);
3823b3a8eb9SGleb Smirnoff }
3833b3a8eb9SGleb Smirnoff
3843b3a8eb9SGleb Smirnoff /*
3853b3a8eb9SGleb Smirnoff * eval_pfqueue computes the queue parameters.
3863b3a8eb9SGleb Smirnoff */
3873b3a8eb9SGleb Smirnoff int
eval_pfqueue(struct pfctl * pf,struct pf_altq * pa,struct node_queue_bw * bw,struct node_queue_opt * opts)3883b3a8eb9SGleb Smirnoff eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
3893b3a8eb9SGleb Smirnoff struct node_queue_opt *opts)
3903b3a8eb9SGleb Smirnoff {
3913b3a8eb9SGleb Smirnoff /* should be merged with expand_queue */
3921d34c9daSPatrick Kelsey struct pfctl_altq *if_ppa, *parent;
3933b3a8eb9SGleb Smirnoff int error = 0;
3943b3a8eb9SGleb Smirnoff
3953b3a8eb9SGleb Smirnoff /* find the corresponding interface and copy fields used by queues */
3961d34c9daSPatrick Kelsey if ((if_ppa = pfaltq_lookup(pa->ifname)) == NULL) {
3973b3a8eb9SGleb Smirnoff fprintf(stderr, "altq not defined on %s\n", pa->ifname);
3983b3a8eb9SGleb Smirnoff return (1);
3993b3a8eb9SGleb Smirnoff }
4001d34c9daSPatrick Kelsey pa->scheduler = if_ppa->pa.scheduler;
4011d34c9daSPatrick Kelsey pa->ifbandwidth = if_ppa->pa.ifbandwidth;
4023b3a8eb9SGleb Smirnoff
4033b3a8eb9SGleb Smirnoff if (qname_to_pfaltq(pa->qname, pa->ifname) != NULL) {
4043b3a8eb9SGleb Smirnoff fprintf(stderr, "queue %s already exists on interface %s\n",
4053b3a8eb9SGleb Smirnoff pa->qname, pa->ifname);
4063b3a8eb9SGleb Smirnoff return (1);
4073b3a8eb9SGleb Smirnoff }
4083b3a8eb9SGleb Smirnoff pa->qid = qname_to_qid(pa->qname);
4093b3a8eb9SGleb Smirnoff
4103b3a8eb9SGleb Smirnoff parent = NULL;
4113b3a8eb9SGleb Smirnoff if (pa->parent[0] != 0) {
4123b3a8eb9SGleb Smirnoff parent = qname_to_pfaltq(pa->parent, pa->ifname);
4133b3a8eb9SGleb Smirnoff if (parent == NULL) {
4143b3a8eb9SGleb Smirnoff fprintf(stderr, "parent %s not found for %s\n",
4153b3a8eb9SGleb Smirnoff pa->parent, pa->qname);
4163b3a8eb9SGleb Smirnoff return (1);
4173b3a8eb9SGleb Smirnoff }
4181d34c9daSPatrick Kelsey pa->parent_qid = parent->pa.qid;
4193b3a8eb9SGleb Smirnoff }
4203b3a8eb9SGleb Smirnoff if (pa->qlimit == 0)
4213b3a8eb9SGleb Smirnoff pa->qlimit = DEFAULT_QLIMIT;
4223b3a8eb9SGleb Smirnoff
423a5b789f6SErmal Luçi if (pa->scheduler == ALTQT_CBQ || pa->scheduler == ALTQT_HFSC ||
424a5b789f6SErmal Luçi pa->scheduler == ALTQT_FAIRQ) {
4253b3a8eb9SGleb Smirnoff pa->bandwidth = eval_bwspec(bw,
4261d34c9daSPatrick Kelsey parent == NULL ? pa->ifbandwidth : parent->pa.bandwidth);
4271d34c9daSPatrick Kelsey
4283b3a8eb9SGleb Smirnoff if (pa->bandwidth > pa->ifbandwidth) {
4293b3a8eb9SGleb Smirnoff fprintf(stderr, "bandwidth for %s higher than "
4303b3a8eb9SGleb Smirnoff "interface\n", pa->qname);
4313b3a8eb9SGleb Smirnoff return (1);
4323b3a8eb9SGleb Smirnoff }
43399766730SPatrick Kelsey /*
43499766730SPatrick Kelsey * If not HFSC, then check that the sum of the child
43599766730SPatrick Kelsey * bandwidths is less than the parent's bandwidth. For
43699766730SPatrick Kelsey * HFSC, the equivalent concept is to check that the sum of
43799766730SPatrick Kelsey * the child linkshare service curves are under the parent's
43899766730SPatrick Kelsey * linkshare service curve, and that check is performed by
43999766730SPatrick Kelsey * eval_pfqueue_hfsc().
44099766730SPatrick Kelsey */
44199766730SPatrick Kelsey if ((parent != NULL) && (pa->scheduler != ALTQT_HFSC)) {
4421d34c9daSPatrick Kelsey if (pa->bandwidth > parent->pa.bandwidth) {
4433b3a8eb9SGleb Smirnoff warnx("bandwidth for %s higher than parent",
4443b3a8eb9SGleb Smirnoff pa->qname);
4453b3a8eb9SGleb Smirnoff return (1);
4463b3a8eb9SGleb Smirnoff }
4471d34c9daSPatrick Kelsey parent->meta.bwsum += pa->bandwidth;
4481d34c9daSPatrick Kelsey if (parent->meta.bwsum > parent->pa.bandwidth) {
4491d34c9daSPatrick Kelsey warnx("the sum of the child bandwidth (%" PRIu64
4501d34c9daSPatrick Kelsey ") higher than parent \"%s\" (%" PRIu64 ")",
4511d34c9daSPatrick Kelsey parent->meta.bwsum, parent->pa.qname,
4521d34c9daSPatrick Kelsey parent->pa.bandwidth);
4533b3a8eb9SGleb Smirnoff }
4543b3a8eb9SGleb Smirnoff }
4553b3a8eb9SGleb Smirnoff }
4563b3a8eb9SGleb Smirnoff
45799766730SPatrick Kelsey if (eval_queue_opts(pa, opts,
45899766730SPatrick Kelsey parent == NULL ? pa->ifbandwidth : parent->pa.bandwidth))
45999766730SPatrick Kelsey return (1);
46099766730SPatrick Kelsey
4611d34c9daSPatrick Kelsey if (parent != NULL)
4621d34c9daSPatrick Kelsey parent->meta.children++;
4633b3a8eb9SGleb Smirnoff
4643b3a8eb9SGleb Smirnoff switch (pa->scheduler) {
4653b3a8eb9SGleb Smirnoff case ALTQT_CBQ:
4661d34c9daSPatrick Kelsey error = eval_pfqueue_cbq(pf, pa, if_ppa);
4673b3a8eb9SGleb Smirnoff break;
4683b3a8eb9SGleb Smirnoff case ALTQT_PRIQ:
4691d34c9daSPatrick Kelsey error = eval_pfqueue_priq(pf, pa, if_ppa);
4703b3a8eb9SGleb Smirnoff break;
4713b3a8eb9SGleb Smirnoff case ALTQT_HFSC:
4721d34c9daSPatrick Kelsey error = eval_pfqueue_hfsc(pf, pa, if_ppa, parent);
4733b3a8eb9SGleb Smirnoff break;
474a5b789f6SErmal Luçi case ALTQT_FAIRQ:
4751d34c9daSPatrick Kelsey error = eval_pfqueue_fairq(pf, pa, if_ppa, parent);
476a5b789f6SErmal Luçi break;
4773b3a8eb9SGleb Smirnoff default:
4783b3a8eb9SGleb Smirnoff break;
4793b3a8eb9SGleb Smirnoff }
4803b3a8eb9SGleb Smirnoff return (error);
4813b3a8eb9SGleb Smirnoff }
4823b3a8eb9SGleb Smirnoff
4833b3a8eb9SGleb Smirnoff /*
4843b3a8eb9SGleb Smirnoff * CBQ support functions
4853b3a8eb9SGleb Smirnoff */
4863b3a8eb9SGleb Smirnoff #define RM_FILTER_GAIN 5 /* log2 of gain, e.g., 5 => 31/32 */
4873b3a8eb9SGleb Smirnoff #define RM_NS_PER_SEC (1000000000)
4883b3a8eb9SGleb Smirnoff
4893b3a8eb9SGleb Smirnoff static int
eval_pfqueue_cbq(struct pfctl * pf,struct pf_altq * pa,struct pfctl_altq * if_ppa)4901d34c9daSPatrick Kelsey eval_pfqueue_cbq(struct pfctl *pf, struct pf_altq *pa, struct pfctl_altq *if_ppa)
4913b3a8eb9SGleb Smirnoff {
4923b3a8eb9SGleb Smirnoff struct cbq_opts *opts;
4933b3a8eb9SGleb Smirnoff u_int ifmtu;
4943b3a8eb9SGleb Smirnoff
4953b3a8eb9SGleb Smirnoff if (pa->priority >= CBQ_MAXPRI) {
4963b3a8eb9SGleb Smirnoff warnx("priority out of range: max %d", CBQ_MAXPRI - 1);
4973b3a8eb9SGleb Smirnoff return (-1);
4983b3a8eb9SGleb Smirnoff }
4993b3a8eb9SGleb Smirnoff
5003b3a8eb9SGleb Smirnoff ifmtu = getifmtu(pa->ifname);
5013b3a8eb9SGleb Smirnoff opts = &pa->pq_u.cbq_opts;
5023b3a8eb9SGleb Smirnoff
5033b3a8eb9SGleb Smirnoff if (opts->pktsize == 0) { /* use default */
5043b3a8eb9SGleb Smirnoff opts->pktsize = ifmtu;
5053b3a8eb9SGleb Smirnoff if (opts->pktsize > MCLBYTES) /* do what TCP does */
5063b3a8eb9SGleb Smirnoff opts->pktsize &= ~MCLBYTES;
5073b3a8eb9SGleb Smirnoff } else if (opts->pktsize > ifmtu)
5083b3a8eb9SGleb Smirnoff opts->pktsize = ifmtu;
5093b3a8eb9SGleb Smirnoff if (opts->maxpktsize == 0) /* use default */
5103b3a8eb9SGleb Smirnoff opts->maxpktsize = ifmtu;
5113b3a8eb9SGleb Smirnoff else if (opts->maxpktsize > ifmtu)
5123b3a8eb9SGleb Smirnoff opts->pktsize = ifmtu;
5133b3a8eb9SGleb Smirnoff
5143b3a8eb9SGleb Smirnoff if (opts->pktsize > opts->maxpktsize)
5153b3a8eb9SGleb Smirnoff opts->pktsize = opts->maxpktsize;
5163b3a8eb9SGleb Smirnoff
5173b3a8eb9SGleb Smirnoff if (pa->parent[0] == 0)
5183b3a8eb9SGleb Smirnoff opts->flags |= (CBQCLF_ROOTCLASS | CBQCLF_WRR);
5193b3a8eb9SGleb Smirnoff
5201d34c9daSPatrick Kelsey if (pa->pq_u.cbq_opts.flags & CBQCLF_ROOTCLASS)
5211d34c9daSPatrick Kelsey if_ppa->meta.root_classes++;
5221d34c9daSPatrick Kelsey if (pa->pq_u.cbq_opts.flags & CBQCLF_DEFCLASS)
5231d34c9daSPatrick Kelsey if_ppa->meta.default_classes++;
5241d34c9daSPatrick Kelsey
5253b3a8eb9SGleb Smirnoff cbq_compute_idletime(pf, pa);
5263b3a8eb9SGleb Smirnoff return (0);
5273b3a8eb9SGleb Smirnoff }
5283b3a8eb9SGleb Smirnoff
5293b3a8eb9SGleb Smirnoff /*
5303b3a8eb9SGleb Smirnoff * compute ns_per_byte, maxidle, minidle, and offtime
5313b3a8eb9SGleb Smirnoff */
5323b3a8eb9SGleb Smirnoff static int
cbq_compute_idletime(struct pfctl * pf,struct pf_altq * pa)5333b3a8eb9SGleb Smirnoff cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa)
5343b3a8eb9SGleb Smirnoff {
5353b3a8eb9SGleb Smirnoff struct cbq_opts *opts;
5363b3a8eb9SGleb Smirnoff double maxidle_s, maxidle, minidle;
5373b3a8eb9SGleb Smirnoff double offtime, nsPerByte, ifnsPerByte, ptime, cptime;
5383b3a8eb9SGleb Smirnoff double z, g, f, gton, gtom;
5393b3a8eb9SGleb Smirnoff u_int minburst, maxburst;
5403b3a8eb9SGleb Smirnoff
5413b3a8eb9SGleb Smirnoff opts = &pa->pq_u.cbq_opts;
5423b3a8eb9SGleb Smirnoff ifnsPerByte = (1.0 / (double)pa->ifbandwidth) * RM_NS_PER_SEC * 8;
5433b3a8eb9SGleb Smirnoff minburst = opts->minburst;
5443b3a8eb9SGleb Smirnoff maxburst = opts->maxburst;
5453b3a8eb9SGleb Smirnoff
5463b3a8eb9SGleb Smirnoff if (pa->bandwidth == 0)
5473b3a8eb9SGleb Smirnoff f = 0.0001; /* small enough? */
5483b3a8eb9SGleb Smirnoff else
5493b3a8eb9SGleb Smirnoff f = ((double) pa->bandwidth / (double) pa->ifbandwidth);
5503b3a8eb9SGleb Smirnoff
5513b3a8eb9SGleb Smirnoff nsPerByte = ifnsPerByte / f;
5523b3a8eb9SGleb Smirnoff ptime = (double)opts->pktsize * ifnsPerByte;
5533b3a8eb9SGleb Smirnoff cptime = ptime * (1.0 - f) / f;
5543b3a8eb9SGleb Smirnoff
5553b3a8eb9SGleb Smirnoff if (nsPerByte * (double)opts->maxpktsize > (double)INT_MAX) {
5563b3a8eb9SGleb Smirnoff /*
5573b3a8eb9SGleb Smirnoff * this causes integer overflow in kernel!
5583b3a8eb9SGleb Smirnoff * (bandwidth < 6Kbps when max_pkt_size=1500)
5593b3a8eb9SGleb Smirnoff */
5602d0730b2SSean Bruno if (pa->bandwidth != 0 && (pf->opts & PF_OPT_QUIET) == 0) {
5613b3a8eb9SGleb Smirnoff warnx("queue bandwidth must be larger than %s",
5623b3a8eb9SGleb Smirnoff rate2str(ifnsPerByte * (double)opts->maxpktsize /
5633b3a8eb9SGleb Smirnoff (double)INT_MAX * (double)pa->ifbandwidth));
5643b3a8eb9SGleb Smirnoff fprintf(stderr, "cbq: queue %s is too slow!\n",
5653b3a8eb9SGleb Smirnoff pa->qname);
5662d0730b2SSean Bruno }
5673b3a8eb9SGleb Smirnoff nsPerByte = (double)(INT_MAX / opts->maxpktsize);
5683b3a8eb9SGleb Smirnoff }
5693b3a8eb9SGleb Smirnoff
5703b3a8eb9SGleb Smirnoff if (maxburst == 0) { /* use default */
5713b3a8eb9SGleb Smirnoff if (cptime > 10.0 * 1000000)
5723b3a8eb9SGleb Smirnoff maxburst = 4;
5733b3a8eb9SGleb Smirnoff else
5743b3a8eb9SGleb Smirnoff maxburst = 16;
5753b3a8eb9SGleb Smirnoff }
5763b3a8eb9SGleb Smirnoff if (minburst == 0) /* use default */
5773b3a8eb9SGleb Smirnoff minburst = 2;
5783b3a8eb9SGleb Smirnoff if (minburst > maxburst)
5793b3a8eb9SGleb Smirnoff minburst = maxburst;
5803b3a8eb9SGleb Smirnoff
5813b3a8eb9SGleb Smirnoff z = (double)(1 << RM_FILTER_GAIN);
5823b3a8eb9SGleb Smirnoff g = (1.0 - 1.0 / z);
5833b3a8eb9SGleb Smirnoff gton = pow(g, (double)maxburst);
5843b3a8eb9SGleb Smirnoff gtom = pow(g, (double)(minburst-1));
5853b3a8eb9SGleb Smirnoff maxidle = ((1.0 / f - 1.0) * ((1.0 - gton) / gton));
5863b3a8eb9SGleb Smirnoff maxidle_s = (1.0 - g);
5873b3a8eb9SGleb Smirnoff if (maxidle > maxidle_s)
5883b3a8eb9SGleb Smirnoff maxidle = ptime * maxidle;
5893b3a8eb9SGleb Smirnoff else
5903b3a8eb9SGleb Smirnoff maxidle = ptime * maxidle_s;
5913b3a8eb9SGleb Smirnoff offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom);
5923b3a8eb9SGleb Smirnoff minidle = -((double)opts->maxpktsize * (double)nsPerByte);
5933b3a8eb9SGleb Smirnoff
5943b3a8eb9SGleb Smirnoff /* scale parameters */
5953b3a8eb9SGleb Smirnoff maxidle = ((maxidle * 8.0) / nsPerByte) *
5963b3a8eb9SGleb Smirnoff pow(2.0, (double)RM_FILTER_GAIN);
5973b3a8eb9SGleb Smirnoff offtime = (offtime * 8.0) / nsPerByte *
5983b3a8eb9SGleb Smirnoff pow(2.0, (double)RM_FILTER_GAIN);
5993b3a8eb9SGleb Smirnoff minidle = ((minidle * 8.0) / nsPerByte) *
6003b3a8eb9SGleb Smirnoff pow(2.0, (double)RM_FILTER_GAIN);
6013b3a8eb9SGleb Smirnoff
6023b3a8eb9SGleb Smirnoff maxidle = maxidle / 1000.0;
6033b3a8eb9SGleb Smirnoff offtime = offtime / 1000.0;
6043b3a8eb9SGleb Smirnoff minidle = minidle / 1000.0;
6053b3a8eb9SGleb Smirnoff
6063b3a8eb9SGleb Smirnoff opts->minburst = minburst;
6073b3a8eb9SGleb Smirnoff opts->maxburst = maxburst;
6083b3a8eb9SGleb Smirnoff opts->ns_per_byte = (u_int)nsPerByte;
6093b3a8eb9SGleb Smirnoff opts->maxidle = (u_int)fabs(maxidle);
6103b3a8eb9SGleb Smirnoff opts->minidle = (int)minidle;
6113b3a8eb9SGleb Smirnoff opts->offtime = (u_int)fabs(offtime);
6123b3a8eb9SGleb Smirnoff
6133b3a8eb9SGleb Smirnoff return (0);
6143b3a8eb9SGleb Smirnoff }
6153b3a8eb9SGleb Smirnoff
6163b3a8eb9SGleb Smirnoff static int
check_commit_cbq(int dev,int opts,struct pfctl_altq * if_ppa)6171d34c9daSPatrick Kelsey check_commit_cbq(int dev, int opts, struct pfctl_altq *if_ppa)
6183b3a8eb9SGleb Smirnoff {
6193b3a8eb9SGleb Smirnoff int error = 0;
6203b3a8eb9SGleb Smirnoff
6213b3a8eb9SGleb Smirnoff /*
6223b3a8eb9SGleb Smirnoff * check if cbq has one root queue and one default queue
6233b3a8eb9SGleb Smirnoff * for this interface
6243b3a8eb9SGleb Smirnoff */
6251d34c9daSPatrick Kelsey if (if_ppa->meta.root_classes != 1) {
6261d34c9daSPatrick Kelsey warnx("should have one root queue on %s", if_ppa->pa.ifname);
6273b3a8eb9SGleb Smirnoff error++;
6283b3a8eb9SGleb Smirnoff }
6291d34c9daSPatrick Kelsey if (if_ppa->meta.default_classes != 1) {
6301d34c9daSPatrick Kelsey warnx("should have one default queue on %s", if_ppa->pa.ifname);
6313b3a8eb9SGleb Smirnoff error++;
6323b3a8eb9SGleb Smirnoff }
6333b3a8eb9SGleb Smirnoff return (error);
6343b3a8eb9SGleb Smirnoff }
6353b3a8eb9SGleb Smirnoff
6363b3a8eb9SGleb Smirnoff static int
print_cbq_opts(const struct pf_altq * a)6373b3a8eb9SGleb Smirnoff print_cbq_opts(const struct pf_altq *a)
6383b3a8eb9SGleb Smirnoff {
6393b3a8eb9SGleb Smirnoff const struct cbq_opts *opts;
6403b3a8eb9SGleb Smirnoff
6413b3a8eb9SGleb Smirnoff opts = &a->pq_u.cbq_opts;
6423b3a8eb9SGleb Smirnoff if (opts->flags) {
6433b3a8eb9SGleb Smirnoff printf("cbq(");
6443b3a8eb9SGleb Smirnoff if (opts->flags & CBQCLF_RED)
6453b3a8eb9SGleb Smirnoff printf(" red");
6463b3a8eb9SGleb Smirnoff if (opts->flags & CBQCLF_ECN)
6473b3a8eb9SGleb Smirnoff printf(" ecn");
6483b3a8eb9SGleb Smirnoff if (opts->flags & CBQCLF_RIO)
6493b3a8eb9SGleb Smirnoff printf(" rio");
6500a70aaf8SLuiz Otavio O Souza if (opts->flags & CBQCLF_CODEL)
6510a70aaf8SLuiz Otavio O Souza printf(" codel");
6523b3a8eb9SGleb Smirnoff if (opts->flags & CBQCLF_CLEARDSCP)
6533b3a8eb9SGleb Smirnoff printf(" cleardscp");
6543b3a8eb9SGleb Smirnoff if (opts->flags & CBQCLF_FLOWVALVE)
6553b3a8eb9SGleb Smirnoff printf(" flowvalve");
6563b3a8eb9SGleb Smirnoff if (opts->flags & CBQCLF_BORROW)
6573b3a8eb9SGleb Smirnoff printf(" borrow");
6583b3a8eb9SGleb Smirnoff if (opts->flags & CBQCLF_WRR)
6593b3a8eb9SGleb Smirnoff printf(" wrr");
6603b3a8eb9SGleb Smirnoff if (opts->flags & CBQCLF_EFFICIENT)
6613b3a8eb9SGleb Smirnoff printf(" efficient");
6623b3a8eb9SGleb Smirnoff if (opts->flags & CBQCLF_ROOTCLASS)
6633b3a8eb9SGleb Smirnoff printf(" root");
6643b3a8eb9SGleb Smirnoff if (opts->flags & CBQCLF_DEFCLASS)
6653b3a8eb9SGleb Smirnoff printf(" default");
6663b3a8eb9SGleb Smirnoff printf(" ) ");
6673b3a8eb9SGleb Smirnoff
6683b3a8eb9SGleb Smirnoff return (1);
6693b3a8eb9SGleb Smirnoff } else
6703b3a8eb9SGleb Smirnoff return (0);
6713b3a8eb9SGleb Smirnoff }
6723b3a8eb9SGleb Smirnoff
6733b3a8eb9SGleb Smirnoff /*
6743b3a8eb9SGleb Smirnoff * PRIQ support functions
6753b3a8eb9SGleb Smirnoff */
6763b3a8eb9SGleb Smirnoff static int
eval_pfqueue_priq(struct pfctl * pf,struct pf_altq * pa,struct pfctl_altq * if_ppa)6771d34c9daSPatrick Kelsey eval_pfqueue_priq(struct pfctl *pf, struct pf_altq *pa, struct pfctl_altq *if_ppa)
6783b3a8eb9SGleb Smirnoff {
6793b3a8eb9SGleb Smirnoff
6803b3a8eb9SGleb Smirnoff if (pa->priority >= PRIQ_MAXPRI) {
6813b3a8eb9SGleb Smirnoff warnx("priority out of range: max %d", PRIQ_MAXPRI - 1);
6823b3a8eb9SGleb Smirnoff return (-1);
6833b3a8eb9SGleb Smirnoff }
6841d34c9daSPatrick Kelsey if (BIT_ISSET(QPRI_BITSET_SIZE, pa->priority, &if_ppa->meta.qpris)) {
6851d34c9daSPatrick Kelsey warnx("%s does not have a unique priority on interface %s",
6861d34c9daSPatrick Kelsey pa->qname, pa->ifname);
6873b3a8eb9SGleb Smirnoff return (-1);
6881d34c9daSPatrick Kelsey } else
6891d34c9daSPatrick Kelsey BIT_SET(QPRI_BITSET_SIZE, pa->priority, &if_ppa->meta.qpris);
6903b3a8eb9SGleb Smirnoff
6911d34c9daSPatrick Kelsey if (pa->pq_u.priq_opts.flags & PRCF_DEFAULTCLASS)
6921d34c9daSPatrick Kelsey if_ppa->meta.default_classes++;
6933b3a8eb9SGleb Smirnoff return (0);
6943b3a8eb9SGleb Smirnoff }
6953b3a8eb9SGleb Smirnoff
6963b3a8eb9SGleb Smirnoff static int
check_commit_priq(int dev,int opts,struct pfctl_altq * if_ppa)6971d34c9daSPatrick Kelsey check_commit_priq(int dev, int opts, struct pfctl_altq *if_ppa)
6983b3a8eb9SGleb Smirnoff {
6993b3a8eb9SGleb Smirnoff
7003b3a8eb9SGleb Smirnoff /*
7013b3a8eb9SGleb Smirnoff * check if priq has one default class for this interface
7023b3a8eb9SGleb Smirnoff */
7031d34c9daSPatrick Kelsey if (if_ppa->meta.default_classes != 1) {
7041d34c9daSPatrick Kelsey warnx("should have one default queue on %s", if_ppa->pa.ifname);
7051d34c9daSPatrick Kelsey return (1);
7063b3a8eb9SGleb Smirnoff }
7071d34c9daSPatrick Kelsey return (0);
7083b3a8eb9SGleb Smirnoff }
7093b3a8eb9SGleb Smirnoff
7103b3a8eb9SGleb Smirnoff static int
print_priq_opts(const struct pf_altq * a)7113b3a8eb9SGleb Smirnoff print_priq_opts(const struct pf_altq *a)
7123b3a8eb9SGleb Smirnoff {
7133b3a8eb9SGleb Smirnoff const struct priq_opts *opts;
7143b3a8eb9SGleb Smirnoff
7153b3a8eb9SGleb Smirnoff opts = &a->pq_u.priq_opts;
7163b3a8eb9SGleb Smirnoff
7173b3a8eb9SGleb Smirnoff if (opts->flags) {
7183b3a8eb9SGleb Smirnoff printf("priq(");
7193b3a8eb9SGleb Smirnoff if (opts->flags & PRCF_RED)
7203b3a8eb9SGleb Smirnoff printf(" red");
7213b3a8eb9SGleb Smirnoff if (opts->flags & PRCF_ECN)
7223b3a8eb9SGleb Smirnoff printf(" ecn");
7233b3a8eb9SGleb Smirnoff if (opts->flags & PRCF_RIO)
7243b3a8eb9SGleb Smirnoff printf(" rio");
7250a70aaf8SLuiz Otavio O Souza if (opts->flags & PRCF_CODEL)
7260a70aaf8SLuiz Otavio O Souza printf(" codel");
7273b3a8eb9SGleb Smirnoff if (opts->flags & PRCF_CLEARDSCP)
7283b3a8eb9SGleb Smirnoff printf(" cleardscp");
7293b3a8eb9SGleb Smirnoff if (opts->flags & PRCF_DEFAULTCLASS)
7303b3a8eb9SGleb Smirnoff printf(" default");
7313b3a8eb9SGleb Smirnoff printf(" ) ");
7323b3a8eb9SGleb Smirnoff
7333b3a8eb9SGleb Smirnoff return (1);
7343b3a8eb9SGleb Smirnoff } else
7353b3a8eb9SGleb Smirnoff return (0);
7363b3a8eb9SGleb Smirnoff }
7373b3a8eb9SGleb Smirnoff
7383b3a8eb9SGleb Smirnoff /*
7393b3a8eb9SGleb Smirnoff * HFSC support functions
7403b3a8eb9SGleb Smirnoff */
7413b3a8eb9SGleb Smirnoff static int
eval_pfqueue_hfsc(struct pfctl * pf,struct pf_altq * pa,struct pfctl_altq * if_ppa,struct pfctl_altq * parent)7421d34c9daSPatrick Kelsey eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa, struct pfctl_altq *if_ppa,
7431d34c9daSPatrick Kelsey struct pfctl_altq *parent)
7443b3a8eb9SGleb Smirnoff {
745249cc75fSPatrick Kelsey struct hfsc_opts_v1 *opts;
7463b3a8eb9SGleb Smirnoff struct service_curve sc;
7473b3a8eb9SGleb Smirnoff
7483b3a8eb9SGleb Smirnoff opts = &pa->pq_u.hfsc_opts;
7493b3a8eb9SGleb Smirnoff
7501d34c9daSPatrick Kelsey if (parent == NULL) {
7513b3a8eb9SGleb Smirnoff /* root queue */
7523b3a8eb9SGleb Smirnoff opts->lssc_m1 = pa->ifbandwidth;
7533b3a8eb9SGleb Smirnoff opts->lssc_m2 = pa->ifbandwidth;
7543b3a8eb9SGleb Smirnoff opts->lssc_d = 0;
7553b3a8eb9SGleb Smirnoff return (0);
7563b3a8eb9SGleb Smirnoff }
7573b3a8eb9SGleb Smirnoff
7581d34c9daSPatrick Kelsey /* First child initializes the parent's service curve accumulators. */
7591d34c9daSPatrick Kelsey if (parent->meta.children == 1) {
7601d34c9daSPatrick Kelsey LIST_INIT(&parent->meta.rtsc);
7611d34c9daSPatrick Kelsey LIST_INIT(&parent->meta.lssc);
7621d34c9daSPatrick Kelsey }
7631d34c9daSPatrick Kelsey
7641d34c9daSPatrick Kelsey if (parent->pa.pq_u.hfsc_opts.flags & HFCF_DEFAULTCLASS) {
7651d34c9daSPatrick Kelsey warnx("adding %s would make default queue %s not a leaf",
7661d34c9daSPatrick Kelsey pa->qname, pa->parent);
7671d34c9daSPatrick Kelsey return (-1);
7681d34c9daSPatrick Kelsey }
7691d34c9daSPatrick Kelsey
7701d34c9daSPatrick Kelsey if (pa->pq_u.hfsc_opts.flags & HFCF_DEFAULTCLASS)
7711d34c9daSPatrick Kelsey if_ppa->meta.default_classes++;
7723b3a8eb9SGleb Smirnoff
7733b3a8eb9SGleb Smirnoff /* if link_share is not specified, use bandwidth */
7743b3a8eb9SGleb Smirnoff if (opts->lssc_m2 == 0)
7753b3a8eb9SGleb Smirnoff opts->lssc_m2 = pa->bandwidth;
7763b3a8eb9SGleb Smirnoff
7773b3a8eb9SGleb Smirnoff if ((opts->rtsc_m1 > 0 && opts->rtsc_m2 == 0) ||
7783b3a8eb9SGleb Smirnoff (opts->lssc_m1 > 0 && opts->lssc_m2 == 0) ||
7793b3a8eb9SGleb Smirnoff (opts->ulsc_m1 > 0 && opts->ulsc_m2 == 0)) {
7803b3a8eb9SGleb Smirnoff warnx("m2 is zero for %s", pa->qname);
7813b3a8eb9SGleb Smirnoff return (-1);
7823b3a8eb9SGleb Smirnoff }
7833b3a8eb9SGleb Smirnoff
7843b3a8eb9SGleb Smirnoff if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) ||
7853b3a8eb9SGleb Smirnoff (opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) ||
7863b3a8eb9SGleb Smirnoff (opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) {
7873b3a8eb9SGleb Smirnoff warnx("m1 must be zero for convex curve: %s", pa->qname);
7883b3a8eb9SGleb Smirnoff return (-1);
7893b3a8eb9SGleb Smirnoff }
7903b3a8eb9SGleb Smirnoff
7913b3a8eb9SGleb Smirnoff /*
7923b3a8eb9SGleb Smirnoff * admission control:
7933b3a8eb9SGleb Smirnoff * for the real-time service curve, the sum of the service curves
7943b3a8eb9SGleb Smirnoff * should not exceed 80% of the interface bandwidth. 20% is reserved
7953b3a8eb9SGleb Smirnoff * not to over-commit the actual interface bandwidth.
7963b3a8eb9SGleb Smirnoff * for the linkshare service curve, the sum of the child service
7973b3a8eb9SGleb Smirnoff * curve should not exceed the parent service curve.
7983b3a8eb9SGleb Smirnoff * for the upper-limit service curve, the assigned bandwidth should
7993b3a8eb9SGleb Smirnoff * be smaller than the interface bandwidth, and the upper-limit should
8003b3a8eb9SGleb Smirnoff * be larger than the real-time service curve when both are defined.
8013b3a8eb9SGleb Smirnoff */
8023b3a8eb9SGleb Smirnoff
8033b3a8eb9SGleb Smirnoff /* check the real-time service curve. reserve 20% of interface bw */
8043b3a8eb9SGleb Smirnoff if (opts->rtsc_m2 != 0) {
8053b3a8eb9SGleb Smirnoff /* add this queue to the sum */
8063b3a8eb9SGleb Smirnoff sc.m1 = opts->rtsc_m1;
8073b3a8eb9SGleb Smirnoff sc.d = opts->rtsc_d;
8083b3a8eb9SGleb Smirnoff sc.m2 = opts->rtsc_m2;
8091d34c9daSPatrick Kelsey gsc_add_sc(&parent->meta.rtsc, &sc);
8103b3a8eb9SGleb Smirnoff /* compare the sum with 80% of the interface */
8113b3a8eb9SGleb Smirnoff sc.m1 = 0;
8123b3a8eb9SGleb Smirnoff sc.d = 0;
8133b3a8eb9SGleb Smirnoff sc.m2 = pa->ifbandwidth / 100 * 80;
8141d34c9daSPatrick Kelsey if (!is_gsc_under_sc(&parent->meta.rtsc, &sc)) {
8153b3a8eb9SGleb Smirnoff warnx("real-time sc exceeds 80%% of the interface "
8163b3a8eb9SGleb Smirnoff "bandwidth (%s)", rate2str((double)sc.m2));
8171d34c9daSPatrick Kelsey return (-1);
8183b3a8eb9SGleb Smirnoff }
8193b3a8eb9SGleb Smirnoff }
8203b3a8eb9SGleb Smirnoff
8213b3a8eb9SGleb Smirnoff /* check the linkshare service curve. */
8223b3a8eb9SGleb Smirnoff if (opts->lssc_m2 != 0) {
8233b3a8eb9SGleb Smirnoff /* add this queue to the child sum */
8243b3a8eb9SGleb Smirnoff sc.m1 = opts->lssc_m1;
8253b3a8eb9SGleb Smirnoff sc.d = opts->lssc_d;
8263b3a8eb9SGleb Smirnoff sc.m2 = opts->lssc_m2;
8271d34c9daSPatrick Kelsey gsc_add_sc(&parent->meta.lssc, &sc);
8283b3a8eb9SGleb Smirnoff /* compare the sum of the children with parent's sc */
8291d34c9daSPatrick Kelsey sc.m1 = parent->pa.pq_u.hfsc_opts.lssc_m1;
8301d34c9daSPatrick Kelsey sc.d = parent->pa.pq_u.hfsc_opts.lssc_d;
8311d34c9daSPatrick Kelsey sc.m2 = parent->pa.pq_u.hfsc_opts.lssc_m2;
8321d34c9daSPatrick Kelsey if (!is_gsc_under_sc(&parent->meta.lssc, &sc)) {
8333b3a8eb9SGleb Smirnoff warnx("linkshare sc exceeds parent's sc");
8341d34c9daSPatrick Kelsey return (-1);
8353b3a8eb9SGleb Smirnoff }
8363b3a8eb9SGleb Smirnoff }
8373b3a8eb9SGleb Smirnoff
8383b3a8eb9SGleb Smirnoff /* check the upper-limit service curve. */
8393b3a8eb9SGleb Smirnoff if (opts->ulsc_m2 != 0) {
8403b3a8eb9SGleb Smirnoff if (opts->ulsc_m1 > pa->ifbandwidth ||
8413b3a8eb9SGleb Smirnoff opts->ulsc_m2 > pa->ifbandwidth) {
8423b3a8eb9SGleb Smirnoff warnx("upper-limit larger than interface bandwidth");
8431d34c9daSPatrick Kelsey return (-1);
8443b3a8eb9SGleb Smirnoff }
8453b3a8eb9SGleb Smirnoff if (opts->rtsc_m2 != 0 && opts->rtsc_m2 > opts->ulsc_m2) {
8463b3a8eb9SGleb Smirnoff warnx("upper-limit sc smaller than real-time sc");
8471d34c9daSPatrick Kelsey return (-1);
8483b3a8eb9SGleb Smirnoff }
8493b3a8eb9SGleb Smirnoff }
8503b3a8eb9SGleb Smirnoff
8513b3a8eb9SGleb Smirnoff return (0);
8523b3a8eb9SGleb Smirnoff }
8533b3a8eb9SGleb Smirnoff
854a5b789f6SErmal Luçi /*
855a5b789f6SErmal Luçi * FAIRQ support functions
856a5b789f6SErmal Luçi */
857a5b789f6SErmal Luçi static int
eval_pfqueue_fairq(struct pfctl * pf __unused,struct pf_altq * pa,struct pfctl_altq * if_ppa,struct pfctl_altq * parent)8581d34c9daSPatrick Kelsey eval_pfqueue_fairq(struct pfctl *pf __unused, struct pf_altq *pa,
8591d34c9daSPatrick Kelsey struct pfctl_altq *if_ppa, struct pfctl_altq *parent)
860a5b789f6SErmal Luçi {
861a5b789f6SErmal Luçi struct fairq_opts *opts;
862a5b789f6SErmal Luçi struct service_curve sc;
863a5b789f6SErmal Luçi
864a5b789f6SErmal Luçi opts = &pa->pq_u.fairq_opts;
865a5b789f6SErmal Luçi
86626705a39SKristof Provost if (parent == NULL) {
867a5b789f6SErmal Luçi /* root queue */
868a5b789f6SErmal Luçi opts->lssc_m1 = pa->ifbandwidth;
869a5b789f6SErmal Luçi opts->lssc_m2 = pa->ifbandwidth;
870a5b789f6SErmal Luçi opts->lssc_d = 0;
871a5b789f6SErmal Luçi return (0);
872a5b789f6SErmal Luçi }
873a5b789f6SErmal Luçi
8741d34c9daSPatrick Kelsey /* First child initializes the parent's service curve accumulator. */
8751d34c9daSPatrick Kelsey if (parent->meta.children == 1)
8761d34c9daSPatrick Kelsey LIST_INIT(&parent->meta.lssc);
8771d34c9daSPatrick Kelsey
8781d34c9daSPatrick Kelsey if (parent->pa.pq_u.fairq_opts.flags & FARF_DEFAULTCLASS) {
8791d34c9daSPatrick Kelsey warnx("adding %s would make default queue %s not a leaf",
8801d34c9daSPatrick Kelsey pa->qname, pa->parent);
8811d34c9daSPatrick Kelsey return (-1);
8821d34c9daSPatrick Kelsey }
8831d34c9daSPatrick Kelsey
8841d34c9daSPatrick Kelsey if (pa->pq_u.fairq_opts.flags & FARF_DEFAULTCLASS)
8851d34c9daSPatrick Kelsey if_ppa->meta.default_classes++;
886a5b789f6SErmal Luçi
887a5b789f6SErmal Luçi /* if link_share is not specified, use bandwidth */
888a5b789f6SErmal Luçi if (opts->lssc_m2 == 0)
889a5b789f6SErmal Luçi opts->lssc_m2 = pa->bandwidth;
890a5b789f6SErmal Luçi
891a5b789f6SErmal Luçi /*
892a5b789f6SErmal Luçi * admission control:
893a5b789f6SErmal Luçi * for the real-time service curve, the sum of the service curves
894a5b789f6SErmal Luçi * should not exceed 80% of the interface bandwidth. 20% is reserved
895a5b789f6SErmal Luçi * not to over-commit the actual interface bandwidth.
896a5b789f6SErmal Luçi * for the link-sharing service curve, the sum of the child service
897a5b789f6SErmal Luçi * curve should not exceed the parent service curve.
898a5b789f6SErmal Luçi * for the upper-limit service curve, the assigned bandwidth should
899a5b789f6SErmal Luçi * be smaller than the interface bandwidth, and the upper-limit should
900a5b789f6SErmal Luçi * be larger than the real-time service curve when both are defined.
901a5b789f6SErmal Luçi */
902a5b789f6SErmal Luçi
9031d34c9daSPatrick Kelsey /* check the linkshare service curve. */
904a5b789f6SErmal Luçi if (opts->lssc_m2 != 0) {
9051d34c9daSPatrick Kelsey /* add this queue to the child sum */
9061d34c9daSPatrick Kelsey sc.m1 = opts->lssc_m1;
9071d34c9daSPatrick Kelsey sc.d = opts->lssc_d;
9081d34c9daSPatrick Kelsey sc.m2 = opts->lssc_m2;
9091d34c9daSPatrick Kelsey gsc_add_sc(&parent->meta.lssc, &sc);
9101d34c9daSPatrick Kelsey /* compare the sum of the children with parent's sc */
9111d34c9daSPatrick Kelsey sc.m1 = parent->pa.pq_u.fairq_opts.lssc_m1;
9121d34c9daSPatrick Kelsey sc.d = parent->pa.pq_u.fairq_opts.lssc_d;
9131d34c9daSPatrick Kelsey sc.m2 = parent->pa.pq_u.fairq_opts.lssc_m2;
9141d34c9daSPatrick Kelsey if (!is_gsc_under_sc(&parent->meta.lssc, &sc)) {
915a5b789f6SErmal Luçi warnx("link-sharing sc exceeds parent's sc");
916a5b789f6SErmal Luçi return (-1);
917a5b789f6SErmal Luçi }
9181d34c9daSPatrick Kelsey }
9191d34c9daSPatrick Kelsey
9201d34c9daSPatrick Kelsey return (0);
9211d34c9daSPatrick Kelsey }
922a5b789f6SErmal Luçi
9233b3a8eb9SGleb Smirnoff static int
check_commit_hfsc(int dev,int opts,struct pfctl_altq * if_ppa)9241d34c9daSPatrick Kelsey check_commit_hfsc(int dev, int opts, struct pfctl_altq *if_ppa)
9253b3a8eb9SGleb Smirnoff {
9263b3a8eb9SGleb Smirnoff
9273b3a8eb9SGleb Smirnoff /* check if hfsc has one default queue for this interface */
9281d34c9daSPatrick Kelsey if (if_ppa->meta.default_classes != 1) {
9291d34c9daSPatrick Kelsey warnx("should have one default queue on %s", if_ppa->pa.ifname);
9303b3a8eb9SGleb Smirnoff return (1);
9313b3a8eb9SGleb Smirnoff }
9321d34c9daSPatrick Kelsey return (0);
9333b3a8eb9SGleb Smirnoff }
9343b3a8eb9SGleb Smirnoff
9353b3a8eb9SGleb Smirnoff static int
check_commit_fairq(int dev __unused,int opts __unused,struct pfctl_altq * if_ppa)9361d34c9daSPatrick Kelsey check_commit_fairq(int dev __unused, int opts __unused, struct pfctl_altq *if_ppa)
937a5b789f6SErmal Luçi {
938a5b789f6SErmal Luçi
939a5b789f6SErmal Luçi /* check if fairq has one default queue for this interface */
9401d34c9daSPatrick Kelsey if (if_ppa->meta.default_classes != 1) {
9411d34c9daSPatrick Kelsey warnx("should have one default queue on %s", if_ppa->pa.ifname);
942a5b789f6SErmal Luçi return (1);
943a5b789f6SErmal Luçi }
9441d34c9daSPatrick Kelsey return (0);
945a5b789f6SErmal Luçi }
946a5b789f6SErmal Luçi
947a5b789f6SErmal Luçi static int
print_hfsc_opts(const struct pf_altq * a,const struct node_queue_opt * qopts)9483b3a8eb9SGleb Smirnoff print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
9493b3a8eb9SGleb Smirnoff {
950249cc75fSPatrick Kelsey const struct hfsc_opts_v1 *opts;
9513b3a8eb9SGleb Smirnoff const struct node_hfsc_sc *rtsc, *lssc, *ulsc;
9523b3a8eb9SGleb Smirnoff
9533b3a8eb9SGleb Smirnoff opts = &a->pq_u.hfsc_opts;
9543b3a8eb9SGleb Smirnoff if (qopts == NULL)
9553b3a8eb9SGleb Smirnoff rtsc = lssc = ulsc = NULL;
9563b3a8eb9SGleb Smirnoff else {
9573b3a8eb9SGleb Smirnoff rtsc = &qopts->data.hfsc_opts.realtime;
9583b3a8eb9SGleb Smirnoff lssc = &qopts->data.hfsc_opts.linkshare;
9593b3a8eb9SGleb Smirnoff ulsc = &qopts->data.hfsc_opts.upperlimit;
9603b3a8eb9SGleb Smirnoff }
9613b3a8eb9SGleb Smirnoff
9623b3a8eb9SGleb Smirnoff if (opts->flags || opts->rtsc_m2 != 0 || opts->ulsc_m2 != 0 ||
9633b3a8eb9SGleb Smirnoff (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
9643b3a8eb9SGleb Smirnoff opts->lssc_d != 0))) {
9653b3a8eb9SGleb Smirnoff printf("hfsc(");
9663b3a8eb9SGleb Smirnoff if (opts->flags & HFCF_RED)
9673b3a8eb9SGleb Smirnoff printf(" red");
9683b3a8eb9SGleb Smirnoff if (opts->flags & HFCF_ECN)
9693b3a8eb9SGleb Smirnoff printf(" ecn");
9703b3a8eb9SGleb Smirnoff if (opts->flags & HFCF_RIO)
9713b3a8eb9SGleb Smirnoff printf(" rio");
9720a70aaf8SLuiz Otavio O Souza if (opts->flags & HFCF_CODEL)
9730a70aaf8SLuiz Otavio O Souza printf(" codel");
9743b3a8eb9SGleb Smirnoff if (opts->flags & HFCF_CLEARDSCP)
9753b3a8eb9SGleb Smirnoff printf(" cleardscp");
9763b3a8eb9SGleb Smirnoff if (opts->flags & HFCF_DEFAULTCLASS)
9773b3a8eb9SGleb Smirnoff printf(" default");
9783b3a8eb9SGleb Smirnoff if (opts->rtsc_m2 != 0)
9793b3a8eb9SGleb Smirnoff print_hfsc_sc("realtime", opts->rtsc_m1, opts->rtsc_d,
9803b3a8eb9SGleb Smirnoff opts->rtsc_m2, rtsc);
9813b3a8eb9SGleb Smirnoff if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
9823b3a8eb9SGleb Smirnoff opts->lssc_d != 0))
9833b3a8eb9SGleb Smirnoff print_hfsc_sc("linkshare", opts->lssc_m1, opts->lssc_d,
9843b3a8eb9SGleb Smirnoff opts->lssc_m2, lssc);
9853b3a8eb9SGleb Smirnoff if (opts->ulsc_m2 != 0)
9863b3a8eb9SGleb Smirnoff print_hfsc_sc("upperlimit", opts->ulsc_m1, opts->ulsc_d,
9873b3a8eb9SGleb Smirnoff opts->ulsc_m2, ulsc);
9883b3a8eb9SGleb Smirnoff printf(" ) ");
9893b3a8eb9SGleb Smirnoff
9903b3a8eb9SGleb Smirnoff return (1);
9913b3a8eb9SGleb Smirnoff } else
9923b3a8eb9SGleb Smirnoff return (0);
9933b3a8eb9SGleb Smirnoff }
9943b3a8eb9SGleb Smirnoff
995a5b789f6SErmal Luçi static int
print_codel_opts(const struct pf_altq * a,const struct node_queue_opt * qopts)9960a70aaf8SLuiz Otavio O Souza print_codel_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
9970a70aaf8SLuiz Otavio O Souza {
9980a70aaf8SLuiz Otavio O Souza const struct codel_opts *opts;
9990a70aaf8SLuiz Otavio O Souza
10000a70aaf8SLuiz Otavio O Souza opts = &a->pq_u.codel_opts;
10010a70aaf8SLuiz Otavio O Souza if (opts->target || opts->interval || opts->ecn) {
10020a70aaf8SLuiz Otavio O Souza printf("codel(");
10030a70aaf8SLuiz Otavio O Souza if (opts->target)
10040a70aaf8SLuiz Otavio O Souza printf(" target %d", opts->target);
10050a70aaf8SLuiz Otavio O Souza if (opts->interval)
10060a70aaf8SLuiz Otavio O Souza printf(" interval %d", opts->interval);
10070a70aaf8SLuiz Otavio O Souza if (opts->ecn)
10080a70aaf8SLuiz Otavio O Souza printf("ecn");
10090a70aaf8SLuiz Otavio O Souza printf(" ) ");
10100a70aaf8SLuiz Otavio O Souza
10110a70aaf8SLuiz Otavio O Souza return (1);
10120a70aaf8SLuiz Otavio O Souza }
10130a70aaf8SLuiz Otavio O Souza
10140a70aaf8SLuiz Otavio O Souza return (0);
10150a70aaf8SLuiz Otavio O Souza }
10160a70aaf8SLuiz Otavio O Souza
10170a70aaf8SLuiz Otavio O Souza static int
print_fairq_opts(const struct pf_altq * a,const struct node_queue_opt * qopts)1018a5b789f6SErmal Luçi print_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
1019a5b789f6SErmal Luçi {
1020a5b789f6SErmal Luçi const struct fairq_opts *opts;
1021a5b789f6SErmal Luçi const struct node_fairq_sc *loc_lssc;
1022a5b789f6SErmal Luçi
1023a5b789f6SErmal Luçi opts = &a->pq_u.fairq_opts;
1024a5b789f6SErmal Luçi if (qopts == NULL)
1025a5b789f6SErmal Luçi loc_lssc = NULL;
1026a5b789f6SErmal Luçi else
1027a5b789f6SErmal Luçi loc_lssc = &qopts->data.fairq_opts.linkshare;
1028a5b789f6SErmal Luçi
1029a5b789f6SErmal Luçi if (opts->flags ||
1030a5b789f6SErmal Luçi (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
1031a5b789f6SErmal Luçi opts->lssc_d != 0))) {
1032a5b789f6SErmal Luçi printf("fairq(");
1033a5b789f6SErmal Luçi if (opts->flags & FARF_RED)
1034a5b789f6SErmal Luçi printf(" red");
1035a5b789f6SErmal Luçi if (opts->flags & FARF_ECN)
1036a5b789f6SErmal Luçi printf(" ecn");
1037a5b789f6SErmal Luçi if (opts->flags & FARF_RIO)
1038a5b789f6SErmal Luçi printf(" rio");
10390a70aaf8SLuiz Otavio O Souza if (opts->flags & FARF_CODEL)
10400a70aaf8SLuiz Otavio O Souza printf(" codel");
1041a5b789f6SErmal Luçi if (opts->flags & FARF_CLEARDSCP)
1042a5b789f6SErmal Luçi printf(" cleardscp");
1043a5b789f6SErmal Luçi if (opts->flags & FARF_DEFAULTCLASS)
1044a5b789f6SErmal Luçi printf(" default");
1045a5b789f6SErmal Luçi if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
1046a5b789f6SErmal Luçi opts->lssc_d != 0))
1047a5b789f6SErmal Luçi print_fairq_sc("linkshare", opts->lssc_m1, opts->lssc_d,
1048a5b789f6SErmal Luçi opts->lssc_m2, loc_lssc);
1049a5b789f6SErmal Luçi printf(" ) ");
1050a5b789f6SErmal Luçi
1051a5b789f6SErmal Luçi return (1);
1052a5b789f6SErmal Luçi } else
1053a5b789f6SErmal Luçi return (0);
1054a5b789f6SErmal Luçi }
1055a5b789f6SErmal Luçi
10563b3a8eb9SGleb Smirnoff /*
10573b3a8eb9SGleb Smirnoff * admission control using generalized service curve
10583b3a8eb9SGleb Smirnoff */
10593b3a8eb9SGleb Smirnoff
10603b3a8eb9SGleb Smirnoff /* add a new service curve to a generalized service curve */
10613b3a8eb9SGleb Smirnoff static void
gsc_add_sc(struct gen_sc * gsc,struct service_curve * sc)10623b3a8eb9SGleb Smirnoff gsc_add_sc(struct gen_sc *gsc, struct service_curve *sc)
10633b3a8eb9SGleb Smirnoff {
10643b3a8eb9SGleb Smirnoff if (is_sc_null(sc))
10653b3a8eb9SGleb Smirnoff return;
10663b3a8eb9SGleb Smirnoff if (sc->d != 0)
10673b3a8eb9SGleb Smirnoff gsc_add_seg(gsc, 0.0, 0.0, (double)sc->d, (double)sc->m1);
10683b3a8eb9SGleb Smirnoff gsc_add_seg(gsc, (double)sc->d, 0.0, INFINITY, (double)sc->m2);
10693b3a8eb9SGleb Smirnoff }
10703b3a8eb9SGleb Smirnoff
10713b3a8eb9SGleb Smirnoff /*
10723b3a8eb9SGleb Smirnoff * check whether all points of a generalized service curve have
10733b3a8eb9SGleb Smirnoff * their y-coordinates no larger than a given two-piece linear
10743b3a8eb9SGleb Smirnoff * service curve.
10753b3a8eb9SGleb Smirnoff */
10763b3a8eb9SGleb Smirnoff static int
is_gsc_under_sc(struct gen_sc * gsc,struct service_curve * sc)10773b3a8eb9SGleb Smirnoff is_gsc_under_sc(struct gen_sc *gsc, struct service_curve *sc)
10783b3a8eb9SGleb Smirnoff {
10793b3a8eb9SGleb Smirnoff struct segment *s, *last, *end;
10803b3a8eb9SGleb Smirnoff double y;
10813b3a8eb9SGleb Smirnoff
10823b3a8eb9SGleb Smirnoff if (is_sc_null(sc)) {
10833b3a8eb9SGleb Smirnoff if (LIST_EMPTY(gsc))
10843b3a8eb9SGleb Smirnoff return (1);
10853b3a8eb9SGleb Smirnoff LIST_FOREACH(s, gsc, _next) {
10863b3a8eb9SGleb Smirnoff if (s->m != 0)
10873b3a8eb9SGleb Smirnoff return (0);
10883b3a8eb9SGleb Smirnoff }
10893b3a8eb9SGleb Smirnoff return (1);
10903b3a8eb9SGleb Smirnoff }
10913b3a8eb9SGleb Smirnoff /*
10923b3a8eb9SGleb Smirnoff * gsc has a dummy entry at the end with x = INFINITY.
10933b3a8eb9SGleb Smirnoff * loop through up to this dummy entry.
10943b3a8eb9SGleb Smirnoff */
10953b3a8eb9SGleb Smirnoff end = gsc_getentry(gsc, INFINITY);
10963b3a8eb9SGleb Smirnoff if (end == NULL)
10973b3a8eb9SGleb Smirnoff return (1);
10983b3a8eb9SGleb Smirnoff last = NULL;
10993b3a8eb9SGleb Smirnoff for (s = LIST_FIRST(gsc); s != end; s = LIST_NEXT(s, _next)) {
11003b3a8eb9SGleb Smirnoff if (s->y > sc_x2y(sc, s->x))
11013b3a8eb9SGleb Smirnoff return (0);
11023b3a8eb9SGleb Smirnoff last = s;
11033b3a8eb9SGleb Smirnoff }
11043b3a8eb9SGleb Smirnoff /* last now holds the real last segment */
11053b3a8eb9SGleb Smirnoff if (last == NULL)
11063b3a8eb9SGleb Smirnoff return (1);
11073b3a8eb9SGleb Smirnoff if (last->m > sc->m2)
11083b3a8eb9SGleb Smirnoff return (0);
11093b3a8eb9SGleb Smirnoff if (last->x < sc->d && last->m > sc->m1) {
11103b3a8eb9SGleb Smirnoff y = last->y + (sc->d - last->x) * last->m;
11113b3a8eb9SGleb Smirnoff if (y > sc_x2y(sc, sc->d))
11123b3a8eb9SGleb Smirnoff return (0);
11133b3a8eb9SGleb Smirnoff }
11143b3a8eb9SGleb Smirnoff return (1);
11153b3a8eb9SGleb Smirnoff }
11163b3a8eb9SGleb Smirnoff
11173b3a8eb9SGleb Smirnoff /*
11183b3a8eb9SGleb Smirnoff * return a segment entry starting at x.
11193b3a8eb9SGleb Smirnoff * if gsc has no entry starting at x, a new entry is created at x.
11203b3a8eb9SGleb Smirnoff */
11213b3a8eb9SGleb Smirnoff static struct segment *
gsc_getentry(struct gen_sc * gsc,double x)11223b3a8eb9SGleb Smirnoff gsc_getentry(struct gen_sc *gsc, double x)
11233b3a8eb9SGleb Smirnoff {
11243b3a8eb9SGleb Smirnoff struct segment *new, *prev, *s;
11253b3a8eb9SGleb Smirnoff
11263b3a8eb9SGleb Smirnoff prev = NULL;
11273b3a8eb9SGleb Smirnoff LIST_FOREACH(s, gsc, _next) {
11283b3a8eb9SGleb Smirnoff if (s->x == x)
11293b3a8eb9SGleb Smirnoff return (s); /* matching entry found */
11303b3a8eb9SGleb Smirnoff else if (s->x < x)
11313b3a8eb9SGleb Smirnoff prev = s;
11323b3a8eb9SGleb Smirnoff else
11333b3a8eb9SGleb Smirnoff break;
11343b3a8eb9SGleb Smirnoff }
11353b3a8eb9SGleb Smirnoff
11363b3a8eb9SGleb Smirnoff /* we have to create a new entry */
11373b3a8eb9SGleb Smirnoff if ((new = calloc(1, sizeof(struct segment))) == NULL)
11383b3a8eb9SGleb Smirnoff return (NULL);
11393b3a8eb9SGleb Smirnoff
11403b3a8eb9SGleb Smirnoff new->x = x;
11413b3a8eb9SGleb Smirnoff if (x == INFINITY || s == NULL)
11423b3a8eb9SGleb Smirnoff new->d = 0;
11433b3a8eb9SGleb Smirnoff else if (s->x == INFINITY)
11443b3a8eb9SGleb Smirnoff new->d = INFINITY;
11453b3a8eb9SGleb Smirnoff else
11463b3a8eb9SGleb Smirnoff new->d = s->x - x;
11473b3a8eb9SGleb Smirnoff if (prev == NULL) {
11483b3a8eb9SGleb Smirnoff /* insert the new entry at the head of the list */
11493b3a8eb9SGleb Smirnoff new->y = 0;
11503b3a8eb9SGleb Smirnoff new->m = 0;
11513b3a8eb9SGleb Smirnoff LIST_INSERT_HEAD(gsc, new, _next);
11523b3a8eb9SGleb Smirnoff } else {
11533b3a8eb9SGleb Smirnoff /*
11543b3a8eb9SGleb Smirnoff * the start point intersects with the segment pointed by
11553b3a8eb9SGleb Smirnoff * prev. divide prev into 2 segments
11563b3a8eb9SGleb Smirnoff */
11573b3a8eb9SGleb Smirnoff if (x == INFINITY) {
11583b3a8eb9SGleb Smirnoff prev->d = INFINITY;
11593b3a8eb9SGleb Smirnoff if (prev->m == 0)
11603b3a8eb9SGleb Smirnoff new->y = prev->y;
11613b3a8eb9SGleb Smirnoff else
11623b3a8eb9SGleb Smirnoff new->y = INFINITY;
11633b3a8eb9SGleb Smirnoff } else {
11643b3a8eb9SGleb Smirnoff prev->d = x - prev->x;
11653b3a8eb9SGleb Smirnoff new->y = prev->d * prev->m + prev->y;
11663b3a8eb9SGleb Smirnoff }
11673b3a8eb9SGleb Smirnoff new->m = prev->m;
11683b3a8eb9SGleb Smirnoff LIST_INSERT_AFTER(prev, new, _next);
11693b3a8eb9SGleb Smirnoff }
11703b3a8eb9SGleb Smirnoff return (new);
11713b3a8eb9SGleb Smirnoff }
11723b3a8eb9SGleb Smirnoff
11733b3a8eb9SGleb Smirnoff /* add a segment to a generalized service curve */
11743b3a8eb9SGleb Smirnoff static int
gsc_add_seg(struct gen_sc * gsc,double x,double y,double d,double m)11753b3a8eb9SGleb Smirnoff gsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m)
11763b3a8eb9SGleb Smirnoff {
11773b3a8eb9SGleb Smirnoff struct segment *start, *end, *s;
11783b3a8eb9SGleb Smirnoff double x2;
11793b3a8eb9SGleb Smirnoff
11803b3a8eb9SGleb Smirnoff if (d == INFINITY)
11813b3a8eb9SGleb Smirnoff x2 = INFINITY;
11823b3a8eb9SGleb Smirnoff else
11833b3a8eb9SGleb Smirnoff x2 = x + d;
11843b3a8eb9SGleb Smirnoff start = gsc_getentry(gsc, x);
11853b3a8eb9SGleb Smirnoff end = gsc_getentry(gsc, x2);
11863b3a8eb9SGleb Smirnoff if (start == NULL || end == NULL)
11873b3a8eb9SGleb Smirnoff return (-1);
11883b3a8eb9SGleb Smirnoff
11893b3a8eb9SGleb Smirnoff for (s = start; s != end; s = LIST_NEXT(s, _next)) {
11903b3a8eb9SGleb Smirnoff s->m += m;
11913b3a8eb9SGleb Smirnoff s->y += y + (s->x - x) * m;
11923b3a8eb9SGleb Smirnoff }
11933b3a8eb9SGleb Smirnoff
11943b3a8eb9SGleb Smirnoff end = gsc_getentry(gsc, INFINITY);
11953b3a8eb9SGleb Smirnoff for (; s != end; s = LIST_NEXT(s, _next)) {
11963b3a8eb9SGleb Smirnoff s->y += m * d;
11973b3a8eb9SGleb Smirnoff }
11983b3a8eb9SGleb Smirnoff
11993b3a8eb9SGleb Smirnoff return (0);
12003b3a8eb9SGleb Smirnoff }
12013b3a8eb9SGleb Smirnoff
12023b3a8eb9SGleb Smirnoff /* get y-projection of a service curve */
12033b3a8eb9SGleb Smirnoff static double
sc_x2y(struct service_curve * sc,double x)12043b3a8eb9SGleb Smirnoff sc_x2y(struct service_curve *sc, double x)
12053b3a8eb9SGleb Smirnoff {
12063b3a8eb9SGleb Smirnoff double y;
12073b3a8eb9SGleb Smirnoff
12083b3a8eb9SGleb Smirnoff if (x <= (double)sc->d)
12093b3a8eb9SGleb Smirnoff /* y belongs to the 1st segment */
12103b3a8eb9SGleb Smirnoff y = x * (double)sc->m1;
12113b3a8eb9SGleb Smirnoff else
12123b3a8eb9SGleb Smirnoff /* y belongs to the 2nd segment */
12133b3a8eb9SGleb Smirnoff y = (double)sc->d * (double)sc->m1
12143b3a8eb9SGleb Smirnoff + (x - (double)sc->d) * (double)sc->m2;
12153b3a8eb9SGleb Smirnoff return (y);
12163b3a8eb9SGleb Smirnoff }
12173b3a8eb9SGleb Smirnoff
12183b3a8eb9SGleb Smirnoff /*
12193b3a8eb9SGleb Smirnoff * misc utilities
12203b3a8eb9SGleb Smirnoff */
12213b3a8eb9SGleb Smirnoff #define R2S_BUFS 8
12223b3a8eb9SGleb Smirnoff #define RATESTR_MAX 16
12233b3a8eb9SGleb Smirnoff
12243b3a8eb9SGleb Smirnoff char *
rate2str(double rate)12253b3a8eb9SGleb Smirnoff rate2str(double rate)
12263b3a8eb9SGleb Smirnoff {
12273b3a8eb9SGleb Smirnoff char *buf;
1228*c9856c4fSGordon Bergling static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring buffer */
12293b3a8eb9SGleb Smirnoff static int idx = 0;
12303b3a8eb9SGleb Smirnoff int i;
12313b3a8eb9SGleb Smirnoff static const char unit[] = " KMG";
12323b3a8eb9SGleb Smirnoff
12333b3a8eb9SGleb Smirnoff buf = r2sbuf[idx++];
12343b3a8eb9SGleb Smirnoff if (idx == R2S_BUFS)
12353b3a8eb9SGleb Smirnoff idx = 0;
12363b3a8eb9SGleb Smirnoff
12373b3a8eb9SGleb Smirnoff for (i = 0; rate >= 1000 && i <= 3; i++)
12383b3a8eb9SGleb Smirnoff rate /= 1000;
12393b3a8eb9SGleb Smirnoff
12403b3a8eb9SGleb Smirnoff if ((int)(rate * 100) % 100)
12413b3a8eb9SGleb Smirnoff snprintf(buf, RATESTR_MAX, "%.2f%cb", rate, unit[i]);
12423b3a8eb9SGleb Smirnoff else
12433b3a8eb9SGleb Smirnoff snprintf(buf, RATESTR_MAX, "%d%cb", (int)rate, unit[i]);
12443b3a8eb9SGleb Smirnoff
12453b3a8eb9SGleb Smirnoff return (buf);
12463b3a8eb9SGleb Smirnoff }
12473b3a8eb9SGleb Smirnoff
12483b3a8eb9SGleb Smirnoff u_int32_t
getifspeed(char * ifname)12493b3a8eb9SGleb Smirnoff getifspeed(char *ifname)
12503b3a8eb9SGleb Smirnoff {
12513b3a8eb9SGleb Smirnoff int s;
12523b3a8eb9SGleb Smirnoff struct ifreq ifr;
12533b3a8eb9SGleb Smirnoff struct if_data ifrdat;
12543b3a8eb9SGleb Smirnoff
12551d34c9daSPatrick Kelsey s = get_query_socket();
12563b3a8eb9SGleb Smirnoff bzero(&ifr, sizeof(ifr));
12573b3a8eb9SGleb Smirnoff if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
12583b3a8eb9SGleb Smirnoff sizeof(ifr.ifr_name))
12593b3a8eb9SGleb Smirnoff errx(1, "getifspeed: strlcpy");
12603b3a8eb9SGleb Smirnoff ifr.ifr_data = (caddr_t)&ifrdat;
12613b3a8eb9SGleb Smirnoff if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
12623b3a8eb9SGleb Smirnoff err(1, "SIOCGIFDATA");
12633b3a8eb9SGleb Smirnoff return ((u_int32_t)ifrdat.ifi_baudrate);
12643b3a8eb9SGleb Smirnoff }
12653b3a8eb9SGleb Smirnoff
12663b3a8eb9SGleb Smirnoff u_long
getifmtu(char * ifname)12673b3a8eb9SGleb Smirnoff getifmtu(char *ifname)
12683b3a8eb9SGleb Smirnoff {
12693b3a8eb9SGleb Smirnoff int s;
12703b3a8eb9SGleb Smirnoff struct ifreq ifr;
12713b3a8eb9SGleb Smirnoff
12721d34c9daSPatrick Kelsey s = get_query_socket();
12733b3a8eb9SGleb Smirnoff bzero(&ifr, sizeof(ifr));
12743b3a8eb9SGleb Smirnoff if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
12753b3a8eb9SGleb Smirnoff sizeof(ifr.ifr_name))
12763b3a8eb9SGleb Smirnoff errx(1, "getifmtu: strlcpy");
12773b3a8eb9SGleb Smirnoff if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == -1)
12783b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__
12793b3a8eb9SGleb Smirnoff ifr.ifr_mtu = 1500;
12803b3a8eb9SGleb Smirnoff #else
12813b3a8eb9SGleb Smirnoff err(1, "SIOCGIFMTU");
12823b3a8eb9SGleb Smirnoff #endif
12833b3a8eb9SGleb Smirnoff if (ifr.ifr_mtu > 0)
12843b3a8eb9SGleb Smirnoff return (ifr.ifr_mtu);
12853b3a8eb9SGleb Smirnoff else {
12863b3a8eb9SGleb Smirnoff warnx("could not get mtu for %s, assuming 1500", ifname);
12873b3a8eb9SGleb Smirnoff return (1500);
12883b3a8eb9SGleb Smirnoff }
12893b3a8eb9SGleb Smirnoff }
12903b3a8eb9SGleb Smirnoff
12913b3a8eb9SGleb Smirnoff int
eval_queue_opts(struct pf_altq * pa,struct node_queue_opt * opts,u_int64_t ref_bw)12923b3a8eb9SGleb Smirnoff eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts,
1293249cc75fSPatrick Kelsey u_int64_t ref_bw)
12943b3a8eb9SGleb Smirnoff {
12953b3a8eb9SGleb Smirnoff int errors = 0;
12963b3a8eb9SGleb Smirnoff
12973b3a8eb9SGleb Smirnoff switch (pa->scheduler) {
12983b3a8eb9SGleb Smirnoff case ALTQT_CBQ:
12993b3a8eb9SGleb Smirnoff pa->pq_u.cbq_opts = opts->data.cbq_opts;
13003b3a8eb9SGleb Smirnoff break;
13013b3a8eb9SGleb Smirnoff case ALTQT_PRIQ:
13023b3a8eb9SGleb Smirnoff pa->pq_u.priq_opts = opts->data.priq_opts;
13033b3a8eb9SGleb Smirnoff break;
13043b3a8eb9SGleb Smirnoff case ALTQT_HFSC:
13053b3a8eb9SGleb Smirnoff pa->pq_u.hfsc_opts.flags = opts->data.hfsc_opts.flags;
13063b3a8eb9SGleb Smirnoff if (opts->data.hfsc_opts.linkshare.used) {
13073b3a8eb9SGleb Smirnoff pa->pq_u.hfsc_opts.lssc_m1 =
13083b3a8eb9SGleb Smirnoff eval_bwspec(&opts->data.hfsc_opts.linkshare.m1,
13093b3a8eb9SGleb Smirnoff ref_bw);
13103b3a8eb9SGleb Smirnoff pa->pq_u.hfsc_opts.lssc_m2 =
13113b3a8eb9SGleb Smirnoff eval_bwspec(&opts->data.hfsc_opts.linkshare.m2,
13123b3a8eb9SGleb Smirnoff ref_bw);
13133b3a8eb9SGleb Smirnoff pa->pq_u.hfsc_opts.lssc_d =
13143b3a8eb9SGleb Smirnoff opts->data.hfsc_opts.linkshare.d;
13153b3a8eb9SGleb Smirnoff }
13163b3a8eb9SGleb Smirnoff if (opts->data.hfsc_opts.realtime.used) {
13173b3a8eb9SGleb Smirnoff pa->pq_u.hfsc_opts.rtsc_m1 =
13183b3a8eb9SGleb Smirnoff eval_bwspec(&opts->data.hfsc_opts.realtime.m1,
13193b3a8eb9SGleb Smirnoff ref_bw);
13203b3a8eb9SGleb Smirnoff pa->pq_u.hfsc_opts.rtsc_m2 =
13213b3a8eb9SGleb Smirnoff eval_bwspec(&opts->data.hfsc_opts.realtime.m2,
13223b3a8eb9SGleb Smirnoff ref_bw);
13233b3a8eb9SGleb Smirnoff pa->pq_u.hfsc_opts.rtsc_d =
13243b3a8eb9SGleb Smirnoff opts->data.hfsc_opts.realtime.d;
13253b3a8eb9SGleb Smirnoff }
13263b3a8eb9SGleb Smirnoff if (opts->data.hfsc_opts.upperlimit.used) {
13273b3a8eb9SGleb Smirnoff pa->pq_u.hfsc_opts.ulsc_m1 =
13283b3a8eb9SGleb Smirnoff eval_bwspec(&opts->data.hfsc_opts.upperlimit.m1,
13293b3a8eb9SGleb Smirnoff ref_bw);
13303b3a8eb9SGleb Smirnoff pa->pq_u.hfsc_opts.ulsc_m2 =
13313b3a8eb9SGleb Smirnoff eval_bwspec(&opts->data.hfsc_opts.upperlimit.m2,
13323b3a8eb9SGleb Smirnoff ref_bw);
13333b3a8eb9SGleb Smirnoff pa->pq_u.hfsc_opts.ulsc_d =
13343b3a8eb9SGleb Smirnoff opts->data.hfsc_opts.upperlimit.d;
13353b3a8eb9SGleb Smirnoff }
13363b3a8eb9SGleb Smirnoff break;
1337a5b789f6SErmal Luçi case ALTQT_FAIRQ:
1338a5b789f6SErmal Luçi pa->pq_u.fairq_opts.flags = opts->data.fairq_opts.flags;
1339a5b789f6SErmal Luçi pa->pq_u.fairq_opts.nbuckets = opts->data.fairq_opts.nbuckets;
1340a5b789f6SErmal Luçi pa->pq_u.fairq_opts.hogs_m1 =
1341a5b789f6SErmal Luçi eval_bwspec(&opts->data.fairq_opts.hogs_bw, ref_bw);
1342a5b789f6SErmal Luçi
1343a5b789f6SErmal Luçi if (opts->data.fairq_opts.linkshare.used) {
1344a5b789f6SErmal Luçi pa->pq_u.fairq_opts.lssc_m1 =
1345a5b789f6SErmal Luçi eval_bwspec(&opts->data.fairq_opts.linkshare.m1,
1346a5b789f6SErmal Luçi ref_bw);
1347a5b789f6SErmal Luçi pa->pq_u.fairq_opts.lssc_m2 =
1348a5b789f6SErmal Luçi eval_bwspec(&opts->data.fairq_opts.linkshare.m2,
1349a5b789f6SErmal Luçi ref_bw);
1350a5b789f6SErmal Luçi pa->pq_u.fairq_opts.lssc_d =
1351a5b789f6SErmal Luçi opts->data.fairq_opts.linkshare.d;
1352a5b789f6SErmal Luçi }
1353a5b789f6SErmal Luçi break;
13540a70aaf8SLuiz Otavio O Souza case ALTQT_CODEL:
13550a70aaf8SLuiz Otavio O Souza pa->pq_u.codel_opts.target = opts->data.codel_opts.target;
13560a70aaf8SLuiz Otavio O Souza pa->pq_u.codel_opts.interval = opts->data.codel_opts.interval;
13570a70aaf8SLuiz Otavio O Souza pa->pq_u.codel_opts.ecn = opts->data.codel_opts.ecn;
13580a70aaf8SLuiz Otavio O Souza break;
13593b3a8eb9SGleb Smirnoff default:
13603b3a8eb9SGleb Smirnoff warnx("eval_queue_opts: unknown scheduler type %u",
13613b3a8eb9SGleb Smirnoff opts->qtype);
13623b3a8eb9SGleb Smirnoff errors++;
13633b3a8eb9SGleb Smirnoff break;
13643b3a8eb9SGleb Smirnoff }
13653b3a8eb9SGleb Smirnoff
13663b3a8eb9SGleb Smirnoff return (errors);
13673b3a8eb9SGleb Smirnoff }
13683b3a8eb9SGleb Smirnoff
1369249cc75fSPatrick Kelsey /*
1370249cc75fSPatrick Kelsey * If absolute bandwidth if set, return the lesser of that value and the
1371249cc75fSPatrick Kelsey * reference bandwidth. Limiting to the reference bandwidth allows simple
1372249cc75fSPatrick Kelsey * limiting of configured bandwidth parameters for schedulers that are
1373249cc75fSPatrick Kelsey * 32-bit limited, as the root/interface bandwidth (top-level reference
1374249cc75fSPatrick Kelsey * bandwidth) will be properly limited in that case.
1375249cc75fSPatrick Kelsey *
1376249cc75fSPatrick Kelsey * Otherwise, if the absolute bandwidth is not set, return given percentage
1377249cc75fSPatrick Kelsey * of reference bandwidth.
1378249cc75fSPatrick Kelsey */
1379249cc75fSPatrick Kelsey u_int64_t
eval_bwspec(struct node_queue_bw * bw,u_int64_t ref_bw)1380249cc75fSPatrick Kelsey eval_bwspec(struct node_queue_bw *bw, u_int64_t ref_bw)
13813b3a8eb9SGleb Smirnoff {
13823b3a8eb9SGleb Smirnoff if (bw->bw_absolute > 0)
1383249cc75fSPatrick Kelsey return (MIN(bw->bw_absolute, ref_bw));
13843b3a8eb9SGleb Smirnoff
13853b3a8eb9SGleb Smirnoff if (bw->bw_percent > 0)
13863b3a8eb9SGleb Smirnoff return (ref_bw / 100 * bw->bw_percent);
13873b3a8eb9SGleb Smirnoff
13883b3a8eb9SGleb Smirnoff return (0);
13893b3a8eb9SGleb Smirnoff }
13903b3a8eb9SGleb Smirnoff
13913b3a8eb9SGleb Smirnoff void
print_hfsc_sc(const char * scname,u_int m1,u_int d,u_int m2,const struct node_hfsc_sc * sc)13923b3a8eb9SGleb Smirnoff print_hfsc_sc(const char *scname, u_int m1, u_int d, u_int m2,
13933b3a8eb9SGleb Smirnoff const struct node_hfsc_sc *sc)
13943b3a8eb9SGleb Smirnoff {
13953b3a8eb9SGleb Smirnoff printf(" %s", scname);
13963b3a8eb9SGleb Smirnoff
13973b3a8eb9SGleb Smirnoff if (d != 0) {
13983b3a8eb9SGleb Smirnoff printf("(");
13993b3a8eb9SGleb Smirnoff if (sc != NULL && sc->m1.bw_percent > 0)
14003b3a8eb9SGleb Smirnoff printf("%u%%", sc->m1.bw_percent);
14013b3a8eb9SGleb Smirnoff else
14023b3a8eb9SGleb Smirnoff printf("%s", rate2str((double)m1));
14033b3a8eb9SGleb Smirnoff printf(" %u", d);
14043b3a8eb9SGleb Smirnoff }
14053b3a8eb9SGleb Smirnoff
14063b3a8eb9SGleb Smirnoff if (sc != NULL && sc->m2.bw_percent > 0)
14073b3a8eb9SGleb Smirnoff printf(" %u%%", sc->m2.bw_percent);
14083b3a8eb9SGleb Smirnoff else
14093b3a8eb9SGleb Smirnoff printf(" %s", rate2str((double)m2));
14103b3a8eb9SGleb Smirnoff
14113b3a8eb9SGleb Smirnoff if (d != 0)
14123b3a8eb9SGleb Smirnoff printf(")");
14133b3a8eb9SGleb Smirnoff }
1414a5b789f6SErmal Luçi
1415a5b789f6SErmal Luçi void
print_fairq_sc(const char * scname,u_int m1,u_int d,u_int m2,const struct node_fairq_sc * sc)1416a5b789f6SErmal Luçi print_fairq_sc(const char *scname, u_int m1, u_int d, u_int m2,
1417a5b789f6SErmal Luçi const struct node_fairq_sc *sc)
1418a5b789f6SErmal Luçi {
1419a5b789f6SErmal Luçi printf(" %s", scname);
1420a5b789f6SErmal Luçi
1421a5b789f6SErmal Luçi if (d != 0) {
1422a5b789f6SErmal Luçi printf("(");
1423a5b789f6SErmal Luçi if (sc != NULL && sc->m1.bw_percent > 0)
1424a5b789f6SErmal Luçi printf("%u%%", sc->m1.bw_percent);
1425a5b789f6SErmal Luçi else
1426a5b789f6SErmal Luçi printf("%s", rate2str((double)m1));
1427a5b789f6SErmal Luçi printf(" %u", d);
1428a5b789f6SErmal Luçi }
1429a5b789f6SErmal Luçi
1430a5b789f6SErmal Luçi if (sc != NULL && sc->m2.bw_percent > 0)
1431a5b789f6SErmal Luçi printf(" %u%%", sc->m2.bw_percent);
1432a5b789f6SErmal Luçi else
1433a5b789f6SErmal Luçi printf(" %s", rate2str((double)m2));
1434a5b789f6SErmal Luçi
1435a5b789f6SErmal Luçi if (d != 0)
1436a5b789f6SErmal Luçi printf(")");
1437a5b789f6SErmal Luçi }
1438