aboutsummaryrefslogtreecommitdiff
path: root/sys/net/altq
diff options
context:
space:
mode:
authorPatrick Kelsey <pkelsey@FreeBSD.org>2018-08-22 19:38:48 +0000
committerPatrick Kelsey <pkelsey@FreeBSD.org>2018-08-22 19:38:48 +0000
commit249cc75fd14eac511a102b657646f98229c9dcc3 (patch)
tree3e80c0ad9bcf7e59a8ad3c979d54e2d4249a6d99 /sys/net/altq
parentfe2bf351fe0095c8ca716ac9f085ced51a243a2e (diff)
downloadsrc-249cc75fd14eac511a102b657646f98229c9dcc3.tar.gz
src-249cc75fd14eac511a102b657646f98229c9dcc3.zip
Extended pf(4) ioctl interface and pfctl(8) to allow bandwidths of
2^32 bps or greater to be used. Prior to this, bandwidth parameters would simply wrap at the 2^32 boundary. The computations in the HFSC scheduler and token bucket regulator have been modified to operate correctly up to at least 100 Gbps. No other algorithms have been examined or modified for correct operation above 2^32 bps (some may have existing computation resolution or overflow issues at rates below that threshold). pfctl(8) will now limit non-HFSC bandwidth parameters to 2^32 - 1 before passing them to the kernel. The extensions to the pf(4) ioctl interface have been made in a backwards-compatible way by versioning affected data structures, supporting all versions in the kernel, and implementing macros that will cause existing code that consumes that interface to use version 0 without source modifications. If version 0 consumers of the interface are used against a new kernel that has had bandwidth parameters of 2^32 or greater configured by updated tools, such bandwidth parameters will be reported as 2^32 - 1 bps by those old consumers. All in-tree consumers of the pf(4) interface have been updated. To update out-of-tree consumers to the latest version of the interface, define PFIOC_USE_LATEST ahead of any includes and use the code of pfctl(8) as a guide for the ioctls of interest. PR: 211730 Reviewed by: jmallett, kp, loos MFC after: 2 weeks Relnotes: yes Sponsored by: RG Nets Differential Revision: https://reviews.freebsd.org/D16782
Notes
Notes: svn path=/head/; revision=338209
Diffstat (limited to 'sys/net/altq')
-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
13 files changed, 303 insertions, 87 deletions
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_ */