summaryrefslogtreecommitdiffstats
path: root/freebsd/sbin/pfctl/pfctl_altq.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sbin/pfctl/pfctl_altq.c')
-rw-r--r--freebsd/sbin/pfctl/pfctl_altq.c69
1 files changed, 47 insertions, 22 deletions
diff --git a/freebsd/sbin/pfctl/pfctl_altq.c b/freebsd/sbin/pfctl/pfctl_altq.c
index 145d60ae..1220cfc6 100644
--- a/freebsd/sbin/pfctl/pfctl_altq.c
+++ b/freebsd/sbin/pfctl/pfctl_altq.c
@@ -24,12 +24,14 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#ifdef __rtems__
#include <machine/rtems-bsd-program.h>
#endif /* __rtems__ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define PFIOC_USE_LATEST
+
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -40,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
+#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
@@ -100,14 +103,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,
@@ -270,7 +273,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;
@@ -287,6 +291,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 */
@@ -298,11 +311,11 @@ eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
size = 4;
else if (rate <= 200 * 1000 * 1000)
size = 8;
- else
+ else if (rate <= 2500 * 1000 * 1000ULL)
size = 24;
+ else
+ size = 128;
size = size * getifmtu(pa->ifname);
- if (size > 0xffff)
- size = 0xffff;
pa->tbrsize = size;
}
return (errors);
@@ -350,7 +363,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 */
@@ -384,7 +397,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 "
@@ -415,7 +428,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) {
@@ -509,12 +523,13 @@ cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa)
* this causes integer overflow in kernel!
* (bandwidth < 6Kbps when max_pkt_size=1500)
*/
- if (pa->bandwidth != 0 && (pf->opts & PF_OPT_QUIET) == 0)
+ if (pa->bandwidth != 0 && (pf->opts & PF_OPT_QUIET) == 0) {
warnx("queue bandwidth must be larger than %s",
rate2str(ifnsPerByte * (double)opts->maxpktsize /
(double)INT_MAX * (double)pa->ifbandwidth));
fprintf(stderr, "cbq: queue %s is too slow!\n",
pa->qname);
+ }
nsPerByte = (double)(INT_MAX / opts->maxpktsize);
}
@@ -720,7 +735,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;
@@ -1012,7 +1027,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;
@@ -1333,7 +1348,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;
@@ -1344,7 +1359,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
@@ -1399,7 +1414,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;
@@ -1475,11 +1490,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);