mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-08-14 03:46:45 +00:00
tc: B.W limits can now be specified in %.
This patch adapts the tc command line interface to allow bandwidth limits to be specified as a percentage of the interface's capacity. Adding this functionality requires passing the specified device string to each class/qdisc which changes the prototype for a couple of functions: the .parse_qopt and .parse_copt interfaces. The device string is a required parameter for tc-qdisc and tc-class, and when not specified, the kernel returns ENODEV. In this patch, if the user tries to specify a bandwidth percentage without naming the device, we return an error from userspace. Signed-off-by: Nishanth Devarajan<ndev2021@gmail.com>
This commit is contained in:
parent
b317557f58
commit
927e3cfb52
@ -88,6 +88,8 @@ int get_prefix(inet_prefix *dst, char *arg, int family);
|
||||
int mask2bits(__u32 netmask);
|
||||
int get_addr_ila(__u64 *val, const char *arg);
|
||||
|
||||
int read_prop(const char *dev, char *prop, long *value);
|
||||
int parse_percent(double *val, const char *str);
|
||||
int get_hex(char c);
|
||||
int get_integer(int *val, const char *arg, int base);
|
||||
int get_unsigned(unsigned *val, const char *arg, int base);
|
||||
|
@ -223,38 +223,6 @@ static int do_del(int argc, char **argv)
|
||||
return tap_del_ioctl(&ifr);
|
||||
}
|
||||
|
||||
static int read_prop(char *dev, char *prop, long *value)
|
||||
{
|
||||
char fname[IFNAMSIZ+25], buf[80], *endp;
|
||||
ssize_t len;
|
||||
int fd;
|
||||
long result;
|
||||
|
||||
sprintf(fname, "/sys/class/net/%s/%s", dev, prop);
|
||||
fd = open(fname, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (strcmp(prop, "tun_flags"))
|
||||
fprintf(stderr, "open %s: %s\n", fname,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
len = read(fd, buf, sizeof(buf)-1);
|
||||
close(fd);
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "read %s: %s", fname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf[len] = 0;
|
||||
result = strtol(buf, &endp, 0);
|
||||
if (*endp != '\n') {
|
||||
fprintf(stderr, "Failed to parse %s\n", fname);
|
||||
return -1;
|
||||
}
|
||||
*value = result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_flags(long flags)
|
||||
{
|
||||
if (flags & IFF_TUN)
|
||||
|
68
lib/utils.c
68
lib/utils.c
@ -38,6 +38,74 @@
|
||||
int resolve_hosts;
|
||||
int timestamp_short;
|
||||
|
||||
int read_prop(const char *dev, char *prop, long *value)
|
||||
{
|
||||
char fname[128], buf[80], *endp, *nl;
|
||||
FILE *fp;
|
||||
long result;
|
||||
int ret;
|
||||
|
||||
ret = snprintf(fname, sizeof(fname), "/sys/class/net/%s/%s",
|
||||
dev, prop);
|
||||
|
||||
if (ret <= 0 || ret >= sizeof(fname)) {
|
||||
fprintf(stderr, "could not build pathname for property\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "fopen %s: %s\n", fname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!fgets(buf, sizeof(buf), fp)) {
|
||||
fprintf(stderr, "property \"%s\" in file %s is currently unknown\n", prop, fname);
|
||||
fclose(fp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
nl = strchr(buf, '\n');
|
||||
if (nl)
|
||||
*nl = '\0';
|
||||
|
||||
fclose(fp);
|
||||
result = strtol(buf, &endp, 0);
|
||||
|
||||
if (*endp || buf == endp) {
|
||||
fprintf(stderr, "value \"%s\" in file %s is not a number\n",
|
||||
buf, fname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((result == LONG_MAX || result == LONG_MIN) && errno == ERANGE) {
|
||||
fprintf(stderr, "strtol %s: %s", fname, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
*value = result;
|
||||
return 0;
|
||||
out:
|
||||
fprintf(stderr, "Failed to parse %s\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parse a percent e.g: '30%'
|
||||
* return: 0 = ok, -1 = error, 1 = out of range
|
||||
*/
|
||||
int parse_percent(double *val, const char *str)
|
||||
{
|
||||
char *p;
|
||||
|
||||
*val = strtod(str, &p) / 100.;
|
||||
if (*val == HUGE_VALF || *val == HUGE_VALL)
|
||||
return 1;
|
||||
if (*val == 0.0 || (*p && strcmp(p, "%")))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_hex(char c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'F')
|
||||
|
@ -443,7 +443,10 @@ see the man pages for individual qdiscs.
|
||||
RATES
|
||||
Bandwidths or rates.
|
||||
These parameters accept a floating point number, possibly followed by
|
||||
a unit (both SI and IEC units supported).
|
||||
either a unit (both SI and IEC units supported), or a float followed by a '%'
|
||||
character to specify the rate as a percentage of the device's speed
|
||||
(e.g. 5%, 99.5%). Warning: specifying the rate as a percentage means a fraction
|
||||
of the current speed; if the speed changes, the value will not be recalculated.
|
||||
.RS
|
||||
.TP
|
||||
bit or a bare number
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define MAX_HDR_LEN 64
|
||||
|
||||
|
||||
static int atm_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int atm_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
if (argc) {
|
||||
fprintf(stderr, "Usage: atm\n");
|
||||
@ -44,7 +44,7 @@ static void explain(void)
|
||||
|
||||
|
||||
static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
struct sockaddr_atmsvc addr = {};
|
||||
struct atm_qos qos;
|
||||
|
25
tc/q_cbq.c
25
tc/q_cbq.c
@ -46,7 +46,7 @@ static void explain1(char *arg)
|
||||
}
|
||||
|
||||
|
||||
static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
struct tc_ratespec r = {};
|
||||
struct tc_cbq_lssopt lss = {};
|
||||
@ -62,7 +62,12 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
|
||||
if (matches(*argv, "bandwidth") == 0 ||
|
||||
matches(*argv, "rate") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_rate(&r.rate, *argv)) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate(&r.rate, *argv, dev)) {
|
||||
explain1("bandwidth");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate(&r.rate, *argv)) {
|
||||
explain1("bandwidth");
|
||||
return -1;
|
||||
}
|
||||
@ -176,7 +181,7 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
int wrr_ok = 0, fopt_ok = 0;
|
||||
struct tc_ratespec r = {};
|
||||
@ -196,13 +201,23 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
|
||||
while (argc > 0) {
|
||||
if (matches(*argv, "rate") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_rate(&r.rate, *argv)) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate(&r.rate, *argv, dev)) {
|
||||
explain1("rate");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate(&r.rate, *argv)) {
|
||||
explain1("rate");
|
||||
return -1;
|
||||
}
|
||||
} else if (matches(*argv, "bandwidth") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_rate(&bndw, *argv)) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate(&bndw, *argv, dev)) {
|
||||
explain1("bandwidth");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate(&bndw, *argv)) {
|
||||
explain1("bandwidth");
|
||||
return -1;
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ static void explain1(const char *arg, const char *val)
|
||||
fprintf(stderr, "cbs: illegal value for \"%s\": \"%s\"\n", arg, val);
|
||||
}
|
||||
|
||||
static int cbs_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int cbs_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
struct tc_cbs_qopt opt = {};
|
||||
struct rtattr *tail;
|
||||
|
@ -31,7 +31,7 @@ static void explain(void)
|
||||
}
|
||||
|
||||
static int choke_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
struct tc_red_qopt opt = {};
|
||||
unsigned int burst = 0;
|
||||
@ -53,7 +53,12 @@ static int choke_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
}
|
||||
} else if (strcmp(*argv, "bandwidth") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_rate(&rate, *argv)) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate(&rate, *argv, dev)) {
|
||||
fprintf(stderr, "Illegal \"bandwidth\"\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate(&rate, *argv)) {
|
||||
fprintf(stderr, "Illegal \"bandwidth\"\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ static void explain(void)
|
||||
}
|
||||
|
||||
static int clsact_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
if (argc > 0) {
|
||||
fprintf(stderr, "What is \"%s\"?\n", *argv);
|
||||
|
@ -58,7 +58,7 @@ static void explain(void)
|
||||
}
|
||||
|
||||
static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
unsigned int limit = 0;
|
||||
unsigned int target = 0;
|
||||
|
@ -33,7 +33,7 @@ static void explain2(void)
|
||||
}
|
||||
|
||||
|
||||
static int drr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int drr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
while (argc) {
|
||||
if (strcmp(*argv, "help") == 0) {
|
||||
@ -49,7 +49,7 @@ static int drr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
|
||||
}
|
||||
|
||||
static int drr_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
struct rtattr *tail;
|
||||
__u32 tmp;
|
||||
|
@ -25,7 +25,7 @@ static void explain(void)
|
||||
|
||||
|
||||
static int dsmark_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
struct rtattr *tail;
|
||||
__u16 ind;
|
||||
@ -84,7 +84,7 @@ static void explain_class(void)
|
||||
|
||||
|
||||
static int dsmark_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
struct rtattr *tail;
|
||||
__u8 tmp;
|
||||
|
@ -27,7 +27,7 @@ static void explain(void)
|
||||
fprintf(stderr, "Usage: ... <[p|b]fifo | pfifo_head_drop> [ limit NUMBER ]\n");
|
||||
}
|
||||
|
||||
static int fifo_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int fifo_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
int ok = 0;
|
||||
struct tc_fifo_qopt opt = {};
|
||||
|
16
tc/q_fq.c
16
tc/q_fq.c
@ -71,7 +71,7 @@ static unsigned int ilog2(unsigned int val)
|
||||
}
|
||||
|
||||
static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
unsigned int plimit;
|
||||
unsigned int flow_plimit;
|
||||
@ -118,7 +118,12 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
}
|
||||
} else if (strcmp(*argv, "maxrate") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_rate(&maxrate, *argv)) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate(&maxrate, *argv, dev)) {
|
||||
fprintf(stderr, "Illegal \"maxrate\"\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate(&maxrate, *argv)) {
|
||||
fprintf(stderr, "Illegal \"maxrate\"\n");
|
||||
return -1;
|
||||
}
|
||||
@ -132,7 +137,12 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
set_low_rate_threshold = true;
|
||||
} else if (strcmp(*argv, "defrate") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_rate(&defrate, *argv)) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate(&defrate, *argv, dev)) {
|
||||
fprintf(stderr, "Illegal \"defrate\"\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate(&defrate, *argv)) {
|
||||
fprintf(stderr, "Illegal \"defrate\"\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ static void explain(void)
|
||||
}
|
||||
|
||||
static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
unsigned int limit = 0;
|
||||
unsigned int flows = 0;
|
||||
|
@ -116,7 +116,7 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv,
|
||||
/*
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
*/
|
||||
static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
int ok = 0;
|
||||
struct tc_gred_qopt opt = { 0 };
|
||||
@ -199,7 +199,12 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
|
||||
ok++;
|
||||
} else if (strcmp(*argv, "bandwidth") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_rate(&rate, *argv)) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate(&rate, *argv, dev)) {
|
||||
fprintf(stderr, "Illegal \"bandwidth\"\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate(&rate, *argv)) {
|
||||
fprintf(stderr, "Illegal \"bandwidth\"\n");
|
||||
return -1;
|
||||
}
|
||||
|
45
tc/q_hfsc.c
45
tc/q_hfsc.c
@ -23,7 +23,7 @@
|
||||
#include "utils.h"
|
||||
#include "tc_util.h"
|
||||
|
||||
static int hfsc_get_sc(int *, char ***, struct tc_service_curve *);
|
||||
static int hfsc_get_sc(int *, char ***, struct tc_service_curve *, const char *);
|
||||
|
||||
|
||||
static void
|
||||
@ -70,7 +70,7 @@ explain1(char *arg)
|
||||
}
|
||||
|
||||
static int
|
||||
hfsc_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
hfsc_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
struct tc_hfsc_qopt qopt = {};
|
||||
|
||||
@ -141,7 +141,7 @@ hfsc_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats)
|
||||
|
||||
static int
|
||||
hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
struct tc_service_curve rsc = {}, fsc = {}, usc = {};
|
||||
int rsc_ok = 0, fsc_ok = 0, usc_ok = 0;
|
||||
@ -150,21 +150,21 @@ hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
while (argc > 0) {
|
||||
if (matches(*argv, "rt") == 0) {
|
||||
NEXT_ARG();
|
||||
if (hfsc_get_sc(&argc, &argv, &rsc) < 0) {
|
||||
if (hfsc_get_sc(&argc, &argv, &rsc, dev) < 0) {
|
||||
explain1("rt");
|
||||
return -1;
|
||||
}
|
||||
rsc_ok = 1;
|
||||
} else if (matches(*argv, "ls") == 0) {
|
||||
NEXT_ARG();
|
||||
if (hfsc_get_sc(&argc, &argv, &fsc) < 0) {
|
||||
if (hfsc_get_sc(&argc, &argv, &fsc, dev) < 0) {
|
||||
explain1("ls");
|
||||
return -1;
|
||||
}
|
||||
fsc_ok = 1;
|
||||
} else if (matches(*argv, "sc") == 0) {
|
||||
NEXT_ARG();
|
||||
if (hfsc_get_sc(&argc, &argv, &rsc) < 0) {
|
||||
if (hfsc_get_sc(&argc, &argv, &rsc, dev) < 0) {
|
||||
explain1("sc");
|
||||
return -1;
|
||||
}
|
||||
@ -173,7 +173,7 @@ hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
fsc_ok = 1;
|
||||
} else if (matches(*argv, "ul") == 0) {
|
||||
NEXT_ARG();
|
||||
if (hfsc_get_sc(&argc, &argv, &usc) < 0) {
|
||||
if (hfsc_get_sc(&argc, &argv, &usc, dev) < 0) {
|
||||
explain1("ul");
|
||||
return -1;
|
||||
}
|
||||
@ -281,7 +281,7 @@ struct qdisc_util hfsc_qdisc_util = {
|
||||
};
|
||||
|
||||
static int
|
||||
hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc)
|
||||
hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc, const char *dev)
|
||||
{
|
||||
char **argv = *argvp;
|
||||
int argc = *argcp;
|
||||
@ -289,7 +289,12 @@ hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc)
|
||||
|
||||
if (matches(*argv, "m1") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_rate(&m1, *argv) < 0) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate(&m1, *argv, dev)) {
|
||||
explain1("m1");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate(&m1, *argv) < 0) {
|
||||
explain1("m1");
|
||||
return -1;
|
||||
}
|
||||
@ -307,7 +312,12 @@ hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc)
|
||||
|
||||
if (matches(*argv, "m2") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_rate(&m2, *argv) < 0) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate(&m2, *argv, dev)) {
|
||||
explain1("m2");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate(&m2, *argv) < 0) {
|
||||
explain1("m2");
|
||||
return -1;
|
||||
}
|
||||
@ -324,7 +334,7 @@ hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc)
|
||||
}
|
||||
|
||||
static int
|
||||
hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc)
|
||||
hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc, const char *dev)
|
||||
{
|
||||
char **argv = *argvp;
|
||||
int argc = *argcp;
|
||||
@ -350,7 +360,12 @@ hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc)
|
||||
|
||||
if (matches(*argv, "rate") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_rate(&rate, *argv) < 0) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate(&rate, *argv, dev)) {
|
||||
explain1("rate");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate(&rate, *argv) < 0) {
|
||||
explain1("rate");
|
||||
return -1;
|
||||
}
|
||||
@ -386,10 +401,10 @@ hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc)
|
||||
}
|
||||
|
||||
static int
|
||||
hfsc_get_sc(int *argcp, char ***argvp, struct tc_service_curve *sc)
|
||||
hfsc_get_sc(int *argcp, char ***argvp, struct tc_service_curve *sc, const char *dev)
|
||||
{
|
||||
if (hfsc_get_sc1(argcp, argvp, sc) < 0 &&
|
||||
hfsc_get_sc2(argcp, argvp, sc) < 0)
|
||||
if (hfsc_get_sc1(argcp, argvp, sc, dev) < 0 &&
|
||||
hfsc_get_sc2(argcp, argvp, sc, dev) < 0)
|
||||
return -1;
|
||||
|
||||
if (sc->m1 == 0 && sc->m2 == 0) {
|
||||
|
@ -25,7 +25,7 @@ static void explain(void)
|
||||
}
|
||||
|
||||
static int hhf_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
unsigned int limit = 0;
|
||||
unsigned int quantum = 0;
|
||||
|
18
tc/q_htb.c
18
tc/q_htb.c
@ -59,7 +59,7 @@ static void explain1(char *arg)
|
||||
}
|
||||
|
||||
|
||||
static int htb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int htb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
unsigned int direct_qlen = ~0U;
|
||||
struct tc_htb_glob opt = {
|
||||
@ -108,7 +108,7 @@ static int htb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
int ok = 0;
|
||||
struct tc_htb_opt opt = {};
|
||||
@ -178,7 +178,12 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
|
||||
fprintf(stderr, "Double \"ceil\" spec\n");
|
||||
return -1;
|
||||
}
|
||||
if (get_rate64(&ceil64, *argv)) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate64(&ceil64, *argv, dev)) {
|
||||
explain1("ceil");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate64(&ceil64, *argv)) {
|
||||
explain1("ceil");
|
||||
return -1;
|
||||
}
|
||||
@ -189,7 +194,12 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
|
||||
fprintf(stderr, "Double \"rate\" spec\n");
|
||||
return -1;
|
||||
}
|
||||
if (get_rate64(&rate64, *argv)) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate64(&rate64, *argv, dev)) {
|
||||
explain1("rate");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate64(&rate64, *argv)) {
|
||||
explain1("rate");
|
||||
return -1;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ static void explain(void)
|
||||
}
|
||||
|
||||
static int ingress_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
while (argc > 0) {
|
||||
if (strcmp(*argv, "handle") == 0) {
|
||||
|
@ -33,7 +33,7 @@ static void explain(void)
|
||||
}
|
||||
|
||||
static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
|
||||
char **argv, struct nlmsghdr *n)
|
||||
char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
int idx;
|
||||
struct tc_mqprio_qopt opt = {
|
||||
|
@ -40,7 +40,7 @@ static void explain(void)
|
||||
}
|
||||
|
||||
static int multiq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
struct tc_multiq_qopt opt = {};
|
||||
|
||||
|
23
tc/q_netem.c
23
tc/q_netem.c
@ -59,20 +59,6 @@ static void set_percent(__u32 *percent, double per)
|
||||
*percent = rint(per * UINT32_MAX);
|
||||
}
|
||||
|
||||
/* Parse either a fraction '.3' or percent '30%
|
||||
* return: 0 = ok, -1 = error, 1 = out of range
|
||||
*/
|
||||
static int parse_percent(double *val, const char *str)
|
||||
{
|
||||
char *p;
|
||||
|
||||
*val = strtod(str, &p) / 100.;
|
||||
if (*p && strcmp(p, "%"))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_percent(__u32 *percent, const char *str)
|
||||
{
|
||||
double per;
|
||||
@ -167,7 +153,7 @@ static int get_ticks(__u32 *ticks, const char *str)
|
||||
}
|
||||
|
||||
static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
int dist_size = 0;
|
||||
struct rtattr *tail;
|
||||
@ -396,7 +382,12 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
} else if (matches(*argv, "rate") == 0) {
|
||||
++present[TCA_NETEM_RATE];
|
||||
NEXT_ARG();
|
||||
if (get_rate64(&rate64, *argv)) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate64(&rate64, *argv, dev)) {
|
||||
explain1("rate");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate64(&rate64, *argv)) {
|
||||
explain1("rate");
|
||||
return -1;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ static void explain(void)
|
||||
#define BETA_MAX 32
|
||||
|
||||
static int pie_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
unsigned int limit = 0;
|
||||
unsigned int target = 0;
|
||||
|
@ -27,7 +27,7 @@ static void explain(void)
|
||||
fprintf(stderr, "Usage: ... prio bands NUMBER priomap P1 P2...[multiqueue]\n");
|
||||
}
|
||||
|
||||
static int prio_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int prio_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
int pmap_mode = 0;
|
||||
int idx = 0;
|
||||
|
@ -35,7 +35,7 @@ static void explain_class(void)
|
||||
}
|
||||
|
||||
static int qfq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
if (argc > 0) {
|
||||
if (matches(*argv, "help") != 0)
|
||||
@ -48,7 +48,7 @@ static int qfq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
}
|
||||
|
||||
static int qfq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
struct rtattr *tail;
|
||||
__u32 tmp;
|
||||
|
@ -32,7 +32,7 @@ static void explain(void)
|
||||
fprintf(stderr, " [ecn] [harddrop]\n");
|
||||
}
|
||||
|
||||
static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
struct tc_red_qopt opt = {};
|
||||
unsigned int burst = 0;
|
||||
@ -83,7 +83,12 @@ static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
|
||||
}
|
||||
} else if (strcmp(*argv, "bandwidth") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_rate(&rate, *argv)) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate(&rate, *argv, dev)) {
|
||||
fprintf(stderr, "Illegal \"bandwidth\"\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate(&rate, *argv)) {
|
||||
fprintf(stderr, "Illegal \"bandwidth\"\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ static void explain(void)
|
||||
}
|
||||
|
||||
|
||||
static int rr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int rr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
int pmap_mode = 0;
|
||||
int idx = 0;
|
||||
|
@ -48,7 +48,7 @@ static int get_prob(__u32 *val, const char *arg)
|
||||
}
|
||||
|
||||
static int sfb_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
struct tc_sfb_qopt opt = {
|
||||
.rehash_interval = 600*1000,
|
||||
|
@ -34,7 +34,7 @@ static void explain(void)
|
||||
fprintf(stderr, " [ ecn ] [ harddrop ]\n");
|
||||
}
|
||||
|
||||
static int sfq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int sfq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
int ok = 0, red = 0;
|
||||
struct tc_sfq_qopt_v1 opt = {};
|
||||
|
16
tc/q_tbf.c
16
tc/q_tbf.c
@ -35,7 +35,7 @@ static void explain1(const char *arg, const char *val)
|
||||
}
|
||||
|
||||
|
||||
static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
int ok = 0;
|
||||
struct tc_tbf_qopt opt = {};
|
||||
@ -125,7 +125,12 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
|
||||
fprintf(stderr, "tbf: duplicate \"rate\" specification\n");
|
||||
return -1;
|
||||
}
|
||||
if (get_rate64(&rate64, *argv)) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate64(&rate64, *argv, dev)) {
|
||||
explain1("rate", *argv);
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate64(&rate64, *argv)) {
|
||||
explain1("rate", *argv);
|
||||
return -1;
|
||||
}
|
||||
@ -136,7 +141,12 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
|
||||
fprintf(stderr, "tbf: duplicate \"peakrate\" specification\n");
|
||||
return -1;
|
||||
}
|
||||
if (get_rate64(&prate64, *argv)) {
|
||||
if (strchr(*argv, '%')) {
|
||||
if (get_percent_rate64(&prate64, *argv, dev)) {
|
||||
explain1("peakrate", *argv);
|
||||
return -1;
|
||||
}
|
||||
} else if (get_rate64(&prate64, *argv)) {
|
||||
explain1("peakrate", *argv);
|
||||
return -1;
|
||||
}
|
||||
|
2
tc/tc.c
2
tc/tc.c
@ -59,7 +59,7 @@ static int print_noqopt(struct qdisc_util *qu, FILE *f,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_noqopt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
|
||||
static int parse_noqopt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
if (argc) {
|
||||
fprintf(stderr, "Unknown qdisc \"%s\", hence option \"%s\" is unparsable\n", qu->id, *argv);
|
||||
|
@ -128,7 +128,7 @@ static int tc_class_modify(int cmd, unsigned int flags, int argc, char **argv)
|
||||
fprintf(stderr, "Error: Qdisc \"%s\" is classless.\n", k);
|
||||
return 1;
|
||||
}
|
||||
if (q->parse_copt(q, argc, argv, &req.n))
|
||||
if (q->parse_copt(q, argc, argv, &req.n, d))
|
||||
return 1;
|
||||
} else {
|
||||
if (argc) {
|
||||
|
@ -140,7 +140,7 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv)
|
||||
|
||||
if (q) {
|
||||
if (q->parse_qopt) {
|
||||
if (q->parse_qopt(q, argc, argv, &req.n))
|
||||
if (q->parse_qopt(q, argc, argv, &req.n, d))
|
||||
return 1;
|
||||
} else if (argc) {
|
||||
fprintf(stderr, "qdisc '%s' does not support option parsing\n", k);
|
||||
|
63
tc/tc_util.c
63
tc/tc_util.c
@ -190,6 +190,69 @@ static const struct rate_suffix {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
int parse_percent_rate(char *rate, const char *str, const char *dev)
|
||||
{
|
||||
long dev_mbit;
|
||||
int ret;
|
||||
double perc, rate_mbit;
|
||||
char *str_perc;
|
||||
|
||||
if (!dev[0]) {
|
||||
fprintf(stderr, "No device specified; specify device to rate limit by percentage\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (read_prop(dev, "speed", &dev_mbit))
|
||||
return -1;
|
||||
|
||||
ret = sscanf(str, "%m[0-9.%]", &str_perc);
|
||||
if (ret != 1)
|
||||
goto malf;
|
||||
|
||||
if (parse_percent(&perc, str_perc))
|
||||
goto malf;
|
||||
|
||||
free(str_perc);
|
||||
|
||||
if (perc > 1.0 || perc < 0.0) {
|
||||
fprintf(stderr, "Invalid rate specified; should be between [0,100]%% but is %s\n", str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rate_mbit = perc * dev_mbit;
|
||||
|
||||
ret = snprintf(rate, 20, "%lf", rate_mbit);
|
||||
if (ret <= 0 || ret >= 20) {
|
||||
fprintf(stderr, "Unable to parse calculated rate\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
malf:
|
||||
fprintf(stderr, "Specified rate value could not be read or is malformed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int get_percent_rate(unsigned int *rate, const char *str, const char *dev)
|
||||
{
|
||||
char r_str[20];
|
||||
|
||||
if (parse_percent_rate(r_str, str, dev))
|
||||
return -1;
|
||||
|
||||
return get_rate(rate, r_str);
|
||||
}
|
||||
|
||||
int get_percent_rate64(__u64 *rate, const char *str, const char *dev)
|
||||
{
|
||||
char r_str[20];
|
||||
|
||||
if (parse_percent_rate(r_str, str, dev))
|
||||
return -1;
|
||||
|
||||
return get_rate64(rate, r_str);
|
||||
}
|
||||
|
||||
int get_rate(unsigned int *rate, const char *str)
|
||||
{
|
||||
|
@ -29,14 +29,14 @@ struct qdisc_util {
|
||||
struct qdisc_util *next;
|
||||
const char *id;
|
||||
int (*parse_qopt)(struct qdisc_util *qu, int argc,
|
||||
char **argv, struct nlmsghdr *n);
|
||||
char **argv, struct nlmsghdr *n, const char *dev);
|
||||
int (*print_qopt)(struct qdisc_util *qu,
|
||||
FILE *f, struct rtattr *opt);
|
||||
int (*print_xstats)(struct qdisc_util *qu,
|
||||
FILE *f, struct rtattr *xstats);
|
||||
|
||||
int (*parse_copt)(struct qdisc_util *qu, int argc,
|
||||
char **argv, struct nlmsghdr *n);
|
||||
char **argv, struct nlmsghdr *n, const char *dev);
|
||||
int (*print_copt)(struct qdisc_util *qu, FILE *f, struct rtattr *opt);
|
||||
};
|
||||
|
||||
@ -71,9 +71,12 @@ const char *get_tc_lib(void);
|
||||
struct qdisc_util *get_qdisc_kind(const char *str);
|
||||
struct filter_util *get_filter_kind(const char *str);
|
||||
|
||||
int parse_percent_rate(char *rate, const char *str, const char *dev);
|
||||
int get_qdisc_handle(__u32 *h, const char *str);
|
||||
int get_rate(unsigned int *rate, const char *str);
|
||||
int get_percent_rate(unsigned int *rate, const char *str, const char *dev);
|
||||
int get_rate64(__u64 *rate, const char *str);
|
||||
int get_percent_rate64(__u64 *rate, const char *str, const char *dev);
|
||||
int get_size(unsigned int *size, const char *str);
|
||||
int get_size_and_cell(unsigned int *size, int *cell_log, char *str);
|
||||
int get_time(unsigned int *time, const char *str);
|
||||
|
Loading…
Reference in New Issue
Block a user