From b317557f5854bb8e4ed0ff47a2327f652c6e3433 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 24 Nov 2017 11:18:31 -0800 Subject: [PATCH 01/36] tc: replace magic constant 16 with #define For places where tc is expecting device name use IFNAMSIZ. For others where it is a filter name, introduce a new constant. Signed-off-by: Stephen Hemminger --- tc/m_action.c | 6 +++--- tc/m_ipt.c | 2 +- tc/m_mirred.c | 2 +- tc/m_pedit.c | 2 +- tc/m_xt.c | 2 +- tc/m_xt_old.c | 2 +- tc/tc_class.c | 6 +++--- tc/tc_exec.c | 2 +- tc/tc_filter.c | 10 +++++----- tc/tc_qdisc.c | 6 +++--- tc/tc_util.h | 11 ++++++++--- 11 files changed, 28 insertions(+), 23 deletions(-) diff --git a/tc/m_action.c b/tc/m_action.c index 0dce97f0..85f9e27b 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -154,7 +154,7 @@ int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) int argc = *argc_p; char **argv = *argv_p; struct rtattr *tail, *tail2; - char k[16]; + char k[FILTER_NAMESZ]; int act_ck_len = 0; int ok = 0; int eap = 0; /* expect action parameters */ @@ -431,7 +431,7 @@ int print_action(const struct sockaddr_nl *who, static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p) { - char k[16]; + char k[FILTER_NAMESZ]; struct action_util *a = NULL; int argc = *argc_p; char **argv = *argv_p; @@ -581,7 +581,7 @@ static int tc_act_list_or_flush(int *argc_p, char ***argv_p, int event) char **argv = *argv_p; __u32 msec_since = 0; int argc = *argc_p; - char k[16]; + char k[FILTER_NAMESZ]; struct { struct nlmsghdr n; struct tcamsg t; diff --git a/tc/m_ipt.c b/tc/m_ipt.c index 942b4f23..1c3c240f 100644 --- a/tc/m_ipt.c +++ b/tc/m_ipt.c @@ -286,7 +286,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, int rargc = *argc_p; char **argv = *argv_p; int argc = 0, iargc = 0; - char k[16]; + char k[FILTER_NAMESZ]; int size = 0; int iok = 0, ok = 0; __u32 hook = 0, index = 0; diff --git a/tc/m_mirred.c b/tc/m_mirred.c index d0b7a46a..33c915d6 100644 --- a/tc/m_mirred.c +++ b/tc/m_mirred.c @@ -70,7 +70,7 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p, int ok = 0, iok = 0, mirror = 0, redir = 0, ingress = 0, egress = 0; struct tc_mirred p = {}; struct rtattr *tail; - char d[16] = {}; + char d[IFNAMSIZ] = {}; while (argc > 0) { diff --git a/tc/m_pedit.c b/tc/m_pedit.c index a6da9536..26549eee 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -524,7 +524,7 @@ static int parse_munge(int *argc_p, char ***argv_p, struct m_pedit_sel *sel) res = parse_offset(&argc, &argv, sel, &tkey); goto done; } else { - char k[16]; + char k[FILTER_NAMESZ]; struct m_pedit_util *p = NULL; strncpy(k, *argv, sizeof(k) - 1); diff --git a/tc/m_xt.c b/tc/m_xt.c index 0baea33c..a1137be9 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -154,7 +154,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, int c; char **argv = *argv_p; int argc; - char k[16]; + char k[FILTER_NAMESZ]; int size = 0; int iok = 0, ok = 0; __u32 hook = 0, index = 0; diff --git a/tc/m_xt_old.c b/tc/m_xt_old.c index 4e56e267..21d90877 100644 --- a/tc/m_xt_old.c +++ b/tc/m_xt_old.c @@ -213,7 +213,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, int rargc = *argc_p; char **argv = *argv_p; int argc = 0, iargc = 0; - char k[16]; + char k[FILTER_NAMESZ]; int size = 0; int iok = 0, ok = 0; __u32 hook = 0, index = 0; diff --git a/tc/tc_class.c b/tc/tc_class.c index c4a6a250..507864ad 100644 --- a/tc/tc_class.c +++ b/tc/tc_class.c @@ -67,8 +67,8 @@ static int tc_class_modify(int cmd, unsigned int flags, int argc, char **argv) }; struct qdisc_util *q = NULL; struct tc_estimator est = {}; - char d[16] = {}; - char k[16] = {}; + char d[IFNAMSIZ] = {}; + char k[FILTER_NAMESZ] = {}; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { @@ -388,7 +388,7 @@ int print_class(const struct sockaddr_nl *who, static int tc_class_list(int argc, char **argv) { struct tcmsg t = { .tcm_family = AF_UNSPEC }; - char d[16] = {}; + char d[IFNAMSIZ] = {}; char buf[1024] = {0}; filter_qdisc = 0; diff --git a/tc/tc_exec.c b/tc/tc_exec.c index d23a825d..0151af7b 100644 --- a/tc/tc_exec.c +++ b/tc/tc_exec.c @@ -84,7 +84,7 @@ noexist: int do_exec(int argc, char **argv) { struct exec_util *eu; - char kind[16] = {}; + char kind[FILTER_NAMESZ] = {}; if (argc < 1) { fprintf(stderr, "No command given, try \"tc exec help\".\n"); diff --git a/tc/tc_filter.c b/tc/tc_filter.c index d0c967a9..276a66cb 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -61,8 +61,8 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv) __u32 chain_index; int chain_index_set = 0; char *fhandle = NULL; - char d[16] = {}; - char k[16] = {}; + char d[IFNAMSIZ] = {}; + char k[FILTER_NAMESZ] = {}; struct tc_estimator est = {}; if (cmd == RTM_NEWTFILTER && flags & NLM_F_CREATE) @@ -339,8 +339,8 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv) int chain_index_set = 0; __u32 parent_handle = 0; char *fhandle = NULL; - char d[16] = {}; - char k[16] = {}; + char d[IFNAMSIZ] = {}; + char k[FILTER_NAMESZ] = {}; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { @@ -507,7 +507,7 @@ static int tc_filter_list(int argc, char **argv) .t.tcm_parent = TC_H_UNSPEC, .t.tcm_family = AF_UNSPEC, }; - char d[16] = {}; + char d[IFNAMSIZ] = {}; __u32 prio = 0; __u32 protocol = 0; __u32 chain_index; diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index fcb75f29..56034b59 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -49,8 +49,8 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv) struct tc_sizespec szopts; __u16 *data; } stab = {}; - char d[16] = {}; - char k[16] = {}; + char d[IFNAMSIZ] = {}; + char k[FILTER_NAMESZ] = {}; struct { struct nlmsghdr n; struct tcmsg t; @@ -300,7 +300,7 @@ int print_qdisc(const struct sockaddr_nl *who, static int tc_qdisc_list(int argc, char **argv) { struct tcmsg t = { .tcm_family = AF_UNSPEC }; - char d[16] = {}; + char d[IFNAMSIZ] = {}; bool dump_invisible = false; while (argc > 0) { diff --git a/tc/tc_util.h b/tc/tc_util.h index 583a21a8..3d3d4f1d 100644 --- a/tc/tc_util.h +++ b/tc/tc_util.h @@ -3,9 +3,12 @@ #define MAX_MSG 16384 #include +#include + #include #include #include + #include "tc_core.h" /* This is the deprecated multiqueue interface */ @@ -20,6 +23,8 @@ enum #define TCA_PRIO_MAX (__TCA_PRIO_MAX - 1) #endif +#define FILTER_NAMESZ 16 + struct qdisc_util { struct qdisc_util *next; const char *id; @@ -38,7 +43,7 @@ struct qdisc_util { extern __u16 f_proto; struct filter_util { struct filter_util *next; - char id[16]; + char id[FILTER_NAMESZ]; int (*parse_fopt)(struct filter_util *qu, char *fhandle, int argc, char **argv, struct nlmsghdr *n); int (*print_fopt)(struct filter_util *qu, @@ -47,7 +52,7 @@ struct filter_util { struct action_util { struct action_util *next; - char id[16]; + char id[FILTER_NAMESZ]; int (*parse_aopt)(struct action_util *a, int *argc, char ***argv, int code, struct nlmsghdr *n); int (*print_aopt)(struct action_util *au, FILE *f, struct rtattr *opt); @@ -57,7 +62,7 @@ struct action_util { struct exec_util { struct exec_util *next; - char id[16]; + char id[FILTER_NAMESZ]; int (*parse_eopt)(struct exec_util *eu, int argc, char **argv); }; From 927e3cfb52b58fbdf217d84204d653db101c137a Mon Sep 17 00:00:00 2001 From: Nishanth Devarajan Date: Tue, 21 Nov 2017 07:50:47 +0530 Subject: [PATCH 02/36] 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 --- include/utils.h | 2 ++ ip/iptuntap.c | 32 ----------------------- lib/utils.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++ man/man8/tc.8 | 5 +++- tc/q_atm.c | 4 +-- tc/q_cbq.c | 25 ++++++++++++++---- tc/q_cbs.c | 2 +- tc/q_choke.c | 9 +++++-- tc/q_clsact.c | 2 +- tc/q_codel.c | 2 +- tc/q_drr.c | 4 +-- tc/q_dsmark.c | 4 +-- tc/q_fifo.c | 2 +- tc/q_fq.c | 16 +++++++++--- tc/q_fq_codel.c | 2 +- tc/q_gred.c | 9 +++++-- tc/q_hfsc.c | 45 +++++++++++++++++++++----------- tc/q_hhf.c | 2 +- tc/q_htb.c | 18 ++++++++++--- tc/q_ingress.c | 2 +- tc/q_mqprio.c | 2 +- tc/q_multiq.c | 2 +- tc/q_netem.c | 23 +++++------------ tc/q_pie.c | 2 +- tc/q_prio.c | 2 +- tc/q_qfq.c | 4 +-- tc/q_red.c | 9 +++++-- tc/q_rr.c | 2 +- tc/q_sfb.c | 2 +- tc/q_sfq.c | 2 +- tc/q_tbf.c | 16 +++++++++--- tc/tc.c | 2 +- tc/tc_class.c | 2 +- tc/tc_qdisc.c | 2 +- tc/tc_util.c | 63 +++++++++++++++++++++++++++++++++++++++++++++ tc/tc_util.h | 7 +++-- 36 files changed, 285 insertions(+), 112 deletions(-) diff --git a/include/utils.h b/include/utils.h index 10749fbe..9c37c613 100644 --- a/include/utils.h +++ b/include/utils.h @@ -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); diff --git a/ip/iptuntap.c b/ip/iptuntap.c index b46e452f..09f2be24 100644 --- a/ip/iptuntap.c +++ b/ip/iptuntap.c @@ -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) diff --git a/lib/utils.c b/lib/utils.c index 48cead19..7ced8c06 100644 --- a/lib/utils.c +++ b/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') diff --git a/man/man8/tc.8 b/man/man8/tc.8 index f96911ae..263dc75d 100644 --- a/man/man8/tc.8 +++ b/man/man8/tc.8 @@ -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 diff --git a/tc/q_atm.c b/tc/q_atm.c index 570e7be5..787b46cd 100644 --- a/tc/q_atm.c +++ b/tc/q_atm.c @@ -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; diff --git a/tc/q_cbq.c b/tc/q_cbq.c index e00d4e38..d05fe9c8 100644 --- a/tc/q_cbq.c +++ b/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; } diff --git a/tc/q_cbs.c b/tc/q_cbs.c index ec1cbe83..e1134c3a 100644 --- a/tc/q_cbs.c +++ b/tc/q_cbs.c @@ -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; diff --git a/tc/q_choke.c b/tc/q_choke.c index 726914b2..50ac4ad4 100644 --- a/tc/q_choke.c +++ b/tc/q_choke.c @@ -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; } diff --git a/tc/q_clsact.c b/tc/q_clsact.c index e2a1a710..5e8dd91c 100644 --- a/tc/q_clsact.c +++ b/tc/q_clsact.c @@ -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); diff --git a/tc/q_codel.c b/tc/q_codel.c index 253629ef..62d6dd68 100644 --- a/tc/q_codel.c +++ b/tc/q_codel.c @@ -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; diff --git a/tc/q_drr.c b/tc/q_drr.c index 50623c22..85aa5b60 100644 --- a/tc/q_drr.c +++ b/tc/q_drr.c @@ -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; diff --git a/tc/q_dsmark.c b/tc/q_dsmark.c index 0aab387d..65eeb271 100644 --- a/tc/q_dsmark.c +++ b/tc/q_dsmark.c @@ -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; diff --git a/tc/q_fifo.c b/tc/q_fifo.c index c3e90886..c89d186d 100644 --- a/tc/q_fifo.c +++ b/tc/q_fifo.c @@ -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 = {}; diff --git a/tc/q_fq.c b/tc/q_fq.c index 49ebeefa..51b5bc36 100644 --- a/tc/q_fq.c +++ b/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; } diff --git a/tc/q_fq_codel.c b/tc/q_fq_codel.c index 1eac1403..86c6fb24 100644 --- a/tc/q_fq_codel.c +++ b/tc/q_fq_codel.c @@ -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; diff --git a/tc/q_gred.c b/tc/q_gred.c index 2eb906d0..5b5761ee 100644 --- a/tc/q_gred.c +++ b/tc/q_gred.c @@ -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; } diff --git a/tc/q_hfsc.c b/tc/q_hfsc.c index dc9fed93..597a659a 100644 --- a/tc/q_hfsc.c +++ b/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) { diff --git a/tc/q_hhf.c b/tc/q_hhf.c index d1f15f9a..2ec3d42f 100644 --- a/tc/q_hhf.c +++ b/tc/q_hhf.c @@ -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; diff --git a/tc/q_htb.c b/tc/q_htb.c index db828523..3e295a71 100644 --- a/tc/q_htb.c +++ b/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; } diff --git a/tc/q_ingress.c b/tc/q_ingress.c index 31699a81..1e422298 100644 --- a/tc/q_ingress.c +++ b/tc/q_ingress.c @@ -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) { diff --git a/tc/q_mqprio.c b/tc/q_mqprio.c index 99798520..89b46002 100644 --- a/tc/q_mqprio.c +++ b/tc/q_mqprio.c @@ -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 = { diff --git a/tc/q_multiq.c b/tc/q_multiq.c index ce91fe83..8ad9e0b2 100644 --- a/tc/q_multiq.c +++ b/tc/q_multiq.c @@ -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 = {}; diff --git a/tc/q_netem.c b/tc/q_netem.c index 82eb46f2..9f9a9b3d 100644 --- a/tc/q_netem.c +++ b/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; } diff --git a/tc/q_pie.c b/tc/q_pie.c index db72add3..b89f53c7 100644 --- a/tc/q_pie.c +++ b/tc/q_pie.c @@ -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; diff --git a/tc/q_prio.c b/tc/q_prio.c index 677e25a3..992da6f6 100644 --- a/tc/q_prio.c +++ b/tc/q_prio.c @@ -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; diff --git a/tc/q_qfq.c b/tc/q_qfq.c index fa270c8a..d70ca1ba 100644 --- a/tc/q_qfq.c +++ b/tc/q_qfq.c @@ -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; diff --git a/tc/q_red.c b/tc/q_red.c index 1564d6ef..cf482fcc 100644 --- a/tc/q_red.c +++ b/tc/q_red.c @@ -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; } diff --git a/tc/q_rr.c b/tc/q_rr.c index 71ce3ce5..843a4fae 100644 --- a/tc/q_rr.c +++ b/tc/q_rr.c @@ -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; diff --git a/tc/q_sfb.c b/tc/q_sfb.c index d074e87b..4b366ddd 100644 --- a/tc/q_sfb.c +++ b/tc/q_sfb.c @@ -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, diff --git a/tc/q_sfq.c b/tc/q_sfq.c index a875abd3..6a1d853b 100644 --- a/tc/q_sfq.c +++ b/tc/q_sfq.c @@ -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 = {}; diff --git a/tc/q_tbf.c b/tc/q_tbf.c index 4955ee49..2c5edbe2 100644 --- a/tc/q_tbf.c +++ b/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; } diff --git a/tc/tc.c b/tc/tc.c index fa71250d..793dca9f 100644 --- a/tc/tc.c +++ b/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); diff --git a/tc/tc_class.c b/tc/tc_class.c index 507864ad..1b214b82 100644 --- a/tc/tc_class.c +++ b/tc/tc_class.c @@ -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) { diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index 56034b59..2f88f11c 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -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); diff --git a/tc/tc_util.c b/tc/tc_util.c index 197953ab..5532d40b 100644 --- a/tc/tc_util.c +++ b/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) { diff --git a/tc/tc_util.h b/tc/tc_util.h index 3d3d4f1d..eae10913 100644 --- a/tc/tc_util.h +++ b/tc/tc_util.h @@ -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); From 859af0a5dca7ccc73cc09b457ec8220fc466811a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 24 Nov 2017 11:31:36 -0800 Subject: [PATCH 03/36] tc: break long lines Signed-off-by: Stephen Hemminger --- tc/f_rsvp.c | 3 ++- tc/q_atm.c | 3 ++- tc/q_cbs.c | 3 ++- tc/q_drr.c | 3 ++- tc/q_fifo.c | 3 ++- tc/q_hfsc.c | 10 ++++++---- tc/q_htb.c | 4 ++-- tc/q_prio.c | 3 ++- tc/q_red.c | 3 ++- tc/q_tbf.c | 3 ++- 10 files changed, 24 insertions(+), 14 deletions(-) diff --git a/tc/f_rsvp.c b/tc/f_rsvp.c index 02028b4b..1ce37340 100644 --- a/tc/f_rsvp.c +++ b/tc/f_rsvp.c @@ -169,7 +169,8 @@ done: } -static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) +static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, + char **argv, struct nlmsghdr *n) { int family = strcmp(qu->id, "rsvp") == 0 ? AF_INET : AF_INET6; struct tc_rsvp_pinfo pinfo = {}; diff --git a/tc/q_atm.c b/tc/q_atm.c index 787b46cd..783a578c 100644 --- a/tc/q_atm.c +++ b/tc/q_atm.c @@ -26,7 +26,8 @@ #define MAX_HDR_LEN 64 -static int atm_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) +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"); diff --git a/tc/q_cbs.c b/tc/q_cbs.c index e1134c3a..b5739057 100644 --- a/tc/q_cbs.c +++ b/tc/q_cbs.c @@ -34,7 +34,8 @@ 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, const char *dev) +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; diff --git a/tc/q_drr.c b/tc/q_drr.c index 85aa5b60..5e541c09 100644 --- a/tc/q_drr.c +++ b/tc/q_drr.c @@ -33,7 +33,8 @@ static void explain2(void) } -static int drr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) +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) { diff --git a/tc/q_fifo.c b/tc/q_fifo.c index c89d186d..5fd6c1b1 100644 --- a/tc/q_fifo.c +++ b/tc/q_fifo.c @@ -27,7 +27,8 @@ 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, const char *dev) +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 = {}; diff --git a/tc/q_hfsc.c b/tc/q_hfsc.c index 597a659a..c19e87f9 100644 --- a/tc/q_hfsc.c +++ b/tc/q_hfsc.c @@ -23,8 +23,8 @@ #include "utils.h" #include "tc_util.h" -static int hfsc_get_sc(int *, char ***, struct tc_service_curve *, const char *); - +static int hfsc_get_sc(int *, char ***, + struct tc_service_curve *, const char *); static void explain_qdisc(void) @@ -70,7 +70,8 @@ explain1(char *arg) } static int -hfsc_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) +hfsc_parse_opt(struct qdisc_util *qu, int argc, char **argv, + struct nlmsghdr *n, const char *dev) { struct tc_hfsc_qopt qopt = {}; @@ -281,7 +282,8 @@ struct qdisc_util hfsc_qdisc_util = { }; static int -hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc, const char *dev) +hfsc_get_sc1(int *argcp, char ***argvp, + struct tc_service_curve *sc, const char *dev) { char **argv = *argvp; int argc = *argcp; diff --git a/tc/q_htb.c b/tc/q_htb.c index 3e295a71..ffb43aa1 100644 --- a/tc/q_htb.c +++ b/tc/q_htb.c @@ -58,8 +58,8 @@ static void explain1(char *arg) explain(); } - -static int htb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) +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 = { diff --git a/tc/q_prio.c b/tc/q_prio.c index 992da6f6..358cf06c 100644 --- a/tc/q_prio.c +++ b/tc/q_prio.c @@ -27,7 +27,8 @@ 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, const char *dev) +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; diff --git a/tc/q_red.c b/tc/q_red.c index cf482fcc..1949558f 100644 --- a/tc/q_red.c +++ b/tc/q_red.c @@ -32,7 +32,8 @@ 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, const char *dev) +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; diff --git a/tc/q_tbf.c b/tc/q_tbf.c index 2c5edbe2..dfaa5d38 100644 --- a/tc/q_tbf.c +++ b/tc/q_tbf.c @@ -35,7 +35,8 @@ 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, const char *dev) +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 = {}; From 6054c1ebf7727123654f2c0764f3693813e9bad6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 24 Nov 2017 12:21:35 -0800 Subject: [PATCH 04/36] SPDX license identifiers For all files in iproute2 which do not have an obvious license identification, mark them with SPDK GPL-2 Signed-off-by: Stephen Hemminger --- Makefile | 1 + bridge/Makefile | 1 + bridge/br_common.h | 2 ++ bridge/bridge.c | 1 + bridge/fdb.c | 1 + bridge/link.c | 1 + bridge/mdb.c | 1 + bridge/vlan.c | 1 + configure | 1 + devlink/Makefile | 1 + examples/bpf/bpf_tailcall.c | 1 + genl/Makefile | 1 + genl/genl_utils.h | 1 + genl/static-syms.c | 1 + include/bpf_api.h | 1 + include/bpf_elf.h | 1 + include/bpf_scm.h | 1 + include/color.h | 1 + include/dlfcn.h | 1 + include/ip6tables.h | 1 + include/iptables.h | 1 + include/iptables/internal.h | 1 + include/libgenl.h | 1 + include/libiptc/ipt_kernel_headers.h | 1 + include/libiptc/libip6tc.h | 1 + include/libiptc/libiptc.h | 1 + include/libiptc/libxtc.h | 1 + include/libiptc/xtcshared.h | 1 + include/libnetlink.h | 1 + include/list.h | 1 + include/ll_map.h | 1 + include/names.h | 1 + include/namespace.h | 1 + include/rt_names.h | 1 + include/rtm_map.h | 1 + include/utils.h | 1 + include/xt-internal.h | 1 + include/xtables.h | 1 + ip/Makefile | 1 + ip/ifcfg | 1 + ip/ila_common.h | 1 + ip/ip_common.h | 1 + ip/iplink_dummy.c | 1 + ip/iplink_ifb.c | 1 + ip/iplink_nlmon.c | 1 + ip/iplink_team.c | 1 + ip/iplink_vcan.c | 1 + ip/ipnetns.c | 1 + ip/iproute_lwtunnel.h | 1 + ip/routef | 1 + ip/routel | 2 +- ip/rtpr | 1 + ip/static-syms.c | 1 + ip/xdp.h | 1 + lib/Makefile | 1 + lib/color.c | 1 + lib/dnet_ntop.c | 1 + lib/dnet_pton.c | 1 + lib/exec.c | 1 + lib/ipx_ntop.c | 1 + lib/ipx_pton.c | 1 + lib/libgenl.c | 1 + lib/mpls_ntop.c | 2 ++ lib/mpls_pton.c | 2 ++ man/Makefile | 1 + man/man3/Makefile | 1 + man/man7/Makefile | 1 + man/man8/Makefile | 1 + misc/Makefile | 1 + misc/lnstat.h | 1 + misc/ssfilter.h | 1 + netem/Makefile | 1 + rdma/Makefile | 1 + tc/Makefile | 1 + tc/emp_ematch.l | 1 + tc/f_tcindex.c | 1 + tc/m_ematch.h | 1 + tc/q_atm.c | 1 + tc/q_clsact.c | 1 + tc/q_dsmark.c | 1 + tc/q_hhf.c | 1 + tc/static-syms.c | 1 + tc/tc_cbq.h | 1 + tc/tc_common.h | 1 + tc/tc_core.h | 1 + tc/tc_red.h | 1 + tc/tc_util.h | 1 + testsuite/Makefile | 1 + testsuite/iproute2/Makefile | 1 + testsuite/tools/Makefile | 1 + tipc/Makefile | 1 + 91 files changed, 94 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6ad96104..6a51e0db 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # Top level Makefile for iproute2 ifeq ($(VERBOSE),0) diff --git a/bridge/Makefile b/bridge/Makefile index b2ae0a4e..c6b7d08d 100644 --- a/bridge/Makefile +++ b/bridge/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 BROBJ = bridge.o fdb.o monitor.o link.o mdb.o vlan.o include ../config.mk diff --git a/bridge/br_common.h b/bridge/br_common.h index 01447ddc..f07c7d1c 100644 --- a/bridge/br_common.h +++ b/bridge/br_common.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + #define MDB_RTA(r) \ ((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(struct br_mdb_entry)))) diff --git a/bridge/bridge.c b/bridge/bridge.c index 6658cb8f..48fe1c8b 100644 --- a/bridge/bridge.c +++ b/bridge/bridge.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Get/set/delete bridge with netlink * diff --git a/bridge/fdb.c b/bridge/fdb.c index 1ab1fb71..376713b6 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Get/set/delete fdb table with netlink * diff --git a/bridge/link.c b/bridge/link.c index 65ca47e1..e2371d0d 100644 --- a/bridge/link.c +++ b/bridge/link.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include diff --git a/bridge/mdb.c b/bridge/mdb.c index f38e326e..7b7b81f4 100644 --- a/bridge/mdb.c +++ b/bridge/mdb.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Get mdb table with netlink */ diff --git a/bridge/vlan.c b/bridge/vlan.c index 0f78a9e8..69fb5425 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include diff --git a/configure b/configure index f0668ab3..d6832464 100755 --- a/configure +++ b/configure @@ -1,4 +1,5 @@ #! /bin/bash +# SPDX-License-Identifier: GPL-2.0 # This is not an autoconf generated configure # INCLUDE=${1:-"$PWD/include"} diff --git a/devlink/Makefile b/devlink/Makefile index 3b2067d6..3afda65e 100644 --- a/devlink/Makefile +++ b/devlink/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 include ../config.mk ifeq ($(HAVE_MNL),y) diff --git a/examples/bpf/bpf_tailcall.c b/examples/bpf/bpf_tailcall.c index 1a30426c..161eb606 100644 --- a/examples/bpf/bpf_tailcall.c +++ b/examples/bpf/bpf_tailcall.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include "../../include/bpf_api.h" #define ENTRY_INIT 3 diff --git a/genl/Makefile b/genl/Makefile index de1635e4..2b7a45b6 100644 --- a/genl/Makefile +++ b/genl/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 GENLOBJ=genl.o include ../config.mk diff --git a/genl/genl_utils.h b/genl/genl_utils.h index 85b51830..6e6f4450 100644 --- a/genl/genl_utils.h +++ b/genl/genl_utils.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _TC_UTIL_H_ #define _TC_UTIL_H_ 1 diff --git a/genl/static-syms.c b/genl/static-syms.c index 0bc80743..47c4092c 100644 --- a/genl/static-syms.c +++ b/genl/static-syms.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * This file creates a dummy version of dynamic loading * for environments where dynamic linking diff --git a/include/bpf_api.h b/include/bpf_api.h index d1324719..89d3488d 100644 --- a/include/bpf_api.h +++ b/include/bpf_api.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __BPF_API__ #define __BPF_API__ diff --git a/include/bpf_elf.h b/include/bpf_elf.h index 406c3087..a8e360f3 100644 --- a/include/bpf_elf.h +++ b/include/bpf_elf.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __BPF_ELF__ #define __BPF_ELF__ diff --git a/include/bpf_scm.h b/include/bpf_scm.h index 122d59fc..669f0538 100644 --- a/include/bpf_scm.h +++ b/include/bpf_scm.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __BPF_SCM__ #define __BPF_SCM__ diff --git a/include/color.h b/include/color.h index 7fd685d0..f6c351b7 100644 --- a/include/color.h +++ b/include/color.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __COLOR_H__ #define __COLOR_H__ 1 diff --git a/include/dlfcn.h b/include/dlfcn.h index f15bc2c7..1d8890ad 100644 --- a/include/dlfcn.h +++ b/include/dlfcn.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Stub dlfcn implementation for systems that lack shared library support * but obviously can still reference compiled-in symbols. diff --git a/include/ip6tables.h b/include/ip6tables.h index 5f1c5b65..bfb28682 100644 --- a/include/ip6tables.h +++ b/include/ip6tables.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _IP6TABLES_USER_H #define _IP6TABLES_USER_H diff --git a/include/iptables.h b/include/iptables.h index 78c10abd..78bc378e 100644 --- a/include/iptables.h +++ b/include/iptables.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _IPTABLES_USER_H #define _IPTABLES_USER_H diff --git a/include/iptables/internal.h b/include/iptables/internal.h index 62a8ecb9..1fd13725 100644 --- a/include/iptables/internal.h +++ b/include/iptables/internal.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef IPTABLES_INTERNAL_H #define IPTABLES_INTERNAL_H 1 diff --git a/include/libgenl.h b/include/libgenl.h index 2dbb4b36..cd13f476 100644 --- a/include/libgenl.h +++ b/include/libgenl.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __LIBGENL_H__ #define __LIBGENL_H__ diff --git a/include/libiptc/ipt_kernel_headers.h b/include/libiptc/ipt_kernel_headers.h index a5963e94..3d2a2a32 100644 --- a/include/libiptc/ipt_kernel_headers.h +++ b/include/libiptc/ipt_kernel_headers.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* This is the userspace/kernel interface for Generic IP Chains, required for libc6. */ #ifndef _FWCHAINS_KERNEL_HEADERS_H diff --git a/include/libiptc/libip6tc.h b/include/libiptc/libip6tc.h index 9aed80a0..cd588de7 100644 --- a/include/libiptc/libip6tc.h +++ b/include/libiptc/libip6tc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LIBIP6TC_H #define _LIBIP6TC_H /* Library which manipulates firewall rules. Version 0.2. */ diff --git a/include/libiptc/libiptc.h b/include/libiptc/libiptc.h index 24cdbdb7..1bfe4e18 100644 --- a/include/libiptc/libiptc.h +++ b/include/libiptc/libiptc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LIBIPTC_H #define _LIBIPTC_H /* Library which manipulates filtering rules. */ diff --git a/include/libiptc/libxtc.h b/include/libiptc/libxtc.h index 37010188..1e9596a6 100644 --- a/include/libiptc/libxtc.h +++ b/include/libiptc/libxtc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LIBXTC_H #define _LIBXTC_H /* Library which manipulates filtering rules. */ diff --git a/include/libiptc/xtcshared.h b/include/libiptc/xtcshared.h index 773ebc4c..278a58f4 100644 --- a/include/libiptc/xtcshared.h +++ b/include/libiptc/xtcshared.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LIBXTC_SHARED_H #define _LIBXTC_SHARED_H 1 diff --git a/include/libnetlink.h b/include/libnetlink.h index 77b62605..a4d83b9e 100644 --- a/include/libnetlink.h +++ b/include/libnetlink.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __LIBNETLINK_H__ #define __LIBNETLINK_H__ 1 diff --git a/include/list.h b/include/list.h index 5b529dc6..5af737c7 100644 --- a/include/list.h +++ b/include/list.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __LIST_H__ #define __LIST_H__ 1 /* List and hash list stuff from kernel */ diff --git a/include/ll_map.h b/include/ll_map.h index 949bfc3e..c8474e6e 100644 --- a/include/ll_map.h +++ b/include/ll_map.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __LL_MAP_H__ #define __LL_MAP_H__ 1 diff --git a/include/names.h b/include/names.h index 6fed5818..3e5d3b14 100644 --- a/include/names.h +++ b/include/names.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef DB_NAMES_H_ #define DB_NAMES_H_ 1 diff --git a/include/namespace.h b/include/namespace.h index 51324b21..aed7ce08 100644 --- a/include/namespace.h +++ b/include/namespace.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __NAMESPACE_H__ #define __NAMESPACE_H__ 1 diff --git a/include/rt_names.h b/include/rt_names.h index 921be060..62ebbd6a 100644 --- a/include/rt_names.h +++ b/include/rt_names.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef RT_NAMES_H_ #define RT_NAMES_H_ 1 diff --git a/include/rtm_map.h b/include/rtm_map.h index d6e5885c..f85e52c4 100644 --- a/include/rtm_map.h +++ b/include/rtm_map.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __RTM_MAP_H__ #define __RTM_MAP_H__ 1 diff --git a/include/utils.h b/include/utils.h index 9c37c613..d3895d56 100644 --- a/include/utils.h +++ b/include/utils.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __UTILS_H__ #define __UTILS_H__ 1 diff --git a/include/xt-internal.h b/include/xt-internal.h index b8ea67da..89c73e4f 100644 --- a/include/xt-internal.h +++ b/include/xt-internal.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _XTABLES_INTERNAL_H #define _XTABLES_INTERNAL_H 1 diff --git a/include/xtables.h b/include/xtables.h index 978ae0d1..b48c3166 100644 --- a/include/xtables.h +++ b/include/xtables.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _XTABLES_H #define _XTABLES_H diff --git a/ip/Makefile b/ip/Makefile index 5a1c7ad2..a653c1bd 100644 --- a/ip/Makefile +++ b/ip/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \ rtm_map.o iptunnel.o ip6tunnel.o tunnel.o ipneigh.o ipntable.o iplink.o \ ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o iptuntap.o iptoken.o \ diff --git a/ip/ifcfg b/ip/ifcfg index 30a2dc49..851b9215 100644 --- a/ip/ifcfg +++ b/ip/ifcfg @@ -1,4 +1,5 @@ #! /bin/bash +# SPDX-License-Identifier: GPL-2.0 CheckForwarding () { local sbase fwd diff --git a/ip/ila_common.h b/ip/ila_common.h index 04c6c2ed..f99c2672 100644 --- a/ip/ila_common.h +++ b/ip/ila_common.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _ILA_COMMON_H_ #define _ILA_COMMON_H_ diff --git a/ip/ip_common.h b/ip/ip_common.h index 4b8b0a71..3203f0cd 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _IP_COMMON_H_ #define _IP_COMMON_H_ diff --git a/ip/iplink_dummy.c b/ip/iplink_dummy.c index cf78ea5b..cba22955 100644 --- a/ip/iplink_dummy.c +++ b/ip/iplink_dummy.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include diff --git a/ip/iplink_ifb.c b/ip/iplink_ifb.c index d7dc8f98..a2a7301f 100644 --- a/ip/iplink_ifb.c +++ b/ip/iplink_ifb.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include diff --git a/ip/iplink_nlmon.c b/ip/iplink_nlmon.c index 51d5919a..6ffb9101 100644 --- a/ip/iplink_nlmon.c +++ b/ip/iplink_nlmon.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include diff --git a/ip/iplink_team.c b/ip/iplink_team.c index 6225268d..58f955a4 100644 --- a/ip/iplink_team.c +++ b/ip/iplink_team.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include diff --git a/ip/iplink_vcan.c b/ip/iplink_vcan.c index b7ae15f0..74a1505b 100644 --- a/ip/iplink_vcan.c +++ b/ip/iplink_vcan.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include diff --git a/ip/ipnetns.c b/ip/ipnetns.c index 1fa53986..059a4220 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #define _ATFILE_SOURCE #include #include diff --git a/ip/iproute_lwtunnel.h b/ip/iproute_lwtunnel.h index b82b58ad..be003cea 100644 --- a/ip/iproute_lwtunnel.h +++ b/ip/iproute_lwtunnel.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __LWTUNNEL_H__ #define __LETUNNEL_H__ 1 diff --git a/ip/routef b/ip/routef index d266e2d9..c251e7b8 100644 --- a/ip/routef +++ b/ip/routef @@ -1,4 +1,5 @@ #! /bin/sh +# SPDX-License-Identifier: GPL-2.0 if [ -z "$*" ] ; then exec ip -4 ro flush scope global type unicast diff --git a/ip/routel b/ip/routel index 9a30462a..7056886d 100644 --- a/ip/routel +++ b/ip/routel @@ -1,5 +1,5 @@ #!/bin/sh -#$Id$ +# SPDX-License-Identifier: GPL-2.0 # # Script created by: Stephen R. van den Berg , 1999/04/18 diff --git a/ip/rtpr b/ip/rtpr index c3629fd6..192a476f 100644 --- a/ip/rtpr +++ b/ip/rtpr @@ -1,4 +1,5 @@ #! /bin/bash +# SPDX-License-Identifier: GPL-2.0 exec tr "[\\\\]" "[ ]" diff --git a/ip/static-syms.c b/ip/static-syms.c index 0bc80743..47c4092c 100644 --- a/ip/static-syms.c +++ b/ip/static-syms.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * This file creates a dummy version of dynamic loading * for environments where dynamic linking diff --git a/ip/xdp.h b/ip/xdp.h index 1efd591b..215a6dcb 100644 --- a/ip/xdp.h +++ b/ip/xdp.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __XDP__ #define __XDP__ diff --git a/lib/Makefile b/lib/Makefile index 0fbdf4c3..7b34ed5f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 include ../config.mk CFLAGS += -fPIC diff --git a/lib/color.c b/lib/color.c index 8d049a01..a13a4930 100644 --- a/lib/color.c +++ b/lib/color.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include diff --git a/lib/dnet_ntop.c b/lib/dnet_ntop.c index 112dc0d9..17d960e3 100644 --- a/lib/dnet_ntop.c +++ b/lib/dnet_ntop.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include diff --git a/lib/dnet_pton.c b/lib/dnet_pton.c index 73857562..1cf54e51 100644 --- a/lib/dnet_pton.c +++ b/lib/dnet_pton.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include diff --git a/lib/exec.c b/lib/exec.c index 97c99120..eb36b59d 100644 --- a/lib/exec.c +++ b/lib/exec.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include diff --git a/lib/ipx_ntop.c b/lib/ipx_ntop.c index 5f646b3e..80b8a34e 100644 --- a/lib/ipx_ntop.c +++ b/lib/ipx_ntop.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include diff --git a/lib/ipx_pton.c b/lib/ipx_pton.c index 071a775e..a97c1c1b 100644 --- a/lib/ipx_pton.c +++ b/lib/ipx_pton.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include diff --git a/lib/libgenl.c b/lib/libgenl.c index bb5fbb5f..f2ce698f 100644 --- a/lib/libgenl.c +++ b/lib/libgenl.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * libgenl.c GENL library */ diff --git a/lib/mpls_ntop.c b/lib/mpls_ntop.c index 5902f503..f8d89f42 100644 --- a/lib/mpls_ntop.c +++ b/lib/mpls_ntop.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + #include #include #include diff --git a/lib/mpls_pton.c b/lib/mpls_pton.c index 6d2e6a69..065374eb 100644 --- a/lib/mpls_pton.c +++ b/lib/mpls_pton.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + #include #include #include diff --git a/man/Makefile b/man/Makefile index 749faa11..6b095ee4 100644 --- a/man/Makefile +++ b/man/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 INSTALL=install INSTALLDIR=install -m 0755 -d INSTALLMAN=install -m 0644 diff --git a/man/man3/Makefile b/man/man3/Makefile index a98741de..e3d3e607 100644 --- a/man/man3/Makefile +++ b/man/man3/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 MAN3PAGES = $(wildcard *.3) all: diff --git a/man/man7/Makefile b/man/man7/Makefile index 689fc713..1a8d5219 100644 --- a/man/man7/Makefile +++ b/man/man7/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 MAN7PAGES = $(wildcard *.7) all: diff --git a/man/man8/Makefile b/man/man8/Makefile index 12af66be..932ba1f3 100644 --- a/man/man8/Makefile +++ b/man/man8/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 TARGETS = ip-address.8 ip-link.8 ip-route.8 MAN8PAGES = $(TARGETS) $(filter-out $(TARGETS),$(wildcard *.8)) diff --git a/misc/Makefile b/misc/Makefile index d02616e3..34ef6b21 100644 --- a/misc/Makefile +++ b/misc/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 SSOBJ=ss.o ssfilter.o LNSTATOBJ=lnstat.o lnstat_util.o diff --git a/misc/lnstat.h b/misc/lnstat.h index 83dad970..199eb54a 100644 --- a/misc/lnstat.h +++ b/misc/lnstat.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LNSTAT_H #define _LNSTAT_H diff --git a/misc/ssfilter.h b/misc/ssfilter.h index dfc5b938..f5b0bc8a 100644 --- a/misc/ssfilter.h +++ b/misc/ssfilter.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #define SSF_DCOND 0 #define SSF_SCOND 1 #define SSF_OR 2 diff --git a/netem/Makefile b/netem/Makefile index 43418527..ba4c5a76 100644 --- a/netem/Makefile +++ b/netem/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 include ../config.mk DISTGEN = maketable normal pareto paretonormal diff --git a/rdma/Makefile b/rdma/Makefile index 1b5aa50b..c8966bfd 100644 --- a/rdma/Makefile +++ b/rdma/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 include ../config.mk ifeq ($(HAVE_MNL),y) diff --git a/tc/Makefile b/tc/Makefile index 24bd3e2e..3716dd6a 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 TCOBJ= tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o tc_monitor.o \ tc_exec.o m_police.o m_estimator.o m_action.o m_ematch.o \ emp_ematch.yacc.o emp_ematch.lex.o diff --git a/tc/emp_ematch.l b/tc/emp_ematch.l index d9b45be1..dc106759 100644 --- a/tc/emp_ematch.l +++ b/tc/emp_ematch.l @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ %{ #include "emp_ematch.yacc.h" #include "m_ematch.h" diff --git a/tc/f_tcindex.c b/tc/f_tcindex.c index 4cd7859f..749273db 100644 --- a/tc/f_tcindex.c +++ b/tc/f_tcindex.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * f_tcindex.c Traffic control index filter * diff --git a/tc/m_ematch.h b/tc/m_ematch.h index 81456aac..fa6e214a 100644 --- a/tc/m_ematch.h +++ b/tc/m_ematch.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __TC_EMATCH_H_ #define __TC_EMATCH_H_ diff --git a/tc/q_atm.c b/tc/q_atm.c index 783a578c..3ea4cf4e 100644 --- a/tc/q_atm.c +++ b/tc/q_atm.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * q_atm.c ATM. * diff --git a/tc/q_clsact.c b/tc/q_clsact.c index 5e8dd91c..341f653f 100644 --- a/tc/q_clsact.c +++ b/tc/q_clsact.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #include #include diff --git a/tc/q_dsmark.c b/tc/q_dsmark.c index 65eeb271..967fd892 100644 --- a/tc/q_dsmark.c +++ b/tc/q_dsmark.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * q_dsmark.c Differentiated Services field marking. * diff --git a/tc/q_hhf.c b/tc/q_hhf.c index 2ec3d42f..66c71886 100644 --- a/tc/q_hhf.c +++ b/tc/q_hhf.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* q_hhf.c Heavy-Hitter Filter (HHF) * * Copyright (C) 2013 Terry Lam diff --git a/tc/static-syms.c b/tc/static-syms.c index 0bc80743..47c4092c 100644 --- a/tc/static-syms.c +++ b/tc/static-syms.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * This file creates a dummy version of dynamic loading * for environments where dynamic linking diff --git a/tc/tc_cbq.h b/tc/tc_cbq.h index 8f956490..fa17d249 100644 --- a/tc/tc_cbq.h +++ b/tc/tc_cbq.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _TC_CBQ_H_ #define _TC_CBQ_H_ 1 diff --git a/tc/tc_common.h b/tc/tc_common.h index a2f38984..264fbdac 100644 --- a/tc/tc_common.h +++ b/tc/tc_common.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #define TCA_BUF_MAX (64*1024) diff --git a/tc/tc_core.h b/tc/tc_core.h index 8a63b79c..1dfa9a4f 100644 --- a/tc/tc_core.h +++ b/tc/tc_core.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _TC_CORE_H_ #define _TC_CORE_H_ 1 diff --git a/tc/tc_red.h b/tc/tc_red.h index 6f6b09e3..88fba58b 100644 --- a/tc/tc_red.h +++ b/tc/tc_red.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _TC_RED_H_ #define _TC_RED_H_ 1 diff --git a/tc/tc_util.h b/tc/tc_util.h index eae10913..40a8865d 100644 --- a/tc/tc_util.h +++ b/tc/tc_util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _TC_UTIL_H_ #define _TC_UTIL_H_ 1 diff --git a/testsuite/Makefile b/testsuite/Makefile index 055136b5..2a54e5c8 100644 --- a/testsuite/Makefile +++ b/testsuite/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 ## -- Config -- DEV := lo PREFIX := sudo -E unshare -n diff --git a/testsuite/iproute2/Makefile b/testsuite/iproute2/Makefile index ba128aa7..b8a7d515 100644 --- a/testsuite/iproute2/Makefile +++ b/testsuite/iproute2/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 SUBDIRS := $(filter-out Makefile,$(wildcard *)) .PHONY: all configure clean distclean show $(SUBDIRS) diff --git a/testsuite/tools/Makefile b/testsuite/tools/Makefile index 9581de51..f2cdc980 100644 --- a/testsuite/tools/Makefile +++ b/testsuite/tools/Makefile @@ -1,2 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 generate_nlmsg: generate_nlmsg.c ../../lib/libnetlink.c $(CC) -o $@ $^ diff --git a/tipc/Makefile b/tipc/Makefile index d3c957e2..abd33ab0 100644 --- a/tipc/Makefile +++ b/tipc/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 include ../config.mk ifeq ($(HAVE_MNL),y) From 658cfebc27f20dd006659b5e90d1585b300eba85 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 23 Nov 2017 18:11:58 -0800 Subject: [PATCH 05/36] bpf: pass program type in struct bpf_cfg_in Program type is needed both for parsing and loading of the program. Parsing may also induce the type based on signatures from __bpf_prog_meta. Instead of passing the type around keep it in struct bpf_cfg_in. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Acked-by: Daniel Borkmann --- include/bpf_util.h | 5 +++-- ip/iplink_xdp.c | 3 ++- ip/iproute_lwtunnel.c | 3 ++- lib/bpf.c | 38 +++++++++++++++++++------------------- tc/f_bpf.c | 3 ++- tc/m_bpf.c | 3 ++- 6 files changed, 30 insertions(+), 25 deletions(-) diff --git a/include/bpf_util.h b/include/bpf_util.h index e818221d..0da4b85c 100644 --- a/include/bpf_util.h +++ b/include/bpf_util.h @@ -60,6 +60,7 @@ struct bpf_cfg_in { const char *object; const char *section; const char *uds; + enum bpf_prog_type type; int argc; char **argv; struct sock_filter *ops; @@ -244,8 +245,8 @@ struct bpf_cfg_in { .off = 0, \ .imm = 0 }) -int bpf_parse_common(enum bpf_prog_type type, struct bpf_cfg_in *cfg, - const struct bpf_cfg_ops *ops, void *nl); +int bpf_parse_common(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops, + void *nl); const char *bpf_prog_to_default_section(enum bpf_prog_type type); diff --git a/ip/iplink_xdp.c b/ip/iplink_xdp.c index 2d2953aa..993e44d7 100644 --- a/ip/iplink_xdp.c +++ b/ip/iplink_xdp.c @@ -52,6 +52,7 @@ int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic, bool drv, bool offload) { struct bpf_cfg_in cfg = { + .type = BPF_PROG_TYPE_XDP, .argc = *argc, .argv = *argv, }; @@ -74,7 +75,7 @@ int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic, return xdp_delete(&xdp); } - if (bpf_parse_common(BPF_PROG_TYPE_XDP, &cfg, &bpf_cb_ops, &xdp)) + if (bpf_parse_common(&cfg, &bpf_cb_ops, &xdp)) return -1; *argc = cfg.argc; diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 27266171..62dc0cd8 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -886,6 +886,7 @@ static int lwt_parse_bpf(struct rtattr *rta, size_t len, int attr, const enum bpf_prog_type bpf_type) { struct bpf_cfg_in cfg = { + .type = bpf_type, .argc = *argcp, .argv = *argvp, }; @@ -897,7 +898,7 @@ static int lwt_parse_bpf(struct rtattr *rta, size_t len, int err; nest = rta_nest(rta, len, attr); - err = bpf_parse_common(bpf_type, &cfg, &bpf_cb_ops, &x); + err = bpf_parse_common(&cfg, &bpf_cb_ops, &x); if (err < 0) { fprintf(stderr, "Failed to parse eBPF program: %s\n", strerror(-err)); diff --git a/lib/bpf.c b/lib/bpf.c index fdc28772..5e65682b 100644 --- a/lib/bpf.c +++ b/lib/bpf.c @@ -813,8 +813,8 @@ enum bpf_mode { BPF_MODE_MAX, }; -static int bpf_parse(enum bpf_prog_type *type, enum bpf_mode *mode, - struct bpf_cfg_in *cfg, const bool *opt_tbl) +static int bpf_parse(enum bpf_mode *mode, struct bpf_cfg_in *cfg, + const bool *opt_tbl) { const char *file, *section, *uds_name; bool verbose = false; @@ -852,7 +852,7 @@ static int bpf_parse(enum bpf_prog_type *type, enum bpf_mode *mode, file = *argv; NEXT_ARG_FWD(); - if (*type == BPF_PROG_TYPE_UNSPEC) { + if (cfg->type == BPF_PROG_TYPE_UNSPEC) { if (argc > 0 && matches(*argv, "type") == 0) { NEXT_ARG(); for (i = 0; i < ARRAY_SIZE(__bpf_prog_meta); @@ -861,30 +861,30 @@ static int bpf_parse(enum bpf_prog_type *type, enum bpf_mode *mode, continue; if (!matches(*argv, __bpf_prog_meta[i].type)) { - *type = i; + cfg->type = i; break; } } - if (*type == BPF_PROG_TYPE_UNSPEC) { + if (cfg->type == BPF_PROG_TYPE_UNSPEC) { fprintf(stderr, "What type is \"%s\"?\n", *argv); return -1; } NEXT_ARG_FWD(); } else { - *type = BPF_PROG_TYPE_SCHED_CLS; + cfg->type = BPF_PROG_TYPE_SCHED_CLS; } } - section = bpf_prog_to_default_section(*type); + section = bpf_prog_to_default_section(cfg->type); if (argc > 0 && matches(*argv, "section") == 0) { NEXT_ARG(); section = *argv; NEXT_ARG_FWD(); } - if (__bpf_prog_meta[*type].may_uds_export) { + if (__bpf_prog_meta[cfg->type].may_uds_export) { uds_name = getenv(BPF_ENV_UDS); if (argc > 0 && !uds_name && matches(*argv, "export") == 0) { @@ -905,9 +905,9 @@ static int bpf_parse(enum bpf_prog_type *type, enum bpf_mode *mode, if (*mode == CBPF_BYTECODE || *mode == CBPF_FILE) ret = bpf_ops_parse(argc, argv, cfg->ops, *mode == CBPF_FILE); else if (*mode == EBPF_OBJECT) - ret = bpf_obj_open(file, *type, section, verbose); + ret = bpf_obj_open(file, cfg->type, section, verbose); else if (*mode == EBPF_PINNED) - ret = bpf_obj_pinned(file, *type); + ret = bpf_obj_pinned(file, cfg->type); else return -1; @@ -920,7 +920,7 @@ static int bpf_parse(enum bpf_prog_type *type, enum bpf_mode *mode, return ret; } -static int bpf_parse_opt_tbl(enum bpf_prog_type type, struct bpf_cfg_in *cfg, +static int bpf_parse_opt_tbl(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops, void *nl, const bool *opt_tbl) { @@ -930,7 +930,7 @@ static int bpf_parse_opt_tbl(enum bpf_prog_type type, struct bpf_cfg_in *cfg, int ret; cfg->ops = opcodes; - ret = bpf_parse(&type, &mode, cfg, opt_tbl); + ret = bpf_parse(&mode, cfg, opt_tbl); cfg->ops = NULL; if (ret < 0) return ret; @@ -947,8 +947,8 @@ static int bpf_parse_opt_tbl(enum bpf_prog_type type, struct bpf_cfg_in *cfg, return 0; } -int bpf_parse_common(enum bpf_prog_type type, struct bpf_cfg_in *cfg, - const struct bpf_cfg_ops *ops, void *nl) +int bpf_parse_common(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops, + void *nl) { bool opt_tbl[BPF_MODE_MAX] = {}; @@ -962,12 +962,11 @@ int bpf_parse_common(enum bpf_prog_type type, struct bpf_cfg_in *cfg, opt_tbl[EBPF_PINNED] = true; } - return bpf_parse_opt_tbl(type, cfg, ops, nl, opt_tbl); + return bpf_parse_opt_tbl(cfg, ops, nl, opt_tbl); } int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv) { - enum bpf_prog_type type = BPF_PROG_TYPE_UNSPEC; const bool opt_tbl[BPF_MODE_MAX] = { [EBPF_OBJECT] = true, [EBPF_PINNED] = true, @@ -978,6 +977,7 @@ int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv) .size_value = sizeof(int), }; struct bpf_cfg_in cfg = { + .type = BPF_PROG_TYPE_UNSPEC, .argc = argc, .argv = argv, }; @@ -986,7 +986,7 @@ int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv) enum bpf_mode mode; uint32_t map_key; - prog_fd = bpf_parse(&type, &mode, &cfg, opt_tbl); + prog_fd = bpf_parse(&mode, &cfg, opt_tbl); if (prog_fd < 0) return prog_fd; if (key) { @@ -1000,7 +1000,7 @@ int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv) } } - map_fd = bpf_obj_get(map_path, type); + map_fd = bpf_obj_get(map_path, cfg.type); if (map_fd < 0) { fprintf(stderr, "Couldn\'t retrieve pinned map \'%s\': %s\n", map_path, strerror(errno)); @@ -1010,7 +1010,7 @@ int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv) ret = bpf_map_selfcheck_pinned(map_fd, &test, &ext, offsetof(struct bpf_elf_map, max_elem), - type); + cfg.type); if (ret < 0) { fprintf(stderr, "Map \'%s\' self-check failed!\n", map_path); goto out_map; diff --git a/tc/f_bpf.c b/tc/f_bpf.c index 3f619d0d..a38ec2ab 100644 --- a/tc/f_bpf.c +++ b/tc/f_bpf.c @@ -103,10 +103,11 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle, NEXT_ARG(); opt_bpf: seen_run = true; + cfg.type = bpf_type; cfg.argc = argc; cfg.argv = argv; - if (bpf_parse_common(bpf_type, &cfg, &bpf_cb_ops, n)) + if (bpf_parse_common(&cfg, &bpf_cb_ops, n)) return -1; argc = cfg.argc; diff --git a/tc/m_bpf.c b/tc/m_bpf.c index e3d0a2b1..f2ce3892 100644 --- a/tc/m_bpf.c +++ b/tc/m_bpf.c @@ -98,10 +98,11 @@ static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv, NEXT_ARG(); opt_bpf: seen_run = true; + cfg.type = bpf_type; cfg.argc = argc; cfg.argv = argv; - if (bpf_parse_common(bpf_type, &cfg, &bpf_cb_ops, n)) + if (bpf_parse_common(&cfg, &bpf_cb_ops, n)) return -1; argc = cfg.argc; From f20ff2f1955237a67af7849466b7b8681a45cd35 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 23 Nov 2017 18:11:59 -0800 Subject: [PATCH 06/36] bpf: keep parsed program mode in struct bpf_cfg_in bpf_parse() will parse command line arguments to find out the program mode. This mode will later be needed at loading time. Instead of keeping it locally add it to struct bpf_cfg_in, this will allow splitting parsing and loading stages. enum bpf_mode has to be moved to the header file, because C doesn't allow forward declaration of enums. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Acked-by: Daniel Borkmann --- include/bpf_util.h | 9 +++++++++ lib/bpf.c | 42 ++++++++++++++++-------------------------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/include/bpf_util.h b/include/bpf_util.h index 0da4b85c..a6f4eeb5 100644 --- a/include/bpf_util.h +++ b/include/bpf_util.h @@ -56,11 +56,20 @@ struct bpf_cfg_ops { void (*ebpf_cb)(void *nl, int fd, const char *annotation); }; +enum bpf_mode { + CBPF_BYTECODE, + CBPF_FILE, + EBPF_OBJECT, + EBPF_PINNED, + BPF_MODE_MAX, +}; + struct bpf_cfg_in { const char *object; const char *section; const char *uds; enum bpf_prog_type type; + enum bpf_mode mode; int argc; char **argv; struct sock_filter *ops; diff --git a/lib/bpf.c b/lib/bpf.c index 5e65682b..33c92d6c 100644 --- a/lib/bpf.c +++ b/lib/bpf.c @@ -805,16 +805,7 @@ static int bpf_obj_pinned(const char *pathname, enum bpf_prog_type type) return prog_fd; } -enum bpf_mode { - CBPF_BYTECODE, - CBPF_FILE, - EBPF_OBJECT, - EBPF_PINNED, - BPF_MODE_MAX, -}; - -static int bpf_parse(enum bpf_mode *mode, struct bpf_cfg_in *cfg, - const bool *opt_tbl) +static int bpf_parse(struct bpf_cfg_in *cfg, const bool *opt_tbl) { const char *file, *section, *uds_name; bool verbose = false; @@ -827,20 +818,20 @@ static int bpf_parse(enum bpf_mode *mode, struct bpf_cfg_in *cfg, if (opt_tbl[CBPF_BYTECODE] && (matches(*argv, "bytecode") == 0 || strcmp(*argv, "bc") == 0)) { - *mode = CBPF_BYTECODE; + cfg->mode = CBPF_BYTECODE; } else if (opt_tbl[CBPF_FILE] && (matches(*argv, "bytecode-file") == 0 || strcmp(*argv, "bcf") == 0)) { - *mode = CBPF_FILE; + cfg->mode = CBPF_FILE; } else if (opt_tbl[EBPF_OBJECT] && (matches(*argv, "object-file") == 0 || strcmp(*argv, "obj") == 0)) { - *mode = EBPF_OBJECT; + cfg->mode = EBPF_OBJECT; } else if (opt_tbl[EBPF_PINNED] && (matches(*argv, "object-pinned") == 0 || matches(*argv, "pinned") == 0 || matches(*argv, "fd") == 0)) { - *mode = EBPF_PINNED; + cfg->mode = EBPF_PINNED; } else { fprintf(stderr, "What mode is \"%s\"?\n", *argv); return -1; @@ -848,7 +839,7 @@ static int bpf_parse(enum bpf_mode *mode, struct bpf_cfg_in *cfg, NEXT_ARG(); file = section = uds_name = NULL; - if (*mode == EBPF_OBJECT || *mode == EBPF_PINNED) { + if (cfg->mode == EBPF_OBJECT || cfg->mode == EBPF_PINNED) { file = *argv; NEXT_ARG_FWD(); @@ -902,11 +893,12 @@ static int bpf_parse(enum bpf_mode *mode, struct bpf_cfg_in *cfg, PREV_ARG(); } - if (*mode == CBPF_BYTECODE || *mode == CBPF_FILE) - ret = bpf_ops_parse(argc, argv, cfg->ops, *mode == CBPF_FILE); - else if (*mode == EBPF_OBJECT) + if (cfg->mode == CBPF_BYTECODE || cfg->mode == CBPF_FILE) + ret = bpf_ops_parse(argc, argv, cfg->ops, + cfg->mode == CBPF_FILE); + else if (cfg->mode == EBPF_OBJECT) ret = bpf_obj_open(file, cfg->type, section, verbose); - else if (*mode == EBPF_PINNED) + else if (cfg->mode == EBPF_PINNED) ret = bpf_obj_pinned(file, cfg->type); else return -1; @@ -926,20 +918,19 @@ static int bpf_parse_opt_tbl(struct bpf_cfg_in *cfg, { struct sock_filter opcodes[BPF_MAXINSNS]; char annotation[256]; - enum bpf_mode mode; int ret; cfg->ops = opcodes; - ret = bpf_parse(&mode, cfg, opt_tbl); + ret = bpf_parse(cfg, opt_tbl); cfg->ops = NULL; if (ret < 0) return ret; - if (mode == CBPF_BYTECODE || mode == CBPF_FILE) + if (cfg->mode == CBPF_BYTECODE || cfg->mode == CBPF_FILE) ops->cbpf_cb(nl, opcodes, ret); - if (mode == EBPF_OBJECT || mode == EBPF_PINNED) { + if (cfg->mode == EBPF_OBJECT || cfg->mode == EBPF_PINNED) { snprintf(annotation, sizeof(annotation), "%s:[%s]", - basename(cfg->object), mode == EBPF_PINNED ? + basename(cfg->object), cfg->mode == EBPF_PINNED ? "*fsobj" : cfg->section); ops->ebpf_cb(nl, ret, annotation); } @@ -983,10 +974,9 @@ int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv) }; struct bpf_map_ext ext = {}; int ret, prog_fd, map_fd; - enum bpf_mode mode; uint32_t map_key; - prog_fd = bpf_parse(&mode, &cfg, opt_tbl); + prog_fd = bpf_parse(&cfg, opt_tbl); if (prog_fd < 0) return prog_fd; if (key) { From 51be754690b8129e2116f9c8e7d4d88e2995fd03 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 23 Nov 2017 18:12:00 -0800 Subject: [PATCH 07/36] bpf: allocate opcode table in struct bpf_cfg_in struct bpf_cfg_in already carries a pointer to sock_filter ops. It's currently set to a local variable in bpf_parse_opt_tbl(), shared between parsing and loading stages. Move the array entirely to struct bpf_cfg_in, this will allow us to split parsing and loading. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Acked-by: Daniel Borkmann --- include/bpf_util.h | 2 +- lib/bpf.c | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/include/bpf_util.h b/include/bpf_util.h index a6f4eeb5..638721f6 100644 --- a/include/bpf_util.h +++ b/include/bpf_util.h @@ -72,7 +72,7 @@ struct bpf_cfg_in { enum bpf_mode mode; int argc; char **argv; - struct sock_filter *ops; + struct sock_filter opcodes[BPF_MAXINSNS]; }; /* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */ diff --git a/lib/bpf.c b/lib/bpf.c index 33c92d6c..7493595a 100644 --- a/lib/bpf.c +++ b/lib/bpf.c @@ -894,7 +894,7 @@ static int bpf_parse(struct bpf_cfg_in *cfg, const bool *opt_tbl) } if (cfg->mode == CBPF_BYTECODE || cfg->mode == CBPF_FILE) - ret = bpf_ops_parse(argc, argv, cfg->ops, + ret = bpf_ops_parse(argc, argv, cfg->opcodes, cfg->mode == CBPF_FILE); else if (cfg->mode == EBPF_OBJECT) ret = bpf_obj_open(file, cfg->type, section, verbose); @@ -916,18 +916,15 @@ static int bpf_parse_opt_tbl(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops, void *nl, const bool *opt_tbl) { - struct sock_filter opcodes[BPF_MAXINSNS]; char annotation[256]; int ret; - cfg->ops = opcodes; ret = bpf_parse(cfg, opt_tbl); - cfg->ops = NULL; if (ret < 0) return ret; if (cfg->mode == CBPF_BYTECODE || cfg->mode == CBPF_FILE) - ops->cbpf_cb(nl, opcodes, ret); + ops->cbpf_cb(nl, cfg->opcodes, ret); if (cfg->mode == EBPF_OBJECT || cfg->mode == EBPF_PINNED) { snprintf(annotation, sizeof(annotation), "%s:[%s]", basename(cfg->object), cfg->mode == EBPF_PINNED ? From 3f0b9e620c5052f56795819ea816643a31831407 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 23 Nov 2017 18:12:01 -0800 Subject: [PATCH 08/36] bpf: split parse from program loading Parsing command line is currently done together with potentially loading a new eBPF program. This makes it more difficult to provide additional parameters for loading (which may come after the eBPF program info on the command line). Split the two (only internally for now). Verbose parameter has to be saved in struct bpf_cfg_in to be carried between the stages. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Acked-by: Daniel Borkmann --- include/bpf_util.h | 5 +++++ lib/bpf.c | 49 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/include/bpf_util.h b/include/bpf_util.h index 638721f6..8e39a2d4 100644 --- a/include/bpf_util.h +++ b/include/bpf_util.h @@ -70,9 +70,14 @@ struct bpf_cfg_in { const char *uds; enum bpf_prog_type type; enum bpf_mode mode; + bool verbose; int argc; char **argv; struct sock_filter opcodes[BPF_MAXINSNS]; + union { + int n_opcodes; + int prog_fd; + }; }; /* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */ diff --git a/lib/bpf.c b/lib/bpf.c index 7493595a..52f7c790 100644 --- a/lib/bpf.c +++ b/lib/bpf.c @@ -805,7 +805,7 @@ static int bpf_obj_pinned(const char *pathname, enum bpf_prog_type type) return prog_fd; } -static int bpf_parse(struct bpf_cfg_in *cfg, const bool *opt_tbl) +static int bpf_do_parse(struct bpf_cfg_in *cfg, const bool *opt_tbl) { const char *file, *section, *uds_name; bool verbose = false; @@ -893,25 +893,39 @@ static int bpf_parse(struct bpf_cfg_in *cfg, const bool *opt_tbl) PREV_ARG(); } - if (cfg->mode == CBPF_BYTECODE || cfg->mode == CBPF_FILE) + if (cfg->mode == CBPF_BYTECODE || cfg->mode == CBPF_FILE) { ret = bpf_ops_parse(argc, argv, cfg->opcodes, cfg->mode == CBPF_FILE); - else if (cfg->mode == EBPF_OBJECT) - ret = bpf_obj_open(file, cfg->type, section, verbose); - else if (cfg->mode == EBPF_PINNED) + cfg->n_opcodes = ret; + } else if (cfg->mode == EBPF_OBJECT) { + ret = 0; /* program will be loaded by load stage */ + } else if (cfg->mode == EBPF_PINNED) { ret = bpf_obj_pinned(file, cfg->type); - else + cfg->prog_fd = ret; + } else { return -1; + } cfg->object = file; cfg->section = section; cfg->uds = uds_name; cfg->argc = argc; cfg->argv = argv; + cfg->verbose = verbose; return ret; } +static int bpf_do_load(struct bpf_cfg_in *cfg) +{ + if (cfg->mode == EBPF_OBJECT) { + cfg->prog_fd = bpf_obj_open(cfg->object, cfg->type, + cfg->section, cfg->verbose); + return cfg->prog_fd; + } + return 0; +} + static int bpf_parse_opt_tbl(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops, void *nl, const bool *opt_tbl) @@ -919,17 +933,21 @@ static int bpf_parse_opt_tbl(struct bpf_cfg_in *cfg, char annotation[256]; int ret; - ret = bpf_parse(cfg, opt_tbl); + ret = bpf_do_parse(cfg, opt_tbl); + if (ret < 0) + return ret; + + ret = bpf_do_load(cfg); if (ret < 0) return ret; if (cfg->mode == CBPF_BYTECODE || cfg->mode == CBPF_FILE) - ops->cbpf_cb(nl, cfg->opcodes, ret); + ops->cbpf_cb(nl, cfg->opcodes, cfg->n_opcodes); if (cfg->mode == EBPF_OBJECT || cfg->mode == EBPF_PINNED) { snprintf(annotation, sizeof(annotation), "%s:[%s]", basename(cfg->object), cfg->mode == EBPF_PINNED ? "*fsobj" : cfg->section); - ops->ebpf_cb(nl, ret, annotation); + ops->ebpf_cb(nl, cfg->prog_fd, annotation); } return 0; @@ -973,9 +991,16 @@ int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv) int ret, prog_fd, map_fd; uint32_t map_key; - prog_fd = bpf_parse(&cfg, opt_tbl); - if (prog_fd < 0) - return prog_fd; + ret = bpf_do_parse(&cfg, opt_tbl); + if (ret < 0) + return ret; + + ret = bpf_do_load(&cfg); + if (ret < 0) + return ret; + + prog_fd = cfg.prog_fd; + if (key) { map_key = *key; } else { From 399db8392bd720588c5355ad79907e9c515e86ac Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 23 Nov 2017 18:12:02 -0800 Subject: [PATCH 09/36] bpf: rename bpf_parse_common() to bpf_parse_and_load_common() bpf_parse_common() parses and loads the program. Rename it accordingly. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Acked-by: Daniel Borkmann --- include/bpf_util.h | 4 ++-- ip/iplink_xdp.c | 2 +- ip/iproute_lwtunnel.c | 2 +- lib/bpf.c | 4 ++-- tc/f_bpf.c | 2 +- tc/m_bpf.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/bpf_util.h b/include/bpf_util.h index 8e39a2d4..da2dee8b 100644 --- a/include/bpf_util.h +++ b/include/bpf_util.h @@ -259,8 +259,8 @@ struct bpf_cfg_in { .off = 0, \ .imm = 0 }) -int bpf_parse_common(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops, - void *nl); +int bpf_parse_and_load_common(struct bpf_cfg_in *cfg, + const struct bpf_cfg_ops *ops, void *nl); const char *bpf_prog_to_default_section(enum bpf_prog_type type); diff --git a/ip/iplink_xdp.c b/ip/iplink_xdp.c index 993e44d7..edaec2a2 100644 --- a/ip/iplink_xdp.c +++ b/ip/iplink_xdp.c @@ -75,7 +75,7 @@ int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic, return xdp_delete(&xdp); } - if (bpf_parse_common(&cfg, &bpf_cb_ops, &xdp)) + if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &xdp)) return -1; *argc = cfg.argc; diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 62dc0cd8..740da7c6 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -898,7 +898,7 @@ static int lwt_parse_bpf(struct rtattr *rta, size_t len, int err; nest = rta_nest(rta, len, attr); - err = bpf_parse_common(&cfg, &bpf_cb_ops, &x); + err = bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &x); if (err < 0) { fprintf(stderr, "Failed to parse eBPF program: %s\n", strerror(-err)); diff --git a/lib/bpf.c b/lib/bpf.c index 52f7c790..9a086712 100644 --- a/lib/bpf.c +++ b/lib/bpf.c @@ -953,8 +953,8 @@ static int bpf_parse_opt_tbl(struct bpf_cfg_in *cfg, return 0; } -int bpf_parse_common(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops, - void *nl) +int bpf_parse_and_load_common(struct bpf_cfg_in *cfg, + const struct bpf_cfg_ops *ops, void *nl) { bool opt_tbl[BPF_MODE_MAX] = {}; diff --git a/tc/f_bpf.c b/tc/f_bpf.c index a38ec2ab..21ba759c 100644 --- a/tc/f_bpf.c +++ b/tc/f_bpf.c @@ -107,7 +107,7 @@ opt_bpf: cfg.argc = argc; cfg.argv = argv; - if (bpf_parse_common(&cfg, &bpf_cb_ops, n)) + if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, n)) return -1; argc = cfg.argc; diff --git a/tc/m_bpf.c b/tc/m_bpf.c index f2ce3892..e275afd0 100644 --- a/tc/m_bpf.c +++ b/tc/m_bpf.c @@ -102,7 +102,7 @@ opt_bpf: cfg.argc = argc; cfg.argv = argv; - if (bpf_parse_common(&cfg, &bpf_cb_ops, n)) + if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, n)) return -1; argc = cfg.argc; From 4a847fcb51839508706b698ddf43b575b9fa9a97 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 23 Nov 2017 18:12:03 -0800 Subject: [PATCH 10/36] bpf: expose bpf_parse_common() and bpf_load_common() Expose bpf_parse_common() and bpf_load_common() functions for those users who may want to modify the parameters to load after parsing is done. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Acked-by: Daniel Borkmann --- include/bpf_util.h | 3 +++ lib/bpf.c | 26 ++++++++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/include/bpf_util.h b/include/bpf_util.h index da2dee8b..f6371994 100644 --- a/include/bpf_util.h +++ b/include/bpf_util.h @@ -259,6 +259,9 @@ struct bpf_cfg_in { .off = 0, \ .imm = 0 }) +int bpf_parse_common(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops); +int bpf_load_common(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops, + void *nl); int bpf_parse_and_load_common(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops, void *nl); diff --git a/lib/bpf.c b/lib/bpf.c index 9a086712..f25f7016 100644 --- a/lib/bpf.c +++ b/lib/bpf.c @@ -926,17 +926,12 @@ static int bpf_do_load(struct bpf_cfg_in *cfg) return 0; } -static int bpf_parse_opt_tbl(struct bpf_cfg_in *cfg, - const struct bpf_cfg_ops *ops, void *nl, - const bool *opt_tbl) +int bpf_load_common(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops, + void *nl) { char annotation[256]; int ret; - ret = bpf_do_parse(cfg, opt_tbl); - if (ret < 0) - return ret; - ret = bpf_do_load(cfg); if (ret < 0) return ret; @@ -953,8 +948,7 @@ static int bpf_parse_opt_tbl(struct bpf_cfg_in *cfg, return 0; } -int bpf_parse_and_load_common(struct bpf_cfg_in *cfg, - const struct bpf_cfg_ops *ops, void *nl) +int bpf_parse_common(struct bpf_cfg_in *cfg, const struct bpf_cfg_ops *ops) { bool opt_tbl[BPF_MODE_MAX] = {}; @@ -968,7 +962,19 @@ int bpf_parse_and_load_common(struct bpf_cfg_in *cfg, opt_tbl[EBPF_PINNED] = true; } - return bpf_parse_opt_tbl(cfg, ops, nl, opt_tbl); + return bpf_do_parse(cfg, opt_tbl); +} + +int bpf_parse_and_load_common(struct bpf_cfg_in *cfg, + const struct bpf_cfg_ops *ops, void *nl) +{ + int ret; + + ret = bpf_parse_common(cfg, ops); + if (ret < 0) + return ret; + + return bpf_load_common(cfg, ops, nl); } int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv) From 65fdae3d181611a8bbb6cb39b682c3c518bc243a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 23 Nov 2017 18:12:04 -0800 Subject: [PATCH 11/36] bpf: allow loading programs for a specific ifindex For BPF offload we need to specify the ifindex when program is loaded now. Extend the bpf common code to accommodate that. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Acked-by: Daniel Borkmann --- include/bpf_util.h | 1 + lib/bpf.c | 37 ++++++++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/include/bpf_util.h b/include/bpf_util.h index f6371994..219beb40 100644 --- a/include/bpf_util.h +++ b/include/bpf_util.h @@ -70,6 +70,7 @@ struct bpf_cfg_in { const char *uds; enum bpf_prog_type type; enum bpf_mode mode; + __u32 ifindex; bool verbose; int argc; char **argv; diff --git a/lib/bpf.c b/lib/bpf.c index f25f7016..d32f1b80 100644 --- a/lib/bpf.c +++ b/lib/bpf.c @@ -113,10 +113,10 @@ const char *bpf_prog_to_default_section(enum bpf_prog_type type) #ifdef HAVE_ELF static int bpf_obj_open(const char *path, enum bpf_prog_type type, - const char *sec, bool verbose); + const char *sec, __u32 ifindex, bool verbose); #else static int bpf_obj_open(const char *path, enum bpf_prog_type type, - const char *sec, bool verbose) + const char *sec, __u32 ifindex, bool verbose) { fprintf(stderr, "No ELF library support compiled in.\n"); errno = ENOSYS; @@ -920,7 +920,8 @@ static int bpf_do_load(struct bpf_cfg_in *cfg) { if (cfg->mode == EBPF_OBJECT) { cfg->prog_fd = bpf_obj_open(cfg->object, cfg->type, - cfg->section, cfg->verbose); + cfg->section, cfg->ifindex, + cfg->verbose); return cfg->prog_fd; } return 0; @@ -1065,9 +1066,10 @@ int bpf_prog_detach_fd(int target_fd, enum bpf_attach_type type) return bpf(BPF_PROG_DETACH, &attr, sizeof(attr)); } -int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, - size_t size_insns, const char *license, char *log, - size_t size_log) +static int bpf_prog_load_dev(enum bpf_prog_type type, + const struct bpf_insn *insns, size_t size_insns, + const char *license, __u32 ifindex, + char *log, size_t size_log) { union bpf_attr attr = {}; @@ -1075,6 +1077,7 @@ int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, attr.insns = bpf_ptr_to_u64(insns); attr.insn_cnt = size_insns / sizeof(struct bpf_insn); attr.license = bpf_ptr_to_u64(license); + attr.prog_ifindex = ifindex; if (size_log > 0) { attr.log_buf = bpf_ptr_to_u64(log); @@ -1085,6 +1088,14 @@ int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, return bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); } +int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, + size_t size_insns, const char *license, char *log, + size_t size_log) +{ + return bpf_prog_load_dev(type, insns, size_insns, license, 0, + log, size_log); +} + #ifdef HAVE_ELF struct bpf_elf_prog { enum bpf_prog_type type; @@ -1120,6 +1131,7 @@ struct bpf_elf_ctx { int sec_maps; char license[ELF_MAX_LICENSE_LEN]; enum bpf_prog_type type; + __u32 ifindex; bool verbose; struct bpf_elf_st stat; struct bpf_hash_entry *ht[256]; @@ -1492,8 +1504,9 @@ static int bpf_prog_attach(const char *section, int tries = 0, fd; retry: errno = 0; - fd = bpf_prog_load(prog->type, prog->insns, prog->size, - prog->license, ctx->log, ctx->log_size); + fd = bpf_prog_load_dev(prog->type, prog->insns, prog->size, + prog->license, ctx->ifindex, + ctx->log, ctx->log_size); if (fd < 0 || ctx->verbose) { /* The verifier log is pretty chatty, sometimes so chatty * on larger programs, that we could fail to dump everything @@ -2421,7 +2434,8 @@ static void bpf_get_cfg(struct bpf_elf_ctx *ctx) } static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, - enum bpf_prog_type type, bool verbose) + enum bpf_prog_type type, __u32 ifindex, + bool verbose) { int ret = -EINVAL; @@ -2433,6 +2447,7 @@ static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, bpf_get_cfg(ctx); ctx->verbose = verbose; ctx->type = type; + ctx->ifindex = ifindex; ctx->obj_fd = open(pathname, O_RDONLY); if (ctx->obj_fd < 0) @@ -2524,12 +2539,12 @@ static void bpf_elf_ctx_destroy(struct bpf_elf_ctx *ctx, bool failure) static struct bpf_elf_ctx __ctx; static int bpf_obj_open(const char *pathname, enum bpf_prog_type type, - const char *section, bool verbose) + const char *section, __u32 ifindex, bool verbose) { struct bpf_elf_ctx *ctx = &__ctx; int fd = 0, ret; - ret = bpf_elf_ctx_init(ctx, pathname, type, verbose); + ret = bpf_elf_ctx_init(ctx, pathname, type, ifindex, verbose); if (ret < 0) { fprintf(stderr, "Cannot initialize ELF context!\n"); return ret; From 67c857df807f490363aea61f5d7ff8dd7063516e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 23 Nov 2017 18:12:05 -0800 Subject: [PATCH 12/36] {f, m}_bpf: don't allow specifying multiple bpf programs Both BPF filter and action will allow users to specify run multiple times, and only the last one will be considered by the kernel. Explicitly refuse such command lines. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Acked-by: Daniel Borkmann --- tc/f_bpf.c | 3 +++ tc/m_bpf.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tc/f_bpf.c b/tc/f_bpf.c index 21ba759c..f598784e 100644 --- a/tc/f_bpf.c +++ b/tc/f_bpf.c @@ -101,6 +101,9 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle, while (argc > 0) { if (matches(*argv, "run") == 0) { NEXT_ARG(); + + if (seen_run) + duparg("run", *argv); opt_bpf: seen_run = true; cfg.type = bpf_type; diff --git a/tc/m_bpf.c b/tc/m_bpf.c index e275afd0..1c1f71cd 100644 --- a/tc/m_bpf.c +++ b/tc/m_bpf.c @@ -96,6 +96,9 @@ static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv, while (argc > 0) { if (matches(*argv, "run") == 0) { NEXT_ARG(); + + if (seen_run) + duparg("run", *argv); opt_bpf: seen_run = true; cfg.type = bpf_type; From 01ea76b1cf54516c71a9a54fba672410ada2cccb Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 23 Nov 2017 18:12:06 -0800 Subject: [PATCH 13/36] tc_filter: resolve device name before parsing filter Move resolving device name into an ifindex before calling filter specific callbacks. This way if filters need the ifindex, they can read it from the request. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Acked-by: Daniel Borkmann --- tc/tc_filter.c | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/tc/tc_filter.c b/tc/tc_filter.c index 276a66cb..73f17816 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -160,6 +160,16 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv) if (k[0]) addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1); + if (d[0]) { + ll_init_map(&rth); + + req.t.tcm_ifindex = ll_name_to_index(d); + if (req.t.tcm_ifindex == 0) { + fprintf(stderr, "Cannot find device \"%s\"\n", d); + return 1; + } + } + if (q) { if (q->parse_fopt(q, fhandle, argc, argv, &req.n)) return 1; @@ -182,17 +192,6 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv) if (est.ewma_log) addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est)); - - if (d[0]) { - ll_init_map(&rth); - - req.t.tcm_ifindex = ll_name_to_index(d); - if (req.t.tcm_ifindex == 0) { - fprintf(stderr, "Cannot find device \"%s\"\n", d); - return 1; - } - } - if (rtnl_talk(&rth, &req.n, NULL) < 0) { fprintf(stderr, "We have an error talking to the kernel\n"); return 2; @@ -452,10 +451,23 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv) return -1; } + if (d[0]) { + ll_init_map(&rth); + + req.t.tcm_ifindex = ll_name_to_index(d); + if (req.t.tcm_ifindex == 0) { + fprintf(stderr, "Cannot find device \"%s\"\n", d); + return 1; + } + filter_ifindex = req.t.tcm_ifindex; + } else { + fprintf(stderr, "Must specify netdevice \"dev\"\n"); + return -1; + } + if (q->parse_fopt(q, fhandle, argc, argv, &req.n)) return 1; - if (!fhandle) { fprintf(stderr, "Must specify filter \"handle\"\n"); return -1; @@ -470,20 +482,6 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv) return -1; } - if (d[0]) { - ll_init_map(&rth); - - req.t.tcm_ifindex = ll_name_to_index(d); - if (req.t.tcm_ifindex == 0) { - fprintf(stderr, "Cannot find device \"%s\"\n", d); - return 1; - } - filter_ifindex = req.t.tcm_ifindex; - } else { - fprintf(stderr, "Must specify netdevice \"dev\"\n"); - return -1; - } - if (rtnl_talk(&rth, &req.n, &answer) < 0) { fprintf(stderr, "We have an error talking to the kernel\n"); return 2; From eb91c55731b580d21abdd5e2c0615913ac0f605f Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 23 Nov 2017 18:12:07 -0800 Subject: [PATCH 14/36] f_bpf: communicate ifindex for eBPF offload Split parsing and loading of the eBPF program and if skip_sw is set load the program for ifindex, to which the qdisc is attached. Note that the ifindex will be ignored for programs which are already loaded (e.g. when using pinned programs), but in that case we just trust the user knows what he's doing. Hopefully we will get extack soon in the driver to help debugging this case. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Acked-by: Daniel Borkmann --- tc/f_bpf.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tc/f_bpf.c b/tc/f_bpf.c index f598784e..5906f8bb 100644 --- a/tc/f_bpf.c +++ b/tc/f_bpf.c @@ -82,6 +82,7 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle, unsigned int bpf_flags = 0; struct bpf_cfg_in cfg = {}; bool seen_run = false; + bool skip_sw = false; struct rtattr *tail; int ret = 0; @@ -110,8 +111,11 @@ opt_bpf: cfg.argc = argc; cfg.argv = argv; - if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, n)) + if (bpf_parse_common(&cfg, &bpf_cb_ops) < 0) { + fprintf(stderr, + "Unable to parse bpf command line\n"); return -1; + } argc = cfg.argc; argv = cfg.argv; @@ -135,6 +139,7 @@ opt_bpf: bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_HW; } else if (matches(*argv, "skip_sw") == 0) { bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_SW; + skip_sw = true; } else if (matches(*argv, "action") == 0) { NEXT_ARG(); if (parse_action(&argc, &argv, TCA_BPF_ACT, n)) { @@ -164,6 +169,13 @@ opt_bpf: NEXT_ARG_FWD(); } + if (skip_sw) + cfg.ifindex = t->tcm_ifindex; + if (bpf_load_common(&cfg, &bpf_cb_ops, n) < 0) { + fprintf(stderr, "Unable to load program\n"); + return -1; + } + if (bpf_gen_flags) addattr32(n, MAX_MSG, TCA_BPF_FLAGS_GEN, bpf_gen_flags); if (bpf_flags) From 4f2eb14f71bfb091228f4a9979c01daa207d4582 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 23 Nov 2017 18:12:08 -0800 Subject: [PATCH 15/36] iplink: communicate ifindex for xdp offload When xdpoffload option is used, communicate the ifindex down to the kernel to trigger device-specific load. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Acked-by: Daniel Borkmann --- ip/iplink.c | 4 ++-- ip/iplink_xdp.c | 10 ++++++++-- ip/xdp.h | 4 ++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ip/iplink.c b/ip/iplink.c index 2c51ef7d..0a8eb56f 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -631,8 +631,8 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, bool offload = strcmp(*argv, "xdpoffload") == 0; NEXT_ARG(); - if (xdp_parse(&argc, &argv, req, generic, drv, - offload)) + if (xdp_parse(&argc, &argv, req, dev_index, + generic, drv, offload)) exit(-1); } else if (strcmp(*argv, "netns") == 0) { NEXT_ARG(); diff --git a/ip/iplink_xdp.c b/ip/iplink_xdp.c index edaec2a2..6eeb820a 100644 --- a/ip/iplink_xdp.c +++ b/ip/iplink_xdp.c @@ -48,8 +48,8 @@ static int xdp_delete(struct xdp_req *xdp) return 0; } -int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic, - bool drv, bool offload) +int xdp_parse(int *argc, char ***argv, struct iplink_req *req, __u32 ifindex, + bool generic, bool drv, bool offload) { struct bpf_cfg_in cfg = { .type = BPF_PROG_TYPE_XDP, @@ -60,6 +60,12 @@ int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic, .req = req, }; + if (offload) { + if (!ifindex) + incomplete_command(); + cfg.ifindex = ifindex; + } + if (!force) xdp.flags |= XDP_FLAGS_UPDATE_IF_NOEXIST; if (generic) diff --git a/ip/xdp.h b/ip/xdp.h index 215a6dcb..7e10696a 100644 --- a/ip/xdp.h +++ b/ip/xdp.h @@ -4,8 +4,8 @@ #include "utils.h" -int xdp_parse(int *argc, char ***argv, struct iplink_req *req, bool generic, - bool drv, bool offload); +int xdp_parse(int *argc, char ***argv, struct iplink_req *req, __u32 ifindex, + bool generic, bool drv, bool offload); void xdp_dump(FILE *fp, struct rtattr *tb, bool link, bool details); #endif /* __XDP__ */ From abff45b8026e24dedfe05376d8fedc1a8fe43402 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 25 Nov 2017 11:07:56 +0100 Subject: [PATCH 16/36] tc: move action cookie print out of the stats if Cookie print was made dependent on show_stats for no good reason. Fix this bu pushing cookie print ot of the stats if. Fixes: fd8b3d2c1b9b ("actions: Add support for user cookies") Signed-off-by: Jiri Pirko --- tc/m_action.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tc/m_action.c b/tc/m_action.c index 85f9e27b..aa3aa52e 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -301,19 +301,18 @@ static int tc_print_one_action(FILE *f, struct rtattr *arg) return err; if (show_stats && tb[TCA_ACT_STATS]) { - fprintf(f, "\tAction statistics:\n"); print_tcstats2_attr(f, tb[TCA_ACT_STATS], "\t", NULL); - if (tb[TCA_ACT_COOKIE]) { - int strsz = RTA_PAYLOAD(tb[TCA_ACT_COOKIE]); - char b1[strsz * 2 + 1]; - - fprintf(f, "\n\tcookie len %d %s ", strsz, - hexstring_n2a(RTA_DATA(tb[TCA_ACT_COOKIE]), - strsz, b1, sizeof(b1))); - } fprintf(f, "\n"); } + if (tb[TCA_ACT_COOKIE]) { + int strsz = RTA_PAYLOAD(tb[TCA_ACT_COOKIE]); + char b1[strsz * 2 + 1]; + + fprintf(f, "\tcookie len %d %s\n", strsz, + hexstring_n2a(RTA_DATA(tb[TCA_ACT_COOKIE]), + strsz, b1, sizeof(b1))); + } return 0; } From 81051c60c24ad083cfcb46271e6450675763c722 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 25 Nov 2017 11:07:57 +0100 Subject: [PATCH 17/36] tc: remove action cookie len from printout Make the output same as input and avoid printout of unnecessary len. Suggested-by: Stephen Hemminger Fixes: fd8b3d2c1b9b ("actions: Add support for user cookies") Signed-off-by: Jiri Pirko --- tc/m_action.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tc/m_action.c b/tc/m_action.c index aa3aa52e..e6d91498 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -309,7 +309,7 @@ static int tc_print_one_action(FILE *f, struct rtattr *arg) int strsz = RTA_PAYLOAD(tb[TCA_ACT_COOKIE]); char b1[strsz * 2 + 1]; - fprintf(f, "\tcookie len %d %s\n", strsz, + fprintf(f, "\tcookie %s\n", hexstring_n2a(RTA_DATA(tb[TCA_ACT_COOKIE]), strsz, b1, sizeof(b1))); } From c91d262f414d2b3051570701ef5fa54443ecc38a Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 25 Nov 2017 15:48:25 +0100 Subject: [PATCH 18/36] tc: jsonify qdisc core Add json output to qdisc core. Signed-off-by: Jiri Pirko --- tc/tc.c | 5 ++++- tc/tc_qdisc.c | 50 +++++++++++++++++++++++++++++++------------------- tc/tc_util.h | 1 + 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/tc/tc.c b/tc/tc.c index 793dca9f..ad9f07e9 100644 --- a/tc/tc.c +++ b/tc/tc.c @@ -41,6 +41,7 @@ int batch_mode; int use_iec; int force; bool use_names; +int json; static char *conf_file; @@ -189,7 +190,7 @@ static void usage(void) " tc [-force] -batch filename\n" "where OBJECT := { qdisc | class | filter | action | monitor | exec }\n" " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [filename] | -n[etns] name |\n" - " -nm | -nam[es] | { -cf | -conf } path }\n"); + " -nm | -nam[es] | { -cf | -conf } path } | -j[son]\n"); } static int do_cmd(int argc, char **argv) @@ -312,6 +313,8 @@ int main(int argc, char **argv) } else if (matches(argv[1], "-tshort") == 0) { ++timestamp; ++timestamp_short; + } else if (matches(argv[1], "-json") == 0) { + ++json; } else { fprintf(stderr, "Option \"%s\" is unknown, try \"tc -help\".\n", argv[1]); return -1; diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index 2f88f11c..4431d5fd 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -227,39 +227,44 @@ int print_qdisc(const struct sockaddr_nl *who, return -1; } + open_json_object(NULL); + if (n->nlmsg_type == RTM_DELQDISC) - fprintf(fp, "deleted "); + print_bool(PRINT_ANY, "deleted", "deleted ", true); if (n->nlmsg_type == RTM_NEWQDISC && (n->nlmsg_flags & NLM_F_CREATE) && (n->nlmsg_flags & NLM_F_REPLACE)) - fprintf(fp, "replaced "); + print_bool(PRINT_ANY, "replaced", "replaced ", true); if (n->nlmsg_type == RTM_NEWQDISC && (n->nlmsg_flags & NLM_F_CREATE) && (n->nlmsg_flags & NLM_F_EXCL)) - fprintf(fp, "added "); + print_bool(PRINT_ANY, "added", "added ", true); - if (show_raw) - fprintf(fp, "qdisc %s %x:[%08x] ", - rta_getattr_str(tb[TCA_KIND]), - t->tcm_handle >> 16, t->tcm_handle); - else - fprintf(fp, "qdisc %s %x: ", rta_getattr_str(tb[TCA_KIND]), - t->tcm_handle >> 16); + print_string(PRINT_ANY, "kind", "qdisc %s", + rta_getattr_str(tb[TCA_KIND])); + sprintf(abuf, "%x:", t->tcm_handle >> 16); + print_string(PRINT_ANY, "handle", " %s", abuf); + if (show_raw) { + sprintf(abuf, "[%08x]", t->tcm_handle); + print_string(PRINT_FP, NULL, "%s", abuf); + } + print_string(PRINT_FP, NULL, " ", NULL); if (filter_ifindex == 0) - fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex)); + print_string(PRINT_ANY, "dev", "dev %s ", + ll_index_to_name(t->tcm_ifindex)); if (t->tcm_parent == TC_H_ROOT) - fprintf(fp, "root "); + print_bool(PRINT_ANY, "root", "root ", true); else if (t->tcm_parent) { print_tc_classid(abuf, sizeof(abuf), t->tcm_parent); - fprintf(fp, "parent %s ", abuf); + print_string(PRINT_ANY, "parent", "parent %s ", abuf); } if (t->tcm_info != 1) - fprintf(fp, "refcnt %d ", t->tcm_info); + print_uint(PRINT_ANY, "refcnt", "refcnt %u ", t->tcm_info); /* pfifo_fast is generic enough to warrant the hardcoding --JHS */ if (strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND])) == 0) @@ -267,17 +272,21 @@ int print_qdisc(const struct sockaddr_nl *who, else q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND])); + open_json_object("options"); if (tb[TCA_OPTIONS]) { if (q) q->print_qopt(q, fp, tb[TCA_OPTIONS]); else - fprintf(fp, "[cannot parse qdisc parameters]"); + print_string(PRINT_FP, NULL, + "[cannot parse qdisc parameters]", NULL); } - fprintf(fp, "\n"); + close_json_object(); + + print_string(PRINT_FP, NULL, "\n", NULL); if (show_details && tb[TCA_STAB]) { print_size_table(fp, " ", tb[TCA_STAB]); - fprintf(fp, "\n"); + print_string(PRINT_FP, NULL, "\n", NULL); } if (show_stats) { @@ -285,14 +294,15 @@ int print_qdisc(const struct sockaddr_nl *who, if (tb[TCA_STATS] || tb[TCA_STATS2] || tb[TCA_XSTATS]) { print_tcstats_attr(fp, tb, " ", &xstats); - fprintf(fp, "\n"); + print_string(PRINT_FP, NULL, "\n", NULL); } if (q && xstats && q->print_xstats) { q->print_xstats(q, fp, xstats); - fprintf(fp, "\n"); + print_string(PRINT_FP, NULL, "\n", NULL); } } + close_json_object(); fflush(fp); return 0; } @@ -360,10 +370,12 @@ static int tc_qdisc_list(int argc, char **argv) return 1; } + new_json_obj(json); if (rtnl_dump_filter(&rth, print_qdisc, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); return 1; } + delete_json_obj(); return 0; } diff --git a/tc/tc_util.h b/tc/tc_util.h index 40a8865d..1218610d 100644 --- a/tc/tc_util.h +++ b/tc/tc_util.h @@ -11,6 +11,7 @@ #include #include "tc_core.h" +#include "json_print.h" /* This is the deprecated multiqueue interface */ #ifndef TCA_PRIO_MAX From 4fcec7f3665b3acfc8a7750acf62e7b77220c33d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 25 Nov 2017 15:48:26 +0100 Subject: [PATCH 19/36] tc: jsonify stats2 Add json output to stats2. Signed-off-by: Jiri Pirko --- tc/tc_util.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/tc/tc_util.c b/tc/tc_util.c index 5532d40b..d2769879 100644 --- a/tc/tc_util.c +++ b/tc/tc_util.c @@ -781,16 +781,19 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat struct gnet_stats_basic bs = {0}; memcpy(&bs, RTA_DATA(tbs[TCA_STATS_BASIC]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_BASIC]), sizeof(bs))); - fprintf(fp, "%sSent %llu bytes %u pkt", - prefix, (unsigned long long) bs.bytes, bs.packets); + print_string(PRINT_FP, NULL, "%s", prefix); + print_lluint(PRINT_ANY, "bytes", "Sent %llu bytes", bs.bytes); + print_uint(PRINT_ANY, "packets", " %u pkt", bs.packets); } if (tbs[TCA_STATS_QUEUE]) { struct gnet_stats_queue q = {0}; memcpy(&q, RTA_DATA(tbs[TCA_STATS_QUEUE]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_QUEUE]), sizeof(q))); - fprintf(fp, " (dropped %u, overlimits %u requeues %u) ", - q.drops, q.overlimits, q.requeues); + print_uint(PRINT_ANY, "drops", " (dropped %u", q.drops); + print_uint(PRINT_ANY, "overlimits", ", overlimits %u", + q.overlimits); + print_uint(PRINT_ANY, "requeues", " requeues %u) ", q.requeues); } if (tbs[TCA_STATS_RATE_EST64]) { @@ -799,8 +802,11 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat memcpy(&re, RTA_DATA(tbs[TCA_STATS_RATE_EST64]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_RATE_EST64]), sizeof(re))); - fprintf(fp, "\n%srate %s %llupps ", - prefix, sprint_rate(re.bps, b1), re.pps); + print_string(PRINT_FP, NULL, "\n%s", prefix); + print_lluint(PRINT_JSON, "rate", NULL, re.bps); + print_string(PRINT_FP, NULL, "rate %s", + sprint_rate(re.bps, b1)); + print_lluint(PRINT_ANY, "pps", " %llupps", re.pps); } else if (tbs[TCA_STATS_RATE_EST]) { struct gnet_stats_rate_est re = {0}; @@ -808,6 +814,11 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat MIN(RTA_PAYLOAD(tbs[TCA_STATS_RATE_EST]), sizeof(re))); fprintf(fp, "\n%srate %s %upps ", prefix, sprint_rate(re.bps, b1), re.pps); + print_string(PRINT_FP, NULL, "\n%s", prefix); + print_uint(PRINT_JSON, "rate", NULL, re.bps); + print_string(PRINT_FP, NULL, "rate %s", + sprint_rate(re.bps, b1)); + print_uint(PRINT_ANY, "pps", " %upps", re.pps); } if (tbs[TCA_STATS_QUEUE]) { @@ -815,9 +826,12 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat memcpy(&q, RTA_DATA(tbs[TCA_STATS_QUEUE]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_QUEUE]), sizeof(q))); if (!tbs[TCA_STATS_RATE_EST]) - fprintf(fp, "\n%s", prefix); - fprintf(fp, "backlog %s %up requeues %u ", - sprint_size(q.backlog, b1), q.qlen, q.requeues); + print_string(PRINT_FP, NULL, "\n%s", prefix); + print_uint(PRINT_JSON, "backlog", NULL, q.backlog); + print_string(PRINT_FP, NULL, "backlog %s", + sprint_size(q.backlog, b1)); + print_uint(PRINT_ANY, "qlen", " %up", q.qlen); + print_uint(PRINT_ANY, "requeues", " requeues %u", q.qlen); } if (xstats) From 378ac491f560beb75925df00de65dce471beeed0 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 25 Nov 2017 15:48:27 +0100 Subject: [PATCH 20/36] tc: jsonify fq_codel qdisc Add json output to fq_codel qdisc. Signed-off-by: Jiri Pirko --- tc/q_fq_codel.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/tc/q_fq_codel.c b/tc/q_fq_codel.c index 86c6fb24..fd1f59c8 100644 --- a/tc/q_fq_codel.c +++ b/tc/q_fq_codel.c @@ -173,44 +173,51 @@ static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt if (tb[TCA_FQ_CODEL_LIMIT] && RTA_PAYLOAD(tb[TCA_FQ_CODEL_LIMIT]) >= sizeof(__u32)) { limit = rta_getattr_u32(tb[TCA_FQ_CODEL_LIMIT]); - fprintf(f, "limit %up ", limit); + print_uint(PRINT_ANY, "limit", "limit %up ", limit); } if (tb[TCA_FQ_CODEL_FLOWS] && RTA_PAYLOAD(tb[TCA_FQ_CODEL_FLOWS]) >= sizeof(__u32)) { flows = rta_getattr_u32(tb[TCA_FQ_CODEL_FLOWS]); - fprintf(f, "flows %u ", flows); + print_uint(PRINT_ANY, "flows", "flows %u ", flows); } if (tb[TCA_FQ_CODEL_QUANTUM] && RTA_PAYLOAD(tb[TCA_FQ_CODEL_QUANTUM]) >= sizeof(__u32)) { quantum = rta_getattr_u32(tb[TCA_FQ_CODEL_QUANTUM]); - fprintf(f, "quantum %u ", quantum); + print_uint(PRINT_ANY, "quantum", "quantum %u ", quantum); } if (tb[TCA_FQ_CODEL_TARGET] && RTA_PAYLOAD(tb[TCA_FQ_CODEL_TARGET]) >= sizeof(__u32)) { target = rta_getattr_u32(tb[TCA_FQ_CODEL_TARGET]); - fprintf(f, "target %s ", sprint_time(target, b1)); + print_uint(PRINT_JSON, "target", NULL, target); + print_string(PRINT_FP, NULL, "target %s ", + sprint_time(target, b1)); } if (tb[TCA_FQ_CODEL_CE_THRESHOLD] && RTA_PAYLOAD(tb[TCA_FQ_CODEL_CE_THRESHOLD]) >= sizeof(__u32)) { ce_threshold = rta_getattr_u32(tb[TCA_FQ_CODEL_CE_THRESHOLD]); - fprintf(f, "ce_threshold %s ", sprint_time(ce_threshold, b1)); + print_uint(PRINT_JSON, "ce_threshold", NULL, ce_threshold); + print_string(PRINT_FP, NULL, "ce_threshold %s ", + sprint_time(ce_threshold, b1)); } if (tb[TCA_FQ_CODEL_INTERVAL] && RTA_PAYLOAD(tb[TCA_FQ_CODEL_INTERVAL]) >= sizeof(__u32)) { interval = rta_getattr_u32(tb[TCA_FQ_CODEL_INTERVAL]); - fprintf(f, "interval %s ", sprint_time(interval, b1)); + print_uint(PRINT_JSON, "interval", NULL, interval); + print_string(PRINT_FP, NULL, "interval %s ", + sprint_time(interval, b1)); } if (tb[TCA_FQ_CODEL_MEMORY_LIMIT] && RTA_PAYLOAD(tb[TCA_FQ_CODEL_MEMORY_LIMIT]) >= sizeof(__u32)) { memory_limit = rta_getattr_u32(tb[TCA_FQ_CODEL_MEMORY_LIMIT]); - - fprintf(f, "memory_limit %s ", sprint_size(memory_limit, b1)); + print_uint(PRINT_JSON, "memory_limit", NULL, memory_limit); + print_string(PRINT_FP, NULL, "memory_limit %s ", + sprint_size(memory_limit, b1)); } if (tb[TCA_FQ_CODEL_ECN] && RTA_PAYLOAD(tb[TCA_FQ_CODEL_ECN]) >= sizeof(__u32)) { ecn = rta_getattr_u32(tb[TCA_FQ_CODEL_ECN]); if (ecn) - fprintf(f, "ecn "); + print_bool(PRINT_ANY, "ecn", "ecn ", true); } return 0; From f354fa6aa5ff05dd214a595e5159ef93a6ab1934 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 25 Nov 2017 15:48:28 +0100 Subject: [PATCH 21/36] tc: jsonify htb qdisc Add json output to htb qdisc. Signed-off-by: Jiri Pirko --- tc/q_htb.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tc/q_htb.c b/tc/q_htb.c index ffb43aa1..3fc2acb3 100644 --- a/tc/q_htb.c +++ b/tc/q_htb.c @@ -293,9 +293,10 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (RTA_PAYLOAD(tb[TCA_HTB_PARMS]) < sizeof(*hopt)) return -1; if (!hopt->level) { - fprintf(f, "prio %d ", (int)hopt->prio); + print_int(PRINT_ANY, "prio", "prio ", (int)hopt->prio); if (show_details) - fprintf(f, "quantum %d ", (int)hopt->quantum); + print_int(PRINT_ANY, "quantum", "quantum ", + (int)hopt->quantum); } rate64 = hopt->rate.rate; @@ -341,16 +342,21 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) gopt = RTA_DATA(tb[TCA_HTB_INIT]); if (RTA_PAYLOAD(tb[TCA_HTB_INIT]) < sizeof(*gopt)) return -1; - fprintf(f, "r2q %d default %x direct_packets_stat %u", - gopt->rate2quantum, gopt->defcls, gopt->direct_pkts); - if (show_details) - fprintf(f, " ver %d.%d", gopt->version >> 16, gopt->version & 0xffff); + print_int(PRINT_ANY, "r2q", "r2q %d", gopt->rate2quantum); + print_uint(PRINT_ANY, "default", " default %u", gopt->defcls); + print_uint(PRINT_ANY, "direct_packets_stat", + " direct_packets_stat %u", gopt->direct_pkts); + if (show_details) { + sprintf(b1, "%d.%d", gopt->version >> 16, gopt->version & 0xffff); + print_string(PRINT_ANY, "ver", " ver %s", b1); + } } if (tb[TCA_HTB_DIRECT_QLEN] && RTA_PAYLOAD(tb[TCA_HTB_DIRECT_QLEN]) >= sizeof(__u32)) { __u32 direct_qlen = rta_getattr_u32(tb[TCA_HTB_DIRECT_QLEN]); - fprintf(f, " direct_qlen %u", direct_qlen); + print_uint(PRINT_ANY, "direct_qlen", " direct_qlen %u", + direct_qlen); } return 0; } From 249284ff5a44a646523df72201eaf341d7c5dbdd Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 25 Nov 2017 15:48:29 +0100 Subject: [PATCH 22/36] tc: jsonify filter core Add json output to filter core. Signed-off-by: Jiri Pirko --- tc/tc_filter.c | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/tc/tc_filter.c b/tc/tc_filter.c index 73f17816..545cc3a1 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -236,33 +236,36 @@ int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) return -1; } + open_json_object(NULL); + if (n->nlmsg_type == RTM_DELTFILTER) - fprintf(fp, "deleted "); + print_bool(PRINT_ANY, "deleted", "deleted ", true); if (n->nlmsg_type == RTM_NEWTFILTER && (n->nlmsg_flags & NLM_F_CREATE) && !(n->nlmsg_flags & NLM_F_EXCL)) - fprintf(fp, "replaced "); + print_bool(PRINT_ANY, "replaced", "replaced ", true); if (n->nlmsg_type == RTM_NEWTFILTER && (n->nlmsg_flags & NLM_F_CREATE) && (n->nlmsg_flags & NLM_F_EXCL)) - fprintf(fp, "added "); + print_bool(PRINT_ANY, "added", "added ", true); - fprintf(fp, "filter "); + print_string(PRINT_FP, NULL, "filter ", NULL); if (!filter_ifindex || filter_ifindex != t->tcm_ifindex) - fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex)); + print_string(PRINT_ANY, "dev", "dev %s ", + ll_index_to_name(t->tcm_ifindex)); if (!filter_parent || filter_parent != t->tcm_parent) { if (t->tcm_parent == TC_H_ROOT) - fprintf(fp, "root "); + print_bool(PRINT_ANY, "root", "root ", true); else if (t->tcm_parent == TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS)) - fprintf(fp, "ingress "); + print_bool(PRINT_ANY, "ingress", "ingress ", true); else if (t->tcm_parent == TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS)) - fprintf(fp, "egress "); + print_bool(PRINT_ANY, "egress", "egress ", true); else { print_tc_classid(abuf, sizeof(abuf), t->tcm_parent); - fprintf(fp, "parent %s ", abuf); + print_string(PRINT_ANY, "parent", "parent %s ", abuf); } } @@ -273,39 +276,45 @@ int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (!filter_protocol || filter_protocol != f_proto) { if (f_proto) { SPRINT_BUF(b1); - fprintf(fp, "protocol %s ", - ll_proto_n2a(f_proto, b1, sizeof(b1))); + print_string(PRINT_JSON, "protocol", + "protocol %s ", + ll_proto_n2a(f_proto, b1, sizeof(b1))); } } if (!filter_prio || filter_prio != prio) { if (prio) - fprintf(fp, "pref %u ", prio); + print_uint(PRINT_ANY, "pref", "pref %u ", prio); } } - fprintf(fp, "%s ", rta_getattr_str(tb[TCA_KIND])); + print_string(PRINT_ANY, "kind", "%s ", rta_getattr_str(tb[TCA_KIND])); if (tb[TCA_CHAIN]) { __u32 chain_index = rta_getattr_u32(tb[TCA_CHAIN]); if (!filter_chain_index_set || filter_chain_index != chain_index) - fprintf(fp, "chain %u ", chain_index); + print_uint(PRINT_ANY, "chain", "chain %u ", + chain_index); } q = get_filter_kind(RTA_DATA(tb[TCA_KIND])); if (tb[TCA_OPTIONS]) { + open_json_object("options"); if (q) q->print_fopt(q, fp, tb[TCA_OPTIONS], t->tcm_handle); else - fprintf(fp, "[cannot parse parameters]"); + print_string(PRINT_FP, NULL, + "[cannot parse parameters]", NULL); + close_json_object(); } - fprintf(fp, "\n"); + print_string(PRINT_FP, NULL, "\n", NULL); if (show_stats && (tb[TCA_STATS] || tb[TCA_STATS2])) { print_tcstats_attr(fp, tb, " ", NULL); - fprintf(fp, "\n"); + print_string(PRINT_FP, NULL, "\n", NULL); } + close_json_object(); fflush(fp); return 0; } @@ -487,7 +496,9 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv) return 2; } + new_json_obj(json); print_filter(NULL, answer, (void *)stdout); + delete_json_obj(); free(answer); return 0; @@ -615,10 +626,12 @@ static int tc_filter_list(int argc, char **argv) return 1; } + new_json_obj(json); if (rtnl_dump_filter(&rth, print_filter, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); return 1; } + delete_json_obj(); return 0; } From e28b88a464c49bb6c92333b2dc6dcc5a922d4e7c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 25 Nov 2017 15:48:30 +0100 Subject: [PATCH 23/36] tc: jsonify flower filter Add json output to flower filter. Signed-off-by: Jiri Pirko --- tc/f_flower.c | 287 +++++++++++++++++++++++++++++--------------------- 1 file changed, 169 insertions(+), 118 deletions(-) diff --git a/tc/f_flower.c b/tc/f_flower.c index 9cad6c85..5a4ec832 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -1037,89 +1037,105 @@ static int __mask_bits(char *addr, size_t len) return bits; } -static void flower_print_eth_addr(FILE *f, char *name, - struct rtattr *addr_attr, +static void flower_print_eth_addr(char *name, struct rtattr *addr_attr, struct rtattr *mask_attr) { + SPRINT_BUF(namefrm); + SPRINT_BUF(out); SPRINT_BUF(b1); + size_t done; int bits; if (!addr_attr || RTA_PAYLOAD(addr_attr) != ETH_ALEN) return; - fprintf(f, "\n %s %s", name, ll_addr_n2a(RTA_DATA(addr_attr), ETH_ALEN, - 0, b1, sizeof(b1))); - if (!mask_attr || RTA_PAYLOAD(mask_attr) != ETH_ALEN) - return; - bits = __mask_bits(RTA_DATA(mask_attr), ETH_ALEN); - if (bits < 0) - fprintf(f, "/%s", ll_addr_n2a(RTA_DATA(mask_attr), ETH_ALEN, - 0, b1, sizeof(b1))); - else if (bits < ETH_ALEN * 8) - fprintf(f, "/%d", bits); + done = sprintf(out, "%s", + ll_addr_n2a(RTA_DATA(addr_attr), ETH_ALEN, + 0, b1, sizeof(b1))); + if (mask_attr && RTA_PAYLOAD(mask_attr) == ETH_ALEN) { + bits = __mask_bits(RTA_DATA(mask_attr), ETH_ALEN); + if (bits < 0) + sprintf(out + done, "/%s", + ll_addr_n2a(RTA_DATA(mask_attr), ETH_ALEN, + 0, b1, sizeof(b1))); + else if (bits < ETH_ALEN * 8) + sprintf(out + done, "/%d", bits); + } + + sprintf(namefrm, "\n %s %%s", name); + print_string(PRINT_ANY, name, namefrm, out); } -static void flower_print_eth_type(FILE *f, __be16 *p_eth_type, +static void flower_print_eth_type(__be16 *p_eth_type, struct rtattr *eth_type_attr) { + SPRINT_BUF(out); __be16 eth_type; if (!eth_type_attr) return; eth_type = rta_getattr_u16(eth_type_attr); - fprintf(f, "\n eth_type "); if (eth_type == htons(ETH_P_IP)) - fprintf(f, "ipv4"); + sprintf(out, "ipv4"); else if (eth_type == htons(ETH_P_IPV6)) - fprintf(f, "ipv6"); + sprintf(out, "ipv6"); else if (eth_type == htons(ETH_P_ARP)) - fprintf(f, "arp"); + sprintf(out, "arp"); else if (eth_type == htons(ETH_P_RARP)) - fprintf(f, "rarp"); + sprintf(out, "rarp"); else - fprintf(f, "%04x", ntohs(eth_type)); + sprintf(out, "%04x", ntohs(eth_type)); + + print_string(PRINT_ANY, "eth_type", "\n eth_type %s", out); *p_eth_type = eth_type; } -static void flower_print_ip_proto(FILE *f, __u8 *p_ip_proto, +static void flower_print_ip_proto(__u8 *p_ip_proto, struct rtattr *ip_proto_attr) { + SPRINT_BUF(out); __u8 ip_proto; if (!ip_proto_attr) return; ip_proto = rta_getattr_u8(ip_proto_attr); - fprintf(f, "\n ip_proto "); if (ip_proto == IPPROTO_TCP) - fprintf(f, "tcp"); + sprintf(out, "tcp"); else if (ip_proto == IPPROTO_UDP) - fprintf(f, "udp"); + sprintf(out, "udp"); else if (ip_proto == IPPROTO_SCTP) - fprintf(f, "sctp"); + sprintf(out, "sctp"); else if (ip_proto == IPPROTO_ICMP) - fprintf(f, "icmp"); + sprintf(out, "icmp"); else if (ip_proto == IPPROTO_ICMPV6) - fprintf(f, "icmpv6"); + sprintf(out, "icmpv6"); else - fprintf(f, "%02x", ip_proto); + sprintf(out, "%02x", ip_proto); + + print_string(PRINT_ANY, "ip_proto", "\n ip_proto %s", out); *p_ip_proto = ip_proto; } -static void flower_print_ip_attr(FILE *f, char *name, - struct rtattr *key_attr, +static void flower_print_ip_attr(char *name, struct rtattr *key_attr, struct rtattr *mask_attr) { + SPRINT_BUF(namefrm); + SPRINT_BUF(out); + size_t done; + if (!key_attr) return; - fprintf(f, "\n %s %x", name, rta_getattr_u8(key_attr)); - if (!mask_attr) - return; - fprintf(f, "/%x", rta_getattr_u8(mask_attr)); + done = sprintf(out, "%x", rta_getattr_u8(key_attr)); + if (mask_attr) + sprintf(out + done, "/%x", rta_getattr_u8(mask_attr)); + + sprintf(namefrm, "\n %s %%x", name); + print_string(PRINT_ANY, name, namefrm, out); } -static void flower_print_matching_flags(FILE *f, char *name, +static void flower_print_matching_flags(char *name, enum flower_matching_flags type, struct rtattr *attr, struct rtattr *mask_attr) @@ -1139,20 +1155,28 @@ static void flower_print_matching_flags(FILE *f, char *name, if (type != flags_str[i].type) continue; if (mtf_mask & flags_str[i].flag) { - if (++count == 1) - fprintf(f, "\n %s ", name); - else - fprintf(f, "/"); + if (++count == 1) { + print_string(PRINT_FP, NULL, "\n %s ", name); + open_json_object(name); + } else { + print_string(PRINT_FP, NULL, "/", NULL); + } + print_bool(PRINT_JSON, flags_str[i].string, NULL, + mtf & flags_str[i].flag); if (mtf & flags_str[i].flag) - fprintf(f, "%s", flags_str[i].string); + print_string(PRINT_FP, NULL, "%s", + flags_str[i].string); else - fprintf(f, "no%s", flags_str[i].string); + print_string(PRINT_FP, NULL, "no%s", + flags_str[i].string); } } + if (count) + close_json_object(); } -static void flower_print_ip_addr(FILE *f, char *name, __be16 eth_type, +static void flower_print_ip_addr(char *name, __be16 eth_type, struct rtattr *addr4_attr, struct rtattr *mask4_attr, struct rtattr *addr6_attr, @@ -1160,6 +1184,9 @@ static void flower_print_ip_addr(FILE *f, char *name, __be16 eth_type, { struct rtattr *addr_attr; struct rtattr *mask_attr; + SPRINT_BUF(namefrm); + SPRINT_BUF(out); + size_t done; int family; size_t len; int bits; @@ -1179,56 +1206,75 @@ static void flower_print_ip_addr(FILE *f, char *name, __be16 eth_type, } if (!addr_attr || RTA_PAYLOAD(addr_attr) != len) return; - fprintf(f, "\n %s %s", name, rt_addr_n2a_rta(family, addr_attr)); if (!mask_attr || RTA_PAYLOAD(mask_attr) != len) return; + done = sprintf(out, "%s", rt_addr_n2a_rta(family, addr_attr)); bits = __mask_bits(RTA_DATA(mask_attr), len); if (bits < 0) - fprintf(f, "/%s", rt_addr_n2a_rta(family, mask_attr)); + sprintf(out + done, "/%s", rt_addr_n2a_rta(family, mask_attr)); else if (bits < len * 8) - fprintf(f, "/%d", bits); + sprintf(out + done, "/%d", bits); + + sprintf(namefrm, "\n %s %%s", name); + print_string(PRINT_ANY, name, namefrm, out); } -static void flower_print_ip4_addr(FILE *f, char *name, - struct rtattr *addr_attr, +static void flower_print_ip4_addr(char *name, struct rtattr *addr_attr, struct rtattr *mask_attr) { - return flower_print_ip_addr(f, name, htons(ETH_P_IP), + return flower_print_ip_addr(name, htons(ETH_P_IP), addr_attr, mask_attr, 0, 0); } -static void flower_print_port(FILE *f, char *name, struct rtattr *attr) +static void flower_print_port(char *name, struct rtattr *attr) { - if (attr) - fprintf(f, "\n %s %d", name, rta_getattr_be16(attr)); + SPRINT_BUF(namefrm); + + if (!attr) + return; + + sprintf(namefrm,"\n %s %%u", name); + print_uint(PRINT_ANY, name, namefrm, rta_getattr_be16(attr)); } -static void flower_print_tcp_flags(FILE *f, char *name, - struct rtattr *flags_attr, - struct rtattr *mask_attr) +static void flower_print_tcp_flags(char *name, struct rtattr *flags_attr, + struct rtattr *mask_attr) { + SPRINT_BUF(namefrm); + SPRINT_BUF(out); + size_t done; + if (!flags_attr) return; - fprintf(f, "\n %s %x", name, rta_getattr_be16(flags_attr)); - if (!mask_attr) - return; - fprintf(f, "/%x", rta_getattr_be16(mask_attr)); + + done = sprintf(out, "%x", rta_getattr_be16(flags_attr)); + if (mask_attr) + sprintf(out + done, "%x", rta_getattr_be16(flags_attr)); + + sprintf(namefrm, "\n %s %%s", name); + print_string(PRINT_ANY, name, namefrm, out); } -static void flower_print_key_id(FILE *f, const char *name, - struct rtattr *attr) +static void flower_print_key_id(const char *name, struct rtattr *attr) { - if (attr) - fprintf(f, "\n %s %d", name, rta_getattr_be32(attr)); + SPRINT_BUF(namefrm); + + if (!attr) + return; + + sprintf(namefrm,"\n %s %%u", name); + print_uint(PRINT_ANY, name, namefrm, rta_getattr_be32(attr)); } -static void flower_print_masked_u8(FILE *f, const char *name, - struct rtattr *attr, +static void flower_print_masked_u8(const char *name, struct rtattr *attr, struct rtattr *mask_attr, const char *(*value_to_str)(__u8 value)) { const char *value_str = NULL; __u8 value, mask; + SPRINT_BUF(namefrm); + SPRINT_BUF(out); + size_t done; if (!attr) return; @@ -1238,39 +1284,39 @@ static void flower_print_masked_u8(FILE *f, const char *name, if (mask == UINT8_MAX && value_to_str) value_str = value_to_str(value); - fprintf(f, "\n %s ", name); - if (value_str) - fputs(value_str, f); + done = sprintf(out, "%s", value_str); else - fprintf(f, "%d", value); + done = sprintf(out, "%d", value); if (mask != UINT8_MAX) - fprintf(f, "/%d", mask); + sprintf(out + done, "/%d", mask); + + sprintf(namefrm,"\n %s %%s", name); + print_string(PRINT_ANY, name, namefrm, out); } -static void flower_print_u8(FILE *f, const char *name, struct rtattr *attr) +static void flower_print_u8(const char *name, struct rtattr *attr) { - flower_print_masked_u8(f, name, attr, NULL, NULL); + flower_print_masked_u8(name, attr, NULL, NULL); } -static void flower_print_u32(FILE *f, const char *name, struct rtattr *attr) +static void flower_print_u32(const char *name, struct rtattr *attr) { - __u32 value; + SPRINT_BUF(namefrm); if (!attr) return; - value = rta_getattr_u32(attr); - - fprintf(f, "\n %s %d", name, value); + sprintf(namefrm,"\n %s %%u", name); + print_uint(PRINT_ANY, name, namefrm, rta_getattr_u32(attr)); } -static void flower_print_arp_op(FILE *f, const char *name, +static void flower_print_arp_op(const char *name, struct rtattr *op_attr, struct rtattr *mask_attr) { - flower_print_masked_u8(f, name, op_attr, mask_attr, + flower_print_masked_u8(name, op_attr, mask_attr, flower_print_arp_op_to_name); } @@ -1288,7 +1334,7 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, parse_rtattr_nested(tb, TCA_FLOWER_MAX, opt); if (handle) - fprintf(f, "handle 0x%x ", handle); + print_uint(PRINT_ANY, "handle", "handle 0x%x ", handle); if (tb[TCA_FLOWER_CLASSID]) { __u32 h = rta_getattr_u32(tb[TCA_FLOWER_CLASSID]); @@ -1296,56 +1342,62 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, if (TC_H_MIN(h) < TC_H_MIN_PRIORITY || TC_H_MIN(h) > (TC_H_MIN_PRIORITY + TC_QOPT_MAX_QUEUE - 1)) { SPRINT_BUF(b1); - fprintf(f, "classid %s ", sprint_tc_classid(h, b1)); + print_string(PRINT_ANY, "classid", "classid %s ", + sprint_tc_classid(h, b1)); } else { - fprintf(f, "hw_tc %u ", - TC_H_MIN(h) - TC_H_MIN_PRIORITY); + print_uint(PRINT_ANY, "hw_tc", "hw_tc %u ", + TC_H_MIN(h) - TC_H_MIN_PRIORITY); } } if (tb[TCA_FLOWER_INDEV]) { struct rtattr *attr = tb[TCA_FLOWER_INDEV]; - fprintf(f, "\n indev %s", rta_getattr_str(attr)); + print_string(PRINT_ANY, "indev", "\n indev %s", + rta_getattr_str(attr)); } + open_json_object("keys"); + if (tb[TCA_FLOWER_KEY_VLAN_ID]) { struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_ID]; - fprintf(f, "\n vlan_id %d", rta_getattr_u16(attr)); + print_uint(PRINT_ANY, "vlan_id", "\n vlan_id %u", + rta_getattr_u16(attr)); } if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) { struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_PRIO]; - fprintf(f, "\n vlan_prio %d", rta_getattr_u8(attr)); + print_uint(PRINT_ANY, "vlan_prio", "\n vlan_prio %d", + rta_getattr_u8(attr)); } - flower_print_eth_addr(f, "dst_mac", tb[TCA_FLOWER_KEY_ETH_DST], + flower_print_eth_addr("dst_mac", tb[TCA_FLOWER_KEY_ETH_DST], tb[TCA_FLOWER_KEY_ETH_DST_MASK]); - flower_print_eth_addr(f, "src_mac", tb[TCA_FLOWER_KEY_ETH_SRC], + flower_print_eth_addr("src_mac", tb[TCA_FLOWER_KEY_ETH_SRC], tb[TCA_FLOWER_KEY_ETH_SRC_MASK]); - flower_print_eth_type(f, ð_type, tb[TCA_FLOWER_KEY_ETH_TYPE]); - flower_print_ip_proto(f, &ip_proto, tb[TCA_FLOWER_KEY_IP_PROTO]); + flower_print_eth_type(ð_type, tb[TCA_FLOWER_KEY_ETH_TYPE]); + flower_print_ip_proto(&ip_proto, tb[TCA_FLOWER_KEY_IP_PROTO]); - flower_print_ip_attr(f, "ip_tos", tb[TCA_FLOWER_KEY_IP_TOS], + flower_print_ip_attr("ip_tos", tb[TCA_FLOWER_KEY_IP_TOS], tb[TCA_FLOWER_KEY_IP_TOS_MASK]); - flower_print_ip_attr(f, "ip_ttl", tb[TCA_FLOWER_KEY_IP_TTL], + flower_print_ip_attr("ip_ttl", tb[TCA_FLOWER_KEY_IP_TTL], tb[TCA_FLOWER_KEY_IP_TTL_MASK]); - flower_print_u32(f, "mpls_label", tb[TCA_FLOWER_KEY_MPLS_LABEL]); - flower_print_u8(f, "mpls_tc", tb[TCA_FLOWER_KEY_MPLS_TC]); - flower_print_u8(f, "mpls_bos", tb[TCA_FLOWER_KEY_MPLS_BOS]); - flower_print_u8(f, "mpls_ttl", tb[TCA_FLOWER_KEY_MPLS_TTL]); + flower_print_u32("mpls_label", tb[TCA_FLOWER_KEY_MPLS_LABEL]); + flower_print_u8("mpls_tc", tb[TCA_FLOWER_KEY_MPLS_TC]); + flower_print_u8("mpls_bos", tb[TCA_FLOWER_KEY_MPLS_BOS]); + flower_print_u8("mpls_ttl", tb[TCA_FLOWER_KEY_MPLS_TTL]); - flower_print_ip_addr(f, "dst_ip", eth_type, + flower_print_ip_addr("dst_ip", eth_type, tb[TCA_FLOWER_KEY_IPV4_DST], tb[TCA_FLOWER_KEY_IPV4_DST_MASK], tb[TCA_FLOWER_KEY_IPV6_DST], tb[TCA_FLOWER_KEY_IPV6_DST_MASK]); - flower_print_ip_addr(f, "src_ip", eth_type, + flower_print_ip_addr("src_ip", eth_type, tb[TCA_FLOWER_KEY_IPV4_SRC], tb[TCA_FLOWER_KEY_IPV4_SRC_MASK], tb[TCA_FLOWER_KEY_IPV6_SRC], @@ -1353,12 +1405,12 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_DST); if (nl_type >= 0) - flower_print_port(f, "dst_port", tb[nl_type]); + flower_print_port("dst_port", tb[nl_type]); nl_type = flower_port_attr_type(ip_proto, FLOWER_ENDPOINT_SRC); if (nl_type >= 0) - flower_print_port(f, "src_port", tb[nl_type]); + flower_print_port("src_port", tb[nl_type]); - flower_print_tcp_flags(f, "tcp_flags", tb[TCA_FLOWER_KEY_TCP_FLAGS], + flower_print_tcp_flags("tcp_flags", tb[TCA_FLOWER_KEY_TCP_FLAGS], tb[TCA_FLOWER_KEY_TCP_FLAGS_MASK]); nl_type = flower_icmp_attr_type(eth_type, ip_proto, @@ -1366,7 +1418,7 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, nl_mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto, FLOWER_ICMP_FIELD_TYPE); if (nl_type >= 0 && nl_mask_type >= 0) - flower_print_masked_u8(f, "icmp_type", tb[nl_type], + flower_print_masked_u8("icmp_type", tb[nl_type], tb[nl_mask_type], NULL); nl_type = flower_icmp_attr_type(eth_type, ip_proto, @@ -1374,21 +1426,21 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, nl_mask_type = flower_icmp_attr_mask_type(eth_type, ip_proto, FLOWER_ICMP_FIELD_CODE); if (nl_type >= 0 && nl_mask_type >= 0) - flower_print_masked_u8(f, "icmp_code", tb[nl_type], + flower_print_masked_u8("icmp_code", tb[nl_type], tb[nl_mask_type], NULL); - flower_print_ip4_addr(f, "arp_sip", tb[TCA_FLOWER_KEY_ARP_SIP], + flower_print_ip4_addr("arp_sip", tb[TCA_FLOWER_KEY_ARP_SIP], tb[TCA_FLOWER_KEY_ARP_SIP_MASK]); - flower_print_ip4_addr(f, "arp_tip", tb[TCA_FLOWER_KEY_ARP_TIP], + flower_print_ip4_addr("arp_tip", tb[TCA_FLOWER_KEY_ARP_TIP], tb[TCA_FLOWER_KEY_ARP_TIP_MASK]); - flower_print_arp_op(f, "arp_op", tb[TCA_FLOWER_KEY_ARP_OP], + flower_print_arp_op("arp_op", tb[TCA_FLOWER_KEY_ARP_OP], tb[TCA_FLOWER_KEY_ARP_OP_MASK]); - flower_print_eth_addr(f, "arp_sha", tb[TCA_FLOWER_KEY_ARP_SHA], + flower_print_eth_addr("arp_sha", tb[TCA_FLOWER_KEY_ARP_SHA], tb[TCA_FLOWER_KEY_ARP_SHA_MASK]); - flower_print_eth_addr(f, "arp_tha", tb[TCA_FLOWER_KEY_ARP_THA], + flower_print_eth_addr("arp_tha", tb[TCA_FLOWER_KEY_ARP_THA], tb[TCA_FLOWER_KEY_ARP_THA_MASK]); - flower_print_ip_addr(f, "enc_dst_ip", + flower_print_ip_addr("enc_dst_ip", tb[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK] ? htons(ETH_P_IP) : htons(ETH_P_IPV6), tb[TCA_FLOWER_KEY_ENC_IPV4_DST], @@ -1396,7 +1448,7 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, tb[TCA_FLOWER_KEY_ENC_IPV6_DST], tb[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]); - flower_print_ip_addr(f, "enc_src_ip", + flower_print_ip_addr("enc_src_ip", tb[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK] ? htons(ETH_P_IP) : htons(ETH_P_IPV6), tb[TCA_FLOWER_KEY_ENC_IPV4_SRC], @@ -1404,29 +1456,28 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, tb[TCA_FLOWER_KEY_ENC_IPV6_SRC], tb[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]); - flower_print_key_id(f, "enc_key_id", - tb[TCA_FLOWER_KEY_ENC_KEY_ID]); + flower_print_key_id("enc_key_id", tb[TCA_FLOWER_KEY_ENC_KEY_ID]); - flower_print_port(f, "enc_dst_port", - tb[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]); + flower_print_port("enc_dst_port", tb[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]); - flower_print_matching_flags(f, "ip_flags", - FLOWER_IP_FLAGS, + flower_print_matching_flags("ip_flags", FLOWER_IP_FLAGS, tb[TCA_FLOWER_KEY_FLAGS], tb[TCA_FLOWER_KEY_FLAGS_MASK]); + close_json_object(); + if (tb[TCA_FLOWER_FLAGS]) { __u32 flags = rta_getattr_u32(tb[TCA_FLOWER_FLAGS]); if (flags & TCA_CLS_FLAGS_SKIP_HW) - fprintf(f, "\n skip_hw"); + print_bool(PRINT_ANY, "skip_hw", "\n skip_hw", true); if (flags & TCA_CLS_FLAGS_SKIP_SW) - fprintf(f, "\n skip_sw"); + print_bool(PRINT_ANY, "skip_sw", "\n skip_sw", true); if (flags & TCA_CLS_FLAGS_IN_HW) - fprintf(f, "\n in_hw"); + print_bool(PRINT_ANY, "in_hw", "\n in_hw", true); else if (flags & TCA_CLS_FLAGS_NOT_IN_HW) - fprintf(f, "\n not_in_hw"); + print_bool(PRINT_ANY, "not_in_hw", "\n not_in_hw", true); } if (tb[TCA_FLOWER_ACT]) From 619ca351e3b7bc619bd53491525d68bfd9f81330 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 25 Nov 2017 15:48:31 +0100 Subject: [PATCH 24/36] tc: jsonify matchall filter Add json output to matchall filter. Signed-off-by: Jiri Pirko --- tc/f_matchall.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tc/f_matchall.c b/tc/f_matchall.c index 183f2611..5ebd0415 100644 --- a/tc/f_matchall.c +++ b/tc/f_matchall.c @@ -121,11 +121,11 @@ static int matchall_print_opt(struct filter_util *qu, FILE *f, parse_rtattr_nested(tb, TCA_MATCHALL_MAX, opt); if (handle) - fprintf(f, "handle 0x%x ", handle); + print_uint(PRINT_ANY, "handle", "handle 0x%x ", handle); if (tb[TCA_MATCHALL_CLASSID]) { SPRINT_BUF(b1); - fprintf(f, "flowid %s ", + print_string(PRINT_ANY, "flowid", "flowid %s ", sprint_tc_classid(rta_getattr_u32(tb[TCA_MATCHALL_CLASSID]), b1)); } @@ -133,14 +133,14 @@ static int matchall_print_opt(struct filter_util *qu, FILE *f, __u32 flags = rta_getattr_u32(tb[TCA_MATCHALL_FLAGS]); if (flags & TCA_CLS_FLAGS_SKIP_HW) - fprintf(f, "\n skip_hw"); + print_bool(PRINT_ANY, "skip_hw", "\n skip_hw", true); if (flags & TCA_CLS_FLAGS_SKIP_SW) - fprintf(f, "\n skip_sw"); + print_bool(PRINT_ANY, "skip_sw", "\n skip_sw", true); if (flags & TCA_CLS_FLAGS_IN_HW) - fprintf(f, "\n in_hw"); + print_bool(PRINT_ANY, "in_hw", "\n in_hw", true); else if (flags & TCA_CLS_FLAGS_NOT_IN_HW) - fprintf(f, "\n not_in_hw"); + print_bool(PRINT_ANY, "not_in_hw", "\n not_in_hw", true); } if (tb[TCA_MATCHALL_ACT]) From 2704bd62558391c00bc1c3e7f8706de8332d8ba0 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 25 Nov 2017 15:48:32 +0100 Subject: [PATCH 25/36] tc: jsonify actions core Add json output to actions core. Signed-off-by: Jiri Pirko --- tc/m_action.c | 22 +++++++++++++++------- tc/tc_util.c | 34 ++++++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/tc/m_action.c b/tc/m_action.c index e6d91498..0940a393 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -301,17 +301,19 @@ static int tc_print_one_action(FILE *f, struct rtattr *arg) return err; if (show_stats && tb[TCA_ACT_STATS]) { - fprintf(f, "\tAction statistics:\n"); + print_string(PRINT_FP, NULL, "\tAction statistics:\n", NULL); + open_json_object("stats"); print_tcstats2_attr(f, tb[TCA_ACT_STATS], "\t", NULL); - fprintf(f, "\n"); + close_json_object(); + print_string(PRINT_FP, NULL, "\n", NULL); } if (tb[TCA_ACT_COOKIE]) { int strsz = RTA_PAYLOAD(tb[TCA_ACT_COOKIE]); char b1[strsz * 2 + 1]; - fprintf(f, "\tcookie %s\n", - hexstring_n2a(RTA_DATA(tb[TCA_ACT_COOKIE]), - strsz, b1, sizeof(b1))); + print_string(PRINT_ANY, "cookie", "\tcookie %s\n", + hexstring_n2a(RTA_DATA(tb[TCA_ACT_COOKIE]), + strsz, b1, sizeof(b1))); } return 0; @@ -362,15 +364,21 @@ tc_print_action(FILE *f, const struct rtattr *arg, unsigned short tot_acts) if (tab_flush && NULL != tb[0] && NULL == tb[1]) return tc_print_action_flush(f, tb[0]); + open_json_array(PRINT_JSON, "actions"); for (i = 0; i < tot_acts; i++) { if (tb[i]) { - fprintf(f, "\n\taction order %d: ", i); + open_json_object(NULL); + print_uint(PRINT_ANY, "order", + "\n\taction order %u: ", i); if (tc_print_one_action(f, tb[i]) < 0) { - fprintf(f, "Error printing action\n"); + print_string(PRINT_FP, NULL, + "Error printing action\n", NULL); } + close_json_object(); } } + close_json_object(); return 0; } diff --git a/tc/tc_util.c b/tc/tc_util.c index d2769879..18879056 100644 --- a/tc/tc_util.c +++ b/tc/tc_util.c @@ -709,12 +709,17 @@ int parse_action_control_slash(int *argc_p, char ***argv_p, void print_action_control(FILE *f, const char *prefix, int action, const char *suffix) { - fprintf(f, "%s%s", prefix, action_n2a(action)); + print_string(PRINT_FP, NULL, "%s", prefix); + open_json_object("control_action"); + print_string(PRINT_ANY, "type", "%s", action_n2a(action)); if (TC_ACT_EXT_CMP(action, TC_ACT_GOTO_CHAIN)) - fprintf(f, " chain %u", action & TC_ACT_EXT_VAL_MASK); + print_uint(PRINT_ANY, "chain", " chain %u", + action & TC_ACT_EXT_VAL_MASK); if (TC_ACT_EXT_CMP(action, TC_ACT_JUMP)) - fprintf(f, " %u", action & TC_ACT_EXT_VAL_MASK); - fprintf(f, "%s", suffix); + print_uint(PRINT_ANY, "jump", " %u", + action & TC_ACT_EXT_VAL_MASK); + close_json_object(); + print_string(PRINT_FP, NULL, "%s", suffix); } int get_linklayer(unsigned int *val, const char *arg) @@ -762,12 +767,21 @@ void print_tm(FILE *f, const struct tcf_t *tm) { int hz = get_user_hz(); - if (tm->install != 0) - fprintf(f, " installed %u sec", (unsigned int)(tm->install/hz)); - if (tm->lastuse != 0) - fprintf(f, " used %u sec", (unsigned int)(tm->lastuse/hz)); - if (tm->expires != 0) - fprintf(f, " expires %u sec", (unsigned int)(tm->expires/hz)); + if (tm->install != 0) { + print_uint(PRINT_JSON, "installed", NULL, tm->install); + print_uint(PRINT_FP, NULL, " installed %u sec", + (unsigned int)(tm->install/hz)); + } + if (tm->lastuse != 0) { + print_uint(PRINT_JSON, "last_used", NULL, tm->lastuse); + print_uint(PRINT_FP, NULL, " used %u sec", + (unsigned int)(tm->lastuse/hz)); + } + if (tm->expires != 0) { + print_uint(PRINT_JSON, "expires", NULL, tm->expires); + print_uint(PRINT_FP, NULL, " expires %u sec", + (unsigned int)(tm->expires/hz)); + } } void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtattr **xstats) From 66fedb6df0b0ccc992a62f564ef164943da5275f Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 25 Nov 2017 15:48:33 +0100 Subject: [PATCH 26/36] tc: jsonify gact action Add json output to gact action. Signed-off-by: Jiri Pirko --- tc/m_gact.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tc/m_gact.c b/tc/m_gact.c index efe992f0..905aa510 100644 --- a/tc/m_gact.c +++ b/tc/m_gact.c @@ -175,12 +175,12 @@ print_gact(struct action_util *au, FILE * f, struct rtattr *arg) parse_rtattr_nested(tb, TCA_GACT_MAX, arg); if (tb[TCA_GACT_PARMS] == NULL) { - fprintf(f, "[NULL gact parameters]"); + print_string(PRINT_FP, NULL, "%s", "[NULL gact parameters]"); return -1; } p = RTA_DATA(tb[TCA_GACT_PARMS]); - fprintf(f, "gact "); + print_string(PRINT_ANY, "kind", "%s ", "gact"); print_action_control(f, "action ", p->action, ""); #ifdef CONFIG_GACT_PROB if (tb[TCA_GACT_PROB] != NULL) { @@ -190,12 +190,16 @@ print_gact(struct action_util *au, FILE * f, struct rtattr *arg) memset(&pp_dummy, 0, sizeof(pp_dummy)); pp = &pp_dummy; } - fprintf(f, "\n\t random type %s", prob_n2a(pp->ptype)); + open_json_object("prob"); + print_string(PRINT_ANY, "random_type", "\n\t random type %s", + prob_n2a(pp->ptype)); print_action_control(f, " ", pp->paction, " "); - fprintf(f, "val %d", pp->pval); + print_int(PRINT_ANY, "val", "val %d", pp->pval); + close_json_object(); #endif - fprintf(f, "\n\t index %u ref %d bind %d", p->index, p->refcnt, - p->bindcnt); + print_uint(PRINT_ANY, "index", "\n\t index %u", p->index); + print_int(PRINT_ANY, "ref", " ref %d", p->refcnt); + print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt); if (show_stats) { if (tb[TCA_GACT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_GACT_TM]); @@ -203,7 +207,7 @@ print_gact(struct action_util *au, FILE * f, struct rtattr *arg) print_tm(f, tm); } } - fprintf(f, "\n "); + print_string(PRINT_FP, NULL, "%s", "\n"); return 0; } From 502c4adf19ab86941f76f76170684c46a5b55b5d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 25 Nov 2017 15:48:34 +0100 Subject: [PATCH 27/36] tc: jsonify mirred action Add json output to mirred action. Signed-off-by: Jiri Pirko --- tc/m_mirred.c | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/tc/m_mirred.c b/tc/m_mirred.c index 33c915d6..c771632c 100644 --- a/tc/m_mirred.c +++ b/tc/m_mirred.c @@ -60,6 +60,34 @@ static const char *mirred_n2a(int action) } } +static const char *mirred_direction(int action) +{ + switch (action) { + case TCA_EGRESS_REDIR: + case TCA_EGRESS_MIRROR: + return "egress"; + case TCA_INGRESS_REDIR: + case TCA_INGRESS_MIRROR: + return "ingress"; + default: + return "unknown"; + } +} + +static const char *mirred_action(int action) +{ + switch (action) { + case TCA_EGRESS_REDIR: + case TCA_INGRESS_REDIR: + return "redirect"; + case TCA_EGRESS_MIRROR: + case TCA_INGRESS_MIRROR: + return "mirror"; + default: + return "unknown"; + } +} + static int parse_direction(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) @@ -254,7 +282,7 @@ print_mirred(struct action_util *au, FILE * f, struct rtattr *arg) parse_rtattr_nested(tb, TCA_MIRRED_MAX, arg); if (tb[TCA_MIRRED_PARMS] == NULL) { - fprintf(f, "[NULL mirred parameters]"); + print_string(PRINT_FP, NULL, "%s", "[NULL mirred parameters]"); return -1; } p = RTA_DATA(tb[TCA_MIRRED_PARMS]); @@ -269,12 +297,18 @@ print_mirred(struct action_util *au, FILE * f, struct rtattr *arg) return -1; } - fprintf(f, "mirred (%s to device %s)", mirred_n2a(p->eaction), dev); + print_string(PRINT_ANY, "kind", "%s ", "mirred"); + print_string(PRINT_FP, NULL, "(%s", mirred_n2a(p->eaction)); + print_string(PRINT_JSON, "mirred_action", NULL, + mirred_action(p->eaction)); + print_string(PRINT_JSON, "direction", NULL, + mirred_direction(p->eaction)); + print_string(PRINT_ANY, "to_dev", " to device %s)", dev); print_action_control(f, " ", p->action, ""); - fprintf(f, "\n "); - fprintf(f, "\tindex %u ref %d bind %d", p->index, p->refcnt, - p->bindcnt); + print_uint(PRINT_ANY, "index", "\n \tindex %u", p->index); + print_int(PRINT_ANY, "ref", " ref %d", p->refcnt); + print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt); if (show_stats) { if (tb[TCA_MIRRED_TM]) { @@ -283,7 +317,7 @@ print_mirred(struct action_util *au, FILE * f, struct rtattr *arg) print_tm(f, tm); } } - fprintf(f, "\n "); + print_string(PRINT_FP, NULL, "%s", "\n "); return 0; } From b021ee40f6426964940cceb9b118640788bf0b52 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 25 Nov 2017 15:48:35 +0100 Subject: [PATCH 28/36] tc: jsonify vlan action Add json output to vlan action. Signed-off-by: Jiri Pirko --- tc/m_vlan.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/tc/m_vlan.c b/tc/m_vlan.c index cccb4996..44254b65 100644 --- a/tc/m_vlan.c +++ b/tc/m_vlan.c @@ -195,39 +195,37 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) parse_rtattr_nested(tb, TCA_VLAN_MAX, arg); if (!tb[TCA_VLAN_PARMS]) { - fprintf(f, "[NULL vlan parameters]"); + print_string(PRINT_FP, NULL, "%s", "[NULL vlan parameters]"); return -1; } parm = RTA_DATA(tb[TCA_VLAN_PARMS]); - fprintf(f, " vlan"); + print_string(PRINT_ANY, "kind", "%s ", "vlan"); + print_string(PRINT_ANY, "vlan_action", " %s", action_names[parm->v_action]); switch (parm->v_action) { - case TCA_VLAN_ACT_POP: - fprintf(f, " pop"); - break; case TCA_VLAN_ACT_PUSH: case TCA_VLAN_ACT_MODIFY: - fprintf(f, " %s", action_names[parm->v_action]); if (tb[TCA_VLAN_PUSH_VLAN_ID]) { val = rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_ID]); - fprintf(f, " id %u", val); + print_uint(PRINT_ANY, "id", " id %u", val); } if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) { - fprintf(f, " protocol %s", - ll_proto_n2a(rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]), - b1, sizeof(b1))); + print_string(PRINT_ANY, "protocol", " protocol %s", + ll_proto_n2a(rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]), + b1, sizeof(b1))); } if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY]) { val = rta_getattr_u8(tb[TCA_VLAN_PUSH_VLAN_PRIORITY]); - fprintf(f, " priority %u", val); + print_uint(PRINT_ANY, "priority", " priority %u", val); } break; } print_action_control(f, " ", parm->action, ""); - fprintf(f, "\n\t index %u ref %d bind %d", parm->index, parm->refcnt, - parm->bindcnt); + print_uint(PRINT_ANY, "index", "\n\t index %u", parm->index); + print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt); + print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt); if (show_stats) { if (tb[TCA_VLAN_TM]) { @@ -237,7 +235,7 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) } } - fprintf(f, "\n "); + print_string(PRINT_FP, NULL, "%s", "\n"); return 0; } From eb4bccf12bfe4f4e4cc240b731b7137ee4f24033 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 26 Nov 2017 12:28:55 -0800 Subject: [PATCH 29/36] m_vlan: style cleanups Break long lines and make duplicated code into function. Signed-off-by: Stephen Hemminger --- tc/m_vlan.c | 71 +++++++++++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/tc/m_vlan.c b/tc/m_vlan.c index 44254b65..161759fd 100644 --- a/tc/m_vlan.c +++ b/tc/m_vlan.c @@ -27,13 +27,14 @@ static const char * const action_names[] = { static void explain(void) { - fprintf(stderr, "Usage: vlan pop\n"); - fprintf(stderr, " vlan push [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n"); - fprintf(stderr, " vlan modify [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n"); - fprintf(stderr, " VLANPROTO is one of 802.1Q or 802.1AD\n"); - fprintf(stderr, " with default: 802.1Q\n"); - fprintf(stderr, " CONTROL := reclassify | pipe | drop | continue | pass |\n"); - fprintf(stderr, " goto chain \n"); + fprintf(stderr, + "Usage: vlan pop\n" + " vlan push [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n" + " vlan modify [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n" + " VLANPROTO is one of 802.1Q or 802.1AD\n" + " with default: 802.1Q\n" + " CONTROL := reclassify | pipe | drop | continue | pass |\n" + " goto chain \n"); } static void usage(void) @@ -47,6 +48,14 @@ static bool has_push_attribs(int action) return action == TCA_VLAN_ACT_PUSH || action == TCA_VLAN_ACT_MODIFY; } +static void unexpected(const char *arg) +{ + fprintf(stderr, + "unexpected \"%s\" - action already specified\n", + arg); + explain(); +} + static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { @@ -70,57 +79,42 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, while (argc > 0) { if (matches(*argv, "pop") == 0) { if (action) { - fprintf(stderr, "unexpected \"%s\" - action already specified\n", - *argv); - explain(); + unexpected(*argv); return -1; } action = TCA_VLAN_ACT_POP; } else if (matches(*argv, "push") == 0) { if (action) { - fprintf(stderr, "unexpected \"%s\" - action already specified\n", - *argv); - explain(); + unexpected(*argv); return -1; } action = TCA_VLAN_ACT_PUSH; } else if (matches(*argv, "modify") == 0) { if (action) { - fprintf(stderr, "unexpected \"%s\" - action already specified\n", - *argv); - explain(); + unexpected(*argv); return -1; } action = TCA_VLAN_ACT_MODIFY; } else if (matches(*argv, "id") == 0) { - if (!has_push_attribs(action)) { - fprintf(stderr, "\"%s\" is only valid for push/modify\n", - *argv); - explain(); - return -1; - } + if (!has_push_attribs(action)) + invarg("only valid for push/modify", *argv); + NEXT_ARG(); if (get_u16(&id, *argv, 0)) invarg("id is invalid", *argv); id_set = 1; } else if (matches(*argv, "protocol") == 0) { - if (!has_push_attribs(action)) { - fprintf(stderr, "\"%s\" is only valid for push/modify\n", - *argv); - explain(); - return -1; - } + if (!has_push_attribs(action)) + invarg("only valid for push/modify", *argv); + NEXT_ARG(); if (ll_proto_a2n(&proto, *argv)) invarg("protocol is invalid", *argv); proto_set = 1; } else if (matches(*argv, "priority") == 0) { - if (!has_push_attribs(action)) { - fprintf(stderr, "\"%s\" is only valid for push/modify\n", - *argv); - explain(); - return -1; - } + if (!has_push_attribs(action)) + invarg("only valid for push/modify", *argv); + NEXT_ARG(); if (get_u8(&prio, *argv, 0) || (prio & ~0x7)) invarg("prio is invalid", *argv); @@ -201,7 +195,8 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) parm = RTA_DATA(tb[TCA_VLAN_PARMS]); print_string(PRINT_ANY, "kind", "%s ", "vlan"); - print_string(PRINT_ANY, "vlan_action", " %s", action_names[parm->v_action]); + print_string(PRINT_ANY, "vlan_action", " %s", + action_names[parm->v_action]); switch (parm->v_action) { case TCA_VLAN_ACT_PUSH: @@ -211,9 +206,11 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) print_uint(PRINT_ANY, "id", " id %u", val); } if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) { + __u16 proto; + + proto = rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]); print_string(PRINT_ANY, "protocol", " protocol %s", - ll_proto_n2a(rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]), - b1, sizeof(b1))); + ll_proto_n2a(proto, b1, sizeof(b1))); } if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY]) { val = rta_getattr_u8(tb[TCA_VLAN_PUSH_VLAN_PRIORITY]); From ed4856919f05f6aa79bd55b88beef46437bb7643 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 26 Nov 2017 12:36:15 -0800 Subject: [PATCH 30/36] m_action: style cleanup Break long lines, and use bool where possible. Signed-off-by: Stephen Hemminger --- tc/m_action.c | 77 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/tc/m_action.c b/tc/m_action.c index 0940a393..13f942bf 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -11,10 +11,11 @@ * TODO: * - parse to be passed a filedescriptor for logging purposes * -*/ + */ #include #include +#include #include #include #include @@ -41,7 +42,7 @@ static void act_usage(void) * with any action .so from the old days. But if someone really * does that, they would know how to fix this .. * - */ + */ fprintf(stderr, "usage: tc actions *\n"); fprintf(stderr, "Where: \tACTSPECOP := ACR | GD | FL\n" @@ -68,16 +69,19 @@ static int print_noaopt(struct action_util *au, FILE *f, struct rtattr *opt) return 0; } -static int parse_noaopt(struct action_util *au, int *argc_p, char ***argv_p, int code, struct nlmsghdr *n) +static int parse_noaopt(struct action_util *au, int *argc_p, + char ***argv_p, int code, struct nlmsghdr *n) { int argc = *argc_p; char **argv = *argv_p; - if (argc) { - fprintf(stderr, "Unknown action \"%s\", hence option \"%s\" is unparsable\n", au->id, *argv); - } else { + if (argc) + fprintf(stderr, + "Unknown action \"%s\", hence option \"%s\" is unparsable\n", + au->id, *argv); + else fprintf(stderr, "Unknown action \"%s\"\n", au->id); - } + return -1; } @@ -135,18 +139,14 @@ noexist: return a; } -static int +static bool new_cmd(char **argv) { - if ((matches(*argv, "change") == 0) || + return (matches(*argv, "change") == 0) || (matches(*argv, "replace") == 0) || (matches(*argv, "delete") == 0) || (matches(*argv, "get") == 0) || - (matches(*argv, "add") == 0)) - return 1; - - return 0; - + (matches(*argv, "add") == 0); } int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) @@ -179,9 +179,8 @@ int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) argv++; eap = 1; #ifdef CONFIG_GACT - if (!gact_ld) { + if (!gact_ld) get_action_kind("gact"); - } #endif continue; } else if (strcmp(*argv, "flowid") == 0) { @@ -207,9 +206,9 @@ done0: goto done; } - if (a == NULL) { + if (a == NULL) goto bad_val; - } + tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, ++prio, NULL, 0); @@ -268,7 +267,8 @@ done: return 0; bad_val: /* no need to undo things, returning from here should - * cause enough pain */ + * cause enough pain + */ fprintf(stderr, "parse_action: bad value (%d:%s)!\n", argc, *argv); return -1; } @@ -436,7 +436,8 @@ int print_action(const struct sockaddr_nl *who, return 0; } -static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p) +static int tc_action_gd(int cmd, unsigned int flags, + int *argc_p, char ***argv_p) { char k[FILTER_NAMESZ]; struct action_util *a = NULL; @@ -492,7 +493,8 @@ static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p argc -= 1; argv += 1; if (argc <= 0) { - fprintf(stderr, "Error: no index specified action: %s\n", k); + fprintf(stderr, + "Error: no index specified action: %s\n", k); ret = -1; goto bad_val; } @@ -507,7 +509,8 @@ static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p argc -= 1; argv += 1; } else { - fprintf(stderr, "Error: no index specified action: %s\n", k); + fprintf(stderr, + "Error: no index specified action: %s\n", k); ret = -1; goto bad_val; } @@ -543,7 +546,8 @@ bad_val: return ret; } -static int tc_action_modify(int cmd, unsigned int flags, int *argc_p, char ***argv_p) +static int tc_action_modify(int cmd, unsigned int flags, + int *argc_p, char ***argv_p) { int argc = *argc_p; char **argv = *argv_p; @@ -604,9 +608,9 @@ static int tc_act_list_or_flush(int *argc_p, char ***argv_p, int event) strncpy(k, *argv, sizeof(k) - 1); #ifdef CONFIG_GACT - if (!gact_ld) { + if (!gact_ld) get_action_kind("gact"); - } + #endif a = get_action_kind(k); if (a == NULL) { @@ -644,10 +648,12 @@ static int tc_act_list_or_flush(int *argc_p, char ***argv_p, int event) addattr32(&req.n, MAX_MSG, TCA_ROOT_TIME_DELTA, msec_since); tail4->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail4; } - msg_size = NLMSG_ALIGN(req.n.nlmsg_len) - NLMSG_ALIGN(sizeof(struct nlmsghdr)); + msg_size = NLMSG_ALIGN(req.n.nlmsg_len) + - NLMSG_ALIGN(sizeof(struct nlmsghdr)); if (event == RTM_GETACTION) { - if (rtnl_dump_request(&rth, event, (void *)&req.t, msg_size) < 0) { + if (rtnl_dump_request(&rth, event, + (void *)&req.t, msg_size) < 0) { perror("Cannot send dump request"); return 1; } @@ -681,10 +687,14 @@ int do_action(int argc, char **argv) while (argc > 0) { if (matches(*argv, "add") == 0) { - ret = tc_action_modify(RTM_NEWACTION, NLM_F_EXCL|NLM_F_CREATE, &argc, &argv); + ret = tc_action_modify(RTM_NEWACTION, + NLM_F_EXCL | NLM_F_CREATE, + &argc, &argv); } else if (matches(*argv, "change") == 0 || matches(*argv, "replace") == 0) { - ret = tc_action_modify(RTM_NEWACTION, NLM_F_CREATE|NLM_F_REPLACE, &argc, &argv); + ret = tc_action_modify(RTM_NEWACTION, + NLM_F_CREATE | NLM_F_REPLACE, + &argc, &argv); } else if (matches(*argv, "delete") == 0) { argc -= 1; argv += 1; @@ -693,8 +703,9 @@ int do_action(int argc, char **argv) argc -= 1; argv += 1; ret = tc_action_gd(RTM_GETACTION, 0, &argc, &argv); - } else if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 - || matches(*argv, "lst") == 0) { + } else if (matches(*argv, "list") == 0 || + matches(*argv, "show") == 0 || + matches(*argv, "lst") == 0) { if (argc <= 2) { act_usage(); return -1; @@ -718,7 +729,9 @@ int do_action(int argc, char **argv) act_usage(); return -1; } else { - fprintf(stderr, "Command \"%s\" is unknown, try \"tc actions help\".\n", *argv); + fprintf(stderr, + "Command \"%s\" is unknown, try \"tc actions help\".\n", + *argv); return -1; } From 5c235ac27ece900db0105e28eece8597e2025101 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 26 Nov 2017 12:38:21 -0800 Subject: [PATCH 31/36] m_gact: whitespace cleanup Fix whitespace errors reported by checkpatch Signed-off-by: Stephen Hemminger --- tc/m_gact.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tc/m_gact.c b/tc/m_gact.c index 905aa510..e7d91dab 100644 --- a/tc/m_gact.c +++ b/tc/m_gact.c @@ -115,17 +115,21 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, &pp.paction, false) == -1) usage(); if (get_u16(&pp.pval, *argv, 10)) { - fprintf(stderr, "Illegal probability val 0x%x\n", pp.pval); + fprintf(stderr, + "Illegal probability val 0x%x\n", + pp.pval); return -1; } if (pp.pval > 10000) { - fprintf(stderr, "Illegal probability val 0x%x\n", pp.pval); + fprintf(stderr, + "Illegal probability val 0x%x\n", + pp.pval); return -1; } argc--; argv++; } else if (matches(*argv, "help") == 0) { - usage(); + usage(); } } #endif @@ -140,7 +144,7 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, argc--; argv++; } else if (matches(*argv, "help") == 0) { - usage(); + usage(); } } @@ -148,9 +152,8 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, addattr_l(n, MAX_MSG, tca_id, NULL, 0); addattr_l(n, MAX_MSG, TCA_GACT_PARMS, &p, sizeof(p)); #ifdef CONFIG_GACT_PROB - if (rd) { + if (rd) addattr_l(n, MAX_MSG, TCA_GACT_PROB, &pp, sizeof(pp)); - } #endif tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; @@ -160,7 +163,7 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, } static int -print_gact(struct action_util *au, FILE * f, struct rtattr *arg) +print_gact(struct action_util *au, FILE *f, struct rtattr *arg) { #ifdef CONFIG_GACT_PROB struct tc_gact_p *pp = NULL; From c6a656f4f9eaa563c760d1d2d72e7e044db03113 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 26 Nov 2017 12:42:17 -0800 Subject: [PATCH 32/36] m_mirred: style cleanups Fix whitespace and long lines. Signed-off-by: Stephen Hemminger --- tc/m_mirred.c | 74 ++++++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/tc/m_mirred.c b/tc/m_mirred.c index c771632c..3870d3a4 100644 --- a/tc/m_mirred.c +++ b/tc/m_mirred.c @@ -28,13 +28,13 @@ static void explain(void) { - fprintf(stderr, "Usage: mirred [index INDEX] \n"); - fprintf(stderr, "where:\n"); - fprintf(stderr, "\tDIRECTION := \n"); - fprintf(stderr, "\tACTION := \n"); - fprintf(stderr, "\tINDEX is the specific policy instance id\n"); - fprintf(stderr, "\tDEVICENAME is the devicename\n"); - + fprintf(stderr, + "Usage: mirred [index INDEX] \n" + "where:\n" + "\tDIRECTION := \n" + "\tACTION := \n" + "\tINDEX is the specific policy instance id\n" + "\tDEVICENAME is the devicename\n"); } static void @@ -107,7 +107,8 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p, } else if (!egress && matches(*argv, "egress") == 0) { egress = 1; if (ingress) { - fprintf(stderr, "Can't have both egress and ingress\n"); + fprintf(stderr, + "Can't have both egress and ingress\n"); return -1; } NEXT_ARG(); @@ -116,7 +117,8 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p, } else if (!ingress && matches(*argv, "ingress") == 0) { ingress = 1; if (egress) { - fprintf(stderr, "Can't have both ingress and egress\n"); + fprintf(stderr, + "Can't have both ingress and egress\n"); return -1; } NEXT_ARG(); @@ -137,30 +139,35 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p, break; } } else if (!ok) { - fprintf(stderr, "was expecting egress or ingress (%s)\n", *argv); + fprintf(stderr, + "was expecting egress or ingress (%s)\n", + *argv); break; } else if (!mirror && matches(*argv, "mirror") == 0) { mirror = 1; if (redir) { - fprintf(stderr, "Can't have both mirror and redir\n"); + fprintf(stderr, + "Can't have both mirror and redir\n"); return -1; } p.eaction = egress ? TCA_EGRESS_MIRROR : - TCA_INGRESS_MIRROR; + TCA_INGRESS_MIRROR; p.action = TC_ACT_PIPE; ok++; } else if (!redir && matches(*argv, "redirect") == 0) { redir = 1; if (mirror) { - fprintf(stderr, "Can't have both mirror and redir\n"); + fprintf(stderr, + "Can't have both mirror and redir\n"); return -1; } p.eaction = egress ? TCA_EGRESS_REDIR : - TCA_INGRESS_REDIR; + TCA_INGRESS_REDIR; p.action = TC_ACT_STOLEN; ok++; - } else if ((redir || mirror) && matches(*argv, "dev") == 0) { + } else if ((redir || mirror) && + matches(*argv, "dev") == 0) { NEXT_ARG(); if (strlen(d)) duparg("dev", *argv); @@ -177,18 +184,16 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p, NEXT_ARG(); } - if (!ok && !iok) { + if (!ok && !iok) return -1; - } - - if (d[0]) { int idx; ll_init_map(&rth); - if ((idx = ll_name_to_index(d)) == 0) { + idx = ll_name_to_index(d); + if (idx == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return -1; } @@ -204,16 +209,17 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p, if (iok && matches(*argv, "index") == 0) { fprintf(stderr, "mirred: Illegal double index\n"); return -1; - } else { - if (matches(*argv, "index") == 0) { - NEXT_ARG(); - if (get_u32(&p.index, *argv, 10)) { - fprintf(stderr, "mirred: Illegal \"index\"\n"); - return -1; - } - argc--; - argv++; + } + + if (matches(*argv, "index") == 0) { + NEXT_ARG(); + if (get_u32(&p.index, *argv, 10)) { + fprintf(stderr, + "mirred: Illegal \"index\"\n"); + return -1; } + argc--; + argv++; } } @@ -270,7 +276,7 @@ parse_mirred(struct action_util *a, int *argc_p, char ***argv_p, } static int -print_mirred(struct action_util *au, FILE * f, struct rtattr *arg) +print_mirred(struct action_util *au, FILE *f, struct rtattr *arg) { struct tc_mirred *p; struct rtattr *tb[TCA_MIRRED_MAX + 1]; @@ -287,12 +293,8 @@ print_mirred(struct action_util *au, FILE * f, struct rtattr *arg) } p = RTA_DATA(tb[TCA_MIRRED_PARMS]); - /* - ll_init_map(&rth); - */ - - - if ((dev = ll_index_to_name(p->ifindex)) == 0) { + dev = ll_index_to_name(p->ifindex); + if (dev == 0) { fprintf(stderr, "Cannot find device %d\n", p->ifindex); return -1; } From 56708ae7c9535859223c5b68097b35bf0fae677c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 28 Nov 2017 16:49:58 +0100 Subject: [PATCH 33/36] link_gre6: Detect invalid encaplimit values Looks like a typo: get_u8() returns 0 on success and -1 on error, so the error checking here was ineffective. Fixes: a11b7b71a6eba ("link_gre6: really support encaplimit option") Signed-off-by: Phil Sutter --- ip/link_gre6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/link_gre6.c b/ip/link_gre6.c index 50c1b804..0a82eaec 100644 --- a/ip/link_gre6.c +++ b/ip/link_gre6.c @@ -372,7 +372,7 @@ get_failed: } else { __u8 uval; - if (get_u8(&uval, *argv, 0) < -1) + if (get_u8(&uval, *argv, 0)) invarg("invalid ELIM", *argv); encap_limit = uval; flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT; From 079e67816e5f7e2970ee1caa8f6427214993d31a Mon Sep 17 00:00:00 2001 From: Robert Shearman Date: Tue, 28 Nov 2017 11:16:21 +0000 Subject: [PATCH 34/36] gre: Fix ttl inherit option Specifying "... ttl inherit" currently does nothing on a GRE link modify since the previous ttl value is retrieved up front. Fix this by explicitly setting ttl to 0 when "inherit" is specified for the option, since 0 represents the semantics of inherit. Signed-off-by: Robert Shearman --- ip/link_gre.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ip/link_gre.c b/ip/link_gre.c index 35782caa..43cb1af6 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -276,7 +276,8 @@ get_failed: if (uval > 255) invarg("TTL must be <= 255\n", *argv); ttl = uval; - } + } else + ttl = 0; } else if (!matches(*argv, "tos") || !matches(*argv, "tclass") || !matches(*argv, "dsfield")) { From b6fae7887ff061d092bb11515f99540ada49684e Mon Sep 17 00:00:00 2001 From: Robert Shearman Date: Tue, 28 Nov 2017 11:16:50 +0000 Subject: [PATCH 35/36] vxlan: Make id optional when modifying a link Specifying the IFLA_VXLAN_LINK attribute on a vxlan link modify is optional in the kernel, so make the id argument optional for "ip link set ..." to avoid a user needing to specify it when changing another attribute. Signed-off-by: Robert Shearman --- ip/iplink_vxlan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index a0530dda..661eaa79 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -345,7 +345,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, return -1; } - if (!metadata && !VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID)) { + if (!metadata && !VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID) && !set_op) { fprintf(stderr, "vxlan: missing virtual network identifier\n"); return -1; } @@ -367,7 +367,8 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, "Use 'dstport 0' to get default and quiet this message\n"); } - addattr32(n, 1024, IFLA_VXLAN_ID, vni); + if (VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID)) + addattr32(n, 1024, IFLA_VXLAN_ID, vni); if (gaddr) addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4); else if (daddr) From 615634c30e5b673367b6f31c527b227a37692beb Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 27 Nov 2017 09:09:04 +0100 Subject: [PATCH 36/36] man: add -json option to tc manpage Signed-off-by: Jiri Pirko --- man/man8/tc.8 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/man/man8/tc.8 b/man/man8/tc.8 index 263dc75d..ff071b33 100644 --- a/man/man8/tc.8 +++ b/man/man8/tc.8 @@ -74,7 +74,8 @@ tc \- show / manipulate traffic control settings \fB\-r\fR[\fIaw\fR] | \fB\-p\fR[\fIretty\fR] | \fB\-i\fR[\fIec\fR] | -\fB\-g\fR[\fIraph\fR] } +\fB\-g\fR[\fIraph\fR] | +\fB\-j\fR[\fIjson\fR] } .SH DESCRIPTION .B Tc @@ -661,6 +662,10 @@ option was specified. Classes can be filtered only by .BR "dev" option. +.TP +.BR "\-j", " \-json" +Display results in JSON format. + .TP .BR "\-nm" , " \-name" resolve class name from