aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/ipfw/altq.c3
-rw-r--r--sbin/pfctl/parse.y12
-rw-r--r--sbin/pfctl/pfctl.c4
-rw-r--r--sbin/pfctl/pfctl_altq.c56
-rw-r--r--sbin/pfctl/pfctl_parser.h2
-rw-r--r--sbin/pfctl/pfctl_qstats.c4
-rw-r--r--sys/net/altq/altq.h29
-rw-r--r--sys/net/altq/altq_cbq.c2
-rw-r--r--sys/net/altq/altq_cbq.h6
-rw-r--r--sys/net/altq/altq_codel.c2
-rw-r--r--sys/net/altq/altq_codel.h6
-rw-r--r--sys/net/altq/altq_fairq.c2
-rw-r--r--sys/net/altq/altq_fairq.h6
-rw-r--r--sys/net/altq/altq_hfsc.c161
-rw-r--r--sys/net/altq/altq_hfsc.h97
-rw-r--r--sys/net/altq/altq_priq.c2
-rw-r--r--sys/net/altq/altq_priq.h6
-rw-r--r--sys/net/altq/altq_subr.c58
-rw-r--r--sys/net/altq/altq_var.h13
-rw-r--r--sys/net/pfvar.h112
-rw-r--r--sys/netpfil/pf/pf_altq.h145
-rw-r--r--sys/netpfil/pf/pf_ioctl.c303
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c8
23 files changed, 884 insertions, 155 deletions
diff --git a/sbin/ipfw/altq.c b/sbin/ipfw/altq.c
index 85f6d7191978..6fa81e7f6f65 100644
--- a/sbin/ipfw/altq.c
+++ b/sbin/ipfw/altq.c
@@ -22,6 +22,8 @@
* altq interface
*/
+#define PFIOC_USE_LATEST
+
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sockio.h>
@@ -85,6 +87,7 @@ altq_fetch(void)
return;
}
bzero(&pfioc, sizeof(pfioc));
+ pfioc.version = PFIOC_ALTQ_VERSION;
if (ioctl(pffd, DIOCGETALTQS, &pfioc) != 0) {
warn("altq support getting queue list");
close(pffd);
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 26d1dbb1a1ec..3b1f0bbea3dd 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -32,6 +32,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#define PFIOC_USE_LATEST
+
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -286,7 +288,7 @@ static struct queue_opts {
struct node_queue_bw queue_bwspec;
struct node_queue_opt scheduler;
int priority;
- int tbrsize;
+ unsigned int tbrsize;
int qlimit;
} queue_opts;
@@ -1623,8 +1625,8 @@ queue_opt : BANDWIDTH bandwidth {
yyerror("tbrsize cannot be respecified");
YYERROR;
}
- if ($2 < 0 || $2 > 65535) {
- yyerror("tbrsize too big: max 65535");
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("tbrsize too big: max %u", UINT_MAX);
YYERROR;
}
queue_opts.marker |= QOM_TBRSIZE;
@@ -1673,10 +1675,10 @@ bandwidth : STRING {
}
}
free($1);
- $$.bw_absolute = (u_int32_t)bps;
+ $$.bw_absolute = (u_int64_t)bps;
}
| NUMBER {
- if ($1 < 0 || $1 > UINT_MAX) {
+ if ($1 < 0 || $1 >= LLONG_MAX) {
yyerror("bandwidth number too big");
YYERROR;
}
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index bd4f5e70ab8b..63298d7449cc 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -36,6 +36,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#define PFIOC_USE_LATEST
+
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -1524,6 +1526,7 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
}
memset(&pa, 0, sizeof(pa));
+ pa.version = PFIOC_ALTQ_VERSION;
memset(&pf, 0, sizeof(pf));
memset(&trs, 0, sizeof(trs));
if ((path = calloc(1, MAXPATHLEN)) == NULL)
@@ -2032,6 +2035,7 @@ pfctl_test_altqsupport(int dev, int opts)
{
struct pfioc_altq pa;
+ pa.version = PFIOC_ALTQ_VERSION;
if (ioctl(dev, DIOCGETALTQS, &pa)) {
if (errno == ENODEV) {
if (opts & PF_OPT_VERBOSE)
diff --git a/sbin/pfctl/pfctl_altq.c b/sbin/pfctl/pfctl_altq.c
index 7b75e87ab6e3..7e8a846a72b3 100644
--- a/sbin/pfctl/pfctl_altq.c
+++ b/sbin/pfctl/pfctl_altq.c
@@ -21,6 +21,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#define PFIOC_USE_LATEST
+
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -31,6 +33,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
+#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
@@ -88,14 +91,14 @@ static int gsc_add_seg(struct gen_sc *, double, double, double,
static double sc_x2y(struct service_curve *, double);
#ifdef __FreeBSD__
-u_int32_t getifspeed(int, char *);
+u_int64_t getifspeed(int, char *);
#else
u_int32_t getifspeed(char *);
#endif
u_long getifmtu(char *);
int eval_queue_opts(struct pf_altq *, struct node_queue_opt *,
- u_int32_t);
-u_int32_t eval_bwspec(struct node_queue_bw *, u_int32_t);
+ u_int64_t);
+u_int64_t eval_bwspec(struct node_queue_bw *, u_int64_t);
void print_hfsc_sc(const char *, u_int, u_int, u_int,
const struct node_hfsc_sc *);
void print_fairq_sc(const char *, u_int, u_int, u_int,
@@ -258,7 +261,8 @@ int
eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
struct node_queue_opt *opts)
{
- u_int rate, size, errors = 0;
+ u_int64_t rate;
+ u_int size, errors = 0;
if (bw->bw_absolute > 0)
pa->ifbandwidth = bw->bw_absolute;
@@ -275,6 +279,15 @@ eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
} else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0)
pa->ifbandwidth = rate;
+ /*
+ * Limit bandwidth to UINT_MAX for schedulers that aren't 64-bit ready.
+ */
+ if ((pa->scheduler != ALTQT_HFSC) && (pa->ifbandwidth > UINT_MAX)) {
+ pa->ifbandwidth = UINT_MAX;
+ warnx("interface %s bandwidth limited to %" PRIu64 " bps "
+ "because selected scheduler is 32-bit limited\n", pa->ifname,
+ pa->ifbandwidth);
+ }
errors += eval_queue_opts(pa, opts, pa->ifbandwidth);
/* if tbrsize is not specified, use heuristics */
@@ -289,8 +302,6 @@ eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
else
size = 24;
size = size * getifmtu(pa->ifname);
- if (size > 0xffff)
- size = 0xffff;
pa->tbrsize = size;
}
return (errors);
@@ -338,7 +349,7 @@ eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
{
/* should be merged with expand_queue */
struct pf_altq *if_pa, *parent, *altq;
- u_int32_t bwsum;
+ u_int64_t bwsum;
int error = 0;
/* find the corresponding interface and copy fields used by queues */
@@ -372,7 +383,7 @@ eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
if (pa->scheduler == ALTQT_CBQ || pa->scheduler == ALTQT_HFSC ||
pa->scheduler == ALTQT_FAIRQ) {
pa->bandwidth = eval_bwspec(bw,
- parent == NULL ? 0 : parent->bandwidth);
+ parent == NULL ? pa->ifbandwidth : parent->bandwidth);
if (pa->bandwidth > pa->ifbandwidth) {
fprintf(stderr, "bandwidth for %s higher than "
@@ -403,7 +414,8 @@ eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
}
}
- if (eval_queue_opts(pa, opts, parent == NULL? 0 : parent->bandwidth))
+ if (eval_queue_opts(pa, opts,
+ parent == NULL ? pa->ifbandwidth : parent->bandwidth))
return (1);
switch (pa->scheduler) {
@@ -709,7 +721,7 @@ static int
eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa)
{
struct pf_altq *altq, *parent;
- struct hfsc_opts *opts;
+ struct hfsc_opts_v1 *opts;
struct service_curve sc;
opts = &pa->pq_u.hfsc_opts;
@@ -1001,7 +1013,7 @@ check_commit_fairq(int dev __unused, int opts __unused, struct pf_altq *pa)
static int
print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
{
- const struct hfsc_opts *opts;
+ const struct hfsc_opts_v1 *opts;
const struct node_hfsc_sc *rtsc, *lssc, *ulsc;
opts = &a->pq_u.hfsc_opts;
@@ -1316,7 +1328,7 @@ rate2str(double rate)
* FreeBSD does not have SIOCGIFDATA.
* To emulate this, DIOCGIFSPEED ioctl added to pf.
*/
-u_int32_t
+u_int64_t
getifspeed(int pfdev, char *ifname)
{
struct pf_ifspeed io;
@@ -1327,7 +1339,7 @@ getifspeed(int pfdev, char *ifname)
errx(1, "getifspeed: strlcpy");
if (ioctl(pfdev, DIOCGIFSPEED, &io) == -1)
err(1, "DIOCGIFSPEED");
- return ((u_int32_t)io.baudrate);
+ return (io.baudrate);
}
#else
u_int32_t
@@ -1382,7 +1394,7 @@ getifmtu(char *ifname)
int
eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts,
- u_int32_t ref_bw)
+ u_int64_t ref_bw)
{
int errors = 0;
@@ -1458,11 +1470,21 @@ eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts,
return (errors);
}
-u_int32_t
-eval_bwspec(struct node_queue_bw *bw, u_int32_t ref_bw)
+/*
+ * If absolute bandwidth if set, return the lesser of that value and the
+ * reference bandwidth. Limiting to the reference bandwidth allows simple
+ * limiting of configured bandwidth parameters for schedulers that are
+ * 32-bit limited, as the root/interface bandwidth (top-level reference
+ * bandwidth) will be properly limited in that case.
+ *
+ * Otherwise, if the absolute bandwidth is not set, return given percentage
+ * of reference bandwidth.
+ */
+u_int64_t
+eval_bwspec(struct node_queue_bw *bw, u_int64_t ref_bw)
{
if (bw->bw_absolute > 0)
- return (bw->bw_absolute);
+ return (MIN(bw->bw_absolute, ref_bw));
if (bw->bw_percent > 0)
return (ref_bw / 100 * bw->bw_percent);
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index 4dd9623cd69d..05ebdf29f6fc 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -134,7 +134,7 @@ struct node_os {
};
struct node_queue_bw {
- u_int32_t bw_absolute;
+ u_int64_t bw_absolute;
u_int16_t bw_percent;
};
diff --git a/sbin/pfctl/pfctl_qstats.c b/sbin/pfctl/pfctl_qstats.c
index 3dd9d3af82d3..5312a6da8eaa 100644
--- a/sbin/pfctl/pfctl_qstats.c
+++ b/sbin/pfctl/pfctl_qstats.c
@@ -19,6 +19,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#define PFIOC_USE_LATEST
+
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -148,6 +150,7 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root)
memset(&pa, 0, sizeof(pa));
memset(&pq, 0, sizeof(pq));
memset(&qstats, 0, sizeof(qstats));
+ pa.version = PFIOC_ALTQ_VERSION;
if (ioctl(dev, DIOCGETALTQS, &pa)) {
warn("DIOCGETALTQS");
return (-1);
@@ -177,6 +180,7 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root)
pq.ticket = pa.ticket;
pq.buf = &qstats.data;
pq.nbytes = sizeof(qstats.data);
+ pq.version = altq_stats_version(pa.altq.scheduler);
if (ioctl(dev, DIOCGETQSTATS, &pq)) {
warn("DIOCGETQSTATS");
return (-1);
diff --git a/sys/net/altq/altq.h b/sys/net/altq/altq.h
index 9cb97bc2ac7a..35024461b851 100644
--- a/sys/net/altq/altq.h
+++ b/sys/net/altq/altq.h
@@ -76,8 +76,8 @@ struct altqreq {
/* simple token backet meter profile */
struct tb_profile {
- u_int rate; /* rate in bit-per-sec */
- u_int depth; /* depth in bytes */
+ u_int64_t rate; /* rate in bit-per-sec */
+ u_int32_t depth; /* depth in bytes */
};
#ifdef ALTQ3_COMPAT
@@ -203,4 +203,29 @@ struct pktcntr {
#include <net/altq/altq_var.h>
#endif
+/*
+ * Can't put these versions in the scheduler-specific headers and include
+ * them all here as that will cause build failure due to cross-including
+ * each other scheduler's private bits into each scheduler's
+ * implementation.
+ */
+#define CBQ_STATS_VERSION 0 /* Latest version of class_stats_t */
+#define CODEL_STATS_VERSION 0 /* Latest version of codel_ifstats */
+#define FAIRQ_STATS_VERSION 0 /* Latest version of fairq_classstats */
+#define HFSC_STATS_VERSION 1 /* Latest version of hfsc_classstats */
+#define PRIQ_STATS_VERSION 0 /* Latest version of priq_classstats */
+
+/* Return the latest stats version for the given scheduler. */
+static inline int altq_stats_version(int scheduler)
+{
+ switch (scheduler) {
+ case ALTQT_CBQ: return (CBQ_STATS_VERSION);
+ case ALTQT_CODEL: return (CODEL_STATS_VERSION);
+ case ALTQT_FAIRQ: return (FAIRQ_STATS_VERSION);
+ case ALTQT_HFSC: return (HFSC_STATS_VERSION);
+ case ALTQT_PRIQ: return (PRIQ_STATS_VERSION);
+ default: return (0);
+ }
+}
+
#endif /* _ALTQ_ALTQ_H_ */
diff --git a/sys/net/altq/altq_cbq.c b/sys/net/altq/altq_cbq.c
index 32fea1745bfd..e587dc1c3bb5 100644
--- a/sys/net/altq/altq_cbq.c
+++ b/sys/net/altq/altq_cbq.c
@@ -452,7 +452,7 @@ cbq_remove_queue(struct pf_altq *a)
}
int
-cbq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
+cbq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes, int version)
{
cbq_state_t *cbqp;
struct rm_class *cl;
diff --git a/sys/net/altq/altq_cbq.h b/sys/net/altq/altq_cbq.h
index 51e7cf9a8256..04bcab1af767 100644
--- a/sys/net/altq/altq_cbq.h
+++ b/sys/net/altq/altq_cbq.h
@@ -99,6 +99,12 @@ typedef struct _cbq_class_stats_ {
struct codel_stats codel;
} class_stats_t;
+/*
+ * CBQ_STATS_VERSION is defined in altq.h to work around issues stemming
+ * from mixing of public-API and internal bits in each scheduler-specific
+ * header.
+ */
+
#ifdef ALTQ3_COMPAT
/*
* Define structures associated with IOCTLS for cbq.
diff --git a/sys/net/altq/altq_codel.c b/sys/net/altq/altq_codel.c
index cc8babca3c04..ee3ea82b7ab9 100644
--- a/sys/net/altq/altq_codel.c
+++ b/sys/net/altq/altq_codel.c
@@ -156,7 +156,7 @@ codel_remove_altq(struct pf_altq *a)
}
int
-codel_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
+codel_getqstats(struct pf_altq *a, void *ubuf, int *nbytes, int version)
{
struct codel_if *cif;
struct codel_ifstats stats;
diff --git a/sys/net/altq/altq_codel.h b/sys/net/altq/altq_codel.h
index 8d7178b4dc78..d7341a87bedc 100644
--- a/sys/net/altq/altq_codel.h
+++ b/sys/net/altq/altq_codel.h
@@ -57,6 +57,12 @@ struct codel_ifstats {
struct pktcntr cl_dropcnt; /* dropped packet counter */
};
+/*
+ * CBQ_STATS_VERSION is defined in altq.h to work around issues stemming
+ * from mixing of public-API and internal bits in each scheduler-specific
+ * header.
+ */
+
#ifdef _KERNEL
#include <net/altq/altq_classq.h>
diff --git a/sys/net/altq/altq_fairq.c b/sys/net/altq/altq_fairq.c
index c808bdb12ad2..b695a5133df0 100644
--- a/sys/net/altq/altq_fairq.c
+++ b/sys/net/altq/altq_fairq.c
@@ -229,7 +229,7 @@ fairq_remove_queue(struct pf_altq *a)
}
int
-fairq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
+fairq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes, int version)
{
struct fairq_if *pif;
struct fairq_class *cl;
diff --git a/sys/net/altq/altq_fairq.h b/sys/net/altq/altq_fairq.h
index 1a4b97ddc999..f1e3217ca79b 100644
--- a/sys/net/altq/altq_fairq.h
+++ b/sys/net/altq/altq_fairq.h
@@ -82,6 +82,12 @@ struct fairq_classstats {
struct codel_stats codel;
};
+/*
+ * FAIRQ_STATS_VERSION is defined in altq.h to work around issues stemming
+ * from mixing of public-API and internal bits in each scheduler-specific
+ * header.
+ */
+
#ifdef _KERNEL
typedef struct fairq_bucket {
diff --git a/sys/net/altq/altq_hfsc.c b/sys/net/altq/altq_hfsc.c
index a2f9b8366538..19a502ba0110 100644
--- a/sys/net/altq/altq_hfsc.c
+++ b/sys/net/altq/altq_hfsc.c
@@ -116,10 +116,10 @@ static struct hfsc_class *actlist_firstfit(struct hfsc_class *,
static __inline u_int64_t seg_x2y(u_int64_t, u_int64_t);
static __inline u_int64_t seg_y2x(u_int64_t, u_int64_t);
-static __inline u_int64_t m2sm(u_int);
-static __inline u_int64_t m2ism(u_int);
+static __inline u_int64_t m2sm(u_int64_t);
+static __inline u_int64_t m2ism(u_int64_t);
static __inline u_int64_t d2dx(u_int);
-static u_int sm2m(u_int64_t);
+static u_int64_t sm2m(u_int64_t);
static u_int dx2d(u_int64_t);
static void sc2isc(struct service_curve *, struct internal_sc *);
@@ -130,7 +130,9 @@ static u_int64_t rtsc_x2y(struct runtime_sc *, u_int64_t);
static void rtsc_min(struct runtime_sc *, struct internal_sc *,
u_int64_t, u_int64_t);
-static void get_class_stats(struct hfsc_classstats *,
+static void get_class_stats_v0(struct hfsc_classstats_v0 *,
+ struct hfsc_class *);
+static void get_class_stats_v1(struct hfsc_classstats_v1 *,
struct hfsc_class *);
static struct hfsc_class *clh_to_clp(struct hfsc_if *, u_int32_t);
@@ -158,7 +160,7 @@ altqdev_decl(hfsc);
*/
#define is_a_parent_class(cl) ((cl)->cl_children != NULL)
-#define HT_INFINITY 0xffffffffffffffffLL /* infinite time value */
+#define HT_INFINITY 0xffffffffffffffffULL /* infinite time value */
#ifdef ALTQ3_COMPAT
/* hif_list keeps all hfsc_if's allocated. */
@@ -226,7 +228,7 @@ hfsc_add_queue(struct pf_altq *a)
{
struct hfsc_if *hif;
struct hfsc_class *cl, *parent;
- struct hfsc_opts *opts;
+ struct hfsc_opts_v1 *opts;
struct service_curve rtsc, lssc, ulsc;
if ((hif = a->altq_disc) == NULL)
@@ -280,11 +282,15 @@ hfsc_remove_queue(struct pf_altq *a)
}
int
-hfsc_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
+hfsc_getqstats(struct pf_altq *a, void *ubuf, int *nbytes, int version)
{
struct hfsc_if *hif;
struct hfsc_class *cl;
- struct hfsc_classstats stats;
+ union {
+ struct hfsc_classstats_v0 v0;
+ struct hfsc_classstats_v1 v1;
+ } stats;
+ size_t stats_size;
int error = 0;
if ((hif = altq_lookup(a->ifname, ALTQT_HFSC)) == NULL)
@@ -293,14 +299,27 @@ hfsc_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
if ((cl = clh_to_clp(hif, a->qid)) == NULL)
return (EINVAL);
- if (*nbytes < sizeof(stats))
+ if (version > HFSC_STATS_VERSION)
return (EINVAL);
- get_class_stats(&stats, cl);
+ memset(&stats, 0, sizeof(stats));
+ switch (version) {
+ case 0:
+ get_class_stats_v0(&stats.v0, cl);
+ stats_size = sizeof(struct hfsc_classstats_v0);
+ break;
+ case 1:
+ get_class_stats_v1(&stats.v1, cl);
+ stats_size = sizeof(struct hfsc_classstats_v1);
+ break;
+ }
+
+ if (*nbytes < stats_size)
+ return (EINVAL);
- if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
+ if ((error = copyout((caddr_t)&stats, ubuf, stats_size)) != 0)
return (error);
- *nbytes = sizeof(stats);
+ *nbytes = stats_size;
return (0);
}
@@ -1357,27 +1376,17 @@ actlist_firstfit(struct hfsc_class *cl, u_int64_t cur_time)
* m: bits/sec
* d: msec
* internal service curve parameters
- * sm: (bytes/tsc_interval) << SM_SHIFT
- * ism: (tsc_count/byte) << ISM_SHIFT
- * dx: tsc_count
- *
- * SM_SHIFT and ISM_SHIFT are scaled in order to keep effective digits.
- * we should be able to handle 100K-1Gbps linkspeed with 200Hz-1GHz CPU
- * speed. SM_SHIFT and ISM_SHIFT are selected to have at least 3 effective
- * digits in decimal using the following table.
+ * sm: (bytes/machclk tick) << SM_SHIFT
+ * ism: (machclk ticks/byte) << ISM_SHIFT
+ * dx: machclk ticks
*
- * bits/sec 100Kbps 1Mbps 10Mbps 100Mbps 1Gbps
- * ----------+-------------------------------------------------------
- * bytes/nsec 12.5e-6 125e-6 1250e-6 12500e-6 125000e-6
- * sm(500MHz) 25.0e-6 250e-6 2500e-6 25000e-6 250000e-6
- * sm(200MHz) 62.5e-6 625e-6 6250e-6 62500e-6 625000e-6
+ * SM_SHIFT and ISM_SHIFT are scaled in order to keep effective digits. we
+ * should be able to handle 100K-100Gbps linkspeed with 256 MHz machclk
+ * frequency and at least 3 effective digits in decimal.
*
- * nsec/byte 80000 8000 800 80 8
- * ism(500MHz) 40000 4000 400 40 4
- * ism(200MHz) 16000 1600 160 16 1.6
*/
#define SM_SHIFT 24
-#define ISM_SHIFT 10
+#define ISM_SHIFT 14
#define SM_MASK ((1LL << SM_SHIFT) - 1)
#define ISM_MASK ((1LL << ISM_SHIFT) - 1)
@@ -1413,16 +1422,16 @@ seg_y2x(u_int64_t y, u_int64_t ism)
}
static __inline u_int64_t
-m2sm(u_int m)
+m2sm(u_int64_t m)
{
u_int64_t sm;
- sm = ((u_int64_t)m << SM_SHIFT) / 8 / machclk_freq;
+ sm = (m << SM_SHIFT) / 8 / machclk_freq;
return (sm);
}
static __inline u_int64_t
-m2ism(u_int m)
+m2ism(u_int64_t m)
{
u_int64_t ism;
@@ -1442,13 +1451,13 @@ d2dx(u_int d)
return (dx);
}
-static u_int
+static u_int64_t
sm2m(u_int64_t sm)
{
u_int64_t m;
m = (sm * 8 * machclk_freq) >> SM_SHIFT;
- return ((u_int)m);
+ return (m);
}
static u_int
@@ -1597,7 +1606,89 @@ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u_int64_t x,
}
static void
-get_class_stats(struct hfsc_classstats *sp, struct hfsc_class *cl)
+get_class_stats_v0(struct hfsc_classstats_v0 *sp, struct hfsc_class *cl)
+{
+ sp->class_id = cl->cl_id;
+ sp->class_handle = cl->cl_handle;
+
+#define SATU32(x) (u_int32_t)uqmin((x), UINT_MAX)
+
+ if (cl->cl_rsc != NULL) {
+ sp->rsc.m1 = SATU32(sm2m(cl->cl_rsc->sm1));
+ sp->rsc.d = dx2d(cl->cl_rsc->dx);
+ sp->rsc.m2 = SATU32(sm2m(cl->cl_rsc->sm2));
+ } else {
+ sp->rsc.m1 = 0;
+ sp->rsc.d = 0;
+ sp->rsc.m2 = 0;
+ }
+ if (cl->cl_fsc != NULL) {
+ sp->fsc.m1 = SATU32(sm2m(cl->cl_fsc->sm1));
+ sp->fsc.d = dx2d(cl->cl_fsc->dx);
+ sp->fsc.m2 = SATU32(sm2m(cl->cl_fsc->sm2));
+ } else {
+ sp->fsc.m1 = 0;
+ sp->fsc.d = 0;
+ sp->fsc.m2 = 0;
+ }
+ if (cl->cl_usc != NULL) {
+ sp->usc.m1 = SATU32(sm2m(cl->cl_usc->sm1));
+ sp->usc.d = dx2d(cl->cl_usc->dx);
+ sp->usc.m2 = SATU32(sm2m(cl->cl_usc->sm2));
+ } else {
+ sp->usc.m1 = 0;
+ sp->usc.d = 0;
+ sp->usc.m2 = 0;
+ }
+
+#undef SATU32
+
+ sp->total = cl->cl_total;
+ sp->cumul = cl->cl_cumul;
+
+ sp->d = cl->cl_d;
+ sp->e = cl->cl_e;
+ sp->vt = cl->cl_vt;
+ sp->f = cl->cl_f;
+
+ sp->initvt = cl->cl_initvt;
+ sp->vtperiod = cl->cl_vtperiod;
+ sp->parentperiod = cl->cl_parentperiod;
+ sp->nactive = cl->cl_nactive;
+ sp->vtoff = cl->cl_vtoff;
+ sp->cvtmax = cl->cl_cvtmax;
+ sp->myf = cl->cl_myf;
+ sp->cfmin = cl->cl_cfmin;
+ sp->cvtmin = cl->cl_cvtmin;
+ sp->myfadj = cl->cl_myfadj;
+ sp->vtadj = cl->cl_vtadj;
+
+ sp->cur_time = read_machclk();
+ sp->machclk_freq = machclk_freq;
+
+ sp->qlength = qlen(cl->cl_q);
+ sp->qlimit = qlimit(cl->cl_q);
+ sp->xmit_cnt = cl->cl_stats.xmit_cnt;
+ sp->drop_cnt = cl->cl_stats.drop_cnt;
+ sp->period = cl->cl_stats.period;
+
+ sp->qtype = qtype(cl->cl_q);
+#ifdef ALTQ_RED
+ if (q_is_red(cl->cl_q))
+ red_getstats(cl->cl_red, &sp->red[0]);
+#endif
+#ifdef ALTQ_RIO
+ if (q_is_rio(cl->cl_q))
+ rio_getstats((rio_t *)cl->cl_red, &sp->red[0]);
+#endif
+#ifdef ALTQ_CODEL
+ if (q_is_codel(cl->cl_q))
+ codel_getstats(cl->cl_codel, &sp->codel);
+#endif
+}
+
+static void
+get_class_stats_v1(struct hfsc_classstats_v1 *sp, struct hfsc_class *cl)
{
sp->class_id = cl->cl_id;
sp->class_handle = cl->cl_handle;
diff --git a/sys/net/altq/altq_hfsc.h b/sys/net/altq/altq_hfsc.h
index 0a9fcf955f4a..67ec0036ff94 100644
--- a/sys/net/altq/altq_hfsc.h
+++ b/sys/net/altq/altq_hfsc.h
@@ -43,12 +43,21 @@
extern "C" {
#endif
-struct service_curve {
+struct service_curve_v0 {
u_int m1; /* slope of the first segment in bits/sec */
u_int d; /* the x-projection of the first segment in msec */
u_int m2; /* slope of the second segment in bits/sec */
};
+struct service_curve_v1 {
+ u_int64_t m1; /* slope of the first segment in bits/sec */
+ u_int d; /* the x-projection of the first segment in msec */
+ u_int64_t m2; /* slope of the second segment in bits/sec */
+};
+
+/* Latest version of struct service_curve_vX */
+#define HFSC_SERVICE_CURVE_VERSION 1
+
/* special class handles */
#define HFSC_NULLCLASS_HANDLE 0
#define HFSC_MAX_CLASSES 64
@@ -67,12 +76,55 @@ struct service_curve {
#define HFSC_UPPERLIMITSC 4
#define HFSC_DEFAULTSC (HFSC_REALTIMESC|HFSC_LINKSHARINGSC)
-struct hfsc_classstats {
+struct hfsc_classstats_v0 {
+ u_int class_id;
+ u_int32_t class_handle;
+ struct service_curve_v0 rsc;
+ struct service_curve_v0 fsc;
+ struct service_curve_v0 usc; /* upper limit service curve */
+
+ u_int64_t total; /* total work in bytes */
+ u_int64_t cumul; /* cumulative work in bytes
+ done by real-time criteria */
+ u_int64_t d; /* deadline */
+ u_int64_t e; /* eligible time */
+ u_int64_t vt; /* virtual time */
+ u_int64_t f; /* fit time for upper-limit */
+
+ /* info helpful for debugging */
+ u_int64_t initvt; /* init virtual time */
+ u_int64_t vtoff; /* cl_vt_ipoff */
+ u_int64_t cvtmax; /* cl_maxvt */
+ u_int64_t myf; /* cl_myf */
+ u_int64_t cfmin; /* cl_mincf */
+ u_int64_t cvtmin; /* cl_mincvt */
+ u_int64_t myfadj; /* cl_myfadj */
+ u_int64_t vtadj; /* cl_vtadj */
+ u_int64_t cur_time;
+ u_int32_t machclk_freq;
+
+ u_int qlength;
+ u_int qlimit;
+ struct pktcntr xmit_cnt;
+ struct pktcntr drop_cnt;
+ u_int period;
+
+ u_int vtperiod; /* vt period sequence no */
+ u_int parentperiod; /* parent's vt period seqno */
+ int nactive; /* number of active children */
+
+ /* codel, red and rio related info */
+ int qtype;
+ struct redstats red[3];
+ struct codel_stats codel;
+};
+
+struct hfsc_classstats_v1 {
u_int class_id;
u_int32_t class_handle;
- struct service_curve rsc;
- struct service_curve fsc;
- struct service_curve usc; /* upper limit service curve */
+ struct service_curve_v1 rsc;
+ struct service_curve_v1 fsc;
+ struct service_curve_v1 usc; /* upper limit service curve */
u_int64_t total; /* total work in bytes */
u_int64_t cumul; /* cumulative work in bytes
@@ -110,6 +162,12 @@ struct hfsc_classstats {
struct codel_stats codel;
};
+/*
+ * HFSC_STATS_VERSION is defined in altq.h to work around issues stemming
+ * from mixing of public-API and internal bits in each scheduler-specific
+ * header.
+ */
+
#ifdef ALTQ3_COMPAT
struct hfsc_interface {
char hfsc_ifname[IFNAMSIZ]; /* interface name (e.g., fxp0) */
@@ -310,6 +368,35 @@ struct hfsc_if {
#endif
};
+/*
+ * Kernel code always wants the latest version - avoid a bunch of renames in
+ * the code to the current latest versioned name.
+ */
+#define service_curve __CONCAT(service_curve_v, HFSC_SERVICE_CURVE_VERSION)
+
+#else /* _KERNEL */
+
+#ifdef PFIOC_USE_LATEST
+/*
+ * Maintaining in-tree consumers of the ioctl interface is easier when that
+ * code can be written in terms old names that refer to the latest interface
+ * version as that reduces the required changes in the consumers to those
+ * that are functionally necessary to accommodate a new interface version.
+ */
+#define hfsc_classstats __CONCAT(hfsc_classstats_v, HFSC_STATS_VERSION)
+#define service_curve __CONCAT(service_curve_v, HFSC_SERVICE_CURVE_VERSION)
+
+#else
+/*
+ * When building out-of-tree code that is written for the old interface,
+ * such as may exist in ports for example, resolve the old struct tags to
+ * the v0 versions.
+ */
+#define hfsc_classstats __CONCAT(hfsc_classstats_v, 0)
+#define service_curve __CONCAT(service_curve_v, 0)
+
+#endif /* PFIOC_USE_LATEST */
+
#endif /* _KERNEL */
#ifdef __cplusplus
diff --git a/sys/net/altq/altq_priq.c b/sys/net/altq/altq_priq.c
index cf031d10db31..4abd0efd9714 100644
--- a/sys/net/altq/altq_priq.c
+++ b/sys/net/altq/altq_priq.c
@@ -199,7 +199,7 @@ priq_remove_queue(struct pf_altq *a)
}
int
-priq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
+priq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes, int version)
{
struct priq_if *pif;
struct priq_class *cl;
diff --git a/sys/net/altq/altq_priq.h b/sys/net/altq/altq_priq.h
index fcbfee9825df..1a824d6097dd 100644
--- a/sys/net/altq/altq_priq.h
+++ b/sys/net/altq/altq_priq.h
@@ -112,6 +112,12 @@ struct priq_classstats {
struct codel_stats codel;
};
+/*
+ * PRIQ_STATS_VERSION is defined in altq.h to work around issues stemming
+ * from mixing of public-API and internal bits in each scheduler-specific
+ * header.
+ */
+
#ifdef ALTQ3_COMPAT
struct priq_class_stats {
struct priq_interface iface;
diff --git a/sys/net/altq/altq_subr.c b/sys/net/altq/altq_subr.c
index 356f79f84b9a..bce83efcd3a7 100644
--- a/sys/net/altq/altq_subr.c
+++ b/sys/net/altq/altq_subr.c
@@ -292,12 +292,12 @@ altq_assert(file, line, failedexpr)
/*
* internal representation of token bucket parameters
- * rate: byte_per_unittime << 32
- * (((bits_per_sec) / 8) << 32) / machclk_freq
- * depth: byte << 32
+ * rate: (byte_per_unittime << TBR_SHIFT) / machclk_freq
+ * (((bits_per_sec) / 8) << TBR_SHIFT) / machclk_freq
+ * depth: byte << TBR_SHIFT
*
*/
-#define TBR_SHIFT 32
+#define TBR_SHIFT 29
#define TBR_SCALE(x) ((int64_t)(x) << TBR_SHIFT)
#define TBR_UNSCALE(x) ((x) >> TBR_SHIFT)
@@ -394,7 +394,20 @@ tbr_set(ifq, profile)
if (tbr->tbr_rate > 0)
tbr->tbr_filluptime = tbr->tbr_depth / tbr->tbr_rate;
else
- tbr->tbr_filluptime = 0xffffffffffffffffLL;
+ tbr->tbr_filluptime = LLONG_MAX;
+ /*
+ * The longest time between tbr_dequeue() calls will be about 1
+ * system tick, as the callout that drives it is scheduled once per
+ * tick. The refill-time detection logic in tbr_dequeue() can only
+ * properly detect the passage of up to LLONG_MAX machclk ticks.
+ * Therefore, in order for this logic to function properly in the
+ * extreme case, the maximum value of tbr_filluptime should be
+ * LLONG_MAX less one system tick's worth of machclk ticks less
+ * some additional slop factor (here one more system tick's worth
+ * of machclk ticks).
+ */
+ if (tbr->tbr_filluptime > (LLONG_MAX - 2 * machclk_per_tick))
+ tbr->tbr_filluptime = LLONG_MAX - 2 * machclk_per_tick;
tbr->tbr_token = tbr->tbr_depth;
tbr->tbr_last = read_machclk();
tbr->tbr_lastop = ALTDQ_REMOVE;
@@ -456,29 +469,6 @@ tbr_timeout(arg)
}
/*
- * get token bucket regulator profile
- */
-int
-tbr_get(ifq, profile)
- struct ifaltq *ifq;
- struct tb_profile *profile;
-{
- struct tb_regulator *tbr;
-
- IFQ_LOCK(ifq);
- if ((tbr = ifq->altq_tbr) == NULL) {
- profile->rate = 0;
- profile->depth = 0;
- } else {
- profile->rate =
- (u_int)TBR_UNSCALE(tbr->tbr_rate * 8 * machclk_freq);
- profile->depth = (u_int)TBR_UNSCALE(tbr->tbr_depth);
- }
- IFQ_UNLOCK(ifq);
- return (0);
-}
-
-/*
* attach a discipline to the interface. if one already exists, it is
* overridden.
* Locking is done in the discipline specific attach functions. Basically
@@ -733,34 +723,34 @@ altq_remove_queue(struct pf_altq *a)
* copyout operations, also it is not yet clear which lock to use.
*/
int
-altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
+altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes, int version)
{
int error = 0;
switch (a->scheduler) {
#ifdef ALTQ_CBQ
case ALTQT_CBQ:
- error = cbq_getqstats(a, ubuf, nbytes);
+ error = cbq_getqstats(a, ubuf, nbytes, version);
break;
#endif
#ifdef ALTQ_PRIQ
case ALTQT_PRIQ:
- error = priq_getqstats(a, ubuf, nbytes);
+ error = priq_getqstats(a, ubuf, nbytes, version);
break;
#endif
#ifdef ALTQ_HFSC
case ALTQT_HFSC:
- error = hfsc_getqstats(a, ubuf, nbytes);
+ error = hfsc_getqstats(a, ubuf, nbytes, version);
break;
#endif
#ifdef ALTQ_FAIRQ
case ALTQT_FAIRQ:
- error = fairq_getqstats(a, ubuf, nbytes);
+ error = fairq_getqstats(a, ubuf, nbytes, version);
break;
#endif
#ifdef ALTQ_CODEL
case ALTQT_CODEL:
- error = codel_getqstats(a, ubuf, nbytes);
+ error = codel_getqstats(a, ubuf, nbytes, version);
break;
#endif
default:
diff --git a/sys/net/altq/altq_var.h b/sys/net/altq/altq_var.h
index 1909599d37ef..47326a03f3dc 100644
--- a/sys/net/altq/altq_var.h
+++ b/sys/net/altq/altq_var.h
@@ -196,7 +196,6 @@ u_int8_t read_dsfield(struct mbuf *, struct altq_pktattr *);
void write_dsfield(struct mbuf *, struct altq_pktattr *, u_int8_t);
void altq_assert(const char *, int, const char *);
int tbr_set(struct ifaltq *, struct tb_profile *);
-int tbr_get(struct ifaltq *, struct tb_profile *);
int altq_pfattach(struct pf_altq *);
int altq_pfdetach(struct pf_altq *);
@@ -204,40 +203,40 @@ int altq_add(struct pf_altq *);
int altq_remove(struct pf_altq *);
int altq_add_queue(struct pf_altq *);
int altq_remove_queue(struct pf_altq *);
-int altq_getqstats(struct pf_altq *, void *, int *);
+int altq_getqstats(struct pf_altq *, void *, int *, int);
int cbq_pfattach(struct pf_altq *);
int cbq_add_altq(struct pf_altq *);
int cbq_remove_altq(struct pf_altq *);
int cbq_add_queue(struct pf_altq *);
int cbq_remove_queue(struct pf_altq *);
-int cbq_getqstats(struct pf_altq *, void *, int *);
+int cbq_getqstats(struct pf_altq *, void *, int *, int);
int codel_pfattach(struct pf_altq *);
int codel_add_altq(struct pf_altq *);
int codel_remove_altq(struct pf_altq *);
-int codel_getqstats(struct pf_altq *, void *, int *);
+int codel_getqstats(struct pf_altq *, void *, int *, int);
int priq_pfattach(struct pf_altq *);
int priq_add_altq(struct pf_altq *);
int priq_remove_altq(struct pf_altq *);
int priq_add_queue(struct pf_altq *);
int priq_remove_queue(struct pf_altq *);
-int priq_getqstats(struct pf_altq *, void *, int *);
+int priq_getqstats(struct pf_altq *, void *, int *, int);
int hfsc_pfattach(struct pf_altq *);
int hfsc_add_altq(struct pf_altq *);
int hfsc_remove_altq(struct pf_altq *);
int hfsc_add_queue(struct pf_altq *);
int hfsc_remove_queue(struct pf_altq *);
-int hfsc_getqstats(struct pf_altq *, void *, int *);
+int hfsc_getqstats(struct pf_altq *, void *, int *, int);
int fairq_pfattach(struct pf_altq *);
int fairq_add_altq(struct pf_altq *);
int fairq_remove_altq(struct pf_altq *);
int fairq_add_queue(struct pf_altq *);
int fairq_remove_queue(struct pf_altq *);
-int fairq_getqstats(struct pf_altq *, void *, int *);
+int fairq_getqstats(struct pf_altq *, void *, int *, int);
#endif /* _KERNEL */
#endif /* _ALTQ_ALTQ_VAR_H_ */
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 9690f086d1c5..5e80b66550de 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1300,21 +1300,56 @@ struct pfioc_limit {
unsigned limit;
};
-struct pfioc_altq {
+struct pfioc_altq_v0 {
u_int32_t action;
u_int32_t ticket;
u_int32_t nr;
- struct pf_altq altq;
+ struct pf_altq_v0 altq;
};
-struct pfioc_qstats {
+struct pfioc_altq_v1 {
+ u_int32_t action;
+ u_int32_t ticket;
+ u_int32_t nr;
+ /*
+ * Placed here so code that only uses the above parameters can be
+ * written entirely in terms of the v0 or v1 type.
+ */
+ u_int32_t version;
+ struct pf_altq_v1 altq;
+};
+
+/*
+ * Latest version of struct pfioc_altq_vX. This must move in lock-step with
+ * the latest version of struct pf_altq_vX as it has that struct as a
+ * member.
+ */
+#define PFIOC_ALTQ_VERSION PF_ALTQ_VERSION
+
+struct pfioc_qstats_v0 {
+ u_int32_t ticket;
+ u_int32_t nr;
+ void *buf;
+ int nbytes;
+ u_int8_t scheduler;
+};
+
+struct pfioc_qstats_v1 {
u_int32_t ticket;
u_int32_t nr;
void *buf;
int nbytes;
u_int8_t scheduler;
+ /*
+ * Placed here so code that only uses the above parameters can be
+ * written entirely in terms of the v0 or v1 type.
+ */
+ u_int32_t version; /* Requested version of stats struct */
};
+/* Latest version of struct pfioc_qstats_vX */
+#define PFIOC_QSTATS_VERSION 1
+
struct pfioc_ruleset {
u_int32_t nr;
char path[MAXPATHLEN];
@@ -1403,11 +1438,16 @@ struct pfioc_iface {
#define DIOCKILLSTATES _IOWR('D', 41, struct pfioc_state_kill)
#define DIOCSTARTALTQ _IO ('D', 42)
#define DIOCSTOPALTQ _IO ('D', 43)
-#define DIOCADDALTQ _IOWR('D', 45, struct pfioc_altq)
-#define DIOCGETALTQS _IOWR('D', 47, struct pfioc_altq)
-#define DIOCGETALTQ _IOWR('D', 48, struct pfioc_altq)
-#define DIOCCHANGEALTQ _IOWR('D', 49, struct pfioc_altq)
-#define DIOCGETQSTATS _IOWR('D', 50, struct pfioc_qstats)
+#define DIOCADDALTQV0 _IOWR('D', 45, struct pfioc_altq_v0)
+#define DIOCADDALTQV1 _IOWR('D', 45, struct pfioc_altq_v1)
+#define DIOCGETALTQSV0 _IOWR('D', 47, struct pfioc_altq_v0)
+#define DIOCGETALTQSV1 _IOWR('D', 47, struct pfioc_altq_v1)
+#define DIOCGETALTQV0 _IOWR('D', 48, struct pfioc_altq_v0)
+#define DIOCGETALTQV1 _IOWR('D', 48, struct pfioc_altq_v1)
+#define DIOCCHANGEALTQV0 _IOWR('D', 49, struct pfioc_altq_v0)
+#define DIOCCHANGEALTQV1 _IOWR('D', 49, struct pfioc_altq_v1)
+#define DIOCGETQSTATSV0 _IOWR('D', 50, struct pfioc_qstats_v0)
+#define DIOCGETQSTATSV1 _IOWR('D', 50, struct pfioc_qstats_v1)
#define DIOCBEGINADDRS _IOWR('D', 51, struct pfioc_pooladdr)
#define DIOCADDADDR _IOWR('D', 52, struct pfioc_pooladdr)
#define DIOCGETADDRS _IOWR('D', 53, struct pfioc_pooladdr)
@@ -1445,11 +1485,63 @@ struct pfioc_iface {
#define DIOCSETIFFLAG _IOWR('D', 89, struct pfioc_iface)
#define DIOCCLRIFFLAG _IOWR('D', 90, struct pfioc_iface)
#define DIOCKILLSRCNODES _IOWR('D', 91, struct pfioc_src_node_kill)
-struct pf_ifspeed {
+struct pf_ifspeed_v0 {
char ifname[IFNAMSIZ];
u_int32_t baudrate;
};
-#define DIOCGIFSPEED _IOWR('D', 92, struct pf_ifspeed)
+
+struct pf_ifspeed_v1 {
+ char ifname[IFNAMSIZ];
+ u_int32_t baudrate32;
+ /* layout identical to struct pf_ifspeed_v0 up to this point */
+ u_int64_t baudrate;
+};
+
+/* Latest version of struct pf_ifspeed_vX */
+#define PF_IFSPEED_VERSION 1
+
+#define DIOCGIFSPEEDV0 _IOWR('D', 92, struct pf_ifspeed_v0)
+#define DIOCGIFSPEEDV1 _IOWR('D', 92, struct pf_ifspeed_v1)
+
+/*
+ * Compatibility and convenience macros
+ */
+#ifndef _KERNEL
+#ifdef PFIOC_USE_LATEST
+/*
+ * Maintaining in-tree consumers of the ioctl interface is easier when that
+ * code can be written in terms old names that refer to the latest interface
+ * version as that reduces the required changes in the consumers to those
+ * that are functionally necessary to accommodate a new interface version.
+ */
+#define pfioc_altq __CONCAT(pfioc_altq_v, PFIOC_ALTQ_VERSION)
+#define pfioc_qstats __CONCAT(pfioc_qstats_v, PFIOC_QSTATS_VERSION)
+#define pf_ifspeed __CONCAT(pf_ifspeed_v, PF_IFSPEED_VERSION)
+
+#define DIOCADDALTQ __CONCAT(DIOCADDALTQV, PFIOC_ALTQ_VERSION)
+#define DIOCGETALTQS __CONCAT(DIOCGETALTQSV, PFIOC_ALTQ_VERSION)
+#define DIOCGETALTQ __CONCAT(DIOCGETALTQV, PFIOC_ALTQ_VERSION)
+#define DIOCCHANGEALTQ __CONCAT(DIOCCHANGEALTQV, PFIOC_ALTQ_VERSION)
+#define DIOCGETQSTATS __CONCAT(DIOCGETQSTATSV, PFIOC_QSTATS_VERSION)
+#define DIOCGIFSPEED __CONCAT(DIOCGIFSPEEDV, PF_IFSPEED_VERSION)
+#else
+/*
+ * When building out-of-tree code that is written for the old interface,
+ * such as may exist in ports for example, resolve the old struct tags and
+ * ioctl command names to the v0 versions.
+ */
+#define pfioc_altq __CONCAT(pfioc_altq_v, 0)
+#define pfioc_qstats __CONCAT(pfioc_qstats_v, 0)
+#define pf_ifspeed __CONCAT(pf_ifspeed_v, 0)
+
+#define DIOCADDALTQ __CONCAT(DIOCADDALTQV, 0)
+#define DIOCGETALTQS __CONCAT(DIOCGETALTQSV, 0)
+#define DIOCGETALTQ __CONCAT(DIOCGETALTQV, 0)
+#define DIOCCHANGEALTQ __CONCAT(DIOCCHANGEALTQV, 0)
+#define DIOCGETQSTATS __CONCAT(DIOCGETQSTATSV, 0)
+#define DIOCGIFSPEED __CONCAT(DIOCGIFSPEEDV, 0)
+#endif /* PFIOC_USE_LATEST */
+#endif /* _KERNEL */
#ifdef _KERNEL
LIST_HEAD(pf_src_node_list, pf_src_node);
diff --git a/sys/netpfil/pf/pf_altq.h b/sys/netpfil/pf/pf_altq.h
index f6d578d39016..35d2d5cb8bbe 100644
--- a/sys/netpfil/pf/pf_altq.h
+++ b/sys/netpfil/pf/pf_altq.h
@@ -57,7 +57,7 @@ struct priq_opts {
int flags;
};
-struct hfsc_opts {
+struct hfsc_opts_v0 {
/* real-time service curve */
u_int rtsc_m1; /* slope of the 1st segment in bps */
u_int rtsc_d; /* the x-projection of m1 in msec */
@@ -73,6 +73,31 @@ struct hfsc_opts {
int flags;
};
+struct hfsc_opts_v1 {
+ /* real-time service curve */
+ u_int64_t rtsc_m1; /* slope of the 1st segment in bps */
+ u_int rtsc_d; /* the x-projection of m1 in msec */
+ u_int64_t rtsc_m2; /* slope of the 2nd segment in bps */
+ /* link-sharing service curve */
+ u_int64_t lssc_m1;
+ u_int lssc_d;
+ u_int64_t lssc_m2;
+ /* upper-limit service curve */
+ u_int64_t ulsc_m1;
+ u_int ulsc_d;
+ u_int64_t ulsc_m2;
+ int flags;
+};
+
+/*
+ * struct hfsc_opts doesn't have a version indicator macro or
+ * backwards-compat and convenience macros because both in the kernel and
+ * the pfctl parser, there are struct hfsc_opts instances named 'hfsc_opts'.
+ * It is believed that only in-tree code uses struct hfsc_opts, so
+ * backwards-compat macros are not necessary. The few in-tree uses can just
+ * be updated to the latest versioned struct tag.
+ */
+
/*
* XXX this needs some work
*/
@@ -87,11 +112,22 @@ struct fairq_opts {
u_int lssc_m2;
};
-struct pf_altq {
+/*
+ * struct pf_altq_v0, struct pf_altq_v1, etc. are the ioctl argument
+ * structures corresponding to struct pfioc_altq_v0, struct pfioc_altq_v1,
+ * etc.
+ *
+ */
+struct pf_altq_v0 {
char ifname[IFNAMSIZ];
- void *altq_disc; /* discipline-specific state */
- TAILQ_ENTRY(pf_altq) entries;
+ /*
+ * This member is a holdover from when the kernel state structure
+ * was reused as the ioctl argument structure, and remains to
+ * preserve the size and layout of this struct for backwards compat.
+ */
+ void *unused1;
+ TAILQ_ENTRY(pf_altq_v0) entries;
/* scheduler spec */
uint8_t scheduler; /* scheduler type */
@@ -113,11 +149,110 @@ struct pf_altq {
struct cbq_opts cbq_opts;
struct codel_opts codel_opts;
struct priq_opts priq_opts;
- struct hfsc_opts hfsc_opts;
+ struct hfsc_opts_v0 hfsc_opts;
+ struct fairq_opts fairq_opts;
+ } pq_u;
+
+ uint32_t qid; /* return value */
+};
+
+struct pf_altq_v1 {
+ char ifname[IFNAMSIZ];
+
+ TAILQ_ENTRY(pf_altq_v1) entries;
+
+ /* scheduler spec */
+ uint8_t scheduler; /* scheduler type */
+ uint32_t tbrsize; /* tokenbucket regulator size */
+ uint64_t ifbandwidth; /* interface bandwidth */
+
+ /* queue spec */
+ char qname[PF_QNAME_SIZE]; /* queue name */
+ char parent[PF_QNAME_SIZE]; /* parent name */
+ uint32_t parent_qid; /* parent queue id */
+ uint64_t bandwidth; /* queue bandwidth */
+ uint8_t priority; /* priority */
+ uint8_t local_flags; /* dynamic interface, see _v0 */
+
+ uint16_t qlimit; /* queue size limit */
+ uint16_t flags; /* misc flags */
+ union {
+ struct cbq_opts cbq_opts;
+ struct codel_opts codel_opts;
+ struct priq_opts priq_opts;
+ struct hfsc_opts_v1 hfsc_opts;
struct fairq_opts fairq_opts;
} pq_u;
uint32_t qid; /* return value */
};
+/* Latest version of struct pf_altq_vX */
+#define PF_ALTQ_VERSION 1
+
+#ifdef _KERNEL
+struct pf_kaltq {
+ char ifname[IFNAMSIZ];
+
+ void *altq_disc; /* discipline-specific state */
+ TAILQ_ENTRY(pf_kaltq) entries;
+
+ /* scheduler spec */
+ uint8_t scheduler; /* scheduler type */
+ uint32_t tbrsize; /* tokenbucket regulator size */
+ uint64_t ifbandwidth; /* interface bandwidth */
+
+ /* queue spec */
+ char qname[PF_QNAME_SIZE]; /* queue name */
+ char parent[PF_QNAME_SIZE]; /* parent name */
+ uint32_t parent_qid; /* parent queue id */
+ uint64_t bandwidth; /* queue bandwidth */
+ uint8_t priority; /* priority */
+ uint8_t local_flags; /* dynamic interface, see _v0 */
+
+ uint16_t qlimit; /* queue size limit */
+ uint16_t flags; /* misc flags */
+ union {
+ struct cbq_opts cbq_opts;
+ struct codel_opts codel_opts;
+ struct priq_opts priq_opts;
+ struct hfsc_opts_v1 hfsc_opts;
+ struct fairq_opts fairq_opts;
+ } pq_u;
+
+ uint32_t qid; /* return value */
+};
+#endif /* _KERNEL */
+
+/*
+ * Compatibility and convenience macros
+ */
+#ifdef _KERNEL
+/*
+ * Avoid a patch with 100+ lines of name substitution.
+ */
+#define pf_altq pf_kaltq
+
+#else /* _KERNEL */
+
+#ifdef PFIOC_USE_LATEST
+/*
+ * Maintaining in-tree consumers of the ioctl interface is easier when that
+ * code can be written in terms old names that refer to the latest interface
+ * version as that reduces the required changes in the consumers to those
+ * that are functionally necessary to accommodate a new interface version.
+ */
+#define pf_altq __CONCAT(pf_altq_v, PF_ALTQ_VERSION)
+
+#else /* PFIOC_USE_LATEST */
+/*
+ * When building out-of-tree code that is written for the old interface,
+ * such as may exist in ports for example, resolve the old pf_altq struct
+ * tag to the v0 version.
+ */
+#define pf_altq __CONCAT(pf_altq_v, 0)
+
+#endif /* PFIOC_USE_LATEST */
+#endif /* _KERNEL */
+
#endif /* _NET_PF_ALTQ_H_ */
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index fa2c2d131d13..ecc3b59edf49 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -113,6 +113,12 @@ static int pf_commit_rules(u_int32_t, int, char *);
static int pf_addr_setup(struct pf_ruleset *,
struct pf_addr_wrap *, sa_family_t);
static void pf_addr_copyout(struct pf_addr_wrap *);
+#ifdef ALTQ
+static int pf_export_kaltq(struct pf_altq *,
+ struct pfioc_altq_v1 *, size_t);
+static int pf_import_kaltq(struct pfioc_altq_v1 *,
+ struct pf_altq *, size_t);
+#endif /* ALTQ */
VNET_DEFINE(struct pf_rule, pf_default_rule);
@@ -990,6 +996,222 @@ pf_addr_copyout(struct pf_addr_wrap *addr)
}
}
+#ifdef ALTQ
+/*
+ * Handle export of struct pf_kaltq to user binaries that may be using any
+ * version of struct pf_altq.
+ */
+static int
+pf_export_kaltq(struct pf_altq *q, struct pfioc_altq_v1 *pa, size_t ioc_size)
+{
+ u_int32_t version;
+
+ if (ioc_size == sizeof(struct pfioc_altq_v0))
+ version = 0;
+ else
+ version = pa->version;
+
+ if (version > PFIOC_ALTQ_VERSION)
+ return (EINVAL);
+
+#define ASSIGN(x) exported_q->x = q->x
+#define COPY(x) \
+ bcopy(&q->x, &exported_q->x, min(sizeof(q->x), sizeof(exported_q->x)))
+#define SATU16(x) (u_int32_t)uqmin((x), USHRT_MAX)
+#define SATU32(x) (u_int32_t)uqmin((x), UINT_MAX)
+
+ switch (version) {
+ case 0: {
+ struct pf_altq_v0 *exported_q =
+ &((struct pfioc_altq_v0 *)pa)->altq;
+
+ COPY(ifname);
+
+ ASSIGN(scheduler);
+ ASSIGN(tbrsize);
+ exported_q->tbrsize = SATU16(q->tbrsize);
+ exported_q->ifbandwidth = SATU32(q->ifbandwidth);
+
+ COPY(qname);
+ COPY(parent);
+ ASSIGN(parent_qid);
+ exported_q->bandwidth = SATU32(q->bandwidth);
+ ASSIGN(priority);
+ ASSIGN(local_flags);
+
+ ASSIGN(qlimit);
+ ASSIGN(flags);
+
+ if (q->scheduler == ALTQT_HFSC) {
+#define ASSIGN_OPT(x) exported_q->pq_u.hfsc_opts.x = q->pq_u.hfsc_opts.x
+#define ASSIGN_OPT_SATU32(x) exported_q->pq_u.hfsc_opts.x = \
+ SATU32(q->pq_u.hfsc_opts.x)
+
+ ASSIGN_OPT_SATU32(rtsc_m1);
+ ASSIGN_OPT(rtsc_d);
+ ASSIGN_OPT_SATU32(rtsc_m2);
+
+ ASSIGN_OPT_SATU32(lssc_m1);
+ ASSIGN_OPT(lssc_d);
+ ASSIGN_OPT_SATU32(lssc_m2);
+
+ ASSIGN_OPT_SATU32(ulsc_m1);
+ ASSIGN_OPT(ulsc_d);
+ ASSIGN_OPT_SATU32(ulsc_m2);
+
+ ASSIGN_OPT(flags);
+
+#undef ASSIGN_OPT
+#undef ASSIGN_OPT_SATU32
+ } else
+ COPY(pq_u);
+
+ ASSIGN(qid);
+ break;
+ }
+ case 1: {
+ struct pf_altq_v1 *exported_q =
+ &((struct pfioc_altq_v1 *)pa)->altq;
+
+ COPY(ifname);
+
+ ASSIGN(scheduler);
+ ASSIGN(tbrsize);
+ ASSIGN(ifbandwidth);
+
+ COPY(qname);
+ COPY(parent);
+ ASSIGN(parent_qid);
+ ASSIGN(bandwidth);
+ ASSIGN(priority);
+ ASSIGN(local_flags);
+
+ ASSIGN(qlimit);
+ ASSIGN(flags);
+ COPY(pq_u);
+
+ ASSIGN(qid);
+ break;
+ }
+ default:
+ panic("%s: unhandled struct pfioc_altq version", __func__);
+ break;
+ }
+
+#undef ASSIGN
+#undef COPY
+#undef SATU16
+#undef SATU32
+
+ return (0);
+}
+
+/*
+ * Handle import to struct pf_kaltq of struct pf_altq from user binaries
+ * that may be using any version of it.
+ */
+static int
+pf_import_kaltq(struct pfioc_altq_v1 *pa, struct pf_altq *q, size_t ioc_size)
+{
+ u_int32_t version;
+
+ if (ioc_size == sizeof(struct pfioc_altq_v0))
+ version = 0;
+ else
+ version = pa->version;
+
+ if (version > PFIOC_ALTQ_VERSION)
+ return (EINVAL);
+
+#define ASSIGN(x) q->x = imported_q->x
+#define COPY(x) \
+ bcopy(&imported_q->x, &q->x, min(sizeof(imported_q->x), sizeof(q->x)))
+
+ switch (version) {
+ case 0: {
+ struct pf_altq_v0 *imported_q =
+ &((struct pfioc_altq_v0 *)pa)->altq;
+
+ COPY(ifname);
+
+ ASSIGN(scheduler);
+ ASSIGN(tbrsize); /* 16-bit -> 32-bit */
+ ASSIGN(ifbandwidth); /* 32-bit -> 64-bit */
+
+ COPY(qname);
+ COPY(parent);
+ ASSIGN(parent_qid);
+ ASSIGN(bandwidth); /* 32-bit -> 64-bit */
+ ASSIGN(priority);
+ ASSIGN(local_flags);
+
+ ASSIGN(qlimit);
+ ASSIGN(flags);
+
+ if (imported_q->scheduler == ALTQT_HFSC) {
+#define ASSIGN_OPT(x) q->pq_u.hfsc_opts.x = imported_q->pq_u.hfsc_opts.x
+
+ /*
+ * The m1 and m2 parameters are being copied from
+ * 32-bit to 64-bit.
+ */
+ ASSIGN_OPT(rtsc_m1);
+ ASSIGN_OPT(rtsc_d);
+ ASSIGN_OPT(rtsc_m2);
+
+ ASSIGN_OPT(lssc_m1);
+ ASSIGN_OPT(lssc_d);
+ ASSIGN_OPT(lssc_m2);
+
+ ASSIGN_OPT(ulsc_m1);
+ ASSIGN_OPT(ulsc_d);
+ ASSIGN_OPT(ulsc_m2);
+
+ ASSIGN_OPT(flags);
+
+#undef ASSIGN_OPT
+ } else
+ COPY(pq_u);
+
+ ASSIGN(qid);
+ break;
+ }
+ case 1: {
+ struct pf_altq_v1 *imported_q =
+ &((struct pfioc_altq_v1 *)pa)->altq;
+
+ COPY(ifname);
+
+ ASSIGN(scheduler);
+ ASSIGN(tbrsize);
+ ASSIGN(ifbandwidth);
+
+ COPY(qname);
+ COPY(parent);
+ ASSIGN(parent_qid);
+ ASSIGN(bandwidth);
+ ASSIGN(priority);
+ ASSIGN(local_flags);
+
+ ASSIGN(qlimit);
+ ASSIGN(flags);
+ COPY(pq_u);
+
+ ASSIGN(qid);
+ break;
+ }
+ default:
+ panic("%s: unhandled struct pfioc_altq version", __func__);
+ break;
+ }
+
+#undef ASSIGN
+#undef COPY
+
+ return (0);
+}
+#endif /* ALTQ */
+
static int
pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
{
@@ -1013,9 +1235,12 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
case DIOCGETTIMEOUT:
case DIOCCLRRULECTRS:
case DIOCGETLIMIT:
- case DIOCGETALTQS:
- case DIOCGETALTQ:
- case DIOCGETQSTATS:
+ case DIOCGETALTQSV0:
+ case DIOCGETALTQSV1:
+ case DIOCGETALTQV0:
+ case DIOCGETALTQV1:
+ case DIOCGETQSTATSV0:
+ case DIOCGETQSTATSV1:
case DIOCGETRULESETS:
case DIOCGETRULESET:
case DIOCRGETTABLES:
@@ -1033,7 +1258,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
case DIOCGETSRCNODES:
case DIOCCLRSRCNODES:
case DIOCIGETIFACES:
- case DIOCGIFSPEED:
+ case DIOCGIFSPEEDV0:
+ case DIOCGIFSPEEDV1:
case DIOCSETIFFLAG:
case DIOCCLRIFFLAG:
break;
@@ -1059,9 +1285,12 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
case DIOCGETSTATES:
case DIOCGETTIMEOUT:
case DIOCGETLIMIT:
- case DIOCGETALTQS:
- case DIOCGETALTQ:
- case DIOCGETQSTATS:
+ case DIOCGETALTQSV0:
+ case DIOCGETALTQSV1:
+ case DIOCGETALTQV0:
+ case DIOCGETALTQV1:
+ case DIOCGETQSTATSV0:
+ case DIOCGETQSTATSV1:
case DIOCGETRULESETS:
case DIOCGETRULESET:
case DIOCNATLOOK:
@@ -1073,7 +1302,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
case DIOCOSFPGET:
case DIOCGETSRCNODES:
case DIOCIGETIFACES:
- case DIOCGIFSPEED:
+ case DIOCGIFSPEEDV1:
+ case DIOCGIFSPEEDV0:
break;
case DIOCRCLRTABLES:
case DIOCRADDTABLES:
@@ -2001,18 +2231,22 @@ DIOCGETSTATES_full:
break;
}
- case DIOCGIFSPEED: {
- struct pf_ifspeed *psp = (struct pf_ifspeed *)addr;
- struct pf_ifspeed ps;
+ case DIOCGIFSPEEDV0:
+ case DIOCGIFSPEEDV1: {
+ struct pf_ifspeed_v1 *psp = (struct pf_ifspeed_v1 *)addr;
+ struct pf_ifspeed_v1 ps;
struct ifnet *ifp;
if (psp->ifname[0] != 0) {
/* Can we completely trust user-land? */
strlcpy(ps.ifname, psp->ifname, IFNAMSIZ);
ifp = ifunit(ps.ifname);
- if (ifp != NULL)
- psp->baudrate = ifp->if_baudrate;
- else
+ if (ifp != NULL) {
+ psp->baudrate32 =
+ (u_int32_t)uqmin(ifp->if_baudrate, UINT_MAX);
+ if (cmd == DIOCGIFSPEEDV1)
+ psp->baudrate = ifp->if_baudrate;
+ } else
error = EINVAL;
} else
error = EINVAL;
@@ -2060,13 +2294,16 @@ DIOCGETSTATES_full:
break;
}
- case DIOCADDALTQ: {
- struct pfioc_altq *pa = (struct pfioc_altq *)addr;
+ case DIOCADDALTQV0:
+ case DIOCADDALTQV1: {
+ struct pfioc_altq_v1 *pa = (struct pfioc_altq_v1 *)addr;
struct pf_altq *altq, *a;
struct ifnet *ifp;
- altq = malloc(sizeof(*altq), M_PFALTQ, M_WAITOK);
- bcopy(&pa->altq, altq, sizeof(struct pf_altq));
+ altq = malloc(sizeof(*altq), M_PFALTQ, M_WAITOK | M_ZERO);
+ error = pf_import_kaltq(pa, altq, IOCPARM_LEN(cmd));
+ if (error)
+ break;
altq->local_flags = 0;
PF_RULES_WLOCK();
@@ -2110,13 +2347,15 @@ DIOCGETSTATES_full:
}
TAILQ_INSERT_TAIL(V_pf_altqs_inactive, altq, entries);
- bcopy(altq, &pa->altq, sizeof(struct pf_altq));
+ /* version error check done on import above */
+ pf_export_kaltq(altq, pa, IOCPARM_LEN(cmd));
PF_RULES_WUNLOCK();
break;
}
- case DIOCGETALTQS: {
- struct pfioc_altq *pa = (struct pfioc_altq *)addr;
+ case DIOCGETALTQSV0:
+ case DIOCGETALTQSV1: {
+ struct pfioc_altq_v1 *pa = (struct pfioc_altq_v1 *)addr;
struct pf_altq *altq;
PF_RULES_RLOCK();
@@ -2128,8 +2367,9 @@ DIOCGETSTATES_full:
break;
}
- case DIOCGETALTQ: {
- struct pfioc_altq *pa = (struct pfioc_altq *)addr;
+ case DIOCGETALTQV0:
+ case DIOCGETALTQV1: {
+ struct pfioc_altq_v1 *pa = (struct pfioc_altq_v1 *)addr;
struct pf_altq *altq;
u_int32_t nr;
@@ -2150,21 +2390,24 @@ DIOCGETSTATES_full:
error = EBUSY;
break;
}
- bcopy(altq, &pa->altq, sizeof(struct pf_altq));
+ pf_export_kaltq(altq, pa, IOCPARM_LEN(cmd));
PF_RULES_RUNLOCK();
break;
}
- case DIOCCHANGEALTQ:
+ case DIOCCHANGEALTQV0:
+ case DIOCCHANGEALTQV1:
/* CHANGEALTQ not supported yet! */
error = ENODEV;
break;
- case DIOCGETQSTATS: {
- struct pfioc_qstats *pq = (struct pfioc_qstats *)addr;
+ case DIOCGETQSTATSV0:
+ case DIOCGETQSTATSV1: {
+ struct pfioc_qstats_v1 *pq = (struct pfioc_qstats_v1 *)addr;
struct pf_altq *altq;
u_int32_t nr;
int nbytes;
+ u_int32_t version;
PF_RULES_RLOCK();
if (pq->ticket != V_ticket_altqs_active) {
@@ -2191,7 +2434,11 @@ DIOCGETSTATES_full:
break;
}
PF_RULES_RUNLOCK();
- error = altq_getqstats(altq, pq->buf, &nbytes);
+ if (cmd == DIOCGETQSTATSV0)
+ version = 0; /* DIOCGETQSTATSV0 means stats struct v0 */
+ else
+ version = pq->version;
+ error = altq_getqstats(altq, pq->buf, &nbytes, version);
if (error == 0) {
pq->scheduler = altq->scheduler;
pq->nbytes = nbytes;
diff --git a/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c b/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
index e79fc2dc24e5..7d4398264322 100644
--- a/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
+++ b/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
@@ -28,6 +28,8 @@
* $FreeBSD$
*/
+#define PFIOC_USE_LATEST
+
#include <sys/queue.h>
#include <bsnmp/snmpmod.h>
@@ -982,7 +984,8 @@ pf_altqq(struct snmp_context __unused *ctx, struct snmp_value *val,
val->v.integer = e->altq.scheduler;
break;
case LEAF_pfAltqQueueBandwidth:
- val->v.uint32 = e->altq.bandwidth;
+ val->v.uint32 = (e->altq.bandwidth > UINT_MAX) ?
+ UINT_MAX : (u_int32_t)e->altq.bandwidth;
break;
case LEAF_pfAltqQueuePriority:
val->v.integer = e->altq.priority;
@@ -1228,7 +1231,7 @@ pfq_refresh(void)
}
bzero(&pa, sizeof(pa));
-
+ pa.version = PFIOC_ALTQ_VERSION;
if (ioctl(dev, DIOCGETALTQS, &pa)) {
syslog(LOG_ERR, "pfq_refresh: ioctl(DIOCGETALTQS): %s",
strerror(errno));
@@ -1646,6 +1649,7 @@ altq_is_enabled(int pfdev)
struct pfioc_altq pa;
errno = 0;
+ pa.version = PFIOC_ALTQ_VERSION;
if (ioctl(pfdev, DIOCGETALTQS, &pa)) {
if (errno == ENODEV) {
syslog(LOG_INFO, "No ALTQ support in kernel\n"