svn commit: r338209 - in head: sbin/ipfw sbin/pfctl sys/net sys/net/altq sys/netpfil/pf usr.sbin/bsnmpd/modules/snmp_pf

Patrick Kelsey pkelsey at FreeBSD.org
Wed Aug 22 19:38:53 UTC 2018


Author: pkelsey
Date: Wed Aug 22 19:38:48 2018
New Revision: 338209
URL: https://svnweb.freebsd.org/changeset/base/338209

Log:
  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

Modified:
  head/sbin/ipfw/altq.c
  head/sbin/pfctl/parse.y
  head/sbin/pfctl/pfctl.c
  head/sbin/pfctl/pfctl_altq.c
  head/sbin/pfctl/pfctl_parser.h
  head/sbin/pfctl/pfctl_qstats.c
  head/sys/net/altq/altq.h
  head/sys/net/altq/altq_cbq.c
  head/sys/net/altq/altq_cbq.h
  head/sys/net/altq/altq_codel.c
  head/sys/net/altq/altq_codel.h
  head/sys/net/altq/altq_fairq.c
  head/sys/net/altq/altq_fairq.h
  head/sys/net/altq/altq_hfsc.c
  head/sys/net/altq/altq_hfsc.h
  head/sys/net/altq/altq_priq.c
  head/sys/net/altq/altq_priq.h
  head/sys/net/altq/altq_subr.c
  head/sys/net/altq/altq_var.h
  head/sys/net/pfvar.h
  head/sys/netpfil/pf/pf_altq.h
  head/sys/netpfil/pf/pf_ioctl.c
  head/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c

Modified: head/sbin/ipfw/altq.c
==============================================================================
--- head/sbin/ipfw/altq.c	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sbin/ipfw/altq.c	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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);

Modified: head/sbin/pfctl/parse.y
==============================================================================
--- head/sbin/pfctl/parse.y	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sbin/pfctl/parse.y	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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;
 			}

Modified: head/sbin/pfctl/pfctl.c
==============================================================================
--- head/sbin/pfctl/pfctl.c	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sbin/pfctl/pfctl.c	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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 opt
 	}
 
 	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)

Modified: head/sbin/pfctl/pfctl_altq.c
==============================================================================
--- head/sbin/pfctl/pfctl_altq.c	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sbin/pfctl/pfctl_altq.c	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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, doub
 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, stru
 		} 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, stru
 		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, str
 {
 	/* 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, str
 	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, str
 		}
 	}
 
-	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
 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_
 	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);

Modified: head/sbin/pfctl/pfctl_parser.h
==============================================================================
--- head/sbin/pfctl/pfctl_parser.h	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sbin/pfctl/pfctl_parser.h	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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;
 };
 

Modified: head/sbin/pfctl/pfctl_qstats.c
==============================================================================
--- head/sbin/pfctl/pfctl_qstats.c	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sbin/pfctl/pfctl_qstats.c	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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 **roo
 	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 **roo
 			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);

Modified: head/sys/net/altq/altq.h
==============================================================================
--- head/sys/net/altq/altq.h	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sys/net/altq/altq.h	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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_ */

Modified: head/sys/net/altq/altq_cbq.c
==============================================================================
--- head/sys/net/altq/altq_cbq.c	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sys/net/altq/altq_cbq.c	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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;

Modified: head/sys/net/altq/altq_cbq.h
==============================================================================
--- head/sys/net/altq/altq_cbq.h	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sys/net/altq/altq_cbq.h	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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.

Modified: head/sys/net/altq/altq_codel.c
==============================================================================
--- head/sys/net/altq/altq_codel.c	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sys/net/altq/altq_codel.c	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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;

Modified: head/sys/net/altq/altq_codel.h
==============================================================================
--- head/sys/net/altq/altq_codel.h	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sys/net/altq/altq_codel.h	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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>
 

Modified: head/sys/net/altq/altq_fairq.c
==============================================================================
--- head/sys/net/altq/altq_fairq.c	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sys/net/altq/altq_fairq.c	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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;

Modified: head/sys/net/altq/altq_fairq.h
==============================================================================
--- head/sys/net/altq/altq_fairq.h	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sys/net/altq/altq_fairq.h	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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 {

Modified: head/sys/net/altq/altq_hfsc.c
==============================================================================
--- head/sys/net/altq/altq_hfsc.c	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sys/net/altq/altq_hfsc.c	Wed Aug 22 19:38:48 2018	(r338209)
@@ -116,10 +116,10 @@ static struct hfsc_class	*actlist_firstfit(struct hfsc
 
 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,8 +130,10 @@ static u_int64_t	rtsc_x2y(struct runtime_sc *, u_int64
 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 *nby
 	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 ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
+	if (*nbytes < stats_size)
+		return (EINVAL);
+
+	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_
  *	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: (bytes/machclk tick) << SM_SHIFT
+ *	ism: (machclk ticks/byte) << ISM_SHIFT
+ *	dx: machclk ticks
  *
- * 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_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.
  *
- *  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
- *
- *  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 *
 }
 
 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;

Modified: head/sys/net/altq/altq_hfsc.h
==============================================================================
--- head/sys/net/altq/altq_hfsc.h	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sys/net/altq/altq_hfsc.h	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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,12 @@ 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	rsc;
-	struct service_curve	fsc;
-	struct service_curve	usc;	/* upper limit service curve */
+	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
@@ -110,6 +119,55 @@ struct hfsc_classstats {
 	struct codel_stats	codel;
 };
 
+struct hfsc_classstats_v1 {
+	u_int			class_id;
+	u_int32_t		class_handle;
+	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
+					   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;
+};
+
+/*
+ * 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) */
@@ -309,6 +367,35 @@ struct hfsc_if {
 	struct acc_classifier	hif_classifier;
 #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 */
 

Modified: head/sys/net/altq/altq_priq.c
==============================================================================
--- head/sys/net/altq/altq_priq.c	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sys/net/altq/altq_priq.c	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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;

Modified: head/sys/net/altq/altq_priq.h
==============================================================================
--- head/sys/net/altq/altq_priq.h	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sys/net/altq/altq_priq.h	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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;

Modified: head/sys/net/altq/altq_subr.c
==============================================================================
--- head/sys/net/altq/altq_subr.c	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sys/net/altq/altq_subr.c	Wed Aug 22 19:38:48 2018	(r338209)
@@ -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:

Modified: head/sys/net/altq/altq_var.h
==============================================================================
--- head/sys/net/altq/altq_var.h	Wed Aug 22 18:19:56 2018	(r338208)
+++ head/sys/net/altq/altq_var.h	Wed Aug 22 19:38:48 2018	(r338209)
@@ -196,7 +196,6 @@ u_int8_t read_dsfield(struct mbuf *, struct altq_pktat
 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 *);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list