From 037660b3513aef53b98c2d0780d3781901986874 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 27 Oct 2015 15:46:20 +0900 Subject: [PATCH 001/513] qfq: fix parse_opt dead code Fix Coverity warning from dead code. --- tc/q_qfq.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/tc/q_qfq.c b/tc/q_qfq.c index 05b4d84e2..0e026749a 100644 --- a/tc/q_qfq.c +++ b/tc/q_qfq.c @@ -38,16 +38,11 @@ static void explain_class(void) static int qfq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - while (argc > 0) { - if (matches(*argv, "help") == 0) { - explain(); - return -1; - } else { + if (argc > 0) { + if (matches(*argv, "help") != 0) fprintf(stderr, "What is \"%s\"?\n", *argv); - explain(); - return -1; - } - argc--; argv++; + explain(); + return -1; } return 0; From 32e93fb7f66d55d597b52ec3b10fd44a47784114 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 13 Nov 2015 00:39:29 +0100 Subject: [PATCH 002/513] {f,m}_bpf: allow for sharing maps This larger work addresses one of the bigger remaining issues on tc's eBPF frontend, that is, to allow for persistent file descriptors. Whenever tc parses the ELF object, extracts and loads maps into the kernel, these file descriptors will be out of reach after the tc instance exits. Meaning, for simple (unnested) programs which contain one or multiple maps, the kernel holds a reference, and they will live on inside the kernel until the program holding them is unloaded, but they will be out of reach for user space, even worse with (also multiple nested) tail calls. For this issue, we introduced the concept of an agent that can receive the set of file descriptors from the tc instance creating them, in order to be able to further inspect/update map data for a specific use case. However, while that is more tied towards specific applications, it still doesn't easily allow for sharing maps accross multiple tc instances and would require a daemon to be running in the background. F.e. when a map should be shared by two eBPF programs, one attached to ingress, one to egress, this currently doesn't work with the tc frontend. This work solves exactly that, i.e. if requested, maps can now be _arbitrarily_ shared between object files (PIN_GLOBAL_NS) or within a single object (but various program sections, PIN_OBJECT_NS) without "loosing" the file descriptor set. To make that happen, we use eBPF object pinning introduced in kernel commit b2197755b263 ("bpf: add support for persistent maps/progs") for exactly this purpose. The shipped examples/bpf/bpf_shared.c code from this patch can be easily applied, for instance, as: - classifier-classifier shared: tc filter add dev foo parent 1: bpf obj shared.o sec egress tc filter add dev foo parent ffff: bpf obj shared.o sec ingress - classifier-action shared (here: late binding to a dummy classifier): tc actions add action bpf obj shared.o sec egress pass index 42 tc filter add dev foo parent ffff: bpf obj shared.o sec ingress tc filter add dev foo parent 1: bpf bytecode '1,6 0 0 4294967295,' \ action bpf index 42 The toy example increments a shared counter on egress and dumps its value on ingress (if no sharing (PIN_NONE) would have been chosen, map value is 0, of course, due to the two map instances being created): [...] -0 [002] ..s. 38264.788234: : map val: 4 -0 [002] ..s. 38264.788919: : map val: 4 -0 [002] ..s. 38264.789599: : map val: 5 [...] ... thus if both sections reference the pinned map(s) in question, tc will take care of fetching the appropriate file descriptor. The patch has been tested extensively on both, classifier and action sides. Signed-off-by: Daniel Borkmann --- examples/bpf/bpf_funcs.h | 7 + examples/bpf/bpf_shared.c | 54 ++ examples/bpf/bpf_shared.h | 4 - include/bpf_elf.h | 6 + include/utils.h | 3 + tc/e_bpf.c | 18 +- tc/f_bpf.c | 131 +--- tc/m_bpf.c | 158 ++--- tc/tc_bpf.c | 1259 +++++++++++++++++++++++++++---------- tc/tc_bpf.h | 73 +-- 10 files changed, 1105 insertions(+), 608 deletions(-) create mode 100644 examples/bpf/bpf_shared.c diff --git a/examples/bpf/bpf_funcs.h b/examples/bpf/bpf_funcs.h index 1545fa9df..1369401a0 100644 --- a/examples/bpf/bpf_funcs.h +++ b/examples/bpf/bpf_funcs.h @@ -1,6 +1,10 @@ #ifndef __BPF_FUNCS__ #define __BPF_FUNCS__ +#include + +#include "../../include/bpf_elf.h" + /* Misc macros. */ #ifndef __maybe_unused # define __maybe_unused __attribute__ ((__unused__)) @@ -43,6 +47,9 @@ static unsigned int (*get_smp_processor_id)(void) __maybe_unused = static unsigned int (*get_prandom_u32)(void) __maybe_unused = (void *) BPF_FUNC_get_prandom_u32; +static int (*bpf_printk)(const char *fmt, int fmt_size, ...) __maybe_unused = + (void *) BPF_FUNC_trace_printk; + /* LLVM built-in functions that an eBPF C program may use to emit * BPF_LD_ABS and BPF_LD_IND instructions. */ diff --git a/examples/bpf/bpf_shared.c b/examples/bpf/bpf_shared.c new file mode 100644 index 000000000..a8dc39c75 --- /dev/null +++ b/examples/bpf/bpf_shared.c @@ -0,0 +1,54 @@ +#include + +#include "bpf_funcs.h" + +/* Minimal, stand-alone toy map pinning example: + * + * clang -target bpf -O2 [...] -o bpf_shared.o -c bpf_shared.c + * tc filter add dev foo parent 1: bpf obj bpf_shared.o sec egress + * tc filter add dev foo parent ffff: bpf obj bpf_shared.o sec ingress + * + * Both classifier will share the very same map instance in this example, + * so map content can be accessed from ingress *and* egress side! + * + * This example has a pinning of PIN_OBJECT_NS, so it's private and + * thus shared among various program sections within the object. + * + * A setting of PIN_GLOBAL_NS would place it into a global namespace, + * so that it can be shared among different object files. A setting + * of PIN_NONE (= 0) means no sharing, so each tc invocation a new map + * instance is being created. + */ + +struct bpf_elf_map __section("maps") map_sh = { + .type = BPF_MAP_TYPE_ARRAY, + .size_key = sizeof(int), + .size_value = sizeof(int), + .pinning = PIN_OBJECT_NS, /* or PIN_GLOBAL_NS, or PIN_NONE */ + .max_elem = 1, +}; + +__section("egress") int emain(struct __sk_buff *skb) +{ + int key = 0, *val; + + val = bpf_map_lookup_elem(&map_sh, &key); + if (val) + __sync_fetch_and_add(val, 1); + + return -1; +} + +__section("ingress") int imain(struct __sk_buff *skb) +{ + char fmt[] = "map val: %d\n"; + int key = 0, *val; + + val = bpf_map_lookup_elem(&map_sh, &key); + if (val) + bpf_printk(fmt, sizeof(fmt), *val); + + return -1; +} + +char __license[] __section("license") = "GPL"; diff --git a/examples/bpf/bpf_shared.h b/examples/bpf/bpf_shared.h index 46423ecac..ea8f01474 100644 --- a/examples/bpf/bpf_shared.h +++ b/examples/bpf/bpf_shared.h @@ -1,10 +1,6 @@ #ifndef __BPF_SHARED__ #define __BPF_SHARED__ -#include - -#include "../../include/bpf_elf.h" - enum { BPF_MAP_ID_PROTO, BPF_MAP_ID_QUEUE, diff --git a/include/bpf_elf.h b/include/bpf_elf.h index 4bd6bb004..0690dd6ae 100644 --- a/include/bpf_elf.h +++ b/include/bpf_elf.h @@ -21,6 +21,11 @@ #define ELF_MAX_MAPS 64 #define ELF_MAX_LICENSE_LEN 128 +/* Object pinning settings */ +#define PIN_NONE 0 +#define PIN_OBJECT_NS 1 +#define PIN_GLOBAL_NS 2 + /* ELF map definition */ struct bpf_elf_map { __u32 type; @@ -28,6 +33,7 @@ struct bpf_elf_map { __u32 size_value; __u32 max_elem; __u32 id; + __u8 pinning; }; #endif /* __BPF_ELF__ */ diff --git a/include/utils.h b/include/utils.h index 1d351490a..5902a9850 100644 --- a/include/utils.h +++ b/include/utils.h @@ -192,6 +192,9 @@ void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n); __attribute__ ((format (printf, (pos_str), (pos_args)))) #endif +#define _textify(x) #x +#define textify(x) _textify(x) + #define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) #define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32)) diff --git a/tc/e_bpf.c b/tc/e_bpf.c index 218ba404b..1f386c360 100644 --- a/tc/e_bpf.c +++ b/tc/e_bpf.c @@ -26,7 +26,7 @@ static char *argv_default[] = { BPF_DEFAULT_CMD, NULL }; static void explain(void) { - fprintf(stderr, "Usage: ... bpf [ import UDS_FILE ] [ run CMD ]\n\n"); + fprintf(stderr, "Usage: ... bpf [ import UDS_FILE ] [ run CMD ] [ debug ]\n\n"); fprintf(stderr, "Where UDS_FILE provides the name of a unix domain socket file\n"); fprintf(stderr, "to import eBPF maps and the optional CMD denotes the command\n"); fprintf(stderr, "to be executed (default: \'%s\').\n", BPF_DEFAULT_CMD); @@ -58,17 +58,21 @@ static int parse_bpf(struct exec_util *eu, int argc, char **argv) NEXT_ARG(); argv_run = argv; break; - } else if (matches(*argv, "import") == 0 || - matches(*argv, "imp") == 0) { + } else if (matches(*argv, "import") == 0) { NEXT_ARG(); bpf_uds_name = *argv; + } else if (matches(*argv, "debug") == 0 || + matches(*argv, "dbg") == 0) { + if (bpf_trace_pipe()) + fprintf(stderr, + "No trace pipe, tracefs not mounted?\n"); + return -1; } else { explain(); return -1; } - argc--; - argv++; + NEXT_ARG_FWD(); } if (!bpf_uds_name) { @@ -142,6 +146,6 @@ static int parse_bpf(struct exec_util *eu, int argc, char **argv) } struct exec_util bpf_exec_util = { - .id = "bpf", - .parse_eopt = parse_bpf, + .id = "bpf", + .parse_eopt = parse_bpf, }; diff --git a/tc/f_bpf.c b/tc/f_bpf.c index ac77af583..afc2e582c 100644 --- a/tc/f_bpf.c +++ b/tc/f_bpf.c @@ -11,19 +11,8 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include + +#include #include "utils.h" #include "tc_util.h" @@ -31,6 +20,13 @@ static const enum bpf_prog_type bpf_type = BPF_PROG_TYPE_SCHED_CLS; +static const int nla_tbl[BPF_NLA_MAX] = { + [BPF_NLA_OPS_LEN] = TCA_BPF_OPS_LEN, + [BPF_NLA_OPS] = TCA_BPF_OPS, + [BPF_NLA_FD] = TCA_BPF_FD, + [BPF_NLA_NAME] = TCA_BPF_NAME, +}; + static void explain(void) { fprintf(stderr, "Usage: ... bpf ...\n"); @@ -42,6 +38,7 @@ static void explain(void) fprintf(stderr, "eBPF use case:\n"); fprintf(stderr, " object-file FILE [ section CLS_NAME ] [ export UDS_FILE ]"); fprintf(stderr, " [ verbose ] [ direct-action ]\n"); + fprintf(stderr, " object-pinned FILE [ direct-action ]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Common remaining options:\n"); fprintf(stderr, " [ action ACTION_SPEC ]\n"); @@ -51,7 +48,8 @@ static void explain(void) fprintf(stderr, "c,t,f,k and s are decimals; s denotes number of 4-tuples\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where FILE points to a file containing the BPF_BYTECODE string,\n"); - fprintf(stderr, "an ELF file containing eBPF map definitions and bytecode.\n"); + fprintf(stderr, "an ELF file containing eBPF map definitions and bytecode, or a\n"); + fprintf(stderr, "pinned eBPF program.\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where CLS_NAME refers to the section name containing the\n"); fprintf(stderr, "classifier (default \'%s\').\n", bpf_default_section(bpf_type)); @@ -66,119 +64,38 @@ static void explain(void) static int bpf_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) { + const char *bpf_obj = NULL, *bpf_uds_name = NULL; struct tcmsg *t = NLMSG_DATA(n); - const char *bpf_uds_name = NULL; - const char *bpf_sec_name = NULL; unsigned int bpf_flags = 0; - char *bpf_obj = NULL; - struct rtattr *tail; bool seen_run = false; - long h = 0; + struct rtattr *tail; int ret = 0; if (argc == 0) return 0; if (handle) { - h = strtol(handle, NULL, 0); - if (h == LONG_MIN || h == LONG_MAX) { - fprintf(stderr, "Illegal handle \"%s\", must be " - "numeric.\n", handle); + if (get_u32(&t->tcm_handle, handle, 0)) { + fprintf(stderr, "Illegal \"handle\"\n"); return -1; } } - t->tcm_handle = h; - tail = (struct rtattr *)(((void *)n) + NLMSG_ALIGN(n->nlmsg_len)); addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); while (argc > 0) { if (matches(*argv, "run") == 0) { - struct sock_filter bpf_ops[BPF_MAXINSNS]; - bool from_file, ebpf, bpf_verbose; - int ret; - NEXT_ARG(); opt_bpf: - bpf_sec_name = bpf_default_section(bpf_type); - bpf_verbose = false; - ebpf = false; seen_run = true; - - if (strcmp(*argv, "bytecode-file") == 0 || - strcmp(*argv, "bcf") == 0) { - from_file = true; - } else if (strcmp(*argv, "bytecode") == 0 || - strcmp(*argv, "bc") == 0) { - from_file = false; - } else if (strcmp(*argv, "object-file") == 0 || - strcmp(*argv, "obj") == 0) { - ebpf = true; - } else { - fprintf(stderr, "What is \"%s\"?\n", *argv); - explain(); - return -1; - } - - NEXT_ARG(); - if (ebpf) { - bpf_uds_name = getenv(BPF_ENV_UDS); - bpf_obj = *argv; - - NEXT_ARG_FWD(); - - if (argc > 0 && - (strcmp(*argv, "section") == 0 || - strcmp(*argv, "sec") == 0)) { - NEXT_ARG(); - bpf_sec_name = *argv; - NEXT_ARG_FWD(); - } - if (argc > 0 && !bpf_uds_name && - (strcmp(*argv, "export") == 0 || - strcmp(*argv, "exp") == 0)) { - NEXT_ARG(); - bpf_uds_name = *argv; - NEXT_ARG_FWD(); - } - if (argc > 0 && - (strcmp(*argv, "verbose") == 0 || - strcmp(*argv, "verb") == 0)) { - bpf_verbose = true; - NEXT_ARG_FWD(); - } - - PREV_ARG(); - } - - ret = ebpf ? bpf_open_object(bpf_obj, bpf_type, bpf_sec_name, - bpf_verbose) : - bpf_parse_ops(argc, argv, bpf_ops, from_file); - if (ret < 0) { - fprintf(stderr, "%s\n", ebpf ? - "Could not load object" : - "Illegal \"bytecode\""); + if (bpf_parse_common(&argc, &argv, nla_tbl, bpf_type, + &bpf_obj, &bpf_uds_name, n)) { + fprintf(stderr, "Failed to retrieve (e)BPF data!\n"); return -1; } - - if (ebpf) { - char bpf_name[256]; - - bpf_obj = basename(bpf_obj); - - snprintf(bpf_name, sizeof(bpf_name), "%s:[%s]", - bpf_obj, bpf_sec_name); - - addattr32(n, MAX_MSG, TCA_BPF_FD, ret); - addattrstrz(n, MAX_MSG, TCA_BPF_NAME, bpf_name); - } else { - addattr16(n, MAX_MSG, TCA_BPF_OPS_LEN, ret); - addattr_l(n, MAX_MSG, TCA_BPF_OPS, &bpf_ops, - ret * sizeof(struct sock_filter)); - } } else if (matches(*argv, "classid") == 0 || - strcmp(*argv, "flowid") == 0) { + matches(*argv, "flowid") == 0) { unsigned int handle; NEXT_ARG(); @@ -204,7 +121,7 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle, return -1; } continue; - } else if (strcmp(*argv, "help") == 0) { + } else if (matches(*argv, "help") == 0) { explain(); return -1; } else { @@ -280,7 +197,7 @@ static int bpf_print_opt(struct filter_util *qu, FILE *f, } struct filter_util bpf_filter_util = { - .id = "bpf", - .parse_fopt = bpf_parse_opt, - .print_fopt = bpf_print_opt, + .id = "bpf", + .parse_fopt = bpf_parse_opt, + .print_fopt = bpf_print_opt, }; diff --git a/tc/m_bpf.c b/tc/m_bpf.c index fb4c3c7ff..c5e2fa5b0 100644 --- a/tc/m_bpf.c +++ b/tc/m_bpf.c @@ -12,20 +12,23 @@ #include #include -#include -#include -#include -#include + #include #include #include "utils.h" -#include "rt_names.h" #include "tc_util.h" #include "tc_bpf.h" static const enum bpf_prog_type bpf_type = BPF_PROG_TYPE_SCHED_ACT; +static const int nla_tbl[BPF_NLA_MAX] = { + [BPF_NLA_OPS_LEN] = TCA_ACT_BPF_OPS_LEN, + [BPF_NLA_OPS] = TCA_ACT_BPF_OPS, + [BPF_NLA_FD] = TCA_ACT_BPF_FD, + [BPF_NLA_NAME] = TCA_ACT_BPF_NAME, +}; + static void explain(void) { fprintf(stderr, "Usage: ... bpf ... [ index INDEX ]\n"); @@ -37,12 +40,14 @@ static void explain(void) fprintf(stderr, "eBPF use case:\n"); fprintf(stderr, " object-file FILE [ section ACT_NAME ] [ export UDS_FILE ]"); fprintf(stderr, " [ verbose ]\n"); + fprintf(stderr, " object-pinned FILE\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n"); fprintf(stderr, "c,t,f,k and s are decimals; s denotes number of 4-tuples\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where FILE points to a file containing the BPF_BYTECODE string,\n"); - fprintf(stderr, "an ELF file containing eBPF map definitions and bytecode.\n"); + fprintf(stderr, "an ELF file containing eBPF map definitions and bytecode, or a\n"); + fprintf(stderr, "pinned eBPF program.\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where ACT_NAME refers to the section name containing the\n"); fprintf(stderr, "action (default \'%s\').\n", bpf_default_section(bpf_type)); @@ -54,114 +59,40 @@ static void explain(void) fprintf(stderr, "explicitly specifies an action index upon creation.\n"); } -static void usage(void) +static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv, + int tca_id, struct nlmsghdr *n) { - explain(); - exit(-1); -} - -static int parse_bpf(struct action_util *a, int *argc_p, char ***argv_p, - int tca_id, struct nlmsghdr *n) -{ - char **argv = *argv_p, bpf_name[256]; + const char *bpf_obj = NULL, *bpf_uds_name = NULL; + struct tc_act_bpf parm; + bool seen_run = false; struct rtattr *tail; - struct tc_act_bpf parm = { 0 }; - struct sock_filter bpf_ops[BPF_MAXINSNS]; - bool ebpf_fill = false, bpf_fill = false; - bool ebpf = false, seen_run = false; - const char *bpf_uds_name = NULL; - const char *bpf_sec_name = NULL; - char *bpf_obj = NULL; - int argc = *argc_p, ret = 0; - __u16 bpf_len = 0; - __u32 bpf_fd = 0; + int argc, ret = 0; + char **argv; + + argv = *ptr_argv; + argc = *ptr_argc; if (matches(*argv, "bpf") != 0) return -1; NEXT_ARG(); + tail = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, tca_id, NULL, 0); + while (argc > 0) { if (matches(*argv, "run") == 0) { - bool from_file, bpf_verbose; - int ret; - NEXT_ARG(); opt_bpf: - bpf_sec_name = bpf_default_section(bpf_type); - bpf_verbose = false; seen_run = true; - - if (strcmp(*argv, "bytecode-file") == 0 || - strcmp(*argv, "bcf") == 0) { - from_file = true; - } else if (strcmp(*argv, "bytecode") == 0 || - strcmp(*argv, "bc") == 0) { - from_file = false; - } else if (strcmp(*argv, "object-file") == 0 || - strcmp(*argv, "obj") == 0) { - ebpf = true; - } else { - fprintf(stderr, "unexpected \"%s\"\n", *argv); - explain(); + if (bpf_parse_common(&argc, &argv, nla_tbl, bpf_type, + &bpf_obj, &bpf_uds_name, n)) { + fprintf(stderr, "Failed to retrieve (e)BPF data!\n"); return -1; } - - NEXT_ARG(); - if (ebpf) { - bpf_uds_name = getenv(BPF_ENV_UDS); - bpf_obj = *argv; - - NEXT_ARG_FWD(); - - if (argc > 0 && - (strcmp(*argv, "section") == 0 || - strcmp(*argv, "sec") == 0)) { - NEXT_ARG(); - bpf_sec_name = *argv; - NEXT_ARG_FWD(); - } - if (argc > 0 && !bpf_uds_name && - (strcmp(*argv, "export") == 0 || - strcmp(*argv, "exp") == 0)) { - NEXT_ARG(); - bpf_uds_name = *argv; - NEXT_ARG_FWD(); - } - if (argc > 0 && - (strcmp(*argv, "verbose") == 0 || - strcmp(*argv, "verb") == 0)) { - bpf_verbose = true; - NEXT_ARG_FWD(); - } - - PREV_ARG(); - } - - ret = ebpf ? bpf_open_object(bpf_obj, bpf_type, bpf_sec_name, - bpf_verbose) : - bpf_parse_ops(argc, argv, bpf_ops, from_file); - if (ret < 0) { - fprintf(stderr, "%s\n", ebpf ? - "Could not load object" : - "Illegal \"bytecode\""); - return -1; - } - - if (ebpf) { - bpf_obj = basename(bpf_obj); - - snprintf(bpf_name, sizeof(bpf_name), "%s:[%s]", - bpf_obj, bpf_sec_name); - - bpf_fd = ret; - ebpf_fill = true; - } else { - bpf_len = ret; - bpf_fill = true; - } } else if (matches(*argv, "help") == 0) { - usage(); + explain(); + return -1; } else if (matches(*argv, "index") == 0) { break; } else { @@ -173,7 +104,9 @@ static int parse_bpf(struct action_util *a, int *argc_p, char ***argv_p, NEXT_ARG_FWD(); } + memset(&parm, 0, sizeof(parm)); parm.action = TC_ACT_PIPE; + if (argc) { if (matches(*argv, "reclassify") == 0) { parm.action = TC_ACT_RECLASSIFY; @@ -207,32 +140,19 @@ static int parse_bpf(struct action_util *a, int *argc_p, char ***argv_p, } } - tail = NLMSG_TAIL(n); - - addattr_l(n, MAX_MSG, tca_id, NULL, 0); addattr_l(n, MAX_MSG, TCA_ACT_BPF_PARMS, &parm, sizeof(parm)); - - if (ebpf_fill) { - addattr32(n, MAX_MSG, TCA_ACT_BPF_FD, bpf_fd); - addattrstrz(n, MAX_MSG, TCA_ACT_BPF_NAME, bpf_name); - } else if (bpf_fill) { - addattr16(n, MAX_MSG, TCA_ACT_BPF_OPS_LEN, bpf_len); - addattr_l(n, MAX_MSG, TCA_ACT_BPF_OPS, &bpf_ops, - bpf_len * sizeof(struct sock_filter)); - } - tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; - *argc_p = argc; - *argv_p = argv; - if (bpf_uds_name) ret = bpf_send_map_fds(bpf_uds_name, bpf_obj); + *ptr_argc = argc; + *ptr_argv = argv; + return ret; } -static int print_bpf(struct action_util *au, FILE *f, struct rtattr *arg) +static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg) { struct rtattr *tb[TCA_ACT_BPF_MAX + 1]; struct tc_act_bpf *parm; @@ -249,7 +169,6 @@ static int print_bpf(struct action_util *au, FILE *f, struct rtattr *arg) } parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]); - fprintf(f, "bpf "); if (tb[TCA_ACT_BPF_NAME]) @@ -276,12 +195,11 @@ static int print_bpf(struct action_util *au, FILE *f, struct rtattr *arg) } fprintf(f, "\n "); - return 0; } struct action_util bpf_action_util = { - .id = "bpf", - .parse_aopt = parse_bpf, - .print_aopt = print_bpf, + .id = "bpf", + .parse_aopt = bpf_parse_opt, + .print_aopt = bpf_print_opt, }; diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index 276871a5c..bc7bc9ffa 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -20,18 +20,25 @@ #include #include #include -#include -#include -#include -#include -#include -#include #ifdef HAVE_ELF #include #include #endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + #include "utils.h" #include "bpf_elf.h" @@ -40,9 +47,47 @@ #include "tc_util.h" #include "tc_bpf.h" -int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len, - char **bpf_string, bool *need_release, - const char separator) +#ifdef HAVE_ELF +static int bpf_obj_open(const char *path, enum bpf_prog_type type, + const char *sec, bool verbose); +#else +static int bpf_obj_open(const char *path, enum bpf_prog_type type, + const char *sec, bool verbose) +{ + fprintf(stderr, "No ELF library support compiled in.\n"); + errno = ENOSYS; + return -1; +} +#endif + +static inline __u64 bpf_ptr_to_u64(const void *ptr) +{ + return (__u64)(unsigned long)ptr; +} + +static int bpf(int cmd, union bpf_attr *attr, unsigned int size) +{ +#ifdef __NR_bpf + return syscall(__NR_bpf, cmd, attr, size); +#else + fprintf(stderr, "No bpf syscall, kernel headers too old?\n"); + errno = ENOSYS; + return -1; +#endif +} + +static int bpf_obj_get(const char *pathname) +{ + union bpf_attr attr = { + .pathname = bpf_ptr_to_u64(pathname), + }; + + return bpf(BPF_OBJ_GET, &attr, sizeof(attr)); +} + +static int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len, + char **bpf_string, bool *need_release, + const char separator) { char sp; @@ -90,8 +135,8 @@ int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len, return 0; } -int bpf_parse_ops(int argc, char **argv, struct sock_filter *bpf_ops, - bool from_file) +static int bpf_ops_parse(int argc, char **argv, struct sock_filter *bpf_ops, + bool from_file) { char *bpf_string, *token, separator = ','; int ret = 0, i = 0; @@ -135,7 +180,6 @@ int bpf_parse_ops(int argc, char **argv, struct sock_filter *bpf_ops, goto out; } ret = bpf_len; - out: if (need_release) free(bpf_string); @@ -161,6 +205,97 @@ void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len) ops[i].jf, ops[i].k); } +static int bpf_valid_mntpt(const char *mnt, unsigned long magic) +{ + struct statfs st_fs; + + if (statfs(mnt, &st_fs) < 0) + return -ENOENT; + if ((unsigned long)st_fs.f_type != magic) + return -ENOENT; + + return 0; +} + +static const char *bpf_find_mntpt(const char *fstype, unsigned long magic, + char *mnt, int len, + const char * const *known_mnts) +{ + const char * const *ptr; + char type[100]; + FILE *fp; + + if (known_mnts) { + ptr = known_mnts; + while (*ptr) { + if (bpf_valid_mntpt(*ptr, magic) == 0) { + strncpy(mnt, *ptr, len - 1); + mnt[len - 1] = 0; + return mnt; + } + ptr++; + } + } + + fp = fopen("/proc/mounts", "r"); + if (fp == NULL || len != PATH_MAX) + return NULL; + + while (fscanf(fp, "%*s %" textify(PATH_MAX) "s %99s %*s %*d %*d\n", + mnt, type) == 2) { + if (strcmp(type, fstype) == 0) + break; + } + + fclose(fp); + if (strcmp(type, fstype) != 0) + return NULL; + + return mnt; +} + +int bpf_trace_pipe(void) +{ + char tracefs_mnt[PATH_MAX] = TRACE_DIR_MNT; + static const char * const tracefs_known_mnts[] = { + TRACE_DIR_MNT, + "/sys/kernel/debug/tracing", + "/tracing", + "/trace", + 0, + }; + char tpipe[PATH_MAX]; + const char *mnt; + int fd; + + mnt = bpf_find_mntpt("tracefs", TRACEFS_MAGIC, tracefs_mnt, + sizeof(tracefs_mnt), tracefs_known_mnts); + if (!mnt) { + fprintf(stderr, "tracefs not mounted?\n"); + return -1; + } + + snprintf(tpipe, sizeof(tpipe), "%s/trace_pipe", mnt); + + fd = open(tpipe, O_RDONLY); + if (fd < 0) + return -1; + + fprintf(stderr, "Running! Hang up with ^C!\n\n"); + while (1) { + static char buff[4096]; + ssize_t ret; + + ret = read(fd, buff, sizeof(buff) - 1); + if (ret > 0) { + write(2, buff, ret); + fflush(stderr); + } + } + + return 0; +} + const char *bpf_default_section(const enum bpf_prog_type type) { switch (type) { @@ -173,18 +308,139 @@ const char *bpf_default_section(const enum bpf_prog_type type) } } +int bpf_parse_common(int *ptr_argc, char ***ptr_argv, const int *nla_tbl, + enum bpf_prog_type type, const char **ptr_object, + const char **ptr_uds_name, struct nlmsghdr *n) +{ + struct sock_filter opcodes[BPF_MAXINSNS]; + const char *file, *section, *uds_name; + char **argv = *ptr_argv; + int argc = *ptr_argc; + char annotation[256]; + bool verbose = false; + int ret; + enum bpf_mode { + CBPF_BYTECODE, + CBPF_FILE, + EBPF_OBJECT, + EBPF_PINNED, + } mode; + + if (matches(*argv, "bytecode") == 0 || + strcmp(*argv, "bc") == 0) { + mode = CBPF_BYTECODE; + } else if (matches(*argv, "bytecode-file") == 0 || + strcmp(*argv, "bcf") == 0) { + mode = CBPF_FILE; + } else if (matches(*argv, "object-file") == 0 || + strcmp(*argv, "obj") == 0) { + mode = EBPF_OBJECT; + } else if (matches(*argv, "object-pinned") == 0 || + matches(*argv, "pinned") == 0 || + matches(*argv, "fd") == 0) { + mode = EBPF_PINNED; + } else { + fprintf(stderr, "What mode is \"%s\"?\n", *argv); + return -1; + } + + NEXT_ARG(); + file = section = uds_name = NULL; + if (mode == EBPF_OBJECT || mode == EBPF_PINNED) { + file = *argv; + NEXT_ARG_FWD(); + + section = bpf_default_section(type); + if (argc > 0 && matches(*argv, "section") == 0) { + NEXT_ARG(); + section = *argv; + NEXT_ARG_FWD(); + } + + uds_name = getenv(BPF_ENV_UDS); + if (argc > 0 && !uds_name && + matches(*argv, "export") == 0) { + NEXT_ARG(); + uds_name = *argv; + NEXT_ARG_FWD(); + } + + if (argc > 0 && matches(*argv, "verbose") == 0) { + verbose = true; + NEXT_ARG_FWD(); + } + + PREV_ARG(); + } + + if (mode == CBPF_BYTECODE || mode == CBPF_FILE) + ret = bpf_ops_parse(argc, argv, opcodes, mode == CBPF_FILE); + else if (mode == EBPF_OBJECT) + ret = bpf_obj_open(file, type, section, verbose); + else if (mode == EBPF_PINNED) + ret = bpf_obj_get(file); + if (ret < 0) + return -1; + + if (mode == CBPF_BYTECODE || mode == CBPF_FILE) { + addattr16(n, MAX_MSG, nla_tbl[BPF_NLA_OPS_LEN], ret); + addattr_l(n, MAX_MSG, nla_tbl[BPF_NLA_OPS], opcodes, + ret * sizeof(struct sock_filter)); + } else if (mode == EBPF_OBJECT || mode == EBPF_PINNED) { + snprintf(annotation, sizeof(annotation), "%s:[%s]", + basename(file), mode == EBPF_PINNED ? "*fsobj" : + section); + + addattr32(n, MAX_MSG, nla_tbl[BPF_NLA_FD], ret); + addattrstrz(n, MAX_MSG, nla_tbl[BPF_NLA_NAME], annotation); + } + + *ptr_object = file; + *ptr_uds_name = uds_name; + + *ptr_argc = argc; + *ptr_argv = argv; + + return 0; +} + #ifdef HAVE_ELF +struct bpf_elf_prog { + enum bpf_prog_type type; + const struct bpf_insn *insns; + size_t size; + const char *license; +}; + +struct bpf_elf_ctx { + Elf *elf_fd; + GElf_Ehdr elf_hdr; + Elf_Data *sym_tab; + Elf_Data *str_tab; + int obj_fd; + int map_fds[ELF_MAX_MAPS]; + struct bpf_elf_map maps[ELF_MAX_MAPS]; + int sym_num; + int map_num; + bool *sec_done; + int sec_maps; + char license[ELF_MAX_LICENSE_LEN]; + enum bpf_prog_type type; + bool verbose; + struct bpf_elf_st stat; +}; + struct bpf_elf_sec_data { - GElf_Shdr sec_hdr; - char *sec_name; - Elf_Data *sec_data; + GElf_Shdr sec_hdr; + Elf_Data *sec_data; + const char *sec_name; }; struct bpf_map_data { - int *fds; - const char *obj; - struct bpf_elf_st *st; - struct bpf_elf_map *ent; + int *fds; + const char *obj; + struct bpf_elf_st *st; + struct bpf_elf_map *ent; }; /* If we provide a small buffer with log level enabled, the kernel @@ -193,15 +449,8 @@ struct bpf_map_data { * verifier we still want to hand something descriptive to the user. */ static char bpf_log_buf[65536]; -static bool bpf_verbose; - -static struct bpf_elf_st bpf_st; -static int map_fds[ELF_MAX_MAPS]; -static struct bpf_elf_map map_ent[ELF_MAX_MAPS]; - -static void bpf_dump_error(const char *format, ...) __check_format_string(1, 2); -static void bpf_dump_error(const char *format, ...) +static __check_format_string(1, 2) void bpf_dump_error(const char *format, ...) { va_list vl; @@ -215,46 +464,7 @@ static void bpf_dump_error(const char *format, ...) } } -static void bpf_save_finfo(int file_fd) -{ - struct stat st; - int ret; - - memset(&bpf_st, 0, sizeof(bpf_st)); - - ret = fstat(file_fd, &st); - if (ret < 0) { - fprintf(stderr, "Stat of elf file failed: %s\n", - strerror(errno)); - return; - } - - bpf_st.st_dev = st.st_dev; - bpf_st.st_ino = st.st_ino; -} - -static void bpf_clear_finfo(void) -{ - memset(&bpf_st, 0, sizeof(bpf_st)); -} - -static bool bpf_may_skip_map_creation(int file_fd) -{ - struct stat st; - int ret; - - ret = fstat(file_fd, &st); - if (ret < 0) { - fprintf(stderr, "Stat of elf file failed: %s\n", - strerror(errno)); - return false; - } - - return (bpf_st.st_dev == st.st_dev) && - (bpf_st.st_ino == st.st_ino); -} - -static int bpf_create_map(enum bpf_map_type type, unsigned int size_key, +static int bpf_map_create(enum bpf_map_type type, unsigned int size_key, unsigned int size_value, unsigned int max_elem) { union bpf_attr attr = { @@ -267,7 +477,7 @@ static int bpf_create_map(enum bpf_map_type type, unsigned int size_key, return bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); } -static int bpf_update_map(int fd, const void *key, const void *value, +static int bpf_map_update(int fd, const void *key, const void *value, uint64_t flags) { union bpf_attr attr = { @@ -281,121 +491,429 @@ static int bpf_update_map(int fd, const void *key, const void *value, } static int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, - unsigned int len, const char *license) + size_t size, const char *license) { union bpf_attr attr = { .prog_type = type, .insns = bpf_ptr_to_u64(insns), - .insn_cnt = len / sizeof(struct bpf_insn), + .insn_cnt = size / sizeof(struct bpf_insn), .license = bpf_ptr_to_u64(license), .log_buf = bpf_ptr_to_u64(bpf_log_buf), .log_size = sizeof(bpf_log_buf), .log_level = 1, }; + if (getenv(BPF_ENV_NOLOG)) { + attr.log_buf = 0; + attr.log_size = 0; + attr.log_level = 0; + } + return bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); } -static int bpf_prog_attach(enum bpf_prog_type type, const char *sec, - const struct bpf_insn *insns, unsigned int size, - const char *license) +static int bpf_obj_pin(int fd, const char *pathname) { - int prog_fd = bpf_prog_load(type, insns, size, license); + union bpf_attr attr = { + .pathname = bpf_ptr_to_u64(pathname), + .bpf_fd = fd, + }; + + return bpf(BPF_OBJ_PIN, &attr, sizeof(attr)); +} - if (prog_fd < 0 || bpf_verbose) { - bpf_dump_error("%s (section \'%s\'): %s\n", prog_fd < 0 ? - "BPF program rejected" : - "BPF program verification", - sec, strerror(errno)); +static int bpf_obj_hash(const char *object, uint8_t *out, size_t len) +{ + struct sockaddr_alg alg = { + .salg_family = AF_ALG, + .salg_type = "hash", + .salg_name = "sha1", + }; + int ret, cfd, ofd, ffd; + struct stat stbuff; + ssize_t size; + + if (!object || len != 20) + return -EINVAL; + + cfd = socket(AF_ALG, SOCK_SEQPACKET, 0); + if (cfd < 0) { + fprintf(stderr, "Cannot get AF_ALG socket: %s\n", + strerror(errno)); + return cfd; + } + + ret = bind(cfd, (struct sockaddr *)&alg, sizeof(alg)); + if (ret < 0) { + fprintf(stderr, "Error binding socket: %s\n", strerror(errno)); + goto out_cfd; + } + + ofd = accept(cfd, NULL, 0); + if (ofd < 0) { + fprintf(stderr, "Error accepting socket: %s\n", + strerror(errno)); + ret = ofd; + goto out_cfd; + } + + ffd = open(object, O_RDONLY); + if (ffd < 0) { + fprintf(stderr, "Error opening object %s: %s\n", + object, strerror(errno)); + ret = ffd; + goto out_ofd; + } + + ret = fstat(ffd, &stbuff); + if (ret < 0) { + fprintf(stderr, "Error doing fstat: %s\n", + strerror(errno)); + goto out_ffd; } - return prog_fd; + size = sendfile(ofd, ffd, NULL, stbuff.st_size); + if (size != stbuff.st_size) { + fprintf(stderr, "Error from sendfile (%zd vs %zu bytes): %s\n", + size, stbuff.st_size, strerror(errno)); + ret = -1; + goto out_ffd; + } + + size = read(ofd, out, len); + if (size != len) { + fprintf(stderr, "Error from read (%zd vs %zu bytes): %s\n", + size, len, strerror(errno)); + ret = -1; + } else { + ret = 0; + } +out_ffd: + close(ffd); +out_ofd: + close(ofd); +out_cfd: + close(cfd); + return ret; } -static int bpf_map_attach(enum bpf_map_type type, unsigned int size_key, - unsigned int size_value, unsigned int max_elem) +static const char *bpf_get_obj_uid(const char *pathname) { - int map_fd = bpf_create_map(type, size_key, size_value, max_elem); + static bool bpf_uid_cached = false; + static char bpf_uid[64]; + uint8_t tmp[20]; + int ret; - if (map_fd < 0) - bpf_dump_error("BPF map rejected: %s\n", strerror(errno)); + if (bpf_uid_cached) + goto done; - return map_fd; + ret = bpf_obj_hash(pathname, tmp, sizeof(tmp)); + if (ret) { + fprintf(stderr, "Object hashing failed!\n"); + return NULL; + } + + hexstring_n2a(tmp, sizeof(tmp), bpf_uid, sizeof(bpf_uid)); + bpf_uid_cached = true; +done: + return bpf_uid; } -static void bpf_maps_init(void) +static int bpf_mnt_fs(const char *target) { - int i; + bool bind_done = false; + + while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) { + if (errno != EINVAL || bind_done) { + fprintf(stderr, "mount --make-private %s failed: %s\n", + target, strerror(errno)); + return -1; + } - memset(map_ent, 0, sizeof(map_ent)); - for (i = 0; i < ARRAY_SIZE(map_fds); i++) - map_fds[i] = -1; + if (mount(target, target, "none", MS_BIND, NULL)) { + fprintf(stderr, "mount --bind %s %s failed: %s\n", + target, target, strerror(errno)); + return -1; + } + + bind_done = true; + } + + if (mount("bpf", target, "bpf", 0, NULL)) { + fprintf(stderr, "mount -t bpf bpf %s failed: %s\n", + target, strerror(errno)); + return -1; + } + + return 0; } -static int bpf_maps_count(void) +static const char *bpf_get_tc_dir(void) { - int i, count = 0; + static bool bpf_mnt_cached = false; + static char bpf_tc_dir[PATH_MAX]; + static const char *mnt; + static const char * const bpf_known_mnts[] = { + BPF_DIR_MNT, + 0, + }; + char bpf_mnt[PATH_MAX] = BPF_DIR_MNT; + char bpf_glo_dir[PATH_MAX]; + int ret; - for (i = 0; i < ARRAY_SIZE(map_fds); i++) { - if (map_fds[i] < 0) - break; - count++; + if (bpf_mnt_cached) + goto done; + + mnt = bpf_find_mntpt("bpf", BPF_FS_MAGIC, bpf_mnt, sizeof(bpf_mnt), + bpf_known_mnts); + if (!mnt) { + mnt = getenv(BPF_ENV_MNT); + if (!mnt) + mnt = BPF_DIR_MNT; + ret = bpf_mnt_fs(mnt); + if (ret) { + mnt = NULL; + goto out; + } } - return count; + snprintf(bpf_tc_dir, sizeof(bpf_tc_dir), "%s/%s", mnt, BPF_DIR_TC); + ret = mkdir(bpf_tc_dir, S_IRWXU); + if (ret && errno != EEXIST) { + fprintf(stderr, "mkdir %s failed: %s\n", bpf_tc_dir, + strerror(errno)); + mnt = NULL; + goto out; + } + + snprintf(bpf_glo_dir, sizeof(bpf_glo_dir), "%s/%s", + bpf_tc_dir, BPF_DIR_GLOBALS); + ret = mkdir(bpf_glo_dir, S_IRWXU); + if (ret && errno != EEXIST) { + fprintf(stderr, "mkdir %s failed: %s\n", bpf_glo_dir, + strerror(errno)); + mnt = NULL; + goto out; + } + + mnt = bpf_tc_dir; +out: + bpf_mnt_cached = true; +done: + return mnt; +} + +static int bpf_init_env(const char *pathname) +{ + struct rlimit limit = { + .rlim_cur = RLIM_INFINITY, + .rlim_max = RLIM_INFINITY, + }; + + /* Don't bother in case we fail! */ + setrlimit(RLIMIT_MEMLOCK, &limit); + + if (!bpf_get_tc_dir()) { + fprintf(stderr, "Continuing without mounted eBPF fs. " + "Too old kernel?\n"); + return 0; + } + + if (!bpf_get_obj_uid(pathname)) + return -1; + + return 0; } -static void bpf_maps_destroy(void) +static bool bpf_no_pinning(int pinning) { + switch (pinning) { + case PIN_OBJECT_NS: + case PIN_GLOBAL_NS: + return false; + case PIN_NONE: + default: + return true; + } +} + +static void bpf_make_pathname(char *pathname, size_t len, const char *name, + int pinning) +{ + switch (pinning) { + case PIN_OBJECT_NS: + snprintf(pathname, len, "%s/%s/%s", bpf_get_tc_dir(), + bpf_get_obj_uid(NULL), name); + break; + case PIN_GLOBAL_NS: + snprintf(pathname, len, "%s/%s/%s", bpf_get_tc_dir(), + BPF_DIR_GLOBALS, name); + break; + } +} + +static int bpf_probe_pinned(const char *name, int pinning) +{ + char pathname[PATH_MAX]; + + if (bpf_no_pinning(pinning) || !bpf_get_tc_dir()) + return 0; + + bpf_make_pathname(pathname, sizeof(pathname), name, pinning); + return bpf_obj_get(pathname); +} + +static int bpf_place_pinned(int fd, const char *name, int pinning) +{ + char pathname[PATH_MAX]; + int ret; + + if (bpf_no_pinning(pinning) || !bpf_get_tc_dir()) + return 0; + + if (pinning == PIN_OBJECT_NS) { + snprintf(pathname, sizeof(pathname), "%s/%s", + bpf_get_tc_dir(), bpf_get_obj_uid(NULL)); + + ret = mkdir(pathname, S_IRWXU); + if (ret && errno != EEXIST) { + fprintf(stderr, "mkdir %s failed: %s\n", pathname, + strerror(errno)); + return ret; + } + } + + bpf_make_pathname(pathname, sizeof(pathname), name, pinning); + return bpf_obj_pin(fd, pathname); +} + +static int bpf_prog_attach(const char *section, + const struct bpf_elf_prog *prog, bool verbose) +{ + int fd; + + /* We can add pinning here later as well, same as bpf_map_attach(). */ + errno = 0; + fd = bpf_prog_load(prog->type, prog->insns, prog->size, + prog->license); + if (fd < 0 || verbose) { + bpf_dump_error("Prog section \'%s\' (type:%u insns:%zu " + "license:\'%s\') %s%s (%d)!\n\n", + section, prog->type, + prog->size / sizeof(struct bpf_insn), + prog->license, fd < 0 ? "rejected :" : + "loaded", fd < 0 ? strerror(errno) : "", + fd < 0 ? errno : fd); + } + + return fd; +} + +static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, + bool verbose) +{ + int fd, ret; + + fd = bpf_probe_pinned(name, map->pinning); + if (fd > 0) { + if (verbose) + fprintf(stderr, "Map \'%s\' loaded as pinned!\n", + name); + return fd; + } + + errno = 0; + fd = bpf_map_create(map->type, map->size_key, map->size_value, + map->max_elem); + if (fd < 0 || verbose) { + bpf_dump_error("Map \'%s\' (type:%u id:%u pinning:%u " + "ksize:%u vsize:%u max-elems:%u) %s%s (%d)!\n", + name, map->type, map->id, map->pinning, + map->size_key, map->size_value, map->max_elem, + fd < 0 ? "rejected: " : "loaded", fd < 0 ? + strerror(errno) : "", fd < 0 ? errno : fd); + if (fd < 0) + return fd; + } + + ret = bpf_place_pinned(fd, name, map->pinning); + if (ret < 0 && errno != EEXIST) { + fprintf(stderr, "Could not pin %s map: %s\n", name, + strerror(errno)); + close(fd); + return ret; + } + + return fd; +} + +#define __ELF_ST_BIND(x) ((x) >> 4) +#define __ELF_ST_TYPE(x) (((unsigned int) x) & 0xf) + +static const char *bpf_str_tab_name(const struct bpf_elf_ctx *ctx, + const GElf_Sym *sym) +{ + return ctx->str_tab->d_buf + sym->st_name; +} + +static const char *bpf_map_fetch_name(struct bpf_elf_ctx *ctx, int which) +{ + GElf_Sym sym; int i; - memset(map_ent, 0, sizeof(map_ent)); - for (i = 0; i < ARRAY_SIZE(map_fds); i++) { - if (map_fds[i] >= 0) - close(map_fds[i]); + for (i = 0; i < ctx->sym_num; i++) { + if (gelf_getsym(ctx->sym_tab, i, &sym) != &sym) + continue; + + if (__ELF_ST_BIND(sym.st_info) != STB_GLOBAL || + __ELF_ST_TYPE(sym.st_info) != STT_NOTYPE || + sym.st_shndx != ctx->sec_maps || + sym.st_value / sizeof(struct bpf_elf_map) != which) + continue; + + return bpf_str_tab_name(ctx, &sym); } + + return NULL; } -static int bpf_maps_attach(struct bpf_elf_map *maps, unsigned int num_maps) +static int bpf_maps_attach_all(struct bpf_elf_ctx *ctx) { - int i, ret; + const char *map_name; + int i, fd; - for (i = 0; (i < num_maps) && (num_maps <= ARRAY_SIZE(map_fds)); i++) { - struct bpf_elf_map *map = &maps[i]; + for (i = 0; i < ctx->map_num; i++) { + map_name = bpf_map_fetch_name(ctx, i); + if (!map_name) + return -EIO; - ret = bpf_map_attach(map->type, map->size_key, - map->size_value, map->max_elem); - if (ret < 0) - goto err_unwind; + fd = bpf_map_attach(map_name, &ctx->maps[i], ctx->verbose); + if (fd < 0) + return fd; - map_fds[i] = ret; + ctx->map_fds[i] = fd; } return 0; - -err_unwind: - bpf_maps_destroy(); - return ret; } -static int bpf_fill_section_data(Elf *elf_fd, GElf_Ehdr *elf_hdr, int sec_index, - struct bpf_elf_sec_data *sec_data) +static int bpf_fill_section_data(struct bpf_elf_ctx *ctx, int section, + struct bpf_elf_sec_data *data) { + Elf_Data *sec_edata; GElf_Shdr sec_hdr; Elf_Scn *sec_fd; - Elf_Data *sec_edata; char *sec_name; - memset(sec_data, 0, sizeof(*sec_data)); + memset(data, 0, sizeof(*data)); - sec_fd = elf_getscn(elf_fd, sec_index); + sec_fd = elf_getscn(ctx->elf_fd, section); if (!sec_fd) return -EINVAL; - if (gelf_getshdr(sec_fd, &sec_hdr) != &sec_hdr) return -EIO; - sec_name = elf_strptr(elf_fd, elf_hdr->e_shstrndx, + sec_name = elf_strptr(ctx->elf_fd, ctx->elf_hdr.e_shstrndx, sec_hdr.sh_name); if (!sec_name || !sec_hdr.sh_size) return -ENOENT; @@ -404,317 +922,395 @@ static int bpf_fill_section_data(Elf *elf_fd, GElf_Ehdr *elf_hdr, int sec_index, if (!sec_edata || elf_getdata(sec_fd, sec_edata)) return -EIO; - memcpy(&sec_data->sec_hdr, &sec_hdr, sizeof(sec_hdr)); - sec_data->sec_name = sec_name; - sec_data->sec_data = sec_edata; + memcpy(&data->sec_hdr, &sec_hdr, sizeof(sec_hdr)); + data->sec_name = sec_name; + data->sec_data = sec_edata; return 0; } -static int bpf_apply_relo_data(struct bpf_elf_sec_data *data_relo, - struct bpf_elf_sec_data *data_insn, - Elf_Data *sym_tab) +static int bpf_fetch_maps(struct bpf_elf_ctx *ctx, int section, + struct bpf_elf_sec_data *data) { - Elf_Data *idata = data_insn->sec_data; - GElf_Shdr *rhdr = &data_relo->sec_hdr; - int relo_ent, relo_num = rhdr->sh_size / rhdr->sh_entsize; - struct bpf_insn *insns = idata->d_buf; - unsigned int num_insns = idata->d_size / sizeof(*insns); - - for (relo_ent = 0; relo_ent < relo_num; relo_ent++) { - unsigned int ioff, fnum; - GElf_Rel relo; - GElf_Sym sym; + if (data->sec_data->d_size % sizeof(struct bpf_elf_map) != 0) + return -EINVAL; - if (gelf_getrel(data_relo->sec_data, relo_ent, &relo) != &relo) - return -EIO; + ctx->map_num = data->sec_data->d_size / sizeof(struct bpf_elf_map); + ctx->sec_maps = section; + ctx->sec_done[section] = true; - ioff = relo.r_offset / sizeof(struct bpf_insn); - if (ioff >= num_insns) - return -EINVAL; - if (insns[ioff].code != (BPF_LD | BPF_IMM | BPF_DW)) - return -EINVAL; + if (ctx->map_num > ARRAY_SIZE(ctx->map_fds)) { + fprintf(stderr, "Too many BPF maps in ELF section!\n"); + return -ENOMEM; + } - if (gelf_getsym(sym_tab, GELF_R_SYM(relo.r_info), &sym) != &sym) - return -EIO; + memcpy(ctx->maps, data->sec_data->d_buf, data->sec_data->d_size); + return 0; +} - fnum = sym.st_value / sizeof(struct bpf_elf_map); - if (fnum >= ARRAY_SIZE(map_fds)) - return -EINVAL; - if (map_fds[fnum] < 0) - return -EINVAL; +static int bpf_fetch_license(struct bpf_elf_ctx *ctx, int section, + struct bpf_elf_sec_data *data) +{ + if (data->sec_data->d_size > sizeof(ctx->license)) + return -ENOMEM; - insns[ioff].src_reg = BPF_PSEUDO_MAP_FD; - insns[ioff].imm = map_fds[fnum]; - } + memcpy(ctx->license, data->sec_data->d_buf, data->sec_data->d_size); + ctx->sec_done[section] = true; + return 0; +} +static int bpf_fetch_symtab(struct bpf_elf_ctx *ctx, int section, + struct bpf_elf_sec_data *data) +{ + ctx->sym_tab = data->sec_data; + ctx->sym_num = data->sec_hdr.sh_size / data->sec_hdr.sh_entsize; + ctx->sec_done[section] = true; return 0; } -static int bpf_fetch_ancillary(int file_fd, Elf *elf_fd, GElf_Ehdr *elf_hdr, - bool *sec_done, char *license, unsigned int lic_len, - Elf_Data **sym_tab) +static int bpf_fetch_strtab(struct bpf_elf_ctx *ctx, int section, + struct bpf_elf_sec_data *data) { - int sec_index, ret = -1; + ctx->str_tab = data->sec_data; + ctx->sec_done[section] = true; + return 0; +} - for (sec_index = 1; sec_index < elf_hdr->e_shnum; sec_index++) { - struct bpf_elf_sec_data data_anc; +static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx) +{ + struct bpf_elf_sec_data data; + int i, ret = -1; - ret = bpf_fill_section_data(elf_fd, elf_hdr, sec_index, - &data_anc); + for (i = 1; i < ctx->elf_hdr.e_shnum; i++) { + ret = bpf_fill_section_data(ctx, i, &data); if (ret < 0) continue; - /* Extract and load eBPF map fds. */ - if (!strcmp(data_anc.sec_name, ELF_SECTION_MAPS) && - !bpf_may_skip_map_creation(file_fd)) { - struct bpf_elf_map *maps; - unsigned int maps_num; - - if (data_anc.sec_data->d_size % sizeof(*maps) != 0) - return -EINVAL; - - maps = data_anc.sec_data->d_buf; - maps_num = data_anc.sec_data->d_size / sizeof(*maps); - memcpy(map_ent, maps, data_anc.sec_data->d_size); - - ret = bpf_maps_attach(maps, maps_num); - if (ret < 0) - return ret; - - sec_done[sec_index] = true; - } - /* Extract eBPF license. */ - else if (!strcmp(data_anc.sec_name, ELF_SECTION_LICENSE)) { - if (data_anc.sec_data->d_size > lic_len) - return -ENOMEM; - - sec_done[sec_index] = true; - memcpy(license, data_anc.sec_data->d_buf, - data_anc.sec_data->d_size); + if (!strcmp(data.sec_name, ELF_SECTION_MAPS)) + ret = bpf_fetch_maps(ctx, i, &data); + else if (!strcmp(data.sec_name, ELF_SECTION_LICENSE)) + ret = bpf_fetch_license(ctx, i, &data); + else if (data.sec_hdr.sh_type == SHT_SYMTAB) + ret = bpf_fetch_symtab(ctx, i, &data); + else if (data.sec_hdr.sh_type == SHT_STRTAB && + i != ctx->elf_hdr.e_shstrndx) + ret = bpf_fetch_strtab(ctx, i, &data); + if (ret < 0) { + fprintf(stderr, "Error parsing section %d! Perhaps" + "check with readelf -a?\n", i); + break; } - /* Extract symbol table for relocations (map fd fixups). */ - else if (data_anc.sec_hdr.sh_type == SHT_SYMTAB) { - sec_done[sec_index] = true; - *sym_tab = data_anc.sec_data; + } + + if (ctx->sym_tab && ctx->str_tab && ctx->sec_maps) { + ret = bpf_maps_attach_all(ctx); + if (ret < 0) { + fprintf(stderr, "Error loading maps into kernel!\n"); + return ret; } } return ret; } -static int bpf_fetch_prog_relo(Elf *elf_fd, GElf_Ehdr *elf_hdr, bool *sec_done, - enum bpf_prog_type type, const char *sec, - const char *license, Elf_Data *sym_tab) +static int bpf_fetch_prog(struct bpf_elf_ctx *ctx, const char *section) { - int sec_index, prog_fd = -1; - - for (sec_index = 1; sec_index < elf_hdr->e_shnum; sec_index++) { - struct bpf_elf_sec_data data_relo, data_insn; - int ins_index, ret; + struct bpf_elf_sec_data data; + struct bpf_elf_prog prog; + int ret, i, fd = -1; - /* Attach eBPF programs with relocation data (maps). */ - ret = bpf_fill_section_data(elf_fd, elf_hdr, sec_index, - &data_relo); - if (ret < 0 || data_relo.sec_hdr.sh_type != SHT_REL) + for (i = 1; i < ctx->elf_hdr.e_shnum; i++) { + if (ctx->sec_done[i]) continue; - ins_index = data_relo.sec_hdr.sh_info; - - ret = bpf_fill_section_data(elf_fd, elf_hdr, ins_index, - &data_insn); - if (ret < 0) - continue; - if (strcmp(data_insn.sec_name, sec)) + ret = bpf_fill_section_data(ctx, i, &data); + if (ret < 0 || strcmp(data.sec_name, section)) continue; - ret = bpf_apply_relo_data(&data_relo, &data_insn, sym_tab); - if (ret < 0) - continue; + memset(&prog, 0, sizeof(prog)); + prog.type = ctx->type; + prog.insns = data.sec_data->d_buf; + prog.size = data.sec_data->d_size; + prog.license = ctx->license; - prog_fd = bpf_prog_attach(type, sec, data_insn.sec_data->d_buf, - data_insn.sec_data->d_size, license); - if (prog_fd < 0) + fd = bpf_prog_attach(section, &prog, ctx->verbose); + if (fd < 0) continue; - sec_done[sec_index] = true; - sec_done[ins_index] = true; + ctx->sec_done[i] = true; break; } - return prog_fd; + return fd; } -static int bpf_fetch_prog(Elf *elf_fd, GElf_Ehdr *elf_hdr, bool *sec_done, - enum bpf_prog_type type, const char *sec, - const char *license) +static int bpf_apply_relo_data(struct bpf_elf_ctx *ctx, + struct bpf_elf_sec_data *data_relo, + struct bpf_elf_sec_data *data_insn) { - int sec_index, prog_fd = -1; + Elf_Data *idata = data_insn->sec_data; + GElf_Shdr *rhdr = &data_relo->sec_hdr; + int relo_ent, relo_num = rhdr->sh_size / rhdr->sh_entsize; + struct bpf_insn *insns = idata->d_buf; + unsigned int num_insns = idata->d_size / sizeof(*insns); - for (sec_index = 1; sec_index < elf_hdr->e_shnum; sec_index++) { - struct bpf_elf_sec_data data_insn; - int ret; + for (relo_ent = 0; relo_ent < relo_num; relo_ent++) { + unsigned int ioff, rmap; + GElf_Rel relo; + GElf_Sym sym; + + if (gelf_getrel(data_relo->sec_data, relo_ent, &relo) != &relo) + return -EIO; + + ioff = relo.r_offset / sizeof(struct bpf_insn); + if (ioff >= num_insns || + insns[ioff].code != (BPF_LD | BPF_IMM | BPF_DW)) + return -EINVAL; + + if (gelf_getsym(ctx->sym_tab, GELF_R_SYM(relo.r_info), &sym) != &sym) + return -EIO; + + rmap = sym.st_value / sizeof(struct bpf_elf_map); + if (rmap >= ARRAY_SIZE(ctx->map_fds)) + return -EINVAL; + if (!ctx->map_fds[rmap]) + return -EINVAL; + + if (ctx->verbose) + fprintf(stderr, "Map \'%s\' (%d) injected into prog " + "section \'%s\' at offset %u!\n", + bpf_str_tab_name(ctx, &sym), ctx->map_fds[rmap], + data_insn->sec_name, ioff); - /* Attach eBPF programs without relocation data. */ - if (sec_done[sec_index]) + insns[ioff].src_reg = BPF_PSEUDO_MAP_FD; + insns[ioff].imm = ctx->map_fds[rmap]; + } + + return 0; +} + +static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section) +{ + struct bpf_elf_sec_data data_relo, data_insn; + struct bpf_elf_prog prog; + int ret, idx, i, fd = -1; + + for (i = 1; i < ctx->elf_hdr.e_shnum; i++) { + ret = bpf_fill_section_data(ctx, i, &data_relo); + if (ret < 0 || data_relo.sec_hdr.sh_type != SHT_REL) continue; - ret = bpf_fill_section_data(elf_fd, elf_hdr, sec_index, - &data_insn); - if (ret < 0) + idx = data_relo.sec_hdr.sh_info; + ret = bpf_fill_section_data(ctx, idx, &data_insn); + if (ret < 0 || strcmp(data_insn.sec_name, section)) continue; - if (strcmp(data_insn.sec_name, sec)) + + ret = bpf_apply_relo_data(ctx, &data_relo, &data_insn); + if (ret < 0) continue; - prog_fd = bpf_prog_attach(type, sec, data_insn.sec_data->d_buf, - data_insn.sec_data->d_size, license); - if (prog_fd < 0) + memset(&prog, 0, sizeof(prog)); + prog.type = ctx->type; + prog.insns = data_insn.sec_data->d_buf; + prog.size = data_insn.sec_data->d_size; + prog.license = ctx->license; + + fd = bpf_prog_attach(section, &prog, ctx->verbose); + if (fd < 0) continue; - sec_done[sec_index] = true; + ctx->sec_done[i] = true; + ctx->sec_done[idx] = true; break; } - return prog_fd; + return fd; } -static int bpf_fetch_prog_sec(Elf *elf_fd, GElf_Ehdr *elf_hdr, bool *sec_done, - enum bpf_prog_type type, const char *sec, - const char *license, Elf_Data *sym_tab) +static int bpf_fetch_prog_sec(struct bpf_elf_ctx *ctx, const char *section) { int ret = -1; - if (sym_tab) - ret = bpf_fetch_prog_relo(elf_fd, elf_hdr, sec_done, type, - sec, license, sym_tab); + if (ctx->sym_tab) + ret = bpf_fetch_prog_relo(ctx, section); if (ret < 0) - ret = bpf_fetch_prog(elf_fd, elf_hdr, sec_done, type, sec, - license); + ret = bpf_fetch_prog(ctx, section); + return ret; } -static int bpf_fill_prog_arrays(Elf *elf_fd, GElf_Ehdr *elf_hdr, bool *sec_done, - enum bpf_prog_type type, const char *license, - Elf_Data *sym_tab) +static int bpf_fill_prog_arrays(struct bpf_elf_ctx *ctx) { - int sec_index; + struct bpf_elf_sec_data data; + uint32_t map_id, key_id; + int fd, i, ret; - for (sec_index = 1; sec_index < elf_hdr->e_shnum; sec_index++) { - struct bpf_elf_sec_data data_insn; - int ret, map_id, key_id, prog_fd; - - if (sec_done[sec_index]) + for (i = 1; i < ctx->elf_hdr.e_shnum; i++) { + if (ctx->sec_done[i]) continue; - ret = bpf_fill_section_data(elf_fd, elf_hdr, sec_index, - &data_insn); + ret = bpf_fill_section_data(ctx, i, &data); if (ret < 0) continue; - ret = sscanf(data_insn.sec_name, "%i/%i", &map_id, &key_id); - if (ret != 2) + ret = sscanf(data.sec_name, "%u/%u", &map_id, &key_id); + if (ret != 2 || map_id >= ARRAY_SIZE(ctx->map_fds) || + !ctx->map_fds[map_id]) + continue; + if (ctx->maps[map_id].type != BPF_MAP_TYPE_PROG_ARRAY || + ctx->maps[map_id].max_elem <= key_id) continue; - if (map_id >= ARRAY_SIZE(map_fds) || map_fds[map_id] < 0) - return -ENOENT; - if (map_ent[map_id].type != BPF_MAP_TYPE_PROG_ARRAY || - map_ent[map_id].max_elem <= key_id) - return -EINVAL; - - prog_fd = bpf_fetch_prog_sec(elf_fd, elf_hdr, sec_done, - type, data_insn.sec_name, - license, sym_tab); - if (prog_fd < 0) + fd = bpf_fetch_prog_sec(ctx, data.sec_name); + if (fd < 0) return -EIO; - ret = bpf_update_map(map_fds[map_id], &key_id, &prog_fd, - BPF_ANY); + ret = bpf_map_update(ctx->map_fds[map_id], &key_id, + &fd, BPF_NOEXIST); if (ret < 0) return -ENOENT; - sec_done[sec_index] = true; + ctx->sec_done[i] = true; } return 0; } -int bpf_open_object(const char *path, enum bpf_prog_type type, - const char *sec, bool verbose) +static void bpf_save_finfo(struct bpf_elf_ctx *ctx) { - char license[ELF_MAX_LICENSE_LEN]; - int file_fd, prog_fd = -1, ret; - Elf_Data *sym_tab = NULL; - GElf_Ehdr elf_hdr; - bool *sec_done; - Elf *elf_fd; + struct stat st; + int ret; - if (elf_version(EV_CURRENT) == EV_NONE) - return -EINVAL; + memset(&ctx->stat, 0, sizeof(ctx->stat)); - file_fd = open(path, O_RDONLY, 0); - if (file_fd < 0) - return -errno; + ret = fstat(ctx->obj_fd, &st); + if (ret < 0) { + fprintf(stderr, "Stat of elf file failed: %s\n", + strerror(errno)); + return; + } - elf_fd = elf_begin(file_fd, ELF_C_READ, NULL); - if (!elf_fd) { + ctx->stat.st_dev = st.st_dev; + ctx->stat.st_ino = st.st_ino; +} + +static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, + enum bpf_prog_type type, bool verbose) +{ + int ret = -EINVAL; + + if (elf_version(EV_CURRENT) == EV_NONE || + bpf_init_env(pathname)) + return ret; + + memset(ctx, 0, sizeof(*ctx)); + ctx->verbose = verbose; + ctx->type = type; + + ctx->obj_fd = open(pathname, O_RDONLY); + if (ctx->obj_fd < 0) + return ctx->obj_fd; + + ctx->elf_fd = elf_begin(ctx->obj_fd, ELF_C_READ, NULL); + if (!ctx->elf_fd) { ret = -EINVAL; - goto out; + goto out_fd; } - if (gelf_getehdr(elf_fd, &elf_hdr) != &elf_hdr) { + if (gelf_getehdr(ctx->elf_fd, &ctx->elf_hdr) != + &ctx->elf_hdr) { ret = -EIO; goto out_elf; } - sec_done = calloc(elf_hdr.e_shnum, sizeof(*sec_done)); - if (!sec_done) { + ctx->sec_done = calloc(ctx->elf_hdr.e_shnum, + sizeof(*(ctx->sec_done))); + if (!ctx->sec_done) { ret = -ENOMEM; goto out_elf; } - memset(license, 0, sizeof(license)); - bpf_verbose = verbose; + bpf_save_finfo(ctx); + return 0; +out_elf: + elf_end(ctx->elf_fd); +out_fd: + close(ctx->obj_fd); + return ret; +} - if (!bpf_may_skip_map_creation(file_fd)) - bpf_maps_init(); +static int bpf_maps_count(struct bpf_elf_ctx *ctx) +{ + int i, count = 0; - ret = bpf_fetch_ancillary(file_fd, elf_fd, &elf_hdr, sec_done, - license, sizeof(license), &sym_tab); - if (ret < 0) - goto out_maps; + for (i = 0; i < ARRAY_SIZE(ctx->map_fds); i++) { + if (!ctx->map_fds[i]) + break; + count++; + } - prog_fd = bpf_fetch_prog_sec(elf_fd, &elf_hdr, sec_done, type, - sec, license, sym_tab); - if (prog_fd < 0) - goto out_maps; + return count; +} - if (!bpf_may_skip_map_creation(file_fd)) { - ret = bpf_fill_prog_arrays(elf_fd, &elf_hdr, sec_done, - type, license, sym_tab); - if (ret < 0) - goto out_prog; +static void bpf_maps_teardown(struct bpf_elf_ctx *ctx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ctx->map_fds); i++) { + if (ctx->map_fds[i]) + close(ctx->map_fds[i]); } +} + +static void bpf_elf_ctx_destroy(struct bpf_elf_ctx *ctx, bool failure) +{ + if (failure) + bpf_maps_teardown(ctx); - bpf_save_finfo(file_fd); + free(ctx->sec_done); + elf_end(ctx->elf_fd); + close(ctx->obj_fd); +} - free(sec_done); +static struct bpf_elf_ctx __ctx; - elf_end(elf_fd); - close(file_fd); +static int bpf_obj_open(const char *pathname, enum bpf_prog_type type, + const char *section, bool verbose) +{ + struct bpf_elf_ctx *ctx = &__ctx; + int fd = 0, ret; - return prog_fd; + ret = bpf_elf_ctx_init(ctx, pathname, type, verbose); + if (ret < 0) { + fprintf(stderr, "Cannot initialize ELF context!\n"); + return ret; + } -out_prog: - close(prog_fd); -out_maps: - bpf_maps_destroy(); - free(sec_done); -out_elf: - elf_end(elf_fd); + ret = bpf_fetch_ancillary(ctx); + if (ret < 0) { + fprintf(stderr, "Error fetching ELF ancillary data!\n"); + goto out; + } + + fd = bpf_fetch_prog_sec(ctx, section); + if (fd < 0) { + fprintf(stderr, "Error fetching program/map!\n"); + ret = fd; + goto out; + } + + ret = bpf_fill_prog_arrays(ctx); + if (ret < 0) + fprintf(stderr, "Error filling program arrays!\n"); out: - close(file_fd); - bpf_clear_finfo(); - return prog_fd; + bpf_elf_ctx_destroy(ctx, ret < 0); + if (ret < 0) { + if (fd) + close(fd); + return ret; + } + + return fd; } static int @@ -803,6 +1399,7 @@ bpf_map_set_recv(int fd, int *fds, struct bpf_map_aux *aux, int bpf_send_map_fds(const char *path, const char *obj) { + struct bpf_elf_ctx *ctx = &__ctx; struct sockaddr_un addr; struct bpf_map_data bpf_aux; int fd, ret; @@ -827,18 +1424,18 @@ int bpf_send_map_fds(const char *path, const char *obj) memset(&bpf_aux, 0, sizeof(bpf_aux)); - bpf_aux.fds = map_fds; - bpf_aux.ent = map_ent; - + bpf_aux.fds = ctx->map_fds; + bpf_aux.ent = ctx->maps; + bpf_aux.st = &ctx->stat; bpf_aux.obj = obj; - bpf_aux.st = &bpf_st; ret = bpf_map_set_send(fd, &addr, sizeof(addr), &bpf_aux, - bpf_maps_count()); + bpf_maps_count(ctx)); if (ret < 0) fprintf(stderr, "Cannot send fds to %s: %s\n", path, strerror(errno)); + bpf_maps_teardown(ctx); close(fd); return ret; } diff --git a/tc/tc_bpf.h b/tc/tc_bpf.h index 2ad881219..dea3c3bc0 100644 --- a/tc/tc_bpf.h +++ b/tc/tc_bpf.h @@ -13,61 +13,56 @@ #ifndef _TC_BPF_H_ #define _TC_BPF_H_ 1 -#include #include -#include #include -#include -#include -#include -#include +#include #include "utils.h" #include "bpf_scm.h" +enum { + BPF_NLA_OPS_LEN = 0, + BPF_NLA_OPS, + BPF_NLA_FD, + BPF_NLA_NAME, + __BPF_NLA_MAX, +}; + +#define BPF_NLA_MAX __BPF_NLA_MAX + #define BPF_ENV_UDS "TC_BPF_UDS" +#define BPF_ENV_MNT "TC_BPF_MNT" +#define BPF_ENV_NOLOG "TC_BPF_NOLOG" -int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len, - char **bpf_string, bool *need_release, - const char separator); -int bpf_parse_ops(int argc, char **argv, struct sock_filter *bpf_ops, - bool from_file); -void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len); +#ifndef BPF_FS_MAGIC +# define BPF_FS_MAGIC 0xcafe4a11 +#endif +#define BPF_DIR_MNT "/sys/fs/bpf" + +#define BPF_DIR_TC "tc" +#define BPF_DIR_GLOBALS "globals" + +#ifndef TRACEFS_MAGIC +# define TRACEFS_MAGIC 0x74726163 +#endif + +#define TRACE_DIR_MNT "/sys/kernel/tracing" + +int bpf_trace_pipe(void); const char *bpf_default_section(const enum bpf_prog_type type); -#ifdef HAVE_ELF -int bpf_open_object(const char *path, enum bpf_prog_type type, - const char *sec, bool verbose); +int bpf_parse_common(int *ptr_argc, char ***ptr_argv, const int *nla_tbl, + enum bpf_prog_type type, const char **ptr_object, + const char **ptr_uds_name, struct nlmsghdr *n); +void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len); + +#ifdef HAVE_ELF int bpf_send_map_fds(const char *path, const char *obj); int bpf_recv_map_fds(const char *path, int *fds, struct bpf_map_aux *aux, unsigned int entries); - -static inline __u64 bpf_ptr_to_u64(const void *ptr) -{ - return (__u64) (unsigned long) ptr; -} - -static inline int bpf(int cmd, union bpf_attr *attr, unsigned int size) -{ -#ifdef __NR_bpf - return syscall(__NR_bpf, cmd, attr, size); #else - fprintf(stderr, "No bpf syscall, kernel headers too old?\n"); - errno = ENOSYS; - return -1; -#endif -} -#else -static inline int bpf_open_object(const char *path, enum bpf_prog_type type, - const char *sec, bool verbose) -{ - fprintf(stderr, "No ELF library support compiled in.\n"); - errno = ENOSYS; - return -1; -} - static inline int bpf_send_map_fds(const char *path, const char *obj) { return 0; From 6581df5ef361bdce6b0b0128e83517a84217965d Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 24 Sep 2015 14:39:39 -0400 Subject: [PATCH 003/513] geneve: add support for IPv6 link partners Signed-off-by: John W. Linville --- ip/iplink_geneve.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c index 331240a6a..13454795d 100644 --- a/ip/iplink_geneve.c +++ b/ip/iplink_geneve.c @@ -55,7 +55,7 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, fprintf(stderr, "Invalid address \"%s\"\n", *argv); return -1; } - if (IN_MULTICAST(ntohl(daddr))) + if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr))) invarg("invalid remote address", *argv); } else if (!matches(*argv, "ttl") || !matches(*argv, "hoplimit")) { @@ -96,18 +96,16 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, return -1; } - if (!daddr) { - fprintf(stderr, "geneve: remove link partner not specified\n"); - return -1; - } - if (memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) != 0) { - fprintf(stderr, "geneve: remove link over IPv6 not supported\n"); + if (!daddr && memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) == 0) { + fprintf(stderr, "geneve: remote link partner not specified\n"); return -1; } addattr32(n, 1024, IFLA_GENEVE_ID, vni); if (daddr) addattr_l(n, 1024, IFLA_GENEVE_REMOTE, &daddr, 4); + if (memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) != 0) + addattr_l(n, 1024, IFLA_GENEVE_REMOTE6, &daddr6, sizeof(struct in6_addr)); addattr8(n, 1024, IFLA_GENEVE_TTL, ttl); addattr8(n, 1024, IFLA_GENEVE_TOS, tos); @@ -135,6 +133,14 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (addr) fprintf(f, "remote %s ", format_host(AF_INET, 4, &addr, s1, sizeof(s1))); + } else if (tb[IFLA_GENEVE_REMOTE6]) { + struct in6_addr addr; + memcpy(&addr, RTA_DATA(tb[IFLA_GENEVE_REMOTE6]), sizeof(struct in6_addr)); + if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) { + if (IN6_IS_ADDR_MULTICAST(&addr)) + fprintf(f, "remote %s ", + format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1))); + } } if (tb[IFLA_GENEVE_TTL]) { From 910b543dcce52290ce723758e1d9bb436188a26b Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 26 Nov 2015 15:38:42 +0100 Subject: [PATCH 004/513] {f,m}_bpf: make tail calls working Now that we have the possibility of sharing maps, it's time we get the ELF loader fully working with regards to tail calls. Since program array maps are pinned, we can keep them finally alive. I've noticed two bugs that are being fixed in bpf_fill_prog_arrays() with this patch. Example code comes as follow-up. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov --- tc/tc_bpf.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index bc7bc9ffa..c3adc23c0 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -1139,11 +1139,22 @@ static int bpf_fetch_prog_sec(struct bpf_elf_ctx *ctx, const char *section) return ret; } +static int bpf_find_map_by_id(struct bpf_elf_ctx *ctx, uint32_t id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ctx->map_fds); i++) + if (ctx->map_fds[i] && ctx->maps[i].id == id && + ctx->maps[i].type == BPF_MAP_TYPE_PROG_ARRAY) + return i; + return -1; +} + static int bpf_fill_prog_arrays(struct bpf_elf_ctx *ctx) { struct bpf_elf_sec_data data; uint32_t map_id, key_id; - int fd, i, ret; + int fd, i, ret, idx; for (i = 1; i < ctx->elf_hdr.e_shnum; i++) { if (ctx->sec_done[i]) @@ -1153,20 +1164,20 @@ static int bpf_fill_prog_arrays(struct bpf_elf_ctx *ctx) if (ret < 0) continue; - ret = sscanf(data.sec_name, "%u/%u", &map_id, &key_id); - if (ret != 2 || map_id >= ARRAY_SIZE(ctx->map_fds) || - !ctx->map_fds[map_id]) + ret = sscanf(data.sec_name, "%i/%i", &map_id, &key_id); + if (ret != 2) continue; - if (ctx->maps[map_id].type != BPF_MAP_TYPE_PROG_ARRAY || - ctx->maps[map_id].max_elem <= key_id) + + idx = bpf_find_map_by_id(ctx, map_id); + if (idx < 0) continue; fd = bpf_fetch_prog_sec(ctx, data.sec_name); if (fd < 0) return -EIO; - ret = bpf_map_update(ctx->map_fds[map_id], &key_id, - &fd, BPF_NOEXIST); + ret = bpf_map_update(ctx->map_fds[idx], &key_id, + &fd, BPF_ANY); if (ret < 0) return -ENOENT; From 9e607f2e722604a57a2c1ec9a174fcc505d9c451 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 26 Nov 2015 15:38:43 +0100 Subject: [PATCH 005/513] {f, m}_bpf: check map attributes when fetching as pinned Make use of the new show_fdinfo() facility and verify that when a pinned map is being fetched that its basic attributes are the same as the map we declared from the ELF file. I.e. when placed into the globalns, collisions could occur. In such a case warn the user and bail out. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov --- tc/tc_bpf.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index c3adc23c0..b44b12374 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -205,6 +205,52 @@ void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len) ops[i].jf, ops[i].k); } +static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map) +{ + char file[PATH_MAX], buff[4096]; + struct bpf_elf_map tmp, zero; + unsigned int val; + FILE *fp; + + snprintf(file, sizeof(file), "/proc/%d/fdinfo/%d", getpid(), fd); + + fp = fopen(file, "r"); + if (!fp) { + fprintf(stderr, "No procfs support?!\n"); + return -EIO; + } + + memset(&tmp, 0, sizeof(tmp)); + while (fgets(buff, sizeof(buff), fp)) { + if (sscanf(buff, "map_type:\t%u", &val) == 1) + tmp.type = val; + else if (sscanf(buff, "key_size:\t%u", &val) == 1) + tmp.size_key = val; + else if (sscanf(buff, "value_size:\t%u", &val) == 1) + tmp.size_value = val; + else if (sscanf(buff, "max_entries:\t%u", &val) == 1) + tmp.max_elem = val; + } + + fclose(fp); + + if (!memcmp(&tmp, map, offsetof(struct bpf_elf_map, id))) { + return 0; + } else { + memset(&zero, 0, sizeof(zero)); + /* If kernel doesn't have eBPF-related fdinfo, we cannot do much, + * so just accept it. We know we do have an eBPF fd and in this + * case, everything is 0. It is guaranteed that no such map exists + * since map type of 0 is unloadable BPF_MAP_TYPE_UNSPEC. + */ + if (!memcmp(&tmp, &zero, offsetof(struct bpf_elf_map, id))) + return 0; + + fprintf(stderr, "Map specs from pinned file differ!\n"); + return -EINVAL; + } +} + static int bpf_valid_mntpt(const char *mnt, unsigned long magic) { struct statfs st_fs; @@ -816,6 +862,13 @@ static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, fd = bpf_probe_pinned(name, map->pinning); if (fd > 0) { + ret = bpf_map_selfcheck_pinned(fd, map); + if (ret < 0) { + close(fd); + fprintf(stderr, "Map \'%s\' self-check failed!\n", + name); + return ret; + } if (verbose) fprintf(stderr, "Map \'%s\' loaded as pinned!\n", name); From f6793eec4600a9f9428026ed75c50a44eeb3c83f Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 26 Nov 2015 15:38:44 +0100 Subject: [PATCH 006/513] {f, m}_bpf: allow for user-defined object pinnings The recently introduced object pinning can be further extended in order to allow sharing maps beyond tc namespace. F.e. maps that are being pinned from tracing side, can be accessed through this facility as well. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov --- etc/iproute2/bpf_pinning | 6 ++ include/bpf_elf.h | 2 +- include/utils.h | 4 + lib/rt_names.c | 5 +- tc/tc_bpf.c | 212 +++++++++++++++++++++++++++++++++++---- 5 files changed, 204 insertions(+), 25 deletions(-) create mode 100644 etc/iproute2/bpf_pinning diff --git a/etc/iproute2/bpf_pinning b/etc/iproute2/bpf_pinning new file mode 100644 index 000000000..2b39c709f --- /dev/null +++ b/etc/iproute2/bpf_pinning @@ -0,0 +1,6 @@ +# +# subpath mappings from mount point for pinning +# +#3 tracing +#4 foo/bar +#5 tc/cls1 diff --git a/include/bpf_elf.h b/include/bpf_elf.h index 0690dd6ae..31a897437 100644 --- a/include/bpf_elf.h +++ b/include/bpf_elf.h @@ -33,7 +33,7 @@ struct bpf_elf_map { __u32 size_value; __u32 max_elem; __u32 id; - __u8 pinning; + __u32 pinning; }; #endif /* __BPF_ELF__ */ diff --git a/include/utils.h b/include/utils.h index 5902a9850..e830be640 100644 --- a/include/utils.h +++ b/include/utils.h @@ -40,6 +40,10 @@ extern bool do_all; #define IPSEC_PROTO_ANY 255 #endif +#ifndef CONFDIR +#define CONFDIR "/etc/iproute2" +#endif + #define SPRINT_BSIZE 64 #define SPRINT_BUF(x) char x[SPRINT_BSIZE] diff --git a/lib/rt_names.c b/lib/rt_names.c index 1071a9383..f6d17c0e5 100644 --- a/lib/rt_names.c +++ b/lib/rt_names.c @@ -23,10 +23,7 @@ #include #include "rt_names.h" - -#ifndef CONFDIR -#define CONFDIR "/etc/iproute2" -#endif +#include "utils.h" #define NAME_MAX_LEN 512 diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index b44b12374..17c04e9b1 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -458,6 +458,12 @@ struct bpf_elf_prog { const char *license; }; +struct bpf_hash_entry { + unsigned int pinning; + const char *subpath; + struct bpf_hash_entry *next; +}; + struct bpf_elf_ctx { Elf *elf_fd; GElf_Ehdr elf_hdr; @@ -474,6 +480,7 @@ struct bpf_elf_ctx { enum bpf_prog_type type; bool verbose; struct bpf_elf_st stat; + struct bpf_hash_entry *ht[256]; }; struct bpf_elf_sec_data { @@ -771,20 +778,34 @@ static int bpf_init_env(const char *pathname) return 0; } -static bool bpf_no_pinning(int pinning) +static const char *bpf_custom_pinning(const struct bpf_elf_ctx *ctx, + uint32_t pinning) +{ + struct bpf_hash_entry *entry; + + entry = ctx->ht[pinning & (ARRAY_SIZE(ctx->ht) - 1)]; + while (entry && entry->pinning != pinning) + entry = entry->next; + + return entry ? entry->subpath : NULL; +} + +static bool bpf_no_pinning(const struct bpf_elf_ctx *ctx, + uint32_t pinning) { switch (pinning) { case PIN_OBJECT_NS: case PIN_GLOBAL_NS: return false; case PIN_NONE: - default: return true; + default: + return !bpf_custom_pinning(ctx, pinning); } } static void bpf_make_pathname(char *pathname, size_t len, const char *name, - int pinning) + const struct bpf_elf_ctx *ctx, uint32_t pinning) { switch (pinning) { case PIN_OBJECT_NS: @@ -795,41 +816,89 @@ static void bpf_make_pathname(char *pathname, size_t len, const char *name, snprintf(pathname, len, "%s/%s/%s", bpf_get_tc_dir(), BPF_DIR_GLOBALS, name); break; + default: + snprintf(pathname, len, "%s/../%s/%s", bpf_get_tc_dir(), + bpf_custom_pinning(ctx, pinning), name); + break; } } -static int bpf_probe_pinned(const char *name, int pinning) +static int bpf_probe_pinned(const char *name, const struct bpf_elf_ctx *ctx, + uint32_t pinning) { char pathname[PATH_MAX]; - if (bpf_no_pinning(pinning) || !bpf_get_tc_dir()) + if (bpf_no_pinning(ctx, pinning) || !bpf_get_tc_dir()) return 0; - bpf_make_pathname(pathname, sizeof(pathname), name, pinning); + bpf_make_pathname(pathname, sizeof(pathname), name, ctx, pinning); return bpf_obj_get(pathname); } -static int bpf_place_pinned(int fd, const char *name, int pinning) +static int bpf_make_obj_path(void) { - char pathname[PATH_MAX]; + char tmp[PATH_MAX]; int ret; - if (bpf_no_pinning(pinning) || !bpf_get_tc_dir()) - return 0; + snprintf(tmp, sizeof(tmp), "%s/%s", bpf_get_tc_dir(), + bpf_get_obj_uid(NULL)); + + ret = mkdir(tmp, S_IRWXU); + if (ret && errno != EEXIST) { + fprintf(stderr, "mkdir %s failed: %s\n", tmp, strerror(errno)); + return ret; + } + + return 0; +} + +static int bpf_make_custom_path(const char *todo) +{ + char tmp[PATH_MAX], rem[PATH_MAX], *sub; + int ret; + + snprintf(tmp, sizeof(tmp), "%s/../", bpf_get_tc_dir()); + snprintf(rem, sizeof(rem), "%s/", todo); + sub = strtok(rem, "/"); - if (pinning == PIN_OBJECT_NS) { - snprintf(pathname, sizeof(pathname), "%s/%s", - bpf_get_tc_dir(), bpf_get_obj_uid(NULL)); + while (sub) { + if (strlen(tmp) + strlen(sub) + 2 > PATH_MAX) + return -EINVAL; + + strcat(tmp, sub); + strcat(tmp, "/"); - ret = mkdir(pathname, S_IRWXU); + ret = mkdir(tmp, S_IRWXU); if (ret && errno != EEXIST) { - fprintf(stderr, "mkdir %s failed: %s\n", pathname, + fprintf(stderr, "mkdir %s failed: %s\n", tmp, strerror(errno)); return ret; } + + sub = strtok(NULL, "/"); } - bpf_make_pathname(pathname, sizeof(pathname), name, pinning); + return 0; +} + +static int bpf_place_pinned(int fd, const char *name, + const struct bpf_elf_ctx *ctx, uint32_t pinning) +{ + char pathname[PATH_MAX]; + const char *tmp; + int ret = 0; + + if (bpf_no_pinning(ctx, pinning) || !bpf_get_tc_dir()) + return 0; + + if (pinning == PIN_OBJECT_NS) + ret = bpf_make_obj_path(); + else if ((tmp = bpf_custom_pinning(ctx, pinning))) + ret = bpf_make_custom_path(tmp); + if (ret < 0) + return ret; + + bpf_make_pathname(pathname, sizeof(pathname), name, ctx, pinning); return bpf_obj_pin(fd, pathname); } @@ -856,11 +925,11 @@ static int bpf_prog_attach(const char *section, } static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, - bool verbose) + const struct bpf_elf_ctx *ctx, bool verbose) { int fd, ret; - fd = bpf_probe_pinned(name, map->pinning); + fd = bpf_probe_pinned(name, ctx, map->pinning); if (fd > 0) { ret = bpf_map_selfcheck_pinned(fd, map); if (ret < 0) { @@ -889,7 +958,7 @@ static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, return fd; } - ret = bpf_place_pinned(fd, name, map->pinning); + ret = bpf_place_pinned(fd, name, ctx, map->pinning); if (ret < 0 && errno != EEXIST) { fprintf(stderr, "Could not pin %s map: %s\n", name, strerror(errno)); @@ -940,7 +1009,8 @@ static int bpf_maps_attach_all(struct bpf_elf_ctx *ctx) if (!map_name) return -EIO; - fd = bpf_map_attach(map_name, &ctx->maps[i], ctx->verbose); + fd = bpf_map_attach(map_name, &ctx->maps[i], ctx, + ctx->verbose); if (fd < 0) return fd; @@ -1258,6 +1328,105 @@ static void bpf_save_finfo(struct bpf_elf_ctx *ctx) ctx->stat.st_ino = st.st_ino; } +static int bpf_read_pin_mapping(FILE *fp, uint32_t *id, char *path) +{ + char buff[PATH_MAX]; + + while (fgets(buff, sizeof(buff), fp)) { + char *ptr = buff; + + while (*ptr == ' ' || *ptr == '\t') + ptr++; + + if (*ptr == '#' || *ptr == '\n' || *ptr == 0) + continue; + + if (sscanf(ptr, "%i %s\n", id, path) != 2 && + sscanf(ptr, "%i %s #", id, path) != 2) { + strcpy(path, ptr); + return -1; + } + + return 1; + } + + return 0; +} + +static bool bpf_pinning_reserved(uint32_t pinning) +{ + switch (pinning) { + case PIN_NONE: + case PIN_OBJECT_NS: + case PIN_GLOBAL_NS: + return true; + default: + return false; + } +} + +static void bpf_hash_init(struct bpf_elf_ctx *ctx, const char *db_file) +{ + struct bpf_hash_entry *entry; + char subpath[PATH_MAX]; + uint32_t pinning; + FILE *fp; + int ret; + + fp = fopen(db_file, "r"); + if (!fp) + return; + + memset(subpath, 0, sizeof(subpath)); + while ((ret = bpf_read_pin_mapping(fp, &pinning, subpath))) { + if (ret == -1) { + fprintf(stderr, "Database %s is corrupted at: %s\n", + db_file, subpath); + fclose(fp); + return; + } + + if (bpf_pinning_reserved(pinning)) { + fprintf(stderr, "Database %s, id %u is reserved - " + "ignoring!\n", db_file, pinning); + continue; + } + + entry = malloc(sizeof(*entry)); + if (!entry) { + fprintf(stderr, "No memory left for db entry!\n"); + continue; + } + + entry->pinning = pinning; + entry->subpath = strdup(subpath); + if (!entry->subpath) { + fprintf(stderr, "No memory left for db entry!\n"); + free(entry); + continue; + } + + entry->next = ctx->ht[pinning & (ARRAY_SIZE(ctx->ht) - 1)]; + ctx->ht[pinning & (ARRAY_SIZE(ctx->ht) - 1)] = entry; + } + + fclose(fp); +} + +static void bpf_hash_destroy(struct bpf_elf_ctx *ctx) +{ + struct bpf_hash_entry *entry; + int i; + + for (i = 0; i < ARRAY_SIZE(ctx->ht); i++) { + while ((entry = ctx->ht[i]) != NULL) { + ctx->ht[i] = entry->next; + free((char *)entry->subpath); + free(entry); + } + } +} + static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, enum bpf_prog_type type, bool verbose) { @@ -1295,6 +1464,8 @@ static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, } bpf_save_finfo(ctx); + bpf_hash_init(ctx, CONFDIR "/bpf_pinning"); + return 0; out_elf: elf_end(ctx->elf_fd); @@ -1331,6 +1502,7 @@ static void bpf_elf_ctx_destroy(struct bpf_elf_ctx *ctx, bool failure) if (failure) bpf_maps_teardown(ctx); + bpf_hash_destroy(ctx); free(ctx->sec_done); elf_end(ctx->elf_fd); close(ctx->obj_fd); From 91d88eeb10cd4f51e3b5c675c7aee4ae1e41ff16 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 26 Nov 2015 15:38:45 +0100 Subject: [PATCH 007/513] {f,m}_bpf: allow updates on program arrays Since we have all infrastructure in place now, allow atomic live updates on program arrays. This can be very useful e.g. in case programs that are being tail-called need to be replaced, f.e. when classifier functionality needs to be changed, new protocols added/removed during runtime, etc. Thus, provide a way for in-place code updates, minimal example: Given is an object file cls.o that contains the entry point in section 'classifier', has a globally pinned program array 'jmp' with 2 slots and id of 0, and two tail called programs under section '0/0' (prog array key 0) and '0/1' (prog array key 1), the section encoding for the loader is . Adding the filter loads everything into cls_bpf: tc filter add dev foo parent ffff: bpf da obj cls.o Now, the program under section '0/1' needs to be replaced with an updated version that resides in the same section (also full path to tc's subfolder of the mount point can be passed, e.g. /sys/fs/bpf/tc/globals/jmp): tc exec bpf graft m:globals/jmp obj cls.o sec 0/1 In case the program resides under a different section 'foo', it can also be injected into the program array like: tc exec bpf graft m:globals/jmp key 1 obj cls.o sec foo If the new tail called classifier program is already available as a pinned object somewhere (here: /sys/fs/bpf/tc/progs/parser), it can be injected into the prog array like: tc exec bpf graft m:globals/jmp key 1 fd m:progs/parser In the kernel, the program on key 1 is being atomically replaced and the old one's refcount dropped. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov --- tc/e_bpf.c | 30 +++- tc/tc_bpf.c | 424 ++++++++++++++++++++++++++++++++++------------------ tc/tc_bpf.h | 1 + 3 files changed, 306 insertions(+), 149 deletions(-) diff --git a/tc/e_bpf.c b/tc/e_bpf.c index 1f386c360..2d650a46c 100644 --- a/tc/e_bpf.c +++ b/tc/e_bpf.c @@ -26,10 +26,19 @@ static char *argv_default[] = { BPF_DEFAULT_CMD, NULL }; static void explain(void) { - fprintf(stderr, "Usage: ... bpf [ import UDS_FILE ] [ run CMD ] [ debug ]\n\n"); + fprintf(stderr, "Usage: ... bpf [ import UDS_FILE ] [ run CMD ]\n"); + fprintf(stderr, " ... bpf [ debug ]\n"); + fprintf(stderr, " ... bpf [ graft MAP_FILE ] [ key KEY ]\n"); + fprintf(stderr, " `... [ object-file OBJ_FILE ] [ type TYPE ] [ section NAME ] [ verbose ]\n"); + fprintf(stderr, " `... [ object-pinned PROG_FILE ]\n"); + fprintf(stderr, "\n"); fprintf(stderr, "Where UDS_FILE provides the name of a unix domain socket file\n"); fprintf(stderr, "to import eBPF maps and the optional CMD denotes the command\n"); fprintf(stderr, "to be executed (default: \'%s\').\n", BPF_DEFAULT_CMD); + fprintf(stderr, "Where MAP_FILE points to a pinned map, OBJ_FILE to an object file\n"); + fprintf(stderr, "and PROG_FILE to a pinned program. TYPE can be {cls, act}, where\n"); + fprintf(stderr, "\'cls\' is default. KEY is optional and can be inferred from the\n"); + fprintf(stderr, "section name, otherwise it needs to be provided.\n"); } static int bpf_num_env_entries(void) @@ -67,6 +76,25 @@ static int parse_bpf(struct exec_util *eu, int argc, char **argv) fprintf(stderr, "No trace pipe, tracefs not mounted?\n"); return -1; + } else if (matches(*argv, "graft") == 0) { + const char *bpf_map_path; + bool has_key = false; + uint32_t key; + + NEXT_ARG(); + bpf_map_path = *argv; + NEXT_ARG(); + if (matches(*argv, "key") == 0) { + NEXT_ARG(); + if (get_unsigned(&key, *argv, 0)) { + fprintf(stderr, "Illegal \"key\"\n"); + return -1; + } + has_key = true; + NEXT_ARG(); + } + return bpf_graft_map(bpf_map_path, has_key ? + &key : NULL, argc, argv); } else { explain(); return -1; diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index 17c04e9b1..beb74be6c 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -76,13 +76,17 @@ static int bpf(int cmd, union bpf_attr *attr, unsigned int size) #endif } -static int bpf_obj_get(const char *pathname) +static int bpf_map_update(int fd, const void *key, const void *value, + uint64_t flags) { union bpf_attr attr = { - .pathname = bpf_ptr_to_u64(pathname), + .map_fd = fd, + .key = bpf_ptr_to_u64(key), + .value = bpf_ptr_to_u64(value), + .flags = flags, }; - return bpf(BPF_OBJ_GET, &attr, sizeof(attr)); + return bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); } static int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len, @@ -205,7 +209,8 @@ void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len) ops[i].jf, ops[i].k); } -static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map) +static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, + int length) { char file[PATH_MAX], buff[4096]; struct bpf_elf_map tmp, zero; @@ -234,7 +239,7 @@ static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map) fclose(fp); - if (!memcmp(&tmp, map, offsetof(struct bpf_elf_map, id))) { + if (!memcmp(&tmp, map, length)) { return 0; } else { memset(&zero, 0, sizeof(zero)); @@ -243,7 +248,7 @@ static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map) * case, everything is 0. It is guaranteed that no such map exists * since map type of 0 is unloadable BPF_MAP_TYPE_UNSPEC. */ - if (!memcmp(&tmp, &zero, offsetof(struct bpf_elf_map, id))) + if (!memcmp(&tmp, &zero, length)) return 0; fprintf(stderr, "Map specs from pinned file differ!\n"); @@ -251,6 +256,35 @@ static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map) } } +static int bpf_mnt_fs(const char *target) +{ + bool bind_done = false; + + while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) { + if (errno != EINVAL || bind_done) { + fprintf(stderr, "mount --make-private %s failed: %s\n", + target, strerror(errno)); + return -1; + } + + if (mount(target, target, "none", MS_BIND, NULL)) { + fprintf(stderr, "mount --bind %s %s failed: %s\n", + target, target, strerror(errno)); + return -1; + } + + bind_done = true; + } + + if (mount("bpf", target, "bpf", 0, NULL)) { + fprintf(stderr, "mount -t bpf bpf %s failed: %s\n", + target, strerror(errno)); + return -1; + } + + return 0; +} + static int bpf_valid_mntpt(const char *mnt, unsigned long magic) { struct statfs st_fs; @@ -342,6 +376,79 @@ int bpf_trace_pipe(void) return 0; } +static const char *bpf_get_tc_dir(void) +{ + static bool bpf_mnt_cached = false; + static char bpf_tc_dir[PATH_MAX]; + static const char *mnt; + static const char * const bpf_known_mnts[] = { + BPF_DIR_MNT, + 0, + }; + char bpf_mnt[PATH_MAX] = BPF_DIR_MNT; + char bpf_glo_dir[PATH_MAX]; + int ret; + + if (bpf_mnt_cached) + goto done; + + mnt = bpf_find_mntpt("bpf", BPF_FS_MAGIC, bpf_mnt, sizeof(bpf_mnt), + bpf_known_mnts); + if (!mnt) { + mnt = getenv(BPF_ENV_MNT); + if (!mnt) + mnt = BPF_DIR_MNT; + ret = bpf_mnt_fs(mnt); + if (ret) { + mnt = NULL; + goto out; + } + } + + snprintf(bpf_tc_dir, sizeof(bpf_tc_dir), "%s/%s", mnt, BPF_DIR_TC); + ret = mkdir(bpf_tc_dir, S_IRWXU); + if (ret && errno != EEXIST) { + fprintf(stderr, "mkdir %s failed: %s\n", bpf_tc_dir, + strerror(errno)); + mnt = NULL; + goto out; + } + + snprintf(bpf_glo_dir, sizeof(bpf_glo_dir), "%s/%s", + bpf_tc_dir, BPF_DIR_GLOBALS); + ret = mkdir(bpf_glo_dir, S_IRWXU); + if (ret && errno != EEXIST) { + fprintf(stderr, "mkdir %s failed: %s\n", bpf_glo_dir, + strerror(errno)); + mnt = NULL; + goto out; + } + + mnt = bpf_tc_dir; +out: + bpf_mnt_cached = true; +done: + return mnt; +} + +static int bpf_obj_get(const char *pathname) +{ + union bpf_attr attr; + char tmp[PATH_MAX]; + + if (strlen(pathname) > 2 && pathname[0] == 'm' && + pathname[1] == ':' && bpf_get_tc_dir()) { + snprintf(tmp, sizeof(tmp), "%s/%s", + bpf_get_tc_dir(), pathname + 2); + pathname = tmp; + } + + memset(&attr, 0, sizeof(attr)); + attr.pathname = bpf_ptr_to_u64(pathname); + + return bpf(BPF_OBJ_GET, &attr, sizeof(attr)); +} + const char *bpf_default_section(const enum bpf_prog_type type) { switch (type) { @@ -354,37 +461,45 @@ const char *bpf_default_section(const enum bpf_prog_type type) } } -int bpf_parse_common(int *ptr_argc, char ***ptr_argv, const int *nla_tbl, - enum bpf_prog_type type, const char **ptr_object, - const char **ptr_uds_name, struct nlmsghdr *n) +enum bpf_mode { + CBPF_BYTECODE = 0, + CBPF_FILE, + EBPF_OBJECT, + EBPF_PINNED, + __BPF_MODE_MAX, +#define BPF_MODE_MAX __BPF_MODE_MAX +}; + +static int bpf_parse(int *ptr_argc, char ***ptr_argv, const bool *opt_tbl, + enum bpf_prog_type *type, enum bpf_mode *mode, + const char **ptr_object, const char **ptr_section, + const char **ptr_uds_name, struct sock_filter *opcodes) { - struct sock_filter opcodes[BPF_MAXINSNS]; const char *file, *section, *uds_name; - char **argv = *ptr_argv; - int argc = *ptr_argc; - char annotation[256]; bool verbose = false; - int ret; - enum bpf_mode { - CBPF_BYTECODE, - CBPF_FILE, - EBPF_OBJECT, - EBPF_PINNED, - } mode; - - if (matches(*argv, "bytecode") == 0 || - strcmp(*argv, "bc") == 0) { - mode = CBPF_BYTECODE; - } else if (matches(*argv, "bytecode-file") == 0 || - strcmp(*argv, "bcf") == 0) { - mode = CBPF_FILE; - } else if (matches(*argv, "object-file") == 0 || - strcmp(*argv, "obj") == 0) { - mode = EBPF_OBJECT; - } else if (matches(*argv, "object-pinned") == 0 || - matches(*argv, "pinned") == 0 || - matches(*argv, "fd") == 0) { - mode = EBPF_PINNED; + int ret, argc; + char **argv; + + argv = *ptr_argv; + argc = *ptr_argc; + + if (opt_tbl[CBPF_BYTECODE] && + (matches(*argv, "bytecode") == 0 || + strcmp(*argv, "bc") == 0)) { + *mode = CBPF_BYTECODE; + } else if (opt_tbl[CBPF_FILE] && + (matches(*argv, "bytecode-file") == 0 || + strcmp(*argv, "bcf") == 0)) { + *mode = CBPF_FILE; + } else if (opt_tbl[EBPF_OBJECT] && + (matches(*argv, "object-file") == 0 || + strcmp(*argv, "obj") == 0)) { + *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; } else { fprintf(stderr, "What mode is \"%s\"?\n", *argv); return -1; @@ -392,11 +507,29 @@ int bpf_parse_common(int *ptr_argc, char ***ptr_argv, const int *nla_tbl, NEXT_ARG(); file = section = uds_name = NULL; - if (mode == EBPF_OBJECT || mode == EBPF_PINNED) { + if (*mode == EBPF_OBJECT || *mode == EBPF_PINNED) { file = *argv; NEXT_ARG_FWD(); - section = bpf_default_section(type); + if (*type == BPF_PROG_TYPE_UNSPEC) { + if (argc > 0 && matches(*argv, "type") == 0) { + NEXT_ARG(); + if (matches(*argv, "cls") == 0) { + *type = BPF_PROG_TYPE_SCHED_CLS; + } else if (matches(*argv, "act") == 0) { + *type = BPF_PROG_TYPE_SCHED_ACT; + } else { + fprintf(stderr, "What type is \"%s\"?\n", + *argv); + return -1; + } + NEXT_ARG_FWD(); + } else { + *type = BPF_PROG_TYPE_SCHED_CLS; + } + } + + section = bpf_default_section(*type); if (argc > 0 && matches(*argv, "section") == 0) { NEXT_ARG(); section = *argv; @@ -419,35 +552,125 @@ int bpf_parse_common(int *ptr_argc, char ***ptr_argv, const int *nla_tbl, PREV_ARG(); } - if (mode == CBPF_BYTECODE || mode == CBPF_FILE) - ret = bpf_ops_parse(argc, argv, opcodes, mode == CBPF_FILE); - else if (mode == EBPF_OBJECT) - ret = bpf_obj_open(file, type, section, verbose); - else if (mode == EBPF_PINNED) + if (*mode == CBPF_BYTECODE || *mode == CBPF_FILE) + ret = bpf_ops_parse(argc, argv, opcodes, *mode == CBPF_FILE); + else if (*mode == EBPF_OBJECT) + ret = bpf_obj_open(file, *type, section, verbose); + else if (*mode == EBPF_PINNED) ret = bpf_obj_get(file); - if (ret < 0) + else return -1; + if (ptr_object) + *ptr_object = file; + if (ptr_section) + *ptr_section = section; + if (ptr_uds_name) + *ptr_uds_name = uds_name; + + *ptr_argc = argc; + *ptr_argv = argv; + + return ret; +} + +int bpf_parse_common(int *ptr_argc, char ***ptr_argv, const int *nla_tbl, + enum bpf_prog_type type, const char **ptr_object, + const char **ptr_uds_name, struct nlmsghdr *n) +{ + struct sock_filter opcodes[BPF_MAXINSNS]; + const bool opt_tbl[BPF_MODE_MAX] = { + [CBPF_BYTECODE] = true, + [CBPF_FILE] = true, + [EBPF_OBJECT] = true, + [EBPF_PINNED] = true, + }; + char annotation[256]; + const char *section; + enum bpf_mode mode; + int ret; + + ret = bpf_parse(ptr_argc, ptr_argv, opt_tbl, &type, &mode, + ptr_object, §ion, ptr_uds_name, opcodes); + if (ret < 0) + return ret; + if (mode == CBPF_BYTECODE || mode == CBPF_FILE) { addattr16(n, MAX_MSG, nla_tbl[BPF_NLA_OPS_LEN], ret); addattr_l(n, MAX_MSG, nla_tbl[BPF_NLA_OPS], opcodes, ret * sizeof(struct sock_filter)); - } else if (mode == EBPF_OBJECT || mode == EBPF_PINNED) { + } + + if (mode == EBPF_OBJECT || mode == EBPF_PINNED) { snprintf(annotation, sizeof(annotation), "%s:[%s]", - basename(file), mode == EBPF_PINNED ? "*fsobj" : - section); + basename(*ptr_object), mode == EBPF_PINNED ? + "*fsobj" : section); addattr32(n, MAX_MSG, nla_tbl[BPF_NLA_FD], ret); addattrstrz(n, MAX_MSG, nla_tbl[BPF_NLA_NAME], annotation); } - *ptr_object = file; - *ptr_uds_name = uds_name; + return 0; +} - *ptr_argc = argc; - *ptr_argv = argv; +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] = { + [CBPF_BYTECODE] = false, + [CBPF_FILE] = false, + [EBPF_OBJECT] = true, + [EBPF_PINNED] = true, + }; + const struct bpf_elf_map test = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .size_key = sizeof(int), + .size_value = sizeof(int), + }; + int ret, prog_fd, map_fd; + const char *section; + enum bpf_mode mode; + uint32_t map_key; + + prog_fd = bpf_parse(&argc, &argv, opt_tbl, &type, &mode, + NULL, §ion, NULL, NULL); + if (prog_fd < 0) + return prog_fd; + if (key) { + map_key = *key; + } else { + ret = sscanf(section, "%*i/%i", &map_key); + if (ret != 1) { + fprintf(stderr, "Couldn\'t infer map key from section " + "name! Please provide \'key\' argument!\n"); + ret = -EINVAL; + goto out_prog; + } + } - return 0; + map_fd = bpf_obj_get(map_path); + if (map_fd < 0) { + fprintf(stderr, "Couldn\'t retrieve pinned map \'%s\': %s\n", + map_path, strerror(errno)); + ret = map_fd; + goto out_prog; + } + + ret = bpf_map_selfcheck_pinned(map_fd, &test, + offsetof(struct bpf_elf_map, max_elem)); + if (ret < 0) { + fprintf(stderr, "Map \'%s\' self-check failed!\n", map_path); + goto out_map; + } + + ret = bpf_map_update(map_fd, &map_key, &prog_fd, BPF_ANY); + if (ret < 0) + fprintf(stderr, "Map update failed: %s\n", strerror(errno)); +out_map: + close(map_fd); +out_prog: + close(prog_fd); + return ret; } #ifdef HAVE_ELF @@ -530,19 +753,6 @@ static int bpf_map_create(enum bpf_map_type type, unsigned int size_key, return bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); } -static int bpf_map_update(int fd, const void *key, const void *value, - uint64_t flags) -{ - union bpf_attr attr = { - .map_fd = fd, - .key = bpf_ptr_to_u64(key), - .value = bpf_ptr_to_u64(value), - .flags = flags, - }; - - return bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); -} - static int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, size_t size, const char *license) { @@ -672,90 +882,6 @@ static const char *bpf_get_obj_uid(const char *pathname) return bpf_uid; } -static int bpf_mnt_fs(const char *target) -{ - bool bind_done = false; - - while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) { - if (errno != EINVAL || bind_done) { - fprintf(stderr, "mount --make-private %s failed: %s\n", - target, strerror(errno)); - return -1; - } - - if (mount(target, target, "none", MS_BIND, NULL)) { - fprintf(stderr, "mount --bind %s %s failed: %s\n", - target, target, strerror(errno)); - return -1; - } - - bind_done = true; - } - - if (mount("bpf", target, "bpf", 0, NULL)) { - fprintf(stderr, "mount -t bpf bpf %s failed: %s\n", - target, strerror(errno)); - return -1; - } - - return 0; -} - -static const char *bpf_get_tc_dir(void) -{ - static bool bpf_mnt_cached = false; - static char bpf_tc_dir[PATH_MAX]; - static const char *mnt; - static const char * const bpf_known_mnts[] = { - BPF_DIR_MNT, - 0, - }; - char bpf_mnt[PATH_MAX] = BPF_DIR_MNT; - char bpf_glo_dir[PATH_MAX]; - int ret; - - if (bpf_mnt_cached) - goto done; - - mnt = bpf_find_mntpt("bpf", BPF_FS_MAGIC, bpf_mnt, sizeof(bpf_mnt), - bpf_known_mnts); - if (!mnt) { - mnt = getenv(BPF_ENV_MNT); - if (!mnt) - mnt = BPF_DIR_MNT; - ret = bpf_mnt_fs(mnt); - if (ret) { - mnt = NULL; - goto out; - } - } - - snprintf(bpf_tc_dir, sizeof(bpf_tc_dir), "%s/%s", mnt, BPF_DIR_TC); - ret = mkdir(bpf_tc_dir, S_IRWXU); - if (ret && errno != EEXIST) { - fprintf(stderr, "mkdir %s failed: %s\n", bpf_tc_dir, - strerror(errno)); - mnt = NULL; - goto out; - } - - snprintf(bpf_glo_dir, sizeof(bpf_glo_dir), "%s/%s", - bpf_tc_dir, BPF_DIR_GLOBALS); - ret = mkdir(bpf_glo_dir, S_IRWXU); - if (ret && errno != EEXIST) { - fprintf(stderr, "mkdir %s failed: %s\n", bpf_glo_dir, - strerror(errno)); - mnt = NULL; - goto out; - } - - mnt = bpf_tc_dir; -out: - bpf_mnt_cached = true; -done: - return mnt; -} - static int bpf_init_env(const char *pathname) { struct rlimit limit = { @@ -931,7 +1057,9 @@ static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, fd = bpf_probe_pinned(name, ctx, map->pinning); if (fd > 0) { - ret = bpf_map_selfcheck_pinned(fd, map); + ret = bpf_map_selfcheck_pinned(fd, map, + offsetof(struct bpf_elf_map, + id)); if (ret < 0) { close(fd); fprintf(stderr, "Map \'%s\' self-check failed!\n", diff --git a/tc/tc_bpf.h b/tc/tc_bpf.h index dea3c3bc0..526d0b126 100644 --- a/tc/tc_bpf.h +++ b/tc/tc_bpf.h @@ -55,6 +55,7 @@ const char *bpf_default_section(const enum bpf_prog_type type); int bpf_parse_common(int *ptr_argc, char ***ptr_argv, const int *nla_tbl, enum bpf_prog_type type, const char **ptr_object, const char **ptr_uds_name, struct nlmsghdr *n); +int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv); void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len); From 0b7e3fc8f1abe63df0d511905b2a09064225f3a5 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 26 Nov 2015 15:38:46 +0100 Subject: [PATCH 008/513] {f,m}_bpf: add more example code I've added three examples to examples/bpf/ that demonstrate how one can implement eBPF tail calls in tc with f.e. multiple levels of nesting. That should act as a good starting point, but also as test cases for the ELF loader and kernel. A real test suite for {f,m,e}_bpf is still to be developed in future work. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov --- examples/bpf/README | 13 ++++ examples/bpf/bpf_cyclic.c | 32 ++++++++++ examples/bpf/bpf_funcs.h | 11 ++++ examples/bpf/bpf_graft.c | 70 ++++++++++++++++++++++ examples/bpf/bpf_tailcall.c | 115 ++++++++++++++++++++++++++++++++++++ 5 files changed, 241 insertions(+) create mode 100644 examples/bpf/README create mode 100644 examples/bpf/bpf_cyclic.c create mode 100644 examples/bpf/bpf_graft.c create mode 100644 examples/bpf/bpf_tailcall.c diff --git a/examples/bpf/README b/examples/bpf/README new file mode 100644 index 000000000..424725785 --- /dev/null +++ b/examples/bpf/README @@ -0,0 +1,13 @@ +eBPF toy code examples (running in kernel) to familiarize yourself +with syntax and features: + + - bpf_prog.c -> Classifier examples with using maps + - bpf_shared.c -> Ingress/egress map sharing example + - bpf_tailcall.c -> Using tail call chains + - bpf_cyclic.c -> Simple cycle as tail calls + - bpf_graft.c -> Demo on altering runtime behaviour + +User space code example: + + - bpf_agent.c -> Counterpart to bpf_prog.c for user + space to transfer/read out map data diff --git a/examples/bpf/bpf_cyclic.c b/examples/bpf/bpf_cyclic.c new file mode 100644 index 000000000..bde061cfb --- /dev/null +++ b/examples/bpf/bpf_cyclic.c @@ -0,0 +1,32 @@ +#include + +#include "bpf_funcs.h" + +/* Cyclic dependency example to test the kernel's runtime upper + * bound on loops. + */ +struct bpf_elf_map __section("maps") jmp_tc = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .id = 0xabccba, + .size_key = sizeof(int), + .size_value = sizeof(int), + .pinning = PIN_OBJECT_NS, + .max_elem = 1, +}; + +__section_tail(0xabccba, 0) int cls_loop(struct __sk_buff *skb) +{ + char fmt[] = "cb: %u\n"; + + bpf_printk(fmt, sizeof(fmt), skb->cb[0]++); + bpf_tail_call(skb, &jmp_tc, 0); + return -1; +} + +__section("classifier") int cls_entry(struct __sk_buff *skb) +{ + bpf_tail_call(skb, &jmp_tc, 0); + return -1; +} + +char __license[] __section("license") = "GPL"; diff --git a/examples/bpf/bpf_funcs.h b/examples/bpf/bpf_funcs.h index 1369401a0..6d058f0ea 100644 --- a/examples/bpf/bpf_funcs.h +++ b/examples/bpf/bpf_funcs.h @@ -10,10 +10,18 @@ # define __maybe_unused __attribute__ ((__unused__)) #endif +#ifndef __stringify +# define __stringify(x) #x +#endif + #ifndef __section # define __section(NAME) __attribute__((section(NAME), used)) #endif +#ifndef __section_tail +# define __section_tail(m, x) __section(__stringify(m) "/" __stringify(x)) +#endif + #ifndef offsetof # define offsetof __builtin_offsetof #endif @@ -50,6 +58,9 @@ static unsigned int (*get_prandom_u32)(void) __maybe_unused = static int (*bpf_printk)(const char *fmt, int fmt_size, ...) __maybe_unused = (void *) BPF_FUNC_trace_printk; +static void (*bpf_tail_call)(void *ctx, void *map, int index) __maybe_unused = + (void *) BPF_FUNC_tail_call; + /* LLVM built-in functions that an eBPF C program may use to emit * BPF_LD_ABS and BPF_LD_IND instructions. */ diff --git a/examples/bpf/bpf_graft.c b/examples/bpf/bpf_graft.c new file mode 100644 index 000000000..f36d25a2a --- /dev/null +++ b/examples/bpf/bpf_graft.c @@ -0,0 +1,70 @@ +#include + +#include "bpf_funcs.h" + +/* This example demonstrates how classifier run-time behaviour + * can be altered with tail calls. We start out with an empty + * jmp_tc array, then add section aaa to the array slot 0, and + * later on atomically replace it with section bbb. Note that + * as shown in other examples, the tc loader can prepopulate + * tail called sections, here we start out with an empty one + * on purpose to show it can also be done this way. + * + * tc filter add dev foo parent ffff: bpf obj graft.o + * tc exec bpf dbg + * [...] + * Socket Thread-20229 [001] ..s. 138993.003923: : fallthrough + * -0 [001] ..s. 138993.202265: : fallthrough + * Socket Thread-20229 [001] ..s. 138994.004149: : fallthrough + * [...] + * + * tc exec bpf graft m:globals/jmp_tc key 0 obj graft.o sec aaa + * tc exec bpf dbg + * [...] + * Socket Thread-19818 [002] ..s. 139012.053587: : aaa + * -0 [002] ..s. 139012.172359: : aaa + * Socket Thread-19818 [001] ..s. 139012.173556: : aaa + * [...] + * + * tc exec bpf graft m:globals/jmp_tc key 0 obj graft.o sec bbb + * tc exec bpf dbg + * [...] + * Socket Thread-19818 [002] ..s. 139022.102967: : bbb + * -0 [002] ..s. 139022.155640: : bbb + * Socket Thread-19818 [001] ..s. 139022.156730: : bbb + * [...] + */ +struct bpf_elf_map __section("maps") jmp_tc = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .size_key = sizeof(int), + .size_value = sizeof(int), + .pinning = PIN_GLOBAL_NS, + .max_elem = 1, +}; + +__section("aaa") int cls_aaa(struct __sk_buff *skb) +{ + char fmt[] = "aaa\n"; + + bpf_printk(fmt, sizeof(fmt)); + return -1; +} + +__section("bbb") int cls_bbb(struct __sk_buff *skb) +{ + char fmt[] = "bbb\n"; + + bpf_printk(fmt, sizeof(fmt)); + return -1; +} + +__section("classifier") int cls_entry(struct __sk_buff *skb) +{ + char fmt[] = "fallthrough\n"; + + bpf_tail_call(skb, &jmp_tc, 0); + bpf_printk(fmt, sizeof(fmt)); + return -1; +} + +char __license[] __section("license") = "GPL"; diff --git a/examples/bpf/bpf_tailcall.c b/examples/bpf/bpf_tailcall.c new file mode 100644 index 000000000..f186e5751 --- /dev/null +++ b/examples/bpf/bpf_tailcall.c @@ -0,0 +1,115 @@ +#include + +#include "bpf_funcs.h" + +#define ENTRY_INIT 3 +#define ENTRY_0 0 +#define ENTRY_1 1 +#define MAX_JMP_SIZE 2 + +#define FOO 42 +#define BAR 43 + +/* This example doesn't really do anything useful, but it's purpose is to + * demonstrate eBPF tail calls on a very simple example. + * + * cls_entry() is our classifier entry point, from there we jump based on + * skb->hash into cls_case1() or cls_case2(). They are both part of the + * program array jmp_tc. Indicated via __section_tail(), the tc loader + * populates the program arrays with the loaded file descriptors already. + * + * To demonstrate nested jumps, cls_case2() jumps within the same jmp_tc + * array to cls_case1(). And whenever we arrive at cls_case1(), we jump + * into cls_exit(), part of the jump array jmp_ex. + * + * Also, to show it's possible, all programs share map_sh and dump the value + * that the entry point incremented. The sections that are loaded into a + * program array can be atomically replaced during run-time, e.g. to change + * classifier behaviour. + */ +struct bpf_elf_map __section("maps") map_sh = { + .type = BPF_MAP_TYPE_ARRAY, + .size_key = sizeof(int), + .size_value = sizeof(int), + .pinning = PIN_OBJECT_NS, + .max_elem = 1, +}; + +struct bpf_elf_map __section("maps") jmp_tc = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .id = FOO, + .size_key = sizeof(int), + .size_value = sizeof(int), + .pinning = PIN_OBJECT_NS, + .max_elem = MAX_JMP_SIZE, +}; + +struct bpf_elf_map __section("maps") jmp_ex = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .id = BAR, + .size_key = sizeof(int), + .size_value = sizeof(int), + .pinning = PIN_OBJECT_NS, + .max_elem = 1, +}; + +__section_tail(FOO, ENTRY_0) int cls_case1(struct __sk_buff *skb) +{ + char fmt[] = "case1: map-val: %d from:%u\n"; + int key = 0, *val; + + val = bpf_map_lookup_elem(&map_sh, &key); + if (val) + bpf_printk(fmt, sizeof(fmt), *val, skb->cb[0]); + + skb->cb[0] = ENTRY_0; + bpf_tail_call(skb, &jmp_ex, ENTRY_0); + return 0; +} + +__section_tail(FOO, ENTRY_1) int cls_case2(struct __sk_buff *skb) +{ + char fmt[] = "case2: map-val: %d from:%u\n"; + int key = 0, *val; + + val = bpf_map_lookup_elem(&map_sh, &key); + if (val) + bpf_printk(fmt, sizeof(fmt), *val, skb->cb[0]); + + skb->cb[0] = ENTRY_1; + bpf_tail_call(skb, &jmp_tc, ENTRY_0); + return 0; +} + +__section_tail(BAR, ENTRY_0) int cls_exit(struct __sk_buff *skb) +{ + char fmt[] = "exit: map-val: %d from:%u\n"; + int key = 0, *val; + + val = bpf_map_lookup_elem(&map_sh, &key); + if (val) + bpf_printk(fmt, sizeof(fmt), *val, skb->cb[0]); + + /* Termination point. */ + return -1; +} + +__section("classifier") int cls_entry(struct __sk_buff *skb) +{ + char fmt[] = "fallthrough\n"; + int key = 0, *val; + + /* For transferring state, we can use skb->cb[0] ... skb->cb[4]. */ + val = bpf_map_lookup_elem(&map_sh, &key); + if (val) { + __sync_fetch_and_add(val, 1); + + skb->cb[0] = ENTRY_INIT; + bpf_tail_call(skb, &jmp_tc, skb->hash & (MAX_JMP_SIZE - 1)); + } + + bpf_printk(fmt, sizeof(fmt)); + return 0; +} + +char __license[] __section("license") = "GPL"; From 41d6e33fc9e5b459b7f715acbd6d8dbeddf58576 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 2 Dec 2015 00:25:36 +0100 Subject: [PATCH 009/513] examples, bpf: further improve examples Improve example files further and add a more generic set of possible helpers for them that can be used. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov --- examples/bpf/bpf_cyclic.c | 38 +++--- examples/bpf/bpf_funcs.h | 76 ------------ examples/bpf/bpf_graft.c | 39 +++---- examples/bpf/bpf_prog.c | 33 +++--- examples/bpf/bpf_shared.c | 32 +++-- examples/bpf/bpf_shared.h | 2 +- examples/bpf/bpf_tailcall.c | 84 ++++++-------- include/bpf_api.h | 225 ++++++++++++++++++++++++++++++++++++ 8 files changed, 327 insertions(+), 202 deletions(-) delete mode 100644 examples/bpf/bpf_funcs.h create mode 100644 include/bpf_api.h diff --git a/examples/bpf/bpf_cyclic.c b/examples/bpf/bpf_cyclic.c index bde061cfb..c66cbecce 100644 --- a/examples/bpf/bpf_cyclic.c +++ b/examples/bpf/bpf_cyclic.c @@ -1,32 +1,30 @@ -#include - -#include "bpf_funcs.h" +#include "../../include/bpf_api.h" /* Cyclic dependency example to test the kernel's runtime upper - * bound on loops. + * bound on loops. Also demonstrates on how to use direct-actions, + * loaded as: tc filter add [...] bpf da obj [...] */ -struct bpf_elf_map __section("maps") jmp_tc = { - .type = BPF_MAP_TYPE_PROG_ARRAY, - .id = 0xabccba, - .size_key = sizeof(int), - .size_value = sizeof(int), - .pinning = PIN_OBJECT_NS, - .max_elem = 1, -}; +#define JMP_MAP_ID 0xabccba + +BPF_PROG_ARRAY(jmp_tc, JMP_MAP_ID, PIN_OBJECT_NS, 1); -__section_tail(0xabccba, 0) int cls_loop(struct __sk_buff *skb) +__section_tail(JMP_MAP_ID, 0) +int cls_loop(struct __sk_buff *skb) { char fmt[] = "cb: %u\n"; - bpf_printk(fmt, sizeof(fmt), skb->cb[0]++); - bpf_tail_call(skb, &jmp_tc, 0); - return -1; + trace_printk(fmt, sizeof(fmt), skb->cb[0]++); + tail_call(skb, &jmp_tc, 0); + + skb->tc_classid = TC_H_MAKE(1, 42); + return TC_ACT_OK; } -__section("classifier") int cls_entry(struct __sk_buff *skb) +__section_cls_entry +int cls_entry(struct __sk_buff *skb) { - bpf_tail_call(skb, &jmp_tc, 0); - return -1; + tail_call(skb, &jmp_tc, 0); + return TC_ACT_SHOT; } -char __license[] __section("license") = "GPL"; +BPF_LICENSE("GPL"); diff --git a/examples/bpf/bpf_funcs.h b/examples/bpf/bpf_funcs.h deleted file mode 100644 index 6d058f0ea..000000000 --- a/examples/bpf/bpf_funcs.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef __BPF_FUNCS__ -#define __BPF_FUNCS__ - -#include - -#include "../../include/bpf_elf.h" - -/* Misc macros. */ -#ifndef __maybe_unused -# define __maybe_unused __attribute__ ((__unused__)) -#endif - -#ifndef __stringify -# define __stringify(x) #x -#endif - -#ifndef __section -# define __section(NAME) __attribute__((section(NAME), used)) -#endif - -#ifndef __section_tail -# define __section_tail(m, x) __section(__stringify(m) "/" __stringify(x)) -#endif - -#ifndef offsetof -# define offsetof __builtin_offsetof -#endif - -#ifndef htons -# define htons(x) __constant_htons((x)) -#endif - -#ifndef likely -# define likely(x) __builtin_expect(!!(x), 1) -#endif - -#ifndef unlikely -# define unlikely(x) __builtin_expect(!!(x), 0) -#endif - -/* The verifier will translate them to actual function calls. */ -static void *(*bpf_map_lookup_elem)(void *map, void *key) __maybe_unused = - (void *) BPF_FUNC_map_lookup_elem; - -static int (*bpf_map_update_elem)(void *map, void *key, void *value, - unsigned long long flags) __maybe_unused = - (void *) BPF_FUNC_map_update_elem; - -static int (*bpf_map_delete_elem)(void *map, void *key) __maybe_unused = - (void *) BPF_FUNC_map_delete_elem; - -static unsigned int (*get_smp_processor_id)(void) __maybe_unused = - (void *) BPF_FUNC_get_smp_processor_id; - -static unsigned int (*get_prandom_u32)(void) __maybe_unused = - (void *) BPF_FUNC_get_prandom_u32; - -static int (*bpf_printk)(const char *fmt, int fmt_size, ...) __maybe_unused = - (void *) BPF_FUNC_trace_printk; - -static void (*bpf_tail_call)(void *ctx, void *map, int index) __maybe_unused = - (void *) BPF_FUNC_tail_call; - -/* LLVM built-in functions that an eBPF C program may use to emit - * BPF_LD_ABS and BPF_LD_IND instructions. - */ -unsigned long long load_byte(void *skb, unsigned long long off) - asm ("llvm.bpf.load.byte"); - -unsigned long long load_half(void *skb, unsigned long long off) - asm ("llvm.bpf.load.half"); - -unsigned long long load_word(void *skb, unsigned long long off) - asm ("llvm.bpf.load.word"); - -#endif /* __BPF_FUNCS__ */ diff --git a/examples/bpf/bpf_graft.c b/examples/bpf/bpf_graft.c index f36d25a2a..f48fd0288 100644 --- a/examples/bpf/bpf_graft.c +++ b/examples/bpf/bpf_graft.c @@ -1,6 +1,4 @@ -#include - -#include "bpf_funcs.h" +#include "../../include/bpf_api.h" /* This example demonstrates how classifier run-time behaviour * can be altered with tail calls. We start out with an empty @@ -34,37 +32,36 @@ * Socket Thread-19818 [001] ..s. 139022.156730: : bbb * [...] */ -struct bpf_elf_map __section("maps") jmp_tc = { - .type = BPF_MAP_TYPE_PROG_ARRAY, - .size_key = sizeof(int), - .size_value = sizeof(int), - .pinning = PIN_GLOBAL_NS, - .max_elem = 1, -}; -__section("aaa") int cls_aaa(struct __sk_buff *skb) +BPF_PROG_ARRAY(jmp_tc, 0, PIN_GLOBAL_NS, 1); + +__section("aaa") +int cls_aaa(struct __sk_buff *skb) { char fmt[] = "aaa\n"; - bpf_printk(fmt, sizeof(fmt)); - return -1; + trace_printk(fmt, sizeof(fmt)); + return TC_H_MAKE(1, 42); } -__section("bbb") int cls_bbb(struct __sk_buff *skb) +__section("bbb") +int cls_bbb(struct __sk_buff *skb) { char fmt[] = "bbb\n"; - bpf_printk(fmt, sizeof(fmt)); - return -1; + trace_printk(fmt, sizeof(fmt)); + return TC_H_MAKE(1, 43); } -__section("classifier") int cls_entry(struct __sk_buff *skb) +__section_cls_entry +int cls_entry(struct __sk_buff *skb) { char fmt[] = "fallthrough\n"; - bpf_tail_call(skb, &jmp_tc, 0); - bpf_printk(fmt, sizeof(fmt)); - return -1; + tail_call(skb, &jmp_tc, 0); + trace_printk(fmt, sizeof(fmt)); + + return BPF_H_DEFAULT; } -char __license[] __section("license") = "GPL"; +BPF_LICENSE("GPL"); diff --git a/examples/bpf/bpf_prog.c b/examples/bpf/bpf_prog.c index 009febd07..472804925 100644 --- a/examples/bpf/bpf_prog.c +++ b/examples/bpf/bpf_prog.c @@ -168,8 +168,8 @@ /* Common, shared definitions with ebpf_agent.c. */ #include "bpf_shared.h" -/* Selection of BPF helper functions for our example. */ -#include "bpf_funcs.h" +/* BPF helper functions for our example. */ +#include "../../include/bpf_api.h" /* Could be defined here as well, or included from the header. */ #define TC_ACT_UNSPEC (-1) @@ -387,10 +387,10 @@ static inline void cls_update_proto_map(const struct __sk_buff *skb, uint8_t proto = flow->ip_proto; struct count_tuple *ct, _ct; - ct = bpf_map_lookup_elem(&map_proto, &proto); + ct = map_lookup_elem(&map_proto, &proto); if (likely(ct)) { - __sync_fetch_and_add(&ct->packets, 1); - __sync_fetch_and_add(&ct->bytes, skb->len); + lock_xadd(&ct->packets, 1); + lock_xadd(&ct->bytes, skb->len); return; } @@ -398,7 +398,7 @@ static inline void cls_update_proto_map(const struct __sk_buff *skb, _ct.packets = 1; _ct.bytes = skb->len; - bpf_map_update_elem(&map_proto, &proto, &_ct, BPF_ANY); + map_update_elem(&map_proto, &proto, &_ct, BPF_ANY); } static inline void cls_update_queue_map(const struct __sk_buff *skb) @@ -409,11 +409,11 @@ static inline void cls_update_queue_map(const struct __sk_buff *skb) mismatch = skb->queue_mapping != get_smp_processor_id(); - cq = bpf_map_lookup_elem(&map_queue, &queue); + cq = map_lookup_elem(&map_queue, &queue); if (likely(cq)) { - __sync_fetch_and_add(&cq->total, 1); + lock_xadd(&cq->total, 1); if (mismatch) - __sync_fetch_and_add(&cq->mismatch, 1); + lock_xadd(&cq->mismatch, 1); return; } @@ -421,7 +421,7 @@ static inline void cls_update_queue_map(const struct __sk_buff *skb) _cq.total = 1; _cq.mismatch = mismatch ? 1 : 0; - bpf_map_update_elem(&map_queue, &queue, &_cq, BPF_ANY); + map_update_elem(&map_queue, &queue, &_cq, BPF_ANY); } /* eBPF program definitions, placed in various sections, which can @@ -439,7 +439,8 @@ static inline void cls_update_queue_map(const struct __sk_buff *skb) * It is however not required to have multiple programs sharing * a file. */ -__section("classifier") int cls_main(struct __sk_buff *skb) +__section("classifier") +int cls_main(struct __sk_buff *skb) { struct flow_keys flow; @@ -456,13 +457,14 @@ static inline void act_update_drop_map(void) { uint32_t *count, cpu = get_smp_processor_id(); - count = bpf_map_lookup_elem(&map_drops, &cpu); + count = map_lookup_elem(&map_drops, &cpu); if (count) /* Only this cpu is accessing this element. */ (*count)++; } -__section("action-mark") int act_mark_main(struct __sk_buff *skb) +__section("action-mark") +int act_mark_main(struct __sk_buff *skb) { /* You could also mangle skb data here with the helper function * BPF_FUNC_skb_store_bytes, etc. Or, alternatively you could @@ -479,7 +481,8 @@ __section("action-mark") int act_mark_main(struct __sk_buff *skb) return TC_ACT_UNSPEC; } -__section("action-rand") int act_rand_main(struct __sk_buff *skb) +__section("action-rand") +int act_rand_main(struct __sk_buff *skb) { /* Sorry, we're near event horizon ... */ if ((get_prandom_u32() & 3) == 0) { @@ -493,4 +496,4 @@ __section("action-rand") int act_rand_main(struct __sk_buff *skb) /* Last but not least, the file contains a license. Some future helper * functions may only be available with a GPL license. */ -char __license[] __section("license") = "GPL"; +BPF_LICENSE("GPL"); diff --git a/examples/bpf/bpf_shared.c b/examples/bpf/bpf_shared.c index a8dc39c75..accc0adf4 100644 --- a/examples/bpf/bpf_shared.c +++ b/examples/bpf/bpf_shared.c @@ -1,6 +1,4 @@ -#include - -#include "bpf_funcs.h" +#include "../../include/bpf_api.h" /* Minimal, stand-alone toy map pinning example: * @@ -20,35 +18,31 @@ * instance is being created. */ -struct bpf_elf_map __section("maps") map_sh = { - .type = BPF_MAP_TYPE_ARRAY, - .size_key = sizeof(int), - .size_value = sizeof(int), - .pinning = PIN_OBJECT_NS, /* or PIN_GLOBAL_NS, or PIN_NONE */ - .max_elem = 1, -}; +BPF_ARRAY4(map_sh, 0, PIN_OBJECT_NS, 1); /* or PIN_GLOBAL_NS, or PIN_NONE */ -__section("egress") int emain(struct __sk_buff *skb) +__section("egress") +int emain(struct __sk_buff *skb) { int key = 0, *val; - val = bpf_map_lookup_elem(&map_sh, &key); + val = map_lookup_elem(&map_sh, &key); if (val) - __sync_fetch_and_add(val, 1); + lock_xadd(val, 1); - return -1; + return BPF_H_DEFAULT; } -__section("ingress") int imain(struct __sk_buff *skb) +__section("ingress") +int imain(struct __sk_buff *skb) { char fmt[] = "map val: %d\n"; int key = 0, *val; - val = bpf_map_lookup_elem(&map_sh, &key); + val = map_lookup_elem(&map_sh, &key); if (val) - bpf_printk(fmt, sizeof(fmt), *val); + trace_printk(fmt, sizeof(fmt), *val); - return -1; + return BPF_H_DEFAULT; } -char __license[] __section("license") = "GPL"; +BPF_LICENSE("GPL"); diff --git a/examples/bpf/bpf_shared.h b/examples/bpf/bpf_shared.h index ea8f01474..a24038dd5 100644 --- a/examples/bpf/bpf_shared.h +++ b/examples/bpf/bpf_shared.h @@ -10,7 +10,7 @@ enum { }; struct count_tuple { - long packets; /* type long for __sync_fetch_and_add() */ + long packets; /* type long for lock_xadd() */ long bytes; }; diff --git a/examples/bpf/bpf_tailcall.c b/examples/bpf/bpf_tailcall.c index f186e5751..040790d0e 100644 --- a/examples/bpf/bpf_tailcall.c +++ b/examples/bpf/bpf_tailcall.c @@ -1,6 +1,4 @@ -#include - -#include "bpf_funcs.h" +#include "../../include/bpf_api.h" #define ENTRY_INIT 3 #define ENTRY_0 0 @@ -27,89 +25,75 @@ * program array can be atomically replaced during run-time, e.g. to change * classifier behaviour. */ -struct bpf_elf_map __section("maps") map_sh = { - .type = BPF_MAP_TYPE_ARRAY, - .size_key = sizeof(int), - .size_value = sizeof(int), - .pinning = PIN_OBJECT_NS, - .max_elem = 1, -}; - -struct bpf_elf_map __section("maps") jmp_tc = { - .type = BPF_MAP_TYPE_PROG_ARRAY, - .id = FOO, - .size_key = sizeof(int), - .size_value = sizeof(int), - .pinning = PIN_OBJECT_NS, - .max_elem = MAX_JMP_SIZE, -}; - -struct bpf_elf_map __section("maps") jmp_ex = { - .type = BPF_MAP_TYPE_PROG_ARRAY, - .id = BAR, - .size_key = sizeof(int), - .size_value = sizeof(int), - .pinning = PIN_OBJECT_NS, - .max_elem = 1, -}; - -__section_tail(FOO, ENTRY_0) int cls_case1(struct __sk_buff *skb) + +BPF_PROG_ARRAY(jmp_tc, FOO, PIN_OBJECT_NS, MAX_JMP_SIZE); +BPF_PROG_ARRAY(jmp_ex, BAR, PIN_OBJECT_NS, 1); + +BPF_ARRAY4(map_sh, 0, PIN_OBJECT_NS, 1); + +__section_tail(FOO, ENTRY_0) +int cls_case1(struct __sk_buff *skb) { char fmt[] = "case1: map-val: %d from:%u\n"; int key = 0, *val; - val = bpf_map_lookup_elem(&map_sh, &key); + val = map_lookup_elem(&map_sh, &key); if (val) - bpf_printk(fmt, sizeof(fmt), *val, skb->cb[0]); + trace_printk(fmt, sizeof(fmt), *val, skb->cb[0]); skb->cb[0] = ENTRY_0; - bpf_tail_call(skb, &jmp_ex, ENTRY_0); - return 0; + tail_call(skb, &jmp_ex, ENTRY_0); + + return BPF_H_DEFAULT; } -__section_tail(FOO, ENTRY_1) int cls_case2(struct __sk_buff *skb) +__section_tail(FOO, ENTRY_1) +int cls_case2(struct __sk_buff *skb) { char fmt[] = "case2: map-val: %d from:%u\n"; int key = 0, *val; - val = bpf_map_lookup_elem(&map_sh, &key); + val = map_lookup_elem(&map_sh, &key); if (val) - bpf_printk(fmt, sizeof(fmt), *val, skb->cb[0]); + trace_printk(fmt, sizeof(fmt), *val, skb->cb[0]); skb->cb[0] = ENTRY_1; - bpf_tail_call(skb, &jmp_tc, ENTRY_0); - return 0; + tail_call(skb, &jmp_tc, ENTRY_0); + + return BPF_H_DEFAULT; } -__section_tail(BAR, ENTRY_0) int cls_exit(struct __sk_buff *skb) +__section_tail(BAR, ENTRY_0) +int cls_exit(struct __sk_buff *skb) { char fmt[] = "exit: map-val: %d from:%u\n"; int key = 0, *val; - val = bpf_map_lookup_elem(&map_sh, &key); + val = map_lookup_elem(&map_sh, &key); if (val) - bpf_printk(fmt, sizeof(fmt), *val, skb->cb[0]); + trace_printk(fmt, sizeof(fmt), *val, skb->cb[0]); /* Termination point. */ - return -1; + return BPF_H_DEFAULT; } -__section("classifier") int cls_entry(struct __sk_buff *skb) +__section_cls_entry +int cls_entry(struct __sk_buff *skb) { char fmt[] = "fallthrough\n"; int key = 0, *val; /* For transferring state, we can use skb->cb[0] ... skb->cb[4]. */ - val = bpf_map_lookup_elem(&map_sh, &key); + val = map_lookup_elem(&map_sh, &key); if (val) { - __sync_fetch_and_add(val, 1); + lock_xadd(val, 1); skb->cb[0] = ENTRY_INIT; - bpf_tail_call(skb, &jmp_tc, skb->hash & (MAX_JMP_SIZE - 1)); + tail_call(skb, &jmp_tc, skb->hash & (MAX_JMP_SIZE - 1)); } - bpf_printk(fmt, sizeof(fmt)); - return 0; + trace_printk(fmt, sizeof(fmt)); + return BPF_H_DEFAULT; } -char __license[] __section("license") = "GPL"; +BPF_LICENSE("GPL"); diff --git a/include/bpf_api.h b/include/bpf_api.h new file mode 100644 index 000000000..8503b9a56 --- /dev/null +++ b/include/bpf_api.h @@ -0,0 +1,225 @@ +#ifndef __BPF_API__ +#define __BPF_API__ + +/* Note: + * + * This file can be included into eBPF kernel programs. It contains + * a couple of useful helper functions, map/section ABI (bpf_elf.h), + * misc macros and some eBPF specific LLVM built-ins. + */ + +#include + +#include +#include +#include + +#include + +#include "bpf_elf.h" + +/** Misc macros. */ + +#ifndef __stringify +# define __stringify(X) #X +#endif + +#ifndef __maybe_unused +# define __maybe_unused __attribute__((__unused__)) +#endif + +#ifndef offsetof +# define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) +#endif + +#ifndef likely +# define likely(X) __builtin_expect(!!(X), 1) +#endif + +#ifndef unlikely +# define unlikely(X) __builtin_expect(!!(X), 0) +#endif + +#ifndef htons +# define htons(X) __constant_htons((X)) +#endif + +#ifndef ntohs +# define ntohs(X) __constant_ntohs((X)) +#endif + +#ifndef htonl +# define htonl(X) __constant_htonl((X)) +#endif + +#ifndef ntohl +# define ntohl(X) __constant_ntohl((X) +#endif + +/** Section helper macros. */ + +#ifndef __section +# define __section(NAME) \ + __attribute__((section(NAME), used)) +#endif + +#ifndef __section_tail +# define __section_tail(ID, KEY) \ + __section(__stringify(ID) "/" __stringify(KEY)) +#endif + +#ifndef __section_cls_entry +# define __section_cls_entry \ + __section(ELF_SECTION_CLASSIFIER) +#endif + +#ifndef __section_act_entry +# define __section_act_entry \ + __section(ELF_SECTION_ACTION) +#endif + +#ifndef __section_license +# define __section_license \ + __section(ELF_SECTION_LICENSE) +#endif + +#ifndef __section_maps +# define __section_maps \ + __section(ELF_SECTION_MAPS) +#endif + +/** Declaration helper macros. */ + +#ifndef BPF_LICENSE +# define BPF_LICENSE(NAME) \ + char ____license[] __section_license = NAME +#endif + +#ifndef __BPF_MAP +# define __BPF_MAP(NAME, TYPE, ID, SIZE_KEY, SIZE_VALUE, PIN, MAX_ELEM) \ + struct bpf_elf_map __section_maps NAME = { \ + .type = (TYPE), \ + .id = (ID), \ + .size_key = (SIZE_KEY), \ + .size_value = (SIZE_VALUE), \ + .pinning = (PIN), \ + .max_elem = (MAX_ELEM), \ + } +#endif + +#ifndef BPF_HASH +# define BPF_HASH(NAME, ID, SIZE_KEY, SIZE_VALUE, PIN, MAX_ELEM) \ + __BPF_MAP(NAME, BPF_MAP_TYPE_HASH, ID, SIZE_KEY, SIZE_VALUE, \ + PIN, MAX_ELEM) +#endif + +#ifndef BPF_ARRAY +# define BPF_ARRAY(NAME, ID, SIZE_VALUE, PIN, MAX_ELEM) \ + __BPF_MAP(NAME, BPF_MAP_TYPE_ARRAY, ID, sizeof(uint32_t), \ + SIZE_VALUE, PIN, MAX_ELEM) +#endif + +#ifndef BPF_ARRAY2 +# define BPF_ARRAY2(NAME, ID, PIN, MAX_ELEM) \ + BPF_ARRAY(NAME, ID, sizeof(uint16_t), PIN, MAX_ELEM) +#endif + +#ifndef BPF_ARRAY4 +# define BPF_ARRAY4(NAME, ID, PIN, MAX_ELEM) \ + BPF_ARRAY(NAME, ID, sizeof(uint32_t), PIN, MAX_ELEM) +#endif + +#ifndef BPF_ARRAY8 +# define BPF_ARRAY8(NAME, ID, PIN, MAX_ELEM) \ + BPF_ARRAY(NAME, ID, sizeof(uint64_t), PIN, MAX_ELEM) +#endif + +#ifndef BPF_PROG_ARRAY +# define BPF_PROG_ARRAY(NAME, ID, PIN, MAX_ELEM) \ + __BPF_MAP(NAME, BPF_MAP_TYPE_PROG_ARRAY, ID, sizeof(uint32_t), \ + sizeof(uint32_t), PIN, MAX_ELEM) +#endif + +/** Classifier helper */ + +#ifndef BPF_H_DEFAULT +# define BPF_H_DEFAULT -1 +#endif + +/** BPF helper functions for tc. */ + +#ifndef BPF_FUNC +# define BPF_FUNC(NAME, ...) \ + (* NAME)(__VA_ARGS__) __maybe_unused = (void *) BPF_FUNC_##NAME +#endif + +/* Map access/manipulation */ +static void *BPF_FUNC(map_lookup_elem, void *map, const void *key); +static int BPF_FUNC(map_update_elem, void *map, const void *key, + const void *value, uint32_t flags); +static int BPF_FUNC(map_delete_elem, void *map, const void *key); + +/* Time access */ +static uint64_t BPF_FUNC(ktime_get_ns); + +/* Debugging */ +static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...); + +/* Random numbers */ +static uint32_t BPF_FUNC(get_prandom_u32); + +/* Tail calls */ +static void BPF_FUNC(tail_call, struct __sk_buff *skb, void *map, + uint32_t index); + +/* System helpers */ +static uint32_t BPF_FUNC(get_smp_processor_id); + +/* Packet misc meta data */ +static uint32_t BPF_FUNC(get_cgroup_classid, struct __sk_buff *skb); +static uint32_t BPF_FUNC(get_route_realm, struct __sk_buff *skb); + +/* Packet redirection */ +static int BPF_FUNC(redirect, int ifindex, uint32_t flags); +static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex, + uint32_t flags); + +/* Packet manipulation */ +#define BPF_PSEUDO_HDR 0x10 +#define BPF_HAS_PSEUDO_HDR(flags) ((flags) & BPF_PSEUDO_HDR) +#define BPF_HDR_FIELD_SIZE(flags) ((flags) & 0x0f) + +static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off, + void *from, uint32_t len, uint32_t flags); +static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off, + uint32_t from, uint32_t to, uint32_t flags); +static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off, + uint32_t from, uint32_t to, uint32_t flags); + +/* Packet vlan encap/decap */ +static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto, + uint16_t vlan_tci); +static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb); + +/* Packet tunnel encap/decap */ +static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb, + struct bpf_tunnel_key *to, uint32_t size, uint32_t flags); +static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb, + struct bpf_tunnel_key *from, uint32_t size, uint32_t flags); + +/** LLVM built-ins */ + +#ifndef lock_xadd +# define lock_xadd(ptr, val) ((void) __sync_fetch_and_add(ptr, val)) +#endif + +unsigned long long load_byte(void *skb, unsigned long long off) + asm ("llvm.bpf.load.byte"); + +unsigned long long load_half(void *skb, unsigned long long off) + asm ("llvm.bpf.load.half"); + +unsigned long long load_word(void *skb, unsigned long long off) + asm ("llvm.bpf.load.word"); + +#endif /* __BPF_API__ */ From 741c20b024f5f51bf194435fc4d79f34ae5c5481 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 17 Dec 2015 17:21:53 -0800 Subject: [PATCH 010/513] include: update kernel headers Current headers for net-next --- include/linux/if_link.h | 3 +++ include/linux/in6.h | 1 + include/linux/rtnetlink.h | 1 + include/linux/sock_diag.h | 1 + 4 files changed, 6 insertions(+) diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 5d206c712..c9ad487d0 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -460,6 +460,9 @@ enum { IFLA_GENEVE_PORT, /* destination port */ IFLA_GENEVE_COLLECT_METADATA, IFLA_GENEVE_REMOTE6, + IFLA_GENEVE_UDP_CSUM, + IFLA_GENEVE_UDP_ZERO_CSUM6_TX, + IFLA_GENEVE_UDP_ZERO_CSUM6_RX, __IFLA_GENEVE_MAX }; #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) diff --git a/include/linux/in6.h b/include/linux/in6.h index 994f4c22d..aa5b66df6 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -196,6 +196,7 @@ struct in6_flowlabel_req { #define IPV6_IPSEC_POLICY 34 #define IPV6_XFRM_POLICY 35 +#define IPV6_HDRINCL 36 #endif /* diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 18c543a59..6aaa2a3e3 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -311,6 +311,7 @@ enum rtattr_type_t { RTA_PREF, RTA_ENCAP_TYPE, RTA_ENCAP, + RTA_EXPIRES, __RTA_MAX }; diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h index 024e1f4cd..dafcb891a 100644 --- a/include/linux/sock_diag.h +++ b/include/linux/sock_diag.h @@ -4,6 +4,7 @@ #include #define SOCK_DIAG_BY_FAMILY 20 +#define SOCK_DESTROY 21 struct sock_diag_req { __u8 sdiag_family; From fd7f9c7fd11fa926bda2edc8bc492e7515753a32 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 14 Dec 2015 16:57:32 +0100 Subject: [PATCH 011/513] bpf: minor fix in api and bpf_dump_error() usage Fix a whitespace in bpf_dump_error() usage, and also a missing closing bracket in ntohl() macro for eBPF programs. Signed-off-by: Daniel Borkmann --- include/bpf_api.h | 2 +- tc/tc_bpf.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bpf_api.h b/include/bpf_api.h index 8503b9a56..0666a312e 100644 --- a/include/bpf_api.h +++ b/include/bpf_api.h @@ -53,7 +53,7 @@ #endif #ifndef ntohl -# define ntohl(X) __constant_ntohl((X) +# define ntohl(X) __constant_ntohl((X)) #endif /** Section helper macros. */ diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index beb74be6c..f9b2b007f 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -1042,7 +1042,7 @@ static int bpf_prog_attach(const char *section, "license:\'%s\') %s%s (%d)!\n\n", section, prog->type, prog->size / sizeof(struct bpf_insn), - prog->license, fd < 0 ? "rejected :" : + prog->license, fd < 0 ? "rejected: " : "loaded", fd < 0 ? strerror(errno) : "", fd < 0 ? errno : fd); } From 68eede2505005ea919e2fb43afc91bad0601faea Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Mon, 21 Dec 2015 16:29:36 +0800 Subject: [PATCH 012/513] route: allow routes to be configured with expire values Signed-off-by: Hangbin Liu --- ip/iproute.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ip/iproute.c b/ip/iproute.c index 4d86a5961..d5e3ebe26 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -86,7 +86,7 @@ static void usage(void) fprintf(stderr, " [ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]\n"); fprintf(stderr, " [ rto_min TIME ] [ hoplimit NUMBER ] [ initrwnd NUMBER ]\n"); fprintf(stderr, " [ features FEATURES ] [ quickack BOOL ] [ congctl NAME ]\n"); - fprintf(stderr, " [ pref PREF ]\n"); + fprintf(stderr, " [ pref PREF ] [ expires TIME ]\n"); fprintf(stderr, "TYPE := [ unicast | local | broadcast | multicast | throw |\n"); fprintf(stderr, " unreachable | prohibit | blackhole | nat ]\n"); fprintf(stderr, "TABLE_ID := [ local | main | default | all | NUMBER ]\n"); @@ -829,6 +829,7 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) int table_ok = 0; int raw = 0; int type_ok = 0; + static int hz; memset(&req, 0, sizeof(req)); @@ -899,6 +900,14 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) if (rtnl_dsfield_a2n(&tos, *argv)) invarg("\"tos\" value is invalid\n", *argv); req.r.rtm_tos = tos; + } else if (strcmp(*argv, "expires") == 0 ) { + __u32 expires; + NEXT_ARG(); + if (get_u32(&expires, *argv, 0)) + invarg("\"expires\" value is invalid\n", *argv); + if (!hz) + hz = get_user_hz(); + addattr32(&req.n, sizeof(req), RTA_EXPIRES, expires*hz); } else if (matches(*argv, "metric") == 0 || matches(*argv, "priority") == 0 || strcmp(*argv, "preference") == 0) { From 966fe23a7ca85c553bb1a3cc5160f0a6b1409996 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 25 Dec 2015 11:12:15 +0800 Subject: [PATCH 013/513] iproute2: ip-route.8.in: Add missing '[' before 'pref' Signed-off-by: Hangbin Liu --- man/man8/ip-route.8.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/ip-route.8.in b/man/man8/ip-route.8.in index 9934a1e8c..743d62be4 100644 --- a/man/man8/ip-route.8.in +++ b/man/man8/ip-route.8.in @@ -130,7 +130,7 @@ replace " } " .B quickack .IR BOOL " ] [ " .B congctl -.IR NAME " ]" +.IR NAME " ] [ " .B pref .IR PREF " ]" From 3fbe7ca847367d0f9c3861283767ae702c2a19ab Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 25 Dec 2015 11:12:16 +0800 Subject: [PATCH 014/513] iproute2: ip-route.8.in: Add expires option for ip route Signed-off-by: Hangbin Liu --- man/man8/ip-route.8.in | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/man/man8/ip-route.8.in b/man/man8/ip-route.8.in index 743d62be4..c764bfc8e 100644 --- a/man/man8/ip-route.8.in +++ b/man/man8/ip-route.8.in @@ -132,7 +132,9 @@ replace " } " .B congctl .IR NAME " ] [ " .B pref -.IR PREF " ]" +.IR PREF " ] [ " +.B expires +.IR TIME " ]" .ti -8 .IR TYPE " := [ " @@ -656,6 +658,12 @@ is a set of encapsulation attributes specific to the .in -8 .RE +.TP +.BI expires " TIME " "(4.4+ only)" +the route will be deleted after the expires time. +.B Only +support IPv6 at present. + .TP ip route delete delete route From b27f005b274fb0332dc7e88e2bc1344e11fba143 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 30 Dec 2015 17:17:45 -0800 Subject: [PATCH 015/513] genl: make string const Signed-off-by: Stephen Hemminger --- genl/genl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/genl/genl.c b/genl/genl.c index 49b65960d..e33fafdf2 100644 --- a/genl/genl.c +++ b/genl/genl.c @@ -54,7 +54,7 @@ static int parse_nofopt(struct genl_util *f, int argc, char **argv) return 0; } -static struct genl_util *get_genl_kind(char *str) +static struct genl_util *get_genl_kind(const char *str) { void *dlh; char buf[256]; From e49b51d6631290bf2df0efd56aa511e3387216ea Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 30 Dec 2015 17:19:04 -0800 Subject: [PATCH 016/513] monitor: fix file handle leak In some cases passing file to monitor left file open. Signed-off-by: Stephen Hemminger --- ip/ipmonitor.c | 6 +++++- ip/xfrm_monitor.c | 6 +++++- tc/tc_monitor.c | 10 +++++++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c index 8bcf8822b..99a237f47 100644 --- a/ip/ipmonitor.c +++ b/ip/ipmonitor.c @@ -284,12 +284,16 @@ int do_ipmonitor(int argc, char **argv) } if (file) { FILE *fp; + int err; + fp = fopen(file, "r"); if (fp == NULL) { perror("Cannot fopen"); exit(-1); } - return rtnl_from_file(fp, accept_msg, stdout); + err = rtnl_from_file(fp, accept_msg, stdout); + fclose(fp); + return err; } if (rtnl_open(&rth, groups) < 0) diff --git a/ip/xfrm_monitor.c b/ip/xfrm_monitor.c index 8b21efad5..e6e991afc 100644 --- a/ip/xfrm_monitor.c +++ b/ip/xfrm_monitor.c @@ -411,12 +411,16 @@ int do_xfrm_monitor(int argc, char **argv) if (file) { FILE *fp; + int err; + fp = fopen(file, "r"); if (fp == NULL) { perror("Cannot fopen"); exit(-1); } - return rtnl_from_file(fp, xfrm_accept_msg, (void*)stdout); + err = rtnl_from_file(fp, xfrm_accept_msg, stdout); + fclose(fp); + return err; } if (rtnl_open_byproto(&rth, groups, NETLINK_XFRM) < 0) diff --git a/tc/tc_monitor.c b/tc/tc_monitor.c index 097068e91..ebb943208 100644 --- a/tc/tc_monitor.c +++ b/tc/tc_monitor.c @@ -91,13 +91,17 @@ int do_tcmonitor(int argc, char **argv) } if (file) { - FILE *fp; - fp = fopen(file, "r"); + FILE *fp = fopen(file, "r"); + int ret; + if (fp == NULL) { perror("Cannot fopen"); exit(-1); } - return rtnl_from_file(fp, accept_tcmsg, (void*)stdout); + + ret = rtnl_from_file(fp, accept_tcmsg, stdout); + fclose(fp); + return ret; } if (rtnl_open(&rth, groups) < 0) From b90b773ca6aa1b1a39d76186d1a7639a13f5c916 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 30 Dec 2015 17:28:11 -0800 Subject: [PATCH 017/513] lnstat: fix error handling Error handling was silent and had leaks. Signed-off-by: Stephen Hemminger --- misc/lnstat_util.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/misc/lnstat_util.c b/misc/lnstat_util.c index 70a77c564..a25836657 100644 --- a/misc/lnstat_util.c +++ b/misc/lnstat_util.c @@ -172,8 +172,10 @@ static struct lnstat_file *alloc_and_open(const char *path, const char *file) /* allocate */ lf = malloc(sizeof(*lf)); - if (!lf) + if (!lf) { + fprintf(stderr, "out of memory\n"); return NULL; + } /* initialize */ memset(lf, 0, sizeof(*lf)); @@ -190,6 +192,7 @@ static struct lnstat_file *alloc_and_open(const char *path, const char *file) /* open */ lf->fp = fopen(lf->path, "r"); if (!lf->fp) { + perror(lf->path); free(lf); return NULL; } @@ -256,12 +259,16 @@ struct lnstat_file *lnstat_scan_dir(const char *path, const int num_req_files, continue; lf = alloc_and_open(path, de->d_name); - if (!lf) + if (!lf) { + closedir(dir); return NULL; + } /* fill in field structure */ - if (lnstat_scan_fields(lf) < 0) + if (lnstat_scan_fields(lf) < 0) { + closedir(dir); return NULL; + } /* prepend to global list */ lf->next = lnstat_files; From c13b6b097ab38b346271ce5ef802a0372dcbf78d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 30 Dec 2015 18:06:12 -0800 Subject: [PATCH 018/513] add coverity model file Track any coverity overrides for this project. Signed-off-by: Stephen Hemminger --- lib/coverity_model.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 lib/coverity_model.c diff --git a/lib/coverity_model.c b/lib/coverity_model.c new file mode 100644 index 000000000..c89630206 --- /dev/null +++ b/lib/coverity_model.c @@ -0,0 +1,19 @@ +/* + * Coverity Scan model + * + * This is a modeling file for Coverity Scan. Modeling helps to avoid false + * positives. + * + * - A model file can't import any header files. + * - Therefore only some built-in primitives like int, char and void are + * available but not wchar_t, NULL etc. + * - Modeling doesn't need full structs and typedefs. Rudimentary structs + * and similar types are sufficient. + * - An uninitialized local pointer is not an error. It signifies that the + * variable could be either NULL or have some data. + * + * Coverity Scan doesn't pick up modifications automatically. The model file + * must be uploaded by an admin. + */ + + From 5cd1adba79d33644debd4ba498bb262c5bebcfba Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 3 Jan 2016 15:14:27 -0800 Subject: [PATCH 019/513] Update to current iptables headers Keep in sync with current iptables upstream --- include/ip6tables.h | 141 +------ include/iptables.h | 186 +-------- include/iptables/internal.h | 13 + include/libiptc/ipt_kernel_headers.h | 13 +- include/libiptc/libip6tc.h | 127 +++--- include/libiptc/libiptc.h | 128 +++--- include/libiptc/libxtc.h | 33 ++ include/libiptc/xtcshared.h | 20 + include/xtables.h | 567 +++++++++++++++++++++++++++ 9 files changed, 794 insertions(+), 434 deletions(-) create mode 100644 include/iptables/internal.h create mode 100644 include/libiptc/libxtc.h create mode 100644 include/libiptc/xtcshared.h create mode 100644 include/xtables.h diff --git a/include/ip6tables.h b/include/ip6tables.h index 1050593a9..5f1c5b65e 100644 --- a/include/ip6tables.h +++ b/include/ip6tables.h @@ -1,141 +1,20 @@ #ifndef _IP6TABLES_USER_H #define _IP6TABLES_USER_H -#include "iptables_common.h" -#include "libiptc/libip6tc.h" - -struct ip6tables_rule_match -{ - struct ip6tables_rule_match *next; - - struct ip6tables_match *match; -}; - -/* Include file for additions: new matches and targets. */ -struct ip6tables_match -{ - struct ip6tables_match *next; - - ip6t_chainlabel name; - - const char *version; - - /* Size of match data. */ - size_t size; - - /* Size of match data relevent for userspace comparison purposes */ - size_t userspacesize; - - /* Function which prints out usage message. */ - void (*help)(void); - - /* Initialize the match. */ - void (*init)(struct ip6t_entry_match *m, unsigned int *nfcache); - - /* Function which parses command options; returns true if it - ate an option */ - int (*parse)(int c, char **argv, int invert, unsigned int *flags, - const struct ip6t_entry *entry, - unsigned int *nfcache, - struct ip6t_entry_match **match); - - /* Final check; exit if not ok. */ - void (*final_check)(unsigned int flags); - - /* Prints out the match iff non-NULL: put space at end */ - void (*print)(const struct ip6t_ip6 *ip, - const struct ip6t_entry_match *match, int numeric); - - /* Saves the union ipt_matchinfo in parsable form to stdout. */ - void (*save)(const struct ip6t_ip6 *ip, - const struct ip6t_entry_match *match); - - /* Pointer to list of extra command-line options */ - const struct option *extra_opts; - - /* Ignore these men behind the curtain: */ - unsigned int option_offset; - struct ip6t_entry_match *m; - unsigned int mflags; -#ifdef NO_SHARED_LIBS - unsigned int loaded; /* simulate loading so options are merged properly */ -#endif -}; - -struct ip6tables_target -{ - struct ip6tables_target *next; - - ip6t_chainlabel name; - - const char *version; - - /* Size of target data. */ - size_t size; - - /* Size of target data relevent for userspace comparison purposes */ - size_t userspacesize; - - /* Function which prints out usage message. */ - void (*help)(void); - - /* Initialize the target. */ - void (*init)(struct ip6t_entry_target *t, unsigned int *nfcache); - - /* Function which parses command options; returns true if it - ate an option */ - int (*parse)(int c, char **argv, int invert, unsigned int *flags, - const struct ip6t_entry *entry, - struct ip6t_entry_target **target); - - /* Final check; exit if not ok. */ - void (*final_check)(unsigned int flags); - - /* Prints out the target iff non-NULL: put space at end */ - void (*print)(const struct ip6t_ip6 *ip, - const struct ip6t_entry_target *target, int numeric); - - /* Saves the targinfo in parsable form to stdout. */ - void (*save)(const struct ip6t_ip6 *ip, - const struct ip6t_entry_target *target); - - /* Pointer to list of extra command-line options */ - struct option *extra_opts; - - /* Ignore these men behind the curtain: */ - unsigned int option_offset; - struct ip6t_entry_target *t; - unsigned int tflags; - unsigned int used; -#ifdef NO_SHARED_LIBS - unsigned int loaded; /* simulate loading so options are merged properly */ -#endif -}; - -extern int line; +#include +#include +#include +#include /* Your shared library should call one of these. */ -extern void register_match6(struct ip6tables_match *me); -extern void register_target6(struct ip6tables_target *me); - extern int do_command6(int argc, char *argv[], char **table, - ip6tc_handle_t *handle); -/* Keeping track of external matches and targets: linked lists. */ -extern struct ip6tables_match *ip6tables_matches; -extern struct ip6tables_target *ip6tables_targets; - -enum ip6t_tryload { - DONT_LOAD, - TRY_LOAD, - LOAD_MUST_SUCCEED -}; + struct xtc_handle **handle, bool restore); -extern struct ip6tables_target *find_target(const char *name, enum ip6t_tryload); -extern struct ip6tables_match *find_match(const char *name, enum ip6t_tryload, struct ip6tables_rule_match **match); +extern int for_each_chain6(int (*fn)(const xt_chainlabel, int, struct xtc_handle *), int verbose, int builtinstoo, struct xtc_handle *handle); +extern int flush_entries6(const xt_chainlabel chain, int verbose, struct xtc_handle *handle); +extern int delete_chain6(const xt_chainlabel chain, int verbose, struct xtc_handle *handle); +void print_rule6(const struct ip6t_entry *e, struct xtc_handle *h, const char *chain, int counters); -extern int for_each_chain(int (*fn)(const ip6t_chainlabel, int, ip6tc_handle_t *), int verbose, int builtinstoo, ip6tc_handle_t *handle); -extern int flush_entries(const ip6t_chainlabel chain, int verbose, ip6tc_handle_t *handle); -extern int delete_chain(const ip6t_chainlabel chain, int verbose, ip6tc_handle_t *handle); -extern int ip6tables_insmod(const char *modname, const char *modprobe); +extern struct xtables_globals ip6tables_globals; #endif /*_IP6TABLES_USER_H*/ diff --git a/include/iptables.h b/include/iptables.h index f1e62e233..78c10abd7 100644 --- a/include/iptables.h +++ b/include/iptables.h @@ -1,179 +1,25 @@ #ifndef _IPTABLES_USER_H #define _IPTABLES_USER_H -#include "iptables_common.h" -#include "libiptc/libiptc.h" - -#ifndef IPT_LIB_DIR -#define IPT_LIB_DIR "/usr/local/lib/iptables" -#endif - -#ifndef IPPROTO_SCTP -#define IPPROTO_SCTP 132 -#endif - -#ifndef IPT_SO_GET_REVISION_MATCH /* Old kernel source. */ -#define IPT_SO_GET_REVISION_MATCH (IPT_BASE_CTL + 2) -#define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3) - -struct ipt_get_revision -{ - char name[IPT_FUNCTION_MAXNAMELEN-1]; - - u_int8_t revision; -}; -#endif /* IPT_SO_GET_REVISION_MATCH Old kernel source */ - -struct iptables_rule_match -{ - struct iptables_rule_match *next; - - struct iptables_match *match; -}; - -/* Include file for additions: new matches and targets. */ -struct iptables_match -{ - struct iptables_match *next; - - ipt_chainlabel name; - - /* Revision of match (0 by default). */ - u_int8_t revision; - - const char *version; - - /* Size of match data. */ - size_t size; - - /* Size of match data relevent for userspace comparison purposes */ - size_t userspacesize; - - /* Function which prints out usage message. */ - void (*help)(void); - - /* Initialize the match. */ - void (*init)(struct ipt_entry_match *m, unsigned int *nfcache); - - /* Function which parses command options; returns true if it - ate an option */ - int (*parse)(int c, char **argv, int invert, unsigned int *flags, - const struct ipt_entry *entry, - unsigned int *nfcache, - struct ipt_entry_match **match); - - /* Final check; exit if not ok. */ - void (*final_check)(unsigned int flags); - - /* Prints out the match iff non-NULL: put space at end */ - void (*print)(const struct ipt_ip *ip, - const struct ipt_entry_match *match, int numeric); - - /* Saves the match info in parsable form to stdout. */ - void (*save)(const struct ipt_ip *ip, - const struct ipt_entry_match *match); - - /* Pointer to list of extra command-line options */ - const struct option *extra_opts; - - /* Ignore these men behind the curtain: */ - unsigned int option_offset; - struct ipt_entry_match *m; - unsigned int mflags; -#ifdef NO_SHARED_LIBS - unsigned int loaded; /* simulate loading so options are merged properly */ -#endif -}; - -struct iptables_target -{ - struct iptables_target *next; - - ipt_chainlabel name; - - /* Revision of target (0 by default). */ - u_int8_t revision; - - const char *version; - - /* Size of target data. */ - size_t size; - - /* Size of target data relevent for userspace comparison purposes */ - size_t userspacesize; - - /* Function which prints out usage message. */ - void (*help)(void); - - /* Initialize the target. */ - void (*init)(struct ipt_entry_target *t, unsigned int *nfcache); - - /* Function which parses command options; returns true if it - ate an option */ - int (*parse)(int c, char **argv, int invert, unsigned int *flags, - const struct ipt_entry *entry, - struct ipt_entry_target **target); - - /* Final check; exit if not ok. */ - void (*final_check)(unsigned int flags); - - /* Prints out the target iff non-NULL: put space at end */ - void (*print)(const struct ipt_ip *ip, - const struct ipt_entry_target *target, int numeric); - - /* Saves the targinfo in parsable form to stdout. */ - void (*save)(const struct ipt_ip *ip, - const struct ipt_entry_target *target); - - /* Pointer to list of extra command-line options */ - struct option *extra_opts; - - /* Ignore these men behind the curtain: */ - unsigned int option_offset; - struct ipt_entry_target *t; - unsigned int tflags; - unsigned int used; -#ifdef NO_SHARED_LIBS - unsigned int loaded; /* simulate loading so options are merged properly */ -#endif -}; - -extern int line; +#include +#include +#include +#include /* Your shared library should call one of these. */ -extern void register_match(struct iptables_match *me); -extern void register_target(struct iptables_target *me); -extern void xtables_register_target(struct iptables_target *me); -extern int build_st(struct iptables_target *target, struct ipt_entry_target *t); - -extern struct in_addr *dotted_to_addr(const char *dotted); -extern char *addr_to_dotted(const struct in_addr *addrp); -extern char *addr_to_anyname(const struct in_addr *addr); -extern char *mask_to_dotted(const struct in_addr *mask); - -extern void parse_hostnetworkmask(const char *name, struct in_addr **addrpp, - struct in_addr *maskp, unsigned int *naddrs); -extern u_int16_t parse_protocol(const char *s); - -extern int do_command(int argc, char *argv[], char **table, - iptc_handle_t *handle); -/* Keeping track of external matches and targets: linked lists. */ -extern struct iptables_match *iptables_matches; -extern struct iptables_target *iptables_targets; +extern int do_command4(int argc, char *argv[], char **table, + struct xtc_handle **handle, bool restore); +extern int delete_chain4(const xt_chainlabel chain, int verbose, + struct xtc_handle *handle); +extern int flush_entries4(const xt_chainlabel chain, int verbose, + struct xtc_handle *handle); +extern int for_each_chain4(int (*fn)(const xt_chainlabel, int, struct xtc_handle *), + int verbose, int builtinstoo, struct xtc_handle *handle); +extern void print_rule4(const struct ipt_entry *e, + struct xtc_handle *handle, const char *chain, int counters); -enum ipt_tryload { - DONT_LOAD, - TRY_LOAD, - LOAD_MUST_SUCCEED -}; +extern struct xtables_globals iptables_globals; -extern struct iptables_target *find_target(const char *name, enum ipt_tryload); -extern struct iptables_match *find_match(const char *name, enum ipt_tryload, struct iptables_rule_match **match); +extern struct xtables_globals xtables_globals; -extern int delete_chain(const ipt_chainlabel chain, int verbose, - iptc_handle_t *handle); -extern int flush_entries(const ipt_chainlabel chain, int verbose, - iptc_handle_t *handle); -extern int for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *), - int verbose, int builtinstoo, iptc_handle_t *handle); #endif /*_IPTABLES_USER_H*/ diff --git a/include/iptables/internal.h b/include/iptables/internal.h new file mode 100644 index 000000000..62a8ecb99 --- /dev/null +++ b/include/iptables/internal.h @@ -0,0 +1,13 @@ +#ifndef IPTABLES_INTERNAL_H +#define IPTABLES_INTERNAL_H 1 + +#define IPTABLES_VERSION "1.6.0" + +/** + * Program's own name and version. + */ +extern const char *program_name, *program_version; + +extern int line; + +#endif /* IPTABLES_INTERNAL_H */ diff --git a/include/libiptc/ipt_kernel_headers.h b/include/libiptc/ipt_kernel_headers.h index 7e8782842..a5963e944 100644 --- a/include/libiptc/ipt_kernel_headers.h +++ b/include/libiptc/ipt_kernel_headers.h @@ -5,22 +5,11 @@ #include -#if defined(__GLIBC__) && __GLIBC__ == 2 #include #include #include #include #include +#include #include -#else /* libc5 */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif #endif diff --git a/include/libiptc/libip6tc.h b/include/libiptc/libip6tc.h index 7a247c46f..9aed80a02 100644 --- a/include/libiptc/libip6tc.h +++ b/include/libiptc/libip6tc.h @@ -2,153 +2,160 @@ #define _LIBIP6TC_H /* Library which manipulates firewall rules. Version 0.2. */ +#include #include -#include - -#ifndef IP6T_MIN_ALIGN -#define IP6T_MIN_ALIGN (__alignof__(struct ip6t_entry)) +#ifdef __cplusplus +# include +#else +# include /* INT_MAX in ip6_tables.h */ #endif -#define IP6T_ALIGN(s) (((s) + (IP6T_MIN_ALIGN-1)) & ~(IP6T_MIN_ALIGN-1)) +#include +#include -typedef char ip6t_chainlabel[32]; +#define ip6tc_handle xtc_handle +#define ip6t_chainlabel xt_chainlabel #define IP6TC_LABEL_ACCEPT "ACCEPT" #define IP6TC_LABEL_DROP "DROP" #define IP6TC_LABEL_QUEUE "QUEUE" #define IP6TC_LABEL_RETURN "RETURN" -/* Transparent handle type. */ -typedef struct ip6tc_handle *ip6tc_handle_t; - /* Does this chain exist? */ -int ip6tc_is_chain(const char *chain, const ip6tc_handle_t handle); +int ip6tc_is_chain(const char *chain, struct xtc_handle *const handle); /* Take a snapshot of the rules. Returns NULL on error. */ -ip6tc_handle_t ip6tc_init(const char *tablename); +struct xtc_handle *ip6tc_init(const char *tablename); /* Cleanup after ip6tc_init(). */ -void ip6tc_free(ip6tc_handle_t *h); +void ip6tc_free(struct xtc_handle *h); /* Iterator functions to run through the chains. Returns NULL at end. */ -const char *ip6tc_first_chain(ip6tc_handle_t *handle); -const char *ip6tc_next_chain(ip6tc_handle_t *handle); +const char *ip6tc_first_chain(struct xtc_handle *handle); +const char *ip6tc_next_chain(struct xtc_handle *handle); /* Get first rule in the given chain: NULL for empty chain. */ const struct ip6t_entry *ip6tc_first_rule(const char *chain, - ip6tc_handle_t *handle); + struct xtc_handle *handle); /* Returns NULL when rules run out. */ const struct ip6t_entry *ip6tc_next_rule(const struct ip6t_entry *prev, - ip6tc_handle_t *handle); + struct xtc_handle *handle); /* Returns a pointer to the target name of this position. */ const char *ip6tc_get_target(const struct ip6t_entry *e, - ip6tc_handle_t *handle); + struct xtc_handle *handle); /* Is this a built-in chain? */ -int ip6tc_builtin(const char *chain, const ip6tc_handle_t handle); +int ip6tc_builtin(const char *chain, struct xtc_handle *const handle); /* Get the policy of a given built-in chain */ const char *ip6tc_get_policy(const char *chain, - struct ip6t_counters *counters, - ip6tc_handle_t *handle); + struct xt_counters *counters, + struct xtc_handle *handle); /* These functions return TRUE for OK or 0 and set errno. If errno == 0, it means there was a version error (ie. upgrade libiptc). */ /* Rule numbers start at 1 for the first rule. */ /* Insert the entry `fw' in chain `chain' into position `rulenum'. */ -int ip6tc_insert_entry(const ip6t_chainlabel chain, +int ip6tc_insert_entry(const xt_chainlabel chain, const struct ip6t_entry *e, unsigned int rulenum, - ip6tc_handle_t *handle); + struct xtc_handle *handle); /* Atomically replace rule `rulenum' in `chain' with `fw'. */ -int ip6tc_replace_entry(const ip6t_chainlabel chain, +int ip6tc_replace_entry(const xt_chainlabel chain, const struct ip6t_entry *e, unsigned int rulenum, - ip6tc_handle_t *handle); + struct xtc_handle *handle); /* Append entry `fw' to chain `chain'. Equivalent to insert with rulenum = length of chain. */ -int ip6tc_append_entry(const ip6t_chainlabel chain, +int ip6tc_append_entry(const xt_chainlabel chain, const struct ip6t_entry *e, - ip6tc_handle_t *handle); + struct xtc_handle *handle); + +/* Check whether a matching rule exists */ +int ip6tc_check_entry(const xt_chainlabel chain, + const struct ip6t_entry *origfw, + unsigned char *matchmask, + struct xtc_handle *handle); /* Delete the first rule in `chain' which matches `fw'. */ -int ip6tc_delete_entry(const ip6t_chainlabel chain, +int ip6tc_delete_entry(const xt_chainlabel chain, const struct ip6t_entry *origfw, unsigned char *matchmask, - ip6tc_handle_t *handle); + struct xtc_handle *handle); /* Delete the rule in position `rulenum' in `chain'. */ -int ip6tc_delete_num_entry(const ip6t_chainlabel chain, +int ip6tc_delete_num_entry(const xt_chainlabel chain, unsigned int rulenum, - ip6tc_handle_t *handle); + struct xtc_handle *handle); /* Check the packet `fw' on chain `chain'. Returns the verdict, or NULL and sets errno. */ -const char *ip6tc_check_packet(const ip6t_chainlabel chain, +const char *ip6tc_check_packet(const xt_chainlabel chain, struct ip6t_entry *, - ip6tc_handle_t *handle); + struct xtc_handle *handle); /* Flushes the entries in the given chain (ie. empties chain). */ -int ip6tc_flush_entries(const ip6t_chainlabel chain, - ip6tc_handle_t *handle); +int ip6tc_flush_entries(const xt_chainlabel chain, + struct xtc_handle *handle); /* Zeroes the counters in a chain. */ -int ip6tc_zero_entries(const ip6t_chainlabel chain, - ip6tc_handle_t *handle); +int ip6tc_zero_entries(const xt_chainlabel chain, + struct xtc_handle *handle); /* Creates a new chain. */ -int ip6tc_create_chain(const ip6t_chainlabel chain, - ip6tc_handle_t *handle); +int ip6tc_create_chain(const xt_chainlabel chain, + struct xtc_handle *handle); /* Deletes a chain. */ -int ip6tc_delete_chain(const ip6t_chainlabel chain, - ip6tc_handle_t *handle); +int ip6tc_delete_chain(const xt_chainlabel chain, + struct xtc_handle *handle); /* Renames a chain. */ -int ip6tc_rename_chain(const ip6t_chainlabel oldname, - const ip6t_chainlabel newname, - ip6tc_handle_t *handle); +int ip6tc_rename_chain(const xt_chainlabel oldname, + const xt_chainlabel newname, + struct xtc_handle *handle); /* Sets the policy on a built-in chain. */ -int ip6tc_set_policy(const ip6t_chainlabel chain, - const ip6t_chainlabel policy, - struct ip6t_counters *counters, - ip6tc_handle_t *handle); +int ip6tc_set_policy(const xt_chainlabel chain, + const xt_chainlabel policy, + struct xt_counters *counters, + struct xtc_handle *handle); /* Get the number of references to this chain */ -int ip6tc_get_references(unsigned int *ref, const ip6t_chainlabel chain, - ip6tc_handle_t *handle); +int ip6tc_get_references(unsigned int *ref, const xt_chainlabel chain, + struct xtc_handle *handle); /* read packet and byte counters for a specific rule */ -struct ip6t_counters *ip6tc_read_counter(const ip6t_chainlabel chain, +struct xt_counters *ip6tc_read_counter(const xt_chainlabel chain, unsigned int rulenum, - ip6tc_handle_t *handle); + struct xtc_handle *handle); /* zero packet and byte counters for a specific rule */ -int ip6tc_zero_counter(const ip6t_chainlabel chain, +int ip6tc_zero_counter(const xt_chainlabel chain, unsigned int rulenum, - ip6tc_handle_t *handle); + struct xtc_handle *handle); /* set packet and byte counters for a specific rule */ -int ip6tc_set_counter(const ip6t_chainlabel chain, +int ip6tc_set_counter(const xt_chainlabel chain, unsigned int rulenum, - struct ip6t_counters *counters, - ip6tc_handle_t *handle); + struct xt_counters *counters, + struct xtc_handle *handle); /* Makes the actual changes. */ -int ip6tc_commit(ip6tc_handle_t *handle); +int ip6tc_commit(struct xtc_handle *handle); /* Get raw socket. */ -int ip6tc_get_raw_socket(); +int ip6tc_get_raw_socket(void); /* Translates errno numbers into more human-readable form than strerror. */ const char *ip6tc_strerror(int err); -/* Return prefix length, or -1 if not contiguous */ -int ipv6_prefix_length(const struct in6_addr *a); +extern void dump_entries6(struct xtc_handle *const); + +extern const struct xtc_ops ip6tc_ops; #endif /* _LIBIP6TC_H */ diff --git a/include/libiptc/libiptc.h b/include/libiptc/libiptc.h index 7628bda6f..24cdbdb79 100644 --- a/include/libiptc/libiptc.h +++ b/include/libiptc/libiptc.h @@ -2,155 +2,157 @@ #define _LIBIPTC_H /* Library which manipulates filtering rules. */ +#include #include +#ifdef __cplusplus +# include +#else +# include /* INT_MAX in ip_tables.h */ +#endif #include +#include #ifdef __cplusplus extern "C" { #endif -#ifndef IPT_MIN_ALIGN -/* ipt_entry has pointers and u_int64_t's in it, so if you align to - it, you'll also align to any crazy matches and targets someone - might write */ -#define IPT_MIN_ALIGN (__alignof__(struct ipt_entry)) -#endif - -#define IPT_ALIGN(s) (((s) + ((IPT_MIN_ALIGN)-1)) & ~((IPT_MIN_ALIGN)-1)) - -typedef char ipt_chainlabel[32]; +#define iptc_handle xtc_handle +#define ipt_chainlabel xt_chainlabel #define IPTC_LABEL_ACCEPT "ACCEPT" #define IPTC_LABEL_DROP "DROP" #define IPTC_LABEL_QUEUE "QUEUE" #define IPTC_LABEL_RETURN "RETURN" -/* Transparent handle type. */ -typedef struct iptc_handle *iptc_handle_t; - /* Does this chain exist? */ -int iptc_is_chain(const char *chain, const iptc_handle_t handle); +int iptc_is_chain(const char *chain, struct xtc_handle *const handle); /* Take a snapshot of the rules. Returns NULL on error. */ -iptc_handle_t iptc_init(const char *tablename); +struct xtc_handle *iptc_init(const char *tablename); /* Cleanup after iptc_init(). */ -void iptc_free(iptc_handle_t *h); +void iptc_free(struct xtc_handle *h); /* Iterator functions to run through the chains. Returns NULL at end. */ -const char *iptc_first_chain(iptc_handle_t *handle); -const char *iptc_next_chain(iptc_handle_t *handle); +const char *iptc_first_chain(struct xtc_handle *handle); +const char *iptc_next_chain(struct xtc_handle *handle); /* Get first rule in the given chain: NULL for empty chain. */ const struct ipt_entry *iptc_first_rule(const char *chain, - iptc_handle_t *handle); + struct xtc_handle *handle); /* Returns NULL when rules run out. */ const struct ipt_entry *iptc_next_rule(const struct ipt_entry *prev, - iptc_handle_t *handle); + struct xtc_handle *handle); /* Returns a pointer to the target name of this entry. */ const char *iptc_get_target(const struct ipt_entry *e, - iptc_handle_t *handle); + struct xtc_handle *handle); /* Is this a built-in chain? */ -int iptc_builtin(const char *chain, const iptc_handle_t handle); +int iptc_builtin(const char *chain, struct xtc_handle *const handle); /* Get the policy of a given built-in chain */ const char *iptc_get_policy(const char *chain, - struct ipt_counters *counter, - iptc_handle_t *handle); + struct xt_counters *counter, + struct xtc_handle *handle); /* These functions return TRUE for OK or 0 and set errno. If errno == 0, it means there was a version error (ie. upgrade libiptc). */ /* Rule numbers start at 1 for the first rule. */ /* Insert the entry `e' in chain `chain' into position `rulenum'. */ -int iptc_insert_entry(const ipt_chainlabel chain, +int iptc_insert_entry(const xt_chainlabel chain, const struct ipt_entry *e, unsigned int rulenum, - iptc_handle_t *handle); + struct xtc_handle *handle); /* Atomically replace rule `rulenum' in `chain' with `e'. */ -int iptc_replace_entry(const ipt_chainlabel chain, +int iptc_replace_entry(const xt_chainlabel chain, const struct ipt_entry *e, unsigned int rulenum, - iptc_handle_t *handle); + struct xtc_handle *handle); /* Append entry `e' to chain `chain'. Equivalent to insert with rulenum = length of chain. */ -int iptc_append_entry(const ipt_chainlabel chain, +int iptc_append_entry(const xt_chainlabel chain, const struct ipt_entry *e, - iptc_handle_t *handle); + struct xtc_handle *handle); + +/* Check whether a mathching rule exists */ +int iptc_check_entry(const xt_chainlabel chain, + const struct ipt_entry *origfw, + unsigned char *matchmask, + struct xtc_handle *handle); /* Delete the first rule in `chain' which matches `e', subject to matchmask (array of length == origfw) */ -int iptc_delete_entry(const ipt_chainlabel chain, +int iptc_delete_entry(const xt_chainlabel chain, const struct ipt_entry *origfw, unsigned char *matchmask, - iptc_handle_t *handle); + struct xtc_handle *handle); /* Delete the rule in position `rulenum' in `chain'. */ -int iptc_delete_num_entry(const ipt_chainlabel chain, +int iptc_delete_num_entry(const xt_chainlabel chain, unsigned int rulenum, - iptc_handle_t *handle); + struct xtc_handle *handle); /* Check the packet `e' on chain `chain'. Returns the verdict, or NULL and sets errno. */ -const char *iptc_check_packet(const ipt_chainlabel chain, +const char *iptc_check_packet(const xt_chainlabel chain, struct ipt_entry *entry, - iptc_handle_t *handle); + struct xtc_handle *handle); /* Flushes the entries in the given chain (ie. empties chain). */ -int iptc_flush_entries(const ipt_chainlabel chain, - iptc_handle_t *handle); +int iptc_flush_entries(const xt_chainlabel chain, + struct xtc_handle *handle); /* Zeroes the counters in a chain. */ -int iptc_zero_entries(const ipt_chainlabel chain, - iptc_handle_t *handle); +int iptc_zero_entries(const xt_chainlabel chain, + struct xtc_handle *handle); /* Creates a new chain. */ -int iptc_create_chain(const ipt_chainlabel chain, - iptc_handle_t *handle); +int iptc_create_chain(const xt_chainlabel chain, + struct xtc_handle *handle); /* Deletes a chain. */ -int iptc_delete_chain(const ipt_chainlabel chain, - iptc_handle_t *handle); +int iptc_delete_chain(const xt_chainlabel chain, + struct xtc_handle *handle); /* Renames a chain. */ -int iptc_rename_chain(const ipt_chainlabel oldname, - const ipt_chainlabel newname, - iptc_handle_t *handle); +int iptc_rename_chain(const xt_chainlabel oldname, + const xt_chainlabel newname, + struct xtc_handle *handle); /* Sets the policy on a built-in chain. */ -int iptc_set_policy(const ipt_chainlabel chain, - const ipt_chainlabel policy, - struct ipt_counters *counters, - iptc_handle_t *handle); +int iptc_set_policy(const xt_chainlabel chain, + const xt_chainlabel policy, + struct xt_counters *counters, + struct xtc_handle *handle); /* Get the number of references to this chain */ int iptc_get_references(unsigned int *ref, - const ipt_chainlabel chain, - iptc_handle_t *handle); + const xt_chainlabel chain, + struct xtc_handle *handle); /* read packet and byte counters for a specific rule */ -struct ipt_counters *iptc_read_counter(const ipt_chainlabel chain, +struct xt_counters *iptc_read_counter(const xt_chainlabel chain, unsigned int rulenum, - iptc_handle_t *handle); + struct xtc_handle *handle); /* zero packet and byte counters for a specific rule */ -int iptc_zero_counter(const ipt_chainlabel chain, +int iptc_zero_counter(const xt_chainlabel chain, unsigned int rulenum, - iptc_handle_t *handle); + struct xtc_handle *handle); /* set packet and byte counters for a specific rule */ -int iptc_set_counter(const ipt_chainlabel chain, +int iptc_set_counter(const xt_chainlabel chain, unsigned int rulenum, - struct ipt_counters *counters, - iptc_handle_t *handle); + struct xt_counters *counters, + struct xtc_handle *handle); /* Makes the actual changes. */ -int iptc_commit(iptc_handle_t *handle); +int iptc_commit(struct xtc_handle *handle); /* Get raw socket. */ int iptc_get_raw_socket(void); @@ -158,6 +160,10 @@ int iptc_get_raw_socket(void); /* Translates errno numbers into more human-readable form than strerror. */ const char *iptc_strerror(int err); +extern void dump_entries(struct xtc_handle *const); + +extern const struct xtc_ops iptc_ops; + #ifdef __cplusplus } #endif diff --git a/include/libiptc/libxtc.h b/include/libiptc/libxtc.h new file mode 100644 index 000000000..37010188b --- /dev/null +++ b/include/libiptc/libxtc.h @@ -0,0 +1,33 @@ +#ifndef _LIBXTC_H +#define _LIBXTC_H +/* Library which manipulates filtering rules. */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef XT_MIN_ALIGN +/* xt_entry has pointers and u_int64_t's in it, so if you align to + it, you'll also align to any crazy matches and targets someone + might write */ +#define XT_MIN_ALIGN (__alignof__(struct xt_entry)) +#endif + +#ifndef XT_ALIGN +#define XT_ALIGN(s) (((s) + ((XT_MIN_ALIGN)-1)) & ~((XT_MIN_ALIGN)-1)) +#endif + +#define XTC_LABEL_ACCEPT "ACCEPT" +#define XTC_LABEL_DROP "DROP" +#define XTC_LABEL_QUEUE "QUEUE" +#define XTC_LABEL_RETURN "RETURN" + + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBXTC_H */ diff --git a/include/libiptc/xtcshared.h b/include/libiptc/xtcshared.h new file mode 100644 index 000000000..773ebc4c7 --- /dev/null +++ b/include/libiptc/xtcshared.h @@ -0,0 +1,20 @@ +#ifndef _LIBXTC_SHARED_H +#define _LIBXTC_SHARED_H 1 + +typedef char xt_chainlabel[32]; +struct xtc_handle; +struct xt_counters; + +struct xtc_ops { + int (*commit)(struct xtc_handle *); + void (*free)(struct xtc_handle *); + int (*builtin)(const char *, struct xtc_handle *const); + int (*is_chain)(const char *, struct xtc_handle *const); + int (*flush_entries)(const xt_chainlabel, struct xtc_handle *); + int (*create_chain)(const xt_chainlabel, struct xtc_handle *); + int (*set_policy)(const xt_chainlabel, const xt_chainlabel, + struct xt_counters *, struct xtc_handle *); + const char *(*strerror)(int); +}; + +#endif /* _LIBXTC_SHARED_H */ diff --git a/include/xtables.h b/include/xtables.h new file mode 100644 index 000000000..978ae0d15 --- /dev/null +++ b/include/xtables.h @@ -0,0 +1,567 @@ +#ifndef _XTABLES_H +#define _XTABLES_H + +/* + * Changing any structs/functions may incur a needed change + * in libxtables_vcurrent/vage too. + */ + +#include /* PF_* */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132 +#endif +#ifndef IPPROTO_DCCP +#define IPPROTO_DCCP 33 +#endif +#ifndef IPPROTO_MH +# define IPPROTO_MH 135 +#endif +#ifndef IPPROTO_UDPLITE +#define IPPROTO_UDPLITE 136 +#endif + +#include + +struct in_addr; + +/* + * .size is here so that there is a somewhat reasonable check + * against the chosen .type. + */ +#define XTOPT_POINTER(stype, member) \ + .ptroff = offsetof(stype, member), \ + .size = sizeof(((stype *)NULL)->member) +#define XTOPT_TABLEEND {.name = NULL} + +/** + * Select the format the input has to conform to, as well as the target type + * (area pointed to with XTOPT_POINTER). Note that the storing is not always + * uniform. @cb->val will be populated with as much as there is space, i.e. + * exactly 2 items for ranges, but the target area can receive more values + * (e.g. in case of ranges), or less values (e.g. %XTTYPE_HOSTMASK). + * + * %XTTYPE_NONE: option takes no argument + * %XTTYPE_UINT*: standard integer + * %XTTYPE_UINT*RC: colon-separated range of standard integers + * %XTTYPE_DOUBLE: double-precision floating point number + * %XTTYPE_STRING: arbitrary string + * %XTTYPE_TOSMASK: 8-bit TOS value with optional mask + * %XTTYPE_MARKMASK32: 32-bit mark with optional mask + * %XTTYPE_SYSLOGLEVEL: syslog level by name or number + * %XTTYPE_HOST: one host or address (ptr: union nf_inet_addr) + * %XTTYPE_HOSTMASK: one host or address, with an optional prefix length + * (ptr: union nf_inet_addr; only host portion is stored) + * %XTTYPE_PROTOCOL: protocol number/name from /etc/protocols (ptr: uint8_t) + * %XTTYPE_PORT: 16-bit port name or number (supports %XTOPT_NBO) + * %XTTYPE_PORTRC: colon-separated port range (names acceptable), + * (supports %XTOPT_NBO) + * %XTTYPE_PLEN: prefix length + * %XTTYPE_PLENMASK: prefix length (ptr: union nf_inet_addr) + * %XTTYPE_ETHERMAC: Ethernet MAC address in hex form + */ +enum xt_option_type { + XTTYPE_NONE, + XTTYPE_UINT8, + XTTYPE_UINT16, + XTTYPE_UINT32, + XTTYPE_UINT64, + XTTYPE_UINT8RC, + XTTYPE_UINT16RC, + XTTYPE_UINT32RC, + XTTYPE_UINT64RC, + XTTYPE_DOUBLE, + XTTYPE_STRING, + XTTYPE_TOSMASK, + XTTYPE_MARKMASK32, + XTTYPE_SYSLOGLEVEL, + XTTYPE_HOST, + XTTYPE_HOSTMASK, + XTTYPE_PROTOCOL, + XTTYPE_PORT, + XTTYPE_PORTRC, + XTTYPE_PLEN, + XTTYPE_PLENMASK, + XTTYPE_ETHERMAC, +}; + +/** + * %XTOPT_INVERT: option is invertible (usable with !) + * %XTOPT_MAND: option is mandatory + * %XTOPT_MULTI: option may be specified multiple times + * %XTOPT_PUT: store value into memory at @ptroff + * %XTOPT_NBO: store value in network-byte order + * (only certain XTTYPEs recognize this) + */ +enum xt_option_flags { + XTOPT_INVERT = 1 << 0, + XTOPT_MAND = 1 << 1, + XTOPT_MULTI = 1 << 2, + XTOPT_PUT = 1 << 3, + XTOPT_NBO = 1 << 4, +}; + +/** + * @name: name of option + * @type: type of input and validation method, see %XTTYPE_* + * @id: unique number (within extension) for option, 0-31 + * @excl: bitmask of flags that cannot be used with this option + * @also: bitmask of flags that must be used with this option + * @flags: bitmask of option flags, see %XTOPT_* + * @ptroff: offset into private structure for member + * @size: size of the item pointed to by @ptroff; this is a safeguard + * @min: lowest allowed value (for singular integral types) + * @max: highest allowed value (for singular integral types) + */ +struct xt_option_entry { + const char *name; + enum xt_option_type type; + unsigned int id, excl, also, flags; + unsigned int ptroff; + size_t size; + unsigned int min, max; +}; + +/** + * @arg: input from command line + * @ext_name: name of extension currently being processed + * @entry: current option being processed + * @data: per-extension kernel data block + * @xflags: options of the extension that have been used + * @invert: whether option was used with ! + * @nvals: number of results in uXX_multi + * @val: parsed result + * @udata: per-extension private scratch area + * (cf. xtables_{match,target}->udata_size) + */ +struct xt_option_call { + const char *arg, *ext_name; + const struct xt_option_entry *entry; + void *data; + unsigned int xflags; + bool invert; + uint8_t nvals; + union { + uint8_t u8, u8_range[2], syslog_level, protocol; + uint16_t u16, u16_range[2], port, port_range[2]; + uint32_t u32, u32_range[2]; + uint64_t u64, u64_range[2]; + double dbl; + struct { + union nf_inet_addr haddr, hmask; + uint8_t hlen; + }; + struct { + uint8_t tos_value, tos_mask; + }; + struct { + uint32_t mark, mask; + }; + uint8_t ethermac[6]; + } val; + /* Wished for a world where the ones below were gone: */ + union { + struct xt_entry_match **match; + struct xt_entry_target **target; + }; + void *xt_entry; + void *udata; +}; + +/** + * @ext_name: name of extension currently being processed + * @data: per-extension (kernel) data block + * @udata: per-extension private scratch area + * (cf. xtables_{match,target}->udata_size) + * @xflags: options of the extension that have been used + */ +struct xt_fcheck_call { + const char *ext_name; + void *data, *udata; + unsigned int xflags; +}; + +/** + * A "linear"/linked-list based name<->id map, for files similar to + * /etc/iproute2/. + */ +struct xtables_lmap { + char *name; + int id; + struct xtables_lmap *next; +}; + +enum xtables_ext_flags { + XTABLES_EXT_ALIAS = 1 << 0, +}; + +/* Include file for additions: new matches and targets. */ +struct xtables_match +{ + /* + * ABI/API version this module requires. Must be first member, + * as the rest of this struct may be subject to ABI changes. + */ + const char *version; + + struct xtables_match *next; + + const char *name; + const char *real_name; + + /* Revision of match (0 by default). */ + uint8_t revision; + + /* Extension flags */ + uint8_t ext_flags; + + uint16_t family; + + /* Size of match data. */ + size_t size; + + /* Size of match data relevant for userspace comparison purposes */ + size_t userspacesize; + + /* Function which prints out usage message. */ + void (*help)(void); + + /* Initialize the match. */ + void (*init)(struct xt_entry_match *m); + + /* Function which parses command options; returns true if it + ate an option */ + /* entry is struct ipt_entry for example */ + int (*parse)(int c, char **argv, int invert, unsigned int *flags, + const void *entry, + struct xt_entry_match **match); + + /* Final check; exit if not ok. */ + void (*final_check)(unsigned int flags); + + /* Prints out the match iff non-NULL: put space at end */ + /* ip is struct ipt_ip * for example */ + void (*print)(const void *ip, + const struct xt_entry_match *match, int numeric); + + /* Saves the match info in parsable form to stdout. */ + /* ip is struct ipt_ip * for example */ + void (*save)(const void *ip, const struct xt_entry_match *match); + + /* Print match name or alias */ + const char *(*alias)(const struct xt_entry_match *match); + + /* Pointer to list of extra command-line options */ + const struct option *extra_opts; + + /* New parser */ + void (*x6_parse)(struct xt_option_call *); + void (*x6_fcheck)(struct xt_fcheck_call *); + const struct xt_option_entry *x6_options; + + /* Size of per-extension instance extra "global" scratch space */ + size_t udata_size; + + /* Ignore these men behind the curtain: */ + void *udata; + unsigned int option_offset; + struct xt_entry_match *m; + unsigned int mflags; + unsigned int loaded; /* simulate loading so options are merged properly */ +}; + +struct xtables_target +{ + /* + * ABI/API version this module requires. Must be first member, + * as the rest of this struct may be subject to ABI changes. + */ + const char *version; + + struct xtables_target *next; + + + const char *name; + + /* Real target behind this, if any. */ + const char *real_name; + + /* Revision of target (0 by default). */ + uint8_t revision; + + /* Extension flags */ + uint8_t ext_flags; + + uint16_t family; + + + /* Size of target data. */ + size_t size; + + /* Size of target data relevant for userspace comparison purposes */ + size_t userspacesize; + + /* Function which prints out usage message. */ + void (*help)(void); + + /* Initialize the target. */ + void (*init)(struct xt_entry_target *t); + + /* Function which parses command options; returns true if it + ate an option */ + /* entry is struct ipt_entry for example */ + int (*parse)(int c, char **argv, int invert, unsigned int *flags, + const void *entry, + struct xt_entry_target **targetinfo); + + /* Final check; exit if not ok. */ + void (*final_check)(unsigned int flags); + + /* Prints out the target iff non-NULL: put space at end */ + void (*print)(const void *ip, + const struct xt_entry_target *target, int numeric); + + /* Saves the targinfo in parsable form to stdout. */ + void (*save)(const void *ip, + const struct xt_entry_target *target); + + /* Print target name or alias */ + const char *(*alias)(const struct xt_entry_target *target); + + /* Pointer to list of extra command-line options */ + const struct option *extra_opts; + + /* New parser */ + void (*x6_parse)(struct xt_option_call *); + void (*x6_fcheck)(struct xt_fcheck_call *); + const struct xt_option_entry *x6_options; + + size_t udata_size; + + /* Ignore these men behind the curtain: */ + void *udata; + unsigned int option_offset; + struct xt_entry_target *t; + unsigned int tflags; + unsigned int used; + unsigned int loaded; /* simulate loading so options are merged properly */ +}; + +struct xtables_rule_match { + struct xtables_rule_match *next; + struct xtables_match *match; + /* Multiple matches of the same type: the ones before + the current one are completed from parsing point of view */ + bool completed; +}; + +/** + * struct xtables_pprot - + * + * A few hardcoded protocols for 'all' and in case the user has no + * /etc/protocols. + */ +struct xtables_pprot { + const char *name; + uint8_t num; +}; + +enum xtables_tryload { + XTF_DONT_LOAD, + XTF_DURING_LOAD, + XTF_TRY_LOAD, + XTF_LOAD_MUST_SUCCEED, +}; + +enum xtables_exittype { + OTHER_PROBLEM = 1, + PARAMETER_PROBLEM, + VERSION_PROBLEM, + RESOURCE_PROBLEM, + XTF_ONLY_ONCE, + XTF_NO_INVERT, + XTF_BAD_VALUE, + XTF_ONE_ACTION, +}; + +struct xtables_globals +{ + unsigned int option_offset; + const char *program_name, *program_version; + struct option *orig_opts; + struct option *opts; + void (*exit_err)(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); + int (*compat_rev)(const char *name, uint8_t rev, int opt); +}; + +#define XT_GETOPT_TABLEEND {.name = NULL, .has_arg = false} + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char *xtables_modprobe_program; +extern struct xtables_match *xtables_matches; +extern struct xtables_target *xtables_targets; + +extern void xtables_init(void); +extern void xtables_set_nfproto(uint8_t); +extern void *xtables_calloc(size_t, size_t); +extern void *xtables_malloc(size_t); +extern void *xtables_realloc(void *, size_t); + +extern int xtables_insmod(const char *, const char *, bool); +extern int xtables_load_ko(const char *, bool); +extern int xtables_set_params(struct xtables_globals *xtp); +extern void xtables_free_opts(int reset_offset); +extern struct option *xtables_merge_options(struct option *origopts, + struct option *oldopts, const struct option *newopts, + unsigned int *option_offset); + +extern int xtables_init_all(struct xtables_globals *xtp, uint8_t nfproto); +extern struct xtables_match *xtables_find_match(const char *name, + enum xtables_tryload, struct xtables_rule_match **match); +extern struct xtables_target *xtables_find_target(const char *name, + enum xtables_tryload); +extern int xtables_compatible_revision(const char *name, uint8_t revision, + int opt); + +extern void xtables_rule_matches_free(struct xtables_rule_match **matches); + +/* Your shared library should call one of these. */ +extern void xtables_register_match(struct xtables_match *me); +extern void xtables_register_matches(struct xtables_match *, unsigned int); +extern void xtables_register_target(struct xtables_target *me); +extern void xtables_register_targets(struct xtables_target *, unsigned int); + +extern bool xtables_strtoul(const char *, char **, uintmax_t *, + uintmax_t, uintmax_t); +extern bool xtables_strtoui(const char *, char **, unsigned int *, + unsigned int, unsigned int); +extern int xtables_service_to_port(const char *name, const char *proto); +extern uint16_t xtables_parse_port(const char *port, const char *proto); +extern void +xtables_parse_interface(const char *arg, char *vianame, unsigned char *mask); + +/* this is a special 64bit data type that is 8-byte aligned */ +#define aligned_u64 uint64_t __attribute__((aligned(8))) + +extern struct xtables_globals *xt_params; +#define xtables_error (xt_params->exit_err) + +extern void xtables_param_act(unsigned int, const char *, ...); + +extern const char *xtables_ipaddr_to_numeric(const struct in_addr *); +extern const char *xtables_ipaddr_to_anyname(const struct in_addr *); +extern const char *xtables_ipmask_to_numeric(const struct in_addr *); +extern struct in_addr *xtables_numeric_to_ipaddr(const char *); +extern struct in_addr *xtables_numeric_to_ipmask(const char *); +extern int xtables_ipmask_to_cidr(const struct in_addr *); +extern void xtables_ipparse_any(const char *, struct in_addr **, + struct in_addr *, unsigned int *); +extern void xtables_ipparse_multiple(const char *, struct in_addr **, + struct in_addr **, unsigned int *); + +extern struct in6_addr *xtables_numeric_to_ip6addr(const char *); +extern const char *xtables_ip6addr_to_numeric(const struct in6_addr *); +extern const char *xtables_ip6addr_to_anyname(const struct in6_addr *); +extern const char *xtables_ip6mask_to_numeric(const struct in6_addr *); +extern int xtables_ip6mask_to_cidr(const struct in6_addr *); +extern void xtables_ip6parse_any(const char *, struct in6_addr **, + struct in6_addr *, unsigned int *); +extern void xtables_ip6parse_multiple(const char *, struct in6_addr **, + struct in6_addr **, unsigned int *); + +/** + * Print the specified value to standard output, quoting dangerous + * characters if required. + */ +extern void xtables_save_string(const char *value); + +#define FMT_NUMERIC 0x0001 +#define FMT_NOCOUNTS 0x0002 +#define FMT_KILOMEGAGIGA 0x0004 +#define FMT_OPTIONS 0x0008 +#define FMT_NOTABLE 0x0010 +#define FMT_NOTARGET 0x0020 +#define FMT_VIA 0x0040 +#define FMT_NONEWLINE 0x0080 +#define FMT_LINENUMBERS 0x0100 + +#define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \ + | FMT_NUMERIC | FMT_NOTABLE) +#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab)) + +extern void xtables_print_num(uint64_t number, unsigned int format); + +#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) +# ifdef _INIT +# undef _init +# define _init _INIT +# endif + extern void init_extensions(void); + extern void init_extensions4(void); + extern void init_extensions6(void); +#else +# define _init __attribute__((constructor)) _INIT +#endif + +extern const struct xtables_pprot xtables_chain_protos[]; +extern uint16_t xtables_parse_protocol(const char *s); + +/* kernel revision handling */ +extern int kernel_version; +extern void get_kernel_version(void); +#define LINUX_VERSION(x,y,z) (0x10000*(x) + 0x100*(y) + z) +#define LINUX_VERSION_MAJOR(x) (((x)>>16) & 0xFF) +#define LINUX_VERSION_MINOR(x) (((x)>> 8) & 0xFF) +#define LINUX_VERSION_PATCH(x) ( (x) & 0xFF) + +/* xtoptions.c */ +extern void xtables_option_metavalidate(const char *, + const struct xt_option_entry *); +extern struct option *xtables_options_xfrm(struct option *, struct option *, + const struct xt_option_entry *, + unsigned int *); +extern void xtables_option_parse(struct xt_option_call *); +extern void xtables_option_tpcall(unsigned int, char **, bool, + struct xtables_target *, void *); +extern void xtables_option_mpcall(unsigned int, char **, bool, + struct xtables_match *, void *); +extern void xtables_option_tfcall(struct xtables_target *); +extern void xtables_option_mfcall(struct xtables_match *); +extern void xtables_options_fcheck(const char *, unsigned int, + const struct xt_option_entry *); + +extern struct xtables_lmap *xtables_lmap_init(const char *); +extern void xtables_lmap_free(struct xtables_lmap *); +extern int xtables_lmap_name2id(const struct xtables_lmap *, const char *); +extern const char *xtables_lmap_id2name(const struct xtables_lmap *, int); + +#ifdef XTABLES_INTERNAL + +/* Shipped modules rely on this... */ + +# ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) +# endif + +extern void _init(void); + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _XTABLES_H */ From a4c89d808734fe980813587cc1b7899835376a62 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 6 Jan 2016 09:14:29 -0800 Subject: [PATCH 020/513] update most kernel headers still have issues with xtables --- include/linux/bpf.h | 1 + include/linux/if_link.h | 1 + include/linux/ila.h | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 2e2524d44..39e7f33c3 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -269,6 +269,7 @@ enum bpf_func_id { * Return: 0 on success */ BPF_FUNC_perf_event_output, + BPF_FUNC_skb_load_bytes, __BPF_FUNC_MAX_ID, }; diff --git a/include/linux/if_link.h b/include/linux/if_link.h index c9ad487d0..d91f2c97d 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -216,6 +216,7 @@ enum in6_addr_gen_mode { IN6_ADDR_GEN_MODE_EUI64, IN6_ADDR_GEN_MODE_NONE, IN6_ADDR_GEN_MODE_STABLE_PRIVACY, + IN6_ADDR_GEN_MODE_RANDOM, }; /* Bridge section */ diff --git a/include/linux/ila.h b/include/linux/ila.h index f08e8d77a..4f9e1deaf 100644 --- a/include/linux/ila.h +++ b/include/linux/ila.h @@ -3,13 +3,35 @@ #ifndef _LINUX_ILA_H #define _LINUX_ILA_H +/* NETLINK_GENERIC related info */ +#define ILA_GENL_NAME "ila" +#define ILA_GENL_VERSION 0x1 + enum { ILA_ATTR_UNSPEC, ILA_ATTR_LOCATOR, /* u64 */ + ILA_ATTR_IDENTIFIER, /* u64 */ + ILA_ATTR_LOCATOR_MATCH, /* u64 */ + ILA_ATTR_IFINDEX, /* s32 */ + ILA_ATTR_DIR, /* u32 */ __ILA_ATTR_MAX, }; #define ILA_ATTR_MAX (__ILA_ATTR_MAX - 1) +enum { + ILA_CMD_UNSPEC, + ILA_CMD_ADD, + ILA_CMD_DEL, + ILA_CMD_GET, + + __ILA_CMD_MAX, +}; + +#define ILA_CMD_MAX (__ILA_CMD_MAX - 1) + +#define ILA_DIR_IN (1 << 0) +#define ILA_DIR_OUT (1 << 1) + #endif /* _LINUX_ILA_H */ From 8e098dd81a1d915c641a094a0bc2bf1c52a8e14e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 4 Jan 2016 10:58:04 +0100 Subject: [PATCH 021/513] iplink: support setting addrgenmode stable_secret MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible to switch to another addrgenmode after setting a valid secret. Allow switching back without reconfiguring the secret for completeness. Cc: Hannes Frederic Sowa Signed-off-by: Bjørn Mork --- ip/iplink.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ip/iplink.c b/ip/iplink.c index f30de86d1..e824082f7 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -84,7 +84,7 @@ void iplink_usage(void) fprintf(stderr, " [ state { auto | enable | disable} ] ]\n"); fprintf(stderr, " [ master DEVICE ]\n"); fprintf(stderr, " [ nomaster ]\n"); - fprintf(stderr, " [ addrgenmode { eui64 | none } ]\n"); + fprintf(stderr, " [ addrgenmode { eui64 | none | stable_secret } ]\n"); fprintf(stderr, " [ protodown { on | off } ]\n"); fprintf(stderr, " ip link show [ DEVICE | group GROUP ] [up] [master DEV] [type TYPE]\n"); @@ -176,6 +176,8 @@ static int get_addr_gen_mode(const char *mode) return IN6_ADDR_GEN_MODE_EUI64; if (strcasecmp(mode, "none") == 0) return IN6_ADDR_GEN_MODE_NONE; + if (strcasecmp(mode, "stable_secret") == 0) + return IN6_ADDR_GEN_MODE_STABLE_PRIVACY; return -1; } From 8e12bc0a9df46516b851c9baa48d9da6b0999022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 4 Jan 2016 10:58:05 +0100 Subject: [PATCH 022/513] iplink: support show and set of "addrgenmode random" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "random" is a new IPv6 addrgenmode, enabling "stable_secret" type addresses with an auto-generated secret. $ ip link set eth0 addrgenmode random $ ip -d link show dev eth0 2: eth0: mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether 00:21:86:a3:25:7d brd ff:ff:ff:ff:ff:ff promiscuity 0 addrgenmode random Cc: Hannes Frederic Sowa Signed-off-by: Bjørn Mork --- ip/ipaddress.c | 3 +++ ip/iplink.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index a495a391a..9d254d27b 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -296,6 +296,9 @@ static void print_af_spec(FILE *fp, struct rtattr *af_spec_attr) case IN6_ADDR_GEN_MODE_STABLE_PRIVACY: fprintf(fp, "addrgenmode stable_secret "); break; + case IN6_ADDR_GEN_MODE_RANDOM: + fprintf(fp, "addrgenmode random "); + break; default: fprintf(fp, "addrgenmode %#.2hhx ", mode); break; diff --git a/ip/iplink.c b/ip/iplink.c index e824082f7..75b21540c 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -84,7 +84,7 @@ void iplink_usage(void) fprintf(stderr, " [ state { auto | enable | disable} ] ]\n"); fprintf(stderr, " [ master DEVICE ]\n"); fprintf(stderr, " [ nomaster ]\n"); - fprintf(stderr, " [ addrgenmode { eui64 | none | stable_secret } ]\n"); + fprintf(stderr, " [ addrgenmode { eui64 | none | stable_secret | random } ]\n"); fprintf(stderr, " [ protodown { on | off } ]\n"); fprintf(stderr, " ip link show [ DEVICE | group GROUP ] [up] [master DEV] [type TYPE]\n"); @@ -178,6 +178,8 @@ static int get_addr_gen_mode(const char *mode) return IN6_ADDR_GEN_MODE_NONE; if (strcasecmp(mode, "stable_secret") == 0) return IN6_ADDR_GEN_MODE_STABLE_PRIVACY; + if (strcasecmp(mode, "random") == 0) + return IN6_ADDR_GEN_MODE_RANDOM; return -1; } From 8f0777a857679678f3ff89e05dbde4594a58930c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 4 Jan 2016 10:58:06 +0100 Subject: [PATCH 023/513] man: iplink: document new addrgenmodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Hannes Frederic Sowa Signed-off-by: Bjørn Mork --- man/man8/ip-link.8.in | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index ac6f4813a..189a8f15f 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -150,7 +150,7 @@ ip-link \- network device configuration .br .B nomaster " |" .br -.B addrgenmode { eui64 | none } +.B addrgenmode { eui64 | none | stable_secret | random } .br .B link-netnsid ID .BR " }" @@ -1029,8 +1029,20 @@ set master device of the device (enslave device). unset master device of the device (release device). .TP -.BR "addrgenmode eui64 " or " addrgenmode none" -set IPv6 address generation mode +.BI addrgenmode " eui64|none|stable_secret|random" +set the IPv6 address generation mode + +.I eui64 +- use a Modified EUI-64 format interface identifier + +.I none +- disable automatic address generation + +.I stable_secret +- generate the interface identifier based on a preset /proc/sys/net/ipv6/conf/{default,DEVICE}/stable_secret + +.I random +- like stable_secret, but auto-generate a new random secret if none is set .TP .BR "link-netnsid " From f9dec657e4578d50a2432e5842d97c857faa6c2c Mon Sep 17 00:00:00 2001 From: Richard Alpe Date: Tue, 5 Jan 2016 10:57:40 +0100 Subject: [PATCH 024/513] tipc: add peer remove functionality This enables a user to remove an offline peer from the kernel data structures. This could for example be useful when deliberately scaling in peer nodes in a cloud environment. Signed-off-by: Richard Alpe Reviewed-by: Jon Maloy Reviewed-by: Ying Xue --- include/linux/tipc_netlink.h | 1 + man/man8/tipc-bearer.8 | 1 + man/man8/tipc-link.8 | 1 + man/man8/tipc-media.8 | 1 + man/man8/tipc-nametable.8 | 1 + man/man8/tipc-node.8 | 1 + man/man8/tipc-peer.8 | 52 ++++++++++++++++++++ man/man8/tipc.8 | 1 + tipc/Makefile | 2 +- tipc/peer.c | 93 ++++++++++++++++++++++++++++++++++++ tipc/peer.h | 21 ++++++++ tipc/tipc.c | 3 ++ 12 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 man/man8/tipc-peer.8 create mode 100644 tipc/peer.c create mode 100644 tipc/peer.h diff --git a/include/linux/tipc_netlink.h b/include/linux/tipc_netlink.h index d4c8f142b..25eb645e3 100644 --- a/include/linux/tipc_netlink.h +++ b/include/linux/tipc_netlink.h @@ -56,6 +56,7 @@ enum { TIPC_NL_NET_GET, TIPC_NL_NET_SET, TIPC_NL_NAME_TABLE_GET, + TIPC_NL_PEER_REMOVE, __TIPC_NL_CMD_MAX, TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 diff --git a/man/man8/tipc-bearer.8 b/man/man8/tipc-bearer.8 index 50a1ed245..565ee01d4 100644 --- a/man/man8/tipc-bearer.8 +++ b/man/man8/tipc-bearer.8 @@ -218,6 +218,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-media (8), .BR tipc-nametable (8), .BR tipc-node (8), +.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-link.8 b/man/man8/tipc-link.8 index 3be8c9ad4..2ee03a0bd 100644 --- a/man/man8/tipc-link.8 +++ b/man/man8/tipc-link.8 @@ -213,6 +213,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-bearer (8), .BR tipc-nametable (8), .BR tipc-node (8), +.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-media.8 b/man/man8/tipc-media.8 index 6c6e2b152..4689cb3fa 100644 --- a/man/man8/tipc-media.8 +++ b/man/man8/tipc-media.8 @@ -74,6 +74,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-link (8), .BR tipc-nametable (8), .BR tipc-node (8), +.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-nametable.8 b/man/man8/tipc-nametable.8 index d3397f97d..4bcefe47f 100644 --- a/man/man8/tipc-nametable.8 +++ b/man/man8/tipc-nametable.8 @@ -87,6 +87,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-link (8), .BR tipc-media (8), .BR tipc-node (8), +.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-node.8 b/man/man8/tipc-node.8 index ef32ec7c8..a72a40991 100644 --- a/man/man8/tipc-node.8 +++ b/man/man8/tipc-node.8 @@ -59,6 +59,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-link (8), .BR tipc-media (8), .BR tipc-nametable (8), +.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-peer.8 b/man/man8/tipc-peer.8 new file mode 100644 index 000000000..430651f7e --- /dev/null +++ b/man/man8/tipc-peer.8 @@ -0,0 +1,52 @@ +.TH TIPC-PEER 8 "04 Dec 2015" "iproute2" "Linux" + +.\" For consistency, please keep padding right aligned. +.\" For example '.B "foo " bar' and not '.B foo " bar"' + +.SH NAME +tipc-peer \- modify peer information + +.SH SYNOPSIS +.ad l +.in +8 + +.ti -8 +.B tipc peer remove address +.IR ADDRESS + +.SH OPTIONS +Options (flags) that can be passed anywhere in the command chain. +.TP +.BR "\-h" , " --help" +Show help about last valid command. For example +.B tipc peer --help +will show peer help and +.B tipc --help +will show general help. The position of the option in the string is irrelevant. +.SH DESCRIPTION + +.SS Peer remove +Remove an offline peer node from the local data structures. The peer is +identified by its +.B address + +.SH EXIT STATUS +Exit status is 0 if command was successful or a positive integer upon failure. + +.SH SEE ALSO +.BR tipc (8), +.BR tipc-bearer (8), +.BR tipc-link (8), +.BR tipc-media (8), +.BR tipc-nametable (8), +.BR tipc-node (8), +.BR tipc-socket (8) +.br +.SH REPORTING BUGS +Report any bugs to the Network Developers mailing list +.B +where the development and maintenance is primarily done. +You do not have to be subscribed to the list to send a message there. + +.SH AUTHOR +Richard Alpe diff --git a/man/man8/tipc.8 b/man/man8/tipc.8 index c11655238..32943fa50 100644 --- a/man/man8/tipc.8 +++ b/man/man8/tipc.8 @@ -87,6 +87,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-media (8), .BR tipc-nametable (8), .BR tipc-node (8), +.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/tipc/Makefile b/tipc/Makefile index bc5ecfd37..f06dcb119 100644 --- a/tipc/Makefile +++ b/tipc/Makefile @@ -6,7 +6,7 @@ TIPCOBJ=bearer.o \ media.o misc.o \ msg.o nametable.o \ node.o socket.o \ - tipc.o + peer.o tipc.o include ../Config diff --git a/tipc/peer.c b/tipc/peer.c new file mode 100644 index 000000000..de0c73c31 --- /dev/null +++ b/tipc/peer.c @@ -0,0 +1,93 @@ +/* + * peer.c TIPC peer functionality. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Richard Alpe + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "cmdl.h" +#include "msg.h" +#include "misc.h" +#include "peer.h" + +static int cmd_peer_rm_addr(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, void *data) +{ + char *str; + uint32_t addr; + struct nlattr *nest; + char buf[MNL_SOCKET_BUFFER_SIZE]; + + if ((cmdl->argc != cmdl->optind + 1) || help_flag) { + fprintf(stderr, "Usage: %s peer remove address ADDRESS\n", + cmdl->argv[0]); + return -EINVAL; + } + + str = shift_cmdl(cmdl); + addr = str2addr(str); + if (!addr) + return -1; + + if (!(nlh = msg_init(buf, TIPC_NL_PEER_REMOVE))) { + fprintf(stderr, "error, message initialisation failed\n"); + return -1; + } + + nest = mnl_attr_nest_start(nlh, TIPC_NLA_NET); + mnl_attr_put_u32(nlh, TIPC_NLA_NET_ADDR, addr); + mnl_attr_nest_end(nlh, nest); + + return msg_doit(nlh, NULL, NULL); +} + +static void cmd_peer_rm_help(struct cmdl *cmdl) +{ + fprintf(stderr, "Usage: %s peer remove address ADDRESS\n", + cmdl->argv[0]); +} + +static int cmd_peer_rm(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, void *data) +{ + const struct cmd cmds[] = { + { "address", cmd_peer_rm_addr, cmd_peer_rm_help }, + { NULL } + }; + + return run_cmd(nlh, cmd, cmds, cmdl, NULL); +} + +void cmd_peer_help(struct cmdl *cmdl) +{ + fprintf(stderr, + "Usage: %s peer COMMAND [ARGS] ...\n\n" + "COMMANDS\n" + " remove - Remove an offline peer node\n", + cmdl->argv[0]); +} + +int cmd_peer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, + void *data) +{ + const struct cmd cmds[] = { + { "remove", cmd_peer_rm, cmd_peer_rm_help }, + { NULL } + }; + + return run_cmd(nlh, cmd, cmds, cmdl, NULL); +} diff --git a/tipc/peer.h b/tipc/peer.h new file mode 100644 index 000000000..897226165 --- /dev/null +++ b/tipc/peer.h @@ -0,0 +1,21 @@ +/* + * peer.h TIPC peer functionality. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Richard Alpe + */ + +#ifndef _TIPC_PEER_H +#define _TIPC_PEER_H + +extern int help_flag; + +int cmd_peer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, + void *data); +void cmd_peer_help(struct cmdl *cmdl); + +#endif diff --git a/tipc/tipc.c b/tipc/tipc.c index 44398052a..600d5e2a1 100644 --- a/tipc/tipc.c +++ b/tipc/tipc.c @@ -20,6 +20,7 @@ #include "socket.h" #include "media.h" #include "node.h" +#include "peer.h" #include "cmdl.h" int help_flag; @@ -39,6 +40,7 @@ static void about(struct cmdl *cmdl) " media - Show or modify media\n" " nametable - Show nametable\n" " node - Show or modify node related parameters\n" + " peer - Peer related operations\n" " socket - Show sockets\n", cmdl->argv[0]); } @@ -59,6 +61,7 @@ int main(int argc, char *argv[]) { "media", cmd_media, cmd_media_help}, { "nametable", cmd_nametable, cmd_nametable_help}, { "node", cmd_node, cmd_node_help}, + { "peer", cmd_peer, cmd_peer_help}, { "socket", cmd_socket, cmd_socket_help}, { NULL } }; From bc223ab8617720902d75d855a702273dc6d232c8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 18 Jan 2016 09:37:38 -0800 Subject: [PATCH 025/513] Revert "tc: fix compilation with old gcc (< 4.6)" This reverts commit 8f80d450c3cb0996d839996807b77ca28bd4da09. --- tc/tc_bpf.c | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index 47993bad8..276871a5c 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -257,14 +257,12 @@ static bool bpf_may_skip_map_creation(int file_fd) static int bpf_create_map(enum bpf_map_type type, unsigned int size_key, unsigned int size_value, unsigned int max_elem) { - union bpf_attr attr; - - memset(&attr, 0, sizeof(attr)); - - attr.map_type = type; - attr.key_size = size_key; - attr.value_size = size_value; - attr.max_entries = max_elem; + union bpf_attr attr = { + .map_type = type, + .key_size = size_key, + .value_size = size_value, + .max_entries = max_elem, + }; return bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); } @@ -272,14 +270,12 @@ static int bpf_create_map(enum bpf_map_type type, unsigned int size_key, static int bpf_update_map(int fd, const void *key, const void *value, uint64_t flags) { - union bpf_attr attr; - - memset(&attr, 0, sizeof(attr)); - - attr.map_fd = fd; - attr.key = bpf_ptr_to_u64(key); - attr.value = bpf_ptr_to_u64(value); - attr.flags = flags; + union bpf_attr attr = { + .map_fd = fd, + .key = bpf_ptr_to_u64(key), + .value = bpf_ptr_to_u64(value), + .flags = flags, + }; return bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); } @@ -287,17 +283,15 @@ static int bpf_update_map(int fd, const void *key, const void *value, static int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, unsigned int len, const char *license) { - union bpf_attr attr; - - memset(&attr, 0, sizeof(attr)); - - attr.prog_type = type; - attr.insns = bpf_ptr_to_u64(insns); - attr.insn_cnt = len / sizeof(struct bpf_insn); - attr.license = bpf_ptr_to_u64(license); - attr.log_buf = bpf_ptr_to_u64(bpf_log_buf); - attr.log_size = sizeof(bpf_log_buf); - attr.log_level = 1; + union bpf_attr attr = { + .prog_type = type, + .insns = bpf_ptr_to_u64(insns), + .insn_cnt = len / sizeof(struct bpf_insn), + .license = bpf_ptr_to_u64(license), + .log_buf = bpf_ptr_to_u64(bpf_log_buf), + .log_size = sizeof(bpf_log_buf), + .log_level = 1, + }; return bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); } From 7321b7db6f0648d231cb7b05671682d89f07aff8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 18 Jan 2016 09:40:13 -0800 Subject: [PATCH 026/513] update headers (post 4.4 merge window) --- include/linux/bpf.h | 26 +++++++++++++++++++++++++- include/linux/pkt_sched.h | 4 ++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 39e7f33c3..f970f9db8 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -273,6 +273,25 @@ enum bpf_func_id { __BPF_FUNC_MAX_ID, }; +/* All flags used by eBPF helper functions, placed here. */ + +/* BPF_FUNC_skb_store_bytes flags. */ +#define BPF_F_RECOMPUTE_CSUM (1ULL << 0) + +/* BPF_FUNC_l3_csum_replace and BPF_FUNC_l4_csum_replace flags. + * First 4 bits are for passing the header field size. + */ +#define BPF_F_HDR_FIELD_MASK 0xfULL + +/* BPF_FUNC_l4_csum_replace flags. */ +#define BPF_F_PSEUDO_HDR (1ULL << 4) + +/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */ +#define BPF_F_INGRESS (1ULL << 0) + +/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */ +#define BPF_F_TUNINFO_IPV6 (1ULL << 0) + /* user accessible mirror of in-kernel sk_buff. * new fields can only be added to the end of this structure */ @@ -296,7 +315,12 @@ struct __sk_buff { struct bpf_tunnel_key { __u32 tunnel_id; - __u32 remote_ipv4; + union { + __u32 remote_ipv4; + __u32 remote_ipv6[4]; + }; + __u8 tunnel_tos; + __u8 tunnel_ttl; }; #endif /* __LINUX_BPF_H__ */ diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index 8d2530dac..8cb18b449 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -72,6 +72,10 @@ struct tc_estimator { #define TC_H_UNSPEC (0U) #define TC_H_ROOT (0xFFFFFFFFU) #define TC_H_INGRESS (0xFFFFFFF1U) +#define TC_H_CLSACT TC_H_INGRESS + +#define TC_H_MIN_INGRESS 0xFFF2U +#define TC_H_MIN_EGRESS 0xFFF3U /* Need to corrospond to iproute2 tc/tc_core.h "enum link_layer" */ enum tc_link_layer { From 0d45c4b420375a5c71d5af08ca4374c9f775372e Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 12 Jan 2016 01:42:19 +0100 Subject: [PATCH 027/513] tc, ingress: clean up ingress handling a bit Clean it up a bit, we can also get rid of some ugly ifdefs as in our case TC_H_INGRESS is always defined. Signed-off-by: Daniel Borkmann --- tc/q_ingress.c | 20 +++++--------------- tc/tc_qdisc.c | 11 +++-------- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/tc/q_ingress.c b/tc/q_ingress.c index 30b24e7de..c3c9b4031 100644 --- a/tc/q_ingress.c +++ b/tc/q_ingress.c @@ -1,5 +1,4 @@ /* - * * q_ingress.c INGRESS. * * This program is free software; you can redistribute it and/or @@ -8,20 +7,9 @@ * 2 of the License, or (at your option) any later version. * * Authors: J Hadi Salim - * - * This is here just in case it is needed - * useless right now; might be useful in the future - * */ #include -#include -#include -#include -#include -#include -#include -#include #include #include "utils.h" @@ -29,10 +17,11 @@ static void explain(void) { - fprintf(stderr, "Usage: ... ingress \n"); + fprintf(stderr, "Usage: ... ingress\n"); } -static int ingress_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) +static int ingress_parse_opt(struct qdisc_util *qu, int argc, char **argv, + struct nlmsghdr *n) { while (argc > 0) { if (strcmp(*argv, "handle") == 0) { @@ -49,7 +38,8 @@ static int ingress_parse_opt(struct qdisc_util *qu, int argc, char **argv, struc return 0; } -static int ingress_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) +static int ingress_print_opt(struct qdisc_util *qu, FILE *f, + struct rtattr *opt) { fprintf(f, "---------------- "); return 0; diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index c31ae8d29..96b808524 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -91,20 +91,17 @@ static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) return -1; } req.t.tcm_parent = TC_H_ROOT; -#ifdef TC_H_INGRESS } else if (strcmp(*argv, "ingress") == 0) { if (req.t.tcm_parent) { fprintf(stderr, "Error: \"ingress\" is a duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_INGRESS; - strncpy(k, "ingress", sizeof(k)-1); + strncpy(k, "ingress", sizeof(k) - 1); q = get_qdisc_kind(k); - req.t.tcm_handle = 0xffff0000; - - argc--; argv++; + req.t.tcm_handle = TC_H_MAKE(TC_H_INGRESS, 0); + NEXT_ARG_FWD(); break; -#endif } else if (strcmp(*argv, "parent") == 0) { __u32 handle; NEXT_ARG(); @@ -291,14 +288,12 @@ static int tc_qdisc_list(int argc, char **argv) if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); strncpy(d, *argv, sizeof(d)-1); -#ifdef TC_H_INGRESS } else if (strcmp(*argv, "ingress") == 0) { if (t.tcm_parent) { fprintf(stderr, "Duplicate parent ID\n"); usage(); } t.tcm_parent = TC_H_INGRESS; -#endif } else if (matches(*argv, "help") == 0) { usage(); } else { From 8f9afdd531560c1534be44424669add2e19deeec Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 12 Jan 2016 01:42:20 +0100 Subject: [PATCH 028/513] tc, clsact: add clsact frontend Add the tc part for the kernel commit 1f211a1b929c ("net, sched: add clsact qdisc"). Quoting example usage from that commit description: Example, adding qdisc: # tc qdisc add dev foo clsact # tc qdisc show dev foo qdisc mq 0: root qdisc pfifo_fast 0: parent :1 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 qdisc pfifo_fast 0: parent :2 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 qdisc pfifo_fast 0: parent :3 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 qdisc pfifo_fast 0: parent :4 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 qdisc clsact ffff: parent ffff:fff1 Adding filters (deleting, etc works analogous by specifying ingress/egress): # tc filter add dev foo ingress bpf da obj bar.o sec ingress # tc filter add dev foo egress bpf da obj bar.o sec egress # tc filter show dev foo ingress filter protocol all pref 49152 bpf filter protocol all pref 49152 bpf handle 0x1 bar.o:[ingress] direct-action # tc filter show dev foo egress filter protocol all pref 49152 bpf filter protocol all pref 49152 bpf handle 0x1 bar.o:[egress] direct-action The ingress parent alias can also be used with ingress qdisc. Signed-off-by: Daniel Borkmann --- tc/Makefile | 1 + tc/q_clsact.c | 34 ++++++++++++++++++++++++++++++++++ tc/tc_filter.c | 46 ++++++++++++++++++++++++++++++++++++++-------- tc/tc_qdisc.c | 21 +++++++++++++++------ 4 files changed, 88 insertions(+), 14 deletions(-) create mode 100644 tc/q_clsact.c diff --git a/tc/Makefile b/tc/Makefile index 56acbaa1a..f5bea877d 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -64,6 +64,7 @@ TCMODULES += q_fq_codel.o TCMODULES += q_fq.o TCMODULES += q_pie.o TCMODULES += q_hhf.o +TCMODULES += q_clsact.o TCMODULES += e_bpf.o ifeq ($(TC_CONFIG_IPSET), y) diff --git a/tc/q_clsact.c b/tc/q_clsact.c new file mode 100644 index 000000000..0c05dbd33 --- /dev/null +++ b/tc/q_clsact.c @@ -0,0 +1,34 @@ +#include +#include + +#include "utils.h" +#include "tc_util.h" + +static void explain(void) +{ + fprintf(stderr, "Usage: ... clsact\n"); +} + +static int clsact_parse_opt(struct qdisc_util *qu, int argc, char **argv, + struct nlmsghdr *n) +{ + if (argc > 0) { + fprintf(stderr, "What is \"%s\"?\n", *argv); + explain(); + return -1; + } + + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); + return 0; +} + +static int clsact_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) +{ + return 0; +} + +struct qdisc_util clsact_qdisc_util = { + .id = "clsact", + .parse_qopt = clsact_parse_opt, + .print_qopt = clsact_print_opt, +}; diff --git a/tc/tc_filter.c b/tc/tc_filter.c index ff03db8fd..1a1082b44 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -26,25 +26,21 @@ #include "tc_util.h" #include "tc_common.h" -static void usage(void); - static void usage(void) { fprintf(stderr, "Usage: tc filter [ add | del | change | replace | show ] dev STRING\n"); fprintf(stderr, " [ pref PRIO ] protocol PROTO\n"); fprintf(stderr, " [ estimator INTERVAL TIME_CONSTANT ]\n"); - fprintf(stderr, " [ root | classid CLASSID ] [ handle FILTERID ]\n"); - fprintf(stderr, " [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n"); + fprintf(stderr, " [ root | ingress | egress | parent CLASSID ]\n"); + fprintf(stderr, " [ handle FILTERID ] [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n"); fprintf(stderr, "\n"); - fprintf(stderr, " tc filter show [ dev STRING ] [ root | parent CLASSID ]\n"); + fprintf(stderr, " tc filter show [ dev STRING ] [ root | ingress | egress | parent CLASSID ]\n"); fprintf(stderr, "Where:\n"); fprintf(stderr, "FILTER_TYPE := { rsvp | u32 | bpf | fw | route | etc. }\n"); fprintf(stderr, "FILTERID := ... format depends on classifier, see there\n"); fprintf(stderr, "OPTIONS := ... try tc filter add help\n"); - return; } - static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) { struct { @@ -87,6 +83,20 @@ static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) return -1; } req.t.tcm_parent = TC_H_ROOT; + } else if (strcmp(*argv, "ingress") == 0) { + if (req.t.tcm_parent) { + fprintf(stderr, "Error: \"ingress\" is duplicate parent ID\n"); + return -1; + } + req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT, + TC_H_MIN_INGRESS); + } else if (strcmp(*argv, "egress") == 0) { + if (req.t.tcm_parent) { + fprintf(stderr, "Error: \"egress\" is duplicate parent ID\n"); + return -1; + } + req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT, + TC_H_MIN_EGRESS); } else if (strcmp(*argv, "parent") == 0) { __u32 handle; NEXT_ARG(); @@ -220,11 +230,16 @@ int print_filter(const struct sockaddr_nl *who, if (!filter_parent || filter_parent != t->tcm_parent) { if (t->tcm_parent == TC_H_ROOT) fprintf(fp, "root "); + else if (t->tcm_parent == TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS)) + fprintf(fp, "ingress "); + else if (t->tcm_parent == TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS)) + fprintf(fp, "egress "); else { print_tc_classid(abuf, sizeof(abuf), t->tcm_parent); fprintf(fp, "parent %s ", abuf); } } + if (t->tcm_info) { f_proto = TC_H_MIN(t->tcm_info); __u32 prio = TC_H_MAJ(t->tcm_info)>>16; @@ -259,7 +274,6 @@ int print_filter(const struct sockaddr_nl *who, return 0; } - static int tc_filter_list(int argc, char **argv) { struct tcmsg t; @@ -284,6 +298,22 @@ static int tc_filter_list(int argc, char **argv) return -1; } filter_parent = t.tcm_parent = TC_H_ROOT; + } else if (strcmp(*argv, "ingress") == 0) { + if (t.tcm_parent) { + fprintf(stderr, "Error: \"ingress\" is duplicate parent ID\n"); + return -1; + } + filter_parent = TC_H_MAKE(TC_H_CLSACT, + TC_H_MIN_INGRESS); + t.tcm_parent = filter_parent; + } else if (strcmp(*argv, "egress") == 0) { + if (t.tcm_parent) { + fprintf(stderr, "Error: \"egress\" is duplicate parent ID\n"); + return -1; + } + filter_parent = TC_H_MAKE(TC_H_CLSACT, + TC_H_MIN_EGRESS); + t.tcm_parent = filter_parent; } else if (strcmp(*argv, "parent") == 0) { __u32 handle; NEXT_ARG(); diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index 96b808524..cb861e085 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -26,17 +26,15 @@ #include "tc_util.h" #include "tc_common.h" -static int usage(void); - static int usage(void) { fprintf(stderr, "Usage: tc qdisc [ add | del | replace | change | show ] dev STRING\n"); - fprintf(stderr, " [ handle QHANDLE ] [ root | ingress | parent CLASSID ]\n"); + fprintf(stderr, " [ handle QHANDLE ] [ root | ingress | clsact | parent CLASSID ]\n"); fprintf(stderr, " [ estimator INTERVAL TIME_CONSTANT ]\n"); fprintf(stderr, " [ stab [ help | STAB_OPTIONS] ]\n"); fprintf(stderr, " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n"); fprintf(stderr, "\n"); - fprintf(stderr, " tc qdisc show [ dev STRING ] [ingress]\n"); + fprintf(stderr, " tc qdisc show [ dev STRING ] [ ingress | clsact ]\n"); fprintf(stderr, "Where:\n"); fprintf(stderr, "QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\n"); fprintf(stderr, "OPTIONS := ... try tc qdisc add help\n"); @@ -91,6 +89,17 @@ static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) return -1; } req.t.tcm_parent = TC_H_ROOT; + } else if (strcmp(*argv, "clsact") == 0) { + if (req.t.tcm_parent) { + fprintf(stderr, "Error: \"clsact\" is a duplicate parent ID\n"); + return -1; + } + req.t.tcm_parent = TC_H_CLSACT; + strncpy(k, "clsact", sizeof(k) - 1); + q = get_qdisc_kind(k); + req.t.tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0); + NEXT_ARG_FWD(); + break; } else if (strcmp(*argv, "ingress") == 0) { if (req.t.tcm_parent) { fprintf(stderr, "Error: \"ingress\" is a duplicate parent ID\n"); @@ -274,7 +283,6 @@ int print_qdisc(const struct sockaddr_nl *who, return 0; } - static int tc_qdisc_list(int argc, char **argv) { struct tcmsg t; @@ -288,7 +296,8 @@ static int tc_qdisc_list(int argc, char **argv) if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); strncpy(d, *argv, sizeof(d)-1); - } else if (strcmp(*argv, "ingress") == 0) { + } else if (strcmp(*argv, "ingress") == 0 || + strcmp(*argv, "clsact") == 0) { if (t.tcm_parent) { fprintf(stderr, "Duplicate parent ID\n"); usage(); From cce3d4664c6bc839116e504183f9caebe6994120 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 12 Jan 2016 02:03:07 +0100 Subject: [PATCH 029/513] tc, bpf: check section names and type everywhere When extracting sections, we better check for name and type. Noticed that some llvm versions emit .strtab and .shstrtab (e.g. saw it on pre 3.7), while more recent ones only seem to emit .strtab. Thus, make sure we get the right sections. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov --- tc/tc_bpf.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index f9b2b007f..677dd628b 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -1237,14 +1237,17 @@ static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx) if (ret < 0) continue; - if (!strcmp(data.sec_name, ELF_SECTION_MAPS)) + if (data.sec_hdr.sh_type == SHT_PROGBITS && + !strcmp(data.sec_name, ELF_SECTION_MAPS)) ret = bpf_fetch_maps(ctx, i, &data); - else if (!strcmp(data.sec_name, ELF_SECTION_LICENSE)) + else if (data.sec_hdr.sh_type == SHT_PROGBITS && + !strcmp(data.sec_name, ELF_SECTION_LICENSE)) ret = bpf_fetch_license(ctx, i, &data); - else if (data.sec_hdr.sh_type == SHT_SYMTAB) + else if (data.sec_hdr.sh_type == SHT_SYMTAB && + !strcmp(data.sec_name, ".symtab")) ret = bpf_fetch_symtab(ctx, i, &data); else if (data.sec_hdr.sh_type == SHT_STRTAB && - i != ctx->elf_hdr.e_shstrndx) + !strcmp(data.sec_name, ".strtab")) ret = bpf_fetch_strtab(ctx, i, &data); if (ret < 0) { fprintf(stderr, "Error parsing section %d! Perhaps" @@ -1275,7 +1278,10 @@ static int bpf_fetch_prog(struct bpf_elf_ctx *ctx, const char *section) continue; ret = bpf_fill_section_data(ctx, i, &data); - if (ret < 0 || strcmp(data.sec_name, section)) + if (ret < 0 || + !(data.sec_hdr.sh_type == SHT_PROGBITS && + data.sec_hdr.sh_flags & SHF_EXECINSTR && + !strcmp(data.sec_name, section))) continue; memset(&prog, 0, sizeof(prog)); @@ -1353,7 +1359,10 @@ static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section) idx = data_relo.sec_hdr.sh_info; ret = bpf_fill_section_data(ctx, idx, &data_insn); - if (ret < 0 || strcmp(data_insn.sec_name, section)) + if (ret < 0 || + !(data_insn.sec_hdr.sh_type == SHT_PROGBITS && + data_insn.sec_hdr.sh_flags & SHF_EXECINSTR && + !strcmp(data_insn.sec_name, section))) continue; ret = bpf_apply_relo_data(ctx, &data_relo, &data_insn); From 8187b012731cf2699c0abd5c88673bdaebca53b2 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 12 Jan 2016 02:03:08 +0100 Subject: [PATCH 030/513] tc, bpf: more header checks on loading elf eBPF llvm backend can support different BPF formats, make sure the object we're trying to load matches with regards to endiannes and while at it, also check for other attributes related to BPF ELFs. # llc --version LLVM (http://llvm.org/): LLVM version 3.8.0svn Optimized build. Built Jan 9 2016 (02:08:10). Default target: x86_64-unknown-linux-gnu Host CPU: ivybridge Registered Targets: bpf - BPF (host endian) bpfeb - BPF (big endian) bpfel - BPF (little endian) [...] Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov --- tc/tc_bpf.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index 677dd628b..42c884186 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -39,6 +39,8 @@ #include #include +#include + #include "utils.h" #include "bpf_elf.h" @@ -1564,6 +1566,38 @@ static void bpf_hash_destroy(struct bpf_elf_ctx *ctx) } } +static int bpf_elf_check_ehdr(const struct bpf_elf_ctx *ctx) +{ + if (ctx->elf_hdr.e_type != ET_REL || + ctx->elf_hdr.e_machine != 0 || + ctx->elf_hdr.e_version != EV_CURRENT) { + fprintf(stderr, "ELF format error, ELF file not for eBPF?\n"); + return -EINVAL; + } + + switch (ctx->elf_hdr.e_ident[EI_DATA]) { + default: + fprintf(stderr, "ELF format error, wrong endianness info?\n"); + return -EINVAL; + case ELFDATA2LSB: + if (htons(1) == 1) { + fprintf(stderr, + "We are big endian, eBPF object is little endian!\n"); + return -EIO; + } + break; + case ELFDATA2MSB: + if (htons(1) != 1) { + fprintf(stderr, + "We are little endian, eBPF object is big endian!\n"); + return -EIO; + } + break; + } + + return 0; +} + static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, enum bpf_prog_type type, bool verbose) { @@ -1587,12 +1621,21 @@ static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, goto out_fd; } + if (elf_kind(ctx->elf_fd) != ELF_K_ELF) { + ret = -EINVAL; + goto out_fd; + } + if (gelf_getehdr(ctx->elf_fd, &ctx->elf_hdr) != &ctx->elf_hdr) { ret = -EIO; goto out_elf; } + ret = bpf_elf_check_ehdr(ctx); + if (ret < 0) + goto out_elf; + ctx->sec_done = calloc(ctx->elf_hdr.e_shnum, sizeof(*(ctx->sec_done))); if (!ctx->sec_done) { From 5cd64c979f97ac1590e7bf28ae9b1adbd7673d3a Mon Sep 17 00:00:00 2001 From: Thomas Faivre Date: Thu, 14 Jan 2016 18:10:19 +0100 Subject: [PATCH 031/513] vxlan: fix help and man text Options 'group' and 'remote' cannot take 'any' as value but 'local' can. Signed-off-by: Thomas Faivre Signed-off-by: Nicolas Dichtel --- ip/iplink_vxlan.c | 2 +- man/man8/ip-link.8.in | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index aa4d5198d..ede848243 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -23,7 +23,7 @@ static void print_explain(FILE *f) { - fprintf(f, "Usage: ... vxlan id VNI [ { group | remote } ADDR ] [ local ADDR ]\n"); + fprintf(f, "Usage: ... vxlan id VNI [ { group | remote } IP_ADDRESS ] [ local ADDR ]\n"); fprintf(f, " [ ttl TTL ] [ tos TOS ] [ dev PHYS_DEV ]\n"); fprintf(f, " [ dstport PORT ] [ srcport MIN MAX ]\n"); fprintf(f, " [ [no]learning ] [ [no]proxy ] [ [no]rsc ]\n"); diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 189a8f15f..364049643 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -391,7 +391,8 @@ the following additional arguments are supported: .RB " ] [ { " group " | " remote " } " .I IPADDR .R " ] [ " -.BI local " IPADDR " +.B local +.RI "{ "IPADDR " | "any " } " .R " ] [ " .BI ttl " TTL " .R " ] [ " From 1ab0f02f465b7bcc09798645d19236a500742e90 Mon Sep 17 00:00:00 2001 From: Thomas Faivre Date: Thu, 14 Jan 2016 18:10:20 +0100 Subject: [PATCH 032/513] ip-link: fix man page warnings grff wrapper returns warnings when parsing the ip-link.8.in file. How to reproduce: $ man --warnings ip-link > /dev/null `R' is a string (producing the registered sign), not a macro. [...] Signed-off-by: Thomas Faivre Signed-off-by: Nicolas Dichtel --- man/man8/ip-link.8.in | 102 +++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 364049643..4d3234352 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -284,28 +284,28 @@ the following additional arguments are supported: .BI link " DEVICE " .BI name " NAME " .BI type " vlan " -.R " [ " +[ .BI protocol " VLAN_PROTO " -.R " ] " +] .BI id " VLANID " -.R " [ " +[ .BR reorder_hdr " { " on " | " off " } " -.R " ] " -.R " [ " +] +[ .BR gvrp " { " on " | " off " } " -.R " ] " -.R " [ " +] +[ .BR mvrp " { " on " | " off " } " -.R " ] " -.R " [ " +] +[ .BR loose_binding " { " on " | " off " } " -.R " ] " -.R " [ " +] +[ .BI ingress-qos-map " QOS-MAP " -.R " ] " -.R " [ " +] +[ .BI egress-qos-map " QOS-MAP " -.R " ] " +] .in +8 .sp @@ -386,44 +386,44 @@ the following additional arguments are supported: .BI "ip link add " DEVICE .BI type " vxlan " id " ID" -.R " [ " +[ .BI dev " PHYS_DEV " .RB " ] [ { " group " | " remote " } " .I IPADDR -.R " ] [ " +] [ .B local .RI "{ "IPADDR " | "any " } " -.R " ] [ " +] [ .BI ttl " TTL " -.R " ] [ " +] [ .BI tos " TOS " -.R " ] [ " +] [ .BI dstport " PORT " -.R " ] [ " +] [ .BI srcport " MIN MAX " -.R " ] [ " +] [ .I "[no]learning " -.R " ] [ " +] [ .I "[no]proxy " -.R " ] [ " +] [ .I "[no]rsc " -.R " ] [ " +] [ .I "[no]l2miss " -.R " ] [ " +] [ .I "[no]l3miss " -.R " ] [ " +] [ .I "[no]udpcsum " -.R " ] [ " +] [ .I "[no]udp6zerocsumtx " -.R " ] [ " +] [ .I "[no]udp6zerocsumrx " -.R " ] [ " +] [ .BI ageing " SECONDS " -.R " ] [ " +] [ .BI maxaddress " NUMBER " -.R " ] [ " +] [ .B gbp -.R " ]" +] .in +8 .sp @@ -565,17 +565,17 @@ the following additional arguments are supported: .BI "ip link add " DEVICE .BR type " { gre | ipip | sit } " .BI " remote " ADDR " local " ADDR -.R " [ " +[ .BR encap " { fou | gue | none } " -.R " ] [ " +] [ .BI "encap-sport { " PORT " | auto } " -.R " ] [ " +] [ .BI "encap-dport " PORT -.R " ] [ " +] [ .I " [no]encap-csum " -.R " ] [ " +] [ .I " [no]encap-remcsum " -.R " ]" +] .in +8 .sp @@ -621,25 +621,25 @@ the following additional arguments are supported: .BI "ip link add " DEVICE .BI type " { ip6gre | ip6gretap } " remote " ADDR " local " ADDR -.R " [ " +[ .I "[i|o]seq]" -.R " ] [ " +] [ .I "[i|o]key" KEY -.R " ] [ " +] [ .I " [i|o]csum " -.R " ] [ " +] [ .BI hoplimit " TTL " -.R " ] [ " +] [ .BI encaplimit " ELIM " -.R " ] [ " +] [ .BI tclass " TCLASS " -.R " ] [ " +] [ .BI flowlabel " FLOWLABEL " -.R " ] [ " +] [ .BI "dscp inherit" -.R " ] [ " +] [ .BI dev " PHYS_DEV " -.R " ]" +] .in +8 .sp @@ -744,11 +744,11 @@ the following additional arguments are supported: .BI "ip link add " DEVICE .BI type " geneve " id " ID " remote " IPADDR" -.R " [ " +[ .BI ttl " TTL " -.R " ] [ " +] [ .BI tos " TOS " -.R " ]" +] .in +8 .sp From 57fdf2d4d94aeee493214d455b8f3336f09afa09 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 8 Jan 2016 17:32:36 +0900 Subject: [PATCH 033/513] libnetlink: don't print NETLINK_SOCK_DIAG errors in rtnl_talk This change is a no-op, as currently no code uses rtnl_talk on NETLINK_SOCK_DIAG_BY_FAMILY sockets. It is needed to suppress spurious errors when using SOCK_DESTROY via rtnl_talk. Signed-off-by: Lorenzo Colitti --- lib/libnetlink.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 165821447..d6b5fd3e8 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -419,8 +419,10 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, return 0; } - fprintf(stderr, "RTNETLINK answers: %s\n", - strerror(-err->error)); + if (rtnl->proto != NETLINK_SOCK_DIAG) + fprintf(stderr, + "RTNETLINK answers: %s\n", + strerror(-err->error)); errno = -err->error; return -1; } From fb2594c183fbedbe8f91fe7b1f7fed1331bb3194 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 8 Jan 2016 17:32:37 +0900 Subject: [PATCH 034/513] ss: support closing inet sockets via SOCK_DESTROY. This patch adds a -K / --kill option to ss that attempts to forcibly close matching sockets using SOCK_DESTROY. Because ss typically prints sockets instead of acting on them, and because the kernel only supports forcibly closing some types of sockets, the output of -K is as follows: - If closing the socket succeeds, the socket is printed. - If the kernel does not support forcibly closing this type of socket (e.g., if it's a UDP socket, or a TIME_WAIT socket), the socket is silently skipped. - If an error occurs (e.g., permission denied), the error is reported and ss exits. Signed-off-by: Lorenzo Colitti --- man/man8/ss.8 | 5 +++++ misc/ss.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/man/man8/ss.8 b/man/man8/ss.8 index f4d5264f3..758460c27 100644 --- a/man/man8/ss.8 +++ b/man/man8/ss.8 @@ -48,6 +48,11 @@ Show process using socket. .B \-i, \-\-info Show internal TCP information. .TP +.B \-K, \-\-kill +Attempts to forcibly close sockets. This option displays sockets that are +successfully closed and silently skips sockets that the kernel does not support +closing. It supports IPv4 and IPv6 sockets only. +.TP .B \-s, \-\-summary Print summary statistics. This option does not parse socket lists obtaining summary from various sources. It is useful when amount of sockets is so huge diff --git a/misc/ss.c b/misc/ss.c index 0dab32cef..13fcc8f66 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -160,6 +160,7 @@ struct filter int states; int families; struct ssfilter *f; + bool kill; }; static const struct filter default_dbs[MAX_DB] = { @@ -2194,8 +2195,27 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f) struct inet_diag_arg { struct filter *f; int protocol; + struct rtnl_handle *rth; }; +static int kill_inet_sock(const struct sockaddr_nl *addr, + struct nlmsghdr *h, void *arg) +{ + struct inet_diag_msg *d = NLMSG_DATA(h); + struct inet_diag_arg *diag_arg = arg; + struct rtnl_handle *rth = diag_arg->rth; + DIAG_REQUEST(req, struct inet_diag_req_v2 r); + + req.nlh.nlmsg_type = SOCK_DESTROY; + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + req.nlh.nlmsg_seq = ++rth->seq; + req.r.sdiag_family = d->idiag_family; + req.r.sdiag_protocol = diag_arg->protocol; + req.r.id = d->id; + + return rtnl_talk(rth, &req.nlh, NULL, 0); +} + static int show_one_inet_sock(const struct sockaddr_nl *addr, struct nlmsghdr *h, void *arg) { @@ -2205,6 +2225,15 @@ static int show_one_inet_sock(const struct sockaddr_nl *addr, if (!(diag_arg->f->families & (1 << r->idiag_family))) return 0; + if (diag_arg->f->kill && kill_inet_sock(addr, h, arg) != 0) { + if (errno == EOPNOTSUPP || errno == ENOENT) { + /* Socket can't be closed, or is already closed. */ + return 0; + } else { + perror("SOCK_DESTROY answers"); + return -1; + } + } if ((err = inet_show_sock(h, diag_arg->f, diag_arg->protocol)) < 0) return err; @@ -2214,12 +2243,21 @@ static int show_one_inet_sock(const struct sockaddr_nl *addr, static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol) { int err = 0; - struct rtnl_handle rth; + struct rtnl_handle rth, rth2; int family = PF_INET; struct inet_diag_arg arg = { .f = f, .protocol = protocol }; if (rtnl_open_byproto(&rth, 0, NETLINK_SOCK_DIAG)) return -1; + + if (f->kill) { + if (rtnl_open_byproto(&rth2, 0, NETLINK_SOCK_DIAG)) { + rtnl_close(&rth); + return -1; + } + arg.rth = &rth2; + } + rth.dump = MAGIC_SEQ; rth.dump_fp = dump_fp; if (preferred_family == PF_INET6) @@ -2243,6 +2281,8 @@ static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol) Exit: rtnl_close(&rth); + if (arg.rth) + rtnl_close(arg.rth); return err; } @@ -3489,6 +3529,8 @@ static void _usage(FILE *dest) " -x, --unix display only Unix domain sockets\n" " -f, --family=FAMILY display sockets of type FAMILY\n" "\n" +" -K, --kill forcibly close sockets, display what was closed\n" +"\n" " -A, --query=QUERY, --socket=QUERY\n" " QUERY := {all|inet|tcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink}[,QUERY]\n" "\n" @@ -3579,6 +3621,7 @@ static const struct option long_opts[] = { { "context", 0, 0, 'Z' }, { "contexts", 0, 0, 'z' }, { "net", 1, 0, 'N' }, + { "kill", 0, 0, 'K' }, { 0 } }; @@ -3593,7 +3636,7 @@ int main(int argc, char *argv[]) int ch; int state_filter = 0; - while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:", + while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:K", long_opts, NULL)) != EOF) { switch(ch) { case 'n': @@ -3774,6 +3817,9 @@ int main(int argc, char *argv[]) if (netns_switch(optarg)) exit(1); break; + case 'K': + current_filter.kill = 1; + break; case 'h': help(); case '?': From eb85526923d1de1857c2b1e6860a471f2a0ae1b9 Mon Sep 17 00:00:00 2001 From: Zhang Shengju Date: Thu, 21 Jan 2016 02:23:49 +0000 Subject: [PATCH 035/513] ip-link: remove warning message the warning was: iproute.c:301:12: warning: 'val' may be used uninitialized in this function [-Wmaybe-uninitialized] features &= ~RTAX_FEATURE_ECN; ^ iproute.c:575:10: note: 'val' was declared here __u32 val; ^ Signed-off-by: Zhang Shengju --- ip/iproute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/iproute.c b/ip/iproute.c index d5e3ebe26..afe70e123 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -572,7 +572,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) mxlock = *(unsigned*)RTA_DATA(mxrta[RTAX_LOCK]); for (i=2; i<= RTAX_MAX; i++) { - __u32 val; + __u32 val = 0U; if (mxrta[i] == NULL) continue; From 4a36b4c2ecafa9ec377fd1ed2a47b74df1c27900 Mon Sep 17 00:00:00 2001 From: Gustavo Zacarias Date: Thu, 21 Jan 2016 15:19:48 -0300 Subject: [PATCH 036/513] iproute2: fix building with musl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need limits.h for PATH_MAX, fixes: rt_names.c:364:13: error: ‘PATH_MAX’ undeclared (first use in this function) Signed-off-by: Gustavo Zacarias --- lib/rt_names.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/rt_names.c b/lib/rt_names.c index f6d17c0e5..b665d3e92 100644 --- a/lib/rt_names.c +++ b/lib/rt_names.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include From 2486337aace9df195eb3d01fb08b665958ce311d Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 22 Jan 2016 00:46:28 +0100 Subject: [PATCH 037/513] tc, bpf: make sure relo is in relation with map section Add a test that symbol from relocation entry is actually related to map section and bail out with an error message if it's not the case; in relation to [1]. [1] https://llvm.org/bugs/show_bug.cgi?id=26243 Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov --- tc/tc_bpf.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index 42c884186..955bd5fbf 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -1328,6 +1328,12 @@ static int bpf_apply_relo_data(struct bpf_elf_ctx *ctx, if (gelf_getsym(ctx->sym_tab, GELF_R_SYM(relo.r_info), &sym) != &sym) return -EIO; + if (sym.st_shndx != ctx->sec_maps) { + fprintf(stderr, "ELF contains non-map related relo data in " + "entry %u pointing to section %u! Compiler bug?!\n", + relo_ent, sym.st_shndx); + return -EIO; + } rmap = sym.st_value / sizeof(struct bpf_elf_map); if (rmap >= ARRAY_SIZE(ctx->map_fds)) From a9390c921acc1b6dfb8c7b8087041c65b54facce Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 2 Feb 2016 16:53:40 -0800 Subject: [PATCH 038/513] ipmonitor: match user option 'all' before 'all-nsid' 'ip monitor all' is broken on older kernels. This patch fixes 'ip monitor all' to match 'all' and not 'all-nsid'. It moves parsing arg 'all-nsid' to after parsing 'all'. Before: $ip monitor all NETLINK_LISTEN_ALL_NSID: Protocol not available After: $ip monitor all [NEIGH]Deleted 10.0.0.1 dev eth1 lladdr c4:54:44:4f:b2:dd STALE Fixes: 449b824ad196 ("ipmonitor: allows to monitor in several netns") Signed-off-by: Roopa Prabhu Acked-by: Nicolas Dichtel --- ip/ipmonitor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c index 99a237f47..7aeccd21d 100644 --- a/ip/ipmonitor.c +++ b/ip/ipmonitor.c @@ -186,8 +186,6 @@ int do_ipmonitor(int argc, char **argv) file = *argv; } else if (matches(*argv, "label") == 0) { prefix_banner = 1; - } else if (matches(*argv, "all-nsid") == 0) { - listen_all_nsid = 1; } else if (matches(*argv, "link") == 0) { llink=1; groups = 0; @@ -217,6 +215,8 @@ int do_ipmonitor(int argc, char **argv) groups = 0; } else if (strcmp(*argv, "all") == 0) { prefix_banner=1; + } else if (matches(*argv, "all-nsid") == 0) { + listen_all_nsid = 1; } else if (matches(*argv, "help") == 0) { usage(); } else if (strcmp(*argv, "dev") == 0) { From 67584e3ab289a22eb9a2e51f90d23e2ced2e76b0 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Wed, 3 Feb 2016 09:25:00 +0100 Subject: [PATCH 039/513] tc: fix compilation with old gcc (< 4.6) (bis) Commit 8f80d450c3cb ("tc: fix compilation with old gcc (< 4.6)") was reverted to ease the merge of the net-next branch. Here is the new version. Signed-off-by: Nicolas Dichtel Signed-off-by: Daniel Borkmann --- tc/tc_bpf.c | 58 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index 955bd5fbf..3c97cdb47 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -49,6 +49,10 @@ #include "tc_util.h" #include "tc_bpf.h" +#ifndef AF_ALG +#define AF_ALG 38 +#endif + #ifdef HAVE_ELF static int bpf_obj_open(const char *path, enum bpf_prog_type type, const char *sec, bool verbose); @@ -81,12 +85,13 @@ static int bpf(int cmd, union bpf_attr *attr, unsigned int size) static int bpf_map_update(int fd, const void *key, const void *value, uint64_t flags) { - union bpf_attr attr = { - .map_fd = fd, - .key = bpf_ptr_to_u64(key), - .value = bpf_ptr_to_u64(value), - .flags = flags, - }; + union bpf_attr attr; + + memset(&attr, 0, sizeof(attr)); + attr.map_fd = fd; + attr.key = bpf_ptr_to_u64(key); + attr.value = bpf_ptr_to_u64(value); + attr.flags = flags; return bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); } @@ -745,12 +750,13 @@ static __check_format_string(1, 2) void bpf_dump_error(const char *format, ...) static int bpf_map_create(enum bpf_map_type type, unsigned int size_key, unsigned int size_value, unsigned int max_elem) { - union bpf_attr attr = { - .map_type = type, - .key_size = size_key, - .value_size = size_value, - .max_entries = max_elem, - }; + union bpf_attr attr; + + memset(&attr, 0, sizeof(attr)); + attr.map_type = type; + attr.key_size = size_key; + attr.value_size = size_value; + attr.max_entries = max_elem; return bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); } @@ -758,15 +764,16 @@ static int bpf_map_create(enum bpf_map_type type, unsigned int size_key, static int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, size_t size, const char *license) { - union bpf_attr attr = { - .prog_type = type, - .insns = bpf_ptr_to_u64(insns), - .insn_cnt = size / sizeof(struct bpf_insn), - .license = bpf_ptr_to_u64(license), - .log_buf = bpf_ptr_to_u64(bpf_log_buf), - .log_size = sizeof(bpf_log_buf), - .log_level = 1, - }; + union bpf_attr attr; + + memset(&attr, 0, sizeof(attr)); + attr.prog_type = type; + attr.insns = bpf_ptr_to_u64(insns); + attr.insn_cnt = size / sizeof(struct bpf_insn); + attr.license = bpf_ptr_to_u64(license); + attr.log_buf = bpf_ptr_to_u64(bpf_log_buf); + attr.log_size = sizeof(bpf_log_buf); + attr.log_level = 1; if (getenv(BPF_ENV_NOLOG)) { attr.log_buf = 0; @@ -779,10 +786,11 @@ static int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, static int bpf_obj_pin(int fd, const char *pathname) { - union bpf_attr attr = { - .pathname = bpf_ptr_to_u64(pathname), - .bpf_fd = fd, - }; + union bpf_attr attr; + + memset(&attr, 0, sizeof(attr)); + attr.pathname = bpf_ptr_to_u64(pathname); + attr.bpf_fd = fd; return bpf(BPF_OBJ_PIN, &attr, sizeof(attr)); } From 9450c5ec63b0cc4068b363eae7c71b024fc25121 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Thu, 28 Jan 2016 14:48:55 +0100 Subject: [PATCH 040/513] geneve: add support for lwt tunnel creation and dst port selection This change add the ability to create lwt/flow based/externally controlled geneve device and to select the udp destination port used by a full geneve tunnel. Signed-off-by: Paolo Abeni --- ip/iplink_geneve.c | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c index 13454795d..30b16b932 100644 --- a/ip/iplink_geneve.c +++ b/ip/iplink_geneve.c @@ -19,6 +19,7 @@ static void print_explain(FILE *f) { fprintf(f, "Usage: ... geneve id VNI remote ADDR\n"); fprintf(f, " [ ttl TTL ] [ tos TOS ]\n"); + fprintf(f, " [ dstport PORT ] [ [no]external ]\n"); fprintf(f, "\n"); fprintf(f, "Where: VNI := 0-16777215\n"); fprintf(f, " ADDR := IP_ADDRESS\n"); @@ -40,6 +41,8 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, struct in6_addr daddr6 = IN6ADDR_ANY_INIT; __u8 ttl = 0; __u8 tos = 0; + __u16 dstport = 0; + bool metadata = 0; while (argc > 0) { if (!matches(*argv, "id") || @@ -80,6 +83,14 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, tos = uval; } else tos = 1; + } else if (!matches(*argv, "dstport")) { + NEXT_ARG(); + if (get_u16(&dstport, *argv, 0)) + invarg("dstport", *argv); + } else if (!matches(*argv, "external")) { + metadata = true; + } else if (!matches(*argv, "noexternal")) { + metadata = false; } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -91,14 +102,22 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, argc--, argv++; } - if (!vni_set) { - fprintf(stderr, "geneve: missing virtual network identifier\n"); + if (metadata && vni_set) { + fprintf(stderr, "geneve: both 'external' and vni cannot be specified\n"); return -1; } - if (!daddr && memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) == 0) { - fprintf(stderr, "geneve: remote link partner not specified\n"); - return -1; + if (!metadata) { + /* parameter checking make sense only for full geneve tunnels */ + if (!vni_set) { + fprintf(stderr, "geneve: missing virtual network identifier\n"); + return -1; + } + + if (!daddr && memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) == 0) { + fprintf(stderr, "geneve: remote link partner not specified\n"); + return -1; + } } addattr32(n, 1024, IFLA_GENEVE_ID, vni); @@ -108,6 +127,10 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, addattr_l(n, 1024, IFLA_GENEVE_REMOTE6, &daddr6, sizeof(struct in6_addr)); addattr8(n, 1024, IFLA_GENEVE_TTL, ttl); addattr8(n, 1024, IFLA_GENEVE_TOS, tos); + if (dstport) + addattr16(n, 1024, IFLA_GENEVE_PORT, htons(dstport)); + if (metadata) + addattr(n, 1024, IFLA_GENEVE_COLLECT_METADATA); return 0; } @@ -156,6 +179,14 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) else fprintf(f, "tos %#x ", tos); } + + if (tb[IFLA_GENEVE_PORT]) + fprintf(f, "dstport %u ", + ntohs(rta_getattr_u16(tb[IFLA_GENEVE_PORT]))); + + if (tb[IFLA_GENEVE_COLLECT_METADATA]) + fputs("external ", f); + } static void geneve_print_help(struct link_util *lu, int argc, char **argv, From 92a36995b3ceb4de4ebd43d9358e0edebce67615 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sun, 7 Feb 2016 02:11:50 +0100 Subject: [PATCH 041/513] tc, bpf, examples: further bpf_api improvements Add a couple of improvements to tc's BPF api, that facilitate program development. Signed-off-by: Daniel Borkmann --- examples/bpf/bpf_cyclic.c | 4 +-- examples/bpf/bpf_graft.c | 13 ++------- examples/bpf/bpf_prog.c | 26 ++++++++--------- examples/bpf/bpf_shared.c | 3 +- examples/bpf/bpf_tailcall.c | 12 +++----- include/bpf_api.h | 56 +++++++++++++++++++++++++++++++------ 6 files changed, 70 insertions(+), 44 deletions(-) diff --git a/examples/bpf/bpf_cyclic.c b/examples/bpf/bpf_cyclic.c index c66cbecce..36745a3c8 100644 --- a/examples/bpf/bpf_cyclic.c +++ b/examples/bpf/bpf_cyclic.c @@ -11,9 +11,7 @@ BPF_PROG_ARRAY(jmp_tc, JMP_MAP_ID, PIN_OBJECT_NS, 1); __section_tail(JMP_MAP_ID, 0) int cls_loop(struct __sk_buff *skb) { - char fmt[] = "cb: %u\n"; - - trace_printk(fmt, sizeof(fmt), skb->cb[0]++); + printt("cb: %u\n", skb->cb[0]++); tail_call(skb, &jmp_tc, 0); skb->tc_classid = TC_H_MAKE(1, 42); diff --git a/examples/bpf/bpf_graft.c b/examples/bpf/bpf_graft.c index f48fd0288..20784ff4a 100644 --- a/examples/bpf/bpf_graft.c +++ b/examples/bpf/bpf_graft.c @@ -38,29 +38,22 @@ BPF_PROG_ARRAY(jmp_tc, 0, PIN_GLOBAL_NS, 1); __section("aaa") int cls_aaa(struct __sk_buff *skb) { - char fmt[] = "aaa\n"; - - trace_printk(fmt, sizeof(fmt)); + printt("aaa\n"); return TC_H_MAKE(1, 42); } __section("bbb") int cls_bbb(struct __sk_buff *skb) { - char fmt[] = "bbb\n"; - - trace_printk(fmt, sizeof(fmt)); + printt("bbb\n"); return TC_H_MAKE(1, 43); } __section_cls_entry int cls_entry(struct __sk_buff *skb) { - char fmt[] = "fallthrough\n"; - tail_call(skb, &jmp_tc, 0); - trace_printk(fmt, sizeof(fmt)); - + printt("fallthrough\n"); return BPF_H_DEFAULT; } diff --git a/examples/bpf/bpf_prog.c b/examples/bpf/bpf_prog.c index 472804925..f15e876c2 100644 --- a/examples/bpf/bpf_prog.c +++ b/examples/bpf/bpf_prog.c @@ -233,7 +233,7 @@ struct flow_keys { __u8 ip_proto; }; -static inline int flow_ports_offset(__u8 ip_proto) +static __inline__ int flow_ports_offset(__u8 ip_proto) { switch (ip_proto) { case IPPROTO_TCP: @@ -249,14 +249,14 @@ static inline int flow_ports_offset(__u8 ip_proto) } } -static inline bool flow_is_frag(struct __sk_buff *skb, int nh_off) +static __inline__ bool flow_is_frag(struct __sk_buff *skb, int nh_off) { return !!(load_half(skb, nh_off + offsetof(struct iphdr, frag_off)) & (IP_MF | IP_OFFSET)); } -static inline int flow_parse_ipv4(struct __sk_buff *skb, int nh_off, - __u8 *ip_proto, struct flow_keys *flow) +static __inline__ int flow_parse_ipv4(struct __sk_buff *skb, int nh_off, + __u8 *ip_proto, struct flow_keys *flow) { __u8 ip_ver_len; @@ -279,7 +279,7 @@ static inline int flow_parse_ipv4(struct __sk_buff *skb, int nh_off, return nh_off; } -static inline __u32 flow_addr_hash_ipv6(struct __sk_buff *skb, int off) +static __inline__ __u32 flow_addr_hash_ipv6(struct __sk_buff *skb, int off) { __u32 w0 = load_word(skb, off); __u32 w1 = load_word(skb, off + sizeof(w0)); @@ -289,8 +289,8 @@ static inline __u32 flow_addr_hash_ipv6(struct __sk_buff *skb, int off) return w0 ^ w1 ^ w2 ^ w3; } -static inline int flow_parse_ipv6(struct __sk_buff *skb, int nh_off, - __u8 *ip_proto, struct flow_keys *flow) +static __inline__ int flow_parse_ipv6(struct __sk_buff *skb, int nh_off, + __u8 *ip_proto, struct flow_keys *flow) { *ip_proto = load_byte(skb, nh_off + offsetof(struct ipv6hdr, nexthdr)); @@ -300,8 +300,8 @@ static inline int flow_parse_ipv6(struct __sk_buff *skb, int nh_off, return nh_off + sizeof(struct ipv6hdr); } -static inline bool flow_dissector(struct __sk_buff *skb, - struct flow_keys *flow) +static __inline__ bool flow_dissector(struct __sk_buff *skb, + struct flow_keys *flow) { int poff, nh_off = BPF_LL_OFF + ETH_HLEN; __be16 proto = skb->protocol; @@ -381,8 +381,8 @@ static inline bool flow_dissector(struct __sk_buff *skb, return true; } -static inline void cls_update_proto_map(const struct __sk_buff *skb, - const struct flow_keys *flow) +static __inline__ void cls_update_proto_map(const struct __sk_buff *skb, + const struct flow_keys *flow) { uint8_t proto = flow->ip_proto; struct count_tuple *ct, _ct; @@ -401,7 +401,7 @@ static inline void cls_update_proto_map(const struct __sk_buff *skb, map_update_elem(&map_proto, &proto, &_ct, BPF_ANY); } -static inline void cls_update_queue_map(const struct __sk_buff *skb) +static __inline__ void cls_update_queue_map(const struct __sk_buff *skb) { uint32_t queue = skb->queue_mapping; struct count_queue *cq, _cq; @@ -453,7 +453,7 @@ int cls_main(struct __sk_buff *skb) return flow.ip_proto; } -static inline void act_update_drop_map(void) +static __inline__ void act_update_drop_map(void) { uint32_t *count, cpu = get_smp_processor_id(); diff --git a/examples/bpf/bpf_shared.c b/examples/bpf/bpf_shared.c index accc0adf4..7fe9ef30f 100644 --- a/examples/bpf/bpf_shared.c +++ b/examples/bpf/bpf_shared.c @@ -35,12 +35,11 @@ int emain(struct __sk_buff *skb) __section("ingress") int imain(struct __sk_buff *skb) { - char fmt[] = "map val: %d\n"; int key = 0, *val; val = map_lookup_elem(&map_sh, &key); if (val) - trace_printk(fmt, sizeof(fmt), *val); + printt("map val: %d\n", *val); return BPF_H_DEFAULT; } diff --git a/examples/bpf/bpf_tailcall.c b/examples/bpf/bpf_tailcall.c index 040790d0e..f545430f7 100644 --- a/examples/bpf/bpf_tailcall.c +++ b/examples/bpf/bpf_tailcall.c @@ -34,12 +34,11 @@ BPF_ARRAY4(map_sh, 0, PIN_OBJECT_NS, 1); __section_tail(FOO, ENTRY_0) int cls_case1(struct __sk_buff *skb) { - char fmt[] = "case1: map-val: %d from:%u\n"; int key = 0, *val; val = map_lookup_elem(&map_sh, &key); if (val) - trace_printk(fmt, sizeof(fmt), *val, skb->cb[0]); + printt("case1: map-val: %d from:%u\n", *val, skb->cb[0]); skb->cb[0] = ENTRY_0; tail_call(skb, &jmp_ex, ENTRY_0); @@ -50,12 +49,11 @@ int cls_case1(struct __sk_buff *skb) __section_tail(FOO, ENTRY_1) int cls_case2(struct __sk_buff *skb) { - char fmt[] = "case2: map-val: %d from:%u\n"; int key = 0, *val; val = map_lookup_elem(&map_sh, &key); if (val) - trace_printk(fmt, sizeof(fmt), *val, skb->cb[0]); + printt("case2: map-val: %d from:%u\n", *val, skb->cb[0]); skb->cb[0] = ENTRY_1; tail_call(skb, &jmp_tc, ENTRY_0); @@ -66,12 +64,11 @@ int cls_case2(struct __sk_buff *skb) __section_tail(BAR, ENTRY_0) int cls_exit(struct __sk_buff *skb) { - char fmt[] = "exit: map-val: %d from:%u\n"; int key = 0, *val; val = map_lookup_elem(&map_sh, &key); if (val) - trace_printk(fmt, sizeof(fmt), *val, skb->cb[0]); + printt("exit: map-val: %d from:%u\n", *val, skb->cb[0]); /* Termination point. */ return BPF_H_DEFAULT; @@ -80,7 +77,6 @@ int cls_exit(struct __sk_buff *skb) __section_cls_entry int cls_entry(struct __sk_buff *skb) { - char fmt[] = "fallthrough\n"; int key = 0, *val; /* For transferring state, we can use skb->cb[0] ... skb->cb[4]. */ @@ -92,7 +88,7 @@ int cls_entry(struct __sk_buff *skb) tail_call(skb, &jmp_tc, skb->hash & (MAX_JMP_SIZE - 1)); } - trace_printk(fmt, sizeof(fmt)); + printt("fallthrough\n"); return BPF_H_DEFAULT; } diff --git a/include/bpf_api.h b/include/bpf_api.h index 0666a312e..4b16d25c3 100644 --- a/include/bpf_api.h +++ b/include/bpf_api.h @@ -56,6 +56,10 @@ # define ntohl(X) __constant_ntohl((X)) #endif +#ifndef __inline__ +# define __inline__ __attribute__((always_inline)) +#endif + /** Section helper macros. */ #ifndef __section @@ -146,7 +150,7 @@ # define BPF_H_DEFAULT -1 #endif -/** BPF helper functions for tc. */ +/** BPF helper functions for tc. Individual flags are in linux/bpf.h */ #ifndef BPF_FUNC # define BPF_FUNC(NAME, ...) \ @@ -163,8 +167,22 @@ static int BPF_FUNC(map_delete_elem, void *map, const void *key); static uint64_t BPF_FUNC(ktime_get_ns); /* Debugging */ + +/* FIXME: __attribute__ ((format(printf, 1, 3))) not possible unless + * llvm bug https://llvm.org/bugs/show_bug.cgi?id=26243 gets resolved. + * It would require ____fmt to be made const, which generates a reloc + * entry (non-map). + */ static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...); +#ifndef printt +# define printt(fmt, ...) \ + ({ \ + char ____fmt[] = fmt; \ + trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \ + }) +#endif + /* Random numbers */ static uint32_t BPF_FUNC(get_prandom_u32); @@ -185,12 +203,11 @@ static int BPF_FUNC(clone_redirect, struct __sk_buff *skb, int ifindex, uint32_t flags); /* Packet manipulation */ -#define BPF_PSEUDO_HDR 0x10 -#define BPF_HAS_PSEUDO_HDR(flags) ((flags) & BPF_PSEUDO_HDR) -#define BPF_HDR_FIELD_SIZE(flags) ((flags) & 0x0f) - +static int BPF_FUNC(skb_load_bytes, struct __sk_buff *skb, uint32_t off, + void *to, uint32_t len); static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, uint32_t off, - void *from, uint32_t len, uint32_t flags); + const void *from, uint32_t len, uint32_t flags); + static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off, uint32_t from, uint32_t to, uint32_t flags); static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off, @@ -205,14 +222,37 @@ static int BPF_FUNC(skb_vlan_pop, struct __sk_buff *skb); static int BPF_FUNC(skb_get_tunnel_key, struct __sk_buff *skb, struct bpf_tunnel_key *to, uint32_t size, uint32_t flags); static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb, - struct bpf_tunnel_key *from, uint32_t size, uint32_t flags); + const struct bpf_tunnel_key *from, uint32_t size, + uint32_t flags); -/** LLVM built-ins */ +/** LLVM built-ins, mem*() routines work for constant size */ #ifndef lock_xadd # define lock_xadd(ptr, val) ((void) __sync_fetch_and_add(ptr, val)) #endif +#ifndef memset +# define memset(s, c, n) __builtin_memset((s), (c), (n)) +#endif + +#ifndef memcpy +# define memcpy(d, s, n) __builtin_memcpy((d), (s), (n)) +#endif + +#ifndef memmove +# define memmove(d, s, n) __builtin_memmove((d), (s), (n)) +#endif + +/* FIXME: __builtin_memcmp() is not yet fully useable unless llvm bug + * https://llvm.org/bugs/show_bug.cgi?id=26218 gets resolved. Also + * this one would generate a reloc entry (non-map), otherwise. + */ +#if 0 +#ifndef memcmp +# define memcmp(a, b, n) __builtin_memcmp((a), (b), (n)) +#endif +#endif + unsigned long long load_byte(void *skb, unsigned long long off) asm ("llvm.bpf.load.byte"); From f31645d138b754b5b15705d80936e1e047a84c04 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sun, 7 Feb 2016 02:11:51 +0100 Subject: [PATCH 042/513] tc, bpf: improve verifier logging With a bit larger, branchy eBPF programs f.e. already ~BPF_MAXINSNS/7 in size, it happens rather quickly that bpf(2) rejects also valid programs when only the verifier log buffer size we have in tc is too small. Change that, so by default we don't do any logging, and only in error case we retry with logging enabled. If we should fail providing a reasonable dump of the verifier analysis, retry few times with a larger log buffer so that we can at least give the user a chance to debug the program. Signed-off-by: Daniel Borkmann Acked-by: John Fastabend --- tc/tc_bpf.c | 156 ++++++++++++++++++++++++++++++++++++---------------- tc/tc_bpf.h | 1 - 2 files changed, 110 insertions(+), 47 deletions(-) diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index 3c97cdb47..a1286baab 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -711,6 +711,8 @@ struct bpf_elf_ctx { bool verbose; struct bpf_elf_st stat; struct bpf_hash_entry *ht[256]; + char *log; + size_t log_size; }; struct bpf_elf_sec_data { @@ -726,14 +728,8 @@ struct bpf_map_data { struct bpf_elf_map *ent; }; -/* If we provide a small buffer with log level enabled, the kernel - * could fail program load as no buffer space is available for the - * log and thus verifier fails. In case something doesn't pass the - * verifier we still want to hand something descriptive to the user. - */ -static char bpf_log_buf[65536]; - -static __check_format_string(1, 2) void bpf_dump_error(const char *format, ...) +static __check_format_string(2, 3) void +bpf_dump_error(struct bpf_elf_ctx *ctx, const char *format, ...) { va_list vl; @@ -741,12 +737,35 @@ static __check_format_string(1, 2) void bpf_dump_error(const char *format, ...) vfprintf(stderr, format, vl); va_end(vl); - if (bpf_log_buf[0]) { - fprintf(stderr, "%s\n", bpf_log_buf); - memset(bpf_log_buf, 0, sizeof(bpf_log_buf)); + if (ctx->log && ctx->log[0]) { + fprintf(stderr, "%s\n", ctx->log); + memset(ctx->log, 0, ctx->log_size); } } +static int bpf_log_realloc(struct bpf_elf_ctx *ctx) +{ + size_t log_size = ctx->log_size; + void *ptr; + + if (!ctx->log) { + log_size = 65536; + } else { + log_size <<= 1; + if (log_size > (UINT_MAX >> 8)) + return -EINVAL; + } + + ptr = realloc(ctx->log, log_size); + if (!ptr) + return -ENOMEM; + + ctx->log = ptr; + ctx->log_size = log_size; + + return 0; +} + static int bpf_map_create(enum bpf_map_type type, unsigned int size_key, unsigned int size_value, unsigned int max_elem) { @@ -762,23 +781,21 @@ static int bpf_map_create(enum bpf_map_type type, unsigned int size_key, } static int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, - size_t size, const char *license) + size_t size_insns, const char *license, char *log, + size_t size_log) { union bpf_attr attr; memset(&attr, 0, sizeof(attr)); attr.prog_type = type; attr.insns = bpf_ptr_to_u64(insns); - attr.insn_cnt = size / sizeof(struct bpf_insn); + attr.insn_cnt = size_insns / sizeof(struct bpf_insn); attr.license = bpf_ptr_to_u64(license); - attr.log_buf = bpf_ptr_to_u64(bpf_log_buf); - attr.log_size = sizeof(bpf_log_buf); - attr.log_level = 1; - if (getenv(BPF_ENV_NOLOG)) { - attr.log_buf = 0; - attr.log_size = 0; - attr.log_level = 0; + if (size_log > 0) { + attr.log_buf = bpf_ptr_to_u64(log); + attr.log_size = size_log; + attr.log_level = 1; } return bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); @@ -1038,30 +1055,73 @@ static int bpf_place_pinned(int fd, const char *name, return bpf_obj_pin(fd, pathname); } -static int bpf_prog_attach(const char *section, - const struct bpf_elf_prog *prog, bool verbose) +static void bpf_prog_report(int fd, const char *section, + const struct bpf_elf_prog *prog, + struct bpf_elf_ctx *ctx) { - int fd; + fprintf(stderr, "Prog section \'%s\' %s%s (%d)!\n", section, + fd < 0 ? "rejected: " : "loaded", + fd < 0 ? strerror(errno) : "", + fd < 0 ? errno : fd); + + fprintf(stderr, " - Type: %u\n", prog->type); + fprintf(stderr, " - Instructions: %zu\n", + prog->size / sizeof(struct bpf_insn)); + fprintf(stderr, " - License: %s\n\n", prog->license); + + bpf_dump_error(ctx, "Verifier analysis:\n\n"); +} - /* We can add pinning here later as well, same as bpf_map_attach(). */ +static int bpf_prog_attach(const char *section, + const struct bpf_elf_prog *prog, + struct bpf_elf_ctx *ctx) +{ + int tries = 0, fd; +retry: errno = 0; fd = bpf_prog_load(prog->type, prog->insns, prog->size, - prog->license); - if (fd < 0 || verbose) { - bpf_dump_error("Prog section \'%s\' (type:%u insns:%zu " - "license:\'%s\') %s%s (%d)!\n\n", - section, prog->type, - prog->size / sizeof(struct bpf_insn), - prog->license, fd < 0 ? "rejected: " : - "loaded", fd < 0 ? strerror(errno) : "", - fd < 0 ? errno : fd); + prog->license, 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 + * into our buffer. Still, try to give a debuggable error + * log for the user, so enlarge it and re-fail. + */ + if (fd < 0 && (errno == ENOSPC || !ctx->log_size)) { + if (tries++ < 6 && !bpf_log_realloc(ctx)) + goto retry; + + fprintf(stderr, "Log buffer too small to dump " + "verifier log %zu bytes (%d tries)!\n", + ctx->log_size, tries); + return fd; + } + + bpf_prog_report(fd, section, prog, ctx); } return fd; } +static void bpf_map_report(int fd, const char *name, + const struct bpf_elf_map *map, + struct bpf_elf_ctx *ctx) +{ + fprintf(stderr, "Map object \'%s\' %s%s (%d)!\n", name, + fd < 0 ? "rejected: " : "loaded", + fd < 0 ? strerror(errno) : "", + fd < 0 ? errno : fd); + + fprintf(stderr, " - Type: %u\n", map->type); + fprintf(stderr, " - Identifier: %u\n", map->id); + fprintf(stderr, " - Pinning: %u\n", map->pinning); + fprintf(stderr, " - Size key: %u\n", map->size_key); + fprintf(stderr, " - Size value: %u\n", map->size_value); + fprintf(stderr, " - Max elems: %u\n\n", map->max_elem); +} + static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, - const struct bpf_elf_ctx *ctx, bool verbose) + struct bpf_elf_ctx *ctx) { int fd, ret; @@ -1076,7 +1136,7 @@ static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, name); return ret; } - if (verbose) + if (ctx->verbose) fprintf(stderr, "Map \'%s\' loaded as pinned!\n", name); return fd; @@ -1085,13 +1145,8 @@ static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, errno = 0; fd = bpf_map_create(map->type, map->size_key, map->size_value, map->max_elem); - if (fd < 0 || verbose) { - bpf_dump_error("Map \'%s\' (type:%u id:%u pinning:%u " - "ksize:%u vsize:%u max-elems:%u) %s%s (%d)!\n", - name, map->type, map->id, map->pinning, - map->size_key, map->size_value, map->max_elem, - fd < 0 ? "rejected: " : "loaded", fd < 0 ? - strerror(errno) : "", fd < 0 ? errno : fd); + if (fd < 0 || ctx->verbose) { + bpf_map_report(fd, name, map, ctx); if (fd < 0) return fd; } @@ -1147,8 +1202,7 @@ static int bpf_maps_attach_all(struct bpf_elf_ctx *ctx) if (!map_name) return -EIO; - fd = bpf_map_attach(map_name, &ctx->maps[i], ctx, - ctx->verbose); + fd = bpf_map_attach(map_name, &ctx->maps[i], ctx); if (fd < 0) return fd; @@ -1300,7 +1354,7 @@ static int bpf_fetch_prog(struct bpf_elf_ctx *ctx, const char *section) prog.size = data.sec_data->d_size; prog.license = ctx->license; - fd = bpf_prog_attach(section, &prog, ctx->verbose); + fd = bpf_prog_attach(section, &prog, ctx); if (fd < 0) continue; @@ -1391,7 +1445,7 @@ static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section) prog.size = data_insn.sec_data->d_size; prog.license = ctx->license; - fd = bpf_prog_attach(section, &prog, ctx->verbose); + fd = bpf_prog_attach(section, &prog, ctx); if (fd < 0) continue; @@ -1657,10 +1711,17 @@ static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname, goto out_elf; } + if (ctx->verbose && bpf_log_realloc(ctx)) { + ret = -ENOMEM; + goto out_free; + } + bpf_save_finfo(ctx); bpf_hash_init(ctx, CONFDIR "/bpf_pinning"); return 0; +out_free: + free(ctx->sec_done); out_elf: elf_end(ctx->elf_fd); out_fd: @@ -1697,7 +1758,10 @@ static void bpf_elf_ctx_destroy(struct bpf_elf_ctx *ctx, bool failure) bpf_maps_teardown(ctx); bpf_hash_destroy(ctx); + free(ctx->sec_done); + free(ctx->log); + elf_end(ctx->elf_fd); close(ctx->obj_fd); } diff --git a/tc/tc_bpf.h b/tc/tc_bpf.h index 526d0b126..93f7f0e24 100644 --- a/tc/tc_bpf.h +++ b/tc/tc_bpf.h @@ -32,7 +32,6 @@ enum { #define BPF_ENV_UDS "TC_BPF_UDS" #define BPF_ENV_MNT "TC_BPF_MNT" -#define BPF_ENV_NOLOG "TC_BPF_NOLOG" #ifndef BPF_FS_MAGIC # define BPF_FS_MAGIC 0xcafe4a11 From a576c6b977f275ae5ffc0e94135c26b18ce5138a Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sun, 7 Feb 2016 02:11:52 +0100 Subject: [PATCH 043/513] tc, bpf: give some more hints wrt false relos Provide some more hints to the user/developer when relos have been found that don't point to ld64 imm instruction. Ran couple of times into relos generated by clang [1], where the compiler tried to uninline inlined functions with eBPF and emitted BPF_JMP | BPF_CALL opcodes. If this seems the case, give a hint that the user should do a work-around to use always_inline annotation. [1] https://llvm.org/bugs/show_bug.cgi?id=26243#c3 Signed-off-by: Daniel Borkmann --- tc/tc_bpf.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index a1286baab..5e80d0f98 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -1385,8 +1385,16 @@ static int bpf_apply_relo_data(struct bpf_elf_ctx *ctx, ioff = relo.r_offset / sizeof(struct bpf_insn); if (ioff >= num_insns || - insns[ioff].code != (BPF_LD | BPF_IMM | BPF_DW)) + insns[ioff].code != (BPF_LD | BPF_IMM | BPF_DW)) { + fprintf(stderr, "ELF contains relo data for non ld64 " + "instruction at offset %u! Compiler bug?!\n", + ioff); + if (ioff < num_insns && + insns[ioff].code == (BPF_JMP | BPF_CALL)) + fprintf(stderr, " - Try to annotate functions " + "with always_inline attribute!\n"); return -EINVAL; + } if (gelf_getsym(ctx->sym_tab, GELF_R_SYM(relo.r_info), &sym) != &sym) return -EIO; From 5230a2ede099ed3141dc9495ee7b98c0b7ef2b10 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sun, 7 Feb 2016 02:11:53 +0100 Subject: [PATCH 044/513] tc, bpf: use bind/type macros from gelf Don't reimplement them and rather use the macros from the gelf header, that is, GELF_ST_BIND()/GELF_ST_TYPE(). Signed-off-by: Daniel Borkmann --- tc/tc_bpf.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index 5e80d0f98..6a94894ff 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -1162,9 +1162,6 @@ static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, return fd; } -#define __ELF_ST_BIND(x) ((x) >> 4) -#define __ELF_ST_TYPE(x) (((unsigned int) x) & 0xf) - static const char *bpf_str_tab_name(const struct bpf_elf_ctx *ctx, const GElf_Sym *sym) { @@ -1180,8 +1177,8 @@ static const char *bpf_map_fetch_name(struct bpf_elf_ctx *ctx, int which) if (gelf_getsym(ctx->sym_tab, i, &sym) != &sym) continue; - if (__ELF_ST_BIND(sym.st_info) != STB_GLOBAL || - __ELF_ST_TYPE(sym.st_info) != STT_NOTYPE || + if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL || + GELF_ST_TYPE(sym.st_info) != STT_NOTYPE || sym.st_shndx != ctx->sec_maps || sym.st_value / sizeof(struct bpf_elf_map) != which) continue; From a1987cd17fcb042bd80f0dc2bf51941769fdb493 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Wed, 27 Jan 2016 09:09:37 -0800 Subject: [PATCH 045/513] bridge: support for static fdb entries There is no intuitive option to add static fdb entries today. 'temp' seems to have a side effect of adding 'static' fdb entries. But the name and intent of 'temp' does not say anything about it being static. example: bridge fdb add operates as follows: $bridge fdb add 00:01:02:03:04:05 dev eth0 master $bridge fdb add 00:01:02:03:04:06 dev eth0 master temp $bridge fdb add 00:01:02:03:04:07 dev eth0 master local $bridge fdb show 00:01:02:03:04:05 dev eth0 permanent 00:01:02:03:04:06 dev eth0 static 00:01:02:03:04:07 dev eth0 permanent 00:01:02:03:04:08 dev eth0 <<== dynamic, ageable learned mac This patch adds a new bridge fdb type 'static' which makes sure NUD_NOARP and NUD_REACHABLE is set for static entries. This effectively is nothing but what 'temp' does today. But the name 'temp' is misleading. After the patch: $bridge fdb add 00:01:02:03:04:06 dev eth0 master static $bridge fdb show 00:01:02:03:04:06 dev eth0 static 'temp' could ideally be a dynamic mac that can age (ie just NUD_REACHABLE). But, 'temp' sets 'NUD_NOARP' and 'NUD_REACHABLE'. Too late to change 'temp' now. But, we are thinking of introduing a 'dynamic' keyword after this patch that only sets NUD_REACHABLE. Signed-off-by: Wilson Kok Signed-off-by: Roopa Prabhu --- bridge/fdb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bridge/fdb.c b/bridge/fdb.c index 4d109251c..9bc6b942a 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -33,7 +33,7 @@ static void usage(void) { fprintf(stderr, "Usage: bridge fdb { add | append | del | replace } ADDR dev DEV\n" " [ self ] [ master ] [ use ] [ router ]\n" - " [ local | temp ] [ dst IPADDR ] [ vlan VID ]\n" + " [ local | temp | static ] [ dst IPADDR ] [ vlan VID ]\n" " [ port PORT] [ vni VNI ] [ via DEV ]\n"); fprintf(stderr, " bridge fdb [ show [ br BRDEV ] [ brport DEV ] ]\n"); exit(-1); @@ -301,7 +301,8 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv) } else if (matches(*argv, "local") == 0|| matches(*argv, "permanent") == 0) { req.ndm.ndm_state |= NUD_PERMANENT; - } else if (matches(*argv, "temp") == 0) { + } else if (matches(*argv, "temp") == 0 || + matches(*argv, "static") == 0) { req.ndm.ndm_state |= NUD_REACHABLE; } else if (matches(*argv, "vlan") == 0) { if (vid >= 0) From 70dfb0b8836d8fb17009b5473b14f4bc470cb68d Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:19 +0100 Subject: [PATCH 046/513] iplink: bridge: export bridge_id and designated_root Netlink returns the bridge_id and designated_root, we just need to make them visible. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 00804093d..3bbbcaa12 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "rt_names.h" #include "utils.h" @@ -39,6 +40,15 @@ static void explain(void) print_explain(stderr); } +static void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, + size_t len) +{ + char eaddr[32]; + + ether_ntoa_r((const struct ether_addr *)id->addr, eaddr); + snprintf(buf, len, "%.2x%.2x.%s", id->prio[0], id->prio[1], eaddr); +} + static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { @@ -155,6 +165,22 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]), b1, sizeof(b1))); } + + if (tb[IFLA_BR_BRIDGE_ID]) { + char bridge_id[32]; + + br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), bridge_id, + sizeof(bridge_id)); + fprintf(f, "bridge_id %s ", bridge_id); + } + + if (tb[IFLA_BR_ROOT_ID]) { + char root_id[32]; + + br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), root_id, + sizeof(root_id)); + fprintf(f, "designated_root %s ", root_id); + } } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 4e3bbc66580fc7249217df9e0ef18cbb50876561 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:20 +0100 Subject: [PATCH 047/513] iplink: bridge: export root_(port|path_cost), topology_change and change_detected Netlink already export these values, we just need to make them visible. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 3bbbcaa12..33ffa6c27 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -181,6 +181,22 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) sizeof(root_id)); fprintf(f, "designated_root %s ", root_id); } + + if (tb[IFLA_BR_ROOT_PORT]) + fprintf(f, "root_port %u ", + rta_getattr_u16(tb[IFLA_BR_ROOT_PORT])); + + if (tb[IFLA_BR_ROOT_PATH_COST]) + fprintf(f, "root_path_cost %u ", + rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST])); + + if (tb[IFLA_BR_TOPOLOGY_CHANGE]) + fprintf(f, "topology_change %u ", + rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE])); + + if (tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]) + fprintf(f, "topology_change_detected %u ", + rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 8c0f7a16305f86baaefe16050139a03b1f3b24ee Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:21 +0100 Subject: [PATCH 048/513] iplink: bridge: export read-only timers Netlink already provides hello_timer, tcn_timer, topology_change_timer and gc_timer, so let's make them visible. Signed-off-by: Nikolay Aleksandrov --- include/utils.h | 18 ++++++++++++++++++ ip/iplink_bridge.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/include/utils.h b/include/utils.h index 7310f4e0e..c43427c35 100644 --- a/include/utils.h +++ b/include/utils.h @@ -175,6 +175,24 @@ static inline __u32 nl_mgrp(__u32 group) return group ? (1 << (group - 1)) : 0; } +/* courtesy of bridge-utils */ +static inline unsigned long __tv_to_jiffies(const struct timeval *tv) +{ + unsigned long long jif; + + jif = 1000000ULL * tv->tv_sec + tv->tv_usec; + + return jif/10000; +} + +static inline void __jiffies_to_tv(struct timeval *tv, unsigned long jiffies) +{ + unsigned long long tvusec; + + tvusec = 10000ULL*jiffies; + tv->tv_sec = tvusec/1000000; + tv->tv_usec = tvusec - 1000000 * tv->tv_sec; +} int print_timestamp(FILE *fp); void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n); diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 33ffa6c27..cd1655751 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -197,6 +197,40 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]) fprintf(f, "topology_change_detected %u ", rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])); + + if (tb[IFLA_BR_HELLO_TIMER]) { + struct timeval tv; + + __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_HELLO_TIMER])); + fprintf(f, "hello_timer %4i.%.2i ", (int)tv.tv_sec, + (int)tv.tv_usec/10000); + } + + if (tb[IFLA_BR_TCN_TIMER]) { + struct timeval tv; + + __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_TCN_TIMER])); + fprintf(f, "tcn_timer %4i.%.2i ", (int)tv.tv_sec, + (int)tv.tv_usec/10000); + } + + if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]) { + unsigned long jiffies; + struct timeval tv; + + jiffies = rta_getattr_u64(tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]); + __jiffies_to_tv(&tv, jiffies); + fprintf(f, "topology_change_timer %4i.%.2i ", (int)tv.tv_sec, + (int)tv.tv_usec/10000); + } + + if (tb[IFLA_BR_GC_TIMER]) { + struct timeval tv; + + __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_GC_TIMER])); + fprintf(f, "gc_timer %4i.%.2i ", (int)tv.tv_sec, + (int)tv.tv_usec/10000); + } } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 8caaf33bdb61d8bc55db4445fd81e098777e8014 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:22 +0100 Subject: [PATCH 049/513] iplink: bridge: add support for IFLA_BR_GROUP_FWD_MASK This patch implements support for the IFLA_BR_GROUP_FWD_MASK attribute in iproute2 so it can change the group forwarding mask. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index cd1655751..2ee4bd690 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -28,6 +28,7 @@ static void print_explain(FILE *f) " [ ageing_time AGEING_TIME ]\n" " [ stp_state STP_STATE ]\n" " [ priority PRIORITY ]\n" + " [ group_fwd_mask MASK ]\n" " [ vlan_filtering VLAN_FILTERING ]\n" " [ vlan_protocol VLAN_PROTOCOL ]\n" "\n" @@ -111,6 +112,14 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, return -1; } addattr16(n, 1024, IFLA_BR_VLAN_PROTOCOL, vlan_proto); + } else if (matches(*argv, "group_fwd_mask") == 0) { + __u16 fwd_mask; + + NEXT_ARG(); + if (get_u16(&fwd_mask, *argv, 0)) + invarg("invalid group_fwd_mask", *argv); + + addattr16(n, 1024, IFLA_BR_GROUP_FWD_MASK, fwd_mask); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -231,6 +240,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fprintf(f, "gc_timer %4i.%.2i ", (int)tv.tv_sec, (int)tv.tv_usec/10000); } + + if (tb[IFLA_BR_GROUP_FWD_MASK]) + fprintf(f, "group_fwd_mask %#x ", + rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 0a61aa3963e25a32e82cad8cdd04f31532ec5b3f Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:23 +0100 Subject: [PATCH 050/513] iplink: bridge: add support for IFLA_BR_GROUP_ADDR This patch implements support for the IFLA_BR_GROUP_ADDR attribute in iproute2 so it can change the group address. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 2ee4bd690..0a2845027 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -29,6 +29,7 @@ static void print_explain(FILE *f) " [ stp_state STP_STATE ]\n" " [ priority PRIORITY ]\n" " [ group_fwd_mask MASK ]\n" + " [ group_address ADDRESS ]\n" " [ vlan_filtering VLAN_FILTERING ]\n" " [ vlan_protocol VLAN_PROTOCOL ]\n" "\n" @@ -120,6 +121,15 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, invarg("invalid group_fwd_mask", *argv); addattr16(n, 1024, IFLA_BR_GROUP_FWD_MASK, fwd_mask); + } else if (matches(*argv, "group_address") == 0) { + char llabuf[32]; + int len; + + NEXT_ARG(); + len = ll_addr_a2n(llabuf, sizeof(llabuf), *argv); + if (len < 0) + return -1; + addattr_l(n, 1024, IFLA_BR_GROUP_ADDR, llabuf, len); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -244,6 +254,15 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_GROUP_FWD_MASK]) fprintf(f, "group_fwd_mask %#x ", rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK])); + + if (tb[IFLA_BR_GROUP_ADDR]) { + SPRINT_BUF(mac); + + fprintf(f, "group_address %s ", + ll_addr_n2a(RTA_DATA(tb[IFLA_BR_GROUP_ADDR]), + RTA_PAYLOAD(tb[IFLA_BR_GROUP_ADDR]), + 1 /*ARPHDR_ETHER*/, mac, sizeof(mac))); + } } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 719832af6c862a04247f28c73b72bf0eea4c7984 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:24 +0100 Subject: [PATCH 051/513] iplink: bridge: add support for IFLA_BR_VLAN_DEFAULT_PVID This patch implements support for the IFLA_BR_VLAN_DEFAULT_PVID attribute in iproute2 so it can change the default pvid. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 0a2845027..9a8924c2e 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -32,6 +32,7 @@ static void print_explain(FILE *f) " [ group_address ADDRESS ]\n" " [ vlan_filtering VLAN_FILTERING ]\n" " [ vlan_protocol VLAN_PROTOCOL ]\n" + " [ vlan_default_pvid VLAN_DEFAULT_PVID ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -130,6 +131,15 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, if (len < 0) return -1; addattr_l(n, 1024, IFLA_BR_GROUP_ADDR, llabuf, len); + } else if (matches(*argv, "vlan_default_pvid") == 0) { + __u16 default_pvid; + + NEXT_ARG(); + if (get_u16(&default_pvid, *argv, 0)) + invarg("invalid vlan_default_pvid", *argv); + + addattr16(n, 1024, IFLA_BR_VLAN_DEFAULT_PVID, + default_pvid); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -251,6 +261,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) (int)tv.tv_usec/10000); } + if (tb[IFLA_BR_VLAN_DEFAULT_PVID]) + fprintf(f, "vlan_default_pvid %u ", + rta_getattr_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID])); + if (tb[IFLA_BR_GROUP_FWD_MASK]) fprintf(f, "group_fwd_mask %#x ", rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK])); From 963d137cf927c4d323cf77fb30c3695feff5367b Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:25 +0100 Subject: [PATCH 052/513] iplink: bridge: add support for IFLA_BR_MCAST_ROUTER This patch implements support for the IFLA_BR_MCAST_ROUTER attribute in iproute2 so it can change the multicast router value. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 9a8924c2e..7a945ed2a 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -33,6 +33,7 @@ static void print_explain(FILE *f) " [ vlan_filtering VLAN_FILTERING ]\n" " [ vlan_protocol VLAN_PROTOCOL ]\n" " [ vlan_default_pvid VLAN_DEFAULT_PVID ]\n" + " [ mcast_router MULTICAST_ROUTER ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -140,6 +141,14 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, addattr16(n, 1024, IFLA_BR_VLAN_DEFAULT_PVID, default_pvid); + } else if (matches(*argv, "mcast_router") == 0) { + __u8 mcast_router; + + NEXT_ARG(); + if (get_u8(&mcast_router, *argv, 0)) + invarg("invalid mcast_router", *argv); + + addattr8(n, 1024, IFLA_BR_MCAST_ROUTER, mcast_router); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -277,6 +286,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) RTA_PAYLOAD(tb[IFLA_BR_GROUP_ADDR]), 1 /*ARPHDR_ETHER*/, mac, sizeof(mac))); } + + if (tb[IFLA_BR_MCAST_ROUTER]) + fprintf(f, "mcast_router %u ", + rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 7ddd2d946cebf031c90d7b0d62b32bd880f7af8c Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:26 +0100 Subject: [PATCH 053/513] iplink: bridge: add support for IFLA_BR_MCAST_SNOOPING This patch implements support for the IFLA_BR_MCAST_SNOOPING attribute in iproute2 so it can change the multicast snooping value. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 7a945ed2a..fef867bfb 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -33,6 +33,7 @@ static void print_explain(FILE *f) " [ vlan_filtering VLAN_FILTERING ]\n" " [ vlan_protocol VLAN_PROTOCOL ]\n" " [ vlan_default_pvid VLAN_DEFAULT_PVID ]\n" + " [ mcast_snooping MULTICAST_SNOOPING ]\n" " [ mcast_router MULTICAST_ROUTER ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" @@ -149,6 +150,14 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, invarg("invalid mcast_router", *argv); addattr8(n, 1024, IFLA_BR_MCAST_ROUTER, mcast_router); + } else if (matches(*argv, "mcast_snooping") == 0) { + __u8 mcast_snoop; + + NEXT_ARG(); + if (get_u8(&mcast_snoop, *argv, 0)) + invarg("invalid mcast_snooping", *argv); + + addattr8(n, 1024, IFLA_BR_MCAST_SNOOPING, mcast_snoop); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -287,6 +296,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) 1 /*ARPHDR_ETHER*/, mac, sizeof(mac))); } + if (tb[IFLA_BR_MCAST_SNOOPING]) + fprintf(f, "mcast_snooping %u ", + rta_getattr_u8(tb[IFLA_BR_MCAST_SNOOPING])); + if (tb[IFLA_BR_MCAST_ROUTER]) fprintf(f, "mcast_router %u ", rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER])); From 449843d1d6b7ed11723b6a6585a4b781a110ffdd Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:27 +0100 Subject: [PATCH 054/513] iplink: bridge: add support for IFLA_BR_MCAST_QUERY_USE_IFADDR This patch implements support for the IFLA_BR_MCAST_QUERY_USE_IFADDR attribute in iproute2 so it can toggle the multicast_query_use_ifaddr val. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index fef867bfb..b802ef15e 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -35,6 +35,7 @@ static void print_explain(FILE *f) " [ vlan_default_pvid VLAN_DEFAULT_PVID ]\n" " [ mcast_snooping MULTICAST_SNOOPING ]\n" " [ mcast_router MULTICAST_ROUTER ]\n" + " [ mcast_query_use_ifaddr MCAST_QUERY_USE_IFADDR ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -158,6 +159,16 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, invarg("invalid mcast_snooping", *argv); addattr8(n, 1024, IFLA_BR_MCAST_SNOOPING, mcast_snoop); + } else if (matches(*argv, "mcast_query_use_ifaddr") == 0) { + __u8 mcast_qui; + + NEXT_ARG(); + if (get_u8(&mcast_qui, *argv, 0)) + invarg("invalid mcast_query_use_ifaddr", + *argv); + + addattr8(n, 1024, IFLA_BR_MCAST_QUERY_USE_IFADDR, + mcast_qui); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -303,6 +314,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_MCAST_ROUTER]) fprintf(f, "mcast_router %u ", rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER])); + + if (tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]) + fprintf(f, "mcast_query_use_ifaddr %u ", + rta_getattr_u8(tb[IFLA_BR_MCAST_QUERY_USE_IFADDR])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 0778b741225a51bb6d72fe42683267e86bc31215 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:28 +0100 Subject: [PATCH 055/513] iplink: bridge: add support for IFLA_BR_MCAST_QUERIER This patch implements support for the IFLA_BR_MCAST_QUERIER attribute in iproute2 so it can toggle the mcast querier value. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index b802ef15e..fbea0a38f 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -36,6 +36,7 @@ static void print_explain(FILE *f) " [ mcast_snooping MULTICAST_SNOOPING ]\n" " [ mcast_router MULTICAST_ROUTER ]\n" " [ mcast_query_use_ifaddr MCAST_QUERY_USE_IFADDR ]\n" + " [ mcast_querier MULTICAST_QUERIER ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -169,6 +170,14 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, addattr8(n, 1024, IFLA_BR_MCAST_QUERY_USE_IFADDR, mcast_qui); + } else if (matches(*argv, "mcast_querier") == 0) { + __u8 mcast_querier; + + NEXT_ARG(); + if (get_u8(&mcast_querier, *argv, 0)) + invarg("invalid mcast_querier", *argv); + + addattr8(n, 1024, IFLA_BR_MCAST_QUERIER, mcast_querier); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -318,6 +327,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]) fprintf(f, "mcast_query_use_ifaddr %u ", rta_getattr_u8(tb[IFLA_BR_MCAST_QUERY_USE_IFADDR])); + + if (tb[IFLA_BR_MCAST_QUERIER]) + fprintf(f, "mcast_querier %u ", + rta_getattr_u8(tb[IFLA_BR_MCAST_QUERIER])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 92c0ef7071b3895ea89f26b7b7b6a77141e43578 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:29 +0100 Subject: [PATCH 056/513] iplink: bridge: add support for IFLA_BR_MCAST_HASH_ELASTICITY This patch implements support for the IFLA_BR_MCAST_HASH_ELASTICTITY attribute in iproute2 so it can change the hash elasticity value. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index fbea0a38f..93dcc982c 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -37,6 +37,7 @@ static void print_explain(FILE *f) " [ mcast_router MULTICAST_ROUTER ]\n" " [ mcast_query_use_ifaddr MCAST_QUERY_USE_IFADDR ]\n" " [ mcast_querier MULTICAST_QUERIER ]\n" + " [ mcast_hash_elasticity HASH_ELASTICITY ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -178,6 +179,16 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, invarg("invalid mcast_querier", *argv); addattr8(n, 1024, IFLA_BR_MCAST_QUERIER, mcast_querier); + } else if (matches(*argv, "mcast_hash_elasticity") == 0) { + __u32 mcast_hash_el; + + NEXT_ARG(); + if (get_u32(&mcast_hash_el, *argv, 0)) + invarg("invalid mcast_hash_elasticity", + *argv); + + addattr32(n, 1024, IFLA_BR_MCAST_HASH_ELASTICITY, + mcast_hash_el); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -331,6 +342,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_MCAST_QUERIER]) fprintf(f, "mcast_querier %u ", rta_getattr_u8(tb[IFLA_BR_MCAST_QUERIER])); + + if (tb[IFLA_BR_MCAST_HASH_ELASTICITY]) + fprintf(f, "mcast_hash_elasticity %u ", + rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_ELASTICITY])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 8b9eb7cd259416d0a46bd7ed7820f6bfdd909b64 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:30 +0100 Subject: [PATCH 057/513] iplink: bridge: add support for IFLA_BR_MCAST_HASH_MAX This patch implements support for the IFLA_BR_MCAST_HASH_MAX attribute in iproute2 so it can change the maximum hashed entries. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 93dcc982c..f912c318c 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -38,6 +38,7 @@ static void print_explain(FILE *f) " [ mcast_query_use_ifaddr MCAST_QUERY_USE_IFADDR ]\n" " [ mcast_querier MULTICAST_QUERIER ]\n" " [ mcast_hash_elasticity HASH_ELASTICITY ]\n" + " [ mcast_hash_max HASH_MAX ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -189,6 +190,15 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, addattr32(n, 1024, IFLA_BR_MCAST_HASH_ELASTICITY, mcast_hash_el); + } else if (matches(*argv, "mcast_hash_max") == 0) { + __u32 mcast_hash_max; + + NEXT_ARG(); + if (get_u32(&mcast_hash_max, *argv, 0)) + invarg("invalid mcast_hash_max", *argv); + + addattr32(n, 1024, IFLA_BR_MCAST_HASH_MAX, + mcast_hash_max); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -346,6 +356,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_MCAST_HASH_ELASTICITY]) fprintf(f, "mcast_hash_elasticity %u ", rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_ELASTICITY])); + + if (tb[IFLA_BR_MCAST_HASH_MAX]) + fprintf(f, "mcast_hash_max %u ", + rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_MAX])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From fb44cadb9200f85fc1c78c5a208ce7bed2c5a594 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:31 +0100 Subject: [PATCH 058/513] iplink: bridge: add support for IFLA_BR_MCAST_LAST_MEMBER_CNT This patch implements support for the IFLA_BR_MCAST_LAST_MEMBER_CNT attribute in iproute2 so it can change the last member count value. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index f912c318c..be83a5690 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -39,6 +39,7 @@ static void print_explain(FILE *f) " [ mcast_querier MULTICAST_QUERIER ]\n" " [ mcast_hash_elasticity HASH_ELASTICITY ]\n" " [ mcast_hash_max HASH_MAX ]\n" + " [ mcast_last_member_count LAST_MEMBER_COUNT ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -199,6 +200,16 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, addattr32(n, 1024, IFLA_BR_MCAST_HASH_MAX, mcast_hash_max); + } else if (matches(*argv, "mcast_last_member_count") == 0) { + __u32 mcast_lmc; + + NEXT_ARG(); + if (get_u32(&mcast_lmc, *argv, 0)) + invarg("invalid mcast_last_member_count", + *argv); + + addattr32(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_CNT, + mcast_lmc); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -360,6 +371,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_MCAST_HASH_MAX]) fprintf(f, "mcast_hash_max %u ", rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_MAX])); + + if (tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]) + fprintf(f, "mcast_last_member_count %u ", + rta_getattr_u32(tb[IFLA_BR_MCAST_LAST_MEMBER_CNT])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From ceb6486655254f6abde06276b564b0bb1fc2ea11 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:32 +0100 Subject: [PATCH 059/513] iplink: bridge: add support for IFLA_BR_MCAST_STARTUP_QUERY_CNT This patch implements support for the IFLA_BR_MCAST_STARTUP_QUERY_CNT attribute in iproute2 so it can change the startup query count. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index be83a5690..58c19a1f0 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -40,6 +40,7 @@ static void print_explain(FILE *f) " [ mcast_hash_elasticity HASH_ELASTICITY ]\n" " [ mcast_hash_max HASH_MAX ]\n" " [ mcast_last_member_count LAST_MEMBER_COUNT ]\n" + " [ mcast_startup_query_count STARTUP_QUERY_COUNT ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -210,6 +211,16 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, addattr32(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_CNT, mcast_lmc); + } else if (matches(*argv, "mcast_startup_query_count") == 0) { + __u32 mcast_sqc; + + NEXT_ARG(); + if (get_u32(&mcast_sqc, *argv, 0)) + invarg("invalid mcast_startup_query_count", + *argv); + + addattr32(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_CNT, + mcast_sqc); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -375,6 +386,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]) fprintf(f, "mcast_last_member_count %u ", rta_getattr_u32(tb[IFLA_BR_MCAST_LAST_MEMBER_CNT])); + + if (tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT]) + fprintf(f, "mcast_startup_query_count %u ", + rta_getattr_u32(tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 10082a253fb2649b94093dec7737b15c72e159d4 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:33 +0100 Subject: [PATCH 060/513] iplink: bridge: add support for IFLA_BR_MCAST_LAST_MEMBER_INTVL This patch implements support for the IFLA_BR_MCAST_LAST_MEMBER_INTVL attribute in iproute2 so it can change the last member interval. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 58c19a1f0..9522c3f19 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -41,6 +41,7 @@ static void print_explain(FILE *f) " [ mcast_hash_max HASH_MAX ]\n" " [ mcast_last_member_count LAST_MEMBER_COUNT ]\n" " [ mcast_startup_query_count STARTUP_QUERY_COUNT ]\n" + " [ mcast_last_member_interval LAST_MEMBER_INTERVAL ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -221,6 +222,16 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, addattr32(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_CNT, mcast_sqc); + } else if (matches(*argv, "mcast_last_member_interval") == 0) { + __u64 mcast_last_member_intvl; + + NEXT_ARG(); + if (get_u64(&mcast_last_member_intvl, *argv, 0)) + invarg("invalid mcast_last_member_interval", + *argv); + + addattr64(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_INTVL, + mcast_last_member_intvl); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -390,6 +401,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT]) fprintf(f, "mcast_startup_query_count %u ", rta_getattr_u32(tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT])); + + if (tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL]) + fprintf(f, "mcast_last_member_interval %llu ", + rta_getattr_u64(tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 7f3d559226458b4b99e78c17080fd263a913e386 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:34 +0100 Subject: [PATCH 061/513] iplink: bridge: add support for IFLA_BR_MCAST_MEMBERSHIP_INTVL This patch implements support for the IFLA_BR_MCAST_MEMBERSHIP_INTVL attribute in iproute2 so it can change the membership interval. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 9522c3f19..fbac442f4 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -42,6 +42,7 @@ static void print_explain(FILE *f) " [ mcast_last_member_count LAST_MEMBER_COUNT ]\n" " [ mcast_startup_query_count STARTUP_QUERY_COUNT ]\n" " [ mcast_last_member_interval LAST_MEMBER_INTERVAL ]\n" + " [ mcast_membership_interval MEMBERSHIP_INTERVAL ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -232,6 +233,17 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, addattr64(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_INTVL, mcast_last_member_intvl); + } else if (matches(*argv, "mcast_membership_interval") == 0) { + __u64 mcast_membership_intvl; + + NEXT_ARG(); + if (get_u64(&mcast_membership_intvl, *argv, 0)) { + invarg("invalid mcast_membership_interval", + *argv); + return -1; + } + addattr64(n, 1024, IFLA_BR_MCAST_MEMBERSHIP_INTVL, + mcast_membership_intvl); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -405,6 +417,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL]) fprintf(f, "mcast_last_member_interval %llu ", rta_getattr_u64(tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL])); + + if (tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL]) + fprintf(f, "mcast_membership_interval %llu ", + rta_getattr_u64(tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 1f2244b851dd21dd023b43afd902251d39b2d43b Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:35 +0100 Subject: [PATCH 062/513] iplink: bridge: add support for IFLA_BR_MCAST_QUERIER_INTVL This patch implements support for the IFLA_BR_MCAST_QUERIER_INTVL attribute in iproute2 so it can change the querier interval. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index fbac442f4..1138e6ee7 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -43,6 +43,7 @@ static void print_explain(FILE *f) " [ mcast_startup_query_count STARTUP_QUERY_COUNT ]\n" " [ mcast_last_member_interval LAST_MEMBER_INTERVAL ]\n" " [ mcast_membership_interval MEMBERSHIP_INTERVAL ]\n" + " [ mcast_querier_interval QUERIER_INTERVAL ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -244,6 +245,17 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, } addattr64(n, 1024, IFLA_BR_MCAST_MEMBERSHIP_INTVL, mcast_membership_intvl); + } else if (matches(*argv, "mcast_querier_interval") == 0) { + __u64 mcast_querier_intvl; + + NEXT_ARG(); + if (get_u64(&mcast_querier_intvl, *argv, 0)) { + invarg("invalid mcast_querier_interval", + *argv); + return -1; + } + addattr64(n, 1024, IFLA_BR_MCAST_QUERIER_INTVL, + mcast_querier_intvl); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -421,6 +433,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL]) fprintf(f, "mcast_membership_interval %llu ", rta_getattr_u64(tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL])); + + if (tb[IFLA_BR_MCAST_QUERIER_INTVL]) + fprintf(f, "mcast_querier_interval %llu ", + rta_getattr_u64(tb[IFLA_BR_MCAST_QUERIER_INTVL])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 5a32388f5ce730d7df2b512dbe31398e5a027a96 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:36 +0100 Subject: [PATCH 063/513] iplink: bridge: add support for IFLA_BR_MCAST_QUERY_INTVL This patch implements support for the IFLA_BR_MCAST_QUERY_INTVL attribute in iproute2 so it can change the query interval. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 1138e6ee7..16fc0d31c 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -44,6 +44,7 @@ static void print_explain(FILE *f) " [ mcast_last_member_interval LAST_MEMBER_INTERVAL ]\n" " [ mcast_membership_interval MEMBERSHIP_INTERVAL ]\n" " [ mcast_querier_interval QUERIER_INTERVAL ]\n" + " [ mcast_query_interval QUERY_INTERVAL ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -256,6 +257,17 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, } addattr64(n, 1024, IFLA_BR_MCAST_QUERIER_INTVL, mcast_querier_intvl); + } else if (matches(*argv, "mcast_query_interval") == 0) { + __u64 mcast_query_intvl; + + NEXT_ARG(); + if (get_u64(&mcast_query_intvl, *argv, 0)) { + invarg("invalid mcast_query_interval", + *argv); + return -1; + } + addattr64(n, 1024, IFLA_BR_MCAST_QUERY_INTVL, + mcast_query_intvl); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -437,6 +449,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_MCAST_QUERIER_INTVL]) fprintf(f, "mcast_querier_interval %llu ", rta_getattr_u64(tb[IFLA_BR_MCAST_QUERIER_INTVL])); + + if (tb[IFLA_BR_MCAST_QUERY_INTVL]) + fprintf(f, "mcast_query_interval %llu ", + rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_INTVL])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 483df11cf113668116cdc69e076194d0b4e7cc7f Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:37 +0100 Subject: [PATCH 064/513] iplink: bridge: add support for IFLA_BR_MCAST_QUERY_RESPONSE_INTVL This patch implements support for the IFLA_BR_MCAST_QUERY_RESPONSE_INTVL attribute in iproute2 so it can change the query response interval. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 16fc0d31c..92060eeae 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -45,6 +45,7 @@ static void print_explain(FILE *f) " [ mcast_membership_interval MEMBERSHIP_INTERVAL ]\n" " [ mcast_querier_interval QUERIER_INTERVAL ]\n" " [ mcast_query_interval QUERY_INTERVAL ]\n" + " [ mcast_query_response_interval QUERY_RESPONSE_INTERVAL ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -268,6 +269,17 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, } addattr64(n, 1024, IFLA_BR_MCAST_QUERY_INTVL, mcast_query_intvl); + } else if (!matches(*argv, "mcast_query_response_interval")) { + __u64 mcast_query_resp_intvl; + + NEXT_ARG(); + if (get_u64(&mcast_query_resp_intvl, *argv, 0)) { + invarg("invalid mcast_query_response_interval", + *argv); + return -1; + } + addattr64(n, 1024, IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, + mcast_query_resp_intvl); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -453,6 +465,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_MCAST_QUERY_INTVL]) fprintf(f, "mcast_query_interval %llu ", rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_INTVL])); + + if (tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]) + fprintf(f, "mcast_query_response_interval %llu ", + rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 178b18066a871f1bc7e7e91620d4a1ca859bba7c Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:38 +0100 Subject: [PATCH 065/513] iplink: bridge: add support for IFLA_BR_MCAST_STARTUP_QUERY_INTVL This patch implements support for the IFLA_BR_MCAST_STARTUP_QUERY_INTVL attribute in iproute2 so it can change the startup query interval. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 92060eeae..a55a36ada 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -46,6 +46,7 @@ static void print_explain(FILE *f) " [ mcast_querier_interval QUERIER_INTERVAL ]\n" " [ mcast_query_interval QUERY_INTERVAL ]\n" " [ mcast_query_response_interval QUERY_RESPONSE_INTERVAL ]\n" + " [ mcast_startup_query_interval STARTUP_QUERY_INTERVAL ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -280,6 +281,17 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, } addattr64(n, 1024, IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, mcast_query_resp_intvl); + } else if (!matches(*argv, "mcast_startup_query_interval")) { + __u64 mcast_startup_query_intvl; + + NEXT_ARG(); + if (get_u64(&mcast_startup_query_intvl, *argv, 0)) { + invarg("invalid mcast_startup_query_interval", + *argv); + return -1; + } + addattr64(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_INTVL, + mcast_startup_query_intvl); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -469,6 +481,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]) fprintf(f, "mcast_query_response_interval %llu ", rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL])); + + if (tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]) + fprintf(f, "mcast_startup_query_interval %llu ", + rta_getattr_u64(tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From 861c5dae5c5ded3af850324c18d10da525c9f605 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 9 Feb 2016 00:14:39 +0100 Subject: [PATCH 066/513] iplink: bridge: add support for netfilter call attributes This patch implements support for the IFLA_BR_NF_CALL_(IP|IP6|ARP)TABLES attributes in iproute2 so it can change their values. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index a55a36ada..1b666f0ad 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -47,6 +47,9 @@ static void print_explain(FILE *f) " [ mcast_query_interval QUERY_INTERVAL ]\n" " [ mcast_query_response_interval QUERY_RESPONSE_INTERVAL ]\n" " [ mcast_startup_query_interval STARTUP_QUERY_INTERVAL ]\n" + " [ nf_call_iptables NF_CALL_IPTABLES ]\n" + " [ nf_call_ip6tables NF_CALL_IP6TABLES ]\n" + " [ nf_call_arptables NF_CALL_ARPTABLES ]\n" "\n" "Where: VLAN_PROTOCOL := { 802.1Q | 802.1ad }\n" ); @@ -292,6 +295,36 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, } addattr64(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_INTVL, mcast_startup_query_intvl); + } else if (matches(*argv, "nf_call_iptables") == 0) { + __u8 nf_call_ipt; + + NEXT_ARG(); + if (get_u8(&nf_call_ipt, *argv, 0)) { + invarg("invalid nf_call_iptables", *argv); + return -1; + } + addattr8(n, 1024, IFLA_BR_NF_CALL_IPTABLES, + nf_call_ipt); + } else if (matches(*argv, "nf_call_ip6tables") == 0) { + __u8 nf_call_ip6t; + + NEXT_ARG(); + if (get_u8(&nf_call_ip6t, *argv, 0)) { + invarg("invalid nf_call_ip6tables", *argv); + return -1; + } + addattr8(n, 1024, IFLA_BR_NF_CALL_IP6TABLES, + nf_call_ip6t); + } else if (matches(*argv, "nf_call_arptables") == 0) { + __u8 nf_call_arpt; + + NEXT_ARG(); + if (get_u8(&nf_call_arpt, *argv, 0)) { + invarg("invalid nf_call_arptables", *argv); + return -1; + } + addattr8(n, 1024, IFLA_BR_NF_CALL_ARPTABLES, + nf_call_arpt); } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -485,6 +518,18 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]) fprintf(f, "mcast_startup_query_interval %llu ", rta_getattr_u64(tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL])); + + if (tb[IFLA_BR_NF_CALL_IPTABLES]) + fprintf(f, "nf_call_iptables %u ", + rta_getattr_u8(tb[IFLA_BR_NF_CALL_IPTABLES])); + + if (tb[IFLA_BR_NF_CALL_IP6TABLES]) + fprintf(f, "nf_call_ip6tables %u ", + rta_getattr_u8(tb[IFLA_BR_NF_CALL_IP6TABLES])); + + if (tb[IFLA_BR_NF_CALL_ARPTABLES]) + fprintf(f, "nf_call_arptables %u ", + rta_getattr_u8(tb[IFLA_BR_NF_CALL_ARPTABLES])); } static void bridge_print_help(struct link_util *lu, int argc, char **argv, From e6c38e2c59c922229ca615b6f913523dd6ee7c24 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Mon, 8 Feb 2016 17:13:58 +0100 Subject: [PATCH 067/513] iplink: bond_slave: fix ad_actor/partner_oper_port_state output It seems that I've made a mistake when I exported these, instead of a space in the end I've put a newline character which is wrong and breaks the single line output. Fixes: 7d6bc3b87abad ("bonding: export 3ad actor and partner port state") Reported-by: Sam Tannous Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bond_slave.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ip/iplink_bond_slave.c b/ip/iplink_bond_slave.c index 9b569b1da..2f3364ee4 100644 --- a/ip/iplink_bond_slave.c +++ b/ip/iplink_bond_slave.c @@ -80,11 +80,11 @@ static void bond_slave_print_opt(struct link_util *lu, FILE *f, struct rtattr *t rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_AGGREGATOR_ID])); if (tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE]) - fprintf(f, "ad_actor_oper_port_state %d\n", + fprintf(f, "ad_actor_oper_port_state %d ", rta_getattr_u8(tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE])); if (tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE]) - fprintf(f, "ad_partner_oper_port_state %d\n", + fprintf(f, "ad_partner_oper_port_state %d ", rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE])); } From ecc509f9a36be953bc41d926be061b5c34a74e94 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Sun, 7 Feb 2016 16:28:16 -0800 Subject: [PATCH 068/513] ip route: add mpls multipath support This patch adds support to add mpls multipath routes. example: ip -f mpls route add 100 \ nexthop as 200 via inet 10.1.1.2 dev swp1 \ nexthop as 700 via inet 10.1.1.6 dev swp2 Signed-off-by: Roopa Prabhu --- ip/iproute.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/ip/iproute.c b/ip/iproute.c index afe70e123..051fc12d1 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -646,7 +646,13 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) lwt_print_encap(fp, tb[RTA_ENCAP_TYPE], tb[RTA_ENCAP]); - + if (tb[RTA_NEWDST]) { + fprintf(fp, " as to %s ", + format_host(r->rtm_family, + RTA_PAYLOAD(tb[RTA_NEWDST]), + RTA_DATA(tb[RTA_NEWDST]), + abuf, sizeof(abuf))); + } if (tb[RTA_GATEWAY]) { fprintf(fp, " via %s ", format_host(r->rtm_family, @@ -681,7 +687,9 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "(ttl>%d)", nh->rtnh_hops); } else { fprintf(fp, " dev %s", ll_index_to_name(nh->rtnh_ifindex)); - fprintf(fp, " weight %d", nh->rtnh_hops+1); + if (r->rtm_family != AF_MPLS) + fprintf(fp, " weight %d", + nh->rtnh_hops+1); } if (nh->rtnh_flags & RTNH_F_DEAD) fprintf(fp, " dead"); @@ -743,7 +751,7 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r, rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen; } else { rta_addattr_l(rta, 4096, RTA_VIA, &addr.family, addr.bytelen+2); - rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen+2; + rtnh->rtnh_len += RTA_SPACE(addr.bytelen+2); } } else if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); @@ -771,6 +779,16 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r, lwt_parse_encap(rta, 4096, &argc, &argv); rtnh->rtnh_len += rta->rta_len - len; + } else if (strcmp(*argv, "as") == 0) { + inet_prefix addr; + + NEXT_ARG(); + if (strcmp(*argv, "to") == 0) + NEXT_ARG(); + get_addr(&addr, *argv, r->rtm_family); + rta_addattr_l(rta, 4096, RTA_NEWDST, &addr.data, + addr.bytelen); + rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen; } else break; } @@ -881,9 +899,11 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) if (req.r.rtm_family == AF_UNSPEC) req.r.rtm_family = addr.family; if (addr.family == req.r.rtm_family) - addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen); + addattr_l(&req.n, sizeof(req), RTA_GATEWAY, + &addr.data, addr.bytelen); else - addattr_l(&req.n, sizeof(req), RTA_VIA, &addr.family, addr.bytelen+2); + addattr_l(&req.n, sizeof(req), RTA_VIA, + &addr.family, addr.bytelen+2); } else if (strcmp(*argv, "from") == 0) { inet_prefix addr; NEXT_ARG(); From 8593b2cac057d64d0f706d3179eed5493855b8a7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 Feb 2016 10:49:03 -0800 Subject: [PATCH 069/513] Update header files from net-next --- include/linux/bpf.h | 2 ++ include/linux/if_bridge.h | 2 ++ include/linux/if_link.h | 12 ++++++++++++ include/linux/tipc_netlink.h | 1 - 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index f970f9db8..9a3897be4 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -81,6 +81,8 @@ enum bpf_map_type { BPF_MAP_TYPE_ARRAY, BPF_MAP_TYPE_PROG_ARRAY, BPF_MAP_TYPE_PERF_EVENT_ARRAY, + BPF_MAP_TYPE_PERCPU_HASH, + BPF_MAP_TYPE_PERCPU_ARRAY, }; enum bpf_prog_type { diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index ee197a379..7dafc0d12 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -183,6 +183,8 @@ struct br_mdb_entry { #define MDB_TEMPORARY 0 #define MDB_PERMANENT 1 __u8 state; +#define MDB_FLAGS_OFFLOAD (1 << 0) + __u8 flags; __u16 vid; struct { union { diff --git a/include/linux/if_link.h b/include/linux/if_link.h index d91f2c97d..0331c723e 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -35,6 +35,8 @@ struct rtnl_link_stats { /* for cslip etc */ __u32 rx_compressed; __u32 tx_compressed; + + __u32 rx_nohandler; /* dropped, no handler found */ }; /* The main device statistics structure */ @@ -68,6 +70,8 @@ struct rtnl_link_stats64 { /* for cslip etc */ __u64 rx_compressed; __u64 tx_compressed; + + __u64 rx_nohandler; /* dropped, no handler found */ }; /* The struct should be in sync with struct ifmap */ @@ -399,6 +403,14 @@ enum { #define IFLA_VRF_MAX (__IFLA_VRF_MAX - 1) +enum { + IFLA_VRF_PORT_UNSPEC, + IFLA_VRF_PORT_TABLE, + __IFLA_VRF_PORT_MAX +}; + +#define IFLA_VRF_PORT_MAX (__IFLA_VRF_PORT_MAX - 1) + /* IPVLAN section */ enum { IFLA_IPVLAN_UNSPEC, diff --git a/include/linux/tipc_netlink.h b/include/linux/tipc_netlink.h index 25eb645e3..d4c8f142b 100644 --- a/include/linux/tipc_netlink.h +++ b/include/linux/tipc_netlink.h @@ -56,7 +56,6 @@ enum { TIPC_NL_NET_GET, TIPC_NL_NET_SET, TIPC_NL_NAME_TABLE_GET, - TIPC_NL_PEER_REMOVE, __TIPC_NL_CMD_MAX, TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 From 385caeb13b4be08a2a142f28a836e0d535a3d8b9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 Feb 2016 10:51:32 -0800 Subject: [PATCH 070/513] Revert "tipc: add peer remove functionality" This reverts commit f9dec657e4578d50a2432e5842d97c857faa6c2c. Since this code is not in upstream kernel, it shouldn't be in iproute2 --- include/linux/tipc_netlink.h | 1 - man/man8/tipc-bearer.8 | 1 - man/man8/tipc-link.8 | 1 - man/man8/tipc-media.8 | 1 - man/man8/tipc-nametable.8 | 1 - man/man8/tipc-node.8 | 1 - man/man8/tipc-peer.8 | 52 -------------------- man/man8/tipc.8 | 1 - tipc/Makefile | 2 +- tipc/peer.c | 93 ------------------------------------ tipc/peer.h | 21 -------- tipc/tipc.c | 3 -- 12 files changed, 1 insertion(+), 177 deletions(-) delete mode 100644 man/man8/tipc-peer.8 delete mode 100644 tipc/peer.c delete mode 100644 tipc/peer.h diff --git a/include/linux/tipc_netlink.h b/include/linux/tipc_netlink.h index 25eb645e3..d4c8f142b 100644 --- a/include/linux/tipc_netlink.h +++ b/include/linux/tipc_netlink.h @@ -56,7 +56,6 @@ enum { TIPC_NL_NET_GET, TIPC_NL_NET_SET, TIPC_NL_NAME_TABLE_GET, - TIPC_NL_PEER_REMOVE, __TIPC_NL_CMD_MAX, TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 diff --git a/man/man8/tipc-bearer.8 b/man/man8/tipc-bearer.8 index 565ee01d4..50a1ed245 100644 --- a/man/man8/tipc-bearer.8 +++ b/man/man8/tipc-bearer.8 @@ -218,7 +218,6 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-media (8), .BR tipc-nametable (8), .BR tipc-node (8), -.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-link.8 b/man/man8/tipc-link.8 index 2ee03a0bd..3be8c9ad4 100644 --- a/man/man8/tipc-link.8 +++ b/man/man8/tipc-link.8 @@ -213,7 +213,6 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-bearer (8), .BR tipc-nametable (8), .BR tipc-node (8), -.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-media.8 b/man/man8/tipc-media.8 index 4689cb3fa..6c6e2b152 100644 --- a/man/man8/tipc-media.8 +++ b/man/man8/tipc-media.8 @@ -74,7 +74,6 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-link (8), .BR tipc-nametable (8), .BR tipc-node (8), -.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-nametable.8 b/man/man8/tipc-nametable.8 index 4bcefe47f..d3397f97d 100644 --- a/man/man8/tipc-nametable.8 +++ b/man/man8/tipc-nametable.8 @@ -87,7 +87,6 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-link (8), .BR tipc-media (8), .BR tipc-node (8), -.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-node.8 b/man/man8/tipc-node.8 index a72a40991..ef32ec7c8 100644 --- a/man/man8/tipc-node.8 +++ b/man/man8/tipc-node.8 @@ -59,7 +59,6 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-link (8), .BR tipc-media (8), .BR tipc-nametable (8), -.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-peer.8 b/man/man8/tipc-peer.8 deleted file mode 100644 index 430651f7e..000000000 --- a/man/man8/tipc-peer.8 +++ /dev/null @@ -1,52 +0,0 @@ -.TH TIPC-PEER 8 "04 Dec 2015" "iproute2" "Linux" - -.\" For consistency, please keep padding right aligned. -.\" For example '.B "foo " bar' and not '.B foo " bar"' - -.SH NAME -tipc-peer \- modify peer information - -.SH SYNOPSIS -.ad l -.in +8 - -.ti -8 -.B tipc peer remove address -.IR ADDRESS - -.SH OPTIONS -Options (flags) that can be passed anywhere in the command chain. -.TP -.BR "\-h" , " --help" -Show help about last valid command. For example -.B tipc peer --help -will show peer help and -.B tipc --help -will show general help. The position of the option in the string is irrelevant. -.SH DESCRIPTION - -.SS Peer remove -Remove an offline peer node from the local data structures. The peer is -identified by its -.B address - -.SH EXIT STATUS -Exit status is 0 if command was successful or a positive integer upon failure. - -.SH SEE ALSO -.BR tipc (8), -.BR tipc-bearer (8), -.BR tipc-link (8), -.BR tipc-media (8), -.BR tipc-nametable (8), -.BR tipc-node (8), -.BR tipc-socket (8) -.br -.SH REPORTING BUGS -Report any bugs to the Network Developers mailing list -.B -where the development and maintenance is primarily done. -You do not have to be subscribed to the list to send a message there. - -.SH AUTHOR -Richard Alpe diff --git a/man/man8/tipc.8 b/man/man8/tipc.8 index 32943fa50..c11655238 100644 --- a/man/man8/tipc.8 +++ b/man/man8/tipc.8 @@ -87,7 +87,6 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-media (8), .BR tipc-nametable (8), .BR tipc-node (8), -.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/tipc/Makefile b/tipc/Makefile index f06dcb119..bc5ecfd37 100644 --- a/tipc/Makefile +++ b/tipc/Makefile @@ -6,7 +6,7 @@ TIPCOBJ=bearer.o \ media.o misc.o \ msg.o nametable.o \ node.o socket.o \ - peer.o tipc.o + tipc.o include ../Config diff --git a/tipc/peer.c b/tipc/peer.c deleted file mode 100644 index de0c73c31..000000000 --- a/tipc/peer.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * peer.c TIPC peer functionality. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Richard Alpe - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "cmdl.h" -#include "msg.h" -#include "misc.h" -#include "peer.h" - -static int cmd_peer_rm_addr(struct nlmsghdr *nlh, const struct cmd *cmd, - struct cmdl *cmdl, void *data) -{ - char *str; - uint32_t addr; - struct nlattr *nest; - char buf[MNL_SOCKET_BUFFER_SIZE]; - - if ((cmdl->argc != cmdl->optind + 1) || help_flag) { - fprintf(stderr, "Usage: %s peer remove address ADDRESS\n", - cmdl->argv[0]); - return -EINVAL; - } - - str = shift_cmdl(cmdl); - addr = str2addr(str); - if (!addr) - return -1; - - if (!(nlh = msg_init(buf, TIPC_NL_PEER_REMOVE))) { - fprintf(stderr, "error, message initialisation failed\n"); - return -1; - } - - nest = mnl_attr_nest_start(nlh, TIPC_NLA_NET); - mnl_attr_put_u32(nlh, TIPC_NLA_NET_ADDR, addr); - mnl_attr_nest_end(nlh, nest); - - return msg_doit(nlh, NULL, NULL); -} - -static void cmd_peer_rm_help(struct cmdl *cmdl) -{ - fprintf(stderr, "Usage: %s peer remove address ADDRESS\n", - cmdl->argv[0]); -} - -static int cmd_peer_rm(struct nlmsghdr *nlh, const struct cmd *cmd, - struct cmdl *cmdl, void *data) -{ - const struct cmd cmds[] = { - { "address", cmd_peer_rm_addr, cmd_peer_rm_help }, - { NULL } - }; - - return run_cmd(nlh, cmd, cmds, cmdl, NULL); -} - -void cmd_peer_help(struct cmdl *cmdl) -{ - fprintf(stderr, - "Usage: %s peer COMMAND [ARGS] ...\n\n" - "COMMANDS\n" - " remove - Remove an offline peer node\n", - cmdl->argv[0]); -} - -int cmd_peer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, - void *data) -{ - const struct cmd cmds[] = { - { "remove", cmd_peer_rm, cmd_peer_rm_help }, - { NULL } - }; - - return run_cmd(nlh, cmd, cmds, cmdl, NULL); -} diff --git a/tipc/peer.h b/tipc/peer.h deleted file mode 100644 index 897226165..000000000 --- a/tipc/peer.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * peer.h TIPC peer functionality. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Richard Alpe - */ - -#ifndef _TIPC_PEER_H -#define _TIPC_PEER_H - -extern int help_flag; - -int cmd_peer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, - void *data); -void cmd_peer_help(struct cmdl *cmdl); - -#endif diff --git a/tipc/tipc.c b/tipc/tipc.c index 600d5e2a1..44398052a 100644 --- a/tipc/tipc.c +++ b/tipc/tipc.c @@ -20,7 +20,6 @@ #include "socket.h" #include "media.h" #include "node.h" -#include "peer.h" #include "cmdl.h" int help_flag; @@ -40,7 +39,6 @@ static void about(struct cmdl *cmdl) " media - Show or modify media\n" " nametable - Show nametable\n" " node - Show or modify node related parameters\n" - " peer - Peer related operations\n" " socket - Show sockets\n", cmdl->argv[0]); } @@ -61,7 +59,6 @@ int main(int argc, char *argv[]) { "media", cmd_media, cmd_media_help}, { "nametable", cmd_nametable, cmd_nametable_help}, { "node", cmd_node, cmd_node_help}, - { "peer", cmd_peer, cmd_peer_help}, { "socket", cmd_socket, cmd_socket_help}, { NULL } }; From 07ec18341871963028a887cd538dafb7b24f5a9d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 Feb 2016 11:13:31 -0800 Subject: [PATCH 071/513] iplink: display rx nohandler stats Support for the new rx_nohandler statistic. This code is designed to handle the case where the kernel reported statistic structure is smaller than the larger structure in later releases (and vice versa). Signed-off-by: Stephen Hemminger --- ip/ipaddress.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 9d254d27b..c4a8fc354 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -481,7 +481,8 @@ static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s, /* RX error stats */ if (show_stats > 1) { fprintf(fp, "%s", _SL_); - fprintf(fp, " RX errors: length crc frame fifo missed%s", _SL_); + fprintf(fp, " RX errors: length crc frame fifo missed%s%s", + s->rx_nohandler ? " nohandler" : "", _SL_); fprintf(fp, " "); print_num(fp, 8, s->rx_length_errors); @@ -489,6 +490,9 @@ static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s, print_num(fp, 7, s->rx_frame_errors); print_num(fp, 7, s->rx_fifo_errors); print_num(fp, 7, s->rx_missed_errors); + if (s->rx_nohandler) + print_num(fp, 7, s->rx_nohandler); + } fprintf(fp, "%s", _SL_); @@ -496,7 +500,6 @@ static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s, fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s", s->tx_compressed ? "compressed" : "", _SL_); - fprintf(fp, " "); print_num(fp, 10, s->tx_bytes); print_num(fp, 8, s->tx_packets); @@ -546,13 +549,16 @@ static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s, /* RX error stats */ if (show_stats > 1) { fprintf(fp, "%s", _SL_); - fprintf(fp, " RX errors: length crc frame fifo missed%s", _SL_); + fprintf(fp, " RX errors: length crc frame fifo missed%s%s", + s->rx_nohandler ? " nohandler" : "", _SL_); fprintf(fp, " "); print_num(fp, 8, s->rx_length_errors); print_num(fp, 7, s->rx_crc_errors); print_num(fp, 7, s->rx_frame_errors); print_num(fp, 7, s->rx_fifo_errors); print_num(fp, 7, s->rx_missed_errors); + if (s->rx_nohandler) + print_num(fp, 7, s->rx_nohandler); } fprintf(fp, "%s", _SL_); @@ -590,12 +596,23 @@ static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s, static void __print_link_stats(FILE *fp, struct rtattr **tb) { - if (tb[IFLA_STATS64]) - print_link_stats64(fp, RTA_DATA(tb[IFLA_STATS64]), - tb[IFLA_CARRIER_CHANGES]); - else if (tb[IFLA_STATS]) - print_link_stats32(fp, RTA_DATA(tb[IFLA_STATS]), - tb[IFLA_CARRIER_CHANGES]); + const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES]; + + if (tb[IFLA_STATS64]) { + struct rtnl_link_stats64 stats = { 0 }; + + memcpy(&stats, RTA_DATA(tb[IFLA_STATS64]), + MIN(RTA_PAYLOAD(tb[IFLA_STATS64]), sizeof(stats))); + + print_link_stats64(fp, &stats, carrier_changes); + } else if (tb[IFLA_STATS]) { + struct rtnl_link_stats stats = { 0 }; + + memcpy(&stats, RTA_DATA(tb[IFLA_STATS]), + MIN(RTA_PAYLOAD(tb[IFLA_STATS]), sizeof(stats))); + + print_link_stats32(fp, &stats, carrier_changes); + } } static void print_link_stats(FILE *fp, struct nlmsghdr *n) From a1b4a274d4917be06b3060d3c8e95aba5c92a9a9 Mon Sep 17 00:00:00 2001 From: Nicolas Cavallari Date: Fri, 12 Feb 2016 14:47:39 +0100 Subject: [PATCH 072/513] netns: Fix an off-by-one strcpy() in netns_map_add(). netns_map_add() does a malloc of (sizeof (struct nsid_cache) + strlen(name)) and then proceed with strcpy() of name into the zero-length member at the end of the nsid_cache structure. The nul-terminator is written outside of the allocated memory and may overwrite the allocator's internal structure. This can trigger a segmentation fault on i386 uclibc with names of size 8: after the corruption occurs, the call to closedir() on netns_map_init() crashes while freeing the DIR structure. Here is the relevant valgrind output: ==1251== Memcheck, a memory error detector ==1251== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==1251== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info ==1251== Command: ./ip netns ==1251== ==1251== Invalid write of size 1 ==1251== at 0x4011975: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) ==1251== by 0x8058B00: netns_map_add (ipnetns.c:181) ==1251== by 0x8058E2A: netns_map_init (ipnetns.c:226) ==1251== by 0x8058E79: do_netns (ipnetns.c:776) ==1251== by 0x804D9FF: do_cmd (ip.c:110) ==1251== by 0x804D814: main (ip.c:300) --- ip/ipnetns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/ipnetns.c b/ip/ipnetns.c index 088096f64..4ce598998 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -172,7 +172,7 @@ static int netns_map_add(int nsid, const char *name) if (netns_map_get_by_nsid(nsid) != NULL) return -EEXIST; - c = malloc(sizeof(*c) + strlen(name)); + c = malloc(sizeof(*c) + strlen(name) + 1); if (c == NULL) { perror("malloc"); return -ENOMEM; From 9e99e49528d4dde8e0ba30b493a553b563925f76 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 17 Feb 2016 17:43:59 -0800 Subject: [PATCH 073/513] ss: display not_sent and min_rtt info Display new info from net-next kernel. Signed-off-by: Stephen Hemminger --- include/linux/genetlink.h | 1 + include/linux/tcp.h | 3 +++ misc/ss.c | 8 ++++++++ 3 files changed, 12 insertions(+) diff --git a/include/linux/genetlink.h b/include/linux/genetlink.h index 8a1d5006e..e79209260 100644 --- a/include/linux/genetlink.h +++ b/include/linux/genetlink.h @@ -21,6 +21,7 @@ struct genlmsghdr { #define GENL_CMD_CAP_DO 0x02 #define GENL_CMD_CAP_DUMP 0x04 #define GENL_CMD_CAP_HASPOL 0x08 +#define GENL_UNS_ADMIN_PERM 0x10 /* * List of reserved static generic netlink identifiers: diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 1e9b4a627..55d656756 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -196,6 +196,9 @@ struct tcp_info { __u64 tcpi_bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived */ __u32 tcpi_segs_out; /* RFC4898 tcpEStatsPerfSegsOut */ __u32 tcpi_segs_in; /* RFC4898 tcpEStatsPerfSegsIn */ + + __u32 tcpi_notsent_bytes; + __u32 tcpi_min_rtt; }; /* for TCP_MD5SIG socket option */ diff --git a/misc/ss.c b/misc/ss.c index 13fcc8f66..f0f590263 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -778,7 +778,9 @@ struct tcpstat unsigned int sacked; unsigned int fackets; unsigned int reordering; + unsigned int not_sent; double rcv_rtt; + double min_rtt; int rcv_space; bool has_ts_opt; bool has_sack_opt; @@ -1737,6 +1739,10 @@ static void tcp_stats_print(struct tcpstat *s) printf(" rcv_rtt:%g", s->rcv_rtt); if (s->rcv_space) printf(" rcv_space:%d", s->rcv_space); + if (s->not_sent) + printf(" notsent:%u", s->not_sent); + if (s->min_rtt) + printf(" minrtt:%g", s->min_rtt); } static void tcp_timer_print(struct tcpstat *s) @@ -1990,6 +1996,8 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, s.bytes_received = info->tcpi_bytes_received; s.segs_out = info->tcpi_segs_out; s.segs_in = info->tcpi_segs_in; + s.not_sent = info->tcpi_notsent_bytes; + s.min_rtt = (double) info->tcpi_min_rtt / 1000; tcp_stats_print(&s); free(s.dctcp); } From 33e41670d79aca1a39ba535ee37aefd1437829e4 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 2 Feb 2016 07:43:46 -0800 Subject: [PATCH 074/513] vrf: Add support for slave_info Print VRF slave_info attributes if present. Signed-off-by: David Ahern --- ip/iplink_vrf.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/ip/iplink_vrf.c b/ip/iplink_vrf.c index 9b4b7728c..abc796886 100644 --- a/ip/iplink_vrf.c +++ b/ip/iplink_vrf.c @@ -64,6 +64,18 @@ static void vrf_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fprintf(f, "table %u ", rta_getattr_u32(tb[IFLA_VRF_TABLE])); } +static void vrf_slave_print_opt(struct link_util *lu, FILE *f, + struct rtattr *tb[]) +{ + if (!tb) + return; + + if (tb[IFLA_VRF_PORT_TABLE]) { + fprintf(f, "table %u ", + rta_getattr_u32(tb[IFLA_VRF_PORT_TABLE])); + } +} + static void vrf_print_help(struct link_util *lu, int argc, char **argv, FILE *f) { @@ -77,3 +89,10 @@ struct link_util vrf_link_util = { .print_opt = vrf_print_opt, .print_help = vrf_print_help, }; + +struct link_util vrf_slave_link_util = { + .id = "vrf", + .maxattr = IFLA_VRF_PORT_MAX, + .print_opt = vrf_slave_print_opt, + .slave = true, +}; From 3069539fb8efd8353d46a6be1a501f77871888ca Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 16 Feb 2016 16:08:51 +0100 Subject: [PATCH 075/513] iplink: bridge_slave: export read-only values Export all the read-only values that get returned about a bridge port such as the timers, the ids, designated_port and cost, topology_change_ack and config_pending. For the bridge ids the br_dump_bridge_id function is exported from iplink_bridge. Signed-off-by: Nikolay Aleksandrov --- ip/ip_common.h | 2 ++ ip/iplink_bridge.c | 3 +- ip/iplink_bridge_slave.c | 70 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/ip/ip_common.h b/ip/ip_common.h index 9a846df34..815487a07 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -87,6 +87,8 @@ struct link_util struct link_util *get_link_kind(const char *kind); struct link_util *get_link_slave_kind(const char *slave_kind); +void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len); + #ifndef INFINITY_LIFE_TIME #define INFINITY_LIFE_TIME 0xFFFFFFFFU #endif diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 1b666f0ad..79f15eff7 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -60,8 +60,7 @@ static void explain(void) print_explain(stderr); } -static void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, - size_t len) +void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len) { char eaddr[32]; diff --git a/ip/iplink_bridge_slave.c b/ip/iplink_bridge_slave.c index 4593872ec..c58f55294 100644 --- a/ip/iplink_bridge_slave.c +++ b/ip/iplink_bridge_slave.c @@ -98,6 +98,76 @@ static void bridge_slave_print_opt(struct link_util *lu, FILE *f, if (tb[IFLA_BRPORT_UNICAST_FLOOD]) print_onoff(f, "flood", rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD])); + + if (tb[IFLA_BRPORT_ID]) + fprintf(f, "port_id 0x%x ", + rta_getattr_u16(tb[IFLA_BRPORT_ID])); + + if (tb[IFLA_BRPORT_NO]) + fprintf(f, "port_no 0x%x ", + rta_getattr_u16(tb[IFLA_BRPORT_NO])); + + if (tb[IFLA_BRPORT_DESIGNATED_PORT]) + fprintf(f, "designated_port %u ", + rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_PORT])); + + if (tb[IFLA_BRPORT_DESIGNATED_COST]) + fprintf(f, "designated_cost %u ", + rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_COST])); + + if (tb[IFLA_BRPORT_BRIDGE_ID]) { + char bridge_id[32]; + + br_dump_bridge_id(RTA_DATA(tb[IFLA_BRPORT_BRIDGE_ID]), + bridge_id, sizeof(bridge_id)); + fprintf(f, "designated_bridge %s ", bridge_id); + } + + if (tb[IFLA_BRPORT_ROOT_ID]) { + char root_id[32]; + + br_dump_bridge_id(RTA_DATA(tb[IFLA_BRPORT_ROOT_ID]), + root_id, sizeof(root_id)); + fprintf(f, "designated_root %s ", root_id); + } + + if (tb[IFLA_BRPORT_HOLD_TIMER]) { + struct timeval tv; + __u64 htimer; + + htimer = rta_getattr_u64(tb[IFLA_BRPORT_HOLD_TIMER]); + __jiffies_to_tv(&tv, htimer); + fprintf(f, "hold_timer %4i.%.2i ", (int)tv.tv_sec, + (int)tv.tv_usec/10000); + } + + if (tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]) { + struct timeval tv; + __u64 agetimer; + + agetimer = rta_getattr_u64(tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]); + __jiffies_to_tv(&tv, agetimer); + fprintf(f, "message_age_timer %4i.%.2i ", (int)tv.tv_sec, + (int)tv.tv_usec/10000); + } + + if (tb[IFLA_BRPORT_FORWARD_DELAY_TIMER]) { + struct timeval tv; + __u64 fwdtimer; + + fwdtimer = rta_getattr_u64(tb[IFLA_BRPORT_FORWARD_DELAY_TIMER]); + __jiffies_to_tv(&tv, fwdtimer); + fprintf(f, "forward_delay_timer %4i.%.2i ", (int)tv.tv_sec, + (int)tv.tv_usec/10000); + } + + if (tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK]) + fprintf(f, "topology_change_ack %u ", + rta_getattr_u8(tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK])); + + if (tb[IFLA_BRPORT_CONFIG_PENDING]) + fprintf(f, "config_pending %u ", + rta_getattr_u8(tb[IFLA_BRPORT_CONFIG_PENDING])); } static void bridge_slave_parse_on_off(char *arg_name, char *arg_val, From f6e615dec9ee9b688308e85a03a51125a9c9fdb9 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 16 Feb 2016 16:08:52 +0100 Subject: [PATCH 076/513] iplink: bridge_slave: add support for IFLA_BRPORT_PROXYARP Add support to be able to view and change IFLA_BRPORT_PROXYARP port attribute. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge_slave.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ip/iplink_bridge_slave.c b/ip/iplink_bridge_slave.c index c58f55294..c27d71837 100644 --- a/ip/iplink_bridge_slave.c +++ b/ip/iplink_bridge_slave.c @@ -29,6 +29,7 @@ static void print_explain(FILE *f) " [ root_block {on | off} ]\n" " [ learning {on | off} ]\n" " [ flood {on | off} ]\n" + " [ proxy_arp {on | off} ]\n" ); } @@ -168,6 +169,9 @@ static void bridge_slave_print_opt(struct link_util *lu, FILE *f, if (tb[IFLA_BRPORT_CONFIG_PENDING]) fprintf(f, "config_pending %u ", rta_getattr_u8(tb[IFLA_BRPORT_CONFIG_PENDING])); + if (tb[IFLA_BRPORT_PROXYARP]) + print_onoff(f, "proxy_arp", + rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP])); } static void bridge_slave_parse_on_off(char *arg_name, char *arg_val, @@ -232,6 +236,10 @@ static int bridge_slave_parse_opt(struct link_util *lu, int argc, char **argv, NEXT_ARG(); bridge_slave_parse_on_off("flood", *argv, n, IFLA_BRPORT_UNICAST_FLOOD); + } else if (matches(*argv, "proxy_arp") == 0) { + NEXT_ARG(); + bridge_slave_parse_on_off("proxy_arp", *argv, n, + IFLA_BRPORT_PROXYARP); } else if (matches(*argv, "help") == 0) { explain(); return -1; From 38b31a78da859e4b72037b66477871ba8fc7bd1e Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 16 Feb 2016 16:08:53 +0100 Subject: [PATCH 077/513] iplink: bridge_slave: add support for IFLA_BRPORT_PROXYARP_WIFI Add support to be able to view and change IFLA_BRPORT_PROXYARP_WIFI port attribute. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge_slave.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ip/iplink_bridge_slave.c b/ip/iplink_bridge_slave.c index c27d71837..68d140894 100644 --- a/ip/iplink_bridge_slave.c +++ b/ip/iplink_bridge_slave.c @@ -30,6 +30,7 @@ static void print_explain(FILE *f) " [ learning {on | off} ]\n" " [ flood {on | off} ]\n" " [ proxy_arp {on | off} ]\n" + " [ proxy_arp_wifi {on | off} ]\n" ); } @@ -172,6 +173,10 @@ static void bridge_slave_print_opt(struct link_util *lu, FILE *f, if (tb[IFLA_BRPORT_PROXYARP]) print_onoff(f, "proxy_arp", rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP])); + + if (tb[IFLA_BRPORT_PROXYARP_WIFI]) + print_onoff(f, "proxy_arp_wifi", + rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP_WIFI])); } static void bridge_slave_parse_on_off(char *arg_name, char *arg_val, @@ -240,6 +245,10 @@ static int bridge_slave_parse_opt(struct link_util *lu, int argc, char **argv, NEXT_ARG(); bridge_slave_parse_on_off("proxy_arp", *argv, n, IFLA_BRPORT_PROXYARP); + } else if (matches(*argv, "proxy_arp_wifi") == 0) { + NEXT_ARG(); + bridge_slave_parse_on_off("proxy_arp_wifi", *argv, n, + IFLA_BRPORT_PROXYARP_WIFI); } else if (matches(*argv, "help") == 0) { explain(); return -1; From 10759a90ab5896b5b0ca8ddd7b91c5b3a7466062 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 16 Feb 2016 16:08:54 +0100 Subject: [PATCH 078/513] iplink: bridge_slave: add support for IFLA_BRPORT_MULTICAST_ROUTER Add support to be able to view and change IFLA_BRPORT_MULTICAST_ROUTER port attribute. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge_slave.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ip/iplink_bridge_slave.c b/ip/iplink_bridge_slave.c index 68d140894..16b364f6b 100644 --- a/ip/iplink_bridge_slave.c +++ b/ip/iplink_bridge_slave.c @@ -31,6 +31,7 @@ static void print_explain(FILE *f) " [ flood {on | off} ]\n" " [ proxy_arp {on | off} ]\n" " [ proxy_arp_wifi {on | off} ]\n" + " [ mcast_router MULTICAST_ROUTER ]\n" ); } @@ -177,6 +178,10 @@ static void bridge_slave_print_opt(struct link_util *lu, FILE *f, if (tb[IFLA_BRPORT_PROXYARP_WIFI]) print_onoff(f, "proxy_arp_wifi", rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP_WIFI])); + + if (tb[IFLA_BRPORT_MULTICAST_ROUTER]) + fprintf(f, "mcast_router %u ", + rta_getattr_u8(tb[IFLA_BRPORT_MULTICAST_ROUTER])); } static void bridge_slave_parse_on_off(char *arg_name, char *arg_val, @@ -249,6 +254,14 @@ static int bridge_slave_parse_opt(struct link_util *lu, int argc, char **argv, NEXT_ARG(); bridge_slave_parse_on_off("proxy_arp_wifi", *argv, n, IFLA_BRPORT_PROXYARP_WIFI); + } else if (matches(*argv, "mcast_router") == 0) { + __u8 mcast_router; + + NEXT_ARG(); + if (get_u8(&mcast_router, *argv, 0)) + invarg("invalid mcast_router", *argv); + addattr8(n, 1024, IFLA_BRPORT_MULTICAST_ROUTER, + mcast_router); } else if (matches(*argv, "help") == 0) { explain(); return -1; From 478a8e59206841b2a2d32a29fdd0cbec1965cd5e Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Tue, 16 Feb 2016 16:08:55 +0100 Subject: [PATCH 079/513] iplink: bridge_slave: add support for IFLA_BRPORT_FAST_LEAVE Add support to be able to view and change IFLA_BRPORT_FAST_LEAVE port attribute. Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge_slave.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ip/iplink_bridge_slave.c b/ip/iplink_bridge_slave.c index 16b364f6b..3ec2bba72 100644 --- a/ip/iplink_bridge_slave.c +++ b/ip/iplink_bridge_slave.c @@ -32,6 +32,7 @@ static void print_explain(FILE *f) " [ proxy_arp {on | off} ]\n" " [ proxy_arp_wifi {on | off} ]\n" " [ mcast_router MULTICAST_ROUTER ]\n" + " [ mcast_fast_leave {on | off} ]\n" ); } @@ -182,6 +183,10 @@ static void bridge_slave_print_opt(struct link_util *lu, FILE *f, if (tb[IFLA_BRPORT_MULTICAST_ROUTER]) fprintf(f, "mcast_router %u ", rta_getattr_u8(tb[IFLA_BRPORT_MULTICAST_ROUTER])); + + if (tb[IFLA_BRPORT_FAST_LEAVE]) + print_onoff(f, "mcast_fast_leave", + rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE])); } static void bridge_slave_parse_on_off(char *arg_name, char *arg_val, @@ -262,6 +267,10 @@ static int bridge_slave_parse_opt(struct link_util *lu, int argc, char **argv, invarg("invalid mcast_router", *argv); addattr8(n, 1024, IFLA_BRPORT_MULTICAST_ROUTER, mcast_router); + } else if (matches(*argv, "mcast_fast_leave") == 0) { + NEXT_ARG(); + bridge_slave_parse_on_off("mcast_fast_leave", *argv, n, + IFLA_BRPORT_FAST_LEAVE); } else if (matches(*argv, "help") == 0) { explain(); return -1; From 1aea7fea262c3ce72febc84934719a51d74d93a1 Mon Sep 17 00:00:00 2001 From: Dmitrii Shcherbakov Date: Sat, 19 Dec 2015 18:25:52 +0300 Subject: [PATCH 080/513] htb: remove printing of a deprecated overhead value Remove printing according to the previously used encoding of mpu and overhead values within the tc_ratespec's mpu field. This encoding is no longer being used as a separate 'overhead' field in the ratespec structure has been introduced. Signed-off-by: Dmitrii Shcherbakov Acked-by: Jesper Dangaard Brouer Acked-by: Phil Sutter --- tc/q_htb.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tc/q_htb.c b/tc/q_htb.c index 7075a4c00..e76d20a40 100644 --- a/tc/q_htb.c +++ b/tc/q_htb.c @@ -273,7 +273,6 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) __u64 rate64, ceil64; SPRINT_BUF(b1); SPRINT_BUF(b2); - SPRINT_BUF(b3); SPRINT_BUF(b4); if (opt == NULL) @@ -313,16 +312,14 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (linklayer > TC_LINKLAYER_ETHERNET || show_details) fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b4)); if (show_details) { - fprintf(f, "burst %s/%u mpu %s overhead %s ", + fprintf(f, "burst %s/%u mpu %s ", sprint_size(buffer, b1), 1<rate.cell_log, - sprint_size(hopt->rate.mpu&0xFF, b2), - sprint_size((hopt->rate.mpu>>8)&0xFF, b3)); - fprintf(f, "cburst %s/%u mpu %s overhead %s ", + sprint_size(hopt->rate.mpu, b2)); + fprintf(f, "cburst %s/%u mpu %s ", sprint_size(cbuffer, b1), 1<ceil.cell_log, - sprint_size(hopt->ceil.mpu&0xFF, b2), - sprint_size((hopt->ceil.mpu>>8)&0xFF, b3)); + sprint_size(hopt->ceil.mpu, b2)); fprintf(f, "level %d ", (int)hopt->level); } else { fprintf(f, "burst %s ", sprint_size(buffer, b1)); From 467f9fce60ebd66d02b81b4c9c6aa9ca2f5ccdbd Mon Sep 17 00:00:00 2001 From: Dmitrii Shcherbakov Date: Sat, 19 Dec 2015 18:26:03 +0300 Subject: [PATCH 081/513] htb: rename b4 buffer to b3 to make its name more consistent b3 buffer has been deleted previously so b2 is followed by b4 which is not consistent. Signed-off-by: Dmitrii Shcherbakov Acked-by: Jesper Dangaard Brouer Acked-by: Phil Sutter --- tc/q_htb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tc/q_htb.c b/tc/q_htb.c index e76d20a40..7d5409085 100644 --- a/tc/q_htb.c +++ b/tc/q_htb.c @@ -273,7 +273,7 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) __u64 rate64, ceil64; SPRINT_BUF(b1); SPRINT_BUF(b2); - SPRINT_BUF(b4); + SPRINT_BUF(b3); if (opt == NULL) return 0; @@ -310,7 +310,7 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) cbuffer = tc_calc_xmitsize(ceil64, hopt->cbuffer); linklayer = (hopt->rate.linklayer & TC_LINKLAYER_MASK); if (linklayer > TC_LINKLAYER_ETHERNET || show_details) - fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b4)); + fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b3)); if (show_details) { fprintf(f, "burst %s/%u mpu %s ", sprint_size(buffer, b1), From c6d0cfb54b8b467a57d259f5c9cec91f94f4e59e Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Fri, 19 Feb 2016 21:34:52 -0800 Subject: [PATCH 082/513] bridge: add support for dynamic fdb entries This patch is a follow up to the recently added 'static' fdb option. It introduces a new option 'dynamic' which adds dynamic fdb entries with NUD_REACHABLE. $bridge fdb add 00:01:02:03:04:06 dev eth0 master dynamic $bridge fdb show 00:01:02:03:04:06 dev eth0 This patch also documents all fdb types. Removes 'temp' from usage message since it is now replaced by 'static'. 'temp' still works and is synonymous with static. Signed-off-by: Wilson Kok Signed-off-by: Roopa Prabhu --- bridge/fdb.c | 5 ++++- man/man8/bridge.8 | 14 +++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/bridge/fdb.c b/bridge/fdb.c index 9bc6b942a..1400b654d 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -33,7 +33,7 @@ static void usage(void) { fprintf(stderr, "Usage: bridge fdb { add | append | del | replace } ADDR dev DEV\n" " [ self ] [ master ] [ use ] [ router ]\n" - " [ local | temp | static ] [ dst IPADDR ] [ vlan VID ]\n" + " [ local | static | dynamic ] [ dst IPADDR ] [ vlan VID ]\n" " [ port PORT] [ vni VNI ] [ via DEV ]\n"); fprintf(stderr, " bridge fdb [ show [ br BRDEV ] [ brport DEV ] ]\n"); exit(-1); @@ -304,6 +304,9 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv) } else if (matches(*argv, "temp") == 0 || matches(*argv, "static") == 0) { req.ndm.ndm_state |= NUD_REACHABLE; + } else if (matches(*argv, "dynamic") == 0) { + req.ndm.ndm_state |= NUD_REACHABLE; + req.ndm.ndm_state &= ~NUD_NOARP; } else if (matches(*argv, "vlan") == 0) { if (vid >= 0) duparg2("vlan", *argv); diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index 0ec6f1747..efd416e71 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -54,7 +54,7 @@ bridge \- show / manipulate bridge addresses and devices .I LLADDR .B dev .IR DEV " { " -.BR local " | " temp " } [ " +.BR local " | " static " | " dynamic " } [ " .BR self " ] [ " master " ] [ " router " ] [ " use " ] [ " .B dst .IR IPADDR " ] [ " @@ -338,6 +338,18 @@ the Ethernet MAC address. .BI dev " DEV" the interface to which this address is associated. +.B local +- is a local permanent fdb entry +.sp + +.B static +- is a static (no arp) fdb entry +.sp + +.B dynamic +- is a dynamic reachable age-able fdb entry +.sp + .B self - the address is associated with the port drivers fdb. Usually hardware. .sp From 8a4cd3943fb8498a108f0d494bb3176deb01ab0f Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Thu, 18 Feb 2016 20:54:34 +0100 Subject: [PATCH 083/513] iplink: bridge: remove unnecessary returns invarg exits so no need to return, remove this c&p error from my recent patches Signed-off-by: Nikolay Aleksandrov --- ip/iplink_bridge.c | 50 +++++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 79f15eff7..d2d420266 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -116,19 +116,17 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, __u8 vlan_filter; NEXT_ARG(); - if (get_u8(&vlan_filter, *argv, 0)) { + if (get_u8(&vlan_filter, *argv, 0)) invarg("invalid vlan_filtering", *argv); - return -1; - } + addattr8(n, 1024, IFLA_BR_VLAN_FILTERING, vlan_filter); } else if (matches(*argv, "vlan_protocol") == 0) { __u16 vlan_proto; NEXT_ARG(); - if (ll_proto_a2n(&vlan_proto, *argv)) { + if (ll_proto_a2n(&vlan_proto, *argv)) invarg("invalid vlan_protocol", *argv); - return -1; - } + addattr16(n, 1024, IFLA_BR_VLAN_PROTOCOL, vlan_proto); } else if (matches(*argv, "group_fwd_mask") == 0) { __u16 fwd_mask; @@ -243,85 +241,77 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv, __u64 mcast_membership_intvl; NEXT_ARG(); - if (get_u64(&mcast_membership_intvl, *argv, 0)) { + if (get_u64(&mcast_membership_intvl, *argv, 0)) invarg("invalid mcast_membership_interval", *argv); - return -1; - } + addattr64(n, 1024, IFLA_BR_MCAST_MEMBERSHIP_INTVL, mcast_membership_intvl); } else if (matches(*argv, "mcast_querier_interval") == 0) { __u64 mcast_querier_intvl; NEXT_ARG(); - if (get_u64(&mcast_querier_intvl, *argv, 0)) { + if (get_u64(&mcast_querier_intvl, *argv, 0)) invarg("invalid mcast_querier_interval", *argv); - return -1; - } + addattr64(n, 1024, IFLA_BR_MCAST_QUERIER_INTVL, mcast_querier_intvl); } else if (matches(*argv, "mcast_query_interval") == 0) { __u64 mcast_query_intvl; NEXT_ARG(); - if (get_u64(&mcast_query_intvl, *argv, 0)) { + if (get_u64(&mcast_query_intvl, *argv, 0)) invarg("invalid mcast_query_interval", *argv); - return -1; - } + addattr64(n, 1024, IFLA_BR_MCAST_QUERY_INTVL, mcast_query_intvl); } else if (!matches(*argv, "mcast_query_response_interval")) { __u64 mcast_query_resp_intvl; NEXT_ARG(); - if (get_u64(&mcast_query_resp_intvl, *argv, 0)) { + if (get_u64(&mcast_query_resp_intvl, *argv, 0)) invarg("invalid mcast_query_response_interval", *argv); - return -1; - } + addattr64(n, 1024, IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, mcast_query_resp_intvl); } else if (!matches(*argv, "mcast_startup_query_interval")) { __u64 mcast_startup_query_intvl; NEXT_ARG(); - if (get_u64(&mcast_startup_query_intvl, *argv, 0)) { + if (get_u64(&mcast_startup_query_intvl, *argv, 0)) invarg("invalid mcast_startup_query_interval", *argv); - return -1; - } + addattr64(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_INTVL, mcast_startup_query_intvl); } else if (matches(*argv, "nf_call_iptables") == 0) { __u8 nf_call_ipt; NEXT_ARG(); - if (get_u8(&nf_call_ipt, *argv, 0)) { + if (get_u8(&nf_call_ipt, *argv, 0)) invarg("invalid nf_call_iptables", *argv); - return -1; - } + addattr8(n, 1024, IFLA_BR_NF_CALL_IPTABLES, nf_call_ipt); } else if (matches(*argv, "nf_call_ip6tables") == 0) { __u8 nf_call_ip6t; NEXT_ARG(); - if (get_u8(&nf_call_ip6t, *argv, 0)) { + if (get_u8(&nf_call_ip6t, *argv, 0)) invarg("invalid nf_call_ip6tables", *argv); - return -1; - } + addattr8(n, 1024, IFLA_BR_NF_CALL_IP6TABLES, nf_call_ip6t); } else if (matches(*argv, "nf_call_arptables") == 0) { __u8 nf_call_arpt; NEXT_ARG(); - if (get_u8(&nf_call_arpt, *argv, 0)) { + if (get_u8(&nf_call_arpt, *argv, 0)) invarg("invalid nf_call_arptables", *argv); - return -1; - } + addattr8(n, 1024, IFLA_BR_NF_CALL_ARPTABLES, nf_call_arpt); } else if (matches(*argv, "help") == 0) { From b6d77d9ee312246146e9b5ca70a8a1426898b484 Mon Sep 17 00:00:00 2001 From: Hiroshi Shimamoto Date: Fri, 26 Feb 2016 02:40:18 +0000 Subject: [PATCH 084/513] iplink: Support VF Trust Add IFLA_VF_TRUST message to trust the VF. PF can accept some privileged operation from the trusted VF. For example, ixgbe PF doesn't allow to enable VF promiscuous mode until the VF is trusted because it may hurt performance. To trust VF. # ip link set dev eth0 vf 1 trust on To untrust VF. # ip link set dev eth0 vf 1 trust off Signed-off-by: Hiroshi Shimamoto --- ip/iplink.c | 13 +++++++++++++ man/man8/ip-link.8.in | 7 ++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ip/iplink.c b/ip/iplink.c index 5ab9d613c..69f505726 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -82,6 +82,7 @@ void iplink_usage(void) fprintf(stderr, " [ spoofchk { on | off} ] ]\n"); fprintf(stderr, " [ query_rss { on | off} ] ]\n"); fprintf(stderr, " [ state { auto | enable | disable} ] ]\n"); + fprintf(stderr, " [ trust { on | off} ] ]\n"); fprintf(stderr, " [ master DEVICE ]\n"); fprintf(stderr, " [ nomaster ]\n"); fprintf(stderr, " [ addrgenmode { eui64 | none | stable_secret | random } ]\n"); @@ -356,6 +357,18 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, ivs.vf = vf; addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(ivs)); + } else if (matches(*argv, "trust") == 0) { + struct ifla_vf_trust ivt; + NEXT_ARG(); + if (matches(*argv, "on") == 0) + ivt.setting = 1; + else if (matches(*argv, "off") == 0) + ivt.setting = 0; + else + invarg("Invalid \"trust\" value\n", *argv); + ivt.vf = vf; + addattr_l(&req->n, sizeof(*req), IFLA_VF_TRUST, &ivt, sizeof(ivt)); + } else if (matches(*argv, "state") == 0) { struct ifla_vf_link_state ivl; diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 4d3234352..221831e52 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -142,7 +142,8 @@ ip-link \- network device configuration .B min_tx_rate .IR TXRATE " ] [" .B spoofchk { on | off } ] [ -.B state { auto | enable | disable} +.B state { auto | enable | disable} ] [ +.B trust { on | off } ] | .br .B master @@ -1019,6 +1020,10 @@ parameter must be specified. reflection of the PF link state, enable lets the VF to communicate with other VFs on this host even if the PF link state is down, disable causes the HW to drop any packets sent by the VF. +.sp +.BI trust " on|off" +- trust the specified VF user. This enables that VF user can set a specific feature +which may impact security and/or performance. (e.g. VF multicast promiscuous mode) .in -8 .TP From 67eedcd9a145f30aa0a185b7235f01b66349effe Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 25 Feb 2016 13:07:35 +0100 Subject: [PATCH 085/513] iprule: Align help text with man page synopsis The help text was misleading: One could think it is possible to list rules by selector, which would be nice but isn't. This change also clarifies that 'ip rule' defaults to 'list' if no further arguments are given. Signed-off-by: Phil Sutter --- ip/iprule.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ip/iprule.c b/ip/iprule.c index 9923b8eb0..33b71976e 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -33,8 +33,9 @@ static void usage(void) __attribute__((noreturn)); static void usage(void) { - fprintf(stderr, "Usage: ip rule [ list | add | del | flush | save ] SELECTOR ACTION\n"); - fprintf(stderr, " ip rule restore\n"); + fprintf(stderr, "Usage: ip rule { add | del } SELECTOR ACTION\n"); + fprintf(stderr, " ip rule { flush | save | restore }\n"); + fprintf(stderr, " ip rule [ list ]\n"); fprintf(stderr, "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n"); fprintf(stderr, " [ iif STRING ] [ oif STRING ] [ pref NUMBER ]\n"); fprintf(stderr, "ACTION := [ table TABLE_ID ]\n"); From 2421ab750a11a0800f693a682a6dff573d093ee1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 2 Mar 2016 09:30:56 -0800 Subject: [PATCH 086/513] update to current 4.5-rc net-next headers --- include/linux/bpf.h | 33 +++++++++++++++++++++++++++++++++ include/linux/if_bridge.h | 35 +++++++++++++++++++++++++++++++++-- include/linux/pkt_cls.h | 1 + 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 9a3897be4..ffaba7c4d 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -83,6 +83,7 @@ enum bpf_map_type { BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_MAP_TYPE_PERCPU_HASH, BPF_MAP_TYPE_PERCPU_ARRAY, + BPF_MAP_TYPE_STACK_TRACE, }; enum bpf_prog_type { @@ -272,6 +273,31 @@ enum bpf_func_id { */ BPF_FUNC_perf_event_output, BPF_FUNC_skb_load_bytes, + + /** + * bpf_get_stackid(ctx, map, flags) - walk user or kernel stack and return id + * @ctx: struct pt_regs* + * @map: pointer to stack_trace map + * @flags: bits 0-7 - numer of stack frames to skip + * bit 8 - collect user stack instead of kernel + * bit 9 - compare stacks by hash only + * bit 10 - if two different stacks hash into the same stackid + * discard old + * other bits - reserved + * Return: >= 0 stackid on success or negative error + */ + BPF_FUNC_get_stackid, + + /** + * bpf_csum_diff(from, from_size, to, to_size, seed) - calculate csum diff + * @from: raw from buffer + * @from_size: length of from buffer + * @to: raw to buffer + * @to_size: length of to buffer + * @seed: optional seed + * Return: csum result + */ + BPF_FUNC_csum_diff, __BPF_FUNC_MAX_ID, }; @@ -287,6 +313,7 @@ enum bpf_func_id { /* BPF_FUNC_l4_csum_replace flags. */ #define BPF_F_PSEUDO_HDR (1ULL << 4) +#define BPF_F_MARK_MANGLED_0 (1ULL << 5) /* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */ #define BPF_F_INGRESS (1ULL << 0) @@ -294,6 +321,12 @@ enum bpf_func_id { /* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */ #define BPF_F_TUNINFO_IPV6 (1ULL << 0) +/* BPF_FUNC_get_stackid flags. */ +#define BPF_F_SKIP_FIELD_MASK 0xffULL +#define BPF_F_USER_STACK (1ULL << 8) +#define BPF_F_FAST_STACK_CMP (1ULL << 9) +#define BPF_F_REUSE_STACKID (1ULL << 10) + /* user accessible mirror of in-kernel sk_buff. * new fields can only be added to the end of this structure */ diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 7dafc0d12..8de96b7a7 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -137,11 +137,17 @@ struct bridge_vlan_info { /* Bridge multicast database attributes * [MDBA_MDB] = { * [MDBA_MDB_ENTRY] = { - * [MDBA_MDB_ENTRY_INFO] + * [MDBA_MDB_ENTRY_INFO] { + * struct br_mdb_entry + * [MDBA_MDB_EATTR attributes] + * } * } * } * [MDBA_ROUTER] = { - * [MDBA_ROUTER_PORT] + * [MDBA_ROUTER_PORT] = { + * u32 ifindex + * [MDBA_ROUTER_PATTR attributes] + * } * } */ enum { @@ -166,6 +172,22 @@ enum { }; #define MDBA_MDB_ENTRY_MAX (__MDBA_MDB_ENTRY_MAX - 1) +/* per mdb entry additional attributes */ +enum { + MDBA_MDB_EATTR_UNSPEC, + MDBA_MDB_EATTR_TIMER, + __MDBA_MDB_EATTR_MAX +}; +#define MDBA_MDB_EATTR_MAX (__MDBA_MDB_EATTR_MAX - 1) + +/* multicast router types */ +enum { + MDB_RTR_TYPE_DISABLED, + MDB_RTR_TYPE_TEMP_QUERY, + MDB_RTR_TYPE_PERM, + MDB_RTR_TYPE_TEMP +}; + enum { MDBA_ROUTER_UNSPEC, MDBA_ROUTER_PORT, @@ -173,6 +195,15 @@ enum { }; #define MDBA_ROUTER_MAX (__MDBA_ROUTER_MAX - 1) +/* router port attributes */ +enum { + MDBA_ROUTER_PATTR_UNSPEC, + MDBA_ROUTER_PATTR_TIMER, + MDBA_ROUTER_PATTR_TYPE, + __MDBA_ROUTER_PATTR_MAX +}; +#define MDBA_ROUTER_PATTR_MAX (__MDBA_ROUTER_PATTR_MAX - 1) + struct br_port_msg { __u8 family; __u32 ifindex; diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index a323146ea..a1b89a11b 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -118,6 +118,7 @@ enum { TCA_U32_INDEV, TCA_U32_PCNT, TCA_U32_MARK, + TCA_U32_FLAGS, __TCA_U32_MAX }; From 05d4f64d4abfe198144df807d7d496086c5a7ce9 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Mon, 22 Feb 2016 15:16:13 +0100 Subject: [PATCH 087/513] bridge: mdb: add user-space support for extended attributes Recently support was added to the kernel to be able to add more per-mdb entry attributes via standard netlink attributes of type MDBA_MDB_EATTR_. This patch adds support to iproute2 to parse and output these attributes. The first exported attribute is the mdb "timer" value which is shown only when the "-s" iproute2 arg is used. Example: $ bridge -s mdb show dev br0 port eth1 grp 239.0.0.11 permanent 0.00 dev br0 port eth1 grp 239.0.0.10 temp 244.15 dev br0 port eth1 grp 239.0.0.1 temp 245.21 dev br0 port eth1 grp 239.0.0.5 temp 246.43 dev br0 port eth2 grp 239.0.0.5 temp 248.44 dev br0 port eth1 grp 239.0.0.2 temp 245.32 Signed-off-by: Nikolay Aleksandrov --- bridge/br_common.h | 3 +++ bridge/mdb.c | 15 ++++++++++++--- man/man8/bridge.8 | 5 +++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/bridge/br_common.h b/bridge/br_common.h index 169a162d0..41eb0dc38 100644 --- a/bridge/br_common.h +++ b/bridge/br_common.h @@ -1,3 +1,6 @@ +#define MDB_RTA(r) \ + ((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(struct br_mdb_entry)))) + extern int print_linkinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); diff --git a/bridge/mdb.c b/bridge/mdb.c index 24c490354..09d4b2255 100644 --- a/bridge/mdb.c +++ b/bridge/mdb.c @@ -49,7 +49,7 @@ static void br_print_router_ports(FILE *f, struct rtattr *attr) } static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e, - struct nlmsghdr *n) + struct nlmsghdr *n, struct rtattr **tb) { SPRINT_BUF(abuf); const void *src; @@ -66,20 +66,29 @@ static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e, (e->state & MDB_PERMANENT) ? "permanent" : "temp"); if (e->vid) fprintf(f, " vid %hu", e->vid); + if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) { + struct timeval tv; + + __jiffies_to_tv(&tv, rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER])); + fprintf(f, "%4i.%.2i", (int)tv.tv_sec, (int)tv.tv_usec/10000); + } fprintf(f, "\n"); } static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr, struct nlmsghdr *n) { + struct rtattr *etb[MDBA_MDB_EATTR_MAX + 1]; + struct br_mdb_entry *e; struct rtattr *i; int rem; - struct br_mdb_entry *e; rem = RTA_PAYLOAD(attr); for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { e = RTA_DATA(i); - print_mdb_entry(f, ifindex, e, n); + parse_rtattr(etb, MDBA_MDB_EATTR_MAX, MDB_RTA(RTA_DATA(i)), + RTA_PAYLOAD(i) - RTA_ALIGN(sizeof(*e))); + print_mdb_entry(f, ifindex, e, n, etb); } } diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index efd416e71..0e98edf47 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -503,6 +503,11 @@ With the option, the command becomes verbose. It prints out the ports known to have a connected router. +.PP +With the +.B -statistics +option, the command displays timer values for mdb entries. + .SH bridge vlan - VLAN filter list .B vlan From e897776690aec728f9033eef146783d3a3d48033 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 24 Feb 2016 09:12:47 +0100 Subject: [PATCH 088/513] ipl2tp: Print help even on systems without l2tp support Signed-off-by: Phil Sutter --- ip/ipl2tp.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index f050880ee..3e3b21ddf 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -720,6 +720,9 @@ static int do_show(int argc, char **argv) int do_ipl2tp(int argc, char **argv) { + if (argc < 1 || !matches(*argv, "help")) + usage(); + if (genl_family < 0) { if (rtnl_open_byproto(&genl_rth, 0, NETLINK_GENERIC) < 0) { fprintf(stderr, "Cannot open generic netlink socket\n"); @@ -731,9 +734,6 @@ int do_ipl2tp(int argc, char **argv) exit(1); } - if (argc < 1) - usage(); - if (matches(*argv, "add") == 0) return do_add(argc-1, argv+1); if (matches(*argv, "delete") == 0) @@ -742,8 +742,6 @@ int do_ipl2tp(int argc, char **argv) matches(*argv, "lst") == 0 || matches(*argv, "list") == 0) return do_show(argc-1, argv+1); - if (matches(*argv, "help") == 0) - usage(); fprintf(stderr, "Command \"%s\" is unknown, try \"ip l2tp help\".\n", *argv); exit(-1); From 7a53aa592fffbe5984aa8adbe76f5b370b247f05 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:19:49 +0100 Subject: [PATCH 089/513] ip: align help text with manpage Although the ip command accepts both "neighbor" and "neighbour" as subcommand, I assume it's sufficient to list it in help text as just "neigh" like ip.8 does. Signed-off-by: Phil Sutter --- ip/ip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/ip.c b/ip/ip.c index eea00b822..123f18133 100644 --- a/ip/ip.c +++ b/ip/ip.c @@ -49,7 +49,7 @@ static void usage(void) fprintf(stderr, "Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n" " ip [ -force ] -batch filename\n" -"where OBJECT := { link | address | addrlabel | route | rule | neighbor | ntable |\n" +"where OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |\n" " tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |\n" " netns | l2tp | fou | tcp_metrics | token | netconf }\n" " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n" From 27ff1a564bb20f80dca1023b29d5d22fe196e727 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:19:50 +0100 Subject: [PATCH 090/513] ipaddrlabel: Improve help text precision Neither 'list' nor 'flush' actions accept parameters, and with given prefix the action keyword is not optional anymore. Signed-off-by: Phil Sutter --- ip/ipaddrlabel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ip/ipaddrlabel.c b/ip/ipaddrlabel.c index f01bc269e..ef093cbe6 100644 --- a/ip/ipaddrlabel.c +++ b/ip/ipaddrlabel.c @@ -49,7 +49,8 @@ static void usage(void) __attribute__((noreturn)); static void usage(void) { - fprintf(stderr, "Usage: ip addrlabel [ list | add | del | flush ] prefix PREFIX [ dev DEV ] [ label LABEL ]\n"); + fprintf(stderr, "Usage: ip addrlabel { add | del } prefix PREFIX [ dev DEV ] [ label LABEL ]\n"); + fprintf(stderr, " ip addrlabel [ list | flush | help ]\n"); exit(-1); } From 5c2ea5b8c001fe3e7c85f2c93b9b05bcb035bafa Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:19:51 +0100 Subject: [PATCH 091/513] iplink: fix help text syntax Get rid of extraneous closing brackets and while here, merge the double netns parameter. Signed-off-by: Phil Sutter --- ip/iplink.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ip/iplink.c b/ip/iplink.c index 69f505726..33d7c0ad0 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -70,17 +70,16 @@ void iplink_usage(void) fprintf(stderr, " [ address LLADDR ]\n"); fprintf(stderr, " [ broadcast LLADDR ]\n"); fprintf(stderr, " [ mtu MTU ]\n"); - fprintf(stderr, " [ netns PID ]\n"); - fprintf(stderr, " [ netns NAME ]\n"); + fprintf(stderr, " [ netns { PID | NAME } ]\n"); fprintf(stderr, " [ link-netnsid ID ]\n"); fprintf(stderr, " [ alias NAME ]\n"); fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n"); fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n"); - fprintf(stderr, " [ rate TXRATE ] ]\n"); + fprintf(stderr, " [ rate TXRATE ]\n"); - fprintf(stderr, " [ spoofchk { on | off} ] ]\n"); - fprintf(stderr, " [ query_rss { on | off} ] ]\n"); + fprintf(stderr, " [ spoofchk { on | off} ]\n"); + fprintf(stderr, " [ query_rss { on | off} ]\n"); fprintf(stderr, " [ state { auto | enable | disable} ] ]\n"); fprintf(stderr, " [ trust { on | off} ] ]\n"); fprintf(stderr, " [ master DEVICE ]\n"); From c339b4cc53f64b79b384524ce0e124965d341579 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:19:52 +0100 Subject: [PATCH 092/513] ipneigh: add missing proxy keyword to help text And while we're at it, add whitespace around braces and pipe symbol. Signed-off-by: Phil Sutter --- ip/ipneigh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/ipneigh.c b/ip/ipneigh.c index 92b7cd6f2..9b1499b08 100644 --- a/ip/ipneigh.c +++ b/ip/ipneigh.c @@ -49,7 +49,7 @@ static void usage(void) fprintf(stderr, "Usage: ip neigh { add | del | change | replace } { ADDR [ lladdr LLADDR ]\n" " [ nud { permanent | noarp | stale | reachable } ]\n" " | proxy ADDR } [ dev DEV ]\n"); - fprintf(stderr, " ip neigh {show|flush} [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n"); + fprintf(stderr, " ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n"); exit(-1); } From f1fdcfe66a8e197a5015cb81c789061c03629108 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:19:53 +0100 Subject: [PATCH 093/513] ipntable: Fix typo in help text Signed-off-by: Phil Sutter --- ip/ipntable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/ipntable.c b/ip/ipntable.c index 6eb84e797..2763570ae 100644 --- a/ip/ipntable.c +++ b/ip/ipntable.c @@ -52,7 +52,7 @@ static void usage(void) "PARMS := [ base_reachable MSEC ] [ retrans MSEC ] [ gc_stale MSEC ]\n" " [ delay_probe MSEC ] [ queue LEN ]\n" - " [ app_probs VAL ] [ ucast_probes VAL ] [ mcast_probes VAL ]\n" + " [ app_probes VAL ] [ ucast_probes VAL ] [ mcast_probes VAL ]\n" " [ anycast_delay MSEC ] [ proxy_delay MSEC ] [ proxy_queue LEN ]\n" " [ locktime MSEC ]\n" ); From 070ebbdf754b02e1d7f9e9dbd84e1499332d9063 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:19:54 +0100 Subject: [PATCH 094/513] iproute: TYPE keyword is not optional, fix help text accordingly This is a bit pedantic, but brackets ([]) show optional values and since TYPE must not become empty, they're not suited to surround the type keyword choices. Use curly braces instead. Also add some missing whitespace to the parameter list above. Signed-off-by: Phil Sutter --- ip/iproute.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ip/iproute.c b/ip/iproute.c index 051fc12d1..5b954478c 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -82,13 +82,13 @@ static void usage(void) fprintf(stderr, "FAMILY := [ inet | inet6 | ipx | dnet | mpls | bridge | link ]\n"); fprintf(stderr, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ] [ as [ to ] ADDRESS ]\n"); fprintf(stderr, " [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n"); - fprintf(stderr, " [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n"); + fprintf(stderr, " [ window NUMBER ] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n"); fprintf(stderr, " [ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]\n"); fprintf(stderr, " [ rto_min TIME ] [ hoplimit NUMBER ] [ initrwnd NUMBER ]\n"); fprintf(stderr, " [ features FEATURES ] [ quickack BOOL ] [ congctl NAME ]\n"); fprintf(stderr, " [ pref PREF ] [ expires TIME ]\n"); - fprintf(stderr, "TYPE := [ unicast | local | broadcast | multicast | throw |\n"); - fprintf(stderr, " unreachable | prohibit | blackhole | nat ]\n"); + fprintf(stderr, "TYPE := { unicast | local | broadcast | multicast | throw |\n"); + fprintf(stderr, " unreachable | prohibit | blackhole | nat }\n"); fprintf(stderr, "TABLE_ID := [ local | main | default | all | NUMBER ]\n"); fprintf(stderr, "SCOPE := [ host | link | global | NUMBER ]\n"); fprintf(stderr, "NHFLAGS := [ onlink | pervasive ]\n"); From 20f2af78fb85e53c6d41e73f010607b8d0edbd6e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:19:55 +0100 Subject: [PATCH 095/513] iprule: add missing nat keyword to help text Signed-off-by: Phil Sutter --- ip/iprule.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ip/iprule.c b/ip/iprule.c index 33b71976e..7e3b38b64 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -39,6 +39,7 @@ static void usage(void) fprintf(stderr, "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n"); fprintf(stderr, " [ iif STRING ] [ oif STRING ] [ pref NUMBER ]\n"); fprintf(stderr, "ACTION := [ table TABLE_ID ]\n"); + fprintf(stderr, " [ nat ADDRESS ]\n"); fprintf(stderr, " [ realms [SRCREALM/]DSTREALM ]\n"); fprintf(stderr, " [ goto NUMBER ]\n"); fprintf(stderr, " SUPPRESSOR\n"); From 37fdeb585d773b22a193c07b0beef8994c2b741f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:19:56 +0100 Subject: [PATCH 096/513] man: ip-address.8: Minor syntax fixes Clarify that the optional '-' prefix of the 'tentative', 'deprecated' and 'dadfailed' keywords has to be put right in front of them, no whitespace is allowed in between. In addition to that, clarify that it is valid to pass both 'valid_lft' and 'preferred_lft' at the same time to 'ip address'. Signed-off-by: Phil Sutter --- man/man8/ip-address.8.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/man/man8/ip-address.8.in b/man/man8/ip-address.8.in index 159d9065f..ff3fe0b96 100644 --- a/man/man8/ip-address.8.in +++ b/man/man8/ip-address.8.in @@ -58,9 +58,9 @@ ip-address \- protocol address management .ti -8 .IR FLAG " := " -.RB "[ " permanent " | " dynamic " | " secondary " | " primary " | \ -[ - ] " tentative " | [ - ] " deprecated " | [ - ] " dadfailed " | "\ -temporary " | " CONFFLAG-LIST " ]" +.RB "[ " permanent " | " dynamic " | " secondary " | " primary " |" +.RB [ - ] tentative " | [" - ] deprecated " | [" - ] dadfailed " |" +.BR temporary " | " CONFFLAG-LIST " ]" .ti -8 .IR CONFFLAG-LIST " := [ " CONFFLAG-LIST " ] " CONFFLAG @@ -72,7 +72,7 @@ temporary " | " CONFFLAG-LIST " ]" .ti -8 .IR LIFETIME " := [ " .BI valid_lft " LFT" -.RB "| " preferred_lft +.RB "] [ " preferred_lft .IR LFT " ]" .ti -8 From d890144ecf7501c9117355d14d013dd5c98936ef Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:19:57 +0100 Subject: [PATCH 097/513] man: ip-link.8: minor font fix We commonly use bold font for terminals and italic for non-terminals. Signed-off-by: Phil Sutter --- man/man8/ip-link.8.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 221831e52..2376f1653 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -49,7 +49,7 @@ ip-link \- network device configuration .RB "[ " numrxqueues .IR QUEUE_COUNT " ]" .br -.BR type " TYPE" +.BI type " TYPE" .RI "[ " ARGS " ]" .ti -8 From ca611d6408c9bf17d122923c72d27d032e054cd8 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:19:58 +0100 Subject: [PATCH 098/513] man: ip-link.8: Fix and improve synopsis Reflect that it is possible to pass multiple parameters at the same time, also use the same trick the help text uses to emphasize vf specific parameters. Signed-off-by: Phil Sutter --- man/man8/ip-link.8.in | 100 +++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 2376f1653..e402fdd03 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -92,79 +92,89 @@ ip-link \- network device configuration .BR "ip link set " { .IR DEVICE " | " .BI "group " GROUP -.RB "} { " up " | " down " | " arp " { " on " | " off " } |" +.RB "} [ { " up " | " down " } ]" .br -.BR promisc " { " on " | " off " } |" +.RB "[ " arp " { " on " | " off " } ]" .br -.BR allmulticast " { " on " | " off " } |" +.RB "[ " dynamic " { " on " | " off " } ]" .br -.BR dynamic " { " on " | " off " } |" +.RB "[ " multicast " { " on " | " off " } ]" .br -.BR multicast " { " on " | " off " } |" +.RB "[ " allmulticast " { " on " | " off " } ]" .br -.BR protodown " { " on " | " off " } |" +.RB "[ " promisc " { " on " | " off " } ]" .br -.B txqueuelen -.IR PACKETS " |" +.RB "[ " protodown " { " on " | " off " } ]" .br -.B name -.IR NEWNAME " |" +.RB "[ " trailers " { " on " | " off " } ]" .br -.B address -.IR LLADDR " |" -.B broadcast -.IR LLADDR " |" +.RB "[ " txqueuelen +.IR PACKETS " ]" +.br +.RB "[ " name +.IR NEWNAME " ]" +.br +.RB "[ " address +.IR LLADDR " ]" .br -.B mtu -.IR MTU " |" +.RB "[ " broadcast +.IR LLADDR " ]" +.br +.RB "[ " mtu +.IR MTU " ]" .br -.B netns -.IR PID " |" +.RB "[ " netns " {" +.IR PID " | " NETNSNAME " } ]" .br -.B netns -.IR NETNSNAME " |" +.RB "[ " link-netnsid +.IR ID " ]" .br -.B alias -.IR NAME " |" +.RB "[ " alias +.IR NAME " ]" .br -.B vf +.RB "[ " vf .IR NUM " [" .B mac -.IR LLADDR " ] [" -.B vlan +.IR LLADDR " ]" +.br +.in +9 +.RB "[ " vlan .IR VLANID " [ " .B qos -.IR VLAN-QOS " ] ] [" -.B rate -.IR TXRATE " ] [" -.B max_tx_rate -.IR TXRATE " ] [" -.B min_tx_rate -.IR TXRATE " ] [" -.B spoofchk { on | off } ] [ -.B state { auto | enable | disable} ] [ -.B trust { on | off } -] | +.IR VLAN-QOS " ] ]" .br -.B master -.IR DEVICE " |" +.RB "[ " rate +.IR TXRATE " ]" +.br +.RB "[ " max_tx_rate +.IR TXRATE " ]" +.br +.RB "[ " min_tx_rate +.IR TXRATE " ]" .br -.B nomaster " |" +.RB "[ " spoofchk " { " on " | " off " } ]" .br -.B addrgenmode { eui64 | none | stable_secret | random } +.RB "[ " state " { " auto " | " enable " | " disable " } ]" .br -.B link-netnsid ID -.BR " }" +.RB "[ " trust " { " on " | " off " } ] ]" +.br +.in -9 +.RB "[ " master +.IR DEVICE " ]" +.br +.RB "[ " nomaster " ]" +.br +.RB "[ " addrgenmode " { " eui64 " | " none " | " stable_secret " | " random " } ]" .ti -8 .B ip link show .RI "[ " DEVICE " | " .B group -.IR GROUP " | " -.BR up " | " +.IR GROUP " ] [" +.BR up " ] [" .B master -.IR DEVICE " | " +.IR DEVICE " ] [" .B type .IR TYPE " ]" From 03cb9d58bc8282d156ff644ad5af15217855af54 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:19:59 +0100 Subject: [PATCH 099/513] man: ip-neighbour: Fix for missing NUD_STATE description Signed-off-by: Phil Sutter --- man/man8/ip-neighbour.8 | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/man/man8/ip-neighbour.8 b/man/man8/ip-neighbour.8 index c9b0256e1..19c6d9d8b 100644 --- a/man/man8/ip-neighbour.8 +++ b/man/man8/ip-neighbour.8 @@ -18,7 +18,9 @@ ip-neighbour \- neighbour/arp tables management. .IR ADDR " [ " .B lladdr .IR LLADDR " ] [ " -.BR nud " { " permanent " | " noarp " | " stale " | " reachable " } ] | " proxy +.B nud +.IR STATE " ] |" +.B proxy .IR ADDR " } [ " .B dev .IR DEV " ]" @@ -31,6 +33,9 @@ ip-neighbour \- neighbour/arp tables management. .B nud .IR STATE " ]" +.ti -8 +.IR STATE " := {" +.BR permanent " | " noarp " | " stale " | " reachable " }" .SH DESCRIPTION The @@ -75,7 +80,7 @@ can also be .BR "null" . .TP -.BI nud " NUD_STATE" +.BI nud " STATE" the state of the neighbour entry. .B nud is an abbreviation for 'Neighbour Unreachability Detection'. @@ -147,7 +152,7 @@ list neighbour proxies. only list neighbours which are not currently in use. .TP -.BI nud " NUD_STATE" +.BI nud " STATE" only list neighbour entries in this state. .I NUD_STATE takes values listed below or the special value From 57e1ace02a3e3d212c2d8809d63b729ea59d7427 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:20:00 +0100 Subject: [PATCH 100/513] man: ip-netns.8: Clarify synopsis a bit Use brackets to show that 'ip netns' defaults to action 'list', drop superfluous curly braces around 'set' action keyword. Signed-off-by: Phil Sutter --- man/man8/ip-netns.8 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/man8/ip-netns.8 b/man/man8/ip-netns.8 index c9b0fbc2c..c5310e24e 100644 --- a/man/man8/ip-netns.8 +++ b/man/man8/ip-netns.8 @@ -13,7 +13,7 @@ ip-netns \- process network namespace management .BR help " }" .sp .ti -8 -.BR "ip netns" " { " list " } " +.BR "ip netns" " [ " list " ]" .ti -8 .B ip netns add @@ -24,7 +24,7 @@ ip-netns \- process network namespace management .RI "[ " NETNSNAME " ]" .ti -8 -.BR "ip netns" " { " set " } " +.B ip netns set .I NETNSNAME NETNSID .ti -8 From 54beacc33464d51db6c44f606d1be6cd75591c0d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:20:01 +0100 Subject: [PATCH 101/513] man: ip-ntable.8: Review synopsis section The first line contained a c'n'p error, incorrectly listing 'ip address' syntax. Since PARAMS is used just once and there are not many other parameters to 'ip ntable change', state them inline and in addition to that clarify the possibility to pass multiple parameters at once. Signed-off-by: Phil Sutter --- man/man8/ip-ntable.8 | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/man/man8/ip-ntable.8 b/man/man8/ip-ntable.8 index 462e5896b..4f0f2e548 100644 --- a/man/man8/ip-ntable.8 +++ b/man/man8/ip-ntable.8 @@ -8,7 +8,7 @@ ip-ntable - neighbour table configuration .ti -8 .B ip .RI "[ " OPTIONS " ]" -.B address +.B ntable .RI " { " COMMAND " | " .BR help " }" .sp @@ -17,34 +17,39 @@ ip-ntable - neighbour table configuration .BR "ip ntable change name" .IR NAME " [ " .B dev -.IR DEV " ] " PARMS - -.ti -8 -.IR PARMS " := { " +.IR DEV " ] [" .B thresh1 -.IR VAL " | " +.IR VAL " ] [" .B thresh2 -.IR VAL " | " +.IR VAL " ] [" .B thresh3 -.IR VAL " | " +.IR VAL " ] [" .B gc_int -.IR MSEC " | " +.IR MSEC " ] [" .B base_reachable -.IR MSEC " | " +.IR MSEC " ] [" .B retrans -.IR MSEC " | " "gc_stale MSEC " " | " +.IR MSEC " ] [" +.B gc_stale +.IR MSEC " ] [" .B delay_probe -.IR MSEC " | " "queue LEN " " | " +.IR MSEC " ] [" +.B queue +.IR LEN " ] [" .B app_probs -.IR VAL " | " +.IR VAL " ] [" .B ucast_probes -.IR VAL " | " "mcast_probes VAL " " | " +.IR VAL " ] [" +.B mcast_probes +.IR VAL " ] [" .B anycast_delay -.IR MSEC " | " +.IR MSEC " ] [" .B proxy_delay -.IR MSEC " | " "proxy_queue LEN " " | " +.IR MSEC " ] [" +.B proxy_queue +.IR LEN " ] [" .B locktime -.IR MSEC " }" +.IR MSEC " ]" .ti -8 .BR "ip ntable show" " [ " From 582b0fc6cb443ebe71b82654aa6307d55cd1fc1a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:20:02 +0100 Subject: [PATCH 102/513] man: ip-rule.8: Review synopsis section Clarify that 'ip rule' defaults to action 'list', that 'flush' and 'save' actions don't accept additional parameters, add missing 'not' and 'goto' keywords and finally fix fonts used in 'fwmark' and 'realms' parameters. Signed-off-by: Phil Sutter --- man/man8/ip-rule.8 | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/man/man8/ip-rule.8 b/man/man8/ip-rule.8 index b7008c6ab..e9fbb3cf1 100644 --- a/man/man8/ip-rule.8 +++ b/man/man8/ip-rule.8 @@ -9,20 +9,26 @@ ip-rule \- routing policy database management .B ip .RI "[ " OPTIONS " ]" .B rule -.RI " { " COMMAND " | " +.RI "{ " COMMAND " | " .BR help " }" .sp .ti -8 .B ip rule -.RB " [ " list " | " add " | " del " | " flush " | " save " ]" +.RB "[ " list " ]" + +.ti -8 +.B ip rule +.RB "{ " add " | " del " }" .I SELECTOR ACTION .ti -8 -.B ip rule " restore " +.B ip rule +.RB "{ " flush " | " save " | " restore " }" .ti -8 .IR SELECTOR " := [ " +.BR not " ] [" .B from .IR PREFIX " ] [ " .B to @@ -30,7 +36,7 @@ ip-rule \- routing policy database management .B tos .IR TOS " ] [ " .B fwmark -.IR FWMARK[/MASK] " ] [ " +.IR FWMARK\fR[\fB/\fIMASK "] ] [ " .B iif .IR STRING " ] [ " .B oif @@ -45,8 +51,9 @@ ip-rule \- routing policy database management .B nat .IR ADDRESS " ] [ " .B realms -.RI "[" SRCREALM "/]" DSTREALM " ]" -.I SUPPRESSOR +.RI "[" SRCREALM "\fB/\fR]" DSTREALM " ] [" +.B goto +.IR NUMBER " ] " SUPPRESSOR .ti -8 .IR SUPPRESSOR " := [ " From 16a124ea2dac186d4c54f3bc166a7be4882855ba Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:20:03 +0100 Subject: [PATCH 103/513] man: ip-token.8: Review synopsis section Drop unnecessary curly braces around single action keywords, point out that 'dev' parameter to 'ip token get' is optional and clarify that 'ip token' defaults to 'list' action. Signed-off-by: Phil Sutter --- man/man8/ip-token.8 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/man/man8/ip-token.8 b/man/man8/ip-token.8 index 35a3d1e3e..260f366af 100644 --- a/man/man8/ip-token.8 +++ b/man/man8/ip-token.8 @@ -7,23 +7,23 @@ ip-token \- tokenized interface identifier support .in +8 .ti -8 .B ip token -.RI " { " COMMAND " | " +.RI "{ " COMMAND " | " .BR help " }" .sp .ti -8 -.BR "ip token" " { " set " } " +.B ip token set .IR TOKEN .B dev .IR DEV .ti -8 -.BR "ip token" " { " get " } " -.B dev -.IR DEV +.B ip token get +.RB "[ " dev +.IR DEV " ]" .ti -8 -.BR "ip token" " { " list " }" +.BR "ip token" " [ " list " ]" .SH "DESCRIPTION" IPv6 tokenized interface identifier support is used for assigning well-known From 5d8cb0900e9fd927a81a91c79434cbf847463078 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:20:04 +0100 Subject: [PATCH 104/513] man: ip-tunnel.8: Document missing 6rd action Also drop the non-terminal 'TIME' description as it is not referenced anywhere. Signed-off-by: Phil Sutter --- man/man8/ip-tunnel.8 | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/man/man8/ip-tunnel.8 b/man/man8/ip-tunnel.8 index 8b746cb0f..4938c7405 100644 --- a/man/man8/ip-tunnel.8 +++ b/man/man8/ip-tunnel.8 @@ -11,7 +11,7 @@ ip-tunnel - tunnel configuration .ti -8 .BR "ip " .RI "[ " OPTIONS " ]" -.BR "tunnel" " { " add " | " change " | " del " | " show " | " prl " }" +.BR "tunnel" " { " add " | " change " | " del " | " show " | " prl " | " 6rd " }" .RI "[ " NAME " ]" .br .RB "[ " mode @@ -42,6 +42,12 @@ ip-tunnel - tunnel configuration .B prl-delete .IR ADDR " ]" .br +.RB "[ " 6rd-prefix +.IR ADDR " ] [" +.B 6rd-relay_prefix +.IR ADDR " ] [ +.BR 6rd-reset " ]" +.br .RB "[ [" no "]" pmtudisc " ]" .RB "[ " dev .IR PHYS_DEV " ]" @@ -75,9 +81,6 @@ ip-tunnel - tunnel configuration .ti -8 .IR KEY " := { " DOTTED_QUAD " | " NUMBER " }" -.ti -8 -.IR TIME " := " NUMBER "[s|ms]" - .SH DESCRIPTION .B tunnel objects are tunnels, encapsulating packets in IP packets and then From a7eef7aa70b2d7ea2a78841e1cc188fa416e0f7f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:20:05 +0100 Subject: [PATCH 105/513] man: ip-xfrm.8: Document missing parameters Namely, 'extra-flag' of 'ip xfrm state' and 'flag' of 'ip xfrm policy'. Signed-off-by: Phil Sutter --- man/man8/ip-xfrm.8 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/man/man8/ip-xfrm.8 b/man/man8/ip-xfrm.8 index dae072881..11f710470 100644 --- a/man/man8/ip-xfrm.8 +++ b/man/man8/ip-xfrm.8 @@ -57,6 +57,8 @@ ip-xfrm \- transform configuration .IR ADDR "[/" PLEN "] ]" .RB "[ " ctx .IR CTX " ]" +.RB "[ " extra-flag +.IR EXTRA-FLAG-LIST " ]" .ti -8 .B "ip xfrm state allocspi" @@ -195,6 +197,13 @@ ip-xfrm \- transform configuration .RB "{ " espinudp " | " espinudp-nonike " }" .IR SPORT " " DPORT " " OADDR +.ti -8 +.IR EXTRA-FLAG-LIST " := [ " EXTRA-FLAG-LIST " ] " EXTRA-FLAG + +.ti -8 +.IR EXTRA-FLAG " := " +.B dont-encap-dscp + .ti -8 .BR "ip xfrm policy" " { " add " | " update " }" .I SELECTOR @@ -247,6 +256,8 @@ ip-xfrm \- transform configuration .IR ACTION " ]" .RB "[ " priority .IR PRIORITY " ]" +.RB "[ " flag +.IR FLAG-LIST "]" .ti -8 .B "ip xfrm policy flush" From ac0eff58fd826683107e47c9df085b4b4e92ec66 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:20:06 +0100 Subject: [PATCH 106/513] man: ip.8: Add missing flags and token subcommand description Signed-off-by: Phil Sutter --- man/man8/ip.8 | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/man/man8/ip.8 b/man/man8/ip.8 index b1f690736..aa2bc68c8 100644 --- a/man/man8/ip.8 +++ b/man/man8/ip.8 @@ -21,7 +21,7 @@ ip \- show / manipulate routing, devices, policy routing and tunnels .IR OBJECT " := { " .BR link " | " address " | " addrlabel " | " route " | " rule " | " neigh " | "\ ntable " | " tunnel " | " tuntap " | " maddress " | " mroute " | " mrule " | "\ - monitor " | " xfrm " | " netns " | " l2tp " | " tcp_metrics " }" + monitor " | " xfrm " | " netns " | " l2tp " | " tcp_metrics " | " token " }" .sp .ti -8 @@ -29,10 +29,22 @@ ip \- show / manipulate routing, devices, policy routing and tunnels \fB\-V\fR[\fIersion\fR] | \fB\-h\fR[\fIuman-readable\fR] | \fB\-s\fR[\fItatistics\fR] | +\fB\-d\fR[\fIetails\fR] | \fB\-r\fR[\fIesolve\fR] | +\fB\-iec\fR | \fB\-f\fR[\fIamily\fR] { .BR inet " | " inet6 " | " ipx " | " dnet " | " link " } | " +\fB-4\fR | +\fB-6\fR | +\fB-I\fR | +\fB-D\fR | +\fB-B\fR | +\fB-0\fR | +\fB-l\fR[\fIoops\fR] { \fBmaximum-addr-flush-attempts\fR } | \fB\-o\fR[\fIneline\fR] | +\fB\-rc\fR[\fIvbuf\fR] [\fBsize\fR] | +\fB\-t\fR[\fIimestamp\fR] | +\fB\-ts\fR[\fIhort\fR] | \fB\-n\fR[\fIetns\fR] name | \fB\-a\fR[\fIll\fR] | \fB\-c\fR[\fIolor\fR] } @@ -179,6 +191,16 @@ Use color output. .BR "\-t" , " \-timestamp" display current time when using monitor option. +.TP +.BR "\-ts" , " \-tshort" +Like +.BR \-timestamp , +but use shorter format. + +.TP +.BR "\-rc" , " \-rcvbuf" +Set the netlink socket receive buffer size, defaults to 1MB. + .SH IP - COMMAND SYNTAX .SS @@ -240,6 +262,10 @@ display current time when using monitor option. .B tcp_metrics/tcpmetrics - manage TCP Metrics +.TP +.B token +- manage tokenized interface identifiers. + .TP .B tunnel - tunnel over IP. @@ -305,6 +331,7 @@ was written by Alexey N. Kuznetsov and added in Linux 2.2. .BR ip-route (8), .BR ip-rule (8), .BR ip-tcp_metrics (8), +.BR ip-token (8), .BR ip-tunnel (8), .BR ip-xfrm (8) .br From 2227f2a5a28fa0fc3cc4257ccc9528cdc81996ac Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:20:07 +0100 Subject: [PATCH 107/513] man: ip-l2tp.8: Fix BNF syntax The 'ADDR' part of 'local' and 'remote' parameters is not optional, but may also consist of the word 'any'. While at it, add missing whitespace and fix fonts. Signed-off-by: Phil Sutter --- man/man8/ip-l2tp.8 | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/man/man8/ip-l2tp.8 b/man/man8/ip-l2tp.8 index 1738035f2..5b7041f93 100644 --- a/man/man8/ip-l2tp.8 +++ b/man/man8/ip-l2tp.8 @@ -15,10 +15,7 @@ ip-l2tp - L2TPv3 static unmanaged tunnel configuration .ti -8 .BR "ip l2tp add tunnel" .br -.B remote -.RI "[ " ADDR " ]" -.B local -.RI "[ " ADDR " ]" +.BI remote " ADDR " local " ADDR " .br .B tunnel_id .IR ID @@ -73,24 +70,21 @@ ip-l2tp - L2TPv3 static unmanaged tunnel configuration .IR ID .br .ti -8 -.BR "ip l2tp show tunnel" -.B "[" tunnel_id -.IR ID -.B "]" +.BR "ip l2tp show tunnel" " [ " tunnel_id +.IR ID " ]" .br .ti -8 -.BR "ip l2tp show session" -.B "[" tunnel_id -.IR ID -.B "] [" session_id -.IR ID -.B "]" +.BR "ip l2tp show session" " [ " tunnel_id +.IR ID .B " ] [" +.B session_id +.IR ID " ]" .br .ti -8 .IR NAME " := " .IR STRING .ti -8 -.IR ADDR " := { " IP_ADDRESS " }" +.IR ADDR " := { " IP_ADDRESS " |" +.BR any " }" .ti -8 .IR PORT " := { " NUMBER " }" .ti -8 From e895ae0b31864df9f7dc16254d6dd2084f7bd523 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 19:20:08 +0100 Subject: [PATCH 108/513] man: ip-*.8: drop any reference to generic ip options Listing generic 'ip' options in subcommand man pages is redundant and error-prone, as they won't be kept in sync anyway. Since many other man pages don't list them either, drop references to them in the remaining ones. Signed-off-by: Phil Sutter --- man/man8/ip-addrlabel.8 | 14 +------------- man/man8/ip-link.8.in | 15 +-------------- man/man8/ip-monitor.8 | 4 +--- man/man8/ip-mroute.8 | 2 +- 4 files changed, 4 insertions(+), 31 deletions(-) diff --git a/man/man8/ip-addrlabel.8 b/man/man8/ip-addrlabel.8 index 51ef5727a..233d6067a 100644 --- a/man/man8/ip-addrlabel.8 +++ b/man/man8/ip-addrlabel.8 @@ -6,21 +6,9 @@ ip-addrlabel \- protocol address label management .ad l .in +8 .ti -8 -.B ip -.RI "[ " OPTIONS " ]" -.B addrlabel +.B ip addrlabel .RI " { " COMMAND " | " .BR help " }" -.sp - -.ti -8 -.IR OPTIONS " := { " -\fB\-V\fR[\fIersion\fR] | -\fB\-s\fR[\fItatistics\fR] | -\fB\-r\fR[\fIesolve\fR] | -\fB\-f\fR[\fIamily\fR] { -.BR inet " | " inet6 " | " ipx " | " dnet " | " link " } | " -\fB\-o\fR[\fIneline\fR] } .ti -8 .BR "ip addrlabel" " { " add " | " del " } " prefix diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index e402fdd03..c6a9c862d 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -6,24 +6,11 @@ ip-link \- network device configuration .ad l .in +8 .ti -8 -.B ip -.RI "[ " OPTIONS " ]" -.B link +.B ip link .RI " { " COMMAND " | " .BR help " }" .sp -.ti -8 -.IR OPTIONS " := { " -\fB\-V\fR[\fIersion\fR] | -\fB\-h\fR[\fIuman-readable\fR] | -\fB\-s\fR[\fItatistics\fR] | -\fB\-r\fR[\fIesolve\fR] | -\fB\-f\fR[\fIamily\fR] { -.BR inet " | " inet6 " | " ipx " | " dnet " | " link " } | " -\fB\-o\fR[\fIneline\fR] | -\fB\-br\fR[\fIief\fR] } - .ti -8 .BI "ip link add" .RB "[ " link diff --git a/man/man8/ip-monitor.8 b/man/man8/ip-monitor.8 index d2bd381a8..86f8f9885 100644 --- a/man/man8/ip-monitor.8 +++ b/man/man8/ip-monitor.8 @@ -6,9 +6,7 @@ ip-monitor, rtmon \- state monitoring .ad l .in +8 .ti -8 -.BR "ip " " [ " -.IR ip-OPTIONS " ]" -.BR "monitor" " [ " all " |" +.BR "ip monitor" " [ " all " |" .IR OBJECT-LIST " ] [" .BI file " FILENAME " ] [ diff --git a/man/man8/ip-mroute.8 b/man/man8/ip-mroute.8 index e89b6b2d2..b64e30d33 100644 --- a/man/man8/ip-mroute.8 +++ b/man/man8/ip-mroute.8 @@ -6,7 +6,7 @@ ip-mroute \- multicast routing cache management .ad l .in +8 .ti -8 -.BR "ip " " [ ip-OPTIONS ] " "mroute show" " [ [ " +.BR "ip mroute show" " [ [ " .BR " to " " ] " .IR PREFIX " ] [ " .B from From 1b5440e94fa6392add98458d0790370b86c577a7 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 13:11:36 +0100 Subject: [PATCH 109/513] man: Add a man page for the connmark action Cc: Felix Fietkau Signed-off-by: Phil Sutter --- man/man8/tc-connmark.8 | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 man/man8/tc-connmark.8 diff --git a/man/man8/tc-connmark.8 b/man/man8/tc-connmark.8 new file mode 100644 index 000000000..bb4cf7543 --- /dev/null +++ b/man/man8/tc-connmark.8 @@ -0,0 +1,55 @@ +.TH "Connmark retriever action in tc" 8 "11 Jan 2016" "iproute2" "Linux" + +.SH NAME +connmark - netfilter connmark retriever action +.SH SYNOPSIS +.in +8 +.ti -8 +.BR tc " ... " "action connmark " [ " zone" +.IR u16_zone_index " ] [ " BRANCH " ] [" +.BI index " u32_index " +] + +.ti -8 +.IR BRANCH " := { " reclassify " | " pipe " | " drop " | " continue " | " ok " }" +.SH DESCRIPTION +The connmark action is used to restore the connection's mark value into the +packet's fwmark. +.SH OPTIONS +.TP +.BI zone " u16_zone_index" +Specify the conntrack zone when doing conntrack lookups for packets. +.I u16_zone_index +is a 16bit unsigned decimal value. +.TP +.I BRANCH +How to continue after executing this action. +.RS +.TP +.B reclassify +Restarts classification by jumping back to the first filter attached to this +action's parent. +.TP +.B pipe +Continue with the next action, this is the default. +.TP +.B drop +.TQ +.B shot +Packet will be dropped without running further actions. +.TP +.B continue +Continue classification with next filter in line. +.TP +.B pass +Return to calling qdisc for packet processing. This ends the classification +process. +.RE +.TP +.BI index " u32_index " +Specify an index for this action in order to being able to identify it in later +commands. +.I u32_index +is a 32bit unsigned decimal value. +.SH SEE ALSO +.BR tc (8) From 438dd1d49d71b5d19f51637c50005f11755558dc Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 13:11:37 +0100 Subject: [PATCH 110/513] man: Add a man page for the csum action. Cc: Gregoire Baron Signed-off-by: Phil Sutter --- man/man8/tc-csum.8 | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 man/man8/tc-csum.8 diff --git a/man/man8/tc-csum.8 b/man/man8/tc-csum.8 new file mode 100644 index 000000000..9d00aae34 --- /dev/null +++ b/man/man8/tc-csum.8 @@ -0,0 +1,54 @@ +.TH "Checksum action in tc" 8 "11 Jan 2015" "iproute2" "Linux" + +.SH NAME +csum - checksum update action +.SH SYNOPSIS +.in +8 +.ti -8 +.BR tc " ... " "action csum" +.I UPDATE + +.ti -8 +.IR UPDATE " := " TARGET " [ " UPDATE " ]" + +.ti -8 +.IR TARGET " := { " +.BR ip4h " |" +.BR icmp " |" +.BR igmp " |" +.BR tcp " |" +.BR udp " |" +.BR udplite " |" +.IR SWEETS " }" + +.ti -8 +.IR SWEETS " := { " +.BR and " | " or " | " + " }" +.SH DESCRIPTION +The +.B csum +action triggers checksum recalculation of specified packet headers. It is +commonly used after packet editing using the +.B pedit +action to fix for then incorrect checksums. +.SH OPTIONS +.TP +.I TARGET +Specify which headers to update: IPv4 header +.RB ( ip4h ), +ICMP header +.RB ( icmp ), +IGMP header +.RB ( igmp ), +TCP header +.RB ( tcp ), +UDP header +.RB ( udp ") or" +UDPLite header +.RB ( udplite ). +.TP +.B SWEETS +These are merely syntactic sugar and ignored internally. +.SH SEE ALSO +.BR tc (8), +.BR tc-pedit (8) From 61d74eed701f8a54c9f0c549cbad0722e53482ff Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 13:11:38 +0100 Subject: [PATCH 111/513] man: Add a man page for the mirred action Signed-off-by: Phil Sutter --- man/man8/tc-mirred.8 | 89 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 man/man8/tc-mirred.8 diff --git a/man/man8/tc-mirred.8 b/man/man8/tc-mirred.8 new file mode 100644 index 000000000..52d98bc41 --- /dev/null +++ b/man/man8/tc-mirred.8 @@ -0,0 +1,89 @@ +.TH "Mirror/redirect action in tc" 8 "11 Jan 2015" "iproute2" "Linux" + +.SH NAME +mirred - mirror/redirect action +.SH SYNOPSIS +.in +8 +.ti -8 +.BR tc " ... " "action mirred" +.I DIRECTION ACTION +.RB "[ " index +.IR INDEX " ] " +.BI dev " DEVICENAME" + +.ti -8 +.IR DIRECTION " := { " +.BR ingress " | " egress " }" + +.ti -8 +.IR ACTION " := { " +.BR mirror " | " redirect " }" +.SH DESCRIPTION +The +.B mirred +action allows to redirect or mirror packets to another network interface on the +same system. It is typically used in combination with the +.B ifb +pseudo device to create a shrared instance where QoS happens, but serves well +for debugging or monitoring purposes, too. +.SH OPTIONS +.TP +.B ingress +.TQ +.B egress +Specify the direction in which the packet shall appear on the destination +interface. Currently only +.B egress +is implemented. +.TP +.B mirror +.TQ +.B redirect +Define whether the packet should be copied +.RB ( mirror ) +or moved +.RB ( redirect ) +to the destination interface. +.TP +.BI index " INDEX" +Assign a unique ID to this action instead of letting the kernel choose one +automatically. +.I INDEX +is a 32bit unsigned integer greater than zero. +.TP +.BI dev " DEVICENAME" +Specify the network interface to redirect or mirror to. +.SH EXAMPLES +Limit ingress bandwidth on eth0 to 1mbit/s, redirect exceeding traffic to lo for +debugging purposes: + +.RS +.EX +# tc qdisc add dev eth0 handle ffff: ingress +# tc filter add dev eth0 parent ffff: u32 \\ + match u32 0 0 \\ + action police rate 1mbit burst 100k conform-exceed pipe \\ + action mirred egress redirect dev lo +.EE +.RE + +Use an +.B ifb +interface to send ingress traffic on eth0 through an instance of +.BR sfq : + +.RS +.EX +# modprobe ifb +# ip link set ifb0 up +# tc qdisc add dev ifb0 root sfq +# tc qdisc add dev eth0 handle ffff: ingress +# tc filter add dev eth0 parent ffff: u32 \\ + match u32 0 0 \\ + action mirred egress redirect dev ifb0 +.EE +.RE + +.SH SEE ALSO +.BR tc (8), +.BR tc-u32 (8) From ec0bab1e028a9a8178ae18c4fa6ca600dcf167ba Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 13:11:39 +0100 Subject: [PATCH 112/513] man: Add a man page for the nat action Cc: Herbert Xu Signed-off-by: Phil Sutter --- man/man8/tc-nat.8 | 78 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 man/man8/tc-nat.8 diff --git a/man/man8/tc-nat.8 b/man/man8/tc-nat.8 new file mode 100644 index 000000000..fdcc052a4 --- /dev/null +++ b/man/man8/tc-nat.8 @@ -0,0 +1,78 @@ +.TH "NAT action in tc" 8 "12 Jan 2015" "iproute2" "Linux" + +.SH NAME +nat - stateless native address translation action +.SH SYNOPSIS +.in +8 +.ti -8 +.BR tc " ... " "action nat" +.I DIRECTION OLD NEW + +.ti -8 +.IR DIRECTION " := { " +.BR ingress " | " egress " }" + +.ti -8 +.IR OLD " := " IPV4_ADDR_SPEC + +.ti -8 +.IR NEW " := " IPV4_ADDR_SPEC + +.ti -8 +.IR IPV4_ADDR_SPEC " := { " +.BR default " | " any " | " all " | " +\fIin_addr\fR[\fB/\fR{\fIprefix\fR|\fInetmask\fR}] +.SH DESCRIPTION +The +.B nat +action allows to perform NAT without the overhead of conntrack, which is +desirable if the number of flows or addresses to perform NAT on is large. This +action is best used in combination with the +.B u32 +filter to allow for efficient lookups of a large number of stateless NAT rules +in constant time. +.SH OPTIONS +.TP +.B ingress +Translate destination addresses, i.e. perform DNAT. +.TP +.B egress +Translate source addresses, i.e. perform SNAT. +.TP +.I OLD +Specifies addresses which should be translated. +.TP +.I NEW +Specifies addresses which +.I OLD +should be translated into. +.SH NOTES +The accepted address format in +.IR OLD " and " NEW +is quite flexible. It may either consist of one of the keywords +.BR default ", " any " or " all , +representing the all-zero IP address or a combination of IP address and netmask +or prefix length separated by a slash +.RB ( / ) +sign. In any case, the mask (or prefix length) value of +.I OLD +is used for +.I NEW +as well so that a one-to-one mapping of addresses is assured. + +Address translation is done using a combination of binary operations. First, the +original (source or destination) address is matched against the value of +.IR OLD . +If the original address fits, the new address is created by taking the leading +bits from +.I NEW +(defined by the netmask of +.IR OLD ) +and taking the remaining bits from the original address. + +There is rudimental support for upper layer protocols, namely TCP, UDP and ICMP. +While for the first two only checksum recalculation is performed, the action +also takes care of embedded IP headers in ICMP packets by translating the +respective address therein, too. +.SH SEE ALSO +.BR tc (8) From 448800026ff7189f297233c6588457a7e9770183 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 13:11:40 +0100 Subject: [PATCH 113/513] man: Add a man page for the pedit action Signed-off-by: Phil Sutter --- man/man8/tc-pedit.8 | 230 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 man/man8/tc-pedit.8 diff --git a/man/man8/tc-pedit.8 b/man/man8/tc-pedit.8 new file mode 100644 index 000000000..c30927ec5 --- /dev/null +++ b/man/man8/tc-pedit.8 @@ -0,0 +1,230 @@ +.TH "Generic packet editor action in tc" 8 "12 Jan 2015" "iproute2" "Linux" + +.SH NAME +pedit - generic packet editor action +.SH SYNOPSIS +.in +8 +.ti -8 +.BR tc " ... " "action pedit munge " { +.IR RAW_OP " | " LAYERED_OP " } [ " BRANCH " ]" + +.ti -8 +.IR RAW_OP " := " +.BI offset " OFFSET" +.RB "{ " u8 " | " u16 " | " u32 " } [" +.IR AT_SPEC " ] " CMD_SPEC + +.ti -8 +.IR AT_SPEC " := " +.BI at " AT " offmask " MASK " shift " SHIFT" + +.ti -8 +.IR LAYERED_OP " := { " +.BI ip " IPHDR_FIELD" +| +.BI ip6 " IP6HDR_FIELD" +| +.BI udp " UDPHDR_FIELD" +| +.BI tcp " TCPHDR_FIELD" +| +.BI icmp " ICMPHDR_FIELD" +.RI } " CMD_SPEC" + +.ti -8 +.IR IPHDR_FIELD " := { " +.BR src " | " dst " | " tos " | " dsfield " | " ihl " | " protocol " |" +.BR precedence " | " nofrag " | " firstfrag " | " ce " | " df " |" +.BR mf " | " dport " | " sport " | " icmp_type " | " icmp_code " }" + +.ti -8 +.IR CMD_SPEC " := {" +.BR clear " | " invert " | " set +.IR VAL " | " +.BR preserve " } [ " retain +.IR RVAL " ]" + +.ti -8 +.IR BRANCH " := {" +.BR reclassify " | " pipe " | " drop " | " shot " | " continue " | " pass " }" +.SH DESCRIPTION +The +.B pedit +action can be used to change arbitrary packet data. The location of data to +change can either be specified by giving an offset and size as in +.IR RAW_OP , +or for header values by naming the header and field to edit the size is then +chosen automatically based on the header field size. Currently this is supported +only for IPv4 headers. +.SH OPTIONS +.TP +.BI offset " OFFSET " "\fR{ \fBu32 \fR| \fBu16 \fR| \fBu8 \fR}" +Specify the offset at which to change data. +.I OFFSET +is a signed integer, it's base is automatically chosen (e.g. hex if prefixed by +.B 0x +or octal if prefixed by +.BR 0 ). +The second argument specifies the length of data to change, that is four bytes +.RB ( u32 ), +two bytes +.RB ( u16 ) +or a single byte +.RB ( u8 ). +.TP +.BI at " AT " offmask " MASK " shift " SHIFT" +This is an optional part of +.IR RAW_OP +which allows to have a variable +.I OFFSET +depending on packet data at offset +.IR AT , +which is binary ANDed with +.I MASK +and right-shifted by +.I SHIFT +before adding it to +.IR OFFSET . +.TP +.BI ip " IPHDR_FIELD" +Change an IPv4 header field. The supported keywords for +.I IPHDR_FIELD +are: +.RS +.TP +.B src +.TQ +.B dst +Source or destination IP address, a four-byte value. +.TP +.B tos +.TQ +.B dsfield +.TQ +.B precedence +Type Of Service field, an eight-bit value. +.TP +.B ihl +Change the IP Header Length field, a four-bit value. +.TP +.B protocol +Next-layer Protocol field, an eight-bit value. +.TP +.B nofrag +.TQ +.B firstfrag +.TQ +.B ce +.TQ +.B df +.TQ +.B mf +Change IP header flags. Note that the value to pass to the +.B set +command is not just a bit value, but the full byte including the flags field. +Though only the relevant bits of that value are respected, the rest ignored. +.TP +.B dport +.TQ +.B sport +Destination or source port numbers, a 16-bit value. Indeed, IPv4 headers don't +contain this information. Instead, this will set an offset which suits at least +TCP and UDP if the IP header is of minimum size (20 bytes). If not, this will do +unexpected things. +.TP +.B icmp_type +.TQ +.B icmp_code +Again, this allows to change data past the actual IP header itself. It assumes +an ICMP header is present immediately following the (minimal sized) IP header. +If it is not or the latter is bigger than the minimum of 20 bytes, this will do +unexpected things. These fields are eight-bit values. +.RE +.TP +.B clear +Clear the addressed data (i.e., set it to zero). +.TP +.B invert +Swap every bit in the addressed data. +.TP +.BI set " VAL" +Set the addressed data to a specific value. The size of +.I VAL +is defined by either one of the +.BR u32 ", " u16 " or " u8 +keywords in +.IR RAW_OP , +or the size of the addressed header field in +.IR LAYERED_OP . +.TP +.B preserve +Keep the addressed data as is. +.TP +.BI retain " RVAL" +This optional extra part of +.I CMD_SPEC +allows to exclude bits from being changed. +.TP +.I BRANCH +The following keywords allow to control how the tree of qdisc, classes, +filters and actions is further traversed after this action. +.RS +.TP +.B reclassify +Restart with the first filter in the current list. +.TP +.B pipe +Continue with the next action attached to the same filter. +.TP +.B drop +.TQ +.B shot +Drop the packet. +.TP +.B continue +Continue classification with the next filter in line. +.TP +.B pass +Finish classification process and return to calling qdisc for further packet +processing. This is the default. +.RE +.SH EXAMPLES +Being able to edit packet data, one could do all kinds of things, such as e.g. +implementing port redirection. Certainly not the most useful application, but +as an example it should do: + +First, qdiscs need to be set up to attach filters to. For the receive path, a simple +.B ingress +qdisc will do, for transmit path a classful qdisc +.RB ( HTB +in this case) is necessary: + +.RS +.EX +tc qdisc replace dev eth0 root handle 1: htb +tc qdisc add dev eth0 ingress handle ffff: +.EE +.RE + +Finally, a filter with +.B pedit +action can be added for each direction. In this case, +.B u32 +is used matching on the port number to redirect from, while +.B pedit +then does the actual rewriting: + +.RS +.EX +tc filter add dev eth0 parent 1: u32 \\ + match ip dport 23 0xffff \\ + action pedit pedit munge ip dport set 22 +tc filter add dev eth0 parent ffff: u32 \\ + match ip sport 22 0xffff \\ + action pedit pedit munge ip sport set 23 +.EE +.RE +.SH SEE ALSO +.BR tc (8), +.BR tc-htb (8), +.BR tc-u32 (8) From d477eea5a6dcb1fe42f8106f2172eaced379eabc Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 13:11:41 +0100 Subject: [PATCH 114/513] man: Add a man page for the police action Cc: Alexey Kuznetsov Signed-off-by: Phil Sutter --- man/man8/tc-police.8 | 127 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 man/man8/tc-police.8 diff --git a/man/man8/tc-police.8 b/man/man8/tc-police.8 new file mode 100644 index 000000000..2b1537ec5 --- /dev/null +++ b/man/man8/tc-police.8 @@ -0,0 +1,127 @@ +.TH "Policing action in tc" 8 "20 Jan 2015" "iproute2" "Linux" + +.SH NAME +police - policing action +.SH SYNOPSIS +.in +8 +.ti -8 +.BR tc " ... " "action police" +.BI rate " RATE " burst +.IR BYTES [\fB/ BYTES "] [" +.B mtu +.IR BYTES [\fB/ BYTES "] ] [" +.BI peakrate " RATE" +] [ +.BI avrate " RATE" +] [ +.BI overhead " BYTES" +] [ +.BI linklayer " TYPE" +] [ +.BI conform-exceed " EXCEEDACT\fR[\fB/\fIEXCEEDACT\fR]" + +.ti -8 +.IR EXCEEDACT " := { " +.BR pipe " | " ok " | " reclassify " | " drop " | " continue " }" +.SH DESCRIPTION +The +.B police +action allows to limit bandwidth of traffic matched by the filter it is +attached to. +.SH OPTIONS +.TP +.BI rate " RATE" +The maximum traffic rate of packets passing this action. Those exceeding it will +be treated as defined by the +.B conform-exceed +option. +.TP +.BI burst " BYTES\fR[\fB/\fIBYTES\fR]" +Set the maximum allowed burst in bytes, optionally followed by a slash ('/') +sign and cell size which must be a power of 2. +.TP +.BI mtu " BYTES\fR[\fB/\fIBYTES\fR]" +This is the maximum packet size handled by the policer (larger ones will be +handled like they exceeded the configured rate). Setting this value correctly +will improve the scheduler's precision. +Value formatting is identical to +.B burst +above. Defaults to unlimited. +.TP +.BI peakrate " RATE" +Set the maximum bucket depletion rate, exceeding +.BR rate . +.TP +.BI avrate " RATE" +Make use of an in-kernel bandwidth rate estimator and match the given +.I RATE +against it. +.TP +.BI overhead " BYTES" +Account for protocol overhead of encapsulating output devices when computing +.BR rate " and " peakrate . +.TP +.BI linklayer " TYPE" +Specify the link layer type. +.I TYPE +may be one of +.B ethernet +(the default), +.BR atm " or " adsl +(which are synonyms). It is used to align the precomputed rate tables to ATM +cell sizes, for +.B ethernet +no action is taken. +.TP +.BI conform-exceed " EXCEEDACT\fR[\fB/\fIEXCEEDACT\fR]" +Define how to handle packets which exceed (and, if the second +.I EXCEEDACT +is given, also those who don't), the configured bandwidth limit. Possible values +are: +.RS +.IP continue +Don't do anything, just continue with the next action in line. +.IP drop +Drop the packet immediately. +.IP shot +This is a synonym to +.BR drop . +.IP ok +Accept the packet. This is the default for conforming packets. +.IP pass +This is a synonym to +.BR ok . +.IP reclassify +Treat the packet as non-matching to the filter this action is attached to and +continue with the next filter in line (if any). This is the default for +exceeding packets. +.IP pipe +Pass the packet to the next action in line. +.SH EXAMPLES +A typical application of the police action is to enforce ingress traffic rate +by dropping exceeding packets. Although better done on the sender's side, +especially in scenarios with lack of peer control (e.g. with dial-up providers) +this is often the best one can do in order to keep latencies low under high +load. The following establishes input bandwidth policing to 1mbit/s using the +.B ingress +qdisc and +.B u32 +filter: + +.RS +.EX +# tc qdisc add dev eth0 handle ffff: ingress +# tc filter add dev eth0 parent ffff: u32 \\ + match u32 0 0 \\ + police rate 1mbit burst 100k +.EE +.RE + +As an action can not live on it's own, there always has to be a filter involved as link between qdisc and action. The example above uses +.B u32 +for that, which is configured to effectively match any packet (passing it to the +.B police +action thereby). + +.SH SEE ALSO +.BR tc (8) From ebf9933bb3d5c6a869edb7405f7a4759862409ab Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 13:11:42 +0100 Subject: [PATCH 115/513] man: Add a man page for the simple action Signed-off-by: Phil Sutter --- man/man8/tc-simple.8 | 76 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 man/man8/tc-simple.8 diff --git a/man/man8/tc-simple.8 b/man/man8/tc-simple.8 new file mode 100644 index 000000000..2206dc3b8 --- /dev/null +++ b/man/man8/tc-simple.8 @@ -0,0 +1,76 @@ +.TH "Simple action in tc" 8 "12 Jan 2015" "iproute2" "Linux" + +.SH NAME +simple - basic example action +.SH SYNOPSIS +.in +8 +.ti -8 +.BR tc " ... " "action simple" +.I STRING +.SH DESCRIPTION +This is a pedagogical example rather than an actually useful action. Upon every access, it prints the given +.I STRING +which may be of arbitrary length. +.SH OPTIONS +.TP +.I STRING +The actual string to print. +.SH EXAMPLES +The following example makes the kernel yell "Incoming ICMP!" every time it sees +an incoming ICMP on eth0. Steps are: +.IP 1) 4 +Add an ingress qdisc point to eth0 +.IP 2) 4 +Start a chain on ingress of eth0 that first matches ICMP then invokes the +simple action to shout. +.IP 3) 4 +display stats and show that no packet has been seen by the action +.IP 4) 4 +Send one ping packet to google (expect to receive a response back) +.IP 5) 4 +grep the logs to see the logged message +.IP 6) 4 +display stats again and observe increment by 1 + +.RE +.EX + hadi@noma1:$ tc qdisc add dev eth0 ingress + hadi@noma1:$tc filter add dev eth0 parent ffff: protocol ip prio 5 \\ + u32 match ip protocol 1 0xff flowid 1:1 action simple "Incoming ICMP" + + hadi@noma1:$ sudo tc -s filter ls dev eth0 parent ffff: + filter protocol ip pref 5 u32 + filter protocol ip pref 5 u32 fh 800: ht divisor 1 + filter protocol ip pref 5 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 + match 00010000/00ff0000 at 8 + action order 1: Simple + index 4 ref 1 bind 1 installed 29 sec used 29 sec + Action statistics: + Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) + backlog 0b 0p requeues 0 + + + hadi@noma1$ ping -c 1 www.google.ca + PING www.google.ca (74.125.225.120) 56(84) bytes of data. + 64 bytes from ord08s08-in-f24.1e100.net (74.125.225.120): icmp_req=1 ttl=53 time=31.3 ms + + --- www.google.ca ping statistics --- + 1 packets transmitted, 1 received, 0% packet loss, time 0ms + rtt min/avg/max/mdev = 31.316/31.316/31.316/0.000 ms + + hadi@noma1$ dmesg | grep simple + [135354.473951] simple: Incoming ICMP_1 + + hadi@noma1$ sudo tc/tc -s filter ls dev eth0 parent ffff: + filter protocol ip pref 5 u32 + filter protocol ip pref 5 u32 fh 800: ht divisor 1 + filter protocol ip pref 5 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 + match 00010000/00ff0000 at 8 + action order 1: Simple + index 4 ref 1 bind 1 installed 206 sec used 67 sec + Action statistics: + Sent 84 bytes 1 pkt (dropped 0, overlimits 0 requeues 0) + backlog 0b 0p requeues 0 +.EE +.SH SEE ALSO +.BR tc (8) From ae6cf29be0dc6e1ce237bfe97c12329638c6edac Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 13:11:43 +0100 Subject: [PATCH 116/513] man: Add a man page for the skbedit action Cc: Alexander Duyck Signed-off-by: Phil Sutter --- man/man8/tc-skbedit.8 | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 man/man8/tc-skbedit.8 diff --git a/man/man8/tc-skbedit.8 b/man/man8/tc-skbedit.8 new file mode 100644 index 000000000..b585a4d42 --- /dev/null +++ b/man/man8/tc-skbedit.8 @@ -0,0 +1,45 @@ +.TH "SKB editing action in tc" 8 "12 Jan 2015" "iproute2" "Linux" + +.SH NAME +skbedit - SKB editing action +.SH SYNOPSIS +.in +8 +.ti -8 +.BR tc " ... " "action skbedit " [ " queue_mapping +.IR QUEUE_MAPPING " ] [" +.B priority +.IR PRIORITY " ] [" +.B mark +.IR MARK " ]" +.SH DESCRIPTION +The +.B skbedit +action allows to change a packet's associated meta data. It complements the +.B pedit +action, which in turn allows to change parts of the packet data itself. +.SH OPTIONS +.TP +.BI queue_mapping " QUEUE_MAPPING" +Override the packet's transmit queue. Useful when applied to packets transmitted +over MQ-capable network interfaces. +.I QUEUE_MAPPING +is an unsigned 16bit value in decimal format. +.TP +.BI priority " PRIORITY" +Override the packet classification decision. +.I PRIORITY +is either +.BR root ", " none +or a hexadecimal major class ID optionally followed by a colon +.RB ( : ) +and a hexadecimal minor class ID. +.TP +.BI mark " MARK" +Change the packet's firewall mark value. +.I MARK +is an unsigned 32bit value in automatically detected format (i.e., prefix with +.RB ' 0x ' +for hexadecimal interpretation, etc.). +.SH SEE ALSO +.BR tc (8), +.BR tc-pedit (8) From 8a1c6d4894b3a4036eeca3b75fd82b0a1f01e35b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 13:11:44 +0100 Subject: [PATCH 117/513] man: Add a man page for the vlan action Cc: Jiri Pirko Signed-off-by: Phil Sutter --- man/man8/tc-vlan.8 | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 man/man8/tc-vlan.8 diff --git a/man/man8/tc-vlan.8 b/man/man8/tc-vlan.8 new file mode 100644 index 000000000..e650b72d3 --- /dev/null +++ b/man/man8/tc-vlan.8 @@ -0,0 +1,54 @@ +.TH "VLAN manipulation action in tc" 8 "12 Jan 2015" "iproute2" "Linux" + +.SH NAME +vlan - vlan manipulation module +.SH SYNOPSIS +.in +8 +.ti -8 +.BR tc " ... " "action vlan" " { " pop " |" +.IR PUSH " }" + +.ti -8 +.IR PUSH " := " +.BR push " [ " protocol +.IR VLANPROTO " ]" +.BI id " VLANID" +.SH DESCRIPTION +The +.B vlan +action allows to perform 802.1Q en- or decapsulation on a packet, reflected by +the two operation modes +.IR POP " and " PUSH . +The +.I POP +mode is simple, as no further information is required to just drop the +outer-most VLAN encapsulation. The +.I PUSH +mode on the other hand requires at least a +.I VLANID +and allows to optionally choose the +.I VLANPROTO +to use. +.SH OPTIONS +.TP +.B pop +Decapsulation mode, no further arguments allowed. +.TP +.B push +Encapsulation mode. Requires at least +.B id +option. +.TP +.BI id " VLANID" +Specify the VLAN ID to encapsulate into. +.I VLANID +is an unsigned 16bit integer, the format is detected automatically (e.g. prefix +with +.RB ' 0x ' +for hexadecimal interpretation, etc.). +.TP +.BI protocol " VLANPROTO" +Choose the VLAN protocol to use. At the time of writing, the kernel accepts only +.BR 802.1Q " or " 802.1ad . +.SH SEE ALSO +.BR tc (8) From fa2c34eff1b89b55b1cdb3c0ed3b29bf8b3d5b40 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 13:11:45 +0100 Subject: [PATCH 118/513] man: Add a man page for the xt action Cc: Jiri Pirko Signed-off-by: Phil Sutter --- man/man8/tc-xt.8 | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 man/man8/tc-xt.8 diff --git a/man/man8/tc-xt.8 b/man/man8/tc-xt.8 new file mode 100644 index 000000000..4fd800cf2 --- /dev/null +++ b/man/man8/tc-xt.8 @@ -0,0 +1,42 @@ +.TH "iptables action in tc" 8 "3 Mar 2016" "iproute2" "Linux" + +.SH NAME +xt - tc iptables action +.SH SYNOPSIS +.in +8 +.ti -8 +.BR tc " ... " "action xt \-j" +.IR TARGET " [ " TARGET_OPTS " ]" +.SH DESCRIPTION +The +.B xt +action allows to call arbitrary iptables targets for packets matching the filter +this action is attached to. +.SH OPTIONS +.TP +.BI -j " TARGET \fR[\fI TARGET_OPTS \fR]" +Perform a jump to the given iptables target, optionally passing any target +specific options in +.IR TARGET_OPTS . +.SH EXAMPLES +The following will attach a +.B u32 +filter to the +.B ingress +qdisc matching ICMP replies and using the +.B xt +action to make the kernel yell 'PONG' each time: + +.RS +.EX +tc qdisc add dev eth0 ingress +tc filter add dev eth0 parent ffff: proto ip u32 \\ + match ip protocol 1 0xff \\ + match ip icmp_type 0 0xff \\ + action xt -j LOG --log-prefix PONG +.EE +.RE +.SH SEE ALSO +.BR tc (8), +.BR tc-u32 (8), +.BR iptables-extensions (8) From bcdd39c5880f39190a63325f1f93e6c9e87c5feb Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 13:11:46 +0100 Subject: [PATCH 119/513] man: ship action man pages Signed-off-by: Phil Sutter --- man/man8/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/man/man8/Makefile b/man/man8/Makefile index 2f7764067..d3fdf66ab 100644 --- a/man/man8/Makefile +++ b/man/man8/Makefile @@ -14,7 +14,9 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. tipc.8 tipc-bearer.8 tipc-link.8 tipc-media.8 tipc-nametable.8 \ tipc-node.8 tipc-socket.8 \ tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \ - tc-tcindex.8 tc-u32.8 + tc-tcindex.8 tc-u32.8 \ + tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ + tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 all: $(TARGETS) From b487954d5baf95b4402456964eaad76dcb54db82 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 12:52:39 +0100 Subject: [PATCH 120/513] man: tc-u32: Minor syntax fix Signed-off-by: Phil Sutter --- man/man8/tc-u32.8 | 1 + 1 file changed, 1 insertion(+) diff --git a/man/man8/tc-u32.8 b/man/man8/tc-u32.8 index 47c8f2d09..691f53c13 100644 --- a/man/man8/tc-u32.8 +++ b/man/man8/tc-u32.8 @@ -370,6 +370,7 @@ then allows to match various header fields: .RS .TP .BI src " ADDR" +.TQ .BI dst " ADDR" Compare Source or Destination Address fields against the value of .IR ADDR . From 4853ee528110f61f4d1c1606cfd5dd276bb39cbd Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 12:52:38 +0100 Subject: [PATCH 121/513] man: ip-link: Beef up VXLAN csum options a bit Signed-off-by: Phil Sutter --- man/man8/ip-link.8.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index c6a9c862d..2cd93b0ff 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -491,15 +491,15 @@ are entered into the VXLAN device forwarding database. .sp .I [no]udpcsum -- specifies if UDP checksum is filled in +- specifies if UDP checksum is calculated for transmitted packets over IPv4. .sp .I [no]udp6zerocsumtx -- specifies if UDP checksum is filled in +- skip UDP checksum calculation for transmitted packets over IPv6. .sp .I [no]udp6zerocsumrx -- specifies if UDP checksum is received +- allow incoming UDP packets over IPv6 with zero checksum field. .sp .BI ageing " SECONDS" From c024acc6414285a09107648c9c21a377404b9d45 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 12:52:37 +0100 Subject: [PATCH 122/513] tc: pedit: document branch control in help output This seems to have been a hidden feature, though it's very useful and necessary at least when combining multiple pedit actions. Signed-off-by: Phil Sutter --- tc/m_pedit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tc/m_pedit.c b/tc/m_pedit.c index 4fdd189d7..86eb0ca3f 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -35,7 +35,7 @@ static int pedit_debug; static void explain(void) { - fprintf(stderr, "Usage: ... pedit munge \n"); + fprintf(stderr, "Usage: ... pedit munge []\n"); fprintf(stderr, "Where: MUNGE := |\n" "\t:= [ATC]\n " @@ -47,6 +47,7 @@ explain(void) "\t\tCMD:= clear | invert | set | retain\n " "\t:= ip | ip6 \n " " \t\t| udp | tcp | icmp \n" + "\t:= reclassify | pipe | drop | continue | pass\n" "For Example usage look at the examples directory\n"); } From 2452c57a5283c85d02a30ba65212b8f423b7a382 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 12:52:40 +0100 Subject: [PATCH 123/513] man: ip-route: Make synopsis consistent with description While the synopsis section contains 'ip route list', it is later described as 'ip route show'. Make this consistent by replacing 'list' with 'show' in synopsis. Signed-off-by: Phil Sutter --- man/man8/ip-route.8.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/ip-route.8.in b/man/man8/ip-route.8.in index c764bfc8e..d7fb8fba8 100644 --- a/man/man8/ip-route.8.in +++ b/man/man8/ip-route.8.in @@ -16,7 +16,7 @@ ip-route \- routing table management .ti -8 .BR "ip route" " { " -.BR list " | " flush " } " +.BR show " | " flush " } " .I SELECTOR .ti -8 From 0ce05841d58b42ef39ce7144dc31e77970e5d2e0 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 12:52:41 +0100 Subject: [PATCH 124/513] doc, man: ip-rule: Remove incorrect statement about rule 0 The documentation is wrong here: it is indeed possible to remove policy rule 0 and recreate it afterwards. Therefore remove these statements. Signed-off-by: Phil Sutter --- doc/ip-cref.tex | 3 --- man/man8/ip-rule.8 | 2 -- 2 files changed, 5 deletions(-) diff --git a/doc/ip-cref.tex b/doc/ip-cref.tex index 67094c95b..242cc266b 100644 --- a/doc/ip-cref.tex +++ b/doc/ip-cref.tex @@ -2049,9 +2049,6 @@ \section{{\tt ip rule} --- routing policy database management} The \verb|local| table is a special routing table containing high priority control routes for local and broadcast addresses. -Rule 0 is special. It cannot be deleted or overridden. - - \item Priority: 32766, Selector: match anything, Action: lookup routing table \verb|main| (ID 254). The \verb|main| table is the normal routing table containing all non-policy diff --git a/man/man8/ip-rule.8 b/man/man8/ip-rule.8 index e9fbb3cf1..1774ae3ee 100644 --- a/man/man8/ip-rule.8 +++ b/man/man8/ip-rule.8 @@ -118,8 +118,6 @@ The .B local table is a special routing table containing high priority control routes for local and broadcast addresses. -.sp -Rule 0 is special. It cannot be deleted or overridden. .TP 2. From 948acfed23e5e314fe0f4f863da0368f56645d32 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 20:07:20 +0100 Subject: [PATCH 125/513] man: ip-neighbour.8: Document all known nud states Not sure how useful they are in practice, but as 'ip neigh' supports setting them all, they deserve to be described as well. While at it, also add a missing layer of indentation to the subordinate nud state list. Signed-off-by: Phil Sutter --- man/man8/ip-neighbour.8 | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/man/man8/ip-neighbour.8 b/man/man8/ip-neighbour.8 index 19c6d9d8b..b292e1814 100644 --- a/man/man8/ip-neighbour.8 +++ b/man/man8/ip-neighbour.8 @@ -35,7 +35,8 @@ ip-neighbour \- neighbour/arp tables management. .ti -8 .IR STATE " := {" -.BR permanent " | " noarp " | " stale " | " reachable " }" +.BR permanent " | " noarp " | " stale " | " reachable " | " none " |" +.BR incomplete " | " delay " | " probe " | " failed " }" .SH DESCRIPTION The @@ -86,6 +87,7 @@ the state of the neighbour entry. is an abbreviation for 'Neighbour Unreachability Detection'. The state can take one of the following values: +.RS .TP .B permanent the neighbour entry is valid forever and can be only @@ -105,6 +107,24 @@ This option to .B ip neigh does not change the neighbour state if it was valid and the address is not changed by this command. +.TP +.B none +this is a pseudo state used when initially creating a neighbour entry or after +trying to remove it before it becomes free to do so. +.TP +.B incomplete +the neighbour entry has not (yet) been validated/resolved. +.TP +.B delay +neighbor entry validation is currently delayed. +.TP +.B probe +neighbor is being probed. +.TP +.B failed +max number of probes exceeded without success, neighbor validation has +ultimately failed. +.RE .RE .TP From 03a0cf20b451105ab13f0593fe57144bd6b25c3b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 20:07:21 +0100 Subject: [PATCH 126/513] ipneigh: List all nud states in help output To not make the output overly confusing, list them in a definition of the STATE placeholder which is already used in the show/flush syntax but wasn't explained before. Signed-off-by: Phil Sutter --- ip/ipneigh.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ip/ipneigh.c b/ip/ipneigh.c index 9b1499b08..48cca196f 100644 --- a/ip/ipneigh.c +++ b/ip/ipneigh.c @@ -46,10 +46,11 @@ static void usage(void) __attribute__((noreturn)); static void usage(void) { - fprintf(stderr, "Usage: ip neigh { add | del | change | replace } { ADDR [ lladdr LLADDR ]\n" - " [ nud { permanent | noarp | stale | reachable } ]\n" - " | proxy ADDR } [ dev DEV ]\n"); - fprintf(stderr, " ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n"); + fprintf(stderr, "Usage: ip neigh { add | del | change | replace }\n" + " { ADDR [ lladdr LLADDR ] [ nud STATE ] | proxy ADDR } [ dev DEV ]\n"); + fprintf(stderr, " ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n\n"); + fprintf(stderr, "STATE := { permanent | noarp | stale | reachable | none |\n" + " incomplete | delay | probe | failed }\n"); exit(-1); } From 5f4d27d533917ccce4249c1d367aabf606167c47 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 13:11:47 +0100 Subject: [PATCH 127/513] doc: Add my article about tc, filters and actions Signed-off-by: Phil Sutter --- .gitignore | 1 + doc/Makefile | 2 +- doc/tc-filters.tex | 529 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 531 insertions(+), 1 deletion(-) create mode 100644 doc/tc-filters.tex diff --git a/.gitignore b/.gitignore index 98d83c5d0..ef03b1742 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ doc/*.ps doc/*.dvi doc/*.html doc/*.pdf +doc/*.out diff --git a/doc/Makefile b/doc/Makefile index e9c0ff79e..0c51872af 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,4 +1,4 @@ -PSFILES=ip-cref.ps ip-tunnels.ps api-ip6-flowlabels.ps ss.ps nstat.ps arpd.ps rtstat.ps +PSFILES=ip-cref.ps ip-tunnels.ps api-ip6-flowlabels.ps ss.ps nstat.ps arpd.ps rtstat.ps tc-filters.ps # tc-cref.ps # api-rtnl.tex api-pmtudisc.tex api-news.tex # iki-netdev.ps iki-neighdst.ps diff --git a/doc/tc-filters.tex b/doc/tc-filters.tex new file mode 100644 index 000000000..59127d667 --- /dev/null +++ b/doc/tc-filters.tex @@ -0,0 +1,529 @@ +\documentclass[12pt,twoside]{article} + +\usepackage[hidelinks]{hyperref} % \url +\usepackage{booktabs} % nicer tabulars +\usepackage{fancyvrb} +\usepackage{fullpage} +\usepackage{float} + +\newcommand{\iface}{\textit} +\newcommand{\cmd}{\texttt} +\newcommand{\man}{\textit} +\newcommand{\qdisc}{\texttt} +\newcommand{\filter}{\texttt} + +\begin{document} +\title{QoS in Linux with TC and Filters} +\author{Phil Sutter (phil@nwl.cc)} +\date{January 2016} +\maketitle + +TC, the Traffic Control utility, has been there for a very long time - forever +in my humble perception. It is still (and has ever been if I'm not mistaken) the +only tool to configure QoS in Linux. + +Standard practice when transmitting packets over a medium which may block (due +to congestion, e.g.) is to use a queue which temporarily holds these packets. In +Linux, this queueing approach is where QoS happens: A Queueing Discipline +(qdisc) holds multiple packet queues with different priorities for dequeueing to +the network driver. The classification (i.e. deciding which queue a packet +should go into) is typically done based on Type Of Service (IPv4) or Traffic +Class (IPv6) header fields but depending on qdisc implementation, might be +controlled by the user as well. + +Qdiscs come in two flavors, classful or classless. While classless qdiscs are +not as flexible as classful ones, they also require much less customizing. Often +it is enough to just attach them to an interface, without exact knowledge of +what is done internally. Classful qdiscs are the exact opposite: flexible in +application, they are often not even usable without insightful configuration. + +As the name implies, classful qdiscs provide configurable classes to sort +traffic into. In it's basic form, this is not much different than, say, the +classless \qdisc{pfifo\_fast} which holds three queues and classifies per +packet upon priority field. Though typically classes go beyond that by +supporting nesting and additional characteristics like e.g. maximum traffic +rate or quantum. + +When it comes to controlling the classification process, filters come into play. +They attach to the parent of a set of classes (i.e. either the qdisc itself or +a parent class) and specify how a packet (or it's associated flow) has to look +like in order to suit a given class. To overcome this simplification, it is +possible to attach multiple filters to the same parent, which then consults each +of them in row until the first one accepts the packet. + +Before getting into detail about what filters there are and how to use them, a +simple setup of a qdisc with classes is necessary: +\begin{figure}[H] +\begin{Verbatim} + .-------------------------------------------------------. + | | + | HTB | + | | + | .----------------------------------------------------.| + | | || + | | Class 1:1 || + | | || + | | .---------------..---------------..---------------.|| + | | | || || ||| + | | | Class 1:10 || Class 1:20 || Class 1:30 ||| + | | | || || ||| + | | | .------------.|| .------------.|| .------------.||| + | | | | ||| | ||| | |||| + | | | | fq_codel ||| | fq_codel ||| | fq_codel |||| + | | | | ||| | ||| | |||| + | | | '------------'|| '------------'|| '------------'||| + | | '---------------''---------------''---------------'|| + | '----------------------------------------------------'| + '-------------------------------------------------------' +\end{Verbatim} +\end{figure} +\noindent +The following commands establish the basic setup shown: +\begin{Verbatim} +(1) # tc qdisc replace dev eth0 root handle 1: htb default 30 +(2) # tc class add dev eth0 parent 1: classid 1:1 htb rate 95mbit +(3) # alias tclass='tc class add dev eth0 parent 1:1' +(4) # tclass classid 1:10 htb rate 1mbit ceil 20mbit prio 1 +(4) # tclass classid 1:20 htb rate 90mbit ceil 95mbit prio 2 +(4) # tclass classid 1:30 htb rate 1mbit ceil 95mbit prio 3 +(5) # tc qdisc add dev eth0 parent 1:10 fq_codel +(5) # tc qdisc add dev eth0 parent 1:20 fq_codel +(5) # tc qdisc add dev eth0 parent 1:30 fq_codel +\end{Verbatim} +A little explanation for the unfamiliar reader: +\begin{enumerate} +\item Replace the root qdisc of \iface{eth0} by an instance of \qdisc{HTB}. + Specifying the handle is necessary so it can be referenced in consecutive + calls to \cmd{tc}. The default class for unclassified traffic is set to + 30. +\item Create a single top-level class with handle 1:1 which limits the total + bandwidth allowed to 95mbit/s. It is assumed that \iface{eth0} is a 100mbit/s link, + staying a little below that helps to keep the main point of enqueueing in + the qdisc layer instead of the interface hardware queue or at another + bottleneck in the network. +\item Define an alias for the common part of the remaining three calls in order + to improve readability. This means all remaining classes are attached to the + common parent class from (2). +\item Create three child classes for different uses: Class 1:10 has highest + priority but is tightly limited in bandwidth - fine for interactive + connections. Class 1:20 has mid priority and high guaranteed bandwidth, for + high priority bulk traffic. Finally, there's the default class 1:30 with + lowest priority, low guaranteed bandwidth and the ability to use the full + link in case it's unused otherwise. This should be fine for uninteresting + traffic not explicitly taken care of. +\item Attach a leaf qdisc to each of the child classes created in (4). Since + \qdisc{HTB} by default attaches \qdisc{pfifo} as leaf qdisc, this step is optional. Still, + the fairness between different flows provided by the classless \qdisc{fq\_codel} is + worth the effort. +\end{enumerate} +More information about the qdiscs and fine-tuning parameters can be found in +\man{tc-htb(8)} and \man{tc-fq\_codel(8)}. + +Without any additional setup done, now all traffic leaving \iface{eth0} is shaped to +95mbit/s and directed through class 1:30. This can be verified by looking at the +\texttt{Sent} field of the class statistics printed via \cmd{tc -s class show dev eth0}: +Only the root class 1:1 and it's child 1:30 should show any traffic. + + +\section*{Finally time to start filtering!} + +Let's begin with a simple one, i.e. reestablishing what \qdisc{pfifo\_fast} did +automatically based on TOS/Priority field. Linux internally translates the +header field into the priority field of struct skbuff, which +\qdisc{pfifo\_fast} uses for +classification. \man{tc-prio(8)} contains a table listing the priority (and +ultimately, \qdisc{pfifo\_fast} queue index) each TOS value is being translated into. +Here is a shorter version: +\begin{center} +\begin{tabular}{lll} +TOS Values & Linux Priority (Number) & Queue Index \\ +\midrule +0x0 - 0x6 & Best Effort (0) & 1 \\ +0x8 - 0xe & Bulk (2) & 2 \\ +0x10 - 0x16 & Interactive (6) & 0 \\ +0x18 - 0x1e & Interactive Bulk (4) & 1 \\ +\end{tabular} +\end{center} +Using the \filter{basic} filter, it is possible to match packets based on that skbuff +field, which has the added benefit of being IP version agnostic. Since the +\qdisc{HTB} setup above defaults to class ID 1:30, the Bulk priority can be +ignored. The \filter{basic} filter allows to combine matches, therefore we get along +with only two filters: +\begin{Verbatim} +# tc filter add dev eth0 parent 1: basic \ + match 'meta(priority eq 6)' classid 1:10 +# tc filter add dev eth0 parent 1: basic \ + match 'meta(priority eq 0)' \ + or 'meta(priority eq 4)' classid 1:20 +\end{Verbatim} +A detailed description of the \filter{basic} filter and the ematch syntax it uses can be +found in \man{tc-basic(8)} and \man{tc-ematch(8)}. + +Obviously, this first example cries for optimization. A simple one would be to +just change the default class from 1:30 to 1:20, so filters are only needed for +Bulk and Interactive priorities: +\begin{Verbatim} +# tc filter add dev eth0 parent 1: basic \ + match 'meta(priority eq 6)' classid 1:10 +# tc filter add dev eth0 parent 1: basic \ + match 'meta(priority eq 2)' classid 1:20 +\end{Verbatim} +Given that class IDs are random, choosing them wisely allows for a direct +mapping. So first, recreate the qdisc and classes configuration: +\begin{Verbatim} +# tc qdisc replace dev eth0 root handle 1: htb default 10 +# tc class add dev eth0 parent 1: classid 1:1 htb rate 95mbit +# alias tclass='tc class add dev eth0 parent 1:1' +# tclass classid 1:16 htb rate 1mbit ceil 20mbit prio 1 +# tclass classid 1:10 htb rate 90mbit ceil 95mbit prio 2 +# tclass classid 1:12 htb rate 1mbit ceil 95mbit prio 3 +# tc qdisc add dev eth0 parent 1:16 fq_codel +# tc qdisc add dev eth0 parent 1:10 fq_codel +# tc qdisc add dev eth0 parent 1:12 fq_codel +\end{Verbatim} +This is basically identical to above, but with changed leaf class IDs and the +second priority class being the default. Using the \filter{flow} filter with it's \texttt{map} +functionality, a single filter command is enough: +\begin{Verbatim} +# tc filter add dev eth0 parent 1: handle 0x1337 flow \ + map key priority baseclass 1:10 +\end{Verbatim} +The \filter{flow} filter now uses the priority value to construct a destination class ID +by adding it to the value of \texttt{baseclass}. While this works for priority values of +0, 2 and 6, it will result in non-existent class ID 1:14 for Interactive Bulk +traffic. In that case, the \qdisc{HTB} default applies so that traffic goes into class +ID 1:10 just as intended. Please note that specifying a handle is a mandatory +requirement by the \filter{flow} filter, although I didn't see where one would use that +later. For more information about \filter{flow}, see \man{tc-flow(8)}. + +While \filter{flow} and \filter{basic} filters are relatively easy to apply and understand, they +are as well quite limited to their intended purpose. A more flexible option is +the \filter{u32} filter, which allows to match on arbitrary parts of the packet data - +yet only on that, not any meta data associated to it by the kernel (with the +exception of firewall mark value). So in order to continue this little +exercise with \filter{u32}, we have to base classification directly upon the actual TOS +value. An intuitive attempt might look like this: +\begin{Verbatim} +# alias tcfilter='tc filter add dev eth0 parent 1:' +# tcfilter u32 match ip dsfield 0x10 0x1e classid 1:16 +# tcfilter u32 match ip dsfield 0x12 0x1e classid 1:16 +# tcfilter u32 match ip dsfield 0x14 0x1e classid 1:16 +# tcfilter u32 match ip dsfield 0x16 0x1e classid 1:16 +# tcfilter u32 match ip dsfield 0x8 0x1e classid 1:12 +# tcfilter u32 match ip dsfield 0xa 0x1e classid 1:12 +# tcfilter u32 match ip dsfield 0xc 0x1e classid 1:12 +# tcfilter u32 match ip dsfield 0xe 0x1e classid 1:12 +\end{Verbatim} +The obvious drawback here is the amount of filters needed. And without the +default class, eight more filters would be necessary. This also has performance +implications: A packet with TOS value 0xe will be checked eight times in total +in order to determine it's destination class. While there's not much to be done +about the number of filters, at least the performance problem can be eliminated +by using \filter{u32}'s hash table support: +\begin{Verbatim} +# tc filter add dev eth0 parent 1: prio 99 handle 1: u32 divisor 16 +\end{Verbatim} +This creates a hash table with 16 buckets. The table size is arbitrary, but not +random: Since the first bit of the TOS field is not interesting, it can be +ignored and therefore the range of values to consider is just [0;15], i.e. a +number of 16 different values. The next step is to populate the hash table: +\begin{Verbatim} +# alias tcfilter='tc filter add dev eth0 parent 1: prio 99' +# tcfilter u32 match u8 0 0 ht 1:0: classid 1:16 +# tcfilter u32 match u8 0 0 ht 1:1: classid 1:16 +# tcfilter u32 match u8 0 0 ht 1:2: classid 1:16 +# tcfilter u32 match u8 0 0 ht 1:3: classid 1:16 +# tcfilter u32 match u8 0 0 ht 1:4: classid 1:12 +# tcfilter u32 match u8 0 0 ht 1:5: classid 1:12 +# tcfilter u32 match u8 0 0 ht 1:6: classid 1:12 +# tcfilter u32 match u8 0 0 ht 1:7: classid 1:12 +# tcfilter u32 match u8 0 0 ht 1:8: classid 1:16 +# tcfilter u32 match u8 0 0 ht 1:9: classid 1:16 +# tcfilter u32 match u8 0 0 ht 1:a: classid 1:16 +# tcfilter u32 match u8 0 0 ht 1:b: classid 1:16 +# tcfilter u32 match u8 0 0 ht 1:c: classid 1:10 +# tcfilter u32 match u8 0 0 ht 1:d: classid 1:10 +# tcfilter u32 match u8 0 0 ht 1:e: classid 1:10 +# tcfilter u32 match u8 0 0 ht 1:f: classid 1:10 +\end{Verbatim} +The parameter \texttt{ht} denotes the hash table and bucket the filter should be added +to. Since the first TOS bit is ignored, it's value has to be divided by two in +order to get to the bucket it maps to. E.g. a TOS value of 0x10 will therefore +map to bucket 0x8. For the sake of completeness, all possible values are mapped +and therefore a configurable default class is not required. Note that the used +match expression is not necessary, but mandatory. Therefore anything that +matches any packet will suffice. Finally, a filter which links to the defined +hash table is needed: +\begin{Verbatim} +# tc filter add dev eth0 parent 1: prio 1 protocol ip u32 \ + link 1: hashkey mask 0x001e0000 match u8 0 0 +\end{Verbatim} +Here again, the actual match statement is not necessary, but syntactically +required. All the magic lies within the \texttt{hashkey} parameter, which defines which +part of the packet should be used directly as hash key. Here's a drawing of the +first four bytes of the IPv4 header, with the area selected by \texttt{hashkey mask} +highlighted: +\begin{figure}[H] +\begin{Verbatim} + 0 1 2 3 + .-----------------------------------------------------------------. + | | | ######## | | | + | Version| IHL | #DSCP### | ECN| Total Length | + | | | ######## | | | + '-----------------------------------------------------------------' +\end{Verbatim} +\end{figure} +\noindent +This may look confusing at first, but keep in mind that bit- as well as +byte-ordering here is LSB while the mask value is written in MSB we humans use. +Therefore reading the mask is done like so, starting from left: +\begin{enumerate} +\item Skip the first byte (which contains Version and IHL fields). +\item Skip the lowest bit of the second byte (0x1e is even). +\item Mark the four following bits (0x1e is 11110 in binary). +\item Skip the remaining three bits of the second byte as well as the remaining two + bytes. +\end{enumerate} +Before doing the lookup, the kernel right-shifts the masked value by the amount +of zero-bits in \texttt{mask}, which implicitly also does the division by two which the +hash table depends on. With this setup, every packet has to pass exactly two +filters to be classified. Note that this filter is limited to IPv4 packets: Due +to the related Traffic Class field being at a different offset in the packet, it +would not work for IPv6. To use the same setup for IPv6 as well, a second +entry-level filter is necessary: +\begin{Verbatim} +# tc filter add dev eth0 parent 1: prio 2 protocol ipv6 u32 \ + link 1: hashkey mask 0x01e00000 match u8 0 0 +\end{Verbatim} +For illustration purposes, here again is a drawing of the first four bytes of +the IPv6 header, again with masked area highlighted: +\begin{figure}[H] +\begin{Verbatim} + 0 1 2 3 + .-----------------------------------------------------------------. + | | ######## | | + | Version| #Traffic Class| Flow Label | + | | ######## | | + '-----------------------------------------------------------------' +\end{Verbatim} +\end{figure} +\noindent +Reading the mask value is analogous to IPv4 with the added complexity that +Traffic Class spans over two bytes. Yet, for comparison there's a simple trick: +IPv6 has the interesting field shifted by four bits to the left, and the new +mask's value is shifted by the same amount. For further information about +\filter{u32} and what can be done with it, consult it's man page +\man{tc-u32(8)}. + +Of course, the kernel provides many more filters than just \filter{basic}, +\filter{flow} and \filter{u32} which have been presented above. As of now, the +remaining ones are: +\begin{description} +\item[bpf] + Filtering using Berkeley Packet Filter programs. The program's return + code determines the packet's destination class ID. + +\item[cgroup] + Filter packets based on control groups. This is only useful for packets + originating from the local host, as control groups only exist in that + scope. + +\item[flower] + An extended variant of the flow filter. + +\item[fw] + Matches on firewall mark values previously assigned to the packet by + netfilter (or a filter action, see below for details). This allows to + export the classification algorithm into netfilter, which is very + convenient if appropriate rules exist on the same system in there + already. + +\item[route] + Filter packets based on matching routing table entry. Basically + equivalent to the \texttt{fw} filter above, to make use of an already existing + extensive routing table setup. + +\item[rsvp, rsvp6] + Implementation of the Resource Reservation Protocol in Linux, to react + upon requests sent by an RSVP daemon. + +\item[tcindex] + Match packets based on tcindex value, which is usually set by the dsmark + qdisc. This is part of an approach to support Differentiated Services in + Linux, which is another topic on it's own. +\end{description} + + +\section*{Filter Actions} + +The tc filter framework provides the infrastructure to another extensible set of +tools as well, namely tc actions. As the name suggests, they allow to do things +with packets (or associated data). (The list of) Actions are part of a given +filter. If it matches, each action it contains is executed in order before +returning the classification result. Since the action has direct access to the +latter, it is in theory possible for an action to react upon or even change the +filtering result - as long as the packet matched, of course. Yet none of the +currently in-tree actions make use of this. + +The Generic Actions framework originally evolved out of the filters' ability to +police traffic to a given maximum bandwidth. One common use case for that is to +limit ingress traffic, dropping packets which exceed the threshold. A classic +setup example is like so: +\begin{Verbatim} +# tc qdisc add dev eth0 handle ffff: ingress +# tc filter add dev eth0 parent ffff: u32 \ + match u32 0 0 + police rate 1mbit burst 100k +\end{Verbatim} +The ingress qdisc is not a real one, but merely a point of reference for filters +to attach to which should get applied to incoming traffic. The \filter{u32} filter added +above matches on any packet and therefore limits the total incoming bandwidth to +1mbit/s, allowing bursts of up to 100kbytes. Using the new syntax, the filter +command changes slightly: +\begin{Verbatim} +# tc filter add dev eth0 parent ffff: u32 \ + match u32 0 0 \ + action police rate 1mbit burst 100k +\end{Verbatim} +The important detail is that this syntax allows to define multiple actions. +E.g. for testing purposes, it is possible to redirect exceeding traffic to the +loopback interface instead of dropping it: +\begin{Verbatim} +# tc filter add dev eth0 parent ffff: u32 \ + match u32 0 0 \ + action police rate 1mbit burst 100k conform-exceed pipe \ + action mirred egress redirect dev lo +\end{Verbatim} +The added parameter \texttt{conform-exceed pipe} tells the police action to allow for +further actions to handle the exceeding packet. + +Apart from \texttt{police} and \texttt{mirred} actions, there are a few more. Here's a full +list of the currently implemented ones: +\begin{description} +\item[bpf] + Apply a Berkeley Packet Filter program to the packet. + +\item[connmark] + Set the packet's firewall mark to that of it's connection. This works by + searching the conntrack table for a matching entry. If found, the mark + is restored. + +\item[csum] + Trigger recalculation of packet checksums. The supported protocols are: + IPv4, ICMP, IGMP, TCP, UDP and UDPLite. + +\item[ipt] + Pass the packet to an iptables target. This allows to use iptables + extensions directly instead of having to go the extra mile via setting + an arbitrary firewall mark and matching on that from within netfilter. + +\item[mirred] + Mirror or redirect packets. This is often combined with the ifb pseudo + device to share a common QoS setup between multiple interfaces or even + ingress traffic. + +\item[nat] + Perform stateless Native Address Translation. This is certainly not + complete and therefore inferior to NAT using iptables: Although the + kernel module decides between TCP, UDP and ICMP traffic, it does not + handle typical problematic protocols such as active FTP or SIP. + +\item[pedit] + Generic packet editing. This allows to alter arbitrary bytes of the + packet, either by specifying an offset into the packet or by naming a + packet header and field name to change. Currently, the latter is + implemented only for IPv4 yet. + +\item[police] + Apply a bandwidth rate limiting policy. Packets exceeding it are dropped + by default, but may optionally be handled differently. + +\item[simple] + This is rather an example than real action. All it does is print a + user-defined string together with a packet counter. Useful maybe for + debugging when filter statistics are not available or too complicated. + +\item[skbedit] + Edit associated packet data, supports changing queue mapping, priority + field and firewall mark value. + +\item[vlan] + Add/remove a VLAN header to/from the packet. This might serve as + alternative to using 802.1Q pseudo-interfaces in combination with + routing rules when e.g. packets for a given destination need to be + encapsulated. +\end{description} + + +\section*{Intermediate Functional Block} + +The Intermediate Functional Block (\texttt{ifb}) pseudo network interface acts as a QoS +concentrator for multiple different sources of traffic. Packets from or to other +interfaces have to be redirected to it using the \texttt{mirred} action in order to be +handled, regularly routed traffic will be dropped. This way, a single stack of +qdiscs, classes and filters can be shared between multiple interfaces. + +Here's a simple example to feed incoming traffic from multiple interfaces +through a Stochastic Fairness Queue (\qdisc{sfq}): +\begin{Verbatim} +(1) # modprobe ifb +(2) # ip link set ifb0 up +(3) # tc qdisc add dev ifb0 root sfq +\end{Verbatim} +The first step is to load the \texttt{ifb} kernel module (1). By default, this will +create two ifb devices: \iface{ifb0} and \iface{ifb1}. After setting +\iface{ifb0} up in (2), the root +qdisc is replaced by \qdisc{sfq} in (3). Finally, one can start redirecting ingress +traffic to \iface{ifb0}, e.g. from \iface{eth0}: +\begin{Verbatim} +# tc qdisc add dev eth0 handle ffff: ingress +# tc filter add dev eth0 parent ffff: u32 \ + match u32 0 0 \ + action mirred egress redirect dev ifb0 +\end{Verbatim} +The same can be done for other interfaces, just replacing \iface{eth0} in the two +commands above. One thing to keep in mind here is the asymmetrical routing this +creates within the host doing the QoS: Incoming packets enter the system via +\iface{ifb0}, while corresponding replies leave directly via \iface{eth0}. This can be observed +using \cmd{tcpdump} on \iface{ifb0}, which shows the input part of the traffic only. What's +more confusing is that \cmd{tcpdump} on \iface{eth0} shows both incoming and outgoing traffic, +but the redirection is still effective - a simple prove is setting +\iface{ifb0} down, +which will interrupt the communication. Obviously \cmd{tcpdump} catches the packets to +dump before they enter the ingress qdisc, which is why it sees them while the +kernel itself doesn't. + + +\section*{Conclusion} + +My personal impression is that although the \cmd{tc} utility is an absolute +necessity for anyone aiming at doing QoS in Linux professionally, there are way +too many loose ends and trip wires present in it's environment. Contributing to +this is the fact, that much of the non-essential functionality is redundantly +available in netfilter. Another problem which adds weight to the first one is a +general lack of documentation. Of course, there are many HOWTOs and guides in +the internet, but since it's often not clear how up to date these are, I prefer +the usual resources such as man or info pages. Surely nothing one couldn't fix +in hindsight, but quality certainly suffers if the original author of the code +does not or can not contribute to that. + +All that being said, once the steep learning curve has been mastered, the +conglomerate of (classful) qdiscs, filters and actions provides a highly +sophisticated and flexible infrastructure to perform QoS, which plays nicely +along with routing and firewalling setups. + + +\section*{Further Reading} + +A good starting point for novice users and experienced ones diving into unknown +areas is the extensive HOWTO at \url{http://lartc.org}. The iproute2 package ships +some examples (usually in /usr/share/doc/, depending on distribution) as well as +man pages for \cmd{tc} in general, qdiscs and filters. The latter have been added +just recently though, so if your distribution does not ship iproute2 version +4.3.0 yet, these are not in there. Apart from that, the internet is a spring of +HOWTOs and scripts people wrote - though these should be taken with a grain of +salt: The complexity of the matter often leads to copying others' solutions +without much validation, which allows for less optimal or even obsolete +implementations to survive much longer than desired. + +\end{document} From 29d61fb385967e6e558aad99f68714df42f18c38 Mon Sep 17 00:00:00 2001 From: Elad Raz Date: Sun, 6 Mar 2016 12:46:04 -0800 Subject: [PATCH 128/513] bridge: mdb: add support for offloaded mdb entries Mark MDB entries which are offloaded to HW with "offload" flag Signed-off-by: Elad Raz Signed-off-by: Jiri Pirko --- bridge/mdb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bridge/mdb.c b/bridge/mdb.c index 09d4b2255..600596c94 100644 --- a/bridge/mdb.c +++ b/bridge/mdb.c @@ -60,10 +60,11 @@ static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e, (const void *)&e->addr.u.ip6; if (n->nlmsg_type == RTM_DELMDB) fprintf(f, "Deleted "); - fprintf(f, "dev %s port %s grp %s %s", ll_index_to_name(ifindex), + fprintf(f, "dev %s port %s grp %s %s %s", ll_index_to_name(ifindex), ll_index_to_name(e->ifindex), inet_ntop(af, src, abuf, sizeof(abuf)), - (e->state & MDB_PERMANENT) ? "permanent" : "temp"); + (e->state & MDB_PERMANENT) ? "permanent" : "temp", + (e->flags & MDB_FLAGS_OFFLOAD) ? "offload" : ""); if (e->vid) fprintf(f, " vid %hu", e->vid); if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) { From dd81ee04edc3461653f1254084e2294083ccdca6 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 16:56:27 +0100 Subject: [PATCH 129/513] ifstat, nstat: fix daemon mode Since the relevant code (and it's bugs) is identical in both files, fix them in one go. This patch fixes multiple issues: * Using 'int' for the 'tdiff' variable does not suffice on 64bit systems, the assigned initial time difference makes it wrap and contain a negative value afterwards. Instead use the more appropriate 'time_t' type. * As far as I understood the code, poll() is supposed to time out just at the right time to trigger update_db() in the configured interval. Therefore it's timeout must be set to the desired interval *minus* the time that has already passed since then. * With the last change to the algorithm in place, it does not make sense to call update_db() before returning data to the connected client. Actually, it never does otherwise we could skip the periodic updates in the first place. Signed-off-by: Phil Sutter --- misc/ifstat.c | 9 +++------ misc/nstat.c | 9 +++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/misc/ifstat.c b/misc/ifstat.c index ac5c29c89..694d9839d 100644 --- a/misc/ifstat.c +++ b/misc/ifstat.c @@ -589,7 +589,7 @@ static void server_loop(int fd) for (;;) { int status; - int tdiff; + time_t tdiff; struct timeval now; gettimeofday(&now, NULL); @@ -600,7 +600,7 @@ static void server_loop(int fd) tdiff = 0; } - if (poll(&p, 1, tdiff + scan_interval) > 0 + if (poll(&p, 1, scan_interval - tdiff) > 0 && (p.revents&POLLIN)) { int clnt = accept(fd, NULL, NULL); if (clnt >= 0) { @@ -613,11 +613,8 @@ static void server_loop(int fd) close(clnt); } else { FILE *fp = fdopen(clnt, "w"); - if (fp) { - if (tdiff > 0) - update_db(tdiff); + if (fp) dump_raw_db(fp, 0); - } exit(0); } } diff --git a/misc/nstat.c b/misc/nstat.c index 99705286d..22b27eba7 100644 --- a/misc/nstat.c +++ b/misc/nstat.c @@ -433,7 +433,7 @@ static void server_loop(int fd) for (;;) { int status; - int tdiff; + time_t tdiff; struct timeval now; gettimeofday(&now, NULL); tdiff = T_DIFF(now, snaptime); @@ -442,7 +442,7 @@ static void server_loop(int fd) snaptime = now; tdiff = 0; } - if (poll(&p, 1, tdiff + scan_interval) > 0 + if (poll(&p, 1, scan_interval - tdiff) > 0 && (p.revents&POLLIN)) { int clnt = accept(fd, NULL, NULL); if (clnt >= 0) { @@ -455,11 +455,8 @@ static void server_loop(int fd) close(clnt); } else { FILE *fp = fdopen(clnt, "w"); - if (fp) { - if (tdiff > 0) - update_db(tdiff); + if (fp) dump_kern_db(fp, 0); - } exit(0); } } From 72b365e8e0fd5efe1d5c05d04c25950736635cfb Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 4 Mar 2016 19:57:28 +0100 Subject: [PATCH 130/513] libnetlink: Double the dump buffer size There have been reports about 'ip addr' printing "Message truncated" on systems with large numbers of VFs. Although I haven't been able to get my hands on hardware suitable to reproduce this, increasing the dump buffer has been reported to resolve the issue. For want of a better idea, just double the buffer size to 32k. Feels like this opportunistic buffer size selection is rather workarounding a design flaw in libnetlink or maybe even the netlink protocol itself. Signed-off-by: Phil Sutter --- lib/libnetlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libnetlink.c b/lib/libnetlink.c index d6b5fd3e8..245c4ca21 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -223,7 +223,7 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth, .msg_iov = &iov, .msg_iovlen = 1, }; - char buf[16384]; + char buf[32768]; int dump_intr = 0; iov.iov_base = buf; From ec0ceeec4954b1a5439ec3684460e8385454de90 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 12:20:29 +0100 Subject: [PATCH 131/513] tc: pedit: Fix layered op parsing After lookup of the layered op submodule, pedit would pass argv and argc including the layered op identifier at first position which confused the submodule parser. Fix this by calling NEXT_ARG() before calling the parse_peopt() callback. Signed-off-by: Phil Sutter --- tc/m_pedit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tc/m_pedit.c b/tc/m_pedit.c index 86eb0ca3f..26272d3cc 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -422,6 +422,7 @@ parse_munge(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel) p = get_pedit_kind(k); if (NULL == p) goto bad_val; + NEXT_ARG(); res = p->parse_peopt(&argc, &argv, sel,&tkey); if (res < 0) { fprintf(stderr,"bad pedit parsing\n"); From f440e9d8c2f6f0eb2e9fccd8f4d7c42c11ba4979 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 12:20:30 +0100 Subject: [PATCH 132/513] tc: pedit: Fix parse_cmd() This was horribly broken: * pack_key8() and pack_key16() ... * missed to invert retain value when applying it to the mask, * did not sanitize val by ANDing it with retain, * and ignored the mask which is necessary for 'invert' command. * pack_key16() did not convert mask to network byte order. * Changing the retain value for 'invert' or 'retain' operation seems just plain wrong. * While here, also got rid of unnecessary offset sanitization in pack_key32(). * Simplify code a bit by always assigning the local mask variable to tkey->mask before calling any of the pack_key*() variants. Signed-off-by: Phil Sutter --- tc/m_pedit.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/tc/m_pedit.c b/tc/m_pedit.c index 26272d3cc..a7960d524 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -153,8 +153,6 @@ pack_key32(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) tkey->val = htonl(tkey->val & retain); tkey->mask = htonl(tkey->mask | ~retain); - /* jamal remove this - it is not necessary given the if check above */ - tkey->off &= ~3; return pack_key(sel,tkey); } @@ -177,11 +175,8 @@ pack_key16(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) } stride = 8 * ind; - tkey->val = htons(tkey->val); - tkey->val <<= stride; - tkey->mask <<= stride; - retain <<= stride; - tkey->mask = retain|m[ind]; + tkey->val = htons(tkey->val & retain) << stride; + tkey->mask = (htons(tkey->mask | ~retain) << stride) | m[ind]; tkey->off &= ~3; @@ -205,10 +200,8 @@ pack_key8(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) ind = tkey->off & 3; stride = 8 * ind; - tkey->val <<= stride; - tkey->mask <<= stride; - retain <<= stride; - tkey->mask = retain|m[ind]; + tkey->val = (tkey->val & retain) << stride; + tkey->mask = ((tkey->mask | ~retain) << stride) | m[ind]; tkey->off &= ~3; @@ -269,13 +262,13 @@ parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct t o = 0xFFFFFFFF; if (matches(*argv, "invert") == 0) { - retain = val = mask = o; + val = mask = o; } else if (matches(*argv, "set") == 0) { NEXT_ARG(); if (parse_val(&argc, &argv, &val, type)) return -1; } else if (matches(*argv, "preserve") == 0) { - retain = mask = o; + retain = 0; } else { if (matches(*argv, "clear") != 0) return -1; @@ -291,19 +284,17 @@ parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct t } tkey->val = val; + tkey->mask = mask; if (len == 1) { - tkey->mask = 0xFF; res = pack_key8(retain,sel,tkey); goto done; } if (len == 2) { - tkey->mask = mask; res = pack_key16(retain,sel,tkey); goto done; } if (len == 4) { - tkey->mask = mask; res = pack_key32(retain,sel,tkey); goto done; } From 338b003bcc22a62c98b84dbe5e491cae84dbb03c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 2 Mar 2016 12:20:31 +0100 Subject: [PATCH 133/513] tc: pedit: Fix retain value for ihl adjustments Since the IP Header Length field is just half a byte, adjust retain to only match these bits so the Version field is not overwritten by accident. The whole concept is actually broken due to dependency on endianness which pedit ignores. Signed-off-by: Phil Sutter --- tc/p_ip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tc/p_ip.c b/tc/p_ip.c index 08fdbaa41..10e4bebc7 100644 --- a/tc/p_ip.c +++ b/tc/p_ip.c @@ -58,7 +58,7 @@ parse_ip(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_ke if (strcmp(*argv, "ihl") == 0) { NEXT_ARG(); tkey->off = 0; - res = parse_cmd(&argc, &argv, 1, TU32,RU8,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32,0x0f,sel,tkey); goto done; } if (strcmp(*argv, "protocol") == 0) { From 162b3ce92e13099739560360f31613e1a01abe5e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 14 Mar 2016 16:02:31 -0700 Subject: [PATCH 134/513] v4.5.0 --- include/SNAPSHOT.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/SNAPSHOT.h b/include/SNAPSHOT.h index 58d36327e..9220f778e 100644 --- a/include/SNAPSHOT.h +++ b/include/SNAPSHOT.h @@ -1 +1 @@ -static const char SNAPSHOT[] = "160111"; +static const char SNAPSHOT[] = "160314"; From ba0372670d1fad0ae6cdbf970000ac7f4f72030f Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Mon, 14 Mar 2016 11:04:46 +0100 Subject: [PATCH 135/513] bridge: mdb: add support for extended router port information Recently a new temp router port mode was added and with it the dumped information was extended similar to how mdb entries were done. This patch adds support to dump the new information by using the "-s" switch. Example: $ bridge -d -s mdb show dev br0 port eth1 grp ff02::1:ffbf:5716 temp 234.39 dev br0 port eth1 grp 239.0.0.2 temp 97.17 dev br0 port eth1 grp 239.0.0.3 temp 105.36 router ports on br0: eth1 0.00 permanent router ports on br0: eth2 254.87 temp It also updates the bridge man page. Signed-off-by: Nikolay Aleksandrov --- bridge/br_common.h | 3 +++ bridge/mdb.c | 53 ++++++++++++++++++++++++++++++++++++++-------- man/man8/bridge.8 | 6 +++++- 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/bridge/br_common.h b/bridge/br_common.h index 41eb0dc38..5ea45c9e6 100644 --- a/bridge/br_common.h +++ b/bridge/br_common.h @@ -1,6 +1,9 @@ #define MDB_RTA(r) \ ((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(struct br_mdb_entry)))) +#define MDB_RTR_RTA(r) \ + ((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(__u32)))) + extern int print_linkinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); diff --git a/bridge/mdb.c b/bridge/mdb.c index 600596c94..97da4dc98 100644 --- a/bridge/mdb.c +++ b/bridge/mdb.c @@ -33,19 +33,56 @@ static void usage(void) exit(-1); } -static void br_print_router_ports(FILE *f, struct rtattr *attr) +static bool is_temp_mcast_rtr(__u8 type) +{ + return type == MDB_RTR_TYPE_TEMP_QUERY || type == MDB_RTR_TYPE_TEMP; +} + +static void __print_router_port_stats(FILE *f, struct rtattr *pattr) +{ + struct rtattr *tb[MDBA_ROUTER_PATTR_MAX + 1]; + struct timeval tv; + __u8 type; + + parse_rtattr(tb, MDBA_ROUTER_PATTR_MAX, MDB_RTR_RTA(RTA_DATA(pattr)), + RTA_PAYLOAD(pattr) - RTA_ALIGN(sizeof(uint32_t))); + if (tb[MDBA_ROUTER_PATTR_TIMER]) { + __jiffies_to_tv(&tv, + rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER])); + fprintf(f, " %4i.%.2i", + (int)tv.tv_sec, (int)tv.tv_usec/10000); + } + if (tb[MDBA_ROUTER_PATTR_TYPE]) { + type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]); + fprintf(f, " %s", + is_temp_mcast_rtr(type) ? "temp" : "permanent"); + } +} + +static void br_print_router_ports(FILE *f, struct rtattr *attr, __u32 brifidx) { uint32_t *port_ifindex; struct rtattr *i; int rem; + if (!show_stats) + fprintf(f, "router ports on %s: ", ll_index_to_name(brifidx)); + rem = RTA_PAYLOAD(attr); for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { port_ifindex = RTA_DATA(i); - fprintf(f, "%s ", ll_index_to_name(*port_ifindex)); + if (show_stats) { + fprintf(f, "router ports on %s: %s", + ll_index_to_name(brifidx), + ll_index_to_name(*port_ifindex)); + __print_router_port_stats(f, i); + fprintf(f, "\n"); + } else { + fprintf(f, "%s ", ll_index_to_name(*port_ifindex)); + } } - - fprintf(f, "\n"); + if (!show_stats) + fprintf(f, "\n"); } static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e, @@ -127,11 +164,9 @@ int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[MDBA_ROUTER]) { if (n->nlmsg_type == RTM_GETMDB) { - if (show_details) { - fprintf(fp, "router ports on %s: ", - ll_index_to_name(r->ifindex)); - br_print_router_ports(fp, tb[MDBA_ROUTER]); - } + if (show_details) + br_print_router_ports(fp, tb[MDBA_ROUTER], + r->ifindex); } else { uint32_t *port_ifindex; diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index 0e98edf47..08e8a5bf5 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -118,6 +118,10 @@ output more information. If this option is given multiple times, the amount of information increases. As a rule, the information is statistics or some time values. +.TP +.BR "\-d" , " \-details" +print detailed information about MDB router ports. + .TP .BR "\-n" , " \-net" , " \-netns " switches @@ -506,7 +510,7 @@ a connected router. .PP With the .B -statistics -option, the command displays timer values for mdb entries. +option, the command displays timer values for mdb and router port entries. .SH bridge vlan - VLAN filter list From dd0c8d193f1c07f4a50e44494ecc9843e3ac9537 Mon Sep 17 00:00:00 2001 From: Luca Lemmo Date: Wed, 16 Mar 2016 17:56:12 +0100 Subject: [PATCH 136/513] tc: f_u32: add missing spaces around operators Signed-off-by: Luca Lemmo --- tc/f_u32.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tc/f_u32.c b/tc/f_u32.c index 0b9767893..2a6c9712d 100644 --- a/tc/f_u32.c +++ b/tc/f_u32.c @@ -47,7 +47,7 @@ static void explain(void) static int get_u32_handle(__u32 *handle, const char *str) { - __u32 htid=0, hash=0, nodeid=0; + __u32 htid = 0, hash = 0, nodeid = 0; char *tmp = strchr(str, ':'); if (tmp == NULL) { @@ -58,21 +58,21 @@ static int get_u32_handle(__u32 *handle, const char *str) htid = strtoul(str, &tmp, 16); if (tmp == str && *str != ':' && *str != 0) return -1; - if (htid>=0x1000) + if (htid >= 0x1000) return -1; if (*tmp) { str = tmp + 1; hash = strtoul(str, &tmp, 16); if (tmp == str && *str != ':' && *str != 0) return -1; - if (hash>=0x100) + if (hash >= 0x100) return -1; if (*tmp) { str = tmp + 1; nodeid = strtoul(str, &tmp, 16); if (tmp == str && *str != 0) return -1; - if (nodeid>=0x1000) + if (nodeid >= 0x1000) return -1; } } @@ -122,7 +122,7 @@ static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask, key &= mask; - for (i=0; ikeys[i].off == off && sel->keys[i].offmask == offmask) { __u32 intersect = mask & sel->keys[i].mask; @@ -1244,7 +1244,7 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, if (sel) { if (sel->nkeys) { int i; - for (i=0; inkeys; i++) { + for (i = 0; i < sel->nkeys; i++) { show_keys(f, sel->keys + i); if (show_stats && NULL != pf) fprintf(f, " (success %llu ) ", From 725f2a872d1c0eb88100384216710356b1ecf238 Mon Sep 17 00:00:00 2001 From: Luca Lemmo Date: Wed, 16 Mar 2016 17:56:13 +0100 Subject: [PATCH 137/513] tc: f_u32: trivial coding style cleanups Signed-off-by: Luca Lemmo --- tc/f_u32.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tc/f_u32.c b/tc/f_u32.c index 2a6c9712d..5ca60c89d 100644 --- a/tc/f_u32.c +++ b/tc/f_u32.c @@ -80,7 +80,7 @@ static int get_u32_handle(__u32 *handle, const char *str) return 0; } -static char * sprint_u32_handle(__u32 handle, char *buf) +static char *sprint_u32_handle(__u32 handle, char *buf) { int bsize = SPRINT_BSIZE-1; __u32 htid = TC_U32_HTID(handle); @@ -382,7 +382,7 @@ static int parse_ip6_addr(int *argc_p, char ***argv_p, plen = addr.bitlen; for (i = 0; i < plen; i += 32) { -// if (((i + 31) & ~0x1F) <= plen) { + /* if (((i + 31) & ~0x1F) <= plen) { */ if (i + 31 <= plen) { res = pack_key(sel, addr.data[i / 32], 0xFFFFFFFF, off + 4 * (i / 32), offmask); @@ -1109,14 +1109,14 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, continue; } else if (strcmp(*argv, "indev") == 0) { char ind[IFNAMSIZ + 1]; - memset(ind, 0, sizeof (ind)); + memset(ind, 0, sizeof(ind)); argc--; argv++; if (argc < 1) { fprintf(stderr, "Illegal indev\n"); return -1; } - strncpy(ind, *argv, sizeof (ind) - 1); + strncpy(ind, *argv, sizeof(ind) - 1); addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind, strlen(ind) + 1); } else if (matches(*argv, "action") == 0) { From 4733b18a5e69bde4844bfa5810afb42af379b6ee Mon Sep 17 00:00:00 2001 From: Luca Lemmo Date: Wed, 16 Mar 2016 17:56:14 +0100 Subject: [PATCH 138/513] tc: q_{codel,fq_codel}: add missing space in help text Signed-off-by: Luca Lemmo --- tc/q_codel.c | 2 +- tc/q_fq_codel.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tc/q_codel.c b/tc/q_codel.c index c24246c5c..cff609e8e 100644 --- a/tc/q_codel.c +++ b/tc/q_codel.c @@ -53,7 +53,7 @@ static void explain(void) { - fprintf(stderr, "Usage: ... codel [ limit PACKETS ] [ target TIME]\n"); + fprintf(stderr, "Usage: ... codel [ limit PACKETS ] [ target TIME ]\n"); fprintf(stderr, " [ interval TIME ] [ ecn | noecn ]\n"); fprintf(stderr, " [ ce_threshold TIME ]\n"); } diff --git a/tc/q_fq_codel.c b/tc/q_fq_codel.c index 4f747ebdf..0392c64fe 100644 --- a/tc/q_fq_codel.c +++ b/tc/q_fq_codel.c @@ -51,7 +51,7 @@ static void explain(void) { fprintf(stderr, "Usage: ... fq_codel [ limit PACKETS ] [ flows NUMBER ]\n"); - fprintf(stderr, " [ target TIME] [ interval TIME ]\n"); + fprintf(stderr, " [ target TIME ] [ interval TIME ]\n"); fprintf(stderr, " [ quantum BYTES ] [ [no]ecn ]\n"); fprintf(stderr, " [ ce_threshold TIME ]\n"); } From 32a121cba257954963fbdd56a1c4567c2efc779a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 21 Mar 2016 11:48:36 -0700 Subject: [PATCH 139/513] tc: code cleanup Use checkpatch to fix whitespace and other style issues. --- tc/em_cmp.c | 2 +- tc/em_ipset.c | 46 ++++++++--------- tc/em_meta.c | 25 ++++----- tc/em_nbyte.c | 2 +- tc/em_u32.c | 3 +- tc/f_basic.c | 9 ++-- tc/f_cgroup.c | 4 +- tc/f_flow.c | 5 +- tc/f_flower.c | 20 +++---- tc/f_fw.c | 17 +++--- tc/f_route.c | 11 ++-- tc/f_rsvp.c | 22 ++++++-- tc/f_tcindex.c | 68 +++++++++++------------- tc/f_u32.c | 51 ++++++++++++------ tc/m_action.c | 113 ++++++++++++++++++++-------------------- tc/m_bpf.c | 2 + tc/m_connmark.c | 1 + tc/m_csum.c | 16 +++--- tc/m_ematch.c | 14 ++--- tc/m_estimator.c | 2 +- tc/m_gact.c | 35 +++++++------ tc/m_ipt.c | 94 ++++++++++++++++++--------------- tc/m_mirred.c | 40 +++++++------- tc/m_nat.c | 12 +++-- tc/m_pedit.c | 111 ++++++++++++++++++++------------------- tc/m_police.c | 29 ++++++----- tc/m_simple.c | 5 +- tc/m_skbedit.c | 6 ++- tc/m_vlan.c | 5 +- tc/m_xt.c | 65 ++++++++++++----------- tc/m_xt_old.c | 129 ++++++++++++++++++++++++---------------------- tc/p_icmp.c | 4 +- tc/p_ip.c | 36 ++++++------- tc/p_tcp.c | 2 +- tc/p_udp.c | 2 +- tc/q_atm.c | 116 +++++++++++++++++++---------------------- tc/q_cbq.c | 66 ++++++++++++++---------- tc/q_choke.c | 6 +-- tc/q_codel.c | 20 +++---- tc/q_drr.c | 2 + tc/q_dsmark.c | 64 +++++++++++------------ tc/q_fifo.c | 3 +- tc/q_fq.c | 1 + tc/q_fq_codel.c | 28 +++++----- tc/q_gred.c | 53 +++++++++---------- tc/q_hfsc.c | 5 +- tc/q_hhf.c | 29 ++++++----- tc/q_htb.c | 39 +++++++------- tc/q_multiq.c | 2 +- tc/q_netem.c | 23 +++++---- tc/q_pie.c | 5 +- tc/q_prio.c | 11 ++-- tc/q_red.c | 7 +-- tc/q_rr.c | 9 ++-- tc/q_sfb.c | 3 +- tc/q_sfq.c | 1 + tc/q_tbf.c | 32 +++++++----- tc/tc.c | 36 ++++++------- tc/tc_bpf.c | 41 ++++++--------- tc/tc_cbq.c | 9 ++-- tc/tc_class.c | 13 +++-- tc/tc_core.c | 37 ++++++------- tc/tc_estimator.c | 9 ++-- tc/tc_exec.c | 6 +-- tc/tc_filter.c | 24 +++++---- tc/tc_monitor.c | 6 +-- tc/tc_qdisc.c | 28 +++++----- tc/tc_red.c | 20 +++---- tc/tc_stab.c | 7 ++- tc/tc_util.c | 61 ++++++++++++---------- 70 files changed, 966 insertions(+), 864 deletions(-) diff --git a/tc/em_cmp.c b/tc/em_cmp.c index 3e6d00e5d..fd8bd028c 100644 --- a/tc/em_cmp.c +++ b/tc/em_cmp.c @@ -49,7 +49,7 @@ static int cmp_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, memset(&cmp, 0, sizeof(cmp)); #define PARSE_ERR(CARG, FMT, ARGS...) \ - em_parse_error(EINVAL, args, CARG, &cmp_ematch_util, FMT ,##ARGS) + em_parse_error(EINVAL, args, CARG, &cmp_ematch_util, FMT, ##ARGS) if (args == NULL) return PARSE_ERR(args, "cmp: missing arguments"); diff --git a/tc/em_ipset.c b/tc/em_ipset.c index a2d0d15a6..806a79c78 100644 --- a/tc/em_ipset.c +++ b/tc/em_ipset.c @@ -52,8 +52,8 @@ union ip_set_name_index { #define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */ struct ip_set_req_get_set { - unsigned op; - unsigned version; + unsigned int op; + unsigned int version; union ip_set_name_index set; }; @@ -62,14 +62,14 @@ struct ip_set_req_get_set { #define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */ struct ip_set_req_version { - unsigned op; - unsigned version; + unsigned int op; + unsigned int version; }; #endif /* IPSET_INVALID_ID */ extern struct ematch_util ipset_ematch_util; -static int get_version(unsigned *version) +static int get_version(unsigned int *version) { int res, sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); struct ip_set_req_version req_version; @@ -95,6 +95,7 @@ static int do_getsockopt(struct ip_set_req_get_set *req) { int sockfd, res; socklen_t size = sizeof(struct ip_set_req_get_set); + sockfd = get_version(&req->version); if (sockfd < 0) return -1; @@ -107,8 +108,7 @@ static int do_getsockopt(struct ip_set_req_get_set *req) if (size != sizeof(struct ip_set_req_get_set)) { fprintf(stderr, - "Incorrect return size from kernel during ipset lookup, " - "(want %zu, got %zu)\n", + "Incorrect return size from kernel during ipset lookup, (want %zu, got %zu)\n", sizeof(struct ip_set_req_get_set), (size_t)size); return -1; } @@ -158,29 +158,29 @@ get_set_byname(const char *setname, struct xt_set_info *info) static int parse_dirs(const char *opt_arg, struct xt_set_info *info) { - char *saved = strdup(opt_arg); - char *ptr, *tmp = saved; + char *saved = strdup(opt_arg); + char *ptr, *tmp = saved; if (!tmp) { perror("strdup"); return -1; } - while (info->dim < IPSET_DIM_MAX && tmp != NULL) { - info->dim++; - ptr = strsep(&tmp, ","); - if (strncmp(ptr, "src", 3) == 0) - info->flags |= (1 << info->dim); - else if (strncmp(ptr, "dst", 3) != 0) { - fputs("You must specify (the comma separated list of) 'src' or 'dst'\n", stderr); + while (info->dim < IPSET_DIM_MAX && tmp != NULL) { + info->dim++; + ptr = strsep(&tmp, ","); + if (strncmp(ptr, "src", 3) == 0) + info->flags |= (1 << info->dim); + else if (strncmp(ptr, "dst", 3) != 0) { + fputs("You must specify (the comma separated list of) 'src' or 'dst'\n", stderr); free(saved); return -1; } - } + } - if (tmp) - fprintf(stderr, "Can't be more src/dst options than %u", IPSET_DIM_MAX); - free(saved); + if (tmp) + fprintf(stderr, "Can't be more src/dst options than %u", IPSET_DIM_MAX); + free(saved); return tmp ? -1 : 0; } @@ -204,7 +204,7 @@ static int ipset_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, memset(&set_info, 0, sizeof(set_info)); #define PARSE_ERR(CARG, FMT, ARGS...) \ - em_parse_error(EINVAL, args, CARG, &ipset_ematch_util, FMT ,##ARGS) + em_parse_error(EINVAL, args, CARG, &ipset_ematch_util, FMT, ##ARGS) if (args == NULL) return PARSE_ERR(args, "ipset: missing set name"); @@ -238,7 +238,7 @@ static int ipset_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data, int data_len) { int i; - char setname[IPSET_MAXNAMELEN]; + char setname[IPSET_MAXNAMELEN]; const struct xt_set_info *set_info = data; if (data_len != sizeof(*set_info)) { @@ -246,7 +246,7 @@ static int ipset_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data, return -1; } - if (get_set_byid(setname, set_info->index)) + if (get_set_byid(setname, set_info->index)) return -1; fputs(setname, fd); for (i = 1; i <= set_info->dim; i++) { diff --git a/tc/em_meta.c b/tc/em_meta.c index b64f333e5..9ce5a78a6 100644 --- a/tc/em_meta.c +++ b/tc/em_meta.c @@ -41,9 +41,9 @@ static void meta_print_usage(FILE *fd) struct meta_entry { int id; - char * kind; - char * mask; - char * desc; + char *kind; + char *mask; + char *desc; } meta_table[] = { #define TCF_META_ID_SECTION 0 #define __A(id, name, mask, desc) { TCF_META_ID_##id, name, mask, desc } @@ -102,7 +102,7 @@ struct meta_entry { __A(SK_RMEM_ALLOC, "sk_rmem", "i", "RMEM"), __A(SK_WMEM_ALLOC, "sk_wmem", "i", "WMEM"), __A(SK_OMEM_ALLOC, "sk_omem", "i", "OMEM"), - __A(SK_WMEM_QUEUED, "sk_wmem_queue","i", "WMEM queue"), + __A(SK_WMEM_QUEUED, "sk_wmem_queue", "i", "WMEM queue"), __A(SK_SND_QLEN, "sk_snd_queue", "i", "Send queue length"), __A(SK_RCV_QLEN, "sk_rcv_queue", "i", "Receive queue length"), __A(SK_ERR_QLEN, "sk_err_queue", "i", "Error queue length"), @@ -122,11 +122,11 @@ static inline int map_type(char k) return INT_MAX; } -static struct meta_entry * lookup_meta_entry(struct bstr *kind) +static struct meta_entry *lookup_meta_entry(struct bstr *kind) { int i; - for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++) + for (i = 0; i < ARRAY_SIZE(meta_table); i++) if (!bstrcmp(kind, meta_table[i].kind) && meta_table[i].id != 0) return &meta_table[i]; @@ -134,11 +134,11 @@ static struct meta_entry * lookup_meta_entry(struct bstr *kind) return NULL; } -static struct meta_entry * lookup_meta_entry_byid(int id) +static struct meta_entry *lookup_meta_entry_byid(int id) { int i; - for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++) + for (i = 0; i < ARRAY_SIZE(meta_table); i++) if (meta_table[i].id == id) return &meta_table[i]; @@ -159,6 +159,7 @@ static inline void dump_value(struct nlmsghdr *n, int tlv, unsigned long val, case TCF_META_TYPE_VAR: if (TCF_META_ID(hdr->kind) == TCF_META_ID_VALUE) { struct bstr *a = (struct bstr *) val; + addattr_l(n, MAX_MSG, tlv, a->data, a->len); } break; @@ -192,7 +193,7 @@ static void list_meta_ids(FILE *fd) " ID Type Description\n" \ "--------------------------------------------------------"); - for (i = 0; i < (sizeof(meta_table)/sizeof(meta_table[0])); i++) { + for (i = 0; i < ARRAY_SIZE(meta_table); i++) { if (meta_table[i].id == TCF_META_ID_SECTION) { fprintf(fd, "\n%s:\n", meta_table[i].kind); } else { @@ -231,7 +232,7 @@ static void list_meta_ids(FILE *fd) #define PARSE_FAILURE ((void *) (-1)) #define PARSE_ERR(CARG, FMT, ARGS...) \ - em_parse_error(EINVAL, args, CARG, &meta_ematch_util, FMT ,##ARGS) + em_parse_error(EINVAL, args, CARG, &meta_ematch_util, FMT, ##ARGS) static inline int can_adopt(struct tcf_meta_val *val) { @@ -308,7 +309,7 @@ parse_object(struct bstr *args, struct bstr *arg, struct tcf_meta_val *obj, a = bstr_next(arg); - while(a) { + while (a) { if (!bstrcmp(a, "shift")) { unsigned long shift; @@ -441,7 +442,7 @@ static inline int print_value(FILE *fd, int type, struct rtattr *rta) return -1; } - switch(type) { + switch (type) { case TCF_META_TYPE_INT: if (RTA_PAYLOAD(rta) < sizeof(__u32)) { fprintf(stderr, "meta int type value TLV " \ diff --git a/tc/em_nbyte.c b/tc/em_nbyte.c index 87f3e9d20..76dd8573e 100644 --- a/tc/em_nbyte.c +++ b/tc/em_nbyte.c @@ -49,7 +49,7 @@ static int nbyte_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, memset(&nb, 0, sizeof(nb)); #define PARSE_ERR(CARG, FMT, ARGS...) \ - em_parse_error(EINVAL, args, CARG, &nbyte_ematch_util, FMT ,##ARGS) + em_parse_error(EINVAL, args, CARG, &nbyte_ematch_util, FMT, ##ARGS) if (args == NULL) return PARSE_ERR(args, "nbyte: missing arguments"); diff --git a/tc/em_u32.c b/tc/em_u32.c index 21ed70fd9..0369e15a3 100644 --- a/tc/em_u32.c +++ b/tc/em_u32.c @@ -44,7 +44,7 @@ static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, memset(&u_key, 0, sizeof(u_key)); #define PARSE_ERR(CARG, FMT, ARGS...) \ - em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT ,##ARGS) + em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT, ##ARGS) if (args == NULL) return PARSE_ERR(args, "u32: missing arguments"); @@ -85,6 +85,7 @@ static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, nh_len = strlen("nexthdr+"); if (a->len > nh_len && !memcmp(a->data, "nexthdr+", nh_len)) { char buf[a->len - nh_len + 1]; + offmask = -1; memcpy(buf, a->data + nh_len, a->len - nh_len); offset = strtoul(buf, NULL, 0); diff --git a/tc/f_basic.c b/tc/f_basic.c index 4adf1d220..d663668a9 100644 --- a/tc/f_basic.c +++ b/tc/f_basic.c @@ -27,7 +27,7 @@ static void explain(void) { - fprintf(stderr, "Usage: ... basic [ match EMATCH_TREE ] \n"); + fprintf(stderr, "Usage: ... basic [ match EMATCH_TREE ]\n"); fprintf(stderr, " [ action ACTION_SPEC ] [ classid CLASSID ]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n"); @@ -56,7 +56,7 @@ static int basic_parse_opt(struct filter_util *qu, char *handle, if (argc == 0) return 0; - tail = (struct rtattr*)(((void*)n)+NLMSG_ALIGN(n->nlmsg_len)); + tail = (struct rtattr *)(((void *)n)+NLMSG_ALIGN(n->nlmsg_len)); addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); while (argc > 0) { @@ -69,7 +69,8 @@ static int basic_parse_opt(struct filter_util *qu, char *handle, continue; } else if (matches(*argv, "classid") == 0 || strcmp(*argv, "flowid") == 0) { - unsigned handle; + unsigned int handle; + NEXT_ARG(); if (get_tc_classid(&handle, *argv)) { fprintf(stderr, "Illegal \"classid\"\n"); @@ -102,7 +103,7 @@ static int basic_parse_opt(struct filter_util *qu, char *handle, argc--; argv++; } - tail->rta_len = (((void*)n)+n->nlmsg_len) - (void*)tail; + tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail; return 0; } diff --git a/tc/f_cgroup.c b/tc/f_cgroup.c index 53f7406f2..ecf990998 100644 --- a/tc/f_cgroup.c +++ b/tc/f_cgroup.c @@ -40,7 +40,7 @@ static int cgroup_parse_opt(struct filter_util *qu, char *handle, t->tcm_handle = h; - tail = (struct rtattr*)(((void*)n)+NLMSG_ALIGN(n->nlmsg_len)); + tail = (struct rtattr *)(((void *)n)+NLMSG_ALIGN(n->nlmsg_len)); addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); while (argc > 0) { @@ -76,7 +76,7 @@ static int cgroup_parse_opt(struct filter_util *qu, char *handle, } } - tail->rta_len = (((void*)n)+n->nlmsg_len) - (void*)tail; + tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail; return 0; } diff --git a/tc/f_flow.c b/tc/f_flow.c index f398f55b6..6ee4dd5e5 100644 --- a/tc/f_flow.c +++ b/tc/f_flow.c @@ -30,8 +30,8 @@ static void explain(void) " [ action ACTION_SPEC ]\n" "\n" "KEY-LIST := [ KEY-LIST , ] KEY\n" -"KEY := [ src | dst | proto | proto-src | proto-dst | iif | priority | \n" -" mark | nfct | nfct-src | nfct-dst | nfct-proto-src | \n" +"KEY := [ src | dst | proto | proto-src | proto-dst | iif | priority |\n" +" mark | nfct | nfct-src | nfct-dst | nfct-proto-src |\n" " nfct-proto-dst | rt-classid | sk-uid | sk-gid |\n" " vlan-tag | rxhash ]\n" "OPS := [ or NUM | and NUM | xor NUM | rshift NUM | addend NUM ]\n" @@ -270,6 +270,7 @@ static int flow_print_opt(struct filter_util *fu, FILE *f, struct rtattr *opt, __u32 handle) { struct rtattr *tb[TCA_FLOW_MAX+1]; + SPRINT_BUF(b1); unsigned int i; __u32 mask = ~0, val = 0; diff --git a/tc/f_flower.c b/tc/f_flower.c index db9cc2961..6139fe086 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -28,14 +28,14 @@ static void explain(void) fprintf(stderr, " [ action ACTION-SPEC ] [ classid CLASSID ]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n"); - fprintf(stderr, " MATCH := { indev DEV-NAME | \n"); - fprintf(stderr, " dst_mac MAC-ADDR | \n"); - fprintf(stderr, " src_mac MAC-ADDR | \n"); - fprintf(stderr, " [ipv4 | ipv6 ] | \n"); - fprintf(stderr, " ip_proto [tcp | udp | IP-PROTO ] | \n"); - fprintf(stderr, " dst_ip [ IPV4-ADDR | IPV6-ADDR ] | \n"); - fprintf(stderr, " src_ip [ IPV4-ADDR | IPV6-ADDR ] | \n"); - fprintf(stderr, " dst_port PORT-NUMBER | \n"); + fprintf(stderr, " MATCH := { indev DEV-NAME |\n"); + fprintf(stderr, " dst_mac MAC-ADDR |\n"); + fprintf(stderr, " src_mac MAC-ADDR |\n"); + fprintf(stderr, " [ipv4 | ipv6 ] |\n"); + fprintf(stderr, " ip_proto [tcp | udp | IP-PROTO ] |\n"); + fprintf(stderr, " dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"); + fprintf(stderr, " src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"); + fprintf(stderr, " dst_port PORT-NUMBER |\n"); fprintf(stderr, " src_port PORT-NUMBER }\n"); fprintf(stderr, " FILTERID := X:Y:Z\n"); fprintf(stderr, " ACTION-SPEC := ... look at individual actions\n"); @@ -187,7 +187,7 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, while (argc > 0) { if (matches(*argv, "classid") == 0 || matches(*argv, "flowid") == 0) { - unsigned handle; + unsigned int handle; NEXT_ARG(); ret = get_tc_classid(&handle, *argv); @@ -301,7 +301,7 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, return -1; } - tail->rta_len = (((void*)n)+n->nlmsg_len) - (void*)tail; + tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail; return 0; } diff --git a/tc/f_fw.c b/tc/f_fw.c index 165f4896f..ff9648c51 100644 --- a/tc/f_fw.c +++ b/tc/f_fw.c @@ -43,6 +43,7 @@ static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **a if (handle) { char *slash; + if ((slash = strchr(handle, '/')) != NULL) *slash = '\0'; if (get_u32(&t->tcm_handle, handle, 0)) { @@ -70,7 +71,8 @@ static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **a while (argc > 0) { if (matches(*argv, "classid") == 0 || matches(*argv, "flowid") == 0) { - unsigned handle; + unsigned int handle; + NEXT_ARG(); if (get_tc_classid(&handle, *argv)) { fprintf(stderr, "Illegal \"classid\"\n"); @@ -93,14 +95,15 @@ static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **a continue; } else if (strcmp(*argv, "indev") == 0) { char d[IFNAMSIZ+1]; - memset(d, 0, sizeof (d)); + + memset(d, 0, sizeof(d)); argc--; argv++; if (argc < 1) { fprintf(stderr, "Illegal indev\n"); return -1; } - strncpy(d, *argv, sizeof (d) - 1); + strncpy(d, *argv, sizeof(d) - 1); addattr_l(n, MAX_MSG, TCA_FW_INDEV, d, strlen(d) + 1); } else if (strcmp(*argv, "help") == 0) { explain(); @@ -127,9 +130,10 @@ static int fw_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u if (handle || tb[TCA_FW_MASK]) { __u32 mark = 0, mask = 0; - if(handle) + + if (handle) mark = handle; - if(tb[TCA_FW_MASK] && + if (tb[TCA_FW_MASK] && (mask = rta_getattr_u32(tb[TCA_FW_MASK])) != 0xFFFFFFFF) fprintf(f, "handle 0x%x/0x%x ", mark, mask); else @@ -145,7 +149,8 @@ static int fw_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u tc_print_police(f, tb[TCA_FW_POLICE]); if (tb[TCA_FW_INDEV]) { struct rtattr *idev = tb[TCA_FW_INDEV]; - fprintf(f, "input dev %s ",rta_getattr_str(idev)); + + fprintf(f, "input dev %s ", rta_getattr_str(idev)); } if (tb[TCA_FW_ACT]) { diff --git a/tc/f_route.c b/tc/f_route.c index 4e9032c58..4d9f4dcef 100644 --- a/tc/f_route.c +++ b/tc/f_route.c @@ -60,6 +60,7 @@ static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char while (argc > 0) { if (matches(*argv, "to") == 0) { __u32 id; + NEXT_ARG(); if (rtnl_rtrealm_a2n(&id, *argv)) { fprintf(stderr, "Illegal \"to\"\n"); @@ -70,6 +71,7 @@ static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char fh |= id&0xFF; } else if (matches(*argv, "from") == 0) { __u32 id; + NEXT_ARG(); if (rtnl_rtrealm_a2n(&id, *argv)) { fprintf(stderr, "Illegal \"from\"\n"); @@ -80,9 +82,10 @@ static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char fh |= id<<16; } else if (matches(*argv, "fromif") == 0) { __u32 id; + NEXT_ARG(); ll_init_map(&rth); - if ((id=ll_name_to_index(*argv)) <= 0) { + if ((id = ll_name_to_index(*argv)) <= 0) { fprintf(stderr, "Illegal \"fromif\"\n"); return -1; } @@ -91,7 +94,8 @@ static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char fh |= (0x8000|id)<<16; } else if (matches(*argv, "classid") == 0 || strcmp(*argv, "flowid") == 0) { - unsigned handle; + unsigned int handle; + NEXT_ARG(); if (get_tc_classid(&handle, *argv)) { fprintf(stderr, "Illegal \"classid\"\n"); @@ -141,6 +145,7 @@ static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char static int route_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 handle) { struct rtattr *tb[TCA_ROUTE4_MAX+1]; + SPRINT_BUF(b1); if (opt == NULL) @@ -162,7 +167,7 @@ static int route_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, if (tb[TCA_ROUTE4_FROM]) fprintf(f, "from %s ", rtnl_rtrealm_n2a(rta_getattr_u32(tb[TCA_ROUTE4_FROM]), b1, sizeof(b1))); if (tb[TCA_ROUTE4_IIF]) - fprintf(f, "fromif %s", ll_index_to_name(*(int*)RTA_DATA(tb[TCA_ROUTE4_IIF]))); + fprintf(f, "fromif %s", ll_index_to_name(*(int *)RTA_DATA(tb[TCA_ROUTE4_IIF]))); if (tb[TCA_ROUTE4_POLICE]) tc_print_police(f, tb[TCA_ROUTE4_POLICE]); if (tb[TCA_ROUTE4_ACT]) diff --git a/tc/f_rsvp.c b/tc/f_rsvp.c index 1fe9b15f4..e7dcc774c 100644 --- a/tc/f_rsvp.c +++ b/tc/f_rsvp.c @@ -37,7 +37,7 @@ static void explain(void) fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n"); } -static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix * addr, +static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix *addr, struct tc_rsvp_pinfo *pinfo, int dir, int family) { int argc = *argc_p; @@ -76,6 +76,7 @@ static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix * addr, if (strcmp(*argv, "spi/ah") == 0 || strcmp(*argv, "gpi/ah") == 0) { __u32 gpi; + NEXT_ARG(); if (get_u32(&gpi, *argv, 0)) return -1; @@ -88,6 +89,7 @@ static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix * addr, } else if (strcmp(*argv, "spi/esp") == 0 || strcmp(*argv, "gpi/esp") == 0) { __u32 gpi; + NEXT_ARG(); if (get_u32(&gpi, *argv, 0)) return -1; @@ -99,6 +101,7 @@ static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix * addr, argc--; argv++; } else if (strcmp(*argv, "flowlabel") == 0) { __u32 flabel; + NEXT_ARG(); if (get_u32(&flabel, *argv, 0)) return -1; @@ -114,6 +117,7 @@ static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix * addr, int sz = 1; __u32 tmp; __u32 mask = 0xff; + if (strcmp(*argv, "u32") == 0) { sz = 4; mask = 0xffff; @@ -194,6 +198,7 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * while (argc > 0) { if (matches(*argv, "session") == 0) { inet_prefix addr; + NEXT_ARG(); if (get_addr_and_pi(&argc, &argv, &addr, &pinfo, 1, family)) { fprintf(stderr, "Illegal \"session\"\n"); @@ -206,6 +211,7 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * } else if (matches(*argv, "sender") == 0 || matches(*argv, "flowspec") == 0) { inet_prefix addr; + NEXT_ARG(); if (get_addr_and_pi(&argc, &argv, &addr, &pinfo, 0, family)) { fprintf(stderr, "Illegal \"sender\"\n"); @@ -217,6 +223,7 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * continue; } else if (matches("ipproto", *argv) == 0) { int num; + NEXT_ARG(); num = inet_proto_a2n(*argv); if (num < 0) { @@ -227,7 +234,8 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * pinfo_ok++; } else if (matches(*argv, "classid") == 0 || strcmp(*argv, "flowid") == 0) { - unsigned handle; + unsigned int handle; + NEXT_ARG(); if (get_tc_classid(&handle, *argv)) { fprintf(stderr, "Illegal \"classid\"\n"); @@ -235,7 +243,8 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * } addattr_l(n, 4096, TCA_RSVP_CLASSID, &handle, 4); } else if (strcmp(*argv, "tunnelid") == 0) { - unsigned tid; + unsigned int tid; + NEXT_ARG(); if (get_unsigned(&tid, *argv, 0)) { fprintf(stderr, "Illegal \"tunnelid\"\n"); @@ -244,7 +253,8 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * pinfo.tunnelid = tid; pinfo_ok++; } else if (strcmp(*argv, "tunnel") == 0) { - unsigned tid; + unsigned int tid; + NEXT_ARG(); if (get_unsigned(&tid, *argv, 0)) { fprintf(stderr, "Illegal \"tunnel\"\n"); @@ -292,7 +302,7 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc, char * return 0; } -static char * sprint_spi(struct tc_rsvp_gpi *pi, int dir, char *buf) +static char *sprint_spi(struct tc_rsvp_gpi *pi, int dir, char *buf) { if (pi->offset == 0) { if (dir && pi->mask == htonl(0xFFFF)) { @@ -351,6 +361,7 @@ static int rsvp_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, _ if (tb[TCA_RSVP_DST]) { char buf[128]; + fprintf(f, "session "); if (inet_ntop(family, RTA_DATA(tb[TCA_RSVP_DST]), buf, sizeof(buf)) == 0) fprintf(f, " [INVALID DADDR] "); @@ -377,6 +388,7 @@ static int rsvp_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, _ fprintf(f, "tunnelid %d ", pinfo->tunnelid); if (tb[TCA_RSVP_SRC]) { char buf[128]; + fprintf(f, "sender "); if (inet_ntop(family, RTA_DATA(tb[TCA_RSVP_SRC]), buf, sizeof(buf)) == 0) { fprintf(f, "[BAD]"); diff --git a/tc/f_tcindex.c b/tc/f_tcindex.c index b1847c899..280d1d4d6 100644 --- a/tc/f_tcindex.c +++ b/tc/f_tcindex.c @@ -17,11 +17,9 @@ static void explain(void) { - fprintf(stderr," Usage: ... tcindex [ hash SIZE ] [ mask MASK ]" - " [ shift SHIFT ]\n"); - fprintf(stderr," [ pass_on | fall_through ]\n"); - fprintf(stderr," [ classid CLASSID ] " - "[ action ACTION_SPEC ]\n"); + fprintf(stderr," Usage: ... tcindex [ hash SIZE ] [ mask MASK ] [ shift SHIFT ]\n"); + fprintf(stderr, " [ pass_on | fall_through ]\n"); + fprintf(stderr," [ classid CLASSID ] [ action ACTION_SPEC ]\n"); } static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc, @@ -32,7 +30,7 @@ static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc, char *end; if (handle) { - t->tcm_handle = strtoul(handle,&end,0); + t->tcm_handle = strtoul(handle, &end, 0); if (*end) { fprintf(stderr, "Illegal filter ID\n"); return -1; @@ -40,81 +38,73 @@ static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc, } if (!argc) return 0; tail = NLMSG_TAIL(n); - addattr_l(n,4096,TCA_OPTIONS,NULL,0); + addattr_l(n, 4096, TCA_OPTIONS, NULL, 0); while (argc) { - if (!strcmp(*argv,"hash")) { + if (!strcmp(*argv, "hash")) { int hash; NEXT_ARG(); - hash = strtoul(*argv,&end,0); + hash = strtoul(*argv, &end, 0); if (*end || !hash || hash > 0x10000) { explain(); return -1; } - addattr_l(n,4096,TCA_TCINDEX_HASH,&hash,sizeof(hash)); - } - else if (!strcmp(*argv,"mask")) { + addattr_l(n, 4096, TCA_TCINDEX_HASH, &hash, sizeof(hash)); + } else if (!strcmp(*argv,"mask")) { __u16 mask; NEXT_ARG(); - mask = strtoul(*argv,&end,0); + mask = strtoul(*argv, &end, 0); if (*end) { explain(); return -1; } - addattr_l(n,4096,TCA_TCINDEX_MASK,&mask,sizeof(mask)); - } - else if (!strcmp(*argv,"shift")) { + addattr_l(n, 4096, TCA_TCINDEX_MASK, &mask, sizeof(mask)); + } else if (!strcmp(*argv,"shift")) { int shift; NEXT_ARG(); - shift = strtoul(*argv,&end,0); + shift = strtoul(*argv, &end, 0); if (*end) { explain(); return -1; } - addattr_l(n,4096,TCA_TCINDEX_SHIFT,&shift, + addattr_l(n, 4096, TCA_TCINDEX_SHIFT, &shift, sizeof(shift)); - } - else if (!strcmp(*argv,"fall_through")) { + } else if (!strcmp(*argv,"fall_through")) { int value = 1; - addattr_l(n,4096,TCA_TCINDEX_FALL_THROUGH,&value, + addattr_l(n, 4096, TCA_TCINDEX_FALL_THROUGH, &value, sizeof(value)); - } - else if (!strcmp(*argv,"pass_on")) { + } else if (!strcmp(*argv,"pass_on")) { int value = 0; - addattr_l(n,4096,TCA_TCINDEX_FALL_THROUGH,&value, + addattr_l(n, 4096, TCA_TCINDEX_FALL_THROUGH, &value, sizeof(value)); - } - else if (!strcmp(*argv,"classid")) { + } else if (!strcmp(*argv,"classid")) { __u32 handle; NEXT_ARG(); - if (get_tc_classid(&handle,*argv)) { + if (get_tc_classid(&handle, *argv)) { fprintf(stderr, "Illegal \"classid\"\n"); return -1; } addattr_l(n, 4096, TCA_TCINDEX_CLASSID, &handle, 4); - } - else if (!strcmp(*argv,"police")) { + } else if (!strcmp(*argv,"police")) { NEXT_ARG(); if (parse_police(&argc, &argv, TCA_TCINDEX_POLICE, n)) { fprintf(stderr, "Illegal \"police\"\n"); return -1; } continue; - } - else if (!strcmp(*argv,"action")) { + } else if (!strcmp(*argv,"action")) { NEXT_ARG(); if (parse_police(&argc, &argv, TCA_TCINDEX_ACT, n)) { fprintf(stderr, "Illegal \"action\"\n"); return -1; } continue; - } - else { + } else { explain(); return -1; } @@ -136,14 +126,14 @@ static int tcindex_print_opt(struct filter_util *qu, FILE *f, parse_rtattr_nested(tb, TCA_TCINDEX_MAX, opt); - if (handle != ~0) fprintf(f,"handle 0x%04x ",handle); + if (handle != ~0) fprintf(f, "handle 0x%04x ", handle); if (tb[TCA_TCINDEX_HASH]) { __u16 hash; if (RTA_PAYLOAD(tb[TCA_TCINDEX_HASH]) < sizeof(hash)) return -1; hash = rta_getattr_u16(tb[TCA_TCINDEX_HASH]); - fprintf(f,"hash %d ",hash); + fprintf(f, "hash %d ", hash); } if (tb[TCA_TCINDEX_MASK]) { __u16 mask; @@ -151,7 +141,7 @@ static int tcindex_print_opt(struct filter_util *qu, FILE *f, if (RTA_PAYLOAD(tb[TCA_TCINDEX_MASK]) < sizeof(mask)) return -1; mask = rta_getattr_u16(tb[TCA_TCINDEX_MASK]); - fprintf(f,"mask 0x%04x ",mask); + fprintf(f, "mask 0x%04x ", mask); } if (tb[TCA_TCINDEX_SHIFT]) { int shift; @@ -159,7 +149,7 @@ static int tcindex_print_opt(struct filter_util *qu, FILE *f, if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT]) < sizeof(shift)) return -1; shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT]); - fprintf(f,"shift %d ",shift); + fprintf(f, "shift %d ", shift); } if (tb[TCA_TCINDEX_FALL_THROUGH]) { int fall_through; @@ -168,11 +158,11 @@ static int tcindex_print_opt(struct filter_util *qu, FILE *f, sizeof(fall_through)) return -1; fall_through = *(int *) RTA_DATA(tb[TCA_TCINDEX_FALL_THROUGH]); - fprintf(f,fall_through ? "fall_through " : "pass_on "); + fprintf(f, fall_through ? "fall_through " : "pass_on "); } if (tb[TCA_TCINDEX_CLASSID]) { SPRINT_BUF(b1); - fprintf(f, "classid %s ",sprint_tc_classid(*(__u32 *) + fprintf(f, "classid %s ", sprint_tc_classid(*(__u32 *) RTA_DATA(tb[TCA_TCINDEX_CLASSID]), b1)); } if (tb[TCA_TCINDEX_POLICE]) { diff --git a/tc/f_u32.c b/tc/f_u32.c index 5ca60c89d..629951539 100644 --- a/tc/f_u32.c +++ b/tc/f_u32.c @@ -30,17 +30,14 @@ extern int show_pretty; static void explain(void) { - fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ]" - " [ classid CLASSID ]\n"); - fprintf(stderr, " [ action ACTION_SPEC ]" - " [ offset OFFSET_SPEC ]\n"); + fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n"); + fprintf(stderr, " [ action ACTION_SPEC ] [ offset OFFSET_SPEC ]\n"); fprintf(stderr, " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n"); fprintf(stderr, " [ sample SAMPLE ]\n"); fprintf(stderr, "or u32 divisor DIVISOR\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n"); - fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp |" - " u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n"); + fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n"); fprintf(stderr, " FILTERID := X:Y:Z\n"); fprintf(stderr, "\nNOTE: CLASSID is parsed at hexadecimal input.\n"); } @@ -94,17 +91,20 @@ static char *sprint_u32_handle(__u32 handle, char *buf) } if (htid) { int l = snprintf(b, bsize, "%x:", htid>>20); + bsize -= l; b += l; } if (nodeid|hash) { if (hash) { int l = snprintf(b, bsize, "%x", hash); + bsize -= l; b += l; } if (nodeid) { int l = snprintf(b, bsize, ":%x", nodeid); + bsize -= l; b += l; } @@ -390,6 +390,7 @@ static int parse_ip6_addr(int *argc_p, char ***argv_p, return -1; } else if (i < plen) { __u32 mask = htonl(0xFFFFFFFF << (32 - (plen - i))); + res = pack_key(sel, addr.data[i / 32], mask, off + 4 * (i / 32), offmask); if (res < 0) @@ -712,7 +713,7 @@ static int parse_selector(int *argc_p, char ***argv_p, } else if (matches(*argv, "ip") == 0) { NEXT_ARG(); res = parse_ip(&argc, &argv, sel); - } else if (matches(*argv, "ip6") == 0) { + } else if (matches(*argv, "ip6") == 0) { NEXT_ARG(); res = parse_ip6(&argc, &argv, sel); } else if (matches(*argv, "udp") == 0) { @@ -746,6 +747,7 @@ static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) while (argc > 0) { if (matches(*argv, "plus") == 0) { int off; + NEXT_ARG(); if (get_integer(&off, *argv, 0)) return -1; @@ -753,6 +755,7 @@ static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) sel->flags |= TC_U32_OFFSET; } else if (matches(*argv, "at") == 0) { int off; + NEXT_ARG(); if (get_integer(&off, *argv, 0)) return -1; @@ -764,6 +767,7 @@ static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) sel->flags |= TC_U32_VAROFFSET; } else if (matches(*argv, "mask") == 0) { __u16 mask; + NEXT_ARG(); if (get_u16(&mask, *argv, 16)) return -1; @@ -771,6 +775,7 @@ static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) sel->flags |= TC_U32_VAROFFSET; } else if (matches(*argv, "shift") == 0) { int shift; + NEXT_ARG(); if (get_integer(&shift, *argv, 0)) return -1; @@ -797,12 +802,14 @@ static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) while (argc > 0) { if (matches(*argv, "mask") == 0) { __u32 mask; + NEXT_ARG(); if (get_u32(&mask, *argv, 16)) return -1; sel->hmask = htonl(mask); } else if (matches(*argv, "at") == 0) { int num; + NEXT_ARG(); if (get_integer(&num, *argv, 0)) return -1; @@ -844,6 +851,7 @@ static void print_ipv4(FILE *f, const struct tc_u32_key *key) case 12: case 16: { int bits = mask2bits(key->mask); + if (bits >= 0) { fprintf(f, "\n %s %s/%d", key->off == 12 ? "match IP src" : "match IP dst", @@ -900,6 +908,7 @@ static void print_ipv6(FILE *f, const struct tc_u32_key *key) case 12: case 16: { int bits = mask2bits(key->mask); + if (bits >= 0) { fprintf(f, "\n %s %s/%d", key->off == 12 ? "match IP src" : "match IP dst", @@ -946,7 +955,7 @@ static const struct { __u16 pad; void (*pprinter)(FILE *f, const struct tc_u32_key *key); } u32_pprinters[] = { - {0, 0, print_raw}, + {0, 0, print_raw}, {ETH_P_IP, 0, print_ipv4}, {ETH_P_IPV6, 0, print_ipv6}, }; @@ -958,7 +967,7 @@ static void show_keys(FILE *f, const struct tc_u32_key *key) if (!show_pretty) goto show_k; - for (i = 0; i < sizeof(u32_pprinters) / sizeof(u32_pprinters[0]); i++) { + for (i = 0; i < ARRAY_SIZE(u32_pprinters); i++) { if (u32_pprinters[i].proto == ntohs(f_proto)) { show_k: u32_pprinters[i].pprinter(f, key); @@ -1022,7 +1031,8 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, continue; } else if (matches(*argv, "classid") == 0 || strcmp(*argv, "flowid") == 0) { - unsigned handle; + unsigned int handle; + NEXT_ARG(); if (get_tc_classid(&handle, *argv)) { fprintf(stderr, "Illegal \"classid\"\n"); @@ -1031,7 +1041,8 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &handle, 4); sel.sel.flags |= TC_U32_TERMINAL; } else if (matches(*argv, "divisor") == 0) { - unsigned divisor; + unsigned int divisor; + NEXT_ARG(); if (get_unsigned(&divisor, *argv, 0) || divisor == 0 || @@ -1047,7 +1058,8 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, return -1; } } else if (strcmp(*argv, "link") == 0) { - unsigned handle; + unsigned int handle; + NEXT_ARG(); if (get_u32_handle(&handle, *argv)) { fprintf(stderr, "Illegal \"link\"\n"); @@ -1059,7 +1071,8 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, } addattr_l(n, MAX_MSG, TCA_U32_LINK, &handle, 4); } else if (strcmp(*argv, "ht") == 0) { - unsigned handle; + unsigned int handle; + NEXT_ARG(); if (get_u32_handle(&handle, *argv)) { fprintf(stderr, "Illegal \"ht\"\n"); @@ -1075,7 +1088,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, htid = (handle & 0xFFFFF000); } else if (strcmp(*argv, "sample") == 0) { __u32 hash; - unsigned divisor = 0x100; + unsigned int divisor = 0x100; struct { struct tc_u32_sel sel; @@ -1088,8 +1101,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, return -1; } if (sel2.sel.nkeys != 1) { - fprintf(stderr, "\"sample\" must contain" - " exactly ONE key.\n"); + fprintf(stderr, "\"sample\" must contain exactly ONE key.\n"); return -1; } if (*argv != 0 && strcmp(*argv, "divisor") == 0) { @@ -1109,6 +1121,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, continue; } else if (strcmp(*argv, "indev") == 0) { char ind[IFNAMSIZ + 1]; + memset(ind, 0, sizeof(ind)); argc--; argv++; @@ -1199,6 +1212,7 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, fprintf(f, "ht divisor %d ", rta_getattr_u32(tb[TCA_U32_DIVISOR])); } else if (tb[TCA_U32_HASH]) { __u32 htid = rta_getattr_u32(tb[TCA_U32_HASH]); + fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid), TC_U32_HASH(htid)); } else { @@ -1220,7 +1234,7 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, if (tb[TCA_U32_PCNT]) { if (RTA_PAYLOAD(tb[TCA_U32_PCNT]) < sizeof(*pf)) { - fprintf(f, "Broken perf counters \n"); + fprintf(f, "Broken perf counters\n"); return -1; } pf = RTA_DATA(tb[TCA_U32_PCNT]); @@ -1233,6 +1247,7 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, if (tb[TCA_U32_MARK]) { struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]); + if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) { fprintf(f, "\n Invalid mark (kernel&iproute2 mismatch)\n"); } else { @@ -1244,6 +1259,7 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, if (sel) { if (sel->nkeys) { int i; + for (i = 0; i < sel->nkeys; i++) { show_keys(f, sel->keys + i); if (show_stats && NULL != pf) @@ -1276,6 +1292,7 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, } if (tb[TCA_U32_INDEV]) { struct rtattr *idev = tb[TCA_U32_INDEV]; + fprintf(f, "\n input dev %s\n", rta_getattr_str(idev)); } if (tb[TCA_U32_ACT]) { diff --git a/tc/m_action.c b/tc/m_action.c index f88ff3a1b..5c47c8252 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -28,11 +28,11 @@ #include "tc_common.h" #include "tc_util.h" -static struct action_util * action_list; +static struct action_util *action_list; #ifdef CONFIG_GACT -int gact_ld = 0 ; //fuckin backward compatibility +int gact_ld; /* f*ckin backward compatibility */ #endif -int tab_flush = 0; +int tab_flush; static void act_usage(void) { @@ -43,10 +43,10 @@ static void act_usage(void) * does that, they would know how to fix this .. * */ - fprintf (stderr, "usage: tc actions *\n"); + fprintf(stderr, "usage: tc actions *\n"); fprintf(stderr, "Where: \tACTSPECOP := ACR | GD | FL\n" - "\tACR := add | change | replace * \n" + "\tACR := add | change | replace *\n" "\tGD := get | delete | *\n" "\tFL := ls | list | flush | \n" "\tACTNAMESPEC := action \n" @@ -65,7 +65,7 @@ static int print_noaopt(struct action_util *au, FILE *f, struct rtattr *opt) { if (opt && RTA_PAYLOAD(opt)) fprintf(f, "[Unknown action, optlen=%u] ", - (unsigned) RTA_PAYLOAD(opt)); + (unsigned int) RTA_PAYLOAD(opt)); return 0; } @@ -122,7 +122,7 @@ static struct action_util *get_action_kind(char *str) #ifdef CONFIG_GACT if (!looked4gact) { looked4gact = 1; - strcpy(str,"gact"); + strcpy(str, "gact"); goto restart_s; } #endif @@ -141,9 +141,9 @@ static int new_cmd(char **argv) { if ((matches(*argv, "change") == 0) || - (matches(*argv, "replace") == 0)|| - (matches(*argv, "delete") == 0)|| - (matches(*argv, "get") == 0)|| + (matches(*argv, "replace") == 0) || + (matches(*argv, "delete") == 0) || + (matches(*argv, "get") == 0) || (matches(*argv, "add") == 0)) return 1; @@ -173,9 +173,9 @@ parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) while (argc > 0) { - memset(k, 0, sizeof (k)); + memset(k, 0, sizeof(k)); - if (strcmp(*argv, "action") == 0 ) { + if (strcmp(*argv, "action") == 0) { argc--; argv++; eap = 1; @@ -195,9 +195,10 @@ parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) goto done0; } else { struct action_util *a = NULL; - strncpy(k, *argv, sizeof (k) - 1); + + strncpy(k, *argv, sizeof(k) - 1); eap = 0; - if (argc > 0 ) { + if (argc > 0) { a = get_action_kind(k); } else { done0: @@ -207,7 +208,7 @@ parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) goto done; } - if (NULL == a) { + if (a == NULL) { goto bad_val; } @@ -215,10 +216,10 @@ parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) addattr_l(n, MAX_MSG, ++prio, NULL, 0); addattr_l(n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1); - ret = a->parse_aopt(a,&argc, &argv, TCA_ACT_OPTIONS, n); + ret = a->parse_aopt(a, &argc, &argv, TCA_ACT_OPTIONS, n); if (ret < 0) { - fprintf(stderr,"bad action parsing\n"); + fprintf(stderr, "bad action parsing\n"); goto bad_val; } tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; @@ -228,7 +229,7 @@ parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) } if (eap > 0) { - fprintf(stderr,"bad action empty %d\n",eap); + fprintf(stderr, "bad action empty %d\n", eap); goto bad_val; } @@ -241,12 +242,12 @@ parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) bad_val: /* no need to undo things, returning from here should * cause enough pain */ - fprintf(stderr, "parse_action: bad value (%d:%s)!\n",argc,*argv); + fprintf(stderr, "parse_action: bad value (%d:%s)!\n", argc, *argv); return -1; } static int -tc_print_one_action(FILE * f, struct rtattr *arg) +tc_print_one_action(FILE *f, struct rtattr *arg) { struct rtattr *tb[TCA_ACT_MAX + 1]; @@ -265,12 +266,12 @@ tc_print_one_action(FILE * f, struct rtattr *arg) a = get_action_kind(RTA_DATA(tb[TCA_ACT_KIND])); - if (NULL == a) + if (a == NULL) return err; err = a->print_aopt(a, f, tb[TCA_ACT_OPTIONS]); - if (0 > err) + if (err < 0) return err; if (show_stats && tb[TCA_ACT_STATS]) { @@ -299,11 +300,11 @@ tc_print_action_flush(FILE *f, const struct rtattr *arg) } a = get_action_kind(RTA_DATA(tb[TCA_KIND])); - if (NULL == a) + if (a == NULL) return err; delete_count = RTA_DATA(tb[TCA_FCNT]); - fprintf(f," %s (%d entries)\n", a->id, *delete_count); + fprintf(f, " %s (%d entries)\n", a->id, *delete_count); tab_flush = 0; return 0; } @@ -326,7 +327,7 @@ tc_print_action(FILE *f, const struct rtattr *arg) for (i = 0; i < TCA_ACT_MAX_PRIO; i++) { if (tb[i]) { fprintf(f, "\n\taction order %d: ", i); - if (0 > tc_print_one_action(f, tb[i])) { + if (tc_print_one_action(f, tb[i]) < 0) { fprintf(f, "Error printing action\n"); } } @@ -340,10 +341,10 @@ int print_action(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct tcamsg *t = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[TCAA_MAX+1]; + struct rtattr *tb[TCAA_MAX+1]; len -= NLMSG_LENGTH(sizeof(*t)); @@ -354,7 +355,7 @@ int print_action(const struct sockaddr_nl *who, parse_rtattr(tb, TCAA_MAX, TA_RTA(t), len); - if (NULL == tb[TCA_ACT_TAB]) { + if (tb[TCA_ACT_TAB] == NULL) { if (n->nlmsg_type != RTM_GETACTION) fprintf(stderr, "print_action: NULL kind\n"); return -1; @@ -376,7 +377,7 @@ int print_action(const struct sockaddr_nl *who, return 0; } -static int tc_action_gd(int cmd, unsigned 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[16]; struct action_util *a = NULL; @@ -406,15 +407,15 @@ static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p) req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; - argc -=1; - argv +=1; + argc -= 1; + argv += 1; tail = NLMSG_TAIL(&req.n); addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0); while (argc > 0) { - if (strcmp(*argv, "action") == 0 ) { + if (strcmp(*argv, "action") == 0) { argc--; argv++; continue; @@ -422,23 +423,23 @@ static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p) return -1; } - strncpy(k, *argv, sizeof (k) - 1); + strncpy(k, *argv, sizeof(k) - 1); a = get_action_kind(k); - if (NULL == a) { - fprintf(stderr, "Error: non existent action: %s\n",k); + if (a == NULL) { + fprintf(stderr, "Error: non existent action: %s\n", k); ret = -1; goto bad_val; } if (strcmp(a->id, k) != 0) { - fprintf(stderr, "Error: non existent action: %s\n",k); + fprintf(stderr, "Error: non existent action: %s\n", k); ret = -1; goto bad_val; } - argc -=1; - argv +=1; + 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; } @@ -450,10 +451,10 @@ static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p) ret = -1; goto bad_val; } - argc -=1; - argv +=1; + 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; } @@ -477,7 +478,7 @@ static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p) return 1; } - if (ans && print_action(NULL, &req.n, (void*)stdout) < 0) { + if (ans && print_action(NULL, &req.n, (void *)stdout) < 0) { fprintf(stderr, "Dump terminated\n"); return 1; } @@ -488,7 +489,7 @@ static int tc_action_gd(int cmd, unsigned flags, int *argc_p, char ***argv_p) return ret; } -static int tc_action_modify(int cmd, unsigned 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; @@ -509,8 +510,8 @@ static int tc_action_modify(int cmd, unsigned flags, int *argc_p, char ***argv_p req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; tail = NLMSG_TAIL(&req.n); - argc -=1; - argv +=1; + argc -= 1; + argv += 1; if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) { fprintf(stderr, "Illegal \"action\"\n"); return -1; @@ -532,7 +533,7 @@ static int tc_act_list_or_flush(int argc, char **argv, int event) { int ret = 0, prio = 0, msg_size = 0; char k[16]; - struct rtattr *tail,*tail2; + struct rtattr *tail, *tail2; struct action_util *a = NULL; struct { struct nlmsghdr n; @@ -550,22 +551,22 @@ static int tc_act_list_or_flush(int argc, char **argv, int event) addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0); tail2 = NLMSG_TAIL(&req.n); - strncpy(k, *argv, sizeof (k) - 1); + strncpy(k, *argv, sizeof(k) - 1); #ifdef CONFIG_GACT if (!gact_ld) { get_action_kind("gact"); } #endif a = get_action_kind(k); - if (NULL == a) { - fprintf(stderr,"bad action %s\n",k); + if (a == NULL) { + fprintf(stderr, "bad action %s\n", k); goto bad_val; } if (strcmp(a->id, k) != 0) { - fprintf(stderr,"bad action %s\n",k); + fprintf(stderr, "bad action %s\n", k); goto bad_val; } - strncpy(k, *argv, sizeof (k) - 1); + strncpy(k, *argv, sizeof(k) - 1); addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0); addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1); @@ -612,12 +613,12 @@ int do_action(int argc, char **argv) matches(*argv, "replace") == 0) { ret = tc_action_modify(RTM_NEWACTION, NLM_F_CREATE|NLM_F_REPLACE, &argc, &argv); } else if (matches(*argv, "delete") == 0) { - argc -=1; - argv +=1; + argc -= 1; + argv += 1; ret = tc_action_gd(RTM_DELACTION, 0, &argc, &argv); } else if (matches(*argv, "get") == 0) { - argc -=1; - argv +=1; + 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) { diff --git a/tc/m_bpf.c b/tc/m_bpf.c index c5e2fa5b0..37cd0d80b 100644 --- a/tc/m_bpf.c +++ b/tc/m_bpf.c @@ -156,6 +156,7 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg) { struct rtattr *tb[TCA_ACT_BPF_MAX + 1]; struct tc_act_bpf *parm; + SPRINT_BUF(action_buf); if (arg == NULL) @@ -190,6 +191,7 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg) if (show_stats) { if (tb[TCA_ACT_BPF_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_ACT_BPF_TM]); + print_tm(f, tm); } } diff --git a/tc/m_connmark.c b/tc/m_connmark.c index 6974c9ba6..2414f321c 100644 --- a/tc/m_connmark.c +++ b/tc/m_connmark.c @@ -151,6 +151,7 @@ static int print_connmark(struct action_util *au, FILE *f, struct rtattr *arg) if (show_stats) { if (tb[TCA_CONNMARK_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_CONNMARK_TM]); + print_tm(f, tm); } } diff --git a/tc/m_csum.c b/tc/m_csum.c index f7da6f0a2..36181fa1c 100644 --- a/tc/m_csum.c +++ b/tc/m_csum.c @@ -24,8 +24,7 @@ explain(void) { fprintf(stderr, "Usage: ... csum \n" "Where: UPDATE := []\n" - " TARGET := { ip4h | icmp | igmp |" - " tcp | udp | udplite | }\n" + " TARGET := { ip4h | icmp | igmp | tcp | udp | udplite | }\n" " SWEETS := { and | or | \'+\' }\n"); } @@ -45,7 +44,7 @@ parse_csum_args(int *argc_p, char ***argv_p, struct tc_csum *sel) if (argc <= 0) return -1; - while(argc > 0) { + while (argc > 0) { if ((matches(*argv, "iph") == 0) || (matches(*argv, "ip4h") == 0) || (matches(*argv, "ipv4h") == 0)) @@ -108,8 +107,7 @@ parse_csum(struct action_util *a, int *argc_p, continue; } else if (matches(*argv, "help") == 0) { usage(); - } - else { + } else { break; } } @@ -174,7 +172,7 @@ parse_csum(struct action_util *a, int *argc_p, } static int -print_csum(struct action_util *au, FILE * f, struct rtattr *arg) +print_csum(struct action_util *au, FILE *f, struct rtattr *arg) { struct tc_csum *sel; @@ -186,6 +184,7 @@ print_csum(struct action_util *au, FILE * f, struct rtattr *arg) char *uflag_4 = ""; char *uflag_5 = ""; char *uflag_6 = ""; + SPRINT_BUF(action_buf); int uflag_count = 0; @@ -212,7 +211,7 @@ print_csum(struct action_util *au, FILE * f, struct rtattr *arg) ", " flag_string : flag_string; \ uflag_count++; \ } \ - } while(0) + } while (0) CSUM_UFLAG_BUFFER(uflag_2, TCA_CSUM_UPDATE_FLAG_ICMP, "icmp"); CSUM_UFLAG_BUFFER(uflag_3, TCA_CSUM_UPDATE_FLAG_IGMP, "igmp"); CSUM_UFLAG_BUFFER(uflag_4, TCA_CSUM_UPDATE_FLAG_TCP, "tcp"); @@ -231,7 +230,8 @@ print_csum(struct action_util *au, FILE * f, struct rtattr *arg) if (show_stats) { if (tb[TCA_CSUM_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_CSUM_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } fprintf(f, "\n"); diff --git a/tc/m_ematch.c b/tc/m_ematch.c index 4c3acf82b..251f5aa19 100644 --- a/tc/m_ematch.c +++ b/tc/m_ematch.c @@ -33,7 +33,7 @@ static struct ematch_util *ematch_list; /* export to bison parser */ int ematch_argc; char **ematch_argv; -char *ematch_err = NULL; +char *ematch_err; struct ematch *ematch_root; static int begin_argc; @@ -188,6 +188,7 @@ static int parse_tree(struct nlmsghdr *n, struct ematch *tree) if (t->child) { __u32 r = t->child_ref; + addraw_l(n, MAX_MSG, &hdr, sizeof(hdr)); addraw_l(n, MAX_MSG, &r, sizeof(r)); } else { @@ -198,7 +199,7 @@ static int parse_tree(struct nlmsghdr *n, struct ematch *tree) if (t->args == NULL) return -1; - strncpy(buf, (char*) t->args->data, sizeof(buf)-1); + strncpy(buf, (char *) t->args->data, sizeof(buf)-1); e = get_ematch_kind(buf); if (e == NULL) { fprintf(stderr, "Unknown ematch \"%s\"\n", @@ -218,7 +219,7 @@ static int parse_tree(struct nlmsghdr *n, struct ematch *tree) return -1; } - tail->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail; + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; } return 0; @@ -353,8 +354,8 @@ int parse_ematch(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) if (parse_tree(n, ematch_root) < 0) return -1; - tail_list->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail_list; - tail->rta_len = (void*) NLMSG_TAIL(n) - (void*) tail; + tail_list->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail_list; + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; } *argc_p = ematch_argc; @@ -492,7 +493,7 @@ int print_ematch(FILE *fd, const struct rtattr *rta) return print_ematch_list(fd, hdr, tb[TCA_EMATCH_TREE_LIST]); } -struct bstr * bstr_alloc(const char *text) +struct bstr *bstr_alloc(const char *text) { struct bstr *b = calloc(1, sizeof(*b)); @@ -558,6 +559,7 @@ void print_ematch_tree(const struct ematch *tree) printf(")"); } else { struct bstr *b; + for (b = t->args; b; b = b->next) printf("%s%s", b->data, b->next ? " " : ""); } diff --git a/tc/m_estimator.c b/tc/m_estimator.c index 3dc8624ff..87745cc2d 100644 --- a/tc/m_estimator.c +++ b/tc/m_estimator.c @@ -38,7 +38,7 @@ int parse_estimator(int *p_argc, char ***p_argv, struct tc_estimator *est) { int argc = *p_argc; char **argv = *p_argv; - unsigned A, time_const; + unsigned int A, time_const; NEXT_ARG(); if (est->ewma_log) diff --git a/tc/m_gact.c b/tc/m_gact.c index 94bd5e736..b22ce1915 100644 --- a/tc/m_gact.c +++ b/tc/m_gact.c @@ -45,16 +45,16 @@ explain(void) #ifdef CONFIG_GACT_PROB fprintf(stderr, "Usage: ... gact [RAND] [INDEX]\n"); fprintf(stderr, - "Where: \tACTION := reclassify | drop | continue | pass \n" - "\tRAND := random \n" - "\tRANDTYPE := netrand | determ\n" + "Where: \tACTION := reclassify | drop | continue | pass\n" + "\tRAND := random \n" + "\tRANDTYPE := netrand | determ\n" "\tVAL : = value not exceeding 10000\n" "\tINDEX := index value used\n" "\n"); #else fprintf(stderr, "Usage: ... gact [INDEX]\n"); fprintf(stderr, - "Where: \tACTION := reclassify | drop | continue | pass \n" + "Where: \tACTION := reclassify | drop | continue | pass\n" "\tINDEX := index value used\n" "\n"); #endif @@ -84,7 +84,7 @@ get_act(char ***argv_p) } else if (matches(*argv, "pass") == 0 || matches(*argv, "ok") == 0) { return TC_ACT_OK; } else { - fprintf(stderr,"bad action type %s\n",*argv); + fprintf(stderr, "bad action type %s\n", *argv); return -10; } } @@ -104,7 +104,7 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, #endif struct rtattr *tail; - memset(&p, 0, sizeof (p)); + memset(&p, 0, sizeof(p)); p.action = TC_POLICE_RECLASSIFY; if (argc < 0) @@ -155,11 +155,11 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, argc--; argv++; 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--; @@ -190,10 +190,10 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); - addattr_l(n, MAX_MSG, TCA_GACT_PARMS, &p, sizeof (p)); + addattr_l(n, MAX_MSG, TCA_GACT_PARMS, &p, sizeof(p)); #ifdef CONFIG_GACT_PROB if (rd) { - addattr_l(n, MAX_MSG, TCA_GACT_PROB, &pp, sizeof (pp)); + addattr_l(n, MAX_MSG, TCA_GACT_PROB, &pp, sizeof(pp)); } #endif tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; @@ -204,7 +204,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) { SPRINT_BUF(b1); #ifdef CONFIG_GACT_PROB @@ -226,22 +226,23 @@ print_gact(struct action_util *au,FILE * f, struct rtattr *arg) } p = RTA_DATA(tb[TCA_GACT_PARMS]); - fprintf(f, "gact action %s", action_n2a(p->action, b1, sizeof (b1))); + fprintf(f, "gact action %s", action_n2a(p->action, b1, sizeof(b1))); #ifdef CONFIG_GACT_PROB - if (NULL != tb[TCA_GACT_PROB]) { + if (tb[TCA_GACT_PROB] != NULL) { pp = RTA_DATA(tb[TCA_GACT_PROB]); } else { /* need to keep consistent output */ - memset(&pp_dummy, 0, sizeof (pp_dummy)); + memset(&pp_dummy, 0, sizeof(pp_dummy)); pp = &pp_dummy; } - fprintf(f, "\n\t random type %s %s val %d",prob_n2a(pp->ptype), action_n2a(pp->paction, b2, sizeof (b2)), pp->pval); + fprintf(f, "\n\t random type %s %s val %d", prob_n2a(pp->ptype), action_n2a(pp->paction, b2, sizeof (b2)), pp->pval); #endif - fprintf(f, "\n\t index %d ref %d bind %d",p->index, p->refcnt, p->bindcnt); + fprintf(f, "\n\t index %d ref %d bind %d", p->index, p->refcnt, p->bindcnt); if (show_stats) { if (tb[TCA_GACT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_GACT_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } fprintf(f, "\n "); diff --git a/tc/m_ipt.c b/tc/m_ipt.c index 948becbc3..d088f5ed6 100644 --- a/tc/m_ipt.c +++ b/tc/m_ipt.c @@ -51,9 +51,9 @@ static struct option original_opts[] = { {0, 0, 0, 0} }; -static struct iptables_target *t_list = NULL; +static struct iptables_target *t_list; static struct option *opts = original_opts; -static unsigned int global_option_offset = 0; +static unsigned int global_option_offset; #define OPTION_OFFSET 256 char *lib_dir; @@ -61,7 +61,7 @@ char *lib_dir; void register_target(struct iptables_target *me) { -/* fprintf(stderr, "\nDummy register_target %s \n", me->name); +/* fprintf(stderr, "\nDummy register_target %s\n", me->name); */ me->next = t_list; t_list = me; @@ -177,18 +177,18 @@ merge_options(struct option *oldopts, const struct option *newopts, struct option *merge; unsigned int num_old, num_new, i; - for (num_old = 0; oldopts[num_old].name; num_old++) ; - for (num_new = 0; newopts[num_new].name; num_new++) ; + for (num_old = 0; oldopts[num_old].name; num_old++); + for (num_new = 0; newopts[num_new].name; num_new++); *option_offset = global_option_offset + OPTION_OFFSET; - merge = malloc(sizeof (struct option) * (num_new + num_old + 1)); - memcpy(merge, oldopts, num_old * sizeof (struct option)); + merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); + memcpy(merge, oldopts, num_old * sizeof(struct option)); for (i = 0; i < num_new; i++) { merge[num_old + i] = newopts[i]; merge[num_old + i].val += *option_offset; } - memset(merge + num_old + num_new, 0, sizeof (struct option)); + memset(merge + num_old + num_new, 0, sizeof(struct option)); return merge; } @@ -209,6 +209,7 @@ static struct iptables_target * find_t(char *name) { struct iptables_target *m; + for (m = t_list; m; m = m->next) { if (strcmp(m->name, name) == 0) return m; @@ -224,7 +225,7 @@ get_target_name(const char *name) char *error; char *new_name, *lname; struct iptables_target *m; - char path[strlen(lib_dir) + sizeof ("/libipt_.so") + strlen(name)]; + char path[strlen(lib_dir) + sizeof("/libipt_.so") + strlen(name)]; #ifdef NO_SHARED_LIBS return NULL; @@ -247,6 +248,7 @@ get_target_name(const char *name) if (isupper(lname[0])) { int i; + for (i = 0; i < strlen(name); i++) { lname[i] = tolower(lname[i]); } @@ -254,6 +256,7 @@ get_target_name(const char *name) if (islower(new_name[0])) { int i; + for (i = 0; i < strlen(new_name); i++) { new_name[i] = toupper(new_name[i]); } @@ -268,12 +271,12 @@ get_target_name(const char *name) handle = dlopen(path, RTLD_LAZY); if (!handle) { - sprintf(path, "%s/libxt_%s.so", lib_dir , lname); + sprintf(path, "%s/libxt_%s.so", lib_dir, lname); handle = dlopen(path, RTLD_LAZY); } if (!handle) { - sprintf(path, "%s/libipt_%s.so", lib_dir , lname); + sprintf(path, "%s/libipt_%s.so", lib_dir, lname); handle = dlopen(path, RTLD_LAZY); } /* ok, lets give up .. */ @@ -291,9 +294,9 @@ get_target_name(const char *name) m = (struct iptables_target *) dlsym(handle, lname); if ((error = dlerror()) != NULL) { m = find_t(new_name); - if (NULL == m) { + if (m == NULL) { m = find_t(lname); - if (NULL == m) { + if (m == NULL) { fputs(error, stderr); fprintf(stderr, "\n"); dlclose(handle); @@ -321,7 +324,7 @@ struct in_addr *dotted_to_addr(const char *dotted) char buf[20]; /* copy dotted string, because we need to modify it */ - strncpy(buf, dotted, sizeof (buf) - 1); + strncpy(buf, dotted, sizeof(buf) - 1); addrp = (unsigned char *) &(addr.s_addr); p = buf; @@ -366,9 +369,9 @@ build_st(struct iptables_target *target, struct ipt_entry_target *t) size_t size; size = - IPT_ALIGN(sizeof (struct ipt_entry_target)) + target->size; + IPT_ALIGN(sizeof(struct ipt_entry_target)) + target->size; - if (NULL == t) { + if (t == NULL) { target->t = fw_calloc(1, size); target->t->u.target_size = size; @@ -385,7 +388,7 @@ build_st(struct iptables_target *target, struct ipt_entry_target *t) return -1; } -static int parse_ipt(struct action_util *a,int *argc_p, +static int parse_ipt(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { struct iptables_target *m = NULL; @@ -406,6 +409,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, { int i; + for (i = 0; i < rargc; i++) { if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) { break; @@ -415,7 +419,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } if (argc <= 2) { - fprintf(stderr,"bad arguments to ipt %d vs %d \n", argc, rargc); + fprintf(stderr, "bad arguments to ipt %d vs %d\n", argc, rargc); return -1; } @@ -426,29 +430,29 @@ static int parse_ipt(struct action_util *a,int *argc_p, switch (c) { case 'j': m = get_target_name(optarg); - if (NULL != m) { + if (m != NULL) { - if (0 > build_st(m, NULL)) { - printf(" %s error \n", m->name); + if (build_st(m, NULL) < 0) { + printf(" %s error\n", m->name); return -1; } opts = merge_options(opts, m->extra_opts, &m->option_offset); } else { - fprintf(stderr," failed to find target %s\n\n", optarg); + fprintf(stderr, " failed to find target %s\n\n", optarg); return -1; } ok++; break; default: - memset(&fw, 0, sizeof (fw)); + memset(&fw, 0, sizeof(fw)); if (m) { m->parse(c - m->option_offset, argv, 0, &m->tflags, NULL, &m->t); } else { - fprintf(stderr," failed to find target %s\n\n", optarg); + fprintf(stderr, " failed to find target %s\n\n", optarg); return -1; } @@ -472,7 +476,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } if (!ok && !iok) { - fprintf(stderr," ipt Parser BAD!! (%s)\n", *argv); + fprintf(stderr, " ipt Parser BAD!! (%s)\n", *argv); return -1; } @@ -482,6 +486,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, { struct tcmsg *t = NLMSG_DATA(n); + if (t->tcm_parent != TC_H_ROOT && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) { hook = NF_IP_PRE_ROUTING; @@ -522,11 +527,11 @@ static int parse_ipt(struct action_util *a,int *argc_p, optind = 0; free_opts(opts); /* Clear flags if target will be used again */ - m->tflags=0; - m->used=0; + m->tflags = 0; + m->used = 0; /* Free allocated memory */ - if (m->t) - free(m->t); + if (m->t) + free(m->t); return 0; @@ -534,7 +539,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } static int -print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) +print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) { struct rtattr *tb[TCA_IPT_MAX + 1]; struct ipt_entry_target *t = NULL; @@ -560,20 +565,22 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) return -1; } else { __u32 hook; + hook = rta_getattr_u32(tb[TCA_IPT_HOOK]); - fprintf(f, " hook: %s \n", ipthooks[hook]); + fprintf(f, " hook: %s\n", ipthooks[hook]); } if (tb[TCA_IPT_TARG] == NULL) { - fprintf(f, "\t[NULL ipt target parameters ] \n"); + fprintf(f, "\t[NULL ipt target parameters ]\n"); return -1; } else { struct iptables_target *m = NULL; + t = RTA_DATA(tb[TCA_IPT_TARG]); m = get_target_name(t->u.user.name); - if (NULL != m) { - if (0 > build_st(m, t)) { - fprintf(stderr, " %s error \n", m->name); + if (m != NULL) { + if (build_st(m, t) < 0) { + fprintf(stderr, " %s error\n", m->name); return -1; } @@ -591,21 +598,24 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) fprintf(f, " [NULL ipt target index ]\n"); } else { __u32 index; + index = rta_getattr_u32(tb[TCA_IPT_INDEX]); - fprintf(f, " \n\tindex %d", index); + fprintf(f, "\n\tindex %d", index); } if (tb[TCA_IPT_CNT]) { - struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]);; + struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]); + fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt); } if (show_stats) { if (tb[TCA_IPT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } - fprintf(f, " \n"); + fprintf(f, "\n"); } free_opts(opts); @@ -614,7 +624,7 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) } struct action_util ipt_action_util = { - .id = "ipt", - .parse_aopt = parse_ipt, - .print_aopt = print_ipt, + .id = "ipt", + .parse_aopt = parse_ipt, + .print_aopt = print_ipt, }; diff --git a/tc/m_mirred.c b/tc/m_mirred.c index dc231d7cd..e7e69dfcb 100644 --- a/tc/m_mirred.c +++ b/tc/m_mirred.c @@ -29,12 +29,12 @@ static void explain(void) { - fprintf(stderr, "Usage: mirred [index INDEX] \n"); - fprintf(stderr, "where: \n"); + 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, "\tDEVICENAME is the devicename\n"); } @@ -68,13 +68,13 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, int argc = *argc_p; char **argv = *argv_p; - int ok = 0, iok = 0, mirror=0,redir=0; + int ok = 0, iok = 0, mirror = 0, redir = 0; struct tc_mirred p; struct rtattr *tail; char d[16]; - memset(d,0,sizeof(d)-1); - memset(&p,0,sizeof(struct tc_mirred)); + memset(d, 0, sizeof(d)-1); + memset(&p, 0, sizeof(struct tc_mirred)); while (argc > 0) { @@ -98,12 +98,12 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, argv++; break; } - } else if(!ok) { + } else if (!ok) { fprintf(stderr, "was expecting egress (%s)\n", *argv); break; } else if (!mirror && matches(*argv, "mirror") == 0) { - mirror=1; + mirror = 1; if (redir) { fprintf(stderr, "Can't have both mirror and redir\n"); return -1; @@ -112,7 +112,7 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, p.action = TC_ACT_PIPE; ok++; } else if (!redir && matches(*argv, "redirect") == 0) { - redir=1; + redir = 1; if (mirror) { fprintf(stderr, "Can't have both mirror and redir\n"); return -1; @@ -145,6 +145,7 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, if (d[0]) { int idx; + ll_init_map(&rth); if ((idx = ll_name_to_index(d)) == 0) { @@ -197,7 +198,7 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); - addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof (p)); + addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof(p)); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; *argc_p = argc; @@ -215,20 +216,21 @@ parse_mirred(struct action_util *a, int *argc_p, char ***argv_p, char **argv = *argv_p; if (argc < 0) { - fprintf(stderr,"mirred bad argument count %d\n", argc); + fprintf(stderr, "mirred bad argument count %d\n", argc); return -1; } if (matches(*argv, "mirred") == 0) { NEXT_ARG(); } else { - fprintf(stderr,"mirred bad argument %s\n", *argv); + fprintf(stderr, "mirred bad argument %s\n", *argv); return -1; } if (matches(*argv, "egress") == 0 || matches(*argv, "index") == 0) { int ret = parse_egress(a, &argc, &argv, tca_id, n); + if (ret == 0) { *argc_p = argc; *argv_p = argv; @@ -236,11 +238,11 @@ parse_mirred(struct action_util *a, int *argc_p, char ***argv_p, } } else if (matches(*argv, "ingress") == 0) { - fprintf(stderr,"mirred ingress not supported at the moment\n"); + fprintf(stderr, "mirred ingress not supported at the moment\n"); } else if (matches(*argv, "help") == 0) { usage(); } else { - fprintf(stderr,"mirred option not supported %s\n", *argv); + fprintf(stderr, "mirred option not supported %s\n", *argv); } return -1; @@ -248,11 +250,12 @@ 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]; const char *dev; + SPRINT_BUF(b1); if (arg == NULL) @@ -276,15 +279,16 @@ print_mirred(struct action_util *au,FILE * f, struct rtattr *arg) return -1; } - fprintf(f, "mirred (%s to device %s) %s", mirred_n2a(p->eaction), dev,action_n2a(p->action, b1, sizeof (b1))); + fprintf(f, "mirred (%s to device %s) %s", mirred_n2a(p->eaction), dev, action_n2a(p->action, b1, sizeof (b1))); fprintf(f, "\n "); - fprintf(f, "\tindex %d ref %d bind %d",p->index,p->refcnt,p->bindcnt); + fprintf(f, "\tindex %d ref %d bind %d", p->index, p->refcnt, p->bindcnt); if (show_stats) { if (tb[TCA_MIRRED_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_MIRRED_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } fprintf(f, "\n "); diff --git a/tc/m_nat.c b/tc/m_nat.c index d502a819e..deb071da9 100644 --- a/tc/m_nat.c +++ b/tc/m_nat.c @@ -41,7 +41,7 @@ usage(void) } static int -parse_nat_args(int *argc_p, char ***argv_p,struct tc_nat *sel) +parse_nat_args(int *argc_p, char ***argv_p, struct tc_nat *sel) { int argc = *argc_p; char **argv = *argv_p; @@ -97,7 +97,7 @@ parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct if (matches(*argv, "nat") == 0) { NEXT_ARG(); if (parse_nat_args(&argc, &argv, &sel)) { - fprintf(stderr, "Illegal nat construct (%s) \n", + fprintf(stderr, "Illegal nat construct (%s)\n", *argv); explain(); return -1; @@ -165,12 +165,13 @@ parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct } static int -print_nat(struct action_util *au,FILE * f, struct rtattr *arg) +print_nat(struct action_util *au, FILE * f, struct rtattr *arg) { struct tc_nat *sel; struct rtattr *tb[TCA_NAT_MAX + 1]; char buf1[256]; char buf2[256]; + SPRINT_BUF(buf3); int len; @@ -193,12 +194,13 @@ print_nat(struct action_util *au,FILE * f, struct rtattr *arg) format_host(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)), len, format_host(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)), - action_n2a(sel->action, buf3, sizeof (buf3))); + action_n2a(sel->action, buf3, sizeof(buf3))); if (show_stats) { if (tb[TCA_NAT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_NAT_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } diff --git a/tc/m_pedit.c b/tc/m_pedit.c index a7960d524..ca78a83dd 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -38,15 +38,11 @@ explain(void) fprintf(stderr, "Usage: ... pedit munge []\n"); fprintf(stderr, "Where: MUNGE := |\n" - "\t:= [ATC]\n " - "\t\tOFFSETC:= offset \n " - "\t\tATC:= at offmask shift \n " - "\t\tNOTE: offval is byte offset, must be multiple of 4\n " - "\t\tNOTE: maskval is a 32 bit hex number\n " - "\t\tNOTE: shiftval is a is a shift value\n " - "\t\tCMD:= clear | invert | set | retain\n " - "\t:= ip | ip6 \n " - " \t\t| udp | tcp | icmp \n" + "\t:= [ATC]\n \t\tOFFSETC:= offset \n " + "\t\tATC:= at offmask shift \n \t\tNOTE: offval is byte offset, must be multiple of 4\n " + "\t\tNOTE: maskval is a 32 bit hex number\n \t\tNOTE: shiftval is a is a shift value\n " + "\t\tCMD:= clear | invert | set | retain\n \t:= ip | ip6 \n " + " \t\t| udp | tcp | icmp \n" "\t:= reclassify | pipe | drop | continue | pass\n" "For Example usage look at the examples directory\n"); @@ -60,7 +56,7 @@ usage(void) } static int -pedit_parse_nopopt (int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +pedit_parse_nopopt (int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int argc = *argc_p; char **argv = *argv_p; @@ -119,7 +115,7 @@ static struct m_pedit_util *get_pedit_kind(const char *str) } int -pack_key(struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +pack_key(struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int hwm = sel->nkeys; @@ -143,7 +139,7 @@ pack_key(struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) int -pack_key32(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +pack_key32(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { if (tkey->off > (tkey->off & ~3)) { fprintf(stderr, @@ -153,14 +149,14 @@ pack_key32(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) tkey->val = htonl(tkey->val & retain); tkey->mask = htonl(tkey->mask | ~retain); - return pack_key(sel,tkey); + return pack_key(sel, tkey); } int -pack_key16(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +pack_key16(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int ind, stride; - __u32 m[4] = {0xFFFF0000,0xFF0000FF,0x0000FFFF}; + __u32 m[4] = {0xFFFF0000, 0xFF0000FF, 0x0000FFFF}; if (tkey->val > 0xFFFF || tkey->mask > 0xFFFF) { fprintf(stderr, "pack_key16 bad value\n"); @@ -170,7 +166,7 @@ pack_key16(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) ind = tkey->off & 3; if (ind == 3) { - fprintf(stderr, "pack_key16 bad index value %d\n",ind); + fprintf(stderr, "pack_key16 bad index value %d\n", ind); return -1; } @@ -181,16 +177,16 @@ pack_key16(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) tkey->off &= ~3; if (pedit_debug) - printf("pack_key16: Final val %08x mask %08x \n",tkey->val,tkey->mask); - return pack_key(sel,tkey); + printf("pack_key16: Final val %08x mask %08x\n", tkey->val, tkey->mask); + return pack_key(sel, tkey); } int -pack_key8(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +pack_key8(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int ind, stride; - __u32 m[4] = {0xFFFFFF00,0xFFFF00FF,0xFF00FFFF,0x00FFFFFF}; + __u32 m[4] = {0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 0x00FFFFFF}; if (tkey->val > 0xFF || tkey->mask > 0xFF) { fprintf(stderr, "pack_key8 bad value (val %x mask %x\n", tkey->val, tkey->mask); @@ -206,12 +202,12 @@ pack_key8(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) tkey->off &= ~3; if (pedit_debug) - printf("pack_key8: Final word off %d val %08x mask %08x \n",tkey->off , tkey->val,tkey->mask); - return pack_key(sel,tkey); + printf("pack_key8: Final word off %d val %08x mask %08x\n", tkey->off, tkey->val, tkey->mask); + return pack_key(sel, tkey); } int -parse_val(int *argc_p, char ***argv_p, __u32 * val, int type) +parse_val(int *argc_p, char ***argv_p, __u32 *val, int type) { int argc = *argc_p; char **argv = *argv_p; @@ -219,21 +215,22 @@ parse_val(int *argc_p, char ***argv_p, __u32 * val, int type) if (argc <= 0) return -1; - if (TINT == type) + if (type == TINT) return get_integer((int *) val, *argv, 0); - if (TU32 == type) + if (type == TU32) return get_u32(val, *argv, 0); - if (TIPV4 == type) { + if (type == TIPV4) { inet_prefix addr; + if (get_prefix_1(&addr, *argv, AF_INET)) { return -1; } - *val=addr.data[0]; + *val = addr.data[0]; return 0; } - if (TIPV6 == type) { + if (type == TIPV6) { /* not implemented yet */ return -1; } @@ -242,7 +239,7 @@ parse_val(int *argc_p, char ***argv_p, __u32 * val, int type) } int -parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { __u32 mask = 0, val = 0; __u32 o = 0xFF; @@ -254,7 +251,7 @@ parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct t return -1; if (pedit_debug) - printf("parse_cmd argc %d %s offset %d length %d\n",argc,*argv,tkey->off,len); + printf("parse_cmd argc %d %s offset %d length %d\n", argc, *argv, tkey->off, len); if (len == 2) o = 0xFFFF; @@ -287,22 +284,22 @@ parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct t tkey->mask = mask; if (len == 1) { - res = pack_key8(retain,sel,tkey); + res = pack_key8(retain, sel, tkey); goto done; } if (len == 2) { - res = pack_key16(retain,sel,tkey); + res = pack_key16(retain, sel, tkey); goto done; } if (len == 4) { - res = pack_key32(retain,sel,tkey); + res = pack_key32(retain, sel, tkey); goto done; } return -1; done: if (pedit_debug) - printf("parse_cmd done argc %d %s offset %d length %d\n",argc,*argv,tkey->off,len); + printf("parse_cmd done argc %d %s offset %d length %d\n", argc, *argv, tkey->off, len); *argc_p = argc; *argv_p = argv; return res; @@ -310,7 +307,7 @@ parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct t } int -parse_offset(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +parse_offset(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int off; __u32 len, retain; @@ -357,7 +354,7 @@ parse_offset(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedi /* [at offmask shift ] */ if (matches(*argv, "at") == 0) { - __u32 atv=0,offmask=0x0,shift=0; + __u32 atv = 0, offmask = 0x0, shift = 0; NEXT_ARG(); if (get_u32(&atv, *argv, 0)) @@ -379,7 +376,7 @@ parse_offset(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedi NEXT_ARG(); } - res = parse_cmd(&argc, &argv, len, TU32,retain,sel,tkey); + res = parse_cmd(&argc, &argv, len, TU32, retain, sel, tkey); *argc_p = argc; *argv_p = argv; @@ -387,7 +384,7 @@ parse_offset(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedi } static int -parse_munge(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel) +parse_munge(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel) { struct tc_pedit_key tkey; int argc = *argc_p; @@ -401,22 +398,22 @@ parse_munge(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel) if (matches(*argv, "offset") == 0) { NEXT_ARG(); - res = parse_offset(&argc, &argv,sel,&tkey); + res = parse_offset(&argc, &argv, sel, &tkey); goto done; } else { char k[16]; struct m_pedit_util *p = NULL; - strncpy(k, *argv, sizeof (k) - 1); + strncpy(k, *argv, sizeof(k) - 1); - if (argc > 0 ) { + if (argc > 0) { p = get_pedit_kind(k); - if (NULL == p) + if (p == NULL) goto bad_val; NEXT_ARG(); - res = p->parse_peopt(&argc, &argv, sel,&tkey); + res = p->parse_peopt(&argc, &argv, sel, &tkey); if (res < 0) { - fprintf(stderr,"bad pedit parsing\n"); + fprintf(stderr, "bad pedit parsing\n"); goto bad_val; } goto done; @@ -450,7 +447,7 @@ parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, stru while (argc > 0) { if (pedit_debug > 1) - fprintf(stderr, "while pedit (%d:%s)\n",argc, *argv); + fprintf(stderr, "while pedit (%d:%s)\n", argc, *argv); if (matches(*argv, "pedit") == 0) { NEXT_ARG(); ok++; @@ -459,13 +456,13 @@ parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, stru usage(); } else if (matches(*argv, "munge") == 0) { if (!ok) { - fprintf(stderr, "Illegal pedit construct (%s) \n", *argv); + fprintf(stderr, "Illegal pedit construct (%s)\n", *argv); explain(); return -1; } NEXT_ARG(); - if (parse_munge(&argc, &argv,&sel.sel)) { - fprintf(stderr, "Illegal pedit construct (%s) \n", *argv); + if (parse_munge(&argc, &argv, &sel.sel)) { + fprintf(stderr, "Illegal pedit construct (%s)\n", *argv); explain(); return -1; } @@ -516,7 +513,7 @@ parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, stru tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); - addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS,&sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_pedit_key)); + addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_pedit_key)); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; *argc_p = argc; @@ -525,10 +522,11 @@ parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, stru } int -print_pedit(struct action_util *au,FILE * f, struct rtattr *arg) +print_pedit(struct action_util *au, FILE * f, struct rtattr *arg) { struct tc_pedit_sel *sel; struct rtattr *tb[TCA_PEDIT_MAX + 1]; + SPRINT_BUF(b1); if (arg == NULL) @@ -542,28 +540,29 @@ print_pedit(struct action_util *au,FILE * f, struct rtattr *arg) } sel = RTA_DATA(tb[TCA_PEDIT_PARMS]); - fprintf(f, " pedit action %s keys %d\n ", action_n2a(sel->action, b1, sizeof (b1)),sel->nkeys); - fprintf(f, "\t index %d ref %d bind %d", sel->index,sel->refcnt, sel->bindcnt); + fprintf(f, " pedit action %s keys %d\n ", action_n2a(sel->action, b1, sizeof (b1)), sel->nkeys); + fprintf(f, "\t index %d ref %d bind %d", sel->index, sel->refcnt, sel->bindcnt); if (show_stats) { if (tb[TCA_PEDIT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_PEDIT_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } if (sel->nkeys) { int i; struct tc_pedit_key *key = sel->keys; - for (i=0; inkeys; i++, key++) { - fprintf(f, "\n\t key #%d",i); + for (i = 0; i < sel->nkeys; i++, key++) { + fprintf(f, "\n\t key #%d", i); fprintf(f, " at %d: val %08x mask %08x", (unsigned int)key->off, (unsigned int)ntohl(key->val), (unsigned int)ntohl(key->mask)); } } else { - fprintf(f, "\npedit %x keys %d is not LEGIT", sel->index,sel->nkeys); + fprintf(f, "\npedit %x keys %d is not LEGIT", sel->index, sel->nkeys); } diff --git a/tc/m_police.c b/tc/m_police.c index 915f1a514..97558bd37 100644 --- a/tc/m_police.c +++ b/tc/m_police.c @@ -38,9 +38,9 @@ static void usage(void) fprintf(stderr, " [ peakrate BPS ] [ avrate BPS ] [ overhead BYTES ]\n"); fprintf(stderr, " [ linklayer TYPE ] [ ACTIONTERM ]\n"); - fprintf(stderr, "New Syntax ACTIONTERM := conform-exceed [/NOTEXCEEDACT] \n"); - fprintf(stderr, "Where: *EXCEEDACT := pipe | ok | reclassify | drop | continue \n"); - fprintf(stderr, "Where: pipe is only valid for new syntax \n"); + fprintf(stderr, "New Syntax ACTIONTERM := conform-exceed [/NOTEXCEEDACT]\n"); + fprintf(stderr, "Where: *EXCEEDACT := pipe | ok | reclassify | drop | continue\n"); + fprintf(stderr, "Where: pipe is only valid for new syntax\n"); exit(-1); } @@ -91,6 +91,7 @@ static int police_action_a2n(const char *arg, int *result) res = TC_POLICE_PIPE; else { char dummy; + if (sscanf(arg, "%d%c", &res, &dummy) != 1) return -1; } @@ -121,21 +122,21 @@ static int get_police_result(int *action, int *result, char *arg) } -int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) +int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { int argc = *argc_p; char **argv = *argv_p; int res = -1; - int ok=0; + int ok = 0; struct tc_police p; __u32 rtab[256]; __u32 ptab[256]; __u32 avrate = 0; int presult = 0; - unsigned buffer=0, mtu=0, mpu=0; - unsigned short overhead=0; + unsigned buffer = 0, mtu = 0, mpu = 0; + unsigned short overhead = 0; unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ - int Rcell_log=-1, Pcell_log = -1; + int Rcell_log = -1, Pcell_log = -1; struct rtattr *tail; memset(&p, 0, sizeof(p)); @@ -297,7 +298,7 @@ int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_ if (p.rate.rate) addattr_l(n, MAX_MSG, TCA_POLICE_RATE, rtab, 1024); if (p.peakrate.rate) - addattr_l(n, MAX_MSG, TCA_POLICE_PEAKRATE, ptab, 1024); + addattr_l(n, MAX_MSG, TCA_POLICE_PEAKRATE, ptab, 1024); if (avrate) addattr32(n, MAX_MSG, TCA_POLICE_AVRATE, avrate); if (presult) @@ -313,7 +314,7 @@ int act_parse_police(struct action_util *a,int *argc_p, char ***argv_p, int tca_ int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { - return act_parse_police(NULL,argc_p,argv_p,tca_id,n); + return act_parse_police(NULL, argc_p, argv_p, tca_id, n); } int @@ -323,7 +324,7 @@ print_police(struct action_util *a, FILE *f, struct rtattr *arg) SPRINT_BUF(b2); struct tc_police *p; struct rtattr *tb[TCA_POLICE_MAX+1]; - unsigned buffer; + unsigned int buffer; unsigned int linklayer; if (arg == NULL) @@ -356,19 +357,19 @@ print_police(struct action_util *a, FILE *f, struct rtattr *arg) fprintf(f, "avrate %s ", sprint_rate(rta_getattr_u32(tb[TCA_POLICE_AVRATE]), b1)); fprintf(f, "action %s", police_action_n2a(p->action, b1, sizeof(b1))); if (tb[TCA_POLICE_RESULT]) { - fprintf(f, "/%s ", police_action_n2a(*(int*)RTA_DATA(tb[TCA_POLICE_RESULT]), b1, sizeof(b1))); + fprintf(f, "/%s ", police_action_n2a(*(int *)RTA_DATA(tb[TCA_POLICE_RESULT]), b1, sizeof(b1))); } else fprintf(f, " "); fprintf(f, "overhead %ub ", p->rate.overhead); linklayer = (p->rate.linklayer & TC_LINKLAYER_MASK); if (linklayer > TC_LINKLAYER_ETHERNET || show_details) fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b2)); - fprintf(f, "\nref %d bind %d\n",p->refcnt, p->bindcnt); + fprintf(f, "\nref %d bind %d\n", p->refcnt, p->bindcnt); return 0; } int tc_print_police(FILE *f, struct rtattr *arg) { - return print_police(&police_action_util,f,arg); + return print_police(&police_action_util, f, arg); } diff --git a/tc/m_simple.c b/tc/m_simple.c index 1ad552687..e167ccae4 100644 --- a/tc/m_simple.c +++ b/tc/m_simple.c @@ -138,7 +138,7 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, } if (strlen(simpdata) > (SIMP_MAX_DATA - 1)) { - fprintf(stderr, "simple: Illegal string len %zu <%s> \n", + fprintf(stderr, "simple: Illegal string len %zu <%s>\n", strlen(simpdata), simpdata); return -1; } @@ -156,7 +156,7 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, return 0; } -static int print_simple(struct action_util *au, FILE * f, struct rtattr *arg) +static int print_simple(struct action_util *au, FILE *f, struct rtattr *arg) { struct tc_defact *sel; struct rtattr *tb[TCA_DEF_MAX + 1]; @@ -187,6 +187,7 @@ static int print_simple(struct action_util *au, FILE * f, struct rtattr *arg) if (show_stats) { if (tb[TCA_DEF_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_DEF_TM]); + print_tm(f, tm); } } diff --git a/tc/m_skbedit.c b/tc/m_skbedit.c index 36323a9d3..180b9cbd6 100644 --- a/tc/m_skbedit.c +++ b/tc/m_skbedit.c @@ -32,8 +32,8 @@ explain(void) { fprintf(stderr, "Usage: ... skbedit <[QM] [PM] [MM]>\n" "QM = queue_mapping QUEUE_MAPPING\n" - "PM = priority PRIORITY \n" - "MM = mark MARK \n" + "PM = priority PRIORITY\n" + "MM = mark MARK\n" "QUEUE_MAPPING = device transmit queue to use\n" "PRIORITY = classID to assign to priority field\n" "MARK = firewall mark to set\n"); @@ -161,6 +161,7 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg) { struct rtattr *tb[TCA_SKBEDIT_MAX + 1]; + SPRINT_BUF(b1); __u32 *priority; __u32 *mark; @@ -198,6 +199,7 @@ static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg) if (show_stats) { if (tb[TCA_SKBEDIT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_SKBEDIT_TM]); + print_tm(f, tm); } } diff --git a/tc/m_vlan.c b/tc/m_vlan.c index 32db5ed5b..8d97963f3 100644 --- a/tc/m_vlan.c +++ b/tc/m_vlan.c @@ -186,7 +186,7 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) fprintf(f, " vlan"); - switch(parm->v_action) { + switch (parm->v_action) { case TCA_VLAN_ACT_POP: fprintf(f, " pop"); break; @@ -203,7 +203,7 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) } break; } - fprintf(f, " %s", action_n2a(parm->action, b1, sizeof (b1))); + fprintf(f, " %s", action_n2a(parm->action, b1, sizeof(b1))); fprintf(f, "\n\t index %d ref %d bind %d", parm->index, parm->refcnt, parm->bindcnt); @@ -211,6 +211,7 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) if (show_stats) { if (tb[TCA_VLAN_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_VLAN_TM]); + print_tm(f, tm); } } diff --git a/tc/m_xt.c b/tc/m_xt.c index bf603fcb8..c3f866df1 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -44,7 +44,7 @@ #endif #ifndef ALIGN -#define ALIGN(x,a) __ALIGN_KERNEL((x), (a)) +#define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) #endif static const char *tname = "mangle"; @@ -85,9 +85,9 @@ build_st(struct xtables_target *target, struct xt_entry_target *t) { size_t size = - XT_ALIGN(sizeof (struct xt_entry_target)) + target->size; + XT_ALIGN(sizeof(struct xt_entry_target)) + target->size; - if (NULL == t) { + if (t == NULL) { target->t = xtables_calloc(1, size); target->t->u.target_size = size; strcpy(target->t->u.user.name, target->name); @@ -109,14 +109,14 @@ static void set_lib_dir(void) if (!lib_dir) { lib_dir = getenv("IPTABLES_LIB_DIR"); if (lib_dir) - fprintf(stderr, "using deprecated IPTABLES_LIB_DIR \n"); + fprintf(stderr, "using deprecated IPTABLES_LIB_DIR\n"); } if (lib_dir == NULL) lib_dir = XT_LIB_DIR; } -static int parse_ipt(struct action_util *a,int *argc_p, +static int parse_ipt(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { struct xtables_target *m = NULL; @@ -138,6 +138,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, { int i; + for (i = 0; i < rargc; i++) { if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) { break; @@ -147,7 +148,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } if (argc <= 2) { - fprintf(stderr,"bad arguments to ipt %d vs %d \n", argc, rargc); + fprintf(stderr, "bad arguments to ipt %d vs %d\n", argc, rargc); return -1; } @@ -158,10 +159,10 @@ static int parse_ipt(struct action_util *a,int *argc_p, switch (c) { case 'j': m = xtables_find_target(optarg, XTF_TRY_LOAD); - if (NULL != m) { + if (m != NULL) { - if (0 > build_st(m, NULL)) { - printf(" %s error \n", m->name); + if (build_st(m, NULL) < 0) { + printf(" %s error\n", m->name); return -1; } #if (XTABLES_VERSION_CODE >= 6) @@ -180,24 +181,24 @@ static int parse_ipt(struct action_util *a,int *argc_p, } else tcipt_globals.opts = opts; } else { - fprintf(stderr," failed to find target %s\n\n", optarg); + fprintf(stderr, " failed to find target %s\n\n", optarg); return -1; } ok++; break; default: - memset(&fw, 0, sizeof (fw)); + memset(&fw, 0, sizeof(fw)); #if (XTABLES_VERSION_CODE >= 6) - if (m != NULL && m->x6_parse != NULL ) { - xtables_option_tpcall(c, argv, 0 , m, NULL); + if (m != NULL && m->x6_parse != NULL) { + xtables_option_tpcall(c, argv, 0, m, NULL); #else - if (m != NULL && m->parse != NULL ) { + if (m != NULL && m->parse != NULL) { m->parse(c - m->option_offset, argv, 0, &m->tflags, NULL, &m->t); #endif } else { - fprintf(stderr,"failed to find target %s\n\n", optarg); + fprintf(stderr, "failed to find target %s\n\n", optarg); return -1; } @@ -220,7 +221,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } if (!ok && !iok) { - fprintf(stderr," ipt Parser BAD!! (%s)\n", *argv); + fprintf(stderr, " ipt Parser BAD!! (%s)\n", *argv); return -1; } @@ -235,6 +236,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, { struct tcmsg *t = NLMSG_DATA(n); + if (t->tcm_parent != TC_H_ROOT && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) { hook = NF_IP_PRE_ROUTING; @@ -289,7 +291,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } static int -print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) +print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) { struct rtattr *tb[TCA_IPT_MAX + 1]; struct xt_entry_target *t = NULL; @@ -318,20 +320,22 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) return -1; } else { __u32 hook; + hook = rta_getattr_u32(tb[TCA_IPT_HOOK]); - fprintf(f, " hook: %s \n", ipthooks[hook]); + fprintf(f, " hook: %s\n", ipthooks[hook]); } if (tb[TCA_IPT_TARG] == NULL) { - fprintf(f, "\t[NULL ipt target parameters ] \n"); + fprintf(f, "\t[NULL ipt target parameters ]\n"); return -1; } else { struct xtables_target *m = NULL; + t = RTA_DATA(tb[TCA_IPT_TARG]); m = xtables_find_target(t->u.user.name, XTF_TRY_LOAD); - if (NULL != m) { - if (0 > build_st(m, t)) { - fprintf(stderr, " %s error \n", m->name); + if (m != NULL) { + if (build_st(m, t) < 0) { + fprintf(stderr, " %s error\n", m->name); return -1; } @@ -361,21 +365,24 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) fprintf(f, " [NULL ipt target index ]\n"); } else { __u32 index; + index = rta_getattr_u32(tb[TCA_IPT_INDEX]); - fprintf(f, " \n\tindex %d", index); + fprintf(f, "\n\tindex %d", index); } if (tb[TCA_IPT_CNT]) { - struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]);; + struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]); + fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt); } if (show_stats) { if (tb[TCA_IPT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } - fprintf(f, " \n"); + fprintf(f, "\n"); } xtables_free_opts(1); @@ -384,7 +391,7 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) } struct action_util xt_action_util = { - .id = "xt", - .parse_aopt = parse_ipt, - .print_aopt = print_ipt, + .id = "xt", + .parse_aopt = parse_ipt, + .print_aopt = print_ipt, }; diff --git a/tc/m_xt_old.c b/tc/m_xt_old.c index 6e643088c..20a6342b1 100644 --- a/tc/m_xt_old.c +++ b/tc/m_xt_old.c @@ -41,8 +41,8 @@ #endif #ifndef ALIGN -#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) -#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) +#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) +#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) #endif static const char *pname = "tc-ipt"; @@ -63,7 +63,7 @@ static struct option original_opts[] = { }; static struct option *opts = original_opts; -static unsigned int global_option_offset = 0; +static unsigned int global_option_offset; char *lib_dir; const char *program_version = XTABLES_VERSION; const char *program_name = "tc-ipt"; @@ -96,18 +96,18 @@ merge_options(struct option *oldopts, const struct option *newopts, struct option *merge; unsigned int num_old, num_new, i; - for (num_old = 0; oldopts[num_old].name; num_old++) ; - for (num_new = 0; newopts[num_new].name; num_new++) ; + for (num_old = 0; oldopts[num_old].name; num_old++); + for (num_new = 0; newopts[num_new].name; num_new++); *option_offset = global_option_offset + OPTION_OFFSET; - merge = malloc(sizeof (struct option) * (num_new + num_old + 1)); - memcpy(merge, oldopts, num_old * sizeof (struct option)); + merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); + memcpy(merge, oldopts, num_old * sizeof(struct option)); for (i = 0; i < num_new; i++) { merge[num_old + i] = newopts[i]; merge[num_old + i].val += *option_offset; } - memset(merge + num_old + num_new, 0, sizeof (struct option)); + memset(merge + num_old + num_new, 0, sizeof(struct option)); return merge; } @@ -125,35 +125,35 @@ merge_options(struct option *oldopts, const struct option *newopts, int check_inverse(const char option[], int *invert, int *my_optind, int argc) { - if (option && strcmp(option, "!") == 0) { - if (*invert) - exit_error(PARAMETER_PROBLEM, - "Multiple `!' flags not allowed"); - *invert = TRUE; - if (my_optind != NULL) { - ++*my_optind; - if (argc && *my_optind > argc) - exit_error(PARAMETER_PROBLEM, - "no argument following `!'"); - } - - return TRUE; - } - return FALSE; + if (option && strcmp(option, "!") == 0) { + if (*invert) + exit_error(PARAMETER_PROBLEM, + "Multiple `!' flags not allowed"); + *invert = TRUE; + if (my_optind != NULL) { + ++*my_optind; + if (argc && *my_optind > argc) + exit_error(PARAMETER_PROBLEM, + "no argument following `!'"); + } + + return TRUE; + } + return FALSE; } /*XXX: TC_CONFIG_XT_H */ void exit_error(enum exittype status, const char *msg, ...) { - va_list args; - - va_start(args, msg); - fprintf(stderr, "%s v%s: ", pname, pversion); - vfprintf(stderr, msg, args); - va_end(args); - fprintf(stderr, "\n"); - /* On error paths, make sure that we don't leak memory */ - exit(status); + va_list args; + + va_start(args, msg); + fprintf(stderr, "%s v%s: ", pname, pversion); + vfprintf(stderr, msg, args); + va_end(args); + fprintf(stderr, "\n"); + /* On error paths, make sure that we don't leak memory */ + exit(status); } /*XXX: TC_CONFIG_XT_H */ @@ -173,9 +173,9 @@ build_st(struct xtables_target *target, struct xt_entry_target *t) { size_t size = - XT_ALIGN(sizeof (struct xt_entry_target)) + target->size; + XT_ALIGN(sizeof(struct xt_entry_target)) + target->size; - if (NULL == t) { + if (t == NULL) { target->t = fw_calloc(1, size); target->t->u.target_size = size; strcpy(target->t->u.user.name, target->name); @@ -197,14 +197,14 @@ inline void set_lib_dir(void) if (!lib_dir) { lib_dir = getenv("IPTABLES_LIB_DIR"); if (lib_dir) - fprintf(stderr, "using deprecated IPTABLES_LIB_DIR \n"); + fprintf(stderr, "using deprecated IPTABLES_LIB_DIR\n"); } if (lib_dir == NULL) lib_dir = XT_LIB_DIR; } -static int parse_ipt(struct action_util *a,int *argc_p, +static int parse_ipt(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { struct xtables_target *m = NULL; @@ -223,6 +223,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, { int i; + for (i = 0; i < rargc; i++) { if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) { break; @@ -232,7 +233,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } if (argc <= 2) { - fprintf(stderr,"bad arguments to ipt %d vs %d \n", argc, rargc); + fprintf(stderr, "bad arguments to ipt %d vs %d\n", argc, rargc); return -1; } @@ -243,29 +244,29 @@ static int parse_ipt(struct action_util *a,int *argc_p, switch (c) { case 'j': m = find_target(optarg, TRY_LOAD); - if (NULL != m) { + if (m != NULL) { - if (0 > build_st(m, NULL)) { - printf(" %s error \n", m->name); + if (build_st(m, NULL) < 0) { + printf(" %s error\n", m->name); return -1; } opts = merge_options(opts, m->extra_opts, &m->option_offset); } else { - fprintf(stderr," failed to find target %s\n\n", optarg); + fprintf(stderr, " failed to find target %s\n\n", optarg); return -1; } ok++; break; default: - memset(&fw, 0, sizeof (fw)); + memset(&fw, 0, sizeof(fw)); if (m) { m->parse(c - m->option_offset, argv, 0, &m->tflags, NULL, &m->t); } else { - fprintf(stderr," failed to find target %s\n\n", optarg); + fprintf(stderr, " failed to find target %s\n\n", optarg); return -1; } @@ -289,7 +290,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } if (!ok && !iok) { - fprintf(stderr," ipt Parser BAD!! (%s)\n", *argv); + fprintf(stderr, " ipt Parser BAD!! (%s)\n", *argv); return -1; } @@ -299,6 +300,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, { struct tcmsg *t = NLMSG_DATA(n); + if (t->tcm_parent != TC_H_ROOT && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) { hook = NF_IP_PRE_ROUTING; @@ -339,11 +341,11 @@ static int parse_ipt(struct action_util *a,int *argc_p, optind = 0; free_opts(opts); /* Clear flags if target will be used again */ - m->tflags=0; - m->used=0; + m->tflags = 0; + m->used = 0; /* Free allocated memory */ - if (m->t) - free(m->t); + if (m->t) + free(m->t); return 0; @@ -351,7 +353,7 @@ static int parse_ipt(struct action_util *a,int *argc_p, } static int -print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) +print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) { struct rtattr *tb[TCA_IPT_MAX + 1]; struct xt_entry_target *t = NULL; @@ -375,20 +377,22 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) return -1; } else { __u32 hook; + hook = rta_getattr_u32(tb[TCA_IPT_HOOK]); - fprintf(f, " hook: %s \n", ipthooks[hook]); + fprintf(f, " hook: %s\n", ipthooks[hook]); } if (tb[TCA_IPT_TARG] == NULL) { - fprintf(f, "\t[NULL ipt target parameters ] \n"); + fprintf(f, "\t[NULL ipt target parameters ]\n"); return -1; } else { struct xtables_target *m = NULL; + t = RTA_DATA(tb[TCA_IPT_TARG]); m = find_target(t->u.user.name, TRY_LOAD); - if (NULL != m) { - if (0 > build_st(m, t)) { - fprintf(stderr, " %s error \n", m->name); + if (m != NULL) { + if (build_st(m, t) < 0) { + fprintf(stderr, " %s error\n", m->name); return -1; } @@ -406,21 +410,24 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) fprintf(f, " [NULL ipt target index ]\n"); } else { __u32 index; + index = rta_getattr_u32(tb[TCA_IPT_INDEX]); - fprintf(f, " \n\tindex %d", index); + fprintf(f, "\n\tindex %d", index); } if (tb[TCA_IPT_CNT]) { - struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]);; + struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]); + fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt); } if (show_stats) { if (tb[TCA_IPT_TM]) { struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]); - print_tm(f,tm); + + print_tm(f, tm); } } - fprintf(f, " \n"); + fprintf(f, "\n"); } free_opts(opts); @@ -429,7 +436,7 @@ print_ipt(struct action_util *au,FILE * f, struct rtattr *arg) } struct action_util ipt_action_util = { - .id = "ipt", - .parse_aopt = parse_ipt, - .print_aopt = print_ipt, + .id = "ipt", + .parse_aopt = parse_ipt, + .print_aopt = print_ipt, }; diff --git a/tc/p_icmp.c b/tc/p_icmp.c index a4b80c2c1..c2a6fcd69 100644 --- a/tc/p_icmp.c +++ b/tc/p_icmp.c @@ -25,7 +25,7 @@ static int -parse_icmp(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +parse_icmp(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int res = -1; #if 0 @@ -47,7 +47,7 @@ parse_icmp(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_ } return -1; - done: +done: *argc_p = argc; *argv_p = argv; #endif diff --git a/tc/p_ip.c b/tc/p_ip.c index 10e4bebc7..53dfb2693 100644 --- a/tc/p_ip.c +++ b/tc/p_ip.c @@ -24,7 +24,7 @@ #include "m_pedit.h" static int -parse_ip(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +parse_ip(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int res = -1; int argc = *argc_p; @@ -36,13 +36,13 @@ parse_ip(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_ke if (strcmp(*argv, "src") == 0) { NEXT_ARG(); tkey->off = 12; - res = parse_cmd(&argc, &argv, 4, TIPV4,RU32,sel,tkey); + res = parse_cmd(&argc, &argv, 4, TIPV4, RU32, sel, tkey); goto done; } if (strcmp(*argv, "dst") == 0) { NEXT_ARG(); tkey->off = 16; - res = parse_cmd(&argc, &argv, 4, TIPV4,RU32,sel,tkey); + res = parse_cmd(&argc, &argv, 4, TIPV4, RU32, sel, tkey); goto done; } /* jamal - look at these and make them either old or new @@ -52,94 +52,94 @@ parse_ip(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_ke if (strcmp(*argv, "tos") == 0 || matches(*argv, "dsfield") == 0) { NEXT_ARG(); tkey->off = 1; - res = parse_cmd(&argc, &argv, 1, TU32,RU8,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); goto done; } if (strcmp(*argv, "ihl") == 0) { NEXT_ARG(); tkey->off = 0; - res = parse_cmd(&argc, &argv, 1, TU32,0x0f,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, 0x0f, sel, tkey); goto done; } if (strcmp(*argv, "protocol") == 0) { NEXT_ARG(); tkey->off = 9; - res = parse_cmd(&argc, &argv, 1, TU32,RU8,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); goto done; } /* jamal - fix this */ if (matches(*argv, "precedence") == 0) { NEXT_ARG(); tkey->off = 1; - res = parse_cmd(&argc, &argv, 1, TU32,RU8,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); goto done; } /* jamal - validate this at some point */ if (strcmp(*argv, "nofrag") == 0) { NEXT_ARG(); tkey->off = 6; - res = parse_cmd(&argc, &argv, 1, TU32,0x3F,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, 0x3F, sel, tkey); goto done; } /* jamal - validate this at some point */ if (strcmp(*argv, "firstfrag") == 0) { NEXT_ARG(); tkey->off = 6; - res = parse_cmd(&argc, &argv, 1, TU32,0x1F,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, 0x1F, sel, tkey); goto done; } if (strcmp(*argv, "ce") == 0) { NEXT_ARG(); tkey->off = 6; - res = parse_cmd(&argc, &argv, 1, TU32,0x80,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, 0x80, sel, tkey); goto done; } if (strcmp(*argv, "df") == 0) { NEXT_ARG(); tkey->off = 6; - res = parse_cmd(&argc, &argv, 1, TU32,0x40,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, 0x40, sel, tkey); goto done; } if (strcmp(*argv, "mf") == 0) { NEXT_ARG(); tkey->off = 6; - res = parse_cmd(&argc, &argv, 1, TU32,0x20,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, 0x20, sel, tkey); goto done; } if (strcmp(*argv, "dport") == 0) { NEXT_ARG(); tkey->off = 22; - res = parse_cmd(&argc, &argv, 2, TU32,RU16,sel,tkey); + res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey); goto done; } if (strcmp(*argv, "sport") == 0) { NEXT_ARG(); tkey->off = 20; - res = parse_cmd(&argc, &argv, 2, TU32,RU16,sel,tkey); + res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey); goto done; } if (strcmp(*argv, "icmp_type") == 0) { NEXT_ARG(); tkey->off = 20; - res = parse_cmd(&argc, &argv, 1, TU32,RU8,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); goto done; } if (strcmp(*argv, "icmp_code") == 0) { NEXT_ARG(); tkey->off = 20; - res = parse_cmd(&argc, &argv, 1, TU32,RU8,sel,tkey); + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); goto done; } return -1; - done: +done: *argc_p = argc; *argv_p = argv; return res; } static int -parse_ip6(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +parse_ip6(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int res = -1; return res; diff --git a/tc/p_tcp.c b/tc/p_tcp.c index 32ffc0272..79f16c58c 100644 --- a/tc/p_tcp.c +++ b/tc/p_tcp.c @@ -24,7 +24,7 @@ #include "m_pedit.h" static int -parse_tcp(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +parse_tcp(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int res = -1; return res; diff --git a/tc/p_udp.c b/tc/p_udp.c index 2b9b88fc1..c056414e6 100644 --- a/tc/p_udp.c +++ b/tc/p_udp.c @@ -24,7 +24,7 @@ #include "m_pedit.h" static int -parse_udp(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey) +parse_udp(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int res = -1; return res; diff --git a/tc/q_atm.c b/tc/q_atm.c index 2598e2989..a5b716fc5 100644 --- a/tc/q_atm.c +++ b/tc/q_atm.c @@ -30,7 +30,7 @@ static int atm_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { if (argc) { - fprintf(stderr,"Usage: atm\n"); + fprintf(stderr, "Usage: atm\n"); return -1; } return 0; @@ -39,10 +39,8 @@ static int atm_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl static void explain(void) { - fprintf(stderr, "Usage: ... atm ( pvc ADDR | svc ADDR [ sap SAP ] ) " - "[ qos QOS ] [ sndbuf BYTES ]\n"); - fprintf(stderr, " [ hdr HEX... ] [ excess ( CLASSID | clp ) ] " - "[ clip ]\n"); + fprintf(stderr, "Usage: ... atm ( pvc ADDR | svc ADDR [ sap SAP ] ) [ qos QOS ] [ sndbuf BYTES ]\n"); + fprintf(stderr, " [ hdr HEX... ] [ excess ( CLASSID | clp ) ] [ clip ]\n"); } @@ -60,52 +58,47 @@ static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, int set_clip = 0; int s; - memset(&addr,0,sizeof(addr)); - (void) text2qos("aal5,ubr:sdu=9180,rx:none",&qos,0); - (void) text2sap("blli:l2=iso8802",&sap,0); + memset(&addr, 0, sizeof(addr)); + (void) text2qos("aal5,ubr:sdu=9180,rx:none", &qos, 0); + (void) text2sap("blli:l2=iso8802", &sap, 0); while (argc > 0) { - if (!strcmp(*argv,"pvc")) { + if (!strcmp(*argv, "pvc")) { NEXT_ARG(); - if (text2atm(*argv,(struct sockaddr *) &addr, - sizeof(addr),T2A_PVC | T2A_NAME) < 0) { + if (text2atm(*argv, (struct sockaddr *) &addr, + sizeof(addr), T2A_PVC | T2A_NAME) < 0) { explain(); return -1; } - } - else if (!strcmp(*argv,"svc")) { + } else if (!strcmp(*argv,"svc")) { NEXT_ARG(); - if (text2atm(*argv,(struct sockaddr *) &addr, - sizeof(addr),T2A_SVC | T2A_NAME) < 0) { + if (text2atm(*argv, (struct sockaddr *) &addr, + sizeof(addr), T2A_SVC | T2A_NAME) < 0) { explain(); return -1; } - } - else if (!strcmp(*argv,"qos")) { + } else if (!strcmp(*argv,"qos")) { NEXT_ARG(); - if (text2qos(*argv,&qos,0) < 0) { + if (text2qos(*argv, &qos, 0) < 0) { explain(); return -1; } - } - else if (!strcmp(*argv,"sndbuf")) { + } else if (!strcmp(*argv,"sndbuf")) { char *end; NEXT_ARG(); - sndbuf = strtol(*argv,&end,0); + sndbuf = strtol(*argv, &end, 0); if (*end) { explain(); return -1; } - } - else if (!strcmp(*argv,"sap")) { + } else if (!strcmp(*argv,"sap")) { NEXT_ARG(); if (addr.sas_family != AF_ATMSVC || - text2sap(*argv,&sap,T2A_NAME) < 0) { + text2sap(*argv, &sap, T2A_NAME) < 0) { explain(); return -1; } - } - else if (!strcmp(*argv,"hdr")) { + } else if (!strcmp(*argv,"hdr")) { unsigned char *ptr; char *walk; @@ -115,7 +108,7 @@ static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, int tmp; if (ptr == hdr+MAX_HDR_LEN) { - fprintf(stderr,"header is too long\n"); + fprintf(stderr, "header is too long\n"); return -1; } if (*walk == '.') continue; @@ -124,64 +117,61 @@ static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, explain(); return -1; } - sscanf(walk,"%2x",&tmp); + sscanf(walk, "%2x", &tmp); *ptr++ = tmp; walk++; } hdr_len = ptr-hdr; - } - else if (!strcmp(*argv,"excess")) { + } else if (!strcmp(*argv,"excess")) { NEXT_ARG(); - if (!strcmp(*argv,"clp")) excess = 0; - else if (get_tc_classid(&excess,*argv)) { + if (!strcmp(*argv, "clp")) excess = 0; + else if (get_tc_classid(&excess, *argv)) { explain(); return -1; } - } - else if (!strcmp(*argv,"clip")) { + } else if (!strcmp(*argv,"clip")) { set_clip = 1; - } - else { + } else { explain(); return 1; } argc--; argv++; } - s = socket(addr.sas_family,SOCK_DGRAM,0); + s = socket(addr.sas_family, SOCK_DGRAM, 0); if (s < 0) { perror("socket"); return -1; } - if (setsockopt(s,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { + if (setsockopt(s, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0) { perror("SO_ATMQOS"); return -1; } if (sndbuf) - if (setsockopt(s,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) { perror("SO_SNDBUF"); return -1; } - if (addr.sas_family == AF_ATMSVC && setsockopt(s,SOL_ATM,SO_ATMSAP, - &sap,sizeof(sap)) < 0) { + if (addr.sas_family == AF_ATMSVC && setsockopt(s, SOL_ATM, SO_ATMSAP, + &sap, sizeof(sap)) < 0) { perror("SO_ATMSAP"); return -1; } - if (connect(s,(struct sockaddr *) &addr,addr.sas_family == AF_ATMPVC ? + if (connect(s, (struct sockaddr *) &addr, addr.sas_family == AF_ATMPVC ? sizeof(struct sockaddr_atmpvc) : sizeof(addr)) < 0) { perror("connect"); return -1; } if (set_clip) - if (ioctl(s,ATMARP_MKIP,0) < 0) { + if (ioctl(s, ATMARP_MKIP, 0) < 0) { perror("ioctl ATMARP_MKIP"); return -1; } tail = NLMSG_TAIL(n); - addattr_l(n,1024,TCA_OPTIONS,NULL,0); - addattr_l(n,1024,TCA_ATM_FD,&s,sizeof(s)); - if (excess) addattr_l(n,1024,TCA_ATM_EXCESS,&excess,sizeof(excess)); - if (hdr_len != -1) addattr_l(n,1024,TCA_ATM_HDR,hdr,hdr_len); + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); + addattr_l(n, 1024, TCA_ATM_FD, &s, sizeof(s)); + if (excess) addattr_l(n, 1024, TCA_ATM_EXCESS, &excess, sizeof(excess)); + if (hdr_len != -1) addattr_l(n, 1024, TCA_ATM_HDR, hdr, hdr_len); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; } @@ -200,37 +190,37 @@ static int atm_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (tb[TCA_ATM_ADDR]) { if (RTA_PAYLOAD(tb[TCA_ATM_ADDR]) < sizeof(struct sockaddr_atmpvc)) - fprintf(stderr,"ATM: address too short\n"); + fprintf(stderr, "ATM: address too short\n"); else { - if (atm2text(buffer,MAX_ATM_ADDR_LEN, - RTA_DATA(tb[TCA_ATM_ADDR]),A2T_PRETTY | A2T_NAME) < - 0) fprintf(stderr,"atm2text error\n"); - fprintf(f,"pvc %s ",buffer); + if (atm2text(buffer, MAX_ATM_ADDR_LEN, + RTA_DATA(tb[TCA_ATM_ADDR]), A2T_PRETTY | A2T_NAME) < + 0) fprintf(stderr, "atm2text error\n"); + fprintf(f, "pvc %s ", buffer); } } if (tb[TCA_ATM_HDR]) { int i; const __u8 *hdr = RTA_DATA(tb[TCA_ATM_HDR]); - fprintf(f,"hdr"); + fprintf(f, "hdr"); for (i = 0; i < RTA_PAYLOAD(tb[TCA_ATM_HDR]); i++) - fprintf(f,"%c%02x", i ? '.' : ' ', hdr[i]); - if (!i) fprintf(f," ."); - fprintf(f," "); + fprintf(f, "%c%02x", i ? '.' : ' ', hdr[i]); + if (!i) fprintf(f, " ."); + fprintf(f, " "); } if (tb[TCA_ATM_EXCESS]) { __u32 excess; if (RTA_PAYLOAD(tb[TCA_ATM_EXCESS]) < sizeof(excess)) - fprintf(stderr,"ATM: excess class ID too short\n"); + fprintf(stderr, "ATM: excess class ID too short\n"); else { excess = rta_getattr_u32(tb[TCA_ATM_EXCESS]); - if (!excess) fprintf(f,"excess clp "); + if (!excess) fprintf(f, "excess clp "); else { char buf[64]; - print_tc_classid(buf,sizeof(buf),excess); - fprintf(f,"excess %s ",buf); + print_tc_classid(buf, sizeof(buf), excess); + fprintf(f, "excess %s ", buf); } } } @@ -239,10 +229,10 @@ static int atm_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) int state; if (RTA_PAYLOAD(tb[TCA_ATM_STATE]) < sizeof(state)) - fprintf(stderr,"ATM: state field too short\n"); + fprintf(stderr, "ATM: state field too short\n"); else { state = *(int *) RTA_DATA(tb[TCA_ATM_STATE]); - fprintf(f,"%s ",map[state]); + fprintf(f, "%s ", map[state]); } } return 0; @@ -250,7 +240,7 @@ static int atm_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct qdisc_util atm_qdisc_util = { - .id = "atm", + .id = "atm", .parse_qopt = atm_parse_opt, .print_qopt = atm_print_opt, .parse_copt = atm_parse_class_opt, diff --git a/tc/q_cbq.c b/tc/q_cbq.c index 38a616306..faad73504 100644 --- a/tc/q_cbq.c +++ b/tc/q_cbq.c @@ -52,11 +52,11 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl struct tc_ratespec r; struct tc_cbq_lssopt lss; __u32 rtab[256]; - unsigned mpu=0, avpkt=0, allot=0; - unsigned short overhead=0; + unsigned mpu = 0, avpkt = 0, allot = 0; + unsigned short overhead = 0; unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ - int cell_log=-1; - int ewma_log=-1; + int cell_log = -1; + int ewma_log = -1; struct rtattr *tail; memset(&lss, 0, sizeof(lss)); @@ -81,17 +81,18 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl return -1; } } else if (matches(*argv, "cell") == 0) { - unsigned cell; + unsigned int cell; int i; + NEXT_ARG(); if (get_size(&cell, *argv)) { explain1("cell"); return -1; } - for (i=0; i<32; i++) + for (i = 0; i < 32; i++) if ((1<=32) { + if (i >= 32) { fprintf(stderr, "cell must be 2^n\n"); return -1; } @@ -170,7 +171,8 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024); if (show_raw) { int i; - for (i=0; i<256; i++) + + for (i = 0; i < 256; i++) printf("%u ", rtab[i]); printf("\n"); } @@ -180,19 +182,19 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - int wrr_ok=0, fopt_ok=0; + int wrr_ok = 0, fopt_ok = 0; struct tc_ratespec r; struct tc_cbq_lssopt lss; struct tc_cbq_wrropt wrr; struct tc_cbq_fopt fopt; struct tc_cbq_ovl ovl; __u32 rtab[256]; - unsigned mpu=0; - int cell_log=-1; - int ewma_log=-1; - unsigned bndw = 0; - unsigned minburst=0, maxburst=0; - unsigned short overhead=0; + unsigned mpu = 0; + int cell_log = -1; + int ewma_log = -1; + unsigned int bndw = 0; + unsigned minburst = 0, maxburst = 0; + unsigned short overhead = 0; unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ struct rtattr *tail; @@ -260,23 +262,25 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str } lss.change |= TCF_CBQ_LSS_EWMA; } else if (matches(*argv, "cell") == 0) { - unsigned cell; + unsigned int cell; int i; + NEXT_ARG(); if (get_size(&cell, *argv)) { explain1("cell"); return -1; } - for (i=0; i<32; i++) + for (i = 0; i < 32; i++) if ((1<=32) { + if (i >= 32) { fprintf(stderr, "cell must be 2^n\n"); return -1; } cell_log = i; } else if (matches(*argv, "prio") == 0) { - unsigned prio; + unsigned int prio; + NEXT_ARG(); if (get_u32(&prio, *argv, 0)) { explain1("prio"); @@ -323,6 +327,7 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str fopt_ok++; } else if (matches(*argv, "defmap") == 0) { int err; + NEXT_ARG(); err = sscanf(*argv, "%08x/%08x", &fopt.defmap, &fopt.defchange); if (err < 1) { @@ -357,7 +362,8 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str /* 1. Prepare link sharing scheduler parameters */ if (r.rate) { - unsigned pktsize = wrr.allot; + unsigned int pktsize = wrr.allot; + if (wrr.allot < (lss.avpkt*3)/2) wrr.allot = (lss.avpkt*3)/2; r.mpu = mpu; @@ -375,7 +381,7 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str fprintf(stderr, "CBQ: avpkt is required for max/minburst.\n"); return -1; } - if (bndw==0 || r.rate == 0) { + if (bndw == 0 || r.rate == 0) { fprintf(stderr, "CBQ: bandwidth&rate are required for max/minburst.\n"); return -1; } @@ -424,7 +430,8 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024); if (show_raw) { int i; - for (i=0; i<256; i++) + + for (i = 0; i < 256; i++) printf("%u ", rtab[i]); printf("\n"); } @@ -443,6 +450,7 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct tc_cbq_fopt *fopt = NULL; struct tc_cbq_ovl *ovl = NULL; unsigned int linklayer; + SPRINT_BUF(b1); SPRINT_BUF(b2); @@ -478,14 +486,15 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (tb[TCA_CBQ_OVL_STRATEGY]) { if (RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]) < sizeof(*ovl)) fprintf(stderr, "CBQ: too short overlimit strategy %u/%u\n", - (unsigned) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]), - (unsigned) sizeof(*ovl)); + (unsigned int) RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]), + (unsigned int) sizeof(*ovl)); else ovl = RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY]); } if (r) { char buf[64]; + print_rate(buf, sizeof(buf), r->rate); fprintf(f, "rate %s ", buf); linklayer = (r->linklayer & TC_LINKLAYER_MASK); @@ -500,11 +509,12 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } } if (lss && lss->flags) { - int comma=0; + int comma = 0; + fprintf(f, "("); if (lss->flags&TCF_CBQ_LSS_BOUNDED) { fprintf(f, "bounded"); - comma=1; + comma = 1; } if (lss->flags&TCF_CBQ_LSS_ISOLATED) { if (comma) @@ -520,6 +530,7 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) fprintf(f, "prio no-transmit"); if (show_details) { char buf[64]; + fprintf(f, "/%u ", wrr->cpriority); if (wrr->weight != 1) { print_rate(buf, sizeof(buf), wrr->weight); @@ -536,7 +547,7 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (show_raw) fprintf(f, "[%08x] ", lss->maxidle); } - if (lss->minidle!=0x7fffffff) { + if (lss->minidle != 0x7fffffff) { fprintf(f, "minidle %s ", sprint_ticks(lss->minidle>>lss->ewma_log, b1)); if (show_raw) fprintf(f, "[%08x] ", lss->minidle); @@ -549,6 +560,7 @@ static int cbq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } if (fopt && show_details) { char buf[64]; + print_tc_classid(buf, sizeof(buf), fopt->split); fprintf(f, "\nsplit %s ", buf); if (fopt->defmap) { diff --git a/tc/q_choke.c b/tc/q_choke.c index bd9ceb842..e983bb50e 100644 --- a/tc/q_choke.c +++ b/tc/q_choke.c @@ -35,10 +35,10 @@ static int choke_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { struct tc_red_qopt opt; - unsigned burst = 0; - unsigned avpkt = 1000; + unsigned int burst = 0; + unsigned int avpkt = 1000; double probability = 0.02; - unsigned rate = 0; + unsigned int rate = 0; int ecn_ok = 0; int wlog; __u8 sbuf[256]; diff --git a/tc/q_codel.c b/tc/q_codel.c index cff609e8e..9221b48b6 100644 --- a/tc/q_codel.c +++ b/tc/q_codel.c @@ -61,10 +61,10 @@ static void explain(void) static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - unsigned limit = 0; - unsigned target = 0; - unsigned interval = 0; - unsigned ce_threshold = ~0U; + unsigned int limit = 0; + unsigned int target = 0; + unsigned int interval = 0; + unsigned int ce_threshold = ~0U; int ecn = -1; struct rtattr *tail; @@ -129,11 +129,12 @@ static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, static int codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { struct rtattr *tb[TCA_CODEL_MAX + 1]; - unsigned limit; - unsigned interval; - unsigned target; - unsigned ecn; - unsigned ce_threshold; + unsigned int limit; + unsigned int interval; + unsigned int target; + unsigned int ecn; + unsigned int ce_threshold; + SPRINT_BUF(b1); if (opt == NULL) @@ -175,6 +176,7 @@ static int codel_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) { struct tc_codel_xstats _st, *st; + SPRINT_BUF(b1); if (xstats == NULL) diff --git a/tc/q_drr.c b/tc/q_drr.c index 746736ddc..79c81a22c 100644 --- a/tc/q_drr.c +++ b/tc/q_drr.c @@ -84,6 +84,7 @@ static int drr_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, static int drr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { struct rtattr *tb[TCA_DRR_MAX + 1]; + SPRINT_BUF(b1); if (opt == NULL) @@ -100,6 +101,7 @@ static int drr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) static int drr_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) { struct tc_drr_stats *x; + SPRINT_BUF(b1); if (xstats == NULL) diff --git a/tc/q_dsmark.c b/tc/q_dsmark.c index 05185c009..ab7b4d439 100644 --- a/tc/q_dsmark.c +++ b/tc/q_dsmark.c @@ -21,8 +21,7 @@ static void explain(void) { - fprintf(stderr,"Usage: dsmark indices INDICES [ default_index " - "DEFAULT_INDEX ] [ set_tc_index ]\n"); + fprintf(stderr,"Usage: dsmark indices INDICES [ default_index DEFAULT_INDEX ] [ set_tc_index ]\n"); } @@ -32,32 +31,29 @@ static int dsmark_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct rtattr *tail; __u16 ind; char *end; - int dflt,set_tc_index; + int dflt, set_tc_index; ind = set_tc_index = 0; dflt = -1; while (argc > 0) { - if (!strcmp(*argv,"indices")) { + if (!strcmp(*argv, "indices")) { NEXT_ARG(); - ind = strtoul(*argv,&end,0); + ind = strtoul(*argv, &end, 0); if (*end) { explain(); return -1; } - } - else if (!strcmp(*argv,"default_index") || !strcmp(*argv, + } else if (!strcmp(*argv,"default_index") || !strcmp(*argv, "default")) { NEXT_ARG(); - dflt = strtoul(*argv,&end,0); + dflt = strtoul(*argv, &end, 0); if (*end) { explain(); return -1; } - } - else if (!strcmp(*argv,"set_tc_index")) { + } else if (!strcmp(*argv,"set_tc_index")) { set_tc_index = 1; - } - else { + } else { explain(); return -1; } @@ -69,14 +65,14 @@ static int dsmark_parse_opt(struct qdisc_util *qu, int argc, char **argv, return -1; } tail = NLMSG_TAIL(n); - addattr_l(n,1024,TCA_OPTIONS,NULL,0); - addattr_l(n,1024,TCA_DSMARK_INDICES,&ind,sizeof(ind)); + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); + addattr_l(n, 1024, TCA_DSMARK_INDICES, &ind, sizeof(ind)); if (dflt != -1) { __u16 tmp = dflt; - addattr_l(n,1024,TCA_DSMARK_DEFAULT_INDEX,&tmp,sizeof(tmp)); + addattr_l(n, 1024, TCA_DSMARK_DEFAULT_INDEX, &tmp, sizeof(tmp)); } - if (set_tc_index) addattr_l(n,1024,TCA_DSMARK_SET_TC_INDEX,NULL,0); + if (set_tc_index) addattr_l(n, 1024, TCA_DSMARK_SET_TC_INDEX, NULL, 0); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; } @@ -96,27 +92,25 @@ static int dsmark_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, char *end; tail = NLMSG_TAIL(n); - addattr_l(n,1024,TCA_OPTIONS,NULL,0); + addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); while (argc > 0) { - if (!strcmp(*argv,"mask")) { + if (!strcmp(*argv, "mask")) { NEXT_ARG(); - tmp = strtoul(*argv,&end,0); + tmp = strtoul(*argv, &end, 0); if (*end) { explain_class(); return -1; } - addattr_l(n,1024,TCA_DSMARK_MASK,&tmp,1); - } - else if (!strcmp(*argv,"value")) { + addattr_l(n, 1024, TCA_DSMARK_MASK, &tmp, 1); + } else if (!strcmp(*argv,"value")) { NEXT_ARG(); - tmp = strtoul(*argv,&end,0); + tmp = strtoul(*argv, &end, 0); if (*end) { explain_class(); return -1; } - addattr_l(n,1024,TCA_DSMARK_VALUE,&tmp,1); - } - else { + addattr_l(n, 1024, TCA_DSMARK_VALUE, &tmp, 1); + } else { explain_class(); return -1; } @@ -138,29 +132,29 @@ static int dsmark_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) parse_rtattr(tb, TCA_DSMARK_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt)); if (tb[TCA_DSMARK_MASK]) { if (!RTA_PAYLOAD(tb[TCA_DSMARK_MASK])) - fprintf(stderr,"dsmark: empty mask\n"); - else fprintf(f,"mask 0x%02x ", + fprintf(stderr, "dsmark: empty mask\n"); + else fprintf(f, "mask 0x%02x ", rta_getattr_u8(tb[TCA_DSMARK_MASK])); } if (tb[TCA_DSMARK_VALUE]) { if (!RTA_PAYLOAD(tb[TCA_DSMARK_VALUE])) - fprintf(stderr,"dsmark: empty value\n"); - else fprintf(f,"value 0x%02x ", + fprintf(stderr, "dsmark: empty value\n"); + else fprintf(f, "value 0x%02x ", rta_getattr_u8(tb[TCA_DSMARK_VALUE])); } if (tb[TCA_DSMARK_INDICES]) { if (RTA_PAYLOAD(tb[TCA_DSMARK_INDICES]) < sizeof(__u16)) - fprintf(stderr,"dsmark: indices too short\n"); - else fprintf(f,"indices 0x%04x ", + fprintf(stderr, "dsmark: indices too short\n"); + else fprintf(f, "indices 0x%04x ", rta_getattr_u16(tb[TCA_DSMARK_INDICES])); } if (tb[TCA_DSMARK_DEFAULT_INDEX]) { if (RTA_PAYLOAD(tb[TCA_DSMARK_DEFAULT_INDEX]) < sizeof(__u16)) - fprintf(stderr,"dsmark: default_index too short\n"); - else fprintf(f,"default_index 0x%04x ", + fprintf(stderr, "dsmark: default_index too short\n"); + else fprintf(f, "default_index 0x%04x ", rta_getattr_u16(tb[TCA_DSMARK_DEFAULT_INDEX])); } - if (tb[TCA_DSMARK_SET_TC_INDEX]) fprintf(f,"set_tc_index "); + if (tb[TCA_DSMARK_SET_TC_INDEX]) fprintf(f, "set_tc_index "); return 0; } diff --git a/tc/q_fifo.c b/tc/q_fifo.c index c9ab123f0..f7fc88b38 100644 --- a/tc/q_fifo.c +++ b/tc/q_fifo.c @@ -30,8 +30,9 @@ static void explain(void) static int fifo_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - int ok=0; + int ok = 0; struct tc_fifo_qopt opt; + memset(&opt, 0, sizeof(opt)); while (argc > 0) { diff --git a/tc/q_fq.c b/tc/q_fq.c index 2a370b365..90147a6aa 100644 --- a/tc/q_fq.c +++ b/tc/q_fq.c @@ -218,6 +218,7 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) unsigned int rate, quantum; unsigned int refill_delay; unsigned int orphan_mask; + SPRINT_BUF(b1); if (opt == NULL) diff --git a/tc/q_fq_codel.c b/tc/q_fq_codel.c index 0392c64fe..f9244ee6c 100644 --- a/tc/q_fq_codel.c +++ b/tc/q_fq_codel.c @@ -59,12 +59,12 @@ static void explain(void) static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - unsigned limit = 0; - unsigned flows = 0; - unsigned target = 0; - unsigned interval = 0; - unsigned quantum = 0; - unsigned ce_threshold = ~0U; + unsigned int limit = 0; + unsigned int flows = 0; + unsigned int target = 0; + unsigned int interval = 0; + unsigned int quantum = 0; + unsigned int ce_threshold = ~0U; int ecn = -1; struct rtattr *tail; @@ -144,13 +144,14 @@ static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { struct rtattr *tb[TCA_FQ_CODEL_MAX + 1]; - unsigned limit; - unsigned flows; - unsigned interval; - unsigned target; - unsigned ecn; - unsigned quantum; - unsigned ce_threshold; + unsigned int limit; + unsigned int flows; + unsigned int interval; + unsigned int target; + unsigned int ecn; + unsigned int quantum; + unsigned int ce_threshold; + SPRINT_BUF(b1); if (opt == NULL) @@ -202,6 +203,7 @@ static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) { struct tc_fq_codel_xstats _st, *st; + SPRINT_BUF(b1); if (xstats == NULL) diff --git a/tc/q_gred.c b/tc/q_gred.c index f31daa37d..0a9894966 100644 --- a/tc/q_gred.c +++ b/tc/q_gred.c @@ -30,9 +30,9 @@ #if 0 -#define DPRINTF(format,args...) fprintf(stderr,format,##args) +#define DPRINTF(format, args...) fprintf(stderr, format, ##args) #else -#define DPRINTF(format,args...) +#define DPRINTF(format, args...) #endif static void explain(void) @@ -55,7 +55,7 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv, opt.def_DP = MAX_DPs; while (argc > 0) { - DPRINTF(stderr,"init_gred: invoked with %s\n",*argv); + DPRINTF(stderr, "init_gred: invoked with %s\n", *argv); if (strcmp(*argv, "vqs") == 0 || strcmp(*argv, "DPs") == 0) { NEXT_ARG(); @@ -63,14 +63,13 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv, fprintf(stderr, "Illegal \"vqs\"\n"); return -1; } else if (opt.DPs > MAX_DPs) { - fprintf(stderr, "GRED: only %u VQs are " - "currently supported\n", MAX_DPs); + fprintf(stderr, "GRED: only %u VQs are currently supported\n", + MAX_DPs); return -1; } } else if (strcmp(*argv, "default") == 0) { if (opt.DPs == 0) { - fprintf(stderr, "\"default\" must be defined " - "after \"vqs\"\n"); + fprintf(stderr, "\"default\" must be defined after \"vqs\"\n"); return -1; } NEXT_ARG(); @@ -78,8 +77,7 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv, fprintf(stderr, "Illegal \"default\"\n"); return -1; } else if (opt.def_DP >= opt.DPs) { - fprintf(stderr, "\"default\" must be less than " - "\"vqs\"\n"); + fprintf(stderr, "\"default\" must be less than \"vqs\"\n"); return -1; } } else if (strcmp(*argv, "grio") == 0) { @@ -102,12 +100,12 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv, } if (!opt.DPs || opt.def_DP == MAX_DPs) { - fprintf(stderr, "Illegal gred setup parameters \n"); + fprintf(stderr, "Illegal gred setup parameters\n"); return -1; } - DPRINTF("TC_GRED: sending DPs=%u def_DP=%u\n",opt.DPs,opt.def_DP); - n->nlmsg_flags|=NLM_F_CREATE; + DPRINTF("TC_GRED: sending DPs=%u def_DP=%u\n", opt.DPs, opt.def_DP); + n->nlmsg_flags |= NLM_F_CREATE; tail = NLMSG_TAIL(n); addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); addattr_l(n, 1024, TCA_GRED_DPS, &opt, sizeof(struct tc_gred_sopt)); @@ -121,12 +119,12 @@ 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) { - int ok=0; + int ok = 0; struct tc_gred_qopt opt = { 0 }; - unsigned burst = 0; - unsigned avpkt = 0; + unsigned int burst = 0; + unsigned int avpkt = 0; double probability = 0.02; - unsigned rate = 0; + unsigned int rate = 0; int parm; __u8 sbuf[256]; struct rtattr *tail; @@ -169,8 +167,8 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n fprintf(stderr, "Illegal \"vq\"\n"); return -1; } else if (opt.DP >= MAX_DPs) { - fprintf(stderr, "GRED: only %u VQs are " - "currently supported\n", MAX_DPs); + fprintf(stderr, "GRED: only %u VQs are currently supported\n", + MAX_DPs); return -1; } /* need a better error check */ ok++; @@ -197,7 +195,7 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n ok++; } else if (strcmp(*argv, "prio") == 0) { NEXT_ARG(); - opt.prio=strtol(*argv, (char **)NULL, 10); + opt.prio = strtol(*argv, (char **)NULL, 10); /* some error check here */ ok++; } else if (strcmp(*argv, "bandwidth") == 0) { @@ -224,8 +222,7 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n } if (opt.DP == MAX_DPs || !opt.limit || !opt.qth_min || !opt.qth_max || !avpkt) { - fprintf(stderr, "Required parameter (vq, limit, min, max, " - "avpkt) is missing\n"); + fprintf(stderr, "Required parameter (vq, limit, min, max, avpkt) is missing\n"); return -1; } if (!burst) { @@ -241,8 +238,8 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n return -1; } if (parm >= 10) - fprintf(stderr, "GRED: WARNING. Burst %u seems to be too " - "large.\n", burst); + fprintf(stderr, "GRED: WARNING. Burst %u seems to be too large.\n", + burst); opt.Wlog = parm; if ((parm = tc_red_eval_P(opt.qth_min, opt.qth_max, probability)) < 0) { fprintf(stderr, "GRED: failed to calculate probability.\n"); @@ -251,8 +248,7 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n opt.Plog = parm; if ((parm = tc_red_eval_idle_damping(opt.Wlog, avpkt, rate, sbuf)) < 0) { - fprintf(stderr, "GRED: failed to calculate idle damping " - "table.\n"); + fprintf(stderr, "GRED: failed to calculate idle damping table.\n"); return -1; } opt.Scell_log = parm; @@ -274,7 +270,8 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct tc_gred_qopt *qopt; __u32 *max_p = NULL; __u32 *limit = NULL; - unsigned i; + unsigned int i; + SPRINT_BUF(b1); SPRINT_BUF(b2); SPRINT_BUF(b3); @@ -299,7 +296,7 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) qopt = RTA_DATA(tb[TCA_GRED_PARMS]); if (RTA_PAYLOAD(tb[TCA_GRED_DPS]) < sizeof(*sopt) || RTA_PAYLOAD(tb[TCA_GRED_PARMS]) < sizeof(*qopt)*MAX_DPs) { - fprintf(f,"\n GRED received message smaller than expected\n"); + fprintf(f, "\n GRED received message smaller than expected\n"); return -1; } @@ -314,7 +311,7 @@ static int gred_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) fprintf(f, "limit %s ", sprint_size(*limit, b1)); - for (i=0;iDP >= MAX_DPs) continue; fprintf(f, "\n vq %u prio %hhu limit %s min %s max %s ", qopt->DP, diff --git a/tc/q_hfsc.c b/tc/q_hfsc.c index 03539ec1a..9ebe323ed 100644 --- a/tc/q_hfsc.c +++ b/tc/q_hfsc.c @@ -144,7 +144,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) { struct tc_service_curve rsc, fsc, usc; int rsc_ok, fsc_ok, usc_ok; @@ -203,8 +203,7 @@ hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, return -1; } if (usc_ok && !fsc_ok) { - fprintf(stderr, "HFSC: Upper-limit Service Curve without " - "Link-Share Service Curve\n"); + fprintf(stderr, "HFSC: Upper-limit Service Curve without Link-Share Service Curve\n"); explain_class(); return -1; } diff --git a/tc/q_hhf.c b/tc/q_hhf.c index 06ec8a28e..738b56360 100644 --- a/tc/q_hhf.c +++ b/tc/q_hhf.c @@ -28,13 +28,13 @@ static void explain(void) static int hhf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - unsigned limit = 0; - unsigned quantum = 0; - unsigned hh_limit = 0; - unsigned reset_timeout = 0; - unsigned admit_bytes = 0; - unsigned evict_timeout = 0; - unsigned non_hh_weight = 0; + unsigned int limit = 0; + unsigned int quantum = 0; + unsigned int hh_limit = 0; + unsigned int reset_timeout = 0; + unsigned int admit_bytes = 0; + unsigned int evict_timeout = 0; + unsigned int non_hh_weight = 0; struct rtattr *tail; while (argc > 0) { @@ -120,13 +120,14 @@ static int hhf_parse_opt(struct qdisc_util *qu, int argc, char **argv, static int hhf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { struct rtattr *tb[TCA_HHF_MAX + 1]; - unsigned limit; - unsigned quantum; - unsigned hh_limit; - unsigned reset_timeout; - unsigned admit_bytes; - unsigned evict_timeout; - unsigned non_hh_weight; + unsigned int limit; + unsigned int quantum; + unsigned int hh_limit; + unsigned int reset_timeout; + unsigned int admit_bytes; + unsigned int evict_timeout; + unsigned int non_hh_weight; + SPRINT_BUF(b1); if (opt == NULL) diff --git a/tc/q_htb.c b/tc/q_htb.c index 7d5409085..9c1a4f86f 100644 --- a/tc/q_htb.c +++ b/tc/q_htb.c @@ -49,7 +49,7 @@ static void explain(void) " mtu max packet size we create rate map for {1600}\n" " prio priority of leaf; lower are served first {0}\n" " quantum how much bytes to serve from leaf at once {use r2q}\n" - "\nTC HTB version %d.%d\n",HTB_TC_VER>>16,HTB_TC_VER&0xffff + "\nTC HTB version %d.%d\n", HTB_TC_VER>>16, HTB_TC_VER&0xffff ); } @@ -65,8 +65,9 @@ static int htb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl unsigned int direct_qlen = ~0U; struct tc_htb_glob opt; struct rtattr *tail; - unsigned i; char *p; - memset(&opt,0,sizeof(opt)); + unsigned int i; char *p; + + memset(&opt, 0, sizeof(opt)); opt.rate2quantum = 10; opt.version = 3; @@ -83,8 +84,8 @@ static int htb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl } } else if (matches(*argv, "debug") == 0) { NEXT_ARG(); p = *argv; - for (i=0; i<16; i++,p++) { - if (*p<'0' || *p>'3') break; + for (i = 0; i < 16; i++, p++) { + if (*p < '0' || *p > '3') break; opt.debug |= (*p-'0')<<(2*i); } } else if (matches(*argv, "direct_qlen") == 0) { @@ -111,12 +112,12 @@ static int htb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - int ok=0; + int ok = 0; struct tc_htb_opt opt; - __u32 rtab[256],ctab[256]; - unsigned buffer=0,cbuffer=0; - int cell_log=-1,ccell_log = -1; - unsigned mtu; + __u32 rtab[256], ctab[256]; + unsigned buffer = 0, cbuffer = 0; + int cell_log = -1, ccell_log = -1; + unsigned int mtu; unsigned short mpu = 0; unsigned short overhead = 0; unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ @@ -268,9 +269,10 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct rtattr *tb[TCA_HTB_MAX + 1]; struct tc_htb_opt *hopt; struct tc_htb_glob *gopt; - double buffer,cbuffer; + double buffer, cbuffer; unsigned int linklayer; __u64 rate64, ceil64; + SPRINT_BUF(b1); SPRINT_BUF(b2); SPRINT_BUF(b3); @@ -327,16 +329,16 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } if (show_raw) fprintf(f, "buffer [%08x] cbuffer [%08x] ", - hopt->buffer,hopt->cbuffer); + hopt->buffer, hopt->cbuffer); } if (tb[TCA_HTB_INIT]) { 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); + gopt->rate2quantum, gopt->defcls, gopt->direct_pkts); if (show_details) - fprintf(f," ver %d.%d",gopt->version >> 16,gopt->version & 0xffff); + fprintf(f, " ver %d.%d", gopt->version >> 16, gopt->version & 0xffff); } if (tb[TCA_HTB_DIRECT_QLEN] && RTA_PAYLOAD(tb[TCA_HTB_DIRECT_QLEN]) >= sizeof(__u32)) { @@ -350,6 +352,7 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) static int htb_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) { struct tc_htb_xstats *st; + if (xstats == NULL) return 0; @@ -358,16 +361,16 @@ static int htb_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstat st = RTA_DATA(xstats); fprintf(f, " lended: %u borrowed: %u giants: %u\n", - st->lends,st->borrows,st->giants); - fprintf(f, " tokens: %d ctokens: %d\n", st->tokens,st->ctokens); + st->lends, st->borrows, st->giants); + fprintf(f, " tokens: %d ctokens: %d\n", st->tokens, st->ctokens); return 0; } struct qdisc_util htb_qdisc_util = { - .id = "htb", + .id = "htb", .parse_qopt = htb_parse_opt, .print_qopt = htb_print_opt, - .print_xstats = htb_print_xstats, + .print_xstats = htb_print_xstats, .parse_copt = htb_parse_class_opt, .print_copt = htb_print_opt, }; diff --git a/tc/q_multiq.c b/tc/q_multiq.c index f4f41f78c..782393149 100644 --- a/tc/q_multiq.c +++ b/tc/q_multiq.c @@ -77,7 +77,7 @@ static int multiq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } struct qdisc_util multiq_qdisc_util = { - .id = "multiq", + .id = "multiq", .parse_qopt = multiq_parse_opt, .print_qopt = multiq_print_opt, }; diff --git a/tc/q_netem.c b/tc/q_netem.c index 7bc8c6a58..8fe220416 100644 --- a/tc/q_netem.c +++ b/tc/q_netem.c @@ -30,10 +30,10 @@ static void explain(void) { fprintf(stderr, -"Usage: ... netem [ limit PACKETS ] \n" \ +"Usage: ... netem [ limit PACKETS ]\n" \ " [ delay TIME [ JITTER [CORRELATION]]]\n" \ " [ distribution {uniform|normal|pareto|paretonormal} ]\n" \ -" [ corrupt PERCENT [CORRELATION]] \n" \ +" [ corrupt PERCENT [CORRELATION]]\n" \ " [ duplicate PERCENT [CORRELATION]]\n" \ " [ loss random PERCENT [CORRELATION]]\n" \ " [ loss state P13 [P31 [P32 [P23 P14]]]\n" \ @@ -58,7 +58,7 @@ static const double max_percent_value = 0xffffffff; /* scaled value used to percent of maximum. */ static void set_percent(__u32 *percent, double per) { - *percent = (unsigned) rint(per * max_percent_value); + *percent = (unsigned int) rint(per * max_percent_value); } @@ -70,7 +70,7 @@ static int parse_percent(double *val, const char *str) char *p; *val = strtod(str, &p) / 100.; - if (*p && strcmp(p, "%") ) + if (*p && strcmp(p, "%")) return -1; return 0; @@ -92,7 +92,7 @@ static void print_percent(char *buf, int len, __u32 per) snprintf(buf, len, "%g%%", 100. * (double) per / max_percent_value); } -static char * sprint_percent(__u32 per, char *buf) +static char *sprint_percent(__u32 per, char *buf) { print_percent(buf, SPRINT_BSIZE-1, per); return buf; @@ -123,6 +123,7 @@ static int get_distribution(const char *type, __s16 *data, int maxdata) n = 0; while (getline(&line, &len, f) != -1) { char *p, *endp; + if (*line == '\n' || *line == '#') continue; @@ -154,9 +155,9 @@ static int get_distribution(const char *type, __s16 *data, int maxdata) (based on kernel PSCHED_CLOCK configuration */ static int get_ticks(__u32 *ticks, const char *str) { - unsigned t; + unsigned int t; - if(get_time(&t, str)) + if (get_time(&t, str)) return -1; if (tc_core_time2big(t)) { @@ -191,7 +192,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, memset(&rate, 0, sizeof(rate)); memset(present, 0, sizeof(present)); - for( ; argc > 0; --argc, ++argv) { + for ( ; argc > 0; --argc, ++argv) { if (matches(*argv, "limit") == 0) { NEXT_ARG(); if (get_size(&opt.limit, *argv)) { @@ -236,7 +237,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, if (!strcmp(*argv, "random")) { NEXT_ARG(); - random_loss_model: +random_loss_model: if (get_percent(&opt.loss, *argv)) { explain1("loss percent"); return -1; @@ -545,6 +546,7 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) const struct tc_netem_rate *rate = NULL; int len = RTA_PAYLOAD(opt) - sizeof(qopt); __u64 rate64 = 0; + SPRINT_BUF(b1); if (opt == NULL) @@ -558,6 +560,7 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (len > 0) { struct rtattr *tb[TCA_NETEM_MAX+1]; + parse_rtattr(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(qopt), len); @@ -684,7 +687,7 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } struct qdisc_util netem_qdisc_util = { - .id = "netem", + .id = "netem", .parse_qopt = netem_parse_opt, .print_qopt = netem_print_opt, }; diff --git a/tc/q_pie.c b/tc/q_pie.c index 193b05dee..069a752b8 100644 --- a/tc/q_pie.c +++ b/tc/q_pie.c @@ -136,8 +136,9 @@ static int pie_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) unsigned int target; unsigned int alpha; unsigned int beta; - unsigned ecn; - unsigned bytemode; + unsigned int ecn; + unsigned int bytemode; + SPRINT_BUF(b1); if (opt == NULL) diff --git a/tc/q_prio.c b/tc/q_prio.c index 3236bec1a..a28928a85 100644 --- a/tc/q_prio.c +++ b/tc/q_prio.c @@ -32,7 +32,7 @@ static int prio_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n { int pmap_mode = 0; int idx = 0; - struct tc_prio_qopt opt={3,{ 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }}; + struct tc_prio_qopt opt = {3, { 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 } }; struct rtattr *nest; unsigned char mq = 0; @@ -57,7 +57,8 @@ static int prio_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n explain(); return -1; } else { - unsigned band; + unsigned int band; + if (!pmap_mode) { fprintf(stderr, "What is \"%s\"?\n", *argv); explain(); @@ -104,10 +105,10 @@ int prio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt, sizeof(*qopt))) - return -1; + return -1; fprintf(f, "bands %u priomap ", qopt->bands); - for (i=0; i<=TC_PRIO_MAX; i++) + for (i = 0; i <= TC_PRIO_MAX; i++) fprintf(f, " %d", qopt->priomap[i]); if (tb[TCA_PRIO_MQ]) @@ -118,7 +119,7 @@ int prio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } struct qdisc_util prio_qdisc_util = { - .id = "prio", + .id = "prio", .parse_qopt = prio_parse_opt, .print_qopt = prio_print_opt, }; diff --git a/tc/q_red.c b/tc/q_red.c index abd86c7bc..e015cbdaf 100644 --- a/tc/q_red.c +++ b/tc/q_red.c @@ -36,10 +36,10 @@ static void explain(void) static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { struct tc_red_qopt opt; - unsigned burst = 0; - unsigned avpkt = 0; + unsigned int burst = 0; + unsigned int avpkt = 0; double probability = 0.02; - unsigned rate = 0; + unsigned int rate = 0; int parm; __u8 sbuf[256]; __u32 max_P; @@ -160,6 +160,7 @@ static int red_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct rtattr *tb[TCA_RED_MAX + 1]; struct tc_red_qopt *qopt; __u32 max_P = 0; + SPRINT_BUF(b1); SPRINT_BUF(b2); SPRINT_BUF(b3); diff --git a/tc/q_rr.c b/tc/q_rr.c index e8a916525..f330311d2 100644 --- a/tc/q_rr.c +++ b/tc/q_rr.c @@ -33,7 +33,7 @@ static int rr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlm { int pmap_mode = 0; int idx = 0; - struct tc_prio_qopt opt={3,{ 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }}; + struct tc_prio_qopt opt = {3, { 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 } }; struct rtattr *nest; unsigned char mq = 0; @@ -58,7 +58,8 @@ static int rr_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlm } else if (strcmp(*argv, "multiqueue") == 0) { mq = 1; } else { - unsigned band; + unsigned int band; + if (!pmap_mode) { fprintf(stderr, "What is \"%s\"?\n", *argv); explain(); @@ -102,7 +103,7 @@ static int rr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) return -1; fprintf(f, "bands %u priomap ", qopt->bands); - for (i=0; i <= TC_PRIO_MAX; i++) + for (i = 0; i <= TC_PRIO_MAX; i++) fprintf(f, " %d", qopt->priomap[i]); if (tb[TCA_PRIO_MQ]) @@ -113,7 +114,7 @@ static int rr_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) } struct qdisc_util rr_qdisc_util = { - .id = "rr", + .id = "rr", .parse_qopt = rr_parse_opt, .print_qopt = rr_print_opt, }; diff --git a/tc/q_sfb.c b/tc/q_sfb.c index f11c33aa1..3b6d45269 100644 --- a/tc/q_sfb.c +++ b/tc/q_sfb.c @@ -158,8 +158,7 @@ static int sfb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) fprintf(f, "limit %d max %d target %d\n" - " increment %.5f decrement %.5f penalty rate %d burst %d " - "(%ums %ums)", + " increment %.5f decrement %.5f penalty rate %d burst %d (%ums %ums)", qopt->limit, qopt->max, qopt->bin_size, (double)qopt->increment / SFB_MAX_PROB, (double)qopt->decrement / SFB_MAX_PROB, diff --git a/tc/q_sfq.c b/tc/q_sfq.c index 50846a98d..7d2165226 100644 --- a/tc/q_sfq.c +++ b/tc/q_sfq.c @@ -207,6 +207,7 @@ static int sfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { struct tc_sfq_qopt *qopt; struct tc_sfq_qopt_v1 *qopt_ext = NULL; + SPRINT_BUF(b1); SPRINT_BUF(b2); SPRINT_BUF(b3); diff --git a/tc/q_tbf.c b/tc/q_tbf.c index 0981e6f74..4a0c5ac75 100644 --- a/tc/q_tbf.c +++ b/tc/q_tbf.c @@ -38,13 +38,13 @@ 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) { - int ok=0; + int ok = 0; struct tc_tbf_qopt opt; __u32 rtab[256]; __u32 ptab[256]; - unsigned buffer=0, mtu=0, mpu=0, latency=0; - int Rcell_log=-1, Pcell_log = -1; - unsigned short overhead=0; + unsigned buffer = 0, mtu = 0, mpu = 0, latency = 0; + int Rcell_log = -1, Pcell_log = -1; + unsigned short overhead = 0; unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ struct rtattr *tail; __u64 rate64 = 0, prate64 = 0; @@ -86,6 +86,7 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl strcmp(*argv, "buffer") == 0 || strcmp(*argv, "maxburst") == 0) { const char *parm_name = *argv; + NEXT_ARG(); if (buffer) { fprintf(stderr, "tbf: duplicate \"buffer/burst/maxburst\" specification\n"); @@ -99,6 +100,7 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl } else if (strcmp(*argv, "mtu") == 0 || strcmp(*argv, "minburst") == 0) { const char *parm_name = *argv; + NEXT_ARG(); if (mtu) { fprintf(stderr, "tbf: duplicate \"mtu/minburst\" specification\n"); @@ -167,12 +169,12 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl argc--; argv++; } - int verdict = 0; + int verdict = 0; - /* Be nice to the user: try to emit all error messages in - * one go rather than reveal one more problem when a - * previous one has been fixed. - */ + /* Be nice to the user: try to emit all error messages in + * one go rather than reveal one more problem when a + * previous one has been fixed. + */ if (rate64 == 0) { fprintf(stderr, "tbf: the \"rate\" parameter is mandatory.\n"); verdict = -1; @@ -193,18 +195,20 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl verdict = -1; } - if (verdict != 0) { - explain(); - return verdict; - } + if (verdict != 0) { + explain(); + return verdict; + } opt.rate.rate = (rate64 >= (1ULL << 32)) ? ~0U : rate64; opt.peakrate.rate = (prate64 >= (1ULL << 32)) ? ~0U : prate64; if (opt.limit == 0) { double lim = rate64*(double)latency/TIME_UNITS_PER_SEC + buffer; + if (prate64) { double lim2 = prate64*(double)latency/TIME_UNITS_PER_SEC + mtu; + if (lim2 < lim) lim = lim2; } @@ -254,6 +258,7 @@ static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) double buffer, mtu; double latency; __u64 rate64 = 0, prate64 = 0; + SPRINT_BUF(b1); SPRINT_BUF(b2); SPRINT_BUF(b3); @@ -305,6 +310,7 @@ static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) latency = TIME_UNITS_PER_SEC*(qopt->limit/(double)rate64) - tc_core_tick2time(qopt->buffer); if (prate64) { double lat2 = TIME_UNITS_PER_SEC*(qopt->limit/(double)prate64) - tc_core_tick2time(qopt->mtu); + if (lat2 > latency) latency = lat2; } diff --git a/tc/tc.c b/tc/tc.c index 17078676f..d0ddb939d 100644 --- a/tc/tc.c +++ b/tc/tc.c @@ -31,33 +31,33 @@ #include "tc_common.h" #include "namespace.h" -int show_stats = 0; -int show_details = 0; -int show_raw = 0; -int show_pretty = 0; -int show_graph = 0; +int show_stats; +int show_details; +int show_raw; +int show_pretty; +int show_graph; int timestamp; -int batch_mode = 0; -int resolve_hosts = 0; -int use_iec = 0; -int force = 0; -bool use_names = false; +int batch_mode; +int resolve_hosts; +int use_iec; +int force; +bool use_names; static char *conf_file; struct rtnl_handle rth; -static void *BODY = NULL; /* cached handle dlopen(NULL) */ -static struct qdisc_util * qdisc_list; -static struct filter_util * filter_list; +static void *BODY; /* cached handle dlopen(NULL) */ +static struct qdisc_util *qdisc_list; +static struct filter_util *filter_list; static int print_noqopt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) { if (opt && RTA_PAYLOAD(opt)) fprintf(f, "[Unknown qdisc, optlen=%u] ", - (unsigned) RTA_PAYLOAD(opt)); + (unsigned int) RTA_PAYLOAD(opt)); return 0; } @@ -74,7 +74,7 @@ static int print_nofopt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u { if (opt && RTA_PAYLOAD(opt)) fprintf(f, "fh %08x [Unknown filter, optlen=%u] ", - fhandle, (unsigned) RTA_PAYLOAD(opt)); + fhandle, (unsigned int) RTA_PAYLOAD(opt)); else if (fhandle) fprintf(f, "fh %08x ", fhandle); return 0; @@ -90,6 +90,7 @@ static int parse_nofopt(struct filter_util *qu, char *fhandle, int argc, char ** } if (fhandle) { struct tcmsg *t = NLMSG_DATA(n); + if (get_u32(&handle, fhandle, 16)) { fprintf(stderr, "Unparsable filter ID \"%s\"\n", fhandle); return -1; @@ -191,9 +192,8 @@ static void usage(void) { fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n" " 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" + "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"); } diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index 6a94894ff..d94af828f 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -167,8 +167,7 @@ static int bpf_ops_parse(int argc, char **argv, struct sock_filter *bpf_ops, token = bpf_string; while ((token = strchr(token, separator)) && (++token)[0]) { if (i >= bpf_len) { - fprintf(stderr, "Real program length exceeds encoded " - "length parameter!\n"); + fprintf(stderr, "Real program length exceeds encoded length parameter!\n"); ret = -EINVAL; goto out; } @@ -185,8 +184,7 @@ static int bpf_ops_parse(int argc, char **argv, struct sock_filter *bpf_ops, } if (i != bpf_len) { - fprintf(stderr, "Parsed program length is less than encoded" - "length parameter!\n"); + fprintf(stderr, "Parsed program length is less than encodedlength parameter!\n"); ret = -EINVAL; goto out; } @@ -385,7 +383,7 @@ int bpf_trace_pipe(void) static const char *bpf_get_tc_dir(void) { - static bool bpf_mnt_cached = false; + static bool bpf_mnt_cached; static char bpf_tc_dir[PATH_MAX]; static const char *mnt; static const char * const bpf_known_mnts[] = { @@ -648,8 +646,7 @@ int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv) } else { ret = sscanf(section, "%*i/%i", &map_key); if (ret != 1) { - fprintf(stderr, "Couldn\'t infer map key from section " - "name! Please provide \'key\' argument!\n"); + fprintf(stderr, "Couldn\'t infer map key from section name! Please provide \'key\' argument!\n"); ret = -EINVAL; goto out_prog; } @@ -855,7 +852,7 @@ static int bpf_obj_hash(const char *object, uint8_t *out, size_t len) goto out_ofd; } - ret = fstat(ffd, &stbuff); + ret = fstat(ffd, &stbuff); if (ret < 0) { fprintf(stderr, "Error doing fstat: %s\n", strerror(errno)); @@ -889,7 +886,7 @@ static int bpf_obj_hash(const char *object, uint8_t *out, size_t len) static const char *bpf_get_obj_uid(const char *pathname) { - static bool bpf_uid_cached = false; + static bool bpf_uid_cached; static char bpf_uid[64]; uint8_t tmp[20]; int ret; @@ -920,8 +917,7 @@ static int bpf_init_env(const char *pathname) setrlimit(RLIMIT_MEMLOCK, &limit); if (!bpf_get_tc_dir()) { - fprintf(stderr, "Continuing without mounted eBPF fs. " - "Too old kernel?\n"); + fprintf(stderr, "Continuing without mounted eBPF fs. Too old kernel?\n"); return 0; } @@ -1091,8 +1087,7 @@ static int bpf_prog_attach(const char *section, if (tries++ < 6 && !bpf_log_realloc(ctx)) goto retry; - fprintf(stderr, "Log buffer too small to dump " - "verifier log %zu bytes (%d tries)!\n", + fprintf(stderr, "Log buffer too small to dump verifier log %zu bytes (%d tries)!\n", ctx->log_size, tries); return fd; } @@ -1311,8 +1306,8 @@ static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx) !strcmp(data.sec_name, ".strtab")) ret = bpf_fetch_strtab(ctx, i, &data); if (ret < 0) { - fprintf(stderr, "Error parsing section %d! Perhaps" - "check with readelf -a?\n", i); + fprintf(stderr, "Error parsing section %d! Perhapscheck with readelf -a?\n", + i); break; } } @@ -1383,21 +1378,18 @@ static int bpf_apply_relo_data(struct bpf_elf_ctx *ctx, ioff = relo.r_offset / sizeof(struct bpf_insn); if (ioff >= num_insns || insns[ioff].code != (BPF_LD | BPF_IMM | BPF_DW)) { - fprintf(stderr, "ELF contains relo data for non ld64 " - "instruction at offset %u! Compiler bug?!\n", + fprintf(stderr, "ELF contains relo data for non ld64 instruction at offset %u! Compiler bug?!\n", ioff); if (ioff < num_insns && insns[ioff].code == (BPF_JMP | BPF_CALL)) - fprintf(stderr, " - Try to annotate functions " - "with always_inline attribute!\n"); + fprintf(stderr, " - Try to annotate functions with always_inline attribute!\n"); return -EINVAL; } if (gelf_getsym(ctx->sym_tab, GELF_R_SYM(relo.r_info), &sym) != &sym) return -EIO; if (sym.st_shndx != ctx->sec_maps) { - fprintf(stderr, "ELF contains non-map related relo data in " - "entry %u pointing to section %u! Compiler bug?!\n", + fprintf(stderr, "ELF contains non-map related relo data in entry %u pointing to section %u! Compiler bug?!\n", relo_ent, sym.st_shndx); return -EIO; } @@ -1409,8 +1401,7 @@ static int bpf_apply_relo_data(struct bpf_elf_ctx *ctx, return -EINVAL; if (ctx->verbose) - fprintf(stderr, "Map \'%s\' (%d) injected into prog " - "section \'%s\' at offset %u!\n", + fprintf(stderr, "Map \'%s\' (%d) injected into prog section \'%s\' at offset %u!\n", bpf_str_tab_name(ctx, &sym), ctx->map_fds[rmap], data_insn->sec_name, ioff); @@ -1599,8 +1590,8 @@ static void bpf_hash_init(struct bpf_elf_ctx *ctx, const char *db_file) } if (bpf_pinning_reserved(pinning)) { - fprintf(stderr, "Database %s, id %u is reserved - " - "ignoring!\n", db_file, pinning); + fprintf(stderr, "Database %s, id %u is reserved - ignoring!\n", + db_file, pinning); continue; } diff --git a/tc/tc_cbq.c b/tc/tc_cbq.c index 0bb262eb5..5e50afa84 100644 --- a/tc/tc_cbq.c +++ b/tc/tc_cbq.c @@ -24,8 +24,8 @@ #include "tc_core.h" #include "tc_cbq.h" -unsigned tc_cbq_calc_maxidle(unsigned bndw, unsigned rate, unsigned avpkt, - int ewma_log, unsigned maxburst) +unsigned int tc_cbq_calc_maxidle(unsigned int bndw, unsigned int rate, unsigned int avpkt, + int ewma_log, unsigned int maxburst) { double maxidle; double g = 1.0 - 1.0/(1< maxidle) maxidle = vxmt; @@ -41,8 +42,8 @@ unsigned tc_cbq_calc_maxidle(unsigned bndw, unsigned rate, unsigned avpkt, return tc_core_time2tick(maxidle*(1<nlmsg_len; struct rtattr *tb[TCA_MAX + 1] = {}; @@ -430,6 +432,7 @@ static int tc_class_list(int argc, char **argv) t.tcm_parent = TC_H_ROOT; } else if (strcmp(*argv, "parent") == 0) { __u32 handle; + if (t.tcm_parent) duparg("parent", *argv); NEXT_ARG(); diff --git a/tc/tc_core.c b/tc/tc_core.c index 46eaefb54..194028ae0 100644 --- a/tc/tc_core.c +++ b/tc/tc_core.c @@ -27,7 +27,7 @@ static double tick_in_usec = 1; static double clock_factor = 1; -int tc_core_time2big(unsigned time) +int tc_core_time2big(unsigned int time) { __u64 t = time; @@ -36,32 +36,32 @@ int tc_core_time2big(unsigned time) } -unsigned tc_core_time2tick(unsigned time) +unsigned int tc_core_time2tick(unsigned int time) { return time*tick_in_usec; } -unsigned tc_core_tick2time(unsigned tick) +unsigned int tc_core_tick2time(unsigned int tick) { return tick/tick_in_usec; } -unsigned tc_core_time2ktime(unsigned time) +unsigned int tc_core_time2ktime(unsigned int time) { return time * clock_factor; } -unsigned tc_core_ktime2time(unsigned ktime) +unsigned int tc_core_ktime2time(unsigned int ktime) { return ktime / clock_factor; } -unsigned tc_calc_xmittime(__u64 rate, unsigned size) +unsigned int tc_calc_xmittime(__u64 rate, unsigned int size) { return tc_core_time2tick(TIME_UNITS_PER_SEC*((double)size/(double)rate)); } -unsigned tc_calc_xmitsize(__u64 rate, unsigned ticks) +unsigned int tc_calc_xmitsize(__u64 rate, unsigned int ticks) { return ((double)rate*tc_core_tick2time(ticks))/TIME_UNITS_PER_SEC; } @@ -76,9 +76,10 @@ unsigned tc_calc_xmitsize(__u64 rate, unsigned ticks) * (as the table will always be aligned for 48 bytes). * --Hawk, d.7/11-2004. */ -static unsigned tc_align_to_atm(unsigned size) +static unsigned int tc_align_to_atm(unsigned int size) { int linksize, cells; + cells = size / ATM_CELL_PAYLOAD; if ((size % ATM_CELL_PAYLOAD) > 0) cells++; @@ -87,7 +88,7 @@ static unsigned tc_align_to_atm(unsigned size) return linksize; } -static unsigned tc_adjust_size(unsigned sz, unsigned mpu, enum link_layer linklayer) +static unsigned int tc_adjust_size(unsigned int sz, unsigned int mpu, enum link_layer linklayer) { if (sz < mpu) sz = mpu; @@ -97,7 +98,7 @@ static unsigned tc_adjust_size(unsigned sz, unsigned mpu, enum link_layer linkla return tc_align_to_atm(sz); case LINKLAYER_ETHERNET: default: - // No size adjustments on Ethernet + /* No size adjustments on Ethernet */ return sz; } } @@ -122,13 +123,13 @@ static unsigned tc_adjust_size(unsigned sz, unsigned mpu, enum link_layer linkla */ int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab, - int cell_log, unsigned mtu, + int cell_log, unsigned int mtu, enum link_layer linklayer) { int i; - unsigned sz; - unsigned bps = r->rate; - unsigned mpu = r->mpu; + unsigned int sz; + unsigned int bps = r->rate; + unsigned int mpu = r->mpu; if (mtu == 0) mtu = 2047; @@ -139,13 +140,13 @@ int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab, cell_log++; } - for (i=0; i<256; i++) { + for (i = 0; i < 256; i++) { sz = tc_adjust_size((i + 1) << cell_log, mpu, linklayer); rtab[i] = tc_calc_xmittime(bps, sz); } - r->cell_align=-1; // Due to the sz calc - r->cell_log=cell_log; + r->cell_align = -1; + r->cell_log = cell_log; r->linklayer = (linklayer & TC_LINKLAYER_MASK); return cell_log; } @@ -193,7 +194,7 @@ int tc_calc_size_table(struct tc_sizespec *s, __u16 **stab) (*stab)[i] = sz >> s->size_log; } - s->cell_align = -1; // Due to the sz calc + s->cell_align = -1; /* Due to the sz calc */ return 0; } diff --git a/tc/tc_estimator.c b/tc/tc_estimator.c index e559add12..c40eea96f 100644 --- a/tc/tc_estimator.c +++ b/tc/tc_estimator.c @@ -23,22 +23,23 @@ #include "tc_core.h" -int tc_setup_estimator(unsigned A, unsigned time_const, struct tc_estimator *est) +int tc_setup_estimator(unsigned int A, unsigned int time_const, struct tc_estimator *est) { - for (est->interval=0; est->interval<=5; est->interval++) { + for (est->interval = 0; est->interval <= 5; est->interval++) { if (A <= (1<interval)*(TIME_UNITS_PER_SEC/4)) break; } if (est->interval > 5) return -1; est->interval -= 2; - for (est->ewma_log=1; est->ewma_log<32; est->ewma_log++) { + for (est->ewma_log = 1; est->ewma_log < 32; est->ewma_log++) { double w = 1.0 - 1.0/(1<ewma_log); + if (A/(-log(w)) > time_const) break; } est->ewma_log--; - if (est->ewma_log==0 || est->ewma_log >= 31) + if (est->ewma_log == 0 || est->ewma_log >= 31) return -1; return 0; } diff --git a/tc/tc_exec.c b/tc/tc_exec.c index 61be67218..520801623 100644 --- a/tc/tc_exec.c +++ b/tc/tc_exec.c @@ -19,7 +19,7 @@ #include "tc_common.h" static struct exec_util *exec_list; -static void *BODY = NULL; +static void *BODY; static void usage(void) { @@ -32,8 +32,8 @@ static void usage(void) static int parse_noeopt(struct exec_util *eu, int argc, char **argv) { if (argc) { - fprintf(stderr, "Unknown exec \"%s\", hence option \"%s\" " - "is unparsable\n", eu->id, *argv); + fprintf(stderr, "Unknown exec \"%s\", hence option \"%s\" is unparsable\n", + eu->id, *argv); return -1; } diff --git a/tc/tc_filter.c b/tc/tc_filter.c index 1a1082b44..66586634d 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -41,12 +41,12 @@ static void usage(void) fprintf(stderr, "OPTIONS := ... try tc filter add help\n"); } -static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) +static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv) { struct { - struct nlmsghdr n; - struct tcmsg t; - char buf[MAX_MSG]; + struct nlmsghdr n; + struct tcmsg t; + char buf[MAX_MSG]; } req; struct filter_util *q = NULL; __u32 prio = 0; @@ -99,6 +99,7 @@ static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) TC_H_MIN_EGRESS); } else if (strcmp(*argv, "parent") == 0) { __u32 handle; + NEXT_ARG(); if (req.t.tcm_parent) duparg("parent", *argv); @@ -119,6 +120,7 @@ static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) invarg("invalid priority value", *argv); } else if (matches(*argv, "protocol") == 0) { __u16 id; + NEXT_ARG(); if (protocol_set) duparg("protocol", *argv); @@ -153,8 +155,7 @@ static int tc_filter_modify(int cmd, unsigned flags, int argc, char **argv) return 1; } else { if (fhandle) { - fprintf(stderr, "Must specify filter type when using " - "\"handle\"\n"); + fprintf(stderr, "Must specify filter type when using \"handle\"\n"); return -1; } if (argc) { @@ -189,16 +190,16 @@ static __u32 filter_parent; static int filter_ifindex; static __u32 filter_prio; static __u32 filter_protocol; -__u16 f_proto = 0; +__u16 f_proto; int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct tcmsg *t = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[TCA_MAX+1]; + struct rtattr *tb[TCA_MAX+1]; struct filter_util *q; char abuf[256]; @@ -243,6 +244,7 @@ int print_filter(const struct sockaddr_nl *who, if (t->tcm_info) { f_proto = TC_H_MIN(t->tcm_info); __u32 prio = TC_H_MAJ(t->tcm_info)>>16; + if (!filter_protocol || filter_protocol != f_proto) { if (f_proto) { SPRINT_BUF(b1); @@ -316,6 +318,7 @@ static int tc_filter_list(int argc, char **argv) t.tcm_parent = filter_parent; } else if (strcmp(*argv, "parent") == 0) { __u32 handle; + NEXT_ARG(); if (t.tcm_parent) duparg("parent", *argv); @@ -337,6 +340,7 @@ static int tc_filter_list(int argc, char **argv) filter_prio = prio; } else if (matches(*argv, "protocol") == 0) { __u16 res; + NEXT_ARG(); if (protocol) duparg("protocol", *argv); @@ -401,7 +405,7 @@ int do_filter(int argc, char **argv) if (matches(*argv, "help") == 0) { usage(); return 0; - } + } fprintf(stderr, "Command \"%s\" is unknown, try \"tc filter help\".\n", *argv); return -1; } diff --git a/tc/tc_monitor.c b/tc/tc_monitor.c index ebb943208..83142cb21 100644 --- a/tc/tc_monitor.c +++ b/tc/tc_monitor.c @@ -39,7 +39,7 @@ static int accept_tcmsg(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; if (timestamp) print_timestamp(fp); @@ -73,7 +73,7 @@ int do_tcmonitor(int argc, char **argv) { struct rtnl_handle rth; char *file = NULL; - unsigned groups = nl_mgrp(RTNLGRP_TC); + unsigned int groups = nl_mgrp(RTNLGRP_TC); while (argc > 0) { if (matches(*argv, "file") == 0) { @@ -109,7 +109,7 @@ int do_tcmonitor(int argc, char **argv) ll_init_map(&rth); - if (rtnl_listen(&rth, accept_tcmsg, (void*)stdout) < 0) { + if (rtnl_listen(&rth, accept_tcmsg, (void *)stdout) < 0) { rtnl_close(&rth); exit(2); } diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index cb861e085..a63c47625 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -42,7 +42,7 @@ static int usage(void) return -1; } -static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) +static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv) { struct qdisc_util *q = NULL; struct tc_estimator est; @@ -53,9 +53,9 @@ static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) char d[16]; char k[16]; struct { - struct nlmsghdr n; - struct tcmsg t; - char buf[TCA_BUF_MAX]; + struct nlmsghdr n; + struct tcmsg t; + char buf[TCA_BUF_MAX]; } req; memset(&req, 0, sizeof(req)); @@ -77,6 +77,7 @@ static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) strncpy(d, *argv, sizeof(d)-1); } else if (strcmp(*argv, "handle") == 0) { __u32 handle; + if (req.t.tcm_handle) duparg("handle", *argv); NEXT_ARG(); @@ -113,6 +114,7 @@ static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) break; } else if (strcmp(*argv, "parent") == 0) { __u32 handle; + NEXT_ARG(); if (req.t.tcm_parent) duparg("parent", *argv); @@ -205,10 +207,10 @@ int print_qdisc(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct tcmsg *t = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[TCA_MAX+1]; + struct rtattr *tb[TCA_MAX+1]; struct qdisc_util *q; char abuf[256]; @@ -296,13 +298,13 @@ static int tc_qdisc_list(int argc, char **argv) if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); strncpy(d, *argv, sizeof(d)-1); - } else if (strcmp(*argv, "ingress") == 0 || + } else if (strcmp(*argv, "ingress") == 0 || strcmp(*argv, "clsact") == 0) { - if (t.tcm_parent) { - fprintf(stderr, "Duplicate parent ID\n"); - usage(); - } - t.tcm_parent = TC_H_INGRESS; + if (t.tcm_parent) { + fprintf(stderr, "Duplicate parent ID\n"); + usage(); + } + t.tcm_parent = TC_H_INGRESS; } else if (matches(*argv, "help") == 0) { usage(); } else { @@ -360,7 +362,7 @@ int do_qdisc(int argc, char **argv) if (matches(*argv, "help") == 0) { usage(); return 0; - } + } fprintf(stderr, "Command \"%s\" is unknown, try \"tc qdisc help\".\n", *argv); return -1; } diff --git a/tc/tc_red.c b/tc/tc_red.c index 81a83bd2e..e9b2f0ee3 100644 --- a/tc/tc_red.c +++ b/tc/tc_red.c @@ -27,7 +27,7 @@ /* Plog = log(prob/(qmax - qmin)) */ -int tc_red_eval_P(unsigned qmin, unsigned qmax, double prob) +int tc_red_eval_P(unsigned int qmin, unsigned int qmax, double prob) { int i = qmax - qmin; @@ -36,12 +36,12 @@ int tc_red_eval_P(unsigned qmin, unsigned qmax, double prob) prob /= i; - for (i=0; i<32; i++) { + for (i = 0; i < 32; i++) { if (prob > 1.0) break; prob *= 2; } - if (i>=32) + if (i >= 32) return -1; return i; } @@ -50,18 +50,18 @@ int tc_red_eval_P(unsigned qmin, unsigned qmax, double prob) burst + 1 - qmin/avpkt < (1-(1-W)^burst)/W */ -int tc_red_eval_ewma(unsigned qmin, unsigned burst, unsigned avpkt) +int tc_red_eval_ewma(unsigned int qmin, unsigned int burst, unsigned int avpkt) { int wlog = 1; double W = 0.5; double a = (double)burst + 1 - (double)qmin/avpkt; if (a < 1.0) { - fprintf(stderr, "tc_red_eval_ewma() burst %u is too small ?" - " Try burst %u\n", burst, 1 + qmin/avpkt); + fprintf(stderr, "tc_red_eval_ewma() burst %u is too small ? Try burst %u\n", + burst, 1 + qmin/avpkt); return -1; } - for (wlog=1; wlog<32; wlog++, W /= 2) { + for (wlog = 1; wlog < 32; wlog++, W /= 2) { if (a <= (1 - pow(1-W, burst))/W) return wlog; } @@ -72,7 +72,7 @@ int tc_red_eval_ewma(unsigned qmin, unsigned burst, unsigned avpkt) Stab[t>>Scell_log] = -log(1-W) * t/xmit_time */ -int tc_red_eval_idle_damping(int Wlog, unsigned avpkt, unsigned bps, __u8 *sbuf) +int tc_red_eval_idle_damping(int Wlog, unsigned int avpkt, unsigned int bps, __u8 *sbuf) { double xmit_time = tc_calc_xmittime(bps, avpkt); double lW = -log(1.0 - 1.0/(1< 31) sbuf[i] = 31; diff --git a/tc/tc_stab.c b/tc/tc_stab.c index aba8ae879..d7e00025c 100644 --- a/tc/tc_stab.c +++ b/tc/tc_stab.c @@ -31,7 +31,7 @@ static void stab_help(void) { fprintf(stderr, - "Usage: ... stab [ mtu BYTES ] [ tsize SLOTS ] [ mpu BYTES ] \n" + "Usage: ... stab [ mtu BYTES ] [ tsize SLOTS ] [ mpu BYTES ]\n" " [ overhead BYTES ] [ linklayer TYPE ] ...\n" " mtu : max packet size we create rate map for {2047}\n" " tsize : how many slots should size table have {512}\n" @@ -110,12 +110,14 @@ int parse_size_table(int *argcp, char ***argvp, struct tc_sizespec *sp) void print_size_table(FILE *fp, const char *prefix, struct rtattr *rta) { struct rtattr *tb[TCA_STAB_MAX + 1]; + SPRINT_BUF(b1); parse_rtattr_nested(tb, TCA_STAB_MAX, rta); if (tb[TCA_STAB_BASE]) { struct tc_sizespec s = {0}; + memcpy(&s, RTA_DATA(tb[TCA_STAB_BASE]), MIN(RTA_PAYLOAD(tb[TCA_STAB_BASE]), sizeof(s))); @@ -135,8 +137,9 @@ void print_size_table(FILE *fp, const char *prefix, struct rtattr *rta) #if 0 if (tb[TCA_STAB_DATA]) { - unsigned i, j, dlen; + unsigned int i, j, dlen; __u16 *data = RTA_DATA(tb[TCA_STAB_DATA]); + dlen = RTA_PAYLOAD(tb[TCA_STAB_DATA]) / sizeof(__u16); fprintf(fp, "\n%sstab data:", prefix); diff --git a/tc/tc_util.c b/tc/tc_util.c index 4764ecce4..afc4cf5ac 100644 --- a/tc/tc_util.c +++ b/tc/tc_util.c @@ -32,7 +32,7 @@ #define LIBDIR "/usr/lib" #endif -static struct db_names *cls_names = NULL; +static struct db_names *cls_names; #define NAMES_DB "/etc/iproute2/tc_cls" @@ -85,7 +85,7 @@ int get_qdisc_handle(__u32 *h, const char *str) if (p == str) return -1; maj <<= 16; - if (*p != ':' && *p!=0) + if (*p != ':' && *p != 0) return -1; ok: *h = maj; @@ -192,7 +192,7 @@ static const struct rate_suffix { }; -int get_rate(unsigned *rate, const char *str) +int get_rate(unsigned int *rate, const char *str) { char *p; double bps = strtod(str, &p); @@ -266,13 +266,13 @@ void print_rate(char *buf, int len, __u64 rate) snprintf(buf, len, "%.0f%s%sbit", (double)rate, units[i], str); } -char * sprint_rate(__u64 rate, char *buf) +char *sprint_rate(__u64 rate, char *buf) { print_rate(buf, SPRINT_BSIZE-1, rate); return buf; } -int get_time(unsigned *time, const char *str) +int get_time(unsigned int *time, const char *str) { double t; char *p; @@ -282,13 +282,13 @@ int get_time(unsigned *time, const char *str) return -1; if (*p) { - if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec")==0 || - strcasecmp(p, "secs")==0) + if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec") == 0 || + strcasecmp(p, "secs") == 0) t *= TIME_UNITS_PER_SEC; - else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec")==0 || + else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec") == 0 || strcasecmp(p, "msecs") == 0) t *= TIME_UNITS_PER_SEC/1000; - else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec")==0 || + else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec") == 0 || strcasecmp(p, "usecs") == 0) t *= TIME_UNITS_PER_SEC/1000000; else @@ -312,18 +312,18 @@ void print_time(char *buf, int len, __u32 time) snprintf(buf, len, "%uus", time); } -char * sprint_time(__u32 time, char *buf) +char *sprint_time(__u32 time, char *buf) { print_time(buf, SPRINT_BSIZE-1, time); return buf; } -char * sprint_ticks(__u32 ticks, char *buf) +char *sprint_ticks(__u32 ticks, char *buf) { return sprint_time(tc_core_tick2time(ticks), buf); } -int get_size(unsigned *size, const char *str) +int get_size(unsigned int *size, const char *str) { double sz; char *p; @@ -333,13 +333,13 @@ int get_size(unsigned *size, const char *str) return -1; if (*p) { - if (strcasecmp(p, "kb") == 0 || strcasecmp(p, "k")==0) + if (strcasecmp(p, "kb") == 0 || strcasecmp(p, "k") == 0) sz *= 1024; - else if (strcasecmp(p, "gb") == 0 || strcasecmp(p, "g")==0) + else if (strcasecmp(p, "gb") == 0 || strcasecmp(p, "g") == 0) sz *= 1024*1024*1024; else if (strcasecmp(p, "gbit") == 0) sz *= 1024*1024*1024/8; - else if (strcasecmp(p, "mb") == 0 || strcasecmp(p, "m")==0) + else if (strcasecmp(p, "mb") == 0 || strcasecmp(p, "m") == 0) sz *= 1024*1024; else if (strcasecmp(p, "mbit") == 0) sz *= 1024*1024/8; @@ -353,9 +353,9 @@ int get_size(unsigned *size, const char *str) return 0; } -int get_size_and_cell(unsigned *size, int *cell_log, char *str) +int get_size_and_cell(unsigned int *size, int *cell_log, char *str) { - char * slash = strchr(str, '/'); + char *slash = strchr(str, '/'); if (slash) *slash = 0; @@ -371,7 +371,7 @@ int get_size_and_cell(unsigned *size, int *cell_log, char *str) return -1; *slash = '/'; - for (i=0; i<32; i++) { + for (i = 0; i < 32; i++) { if ((1<>16); } -char * sprint_qdisc_handle(__u32 h, char *buf) +char *sprint_qdisc_handle(__u32 h, char *buf) { print_qdisc_handle(buf, SPRINT_BSIZE-1, h); return buf; } -char * action_n2a(int action, char *buf, int len) +char *action_n2a(int action, char *buf, int len) { switch (action) { case -1: @@ -453,6 +453,7 @@ int action_a2n(char *arg, int *result) res = TC_ACT_RECLASSIFY; else { char dummy; + if (sscanf(arg, "%d%c", &res, &dummy) != 1) return -1; } @@ -460,7 +461,7 @@ int action_a2n(char *arg, int *result) return 0; } -int get_linklayer(unsigned *val, const char *arg) +int get_linklayer(unsigned int *val, const char *arg) { int res; @@ -477,7 +478,7 @@ int get_linklayer(unsigned *val, const char *arg) return 0; } -void print_linklayer(char *buf, int len, unsigned linklayer) +void print_linklayer(char *buf, int len, unsigned int linklayer) { switch (linklayer) { case LINKLAYER_UNSPEC: @@ -495,21 +496,22 @@ void print_linklayer(char *buf, int len, unsigned linklayer) } } -char *sprint_linklayer(unsigned linklayer, char *buf) +char *sprint_linklayer(unsigned int linklayer, char *buf) { print_linklayer(buf, SPRINT_BSIZE-1, linklayer); return buf; } -void print_tm(FILE * f, const struct tcf_t *tm) +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)(tm->install/hz)); + fprintf(f, " installed %u sec", (unsigned int)(tm->install/hz)); if (tm->lastuse != 0) - fprintf(f, " used %u sec", (unsigned)(tm->lastuse/hz)); + fprintf(f, " used %u sec", (unsigned int)(tm->lastuse/hz)); if (tm->expires != 0) - fprintf(f, " expires %u sec", (unsigned)(tm->expires/hz)); + fprintf(f, " expires %u sec", (unsigned int)(tm->expires/hz)); } void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtattr **xstats) @@ -521,6 +523,7 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat if (tbs[TCA_STATS_BASIC]) { 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); @@ -528,6 +531,7 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat 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); @@ -552,6 +556,7 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat 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))); if (!tbs[TCA_STATS_RATE_EST]) fprintf(fp, "\n%s", prefix); From 56f5daac98da0c405fdbc52f04afd5de82404bce Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 21 Mar 2016 11:52:19 -0700 Subject: [PATCH 140/513] ip: code cleanup Run all the ip code through checkpatch and have it fix the obvious stuff. --- ip/ip6tunnel.c | 22 ++++-- ip/ipaddress.c | 116 ++++++++++++++++------------- ip/ipaddrlabel.c | 11 +-- ip/ipl2tp.c | 10 +++ ip/iplink.c | 20 ++--- ip/iplink_bond.c | 9 ++- ip/iplink_bond_slave.c | 4 +- ip/iplink_bridge_slave.c | 2 +- ip/iplink_can.c | 33 +++------ ip/iplink_geneve.c | 5 +- ip/iplink_ipoib.c | 6 +- ip/iplink_ipvlan.c | 4 +- ip/iplink_macvlan.c | 6 +- ip/iplink_vlan.c | 6 +- ip/iplink_vrf.c | 8 +- ip/iplink_vxlan.c | 15 +++- ip/ipmaddr.c | 20 ++--- ip/ipmonitor.c | 43 ++++++----- ip/ipmroute.c | 11 +-- ip/ipneigh.c | 38 ++++++---- ip/ipnetconf.c | 4 +- ip/ipnetns.c | 11 ++- ip/ipntable.c | 25 ++++++- ip/ipprefix.c | 5 +- ip/iproute.c | 155 ++++++++++++++++++++++++++------------- ip/iproute_lwtunnel.c | 10 ++- ip/iprule.c | 24 ++++-- ip/iptoken.c | 6 +- ip/iptuntap.c | 16 ++-- ip/ipxfrm.c | 32 +++++--- ip/link_gre.c | 32 ++++---- ip/link_gre6.c | 37 ++++++---- ip/link_ip6tnl.c | 10 ++- ip/link_iptnl.c | 10 ++- ip/link_veth.c | 2 +- ip/link_vti.c | 22 +++--- ip/link_vti6.c | 16 ++-- ip/rtmon.c | 25 ++++--- ip/tcp_metrics.c | 7 +- ip/tunnel.c | 12 +-- ip/xfrm_monitor.c | 54 +++++++------- ip/xfrm_policy.c | 70 +++++++++--------- ip/xfrm_state.c | 57 +++++++------- 43 files changed, 609 insertions(+), 422 deletions(-) diff --git a/ip/ip6tunnel.c b/ip/ip6tunnel.c index 7a3cd0461..2e9d3ed40 100644 --- a/ip/ip6tunnel.c +++ b/ip/ip6tunnel.c @@ -50,7 +50,7 @@ static void usage(void) fprintf(stderr, " [ mode { ip6ip6 | ipip6 | ip6gre | vti6 | any } ]\n"); fprintf(stderr, " [ remote ADDR local ADDR ] [ dev PHYS_DEV ]\n"); fprintf(stderr, " [ encaplimit ELIM ]\n"); - fprintf(stderr ," [ hoplimit TTL ] [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n"); + fprintf(stderr, " [ hoplimit TTL ] [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n"); fprintf(stderr, " [ dscp inherit ]\n"); fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n"); fprintf(stderr, "\n"); @@ -81,6 +81,7 @@ static void print_tunnel(struct ip6_tnl_parm2 *p) rt_addr_n2a(AF_INET6, 16, &p->laddr, s2, sizeof(s2))); if (p->link) { const char *n = ll_index_to_name(p->link); + if (n) printf(" dev %s", n); } @@ -96,6 +97,7 @@ static void print_tunnel(struct ip6_tnl_parm2 *p) printf(" tclass inherit"); else { __u32 val = ntohl(p->flowinfo & IP6_FLOWINFO_TCLASS); + printf(" tclass 0x%02x", (__u8)(val >> 20)); } @@ -158,11 +160,12 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm2 *p) strcmp(*argv, "any") == 0) p->proto = 0; else { - fprintf(stderr,"Unknown tunnel mode \"%s\"\n", *argv); + fprintf(stderr, "Unknown tunnel mode \"%s\"\n", *argv); exit(-1); } } else if (strcmp(*argv, "remote") == 0) { inet_prefix raddr; + NEXT_ARG(); get_prefix(&raddr, *argv, preferred_family); if (raddr.family == AF_UNSPEC) @@ -170,6 +173,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm2 *p) memcpy(&p->raddr, &raddr.data, sizeof(p->raddr)); } else if (strcmp(*argv, "local") == 0) { inet_prefix laddr; + NEXT_ARG(); get_prefix(&laddr, *argv, preferred_family); if (laddr.family == AF_UNSPEC) @@ -184,6 +188,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm2 *p) p->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT; } else { __u8 uval; + if (get_u8(&uval, *argv, 0) < -1) invarg("invalid ELIM", *argv); p->encap_limit = uval; @@ -193,6 +198,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm2 *p) strcmp(*argv, "ttl") == 0 || strcmp(*argv, "hlim") == 0) { __u8 uval; + NEXT_ARG(); if (get_u8(&uval, *argv, 0)) invarg("invalid TTL", *argv); @@ -202,6 +208,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm2 *p) strcmp(*argv, "tos") == 0 || matches(*argv, "dsfield") == 0) { __u8 uval; + NEXT_ARG(); p->flowinfo &= ~IP6_FLOWINFO_TCLASS; if (strcmp(*argv, "inherit") == 0) @@ -215,6 +222,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm2 *p) } else if (strcmp(*argv, "flowlabel") == 0 || strcmp(*argv, "fl") == 0) { __u32 uval; + NEXT_ARG(); p->flowinfo &= ~IP6_FLOWINFO_FLOWLABEL; if (strcmp(*argv, "inherit") == 0) @@ -269,6 +277,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm2 *p) strncpy(p->name, *argv, IFNAMSIZ - 1); if (cmd == SIOCCHGTUNNEL && count == 0) { struct ip6_tnl_parm2 old_p; + memset(&old_p, 0, sizeof(old_p)); if (tnl_get_ioctl(*argv, &old_p)) return -1; @@ -326,6 +335,7 @@ static int do_tunnels_list(struct ip6_tnl_parm2 *p) char buf[512]; int err = -1; FILE *fp = fopen("/proc/net/dev", "r"); + if (fp == NULL) { perror("fopen"); return -1; @@ -387,14 +397,14 @@ static int do_tunnels_list(struct ip6_tnl_parm2 *p) static int do_show(int argc, char **argv) { - struct ip6_tnl_parm2 p; + struct ip6_tnl_parm2 p; ll_init_map(&rth); ip6_tnl_parm_init(&p, 0); p.proto = 0; /* default to any */ - if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0) - return -1; + if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0) + return -1; if (!p.name[0] || show_stats) do_tunnels_list(&p); @@ -405,7 +415,7 @@ static int do_show(int argc, char **argv) printf("\n"); } - return 0; + return 0; } static int do_add(int cmd, int argc, char **argv) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index c4a8fc354..f8c502940 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -93,7 +93,7 @@ static void usage(void) exit(-1); } -static void print_link_flags(FILE *fp, unsigned flags, unsigned mdown) +static void print_link_flags(FILE *fp, unsigned int flags, unsigned int mdown) { fprintf(fp, "<"); if (flags & IFF_UP && !(flags & IFF_RUNNING)) @@ -135,7 +135,7 @@ static const char *oper_states[] = { static void print_operstate(FILE *f, __u8 state) { - if (state >= sizeof(oper_states)/sizeof(oper_states[0])) + if (state >= ARRAY_SIZE(oper_states)) fprintf(f, "state %#x ", state); else { if (brief) { @@ -161,7 +161,7 @@ int get_operstate(const char *name) { int i; - for (i = 0; i < sizeof(oper_states)/sizeof(oper_states[0]); i++) + for (i = 0; i < ARRAY_SIZE(oper_states); i++) if (strcasecmp(name, oper_states[i]) == 0) return i; return -1; @@ -202,7 +202,7 @@ static void print_linkmode(FILE *f, struct rtattr *tb) { unsigned int mode = rta_getattr_u8(tb); - if (mode >= sizeof(link_modes) / sizeof(link_modes[0])) + if (mode >= ARRAY_SIZE(link_modes)) fprintf(f, "mode %d ", mode); else fprintf(f, "mode %s ", link_modes[mode]); @@ -286,6 +286,7 @@ static void print_af_spec(FILE *fp, struct rtattr *af_spec_attr) if (tb[IFLA_INET6_ADDR_GEN_MODE]) { __u8 mode = rta_getattr_u8(tb[IFLA_INET6_ADDR_GEN_MODE]); + switch (mode) { case IN6_ADDR_GEN_MODE_EUI64: fprintf(fp, "addrgenmode eui64 "); @@ -317,6 +318,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) struct ifla_vf_link_state *vf_linkstate; struct rtattr *vf[IFLA_VF_MAX + 1] = {}; struct rtattr *tmp; + SPRINT_BUF(b1); if (vfinfo->rta_type != IFLA_VF_INFO) { @@ -392,7 +394,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) print_vf_stats64(fp, vf[IFLA_VF_STATS]); } -static void print_num(FILE *fp, unsigned width, uint64_t count) +static void print_num(FILE *fp, unsigned int width, uint64_t count) { const char *prefix = "kMGTPE"; const unsigned int base = use_iec ? 1024 : 1000; @@ -408,7 +410,7 @@ static void print_num(FILE *fp, unsigned width, uint64_t count) /* increase value by a factor of 1000/1024 and print * if result is something a human can read */ - for(;;) { + for (;;) { powi *= base; if (count / base < powi) break; @@ -462,7 +464,7 @@ static void print_vf_stats64(FILE *fp, struct rtattr *vfstats) } static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s, - const struct rtattr *carrier_changes) + const struct rtattr *carrier_changes) { /* RX stats */ fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s", @@ -514,7 +516,7 @@ static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s, if (show_stats > 1) { fprintf(fp, "%s", _SL_); fprintf(fp, " TX errors: aborted fifo window heartbeat"); - if (carrier_changes) + if (carrier_changes) fprintf(fp, " transns"); fprintf(fp, "%s", _SL_); @@ -524,7 +526,7 @@ static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s, print_num(fp, 7, s->tx_window_errors); print_num(fp, 7, s->tx_heartbeat_errors); if (carrier_changes) - print_num(fp, 7, *(uint32_t*)RTA_DATA(carrier_changes)); + print_num(fp, 7, *(uint32_t *)RTA_DATA(carrier_changes)); } } @@ -580,7 +582,7 @@ static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s, if (show_stats > 1) { fprintf(fp, "%s", _SL_); fprintf(fp, " TX errors: aborted fifo window heartbeat"); - if (carrier_changes) + if (carrier_changes) fprintf(fp, " transns"); fprintf(fp, "%s", _SL_); @@ -590,7 +592,7 @@ static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s, print_num(fp, 7, s->tx_window_errors); print_num(fp, 7, s->tx_heartbeat_errors); if (carrier_changes) - print_num(fp, 7, *(uint32_t*)RTA_DATA(carrier_changes)); + print_num(fp, 7, *(uint32_t *)RTA_DATA(carrier_changes)); } } @@ -618,7 +620,7 @@ static void __print_link_stats(FILE *fp, struct rtattr **tb) static void print_link_stats(FILE *fp, struct nlmsghdr *n) { struct ifinfomsg *ifi = NLMSG_DATA(n); - struct rtattr * tb[IFLA_MAX+1]; + struct rtattr *tb[IFLA_MAX+1]; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi))); @@ -629,13 +631,13 @@ static void print_link_stats(FILE *fp, struct nlmsghdr *n) int print_linkinfo_brief(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct ifinfomsg *ifi = NLMSG_DATA(n); - struct rtattr * tb[IFLA_MAX+1]; + struct rtattr *tb[IFLA_MAX+1]; int len = n->nlmsg_len; char *name; char buf[32] = { 0, }; - unsigned m_flag = 0; + unsigned int m_flag = 0; if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) return -1; @@ -659,17 +661,18 @@ int print_linkinfo_brief(const struct sockaddr_nl *who, return -1; if (tb[IFLA_GROUP]) { - int group = *(int*)RTA_DATA(tb[IFLA_GROUP]); + int group = *(int *)RTA_DATA(tb[IFLA_GROUP]); + if (filter.group != -1 && group != filter.group) return -1; } if (tb[IFLA_MASTER]) { - int master = *(int*)RTA_DATA(tb[IFLA_MASTER]); + int master = *(int *)RTA_DATA(tb[IFLA_MASTER]); + if (filter.master > 0 && master != filter.master) return -1; - } - else if (filter.master > 0) + } else if (filter.master > 0) return -1; if (filter.kind) { @@ -690,7 +693,8 @@ int print_linkinfo_brief(const struct sockaddr_nl *who, if (tb[IFLA_LINK]) { SPRINT_BUF(b1); - int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]); + int iflink = *(int *)RTA_DATA(tb[IFLA_LINK]); + if (iflink == 0) snprintf(buf, sizeof(buf), "%s@NONE", name); else { @@ -730,11 +734,11 @@ int print_linkinfo_brief(const struct sockaddr_nl *who, int print_linkinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct ifinfomsg *ifi = NLMSG_DATA(n); - struct rtattr * tb[IFLA_MAX+1]; + struct rtattr *tb[IFLA_MAX+1]; int len = n->nlmsg_len; - unsigned m_flag = 0; + unsigned int m_flag = 0; if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) return 0; @@ -758,17 +762,18 @@ int print_linkinfo(const struct sockaddr_nl *who, return 0; if (tb[IFLA_GROUP]) { - int group = *(int*)RTA_DATA(tb[IFLA_GROUP]); + int group = *(int *)RTA_DATA(tb[IFLA_GROUP]); + if (filter.group != -1 && group != filter.group) return -1; } if (tb[IFLA_MASTER]) { - int master = *(int*)RTA_DATA(tb[IFLA_MASTER]); + int master = *(int *)RTA_DATA(tb[IFLA_MASTER]); + if (filter.master > 0 && master != filter.master) return -1; - } - else if (filter.master > 0) + } else if (filter.master > 0) return -1; if (filter.kind) { @@ -791,7 +796,8 @@ int print_linkinfo(const struct sockaddr_nl *who, if (tb[IFLA_LINK]) { SPRINT_BUF(b1); - int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]); + int iflink = *(int *)RTA_DATA(tb[IFLA_LINK]); + if (iflink == 0) fprintf(fp, "@NONE: "); else { @@ -809,12 +815,12 @@ int print_linkinfo(const struct sockaddr_nl *who, print_link_flags(fp, ifi->ifi_flags, m_flag); if (tb[IFLA_MTU]) - fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU])); + fprintf(fp, "mtu %u ", *(int *)RTA_DATA(tb[IFLA_MTU])); if (tb[IFLA_QDISC]) fprintf(fp, "qdisc %s ", rta_getattr_str(tb[IFLA_QDISC])); if (tb[IFLA_MASTER]) { SPRINT_BUF(b1); - fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1)); + fprintf(fp, "master %s ", ll_idx_n2a(*(int *)RTA_DATA(tb[IFLA_MASTER]), b1)); } if (tb[IFLA_PHYS_PORT_ID]) { @@ -841,7 +847,8 @@ int print_linkinfo(const struct sockaddr_nl *who, if (tb[IFLA_GROUP]) { SPRINT_BUF(b1); - int group = *(int*)RTA_DATA(tb[IFLA_GROUP]); + int group = *(int *)RTA_DATA(tb[IFLA_GROUP]); + fprintf(fp, "group %s ", rtnl_group_n2a(group, b1, sizeof(b1))); } @@ -873,7 +880,7 @@ int print_linkinfo(const struct sockaddr_nl *who, } if (tb[IFLA_LINK_NETNSID]) { - int id = *(int*)RTA_DATA(tb[IFLA_LINK_NETNSID]); + int id = *(int *)RTA_DATA(tb[IFLA_LINK_NETNSID]); if (id >= 0) fprintf(fp, " link-netnsid %d", id); @@ -888,7 +895,7 @@ int print_linkinfo(const struct sockaddr_nl *who, if (tb[IFLA_PROMISCUITY] && show_details) fprintf(fp, " promiscuity %u ", - *(int*)RTA_DATA(tb[IFLA_PROMISCUITY])); + *(int *)RTA_DATA(tb[IFLA_PROMISCUITY])); if (tb[IFLA_LINKINFO] && show_details) print_linktype(fp, tb[IFLA_LINKINFO]); @@ -909,6 +916,7 @@ int print_linkinfo(const struct sockaddr_nl *who, if ((do_link || show_details) && tb[IFLA_VFINFO_LIST] && tb[IFLA_NUM_VF]) { struct rtattr *i, *vflist = tb[IFLA_VFINFO_LIST]; int rem = RTA_PAYLOAD(vflist); + for (i = RTA_DATA(vflist); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) print_vfinfo(fp, i); } @@ -964,8 +972,9 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, int deprecated = 0; /* Use local copy of ifa_flags to not interfere with filtering code */ unsigned int ifa_flags; - struct rtattr * rta_tb[IFA_MAX+1]; + struct rtattr *rta_tb[IFA_MAX+1]; char abuf[256]; + SPRINT_BUF(b1); if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR) @@ -998,6 +1007,7 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, if (filter.label) { SPRINT_BUF(b1); const char *label; + if (rta_tb[IFA_LABEL]) label = RTA_DATA(rta_tb[IFA_LABEL]); else @@ -1008,6 +1018,7 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, if (filter.pfx.family) { if (rta_tb[IFA_LOCAL]) { inet_prefix dst; + memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL])); @@ -1021,16 +1032,17 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, if (filter.flushb) { struct nlmsghdr *fn; + if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } - fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); + fn = (struct nlmsghdr *)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELADDR; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++rth.seq; - filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; + filter.flushp = (((char *)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; if (show_stats < 2) return 0; @@ -1153,6 +1165,7 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, fprintf(fp, "%s", rta_getattr_str(rta_tb[IFA_LABEL])); if (rta_tb[IFA_CACHEINFO]) { struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]); + fprintf(fp, "%s", _SL_); fprintf(fp, " valid_lft "); if (ci->ifa_valid == INFINITY_LIFE_TIME) @@ -1175,14 +1188,12 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, return 0; } -struct nlmsg_list -{ +struct nlmsg_list { struct nlmsg_list *next; struct nlmsghdr h; }; -struct nlmsg_chain -{ +struct nlmsg_chain { struct nlmsg_list *head; struct nlmsg_list *tail; }; @@ -1190,7 +1201,7 @@ struct nlmsg_chain static int print_selected_addrinfo(struct ifinfomsg *ifi, struct nlmsg_list *ainfo, FILE *fp) { - for ( ;ainfo ; ainfo = ainfo->next) { + for ( ; ainfo ; ainfo = ainfo->next) { struct nlmsghdr *n = &ainfo->h; struct ifaddrmsg *ifa = NLMSG_DATA(n); @@ -1223,7 +1234,7 @@ static int store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, struct nlmsg_chain *lchain = (struct nlmsg_chain *)arg; struct nlmsg_list *h; - h = malloc(n->nlmsg_len+sizeof(void*)); + h = malloc(n->nlmsg_len+sizeof(void *)); if (h == NULL) return -1; @@ -1352,7 +1363,7 @@ static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo) struct nlmsg_list *l, **lp; lp = &linfo->head; - while ( (l = *lp) != NULL) { + while ((l = *lp) != NULL) { int ok = 0; int missing_net_address = 1; struct ifinfomsg *ifi = NLMSG_DATA(&l->h); @@ -1383,6 +1394,7 @@ static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo) if (filter.pfx.family && tb[IFA_LOCAL]) { inet_prefix dst; + memset(&dst, 0, sizeof(dst)); dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL])); @@ -1392,6 +1404,7 @@ static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo) if (filter.label) { SPRINT_BUF(b1); const char *label; + if (tb[IFA_LABEL]) label = RTA_DATA(tb[IFA_LABEL]); else @@ -1441,7 +1454,7 @@ static int ipaddr_flush(void) if (round == 0) printf("Nothing to flush.\n"); else - printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":""); + printf("*** Flush is complete after %d round%s ***\n", round, round > 1?"s":""); } fflush(stdout); return 0; @@ -1500,7 +1513,8 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) if (filter.family == AF_UNSPEC) filter.family = filter.pfx.family; } else if (strcmp(*argv, "scope") == 0) { - unsigned scope = 0; + unsigned int scope = 0; + NEXT_ARG(); filter.scopemask = -1; if (rtnl_rtscope_a2n(&scope, *argv)) { @@ -1567,6 +1581,7 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) invarg("Invalid \"group\" value\n", *argv); } else if (strcmp(*argv, "master") == 0) { int ifindex; + NEXT_ARG(); ifindex = ll_name_to_index(*argv); if (!ifindex) @@ -1578,8 +1593,7 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) } else { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); - } - else if (matches(*argv, "help") == 0) + } else if (matches(*argv, "help") == 0) usage(); if (filter_dev) duparg2("dev", *argv); @@ -1757,7 +1771,7 @@ void ipaddr_reset_filter(int oneline, int ifindex) static int default_scope(inet_prefix *lcl) { if (lcl->family == AF_INET) { - if (lcl->bytelen >= 1 && *(__u8*)&lcl->data == 127) + if (lcl->bytelen >= 1 && *(__u8 *)&lcl->data == 127) return RT_SCOPE_HOST; } return 0; @@ -1820,6 +1834,7 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv) } else if (matches(*argv, "broadcast") == 0 || strcmp(*argv, "brd") == 0) { inet_prefix addr; + NEXT_ARG(); if (brd_len) duparg("broadcast", *argv); @@ -1836,6 +1851,7 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv) } } else if (strcmp(*argv, "anycast") == 0) { inet_prefix addr; + NEXT_ARG(); if (any_len) duparg("anycast", *argv); @@ -1845,7 +1861,8 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv) addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen); any_len = addr.bytelen; } else if (strcmp(*argv, "scope") == 0) { - unsigned scope = 0; + unsigned int scope = 0; + NEXT_ARG(); if (rtnl_rtscope_a2n(&scope, *argv)) invarg("invalid scope value.", *argv); @@ -1931,6 +1948,7 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv) if (brd_len < 0 && cmd != RTM_DELADDR) { inet_prefix brd; int i; + if (req.ifa.ifa_family != AF_INET) { fprintf(stderr, "Broadcast can be set only for IPv4 addresses\n"); return -1; diff --git a/ip/ipaddrlabel.c b/ip/ipaddrlabel.c index ef093cbe6..05c44978f 100644 --- a/ip/ipaddrlabel.c +++ b/ip/ipaddrlabel.c @@ -40,8 +40,8 @@ #include "utils.h" #include "ip_common.h" -#define IFAL_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg)))) -#define IFAL_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrlblmsg)) +#define IFAL_RTA(r) ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg)))) +#define IFAL_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct ifaddrlblmsg)) extern struct rtnl_handle rth; @@ -56,7 +56,7 @@ static void usage(void) int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct ifaddrlblmsg *ifal = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[IFAL_MAX+1]; @@ -88,6 +88,7 @@ int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(uint32_t)) { uint32_t label; + memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label)); fprintf(fp, "label %u ", label); } @@ -128,7 +129,7 @@ static int ipaddrlabel_modify(int cmd, int argc, char **argv) struct { struct nlmsghdr n; struct ifaddrlblmsg ifal; - char buf[1024]; + char buf[1024]; } req; inet_prefix prefix; @@ -195,7 +196,7 @@ static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, vo struct rtnl_handle rth2; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[IFAL_MAX+1]; + struct rtattr *tb[IFAL_MAX+1]; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index 3e3b21ddf..3c8ee9355 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -526,6 +526,7 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p) } else if ((strcmp(*argv, "tunnel_id") == 0) || (strcmp(*argv, "tid") == 0)) { __u32 uval; + NEXT_ARG(); if (get_u32(&uval, *argv, 0)) invarg("invalid ID\n", *argv); @@ -533,6 +534,7 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p) } else if ((strcmp(*argv, "peer_tunnel_id") == 0) || (strcmp(*argv, "ptid") == 0)) { __u32 uval; + NEXT_ARG(); if (get_u32(&uval, *argv, 0)) invarg("invalid ID\n", *argv); @@ -540,6 +542,7 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p) } else if ((strcmp(*argv, "session_id") == 0) || (strcmp(*argv, "sid") == 0)) { __u32 uval; + NEXT_ARG(); if (get_u32(&uval, *argv, 0)) invarg("invalid ID\n", *argv); @@ -547,36 +550,42 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p) } else if ((strcmp(*argv, "peer_session_id") == 0) || (strcmp(*argv, "psid") == 0)) { __u32 uval; + NEXT_ARG(); if (get_u32(&uval, *argv, 0)) invarg("invalid ID\n", *argv); p->peer_session_id = uval; } else if (strcmp(*argv, "udp_sport") == 0) { __u16 uval; + NEXT_ARG(); if (get_u16(&uval, *argv, 0)) invarg("invalid port\n", *argv); p->local_udp_port = uval; } else if (strcmp(*argv, "udp_dport") == 0) { __u16 uval; + NEXT_ARG(); if (get_u16(&uval, *argv, 0)) invarg("invalid port\n", *argv); p->peer_udp_port = uval; } else if (strcmp(*argv, "offset") == 0) { __u8 uval; + NEXT_ARG(); if (get_u8(&uval, *argv, 0)) invarg("invalid offset\n", *argv); p->offset = uval; } else if (strcmp(*argv, "peer_offset") == 0) { __u8 uval; + NEXT_ARG(); if (get_u8(&uval, *argv, 0)) invarg("invalid offset\n", *argv); p->peer_offset = uval; } else if (strcmp(*argv, "cookie") == 0) { int slen; + NEXT_ARG(); slen = strlen(*argv); if ((slen != 8) && (slen != 16)) @@ -587,6 +596,7 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p) invarg("cookie must be a hex string\n", *argv); } else if (strcmp(*argv, "peer_cookie") == 0) { int slen; + NEXT_ARG(); slen = strlen(*argv); if ((slen != 8) && (slen != 16)) diff --git a/ip/iplink.c b/ip/iplink.c index 33d7c0ad0..d2e586b6d 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -358,6 +358,7 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, } else if (matches(*argv, "trust") == 0) { struct ifla_vf_trust ivt; + NEXT_ARG(); if (matches(*argv, "on") == 0) ivt.setting = 1; @@ -712,14 +713,12 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) &group, sizeof(group)); else { if (argc) { - fprintf(stderr, "Garbage instead of arguments " - "\"%s ...\". Try \"ip link " + fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"ip link " "help\".\n", *argv); return -1; } if (flags & NLM_F_CREATE) { - fprintf(stderr, "group cannot be used when " - "creating devices.\n"); + fprintf(stderr, "group cannot be used when creating devices.\n"); return -1; } @@ -733,13 +732,11 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) if (!(flags & NLM_F_CREATE)) { if (!dev) { - fprintf(stderr, "Not enough information: \"dev\" " - "argument is required.\n"); + fprintf(stderr, "Not enough information: \"dev\" argument is required.\n"); exit(-1); } if (cmd == RTM_NEWLINK && index != -1) { - fprintf(stderr, "index can be used only when " - "creating devices.\n"); + fprintf(stderr, "index can be used only when creating devices.\n"); exit(-1); } @@ -813,14 +810,13 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) } else if (argc) { if (matches(*argv, "help") == 0) usage(); - fprintf(stderr, "Garbage instead of arguments \"%s ...\". " - "Try \"ip link help\".\n", *argv); + fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n", + *argv); return -1; } addattr_nest_end(&req.n, linkinfo); } else if (flags & NLM_F_CREATE) { - fprintf(stderr, "Not enough information: \"type\" argument " - "is required\n"); + fprintf(stderr, "Not enough information: \"type\" argument is required\n"); return -1; } diff --git a/ip/iplink_bond.c b/ip/iplink_bond.c index cb2f045a5..45473f66d 100644 --- a/ip/iplink_bond.c +++ b/ip/iplink_bond.c @@ -166,7 +166,7 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv, __u32 miimon, updelay, downdelay, arp_interval, arp_validate; __u32 arp_all_targets, resend_igmp, min_links, lp_interval; __u32 packets_per_slave; - unsigned ifindex; + unsigned int ifindex; while (argc > 0) { if (matches(*argv, "mode") == 0) { @@ -209,7 +209,7 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv, invarg("invalid arp_interval", *argv); addattr32(n, 1024, IFLA_BOND_ARP_INTERVAL, arp_interval); } else if (matches(*argv, "arp_ip_target") == 0) { - struct rtattr * nest = addattr_nest(n, 1024, + struct rtattr *nest = addattr_nest(n, 1024, IFLA_BOND_ARP_IP_TARGET); if (NEXT_ARG_OK()) { NEXT_ARG(); @@ -217,8 +217,9 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv, char *target = strtok(targets, ","); int i; - for(i = 0; target && i < BOND_MAX_ARP_TARGETS; i++) { + for (i = 0; target && i < BOND_MAX_ARP_TARGETS; i++) { __u32 addr = get_addr32(target); + addattr32(n, 1024, i, addr); target = strtok(NULL, ","); } @@ -368,7 +369,7 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv, static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { - unsigned ifindex; + unsigned int ifindex; if (!tb) return; diff --git a/ip/iplink_bond_slave.c b/ip/iplink_bond_slave.c index 2f3364ee4..d67793237 100644 --- a/ip/iplink_bond_slave.c +++ b/ip/iplink_bond_slave.c @@ -26,7 +26,7 @@ static void print_slave_state(FILE *f, struct rtattr *tb) { unsigned int state = rta_getattr_u8(tb); - if (state >= sizeof(slave_states) / sizeof(slave_states[0])) + if (state >= ARRAY_SIZE(slave_states)) fprintf(f, "state %d ", state); else fprintf(f, "state %s ", slave_states[state]); @@ -43,7 +43,7 @@ static void print_slave_mii_status(FILE *f, struct rtattr *tb) { unsigned int status = rta_getattr_u8(tb); - if (status >= sizeof(slave_mii_status) / sizeof(slave_mii_status[0])) + if (status >= ARRAY_SIZE(slave_mii_status)) fprintf(f, "mii_status %d ", status); else fprintf(f, "mii_status %s ", slave_mii_status[status]); diff --git a/ip/iplink_bridge_slave.c b/ip/iplink_bridge_slave.c index 3ec2bba72..a44d4e413 100644 --- a/ip/iplink_bridge_slave.c +++ b/ip/iplink_bridge_slave.c @@ -24,7 +24,7 @@ static void print_explain(FILE *f) fprintf(f, "Usage: ... bridge_slave [ state STATE ] [ priority PRIO ] [cost COST ]\n" " [ guard {on | off} ]\n" - " [ hairpin {on | off} ] \n" + " [ hairpin {on | off} ]\n" " [ fastleave {on | off} ]\n" " [ root_block {on | off} ]\n" " [ learning {on | off} ]\n" diff --git a/ip/iplink_can.c b/ip/iplink_can.c index f1b089dfa..a00d42311 100644 --- a/ip/iplink_can.c +++ b/ip/iplink_can.c @@ -23,13 +23,11 @@ static void print_usage(FILE *f) { fprintf(f, "Usage: ip link set DEVICE type can\n" - "\t[ bitrate BITRATE [ sample-point SAMPLE-POINT] ] | \n" - "\t[ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1\n " - "\t phase-seg2 PHASE-SEG2 [ sjw SJW ] ]\n" + "\t[ bitrate BITRATE [ sample-point SAMPLE-POINT] ] |\n" + "\t[ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1\n \t phase-seg2 PHASE-SEG2 [ sjw SJW ] ]\n" "\n" - "\t[ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] | \n" - "\t[ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1\n " - "\t dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ]\n" + "\t[ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] |\n" + "\t[ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1\n \t dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ]\n" "\n" "\t[ loopback { on | off } ]\n" "\t[ listen-only { on | off } ]\n" @@ -73,7 +71,7 @@ static int get_float(float *val, const char *arg) return 0; } -static void set_ctrlmode(char* name, char *arg, +static void set_ctrlmode(char *name, char *arg, struct can_ctrlmode *cm, __u32 flags) { if (strcmp(arg, "on") == 0) { @@ -289,11 +287,9 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_CAN_BITTIMING]) { struct can_bittiming *bt = RTA_DATA(tb[IFLA_CAN_BITTIMING]); - fprintf(f, "\n " - "bitrate %d sample-point %.3f ", + fprintf(f, "\n bitrate %d sample-point %.3f ", bt->bitrate, (float)bt->sample_point / 1000.); - fprintf(f, "\n " - "tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d", + fprintf(f, "\n tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d", bt->tq, bt->prop_seg, bt->phase_seg1, bt->phase_seg2, bt->sjw); } @@ -302,8 +298,7 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) struct can_bittiming_const *btc = RTA_DATA(tb[IFLA_CAN_BITTIMING_CONST]); - fprintf(f, "\n " - "%s: tseg1 %d..%d tseg2 %d..%d " + fprintf(f, "\n %s: tseg1 %d..%d tseg2 %d..%d " "sjw 1..%d brp %d..%d brp-inc %d", btc->name, btc->tseg1_min, btc->tseg1_max, btc->tseg2_min, btc->tseg2_max, btc->sjw_max, @@ -314,11 +309,9 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) struct can_bittiming *dbt = RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]); - fprintf(f, "\n " - "dbitrate %d dsample-point %.3f ", + fprintf(f, "\n dbitrate %d dsample-point %.3f ", dbt->bitrate, (float)dbt->sample_point / 1000.); - fprintf(f, "\n " - "dtq %d dprop-seg %d dphase-seg1 %d " + fprintf(f, "\n dtq %d dprop-seg %d dphase-seg1 %d " "dphase-seg2 %d dsjw %d", dbt->tq, dbt->prop_seg, dbt->phase_seg1, dbt->phase_seg2, dbt->sjw); @@ -328,8 +321,7 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) struct can_bittiming_const *dbtc = RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING_CONST]); - fprintf(f, "\n " - "%s: dtseg1 %d..%d dtseg2 %d..%d " + fprintf(f, "\n %s: dtseg1 %d..%d dtseg2 %d..%d " "dsjw 1..%d dbrp %d..%d dbrp-inc %d", dbtc->name, dbtc->tseg1_min, dbtc->tseg1_max, dbtc->tseg2_min, dbtc->tseg2_max, dbtc->sjw_max, @@ -351,8 +343,7 @@ static void can_print_xstats(struct link_util *lu, if (xstats && RTA_PAYLOAD(xstats) == sizeof(*stats)) { stats = RTA_DATA(xstats); - fprintf(f, "\n " - "re-started bus-errors arbit-lost " + fprintf(f, "\n re-started bus-errors arbit-lost " "error-warn error-pass bus-off"); fprintf(f, "\n %-10d %-10d %-10d %-10d %-10d %-10d", stats->restarts, stats->bus_error, diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c index 30b16b932..40c08ec27 100644 --- a/ip/iplink_geneve.c +++ b/ip/iplink_geneve.c @@ -62,7 +62,7 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, invarg("invalid remote address", *argv); } else if (!matches(*argv, "ttl") || !matches(*argv, "hoplimit")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { @@ -153,11 +153,13 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_GENEVE_REMOTE]) { __be32 addr = rta_getattr_u32(tb[IFLA_GENEVE_REMOTE]); + if (addr) fprintf(f, "remote %s ", format_host(AF_INET, 4, &addr, s1, sizeof(s1))); } else if (tb[IFLA_GENEVE_REMOTE6]) { struct in6_addr addr; + memcpy(&addr, RTA_DATA(tb[IFLA_GENEVE_REMOTE6]), sizeof(struct in6_addr)); if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) { if (IN6_IS_ADDR_MULTICAST(&addr)) @@ -168,6 +170,7 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_GENEVE_TTL]) { __u8 ttl = rta_getattr_u8(tb[IFLA_GENEVE_TTL]); + if (ttl) fprintf(f, "ttl %d ", ttl); } diff --git a/ip/iplink_ipoib.c b/ip/iplink_ipoib.c index 6087cbe1d..cb204af4a 100644 --- a/ip/iplink_ipoib.c +++ b/ip/iplink_ipoib.c @@ -22,8 +22,7 @@ static void print_explain(FILE *f) { fprintf(f, - "Usage: ... ipoib [pkey PKEY] [mode {datagram | connected}]" - "[umcast {0|1}]\n" + "Usage: ... ipoib [pkey PKEY] [mode {datagram | connected}][umcast {0|1}]\n" "\n" "PKEY := 0x8001-0xffff\n" ); @@ -36,8 +35,7 @@ static void explain(void) static int mode_arg(void) { - fprintf(stderr, "Error: argument of \"mode\" must be \"datagram\"" - "or \"connected\"\n"); + fprintf(stderr, "Error: argument of \"mode\" must be \"datagram\"or \"connected\"\n"); return -1; } diff --git a/ip/iplink_ipvlan.c b/ip/iplink_ipvlan.c index e08fc397b..a6273be88 100644 --- a/ip/iplink_ipvlan.c +++ b/ip/iplink_ipvlan.c @@ -30,8 +30,7 @@ static void explain(void) static int mode_arg(void) { - fprintf(stderr, "Error: argument of \"mode\" must be either \"l2\", " - "or \"l3\"\n"); + fprintf(stderr, "Error: argument of \"mode\" must be either \"l2\", or \"l3\"\n"); return -1; } @@ -41,6 +40,7 @@ static int ipvlan_parse_opt(struct link_util *lu, int argc, char **argv, while (argc > 0) { if (matches(*argv, "mode") == 0) { __u16 mode = 0; + NEXT_ARG(); if (strcmp(*argv, "l2") == 0) diff --git a/ip/iplink_macvlan.c b/ip/iplink_macvlan.c index f195e81d6..53cd4f472 100644 --- a/ip/iplink_macvlan.c +++ b/ip/iplink_macvlan.c @@ -41,9 +41,9 @@ static void explain(struct link_util *lu) static int mode_arg(const char *arg) { - fprintf(stderr, "Error: argument of \"mode\" must be \"private\", " - "\"vepa\", \"bridge\" or \"passthru\", not \"%s\"\n", arg); - return -1; + fprintf(stderr, "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\" or \"passthru\", not \"%s\"\n", + arg); + return -1; } static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, diff --git a/ip/iplink_vlan.c b/ip/iplink_vlan.c index 5bd766f86..144c83cbf 100644 --- a/ip/iplink_vlan.c +++ b/ip/iplink_vlan.c @@ -21,8 +21,7 @@ static void print_explain(FILE *f) { fprintf(f, - "Usage: ... vlan [ protocol VLANPROTO ] id VLANID" - " [ FLAG-LIST ]\n" + "Usage: ... vlan [ protocol VLANPROTO ] id VLANID [ FLAG-LIST ]\n" " [ ingress-qos-map QOS-MAP ] [ egress-qos-map QOS-MAP ]\n" "\n" "VLANPROTO: [ 802.1Q / 802.1ad ]\n" @@ -182,7 +181,7 @@ static void vlan_print_flags(FILE *fp, __u32 flags) { fprintf(fp, "<"); #define _PF(f) if (flags & VLAN_FLAG_##f) { \ - flags &= ~ VLAN_FLAG_##f; \ + flags &= ~VLAN_FLAG_##f; \ fprintf(fp, #f "%s", flags ? "," : ""); \ } _PF(REORDER_HDR); @@ -198,6 +197,7 @@ static void vlan_print_flags(FILE *fp, __u32 flags) static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { struct ifla_vlan_flags *flags; + SPRINT_BUF(b1); if (!tb) diff --git a/ip/iplink_vrf.c b/ip/iplink_vrf.c index abc796886..e3c7b4652 100644 --- a/ip/iplink_vrf.c +++ b/ip/iplink_vrf.c @@ -20,7 +20,7 @@ static void vrf_explain(FILE *f) { - fprintf(f, "Usage: ... vrf table TABLEID \n"); + fprintf(f, "Usage: ... vrf table TABLEID\n"); } static void explain(void) @@ -91,8 +91,8 @@ struct link_util vrf_link_util = { }; struct link_util vrf_slave_link_util = { - .id = "vrf", - .maxattr = IFLA_VRF_PORT_MAX, + .id = "vrf", + .maxattr = IFLA_VRF_PORT_MAX, .print_opt = vrf_slave_print_opt, - .slave = true, + .slave = true, }; diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index ede848243..5c23cf534 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -55,7 +55,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, struct in6_addr saddr6 = IN6ADDR_ANY_INIT; struct in6_addr gaddr6 = IN6ADDR_ANY_INIT; struct in6_addr daddr6 = IN6ADDR_ANY_INIT; - unsigned link = 0; + unsigned int link = 0; __u8 tos = 0; __u8 ttl = 0; __u8 learning = 1; @@ -122,7 +122,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, } } else if (!matches(*argv, "ttl") || !matches(*argv, "hoplimit")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { @@ -158,6 +158,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, } else if (!matches(*argv, "port") || !matches(*argv, "srcport")) { __u16 minport, maxport; + NEXT_ARG(); if (get_u16(&minport, *argv, 0)) invarg("min port", *argv); @@ -166,7 +167,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, invarg("max port", *argv); range.low = htons(minport); range.high = htons(maxport); - } else if (!matches(*argv, "dstport")){ + } else if (!matches(*argv, "dstport")) { NEXT_ARG(); if (get_u16(&dstport, *argv, 0)) invarg("dst port", *argv); @@ -306,7 +307,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { __u32 vni; - unsigned link; + unsigned int link; __u8 tos; __u32 maxaddr; char s1[1024]; @@ -324,6 +325,7 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_VXLAN_GROUP]) { __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_GROUP]); + if (addr) { if (IN_MULTICAST(ntohl(addr))) fprintf(f, "group %s ", @@ -334,6 +336,7 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) } } else if (tb[IFLA_VXLAN_GROUP6]) { struct in6_addr addr; + memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_GROUP6]), sizeof(struct in6_addr)); if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) { if (IN6_IS_ADDR_MULTICAST(&addr)) @@ -347,11 +350,13 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_VXLAN_LOCAL]) { __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_LOCAL]); + if (addr) fprintf(f, "local %s ", format_host(AF_INET, 4, &addr, s1, sizeof(s1))); } else if (tb[IFLA_VXLAN_LOCAL6]) { struct in6_addr addr; + memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_LOCAL6]), sizeof(struct in6_addr)); if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) fprintf(f, "local %s ", @@ -404,12 +409,14 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_VXLAN_TTL]) { __u8 ttl = rta_getattr_u8(tb[IFLA_VXLAN_TTL]); + if (ttl) fprintf(f, "ttl %d ", ttl); } if (tb[IFLA_VXLAN_AGEING]) { __u32 age = rta_getattr_u32(tb[IFLA_VXLAN_AGEING]); + if (age == 0) fprintf(f, "ageing none "); else diff --git a/ip/ipmaddr.c b/ip/ipmaddr.c index cbd6d115f..347990b5c 100644 --- a/ip/ipmaddr.c +++ b/ip/ipmaddr.c @@ -50,6 +50,7 @@ static int parse_hex(char *str, unsigned char *addr, size_t size) while (*str && (len < 2 * size)) { int tmp; + if (str[1] == 0) return -1; if (sscanf(str, "%02x", &tmp) != 1) @@ -61,8 +62,7 @@ static int parse_hex(char *str, unsigned char *addr, size_t size) return len; } -struct ma_info -{ +struct ma_info { struct ma_info *next; int index; int users; @@ -105,7 +105,7 @@ static void read_dev_mcast(struct ma_info **result_p) m.addr.family = AF_PACKET; - len = parse_hex(hexa, (unsigned char*)&m.addr.data, sizeof (m.addr.data)); + len = parse_hex(hexa, (unsigned char *)&m.addr.data, sizeof(m.addr.data)); if (len >= 0) { struct ma_info *ma = malloc(sizeof(m)); @@ -149,7 +149,7 @@ static void read_igmp(struct ma_info **result_p) if (filter.dev && strcmp(filter.dev, m.name)) continue; - sscanf(buf, "%08x%d", (__u32*)&m.addr.data, &m.users); + sscanf(buf, "%08x%d", (__u32 *)&m.addr.data, &m.users); ma = malloc(sizeof(m)); memcpy(ma, &m, sizeof(m)); @@ -180,7 +180,7 @@ static void read_igmp6(struct ma_info **result_p) m.addr.family = AF_INET6; - len = parse_hex(hexa, (unsigned char*)&m.addr.data, sizeof (m.addr.data)); + len = parse_hex(hexa, (unsigned char *)&m.addr.data, sizeof(m.addr.data)); if (len >= 0) { struct ma_info *ma = malloc(sizeof(m)); @@ -200,12 +200,13 @@ static void print_maddr(FILE *fp, struct ma_info *list) if (list->addr.family == AF_PACKET) { SPRINT_BUF(b1); - fprintf(fp, "link %s", ll_addr_n2a((unsigned char*)list->addr.data, + fprintf(fp, "link %s", ll_addr_n2a((unsigned char *)list->addr.data, list->addr.bytelen, 0, b1, sizeof(b1))); } else { char abuf[256]; - switch(list->addr.family) { + + switch (list->addr.family) { case AF_INET: fprintf(fp, "inet "); break; @@ -256,8 +257,7 @@ static int multiaddr_list(int argc, char **argv) if (1) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); - } - else if (matches(*argv, "help") == 0) + } else if (matches(*argv, "help") == 0) usage(); if (filter.dev) duparg2("dev", *argv); @@ -320,7 +320,7 @@ static int multiaddr_modify(int cmd, int argc, char **argv) perror("Cannot create socket"); exit(1); } - if (ioctl(fd, cmd, (char*)&ifr) != 0) { + if (ioctl(fd, cmd, (char *)&ifr) != 0) { perror("ioctl"); exit(1); } diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c index 7aeccd21d..2090a45d7 100644 --- a/ip/ipmonitor.c +++ b/ip/ipmonitor.c @@ -30,8 +30,7 @@ int listen_all_nsid; static void usage(void) { - fprintf(stderr, "Usage: ip monitor [ all | LISTofOBJECTS ] [ FILE ] " - "[ label ] [all-nsid] [dev DEVICE]\n"); + fprintf(stderr, "Usage: ip monitor [ all | LISTofOBJECTS ] [ FILE ] [ label ] [all-nsid] [dev DEVICE]\n"); fprintf(stderr, "LISTofOBJECTS := link | address | route | mroute | prefix |\n"); fprintf(stderr, " neigh | netconf | rule | nsid\n"); fprintf(stderr, "FILE := file FILENAME\n"); @@ -58,7 +57,7 @@ static int accept_msg(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; if (n->nlmsg_type == RTM_NEWROUTE || n->nlmsg_type == RTM_DELROUTE) { struct rtmsg *r = NLMSG_DATA(n); @@ -139,8 +138,8 @@ static int accept_msg(const struct sockaddr_nl *who, } if (n->nlmsg_type != NLMSG_ERROR && n->nlmsg_type != NLMSG_NOOP && n->nlmsg_type != NLMSG_DONE) { - fprintf(fp, "Unknown message: type=0x%08x(%d) flags=0x%08x(%d)" - "len=0x%08x(%d)\n", n->nlmsg_type, n->nlmsg_type, + fprintf(fp, "Unknown message: type=0x%08x(%d) flags=0x%08x(%d)len=0x%08x(%d)\n", + n->nlmsg_type, n->nlmsg_type, n->nlmsg_flags, n->nlmsg_flags, n->nlmsg_len, n->nlmsg_len); } @@ -150,17 +149,17 @@ static int accept_msg(const struct sockaddr_nl *who, int do_ipmonitor(int argc, char **argv) { char *file = NULL; - unsigned groups = 0; - int llink=0; - int laddr=0; - int lroute=0; - int lmroute=0; - int lprefix=0; - int lneigh=0; - int lnetconf=0; - int lrule=0; - int lnsid=0; - int ifindex=0; + unsigned int groups = 0; + int llink = 0; + int laddr = 0; + int lroute = 0; + int lmroute = 0; + int lprefix = 0; + int lneigh = 0; + int lnetconf = 0; + int lrule = 0; + int lnsid = 0; + int ifindex = 0; groups |= nl_mgrp(RTNLGRP_LINK); groups |= nl_mgrp(RTNLGRP_IPV4_IFADDR); @@ -187,19 +186,19 @@ int do_ipmonitor(int argc, char **argv) } else if (matches(*argv, "label") == 0) { prefix_banner = 1; } else if (matches(*argv, "link") == 0) { - llink=1; + llink = 1; groups = 0; } else if (matches(*argv, "address") == 0) { - laddr=1; + laddr = 1; groups = 0; } else if (matches(*argv, "route") == 0) { - lroute=1; + lroute = 1; groups = 0; } else if (matches(*argv, "mroute") == 0) { - lmroute=1; + lmroute = 1; groups = 0; } else if (matches(*argv, "prefix") == 0) { - lprefix=1; + lprefix = 1; groups = 0; } else if (matches(*argv, "neigh") == 0) { lneigh = 1; @@ -214,7 +213,7 @@ int do_ipmonitor(int argc, char **argv) lnsid = 1; groups = 0; } else if (strcmp(*argv, "all") == 0) { - prefix_banner=1; + prefix_banner = 1; } else if (matches(*argv, "all-nsid") == 0) { listen_all_nsid = 1; } else if (matches(*argv, "help") == 0) { diff --git a/ip/ipmroute.c b/ip/ipmroute.c index fffa9e2c7..34543c00e 100644 --- a/ip/ipmroute.c +++ b/ip/ipmroute.c @@ -44,8 +44,7 @@ static void usage(void) exit(-1); } -struct rtfilter -{ +struct rtfilter { int tb; int af; int iif; @@ -55,12 +54,13 @@ struct rtfilter int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[RTA_MAX+1]; + struct rtattr *tb[RTA_MAX+1]; char abuf[256]; char obuf[256]; + SPRINT_BUF(b1); __u32 table; int iif = 0; @@ -90,7 +90,7 @@ int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) return 0; if (tb[RTA_IIF]) - iif = *(int*)RTA_DATA(tb[RTA_IIF]); + iif = *(int *)RTA_DATA(tb[RTA_IIF]); if (filter.iif && filter.iif != iif) return 0; @@ -212,6 +212,7 @@ static int mroute_list(int argc, char **argv) while (argc > 0) { if (matches(*argv, "table") == 0) { __u32 tid; + NEXT_ARG(); if (rtnl_rttable_a2n(&tid, *argv)) { if (strcmp(*argv, "all") == 0) { diff --git a/ip/ipneigh.c b/ip/ipneigh.c index 48cca196f..6458c8eaa 100644 --- a/ip/ipneigh.c +++ b/ip/ipneigh.c @@ -31,7 +31,7 @@ static struct { int family; - int index; + int index; int state; int unused_only; inet_prefix pfx; @@ -50,11 +50,11 @@ static void usage(void) " { ADDR [ lladdr LLADDR ] [ nud STATE ] | proxy ADDR } [ dev DEV ]\n"); fprintf(stderr, " ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n\n"); fprintf(stderr, "STATE := { permanent | noarp | stale | reachable | none |\n" - " incomplete | delay | probe | failed }\n"); + " incomplete | delay | probe | failed }\n"); exit(-1); } -static int nud_state_a2n(unsigned *state, const char *arg) +static int nud_state_a2n(unsigned int *state, const char *arg) { if (matches(arg, "permanent") == 0) *state = NUD_PERMANENT; @@ -77,7 +77,7 @@ static int nud_state_a2n(unsigned *state, const char *arg) else { if (get_unsigned(state, arg, 0)) return -1; - if (*state>=0x100 || (*state&((*state)-1))) + if (*state >= 0x100 || (*state&((*state)-1))) return -1; } return 0; @@ -99,13 +99,13 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv) struct { struct nlmsghdr n; struct ndmsg ndm; - char buf[256]; + char buf[256]; } req; char *dev = NULL; int dst_ok = 0; int dev_ok = 0; int lladdr_ok = 0; - char * lla = NULL; + char *lla = NULL; inet_prefix dst; memset(&req, 0, sizeof(req)); @@ -124,7 +124,8 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv) lla = *argv; lladdr_ok = 1; } else if (strcmp(*argv, "nud") == 0) { - unsigned state; + unsigned int state; + NEXT_ARG(); if (nud_state_a2n(&state, *argv)) invarg("nud state is bad", *argv); @@ -193,10 +194,10 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv) int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct ndmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[NDA_MAX+1]; + struct rtattr *tb[NDA_MAX+1]; char abuf[256]; static int logit = 1; @@ -223,7 +224,7 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (!(filter.state&r->ndm_state) && !(r->ndm_flags & NTF_PROXY) && (r->ndm_state || !(filter.state&0x100)) && - (r->ndm_family != AF_DECnet)) + (r->ndm_family != AF_DECnet)) return 0; if (filter.master && !(n->nlmsg_flags & NLM_F_DUMP_FILTERED)) { @@ -239,6 +240,7 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[NDA_DST]) { if (filter.pfx.family) { inet_prefix dst; + memset(&dst, 0, sizeof(dst)); dst.family = r->ndm_family; memcpy(&dst.data, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); @@ -248,22 +250,24 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) } if (filter.unused_only && tb[NDA_CACHEINFO]) { struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]); + if (ci->ndm_refcnt) return 0; } if (filter.flushb) { struct nlmsghdr *fn; + if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } - fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); + fn = (struct nlmsghdr *)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELNEIGH; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++rth.seq; - filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; + filter.flushp = (((char *)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; if (show_stats < 2) return 0; @@ -307,11 +311,13 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[NDA_PROBES] && show_stats) { __u32 p = rta_getattr_u32(tb[NDA_PROBES]); + fprintf(fp, " probes %u", p); } if (r->ndm_state) { int nud = r->ndm_state; + fprintf(fp, " "); #define PRINT_FLAG(f) if (nud & NUD_##f) { \ @@ -344,7 +350,7 @@ static int do_show_or_flush(int argc, char **argv, int flush) struct { struct nlmsghdr n; struct ndmsg ndm; - char buf[256]; + char buf[256]; } req; char *filter_dev = NULL; int state_given = 0; @@ -376,6 +382,7 @@ static int do_show_or_flush(int argc, char **argv, int flush) filter_dev = *argv; } else if (strcmp(*argv, "master") == 0) { int ifindex; + NEXT_ARG(); ifindex = ll_name_to_index(*argv); if (!ifindex) @@ -385,7 +392,8 @@ static int do_show_or_flush(int argc, char **argv, int flush) } else if (strcmp(*argv, "unused") == 0) { filter.unused_only = 1; } else if (strcmp(*argv, "nud") == 0) { - unsigned state; + unsigned int state; + NEXT_ARG(); if (!state_given) { state_given = 1; @@ -450,7 +458,7 @@ static int do_show_or_flush(int argc, char **argv, int flush) if (round == 0) printf("Nothing to flush.\n"); else - printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":""); + printf("*** Flush is complete after %d round%s ***\n", round, round > 1?"s":""); } fflush(stdout); return 0; diff --git a/ip/ipnetconf.c b/ip/ipnetconf.c index eca6eeee8..58657a915 100644 --- a/ip/ipnetconf.c +++ b/ip/ipnetconf.c @@ -38,12 +38,12 @@ static void usage(void) exit(-1); } -#define NETCONF_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct netconfmsg)))) +#define NETCONF_RTA(r) ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct netconfmsg)))) int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct netconfmsg *ncm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[NETCONFA_MAX+1]; diff --git a/ip/ipnetns.c b/ip/ipnetns.c index 4ce598998..71fbfce50 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -389,6 +389,7 @@ static int cmd_exec(const char *cmd, char **argv, bool do_fork) static int on_netns_exec(char *nsname, void *arg) { char **argv = arg; + cmd_exec(argv[1], argv + 1, true); return 0; } @@ -426,6 +427,7 @@ static int netns_exec(int argc, char **argv) static int is_pid(const char *str) { int ch; + for (; (ch = *str); str++) { if (!isdigit(ch)) return 0; @@ -470,9 +472,10 @@ static int netns_pids(int argc, char **argv) strerror(errno)); return -1; } - while((entry = readdir(dir))) { + while ((entry = readdir(dir))) { char pid_net_path[PATH_MAX]; struct stat st; + if (!is_pid(entry->d_name)) continue; snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net", @@ -535,7 +538,7 @@ static int netns_identify(int argc, char **argv) return -1; } - while((entry = readdir(dir))) { + while ((entry = readdir(dir))) { char name_path[PATH_MAX]; struct stat st; @@ -737,6 +740,7 @@ static int netns_monitor(int argc, char **argv) char buf[4096]; struct inotify_event *event; int fd; + fd = inotify_init(); if (fd < 0) { fprintf(stderr, "inotify_init failed: %s\n", @@ -752,8 +756,9 @@ static int netns_monitor(int argc, char **argv) strerror(errno)); return -1; } - for(;;) { + for (;;) { ssize_t len = read(fd, buf, sizeof(buf)); + if (len < 0) { fprintf(stderr, "read failed: %s\n", strerror(errno)); diff --git a/ip/ipntable.c b/ip/ipntable.c index 2763570ae..8e78773d0 100644 --- a/ip/ipntable.c +++ b/ip/ipntable.c @@ -35,7 +35,7 @@ static struct { int family; - int index; + int index; #define NONE_DEV (-1) char name[1024]; } filter; @@ -65,7 +65,7 @@ static int ipntable_modify(int cmd, int flags, int argc, char **argv) struct { struct nlmsghdr n; struct ndtmsg ndtm; - char buf[1024]; + char buf[1024]; } req; char *namep = NULL; char *threshsp = NULL; @@ -351,7 +351,7 @@ static const char *ntable_strtime_delta(__u32 msec) static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct ndtmsg *ndtm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[NDTA_MAX+1]; @@ -407,6 +407,7 @@ static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void if (tb[NDTA_NAME]) { const char *name = rta_getattr_str(tb[NDTA_NAME]); + fprintf(fp, "%s ", name); } @@ -419,18 +420,22 @@ static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void if (tb[NDTA_THRESH1]) { __u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]); + fprintf(fp, "thresh1 %u ", thresh1); } if (tb[NDTA_THRESH2]) { __u32 thresh2 = rta_getattr_u32(tb[NDTA_THRESH2]); + fprintf(fp, "thresh2 %u ", thresh2); } if (tb[NDTA_THRESH3]) { __u32 thresh3 = rta_getattr_u32(tb[NDTA_THRESH3]); + fprintf(fp, "thresh3 %u ", thresh3); } if (tb[NDTA_GC_INTERVAL]) { unsigned long long gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]); + fprintf(fp, "gc_int %llu ", gc_int); } @@ -480,18 +485,22 @@ static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void if (tpb[NDTPA_REFCNT]) { __u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]); + fprintf(fp, "refcnt %u ", refcnt); } if (tpb[NDTPA_REACHABLE_TIME]) { unsigned long long reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]); + fprintf(fp, "reachable %llu ", reachable); } if (tpb[NDTPA_BASE_REACHABLE_TIME]) { unsigned long long breachable = rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]); + fprintf(fp, "base_reachable %llu ", breachable); } if (tpb[NDTPA_RETRANS_TIME]) { unsigned long long retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]); + fprintf(fp, "retrans %llu ", retrans); } @@ -501,14 +510,17 @@ static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void if (tpb[NDTPA_GC_STALETIME]) { unsigned long long gc_stale = rta_getattr_u64(tpb[NDTPA_GC_STALETIME]); + fprintf(fp, "gc_stale %llu ", gc_stale); } if (tpb[NDTPA_DELAY_PROBE_TIME]) { unsigned long long delay_probe = rta_getattr_u64(tpb[NDTPA_DELAY_PROBE_TIME]); + fprintf(fp, "delay_probe %llu ", delay_probe); } if (tpb[NDTPA_QUEUE_LEN]) { __u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]); + fprintf(fp, "queue %u ", queue); } @@ -518,14 +530,17 @@ static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void if (tpb[NDTPA_APP_PROBES]) { __u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]); + fprintf(fp, "app_probes %u ", aprobe); } if (tpb[NDTPA_UCAST_PROBES]) { __u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]); + fprintf(fp, "ucast_probes %u ", uprobe); } if (tpb[NDTPA_MCAST_PROBES]) { __u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]); + fprintf(fp, "mcast_probes %u ", mprobe); } @@ -535,18 +550,22 @@ static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void if (tpb[NDTPA_ANYCAST_DELAY]) { unsigned long long anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]); + fprintf(fp, "anycast_delay %llu ", anycast_delay); } if (tpb[NDTPA_PROXY_DELAY]) { unsigned long long proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]); + fprintf(fp, "proxy_delay %llu ", proxy_delay); } if (tpb[NDTPA_PROXY_QLEN]) { __u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]); + fprintf(fp, "proxy_queue %u ", pqueue); } if (tpb[NDTPA_LOCKTIME]) { unsigned long long locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]); + fprintf(fp, "locktime %llu ", locktime); } diff --git a/ip/ipprefix.c b/ip/ipprefix.c index ee51f04d5..2524f7849 100644 --- a/ip/ipprefix.c +++ b/ip/ipprefix.c @@ -37,10 +37,10 @@ int print_prefix(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct prefixmsg *prefix = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[RTA_MAX+1]; + struct rtattr *tb[RTA_MAX+1]; int family = preferred_family; if (n->nlmsg_type != RTM_NEWPREFIX) { @@ -96,6 +96,7 @@ int print_prefix(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[PREFIX_CACHEINFO]) { struct prefix_cacheinfo *pc; + pc = (struct prefix_cacheinfo *)RTA_DATA(tb[PREFIX_CACHEINFO]); fprintf(fp, "valid %u ", pc->valid_time); diff --git a/ip/iproute.c b/ip/iproute.c index 5b954478c..19b28701d 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -48,7 +48,7 @@ static const char *mx_names[RTAX_MAX+1] = { [RTAX_SSTHRESH] = "ssthresh", [RTAX_CWND] = "cwnd", [RTAX_ADVMSS] = "advmss", - [RTAX_REORDERING]="reordering", + [RTAX_REORDERING] = "reordering", [RTAX_HOPLIMIT] = "hoplimit", [RTAX_INITCWND] = "initcwnd", [RTAX_FEATURES] = "features", @@ -198,8 +198,10 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) return 0; if (filter.rvia.family) { int family = r->rtm_family; + if (tb[RTA_VIA]) { struct rtvia *via = RTA_DATA(tb[RTA_VIA]); + family = via->rtvia_family; } if (family != filter.rvia.family) @@ -218,7 +220,7 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) if (tb[RTA_SRC]) memcpy(&src.data, RTA_DATA(tb[RTA_SRC]), (r->rtm_src_len+7)/8); } - if (filter.rvia.bitlen>0) { + if (filter.rvia.bitlen > 0) { memset(&via, 0, sizeof(via)); via.family = r->rtm_family; if (tb[RTA_GATEWAY]) @@ -226,11 +228,12 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) if (tb[RTA_VIA]) { size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2; struct rtvia *rtvia = RTA_DATA(tb[RTA_VIA]); + via.family = rtvia->rtvia_family; memcpy(&via.data, rtvia->rtvia_addr, len); } } - if (filter.rprefsrc.bitlen>0) { + if (filter.rprefsrc.bitlen > 0) { memset(&prefsrc, 0, sizeof(prefsrc)); prefsrc.family = r->rtm_family; if (tb[RTA_PREFSRC]) @@ -255,6 +258,7 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) return 0; if (filter.realmmask) { __u32 realms = 0; + if (tb[RTA_FLOW]) realms = rta_getattr_u32(tb[RTA_FLOW]); if ((realms^filter.realm)&filter.realmmask) @@ -262,20 +266,23 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) } if (filter.iifmask) { int iif = 0; + if (tb[RTA_IIF]) - iif = *(int*)RTA_DATA(tb[RTA_IIF]); + iif = *(int *)RTA_DATA(tb[RTA_IIF]); if ((iif^filter.iif)&filter.iifmask) return 0; } if (filter.oifmask) { int oif = 0; + if (tb[RTA_OIF]) - oif = *(int*)RTA_DATA(tb[RTA_OIF]); + oif = *(int *)RTA_DATA(tb[RTA_OIF]); if ((oif^filter.oif)&filter.oifmask) return 0; } if (filter.markmask) { int mark = 0; + if (tb[RTA_MARK]) mark = *(int *)RTA_DATA(tb[RTA_MARK]); if ((mark ^ filter.mark) & filter.markmask) @@ -286,7 +293,7 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) r->rtm_dst_len == 0 && r->rtm_type == RTN_UNREACHABLE && tb[RTA_PRIORITY] && - *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1) + *(int *)RTA_DATA(tb[RTA_PRIORITY]) == -1) return 0; return 1; @@ -307,13 +314,14 @@ static void print_rtax_features(FILE *fp, unsigned int features) int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[RTA_MAX+1]; + struct rtattr *tb[RTA_MAX+1]; char abuf[256]; int host_len; __u32 table; + SPRINT_BUF(b1); static int hz; @@ -340,16 +348,17 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (filter.flushb) { struct nlmsghdr *fn; + if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } - fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); + fn = (struct nlmsghdr *)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELROUTE; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++rth.seq; - filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; + filter.flushp = (((char *)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; if (show_stats < 2) return 0; @@ -424,13 +433,14 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[RTA_VIA]) { size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2; struct rtvia *via = RTA_DATA(tb[RTA_VIA]); + fprintf(fp, "via %s %s ", family_name(via->rtvia_family), format_host(via->rtvia_family, len, via->rtvia_addr, abuf, sizeof(abuf))); } if (tb[RTA_OIF] && filter.oifmask != -1) - fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); + fprintf(fp, "dev %s ", ll_index_to_name(*(int *)RTA_DATA(tb[RTA_OIF]))); if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb) fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); @@ -465,7 +475,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (r->rtm_flags & RTNH_F_LINKDOWN) fprintf(fp, "linkdown "); if (tb[RTA_MARK]) { - unsigned int mark = *(unsigned int*)RTA_DATA(tb[RTA_MARK]); + unsigned int mark = *(unsigned int *)RTA_DATA(tb[RTA_MARK]); + if (mark) { if (mark >= 16) fprintf(fp, " mark 0x%x", mark); @@ -477,6 +488,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[RTA_FLOW] && filter.realmmask != ~0U) { __u32 to = rta_getattr_u32(tb[RTA_FLOW]); __u32 from = to>>16; + to &= 0xFFFF; fprintf(fp, "realm%s ", from ? "s" : ""); if (from) { @@ -492,7 +504,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "%s cache ", _SL_); -#define PRTFL(fl,flname) if (flags&RTCF_##fl) { \ +#define PRTFL(fl, flname) if (flags&RTCF_##fl) { \ flags &= ~RTCF_##fl; \ fprintf(fp, "%s" flname "%s", first ? "<" : "", flags ? "," : "> "); \ first = 0; } @@ -515,6 +527,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "%s%x> ", first ? "<" : "", flags); if (tb[RTA_CACHEINFO]) { struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]); + if (!hz) hz = get_user_hz(); if (ci->rta_expires != 0) @@ -537,6 +550,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) } } else if (r->rtm_family == AF_INET6) { struct rta_cacheinfo *ci = NULL; + if (tb[RTA_CACHEINFO]) ci = RTA_DATA(tb[RTA_CACHEINFO]); if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) { @@ -563,15 +577,15 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) } if (tb[RTA_METRICS]) { int i; - unsigned mxlock = 0; + unsigned int mxlock = 0; struct rtattr *mxrta[RTAX_MAX+1]; parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]), RTA_PAYLOAD(tb[RTA_METRICS])); if (mxrta[RTAX_LOCK]) - mxlock = *(unsigned*)RTA_DATA(mxrta[RTAX_LOCK]); + mxlock = *(unsigned *)RTA_DATA(mxrta[RTAX_LOCK]); - for (i=2; i<= RTAX_MAX; i++) { + for (i = 2; i <= RTAX_MAX; i++) { __u32 val = 0U; if (mxrta[i] == NULL) @@ -583,7 +597,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (i == RTAX_HOPLIMIT && (int)val == -1) continue; - if (i < sizeof(mx_names)/sizeof(char*) && mx_names[i]) + if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i]) fprintf(fp, " %s", mx_names[i]); else fprintf(fp, " metric %d", i); @@ -619,7 +633,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) } } if (tb[RTA_IIF] && filter.iifmask != -1) { - fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF]))); + fprintf(fp, " iif %s", ll_index_to_name(*(int *)RTA_DATA(tb[RTA_IIF]))); } if (tb[RTA_MULTIPATH]) { struct rtnexthop *nh = RTA_DATA(tb[RTA_MULTIPATH]); @@ -663,6 +677,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[RTA_VIA]) { size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2; struct rtvia *via = RTA_DATA(tb[RTA_VIA]); + fprintf(fp, "via %s %s ", family_name(via->rtvia_family), format_host(via->rtvia_family, len, via->rtvia_addr, @@ -671,6 +686,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[RTA_FLOW]) { __u32 to = rta_getattr_u32(tb[RTA_FLOW]); __u32 from = to>>16; + to &= 0xFFFF; fprintf(fp, " realm%s ", from ? "s" : ""); if (from) { @@ -705,6 +721,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) } if (tb[RTA_PREF]) { unsigned int pref = rta_getattr_u8(tb[RTA_PREF]); + fprintf(fp, " pref "); switch (pref) { @@ -737,6 +754,7 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r, if (strcmp(*argv, "via") == 0) { inet_prefix addr; int family; + NEXT_ARG(); family = read_family(*argv); if (family == AF_UNSPEC) @@ -760,7 +778,8 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r, exit(1); } } else if (strcmp(*argv, "weight") == 0) { - unsigned w; + unsigned int w; + NEXT_ARG(); if (get_unsigned(&w, *argv, 0) || w == 0 || w > 256) invarg("\"weight\" is invalid\n", *argv); @@ -769,6 +788,7 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r, rtnh->rtnh_flags |= RTNH_F_ONLINK; } else if (matches(*argv, "realms") == 0) { __u32 realm; + NEXT_ARG(); if (get_rt_realms_or_raw(&realm, *argv)) invarg("\"realm\" value is invalid\n", *argv); @@ -801,7 +821,7 @@ static int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r, int argc, char **argv) { char buf[1024]; - struct rtattr *rta = (void*)buf; + struct rtattr *rta = (void *)buf; struct rtnexthop *rtnh; rta->rta_type = RTA_MULTIPATH; @@ -829,16 +849,16 @@ static int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r, return 0; } -static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) +static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv) { struct { struct nlmsghdr n; struct rtmsg r; - char buf[1024]; + char buf[1024]; } req; char mxbuf[256]; - struct rtattr * mxrta = (void*)mxbuf; - unsigned mxlock = 0; + struct rtattr *mxrta = (void *)mxbuf; + unsigned int mxlock = 0; char *d = NULL; int gw_ok = 0; int dst_ok = 0; @@ -870,6 +890,7 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) while (argc > 0) { if (strcmp(*argv, "src") == 0) { inet_prefix addr; + NEXT_ARG(); get_addr(&addr, *argv, req.r.rtm_family); if (req.r.rtm_family == AF_UNSPEC) @@ -877,6 +898,7 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen); } else if (strcmp(*argv, "as") == 0) { inet_prefix addr; + NEXT_ARG(); if (strcmp(*argv, "to") == 0) { NEXT_ARG(); @@ -888,6 +910,7 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) } else if (strcmp(*argv, "via") == 0) { inet_prefix addr; int family; + gw_ok = 1; NEXT_ARG(); family = read_family(*argv); @@ -906,6 +929,7 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) &addr.family, addr.bytelen+2); } else if (strcmp(*argv, "from") == 0) { inet_prefix addr; + NEXT_ARG(); get_prefix(&addr, *argv, req.r.rtm_family); if (req.r.rtm_family == AF_UNSPEC) @@ -916,12 +940,14 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) } else if (strcmp(*argv, "tos") == 0 || matches(*argv, "dsfield") == 0) { __u32 tos; + NEXT_ARG(); if (rtnl_dsfield_a2n(&tos, *argv)) invarg("\"tos\" value is invalid\n", *argv); req.r.rtm_tos = tos; - } else if (strcmp(*argv, "expires") == 0 ) { + } else if (strcmp(*argv, "expires") == 0) { __u32 expires; + NEXT_ARG(); if (get_u32(&expires, *argv, 0)) invarg("\"expires\" value is invalid\n", *argv); @@ -932,19 +958,22 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv) matches(*argv, "priority") == 0 || strcmp(*argv, "preference") == 0) { __u32 metric; + NEXT_ARG(); if (get_u32(&metric, *argv, 0)) invarg("\"metric\" value is invalid\n", *argv); addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric); } else if (strcmp(*argv, "scope") == 0) { __u32 scope = 0; + NEXT_ARG(); if (rtnl_rtscope_a2n(&scope, *argv)) invarg("invalid \"scope\" value\n", *argv); req.r.rtm_scope = scope; scope_ok = 1; } else if (strcmp(*argv, "mtu") == 0) { - unsigned mtu; + unsigned int mtu; + NEXT_ARG(); if (strcmp(*argv, "lock") == 0) { mxlock |= (1<rta_type = RTA_ENCAP; rta->rta_len = RTA_LENGTH(0); @@ -1262,7 +1307,7 @@ static int rtnl_rtcache_request(struct rtnl_handle *rth, int family) req.rtm.rtm_family = family; req.rtm.rtm_flags |= RTM_F_CLONED; - return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); + return sendto(rth->fd, (void *)&req, sizeof(req), 0, (struct sockaddr *)&nladdr, sizeof(nladdr)); } static int iproute_flush_cache(void) @@ -1270,19 +1315,19 @@ static int iproute_flush_cache(void) #define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush" int len; - int flush_fd = open (ROUTE_FLUSH_PATH, O_WRONLY); + int flush_fd = open(ROUTE_FLUSH_PATH, O_WRONLY); char *buffer = "-1"; if (flush_fd < 0) { - fprintf (stderr, "Cannot open \"%s\": %s\n", + fprintf(stderr, "Cannot open \"%s\": %s\n", ROUTE_FLUSH_PATH, strerror(errno)); return -1; } - len = strlen (buffer); + len = strlen(buffer); - if ((write (flush_fd, (void *)buffer, len)) < len) { - fprintf (stderr, "Cannot flush routing cache\n"); + if ((write(flush_fd, (void *)buffer, len)) < len) { + fprintf(stderr, "Cannot flush routing cache\n"); close(flush_fd); return -1; } @@ -1362,6 +1407,7 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) while (argc > 0) { if (matches(*argv, "table") == 0) { __u32 tid; + NEXT_ARG(); if (rtnl_rttable_a2n(&tid, *argv)) { if (strcmp(*argv, "all") == 0) { @@ -1381,6 +1427,7 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) } else if (strcmp(*argv, "tos") == 0 || matches(*argv, "dsfield") == 0) { __u32 tos; + NEXT_ARG(); if (rtnl_dsfield_a2n(&tos, *argv)) invarg("TOS value is invalid\n", *argv); @@ -1388,6 +1435,7 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) filter.tosmask = -1; } else if (matches(*argv, "protocol") == 0) { __u32 prot = 0; + NEXT_ARG(); filter.protocolmask = -1; if (rtnl_rtprot_a2n(&prot, *argv)) { @@ -1399,6 +1447,7 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) filter.protocol = prot; } else if (matches(*argv, "scope") == 0) { __u32 scope = 0; + NEXT_ARG(); filter.scopemask = -1; if (rtnl_rtscope_a2n(&scope, *argv)) { @@ -1410,6 +1459,7 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) filter.scope = scope; } else if (matches(*argv, "type") == 0) { int type; + NEXT_ARG(); filter.typemask = -1; if (rtnl_rtntype_a2n(&type, *argv)) @@ -1428,6 +1478,7 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) filter.markmask = -1; } else if (strcmp(*argv, "via") == 0) { int family; + NEXT_ARG(); family = read_family(*argv); if (family == AF_UNSPEC) @@ -1440,6 +1491,7 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) get_prefix(&filter.rprefsrc, *argv, do_ipv6); } else if (matches(*argv, "realms") == 0) { __u32 realm; + NEXT_ARG(); if (get_rt_realms_or_raw(&realm, *argv)) invarg("invalid realms\n", *argv); @@ -1547,7 +1599,7 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) if (round == 0 && (!filter.cloned || do_ipv6 == AF_INET6)) printf("Nothing to flush.\n"); else - printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":""); + printf("*** Flush is complete after %d round%s ***\n", round, round > 1?"s":""); } fflush(stdout); return 0; @@ -1595,7 +1647,7 @@ static int iproute_get(int argc, char **argv) struct { struct nlmsghdr n; struct rtmsg r; - char buf[1024]; + char buf[1024]; } req; char *idev = NULL; char *odev = NULL; @@ -1624,12 +1676,14 @@ static int iproute_get(int argc, char **argv) if (strcmp(*argv, "tos") == 0 || matches(*argv, "dsfield") == 0) { __u32 tos; + NEXT_ARG(); if (rtnl_dsfield_a2n(&tos, *argv)) invarg("TOS value is invalid\n", *argv); req.r.rtm_tos = tos; } else if (matches(*argv, "from") == 0) { inet_prefix addr; + NEXT_ARG(); if (matches(*argv, "help") == 0) usage(); @@ -1656,6 +1710,7 @@ static int iproute_get(int argc, char **argv) connected = 1; } else { inet_prefix addr; + if (strcmp(*argv, "to") == 0) { NEXT_ARG(); } @@ -1708,9 +1763,9 @@ static int iproute_get(int argc, char **argv) if (connected && !from_ok) { struct rtmsg *r = NLMSG_DATA(&req.n); int len = req.n.nlmsg_len; - struct rtattr * tb[RTA_MAX+1]; + struct rtattr *tb[RTA_MAX+1]; - if (print_route(NULL, &req.n, (void*)stdout) < 0) { + if (print_route(NULL, &req.n, (void *)stdout) < 0) { fprintf(stderr, "An error :-)\n"); exit(1); } @@ -1749,7 +1804,7 @@ static int iproute_get(int argc, char **argv) return -2; } - if (print_route(NULL, &req.n, (void*)stdout) < 0) { + if (print_route(NULL, &req.n, (void *)stdout) < 0) { fprintf(stderr, "An error :-)\n"); return -1; } diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 707490639..a53e11d94 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -7,7 +7,7 @@ * 2 of the License, or (at your option) any later version. * * Authors: Roopa Prabhu, - * Thomas Graf + * Thomas Graf * */ @@ -203,6 +203,7 @@ static int parse_encap_ip(struct rtattr *rta, size_t len, int *argcp, char ***ar while (argc > 0) { if (strcmp(*argv, "id") == 0) { __u64 id; + NEXT_ARG(); if (id_ok++) duparg2("id", *argv); @@ -211,6 +212,7 @@ static int parse_encap_ip(struct rtattr *rta, size_t len, int *argcp, char ***ar rta_addattr64(rta, len, LWTUNNEL_IP_ID, htonll(id)); } else if (strcmp(*argv, "dst") == 0) { inet_prefix addr; + NEXT_ARG(); if (dst_ok++) duparg2("dst", *argv); @@ -218,6 +220,7 @@ static int parse_encap_ip(struct rtattr *rta, size_t len, int *argcp, char ***ar rta_addattr_l(rta, len, LWTUNNEL_IP_DST, &addr.data, addr.bytelen); } else if (strcmp(*argv, "tos") == 0) { __u32 tos; + NEXT_ARG(); if (tos_ok++) duparg2("tos", *argv); @@ -226,6 +229,7 @@ static int parse_encap_ip(struct rtattr *rta, size_t len, int *argcp, char ***ar rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos); } else if (strcmp(*argv, "ttl") == 0) { __u8 ttl; + NEXT_ARG(); if (ttl_ok++) duparg2("ttl", *argv); @@ -276,6 +280,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len, int *argcp, char ***a while (argc > 0) { if (strcmp(*argv, "id") == 0) { __u64 id; + NEXT_ARG(); if (id_ok++) duparg2("id", *argv); @@ -284,6 +289,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len, int *argcp, char ***a rta_addattr64(rta, len, LWTUNNEL_IP6_ID, htonll(id)); } else if (strcmp(*argv, "dst") == 0) { inet_prefix addr; + NEXT_ARG(); if (dst_ok++) duparg2("dst", *argv); @@ -291,6 +297,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len, int *argcp, char ***a rta_addattr_l(rta, len, LWTUNNEL_IP6_DST, &addr.data, addr.bytelen); } else if (strcmp(*argv, "tc") == 0) { __u32 tc; + NEXT_ARG(); if (tos_ok++) duparg2("tc", *argv); @@ -299,6 +306,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len, int *argcp, char ***a rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc); } else if (strcmp(*argv, "hoplimit") == 0) { __u8 hoplimit; + NEXT_ARG(); if (ttl_ok++) duparg2("hoplimit", *argv); diff --git a/ip/iprule.c b/ip/iprule.c index 7e3b38b64..dc45c6b43 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -51,13 +51,14 @@ static void usage(void) int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; int host_len = -1; __u32 table; - struct rtattr * tb[FRA_MAX+1]; + struct rtattr *tb[FRA_MAX+1]; char abuf[256]; + SPRINT_BUF(b1); if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE) @@ -75,7 +76,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "Deleted "); if (tb[FRA_PRIORITY]) - fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[FRA_PRIORITY])); + fprintf(fp, "%u:\t", *(unsigned *)RTA_DATA(tb[FRA_PRIORITY])); else fprintf(fp, "0:\t"); @@ -157,12 +158,14 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[FRA_SUPPRESS_PREFIXLEN]) { int pl = rta_getattr_u32(tb[FRA_SUPPRESS_PREFIXLEN]); + if (pl != -1) { fprintf(fp, "suppress_prefixlength %d ", pl); } } if (tb[FRA_SUPPRESS_IFGROUP]) { int group = rta_getattr_u32(tb[FRA_SUPPRESS_IFGROUP]); + if (group != -1) { SPRINT_BUF(b1); fprintf(fp, "suppress_ifgroup %s ", rtnl_group_n2a(group, b1, sizeof(b1))); @@ -173,6 +176,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[FRA_FLOW]) { __u32 to = rta_getattr_u32(tb[FRA_FLOW]); __u32 from = to>>16; + to &= 0xFFFF; if (from) { fprintf(fp, "realms %s/", @@ -326,7 +330,7 @@ static int iprule_modify(int cmd, int argc, char **argv) struct { struct nlmsghdr n; struct rtmsg r; - char buf[1024]; + char buf[1024]; } req; memset(&req, 0, sizeof(req)); @@ -351,12 +355,14 @@ static int iprule_modify(int cmd, int argc, char **argv) req.r.rtm_flags |= FIB_RULE_INVERT; } else if (strcmp(*argv, "from") == 0) { inet_prefix dst; + NEXT_ARG(); get_prefix(&dst, *argv, req.r.rtm_family); req.r.rtm_src_len = dst.bitlen; addattr_l(&req.n, sizeof(req), FRA_SRC, &dst.data, dst.bytelen); } else if (strcmp(*argv, "to") == 0) { inet_prefix dst; + NEXT_ARG(); get_prefix(&dst, *argv, req.r.rtm_family); req.r.rtm_dst_len = dst.bitlen; @@ -365,6 +371,7 @@ static int iprule_modify(int cmd, int argc, char **argv) matches(*argv, "order") == 0 || matches(*argv, "priority") == 0) { __u32 pref; + NEXT_ARG(); if (get_u32(&pref, *argv, 0)) invarg("preference value is invalid\n", *argv); @@ -372,6 +379,7 @@ static int iprule_modify(int cmd, int argc, char **argv) } else if (strcmp(*argv, "tos") == 0 || matches(*argv, "dsfield") == 0) { __u32 tos; + NEXT_ARG(); if (rtnl_dsfield_a2n(&tos, *argv)) invarg("TOS value is invalid\n", *argv); @@ -379,6 +387,7 @@ static int iprule_modify(int cmd, int argc, char **argv) } else if (strcmp(*argv, "fwmark") == 0) { char *slash; __u32 fwmark, fwmask; + NEXT_ARG(); if ((slash = strchr(*argv, '/')) != NULL) *slash = '\0'; @@ -392,6 +401,7 @@ static int iprule_modify(int cmd, int argc, char **argv) } } else if (matches(*argv, "realms") == 0) { __u32 realm; + NEXT_ARG(); if (get_rt_realms_or_raw(&realm, *argv)) invarg("invalid realms\n", *argv); @@ -399,6 +409,7 @@ static int iprule_modify(int cmd, int argc, char **argv) } else if (matches(*argv, "table") == 0 || strcmp(*argv, "lookup") == 0) { __u32 tid; + NEXT_ARG(); if (rtnl_rttable_a2n(&tid, *argv)) invarg("invalid table ID\n", *argv); @@ -412,6 +423,7 @@ static int iprule_modify(int cmd, int argc, char **argv) } else if (matches(*argv, "suppress_prefixlength") == 0 || strcmp(*argv, "sup_pl") == 0) { int pl; + NEXT_ARG(); if (get_s32(&pl, *argv, 0) || pl < 0) invarg("suppress_prefixlength value is invalid\n", *argv); @@ -420,6 +432,7 @@ static int iprule_modify(int cmd, int argc, char **argv) strcmp(*argv, "sup_group") == 0) { NEXT_ARG(); int group; + if (rtnl_group_a2n(&group, *argv)) invarg("Invalid \"suppress_ifgroup\" value\n", *argv); addattr32(&req.n, sizeof(req), FRA_SUPPRESS_IFGROUP, group); @@ -446,6 +459,7 @@ static int iprule_modify(int cmd, int argc, char **argv) usage(); else if (matches(*argv, "goto") == 0) { __u32 target; + type = FR_ACT_GOTO; NEXT_ARG(); if (get_u32(&target, *argv, 0)) @@ -480,7 +494,7 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *a struct rtnl_handle rth2; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[FRA_MAX+1]; + struct rtattr *tb[FRA_MAX+1]; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) diff --git a/ip/iptoken.c b/ip/iptoken.c index 428f13320..1d22c03c6 100644 --- a/ip/iptoken.c +++ b/ip/iptoken.c @@ -168,13 +168,11 @@ static int iptoken_set(int argc, char **argv) } if (!have_token) { - fprintf(stderr, "Not enough information: token " - "is required.\n"); + fprintf(stderr, "Not enough information: token is required.\n"); return -1; } if (!have_dev) { - fprintf(stderr, "Not enough information: \"dev\" " - "argument is required.\n"); + fprintf(stderr, "Not enough information: \"dev\" argument is required.\n"); return -1; } diff --git a/ip/iptuntap.c b/ip/iptuntap.c index b9b28a125..43774f96e 100644 --- a/ip/iptuntap.c +++ b/ip/iptuntap.c @@ -36,7 +36,7 @@ static void usage(void) __attribute__((noreturn)); static void usage(void) { - fprintf(stderr, "Usage: ip tuntap { add | del | show | list | lst | help } [ dev PHYS_DEV ] \n"); + fprintf(stderr, "Usage: ip tuntap { add | del | show | list | lst | help } [ dev PHYS_DEV ]\n"); fprintf(stderr, " [ mode { tun | tap } ] [ user USER ] [ group GROUP ]\n"); fprintf(stderr, " [ one_queue ] [ pi ] [ vnet_hdr ] [ multi_queue ]\n"); fprintf(stderr, "\n"); @@ -117,18 +117,18 @@ static int parse_args(int argc, char **argv, struct ifreq *ifr, uid_t *uid, gid_ NEXT_ARG(); if (matches(*argv, "tun") == 0) { if (ifr->ifr_flags & IFF_TAP) { - fprintf(stderr,"You managed to ask for more than one tunnel mode.\n"); + fprintf(stderr, "You managed to ask for more than one tunnel mode.\n"); exit(-1); } ifr->ifr_flags |= IFF_TUN; } else if (matches(*argv, "tap") == 0) { if (ifr->ifr_flags & IFF_TUN) { - fprintf(stderr,"You managed to ask for more than one tunnel mode.\n"); + fprintf(stderr, "You managed to ask for more than one tunnel mode.\n"); exit(-1); } ifr->ifr_flags |= IFF_TAP; } else { - fprintf(stderr,"Unknown tunnel mode \"%s\"\n", *argv); + fprintf(stderr, "Unknown tunnel mode \"%s\"\n", *argv); exit(-1); } } else if (uid && matches(*argv, "user") == 0) { @@ -140,6 +140,7 @@ static int parse_args(int argc, char **argv, struct ifreq *ifr, uid_t *uid, gid_ *uid = user; else { struct passwd *pw = getpwnam(*argv); + if (!pw) { fprintf(stderr, "invalid user \"%s\"\n", *argv); exit(-1); @@ -156,6 +157,7 @@ static int parse_args(int argc, char **argv, struct ifreq *ifr, uid_t *uid, gid_ *gid = group; else { struct group *gr = getgrnam(*argv); + if (!gr) { fprintf(stderr, "invalid group \"%s\"\n", *argv); exit(-1); @@ -313,9 +315,9 @@ int do_iptuntap(int argc, char **argv) if (matches(*argv, "delete") == 0) return do_del(argc-1, argv+1); if (matches(*argv, "show") == 0 || - matches(*argv, "lst") == 0 || - matches(*argv, "list") == 0) - return do_show(argc-1, argv+1); + matches(*argv, "lst") == 0 || + matches(*argv, "list") == 0) + return do_show(argc-1, argv+1); if (matches(*argv, "help") == 0) usage(); } else diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c index e583abf75..860414d37 100644 --- a/ip/ipxfrm.c +++ b/ip/ipxfrm.c @@ -50,7 +50,7 @@ strncat(buf, str, len); \ buf[sizeof(buf) - 1] = '\0'; \ } \ - } while(0); + } while (0); struct xfrm_filter filter; @@ -111,7 +111,7 @@ struct typeent { int t_type; }; -static const struct typeent xfrmproto_types[]= { +static const struct typeent xfrmproto_types[] = { { "esp", IPPROTO_ESP }, { "ah", IPPROTO_AH }, { "comp", IPPROTO_COMP }, { "route2", IPPROTO_ROUTING }, { "hao", IPPROTO_DSTOPTS }, { "ipsec-any", IPSEC_PROTO_ANY }, @@ -124,6 +124,7 @@ int xfrm_xfrmproto_getbyname(char *name) for (i = 0; ; i++) { const struct typeent *t = &xfrmproto_types[i]; + if (!t->t_name || t->t_type == -1) break; @@ -141,6 +142,7 @@ const char *strxf_xfrmproto(__u8 proto) for (i = 0; ; i++) { const struct typeent *t = &xfrmproto_types[i]; + if (!t->t_name || t->t_type == -1) break; @@ -152,7 +154,7 @@ const char *strxf_xfrmproto(__u8 proto) return str; } -static const struct typeent algo_types[]= { +static const struct typeent algo_types[] = { { "enc", XFRMA_ALG_CRYPT }, { "auth", XFRMA_ALG_AUTH }, { "comp", XFRMA_ALG_COMP }, { "aead", XFRMA_ALG_AEAD }, { "auth-trunc", XFRMA_ALG_AUTH_TRUNC }, @@ -165,6 +167,7 @@ int xfrm_algotype_getbyname(char *name) for (i = 0; ; i++) { const struct typeent *t = &algo_types[i]; + if (!t->t_name || t->t_type == -1) break; @@ -182,6 +185,7 @@ const char *strxf_algotype(int type) for (i = 0; ; i++) { const struct typeent *t = &algo_types[i]; + if (!t->t_name || t->t_type == -1) break; @@ -302,6 +306,7 @@ void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id, if (show_stats > 0 || force_spi || id->spi) { __u32 spi = ntohl(id->spi); + fprintf(fp, "spi 0x%08x", spi); if (show_stats > 0) fprintf(fp, "(%u)", spi); @@ -340,6 +345,7 @@ void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id, static const char *strxf_limit(__u64 limit) { static char str[32]; + if (limit == XFRM_INF) strcpy(str, "(INF)"); else @@ -389,7 +395,7 @@ void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg, if (cfg) { if (prefix) fputs(prefix, fp); - fprintf(fp, "lifetime config:%s",_SL_); + fprintf(fp, "lifetime config:%s", _SL_); if (prefix) fputs(prefix, fp); @@ -538,7 +544,7 @@ static void __xfrm_algo_print(struct xfrm_algo *algo, int type, int len, if (keylen > 0) { fprintf(fp, "0x"); - for (i = 0; i < keylen; i ++) + for (i = 0; i < keylen; i++) fprintf(fp, "%.2x", (unsigned char)algo->alg_key[i]); if (show_stats > 0) @@ -692,36 +698,42 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, if (tb[XFRMA_MARK]) { struct rtattr *rta = tb[XFRMA_MARK]; struct xfrm_mark *m = (struct xfrm_mark *) RTA_DATA(rta); + fprintf(fp, "\tmark %#x/%#x", m->v, m->m); fprintf(fp, "%s", _SL_); } if (tb[XFRMA_ALG_AUTH] && !tb[XFRMA_ALG_AUTH_TRUNC]) { struct rtattr *rta = tb[XFRMA_ALG_AUTH]; + xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta), XFRMA_ALG_AUTH, RTA_PAYLOAD(rta), fp, prefix); } if (tb[XFRMA_ALG_AUTH_TRUNC]) { struct rtattr *rta = tb[XFRMA_ALG_AUTH_TRUNC]; + xfrm_auth_trunc_print((struct xfrm_algo_auth *) RTA_DATA(rta), RTA_PAYLOAD(rta), fp, prefix); } if (tb[XFRMA_ALG_AEAD]) { struct rtattr *rta = tb[XFRMA_ALG_AEAD]; + xfrm_aead_print((struct xfrm_algo_aead *)RTA_DATA(rta), RTA_PAYLOAD(rta), fp, prefix); } if (tb[XFRMA_ALG_CRYPT]) { struct rtattr *rta = tb[XFRMA_ALG_CRYPT]; + xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta), XFRMA_ALG_CRYPT, RTA_PAYLOAD(rta), fp, prefix); } if (tb[XFRMA_ALG_COMP]) { struct rtattr *rta = tb[XFRMA_ALG_COMP]; + xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta), XFRMA_ALG_COMP, RTA_PAYLOAD(rta), fp, prefix); } @@ -765,6 +777,7 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, if (tb[XFRMA_TMPL]) { struct rtattr *rta = tb[XFRMA_TMPL]; + xfrm_tmpl_print((struct xfrm_user_tmpl *) RTA_DATA(rta), RTA_PAYLOAD(rta), fp, prefix); } @@ -1140,11 +1153,11 @@ int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family, if (id->spi && id->proto) { if (xfrm_xfrmproto_is_ro(id->proto)) { fprintf(stderr, "\"spi\" is invalid with XFRM-PROTO value \"%s\"\n", - strxf_xfrmproto(id->proto)); + strxf_xfrmproto(id->proto)); exit(1); } else if (id->proto == IPPROTO_COMP && ntohl(id->spi) >= 0x10000) { fprintf(stderr, "SPI value is too large with XFRM-PROTO value \"%s\"\n", - strxf_xfrmproto(id->proto)); + strxf_xfrmproto(id->proto)); exit(1); } } @@ -1238,6 +1251,7 @@ static int xfrm_selector_upspec_parse(struct xfrm_selector *sel, upspec = 0; else { struct protoent *pp; + pp = getprotobyname(*argv); if (pp) upspec = pp->p_proto; @@ -1304,7 +1318,7 @@ static int xfrm_selector_upspec_parse(struct xfrm_selector *sel, filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "key") == 0) { - unsigned uval; + unsigned int uval; grekey = *argv; @@ -1313,7 +1327,7 @@ static int xfrm_selector_upspec_parse(struct xfrm_selector *sel, if (strchr(*argv, '.')) uval = htonl(get_addr32(*argv)); else { - if (get_unsigned(&uval, *argv, 0)<0) { + if (get_unsigned(&uval, *argv, 0) < 0) { fprintf(stderr, "value after \"key\" is invalid\n"); exit(-1); } diff --git a/ip/link_gre.c b/ip/link_gre.c index c85741f57..c50963d79 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -61,11 +61,11 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, struct rtattr *greinfo[IFLA_GRE_MAX + 1]; __u16 iflags = 0; __u16 oflags = 0; - unsigned ikey = 0; - unsigned okey = 0; - unsigned saddr = 0; - unsigned daddr = 0; - unsigned link = 0; + unsigned int ikey = 0; + unsigned int okey = 0; + unsigned int saddr = 0; + unsigned int daddr = 0; + unsigned int link = 0; __u8 pmtudisc = 1; __u8 ttl = 0; __u8 tos = 0; @@ -156,7 +156,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, while (argc > 0) { if (!matches(*argv, "key")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); iflags |= GRE_KEY; @@ -174,14 +174,14 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, ikey = okey = uval; } else if (!matches(*argv, "ikey")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); iflags |= GRE_KEY; if (strchr(*argv, '.')) uval = get_addr32(*argv); else { - if (get_unsigned(&uval, *argv, 0)<0) { + if (get_unsigned(&uval, *argv, 0) < 0) { fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv); exit(-1); } @@ -189,14 +189,14 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, } ikey = uval; } else if (!matches(*argv, "okey")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); oflags |= GRE_KEY; if (strchr(*argv, '.')) uval = get_addr32(*argv); else { - if (get_unsigned(&uval, *argv, 0)<0) { + if (get_unsigned(&uval, *argv, 0) < 0) { fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv); exit(-1); } @@ -239,7 +239,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, } } else if (!matches(*argv, "ttl") || !matches(*argv, "hoplimit")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { @@ -343,14 +343,14 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) char s2[64]; const char *local = "any"; const char *remote = "any"; - unsigned iflags = 0; - unsigned oflags = 0; + unsigned int iflags = 0; + unsigned int oflags = 0; if (!tb) return; if (tb[IFLA_GRE_REMOTE]) { - unsigned addr = rta_getattr_u32(tb[IFLA_GRE_REMOTE]); + unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_REMOTE]); if (addr) remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); @@ -359,7 +359,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fprintf(f, "remote %s ", remote); if (tb[IFLA_GRE_LOCAL]) { - unsigned addr = rta_getattr_u32(tb[IFLA_GRE_LOCAL]); + unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_LOCAL]); if (addr) local = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); @@ -368,7 +368,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fprintf(f, "local %s ", local); if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) { - unsigned link = rta_getattr_u32(tb[IFLA_GRE_LINK]); + unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]); const char *n = if_indextoname(link, s2); if (n) diff --git a/ip/link_gre6.c b/ip/link_gre6.c index e00ea0917..a48ea8b1e 100644 --- a/ip/link_gre6.c +++ b/ip/link_gre6.c @@ -71,13 +71,13 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, struct rtattr *greinfo[IFLA_GRE_MAX + 1]; __u16 iflags = 0; __u16 oflags = 0; - unsigned ikey = 0; - unsigned okey = 0; + unsigned int ikey = 0; + unsigned int okey = 0; struct in6_addr raddr = IN6ADDR_ANY_INIT; struct in6_addr laddr = IN6ADDR_ANY_INIT; - unsigned link = 0; - unsigned flowinfo = 0; - unsigned flags = 0; + unsigned int link = 0; + unsigned int flowinfo = 0; + unsigned int flags = 0; __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT; __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; int len; @@ -152,7 +152,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, while (argc > 0) { if (!matches(*argv, "key")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); iflags |= GRE_KEY; @@ -170,14 +170,14 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, ikey = okey = uval; } else if (!matches(*argv, "ikey")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); iflags |= GRE_KEY; if (strchr(*argv, '.')) uval = get_addr32(*argv); else { - if (get_unsigned(&uval, *argv, 0)<0) { + if (get_unsigned(&uval, *argv, 0) < 0) { fprintf(stderr, "invalid value of \"ikey\"\n"); exit(-1); } @@ -185,14 +185,14 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, } ikey = uval; } else if (!matches(*argv, "okey")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); oflags |= GRE_KEY; if (strchr(*argv, '.')) uval = get_addr32(*argv); else { - if (get_unsigned(&uval, *argv, 0)<0) { + if (get_unsigned(&uval, *argv, 0) < 0) { fprintf(stderr, "invalid value of \"okey\"\n"); exit(-1); } @@ -215,6 +215,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, oflags |= GRE_CSUM; } else if (!matches(*argv, "remote")) { inet_prefix addr; + NEXT_ARG(); get_prefix(&addr, *argv, preferred_family); if (addr.family == AF_UNSPEC) @@ -222,6 +223,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, memcpy(&raddr, &addr.data, sizeof(raddr)); } else if (!matches(*argv, "local")) { inet_prefix addr; + NEXT_ARG(); get_prefix(&addr, *argv, preferred_family); if (addr.family == AF_UNSPEC) @@ -238,6 +240,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, } else if (!matches(*argv, "ttl") || !matches(*argv, "hoplimit")) { __u8 uval; + NEXT_ARG(); if (get_u8(&uval, *argv, 0)) invarg("invalid TTL", *argv); @@ -246,6 +249,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, !matches(*argv, "tclass") || !matches(*argv, "dsfield")) { __u8 uval; + NEXT_ARG(); if (strcmp(*argv, "inherit") == 0) flags |= IP6_TNL_F_USE_ORIG_TCLASS; @@ -258,6 +262,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, } else if (strcmp(*argv, "flowlabel") == 0 || strcmp(*argv, "fl") == 0) { __u32 uval; + NEXT_ARG(); if (strcmp(*argv, "inherit") == 0) flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL; @@ -301,10 +306,10 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) char s2[64]; const char *local = "any"; const char *remote = "any"; - unsigned iflags = 0; - unsigned oflags = 0; - unsigned flags = 0; - unsigned flowinfo = 0; + unsigned int iflags = 0; + unsigned int oflags = 0; + unsigned int flags = 0; + unsigned int flowinfo = 0; struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT; if (!tb) @@ -318,6 +323,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_GRE_REMOTE]) { struct in6_addr addr; + memcpy(&addr, RTA_DATA(tb[IFLA_GRE_REMOTE]), sizeof(addr)); if (memcmp(&addr, &in6_addr_any, sizeof(addr))) @@ -328,6 +334,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_GRE_LOCAL]) { struct in6_addr addr; + memcpy(&addr, RTA_DATA(tb[IFLA_GRE_LOCAL]), sizeof(addr)); if (memcmp(&addr, &in6_addr_any, sizeof(addr))) @@ -337,7 +344,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fprintf(f, "local %s ", local); if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) { - unsigned link = rta_getattr_u32(tb[IFLA_GRE_LINK]); + unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]); const char *n = if_indextoname(link, s2); if (n) diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c index f771c75de..ab5e50a20 100644 --- a/ip/link_ip6tnl.c +++ b/ip/link_ip6tnl.c @@ -35,7 +35,7 @@ static void print_usage(FILE *f) fprintf(f, " [ mode { ip6ip6 | ipip6 | any } ]\n"); fprintf(f, " type ip6tnl [ remote ADDR ] [ local ADDR ]\n"); fprintf(f, " [ dev PHYS_DEV ] [ encaplimit ELIM ]\n"); - fprintf(f ," [ hoplimit HLIM ] [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n"); + fprintf(f, " [ hoplimit HLIM ] [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n"); fprintf(f, " [ dscp inherit ] [ fwmark inherit ]\n"); fprintf(f, "\n"); fprintf(f, "Where: NAME := STRING\n"); @@ -159,6 +159,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, invarg("Cannot guess tunnel mode.", *argv); } else if (strcmp(*argv, "remote") == 0) { inet_prefix addr; + NEXT_ARG(); get_prefix(&addr, *argv, preferred_family); if (addr.family == AF_UNSPEC) @@ -166,6 +167,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, memcpy(&raddr, addr.data, addr.bytelen); } else if (strcmp(*argv, "local") == 0) { inet_prefix addr; + NEXT_ARG(); get_prefix(&addr, *argv, preferred_family); if (addr.family == AF_UNSPEC) @@ -180,6 +182,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, strcmp(*argv, "ttl") == 0 || strcmp(*argv, "hlim") == 0) { __u8 uval; + NEXT_ARG(); if (get_u8(&uval, *argv, 0)) invarg("invalid HLIM", *argv); @@ -190,6 +193,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, flags |= IP6_TNL_F_IGN_ENCAP_LIMIT; } else { __u8 uval; + if (get_u8(&uval, *argv, 0) < -1) invarg("invalid ELIM", *argv); encap_limit = uval; @@ -200,6 +204,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, strcmp(*argv, "tos") == 0 || matches(*argv, "dsfield") == 0) { __u8 uval; + NEXT_ARG(); flowinfo &= ~IP6_FLOWINFO_TCLASS; if (strcmp(*argv, "inherit") == 0) @@ -213,6 +218,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, } else if (strcmp(*argv, "flowlabel") == 0 || strcmp(*argv, "fl") == 0) { __u32 uval; + NEXT_ARG(); flowinfo &= ~IP6_FLOWINFO_FLOWLABEL; if (strcmp(*argv, "inherit") == 0) @@ -299,7 +305,7 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb } if (tb[IFLA_IPTUN_LINK] && rta_getattr_u32(tb[IFLA_IPTUN_LINK])) { - unsigned link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]); + unsigned int link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]); const char *n = if_indextoname(link, s2); if (n) diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c index 9d6bc9860..04568ffbd 100644 --- a/ip/link_iptnl.c +++ b/ip/link_iptnl.c @@ -197,6 +197,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, strcmp(*argv, "tclass") == 0 || matches(*argv, "dsfield") == 0) { __u32 uval; + NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { if (rtnl_dsfield_a2n(&uval, *argv)) @@ -262,6 +263,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM; } else if (strcmp(*argv, "6rd-prefix") == 0) { inet_prefix prefix; + NEXT_ARG(); if (get_prefix(&prefix, *argv, AF_INET6)) invarg("invalid 6rd_prefix\n", *argv); @@ -269,6 +271,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, ip6rdprefixlen = prefix.bitlen; } else if (strcmp(*argv, "6rd-relay_prefix") == 0) { inet_prefix prefix; + NEXT_ARG(); if (get_prefix(&prefix, *argv, AF_INET)) invarg("invalid 6rd-relay_prefix\n", *argv); @@ -276,6 +279,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, ip6rdrelayprefixlen = prefix.bitlen; } else if (strcmp(*argv, "6rd-reset") == 0) { inet_prefix prefix; + get_prefix(&prefix, "2002::", AF_INET6); memcpy(&ip6rdprefix, prefix.data, 16); ip6rdprefixlen = 16; @@ -332,7 +336,7 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[ return; if (tb[IFLA_IPTUN_REMOTE]) { - unsigned addr = rta_getattr_u32(tb[IFLA_IPTUN_REMOTE]); + unsigned int addr = rta_getattr_u32(tb[IFLA_IPTUN_REMOTE]); if (addr) remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); @@ -341,7 +345,7 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[ fprintf(f, "remote %s ", remote); if (tb[IFLA_IPTUN_LOCAL]) { - unsigned addr = rta_getattr_u32(tb[IFLA_IPTUN_LOCAL]); + unsigned int addr = rta_getattr_u32(tb[IFLA_IPTUN_LOCAL]); if (addr) local = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); @@ -350,7 +354,7 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[ fprintf(f, "local %s ", local); if (tb[IFLA_IPTUN_LINK] && rta_getattr_u32(tb[IFLA_IPTUN_LINK])) { - unsigned link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]); + unsigned int link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]); const char *n = if_indextoname(link, s2); if (n) diff --git a/ip/link_veth.c b/ip/link_veth.c index 314216cb6..a36882744 100644 --- a/ip/link_veth.c +++ b/ip/link_veth.c @@ -37,7 +37,7 @@ static int veth_parse_opt(struct link_util *lu, int argc, char **argv, char *type = NULL; int index = 0; int err, len; - struct rtattr * data; + struct rtattr *data; int group; struct ifinfomsg *ifm, *peer_ifm; unsigned int ifi_flags, ifi_change; diff --git a/ip/link_vti.c b/ip/link_vti.c index f3fea338f..587993035 100644 --- a/ip/link_vti.c +++ b/ip/link_vti.c @@ -55,11 +55,11 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv, struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; - unsigned ikey = 0; - unsigned okey = 0; - unsigned saddr = 0; - unsigned daddr = 0; - unsigned link = 0; + unsigned int ikey = 0; + unsigned int okey = 0; + unsigned int saddr = 0; + unsigned int daddr = 0; + unsigned int link = 0; int len; if (!(n->nlmsg_flags & NLM_F_CREATE)) { @@ -114,7 +114,7 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv, while (argc > 0) { if (!matches(*argv, "key")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); if (strchr(*argv, '.')) @@ -130,7 +130,7 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv, ikey = okey = uval; } else if (!matches(*argv, "ikey")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); if (strchr(*argv, '.')) @@ -144,7 +144,7 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv, } ikey = uval; } else if (!matches(*argv, "okey")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); if (strchr(*argv, '.')) @@ -207,7 +207,7 @@ static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) return; if (tb[IFLA_VTI_REMOTE]) { - unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_VTI_REMOTE]); + unsigned int addr = *(__u32 *)RTA_DATA(tb[IFLA_VTI_REMOTE]); if (addr) remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); @@ -216,7 +216,7 @@ static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fprintf(f, "remote %s ", remote); if (tb[IFLA_VTI_LOCAL]) { - unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LOCAL]); + unsigned int addr = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LOCAL]); if (addr) local = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); @@ -225,7 +225,7 @@ static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fprintf(f, "local %s ", local); if (tb[IFLA_VTI_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK])) { - unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK]); + unsigned int link = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK]); const char *n = if_indextoname(link, s2); if (n) diff --git a/ip/link_vti6.c b/ip/link_vti6.c index c146f791a..9a62eb5aa 100644 --- a/ip/link_vti6.c +++ b/ip/link_vti6.c @@ -53,9 +53,9 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; struct in6_addr saddr; struct in6_addr daddr; - unsigned ikey = 0; - unsigned okey = 0; - unsigned link = 0; + unsigned int ikey = 0; + unsigned int okey = 0; + unsigned int link = 0; int len; if (!(n->nlmsg_flags & NLM_F_CREATE)) { @@ -110,7 +110,7 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, while (argc > 0) { if (!matches(*argv, "key")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); if (strchr(*argv, '.')) @@ -126,7 +126,7 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, ikey = okey = uval; } else if (!matches(*argv, "ikey")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); if (strchr(*argv, '.')) @@ -140,7 +140,7 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, } ikey = uval; } else if (!matches(*argv, "okey")) { - unsigned uval; + unsigned int uval; NEXT_ARG(); if (strchr(*argv, '.')) @@ -160,6 +160,7 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, exit(-1); } else { inet_prefix addr; + get_prefix(&addr, *argv, AF_INET6); memcpy(&daddr, addr.data, addr.bytelen); } @@ -170,6 +171,7 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, exit(-1); } else { inet_prefix addr; + get_prefix(&addr, *argv, AF_INET6); memcpy(&saddr, addr.data, addr.bytelen); } @@ -222,7 +224,7 @@ static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fprintf(f, "local %s ", local); if (tb[IFLA_VTI_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK])) { - unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK]); + unsigned int link = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LINK]); const char *n = if_indextoname(link, s2); if (n) diff --git a/ip/rtmon.c b/ip/rtmon.c index 42b24fb5f..1c2981f79 100644 --- a/ip/rtmon.c +++ b/ip/rtmon.c @@ -25,13 +25,13 @@ #include "utils.h" #include "libnetlink.h" -int resolve_hosts = 0; +int resolve_hosts; static int init_phase = 1; static void write_stamp(FILE *fp) { char buf[128]; - struct nlmsghdr *n1 = (void*)buf; + struct nlmsghdr *n1 = (void *)buf; struct timeval tv; n1->nlmsg_type = NLMSG_TSTAMP; @@ -40,18 +40,19 @@ static void write_stamp(FILE *fp) n1->nlmsg_pid = 0; n1->nlmsg_len = NLMSG_LENGTH(4*2); gettimeofday(&tv, NULL); - ((__u32*)NLMSG_DATA(n1))[0] = tv.tv_sec; - ((__u32*)NLMSG_DATA(n1))[1] = tv.tv_usec; - fwrite((void*)n1, 1, NLMSG_ALIGN(n1->nlmsg_len), fp); + ((__u32 *)NLMSG_DATA(n1))[0] = tv.tv_sec; + ((__u32 *)NLMSG_DATA(n1))[1] = tv.tv_usec; + fwrite((void *)n1, 1, NLMSG_ALIGN(n1->nlmsg_len), fp); } static int dump_msg(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; + if (!init_phase) write_stamp(fp); - fwrite((void*)n, 1, NLMSG_ALIGN(n->nlmsg_len), fp); + fwrite((void *)n, 1, NLMSG_ALIGN(n->nlmsg_len), fp); fflush(fp); return 0; } @@ -75,7 +76,7 @@ main(int argc, char **argv) FILE *fp; struct rtnl_handle rth; int family = AF_UNSPEC; - unsigned groups = ~0U; + unsigned int groups = ~0U; int llink = 0; int laddr = 0; int lroute = 0; @@ -115,13 +116,13 @@ main(int argc, char **argv) usage(); file = argv[1]; } else if (matches(argv[1], "link") == 0) { - llink=1; + llink = 1; groups = 0; } else if (matches(argv[1], "address") == 0) { - laddr=1; + laddr = 1; groups = 0; } else if (matches(argv[1], "route") == 0) { - lroute=1; + lroute = 1; groups = 0; } else if (strcmp(argv[1], "all") == 0) { groups = ~0U; @@ -176,7 +177,7 @@ main(int argc, char **argv) init_phase = 0; - if (rtnl_listen(&rth, dump_msg, (void*)fp) < 0) + if (rtnl_listen(&rth, dump_msg, (void *)fp) < 0) exit(2); exit(0); diff --git a/ip/tcp_metrics.c b/ip/tcp_metrics.c index 57b605fdd..3a6499171 100644 --- a/ip/tcp_metrics.c +++ b/ip/tcp_metrics.c @@ -168,6 +168,7 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, if (f.flushb) { struct nlmsghdr *fn; + TCPM_REQUEST(req2, 128, TCP_METRICS_CMD_DEL, NLM_F_REQUEST); addattr_l(&req2.n, sizeof(req2), atype, &daddr.data, @@ -333,6 +334,7 @@ static int tcpm_do_cmd(int cmd, int argc, char **argv) if (strcmp(*argv, "src") == 0 || strcmp(*argv, "source") == 0) { char *who = *argv; + NEXT_ARG(); if (matches(*argv, "help") == 0) usage(); @@ -354,6 +356,7 @@ static int tcpm_do_cmd(int cmd, int argc, char **argv) } } else { char *who = "address"; + if (strcmp(*argv, "addr") == 0 || strcmp(*argv, "address") == 0) { who = *argv; @@ -504,7 +507,7 @@ int do_tcp_metrics(int argc, char **argv) if (matches(argv[0], "help") == 0) usage(); - fprintf(stderr, "Command \"%s\" is unknown, " - "try \"ip tcp_metrics help\".\n", *argv); + fprintf(stderr, "Command \"%s\" is unknown, try \"ip tcp_metrics help\".\n", + *argv); exit(-1); } diff --git a/ip/tunnel.c b/ip/tunnel.c index 39f825bae..7956d71aa 100644 --- a/ip/tunnel.c +++ b/ip/tunnel.c @@ -72,7 +72,7 @@ int tnl_get_ioctl(const char *basedev, void *p) int err; strncpy(ifr.ifr_name, basedev, IFNAMSIZ); - ifr.ifr_ifru.ifru_data = (void*)p; + ifr.ifr_ifru.ifru_data = (void *)p; fd = socket(preferred_family, SOCK_DGRAM, 0); if (fd < 0) { @@ -183,7 +183,7 @@ int tnl_ioctl_get_6rd(const char *name, void *p) __be32 tnl_parse_key(const char *name, const char *key) { - unsigned uval; + unsigned int uval; if (strchr(key, '.')) return get_addr32(key); @@ -209,10 +209,10 @@ void tnl_print_stats(const char *buf) tx_fifo, tx_colls, tx_carrier, rx_multi; if (sscanf(buf, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu", - &rx_bytes, &rx_packets, &rx_errs, &rx_drops, - &rx_fifo, &rx_frame, &rx_multi, - &tx_bytes, &tx_packets, &tx_errs, &tx_drops, - &tx_fifo, &tx_colls, &tx_carrier) != 14) + &rx_bytes, &rx_packets, &rx_errs, &rx_drops, + &rx_fifo, &rx_frame, &rx_multi, + &tx_bytes, &tx_packets, &tx_errs, &tx_drops, + &tx_fifo, &tx_colls, &tx_carrier) != 14) return; printf("%s", _SL_); diff --git a/ip/xfrm_monitor.c b/ip/xfrm_monitor.c index e6e991afc..96b52a44b 100644 --- a/ip/xfrm_monitor.c +++ b/ip/xfrm_monitor.c @@ -46,10 +46,10 @@ static void usage(void) static int xfrm_acquire_print(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct xfrm_user_acquire *xacq = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[XFRMA_MAX+1]; + struct rtattr *tb[XFRMA_MAX+1]; __u16 family; len -= NLMSG_LENGTH(sizeof(*xacq)); @@ -71,6 +71,7 @@ static int xfrm_acquire_print(const struct sockaddr_nl *who, fprintf(fp, "proto %s ", strxf_xfrmproto(xacq->id.proto)); if (show_stats > 0 || xacq->id.spi) { __u32 spi = ntohl(xacq->id.spi); + fprintf(fp, "spi 0x%08x", spi); if (show_stats > 0) fprintf(fp, "(%u)", spi); @@ -107,7 +108,7 @@ static int xfrm_acquire_print(const struct sockaddr_nl *who, static int xfrm_state_flush_print(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct xfrm_usersa_flush *xsf = NLMSG_DATA(n); int len = n->nlmsg_len; const char *str; @@ -137,8 +138,8 @@ static int xfrm_state_flush_print(const struct sockaddr_nl *who, static int xfrm_policy_flush_print(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - struct rtattr * tb[XFRMA_MAX+1]; - FILE *fp = (FILE*)arg; + struct rtattr *tb[XFRMA_MAX+1]; + FILE *fp = (FILE *)arg; int len = n->nlmsg_len; len -= NLMSG_SPACE(0); @@ -175,10 +176,10 @@ static int xfrm_policy_flush_print(const struct sockaddr_nl *who, static int xfrm_report_print(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct xfrm_user_report *xrep = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[XFRMA_MAX+1]; + struct rtattr *tb[XFRMA_MAX+1]; __u16 family; len -= NLMSG_LENGTH(sizeof(*xrep)); @@ -210,7 +211,8 @@ static int xfrm_report_print(const struct sockaddr_nl *who, static void xfrm_ae_flags_print(__u32 flags, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; + fprintf(fp, " (0x%x) ", flags); if (!flags) return; @@ -241,13 +243,13 @@ static void xfrm_usersa_print(const struct xfrm_usersa_id *sa_id, __u32 reqid, F static int xfrm_ae_print(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct xfrm_aevent_id *id = NLMSG_DATA(n); char abuf[256]; fprintf(fp, "Async event "); xfrm_ae_flags_print(id->flags, arg); - fprintf(fp,"\n\t"); + fprintf(fp, "\n\t"); memset(abuf, '\0', sizeof(abuf)); fprintf(fp, "src %s ", rt_addr_n2a(id->sa_id.family, sizeof(id->saddr), &id->saddr, @@ -272,7 +274,7 @@ static void xfrm_print_addr(FILE *fp, int family, xfrm_address_t *a) static int xfrm_mapping_print(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; struct xfrm_user_mapping *map = NLMSG_DATA(n); fprintf(fp, "Mapping change "); @@ -293,7 +295,7 @@ static int xfrm_accept_msg(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; if (timestamp) print_timestamp(fp); @@ -353,13 +355,13 @@ extern struct rtnl_handle rth; int do_xfrm_monitor(int argc, char **argv) { char *file = NULL; - unsigned groups = ~((unsigned)0); /* XXX */ - int lacquire=0; - int lexpire=0; - int laevent=0; - int lpolicy=0; - int lsa=0; - int lreport=0; + unsigned int groups = ~((unsigned)0); /* XXX */ + int lacquire = 0; + int lexpire = 0; + int laevent = 0; + int lpolicy = 0; + int lsa = 0; + int lreport = 0; rtnl_close(&rth); @@ -370,22 +372,22 @@ int do_xfrm_monitor(int argc, char **argv) } else if (matches(*argv, "all-nsid") == 0) { listen_all_nsid = 1; } else if (matches(*argv, "acquire") == 0) { - lacquire=1; + lacquire = 1; groups = 0; } else if (matches(*argv, "expire") == 0) { - lexpire=1; + lexpire = 1; groups = 0; } else if (matches(*argv, "SA") == 0) { - lsa=1; + lsa = 1; groups = 0; } else if (matches(*argv, "aevent") == 0) { - laevent=1; + laevent = 1; groups = 0; } else if (matches(*argv, "policy") == 0) { - lpolicy=1; + lpolicy = 1; groups = 0; } else if (matches(*argv, "report") == 0) { - lreport=1; + lreport = 1; groups = 0; } else if (matches(*argv, "help") == 0) { usage(); @@ -428,7 +430,7 @@ int do_xfrm_monitor(int argc, char **argv) if (listen_all_nsid && rtnl_listen_all_nsid(&rth) < 0) exit(1); - if (rtnl_listen(&rth, xfrm_accept_msg, (void*)stdout) < 0) + if (rtnl_listen(&rth, xfrm_accept_msg, (void *)stdout) < 0) exit(2); return 0; diff --git a/ip/xfrm_policy.c b/ip/xfrm_policy.c index efea1e8d1..f1ac3e91d 100644 --- a/ip/xfrm_policy.c +++ b/ip/xfrm_policy.c @@ -33,7 +33,7 @@ #include "xfrm.h" #include "ip_common.h" -//#define NLMSG_DELETEALL_BUF_SIZE (4096-512) +/* #define NLMSG_DELETEALL_BUF_SIZE (4096-512) */ #define NLMSG_DELETEALL_BUF_SIZE 8192 /* @@ -241,7 +241,7 @@ int xfrm_sctx_parse(char *ctxstr, char *s, return 0; } -static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv) +static int xfrm_policy_modify(int cmd, unsigned int flags, int argc, char **argv) { struct rtnl_handle rth; struct { @@ -376,7 +376,7 @@ static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv) int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, (void *)&mark, sizeof(mark)); if (r < 0) { - fprintf(stderr, "%s: XFRMA_MARK failed\n",__func__); + fprintf(stderr, "%s: XFRMA_MARK failed\n", __func__); exit(1); } } @@ -459,13 +459,13 @@ static int xfrm_policy_filter_match(struct xfrm_userpolicy_info *xpinfo, int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - struct rtattr * tb[XFRMA_MAX+1]; - struct rtattr * rta; + struct rtattr *tb[XFRMA_MAX+1]; + struct rtattr *rta; struct xfrm_userpolicy_info *xpinfo = NULL; struct xfrm_user_polexpire *xpexp = NULL; struct xfrm_userpolicy_id *xpid = NULL; __u8 ptype = XFRM_POLICY_TYPE_MAIN; - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; int len = n->nlmsg_len; if (n->nlmsg_type != XFRM_MSG_NEWPOLICY && @@ -526,7 +526,7 @@ int xfrm_policy_print(const struct sockaddr_nl *who, struct nlmsghdr *n, fprintf(fp, "Expired "); if (n->nlmsg_type == XFRM_MSG_DELPOLICY) { - //xfrm_policy_id_print(); + /* xfrm_policy_id_print(); */ if (!tb[XFRMA_POLICY]) { fprintf(stderr, "Buggy XFRM_MSG_DELPOLICY: no XFRMA_POLICY\n"); return -1; @@ -659,7 +659,7 @@ static int xfrm_policy_get_or_delete(int argc, char **argv, int delete, int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, (void *)&mark, sizeof(mark)); if (r < 0) { - fprintf(stderr, "%s: XFRMA_MARK failed\n",__func__); + fprintf(stderr, "%s: XFRMA_MARK failed\n", __func__); exit(1); } } @@ -691,7 +691,7 @@ static int xfrm_policy_get(int argc, char **argv) xfrm_policy_get_or_delete(argc, argv, 0, n, sizeof(buf)); - if (xfrm_policy_print(NULL, n, (void*)stdout) < 0) { + if (xfrm_policy_print(NULL, n, (void *)stdout) < 0) { fprintf(stderr, "An error :-)\n"); exit(1); } @@ -761,7 +761,7 @@ static int xfrm_policy_keep(const struct sockaddr_nl *who, xpid->index = xpinfo->index; xb->offset += new_n->nlmsg_len; - xb->nlmsg_count ++; + xb->nlmsg_count++; return 0; } @@ -915,12 +915,12 @@ static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall) exit(0); } -static int print_spdinfo( struct nlmsghdr *n, void *arg) +static int print_spdinfo(struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; __u32 *f = NLMSG_DATA(n); - struct rtattr * tb[XFRMA_SPD_MAX+1]; - struct rtattr * rta; + struct rtattr *tb[XFRMA_SPD_MAX+1]; + struct rtattr *rta; int len = n->nlmsg_len; @@ -933,7 +933,7 @@ static int print_spdinfo( struct nlmsghdr *n, void *arg) rta = XFRMSAPD_RTA(f); parse_rtattr(tb, XFRMA_SPD_MAX, rta, len); - fprintf(fp,"\t SPD"); + fprintf(fp, "\t SPD"); if (tb[XFRMA_SPD_INFO]) { struct xfrmu_spdinfo *si; @@ -942,16 +942,16 @@ static int print_spdinfo( struct nlmsghdr *n, void *arg) return -1; } si = RTA_DATA(tb[XFRMA_SPD_INFO]); - fprintf(fp," IN %d", si->incnt); - fprintf(fp," OUT %d", si->outcnt); - fprintf(fp," FWD %d", si->fwdcnt); + fprintf(fp, " IN %d", si->incnt); + fprintf(fp, " OUT %d", si->outcnt); + fprintf(fp, " FWD %d", si->fwdcnt); if (show_stats) { - fprintf(fp," (Sock:"); - fprintf(fp," IN %d", si->inscnt); - fprintf(fp," OUT %d", si->outscnt); - fprintf(fp," FWD %d", si->fwdscnt); - fprintf(fp,")"); + fprintf(fp, " (Sock:"); + fprintf(fp, " IN %d", si->inscnt); + fprintf(fp, " OUT %d", si->outscnt); + fprintf(fp, " FWD %d", si->fwdscnt); + fprintf(fp, ")"); } fprintf(fp, "%s", _SL_); @@ -965,34 +965,36 @@ static int print_spdinfo( struct nlmsghdr *n, void *arg) return -1; } sh = RTA_DATA(tb[XFRMA_SPD_HINFO]); - fprintf(fp,"\t SPD buckets:"); - fprintf(fp," count %d", sh->spdhcnt); - fprintf(fp," Max %d", sh->spdhmcnt); + fprintf(fp, "\t SPD buckets:"); + fprintf(fp, " count %d", sh->spdhcnt); + fprintf(fp, " Max %d", sh->spdhmcnt); fprintf(fp, "%s", _SL_); } if (tb[XFRMA_SPD_IPV4_HTHRESH]) { struct xfrmu_spdhthresh *th; + if (RTA_PAYLOAD(tb[XFRMA_SPD_IPV4_HTHRESH]) < sizeof(*th)) { fprintf(stderr, "SPDinfo: Wrong len %d\n", len); return -1; } th = RTA_DATA(tb[XFRMA_SPD_IPV4_HTHRESH]); - fprintf(fp,"\t SPD IPv4 thresholds:"); - fprintf(fp," local %d", th->lbits); - fprintf(fp," remote %d", th->rbits); + fprintf(fp, "\t SPD IPv4 thresholds:"); + fprintf(fp, " local %d", th->lbits); + fprintf(fp, " remote %d", th->rbits); fprintf(fp, "%s", _SL_); } if (tb[XFRMA_SPD_IPV6_HTHRESH]) { struct xfrmu_spdhthresh *th; + if (RTA_PAYLOAD(tb[XFRMA_SPD_IPV6_HTHRESH]) < sizeof(*th)) { fprintf(stderr, "SPDinfo: Wrong len %d\n", len); return -1; } th = RTA_DATA(tb[XFRMA_SPD_IPV6_HTHRESH]); - fprintf(fp,"\t SPD IPv6 thresholds:"); - fprintf(fp," local %d", th->lbits); - fprintf(fp," remote %d", th->rbits); + fprintf(fp, "\t SPD IPv6 thresholds:"); + fprintf(fp, " local %d", th->lbits); + fprintf(fp, " remote %d", th->rbits); fprintf(fp, "%s", _SL_); } } @@ -1000,7 +1002,7 @@ static int print_spdinfo( struct nlmsghdr *n, void *arg) if (oneline) fprintf(fp, "\n"); - return 0; + return 0; } static int xfrm_spd_setinfo(int argc, char **argv) @@ -1093,7 +1095,7 @@ static int xfrm_spd_getinfo(int argc, char **argv) if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) exit(2); - print_spdinfo(&req.n, (void*)stdout); + print_spdinfo(&req.n, (void *)stdout); rtnl_close(&rth); diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c index b5734da2a..5e2b64195 100644 --- a/ip/xfrm_state.c +++ b/ip/xfrm_state.c @@ -32,7 +32,7 @@ #include "xfrm.h" #include "ip_common.h" -//#define NLMSG_DELETEALL_BUF_SIZE (4096-512) +/* #define NLMSG_DELETEALL_BUF_SIZE (4096-512) */ #define NLMSG_DELETEALL_BUF_SIZE 8192 /* @@ -107,7 +107,7 @@ static void usage(void) fprintf(stderr, "LIMIT-LIST := [ LIMIT-LIST ] limit LIMIT\n"); fprintf(stderr, "LIMIT := { time-soft | time-hard | time-use-soft | time-use-hard } SECONDS |\n"); fprintf(stderr, " { byte-soft | byte-hard } SIZE | { packet-soft | packet-hard } COUNT\n"); - fprintf(stderr, "ENCAP := { espinudp | espinudp-nonike } SPORT DPORT OADDR\n"); + fprintf(stderr, "ENCAP := { espinudp | espinudp-nonike } SPORT DPORT OADDR\n"); exit(-1); } @@ -142,7 +142,7 @@ static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type, if (len > max) invarg("ALGO-KEYMAT value makes buffer overflow\n", key); - for (i = - (plen % 2), j = 0; j < len; i += 2, j++) { + for (i = -(plen % 2), j = 0; j < len; i += 2, j++) { char vbuf[3]; __u8 val; @@ -266,13 +266,13 @@ static int xfrm_state_extra_flag_parse(__u32 *extra_flags, int *argcp, char ***a return 0; } -static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv) +static int xfrm_state_modify(int cmd, unsigned int flags, int argc, char **argv) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct xfrm_usersa_info xsinfo; - char buf[RTA_BUF_SIZE]; + char buf[RTA_BUF_SIZE]; } req; struct xfrm_replay_state replay; struct xfrm_replay_state_esn replay_esn; @@ -356,7 +356,7 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv) } else if (strcmp(*argv, "encap") == 0) { struct xfrm_encap_tmpl encap; inet_prefix oa; - NEXT_ARG(); + NEXT_ARG(); xfrm_encap_type_parse(&encap.encap_type, &argc, &argv); NEXT_ARG(); if (get_u16(&encap.encap_sport, *argv, 0)) @@ -408,6 +408,7 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv) } else { /* try to assume ALGO */ int type = xfrm_algotype_getbyname(*argv); + switch (type) { case XFRMA_ALG_AEAD: case XFRMA_ALG_CRYPT: @@ -701,7 +702,7 @@ static int xfrm_state_allocspi(int argc, char **argv) struct { struct nlmsghdr n; struct xfrm_userspi_info xspi; - char buf[RTA_BUF_SIZE]; + char buf[RTA_BUF_SIZE]; } req; char *idp = NULL; char *minp = NULL; @@ -827,7 +828,7 @@ static int xfrm_state_allocspi(int argc, char **argv) if (rtnl_talk(&rth, &req.n, res_n, sizeof(res_buf)) < 0) exit(2); - if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) { + if (xfrm_state_print(NULL, res_n, (void *)stdout) < 0) { fprintf(stderr, "An error :-)\n"); exit(1); } @@ -868,9 +869,9 @@ static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo) int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; - struct rtattr * tb[XFRMA_MAX+1]; - struct rtattr * rta; + FILE *fp = (FILE *)arg; + struct rtattr *tb[XFRMA_MAX+1]; + struct rtattr *rta; struct xfrm_usersa_info *xsinfo = NULL; struct xfrm_user_expire *xexp = NULL; struct xfrm_usersa_id *xsid = NULL; @@ -924,7 +925,7 @@ int xfrm_state_print(const struct sockaddr_nl *who, struct nlmsghdr *n, parse_rtattr(tb, XFRMA_MAX, rta, len); if (n->nlmsg_type == XFRM_MSG_DELSA) { - //xfrm_policy_id_print(); + /* xfrm_policy_id_print(); */ if (!tb[XFRMA_SA]) { fprintf(stderr, "Buggy XFRM_MSG_DELSA: no XFRMA_SA\n"); @@ -958,7 +959,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete) struct { struct nlmsghdr n; struct xfrm_usersa_id xsid; - char buf[RTA_BUF_SIZE]; + char buf[RTA_BUF_SIZE]; } req; struct xfrm_id id; char *idp = NULL; @@ -1025,7 +1026,7 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete) if (rtnl_talk(&rth, &req.n, res_n, sizeof(req)) < 0) exit(2); - if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) { + if (xfrm_state_print(NULL, res_n, (void *)stdout) < 0) { fprintf(stderr, "An error :-)\n"); exit(1); } @@ -1087,7 +1088,7 @@ static int xfrm_state_keep(const struct sockaddr_nl *who, sizeof(xsid->daddr)); xb->offset += new_n->nlmsg_len; - xb->nlmsg_count ++; + xb->nlmsg_count++; return 0; } @@ -1097,7 +1098,7 @@ static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall) char *idp = NULL; struct rtnl_handle rth; - if(argc > 0) + if (argc > 0) filter.use = 1; filter.xsinfo.family = preferred_family; @@ -1231,7 +1232,7 @@ static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall) static int print_sadinfo(struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE*)arg; + FILE *fp = (FILE *)arg; __u32 *f = NLMSG_DATA(n); struct rtattr *tb[XFRMA_SAD_MAX+1]; struct rtattr *rta; @@ -1249,11 +1250,11 @@ static int print_sadinfo(struct nlmsghdr *n, void *arg) parse_rtattr(tb, XFRMA_SAD_MAX, rta, len); if (tb[XFRMA_SAD_CNT]) { - fprintf(fp,"\t SAD"); + fprintf(fp, "\t SAD"); cnt = (__u32 *)RTA_DATA(tb[XFRMA_SAD_CNT]); - fprintf(fp," count %d", *cnt); + fprintf(fp, " count %d", *cnt); } else { - fprintf(fp,"BAD SAD info returned\n"); + fprintf(fp, "BAD SAD info returned\n"); return -1; } @@ -1262,20 +1263,20 @@ static int print_sadinfo(struct nlmsghdr *n, void *arg) struct xfrmu_sadhinfo *si; if (RTA_PAYLOAD(tb[XFRMA_SAD_HINFO]) < sizeof(*si)) { - fprintf(fp,"BAD SAD length returned\n"); + fprintf(fp, "BAD SAD length returned\n"); return -1; } si = RTA_DATA(tb[XFRMA_SAD_HINFO]); - fprintf(fp," (buckets "); - fprintf(fp,"count %d", si->sadhcnt); - fprintf(fp," Max %d", si->sadhmcnt); - fprintf(fp,")"); + fprintf(fp, " (buckets "); + fprintf(fp, "count %d", si->sadhcnt); + fprintf(fp, " Max %d", si->sadhmcnt); + fprintf(fp, ")"); } } - fprintf(fp,"\n"); + fprintf(fp, "\n"); - return 0; + return 0; } static int xfrm_sad_getinfo(int argc, char **argv) @@ -1299,7 +1300,7 @@ static int xfrm_sad_getinfo(int argc, char **argv) if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) exit(2); - print_sadinfo(&req.n, (void*)stdout); + print_sadinfo(&req.n, (void *)stdout); rtnl_close(&rth); From df4b043f0845eaf3534b32925c5e79970f9a95a0 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 21 Mar 2016 11:56:01 -0700 Subject: [PATCH 141/513] bridge: code cleanup Use checkpatch auto fix to cleanup lingering style issues --- bridge/fdb.c | 20 +++++++++++--------- bridge/link.c | 25 +++++++++++++------------ bridge/mdb.c | 6 +++--- bridge/monitor.c | 13 +++++++------ bridge/vlan.c | 9 +++++---- 5 files changed, 39 insertions(+), 34 deletions(-) diff --git a/bridge/fdb.c b/bridge/fdb.c index 1400b654d..88f1b63c2 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -34,12 +34,12 @@ static void usage(void) fprintf(stderr, "Usage: bridge fdb { add | append | del | replace } ADDR dev DEV\n" " [ self ] [ master ] [ use ] [ router ]\n" " [ local | static | dynamic ] [ dst IPADDR ] [ vlan VID ]\n" - " [ port PORT] [ vni VNI ] [ via DEV ]\n"); + " [ port PORT] [ vni VNI ] [ via DEV ]\n"); fprintf(stderr, " bridge fdb [ show [ br BRDEV ] [ brport DEV ] ]\n"); exit(-1); } -static const char *state_n2a(unsigned s) +static const char *state_n2a(unsigned int s) { static char buf[32]; @@ -64,7 +64,7 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) FILE *fp = arg; struct ndmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[NDA_MAX+1]; + struct rtattr *tb[NDA_MAX+1]; if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) { fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n", @@ -119,6 +119,7 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[NDA_VLAN]) { __u16 vid = rta_getattr_u16(tb[NDA_VLAN]); + fprintf(fp, "vlan %hu ", vid); } @@ -171,9 +172,9 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) static int fdb_show(int argc, char **argv) { struct { - struct nlmsghdr n; + struct nlmsghdr n; struct ifinfomsg ifm; - char buf[256]; + char buf[256]; } req; char *filter_dev = NULL; @@ -200,6 +201,7 @@ static int fdb_show(int argc, char **argv) if (br) { int br_ifindex = ll_name_to_index(br); + if (br_ifindex == 0) { fprintf(stderr, "Cannot find bridge device \"%s\"\n", br); return -1; @@ -235,9 +237,9 @@ static int fdb_show(int argc, char **argv) static int fdb_modify(int cmd, int flags, int argc, char **argv) { struct { - struct nlmsghdr n; - struct ndmsg ndm; - char buf[256]; + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; } req; char *addr = NULL; char *d = NULL; @@ -298,7 +300,7 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv) req.ndm.ndm_flags |= NTF_MASTER; } else if (matches(*argv, "router") == 0) { req.ndm.ndm_flags |= NTF_ROUTER; - } else if (matches(*argv, "local") == 0|| + } else if (matches(*argv, "local") == 0 || matches(*argv, "permanent") == 0) { req.ndm.ndm_state |= NUD_PERMANENT; } else if (matches(*argv, "temp") == 0 || diff --git a/bridge/link.c b/bridge/link.c index a9b1262df..353e1c3da 100644 --- a/bridge/link.c +++ b/bridge/link.c @@ -25,17 +25,17 @@ static const char *port_states[] = { [BR_STATE_BLOCKING] = "blocking", }; -extern char *if_indextoname (unsigned int __ifindex, char *__ifname); +extern char *if_indextoname(unsigned int __ifindex, char *__ifname); -static void print_link_flags(FILE *fp, unsigned flags) +static void print_link_flags(FILE *fp, unsigned int flags) { fprintf(fp, "<"); if (flags & IFF_UP && !(flags & IFF_RUNNING)) fprintf(fp, "NO-CARRIER%s", flags ? "," : ""); flags &= ~IFF_RUNNING; #define _PF(f) if (flags&IFF_##f) { \ - flags &= ~IFF_##f ; \ - fprintf(fp, #f "%s", flags ? "," : ""); } + flags &= ~IFF_##f ; \ + fprintf(fp, #f "%s", flags ? "," : ""); } _PF(LOOPBACK); _PF(BROADCAST); _PF(POINTOPOINT); @@ -55,7 +55,7 @@ static void print_link_flags(FILE *fp, unsigned flags) _PF(DORMANT); _PF(ECHO); #undef _PF - if (flags) + if (flags) fprintf(fp, "%x", flags); fprintf(fp, "> "); } @@ -69,7 +69,7 @@ static const char *hw_mode[] = {"VEB", "VEPA"}; static void print_operstate(FILE *f, __u8 state) { - if (state >= sizeof(oper_states)/sizeof(oper_states[0])) + if (state >= ARRAY_SIZE(oper_states)) fprintf(f, "state %#x ", state); else fprintf(f, "state %s ", oper_states[state]); @@ -90,7 +90,7 @@ static void print_onoff(FILE *f, char *flag, __u8 val) static void print_hwmode(FILE *f, __u16 mode) { - if (mode >= sizeof(hw_mode)/sizeof(hw_mode[0])) + if (mode >= ARRAY_SIZE(hw_mode)) fprintf(f, "hwmode %#hx ", mode); else fprintf(f, "hwmode %s ", hw_mode[mode]); @@ -102,14 +102,14 @@ int print_linkinfo(const struct sockaddr_nl *who, FILE *fp = arg; int len = n->nlmsg_len; struct ifinfomsg *ifi = NLMSG_DATA(n); - struct rtattr * tb[IFLA_MAX+1]; + struct rtattr *tb[IFLA_MAX+1]; char b1[IFNAMSIZ]; len -= NLMSG_LENGTH(sizeof(*ifi)); if (len < 0) { fprintf(stderr, "Message too short!\n"); return -1; - } + } if (!(ifi->ifi_family == AF_BRIDGE || ifi->ifi_family == AF_UNSPEC)) return 0; @@ -136,6 +136,7 @@ int print_linkinfo(const struct sockaddr_nl *who, if (tb[IFLA_LINK]) { SPRINT_BUF(b1); int iflink = rta_getattr_u32(tb[IFLA_LINK]); + if (iflink == 0) fprintf(fp, "@NONE: "); else @@ -220,7 +221,7 @@ static void usage(void) { fprintf(stderr, "Usage: bridge link set dev DEV [ cost COST ] [ priority PRIO ] [ state STATE ]\n"); fprintf(stderr, " [ guard {on | off} ]\n"); - fprintf(stderr, " [ hairpin {on | off} ] \n"); + fprintf(stderr, " [ hairpin {on | off} ]\n"); fprintf(stderr, " [ fastleave {on | off} ]\n"); fprintf(stderr, " [ root_block {on | off} ]\n"); fprintf(stderr, " [ learning {on | off} ]\n"); @@ -319,6 +320,7 @@ static int brlink_modify(int argc, char **argv) NEXT_ARG(); char *endptr; size_t nstates = sizeof(port_states) / sizeof(*port_states); + state = strtol(*argv, &endptr, 10); if (!(**argv != '\0' && *endptr == '\0')) { for (state = 0; state < nstates; state++) @@ -339,8 +341,7 @@ static int brlink_modify(int argc, char **argv) mode = BRIDGE_MODE_VEB; else { fprintf(stderr, - "Mode argument must be \"vepa\" or " - "\"veb\".\n"); + "Mode argument must be \"vepa\" or \"veb\".\n"); return -1; } } else if (strcmp(*argv, "self") == 0) { diff --git a/bridge/mdb.c b/bridge/mdb.c index 97da4dc98..842536ec0 100644 --- a/bridge/mdb.c +++ b/bridge/mdb.c @@ -21,7 +21,7 @@ #ifndef MDBA_RTA #define MDBA_RTA(r) \ - ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct br_port_msg)))) + ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct br_port_msg)))) #endif static unsigned int filter_index; @@ -224,9 +224,9 @@ static int mdb_show(int argc, char **argv) static int mdb_modify(int cmd, int flags, int argc, char **argv) { struct { - struct nlmsghdr n; + struct nlmsghdr n; struct br_port_msg bpm; - char buf[1024]; + char buf[1024]; } req; struct br_mdb_entry entry; char *d = NULL, *p = NULL, *grp = NULL; diff --git a/bridge/monitor.c b/bridge/monitor.c index d8341ec5f..62690810d 100644 --- a/bridge/monitor.c +++ b/bridge/monitor.c @@ -76,10 +76,10 @@ static int accept_msg(const struct sockaddr_nl *who, int do_monitor(int argc, char **argv) { char *file = NULL; - unsigned groups = ~RTMGRP_TC; - int llink=0; - int lneigh=0; - int lmdb=0; + unsigned int groups = ~RTMGRP_TC; + int llink = 0; + int lneigh = 0; + int lmdb = 0; rtnl_close(&rth); @@ -88,7 +88,7 @@ int do_monitor(int argc, char **argv) NEXT_ARG(); file = *argv; } else if (matches(*argv, "link") == 0) { - llink=1; + llink = 1; groups = 0; } else if (matches(*argv, "fdb") == 0) { lneigh = 1; @@ -98,7 +98,7 @@ int do_monitor(int argc, char **argv) groups = 0; } else if (strcmp(*argv, "all") == 0) { groups = ~RTMGRP_TC; - prefix_banner=1; + prefix_banner = 1; } else if (matches(*argv, "help") == 0) { usage(); } else { @@ -122,6 +122,7 @@ int do_monitor(int argc, char **argv) if (file) { FILE *fp; int err; + fp = fopen(file, "r"); if (fp == NULL) { perror("Cannot fopen"); diff --git a/bridge/vlan.c b/bridge/vlan.c index ac2f52311..ae588323d 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -26,9 +26,9 @@ static void usage(void) static int vlan_modify(int cmd, int argc, char **argv) { struct { - struct nlmsghdr n; - struct ifinfomsg ifm; - char buf[1024]; + struct nlmsghdr n; + struct ifinfomsg ifm; + char buf[1024]; } req; char *d = NULL; short vid = -1; @@ -51,6 +51,7 @@ static int vlan_modify(int cmd, int argc, char **argv) d = *argv; } else if (strcmp(*argv, "vid") == 0) { char *p; + NEXT_ARG(); p = strchr(*argv, '-'); if (p) { @@ -144,7 +145,7 @@ static int print_vlan(const struct sockaddr_nl *who, FILE *fp = arg; struct ifinfomsg *ifm = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[IFLA_MAX+1]; + struct rtattr *tb[IFLA_MAX+1]; if (n->nlmsg_type != RTM_NEWLINK) { fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n", From acd1e437befbb5b7d575bb7116522cffce7495cd Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 21 Mar 2016 11:56:36 -0700 Subject: [PATCH 142/513] misc: fix style issues More checkpatch spring cleaning --- misc/arpd.c | 81 ++++++++------- misc/ifstat.c | 100 +++++++++++-------- misc/lnstat.c | 20 ++-- misc/lnstat_util.c | 6 +- misc/nstat.c | 63 ++++++++---- misc/rtacct.c | 106 ++++++++++---------- misc/ss.c | 243 ++++++++++++++++++++++++++------------------- 7 files changed, 348 insertions(+), 271 deletions(-) diff --git a/misc/arpd.c b/misc/arpd.c index 6bb9bd16b..65c03cd2b 100644 --- a/misc/arpd.c +++ b/misc/arpd.c @@ -47,17 +47,16 @@ int ifnum; int *ifvec; char **ifnames; -struct dbkey -{ +struct dbkey { __u32 iface; __u32 addr; }; -#define IS_NEG(x) (((__u8*)(x))[0] == 0xFF) +#define IS_NEG(x) (((__u8 *)(x))[0] == 0xFF) #define NEG_TIME(x) (((x)[2]<<24)|((x)[3]<<16)|((x)[4]<<8)|(x)[5]) -#define NEG_AGE(x) ((__u32)time(NULL) - NEG_TIME((__u8*)x)) +#define NEG_AGE(x) ((__u32)time(NULL) - NEG_TIME((__u8 *)x)) #define NEG_VALID(x) (NEG_AGE(x) < negative_timeout) -#define NEG_CNT(x) (((__u8*)(x))[1]) +#define NEG_CNT(x) (((__u8 *)(x))[1]) struct rtnl_handle rth; @@ -96,8 +95,7 @@ int poll_timeout = 30000; static void usage(void) { fprintf(stderr, - "Usage: arpd [ -lkh? ] [ -a N ] [ -b dbase ] [ -B number ]" - " [ -f file ] [ -n time ] [-p interval ] [ -R rate ] [ interfaces ]\n"); + "Usage: arpd [ -lkh? ] [ -a N ] [ -b dbase ] [ -B number ] [ -f file ] [ -n time ] [-p interval ] [ -R rate ] [ interfaces ]\n"); exit(1); } @@ -108,7 +106,7 @@ static int handle_if(int ifindex) if (ifnum == 0) return 1; - for (i=0; i=2 ? 1 : 3-active_probing); + sprintf(buf, "%d\n", active_probing >= 2 ? 1 : 3-active_probing); fputs(buf, fp); fclose(fp); } @@ -141,7 +139,7 @@ static void do_sysctl_adjustments(void) sprintf(buf, "/proc/sys/net/ipv4/neigh/%s/app_solicit", ifnames[i]); if ((fp = fopen(buf, "w")) != NULL) { - sprintf(buf, "%d\n", active_probing<=1 ? 1 : active_probing); + sprintf(buf, "%d\n", active_probing <= 1 ? 1 : active_probing); fputs(buf, fp); fclose(fp); } @@ -156,7 +154,7 @@ static void undo_sysctl_adjustments(void) if (!sysctl_adjusted) return; - for (i=0; iar_hrd = htons(ifr.ifr_hwaddr.sa_family); @@ -219,19 +217,19 @@ static int send_probe(int ifindex, __u32 addr) p += ah->ar_hln; memcpy(p, &dst.sin_addr, 4); - p+=4; + p += 4; sll.sll_family = AF_PACKET; memset(sll.sll_addr, 0xFF, sizeof(sll.sll_addr)); sll.sll_ifindex = ifindex; sll.sll_protocol = htons(ETH_P_ARP); memcpy(p, &sll.sll_addr, ah->ar_hln); - p+=ah->ar_hln; + p += ah->ar_hln; memcpy(p, &addr, 4); - p+=4; + p += 4; - if (sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr*)&sll, sizeof(sll)) < 0) + if (sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr *)&sll, sizeof(sll)) < 0) return -1; stats.probes_sent++; return 0; @@ -248,6 +246,7 @@ static int queue_active_probe(int ifindex, __u32 addr) gettimeofday(&now, NULL); if (prev.tv_sec) { int diff = (now.tv_sec-prev.tv_sec)*1000+(now.tv_usec-prev.tv_usec)/1000; + buckets += diff; } else { buckets = broadcast_burst; @@ -266,9 +265,9 @@ static int queue_active_probe(int ifindex, __u32 addr) static int respond_to_kernel(int ifindex, __u32 addr, char *lla, int llalen) { struct { - struct nlmsghdr n; - struct ndmsg ndm; - char buf[256]; + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; } req; memset(&req.n, 0, sizeof(req.n)); @@ -302,7 +301,7 @@ static int do_one_request(struct nlmsghdr *n) { struct ndmsg *ndm = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[NDA_MAX+1]; + struct rtattr *tb[NDA_MAX+1]; struct dbkey key; DBT dbkey, dbdat; int do_acct = 0; @@ -405,6 +404,7 @@ static int do_one_request(struct nlmsghdr *n) !IS_NEG(dbdat.data) || !NEG_VALID(dbdat.data)) { __u8 ndata[6]; + stats.kern_neg++; prepare_neg_entry(ndata, time(NULL)); dbdat.data = ndata; @@ -444,7 +444,7 @@ static void get_kern_msg(void) struct iovec iov; char buf[8192]; struct msghdr msg = { - (void*)&nladdr, sizeof(nladdr), + (void *)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 @@ -466,7 +466,7 @@ static void get_kern_msg(void) if (nladdr.nl_pid) return; - for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { + for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) { int len = h->nlmsg_len; int l = len - sizeof(*h); @@ -477,7 +477,7 @@ static void get_kern_msg(void) return; status -= NLMSG_ALIGN(len); - h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); } } @@ -487,13 +487,13 @@ static void get_arp_pkt(void) unsigned char buf[1024]; struct sockaddr_ll sll; socklen_t sll_len = sizeof(sll); - struct arphdr *a = (struct arphdr*)buf; + struct arphdr *a = (struct arphdr *)buf; struct dbkey key; DBT dbkey, dbdat; int n; n = recvfrom(pset[0].fd, buf, sizeof(buf), MSG_DONTWAIT, - (struct sockaddr*)&sll, &sll_len); + (struct sockaddr *)&sll, &sll_len); if (n < 0) { if (errno != EINTR && errno != EAGAIN) syslog(LOG_ERR, "recvfrom: %m"); @@ -515,7 +515,7 @@ static void get_arp_pkt(void) return; key.iface = sll.sll_ifindex; - memcpy(&key.addr, (char*)(a+1) + a->ar_hln, 4); + memcpy(&key.addr, (char *)(a+1) + a->ar_hln, 4); /* DAD message, ignore. */ if (key.addr == 0) @@ -600,7 +600,7 @@ int main(int argc, char **argv) while ((opt = getopt(argc, argv, "h?b:lf:a:n:p:kR:B:")) != EOF) { switch (opt) { - case 'b': + case 'b': dbname = optarg; break; case 'f': @@ -624,7 +624,7 @@ int main(int argc, char **argv) break; case 'p': if ((poll_timeout = 1000 * strtod(optarg, NULL)) < 100) { - fprintf(stderr,"Invalid poll timeout\n"); + fprintf(stderr, "Invalid poll timeout\n"); exit(-1); } break; @@ -666,15 +666,16 @@ int main(int argc, char **argv) exit(-1); } - if (ifnum) { + if (ifnum) { int i; struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); - for (i=0; iseq(dbase, &dbkey, &dbdat, R_NEXT) == 0) { struct dbkey *key = dbkey.data; + if (handle_if(key->iface)) { if (!IS_NEG(dbdat.data)) { char b1[18]; + printf("%-8d %-15s %s\n", key->iface, - inet_ntoa(*(struct in_addr*)&key->addr), + inet_ntoa(*(struct in_addr *)&key->addr), ll_addr_n2a(dbdat.data, 6, ARPHRD_ETHER, b1, 18)); } else { printf("%-8d %-15s FAILED: %dsec ago\n", key->iface, - inet_ntoa(*(struct in_addr*)&key->addr), + inet_ntoa(*(struct in_addr *)&key->addr), NEG_AGE(dbdat.data)); } } @@ -769,11 +773,12 @@ int main(int argc, char **argv) if (1) { struct sockaddr_ll sll; + memset(&sll, 0, sizeof(sll)); sll.sll_family = AF_PACKET; sll.sll_protocol = htons(ETH_P_ARP); sll.sll_ifindex = (ifnum == 1 ? ifvec[0] : 0); - if (bind(pset[0].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) { + if (bind(pset[0].fd, (struct sockaddr *)&sll, sizeof(sll)) < 0) { perror("bind"); goto do_abort; } diff --git a/misc/ifstat.c b/misc/ifstat.c index 694d9839d..abbb4e732 100644 --- a/misc/ifstat.c +++ b/misc/ifstat.c @@ -35,15 +35,15 @@ #include -int dump_zeros = 0; -int reset_history = 0; -int ignore_history = 0; -int no_output = 0; -int json_output = 0; -int no_update = 0; -int scan_interval = 0; -int time_constant = 0; -int show_errors = 0; +int dump_zeros; +int reset_history; +int ignore_history; +int no_output; +int json_output; +int no_update; +int scan_interval; +int time_constant; +int show_errors; int pretty; double W; char **patterns; @@ -54,8 +54,7 @@ int source_mismatch; #define MAXS (sizeof(struct rtnl_link_stats)/sizeof(__u32)) -struct ifstat_ent -{ +struct ifstat_ent { struct ifstat_ent *next; char *name; int ifindex; @@ -100,7 +99,7 @@ static int match(const char *id) if (npatterns == 0) return 1; - for (i=0; inlmsg_len; struct ifstat_ent *n; int i; @@ -137,7 +136,7 @@ static int get_nlmsg(const struct sockaddr_nl *who, n->name = strdup(RTA_DATA(tb[IFLA_IFNAME])); memcpy(&n->ival, RTA_DATA(tb[IFLA_STATS]), sizeof(n->ival)); memset(&n->rate, 0, sizeof(n->rate)); - for (i=0; ival[i] = n->ival[i]; n->next = kern_db; kern_db = n; @@ -209,8 +208,9 @@ static void load_raw_table(FILE *fp) n->name = strdup(p); p = next; - for (i=0; inext) { + for (n = kern_db; n; n = n->next) { int i; unsigned long long *vals = n->val; double *rates = n->rate; + if (!match(n->name)) { struct ifstat_ent *h1; + if (!to_hist) continue; for (h1 = h; h1; h1 = h1->next) { @@ -273,14 +275,14 @@ static void dump_raw_db(FILE *fp, int to_hist) jsonw_name(jw, n->name); jsonw_start_object(jw); - for (i=0; iifindex, n->name); - for (i=0; i mega) { - sprintf(temp, "%uM", (unsigned)(rates[i]/mega)); + sprintf(temp, "%uM", (unsigned int)(rates[i]/mega)); fprintf(fp, "%-6s ", temp); } else if (rates[i] > kilo) { - sprintf(temp, "%uK", (unsigned)(rates[i]/kilo)); + sprintf(temp, "%uK", (unsigned int)(rates[i]/kilo)); fprintf(fp, "%-6s ", temp); } else - fprintf(fp, "%-6u ", (unsigned)rates[i]); + fprintf(fp, "%-6u ", (unsigned int)rates[i]); } static void format_pair(FILE *fp, const unsigned long long *vals, int i, int k) { char temp[64]; + if (vals[i] > giga) fprintf(fp, "%7lluM ", vals[i]/mega); else if (vals[i] > mega) @@ -328,13 +331,13 @@ static void format_pair(FILE *fp, const unsigned long long *vals, int i, int k) fprintf(fp, "%8llu ", vals[i]); if (vals[k] > giga) { - sprintf(temp, "%uM", (unsigned)(vals[k]/mega)); + sprintf(temp, "%uM", (unsigned int)(vals[k]/mega)); fprintf(fp, "%-6s ", temp); } else if (vals[k] > mega) { - sprintf(temp, "%uK", (unsigned)(vals[k]/kilo)); + sprintf(temp, "%uK", (unsigned int)(vals[k]/kilo)); fprintf(fp, "%-6s ", temp); } else - fprintf(fp, "%-6u ", (unsigned)vals[k]); + fprintf(fp, "%-6u ", (unsigned int)vals[k]); } static void print_head(FILE *fp) @@ -345,38 +348,38 @@ static void print_head(FILE *fp) fprintf(fp, "%8s/%-6s ", "RX Pkts", "Rate"); fprintf(fp, "%8s/%-6s ", "TX Pkts", "Rate"); fprintf(fp, "%8s/%-6s ", "RX Data", "Rate"); - fprintf(fp, "%8s/%-6s\n","TX Data", "Rate"); + fprintf(fp, "%8s/%-6s\n", "TX Data", "Rate"); if (!show_errors) { fprintf(fp, "%-15s ", ""); fprintf(fp, "%8s/%-6s ", "RX Errs", "Drop"); fprintf(fp, "%8s/%-6s ", "TX Errs", "Drop"); fprintf(fp, "%8s/%-6s ", "RX Over", "Rate"); - fprintf(fp, "%8s/%-6s\n","TX Coll", "Rate"); + fprintf(fp, "%8s/%-6s\n", "TX Coll", "Rate"); } else { fprintf(fp, "%-15s ", ""); fprintf(fp, "%8s/%-6s ", "RX Errs", "Rate"); fprintf(fp, "%8s/%-6s ", "RX Drop", "Rate"); fprintf(fp, "%8s/%-6s ", "RX Over", "Rate"); - fprintf(fp, "%8s/%-6s\n","RX Leng", "Rate"); + fprintf(fp, "%8s/%-6s\n", "RX Leng", "Rate"); fprintf(fp, "%-15s ", ""); fprintf(fp, "%8s/%-6s ", "RX Crc", "Rate"); fprintf(fp, "%8s/%-6s ", "RX Frm", "Rate"); fprintf(fp, "%8s/%-6s ", "RX Fifo", "Rate"); - fprintf(fp, "%8s/%-6s\n","RX Miss", "Rate"); + fprintf(fp, "%8s/%-6s\n", "RX Miss", "Rate"); fprintf(fp, "%-15s ", ""); fprintf(fp, "%8s/%-6s ", "TX Errs", "Rate"); fprintf(fp, "%8s/%-6s ", "TX Drop", "Rate"); fprintf(fp, "%8s/%-6s ", "TX Coll", "Rate"); - fprintf(fp, "%8s/%-6s\n","TX Carr", "Rate"); + fprintf(fp, "%8s/%-6s\n", "TX Carr", "Rate"); fprintf(fp, "%-15s ", ""); fprintf(fp, "%8s/%-6s ", "TX Abrt", "Rate"); fprintf(fp, "%8s/%-6s ", "TX Fifo", "Rate"); fprintf(fp, "%8s/%-6s ", "TX Hear", "Rate"); - fprintf(fp, "%8s/%-6s\n","TX Wind", "Rate"); + fprintf(fp, "%8s/%-6s\n", "TX Wind", "Rate"); } } @@ -388,7 +391,7 @@ static void print_one_json(json_writer_t *jw, const struct ifstat_ent *n, jsonw_name(jw, n->name); jsonw_start_object(jw); - for (i=0; i < m && stats[i]; i++) + for (i = 0; i < m && stats[i]; i++) jsonw_uint_field(jw, stats[i], vals[i]); jsonw_end_object(jw); @@ -400,7 +403,7 @@ static void print_one_if(FILE *fp, const struct ifstat_ent *n, int i; fprintf(fp, "%-15s ", n->name); - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) format_rate(fp, vals, n->rate, i); fprintf(fp, "\n"); @@ -454,7 +457,7 @@ static void dump_kern_db(FILE *fp) } else print_head(fp); - for (n=kern_db; n; n=n->next) { + for (n = kern_db; n; n = n->next) { if (!match(n->name)) continue; @@ -480,7 +483,7 @@ static void dump_incr_db(FILE *fp) } else print_head(fp); - for (n=kern_db; n; n=n->next) { + for (n = kern_db; n; n = n->next) { int i; unsigned long long vals[MAXS]; struct ifstat_ent *h1; @@ -530,9 +533,11 @@ static void update_db(int interval) for (n = kern_db; n; n = n->next) { struct ifstat_ent *h1; + for (h1 = h; h1; h1 = h1->next) { if (h1->ifindex == n->ifindex) { int i; + for (i = 0; i < MAXS; i++) { if ((long)(h1->ival[i] - n->ival[i]) < 0) { memset(n->ival, 0, sizeof(n->ival)); @@ -542,6 +547,7 @@ static void update_db(int interval) for (i = 0; i < MAXS; i++) { double sample; unsigned long incr = h1->ival[i] - n->ival[i]; + n->val[i] += incr; n->ival[i] = h1->ival[i]; sample = (double)(incr*1000)/interval; @@ -552,6 +558,7 @@ static void update_db(int interval) n->rate[i] = sample; } else { double w = W*(double)interval/scan_interval; + n->rate[i] += w*(sample-n->rate[i]); } } @@ -559,6 +566,7 @@ static void update_db(int interval) while (h != h1) { struct ifstat_ent *tmp = h; + h = h->next; free(tmp->name); free(tmp); @@ -572,13 +580,14 @@ static void update_db(int interval) } } -#define T_DIFF(a,b) (((a).tv_sec-(b).tv_sec)*1000 + ((a).tv_usec-(b).tv_usec)/1000) +#define T_DIFF(a, b) (((a).tv_sec-(b).tv_sec)*1000 + ((a).tv_usec-(b).tv_usec)/1000) static void server_loop(int fd) { struct timeval snaptime = { 0 }; struct pollfd p; + p.fd = fd; p.events = p.revents = POLLIN; @@ -603,16 +612,19 @@ static void server_loop(int fd) if (poll(&p, 1, scan_interval - tdiff) > 0 && (p.revents&POLLIN)) { int clnt = accept(fd, NULL, NULL); + if (clnt >= 0) { pid_t pid; + if (children >= 5) { close(clnt); } else if ((pid = fork()) != 0) { - if (pid>0) + if (pid > 0) children++; close(clnt); } else { FILE *fp = fdopen(clnt, "w"); + if (fp) dump_raw_db(fp, 0); exit(0); @@ -629,7 +641,7 @@ static int verify_forging(int fd) struct ucred cred; socklen_t olen = sizeof(cred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, (void*)&cred, &olen) || + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &olen) || olen < sizeof(cred)) return -1; if (cred.uid == getuid() || cred.uid == 0) @@ -685,7 +697,7 @@ int main(int argc, char *argv[]) while ((ch = getopt_long(argc, argv, "hjpvVzrnasd:t:e", longopts, NULL)) != EOF) { - switch(ch) { + switch (ch) { case 'z': dump_zeros = 1; break; @@ -751,7 +763,7 @@ int main(int argc, char *argv[]) perror("ifstat: socket"); exit(-1); } - if (bind(fd, (struct sockaddr*)&sun, 2+1+strlen(sun.sun_path+1)) < 0) { + if (bind(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) < 0) { perror("ifstat: bind"); exit(-1); } @@ -809,6 +821,7 @@ int main(int argc, char *argv[]) if (!ignore_history) { FILE *tfp; long uptime = -1; + if ((tfp = fopen("/proc/uptime", "r")) != NULL) { if (fscanf(tfp, "%ld", &uptime) != 1) uptime = -1; @@ -828,11 +841,12 @@ int main(int argc, char *argv[]) } if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0 && - (connect(fd, (struct sockaddr*)&sun, 2+1+strlen(sun.sun_path+1)) == 0 + (connect(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) == 0 || (strcpy(sun.sun_path+1, "ifstat0"), - connect(fd, (struct sockaddr*)&sun, 2+1+strlen(sun.sun_path+1)) == 0)) + connect(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) == 0)) && verify_forging(fd) == 0) { FILE *sfp = fdopen(fd, "r"); + load_raw_table(sfp); if (hist_db && source_mismatch) { fprintf(stderr, "ifstat: history is stale, ignoring it.\n"); diff --git a/misc/lnstat.c b/misc/lnstat.c index 264c9531a..659a01bd6 100644 --- a/misc/lnstat.c +++ b/misc/lnstat.c @@ -56,10 +56,8 @@ static struct option opts[] = { static int usage(char *name, int exit_code) { fprintf(stderr, "%s Version %s\n", name, LNSTAT_VERSION); - fprintf(stderr, "Copyright (C) 2004 by Harald Welte " - "\n"); - fprintf(stderr, "This program is free software licensed under GNU GPLv2" - "\nwith ABSOLUTELY NO WARRANTY.\n\n"); + fprintf(stderr, "Copyright (C) 2004 by Harald Welte \n"); + fprintf(stderr, "This program is free software licensed under GNU GPLv2\nwith ABSOLUTELY NO WARRANTY.\n\n"); fprintf(stderr, "Parameters:\n"); fprintf(stderr, "\t-V --version\t\tPrint Version of Program\n"); fprintf(stderr, "\t-c --count \t" @@ -145,14 +143,13 @@ static int map_field_params(struct lnstat_file *lnstat_files, if (++j >= MAX_FIELDS - 1) { fprintf(stderr, - "WARN: MAX_FIELDS (%d) reached," - " truncating number of keys\n", + "WARN: MAX_FIELDS (%d) reached, truncating number of keys\n", MAX_FIELDS); goto full; } } } - full: +full: fps->num = j; return 1; } @@ -181,7 +178,7 @@ static struct table_hdr *build_hdr_string(struct lnstat_file *lnstat_files, struct field_params *fps, int linewidth) { - int h,i; + int h, i; static struct table_hdr th; int ofs = 0; @@ -269,7 +266,7 @@ int main(int argc, char **argv) num_req_files = 1; } - while ((c = getopt_long(argc, argv,"Vc:djpf:h?i:k:s:w:", + while ((c = getopt_long(argc, argv, "Vc:djpf:h?i:k:s:w:", opts, NULL)) != -1) { int len = 0; char *tmp, *tok; @@ -303,8 +300,7 @@ int main(int argc, char **argv) tok = strtok(NULL, ",")) { if (fp.num >= MAX_FIELDS) { fprintf(stderr, - "WARN: too many keys" - " requested: (%d max)\n", + "WARN: too many keys requested: (%d max)\n", MAX_FIELDS); break; } @@ -356,7 +352,7 @@ int main(int argc, char **argv) if (!header) exit(1); - if (interval < 1 ) + if (interval < 1) interval = 1; for (i = 0; i < count || !count; i++) { diff --git a/misc/lnstat_util.c b/misc/lnstat_util.c index a25836657..d91815128 100644 --- a/misc/lnstat_util.c +++ b/misc/lnstat_util.c @@ -49,7 +49,7 @@ static int scan_lines(struct lnstat_file *lf, int i) if (!lf->compat && !fgets(buf, sizeof(buf)-1, lf->fp)) return -1; - while(!feof(lf->fp) && fgets(buf, sizeof(buf)-1, lf->fp)) { + while (!feof(lf->fp) && fgets(buf, sizeof(buf)-1, lf->fp)) { char *ptr = buf; num_lines++; @@ -58,6 +58,7 @@ static int scan_lines(struct lnstat_file *lf, int i) for (j = 0; j < lf->num_fields; j++) { unsigned long f = strtoul(ptr, &ptr, 16); + if (j == 0) lf->fields[j].values[i] = f; else @@ -102,7 +103,7 @@ int lnstat_update(struct lnstat_file *lnstat_files) lfi->result = lfi->values[1]; else lfi->result = (lfi->values[1]-lfi->values[0]) - / lf->interval.tv_sec; + / lf->interval.tv_sec; } scan_lines(lf, 0); @@ -158,6 +159,7 @@ static int lnstat_scan_compat_rtstat_fields(struct lnstat_file *lf) static int name_in_array(const int num, const char **arr, const char *name) { int i; + for (i = 0; i < num; i++) { if (!strcmp(arr[i], name)) return 1; diff --git a/misc/nstat.c b/misc/nstat.c index 22b27eba7..a9e0f2078 100644 --- a/misc/nstat.c +++ b/misc/nstat.c @@ -31,15 +31,15 @@ #include #include -int dump_zeros = 0; -int reset_history = 0; -int ignore_history = 0; -int no_output = 0; -int json_output = 0; -int pretty = 0; -int no_update = 0; -int scan_interval = 0; -int time_constant = 0; +int dump_zeros; +int reset_history; +int ignore_history; +int no_output; +int json_output; +int pretty; +int no_update; +int scan_interval; +int time_constant; double W; char **patterns; int npatterns; @@ -51,6 +51,7 @@ static int generic_proc_open(const char *env, char *name) { char store[128]; char *p = getenv(env); + if (!p) { p = getenv("PROC_ROOT") ? : "/proc"; snprintf(store, sizeof(store)-1, "%s/%s", p, name); @@ -74,8 +75,7 @@ static int net_snmp6_open(void) return generic_proc_open("PROC_NET_SNMP6", "net/snmp6"); } -struct nstat_ent -{ +struct nstat_ent { struct nstat_ent *next; char *id; unsigned long long val; @@ -94,7 +94,8 @@ static const char *useless_numbers[] = { static int useless_number(const char *id) { int i; - for (i=0; inext) { + for (n = kern_db; n; n = n->next) { unsigned long long val = n->val; + if (!dump_zeros && !val && !n->rate) continue; if (!match(n->id)) { struct nstat_ent *h1; + if (!to_hist) continue; for (h1 = h; h1; h1 = h1->next) { @@ -326,10 +334,11 @@ static void dump_incr_db(FILE *fp) } else fprintf(fp, "#%s\n", info_source); - for (n=kern_db; n; n=n->next) { + for (n = kern_db; n; n = n->next) { int ovfl = 0; unsigned long long val = n->val; struct nstat_ent *h1; + for (h1 = h; h1; h1 = h1->next) { if (strcmp(h1->id, n->id) == 0) { if (val < h1->val) { @@ -381,6 +390,7 @@ static void update_db(int interval) for (n = kern_db; n; n = n->next) { struct nstat_ent *h1; + for (h1 = h; h1; h1 = h1->next) { if (strcmp(h1->id, n->id) == 0) { double sample; @@ -395,12 +405,14 @@ static void update_db(int interval) n->rate = sample; } else { double w = W*(double)interval/scan_interval; + n->rate += w*(sample-n->rate); } } while (h != h1) { struct nstat_ent *tmp = h; + h = h->next; free(tmp->id); free(tmp); @@ -414,13 +426,14 @@ static void update_db(int interval) } } -#define T_DIFF(a,b) (((a).tv_sec-(b).tv_sec)*1000 + ((a).tv_usec-(b).tv_usec)/1000) +#define T_DIFF(a, b) (((a).tv_sec-(b).tv_sec)*1000 + ((a).tv_usec-(b).tv_usec)/1000) static void server_loop(int fd) { struct timeval snaptime = { 0 }; struct pollfd p; + p.fd = fd; p.events = p.revents = POLLIN; @@ -435,6 +448,7 @@ static void server_loop(int fd) int status; time_t tdiff; struct timeval now; + gettimeofday(&now, NULL); tdiff = T_DIFF(now, snaptime); if (tdiff >= scan_interval) { @@ -445,16 +459,19 @@ static void server_loop(int fd) if (poll(&p, 1, scan_interval - tdiff) > 0 && (p.revents&POLLIN)) { int clnt = accept(fd, NULL, NULL); + if (clnt >= 0) { pid_t pid; + if (children >= 5) { close(clnt); } else if ((pid = fork()) != 0) { - if (pid>0) + if (pid > 0) children++; close(clnt); } else { FILE *fp = fdopen(clnt, "w"); + if (fp) dump_kern_db(fp, 0); exit(0); @@ -471,7 +488,7 @@ static int verify_forging(int fd) struct ucred cred; socklen_t olen = sizeof(cred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, (void*)&cred, &olen) || + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &olen) || olen < sizeof(cred)) return -1; if (cred.uid == getuid() || cred.uid == 0) @@ -524,7 +541,7 @@ int main(int argc, char *argv[]) while ((ch = getopt_long(argc, argv, "h?vVzrnasd:t:jp", longopts, NULL)) != EOF) { - switch(ch) { + switch (ch) { case 'z': dump_zeros = 1; break; @@ -583,7 +600,7 @@ int main(int argc, char *argv[]) perror("nstat: socket"); exit(-1); } - if (bind(fd, (struct sockaddr*)&sun, 2+1+strlen(sun.sun_path+1)) < 0) { + if (bind(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) < 0) { perror("nstat: bind"); exit(-1); } @@ -639,6 +656,7 @@ int main(int argc, char *argv[]) if (!ignore_history) { FILE *tfp; long uptime = -1; + if ((tfp = fopen("/proc/uptime", "r")) != NULL) { if (fscanf(tfp, "%ld", &uptime) != 1) uptime = -1; @@ -658,11 +676,12 @@ int main(int argc, char *argv[]) } if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0 && - (connect(fd, (struct sockaddr*)&sun, 2+1+strlen(sun.sun_path+1)) == 0 + (connect(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) == 0 || (strcpy(sun.sun_path+1, "nstat0"), - connect(fd, (struct sockaddr*)&sun, 2+1+strlen(sun.sun_path+1)) == 0)) + connect(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) == 0)) && verify_forging(fd) == 0) { FILE *sfp = fdopen(fd, "r"); + load_good_table(sfp); if (hist_db && source_mismatch) { fprintf(stderr, "nstat: history is stale, ignoring it.\n"); diff --git a/misc/rtacct.c b/misc/rtacct.c index bb8c90f98..b1cb37881 100644 --- a/misc/rtacct.c +++ b/misc/rtacct.c @@ -33,20 +33,21 @@ #include -int reset_history = 0; -int ignore_history = 0; -int no_output = 0; -int no_update = 0; -int scan_interval = 0; -int time_constant = 0; -int dump_zeros = 0; -unsigned long magic_number = 0; +int reset_history; +int ignore_history; +int no_output; +int no_update; +int scan_interval; +int time_constant; +int dump_zeros; +unsigned long magic_number; double W; static int generic_proc_open(const char *env, const char *name) { char store[1024]; char *p = getenv(env); + if (!p) { p = getenv("PROC_ROOT") ? : "/proc"; snprintf(store, sizeof(store)-1, "%s/%s", p, name); @@ -62,8 +63,7 @@ static int net_rtacct_open(void) static __u32 rmap[256/4]; -struct rtacct_data -{ +struct rtacct_data { __u32 ival[256*4]; unsigned long long val[256*4]; @@ -82,6 +82,7 @@ static void nread(int fd, char *buf, int tot) while (count < tot) { int n = read(fd, buf+count, tot-count); + if (n < 0) { if (errno == EINTR) continue; @@ -121,7 +122,7 @@ static __u32 *read_kern_table(__u32 *tbl) fd = net_rtacct_open(); if (fd >= 0) { - nread(fd, (char*)tbl, 256*16); + nread(fd, (char *)tbl, 256*16); close(fd); } else { memset(tbl, 0, 256*16); @@ -134,13 +135,13 @@ static void format_rate(FILE *fp, double rate) char temp[64]; if (rate > 1024*1024) { - sprintf(temp, "%uM", (unsigned)rint(rate/(1024*1024))); + sprintf(temp, "%uM", (unsigned int)rint(rate/(1024*1024))); fprintf(fp, " %-10s", temp); } else if (rate > 1024) { - sprintf(temp, "%uK", (unsigned)rint(rate/1024)); + sprintf(temp, "%uK", (unsigned int)rint(rate/1024)); fprintf(fp, " %-10s", temp); } else - fprintf(fp, " %-10u", (unsigned)rate); + fprintf(fp, " %-10u", (unsigned int)rate); } static void format_count(FILE *fp, unsigned long long val) @@ -161,25 +162,19 @@ static void dump_abs_db(FILE *fp) if (!no_output) { fprintf(fp, "#%s\n", kern_db->signature); fprintf(fp, -"%-10s " -"%-10s " -"%-10s " -"%-10s " -"%-10s " -"\n" +"%-10s %-10s " +"%-10s %-10s " +"%-10s \n" , "Realm", "BytesTo", "PktsTo", "BytesFrom", "PktsFrom"); fprintf(fp, -"%-10s " -"%-10s " -"%-10s " -"%-10s " -"%-10s " -"\n" +"%-10s %-10s " +"%-10s %-10s " +"%-10s \n" , "", "BPSTo", "PPSTo", "BPSFrom", "PPSFrom"); } - for (realm=0; realm<256; realm++) { + for (realm = 0; realm < 256; realm++) { int i; unsigned long long *val; double *rate; @@ -223,24 +218,18 @@ static void dump_incr_db(FILE *fp) if (!no_output) { fprintf(fp, "#%s\n", kern_db->signature); fprintf(fp, -"%-10s " -"%-10s " -"%-10s " -"%-10s " -"%-10s " -"\n" +"%-10s %-10s " +"%-10s %-10s " +"%-10s \n" , "Realm", "BytesTo", "PktsTo", "BytesFrom", "PktsFrom"); fprintf(fp, -"%-10s " -"%-10s " -"%-10s " -"%-10s " -"%-10s " -"\n" +"%-10s %-10s " +"%-10s %-10s " +"%-10s \n" , "", "BPSTo", "PPSTo", "BPSFrom", "PPSFrom"); } - for (realm=0; realm<256; realm++) { + for (realm = 0; realm < 256; realm++) { int ovfl = 0; int i; unsigned long long *val; @@ -253,7 +242,7 @@ static void dump_incr_db(FILE *fp) val = &kern_db->val[realm*4]; rate = &kern_db->rate[realm*4]; - for (k=0; k<4; k++) { + for (k = 0; k < 4; k++) { rval[k] = val[k]; if (rval[k] < hist_db->val[realm*4+k]) ovfl = 1; @@ -261,7 +250,7 @@ static void dump_incr_db(FILE *fp) rval[k] -= hist_db->val[realm*4+k]; } if (ovfl) { - for (k=0; k<4; k++) + for (k = 0; k < 4; k++) rval[k] = val[k]; } if (hist_db) { @@ -306,7 +295,7 @@ static void update_db(int interval) ival = read_kern_table(_ival); - for (i=0; i<256*4; i++) { + for (i = 0; i < 256*4; i++) { double sample; __u32 incr = ival[i] - kern_db->ival[i]; @@ -324,6 +313,7 @@ static void update_db(int interval) kern_db->rate[i] = sample; } else { double w = W*(double)interval/scan_interval; + kern_db->rate[i] += w*(sample-kern_db->rate[i]); } } @@ -335,7 +325,8 @@ static void send_db(int fd) int tot = 0; while (tot < sizeof(*kern_db)) { - int n = write(fd, ((char*)kern_db) + tot, sizeof(*kern_db)-tot); + int n = write(fd, ((char *)kern_db) + tot, sizeof(*kern_db)-tot); + if (n < 0) { if (errno == EINTR) continue; @@ -347,16 +338,17 @@ static void send_db(int fd) -#define T_DIFF(a,b) (((a).tv_sec-(b).tv_sec)*1000 + ((a).tv_usec-(b).tv_usec)/1000) +#define T_DIFF(a, b) (((a).tv_sec-(b).tv_sec)*1000 + ((a).tv_usec-(b).tv_usec)/1000) static void pad_kern_table(struct rtacct_data *dat, __u32 *ival) { int i; + memset(dat->rate, 0, sizeof(dat->rate)); if (dat->ival != ival) memcpy(dat->ival, ival, sizeof(dat->ival)); - for (i=0; i<256*4; i++) + for (i = 0; i < 256*4; i++) dat->val[i] = ival[i]; } @@ -364,12 +356,13 @@ static void server_loop(int fd) { struct timeval snaptime = { 0 }; struct pollfd p; + p.fd = fd; p.events = p.revents = POLLIN; sprintf(kern_db->signature, "%u.%lu sampling_interval=%d time_const=%d", - (unsigned) getpid(), (unsigned long)random(), + (unsigned int) getpid(), (unsigned long)random(), scan_interval/1000, time_constant/1000); pad_kern_table(kern_db, read_kern_table(kern_db->ival)); @@ -378,6 +371,7 @@ static void server_loop(int fd) int status; int tdiff; struct timeval now; + gettimeofday(&now, NULL); tdiff = T_DIFF(now, snaptime); if (tdiff >= scan_interval) { @@ -388,12 +382,14 @@ static void server_loop(int fd) if (poll(&p, 1, tdiff + scan_interval) > 0 && (p.revents&POLLIN)) { int clnt = accept(fd, NULL, NULL); + if (clnt >= 0) { pid_t pid; + if (children >= 5) { close(clnt); } else if ((pid = fork()) != 0) { - if (pid>0) + if (pid > 0) children++; close(clnt); } else { @@ -414,7 +410,7 @@ static int verify_forging(int fd) struct ucred cred; socklen_t olen = sizeof(cred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, (void*)&cred, &olen) || + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &olen) || olen < sizeof(cred)) return -1; if (cred.uid == getuid() || cred.uid == 0) @@ -440,7 +436,7 @@ int main(int argc, char *argv[]) int fd; while ((ch = getopt(argc, argv, "h?vVzrM:nasd:t:")) != EOF) { - switch(ch) { + switch (ch) { case 'z': dump_zeros = 1; break; @@ -489,6 +485,7 @@ int main(int argc, char *argv[]) if (argc) { while (argc > 0) { __u32 realm; + if (rtnl_rtrealm_a2n(&realm, argv[0])) { fprintf(stderr, "Warning: realm \"%s\" does not exist.\n", argv[0]); exit(-1); @@ -515,7 +512,7 @@ int main(int argc, char *argv[]) perror("rtacct: socket"); exit(-1); } - if (bind(fd, (struct sockaddr*)&sun, 2+1+strlen(sun.sun_path+1)) < 0) { + if (bind(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) < 0) { perror("rtacct: bind"); exit(-1); } @@ -580,6 +577,7 @@ int main(int argc, char *argv[]) if (!ignore_history) { FILE *tfp; long uptime = -1; + if ((tfp = fopen("/proc/uptime", "r")) != NULL) { if (fscanf(tfp, "%ld", &uptime) != 1) uptime = -1; @@ -596,11 +594,11 @@ int main(int argc, char *argv[]) } if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0 && - (connect(fd, (struct sockaddr*)&sun, 2+1+strlen(sun.sun_path+1)) == 0 + (connect(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) == 0 || (strcpy(sun.sun_path+1, "rtacct0"), - connect(fd, (struct sockaddr*)&sun, 2+1+strlen(sun.sun_path+1)) == 0)) + connect(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) == 0)) && verify_forging(fd) == 0) { - nread(fd, (char*)kern_db, sizeof(*kern_db)); + nread(fd, (char *)kern_db, sizeof(*kern_db)); if (hist_db && hist_db->signature[0] && strcmp(kern_db->signature, hist_db->signature)) { fprintf(stderr, "rtacct: history is stale, ignoring it.\n"); diff --git a/misc/ss.c b/misc/ss.c index f0f590263..192389cc8 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -86,20 +86,20 @@ static int security_get_initial_context(char *name, char **context) } #endif -int resolve_hosts = 0; +int resolve_hosts; int resolve_services = 1; int preferred_family = AF_UNSPEC; -int show_options = 0; -int show_details = 0; -int show_users = 0; -int show_mem = 0; -int show_tcpinfo = 0; -int show_bpf = 0; -int show_proc_ctx = 0; -int show_sock_ctx = 0; +int show_options; +int show_details; +int show_users; +int show_mem; +int show_tcpinfo; +int show_bpf; +int show_proc_ctx; +int show_sock_ctx; /* If show_users & show_proc_ctx only do user_ent_hash_build() once */ -int user_ent_hash_build_init = 0; -int follow_events = 0; +int user_ent_hash_build_init; +int follow_events; int netid_width; int state_width; @@ -111,10 +111,9 @@ int screen_width; static const char *TCP_PROTO = "tcp"; static const char *UDP_PROTO = "udp"; static const char *RAW_PROTO = "raw"; -static const char *dg_proto = NULL; +static const char *dg_proto; -enum -{ +enum { TCP_DB, DCCP_DB, UDP_DB, @@ -154,8 +153,7 @@ enum { #include "ssfilter.h" -struct filter -{ +struct filter { int dbs; int states; int families; @@ -551,7 +549,7 @@ enum entry_types { }; #define ENTRY_BUF_SIZE 512 -static int find_entry(unsigned ino, char **buf, int type) +static int find_entry(unsigned int ino, char **buf, int type) { struct user_ent *p; int cnt = 0; @@ -624,8 +622,7 @@ static int find_entry(unsigned ino, char **buf, int type) /* Get stats from slab */ -struct slabstat -{ +struct slabstat { int socks; int tcp_ports; int tcp_tws; @@ -635,8 +632,8 @@ struct slabstat static struct slabstat slabstat; -static const char *slabstat_ids[] = -{ +static const char *slabstat_ids[] = { + "sock", "tcp_bind_bucket", "tcp_tw_bucket", @@ -666,9 +663,10 @@ static int get_slabstat(struct slabstat *s) fclose(fp); return -1; } - while(fgets(buf, sizeof(buf), fp) != NULL) { + while (fgets(buf, sizeof(buf), fp) != NULL) { int i; - for (i=0; idata[0] == 0 && a->data[1] == 0 && a->data[2] == htonl(0xffff)) { inet_prefix tmp = *a; + tmp.data[0] = a->data[3]; return inet_addr_match(&tmp, p, plen); } @@ -1071,6 +1068,7 @@ static int inet2_addr_match(const inet_prefix *a, const inet_prefix *p, static int unix_match(const inet_prefix *a, const inet_prefix *p) { char *addr, *pattern; + memcpy(&addr, a->data, sizeof(addr)); memcpy(&pattern, p->data, sizeof(pattern)); if (pattern == NULL) @@ -1087,6 +1085,7 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s) { if (s->local.family == AF_UNIX) { char *p; + memcpy(&p, s->local.data, sizeof(p)); return p == NULL || (p[0] == '@' && strlen(p) == 6 && strspn(p+1, "0123456789abcdef") == 5); @@ -1100,7 +1099,8 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s) } case SSF_DCOND: { - struct aafilter *a = (void*)f->pred; + struct aafilter *a = (void *)f->pred; + if (a->addr.family == AF_UNIX) return unix_match(&s->remote, &a->addr); if (a->port != -1 && a->port != s->rport) @@ -1116,7 +1116,8 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s) } case SSF_SCOND: { - struct aafilter *a = (void*)f->pred; + struct aafilter *a = (void *)f->pred; + if (a->addr.family == AF_UNIX) return unix_match(&s->local, &a->addr); if (a->port != -1 && a->port != s->lport) @@ -1132,22 +1133,26 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s) } case SSF_D_GE: { - struct aafilter *a = (void*)f->pred; + struct aafilter *a = (void *)f->pred; + return s->rport >= a->port; } case SSF_D_LE: { - struct aafilter *a = (void*)f->pred; + struct aafilter *a = (void *)f->pred; + return s->rport <= a->port; } case SSF_S_GE: { - struct aafilter *a = (void*)f->pred; + struct aafilter *a = (void *)f->pred; + return s->lport >= a->port; } case SSF_S_LE: { - struct aafilter *a = (void*)f->pred; + struct aafilter *a = (void *)f->pred; + return s->lport <= a->port; } @@ -1167,7 +1172,8 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s) static void ssfilter_patch(char *a, int len, int reloc) { while (len > 0) { - struct inet_diag_bc_op *op = (struct inet_diag_bc_op*)a; + struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)a; + if (op->no == len+4) op->no += reloc; len -= op->yes; @@ -1182,20 +1188,20 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) switch (f->type) { case SSF_S_AUTO: { - if (!(*bytecode=malloc(4))) abort(); - ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_AUTO, 4, 8 }; + if (!(*bytecode = malloc(4))) abort(); + ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_AUTO, 4, 8 }; return 4; } case SSF_DCOND: case SSF_SCOND: { - struct aafilter *a = (void*)f->pred; + struct aafilter *a = (void *)f->pred; struct aafilter *b; char *ptr; int code = (f->type == SSF_DCOND ? INET_DIAG_BC_D_COND : INET_DIAG_BC_S_COND); int len = 0; - for (b=a; b; b=b->next) { + for (b = a; b; b = b->next) { len += 4 + sizeof(struct inet_diag_hostcond); if (a->addr.family == AF_INET6) len += 16; @@ -1206,11 +1212,11 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) } if (!(ptr = malloc(len))) abort(); *bytecode = ptr; - for (b=a; b; b=b->next) { + for (b = a; b; b = b->next) { struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)ptr; int alen = (a->addr.family == AF_INET6 ? 16 : 4); int oplen = alen + 4 + sizeof(struct inet_diag_hostcond); - struct inet_diag_hostcond *cond = (struct inet_diag_hostcond*)(ptr+4); + struct inet_diag_hostcond *cond = (struct inet_diag_hostcond *)(ptr+4); *op = (struct inet_diag_bc_op){ code, oplen, oplen+4 }; cond->family = a->addr.family; @@ -1228,34 +1234,38 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) } case SSF_D_GE: { - struct aafilter *x = (void*)f->pred; - if (!(*bytecode=malloc(8))) abort(); - ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_GE, 8, 12 }; - ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port }; + struct aafilter *x = (void *)f->pred; + + if (!(*bytecode = malloc(8))) abort(); + ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_GE, 8, 12 }; + ((struct inet_diag_bc_op *)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port }; return 8; } case SSF_D_LE: { - struct aafilter *x = (void*)f->pred; - if (!(*bytecode=malloc(8))) abort(); - ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_LE, 8, 12 }; - ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port }; + struct aafilter *x = (void *)f->pred; + + if (!(*bytecode = malloc(8))) abort(); + ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_LE, 8, 12 }; + ((struct inet_diag_bc_op *)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port }; return 8; } case SSF_S_GE: { - struct aafilter *x = (void*)f->pred; - if (!(*bytecode=malloc(8))) abort(); - ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_GE, 8, 12 }; - ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port }; + struct aafilter *x = (void *)f->pred; + + if (!(*bytecode = malloc(8))) abort(); + ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_GE, 8, 12 }; + ((struct inet_diag_bc_op *)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port }; return 8; } case SSF_S_LE: { - struct aafilter *x = (void*)f->pred; - if (!(*bytecode=malloc(8))) abort(); - ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_LE, 8, 12 }; - ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port }; + struct aafilter *x = (void *)f->pred; + + if (!(*bytecode = malloc(8))) abort(); + ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_LE, 8, 12 }; + ((struct inet_diag_bc_op *)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port }; return 8; } @@ -1263,6 +1273,7 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) { char *a1, *a2, *a; int l1, l2; + l1 = ssfilter_bytecompile(f->pred, &a1); l2 = ssfilter_bytecompile(f->post, &a2); if (!(a = malloc(l1+l2))) abort(); @@ -1277,13 +1288,14 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) { char *a1, *a2, *a; int l1, l2; + l1 = ssfilter_bytecompile(f->pred, &a1); l2 = ssfilter_bytecompile(f->post, &a2); if (!(a = malloc(l1+l2+4))) abort(); memcpy(a, a1, l1); memcpy(a+l1+4, a2, l2); free(a1); free(a2); - *(struct inet_diag_bc_op*)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, l2+4 }; + *(struct inet_diag_bc_op *)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, l2+4 }; *bytecode = a; return l1+l2+4; } @@ -1291,11 +1303,12 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) { char *a1, *a; int l1; + l1 = ssfilter_bytecompile(f->pred, &a1); if (!(a = malloc(l1+4))) abort(); memcpy(a, a1, l1); free(a1); - *(struct inet_diag_bc_op*)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, 8 }; + *(struct inet_diag_bc_op *)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, 8 }; *bytecode = a; return l1+4; } @@ -1319,6 +1332,7 @@ static int remember_he(struct aafilter *a, struct hostent *he) while (*ptr) { struct aafilter *b = a; + if (a->addr.bitlen) { if ((b = malloc(sizeof(*b))) == NULL) return cnt; @@ -1358,11 +1372,12 @@ static int get_dns_host(struct aafilter *a, const char *addr, int fam) return !cnt; } -static int xll_initted = 0; +static int xll_initted; static void xll_init(void) { struct rtnl_handle rth; + if (rtnl_open(&rth, 0) < 0) exit(1); @@ -1395,9 +1410,10 @@ void *parse_hostcond(char *addr, bool is_port) if (fam == AF_UNIX || strncmp(addr, "unix:", 5) == 0) { char *p; + a.addr.family = AF_UNIX; if (strncmp(addr, "unix:", 5) == 0) - addr+=5; + addr += 5; p = strdup(addr); a.addr.bitlen = 8*strlen(p); memcpy(a.addr.data, &p, sizeof(p)); @@ -1409,7 +1425,7 @@ void *parse_hostcond(char *addr, bool is_port) a.addr.family = AF_PACKET; a.addr.bitlen = 0; if (strncmp(addr, "link:", 5) == 0) - addr+=5; + addr += 5; port = strchr(addr, ':'); if (port) { *port = 0; @@ -1422,6 +1438,7 @@ void *parse_hostcond(char *addr, bool is_port) } if (addr[0] && strcmp(addr, "*")) { unsigned short tmp; + a.addr.bitlen = 32; if (ll_proto_a2n(&tmp, addr)) return NULL; @@ -1435,7 +1452,7 @@ void *parse_hostcond(char *addr, bool is_port) a.addr.family = AF_NETLINK; a.addr.bitlen = 0; if (strncmp(addr, "netlink:", 8) == 0) - addr+=8; + addr += 8; port = strchr(addr, ':'); if (port) { *port = 0; @@ -1490,6 +1507,7 @@ void *parse_hostcond(char *addr, bool is_port) if (get_integer(&a.port, port, 0)) { struct servent *se1 = NULL; struct servent *se2 = NULL; + if (current_filter.dbs&(1<s_port); } else { struct scache *s; + for (s = rlist; s; s = s->next) { if ((s->proto == UDP_PROTO && (current_filter.dbs&(1<local.family = s->remote.family = family; if (family == AF_INET) { - sscanf(loc, "%x:%x", s->local.data, (unsigned*)&s->lport); - sscanf(rem, "%x:%x", s->remote.data, (unsigned*)&s->rport); + sscanf(loc, "%x:%x", s->local.data, (unsigned *)&s->lport); + sscanf(rem, "%x:%x", s->remote.data, (unsigned *)&s->rport); s->local.bytelen = s->remote.bytelen = 4; return 0; } else { @@ -1640,9 +1659,9 @@ static int proc_inet_split_line(char *line, char **loc, char **rem, char **data) static char *sprint_bw(char *buf, double bw) { if (bw > 1000000.) - sprintf(buf,"%.1fM", bw / 1000000.); + sprintf(buf, "%.1fM", bw / 1000000.); else if (bw > 1000.) - sprintf(buf,"%.1fK", bw / 1000.); + sprintf(buf, "%.1fK", bw / 1000.); else sprintf(buf, "%g", bw); @@ -1770,6 +1789,7 @@ static int tcp_show_line(char *line, const struct filter *f, int family) return -1; int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0'); + if (!(f->states & (1 << state))) return 0; @@ -1833,6 +1853,7 @@ static int generic_record_read(FILE *fp, while (fgets(line, sizeof(line), fp) != NULL) { int n = strlen(line); + if (n == 0 || line[n-1] != '\n') { errno = -EINVAL; return -1; @@ -2005,11 +2026,11 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol) { - struct rtattr * tb[INET_DIAG_MAX+1]; + struct rtattr *tb[INET_DIAG_MAX+1]; struct inet_diag_msg *r = NLMSG_DATA(nlh); struct sockstat s = {}; - parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr*)(r+1), + parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr *)(r+1), nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); s.state = r->idiag_state; @@ -2053,11 +2074,13 @@ static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol) sock_details_print(&s); if (s.local.family == AF_INET6 && tb[INET_DIAG_SKV6ONLY]) { unsigned char v6only; + v6only = *(__u8 *)RTA_DATA(tb[INET_DIAG_SKV6ONLY]); printf(" v6only:%u", v6only); } if (tb[INET_DIAG_SHUTDOWN]) { unsigned char mask; + mask = *(__u8 *)RTA_DATA(tb[INET_DIAG_SHUTDOWN]); printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>'); } @@ -2127,7 +2150,7 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f) } msg = (struct msghdr) { - .msg_name = (void*)&nladdr, + .msg_name = (void *)&nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = iov, .msg_iovlen = f->f ? 3 : 1, @@ -2144,6 +2167,7 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f) static int sockdiag_send(int family, int fd, int protocol, struct filter *f) { struct sockaddr_nl nladdr; + DIAG_REQUEST(req, struct inet_diag_req_v2 r); char *bc = NULL; int bclen; @@ -2186,7 +2210,7 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f) } msg = (struct msghdr) { - .msg_name = (void*)&nladdr, + .msg_name = (void *)&nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = iov, .msg_iovlen = f->f ? 3 : 1, @@ -2212,6 +2236,7 @@ static int kill_inet_sock(const struct sockaddr_nl *addr, struct inet_diag_msg *d = NLMSG_DATA(h); struct inet_diag_arg *diag_arg = arg; struct rtnl_handle *rth = diag_arg->rth; + DIAG_REQUEST(req, struct inet_diag_req_v2 r); req.nlh.nlmsg_type = SOCK_DESTROY; @@ -2306,7 +2331,7 @@ static int tcp_show_netlink_file(struct filter *f) while (1) { int status, err; - struct nlmsghdr *h = (struct nlmsghdr*)buf; + struct nlmsghdr *h = (struct nlmsghdr *)buf; status = fread(buf, 1, sizeof(*h), fp); if (status < 0) { @@ -2334,7 +2359,8 @@ static int tcp_show_netlink_file(struct filter *f) return 0; if (h->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h); + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { fprintf(stderr, "ERROR truncated\n"); } else { @@ -2381,6 +2407,7 @@ static int tcp_show(struct filter *f, int socktype) get_slabstat(&slabstat); int guess = slabstat.socks+slabstat.tcp_syns; + if (f->states&(1< (16*1024*1024)/128) @@ -2423,6 +2450,7 @@ static int tcp_show(struct filter *f, int socktype) outerr: do { int saved_errno = errno; + free(buf); if (fp) fclose(fp); @@ -2443,6 +2471,7 @@ static int dgram_show_line(char *line, const struct filter *f, int family) return -1; int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0'); + if (!(f->states & (1 << state))) return 0; @@ -2501,6 +2530,7 @@ static int udp_show(struct filter *f) outerr: do { int saved_errno = errno; + if (fp) fclose(fp); errno = saved_errno; @@ -2536,6 +2566,7 @@ static int raw_show(struct filter *f) outerr: do { int saved_errno = errno; + if (fp) fclose(fp); errno = saved_errno; @@ -2629,6 +2660,7 @@ static void unix_stats_print(struct sockstat *list, struct filter *f) if (use_proc && f->f) { struct sockstat st; + st.local.family = AF_UNIX; st.remote.family = AF_UNIX; memcpy(st.local.data, &s->name, sizeof(s->name)); @@ -2673,7 +2705,7 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh, char name[128]; struct sockstat stat = { .name = "*", .peer_name = "*" }; - parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr*)(r+1), + parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr *)(r+1), nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); stat.type = r->udiag_type; @@ -2686,6 +2718,7 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh, if (tb[UNIX_DIAG_RQLEN]) { struct unix_diag_rqlen *rql = RTA_DATA(tb[UNIX_DIAG_RQLEN]); + stat.rq = rql->udiag_rqueue; stat.wq = rql->udiag_wqueue; } @@ -2714,6 +2747,7 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh, if (show_details) { if (tb[UNIX_DIAG_SHUTDOWN]) { unsigned char mask; + mask = *(__u8 *)RTA_DATA(tb[UNIX_DIAG_SHUTDOWN]); printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>'); } @@ -2922,7 +2956,7 @@ static int packet_show_sock(const struct sockaddr_nl *addr, uint32_t fanout = 0; bool has_fanout = false; - parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr*)(r+1), + parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr *)(r+1), nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); /* use /proc/net/packet if all info are not available */ @@ -2937,6 +2971,7 @@ static int packet_show_sock(const struct sockaddr_nl *addr, if (tb[PACKET_DIAG_MEMINFO]) { __u32 *skmeminfo = RTA_DATA(tb[PACKET_DIAG_MEMINFO]); + stat.rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC]; } @@ -3100,12 +3135,13 @@ static int packet_show(struct filter *f) } static int netlink_show_one(struct filter *f, - int prot, int pid, unsigned groups, - int state, int dst_pid, unsigned dst_group, + int prot, int pid, unsigned int groups, + int state, int dst_pid, unsigned int dst_group, int rq, int wq, unsigned long long sk, unsigned long long cb) { struct sockstat st; + SPRINT_BUF(prot_buf) = {}; const char *prot_name; char procname[64] = {}; @@ -3135,11 +3171,13 @@ static int netlink_show_one(struct filter *f, procname[0] = '*'; } else if (resolve_services) { int done = 0; + if (!pid) { done = 1; strncpy(procname, "kernel", 6); } else if (pid > 0) { FILE *fp; + snprintf(procname, sizeof(procname), "%s/%d/stat", getenv("PROC_ROOT") ? : "/proc", pid); if ((fp = fopen(procname, "r")) != NULL) { @@ -3163,6 +3201,7 @@ static int netlink_show_one(struct filter *f, if (state == NETLINK_CONNECTED) { char dst_group_buf[30]; char dst_pid_buf[30]; + sock_addr_print(int_to_str(dst_group, dst_group_buf), ":", int_to_str(dst_pid, dst_pid_buf), NULL); } else { @@ -3170,6 +3209,7 @@ static int netlink_show_one(struct filter *f, } char *pid_context = NULL; + if (show_proc_ctx) { /* The pid value will either be: * 0 if destination kernel - show kernel initial context. @@ -3207,7 +3247,7 @@ static int netlink_show_sock(const struct sockaddr_nl *addr, int rq = 0, wq = 0; unsigned long groups = 0; - parse_rtattr(tb, NETLINK_DIAG_MAX, (struct rtattr*)(r+1), + parse_rtattr(tb, NETLINK_DIAG_MAX, (struct rtattr *)(r+1), nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); if (tb[NETLINK_DIAG_GROUPS] && RTA_PAYLOAD(tb[NETLINK_DIAG_GROUPS])) @@ -3215,6 +3255,7 @@ static int netlink_show_sock(const struct sockaddr_nl *addr, if (tb[NETLINK_DIAG_MEMINFO]) { const __u32 *skmeminfo; + skmeminfo = RTA_DATA(tb[NETLINK_DIAG_MEMINFO]); rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC]; @@ -3252,7 +3293,7 @@ static int netlink_show(struct filter *f) FILE *fp; char buf[256]; int prot, pid; - unsigned groups; + unsigned int groups; int rq, wq, rc; unsigned long long sk, cb; @@ -3340,8 +3381,7 @@ static int handle_follow_request(struct filter *f) return ret; } -struct snmpstat -{ +struct snmpstat { int tcp_estab; }; @@ -3360,6 +3400,7 @@ static int get_snmp_int(char *proto, char *key, int *result) while (fgets(buf, sizeof(buf), fp) != NULL) { char *p = buf; int pos = 0; + if (memcmp(buf, proto, protolen)) continue; while ((p = strchr(p, ' ')) != NULL) { @@ -3392,8 +3433,7 @@ static int get_snmp_int(char *proto, char *key, int *result) /* Get stats from sockstat */ -struct ssummary -{ +struct ssummary { int socks; int tcp_mem; int tcp_total; @@ -3449,13 +3489,13 @@ static int get_sockstat(struct ssummary *s) if ((fp = net_sockstat_open()) == NULL) return -1; - while(fgets(buf, sizeof(buf), fp) != NULL) + while (fgets(buf, sizeof(buf), fp) != NULL) get_sockstat_line(buf, s); fclose(fp); if ((fp = net_sockstat6_open()) == NULL) return 0; - while(fgets(buf, sizeof(buf), fp) != NULL) + while (fgets(buf, sizeof(buf), fp) != NULL) get_sockstat_line(buf, s); fclose(fp); @@ -3572,6 +3612,7 @@ static void usage(void) static int scan_state(const char *state) { int i; + if (strcasecmp(state, "close") == 0 || strcasecmp(state, "closed") == 0) return (1< Date: Mon, 21 Mar 2016 12:02:32 -0700 Subject: [PATCH 143/513] update kernel headers to 4.6 (pre rc1) --- include/linux/bpf.h | 20 ++++++++++++++++++++ include/linux/if.h | 2 +- include/linux/if_ether.h | 1 + include/linux/if_link.h | 31 +++++++++++++++++++++++++++++++ include/linux/netconf.h | 1 + include/linux/pkt_cls.h | 2 ++ include/linux/tcp.h | 2 ++ 7 files changed, 58 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index ffaba7c4d..dc043ef1f 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -101,12 +101,15 @@ enum bpf_prog_type { #define BPF_NOEXIST 1 /* create new element if it didn't exist */ #define BPF_EXIST 2 /* update existing element */ +#define BPF_F_NO_PREALLOC (1U << 0) + union bpf_attr { struct { /* anonymous struct used by BPF_MAP_CREATE command */ __u32 map_type; /* one of enum bpf_map_type */ __u32 key_size; /* size of key in bytes */ __u32 value_size; /* size of value in bytes */ __u32 max_entries; /* max number of entries in a map */ + __u32 map_flags; /* prealloc or not */ }; struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ @@ -298,6 +301,17 @@ enum bpf_func_id { * Return: csum result */ BPF_FUNC_csum_diff, + + /** + * bpf_skb_[gs]et_tunnel_opt(skb, opt, size) + * retrieve or populate tunnel options metadata + * @skb: pointer to skb + * @opt: pointer to raw tunnel option data + * @size: size of @opt + * Return: 0 on success for set, option size for get + */ + BPF_FUNC_skb_get_tunnel_opt, + BPF_FUNC_skb_set_tunnel_opt, __BPF_FUNC_MAX_ID, }; @@ -305,6 +319,7 @@ enum bpf_func_id { /* BPF_FUNC_skb_store_bytes flags. */ #define BPF_F_RECOMPUTE_CSUM (1ULL << 0) +#define BPF_F_INVALIDATE_HASH (1ULL << 1) /* BPF_FUNC_l3_csum_replace and BPF_FUNC_l4_csum_replace flags. * First 4 bits are for passing the header field size. @@ -327,6 +342,10 @@ enum bpf_func_id { #define BPF_F_FAST_STACK_CMP (1ULL << 9) #define BPF_F_REUSE_STACKID (1ULL << 10) +/* BPF_FUNC_skb_set_tunnel_key flags. */ +#define BPF_F_ZERO_CSUM_TX (1ULL << 1) +#define BPF_F_DONT_FRAGMENT (1ULL << 2) + /* user accessible mirror of in-kernel sk_buff. * new fields can only be added to the end of this structure */ @@ -356,6 +375,7 @@ struct bpf_tunnel_key { }; __u8 tunnel_tos; __u8 tunnel_ttl; + __u32 tunnel_label; }; #endif /* __LINUX_BPF_H__ */ diff --git a/include/linux/if.h b/include/linux/if.h index a55a9e0ef..86fffb05e 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -37,7 +37,7 @@ * are shared for all types of net_devices. The sysfs entries are available * via /sys/class/net//flags. Flags which can be toggled through sysfs * are annotated below, note that only a few flags can be toggled and some - * other flags are always always preserved from the original net_device flags + * other flags are always preserved from the original net_device flags * even if you try to set them via sysfs. Flags which are always preserved * are kept under the flag grouping @IFF_VOLATILE. Flags which are __volatile__ * are annotated below as such. diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index bf278d65b..8f3b0f40e 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -83,6 +83,7 @@ #define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */ #define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */ #define ETH_P_TIPC 0x88CA /* TIPC */ +#define ETH_P_MACSEC 0x88E5 /* 802.1ae MACsec */ #define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ #define ETH_P_MVRP 0x88F5 /* 802.1Q MVRP */ #define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 0331c723e..9b7f3c8d6 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -411,6 +411,35 @@ enum { #define IFLA_VRF_PORT_MAX (__IFLA_VRF_PORT_MAX - 1) +/* MACSEC section */ +enum { + IFLA_MACSEC_UNSPEC, + IFLA_MACSEC_SCI, + IFLA_MACSEC_PORT, + IFLA_MACSEC_ICV_LEN, + IFLA_MACSEC_CIPHER_SUITE, + IFLA_MACSEC_WINDOW, + IFLA_MACSEC_ENCODING_SA, + IFLA_MACSEC_ENCRYPT, + IFLA_MACSEC_PROTECT, + IFLA_MACSEC_INC_SCI, + IFLA_MACSEC_ES, + IFLA_MACSEC_SCB, + IFLA_MACSEC_REPLAY_PROTECT, + IFLA_MACSEC_VALIDATION, + __IFLA_MACSEC_MAX, +}; + +#define IFLA_MACSEC_MAX (__IFLA_MACSEC_MAX - 1) + +enum macsec_validation_type { + MACSEC_VALIDATE_DISABLED = 0, + MACSEC_VALIDATE_CHECK = 1, + MACSEC_VALIDATE_STRICT = 2, + __MACSEC_VALIDATE_END, + MACSEC_VALIDATE_MAX = __MACSEC_VALIDATE_END - 1, +}; + /* IPVLAN section */ enum { IFLA_IPVLAN_UNSPEC, @@ -454,6 +483,7 @@ enum { IFLA_VXLAN_GBP, IFLA_VXLAN_REMCSUM_NOPARTIAL, IFLA_VXLAN_COLLECT_METADATA, + IFLA_VXLAN_LABEL, __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) @@ -476,6 +506,7 @@ enum { IFLA_GENEVE_UDP_CSUM, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, + IFLA_GENEVE_LABEL, __IFLA_GENEVE_MAX }; #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) diff --git a/include/linux/netconf.h b/include/linux/netconf.h index 7210fe4d2..70306a89a 100644 --- a/include/linux/netconf.h +++ b/include/linux/netconf.h @@ -19,6 +19,7 @@ enum { __NETCONFA_MAX }; #define NETCONFA_MAX (__NETCONFA_MAX - 1) +#define NETCONFA_ALL -1 #define NETCONFA_IFINDEX_ALL -1 #define NETCONFA_IFINDEX_DEFAULT -2 diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index a1b89a11b..b69358b48 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -363,6 +363,8 @@ enum { TCA_FLOWER_KEY_TCP_DST, /* be16 */ TCA_FLOWER_KEY_UDP_SRC, /* be16 */ TCA_FLOWER_KEY_UDP_DST, /* be16 */ + + TCA_FLOWER_FLAGS, __TCA_FLOWER_MAX, }; diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 55d656756..7f21db9b5 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -199,6 +199,8 @@ struct tcp_info { __u32 tcpi_notsent_bytes; __u32 tcpi_min_rtt; + __u32 tcpi_data_segs_in; /* RFC4898 tcpEStatsDataSegsIn */ + __u32 tcpi_data_segs_out; /* RFC4898 tcpEStatsDataSegsOut */ }; /* for TCP_MD5SIG socket option */ From 52a4474d90409b9d20758e023711093f903a37d7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 21 Mar 2016 12:13:57 -0700 Subject: [PATCH 144/513] netconf: replace macro with a function The number of casts in macro was excessive. --- ip/ipnetconf.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ip/ipnetconf.c b/ip/ipnetconf.c index 58657a915..158cfa6a4 100644 --- a/ip/ipnetconf.c +++ b/ip/ipnetconf.c @@ -24,8 +24,7 @@ #include "utils.h" #include "ip_common.h" -static struct -{ +static struct { int family; int ifindex; } filter; @@ -38,7 +37,11 @@ static void usage(void) exit(-1); } -#define NETCONF_RTA(r) ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct netconfmsg)))) +static struct rtattr *netconf_rta(struct netconfmsg *ncm) +{ + return (struct rtattr *)((char *)ncm + + NLMSG_ALIGN(sizeof(struct netconfmsg))); +} int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg) @@ -65,7 +68,7 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, if (filter.family && filter.family != ncm->ncm_family) return 0; - parse_rtattr(tb, NETCONFA_MAX, NETCONF_RTA(ncm), + parse_rtattr(tb, NETCONFA_MAX, netconf_rta(ncm), NLMSG_PAYLOAD(n, sizeof(*ncm))); switch (ncm->ncm_family) { From c256dcd47ce7328beeced8ad3ad6cea27a590201 Mon Sep 17 00:00:00 2001 From: Zhang Shengju Date: Tue, 15 Mar 2016 02:32:12 +0000 Subject: [PATCH 145/513] man: update netconf manual for new attributes Update this manual to add attributes proxy_neigh and ignore_routes_with_linkdown. Signed-off-by: Zhang Shengju --- man/man8/ip-netconf.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/ip-netconf.8 b/man/man8/ip-netconf.8 index 27182582f..7fe3e5f35 100644 --- a/man/man8/ip-netconf.8 +++ b/man/man8/ip-netconf.8 @@ -15,7 +15,7 @@ The .B ip netconf utility can monitor IPv4 and IPv6 parameters (see .BR "/proc/sys/net/ipv[4|6]/conf/[all|DEV]/" ")" -like forwarding, rp_filter +like forwarding, rp_filter, proxy_neigh, ignore_routes_with_linkdown or mc_forwarding status. If no interface is specified, the entry From 95c9d0d301d34cb0d0367ae2320c41384681936f Mon Sep 17 00:00:00 2001 From: Zhang Shengju Date: Mon, 21 Mar 2016 12:16:25 -0700 Subject: [PATCH 146/513] netconf: add support for ignore route attribute Add support for ignore route attribute, and refine the code to use rta_getattr_* function to get attribute value. Signed-off-by: Zhang Shengju --- ip/ipnetconf.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/ip/ipnetconf.c b/ip/ipnetconf.c index 158cfa6a4..5fdbfb644 100644 --- a/ip/ipnetconf.c +++ b/ip/ipnetconf.c @@ -37,6 +37,11 @@ static void usage(void) exit(-1); } +static void print_onoff(FILE *f, const char *flag, __u32 val) +{ + fprintf(f, "%s %s ", flag, val ? "on" : "off"); +} + static struct rtattr *netconf_rta(struct netconfmsg *ncm) { return (struct rtattr *)((char *)ncm @@ -84,7 +89,7 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, } if (tb[NETCONFA_IFINDEX]) { - int *ifindex = (int *)RTA_DATA(tb[NETCONFA_IFINDEX]); + int *ifindex = (int *)rta_getattr_str(tb[NETCONFA_IFINDEX]); switch (*ifindex) { case NETCONFA_IFINDEX_ALL: @@ -100,10 +105,10 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, } if (tb[NETCONFA_FORWARDING]) - fprintf(fp, "forwarding %s ", - *(int *)RTA_DATA(tb[NETCONFA_FORWARDING])?"on":"off"); + print_onoff(fp, "forwarding", + rta_getattr_u32(tb[NETCONFA_FORWARDING])); if (tb[NETCONFA_RP_FILTER]) { - int rp_filter = *(int *)RTA_DATA(tb[NETCONFA_RP_FILTER]); + __u32 rp_filter = rta_getattr_u32(tb[NETCONFA_RP_FILTER]); if (rp_filter == 0) fprintf(fp, "rp_filter off "); @@ -115,12 +120,16 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, fprintf(fp, "rp_filter unknown mode "); } if (tb[NETCONFA_MC_FORWARDING]) - fprintf(fp, "mc_forwarding %d ", - *(int *)RTA_DATA(tb[NETCONFA_MC_FORWARDING])); + print_onoff(fp, "mc_forwarding", + rta_getattr_u32(tb[NETCONFA_MC_FORWARDING])); if (tb[NETCONFA_PROXY_NEIGH]) - fprintf(fp, "proxy_neigh %s ", - *(int *)RTA_DATA(tb[NETCONFA_PROXY_NEIGH])?"on":"off"); + print_onoff(fp, "proxy_neigh", + rta_getattr_u32(tb[NETCONFA_PROXY_NEIGH])); + + if (tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]) + print_onoff(fp, "ignore_routes_with_linkdown", + rta_getattr_u32(tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN])); fprintf(fp, "\n"); fflush(fp); From 952f89debadfb2cf9a4eeeb57b8d9d007bc4e764 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 15:16:21 +0100 Subject: [PATCH 147/513] tc/p_ip.c: Minor coding style cleanup Break overlong function definitions and remove one extraneous whitespace. Signed-off-by: Phil Sutter Signed-off-by: Stephen Hemminger --- tc/p_ip.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tc/p_ip.c b/tc/p_ip.c index 53dfb2693..535151e5d 100644 --- a/tc/p_ip.c +++ b/tc/p_ip.c @@ -24,7 +24,8 @@ #include "m_pedit.h" static int -parse_ip(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) +parse_ip(int *argc_p, char ***argv_p, + struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int res = -1; int argc = *argc_p; @@ -52,7 +53,7 @@ parse_ip(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_ if (strcmp(*argv, "tos") == 0 || matches(*argv, "dsfield") == 0) { NEXT_ARG(); tkey->off = 1; - res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); + res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey); goto done; } if (strcmp(*argv, "ihl") == 0) { @@ -139,7 +140,8 @@ parse_ip(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_ } static int -parse_ip6(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) +parse_ip6(int *argc_p, char ***argv_p, + struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int res = -1; return res; From 77bed404d03f39adf2842ee4aefb53ba8a68f087 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 15:16:22 +0100 Subject: [PATCH 148/513] tc: pedit: Fix for big-endian systems This was tricky to get right: - The 'stride' value used for 8 and 16 bit values must behave inverse to the value's intra word offset to work correctly with big-endian data act_pedit is editing. - The 'm' array's values are in host byte order, so they have to be converted as well (and the ordering was just inverse, for some reason). - The only sane way of getting this right is to manipulate value/mask in host byte order and convert the output. - TIPV4 (i.e. 'munge ip src/dst') had it's own pitfall: the address parser converts to network byte order automatically. This patch fixes this by converting it back before calling pack_key32, which is a hack but at least does not require to implement a completely separate code flow. Signed-off-by: Phil Sutter Signed-off-by: Stephen Hemminger --- tc/m_pedit.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tc/m_pedit.c b/tc/m_pedit.c index ca78a83dd..30a6f3673 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -156,7 +156,7 @@ int pack_key16(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int ind, stride; - __u32 m[4] = {0xFFFF0000, 0xFF0000FF, 0x0000FFFF}; + __u32 m[4] = {0x0000FFFF, 0xFF0000FF, 0xFFFF0000}; if (tkey->val > 0xFFFF || tkey->mask > 0xFFFF) { fprintf(stderr, "pack_key16 bad value\n"); @@ -170,9 +170,9 @@ pack_key16(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) return -1; } - stride = 8 * ind; - tkey->val = htons(tkey->val & retain) << stride; - tkey->mask = (htons(tkey->mask | ~retain) << stride) | m[ind]; + stride = 8 * (2 - ind); + tkey->val = htonl((tkey->val & retain) << stride); + tkey->mask = htonl(((tkey->mask | ~retain) << stride) | m[ind]); tkey->off &= ~3; @@ -186,7 +186,7 @@ int pack_key8(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int ind, stride; - __u32 m[4] = {0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 0x00FFFFFF}; + __u32 m[4] = {0x00FFFFFF, 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00}; if (tkey->val > 0xFF || tkey->mask > 0xFF) { fprintf(stderr, "pack_key8 bad value (val %x mask %x\n", tkey->val, tkey->mask); @@ -195,9 +195,9 @@ pack_key8(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) ind = tkey->off & 3; - stride = 8 * ind; - tkey->val = (tkey->val & retain) << stride; - tkey->mask = ((tkey->mask | ~retain) << stride) | m[ind]; + stride = 8 * (3 - ind); + tkey->val = htonl((tkey->val & retain) << stride); + tkey->mask = htonl(((tkey->mask | ~retain) << stride) | m[ind]); tkey->off &= ~3; @@ -283,6 +283,9 @@ parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain, struct tkey->val = val; tkey->mask = mask; + if (type == TIPV4) + tkey->val = ntohl(tkey->val); + if (len == 1) { res = pack_key8(retain, sel, tkey); goto done; From a33786b582a29a940cfe1eff826ff5a0548a6d81 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 15:16:23 +0100 Subject: [PATCH 149/513] tc: pedit: Fix raw op The retain value was wrong for u16 and u8 types. Signed-off-by: Phil Sutter Signed-off-by: Stephen Hemminger --- tc/m_pedit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tc/m_pedit.c b/tc/m_pedit.c index 30a6f3673..8ccec8bc4 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -339,12 +339,12 @@ parse_offset(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pe } if (matches(*argv, "u16") == 0) { len = 2; - retain = 0x0; + retain = 0xffff; goto done; } if (matches(*argv, "u8") == 0) { len = 1; - retain = 0x0; + retain = 0xff; goto done; } From 3c48c714a35958f480289c6d7580aa96b3dad572 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 15:16:24 +0100 Subject: [PATCH 150/513] testsuite: add a test for tc pedit action This is not a full test, since kernel functionality is not actually tested. It only compares that the kernel returned values when listing the action are what one expects them to be. Since this test succeeded on both a little-endian and a big-endian system, it shows that any endianness issues have been resolved in tc/p_ip.c at least. Signed-off-by: Phil Sutter Signed-off-by: Stephen Hemminger --- testsuite/tests/tc/pedit.t | 217 +++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100755 testsuite/tests/tc/pedit.t diff --git a/testsuite/tests/tc/pedit.t b/testsuite/tests/tc/pedit.t new file mode 100755 index 000000000..e9b6c333a --- /dev/null +++ b/testsuite/tests/tc/pedit.t @@ -0,0 +1,217 @@ +#!/bin/sh + +source lib/generic.sh + +DEV="$(rand_dev)" +ts_ip "$0" "Add $DEV dummy interface" link add dev $DEV type dummy +ts_ip "$0" "Enable $DEV" link set $DEV up +ts_tc "pedit" "Add ingress qdisc" qdisc add dev $DEV ingress + + +do_pedit() { + ts_tc "pedit" "Drop ingress qdisc" \ + qdisc del dev $DEV ingress + ts_tc "pedit" "Add ingress qdisc" \ + qdisc add dev $DEV ingress + ts_tc "pedit" "Add pedit action $*" \ + filter add dev $DEV parent ffff: \ + u32 match u32 0 0 \ + action pedit munge $@ + ts_tc "pedit" "Show ingress filters" \ + filter show dev $DEV parent ffff: +} + +do_pedit offset 12 u32 set 0x12345678 +test_on "key #0 at 12: val 12345678 mask 00000000" +do_pedit offset 12 u16 set 0x1234 +test_on "key #0 at 12: val 12340000 mask 0000ffff" +do_pedit offset 14 u16 set 0x1234 +test_on "key #0 at 12: val 00001234 mask ffff0000" +do_pedit offset 12 u8 set 0x23 +test_on "key #0 at 12: val 23000000 mask 00ffffff" +do_pedit offset 13 u8 set 0x23 +test_on "key #0 at 12: val 00230000 mask ff00ffff" +do_pedit offset 14 u8 set 0x23 +test_on "key #0 at 12: val 00002300 mask ffff00ff" +do_pedit offset 15 u8 set 0x23 +test_on "key #0 at 12: val 00000023 mask ffffff00" + +do_pedit offset 13 u8 invert +test_on "key #0 at 12: val 00ff0000 mask ffffffff" +do_pedit offset 13 u8 clear +test_on "key #0 at 12: val 00000000 mask ff00ffff" +do_pedit offset 13 u8 preserve +test_on "key #0 at 12: val 00000000 mask ffffffff" + +# the following set of tests has been auto-generated by running this little +# shell script: +# +# do_it() { +# echo "do_pedit $@" +# tc qd del dev veth0 ingress >/dev/null 2>&1 +# tc qd add dev veth0 ingress >/dev/null 2>&1 +# tc filter add dev veth0 parent ffff: u32 \ +# match u32 0 0 \ +# action pedit munge $@ >/dev/null 2>&1 +# tc filter show dev veth0 parent ffff: | \ +# sed -n 's/^[\t ]*\(key #0.*\)/test_on "\1"/p' +# } +# +# do_it_all() { # (field, val1 [, val2, ...]) +# local field=$1 +# shift +# for val in $@; do +# do_it ip $field set $val +# done +# for i in preserve invert clear; do +# do_it ip $field $i +# done +# } +# +# do_it_all ihl 0x04 0x40 +# do_it_all src 1.2.3.4 +# do_it_all dst 1.2.3.4 +# do_it_all tos 0x1 0x10 +# do_it_all protocol 0x23 +# do_it_all nofrag 0x23 0xf4 +# do_it_all firstfrag 0x03 0xfa +# do_it_all ce 0x23 0x04 0xf3 +# do_it_all df 0x23 0x04 0xf3 +# do_it_all mf 0x23 0x04 0xf3 +# do_it_all dport 0x1234 +# do_it_all sport 0x1234 +# do_it_all icmp_type 0x23 +# do_it_all icmp_code 0x23 + +do_pedit ip ihl set 0x04 +test_on "key #0 at 0: val 04000000 mask f0ffffff" +do_pedit ip ihl set 0x40 +test_on "key #0 at 0: val 00000000 mask f0ffffff" +do_pedit ip ihl preserve +test_on "key #0 at 0: val 00000000 mask ffffffff" +do_pedit ip ihl invert +test_on "key #0 at 0: val 0f000000 mask ffffffff" +do_pedit ip ihl clear +test_on "key #0 at 0: val 00000000 mask f0ffffff" +do_pedit ip src set 1.2.3.4 +test_on "key #0 at 12: val 01020304 mask 00000000" +do_pedit ip src preserve +test_on "key #0 at 12: val 00000000 mask ffffffff" +do_pedit ip src invert +test_on "key #0 at 12: val ffffffff mask ffffffff" +do_pedit ip src clear +test_on "key #0 at 12: val 00000000 mask 00000000" +do_pedit ip dst set 1.2.3.4 +test_on "key #0 at 16: val 01020304 mask 00000000" +do_pedit ip dst preserve +test_on "key #0 at 16: val 00000000 mask ffffffff" +do_pedit ip dst invert +test_on "key #0 at 16: val ffffffff mask ffffffff" +do_pedit ip dst clear +test_on "key #0 at 16: val 00000000 mask 00000000" +do_pedit ip tos set 0x1 +test_on "key #0 at 0: val 00010000 mask ff00ffff" +do_pedit ip tos set 0x10 +test_on "key #0 at 0: val 00100000 mask ff00ffff" +do_pedit ip tos preserve +test_on "key #0 at 0: val 00000000 mask ffffffff" +do_pedit ip tos invert +test_on "key #0 at 0: val 00ff0000 mask ffffffff" +do_pedit ip tos clear +test_on "key #0 at 0: val 00000000 mask ff00ffff" +do_pedit ip protocol set 0x23 +test_on "key #0 at 8: val 00230000 mask ff00ffff" +do_pedit ip protocol preserve +test_on "key #0 at 8: val 00000000 mask ffffffff" +do_pedit ip protocol invert +test_on "key #0 at 8: val 00ff0000 mask ffffffff" +do_pedit ip protocol clear +test_on "key #0 at 8: val 00000000 mask ff00ffff" +do_pedit ip nofrag set 0x23 +test_on "key #0 at 4: val 00002300 mask ffffc0ff" +do_pedit ip nofrag set 0xf4 +test_on "key #0 at 4: val 00003400 mask ffffc0ff" +do_pedit ip nofrag preserve +test_on "key #0 at 4: val 00000000 mask ffffffff" +do_pedit ip nofrag invert +test_on "key #0 at 4: val 00003f00 mask ffffffff" +do_pedit ip nofrag clear +test_on "key #0 at 4: val 00000000 mask ffffc0ff" +do_pedit ip firstfrag set 0x03 +test_on "key #0 at 4: val 00000300 mask ffffe0ff" +do_pedit ip firstfrag set 0xfa +test_on "key #0 at 4: val 00001a00 mask ffffe0ff" +do_pedit ip firstfrag preserve +test_on "key #0 at 4: val 00000000 mask ffffffff" +do_pedit ip firstfrag invert +test_on "key #0 at 4: val 00001f00 mask ffffffff" +do_pedit ip firstfrag clear +test_on "key #0 at 4: val 00000000 mask ffffe0ff" +do_pedit ip ce set 0x23 +test_on "key #0 at 4: val 00000000 mask ffff7fff" +do_pedit ip ce set 0x04 +test_on "key #0 at 4: val 00000000 mask ffff7fff" +do_pedit ip ce set 0xf3 +test_on "key #0 at 4: val 00008000 mask ffff7fff" +do_pedit ip ce preserve +test_on "key #0 at 4: val 00000000 mask ffffffff" +do_pedit ip ce invert +test_on "key #0 at 4: val 00008000 mask ffffffff" +do_pedit ip ce clear +test_on "key #0 at 4: val 00000000 mask ffff7fff" +do_pedit ip df set 0x23 +test_on "key #0 at 4: val 00000000 mask ffffbfff" +do_pedit ip df set 0x04 +test_on "key #0 at 4: val 00000000 mask ffffbfff" +do_pedit ip df set 0xf3 +test_on "key #0 at 4: val 00004000 mask ffffbfff" +do_pedit ip df preserve +test_on "key #0 at 4: val 00000000 mask ffffffff" +do_pedit ip df invert +test_on "key #0 at 4: val 00004000 mask ffffffff" +do_pedit ip df clear +test_on "key #0 at 4: val 00000000 mask ffffbfff" +do_pedit ip mf set 0x23 +test_on "key #0 at 4: val 00002000 mask ffffdfff" +do_pedit ip mf set 0x04 +test_on "key #0 at 4: val 00000000 mask ffffdfff" +do_pedit ip mf set 0xf3 +test_on "key #0 at 4: val 00002000 mask ffffdfff" +do_pedit ip mf preserve +test_on "key #0 at 4: val 00000000 mask ffffffff" +do_pedit ip mf invert +test_on "key #0 at 4: val 00002000 mask ffffffff" +do_pedit ip mf clear +test_on "key #0 at 4: val 00000000 mask ffffdfff" +do_pedit ip dport set 0x1234 +test_on "key #0 at 20: val 00001234 mask ffff0000" +do_pedit ip dport preserve +test_on "key #0 at 20: val 00000000 mask ffffffff" +do_pedit ip dport invert +test_on "key #0 at 20: val 0000ffff mask ffffffff" +do_pedit ip dport clear +test_on "key #0 at 20: val 00000000 mask ffff0000" +do_pedit ip sport set 0x1234 +test_on "key #0 at 20: val 12340000 mask 0000ffff" +do_pedit ip sport preserve +test_on "key #0 at 20: val 00000000 mask ffffffff" +do_pedit ip sport invert +test_on "key #0 at 20: val ffff0000 mask ffffffff" +do_pedit ip sport clear +test_on "key #0 at 20: val 00000000 mask 0000ffff" +do_pedit ip icmp_type set 0x23 +test_on "key #0 at 20: val 23000000 mask 00ffffff" +do_pedit ip icmp_type preserve +test_on "key #0 at 20: val 00000000 mask ffffffff" +do_pedit ip icmp_type invert +test_on "key #0 at 20: val ff000000 mask ffffffff" +do_pedit ip icmp_type clear +test_on "key #0 at 20: val 00000000 mask 00ffffff" +do_pedit ip icmp_code set 0x23 +test_on "key #0 at 20: val 23000000 mask 00ffffff" +do_pedit ip icmp_code preserve +test_on "key #0 at 20: val 00000000 mask ffffffff" +do_pedit ip icmp_code invert +test_on "key #0 at 20: val ff000000 mask ffffffff" +do_pedit ip icmp_code clear +test_on "key #0 at 20: val 00000000 mask 00ffffff" From edf35b88248f667c0b4f1502ccd35ce423d12451 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 15:48:32 +0100 Subject: [PATCH 151/513] doc/tc-filters.tex: Drop overly subjective paragraphs Cc: Alexei Starovoitov Signed-off-by: Phil Sutter Signed-off-by: Stephen Hemminger --- doc/tc-filters.tex | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/doc/tc-filters.tex b/doc/tc-filters.tex index 59127d667..54cc0c992 100644 --- a/doc/tc-filters.tex +++ b/doc/tc-filters.tex @@ -18,10 +18,6 @@ \date{January 2016} \maketitle -TC, the Traffic Control utility, has been there for a very long time - forever -in my humble perception. It is still (and has ever been if I'm not mistaken) the -only tool to configure QoS in Linux. - Standard practice when transmitting packets over a medium which may block (due to congestion, e.g.) is to use a queue which temporarily holds these packets. In Linux, this queueing approach is where QoS happens: A Queueing Discipline @@ -496,21 +492,10 @@ \section*{Intermediate Functional Block} \section*{Conclusion} -My personal impression is that although the \cmd{tc} utility is an absolute -necessity for anyone aiming at doing QoS in Linux professionally, there are way -too many loose ends and trip wires present in it's environment. Contributing to -this is the fact, that much of the non-essential functionality is redundantly -available in netfilter. Another problem which adds weight to the first one is a -general lack of documentation. Of course, there are many HOWTOs and guides in -the internet, but since it's often not clear how up to date these are, I prefer -the usual resources such as man or info pages. Surely nothing one couldn't fix -in hindsight, but quality certainly suffers if the original author of the code -does not or can not contribute to that. - -All that being said, once the steep learning curve has been mastered, the -conglomerate of (classful) qdiscs, filters and actions provides a highly -sophisticated and flexible infrastructure to perform QoS, which plays nicely -along with routing and firewalling setups. +Once the steep learning curve has been mastered, the conglomerate of (classful) +qdiscs, filters and actions provides a highly sophisticated and flexible +infrastructure to perform QoS, which plays nicely along with routing and +firewalling setups. \section*{Further Reading} From 1672f42195406d2d4d8fb014b8ea2a59e59f2d6a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 15:48:33 +0100 Subject: [PATCH 152/513] tc: connmark, pedit: Rename BRANCH to CONTROL As Jamal suggested, BRANCH is the wrong name, as these keywords go beyond simple branch control - e.g. loops are possible, too. Therefore rename the non-terminal to CONTROL instead which should be more appropriate. Signed-off-by: Phil Sutter Signed-off-by: Stephen Hemminger --- man/man8/tc-connmark.8 | 6 +++--- man/man8/tc-pedit.8 | 6 +++--- tc/m_connmark.c | 4 ++-- tc/m_pedit.c | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/man/man8/tc-connmark.8 b/man/man8/tc-connmark.8 index bb4cf7543..44f29f508 100644 --- a/man/man8/tc-connmark.8 +++ b/man/man8/tc-connmark.8 @@ -6,12 +6,12 @@ connmark - netfilter connmark retriever action .in +8 .ti -8 .BR tc " ... " "action connmark " [ " zone" -.IR u16_zone_index " ] [ " BRANCH " ] [" +.IR u16_zone_index " ] [ " CONTROL " ] [" .BI index " u32_index " ] .ti -8 -.IR BRANCH " := { " reclassify " | " pipe " | " drop " | " continue " | " ok " }" +.IR CONTROL " := { " reclassify " | " pipe " | " drop " | " continue " | " ok " }" .SH DESCRIPTION The connmark action is used to restore the connection's mark value into the packet's fwmark. @@ -22,7 +22,7 @@ Specify the conntrack zone when doing conntrack lookups for packets. .I u16_zone_index is a 16bit unsigned decimal value. .TP -.I BRANCH +.I CONTROL How to continue after executing this action. .RS .TP diff --git a/man/man8/tc-pedit.8 b/man/man8/tc-pedit.8 index c30927ec5..c34520c04 100644 --- a/man/man8/tc-pedit.8 +++ b/man/man8/tc-pedit.8 @@ -6,7 +6,7 @@ pedit - generic packet editor action .in +8 .ti -8 .BR tc " ... " "action pedit munge " { -.IR RAW_OP " | " LAYERED_OP " } [ " BRANCH " ]" +.IR RAW_OP " | " LAYERED_OP " } [ " CONTROL " ]" .ti -8 .IR RAW_OP " := " @@ -45,7 +45,7 @@ pedit - generic packet editor action .IR RVAL " ]" .ti -8 -.IR BRANCH " := {" +.IR CONTROL " := {" .BR reclassify " | " pipe " | " drop " | " shot " | " continue " | " pass " }" .SH DESCRIPTION The @@ -165,7 +165,7 @@ This optional extra part of .I CMD_SPEC allows to exclude bits from being changed. .TP -.I BRANCH +.I CONTROL The following keywords allow to control how the tree of qdisc, classes, filters and actions is further traversed after this action. .RS diff --git a/tc/m_connmark.c b/tc/m_connmark.c index 2414f321c..b1c7d3af5 100644 --- a/tc/m_connmark.c +++ b/tc/m_connmark.c @@ -27,10 +27,10 @@ static void explain(void) { - fprintf(stderr, "Usage: ... connmark [zone ZONE] [BRANCH] [index ]\n"); + fprintf(stderr, "Usage: ... connmark [zone ZONE] [CONTROL] [index ]\n"); fprintf(stderr, "where :\n" "\tZONE is the conntrack zone\n" - "\tBRANCH := reclassify|pipe|drop|continue|ok\n"); + "\tCONTROL := reclassify|pipe|drop|continue|ok\n"); } static void diff --git a/tc/m_pedit.c b/tc/m_pedit.c index 8ccec8bc4..2a94dfba7 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -35,7 +35,7 @@ static int pedit_debug; static void explain(void) { - fprintf(stderr, "Usage: ... pedit munge []\n"); + fprintf(stderr, "Usage: ... pedit munge [CONTROL]\n"); fprintf(stderr, "Where: MUNGE := |\n" "\t:= [ATC]\n \t\tOFFSETC:= offset \n " @@ -43,7 +43,7 @@ explain(void) "\t\tNOTE: maskval is a 32 bit hex number\n \t\tNOTE: shiftval is a is a shift value\n " "\t\tCMD:= clear | invert | set | retain\n \t:= ip | ip6 \n " " \t\t| udp | tcp | icmp \n" - "\t:= reclassify | pipe | drop | continue | pass\n" + "\tCONTROL:= reclassify | pipe | drop | continue | pass\n" "For Example usage look at the examples directory\n"); } From dbfb17a67f9c7cf64a38ca734ef638a3f613546c Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 15:48:34 +0100 Subject: [PATCH 153/513] man: tc-csum.8: Add an example Signed-off-by: Phil Sutter Signed-off-by: Stephen Hemminger --- man/man8/tc-csum.8 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/man/man8/tc-csum.8 b/man/man8/tc-csum.8 index 9d00aae34..3a64c82f0 100644 --- a/man/man8/tc-csum.8 +++ b/man/man8/tc-csum.8 @@ -49,6 +49,21 @@ UDPLite header .TP .B SWEETS These are merely syntactic sugar and ignored internally. +.SH EXAMPLES +The following performs stateless NAT for incoming packets from 192.168.1.100 to +new destination 18.52.86.120 (0x12345678 in hex). Assuming these are UDP +packets, both IP and UDP checksums have to be recalculated: + +.RS +.EX +# tc qdisc add dev eth0 ingress handle ffff: +# tc filter add eth0 prio 1 protocol ip parent ffff: \\ + u32 match ip src 192.168.1.100/32 flowid :1 \\ + action pedit munge ip dst set 0x12345678 pipe \\ + csum ip and udp +.EE +.RE + .SH SEE ALSO .BR tc (8), .BR tc-pedit (8) From 26df2953a5c34fe03986cbf3466321fd8a3af1c5 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 15:48:35 +0100 Subject: [PATCH 154/513] man: tc-mirred.8: Reword man page a bit, add generic mirror example Signed-off-by: Phil Sutter Signed-off-by: Stephen Hemminger --- man/man8/tc-mirred.8 | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/man/man8/tc-mirred.8 b/man/man8/tc-mirred.8 index 52d98bc41..bba96e0e5 100644 --- a/man/man8/tc-mirred.8 +++ b/man/man8/tc-mirred.8 @@ -21,11 +21,9 @@ mirred - mirror/redirect action .SH DESCRIPTION The .B mirred -action allows to redirect or mirror packets to another network interface on the -same system. It is typically used in combination with the -.B ifb -pseudo device to create a shrared instance where QoS happens, but serves well -for debugging or monitoring purposes, too. +action allows packet mirroring (copying) or redirecting (stealing) the packet it +receives. Mirroring is what is sometimes referred to as Switch Port Analyzer +(SPAN) and is commonly used to analyze and/or debug flows. .SH OPTIONS .TP .B ingress @@ -67,9 +65,23 @@ debugging purposes: .EE .RE -Use an +Mirror all incoming ICMP packets on eth0 to a dummy interface for examination +with e.g. tcpdump: + +.RS +.EX +# ip link add dummy0 type dummy +# ip link set dummy0 up +# tc qdisc add dev eth0 handle ffff: ingress +# tc filter add dev eth0 parent ffff: protocol ip \\ + u32 match ip protocol 1 0xff \\ + action mirred egress mirror dev dummy0 +.EE +.RE + +Using an .B ifb -interface to send ingress traffic on eth0 through an instance of +interface, it is possible to send ingress traffic through an instance of .BR sfq : .RS From 8409abd59bbc8a79689be25ab3a385c65d1334bd Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 15:48:36 +0100 Subject: [PATCH 155/513] man: tc-police.8: Emphasize on the two rate control mechanisms As Jamal pointed out, there are two different approaches to bandwidth measurement. Try to make this clear by separating them in synopsis and also documenting the way to fine-tune avrate. Signed-off-by: Phil Sutter Signed-off-by: Stephen Hemminger --- man/man8/tc-police.8 | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/man/man8/tc-police.8 b/man/man8/tc-police.8 index 2b1537ec5..5c5a63233 100644 --- a/man/man8/tc-police.8 +++ b/man/man8/tc-police.8 @@ -12,13 +12,21 @@ police - policing action .IR BYTES [\fB/ BYTES "] ] [" .BI peakrate " RATE" ] [ -.BI avrate " RATE" -] [ .BI overhead " BYTES" ] [ .BI linklayer " TYPE" ] [ -.BI conform-exceed " EXCEEDACT\fR[\fB/\fIEXCEEDACT\fR]" +.IR CONTROL " ]" + +.ti -8 +.BR tc " ... " filter " ... [ " estimator +.IR "SAMPLE AVERAGE " ] +.BR "action police avrate" +.IR RATE " [ " CONTROL " ]" + +.ti -8 +.IR CONTROL " :=" +.BI conform-exceed " EXCEEDACT\fR[\fB/\fIEXCEEDACT" .ti -8 .IR EXCEEDACT " := { " @@ -27,7 +35,14 @@ police - policing action The .B police action allows to limit bandwidth of traffic matched by the filter it is -attached to. +attached to. Basically there are two different algorithms available to measure +the packet rate: The first one uses an internal dual token bucket and is +configured using the +.BR rate ", " burst ", " mtu ", " peakrate ", " overhead " and " linklayer +parameters. The second one uses an in-kernel sampling mechanism. It can be +fine-tuned using the +.B estimator +filter parameter. .SH OPTIONS .TP .BI rate " RATE" @@ -73,6 +88,12 @@ cell sizes, for .B ethernet no action is taken. .TP +.BI estimator " SAMPLE AVERAGE" +Fine-tune the in-kernel packet rate estimator. +.IR SAMPLE " and " AVERAGE +are time values and control the frequency in which samples are taken and over +what timespan an average is built. +.TP .BI conform-exceed " EXCEEDACT\fR[\fB/\fIEXCEEDACT\fR]" Define how to handle packets which exceed (and, if the second .I EXCEEDACT From c73b621cfa480b039bf09dc732d7e224e14684ba Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 15:48:37 +0100 Subject: [PATCH 156/513] man: tc-skbedit.8: Elaborate a bit on TX queues Signed-off-by: Phil Sutter Signed-off-by: Stephen Hemminger --- man/man8/tc-skbedit.8 | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/man/man8/tc-skbedit.8 b/man/man8/tc-skbedit.8 index b585a4d42..e6902960e 100644 --- a/man/man8/tc-skbedit.8 +++ b/man/man8/tc-skbedit.8 @@ -17,6 +17,18 @@ The action allows to change a packet's associated meta data. It complements the .B pedit action, which in turn allows to change parts of the packet data itself. + +The most unique feature of +.B skbedit +is it's ability to decide over which queue of an interface with multiple +transmit queues the packet is to be sent out. The number of available transmit +queues is reflected by sysfs entries within +.I /sys/class/net//queues +with name +.I tx-N +(where +.I N +is the actual queue number). .SH OPTIONS .TP .BI queue_mapping " QUEUE_MAPPING" From 51011dac361ee491463fa4ba5a5927e6442b6c68 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 15:48:38 +0100 Subject: [PATCH 157/513] tc/m_vlan.c: mention CONTROL option in help text Signed-off-by: Phil Sutter Signed-off-by: Stephen Hemminger --- tc/m_vlan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tc/m_vlan.c b/tc/m_vlan.c index 8d97963f3..3233d2073 100644 --- a/tc/m_vlan.c +++ b/tc/m_vlan.c @@ -22,9 +22,10 @@ static void explain(void) { fprintf(stderr, "Usage: vlan pop\n"); - fprintf(stderr, " vlan push [ protocol VLANPROTO ] id VLANID\n"); + fprintf(stderr, " vlan push [ protocol VLANPROTO ] id VLANID [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"); } static void usage(void) From 16418561b78e2fe868232c432b871191696a11f3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 15:48:39 +0100 Subject: [PATCH 158/513] man: tc-vlan.8: Describe CONTROL option This should be made generic and part of a common tc-actions man page. Though leave it here for now to not confuse readers of the example which uses it. Signed-off-by: Phil Sutter Signed-off-by: Stephen Hemminger --- man/man8/tc-vlan.8 | 56 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/man/man8/tc-vlan.8 b/man/man8/tc-vlan.8 index e650b72d3..4bfd72b12 100644 --- a/man/man8/tc-vlan.8 +++ b/man/man8/tc-vlan.8 @@ -6,13 +6,17 @@ vlan - vlan manipulation module .in +8 .ti -8 .BR tc " ... " "action vlan" " { " pop " |" -.IR PUSH " }" +.IR PUSH " } [ " CONTROL " ]" .ti -8 .IR PUSH " := " .BR push " [ " protocol .IR VLANPROTO " ]" .BI id " VLANID" + +.ti -8 +.IR CONTROL " := { " +.BR reclassify " | " pipe " | " drop " | " continue " | " pass " }" .SH DESCRIPTION The .B vlan @@ -50,5 +54,55 @@ for hexadecimal interpretation, etc.). .BI protocol " VLANPROTO" Choose the VLAN protocol to use. At the time of writing, the kernel accepts only .BR 802.1Q " or " 802.1ad . +.TP +.I CONTROL +How to continue after executing this action. +.RS +.TP +.B reclassify +Restarts classification by jumping back to the first filter attached to this +action's parent. +.TP +.B pipe +Continue with the next action, this is the default. +.TP +.B drop +Packet will be dropped without running further actions. +.TP +.B continue +Continue classification with next filter in line. +.TP +.B pass +Return to calling qdisc for packet processing. This ends the classification +process. +.RE +.SH EXAMPLES +The following example encapsulates incoming ICMP packets on eth0 from 10.0.0.2 +into VLAN ID 123: + +.RS +.EX +#tc qdisc add dev eth0 handle ffff: ingress +#tc filter add dev eth0 parent ffff: pref 11 protocol ip \\ + u32 match ip protocol 1 0xff flowid 1:1 \\ + u32 match ip src 10.0.0.2 flowid 1:1 \\ + action vlan push id 123 +.EE +.RE + +Here is an example of the +.B pop +function: Incoming VLAN packets on eth0 are decapsulated and the classification +process then restarted for the plain packet: + +.RS +.EX +#tc qdisc add dev eth0 handle ffff: ingress +#tc filter add dev $ETH parent ffff: pref 1 protocol 802.1Q \\ + u32 match u32 0 0 flowid 1:1 \\ + action vlan pop reclassify +.EE +.RE + .SH SEE ALSO .BR tc (8) From a1121aa1f59ffc1c3469e7c7bbe809f87c654781 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 19:35:13 +0100 Subject: [PATCH 159/513] color: introduce color helpers and COLOR_CLEAR This adds two helper functions which map a given data field to a color, so color_fprintf() statements don't have to be duplicated with only a different color value depending on that data field's value. In order for this to work in a generic way, COLOR_CLEAR has been added to serve as a fallback default of uncolored output. Signed-off-by: Phil Sutter --- include/color.h | 5 ++++- ip/ipaddress.c | 47 +++++++++++++---------------------------------- lib/color.c | 30 +++++++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 36 deletions(-) diff --git a/include/color.h b/include/color.h index b85003aed..c1c298311 100644 --- a/include/color.h +++ b/include/color.h @@ -7,10 +7,13 @@ enum color_attr { COLOR_INET, COLOR_INET6, COLOR_OPERSTATE_UP, - COLOR_OPERSTATE_DOWN + COLOR_OPERSTATE_DOWN, + COLOR_CLEAR }; void enable_color(void); int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...); +enum color_attr ifa_family_color(__u8 ifa_family); +enum color_attr oper_state_color(__u8 state); #endif diff --git a/ip/ipaddress.c b/ip/ipaddress.c index f8c502940..7aab8e781 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -135,25 +135,15 @@ static const char *oper_states[] = { static void print_operstate(FILE *f, __u8 state) { - if (state >= ARRAY_SIZE(oper_states)) + if (state >= ARRAY_SIZE(oper_states)) { fprintf(f, "state %#x ", state); - else { - if (brief) { - if (strcmp(oper_states[state], "UP") == 0) - color_fprintf(f, COLOR_OPERSTATE_UP, "%-14s ", oper_states[state]); - else if (strcmp(oper_states[state], "DOWN") == 0) - color_fprintf(f, COLOR_OPERSTATE_DOWN, "%-14s ", oper_states[state]); - else - fprintf(f, "%-14s ", oper_states[state]); - } else { - fprintf(f, "state "); - if (strcmp(oper_states[state], "UP") == 0) - color_fprintf(f, COLOR_OPERSTATE_UP, "%s ", oper_states[state]); - else if (strcmp(oper_states[state], "DOWN") == 0) - color_fprintf(f, COLOR_OPERSTATE_DOWN, "%s ", oper_states[state]); - else - fprintf(f, "%s ", oper_states[state]); - } + } else if (brief) { + color_fprintf(f, oper_state_color(state), + "%-14s ", oper_states[state]); + } else { + fprintf(f, "state "); + color_fprintf(f, oper_state_color(state), + "%s ", oper_states[state]); } } @@ -1067,22 +1057,11 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, } if (rta_tb[IFA_LOCAL]) { - if (ifa->ifa_family == AF_INET) - color_fprintf(fp, COLOR_INET, "%s", format_host(ifa->ifa_family, - RTA_PAYLOAD(rta_tb[IFA_LOCAL]), - RTA_DATA(rta_tb[IFA_LOCAL]), - abuf, sizeof(abuf))); - else if (ifa->ifa_family == AF_INET6) - color_fprintf(fp, COLOR_INET6, "%s", format_host(ifa->ifa_family, - RTA_PAYLOAD(rta_tb[IFA_LOCAL]), - RTA_DATA(rta_tb[IFA_LOCAL]), - abuf, sizeof(abuf))); - else - fprintf(fp, "%s", format_host(ifa->ifa_family, - RTA_PAYLOAD(rta_tb[IFA_LOCAL]), - RTA_DATA(rta_tb[IFA_LOCAL]), - abuf, sizeof(abuf))); - + color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s", + format_host(ifa->ifa_family, + RTA_PAYLOAD(rta_tb[IFA_LOCAL]), + RTA_DATA(rta_tb[IFA_LOCAL]), + abuf, sizeof(abuf))); if (rta_tb[IFA_ADDRESS] == NULL || memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), ifa->ifa_family == AF_INET ? 4 : 16) == 0) { diff --git a/lib/color.c b/lib/color.c index 8c9a48ba7..95596be23 100644 --- a/lib/color.c +++ b/lib/color.c @@ -1,5 +1,8 @@ #include #include +#include +#include +#include #include "color.h" @@ -32,7 +35,8 @@ static enum color attr_colors[] = { C_MAGENTA, C_BLUE, C_GREEN, - C_RED + C_RED, + C_CLEAR }; static int color_is_enabled; @@ -62,3 +66,27 @@ int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...) va_end(args); return ret; } + +enum color_attr ifa_family_color(__u8 ifa_family) +{ + switch (ifa_family) { + case AF_INET: + return COLOR_INET; + case AF_INET6: + return COLOR_INET6; + default: + return COLOR_CLEAR; + } +} + +enum color_attr oper_state_color(__u8 state) +{ + switch (state) { + case IF_OPER_UP: + return COLOR_OPERSTATE_UP; + case IF_OPER_DOWN: + return COLOR_OPERSTATE_DOWN; + default: + return COLOR_CLEAR; + } +} From ff9d8f3728aff0115aa672280d06c0907eb35bbe Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 19:35:14 +0100 Subject: [PATCH 160/513] ipaddress: colorize peer, broadcast and anycast addresses as well Signed-off-by: Phil Sutter --- ip/ipaddress.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 7aab8e781..90d7b1096 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -862,7 +862,8 @@ int print_linkinfo(const struct sockaddr_nl *who, fprintf(fp, " peer "); else fprintf(fp, " brd "); - fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]), + color_fprintf(fp, COLOR_MAC, "%s", + ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]), RTA_PAYLOAD(tb[IFLA_BROADCAST]), ifi->ifi_type, b1, sizeof(b1))); @@ -1062,32 +1063,34 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, RTA_PAYLOAD(rta_tb[IFA_LOCAL]), RTA_DATA(rta_tb[IFA_LOCAL]), abuf, sizeof(abuf))); - if (rta_tb[IFA_ADDRESS] == NULL || - memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), - ifa->ifa_family == AF_INET ? 4 : 16) == 0) { - fprintf(fp, "/%d ", ifa->ifa_prefixlen); - } else { - fprintf(fp, " peer %s/%d ", - format_host(ifa->ifa_family, - RTA_PAYLOAD(rta_tb[IFA_ADDRESS]), - RTA_DATA(rta_tb[IFA_ADDRESS]), - abuf, sizeof(abuf)), - ifa->ifa_prefixlen); + if (rta_tb[IFA_ADDRESS] && + memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), + RTA_DATA(rta_tb[IFA_LOCAL]), + ifa->ifa_family == AF_INET ? 4 : 16)) { + fprintf(fp, " peer "); + color_fprintf(fp, ifa_family_color(ifa->ifa_family), + "%s", format_host(ifa->ifa_family, + RTA_PAYLOAD(rta_tb[IFA_ADDRESS]), + RTA_DATA(rta_tb[IFA_ADDRESS]), + abuf, sizeof(abuf))); } + fprintf(fp, "/%d ", ifa->ifa_prefixlen); } if (brief) goto brief_exit; if (rta_tb[IFA_BROADCAST]) { - fprintf(fp, "brd %s ", + fprintf(fp, "brd "); + color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_BROADCAST]), RTA_DATA(rta_tb[IFA_BROADCAST]), abuf, sizeof(abuf))); } if (rta_tb[IFA_ANYCAST]) { - fprintf(fp, "any %s ", + fprintf(fp, "any "); + color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_ANYCAST]), RTA_DATA(rta_tb[IFA_ANYCAST]), From a418e451643e77fe36861e53359587ba8aa41873 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 19:35:15 +0100 Subject: [PATCH 161/513] make format_host non-reentrant by default There are only three users which require it to be reentrant, the rest is fine without. Instead, provide a reentrant format_host_r() for users which need it. Signed-off-by: Phil Sutter --- bridge/fdb.c | 4 +--- include/utils.h | 3 ++- ip/ip6tunnel.c | 2 +- ip/ipaddress.c | 13 ++++--------- ip/ipaddrlabel.c | 4 +--- ip/iplink_geneve.c | 5 ++--- ip/iplink_vxlan.c | 13 ++++++------- ip/ipmaddr.c | 6 +----- ip/ipneigh.c | 4 +--- ip/iproute.c | 21 +++++++-------------- ip/iproute_lwtunnel.c | 4 +--- ip/iprule.c | 9 +++------ ip/iptoken.c | 4 +--- ip/iptunnel.c | 6 +++--- ip/link_gre.c | 5 ++--- ip/link_gre6.c | 5 ++--- ip/link_iptnl.c | 7 +++---- ip/link_vti.c | 5 ++--- ip/link_vti6.c | 5 ++--- ip/tcp_metrics.c | 6 ++---- lib/utils.c | 9 ++++++++- misc/ss.c | 4 ++-- tc/m_nat.c | 4 ++-- 23 files changed, 59 insertions(+), 89 deletions(-) diff --git a/bridge/fdb.c b/bridge/fdb.c index 88f1b63c2..e8c314a3c 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -104,7 +104,6 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex)); if (tb[NDA_DST]) { - SPRINT_BUF(abuf); int family = AF_INET; if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr)) @@ -113,8 +112,7 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "dst %s ", format_host(family, RTA_PAYLOAD(tb[NDA_DST]), - RTA_DATA(tb[NDA_DST]), - abuf, sizeof(abuf))); + RTA_DATA(tb[NDA_DST]))); } if (tb[NDA_VLAN]) { diff --git a/include/utils.h b/include/utils.h index c43427c35..84083b0db 100644 --- a/include/utils.h +++ b/include/utils.h @@ -122,8 +122,9 @@ int addr64_n2a(__u64 addr, char *buff, size_t len); int af_bit_len(int af); int af_byte_len(int af); -const char *format_host(int af, int len, const void *addr, +const char *format_host_r(int af, int len, const void *addr, char *buf, int buflen); +const char *format_host(int af, int lne, const void *addr); const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen); diff --git a/ip/ip6tunnel.c b/ip/ip6tunnel.c index 2e9d3ed40..d588645eb 100644 --- a/ip/ip6tunnel.c +++ b/ip/ip6tunnel.c @@ -77,7 +77,7 @@ static void print_tunnel(struct ip6_tnl_parm2 *p) printf("%s: %s/ipv6 remote %s local %s", p->name, tnl_strproto(p->proto), - format_host(AF_INET6, 16, &p->raddr, s1, sizeof(s1)), + format_host_r(AF_INET6, 16, &p->raddr, s1, sizeof(s1)), rt_addr_n2a(AF_INET6, 16, &p->laddr, s2, sizeof(s2))); if (p->link) { const char *n = ll_index_to_name(p->link); diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 90d7b1096..03c8c03cd 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -964,7 +964,6 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, /* Use local copy of ifa_flags to not interfere with filtering code */ unsigned int ifa_flags; struct rtattr *rta_tb[IFA_MAX+1]; - char abuf[256]; SPRINT_BUF(b1); @@ -1061,8 +1060,7 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_LOCAL]), - RTA_DATA(rta_tb[IFA_LOCAL]), - abuf, sizeof(abuf))); + RTA_DATA(rta_tb[IFA_LOCAL]))); if (rta_tb[IFA_ADDRESS] && memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), @@ -1071,8 +1069,7 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_ADDRESS]), - RTA_DATA(rta_tb[IFA_ADDRESS]), - abuf, sizeof(abuf))); + RTA_DATA(rta_tb[IFA_ADDRESS]))); } fprintf(fp, "/%d ", ifa->ifa_prefixlen); } @@ -1085,16 +1082,14 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_BROADCAST]), - RTA_DATA(rta_tb[IFA_BROADCAST]), - abuf, sizeof(abuf))); + RTA_DATA(rta_tb[IFA_BROADCAST]))); } if (rta_tb[IFA_ANYCAST]) { fprintf(fp, "any "); color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ", format_host(ifa->ifa_family, RTA_PAYLOAD(rta_tb[IFA_ANYCAST]), - RTA_DATA(rta_tb[IFA_ANYCAST]), - abuf, sizeof(abuf))); + RTA_DATA(rta_tb[IFA_ANYCAST]))); } fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1))); if (ifa_flags & IFA_F_SECONDARY) { diff --git a/ip/ipaddrlabel.c b/ip/ipaddrlabel.c index 05c44978f..6076bb952 100644 --- a/ip/ipaddrlabel.c +++ b/ip/ipaddrlabel.c @@ -60,7 +60,6 @@ int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg struct ifaddrlblmsg *ifal = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[IFAL_MAX+1]; - char abuf[256]; if (n->nlmsg_type != RTM_NEWADDRLABEL && n->nlmsg_type != RTM_DELADDRLABEL) return 0; @@ -78,8 +77,7 @@ int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg fprintf(fp, "prefix %s/%u ", format_host(ifal->ifal_family, RTA_PAYLOAD(tb[IFAL_ADDRESS]), - RTA_DATA(tb[IFAL_ADDRESS]), - abuf, sizeof(abuf)), + RTA_DATA(tb[IFAL_ADDRESS])), ifal->ifal_prefixlen); } diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c index 40c08ec27..c6e7bbe0c 100644 --- a/ip/iplink_geneve.c +++ b/ip/iplink_geneve.c @@ -138,7 +138,6 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { __u32 vni; - char s1[1024]; __u8 tos; if (!tb) @@ -156,7 +155,7 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (addr) fprintf(f, "remote %s ", - format_host(AF_INET, 4, &addr, s1, sizeof(s1))); + format_host(AF_INET, 4, &addr)); } else if (tb[IFLA_GENEVE_REMOTE6]) { struct in6_addr addr; @@ -164,7 +163,7 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) { if (IN6_IS_ADDR_MULTICAST(&addr)) fprintf(f, "remote %s ", - format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1))); + format_host(AF_INET6, sizeof(struct in6_addr), &addr)); } } diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index 5c23cf534..543522e13 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -310,7 +310,6 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) unsigned int link; __u8 tos; __u32 maxaddr; - char s1[1024]; char s2[64]; if (!tb) @@ -329,10 +328,10 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (addr) { if (IN_MULTICAST(ntohl(addr))) fprintf(f, "group %s ", - format_host(AF_INET, 4, &addr, s1, sizeof(s1))); + format_host(AF_INET, 4, &addr)); else fprintf(f, "remote %s ", - format_host(AF_INET, 4, &addr, s1, sizeof(s1))); + format_host(AF_INET, 4, &addr)); } } else if (tb[IFLA_VXLAN_GROUP6]) { struct in6_addr addr; @@ -341,10 +340,10 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) { if (IN6_IS_ADDR_MULTICAST(&addr)) fprintf(f, "group %s ", - format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1))); + format_host(AF_INET6, sizeof(struct in6_addr), &addr)); else fprintf(f, "remote %s ", - format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1))); + format_host(AF_INET6, sizeof(struct in6_addr), &addr)); } } @@ -353,14 +352,14 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (addr) fprintf(f, "local %s ", - format_host(AF_INET, 4, &addr, s1, sizeof(s1))); + format_host(AF_INET, 4, &addr)); } else if (tb[IFLA_VXLAN_LOCAL6]) { struct in6_addr addr; memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_LOCAL6]), sizeof(struct in6_addr)); if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) fprintf(f, "local %s ", - format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1))); + format_host(AF_INET6, sizeof(struct in6_addr), &addr)); } if (tb[IFLA_VXLAN_LINK] && diff --git a/ip/ipmaddr.c b/ip/ipmaddr.c index 347990b5c..c3673979f 100644 --- a/ip/ipmaddr.c +++ b/ip/ipmaddr.c @@ -204,8 +204,6 @@ static void print_maddr(FILE *fp, struct ma_info *list) list->addr.bytelen, 0, b1, sizeof(b1))); } else { - char abuf[256]; - switch (list->addr.family) { case AF_INET: fprintf(fp, "inet "); @@ -219,9 +217,7 @@ static void print_maddr(FILE *fp, struct ma_info *list) } fprintf(fp, "%s", format_host(list->addr.family, - -1, - list->addr.data, - abuf, sizeof(abuf))); + -1, list->addr.data)); } if (list->users != 1) fprintf(fp, " users %d", list->users); diff --git a/ip/ipneigh.c b/ip/ipneigh.c index 6458c8eaa..583aad30d 100644 --- a/ip/ipneigh.c +++ b/ip/ipneigh.c @@ -198,7 +198,6 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) struct ndmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[NDA_MAX+1]; - char abuf[256]; static int logit = 1; if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH && @@ -281,8 +280,7 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "%s ", format_host(r->ndm_family, RTA_PAYLOAD(tb[NDA_DST]), - RTA_DATA(tb[NDA_DST]), - abuf, sizeof(abuf))); + RTA_DATA(tb[NDA_DST]))); } if (!filter.index && r->ndm_ifindex) fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex)); diff --git a/ip/iproute.c b/ip/iproute.c index 19b28701d..8315ad3e6 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -380,8 +380,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) } else { fprintf(fp, "%s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), - RTA_DATA(tb[RTA_DST]), - abuf, sizeof(abuf)) + RTA_DATA(tb[RTA_DST])) ); } } else if (r->rtm_dst_len) { @@ -400,8 +399,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) } else { fprintf(fp, "from %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), - RTA_DATA(tb[RTA_SRC]), - abuf, sizeof(abuf)) + RTA_DATA(tb[RTA_SRC])) ); } } else if (r->rtm_src_len) { @@ -410,8 +408,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[RTA_NEWDST]) { fprintf(fp, "as to %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_NEWDST]), - RTA_DATA(tb[RTA_NEWDST]), - abuf, sizeof(abuf)) + RTA_DATA(tb[RTA_NEWDST])) ); } @@ -427,8 +424,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "via %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_GATEWAY]), - RTA_DATA(tb[RTA_GATEWAY]), - abuf, sizeof(abuf))); + RTA_DATA(tb[RTA_GATEWAY]))); } if (tb[RTA_VIA]) { size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2; @@ -436,8 +432,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "via %s %s ", family_name(via->rtvia_family), - format_host(via->rtvia_family, len, via->rtvia_addr, - abuf, sizeof(abuf))); + format_host(via->rtvia_family, len, via->rtvia_addr)); } if (tb[RTA_OIF] && filter.oifmask != -1) fprintf(fp, "dev %s ", ll_index_to_name(*(int *)RTA_DATA(tb[RTA_OIF]))); @@ -671,8 +666,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, " via %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_GATEWAY]), - RTA_DATA(tb[RTA_GATEWAY]), - abuf, sizeof(abuf))); + RTA_DATA(tb[RTA_GATEWAY]))); } if (tb[RTA_VIA]) { size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2; @@ -680,8 +674,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "via %s %s ", family_name(via->rtvia_family), - format_host(via->rtvia_family, len, via->rtvia_addr, - abuf, sizeof(abuf))); + format_host(via->rtvia_family, len, via->rtvia_addr)); } if (tb[RTA_FLOW]) { __u32 to = rta_getattr_u32(tb[RTA_FLOW]); diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index a53e11d94..42abe3753 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -58,15 +58,13 @@ static const char *format_encap_type(int type) static void print_encap_mpls(FILE *fp, struct rtattr *encap) { struct rtattr *tb[MPLS_IPTUNNEL_MAX+1]; - char abuf[256]; parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap); if (tb[MPLS_IPTUNNEL_DST]) fprintf(fp, " %s ", format_host(AF_MPLS, RTA_PAYLOAD(tb[MPLS_IPTUNNEL_DST]), - RTA_DATA(tb[MPLS_IPTUNNEL_DST]), - abuf, sizeof(abuf))); + RTA_DATA(tb[MPLS_IPTUNNEL_DST]))); } static void print_encap_ip(FILE *fp, struct rtattr *encap) diff --git a/ip/iprule.c b/ip/iprule.c index dc45c6b43..345b3b042 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -94,8 +94,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) } else { fprintf(fp, "from %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[FRA_SRC]), - RTA_DATA(tb[FRA_SRC]), - abuf, sizeof(abuf)) + RTA_DATA(tb[FRA_SRC])) ); } } else if (r->rtm_src_len) { @@ -115,8 +114,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) } else { fprintf(fp, "to %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[FRA_DST]), - RTA_DATA(tb[FRA_DST]), - abuf, sizeof(abuf))); + RTA_DATA(tb[FRA_DST]))); } } else if (r->rtm_dst_len) { fprintf(fp, "to 0/%d ", r->rtm_dst_len); @@ -191,8 +189,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "map-to %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_GATEWAY]), - RTA_DATA(tb[RTA_GATEWAY]), - abuf, sizeof(abuf))); + RTA_DATA(tb[RTA_GATEWAY]))); } else fprintf(fp, "masquerade"); } else if (r->rtm_type == FR_ACT_GOTO) { diff --git a/ip/iptoken.c b/ip/iptoken.c index 1d22c03c6..02fe98e24 100644 --- a/ip/iptoken.c +++ b/ip/iptoken.c @@ -51,7 +51,6 @@ static int print_token(const struct sockaddr_nl *who, struct nlmsghdr *n, void * int len = n->nlmsg_len; struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *ltb[IFLA_INET6_MAX + 1]; - char abuf[256]; if (n->nlmsg_type != RTM_NEWLINK) return -1; @@ -82,8 +81,7 @@ static int print_token(const struct sockaddr_nl *who, struct nlmsghdr *n, void * fprintf(fp, "token %s ", format_host(ifi->ifi_family, RTA_PAYLOAD(ltb[IFLA_INET6_TOKEN]), - RTA_DATA(ltb[IFLA_INET6_TOKEN]), - abuf, sizeof(abuf))); + RTA_DATA(ltb[IFLA_INET6_TOKEN]))); fprintf(fp, "dev %s ", ll_index_to_name(ifi->ifi_index)); fprintf(fp, "\n"); fflush(fp); diff --git a/ip/iptunnel.c b/ip/iptunnel.c index 65a4e6e9c..bfee99561 100644 --- a/ip/iptunnel.c +++ b/ip/iptunnel.c @@ -308,7 +308,7 @@ static void print_tunnel(struct ip_tunnel_parm *p) printf("%s: %s/ip remote %s local %s", p->name, tnl_strproto(p->iph.protocol), - p->iph.daddr ? format_host(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1)) : "any", + p->iph.daddr ? format_host_r(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1)) : "any", p->iph.saddr ? rt_addr_n2a(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)) : "any"); if (p->iph.protocol == IPPROTO_IPV6 && (p->i_flags & SIT_ISATAP)) { @@ -324,7 +324,7 @@ static void print_tunnel(struct ip_tunnel_parm *p) if (prl[i].addr != htonl(INADDR_ANY)) { printf(" %s %s ", (prl[i].flags & PRL_DEFAULT) ? "pdr" : "pr", - format_host(AF_INET, 4, &prl[i].addr, s1, sizeof(s1))); + format_host(AF_INET, 4, &prl[i].addr)); } } } @@ -360,7 +360,7 @@ static void print_tunnel(struct ip_tunnel_parm *p) ip6rd.prefixlen); if (ip6rd.relay_prefix) { printf(" 6rd-relay_prefix %s/%u", - format_host(AF_INET, 4, &ip6rd.relay_prefix, s1, sizeof(s1)), + format_host(AF_INET, 4, &ip6rd.relay_prefix), ip6rd.relay_prefixlen); } } diff --git a/ip/link_gre.c b/ip/link_gre.c index c50963d79..bcf003aaa 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -339,7 +339,6 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { - char s1[1024]; char s2[64]; const char *local = "any"; const char *remote = "any"; @@ -353,7 +352,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_REMOTE]); if (addr) - remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); + remote = format_host(AF_INET, 4, &addr); } fprintf(f, "remote %s ", remote); @@ -362,7 +361,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_LOCAL]); if (addr) - local = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); + local = format_host(AF_INET, 4, &addr); } fprintf(f, "local %s ", local); diff --git a/ip/link_gre6.c b/ip/link_gre6.c index a48ea8b1e..bddfc0ff9 100644 --- a/ip/link_gre6.c +++ b/ip/link_gre6.c @@ -302,7 +302,6 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { - char s1[1024]; char s2[64]; const char *local = "any"; const char *remote = "any"; @@ -327,7 +326,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) memcpy(&addr, RTA_DATA(tb[IFLA_GRE_REMOTE]), sizeof(addr)); if (memcmp(&addr, &in6_addr_any, sizeof(addr))) - remote = format_host(AF_INET6, sizeof(addr), &addr, s1, sizeof(s1)); + remote = format_host(AF_INET6, sizeof(addr), &addr); } fprintf(f, "remote %s ", remote); @@ -338,7 +337,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) memcpy(&addr, RTA_DATA(tb[IFLA_GRE_LOCAL]), sizeof(addr)); if (memcmp(&addr, &in6_addr_any, sizeof(addr))) - local = format_host(AF_INET6, sizeof(addr), &addr, s1, sizeof(s1)); + local = format_host(AF_INET6, sizeof(addr), &addr); } fprintf(f, "local %s ", local); diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c index 04568ffbd..8411a6a00 100644 --- a/ip/link_iptnl.c +++ b/ip/link_iptnl.c @@ -339,7 +339,7 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[ unsigned int addr = rta_getattr_u32(tb[IFLA_IPTUN_REMOTE]); if (addr) - remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); + remote = format_host(AF_INET, 4, &addr); } fprintf(f, "remote %s ", remote); @@ -348,7 +348,7 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[ unsigned int addr = rta_getattr_u32(tb[IFLA_IPTUN_LOCAL]); if (addr) - local = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); + local = format_host(AF_INET, 4, &addr); } fprintf(f, "local %s ", local); @@ -404,8 +404,7 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[ prefixlen); if (relayprefix) { printf("6rd-relay_prefix %s/%u ", - format_host(AF_INET, 4, &relayprefix, s1, - sizeof(s1)), + format_host(AF_INET, 4, &relayprefix), relayprefixlen); } } diff --git a/ip/link_vti.c b/ip/link_vti.c index 587993035..8052e7514 100644 --- a/ip/link_vti.c +++ b/ip/link_vti.c @@ -198,7 +198,6 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv, static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { - char s1[1024]; char s2[64]; const char *local = "any"; const char *remote = "any"; @@ -210,7 +209,7 @@ static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) unsigned int addr = *(__u32 *)RTA_DATA(tb[IFLA_VTI_REMOTE]); if (addr) - remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); + remote = format_host(AF_INET, 4, &addr); } fprintf(f, "remote %s ", remote); @@ -219,7 +218,7 @@ static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) unsigned int addr = *(__u32 *)RTA_DATA(tb[IFLA_VTI_LOCAL]); if (addr) - local = format_host(AF_INET, 4, &addr, s1, sizeof(s1)); + local = format_host(AF_INET, 4, &addr); } fprintf(f, "local %s ", local); diff --git a/ip/link_vti6.c b/ip/link_vti6.c index 9a62eb5aa..9bcf7fe9d 100644 --- a/ip/link_vti6.c +++ b/ip/link_vti6.c @@ -197,7 +197,6 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { - char s1[1024]; char s2[64]; const char *local = "any"; const char *remote = "any"; @@ -210,7 +209,7 @@ static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_VTI_REMOTE]) { memcpy(&daddr, RTA_DATA(tb[IFLA_VTI_REMOTE]), sizeof(daddr)); - remote = format_host(AF_INET6, 16, &daddr, s1, sizeof(s1)); + remote = format_host(AF_INET6, 16, &daddr); } fprintf(f, "remote %s ", remote); @@ -218,7 +217,7 @@ static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_VTI_LOCAL]) { memcpy(&saddr, RTA_DATA(tb[IFLA_VTI_LOCAL]), sizeof(saddr)); - local = format_host(AF_INET6, 16, &saddr, s1, sizeof(s1)); + local = format_host(AF_INET6, 16, &saddr); } fprintf(f, "local %s ", local); diff --git a/ip/tcp_metrics.c b/ip/tcp_metrics.c index 3a6499171..f82604f45 100644 --- a/ip/tcp_metrics.c +++ b/ip/tcp_metrics.c @@ -95,7 +95,6 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, struct genlmsghdr *ghdr; struct rtattr *attrs[TCP_METRICS_ATTR_MAX + 1], *a; int len = n->nlmsg_len; - char abuf[256]; inet_prefix daddr, saddr; int family, i, atype, stype, dlen = 0, slen = 0; @@ -194,7 +193,7 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, fprintf(fp, "Deleted "); fprintf(fp, "%s", - format_host(family, dlen, &daddr.data, abuf, sizeof(abuf))); + format_host(family, dlen, &daddr.data)); a = attrs[TCP_METRICS_ATTR_AGE]; if (a) { @@ -298,8 +297,7 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, if (slen) { fprintf(fp, " source %s", - format_host(family, slen, &saddr.data, abuf, - sizeof(abuf))); + format_host(family, slen, &saddr.data)); } fprintf(fp, "\n"); diff --git a/lib/utils.c b/lib/utils.c index fa35f4d04..22a5ef8fa 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -818,7 +818,7 @@ static const char *resolve_address(const void *addr, int len, int af) } #endif -const char *format_host(int af, int len, const void *addr, +const char *format_host_r(int af, int len, const void *addr, char *buf, int buflen) { #ifdef RESOLVE_HOSTNAMES @@ -835,6 +835,13 @@ const char *format_host(int af, int len, const void *addr, return rt_addr_n2a(af, len, addr, buf, buflen); } +const char *format_host(int af, int len, const void *addr) +{ + static char buf[256]; + + return format_host_r(af, len, addr, buf, 256); +} + char *hexstring_n2a(const __u8 *str, int len, char *buf, int blen) { diff --git a/misc/ss.c b/misc/ss.c index 192389cc8..38cf3312a 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -1016,10 +1016,10 @@ static void inet_addr_print(const inet_prefix *a, int port, unsigned int ifindex buf[0] = '*'; buf[1] = 0; } else { - ap = format_host(AF_INET, 4, a->data, buf, sizeof(buf)); + ap = format_host(AF_INET, 4, a->data); } } else { - ap = format_host(a->family, 16, a->data, buf, sizeof(buf)); + ap = format_host(a->family, 16, a->data); est_len = strlen(ap); if (est_len <= addr_width) est_len = addr_width; diff --git a/tc/m_nat.c b/tc/m_nat.c index deb071da9..4b90121c4 100644 --- a/tc/m_nat.c +++ b/tc/m_nat.c @@ -191,9 +191,9 @@ print_nat(struct action_util *au, FILE * f, struct rtattr *arg) fprintf(f, " nat %s %s/%d %s %s", sel->flags & TCA_NAT_FLAG_EGRESS ? "egress" : "ingress", - format_host(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)), + format_host_r(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)), len, - format_host(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)), + format_host_r(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)), action_n2a(sel->action, buf3, sizeof(buf3))); if (show_stats) { From 2e96d2ccd03a29896fc8a2c6ee6b769c512501df Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 19:35:16 +0100 Subject: [PATCH 162/513] utils: make rt_addr_n2a() non-reentrant by default There is only a single user who needs it to be reentrant (not really, but it's safer like this), add rt_addr_n2a_r() for it to use. Signed-off-by: Phil Sutter --- include/utils.h | 3 ++- ip/ip6tunnel.c | 2 +- ip/iplink_bond.c | 5 +---- ip/ipmroute.c | 7 ++----- ip/ipprefix.c | 5 +---- ip/iproute.c | 10 +++------- ip/iproute_lwtunnel.c | 7 ++----- ip/iprule.c | 8 ++------ ip/iptunnel.c | 2 +- ip/ipxfrm.c | 29 ++++++----------------------- ip/link_ip6tnl.c | 7 ++----- ip/xfrm_monitor.c | 16 +++------------- lib/utils.c | 11 +++++++++-- tc/f_flower.c | 7 ++----- 14 files changed, 37 insertions(+), 82 deletions(-) diff --git a/include/utils.h b/include/utils.h index 84083b0db..bc2cbce0c 100644 --- a/include/utils.h +++ b/include/utils.h @@ -125,8 +125,9 @@ int af_byte_len(int af); const char *format_host_r(int af, int len, const void *addr, char *buf, int buflen); const char *format_host(int af, int lne, const void *addr); -const char *rt_addr_n2a(int af, int len, const void *addr, +const char *rt_addr_n2a_r(int af, int len, const void *addr, char *buf, int buflen); +const char *rt_addr_n2a(int af, int len, const void *addr); int read_family(const char *name); const char *family_name(int family); diff --git a/ip/ip6tunnel.c b/ip/ip6tunnel.c index d588645eb..c02fa0746 100644 --- a/ip/ip6tunnel.c +++ b/ip/ip6tunnel.c @@ -78,7 +78,7 @@ static void print_tunnel(struct ip6_tnl_parm2 *p) p->name, tnl_strproto(p->proto), format_host_r(AF_INET6, 16, &p->raddr, s1, sizeof(s1)), - rt_addr_n2a(AF_INET6, 16, &p->laddr, s2, sizeof(s2))); + rt_addr_n2a_r(AF_INET6, 16, &p->laddr, s2, sizeof(s2))); if (p->link) { const char *n = ll_index_to_name(p->link); diff --git a/ip/iplink_bond.c b/ip/iplink_bond.c index 45473f66d..7da58e455 100644 --- a/ip/iplink_bond.c +++ b/ip/iplink_bond.c @@ -411,7 +411,6 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_BOND_ARP_IP_TARGET]) { struct rtattr *iptb[BOND_MAX_ARP_TARGETS + 1]; - char buf[INET_ADDRSTRLEN]; int i; parse_rtattr_nested(iptb, BOND_MAX_ARP_TARGETS, @@ -425,9 +424,7 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fprintf(f, "%s", rt_addr_n2a(AF_INET, RTA_PAYLOAD(iptb[i]), - RTA_DATA(iptb[i]), - buf, - INET_ADDRSTRLEN)); + RTA_DATA(iptb[i]))); if (i < BOND_MAX_ARP_TARGETS-1 && iptb[i+1]) fprintf(f, ","); } diff --git a/ip/ipmroute.c b/ip/ipmroute.c index 34543c00e..2b9f892a6 100644 --- a/ip/ipmroute.c +++ b/ip/ipmroute.c @@ -58,7 +58,6 @@ int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[RTA_MAX+1]; - char abuf[256]; char obuf[256]; SPRINT_BUF(b1); @@ -126,16 +125,14 @@ int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) len = snprintf(obuf, sizeof(obuf), "(%s, ", rt_addr_n2a(family, RTA_PAYLOAD(tb[RTA_SRC]), - RTA_DATA(tb[RTA_SRC]), - abuf, sizeof(abuf))); + RTA_DATA(tb[RTA_SRC]))); else len = sprintf(obuf, "(unknown, "); if (tb[RTA_DST]) snprintf(obuf + len, sizeof(obuf) - len, "%s)", rt_addr_n2a(family, RTA_PAYLOAD(tb[RTA_DST]), - RTA_DATA(tb[RTA_DST]), - abuf, sizeof(abuf))); + RTA_DATA(tb[RTA_DST]))); else snprintf(obuf + len, sizeof(obuf) - len, "unknown) "); diff --git a/ip/ipprefix.c b/ip/ipprefix.c index 2524f7849..4d986dbc1 100644 --- a/ip/ipprefix.c +++ b/ip/ipprefix.c @@ -75,15 +75,12 @@ int print_prefix(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[PREFIX_ADDRESS]) { struct in6_addr *pfx; - char abuf[256]; pfx = (struct in6_addr *)RTA_DATA(tb[PREFIX_ADDRESS]); - memset(abuf, '\0', sizeof(abuf)); fprintf(fp, "%s", rt_addr_n2a(family, RTA_PAYLOAD(tb[PREFIX_ADDRESS]), - pfx, - abuf, sizeof(abuf))); + pfx)); } fprintf(fp, "/%u ", prefix->prefix_len); diff --git a/ip/iproute.c b/ip/iproute.c index 8315ad3e6..1ec929429 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -318,7 +318,6 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[RTA_MAX+1]; - char abuf[256]; int host_len; __u32 table; @@ -373,8 +372,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (r->rtm_dst_len != host_len) { fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), - RTA_DATA(tb[RTA_DST]), - abuf, sizeof(abuf)), + RTA_DATA(tb[RTA_DST])), r->rtm_dst_len ); } else { @@ -392,8 +390,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), - RTA_DATA(tb[RTA_SRC]), - abuf, sizeof(abuf)), + RTA_DATA(tb[RTA_SRC])), r->rtm_src_len ); } else { @@ -452,8 +449,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, " src %s ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_PREFSRC]), - RTA_DATA(tb[RTA_PREFSRC]), - abuf, sizeof(abuf))); + RTA_DATA(tb[RTA_PREFSRC]))); } if (tb[RTA_PRIORITY]) fprintf(fp, " metric %u ", rta_getattr_u32(tb[RTA_PRIORITY])); diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 42abe3753..53d3ad4e6 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -70,7 +70,6 @@ static void print_encap_mpls(FILE *fp, struct rtattr *encap) static void print_encap_ip(FILE *fp, struct rtattr *encap) { struct rtattr *tb[LWTUNNEL_IP_MAX+1]; - char abuf[256]; parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap); @@ -81,15 +80,13 @@ static void print_encap_ip(FILE *fp, struct rtattr *encap) fprintf(fp, "src %s ", rt_addr_n2a(AF_INET, RTA_PAYLOAD(tb[LWTUNNEL_IP_SRC]), - RTA_DATA(tb[LWTUNNEL_IP_SRC]), - abuf, sizeof(abuf))); + RTA_DATA(tb[LWTUNNEL_IP_SRC]))); if (tb[LWTUNNEL_IP_DST]) fprintf(fp, "dst %s ", rt_addr_n2a(AF_INET, RTA_PAYLOAD(tb[LWTUNNEL_IP_DST]), - RTA_DATA(tb[LWTUNNEL_IP_DST]), - abuf, sizeof(abuf))); + RTA_DATA(tb[LWTUNNEL_IP_DST]))); if (tb[LWTUNNEL_IP_TTL]) fprintf(fp, "ttl %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL])); diff --git a/ip/iprule.c b/ip/iprule.c index 345b3b042..3fd510efe 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -57,8 +57,6 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) int host_len = -1; __u32 table; struct rtattr *tb[FRA_MAX+1]; - char abuf[256]; - SPRINT_BUF(b1); if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE) @@ -87,8 +85,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[FRA_SRC]), - RTA_DATA(tb[FRA_SRC]), - abuf, sizeof(abuf)), + RTA_DATA(tb[FRA_SRC])), r->rtm_src_len ); } else { @@ -107,8 +104,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (r->rtm_dst_len != host_len) { fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[FRA_DST]), - RTA_DATA(tb[FRA_DST]), - abuf, sizeof(abuf)), + RTA_DATA(tb[FRA_DST])), r->rtm_dst_len ); } else { diff --git a/ip/iptunnel.c b/ip/iptunnel.c index bfee99561..e3161d81b 100644 --- a/ip/iptunnel.c +++ b/ip/iptunnel.c @@ -309,7 +309,7 @@ static void print_tunnel(struct ip_tunnel_parm *p) p->name, tnl_strproto(p->iph.protocol), p->iph.daddr ? format_host_r(AF_INET, 4, &p->iph.daddr, s1, sizeof(s1)) : "any", - p->iph.saddr ? rt_addr_n2a(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)) : "any"); + p->iph.saddr ? rt_addr_n2a_r(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)) : "any"); if (p->iph.protocol == IPPROTO_IPV6 && (p->i_flags & SIT_ISATAP)) { struct ip_tunnel_prl prl[16]; diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c index 860414d37..8741ff3b3 100644 --- a/ip/ipxfrm.c +++ b/ip/ipxfrm.c @@ -285,17 +285,11 @@ void xfrm_id_info_print(xfrm_address_t *saddr, struct xfrm_id *id, __u8 mode, __u32 reqid, __u16 family, int force_spi, FILE *fp, const char *prefix, const char *title) { - char abuf[256]; - if (title) fputs(title, fp); - memset(abuf, '\0', sizeof(abuf)); - fprintf(fp, "src %s ", rt_addr_n2a(family, sizeof(*saddr), - saddr, abuf, sizeof(abuf))); - memset(abuf, '\0', sizeof(abuf)); - fprintf(fp, "dst %s", rt_addr_n2a(family, sizeof(id->daddr), - &id->daddr, abuf, sizeof(abuf))); + fprintf(fp, "src %s ", rt_addr_n2a(family, sizeof(*saddr), saddr)); + fprintf(fp, "dst %s", rt_addr_n2a(family, sizeof(id->daddr), &id->daddr)); fprintf(fp, "%s", _SL_); if (prefix) @@ -447,7 +441,6 @@ void xfrm_lifetime_print(struct xfrm_lifetime_cfg *cfg, void xfrm_selector_print(struct xfrm_selector *sel, __u16 family, FILE *fp, const char *prefix) { - char abuf[256]; __u16 f; f = sel->family; @@ -459,16 +452,12 @@ void xfrm_selector_print(struct xfrm_selector *sel, __u16 family, if (prefix) fputs(prefix, fp); - memset(abuf, '\0', sizeof(abuf)); fprintf(fp, "src %s/%u ", - rt_addr_n2a(f, sizeof(sel->saddr), &sel->saddr, - abuf, sizeof(abuf)), + rt_addr_n2a(f, sizeof(sel->saddr), &sel->saddr), sel->prefixlen_s); - memset(abuf, '\0', sizeof(abuf)); fprintf(fp, "dst %s/%u ", - rt_addr_n2a(f, sizeof(sel->daddr), &sel->daddr, - abuf, sizeof(abuf)), + rt_addr_n2a(f, sizeof(sel->daddr), &sel->daddr), sel->prefixlen_d); if (sel->proto) @@ -740,7 +729,6 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, if (tb[XFRMA_ENCAP]) { struct xfrm_encap_tmpl *e; - char abuf[256]; if (prefix) fputs(prefix, fp); @@ -768,10 +756,8 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, fprintf(fp, "sport %u ", ntohs(e->encap_sport)); fprintf(fp, "dport %u ", ntohs(e->encap_dport)); - memset(abuf, '\0', sizeof(abuf)); fprintf(fp, "addr %s", - rt_addr_n2a(family, sizeof(e->encap_oa), &e->encap_oa, - abuf, sizeof(abuf))); + rt_addr_n2a(family, sizeof(e->encap_oa), &e->encap_oa)); fprintf(fp, "%s", _SL_); } @@ -783,7 +769,6 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, } if (tb[XFRMA_COADDR]) { - char abuf[256]; xfrm_address_t *coa; if (prefix) @@ -798,10 +783,8 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, return; } - memset(abuf, '\0', sizeof(abuf)); fprintf(fp, "%s", - rt_addr_n2a(family, sizeof(*coa), coa, - abuf, sizeof(abuf))); + rt_addr_n2a(family, sizeof(*coa), coa)); fprintf(fp, "%s", _SL_); } diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c index ab5e50a20..4b32fe5aa 100644 --- a/ip/link_ip6tnl.c +++ b/ip/link_ip6tnl.c @@ -260,7 +260,6 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { - char s1[256]; char s2[64]; int flags = 0; __u32 flowinfo = 0; @@ -292,16 +291,14 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb fprintf(f, "remote %s ", rt_addr_n2a(AF_INET6, RTA_PAYLOAD(tb[IFLA_IPTUN_REMOTE]), - RTA_DATA(tb[IFLA_IPTUN_REMOTE]), - s1, sizeof(s1))); + RTA_DATA(tb[IFLA_IPTUN_REMOTE]))); } if (tb[IFLA_IPTUN_LOCAL]) { fprintf(f, "local %s ", rt_addr_n2a(AF_INET6, RTA_PAYLOAD(tb[IFLA_IPTUN_LOCAL]), - RTA_DATA(tb[IFLA_IPTUN_LOCAL]), - s1, sizeof(s1))); + RTA_DATA(tb[IFLA_IPTUN_LOCAL]))); } if (tb[IFLA_IPTUN_LINK] && rta_getattr_u32(tb[IFLA_IPTUN_LINK])) { diff --git a/ip/xfrm_monitor.c b/ip/xfrm_monitor.c index 96b52a44b..9d01a2aab 100644 --- a/ip/xfrm_monitor.c +++ b/ip/xfrm_monitor.c @@ -227,12 +227,8 @@ static void xfrm_ae_flags_print(__u32 flags, void *arg) static void xfrm_usersa_print(const struct xfrm_usersa_id *sa_id, __u32 reqid, FILE *fp) { - char buf[256]; - - buf[0] = 0; fprintf(fp, "dst %s ", - rt_addr_n2a(sa_id->family, sizeof(sa_id->daddr), &sa_id->daddr, - buf, sizeof(buf))); + rt_addr_n2a(sa_id->family, sizeof(sa_id->daddr), &sa_id->daddr)); fprintf(fp, " reqid 0x%x", reqid); @@ -245,15 +241,12 @@ static int xfrm_ae_print(const struct sockaddr_nl *who, { FILE *fp = (FILE *)arg; struct xfrm_aevent_id *id = NLMSG_DATA(n); - char abuf[256]; fprintf(fp, "Async event "); xfrm_ae_flags_print(id->flags, arg); fprintf(fp, "\n\t"); - memset(abuf, '\0', sizeof(abuf)); fprintf(fp, "src %s ", rt_addr_n2a(id->sa_id.family, - sizeof(id->saddr), &id->saddr, - abuf, sizeof(abuf))); + sizeof(id->saddr), &id->saddr)); xfrm_usersa_print(&id->sa_id, id->reqid, fp); @@ -265,10 +258,7 @@ static int xfrm_ae_print(const struct sockaddr_nl *who, static void xfrm_print_addr(FILE *fp, int family, xfrm_address_t *a) { - char buf[256]; - - buf[0] = 0; - fprintf(fp, "%s", rt_addr_n2a(family, sizeof(*a), a, buf, sizeof(buf))); + fprintf(fp, "%s", rt_addr_n2a(family, sizeof(*a), a)); } static int xfrm_mapping_print(const struct sockaddr_nl *who, diff --git a/lib/utils.c b/lib/utils.c index 22a5ef8fa..9b303a6b0 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -702,7 +702,7 @@ int __get_user_hz(void) return sysconf(_SC_CLK_TCK); } -const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen) +const char *rt_addr_n2a_r(int af, int len, const void *addr, char *buf, int buflen) { switch (af) { case AF_INET: @@ -725,6 +725,13 @@ const char *rt_addr_n2a(int af, int len, const void *addr, char *buf, int buflen } } +const char *rt_addr_n2a(int af, int len, const void *addr) +{ + static char buf[256]; + + return rt_addr_n2a_r(af, len, addr, buf, 256); +} + int read_family(const char *name) { int family = AF_UNSPEC; @@ -832,7 +839,7 @@ const char *format_host_r(int af, int len, const void *addr, return n; } #endif - return rt_addr_n2a(af, len, addr, buf, buflen); + return rt_addr_n2a_r(af, len, addr, buf, buflen); } const char *format_host(int af, int len, const void *addr) diff --git a/tc/f_flower.c b/tc/f_flower.c index 6139fe086..40f8c595b 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -394,7 +394,6 @@ static void flower_print_ip_addr(FILE *f, char *name, __be16 eth_type, struct rtattr *addr6_attr, struct rtattr *mask6_attr) { - SPRINT_BUF(b1); struct rtattr *addr_attr; struct rtattr *mask_attr; int family; @@ -418,16 +417,14 @@ static void flower_print_ip_addr(FILE *f, char *name, __be16 eth_type, return; fprintf(f, "\n %s %s", name, rt_addr_n2a(family, RTA_PAYLOAD(addr_attr), - RTA_DATA(addr_attr), - b1, sizeof(b1))); + RTA_DATA(addr_attr))); if (!mask_attr || RTA_PAYLOAD(mask_attr) != len) return; bits = __mask_bits(RTA_DATA(mask_attr), len); if (bits < 0) fprintf(f, "/%s", rt_addr_n2a(family, RTA_PAYLOAD(mask_attr), - RTA_DATA(mask_attr), - b1, sizeof(b1))); + RTA_DATA(mask_attr))); else if (bits < len * 8) fprintf(f, "/%d", bits); } From d49f934c1019cf92a500b951e21ae7cbc46ca7c7 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 19:35:17 +0100 Subject: [PATCH 163/513] lib/utils: introduce format_host_rta() This simple macro eases calling format_host() with data from an rt_attr pointer. Signed-off-by: Phil Sutter --- include/utils.h | 2 ++ ip/ipaddress.c | 20 ++++++++------------ ip/ipaddrlabel.c | 5 ++--- ip/ipneigh.c | 4 +--- ip/iproute.c | 33 +++++++++++---------------------- ip/iproute_lwtunnel.c | 5 ++--- ip/iprule.c | 16 ++++++---------- ip/iptoken.c | 9 +++------ 8 files changed, 35 insertions(+), 59 deletions(-) diff --git a/include/utils.h b/include/utils.h index bc2cbce0c..ebb80c9c2 100644 --- a/include/utils.h +++ b/include/utils.h @@ -125,6 +125,8 @@ int af_byte_len(int af); const char *format_host_r(int af, int len, const void *addr, char *buf, int buflen); const char *format_host(int af, int lne, const void *addr); +#define format_host_rta(af, rta) \ + format_host(af, RTA_PAYLOAD(rta), RTA_DATA(rta)) const char *rt_addr_n2a_r(int af, int len, const void *addr, char *buf, int buflen); const char *rt_addr_n2a(int af, int len, const void *addr); diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 03c8c03cd..3998d8cec 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -1058,18 +1058,16 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, if (rta_tb[IFA_LOCAL]) { color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s", - format_host(ifa->ifa_family, - RTA_PAYLOAD(rta_tb[IFA_LOCAL]), - RTA_DATA(rta_tb[IFA_LOCAL]))); + format_host_rta(ifa->ifa_family, + rta_tb[IFA_LOCAL])); if (rta_tb[IFA_ADDRESS] && memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), ifa->ifa_family == AF_INET ? 4 : 16)) { fprintf(fp, " peer "); color_fprintf(fp, ifa_family_color(ifa->ifa_family), - "%s", format_host(ifa->ifa_family, - RTA_PAYLOAD(rta_tb[IFA_ADDRESS]), - RTA_DATA(rta_tb[IFA_ADDRESS]))); + "%s", format_host_rta(ifa->ifa_family, + rta_tb[IFA_ADDRESS])); } fprintf(fp, "/%d ", ifa->ifa_prefixlen); } @@ -1080,16 +1078,14 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, if (rta_tb[IFA_BROADCAST]) { fprintf(fp, "brd "); color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ", - format_host(ifa->ifa_family, - RTA_PAYLOAD(rta_tb[IFA_BROADCAST]), - RTA_DATA(rta_tb[IFA_BROADCAST]))); + format_host_rta(ifa->ifa_family, + rta_tb[IFA_BROADCAST])); } if (rta_tb[IFA_ANYCAST]) { fprintf(fp, "any "); color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ", - format_host(ifa->ifa_family, - RTA_PAYLOAD(rta_tb[IFA_ANYCAST]), - RTA_DATA(rta_tb[IFA_ANYCAST]))); + format_host_rta(ifa->ifa_family, + rta_tb[IFA_ANYCAST])); } fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1))); if (ifa_flags & IFA_F_SECONDARY) { diff --git a/ip/ipaddrlabel.c b/ip/ipaddrlabel.c index 6076bb952..b4cd78409 100644 --- a/ip/ipaddrlabel.c +++ b/ip/ipaddrlabel.c @@ -75,9 +75,8 @@ int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg if (tb[IFAL_ADDRESS]) { fprintf(fp, "prefix %s/%u ", - format_host(ifal->ifal_family, - RTA_PAYLOAD(tb[IFAL_ADDRESS]), - RTA_DATA(tb[IFAL_ADDRESS])), + format_host_rta(ifal->ifal_family, + tb[IFAL_ADDRESS]), ifal->ifal_prefixlen); } diff --git a/ip/ipneigh.c b/ip/ipneigh.c index 583aad30d..c49fb4e7f 100644 --- a/ip/ipneigh.c +++ b/ip/ipneigh.c @@ -278,9 +278,7 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "miss "); if (tb[NDA_DST]) { fprintf(fp, "%s ", - format_host(r->ndm_family, - RTA_PAYLOAD(tb[NDA_DST]), - RTA_DATA(tb[NDA_DST]))); + format_host_rta(r->ndm_family, tb[NDA_DST])); } if (!filter.index && r->ndm_ifindex) fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex)); diff --git a/ip/iproute.c b/ip/iproute.c index 1ec929429..67d551b54 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -376,10 +376,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) r->rtm_dst_len ); } else { - fprintf(fp, "%s ", format_host(r->rtm_family, - RTA_PAYLOAD(tb[RTA_DST]), - RTA_DATA(tb[RTA_DST])) - ); + fprintf(fp, "%s ", + format_host_rta(r->rtm_family, tb[RTA_DST])); } } else if (r->rtm_dst_len) { fprintf(fp, "0/%d ", r->rtm_dst_len); @@ -394,19 +392,15 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) r->rtm_src_len ); } else { - fprintf(fp, "from %s ", format_host(r->rtm_family, - RTA_PAYLOAD(tb[RTA_SRC]), - RTA_DATA(tb[RTA_SRC])) - ); + fprintf(fp, "from %s ", + format_host_rta(r->rtm_family, tb[RTA_SRC])); } } else if (r->rtm_src_len) { fprintf(fp, "from 0/%u ", r->rtm_src_len); } if (tb[RTA_NEWDST]) { - fprintf(fp, "as to %s ", format_host(r->rtm_family, - RTA_PAYLOAD(tb[RTA_NEWDST]), - RTA_DATA(tb[RTA_NEWDST])) - ); + fprintf(fp, "as to %s ", + format_host_rta(r->rtm_family, tb[RTA_NEWDST])); } if (tb[RTA_ENCAP]) @@ -419,9 +413,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) { fprintf(fp, "via %s ", - format_host(r->rtm_family, - RTA_PAYLOAD(tb[RTA_GATEWAY]), - RTA_DATA(tb[RTA_GATEWAY]))); + format_host_rta(r->rtm_family, tb[RTA_GATEWAY])); } if (tb[RTA_VIA]) { size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2; @@ -653,16 +645,13 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) tb[RTA_ENCAP]); if (tb[RTA_NEWDST]) { fprintf(fp, " as to %s ", - format_host(r->rtm_family, - RTA_PAYLOAD(tb[RTA_NEWDST]), - RTA_DATA(tb[RTA_NEWDST]), - abuf, sizeof(abuf))); + format_host_rta(r->rtm_family, + tb[RTA_NEWDST])); } if (tb[RTA_GATEWAY]) { fprintf(fp, " via %s ", - format_host(r->rtm_family, - RTA_PAYLOAD(tb[RTA_GATEWAY]), - RTA_DATA(tb[RTA_GATEWAY]))); + format_host_rta(r->rtm_family, + tb[RTA_GATEWAY])); } if (tb[RTA_VIA]) { size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2; diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 53d3ad4e6..56af9e4e9 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -62,9 +62,8 @@ static void print_encap_mpls(FILE *fp, struct rtattr *encap) parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap); if (tb[MPLS_IPTUNNEL_DST]) - fprintf(fp, " %s ", format_host(AF_MPLS, - RTA_PAYLOAD(tb[MPLS_IPTUNNEL_DST]), - RTA_DATA(tb[MPLS_IPTUNNEL_DST]))); + fprintf(fp, " %s ", + format_host_rta(AF_MPLS, tb[MPLS_IPTUNNEL_DST])); } static void print_encap_ip(FILE *fp, struct rtattr *encap) diff --git a/ip/iprule.c b/ip/iprule.c index 3fd510efe..ac570440d 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -89,10 +89,8 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) r->rtm_src_len ); } else { - fprintf(fp, "from %s ", format_host(r->rtm_family, - RTA_PAYLOAD(tb[FRA_SRC]), - RTA_DATA(tb[FRA_SRC])) - ); + fprintf(fp, "from %s ", + format_host_rta(r->rtm_family, tb[FRA_SRC])); } } else if (r->rtm_src_len) { fprintf(fp, "from 0/%d ", r->rtm_src_len); @@ -108,9 +106,8 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) r->rtm_dst_len ); } else { - fprintf(fp, "to %s ", format_host(r->rtm_family, - RTA_PAYLOAD(tb[FRA_DST]), - RTA_DATA(tb[FRA_DST]))); + fprintf(fp, "to %s ", + format_host_rta(r->rtm_family, tb[FRA_DST])); } } else if (r->rtm_dst_len) { fprintf(fp, "to 0/%d ", r->rtm_dst_len); @@ -183,9 +180,8 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (r->rtm_type == RTN_NAT) { if (tb[RTA_GATEWAY]) { fprintf(fp, "map-to %s ", - format_host(r->rtm_family, - RTA_PAYLOAD(tb[RTA_GATEWAY]), - RTA_DATA(tb[RTA_GATEWAY]))); + format_host_rta(r->rtm_family, + tb[RTA_GATEWAY])); } else fprintf(fp, "masquerade"); } else if (r->rtm_type == FR_ACT_GOTO) { diff --git a/ip/iptoken.c b/ip/iptoken.c index 02fe98e24..6e1a1ab7f 100644 --- a/ip/iptoken.c +++ b/ip/iptoken.c @@ -78,12 +78,9 @@ static int print_token(const struct sockaddr_nl *who, struct nlmsghdr *n, void * return -1; } - fprintf(fp, "token %s ", - format_host(ifi->ifi_family, - RTA_PAYLOAD(ltb[IFLA_INET6_TOKEN]), - RTA_DATA(ltb[IFLA_INET6_TOKEN]))); - fprintf(fp, "dev %s ", ll_index_to_name(ifi->ifi_index)); - fprintf(fp, "\n"); + fprintf(fp, "token %s dev %s\n", + format_host_rta(ifi->ifi_family, ltb[IFLA_INET6_TOKEN]), + ll_index_to_name(ifi->ifi_index)); fflush(fp); return 0; From 7faf1588a755edb9c9cabbe1d3211265e9826d28 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 19:35:18 +0100 Subject: [PATCH 164/513] lib/utils: introduce rt_addr_n2a_rta() This simple macro eases calling rt_addr_n2a() with data from an rt_attr pointer. Signed-off-by: Phil Sutter --- include/utils.h | 2 ++ ip/iplink_bond.c | 4 +--- ip/ipmroute.c | 8 ++------ ip/ipprefix.c | 14 +++----------- ip/iproute.c | 20 +++++++------------- ip/iproute_lwtunnel.c | 19 ++++--------------- ip/iprule.c | 16 ++++++---------- ip/link_ip6tnl.c | 8 ++------ tc/f_flower.c | 8 ++------ 9 files changed, 29 insertions(+), 70 deletions(-) diff --git a/include/utils.h b/include/utils.h index ebb80c9c2..ef81d00f3 100644 --- a/include/utils.h +++ b/include/utils.h @@ -130,6 +130,8 @@ const char *format_host(int af, int lne, const void *addr); const char *rt_addr_n2a_r(int af, int len, const void *addr, char *buf, int buflen); const char *rt_addr_n2a(int af, int len, const void *addr); +#define rt_addr_n2a_rta(af, rta) \ + rt_addr_n2a(af, RTA_PAYLOAD(rta), RTA_DATA(rta)) int read_family(const char *name); const char *family_name(int family); diff --git a/ip/iplink_bond.c b/ip/iplink_bond.c index 7da58e455..fe83479a0 100644 --- a/ip/iplink_bond.c +++ b/ip/iplink_bond.c @@ -422,9 +422,7 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { if (iptb[i]) fprintf(f, "%s", - rt_addr_n2a(AF_INET, - RTA_PAYLOAD(iptb[i]), - RTA_DATA(iptb[i]))); + rt_addr_n2a_rta(AF_INET, iptb[i])); if (i < BOND_MAX_ARP_TARGETS-1 && iptb[i+1]) fprintf(f, ","); } diff --git a/ip/ipmroute.c b/ip/ipmroute.c index 2b9f892a6..c33cdcbbd 100644 --- a/ip/ipmroute.c +++ b/ip/ipmroute.c @@ -123,16 +123,12 @@ int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[RTA_SRC]) len = snprintf(obuf, sizeof(obuf), - "(%s, ", rt_addr_n2a(family, - RTA_PAYLOAD(tb[RTA_SRC]), - RTA_DATA(tb[RTA_SRC]))); + "(%s, ", rt_addr_n2a_rta(family, tb[RTA_SRC])); else len = sprintf(obuf, "(unknown, "); if (tb[RTA_DST]) snprintf(obuf + len, sizeof(obuf) - len, - "%s)", rt_addr_n2a(family, - RTA_PAYLOAD(tb[RTA_DST]), - RTA_DATA(tb[RTA_DST]))); + "%s)", rt_addr_n2a_rta(family, tb[RTA_DST])); else snprintf(obuf + len, sizeof(obuf) - len, "unknown) "); diff --git a/ip/ipprefix.c b/ip/ipprefix.c index 4d986dbc1..a833efcf6 100644 --- a/ip/ipprefix.c +++ b/ip/ipprefix.c @@ -71,19 +71,11 @@ int print_prefix(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) parse_rtattr(tb, RTA_MAX, RTM_RTA(prefix), len); - fprintf(fp, "prefix "); - if (tb[PREFIX_ADDRESS]) { - struct in6_addr *pfx; - - pfx = (struct in6_addr *)RTA_DATA(tb[PREFIX_ADDRESS]); - - fprintf(fp, "%s", rt_addr_n2a(family, - RTA_PAYLOAD(tb[PREFIX_ADDRESS]), - pfx)); + fprintf(fp, "prefix %s/%u", + rt_addr_n2a_rta(family, tb[PREFIX_ADDRESS]), + prefix->prefix_len); } - fprintf(fp, "/%u ", prefix->prefix_len); - fprintf(fp, "dev %s ", ll_index_to_name(prefix->prefix_ifindex)); if (prefix->prefix_flags & IF_PREFIX_ONLINK) diff --git a/ip/iproute.c b/ip/iproute.c index 67d551b54..8224d7ffa 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -370,11 +370,9 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[RTA_DST]) { if (r->rtm_dst_len != host_len) { - fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family, - RTA_PAYLOAD(tb[RTA_DST]), - RTA_DATA(tb[RTA_DST])), - r->rtm_dst_len - ); + fprintf(fp, "%s/%u ", + rt_addr_n2a_rta(r->rtm_family, tb[RTA_DST]), + r->rtm_dst_len); } else { fprintf(fp, "%s ", format_host_rta(r->rtm_family, tb[RTA_DST])); @@ -386,11 +384,9 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) } if (tb[RTA_SRC]) { if (r->rtm_src_len != host_len) { - fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, - RTA_PAYLOAD(tb[RTA_SRC]), - RTA_DATA(tb[RTA_SRC])), - r->rtm_src_len - ); + fprintf(fp, "from %s/%u ", + rt_addr_n2a_rta(r->rtm_family, tb[RTA_SRC]), + r->rtm_src_len); } else { fprintf(fp, "from %s ", format_host_rta(r->rtm_family, tb[RTA_SRC])); @@ -439,9 +435,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) and symbolic name will not be useful. */ fprintf(fp, " src %s ", - rt_addr_n2a(r->rtm_family, - RTA_PAYLOAD(tb[RTA_PREFSRC]), - RTA_DATA(tb[RTA_PREFSRC]))); + rt_addr_n2a_rta(r->rtm_family, tb[RTA_PREFSRC])); } if (tb[RTA_PRIORITY]) fprintf(fp, " metric %u ", rta_getattr_u32(tb[RTA_PRIORITY])); diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 56af9e4e9..3baac7720 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -77,15 +77,11 @@ static void print_encap_ip(FILE *fp, struct rtattr *encap) if (tb[LWTUNNEL_IP_SRC]) fprintf(fp, "src %s ", - rt_addr_n2a(AF_INET, - RTA_PAYLOAD(tb[LWTUNNEL_IP_SRC]), - RTA_DATA(tb[LWTUNNEL_IP_SRC]))); + rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC])); if (tb[LWTUNNEL_IP_DST]) fprintf(fp, "dst %s ", - rt_addr_n2a(AF_INET, - RTA_PAYLOAD(tb[LWTUNNEL_IP_DST]), - RTA_DATA(tb[LWTUNNEL_IP_DST]))); + rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST])); if (tb[LWTUNNEL_IP_TTL]) fprintf(fp, "ttl %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL])); @@ -112,7 +108,6 @@ static void print_encap_ila(FILE *fp, struct rtattr *encap) static void print_encap_ip6(FILE *fp, struct rtattr *encap) { struct rtattr *tb[LWTUNNEL_IP6_MAX+1]; - char abuf[256]; parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap); @@ -121,17 +116,11 @@ static void print_encap_ip6(FILE *fp, struct rtattr *encap) if (tb[LWTUNNEL_IP6_SRC]) fprintf(fp, "src %s ", - rt_addr_n2a(AF_INET6, - RTA_PAYLOAD(tb[LWTUNNEL_IP6_SRC]), - RTA_DATA(tb[LWTUNNEL_IP6_SRC]), - abuf, sizeof(abuf))); + rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC])); if (tb[LWTUNNEL_IP6_DST]) fprintf(fp, "dst %s ", - rt_addr_n2a(AF_INET6, - RTA_PAYLOAD(tb[LWTUNNEL_IP6_DST]), - RTA_DATA(tb[LWTUNNEL_IP6_DST]), - abuf, sizeof(abuf))); + rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST])); if (tb[LWTUNNEL_IP6_HOPLIMIT]) fprintf(fp, "hoplimit %d ", rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT])); diff --git a/ip/iprule.c b/ip/iprule.c index ac570440d..7cb19e4d5 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -83,11 +83,9 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[FRA_SRC]) { if (r->rtm_src_len != host_len) { - fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, - RTA_PAYLOAD(tb[FRA_SRC]), - RTA_DATA(tb[FRA_SRC])), - r->rtm_src_len - ); + fprintf(fp, "from %s/%u ", + rt_addr_n2a_rta(r->rtm_family, tb[FRA_SRC]), + r->rtm_src_len); } else { fprintf(fp, "from %s ", format_host_rta(r->rtm_family, tb[FRA_SRC])); @@ -100,11 +98,9 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[FRA_DST]) { if (r->rtm_dst_len != host_len) { - fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family, - RTA_PAYLOAD(tb[FRA_DST]), - RTA_DATA(tb[FRA_DST])), - r->rtm_dst_len - ); + fprintf(fp, "to %s/%u ", + rt_addr_n2a_rta(r->rtm_family, tb[FRA_DST]), + r->rtm_dst_len); } else { fprintf(fp, "to %s ", format_host_rta(r->rtm_family, tb[FRA_DST])); diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c index 4b32fe5aa..8a31d0dcd 100644 --- a/ip/link_ip6tnl.c +++ b/ip/link_ip6tnl.c @@ -289,16 +289,12 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb if (tb[IFLA_IPTUN_REMOTE]) { fprintf(f, "remote %s ", - rt_addr_n2a(AF_INET6, - RTA_PAYLOAD(tb[IFLA_IPTUN_REMOTE]), - RTA_DATA(tb[IFLA_IPTUN_REMOTE]))); + rt_addr_n2a_rta(AF_INET6, tb[IFLA_IPTUN_REMOTE])); } if (tb[IFLA_IPTUN_LOCAL]) { fprintf(f, "local %s ", - rt_addr_n2a(AF_INET6, - RTA_PAYLOAD(tb[IFLA_IPTUN_LOCAL]), - RTA_DATA(tb[IFLA_IPTUN_LOCAL]))); + rt_addr_n2a_rta(AF_INET6, tb[IFLA_IPTUN_LOCAL])); } if (tb[IFLA_IPTUN_LINK] && rta_getattr_u32(tb[IFLA_IPTUN_LINK])) { diff --git a/tc/f_flower.c b/tc/f_flower.c index 40f8c595b..306f056c1 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -415,16 +415,12 @@ 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(family, - RTA_PAYLOAD(addr_attr), - RTA_DATA(addr_attr))); + fprintf(f, "\n %s %s", name, rt_addr_n2a_rta(family, addr_attr)); if (!mask_attr || RTA_PAYLOAD(mask_attr) != len) return; bits = __mask_bits(RTA_DATA(mask_attr), len); if (bits < 0) - fprintf(f, "/%s", rt_addr_n2a(family, - RTA_PAYLOAD(mask_attr), - RTA_DATA(mask_attr))); + fprintf(f, "/%s", rt_addr_n2a_rta(family, mask_attr)); else if (bits < len * 8) fprintf(f, "/%d", bits); } From f63ed3e629893046aca58a3bb409a3ff909a8fae Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 22 Mar 2016 19:35:19 +0100 Subject: [PATCH 165/513] lib/ll_addr: improve ll_addr_n2a() a bit Apart from making the code a bit more compact and efficient, this also prevents a potential buffer overflow if the passed buffer is really too small: Although correctly decrementing the size parameter passed to snprintf, it could become negative which would then wrap since snprintf uses (unsigned) size_t for the parameter. Signed-off-by: Phil Sutter --- lib/ll_addr.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/lib/ll_addr.c b/lib/ll_addr.c index 2ce9abfbb..465ed6fa4 100644 --- a/lib/ll_addr.c +++ b/lib/ll_addr.c @@ -41,18 +41,9 @@ const char *ll_addr_n2a(const unsigned char *addr, int alen, int type, char *buf if (alen == 16 && type == ARPHRD_TUNNEL6) { return inet_ntop(AF_INET6, addr, buf, blen); } - l = 0; - for (i=0; i Date: Sun, 27 Mar 2016 10:45:51 -0700 Subject: [PATCH 166/513] fix get_addr() and get_prefix() error messages An attempt to add invalid address to interface would print "???" string instead of the address family name. For example: $ ip address add 256.10.166.1/24 dev ens8 Error: ??? prefix is expected rather than "256.10.166.1/24". $ ip neighbor add proxy 2001:db8::g dev ens8 Error: ??? address is expected rather than "2001:db8::g". With this patch the output will look like: $ ip address add 256.10.166.1/24 dev ens8 Error: inet prefix is expected rather than "256.10.166.1/24". $ ip neighbor add proxy 2001:db8::g dev ens8 Error: inet6 address is expected rather than "2001:db8::g". Signed-off-by: Przemyslaw Szczerbik Signed-off-by: Marco Varlese --- lib/utils.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/utils.c b/lib/utils.c index 9b303a6b0..bd5842730 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -567,7 +567,7 @@ int get_addr(inet_prefix *dst, const char *arg, int family) { if (get_addr_1(dst, arg, family)) { fprintf(stderr, "Error: %s address is expected rather than \"%s\".\n", - family_name(family) ,arg); + family_name(dst->family) ,arg); exit(1); } return 0; @@ -579,9 +579,10 @@ int get_prefix(inet_prefix *dst, char *arg, int family) fprintf(stderr, "Error: \"%s\" may be inet prefix, but it is not allowed in this context.\n", arg); exit(1); } + if (get_prefix_1(dst, arg, family)) { fprintf(stderr, "Error: %s prefix is expected rather than \"%s\".\n", - family_name(family) ,arg); + family_name(dst->family) ,arg); exit(1); } return 0; From e9e9365b562ef5084bf21fb01e928c52c7078c93 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 27 Mar 2016 10:47:46 -0700 Subject: [PATCH 167/513] scrub out whitespace issues Run script that removes trailing whitespace everywhere. --- bridge/fdb.c | 2 +- bridge/monitor.c | 1 - genl/ctrl.c | 2 +- include/libnetlink.h | 32 +++++++++++++++----------------- lib/coverity_model.c | 2 -- lib/dnet_ntop.c | 2 -- lib/inet_proto.c | 2 -- lib/ipx_ntop.c | 2 -- lib/libgenl.c | 1 - lib/libnetlink.c | 2 +- lib/utils.c | 6 +++--- netem/maketable.c | 4 ++-- netem/normal.c | 2 +- netem/pareto.c | 4 ++-- netem/paretonormal.c | 2 +- tc/m_action.c | 6 +++--- tc/tc_core.c | 2 +- 17 files changed, 31 insertions(+), 43 deletions(-) diff --git a/bridge/fdb.c b/bridge/fdb.c index e8c314a3c..df55e86df 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -298,7 +298,7 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv) req.ndm.ndm_flags |= NTF_MASTER; } else if (matches(*argv, "router") == 0) { req.ndm.ndm_flags |= NTF_ROUTER; - } else if (matches(*argv, "local") == 0 || + } else if (matches(*argv, "local") == 0 || matches(*argv, "permanent") == 0) { req.ndm.ndm_state |= NUD_PERMANENT; } else if (matches(*argv, "temp") == 0 || diff --git a/bridge/monitor.c b/bridge/monitor.c index 62690810d..d294269e1 100644 --- a/bridge/monitor.c +++ b/bridge/monitor.c @@ -142,4 +142,3 @@ int do_monitor(int argc, char **argv) return 0; } - diff --git a/genl/ctrl.c b/genl/ctrl.c index b7a8878c8..ffa34af56 100644 --- a/genl/ctrl.c +++ b/genl/ctrl.c @@ -132,7 +132,7 @@ static void print_ctrl_cmd_flags(FILE *fp, __u32 fl) fprintf(fp, "\n"); } - + static int print_ctrl_cmds(FILE *fp, struct rtattr *arg, __u32 ctrl_ver) { struct rtattr *tb[CTRL_ATTR_OP_MAX + 1]; diff --git a/include/libnetlink.h b/include/libnetlink.h index 431189e20..491263f7e 100644 --- a/include/libnetlink.h +++ b/include/libnetlink.h @@ -11,8 +11,7 @@ #include #include -struct rtnl_handle -{ +struct rtnl_handle { int fd; struct sockaddr_nl local; struct sockaddr_nl peer; @@ -26,10 +25,10 @@ struct rtnl_handle extern int rcvbuf; -int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) +int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions) __attribute__((warn_unused_result)); -int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, +int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions, int protocol) __attribute__((warn_unused_result)); @@ -56,8 +55,7 @@ typedef int (*rtnl_listen_filter_t)(const struct sockaddr_nl *, struct rtnl_ctrl_data *, struct nlmsghdr *n, void *); -struct rtnl_dump_filter_arg -{ +struct rtnl_dump_filter_arg { rtnl_filter_t filter; void *arg1; __u16 nc_flags; @@ -140,6 +138,7 @@ static inline __u32 rta_getattr_u32(const struct rtattr *rta) static inline __u64 rta_getattr_u64(const struct rtattr *rta) { __u64 tmp; + memcpy(&tmp, RTA_DATA(rta), sizeof(__u64)); return tmp; } @@ -159,42 +158,42 @@ int rtnl_from_file(FILE *, rtnl_listen_filter_t handler, #ifndef IFA_RTA #define IFA_RTA(r) \ - ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) + ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) #endif #ifndef IFA_PAYLOAD -#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) +#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct ifaddrmsg)) #endif #ifndef IFLA_RTA #define IFLA_RTA(r) \ - ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) + ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) #endif #ifndef IFLA_PAYLOAD -#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) +#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg)) #endif #ifndef NDA_RTA #define NDA_RTA(r) \ - ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) + ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) #endif #ifndef NDA_PAYLOAD -#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg)) +#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct ndmsg)) #endif #ifndef NDTA_RTA #define NDTA_RTA(r) \ - ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndtmsg)))) + ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ndtmsg)))) #endif #ifndef NDTA_PAYLOAD -#define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg)) +#define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct ndtmsg)) #endif #ifndef NETNS_RTA #define NETNS_RTA(r) \ - ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtgenmsg)))) + ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct rtgenmsg)))) #endif #ifndef NETNS_PAYLOAD -#define NETNS_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtgenmsg)) +#define NETNS_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct rtgenmsg)) #endif /* User defined nlmsg_type which is used mostly for logging netlink @@ -202,4 +201,3 @@ int rtnl_from_file(FILE *, rtnl_listen_filter_t handler, #define NLMSG_TSTAMP 15 #endif /* __LIBNETLINK_H__ */ - diff --git a/lib/coverity_model.c b/lib/coverity_model.c index c89630206..1321fe822 100644 --- a/lib/coverity_model.c +++ b/lib/coverity_model.c @@ -15,5 +15,3 @@ * Coverity Scan doesn't pick up modifications automatically. The model file * must be uploaded by an admin. */ - - diff --git a/lib/dnet_ntop.c b/lib/dnet_ntop.c index 507a7eb8e..112dc0d90 100644 --- a/lib/dnet_ntop.c +++ b/lib/dnet_ntop.c @@ -98,5 +98,3 @@ const char *dnet_ntop(int af, const void *addr, char *str, size_t len) return NULL; } - - diff --git a/lib/inet_proto.c b/lib/inet_proto.c index 57a835113..ceda082b1 100644 --- a/lib/inet_proto.c +++ b/lib/inet_proto.c @@ -67,5 +67,3 @@ int inet_proto_a2n(const char *buf) } return -1; } - - diff --git a/lib/ipx_ntop.c b/lib/ipx_ntop.c index 1e46bc219..5f646b3e0 100644 --- a/lib/ipx_ntop.c +++ b/lib/ipx_ntop.c @@ -68,5 +68,3 @@ const char *ipx_ntop(int af, const void *addr, char *str, size_t len) return NULL; } - - diff --git a/lib/libgenl.c b/lib/libgenl.c index acb147838..a1a37a440 100644 --- a/lib/libgenl.c +++ b/lib/libgenl.c @@ -60,4 +60,3 @@ int genl_resolve_family(struct rtnl_handle *grth, const char *family) return genl_parse_getfamily(&req.n); } - diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 245c4ca21..a90e52ca2 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -158,7 +158,7 @@ int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len) struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) fprintf(stderr, "ERROR truncated\n"); - else + else errno = -err->error; return -1; } diff --git a/lib/utils.c b/lib/utils.c index bd5842730..b93b1dc84 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -95,7 +95,7 @@ static int get_netmask(unsigned *val, const char *arg, int base) /* try coverting dotted quad to CIDR */ if (!get_addr_1(&addr, arg, AF_INET) && addr.family == AF_INET) { int b = mask2bits(addr.data[0]); - + if (b >= 0) { *val = b; return 0; @@ -191,7 +191,7 @@ int get_time_rtt(unsigned *val, const char *arg, int *raw) *val = t; if (*val < t) *val += 1; - + return 0; } @@ -363,7 +363,7 @@ static int get_addr_ipv4(__u8 *ap, const char *cp) for (i = 0; i < 4; i++) { unsigned long n; char *endp; - + n = strtoul(cp, &endp, 0); if (n > 255) return -1; /* bogus network value */ diff --git a/netem/maketable.c b/netem/maketable.c index a5452b617..dc5053285 100644 --- a/netem/maketable.c +++ b/netem/maketable.c @@ -210,7 +210,7 @@ main(int argc, char **argv) } } else { fp = stdin; - } + } x = readdoubles(fp, &limit); if (limit <= 0) { fprintf(stderr, "Nothing much read!\n"); @@ -221,7 +221,7 @@ main(int argc, char **argv) fprintf(stderr, "%d values, mu %10.4f, sigma %10.4f, rho %10.4f\n", limit, mu, sigma, rho); #endif - + table = makedist(x, limit, mu, sigma); free((void *) x); cumulativedist(table, DISTTABLESIZE, &total); diff --git a/netem/normal.c b/netem/normal.c index dbdebb1d0..90963f4e9 100644 --- a/netem/normal.c +++ b/netem/normal.c @@ -33,7 +33,7 @@ main(int argc, char **argv) table[i] = x; } - + printf("# This is the distribution table for the normal distribution.\n"); for (i = n = 0; i < TABLESIZE; i += 4) { int value = (int) rint(table[i]*TABLEFACTOR); diff --git a/netem/pareto.c b/netem/pareto.c index 8aa647b62..51d9437db 100644 --- a/netem/pareto.c +++ b/netem/pareto.c @@ -36,6 +36,6 @@ main(int argc, char **argv) n = 0; } } - + return 0; -} +} diff --git a/netem/paretonormal.c b/netem/paretonormal.c index ed75f2883..83ec87d4d 100644 --- a/netem/paretonormal.c +++ b/netem/paretonormal.c @@ -44,7 +44,7 @@ paretovalue(int i) if (dvalue > 32767) dvalue = 32767; return (int)rint(dvalue); -} +} int main(int argc, char **argv) diff --git a/tc/m_action.c b/tc/m_action.c index 5c47c8252..c416d98a7 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -141,9 +141,9 @@ static int new_cmd(char **argv) { if ((matches(*argv, "change") == 0) || - (matches(*argv, "replace") == 0) || - (matches(*argv, "delete") == 0) || - (matches(*argv, "get") == 0) || + (matches(*argv, "replace") == 0) || + (matches(*argv, "delete") == 0) || + (matches(*argv, "get") == 0) || (matches(*argv, "add") == 0)) return 1; diff --git a/tc/tc_core.c b/tc/tc_core.c index 194028ae0..7bbe0d733 100644 --- a/tc/tc_core.c +++ b/tc/tc_core.c @@ -145,7 +145,7 @@ int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab, rtab[i] = tc_calc_xmittime(bps, sz); } - r->cell_align = -1; + r->cell_align = -1; r->cell_log = cell_log; r->linklayer = (linklayer & TC_LINKLAYER_MASK); return cell_log; From af3253984df3190ff58a7a8aa34a7e866bff8604 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Fri, 18 Mar 2016 17:51:08 -0700 Subject: [PATCH 168/513] vxlan: Follow kernel defaults for outer UDP checksum. On recent kernels, UDP checksum computation has become more efficient and the default behavior was changed, however, the ip command overrides this by always specifying a particular behavior. If the user does not specify that UDP checksums should either be computed or not then we don't need to send an explicit netlink message - the kernel can just use its default behavior. Signed-off-by: Jesse Gross --- ip/iplink_vxlan.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index 543522e13..8dcf5316b 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -68,8 +68,11 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, __u32 maxaddr = 0; __u16 dstport = 0; __u8 udpcsum = 0; + bool udpcsum_set = false; __u8 udp6zerocsumtx = 0; + bool udp6zerocsumtx_set = false; __u8 udp6zerocsumrx = 0; + bool udp6zerocsumrx_set = false; __u8 remcsumtx = 0; __u8 remcsumrx = 0; __u8 metadata = 0; @@ -194,16 +197,22 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, l3miss = 1; } else if (!matches(*argv, "udpcsum")) { udpcsum = 1; + udpcsum_set = true; } else if (!matches(*argv, "noudpcsum")) { udpcsum = 0; + udpcsum_set = true; } else if (!matches(*argv, "udp6zerocsumtx")) { udp6zerocsumtx = 1; + udp6zerocsumtx_set = true; } else if (!matches(*argv, "noudp6zerocsumtx")) { udp6zerocsumtx = 0; + udp6zerocsumtx_set = true; } else if (!matches(*argv, "udp6zerocsumrx")) { udp6zerocsumrx = 1; + udp6zerocsumrx_set = true; } else if (!matches(*argv, "noudp6zerocsumrx")) { udp6zerocsumrx = 0; + udp6zerocsumrx_set = true; } else if (!matches(*argv, "remcsumtx")) { remcsumtx = 1; } else if (!matches(*argv, "noremcsumtx")) { @@ -278,13 +287,16 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, addattr8(n, 1024, IFLA_VXLAN_RSC, rsc); addattr8(n, 1024, IFLA_VXLAN_L2MISS, l2miss); addattr8(n, 1024, IFLA_VXLAN_L3MISS, l3miss); - addattr8(n, 1024, IFLA_VXLAN_UDP_CSUM, udpcsum); - addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, udp6zerocsumtx); - addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, udp6zerocsumrx); addattr8(n, 1024, IFLA_VXLAN_REMCSUM_TX, remcsumtx); addattr8(n, 1024, IFLA_VXLAN_REMCSUM_RX, remcsumrx); addattr8(n, 1024, IFLA_VXLAN_COLLECT_METADATA, metadata); + if (udpcsum_set) + addattr8(n, 1024, IFLA_VXLAN_UDP_CSUM, udpcsum); + if (udp6zerocsumtx_set) + addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, udp6zerocsumtx); + if (udp6zerocsumrx_set) + addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, udp6zerocsumrx); if (noage) addattr32(n, 1024, IFLA_VXLAN_AGEING, 0); else if (age) @@ -426,16 +438,23 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) ((maxaddr = rta_getattr_u32(tb[IFLA_VXLAN_LIMIT])) != 0)) fprintf(f, "maxaddr %u ", maxaddr); - if (tb[IFLA_VXLAN_UDP_CSUM] && rta_getattr_u8(tb[IFLA_VXLAN_UDP_CSUM])) + if (tb[IFLA_VXLAN_UDP_CSUM]) { + if (!rta_getattr_u8(tb[IFLA_VXLAN_UDP_CSUM])) + fputs("no", f); fputs("udpcsum ", f); + } - if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX] && - rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX])) + if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]) { + if (!rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX])) + fputs("no", f); fputs("udp6zerocsumtx ", f); + } - if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX] && - rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX])) + if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]) { + if (!rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX])) + fputs("no", f); fputs("udp6zerocsumrx ", f); + } if (tb[IFLA_VXLAN_REMCSUM_TX] && rta_getattr_u8(tb[IFLA_VXLAN_REMCSUM_TX])) From 325d02b44ce3194a6d7a57e6a46b5ed767b61025 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Fri, 18 Mar 2016 17:51:09 -0700 Subject: [PATCH 169/513] geneve: Add support for configuring UDP checksums. Enable support for configuring outer UDP checksums on Geneve tunnels: ip link add type geneve id 10 remote 10.0.0.2 udpcsum Signed-off-by: Jesse Gross --- ip/iplink_geneve.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c index c6e7bbe0c..1c6879e76 100644 --- a/ip/iplink_geneve.c +++ b/ip/iplink_geneve.c @@ -20,6 +20,7 @@ static void print_explain(FILE *f) fprintf(f, "Usage: ... geneve id VNI remote ADDR\n"); fprintf(f, " [ ttl TTL ] [ tos TOS ]\n"); fprintf(f, " [ dstport PORT ] [ [no]external ]\n"); + fprintf(f, " [ [no]udpcsum ] [ [no]udp6zerocsumtx ] [ [no]udp6zerocsumrx ]\n"); fprintf(f, "\n"); fprintf(f, "Where: VNI := 0-16777215\n"); fprintf(f, " ADDR := IP_ADDRESS\n"); @@ -43,6 +44,12 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, __u8 tos = 0; __u16 dstport = 0; bool metadata = 0; + __u8 udpcsum = 0; + bool udpcsum_set = false; + __u8 udp6zerocsumtx = 0; + bool udp6zerocsumtx_set = false; + __u8 udp6zerocsumrx = 0; + bool udp6zerocsumrx_set = false; while (argc > 0) { if (!matches(*argv, "id") || @@ -91,6 +98,24 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, metadata = true; } else if (!matches(*argv, "noexternal")) { metadata = false; + } else if (!matches(*argv, "udpcsum")) { + udpcsum = 1; + udpcsum_set = true; + } else if (!matches(*argv, "noudpcsum")) { + udpcsum = 0; + udpcsum_set = true; + } else if (!matches(*argv, "udp6zerocsumtx")) { + udp6zerocsumtx = 1; + udp6zerocsumtx_set = true; + } else if (!matches(*argv, "noudp6zerocsumtx")) { + udp6zerocsumtx = 0; + udp6zerocsumtx_set = true; + } else if (!matches(*argv, "udp6zerocsumrx")) { + udp6zerocsumrx = 1; + udp6zerocsumrx_set = true; + } else if (!matches(*argv, "noudp6zerocsumrx")) { + udp6zerocsumrx = 0; + udp6zerocsumrx_set = true; } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -131,6 +156,12 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, addattr16(n, 1024, IFLA_GENEVE_PORT, htons(dstport)); if (metadata) addattr(n, 1024, IFLA_GENEVE_COLLECT_METADATA); + if (udpcsum_set) + addattr8(n, 1024, IFLA_GENEVE_UDP_CSUM, udpcsum); + if (udp6zerocsumtx_set) + addattr8(n, 1024, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, udp6zerocsumtx); + if (udp6zerocsumrx_set) + addattr8(n, 1024, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, udp6zerocsumrx); return 0; } @@ -189,6 +220,23 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_GENEVE_COLLECT_METADATA]) fputs("external ", f); + if (tb[IFLA_GENEVE_UDP_CSUM]) { + if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_CSUM])) + fputs("no", f); + fputs("udpcsum ", f); + } + + if (tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) { + if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX])) + fputs("no", f); + fputs("udp6zerocsumtx ", f); + } + + if (tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) { + if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX])) + fputs("no", f); + fputs("udp6zerocsumrx ", f); + } } static void geneve_print_help(struct link_util *lu, int argc, char **argv, From 4952b45946d73a4e5dd673928cf50327251de1de Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 22 Mar 2016 10:02:20 +0100 Subject: [PATCH 170/513] include: add linked list implementation from kernel Rename hlist.h to list.h while adding it to be aligned with kernel Signed-off-by: Jiri Pirko --- include/hlist.h | 56 ------------------------ include/list.h | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ ip/ipnetns.c | 2 +- lib/ll_map.c | 2 +- tc/tc_class.c | 2 +- 5 files changed, 115 insertions(+), 59 deletions(-) delete mode 100644 include/hlist.h create mode 100644 include/list.h diff --git a/include/hlist.h b/include/hlist.h deleted file mode 100644 index 4e8de9e5e..000000000 --- a/include/hlist.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __HLIST_H__ -#define __HLIST_H__ 1 -/* Hash list stuff from kernel */ - -#include - -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; - -static inline void hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - *pprev = next; - if (next) - next->pprev = pprev; -} - -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; -} - -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos ; pos = pos->next) - - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ - pos = n) - -#define hlist_entry_safe(ptr, type, member) \ - ({ typeof(ptr) ____ptr = (ptr); \ - ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ - }) - -#define hlist_for_each_entry(pos, head, member) \ - for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ - pos; \ - pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) - -#endif /* __HLIST_H__ */ diff --git a/include/list.h b/include/list.h new file mode 100644 index 000000000..cdebe4de3 --- /dev/null +++ b/include/list.h @@ -0,0 +1,112 @@ +#ifndef __LIST_H__ +#define __LIST_H__ 1 +/* List and hash list stuff from kernel */ + +#include + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +struct list_head { + struct list_head *next, *prev; +}; + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +#define list_for_each_entry(pos, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member), \ + n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +static inline void hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos ; pos = pos->next) + + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +#define hlist_entry_safe(ptr, type, member) \ + ({ typeof(ptr) ____ptr = (ptr); \ + ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ + }) + +#define hlist_for_each_entry(pos, head, member) \ + for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ + pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + +#endif /* __LIST_H__ */ diff --git a/ip/ipnetns.c b/ip/ipnetns.c index 71fbfce50..b3ee23c23 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -18,7 +18,7 @@ #include #include "utils.h" -#include "hlist.h" +#include "list.h" #include "ip_common.h" #include "namespace.h" diff --git a/lib/ll_map.c b/lib/ll_map.c index c6f702744..fa14a7760 100644 --- a/lib/ll_map.c +++ b/lib/ll_map.c @@ -22,7 +22,7 @@ #include "libnetlink.h" #include "ll_map.h" -#include "hlist.h" +#include "list.h" struct ll_cache { struct hlist_node idx_hash; diff --git a/tc/tc_class.c b/tc/tc_class.c index ddc6d6117..7747c8db3 100644 --- a/tc/tc_class.c +++ b/tc/tc_class.c @@ -24,7 +24,7 @@ #include "utils.h" #include "tc_util.h" #include "tc_common.h" -#include "hlist.h" +#include "list.h" struct graph_node { struct hlist_node hlist; From a3c4b484a1eddc87fbb66812a2453d840bc89f35 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 22 Mar 2016 10:02:21 +0100 Subject: [PATCH 171/513] add devlink tool Add new tool called devlink which is userspace counterpart of devlink Netlink socket. Signed-off-by: Jiri Pirko --- Makefile | 2 +- devlink/Makefile | 20 + devlink/devlink.c | 986 +++++++++++++++++++++++++++++++++++++ devlink/mnlg.c | 274 +++++++++++ devlink/mnlg.h | 27 + include/linux/devlink.h | 72 +++ man/man8/devlink-dev.8 | 58 +++ man/man8/devlink-monitor.8 | 36 ++ man/man8/devlink-port.8 | 126 +++++ man/man8/devlink.8 | 83 ++++ 10 files changed, 1683 insertions(+), 1 deletion(-) create mode 100644 devlink/Makefile create mode 100644 devlink/devlink.c create mode 100644 devlink/mnlg.c create mode 100644 devlink/mnlg.h create mode 100644 include/linux/devlink.h create mode 100644 man/man8/devlink-dev.8 create mode 100644 man/man8/devlink-monitor.8 create mode 100644 man/man8/devlink-port.8 create mode 100644 man/man8/devlink.8 diff --git a/Makefile b/Makefile index 67176beff..0190aa004 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ WFLAGS += -Wmissing-declarations -Wold-style-definition -Wformat=2 CFLAGS := $(WFLAGS) $(CCOPTS) -I../include $(DEFINES) $(CFLAGS) YACCFLAGS = -d -t -v -SUBDIRS=lib ip tc bridge misc netem genl tipc man +SUBDIRS=lib ip tc bridge misc netem genl tipc devlink man LIBNETLINK=../lib/libnetlink.a ../lib/libutil.a LDLIBS += $(LIBNETLINK) diff --git a/devlink/Makefile b/devlink/Makefile new file mode 100644 index 000000000..3fdaa6904 --- /dev/null +++ b/devlink/Makefile @@ -0,0 +1,20 @@ +include ../Config +ifeq ($(HAVE_MNL),y) + +DEVLINKOBJ = devlink.o mnlg.o +TARGETS=devlink + +CFLAGS += $(shell $(PKG_CONFIG) libmnl --cflags) +LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs) + +endif + +all: $(TARGETS) $(LIBS) + +devlink: $(DEVLINKOBJ) + +install: all + install -m 0755 $(TARGETS) $(DESTDIR)$(SBINDIR) + +clean: + rm -f $(DEVLINKOBJ) $(TARGETS) diff --git a/devlink/devlink.c b/devlink/devlink.c new file mode 100644 index 000000000..c2da85074 --- /dev/null +++ b/devlink/devlink.c @@ -0,0 +1,986 @@ +/* + * devlink.c Devlink tool + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Jiri Pirko + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SNAPSHOT.h" +#include "list.h" +#include "mnlg.h" + +#define pr_err(args...) fprintf(stderr, ##args) +#define pr_out(args...) fprintf(stdout, ##args) + +static int _mnlg_socket_recv_run(struct mnlg_socket *nlg, + mnl_cb_t data_cb, void *data) +{ + int err; + + err = mnlg_socket_recv_run(nlg, data_cb, data); + if (err < 0) { + pr_err("devlink answers: %s\n", strerror(errno)); + return -errno; + } + return 0; +} + +static int _mnlg_socket_sndrcv(struct mnlg_socket *nlg, + const struct nlmsghdr *nlh, + mnl_cb_t data_cb, void *data) +{ + int err; + + err = mnlg_socket_send(nlg, nlh); + if (err < 0) { + pr_err("Failed to call mnlg_socket_send\n"); + return -errno; + } + return _mnlg_socket_recv_run(nlg, data_cb, data); +} + +static int _mnlg_socket_group_add(struct mnlg_socket *nlg, + const char *group_name) +{ + int err; + + err = mnlg_socket_group_add(nlg, group_name); + if (err < 0) { + pr_err("Failed to call mnlg_socket_group_add\n"); + return -errno; + } + return 0; +} + +struct ifname_map { + struct list_head list; + char *bus_name; + char *dev_name; + uint32_t port_index; + char *ifname; +}; + +static struct ifname_map *ifname_map_alloc(const char *bus_name, + const char *dev_name, + uint32_t port_index, + const char *ifname) +{ + struct ifname_map *ifname_map; + + ifname_map = calloc(1, sizeof(*ifname_map)); + if (!ifname_map) + return NULL; + ifname_map->bus_name = strdup(bus_name); + ifname_map->dev_name = strdup(dev_name); + ifname_map->port_index = port_index; + ifname_map->ifname = strdup(ifname); + if (!ifname_map->bus_name || !ifname_map->dev_name || + !ifname_map->ifname) { + free(ifname_map->ifname); + free(ifname_map->dev_name); + free(ifname_map->bus_name); + free(ifname_map); + return NULL; + } + return ifname_map; +} + +static void ifname_map_free(struct ifname_map *ifname_map) +{ + free(ifname_map->ifname); + free(ifname_map->dev_name); + free(ifname_map->bus_name); + free(ifname_map); +} + +struct dl { + struct mnlg_socket *nlg; + struct list_head ifname_map_list; + int argc; + char **argv; +}; + +static int dl_argc(struct dl *dl) +{ + return dl->argc; +} + +static char *dl_argv(struct dl *dl) +{ + if (dl_argc(dl) == 0) + return NULL; + return *dl->argv; +} + +static void dl_arg_inc(struct dl *dl) +{ + if (dl_argc(dl) == 0) + return; + dl->argc--; + dl->argv++; +} + +static char *dl_argv_next(struct dl *dl) +{ + char *ret; + + if (dl_argc(dl) == 0) + return NULL; + + ret = *dl->argv; + dl_arg_inc(dl); + return ret; +} + +static char *dl_argv_index(struct dl *dl, unsigned int index) +{ + if (index >= dl_argc(dl)) + return NULL; + return dl->argv[index]; +} + +static int strcmpx(const char *str1, const char *str2) +{ + if (strlen(str1) > strlen(str2)) + return -1; + return strncmp(str1, str2, strlen(str1)); +} + +static bool dl_argv_match(struct dl *dl, const char *pattern) +{ + if (dl_argc(dl) == 0) + return false; + return strcmpx(dl_argv(dl), pattern) == 0; +} + +static bool dl_no_arg(struct dl *dl) +{ + return dl_argc(dl) == 0; +} + +static int attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type; + + type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, DEVLINK_ATTR_MAX) < 0) + return MNL_CB_ERROR; + + if (type == DEVLINK_ATTR_BUS_NAME && + mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_DEV_NAME && + mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_PORT_INDEX && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_PORT_TYPE && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_PORT_DESIRED_TYPE && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_PORT_NETDEV_IFINDEX && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_PORT_NETDEV_NAME && + mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_PORT_IBDEV_NAME && + mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) + return MNL_CB_ERROR; + tb[type] = attr; + return MNL_CB_OK; +} + +static int ifname_map_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + struct dl *dl = data; + struct ifname_map *ifname_map; + const char *bus_name; + const char *dev_name; + uint32_t port_ifindex; + const char *port_ifname; + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_PORT_INDEX]) + return MNL_CB_ERROR; + + if (!tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) + return MNL_CB_OK; + + bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); + dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); + port_ifindex = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); + port_ifname = mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]); + ifname_map = ifname_map_alloc(bus_name, dev_name, + port_ifindex, port_ifname); + if (!ifname_map) + return MNL_CB_ERROR; + list_add(&ifname_map->list, &dl->ifname_map_list); + + return MNL_CB_OK; +} + +static void ifname_map_fini(struct dl *dl) +{ + struct ifname_map *ifname_map, *tmp; + + list_for_each_entry_safe(ifname_map, tmp, + &dl->ifname_map_list, list) { + list_del(&ifname_map->list); + ifname_map_free(ifname_map); + } +} + +static int ifname_map_init(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + INIT_LIST_HEAD(&dl->ifname_map_list); + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, + NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); + + err = _mnlg_socket_sndrcv(dl->nlg, nlh, ifname_map_cb, dl); + if (err) { + ifname_map_fini(dl); + return err; + } + return 0; +} + +static int ifname_map_lookup(struct dl *dl, const char *ifname, + char **p_bus_name, char **p_dev_name, + uint32_t *p_port_index) +{ + struct ifname_map *ifname_map; + + list_for_each_entry(ifname_map, &dl->ifname_map_list, list) { + if (strcmp(ifname, ifname_map->ifname) == 0) { + *p_bus_name = ifname_map->bus_name; + *p_dev_name = ifname_map->dev_name; + *p_port_index = ifname_map->port_index; + return 0; + } + } + return -ENOENT; +} + +static unsigned int strslashcount(char *str) +{ + unsigned int count = 0; + char *pos = str; + + while ((pos = strchr(pos, '/'))) { + count++; + pos++; + } + return count; +} + +static int strslashrsplit(char *str, char **before, char **after) +{ + char *slash; + + slash = strrchr(str, '/'); + if (!slash) + return -EINVAL; + *slash = '\0'; + *before = str; + *after = slash + 1; + return 0; +} + +static int strtouint32_t(const char *str, uint32_t *p_val) +{ + char *endptr; + unsigned long int val; + + val = strtoul(str, &endptr, 10); + if (endptr == str || *endptr != '\0') + return -EINVAL; + if (val > UINT_MAX) + return -ERANGE; + *p_val = val; + return 0; +} + +static int dl_argv_put_handle(struct nlmsghdr *nlh, struct dl *dl) +{ + char *str = dl_argv_next(dl); + char *bus_name = bus_name; + char *dev_name = dev_name; + + if (!str) { + pr_err("Devlink identification (\"bus_name/dev_name\") expected\n"); + return -EINVAL; + } + if (strslashcount(str) != 1) { + pr_err("Wrong devlink identification string format.\n"); + pr_err("Expected \"bus_name/dev_name\".\n"); + return -EINVAL; + } + + strslashrsplit(str, &bus_name, &dev_name); + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, bus_name); + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, dev_name); + return 0; +} + +static int dl_argv_put_handle_port(struct nlmsghdr *nlh, struct dl *dl) +{ + char *str = dl_argv_next(dl); + unsigned int slash_count; + char *bus_name = bus_name; + char *dev_name = dev_name; + uint32_t port_index = port_index; + int err; + + if (!str) { + pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n"); + return -EINVAL; + } + slash_count = strslashcount(str); + if (slash_count != 2 && slash_count != 0) { + pr_err("Wrong port identification string format.\n"); + pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n"); + return -EINVAL; + } + + if (slash_count == 2) { + char *handlestr = handlestr; + char *portstr = portstr; + + err = strslashrsplit(str, &handlestr, &portstr); + err = strtouint32_t(portstr, &port_index); + if (err) { + pr_err("Port index \"%s\" is not a number or not within range\n", + portstr); + return err; + } + strslashrsplit(handlestr, &bus_name, &dev_name); + } else if (slash_count == 0) { + err = ifname_map_lookup(dl, str, &bus_name, &dev_name, + &port_index); + if (err) { + pr_err("Netdevice \"%s\" not found\n", str); + return err; + } + } + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, bus_name); + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, dev_name); + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, port_index); + return 0; +} + +static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val) +{ + char *str = dl_argv_next(dl); + int err; + + if (!str) { + pr_err("Unsigned number argument expected\n"); + return -EINVAL; + } + + err = strtouint32_t(str, p_val); + if (err) { + pr_err("\"%s\" is not a number or not within range\n", str); + return err; + } + return 0; +} + +static int dl_argv_str(struct dl *dl, const char **p_str) +{ + const char *str = dl_argv_next(dl); + + if (!str) { + pr_err("String parameter expected\n"); + return -EINVAL; + } + *p_str = str; + return 0; +} + +static int port_type_get(const char *typestr, enum devlink_port_type *p_type) +{ + if (strcmp(typestr, "auto") == 0) { + *p_type = DEVLINK_PORT_TYPE_AUTO; + } else if (strcmp(typestr, "eth") == 0) { + *p_type = DEVLINK_PORT_TYPE_ETH; + } else if (strcmp(typestr, "ib") == 0) { + *p_type = DEVLINK_PORT_TYPE_IB; + } else { + pr_err("Unknown port type \"%s\"\n", typestr); + return -EINVAL; + } + return 0; +} + +#define BIT(nr) (1UL << (nr)) +#define DL_OPT_HANDLE BIT(0) +#define DL_OPT_HANDLEP BIT(1) +#define DL_OPT_PORT_TYPE BIT(2) +#define DL_OPT_PORT_COUNT BIT(3) + +static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, + uint32_t o_required, uint32_t o_optional) +{ + uint32_t o_all = o_required | o_optional; + uint32_t o_found = 0; + int err; + + if (o_required & DL_OPT_HANDLE) { + err = dl_argv_put_handle(nlh, dl); + if (err) + return err; + } else if (o_required & DL_OPT_HANDLEP) { + err = dl_argv_put_handle_port(nlh, dl); + if (err) + return err; + } + + while (dl_argc(dl)) { + if (dl_argv_match(dl, "type") && + (o_all & DL_OPT_PORT_TYPE)) { + enum devlink_port_type port_type; + const char *typestr; + + dl_arg_inc(dl); + err = dl_argv_str(dl, &typestr); + if (err) + return err; + err = port_type_get(typestr, &port_type); + if (err) + return err; + mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE, + port_type); + o_found |= DL_OPT_PORT_TYPE; + } else if (dl_argv_match(dl, "count") && + (o_all & DL_OPT_PORT_COUNT)) { + uint32_t count; + + dl_arg_inc(dl); + err = dl_argv_uint32_t(dl, &count); + if (err) + return err; + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, + count); + o_found |= DL_OPT_PORT_COUNT; + } else { + pr_err("Unknown option \"%s\"\n", dl_argv(dl)); + return -EINVAL; + } + } + + if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) { + pr_err("Port type option expected.\n"); + return -EINVAL; + } + + if ((o_required & DL_OPT_PORT_COUNT) && + !(o_found & DL_OPT_PORT_COUNT)) { + pr_err("Port split count option expected.\n"); + return -EINVAL; + } + + return 0; +} + +static void cmd_dev_help(void) +{ + pr_out("Usage: devlink dev show [ DEV ]\n"); +} + +static void pr_out_handle(struct nlattr **tb) +{ + pr_out("%s/%s", mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), + mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME])); +} + +static void pr_out_dev(struct nlattr **tb) +{ + pr_out_handle(tb); + pr_out("\n"); +} + +static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) + return MNL_CB_ERROR; + pr_out_dev(tb); + return MNL_CB_OK; +} + +static int cmd_dev_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + int err; + + if (dl_argc(dl) == 0) + flags |= NLM_F_DUMP; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags); + + if (dl_argc(dl) > 0) { + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0); + if (err) + return err; + } + + return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, NULL); +} + +static int cmd_dev(struct dl *dl) +{ + if (dl_argv_match(dl, "help")) { + cmd_dev_help(); + return 0; + } else if (dl_argv_match(dl, "show") || + dl_argv_match(dl, "list") || dl_no_arg(dl)) { + dl_arg_inc(dl); + return cmd_dev_show(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static void cmd_port_help(void) +{ + pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n"); + pr_out(" dl port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n"); + pr_out(" dl port split DEV/PORT_INDEX count COUNT\n"); + pr_out(" dl port unsplit DEV/PORT_INDEX\n"); +} + +static const char *port_type_name(uint32_t type) +{ + switch (type) { + case DEVLINK_PORT_TYPE_NOTSET: return "notset"; + case DEVLINK_PORT_TYPE_AUTO: return "auto"; + case DEVLINK_PORT_TYPE_ETH: return "eth"; + case DEVLINK_PORT_TYPE_IB: return "ib"; + default: return ""; + } +} + +static void pr_out_port(struct nlattr **tb) +{ + struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE]; + struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE]; + + pr_out_handle(tb); + pr_out("/%d:", mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); + if (pt_attr) { + uint16_t port_type = mnl_attr_get_u16(pt_attr); + + pr_out(" type %s", port_type_name(port_type)); + if (dpt_attr) { + uint16_t des_port_type = mnl_attr_get_u16(dpt_attr); + + if (port_type != des_port_type) + pr_out("(%s)", port_type_name(des_port_type)); + } + } + if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) + pr_out(" netdev %s", + mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME])); + if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME]) + pr_out(" ibdev %s", + mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME])); + if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]) + pr_out(" split_group %u", + mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])); + pr_out("\n"); +} + +static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_PORT_INDEX]) + return MNL_CB_ERROR; + pr_out_port(tb); + return MNL_CB_OK; +} + +static int cmd_port_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + int err; + + if (dl_argc(dl) == 0) + flags |= NLM_F_DUMP; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags); + + if (dl_argc(dl) > 0) { + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0); + if (err) + return err; + } + + return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, NULL); +} + +static int cmd_port_set(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_port_split(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_port_unsplit(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_port(struct dl *dl) +{ + if (dl_argv_match(dl, "help")) { + cmd_port_help(); + return 0; + } else if (dl_argv_match(dl, "show") || + dl_argv_match(dl, "list") || dl_no_arg(dl)) { + dl_arg_inc(dl); + return cmd_port_show(dl); + } else if (dl_argv_match(dl, "set")) { + dl_arg_inc(dl); + return cmd_port_set(dl); + } else if (dl_argv_match(dl, "split")) { + dl_arg_inc(dl); + return cmd_port_split(dl); + } else if (dl_argv_match(dl, "unsplit")) { + dl_arg_inc(dl); + return cmd_port_unsplit(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static const char *cmd_name(uint8_t cmd) +{ + switch (cmd) { + case DEVLINK_CMD_UNSPEC: return "unspec"; + case DEVLINK_CMD_GET: return "get"; + case DEVLINK_CMD_SET: return "set"; + case DEVLINK_CMD_NEW: return "new"; + case DEVLINK_CMD_DEL: return "del"; + case DEVLINK_CMD_PORT_GET: return "get"; + case DEVLINK_CMD_PORT_SET: return "set"; + case DEVLINK_CMD_PORT_NEW: return "net"; + case DEVLINK_CMD_PORT_DEL: return "del"; + default: return ""; + } +} + +static const char *cmd_obj(uint8_t cmd) +{ + switch (cmd) { + case DEVLINK_CMD_UNSPEC: return "unspec"; + case DEVLINK_CMD_GET: + case DEVLINK_CMD_SET: + case DEVLINK_CMD_NEW: + case DEVLINK_CMD_DEL: + return "dev"; + case DEVLINK_CMD_PORT_GET: + case DEVLINK_CMD_PORT_SET: + case DEVLINK_CMD_PORT_NEW: + case DEVLINK_CMD_PORT_DEL: + return "port"; + default: return ""; + } +} + +static void pr_out_mon_header(uint8_t cmd) +{ + pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd)); +} + +static bool cmd_filter_check(struct dl *dl, uint8_t cmd) +{ + const char *obj = cmd_obj(cmd); + unsigned int index = 0; + const char *cur_obj; + + if (dl_no_arg(dl)) + return true; + while ((cur_obj = dl_argv_index(dl, index++))) { + if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0) + return true; + } + return false; +} + +static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + uint8_t cmd = genl->cmd; + + if (!cmd_filter_check(dl, cmd)) + return MNL_CB_OK; + + switch (cmd) { + case DEVLINK_CMD_GET: /* fall through */ + case DEVLINK_CMD_SET: /* fall through */ + case DEVLINK_CMD_NEW: /* fall through */ + case DEVLINK_CMD_DEL: + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) + return MNL_CB_ERROR; + pr_out_mon_header(genl->cmd); + pr_out_dev(tb); + break; + case DEVLINK_CMD_PORT_GET: /* fall through */ + case DEVLINK_CMD_PORT_SET: /* fall through */ + case DEVLINK_CMD_PORT_NEW: /* fall through */ + case DEVLINK_CMD_PORT_DEL: + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_PORT_INDEX]) + return MNL_CB_ERROR; + pr_out_mon_header(genl->cmd); + pr_out_port(tb); + break; + } + return MNL_CB_OK; +} + +static int cmd_mon_show(struct dl *dl) +{ + int err; + unsigned int index = 0; + const char *cur_obj; + + while ((cur_obj = dl_argv_index(dl, index++))) { + if (strcmp(cur_obj, "all") != 0 && + strcmp(cur_obj, "dev") != 0 && + strcmp(cur_obj, "port") != 0) { + pr_err("Unknown object \"%s\"\n", cur_obj); + return -EINVAL; + } + } + err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME); + if (err) + return err; + err = _mnlg_socket_recv_run(dl->nlg, cmd_mon_show_cb, dl); + if (err) + return err; + return 0; +} + +static void cmd_mon_help(void) +{ + pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n" + "where OBJECT-LIST := { dev | port }\n"); +} + +static int cmd_mon(struct dl *dl) +{ + if (dl_argv_match(dl, "help")) { + cmd_mon_help(); + return 0; + } else if (dl_no_arg(dl)) { + dl_arg_inc(dl); + return cmd_mon_show(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static void help(void) +{ + pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" + "where OBJECT := { dev | port | monitor }\n" + " OPTIONS := { -V[ersion] }\n"); +} + +static int dl_cmd(struct dl *dl) +{ + if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { + help(); + return 0; + } else if (dl_argv_match(dl, "dev")) { + dl_arg_inc(dl); + return cmd_dev(dl); + } else if (dl_argv_match(dl, "port")) { + dl_arg_inc(dl); + return cmd_port(dl); + } else if (dl_argv_match(dl, "monitor")) { + dl_arg_inc(dl); + return cmd_mon(dl); + } + pr_err("Object \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static int dl_init(struct dl *dl, int argc, char **argv) +{ + int err; + + dl->argc = argc; + dl->argv = argv; + + dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION); + if (!dl->nlg) { + pr_err("Failed to connect to devlink Netlink\n"); + return -errno; + } + + err = ifname_map_init(dl); + if (err) { + pr_err("Failed to create index map\n"); + goto err_ifname_map_create; + } + return 0; + +err_ifname_map_create: + mnlg_socket_close(dl->nlg); + return err; +} + +static void dl_fini(struct dl *dl) +{ + ifname_map_fini(dl); + mnlg_socket_close(dl->nlg); +} + +static struct dl *dl_alloc(void) +{ + struct dl *dl; + + dl = calloc(1, sizeof(*dl)); + if (!dl) + return NULL; + return dl; +} + +static void dl_free(struct dl *dl) +{ + free(dl); +} + +int main(int argc, char **argv) +{ + static const struct option long_options[] = { + { "Version", no_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 } + }; + struct dl *dl; + int opt; + int err; + int ret; + + while ((opt = getopt_long(argc, argv, "V", + long_options, NULL)) >= 0) { + + switch (opt) { + case 'V': + printf("devlink utility, iproute2-ss%s\n", SNAPSHOT); + return EXIT_SUCCESS; + default: + pr_err("Unknown option.\n"); + help(); + return EXIT_FAILURE; + } + } + + argc -= optind; + argv += optind; + + dl = dl_alloc(); + if (!dl) { + pr_err("Failed to allocate memory for devlink\n"); + return EXIT_FAILURE; + } + + err = dl_init(dl, argc, argv); + if (err) { + ret = EXIT_FAILURE; + goto dl_free; + } + + err = dl_cmd(dl); + if (err) { + ret = EXIT_FAILURE; + goto dl_fini; + } + + ret = EXIT_SUCCESS; + +dl_fini: + dl_fini(dl); +dl_free: + dl_free(dl); + + return ret; +} diff --git a/devlink/mnlg.c b/devlink/mnlg.c new file mode 100644 index 000000000..9e27de275 --- /dev/null +++ b/devlink/mnlg.c @@ -0,0 +1,274 @@ +/* + * mnlg.c Generic Netlink helpers for libmnl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Jiri Pirko + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mnlg.h" + +struct mnlg_socket { + struct mnl_socket *nl; + char *buf; + uint32_t id; + uint8_t version; + unsigned int seq; + unsigned int portid; +}; + +static struct nlmsghdr *__mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd, + uint16_t flags, uint32_t id, + uint8_t version) +{ + struct nlmsghdr *nlh; + struct genlmsghdr *genl; + + nlh = mnl_nlmsg_put_header(nlg->buf); + nlh->nlmsg_type = id; + nlh->nlmsg_flags = flags; + nlg->seq = time(NULL); + nlh->nlmsg_seq = nlg->seq; + + genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr)); + genl->cmd = cmd; + genl->version = version; + + return nlh; +} + +struct nlmsghdr *mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd, + uint16_t flags) +{ + return __mnlg_msg_prepare(nlg, cmd, flags, nlg->id, nlg->version); +} + +int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsghdr *nlh) +{ + return mnl_socket_sendto(nlg->nl, nlh, nlh->nlmsg_len); +} + +int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data) +{ + int err; + + do { + err = mnl_socket_recvfrom(nlg->nl, nlg->buf, + MNL_SOCKET_BUFFER_SIZE); + if (err <= 0) + break; + err = mnl_cb_run(nlg->buf, err, nlg->seq, nlg->portid, + data_cb, data); + } while (err > 0); + + return err; +} + +struct group_info { + bool found; + uint32_t id; + const char *name; +}; + +static int parse_mc_grps_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTRL_ATTR_MCAST_GRP_MAX) < 0) + return MNL_CB_OK; + + switch (type) { + case CTRL_ATTR_MCAST_GRP_ID: + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; + break; + case CTRL_ATTR_MCAST_GRP_NAME: + if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) + return MNL_CB_ERROR; + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static void parse_genl_mc_grps(struct nlattr *nested, + struct group_info *group_info) +{ + struct nlattr *pos; + const char *name; + + mnl_attr_for_each_nested(pos, nested) { + struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1] = {}; + + mnl_attr_parse_nested(pos, parse_mc_grps_cb, tb); + if (!tb[CTRL_ATTR_MCAST_GRP_NAME] || + !tb[CTRL_ATTR_MCAST_GRP_ID]) + continue; + + name = mnl_attr_get_str(tb[CTRL_ATTR_MCAST_GRP_NAME]); + if (strcmp(name, group_info->name) != 0) + continue; + + group_info->id = mnl_attr_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]); + group_info->found = true; + } +} + +static int get_group_id_attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0) + return MNL_CB_ERROR; + + if (type == CTRL_ATTR_MCAST_GROUPS && + mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) + return MNL_CB_ERROR; + tb[type] = attr; + return MNL_CB_OK; +} + +static int get_group_id_cb(const struct nlmsghdr *nlh, void *data) +{ + struct group_info *group_info = data; + struct nlattr *tb[CTRL_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), get_group_id_attr_cb, tb); + if (!tb[CTRL_ATTR_MCAST_GROUPS]) + return MNL_CB_ERROR; + parse_genl_mc_grps(tb[CTRL_ATTR_MCAST_GROUPS], group_info); + return MNL_CB_OK; +} + +int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name) +{ + struct nlmsghdr *nlh; + struct group_info group_info; + int err; + + nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY, + NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1); + mnl_attr_put_u32(nlh, CTRL_ATTR_FAMILY_ID, nlg->id); + + err = mnlg_socket_send(nlg, nlh); + if (err < 0) + return err; + + group_info.found = false; + group_info.name = group_name; + err = mnlg_socket_recv_run(nlg, get_group_id_cb, &group_info); + if (err < 0) + return err; + + if (!group_info.found) { + errno = ENOENT; + return -1; + } + + err = mnl_socket_setsockopt(nlg->nl, NETLINK_ADD_MEMBERSHIP, + &group_info.id, sizeof(group_info.id)); + if (err < 0) + return err; + + return 0; +} + +static int get_family_id_attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0) + return MNL_CB_ERROR; + + if (type == CTRL_ATTR_FAMILY_ID && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; + tb[type] = attr; + return MNL_CB_OK; +} + +static int get_family_id_cb(const struct nlmsghdr *nlh, void *data) +{ + uint32_t *p_id = data; + struct nlattr *tb[CTRL_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), get_family_id_attr_cb, tb); + if (!tb[CTRL_ATTR_FAMILY_ID]) + return MNL_CB_ERROR; + *p_id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]); + return MNL_CB_OK; +} + +struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version) +{ + struct mnlg_socket *nlg; + struct nlmsghdr *nlh; + int err; + + nlg = malloc(sizeof(*nlg)); + if (!nlg) + return NULL; + + nlg->buf = malloc(MNL_SOCKET_BUFFER_SIZE); + if (!nlg->buf) + goto err_buf_alloc; + + nlg->nl = mnl_socket_open(NETLINK_GENERIC); + if (!nlg->nl) + goto err_mnl_socket_open; + + err = mnl_socket_bind(nlg->nl, 0, MNL_SOCKET_AUTOPID); + if (err < 0) + goto err_mnl_socket_bind; + + nlg->portid = mnl_socket_get_portid(nlg->nl); + + nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY, + NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1); + mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name); + + err = mnlg_socket_send(nlg, nlh); + if (err < 0) + goto err_mnlg_socket_send; + + err = mnlg_socket_recv_run(nlg, get_family_id_cb, &nlg->id); + if (err < 0) + goto err_mnlg_socket_recv_run; + + nlg->version = version; + return nlg; + +err_mnlg_socket_recv_run: +err_mnlg_socket_send: +err_mnl_socket_bind: + mnl_socket_close(nlg->nl); +err_mnl_socket_open: + free(nlg->buf); +err_buf_alloc: + free(nlg); + return NULL; +} + +void mnlg_socket_close(struct mnlg_socket *nlg) +{ + mnl_socket_close(nlg->nl); + free(nlg->buf); + free(nlg); +} diff --git a/devlink/mnlg.h b/devlink/mnlg.h new file mode 100644 index 000000000..4d1babf3b --- /dev/null +++ b/devlink/mnlg.h @@ -0,0 +1,27 @@ +/* + * mnlg.h Generic Netlink helpers for libmnl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Jiri Pirko + */ + +#ifndef _MNLG_H_ +#define _MNLG_H_ + +#include + +struct mnlg_socket; + +struct nlmsghdr *mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd, + uint16_t flags); +int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsghdr *nlh); +int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data); +int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name); +struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version); +void mnlg_socket_close(struct mnlg_socket *nlg); + +#endif /* _MNLG_H_ */ diff --git a/include/linux/devlink.h b/include/linux/devlink.h new file mode 100644 index 000000000..c9fee5781 --- /dev/null +++ b/include/linux/devlink.h @@ -0,0 +1,72 @@ +/* + * include/uapi/linux/devlink.h - Network physical device Netlink interface + * Copyright (c) 2016 Mellanox Technologies. All rights reserved. + * Copyright (c) 2016 Jiri Pirko + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _UAPI_LINUX_DEVLINK_H_ +#define _UAPI_LINUX_DEVLINK_H_ + +#define DEVLINK_GENL_NAME "devlink" +#define DEVLINK_GENL_VERSION 0x1 +#define DEVLINK_GENL_MCGRP_CONFIG_NAME "config" + +enum devlink_command { + /* don't change the order or add anything between, this is ABI! */ + DEVLINK_CMD_UNSPEC, + + DEVLINK_CMD_GET, /* can dump */ + DEVLINK_CMD_SET, + DEVLINK_CMD_NEW, + DEVLINK_CMD_DEL, + + DEVLINK_CMD_PORT_GET, /* can dump */ + DEVLINK_CMD_PORT_SET, + DEVLINK_CMD_PORT_NEW, + DEVLINK_CMD_PORT_DEL, + + DEVLINK_CMD_PORT_SPLIT, + DEVLINK_CMD_PORT_UNSPLIT, + + /* add new commands above here */ + + __DEVLINK_CMD_MAX, + DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1 +}; + +enum devlink_port_type { + DEVLINK_PORT_TYPE_NOTSET, + DEVLINK_PORT_TYPE_AUTO, + DEVLINK_PORT_TYPE_ETH, + DEVLINK_PORT_TYPE_IB, +}; + +enum devlink_attr { + /* don't change the order or add anything between, this is ABI! */ + DEVLINK_ATTR_UNSPEC, + + /* bus name + dev name together are a handle for devlink entity */ + DEVLINK_ATTR_BUS_NAME, /* string */ + DEVLINK_ATTR_DEV_NAME, /* string */ + + DEVLINK_ATTR_PORT_INDEX, /* u32 */ + DEVLINK_ATTR_PORT_TYPE, /* u16 */ + DEVLINK_ATTR_PORT_DESIRED_TYPE, /* u16 */ + DEVLINK_ATTR_PORT_NETDEV_IFINDEX, /* u32 */ + DEVLINK_ATTR_PORT_NETDEV_NAME, /* string */ + DEVLINK_ATTR_PORT_IBDEV_NAME, /* string */ + DEVLINK_ATTR_PORT_SPLIT_COUNT, /* u32 */ + DEVLINK_ATTR_PORT_SPLIT_GROUP, /* u32 */ + + /* add new attributes above here, update the policy in devlink.c */ + + __DEVLINK_ATTR_MAX, + DEVLINK_ATTR_MAX = __DEVLINK_ATTR_MAX - 1 +}; + +#endif /* _UAPI_LINUX_DEVLINK_H_ */ diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8 new file mode 100644 index 000000000..7878d89b3 --- /dev/null +++ b/man/man8/devlink-dev.8 @@ -0,0 +1,58 @@ +.TH DEVLINK\-DEV 8 "14 Mar 2016" "iproute2" "Linux" +.SH NAME +devlink-dev \- devlink device configuration +.SH SYNOPSIS +.sp +.ad l +.in +8 +.ti -8 +.B devlink +.RI "[ " OPTIONS " ]" +.B dev +.RI " { " COMMAND " | " +.BR help " }" +.sp + +.ti -8 +.IR OPTIONS " := { " +\fB\-V\fR[\fIersion\fR] | + +.ti -8 +.B devlink dev show +.RI "[ " DEV " ]" + +.ti -8 +.B devlink dev help + +.SH "DESCRIPTION" +.SS devlink dev show - display devlink device attributes + +.PP +.I "DEV" +- specifies the devlink device to show. +If this argument is omitted all devices are listed. + +.in +4 +Format is: +.in +2 +BUS_NAME/BUS_ADDRESS + +.SH "EXAMPLES" +.PP +devlink dev show +.RS 4 +Shows the state of all devlink devices on the system. +.RE +.PP +devlink dev show pci/0000:01:00.0 +.RS 4 +Shows the state of specified devlink device. + +.SH SEE ALSO +.BR devlink (8), +.BR devlink-port (8), +.BR devlink-monitor (8), +.br + +.SH AUTHOR +Jiri Pirko diff --git a/man/man8/devlink-monitor.8 b/man/man8/devlink-monitor.8 new file mode 100644 index 000000000..98134c370 --- /dev/null +++ b/man/man8/devlink-monitor.8 @@ -0,0 +1,36 @@ +.TH DEVLINK\-MONITOR 8 "14 Mar 2016" "iproute2" "Linux" +.SH "NAME" +devlink-monitor \- state monitoring +.SH SYNOPSIS +.sp +.ad l +.in +8 +.ti -8 +.BR "devlink monitor" " [ " all " |" +.IR OBJECT-LIST " ]" +.sp + +.SH DESCRIPTION +The +.B devlink +utility can monitor the state of devlink devices and ports +continuously. This option has a slightly different format. Namely, the +.B monitor +command is the first in the command line and then the object list. + +.I OBJECT-LIST +is the list of object types that we want to monitor. +It may contain +.BR dev ", " port ". + +.B devlink +opens Devlink Netlink socket, listens on it and dumps state changes. + +.SH SEE ALSO +.BR devlink (8), +.BR devlink-dev (8), +.BR devlink-port (8), +.br + +.SH AUTHOR +Jiri Pirko diff --git a/man/man8/devlink-port.8 b/man/man8/devlink-port.8 new file mode 100644 index 000000000..e6ae6869b --- /dev/null +++ b/man/man8/devlink-port.8 @@ -0,0 +1,126 @@ +.TH DEVLINK\-PORT 8 "14 Mar 2016" "iproute2" "Linux" +.SH NAME +devlink-port \- devlink port configuration +.SH SYNOPSIS +.sp +.ad l +.in +8 +.ti -8 +.B devlink +.RI "[ " OPTIONS " ]" +.B port +.RI " { " COMMAND " | " +.BR help " }" +.sp + +.ti -8 +.IR OPTIONS " := { " +\fB\-V\fR[\fIersion\fR] | + +.ti -8 +.BR "devlink port set " +.IR DEV/PORT_INDEX +.RI "[ " +.BR type " { " eth " | " ib " | " auto " }" +.RI "]" + +.ti -8 +.BR "devlink port split " +.IR DEV/PORT_INDEX +.BR count +.IR COUNT + +.ti -8 +.BR "devlink port unsplit " +.IR DEV/PORT_INDEX + +.ti -8 +.B devlink port show +.RI "[ " DEV/PORT_INDEX " ]" + +.ti -8 +.B devlink port help + +.SH "DESCRIPTION" +.SS devlink port set - change devlink port attributes + +.PP +.B "DEV/PORT_INDEX" +- specifies the devlink port to operate on. + +.in +4 +Format is: +.in +2 +BUS_NAME/BUS_ADDRESS/PORT_INDEX + +.TP +.BR type " { " eth " | " ib " | " auto " } " +set port type + +.I eth +- Ethernet + +.I ib +- Infiniband + +.I auto +- autoselect + +.SS devlink port split - split devlink port into more + +.PP +.B "DEV/PORT_INDEX" +- specifies the devlink port to operate on. + +.TP +.BI count " COUNT" +number of ports to split to. + +.SS devlink port unsplit - unsplit previously split devlink port +Could be performed on any split port of the same split group. + +.PP +.B "DEV/PORT_INDEX" +- specifies the devlink port to operate on. + +.SS devlink port show - display devlink port attributes + +.PP +.I "DEV/PORT_INDEX" +- specifies the devlink port to show. +If this argument is omitted all ports are listed. + +.SH "EXAMPLES" +.PP +devlink port show +.RS 4 +Shows the state of all devlink ports on the system. +.RE +.PP +devlink port show pci/0000:01:00.0/1 +.RS 4 +Shows the state of specified devlink port. +.RE +.PP +devlink port set pci/0000:01:00.0/1 type eth +.RS 4 +Set type of specified devlink port to Ethernet. +.RE +.PP +devlink port split pci/0000:01:00.0/1 count 4 +.RS 4 +Split the specified devlink port into four ports. +.RE +.PP +devlink port unsplit pci/0000:01:00.0/1 +.RS 4 +Unplit the specified previously split devlink port. + +.SH SEE ALSO +.BR devlink (8), +.BR devlink-dev (8), +.BR devlink-monitor (8), +.br + +.SH AUTHOR +Jiri Pirko diff --git a/man/man8/devlink.8 b/man/man8/devlink.8 new file mode 100644 index 000000000..f608ccca2 --- /dev/null +++ b/man/man8/devlink.8 @@ -0,0 +1,83 @@ +.TH DEVLINK 8 "14 Mar 2016" "iproute2" "Linux" +.SH NAME +devlink \- Devlink tool +.SH SYNOPSIS +.sp +.ad l +.in +8 +.ti -8 +.B devlink +.RI "[ " OPTIONS " ] " OBJECT " { " COMMAND " | " +.BR help " }" +.sp + +.ti -8 +.IR OBJECT " := { " +.BR dev " | " port " | " monitor " }" +.sp + +.ti -8 +.IR OPTIONS " := { " +\fB\-V\fR[\fIersion\fR] | + +.SH OPTIONS + +.TP +.BR "\-V" , " -Version" +Print the version of the +.B devlink +utility and exit. + +.SS +.I OBJECT + +.TP +.B dev +- devlink device. + +.TP +.B port +- devlink port. + +.TP +.B monitor +- watch for netlink messages. + +.SS +.I COMMAND + +Specifies the action to perform on the object. +The set of possible actions depends on the object type. +As a rule, it is possible to +.B show +(or +.B list +) objects, but some objects do not allow all of these operations +or have some additional commands. The +.B help +command is available for all objects. It prints +out a list of available commands and argument syntax conventions. +.sp +If no command is given, some default command is assumed. +Usually it is +.B list +or, if the objects of this class cannot be listed, +.BR "help" . + +.SH EXIT STATUS +Exit status is 0 if command was successful or a positive integer upon failure. + +.SH SEE ALSO +.BR devlink-dev (8), +.BR devlink-port (8), +.BR devlink-monitor (8), +.br + +.SH REPORTING BUGS +Report any bugs to the Network Developers mailing list +.B +where the development and maintenance is primarily done. +You do not have to be subscribed to the list to send a message there. + +.SH AUTHOR +Jiri Pirko From f8eb79a6244349d0f987e98b14b222fbf706bdb8 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 24 Mar 2016 16:49:55 +0100 Subject: [PATCH 172/513] vxlan: add support to set flow label Follow-up for kernel commit e7f70af111f0 ("vxlan: support setting IPv6 flow label") to allow setting the label for the device config. Signed-off-by: Daniel Borkmann --- ip/ip_common.h | 4 ++++ ip/iplink_vxlan.c | 29 ++++++++++++++++++++++++----- man/man8/ip-link.8.in | 6 ++++++ 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/ip/ip_common.h b/ip/ip_common.h index 815487a07..b7361a8fc 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -92,3 +92,7 @@ void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len); #ifndef INFINITY_LIFE_TIME #define INFINITY_LIFE_TIME 0xFFFFFFFFU #endif + +#ifndef LABEL_MAX_MASK +#define LABEL_MAX_MASK 0xFFFFFU +#endif diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index 8dcf5316b..e3bbea003 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -24,7 +24,7 @@ static void print_explain(FILE *f) { fprintf(f, "Usage: ... vxlan id VNI [ { group | remote } IP_ADDRESS ] [ local ADDR ]\n"); - fprintf(f, " [ ttl TTL ] [ tos TOS ] [ dev PHYS_DEV ]\n"); + fprintf(f, " [ ttl TTL ] [ tos TOS ] [ flowlabel LABEL ] [ dev PHYS_DEV ]\n"); fprintf(f, " [ dstport PORT ] [ srcport MIN MAX ]\n"); fprintf(f, " [ [no]learning ] [ [no]proxy ] [ [no]rsc ]\n"); fprintf(f, " [ [no]l2miss ] [ [no]l3miss ]\n"); @@ -33,10 +33,11 @@ static void print_explain(FILE *f) fprintf(f, " [ [no]remcsumtx ] [ [no]remcsumrx ]\n"); fprintf(f, " [ [no]external ] [ gbp ]\n"); fprintf(f, "\n"); - fprintf(f, "Where: VNI := 0-16777215\n"); - fprintf(f, " ADDR := { IP_ADDRESS | any }\n"); - fprintf(f, " TOS := { NUMBER | inherit }\n"); - fprintf(f, " TTL := { 1..255 | inherit }\n"); + fprintf(f, "Where: VNI := 0-16777215\n"); + fprintf(f, " ADDR := { IP_ADDRESS | any }\n"); + fprintf(f, " TOS := { NUMBER | inherit }\n"); + fprintf(f, " TTL := { 1..255 | inherit }\n"); + fprintf(f, " LABEL := 0-1048575\n"); } static void explain(void) @@ -58,6 +59,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, unsigned int link = 0; __u8 tos = 0; __u8 ttl = 0; + __u32 label = 0; __u8 learning = 1; __u8 proxy = 0; __u8 rsc = 0; @@ -146,6 +148,15 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, tos = uval; } else tos = 1; + } else if (!matches(*argv, "label") || + !matches(*argv, "flowlabel")) { + __u32 uval; + + NEXT_ARG(); + if (get_u32(&uval, *argv, 0) || + (uval & ~LABEL_MAX_MASK)) + invarg("invalid flowlabel", *argv); + label = htonl(uval); } else if (!matches(*argv, "ageing")) { NEXT_ARG(); if (strcmp(*argv, "none") == 0) @@ -280,6 +291,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, if (link) addattr32(n, 1024, IFLA_VXLAN_LINK, link); + addattr32(n, 1024, IFLA_VXLAN_LABEL, label); addattr8(n, 1024, IFLA_VXLAN_TTL, ttl); addattr8(n, 1024, IFLA_VXLAN_TOS, tos); addattr8(n, 1024, IFLA_VXLAN_LEARNING, learning); @@ -425,6 +437,13 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fprintf(f, "ttl %d ", ttl); } + if (tb[IFLA_VXLAN_LABEL]) { + __u32 label = rta_getattr_u32(tb[IFLA_VXLAN_LABEL]); + + if (label) + fprintf(f, "flowlabel %#x ", ntohl(label)); + } + if (tb[IFLA_VXLAN_AGEING]) { __u32 age = rta_getattr_u32(tb[IFLA_VXLAN_AGEING]); diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 2cd93b0ff..f115c1991 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -396,6 +396,8 @@ the following additional arguments are supported: ] [ .BI tos " TOS " ] [ +.BI flowlabel " FLOWLABEL " +] [ .BI dstport " PORT " ] [ .BI srcport " MIN MAX " @@ -459,6 +461,10 @@ parameter. .BI tos " TOS" - specifies the TOS value to use in outgoing packets. +.sp +.BI flowlabel " FLOWLABEL" +- specifies the flow label to use in outgoing packets. + .sp .BI dstport " PORT" - specifies the UDP destination port to communicate to the remote VXLAN tunnel endpoint. From 29bb2373a8777d0c8b8c68450a872c19bc7f245c Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 24 Mar 2016 16:49:56 +0100 Subject: [PATCH 173/513] geneve: add support to set flow label Follow-up for kernel commit 8eb3b99554b8 ("geneve: support setting IPv6 flow label") to allow setting the label for the device config. Signed-off-by: Daniel Borkmann --- ip/iplink_geneve.c | 29 ++++++++++++++++++++++++----- man/man8/ip-link.8.in | 6 ++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c index 1c6879e76..84d948fc7 100644 --- a/ip/iplink_geneve.c +++ b/ip/iplink_geneve.c @@ -18,14 +18,15 @@ static void print_explain(FILE *f) { fprintf(f, "Usage: ... geneve id VNI remote ADDR\n"); - fprintf(f, " [ ttl TTL ] [ tos TOS ]\n"); + fprintf(f, " [ ttl TTL ] [ tos TOS ] [ flowlabel LABEL ]\n"); fprintf(f, " [ dstport PORT ] [ [no]external ]\n"); fprintf(f, " [ [no]udpcsum ] [ [no]udp6zerocsumtx ] [ [no]udp6zerocsumrx ]\n"); fprintf(f, "\n"); - fprintf(f, "Where: VNI := 0-16777215\n"); - fprintf(f, " ADDR := IP_ADDRESS\n"); - fprintf(f, " TOS := { NUMBER | inherit }\n"); - fprintf(f, " TTL := { 1..255 | inherit }\n"); + fprintf(f, "Where: VNI := 0-16777215\n"); + fprintf(f, " ADDR := IP_ADDRESS\n"); + fprintf(f, " TOS := { NUMBER | inherit }\n"); + fprintf(f, " TTL := { 1..255 | inherit }\n"); + fprintf(f, " LABEL := 0-1048575\n"); } static void explain(void) @@ -40,6 +41,7 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, int vni_set = 0; __u32 daddr = 0; struct in6_addr daddr6 = IN6ADDR_ANY_INIT; + __u32 label = 0; __u8 ttl = 0; __u8 tos = 0; __u16 dstport = 0; @@ -90,6 +92,15 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, tos = uval; } else tos = 1; + } else if (!matches(*argv, "label") || + !matches(*argv, "flowlabel")) { + __u32 uval; + + NEXT_ARG(); + if (get_u32(&uval, *argv, 0) || + (uval & ~LABEL_MAX_MASK)) + invarg("invalid flowlabel", *argv); + label = htonl(uval); } else if (!matches(*argv, "dstport")) { NEXT_ARG(); if (get_u16(&dstport, *argv, 0)) @@ -150,6 +161,7 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, addattr_l(n, 1024, IFLA_GENEVE_REMOTE, &daddr, 4); if (memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) != 0) addattr_l(n, 1024, IFLA_GENEVE_REMOTE6, &daddr6, sizeof(struct in6_addr)); + addattr32(n, 1024, IFLA_GENEVE_LABEL, label); addattr8(n, 1024, IFLA_GENEVE_TTL, ttl); addattr8(n, 1024, IFLA_GENEVE_TOS, tos); if (dstport) @@ -213,6 +225,13 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fprintf(f, "tos %#x ", tos); } + if (tb[IFLA_GENEVE_LABEL]) { + __u32 label = rta_getattr_u32(tb[IFLA_GENEVE_LABEL]); + + if (label) + fprintf(f, "flowlabel %#x ", ntohl(label)); + } + if (tb[IFLA_GENEVE_PORT]) fprintf(f, "dstport %u ", ntohs(rta_getattr_u16(tb[IFLA_GENEVE_PORT]))); diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index f115c1991..805511423 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -752,6 +752,8 @@ the following additional arguments are supported: .BI ttl " TTL " ] [ .BI tos " TOS " +] [ +.BI flowlabel " FLOWLABEL " ] .in +8 @@ -771,6 +773,10 @@ the following additional arguments are supported: .BI tos " TOS" - specifies the TOS value to use in outgoing packets. +.sp +.BI flowlabel " FLOWLABEL" +- specifies the flow label to use in outgoing packets. + .in -8 .TP From 3273e3c13258a1845d1bc7eaa012c4824f4b47cb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 11 Apr 2016 13:32:22 -0700 Subject: [PATCH 174/513] devlink: ignore build result devlink binary is built --- devlink/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 devlink/.gitignore diff --git a/devlink/.gitignore b/devlink/.gitignore new file mode 100644 index 000000000..08d175f08 --- /dev/null +++ b/devlink/.gitignore @@ -0,0 +1 @@ +devlink From 6268b08c13e9513b51d66a0d167fb5ecf23f3ce8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 11 Apr 2016 13:40:40 -0700 Subject: [PATCH 175/513] update kernel headers Update from 4.6-rc3 --- include/linux/bpf.h | 1 + include/linux/if_link.h | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index dc043ef1f..0f5d6f549 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -375,6 +375,7 @@ struct bpf_tunnel_key { }; __u8 tunnel_tos; __u8 tunnel_ttl; + __u16 tunnel_ext; __u32 tunnel_label; }; diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 9b7f3c8d6..6a688e8c6 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -153,6 +153,8 @@ enum { IFLA_LINK_NETNSID, IFLA_PHYS_PORT_NAME, IFLA_PROTO_DOWN, + IFLA_GSO_MAX_SEGS, + IFLA_GSO_MAX_SIZE, __IFLA_MAX }; @@ -597,6 +599,8 @@ enum { */ IFLA_VF_STATS, /* network device statistics */ IFLA_VF_TRUST, /* Trust VF */ + IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */ + IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */ __IFLA_VF_MAX, }; @@ -629,6 +633,11 @@ struct ifla_vf_spoofchk { __u32 setting; }; +struct ifla_vf_guid { + __u32 vf; + __u64 guid; +}; + enum { IFLA_VF_LINK_STATE_AUTO, /* link state of the uplink */ IFLA_VF_LINK_STATE_ENABLE, /* link always up */ From bc9fb25788eb3a5e17df43d35ae4885471929ce7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 11 Apr 2016 13:44:50 -0700 Subject: [PATCH 176/513] update kernel headers Headers up to date with 4.6-net-next --- include/linux/bpf.h | 1 + include/linux/if_link.h | 1 + include/linux/sock_diag.h | 1 + 3 files changed, 3 insertions(+) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 0f5d6f549..3398b5de8 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -92,6 +92,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_KPROBE, BPF_PROG_TYPE_SCHED_CLS, BPF_PROG_TYPE_SCHED_ACT, + BPF_PROG_TYPE_TRACEPOINT, }; #define BPF_PSEUDO_MAP_FD 1 diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 6a688e8c6..e296f2938 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -486,6 +486,7 @@ enum { IFLA_VXLAN_REMCSUM_NOPARTIAL, IFLA_VXLAN_COLLECT_METADATA, IFLA_VXLAN_LABEL, + IFLA_VXLAN_GPE, __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h index dafcb891a..901231e64 100644 --- a/include/linux/sock_diag.h +++ b/include/linux/sock_diag.h @@ -20,6 +20,7 @@ enum { SK_MEMINFO_WMEM_QUEUED, SK_MEMINFO_OPTMEM, SK_MEMINFO_BACKLOG, + SK_MEMINFO_DROPS, SK_MEMINFO_VARS, }; From f1c656e5c0f0bed919a87856e3916116e6e4c2a4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Apr 2016 16:11:39 -0700 Subject: [PATCH 177/513] iplink: display number of rx/tx queues We can set the attributes, so would be nice to display them when provided by the kernel. Signed-off-by: Eric Dumazet --- ip/ipaddress.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 3998d8cec..f7bd1c76b 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -894,6 +894,12 @@ int print_linkinfo(const struct sockaddr_nl *who, if (do_link && tb[IFLA_AF_SPEC] && show_details) print_af_spec(fp, tb[IFLA_AF_SPEC]); + if (tb[IFLA_NUM_TX_QUEUES] && show_details) + fprintf(fp, "numtxqueues %u ", rta_getattr_u32(tb[IFLA_NUM_TX_QUEUES])); + + if (tb[IFLA_NUM_RX_QUEUES] && show_details) + fprintf(fp, "numrxqueues %u ", rta_getattr_u32(tb[IFLA_NUM_RX_QUEUES])); + if ((do_link || show_details) && tb[IFLA_IFALIAS]) { fprintf(fp, "%s alias %s", _SL_, rta_getattr_str(tb[IFLA_IFALIAS])); From ae6eb9075fdfe1bf0804c9a9315a37e111e8e293 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Mon, 11 Apr 2016 17:45:14 +0200 Subject: [PATCH 178/513] bridge: fdb: add support to filter by vlan id Add the optional keyword "vlan" to bridge fdb show so the user can request filtering by a specific vlan id. Currently the filtering is implemented only in user-space. The argument name has been chosen to match the add/del one - "vlan". Example: $ bridge fdb show vlan 400 52:54:00:bf:57:16 dev eth2 vlan 400 master br0 permanent Signed-off-by: Nikolay Aleksandrov --- bridge/fdb.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/bridge/fdb.c b/bridge/fdb.c index df55e86df..be849f980 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -27,7 +27,7 @@ #include "rt_names.h" #include "utils.h" -static unsigned int filter_index; +static unsigned int filter_index, filter_vlan; static void usage(void) { @@ -35,7 +35,7 @@ static void usage(void) " [ self ] [ master ] [ use ] [ router ]\n" " [ local | static | dynamic ] [ dst IPADDR ] [ vlan VID ]\n" " [ port PORT] [ vni VNI ] [ via DEV ]\n"); - fprintf(stderr, " bridge fdb [ show [ br BRDEV ] [ brport DEV ] ]\n"); + fprintf(stderr, " bridge fdb [ show [ br BRDEV ] [ brport DEV ] [ vlan VID ] ]\n"); exit(-1); } @@ -65,6 +65,7 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) struct ndmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[NDA_MAX+1]; + __u16 vid = 0; if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) { fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n", @@ -88,6 +89,12 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); + if (tb[NDA_VLAN]) + vid = rta_getattr_u16(tb[NDA_VLAN]); + + if (filter_vlan && filter_vlan != vid) + return 0; + if (n->nlmsg_type == RTM_DELNEIGH) fprintf(fp, "Deleted "); @@ -115,11 +122,8 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) RTA_DATA(tb[NDA_DST]))); } - if (tb[NDA_VLAN]) { - __u16 vid = rta_getattr_u16(tb[NDA_VLAN]); - + if (vid) fprintf(fp, "vlan %hu ", vid); - } if (tb[NDA_PORT]) fprintf(fp, "port %d ", ntohs(rta_getattr_u16(tb[NDA_PORT]))); @@ -190,6 +194,11 @@ static int fdb_show(int argc, char **argv) } else if (strcmp(*argv, "br") == 0) { NEXT_ARG(); br = *argv; + } else if (strcmp(*argv, "vlan") == 0) { + NEXT_ARG(); + if (filter_vlan) + duparg("vlan", *argv); + filter_vlan = atoi(*argv); } else { if (matches(*argv, "help") == 0) usage(); From 24687d678fd540c554f76dd43a06933ba1ca5c7d Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Mon, 11 Apr 2016 17:45:15 +0200 Subject: [PATCH 179/513] bridge: mdb: add support to filter by vlan id Add the optional keyword "vid" to bridge mdb show so the user can request filtering by a specific vlan id. Currently the filtering is implemented only in user-space. The argument name has been chosen to match the add/del one - "vid". Example: $ bridge mdb show vid 200 dev br0 port eth2 grp 239.0.0.1 permanent vid 200 Signed-off-by: Nikolay Aleksandrov --- bridge/mdb.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bridge/mdb.c b/bridge/mdb.c index 842536ec0..6c904f8e6 100644 --- a/bridge/mdb.c +++ b/bridge/mdb.c @@ -24,12 +24,12 @@ ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct br_port_msg)))) #endif -static unsigned int filter_index; +static unsigned int filter_index, filter_vlan; static void usage(void) { fprintf(stderr, "Usage: bridge mdb { add | del } dev DEV port PORT grp GROUP [permanent | temp] [vid VID]\n"); - fprintf(stderr, " bridge mdb {show} [ dev DEV ]\n"); + fprintf(stderr, " bridge mdb {show} [ dev DEV ] [ vid VID ]\n"); exit(-1); } @@ -92,6 +92,8 @@ static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e, const void *src; int af; + if (filter_vlan && e->vid != filter_vlan) + return; af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6; src = af == AF_INET ? (const void *)&e->addr.u.ip4 : (const void *)&e->addr.u.ip6; @@ -195,6 +197,11 @@ static int mdb_show(int argc, char **argv) if (filter_dev) duparg("dev", *argv); filter_dev = *argv; + } else if (strcmp(*argv, "vid") == 0) { + NEXT_ARG(); + if (filter_vlan) + duparg("vid", *argv); + filter_vlan = atoi(*argv); } argc--; argv++; } From 5a2d0201cce161617b30102d10b709fa24c6e833 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Mon, 11 Apr 2016 17:45:16 +0200 Subject: [PATCH 180/513] bridge: vlan: add support to filter by vlan id Add the optional keyword "vid" to bridge vlan show so the user can request filtering by a specific vlan id. Currently the filtering is implemented only in user-space. The argument name has been chosen to match the add/del one - "vid". This filtering can be used also with the "-compressvlans" option to see in which range is a vlan (if in any). Also this will be used to show only specific per-vlan statistics later when support is added to the kernel for it. Examples: $ bridge vlan show vid 450 port vlan ids eth2 450 $ bridge -c vlan show vid 450 port vlan ids eth2 400-500 $ bridge vlan show vid 1 port vlan ids eth1 1 PVID Egress Untagged eth2 1 PVID br0 1 PVID Egress Untagged Signed-off-by: Nikolay Aleksandrov --- bridge/vlan.c | 60 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/bridge/vlan.c b/bridge/vlan.c index ae588323d..717025ae6 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -13,13 +13,13 @@ #include "br_common.h" #include "utils.h" -static unsigned int filter_index; +static unsigned int filter_index, filter_vlan; static void usage(void) { fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid] [ untagged ]\n"); fprintf(stderr, " [ self ] [ master ]\n"); - fprintf(stderr, " bridge vlan { show } [ dev DEV ]\n"); + fprintf(stderr, " bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n"); exit(-1); } @@ -138,6 +138,26 @@ static int vlan_modify(int cmd, int argc, char **argv) return 0; } +/* In order to use this function for both filtering and non-filtering cases + * we need to make it a tristate: + * return -1 - if filtering we've gone over so don't continue + * return 0 - skip entry and continue (applies to range start or to entries + * which are less than filter_vlan) + * return 1 - print the entry and continue + */ +static int filter_vlan_check(struct bridge_vlan_info *vinfo) +{ + /* if we're filtering we should stop on the first greater entry */ + if (filter_vlan && vinfo->vid > filter_vlan && + !(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)) + return -1; + if ((vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) || + vinfo->vid < filter_vlan) + return 0; + + return 1; +} + static int print_vlan(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) @@ -169,26 +189,40 @@ static int print_vlan(const struct sockaddr_nl *who, /* if AF_SPEC isn't there, vlan table is not preset for this port */ if (!tb[IFLA_AF_SPEC]) { - fprintf(fp, "%s\tNone\n", ll_index_to_name(ifm->ifi_index)); + if (!filter_vlan) + fprintf(fp, "%s\tNone\n", + ll_index_to_name(ifm->ifi_index)); return 0; } else { struct rtattr *i, *list = tb[IFLA_AF_SPEC]; int rem = RTA_PAYLOAD(list); + __u16 last_vid_start = 0; - fprintf(fp, "%s", ll_index_to_name(ifm->ifi_index)); + if (!filter_vlan) + fprintf(fp, "%s", ll_index_to_name(ifm->ifi_index)); for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { struct bridge_vlan_info *vinfo; + int vcheck_ret; if (i->rta_type != IFLA_BRIDGE_VLAN_INFO) continue; vinfo = RTA_DATA(i); - if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) - fprintf(fp, "-%hu", vinfo->vid); - else - fprintf(fp, "\t %hu", vinfo->vid); - if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) + + if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)) + last_vid_start = vinfo->vid; + vcheck_ret = filter_vlan_check(vinfo); + if (vcheck_ret == -1) + break; + else if (vcheck_ret == 0) continue; + + if (filter_vlan) + fprintf(fp, "%s", + ll_index_to_name(ifm->ifi_index)); + fprintf(fp, "\t %hu", last_vid_start); + if (last_vid_start != vinfo->vid) + fprintf(fp, "-%hu", vinfo->vid); if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) fprintf(fp, " PVID"); if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) @@ -196,7 +230,8 @@ static int print_vlan(const struct sockaddr_nl *who, fprintf(fp, "\n"); } } - fprintf(fp, "\n"); + if (!filter_vlan) + fprintf(fp, "\n"); fflush(fp); return 0; } @@ -211,6 +246,11 @@ static int vlan_show(int argc, char **argv) if (filter_dev) duparg("dev", *argv); filter_dev = *argv; + } else if (strcmp(*argv, "vid") == 0) { + NEXT_ARG(); + if (filter_vlan) + duparg("vid", *argv); + filter_vlan = atoi(*argv); } argc--; argv++; } From 0395711c52260c3a1cb0984948c3db56c69a073b Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 9 Apr 2016 00:32:03 +0200 Subject: [PATCH 181/513] tc, bpf: add new csum and tunnel signatures Add new signatures for BPF_FUNC_csum_diff, BPF_FUNC_skb_get_tunnel_opt and BPF_FUNC_skb_set_tunnel_opt. Signed-off-by: Daniel Borkmann --- include/bpf_api.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/bpf_api.h b/include/bpf_api.h index 4b16d25c3..0f278f0c2 100644 --- a/include/bpf_api.h +++ b/include/bpf_api.h @@ -212,6 +212,8 @@ static int BPF_FUNC(l3_csum_replace, struct __sk_buff *skb, uint32_t off, uint32_t from, uint32_t to, uint32_t flags); static int BPF_FUNC(l4_csum_replace, struct __sk_buff *skb, uint32_t off, uint32_t from, uint32_t to, uint32_t flags); +static int BPF_FUNC(csum_diff, const void *from, uint32_t from_size, + const void *to, uint32_t to_size, uint32_t seed); /* Packet vlan encap/decap */ static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto, @@ -225,6 +227,11 @@ static int BPF_FUNC(skb_set_tunnel_key, struct __sk_buff *skb, const struct bpf_tunnel_key *from, uint32_t size, uint32_t flags); +static int BPF_FUNC(skb_get_tunnel_opt, struct __sk_buff *skb, + void *to, uint32_t size); +static int BPF_FUNC(skb_set_tunnel_opt, struct __sk_buff *skb, + const void *from, uint32_t size); + /** LLVM built-ins, mem*() routines work for constant size */ #ifndef lock_xadd From afc1a2000b6f991587c815076941385c259e21ed Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 9 Apr 2016 00:32:04 +0200 Subject: [PATCH 182/513] tc, bpf: further improve error reporting Make it easier to spot issues when loading the object file fails. This includes reporting in what pinned object specs differ, better indication when we've reached instruction limits. Don't retry to load a non relo program once we failed with bpf(2), and report out of bounds tail call key. Also, add truncation of huge log outputs by default. Sometimes errors are quite easy to spot by only looking at the tail of the verifier log, but logs can get huge in size e.g. up to few MB (due to verifier checking all possible program paths). Thus, by default limit output to the last 4096 bytes and indicate that it's truncated. For the full log, the verbose option can be used. Signed-off-by: Daniel Borkmann --- tc/tc_bpf.c | 82 ++++++++++++++++++++++++++++++++++++++++++----------- tc/tc_bpf.h | 4 +++ 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index d94af828f..0c59427e8 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -184,7 +184,7 @@ static int bpf_ops_parse(int argc, char **argv, struct sock_filter *bpf_ops, } if (i != bpf_len) { - fprintf(stderr, "Parsed program length is less than encodedlength parameter!\n"); + fprintf(stderr, "Parsed program length is less than encoded length parameter!\n"); ret = -EINVAL; goto out; } @@ -214,6 +214,27 @@ void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len) ops[i].jf, ops[i].k); } +static void bpf_map_pin_report(const struct bpf_elf_map *pin, + const struct bpf_elf_map *obj) +{ + fprintf(stderr, "Map specification differs from pinned file!\n"); + + if (obj->type != pin->type) + fprintf(stderr, " - Type: %u (obj) != %u (pin)\n", + obj->type, pin->type); + if (obj->size_key != pin->size_key) + fprintf(stderr, " - Size key: %u (obj) != %u (pin)\n", + obj->size_key, pin->size_key); + if (obj->size_value != pin->size_value) + fprintf(stderr, " - Size value: %u (obj) != %u (pin)\n", + obj->size_value, pin->size_value); + if (obj->max_elem != pin->max_elem) + fprintf(stderr, " - Max elems: %u (obj) != %u (pin)\n", + obj->max_elem, pin->max_elem); + + fprintf(stderr, "\n"); +} + static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, int length) { @@ -256,7 +277,7 @@ static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, if (!memcmp(&tmp, &zero, length)) return 0; - fprintf(stderr, "Map specs from pinned file differ!\n"); + bpf_map_pin_report(&tmp, map); return -EINVAL; } } @@ -735,7 +756,19 @@ bpf_dump_error(struct bpf_elf_ctx *ctx, const char *format, ...) va_end(vl); if (ctx->log && ctx->log[0]) { - fprintf(stderr, "%s\n", ctx->log); + if (ctx->verbose) { + fprintf(stderr, "%s\n", ctx->log); + } else { + unsigned int off = 0, len = strlen(ctx->log); + + if (len > BPF_MAX_LOG) { + off = len - BPF_MAX_LOG; + fprintf(stderr, "Skipped %u bytes, use \'verb\' option for the full verbose log.\n[...]\n", + off); + } + fprintf(stderr, "%s\n", ctx->log + off); + } + memset(ctx->log, 0, ctx->log_size); } } @@ -1055,14 +1088,16 @@ static void bpf_prog_report(int fd, const char *section, const struct bpf_elf_prog *prog, struct bpf_elf_ctx *ctx) { - fprintf(stderr, "Prog section \'%s\' %s%s (%d)!\n", section, + unsigned int insns = prog->size / sizeof(struct bpf_insn); + + fprintf(stderr, "\nProg section \'%s\' %s%s (%d)!\n", section, fd < 0 ? "rejected: " : "loaded", fd < 0 ? strerror(errno) : "", fd < 0 ? errno : fd); fprintf(stderr, " - Type: %u\n", prog->type); - fprintf(stderr, " - Instructions: %zu\n", - prog->size / sizeof(struct bpf_insn)); + fprintf(stderr, " - Instructions: %u (%u over limit)\n", + insns, insns > BPF_MAXINSNS ? insns - BPF_MAXINSNS : 0); fprintf(stderr, " - License: %s\n\n", prog->license); bpf_dump_error(ctx, "Verifier analysis:\n\n"); @@ -1283,6 +1318,11 @@ static int bpf_fetch_strtab(struct bpf_elf_ctx *ctx, int section, return 0; } +static bool bpf_has_map_data(const struct bpf_elf_ctx *ctx) +{ + return ctx->sym_tab && ctx->str_tab && ctx->sec_maps; +} + static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx) { struct bpf_elf_sec_data data; @@ -1306,13 +1346,13 @@ static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx) !strcmp(data.sec_name, ".strtab")) ret = bpf_fetch_strtab(ctx, i, &data); if (ret < 0) { - fprintf(stderr, "Error parsing section %d! Perhapscheck with readelf -a?\n", + fprintf(stderr, "Error parsing section %d! Perhaps check with readelf -a?\n", i); break; } } - if (ctx->sym_tab && ctx->str_tab && ctx->sec_maps) { + if (bpf_has_map_data(ctx)) { ret = bpf_maps_attach_all(ctx); if (ret < 0) { fprintf(stderr, "Error loading maps into kernel!\n"); @@ -1348,7 +1388,7 @@ static int bpf_fetch_prog(struct bpf_elf_ctx *ctx, const char *section) fd = bpf_prog_attach(section, &prog, ctx); if (fd < 0) - continue; + break; ctx->sec_done[i] = true; break; @@ -1412,7 +1452,8 @@ static int bpf_apply_relo_data(struct bpf_elf_ctx *ctx, return 0; } -static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section) +static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section, + bool *lderr) { struct bpf_elf_sec_data data_relo, data_insn; struct bpf_elf_prog prog; @@ -1442,8 +1483,10 @@ static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section) prog.license = ctx->license; fd = bpf_prog_attach(section, &prog, ctx); - if (fd < 0) - continue; + if (fd < 0) { + *lderr = true; + break; + } ctx->sec_done[i] = true; ctx->sec_done[idx] = true; @@ -1455,11 +1498,12 @@ static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section) static int bpf_fetch_prog_sec(struct bpf_elf_ctx *ctx, const char *section) { + bool lderr = false; int ret = -1; - if (ctx->sym_tab) - ret = bpf_fetch_prog_relo(ctx, section); - if (ret < 0) + if (bpf_has_map_data(ctx)) + ret = bpf_fetch_prog_relo(ctx, section, &lderr); + if (ret < 0 && !lderr) ret = bpf_fetch_prog(ctx, section); return ret; @@ -1504,8 +1548,12 @@ static int bpf_fill_prog_arrays(struct bpf_elf_ctx *ctx) ret = bpf_map_update(ctx->map_fds[idx], &key_id, &fd, BPF_ANY); - if (ret < 0) - return -ENOENT; + if (ret < 0) { + if (errno == E2BIG) + fprintf(stderr, "Tail call key %u for map %u out of bounds?\n", + key_id, map_id); + return -errno; + } ctx->sec_done[i] = true; } diff --git a/tc/tc_bpf.h b/tc/tc_bpf.h index 93f7f0e24..30306deab 100644 --- a/tc/tc_bpf.h +++ b/tc/tc_bpf.h @@ -33,6 +33,10 @@ enum { #define BPF_ENV_UDS "TC_BPF_UDS" #define BPF_ENV_MNT "TC_BPF_MNT" +#ifndef BPF_MAX_LOG +# define BPF_MAX_LOG 4096 +#endif + #ifndef BPF_FS_MAGIC # define BPF_FS_MAGIC 0xcafe4a11 #endif From 4dd3f50af4b82a6a29ede951bde97197e88f9c5d Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 9 Apr 2016 00:32:05 +0200 Subject: [PATCH 183/513] tc, bpf: add support for map pre/allocation Follow-up to kernel commit 6c9059817432 ("bpf: pre-allocate hash map elements"). Add flags support, so that we can pass in BPF_F_NO_PREALLOC flag for disallowing preallocation. Update examples accordingly and also remove the BPF_* map helper macros from them as they were not very useful. Signed-off-by: Daniel Borkmann --- examples/bpf/bpf_cyclic.c | 9 +++++++- examples/bpf/bpf_graft.c | 8 ++++++- examples/bpf/bpf_prog.c | 2 ++ examples/bpf/bpf_shared.c | 8 ++++++- examples/bpf/bpf_tailcall.c | 29 ++++++++++++++++++++---- include/bpf_api.h | 45 ------------------------------------- include/bpf_elf.h | 1 + tc/tc_bpf.c | 16 +++++++++---- 8 files changed, 62 insertions(+), 56 deletions(-) diff --git a/examples/bpf/bpf_cyclic.c b/examples/bpf/bpf_cyclic.c index 36745a3c8..11d1c061d 100644 --- a/examples/bpf/bpf_cyclic.c +++ b/examples/bpf/bpf_cyclic.c @@ -6,7 +6,14 @@ */ #define JMP_MAP_ID 0xabccba -BPF_PROG_ARRAY(jmp_tc, JMP_MAP_ID, PIN_OBJECT_NS, 1); +struct bpf_elf_map __section_maps jmp_tc = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .id = JMP_MAP_ID, + .size_key = sizeof(uint32_t), + .size_value = sizeof(uint32_t), + .pinning = PIN_OBJECT_NS, + .max_elem = 1, +}; __section_tail(JMP_MAP_ID, 0) int cls_loop(struct __sk_buff *skb) diff --git a/examples/bpf/bpf_graft.c b/examples/bpf/bpf_graft.c index 20784ff4a..07113d4a0 100644 --- a/examples/bpf/bpf_graft.c +++ b/examples/bpf/bpf_graft.c @@ -33,7 +33,13 @@ * [...] */ -BPF_PROG_ARRAY(jmp_tc, 0, PIN_GLOBAL_NS, 1); +struct bpf_elf_map __section_maps jmp_tc = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .size_key = sizeof(uint32_t), + .size_value = sizeof(uint32_t), + .pinning = PIN_GLOBAL_NS, + .max_elem = 1, +}; __section("aaa") int cls_aaa(struct __sk_buff *skb) diff --git a/examples/bpf/bpf_prog.c b/examples/bpf/bpf_prog.c index f15e876c2..d6caf374b 100644 --- a/examples/bpf/bpf_prog.c +++ b/examples/bpf/bpf_prog.c @@ -192,6 +192,7 @@ struct bpf_elf_map __section("maps") map_proto = { .size_key = sizeof(uint8_t), .size_value = sizeof(struct count_tuple), .max_elem = 256, + .flags = BPF_F_NO_PREALLOC, }; struct bpf_elf_map __section("maps") map_queue = { @@ -200,6 +201,7 @@ struct bpf_elf_map __section("maps") map_queue = { .size_key = sizeof(uint32_t), .size_value = sizeof(struct count_queue), .max_elem = 1024, + .flags = BPF_F_NO_PREALLOC, }; struct bpf_elf_map __section("maps") map_drops = { diff --git a/examples/bpf/bpf_shared.c b/examples/bpf/bpf_shared.c index 7fe9ef30f..21fe6f1e0 100644 --- a/examples/bpf/bpf_shared.c +++ b/examples/bpf/bpf_shared.c @@ -18,7 +18,13 @@ * instance is being created. */ -BPF_ARRAY4(map_sh, 0, PIN_OBJECT_NS, 1); /* or PIN_GLOBAL_NS, or PIN_NONE */ +struct bpf_elf_map __section_maps map_sh = { + .type = BPF_MAP_TYPE_ARRAY, + .size_key = sizeof(uint32_t), + .size_value = sizeof(uint32_t), + .pinning = PIN_OBJECT_NS, /* or PIN_GLOBAL_NS, or PIN_NONE */ + .max_elem = 1, +}; __section("egress") int emain(struct __sk_buff *skb) diff --git a/examples/bpf/bpf_tailcall.c b/examples/bpf/bpf_tailcall.c index f545430f7..1a30426c3 100644 --- a/examples/bpf/bpf_tailcall.c +++ b/examples/bpf/bpf_tailcall.c @@ -26,10 +26,31 @@ * classifier behaviour. */ -BPF_PROG_ARRAY(jmp_tc, FOO, PIN_OBJECT_NS, MAX_JMP_SIZE); -BPF_PROG_ARRAY(jmp_ex, BAR, PIN_OBJECT_NS, 1); - -BPF_ARRAY4(map_sh, 0, PIN_OBJECT_NS, 1); +struct bpf_elf_map __section_maps jmp_tc = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .id = FOO, + .size_key = sizeof(uint32_t), + .size_value = sizeof(uint32_t), + .pinning = PIN_OBJECT_NS, + .max_elem = MAX_JMP_SIZE, +}; + +struct bpf_elf_map __section_maps jmp_ex = { + .type = BPF_MAP_TYPE_PROG_ARRAY, + .id = BAR, + .size_key = sizeof(uint32_t), + .size_value = sizeof(uint32_t), + .pinning = PIN_OBJECT_NS, + .max_elem = 1, +}; + +struct bpf_elf_map __section_maps map_sh = { + .type = BPF_MAP_TYPE_ARRAY, + .size_key = sizeof(uint32_t), + .size_value = sizeof(uint32_t), + .pinning = PIN_OBJECT_NS, + .max_elem = 1, +}; __section_tail(FOO, ENTRY_0) int cls_case1(struct __sk_buff *skb) diff --git a/include/bpf_api.h b/include/bpf_api.h index 0f278f0c2..1b250d2e9 100644 --- a/include/bpf_api.h +++ b/include/bpf_api.h @@ -99,51 +99,6 @@ char ____license[] __section_license = NAME #endif -#ifndef __BPF_MAP -# define __BPF_MAP(NAME, TYPE, ID, SIZE_KEY, SIZE_VALUE, PIN, MAX_ELEM) \ - struct bpf_elf_map __section_maps NAME = { \ - .type = (TYPE), \ - .id = (ID), \ - .size_key = (SIZE_KEY), \ - .size_value = (SIZE_VALUE), \ - .pinning = (PIN), \ - .max_elem = (MAX_ELEM), \ - } -#endif - -#ifndef BPF_HASH -# define BPF_HASH(NAME, ID, SIZE_KEY, SIZE_VALUE, PIN, MAX_ELEM) \ - __BPF_MAP(NAME, BPF_MAP_TYPE_HASH, ID, SIZE_KEY, SIZE_VALUE, \ - PIN, MAX_ELEM) -#endif - -#ifndef BPF_ARRAY -# define BPF_ARRAY(NAME, ID, SIZE_VALUE, PIN, MAX_ELEM) \ - __BPF_MAP(NAME, BPF_MAP_TYPE_ARRAY, ID, sizeof(uint32_t), \ - SIZE_VALUE, PIN, MAX_ELEM) -#endif - -#ifndef BPF_ARRAY2 -# define BPF_ARRAY2(NAME, ID, PIN, MAX_ELEM) \ - BPF_ARRAY(NAME, ID, sizeof(uint16_t), PIN, MAX_ELEM) -#endif - -#ifndef BPF_ARRAY4 -# define BPF_ARRAY4(NAME, ID, PIN, MAX_ELEM) \ - BPF_ARRAY(NAME, ID, sizeof(uint32_t), PIN, MAX_ELEM) -#endif - -#ifndef BPF_ARRAY8 -# define BPF_ARRAY8(NAME, ID, PIN, MAX_ELEM) \ - BPF_ARRAY(NAME, ID, sizeof(uint64_t), PIN, MAX_ELEM) -#endif - -#ifndef BPF_PROG_ARRAY -# define BPF_PROG_ARRAY(NAME, ID, PIN, MAX_ELEM) \ - __BPF_MAP(NAME, BPF_MAP_TYPE_PROG_ARRAY, ID, sizeof(uint32_t), \ - sizeof(uint32_t), PIN, MAX_ELEM) -#endif - /** Classifier helper */ #ifndef BPF_H_DEFAULT diff --git a/include/bpf_elf.h b/include/bpf_elf.h index 31a897437..36cc98828 100644 --- a/include/bpf_elf.h +++ b/include/bpf_elf.h @@ -32,6 +32,7 @@ struct bpf_elf_map { __u32 size_key; __u32 size_value; __u32 max_elem; + __u32 flags; __u32 id; __u32 pinning; }; diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index 0c59427e8..fe927ac90 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -231,6 +231,9 @@ static void bpf_map_pin_report(const struct bpf_elf_map *pin, if (obj->max_elem != pin->max_elem) fprintf(stderr, " - Max elems: %u (obj) != %u (pin)\n", obj->max_elem, pin->max_elem); + if (obj->flags != pin->flags) + fprintf(stderr, " - Flags: %#x (obj) != %#x (pin)\n", + obj->flags, pin->flags); fprintf(stderr, "\n"); } @@ -261,6 +264,8 @@ static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, tmp.size_value = val; else if (sscanf(buff, "max_entries:\t%u", &val) == 1) tmp.max_elem = val; + else if (sscanf(buff, "map_flags:\t%i", &val) == 1) + tmp.flags = val; } fclose(fp); @@ -796,8 +801,9 @@ static int bpf_log_realloc(struct bpf_elf_ctx *ctx) return 0; } -static int bpf_map_create(enum bpf_map_type type, unsigned int size_key, - unsigned int size_value, unsigned int max_elem) +static int bpf_map_create(enum bpf_map_type type, uint32_t size_key, + uint32_t size_value, uint32_t max_elem, + uint32_t flags) { union bpf_attr attr; @@ -806,6 +812,7 @@ static int bpf_map_create(enum bpf_map_type type, unsigned int size_key, attr.key_size = size_key; attr.value_size = size_value; attr.max_entries = max_elem; + attr.map_flags = flags; return bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); } @@ -1147,7 +1154,8 @@ static void bpf_map_report(int fd, const char *name, fprintf(stderr, " - Pinning: %u\n", map->pinning); fprintf(stderr, " - Size key: %u\n", map->size_key); fprintf(stderr, " - Size value: %u\n", map->size_value); - fprintf(stderr, " - Max elems: %u\n\n", map->max_elem); + fprintf(stderr, " - Max elems: %u\n", map->max_elem); + fprintf(stderr, " - Flags: %#x\n\n", map->flags); } static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, @@ -1174,7 +1182,7 @@ static int bpf_map_attach(const char *name, const struct bpf_elf_map *map, errno = 0; fd = bpf_map_create(map->type, map->size_key, map->size_value, - map->max_elem); + map->max_elem, map->flags); if (fd < 0 || ctx->verbose) { bpf_map_report(fd, name, map, ctx); if (fd < 0) From df590401d6297fd4df69f2d514ec055d59e887cc Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Fri, 1 Apr 2016 16:22:01 +0200 Subject: [PATCH 184/513] iplink: display IFLA_PHYS_PORT_NAME Signed-off-by: Nicolas Dichtel --- ip/ipaddress.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index f7bd1c76b..ca97907fe 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -813,6 +813,10 @@ int print_linkinfo(const struct sockaddr_nl *who, fprintf(fp, "master %s ", ll_idx_n2a(*(int *)RTA_DATA(tb[IFLA_MASTER]), b1)); } + if (tb[IFLA_PHYS_PORT_NAME]) + fprintf(fp, "portname %s ", + rta_getattr_str(tb[IFLA_PHYS_PORT_NAME])); + if (tb[IFLA_PHYS_PORT_ID]) { SPRINT_BUF(b1); fprintf(fp, "portid %s ", From 11522e7d02758653145f68bda7a6d123bdd0654b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 11 Apr 2016 22:07:51 +0000 Subject: [PATCH 185/513] ip: only display phys attributes with details option Since output of ip commands are already cluttered, move the physical port details under a show_details option. --- ip/ipaddress.c | 85 ++++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index ca97907fe..f27d423ca 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -782,7 +782,7 @@ int print_linkinfo(const struct sockaddr_nl *who, fprintf(fp, "%d: ", ifi->ifi_index); color_fprintf(fp, COLOR_IFNAME, "%s", - tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : ""); + tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : ""); if (tb[IFLA_LINK]) { SPRINT_BUF(b1); @@ -813,26 +813,6 @@ int print_linkinfo(const struct sockaddr_nl *who, fprintf(fp, "master %s ", ll_idx_n2a(*(int *)RTA_DATA(tb[IFLA_MASTER]), b1)); } - if (tb[IFLA_PHYS_PORT_NAME]) - fprintf(fp, "portname %s ", - rta_getattr_str(tb[IFLA_PHYS_PORT_NAME])); - - if (tb[IFLA_PHYS_PORT_ID]) { - SPRINT_BUF(b1); - fprintf(fp, "portid %s ", - hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_PORT_ID]), - RTA_PAYLOAD(tb[IFLA_PHYS_PORT_ID]), - b1, sizeof(b1))); - } - - if (tb[IFLA_PHYS_SWITCH_ID]) { - SPRINT_BUF(b1); - fprintf(fp, "switchid %s ", - hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_SWITCH_ID]), - RTA_PAYLOAD(tb[IFLA_PHYS_SWITCH_ID]), - b1, sizeof(b1))); - } - if (tb[IFLA_OPERSTATE]) print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE])); @@ -856,10 +836,10 @@ int print_linkinfo(const struct sockaddr_nl *who, if (tb[IFLA_ADDRESS]) { color_fprintf(fp, COLOR_MAC, "%s", - ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]), - RTA_PAYLOAD(tb[IFLA_ADDRESS]), - ifi->ifi_type, - b1, sizeof(b1))); + ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]), + RTA_PAYLOAD(tb[IFLA_ADDRESS]), + ifi->ifi_type, + b1, sizeof(b1))); } if (tb[IFLA_BROADCAST]) { if (ifi->ifi_flags&IFF_POINTOPOINT) @@ -867,10 +847,10 @@ int print_linkinfo(const struct sockaddr_nl *who, else fprintf(fp, " brd "); color_fprintf(fp, COLOR_MAC, "%s", - ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]), - RTA_PAYLOAD(tb[IFLA_BROADCAST]), - ifi->ifi_type, - b1, sizeof(b1))); + ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]), + RTA_PAYLOAD(tb[IFLA_BROADCAST]), + ifi->ifi_type, + b1, sizeof(b1))); } } @@ -888,21 +868,46 @@ int print_linkinfo(const struct sockaddr_nl *who, fprintf(fp, " protodown on "); } - if (tb[IFLA_PROMISCUITY] && show_details) - fprintf(fp, " promiscuity %u ", - *(int *)RTA_DATA(tb[IFLA_PROMISCUITY])); + if (show_details) { + if (tb[IFLA_PROMISCUITY]) + fprintf(fp, " promiscuity %u ", + *(int *)RTA_DATA(tb[IFLA_PROMISCUITY])); + + if (tb[IFLA_LINKINFO]) + print_linktype(fp, tb[IFLA_LINKINFO]); + + if (do_link && tb[IFLA_AF_SPEC]) + print_af_spec(fp, tb[IFLA_AF_SPEC]); + + if (tb[IFLA_NUM_TX_QUEUES]) + fprintf(fp, "numtxqueues %u ", + rta_getattr_u32(tb[IFLA_NUM_TX_QUEUES])); - if (tb[IFLA_LINKINFO] && show_details) - print_linktype(fp, tb[IFLA_LINKINFO]); + if (tb[IFLA_NUM_RX_QUEUES]) + fprintf(fp, "numrxqueues %u ", + rta_getattr_u32(tb[IFLA_NUM_RX_QUEUES])); - if (do_link && tb[IFLA_AF_SPEC] && show_details) - print_af_spec(fp, tb[IFLA_AF_SPEC]); + if (tb[IFLA_PHYS_PORT_NAME]) + fprintf(fp, "portname %s ", + rta_getattr_str(tb[IFLA_PHYS_PORT_NAME])); - if (tb[IFLA_NUM_TX_QUEUES] && show_details) - fprintf(fp, "numtxqueues %u ", rta_getattr_u32(tb[IFLA_NUM_TX_QUEUES])); + if (tb[IFLA_PHYS_PORT_ID]) { + SPRINT_BUF(b1); + fprintf(fp, "portid %s ", + hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_PORT_ID]), + RTA_PAYLOAD(tb[IFLA_PHYS_PORT_ID]), + b1, sizeof(b1))); + } + + if (tb[IFLA_PHYS_SWITCH_ID]) { + SPRINT_BUF(b1); + fprintf(fp, "switchid %s ", + hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_SWITCH_ID]), + RTA_PAYLOAD(tb[IFLA_PHYS_SWITCH_ID]), + b1, sizeof(b1))); + } + } - if (tb[IFLA_NUM_RX_QUEUES] && show_details) - fprintf(fp, "numrxqueues %u ", rta_getattr_u32(tb[IFLA_NUM_RX_QUEUES])); if ((do_link || show_details) && tb[IFLA_IFALIAS]) { fprintf(fp, "%s alias %s", _SL_, From 5c5a0f3df9261340725a65f4655a2ab50fd3db4e Mon Sep 17 00:00:00 2001 From: Gustavo Zacarias Date: Fri, 8 Apr 2016 09:59:33 -0300 Subject: [PATCH 186/513] iproute2: tc_bpf.c: fix building with musl libc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need limits.h for PATH_MAX, fixes: tc_bpf.c: In function ‘bpf_map_selfcheck_pinned’: tc_bpf.c:222:12: error: ‘PATH_MAX’ undeclared (first use in this function) char file[PATH_MAX], buff[4096]; Signed-off-by: Gustavo Zacarias Acked-by: Daniel Borkmann --- tc/tc_bpf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index fe927ac90..86c6069b6 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef HAVE_ELF #include From fe9322781e6351b5572cbaa8df4dd0e5ec96398a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 31 Mar 2016 14:43:32 +0200 Subject: [PATCH 187/513] ip-link: Support printing VF trust setting This adds a new item to VF lines of a PF, stating whether the VF is trusted or not. Signed-off-by: Phil Sutter --- ip/ipaddress.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index f27d423ca..b2e294d29 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -380,6 +380,13 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) else fprintf(fp, ", link-state disable"); } + if (vf[IFLA_VF_TRUST]) { + struct ifla_vf_trust *vf_trust = RTA_DATA(vf[IFLA_VF_TRUST]); + + if (vf_trust->setting != -1) + fprintf(fp, ", trust %s", + vf_trust->setting ? "on" : "off"); + } if (vf[IFLA_VF_STATS] && show_stats) print_vf_stats64(fp, vf[IFLA_VF_STATS]); } From bbac6c63011b6c89d79f3f6aae7d4d38962e4000 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 11 Apr 2016 22:13:55 +0000 Subject: [PATCH 188/513] ip: whitespace cleanup Fix whitespace --- ip/ipaddress.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index b2e294d29..aac7970e1 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -326,7 +326,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) * this kernel. */ tmp = (struct rtattr *)((char *)vf[IFLA_VF_TX_RATE] + - vf[IFLA_VF_TX_RATE]->rta_len); + vf[IFLA_VF_TX_RATE]->rta_len); if (tmp->rta_type != IFLA_VF_SPOOFCHK) vf_spoofchk = NULL; @@ -338,7 +338,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) * this kernel. */ tmp = (struct rtattr *)((char *)vf[IFLA_VF_SPOOFCHK] + - vf[IFLA_VF_SPOOFCHK]->rta_len); + vf[IFLA_VF_SPOOFCHK]->rta_len); if (tmp->rta_type != IFLA_VF_LINK_STATE) vf_linkstate = NULL; @@ -349,7 +349,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) fprintf(fp, "%s vf %d MAC %s", _SL_, vf_mac->vf, ll_addr_n2a((unsigned char *)&vf_mac->mac, - ETH_ALEN, 0, b1, sizeof(b1))); + ETH_ALEN, 0, b1, sizeof(b1))); if (vf_vlan->vlan) fprintf(fp, ", vlan %d", vf_vlan->vlan); if (vf_vlan->qos) From 44df45973a23fc32a3611a8571b18d5fad91d97e Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Thu, 7 Apr 2016 14:36:27 +0200 Subject: [PATCH 189/513] vxlan: 'external' implies 'nolearning' It doesn't make sense to use external control plane and fill internal FDB at the same time. It's even an illegal combination for VXLAN-GPE. Just switch off learning when 'external' is specified. Signed-off-by: Jiri Benc --- ip/iplink_vxlan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index e3bbea003..e9d64b451 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -234,6 +234,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, remcsumrx = 0; } else if (!matches(*argv, "external")) { metadata = 1; + learning = 0; } else if (!matches(*argv, "noexternal")) { metadata = 0; } else if (!matches(*argv, "gbp")) { From 42d17a617fc7c3ebccf6bdb115fa907bb2940eec Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Thu, 7 Apr 2016 14:36:28 +0200 Subject: [PATCH 190/513] ip-link.8: document "external" flag for vxlan Signed-off-by: Jiri Benc --- man/man8/ip-link.8.in | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 805511423..f677f8c55 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -422,6 +422,8 @@ the following additional arguments are supported: ] [ .BI maxaddress " NUMBER " ] [ +.RI "[no]external " +] [ .B gbp ] @@ -515,6 +517,12 @@ are entered into the VXLAN device forwarding database. .BI maxaddress " NUMBER" - specifies the maximum number of FDB entries. +.sp +.I [no]external +- specifies whether an external control plane +.RB "(e.g. " "ip route encap" ) +or the internal FDB should be used. + .sp .B gbp - enables the Group Policy extension (VXLAN-GBP). From 346410bdb49fe104476789260d6a43989a756e8f Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Thu, 7 Apr 2016 14:36:29 +0200 Subject: [PATCH 191/513] vxlan: add support for VXLAN-GPE Adds support to create a VXLAN-GPE interface. Signed-off-by: Jiri Benc --- ip/iplink_vxlan.c | 13 +++++++++++-- man/man8/ip-link.8.in | 9 +++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index e9d64b451..49a40befa 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -31,7 +31,7 @@ static void print_explain(FILE *f) fprintf(f, " [ ageing SECONDS ] [ maxaddress NUMBER ]\n"); fprintf(f, " [ [no]udpcsum ] [ [no]udp6zerocsumtx ] [ [no]udp6zerocsumrx ]\n"); fprintf(f, " [ [no]remcsumtx ] [ [no]remcsumrx ]\n"); - fprintf(f, " [ [no]external ] [ gbp ]\n"); + fprintf(f, " [ [no]external ] [ gbp ] [ gpe ]\n"); fprintf(f, "\n"); fprintf(f, "Where: VNI := 0-16777215\n"); fprintf(f, " ADDR := { IP_ADDRESS | any }\n"); @@ -79,6 +79,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, __u8 remcsumrx = 0; __u8 metadata = 0; __u8 gbp = 0; + __u8 gpe = 0; int dst_port_set = 0; struct ifla_vxlan_port_range range = { 0, 0 }; @@ -239,6 +240,8 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, metadata = 0; } else if (!matches(*argv, "gbp")) { gbp = 1; + } else if (!matches(*argv, "gpe")) { + gpe = 1; } else if (matches(*argv, "help") == 0) { explain(); return -1; @@ -267,7 +270,9 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, return -1; } - if (!dst_port_set) { + if (!dst_port_set && gpe) { + dstport = 4790; + } else if (!dst_port_set) { fprintf(stderr, "vxlan: destination port not specified\n" "Will use Linux kernel default (non-standard value)\n"); fprintf(stderr, @@ -324,6 +329,8 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, if (gbp) addattr_l(n, 1024, IFLA_VXLAN_GBP, NULL, 0); + if (gpe) + addattr_l(n, 1024, IFLA_VXLAN_GPE, NULL, 0); return 0; @@ -490,6 +497,8 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_VXLAN_GBP]) fputs("gbp ", f); + if (tb[IFLA_VXLAN_GPE]) + fputs("gpe ", f); } static void vxlan_print_help(struct link_util *lu, int argc, char **argv, diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index f677f8c55..984fb2eb0 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -425,6 +425,8 @@ the following additional arguments are supported: .RI "[no]external " ] [ .B gbp +] [ +.B gpe ] .in +8 @@ -566,6 +568,13 @@ Example: .in -4 +.sp +.B gpe +- enables the Generic Protocol extension (VXLAN-GPE). Currently, this is +only supported together with the +.B external +keyword. + .in -8 .TP From 1c346dccf8a16e32f855427dcb2bb7f29cbf06f1 Mon Sep 17 00:00:00 2001 From: Jeff Harris Date: Thu, 14 Apr 2016 14:15:03 -0400 Subject: [PATCH 192/513] ip: neigh: Fix leftover attributes message during flush Use the same rtnl_dump_request_n call as the show. The rtnl_wilddump_request assumes the type uses an ifinfomsg which is not the case for the neighbor table. Signed-off-by: Jeff Harris Acked-by: David Ahern --- ip/ipneigh.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ip/ipneigh.c b/ip/ipneigh.c index c49fb4e7f..4ddb747e2 100644 --- a/ip/ipneigh.c +++ b/ip/ipneigh.c @@ -430,6 +430,8 @@ static int do_show_or_flush(int argc, char **argv, int flush) addattr32(&req.n, sizeof(req), NDA_IFINDEX, filter.index); } + req.ndm.ndm_family = filter.family; + if (flush) { int round = 0; char flushb[4096-512]; @@ -440,7 +442,7 @@ static int do_show_or_flush(int argc, char **argv, int flush) filter.state &= ~NUD_FAILED; while (round < MAX_ROUNDS) { - if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNEIGH) < 0) { + if (rtnl_dump_request_n(&rth, &req.n) < 0) { perror("Cannot send dump request"); exit(1); } @@ -472,8 +474,6 @@ static int do_show_or_flush(int argc, char **argv, int flush) return 1; } - req.ndm.ndm_family = filter.family; - if (rtnl_dump_request_n(&rth, &req.n) < 0) { perror("Cannot send dump request"); exit(1); From 9d320e1e928630d8b2b83d5e4ef4e10a117352bc Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 13 Apr 2016 22:07:04 +0200 Subject: [PATCH 193/513] ss: Drop silly assignment An expression of the form '(a | b) & b' will evaluate to the value of b for any value of a or b. Signed-off-by: Phil Sutter --- misc/ss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/ss.c b/misc/ss.c index 38cf3312a..d6090018c 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -267,7 +267,7 @@ static void filter_default_dbs(struct filter *f) static void filter_states_set(struct filter *f, int states) { if (states) - f->states = (f->states | states) & states; + f->states = states; } static void filter_merge_defaults(struct filter *f) From e56a959e550f424023ebf3ebb8437f214944a245 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 13 Apr 2016 22:07:05 +0200 Subject: [PATCH 194/513] ss: Fix accidental state filter override Passing a filter expression and selecting an address family using the '-f' flag would overwrite the state filter by accident. Therefore calling e.g. 'ss -nl -f inet '(sport = :22)' would not only print listening sockets (as requested by '-l' flag) but connected ones, as well. Fix this by reusing the formerly ineffective call to filter_states_set() to restore the state filter as it was before the call to filter_af_set(). Signed-off-by: Phil Sutter --- misc/ss.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/misc/ss.c b/misc/ss.c index d6090018c..544def3f0 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -1556,9 +1556,10 @@ void *parse_hostcond(char *addr, bool is_port) out: if (fam != AF_UNSPEC) { + int states = f->states; f->families = 0; filter_af_set(f, fam); - filter_states_set(f, 0); + filter_states_set(f, states); } res = malloc(sizeof(*res)); From d9ba887e9d37b2c5ff012f2abd0776cf93208fba Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 13 Apr 2016 15:18:38 -0700 Subject: [PATCH 195/513] ss: take care of unknown min_rtt Kernel sets info->tcpi_min_rtt to ~0U when no RTT sample was ever taken for the session, thus min_rtt is unknown. Signed-off-by: Eric Dumazet --- misc/ss.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/misc/ss.c b/misc/ss.c index 544def3f0..deefc9676 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -2019,7 +2019,8 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, s.segs_out = info->tcpi_segs_out; s.segs_in = info->tcpi_segs_in; s.not_sent = info->tcpi_notsent_bytes; - s.min_rtt = (double) info->tcpi_min_rtt / 1000; + if (info->tcpi_min_rtt && info->tcpi_min_rtt != ~0U) + s.min_rtt = (double) info->tcpi_min_rtt / 1000; tcp_stats_print(&s); free(s.dctcp); } From ec7513faa959811e3a68aed0836d949dd924afca Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 15 Apr 2016 09:51:43 +0200 Subject: [PATCH 196/513] devlink: fix "devlink port" help message "dl" -> "devlink" Signed-off-by: Jiri Pirko --- devlink/devlink.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index c2da85074..39f423aa3 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -578,9 +578,9 @@ static int cmd_dev(struct dl *dl) static void cmd_port_help(void) { pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n"); - pr_out(" dl port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n"); - pr_out(" dl port split DEV/PORT_INDEX count COUNT\n"); - pr_out(" dl port unsplit DEV/PORT_INDEX\n"); + pr_out(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n"); + pr_out(" devlink port split DEV/PORT_INDEX count COUNT\n"); + pr_out(" devlink port unsplit DEV/PORT_INDEX\n"); } static const char *port_type_name(uint32_t type) From f1239ca1f96c76fbc0742ca0d0c7e87b9b15d437 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 15 Apr 2016 09:51:44 +0200 Subject: [PATCH 197/513] list: add list_for_each_entry_reverse macro Signed-off-by: Jiri Pirko --- include/list.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/list.h b/include/list.h index cdebe4de3..b549c3ec8 100644 --- a/include/list.h +++ b/include/list.h @@ -50,9 +50,15 @@ static inline void list_del(struct list_head *entry) #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + #define list_next_entry(pos, member) \ list_entry((pos)->member.next, typeof(*(pos)), member) +#define list_prev_entry(pos, member) \ + list_entry((pos)->member.prev, typeof(*(pos)), member) + #define list_for_each_entry(pos, head, member) \ for (pos = list_first_entry(head, typeof(*pos), member); \ &pos->member != (head); \ @@ -64,6 +70,11 @@ static inline void list_del(struct list_head *entry) &pos->member != (head); \ pos = n, n = list_next_entry(n, member)) +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_last_entry(head, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_prev_entry(pos, member)) + struct hlist_head { struct hlist_node *first; }; From ebaf76b55ea509bcfb8845e4c40a9ecd3e8377f5 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 15 Apr 2016 09:51:45 +0200 Subject: [PATCH 198/513] list: add list_add_tail helper Signed-off-by: Jiri Pirko --- include/list.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/list.h b/include/list.h index b549c3ec8..5b529dc6e 100644 --- a/include/list.h +++ b/include/list.h @@ -33,6 +33,11 @@ static inline void list_add(struct list_head *new, struct list_head *head) __list_add(new, head, head->next); } +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + static inline void __list_del(struct list_head *prev, struct list_head *next) { next->prev = prev; From 68cab0ba763f9d80740d171e1882ad4f262ca6e1 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 15 Apr 2016 09:51:46 +0200 Subject: [PATCH 199/513] devlink: introduce pr_out_port_handle helper Signed-off-by: Jiri Pirko --- devlink/devlink.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index 39f423aa3..0904e07fc 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -523,6 +523,12 @@ static void pr_out_handle(struct nlattr **tb) mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME])); } +static void pr_out_port_handle(struct nlattr **tb) +{ + pr_out_handle(tb); + pr_out("/%d", mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); +} + static void pr_out_dev(struct nlattr **tb) { pr_out_handle(tb); @@ -599,8 +605,8 @@ static void pr_out_port(struct nlattr **tb) struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE]; struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE]; - pr_out_handle(tb); - pr_out("/%d:", mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); + pr_out_port_handle(tb); + pr_out(":"); if (pt_attr) { uint16_t port_type = mnl_attr_get_u16(pt_attr); From 43f35be4ebb63bf5dea9cc0570ba8d15458d2457 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 15 Apr 2016 09:51:47 +0200 Subject: [PATCH 200/513] devlink: introduce helper to print out nice names (ifnames) By default, ifnames will be printed out. User can turn that off using "-n" option on the command line. Signed-off-by: Jiri Pirko --- devlink/devlink.c | 90 ++++++++++++++++++++++++++++++++++++----- man/man8/devlink-dev.8 | 1 + man/man8/devlink-port.8 | 1 + man/man8/devlink.8 | 5 +++ 4 files changed, 86 insertions(+), 11 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index 0904e07fc..5e08666d1 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -114,6 +114,7 @@ struct dl { struct list_head ifname_map_list; int argc; char **argv; + bool no_nice_names; }; static int dl_argc(struct dl *dl) @@ -290,6 +291,23 @@ static int ifname_map_lookup(struct dl *dl, const char *ifname, return -ENOENT; } +static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name, + const char *dev_name, uint32_t port_index, + char **p_ifname) +{ + struct ifname_map *ifname_map; + + list_for_each_entry(ifname_map, &dl->ifname_map_list, list) { + if (strcmp(bus_name, ifname_map->bus_name) == 0 && + strcmp(dev_name, ifname_map->dev_name) == 0 && + port_index == ifname_map->port_index) { + *p_ifname = ifname_map->ifname; + return 0; + } + } + return -ENOENT; +} + static unsigned int strslashcount(char *str) { unsigned int count = 0; @@ -517,16 +535,62 @@ static void cmd_dev_help(void) pr_out("Usage: devlink dev show [ DEV ]\n"); } +static void __pr_out_handle(const char *bus_name, const char *dev_name) +{ + pr_out("%s/%s", bus_name, dev_name); +} + static void pr_out_handle(struct nlattr **tb) { - pr_out("%s/%s", mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), + __pr_out_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME])); } +static void __pr_out_port_handle(const char *bus_name, const char *dev_name, + uint32_t port_index) +{ + __pr_out_handle(bus_name, dev_name); + pr_out("/%d", port_index); +} + static void pr_out_port_handle(struct nlattr **tb) { - pr_out_handle(tb); - pr_out("/%d", mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); + __pr_out_port_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), + mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]), + mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); +} + +static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name, + const char *dev_name, uint32_t port_index) +{ + char *ifname; + int err; + + if (dl->no_nice_names) + goto no_nice_names; + + err = ifname_map_rev_lookup(dl, bus_name, dev_name, + port_index, &ifname); + if (err) + goto no_nice_names; + pr_out("%s", ifname); + return; + +no_nice_names: + __pr_out_port_handle(bus_name, dev_name, port_index); +} + +static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) +{ + const char *bus_name; + const char *dev_name; + uint32_t port_index; + + bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); + dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); + port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); + + __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index); } static void pr_out_dev(struct nlattr **tb) @@ -867,7 +931,7 @@ static void help(void) { pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" "where OBJECT := { dev | port | monitor }\n" - " OPTIONS := { -V[ersion] }\n"); + " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); } static int dl_cmd(struct dl *dl) @@ -939,6 +1003,7 @@ int main(int argc, char **argv) { static const struct option long_options[] = { { "Version", no_argument, NULL, 'V' }, + { "no-nice-names", no_argument, NULL, 'n' }, { NULL, 0, NULL, 0 } }; struct dl *dl; @@ -946,13 +1011,22 @@ int main(int argc, char **argv) int err; int ret; - while ((opt = getopt_long(argc, argv, "V", + dl = dl_alloc(); + if (!dl) { + pr_err("Failed to allocate memory for devlink\n"); + return EXIT_FAILURE; + } + + while ((opt = getopt_long(argc, argv, "Vn", long_options, NULL)) >= 0) { switch (opt) { case 'V': printf("devlink utility, iproute2-ss%s\n", SNAPSHOT); return EXIT_SUCCESS; + case 'n': + dl->no_nice_names = true; + break; default: pr_err("Unknown option.\n"); help(); @@ -963,12 +1037,6 @@ int main(int argc, char **argv) argc -= optind; argv += optind; - dl = dl_alloc(); - if (!dl) { - pr_err("Failed to allocate memory for devlink\n"); - return EXIT_FAILURE; - } - err = dl_init(dl, argc, argv); if (err) { ret = EXIT_FAILURE; diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8 index 7878d89b3..af96a298a 100644 --- a/man/man8/devlink-dev.8 +++ b/man/man8/devlink-dev.8 @@ -16,6 +16,7 @@ devlink-dev \- devlink device configuration .ti -8 .IR OPTIONS " := { " \fB\-V\fR[\fIersion\fR] | +\fB\-n\fR[\fIno-nice-names\fR] } .ti -8 .B devlink dev show diff --git a/man/man8/devlink-port.8 b/man/man8/devlink-port.8 index e6ae6869b..d78837c77 100644 --- a/man/man8/devlink-port.8 +++ b/man/man8/devlink-port.8 @@ -16,6 +16,7 @@ devlink-port \- devlink port configuration .ti -8 .IR OPTIONS " := { " \fB\-V\fR[\fIersion\fR] | +\fB\-n\fR[\fIno-nice-names\fR] } .ti -8 .BR "devlink port set " diff --git a/man/man8/devlink.8 b/man/man8/devlink.8 index f608ccca2..df00f4fa3 100644 --- a/man/man8/devlink.8 +++ b/man/man8/devlink.8 @@ -19,6 +19,7 @@ devlink \- Devlink tool .ti -8 .IR OPTIONS " := { " \fB\-V\fR[\fIersion\fR] | +\fB\-n\fR[\fIno-nice-names\fR] } .SH OPTIONS @@ -28,6 +29,10 @@ Print the version of the .B devlink utility and exit. +.TP +.BR "\-n" , " -no-nice-names" +Turn off printing out nice names, for example netdevice ifnames instead of devlink port identification. + .SS .I OBJECT From 6563a6eb539ba5c3f9fa262bc302190abb7e5f39 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 15 Apr 2016 09:51:48 +0200 Subject: [PATCH 201/513] devlink: split dl_argv_parse_put to parse and put parts It is handy to have parsed cmdline data stored so they can be used for dumps filtering. So split original dl_argv_parse_put into parse and put parts. Signed-off-by: Jiri Pirko --- devlink/devlink.c | 105 ++++++++++++++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 36 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index 5e08666d1..0c2132f0a 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -109,12 +109,28 @@ static void ifname_map_free(struct ifname_map *ifname_map) free(ifname_map); } +#define BIT(nr) (1UL << (nr)) +#define DL_OPT_HANDLE BIT(0) +#define DL_OPT_HANDLEP BIT(1) +#define DL_OPT_PORT_TYPE BIT(2) +#define DL_OPT_PORT_COUNT BIT(3) + +struct dl_opts { + uint32_t present; /* flags of present items */ + char *bus_name; + char *dev_name; + uint32_t port_index; + enum devlink_port_type port_type; + uint32_t port_count; +}; + struct dl { struct mnlg_socket *nlg; struct list_head ifname_map_list; int argc; char **argv; bool no_nice_names; + struct dl_opts opts; }; static int dl_argc(struct dl *dl) @@ -347,11 +363,9 @@ static int strtouint32_t(const char *str, uint32_t *p_val) return 0; } -static int dl_argv_put_handle(struct nlmsghdr *nlh, struct dl *dl) +static int dl_argv_handle(struct dl *dl, char **p_bus_name, char **p_dev_name) { char *str = dl_argv_next(dl); - char *bus_name = bus_name; - char *dev_name = dev_name; if (!str) { pr_err("Devlink identification (\"bus_name/dev_name\") expected\n"); @@ -363,19 +377,15 @@ static int dl_argv_put_handle(struct nlmsghdr *nlh, struct dl *dl) return -EINVAL; } - strslashrsplit(str, &bus_name, &dev_name); - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, bus_name); - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, dev_name); + strslashrsplit(str, p_bus_name, p_dev_name); return 0; } -static int dl_argv_put_handle_port(struct nlmsghdr *nlh, struct dl *dl) +static int dl_argv_handle_port(struct dl *dl, char **p_bus_name, + char **p_dev_name, uint32_t *p_port_index) { char *str = dl_argv_next(dl); unsigned int slash_count; - char *bus_name = bus_name; - char *dev_name = dev_name; - uint32_t port_index = port_index; int err; if (!str) { @@ -394,24 +404,21 @@ static int dl_argv_put_handle_port(struct nlmsghdr *nlh, struct dl *dl) char *portstr = portstr; err = strslashrsplit(str, &handlestr, &portstr); - err = strtouint32_t(portstr, &port_index); + err = strtouint32_t(portstr, p_port_index); if (err) { pr_err("Port index \"%s\" is not a number or not within range\n", portstr); return err; } - strslashrsplit(handlestr, &bus_name, &dev_name); + strslashrsplit(handlestr, p_bus_name, p_dev_name); } else if (slash_count == 0) { - err = ifname_map_lookup(dl, str, &bus_name, &dev_name, - &port_index); + err = ifname_map_lookup(dl, str, p_bus_name, p_dev_name, + p_port_index); if (err) { pr_err("Netdevice \"%s\" not found\n", str); return err; } } - mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, bus_name); - mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, dev_name); - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, port_index); return 0; } @@ -460,55 +467,46 @@ static int port_type_get(const char *typestr, enum devlink_port_type *p_type) return 0; } -#define BIT(nr) (1UL << (nr)) -#define DL_OPT_HANDLE BIT(0) -#define DL_OPT_HANDLEP BIT(1) -#define DL_OPT_PORT_TYPE BIT(2) -#define DL_OPT_PORT_COUNT BIT(3) - -static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, - uint32_t o_required, uint32_t o_optional) +static int dl_argv_parse(struct dl *dl, uint32_t o_required, + uint32_t o_optional) { + struct dl_opts *opts = &dl->opts; uint32_t o_all = o_required | o_optional; uint32_t o_found = 0; int err; if (o_required & DL_OPT_HANDLE) { - err = dl_argv_put_handle(nlh, dl); + err = dl_argv_handle(dl, &opts->bus_name, &opts->dev_name); if (err) return err; + o_found |= DL_OPT_HANDLE; } else if (o_required & DL_OPT_HANDLEP) { - err = dl_argv_put_handle_port(nlh, dl); + err = dl_argv_handle_port(dl, &opts->bus_name, &opts->dev_name, + &opts->port_index); if (err) return err; + o_found |= DL_OPT_HANDLEP; } while (dl_argc(dl)) { if (dl_argv_match(dl, "type") && (o_all & DL_OPT_PORT_TYPE)) { - enum devlink_port_type port_type; const char *typestr; dl_arg_inc(dl); err = dl_argv_str(dl, &typestr); if (err) return err; - err = port_type_get(typestr, &port_type); + err = port_type_get(typestr, &opts->port_type); if (err) return err; - mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE, - port_type); o_found |= DL_OPT_PORT_TYPE; } else if (dl_argv_match(dl, "count") && (o_all & DL_OPT_PORT_COUNT)) { - uint32_t count; - dl_arg_inc(dl); - err = dl_argv_uint32_t(dl, &count); + err = dl_argv_uint32_t(dl, &opts->port_count); if (err) return err; - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, - count); o_found |= DL_OPT_PORT_COUNT; } else { pr_err("Unknown option \"%s\"\n", dl_argv(dl)); @@ -516,6 +514,8 @@ static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, } } + opts->present = o_found; + if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) { pr_err("Port type option expected.\n"); return -EINVAL; @@ -530,6 +530,39 @@ static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, return 0; } +static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) +{ + struct dl_opts *opts = &dl->opts; + + if (opts->present & DL_OPT_HANDLE) { + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name); + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name); + } else if (opts->present & DL_OPT_HANDLEP) { + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name); + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name); + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, + opts->port_index); + } + if (opts->present & DL_OPT_PORT_TYPE) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE, + opts->port_type); + if (opts->present & DL_OPT_PORT_COUNT) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, + opts->port_count); +} + +static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, + uint32_t o_required, uint32_t o_optional) +{ + int err; + + err = dl_argv_parse(dl, o_required, o_optional); + if (err) + return err; + dl_opts_put(nlh, dl); + return 0; +} + static void cmd_dev_help(void) { pr_out("Usage: devlink dev show [ DEV ]\n"); From 707a91c5494962e3f5b358fc866ebb79dc28c3e3 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 15 Apr 2016 09:51:49 +0200 Subject: [PATCH 202/513] devlink: introduce dump filtering function This function is to be used from dump callbacks to decide if the output currect output should be filtered off or not. Filtering is based on previously parsed and stored command line options. Signed-off-by: Jiri Pirko --- devlink/devlink.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/devlink/devlink.c b/devlink/devlink.c index 0c2132f0a..d436bbf3a 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -563,6 +563,36 @@ static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, return 0; } +static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) +{ + struct dl_opts *opts = &dl->opts; + struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME]; + struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME]; + struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX]; + + if (opts->present & DL_OPT_HANDLE && + attr_bus_name && attr_dev_name) { + const char *bus_name = mnl_attr_get_str(attr_bus_name); + const char *dev_name = mnl_attr_get_str(attr_dev_name); + + if (strcmp(bus_name, opts->bus_name) != 0 || + strcmp(dev_name, opts->dev_name) != 0) + return false; + } + if (opts->present & DL_OPT_HANDLEP && + attr_bus_name && attr_dev_name && attr_port_index) { + const char *bus_name = mnl_attr_get_str(attr_bus_name); + const char *dev_name = mnl_attr_get_str(attr_dev_name); + uint32_t port_index = mnl_attr_get_u32(attr_port_index); + + if (strcmp(bus_name, opts->bus_name) != 0 || + strcmp(dev_name, opts->dev_name) != 0 || + port_index != opts->port_index) + return false; + } + return true; +} + static void cmd_dev_help(void) { pr_out("Usage: devlink dev show [ DEV ]\n"); From 2f85a9c535874e721cfc8b8743325afc93a8b1fa Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 15 Apr 2016 09:51:50 +0200 Subject: [PATCH 203/513] devlink: allow to parse both devlink and port handle in the same time For filtering purposes, it makes sense for used to either specify devlink handle of port handle. Signed-off-by: Jiri Pirko --- devlink/devlink.c | 109 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 19 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index d436bbf3a..e2e04136c 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -363,6 +363,12 @@ static int strtouint32_t(const char *str, uint32_t *p_val) return 0; } +static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name) +{ + strslashrsplit(str, p_bus_name, p_dev_name); + return 0; +} + static int dl_argv_handle(struct dl *dl, char **p_bus_name, char **p_dev_name) { char *str = dl_argv_next(dl); @@ -376,8 +382,40 @@ static int dl_argv_handle(struct dl *dl, char **p_bus_name, char **p_dev_name) pr_err("Expected \"bus_name/dev_name\".\n"); return -EINVAL; } + return __dl_argv_handle(str, p_bus_name, p_dev_name); +} - strslashrsplit(str, p_bus_name, p_dev_name); +static int __dl_argv_handle_port(char *str, + char **p_bus_name, char **p_dev_name, + uint32_t *p_port_index) +{ + char *handlestr = handlestr; + char *portstr = portstr; + int err; + + strslashrsplit(str, &handlestr, &portstr); + err = strtouint32_t(portstr, p_port_index); + if (err) { + pr_err("Port index \"%s\" is not a number or not within range\n", + portstr); + return err; + } + strslashrsplit(handlestr, p_bus_name, p_dev_name); + return 0; +} + +static int __dl_argv_handle_port_ifname(struct dl *dl, char *str, + char **p_bus_name, char **p_dev_name, + uint32_t *p_port_index) +{ + int err; + + err = ifname_map_lookup(dl, str, p_bus_name, p_dev_name, + p_port_index); + if (err) { + pr_err("Netdevice \"%s\" not found\n", str); + return err; + } return 0; } @@ -386,7 +424,6 @@ static int dl_argv_handle_port(struct dl *dl, char **p_bus_name, { char *str = dl_argv_next(dl); unsigned int slash_count; - int err; if (!str) { pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n"); @@ -398,26 +435,52 @@ static int dl_argv_handle_port(struct dl *dl, char **p_bus_name, pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n"); return -EINVAL; } - if (slash_count == 2) { - char *handlestr = handlestr; - char *portstr = portstr; - - err = strslashrsplit(str, &handlestr, &portstr); - err = strtouint32_t(portstr, p_port_index); - if (err) { - pr_err("Port index \"%s\" is not a number or not within range\n", - portstr); + return __dl_argv_handle_port(str, p_bus_name, + p_dev_name, p_port_index); + } else if (slash_count == 0) { + return __dl_argv_handle_port_ifname(dl, str, p_bus_name, + p_dev_name, p_port_index); + } + return 0; +} + +static int dl_argv_handle_both(struct dl *dl, char **p_bus_name, + char **p_dev_name, uint32_t *p_port_index, + uint32_t *p_handle_bit) +{ + char *str = dl_argv_next(dl); + unsigned int slash_count; + int err; + + if (!str) { + pr_err("One of following identifications expected:\n" + "Devlink identification (\"bus_name/dev_name\")\n" + "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n"); + return -EINVAL; + } + slash_count = strslashcount(str); + if (slash_count == 1) { + err = __dl_argv_handle(str, p_bus_name, p_dev_name); + if (err) return err; - } - strslashrsplit(handlestr, p_bus_name, p_dev_name); + *p_handle_bit = DL_OPT_HANDLE; + } else if (slash_count == 2) { + err = __dl_argv_handle_port(str, p_bus_name, + p_dev_name, p_port_index); + if (err) + return err; + *p_handle_bit = DL_OPT_HANDLEP; } else if (slash_count == 0) { - err = ifname_map_lookup(dl, str, p_bus_name, p_dev_name, - p_port_index); - if (err) { - pr_err("Netdevice \"%s\" not found\n", str); + err = __dl_argv_handle_port_ifname(dl, str, p_bus_name, + p_dev_name, p_port_index); + if (err) return err; - } + *p_handle_bit = DL_OPT_HANDLEP; + } else { + pr_err("Wrong port identification string format.\n"); + pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n"); + return -EINVAL; } return 0; } @@ -475,7 +538,15 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, uint32_t o_found = 0; int err; - if (o_required & DL_OPT_HANDLE) { + if (o_required & DL_OPT_HANDLE && o_required & DL_OPT_HANDLEP) { + uint32_t handle_bit = handle_bit; + + err = dl_argv_handle_both(dl, &opts->bus_name, &opts->dev_name, + &opts->port_index, &handle_bit); + if (err) + return err; + o_found |= handle_bit; + } else if (o_required & DL_OPT_HANDLE) { err = dl_argv_handle(dl, &opts->bus_name, &opts->dev_name); if (err) return err; From b56700bf8add4ebb2fe451c85f50602b58a886a2 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 15 Apr 2016 09:51:51 +0200 Subject: [PATCH 204/513] devlink: implement shared buffer support Implement kernel devlink shared buffer interface. Introduce new object "sb" and allow to browse the shared buffer parameters and also change configuration. Signed-off-by: Jiri Pirko --- devlink/devlink.c | 603 +++++++++++++++++++++++++++++++++++++++- include/linux/devlink.h | 57 ++++ 2 files changed, 659 insertions(+), 1 deletion(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index e2e04136c..228807f88 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -114,6 +114,13 @@ static void ifname_map_free(struct ifname_map *ifname_map) #define DL_OPT_HANDLEP BIT(1) #define DL_OPT_PORT_TYPE BIT(2) #define DL_OPT_PORT_COUNT BIT(3) +#define DL_OPT_SB BIT(4) +#define DL_OPT_SB_POOL BIT(5) +#define DL_OPT_SB_SIZE BIT(6) +#define DL_OPT_SB_TYPE BIT(7) +#define DL_OPT_SB_THTYPE BIT(8) +#define DL_OPT_SB_TH BIT(9) +#define DL_OPT_SB_TC BIT(10) struct dl_opts { uint32_t present; /* flags of present items */ @@ -122,6 +129,13 @@ struct dl_opts { uint32_t port_index; enum devlink_port_type port_type; uint32_t port_count; + uint32_t sb_index; + uint16_t sb_pool_index; + uint32_t sb_pool_size; + enum devlink_sb_pool_type sb_pool_type; + enum devlink_sb_threshold_type sb_pool_thtype; + uint32_t sb_threshold; + uint16_t sb_tc_index; }; struct dl { @@ -225,6 +239,42 @@ static int attr_cb(const struct nlattr *attr, void *data) if (type == DEVLINK_ATTR_PORT_IBDEV_NAME && mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_INDEX && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_SIZE && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_INGRESS_POOL_COUNT && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_EGRESS_POOL_COUNT && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_INGRESS_TC_COUNT && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_EGRESS_TC_COUNT && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_POOL_INDEX && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_POOL_TYPE && + mnl_attr_validate(attr, MNL_TYPE_U8) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_POOL_SIZE && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE && + mnl_attr_validate(attr, MNL_TYPE_U8) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_THRESHOLD && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_TC_INDEX && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; tb[type] = attr; return MNL_CB_OK; } @@ -363,6 +413,20 @@ static int strtouint32_t(const char *str, uint32_t *p_val) return 0; } +static int strtouint16_t(const char *str, uint16_t *p_val) +{ + char *endptr; + unsigned long int val; + + val = strtoul(str, &endptr, 10); + if (endptr == str || *endptr != '\0') + return -EINVAL; + if (val > USHRT_MAX) + return -ERANGE; + *p_val = val; + return 0; +} + static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name) { strslashrsplit(str, p_bus_name, p_dev_name); @@ -503,6 +567,24 @@ static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val) return 0; } +static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val) +{ + char *str = dl_argv_next(dl); + int err; + + if (!str) { + pr_err("Unsigned number argument expected\n"); + return -EINVAL; + } + + err = strtouint16_t(str, p_val); + if (err) { + pr_err("\"%s\" is not a number or not within range\n", str); + return err; + } + return 0; +} + static int dl_argv_str(struct dl *dl, const char **p_str) { const char *str = dl_argv_next(dl); @@ -530,6 +612,33 @@ static int port_type_get(const char *typestr, enum devlink_port_type *p_type) return 0; } +static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type) +{ + if (strcmp(typestr, "ingress") == 0) { + *p_type = DEVLINK_SB_POOL_TYPE_INGRESS; + } else if (strcmp(typestr, "egress") == 0) { + *p_type = DEVLINK_SB_POOL_TYPE_EGRESS; + } else { + pr_err("Unknown pool type \"%s\"\n", typestr); + return -EINVAL; + } + return 0; +} + +static int threshold_type_get(const char *typestr, + enum devlink_sb_threshold_type *p_type) +{ + if (strcmp(typestr, "static") == 0) { + *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC; + } else if (strcmp(typestr, "dynamic") == 0) { + *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC; + } else { + pr_err("Unknown threshold type \"%s\"\n", typestr); + return -EINVAL; + } + return 0; +} + static int dl_argv_parse(struct dl *dl, uint32_t o_required, uint32_t o_optional) { @@ -579,6 +688,66 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, if (err) return err; o_found |= DL_OPT_PORT_COUNT; + } else if (dl_argv_match(dl, "sb") && + (o_all & DL_OPT_SB)) { + dl_arg_inc(dl); + err = dl_argv_uint32_t(dl, &opts->sb_index); + if (err) + return err; + o_found |= DL_OPT_SB; + } else if (dl_argv_match(dl, "pool") && + (o_all & DL_OPT_SB_POOL)) { + dl_arg_inc(dl); + err = dl_argv_uint16_t(dl, &opts->sb_pool_index); + if (err) + return err; + o_found |= DL_OPT_SB_POOL; + } else if (dl_argv_match(dl, "size") && + (o_all & DL_OPT_SB_SIZE)) { + dl_arg_inc(dl); + err = dl_argv_uint32_t(dl, &opts->sb_pool_size); + if (err) + return err; + o_found |= DL_OPT_SB_SIZE; + } else if (dl_argv_match(dl, "type") && + (o_all & DL_OPT_SB_TYPE)) { + const char *typestr; + + dl_arg_inc(dl); + err = dl_argv_str(dl, &typestr); + if (err) + return err; + err = pool_type_get(typestr, &opts->sb_pool_type); + if (err) + return err; + o_found |= DL_OPT_SB_TYPE; + } else if (dl_argv_match(dl, "thtype") && + (o_all & DL_OPT_SB_THTYPE)) { + const char *typestr; + + dl_arg_inc(dl); + err = dl_argv_str(dl, &typestr); + if (err) + return err; + err = threshold_type_get(typestr, + &opts->sb_pool_thtype); + if (err) + return err; + o_found |= DL_OPT_SB_THTYPE; + } else if (dl_argv_match(dl, "th") && + (o_all & DL_OPT_SB_TH)) { + dl_arg_inc(dl); + err = dl_argv_uint32_t(dl, &opts->sb_threshold); + if (err) + return err; + o_found |= DL_OPT_SB_TH; + } else if (dl_argv_match(dl, "tc") && + (o_all & DL_OPT_SB_TC)) { + dl_arg_inc(dl); + err = dl_argv_uint16_t(dl, &opts->sb_tc_index); + if (err) + return err; + o_found |= DL_OPT_SB_TC; } else { pr_err("Unknown option \"%s\"\n", dl_argv(dl)); return -EINVAL; @@ -587,6 +756,11 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, opts->present = o_found; + if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) { + opts->sb_index = 0; + opts->present |= DL_OPT_SB; + } + if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) { pr_err("Port type option expected.\n"); return -EINVAL; @@ -598,6 +772,35 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, return -EINVAL; } + if ((o_required & DL_OPT_SB_POOL) && !(o_found & DL_OPT_SB_POOL)) { + pr_err("Pool index option expected.\n"); + return -EINVAL; + } + + if ((o_required & DL_OPT_SB_SIZE) && !(o_found & DL_OPT_SB_SIZE)) { + pr_err("Pool size option expected.\n"); + return -EINVAL; + } + + if ((o_required & DL_OPT_SB_TYPE) && !(o_found & DL_OPT_SB_TYPE)) { + pr_err("Pool type option expected.\n"); + return -EINVAL; + } + + if ((o_required & DL_OPT_SB_THTYPE) && !(o_found & DL_OPT_SB_THTYPE)) { + pr_err("Pool threshold type option expected.\n"); + return -EINVAL; + } + + if ((o_required & DL_OPT_SB_TH) && !(o_found & DL_OPT_SB_TH)) { + pr_err("Threshold option expected.\n"); + return -EINVAL; + } + + if ((o_required & DL_OPT_SB_TC) && !(o_found & DL_OPT_SB_TC)) { + pr_err("TC index option expected.\n"); + return -EINVAL; + } return 0; } @@ -620,6 +823,27 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) if (opts->present & DL_OPT_PORT_COUNT) mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, opts->port_count); + if (opts->present & DL_OPT_SB) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, + opts->sb_index); + if (opts->present & DL_OPT_SB_POOL) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, + opts->sb_pool_index); + if (opts->present & DL_OPT_SB_SIZE) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE, + opts->sb_pool_size); + if (opts->present & DL_OPT_SB_TYPE) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, + opts->sb_pool_type); + if (opts->present & DL_OPT_SB_THTYPE) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, + opts->sb_pool_thtype); + if (opts->present & DL_OPT_SB_TH) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, + opts->sb_threshold); + if (opts->present & DL_OPT_SB_TC) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, + opts->sb_tc_index); } static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, @@ -929,6 +1153,380 @@ static int cmd_port(struct dl *dl) return -ENOENT; } +static void cmd_sb_help(void) +{ + pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); + pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); + pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); + pr_out(" size POOL_SIZE thtype { static | dynamic }\n"); + pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); + pr_out(" pool POOL_INDEX ]\n"); + pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); + pr_out(" pool POOL_INDEX th THRESHOLD\n"); + pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); + pr_out(" type { ingress | egress } ]\n"); + pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); + pr_out(" type { ingress | egress } pool POOL_INDEX\n"); + pr_out(" th THRESHOLD\n"); +} + +static void pr_out_sb(struct nlattr **tb) +{ + pr_out_handle(tb); + pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); +} + +static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] || + !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] || + !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] || + !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] || + !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]) + return MNL_CB_ERROR; + pr_out_sb(tb); + return MNL_CB_OK; +} + +static int cmd_sb_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + int err; + + if (dl_argc(dl) == 0) + flags |= NLM_F_DUMP; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags); + + if (dl_argc(dl) > 0) { + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); + if (err) + return err; + } + + return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL); +} + +static const char *pool_type_name(uint8_t type) +{ + switch (type) { + case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress"; + case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress"; + default: return ""; + } +} + +static const char *threshold_type_name(uint8_t type) +{ + switch (type) { + case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static"; + case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic"; + default: return ""; + } +} + +static void pr_out_sb_pool(struct nlattr **tb) +{ + pr_out_handle(tb); + pr_out(": sb %u pool %u type %s size %u thtype %s\n", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), + pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]), + threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); +} + +static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] || + !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] || + !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) + return MNL_CB_ERROR; + pr_out_sb_pool(tb); + return MNL_CB_OK; +} + +static int cmd_sb_pool_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + int err; + + if (dl_argc(dl) == 0) + flags |= NLM_F_DUMP; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags); + + if (dl_argc(dl) > 0) { + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL, + DL_OPT_SB); + if (err) + return err; + } + + return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL); +} + +static int cmd_sb_pool_set(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL | + DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_sb_pool(struct dl *dl) +{ + if (dl_argv_match(dl, "help")) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "show") || + dl_argv_match(dl, "list") || dl_no_arg(dl)) { + dl_arg_inc(dl); + return cmd_sb_pool_show(dl); + } else if (dl_argv_match(dl, "set")) { + dl_arg_inc(dl); + return cmd_sb_pool_set(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb) +{ + pr_out_port_handle_nice(dl, tb); + pr_out(": sb %u pool %u threshold %u\n", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); +} + +static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || + !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) + return MNL_CB_ERROR; + pr_out_sb_port_pool(dl, tb); + return MNL_CB_OK; +} + +static int cmd_sb_port_pool_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + int err; + + if (dl_argc(dl) == 0) + flags |= NLM_F_DUMP; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); + + if (dl_argc(dl) > 0) { + err = dl_argv_parse_put(nlh, dl, + DL_OPT_HANDLEP | DL_OPT_SB_POOL, + DL_OPT_SB); + if (err) + return err; + } + + return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); +} + +static int cmd_sb_port_pool_set(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL | + DL_OPT_SB_TH, DL_OPT_SB); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_sb_port_pool(struct dl *dl) +{ + if (dl_argv_match(dl, "help")) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "show") || + dl_argv_match(dl, "list") || dl_no_arg(dl)) { + dl_arg_inc(dl); + return cmd_sb_port_pool_show(dl); + } else if (dl_argv_match(dl, "set")) { + dl_arg_inc(dl); + return cmd_sb_port_pool_set(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static int cmd_sb_port(struct dl *dl) +{ + if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "pool")) { + dl_arg_inc(dl); + return cmd_sb_port_pool(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb) +{ + pr_out_port_handle_nice(dl, tb); + pr_out(": sb %u tc %u type %s pool %u threshold %u\n", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]), + pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); +} + +static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || + !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || + !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) + return MNL_CB_ERROR; + pr_out_sb_tc_bind(dl, tb); + return MNL_CB_OK; +} + +static int cmd_sb_tc_bind_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + int err; + + if (dl_argc(dl) == 0) + flags |= NLM_F_DUMP; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); + + if (dl_argc(dl) > 0) { + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | + DL_OPT_SB_TYPE, DL_OPT_SB); + if (err) + return err; + } + + return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); +} + +static int cmd_sb_tc_bind_set(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | + DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH, + DL_OPT_SB); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_sb_tc_bind(struct dl *dl) +{ + if (dl_argv_match(dl, "help")) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "show") || + dl_argv_match(dl, "list") || dl_no_arg(dl)) { + dl_arg_inc(dl); + return cmd_sb_tc_bind_show(dl); + } else if (dl_argv_match(dl, "set")) { + dl_arg_inc(dl); + return cmd_sb_tc_bind_set(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static int cmd_sb_tc(struct dl *dl) +{ + if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "bind")) { + dl_arg_inc(dl); + return cmd_sb_tc_bind(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static int cmd_sb(struct dl *dl) +{ + if (dl_argv_match(dl, "help")) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "show") || + dl_argv_match(dl, "list") || dl_no_arg(dl)) { + dl_arg_inc(dl); + return cmd_sb_show(dl); + } else if (dl_argv_match(dl, "pool")) { + dl_arg_inc(dl); + return cmd_sb_pool(dl); + } else if (dl_argv_match(dl, "port")) { + dl_arg_inc(dl); + return cmd_sb_port(dl); + } else if (dl_argv_match(dl, "tc")) { + dl_arg_inc(dl); + return cmd_sb_tc(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + static const char *cmd_name(uint8_t cmd) { switch (cmd) { @@ -1064,7 +1662,7 @@ static int cmd_mon(struct dl *dl) static void help(void) { pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" - "where OBJECT := { dev | port | monitor }\n" + "where OBJECT := { dev | port | sb | monitor }\n" " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); } @@ -1079,6 +1677,9 @@ static int dl_cmd(struct dl *dl) } else if (dl_argv_match(dl, "port")) { dl_arg_inc(dl); return cmd_port(dl); + } else if (dl_argv_match(dl, "sb")) { + dl_arg_inc(dl); + return cmd_sb(dl); } else if (dl_argv_match(dl, "monitor")) { dl_arg_inc(dl); return cmd_mon(dl); diff --git a/include/linux/devlink.h b/include/linux/devlink.h index c9fee5781..9c1aa5783 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -33,6 +33,26 @@ enum devlink_command { DEVLINK_CMD_PORT_SPLIT, DEVLINK_CMD_PORT_UNSPLIT, + DEVLINK_CMD_SB_GET, /* can dump */ + DEVLINK_CMD_SB_SET, + DEVLINK_CMD_SB_NEW, + DEVLINK_CMD_SB_DEL, + + DEVLINK_CMD_SB_POOL_GET, /* can dump */ + DEVLINK_CMD_SB_POOL_SET, + DEVLINK_CMD_SB_POOL_NEW, + DEVLINK_CMD_SB_POOL_DEL, + + DEVLINK_CMD_SB_PORT_POOL_GET, /* can dump */ + DEVLINK_CMD_SB_PORT_POOL_SET, + DEVLINK_CMD_SB_PORT_POOL_NEW, + DEVLINK_CMD_SB_PORT_POOL_DEL, + + DEVLINK_CMD_SB_TC_POOL_BIND_GET, /* can dump */ + DEVLINK_CMD_SB_TC_POOL_BIND_SET, + DEVLINK_CMD_SB_TC_POOL_BIND_NEW, + DEVLINK_CMD_SB_TC_POOL_BIND_DEL, + /* add new commands above here */ __DEVLINK_CMD_MAX, @@ -46,6 +66,31 @@ enum devlink_port_type { DEVLINK_PORT_TYPE_IB, }; +enum devlink_sb_pool_type { + DEVLINK_SB_POOL_TYPE_INGRESS, + DEVLINK_SB_POOL_TYPE_EGRESS, +}; + +/* static threshold - limiting the maximum number of bytes. + * dynamic threshold - limiting the maximum number of bytes + * based on the currently available free space in the shared buffer pool. + * In this mode, the maximum quota is calculated based + * on the following formula: + * max_quota = alpha / (1 + alpha) * Free_Buffer + * While Free_Buffer is the amount of none-occupied buffer associated to + * the relevant pool. + * The value range which can be passed is 0-20 and serves + * for computation of alpha by following formula: + * alpha = 2 ^ (passed_value - 10) + */ + +enum devlink_sb_threshold_type { + DEVLINK_SB_THRESHOLD_TYPE_STATIC, + DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC, +}; + +#define DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX 20 + enum devlink_attr { /* don't change the order or add anything between, this is ABI! */ DEVLINK_ATTR_UNSPEC, @@ -62,6 +107,18 @@ enum devlink_attr { DEVLINK_ATTR_PORT_IBDEV_NAME, /* string */ DEVLINK_ATTR_PORT_SPLIT_COUNT, /* u32 */ DEVLINK_ATTR_PORT_SPLIT_GROUP, /* u32 */ + DEVLINK_ATTR_SB_INDEX, /* u32 */ + DEVLINK_ATTR_SB_SIZE, /* u32 */ + DEVLINK_ATTR_SB_INGRESS_POOL_COUNT, /* u16 */ + DEVLINK_ATTR_SB_EGRESS_POOL_COUNT, /* u16 */ + DEVLINK_ATTR_SB_INGRESS_TC_COUNT, /* u16 */ + DEVLINK_ATTR_SB_EGRESS_TC_COUNT, /* u16 */ + DEVLINK_ATTR_SB_POOL_INDEX, /* u16 */ + DEVLINK_ATTR_SB_POOL_TYPE, /* u8 */ + DEVLINK_ATTR_SB_POOL_SIZE, /* u32 */ + DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ + DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ + DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ /* add new attributes above here, update the policy in devlink.c */ From a60ebcb6f34f4c43cba092f52b1150d7fb1deec5 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 15 Apr 2016 09:51:52 +0200 Subject: [PATCH 205/513] devlink: implement shared buffer occupancy control Use kernel shared buffer occupancy control commands to make snapshot and clear occupancy watermarks. Also, allow to show occupancy values in a nice way. Signed-off-by: Jiri Pirko --- devlink/devlink.c | 349 ++++++++++++++++++++++++++++++++++++++++ include/linux/devlink.h | 6 + 2 files changed, 355 insertions(+) diff --git a/devlink/devlink.c b/devlink/devlink.c index 228807f88..ffefa86d2 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -27,6 +27,12 @@ #define pr_err(args...) fprintf(stderr, ##args) #define pr_out(args...) fprintf(stdout, ##args) +#define pr_out_sp(num, args...) \ + do { \ + int ret = fprintf(stdout, ##args); \ + if (ret < num) \ + fprintf(stdout, "%*s", num - ret, ""); \ + } while (0) static int _mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data) @@ -275,6 +281,12 @@ static int attr_cb(const struct nlattr *attr, void *data) if (type == DEVLINK_ATTR_SB_TC_INDEX && mnl_attr_validate(attr, MNL_TYPE_U16) < 0) return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_OCC_CUR && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_OCC_MAX && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; tb[type] = attr; return MNL_CB_OK; } @@ -864,6 +876,7 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME]; struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME]; struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX]; + struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX]; if (opts->present & DL_OPT_HANDLE && attr_bus_name && attr_dev_name) { @@ -885,6 +898,12 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) port_index != opts->port_index) return false; } + if (opts->present & DL_OPT_SB && attr_sb_index) { + uint32_t sb_index = mnl_attr_get_u32(attr_sb_index); + + if (sb_index != opts->sb_index) + return false; + } return true; } @@ -1168,6 +1187,9 @@ static void cmd_sb_help(void) pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); pr_out(" type { ingress | egress } pool POOL_INDEX\n"); pr_out(" th THRESHOLD\n"); + pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); + pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); + pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); } static void pr_out_sb(struct nlattr **tb) @@ -1504,6 +1526,330 @@ static int cmd_sb_tc(struct dl *dl) return -ENOENT; } +struct occ_item { + struct list_head list; + uint32_t index; + uint32_t cur; + uint32_t max; + uint32_t bound_pool_index; +}; + +struct occ_port { + struct list_head list; + char *bus_name; + char *dev_name; + uint32_t port_index; + uint32_t sb_index; + struct list_head pool_list; + struct list_head ing_tc_list; + struct list_head eg_tc_list; +}; + +struct occ_show { + struct dl *dl; + int err; + struct list_head port_list; +}; + +static struct occ_item *occ_item_alloc(void) +{ + return calloc(1, sizeof(struct occ_item)); +} + +static void occ_item_free(struct occ_item *occ_item) +{ + free(occ_item); +} + +static struct occ_port *occ_port_alloc(uint32_t port_index) +{ + struct occ_port *occ_port; + + occ_port = calloc(1, sizeof(*occ_port)); + if (!occ_port) + return NULL; + occ_port->port_index = port_index; + INIT_LIST_HEAD(&occ_port->pool_list); + INIT_LIST_HEAD(&occ_port->ing_tc_list); + INIT_LIST_HEAD(&occ_port->eg_tc_list); + return occ_port; +} + +static void occ_port_free(struct occ_port *occ_port) +{ + struct occ_item *occ_item, *tmp; + + list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list) + occ_item_free(occ_item); + list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list) + occ_item_free(occ_item); + list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list) + occ_item_free(occ_item); +} + +static struct occ_show *occ_show_alloc(struct dl *dl) +{ + struct occ_show *occ_show; + + occ_show = calloc(1, sizeof(*occ_show)); + if (!occ_show) + return NULL; + occ_show->dl = dl; + INIT_LIST_HEAD(&occ_show->port_list); + return occ_show; +} + +static void occ_show_free(struct occ_show *occ_show) +{ + struct occ_port *occ_port, *tmp; + + list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list) + occ_port_free(occ_port); +} + +static struct occ_port *occ_port_get(struct occ_show *occ_show, + struct nlattr **tb) +{ + struct occ_port *occ_port; + uint32_t port_index; + + port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); + + list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) { + if (occ_port->port_index == port_index) + return occ_port; + } + occ_port = occ_port_alloc(port_index); + if (!occ_port) + return NULL; + list_add_tail(&occ_port->list, &occ_show->port_list); + return occ_port; +} + +static void pr_out_occ_show_item_list(const char *label, struct list_head *list, + bool bound_pool) +{ + struct occ_item *occ_item; + int i = 1; + + pr_out_sp(7, " %s:", label); + list_for_each_entry(occ_item, list, list) { + if ((i - 1) % 4 == 0 && i != 1) + pr_out_sp(7, " "); + if (bound_pool) + pr_out_sp(7, "%2u(%u):", occ_item->index, + occ_item->bound_pool_index); + else + pr_out_sp(7, "%2u:", occ_item->index); + pr_out_sp(15, "%7u/%u", occ_item->cur, occ_item->max); + if (i++ % 4 == 0) + pr_out("\n"); + } + if ((i - 1) % 4 != 0) + pr_out("\n"); +} + +static void pr_out_occ_show_port(struct occ_port *occ_port) +{ + pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); + pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); + pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); +} + +static void pr_out_occ_show(struct occ_show *occ_show) +{ + struct dl *dl = occ_show->dl; + struct dl_opts *opts = &dl->opts; + struct occ_port *occ_port; + + list_for_each_entry(occ_port, &occ_show->port_list, list) { + __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name, + occ_port->port_index); + pr_out(":\n"); + pr_out_occ_show_port(occ_port); + } +} + +static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show, + struct nlattr **tb) +{ + struct occ_port *occ_port; + struct occ_item *occ_item; + + if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) + return; + + occ_port = occ_port_get(occ_show, tb); + if (!occ_port) { + occ_show->err = -ENOMEM; + return; + } + + occ_item = occ_item_alloc(); + if (!occ_item) { + occ_show->err = -ENOMEM; + return; + } + occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); + occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); + occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); + list_add_tail(&occ_item->list, &occ_port->pool_list); +} + +static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data) +{ + struct occ_show *occ_show = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || + !tb[DEVLINK_ATTR_SB_POOL_INDEX] || + !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) + return MNL_CB_ERROR; + cmd_sb_occ_port_pool_process(occ_show, tb); + return MNL_CB_OK; +} + +static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show, + struct nlattr **tb) +{ + struct occ_port *occ_port; + struct occ_item *occ_item; + uint8_t pool_type; + + if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) + return; + + occ_port = occ_port_get(occ_show, tb); + if (!occ_port) { + occ_show->err = -ENOMEM; + return; + } + + occ_item = occ_item_alloc(); + if (!occ_item) { + occ_show->err = -ENOMEM; + return; + } + occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]); + occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); + occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); + occ_item->bound_pool_index = + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); + pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]); + if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS) + list_add_tail(&occ_item->list, &occ_port->ing_tc_list); + else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS) + list_add_tail(&occ_item->list, &occ_port->eg_tc_list); + else + occ_item_free(occ_item); +} + +static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data) +{ + struct occ_show *occ_show = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || + !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || + !tb[DEVLINK_ATTR_SB_POOL_INDEX] || + !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) + return MNL_CB_ERROR; + cmd_sb_occ_tc_pool_process(occ_show, tb); + return MNL_CB_OK; +} + +static int cmd_sb_occ_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + struct occ_show *occ_show; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP; + int err; + + err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB); + if (err) + return err; + + occ_show = occ_show_alloc(dl); + if (!occ_show) + return -ENOMEM; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); + + err = _mnlg_socket_sndrcv(dl->nlg, nlh, + cmd_sb_occ_port_pool_process_cb, occ_show); + if (err) + goto out; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); + + err = _mnlg_socket_sndrcv(dl->nlg, nlh, + cmd_sb_occ_tc_pool_process_cb, occ_show); + if (err) + goto out; + + pr_out_occ_show(occ_show); + +out: + occ_show_free(occ_show); + return err; +} + +static int cmd_sb_occ_snapshot(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_sb_occ_clearmax(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_sb_occ(struct dl *dl) +{ + if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "show") || + dl_argv_match(dl, "list")) { + dl_arg_inc(dl); + return cmd_sb_occ_show(dl); + } else if (dl_argv_match(dl, "snapshot")) { + dl_arg_inc(dl); + return cmd_sb_occ_snapshot(dl); + } else if (dl_argv_match(dl, "clearmax")) { + dl_arg_inc(dl); + return cmd_sb_occ_clearmax(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + static int cmd_sb(struct dl *dl) { if (dl_argv_match(dl, "help")) { @@ -1522,6 +1868,9 @@ static int cmd_sb(struct dl *dl) } else if (dl_argv_match(dl, "tc")) { dl_arg_inc(dl); return cmd_sb_tc(dl); + } else if (dl_argv_match(dl, "occupancy")) { + dl_arg_inc(dl); + return cmd_sb_occ(dl); } pr_err("Command \"%s\" not found\n", dl_argv(dl)); return -ENOENT; diff --git a/include/linux/devlink.h b/include/linux/devlink.h index 9c1aa5783..ba0073b26 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -53,6 +53,10 @@ enum devlink_command { DEVLINK_CMD_SB_TC_POOL_BIND_NEW, DEVLINK_CMD_SB_TC_POOL_BIND_DEL, + /* Shared buffer occupancy monitoring commands */ + DEVLINK_CMD_SB_OCC_SNAPSHOT, + DEVLINK_CMD_SB_OCC_MAX_CLEAR, + /* add new commands above here */ __DEVLINK_CMD_MAX, @@ -119,6 +123,8 @@ enum devlink_attr { DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ + DEVLINK_ATTR_SB_OCC_CUR, /* u32 */ + DEVLINK_ATTR_SB_OCC_MAX, /* u32 */ /* add new attributes above here, update the policy in devlink.c */ From 4bf138d6d2747b198fc0a78f5fe4e1c9287e9e90 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 15 Apr 2016 09:51:53 +0200 Subject: [PATCH 206/513] devlink: add manpage for shared buffer Manpage for devlink "sb" object. Signed-off-by: Jiri Pirko --- man/man8/devlink-dev.8 | 1 + man/man8/devlink-monitor.8 | 1 + man/man8/devlink-port.8 | 1 + man/man8/devlink-sb.8 | 313 +++++++++++++++++++++++++++++++++++++ 4 files changed, 316 insertions(+) create mode 100644 man/man8/devlink-sb.8 diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8 index af96a298a..62bcead37 100644 --- a/man/man8/devlink-dev.8 +++ b/man/man8/devlink-dev.8 @@ -52,6 +52,7 @@ Shows the state of specified devlink device. .SH SEE ALSO .BR devlink (8), .BR devlink-port (8), +.BR devlink-sb (8), .BR devlink-monitor (8), .br diff --git a/man/man8/devlink-monitor.8 b/man/man8/devlink-monitor.8 index 98134c370..13fe641dc 100644 --- a/man/man8/devlink-monitor.8 +++ b/man/man8/devlink-monitor.8 @@ -29,6 +29,7 @@ opens Devlink Netlink socket, listens on it and dumps state changes. .SH SEE ALSO .BR devlink (8), .BR devlink-dev (8), +.BR devlink-sb (8), .BR devlink-port (8), .br diff --git a/man/man8/devlink-port.8 b/man/man8/devlink-port.8 index d78837c77..a639d01fa 100644 --- a/man/man8/devlink-port.8 +++ b/man/man8/devlink-port.8 @@ -120,6 +120,7 @@ Unplit the specified previously split devlink port. .SH SEE ALSO .BR devlink (8), .BR devlink-dev (8), +.BR devlink-sb (8), .BR devlink-monitor (8), .br diff --git a/man/man8/devlink-sb.8 b/man/man8/devlink-sb.8 new file mode 100644 index 000000000..ffb5553e3 --- /dev/null +++ b/man/man8/devlink-sb.8 @@ -0,0 +1,313 @@ +.TH DEVLINK\-SB 8 "14 Apr 2016" "iproute2" "Linux" +.SH NAME +devlink-sb \- devlink shared buffer configuration +.SH SYNOPSIS +.sp +.ad l +.in +8 +.ti -8 +.B devlink +.RI "[ " OPTIONS " ]" +.B sb +.RI " { " COMMAND " | " +.BR help " }" +.sp + +.ti -8 +.IR OPTIONS " := { " +\fB\-V\fR[\fIersion\fR] | +\fB\-n\fR[\fIno-nice-names\fR] } + +.ti -8 +.BR "devlink sb show " +.RI "[ " DEV " [ " +.B sb +.IR SB_INDEX " ] ]" + +.ti -8 +.BR "devlink sb pool show " +.RI "[ " DEV " [ " +.B sb +.IR SB_INDEX " ] " +.br +.B pool +.IR POOL_INDEX " ]" + +.ti -8 +.BI "devlink sb pool set " DEV " +.RB "[ " sb +.IR SB_INDEX " ] " +.br +.BI pool " POOL_INDEX " +.br +.BI size " POOL_SIZE " +.br +.BR thtype " { " static " | " dynamic " }" + +.ti -8 +.BR "devlink sb port pool show " +.RI "[ " DEV/PORT_INDEX " [ " +.B sb +.IR SB_INDEX " ] " +.br +.B pool +.IR POOL_INDEX " ]" + +.ti -8 +.BI "devlink sb port pool set " DEV/PORT_INDEX " +.RB "[ " sb +.IR SB_INDEX " ] " +.br +.BI pool " POOL_INDEX " +.br +.BI th " THRESHOLD " + +.ti -8 +.BR "devlink sb tc bind show " +.RI "[ " DEV/PORT_INDEX " [ " +.B sb +.IR SB_INDEX " ] " +.br +.BI tc " TC_INDEX " +.br +.B type +.RB "{ " ingress " | " egress " } ]" + +.ti -8 +.BI "devlink sb tc bind set " DEV/PORT_INDEX " +.RB "[ " sb +.IR SB_INDEX " ] " +.br +.BI tc " TC_INDEX " +.br +.BR type " { " ingress " | " egress " }" +.br +.BI pool " POOL_INDEX " +.br +.BI th " THRESHOLD " + +.ti -8 +.BR "devlink sb occupancy show " +.RI "{ " DEV " | " DEV/PORT_INDEX " } [ " +.B sb +.IR SB_INDEX " ] " + +.ti -8 +.BR "devlink sb occupancy snapshot " +.IR DEV " [ " +.B sb +.IR SB_INDEX " ]" + +.ti -8 +.BR "devlink sb occupancy clearmax " +.IR DEV " [ " +.B sb +.IR SB_INDEX " ]" + +.ti -8 +.B devlink sb help + +.SH "DESCRIPTION" +.SS devlink sb show - display available shared buffers and their attributes + +.PP +.I "DEV" +- specifies the devlink device to show shared buffers. +If this argument is omitted all shared buffers of all devices are listed. + +.PP +.I "SB_INDEX" +- specifies the shared buffer. +If this argument is omitted shared buffer with index 0 is selected. +Behaviour of this argument it the same for every command. + +.SS devlink sb pool show - display available pools and their attributes + +.PP +.I "DEV" +- specifies the devlink device to show pools. +If this argument is omitted all pools of all devices are listed. + +.SS devlink sb pool set - set attributes of pool + +.PP +.I "DEV" +- specifies the devlink device to set pool. + +.TP +.BI size " POOL_SIZE" +size of the pool in Bytes. + +.TP +.BR thtype " { " static " | " dynamic " } " +pool threshold type. + +.I static +- Threshold values for the pool will be passed in Bytes. + +.I dynamic +- Threshold values ("to_alpha") for the pool will be used to compute alpha parameter according to formula: +.br +.in +16 +alpha = 2 ^ (to_alpha - 10) +.in -16 + +.in +10 +The range of the passed value is between 0 to 20. The computed alpha is used to determine the maximum usage of the flow: +.in -10 +.br +.in +16 +max_usage = alpha / (1 + alpha) * Free_Buffer +.in -16 + +.SS devlink sb port pool show - display port-pool combinations and threshold for each +.I "DEV/PORT_INDEX" +- specifies the devlink port. + +.TP +.BI pool " POOL_INDEX" +pool index. + +.SS devlink sb port pool set - set port-pool threshold +.I "DEV/PORT_INDEX" +- specifies the devlink port. + +.TP +.BI pool " POOL_INDEX" +pool index. + +.TP +.BI th " THRESHOLD" +threshold value. Type of the value is either Bytes or "to_alpha", depends on +.B thtype +set for the pool. + +.SS devlink sb tc bind show - display port-TC to pool bindings and threshold for each + +.I "DEV/PORT_INDEX" +- specifies the devlink port. + +.TP +.BI tc " TC_INDEX" +index of either ingress or egress TC, usually in range 0 to 8 (depends on device). + +.TP +.BR type " { " ingress " | " egress " } " +TC type. + +.SS devlink sb tc bind set - set port-TC to pool binding with specified threshold + +.I "DEV/PORT_INDEX" +- specifies the devlink port. + +.TP +.BI tc " TC_INDEX" +index of either ingress or egress TC, usually in range 0 to 8 (depends on device). + +.TP +.BR type " { " ingress " | " egress " } " +TC type. + +.TP +.BI pool " POOL_INDEX" +index of pool to bind this to. + +.TP +.BI th " THRESHOLD" +threshold value. Type of the value is either Bytes or "to_alpha", depends on +.B thtype +set for the pool. + +.SS devlink sb occupancy show - display shared buffer occupancy values for device or port + +.PP +This command is used to browse shared buffer occupancy values. Values are showed for every port-pool combination as well as for all port-TC combinations (with pool this port-TC is bound to). Format of value is: +.br +.in +16 +current_value/max_value +.in -16 +Note that before showing values, one has to issue +.b occupancy snapshot +command first. + +.PP +.I "DEV" +- specifies the devlink device to show occupancy values for. + +.I "DEV/PORT_INDEX" +- specifies the devlink port to show occupancy values for. + +.SS devlink sb occupancy snapshot - take occupancy snapshot of shared buffer for device +This command is used to take a snapshot of shared buffer occupancy values. After that, the values can be showed using +.B occupancy show +command. + +.PP +.I "DEV" +- specifies the devlink device to take occupancy snapshot on. + +.SS devlink sb occupancy clearmax - clear occupancy watermarks of shared buffer for device +This command is used to reset maximal occupancy values reached for whole device. Note that before browsing reset values, one has to issue +.B occupancy snapshot +command. + +.PP +.I "DEV" +- specifies the devlink device to clear occupancy watermarks on. + +.SH "EXAMPLES" +.PP +devlink sb show +.RS 4 +List available share buffers. +.RE +.PP +devlink sb pool show +.RS 4 +List available pools and their config. +.RE +.PP +devlink sb port pool show pci/0000:03:00.0/1 pool 0 +.RS 4 +Show port-pool setup for specified port and pool. +.RE +.PP +sudo devlink sb port pool set pci/0000:03:00.0/1 pool 0 th 15 +.RS 4 +Change threshold for port specified port and pool. +.RE +.PP +devlink sb tc bind show pci/0000:03:00.0/1 tc 0 type ingress +.RS 4 +Show pool binding and threshold for specified port and TC. +.RE +.PP +sudo devlink sb tc bind set pci/0000:03:00.0/1 tc 0 type ingress pool 0 th 9 +.RS 4 +Set pool binding and threshold for specified port and TC. +.RE +.PP +sudo devlink sb occupancy snapshot pci/0000:03:00.0 +.RS 4 +Make a snapshot of occupancy of shared buffer for specified devlink device. +.RE +.PP +devlink sb occupancy show pci/0000:03:00.0/1 +.RS 4 +Show occupancy for specified port from the snapshot. +.RE +.PP +sudo devlink sb occupancy clearmax pci/0000:03:00.0 +.RS 4 +Clear watermarks for shared buffer of specified devlink device. + + +.SH SEE ALSO +.BR devlink (8), +.BR devlink-dev (8), +.BR devlink-port (8), +.BR devlink-monitor (8), +.br + +.SH AUTHOR +Jiri Pirko From 8b5be9ecfff493d06189234405be210404dc38bb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 19 Apr 2016 08:06:11 -0700 Subject: [PATCH 207/513] update inet_diag.h header --- include/linux/inet_diag.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index 1db411688..b806fcfc1 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -113,6 +113,8 @@ enum { INET_DIAG_DCTCPINFO, INET_DIAG_PROTOCOL, /* response attribute only */ INET_DIAG_SKV6ONLY, + INET_DIAG_LOCALS, + INET_DIAG_PEERS, }; #define INET_DIAG_MAX INET_DIAG_SKV6ONLY From 32c0b9b7a8211d83ef82fc030c3cb2e137e00821 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 22 Apr 2016 10:01:12 -0700 Subject: [PATCH 208/513] update kernel headers from net-next --- include/linux/bpf.h | 4 ++++ include/linux/devlink.h | 6 +++--- include/linux/if_ether.h | 1 + include/linux/if_link.h | 25 +++++++++++++++++++++++++ include/linux/rtnetlink.h | 6 ++++++ 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 3398b5de8..ce6d03ee0 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -347,6 +347,10 @@ enum bpf_func_id { #define BPF_F_ZERO_CSUM_TX (1ULL << 1) #define BPF_F_DONT_FRAGMENT (1ULL << 2) +/* BPF_FUNC_perf_event_output flags. */ +#define BPF_F_INDEX_MASK 0xffffffffULL +#define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK + /* user accessible mirror of in-kernel sk_buff. * new fields can only be added to the end of this structure */ diff --git a/include/linux/devlink.h b/include/linux/devlink.h index ba0073b26..0e21d001f 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -9,8 +9,8 @@ * (at your option) any later version. */ -#ifndef _UAPI_LINUX_DEVLINK_H_ -#define _UAPI_LINUX_DEVLINK_H_ +#ifndef _LINUX_DEVLINK_H_ +#define _LINUX_DEVLINK_H_ #define DEVLINK_GENL_NAME "devlink" #define DEVLINK_GENL_VERSION 0x1 @@ -132,4 +132,4 @@ enum devlink_attr { DEVLINK_ATTR_MAX = __DEVLINK_ATTR_MAX - 1 }; -#endif /* _UAPI_LINUX_DEVLINK_H_ */ +#endif /* _LINUX_DEVLINK_H_ */ diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 8f3b0f40e..c396f3179 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -92,6 +92,7 @@ #define ETH_P_TDLS 0x890D /* TDLS */ #define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ #define ETH_P_80221 0x8917 /* IEEE 802.21 Media Independent Handover Protocol */ +#define ETH_P_HSR 0x892F /* IEC 62439-3 HSRv1 */ #define ETH_P_LOOPBACK 0x9000 /* Ethernet loopback packet, per IEEE 802.3 */ #define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ #define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ diff --git a/include/linux/if_link.h b/include/linux/if_link.h index e296f2938..0a7abb11f 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -155,6 +155,7 @@ enum { IFLA_PROTO_DOWN, IFLA_GSO_MAX_SEGS, IFLA_GSO_MAX_SIZE, + IFLA_PAD, __IFLA_MAX }; @@ -773,9 +774,33 @@ enum { IFLA_HSR_MULTICAST_SPEC, /* Last byte of supervision addr */ IFLA_HSR_SUPERVISION_ADDR, /* Supervision frame multicast addr */ IFLA_HSR_SEQ_NR, + IFLA_HSR_VERSION, /* HSR version */ __IFLA_HSR_MAX, }; #define IFLA_HSR_MAX (__IFLA_HSR_MAX - 1) +/* STATS section */ + +struct if_stats_msg { + __u8 family; + __u8 pad1; + __u16 pad2; + __u32 ifindex; + __u32 filter_mask; +}; + +/* A stats attribute can be netdev specific or a global stat. + * For netdev stats, lets use the prefix IFLA_STATS_LINK_* + */ +enum { + IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */ + IFLA_STATS_LINK_64, + __IFLA_STATS_MAX, +}; + +#define IFLA_STATS_MAX (__IFLA_STATS_MAX - 1) + +#define IFLA_STATS_FILTER_BIT(ATTR) (1 << (ATTR - 1)) + #endif /* _LINUX_IF_LINK_H */ diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 6aaa2a3e3..ae8b02a50 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -139,6 +139,11 @@ enum { RTM_GETNSID = 90, #define RTM_GETNSID RTM_GETNSID + RTM_NEWSTATS = 92, +#define RTM_NEWSTATS RTM_NEWSTATS + RTM_GETSTATS = 94, +#define RTM_GETSTATS RTM_GETSTATS + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; @@ -312,6 +317,7 @@ enum rtattr_type_t { RTA_ENCAP_TYPE, RTA_ENCAP, RTA_EXPIRES, + RTA_PAD, __RTA_MAX }; From 6df9c7a06a8454db30121b9890ecd5a544f9710e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 21 Apr 2016 05:19:04 -0700 Subject: [PATCH 209/513] ss: add SK_MEMINFO_DROPS display SK_MEMINFO_DROPS is added in linux-4.7 for TCP, UDP and SCTP skmem will display the socket drop count using d prefix as in : $ ss -tm src :22 | more State Recv-Q Send-Q Local Address:Port Peer Address:Port ESTAB 0 52 10.246.7.151:ssh 172.20.10.101:50759 skmem:(r0,rb8388608,t0,tb8388608,f1792,w2304,o0,bl0,d0) Signed-off-by: Eric Dumazet --- misc/ss.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/misc/ss.c b/misc/ss.c index deefc9676..3258584b2 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -1905,6 +1905,10 @@ static void print_skmeminfo(struct rtattr *tb[], int attrtype) (SK_MEMINFO_BACKLOG + 1) * sizeof(__u32)) printf(",bl%u", skmeminfo[SK_MEMINFO_BACKLOG]); + if (RTA_PAYLOAD(tb[attrtype]) >= + (SK_MEMINFO_DROPS + 1) * sizeof(__u32)) + printf(",d%u", skmeminfo[SK_MEMINFO_DROPS]); + printf(")"); } From b76b93ddac7ac559f3842e6386cda32120e4b912 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 24 Apr 2016 22:30:46 -0700 Subject: [PATCH 210/513] update kernel headers from net-next --- include/linux/fib_rules.h | 1 + include/linux/l2tp.h | 1 + include/linux/lwtunnel.h | 2 ++ include/linux/neighbour.h | 2 ++ include/linux/tcp_metrics.h | 1 + include/linux/xfrm.h | 1 + 6 files changed, 8 insertions(+) diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index 96161b820..620c8a5dd 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h @@ -49,6 +49,7 @@ enum { FRA_TABLE, /* Extended table id */ FRA_FWMASK, /* mask for netfilter mark */ FRA_OIFNAME, + FRA_PAD, __FRA_MAX }; diff --git a/include/linux/l2tp.h b/include/linux/l2tp.h index 5b0e36d0f..9ca4d0cff 100644 --- a/include/linux/l2tp.h +++ b/include/linux/l2tp.h @@ -124,6 +124,7 @@ enum { L2TP_ATTR_IP6_DADDR, /* struct in6_addr */ L2TP_ATTR_UDP_ZERO_CSUM6_TX, /* u8 */ L2TP_ATTR_UDP_ZERO_CSUM6_RX, /* u8 */ + L2TP_ATTR_PAD, __L2TP_ATTR_MAX, }; diff --git a/include/linux/lwtunnel.h b/include/linux/lwtunnel.h index 1d2f4f6cc..7cea3cbfa 100644 --- a/include/linux/lwtunnel.h +++ b/include/linux/lwtunnel.h @@ -22,6 +22,7 @@ enum lwtunnel_ip_t { LWTUNNEL_IP_TTL, LWTUNNEL_IP_TOS, LWTUNNEL_IP_FLAGS, + LWTUNNEL_IP_PAD, __LWTUNNEL_IP_MAX, }; @@ -35,6 +36,7 @@ enum lwtunnel_ip6_t { LWTUNNEL_IP6_HOPLIMIT, LWTUNNEL_IP6_TC, LWTUNNEL_IP6_FLAGS, + LWTUNNEL_IP6_PAD, __LWTUNNEL_IP6_MAX, }; diff --git a/include/linux/neighbour.h b/include/linux/neighbour.h index 788655bfa..bd99a8d80 100644 --- a/include/linux/neighbour.h +++ b/include/linux/neighbour.h @@ -128,6 +128,7 @@ enum { NDTPA_LOCKTIME, /* u64, msecs */ NDTPA_QUEUE_LENBYTES, /* u32 */ NDTPA_MCAST_REPROBES, /* u32 */ + NDTPA_PAD, __NDTPA_MAX }; #define NDTPA_MAX (__NDTPA_MAX - 1) @@ -160,6 +161,7 @@ enum { NDTA_PARMS, /* nested TLV NDTPA_* */ NDTA_STATS, /* struct ndt_stats, read-only */ NDTA_GC_INTERVAL, /* u64, msecs */ + NDTA_PAD, __NDTA_MAX }; #define NDTA_MAX (__NDTA_MAX - 1) diff --git a/include/linux/tcp_metrics.h b/include/linux/tcp_metrics.h index 935339260..80ad90d0c 100644 --- a/include/linux/tcp_metrics.h +++ b/include/linux/tcp_metrics.h @@ -40,6 +40,7 @@ enum { TCP_METRICS_ATTR_FOPEN_COOKIE, /* binary */ TCP_METRICS_ATTR_SADDR_IPV4, /* u32 */ TCP_METRICS_ATTR_SADDR_IPV6, /* binary */ + TCP_METRICS_ATTR_PAD, __TCP_METRICS_ATTR_MAX, }; diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index b8f54510d..d09be24e0 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -302,6 +302,7 @@ enum xfrm_attr_type_t { XFRMA_SA_EXTRA_FLAGS, /* __u32 */ XFRMA_PROTO, /* __u8 */ XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */ + XFRMA_PAD, __XFRMA_MAX #define XFRMA_MAX (__XFRMA_MAX - 1) From 27d44f3a8a4708bcc99995a4d9b6fe6f81e3e15b Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Tue, 3 May 2016 09:39:08 +0200 Subject: [PATCH 211/513] tc: add bash-completion function Add function for command completion for tc in bash, and update Makefile to install it under /usr/share/bash-completion/completions/. Inside iproute2 repository, the completion code is in a new `bash-completion` toplevel directory. v2: Remove `if` statement in Makefile: do not try to install in /etc/bash_completion.d/ if /usr/share/bash-completion/completions/ is not found; instead, the user can override the installation path with the specific environment variable. Signed-off-by: Quentin Monnet --- Makefile | 3 + bash-completion/tc | 723 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 726 insertions(+) create mode 100644 bash-completion/tc diff --git a/Makefile b/Makefile index 0190aa004..eb571a5ac 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ DOCDIR?=$(DATADIR)/doc/iproute2 MANDIR?=$(DATADIR)/man ARPDDIR?=/var/lib/arpd KERNEL_INCLUDE?=/usr/include +BASH_COMPDIR?=$(DATADIR)/bash-completion/completions # Path to db_185.h include DBM_INCLUDE:=$(DESTDIR)/usr/include @@ -66,6 +67,8 @@ install: all $(DESTDIR)$(DOCDIR)/examples/diffserv @for i in $(SUBDIRS) doc; do $(MAKE) -C $$i install; done install -m 0644 $(shell find etc/iproute2 -maxdepth 1 -type f) $(DESTDIR)$(CONFDIR) + install -m 0755 -d $(DESTDIR)$(BASH_COMPDIR) + install -m 0644 bash-completion/tc $(DESTDIR)$(BASH_COMPDIR) snapshot: echo "static const char SNAPSHOT[] = \""`date +%y%m%d`"\";" \ diff --git a/bash-completion/tc b/bash-completion/tc new file mode 100644 index 000000000..79dd5fcc1 --- /dev/null +++ b/bash-completion/tc @@ -0,0 +1,723 @@ +# tc(8) completion -*- shell-script -*- +# Copyright 2016 6WIND S.A. +# Copyright 2016 Quentin Monnet + +# Takes a list of words in argument; each one of them is added to COMPREPLY if +# it is not already present on the command line. Returns no value. +_tc_once_attr() +{ + local w subcword found + for w in $*; do + found=0 + for (( subcword=3; subcword < ${#words[@]}-1; subcword++ )); do + if [[ $w == ${words[subcword]} ]]; then + found=1 + break + fi + done + [[ $found -eq 0 ]] && \ + COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) ) + done +} + +# Takes a list of words in argument; adds them all to COMPREPLY if none of them +# is already present on the command line. Returns no value. +_tc_one_of_list() +{ + local w subcword + for w in $*; do + for (( subcword=3; subcword < ${#words[@]}-1; subcword++ )); do + [[ $w == ${words[subcword]} ]] && return 1 + done + done + COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) ) +} + +# Returns "$cur ${cur}arg1 ${cur}arg2 ..." +_tc_expand_units() +{ + [[ $cur =~ ^[0-9]+ ]] || return 1 + local value=${cur%%[^0-9]*} + [[ $cur == $value ]] && echo $cur + echo ${@/#/$value} +} + +# Complete based on given word, usually $prev (or possibly the word before), +# for when an argument or an option name has but a few possible arguments (so +# tc does not take particular commands into account here). +# Returns 0 is completion should stop after running this function, 1 otherwise. +_tc_direct_complete() +{ + case $1 in + # Command options + dev) + _available_interfaces + return 0 + ;; + classid) + return 0 + ;; + estimator) + local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' ) + COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) + return 0 + ;; + handle) + return 0 + ;; + parent|flowid) + local i iface ids cmd + for (( i=3; i < ${#words[@]}-2; i++ )); do + [[ ${words[i]} == dev ]] && iface=${words[i+1]} + break + done + for cmd in qdisc class; do + if [[ -n $iface ]]; then + ids+=$( tc $cmd show dev $iface 2>/dev/null | \ + cut -d\ -f 3 )" " + else + ids+=$( tc $cmd show 2>/dev/null | cut -d\ -f 3 ) + fi + done + [[ $ids != " " ]] && \ + COMPREPLY+=( $( compgen -W "$ids" -- "$cur" ) ) + return 0 + ;; + protocol) # list comes from lib/ll_proto.c + COMPREPLY+=( $( compgen -W ' 802.1Q 802.1ad 802_2 802_3 LLDP aarp \ + all aoe arp atalk atmfate atmmpoa ax25 bpq can control cust \ + ddcmp dec diag dna_dl dna_rc dna_rt econet ieeepup ieeepupat \ + ip ipv4 ipv6 ipx irda lat localtalk loop mobitex ppp_disc \ + ppp_mp ppp_ses ppptalk pup pupat rarp sca snap tipc tr_802_2 \ + wan_ppp x25' -- "$cur" ) ) + return 0 + ;; + prio) + return 0 + ;; + stab) + COMPREPLY+=( $( compgen -W 'mtu tsize mpu overhead + linklayer' -- "$cur" ) ) + ;; + + # Qdiscs and classes options + alpha|bands|beta|buckets|corrupt|debug|decrement|default|\ + default_index|depth|direct_qlen|divisor|duplicate|ewma|flow_limit|\ + flows|hh_limit|increment|indices|linklayer|non_hh_weight|num_tc|\ + penalty_burst|penalty_rate|prio|priomap|probability|queues|r2q|\ + reorder|vq|vqs) + return 0 + ;; + setup) + COMPREPLY+=( $( compgen -W 'vqs' -- "$cur" ) ) + return 0 + ;; + hw) + COMPREPLY+=( $( compgen -W '1 0' -- "$cur" ) ) + return 0 + ;; + distribution) + COMPREPLY+=( $( compgen -W 'uniform normal pareto + paretonormal' -- "$cur" ) ) + return 0 + ;; + loss) + COMPREPLY+=( $( compgen -W 'random state gmodel' -- "$cur" ) ) + return 0 + ;; + + # Qdiscs and classes options options + gap|gmodel|state) + return 0 + ;; + + # Filters options + map) + COMPREPLY+=( $( compgen -W 'key' -- "$cur" ) ) + return 0 + ;; + hash) + COMPREPLY+=( $( compgen -W 'keys' -- "$cur" ) ) + return 0 + ;; + indev) + _available_interfaces + return 0 + ;; + eth_type) + COMPREPLY+=( $( compgen -W 'ipv4 ipv6' -- "$cur" ) ) + return 0 + ;; + ip_proto) + COMPREPLY+=( $( compgen -W 'tcp udp' -- "$cur" ) ) + return 0 + ;; + + # Filters options options + key|keys) + [[ ${words[@]} =~ graft ]] && return 1 + COMPREPLY+=( $( compgen -W 'src dst proto proto-src proto-dst iif \ + priority mark nfct nfct-src nfct-dst nfct-proto-src \ + nfct-proto-dst rt-classid sk-uid sk-gid vlan-tag rxhash' -- \ + "$cur" ) ) + return 0 + ;; + + # BPF options - used for filters, actions, and exec + export|bytecode|bytecode-file|object-file) + _filedir + return 0 + ;; + object-pinned|graft) # Pinned object is probably under /sys/fs/bpf/ + [[ -n "$cur" ]] && _filedir && return 0 + COMPREPLY=( $( compgen -G "/sys/fs/bpf/*" -- "$cur" ) ) || _filedir + compopt -o nospace + return 0 + ;; + section) + if (type objdump > /dev/null 2>&1) ; then + local fword objfile section_list + for (( fword=3; fword < ${#words[@]}-3; fword++ )); do + if [[ ${words[fword]} == object-file ]]; then + objfile=${words[fword+1]} + break + fi + done + section_list=$( objdump -h $objfile 2>/dev/null | \ + sed -n 's/^ *[0-9]\+ \([^ ]*\) *.*/\1/p' ) + COMPREPLY+=( $( compgen -W "$section_list" -- "$cur" ) ) + fi + return 0 + ;; + import|run) + _filedir + return 0 + ;; + type) + COMPREPLY+=( $( compgen -W 'cls act' -- "$cur" ) ) + return 0 + ;; + + # Actions options + random) + _tc_one_of_list 'netrand determ' + return 0 + ;; + + # Units for option arguments + bandwidth|maxrate|peakrate|rate) + local list=$( _tc_expand_units 'bit' \ + 'kbit' 'kibit' 'kbps' 'kibps' \ + 'mbit' 'mibit' 'mbps' 'mibps' \ + 'gbit' 'gibit' 'gbps' 'gibps' \ + 'tbit' 'tibit' 'tbps' 'tibps' ) + COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) + ;; + admit_bytes|avpkt|burst|cell|initial_quantum|limit|max|min|mtu|mpu|\ + overhead|quantum|redflowlist) + local list=$( _tc_expand_units \ + 'b' 'kbit' 'k' 'mbit' 'm' 'gbit' 'g' ) + COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) + ;; + db|delay|evict_timeout|interval|latency|perturb|rehash|reset_timeout|\ + target|tupdate) + local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' ) + COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) + ;; + esac + return 1 +} + +# Complete with options names for qdiscs. Each qdisc has its own set of options +# and it seems we cannot really parse it from anywhere, so we add it manually +# in this function. +# Returns 0 is completion should stop after running this function, 1 otherwise. +_tc_qdisc_options() +{ + case $1 in + choke) + _tc_once_attr 'limit bandwidth ecn min max burst' + return 0 + ;; + codel) + _tc_once_attr 'limit target interval' + _tc_one_of_list 'ecn noecn' + return 0 + ;; + bfifo|pfifo|pfifo_head_drop) + _tc_once_attr 'limit' + return 0 + ;; + fq) + _tc_once_attr 'limit flow_limit quantum initial_quantum maxrate \ + buckets' + _tc_one_of_list 'pacing nopacing' + return 0 + ;; + fq_codel) + _tc_once_attr 'limit flows target interval quantum' + _tc_one_of_list 'ecn noecn' + return 0 + ;; + gred) + _tc_once_attr 'setup vqs default grio vq prio limit min max avpkt \ + burst probability bandwidth' + return 0 + ;; + hhf) + _tc_once_attr 'limit quantum hh_limit reset_timeout admit_bytes \ + evict_timeout non_hh_weight' + return 0 + ;; + mqprio) + _tc_once_attr 'num_tc map queues hw' + return 0 + ;; + netem) + _tc_once_attr 'delay distribution corrupt duplicate loss ecn \ + reorder rate' + return 0 + ;; + pie) + _tc_once_attr 'limit target tupdate alpha beta' + _tc_one_of_list 'bytemode nobytemode' + _tc_one_of_list 'ecn noecn' + return 0 + ;; + red) + _tc_once_attr 'limit min max avpkt burst adaptive probability \ + bandwidth ecn harddrop' + return 0 + ;; + rr|prio) + _tc_once_attr 'bands priomap multiqueue' + return 0 + ;; + sfb) + _tc_once_attr 'rehash db limit max target increment decrement \ + penalty_rate penalty_burst' + return 0 + ;; + sfq) + _tc_once_attr 'limit perturb quantum divisor flows depth headdrop \ + redflowlimit min max avpkt burst probability ecn harddrop' + return 0 + ;; + tbf) + _tc_once_attr 'limit burst rate mtu peakrate latency overhead \ + linklayer' + return 0 + ;; + cbq) + _tc_once_attr 'bandwidth avpkt mpu cell ewma' + return 0 + ;; + dsmark) + _tc_once_attr 'indices default_index set_tc_index' + return 0 + ;; + hfsc) + _tc_once_attr 'default' + return 0 + ;; + htb) + _tc_once_attr 'default r2q direct_qlen debug' + return 0 + ;; + multiq|pfifo_fast|atm|drr|qfq) + return 0 + ;; + esac + return 1 +} + +# Complete with options names for BPF filters or actions. +# Returns 0 is completion should stop after running this function, 1 otherwise. +_tc_bpf_options() +{ + [[ ${words[${#words[@]}-3]} == object-file ]] && \ + _tc_once_attr 'section export' + [[ ${words[${#words[@]}-5]} == object-file ]] && \ + [[ ${words[${#words[@]}-3]} =~ (section|export) ]] && \ + _tc_once_attr 'section export' + _tc_one_of_list 'bytecode bytecode-file object-file object-pinned' + _tc_once_attr 'verbose index direct-action action classid' + return 0 +} + +# Complete with options names for filters. +# Returns 0 is completion should stop after running this function, 1 otherwise. +_tc_filter_options() +{ + case $1 in + basic) + _tc_once_attr 'match action classid' + return 0 + ;; + bpf) + _tc_bpf_options + return 0 + ;; + cgroup) + _tc_once_attr 'match action' + return 0 + ;; + flow) + local i + for (( i=5; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} =~ ^keys?$ ]]; then + _tc_direct_complete 'key' + COMPREPLY+=( $( compgen -W 'or and xor rshift addend' -- \ + "$cur" ) ) + break + fi + done + _tc_once_attr 'map hash divisor baseclass match action' + return 0 + ;; + flower) + _tc_once_attr 'action classid indev dst_mac src_mac eth_type \ + ip_proto dst_ip src_ip dst_port src_port' + return 0 + ;; + fw) + _tc_once_attr 'action classid' + return 0 + ;; + route) + _tc_one_of_list 'from fromif' + _tc_once_attr 'to classid action' + return 0 + ;; + rsvp) + _tc_once_attr 'ipproto session sender classid action tunnelid \ + tunnel flowlabel spi/ah spi/esp u8 u16 u32' + [[ ${words[${#words[@]}-3]} == tunnel ]] && \ + COMPREPLY+=( $( compgen -W 'skip' -- "$cur" ) ) + [[ ${words[${#words[@]}-3]} =~ u(8|16|32) ]] && \ + COMPREPLY+=( $( compgen -W 'mask' -- "$cur" ) ) + [[ ${words[${#words[@]}-3]} == mask ]] && \ + COMPREPLY+=( $( compgen -W 'at' -- "$cur" ) ) + return 0 + ;; + tcindex) + _tc_once_attr 'hash mask shift classid action' + _tc_one_of_list 'pass_on fall_through' + return 0 + ;; + u32) + _tc_once_attr 'match link classid action offset ht hashkey sample' + COMPREPLY+=( $( compgen -W 'ip ip6 udp tcp icmp u8 u16 u32 mark \ + divisor' -- "$cur" ) ) + return 0 + ;; + esac + return 1 +} + +# Complete with options names for actions. +# Returns 0 is completion should stop after running this function, 1 otherwise. +_tc_action_options() +{ + case $1 in + bpf) + _tc_bpf_options + return 0 + ;; + mirred) + _tc_one_of_list 'ingress egress' + _tc_one_of_list 'mirror redirect' + _tc_once_attr 'index dev' + return 0 + ;; + gact) + _tc_one_of_list 'reclassify drop continue pass' + _tc_once_attr 'random' + return 0 + ;; + esac + return 1 +} + +# Complete with options names for exec. +# Returns 0 is completion should stop after running this function, 1 otherwise. +_tc_exec_options() +{ + case $1 in + import) + [[ ${words[${#words[@]}-3]} == import ]] && \ + _tc_once_attr 'run' + return 0 + ;; + graft) + COMPREPLY+=( $( compgen -W 'key type' -- "$cur" ) ) + [[ ${words[${#words[@]}-3]} == object-file ]] && \ + _tc_once_attr 'type' + _tc_bpf_options + return 0 + ;; + esac + return 1 +} + +# Main completion function +# Logic is as follows: +# 1. Check if previous word is a global option; if so, propose arguments. +# 2. Check if current word is a global option; if so, propose completion. +# 3. Check for the presence of a main command (qdisc|class|filter|...). If +# there is one, first call _tc_direct_complete to see if previous word is +# waiting for a particular completion. If so, propose completion and exit. +# 4. Extract main command and -- if available -- its subcommand +# (add|delete|show|...). +# 5. Propose completion based on main and sub- command in use. Additional +# functions may be called for qdiscs, classes or filter options. +_tc() +{ + local cur prev words cword + _init_completion || return + + case $prev in + -V|-Version) + return 0 + ;; + -b|-batch|-cf|-conf) + _filedir + return 0 + ;; + -force) + COMPREPLY=( $( compgen -W '-batch' -- "$cur" ) ) + return 0 + ;; + -nm|name) + [[ -r /etc/iproute2/tc_cls ]] || \ + COMPREPLY=( $( compgen -W '-conf' -- "$cur" ) ) + return 0 + ;; + -n|-net|-netns) + local nslist=$( ip netns list 2>/dev/null ) + COMPREPLY+=( $( compgen -W "$nslist" -- "$cur" ) ) + return 0 + ;; + -tshort) + _tc_once_attr '-statistics' + COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) ) + return 0 + ;; + -timestamp) + _tc_once_attr '-statistics -tshort' + COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) ) + return 0 + ;; + esac + + # Search for main commands + local subcword cmd subcmd + for (( subcword=1; subcword < ${#words[@]}-1; subcword++ )); do + [[ ${words[subcword]} == -b?(atch) ]] && return 0 + [[ -n $cmd ]] && subcmd=${words[subcword]} && break + [[ ${words[subcword]} != -* && \ + ${words[subcword-1]} != -@(n?(et?(ns))|c?(on)f) ]] && \ + cmd=${words[subcword]} + done + + if [[ -z $cmd ]]; then + case $cur in + -*) + local c='-Version -statistics -details -raw -pretty \ + -iec -graphe -batch -name -netns -timestamp' + [[ $cword -eq 1 ]] && c+=' -force' + COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) + return 0 + ;; + *) + COMPREPLY=( $( compgen -W "help $( tc help 2>&1 | \ + command sed \ + -e '/OBJECT := /!d' \ + -e 's/.*{//' \ + -e 's/}.*//' \ + -e \ 's/|//g' )" -- "$cur" ) ) + return 0 + ;; + esac + fi + + [[ $subcmd == help ]] && return 0 + + # For this set of commands we may create COMPREPLY just by analysing the + # previous word, if it expects for a specific list of options or values. + if [[ $cmd =~ (qdisc|class|filter|action|exec) ]]; then + _tc_direct_complete $prev && return 0 + if [[ ${words[${#words[@]}-3]} == estimator ]]; then + local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' ) + COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) && return 0 + fi + fi + + # Completion depends on main command and subcommand in use. + case $cmd in + qdisc) + case $subcmd in + add|change|replace|link|del|delete) + if [[ $(($cword-$subcword)) -eq 1 ]]; then + COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) ) + return 0 + fi + local qdisc qdwd QDISC_KIND=' choke codel bfifo pfifo \ + pfifo_head_drop fq fq_codel gred hhf mqprio multiq \ + netem pfifo_fast pie red rr sfb sfq tbf atm cbq drr \ + dsmark hfsc htb prio qfq ' + for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do + if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then + qdisc=${words[qdwd]} + _tc_qdisc_options $qdisc && return 0 + fi + done + _tc_one_of_list $QDISC_KIND + _tc_one_of_list 'root ingress parent clsact' + _tc_once_attr 'handle estimator stab' + ;; + show) + _tc_once_attr 'dev' + _tc_one_of_list 'ingress clsact' + _tc_once_attr '-statistics -details -raw -pretty -iec \ + -graph -name' + ;; + help) + return 0 + ;; + *) + [[ $cword -eq $subcword ]] && \ + COMPREPLY=( $( compgen -W 'help add delete change \ + replace link show' -- "$cur" ) ) + ;; + esac + ;; + + class) + case $subcmd in + add|change|replace|del|delete) + if [[ $(($cword-$subcword)) -eq 1 ]]; then + COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) ) + return 0 + fi + local qdisc qdwd QDISC_KIND=' choke codel bfifo pfifo \ + pfifo_head_drop fq fq_codel gred hhf mqprio multiq \ + netem pfifo_fast pie red rr sfb sfq tbf atm cbq drr \ + dsmark hfsc htb prio qfq ' + for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do + if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then + qdisc=${words[qdwd]} + _tc_qdisc_options $qdisc && return 0 + fi + done + _tc_one_of_list $QDISC_KIND + _tc_one_of_list 'root parent' + _tc_once_attr 'classid' + ;; + show) + _tc_once_attr 'dev' + _tc_one_of_list 'root parent' + _tc_once_attr '-statistics -details -raw -pretty -iec \ + -graph -name' + ;; + help) + return 0 + ;; + *) + [[ $cword -eq $subcword ]] && \ + COMPREPLY=( $( compgen -W 'help add delete change \ + replace show' -- "$cur" ) ) + ;; + esac + ;; + + filter) + case $subcmd in + add|change|replace|del|delete) + if [[ $(($cword-$subcword)) -eq 1 ]]; then + COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) ) + return 0 + fi + local filter fltwd FILTER_KIND=' basic bpf cgroup flow \ + flower fw route rsvp tcindex u32 ' + for ((fltwd=$subcword; fltwd < ${#words[@]}-1; fltwd++)); + do + if [[ $FILTER_KIND =~ ' '${words[fltwd]}' ' ]]; then + filter=${words[fltwd]} + _tc_filter_options $filter && return 0 + fi + done + _tc_one_of_list $FILTER_KIND + _tc_one_of_list 'root ingress egress parent' + _tc_once_attr 'handle estimator pref protocol' + ;; + show) + _tc_once_attr 'dev' + _tc_one_of_list 'root ingress egress parent' + _tc_once_attr '-statistics -details -raw -pretty -iec \ + -graph -name' + ;; + help) + return 0 + ;; + *) + [[ $cword -eq $subcword ]] && \ + COMPREPLY=( $( compgen -W 'help add delete change \ + replace show' -- "$cur" ) ) + ;; + esac + ;; + + action) + case $subcmd in + add|change|replace) + local action acwd ACTION_KIND=' gact mirred bpf ' + for ((acwd=$subcword; acwd < ${#words[@]}-1; acwd++)); do + if [[ $ACTION_KIND =~ ' '${words[acwd]}' ' ]]; then + action=${words[acwd]} + _tc_action_options $action && return 0 + fi + done + _tc_one_of_list $ACTION_KIND + ;; + get|del|delete) + _tc_once_attr 'index' + ;; + lst|list|flush|show) + _tc_one_of_list $ACTION_KIND + ;; + *) + [[ $cword -eq $subcword ]] && \ + COMPREPLY=( $( compgen -W 'help add delete change \ + replace show list flush action' -- "$cur" ) ) + ;; + esac + ;; + + monitor) + COMPREPLY=( $( compgen -W 'help' -- "$cur" ) ) + ;; + + exec) + case $subcmd in + bpf) + local excmd exwd EXEC_KIND=' import debug graft ' + for ((exwd=$subcword; exwd < ${#words[@]}-1; exwd++)); do + if [[ $EXEC_KIND =~ ' '${words[exwd]}' ' ]]; then + excmd=${words[exwd]} + _tc_exec_options $excmd && return 0 + fi + done + _tc_one_of_list $EXEC_KIND + ;; + *) + [[ $cword -eq $subcword ]] && \ + COMPREPLY=( $( compgen -W 'bpf' -- "$cur" ) ) + ;; + esac + ;; + esac +} && +complete -F _tc tc + +# ex: ts=4 sw=4 et filetype=sh From df217d5d5ccc25e564acf94935ab5d74443fe69b Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Wed, 27 Apr 2016 16:11:13 +0200 Subject: [PATCH 212/513] ip link gre: create interfaces in external mode correctly For GRE interfaces in 'external' mode, the kernel ignores all manual settings like remote IP address or TTL. However, for some of those attributes, kernel checks their value and does not allow them to be zero (even though they're ignored later). Currently, 'ip link' always includes all attributes in the netlink message. This leads to problem with creating interfaces in 'external' mode. For example, this command does not work: ip link add gre1 type gretap external and needs a bogus remote IP address to be specified, as the kernel enforces remote IP address to be either not present, or not null. Ignore the parameters that do not make sense in 'external' mode. Unfortunately, we cannot error out, as there may be existing deployments that workarounded the bug by specifying bogus values. Fixes: 926b39e1feffd ("gre: add support for collect metadata flag") Signed-off-by: Jiri Benc --- ip/link_gre.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/ip/link_gre.c b/ip/link_gre.c index bcf003aaa..36ce12526 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -315,24 +315,26 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, return -1; } - addattr32(n, 1024, IFLA_GRE_IKEY, ikey); - addattr32(n, 1024, IFLA_GRE_OKEY, okey); - addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2); - addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2); - addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4); - addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4); - addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1); - if (link) - addattr32(n, 1024, IFLA_GRE_LINK, link); - addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1); - addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1); + if (!metadata) { + addattr32(n, 1024, IFLA_GRE_IKEY, ikey); + addattr32(n, 1024, IFLA_GRE_OKEY, okey); + addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2); + addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2); + addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4); + addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4); + addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1); + if (link) + addattr32(n, 1024, IFLA_GRE_LINK, link); + addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1); + addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1); + } else { + addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0); + } addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype); addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags); addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport)); addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport)); - if (metadata) - addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0); return 0; } From 7c337e2c20cac3ec85fb011617d4d281fde912b3 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Wed, 27 Apr 2016 16:11:14 +0200 Subject: [PATCH 213/513] ip link gre: print only relevant info in external mode Display only attributes that are relevant when a GRE interface is in 'external' mode instead of the default values (which are ignored by the kernel even if passed back). Fixes: 926b39e1feffd ("gre: add support for collect metadata flag") Signed-off-by: Jiri Benc --- ip/link_gre.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ip/link_gre.c b/ip/link_gre.c index 36ce12526..492c22053 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -339,7 +339,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, return 0; } -static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) +static void gre_print_direct_opt(FILE *f, struct rtattr *tb[]) { char s2[64]; const char *local = "any"; @@ -347,9 +347,6 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) unsigned int iflags = 0; unsigned int oflags = 0; - if (!tb) - return; - if (tb[IFLA_GRE_REMOTE]) { unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_REMOTE]); @@ -421,8 +418,16 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fputs("icsum ", f); if (oflags & GRE_CSUM) fputs("ocsum ", f); +} - if (tb[IFLA_GRE_COLLECT_METADATA]) +static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) +{ + if (!tb) + return; + + if (!tb[IFLA_GRE_COLLECT_METADATA]) + gre_print_direct_opt(f, tb); + else fputs("external ", f); if (tb[IFLA_GRE_ENCAP_TYPE] && From 2642b6b03e546b04e163a7cb2585ece791324a05 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 6 May 2016 15:28:25 +0100 Subject: [PATCH 214/513] geneve: fix IPv6 remote address reporting Since we can only configure unicast, we probably want to be able to display unicast, rather than multicast. Fixes: 906ac5437ab8 ("geneve: add support for IPv6 link partners") Signed-off-by: Edward Cree --- ip/iplink_geneve.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c index 84d948fc7..65af6b35e 100644 --- a/ip/iplink_geneve.c +++ b/ip/iplink_geneve.c @@ -204,7 +204,7 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) memcpy(&addr, RTA_DATA(tb[IFLA_GENEVE_REMOTE6]), sizeof(struct in6_addr)); if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) { - if (IN6_IS_ADDR_MULTICAST(&addr)) + if (!IN6_IS_ADDR_MULTICAST(&addr)) fprintf(f, "remote %s ", format_host(AF_INET6, sizeof(struct in6_addr), &addr)); } From c3d25ec3924ad4a90d04112f8da8846201f0b138 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 May 2016 14:38:38 -0700 Subject: [PATCH 215/513] Revert "devlink: implement shared buffer occupancy control" This reverts commit a60ebcb6f34f4c43cba092f52b1150d7fb1deec5. --- devlink/devlink.c | 349 ---------------------------------------- include/linux/devlink.h | 6 - 2 files changed, 355 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index ffefa86d2..228807f88 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -27,12 +27,6 @@ #define pr_err(args...) fprintf(stderr, ##args) #define pr_out(args...) fprintf(stdout, ##args) -#define pr_out_sp(num, args...) \ - do { \ - int ret = fprintf(stdout, ##args); \ - if (ret < num) \ - fprintf(stdout, "%*s", num - ret, ""); \ - } while (0) static int _mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data) @@ -281,12 +275,6 @@ static int attr_cb(const struct nlattr *attr, void *data) if (type == DEVLINK_ATTR_SB_TC_INDEX && mnl_attr_validate(attr, MNL_TYPE_U16) < 0) return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_OCC_CUR && - mnl_attr_validate(attr, MNL_TYPE_U32) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_OCC_MAX && - mnl_attr_validate(attr, MNL_TYPE_U32) < 0) - return MNL_CB_ERROR; tb[type] = attr; return MNL_CB_OK; } @@ -876,7 +864,6 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME]; struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME]; struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX]; - struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX]; if (opts->present & DL_OPT_HANDLE && attr_bus_name && attr_dev_name) { @@ -898,12 +885,6 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) port_index != opts->port_index) return false; } - if (opts->present & DL_OPT_SB && attr_sb_index) { - uint32_t sb_index = mnl_attr_get_u32(attr_sb_index); - - if (sb_index != opts->sb_index) - return false; - } return true; } @@ -1187,9 +1168,6 @@ static void cmd_sb_help(void) pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); pr_out(" type { ingress | egress } pool POOL_INDEX\n"); pr_out(" th THRESHOLD\n"); - pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); - pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); - pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); } static void pr_out_sb(struct nlattr **tb) @@ -1526,330 +1504,6 @@ static int cmd_sb_tc(struct dl *dl) return -ENOENT; } -struct occ_item { - struct list_head list; - uint32_t index; - uint32_t cur; - uint32_t max; - uint32_t bound_pool_index; -}; - -struct occ_port { - struct list_head list; - char *bus_name; - char *dev_name; - uint32_t port_index; - uint32_t sb_index; - struct list_head pool_list; - struct list_head ing_tc_list; - struct list_head eg_tc_list; -}; - -struct occ_show { - struct dl *dl; - int err; - struct list_head port_list; -}; - -static struct occ_item *occ_item_alloc(void) -{ - return calloc(1, sizeof(struct occ_item)); -} - -static void occ_item_free(struct occ_item *occ_item) -{ - free(occ_item); -} - -static struct occ_port *occ_port_alloc(uint32_t port_index) -{ - struct occ_port *occ_port; - - occ_port = calloc(1, sizeof(*occ_port)); - if (!occ_port) - return NULL; - occ_port->port_index = port_index; - INIT_LIST_HEAD(&occ_port->pool_list); - INIT_LIST_HEAD(&occ_port->ing_tc_list); - INIT_LIST_HEAD(&occ_port->eg_tc_list); - return occ_port; -} - -static void occ_port_free(struct occ_port *occ_port) -{ - struct occ_item *occ_item, *tmp; - - list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list) - occ_item_free(occ_item); - list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list) - occ_item_free(occ_item); - list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list) - occ_item_free(occ_item); -} - -static struct occ_show *occ_show_alloc(struct dl *dl) -{ - struct occ_show *occ_show; - - occ_show = calloc(1, sizeof(*occ_show)); - if (!occ_show) - return NULL; - occ_show->dl = dl; - INIT_LIST_HEAD(&occ_show->port_list); - return occ_show; -} - -static void occ_show_free(struct occ_show *occ_show) -{ - struct occ_port *occ_port, *tmp; - - list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list) - occ_port_free(occ_port); -} - -static struct occ_port *occ_port_get(struct occ_show *occ_show, - struct nlattr **tb) -{ - struct occ_port *occ_port; - uint32_t port_index; - - port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); - - list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) { - if (occ_port->port_index == port_index) - return occ_port; - } - occ_port = occ_port_alloc(port_index); - if (!occ_port) - return NULL; - list_add_tail(&occ_port->list, &occ_show->port_list); - return occ_port; -} - -static void pr_out_occ_show_item_list(const char *label, struct list_head *list, - bool bound_pool) -{ - struct occ_item *occ_item; - int i = 1; - - pr_out_sp(7, " %s:", label); - list_for_each_entry(occ_item, list, list) { - if ((i - 1) % 4 == 0 && i != 1) - pr_out_sp(7, " "); - if (bound_pool) - pr_out_sp(7, "%2u(%u):", occ_item->index, - occ_item->bound_pool_index); - else - pr_out_sp(7, "%2u:", occ_item->index); - pr_out_sp(15, "%7u/%u", occ_item->cur, occ_item->max); - if (i++ % 4 == 0) - pr_out("\n"); - } - if ((i - 1) % 4 != 0) - pr_out("\n"); -} - -static void pr_out_occ_show_port(struct occ_port *occ_port) -{ - pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); - pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); - pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); -} - -static void pr_out_occ_show(struct occ_show *occ_show) -{ - struct dl *dl = occ_show->dl; - struct dl_opts *opts = &dl->opts; - struct occ_port *occ_port; - - list_for_each_entry(occ_port, &occ_show->port_list, list) { - __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name, - occ_port->port_index); - pr_out(":\n"); - pr_out_occ_show_port(occ_port); - } -} - -static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show, - struct nlattr **tb) -{ - struct occ_port *occ_port; - struct occ_item *occ_item; - - if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) - return; - - occ_port = occ_port_get(occ_show, tb); - if (!occ_port) { - occ_show->err = -ENOMEM; - return; - } - - occ_item = occ_item_alloc(); - if (!occ_item) { - occ_show->err = -ENOMEM; - return; - } - occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); - occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); - occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); - list_add_tail(&occ_item->list, &occ_port->pool_list); -} - -static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data) -{ - struct occ_show *occ_show = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || - !tb[DEVLINK_ATTR_SB_POOL_INDEX] || - !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) - return MNL_CB_ERROR; - cmd_sb_occ_port_pool_process(occ_show, tb); - return MNL_CB_OK; -} - -static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show, - struct nlattr **tb) -{ - struct occ_port *occ_port; - struct occ_item *occ_item; - uint8_t pool_type; - - if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) - return; - - occ_port = occ_port_get(occ_show, tb); - if (!occ_port) { - occ_show->err = -ENOMEM; - return; - } - - occ_item = occ_item_alloc(); - if (!occ_item) { - occ_show->err = -ENOMEM; - return; - } - occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]); - occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); - occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); - occ_item->bound_pool_index = - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); - pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]); - if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS) - list_add_tail(&occ_item->list, &occ_port->ing_tc_list); - else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS) - list_add_tail(&occ_item->list, &occ_port->eg_tc_list); - else - occ_item_free(occ_item); -} - -static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data) -{ - struct occ_show *occ_show = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || - !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || - !tb[DEVLINK_ATTR_SB_POOL_INDEX] || - !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) - return MNL_CB_ERROR; - cmd_sb_occ_tc_pool_process(occ_show, tb); - return MNL_CB_OK; -} - -static int cmd_sb_occ_show(struct dl *dl) -{ - struct nlmsghdr *nlh; - struct occ_show *occ_show; - uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP; - int err; - - err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB); - if (err) - return err; - - occ_show = occ_show_alloc(dl); - if (!occ_show) - return -ENOMEM; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); - - err = _mnlg_socket_sndrcv(dl->nlg, nlh, - cmd_sb_occ_port_pool_process_cb, occ_show); - if (err) - goto out; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); - - err = _mnlg_socket_sndrcv(dl->nlg, nlh, - cmd_sb_occ_tc_pool_process_cb, occ_show); - if (err) - goto out; - - pr_out_occ_show(occ_show); - -out: - occ_show_free(occ_show); - return err; -} - -static int cmd_sb_occ_snapshot(struct dl *dl) -{ - struct nlmsghdr *nlh; - int err; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT, - NLM_F_REQUEST | NLM_F_ACK); - - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); - if (err) - return err; - - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -} - -static int cmd_sb_occ_clearmax(struct dl *dl) -{ - struct nlmsghdr *nlh; - int err; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR, - NLM_F_REQUEST | NLM_F_ACK); - - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); - if (err) - return err; - - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -} - -static int cmd_sb_occ(struct dl *dl) -{ - if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "show") || - dl_argv_match(dl, "list")) { - dl_arg_inc(dl); - return cmd_sb_occ_show(dl); - } else if (dl_argv_match(dl, "snapshot")) { - dl_arg_inc(dl); - return cmd_sb_occ_snapshot(dl); - } else if (dl_argv_match(dl, "clearmax")) { - dl_arg_inc(dl); - return cmd_sb_occ_clearmax(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - static int cmd_sb(struct dl *dl) { if (dl_argv_match(dl, "help")) { @@ -1868,9 +1522,6 @@ static int cmd_sb(struct dl *dl) } else if (dl_argv_match(dl, "tc")) { dl_arg_inc(dl); return cmd_sb_tc(dl); - } else if (dl_argv_match(dl, "occupancy")) { - dl_arg_inc(dl); - return cmd_sb_occ(dl); } pr_err("Command \"%s\" not found\n", dl_argv(dl)); return -ENOENT; diff --git a/include/linux/devlink.h b/include/linux/devlink.h index ba0073b26..9c1aa5783 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -53,10 +53,6 @@ enum devlink_command { DEVLINK_CMD_SB_TC_POOL_BIND_NEW, DEVLINK_CMD_SB_TC_POOL_BIND_DEL, - /* Shared buffer occupancy monitoring commands */ - DEVLINK_CMD_SB_OCC_SNAPSHOT, - DEVLINK_CMD_SB_OCC_MAX_CLEAR, - /* add new commands above here */ __DEVLINK_CMD_MAX, @@ -123,8 +119,6 @@ enum devlink_attr { DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ - DEVLINK_ATTR_SB_OCC_CUR, /* u32 */ - DEVLINK_ATTR_SB_OCC_MAX, /* u32 */ /* add new attributes above here, update the policy in devlink.c */ From 7aca60c0eb73b8d577c2a36be830a82d4cb8f861 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 May 2016 14:38:47 -0700 Subject: [PATCH 216/513] Revert "devlink: implement shared buffer support" This reverts commit b56700bf8add4ebb2fe451c85f50602b58a886a2. --- devlink/devlink.c | 603 +--------------------------------------- include/linux/devlink.h | 57 ---- 2 files changed, 1 insertion(+), 659 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index 228807f88..e2e04136c 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -114,13 +114,6 @@ static void ifname_map_free(struct ifname_map *ifname_map) #define DL_OPT_HANDLEP BIT(1) #define DL_OPT_PORT_TYPE BIT(2) #define DL_OPT_PORT_COUNT BIT(3) -#define DL_OPT_SB BIT(4) -#define DL_OPT_SB_POOL BIT(5) -#define DL_OPT_SB_SIZE BIT(6) -#define DL_OPT_SB_TYPE BIT(7) -#define DL_OPT_SB_THTYPE BIT(8) -#define DL_OPT_SB_TH BIT(9) -#define DL_OPT_SB_TC BIT(10) struct dl_opts { uint32_t present; /* flags of present items */ @@ -129,13 +122,6 @@ struct dl_opts { uint32_t port_index; enum devlink_port_type port_type; uint32_t port_count; - uint32_t sb_index; - uint16_t sb_pool_index; - uint32_t sb_pool_size; - enum devlink_sb_pool_type sb_pool_type; - enum devlink_sb_threshold_type sb_pool_thtype; - uint32_t sb_threshold; - uint16_t sb_tc_index; }; struct dl { @@ -239,42 +225,6 @@ static int attr_cb(const struct nlattr *attr, void *data) if (type == DEVLINK_ATTR_PORT_IBDEV_NAME && mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_INDEX && - mnl_attr_validate(attr, MNL_TYPE_U32) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_SIZE && - mnl_attr_validate(attr, MNL_TYPE_U32) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_INGRESS_POOL_COUNT && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_EGRESS_POOL_COUNT && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_INGRESS_TC_COUNT && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_EGRESS_TC_COUNT && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_POOL_INDEX && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_POOL_TYPE && - mnl_attr_validate(attr, MNL_TYPE_U8) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_POOL_SIZE && - mnl_attr_validate(attr, MNL_TYPE_U32) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE && - mnl_attr_validate(attr, MNL_TYPE_U8) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_THRESHOLD && - mnl_attr_validate(attr, MNL_TYPE_U32) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_TC_INDEX && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; tb[type] = attr; return MNL_CB_OK; } @@ -413,20 +363,6 @@ static int strtouint32_t(const char *str, uint32_t *p_val) return 0; } -static int strtouint16_t(const char *str, uint16_t *p_val) -{ - char *endptr; - unsigned long int val; - - val = strtoul(str, &endptr, 10); - if (endptr == str || *endptr != '\0') - return -EINVAL; - if (val > USHRT_MAX) - return -ERANGE; - *p_val = val; - return 0; -} - static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name) { strslashrsplit(str, p_bus_name, p_dev_name); @@ -567,24 +503,6 @@ static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val) return 0; } -static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val) -{ - char *str = dl_argv_next(dl); - int err; - - if (!str) { - pr_err("Unsigned number argument expected\n"); - return -EINVAL; - } - - err = strtouint16_t(str, p_val); - if (err) { - pr_err("\"%s\" is not a number or not within range\n", str); - return err; - } - return 0; -} - static int dl_argv_str(struct dl *dl, const char **p_str) { const char *str = dl_argv_next(dl); @@ -612,33 +530,6 @@ static int port_type_get(const char *typestr, enum devlink_port_type *p_type) return 0; } -static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type) -{ - if (strcmp(typestr, "ingress") == 0) { - *p_type = DEVLINK_SB_POOL_TYPE_INGRESS; - } else if (strcmp(typestr, "egress") == 0) { - *p_type = DEVLINK_SB_POOL_TYPE_EGRESS; - } else { - pr_err("Unknown pool type \"%s\"\n", typestr); - return -EINVAL; - } - return 0; -} - -static int threshold_type_get(const char *typestr, - enum devlink_sb_threshold_type *p_type) -{ - if (strcmp(typestr, "static") == 0) { - *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC; - } else if (strcmp(typestr, "dynamic") == 0) { - *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC; - } else { - pr_err("Unknown threshold type \"%s\"\n", typestr); - return -EINVAL; - } - return 0; -} - static int dl_argv_parse(struct dl *dl, uint32_t o_required, uint32_t o_optional) { @@ -688,66 +579,6 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, if (err) return err; o_found |= DL_OPT_PORT_COUNT; - } else if (dl_argv_match(dl, "sb") && - (o_all & DL_OPT_SB)) { - dl_arg_inc(dl); - err = dl_argv_uint32_t(dl, &opts->sb_index); - if (err) - return err; - o_found |= DL_OPT_SB; - } else if (dl_argv_match(dl, "pool") && - (o_all & DL_OPT_SB_POOL)) { - dl_arg_inc(dl); - err = dl_argv_uint16_t(dl, &opts->sb_pool_index); - if (err) - return err; - o_found |= DL_OPT_SB_POOL; - } else if (dl_argv_match(dl, "size") && - (o_all & DL_OPT_SB_SIZE)) { - dl_arg_inc(dl); - err = dl_argv_uint32_t(dl, &opts->sb_pool_size); - if (err) - return err; - o_found |= DL_OPT_SB_SIZE; - } else if (dl_argv_match(dl, "type") && - (o_all & DL_OPT_SB_TYPE)) { - const char *typestr; - - dl_arg_inc(dl); - err = dl_argv_str(dl, &typestr); - if (err) - return err; - err = pool_type_get(typestr, &opts->sb_pool_type); - if (err) - return err; - o_found |= DL_OPT_SB_TYPE; - } else if (dl_argv_match(dl, "thtype") && - (o_all & DL_OPT_SB_THTYPE)) { - const char *typestr; - - dl_arg_inc(dl); - err = dl_argv_str(dl, &typestr); - if (err) - return err; - err = threshold_type_get(typestr, - &opts->sb_pool_thtype); - if (err) - return err; - o_found |= DL_OPT_SB_THTYPE; - } else if (dl_argv_match(dl, "th") && - (o_all & DL_OPT_SB_TH)) { - dl_arg_inc(dl); - err = dl_argv_uint32_t(dl, &opts->sb_threshold); - if (err) - return err; - o_found |= DL_OPT_SB_TH; - } else if (dl_argv_match(dl, "tc") && - (o_all & DL_OPT_SB_TC)) { - dl_arg_inc(dl); - err = dl_argv_uint16_t(dl, &opts->sb_tc_index); - if (err) - return err; - o_found |= DL_OPT_SB_TC; } else { pr_err("Unknown option \"%s\"\n", dl_argv(dl)); return -EINVAL; @@ -756,11 +587,6 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, opts->present = o_found; - if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) { - opts->sb_index = 0; - opts->present |= DL_OPT_SB; - } - if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) { pr_err("Port type option expected.\n"); return -EINVAL; @@ -772,35 +598,6 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, return -EINVAL; } - if ((o_required & DL_OPT_SB_POOL) && !(o_found & DL_OPT_SB_POOL)) { - pr_err("Pool index option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_SIZE) && !(o_found & DL_OPT_SB_SIZE)) { - pr_err("Pool size option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_TYPE) && !(o_found & DL_OPT_SB_TYPE)) { - pr_err("Pool type option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_THTYPE) && !(o_found & DL_OPT_SB_THTYPE)) { - pr_err("Pool threshold type option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_TH) && !(o_found & DL_OPT_SB_TH)) { - pr_err("Threshold option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_TC) && !(o_found & DL_OPT_SB_TC)) { - pr_err("TC index option expected.\n"); - return -EINVAL; - } return 0; } @@ -823,27 +620,6 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) if (opts->present & DL_OPT_PORT_COUNT) mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, opts->port_count); - if (opts->present & DL_OPT_SB) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, - opts->sb_index); - if (opts->present & DL_OPT_SB_POOL) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, - opts->sb_pool_index); - if (opts->present & DL_OPT_SB_SIZE) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE, - opts->sb_pool_size); - if (opts->present & DL_OPT_SB_TYPE) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, - opts->sb_pool_type); - if (opts->present & DL_OPT_SB_THTYPE) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, - opts->sb_pool_thtype); - if (opts->present & DL_OPT_SB_TH) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, - opts->sb_threshold); - if (opts->present & DL_OPT_SB_TC) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, - opts->sb_tc_index); } static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, @@ -1153,380 +929,6 @@ static int cmd_port(struct dl *dl) return -ENOENT; } -static void cmd_sb_help(void) -{ - pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); - pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); - pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); - pr_out(" size POOL_SIZE thtype { static | dynamic }\n"); - pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); - pr_out(" pool POOL_INDEX ]\n"); - pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); - pr_out(" pool POOL_INDEX th THRESHOLD\n"); - pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); - pr_out(" type { ingress | egress } ]\n"); - pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); - pr_out(" type { ingress | egress } pool POOL_INDEX\n"); - pr_out(" th THRESHOLD\n"); -} - -static void pr_out_sb(struct nlattr **tb) -{ - pr_out_handle(tb); - pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); -} - -static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) -{ - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] || - !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] || - !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] || - !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] || - !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]) - return MNL_CB_ERROR; - pr_out_sb(tb); - return MNL_CB_OK; -} - -static int cmd_sb_show(struct dl *dl) -{ - struct nlmsghdr *nlh; - uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; - int err; - - if (dl_argc(dl) == 0) - flags |= NLM_F_DUMP; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags); - - if (dl_argc(dl) > 0) { - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); - if (err) - return err; - } - - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL); -} - -static const char *pool_type_name(uint8_t type) -{ - switch (type) { - case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress"; - case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress"; - default: return ""; - } -} - -static const char *threshold_type_name(uint8_t type) -{ - switch (type) { - case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static"; - case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic"; - default: return ""; - } -} - -static void pr_out_sb_pool(struct nlattr **tb) -{ - pr_out_handle(tb); - pr_out(": sb %u pool %u type %s size %u thtype %s\n", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), - pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]), - threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); -} - -static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) -{ - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] || - !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] || - !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) - return MNL_CB_ERROR; - pr_out_sb_pool(tb); - return MNL_CB_OK; -} - -static int cmd_sb_pool_show(struct dl *dl) -{ - struct nlmsghdr *nlh; - uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; - int err; - - if (dl_argc(dl) == 0) - flags |= NLM_F_DUMP; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags); - - if (dl_argc(dl) > 0) { - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL, - DL_OPT_SB); - if (err) - return err; - } - - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL); -} - -static int cmd_sb_pool_set(struct dl *dl) -{ - struct nlmsghdr *nlh; - int err; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET, - NLM_F_REQUEST | NLM_F_ACK); - - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL | - DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB); - if (err) - return err; - - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -} - -static int cmd_sb_pool(struct dl *dl) -{ - if (dl_argv_match(dl, "help")) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "show") || - dl_argv_match(dl, "list") || dl_no_arg(dl)) { - dl_arg_inc(dl); - return cmd_sb_pool_show(dl); - } else if (dl_argv_match(dl, "set")) { - dl_arg_inc(dl); - return cmd_sb_pool_set(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - -static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb) -{ - pr_out_port_handle_nice(dl, tb); - pr_out(": sb %u pool %u threshold %u\n", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -} - -static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data) -{ - struct dl *dl = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || - !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) - return MNL_CB_ERROR; - pr_out_sb_port_pool(dl, tb); - return MNL_CB_OK; -} - -static int cmd_sb_port_pool_show(struct dl *dl) -{ - struct nlmsghdr *nlh; - uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; - int err; - - if (dl_argc(dl) == 0) - flags |= NLM_F_DUMP; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); - - if (dl_argc(dl) > 0) { - err = dl_argv_parse_put(nlh, dl, - DL_OPT_HANDLEP | DL_OPT_SB_POOL, - DL_OPT_SB); - if (err) - return err; - } - - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); -} - -static int cmd_sb_port_pool_set(struct dl *dl) -{ - struct nlmsghdr *nlh; - int err; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET, - NLM_F_REQUEST | NLM_F_ACK); - - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL | - DL_OPT_SB_TH, DL_OPT_SB); - if (err) - return err; - - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -} - -static int cmd_sb_port_pool(struct dl *dl) -{ - if (dl_argv_match(dl, "help")) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "show") || - dl_argv_match(dl, "list") || dl_no_arg(dl)) { - dl_arg_inc(dl); - return cmd_sb_port_pool_show(dl); - } else if (dl_argv_match(dl, "set")) { - dl_arg_inc(dl); - return cmd_sb_port_pool_set(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - -static int cmd_sb_port(struct dl *dl) -{ - if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "pool")) { - dl_arg_inc(dl); - return cmd_sb_port_pool(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - -static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb) -{ - pr_out_port_handle_nice(dl, tb); - pr_out(": sb %u tc %u type %s pool %u threshold %u\n", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]), - pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -} - -static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data) -{ - struct dl *dl = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || - !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || - !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) - return MNL_CB_ERROR; - pr_out_sb_tc_bind(dl, tb); - return MNL_CB_OK; -} - -static int cmd_sb_tc_bind_show(struct dl *dl) -{ - struct nlmsghdr *nlh; - uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; - int err; - - if (dl_argc(dl) == 0) - flags |= NLM_F_DUMP; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); - - if (dl_argc(dl) > 0) { - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | - DL_OPT_SB_TYPE, DL_OPT_SB); - if (err) - return err; - } - - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); -} - -static int cmd_sb_tc_bind_set(struct dl *dl) -{ - struct nlmsghdr *nlh; - int err; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET, - NLM_F_REQUEST | NLM_F_ACK); - - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | - DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH, - DL_OPT_SB); - if (err) - return err; - - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -} - -static int cmd_sb_tc_bind(struct dl *dl) -{ - if (dl_argv_match(dl, "help")) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "show") || - dl_argv_match(dl, "list") || dl_no_arg(dl)) { - dl_arg_inc(dl); - return cmd_sb_tc_bind_show(dl); - } else if (dl_argv_match(dl, "set")) { - dl_arg_inc(dl); - return cmd_sb_tc_bind_set(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - -static int cmd_sb_tc(struct dl *dl) -{ - if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "bind")) { - dl_arg_inc(dl); - return cmd_sb_tc_bind(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - -static int cmd_sb(struct dl *dl) -{ - if (dl_argv_match(dl, "help")) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "show") || - dl_argv_match(dl, "list") || dl_no_arg(dl)) { - dl_arg_inc(dl); - return cmd_sb_show(dl); - } else if (dl_argv_match(dl, "pool")) { - dl_arg_inc(dl); - return cmd_sb_pool(dl); - } else if (dl_argv_match(dl, "port")) { - dl_arg_inc(dl); - return cmd_sb_port(dl); - } else if (dl_argv_match(dl, "tc")) { - dl_arg_inc(dl); - return cmd_sb_tc(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - static const char *cmd_name(uint8_t cmd) { switch (cmd) { @@ -1662,7 +1064,7 @@ static int cmd_mon(struct dl *dl) static void help(void) { pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" - "where OBJECT := { dev | port | sb | monitor }\n" + "where OBJECT := { dev | port | monitor }\n" " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); } @@ -1677,9 +1079,6 @@ static int dl_cmd(struct dl *dl) } else if (dl_argv_match(dl, "port")) { dl_arg_inc(dl); return cmd_port(dl); - } else if (dl_argv_match(dl, "sb")) { - dl_arg_inc(dl); - return cmd_sb(dl); } else if (dl_argv_match(dl, "monitor")) { dl_arg_inc(dl); return cmd_mon(dl); diff --git a/include/linux/devlink.h b/include/linux/devlink.h index 9c1aa5783..c9fee5781 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -33,26 +33,6 @@ enum devlink_command { DEVLINK_CMD_PORT_SPLIT, DEVLINK_CMD_PORT_UNSPLIT, - DEVLINK_CMD_SB_GET, /* can dump */ - DEVLINK_CMD_SB_SET, - DEVLINK_CMD_SB_NEW, - DEVLINK_CMD_SB_DEL, - - DEVLINK_CMD_SB_POOL_GET, /* can dump */ - DEVLINK_CMD_SB_POOL_SET, - DEVLINK_CMD_SB_POOL_NEW, - DEVLINK_CMD_SB_POOL_DEL, - - DEVLINK_CMD_SB_PORT_POOL_GET, /* can dump */ - DEVLINK_CMD_SB_PORT_POOL_SET, - DEVLINK_CMD_SB_PORT_POOL_NEW, - DEVLINK_CMD_SB_PORT_POOL_DEL, - - DEVLINK_CMD_SB_TC_POOL_BIND_GET, /* can dump */ - DEVLINK_CMD_SB_TC_POOL_BIND_SET, - DEVLINK_CMD_SB_TC_POOL_BIND_NEW, - DEVLINK_CMD_SB_TC_POOL_BIND_DEL, - /* add new commands above here */ __DEVLINK_CMD_MAX, @@ -66,31 +46,6 @@ enum devlink_port_type { DEVLINK_PORT_TYPE_IB, }; -enum devlink_sb_pool_type { - DEVLINK_SB_POOL_TYPE_INGRESS, - DEVLINK_SB_POOL_TYPE_EGRESS, -}; - -/* static threshold - limiting the maximum number of bytes. - * dynamic threshold - limiting the maximum number of bytes - * based on the currently available free space in the shared buffer pool. - * In this mode, the maximum quota is calculated based - * on the following formula: - * max_quota = alpha / (1 + alpha) * Free_Buffer - * While Free_Buffer is the amount of none-occupied buffer associated to - * the relevant pool. - * The value range which can be passed is 0-20 and serves - * for computation of alpha by following formula: - * alpha = 2 ^ (passed_value - 10) - */ - -enum devlink_sb_threshold_type { - DEVLINK_SB_THRESHOLD_TYPE_STATIC, - DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC, -}; - -#define DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX 20 - enum devlink_attr { /* don't change the order or add anything between, this is ABI! */ DEVLINK_ATTR_UNSPEC, @@ -107,18 +62,6 @@ enum devlink_attr { DEVLINK_ATTR_PORT_IBDEV_NAME, /* string */ DEVLINK_ATTR_PORT_SPLIT_COUNT, /* u32 */ DEVLINK_ATTR_PORT_SPLIT_GROUP, /* u32 */ - DEVLINK_ATTR_SB_INDEX, /* u32 */ - DEVLINK_ATTR_SB_SIZE, /* u32 */ - DEVLINK_ATTR_SB_INGRESS_POOL_COUNT, /* u16 */ - DEVLINK_ATTR_SB_EGRESS_POOL_COUNT, /* u16 */ - DEVLINK_ATTR_SB_INGRESS_TC_COUNT, /* u16 */ - DEVLINK_ATTR_SB_EGRESS_TC_COUNT, /* u16 */ - DEVLINK_ATTR_SB_POOL_INDEX, /* u16 */ - DEVLINK_ATTR_SB_POOL_TYPE, /* u8 */ - DEVLINK_ATTR_SB_POOL_SIZE, /* u32 */ - DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ - DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ - DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ /* add new attributes above here, update the policy in devlink.c */ From 8a781d7e2580e14f097b23a7c4731bafc800a824 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 May 2016 14:41:45 -0700 Subject: [PATCH 217/513] update kernel headers to 4.6-rc6 Close to final upstream headers --- include/linux/devlink.h | 6 ++-- include/linux/if.h | 28 +++++++++++++++ include/linux/libc-compat.h | 44 ++++++++++++++++++++++++ include/linux/netfilter_ipv4/ip_tables.h | 1 + 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/include/linux/devlink.h b/include/linux/devlink.h index c9fee5781..a96e1a0e5 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -9,8 +9,8 @@ * (at your option) any later version. */ -#ifndef _UAPI_LINUX_DEVLINK_H_ -#define _UAPI_LINUX_DEVLINK_H_ +#ifndef _LINUX_DEVLINK_H_ +#define _LINUX_DEVLINK_H_ #define DEVLINK_GENL_NAME "devlink" #define DEVLINK_GENL_VERSION 0x1 @@ -69,4 +69,4 @@ enum devlink_attr { DEVLINK_ATTR_MAX = __DEVLINK_ATTR_MAX - 1 }; -#endif /* _UAPI_LINUX_DEVLINK_H_ */ +#endif /* _LINUX_DEVLINK_H_ */ diff --git a/include/linux/if.h b/include/linux/if.h index 86fffb05e..5b8494821 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -19,14 +19,20 @@ #ifndef _LINUX_IF_H #define _LINUX_IF_H +#include /* for compatibility with glibc */ #include /* for "__kernel_caddr_t" et al */ #include /* for "struct sockaddr" et al */ /* for "__user" et al */ +#if __UAPI_DEF_IF_IFNAMSIZ #define IFNAMSIZ 16 +#endif /* __UAPI_DEF_IF_IFNAMSIZ */ #define IFALIASZ 256 #include +/* For glibc compatibility. An empty enum does not compile. */ +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && \ + __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 /** * enum net_device_flags - &struct net_device flags * @@ -68,6 +74,8 @@ * @IFF_ECHO: echo sent packets. Volatile. */ enum net_device_flags { +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS IFF_UP = 1<<0, /* sysfs */ IFF_BROADCAST = 1<<1, /* __volatile__ */ IFF_DEBUG = 1<<2, /* sysfs */ @@ -84,11 +92,17 @@ enum net_device_flags { IFF_PORTSEL = 1<<13, /* sysfs */ IFF_AUTOMEDIA = 1<<14, /* sysfs */ IFF_DYNAMIC = 1<<15, /* sysfs */ +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */ +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO IFF_LOWER_UP = 1<<16, /* __volatile__ */ IFF_DORMANT = 1<<17, /* __volatile__ */ IFF_ECHO = 1<<18, /* __volatile__ */ +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ }; +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */ +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS #define IFF_UP IFF_UP #define IFF_BROADCAST IFF_BROADCAST #define IFF_DEBUG IFF_DEBUG @@ -105,9 +119,13 @@ enum net_device_flags { #define IFF_PORTSEL IFF_PORTSEL #define IFF_AUTOMEDIA IFF_AUTOMEDIA #define IFF_DYNAMIC IFF_DYNAMIC +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */ + +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO #define IFF_LOWER_UP IFF_LOWER_UP #define IFF_DORMANT IFF_DORMANT #define IFF_ECHO IFF_ECHO +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ #define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\ IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT) @@ -166,6 +184,8 @@ enum { * being very small might be worth keeping for clean configuration. */ +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_IFMAP struct ifmap { unsigned long mem_start; unsigned long mem_end; @@ -175,6 +195,7 @@ struct ifmap { unsigned char port; /* 3 bytes spare */ }; +#endif /* __UAPI_DEF_IF_IFMAP */ struct if_settings { unsigned int type; /* Type of physical device or protocol */ @@ -200,6 +221,8 @@ struct if_settings { * remainder may be interface specific. */ +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_IFREQ struct ifreq { #define IFHWADDRLEN 6 union @@ -223,6 +246,7 @@ struct ifreq { struct if_settings ifru_settings; } ifr_ifru; }; +#endif /* __UAPI_DEF_IF_IFREQ */ #define ifr_name ifr_ifrn.ifrn_name /* interface name */ #define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ @@ -249,6 +273,8 @@ struct ifreq { * must know all networks accessible). */ +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_IFCONF struct ifconf { int ifc_len; /* size of buffer */ union { @@ -256,6 +282,8 @@ struct ifconf { struct ifreq *ifcu_req; } ifc_ifcu; }; +#endif /* __UAPI_DEF_IF_IFCONF */ + #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ #define ifc_req ifc_ifcu.ifcu_req /* array of structures */ diff --git a/include/linux/libc-compat.h b/include/linux/libc-compat.h index 9bed5b6ae..b3c208512 100644 --- a/include/linux/libc-compat.h +++ b/include/linux/libc-compat.h @@ -51,6 +51,40 @@ /* We have included glibc headers... */ #if defined(__GLIBC__) +/* Coordinate with glibc net/if.h header. */ +#if defined(_NET_IF_H) + +/* GLIBC headers included first so don't define anything + * that would already be defined. */ + +#define __UAPI_DEF_IF_IFCONF 0 +#define __UAPI_DEF_IF_IFMAP 0 +#define __UAPI_DEF_IF_IFNAMSIZ 0 +#define __UAPI_DEF_IF_IFREQ 0 +/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0 +/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ +#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ + +#else /* _NET_IF_H */ + +/* Linux headers included first, and we must define everything + * we need. The expectation is that glibc will check the + * __UAPI_DEF_* defines and adjust appropriately. */ + +#define __UAPI_DEF_IF_IFCONF 1 +#define __UAPI_DEF_IF_IFMAP 1 +#define __UAPI_DEF_IF_IFNAMSIZ 1 +#define __UAPI_DEF_IF_IFREQ 1 +/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1 +/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 + +#endif /* _NET_IF_H */ + /* Coordinate with glibc netinet/in.h header. */ #if defined(_NETINET_IN_H) @@ -117,6 +151,16 @@ * that we need. */ #else /* !defined(__GLIBC__) */ +/* Definitions for if.h */ +#define __UAPI_DEF_IF_IFCONF 1 +#define __UAPI_DEF_IF_IFMAP 1 +#define __UAPI_DEF_IF_IFNAMSIZ 1 +#define __UAPI_DEF_IF_IFREQ 1 +/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1 +/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 + /* Definitions for in.h */ #define __UAPI_DEF_IN_ADDR 1 #define __UAPI_DEF_IN_IPPROTO 1 diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index 38542b4f7..456fb863e 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h @@ -17,6 +17,7 @@ #include +#include #include #include From 719c443bb8c4c49da78e7b19d88b30cd2399c6d1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 May 2016 14:42:06 -0700 Subject: [PATCH 218/513] devlink: remove unused code Unused code causes warnings, removed. --- devlink/devlink.c | 42 ------------------------------------------ 1 file changed, 42 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index e2e04136c..68bdf3978 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -634,35 +634,6 @@ static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, return 0; } -static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) -{ - struct dl_opts *opts = &dl->opts; - struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME]; - struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME]; - struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX]; - - if (opts->present & DL_OPT_HANDLE && - attr_bus_name && attr_dev_name) { - const char *bus_name = mnl_attr_get_str(attr_bus_name); - const char *dev_name = mnl_attr_get_str(attr_dev_name); - - if (strcmp(bus_name, opts->bus_name) != 0 || - strcmp(dev_name, opts->dev_name) != 0) - return false; - } - if (opts->present & DL_OPT_HANDLEP && - attr_bus_name && attr_dev_name && attr_port_index) { - const char *bus_name = mnl_attr_get_str(attr_bus_name); - const char *dev_name = mnl_attr_get_str(attr_dev_name); - uint32_t port_index = mnl_attr_get_u32(attr_port_index); - - if (strcmp(bus_name, opts->bus_name) != 0 || - strcmp(dev_name, opts->dev_name) != 0 || - port_index != opts->port_index) - return false; - } - return true; -} static void cmd_dev_help(void) { @@ -714,19 +685,6 @@ static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name, __pr_out_port_handle(bus_name, dev_name, port_index); } -static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) -{ - const char *bus_name; - const char *dev_name; - uint32_t port_index; - - bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); - dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); - port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); - - __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index); -} - static void pr_out_dev(struct nlattr **tb) { pr_out_handle(tb); From b38e740903f87882cf5b45a56fb0254faa4b7ab0 Mon Sep 17 00:00:00 2001 From: "subashab@codeaurora.org" Date: Mon, 9 May 2016 14:54:36 -0600 Subject: [PATCH 219/513] ss: Remove unused argument from kill_inet_sock addr is not used here. Signed-off-by: Subash Abhinov Kasiviswanathan --- misc/ss.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index deefc9676..5cda728a2 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -2232,8 +2232,7 @@ struct inet_diag_arg { struct rtnl_handle *rth; }; -static int kill_inet_sock(const struct sockaddr_nl *addr, - struct nlmsghdr *h, void *arg) +static int kill_inet_sock(struct nlmsghdr *h, void *arg) { struct inet_diag_msg *d = NLMSG_DATA(h); struct inet_diag_arg *diag_arg = arg; @@ -2260,7 +2259,7 @@ static int show_one_inet_sock(const struct sockaddr_nl *addr, if (!(diag_arg->f->families & (1 << r->idiag_family))) return 0; - if (diag_arg->f->kill && kill_inet_sock(addr, h, arg) != 0) { + if (diag_arg->f->kill && kill_inet_sock(h, arg) != 0) { if (errno == EOPNOTSUPP || errno == ENOENT) { /* Socket can't be closed, or is already closed. */ return 0; From c13363e4cd4c9499fc33d798036081a674461d1b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 May 2016 14:48:32 -0700 Subject: [PATCH 220/513] devlink: remove more unused code --- devlink/devlink.c | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index 68bdf3978..89a308317 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -307,23 +307,6 @@ static int ifname_map_lookup(struct dl *dl, const char *ifname, return -ENOENT; } -static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name, - const char *dev_name, uint32_t port_index, - char **p_ifname) -{ - struct ifname_map *ifname_map; - - list_for_each_entry(ifname_map, &dl->ifname_map_list, list) { - if (strcmp(bus_name, ifname_map->bus_name) == 0 && - strcmp(dev_name, ifname_map->dev_name) == 0 && - port_index == ifname_map->port_index) { - *p_ifname = ifname_map->ifname; - return 0; - } - } - return -ENOENT; -} - static unsigned int strslashcount(char *str) { unsigned int count = 0; @@ -665,26 +648,6 @@ static void pr_out_port_handle(struct nlattr **tb) mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); } -static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name, - const char *dev_name, uint32_t port_index) -{ - char *ifname; - int err; - - if (dl->no_nice_names) - goto no_nice_names; - - err = ifname_map_rev_lookup(dl, bus_name, dev_name, - port_index, &ifname); - if (err) - goto no_nice_names; - pr_out("%s", ifname); - return; - -no_nice_names: - __pr_out_port_handle(bus_name, dev_name, port_index); -} - static void pr_out_dev(struct nlattr **tb) { pr_out_handle(tb); From 0c9ffc0b0a95ebd529af19b2f086384ab90766b9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 May 2016 14:49:40 -0700 Subject: [PATCH 221/513] devlink: update uapi header Get santized version from net-next --- include/linux/devlink.h | 63 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/include/linux/devlink.h b/include/linux/devlink.h index a96e1a0e5..0e21d001f 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -33,6 +33,30 @@ enum devlink_command { DEVLINK_CMD_PORT_SPLIT, DEVLINK_CMD_PORT_UNSPLIT, + DEVLINK_CMD_SB_GET, /* can dump */ + DEVLINK_CMD_SB_SET, + DEVLINK_CMD_SB_NEW, + DEVLINK_CMD_SB_DEL, + + DEVLINK_CMD_SB_POOL_GET, /* can dump */ + DEVLINK_CMD_SB_POOL_SET, + DEVLINK_CMD_SB_POOL_NEW, + DEVLINK_CMD_SB_POOL_DEL, + + DEVLINK_CMD_SB_PORT_POOL_GET, /* can dump */ + DEVLINK_CMD_SB_PORT_POOL_SET, + DEVLINK_CMD_SB_PORT_POOL_NEW, + DEVLINK_CMD_SB_PORT_POOL_DEL, + + DEVLINK_CMD_SB_TC_POOL_BIND_GET, /* can dump */ + DEVLINK_CMD_SB_TC_POOL_BIND_SET, + DEVLINK_CMD_SB_TC_POOL_BIND_NEW, + DEVLINK_CMD_SB_TC_POOL_BIND_DEL, + + /* Shared buffer occupancy monitoring commands */ + DEVLINK_CMD_SB_OCC_SNAPSHOT, + DEVLINK_CMD_SB_OCC_MAX_CLEAR, + /* add new commands above here */ __DEVLINK_CMD_MAX, @@ -46,6 +70,31 @@ enum devlink_port_type { DEVLINK_PORT_TYPE_IB, }; +enum devlink_sb_pool_type { + DEVLINK_SB_POOL_TYPE_INGRESS, + DEVLINK_SB_POOL_TYPE_EGRESS, +}; + +/* static threshold - limiting the maximum number of bytes. + * dynamic threshold - limiting the maximum number of bytes + * based on the currently available free space in the shared buffer pool. + * In this mode, the maximum quota is calculated based + * on the following formula: + * max_quota = alpha / (1 + alpha) * Free_Buffer + * While Free_Buffer is the amount of none-occupied buffer associated to + * the relevant pool. + * The value range which can be passed is 0-20 and serves + * for computation of alpha by following formula: + * alpha = 2 ^ (passed_value - 10) + */ + +enum devlink_sb_threshold_type { + DEVLINK_SB_THRESHOLD_TYPE_STATIC, + DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC, +}; + +#define DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX 20 + enum devlink_attr { /* don't change the order or add anything between, this is ABI! */ DEVLINK_ATTR_UNSPEC, @@ -62,6 +111,20 @@ enum devlink_attr { DEVLINK_ATTR_PORT_IBDEV_NAME, /* string */ DEVLINK_ATTR_PORT_SPLIT_COUNT, /* u32 */ DEVLINK_ATTR_PORT_SPLIT_GROUP, /* u32 */ + DEVLINK_ATTR_SB_INDEX, /* u32 */ + DEVLINK_ATTR_SB_SIZE, /* u32 */ + DEVLINK_ATTR_SB_INGRESS_POOL_COUNT, /* u16 */ + DEVLINK_ATTR_SB_EGRESS_POOL_COUNT, /* u16 */ + DEVLINK_ATTR_SB_INGRESS_TC_COUNT, /* u16 */ + DEVLINK_ATTR_SB_EGRESS_TC_COUNT, /* u16 */ + DEVLINK_ATTR_SB_POOL_INDEX, /* u16 */ + DEVLINK_ATTR_SB_POOL_TYPE, /* u8 */ + DEVLINK_ATTR_SB_POOL_SIZE, /* u32 */ + DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ + DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ + DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ + DEVLINK_ATTR_SB_OCC_CUR, /* u32 */ + DEVLINK_ATTR_SB_OCC_MAX, /* u32 */ /* add new attributes above here, update the policy in devlink.c */ From 31ce6e010195d049ec3f8415e03d2951f494bf1d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 May 2016 14:56:31 -0700 Subject: [PATCH 222/513] update kernel headers from net-next Take sanitized headers for davem net-next --- include/linux/bpf.h | 2 ++ include/linux/gen_stats.h | 1 + include/linux/if_bridge.h | 18 +++++++++++++++ include/linux/if_link.h | 36 ++++++++++++++++++++++++++++++ include/linux/ila.h | 8 +++++++ include/linux/inet_diag.h | 4 +++- include/linux/l2tp.h | 1 + include/linux/pkt_cls.h | 2 ++ include/linux/pkt_sched.h | 7 ++++++ include/linux/rtnetlink.h | 1 + include/linux/tc_act/tc_bpf.h | 1 + include/linux/tc_act/tc_connmark.h | 1 + include/linux/tc_act/tc_csum.h | 1 + include/linux/tc_act/tc_defact.h | 1 + include/linux/tc_act/tc_gact.h | 1 + include/linux/tc_act/tc_ipt.h | 1 + include/linux/tc_act/tc_mirred.h | 1 + include/linux/tc_act/tc_nat.h | 1 + include/linux/tc_act/tc_pedit.h | 1 + include/linux/tc_act/tc_skbedit.h | 1 + include/linux/tc_act/tc_vlan.h | 1 + 21 files changed, 90 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index ce6d03ee0..5e4d3739a 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -370,6 +370,8 @@ struct __sk_buff { __u32 cb[5]; __u32 hash; __u32 tc_classid; + __u32 data; + __u32 data_end; }; struct bpf_tunnel_key { diff --git a/include/linux/gen_stats.h b/include/linux/gen_stats.h index 6487317ea..52deccc21 100644 --- a/include/linux/gen_stats.h +++ b/include/linux/gen_stats.h @@ -10,6 +10,7 @@ enum { TCA_STATS_QUEUE, TCA_STATS_APP, TCA_STATS_RATE_EST64, + TCA_STATS_PAD, __TCA_STATS_MAX, }; #define TCA_STATS_MAX (__TCA_STATS_MAX - 1) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 8de96b7a7..fc3dcfa46 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -134,6 +134,16 @@ struct bridge_vlan_info { __u16 vid; }; +struct bridge_vlan_xstats { + __u64 rx_bytes; + __u64 rx_packets; + __u64 tx_bytes; + __u64 tx_packets; + __u16 vid; + __u16 pad1; + __u32 pad2; +}; + /* Bridge multicast database attributes * [MDBA_MDB] = { * [MDBA_MDB_ENTRY] = { @@ -233,4 +243,12 @@ enum { }; #define MDBA_SET_ENTRY_MAX (__MDBA_SET_ENTRY_MAX - 1) +/* Embedded inside LINK_XSTATS_TYPE_BRIDGE */ +enum { + BRIDGE_XSTATS_UNSPEC, + BRIDGE_XSTATS_VLAN, + __BRIDGE_XSTATS_MAX +}; +#define BRIDGE_XSTATS_MAX (__BRIDGE_XSTATS_MAX - 1) + #endif /* _LINUX_IF_BRIDGE_H */ diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 0a7abb11f..15bbeb818 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -269,6 +269,8 @@ enum { IFLA_BR_NF_CALL_IP6TABLES, IFLA_BR_NF_CALL_ARPTABLES, IFLA_BR_VLAN_DEFAULT_PVID, + IFLA_BR_PAD, + IFLA_BR_VLAN_STATS_ENABLED, __IFLA_BR_MAX, }; @@ -311,6 +313,7 @@ enum { IFLA_BRPORT_HOLD_TIMER, IFLA_BRPORT_FLUSH, IFLA_BRPORT_MULTICAST_ROUTER, + IFLA_BRPORT_PAD, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) @@ -430,6 +433,7 @@ enum { IFLA_MACSEC_SCB, IFLA_MACSEC_REPLAY_PROTECT, IFLA_MACSEC_VALIDATION, + IFLA_MACSEC_PAD, __IFLA_MACSEC_MAX, }; @@ -515,6 +519,24 @@ enum { }; #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) +/* PPP section */ +enum { + IFLA_PPP_UNSPEC, + IFLA_PPP_DEV_FD, + __IFLA_PPP_MAX +}; +#define IFLA_PPP_MAX (__IFLA_PPP_MAX - 1) + +/* GTP section */ +enum { + IFLA_GTP_UNSPEC, + IFLA_GTP_FD0, + IFLA_GTP_FD1, + IFLA_GTP_PDP_HASHSIZE, + __IFLA_GTP_MAX, +}; +#define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1) + /* Bonding section */ enum { @@ -664,6 +686,7 @@ enum { IFLA_VF_STATS_TX_BYTES, IFLA_VF_STATS_BROADCAST, IFLA_VF_STATS_MULTICAST, + IFLA_VF_STATS_PAD, __IFLA_VF_STATS_MAX, }; @@ -796,6 +819,7 @@ struct if_stats_msg { enum { IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */ IFLA_STATS_LINK_64, + IFLA_STATS_LINK_XSTATS, __IFLA_STATS_MAX, }; @@ -803,4 +827,16 @@ enum { #define IFLA_STATS_FILTER_BIT(ATTR) (1 << (ATTR - 1)) +/* These are embedded into IFLA_STATS_LINK_XSTATS: + * [IFLA_STATS_LINK_XSTATS] + * -> [LINK_XSTATS_TYPE_xxx] + * -> [rtnl link type specific attributes] + */ +enum { + LINK_XSTATS_TYPE_UNSPEC, + LINK_XSTATS_TYPE_BRIDGE, + __LINK_XSTATS_TYPE_MAX +}; +#define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1) + #endif /* _LINUX_IF_LINK_H */ diff --git a/include/linux/ila.h b/include/linux/ila.h index 4f9e1deaf..7e328d72c 100644 --- a/include/linux/ila.h +++ b/include/linux/ila.h @@ -14,6 +14,8 @@ enum { ILA_ATTR_LOCATOR_MATCH, /* u64 */ ILA_ATTR_IFINDEX, /* s32 */ ILA_ATTR_DIR, /* u32 */ + ILA_ATTR_PAD, + ILA_ATTR_CSUM_MODE, /* u8 */ __ILA_ATTR_MAX, }; @@ -34,4 +36,10 @@ enum { #define ILA_DIR_IN (1 << 0) #define ILA_DIR_OUT (1 << 1) +enum { + ILA_CSUM_ADJUST_TRANSPORT, + ILA_CSUM_NEUTRAL_MAP, + ILA_CSUM_NO_ACTION, +}; + #endif /* _LINUX_ILA_H */ diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index b806fcfc1..07e486cb2 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -115,9 +115,11 @@ enum { INET_DIAG_SKV6ONLY, INET_DIAG_LOCALS, INET_DIAG_PEERS, + INET_DIAG_PAD, + __INET_DIAG_MAX, }; -#define INET_DIAG_MAX INET_DIAG_SKV6ONLY +#define INET_DIAG_MAX (__INET_DIAG_MAX - 1) /* INET_DIAG_MEM */ diff --git a/include/linux/l2tp.h b/include/linux/l2tp.h index 9ca4d0cff..f00e4248b 100644 --- a/include/linux/l2tp.h +++ b/include/linux/l2tp.h @@ -141,6 +141,7 @@ enum { L2TP_ATTR_RX_SEQ_DISCARDS, /* u64 */ L2TP_ATTR_RX_OOS_PACKETS, /* u64 */ L2TP_ATTR_RX_ERRORS, /* u64 */ + L2TP_ATTR_STATS_PAD, __L2TP_ATTR_STATS_MAX, }; diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index b69358b48..036283214 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -12,6 +12,7 @@ enum { TCA_ACT_OPTIONS, TCA_ACT_INDEX, TCA_ACT_STATS, + TCA_ACT_PAD, __TCA_ACT_MAX }; @@ -119,6 +120,7 @@ enum { TCA_U32_PCNT, TCA_U32_MARK, TCA_U32_FLAGS, + TCA_U32_PAD, __TCA_U32_MAX }; diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index 8cb18b449..2382eed50 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -179,6 +179,7 @@ enum { TCA_TBF_PRATE64, TCA_TBF_BURST, TCA_TBF_PBURST, + TCA_TBF_PAD, __TCA_TBF_MAX, }; @@ -368,6 +369,7 @@ enum { TCA_HTB_DIRECT_QLEN, TCA_HTB_RATE64, TCA_HTB_CEIL64, + TCA_HTB_PAD, __TCA_HTB_MAX, }; @@ -531,6 +533,7 @@ enum { TCA_NETEM_RATE, TCA_NETEM_ECN, TCA_NETEM_RATE64, + TCA_NETEM_PAD, __TCA_NETEM_MAX, }; @@ -715,6 +718,8 @@ enum { TCA_FQ_CODEL_FLOWS, TCA_FQ_CODEL_QUANTUM, TCA_FQ_CODEL_CE_THRESHOLD, + TCA_FQ_CODEL_DROP_BATCH_SIZE, + TCA_FQ_CODEL_MEMORY_LIMIT, __TCA_FQ_CODEL_MAX }; @@ -739,6 +744,8 @@ struct tc_fq_codel_qd_stats { __u32 new_flows_len; /* count of flows in new list */ __u32 old_flows_len; /* count of flows in old list */ __u32 ce_mark; /* packets above ce_threshold */ + __u32 memory_usage; /* in bytes */ + __u32 drop_overmemory; }; struct tc_fq_codel_cl_stats { diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index ae8b02a50..2d2e3e6c5 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -542,6 +542,7 @@ enum { TCA_FCNT, TCA_STATS2, TCA_STAB, + TCA_PAD, __TCA_MAX }; diff --git a/include/linux/tc_act/tc_bpf.h b/include/linux/tc_act/tc_bpf.h index 07f17cc70..063d9d465 100644 --- a/include/linux/tc_act/tc_bpf.h +++ b/include/linux/tc_act/tc_bpf.h @@ -26,6 +26,7 @@ enum { TCA_ACT_BPF_OPS, TCA_ACT_BPF_FD, TCA_ACT_BPF_NAME, + TCA_ACT_BPF_PAD, __TCA_ACT_BPF_MAX, }; #define TCA_ACT_BPF_MAX (__TCA_ACT_BPF_MAX - 1) diff --git a/include/linux/tc_act/tc_connmark.h b/include/linux/tc_act/tc_connmark.h index 994b0971b..62a5e944c 100644 --- a/include/linux/tc_act/tc_connmark.h +++ b/include/linux/tc_act/tc_connmark.h @@ -15,6 +15,7 @@ enum { TCA_CONNMARK_UNSPEC, TCA_CONNMARK_PARMS, TCA_CONNMARK_TM, + TCA_CONNMARK_PAD, __TCA_CONNMARK_MAX }; #define TCA_CONNMARK_MAX (__TCA_CONNMARK_MAX - 1) diff --git a/include/linux/tc_act/tc_csum.h b/include/linux/tc_act/tc_csum.h index a047c49a3..8ac8041ab 100644 --- a/include/linux/tc_act/tc_csum.h +++ b/include/linux/tc_act/tc_csum.h @@ -10,6 +10,7 @@ enum { TCA_CSUM_UNSPEC, TCA_CSUM_PARMS, TCA_CSUM_TM, + TCA_CSUM_PAD, __TCA_CSUM_MAX }; #define TCA_CSUM_MAX (__TCA_CSUM_MAX - 1) diff --git a/include/linux/tc_act/tc_defact.h b/include/linux/tc_act/tc_defact.h index 17dddb40f..d2a3abb77 100644 --- a/include/linux/tc_act/tc_defact.h +++ b/include/linux/tc_act/tc_defact.h @@ -12,6 +12,7 @@ enum { TCA_DEF_TM, TCA_DEF_PARMS, TCA_DEF_DATA, + TCA_DEF_PAD, __TCA_DEF_MAX }; #define TCA_DEF_MAX (__TCA_DEF_MAX - 1) diff --git a/include/linux/tc_act/tc_gact.h b/include/linux/tc_act/tc_gact.h index f7bf94eed..70b536a8f 100644 --- a/include/linux/tc_act/tc_gact.h +++ b/include/linux/tc_act/tc_gact.h @@ -25,6 +25,7 @@ enum { TCA_GACT_TM, TCA_GACT_PARMS, TCA_GACT_PROB, + TCA_GACT_PAD, __TCA_GACT_MAX }; #define TCA_GACT_MAX (__TCA_GACT_MAX - 1) diff --git a/include/linux/tc_act/tc_ipt.h b/include/linux/tc_act/tc_ipt.h index 130aaadf6..7c6e155dd 100644 --- a/include/linux/tc_act/tc_ipt.h +++ b/include/linux/tc_act/tc_ipt.h @@ -14,6 +14,7 @@ enum { TCA_IPT_CNT, TCA_IPT_TM, TCA_IPT_TARG, + TCA_IPT_PAD, __TCA_IPT_MAX }; #define TCA_IPT_MAX (__TCA_IPT_MAX - 1) diff --git a/include/linux/tc_act/tc_mirred.h b/include/linux/tc_act/tc_mirred.h index 7561750e8..3d7a2b352 100644 --- a/include/linux/tc_act/tc_mirred.h +++ b/include/linux/tc_act/tc_mirred.h @@ -20,6 +20,7 @@ enum { TCA_MIRRED_UNSPEC, TCA_MIRRED_TM, TCA_MIRRED_PARMS, + TCA_MIRRED_PAD, __TCA_MIRRED_MAX }; #define TCA_MIRRED_MAX (__TCA_MIRRED_MAX - 1) diff --git a/include/linux/tc_act/tc_nat.h b/include/linux/tc_act/tc_nat.h index 6663aeba0..923457c9e 100644 --- a/include/linux/tc_act/tc_nat.h +++ b/include/linux/tc_act/tc_nat.h @@ -10,6 +10,7 @@ enum { TCA_NAT_UNSPEC, TCA_NAT_PARMS, TCA_NAT_TM, + TCA_NAT_PAD, __TCA_NAT_MAX }; #define TCA_NAT_MAX (__TCA_NAT_MAX - 1) diff --git a/include/linux/tc_act/tc_pedit.h b/include/linux/tc_act/tc_pedit.h index 716cfabcd..6389959a5 100644 --- a/include/linux/tc_act/tc_pedit.h +++ b/include/linux/tc_act/tc_pedit.h @@ -10,6 +10,7 @@ enum { TCA_PEDIT_UNSPEC, TCA_PEDIT_TM, TCA_PEDIT_PARMS, + TCA_PEDIT_PAD, __TCA_PEDIT_MAX }; #define TCA_PEDIT_MAX (__TCA_PEDIT_MAX - 1) diff --git a/include/linux/tc_act/tc_skbedit.h b/include/linux/tc_act/tc_skbedit.h index 7a2e910a5..fecb5cc48 100644 --- a/include/linux/tc_act/tc_skbedit.h +++ b/include/linux/tc_act/tc_skbedit.h @@ -39,6 +39,7 @@ enum { TCA_SKBEDIT_PRIORITY, TCA_SKBEDIT_QUEUE_MAPPING, TCA_SKBEDIT_MARK, + TCA_SKBEDIT_PAD, __TCA_SKBEDIT_MAX }; #define TCA_SKBEDIT_MAX (__TCA_SKBEDIT_MAX - 1) diff --git a/include/linux/tc_act/tc_vlan.h b/include/linux/tc_act/tc_vlan.h index f7b8d448b..31151ff62 100644 --- a/include/linux/tc_act/tc_vlan.h +++ b/include/linux/tc_act/tc_vlan.h @@ -28,6 +28,7 @@ enum { TCA_VLAN_PARMS, TCA_VLAN_PUSH_VLAN_ID, TCA_VLAN_PUSH_VLAN_PROTOCOL, + TCA_VLAN_PAD, __TCA_VLAN_MAX, }; #define TCA_VLAN_MAX (__TCA_VLAN_MAX - 1) From 29b7968926edb6256aaa1f699ad4f40041281856 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 16 May 2016 11:13:05 -0700 Subject: [PATCH 223/513] add tc_ife.h --- include/linux/tc_act/tc_ife.h | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 include/linux/tc_act/tc_ife.h diff --git a/include/linux/tc_act/tc_ife.h b/include/linux/tc_act/tc_ife.h new file mode 100644 index 000000000..d648ff665 --- /dev/null +++ b/include/linux/tc_act/tc_ife.h @@ -0,0 +1,38 @@ +#ifndef __UAPI_TC_IFE_H +#define __UAPI_TC_IFE_H + +#include +#include + +#define TCA_ACT_IFE 25 +/* Flag bits for now just encoding/decoding; mutually exclusive */ +#define IFE_ENCODE 1 +#define IFE_DECODE 0 + +struct tc_ife { + tc_gen; + __u16 flags; +}; + +/*XXX: We need to encode the total number of bytes consumed */ +enum { + TCA_IFE_UNSPEC, + TCA_IFE_PARMS, + TCA_IFE_TM, + TCA_IFE_DMAC, + TCA_IFE_SMAC, + TCA_IFE_TYPE, + TCA_IFE_METALST, + __TCA_IFE_MAX +}; +#define TCA_IFE_MAX (__TCA_IFE_MAX - 1) + +#define IFE_META_SKBMARK 1 +#define IFE_META_HASHID 2 +#define IFE_META_PRIO 3 +#define IFE_META_QMAP 4 +/*Can be overridden at runtime by module option*/ +#define __IFE_META_MAX 5 +#define IFE_META_MAX (__IFE_META_MAX - 1) + +#endif From d3e511223fc5042f181332622ea97ae617cc73bc Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sat, 7 May 2016 09:35:23 -0400 Subject: [PATCH 224/513] tc: introduce IFE action This action allows for a sending side to encapsulate arbitrary metadata which is decapsulated by the receiving end. The sender runs in encoding mode and the receiver in decode mode. Both sender and receiver must specify the same ethertype. At some point we hope to have a registered ethertype and we'll then provide a default so the user doesnt have to specify it. For now we enforce the user specify it. Described in netdev01 paper: "Distributing Linux Traffic Control Classifier-Action Subsystem" Authors: Jamal Hadi Salim and Damascene M. Joachimpillai Also refer to IETF draft-ietf-forces-interfelfb-04.txt Lets show example usage where we encode icmp from a sender towards a receiver with an skbmark of 17; both sender and receiver use ethertype of 0xdead to interop. YYYY: Lets start with Receiver-side policy config: xxx: add an ingress qdisc sudo tc qdisc add dev $ETH ingress xxx: any packets with ethertype 0xdead will be subjected to ife decoding xxx: we then restart the classification so we can match on icmp at prio 3 sudo $TC filter add dev $ETH parent ffff: prio 2 protocol 0xdead \ u32 match u32 0 0 flowid 1:1 \ action ife decode reclassify xxx: on restarting the classification from above if it was an icmp xxx: packet, then match it here and continue to the next rule at prio 4 xxx: which will match based on skb mark of 17 sudo tc filter add dev $ETH parent ffff: prio 3 protocol ip \ u32 match ip protocol 1 0xff flowid 1:1 \ action continue xxx: match on skbmark of 0x11 (decimal 17) and accept sudo tc filter add dev $ETH parent ffff: prio 4 protocol ip \ handle 0x11 fw flowid 1:1 \ action ok xxx: Lets show the decoding policy sudo tc -s filter ls dev $ETH parent ffff: protocol 0xdead xxx: filter pref 2 u32 filter pref 2 u32 fh 800: ht divisor 1 filter pref 2 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 (rule hit 0 success 0) match 00000000/00000000 at 0 (success 0 ) action order 1: ife decode action reclassify type 0x0 allow mark allow prio index 11 ref 1 bind 1 installed 45 sec used 45 sec Action statistics: Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 xxx: Observe that above lists all metadatum it can decode. Typically these submodules will already be compiled into a monolithic kernel or loaded as modules YYYY: Lets show the sender side now .. xxx: Add an egress qdisc on the sender netdev sudo tc qdisc add dev $ETH root handle 1: prio xxx: xxx: Match all icmp packets to 192.168.122.237/24, then xxx: tag the packet with skb mark of decimal 17, then xxx: Encode it with: xxx: ethertype 0xdead xxx: add skb->mark to whitelist of metadatum to send xxx: rewrite target dst MAC address to 02:15:15:15:15:15 xxx: sudo $TC filter add dev $ETH parent 1: protocol ip prio 10 u32 \ match ip dst 192.168.122.237/24 \ match ip protocol 1 0xff \ flowid 1:2 \ action skbedit mark 17 \ action ife encode \ type 0xDEAD \ allow mark \ dst 02:15:15:15:15:15 xxx: Lets show the encoding policy filter pref 10 u32 filter pref 10 u32 fh 800: ht divisor 1 filter pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:2 (rule hit 118 success 0) match c0a87a00/ffffff00 at 16 (success 0 ) match 00010000/00ff0000 at 8 (success 0 ) action order 1: skbedit mark 17 index 11 ref 1 bind 1 installed 3 sec used 3 sec Action statistics: Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 action order 2: ife encode action pipe type 0xDEAD allow mark dst 02:15:15:15:15:15 index 12 ref 1 bind 1 installed 3 sec used 3 sec Action statistics: Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 xxx: Now test by sending ping from sender to destination Signed-off-by: Jamal Hadi Salim --- tc/Makefile | 1 + tc/m_ife.c | 341 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 342 insertions(+) create mode 100644 tc/m_ife.c diff --git a/tc/Makefile b/tc/Makefile index f5bea877d..20f511000 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -43,6 +43,7 @@ TCMODULES += m_gact.o TCMODULES += m_mirred.o TCMODULES += m_nat.o TCMODULES += m_pedit.o +TCMODULES += m_ife.o TCMODULES += m_skbedit.o TCMODULES += m_csum.o TCMODULES += m_simple.o diff --git a/tc/m_ife.c b/tc/m_ife.c new file mode 100644 index 000000000..839e370af --- /dev/null +++ b/tc/m_ife.c @@ -0,0 +1,341 @@ +/* + * m_ife.c IFE actions module + * + * This program is free software; you can distribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: J Hadi Salim (jhs@mojatatu.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt_names.h" +#include "utils.h" +#include "tc_util.h" +#include + +static void ife_explain(void) +{ + fprintf(stderr, + "Usage:... ife {decode|encode} {ALLOW|USE} [dst DMAC] [src SMAC] [type TYPE] [CONTROL] [index INDEX]\n"); + fprintf(stderr, + "\tALLOW := Encode direction. Allows encoding specified metadata\n" + "\t\t e.g \"allow mark\"\n" + "\tUSE := Encode direction. Enforce Static encoding of specified metadata\n" + "\t\t e.g \"use mark 0x12\"\n" + "\tDMAC := 6 byte Destination MAC address to encode\n" + "\tSMAC := optional 6 byte Source MAC address to encode\n" + "\tTYPE := optional 16 bit ethertype to encode\n" + "\tCONTROL := reclassify|pipe|drop|continue|ok\n" + "\tINDEX := optional IFE table index value used\n"); + fprintf(stderr, "encode is used for sending IFE packets\n"); + fprintf(stderr, "decode is used for receiving IFE packets\n"); +} + +static void ife_usage(void) +{ + ife_explain(); + exit(-1); +} + +static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, + int tca_id, struct nlmsghdr *n) +{ + int argc = *argc_p; + char **argv = *argv_p; + int ok = 0; + struct tc_ife p; + struct rtattr *tail; + struct rtattr *tail2; + char dbuf[ETH_ALEN]; + char sbuf[ETH_ALEN]; + __u16 ife_type = 0; + __u32 ife_prio = 0; + __u32 ife_prio_v = 0; + __u32 ife_mark = 0; + __u32 ife_mark_v = 0; + char *daddr = NULL; + char *saddr = NULL; + + memset(&p, 0, sizeof(p)); + p.action = TC_ACT_PIPE; /* good default */ + + if (argc <= 0) + return -1; + + while (argc > 0) { + if (matches(*argv, "ife") == 0) { + NEXT_ARG(); + continue; + } else if (matches(*argv, "decode") == 0) { + p.flags = IFE_DECODE; /* readability aid */ + ok++; + } else if (matches(*argv, "encode") == 0) { + p.flags = IFE_ENCODE; + ok++; + } else if (matches(*argv, "allow") == 0) { + NEXT_ARG(); + if (matches(*argv, "mark") == 0) { + ife_mark = IFE_META_SKBMARK; + } else if (matches(*argv, "prio") == 0) { + ife_prio = IFE_META_PRIO; + } else { + fprintf(stderr, "Illegal meta define <%s>\n", + *argv); + return -1; + } + } else if (matches(*argv, "use") == 0) { + NEXT_ARG(); + if (matches(*argv, "mark") == 0) { + NEXT_ARG(); + if (get_u32(&ife_mark_v, *argv, 0)) + invarg("ife mark val is invalid", + *argv); + } else if (matches(*argv, "prio") == 0) { + NEXT_ARG(); + if (get_u32(&ife_prio_v, *argv, 0)) + invarg("ife prio val is invalid", + *argv); + } else { + fprintf(stderr, "Illegal meta use type <%s>\n", + *argv); + return -1; + } + } else if (matches(*argv, "type") == 0) { + NEXT_ARG(); + if (get_u16(&ife_type, *argv, 0)) + invarg("ife type is invalid", *argv); + fprintf(stderr, "IFE type 0x%x\n", ife_type); + } else if (matches(*argv, "dst") == 0) { + NEXT_ARG(); + daddr = *argv; + if (sscanf(daddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + dbuf, dbuf + 1, dbuf + 2, + dbuf + 3, dbuf + 4, dbuf + 5) != 6) { + fprintf(stderr, "Invalid mac address %s\n", + daddr); + } + fprintf(stderr, "dst MAC address <%s>\n", daddr); + + } else if (matches(*argv, "src") == 0) { + NEXT_ARG(); + saddr = *argv; + if (sscanf(saddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + sbuf, sbuf + 1, sbuf + 2, + sbuf + 3, sbuf + 4, sbuf + 5) != 6) { + fprintf(stderr, "Invalid mac address %s\n", + saddr); + } + fprintf(stderr, "src MAC address <%s>\n", saddr); + } else if (matches(*argv, "help") == 0) { + ife_usage(); + } else { + break; + } + + argc--; + argv++; + } + + if (argc) { + if (matches(*argv, "reclassify") == 0) { + p.action = TC_ACT_RECLASSIFY; + argc--; + argv++; + } else if (matches(*argv, "pipe") == 0) { + p.action = TC_ACT_PIPE; + argc--; + argv++; + } else if (matches(*argv, "drop") == 0 || + matches(*argv, "shot") == 0) { + p.action = TC_ACT_SHOT; + argc--; + argv++; + } else if (matches(*argv, "continue") == 0) { + p.action = TC_ACT_UNSPEC; + argc--; + argv++; + } else if (matches(*argv, "pass") == 0) { + p.action = TC_ACT_OK; + argc--; + argv++; + } + } + + if (argc) { + if (matches(*argv, "index") == 0) { + NEXT_ARG(); + if (get_u32(&p.index, *argv, 10)) { + fprintf(stderr, "ife: Illegal \"index\"\n"); + return -1; + } + argc--; + argv++; + } + } + + if (!ok) { + fprintf(stderr, "IFE requires decode/encode specified\n"); + ife_usage(); + } + + tail = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, tca_id, NULL, 0); + addattr_l(n, MAX_MSG, TCA_IFE_PARMS, &p, sizeof(p)); + + if (!(p.flags & IFE_ENCODE)) + goto skip_encode; + + if (daddr) + addattr_l(n, MAX_MSG, TCA_IFE_DMAC, dbuf, ETH_ALEN); + if (ife_type) + addattr_l(n, MAX_MSG, TCA_IFE_TYPE, &ife_type, 2); + if (saddr) + addattr_l(n, MAX_MSG, TCA_IFE_SMAC, sbuf, ETH_ALEN); + + tail2 = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, TCA_IFE_METALST, NULL, 0); + if (ife_mark || ife_mark_v) { + if (ife_mark_v) + addattr_l(n, MAX_MSG, IFE_META_SKBMARK, &ife_mark_v, 4); + else + addattr_l(n, MAX_MSG, IFE_META_SKBMARK, NULL, 0); + } + if (ife_prio || ife_prio_v) { + if (ife_prio_v) + addattr_l(n, MAX_MSG, IFE_META_PRIO, &ife_prio_v, 4); + else + addattr_l(n, MAX_MSG, IFE_META_PRIO, NULL, 0); + } + + tail2->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail2; + +skip_encode: + tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail; + + *argc_p = argc; + *argv_p = argv; + return 0; +} + +static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg) +{ + struct tc_ife *p = NULL; + struct rtattr *tb[TCA_IFE_MAX + 1]; + __u16 ife_type = 0; + __u32 mmark = 0; + __u32 mhash = 0; + __u32 mprio = 0; + int has_optional = 0; + SPRINT_BUF(b1); + SPRINT_BUF(b2); + + if (arg == NULL) + return -1; + + parse_rtattr_nested(tb, TCA_IFE_MAX, arg); + + if (tb[TCA_IFE_PARMS] == NULL) { + fprintf(f, "[NULL ife parameters]"); + return -1; + } + p = RTA_DATA(tb[TCA_IFE_PARMS]); + + fprintf(f, "ife %s action %s ", + (p->flags & IFE_ENCODE) ? "encode" : "decode", + action_n2a(p->action, b1, sizeof(b1))); + + if (tb[TCA_IFE_TYPE]) { + ife_type = rta_getattr_u16(tb[TCA_IFE_TYPE]); + has_optional = 1; + fprintf(f, "type 0x%X ", ife_type); + } + + if (has_optional) + fprintf(f, "\n\t "); + + if (tb[TCA_IFE_METALST]) { + struct rtattr *metalist[IFE_META_MAX + 1]; + int len = 0; + + parse_rtattr_nested(metalist, IFE_META_MAX, + tb[TCA_IFE_METALST]); + + if (metalist[IFE_META_SKBMARK]) { + len = RTA_PAYLOAD(metalist[IFE_META_SKBMARK]); + if (len) { + mmark = rta_getattr_u32(metalist[IFE_META_SKBMARK]); + fprintf(f, "use mark %d ", mmark); + } else + fprintf(f, "allow mark "); + } + + if (metalist[IFE_META_HASHID]) { + len = RTA_PAYLOAD(metalist[IFE_META_HASHID]); + if (len) { + mhash = rta_getattr_u32(metalist[IFE_META_HASHID]); + fprintf(f, "use hash %d ", mhash); + } else + fprintf(f, "allow hash "); + } + + if (metalist[IFE_META_PRIO]) { + len = RTA_PAYLOAD(metalist[IFE_META_PRIO]); + if (len) { + mprio = rta_getattr_u32(metalist[IFE_META_PRIO]); + fprintf(f, "use prio %d ", mprio); + } else + fprintf(f, "allow prio "); + } + + } + + if (tb[TCA_IFE_DMAC]) { + has_optional = 1; + fprintf(f, "dst %s ", + ll_addr_n2a(RTA_DATA(tb[TCA_IFE_DMAC]), + RTA_PAYLOAD(tb[TCA_IFE_DMAC]), 0, b2, + sizeof(b2))); + + } + + if (tb[TCA_IFE_SMAC]) { + has_optional = 1; + fprintf(f, "src %s ", + ll_addr_n2a(RTA_DATA(tb[TCA_IFE_SMAC]), + RTA_PAYLOAD(tb[TCA_IFE_SMAC]), 0, b2, + sizeof(b2))); + } + + fprintf(f, "\n\t index %d ref %d bind %d", p->index, p->refcnt, + p->bindcnt); + if (show_stats) { + if (tb[TCA_IFE_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_IFE_TM]); + + print_tm(f, tm); + } + } + + fprintf(f, "\n"); + + return 0; +} + +struct action_util ife_action_util = { + .id = "ife", + .parse_aopt = parse_ife, + .print_aopt = print_ife, +}; From 43726b750a398323a6becdfbea45ae502a180ea8 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sat, 7 May 2016 09:39:36 -0400 Subject: [PATCH 225/513] tc: don't ignore ok as an action branch This is what used to happen before: tc filter add dev tap1 parent ffff: protocol 0xfefe prio 10 \ u32 match u32 0 0 flowid 1:16 \ action ife decode allow mark ok tc -s filter ls dev tap1 parent ffff: filter protocol [65278] pref 10 u32 filter protocol [65278] pref 10 u32 fh 800: ht divisor 1 filter protocol [65278] pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:16 match 00000000/00000000 at 0 action order 1: ife decode action pipe index 2 ref 1 bind 1 installed 4 sec used 4 sec type: 0x0 Metadata: allow mark Action statistics: Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 action order 2: gact action pass random type none pass val 0 index 1 ref 1 bind 1 installed 4 sec used 4 sec Action statistics: Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 Note the extra action added at the end.. Signed-off-by: Jamal Hadi Salim --- tc/m_connmark.c | 3 ++- tc/m_csum.c | 3 ++- tc/m_ife.c | 3 ++- tc/m_mirred.c | 3 ++- tc/m_nat.c | 3 ++- tc/m_pedit.c | 3 ++- tc/m_skbedit.c | 3 ++- tc/m_vlan.c | 3 ++- 8 files changed, 16 insertions(+), 8 deletions(-) diff --git a/tc/m_connmark.c b/tc/m_connmark.c index b1c7d3af5..143d75de6 100644 --- a/tc/m_connmark.c +++ b/tc/m_connmark.c @@ -99,7 +99,8 @@ parse_connmark(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, sel.action = TC_ACT_UNSPEC; argc--; argv++; - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { sel.action = TC_ACT_OK; argc--; argv++; diff --git a/tc/m_csum.c b/tc/m_csum.c index 36181fa1c..fb1183a98 100644 --- a/tc/m_csum.c +++ b/tc/m_csum.c @@ -140,7 +140,8 @@ parse_csum(struct action_util *a, int *argc_p, sel.action = TC_ACT_UNSPEC; argc--; argv++; - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { sel.action = TC_ACT_OK; argc--; argv++; diff --git a/tc/m_ife.c b/tc/m_ife.c index 839e370af..ed01ff724 100644 --- a/tc/m_ife.c +++ b/tc/m_ife.c @@ -167,7 +167,8 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, p.action = TC_ACT_UNSPEC; argc--; argv++; - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { p.action = TC_ACT_OK; argc--; argv++; diff --git a/tc/m_mirred.c b/tc/m_mirred.c index e7e69dfcb..64aad4d22 100644 --- a/tc/m_mirred.c +++ b/tc/m_mirred.c @@ -172,7 +172,8 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, } else if (matches(*argv, "continue") == 0) { p.action = TC_POLICE_UNSPEC; NEXT_ARG(); - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { p.action = TC_POLICE_OK; NEXT_ARG(); } diff --git a/tc/m_nat.c b/tc/m_nat.c index 4b90121c4..4d1b1edfe 100644 --- a/tc/m_nat.c +++ b/tc/m_nat.c @@ -135,7 +135,8 @@ parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct sel.action = TC_ACT_UNSPEC; argc--; argv++; - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { sel.action = TC_ACT_OK; argc--; argv++; diff --git a/tc/m_pedit.c b/tc/m_pedit.c index 2a94dfba7..a539b68bd 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -495,7 +495,8 @@ parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, stru } else if (matches(*argv, "continue") == 0) { sel.sel.action = TC_ACT_UNSPEC; NEXT_ARG(); - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { sel.sel.action = TC_ACT_OK; NEXT_ARG(); } diff --git a/tc/m_skbedit.c b/tc/m_skbedit.c index 180b9cbd6..9ba288c07 100644 --- a/tc/m_skbedit.c +++ b/tc/m_skbedit.c @@ -114,7 +114,8 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, } else if (matches(*argv, "continue") == 0) { sel.action = TC_ACT_UNSPEC; NEXT_ARG(); - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { sel.action = TC_ACT_OK; NEXT_ARG(); } diff --git a/tc/m_vlan.c b/tc/m_vlan.c index 3233d2073..c2684461b 100644 --- a/tc/m_vlan.c +++ b/tc/m_vlan.c @@ -119,7 +119,8 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, parm.action = TC_ACT_UNSPEC; argc--; argv++; - } else if (matches(*argv, "pass") == 0) { + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { parm.action = TC_ACT_OK; argc--; argv++; From fdf1bdd0f14db7b465d93ec09e45e5da70b1c582 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sun, 8 May 2016 11:02:06 -0400 Subject: [PATCH 226/513] tc simple action update and breakage Brings it closer to more serious actions (adding branching and allowing for late binding) Unfortunately this breaks old syntax of the simple action. But because simple is a pedagogical example unlikely to be used in production environments (i.e its role is to serve as an example on how to write actions), then this is ok. New syntax for simple has new keyword "sdata". Example usage is: sudo tc actions add action simple sdata "foobar" index 1 or tc filter add dev $DEV parent ffff: protocol ip prio 1 u32\ match ip dst 17.0.0.1/32 flowid 1:10 action simple sdata "foobar" Signed-off-by: Jamal Hadi Salim --- tc/m_simple.c | 58 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/tc/m_simple.c b/tc/m_simple.c index e167ccae4..feba61b5d 100644 --- a/tc/m_simple.c +++ b/tc/m_simple.c @@ -81,9 +81,10 @@ #endif static void explain(void) { - fprintf(stderr, "Usage: ... simple STRING\n" - "STRING being an arbitrary string\n" - "example: \"simple blah\"\n"); + fprintf(stderr, "Usage:... simple [sdata STRING] [CONTROL] [index INDEX]\n"); + fprintf(stderr, "\tSTRING being an arbitrary string\n" + "\tCONTROL := reclassify|pipe|drop|continue|ok\n" + "\tINDEX := optional index value used\n"); } static void usage(void) @@ -99,56 +100,85 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct tc_defact sel = {}; int argc = *argc_p; char **argv = *argv_p; - int ok = 0; + int ok = 0, maybe_bind = 0; struct rtattr *tail; char *simpdata = NULL; - while (argc > 0) { if (matches(*argv, "simple") == 0) { NEXT_ARG(); + } else if (matches(*argv, "sdata") == 0) { + NEXT_ARG(); + ok += 1; simpdata = *argv; - ok = 1; argc--; argv++; - break; } else if (matches(*argv, "help") == 0) { usage(); } else { break; } - } - if (!ok) { - explain(); - return -1; + if (argc) { + if (matches(*argv, "reclassify") == 0) { + sel.action = TC_ACT_RECLASSIFY; + argc--; + argv++; + } else if (matches(*argv, "pipe") == 0) { + sel.action = TC_ACT_PIPE; + argc--; + argv++; + } else if (matches(*argv, "drop") == 0 || + matches(*argv, "shot") == 0) { + sel.action = TC_ACT_SHOT; + argc--; + argv++; + } else if (matches(*argv, "continue") == 0) { + sel.action = TC_ACT_UNSPEC; + argc--; + argv++; + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { + sel.action = TC_ACT_OK; + argc--; + argv++; + } } if (argc) { if (matches(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&sel.index, *argv, 10)) { - fprintf(stderr, "simple: Illegal \"index\"\n"); + fprintf(stderr, "simple: Illegal \"index\"\n", + *argv); return -1; } + ok += 1; argc--; argv++; } } - if (strlen(simpdata) > (SIMP_MAX_DATA - 1)) { + if (!ok) { + explain(); + return -1; + } + + if (simpdata && (strlen(simpdata) > (SIMP_MAX_DATA - 1))) { fprintf(stderr, "simple: Illegal string len %zu <%s>\n", strlen(simpdata), simpdata); return -1; } + sel.action = TC_ACT_PIPE; tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); addattr_l(n, MAX_MSG, TCA_DEF_PARMS, &sel, sizeof(sel)); - addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA); + if (simpdata) + addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA); tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; *argc_p = argc; From a2de651e64f953911f58129389f2d6674905b561 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sun, 15 May 2016 18:36:03 +0200 Subject: [PATCH 227/513] ingress, clsact: don't add TCA_OPTIONS to nl msg In ingress and clsact qdisc TCA_OPTIONS are ignored, since it's parameterless. In tc, we add an empty addattr_l(... TCA_OPTIONS, NULL, 0) to the netlink message nevertheless. This has the side effect that when someone tries a 'tc qdisc replace' and already an existing such qdisc is present, tc fails with EINVAL here. Reason is that in the kernel, this invokes qdisc_change() when such requested qdisc is already present. When TCA_OPTIONS are passed to modify parameters, it looks whether qdisc implements .change() callback, and if not present (like in both cases here) it returns with error. Rather than adding an empty stub to the kernel that ignores TCA_OPTIONS again, just don't add TCA_OPTIONS to the netlink message in the first place. Before: # tc qdisc replace dev foo clsact # first try # tc qdisc replace dev foo clsact # second one RTNETLINK answers: Invalid argument After: # tc qdisc replace dev foo clsact # tc qdisc replace dev foo clsact # tc qdisc replace dev foo clsact Signed-off-by: Daniel Borkmann --- tc/q_clsact.c | 1 - tc/q_ingress.c | 1 - 2 files changed, 2 deletions(-) diff --git a/tc/q_clsact.c b/tc/q_clsact.c index 0c05dbd33..e2a1a7100 100644 --- a/tc/q_clsact.c +++ b/tc/q_clsact.c @@ -18,7 +18,6 @@ static int clsact_parse_opt(struct qdisc_util *qu, int argc, char **argv, return -1; } - addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); return 0; } diff --git a/tc/q_ingress.c b/tc/q_ingress.c index c3c9b4031..31699a81f 100644 --- a/tc/q_ingress.c +++ b/tc/q_ingress.c @@ -34,7 +34,6 @@ static int ingress_parse_opt(struct qdisc_util *qu, int argc, char **argv, } } - addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); return 0; } From e6d7367d795a41abeea4acc1af8f3885c8918ba7 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 14 May 2016 15:21:01 +0200 Subject: [PATCH 228/513] devlink: implement shared buffer support Implement kernel devlink shared buffer interface. Introduce new object "sb" and allow to browse the shared buffer parameters and also change configuration. Signed-off-by: Jiri Pirko --- devlink/devlink.c | 653 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 652 insertions(+), 1 deletion(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index 89a308317..ca3f58617 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -114,6 +114,13 @@ static void ifname_map_free(struct ifname_map *ifname_map) #define DL_OPT_HANDLEP BIT(1) #define DL_OPT_PORT_TYPE BIT(2) #define DL_OPT_PORT_COUNT BIT(3) +#define DL_OPT_SB BIT(4) +#define DL_OPT_SB_POOL BIT(5) +#define DL_OPT_SB_SIZE BIT(6) +#define DL_OPT_SB_TYPE BIT(7) +#define DL_OPT_SB_THTYPE BIT(8) +#define DL_OPT_SB_TH BIT(9) +#define DL_OPT_SB_TC BIT(10) struct dl_opts { uint32_t present; /* flags of present items */ @@ -122,6 +129,13 @@ struct dl_opts { uint32_t port_index; enum devlink_port_type port_type; uint32_t port_count; + uint32_t sb_index; + uint16_t sb_pool_index; + uint32_t sb_pool_size; + enum devlink_sb_pool_type sb_pool_type; + enum devlink_sb_threshold_type sb_pool_thtype; + uint32_t sb_threshold; + uint16_t sb_tc_index; }; struct dl { @@ -225,6 +239,42 @@ static int attr_cb(const struct nlattr *attr, void *data) if (type == DEVLINK_ATTR_PORT_IBDEV_NAME && mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_INDEX && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_SIZE && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_INGRESS_POOL_COUNT && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_EGRESS_POOL_COUNT && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_INGRESS_TC_COUNT && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_EGRESS_TC_COUNT && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_POOL_INDEX && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_POOL_TYPE && + mnl_attr_validate(attr, MNL_TYPE_U8) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_POOL_SIZE && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE && + mnl_attr_validate(attr, MNL_TYPE_U8) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_THRESHOLD && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_TC_INDEX && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; tb[type] = attr; return MNL_CB_OK; } @@ -307,6 +357,23 @@ static int ifname_map_lookup(struct dl *dl, const char *ifname, return -ENOENT; } +static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name, + const char *dev_name, uint32_t port_index, + char **p_ifname) +{ + struct ifname_map *ifname_map; + + list_for_each_entry(ifname_map, &dl->ifname_map_list, list) { + if (strcmp(bus_name, ifname_map->bus_name) == 0 && + strcmp(dev_name, ifname_map->dev_name) == 0 && + port_index == ifname_map->port_index) { + *p_ifname = ifname_map->ifname; + return 0; + } + } + return -ENOENT; +} + static unsigned int strslashcount(char *str) { unsigned int count = 0; @@ -346,6 +413,20 @@ static int strtouint32_t(const char *str, uint32_t *p_val) return 0; } +static int strtouint16_t(const char *str, uint16_t *p_val) +{ + char *endptr; + unsigned long int val; + + val = strtoul(str, &endptr, 10); + if (endptr == str || *endptr != '\0') + return -EINVAL; + if (val > USHRT_MAX) + return -ERANGE; + *p_val = val; + return 0; +} + static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name) { strslashrsplit(str, p_bus_name, p_dev_name); @@ -486,6 +567,24 @@ static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val) return 0; } +static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val) +{ + char *str = dl_argv_next(dl); + int err; + + if (!str) { + pr_err("Unsigned number argument expected\n"); + return -EINVAL; + } + + err = strtouint16_t(str, p_val); + if (err) { + pr_err("\"%s\" is not a number or not within range\n", str); + return err; + } + return 0; +} + static int dl_argv_str(struct dl *dl, const char **p_str) { const char *str = dl_argv_next(dl); @@ -513,6 +612,33 @@ static int port_type_get(const char *typestr, enum devlink_port_type *p_type) return 0; } +static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type) +{ + if (strcmp(typestr, "ingress") == 0) { + *p_type = DEVLINK_SB_POOL_TYPE_INGRESS; + } else if (strcmp(typestr, "egress") == 0) { + *p_type = DEVLINK_SB_POOL_TYPE_EGRESS; + } else { + pr_err("Unknown pool type \"%s\"\n", typestr); + return -EINVAL; + } + return 0; +} + +static int threshold_type_get(const char *typestr, + enum devlink_sb_threshold_type *p_type) +{ + if (strcmp(typestr, "static") == 0) { + *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC; + } else if (strcmp(typestr, "dynamic") == 0) { + *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC; + } else { + pr_err("Unknown threshold type \"%s\"\n", typestr); + return -EINVAL; + } + return 0; +} + static int dl_argv_parse(struct dl *dl, uint32_t o_required, uint32_t o_optional) { @@ -562,6 +688,66 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, if (err) return err; o_found |= DL_OPT_PORT_COUNT; + } else if (dl_argv_match(dl, "sb") && + (o_all & DL_OPT_SB)) { + dl_arg_inc(dl); + err = dl_argv_uint32_t(dl, &opts->sb_index); + if (err) + return err; + o_found |= DL_OPT_SB; + } else if (dl_argv_match(dl, "pool") && + (o_all & DL_OPT_SB_POOL)) { + dl_arg_inc(dl); + err = dl_argv_uint16_t(dl, &opts->sb_pool_index); + if (err) + return err; + o_found |= DL_OPT_SB_POOL; + } else if (dl_argv_match(dl, "size") && + (o_all & DL_OPT_SB_SIZE)) { + dl_arg_inc(dl); + err = dl_argv_uint32_t(dl, &opts->sb_pool_size); + if (err) + return err; + o_found |= DL_OPT_SB_SIZE; + } else if (dl_argv_match(dl, "type") && + (o_all & DL_OPT_SB_TYPE)) { + const char *typestr; + + dl_arg_inc(dl); + err = dl_argv_str(dl, &typestr); + if (err) + return err; + err = pool_type_get(typestr, &opts->sb_pool_type); + if (err) + return err; + o_found |= DL_OPT_SB_TYPE; + } else if (dl_argv_match(dl, "thtype") && + (o_all & DL_OPT_SB_THTYPE)) { + const char *typestr; + + dl_arg_inc(dl); + err = dl_argv_str(dl, &typestr); + if (err) + return err; + err = threshold_type_get(typestr, + &opts->sb_pool_thtype); + if (err) + return err; + o_found |= DL_OPT_SB_THTYPE; + } else if (dl_argv_match(dl, "th") && + (o_all & DL_OPT_SB_TH)) { + dl_arg_inc(dl); + err = dl_argv_uint32_t(dl, &opts->sb_threshold); + if (err) + return err; + o_found |= DL_OPT_SB_TH; + } else if (dl_argv_match(dl, "tc") && + (o_all & DL_OPT_SB_TC)) { + dl_arg_inc(dl); + err = dl_argv_uint16_t(dl, &opts->sb_tc_index); + if (err) + return err; + o_found |= DL_OPT_SB_TC; } else { pr_err("Unknown option \"%s\"\n", dl_argv(dl)); return -EINVAL; @@ -570,6 +756,11 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, opts->present = o_found; + if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) { + opts->sb_index = 0; + opts->present |= DL_OPT_SB; + } + if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) { pr_err("Port type option expected.\n"); return -EINVAL; @@ -581,6 +772,35 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, return -EINVAL; } + if ((o_required & DL_OPT_SB_POOL) && !(o_found & DL_OPT_SB_POOL)) { + pr_err("Pool index option expected.\n"); + return -EINVAL; + } + + if ((o_required & DL_OPT_SB_SIZE) && !(o_found & DL_OPT_SB_SIZE)) { + pr_err("Pool size option expected.\n"); + return -EINVAL; + } + + if ((o_required & DL_OPT_SB_TYPE) && !(o_found & DL_OPT_SB_TYPE)) { + pr_err("Pool type option expected.\n"); + return -EINVAL; + } + + if ((o_required & DL_OPT_SB_THTYPE) && !(o_found & DL_OPT_SB_THTYPE)) { + pr_err("Pool threshold type option expected.\n"); + return -EINVAL; + } + + if ((o_required & DL_OPT_SB_TH) && !(o_found & DL_OPT_SB_TH)) { + pr_err("Threshold option expected.\n"); + return -EINVAL; + } + + if ((o_required & DL_OPT_SB_TC) && !(o_found & DL_OPT_SB_TC)) { + pr_err("TC index option expected.\n"); + return -EINVAL; + } return 0; } @@ -603,6 +823,27 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) if (opts->present & DL_OPT_PORT_COUNT) mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, opts->port_count); + if (opts->present & DL_OPT_SB) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, + opts->sb_index); + if (opts->present & DL_OPT_SB_POOL) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, + opts->sb_pool_index); + if (opts->present & DL_OPT_SB_SIZE) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE, + opts->sb_pool_size); + if (opts->present & DL_OPT_SB_TYPE) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, + opts->sb_pool_type); + if (opts->present & DL_OPT_SB_THTYPE) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, + opts->sb_pool_thtype); + if (opts->present & DL_OPT_SB_TH) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, + opts->sb_threshold); + if (opts->present & DL_OPT_SB_TC) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, + opts->sb_tc_index); } static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, @@ -648,6 +889,39 @@ static void pr_out_port_handle(struct nlattr **tb) mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); } +static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name, + const char *dev_name, uint32_t port_index) +{ + char *ifname; + int err; + + if (dl->no_nice_names) + goto no_nice_names; + + err = ifname_map_rev_lookup(dl, bus_name, dev_name, + port_index, &ifname); + if (err) + goto no_nice_names; + pr_out("%s", ifname); + return; + +no_nice_names: + __pr_out_port_handle(bus_name, dev_name, port_index); +} + +static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) +{ + const char *bus_name; + const char *dev_name; + uint32_t port_index; + + bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); + dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); + port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); + + __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index); +} + static void pr_out_dev(struct nlattr **tb) { pr_out_handle(tb); @@ -850,6 +1124,380 @@ static int cmd_port(struct dl *dl) return -ENOENT; } +static void cmd_sb_help(void) +{ + pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); + pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); + pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); + pr_out(" size POOL_SIZE thtype { static | dynamic }\n"); + pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); + pr_out(" pool POOL_INDEX ]\n"); + pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); + pr_out(" pool POOL_INDEX th THRESHOLD\n"); + pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); + pr_out(" type { ingress | egress } ]\n"); + pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); + pr_out(" type { ingress | egress } pool POOL_INDEX\n"); + pr_out(" th THRESHOLD\n"); +} + +static void pr_out_sb(struct nlattr **tb) +{ + pr_out_handle(tb); + pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); +} + +static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] || + !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] || + !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] || + !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] || + !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]) + return MNL_CB_ERROR; + pr_out_sb(tb); + return MNL_CB_OK; +} + +static int cmd_sb_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + int err; + + if (dl_argc(dl) == 0) + flags |= NLM_F_DUMP; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags); + + if (dl_argc(dl) > 0) { + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); + if (err) + return err; + } + + return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL); +} + +static const char *pool_type_name(uint8_t type) +{ + switch (type) { + case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress"; + case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress"; + default: return ""; + } +} + +static const char *threshold_type_name(uint8_t type) +{ + switch (type) { + case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static"; + case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic"; + default: return ""; + } +} + +static void pr_out_sb_pool(struct nlattr **tb) +{ + pr_out_handle(tb); + pr_out(": sb %u pool %u type %s size %u thtype %s\n", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), + pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]), + threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); +} + +static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] || + !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] || + !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) + return MNL_CB_ERROR; + pr_out_sb_pool(tb); + return MNL_CB_OK; +} + +static int cmd_sb_pool_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + int err; + + if (dl_argc(dl) == 0) + flags |= NLM_F_DUMP; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags); + + if (dl_argc(dl) > 0) { + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL, + DL_OPT_SB); + if (err) + return err; + } + + return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL); +} + +static int cmd_sb_pool_set(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL | + DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_sb_pool(struct dl *dl) +{ + if (dl_argv_match(dl, "help")) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "show") || + dl_argv_match(dl, "list") || dl_no_arg(dl)) { + dl_arg_inc(dl); + return cmd_sb_pool_show(dl); + } else if (dl_argv_match(dl, "set")) { + dl_arg_inc(dl); + return cmd_sb_pool_set(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb) +{ + pr_out_port_handle_nice(dl, tb); + pr_out(": sb %u pool %u threshold %u\n", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); +} + +static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || + !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) + return MNL_CB_ERROR; + pr_out_sb_port_pool(dl, tb); + return MNL_CB_OK; +} + +static int cmd_sb_port_pool_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + int err; + + if (dl_argc(dl) == 0) + flags |= NLM_F_DUMP; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); + + if (dl_argc(dl) > 0) { + err = dl_argv_parse_put(nlh, dl, + DL_OPT_HANDLEP | DL_OPT_SB_POOL, + DL_OPT_SB); + if (err) + return err; + } + + return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); +} + +static int cmd_sb_port_pool_set(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL | + DL_OPT_SB_TH, DL_OPT_SB); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_sb_port_pool(struct dl *dl) +{ + if (dl_argv_match(dl, "help")) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "show") || + dl_argv_match(dl, "list") || dl_no_arg(dl)) { + dl_arg_inc(dl); + return cmd_sb_port_pool_show(dl); + } else if (dl_argv_match(dl, "set")) { + dl_arg_inc(dl); + return cmd_sb_port_pool_set(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static int cmd_sb_port(struct dl *dl) +{ + if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "pool")) { + dl_arg_inc(dl); + return cmd_sb_port_pool(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb) +{ + pr_out_port_handle_nice(dl, tb); + pr_out(": sb %u tc %u type %s pool %u threshold %u\n", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]), + pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); +} + +static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || + !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || + !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) + return MNL_CB_ERROR; + pr_out_sb_tc_bind(dl, tb); + return MNL_CB_OK; +} + +static int cmd_sb_tc_bind_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + int err; + + if (dl_argc(dl) == 0) + flags |= NLM_F_DUMP; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); + + if (dl_argc(dl) > 0) { + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | + DL_OPT_SB_TYPE, DL_OPT_SB); + if (err) + return err; + } + + return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); +} + +static int cmd_sb_tc_bind_set(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | + DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH, + DL_OPT_SB); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_sb_tc_bind(struct dl *dl) +{ + if (dl_argv_match(dl, "help")) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "show") || + dl_argv_match(dl, "list") || dl_no_arg(dl)) { + dl_arg_inc(dl); + return cmd_sb_tc_bind_show(dl); + } else if (dl_argv_match(dl, "set")) { + dl_arg_inc(dl); + return cmd_sb_tc_bind_set(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static int cmd_sb_tc(struct dl *dl) +{ + if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "bind")) { + dl_arg_inc(dl); + return cmd_sb_tc_bind(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + +static int cmd_sb(struct dl *dl) +{ + if (dl_argv_match(dl, "help")) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "show") || + dl_argv_match(dl, "list") || dl_no_arg(dl)) { + dl_arg_inc(dl); + return cmd_sb_show(dl); + } else if (dl_argv_match(dl, "pool")) { + dl_arg_inc(dl); + return cmd_sb_pool(dl); + } else if (dl_argv_match(dl, "port")) { + dl_arg_inc(dl); + return cmd_sb_port(dl); + } else if (dl_argv_match(dl, "tc")) { + dl_arg_inc(dl); + return cmd_sb_tc(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + static const char *cmd_name(uint8_t cmd) { switch (cmd) { @@ -985,7 +1633,7 @@ static int cmd_mon(struct dl *dl) static void help(void) { pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" - "where OBJECT := { dev | port | monitor }\n" + "where OBJECT := { dev | port | sb | monitor }\n" " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); } @@ -1000,6 +1648,9 @@ static int dl_cmd(struct dl *dl) } else if (dl_argv_match(dl, "port")) { dl_arg_inc(dl); return cmd_port(dl); + } else if (dl_argv_match(dl, "sb")) { + dl_arg_inc(dl); + return cmd_sb(dl); } else if (dl_argv_match(dl, "monitor")) { dl_arg_inc(dl); return cmd_mon(dl); From 25ec49be2cdfa571d5151f19a7395a7e462d2f49 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 14 May 2016 15:21:02 +0200 Subject: [PATCH 229/513] devlink: implement shared buffer occupancy control Use kernel shared buffer occupancy control commands to make snapshot and clear occupancy watermarks. Also, allow to show occupancy values in a nice way. Signed-off-by: Jiri Pirko --- devlink/devlink.c | 378 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 378 insertions(+) diff --git a/devlink/devlink.c b/devlink/devlink.c index ca3f58617..ffefa86d2 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -27,6 +27,12 @@ #define pr_err(args...) fprintf(stderr, ##args) #define pr_out(args...) fprintf(stdout, ##args) +#define pr_out_sp(num, args...) \ + do { \ + int ret = fprintf(stdout, ##args); \ + if (ret < num) \ + fprintf(stdout, "%*s", num - ret, ""); \ + } while (0) static int _mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data) @@ -275,6 +281,12 @@ static int attr_cb(const struct nlattr *attr, void *data) if (type == DEVLINK_ATTR_SB_TC_INDEX && mnl_attr_validate(attr, MNL_TYPE_U16) < 0) return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_OCC_CUR && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_SB_OCC_MAX && + mnl_attr_validate(attr, MNL_TYPE_U32) < 0) + return MNL_CB_ERROR; tb[type] = attr; return MNL_CB_OK; } @@ -858,6 +870,42 @@ static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, return 0; } +static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) +{ + struct dl_opts *opts = &dl->opts; + struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME]; + struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME]; + struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX]; + struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX]; + + if (opts->present & DL_OPT_HANDLE && + attr_bus_name && attr_dev_name) { + const char *bus_name = mnl_attr_get_str(attr_bus_name); + const char *dev_name = mnl_attr_get_str(attr_dev_name); + + if (strcmp(bus_name, opts->bus_name) != 0 || + strcmp(dev_name, opts->dev_name) != 0) + return false; + } + if (opts->present & DL_OPT_HANDLEP && + attr_bus_name && attr_dev_name && attr_port_index) { + const char *bus_name = mnl_attr_get_str(attr_bus_name); + const char *dev_name = mnl_attr_get_str(attr_dev_name); + uint32_t port_index = mnl_attr_get_u32(attr_port_index); + + if (strcmp(bus_name, opts->bus_name) != 0 || + strcmp(dev_name, opts->dev_name) != 0 || + port_index != opts->port_index) + return false; + } + if (opts->present & DL_OPT_SB && attr_sb_index) { + uint32_t sb_index = mnl_attr_get_u32(attr_sb_index); + + if (sb_index != opts->sb_index) + return false; + } + return true; +} static void cmd_dev_help(void) { @@ -1139,6 +1187,9 @@ static void cmd_sb_help(void) pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); pr_out(" type { ingress | egress } pool POOL_INDEX\n"); pr_out(" th THRESHOLD\n"); + pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); + pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); + pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); } static void pr_out_sb(struct nlattr **tb) @@ -1475,6 +1526,330 @@ static int cmd_sb_tc(struct dl *dl) return -ENOENT; } +struct occ_item { + struct list_head list; + uint32_t index; + uint32_t cur; + uint32_t max; + uint32_t bound_pool_index; +}; + +struct occ_port { + struct list_head list; + char *bus_name; + char *dev_name; + uint32_t port_index; + uint32_t sb_index; + struct list_head pool_list; + struct list_head ing_tc_list; + struct list_head eg_tc_list; +}; + +struct occ_show { + struct dl *dl; + int err; + struct list_head port_list; +}; + +static struct occ_item *occ_item_alloc(void) +{ + return calloc(1, sizeof(struct occ_item)); +} + +static void occ_item_free(struct occ_item *occ_item) +{ + free(occ_item); +} + +static struct occ_port *occ_port_alloc(uint32_t port_index) +{ + struct occ_port *occ_port; + + occ_port = calloc(1, sizeof(*occ_port)); + if (!occ_port) + return NULL; + occ_port->port_index = port_index; + INIT_LIST_HEAD(&occ_port->pool_list); + INIT_LIST_HEAD(&occ_port->ing_tc_list); + INIT_LIST_HEAD(&occ_port->eg_tc_list); + return occ_port; +} + +static void occ_port_free(struct occ_port *occ_port) +{ + struct occ_item *occ_item, *tmp; + + list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list) + occ_item_free(occ_item); + list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list) + occ_item_free(occ_item); + list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list) + occ_item_free(occ_item); +} + +static struct occ_show *occ_show_alloc(struct dl *dl) +{ + struct occ_show *occ_show; + + occ_show = calloc(1, sizeof(*occ_show)); + if (!occ_show) + return NULL; + occ_show->dl = dl; + INIT_LIST_HEAD(&occ_show->port_list); + return occ_show; +} + +static void occ_show_free(struct occ_show *occ_show) +{ + struct occ_port *occ_port, *tmp; + + list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list) + occ_port_free(occ_port); +} + +static struct occ_port *occ_port_get(struct occ_show *occ_show, + struct nlattr **tb) +{ + struct occ_port *occ_port; + uint32_t port_index; + + port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); + + list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) { + if (occ_port->port_index == port_index) + return occ_port; + } + occ_port = occ_port_alloc(port_index); + if (!occ_port) + return NULL; + list_add_tail(&occ_port->list, &occ_show->port_list); + return occ_port; +} + +static void pr_out_occ_show_item_list(const char *label, struct list_head *list, + bool bound_pool) +{ + struct occ_item *occ_item; + int i = 1; + + pr_out_sp(7, " %s:", label); + list_for_each_entry(occ_item, list, list) { + if ((i - 1) % 4 == 0 && i != 1) + pr_out_sp(7, " "); + if (bound_pool) + pr_out_sp(7, "%2u(%u):", occ_item->index, + occ_item->bound_pool_index); + else + pr_out_sp(7, "%2u:", occ_item->index); + pr_out_sp(15, "%7u/%u", occ_item->cur, occ_item->max); + if (i++ % 4 == 0) + pr_out("\n"); + } + if ((i - 1) % 4 != 0) + pr_out("\n"); +} + +static void pr_out_occ_show_port(struct occ_port *occ_port) +{ + pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); + pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); + pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); +} + +static void pr_out_occ_show(struct occ_show *occ_show) +{ + struct dl *dl = occ_show->dl; + struct dl_opts *opts = &dl->opts; + struct occ_port *occ_port; + + list_for_each_entry(occ_port, &occ_show->port_list, list) { + __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name, + occ_port->port_index); + pr_out(":\n"); + pr_out_occ_show_port(occ_port); + } +} + +static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show, + struct nlattr **tb) +{ + struct occ_port *occ_port; + struct occ_item *occ_item; + + if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) + return; + + occ_port = occ_port_get(occ_show, tb); + if (!occ_port) { + occ_show->err = -ENOMEM; + return; + } + + occ_item = occ_item_alloc(); + if (!occ_item) { + occ_show->err = -ENOMEM; + return; + } + occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); + occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); + occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); + list_add_tail(&occ_item->list, &occ_port->pool_list); +} + +static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data) +{ + struct occ_show *occ_show = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || + !tb[DEVLINK_ATTR_SB_POOL_INDEX] || + !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) + return MNL_CB_ERROR; + cmd_sb_occ_port_pool_process(occ_show, tb); + return MNL_CB_OK; +} + +static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show, + struct nlattr **tb) +{ + struct occ_port *occ_port; + struct occ_item *occ_item; + uint8_t pool_type; + + if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) + return; + + occ_port = occ_port_get(occ_show, tb); + if (!occ_port) { + occ_show->err = -ENOMEM; + return; + } + + occ_item = occ_item_alloc(); + if (!occ_item) { + occ_show->err = -ENOMEM; + return; + } + occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]); + occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); + occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); + occ_item->bound_pool_index = + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); + pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]); + if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS) + list_add_tail(&occ_item->list, &occ_port->ing_tc_list); + else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS) + list_add_tail(&occ_item->list, &occ_port->eg_tc_list); + else + occ_item_free(occ_item); +} + +static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data) +{ + struct occ_show *occ_show = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || + !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || + !tb[DEVLINK_ATTR_SB_POOL_INDEX] || + !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) + return MNL_CB_ERROR; + cmd_sb_occ_tc_pool_process(occ_show, tb); + return MNL_CB_OK; +} + +static int cmd_sb_occ_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + struct occ_show *occ_show; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP; + int err; + + err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB); + if (err) + return err; + + occ_show = occ_show_alloc(dl); + if (!occ_show) + return -ENOMEM; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); + + err = _mnlg_socket_sndrcv(dl->nlg, nlh, + cmd_sb_occ_port_pool_process_cb, occ_show); + if (err) + goto out; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); + + err = _mnlg_socket_sndrcv(dl->nlg, nlh, + cmd_sb_occ_tc_pool_process_cb, occ_show); + if (err) + goto out; + + pr_out_occ_show(occ_show); + +out: + occ_show_free(occ_show); + return err; +} + +static int cmd_sb_occ_snapshot(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_sb_occ_clearmax(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_sb_occ(struct dl *dl) +{ + if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { + cmd_sb_help(); + return 0; + } else if (dl_argv_match(dl, "show") || + dl_argv_match(dl, "list")) { + dl_arg_inc(dl); + return cmd_sb_occ_show(dl); + } else if (dl_argv_match(dl, "snapshot")) { + dl_arg_inc(dl); + return cmd_sb_occ_snapshot(dl); + } else if (dl_argv_match(dl, "clearmax")) { + dl_arg_inc(dl); + return cmd_sb_occ_clearmax(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + static int cmd_sb(struct dl *dl) { if (dl_argv_match(dl, "help")) { @@ -1493,6 +1868,9 @@ static int cmd_sb(struct dl *dl) } else if (dl_argv_match(dl, "tc")) { dl_arg_inc(dl); return cmd_sb_tc(dl); + } else if (dl_argv_match(dl, "occupancy")) { + dl_arg_inc(dl); + return cmd_sb_occ(dl); } pr_err("Command \"%s\" not found\n", dl_argv(dl)); return -ENOENT; From b0a4ce620e4167428027abc1246f57c4086d99fa Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 11 May 2016 06:51:58 -0700 Subject: [PATCH 230/513] ip link: Add support for kernel side filtering Kernel gained support for filtering link dumps with commit dc599f76c22b ("net: Add support for filtering link dump by master device and kind"). Add support to ip link command. If a user passes master device or kind to ip link command they are added to the link dump request message. Signed-off-by: David Ahern --- include/libnetlink.h | 6 ++++++ ip/ipaddress.c | 33 ++++++++++++++++++++++++++++++++- lib/libnetlink.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/include/libnetlink.h b/include/libnetlink.h index 491263f7e..f7b85dcce 100644 --- a/include/libnetlink.h +++ b/include/libnetlink.h @@ -38,6 +38,12 @@ int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type) int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int fam, int type, __u32 filt_mask) __attribute__((warn_unused_result)); + +typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen); + +int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int fam, int type, + req_filter_fn_t fn) + __attribute__((warn_unused_result)); int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) __attribute__((warn_unused_result)); diff --git a/ip/ipaddress.c b/ip/ipaddress.c index aac7970e1..0692fbacd 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -1476,6 +1476,36 @@ static int ipaddr_flush(void) return 1; } +static int iplink_filter_req(struct nlmsghdr *nlh, int reqlen) +{ + int err; + + err = addattr32(nlh, reqlen, IFLA_EXT_MASK, RTEXT_FILTER_VF); + if (err) + return err; + + if (filter.master) { + err = addattr32(nlh, reqlen, IFLA_MASTER, filter.master); + if (err) + return err; + } + + if (filter.kind) { + struct rtattr *linkinfo; + + linkinfo = addattr_nest(nlh, reqlen, IFLA_LINKINFO); + + err = addattr_l(nlh, reqlen, IFLA_INFO_KIND, filter.kind, + strlen(filter.kind)); + if (err) + return err; + + addattr_nest_end(nlh, linkinfo); + } + + return 0; +} + static int ipaddr_list_flush_or_save(int argc, char **argv, int action) { struct nlmsg_chain linfo = { NULL, NULL}; @@ -1638,7 +1668,8 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) exit(0); } - if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) { + if (rtnl_wilddump_req_filter_fn(&rth, preferred_family, RTM_GETLINK, + iplink_filter_req) < 0) { perror("Cannot send dump request"); exit(1); } diff --git a/lib/libnetlink.c b/lib/libnetlink.c index a90e52ca2..0adcbf3f6 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -129,6 +129,34 @@ int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int family, int type, return send(rth->fd, (void*)&req, sizeof(req), 0); } +int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int family, int type, + req_filter_fn_t filter_fn) +{ + struct { + struct nlmsghdr nlh; + struct ifinfomsg ifm; + char buf[1024]; + } req; + int err; + + if (!filter_fn) + return -EINVAL; + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.nlh.nlmsg_type = type; + req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = rth->dump = ++rth->seq; + req.ifm.ifi_family = family; + + err = filter_fn(&req.nlh, sizeof(req)); + if (err) + return err; + + return send(rth->fd, (void*)&req, sizeof(req), 0); +} + int rtnl_send(struct rtnl_handle *rth, const void *buf, int len) { return send(rth->fd, buf, len, 0); From bbe2abdf3d8203620a4ec067ca4b8e709d37acd8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 18 May 2016 11:56:02 -0700 Subject: [PATCH 231/513] vv4.6.0 --- include/SNAPSHOT.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/SNAPSHOT.h b/include/SNAPSHOT.h index 9220f778e..cc67058f5 100644 --- a/include/SNAPSHOT.h +++ b/include/SNAPSHOT.h @@ -1 +1 @@ -static const char SNAPSHOT[] = "160314"; +static const char SNAPSHOT[] = "160518"; From 0a99e7badf3c301791f1dedf2877231759eb0a94 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 23 May 2016 09:06:11 -0700 Subject: [PATCH 232/513] update kernel headers (from 4.7-rc1) --- include/linux/libc-compat.h | 2 +- include/linux/pkt_cls.h | 4 ++++ include/linux/tc_act/tc_ife.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/linux/libc-compat.h b/include/linux/libc-compat.h index b3c208512..2280d3f1c 100644 --- a/include/linux/libc-compat.h +++ b/include/linux/libc-compat.h @@ -52,7 +52,7 @@ #if defined(__GLIBC__) /* Coordinate with glibc net/if.h header. */ -#if defined(_NET_IF_H) +#if defined(_NET_IF_H) && defined(__USE_MISC) /* GLIBC headers included first so don't define anything * that would already be defined. */ diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index 036283214..25b8743ca 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -97,6 +97,10 @@ enum { #define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1) +/* tca flags definitions */ +#define TCA_CLS_FLAGS_SKIP_HW (1 << 0) +#define TCA_CLS_FLAGS_SKIP_SW (1 << 1) + /* U32 filters */ #define TC_U32_HTID(h) ((h)&0xFFF00000) diff --git a/include/linux/tc_act/tc_ife.h b/include/linux/tc_act/tc_ife.h index d648ff665..4ece02a77 100644 --- a/include/linux/tc_act/tc_ife.h +++ b/include/linux/tc_act/tc_ife.h @@ -23,6 +23,7 @@ enum { TCA_IFE_SMAC, TCA_IFE_TYPE, TCA_IFE_METALST, + TCA_IFE_PAD, __TCA_IFE_MAX }; #define TCA_IFE_MAX (__TCA_IFE_MAX - 1) From 5c33c9592412216eec32d3a8b1c21c03311c79fc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 23 May 2016 16:10:43 -0700 Subject: [PATCH 233/513] add if_macsec header Current version from 4.7-pre-rc1 --- include/linux/if_macsec.h | 169 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 include/linux/if_macsec.h diff --git a/include/linux/if_macsec.h b/include/linux/if_macsec.h new file mode 100644 index 000000000..cbd4faa35 --- /dev/null +++ b/include/linux/if_macsec.h @@ -0,0 +1,169 @@ +/* + * include/uapi/linux/if_macsec.h - MACsec device + * + * Copyright (c) 2015 Sabrina Dubroca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _MACSEC_H +#define _MACSEC_H + +#include + +#define MACSEC_GENL_NAME "macsec" +#define MACSEC_GENL_VERSION 1 + +#define MACSEC_MAX_KEY_LEN 128 + +#define MACSEC_KEYID_LEN 16 + +#define MACSEC_DEFAULT_CIPHER_ID 0x0080020001000001ULL +#define MACSEC_DEFAULT_CIPHER_ALT 0x0080C20001000001ULL + +#define MACSEC_MIN_ICV_LEN 8 +#define MACSEC_MAX_ICV_LEN 32 + +enum macsec_attrs { + MACSEC_ATTR_UNSPEC, + MACSEC_ATTR_IFINDEX, /* u32, ifindex of the MACsec netdevice */ + MACSEC_ATTR_RXSC_CONFIG, /* config, nested macsec_rxsc_attrs */ + MACSEC_ATTR_SA_CONFIG, /* config, nested macsec_sa_attrs */ + MACSEC_ATTR_SECY, /* dump, nested macsec_secy_attrs */ + MACSEC_ATTR_TXSA_LIST, /* dump, nested, macsec_sa_attrs for each TXSA */ + MACSEC_ATTR_RXSC_LIST, /* dump, nested, macsec_rxsc_attrs for each RXSC */ + MACSEC_ATTR_TXSC_STATS, /* dump, nested, macsec_txsc_stats_attr */ + MACSEC_ATTR_SECY_STATS, /* dump, nested, macsec_secy_stats_attr */ + __MACSEC_ATTR_END, + NUM_MACSEC_ATTR = __MACSEC_ATTR_END, + MACSEC_ATTR_MAX = __MACSEC_ATTR_END - 1, +}; + +enum macsec_secy_attrs { + MACSEC_SECY_ATTR_UNSPEC, + MACSEC_SECY_ATTR_SCI, + MACSEC_SECY_ATTR_ENCODING_SA, + MACSEC_SECY_ATTR_WINDOW, + MACSEC_SECY_ATTR_CIPHER_SUITE, + MACSEC_SECY_ATTR_ICV_LEN, + MACSEC_SECY_ATTR_PROTECT, + MACSEC_SECY_ATTR_REPLAY, + MACSEC_SECY_ATTR_OPER, + MACSEC_SECY_ATTR_VALIDATE, + MACSEC_SECY_ATTR_ENCRYPT, + MACSEC_SECY_ATTR_INC_SCI, + MACSEC_SECY_ATTR_ES, + MACSEC_SECY_ATTR_SCB, + MACSEC_SECY_ATTR_PAD, + __MACSEC_SECY_ATTR_END, + NUM_MACSEC_SECY_ATTR = __MACSEC_SECY_ATTR_END, + MACSEC_SECY_ATTR_MAX = __MACSEC_SECY_ATTR_END - 1, +}; + +enum macsec_rxsc_attrs { + MACSEC_RXSC_ATTR_UNSPEC, + MACSEC_RXSC_ATTR_SCI, /* config/dump, u64 */ + MACSEC_RXSC_ATTR_ACTIVE, /* config/dump, u8 0..1 */ + MACSEC_RXSC_ATTR_SA_LIST, /* dump, nested */ + MACSEC_RXSC_ATTR_STATS, /* dump, nested, macsec_rxsc_stats_attr */ + MACSEC_RXSC_ATTR_PAD, + __MACSEC_RXSC_ATTR_END, + NUM_MACSEC_RXSC_ATTR = __MACSEC_RXSC_ATTR_END, + MACSEC_RXSC_ATTR_MAX = __MACSEC_RXSC_ATTR_END - 1, +}; + +enum macsec_sa_attrs { + MACSEC_SA_ATTR_UNSPEC, + MACSEC_SA_ATTR_AN, /* config/dump, u8 0..3 */ + MACSEC_SA_ATTR_ACTIVE, /* config/dump, u8 0..1 */ + MACSEC_SA_ATTR_PN, /* config/dump, u32 */ + MACSEC_SA_ATTR_KEY, /* config, data */ + MACSEC_SA_ATTR_KEYID, /* config/dump, 128-bit */ + MACSEC_SA_ATTR_STATS, /* dump, nested, macsec_sa_stats_attr */ + MACSEC_SA_ATTR_PAD, + __MACSEC_SA_ATTR_END, + NUM_MACSEC_SA_ATTR = __MACSEC_SA_ATTR_END, + MACSEC_SA_ATTR_MAX = __MACSEC_SA_ATTR_END - 1, +}; + +enum macsec_nl_commands { + MACSEC_CMD_GET_TXSC, + MACSEC_CMD_ADD_RXSC, + MACSEC_CMD_DEL_RXSC, + MACSEC_CMD_UPD_RXSC, + MACSEC_CMD_ADD_TXSA, + MACSEC_CMD_DEL_TXSA, + MACSEC_CMD_UPD_TXSA, + MACSEC_CMD_ADD_RXSA, + MACSEC_CMD_DEL_RXSA, + MACSEC_CMD_UPD_RXSA, +}; + +/* u64 per-RXSC stats */ +enum macsec_rxsc_stats_attr { + MACSEC_RXSC_STATS_ATTR_UNSPEC, + MACSEC_RXSC_STATS_ATTR_IN_OCTETS_VALIDATED, + MACSEC_RXSC_STATS_ATTR_IN_OCTETS_DECRYPTED, + MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNCHECKED, + MACSEC_RXSC_STATS_ATTR_IN_PKTS_DELAYED, + MACSEC_RXSC_STATS_ATTR_IN_PKTS_OK, + MACSEC_RXSC_STATS_ATTR_IN_PKTS_INVALID, + MACSEC_RXSC_STATS_ATTR_IN_PKTS_LATE, + MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_VALID, + MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_USING_SA, + MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNUSED_SA, + MACSEC_RXSC_STATS_ATTR_PAD, + __MACSEC_RXSC_STATS_ATTR_END, + NUM_MACSEC_RXSC_STATS_ATTR = __MACSEC_RXSC_STATS_ATTR_END, + MACSEC_RXSC_STATS_ATTR_MAX = __MACSEC_RXSC_STATS_ATTR_END - 1, +}; + +/* u32 per-{RX,TX}SA stats */ +enum macsec_sa_stats_attr { + MACSEC_SA_STATS_ATTR_UNSPEC, + MACSEC_SA_STATS_ATTR_IN_PKTS_OK, + MACSEC_SA_STATS_ATTR_IN_PKTS_INVALID, + MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_VALID, + MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_USING_SA, + MACSEC_SA_STATS_ATTR_IN_PKTS_UNUSED_SA, + MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED, + MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED, + __MACSEC_SA_STATS_ATTR_END, + NUM_MACSEC_SA_STATS_ATTR = __MACSEC_SA_STATS_ATTR_END, + MACSEC_SA_STATS_ATTR_MAX = __MACSEC_SA_STATS_ATTR_END - 1, +}; + +/* u64 per-TXSC stats */ +enum macsec_txsc_stats_attr { + MACSEC_TXSC_STATS_ATTR_UNSPEC, + MACSEC_TXSC_STATS_ATTR_OUT_PKTS_PROTECTED, + MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED, + MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED, + MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED, + MACSEC_TXSC_STATS_ATTR_PAD, + __MACSEC_TXSC_STATS_ATTR_END, + NUM_MACSEC_TXSC_STATS_ATTR = __MACSEC_TXSC_STATS_ATTR_END, + MACSEC_TXSC_STATS_ATTR_MAX = __MACSEC_TXSC_STATS_ATTR_END - 1, +}; + +/* u64 per-SecY stats */ +enum macsec_secy_stats_attr { + MACSEC_SECY_STATS_ATTR_UNSPEC, + MACSEC_SECY_STATS_ATTR_OUT_PKTS_UNTAGGED, + MACSEC_SECY_STATS_ATTR_IN_PKTS_UNTAGGED, + MACSEC_SECY_STATS_ATTR_OUT_PKTS_TOO_LONG, + MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_TAG, + MACSEC_SECY_STATS_ATTR_IN_PKTS_BAD_TAG, + MACSEC_SECY_STATS_ATTR_IN_PKTS_UNKNOWN_SCI, + MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_SCI, + MACSEC_SECY_STATS_ATTR_IN_PKTS_OVERRUN, + MACSEC_SECY_STATS_ATTR_PAD, + __MACSEC_SECY_STATS_ATTR_END, + NUM_MACSEC_SECY_STATS_ATTR = __MACSEC_SECY_STATS_ATTR_END, + MACSEC_SECY_STATS_ATTR_MAX = __MACSEC_SECY_STATS_ATTR_END - 1, +}; + +#endif /* _MACSEC_H */ From 110e84a0589a54309a23e9b1fe333a7b72cc14d9 Mon Sep 17 00:00:00 2001 From: Kylie McClain Date: Sun, 22 May 2016 19:52:02 -0400 Subject: [PATCH 234/513] ipaddress: fix build with musl libc MIN() is defined within sys/param.h. Signed-off-by: Kylie McClain --- ip/ipaddress.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 0692fbacd..df363b070 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include From 1a0320727c6e4b55ff3ec02979a29fd275fa6291 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 18 May 2016 11:58:41 +0200 Subject: [PATCH 235/513] f_bpf: fix filling of handle when no further arg is provided We need to fill handle when provided by the user, even if no further argument is provided. Thus, move the test for arg to the correct location, so that it works correctly: # tc filter show dev foo egress filter protocol all pref 1 bpf filter protocol all pref 1 bpf handle 0x1 bpf.o:[classifier] direct-action filter protocol all pref 1 bpf handle 0x2 bpf.o:[classifier] direct-action # tc filter del dev foo egress prio 1 handle 2 bpf # tc filter show dev foo egress filter protocol all pref 1 bpf filter protocol all pref 1 bpf handle 0x1 bpf.o:[classifier] direct-action Signed-off-by: Daniel Borkmann --- tc/f_bpf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tc/f_bpf.c b/tc/f_bpf.c index afc2e582c..5c97c863d 100644 --- a/tc/f_bpf.c +++ b/tc/f_bpf.c @@ -71,9 +71,6 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle, struct rtattr *tail; int ret = 0; - if (argc == 0) - return 0; - if (handle) { if (get_u32(&t->tcm_handle, handle, 0)) { fprintf(stderr, "Illegal \"handle\"\n"); @@ -81,6 +78,9 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle, } } + if (argc == 0) + return 0; + tail = (struct rtattr *)(((void *)n) + NLMSG_ALIGN(n->nlmsg_len)); addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); From a78a2dba27b5c7b752dcb493043ec1e91f46ad63 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sun, 22 May 2016 13:11:16 -0400 Subject: [PATCH 236/513] tc fix ife late binding following late binding didn't work sudo tc actions add action ife encode \ type 0xDEAD allow mark dst 02:15:15:15:15:15 index 1 Signed-off-by: Jamal Hadi Salim --- tc/m_ife.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tc/m_ife.c b/tc/m_ife.c index ed01ff724..c8ae04d30 100644 --- a/tc/m_ife.c +++ b/tc/m_ife.c @@ -182,6 +182,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, fprintf(stderr, "ife: Illegal \"index\"\n"); return -1; } + ok++; argc--; argv++; } From 4273f100edb812477cff3a89d9f52f573665ab94 Mon Sep 17 00:00:00 2001 From: Peter Heise Date: Mon, 30 May 2016 15:32:07 +0200 Subject: [PATCH 237/513] Added support for selection of new HSR version A new HSR version was added in 4.7 that can be enabled via iproute2. Per default the old version is selected, however, with "ip link add [..] type hsr [..] version 1" the newer version can be enabled. Signed-off-by: Peter Heise --- ip/iplink_hsr.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ip/iplink_hsr.c b/ip/iplink_hsr.c index 65fbec8e5..cb744ebf9 100644 --- a/ip/iplink_hsr.c +++ b/ip/iplink_hsr.c @@ -25,7 +25,7 @@ static void print_usage(FILE *f) { fprintf(f, "Usage:\tip link add name NAME type hsr slave1 SLAVE1-IF slave2 SLAVE2-IF\n" -"\t[ supervision ADDR-BYTE ]\n" +"\t[ supervision ADDR-BYTE ] [version VERSION]\n" "\n" "NAME\n" " name of new hsr device (e.g. hsr0)\n" @@ -33,7 +33,9 @@ static void print_usage(FILE *f) " the two slave devices bound to the HSR device\n" "ADDR-BYTE\n" " 0-255; the last byte of the multicast address used for HSR supervision\n" -" frames (default = 0)\n"); +" frames (default = 0)\n" +"VERSION\n" +" 0,1; the protocol version to be used. (default = 0)\n"); } static void usage(void) @@ -46,6 +48,7 @@ static int hsr_parse_opt(struct link_util *lu, int argc, char **argv, { int ifindex; unsigned char multicast_spec; + unsigned char protocol_version; while (argc > 0) { if (matches(*argv, "supervision") == 0) { @@ -54,6 +57,13 @@ static int hsr_parse_opt(struct link_util *lu, int argc, char **argv, invarg("ADDR-BYTE is invalid", *argv); addattr_l(n, 1024, IFLA_HSR_MULTICAST_SPEC, &multicast_spec, 1); + } else if (matches(*argv, "version") == 0) { + NEXT_ARG(); + if (!(get_u8(&protocol_version, *argv, 0) == 0 || + get_u8(&protocol_version, *argv, 0) == 1)) + invarg("version is invalid", *argv); + addattr_l(n, 1024, IFLA_HSR_VERSION, + &protocol_version, 1); } else if (matches(*argv, "slave1") == 0) { NEXT_ARG(); ifindex = ll_name_to_index(*argv); From f8daee42a51c62490135ba1847f83e3b9832fa98 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 24 May 2016 00:47:38 +0200 Subject: [PATCH 238/513] ip, token: add del command For convenience also add a del command for deleting a token and update the man page accordingly. Signed-off-by: Daniel Borkmann --- ip/iptoken.c | 26 ++++++++++++++------------ man/man8/ip-token.8 | 13 +++++++++++-- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/ip/iptoken.c b/ip/iptoken.c index 6e1a1ab7f..722b526ad 100644 --- a/ip/iptoken.c +++ b/ip/iptoken.c @@ -38,7 +38,7 @@ static void usage(void) __attribute__((noreturn)); static void usage(void) { - fprintf(stderr, "Usage: ip token [ list | set | get ] [ TOKEN ] [ dev DEV ]\n"); + fprintf(stderr, "Usage: ip token [ list | set | del | get ] [ TOKEN ] [ dev DEV ]\n"); exit(-1); } @@ -117,7 +117,7 @@ static int iptoken_list(int argc, char **argv) return 0; } -static int iptoken_set(int argc, char **argv) +static int iptoken_set(int argc, char **argv, bool delete) { struct { struct nlmsghdr n; @@ -125,10 +125,9 @@ static int iptoken_set(int argc, char **argv) char buf[512]; } req; struct rtattr *afs, *afs6; - bool have_token = false, have_dev = false; - inet_prefix addr; + bool have_token = delete, have_dev = false; + inet_prefix addr = { .bytelen = 16, }; - memset(&addr, 0, sizeof(addr)); memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); @@ -149,13 +148,7 @@ static int iptoken_set(int argc, char **argv) if (matches(*argv, "help") == 0) usage(); if (!have_token) { - afs = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC); - afs6 = addattr_nest(&req.n, sizeof(req), AF_INET6); get_prefix(&addr, *argv, req.ifi.ifi_family); - addattr_l(&req.n, sizeof(req), IFLA_INET6_TOKEN, - &addr.data, addr.bytelen); - addattr_nest_end(&req.n, afs6); - addattr_nest_end(&req.n, afs); have_token = true; } } @@ -171,6 +164,13 @@ static int iptoken_set(int argc, char **argv) return -1; } + afs = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC); + afs6 = addattr_nest(&req.n, sizeof(req), AF_INET6); + addattr_l(&req.n, sizeof(req), IFLA_INET6_TOKEN, + &addr.data, addr.bytelen); + addattr_nest_end(&req.n, afs6); + addattr_nest_end(&req.n, afs); + if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) return -2; @@ -189,7 +189,9 @@ int do_iptoken(int argc, char **argv) return iptoken_list(argc - 1, argv + 1); } else if (matches(argv[0], "set") == 0 || matches(argv[0], "add") == 0) { - return iptoken_set(argc - 1, argv + 1); + return iptoken_set(argc - 1, argv + 1, false); + } else if (matches(argv[0], "delete") == 0) { + return iptoken_set(argc - 1, argv + 1, true); } else if (matches(argv[0], "get") == 0) { return iptoken_list(argc - 1, argv + 1); } else if (matches(argv[0], "help") == 0) diff --git a/man/man8/ip-token.8 b/man/man8/ip-token.8 index 260f366af..6505b8c51 100644 --- a/man/man8/ip-token.8 +++ b/man/man8/ip-token.8 @@ -17,6 +17,10 @@ ip-token \- tokenized interface identifier support .B dev .IR DEV +.ti -8 +.B ip token del dev +.IR DEV + .ti -8 .B ip token get .RB "[ " dev @@ -37,8 +41,7 @@ IPv6 Identifiers are described in the draft [1]: . .SS ip token set - set an interface token -set the interface token to the kernel. Once a token is set, it cannot be -removed from the interface, only overwritten. +set the interface token to the kernel. .TP .I TOKEN the interface identifier token address. @@ -46,6 +49,12 @@ the interface identifier token address. .BI dev " DEV" the networking interface. +.SS ip token del - delete an interface token +delete the interface token from the kernel. +.TP +.BI dev " DEV" +the networking interface. + .SS ip token get - get the interface token from the kernel show a tokenized interface identifier of a particular networking device. .B Arguments: From e70b9f16ea5d461729e87e2b1ca927749bfb4f87 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Tue, 24 May 2016 07:52:48 -0400 Subject: [PATCH 239/513] tc simple action: bug fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Failed compile m_simple.c: In function ‘parse_simple’: m_simple.c:154:6: warning: too many arguments for format [-Wformat-extra-args] *argv); ^ m_simple.c:103:14: warning: unused variable ‘maybe_bind’ [-Wunused-variable] Reported-by: Daniel Borkmann Signed-off-by: Jamal Hadi Salim --- tc/m_simple.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tc/m_simple.c b/tc/m_simple.c index feba61b5d..27b3e5e40 100644 --- a/tc/m_simple.c +++ b/tc/m_simple.c @@ -100,7 +100,7 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct tc_defact sel = {}; int argc = *argc_p; char **argv = *argv_p; - int ok = 0, maybe_bind = 0; + int ok = 0; struct rtattr *tail; char *simpdata = NULL; @@ -150,7 +150,7 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, if (matches(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&sel.index, *argv, 10)) { - fprintf(stderr, "simple: Illegal \"index\"\n", + fprintf(stderr, "simple: Illegal \"index\" (%s)\n", *argv); return -1; } @@ -171,7 +171,6 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, return -1; } - sel.action = TC_ACT_PIPE; tail = NLMSG_TAIL(n); From 57bdf8b76451db9de7a9becf32a8ec1c101fa294 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 24 May 2016 15:04:49 -0700 Subject: [PATCH 240/513] Make builds default to quiet mode Similar to the Linux kernel and perf add infrastructure to reduce the amount of output tossed to a user during a build. Full build output can be obtained with 'make V=1' Builds go from: make[1]: Leaving directory `/home/dsa/iproute2.git/lib' make[1]: Entering directory `/home/dsa/iproute2.git/ip' gcc -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wold-style-definition -Wformat=2 -O2 -I../include -DRESOLVE_HOSTNAMES -DLIBDIR=\"/usr/lib\" -DCONFDIR=\"/etc/iproute2\" -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -c -o ip.o ip.c gcc -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wold-style-definition -Wformat=2 -O2 -I../include -DRESOLVE_HOSTNAMES -DLIBDIR=\"/usr/lib\" -DCONFDIR=\"/etc/iproute2\" -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -c -o ipaddress.o ipaddress.c to: ... AR libutil.a ip CC ip.o CC ipaddress.o ... Signed-off-by: David Ahern --- Makefile | 6 +++++- bridge/Makefile | 1 + configure | 32 ++++++++++++++++++++++++++++++++ devlink/Makefile | 1 + genl/Makefile | 1 + ip/Makefile | 2 ++ lib/Makefile | 4 ++-- misc/Makefile | 12 +++++++----- tc/Makefile | 15 ++++++++------- tipc/Makefile | 1 + 10 files changed, 60 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index eb571a5ac..15c81ecfd 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,7 @@ +ifndef VERBOSE +MAKEFLAGS += --no-print-directory +endif + PREFIX?=/usr LIBDIR?=$(PREFIX)/lib SBINDIR?=/sbin @@ -50,7 +54,7 @@ LDLIBS += $(LIBNETLINK) all: Config @set -e; \ for i in $(SUBDIRS); \ - do $(MAKE) $(MFLAGS) -C $$i; done + do echo; echo $$i; $(MAKE) $(MFLAGS) -C $$i; done Config: sh configure $(KERNEL_INCLUDE) diff --git a/bridge/Makefile b/bridge/Makefile index 980075302..7203f70bc 100644 --- a/bridge/Makefile +++ b/bridge/Makefile @@ -9,6 +9,7 @@ endif all: bridge bridge: $(BROBJ) $(LIBNETLINK) + $(QUIET_LINK)$(CC) $^ $(LDFLAGS) $(LDLIBS) -o $@ install: all install -m 0755 bridge $(DESTDIR)$(SBINDIR) diff --git a/configure b/configure index d2540b0d3..60eb6b51a 100755 --- a/configure +++ b/configure @@ -317,7 +317,35 @@ EOF rm -f $TMPDIR/dbtest.c $TMPDIR/dbtest } +quiet_config() +{ + cat <Config +quiet_config >> Config + check_toolchain echo "TC schedulers" @@ -357,3 +385,7 @@ echo echo -n "docs:" check_docs echo + +echo >> Config +echo "%.o: %.c" >> Config +echo ' $(QUIET_CC)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<' >> Config diff --git a/devlink/Makefile b/devlink/Makefile index 3fdaa6904..7256c2870 100644 --- a/devlink/Makefile +++ b/devlink/Makefile @@ -12,6 +12,7 @@ endif all: $(TARGETS) $(LIBS) devlink: $(DEVLINKOBJ) + $(QUIET_LINK)$(CC) $^ $(LDFLAGS) $(LDLIBS) -o $@ install: all install -m 0755 $(TARGETS) $(DESTDIR)$(SBINDIR) diff --git a/genl/Makefile b/genl/Makefile index 03d1f26a1..f5a0bfe42 100644 --- a/genl/Makefile +++ b/genl/Makefile @@ -20,6 +20,7 @@ endif all: genl genl: $(GENLOBJ) $(LIBNETLINK) $(LIBUTIL) $(GENLLIB) + $(QUIET_LINK)$(CC) $^ $(LDFLAGS) $(LDLIBS) -o $@ install: all install -m 0755 genl $(DESTDIR)$(SBINDIR) diff --git a/ip/Makefile b/ip/Makefile index f3d298739..a7f9c1101 100644 --- a/ip/Makefile +++ b/ip/Makefile @@ -24,8 +24,10 @@ TARGETS=ip rtmon all: $(TARGETS) $(SCRIPTS) ip: $(IPOBJ) $(LIBNETLINK) + $(QUIET_LINK)$(CC) $^ $(LDFLAGS) $(LDLIBS) -o $@ rtmon: $(RTMONOBJ) + $(QUIET_LINK)$(CC) $^ $(LDFLAGS) $(LDLIBS) -o $@ install: all install -m 0755 $(TARGETS) $(DESTDIR)$(SBINDIR) diff --git a/lib/Makefile b/lib/Makefile index 9d1307dd4..52e016db5 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -15,10 +15,10 @@ NLOBJ=libgenl.o ll_map.o libnetlink.o all: libnetlink.a libutil.a libnetlink.a: $(NLOBJ) - $(AR) rcs $@ $(NLOBJ) + $(QUIET_AR)$(AR) rcs $@ $^ libutil.a: $(UTILOBJ) $(ADDLIB) - $(AR) rcs $@ $(UTILOBJ) $(ADDLIB) + $(QUIET_AR)$(AR) rcs $@ $^ install: diff --git a/misc/Makefile b/misc/Makefile index f50e7403a..728076780 100644 --- a/misc/Makefile +++ b/misc/Makefile @@ -21,23 +21,25 @@ endif all: $(TARGETS) ss: $(SSOBJ) + $(QUIET_LINK)$(CC) $^ $(LDFLAGS) $(LDLIBS) -o $@ nstat: nstat.c - $(CC) $(CFLAGS) $(LDFLAGS) -o nstat nstat.c $(LIBNETLINK) -lm + $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o nstat nstat.c $(LIBNETLINK) -lm ifstat: ifstat.c - $(CC) $(CFLAGS) $(LDFLAGS) -o ifstat ifstat.c $(LIBNETLINK) -lm + $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o ifstat ifstat.c $(LIBNETLINK) -lm rtacct: rtacct.c - $(CC) $(CFLAGS) $(LDFLAGS) -o rtacct rtacct.c $(LIBNETLINK) -lm + $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o rtacct rtacct.c $(LIBNETLINK) -lm arpd: arpd.c - $(CC) $(CFLAGS) -I$(DBM_INCLUDE) $(LDFLAGS) -o arpd arpd.c $(LIBNETLINK) -ldb -lpthread + $(QUIET_CC)$(CC) $(CFLAGS) -I$(DBM_INCLUDE) $(LDFLAGS) -o arpd arpd.c $(LIBNETLINK) -ldb -lpthread ssfilter.c: ssfilter.y - bison ssfilter.y -o ssfilter.c + $(QUIET_YACC)bison ssfilter.y -o ssfilter.c lnstat: $(LNSTATOBJ) + $(QUIET_LINK)$(CC) $^ $(LDFLAGS) $(LDLIBS) -o $@ install: all install -m 0755 $(TARGETS) $(DESTDIR)$(SBINDIR) diff --git a/tc/Makefile b/tc/Makefile index 20f511000..42747c517 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -125,15 +125,16 @@ CFLAGS += -DYY_NO_INPUT MODDESTDIR := $(DESTDIR)$(LIBDIR)/tc %.so: %.c - $(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic $< -o $@ + $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic $< -o $@ all: libtc.a tc $(TCSO) tc: $(TCOBJ) $(TCLIB) + $(QUIET_LINK)$(CC) $^ $(LDFLAGS) $(LDLIBS) -o $@ libtc.a: $(TCLIB) - $(AR) rcs $@ $(TCLIB) + $(QUIET_AR)$(AR) rcs $@ $(TCLIB) install: all mkdir -p $(MODDESTDIR) @@ -154,21 +155,21 @@ clean: rm -f emp_ematch.yacc.* q_atm.so: q_atm.c - $(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic -o q_atm.so q_atm.c -latm + $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic -o q_atm.so q_atm.c -latm m_xt.so: m_xt.c - $(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic -o m_xt.so m_xt.c $$($(PKG_CONFIG) xtables --cflags --libs) + $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic -o m_xt.so m_xt.c $$($(PKG_CONFIG) xtables --cflags --libs) m_xt_old.so: m_xt_old.c - $(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic -o m_xt_old.so m_xt_old.c $$($(PKG_CONFIG) xtables --cflags --libs) + $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -shared -fpic -o m_xt_old.so m_xt_old.c $$($(PKG_CONFIG) xtables --cflags --libs) em_ipset.o: CFLAGS += $$($(PKG_CONFIG) xtables --cflags) %.yacc.c: %.y - $(YACC) $(YACCFLAGS) -o $@ $< + $(QUIET_YACC)$(YACC) $(YACCFLAGS) -o $@ $< %.lex.c: %.l - $(LEX) $(LEXFLAGS) -o$@ $< + $(QUIET_LEX)$(LEX) $(LEXFLAGS) -o$@ $< # our lexer includes the header from yacc, so make sure # we don't attempt to compile it before the header has diff --git a/tipc/Makefile b/tipc/Makefile index bc5ecfd37..868d13abf 100644 --- a/tipc/Makefile +++ b/tipc/Makefile @@ -19,6 +19,7 @@ endif all: $(TARGETS) $(LIBS) tipc: $(TIPCOBJ) + $(QUIET_LINK)$(CC) $^ $(LDFLAGS) $(LDLIBS) -o $@ install: all install -m 0755 $(TARGETS) $(DESTDIR)$(SBINDIR) From 45c68379112aaf0a2c738f5ee3067c96507e255f Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Wed, 25 May 2016 06:05:48 -0400 Subject: [PATCH 241/513] tc action policer: Avoid nonsensical input The user must at least specify a choice of the token bucket or ewma policing or late binding index. TB policing requires at minimal a rate and burst. In addition fix formatting issues (80 chars etc). Signed-off-by: Jamal Hadi Salim --- tc/m_police.c | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/tc/m_police.c b/tc/m_police.c index 97558bd37..8752d4f6c 100644 --- a/tc/m_police.c +++ b/tc/m_police.c @@ -99,7 +99,6 @@ static int police_action_a2n(const char *arg, int *result) return 0; } - static int get_police_result(int *action, int *result, char *arg) { char *p = strchr(arg, '/'); @@ -121,8 +120,8 @@ static int get_police_result(int *action, int *result, char *arg) return 0; } - -int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) +int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p, + int tca_id, struct nlmsghdr *n) { int argc = *argc_p; char **argv = *argv_p; @@ -258,10 +257,21 @@ int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p, int tca if (!ok) return -1; - if (p.rate.rate && !buffer) { + if (p.rate.rate && avrate) + return -1; + + /* Must at least do late binding, use TB or ewma policing */ + if (!p.rate.rate && !avrate && !p.index) { + fprintf(stderr, "\"rate\" or \"avrate\" MUST be specified.\n"); + return -1; + } + + /* When the TB policer is used, burst is required */ + if (p.rate.rate && !buffer && !avrate) { fprintf(stderr, "\"burst\" requires \"rate\".\n"); return -1; } + if (p.peakrate.rate) { if (!p.rate.rate) { fprintf(stderr, "\"peakrate\" requires \"rate\".\n"); @@ -276,8 +286,9 @@ int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p, int tca if (p.rate.rate) { p.rate.mpu = mpu; p.rate.overhead = overhead; - if (tc_calc_rtable(&p.rate, rtab, Rcell_log, mtu, linklayer) < 0) { - fprintf(stderr, "TBF: failed to calculate rate table.\n"); + if (tc_calc_rtable(&p.rate, rtab, Rcell_log, mtu, + linklayer) < 0) { + fprintf(stderr, "POLICE: failed to calculate rate table.\n"); return -1; } p.burst = tc_calc_xmittime(p.rate.rate, buffer); @@ -286,7 +297,8 @@ int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p, int tca if (p.peakrate.rate) { p.peakrate.mpu = mpu; p.peakrate.overhead = overhead; - if (tc_calc_rtable(&p.peakrate, ptab, Pcell_log, mtu, linklayer) < 0) { + if (tc_calc_rtable(&p.peakrate, ptab, Pcell_log, mtu, + linklayer) < 0) { fprintf(stderr, "POLICE: failed to calculate peak rate table.\n"); return -1; } @@ -317,8 +329,7 @@ int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) return act_parse_police(NULL, argc_p, argv_p, tca_id, n); } -int -print_police(struct action_util *a, FILE *f, struct rtattr *arg) +int print_police(struct action_util *a, FILE *f, struct rtattr *arg) { SPRINT_BUF(b1); SPRINT_BUF(b2); @@ -354,22 +365,26 @@ print_police(struct action_util *a, FILE *f, struct rtattr *arg) if (p->peakrate.rate) fprintf(f, "peakrate %s ", sprint_rate(p->peakrate.rate, b1)); if (tb[TCA_POLICE_AVRATE]) - fprintf(f, "avrate %s ", sprint_rate(rta_getattr_u32(tb[TCA_POLICE_AVRATE]), b1)); - fprintf(f, "action %s", police_action_n2a(p->action, b1, sizeof(b1))); + fprintf(f, "avrate %s ", + sprint_rate(rta_getattr_u32(tb[TCA_POLICE_AVRATE]), + b1)); + fprintf(f, "action %s", + police_action_n2a(p->action, b1, sizeof(b1))); if (tb[TCA_POLICE_RESULT]) { - fprintf(f, "/%s ", police_action_n2a(*(int *)RTA_DATA(tb[TCA_POLICE_RESULT]), b1, sizeof(b1))); + fprintf(f, "/%s", + police_action_n2a(*(int *)RTA_DATA(tb[TCA_POLICE_RESULT]), b1, sizeof(b1))); } else fprintf(f, " "); fprintf(f, "overhead %ub ", p->rate.overhead); linklayer = (p->rate.linklayer & TC_LINKLAYER_MASK); if (linklayer > TC_LINKLAYER_ETHERNET || show_details) fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b2)); - fprintf(f, "\nref %d bind %d\n", p->refcnt, p->bindcnt); + fprintf(f, "\n\tref %d bind %d\n", p->refcnt, p->bindcnt); return 0; } -int -tc_print_police(FILE *f, struct rtattr *arg) { +int tc_print_police(FILE *f, struct rtattr *arg) +{ return print_police(&police_action_util, f, arg); } From e6263c85830c05a85017ee32b0a9c6f9118ec584 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 31 May 2016 12:22:45 -0700 Subject: [PATCH 242/513] tc: action result is u32 In kernel action result is u32 not int in netlink messages. --- tc/m_police.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tc/m_police.c b/tc/m_police.c index 8752d4f6c..8f794ed4d 100644 --- a/tc/m_police.c +++ b/tc/m_police.c @@ -362,19 +362,25 @@ int print_police(struct action_util *a, FILE *f, struct rtattr *arg) fprintf(f, "mtu %s ", sprint_size(p->mtu, b1)); if (show_raw) fprintf(f, "[%08x] ", p->burst); + if (p->peakrate.rate) fprintf(f, "peakrate %s ", sprint_rate(p->peakrate.rate, b1)); + if (tb[TCA_POLICE_AVRATE]) fprintf(f, "avrate %s ", sprint_rate(rta_getattr_u32(tb[TCA_POLICE_AVRATE]), b1)); fprintf(f, "action %s", police_action_n2a(p->action, b1, sizeof(b1))); + if (tb[TCA_POLICE_RESULT]) { + __u32 action = rta_getattr_u32(tb[TCA_POLICE_RESULT]); + fprintf(f, "/%s", - police_action_n2a(*(int *)RTA_DATA(tb[TCA_POLICE_RESULT]), b1, sizeof(b1))); + police_action_n2a(action, b1, sizeof(b1))); } else fprintf(f, " "); + fprintf(f, "overhead %ub ", p->rate.overhead); linklayer = (p->rate.linklayer & TC_LINKLAYER_MASK); if (linklayer > TC_LINKLAYER_ETHERNET || show_details) From 82e6efe2e3a4e6237d80a0c7d78bb1de631ef467 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Wed, 25 May 2016 06:11:55 -0400 Subject: [PATCH 243/513] tc filter u32: Coding style fixes "handle" was being used several times for different things. Fix the 80 character limit abuse and other little issues while at it. Signed-off-by: Jamal Hadi Salim --- tc/f_u32.c | 66 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/tc/f_u32.c b/tc/f_u32.c index 629951539..1962dfe21 100644 --- a/tc/f_u32.c +++ b/tc/f_u32.c @@ -171,7 +171,8 @@ static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask, return pack_key(sel, key, mask, off, offmask); } -static int pack_key8(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask) +static int pack_key8(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, + int offmask) { if (key > 0xFF || mask > 0xFF) return -1; @@ -835,16 +836,19 @@ static void print_ipv4(FILE *f, const struct tc_u32_key *key) case 0: switch (ntohl(key->mask)) { case 0x0f000000: - fprintf(f, "\n match IP ihl %u", ntohl(key->val) >> 24); + fprintf(f, "\n match IP ihl %u", + ntohl(key->val) >> 24); return; case 0x00ff0000: - fprintf(f, "\n match IP dsfield %#x", ntohl(key->val) >> 16); + fprintf(f, "\n match IP dsfield %#x", + ntohl(key->val) >> 16); return; } break; case 8: if (ntohl(key->mask) == 0x00ff0000) { - fprintf(f, "\n match IP protocol %d", ntohl(key->val) >> 16); + fprintf(f, "\n match IP protocol %d", + ntohl(key->val) >> 16); return; } break; @@ -892,16 +896,19 @@ static void print_ipv6(FILE *f, const struct tc_u32_key *key) case 0: switch (ntohl(key->mask)) { case 0x0f000000: - fprintf(f, "\n match IP ihl %u", ntohl(key->val) >> 24); + fprintf(f, "\n match IP ihl %u", + ntohl(key->val) >> 24); return; case 0x00ff0000: - fprintf(f, "\n match IP dsfield %#x", ntohl(key->val) >> 16); + fprintf(f, "\n match IP dsfield %#x", + ntohl(key->val) >> 16); return; } break; case 8: if (ntohl(key->mask) == 0x00ff0000) { - fprintf(f, "\n match IP protocol %d", ntohl(key->val) >> 16); + fprintf(f, "\n match IP protocol %d", + ntohl(key->val) >> 16); return; } break; @@ -1031,14 +1038,14 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, continue; } else if (matches(*argv, "classid") == 0 || strcmp(*argv, "flowid") == 0) { - unsigned int handle; + unsigned int flowid; NEXT_ARG(); - if (get_tc_classid(&handle, *argv)) { + if (get_tc_classid(&flowid, *argv)) { fprintf(stderr, "Illegal \"classid\"\n"); return -1; } - addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &handle, 4); + addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &flowid, 4); sel.sel.flags |= TC_U32_TERMINAL; } else if (matches(*argv, "divisor") == 0) { unsigned int divisor; @@ -1058,34 +1065,34 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, return -1; } } else if (strcmp(*argv, "link") == 0) { - unsigned int handle; + unsigned int linkid; NEXT_ARG(); - if (get_u32_handle(&handle, *argv)) { + if (get_u32_handle(&linkid, *argv)) { fprintf(stderr, "Illegal \"link\"\n"); return -1; } - if (handle && TC_U32_NODE(handle)) { + if (linkid && TC_U32_NODE(linkid)) { fprintf(stderr, "\"link\" must be a hash table.\n"); return -1; } addattr_l(n, MAX_MSG, TCA_U32_LINK, &handle, 4); } else if (strcmp(*argv, "ht") == 0) { - unsigned int handle; + unsigned int ht; NEXT_ARG(); - if (get_u32_handle(&handle, *argv)) { + if (get_u32_handle(&ht, *argv)) { fprintf(stderr, "Illegal \"ht\"\n"); return -1; } - if (handle && TC_U32_NODE(handle)) { + if (handle && TC_U32_NODE(ht)) { fprintf(stderr, "\"ht\" must be a hash table.\n"); return -1; } if (sample_ok) - htid = (htid & 0xFF000) | (handle & 0xFFF00000); + htid = (htid & 0xFF000) | (ht & 0xFFF00000); else - htid = (handle & 0xFFFFF000); + htid = (ht & 0xFFFFF000); } else if (strcmp(*argv, "sample") == 0) { __u32 hash; unsigned int divisor = 0x100; @@ -1106,8 +1113,9 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, } if (*argv != 0 && strcmp(*argv, "divisor") == 0) { NEXT_ARG(); - if (get_unsigned(&divisor, *argv, 0) || divisor == 0 || - divisor > 0x100 || ((divisor - 1) & divisor)) { + if (get_unsigned(&divisor, *argv, 0) || + divisor == 0 || divisor > 0x100 || + ((divisor - 1) & divisor)) { fprintf(stderr, "Illegal sample \"divisor\"\n"); return -1; } @@ -1130,7 +1138,8 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, return -1; } strncpy(ind, *argv, sizeof(ind) - 1); - addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind, strlen(ind) + 1); + addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind, + strlen(ind) + 1); } else if (matches(*argv, "action") == 0) { NEXT_ARG(); @@ -1165,7 +1174,8 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, sel.sel.flags |= TC_U32_TERMINAL; if (order) { - if (TC_U32_NODE(t->tcm_handle) && order != TC_U32_NODE(t->tcm_handle)) { + if (TC_U32_NODE(t->tcm_handle) && + order != TC_U32_NODE(t->tcm_handle)) { fprintf(stderr, "\"order\" contradicts \"handle\"\n"); return -1; } @@ -1176,7 +1186,8 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4); if (sel_ok) addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel, - sizeof(sel.sel) + sel.sel.nkeys * sizeof(struct tc_u32_key)); + sizeof(sel.sel) + + sel.sel.nkeys * sizeof(struct tc_u32_key)); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; } @@ -1209,7 +1220,8 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, } if (tb[TCA_U32_DIVISOR]) { - fprintf(f, "ht divisor %d ", rta_getattr_u32(tb[TCA_U32_DIVISOR])); + fprintf(f, "ht divisor %d ", + rta_getattr_u32(tb[TCA_U32_DIVISOR])); } else if (tb[TCA_U32_HASH]) { __u32 htid = rta_getattr_u32(tb[TCA_U32_HASH]); @@ -1222,14 +1234,16 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, SPRINT_BUF(b1); fprintf(f, "%sflowid %s ", !sel || !(sel->flags & TC_U32_TERMINAL) ? "*" : "", - sprint_tc_classid(rta_getattr_u32(tb[TCA_U32_CLASSID]), b1)); + sprint_tc_classid(rta_getattr_u32(tb[TCA_U32_CLASSID]), + b1)); } else if (sel && sel->flags & TC_U32_TERMINAL) { fprintf(f, "terminal flowid ??? "); } if (tb[TCA_U32_LINK]) { SPRINT_BUF(b1); fprintf(f, "link %s ", - sprint_u32_handle(rta_getattr_u32(tb[TCA_U32_LINK]), b1)); + sprint_u32_handle(rta_getattr_u32(tb[TCA_U32_LINK]), + b1)); } if (tb[TCA_U32_PCNT]) { From 134080cff35e379cac81d47ec669d265c56d528d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 30 May 2016 20:46:27 +0200 Subject: [PATCH 244/513] man: ip, ip-link: Fix ip option location This patch drops the redundant description of some of ip's options in ip-link.8's description of the 'show' subcommand, preserving the description of -iec (but appending it to the list in ip.8 with minor fixes). Signed-off-by: Phil Sutter --- man/man8/ip-link.8.in | 21 --------------------- man/man8/ip.8 | 4 ++++ 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 984fb2eb0..d3881e55d 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -1119,27 +1119,6 @@ specifies the master device which enslaves devices to show. .I TYPE specifies the type of devices to show. -.TP -The show command has additional formatting options: - -.RS -.TP -.BR "\-s" , " \-stats", " \-statistics" -output more statistics about packet usage. - -.TP -.BR "\-d", " \-details" -output more detailed information. - -.TP -.BR "\-h", " \-human", " \-human-readable" -output statistics with human readable values number followed by suffix - -.TP -.BR "\-iec" -print human readable rates in IEC units (ie. 1K = 1024). -.RE - .SS ip link help - display help .PP diff --git a/man/man8/ip.8 b/man/man8/ip.8 index aa2bc68c8..f11fc0b9c 100644 --- a/man/man8/ip.8 +++ b/man/man8/ip.8 @@ -201,6 +201,10 @@ but use shorter format. .BR "\-rc" , " \-rcvbuf" Set the netlink socket receive buffer size, defaults to 1MB. +.TP +.BR "\-iec" +print human readable rates in IEC units (e.g. 1Ki = 1024). + .SH IP - COMMAND SYNTAX .SS From de70bd2f6b81dc3f5cb029875fbae93714c4b6b6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 31 May 2016 13:02:28 -0700 Subject: [PATCH 245/513] tc: update headers for TCA_POLICE These are from linux-net but will be in next rc. --- include/linux/pkt_cls.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index 25b8743ca..333b17167 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -91,6 +91,8 @@ enum { TCA_POLICE_PEAKRATE, TCA_POLICE_AVRATE, TCA_POLICE_RESULT, + TCA_POLICE_TM, + TCA_POLICE_PAD, __TCA_POLICE_MAX #define TCA_POLICE_RESULT TCA_POLICE_RESULT }; @@ -119,7 +121,7 @@ enum { TCA_U32_DIVISOR, TCA_U32_SEL, TCA_U32_POLICE, - TCA_U32_ACT, + TCA_U32_ACT, TCA_U32_INDEV, TCA_U32_PCNT, TCA_U32_MARK, From ead954cbd40a2a9e3756d2010c6bfb1d80c340ed Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Wed, 25 May 2016 06:05:49 -0400 Subject: [PATCH 246/513] tc action policer: enable timestamp display Signed-off-by: Jamal Hadi Salim --- tc/m_police.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tc/m_police.c b/tc/m_police.c index 8f794ed4d..a8b65dd9c 100644 --- a/tc/m_police.c +++ b/tc/m_police.c @@ -385,7 +385,16 @@ int print_police(struct action_util *a, FILE *f, struct rtattr *arg) linklayer = (p->rate.linklayer & TC_LINKLAYER_MASK); if (linklayer > TC_LINKLAYER_ETHERNET || show_details) fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b2)); - fprintf(f, "\n\tref %d bind %d\n", p->refcnt, p->bindcnt); + fprintf(f, "\n\tref %d bind %d", p->refcnt, p->bindcnt); + if (show_stats) { + if (tb[TCA_POLICE_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_POLICE_TM]); + + print_tm(f, tm); + } + } + fprintf(f, "\n"); + return 0; } From 9b3c971a49cd6022c86adf9db79d2c11a247d15d Mon Sep 17 00:00:00 2001 From: Peter Heise Date: Wed, 1 Jun 2016 09:43:15 +0200 Subject: [PATCH 247/513] man: ip-link: Added HSR part Added HSR part to manpage as follow-up to last commit's feedback. Signed-off-by: Peter Heise --- man/man8/ip-link.8.in | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index d3881e55d..0e3ae1ba4 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -846,6 +846,39 @@ forces the underlying interface into promiscuous mode. Passing the using standard tools. .in -8 +.TP +High-availability Seamless Redundancy (HSR) Support +For a link of type +.I HSR +the following additional arguments are supported: + +.BI "ip link add link " DEVICE " name " NAME +.BI type " hsr " +.BI slave1 " SLAVE1-IF " slave2 " SLAVE2-IF " +.BR " [ supervision " ADDR-BYTE " ] " +.BR " [ version { " 0 " | " 1 " } ] " + +.in +8 +.sp +.BR type " hsr " +- specifies the link type to use, here HSR. + +.BI slave1 " SLAVE1-IF " +- Specifies the physical device used for the first of the two ring ports. + +.BI slave2 " SLAVE2-IF " +- Specifies the physical device used for the second of the two ring ports. + +.BR "supervision ADDR-BYTE " +- The last byte of the multicast address used for HSR supervision frames. +Default option is "0", possible values 0-255. + +.BR "version { 0 | 1 }" +- Selects the protocol version of the interface. Default option is "0", which +corresponds to the 2010 version of the HSR standard. Option "1" activates the +2012 version. +.in -8 + .SS ip link delete - delete virtual link .TP From ebef3174b6fd8fb5f3038e52e80d41584aa1e7cb Mon Sep 17 00:00:00 2001 From: Fabien Siron Date: Mon, 6 Jun 2016 14:53:38 +0000 Subject: [PATCH 248/513] misc/ss: Add family list to -f option in _usage() Signed-off-by: Fabien Siron --- misc/ss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/misc/ss.c b/misc/ss.c index 23fff19d9..9c456d4f1 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -3581,6 +3581,7 @@ static void _usage(FILE *dest) " -w, --raw display only RAW sockets\n" " -x, --unix display only Unix domain sockets\n" " -f, --family=FAMILY display sockets of type FAMILY\n" +" FAMILY := {inet|inet6|link|unix|netlink|help}\n" "\n" " -K, --kill forcibly close sockets, display what was closed\n" "\n" From 3088787c4b951648e9d6a02c0a645bac8e39b1b4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 1 Jun 2016 21:58:21 +0200 Subject: [PATCH 249/513] man: rtpr: Fix minor typo Signed-off-by: Phil Sutter --- man/man8/rtpr.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/rtpr.8 b/man/man8/rtpr.8 index 5e32b2eee..1b04a821a 100644 --- a/man/man8/rtpr.8 +++ b/man/man8/rtpr.8 @@ -13,7 +13,7 @@ flag. .SH EXAMPLES .TP -ip --onenline address show | rtpr +ip --oneline address show | rtpr Undo oneline converted .B ip-address output. From 06f9a59170c0ed168d5d36335d98c9825a0d661b Mon Sep 17 00:00:00 2001 From: Lucas Bates Date: Sun, 5 Jun 2016 09:17:15 -0400 Subject: [PATCH 250/513] man: tc-ife.8: man page for ife action Signed-off-by: Lucas Bates Signed-off-by: Jamal Hadi Salim Acked-by: Phil Sutter --- man/man8/tc-ife.8 | 117 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 man/man8/tc-ife.8 diff --git a/man/man8/tc-ife.8 b/man/man8/tc-ife.8 new file mode 100644 index 000000000..7b3601ee3 --- /dev/null +++ b/man/man8/tc-ife.8 @@ -0,0 +1,117 @@ +.TH "IFE action in tc" 8 "22 Apr 2016" "iproute2" "Linux" + +.SH NAME +IFE - encapsulate/decapsulate metadata +.SH SYNOPSIS +.in +8 +.ti -8 +.BR tc " ... " action ife" +.I DIRECTION ACTION +.RB "[ " dst +.IR DMAC " ] " +.RB "[ " src +.IR SMAC " ] " +.RB "[ " type +.IR TYPE " ] " +.R "[ " +.IR CONTROL " ] " +.RB "[ " index +.IR INDEX " ] " + +.ti -8 +.IR DIRECTION " := { " +.BR decode " | " encode " }" + +.ti -8 +.IR ACTION " := { " +.BR allow " | " use " }" + +.ti -8 +.IR CONTROL " := { " +.BR reclassify " | " use " | " pipe " | " drop " | " continue " | " ok " }" +.SH DESCRIPTION +The +.B ife +action allows for a sending side to encapsulate arbitrary metadata, which is +then decapsulated by the receiving end. The sender runs in encoding mode and +the receiver in decode mode. Both sender and receiver must specify the same +ethertype. In the future, a registered ethertype may be available as a default. +.SH OPTIONS +.TP +.B decode +For the receiving side; decode the metadata if the packet matches. +.TP +.B encode +For the sending side. Encode the specified metadata if the packet matches. +.TP +.B allow +Encode direction only. Allows encoding specified metadata. +.TP +.B use +Encode direction only. Enforce static encoding of specified metadata. +.TP +.BI dmac " DMAC" +.TQ +.BI smac " SMAC" +Optional six byte destination or source MAC address to encode. +.TP +.BI type " TYPE" +Optional 16-bit ethertype to encode. +.TP +.BI CONTROL +Action to take following an encode/decode. +.TP +.BI index " INDEX" +Assign a unique ID to this action instead of letting the kernel choose one +automatically. +.I INDEX +is a 32bit unsigned integer greater than zero. +.SH EXAMPLES + +On the receiving side, match packets with ethertype 0xdead and restart +classification so that it will match ICMP on the next rule, at prio 3: +.RS +.EX +# tc qdisc add dev eth0 handle ffff: ingress +# tc filter add dev eth0 parent ffff: prio 2 protocol 0xdead \\ + u32 match u32 0 0 flowid 1:1 \\ + action ife decode reclassify +# tc filter add dev eth0 parent ffff: priod 3 protocol ip \\ + u32 match ip protocol 0xff flowid 1:1 \\ + action continue +.EE +.RE + +Match with skb mark of 17: + +.RS +.EX +# tc filter add dev eth0 parent ffff: prio 4 protocol ip \\ + handle 0x11 fw flowid 1:1 \\ + action ok +.EE +.RE + +Configure the sending side to encode for the filters above. Use a destination +IP address of 192.168.122.237/24, then tag with skb mark of decimal 17. Encode +the packaet with ethertype 0xdead, add skb->mark to whitelist of metadatum to +send, and rewrite the destination MAC address to 02:15:15:15:15:15. + +.RS +.EX +# tc qdisc add dev eth0 root handle 1: prio +# tc filter add dev eth0 parent 1: protocol ip prio 10 u32 \\ + match ip dst 192.168.122.237/24 \\ + match ip protocol 1 0xff \\ + flowid 1:2 \\ + action skbedit mark 17 \\ + action ife encode \\ + type 0xDEAD \\ + allow mark \\ + dst 02:15:15:15:15:15 +.EE +.RE + +.SH SEE ALSO +.BR tc (8), +.BR tc-u32 (8) From 4de4b5ca14ec6e1681c3c86ea7547d207617833d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jun 2016 08:42:00 -0700 Subject: [PATCH 251/513] fq_codel: add per queue memory limit This patch adds support for TCA_FQ_CODEL_MEMORY_LIMIT attribute. .. qdisc fq_codel 8008: root refcnt 257 limit 10240p flows 1024 quantum 1514 target 5.0ms interval 100.0ms memory_limit 4Mb ecn Sent 2083566791363 bytes 1376214889 pkt (dropped 4994406, overlimits 0 requeues 21705223) rate 9841Mbit 812549pps backlog 3906120b 376p requeues 21705223 maxpacket 68130 drop_overlimit 4994406 new_flow_count 28855414 ecn_mark 0 memory_used 4190048 drop_overmemory 4994406 new_flows_len 1 old_flows_len 177 Signed-off-by: Eric Dumazet --- tc/q_fq_codel.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tc/q_fq_codel.c b/tc/q_fq_codel.c index f9244ee6c..f813badaa 100644 --- a/tc/q_fq_codel.c +++ b/tc/q_fq_codel.c @@ -65,6 +65,7 @@ static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, unsigned int interval = 0; unsigned int quantum = 0; unsigned int ce_threshold = ~0U; + unsigned int memory = ~0U; int ecn = -1; struct rtattr *tail; @@ -99,6 +100,12 @@ static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, fprintf(stderr, "Illegal \"ce_threshold\"\n"); return -1; } + } else if (strcmp(*argv, "memory_limit") == 0) { + NEXT_ARG(); + if (get_size(&memory, *argv)) { + fprintf(stderr, "Illegal \"memory_limit\"\n"); + return -1; + } } else if (strcmp(*argv, "interval") == 0) { NEXT_ARG(); if (get_time(&interval, *argv)) { @@ -137,6 +144,10 @@ static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, if (ce_threshold != ~0U) addattr_l(n, 1024, TCA_FQ_CODEL_CE_THRESHOLD, &ce_threshold, sizeof(ce_threshold)); + if (memory != ~0U) + addattr_l(n, 1024, TCA_FQ_CODEL_MEMORY_LIMIT, + &memory, sizeof(memory)); + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; } @@ -151,6 +162,7 @@ static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt unsigned int ecn; unsigned int quantum; unsigned int ce_threshold; + unsigned int memory_limit; SPRINT_BUF(b1); @@ -189,6 +201,12 @@ static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt interval = rta_getattr_u32(tb[TCA_FQ_CODEL_INTERVAL]); fprintf(f, "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)); + } if (tb[TCA_FQ_CODEL_ECN] && RTA_PAYLOAD(tb[TCA_FQ_CODEL_ECN]) >= sizeof(__u32)) { ecn = rta_getattr_u32(tb[TCA_FQ_CODEL_ECN]); @@ -223,6 +241,10 @@ static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, st->qdisc_stats.ecn_mark); if (st->qdisc_stats.ce_mark) fprintf(f, " ce_mark %u", st->qdisc_stats.ce_mark); + if (st->qdisc_stats.memory_usage) + fprintf(f, " memory_used %u", st->qdisc_stats.memory_usage); + if (st->qdisc_stats.drop_overmemory) + fprintf(f, " drop_overmemory %u", st->qdisc_stats.drop_overmemory); fprintf(f, "\n new_flows_len %u old_flows_len %u", st->qdisc_stats.new_flows_len, st->qdisc_stats.old_flows_len); From 90353c33413293d8b67ff8440d607be425cc1108 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 8 Jun 2016 09:15:52 -0700 Subject: [PATCH 252/513] ip: minor checkpatch cleanup --- ip/ip_common.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ip/ip_common.h b/ip/ip_common.h index b7361a8fc..f57105d36 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -8,7 +8,7 @@ int print_addrinfo(const struct sockaddr_nl *who, int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); int print_neigh(const struct sockaddr_nl *who, - struct nlmsghdr *n, void *arg); + struct nlmsghdr *n, void *arg); int ipaddr_list_link(int argc, char **argv); void ipaddr_get_vf_rate(int, int *, int *, int); void iplink_usage(void) __attribute__((noreturn)); @@ -59,6 +59,7 @@ int iplink_get(unsigned int flags, char *name, __u32 filt_mask); static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb) { __u32 table = r->rtm_table; + if (tb[RTA_TABLE]) table = rta_getattr_u32(tb[RTA_TABLE]); return table; @@ -68,8 +69,7 @@ extern struct rtnl_handle rth; #include -struct link_util -{ +struct link_util { struct link_util *next; const char *id; int maxattr; From 89ae502056f58a0177b9970f1f79a9683ac7fdd0 Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Fri, 3 Jun 2016 16:45:45 +0200 Subject: [PATCH 253/513] utils: make hexstring_a2n provide the number of hex digits parsed Signed-off-by: Sabrina Dubroca Acked-by: Phil Sutter --- include/utils.h | 4 ++-- lib/utils.c | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/utils.h b/include/utils.h index ef81d00f3..aef28ce73 100644 --- a/include/utils.h +++ b/include/utils.h @@ -114,8 +114,8 @@ int get_u8(__u8 *val, const char *arg, int base); int get_s8(__s8 *val, const char *arg, int base); int get_addr64(__u64 *ap, const char *cp); -char* hexstring_n2a(const __u8 *str, int len, char *buf, int blen); -__u8* hexstring_a2n(const char *str, __u8 *buf, int blen); +char *hexstring_n2a(const __u8 *str, int len, char *buf, int blen); +__u8 *hexstring_a2n(const char *str, __u8 *buf, int blen, unsigned int *len); #define ADDR64_BUF_SIZE sizeof("xxxx:xxxx:xxxx:xxxx") int addr64_n2a(__u64 addr, char *buff, size_t len); diff --git a/lib/utils.c b/lib/utils.c index b93b1dc84..bd10c0d71 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -866,9 +866,9 @@ char *hexstring_n2a(const __u8 *str, int len, char *buf, int blen) return buf; } -__u8* hexstring_a2n(const char *str, __u8 *buf, int blen) +__u8 *hexstring_a2n(const char *str, __u8 *buf, int blen, unsigned int *len) { - int cnt = 0; + unsigned int cnt = 0; char *endptr; if (strlen(str) % 2) @@ -885,6 +885,10 @@ __u8* hexstring_a2n(const char *str, __u8 *buf, int blen) buf[cnt++] = tmp; str += 2; } + + if (len) + *len = cnt; + return buf; } From 9f7401fa4967178a071c53498f6bdc460c7cc4ea Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Fri, 3 Jun 2016 16:45:46 +0200 Subject: [PATCH 254/513] utils: add get_be{16, 32, 64}, use them where possible Signed-off-by: Sabrina Dubroca Acked-by: Phil Sutter --- include/utils.h | 3 +++ ip/ipfou.c | 3 +-- ip/iplink_vxlan.c | 8 ++------ ip/iproute_lwtunnel.c | 8 ++++---- ip/ipxfrm.c | 13 +++---------- ip/xfrm_state.c | 10 +++------- lib/ll_proto.c | 3 +-- lib/utils.c | 33 +++++++++++++++++++++++++++++++++ tc/f_flower.c | 4 ++-- tc/f_u32.c | 10 ++-------- 10 files changed, 54 insertions(+), 41 deletions(-) diff --git a/include/utils.h b/include/utils.h index aef28ce73..a9aa89162 100644 --- a/include/utils.h +++ b/include/utils.h @@ -112,6 +112,9 @@ int get_u16(__u16 *val, const char *arg, int base); int get_s16(__s16 *val, const char *arg, int base); int get_u8(__u8 *val, const char *arg, int base); int get_s8(__s8 *val, const char *arg, int base); +int get_be64(__be64 *val, const char *arg, int base); +int get_be32(__be32 *val, const char *arg, int base); +int get_be16(__be16 *val, const char *arg, int base); int get_addr64(__u64 *ap, const char *cp); char *hexstring_n2a(const __u8 *str, int len, char *buf, int blen); diff --git a/ip/ipfou.c b/ip/ipfou.c index 8a86b18fc..2a6ae1755 100644 --- a/ip/ipfou.c +++ b/ip/ipfou.c @@ -55,9 +55,8 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n, if (!matches(*argv, "port")) { NEXT_ARG(); - if (get_u16(&port, *argv, 0) || port == 0) + if (get_be16(&port, *argv, 0) || port == 0) invarg("invalid port", *argv); - port = htons(port); port_set = 1; } else if (!matches(*argv, "ipproto")) { struct protoent *servptr; diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index 49a40befa..7ba68bc14 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -172,16 +172,12 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, invarg("max addresses", *argv); } else if (!matches(*argv, "port") || !matches(*argv, "srcport")) { - __u16 minport, maxport; - NEXT_ARG(); - if (get_u16(&minport, *argv, 0)) + if (get_be16(&range.low, *argv, 0)) invarg("min port", *argv); NEXT_ARG(); - if (get_u16(&maxport, *argv, 0)) + if (get_be16(&range.high, *argv, 0)) invarg("max port", *argv); - range.low = htons(minport); - range.high = htons(maxport); } else if (!matches(*argv, "dstport")) { NEXT_ARG(); if (get_u16(&dstport, *argv, 0)) diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 3baac7720..bdbb15d2b 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -190,9 +190,9 @@ static int parse_encap_ip(struct rtattr *rta, size_t len, int *argcp, char ***ar NEXT_ARG(); if (id_ok++) duparg2("id", *argv); - if (get_u64(&id, *argv, 0)) + if (get_be64(&id, *argv, 0)) invarg("\"id\" value is invalid\n", *argv); - rta_addattr64(rta, len, LWTUNNEL_IP_ID, htonll(id)); + rta_addattr64(rta, len, LWTUNNEL_IP_ID, id); } else if (strcmp(*argv, "dst") == 0) { inet_prefix addr; @@ -267,9 +267,9 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len, int *argcp, char ***a NEXT_ARG(); if (id_ok++) duparg2("id", *argv); - if (get_u64(&id, *argv, 0)) + if (get_be64(&id, *argv, 0)) invarg("\"id\" value is invalid\n", *argv); - rta_addattr64(rta, len, LWTUNNEL_IP6_ID, htonll(id)); + rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id); } else if (strcmp(*argv, "dst") == 0) { inet_prefix addr; diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c index 8741ff3b3..8d786d133 100644 --- a/ip/ipxfrm.c +++ b/ip/ipxfrm.c @@ -1109,15 +1109,10 @@ int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family, filter.id_proto_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "spi") == 0) { - __u32 spi; - NEXT_ARG(); - if (get_u32(&spi, *argv, 0)) + if (get_be32(&id->spi, *argv, 0)) invarg("SPI value is invalid", *argv); - spi = htonl(spi); - id->spi = spi; - filter.id_spi_mask = XFRM_FILTER_MASK_FULL; } else { @@ -1252,9 +1247,8 @@ static int xfrm_selector_upspec_parse(struct xfrm_selector *sel, NEXT_ARG(); - if (get_u16(&sel->sport, *argv, 0)) + if (get_be16(&sel->sport, *argv, 0)) invarg("value after \"sport\" is invalid", *argv); - sel->sport = htons(sel->sport); if (sel->sport) sel->sport_mask = ~((__u16)0); @@ -1265,9 +1259,8 @@ static int xfrm_selector_upspec_parse(struct xfrm_selector *sel, NEXT_ARG(); - if (get_u16(&sel->dport, *argv, 0)) + if (get_be16(&sel->dport, *argv, 0)) invarg("value after \"dport\" is invalid", *argv); - sel->dport = htons(sel->dport); if (sel->dport) sel->dport_mask = ~((__u16)0); diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c index 5e2b64195..21ada3647 100644 --- a/ip/xfrm_state.c +++ b/ip/xfrm_state.c @@ -175,11 +175,9 @@ static int xfrm_seq_parse(__u32 *seq, int *argcp, char ***argvp) int argc = *argcp; char **argv = *argvp; - if (get_u32(seq, *argv, 0)) + if (get_be32(seq, *argv, 0)) invarg("SEQ value is invalid", *argv); - *seq = htonl(*seq); - *argcp = argc; *argvp = argv; @@ -359,13 +357,11 @@ static int xfrm_state_modify(int cmd, unsigned int flags, int argc, char **argv) NEXT_ARG(); xfrm_encap_type_parse(&encap.encap_type, &argc, &argv); NEXT_ARG(); - if (get_u16(&encap.encap_sport, *argv, 0)) + if (get_be16(&encap.encap_sport, *argv, 0)) invarg("SPORT value after \"encap\" is invalid", *argv); - encap.encap_sport = htons(encap.encap_sport); NEXT_ARG(); - if (get_u16(&encap.encap_dport, *argv, 0)) + if (get_be16(&encap.encap_dport, *argv, 0)) invarg("DPORT value after \"encap\" is invalid", *argv); - encap.encap_dport = htons(encap.encap_dport); NEXT_ARG(); get_addr(&oa, *argv, AF_UNSPEC); memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa)); diff --git a/lib/ll_proto.c b/lib/ll_proto.c index d8df68c11..e094d9f81 100644 --- a/lib/ll_proto.c +++ b/lib/ll_proto.c @@ -111,8 +111,7 @@ int ll_proto_a2n(unsigned short *id, const char *buf) return 0; } } - if (get_u16(id, buf, 0)) + if (get_be16(id, buf, 0)) return -1; - *id = htons(*id); return 0; } diff --git a/lib/utils.c b/lib/utils.c index bd10c0d71..e0cee5e9d 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -353,6 +353,39 @@ int get_s8(__s8 *val, const char *arg, int base) return 0; } +int get_be64(__be64 *val, const char *arg, int base) +{ + __u64 v; + int ret = get_u64(&v, arg, base); + + if (!ret) + *val = htonll(v); + + return ret; +} + +int get_be32(__be32 *val, const char *arg, int base) +{ + __u32 v; + int ret = get_u32(&v, arg, base); + + if (!ret) + *val = htonl(v); + + return ret; +} + +int get_be16(__be16 *val, const char *arg, int base) +{ + __u16 v; + int ret = get_u16(&v, arg, base); + + if (!ret) + *val = htons(v); + + return ret; +} + /* This uses a non-standard parsing (ie not inet_aton, or inet_pton) * because of legacy choice to parse 10.8 as 10.8.0.0 not 10.0.0.8 */ diff --git a/tc/f_flower.c b/tc/f_flower.c index 306f056c1..fd2014b37 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -150,11 +150,11 @@ static int flower_parse_port(char *str, __u8 ip_port, return -1; } - ret = get_u16(&port, str, 10); + ret = get_be16(&port, str, 10); if (ret) return -1; - addattr16(n, MAX_MSG, type, htons(port)); + addattr16(n, MAX_MSG, type, port); return 0; } diff --git a/tc/f_u32.c b/tc/f_u32.c index 1962dfe21..9424dc378 100644 --- a/tc/f_u32.c +++ b/tc/f_u32.c @@ -767,12 +767,9 @@ static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) } sel->flags |= TC_U32_VAROFFSET; } else if (matches(*argv, "mask") == 0) { - __u16 mask; - NEXT_ARG(); - if (get_u16(&mask, *argv, 16)) + if (get_be16(&sel->offmask, *argv, 16)) return -1; - sel->offmask = htons(mask); sel->flags |= TC_U32_VAROFFSET; } else if (matches(*argv, "shift") == 0) { int shift; @@ -802,12 +799,9 @@ static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel) while (argc > 0) { if (matches(*argv, "mask") == 0) { - __u32 mask; - NEXT_ARG(); - if (get_u32(&mask, *argv, 16)) + if (get_be32(&sel->hmask, *argv, 16)) return -1; - sel->hmask = htonl(mask); } else if (matches(*argv, "at") == 0) { int num; From 609640f5f0feda8099b04452297d81dd1a8a1777 Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Fri, 3 Jun 2016 16:45:47 +0200 Subject: [PATCH 255/513] utils: provide get_hex to read a hex digit from a char Signed-off-by: Sabrina Dubroca Acked-by: Phil Sutter --- include/utils.h | 1 + ip/ipl2tp.c | 15 ++------------- lib/ipx_pton.c | 18 +++--------------- lib/utils.c | 12 ++++++++++++ 4 files changed, 18 insertions(+), 28 deletions(-) diff --git a/include/utils.h b/include/utils.h index a9aa89162..27562a1c9 100644 --- a/include/utils.h +++ b/include/utils.h @@ -99,6 +99,7 @@ int get_prefix(inet_prefix *dst, char *arg, int family); int mask2bits(__u32 netmask); int get_addr_ila(__u64 *val, const char *arg); +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); int get_time_rtt(unsigned *val, const char *arg, int *raw); diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index 3c8ee9355..1f84c6149 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -425,30 +425,19 @@ static int get_tunnel(struct l2tp_data *p) * Command parser *****************************************************************************/ -static int hex(char ch) -{ - if ((ch >= 'a') && (ch <= 'f')) - return ch - 'a' + 10; - if ((ch >= '0') && (ch <= '9')) - return ch - '0'; - if ((ch >= 'A') && (ch <= 'F')) - return ch - 'A' + 10; - return -1; -} - static int hex2mem(const char *buf, uint8_t *mem, int count) { int i, j; int c; for (i = 0, j = 0; i < count; i++, j += 2) { - c = hex(buf[j]); + c = get_hex(buf[j]); if (c < 0) goto err; mem[i] = c << 4; - c = hex(buf[j + 1]); + c = get_hex(buf[j + 1]); if (c < 0) goto err; diff --git a/lib/ipx_pton.c b/lib/ipx_pton.c index 3dca27137..071a775e7 100644 --- a/lib/ipx_pton.c +++ b/lib/ipx_pton.c @@ -6,18 +6,6 @@ #include "utils.h" -static u_int32_t hexget(char c) -{ - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - if (c >= '0' && c <= '9') - return c - '0'; - - return 0xf0; -} - static int ipx_getnet(u_int32_t *net, const char *str) { int i; @@ -25,7 +13,7 @@ static int ipx_getnet(u_int32_t *net, const char *str) for(i = 0; *str && (i < 8); i++) { - if ((tmp = hexget(*str)) & 0xf0) { + if ((tmp = get_hex(*str)) == -1) { if (*str == '.') return 0; else @@ -49,11 +37,11 @@ static int ipx_getnode(u_int8_t *node, const char *str) u_int32_t tmp; for(i = 0; i < 6; i++) { - if ((tmp = hexget(*str++)) & 0xf0) + if ((tmp = get_hex(*str++)) == -1) return -1; node[i] = (u_int8_t)tmp; node[i] <<= 4; - if ((tmp = hexget(*str++)) & 0xf0) + if ((tmp = get_hex(*str++)) == -1) return -1; node[i] |= (u_int8_t)tmp; if (*str == ':') diff --git a/lib/utils.c b/lib/utils.c index e0cee5e9d..70e85b75b 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -37,6 +37,18 @@ int timestamp_short = 0; +int get_hex(char c) +{ + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= '0' && c <= '9') + return c - '0'; + + return -1; +} + int get_integer(int *val, const char *arg, int base) { long res; From b26fc590ce6272835da35c016f6a99f5f43d6a88 Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Wed, 8 Jun 2016 09:34:21 -0700 Subject: [PATCH 256/513] ip: add MACsec support Extend ip-link to create MACsec devices ip link add link type macsec [options] Add `ip macsec` command to configure receive-side secure channels and secure associations within a macsec netdevice. Signed-off-by: Sabrina Dubroca Acked-by: Phil Sutter --- ip/Makefile | 2 +- ip/ip.c | 3 +- ip/ip_common.h | 1 + ip/ipmacsec.c | 1301 +++++++++++++++++++++++++++++++++++++++++ man/man8/Makefile | 2 +- man/man8/ip-link.8.in | 85 +++ man/man8/ip-macsec.8 | 98 ++++ 7 files changed, 1489 insertions(+), 3 deletions(-) create mode 100644 ip/ipmacsec.c create mode 100644 man/man8/ip-macsec.8 diff --git a/ip/Makefile b/ip/Makefile index a7f9c1101..33e9286d4 100644 --- a/ip/Makefile +++ b/ip/Makefile @@ -7,7 +7,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \ iplink_vxlan.o tcp_metrics.o iplink_ipoib.o ipnetconf.o link_ip6tnl.o \ link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o \ iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \ - iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o + iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o RTMONOBJ=rtmon.o diff --git a/ip/ip.c b/ip/ip.c index 123f18133..166ef1749 100644 --- a/ip/ip.c +++ b/ip/ip.c @@ -51,7 +51,7 @@ static void usage(void) " ip [ -force ] -batch filename\n" "where OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |\n" " tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |\n" -" netns | l2tp | fou | tcp_metrics | token | netconf }\n" +" netns | l2tp | fou | macsec | tcp_metrics | token | netconf }\n" " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n" " -h[uman-readable] | -iec |\n" " -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n" @@ -84,6 +84,7 @@ static const struct cmd { { "link", do_iplink }, { "l2tp", do_ipl2tp }, { "fou", do_ipfou }, + { "macsec", do_ipmacsec }, { "tunnel", do_iptunnel }, { "tunl", do_iptunnel }, { "tuntap", do_iptuntap }, diff --git a/ip/ip_common.h b/ip/ip_common.h index f57105d36..e8da9e034 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -43,6 +43,7 @@ int do_iptunnel(int argc, char **argv); int do_ip6tunnel(int argc, char **argv); int do_iptuntap(int argc, char **argv); int do_iplink(int argc, char **argv); +int do_ipmacsec(int argc, char **argv); int do_ipmonitor(int argc, char **argv); int do_multiaddr(int argc, char **argv); int do_multiroute(int argc, char **argv); diff --git a/ip/ipmacsec.c b/ip/ipmacsec.c new file mode 100644 index 000000000..34ba341a8 --- /dev/null +++ b/ip/ipmacsec.c @@ -0,0 +1,1301 @@ +/* + * ipmacsec.c "ip macsec". + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Sabrina Dubroca + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rt_names.h" +#include "utils.h" +#include "ip_common.h" +#include "ll_map.h" +#include "libgenl.h" + +static const char *values_on_off[] = { "off", "on" }; + +static const char *VALIDATE_STR[] = { + [MACSEC_VALIDATE_DISABLED] = "disabled", + [MACSEC_VALIDATE_CHECK] = "check", + [MACSEC_VALIDATE_STRICT] = "strict", +}; + +struct sci { + __u64 sci; + __u16 port; + char abuf[6]; +}; + +struct sa_desc { + __u8 an; + __u32 pn; + __u8 key_id[MACSEC_KEYID_LEN]; + __u32 key_len; + __u8 key[MACSEC_MAX_KEY_LEN]; + __u8 active; +}; + +struct cipher_args { + __u64 id; + __u8 icv_len; +}; + +struct txsc_desc { + int ifindex; + __u64 sci; + __be16 port; + struct cipher_args cipher; + __u32 window; + enum macsec_validation_type validate; + __u8 encoding_sa; +}; + +struct rxsc_desc { + int ifindex; + __u64 sci; + __u8 active; +}; + +#define MACSEC_BUFLEN 1024 + + +/* netlink socket */ +static struct rtnl_handle genl_rth; +static int genl_family = -1; + +#define MACSEC_GENL_REQ(_req, _bufsiz, _cmd, _flags) \ + GENL_REQUEST(_req, _bufsiz, genl_family, 0, MACSEC_GENL_VERSION, \ + _cmd, _flags) + + +static void init_genl(void) +{ + if (genl_family >= 0) + return; + + if (rtnl_open_byproto(&genl_rth, 0, NETLINK_GENERIC) < 0) { + fprintf(stderr, "Cannot open generic netlink socket\n"); + exit(1); + } + + genl_family = genl_resolve_family(&genl_rth, MACSEC_GENL_NAME); + if (genl_family < 0) + exit(1); +} + +static void ipmacsec_usage(void) +{ + fprintf(stderr, "Usage: ip macsec add DEV tx sa { 0..3 } [ OPTS ] key ID KEY\n"); + fprintf(stderr, " ip macsec set DEV tx sa { 0..3 } [ OPTS ]\n"); + fprintf(stderr, " ip macsec del DEV tx sa { 0..3 }\n"); + fprintf(stderr, " ip macsec add DEV rx SCI [ on | off ]\n"); + fprintf(stderr, " ip macsec set DEV rx SCI [ on | off ]\n"); + fprintf(stderr, " ip macsec del DEV rx SCI\n"); + fprintf(stderr, " ip macsec add DEV rx SCI sa { 0..3 } [ OPTS ] key ID KEY\n"); + fprintf(stderr, " ip macsec set DEV rx SCI sa { 0..3 } [ OPTS ]\n"); + fprintf(stderr, " ip macsec del DEV rx SCI sa { 0..3 }\n"); + fprintf(stderr, " ip macsec show\n"); + fprintf(stderr, " ip macsec show DEV\n"); + fprintf(stderr, "where OPTS := [ pn ] [ on | off ]\n"); + fprintf(stderr, " ID := 128-bit hex string\n"); + fprintf(stderr, " KEY := 128-bit hex string\n"); + fprintf(stderr, " SCI := { sci | port address }\n"); + + exit(-1); +} + +static int one_of(const char *msg, const char *realval, const char **list, + size_t len, int *index) +{ + int i; + + for (i = 0; i < len; i++) { + if (matches(realval, list[i]) == 0) { + *index = i; + return 0; + } + } + + fprintf(stderr, "Error: argument of \"%s\" must be one of ", msg); + for (i = 0; i < len; i++) + fprintf(stderr, "\"%s\", ", list[i]); + fprintf(stderr, "not \"%s\"\n", realval); + return -1; +} + +static int get_an(__u8 *val, const char *arg) +{ + int ret = get_u8(val, arg, 0); + + if (ret) + return ret; + + if (*val > 3) + return -1; + + return 0; +} + +static int get_sci(__u64 *sci, const char *arg) +{ + return get_u64(sci, arg, 16); +} + +static int get_port(__be16 *port, const char *arg) +{ + return get_be16(port, arg, 10); +} + +#define _STR(a) #a +#define STR(a) _STR(a) + +static void get_icvlen(__u8 *icvlen, char *arg) +{ + int ret = get_u8(icvlen, arg, 10); + + if (ret) + invarg("expected ICV length", arg); + + if (*icvlen < MACSEC_MIN_ICV_LEN || *icvlen > MACSEC_MAX_ICV_LEN) + invarg("ICV length must be in the range {" + STR(MACSEC_MIN_ICV_LEN) ".." STR(MACSEC_MAX_ICV_LEN) + "}", arg); +} + +static bool get_sa(int *argcp, char ***argvp, __u8 *an) +{ + int argc = *argcp; + char **argv = *argvp; + int ret; + + if (argc <= 0 || strcmp(*argv, "sa") != 0) + return false; + + NEXT_ARG(); + ret = get_an(an, *argv); + if (ret) + invarg("expected an { 0..3 }", *argv); + argc--; argv++; + + *argvp = argv; + *argcp = argc; + return true; +} + +static int parse_sa_args(int *argcp, char ***argvp, struct sa_desc *sa) +{ + int argc = *argcp; + char **argv = *argvp; + int ret; + bool active_set = false; + + while (argc > 0) { + if (strcmp(*argv, "pn") == 0) { + if (sa->pn != 0) + duparg2("pn", "pn"); + NEXT_ARG(); + ret = get_u32(&sa->pn, *argv, 0); + if (ret) + invarg("expected pn", *argv); + if (sa->pn == 0) + invarg("expected pn != 0", *argv); + } else if (strcmp(*argv, "key") == 0) { + unsigned int len; + + NEXT_ARG(); + if (!hexstring_a2n(*argv, sa->key_id, MACSEC_KEYID_LEN, + &len)) + invarg("expected key id", *argv); + NEXT_ARG(); + if (!hexstring_a2n(*argv, sa->key, MACSEC_MAX_KEY_LEN, + &sa->key_len)) + invarg("expected key", *argv); + } else if (strcmp(*argv, "on") == 0) { + if (active_set) + duparg2("on/off", "on"); + sa->active = true; + active_set = true; + } else if (strcmp(*argv, "off") == 0) { + if (active_set) + duparg2("on/off", "off"); + sa->active = false; + active_set = true; + } else { + fprintf(stderr, "macsec: unknown command \"%s\"?\n", + *argv); + ipmacsec_usage(); + } + + argv++; argc--; + } + + *argvp = argv; + *argcp = argc; + return 0; +} + +static __u64 make_sci(char *addr, __be16 port) +{ + __u64 sci; + + memcpy(&sci, addr, ETH_ALEN); + memcpy(((char *)&sci) + ETH_ALEN, &port, sizeof(port)); + + return sci; +} + +static bool sci_complete(bool sci, bool port, bool addr, bool port_only) +{ + return sci || (port && (addr || port_only)); +} + +static int get_sci_portaddr(struct sci *sci, int *argcp, char ***argvp, + bool port_only, bool optional) +{ + int argc = *argcp; + char **argv = *argvp; + int ret; + bool p = false, a = false, s = false; + + while (argc > 0) { + if (strcmp(*argv, "sci") == 0) { + if (p) + invarg("expected address", *argv); + if (a) + invarg("expected port", *argv); + NEXT_ARG(); + ret = get_sci(&sci->sci, *argv); + if (ret) + invarg("expected sci", *argv); + s = true; + } else if (strcmp(*argv, "port") == 0) { + NEXT_ARG(); + ret = get_port(&sci->port, *argv); + if (ret) + invarg("expected port", *argv); + if (sci->port == 0) + invarg("expected port != 0", *argv); + p = true; + } else if (strcmp(*argv, "address") == 0) { + NEXT_ARG(); + ret = ll_addr_a2n(sci->abuf, sizeof(sci->abuf), *argv); + if (ret < 0) + invarg("expected lladdr", *argv); + a = true; + } else if (optional) { + break; + } else { + invarg("expected sci, port, or address", *argv); + } + + argv++; argc--; + + if (sci_complete(s, p, a, port_only)) + break; + } + + if (!optional && !sci_complete(s, p, a, port_only)) + return -1; + + if (p && a) + sci->sci = make_sci(sci->abuf, sci->port); + + *argvp = argv; + *argcp = argc; + + return p || a || s; +} + +static bool parse_rxsci(int *argcp, char ***argvp, struct rxsc_desc *rxsc, + struct sa_desc *rxsa) +{ + struct sci sci = { 0 }; + + if (*argcp == 0 || + get_sci_portaddr(&sci, argcp, argvp, false, false) < 0) { + fprintf(stderr, "expected sci\n"); + ipmacsec_usage(); + } + + rxsc->sci = sci.sci; + + return get_sa(argcp, argvp, &rxsa->an); +} + +static int parse_rxsci_args(int *argcp, char ***argvp, struct rxsc_desc *rxsc) +{ + int argc = *argcp; + char **argv = *argvp; + bool active_set = false; + + while (argc > 0) { + if (strcmp(*argv, "on") == 0) { + if (active_set) + duparg2("on/off", "on"); + rxsc->active = true; + active_set = true; + } else if (strcmp(*argv, "off") == 0) { + if (active_set) + duparg2("on/off", "off"); + rxsc->active = false; + active_set = true; + } else { + fprintf(stderr, "macsec: unknown command \"%s\"?\n", + *argv); + ipmacsec_usage(); + } + + argv++; argc--; + } + + *argvp = argv; + *argcp = argc; + return 0; +} + +enum cmd { + CMD_ADD, + CMD_DEL, + CMD_UPD, + __CMD_MAX +}; + +static const enum macsec_nl_commands macsec_commands[__CMD_MAX][2][2] = { + [CMD_ADD] = { + [0] = {-1, MACSEC_CMD_ADD_RXSC}, + [1] = {MACSEC_CMD_ADD_TXSA, MACSEC_CMD_ADD_RXSA}, + }, + [CMD_UPD] = { + [0] = {-1, MACSEC_CMD_UPD_RXSC}, + [1] = {MACSEC_CMD_UPD_TXSA, MACSEC_CMD_UPD_RXSA}, + }, + [CMD_DEL] = { + [0] = {-1, MACSEC_CMD_DEL_RXSC}, + [1] = {MACSEC_CMD_DEL_TXSA, MACSEC_CMD_DEL_RXSA}, + }, +}; + +static int do_modify_nl(enum cmd c, enum macsec_nl_commands cmd, int ifindex, + struct rxsc_desc *rxsc, struct sa_desc *sa) +{ + struct rtattr *attr_sa; + + MACSEC_GENL_REQ(req, MACSEC_BUFLEN, cmd, NLM_F_REQUEST); + + addattr32(&req.n, MACSEC_BUFLEN, MACSEC_ATTR_IFINDEX, ifindex); + if (rxsc) { + struct rtattr *attr_rxsc; + + attr_rxsc = addattr_nest(&req.n, MACSEC_BUFLEN, + MACSEC_ATTR_RXSC_CONFIG); + addattr64(&req.n, MACSEC_BUFLEN, + MACSEC_RXSC_ATTR_SCI, rxsc->sci); + if (c != CMD_DEL && rxsc->active != 0xff) + addattr8(&req.n, MACSEC_BUFLEN, + MACSEC_RXSC_ATTR_ACTIVE, rxsc->active); + + addattr_nest_end(&req.n, attr_rxsc); + } + + if (sa->an == 0xff) + goto talk; + + attr_sa = addattr_nest(&req.n, MACSEC_BUFLEN, MACSEC_ATTR_SA_CONFIG); + + addattr8(&req.n, MACSEC_BUFLEN, MACSEC_SA_ATTR_AN, sa->an); + + if (c != CMD_DEL) { + if (sa->pn) + addattr32(&req.n, MACSEC_BUFLEN, MACSEC_SA_ATTR_PN, + sa->pn); + + if (sa->key_len) { + addattr_l(&req.n, MACSEC_BUFLEN, MACSEC_SA_ATTR_KEYID, + sa->key_id, MACSEC_KEYID_LEN); + addattr_l(&req.n, MACSEC_BUFLEN, MACSEC_SA_ATTR_KEY, + sa->key, sa->key_len); + } + + if (sa->active != 0xff) { + addattr8(&req.n, MACSEC_BUFLEN, + MACSEC_SA_ATTR_ACTIVE, sa->active); + } + } + + addattr_nest_end(&req.n, attr_sa); + +talk: + if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0) + return -2; + + return 0; +} + +static bool check_sa_args(enum cmd c, struct sa_desc *sa) +{ + if (c == CMD_ADD) { + if (!sa->key_len) { + fprintf(stderr, "cannot create SA without key\n"); + return -1; + } + + if (sa->pn == 0) { + fprintf(stderr, "must specify a packet number != 0\n"); + return -1; + } + } else if (c == CMD_UPD) { + if (sa->key_len) { + fprintf(stderr, "cannot change key on SA\n"); + return -1; + } + } + + return 0; +} + +static int do_modify_txsa(enum cmd c, int argc, char **argv, int ifindex) +{ + struct sa_desc txsa = {0}; + enum macsec_nl_commands cmd; + + txsa.an = 0xff; + txsa.active = 0xff; + + if (argc == 0 || !get_sa(&argc, &argv, &txsa.an)) + ipmacsec_usage(); + + if (c == CMD_DEL) + goto modify; + + if (parse_sa_args(&argc, &argv, &txsa)) + return -1; + + if (check_sa_args(c, &txsa)) + return -1; + +modify: + cmd = macsec_commands[c][1][0]; + return do_modify_nl(c, cmd, ifindex, NULL, &txsa); +} + +static int do_modify_rxsci(enum cmd c, int argc, char **argv, int ifindex) +{ + struct rxsc_desc rxsc = {0}; + struct sa_desc rxsa = {0}; + bool sa_set; + enum macsec_nl_commands cmd; + + rxsc.ifindex = ifindex; + rxsc.active = 0xff; + rxsa.an = 0xff; + rxsa.active = 0xff; + + sa_set = parse_rxsci(&argc, &argv, &rxsc, &rxsa); + + if (c == CMD_DEL) + goto modify; + + if (sa_set && (parse_sa_args(&argc, &argv, &rxsa) || + check_sa_args(c, &rxsa))) + return -1; + if (!sa_set && parse_rxsci_args(&argc, &argv, &rxsc)) + return -1; + +modify: + cmd = macsec_commands[c][sa_set][1]; + return do_modify_nl(c, cmd, rxsc.ifindex, &rxsc, &rxsa); +} + +static int do_modify(enum cmd c, int argc, char **argv) +{ + int ifindex; + + if (argc == 0) + ipmacsec_usage(); + + ifindex = ll_name_to_index(*argv); + if (!ifindex) { + fprintf(stderr, "Device \"%s\" does not exist.\n", *argv); + return -1; + } + argc--; argv++; + + if (argc == 0) + ipmacsec_usage(); + + if (strcmp(*argv, "tx") == 0) + return do_modify_txsa(c, argc-1, argv+1, ifindex); + if (strcmp(*argv, "rx") == 0) + return do_modify_rxsci(c, argc-1, argv+1, ifindex); + + ipmacsec_usage(); + return -1; +} + +/* dump/show */ +static struct { + int ifindex; + __u64 sci; +} filter; + +static int validate_dump(struct rtattr **attrs) +{ + return attrs[MACSEC_ATTR_IFINDEX] && attrs[MACSEC_ATTR_SECY] && + attrs[MACSEC_ATTR_TXSA_LIST] && attrs[MACSEC_ATTR_RXSC_LIST] && + attrs[MACSEC_ATTR_TXSC_STATS] && attrs[MACSEC_ATTR_SECY_STATS]; + +} + +static int validate_secy_dump(struct rtattr **attrs) +{ + return attrs[MACSEC_SECY_ATTR_SCI] && + attrs[MACSEC_SECY_ATTR_ENCODING_SA] && + attrs[MACSEC_SECY_ATTR_CIPHER_SUITE] && + attrs[MACSEC_SECY_ATTR_ICV_LEN] && + attrs[MACSEC_SECY_ATTR_PROTECT] && + attrs[MACSEC_SECY_ATTR_REPLAY] && + attrs[MACSEC_SECY_ATTR_OPER] && + attrs[MACSEC_SECY_ATTR_VALIDATE] && + attrs[MACSEC_SECY_ATTR_ENCRYPT] && + attrs[MACSEC_SECY_ATTR_INC_SCI] && + attrs[MACSEC_SECY_ATTR_ES] && + attrs[MACSEC_SECY_ATTR_SCB]; +} + +static void print_flag(FILE *f, struct rtattr *attrs[], const char *desc, + int field) +{ + if (attrs[field]) + fprintf(f, "%s %s ", desc, + values_on_off[!!rta_getattr_u8(attrs[field])]); +} + +#define DEFAULT_CIPHER_NAME "GCM-AES-128" + +static const char *cs_id_to_name(__u64 cid) +{ + switch (cid) { + case MACSEC_DEFAULT_CIPHER_ID: + case MACSEC_DEFAULT_CIPHER_ALT: + return DEFAULT_CIPHER_NAME; + default: + return "(unknown)"; + } +} + +static void print_cipher_suite(const char *prefix, __u64 cid, __u8 icv_len) +{ + printf("%scipher suite: %s, using ICV length %d\n", prefix, + cs_id_to_name(cid), icv_len); +} + +static void print_attrs(const char *prefix, struct rtattr *attrs[]) +{ + print_flag(stdout, attrs, "protect", MACSEC_SECY_ATTR_PROTECT); + + if (attrs[MACSEC_SECY_ATTR_VALIDATE]) { + __u8 val = rta_getattr_u8(attrs[MACSEC_SECY_ATTR_VALIDATE]); + + printf("validate %s ", VALIDATE_STR[val]); + } + + print_flag(stdout, attrs, "sc", MACSEC_RXSC_ATTR_ACTIVE); + print_flag(stdout, attrs, "sa", MACSEC_SA_ATTR_ACTIVE); + print_flag(stdout, attrs, "encrypt", MACSEC_SECY_ATTR_ENCRYPT); + print_flag(stdout, attrs, "send_sci", MACSEC_SECY_ATTR_INC_SCI); + print_flag(stdout, attrs, "end_station", MACSEC_SECY_ATTR_ES); + print_flag(stdout, attrs, "scb", MACSEC_SECY_ATTR_SCB); + + print_flag(stdout, attrs, "replay", MACSEC_SECY_ATTR_REPLAY); + if (attrs[MACSEC_SECY_ATTR_WINDOW]) { + printf("window %d ", + rta_getattr_u32(attrs[MACSEC_SECY_ATTR_WINDOW])); + } + + if (attrs[MACSEC_SECY_ATTR_CIPHER_SUITE] && + attrs[MACSEC_SECY_ATTR_ICV_LEN]) { + printf("\n"); + print_cipher_suite(prefix, + rta_getattr_u64(attrs[MACSEC_SECY_ATTR_CIPHER_SUITE]), + rta_getattr_u8(attrs[MACSEC_SECY_ATTR_ICV_LEN])); + } + +} + +static void print_one_stat(const char **names, struct rtattr **attr, int idx, + bool long_stat) +{ + int pad = strlen(names[idx]) + 1; + + if (attr[idx]) { + if (long_stat) + printf("%*llu", pad, rta_getattr_u64(attr[idx])); + else + printf("%*u", pad, rta_getattr_u32(attr[idx])); + } else { + printf("%*c", pad, '-'); + } +} + +static const char *txsc_stats_names[NUM_MACSEC_TXSC_STATS_ATTR] = { + [MACSEC_TXSC_STATS_ATTR_OUT_PKTS_PROTECTED] = "OutOctetsProtected", + [MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED] = "OutOctetsEncrypted", + [MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED] = "OutPktsProtected", + [MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED] = "OutPktsEncrypted", +}; + +static void print_txsc_stats(const char *prefix, struct rtattr *attr) +{ + struct rtattr *stats[MACSEC_TXSC_STATS_ATTR_MAX + 1]; + int i; + + if (!attr || show_stats == 0) + return; + + parse_rtattr_nested(stats, MACSEC_TXSC_STATS_ATTR_MAX + 1, attr); + printf("%sstats:", prefix); + + for (i = 1; i < NUM_MACSEC_TXSC_STATS_ATTR; i++) { + if (!txsc_stats_names[i]) + continue; + printf(" %s", txsc_stats_names[i]); + } + + printf("\n%s ", prefix); + + for (i = 1; i < NUM_MACSEC_TXSC_STATS_ATTR; i++) { + if (!txsc_stats_names[i]) + continue; + print_one_stat(txsc_stats_names, stats, i, true); + } + + printf("\n"); +} + +static const char *secy_stats_names[NUM_MACSEC_SECY_STATS_ATTR] = { + [MACSEC_SECY_STATS_ATTR_OUT_PKTS_UNTAGGED] = "OutPktsUntagged", + [MACSEC_SECY_STATS_ATTR_IN_PKTS_UNTAGGED] = "InPktsUntagged", + [MACSEC_SECY_STATS_ATTR_OUT_PKTS_TOO_LONG] = "OutPktsTooLong", + [MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_TAG] = "InPktsNoTag", + [MACSEC_SECY_STATS_ATTR_IN_PKTS_BAD_TAG] = "InPktsBadTag", + [MACSEC_SECY_STATS_ATTR_IN_PKTS_UNKNOWN_SCI] = "InPktsUnknownSCI", + [MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_SCI] = "InPktsNoSCI", + [MACSEC_SECY_STATS_ATTR_IN_PKTS_OVERRUN] = "InPktsOverrun", +}; + +static void print_secy_stats(const char *prefix, struct rtattr *attr) +{ + struct rtattr *stats[MACSEC_SECY_STATS_ATTR_MAX + 1]; + int i; + + if (!attr || show_stats == 0) + return; + + parse_rtattr_nested(stats, MACSEC_SECY_STATS_ATTR_MAX + 1, attr); + printf("%sstats:", prefix); + + for (i = 1; i < NUM_MACSEC_SECY_STATS_ATTR; i++) { + if (!secy_stats_names[i]) + continue; + printf(" %s", secy_stats_names[i]); + } + + printf("\n%s ", prefix); + + for (i = 1; i < NUM_MACSEC_SECY_STATS_ATTR; i++) { + if (!secy_stats_names[i]) + continue; + print_one_stat(secy_stats_names, stats, i, true); + } + + printf("\n"); +} + +static const char *rxsa_stats_names[NUM_MACSEC_SA_STATS_ATTR] = { + [MACSEC_SA_STATS_ATTR_IN_PKTS_OK] = "InPktsOK", + [MACSEC_SA_STATS_ATTR_IN_PKTS_INVALID] = "InPktsInvalid", + [MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_VALID] = "InPktsNotValid", + [MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_USING_SA] = "InPktsNotUsingSA", + [MACSEC_SA_STATS_ATTR_IN_PKTS_UNUSED_SA] = "InPktsUnusedSA", +}; + +static void print_rxsa_stats(const char *prefix, struct rtattr *attr) +{ + struct rtattr *stats[MACSEC_SA_STATS_ATTR_MAX + 1]; + int i; + + if (!attr || show_stats == 0) + return; + + parse_rtattr_nested(stats, MACSEC_SA_STATS_ATTR_MAX + 1, attr); + printf("%s%s ", prefix, prefix); + + for (i = 1; i < NUM_MACSEC_SA_STATS_ATTR; i++) { + if (!rxsa_stats_names[i]) + continue; + printf(" %s", rxsa_stats_names[i]); + } + + printf("\n%s%s ", prefix, prefix); + + for (i = 1; i < NUM_MACSEC_SA_STATS_ATTR; i++) { + if (!rxsa_stats_names[i]) + continue; + print_one_stat(rxsa_stats_names, stats, i, false); + } + + printf("\n"); +} + +static const char *txsa_stats_names[NUM_MACSEC_SA_STATS_ATTR] = { + [MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED] = "OutPktsProtected", + [MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED] = "OutPktsEncrypted", +}; + +static void print_txsa_stats(const char *prefix, struct rtattr *attr) +{ + struct rtattr *stats[MACSEC_SA_STATS_ATTR_MAX + 1]; + + if (!attr || show_stats == 0) + return; + + parse_rtattr_nested(stats, MACSEC_SA_STATS_ATTR_MAX + 1, attr); + printf("%s%s %s %s\n", prefix, prefix, + txsa_stats_names[MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED], + txsa_stats_names[MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED]); + printf("%s%s ", prefix, prefix); + + print_one_stat(txsa_stats_names, stats, + MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED, false); + print_one_stat(txsa_stats_names, stats, + MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED, false); + printf("\n"); +} + +static void print_tx_sc(const char *prefix, __u64 sci, __u8 encoding_sa, + struct rtattr *txsc_stats, struct rtattr *secy_stats, + struct rtattr *sa) +{ + struct rtattr *sa_attr[MACSEC_SA_ATTR_MAX + 1]; + struct rtattr *a; + int rem; + + printf("%sTXSC: %016llx on SA %d\n", prefix, sci, encoding_sa); + print_secy_stats(prefix, secy_stats); + print_txsc_stats(prefix, txsc_stats); + + rem = RTA_PAYLOAD(sa); + for (a = RTA_DATA(sa); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) { + SPRINT_BUF(keyid); + bool state; + + parse_rtattr_nested(sa_attr, MACSEC_SA_ATTR_MAX + 1, a); + state = rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_ACTIVE]); + printf("%s%s%d: PN %u, state %s, key %s\n", prefix, prefix, + rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_AN]), + rta_getattr_u32(sa_attr[MACSEC_SA_ATTR_PN]), + values_on_off[state], + hexstring_n2a(RTA_DATA(sa_attr[MACSEC_SA_ATTR_KEYID]), + RTA_PAYLOAD(sa_attr[MACSEC_SA_ATTR_KEYID]), + keyid, sizeof(keyid))); + print_txsa_stats(prefix, sa_attr[MACSEC_SA_ATTR_STATS]); + } +} + +static const char *rxsc_stats_names[NUM_MACSEC_RXSC_STATS_ATTR] = { + [MACSEC_RXSC_STATS_ATTR_IN_OCTETS_VALIDATED] = "InOctetsValidated", + [MACSEC_RXSC_STATS_ATTR_IN_OCTETS_DECRYPTED] = "InOctetsDecrypted", + [MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNCHECKED] = "InPktsUnchecked", + [MACSEC_RXSC_STATS_ATTR_IN_PKTS_DELAYED] = "InPktsDelayed", + [MACSEC_RXSC_STATS_ATTR_IN_PKTS_OK] = "InPktsOK", + [MACSEC_RXSC_STATS_ATTR_IN_PKTS_INVALID] = "InPktsInvalid", + [MACSEC_RXSC_STATS_ATTR_IN_PKTS_LATE] = "InPktsLate", + [MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_VALID] = "InPktsNotValid", + [MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_USING_SA] = "InPktsNotUsingSA", + [MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNUSED_SA] = "InPktsUnusedSA", +}; + +static void print_rxsc_stats(const char *prefix, struct rtattr *attr) +{ + struct rtattr *stats[MACSEC_RXSC_STATS_ATTR_MAX + 1]; + int i; + + if (!attr || show_stats == 0) + return; + + parse_rtattr_nested(stats, MACSEC_RXSC_STATS_ATTR_MAX + 1, attr); + printf("%sstats:", prefix); + for (i = 1; i < NUM_MACSEC_RXSC_STATS_ATTR; i++) { + if (!rxsc_stats_names[i]) + continue; + printf(" %s", rxsc_stats_names[i]); + } + + printf("\n%s ", prefix); + + for (i = 1; i < NUM_MACSEC_RXSC_STATS_ATTR; i++) { + if (!rxsc_stats_names[i]) + continue; + print_one_stat(rxsc_stats_names, stats, i, true); + } + + printf("\n"); +} + +static void print_rx_sc(const char *prefix, __u64 sci, __u8 active, + struct rtattr *rxsc_stats, struct rtattr *sa) +{ + struct rtattr *sa_attr[MACSEC_SA_ATTR_MAX + 1]; + struct rtattr *a; + int rem; + + printf("%sRXSC: %016llx, state %s\n", prefix, sci, + values_on_off[!!active]); + print_rxsc_stats(prefix, rxsc_stats); + + rem = RTA_PAYLOAD(sa); + for (a = RTA_DATA(sa); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) { + SPRINT_BUF(keyid); + bool state; + + parse_rtattr_nested(sa_attr, MACSEC_SA_ATTR_MAX + 1, a); + state = rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_ACTIVE]); + printf("%s%s%d: PN %u, state %s, key %s\n", prefix, prefix, + rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_AN]), + rta_getattr_u32(sa_attr[MACSEC_SA_ATTR_PN]), + values_on_off[state], + hexstring_n2a(RTA_DATA(sa_attr[MACSEC_SA_ATTR_KEYID]), + RTA_PAYLOAD(sa_attr[MACSEC_SA_ATTR_KEYID]), + keyid, sizeof(keyid))); + print_rxsa_stats(prefix, sa_attr[MACSEC_SA_ATTR_STATS]); + } +} + +static int process(const struct sockaddr_nl *who, struct nlmsghdr *n, + void *arg) +{ + struct genlmsghdr *ghdr; + struct rtattr *attrs[MACSEC_ATTR_MAX + 1], *sc, *c; + struct rtattr *attrs_secy[MACSEC_SECY_ATTR_MAX + 1]; + int len = n->nlmsg_len; + int ifindex; + __u64 sci; + __u8 encoding_sa; + int rem; + + if (n->nlmsg_type != genl_family) + return -1; + + len -= NLMSG_LENGTH(GENL_HDRLEN); + if (len < 0) + return -1; + + ghdr = NLMSG_DATA(n); + if (ghdr->cmd != MACSEC_CMD_GET_TXSC) + return 0; + + parse_rtattr(attrs, MACSEC_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len); + if (!validate_dump(attrs)) { + printf("incomplete dump message\n"); + return -1; + } + + ifindex = rta_getattr_u32(attrs[MACSEC_ATTR_IFINDEX]); + parse_rtattr_nested(attrs_secy, MACSEC_SECY_ATTR_MAX + 1, + attrs[MACSEC_ATTR_SECY]); + + if (!validate_secy_dump(attrs_secy)) { + printf("incomplete dump message\n"); + return -1; + } + + sci = rta_getattr_u64(attrs_secy[MACSEC_SECY_ATTR_SCI]); + encoding_sa = rta_getattr_u8(attrs_secy[MACSEC_SECY_ATTR_ENCODING_SA]); + + if (filter.ifindex && ifindex != filter.ifindex) + return 0; + + if (filter.sci && sci != filter.sci) + return 0; + + printf("%d: %s: ", ifindex, ll_index_to_name(ifindex)); + print_attrs(" ", attrs_secy); + + print_tx_sc(" ", sci, encoding_sa, + attrs[MACSEC_ATTR_TXSC_STATS], + attrs[MACSEC_ATTR_SECY_STATS], + attrs[MACSEC_ATTR_TXSA_LIST]); + + if (!attrs[MACSEC_ATTR_RXSC_LIST]) + return 0; + + sc = attrs[MACSEC_ATTR_RXSC_LIST]; + rem = RTA_PAYLOAD(sc); + for (c = RTA_DATA(sc); RTA_OK(c, rem); c = RTA_NEXT(c, rem)) { + struct rtattr *sc_attr[MACSEC_RXSC_ATTR_MAX + 1]; + + parse_rtattr_nested(sc_attr, MACSEC_RXSC_ATTR_MAX + 1, c); + print_rx_sc(" ", + rta_getattr_u64(sc_attr[MACSEC_RXSC_ATTR_SCI]), + rta_getattr_u32(sc_attr[MACSEC_RXSC_ATTR_ACTIVE]), + sc_attr[MACSEC_RXSC_ATTR_STATS], + sc_attr[MACSEC_RXSC_ATTR_SA_LIST]); + } + + return 0; +} + +static int do_dump(int ifindex) +{ + MACSEC_GENL_REQ(req, MACSEC_BUFLEN, MACSEC_CMD_GET_TXSC, + NLM_F_REQUEST | NLM_F_DUMP); + + memset(&filter, 0, sizeof(filter)); + filter.ifindex = ifindex; + + req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq; + if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0) { + perror("Failed to send dump request"); + exit(1); + } + + if (rtnl_dump_filter(&genl_rth, process, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); + exit(1); + } + + return 0; +} + +static int do_show(int argc, char **argv) +{ + int ifindex; + + if (argc == 0) + return do_dump(0); + + ifindex = ll_name_to_index(*argv); + if (ifindex == 0) { + fprintf(stderr, "Device \"%s\" does not exist.\n", *argv); + return -1; + } + + argc--, argv++; + if (argc == 0) + return do_dump(ifindex); + + ipmacsec_usage(); + return -1; +} + +int do_ipmacsec(int argc, char **argv) +{ + init_genl(); + + if (argc < 1) + ipmacsec_usage(); + + if (matches(*argv, "help") == 0) + ipmacsec_usage(); + + if (matches(*argv, "show") == 0) + return do_show(argc-1, argv+1); + + if (matches(*argv, "add") == 0) + return do_modify(CMD_ADD, argc-1, argv+1); + if (matches(*argv, "set") == 0) + return do_modify(CMD_UPD, argc-1, argv+1); + if (matches(*argv, "delete") == 0) + return do_modify(CMD_DEL, argc-1, argv+1); + + fprintf(stderr, "Command \"%s\" is unknown, try \"ip macsec help\".\n", + *argv); + exit(-1); +} + +/* device creation */ +static void macsec_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) +{ + if (!tb) + return; + + if (tb[IFLA_MACSEC_SCI]) { + fprintf(f, "sci %016llx ", + rta_getattr_u64(tb[IFLA_MACSEC_SCI])); + } + + print_flag(f, tb, "protect", IFLA_MACSEC_PROTECT); + + if (tb[IFLA_MACSEC_CIPHER_SUITE]) { + __u64 csid = rta_getattr_u64(tb[IFLA_MACSEC_CIPHER_SUITE]); + + fprintf(f, "cipher %s ", cs_id_to_name(csid)); + } + + if (tb[IFLA_MACSEC_ICV_LEN]) { + fprintf(f, "icvlen %hhu ", + rta_getattr_u8(tb[IFLA_MACSEC_ICV_LEN])); + } + + if (tb[IFLA_MACSEC_ENCODING_SA]) { + fprintf(f, "encodingsa %hhu ", + rta_getattr_u8(tb[IFLA_MACSEC_ENCODING_SA])); + } + + if (tb[IFLA_MACSEC_VALIDATION]) { + __u8 val = rta_getattr_u8(tb[IFLA_MACSEC_VALIDATION]); + + fprintf(f, "validate %s ", VALIDATE_STR[val]); + } + + print_flag(f, tb, "encrypt", IFLA_MACSEC_ENCRYPT); + print_flag(f, tb, "send_sci", IFLA_MACSEC_INC_SCI); + print_flag(f, tb, "end_station", IFLA_MACSEC_ES); + print_flag(f, tb, "scb", IFLA_MACSEC_SCB); + + print_flag(f, tb, "replay", IFLA_MACSEC_REPLAY_PROTECT); + if (tb[IFLA_MACSEC_WINDOW]) { + fprintf(f, "window %d ", + rta_getattr_u32(tb[IFLA_MACSEC_WINDOW])); + } +} + + +static int do_cipher_suite(struct cipher_args *cipher, int *argcp, + char ***argvp) +{ + char **argv = *argvp; + int argc = *argcp; + + if (argc == 0) + return -1; + + if (strcmp(*argv, "default") == 0 || + strcmp(*argv, "gcm-aes-128") == 0 || + strcmp(*argv, "GCM-AES-128") == 0) + cipher->id = MACSEC_DEFAULT_CIPHER_ID; + NEXT_ARG(); + + if (strcmp(*argv, "icvlen") == 0) { + NEXT_ARG(); + if (cipher->icv_len != 0) + duparg2("icvlen", "icvlen"); + get_icvlen(&cipher->icv_len, *argv); + } + *argcp = argc; + *argvp = argv; + + return 0; +} + +static bool check_txsc_flags(bool es, bool scb, bool sci) +{ + if (sci && (es || scb)) + return false; + if (es && scb) + return false; + return true; +} + +static void usage(FILE *f) +{ + fprintf(f, + "Usage: ... macsec [ port PORT | sci SCI ]\n" + " [ cipher CIPHER_SUITE ]\n" + " [ encrypt { on | off } ]\n" + " [ send_sci { on | off } ]\n" + " [ end_station { on | off } ]\n" + " [ scb { on | off } ]\n" + " [ protect { on | off } ]\n" + " [ replay { on | off} window { 0..2^32-1 } ]\n" + " [ validate { strict | check | disabled } ]\n" + " [ encodingsa { 0..3 } ]\n" + ); + fprintf(f, "CIPHER_SUITE := [ default = gcm-aes-128 ] icvlen { 8..32 }\n"); +} + +static int macsec_parse_opt(struct link_util *lu, int argc, char **argv, + struct nlmsghdr *hdr) +{ + int ret; + __u8 encoding_sa = 0xff; + __u32 window = -1; + struct cipher_args cipher = {0}; + enum macsec_validation_type validate; + bool es = false, scb = false, send_sci = false; + int replay_protect = -1; + struct sci sci = { 0 }; + + ret = get_sci_portaddr(&sci, &argc, &argv, true, true); + if (ret < 0) { + fprintf(stderr, "expected sci\n"); + return -1; + } + + if (ret > 0) { + if (sci.sci) + addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_SCI, + &sci.sci, sizeof(sci.sci)); + else + addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_PORT, + &sci.port, sizeof(sci.port)); + } + + while (argc > 0) { + if (strcmp(*argv, "cipher") == 0) { + if (cipher.id) + duparg2("cipher", "cipher"); + NEXT_ARG(); + if (do_cipher_suite(&cipher, &argc, &argv)) + return -1; + } else if (strcmp(*argv, "encrypt") == 0) { + NEXT_ARG(); + int i; + + ret = one_of("encrypt", *argv, values_on_off, + ARRAY_SIZE(values_on_off), &i); + if (ret != 0) + return ret; + addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_ENCRYPT, i); + } else if (strcmp(*argv, "send_sci") == 0) { + NEXT_ARG(); + int i; + + ret = one_of("send_sci", *argv, values_on_off, + ARRAY_SIZE(values_on_off), &i); + if (ret != 0) + return ret; + send_sci = i; + addattr8(hdr, MACSEC_BUFLEN, + IFLA_MACSEC_INC_SCI, send_sci); + } else if (strcmp(*argv, "end_station") == 0) { + NEXT_ARG(); + int i; + + ret = one_of("end_station", *argv, values_on_off, + ARRAY_SIZE(values_on_off), &i); + if (ret != 0) + return ret; + es = i; + addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_ES, es); + } else if (strcmp(*argv, "scb") == 0) { + NEXT_ARG(); + int i; + + ret = one_of("scb", *argv, values_on_off, + ARRAY_SIZE(values_on_off), &i); + if (ret != 0) + return ret; + scb = i; + addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_SCB, scb); + } else if (strcmp(*argv, "protect") == 0) { + NEXT_ARG(); + int i; + + ret = one_of("protect", *argv, values_on_off, + ARRAY_SIZE(values_on_off), &i); + if (ret != 0) + return ret; + addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_PROTECT, i); + } else if (strcmp(*argv, "replay") == 0) { + NEXT_ARG(); + int i; + + ret = one_of("replay", *argv, values_on_off, + ARRAY_SIZE(values_on_off), &i); + if (ret != 0) + return ret; + replay_protect = !!i; + } else if (strcmp(*argv, "window") == 0) { + NEXT_ARG(); + ret = get_u32(&window, *argv, 0); + if (ret) + invarg("expected replay window size", *argv); + } else if (strcmp(*argv, "validate") == 0) { + NEXT_ARG(); + ret = one_of("validate", *argv, + VALIDATE_STR, ARRAY_SIZE(VALIDATE_STR), + (int *)&validate); + if (ret != 0) + return ret; + addattr8(hdr, MACSEC_BUFLEN, + IFLA_MACSEC_VALIDATION, validate); + } else if (strcmp(*argv, "encodingsa") == 0) { + if (encoding_sa != 0xff) + duparg2("encodingsa", "encodingsa"); + NEXT_ARG(); + ret = get_an(&encoding_sa, *argv); + if (ret) + invarg("expected an { 0..3 }", *argv); + } else { + fprintf(stderr, "macsec: unknown command \"%s\"?\n", + *argv); + usage(stderr); + return -1; + } + + argv++; argc--; + } + + if (!check_txsc_flags(es, scb, send_sci)) { + fprintf(stderr, "invalid combination of send_sci/end_station/scb\n"); + return -1; + } + + if (window != -1 && replay_protect == -1) { + fprintf(stderr, + "replay window set, but replay protection not enabled. did you mean 'replay on window %u'?\n", + window); + return -1; + } else if (window == -1 && replay_protect == 1) { + fprintf(stderr, + "replay protection enabled, but no window set. did you mean 'replay on window VALUE'?\n"); + return -1; + } + + if (cipher.id) { + addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_CIPHER_SUITE, + &cipher.id, sizeof(cipher.id)); + addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_ICV_LEN, + &cipher.icv_len, sizeof(cipher.icv_len)); + } + + if (replay_protect != -1) { + addattr32(hdr, MACSEC_BUFLEN, IFLA_MACSEC_WINDOW, window); + addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_REPLAY_PROTECT, + replay_protect); + } + + if (encoding_sa != 0xff) { + addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_ENCODING_SA, + &encoding_sa, sizeof(encoding_sa)); + } + + return 0; +} + +static void macsec_print_help(struct link_util *lu, int argc, char **argv, + FILE *f) +{ + usage(f); +} + +struct link_util macsec_link_util = { + .id = "macsec", + .maxattr = IFLA_MACSEC_MAX, + .parse_opt = macsec_parse_opt, + .print_help = macsec_print_help, + .print_opt = macsec_print_opt, + .slave = false, +}; diff --git a/man/man8/Makefile b/man/man8/Makefile index d3fdf66ab..929826ecb 100644 --- a/man/man8/Makefile +++ b/man/man8/Makefile @@ -7,7 +7,7 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. tc-mqprio.8 tc-netem.8 tc-pfifo.8 tc-pfifo_fast.8 tc-prio.8 tc-red.8 \ tc-sfb.8 tc-sfq.8 tc-stab.8 tc-tbf.8 \ bridge.8 rtstat.8 ctstat.8 nstat.8 routef.8 \ - ip-addrlabel.8 ip-fou.8 ip-gue.8 ip-l2tp.8 \ + ip-addrlabel.8 ip-fou.8 ip-gue.8 ip-l2tp.8 ip-macsec.8 \ ip-maddress.8 ip-monitor.8 ip-mroute.8 ip-neighbour.8 \ ip-netns.8 ip-ntable.8 ip-rule.8 ip-tunnel.8 ip-xfrm.8 \ ip-tcp_metrics.8 ip-netconf.8 ip-token.8 \ diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 0e3ae1ba4..8fcce5e53 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -258,6 +258,9 @@ Link types: .sp .BR geneve - GEneric NEtwork Virtualization Encapsulation +.sp +.BR macsec +- Interface for IEEE 802.1AE MAC Security (MACsec) .in -8 .TP @@ -879,6 +882,88 @@ corresponds to the 2010 version of the HSR standard. Option "1" activates the 2012 version. .in -8 +.TP +MACsec Type Support +For a link of type +.I MACsec +the following additional arguments are supported: + +.BI "ip link add link " DEVICE " name " NAME " type macsec" +[ +.BI port " PORT" +| +.BI sci " SCI" +] [ +.BI cipher " CIPHER_SUITE" +] [ +.BR encrypt " {" +.BR on " | " off " } ] [ " +.BR send_sci " { " on " | " off " } ] [" +.BR es " { " on " | " off " } ] [" +.BR scb " { " on " | " off " } ] [" +.BR protect " { " on " | " off " } ] [" +.BR replay " { " on " | " off " }" +.BR window " { " +.IR 0..2^32-1 " } ] [" +.BR validate " { " strict " | " check " | " disabled " } ] [" +.BR encoding " { " +.IR 0..3 " } ]" + +.in +8 +.sp +.BI port " PORT " +- sets the port number for this MACsec device. + +.sp +.BI sci " SCI " +- sets the SCI for this MACsec device. + +.sp +.BI cipher " CIPHER_SUITE " +- defines the cipher suite to use. + +.sp +.BR "encrypt on " or " encrypt off" +- switches between authenticated encryption, or authenticity mode only. + +.sp +.BR "send_sci on " or " send_sci off" +- specifies whether the SCI is included in every packet, or only when it is necessary. + +.sp +.BR "es on " or " es off" +- sets the End Station bit. + +.sp +.BR "scb on " or " scb off" +- sets the Single Copy Broadcast bit. + +.sp +.BR "protect on " or " protect off" +- enables MACsec protection on the device. + +.sp +.BR "replay on " or " replay off" +- enables replay protection on the device. + +.in +8 + +.sp +.BI window " SIZE " +- sets the size of the replay window. + +.in -8 + +.sp +.BR "validate strict " or " validate check " or " validate disabled" +- sets the validation mode on the device. + +.sp +.BI encoding " AN " +- sets the active secure association for transmission. + +.in -8 + .SS ip link delete - delete virtual link .TP diff --git a/man/man8/ip-macsec.8 b/man/man8/ip-macsec.8 new file mode 100644 index 000000000..e8455d77e --- /dev/null +++ b/man/man8/ip-macsec.8 @@ -0,0 +1,98 @@ +.TH IP\-MACSEC 8 "07 Mar 2016" "iproute" "Linux" +.SH NAME +ip-macsec \- MACsec device configuration +.SH "SYNOPSIS" +.BI "ip link add link " DEVICE " name " NAME " type macsec " +[ [ +.BR cipher " { " default " | " gcm-aes-128 " } ] " +.BI icvlen " ICVLEN" +] [ [ +.BR encrypt " { " on " | " off " } ] [" +.BR send_sci " { " on " | " off " } ] [" +.BR end_station " { " on " | " off " } ] [" +.BR scb " { " on " | " off " } ] [" +.BR protect " { " on " | " off " } ] [" +.BR replay " { " on " | " off " } ] [" +.BI window " WINDOW" +] [ +.BI encodingsa " SA" +] + +.BI "ip macsec add " DEV " tx sa" +.RI "{ " 0..3 " } [ " OPTS " ]" +.BI key " ID KEY" +.br +.BI "ip macsec set " DEV " tx sa" +.RI "{ " 0..3 " } [ " OPTS " ]" +.br +.BI "ip macsec del " DEV " tx sa" +.RI "{ " 0..3 " }" + +.BI "ip macsec add " DEV " rx " SCI +.RB [ " on " | " off " ] +.br +.BI "ip macsec set " DEV " rx " SCI +.RB [ " on " | " off " ] +.br +.BI "ip macsec del " DEV " rx " SCI + +.BI "ip macsec add " DEV " rx " SCI " sa" +.RI "{ " 0..3 " } [ " OPTS " ]" +.BI key " ID KEY" +.br +.BI "ip macsec set " DEV " rx " SCI " sa" +.RI "{ " 0..3 " } [ " OPTS " ]" +.br +.BI "ip macsec del " DEV " rx " SCI " sa" +.RI "{ " 0..3 " }" + +.B ip macsec show +.RI [ " DEV " ] + +.IR OPTS " := [ " +.BR pn " { " +.IR 1..2^32-1 " } ] [" +.BR on " | " off " ]" +.br +.IR SCI " := { " +.B sci +.IR " | " +.BI port " " address " " +} + + +.SH DESCRIPTION +The +.B ip macsec +commands are used to configure transmit secure associations and receive secure channels and their secure associations on a MACsec device created with the +.B ip link add +command using the +.I macsec +type. + +.SH EXAMPLES +.PP +.SS Create a MACsec device on link eth0 +.nf +# ip link add device eth0 macsec0 type macsec port 11 encrypt on +.PP +.SS Configure a secure association on that device +.nf +# ip macsec add macsec0 tx sa 0 pn 1024 on key 01 81818181818181818181818181818181 +.PP +.SS Configure a receive channel +.nf +# ip macsec add macsec0 rx port 1234 address c6:19:52:8f:e6:a0 +.PP +.SS Configure a receive association +.nf +# ip macsec add macsec0 rx port 1234 address c6:19:52:8f:e6:a0 sa 0 pn 1 on key 00 82828282828282828282828282828282 +.PP +.SS Display MACsec configuration +.nf +# ip macsec show +.SH SEE ALSO +.br +.BR ip-link (8) +.SH AUTHOR +Sabrina Dubroca From c68780826d7255ae80ee7834117958f5ba97ebe5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 8 Jun 2016 09:39:03 -0700 Subject: [PATCH 257/513] minor header update from net-next --- include/linux/pkt_cls.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index 333b17167..44cda2549 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -61,8 +61,8 @@ struct tc_police { __u32 mtu; struct tc_ratespec rate; struct tc_ratespec peakrate; - int refcnt; - int bindcnt; + int refcnt; + int bindcnt; __u32 capab; }; @@ -70,10 +70,11 @@ struct tcf_t { __u64 install; __u64 lastuse; __u64 expires; + __u64 firstuse; }; struct tc_cnt { - int refcnt; + int refcnt; int bindcnt; }; From 6f1aded9d051aa954b673da68bec900adaea74aa Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 1 Jun 2016 12:21:41 +0900 Subject: [PATCH 258/513] iproute2: correct port in FOU/GRE example This resolves what appears to be a typo. Cc: Tom Herbert Reviewed-by: Dinan Gunawardena Signed-off-by: Simon Horman --- man/man8/ip-fou.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/ip-fou.8 b/man/man8/ip-fou.8 index 0fa22ee61..0c8f0a4d6 100644 --- a/man/man8/ip-fou.8 +++ b/man/man8/ip-fou.8 @@ -56,7 +56,7 @@ in the delete command. .PP .SS Configure a FOU receive port for GRE bound to 7777 .nf -# ip fou add port 8888 ipproto 47 +# ip fou add port 7777 ipproto 47 .PP .SS Configure a FOU receive port for IPIP bound to 8888 .nf From 5e5b3008d1fbb2ed74ac94153d6b5db37a903ae1 Mon Sep 17 00:00:00 2001 From: "Samudrala, Sridhar" Date: Wed, 8 Jun 2016 16:16:01 -0700 Subject: [PATCH 259/513] tc: f_u32: Add support for skip_hw and skip_sw flags On devices that support TC U32 offloads, these flags enable a filter to be added only to HW or only to SW. skip_sw and skip_hw are mutually exclusive flags. By default without any flags, the filter is added to both HW and SW, but no error checks are done in case of failure to add to HW. With skip-sw, failure to add to HW is treated as an error. Here is a sample script that adds 2 filters, one with skip_sw and the other with skip_hw flag. # add ingress qdisc tc qdisc add dev p4p1 ingress # enable hw tc offload. ethtool -K p4p1 hw-tc-offload on # add u32 filter with skip-sw flag. tc filter add dev p4p1 parent ffff: protocol ip prio 99 \ handle 800:0:1 u32 ht 800: flowid 800:1 \ skip-sw \ match ip src 192.168.1.0/24 \ action drop # add u32 filter with skip-hw flag. tc filter add dev p4p1 parent ffff: protocol ip prio 99 \ handle 800:0:2 u32 ht 800: flowid 800:2 \ skip-hw \ match ip src 192.168.2.0/24 \ action drop Signed-off-by: Sridhar Samudrala --- tc/f_u32.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/tc/f_u32.c b/tc/f_u32.c index 9424dc378..b6ae4d286 100644 --- a/tc/f_u32.c +++ b/tc/f_u32.c @@ -30,7 +30,7 @@ extern int show_pretty; static void explain(void) { - fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n"); + fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ] [skip-hw | skip-sw]\n"); fprintf(stderr, " [ action ACTION_SPEC ] [ offset OFFSET_SPEC ]\n"); fprintf(stderr, " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n"); fprintf(stderr, " [ sample SAMPLE ]\n"); @@ -993,6 +993,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, int sample_ok = 0; __u32 htid = 0; __u32 order = 0; + __u32 flags = 0; memset(&sel, 0, sizeof(sel)); @@ -1152,6 +1153,14 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, } terminal_ok++; continue; + } else if (strcmp(*argv, "skip_hw") == 0) { + NEXT_ARG(); + flags |= TCA_CLS_FLAGS_SKIP_HW; + continue; + } else if (strcmp(*argv, "skip_sw") == 0) { + NEXT_ARG(); + flags |= TCA_CLS_FLAGS_SKIP_SW; + continue; } else if (strcmp(*argv, "help") == 0) { explain(); return -1; @@ -1182,6 +1191,15 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel, sizeof(sel.sel) + sel.sel.nkeys * sizeof(struct tc_u32_key)); + if (flags) { + if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW))) { + fprintf(stderr, "skip_hw and skip_sw are mutually " + "exclusive flags. Only one can be set\n"); + return -1; + } + addattr_l(n, MAX_MSG, TCA_U32_FLAGS, &flags, 4); + } + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; } @@ -1240,6 +1258,15 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, b1)); } + if (tb[TCA_U32_FLAGS]) { + __u32 flags = rta_getattr_u32(tb[TCA_U32_FLAGS]); + + if (flags & TCA_CLS_FLAGS_SKIP_HW) + fprintf(f, "skip_hw "); + if (flags & TCA_CLS_FLAGS_SKIP_SW) + fprintf(f, "skip_sw "); + } + if (tb[TCA_U32_PCNT]) { if (RTA_PAYLOAD(tb[TCA_U32_PCNT]) < sizeof(*pf)) { fprintf(f, "Broken perf counters\n"); From 622812052a71e752d55f5348ad9679884cc239d9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 8 Jun 2016 16:45:26 -0700 Subject: [PATCH 260/513] tc: f_u32 cleanup indentation and long lines Several long lines and too long messages here. --- tc/f_u32.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/tc/f_u32.c b/tc/f_u32.c index b6ae4d286..0926461dc 100644 --- a/tc/f_u32.c +++ b/tc/f_u32.c @@ -30,16 +30,18 @@ extern int show_pretty; static void explain(void) { - fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ] [skip-hw | skip-sw]\n"); - fprintf(stderr, " [ action ACTION_SPEC ] [ offset OFFSET_SPEC ]\n"); - fprintf(stderr, " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n"); - fprintf(stderr, " [ sample SAMPLE ]\n"); - fprintf(stderr, "or u32 divisor DIVISOR\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n"); - fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n"); - fprintf(stderr, " FILTERID := X:Y:Z\n"); - fprintf(stderr, "\nNOTE: CLASSID is parsed at hexadecimal input.\n"); + fprintf(stderr, + "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n" + " [ action ACTION_SPEC ] [ offset OFFSET_SPEC ]\n" + " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n" + " [ sample SAMPLE ] [skip-hw | skip-sw]\n" + "or u32 divisor DIVISOR\n" + "\n" + "Where: SELECTOR := SAMPLE SAMPLE ...\n" + " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark }\n" + " SAMPLE_ARGS [ divisor DIVISOR ]\n" + " FILTERID := X:Y:Z\n" + "\nNOTE: CLASSID is parsed at hexadecimal input.\n"); } static int get_u32_handle(__u32 *handle, const char *str) @@ -1192,9 +1194,10 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, sizeof(sel.sel) + sel.sel.nkeys * sizeof(struct tc_u32_key)); if (flags) { - if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW))) { - fprintf(stderr, "skip_hw and skip_sw are mutually " - "exclusive flags. Only one can be set\n"); + if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW | + TCA_CLS_FLAGS_SKIP_SW))) { + fprintf(stderr, + "skip_hw and skip_sw are mutually exclusive\n"); return -1; } addattr_l(n, MAX_MSG, TCA_U32_FLAGS, &flags, 4); @@ -1220,9 +1223,9 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, SPRINT_BUF(b1); fprintf(f, "fh %s ", sprint_u32_handle(handle, b1)); } - if (TC_U32_NODE(handle)) { + + if (TC_U32_NODE(handle)) fprintf(f, "order %d ", TC_U32_NODE(handle)); - } if (tb[TCA_U32_SEL]) { if (RTA_PAYLOAD(tb[TCA_U32_SEL]) < sizeof(*sel)) @@ -1325,14 +1328,15 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, fprintf(f, "\n"); tc_print_police(f, tb[TCA_U32_POLICE]); } + if (tb[TCA_U32_INDEV]) { struct rtattr *idev = tb[TCA_U32_INDEV]; fprintf(f, "\n input dev %s\n", rta_getattr_str(idev)); } - if (tb[TCA_U32_ACT]) { + + if (tb[TCA_U32_ACT]) tc_print_action(f, tb[TCA_U32_ACT]); - } return 0; } From 24604eb2877a3be3f3167ca329b37cba178537f2 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 9 Jun 2016 19:20:36 +0200 Subject: [PATCH 261/513] ipaddress: Allow listing addresses by type Not sure why this was limited to ip-link before. It is semantically equal to the 'master' keyword, which is not restricted at all. The man page and help text adjustments include the 'master' keyword as well since that is also supported but wasn't documented before. Cc: Vadim Kochan Signed-off-by: Phil Sutter --- ip/ipaddress.c | 11 ++++++-- man/man8/ip-address.8.in | 57 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index df363b070..8766530f7 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -75,8 +75,11 @@ static void usage(void) fprintf(stderr, "Usage: ip address {add|change|replace} IFADDR dev IFNAME [ LIFETIME ]\n"); fprintf(stderr, " [ CONFFLAG-LIST ]\n"); fprintf(stderr, " ip address del IFADDR dev IFNAME [mngtmpaddr]\n"); - fprintf(stderr, " ip address {show|save|flush} [ dev IFNAME ] [ scope SCOPE-ID ]\n"); + fprintf(stderr, " ip address {save|flush} [ dev IFNAME ] [ scope SCOPE-ID ]\n"); fprintf(stderr, " [ to PREFIX ] [ FLAG-LIST ] [ label LABEL ] [up]\n"); + fprintf(stderr, " ip address [ show [ dev IFNAME ] [ scope SCOPE-ID ] [ master DEVICE ]\n"); + fprintf(stderr, " [ type TYPE ] [ to PREFIX ] [ FLAG-LIST ]\n"); + fprintf(stderr, " [ label LABEL ] [up] ]\n"); fprintf(stderr, " ip address {showdump|restore}\n"); fprintf(stderr, "IFADDR := PREFIX | ADDR peer PREFIX\n"); fprintf(stderr, " [ broadcast ADDR ] [ anycast ADDR ]\n"); @@ -90,6 +93,10 @@ static void usage(void) fprintf(stderr, "CONFFLAG := [ home | nodad | mngtmpaddr | noprefixroute | autojoin ]\n"); fprintf(stderr, "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n"); fprintf(stderr, "LFT := forever | SECONDS\n"); + fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"); + fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n"); + fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n"); + fprintf(stderr, " bond_slave | ipvlan | geneve | bridge_slave | vrf }\n"); exit(-1); } @@ -1613,7 +1620,7 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) if (!ifindex) invarg("Device does not exist\n", *argv); filter.master = ifindex; - } else if (do_link && strcmp(*argv, "type") == 0) { + } else if (strcmp(*argv, "type") == 0) { NEXT_ARG(); filter.kind = *argv; } else { diff --git a/man/man8/ip-address.8.in b/man/man8/ip-address.8.in index ff3fe0b96..ab0942d7e 100644 --- a/man/man8/ip-address.8.in +++ b/man/man8/ip-address.8.in @@ -23,7 +23,7 @@ ip-address \- protocol address management .IB IFADDR " dev " IFNAME " [ " mngtmpaddr " ]" .ti -8 -.BR "ip address" " { " show " | " save " | " flush " } [ " dev +.BR "ip address" " { " save " | " flush " } [ " dev .IR IFNAME " ] [ " .B scope .IR SCOPE-ID " ] [ " @@ -32,6 +32,21 @@ ip-address \- protocol address management .B label .IR PATTERN " ] [ " up " ]" +.ti -8 +.BR "ip address" " [ " show " [ " dev +.IR IFNAME " ] [ " +.B scope +.IR SCOPE-ID " ] [ " +.B to +.IR PREFIX " ] [ " FLAG-LIST " ] [ " +.B label +.IR PATTERN " ] [ " +.B master +.IR DEVICE " ] [ " +.B type +.IR TYPE " ] [ " +.BR up " ] ]" + .ti -8 .BR "ip address" " { " showdump " | " restore " }" @@ -80,6 +95,34 @@ ip-address \- protocol address management .BR forever " |" .IR SECONDS " ]" +.ti -8 +.IR TYPE " := [ " +.BR bridge " | " +.BR bond " | " +.BR can " | " +.BR dummy " | " +.BR hsr " | " +.BR ifb " | " +.BR ipoib " |" +.BR macvlan " | " +.BR macvtap " | " +.BR vcan " | " +.BR veth " | " +.BR vlan " | " +.BR vxlan " |" +.BR ip6tnl " |" +.BR ipip " |" +.BR sit " |" +.BR gre " |" +.BR gretap " |" +.BR ip6gre " |" +.BR ip6gretap " |" +.BR vti " |" +.BR nlmon " |" +.BR ipvlan " |" +.BR lowpan " |" +.BR geneve " ]" + .SH "DESCRIPTION" The .B address @@ -229,6 +272,14 @@ only list addresses with labels matching the .I PATTERN is a usual shell style pattern. +.TP +.BI master " DEVICE" +only list interfaces enslaved to this master device. + +.TP +.BI type " TYPE" +only list interfaces of the given type. + .TP .B up only list running interfaces. @@ -280,8 +331,8 @@ This command flushes the protocol addresses selected by some criteria. .PP This command has the same arguments as -.B show. -The difference is that it does not run when no arguments are given. +.BR show " except that " type " and " master " selectors are not supported." +Another difference is that it does not run when no arguments are given. .PP .B Warning: From 9ba4126dc4d6abb8dc5c8c8d52177849e764a14e Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Tue, 14 Jun 2016 22:55:17 +0200 Subject: [PATCH 262/513] utils: fix hex digits parsing in hexstring_a2n() strtoul() only modifies errno on overflow, so if errno is not zero before calling the function its value is preserved and makes the function fail for valid inputs; initialize it. Signed-off-by: Beniamino Galvani --- lib/utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/utils.c b/lib/utils.c index 70e85b75b..7dceeb580 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -924,6 +924,7 @@ __u8 *hexstring_a2n(const char *str, __u8 *buf, int blen, unsigned int *len) strncpy(tmpstr, str, 2); tmpstr[2] = '\0'; + errno = 0; tmp = strtoul(tmpstr, &endptr, 16); if (errno != 0 || tmp > 0xFF || *endptr != '\0') return NULL; From 8e45e44b7923a30c97ea50e43f72db6688c6175e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 10 Jun 2016 16:39:50 +0200 Subject: [PATCH 263/513] man: ip-link: Document query_rss option Doc text shamelessly stolen from the introducing commit's message (6c55c8c4617c5 ['ip link set vf: Added "query_rss" command']). Signed-off-by: Phil Sutter --- man/man8/ip-link.8.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 8fcce5e53..d5673639d 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -141,6 +141,8 @@ ip-link \- network device configuration .br .RB "[ " spoofchk " { " on " | " off " } ]" .br +.RB "[ " query_rss " { " on " | " off " } ]" +.br .RB "[ " state " { " auto " | " enable " | " disable " } ]" .br .RB "[ " trust " { " on " | " off " } ] ]" @@ -1159,6 +1161,9 @@ parameter must be specified. .BI spoofchk " on|off" - turn packet spoof checking on or off for the specified VF. .sp +.BI query_rss " on|off" +- toggle the ability of querying the RSS configuration of a specific VF. VF RSS information like RSS hash key may be considered sensitive on some devices where this information is shared between VF and PF and thus its querying may be prohibited by default. +.sp .BI state " auto|enable|disable" - set the virtual link state as seen by the specified VF. Setting to auto means a reflection of the PF link state, enable lets the VF to communicate with other VFs on From d8694a30a4027a3b5d9a2a14ca846b77abd02ea1 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sun, 12 Jun 2016 17:40:34 -0400 Subject: [PATCH 264/513] action pedit: stylistic changes More modern layout. Signed-off-by: Jamal Hadi Salim --- tc/m_pedit.c | 118 +++++++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 56 deletions(-) diff --git a/tc/m_pedit.c b/tc/m_pedit.c index a539b68bd..d276ba04f 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -32,8 +32,7 @@ static struct m_pedit_util *pedit_list; static int pedit_debug; -static void -explain(void) +static void explain(void) { fprintf(stderr, "Usage: ... pedit munge [CONTROL]\n"); fprintf(stderr, @@ -48,22 +47,24 @@ explain(void) } -static void -usage(void) +static void usage(void) { explain(); exit(-1); } -static int -pedit_parse_nopopt (int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) +static int pedit_parse_nopopt(int *argc_p, char ***argv_p, + struct tc_pedit_sel *sel, + struct tc_pedit_key *tkey) { int argc = *argc_p; char **argv = *argv_p; if (argc) { - fprintf(stderr, "Unknown action hence option \"%s\" is unparsable\n", *argv); - return -1; + fprintf(stderr, + "Unknown action hence option \"%s\" is unparsable\n", + *argv); + return -1; } return 0; @@ -75,7 +76,7 @@ static struct m_pedit_util *get_pedit_kind(const char *str) static void *pBODY; void *dlh; char buf[256]; - struct m_pedit_util *p; + struct m_pedit_util *p; for (p = pedit_list; p; p = p->next) { if (strcmp(p->id, str) == 0) @@ -107,15 +108,14 @@ static struct m_pedit_util *get_pedit_kind(const char *str) p = malloc(sizeof(*p)); if (p) { memset(p, 0, sizeof(*p)); - strncpy(p->id, str, sizeof(p->id)-1); + strncpy(p->id, str, sizeof(p->id) - 1); p->parse_peopt = pedit_parse_nopopt; goto reg; } return p; } -int -pack_key(struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) +int pack_key(struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int hwm = sel->nkeys; @@ -137,9 +137,8 @@ pack_key(struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) return 0; } - -int -pack_key32(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) +int pack_key32(__u32 retain, struct tc_pedit_sel *sel, + struct tc_pedit_key *tkey) { if (tkey->off > (tkey->off & ~3)) { fprintf(stderr, @@ -152,11 +151,11 @@ pack_key32(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) return pack_key(sel, tkey); } -int -pack_key16(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) +int pack_key16(__u32 retain, struct tc_pedit_sel *sel, + struct tc_pedit_key *tkey) { int ind, stride; - __u32 m[4] = {0x0000FFFF, 0xFF0000FF, 0xFFFF0000}; + __u32 m[4] = { 0x0000FFFF, 0xFF0000FF, 0xFFFF0000 }; if (tkey->val > 0xFFFF || tkey->mask > 0xFFFF) { fprintf(stderr, "pack_key16 bad value\n"); @@ -177,19 +176,20 @@ pack_key16(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) tkey->off &= ~3; if (pedit_debug) - printf("pack_key16: Final val %08x mask %08x\n", tkey->val, tkey->mask); + printf("pack_key16: Final val %08x mask %08x\n", + tkey->val, tkey->mask); return pack_key(sel, tkey); } -int -pack_key8(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) +int pack_key8(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { int ind, stride; - __u32 m[4] = {0x00FFFFFF, 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00}; + __u32 m[4] = { 0x00FFFFFF, 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00 }; if (tkey->val > 0xFF || tkey->mask > 0xFF) { - fprintf(stderr, "pack_key8 bad value (val %x mask %x\n", tkey->val, tkey->mask); + fprintf(stderr, "pack_key8 bad value (val %x mask %x\n", + tkey->val, tkey->mask); return -1; } @@ -202,12 +202,12 @@ pack_key8(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) tkey->off &= ~3; if (pedit_debug) - printf("pack_key8: Final word off %d val %08x mask %08x\n", tkey->off, tkey->val, tkey->mask); + printf("pack_key8: Final word off %d val %08x mask %08x\n", + tkey->off, tkey->val, tkey->mask); return pack_key(sel, tkey); } -int -parse_val(int *argc_p, char ***argv_p, __u32 *val, int type) +int parse_val(int *argc_p, char ***argv_p, __u32 * val, int type) { int argc = *argc_p; char **argv = *argv_p; @@ -216,7 +216,7 @@ parse_val(int *argc_p, char ***argv_p, __u32 *val, int type) return -1; if (type == TINT) - return get_integer((int *) val, *argv, 0); + return get_integer((int *)val, *argv, 0); if (type == TU32) return get_u32(val, *argv, 0); @@ -238,8 +238,8 @@ parse_val(int *argc_p, char ***argv_p, __u32 *val, int type) return -1; } -int -parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) +int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain, + struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) { __u32 mask = 0, val = 0; __u32 o = 0xFF; @@ -251,7 +251,8 @@ parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain, struct return -1; if (pedit_debug) - printf("parse_cmd argc %d %s offset %d length %d\n", argc, *argv, tkey->off, len); + printf("parse_cmd argc %d %s offset %d length %d\n", + argc, *argv, tkey->off, len); if (len == 2) o = 0xFFFF; @@ -271,13 +272,15 @@ parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain, struct return -1; } - argc--; argv++; + argc--; + argv++; if (argc && matches(*argv, "retain") == 0) { NEXT_ARG(); if (parse_val(&argc, &argv, &retain, TU32)) return -1; - argc--; argv++; + argc--; + argv++; } tkey->val = val; @@ -302,15 +305,16 @@ parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain, struct return -1; done: if (pedit_debug) - printf("parse_cmd done argc %d %s offset %d length %d\n", argc, *argv, tkey->off, len); + printf("parse_cmd done argc %d %s offset %d length %d\n", + argc, *argv, tkey->off, len); *argc_p = argc; *argv_p = argv; return res; } -int -parse_offset(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) +int parse_offset(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, + struct tc_pedit_key *tkey) { int off; __u32 len, retain; @@ -331,7 +335,6 @@ parse_offset(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pe if (argc <= 0) return -1; - if (matches(*argv, "u32") == 0) { len = 4; retain = 0xFFFFFFFF; @@ -386,8 +389,7 @@ parse_offset(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pe return res; } -static int -parse_munge(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel) +static int parse_munge(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel) { struct tc_pedit_key tkey; int argc = *argc_p; @@ -433,8 +435,8 @@ parse_munge(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel) return res; } -int -parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) +int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, + struct nlmsghdr *n) { struct { struct tc_pedit_sel sel; @@ -459,13 +461,15 @@ parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, stru usage(); } else if (matches(*argv, "munge") == 0) { if (!ok) { - fprintf(stderr, "Illegal pedit construct (%s)\n", *argv); + fprintf(stderr, "Bad pedit construct (%s)\n", + *argv); explain(); return -1; } NEXT_ARG(); if (parse_munge(&argc, &argv, &sel.sel)) { - fprintf(stderr, "Illegal pedit construct (%s)\n", *argv); + fprintf(stderr, "Bad pedit construct (%s)\n", + *argv); explain(); return -1; } @@ -489,7 +493,7 @@ parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, stru sel.sel.action = TC_ACT_PIPE; NEXT_ARG(); } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { + matches(*argv, "shot") == 0) { sel.sel.action = TC_ACT_SHOT; NEXT_ARG(); } else if (matches(*argv, "continue") == 0) { @@ -517,16 +521,17 @@ parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, stru tail = NLMSG_TAIL(n); addattr_l(n, MAX_MSG, tca_id, NULL, 0); - addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_pedit_key)); - tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; + addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel, + sizeof(sel.sel) + + sel.sel.nkeys * sizeof(struct tc_pedit_key)); + tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail; *argc_p = argc; *argv_p = argv; return 0; } -int -print_pedit(struct action_util *au, FILE * f, struct rtattr *arg) +int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg) { struct tc_pedit_sel *sel; struct rtattr *tb[TCA_PEDIT_MAX + 1]; @@ -544,8 +549,10 @@ print_pedit(struct action_util *au, FILE * f, struct rtattr *arg) } sel = RTA_DATA(tb[TCA_PEDIT_PARMS]); - fprintf(f, " pedit action %s keys %d\n ", action_n2a(sel->action, b1, sizeof (b1)), sel->nkeys); - fprintf(f, "\t index %d ref %d bind %d", sel->index, sel->refcnt, sel->bindcnt); + fprintf(f, " pedit action %s keys %d\n ", + action_n2a(sel->action, b1, sizeof(b1)), sel->nkeys); + fprintf(f, "\t index %d ref %d bind %d", sel->index, sel->refcnt, + sel->bindcnt); if (show_stats) { if (tb[TCA_PEDIT_TM]) { @@ -561,21 +568,20 @@ print_pedit(struct action_util *au, FILE * f, struct rtattr *arg) for (i = 0; i < sel->nkeys; i++, key++) { fprintf(f, "\n\t key #%d", i); fprintf(f, " at %d: val %08x mask %08x", - (unsigned int)key->off, - (unsigned int)ntohl(key->val), - (unsigned int)ntohl(key->mask)); + (unsigned int)key->off, + (unsigned int)ntohl(key->val), + (unsigned int)ntohl(key->mask)); } } else { - fprintf(f, "\npedit %x keys %d is not LEGIT", sel->index, sel->nkeys); + fprintf(f, "\npedit %x keys %d is not LEGIT", sel->index, + sel->nkeys); } - fprintf(f, "\n "); return 0; } -int -pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats) +int pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats) { return 0; } From 8b625177ba69985be6673e776c54f45ab8d40e58 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 14 Jun 2016 14:31:37 -0700 Subject: [PATCH 265/513] pedit: fix whitespace etc Minor changes from checkpatch --- tc/m_pedit.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/tc/m_pedit.c b/tc/m_pedit.c index d276ba04f..64533060c 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -37,10 +37,12 @@ static void explain(void) fprintf(stderr, "Usage: ... pedit munge [CONTROL]\n"); fprintf(stderr, "Where: MUNGE := |\n" - "\t:= [ATC]\n \t\tOFFSETC:= offset \n " - "\t\tATC:= at offmask shift \n \t\tNOTE: offval is byte offset, must be multiple of 4\n " - "\t\tNOTE: maskval is a 32 bit hex number\n \t\tNOTE: shiftval is a is a shift value\n " - "\t\tCMD:= clear | invert | set | retain\n \t:= ip | ip6 \n " + "\t:= [ATC]\n \t\tOFFSETC:= offset \n" + "\t\tATC:= at offmask shift \n" + "\t\tNOTE: offval is byte offset, must be multiple of 4\n" + "\t\tNOTE: maskval is a 32 bit hex number\n \t\tNOTE: shiftval is a is a shift value\n" + "\t\tCMD:= clear | invert | set | retain\n" + "\t:= ip | ip6 \n" " \t\t| udp | tcp | icmp \n" "\tCONTROL:= reclassify | pipe | drop | continue | pass\n" "For Example usage look at the examples directory\n"); @@ -207,7 +209,7 @@ int pack_key8(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) return pack_key(sel, tkey); } -int parse_val(int *argc_p, char ***argv_p, __u32 * val, int type) +int parse_val(int *argc_p, char ***argv_p, __u32 *val, int type) { int argc = *argc_p; char **argv = *argv_p; @@ -224,16 +226,15 @@ int parse_val(int *argc_p, char ***argv_p, __u32 * val, int type) if (type == TIPV4) { inet_prefix addr; - if (get_prefix_1(&addr, *argv, AF_INET)) { + if (get_prefix_1(&addr, *argv, AF_INET)) return -1; - } + *val = addr.data[0]; return 0; } - if (type == TIPV6) { - /* not implemented yet */ - return -1; - } + + if (type == TIPV6) + return -1; /* not implemented yet */ return -1; } From 445745221a21ecb4111c19cfa7f4c2cf4796337f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 10 Jun 2016 13:42:00 +0200 Subject: [PATCH 266/513] tc: m_xt: Prevent segfault with standard targets Iptables standard targets like DROP or REJECT don't implement the print callback in libxtables. Hence the following command would segfault: | tc filter add dev d0 parent ffff: u32 match u32 0 0 action xt -j DROP With this patch standard targets still can't be used (and are not really useful anyway), but at least it doesn't crash anymore. Signed-off-by: Phil Sutter --- tc/m_xt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tc/m_xt.c b/tc/m_xt.c index c3f866df1..62ec6d7f1 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -250,8 +250,12 @@ static int parse_ipt(struct action_util *a, int *argc_p, fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]); fprintf(stdout, "\ttarget: "); - if (m) - m->print(NULL, m->t, 0); + if (m) { + if (m->print) + m->print(NULL, m->t, 0); + else + printf("%s ", m->name); + } fprintf(stdout, " index %d\n", index); if (strlen(tname) > 16) { From 8eee75a8358c542d881d2a84e2c47cc0a9fa92ef Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 10 Jun 2016 13:42:01 +0200 Subject: [PATCH 267/513] tc: m_xt: Fix segfault when adding multiple actions at once Without this, the following call to tc would segfault: | tc filter add dev d0 parent ffff: u32 match u32 0 0 \ | action xt -j MARK --set-mark 0x1 \ | action xt -j MARK --set-mark 0x1 The reason is basically the same as for 6e2e5ec28bad4 ("fix print_ipt: segfault if more then one filter with action -j MARK.") but in parse_ipt() instead of print_ipt(). Signed-off-by: Phil Sutter --- tc/m_xt.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tc/m_xt.c b/tc/m_xt.c index 62ec6d7f1..45d86d662 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -133,7 +133,9 @@ static int parse_ipt(struct action_util *a, int *argc_p, __u32 hook = 0, index = 0; struct option *opts = NULL; - xtables_init_all(&tcipt_globals, NFPROTO_IPV4); + /* copy tcipt_globals because .opts will be modified by iptables */ + struct xtables_globals tmp_tcipt_globals = tcipt_globals; + xtables_init_all(&tmp_tcipt_globals, NFPROTO_IPV4); set_lib_dir(); { @@ -153,7 +155,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, } while (1) { - c = getopt_long(argc, argv, "j:", tcipt_globals.opts, NULL); + c = getopt_long(argc, argv, "j:", tmp_tcipt_globals.opts, NULL); if (c == -1) break; switch (c) { @@ -166,12 +168,12 @@ static int parse_ipt(struct action_util *a, int *argc_p, return -1; } #if (XTABLES_VERSION_CODE >= 6) - opts = xtables_options_xfrm(tcipt_globals.orig_opts, - tcipt_globals.opts, + opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts, + tmp_tcipt_globals.opts, m->x6_options, &m->option_offset); #else - opts = xtables_merge_options(tcipt_globals.opts, + opts = xtables_merge_options(tmp_tcipt_globals.opts, m->extra_opts, &m->option_offset); #endif @@ -179,7 +181,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, fprintf(stderr, " failed to find additional options for target %s\n\n", optarg); return -1; } else - tcipt_globals.opts = opts; + tmp_tcipt_globals.opts = opts; } else { fprintf(stderr, " failed to find target %s\n\n", optarg); return -1; From f1a7c7d8301e9dcead8f8c0d28e7f1587c0cd3cc Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 10 Jun 2016 13:42:02 +0200 Subject: [PATCH 268/513] tc: m_xt: Fix indenting By exiting early if xtables_find_target() fails, one indenting level can be dropped. Some of the wrongly indented code then happens to sit at the right spot by accident which is why this patch is smaller than expected. Signed-off-by: Phil Sutter --- tc/m_xt.c | 54 ++++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/tc/m_xt.c b/tc/m_xt.c index 45d86d662..5a629c442 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -161,12 +161,15 @@ static int parse_ipt(struct action_util *a, int *argc_p, switch (c) { case 'j': m = xtables_find_target(optarg, XTF_TRY_LOAD); - if (m != NULL) { + if (!m) { + fprintf(stderr, " failed to find target %s\n\n", optarg); + return -1; + } - if (build_st(m, NULL) < 0) { - printf(" %s error\n", m->name); - return -1; - } + if (build_st(m, NULL) < 0) { + printf(" %s error\n", m->name); + return -1; + } #if (XTABLES_VERSION_CODE >= 6) opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts, tmp_tcipt_globals.opts, @@ -182,22 +185,18 @@ static int parse_ipt(struct action_util *a, int *argc_p, return -1; } else tmp_tcipt_globals.opts = opts; - } else { - fprintf(stderr, " failed to find target %s\n\n", optarg); - return -1; - } ok++; break; default: memset(&fw, 0, sizeof(fw)); #if (XTABLES_VERSION_CODE >= 6) - if (m != NULL && m->x6_parse != NULL) { - xtables_option_tpcall(c, argv, 0, m, NULL); + if (m != NULL && m->x6_parse != NULL) { + xtables_option_tpcall(c, argv, 0, m, NULL); #else - if (m != NULL && m->parse != NULL) { - m->parse(c - m->option_offset, argv, 0, &m->tflags, - NULL, &m->t); + if (m != NULL && m->parse != NULL) { + m->parse(c - m->option_offset, argv, 0, + &m->tflags, NULL, &m->t); #endif } else { fprintf(stderr, "failed to find target %s\n\n", optarg); @@ -339,11 +338,15 @@ print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) t = RTA_DATA(tb[TCA_IPT_TARG]); m = xtables_find_target(t->u.user.name, XTF_TRY_LOAD); - if (m != NULL) { - if (build_st(m, t) < 0) { - fprintf(stderr, " %s error\n", m->name); - return -1; - } + if (!m) { + fprintf(stderr, " failed to find target %s\n\n", + t->u.user.name); + return -1; + } + if (build_st(m, t) < 0) { + fprintf(stderr, " %s error\n", m->name); + return -1; + } #if (XTABLES_VERSION_CODE >= 6) opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts, @@ -355,16 +358,11 @@ print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) m->extra_opts, &m->option_offset); #endif - if (opts == NULL) { - fprintf(stderr, " failed to find additional options for target %s\n\n", optarg); - return -1; - } else - tmp_tcipt_globals.opts = opts; - } else { - fprintf(stderr, " failed to find target %s\n\n", - t->u.user.name); + if (opts == NULL) { + fprintf(stderr, " failed to find additional options for target %s\n\n", optarg); return -1; - } + } else + tmp_tcipt_globals.opts = opts; fprintf(f, "\ttarget "); m->print(NULL, m->t, 0); if (tb[TCA_IPT_INDEX] == NULL) { From b45f9141c2602de790a9fc3f0f423ed72419da24 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 10 Jun 2016 13:42:03 +0200 Subject: [PATCH 269/513] tc: m_xt: Get rid of one indentation level in parse_ipt() Signed-off-by: Phil Sutter --- tc/m_xt.c | 91 +++++++++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/tc/m_xt.c b/tc/m_xt.c index 5a629c442..b3731086c 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -298,6 +298,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, static int print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) { + struct xtables_target *m; struct rtattr *tb[TCA_IPT_MAX + 1]; struct xt_entry_target *t = NULL; struct option *opts = NULL; @@ -333,62 +334,60 @@ print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) if (tb[TCA_IPT_TARG] == NULL) { fprintf(f, "\t[NULL ipt target parameters ]\n"); return -1; - } else { - struct xtables_target *m = NULL; - - t = RTA_DATA(tb[TCA_IPT_TARG]); - m = xtables_find_target(t->u.user.name, XTF_TRY_LOAD); - if (!m) { - fprintf(stderr, " failed to find target %s\n\n", - t->u.user.name); - return -1; - } - if (build_st(m, t) < 0) { - fprintf(stderr, " %s error\n", m->name); - return -1; - } + } + + t = RTA_DATA(tb[TCA_IPT_TARG]); + m = xtables_find_target(t->u.user.name, XTF_TRY_LOAD); + if (!m) { + fprintf(stderr, " failed to find target %s\n\n", + t->u.user.name); + return -1; + } + if (build_st(m, t) < 0) { + fprintf(stderr, " %s error\n", m->name); + return -1; + } #if (XTABLES_VERSION_CODE >= 6) - opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts, - tmp_tcipt_globals.opts, - m->x6_options, - &m->option_offset); + opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts, + tmp_tcipt_globals.opts, + m->x6_options, + &m->option_offset); #else - opts = xtables_merge_options(tmp_tcipt_globals.opts, - m->extra_opts, - &m->option_offset); + opts = xtables_merge_options(tmp_tcipt_globals.opts, + m->extra_opts, + &m->option_offset); #endif - if (opts == NULL) { - fprintf(stderr, " failed to find additional options for target %s\n\n", optarg); - return -1; - } else - tmp_tcipt_globals.opts = opts; - fprintf(f, "\ttarget "); - m->print(NULL, m->t, 0); - if (tb[TCA_IPT_INDEX] == NULL) { - fprintf(f, " [NULL ipt target index ]\n"); - } else { - __u32 index; + if (opts == NULL) { + fprintf(stderr, " failed to find additional options for target %s\n\n", optarg); + return -1; + } else + tmp_tcipt_globals.opts = opts; + fprintf(f, "\ttarget "); + m->print(NULL, m->t, 0); + if (tb[TCA_IPT_INDEX] == NULL) { + fprintf(f, " [NULL ipt target index ]\n"); + } else { + __u32 index; - index = rta_getattr_u32(tb[TCA_IPT_INDEX]); - fprintf(f, "\n\tindex %d", index); - } + index = rta_getattr_u32(tb[TCA_IPT_INDEX]); + fprintf(f, "\n\tindex %d", index); + } - if (tb[TCA_IPT_CNT]) { - struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]); + if (tb[TCA_IPT_CNT]) { + struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]); - fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt); - } - if (show_stats) { - if (tb[TCA_IPT_TM]) { - struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]); + fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt); + } + if (show_stats) { + if (tb[TCA_IPT_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]); - print_tm(f, tm); - } + print_tm(f, tm); } - fprintf(f, "\n"); - } + fprintf(f, "\n"); + xtables_free_opts(1); return 0; From b0ba0185763ad2bae3335423221919ed47951885 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 10 Jun 2016 13:42:04 +0200 Subject: [PATCH 270/513] tc: m_xt: Drop unused variable fw in parse_ipt() Signed-off-by: Phil Sutter --- tc/m_xt.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tc/m_xt.c b/tc/m_xt.c index b3731086c..c42f3bda4 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -120,7 +120,6 @@ static int parse_ipt(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { struct xtables_target *m = NULL; - struct ipt_entry fw; struct rtattr *tail; int c; @@ -189,7 +188,6 @@ static int parse_ipt(struct action_util *a, int *argc_p, break; default: - memset(&fw, 0, sizeof(fw)); #if (XTABLES_VERSION_CODE >= 6) if (m != NULL && m->x6_parse != NULL) { xtables_option_tpcall(c, argv, 0, m, NULL); From ab8f52fc4ae1141ff9980d24244f2d9559e47968 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 10 Jun 2016 13:42:05 +0200 Subject: [PATCH 271/513] tc: m_xt: Get rid of rargc in parse_ipt() No need to copy the passed parameter, it's changed only once right before function return. Signed-off-by: Phil Sutter --- tc/m_xt.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tc/m_xt.c b/tc/m_xt.c index c42f3bda4..61fc437df 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -123,7 +123,6 @@ static int parse_ipt(struct action_util *a, int *argc_p, struct rtattr *tail; int c; - int rargc = *argc_p; char **argv = *argv_p; int argc = 0, iargc = 0; char k[16]; @@ -140,7 +139,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, { int i; - for (i = 0; i < rargc; i++) { + for (i = 0; i < *argc_p; i++) { if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) { break; } @@ -149,7 +148,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, } if (argc <= 2) { - fprintf(stderr, "bad arguments to ipt %d vs %d\n", argc, rargc); + fprintf(stderr, "bad arguments to ipt %d vs %d\n", argc, *argc_p); return -1; } @@ -274,7 +273,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, argc -= optind; argv += optind; - *argc_p = rargc - iargc; + *argc_p -= iargc; *argv_p = argv; optind = 0; From 28432f370e6ad72a7eab9ba6bae67eabdd4b1c57 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 10 Jun 2016 13:42:06 +0200 Subject: [PATCH 272/513] tc: m_xt: Get rid of iargc variable in parse_ipt() After dropping the unused decrement of argc in the function's tail, it can fully take over what iargc has been used for. Signed-off-by: Phil Sutter --- tc/m_xt.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tc/m_xt.c b/tc/m_xt.c index 61fc437df..55ebadf2c 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -124,7 +124,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, int c; char **argv = *argv_p; - int argc = 0, iargc = 0; + int argc = 0; char k[16]; int size = 0; int iok = 0, ok = 0; @@ -144,7 +144,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, break; } } - iargc = argc = i; + argc = i; } if (argc <= 2) { @@ -205,7 +205,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, } } - if (iargc > optind) { + if (argc > optind) { if (matches(argv[optind], "index") == 0) { if (get_u32(&index, argv[optind + 1], 10)) { fprintf(stderr, "Illegal \"index\"\n"); @@ -271,9 +271,8 @@ static int parse_ipt(struct action_util *a, int *argc_p, addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size); tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; - argc -= optind; argv += optind; - *argc_p -= iargc; + *argc_p -= argc; *argv_p = argv; optind = 0; From f6ddd9c5da4e552322baf237075aae6db17237d4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 10 Jun 2016 13:42:07 +0200 Subject: [PATCH 273/513] tc: m_xt: Simplify argc adjusting in parse_ipt() And while at it, also improve the error message in case too few parameters have been given. Signed-off-by: Phil Sutter --- tc/m_xt.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/tc/m_xt.c b/tc/m_xt.c index 55ebadf2c..f449c9d1a 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -124,7 +124,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, int c; char **argv = *argv_p; - int argc = 0; + int argc; char k[16]; int size = 0; int iok = 0, ok = 0; @@ -136,19 +136,14 @@ static int parse_ipt(struct action_util *a, int *argc_p, xtables_init_all(&tmp_tcipt_globals, NFPROTO_IPV4); set_lib_dir(); - { - int i; - - for (i = 0; i < *argc_p; i++) { - if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) { - break; - } - } - argc = i; + /* parse only up until the next action */ + for (argc = 0; argc < *argc_p; argc++) { + if (!argv[argc] || !strcmp(argv[argc], "action")) + break; } if (argc <= 2) { - fprintf(stderr, "bad arguments to ipt %d vs %d\n", argc, *argc_p); + fprintf(stderr, "too few arguments for xt, need at least '-j '\n"); return -1; } From 2ef4008585ec9184a0abf7534bf7f575ce6579d1 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 10 Jun 2016 13:42:08 +0200 Subject: [PATCH 274/513] tc: m_xt: Introduce get_xtables_target_opts() This pulls common code from parse_ipt() and print_ipt() functions together. While here, also fix for incorrect use of the global 'optarg' variable in print_ipt(). Signed-off-by: Phil Sutter --- tc/m_xt.c | 58 +++++++++++++++++++++++++++---------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/tc/m_xt.c b/tc/m_xt.c index f449c9d1a..1224e4fe4 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -116,6 +116,27 @@ static void set_lib_dir(void) } +static int get_xtables_target_opts(struct xtables_globals *globals, + struct xtables_target *m) +{ + struct option *opts; + +#if (XTABLES_VERSION_CODE >= 6) + opts = xtables_options_xfrm(globals->orig_opts, + globals->opts, + m->x6_options, + &m->option_offset); +#else + opts = xtables_merge_options(globals->opts, + m->extra_opts, + &m->option_offset); +#endif + if (!opts) + return -1; + globals->opts = opts; + return 0; +} + static int parse_ipt(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { @@ -129,7 +150,6 @@ static int parse_ipt(struct action_util *a, int *argc_p, int size = 0; int iok = 0, ok = 0; __u32 hook = 0, index = 0; - struct option *opts = NULL; /* copy tcipt_globals because .opts will be modified by iptables */ struct xtables_globals tmp_tcipt_globals = tcipt_globals; @@ -163,21 +183,11 @@ static int parse_ipt(struct action_util *a, int *argc_p, printf(" %s error\n", m->name); return -1; } -#if (XTABLES_VERSION_CODE >= 6) - opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts, - tmp_tcipt_globals.opts, - m->x6_options, - &m->option_offset); -#else - opts = xtables_merge_options(tmp_tcipt_globals.opts, - m->extra_opts, - &m->option_offset); -#endif - if (opts == NULL) { + + if (get_xtables_target_opts(&tmp_tcipt_globals, m) < 0) { fprintf(stderr, " failed to find additional options for target %s\n\n", optarg); return -1; - } else - tmp_tcipt_globals.opts = opts; + } ok++; break; @@ -292,7 +302,6 @@ print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) struct xtables_target *m; struct rtattr *tb[TCA_IPT_MAX + 1]; struct xt_entry_target *t = NULL; - struct option *opts = NULL; if (arg == NULL) return -1; @@ -339,21 +348,12 @@ print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) return -1; } -#if (XTABLES_VERSION_CODE >= 6) - opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts, - tmp_tcipt_globals.opts, - m->x6_options, - &m->option_offset); -#else - opts = xtables_merge_options(tmp_tcipt_globals.opts, - m->extra_opts, - &m->option_offset); -#endif - if (opts == NULL) { - fprintf(stderr, " failed to find additional options for target %s\n\n", optarg); + if (get_xtables_target_opts(&tmp_tcipt_globals, m) < 0) { + fprintf(stderr, + " failed to find additional options for target %s\n\n", + t->u.user.name); return -1; - } else - tmp_tcipt_globals.opts = opts; + } fprintf(f, "\ttarget "); m->print(NULL, m->t, 0); if (tb[TCA_IPT_INDEX] == NULL) { From 4b83a08c280fcd14ed8e775adc7604ea13c1252f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 14 Jun 2016 14:40:53 -0700 Subject: [PATCH 275/513] m_xt: whitespace cleanup Make it 99% checkpatch clean. --- tc/m_xt.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/tc/m_xt.c b/tc/m_xt.c index 1224e4fe4..028bad649 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -39,8 +39,10 @@ #endif #ifndef __ALIGN_KERNEL -#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) -#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define __ALIGN_KERNEL(x, a) \ + __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) +#define __ALIGN_KERNEL_MASK(x, mask) \ + (((x) + (mask)) & ~(mask)) #endif #ifndef ALIGN @@ -51,7 +53,7 @@ static const char *tname = "mangle"; char *lib_dir; -static const char *ipthooks[] = { +static const char * const ipthooks[] = { "NF_IP_PRE_ROUTING", "NF_IP_LOCAL_IN", "NF_IP_FORWARD", @@ -153,6 +155,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, /* copy tcipt_globals because .opts will be modified by iptables */ struct xtables_globals tmp_tcipt_globals = tcipt_globals; + xtables_init_all(&tmp_tcipt_globals, NFPROTO_IPV4); set_lib_dir(); @@ -163,7 +166,8 @@ static int parse_ipt(struct action_util *a, int *argc_p, } if (argc <= 2) { - fprintf(stderr, "too few arguments for xt, need at least '-j '\n"); + fprintf(stderr, + "too few arguments for xt, need at least '-j '\n"); return -1; } @@ -175,7 +179,9 @@ static int parse_ipt(struct action_util *a, int *argc_p, case 'j': m = xtables_find_target(optarg, XTF_TRY_LOAD); if (!m) { - fprintf(stderr, " failed to find target %s\n\n", optarg); + fprintf(stderr, + " failed to find target %s\n\n", + optarg); return -1; } @@ -184,8 +190,11 @@ static int parse_ipt(struct action_util *a, int *argc_p, return -1; } - if (get_xtables_target_opts(&tmp_tcipt_globals, m) < 0) { - fprintf(stderr, " failed to find additional options for target %s\n\n", optarg); + if (get_xtables_target_opts(&tmp_tcipt_globals, + m) < 0) { + fprintf(stderr, + " failed to find additional options for target %s\n\n", + optarg); return -1; } ok++; @@ -198,10 +207,11 @@ static int parse_ipt(struct action_util *a, int *argc_p, #else if (m != NULL && m->parse != NULL) { m->parse(c - m->option_offset, argv, 0, - &m->tflags, NULL, &m->t); + &m->tflags, NULL, &m->t); #endif } else { - fprintf(stderr, "failed to find target %s\n\n", optarg); + fprintf(stderr, + "failed to find target %s\n\n", optarg); return -1; } @@ -297,7 +307,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, } static int -print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) +print_ipt(struct action_util *au, FILE *f, struct rtattr *arg) { struct xtables_target *m; struct rtattr *tb[TCA_IPT_MAX + 1]; @@ -350,7 +360,7 @@ print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) if (get_xtables_target_opts(&tmp_tcipt_globals, m) < 0) { fprintf(stderr, - " failed to find additional options for target %s\n\n", + " failed to find additional options for target %s\n\n", t->u.user.name); return -1; } From ec0911874910f2776b57adc64947124abd36eade Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 14 Jun 2016 16:33:48 -0700 Subject: [PATCH 276/513] fib_rules.h update header file Add new L3MDEV (clone from net-next) --- include/linux/fib_rules.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index 620c8a5dd..14404b3eb 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h @@ -50,6 +50,7 @@ enum { FRA_FWMASK, /* mask for netfilter mark */ FRA_OIFNAME, FRA_PAD, + FRA_L3MDEV, /* iif or oif is l3mdev goto its table */ __FRA_MAX }; From 8c92e122774d14e698a67fc9519288c367320108 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 10 Jun 2016 10:47:17 -0700 Subject: [PATCH 277/513] ip rule: Add support for l3mdev rules Kernel commit 96c63fa7393d ("net: Add l3mdev rule") added support for the FRA_L3MDEV attribute. The attribute enables use of l3mdev rules which mean 'get table id from l3 master device'. This patch adds support to iproute2 to show, add and delete rules with this attribute. Signed-off-by: David Ahern --- ip/iprule.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/ip/iprule.c b/ip/iprule.c index 7cb19e4d5..b0566d5e4 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -37,7 +37,7 @@ static void usage(void) fprintf(stderr, " ip rule { flush | save | restore }\n"); fprintf(stderr, " ip rule [ list ]\n"); fprintf(stderr, "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n"); - fprintf(stderr, " [ iif STRING ] [ oif STRING ] [ pref NUMBER ]\n"); + fprintf(stderr, " [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n"); fprintf(stderr, "ACTION := [ table TABLE_ID ]\n"); fprintf(stderr, " [ nat ADDRESS ]\n"); fprintf(stderr, " [ realms [SRCREALM/]DSTREALM ]\n"); @@ -139,6 +139,11 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "[detached] "); } + if (tb[FRA_L3MDEV]) { + if (rta_getattr_u8(tb[FRA_L3MDEV])) + fprintf(fp, "lookup [l3mdev-table] "); + } + table = rtm_get_table(r, tb); if (table) { fprintf(fp, "lookup %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); @@ -311,7 +316,9 @@ static int iprule_restore(void) static int iprule_modify(int cmd, int argc, char **argv) { + int l3mdev_rule = 0; int table_ok = 0; + __u32 tid = 0; struct { struct nlmsghdr n; struct rtmsg r; @@ -393,8 +400,6 @@ static int iprule_modify(int cmd, int argc, char **argv) addattr32(&req.n, sizeof(req), FRA_FLOW, realm); } else if (matches(*argv, "table") == 0 || strcmp(*argv, "lookup") == 0) { - __u32 tid; - NEXT_ARG(); if (rtnl_rttable_a2n(&tid, *argv)) invarg("invalid table ID\n", *argv); @@ -428,6 +433,10 @@ static int iprule_modify(int cmd, int argc, char **argv) } else if (strcmp(*argv, "oif") == 0) { NEXT_ARG(); addattr_l(&req.n, sizeof(req), FRA_OIFNAME, *argv, strlen(*argv)+1); + } else if (strcmp(*argv, "l3mdev") == 0) { + addattr8(&req.n, sizeof(req), FRA_L3MDEV, 1); + table_ok = 1; + l3mdev_rule = 1; } else if (strcmp(*argv, "nat") == 0 || matches(*argv, "map-to") == 0) { NEXT_ARG(); @@ -461,6 +470,12 @@ static int iprule_modify(int cmd, int argc, char **argv) argv++; } + if (l3mdev_rule && tid != 0) { + fprintf(stderr, + "table can not be specified for l3mdev rules\n"); + return -EINVAL; + } + if (req.r.rtm_family == AF_UNSPEC) req.r.rtm_family = AF_INET; From d831cc7c00e906f384b63d12f63dedf6e0590b6f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 14 Jun 2016 17:20:02 -0700 Subject: [PATCH 278/513] iprule: whitespace cleanup Cleanup long lines, and indentation issues. Use rta_getattru32 rather than cast to unsigned. --- ip/iprule.c | 95 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 35 deletions(-) diff --git a/ip/iprule.c b/ip/iprule.c index b0566d5e4..a412804dd 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -57,6 +57,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) int host_len = -1; __u32 table; struct rtattr *tb[FRA_MAX+1]; + SPRINT_BUF(b1); if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE) @@ -74,7 +75,8 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "Deleted "); if (tb[FRA_PRIORITY]) - fprintf(fp, "%u:\t", *(unsigned *)RTA_DATA(tb[FRA_PRIORITY])); + fprintf(fp, "%u:\t", + rta_getattr_u32(tb[FRA_PRIORITY])); else fprintf(fp, "0:\t"); @@ -84,11 +86,11 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[FRA_SRC]) { if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", - rt_addr_n2a_rta(r->rtm_family, tb[FRA_SRC]), - r->rtm_src_len); + rt_addr_n2a_rta(r->rtm_family, tb[FRA_SRC]), + r->rtm_src_len); } else { fprintf(fp, "from %s ", - format_host_rta(r->rtm_family, tb[FRA_SRC])); + format_host_rta(r->rtm_family, tb[FRA_SRC])); } } else if (r->rtm_src_len) { fprintf(fp, "from 0/%d ", r->rtm_src_len); @@ -99,11 +101,11 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[FRA_DST]) { if (r->rtm_dst_len != host_len) { fprintf(fp, "to %s/%u ", - rt_addr_n2a_rta(r->rtm_family, tb[FRA_DST]), - r->rtm_dst_len); + rt_addr_n2a_rta(r->rtm_family, tb[FRA_DST]), + r->rtm_dst_len); } else { fprintf(fp, "to %s ", - format_host_rta(r->rtm_family, tb[FRA_DST])); + format_host_rta(r->rtm_family, tb[FRA_DST])); } } else if (r->rtm_dst_len) { fprintf(fp, "to 0/%d ", r->rtm_dst_len); @@ -111,7 +113,8 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (r->rtm_tos) { SPRINT_BUF(b1); - fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); + fprintf(fp, "tos %s ", + rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); } if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) { @@ -146,21 +149,22 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) table = rtm_get_table(r, tb); if (table) { - fprintf(fp, "lookup %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); + fprintf(fp, "lookup %s ", + rtnl_rttable_n2a(table, b1, sizeof(b1))); if (tb[FRA_SUPPRESS_PREFIXLEN]) { int pl = rta_getattr_u32(tb[FRA_SUPPRESS_PREFIXLEN]); - if (pl != -1) { + if (pl != -1) fprintf(fp, "suppress_prefixlength %d ", pl); - } } if (tb[FRA_SUPPRESS_IFGROUP]) { int group = rta_getattr_u32(tb[FRA_SUPPRESS_IFGROUP]); if (group != -1) { SPRINT_BUF(b1); - fprintf(fp, "suppress_ifgroup %s ", rtnl_group_n2a(group, b1, sizeof(b1))); + fprintf(fp, "suppress_ifgroup %s ", + rtnl_group_n2a(group, b1, sizeof(b1))); } } } @@ -181,8 +185,8 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (r->rtm_type == RTN_NAT) { if (tb[RTA_GATEWAY]) { fprintf(fp, "map-to %s ", - format_host_rta(r->rtm_family, - tb[RTA_GATEWAY])); + format_host_rta(r->rtm_family, + tb[RTA_GATEWAY])); } else fprintf(fp, "masquerade"); } else if (r->rtm_type == FR_ACT_GOTO) { @@ -196,7 +200,9 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) } else if (r->rtm_type == FR_ACT_NOP) fprintf(fp, "nop"); else if (r->rtm_type != RTN_UNICAST) - fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); + fprintf(fp, "%s", + rtnl_rtntype_n2a(r->rtm_type, + b1, sizeof(b1))); fprintf(fp, "\n"); fflush(fp); @@ -223,7 +229,8 @@ static int save_rule_prep(void) return 0; } -static int save_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +static int save_rule(const struct sockaddr_nl *who, + struct nlmsghdr *n, void *arg) { int ret; @@ -281,7 +288,8 @@ static int rule_dump_check_magic(void) ret = fread(&magic, sizeof(magic), 1, stdin); if (magic != rule_dump_magic) { - fprintf(stderr, "Magic mismatch (%d elems, %x magic)\n", ret, magic); + fprintf(stderr, "Magic mismatch (%d elems, %x magic)\n", + ret, magic); return -1; } @@ -351,14 +359,16 @@ static int iprule_modify(int cmd, int argc, char **argv) NEXT_ARG(); get_prefix(&dst, *argv, req.r.rtm_family); req.r.rtm_src_len = dst.bitlen; - addattr_l(&req.n, sizeof(req), FRA_SRC, &dst.data, dst.bytelen); + addattr_l(&req.n, sizeof(req), FRA_SRC, + &dst.data, dst.bytelen); } else if (strcmp(*argv, "to") == 0) { inet_prefix dst; NEXT_ARG(); get_prefix(&dst, *argv, req.r.rtm_family); req.r.rtm_dst_len = dst.bitlen; - addattr_l(&req.n, sizeof(req), FRA_DST, &dst.data, dst.bytelen); + addattr_l(&req.n, sizeof(req), FRA_DST, + &dst.data, dst.bytelen); } else if (matches(*argv, "preference") == 0 || matches(*argv, "order") == 0 || matches(*argv, "priority") == 0) { @@ -381,15 +391,19 @@ static int iprule_modify(int cmd, int argc, char **argv) __u32 fwmark, fwmask; NEXT_ARG(); - if ((slash = strchr(*argv, '/')) != NULL) + + slash = strchr(*argv, '/'); + if (slash != NULL) *slash = '\0'; if (get_u32(&fwmark, *argv, 0)) invarg("fwmark value is invalid\n", *argv); addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark); if (slash) { if (get_u32(&fwmask, slash+1, 0)) - invarg("fwmask value is invalid\n", slash+1); - addattr32(&req.n, sizeof(req), FRA_FWMASK, fwmask); + invarg("fwmask value is invalid\n", + slash+1); + addattr32(&req.n, sizeof(req), + FRA_FWMASK, fwmask); } } else if (matches(*argv, "realms") == 0) { __u32 realm; @@ -416,23 +430,29 @@ static int iprule_modify(int cmd, int argc, char **argv) NEXT_ARG(); if (get_s32(&pl, *argv, 0) || pl < 0) - invarg("suppress_prefixlength value is invalid\n", *argv); - addattr32(&req.n, sizeof(req), FRA_SUPPRESS_PREFIXLEN, pl); + invarg("suppress_prefixlength value is invalid\n", + *argv); + addattr32(&req.n, sizeof(req), + FRA_SUPPRESS_PREFIXLEN, pl); } else if (matches(*argv, "suppress_ifgroup") == 0 || strcmp(*argv, "sup_group") == 0) { NEXT_ARG(); int group; if (rtnl_group_a2n(&group, *argv)) - invarg("Invalid \"suppress_ifgroup\" value\n", *argv); - addattr32(&req.n, sizeof(req), FRA_SUPPRESS_IFGROUP, group); + invarg("Invalid \"suppress_ifgroup\" value\n", + *argv); + addattr32(&req.n, sizeof(req), + FRA_SUPPRESS_IFGROUP, group); } else if (strcmp(*argv, "dev") == 0 || strcmp(*argv, "iif") == 0) { NEXT_ARG(); - addattr_l(&req.n, sizeof(req), FRA_IFNAME, *argv, strlen(*argv)+1); + addattr_l(&req.n, sizeof(req), FRA_IFNAME, + *argv, strlen(*argv)+1); } else if (strcmp(*argv, "oif") == 0) { NEXT_ARG(); - addattr_l(&req.n, sizeof(req), FRA_OIFNAME, *argv, strlen(*argv)+1); + addattr_l(&req.n, sizeof(req), FRA_OIFNAME, + *argv, strlen(*argv)+1); } else if (strcmp(*argv, "l3mdev") == 0) { addattr8(&req.n, sizeof(req), FRA_L3MDEV, 1); table_ok = 1; @@ -441,14 +461,15 @@ static int iprule_modify(int cmd, int argc, char **argv) matches(*argv, "map-to") == 0) { NEXT_ARG(); fprintf(stderr, "Warning: route NAT is deprecated\n"); - addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv)); + addattr32(&req.n, sizeof(req), RTA_GATEWAY, + get_addr32(*argv)); req.r.rtm_type = RTN_NAT; } else { int type; - if (strcmp(*argv, "type") == 0) { + if (strcmp(*argv, "type") == 0) NEXT_ARG(); - } + if (matches(*argv, "help") == 0) usage(); else if (matches(*argv, "goto") == 0) { @@ -458,7 +479,8 @@ static int iprule_modify(int cmd, int argc, char **argv) NEXT_ARG(); if (get_u32(&target, *argv, 0)) invarg("invalid target\n", *argv); - addattr32(&req.n, sizeof(req), FRA_GOTO, target); + addattr32(&req.n, sizeof(req), + FRA_GOTO, target); } else if (matches(*argv, "nop") == 0) type = FR_ACT_NOP; else if (rtnl_rtntype_a2n(&type, *argv)) @@ -489,7 +511,8 @@ static int iprule_modify(int cmd, int argc, char **argv) } -static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, + void *arg) { struct rtnl_handle rth2; struct rtmsg *r = NLMSG_DATA(n); @@ -564,7 +587,8 @@ int do_iprule(int argc, char **argv) } else if (matches(argv[0], "help") == 0) usage(); - fprintf(stderr, "Command \"%s\" is unknown, try \"ip rule help\".\n", *argv); + fprintf(stderr, + "Command \"%s\" is unknown, try \"ip rule help\".\n", *argv); exit(-1); } @@ -582,7 +606,8 @@ int do_multirule(int argc, char **argv) case RTNL_FAMILY_IP6MR: break; default: - fprintf(stderr, "Multicast rules are only supported for IPv4/IPv6, was: %i\n", + fprintf(stderr, + "Multicast rules are only supported for IPv4/IPv6, was: %i\n", preferred_family); exit(-1); } From 9b32f89693ef030785196987c29e3ebb2632834b Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 29 May 2016 20:27:13 +0200 Subject: [PATCH 279/513] tc: let m_ipt work with new iptables API headers Since commit 5cd1adb ("Update to current iptables headers") the build with m_ipt.o and the following config will fail: TC_CONFIG_XT:=n TC_CONFIG_XT_OLD:=n TC_CONFIG_XT_OLD_H:=n This patch renames "iptables_target" to "xtables_target" and some other things which gets renamed and I noticed while reading iptables git log. Functions which are not used in m_ipt.c and not exported by the header are removed, if they still used in m_ipt.c I added a static to the function. Reported-by: Clemens Gruber Signed-off-by: Alexander Aring --- tc/m_ipt.c | 134 ++++++----------------------------------------------- 1 file changed, 14 insertions(+), 120 deletions(-) diff --git a/tc/m_ipt.c b/tc/m_ipt.c index d088f5ed6..098f610f9 100644 --- a/tc/m_ipt.c +++ b/tc/m_ipt.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -51,7 +50,7 @@ static struct option original_opts[] = { {0, 0, 0, 0} }; -static struct iptables_target *t_list; +static struct xtables_target *t_list; static struct option *opts = original_opts; static unsigned int global_option_offset; #define OPTION_OFFSET 256 @@ -59,32 +58,21 @@ static unsigned int global_option_offset; char *lib_dir; void -register_target(struct iptables_target *me) +xtables_register_target(struct xtables_target *me) { -/* fprintf(stderr, "\nDummy register_target %s\n", me->name); -*/ me->next = t_list; t_list = me; } -void -xtables_register_target(struct iptables_target *me) -{ - me->next = t_list; - t_list = me; -} - -void -exit_tryhelp(int status) +static void exit_tryhelp(int status) { fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", pname, pname); exit(status); } -void -exit_error(enum exittype status, char *msg, ...) +static void exit_error(enum xtables_exittype status, char *msg, ...) { va_list args; @@ -106,61 +94,6 @@ They should really have them as a library so i can link to them Email them next time i remember */ -char * -addr_to_dotted(const struct in_addr *addrp) -{ - static char buf[20]; - const unsigned char *bytep; - - bytep = (const unsigned char *) &(addrp->s_addr); - sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]); - return buf; -} - -int string_to_number_ll(const char *s, unsigned long long min, - unsigned long long max, - unsigned long long *ret) -{ - unsigned long long number; - char *end; - - /* Handle hex, octal, etc. */ - errno = 0; - number = strtoull(s, &end, 0); - if (*end == '\0' && end != s) { - /* we parsed a number, let's see if we want this */ - if (errno != ERANGE && min <= number && (!max || number <= max)) { - *ret = number; - return 0; - } - } - return -1; -} - -int string_to_number_l(const char *s, unsigned long min, unsigned long max, - unsigned long *ret) -{ - int result; - unsigned long long number; - - result = string_to_number_ll(s, min, max, &number); - *ret = (unsigned long)number; - - return result; -} - -int string_to_number(const char *s, unsigned int min, unsigned int max, - unsigned int *ret) -{ - int result; - unsigned long number; - - result = string_to_number_l(s, min, max, &number); - *ret = (unsigned int)number; - - return result; -} - static void free_opts(struct option *local_opts) { if (local_opts != original_opts) { @@ -205,10 +138,10 @@ fw_calloc(size_t count, size_t size) return p; } -static struct iptables_target * +static struct xtables_target * find_t(char *name) { - struct iptables_target *m; + struct xtables_target *m; for (m = t_list; m; m = m->next) { if (strcmp(m->name, name) == 0) @@ -218,13 +151,13 @@ find_t(char *name) return NULL; } -static struct iptables_target * +static struct xtables_target * get_target_name(const char *name) { void *handle; char *error; char *new_name, *lname; - struct iptables_target *m; + struct xtables_target *m; char path[strlen(lib_dir) + sizeof("/libipt_.so") + strlen(name)]; #ifdef NO_SHARED_LIBS @@ -291,7 +224,7 @@ get_target_name(const char *name) m = dlsym(handle, new_name); if ((error = dlerror()) != NULL) { - m = (struct iptables_target *) dlsym(handle, lname); + m = (struct xtables_target *) dlsym(handle, lname); if ((error = dlerror()) != NULL) { m = find_t(new_name); if (m == NULL) { @@ -313,42 +246,6 @@ get_target_name(const char *name) return m; } - -struct in_addr *dotted_to_addr(const char *dotted) -{ - static struct in_addr addr; - unsigned char *addrp; - char *p, *q; - unsigned int onebyte; - int i; - char buf[20]; - - /* copy dotted string, because we need to modify it */ - strncpy(buf, dotted, sizeof(buf) - 1); - addrp = (unsigned char *) &(addr.s_addr); - - p = buf; - for (i = 0; i < 3; i++) { - if ((q = strchr(p, '.')) == NULL) - return (struct in_addr *) NULL; - - *q = '\0'; - if (string_to_number(p, 0, 255, &onebyte) == -1) - return (struct in_addr *) NULL; - - addrp[i] = (unsigned char) onebyte; - p = q + 1; - } - - /* we've checked 3 bytes, now we check the last one */ - if (string_to_number(p, 0, 255, &onebyte) == -1) - return (struct in_addr *) NULL; - - addrp[3] = (unsigned char) onebyte; - - return &addr; -} - static void set_revision(char *name, u_int8_t revision) { /* Old kernel sources don't have ".revision" field, @@ -360,23 +257,20 @@ static void set_revision(char *name, u_int8_t revision) /* * we may need to check for version mismatch */ -int -build_st(struct iptables_target *target, struct ipt_entry_target *t) +static int build_st(struct xtables_target *target, struct ipt_entry_target *t) { - unsigned int nfcache = 0; - if (target) { size_t size; size = - IPT_ALIGN(sizeof(struct ipt_entry_target)) + target->size; + XT_ALIGN(sizeof(struct ipt_entry_target)) + target->size; if (t == NULL) { target->t = fw_calloc(1, size); target->t->u.target_size = size; if (target->init != NULL) - target->init(target->t, &nfcache); + target->init(target->t); set_revision(target->t->u.user.name, target->revision); } else { target->t = t; @@ -391,7 +285,7 @@ build_st(struct iptables_target *target, struct ipt_entry_target *t) static int parse_ipt(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { - struct iptables_target *m = NULL; + struct xtables_target *m = NULL; struct ipt_entry fw; struct rtattr *tail; int c; @@ -574,7 +468,7 @@ print_ipt(struct action_util *au, FILE * f, struct rtattr *arg) fprintf(f, "\t[NULL ipt target parameters ]\n"); return -1; } else { - struct iptables_target *m = NULL; + struct xtables_target *m = NULL; t = RTA_DATA(tb[TCA_IPT_TARG]); m = get_target_name(t->u.user.name); From a0a73b298a579c4dd3a342eded419304d29ab60a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 16 Jun 2016 00:50:38 +0200 Subject: [PATCH 280/513] tc: m_action: Use C99 style initializers for struct req Instead of initializing fields after (or sometimes even before) zeroing the whole struct via memset(), initialize the whole thing at declaration time. Signed-off-by: Phil Sutter --- tc/m_action.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/tc/m_action.c b/tc/m_action.c index c416d98a7..f97ed2e77 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -395,18 +395,19 @@ static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p struct nlmsghdr n; struct tcamsg t; char buf[MAX_MSG]; - } req; - - req.t.tca_family = AF_UNSPEC; - - memset(&req, 0, sizeof(req)); + } req = { + .n = { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)), + .nlmsg_flags = NLM_F_REQUEST | flags, + .nlmsg_type = cmd, + }, + .t.tca_family = AF_UNSPEC, + .buf = { 0 } + }; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; argc -= 1; argv += 1; @@ -500,15 +501,16 @@ static int tc_action_modify(int cmd, unsigned int flags, int *argc_p, char ***ar struct nlmsghdr n; struct tcamsg t; char buf[MAX_MSG]; - } req; - - req.t.tca_family = AF_UNSPEC; - - memset(&req, 0, sizeof(req)); + } req = { + .n = { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)), + .nlmsg_flags = NLM_F_REQUEST | flags, + .nlmsg_type = cmd, + }, + .t.tca_family = AF_UNSPEC, + .buf = { 0 } + }; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; tail = NLMSG_TAIL(&req.n); argc -= 1; argv += 1; @@ -539,13 +541,11 @@ static int tc_act_list_or_flush(int argc, char **argv, int event) struct nlmsghdr n; struct tcamsg t; char buf[MAX_MSG]; - } req; - - req.t.tca_family = AF_UNSPEC; - - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)); + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)), + .t.tca_family = AF_UNSPEC, + .buf = { 0 } + }; tail = NLMSG_TAIL(&req.n); addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0); From 5f6a467f59c4b9474a7bb2851798c6cf7f44887e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 16 Jun 2016 00:50:39 +0200 Subject: [PATCH 281/513] tc: m_action: Drop unused variable nladdr in tc_action_gd() This has been there since the introduction of tc/m_action.c back in 2004 and was apparently never in use. Signed-off-by: Phil Sutter --- tc/m_action.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tc/m_action.c b/tc/m_action.c index f97ed2e77..ea16817ae 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -386,7 +386,6 @@ static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p int prio = 0; int ret = 0; __u32 i; - struct sockaddr_nl nladdr; struct rtattr *tail; struct rtattr *tail2; struct nlmsghdr *ans = NULL; @@ -405,9 +404,6 @@ static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p .buf = { 0 } }; - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - argc -= 1; argv += 1; From 414aeec90f82d73614e4b931f04c28caabb21824 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 17 Jun 2016 17:38:53 -0700 Subject: [PATCH 282/513] ss: Add tcp_info fields data_segs_in/out tcp_info fields, data_segs_in and data_segs_out, have been added to the kernel in commit a44d6eacdaf5 ("tcp: Add RFC4898 tcpEStatsPerfDataSegsOut/In") since kernel 4.6. This patch supports those fileds in ss: ESTAB 801736 360 face:face:face:face::1:22 face:face:face:face::face:46779 cubic wscale:9,7 rto:223 rtt:22.195/8.202 ato:40 mss:1428 cwnd:11 ssthresh:7 bytes_acked:203649 bytes_received:334034603 segs_out:18513 segs_in:241825 data_segs_out:4192 data_segs_in:241672 send 5.7Mbps lastsnd:2 lastack:3 pacing_rate 6.8Mbps unacked:10 retrans:0/1 rcv_rtt:29.375 rcv_space:1241704 minrtt:0.013 Signed-off-by: Martin KaFai Lau --- misc/ss.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/misc/ss.c b/misc/ss.c index 9c456d4f1..02be7e740 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -766,6 +766,8 @@ struct tcpstat { unsigned long long bytes_received; unsigned int segs_out; unsigned int segs_in; + unsigned int data_segs_out; + unsigned int data_segs_in; unsigned int unacked; unsigned int retrans; unsigned int retrans_total; @@ -1716,6 +1718,10 @@ static void tcp_stats_print(struct tcpstat *s) printf(" segs_out:%u", s->segs_out); if (s->segs_in) printf(" segs_in:%u", s->segs_in); + if (s->data_segs_out) + printf(" data_segs_out:%u", s->data_segs_out); + if (s->data_segs_in) + printf(" data_segs_in:%u", s->data_segs_in); if (s->dctcp && s->dctcp->enabled) { struct dctcpstat *dctcp = s->dctcp; @@ -2022,6 +2028,8 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, s.bytes_received = info->tcpi_bytes_received; s.segs_out = info->tcpi_segs_out; s.segs_in = info->tcpi_segs_in; + s.data_segs_out = info->tcpi_data_segs_out; + s.data_segs_in = info->tcpi_data_segs_in; s.not_sent = info->tcpi_notsent_bytes; if (info->tcpi_min_rtt && info->tcpi_min_rtt != ~0U) s.min_rtt = (double) info->tcpi_min_rtt / 1000; From a89193a7d68f59c1ce3bf47a32ff7b73661f1c54 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 16 Jun 2016 16:19:39 +0200 Subject: [PATCH 283/513] iplink: Add missing variable initialization Without this, we might feed garbage to the kernel when the address is shorter than expected. Signed-off-by: Phil Sutter --- ip/iplink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/iplink.c b/ip/iplink.c index d2e586b6d..4cb9bab66 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -273,7 +273,7 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, while (NEXT_ARG_OK()) { NEXT_ARG(); if (matches(*argv, "mac") == 0) { - struct ifla_vf_mac ivm; + struct ifla_vf_mac ivm = { 0 }; NEXT_ARG(); ivm.vf = vf; From 8fe58d58941f440140986f444c3d040b5e350c87 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 16 Jun 2016 16:19:40 +0200 Subject: [PATCH 284/513] iplink: Check address length via netlink This is a feature which was lost during the conversion to netlink interface: If the device exists and a user tries to change the link layer address, query the kernel for the old address first and reject the new one if sizes differ. This patch adds the same check when setting VF address by assuming same length as PF device. Note that at least for VFs the check can't be done in kernel space since struct ifla_vf_mac lacks a length field and due to netlink padding the exact size can't be communicated to the kernel. Signed-off-by: Phil Sutter --- ip/iplink.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/ip/iplink.c b/ip/iplink.c index 4cb9bab66..68e5faea3 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -237,6 +237,36 @@ struct iplink_req { char buf[1024]; }; +static int nl_get_ll_addr_len(unsigned int dev_index) +{ + int len; + struct iplink_req req = { + .n = { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .nlmsg_type = RTM_GETLINK, + .nlmsg_flags = NLM_F_REQUEST + }, + .i = { + .ifi_family = preferred_family, + .ifi_index = dev_index, + } + }; + struct rtattr *tb[IFLA_MAX+1]; + + if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) + return -1; + + len = req.n.nlmsg_len - NLMSG_LENGTH(sizeof(req.i)); + if (len < 0) + return -1; + + parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(&req.i), len, NLA_F_NESTED); + if (!tb[IFLA_ADDRESS]) + return -1; + + return RTA_PAYLOAD(tb[IFLA_ADDRESS]); +} + static int iplink_parse_vf(int vf, int *argcp, char ***argvp, struct iplink_req *req, int dev_index) { @@ -274,12 +304,19 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, NEXT_ARG(); if (matches(*argv, "mac") == 0) { struct ifla_vf_mac ivm = { 0 }; + int halen = nl_get_ll_addr_len(dev_index); NEXT_ARG(); ivm.vf = vf; len = ll_addr_a2n((char *)ivm.mac, 32, *argv); if (len < 0) return -1; + if (halen > 0 && len != halen) { + fprintf(stderr, + "Invalid address length %d - must be %d bytes\n", + len, halen); + return -1; + } addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm)); } else if (matches(*argv, "vlan") == 0) { struct ifla_vf_vlan ivv; @@ -428,6 +465,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, int numrxqueues = -1; int dev_index = 0; int link_netnsid = -1; + int addr_len = 0; *group = -1; ret = argc; @@ -452,10 +490,10 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, *link = *argv; } else if (matches(*argv, "address") == 0) { NEXT_ARG(); - len = ll_addr_a2n(abuf, sizeof(abuf), *argv); + addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv); if (len < 0) return -1; - addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len); + addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, addr_len); } else if (matches(*argv, "broadcast") == 0 || strcmp(*argv, "brd") == 0) { NEXT_ARG(); @@ -677,6 +715,16 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, argc--; argv++; } + if (dev_index && addr_len) { + int halen = nl_get_ll_addr_len(dev_index); + if (halen >= 0 && halen != addr_len) { + fprintf(stderr, + "Invalid address length %d - must be %d bytes\n", + addr_len, halen); + return -1; + } + } + return ret - argc; } From 5b26063c256c68d4b4f1f13931e57cdcd226e360 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 21 Jun 2016 11:24:52 -0700 Subject: [PATCH 285/513] if: add missing kernel headers Add kernel headers for all headers that included by current source. --- include/linux/if_alg.h | 42 ++++++ include/linux/if_bonding.h | 130 ++++++++++++++++ include/linux/if_packet.h | 301 +++++++++++++++++++++++++++++++++++++ 3 files changed, 473 insertions(+) create mode 100644 include/linux/if_alg.h create mode 100644 include/linux/if_bonding.h create mode 100644 include/linux/if_packet.h diff --git a/include/linux/if_alg.h b/include/linux/if_alg.h new file mode 100644 index 000000000..f2acd2fde --- /dev/null +++ b/include/linux/if_alg.h @@ -0,0 +1,42 @@ +/* + * if_alg: User-space algorithm interface + * + * Copyright (c) 2010 Herbert Xu + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#ifndef _LINUX_IF_ALG_H +#define _LINUX_IF_ALG_H + +#include + +struct sockaddr_alg { + __u16 salg_family; + __u8 salg_type[14]; + __u32 salg_feat; + __u32 salg_mask; + __u8 salg_name[64]; +}; + +struct af_alg_iv { + __u32 ivlen; + __u8 iv[0]; +}; + +/* Socket options */ +#define ALG_SET_KEY 1 +#define ALG_SET_IV 2 +#define ALG_SET_OP 3 +#define ALG_SET_AEAD_ASSOCLEN 4 +#define ALG_SET_AEAD_AUTHSIZE 5 + +/* Operations */ +#define ALG_OP_DECRYPT 0 +#define ALG_OP_ENCRYPT 1 + +#endif /* _LINUX_IF_ALG_H */ diff --git a/include/linux/if_bonding.h b/include/linux/if_bonding.h new file mode 100644 index 000000000..9635a62f6 --- /dev/null +++ b/include/linux/if_bonding.h @@ -0,0 +1,130 @@ +/* + * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'. + * + * + * Portions are (c) Copyright 1995 Simon "Guru Aleph-Null" Janes + * NCM: Network and Communications Management, Inc. + * + * BUT, I'm the one who modified it for ethernet, so: + * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * 2003/03/18 - Amir Noam + * - Added support for getting slave's speed and duplex via ethtool. + * Needed for 802.3ad and other future modes. + * + * 2003/03/18 - Tsippy Mendelson and + * Shmulik Hen + * - Enable support of modes that need to use the unique mac address of + * each slave. + * + * 2003/03/18 - Tsippy Mendelson and + * Amir Noam + * - Moved driver's private data types to bonding.h + * + * 2003/03/18 - Amir Noam , + * Tsippy Mendelson and + * Shmulik Hen + * - Added support for IEEE 802.3ad Dynamic link aggregation mode. + * + * 2003/05/01 - Amir Noam + * - Added ABI version control to restore compatibility between + * new/old ifenslave and new/old bonding. + * + * 2003/12/01 - Shmulik Hen + * - Code cleanup and style changes + * + * 2005/05/05 - Jason Gabler + * - added definitions for various XOR hashing policies + */ + +#ifndef _LINUX_IF_BONDING_H +#define _LINUX_IF_BONDING_H + +#include +#include +#include + +/* userland - kernel ABI version (2003/05/08) */ +#define BOND_ABI_VERSION 2 + +/* + * We can remove these ioctl definitions in 2.5. People should use the + * SIOC*** versions of them instead + */ +#define BOND_ENSLAVE_OLD (SIOCDEVPRIVATE) +#define BOND_RELEASE_OLD (SIOCDEVPRIVATE + 1) +#define BOND_SETHWADDR_OLD (SIOCDEVPRIVATE + 2) +#define BOND_SLAVE_INFO_QUERY_OLD (SIOCDEVPRIVATE + 11) +#define BOND_INFO_QUERY_OLD (SIOCDEVPRIVATE + 12) +#define BOND_CHANGE_ACTIVE_OLD (SIOCDEVPRIVATE + 13) + +#define BOND_CHECK_MII_STATUS (SIOCGMIIPHY) + +#define BOND_MODE_ROUNDROBIN 0 +#define BOND_MODE_ACTIVEBACKUP 1 +#define BOND_MODE_XOR 2 +#define BOND_MODE_BROADCAST 3 +#define BOND_MODE_8023AD 4 +#define BOND_MODE_TLB 5 +#define BOND_MODE_ALB 6 /* TLB + RLB (receive load balancing) */ + +/* each slave's link has 4 states */ +#define BOND_LINK_UP 0 /* link is up and running */ +#define BOND_LINK_FAIL 1 /* link has just gone down */ +#define BOND_LINK_DOWN 2 /* link has been down for too long time */ +#define BOND_LINK_BACK 3 /* link is going back */ + +/* each slave has several states */ +#define BOND_STATE_ACTIVE 0 /* link is active */ +#define BOND_STATE_BACKUP 1 /* link is backup */ + +#define BOND_DEFAULT_MAX_BONDS 1 /* Default maximum number of devices to support */ + +#define BOND_DEFAULT_TX_QUEUES 16 /* Default number of tx queues per device */ + +#define BOND_DEFAULT_RESEND_IGMP 1 /* Default number of IGMP membership reports */ + +/* hashing types */ +#define BOND_XMIT_POLICY_LAYER2 0 /* layer 2 (MAC only), default */ +#define BOND_XMIT_POLICY_LAYER34 1 /* layer 3+4 (IP ^ (TCP || UDP)) */ +#define BOND_XMIT_POLICY_LAYER23 2 /* layer 2+3 (IP ^ MAC) */ +#define BOND_XMIT_POLICY_ENCAP23 3 /* encapsulated layer 2+3 */ +#define BOND_XMIT_POLICY_ENCAP34 4 /* encapsulated layer 3+4 */ + +typedef struct ifbond { + __s32 bond_mode; + __s32 num_slaves; + __s32 miimon; +} ifbond; + +typedef struct ifslave { + __s32 slave_id; /* Used as an IN param to the BOND_SLAVE_INFO_QUERY ioctl */ + char slave_name[IFNAMSIZ]; + __s8 link; + __s8 state; + __u32 link_failure_count; +} ifslave; + +struct ad_info { + __u16 aggregator_id; + __u16 ports; + __u16 actor_key; + __u16 partner_key; + __u8 partner_system[ETH_ALEN]; +}; + +#endif /* _LINUX_IF_BONDING_H */ + +/* + * Local variables: + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ + diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h new file mode 100644 index 000000000..9e7edfd81 --- /dev/null +++ b/include/linux/if_packet.h @@ -0,0 +1,301 @@ +#ifndef __LINUX_IF_PACKET_H +#define __LINUX_IF_PACKET_H + +#include + +struct sockaddr_pkt { + unsigned short spkt_family; + unsigned char spkt_device[14]; + __be16 spkt_protocol; +}; + +struct sockaddr_ll { + unsigned short sll_family; + __be16 sll_protocol; + int sll_ifindex; + unsigned short sll_hatype; + unsigned char sll_pkttype; + unsigned char sll_halen; + unsigned char sll_addr[8]; +}; + +/* Packet types */ + +#define PACKET_HOST 0 /* To us */ +#define PACKET_BROADCAST 1 /* To all */ +#define PACKET_MULTICAST 2 /* To group */ +#define PACKET_OTHERHOST 3 /* To someone else */ +#define PACKET_OUTGOING 4 /* Outgoing of any type */ +#define PACKET_LOOPBACK 5 /* MC/BRD frame looped back */ +#define PACKET_USER 6 /* To user space */ +#define PACKET_KERNEL 7 /* To kernel space */ +/* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */ +#define PACKET_FASTROUTE 6 /* Fastrouted frame */ + +/* Packet socket options */ + +#define PACKET_ADD_MEMBERSHIP 1 +#define PACKET_DROP_MEMBERSHIP 2 +#define PACKET_RECV_OUTPUT 3 +/* Value 4 is still used by obsolete turbo-packet. */ +#define PACKET_RX_RING 5 +#define PACKET_STATISTICS 6 +#define PACKET_COPY_THRESH 7 +#define PACKET_AUXDATA 8 +#define PACKET_ORIGDEV 9 +#define PACKET_VERSION 10 +#define PACKET_HDRLEN 11 +#define PACKET_RESERVE 12 +#define PACKET_TX_RING 13 +#define PACKET_LOSS 14 +#define PACKET_VNET_HDR 15 +#define PACKET_TX_TIMESTAMP 16 +#define PACKET_TIMESTAMP 17 +#define PACKET_FANOUT 18 +#define PACKET_TX_HAS_OFF 19 +#define PACKET_QDISC_BYPASS 20 +#define PACKET_ROLLOVER_STATS 21 +#define PACKET_FANOUT_DATA 22 + +#define PACKET_FANOUT_HASH 0 +#define PACKET_FANOUT_LB 1 +#define PACKET_FANOUT_CPU 2 +#define PACKET_FANOUT_ROLLOVER 3 +#define PACKET_FANOUT_RND 4 +#define PACKET_FANOUT_QM 5 +#define PACKET_FANOUT_CBPF 6 +#define PACKET_FANOUT_EBPF 7 +#define PACKET_FANOUT_FLAG_ROLLOVER 0x1000 +#define PACKET_FANOUT_FLAG_DEFRAG 0x8000 + +struct tpacket_stats { + unsigned int tp_packets; + unsigned int tp_drops; +}; + +struct tpacket_stats_v3 { + unsigned int tp_packets; + unsigned int tp_drops; + unsigned int tp_freeze_q_cnt; +}; + +struct tpacket_rollover_stats { + __aligned_u64 tp_all; + __aligned_u64 tp_huge; + __aligned_u64 tp_failed; +}; + +union tpacket_stats_u { + struct tpacket_stats stats1; + struct tpacket_stats_v3 stats3; +}; + +struct tpacket_auxdata { + __u32 tp_status; + __u32 tp_len; + __u32 tp_snaplen; + __u16 tp_mac; + __u16 tp_net; + __u16 tp_vlan_tci; + __u16 tp_vlan_tpid; +}; + +/* Rx ring - header status */ +#define TP_STATUS_KERNEL 0 +#define TP_STATUS_USER (1 << 0) +#define TP_STATUS_COPY (1 << 1) +#define TP_STATUS_LOSING (1 << 2) +#define TP_STATUS_CSUMNOTREADY (1 << 3) +#define TP_STATUS_VLAN_VALID (1 << 4) /* auxdata has valid tp_vlan_tci */ +#define TP_STATUS_BLK_TMO (1 << 5) +#define TP_STATUS_VLAN_TPID_VALID (1 << 6) /* auxdata has valid tp_vlan_tpid */ +#define TP_STATUS_CSUM_VALID (1 << 7) + +/* Tx ring - header status */ +#define TP_STATUS_AVAILABLE 0 +#define TP_STATUS_SEND_REQUEST (1 << 0) +#define TP_STATUS_SENDING (1 << 1) +#define TP_STATUS_WRONG_FORMAT (1 << 2) + +/* Rx and Tx ring - header status */ +#define TP_STATUS_TS_SOFTWARE (1 << 29) +#define TP_STATUS_TS_SYS_HARDWARE (1 << 30) /* deprecated, never set */ +#define TP_STATUS_TS_RAW_HARDWARE (1 << 31) + +/* Rx ring - feature request bits */ +#define TP_FT_REQ_FILL_RXHASH 0x1 + +struct tpacket_hdr { + unsigned long tp_status; + unsigned int tp_len; + unsigned int tp_snaplen; + unsigned short tp_mac; + unsigned short tp_net; + unsigned int tp_sec; + unsigned int tp_usec; +}; + +#define TPACKET_ALIGNMENT 16 +#define TPACKET_ALIGN(x) (((x)+TPACKET_ALIGNMENT-1)&~(TPACKET_ALIGNMENT-1)) +#define TPACKET_HDRLEN (TPACKET_ALIGN(sizeof(struct tpacket_hdr)) + sizeof(struct sockaddr_ll)) + +struct tpacket2_hdr { + __u32 tp_status; + __u32 tp_len; + __u32 tp_snaplen; + __u16 tp_mac; + __u16 tp_net; + __u32 tp_sec; + __u32 tp_nsec; + __u16 tp_vlan_tci; + __u16 tp_vlan_tpid; + __u8 tp_padding[4]; +}; + +struct tpacket_hdr_variant1 { + __u32 tp_rxhash; + __u32 tp_vlan_tci; + __u16 tp_vlan_tpid; + __u16 tp_padding; +}; + +struct tpacket3_hdr { + __u32 tp_next_offset; + __u32 tp_sec; + __u32 tp_nsec; + __u32 tp_snaplen; + __u32 tp_len; + __u32 tp_status; + __u16 tp_mac; + __u16 tp_net; + /* pkt_hdr variants */ + union { + struct tpacket_hdr_variant1 hv1; + }; + __u8 tp_padding[8]; +}; + +struct tpacket_bd_ts { + unsigned int ts_sec; + union { + unsigned int ts_usec; + unsigned int ts_nsec; + }; +}; + +struct tpacket_hdr_v1 { + __u32 block_status; + __u32 num_pkts; + __u32 offset_to_first_pkt; + + /* Number of valid bytes (including padding) + * blk_len <= tp_block_size + */ + __u32 blk_len; + + /* + * Quite a few uses of sequence number: + * 1. Make sure cache flush etc worked. + * Well, one can argue - why not use the increasing ts below? + * But look at 2. below first. + * 2. When you pass around blocks to other user space decoders, + * you can see which blk[s] is[are] outstanding etc. + * 3. Validate kernel code. + */ + __aligned_u64 seq_num; + + /* + * ts_last_pkt: + * + * Case 1. Block has 'N'(N >=1) packets and TMO'd(timed out) + * ts_last_pkt == 'time-stamp of last packet' and NOT the + * time when the timer fired and the block was closed. + * By providing the ts of the last packet we can absolutely + * guarantee that time-stamp wise, the first packet in the + * next block will never precede the last packet of the + * previous block. + * Case 2. Block has zero packets and TMO'd + * ts_last_pkt = time when the timer fired and the block + * was closed. + * Case 3. Block has 'N' packets and NO TMO. + * ts_last_pkt = time-stamp of the last pkt in the block. + * + * ts_first_pkt: + * Is always the time-stamp when the block was opened. + * Case a) ZERO packets + * No packets to deal with but atleast you know the + * time-interval of this block. + * Case b) Non-zero packets + * Use the ts of the first packet in the block. + * + */ + struct tpacket_bd_ts ts_first_pkt, ts_last_pkt; +}; + +union tpacket_bd_header_u { + struct tpacket_hdr_v1 bh1; +}; + +struct tpacket_block_desc { + __u32 version; + __u32 offset_to_priv; + union tpacket_bd_header_u hdr; +}; + +#define TPACKET2_HDRLEN (TPACKET_ALIGN(sizeof(struct tpacket2_hdr)) + sizeof(struct sockaddr_ll)) +#define TPACKET3_HDRLEN (TPACKET_ALIGN(sizeof(struct tpacket3_hdr)) + sizeof(struct sockaddr_ll)) + +enum tpacket_versions { + TPACKET_V1, + TPACKET_V2, + TPACKET_V3 +}; + +/* + Frame structure: + + - Start. Frame must be aligned to TPACKET_ALIGNMENT=16 + - struct tpacket_hdr + - pad to TPACKET_ALIGNMENT=16 + - struct sockaddr_ll + - Gap, chosen so that packet data (Start+tp_net) alignes to TPACKET_ALIGNMENT=16 + - Start+tp_mac: [ Optional MAC header ] + - Start+tp_net: Packet data, aligned to TPACKET_ALIGNMENT=16. + - Pad to align to TPACKET_ALIGNMENT=16 + */ + +struct tpacket_req { + unsigned int tp_block_size; /* Minimal size of contiguous block */ + unsigned int tp_block_nr; /* Number of blocks */ + unsigned int tp_frame_size; /* Size of frame */ + unsigned int tp_frame_nr; /* Total number of frames */ +}; + +struct tpacket_req3 { + unsigned int tp_block_size; /* Minimal size of contiguous block */ + unsigned int tp_block_nr; /* Number of blocks */ + unsigned int tp_frame_size; /* Size of frame */ + unsigned int tp_frame_nr; /* Total number of frames */ + unsigned int tp_retire_blk_tov; /* timeout in msecs */ + unsigned int tp_sizeof_priv; /* offset to private data area */ + unsigned int tp_feature_req_word; +}; + +union tpacket_req_u { + struct tpacket_req req; + struct tpacket_req3 req3; +}; + +struct packet_mreq { + int mr_ifindex; + unsigned short mr_type; + unsigned short mr_alen; + unsigned char mr_address[8]; +}; + +#define PACKET_MR_MULTICAST 0 +#define PACKET_MR_PROMISC 1 +#define PACKET_MR_ALLMULTI 2 +#define PACKET_MR_UNICAST 3 + +#endif From 3b6d9ab2e25d64e5b771c4786628981626c32863 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 21 Jun 2016 11:29:20 -0700 Subject: [PATCH 286/513] update kernel headers (net-next) --- include/linux/if_tunnel.h | 1 + include/linux/netlink_diag.h | 1 + 2 files changed, 2 insertions(+) diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index f0201ca01..1fa343db4 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -113,6 +113,7 @@ enum { IFLA_GRE_ENCAP_SPORT, IFLA_GRE_ENCAP_DPORT, IFLA_GRE_COLLECT_METADATA, + IFLA_GRE_IGNORE_DF, __IFLA_GRE_MAX, }; diff --git a/include/linux/netlink_diag.h b/include/linux/netlink_diag.h index f2159d30d..defd25fb5 100644 --- a/include/linux/netlink_diag.h +++ b/include/linux/netlink_diag.h @@ -48,6 +48,7 @@ enum { #define NDIAG_SHOW_MEMINFO 0x00000001 /* show memory info of a socket */ #define NDIAG_SHOW_GROUPS 0x00000002 /* show groups of a netlink socket */ +/* deprecated since 4.6 */ #define NDIAG_SHOW_RING_CFG 0x00000004 /* show ring configuration */ #endif From 3462c116f8dd578591f5f41d249d7542ea476ca4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 24 Jun 2016 12:14:23 +0200 Subject: [PATCH 287/513] man: ip-address, ip-link: Document 'type' quirk This covers the fact that calling 'ip {link|addr} show type foobar' does not return an error. Signed-off-by: Phil Sutter --- man/man8/ip-address.8.in | 6 ++++++ man/man8/ip-link.8.in | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/man/man8/ip-address.8.in b/man/man8/ip-address.8.in index ab0942d7e..8d34adb33 100644 --- a/man/man8/ip-address.8.in +++ b/man/man8/ip-address.8.in @@ -280,6 +280,12 @@ only list interfaces enslaved to this master device. .BI type " TYPE" only list interfaces of the given type. +Note that the type name is not checked against the list of supported types - +instead it is sent as-is to the kernel. Later it is used to filter the returned +interface list by comparing it with the relevant attribute in case the kernel +didn't filter already. Therefore any string is accepted, but may lead to empty +output. + .TP .B up only list running interfaces. diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index d5673639d..e10f541b2 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -1242,6 +1242,12 @@ specifies the master device which enslaves devices to show. .I TYPE specifies the type of devices to show. +Note that the type name is not checked against the list of supported types - +instead it is sent as-is to the kernel. Later it is used to filter the returned +interface list by comparing it with the relevant attribute in case the kernel +didn't filter already. Therefore any string is accepted, but may lead to empty +output. + .SS ip link help - display help .PP From 0aae23468ac57924c040ef4588ecd6b6dcb33075 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 22 Jun 2016 12:05:38 +0200 Subject: [PATCH 288/513] Fix MAC address length check I forgot to change the variable in the conditional, too. Fixes: 8fe58d58941f4 ("iplink: Check address length via netlink") Signed-off-by: Phil Sutter --- ip/iplink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/iplink.c b/ip/iplink.c index 68e5faea3..b1f8a3792 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -491,7 +491,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, } else if (matches(*argv, "address") == 0) { NEXT_ARG(); addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv); - if (len < 0) + if (addr_len < 0) return -1; addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, addr_len); } else if (matches(*argv, "broadcast") == 0 || From 296cee6fdfaabfbf29a9f6bbf106c83c82c1d838 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Tue, 21 Jun 2016 15:28:26 -0400 Subject: [PATCH 289/513] bridge: vlan: fix a few "fdb" typos in vlan doc Signed-off-by: Vivien Didelot --- bridge/vlan.c | 2 +- man/man8/bridge.8 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bridge/vlan.c b/bridge/vlan.c index 717025ae6..a8a2e1d95 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -299,6 +299,6 @@ int do_vlan(int argc, char **argv) } else return vlan_show(0, NULL); - fprintf(stderr, "Command \"%s\" is unknown, try \"bridge fdb help\".\n", *argv); + fprintf(stderr, "Command \"%s\" is unknown, try \"bridge vlan help\".\n", *argv); exit(-1); } diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index 08e8a5bf5..1818542eb 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -551,8 +551,8 @@ device is the bridge device. .BI master the vlan is configured on the software bridge (default). -.SS bridge vlan delete - delete a forwarding database entry -This command removes an existing fdb entry. +.SS bridge vlan delete - delete a vlan filter entry +This command removes an existing vlan filter entry. .PP The arguments are the same as with From 7fab22abd1ff6c8e8d4e5cd3602d7c28a3fa98de Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Tue, 21 Jun 2016 15:28:50 -0400 Subject: [PATCH 290/513] bridge: man: fix "brige" typo Signed-off-by: Vivien Didelot --- man/man8/bridge.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index 1818542eb..ac42118e7 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -234,7 +234,7 @@ error. .sp .B 1 -- STP LISTENING state. Only valid if STP is enabled on the brige. In this +- STP LISTENING state. Only valid if STP is enabled on the bridge. In this state the port for list for STP BPDUs and drop all other traffic. .sp From 2a6f9cfa8b31a4adf2ba6a3f9b2c8c69ea8f65b5 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 21 Jun 2016 16:29:01 -0700 Subject: [PATCH 291/513] man: ip-link: Add vrf type Add description for vrf type to ip-link man page. Signed-off-by: David Ahern --- man/man8/ip-link.8.in | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index e10f541b2..375b4d081 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -65,7 +65,8 @@ ip-link \- network device configuration .BR nlmon " |" .BR ipvlan " |" .BR lowpan " |" -.BR geneve " ]" +.BR geneve " |" +.BR vrf " ]" .ti -8 .BR "ip link delete " { @@ -263,6 +264,9 @@ Link types: .sp .BR macsec - Interface for IEEE 802.1AE MAC Security (MACsec) +.sp +.BR vrf +- Interface for L3 VRF domains .in -8 .TP @@ -966,6 +970,20 @@ the following additional arguments are supported: .in -8 +.TP +VRF Type Support +For a link of type +.I VRF +the following additional arguments are supported: + +.BI "ip link add " DEVICE " type vrf table " TABLE + +.in +8 +.sp +.BR table " table id associated with VRF device" + +.in -8 + .SS ip link delete - delete virtual link .TP From 08401220a936cedd439a605c923122825641ff44 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Wed, 22 Jun 2016 13:34:13 +0200 Subject: [PATCH 292/513] ip/tcp_metrics: Simplify process_msg a bit On Tue, Jun 21, 2016 at 06:18 PM CEST, Phil Sutter wrote: > By combining the attribute extraction and check for existence, the > additional indentation level in the 'else' clause can be avoided. > > In addition to that, common actions for 'daddr' are combined since the > function returns if neither of the branches are taken. > > Signed-off-by: Phil Sutter > --- > ip/tcp_metrics.c | 45 ++++++++++++++++++--------------------------- > 1 file changed, 18 insertions(+), 27 deletions(-) > > diff --git a/ip/tcp_metrics.c b/ip/tcp_metrics.c > index f82604f458ada..899830c127bcb 100644 > --- a/ip/tcp_metrics.c > +++ b/ip/tcp_metrics.c > @@ -112,47 +112,38 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, > parse_rtattr(attrs, TCP_METRICS_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, > len); > > - a = attrs[TCP_METRICS_ATTR_ADDR_IPV4]; > - if (a) { > + if ((a = attrs[TCP_METRICS_ATTR_ADDR_IPV4])) { Copy the pointer inside the branch? Same gain on indentation while keeping checkpatch happy. I only compile-tested the patch below. Thanks, Jakub --- ip/tcp_metrics.c | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/ip/tcp_metrics.c b/ip/tcp_metrics.c index f82604f45..ac2613a0a 100644 --- a/ip/tcp_metrics.c +++ b/ip/tcp_metrics.c @@ -112,47 +112,44 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, parse_rtattr(attrs, TCP_METRICS_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len); - a = attrs[TCP_METRICS_ATTR_ADDR_IPV4]; - if (a) { + if (attrs[TCP_METRICS_ATTR_ADDR_IPV4]) { if (f.daddr.family && f.daddr.family != AF_INET) return 0; + a = attrs[TCP_METRICS_ATTR_ADDR_IPV4]; memcpy(&daddr.data, RTA_DATA(a), 4); daddr.bytelen = 4; family = AF_INET; atype = TCP_METRICS_ATTR_ADDR_IPV4; dlen = RTA_PAYLOAD(a); - } else { - a = attrs[TCP_METRICS_ATTR_ADDR_IPV6]; - if (a) { - if (f.daddr.family && f.daddr.family != AF_INET6) - return 0; - memcpy(&daddr.data, RTA_DATA(a), 16); - daddr.bytelen = 16; - family = AF_INET6; - atype = TCP_METRICS_ATTR_ADDR_IPV6; - dlen = RTA_PAYLOAD(a); - } else + } else if (attrs[TCP_METRICS_ATTR_ADDR_IPV6]) { + if (f.daddr.family && f.daddr.family != AF_INET6) return 0; + a = attrs[TCP_METRICS_ATTR_ADDR_IPV6]; + memcpy(&daddr.data, RTA_DATA(a), 16); + daddr.bytelen = 16; + family = AF_INET6; + atype = TCP_METRICS_ATTR_ADDR_IPV6; + dlen = RTA_PAYLOAD(a); + } else { + return 0; } - a = attrs[TCP_METRICS_ATTR_SADDR_IPV4]; - if (a) { + if (attrs[TCP_METRICS_ATTR_SADDR_IPV4]) { if (f.saddr.family && f.saddr.family != AF_INET) return 0; + a = attrs[TCP_METRICS_ATTR_SADDR_IPV4]; memcpy(&saddr.data, RTA_DATA(a), 4); saddr.bytelen = 4; stype = TCP_METRICS_ATTR_SADDR_IPV4; slen = RTA_PAYLOAD(a); - } else { + } else if (attrs[TCP_METRICS_ATTR_SADDR_IPV6]) { + if (f.saddr.family && f.saddr.family != AF_INET6) + return 0; a = attrs[TCP_METRICS_ATTR_SADDR_IPV6]; - if (a) { - if (f.saddr.family && f.saddr.family != AF_INET6) - return 0; - memcpy(&saddr.data, RTA_DATA(a), 16); - saddr.bytelen = 16; - stype = TCP_METRICS_ATTR_SADDR_IPV6; - slen = RTA_PAYLOAD(a); - } + memcpy(&saddr.data, RTA_DATA(a), 16); + saddr.bytelen = 16; + stype = TCP_METRICS_ATTR_SADDR_IPV6; + slen = RTA_PAYLOAD(a); } if (f.daddr.family && f.daddr.bitlen >= 0 && From 82d73ea03a1495a51425c28025ae48f92fb19182 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 27 Jun 2016 11:34:23 -0700 Subject: [PATCH 293/513] ss: Refactor inet_show_sock Extract parsing of sockstat and filter from inet_show_sock. While moving run_ssfilter into callers of inet_show_sock enable userspace filtering before the kill. Signed-off-by: David Ahern --- misc/ss.c | 75 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index 02be7e740..f164ca920 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -2038,42 +2038,48 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, } } -static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol) +static void parse_diag_msg(struct nlmsghdr *nlh, struct sockstat *s) { struct rtattr *tb[INET_DIAG_MAX+1]; struct inet_diag_msg *r = NLMSG_DATA(nlh); - struct sockstat s = {}; parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr *)(r+1), nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); - s.state = r->idiag_state; - s.local.family = s.remote.family = r->idiag_family; - s.lport = ntohs(r->id.idiag_sport); - s.rport = ntohs(r->id.idiag_dport); - s.wq = r->idiag_wqueue; - s.rq = r->idiag_rqueue; - s.ino = r->idiag_inode; - s.uid = r->idiag_uid; - s.iface = r->id.idiag_if; - s.sk = cookie_sk_get(&r->id.idiag_cookie[0]); - - if (s.local.family == AF_INET) { - s.local.bytelen = s.remote.bytelen = 4; - } else { - s.local.bytelen = s.remote.bytelen = 16; - } + s->state = r->idiag_state; + s->local.family = s->remote.family = r->idiag_family; + s->lport = ntohs(r->id.idiag_sport); + s->rport = ntohs(r->id.idiag_dport); + s->wq = r->idiag_wqueue; + s->rq = r->idiag_rqueue; + s->ino = r->idiag_inode; + s->uid = r->idiag_uid; + s->iface = r->id.idiag_if; + s->sk = cookie_sk_get(&r->id.idiag_cookie[0]); + + if (s->local.family == AF_INET) + s->local.bytelen = s->remote.bytelen = 4; + else + s->local.bytelen = s->remote.bytelen = 16; - memcpy(s.local.data, r->id.idiag_src, s.local.bytelen); - memcpy(s.remote.data, r->id.idiag_dst, s.local.bytelen); + memcpy(s->local.data, r->id.idiag_src, s->local.bytelen); + memcpy(s->remote.data, r->id.idiag_dst, s->local.bytelen); +} - if (f && f->f && run_ssfilter(f->f, &s) == 0) - return 0; +static int inet_show_sock(struct nlmsghdr *nlh, + struct sockstat *s, + int protocol) +{ + struct rtattr *tb[INET_DIAG_MAX+1]; + struct inet_diag_msg *r = NLMSG_DATA(nlh); + + parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr *)(r+1), + nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); if (tb[INET_DIAG_PROTOCOL]) protocol = *(__u8 *)RTA_DATA(tb[INET_DIAG_PROTOCOL]); - inet_stats_print(&s, protocol); + inet_stats_print(s, protocol); if (show_options) { struct tcpstat t = {}; @@ -2085,8 +2091,8 @@ static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol) } if (show_details) { - sock_details_print(&s); - if (s.local.family == AF_INET6 && tb[INET_DIAG_SKV6ONLY]) { + sock_details_print(s); + if (s->local.family == AF_INET6 && tb[INET_DIAG_SKV6ONLY]) { unsigned char v6only; v6only = *(__u8 *)RTA_DATA(tb[INET_DIAG_SKV6ONLY]); @@ -2268,9 +2274,16 @@ static int show_one_inet_sock(const struct sockaddr_nl *addr, int err; struct inet_diag_arg *diag_arg = arg; struct inet_diag_msg *r = NLMSG_DATA(h); + struct sockstat s = {}; if (!(diag_arg->f->families & (1 << r->idiag_family))) return 0; + + parse_diag_msg(h, &s); + + if (diag_arg->f->f && run_ssfilter(diag_arg->f->f, &s) == 0) + return 0; + if (diag_arg->f->kill && kill_inet_sock(h, arg) != 0) { if (errno == EOPNOTSUPP || errno == ENOENT) { /* Socket can't be closed, or is already closed. */ @@ -2280,7 +2293,9 @@ static int show_one_inet_sock(const struct sockaddr_nl *addr, return -1; } } - if ((err = inet_show_sock(h, diag_arg->f, diag_arg->protocol)) < 0) + + err = inet_show_sock(h, &s, diag_arg->protocol); + if (err < 0) return err; return 0; @@ -2345,6 +2360,7 @@ static int tcp_show_netlink_file(struct filter *f) while (1) { int status, err; struct nlmsghdr *h = (struct nlmsghdr *)buf; + struct sockstat s = {}; status = fread(buf, 1, sizeof(*h), fp); if (status < 0) { @@ -2383,7 +2399,12 @@ static int tcp_show_netlink_file(struct filter *f) return -1; } - err = inet_show_sock(h, f, IPPROTO_TCP); + parse_diag_msg(h, &s); + + if (f && f->f && run_ssfilter(f->f, &s) == 0) + continue; + + err = inet_show_sock(h, &s, IPPROTO_TCP); if (err < 0) return err; } From 376fb86872c06a34e59d681661b8f66adaeb6815 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 27 Jun 2016 11:34:24 -0700 Subject: [PATCH 294/513] ss: Allow ssfilter_bytecompile to return 0 Allow ssfilter_bytecompile to return 0 for filter ops the kernel does not support. If such an op is in the filter string then all filtering is done in userspace. Signed-off-by: David Ahern --- misc/ss.c | 52 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index f164ca920..051070161 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -1273,11 +1273,16 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) case SSF_AND: { - char *a1, *a2, *a; + char *a1 = NULL, *a2 = NULL, *a; int l1, l2; l1 = ssfilter_bytecompile(f->pred, &a1); l2 = ssfilter_bytecompile(f->post, &a2); + if (!l1 || !l2) { + free(a1); + free(a2); + return 0; + } if (!(a = malloc(l1+l2))) abort(); memcpy(a, a1, l1); memcpy(a+l1, a2, l2); @@ -1288,11 +1293,16 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) } case SSF_OR: { - char *a1, *a2, *a; + char *a1 = NULL, *a2 = NULL, *a; int l1, l2; l1 = ssfilter_bytecompile(f->pred, &a1); l2 = ssfilter_bytecompile(f->post, &a2); + if (!l1 || !l2) { + free(a1); + free(a2); + return 0; + } if (!(a = malloc(l1+l2+4))) abort(); memcpy(a, a1, l1); memcpy(a+l1+4, a2, l2); @@ -1303,10 +1313,14 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) } case SSF_NOT: { - char *a1, *a; + char *a1 = NULL, *a; int l1; l1 = ssfilter_bytecompile(f->pred, &a1); + if (!l1) { + free(a1); + return 0; + } if (!(a = malloc(l1+4))) abort(); memcpy(a, a1, l1); free(a1); @@ -2127,6 +2141,7 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f) struct msghdr msg; struct rtattr rta; struct iovec iov[3]; + int iovlen = 1; if (protocol == IPPROTO_UDP) return -1; @@ -2162,18 +2177,21 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f) }; if (f->f) { bclen = ssfilter_bytecompile(f->f, &bc); - rta.rta_type = INET_DIAG_REQ_BYTECODE; - rta.rta_len = RTA_LENGTH(bclen); - iov[1] = (struct iovec){ &rta, sizeof(rta) }; - iov[2] = (struct iovec){ bc, bclen }; - req.nlh.nlmsg_len += RTA_LENGTH(bclen); + if (bclen) { + rta.rta_type = INET_DIAG_REQ_BYTECODE; + rta.rta_len = RTA_LENGTH(bclen); + iov[1] = (struct iovec){ &rta, sizeof(rta) }; + iov[2] = (struct iovec){ bc, bclen }; + req.nlh.nlmsg_len += RTA_LENGTH(bclen); + iovlen = 3; + } } msg = (struct msghdr) { .msg_name = (void *)&nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = iov, - .msg_iovlen = f->f ? 3 : 1, + .msg_iovlen = iovlen, }; if (sendmsg(fd, &msg, 0) < 0) { @@ -2194,6 +2212,7 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f) struct msghdr msg; struct rtattr rta; struct iovec iov[3]; + int iovlen = 1; if (family == PF_UNSPEC) return tcpdiag_send(fd, protocol, f); @@ -2222,18 +2241,21 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f) }; if (f->f) { bclen = ssfilter_bytecompile(f->f, &bc); - rta.rta_type = INET_DIAG_REQ_BYTECODE; - rta.rta_len = RTA_LENGTH(bclen); - iov[1] = (struct iovec){ &rta, sizeof(rta) }; - iov[2] = (struct iovec){ bc, bclen }; - req.nlh.nlmsg_len += RTA_LENGTH(bclen); + if (bclen) { + rta.rta_type = INET_DIAG_REQ_BYTECODE; + rta.rta_len = RTA_LENGTH(bclen); + iov[1] = (struct iovec){ &rta, sizeof(rta) }; + iov[2] = (struct iovec){ bc, bclen }; + req.nlh.nlmsg_len += RTA_LENGTH(bclen); + iovlen = 3; + } } msg = (struct msghdr) { .msg_name = (void *)&nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = iov, - .msg_iovlen = f->f ? 3 : 1, + .msg_iovlen = iovlen, }; if (sendmsg(fd, &msg, 0) < 0) { From 2d29321256168e13e10fbde3c57f33e70dcb6cc8 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 27 Jun 2016 11:34:25 -0700 Subject: [PATCH 295/513] ss: Add support to filter on device Add support for device names in the filter. Example: root@kenny:~# ss -t 'sport == :22 && dev == red' State Recv-Q Send-Q Local Address:Port Peer Address:Port ESTAB 0 0 10.100.1.2%red:ssh 10.100.1.254:47814 ESTAB 0 0 2100:1::2%red:ssh 2100:1::64:49406 Since kernel does not support iface in the filter specifying a device name means all filtering is done in userspace. Signed-off-by: David Ahern --- misc/ss.c | 32 ++++++++++++++++++++++++++++++++ misc/ssfilter.h | 2 ++ misc/ssfilter.y | 22 +++++++++++++++++++++- 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/misc/ss.c b/misc/ss.c index 051070161..20ea3a44f 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -1043,6 +1043,7 @@ static void inet_addr_print(const inet_prefix *a, int port, unsigned int ifindex struct aafilter { inet_prefix addr; int port; + unsigned int iface; struct aafilter *next; }; @@ -1157,7 +1158,12 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s) return s->lport <= a->port; } + case SSF_DEVCOND: + { + struct aafilter *a = (void *)f->pred; + return s->iface == a->iface; + } /* Yup. It is recursion. Sorry. */ case SSF_AND: return run_ssfilter(f->pred, s) && run_ssfilter(f->post, s); @@ -1327,6 +1333,11 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) *(struct inet_diag_bc_op *)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, 8 }; *bytecode = a; return l1+4; + } + case SSF_DEVCOND: + { + /* bytecompile for SSF_DEVCOND not supported yet */ + return 0; } default: abort(); @@ -1416,6 +1427,27 @@ static int xll_name_to_index(const char *dev) return ll_name_to_index(dev); } +void *parse_devcond(char *name) +{ + struct aafilter a = { .iface = 0 }; + struct aafilter *res; + + a.iface = xll_name_to_index(name); + if (a.iface == 0) { + char *end; + unsigned long res; + + res = strtoul(name, &end, 0); + if (!end || end == name || *end || res > UINT_MAX) + return NULL; + } + + res = malloc(sizeof(*res)); + *res = a; + + return res; +} + void *parse_hostcond(char *addr, bool is_port) { char *port = NULL; diff --git a/misc/ssfilter.h b/misc/ssfilter.h index 53922a844..c7db8eee9 100644 --- a/misc/ssfilter.h +++ b/misc/ssfilter.h @@ -8,6 +8,7 @@ #define SSF_S_GE 7 #define SSF_S_LE 8 #define SSF_S_AUTO 9 +#define SSF_DEVCOND 10 #include @@ -20,3 +21,4 @@ struct ssfilter int ssfilter_parse(struct ssfilter **f, int argc, char **argv, FILE *fp); void *parse_hostcond(char *addr, bool is_port); +void *parse_devcond(char *name); diff --git a/misc/ssfilter.y b/misc/ssfilter.y index a258d04b8..14bf9817f 100644 --- a/misc/ssfilter.y +++ b/misc/ssfilter.y @@ -36,7 +36,7 @@ static void yyerror(char *s) %} -%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND +%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND DEVCOND DEVNAME %left '|' %left '&' %nonassoc '!' @@ -108,6 +108,14 @@ expr: DCOND HOSTCOND { $$ = alloc_node(SSF_NOT, alloc_node(SSF_SCOND, $3)); } + | DEVNAME '=' DEVCOND + { + $$ = alloc_node(SSF_DEVCOND, $3); + } + | DEVNAME NEQ DEVCOND + { + $$ = alloc_node(SSF_NOT, alloc_node(SSF_DEVCOND, $3)); + } | AUTOBOUND { @@ -237,6 +245,10 @@ int yylex(void) tok_type = SPORT; return SPORT; } + if (strcmp(curtok, "dev") == 0) { + tok_type = DEVNAME; + return DEVNAME; + } if (strcmp(curtok, ">=") == 0 || strcmp(curtok, "ge") == 0 || strcmp(curtok, "geq") == 0) @@ -263,6 +275,14 @@ int yylex(void) tok_type = AUTOBOUND; return AUTOBOUND; } + if (tok_type == DEVNAME) { + yylval = (void*)parse_devcond(curtok); + if (yylval == NULL) { + fprintf(stderr, "Cannot parse device.\n"); + exit(1); + } + return DEVCOND; + } yylval = (void*)parse_hostcond(curtok, tok_type == SPORT || tok_type == DPORT); if (yylval == NULL) { fprintf(stderr, "Cannot parse dst/src address.\n"); From 62000e51e05d635016bae9891a4e00134ed8aefb Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 28 Jun 2016 18:42:15 +0200 Subject: [PATCH 296/513] Use ARRAY_SIZE macro everywhere This patch was generated by the following semantic patch (a trimmed down version of what is shipped with Linux sources): @@ type T; T[] E; @@ ( - (sizeof(E)/sizeof(*E)) + ARRAY_SIZE(E) | - (sizeof(E)/sizeof(E[...])) + ARRAY_SIZE(E) | - (sizeof(E)/sizeof(T)) + ARRAY_SIZE(E) ) The only manual adjustment was to include utils.h in misc/nstat.c to make the macro known there. Signed-off-by: Phil Sutter --- bridge/link.c | 2 +- misc/nstat.c | 3 ++- misc/ss.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bridge/link.c b/bridge/link.c index 353e1c3da..b347040cc 100644 --- a/bridge/link.c +++ b/bridge/link.c @@ -319,7 +319,7 @@ static int brlink_modify(int argc, char **argv) } else if (strcmp(*argv, "state") == 0) { NEXT_ARG(); char *endptr; - size_t nstates = sizeof(port_states) / sizeof(*port_states); + size_t nstates = ARRAY_SIZE(port_states); state = strtol(*argv, &endptr, 10); if (!(**argv != '\0' && *endptr == '\0')) { diff --git a/misc/nstat.c b/misc/nstat.c index a9e0f2078..e579ce1d3 100644 --- a/misc/nstat.c +++ b/misc/nstat.c @@ -30,6 +30,7 @@ #include #include +#include "utils.h" int dump_zeros; int reset_history; @@ -95,7 +96,7 @@ static int useless_number(const char *id) { int i; - for (i = 0; i < sizeof(useless_numbers)/sizeof(*useless_numbers); i++) + for (i = 0; i < ARRAY_SIZE(useless_numbers); i++) if (strcmp(id, useless_numbers[i]) == 0) return 1; return 0; diff --git a/misc/ss.c b/misc/ss.c index 20ea3a44f..a0f9c6b96 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -666,7 +666,7 @@ static int get_slabstat(struct slabstat *s) while (fgets(buf, sizeof(buf), fp) != NULL) { int i; - for (i = 0; i < sizeof(slabstat_ids)/sizeof(slabstat_ids[0]); i++) { + for (i = 0; i < ARRAY_SIZE(slabstat_ids); i++) { if (memcmp(buf, slabstat_ids[i], strlen(slabstat_ids[i])) == 0) { sscanf(buf, "%*s%d", ((int *)s) + i); cnt--; From e0513807f6dbbd4631fdbb27f0bd6bbce138e8cd Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 28 Jun 2016 15:07:16 +0200 Subject: [PATCH 297/513] ip-address: Support filtering by slave type, too This patch allows to query all interfaces enslaved to a bridge or bond using the following syntax: | ip addr show type bridge_slave Filtering has to be done in userspace since the kernel does not support filtering on IFLA_INFO_SLAVE_KIND. Functionality introduced in this patch is not fully complete since it does not allow to match on type and slave type at the same time, but it doesn't prevent implementing a dedicated slave_type match, either. Signed-off-by: Phil Sutter --- ip/ipaddress.c | 52 +++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 8766530f7..56f68eb21 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -61,6 +61,7 @@ static struct int group; int master; char *kind; + char *slave_kind; } filter; static int do_link; @@ -206,18 +207,27 @@ static void print_linkmode(FILE *f, struct rtattr *tb) fprintf(f, "mode %s ", link_modes[mode]); } -static char *parse_link_kind(struct rtattr *tb) +static char *parse_link_kind(struct rtattr *tb, bool slave) { struct rtattr *linkinfo[IFLA_INFO_MAX+1]; + int attr = slave ? IFLA_INFO_SLAVE_KIND : IFLA_INFO_KIND; parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb); - if (linkinfo[IFLA_INFO_KIND]) - return RTA_DATA(linkinfo[IFLA_INFO_KIND]); + if (linkinfo[attr]) + return RTA_DATA(linkinfo[attr]); return ""; } +static int match_link_kind(struct rtattr **tb, char *kind, bool slave) +{ + if (!tb[IFLA_LINKINFO]) + return -1; + + return strcmp(parse_link_kind(tb[IFLA_LINKINFO], slave), kind); +} + static void print_linktype(FILE *fp, struct rtattr *tb) { struct rtattr *linkinfo[IFLA_INFO_MAX+1]; @@ -680,16 +690,11 @@ int print_linkinfo_brief(const struct sockaddr_nl *who, } else if (filter.master > 0) return -1; - if (filter.kind) { - if (tb[IFLA_LINKINFO]) { - char *kind = parse_link_kind(tb[IFLA_LINKINFO]); + if (filter.kind && match_link_kind(tb, filter.kind, 0)) + return -1; - if (strcmp(kind, filter.kind)) - return -1; - } else { - return -1; - } - } + if (filter.slave_kind && match_link_kind(tb, filter.slave_kind, 1)) + return -1; if (n->nlmsg_type == RTM_DELLINK) fprintf(fp, "Deleted "); @@ -781,16 +786,11 @@ int print_linkinfo(const struct sockaddr_nl *who, } else if (filter.master > 0) return -1; - if (filter.kind) { - if (tb[IFLA_LINKINFO]) { - char *kind = parse_link_kind(tb[IFLA_LINKINFO]); + if (filter.kind && match_link_kind(tb, filter.kind, 0)) + return -1; - if (strcmp(kind, filter.kind)) - return -1; - } else { - return -1; - } - } + if (filter.slave_kind && match_link_kind(tb, filter.slave_kind, 1)) + return -1; if (n->nlmsg_type == RTM_DELLINK) fprintf(fp, "Deleted "); @@ -1621,8 +1621,16 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) invarg("Device does not exist\n", *argv); filter.master = ifindex; } else if (strcmp(*argv, "type") == 0) { + int soff; + NEXT_ARG(); - filter.kind = *argv; + soff = strlen(*argv) - strlen("_slave"); + if (!strcmp(*argv + soff, "_slave")) { + (*argv)[soff] = '\0'; + filter.slave_kind = *argv; + } else { + filter.kind = *argv; + } } else { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); From 577cfe0b677e509c2614c5b67fd9a25a6e432af2 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 28 Jun 2016 15:07:17 +0200 Subject: [PATCH 298/513] ip-address: Align type list in help and man page This adds missing entries on both sides until they are identical. Signed-off-by: Phil Sutter --- ip/ipaddress.c | 6 +++--- man/man8/ip-address.8.in | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 56f68eb21..d4d649505 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -95,9 +95,9 @@ static void usage(void) fprintf(stderr, "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n"); fprintf(stderr, "LFT := forever | SECONDS\n"); fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"); - fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n"); - fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n"); - fprintf(stderr, " bond_slave | ipvlan | geneve | bridge_slave | vrf }\n"); + fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | lowpan |\n"); + fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon | can |\n"); + fprintf(stderr, " bond_slave | ipvlan | geneve | bridge_slave | vrf | hsr}\n"); exit(-1); } diff --git a/man/man8/ip-address.8.in b/man/man8/ip-address.8.in index 8d34adb33..3cbe4181f 100644 --- a/man/man8/ip-address.8.in +++ b/man/man8/ip-address.8.in @@ -98,7 +98,9 @@ ip-address \- protocol address management .ti -8 .IR TYPE " := [ " .BR bridge " | " +.BR bridge_slave " |" .BR bond " | " +.BR bond_slave " |" .BR can " | " .BR dummy " | " .BR hsr " | " @@ -118,6 +120,7 @@ ip-address \- protocol address management .BR ip6gre " |" .BR ip6gretap " |" .BR vti " |" +.BR vrf " |" .BR nlmon " |" .BR ipvlan " |" .BR lowpan " |" From eecc006952d6f3992b632974d0f04f995d2a176e Mon Sep 17 00:00:00 2001 From: Andrew Vagin Date: Wed, 29 Jun 2016 02:27:14 +0300 Subject: [PATCH 299/513] ip route: timeout for routes has to be set in seconds Currently a timeout is multiplied by HZ in user-space and then it multiplied by HZ in kernel-space. $ ./ip/ip r add 2002::0/64 dev veth1 expires 10 $ ./ip/ip -6 r 2002::/64 dev veth1 metric 1024 linkdown expires 996sec pref medium Cc: Xin Long Cc: Hangbin Liu Cc: Stephen Hemminger Fixes: 68eede250500 ("route: allow routes to be configured with expire values") Signed-off-by: Andrew Vagin --- ip/iproute.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ip/iproute.c b/ip/iproute.c index 8224d7ffa..7c0f5a4fa 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -839,7 +839,6 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv) int table_ok = 0; int raw = 0; int type_ok = 0; - static int hz; memset(&req, 0, sizeof(req)); @@ -923,9 +922,7 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv) NEXT_ARG(); if (get_u32(&expires, *argv, 0)) invarg("\"expires\" value is invalid\n", *argv); - if (!hz) - hz = get_user_hz(); - addattr32(&req.n, sizeof(req), RTA_EXPIRES, expires*hz); + addattr32(&req.n, sizeof(req), RTA_EXPIRES, expires); } else if (matches(*argv, "metric") == 0 || matches(*argv, "priority") == 0 || strcmp(*argv, "preference") == 0) { From 400b5404af35f58f501780663693886d37c2061e Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 29 Jun 2016 15:26:10 -0400 Subject: [PATCH 300/513] bridge: man: fix BPUD typo s/BPUD/BPDU/ in guard description. Signed-off-by: Vivien Didelot --- man/man8/bridge.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index ac42118e7..a30ed0b30 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -256,7 +256,7 @@ STP BPDUs. .TP .BR "guard on " or " guard off " -Controls whether STP BPUDs will be processed by the bridge port. By default, +Controls whether STP BPDUs will be processed by the bridge port. By default, the flag is turned off allowed BPDU processing. Turning this flag on will cause the port to stop processing STP BPDUs. From 3aa8f8cb7af952bd09efb7ec6d4f3f0507ada16a Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 29 Jun 2016 15:26:29 -0400 Subject: [PATCH 301/513] bridge: man: fix STP LISTENING description Correct the unclear and poorly conjugated STP LISTENING documentation. Signed-off-by: Vivien Didelot --- man/man8/bridge.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index a30ed0b30..ef4f83ee7 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -235,7 +235,7 @@ error. .B 1 - STP LISTENING state. Only valid if STP is enabled on the bridge. In this -state the port for list for STP BPDUs and drop all other traffic. +state the port listens for STP BPDUs and drops all other traffic frames. .sp .B 2 From fab3e001fde511db507ba8c6fc4d1620ac9ced65 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Tue, 5 Jul 2016 18:08:50 +0900 Subject: [PATCH 302/513] man: rtacct: add missing TP marker Signed-off-by: Masatake YAMATO --- man/man8/rtacct.8 | 1 + 1 file changed, 1 insertion(+) diff --git a/man/man8/rtacct.8 b/man/man8/rtacct.8 index 7cf97aa45..01321e6db 100644 --- a/man/man8/rtacct.8 +++ b/man/man8/rtacct.8 @@ -35,6 +35,7 @@ Dump absolute values of counters. The default is to calculate increments since t .TP .B \-s, \-\-noupdate Do not update history, so that the next time you will see counters including values accumulated to the moment of this measurement too. +.TP .B \-j, \-\-json Display results in JSON format. .TP From 509dcd43c91abf834721ca6f92b6617fde36ed41 Mon Sep 17 00:00:00 2001 From: Michal Soltys Date: Sat, 2 Jul 2016 13:03:12 +0200 Subject: [PATCH 303/513] iproute2: unmangle netdev/my emails in man pages (hfsc, stab) No other man pages do so, hiding netdev is kind of silly and I don't mind having my own address normally visible. --- man/man7/tc-hfsc.7 | 4 ++-- man/man8/tc-hfsc.8 | 4 ++-- man/man8/tc-stab.8 | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/man/man7/tc-hfsc.7 b/man/man7/tc-hfsc.7 index ca049619b..5ae5e6b3f 100644 --- a/man/man7/tc-hfsc.7 +++ b/man/man7/tc-hfsc.7 @@ -555,8 +555,8 @@ Please refer to \fBtc\-stab\fR(8) . \fBtc\fR(8), \fBtc\-hfsc\fR(8), \fBtc\-stab\fR(8) -Please direct bugreports and patches to: +Please direct bugreports and patches to: . .SH "AUTHOR" . -Manpage created by Michal Soltys (sol...@ziu.info) +Manpage created by Michal Soltys (soltys@ziu.info) diff --git a/man/man8/tc-hfsc.8 b/man/man8/tc-hfsc.8 index 5444118e2..fd0df8ff2 100644 --- a/man/man8/tc-hfsc.8 +++ b/man/man8/tc-hfsc.8 @@ -54,8 +54,8 @@ parameters, you will specify linear service curve. . \fBtc\fR(8), \fBtc\-hfsc\fR(7), \fBtc\-stab\fR(8) -Please direct bugreports and patches to: +Please direct bugreports and patches to: . .SH "AUTHOR" . -Manpage created by Michal Soltys (sol...@ziu.info) +Manpage created by Michal Soltys (soltys@ziu.info) diff --git a/man/man8/tc-stab.8 b/man/man8/tc-stab.8 index 02caa7dff..03a0659b9 100644 --- a/man/man8/tc-stab.8 +++ b/man/man8/tc-stab.8 @@ -156,8 +156,8 @@ it's good to use \fBethtool\fR to turn off offloading features. .br \fB[2]\fR http://www.faqs.org/rfcs/rfc2684.html -Please direct bugreports and patches to: +Please direct bugreports and patches to: . .SH "AUTHOR" . -Manpage created by Michal Soltys (sol...@ziu.info) +Manpage created by Michal Soltys (soltys@ziu.info) From 03ac85b708168c57ce6ec32dfa5aa850fbf2c4ee Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 30 Jun 2016 16:47:02 +0200 Subject: [PATCH 304/513] ip-address: constify match_link_kind arg Since the function won't ever change the data 'kind' is pointing at, it can sanely be made const. Fixes: e0513807f6dbb ("ip-address: Support filtering by slave type, too") Suggested-by: Stephen Hemminger Signed-off-by: Phil Sutter --- ip/ipaddress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index d4d649505..02bc9029d 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -220,7 +220,7 @@ static char *parse_link_kind(struct rtattr *tb, bool slave) return ""; } -static int match_link_kind(struct rtattr **tb, char *kind, bool slave) +static int match_link_kind(struct rtattr **tb, const char *kind, bool slave) { if (!tb[IFLA_LINKINFO]) return -1; From 4824bb4151e8595913f43860a50735961bff3b75 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 6 Jul 2016 21:14:57 -0700 Subject: [PATCH 305/513] update kernel header (4.7 net-next) --- include/linux/bpf.h | 46 ++++++++++++++++++++++++++++++- include/linux/devlink.h | 8 ++++++ include/linux/if_bridge.h | 26 +++++++++++++++++ include/linux/if_link.h | 2 ++ include/linux/inet_diag.h | 1 + include/linux/tc_act/tc_skbedit.h | 2 ++ include/linux/tcp.h | 10 +++++++ 7 files changed, 94 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 5e4d3739a..3aa778d34 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -84,6 +84,7 @@ enum bpf_map_type { BPF_MAP_TYPE_PERCPU_HASH, BPF_MAP_TYPE_PERCPU_ARRAY, BPF_MAP_TYPE_STACK_TRACE, + BPF_MAP_TYPE_CGROUP_ARRAY, }; enum bpf_prog_type { @@ -313,6 +314,49 @@ enum bpf_func_id { */ BPF_FUNC_skb_get_tunnel_opt, BPF_FUNC_skb_set_tunnel_opt, + + /** + * bpf_skb_change_proto(skb, proto, flags) + * Change protocol of the skb. Currently supported is + * v4 -> v6, v6 -> v4 transitions. The helper will also + * resize the skb. eBPF program is expected to fill the + * new headers via skb_store_bytes and lX_csum_replace. + * @skb: pointer to skb + * @proto: new skb->protocol type + * @flags: reserved + * Return: 0 on success or negative error + */ + BPF_FUNC_skb_change_proto, + + /** + * bpf_skb_change_type(skb, type) + * Change packet type of skb. + * @skb: pointer to skb + * @type: new skb->pkt_type type + * Return: 0 on success or negative error + */ + BPF_FUNC_skb_change_type, + + /** + * bpf_skb_in_cgroup(skb, map, index) - Check cgroup2 membership of skb + * @skb: pointer to skb + * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type + * @index: index of the cgroup in the bpf_map + * Return: + * == 0 skb failed the cgroup2 descendant test + * == 1 skb succeeded the cgroup2 descendant test + * < 0 error + */ + BPF_FUNC_skb_in_cgroup, + + /** + * bpf_get_hash_recalc(skb) + * Retrieve and possibly recalculate skb->hash. + * @skb: pointer to skb + * Return: hash + */ + BPF_FUNC_get_hash_recalc, + __BPF_FUNC_MAX_ID, }; @@ -347,7 +391,7 @@ enum bpf_func_id { #define BPF_F_ZERO_CSUM_TX (1ULL << 1) #define BPF_F_DONT_FRAGMENT (1ULL << 2) -/* BPF_FUNC_perf_event_output flags. */ +/* BPF_FUNC_perf_event_output and BPF_FUNC_perf_event_read flags. */ #define BPF_F_INDEX_MASK 0xffffffffULL #define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK diff --git a/include/linux/devlink.h b/include/linux/devlink.h index 0e21d001f..b7c1a0697 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -57,6 +57,8 @@ enum devlink_command { DEVLINK_CMD_SB_OCC_SNAPSHOT, DEVLINK_CMD_SB_OCC_MAX_CLEAR, + DEVLINK_CMD_ESWITCH_MODE_GET, + DEVLINK_CMD_ESWITCH_MODE_SET, /* add new commands above here */ __DEVLINK_CMD_MAX, @@ -95,6 +97,11 @@ enum devlink_sb_threshold_type { #define DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX 20 +enum devlink_eswitch_mode { + DEVLINK_ESWITCH_MODE_LEGACY, + DEVLINK_ESWITCH_MODE_SWITCHDEV, +}; + enum devlink_attr { /* don't change the order or add anything between, this is ABI! */ DEVLINK_ATTR_UNSPEC, @@ -125,6 +132,7 @@ enum devlink_attr { DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ DEVLINK_ATTR_SB_OCC_CUR, /* u32 */ DEVLINK_ATTR_SB_OCC_MAX, /* u32 */ + DEVLINK_ATTR_ESWITCH_MODE, /* u16 */ /* add new attributes above here, update the policy in devlink.c */ diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index fc3dcfa46..61e19ffee 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -247,8 +247,34 @@ enum { enum { BRIDGE_XSTATS_UNSPEC, BRIDGE_XSTATS_VLAN, + BRIDGE_XSTATS_MCAST, + BRIDGE_XSTATS_PAD, __BRIDGE_XSTATS_MAX }; #define BRIDGE_XSTATS_MAX (__BRIDGE_XSTATS_MAX - 1) +enum { + BR_MCAST_DIR_RX, + BR_MCAST_DIR_TX, + BR_MCAST_DIR_SIZE +}; + +/* IGMP/MLD statistics */ +struct br_mcast_stats { + __u64 igmp_queries[BR_MCAST_DIR_SIZE]; + __u64 igmp_leaves[BR_MCAST_DIR_SIZE]; + __u64 igmp_v1reports[BR_MCAST_DIR_SIZE]; + __u64 igmp_v2reports[BR_MCAST_DIR_SIZE]; + __u64 igmp_v3reports[BR_MCAST_DIR_SIZE]; + __u64 igmp_parse_errors; + + __u64 mld_queries[BR_MCAST_DIR_SIZE]; + __u64 mld_leaves[BR_MCAST_DIR_SIZE]; + __u64 mld_v1reports[BR_MCAST_DIR_SIZE]; + __u64 mld_v2reports[BR_MCAST_DIR_SIZE]; + __u64 mld_parse_errors; + + __u64 mcast_bytes[BR_MCAST_DIR_SIZE]; + __u64 mcast_packets[BR_MCAST_DIR_SIZE]; +}; #endif /* _LINUX_IF_BRIDGE_H */ diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 15bbeb818..af0b2d8a2 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -271,6 +271,7 @@ enum { IFLA_BR_VLAN_DEFAULT_PVID, IFLA_BR_PAD, IFLA_BR_VLAN_STATS_ENABLED, + IFLA_BR_MCAST_STATS_ENABLED, __IFLA_BR_MAX, }; @@ -820,6 +821,7 @@ enum { IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */ IFLA_STATS_LINK_64, IFLA_STATS_LINK_XSTATS, + IFLA_STATS_LINK_XSTATS_SLAVE, __IFLA_STATS_MAX, }; diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index 07e486cb2..beb74ee1f 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -72,6 +72,7 @@ enum { INET_DIAG_BC_AUTO, INET_DIAG_BC_S_COND, INET_DIAG_BC_D_COND, + INET_DIAG_BC_DEV_COND, /* u32 ifindex */ }; struct inet_diag_hostcond { diff --git a/include/linux/tc_act/tc_skbedit.h b/include/linux/tc_act/tc_skbedit.h index fecb5cc48..a4d00c608 100644 --- a/include/linux/tc_act/tc_skbedit.h +++ b/include/linux/tc_act/tc_skbedit.h @@ -27,6 +27,7 @@ #define SKBEDIT_F_PRIORITY 0x1 #define SKBEDIT_F_QUEUE_MAPPING 0x2 #define SKBEDIT_F_MARK 0x4 +#define SKBEDIT_F_PTYPE 0x8 struct tc_skbedit { tc_gen; @@ -40,6 +41,7 @@ enum { TCA_SKBEDIT_QUEUE_MAPPING, TCA_SKBEDIT_MARK, TCA_SKBEDIT_PAD, + TCA_SKBEDIT_PTYPE, __TCA_SKBEDIT_MAX }; #define TCA_SKBEDIT_MAX (__TCA_SKBEDIT_MAX - 1) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 7f21db9b5..f3dcdb777 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -115,12 +115,22 @@ enum { #define TCP_CC_INFO 26 /* Get Congestion Control (optional) info */ #define TCP_SAVE_SYN 27 /* Record SYN headers for new connections */ #define TCP_SAVED_SYN 28 /* Get SYN headers recorded for connection */ +#define TCP_REPAIR_WINDOW 29 /* Get/set window parameters */ struct tcp_repair_opt { __u32 opt_code; __u32 opt_val; }; +struct tcp_repair_window { + __u32 snd_wl1; + __u32 snd_wnd; + __u32 max_window; + + __u32 rcv_wnd; + __u32 rcv_wup; +}; + enum { TCP_NO_QUEUE, TCP_RECV_QUEUE, From 1d1e0fd29b66ab2da25dcb892275430fcb427ce2 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sat, 2 Jul 2016 07:14:33 -0400 Subject: [PATCH 306/513] actions: skbedit add support for mod-ing skb pkt_type I'll make a formal submission sans the header when the kernel patches makes it in. This version is for someone who wants to play around with the net-next kernel patches i sent Signed-off-by: Jamal Hadi Salim --- man/man8/tc-skbedit.8 | 9 ++++++++ tc/m_skbedit.c | 50 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/man/man8/tc-skbedit.8 b/man/man8/tc-skbedit.8 index e6902960e..003f05c93 100644 --- a/man/man8/tc-skbedit.8 +++ b/man/man8/tc-skbedit.8 @@ -11,6 +11,8 @@ skbedit - SKB editing action .IR PRIORITY " ] [" .B mark .IR MARK " ]" +.B ptype +.IR PTYPE " ]" .SH DESCRIPTION The .B skbedit @@ -52,6 +54,13 @@ Change the packet's firewall mark value. is an unsigned 32bit value in automatically detected format (i.e., prefix with .RB ' 0x ' for hexadecimal interpretation, etc.). +.TP +.BI ptype " PTYPE" +Override the packet's type. Useful for setting packet type to host when +needing to allow ingressing packets with the wrong MAC address but +correct IP address. +.I PTYPE +is one of: host, otherhost, broadcast, multicast .SH SEE ALSO .BR tc (8), .BR tc-pedit (8) diff --git a/tc/m_skbedit.c b/tc/m_skbedit.c index 9ba288c07..4f6c2b45b 100644 --- a/tc/m_skbedit.c +++ b/tc/m_skbedit.c @@ -26,14 +26,17 @@ #include "utils.h" #include "tc_util.h" #include +#include -static void -explain(void) +static void explain(void) { - fprintf(stderr, "Usage: ... skbedit <[QM] [PM] [MM]>\n" + fprintf(stderr, "Usage: ... skbedit <[QM] [PM] [MM] [PT]>\n" "QM = queue_mapping QUEUE_MAPPING\n" "PM = priority PRIORITY\n" "MM = mark MARK\n" + "PT = ptype PACKETYPE\n" + "PACKETYPE = is one of:\n" + " host, otherhost, broadcast, multicast\n" "QUEUE_MAPPING = device transmit queue to use\n" "PRIORITY = classID to assign to priority field\n" "MARK = firewall mark to set\n"); @@ -55,7 +58,7 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, int ok = 0; struct rtattr *tail; unsigned int tmp; - __u16 queue_mapping; + __u16 queue_mapping, ptype; __u32 flags = 0, priority, mark; struct tc_skbedit sel = { 0 }; @@ -90,6 +93,24 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, return -1; } ok++; + } else if (matches(*argv, "ptype") == 0) { + + NEXT_ARG(); + if (matches(*argv, "host") == 0) { + ptype = PACKET_HOST; + } else if (matches(*argv, "broadcast") == 0) { + ptype = PACKET_BROADCAST; + } else if (matches(*argv, "multicast") == 0) { + ptype = PACKET_MULTICAST; + } else if (matches(*argv, "otherhost") == 0) { + ptype = PACKET_OTHERHOST; + } else { + fprintf(stderr, "Illegal ptype (%s)\n", + *argv); + return -1; + } + flags |= SKBEDIT_F_PTYPE; + ok++; } else if (matches(*argv, "help") == 0) { usage(); } else { @@ -152,6 +173,9 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, if (flags & SKBEDIT_F_MARK) addattr_l(n, MAX_MSG, TCA_SKBEDIT_MARK, &mark, sizeof(mark)); + if (flags & SKBEDIT_F_PTYPE) + addattr_l(n, MAX_MSG, TCA_SKBEDIT_PTYPE, + &ptype, sizeof(ptype)); tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; *argc_p = argc; @@ -166,7 +190,7 @@ static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg) SPRINT_BUF(b1); __u32 *priority; __u32 *mark; - __u16 *queue_mapping; + __u16 *queue_mapping, *ptype; struct tc_skbedit *p = NULL; if (arg == NULL) @@ -194,8 +218,22 @@ static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg) mark = RTA_DATA(tb[TCA_SKBEDIT_MARK]); fprintf(f, " mark %d", *mark); } + if (tb[TCA_SKBEDIT_PTYPE] != NULL) { + ptype = RTA_DATA(tb[TCA_SKBEDIT_PTYPE]); + if (*ptype == PACKET_HOST) + fprintf(f, " ptype host"); + else if (*ptype == PACKET_BROADCAST) + fprintf(f, " ptype broadcast"); + else if (*ptype == PACKET_MULTICAST) + fprintf(f, " ptype multicast"); + else if (*ptype == PACKET_OTHERHOST) + fprintf(f, " ptype otherhost"); + else + fprintf(f, " ptype %d", *ptype); + } - fprintf(f, "\n\t index %d ref %d bind %d", p->index, p->refcnt, p->bindcnt); + fprintf(f, "\n\t index %d ref %d bind %d", + p->index, p->refcnt, p->bindcnt); if (show_stats) { if (tb[TCA_SKBEDIT_TM]) { From cfcabf18d84a2f4908cb5b4489f67c2cd3f70426 Mon Sep 17 00:00:00 2001 From: Amir Vadai Date: Mon, 4 Jul 2016 10:34:11 +0300 Subject: [PATCH 307/513] tc: flower: Add skip_{hw|sw} support On devices that support TC flower offloads, these flags enable a filter to be added only to HW or only to SW. skip_sw and skip_hw are mutually exclusive flags. By default without any flags, the filter is added to both HW and SW, but no error checks are done in case of failure to add to HW. With skip-sw, failure to add to HW is treated as an error. Here is a sample script that adds 2 filters, one with skip_sw and the other with skip_hw flag. # add ingress qdisc tc qdisc add dev enp0s9 ingress # enable hw tc offload. ethtool -K enp0s9 hw-tc-offload on # add a flower filter with skip-sw flag. tc filter add dev enp0s9 protocol ip parent ffff: flower \ ip_proto 1 indev enp0s9 skip_sw \ action drop # add a flower filter with skip-hw flag. tc filter add dev enp0s9 protocol ip parent ffff: flower \ ip_proto 3 indev enp0s9 skip_hw \ action drop Signed-off-by: Amir Vadai Acked-by: Jiri Pirko --- man/man8/tc-flower.8 | 11 ++++++++++- tc/f_flower.c | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8 index df4d8e197..9ae10e6f8 100644 --- a/man/man8/tc-flower.8 +++ b/man/man8/tc-flower.8 @@ -18,7 +18,9 @@ flower \- flow based traffic control filter .ti -8 .IR MATCH " := { " .B indev -.IR ifname " | { " +.IR ifname " | " +.BR skip_sw " | " skip_hw +.R " | { " .BR dst_mac " | " src_mac " } " .IR mac_address " | " .BR eth_type " { " ipv4 " | " ipv6 " | " @@ -55,6 +57,13 @@ is the name of an interface which must exist at the time of .B tc invocation. .TP +.BI skip_sw +Do not process filter by software. If hardware has no offload support for this +filter, or TC offload is not enabled for the interface, operation will fail. +.TP +.BI skip_hw +Do not process filter by hardware. +.TP .BI dst_mac " mac_address" .TQ .BI src_mac " mac_address" diff --git a/tc/f_flower.c b/tc/f_flower.c index fd2014b37..7b46ceb14 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -25,6 +25,7 @@ static void explain(void) { fprintf(stderr, "Usage: ... flower [ MATCH-LIST ]\n"); + fprintf(stderr, " [ skip_sw | skip_hw ]\n"); fprintf(stderr, " [ action ACTION-SPEC ] [ classid CLASSID ]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n"); @@ -167,6 +168,7 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, struct rtattr *tail; __be16 eth_type = TC_H_MIN(t->tcm_info); __u8 ip_proto = 0xff; + __u32 flags = 0; if (handle) { ret = get_u32(&t->tcm_handle, handle, 0); @@ -196,6 +198,10 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, return -1; } addattr_l(n, MAX_MSG, TCA_FLOWER_CLASSID, &handle, 4); + } else if (matches(*argv, "skip_hw") == 0) { + flags |= TCA_CLS_FLAGS_SKIP_HW; + } else if (matches(*argv, "skip_sw") == 0) { + flags |= TCA_CLS_FLAGS_SKIP_SW; } else if (matches(*argv, "indev") == 0) { char ifname[IFNAMSIZ]; @@ -294,6 +300,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, } parse_done: + addattr32(n, MAX_MSG, TCA_FLOWER_FLAGS, flags); + ret = addattr16(n, MAX_MSG, TCA_FLOWER_KEY_ETH_TYPE, eth_type); if (ret) { fprintf(stderr, "Illegal \"eth_type\"(0x%x)\n", @@ -498,6 +506,15 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, tb[TCA_FLOWER_KEY_TCP_SRC], tb[TCA_FLOWER_KEY_UDP_SRC]); + 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"); + if (flags & TCA_CLS_FLAGS_SKIP_SW) + fprintf(f, "\n skip_sw"); + } + if (tb[TCA_FLOWER_ACT]) { tc_print_action(f, tb[TCA_FLOWER_ACT]); } From 7dc0e974f16b5dd827d1ceb4323376012490a608 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 29 Jun 2016 11:26:57 -0700 Subject: [PATCH 308/513] ip vrf: Add name_is_vrf Add name_is_vrf function to determine if given name corresponds to a VRF device. Signed-off-by: David Ahern --- ip/ip_common.h | 2 ++ ip/iplink_vrf.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/ip/ip_common.h b/ip/ip_common.h index e8da9e034..b747ea471 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -90,6 +90,8 @@ struct link_util *get_link_slave_kind(const char *slave_kind); void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len); +bool name_is_vrf(const char *name); + #ifndef INFINITY_LIFE_TIME #define INFINITY_LIFE_TIME 0xFFFFFFFFU #endif diff --git a/ip/iplink_vrf.c b/ip/iplink_vrf.c index e3c7b4652..166f566e6 100644 --- a/ip/iplink_vrf.c +++ b/ip/iplink_vrf.c @@ -96,3 +96,53 @@ struct link_util vrf_slave_link_util = { .print_opt = vrf_slave_print_opt, .slave = true, }; + +bool name_is_vrf(const char *name) +{ + struct { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; + } req = { + .n = { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .nlmsg_flags = NLM_F_REQUEST, + .nlmsg_type = RTM_GETLINK, + }, + .i = { + .ifi_family = preferred_family, + }, + }; + struct { + struct nlmsghdr n; + char buf[8192]; + } answer; + struct rtattr *tb[IFLA_MAX+1]; + struct rtattr *li[IFLA_INFO_MAX+1]; + struct ifinfomsg *ifi; + int len; + + addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, strlen(name) + 1); + + if (rtnl_talk(&rth, &req.n, &answer.n, sizeof(answer)) < 0) + return false; + + ifi = NLMSG_DATA(&answer.n); + len = answer.n.nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)); + if (len < 0) { + fprintf(stderr, "BUG: Invalid response to link query.\n"); + return false; + } + + parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); + + if (!tb[IFLA_LINKINFO]) + return false; + + parse_rtattr_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); + + if (!li[IFLA_INFO_KIND]) + return false; + + return strcmp(RTA_DATA(li[IFLA_INFO_KIND]), "vrf") == 0; +} From 104444c2019a60671683da5ccfb6273e8238b050 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 29 Jun 2016 11:26:58 -0700 Subject: [PATCH 309/513] ip link/addr: Add support for vrf keyword Add vrf keyword to 'ip link' and 'ip addr' commands (common list code). Allows: 1. Adding a link to a VRF $ ip link set NAME vrf NAME Removing a link from a VRF still uses 'ip link set NAME nomaster' 2. Showing links associated with a VRF: $ ip link show vrf NAME 3. List addresses associated with links in a VRF $ ip -br addr show vrf red Signed-off-by: David Ahern --- ip/ipaddress.c | 12 +++++++++++- ip/iplink.c | 15 +++++++++++++-- man/man8/ip-address.8.in | 6 ++++++ man/man8/ip-link.8.in | 10 ++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 02bc9029d..88e966222 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -80,7 +80,7 @@ static void usage(void) fprintf(stderr, " [ to PREFIX ] [ FLAG-LIST ] [ label LABEL ] [up]\n"); fprintf(stderr, " ip address [ show [ dev IFNAME ] [ scope SCOPE-ID ] [ master DEVICE ]\n"); fprintf(stderr, " [ type TYPE ] [ to PREFIX ] [ FLAG-LIST ]\n"); - fprintf(stderr, " [ label LABEL ] [up] ]\n"); + fprintf(stderr, " [ label LABEL ] [up] [ vrf NAME ] ]\n"); fprintf(stderr, " ip address {showdump|restore}\n"); fprintf(stderr, "IFADDR := PREFIX | ADDR peer PREFIX\n"); fprintf(stderr, " [ broadcast ADDR ] [ anycast ADDR ]\n"); @@ -1620,6 +1620,16 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) if (!ifindex) invarg("Device does not exist\n", *argv); filter.master = ifindex; + } else if (strcmp(*argv, "vrf") == 0) { + int ifindex; + + NEXT_ARG(); + ifindex = ll_name_to_index(*argv); + if (!ifindex) + invarg("Not a valid VRF name\n", *argv); + if (!name_is_vrf(*argv)) + invarg("Not a valid VRF name\n", *argv); + filter.master = ifindex; } else if (strcmp(*argv, "type") == 0) { int soff; diff --git a/ip/iplink.c b/ip/iplink.c index b1f8a3792..f2a2e13cf 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -82,11 +82,11 @@ void iplink_usage(void) fprintf(stderr, " [ query_rss { on | off} ]\n"); fprintf(stderr, " [ state { auto | enable | disable} ] ]\n"); fprintf(stderr, " [ trust { on | off} ] ]\n"); - fprintf(stderr, " [ master DEVICE ]\n"); + fprintf(stderr, " [ master DEVICE ][ vrf NAME ]\n"); fprintf(stderr, " [ nomaster ]\n"); fprintf(stderr, " [ addrgenmode { eui64 | none | stable_secret | random } ]\n"); fprintf(stderr, " [ protodown { on | off } ]\n"); - fprintf(stderr, " ip link show [ DEVICE | group GROUP ] [up] [master DEV] [type TYPE]\n"); + fprintf(stderr, " ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n"); if (iplink_have_newlink()) { fprintf(stderr, " ip link help [ TYPE ]\n"); @@ -603,6 +603,17 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, invarg("Device does not exist\n", *argv); addattr_l(&req->n, sizeof(*req), IFLA_MASTER, &ifindex, 4); + } else if (strcmp(*argv, "vrf") == 0) { + int ifindex; + + NEXT_ARG(); + ifindex = ll_name_to_index(*argv); + if (!ifindex) + invarg("Not a valid VRF name\n", *argv); + if (!name_is_vrf(*argv)) + invarg("Not a valid VRF name\n", *argv); + addattr_l(&req->n, sizeof(*req), IFLA_MASTER, + &ifindex, sizeof(ifindex)); } else if (matches(*argv, "nomaster") == 0) { int ifindex = 0; diff --git a/man/man8/ip-address.8.in b/man/man8/ip-address.8.in index 3cbe4181f..7cb927173 100644 --- a/man/man8/ip-address.8.in +++ b/man/man8/ip-address.8.in @@ -45,6 +45,8 @@ ip-address \- protocol address management .IR DEVICE " ] [ " .B type .IR TYPE " ] [ " +.B vrf +.IR NAME " ] [ " .BR up " ] ]" .ti -8 @@ -279,6 +281,10 @@ is a usual shell style pattern. .BI master " DEVICE" only list interfaces enslaved to this master device. +.TP +.BI vrf " NAME " +only list interfaces enslaved to this vrf. + .TP .BI type " TYPE" only list interfaces of the given type. diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 375b4d081..ad18f7555 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -154,6 +154,9 @@ ip-link \- network device configuration .br .RB "[ " nomaster " ]" .br +.RB "[ " vrf +.IR NAME " ]" +.br .RB "[ " addrgenmode " { " eui64 " | " none " | " stable_secret " | " random " } ]" @@ -167,6 +170,8 @@ ip-link \- network device configuration .IR DEVICE " ] [" .B type .IR TYPE " ]" +.B vrf +.IR NAME " ]" .ti -8 .B ip link help @@ -1255,6 +1260,11 @@ only display running interfaces. .I DEVICE specifies the master device which enslaves devices to show. +.TP +.BI vrf " NAME " +.I NAME +speficies the VRF which enslaves devices to show. + .TP .BI type " TYPE " .I TYPE From 5db1adae2a8f73563f8a3945cbdf2945975fe3c2 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 29 Jun 2016 11:26:59 -0700 Subject: [PATCH 310/513] ip neigh: Add support for keyword Add vrf keyword to 'ip neigh' commands. Allows listing neighbor entries for all links associated with a given VRF. Signed-off-by: David Ahern --- ip/ipneigh.c | 14 +++++++++++++- man/man8/ip-neighbour.8 | 8 +++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/ip/ipneigh.c b/ip/ipneigh.c index 4ddb747e2..3e4447126 100644 --- a/ip/ipneigh.c +++ b/ip/ipneigh.c @@ -48,7 +48,8 @@ static void usage(void) { fprintf(stderr, "Usage: ip neigh { add | del | change | replace }\n" " { ADDR [ lladdr LLADDR ] [ nud STATE ] | proxy ADDR } [ dev DEV ]\n"); - fprintf(stderr, " ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n\n"); + fprintf(stderr, " ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n"); + fprintf(stderr, " [ vrf NAME ]\n\n"); fprintf(stderr, "STATE := { permanent | noarp | stale | reachable | none |\n" " incomplete | delay | probe | failed }\n"); exit(-1); @@ -385,6 +386,17 @@ static int do_show_or_flush(int argc, char **argv, int flush) invarg("Device does not exist\n", *argv); addattr32(&req.n, sizeof(req), NDA_MASTER, ifindex); filter.master = ifindex; + } else if (strcmp(*argv, "vrf") == 0) { + int ifindex; + + NEXT_ARG(); + ifindex = ll_name_to_index(*argv); + if (!ifindex) + invarg("Not a valid VRF name\n", *argv); + if (!name_is_vrf(*argv)) + invarg("Not a valid VRF name\n", *argv); + addattr32(&req.n, sizeof(req), NDA_MASTER, ifindex); + filter.master = ifindex; } else if (strcmp(*argv, "unused") == 0) { filter.unused_only = 1; } else if (strcmp(*argv, "nud") == 0) { diff --git a/man/man8/ip-neighbour.8 b/man/man8/ip-neighbour.8 index b292e1814..bbfe8e72a 100644 --- a/man/man8/ip-neighbour.8 +++ b/man/man8/ip-neighbour.8 @@ -31,7 +31,9 @@ ip-neighbour \- neighbour/arp tables management. .B dev .IR DEV " ] [ " .B nud -.IR STATE " ]" +.IR STATE " ] [ " +.B vrf +.IR NAME " ] " .ti -8 .IR STATE " := {" @@ -163,6 +165,10 @@ the prefix selecting the neighbours to list. .BI dev " NAME" only list the neighbours attached to this device. +.TP +.BI vrf " NAME" +only list the neighbours for given VRF. + .TP .BI proxy list neighbour proxies. From d84b1878eaae882e066b7d051eb6af13cf64152e Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 29 Jun 2016 11:27:00 -0700 Subject: [PATCH 311/513] ip route: Change type mask to bitmask Allow option to select multiple route types to show or exlude specific route types. Signed-off-by: David Ahern --- ip/iproute.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ip/iproute.c b/ip/iproute.c index 7c0f5a4fa..e785d401d 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -113,7 +113,7 @@ static struct int flushe; int protocol, protocolmask; int scope, scopemask; - int type, typemask; + __u64 typemask; int tos, tosmask; int iif, iifmask; int oif, oifmask; @@ -178,7 +178,8 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) return 0; if ((filter.scope^r->rtm_scope)&filter.scopemask) return 0; - if ((filter.type^r->rtm_type)&filter.typemask) + + if (filter.typemask && !(filter.typemask & (1 << r->rtm_type))) return 0; if ((filter.tos^r->rtm_tos)&filter.tosmask) return 0; @@ -365,7 +366,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (n->nlmsg_type == RTM_DELROUTE) fprintf(fp, "Deleted "); - if ((r->rtm_type != RTN_UNICAST || show_details > 0) && !filter.type) + if ((r->rtm_type != RTN_UNICAST || show_details > 0) && + (!filter.typemask || (filter.typemask & (1 << r->rtm_type)))) fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); if (tb[RTA_DST]) { @@ -1430,10 +1432,9 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) int type; NEXT_ARG(); - filter.typemask = -1; if (rtnl_rtntype_a2n(&type, *argv)) invarg("node type value is invalid\n", *argv); - filter.type = type; + filter.typemask = (1< Date: Wed, 29 Jun 2016 11:27:01 -0700 Subject: [PATCH 312/513] ip vrf: Add ipvrf_get_table Add ipvrf_get_table to lookup table id for device name. Returns 0 on any error or if name is not a VRF device. Signed-off-by: David Ahern --- ip/ip_common.h | 1 + ip/iplink_vrf.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/ip/ip_common.h b/ip/ip_common.h index b747ea471..c8188122a 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -90,6 +90,7 @@ struct link_util *get_link_slave_kind(const char *slave_kind); void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len); +__u32 ipvrf_get_table(const char *name); bool name_is_vrf(const char *name); #ifndef INFINITY_LIFE_TIME diff --git a/ip/iplink_vrf.c b/ip/iplink_vrf.c index 166f566e6..015b41e1e 100644 --- a/ip/iplink_vrf.c +++ b/ip/iplink_vrf.c @@ -97,6 +97,69 @@ struct link_util vrf_slave_link_util = { .slave = true, }; +/* returns table id if name is a VRF device */ +__u32 ipvrf_get_table(const char *name) +{ + struct { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; + } req = { + .n = { + .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .nlmsg_flags = NLM_F_REQUEST, + .nlmsg_type = RTM_GETLINK, + }, + .i = { + .ifi_family = preferred_family, + }, + }; + struct { + struct nlmsghdr n; + char buf[8192]; + } answer; + struct rtattr *tb[IFLA_MAX+1]; + struct rtattr *li[IFLA_INFO_MAX+1]; + struct rtattr *vrf_attr[IFLA_VRF_MAX + 1]; + struct ifinfomsg *ifi; + __u32 tb_id = 0; + int len; + + addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, strlen(name) + 1); + + if (rtnl_talk(&rth, &req.n, &answer.n, sizeof(answer)) < 0) + return 0; + + ifi = NLMSG_DATA(&answer.n); + len = answer.n.nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)); + if (len < 0) { + fprintf(stderr, "BUG: Invalid response to link query.\n"); + return 0; + } + + parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); + + if (!tb[IFLA_LINKINFO]) + return 0; + + parse_rtattr_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); + + if (!li[IFLA_INFO_KIND] || !li[IFLA_INFO_DATA]) + return 0; + + if (strcmp(RTA_DATA(li[IFLA_INFO_KIND]), "vrf")) + return 0; + + parse_rtattr_nested(vrf_attr, IFLA_VRF_MAX, li[IFLA_INFO_DATA]); + if (vrf_attr[IFLA_VRF_TABLE]) + tb_id = rta_getattr_u32(vrf_attr[IFLA_VRF_TABLE]); + + if (!tb_id) + fprintf(stderr, "BUG: VRF %s is missing table id\n", name); + + return tb_id; +} + bool name_is_vrf(const char *name) { struct { From 0130f0120b84870ca1d31f9e215793594c98a38b Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 29 Jun 2016 11:27:02 -0700 Subject: [PATCH 313/513] ip route: Add support for vrf keyword Add vrf keyword to 'ip route' commands. Allows: 1. Users can list routes by VRF name: $ ip route show vrf NAME VRF tables have all routes including local and broadcast routes. The VRF keyword filters LOCAL and BROADCAST routes; to see all routes the table option can be used. Or to see local routes only for a VRF: $ ip route show vrf NAME type local 2. Add or delete a route for a VRF: $ ip route {add|delete} vrf NAME 3. Do a route lookup for a VRF: $ ip route get vrf NAME ADDRESS Signed-off-by: David Ahern --- ip/iproute.c | 32 ++++++++++++++++++++++++++++++-- man/man8/ip-route.8.in | 19 ++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/ip/iproute.c b/ip/iproute.c index e785d401d..24f6b0101 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -67,10 +67,10 @@ static void usage(void) fprintf(stderr, " ip route showdump\n"); fprintf(stderr, " ip route get ADDRESS [ from ADDRESS iif STRING ]\n"); fprintf(stderr, " [ oif STRING ] [ tos TOS ]\n"); - fprintf(stderr, " [ mark NUMBER ]\n"); + fprintf(stderr, " [ mark NUMBER ] [ vrf NAME ]\n"); fprintf(stderr, " ip route { add | del | change | append | replace } ROUTE\n"); fprintf(stderr, "SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ]\n"); - fprintf(stderr, " [ table TABLE_ID ] [ proto RTPROTO ]\n"); + fprintf(stderr, " [ table TABLE_ID ] [ vrf NAME ] [ proto RTPROTO ]\n"); fprintf(stderr, " [ type TYPE ] [ scope SCOPE ]\n"); fprintf(stderr, "ROUTE := NODE_SPEC [ INFO_SPEC ]\n"); fprintf(stderr, "NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ]\n"); @@ -1138,6 +1138,20 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv) addattr32(&req.n, sizeof(req), RTA_TABLE, tid); } table_ok = 1; + } else if (matches(*argv, "vrf") == 0) { + __u32 tid; + + NEXT_ARG(); + tid = ipvrf_get_table(*argv); + if (tid == 0) + invarg("Invalid VRF\n", *argv); + if (tid < 256) + req.r.rtm_table = tid; + else { + req.r.rtm_table = RT_TABLE_UNSPEC; + addattr32(&req.n, sizeof(req), RTA_TABLE, tid); + } + table_ok = 1; } else if (strcmp(*argv, "dev") == 0 || strcmp(*argv, "oif") == 0) { NEXT_ARG(); @@ -1392,6 +1406,15 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action) } } else filter.tb = tid; + } else if (matches(*argv, "vrf") == 0) { + __u32 tid; + + NEXT_ARG(); + tid = ipvrf_get_table(*argv); + if (tid == 0) + invarg("Invalid VRF\n", *argv); + filter.tb = tid; + filter.typemask = ~(1 << RTN_LOCAL | 1< Date: Thu, 7 Jul 2016 16:09:03 -0500 Subject: [PATCH 314/513] Add support for configuring Infiniband GUIDs Add two NLA's that allow configuration of Infiniband node or port GUIDs by referencing the IPoIB net device set over the physical function. The format to be used is as follows: ip link set dev ib0 vf 0 node_guid 00:02:c9:03:00:21:6e:70 ip link set dev ib0 vf 0 port_guid 00:02:c9:03:00:21:6e:78 Signed-off-by: Eli Cohen --- include/utils.h | 1 + ip/iplink.c | 20 ++++++++++++++++++++ lib/utils.c | 35 +++++++++++++++++++++++++++++++++++ man/man8/ip-link.8.in | 12 +++++++++++- 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/include/utils.h b/include/utils.h index 27562a1c9..82f1aa7de 100644 --- a/include/utils.h +++ b/include/utils.h @@ -248,5 +248,6 @@ int do_each_netns(int (*func)(char *nsname, void *arg), void *arg, bool show_label); char *int_to_str(int val, char *buf); +int get_guid(__u64 *guid, const char *arg); #endif /* __UTILS_H__ */ diff --git a/ip/iplink.c b/ip/iplink.c index f2a2e13cf..28a0a21cf 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -420,6 +420,26 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, invarg("Invalid \"state\" value\n", *argv); ivl.vf = vf; addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE, &ivl, sizeof(ivl)); + } else if (matches(*argv, "node_guid") == 0) { + struct ifla_vf_guid ivg; + + NEXT_ARG(); + ivg.vf = vf; + if (get_guid(&ivg.guid, *argv)) { + invarg("Invalid GUID format\n", *argv); + return -1; + } + addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_NODE_GUID, &ivg, sizeof(ivg)); + } else if (matches(*argv, "port_guid") == 0) { + struct ifla_vf_guid ivg; + + NEXT_ARG(); + ivg.vf = vf; + if (get_guid(&ivg.guid, *argv)) { + invarg("Invalid GUID format\n", *argv); + return -1; + } + addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_PORT_GUID, &ivg, sizeof(ivg)); } else { /* rewind arg */ PREV_ARG(); diff --git a/lib/utils.c b/lib/utils.c index 7dceeb580..966047460 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -1121,3 +1121,38 @@ char *int_to_str(int val, char *buf) sprintf(buf, "%d", val); return buf; } + +int get_guid(__u64 *guid, const char *arg) +{ + unsigned long int tmp; + char *endptr; + int i; + +#define GUID_STR_LEN 23 + /* Verify strict format: format string must be + * xx:xx:xx:xx:xx:xx:xx:xx where xx can be an arbitrary + * hex digit + */ + + if (strlen(arg) != GUID_STR_LEN) + return -1; + + /* make sure columns are in place */ + for (i = 0; i < 7; i++) + if (arg[2 + i * 3] != ':') + return -1; + + *guid = 0; + for (i = 0; i < 8; i++) { + tmp = strtoul(arg + i * 3, &endptr, 16); + if (endptr != arg + i * 3 + 2) + return -1; + + if (tmp > 255) + return -1; + + *guid |= tmp << (56 - 8 * i); + } + + return 0; +} diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index ad18f7555..95fef02c8 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -146,7 +146,11 @@ ip-link \- network device configuration .br .RB "[ " state " { " auto " | " enable " | " disable " } ]" .br -.RB "[ " trust " { " on " | " off " } ] ]" +.RB "[ " trust " { " on " | " off " } ]" +.br +.RB "[ " node_guid " eui64 ]" +.br +.RB "[ " port_guid " eui64 ] ]" .br .in -9 .RB "[ " master @@ -1196,6 +1200,12 @@ sent by the VF. .BI trust " on|off" - trust the specified VF user. This enables that VF user can set a specific feature which may impact security and/or performance. (e.g. VF multicast promiscuous mode) +.sp +.BI node_guid " eui64" +- configure node GUID for the VF. +.sp +.BI port_guid " eui64" +- configure port GUID for the VF. .in -8 .TP From ef0a738c8d170bc8146954f4bb4e981d0b1eff55 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 15 Jul 2016 11:31:20 -0700 Subject: [PATCH 315/513] ip: link style cleanup break long lines and other trivial changes --- ip/iplink.c | 57 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/ip/iplink.c b/ip/iplink.c index 28a0a21cf..365240e60 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -317,7 +317,8 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, len, halen); return -1; } - addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm)); + addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, + &ivm, sizeof(ivm)); } else if (matches(*argv, "vlan") == 0) { struct ifla_vf_vlan ivv; @@ -338,7 +339,8 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, PREV_ARG(); } } - addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv)); + addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, + &ivv, sizeof(ivv)); } else if (matches(*argv, "rate") == 0) { struct ifla_vf_tx_rate ivt; @@ -378,7 +380,8 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, else return on_off("spoofchk", *argv); ivs.vf = vf; - addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs)); + addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, + &ivs, sizeof(ivs)); } else if (matches(*argv, "query_rss") == 0) { struct ifla_vf_rss_query_en ivs; @@ -391,7 +394,8 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, else return on_off("query_rss", *argv); ivs.vf = vf; - addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(ivs)); + addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN, + &ivs, sizeof(ivs)); } else if (matches(*argv, "trust") == 0) { struct ifla_vf_trust ivt; @@ -404,7 +408,8 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, else invarg("Invalid \"trust\" value\n", *argv); ivt.vf = vf; - addattr_l(&req->n, sizeof(*req), IFLA_VF_TRUST, &ivt, sizeof(ivt)); + addattr_l(&req->n, sizeof(*req), IFLA_VF_TRUST, + &ivt, sizeof(ivt)); } else if (matches(*argv, "state") == 0) { struct ifla_vf_link_state ivl; @@ -419,7 +424,8 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, else invarg("Invalid \"state\" value\n", *argv); ivl.vf = vf; - addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE, &ivl, sizeof(ivl)); + addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE, + &ivl, sizeof(ivl)); } else if (matches(*argv, "node_guid") == 0) { struct ifla_vf_guid ivg; @@ -429,7 +435,8 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, invarg("Invalid GUID format\n", *argv); return -1; } - addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_NODE_GUID, &ivg, sizeof(ivg)); + addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_NODE_GUID, + &ivg, sizeof(ivg)); } else if (matches(*argv, "port_guid") == 0) { struct ifla_vf_guid ivg; @@ -439,7 +446,8 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, invarg("Invalid GUID format\n", *argv); return -1; } - addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_PORT_GUID, &ivg, sizeof(ivg)); + addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_PORT_GUID, + &ivg, sizeof(ivg)); } else { /* rewind arg */ PREV_ARG(); @@ -543,9 +551,11 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, duparg("netns", *argv); netns = netns_get_fd(*argv); if (netns >= 0) - addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4); + addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, + &netns, 4); else if (get_integer(&netns, *argv, 0) == 0) - addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4); + addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, + &netns, 4); else invarg("Invalid \"netns\" value\n", *argv); } else if (strcmp(*argv, "multicast") == 0) { @@ -709,7 +719,8 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, invarg("Invalid address generation mode\n", *argv); afs = addattr_nest(&req->n, sizeof(*req), IFLA_AF_SPEC); afs6 = addattr_nest(&req->n, sizeof(*req), AF_INET6); - addattr8(&req->n, sizeof(*req), IFLA_INET6_ADDR_GEN_MODE, mode); + addattr8(&req->n, sizeof(*req), + IFLA_INET6_ADDR_GEN_MODE, mode); addattr_nest_end(&req->n, afs6); addattr_nest_end(&req->n, afs); } else if (matches(*argv, "link-netnsid") == 0) { @@ -748,10 +759,11 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, if (dev_index && addr_len) { int halen = nl_get_ll_addr_len(dev_index); + if (halen >= 0 && halen != addr_len) { fprintf(stderr, - "Invalid address length %d - must be %d bytes\n", - addr_len, halen); + "Invalid address length %d - must be %d bytes\n", + addr_len, halen); return -1; } } @@ -779,7 +791,8 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) req.n.nlmsg_type = cmd; req.i.ifi_family = preferred_family; - ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group, &index); + ret = iplink_parse(argc, argv, + &req, &name, &type, &link, &dev, &group, &index); if (ret < 0) return ret; @@ -792,8 +805,8 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) &group, sizeof(group)); else { if (argc) { - fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"ip link " - "help\".\n", *argv); + fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n", + *argv); return -1; } if (flags & NLM_F_CREATE) { @@ -850,7 +863,8 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) if (name) { len = strlen(name) + 1; if (len == 1) - invarg("\"\" is not a valid device identifier\n", "name"); + invarg("\"\" is not a valid device identifier\n", + "name"); if (len > IFNAMSIZ) invarg("\"name\" too long\n", name); addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len); @@ -879,7 +893,8 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) iflatype = IFLA_INFO_DATA; } if (lu && argc) { - struct rtattr *data = addattr_nest(&req.n, sizeof(req), iflatype); + struct rtattr *data = addattr_nest(&req.n, + sizeof(req), iflatype); if (lu->parse_opt && lu->parse_opt(lu, argc, argv, &req.n)) @@ -1110,7 +1125,8 @@ static int parse_address(const char *dev, int hatype, int halen, if (alen < 0) return -1; if (alen != halen) { - fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen); + fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", + lla, halen); return -1; } return 0; @@ -1250,7 +1266,8 @@ static int do_set(int argc, char **argv) } if (!dev) { - fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n"); + fprintf(stderr, + "Not enough of information: \"dev\" argument is required.\n"); exit(-1); } From 74af8dd9620e4322babf9d2a936b1d333a4e37e0 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Tue, 12 Jul 2016 21:37:58 +0800 Subject: [PATCH 316/513] ip route: restore route entries in correct order Sometimes we cannot restore route entries, because in kernel [1] fib_check_nh() [2] fib_valid_prefsrc() cause some routes to depend on existence of others while adding. For example, we saved all the routes, and flushed all tables [a] default via 192.168.122.1 dev eth0 [b] 192.168.122.0/24 dev eth0 src 192.168.122.21 [c] broadcast 127.0.0.0 dev lo table local src 127.0.0.1 [d] local 127.0.0.0/8 dev lo table local src 127.0.0.1 [e] local 127.0.0.1 dev lo table local src 127.0.0.1 [f] broadcast 127.255.255.255 dev lo table local src 127.0.0.1 [g] broadcast 192.168.122.0 dev eth0 table local src 192.168.122.21 [h] local 192.168.122.21 dev eth0 table local src 192.168.122.21 [i] broadcast 192.168.122.255 dev eth0 table local src 192.168.122.21 Now start to restore them: If we want to add [a], we have to add [b] first, as [1] and 'via 192.168.122.1' in [a]. If we want to add [b], we have to add [h] first, as [2] and 'src 192.168.122.21' in [b]. So the correct order to restore should be like: [e][h] -> [b][c][d][f][g][i] -> [a] This patch fixes it by traversing the file 3 times, it only restores part of them in each run according to the following conditions, to make sure every entry can be restored successfully. 1. !gw && (!fib_prefsrc || fib_prefsrc == cfg->fc_dst) 2. !gw && (fib_prefsrc != cfg->fc_dst) 3. gw Signed-off-by: Xin Long Acked-by: Phil Sutter --- ip/iproute.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/ip/iproute.c b/ip/iproute.c index 24f6b0101..c73500095 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -1810,12 +1810,42 @@ static int iproute_get(int argc, char **argv) return 0; } +static int rtattr_cmp(struct rtattr *rta1, struct rtattr *rta2) +{ + if (!rta1 || !rta2 || rta1->rta_len != rta2->rta_len) + return 1; + + return memcmp(RTA_DATA(rta1), RTA_DATA(rta2), RTA_PAYLOAD(rta1)); +} + static int restore_handler(const struct sockaddr_nl *nl, struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg) { - int ret; + struct rtmsg *r = NLMSG_DATA(n); + struct rtattr *tb[RTA_MAX+1]; + int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)); + int ret, prio = *(int *)arg; + + parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); + /* Restore routes in correct order: + * 0. ones for local addresses, + * 1. ones for local networks, + * 2. others (remote networks/hosts). + */ + if (!prio && !tb[RTA_GATEWAY] && (!tb[RTA_PREFSRC] || + !rtattr_cmp(tb[RTA_PREFSRC], tb[RTA_DST]))) + goto restore; + else if (prio == 1 && !tb[RTA_GATEWAY] && + rtattr_cmp(tb[RTA_PREFSRC], tb[RTA_DST])) + goto restore; + else if (prio == 2 && tb[RTA_GATEWAY]) + goto restore; + + return 0; + +restore: n->nlmsg_flags |= NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK; ll_init_map(&rth); @@ -1848,10 +1878,23 @@ static int route_dump_check_magic(void) static int iproute_restore(void) { + int pos, prio; + if (route_dump_check_magic()) exit(-1); - exit(rtnl_from_file(stdin, &restore_handler, NULL)); + pos = ftell(stdin); + for (prio = 0; prio < 3; prio++) { + int err; + + err = rtnl_from_file(stdin, &restore_handler, &prio); + if (err) + exit(err); + + fseek(stdin, pos, SEEK_SET); + } + + exit(0); } static int show_handler(const struct sockaddr_nl *nl, From 79f4a39365361732622e114dbc86bc90ed32d25f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 15 Jul 2016 11:34:45 -0700 Subject: [PATCH 317/513] iproute: constify rtattr_cmp --- ip/iproute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/iproute.c b/ip/iproute.c index c73500095..c564fa6d3 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -1810,7 +1810,7 @@ static int iproute_get(int argc, char **argv) return 0; } -static int rtattr_cmp(struct rtattr *rta1, struct rtattr *rta2) +static int rtattr_cmp(const struct rtattr *rta1, const struct rtattr *rta2) { if (!rta1 || !rta2 || rta1->rta_len != rta2->rta_len) return 1; From e3da7a45bad1672328d67f016627e026cb41feba Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 13 Jul 2016 09:53:53 +0300 Subject: [PATCH 318/513] man: Add devlink man pages to Makefile Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel --- man/man8/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/man/man8/Makefile b/man/man8/Makefile index 929826ecb..9badbed71 100644 --- a/man/man8/Makefile +++ b/man/man8/Makefile @@ -16,7 +16,8 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \ tc-tcindex.8 tc-u32.8 \ tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ - tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 + tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 \ + devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 all: $(TARGETS) From 78c610e6ea8554e87e2204f540cf0ce61ef52695 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 13 Jul 2016 09:53:54 +0300 Subject: [PATCH 319/513] man: Point to 'devlink-sb' from 'devlink' man page Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel --- man/man8/devlink.8 | 1 + 1 file changed, 1 insertion(+) diff --git a/man/man8/devlink.8 b/man/man8/devlink.8 index df00f4fa3..cf0563b90 100644 --- a/man/man8/devlink.8 +++ b/man/man8/devlink.8 @@ -76,6 +76,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR devlink-dev (8), .BR devlink-port (8), .BR devlink-monitor (8), +.BR devlink-sb (8), .br .SH REPORTING BUGS From a9514280584270232610610a7a46d5ed1a84e0b9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 15 Jul 2016 11:55:14 -0700 Subject: [PATCH 320/513] update headers files to current net-next --- include/linux/bpf.h | 7 +++++++ include/linux/if_bridge.h | 7 +++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 3aa778d34..7c55533e7 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -357,6 +357,13 @@ enum bpf_func_id { */ BPF_FUNC_get_hash_recalc, + /** + * u64 bpf_get_current_task(void) + * Returns current task_struct + * Return: current + */ + BPF_FUNC_get_current_task, + __BPF_FUNC_MAX_ID, }; diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 61e19ffee..d9c76fe7a 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -261,14 +261,17 @@ enum { /* IGMP/MLD statistics */ struct br_mcast_stats { - __u64 igmp_queries[BR_MCAST_DIR_SIZE]; + __u64 igmp_v1queries[BR_MCAST_DIR_SIZE]; + __u64 igmp_v2queries[BR_MCAST_DIR_SIZE]; + __u64 igmp_v3queries[BR_MCAST_DIR_SIZE]; __u64 igmp_leaves[BR_MCAST_DIR_SIZE]; __u64 igmp_v1reports[BR_MCAST_DIR_SIZE]; __u64 igmp_v2reports[BR_MCAST_DIR_SIZE]; __u64 igmp_v3reports[BR_MCAST_DIR_SIZE]; __u64 igmp_parse_errors; - __u64 mld_queries[BR_MCAST_DIR_SIZE]; + __u64 mld_v1queries[BR_MCAST_DIR_SIZE]; + __u64 mld_v2queries[BR_MCAST_DIR_SIZE]; __u64 mld_leaves[BR_MCAST_DIR_SIZE]; __u64 mld_v1reports[BR_MCAST_DIR_SIZE]; __u64 mld_v2reports[BR_MCAST_DIR_SIZE]; From e77fa41d4c78b06bdc32808212e5649cb7a37ba3 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 19 Jul 2016 01:09:52 +0200 Subject: [PATCH 321/513] bpf: also check elf for official e_machine value Use the official BPF ELF e_machine value that was assigned recently [1] and will be propagated to glibc, libelf et al. LLVM will switch to it in 3.9 release, therefore we need to prepare tc to check for EM_ELF as well, older version still have the EM_NONE. [1] https://github.com/llvm-mirror/llvm/commit/36b9c09330bfb5e771914cfe307588f30d5510d2 Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov --- tc/tc_bpf.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index 86c6069b6..7eb1cd74a 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -54,6 +54,10 @@ #define AF_ALG 38 #endif +#ifndef EM_BPF +#define EM_BPF 247 +#endif + #ifdef HAVE_ELF static int bpf_obj_open(const char *path, enum bpf_prog_type type, const char *sec, bool verbose); @@ -1690,7 +1694,8 @@ static void bpf_hash_destroy(struct bpf_elf_ctx *ctx) static int bpf_elf_check_ehdr(const struct bpf_elf_ctx *ctx) { if (ctx->elf_hdr.e_type != ET_REL || - ctx->elf_hdr.e_machine != 0 || + (ctx->elf_hdr.e_machine != EM_NONE && + ctx->elf_hdr.e_machine != EM_BPF) || ctx->elf_hdr.e_version != EV_CURRENT) { fprintf(stderr, "ELF format error, ELF file not for eBPF?\n"); return -EINVAL; From 930d3f281980997176d12717e85ca6e37604a307 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 15 Jul 2016 15:41:35 -0700 Subject: [PATCH 322/513] ss: Fix support for device filter by index Support was recently added for device filters. The intent was to allow the device to be specified by name or index, and using the if%u format (dev == if5) or the simpler and more intuitive index alone (dev == 5). The latter case is broken since the index is not saved to the filter after the strtoul conversion. Further, the tmp variable used for the conversion shadows another variable used in the function. Fix both. With this change all 3 variants work as expected: $ ss -t 'dev == 62' State Recv-Q Send-Q Local Address:Port Peer Address:Port ESTAB 0 224 10.0.1.3%mgmt:ssh 192.168.0.50:58442 $ ss -t 'dev == mgmt' State Recv-Q Send-Q Local Address:Port Peer Address:Port ESTAB 0 224 10.0.1.3%mgmt:ssh 192.168.0.50:58442 $ ss -t 'dev == if62' State Recv-Q Send-Q Local Address:Port Peer Address:Port ESTAB 0 36 10.0.1.3%mgmt:ssh 192.168.0.50:58442 Fixes: 2d2932125616 ("ss: Add support to filter on device") Signed-off-by: David Ahern --- misc/ss.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index a0f9c6b96..abece96c0 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -1435,11 +1435,13 @@ void *parse_devcond(char *name) a.iface = xll_name_to_index(name); if (a.iface == 0) { char *end; - unsigned long res; + unsigned long n; - res = strtoul(name, &end, 0); - if (!end || end == name || *end || res > UINT_MAX) + n = strtoul(name, &end, 0); + if (!end || end == name || *end || n > UINT_MAX) return NULL; + + a.iface = n; } res = malloc(sizeof(*res)); From 7a4559f67c8c4dcd6d8d361018ac239090713b69 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 15 Jul 2016 15:45:39 -0700 Subject: [PATCH 323/513] ss: Add option to suppress header line Add option to suppress header line. When used the following line is not shown: "State Recv-Q Send-Q Local Address:Port Peer Address:Port" Signed-off-by: David Ahern --- man/man8/ss.8 | 3 +++ misc/ss.c | 28 +++++++++++++++++++--------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/man/man8/ss.8 b/man/man8/ss.8 index 758460c27..8911976fa 100644 --- a/man/man8/ss.8 +++ b/man/man8/ss.8 @@ -21,6 +21,9 @@ Show summary of options. .B \-V, \-\-version Output version information. .TP +.B \-H, \-\-no-header +Suppress header line. +.TP .B \-n, \-\-numeric Do not try to resolve service names. .TP diff --git a/misc/ss.c b/misc/ss.c index abece96c0..38205b0e8 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -97,6 +97,7 @@ int show_tcpinfo; int show_bpf; int show_proc_ctx; int show_sock_ctx; +int show_header = 1; /* If show_users & show_proc_ctx only do user_ent_hash_build() once */ int user_ent_hash_build_init; int follow_events; @@ -3669,6 +3670,7 @@ static void _usage(FILE *dest) " FAMILY := {inet|inet6|link|unix|netlink|help}\n" "\n" " -K, --kill forcibly close sockets, display what was closed\n" +" -H, --no-header Suppress header line\n" "\n" " -A, --query=QUERY, --socket=QUERY\n" " QUERY := {all|inet|tcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink}[,QUERY]\n" @@ -3762,6 +3764,7 @@ static const struct option long_opts[] = { { "contexts", 0, 0, 'z' }, { "net", 1, 0, 'N' }, { "kill", 0, 0, 'K' }, + { "no-header", 0, 0, 'H' }, { 0 } }; @@ -3776,7 +3779,7 @@ int main(int argc, char *argv[]) int ch; int state_filter = 0; - while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:K", + while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:KH", long_opts, NULL)) != EOF) { switch (ch) { case 'n': @@ -3961,6 +3964,9 @@ int main(int argc, char *argv[]) case 'K': current_filter.kill = 1; break; + case 'H': + show_header = 0; + break; case 'h': help(); case '?': @@ -4086,19 +4092,23 @@ int main(int argc, char *argv[]) addr_width = addrp_width - serv_width - 1; - if (netid_width) - printf("%-*s ", netid_width, "Netid"); - if (state_width) - printf("%-*s ", state_width, "State"); - printf("%-6s %-6s ", "Recv-Q", "Send-Q"); + if (show_header) { + if (netid_width) + printf("%-*s ", netid_width, "Netid"); + if (state_width) + printf("%-*s ", state_width, "State"); + printf("%-6s %-6s ", "Recv-Q", "Send-Q"); + } /* Make enough space for the local/remote port field */ addr_width -= 13; serv_width += 13; - printf("%*s:%-*s %*s:%-*s\n", - addr_width, "Local Address", serv_width, "Port", - addr_width, "Peer Address", serv_width, "Port"); + if (show_header) { + printf("%*s:%-*s %*s:%-*s\n", + addr_width, "Local Address", serv_width, "Port", + addr_width, "Peer Address", serv_width, "Port"); + } fflush(stdout); From d721a14590bae641546fb61aa7e4a0e604e75106 Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Wed, 22 Jun 2016 06:45:51 -0700 Subject: [PATCH 324/513] json_writer: Removed automatic json-object type from the constructor Top level can be any json type and can be created using jsonw_start_object/jsonw_end_object etc. Signed-off-by: Anuradha Karuppiah --- lib/json_writer.c | 8 ++++---- misc/ifstat.c | 7 +++++++ misc/nstat.c | 6 ++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/json_writer.c b/lib/json_writer.c index 2af16e101..9fc05e96b 100644 --- a/lib/json_writer.c +++ b/lib/json_writer.c @@ -33,7 +33,7 @@ struct json_writer { static void jsonw_indent(json_writer_t *self) { unsigned i; - for (i = 0; i <= self->depth; ++i) + for (i = 0; i < self->depth; ++i) fputs(" ", self->out); } @@ -102,7 +102,6 @@ json_writer_t *jsonw_new(FILE *f) self->depth = 0; self->pretty = false; self->sep = '\0'; - putc('{', self->out); } return self; } @@ -113,8 +112,7 @@ void jsonw_destroy(json_writer_t **self_p) json_writer_t *self = *self_p; assert(self->depth == 0); - jsonw_eol(self); - fputs("}\n", self->out); + fputs("\n", self->out); fflush(self->out); free(self); *self_p = NULL; @@ -269,6 +267,7 @@ int main(int argc, char **argv) { json_writer_t *wr = jsonw_new(stdout); + jsonw_start_object(wr); jsonw_pretty(wr, true); jsonw_name(wr, "Vyatta"); jsonw_start_object(wr); @@ -305,6 +304,7 @@ int main(int argc, char **argv) jsonw_end_object(wr); + jsonw_end_object(wr); jsonw_destroy(&wr); return 0; } diff --git a/misc/ifstat.c b/misc/ifstat.c index abbb4e732..d55197375 100644 --- a/misc/ifstat.c +++ b/misc/ifstat.c @@ -245,6 +245,7 @@ static void dump_raw_db(FILE *fp, int to_hist) h = hist_db; if (jw) { + jsonw_start_object(jw); jsonw_pretty(jw, pretty); jsonw_name(jw, info_source); jsonw_start_object(jw); @@ -287,6 +288,8 @@ static void dump_raw_db(FILE *fp, int to_hist) } } if (jw) { + jsonw_end_object(jw); + jsonw_end_object(jw); jsonw_destroy(&jw); } @@ -451,6 +454,7 @@ static void dump_kern_db(FILE *fp) struct ifstat_ent *n; if (jw) { + jsonw_start_object(jw); jsonw_pretty(jw, pretty); jsonw_name(jw, info_source); jsonw_start_object(jw); @@ -477,6 +481,7 @@ static void dump_incr_db(FILE *fp) h = hist_db; if (jw) { + jsonw_start_object(jw); jsonw_pretty(jw, pretty); jsonw_name(jw, info_source); jsonw_start_object(jw); @@ -508,6 +513,8 @@ static void dump_incr_db(FILE *fp) } if (jw) { + jsonw_end_object(jw); + jsonw_end_object(jw); jsonw_destroy(&jw); } diff --git a/misc/nstat.c b/misc/nstat.c index e579ce1d3..6143719e3 100644 --- a/misc/nstat.c +++ b/misc/nstat.c @@ -285,6 +285,7 @@ static void dump_kern_db(FILE *fp, int to_hist) h = hist_db; if (jw) { + jsonw_start_object(jw); jsonw_pretty(jw, pretty); jsonw_name(jw, info_source); jsonw_start_object(jw); @@ -317,6 +318,8 @@ static void dump_kern_db(FILE *fp, int to_hist) } if (jw) { + jsonw_end_object(jw); + jsonw_end_object(jw); jsonw_destroy(&jw); } @@ -329,6 +332,7 @@ static void dump_incr_db(FILE *fp) h = hist_db; if (jw) { + jsonw_start_object(jw); jsonw_pretty(jw, pretty); jsonw_name(jw, info_source); jsonw_start_object(jw); @@ -364,6 +368,8 @@ static void dump_incr_db(FILE *fp) } if (jw) { + jsonw_end_object(jw); + jsonw_end_object(jw); jsonw_destroy(&jw); } From d82a49ce85f0994b09310c24ad360be7739225fa Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Wed, 22 Jun 2016 06:45:52 -0700 Subject: [PATCH 325/513] bridge: add json support for bridge vlan show $bridge -c vlan show port vlan ids swp1 1 PVID Egress Untagged 10-13 swp2 1 PVID Egress Untagged 10-13 br0 1 PVID Egress Untagged $bridge -json vlan show { "swp1": [{ "vlan": 1, "flags": ["PVID","Egress Untagged" ] },{ "vlan": 10 },{ "vlan": 11 },{ "vlan": 12 },{ "vlan": 13 } ], "swp2": [{ "vlan": 1, "flags": ["PVID","Egress Untagged" ] },{ "vlan": 10 },{ "vlan": 11 },{ "vlan": 12 },{ "vlan": 13 } ], "br0": [{ "vlan": 1, "flags": ["PVID","Egress Untagged" ] } ] } $bridge -c -json vlan show { "swp1": [{ "vlan": 1, "flags": ["PVID","Egress Untagged" ] },{ "vlan": 10, "vlanEnd": 13 } ], "swp2": [{ "vlan": 1, "flags": ["PVID","Egress Untagged" ] },{ "vlan": 10, "vlanEnd": 13 } ], "br0": [{ "vlan": 1, "flags": ["PVID","Egress Untagged" ] } ] } Signed-off-by: Roopa Prabhu --- bridge/br_common.h | 1 + bridge/bridge.c | 5 ++- bridge/vlan.c | 109 +++++++++++++++++++++++++++++++++++++++------ 3 files changed, 100 insertions(+), 15 deletions(-) diff --git a/bridge/br_common.h b/bridge/br_common.h index 5ea45c9e6..c649e7d9f 100644 --- a/bridge/br_common.h +++ b/bridge/br_common.h @@ -23,4 +23,5 @@ extern int show_stats; extern int show_details; extern int timestamp; extern int compress_vlans; +extern int json_output; extern struct rtnl_handle rth; diff --git a/bridge/bridge.c b/bridge/bridge.c index 72f153f2b..5ff038d67 100644 --- a/bridge/bridge.c +++ b/bridge/bridge.c @@ -23,6 +23,7 @@ int oneline; int show_stats; int show_details; int compress_vlans; +int json_output; int timestamp; char *batch_file; int force; @@ -38,7 +39,7 @@ static void usage(void) "where OBJECT := { link | fdb | mdb | vlan | monitor }\n" " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n" " -o[neline] | -t[imestamp] | -n[etns] name |\n" -" -c[ompressvlans] }\n"); +" -c[ompressvlans] -j{son} }\n"); exit(-1); } @@ -173,6 +174,8 @@ main(int argc, char **argv) ++compress_vlans; } else if (matches(opt, "-force") == 0) { ++force; + } else if (matches(opt, "-json") == 0) { + ++json_output; } else if (matches(opt, "-batch") == 0) { argc--; argv++; diff --git a/bridge/vlan.c b/bridge/vlan.c index a8a2e1d95..f34e84a2a 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "libnetlink.h" @@ -15,6 +16,8 @@ static unsigned int filter_index, filter_vlan; +json_writer_t *jw_global = NULL; + static void usage(void) { fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid] [ untagged ]\n"); @@ -158,6 +161,28 @@ static int filter_vlan_check(struct bridge_vlan_info *vinfo) return 1; } +static void print_vlan_port(FILE *fp, int ifi_index) +{ + if (jw_global) { + jsonw_pretty(jw_global, 1); + jsonw_name(jw_global, + ll_index_to_name(ifi_index)); + jsonw_start_array(jw_global); + } else { + fprintf(fp, "%s", + ll_index_to_name(ifi_index)); + } +} + +static void start_json_vlan_flags_array(bool *vlan_flags) +{ + if (*vlan_flags) + return; + jsonw_name(jw_global, "flags"); + jsonw_start_array(jw_global); + *vlan_flags = true; +} + static int print_vlan(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) @@ -166,6 +191,8 @@ static int print_vlan(const struct sockaddr_nl *who, struct ifinfomsg *ifm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[IFLA_MAX+1]; + bool vlan_flags; + char flags[80]; if (n->nlmsg_type != RTM_NEWLINK) { fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n", @@ -199,7 +226,8 @@ static int print_vlan(const struct sockaddr_nl *who, __u16 last_vid_start = 0; if (!filter_vlan) - fprintf(fp, "%s", ll_index_to_name(ifm->ifi_index)); + print_vlan_port(fp, ifm->ifi_index); + for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { struct bridge_vlan_info *vinfo; int vcheck_ret; @@ -218,20 +246,58 @@ static int print_vlan(const struct sockaddr_nl *who, continue; if (filter_vlan) - fprintf(fp, "%s", - ll_index_to_name(ifm->ifi_index)); - fprintf(fp, "\t %hu", last_vid_start); - if (last_vid_start != vinfo->vid) - fprintf(fp, "-%hu", vinfo->vid); - if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) - fprintf(fp, " PVID"); - if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) - fprintf(fp, " Egress Untagged"); - fprintf(fp, "\n"); + print_vlan_port(fp, ifm->ifi_index); + if (jw_global) { + jsonw_start_object(jw_global); + jsonw_uint_field(jw_global, "vlan", + last_vid_start); + if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) + continue; + } else { + fprintf(fp, "\t %hu", last_vid_start); + } + if (last_vid_start != vinfo->vid) { + if (jw_global) + jsonw_uint_field(jw_global, "vlanEnd", + vinfo->vid); + else + fprintf(fp, "-%hu", vinfo->vid); + } + if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) { + if (jw_global) { + start_json_vlan_flags_array(&vlan_flags); + jsonw_string(jw_global, "PVID"); + } else { + fprintf(fp, " PVID"); + } + } + if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) { + if (jw_global) { + start_json_vlan_flags_array(&vlan_flags); + jsonw_string(jw_global, + "Egress Untagged"); + } else { + fprintf(fp, " Egress Untagged"); + } + } + if (vlan_flags) { + jsonw_end_array(jw_global); + vlan_flags = false; + } + + if (jw_global) + jsonw_end_object(jw_global); + else + fprintf(fp, "\n"); } } - if (!filter_vlan) - fprintf(fp, "\n"); + if (!filter_vlan) { + if (jw_global) + jsonw_end_array(jw_global); + else + fprintf(fp, "\n"); + + } fflush(fp); return 0; } @@ -271,12 +337,27 @@ static int vlan_show(int argc, char **argv) exit(1); } - printf("port\tvlan ids\n"); + if (json_output) { + jw_global = jsonw_new(stdout); + if (!jw_global) { + fprintf(stderr, "Error allocation json object\n"); + exit(1); + } + jsonw_start_object(jw_global); + } else { + printf("port\tvlan ids\n"); + } + if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) { fprintf(stderr, "Dump ternminated\n"); exit(1); } + if (jw_global) { + jsonw_end_object(jw_global); + jsonw_destroy(&jw_global); + } + return 0; } From b239c56ebc5ee27f7688b0e61166a78486721238 Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Wed, 22 Jun 2016 06:45:53 -0700 Subject: [PATCH 326/513] bridge: add json support for bridge fdb show Sample output: $bridge -j fdb show [{ "mac": "44:38:39:00:69:88", "dev": "swp2s0", "vlan": 2, "master": "br0", "state": "permanent" },{ "mac": "00:02:00:00:00:01", "dev": "swp2s0", "vlan": 2, "master": "br0" },{ "mac": "00:02:00:00:00:02", "dev": "swp2s1", "vlan": 2, "master": "br0" },{ "mac": "44:38:39:00:69:89", "dev": "swp2s1", "master": "br0", "state": "permanent" },{ "mac": "44:38:39:00:69:89", "dev": "swp2s1", "vlan": 2, "master": "br0", "state": "permanent" },{ "mac": "44:38:39:00:69:88", "dev": "br0", "master": "br0", "state": "permanent" } ] Signed-off-by: Anuradha Karuppiah Signed-off-by: Roopa Prabhu --- bridge/fdb.c | 210 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 167 insertions(+), 43 deletions(-) diff --git a/bridge/fdb.c b/bridge/fdb.c index be849f980..3d1ef6c88 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "libnetlink.h" #include "br_common.h" @@ -29,6 +31,8 @@ static unsigned int filter_index, filter_vlan; +json_writer_t *jw_global; + static void usage(void) { fprintf(stderr, "Usage: bridge fdb { add | append | del | replace } ADDR dev DEV\n" @@ -59,6 +63,15 @@ static const char *state_n2a(unsigned int s) return buf; } +static void start_json_fdb_flags_array(bool *fdb_flags) +{ + if (*fdb_flags) + return; + jsonw_name(jw_global, "flags"); + jsonw_start_array(jw_global); + *fdb_flags = true; +} + int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = arg; @@ -66,11 +79,12 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) int len = n->nlmsg_len; struct rtattr *tb[NDA_MAX+1]; __u16 vid = 0; + bool fdb_flags = false; + const char *state_s; if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) { fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); - return 0; } @@ -86,6 +100,11 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (filter_index && filter_index != r->ndm_ifindex) return 0; + if (jw_global) { + jsonw_pretty(jw_global, 1); + jsonw_start_object(jw_global); + } + parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); @@ -95,40 +114,75 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (filter_vlan && filter_vlan != vid) return 0; - if (n->nlmsg_type == RTM_DELNEIGH) - fprintf(fp, "Deleted "); + if (n->nlmsg_type == RTM_DELNEIGH) { + if (jw_global) + jsonw_string_field(jw_global, "opCode", "deleted"); + else + fprintf(fp, "Deleted "); + } if (tb[NDA_LLADDR]) { SPRINT_BUF(b1); - fprintf(fp, "%s ", - ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]), - RTA_PAYLOAD(tb[NDA_LLADDR]), - ll_index_to_type(r->ndm_ifindex), - b1, sizeof(b1))); + ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]), + RTA_PAYLOAD(tb[NDA_LLADDR]), + ll_index_to_type(r->ndm_ifindex), + b1, sizeof(b1)); + if (jw_global) + jsonw_string_field(jw_global, "mac", b1); + else + fprintf(fp, "%s ", b1); } - if (!filter_index && r->ndm_ifindex) - fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex)); + if (!filter_index && r->ndm_ifindex) { + if (jw_global) + jsonw_string_field(jw_global, "dev", + ll_index_to_name(r->ndm_ifindex)); + else + fprintf(fp, "dev %s ", + ll_index_to_name(r->ndm_ifindex)); + } if (tb[NDA_DST]) { int family = AF_INET; + const char *abuf_s; if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr)) family = AF_INET6; - fprintf(fp, "dst %s ", - format_host(family, - RTA_PAYLOAD(tb[NDA_DST]), - RTA_DATA(tb[NDA_DST]))); + abuf_s = format_host(family, + RTA_PAYLOAD(tb[NDA_DST]), + RTA_DATA(tb[NDA_DST])); + if (jw_global) + jsonw_string_field(jw_global, "dst", abuf_s); + else + fprintf(fp, "dst %s ", abuf_s); + } + + if (vid) { + if (jw_global) + jsonw_uint_field(jw_global, "vlan", vid); + else + fprintf(fp, "vlan %hu ", vid); + } + + if (tb[NDA_PORT]) { + if (jw_global) + jsonw_uint_field(jw_global, "port", + ntohs(rta_getattr_u16(tb[NDA_PORT]))); + else + fprintf(fp, "port %d ", + ntohs(rta_getattr_u16(tb[NDA_PORT]))); } - if (vid) - fprintf(fp, "vlan %hu ", vid); + if (tb[NDA_VNI]) { + if (jw_global) + jsonw_uint_field(jw_global, "vni", + rta_getattr_u32(tb[NDA_VNI])); + else + fprintf(fp, "vni %d ", + rta_getattr_u32(tb[NDA_VNI])); + } - if (tb[NDA_PORT]) - fprintf(fp, "port %d ", ntohs(rta_getattr_u16(tb[NDA_PORT]))); - if (tb[NDA_VNI]) - fprintf(fp, "vni %d ", rta_getattr_u32(tb[NDA_VNI])); if (tb[NDA_IFINDEX]) { unsigned int ifindex = rta_getattr_u32(tb[NDA_IFINDEX]); @@ -136,37 +190,95 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) char ifname[IF_NAMESIZE]; if (!tb[NDA_LINK_NETNSID] && - if_indextoname(ifindex, ifname)) - fprintf(fp, "via %s ", ifname); - else - fprintf(fp, "via ifindex %u ", ifindex); + if_indextoname(ifindex, ifname)) { + if (jw_global) + jsonw_string_field(jw_global, "viaIf", + ifname); + else + fprintf(fp, "via %s ", ifname); + } else { + if (jw_global) + jsonw_uint_field(jw_global, "viaIfIndex", + ifindex); + else + fprintf(fp, "via ifindex %u ", ifindex); + } } } - if (tb[NDA_LINK_NETNSID]) - fprintf(fp, "link-netnsid %d ", - rta_getattr_u32(tb[NDA_LINK_NETNSID])); + + if (tb[NDA_LINK_NETNSID]) { + if (jw_global) + jsonw_uint_field(jw_global, "linkNetNsId", + rta_getattr_u32(tb[NDA_LINK_NETNSID])); + else + fprintf(fp, "link-netnsid %d ", + rta_getattr_u32(tb[NDA_LINK_NETNSID])); + } if (show_stats && tb[NDA_CACHEINFO]) { struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]); int hz = get_user_hz(); - fprintf(fp, "used %d/%d ", ci->ndm_used/hz, - ci->ndm_updated/hz); + if (jw_global) { + jsonw_uint_field(jw_global, "used", + ci->ndm_used/hz); + jsonw_uint_field(jw_global, "updated", + ci->ndm_updated/hz); + } else { + fprintf(fp, "used %d/%d ", ci->ndm_used/hz, + ci->ndm_updated/hz); + } + } + + if (jw_global) { + if (r->ndm_flags & NTF_SELF) { + start_json_fdb_flags_array(&fdb_flags); + jsonw_string(jw_global, "self"); + } + if (r->ndm_flags & NTF_ROUTER) { + start_json_fdb_flags_array(&fdb_flags); + jsonw_string(jw_global, "router"); + } + if (r->ndm_flags & NTF_EXT_LEARNED) { + start_json_fdb_flags_array(&fdb_flags); + jsonw_string(jw_global, "offload"); + } + if (r->ndm_flags & NTF_MASTER) + jsonw_string(jw_global, "master"); + if (fdb_flags) + jsonw_end_array(jw_global); + + if (tb[NDA_MASTER]) + jsonw_string_field(jw_global, + "master", + ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER]))); + + } else { + if (r->ndm_flags & NTF_SELF) + fprintf(fp, "self "); + if (r->ndm_flags & NTF_ROUTER) + fprintf(fp, "router "); + if (r->ndm_flags & NTF_EXT_LEARNED) + fprintf(fp, "offload "); + if (tb[NDA_MASTER]) { + fprintf(fp, "master %s ", + ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER]))); + } else if (r->ndm_flags & NTF_MASTER) { + fprintf(fp, "master "); + } + } + + state_s = state_n2a(r->ndm_state); + if (jw_global) { + if (state_s[0]) + jsonw_string_field(jw_global, "state", state_s); + + jsonw_end_object(jw_global); + } else { + fprintf(fp, "%s\n", state_s); + + fflush(fp); } - if (r->ndm_flags & NTF_SELF) - fprintf(fp, "self "); - if (tb[NDA_MASTER]) - fprintf(fp, "master %s ", - ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER]))); - else if (r->ndm_flags & NTF_MASTER) - fprintf(fp, "master "); - if (r->ndm_flags & NTF_ROUTER) - fprintf(fp, "router "); - if (r->ndm_flags & NTF_EXT_LEARNED) - fprintf(fp, "offload "); - - fprintf(fp, "%s\n", state_n2a(r->ndm_state)); - fflush(fp); return 0; } @@ -233,10 +345,22 @@ static int fdb_show(int argc, char **argv) exit(1); } + if (json_output) { + jw_global = jsonw_new(stdout); + if (!jw_global) { + fprintf(stderr, "Error allocation json object\n"); + exit(1); + } + jsonw_start_array(jw_global); + } if (rtnl_dump_filter(&rth, print_fdb, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } + if (jw_global) { + jsonw_end_array(jw_global); + jsonw_destroy(&jw_global); + } return 0; } From 15539fc6f938f08b4f5cc559d153d16b6e1ef971 Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Wed, 22 Jun 2016 06:45:54 -0700 Subject: [PATCH 327/513] bridge: add json schema for bridge fdb show Storing the schema file for the json format will be useful for doc purposes as optional paramaters are typically suppressed in the json sample outputs. Signed-off-by: Anuradha Karuppiah --- schema/bridge_fdb_schema.json | 62 +++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 schema/bridge_fdb_schema.json diff --git a/schema/bridge_fdb_schema.json b/schema/bridge_fdb_schema.json new file mode 100644 index 000000000..3e5be8d26 --- /dev/null +++ b/schema/bridge_fdb_schema.json @@ -0,0 +1,62 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "bridge fdb show", + "type": "array", + "items": { + "type": "object", + "properties": { + "dev": { + "type": "string" + }, + "dst": { + "description" : "host name or ip address", + "type": "string" + }, + "flags": { + "type": "array", + "items": { + "enum": ["self", "master", "router", "offload"] + }, + "uniqueItems": true + }, + "linkNetNsId": { + "type": "integer" + }, + "mac": { + "type": "string" + }, + "master": { + "type": "string" + }, + "opCode": { + "description" : "used to indicate fdb entry del", + "enum": ["deleted"] + }, + "port": { + "type": "integer" + }, + "state": { + "description" : "permanent, static, stale, state=#x", + "type": "string" + }, + "updated": { + "type": "integer" + }, + "used": { + "type": "integer" + }, + "viaIf": { + "type": "string" + }, + "viaIfIndex": { + "type": "integer" + }, + "vlan": { + "type": "integer" + }, + "vni": { + "type": "integer" + } + } + } +} From db7263798aa8966fef5cdd16b7ae8f9ba22ac9ff Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Wed, 22 Jun 2016 06:45:55 -0700 Subject: [PATCH 328/513] bridge: update man page Signed-off-by: Roopa Prabhu --- man/man8/bridge.8 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index ef4f83ee7..bb7044221 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -20,8 +20,9 @@ bridge \- show / manipulate bridge addresses and devices .IR OPTIONS " := { " \fB\-V\fR[\fIersion\fR] | \fB\-s\fR[\fItatistics\fR] | -\fB\-n\fR[\fIetns\fR] name } -\fB\-b\fR[\fIatch\fR] filename } +\fB\-n\fR[\fIetns\fR] name | +\fB\-b\fR[\fIatch\fR] filename | +\fB\-j\fR[\fIson\fR] } .ti -8 .BR "bridge link set" @@ -153,6 +154,10 @@ Don't terminate bridge command on errors in batch mode. If there were any errors during execution of the commands, the application return code will be non zero. +.TP +.BR "\-json" +Display results in JSON format. Currently available for vlan and fdb. + .SH BRIDGE - COMMAND SYNTAX .SS From 48703289da80fcc5a6a7cde4df9aeafc08a67d42 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 20 Jul 2016 12:03:33 -0700 Subject: [PATCH 329/513] bridge: remove unused variable Debris from JSON changes. --- bridge/vlan.c | 1 - 1 file changed, 1 deletion(-) diff --git a/bridge/vlan.c b/bridge/vlan.c index f34e84a2a..5dd352e65 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -192,7 +192,6 @@ static int print_vlan(const struct sockaddr_nl *who, int len = n->nlmsg_len; struct rtattr *tb[IFLA_MAX+1]; bool vlan_flags; - char flags[80]; if (n->nlmsg_type != RTM_NEWLINK) { fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n", From 771a24289044c264cfe7b83040c2b35459b4227d Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 9 Jul 2016 11:22:45 +0200 Subject: [PATCH 330/513] iplink: List valid 'type' argument in ip link help text Signed-off-by: Phil Sutter --- ip/iplink.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ip/iplink.c b/ip/iplink.c index 365240e60..5609cc95b 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -55,7 +55,9 @@ void iplink_usage(void) fprintf(stderr, " type TYPE [ ARGS ]\n"); fprintf(stderr, " ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n"); fprintf(stderr, "\n"); - fprintf(stderr, " ip link set { DEVICE | dev DEVICE | group DEVGROUP } [ { up | down } ]\n"); + fprintf(stderr, " ip link set { DEVICE | dev DEVICE | group DEVGROUP }\n"); + fprintf(stderr, " [ { up | down } ]\n"); + fprintf(stderr, " [ type TYPE ARGS ]\n"); } else fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n"); From 25c93faa58806479ea73bc2d5ceb545e5e932867 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 9 Jul 2016 11:22:46 +0200 Subject: [PATCH 331/513] iplink: bond_slave: Add missing help functions Signed-off-by: Phil Sutter --- ip/iplink_bond_slave.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ip/iplink_bond_slave.c b/ip/iplink_bond_slave.c index d67793237..9c60dea8a 100644 --- a/ip/iplink_bond_slave.c +++ b/ip/iplink_bond_slave.c @@ -17,6 +17,16 @@ #include "utils.h" #include "ip_common.h" +static void print_explain(FILE *f) +{ + fprintf(f, "Usage: ... bond_slave [ queue_id ID ]\n"); +} + +static void explain(void) +{ + print_explain(stderr); +} + static const char *slave_states[] = { [BOND_STATE_ACTIVE] = "ACTIVE", [BOND_STATE_BACKUP] = "BACKUP", @@ -99,6 +109,13 @@ static int bond_slave_parse_opt(struct link_util *lu, int argc, char **argv, if (get_u16(&queue_id, *argv, 0)) invarg("queue_id is invalid", *argv); addattr16(n, 1024, IFLA_BOND_SLAVE_QUEUE_ID, queue_id); + } else { + if (matches(*argv, "help") != 0) + fprintf(stderr, + "bond_slave: unknown option \"%s\"?\n", + *argv); + explain(); + return -1; } argc--, argv++; } @@ -106,10 +123,17 @@ static int bond_slave_parse_opt(struct link_util *lu, int argc, char **argv, return 0; } +static void bond_slave_print_help(struct link_util *lu, int argc, char **argv, + FILE *f) +{ + print_explain(f); +} + struct link_util bond_slave_link_util = { .id = "bond", .maxattr = IFLA_BOND_SLAVE_MAX, .print_opt = bond_slave_print_opt, .parse_opt = bond_slave_parse_opt, + .print_help = bond_slave_print_help, .slave = true, }; From 657426c5060ace22197397fbcaa6ac2c60d2ebec Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 9 Jul 2016 11:22:47 +0200 Subject: [PATCH 332/513] ip-link.8: Extend type list in synopsis 'ip link set' supports passing a type to set type-specific parameters. Add this missing piece of information to the synopsis section. Signed-off-by: Phil Sutter --- man/man8/ip-link.8.in | 71 ++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 95fef02c8..5d22e1552 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -39,35 +39,6 @@ ip-link \- network device configuration .BI type " TYPE" .RI "[ " ARGS " ]" -.ti -8 -.IR TYPE " := [ " -.BR bridge " | " -.BR bond " | " -.BR can " | " -.BR dummy " | " -.BR hsr " | " -.BR ifb " | " -.BR ipoib " |" -.BR macvlan " | " -.BR macvtap " | " -.BR vcan " | " -.BR veth " | " -.BR vlan " | " -.BR vxlan " |" -.BR ip6tnl " |" -.BR ipip " |" -.BR sit " |" -.BR gre " |" -.BR gretap " |" -.BR ip6gre " |" -.BR ip6gretap " |" -.BR vti " |" -.BR nlmon " |" -.BR ipvlan " |" -.BR lowpan " |" -.BR geneve " |" -.BR vrf " ]" - .ti -8 .BR "ip link delete " { .IR DEVICE " | " @@ -80,7 +51,12 @@ ip-link \- network device configuration .BR "ip link set " { .IR DEVICE " | " .BI "group " GROUP -.RB "} [ { " up " | " down " } ]" +} +.br +.RB "[ { " up " | " down " } ]" +.br +.RB "[ " type +.IR "ETYPE TYPE_ARGS" " ]" .br .RB "[ " arp " { " on " | " off " } ]" .br @@ -173,7 +149,7 @@ ip-link \- network device configuration .B master .IR DEVICE " ] [" .B type -.IR TYPE " ]" +.IR ETYPE " ]" .B vrf .IR NAME " ]" @@ -181,6 +157,39 @@ ip-link \- network device configuration .B ip link help .RI "[ " TYPE " ]" +.ti -8 +.IR TYPE " := [ " +.BR bridge " | " +.BR bond " | " +.BR can " | " +.BR dummy " | " +.BR hsr " | " +.BR ifb " | " +.BR ipoib " |" +.BR macvlan " | " +.BR macvtap " | " +.BR vcan " | " +.BR veth " | " +.BR vlan " | " +.BR vxlan " |" +.BR ip6tnl " |" +.BR ipip " |" +.BR sit " |" +.BR gre " |" +.BR gretap " |" +.BR ip6gre " |" +.BR ip6gretap " |" +.BR vti " |" +.BR nlmon " |" +.BR ipvlan " |" +.BR lowpan " |" +.BR geneve " |" +.BR vrf " ]" + +.ti -8 +.IR ETYPE " := [ " TYPE " |" +.BR bridge_slave " | " bond_slave " ]" + .SH "DESCRIPTION" .SS ip link add - add virtual link From f9e9f92881fcd8e2241e2f5c6afcdbfb9398bf89 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 9 Jul 2016 11:22:48 +0200 Subject: [PATCH 333/513] ip-link.8: Place 'ip link set' warning more prominently This moves the warning to the beginning of the section about 'ip link set' which makes it still stand out after adding more text to it's end. Signed-off-by: Phil Sutter --- man/man8/ip-link.8.in | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 5d22e1552..d168b6db3 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -1019,6 +1019,18 @@ specifies the type of the device. .SS ip link set - change device attributes +.PP +.B Warning: +If multiple parameter changes are requested, +.B ip +aborts immediately after any of the changes have failed. +This is the only case when +.B ip +can move the system to an unpredictable state. The solution +is to avoid changing several parameters with one +.B ip link set +call. + .TP .BI dev " DEVICE " .I DEVICE @@ -1245,18 +1257,6 @@ set the IPv6 address generation mode .BR "link-netnsid " set peer netnsid for a cross-netns interface -.PP -.B Warning: -If multiple parameter changes are requested, -.B ip -aborts immediately after any of the changes have failed. -This is the only case when -.B ip -can move the system to an unpredictable state. The solution -is to avoid changing several parameters with one -.B ip link set -call. - .SS ip link show - display device attributes .TP From 3dd4b8936bd8c07eaf0f9e410a1b0cebaef77e40 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 9 Jul 2016 11:22:49 +0200 Subject: [PATCH 334/513] ip-link.8: Add slave type option descriptions Signed-off-by: Phil Sutter --- man/man8/ip-link.8.in | 129 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index d168b6db3..a642e08f2 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -1257,6 +1257,135 @@ set the IPv6 address generation mode .BR "link-netnsid " set peer netnsid for a cross-netns interface +.TP +.BI type " ETYPE TYPE_ARGS" +Change type-specific settings. For a list of supported types and arguments refer +to the description of +.B "ip link add" +above. In addition to that, it is possible to manipulate settings to slave +devices: + +.TP +Bridge Slave Support +For a link with master +.B bridge +the following additional arguments are supported: + +.B "ip link set type bridge_slave" +[ +.BI state " STATE" +] [ +.BI priority " PRIO" +] [ +.BI cost " COST" +] [ +.BR guard " { " on " | " off " }" +] [ +.BR hairpin " { " on " | " off " }" +] [ +.BR fastleave " { " on " | " off " }" +] [ +.BR root_block " { " on " | " off " }" +] [ +.BR learning " { " on " | " off " }" +] [ +.BR flood " { " on " | " off " }" +] [ +.BR proxy_arp " { " on " | " off " }" +] [ +.BR proxy_arp_wifi " { " on " | " off " }" +] [ +.BI mcast_router " MULTICAST_ROUTER" +] [ +.BR mcast_fast_leave " { " on " | " off "} ]" + +.in +8 +.sp +.BI state " STATE" +- Set port state. +.I STATE +is a number representing the following states: +.BR 0 " (disabled)," +.BR 1 " (listening)," +.BR 2 " (learning)," +.BR 3 " (forwarding)," +.BR 4 " (blocking)." + +.BI priority " PRIO" +- set port priority (a 16bit unsigned value). + +.BI cost " COST" +- set port cost (a 32bit unsigned value). + +.BR guard " { " on " | " off " }" +- block incoming BPDU packets on this port. + +.BR hairpin " { " on " | " off " }" +- enable hairpin mode on this port. This will allow incoming packets on this +port to be reflected back. + +.BR fastleave " { " on " | " off " }" +- enable multicast fast leave on this port. + +.BR root_block " { " on " | " off " }" +- block this port from becoming the bridge's root port. + +.BR learning " { " on " | " off " }" +- allow MAC address learning on this port. + +.BR flood " { " on " | " off " }" +- open the flood gates on this port, i.e. forward all unicast frames to this +port also. Requires +.BR proxy_arp " and " proxy_arp_wifi +to be turned off. + +.BR proxy_arp " { " on " | " off " }" +- enable proxy ARP on this port. + +.BR proxy_arp_wifi " { " on " | " off " }" +- enable proxy ARP on this port which meets extended requirements by IEEE +802.11 and Hotspot 2.0 specifications. + +.BI mcast_router " MULTICAST_ROUTER" +- configure this port for having multicast routers attached. A port with a +multicast router will receive all multicast traffic. +.I MULTICAST_ROUTER +may be either +.B 0 +to disable multicast routers on this port, +.B 1 +to let the system detect the presence of of routers (this is the default), +.B 2 +to permanently enable multicast traffic forwarding on this port or +.B 3 +to enable multicast routers temporarily on this port, not depending on incoming +queries. + +.BR mcast_fast_leave " { " on " | " off " }" +- this is a synonym to the +.B fastleave +option above. + +.in -8 + +.TP +Bonding Slave Support +For a link with master +.B bond +the following additional arguments are supported: + +.B "ip link set type bond_slave" +[ +.BI queue_id " ID" +] + +.in +8 +.sp +.BI queue_id " ID" +- set the slave's queue ID (a 16bit unsigned value). + +.in -8 + .SS ip link show - display device attributes .TP From 52a598698052773857a2ca590b81940367774fce Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 9 Jul 2016 11:22:50 +0200 Subject: [PATCH 335/513] ip-link.8: Fix font choices Signed-off-by: Phil Sutter --- man/man8/ip-link.8.in | 92 ++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index a642e08f2..2cd613372 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -308,7 +308,7 @@ the following additional arguments are supported: .BI "ip link add .BI link " DEVICE " .BI name " NAME " -.BI type " vlan " +.B "type vlan" [ .BI protocol " VLAN_PROTO " ] @@ -410,7 +410,7 @@ For a link of type the following additional arguments are supported: .BI "ip link add " DEVICE -.BI type " vxlan " id " ID" +.BI type " vxlan " id " VNI" [ .BI dev " PHYS_DEV " .RB " ] [ { " group " | " remote " } " @@ -429,27 +429,27 @@ the following additional arguments are supported: ] [ .BI srcport " MIN MAX " ] [ -.I "[no]learning " +.RB [ no ] learning ] [ -.I "[no]proxy " +.RB [ no ] proxy ] [ -.I "[no]rsc " +.RB [ no ] rsc ] [ -.I "[no]l2miss " +.RB [ no ] l2miss ] [ -.I "[no]l3miss " +.RB [ no ] l3miss ] [ -.I "[no]udpcsum " +.RB [ no ] udpcsum ] [ -.I "[no]udp6zerocsumtx " +.RB [ no ] udp6zerocsumtx ] [ -.I "[no]udp6zerocsumrx " +.RB [ no ] udp6zerocsumrx ] [ .BI ageing " SECONDS " ] [ .BI maxaddress " NUMBER " ] [ -.RI "[no]external " +.RB [ no ] external ] [ .B gbp ] [ @@ -506,36 +506,36 @@ parameter. source ports to communicate to the remote VXLAN tunnel endpoint. .sp -.I [no]learning +.RB [ no ] learning - specifies if unknown source link layer addresses and IP addresses are entered into the VXLAN device forwarding database. .sp -.I [no]rsc +.RB [ no ] rsc - specifies if route short circuit is turned on. .sp -.I [no]proxy +.RB [ no ] proxy - specifies ARP proxy is turned on. .sp -.I [no]l2miss +.RB [ no ] l2miss - specifies if netlink LLADDR miss notifications are generated. .sp -.I [no]l3miss +.RB [ no ] l3miss - specifies if netlink IP ADDR miss notifications are generated. .sp -.I [no]udpcsum +.RB [ no ] udpcsum - specifies if UDP checksum is calculated for transmitted packets over IPv4. .sp -.I [no]udp6zerocsumtx +.RB [ no ] udp6zerocsumtx - skip UDP checksum calculation for transmitted packets over IPv6. .sp -.I [no]udp6zerocsumrx +.RB [ no ] udp6zerocsumrx - allow incoming UDP packets over IPv6 with zero checksum field. .sp @@ -547,7 +547,7 @@ are entered into the VXLAN device forwarding database. - specifies the maximum number of FDB entries. .sp -.I [no]external +.RB [ no ] external - specifies whether an external control plane .RB "(e.g. " "ip route encap" ) or the internal FDB should be used. @@ -611,18 +611,18 @@ For a link of types the following additional arguments are supported: .BI "ip link add " DEVICE -.BR type " { gre | ipip | sit } " +.BR type " { " gre " | " ipip " | " sit " }" .BI " remote " ADDR " local " ADDR [ -.BR encap " { fou | gue | none } " +.BR encap " { " fou " | " gue " | " none " }" ] [ -.BI "encap-sport { " PORT " | auto } " +.BR encap-sport " { " \fIPORT " | " auto " }" ] [ .BI "encap-dport " PORT ] [ -.I " [no]encap-csum " +.RB [ no ] encap-csum ] [ -.I " [no]encap-remcsum " +.RB [ no ] encap-remcsum ] .in +8 @@ -636,12 +636,12 @@ the following additional arguments are supported: It must be an address on another interface on this host. .sp -.BR encap " { fou | gue | none } " +.BR encap " { " fou " | " gue " | " none " }" - specifies type of secondary UDP encapsulation. "fou" indicates Foo-Over-UDP, "gue" indicates Generic UDP Encapsulation. .sp -.BI "encap-sport { " PORT " | auto } " +.BR encap-sport " { " \fIPORT " | " auto " }" - specifies the source port in UDP encapsulation. .IR PORT indicates the port by number, "auto" @@ -650,12 +650,12 @@ indicates that the port number should be chosen automatically encapsulated packet). .sp -.I [no]encap-csum +.RB [ no ] encap-csum - specifies if UDP checksums are enabled in the secondary encapsulation. .sp -.I [no]encap-remcsum +.RB [ no ] encap-remcsum - specifies if Remote Checksum Offload is enabled. This is only applicable for Generic UDP Encapsulation. @@ -668,13 +668,15 @@ For a link of type the following additional arguments are supported: .BI "ip link add " DEVICE -.BI type " { ip6gre | ip6gretap } " remote " ADDR " local " ADDR +.BR type " { " ip6gre " | " ip6gretap " }" +.BI remote " ADDR " local " ADDR" [ -.I "[i|o]seq]" +.RB [ i | o ] seq ] [ -.I "[i|o]key" KEY +.RB [ i | o ] key +.I KEY ] [ -.I " [i|o]csum " +.RB [ i | o ] csum ] [ .BI hoplimit " TTL " ] [ @@ -700,7 +702,7 @@ the following additional arguments are supported: It must be an address on another interface on this host. .sp -.BI [i|o]seq +.RB [ i | o ] seq - serialize packets. The .B oseq @@ -710,7 +712,7 @@ The flag requires that all input packets are serialized. .sp -.BI [i|o]key " KEY" +.RB [ i | o ] key " \fIKEY" - use keyed GRE with key .IR KEY ". "KEY is either a number or an IPv4 address-like dotted quad. @@ -722,7 +724,7 @@ The parameters specify different keys for input and output. .sp -.BI [i|o]csum +.RB [ i | o ] csum - generate/require checksums for tunneled packets. The .B ocsum @@ -774,7 +776,7 @@ For a link of type the following additional arguments are supported: .BI "ip link add " DEVICE " name " NAME -.BI type " ipoib [ " pkey " PKEY ] [" mode " MODE " ] +.BR "type ipoib " [ " pkey \fIPKEY" " ] [ " mode " \fIMODE \fR]" .in +8 .sp @@ -791,7 +793,7 @@ For a link of type the following additional arguments are supported: .BI "ip link add " DEVICE -.BI type " geneve " id " ID " remote " IPADDR" +.BI type " geneve " id " VNI " remote " IPADDR" [ .BI ttl " TTL " ] [ @@ -834,7 +836,7 @@ the following additional arguments are supported: .BI "ip link add link " DEVICE " name " NAME .BR type " { " macvlan " | " macvtap " } " .BR mode " { " private " | " vepa " | " bridge " | " passthru -.BR " [ " nopromisc " ] } " +.RB " [ " nopromisc " ] } " .in +8 .sp @@ -879,11 +881,11 @@ For a link of type .I HSR the following additional arguments are supported: -.BI "ip link add link " DEVICE " name " NAME -.BI type " hsr " +.BI "ip link add link " DEVICE " name " NAME " type hsr" .BI slave1 " SLAVE1-IF " slave2 " SLAVE2-IF " -.BR " [ supervision " ADDR-BYTE " ] " -.BR " [ version { " 0 " | " 1 " } ] " +.RB [ " supervision" +.IR ADDR-BYTE " ] [" +.BR version " { " 0 " | " 1 " } ]" .in +8 .sp @@ -896,11 +898,11 @@ the following additional arguments are supported: .BI slave2 " SLAVE2-IF " - Specifies the physical device used for the second of the two ring ports. -.BR "supervision ADDR-BYTE " +.BI supervision " ADDR-BYTE" - The last byte of the multicast address used for HSR supervision frames. Default option is "0", possible values 0-255. -.BR "version { 0 | 1 }" +.BR version " { " 0 " | " 1 " }" - Selects the protocol version of the interface. Default option is "0", which corresponds to the 2010 version of the HSR standard. Option "1" activates the 2012 version. From d892aaf7400ac410864ab03b48891e34206b1307 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 18 Jul 2016 16:48:41 +0200 Subject: [PATCH 336/513] tc: m_action: Improve conversion to C99 style initializers This improves my initial change in the following points: - Flatten embedded struct's initializers. - No need to initialize variables to zero as the key feature of C99 initializers is to do this implicitly. - By relocating the declaration of struct rtattr *tail, it can be initialized at the same time. Fixes: a0a73b298a579 ("tc: m_action: Use C99 style initializers for struct req") Signed-off-by: Phil Sutter Acked-by: David Ahern --- tc/m_action.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/tc/m_action.c b/tc/m_action.c index ea16817ae..806fdd197 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -395,13 +395,10 @@ static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p struct tcamsg t; char buf[MAX_MSG]; } req = { - .n = { - .nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)), - .nlmsg_flags = NLM_F_REQUEST | flags, - .nlmsg_type = cmd, - }, + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, .t.tca_family = AF_UNSPEC, - .buf = { 0 } }; argc -= 1; @@ -491,23 +488,18 @@ static int tc_action_modify(int cmd, unsigned int flags, int *argc_p, char ***ar int argc = *argc_p; char **argv = *argv_p; int ret = 0; - - struct rtattr *tail; struct { struct nlmsghdr n; struct tcamsg t; char buf[MAX_MSG]; } req = { - .n = { - .nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)), - .nlmsg_flags = NLM_F_REQUEST | flags, - .nlmsg_type = cmd, - }, + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, .t.tca_family = AF_UNSPEC, - .buf = { 0 } }; + struct rtattr *tail = NLMSG_TAIL(&req.n); - tail = NLMSG_TAIL(&req.n); argc -= 1; argv += 1; if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) { @@ -540,7 +532,6 @@ static int tc_act_list_or_flush(int argc, char **argv, int event) } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)), .t.tca_family = AF_UNSPEC, - .buf = { 0 } }; tail = NLMSG_TAIL(&req.n); From d17b136f7d7dd6ed7ea518e4f068d3de735e8756 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 18 Jul 2016 16:48:42 +0200 Subject: [PATCH 337/513] Use C99 style initializers everywhere This big patch was compiled by vimgrepping for memset calls and changing to C99 initializer if applicable. One notable exception is the initialization of union bpf_attr in tc/tc_bpf.c: changing it would break for older gcc versions (at least <=3.4.6). Calls to memset for struct rtattr pointer fields for parse_rtattr*() were just dropped since they are not needed. The changes here allowed the compiler to discover some unused variables, so get rid of them, too. Signed-off-by: Phil Sutter Acked-by: David Ahern --- bridge/fdb.c | 25 +++++------ bridge/link.c | 14 +++--- bridge/mdb.c | 17 +++----- bridge/vlan.c | 17 +++----- genl/ctrl.c | 44 ++++++++----------- ip/ip6tunnel.c | 10 ++--- ip/ipaddress.c | 31 ++++++------- ip/ipaddrlabel.c | 21 ++++----- ip/iplink.c | 61 +++++++++++--------------- ip/iplink_can.c | 4 +- ip/ipmaddr.c | 25 ++++------- ip/ipmroute.c | 8 +--- ip/ipneigh.c | 30 ++++++------- ip/ipnetconf.c | 10 ++--- ip/ipnetns.c | 39 ++++++++--------- ip/ipntable.c | 25 ++++------- ip/iproute.c | 78 ++++++++++++--------------------- ip/iprule.c | 22 ++++------ ip/iptoken.c | 19 +++----- ip/iptunnel.c | 31 ++++--------- ip/ipxfrm.c | 26 +++-------- ip/link_gre.c | 18 ++++---- ip/link_gre6.c | 18 ++++---- ip/link_ip6tnl.c | 25 +++++------ ip/link_iptnl.c | 22 ++++------ ip/link_vti.c | 18 ++++---- ip/link_vti6.c | 18 ++++---- ip/xfrm_policy.c | 99 +++++++++++++++++------------------------- ip/xfrm_state.c | 110 +++++++++++++++++++---------------------------- lib/libnetlink.c | 77 ++++++++++++--------------------- lib/ll_map.c | 1 - misc/arpd.c | 64 ++++++++++++--------------- misc/ss.c | 37 ++++++---------- tc/e_bpf.c | 7 +-- tc/em_cmp.c | 4 +- tc/em_ipset.c | 4 +- tc/em_meta.c | 4 +- tc/em_nbyte.c | 4 +- tc/em_u32.c | 4 +- tc/f_flow.c | 3 -- tc/f_flower.c | 3 +- tc/f_fw.c | 6 +-- tc/f_route.c | 3 -- tc/f_rsvp.c | 6 +-- tc/f_u32.c | 12 ++---- tc/m_bpf.c | 5 +-- tc/m_csum.c | 4 +- tc/m_ematch.c | 4 +- tc/m_gact.c | 5 +-- tc/m_ife.c | 5 +-- tc/m_mirred.c | 7 +-- tc/m_nat.c | 4 +- tc/m_pedit.c | 8 +--- tc/m_police.c | 5 +-- tc/q_atm.c | 3 +- tc/q_cbq.c | 22 +++------- tc/q_choke.c | 4 +- tc/q_codel.c | 3 +- tc/q_dsmark.c | 1 - tc/q_fifo.c | 4 +- tc/q_fq_codel.c | 3 +- tc/q_hfsc.c | 13 ++---- tc/q_htb.c | 15 +++---- tc/q_netem.c | 16 +++---- tc/q_red.c | 4 +- tc/q_sfb.c | 17 ++++---- tc/q_sfq.c | 4 +- tc/q_tbf.c | 4 +- tc/tc_bpf.c | 54 ++++++++--------------- tc/tc_class.c | 31 +++++-------- tc/tc_exec.c | 3 +- tc/tc_filter.c | 33 +++++--------- tc/tc_qdisc.c | 33 +++++--------- tc/tc_stab.c | 4 +- tc/tc_util.c | 3 +- 75 files changed, 532 insertions(+), 913 deletions(-) diff --git a/bridge/fdb.c b/bridge/fdb.c index 3d1ef6c88..c6e03793a 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -289,16 +289,15 @@ static int fdb_show(int argc, char **argv) struct nlmsghdr n; struct ifinfomsg ifm; char buf[256]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .ifm.ifi_family = PF_BRIDGE, + }; char *filter_dev = NULL; char *br = NULL; int msg_size = sizeof(struct ifinfomsg); - memset(&req, 0, sizeof(req)); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.ifm.ifi_family = PF_BRIDGE; - while (argc > 0) { if ((strcmp(*argv, "brport") == 0) || strcmp(*argv, "dev") == 0) { NEXT_ARG(); @@ -371,7 +370,13 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv) struct nlmsghdr n; struct ndmsg ndm; char buf[256]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .ndm.ndm_family = PF_BRIDGE, + .ndm.ndm_state = NUD_NOARP, + }; char *addr = NULL; char *d = NULL; char abuf[ETH_ALEN]; @@ -383,14 +388,6 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv) char *endptr; short vid = -1; - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - req.ndm.ndm_family = PF_BRIDGE; - req.ndm.ndm_state = NUD_NOARP; - while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); diff --git a/bridge/link.c b/bridge/link.c index b347040cc..13f606c7d 100644 --- a/bridge/link.c +++ b/bridge/link.c @@ -255,7 +255,12 @@ static int brlink_modify(int argc, char **argv) struct nlmsghdr n; struct ifinfomsg ifm; char buf[512]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_SETLINK, + .ifm.ifi_family = PF_BRIDGE, + }; char *d = NULL; __s8 learning = -1; __s8 learning_sync = -1; @@ -271,13 +276,6 @@ static int brlink_modify(int argc, char **argv) __u16 flags = 0; struct rtattr *nest; - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_SETLINK; - req.ifm.ifi_family = PF_BRIDGE; - while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); diff --git a/bridge/mdb.c b/bridge/mdb.c index 6c904f8e6..e60ff3ef3 100644 --- a/bridge/mdb.c +++ b/bridge/mdb.c @@ -234,19 +234,16 @@ static int mdb_modify(int cmd, int flags, int argc, char **argv) struct nlmsghdr n; struct br_port_msg bpm; char buf[1024]; - } req; - struct br_mdb_entry entry; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .bpm.family = PF_BRIDGE, + }; + struct br_mdb_entry entry = {}; char *d = NULL, *p = NULL, *grp = NULL; short vid = 0; - memset(&req, 0, sizeof(req)); - memset(&entry, 0, sizeof(entry)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - req.bpm.family = PF_BRIDGE; - while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); diff --git a/bridge/vlan.c b/bridge/vlan.c index 5dd352e65..f262cc7f1 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -32,22 +32,19 @@ static int vlan_modify(int cmd, int argc, char **argv) struct nlmsghdr n; struct ifinfomsg ifm; char buf[1024]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = cmd, + .ifm.ifi_family = PF_BRIDGE, + }; char *d = NULL; short vid = -1; short vid_end = -1; struct rtattr *afspec; - struct bridge_vlan_info vinfo; + struct bridge_vlan_info vinfo = {}; unsigned short flags = 0; - memset(&vinfo, 0, sizeof(vinfo)); - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = cmd; - req.ifm.ifi_family = PF_BRIDGE; - while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); diff --git a/genl/ctrl.c b/genl/ctrl.c index ffa34af56..6abd52582 100644 --- a/genl/ctrl.c +++ b/genl/ctrl.c @@ -42,23 +42,19 @@ static int usage(void) int genl_ctrl_resolve_family(const char *family) { struct rtnl_handle rth; - struct nlmsghdr *nlh; - struct genlmsghdr *ghdr; int ret = 0; struct { struct nlmsghdr n; + struct genlmsghdr g; char buf[4096]; - } req; - - memset(&req, 0, sizeof(req)); - - nlh = &req.n; - nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - nlh->nlmsg_type = GENL_ID_CTRL; - - ghdr = NLMSG_DATA(&req.n); - ghdr->cmd = CTRL_CMD_GETFAMILY; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN), + .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, + .n.nlmsg_type = GENL_ID_CTRL, + .g.cmd = CTRL_CMD_GETFAMILY, + }; + struct nlmsghdr *nlh = &req.n; + struct genlmsghdr *ghdr = &req.g; if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) { fprintf(stderr, "Cannot open generic netlink socket\n"); @@ -74,7 +70,6 @@ int genl_ctrl_resolve_family(const char *family) { struct rtattr *tb[CTRL_ATTR_MAX + 1]; - struct genlmsghdr *ghdr = NLMSG_DATA(nlh); int len = nlh->nlmsg_len; struct rtattr *attrs; @@ -291,24 +286,19 @@ static int print_ctrl2(const struct sockaddr_nl *who, static int ctrl_list(int cmd, int argc, char **argv) { struct rtnl_handle rth; - struct nlmsghdr *nlh; - struct genlmsghdr *ghdr; int ret = -1; char d[GENL_NAMSIZ]; struct { struct nlmsghdr n; + struct genlmsghdr g; char buf[4096]; - } req; - - memset(&req, 0, sizeof(req)); - - nlh = &req.n; - nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - nlh->nlmsg_type = GENL_ID_CTRL; - - ghdr = NLMSG_DATA(&req.n); - ghdr->cmd = CTRL_CMD_GETFAMILY; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN), + .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, + .n.nlmsg_type = GENL_ID_CTRL, + .g.cmd = CTRL_CMD_GETFAMILY, + }; + struct nlmsghdr *nlh = &req.n; if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) { fprintf(stderr, "Cannot open generic netlink socket\n"); diff --git a/ip/ip6tunnel.c b/ip/ip6tunnel.c index c02fa0746..ce760bd0b 100644 --- a/ip/ip6tunnel.c +++ b/ip/ip6tunnel.c @@ -135,9 +135,7 @@ static void print_tunnel(struct ip6_tnl_parm2 *p) static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm2 *p) { int count = 0; - char medium[IFNAMSIZ]; - - memset(medium, 0, sizeof(medium)); + char medium[IFNAMSIZ] = {}; while (argc > 0) { if (strcmp(*argv, "mode") == 0) { @@ -276,9 +274,8 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm2 *p) duparg2("name", *argv); strncpy(p->name, *argv, IFNAMSIZ - 1); if (cmd == SIOCCHGTUNNEL && count == 0) { - struct ip6_tnl_parm2 old_p; + struct ip6_tnl_parm2 old_p = {}; - memset(&old_p, 0, sizeof(old_p)); if (tnl_get_ioctl(*argv, &old_p)) return -1; *p = old_p; @@ -351,7 +348,7 @@ static int do_tunnels_list(struct ip6_tnl_parm2 *p) while (fgets(buf, sizeof(buf), fp) != NULL) { char name[IFNAMSIZ]; int index, type; - struct ip6_tnl_parm2 p1; + struct ip6_tnl_parm2 p1 = {}; char *ptr; buf[sizeof(buf) - 1] = '\0'; @@ -372,7 +369,6 @@ static int do_tunnels_list(struct ip6_tnl_parm2 *p) } if (type != ARPHRD_TUNNEL6 && type != ARPHRD_IP6GRE) continue; - memset(&p1, 0, sizeof(p1)); ip6_tnl_parm_init(&p1, 0); if (type == ARPHRD_IP6GRE) p1.proto = IPPROTO_GRE; diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 88e966222..cfcebe76a 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -173,13 +173,12 @@ static void print_queuelen(FILE *f, struct rtattr *tb[IFLA_MAX + 1]) if (tb[IFLA_TXQLEN]) qlen = *(int *)RTA_DATA(tb[IFLA_TXQLEN]); else { - struct ifreq ifr; + struct ifreq ifr = {}; int s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) return; - memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, rta_getattr_str(tb[IFLA_IFNAME])); if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) { fprintf(f, "ioctl(SIOCGIFTXQLEN) failed: %s\n", strerror(errno)); @@ -1037,10 +1036,8 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, } if (filter.pfx.family) { if (rta_tb[IFA_LOCAL]) { - inet_prefix dst; + inet_prefix dst = { .family = ifa->ifa_family }; - memset(&dst, 0, sizeof(dst)); - dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) return 0; @@ -1396,10 +1393,10 @@ static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (filter.pfx.family && tb[IFA_LOCAL]) { - inet_prefix dst; + inet_prefix dst = { + .family = ifa->ifa_family + }; - memset(&dst, 0, sizeof(dst)); - dst.family = ifa->ifa_family; memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) continue; @@ -1845,7 +1842,12 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv) struct nlmsghdr n; struct ifaddrmsg ifa; char buf[256]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .ifa.ifa_family = preferred_family, + }; char *d = NULL; char *l = NULL; char *lcl_arg = NULL; @@ -1860,16 +1862,8 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv) int scoped = 0; __u32 preferred_lft = INFINITY_LIFE_TIME; __u32 valid_lft = INFINITY_LIFE_TIME; - struct ifa_cacheinfo cinfo; unsigned int ifa_flags = 0; - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST | flags; - req.n.nlmsg_type = cmd; - req.ifa.ifa_family = preferred_family; - while (argc > 0) { if (strcmp(*argv, "peer") == 0 || strcmp(*argv, "remote") == 0) { @@ -2026,6 +2020,8 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv) } if (valid_lftp || preferred_lftp) { + struct ifa_cacheinfo cinfo = {}; + if (!valid_lft) { fprintf(stderr, "valid_lft is zero\n"); return -1; @@ -2035,7 +2031,6 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv) return -1; } - memset(&cinfo, 0, sizeof(cinfo)); cinfo.ifa_prefered = preferred_lft; cinfo.ifa_valid = valid_lft; addattr_l(&req.n, sizeof(req), IFA_CACHEINFO, &cinfo, diff --git a/ip/ipaddrlabel.c b/ip/ipaddrlabel.c index b4cd78409..1d324dac0 100644 --- a/ip/ipaddrlabel.c +++ b/ip/ipaddrlabel.c @@ -127,23 +127,18 @@ static int ipaddrlabel_modify(int cmd, int argc, char **argv) struct nlmsghdr n; struct ifaddrlblmsg ifal; char buf[1024]; - } req; - - inet_prefix prefix; + } req = { + .n.nlmsg_type = cmd, + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .ifal.ifal_family = preferred_family, + }; + + inet_prefix prefix = {}; uint32_t label = 0xffffffffUL; char *p = NULL; char *l = NULL; - memset(&req, 0, sizeof(req)); - memset(&prefix, 0, sizeof(prefix)); - - req.n.nlmsg_type = cmd; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.ifal.ifal_family = preferred_family; - req.ifal.ifal_prefixlen = 0; - req.ifal.ifal_index = 0; - if (cmd == RTM_NEWADDRLABEL) { req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; } diff --git a/ip/iplink.c b/ip/iplink.c index 5609cc95b..ef17fd9d2 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -208,16 +208,14 @@ static int iplink_have_newlink(void) struct nlmsghdr n; struct ifinfomsg i; char buf[1024]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, + .n.nlmsg_type = RTM_NEWLINK, + .i.ifi_family = AF_UNSPEC, + }; if (have_rtnl_newlink < 0) { - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; - req.n.nlmsg_type = RTM_NEWLINK; - req.i.ifi_family = AF_UNSPEC; - if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) { perror("request send failed"); exit(1); @@ -783,16 +781,14 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) int index = -1; int group; struct link_util *lu = NULL; - struct iplink_req req; + struct iplink_req req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .i.ifi_family = preferred_family, + }; int ret; - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - req.i.ifi_family = preferred_family; - ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group, &index); if (ret < 0) @@ -925,19 +921,17 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) int iplink_get(unsigned int flags, char *name, __u32 filt_mask) { int len; - struct iplink_req req; + struct iplink_req req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = RTM_GETLINK, + .i.ifi_family = preferred_family, + }; struct { struct nlmsghdr n; char buf[16384]; } answer; - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = RTM_GETLINK; - req.i.ifi_family = preferred_family; - if (name) { len = strlen(name) + 1; if (len == 1) @@ -1031,16 +1025,14 @@ static int do_changename(const char *dev, const char *newdev) static int set_qlen(const char *dev, int qlen) { - struct ifreq ifr; + struct ifreq ifr = { .ifr_qlen = qlen }; int s; s = get_ctl_fd(); if (s < 0) return -1; - memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev, IFNAMSIZ); - ifr.ifr_qlen = qlen; if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) { perror("SIOCSIFXQLEN"); close(s); @@ -1053,16 +1045,14 @@ static int set_qlen(const char *dev, int qlen) static int set_mtu(const char *dev, int mtu) { - struct ifreq ifr; + struct ifreq ifr = { .ifr_mtu = mtu }; int s; s = get_ctl_fd(); if (s < 0) return -1; - memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev, IFNAMSIZ); - ifr.ifr_mtu = mtu; if (ioctl(s, SIOCSIFMTU, &ifr) < 0) { perror("SIOCSIFMTU"); close(s); @@ -1075,8 +1065,11 @@ static int set_mtu(const char *dev, int mtu) static int get_address(const char *dev, int *htype) { - struct ifreq ifr; - struct sockaddr_ll me; + struct ifreq ifr = {}; + struct sockaddr_ll me = { + .sll_family = AF_PACKET, + .sll_protocol = htons(ETH_P_LOOP), + }; socklen_t alen; int s; @@ -1086,7 +1079,6 @@ static int get_address(const char *dev, int *htype) return -1; } - memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev, IFNAMSIZ); if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { perror("SIOCGIFINDEX"); @@ -1094,10 +1086,7 @@ static int get_address(const char *dev, int *htype) return -1; } - memset(&me, 0, sizeof(me)); - me.sll_family = AF_PACKET; me.sll_ifindex = ifr.ifr_ifindex; - me.sll_protocol = htons(ETH_P_LOOP); if (bind(s, (struct sockaddr *)&me, sizeof(me)) == -1) { perror("bind"); close(s); diff --git a/ip/iplink_can.c b/ip/iplink_can.c index a00d42311..aecad76bc 100644 --- a/ip/iplink_can.c +++ b/ip/iplink_can.c @@ -110,11 +110,9 @@ static void print_ctrlmode(FILE *f, __u32 cm) static int can_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { - struct can_bittiming bt, dbt; + struct can_bittiming bt = {}, dbt = {}; struct can_ctrlmode cm = {0, 0}; - memset(&bt, 0, sizeof(bt)); - memset(&dbt, 0, sizeof(dbt)); while (argc > 0) { if (matches(*argv, "bitrate") == 0) { NEXT_ARG(); diff --git a/ip/ipmaddr.c b/ip/ipmaddr.c index c3673979f..22eb407b4 100644 --- a/ip/ipmaddr.c +++ b/ip/ipmaddr.c @@ -93,18 +93,15 @@ static void read_dev_mcast(struct ma_info **result_p) while (fgets(buf, sizeof(buf), fp)) { char hexa[256]; - struct ma_info m; + struct ma_info m = { .addr.family = AF_PACKET }; int len; int st; - memset(&m, 0, sizeof(m)); sscanf(buf, "%d%s%d%d%s", &m.index, m.name, &m.users, &st, hexa); if (filter.dev && strcmp(filter.dev, m.name)) continue; - m.addr.family = AF_PACKET; - len = parse_hex(hexa, (unsigned char *)&m.addr.data, sizeof(m.addr.data)); if (len >= 0) { struct ma_info *ma = malloc(sizeof(m)); @@ -122,22 +119,21 @@ static void read_dev_mcast(struct ma_info **result_p) static void read_igmp(struct ma_info **result_p) { - struct ma_info m; + struct ma_info m = { + .addr.family = AF_INET, + .addr.bitlen = 32, + .addr.bytelen = 4, + }; char buf[256]; FILE *fp = fopen("/proc/net/igmp", "r"); if (!fp) return; - memset(&m, 0, sizeof(m)); if (!fgets(buf, sizeof(buf), fp)) { fclose(fp); return; } - m.addr.family = AF_INET; - m.addr.bitlen = 32; - m.addr.bytelen = 4; - while (fgets(buf, sizeof(buf), fp)) { struct ma_info *ma; @@ -169,17 +165,14 @@ static void read_igmp6(struct ma_info **result_p) while (fgets(buf, sizeof(buf), fp)) { char hexa[256]; - struct ma_info m; + struct ma_info m = { .addr.family = AF_INET6 }; int len; - memset(&m, 0, sizeof(m)); sscanf(buf, "%d%s%s%d", &m.index, m.name, hexa, &m.users); if (filter.dev && strcmp(filter.dev, m.name)) continue; - m.addr.family = AF_INET6; - len = parse_hex(hexa, (unsigned char *)&m.addr.data, sizeof(m.addr.data)); if (len >= 0) { struct ma_info *ma = malloc(sizeof(m)); @@ -274,11 +267,9 @@ static int multiaddr_list(int argc, char **argv) static int multiaddr_modify(int cmd, int argc, char **argv) { - struct ifreq ifr; + struct ifreq ifr = {}; int fd; - memset(&ifr, 0, sizeof(ifr)); - if (cmd == RTM_NEWADDR) cmd = SIOCADDMULTI; else diff --git a/ip/ipmroute.c b/ip/ipmroute.c index c33cdcbbd..5d6922a23 100644 --- a/ip/ipmroute.c +++ b/ip/ipmroute.c @@ -97,20 +97,16 @@ int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) return 0; if (tb[RTA_DST] && filter.mdst.bitlen > 0) { - inet_prefix dst; + inet_prefix dst = { .family = r->rtm_family }; - memset(&dst, 0, sizeof(dst)); - dst.family = r->rtm_family; memcpy(&dst.data, RTA_DATA(tb[RTA_DST]), RTA_PAYLOAD(tb[RTA_DST])); if (inet_addr_match(&dst, &filter.mdst, filter.mdst.bitlen)) return 0; } if (tb[RTA_SRC] && filter.msrc.bitlen > 0) { - inet_prefix src; + inet_prefix src = { .family = r->rtm_family }; - memset(&src, 0, sizeof(src)); - src.family = r->rtm_family; memcpy(&src.data, RTA_DATA(tb[RTA_SRC]), RTA_PAYLOAD(tb[RTA_SRC])); if (inet_addr_match(&src, &filter.msrc, filter.msrc.bitlen)) return 0; diff --git a/ip/ipneigh.c b/ip/ipneigh.c index 3e4447126..4d8fc8521 100644 --- a/ip/ipneigh.c +++ b/ip/ipneigh.c @@ -101,7 +101,13 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv) struct nlmsghdr n; struct ndmsg ndm; char buf[256]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .ndm.ndm_family = preferred_family, + .ndm.ndm_state = NUD_PERMANENT, + }; char *dev = NULL; int dst_ok = 0; int dev_ok = 0; @@ -109,14 +115,6 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv) char *lla = NULL; inet_prefix dst; - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - req.ndm.ndm_family = preferred_family; - req.ndm.ndm_state = NUD_PERMANENT; - while (argc > 0) { if (matches(*argv, "lladdr") == 0) { NEXT_ARG(); @@ -239,10 +237,8 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (tb[NDA_DST]) { if (filter.pfx.family) { - inet_prefix dst; + inet_prefix dst = { .family = r->ndm_family }; - memset(&dst, 0, sizeof(dst)); - dst.family = r->ndm_family; memcpy(&dst.data, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen)) return 0; @@ -348,15 +344,13 @@ static int do_show_or_flush(int argc, char **argv, int flush) struct nlmsghdr n; struct ndmsg ndm; char buf[256]; - } req; + } req = { + .n.nlmsg_type = RTM_GETNEIGH, + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)), + }; char *filter_dev = NULL; int state_given = 0; - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_type = RTM_GETNEIGH; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); - ipneigh_reset_filter(0); if (!filter.family) diff --git a/ip/ipnetconf.c b/ip/ipnetconf.c index 5fdbfb644..50c4e33cf 100644 --- a/ip/ipnetconf.c +++ b/ip/ipnetconf.c @@ -154,7 +154,11 @@ static int do_show(int argc, char **argv) struct nlmsghdr n; struct netconfmsg ncm; char buf[1024]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg)), + .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, + .n.nlmsg_type = RTM_GETNETCONF, + }; ipnetconf_reset_filter(0); filter.family = preferred_family; @@ -176,10 +180,6 @@ static int do_show(int argc, char **argv) ll_init_map(&rth); if (filter.ifindex) { - memset(&req, 0, sizeof(req)); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; - req.n.nlmsg_type = RTM_GETNETCONF; req.ncm.ncm_family = filter.family; if (filter.ifindex) addattr_l(&req.n, sizeof(req), NETCONFA_IFINDEX, diff --git a/ip/ipnetns.c b/ip/ipnetns.c index b3ee23c23..af8706530 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -61,16 +61,15 @@ static int ipnetns_have_nsid(void) struct nlmsghdr n; struct rtgenmsg g; char buf[1024]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_GETNSID, + .g.rtgen_family = AF_UNSPEC, + }; int fd; if (have_rtnl_getnsid < 0) { - memset(&req, 0, sizeof(req)); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_GETNSID; - req.g.rtgen_family = AF_UNSPEC; - fd = open("/proc/self/ns/net", O_RDONLY); if (fd < 0) { perror("open(\"/proc/self/ns/net\")"); @@ -96,17 +95,16 @@ static int get_netnsid_from_name(const char *name) struct nlmsghdr n; struct rtgenmsg g; char buf[1024]; - } req, answer; + } answer, req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_GETNSID, + .g.rtgen_family = AF_UNSPEC, + }; struct rtattr *tb[NETNSA_MAX + 1]; struct rtgenmsg *rthdr; int len, fd; - memset(&req, 0, sizeof(req)); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_GETNSID; - req.g.rtgen_family = AF_UNSPEC; - fd = netns_get_fd(name); if (fd < 0) return fd; @@ -685,15 +683,14 @@ static int set_netnsid_from_name(const char *name, int nsid) struct nlmsghdr n; struct rtgenmsg g; char buf[1024]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_NEWNSID, + .g.rtgen_family = AF_UNSPEC, + }; int fd, err = 0; - memset(&req, 0, sizeof(req)); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_NEWNSID; - req.g.rtgen_family = AF_UNSPEC; - fd = netns_get_fd(name); if (fd < 0) return fd; diff --git a/ip/ipntable.c b/ip/ipntable.c index 8e78773d0..879626ee4 100644 --- a/ip/ipntable.c +++ b/ip/ipntable.c @@ -66,26 +66,19 @@ static int ipntable_modify(int cmd, int flags, int argc, char **argv) struct nlmsghdr n; struct ndtmsg ndtm; char buf[1024]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .ndtm.ndtm_family = preferred_family, + }; char *namep = NULL; char *threshsp = NULL; char *gc_intp = NULL; - char parms_buf[1024]; + char parms_buf[1024] = {}; struct rtattr *parms_rta = (struct rtattr *)parms_buf; int parms_change = 0; - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - - req.ndtm.ndtm_family = preferred_family; - req.ndtm.ndtm_pad1 = 0; - req.ndtm.ndtm_pad2 = 0; - - memset(&parms_buf, 0, sizeof(parms_buf)); - parms_rta->rta_type = NDTA_PARMS; parms_rta->rta_len = RTA_LENGTH(0); @@ -322,15 +315,13 @@ static int ipntable_modify(int cmd, int flags, int argc, char **argv) static const char *ntable_strtime_delta(__u32 msec) { static char str[32]; - struct timeval now; + struct timeval now = {}; time_t t; struct tm *tp; if (msec == 0) goto error; - memset(&now, 0, sizeof(now)); - if (gettimeofday(&now, NULL) < 0) { perror("gettimeofday"); goto error; diff --git a/ip/iproute.c b/ip/iproute.c index c564fa6d3..c52294d29 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -140,10 +140,10 @@ static int flush_update(void) static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) { struct rtmsg *r = NLMSG_DATA(n); - inet_prefix dst; - inet_prefix src; - inet_prefix via; - inet_prefix prefsrc; + inet_prefix dst = { .family = r->rtm_family }; + inet_prefix src = { .family = r->rtm_family }; + inet_prefix via = { .family = r->rtm_family }; + inet_prefix prefsrc = { .family = r->rtm_family }; __u32 table; static int ip6_multiple_tables; @@ -211,19 +211,13 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family) return 0; - memset(&dst, 0, sizeof(dst)); - dst.family = r->rtm_family; if (tb[RTA_DST]) memcpy(&dst.data, RTA_DATA(tb[RTA_DST]), (r->rtm_dst_len+7)/8); if (filter.rsrc.family || filter.msrc.family) { - memset(&src, 0, sizeof(src)); - src.family = r->rtm_family; if (tb[RTA_SRC]) memcpy(&src.data, RTA_DATA(tb[RTA_SRC]), (r->rtm_src_len+7)/8); } if (filter.rvia.bitlen > 0) { - memset(&via, 0, sizeof(via)); - via.family = r->rtm_family; if (tb[RTA_GATEWAY]) memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len/8); if (tb[RTA_VIA]) { @@ -235,8 +229,6 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) } } if (filter.rprefsrc.bitlen > 0) { - memset(&prefsrc, 0, sizeof(prefsrc)); - prefsrc.family = r->rtm_family; if (tb[RTA_PREFSRC]) memcpy(&prefsrc.data, RTA_DATA(tb[RTA_PREFSRC]), host_len/8); } @@ -829,7 +821,14 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv) struct nlmsghdr n; struct rtmsg r; char buf[1024]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .r.rtm_family = preferred_family, + .r.rtm_table = RT_TABLE_MAIN, + .r.rtm_scope = RT_SCOPE_NOWHERE, + }; char mxbuf[256]; struct rtattr *mxrta = (void *)mxbuf; unsigned int mxlock = 0; @@ -842,15 +841,6 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv) int raw = 0; int type_ok = 0; - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - req.r.rtm_family = preferred_family; - req.r.rtm_table = RT_TABLE_MAIN; - req.r.rtm_scope = RT_SCOPE_NOWHERE; - if (cmd != RTM_DELROUTE) { req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_scope = RT_SCOPE_UNIVERSE; @@ -1277,20 +1267,15 @@ static int rtnl_rtcache_request(struct rtnl_handle *rth, int family) struct { struct nlmsghdr nlh; struct rtmsg rtm; - } req; - struct sockaddr_nl nladdr; - - memset(&nladdr, 0, sizeof(nladdr)); - memset(&req, 0, sizeof(req)); - nladdr.nl_family = AF_NETLINK; - - req.nlh.nlmsg_len = sizeof(req); - req.nlh.nlmsg_type = RTM_GETROUTE; - req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST; - req.nlh.nlmsg_pid = 0; - req.nlh.nlmsg_seq = rth->dump = ++rth->seq; - req.rtm.rtm_family = family; - req.rtm.rtm_flags |= RTM_F_CLONED; + } req = { + .nlh.nlmsg_len = sizeof(req), + .nlh.nlmsg_type = RTM_GETROUTE, + .nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST, + .nlh.nlmsg_seq = rth->dump = ++rth->seq, + .rtm.rtm_family = family, + .rtm.rtm_flags = RTM_F_CLONED, + }; + struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; return sendto(rth->fd, (void *)&req, sizeof(req), 0, (struct sockaddr *)&nladdr, sizeof(nladdr)); } @@ -1641,30 +1626,21 @@ static int iproute_get(int argc, char **argv) struct nlmsghdr n; struct rtmsg r; char buf[1024]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_GETROUTE, + .r.rtm_family = preferred_family, + }; char *idev = NULL; char *odev = NULL; int connected = 0; int from_ok = 0; unsigned int mark = 0; - memset(&req, 0, sizeof(req)); - iproute_reset_filter(0); filter.cloned = 2; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_GETROUTE; - req.r.rtm_family = preferred_family; - req.r.rtm_table = 0; - req.r.rtm_protocol = 0; - req.r.rtm_scope = 0; - req.r.rtm_type = 0; - req.r.rtm_src_len = 0; - req.r.rtm_dst_len = 0; - req.r.rtm_tos = 0; - while (argc > 0) { if (strcmp(*argv, "tos") == 0 || matches(*argv, "dsfield") == 0) { diff --git a/ip/iprule.c b/ip/iprule.c index 7cb19e4d5..f3ada820f 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -316,19 +316,15 @@ static int iprule_modify(int cmd, int argc, char **argv) struct nlmsghdr n; struct rtmsg r; char buf[1024]; - } req; - - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_type = cmd; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.r.rtm_family = preferred_family; - req.r.rtm_protocol = RTPROT_BOOT; - req.r.rtm_scope = RT_SCOPE_UNIVERSE; - req.r.rtm_table = 0; - req.r.rtm_type = RTN_UNSPEC; - req.r.rtm_flags = 0; + } req = { + .n.nlmsg_type = cmd, + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .r.rtm_family = preferred_family, + .r.rtm_protocol = RTPROT_BOOT, + .r.rtm_scope = RT_SCOPE_UNIVERSE, + .r.rtm_type = RTN_UNSPEC, + }; if (cmd == RTM_NEWRULE) { req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; diff --git a/ip/iptoken.c b/ip/iptoken.c index 722b526ad..1869f7644 100644 --- a/ip/iptoken.c +++ b/ip/iptoken.c @@ -89,10 +89,7 @@ static int print_token(const struct sockaddr_nl *who, struct nlmsghdr *n, void * static int iptoken_list(int argc, char **argv) { int af = AF_INET6; - struct rtnl_dump_args da; - - memset(&da, 0, sizeof(da)); - da.fp = stdout; + struct rtnl_dump_args da = { .fp = stdout }; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { @@ -123,18 +120,16 @@ static int iptoken_set(int argc, char **argv, bool delete) struct nlmsghdr n; struct ifinfomsg ifi; char buf[512]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_SETLINK, + .ifi.ifi_family = AF_INET6, + }; struct rtattr *afs, *afs6; bool have_token = delete, have_dev = false; inet_prefix addr = { .bytelen = 16, }; - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_SETLINK; - req.ifi.ifi_family = AF_INET6; - while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); diff --git a/ip/iptunnel.c b/ip/iptunnel.c index e3161d81b..105d0f557 100644 --- a/ip/iptunnel.c +++ b/ip/iptunnel.c @@ -60,12 +60,10 @@ static void set_tunnel_proto(struct ip_tunnel_parm *p, int proto) static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) { int count = 0; - char medium[IFNAMSIZ]; + char medium[IFNAMSIZ] = {}; int isatap = 0; memset(p, 0, sizeof(*p)); - memset(&medium, 0, sizeof(medium)); - p->iph.version = 4; p->iph.ihl = 5; #ifndef IP_DF @@ -182,9 +180,8 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p) duparg2("name", *argv); strncpy(p->name, *argv, IFNAMSIZ - 1); if (cmd == SIOCCHGTUNNEL && count == 0) { - struct ip_tunnel_parm old_p; + struct ip_tunnel_parm old_p = {}; - memset(&old_p, 0, sizeof(old_p)); if (tnl_get_ioctl(*argv, &old_p)) return -1; *p = old_p; @@ -296,12 +293,10 @@ static int do_del(int argc, char **argv) static void print_tunnel(struct ip_tunnel_parm *p) { - struct ip_tunnel_6rd ip6rd; + struct ip_tunnel_6rd ip6rd = {}; char s1[1024]; char s2[1024]; - memset(&ip6rd, 0, sizeof(ip6rd)); - /* Do not use format_host() for local addr, * symbolic name will not be useful. */ @@ -312,10 +307,9 @@ static void print_tunnel(struct ip_tunnel_parm *p) p->iph.saddr ? rt_addr_n2a_r(AF_INET, 4, &p->iph.saddr, s2, sizeof(s2)) : "any"); if (p->iph.protocol == IPPROTO_IPV6 && (p->i_flags & SIT_ISATAP)) { - struct ip_tunnel_prl prl[16]; + struct ip_tunnel_prl prl[16] = {}; int i; - memset(prl, 0, sizeof(prl)); prl[0].datalen = sizeof(prl) - sizeof(prl[0]); prl[0].addr = htonl(INADDR_ANY); @@ -405,7 +399,7 @@ static int do_tunnels_list(struct ip_tunnel_parm *p) while (fgets(buf, sizeof(buf), fp) != NULL) { char name[IFNAMSIZ]; int index, type; - struct ip_tunnel_parm p1; + struct ip_tunnel_parm p1 = {}; char *ptr; buf[sizeof(buf) - 1] = 0; @@ -427,7 +421,6 @@ static int do_tunnels_list(struct ip_tunnel_parm *p) } if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT) continue; - memset(&p1, 0, sizeof(p1)); if (tnl_get_ioctl(name, &p1)) continue; if ((p->link && p1.link != p->link) || @@ -470,14 +463,11 @@ static int do_show(int argc, char **argv) static int do_prl(int argc, char **argv) { - struct ip_tunnel_prl p; + struct ip_tunnel_prl p = {}; int count = 0; int devname = 0; int cmd = 0; - char medium[IFNAMSIZ]; - - memset(&p, 0, sizeof(p)); - memset(&medium, 0, sizeof(medium)); + char medium[IFNAMSIZ] = {}; while (argc > 0) { if (strcmp(*argv, "prl-default") == 0) { @@ -522,15 +512,12 @@ static int do_prl(int argc, char **argv) static int do_6rd(int argc, char **argv) { - struct ip_tunnel_6rd ip6rd; + struct ip_tunnel_6rd ip6rd = {}; int devname = 0; int cmd = 0; - char medium[IFNAMSIZ]; + char medium[IFNAMSIZ] = {}; inet_prefix prefix; - memset(&ip6rd, 0, sizeof(ip6rd)); - memset(&medium, 0, sizeof(medium)); - while (argc > 0) { if (strcmp(*argv, "6rd-prefix") == 0) { NEXT_ARG(); diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c index 8d786d133..8ae0fcafe 100644 --- a/ip/ipxfrm.c +++ b/ip/ipxfrm.c @@ -867,9 +867,7 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, static int xfrm_selector_iszero(struct xfrm_selector *s) { - struct xfrm_selector s0; - - memset(&s0, 0, sizeof(s0)); + struct xfrm_selector s0 = {}; return (memcmp(&s0, s, sizeof(s0)) == 0); } @@ -878,11 +876,9 @@ void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo, struct rtattr *tb[], FILE *fp, const char *prefix, const char *title) { - char buf[STRBUF_SIZE]; + char buf[STRBUF_SIZE] = {}; int force_spi = xfrm_xfrmproto_is_ipsec(xsinfo->id.proto); - memset(buf, '\0', sizeof(buf)); - xfrm_id_info_print(&xsinfo->saddr, &xsinfo->id, xsinfo->mode, xsinfo->reqid, xsinfo->family, force_spi, fp, prefix, title); @@ -959,9 +955,7 @@ void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo, struct rtattr *tb[], FILE *fp, const char *prefix, const char *title) { - char buf[STRBUF_SIZE]; - - memset(buf, '\0', sizeof(buf)); + char buf[STRBUF_SIZE] = {}; xfrm_selector_print(&xpinfo->sel, preferred_family, fp, title); @@ -1062,11 +1056,8 @@ int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family, { int argc = *argcp; char **argv = *argvp; - inet_prefix dst; - inet_prefix src; - - memset(&dst, 0, sizeof(dst)); - memset(&src, 0, sizeof(src)); + inet_prefix dst = {}; + inet_prefix src = {}; while (1) { if (strcmp(*argv, "src") == 0) { @@ -1371,13 +1362,10 @@ int xfrm_selector_parse(struct xfrm_selector *sel, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; - inet_prefix dst; - inet_prefix src; + inet_prefix dst = {}; + inet_prefix src = {}; char *upspecp = NULL; - memset(&dst, 0, sizeof(dst)); - memset(&src, 0, sizeof(src)); - while (1) { if (strcmp(*argv, "src") == 0) { NEXT_ARG(); diff --git a/ip/link_gre.c b/ip/link_gre.c index 492c22053..5dc4067bc 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -50,12 +50,18 @@ static void usage(void) static int gre_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { + struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct { struct nlmsghdr n; struct ifinfomsg i; char buf[16384]; - } req; - struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_GETLINK, + .i.ifi_family = preferred_family, + .i.ifi_index = ifi->ifi_index, + }; struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *greinfo[IFLA_GRE_MAX + 1]; @@ -77,14 +83,6 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, __u8 metadata = 0; if (!(n->nlmsg_flags & NLM_F_CREATE)) { - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_GETLINK; - req.i.ifi_family = preferred_family; - req.i.ifi_index = ifi->ifi_index; - if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { get_failed: fprintf(stderr, diff --git a/ip/link_gre6.c b/ip/link_gre6.c index bddfc0ff9..6767ef64e 100644 --- a/ip/link_gre6.c +++ b/ip/link_gre6.c @@ -60,12 +60,18 @@ static void usage(void) static int gre_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { + struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct { struct nlmsghdr n; struct ifinfomsg i; char buf[1024]; - } req; - struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_GETLINK, + .i.ifi_family = preferred_family, + .i.ifi_index = ifi->ifi_index, + }; struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *greinfo[IFLA_GRE_MAX + 1]; @@ -83,14 +89,6 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, int len; if (!(n->nlmsg_flags & NLM_F_CREATE)) { - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_GETLINK; - req.i.ifi_family = preferred_family; - req.i.ifi_index = ifi->ifi_index; - if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { get_failed: fprintf(stderr, diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c index 8a31d0dcd..89861c643 100644 --- a/ip/link_ip6tnl.c +++ b/ip/link_ip6tnl.c @@ -58,18 +58,24 @@ static void usage(void) static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { + struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct { struct nlmsghdr n; struct ifinfomsg i; char buf[2048]; - } req; - struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_GETLINK, + .i.ifi_family = preferred_family, + .i.ifi_index = ifi->ifi_index, + }; struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1]; int len; - struct in6_addr laddr; - struct in6_addr raddr; + struct in6_addr laddr = {}; + struct in6_addr raddr = {}; __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT; __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; __u32 flowinfo = 0; @@ -77,18 +83,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, __u32 link = 0; __u8 proto = 0; - memset(&laddr, 0, sizeof(laddr)); - memset(&raddr, 0, sizeof(raddr)); - if (!(n->nlmsg_flags & NLM_F_CREATE)) { - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_GETLINK; - req.i.ifi_family = preferred_family; - req.i.ifi_index = ifi->ifi_index; - if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { get_failed: fprintf(stderr, diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c index 8411a6a00..7ec377791 100644 --- a/ip/link_iptnl.c +++ b/ip/link_iptnl.c @@ -53,12 +53,18 @@ static void usage(int sit) static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { + struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct { struct nlmsghdr n; struct ifinfomsg i; char buf[2048]; - } req; - struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_GETLINK, + .i.ifi_family = preferred_family, + .i.ifi_index = ifi->ifi_index, + }; struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1]; @@ -71,7 +77,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, __u8 pmtudisc = 1; __u16 iflags = 0; __u8 proto = 0; - struct in6_addr ip6rdprefix; + struct in6_addr ip6rdprefix = {}; __u16 ip6rdprefixlen = 0; __u32 ip6rdrelayprefix = 0; __u16 ip6rdrelayprefixlen = 0; @@ -80,17 +86,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, __u16 encapsport = 0; __u16 encapdport = 0; - memset(&ip6rdprefix, 0, sizeof(ip6rdprefix)); - if (!(n->nlmsg_flags & NLM_F_CREATE)) { - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_GETLINK; - req.i.ifi_family = preferred_family; - req.i.ifi_index = ifi->ifi_index; - if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { get_failed: fprintf(stderr, diff --git a/ip/link_vti.c b/ip/link_vti.c index 8052e7514..1926c53e3 100644 --- a/ip/link_vti.c +++ b/ip/link_vti.c @@ -46,12 +46,18 @@ static void usage(void) static int vti_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { + struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct { struct nlmsghdr n; struct ifinfomsg i; char buf[1024]; - } req; - struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_GETLINK, + .i.ifi_family = preferred_family, + .i.ifi_index = ifi->ifi_index, + }; struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; @@ -63,14 +69,6 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv, int len; if (!(n->nlmsg_flags & NLM_F_CREATE)) { - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_GETLINK; - req.i.ifi_family = preferred_family; - req.i.ifi_index = ifi->ifi_index; - if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { get_failed: fprintf(stderr, diff --git a/ip/link_vti6.c b/ip/link_vti6.c index 9bcf7fe9d..7f32ee017 100644 --- a/ip/link_vti6.c +++ b/ip/link_vti6.c @@ -42,12 +42,18 @@ static void usage(void) static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { + struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct { struct nlmsghdr n; struct ifinfomsg i; char buf[1024]; - } req; - struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_GETLINK, + .i.ifi_family = preferred_family, + .i.ifi_index = ifi->ifi_index, + }; struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; @@ -59,14 +65,6 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, int len; if (!(n->nlmsg_flags & NLM_F_CREATE)) { - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_GETLINK; - req.i.ifi_family = preferred_family; - req.i.ifi_index = ifi->ifi_index; - if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { get_failed: fprintf(stderr, diff --git a/ip/xfrm_policy.c b/ip/xfrm_policy.c index f1ac3e91d..cc9c0f1fb 100644 --- a/ip/xfrm_policy.c +++ b/ip/xfrm_policy.c @@ -248,34 +248,28 @@ static int xfrm_policy_modify(int cmd, unsigned int flags, int argc, char **argv struct nlmsghdr n; struct xfrm_userpolicy_info xpinfo; char buf[RTA_BUF_SIZE]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpinfo)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .xpinfo.sel.family = preferred_family, + .xpinfo.lft.soft_byte_limit = XFRM_INF, + .xpinfo.lft.hard_byte_limit = XFRM_INF, + .xpinfo.lft.soft_packet_limit = XFRM_INF, + .xpinfo.lft.hard_packet_limit = XFRM_INF, + }; char *dirp = NULL; char *selp = NULL; char *ptypep = NULL; char *sctxp = NULL; - struct xfrm_userpolicy_type upt; - char tmpls_buf[XFRM_TMPLS_BUF_SIZE]; + struct xfrm_userpolicy_type upt = {}; + char tmpls_buf[XFRM_TMPLS_BUF_SIZE] = {}; int tmpls_len = 0; struct xfrm_mark mark = {0, 0}; struct { struct xfrm_user_sec_ctx sctx; char str[CTX_BUF_SIZE]; - } ctx; - - memset(&req, 0, sizeof(req)); - memset(&upt, 0, sizeof(upt)); - memset(&tmpls_buf, 0, sizeof(tmpls_buf)); - memset(&ctx, 0, sizeof(ctx)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpinfo)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - req.xpinfo.sel.family = preferred_family; - - req.xpinfo.lft.soft_byte_limit = XFRM_INF; - req.xpinfo.lft.hard_byte_limit = XFRM_INF; - req.xpinfo.lft.soft_packet_limit = XFRM_INF; - req.xpinfo.lft.hard_packet_limit = XFRM_INF; + } ctx = {}; while (argc > 0) { if (strcmp(*argv, "dir") == 0) { @@ -561,27 +555,23 @@ static int xfrm_policy_get_or_delete(int argc, char **argv, int delete, struct nlmsghdr n; struct xfrm_userpolicy_id xpid; char buf[RTA_BUF_SIZE]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpid)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = delete ? XFRM_MSG_DELPOLICY + : XFRM_MSG_GETPOLICY, + }; char *dirp = NULL; char *selp = NULL; char *indexp = NULL; char *ptypep = NULL; char *sctxp = NULL; - struct xfrm_userpolicy_type upt; + struct xfrm_userpolicy_type upt = {}; struct xfrm_mark mark = {0, 0}; struct { struct xfrm_user_sec_ctx sctx; char str[CTX_BUF_SIZE]; - } ctx; - - - memset(&req, 0, sizeof(req)); - memset(&upt, 0, sizeof(upt)); - memset(&ctx, 0, sizeof(ctx)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpid)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = delete ? XFRM_MSG_DELPOLICY : XFRM_MSG_GETPOLICY; + } ctx = {}; while (argc > 0) { if (strcmp(*argv, "dir") == 0) { @@ -684,11 +674,9 @@ static int xfrm_policy_delete(int argc, char **argv) static int xfrm_policy_get(int argc, char **argv) { - char buf[NLMSG_BUF_SIZE]; + char buf[NLMSG_BUF_SIZE] = {}; struct nlmsghdr *n = (struct nlmsghdr *)buf; - memset(buf, 0, sizeof(buf)); - xfrm_policy_get_or_delete(argc, argv, 0, n, sizeof(buf)); if (xfrm_policy_print(NULL, n, (void *)stdout) < 0) { @@ -1012,18 +1000,16 @@ static int xfrm_spd_setinfo(int argc, char **argv) struct nlmsghdr n; __u32 flags; char buf[RTA_BUF_SIZE]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(__u32)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = XFRM_MSG_NEWSPDINFO, + .flags = 0XFFFFFFFF, + }; char *thr4 = NULL; char *thr6 = NULL; - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(__u32)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_NEWSPDINFO; - req.flags = 0XFFFFFFFF; - while (argc > 0) { if (strcmp(*argv, "hthresh4") == 0) { struct xfrmu_spdhthresh thr; @@ -1080,14 +1066,12 @@ static int xfrm_spd_getinfo(int argc, char **argv) struct nlmsghdr n; __u32 flags; char ans[128]; - } req; - - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(__u32)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_GETSPDINFO; - req.flags = 0XFFFFFFFF; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(__u32)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = XFRM_MSG_GETSPDINFO, + .flags = 0XFFFFFFFF, + }; if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); @@ -1108,16 +1092,13 @@ static int xfrm_policy_flush(int argc, char **argv) struct { struct nlmsghdr n; char buf[RTA_BUF_SIZE]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(0), /* nlmsg data is nothing */ + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = XFRM_MSG_FLUSHPOLICY, + }; char *ptypep = NULL; - struct xfrm_userpolicy_type upt; - - memset(&req, 0, sizeof(req)); - memset(&upt, 0, sizeof(upt)); - - req.n.nlmsg_len = NLMSG_LENGTH(0); /* nlmsg data is nothing */ - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_FLUSHPOLICY; + struct xfrm_userpolicy_type upt = {}; while (argc > 0) { if (strcmp(*argv, "ptype") == 0) { diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c index 21ada3647..0357a435c 100644 --- a/ip/xfrm_state.c +++ b/ip/xfrm_state.c @@ -271,9 +271,18 @@ static int xfrm_state_modify(int cmd, unsigned int flags, int argc, char **argv) struct nlmsghdr n; struct xfrm_usersa_info xsinfo; char buf[RTA_BUF_SIZE]; - } req; - struct xfrm_replay_state replay; - struct xfrm_replay_state_esn replay_esn; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .xsinfo.family = preferred_family, + .xsinfo.lft.soft_byte_limit = XFRM_INF, + .xsinfo.lft.hard_byte_limit = XFRM_INF, + .xsinfo.lft.soft_packet_limit = XFRM_INF, + .xsinfo.lft.hard_packet_limit = XFRM_INF, + }; + struct xfrm_replay_state replay = {}; + struct xfrm_replay_state_esn replay_esn = {}; __u32 replay_window = 0; __u32 seq = 0, oseq = 0, seq_hi = 0, oseq_hi = 0; char *idp = NULL; @@ -288,22 +297,7 @@ static int xfrm_state_modify(int cmd, unsigned int flags, int argc, char **argv) struct { struct xfrm_user_sec_ctx sctx; char str[CTX_BUF_SIZE]; - } ctx; - - memset(&req, 0, sizeof(req)); - memset(&replay, 0, sizeof(replay)); - memset(&replay_esn, 0, sizeof(replay_esn)); - memset(&ctx, 0, sizeof(ctx)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - req.xsinfo.family = preferred_family; - - req.xsinfo.lft.soft_byte_limit = XFRM_INF; - req.xsinfo.lft.hard_byte_limit = XFRM_INF; - req.xsinfo.lft.soft_packet_limit = XFRM_INF; - req.xsinfo.lft.hard_packet_limit = XFRM_INF; + } ctx = {}; while (argc > 0) { if (strcmp(*argv, "mode") == 0) { @@ -369,7 +363,7 @@ static int xfrm_state_modify(int cmd, unsigned int flags, int argc, char **argv) (void *)&encap, sizeof(encap)); } else if (strcmp(*argv, "coa") == 0) { inet_prefix coa; - xfrm_address_t xcoa; + xfrm_address_t xcoa = {}; if (coap) duparg("coa", *argv); @@ -383,7 +377,6 @@ static int xfrm_state_modify(int cmd, unsigned int flags, int argc, char **argv) if (coa.bytelen > sizeof(xcoa)) invarg("value after \"coa\" is too large", *argv); - memset(&xcoa, 0, sizeof(xcoa)); memcpy(&xcoa, &coa.data, coa.bytelen); addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR, @@ -699,30 +692,25 @@ static int xfrm_state_allocspi(int argc, char **argv) struct nlmsghdr n; struct xfrm_userspi_info xspi; char buf[RTA_BUF_SIZE]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = XFRM_MSG_ALLOCSPI, + .xspi.info.family = preferred_family, +#if 0 + .xspi.lft.soft_byte_limit = XFRM_INF, + .xspi.lft.hard_byte_limit = XFRM_INF, + .xspi.lft.soft_packet_limit = XFRM_INF, + .xspi.lft.hard_packet_limit = XFRM_INF, +#endif + }; char *idp = NULL; char *minp = NULL; char *maxp = NULL; struct xfrm_mark mark = {0, 0}; - char res_buf[NLMSG_BUF_SIZE]; + char res_buf[NLMSG_BUF_SIZE] = {}; struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf; - memset(res_buf, 0, sizeof(res_buf)); - - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_ALLOCSPI; - req.xspi.info.family = preferred_family; - -#if 0 - req.xsinfo.lft.soft_byte_limit = XFRM_INF; - req.xsinfo.lft.hard_byte_limit = XFRM_INF; - req.xsinfo.lft.soft_packet_limit = XFRM_INF; - req.xsinfo.lft.hard_packet_limit = XFRM_INF; -#endif - while (argc > 0) { if (strcmp(*argv, "mode") == 0) { NEXT_ARG(); @@ -956,18 +944,16 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete) struct nlmsghdr n; struct xfrm_usersa_id xsid; char buf[RTA_BUF_SIZE]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA, + .xsid.family = preferred_family, + }; struct xfrm_id id; char *idp = NULL; struct xfrm_mark mark = {0, 0}; - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsid)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = delete ? XFRM_MSG_DELSA : XFRM_MSG_GETSA; - req.xsid.family = preferred_family; - while (argc > 0) { xfrm_address_t saddr; @@ -1014,11 +1000,9 @@ static int xfrm_state_get_or_delete(int argc, char **argv, int delete) if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) exit(2); } else { - char buf[NLMSG_BUF_SIZE]; + char buf[NLMSG_BUF_SIZE] = {}; struct nlmsghdr *res_n = (struct nlmsghdr *)buf; - memset(buf, 0, sizeof(buf)); - if (rtnl_talk(&rth, &req.n, res_n, sizeof(req)) < 0) exit(2); @@ -1282,13 +1266,12 @@ static int xfrm_sad_getinfo(int argc, char **argv) struct nlmsghdr n; __u32 flags; char ans[64]; - } req; - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.flags)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_GETSADINFO; - req.flags = 0XFFFFFFFF; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(req.flags)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = XFRM_MSG_GETSADINFO, + .flags = 0XFFFFFFFF, + }; if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); @@ -1309,16 +1292,13 @@ static int xfrm_state_flush(int argc, char **argv) struct { struct nlmsghdr n; struct xfrm_usersa_flush xsf; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = XFRM_MSG_FLUSHSA, + }; char *protop = NULL; - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsf)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = XFRM_MSG_FLUSHSA; - req.xsf.proto = 0; - while (argc > 0) { if (strcmp(*argv, "proto") == 0) { int ret; diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 0adcbf3f6..a02cf9f0d 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -112,19 +112,16 @@ int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int family, int type, /* attribute has to be NLMSG aligned */ struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO))); __u32 ext_filter_mask; - } req; - - memset(&req, 0, sizeof(req)); - req.nlh.nlmsg_len = sizeof(req); - req.nlh.nlmsg_type = type; - req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; - req.nlh.nlmsg_pid = 0; - req.nlh.nlmsg_seq = rth->dump = ++rth->seq; - req.ifm.ifi_family = family; - - req.ext_req.rta_type = IFLA_EXT_MASK; - req.ext_req.rta_len = RTA_LENGTH(sizeof(__u32)); - req.ext_filter_mask = filt_mask; + } req = { + .nlh.nlmsg_len = sizeof(req), + .nlh.nlmsg_type = type, + .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, + .nlh.nlmsg_seq = rth->dump = ++rth->seq, + .ifm.ifi_family = family, + .ext_req.rta_type = IFLA_EXT_MASK, + .ext_req.rta_len = RTA_LENGTH(sizeof(__u32)), + .ext_filter_mask = filt_mask, + }; return send(rth->fd, (void*)&req, sizeof(req), 0); } @@ -136,20 +133,18 @@ int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int family, int type, struct nlmsghdr nlh; struct ifinfomsg ifm; char buf[1024]; - } req; + } req = { + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), + .nlh.nlmsg_type = type, + .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, + .nlh.nlmsg_seq = rth->dump = ++rth->seq, + .ifm.ifi_family = family, + }; int err; if (!filter_fn) return -EINVAL; - memset(&req, 0, sizeof(req)); - req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.nlh.nlmsg_type = type; - req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; - req.nlh.nlmsg_pid = 0; - req.nlh.nlmsg_seq = rth->dump = ++rth->seq; - req.ifm.ifi_family = family; - err = filter_fn(&req.nlh, sizeof(req)); if (err) return err; @@ -197,7 +192,12 @@ int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len) int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) { - struct nlmsghdr nlh; + struct nlmsghdr nlh = { + .nlmsg_len = NLMSG_LENGTH(len), + .nlmsg_type = type, + .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, + .nlmsg_seq = rth->dump = ++rth->seq, + }; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; struct iovec iov[2] = { { .iov_base = &nlh, .iov_len = sizeof(nlh) }, @@ -205,17 +205,11 @@ int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) }; struct msghdr msg = { .msg_name = &nladdr, - .msg_namelen = sizeof(nladdr), + .msg_namelen = sizeof(nladdr), .msg_iov = iov, .msg_iovlen = 2, }; - nlh.nlmsg_len = NLMSG_LENGTH(len); - nlh.nlmsg_type = type; - nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; - nlh.nlmsg_pid = 0; - nlh.nlmsg_seq = rth->dump = ++rth->seq; - return sendmsg(rth->fd, &msg, 0); } @@ -365,7 +359,7 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, int status; unsigned seq; struct nlmsghdr *h; - struct sockaddr_nl nladdr; + struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; struct iovec iov = { .iov_base = (void*) n, .iov_len = n->nlmsg_len @@ -376,10 +370,7 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, .msg_iov = &iov, .msg_iovlen = 1, }; - char buf[32768]; - - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; + char buf[32768] = {}; n->nlmsg_seq = seq = ++rtnl->seq; @@ -392,8 +383,6 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, return -1; } - memset(buf,0,sizeof(buf)); - iov.iov_base = buf; while (1) { iov.iov_len = sizeof(buf); @@ -498,7 +487,7 @@ int rtnl_listen(struct rtnl_handle *rtnl, { int status; struct nlmsghdr *h; - struct sockaddr_nl nladdr; + struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; struct iovec iov; struct msghdr msg = { .msg_name = &nladdr, @@ -514,11 +503,6 @@ int rtnl_listen(struct rtnl_handle *rtnl, msg.msg_controllen = sizeof(cmsgbuf); } - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - nladdr.nl_pid = 0; - nladdr.nl_groups = 0; - iov.iov_base = buf; while (1) { struct rtnl_ctrl_data ctrl; @@ -595,15 +579,10 @@ int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler, void *jarg) { int status; - struct sockaddr_nl nladdr; + struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; char buf[16384]; struct nlmsghdr *h = (void*)buf; - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - nladdr.nl_pid = 0; - nladdr.nl_groups = 0; - while (1) { int err, len; int l; diff --git a/lib/ll_map.c b/lib/ll_map.c index fa14a7760..571d11e1c 100644 --- a/lib/ll_map.c +++ b/lib/ll_map.c @@ -103,7 +103,6 @@ int ll_remember_index(const struct sockaddr_nl *who, return 0; } - memset(tb, 0, sizeof(tb)); parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); ifname = rta_getattr_str(tb[IFLA_IFNAME]); if (ifname == NULL) diff --git a/misc/arpd.c b/misc/arpd.c index 65c03cd2b..bfab44544 100644 --- a/misc/arpd.c +++ b/misc/arpd.c @@ -179,16 +179,22 @@ static void undo_sysctl_adjustments(void) static int send_probe(int ifindex, __u32 addr) { - struct ifreq ifr; - struct sockaddr_in dst; + struct ifreq ifr = { .ifr_ifindex = ifindex }; + struct sockaddr_in dst = { + .sin_family = AF_INET, + .sin_port = htons(1025), + .sin_addr.s_addr = addr, + }; socklen_t len; unsigned char buf[256]; struct arphdr *ah = (struct arphdr *)buf; unsigned char *p = (unsigned char *)(ah+1); - struct sockaddr_ll sll; + struct sockaddr_ll sll = { + .sll_family = AF_PACKET, + .sll_ifindex = ifindex, + .sll_protocol = htons(ETH_P_ARP), + }; - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_ifindex = ifindex; if (ioctl(udp_sock, SIOCGIFNAME, &ifr)) return -1; if (ioctl(udp_sock, SIOCGIFHWADDR, &ifr)) @@ -198,9 +204,6 @@ static int send_probe(int ifindex, __u32 addr) if (setsockopt(udp_sock, SOL_SOCKET, SO_BINDTODEVICE, ifr.ifr_name, strlen(ifr.ifr_name)+1) < 0) return -1; - dst.sin_family = AF_INET; - dst.sin_port = htons(1025); - dst.sin_addr.s_addr = addr; if (connect(udp_sock, (struct sockaddr *)&dst, sizeof(dst)) < 0) return -1; len = sizeof(dst); @@ -219,10 +222,7 @@ static int send_probe(int ifindex, __u32 addr) memcpy(p, &dst.sin_addr, 4); p += 4; - sll.sll_family = AF_PACKET; memset(sll.sll_addr, 0xFF, sizeof(sll.sll_addr)); - sll.sll_ifindex = ifindex; - sll.sll_protocol = htons(ETH_P_ARP); memcpy(p, &sll.sll_addr, ah->ar_hln); p += ah->ar_hln; @@ -268,18 +268,15 @@ static int respond_to_kernel(int ifindex, __u32 addr, char *lla, int llalen) struct nlmsghdr n; struct ndmsg ndm; char buf[256]; - } req; - - memset(&req.n, 0, sizeof(req.n)); - memset(&req.ndm, 0, sizeof(req.ndm)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.n.nlmsg_type = RTM_NEWNEIGH; - req.ndm.ndm_family = AF_INET; - req.ndm.ndm_state = NUD_STALE; - req.ndm.ndm_ifindex = ifindex; - req.ndm.ndm_type = RTN_UNICAST; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_NEWNEIGH, + .ndm.ndm_family = AF_INET, + .ndm.ndm_state = NUD_STALE, + .ndm.ndm_ifindex = ifindex, + .ndm.ndm_type = RTN_UNICAST, + }; addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); @@ -440,7 +437,7 @@ static void get_kern_msg(void) { int status; struct nlmsghdr *h; - struct sockaddr_nl nladdr; + struct sockaddr_nl nladdr = {}; struct iovec iov; char buf[8192]; struct msghdr msg = { @@ -450,8 +447,6 @@ static void get_kern_msg(void) 0 }; - memset(&nladdr, 0, sizeof(nladdr)); - iov.iov_base = buf; iov.iov_len = sizeof(buf); @@ -539,10 +534,8 @@ static void get_arp_pkt(void) static void catch_signal(int sig, void (*handler)(int)) { - struct sigaction sa; + struct sigaction sa = { .sa_handler = handler }; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = handler; #ifdef SA_INTERRUPT sa.sa_flags = SA_INTERRUPT; #endif @@ -668,9 +661,8 @@ int main(int argc, char **argv) if (ifnum) { int i; - struct ifreq ifr; + struct ifreq ifr = {}; - memset(&ifr, 0, sizeof(ifr)); for (i = 0; i < ifnum; i++) { strncpy(ifr.ifr_name, ifnames[i], IFNAMSIZ); if (ioctl(udp_sock, SIOCGIFINDEX, &ifr)) { @@ -772,12 +764,12 @@ int main(int argc, char **argv) } if (1) { - struct sockaddr_ll sll; + struct sockaddr_ll sll = { + .sll_family = AF_PACKET, + .sll_protocol = htons(ETH_P_ARP), + .sll_ifindex = (ifnum == 1 ? ifvec[0] : 0), + }; - memset(&sll, 0, sizeof(sll)); - sll.sll_family = AF_PACKET; - sll.sll_protocol = htons(ETH_P_ARP); - sll.sll_ifindex = (ifnum == 1 ? ifvec[0] : 0); if (bind(pset[0].fd, (struct sockaddr *)&sll, sizeof(sll)) < 0) { perror("bind"); goto do_abort; diff --git a/misc/ss.c b/misc/ss.c index 38205b0e8..e758f5720 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -2166,11 +2166,17 @@ static int inet_show_sock(struct nlmsghdr *nlh, static int tcpdiag_send(int fd, int protocol, struct filter *f) { - struct sockaddr_nl nladdr; + struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; struct { struct nlmsghdr nlh; struct inet_diag_req r; - } req; + } req = { + .nlh.nlmsg_len = sizeof(req), + .nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST, + .nlh.nlmsg_seq = MAGIC_SEQ, + .r.idiag_family = AF_INET, + .r.idiag_states = f->states, + }; char *bc = NULL; int bclen; struct msghdr msg; @@ -2181,20 +2187,10 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f) if (protocol == IPPROTO_UDP) return -1; - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - - req.nlh.nlmsg_len = sizeof(req); if (protocol == IPPROTO_TCP) req.nlh.nlmsg_type = TCPDIAG_GETSOCK; else req.nlh.nlmsg_type = DCCPDIAG_GETSOCK; - req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; - req.nlh.nlmsg_pid = 0; - req.nlh.nlmsg_seq = MAGIC_SEQ; - memset(&req.r, 0, sizeof(req.r)); - req.r.idiag_family = AF_INET; - req.r.idiag_states = f->states; if (show_mem) { req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1)); req.r.idiag_ext |= (1<<(INET_DIAG_SKMEMINFO-1)); @@ -2239,8 +2235,7 @@ static int tcpdiag_send(int fd, int protocol, struct filter *f) static int sockdiag_send(int family, int fd, int protocol, struct filter *f) { - struct sockaddr_nl nladdr; - + struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; DIAG_REQUEST(req, struct inet_diag_req_v2 r); char *bc = NULL; int bclen; @@ -2252,9 +2247,6 @@ static int sockdiag_send(int family, int fd, int protocol, struct filter *f) if (family == PF_UNSPEC) return tcpdiag_send(fd, protocol, f); - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; - memset(&req.r, 0, sizeof(req.r)); req.r.sdiag_family = family; req.r.sdiag_protocol = protocol; @@ -2750,14 +2742,13 @@ static void unix_stats_print(struct sockstat *list, struct filter *f) } if (use_proc && f->f) { - struct sockstat st; + struct sockstat st = { + .local.family = AF_UNIX, + .remote.family = AF_UNIX, + }; - st.local.family = AF_UNIX; - st.remote.family = AF_UNIX; memcpy(st.local.data, &s->name, sizeof(s->name)); - if (strcmp(peer, "*") == 0) - memset(st.remote.data, 0, sizeof(peer)); - else + if (strcmp(peer, "*")) memcpy(st.remote.data, &peer, sizeof(peer)); if (run_ssfilter(f->f, &st) == 0) continue; diff --git a/tc/e_bpf.c b/tc/e_bpf.c index 2d650a46c..d1f5d87fe 100644 --- a/tc/e_bpf.c +++ b/tc/e_bpf.c @@ -56,8 +56,8 @@ static int parse_bpf(struct exec_util *eu, int argc, char **argv) char **argv_run = argv_default, **envp_run, *tmp; int ret, i, env_old, env_num, env_map; const char *bpf_uds_name = NULL; - int fds[BPF_SCM_MAX_FDS]; - struct bpf_map_aux aux; + int fds[BPF_SCM_MAX_FDS] = {}; + struct bpf_map_aux aux = {}; if (argc == 0) return 0; @@ -115,9 +115,6 @@ static int parse_bpf(struct exec_util *eu, int argc, char **argv) return -1; } - memset(fds, 0, sizeof(fds)); - memset(&aux, 0, sizeof(aux)); - ret = bpf_recv_map_fds(bpf_uds_name, fds, &aux, ARRAY_SIZE(fds)); if (ret < 0) { fprintf(stderr, "bpf: Could not receive fds!\n"); diff --git a/tc/em_cmp.c b/tc/em_cmp.c index fd8bd028c..8ea0accfb 100644 --- a/tc/em_cmp.c +++ b/tc/em_cmp.c @@ -44,9 +44,7 @@ static int cmp_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, int align, opnd = 0; unsigned long offset = 0, layer = TCF_LAYER_NETWORK, mask = 0, value = 0; int offset_present = 0, value_present = 0; - struct tcf_em_cmp cmp; - - memset(&cmp, 0, sizeof(cmp)); + struct tcf_em_cmp cmp = {}; #define PARSE_ERR(CARG, FMT, ARGS...) \ em_parse_error(EINVAL, args, CARG, &cmp_ematch_util, FMT, ##ARGS) diff --git a/tc/em_ipset.c b/tc/em_ipset.c index 806a79c78..fab975f5e 100644 --- a/tc/em_ipset.c +++ b/tc/em_ipset.c @@ -198,11 +198,9 @@ static void ipset_print_usage(FILE *fd) static int ipset_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, struct bstr *args) { - struct xt_set_info set_info; + struct xt_set_info set_info = {}; int ret; - memset(&set_info, 0, sizeof(set_info)); - #define PARSE_ERR(CARG, FMT, ARGS...) \ em_parse_error(EINVAL, args, CARG, &ipset_ematch_util, FMT, ##ARGS) diff --git a/tc/em_meta.c b/tc/em_meta.c index 9ce5a78a6..b00dd3588 100644 --- a/tc/em_meta.c +++ b/tc/em_meta.c @@ -361,11 +361,9 @@ static int meta_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, { int opnd; struct bstr *a; - struct tcf_meta_hdr meta_hdr; + struct tcf_meta_hdr meta_hdr = {}; unsigned long lvalue = 0, rvalue = 0; - memset(&meta_hdr, 0, sizeof(meta_hdr)); - if (args == NULL) return PARSE_ERR(args, "meta: missing arguments"); diff --git a/tc/em_nbyte.c b/tc/em_nbyte.c index 76dd8573e..52b4d10a1 100644 --- a/tc/em_nbyte.c +++ b/tc/em_nbyte.c @@ -44,9 +44,7 @@ static int nbyte_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, struct bstr *needle = args; unsigned long offset = 0, layer = TCF_LAYER_NETWORK; int offset_present = 0; - struct tcf_em_nbyte nb; - - memset(&nb, 0, sizeof(nb)); + struct tcf_em_nbyte nb = {}; #define PARSE_ERR(CARG, FMT, ARGS...) \ em_parse_error(EINVAL, args, CARG, &nbyte_ematch_util, FMT, ##ARGS) diff --git a/tc/em_u32.c b/tc/em_u32.c index 0369e15a3..869ebde0f 100644 --- a/tc/em_u32.c +++ b/tc/em_u32.c @@ -39,9 +39,7 @@ static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, struct bstr *a; int align, nh_len; unsigned long key, mask, offmask = 0, offset; - struct tc_u32_key u_key; - - memset(&u_key, 0, sizeof(u_key)); + struct tc_u32_key u_key = {}; #define PARSE_ERR(CARG, FMT, ARGS...) \ em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT, ##ARGS) diff --git a/tc/f_flow.c b/tc/f_flow.c index 6ee4dd5e5..09ddcaa66 100644 --- a/tc/f_flow.c +++ b/tc/f_flow.c @@ -133,7 +133,6 @@ static int get_addend(__u32 *addend, char *argv, __u32 keys) static int flow_parse_opt(struct filter_util *fu, char *handle, int argc, char **argv, struct nlmsghdr *n) { - struct tc_police tp; struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tail; __u32 mask = ~0U, xor = 0; @@ -141,8 +140,6 @@ static int flow_parse_opt(struct filter_util *fu, char *handle, __u32 mode = FLOW_MODE_MAP; __u32 tmp; - memset(&tp, 0, sizeof(tp)); - if (handle) { if (get_u32(&t->tcm_handle, handle, 0)) { fprintf(stderr, "Illegal \"handle\"\n"); diff --git a/tc/f_flower.c b/tc/f_flower.c index 7b46ceb14..791ade7f8 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -203,10 +203,9 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, } else if (matches(*argv, "skip_sw") == 0) { flags |= TCA_CLS_FLAGS_SKIP_SW; } else if (matches(*argv, "indev") == 0) { - char ifname[IFNAMSIZ]; + char ifname[IFNAMSIZ] = {}; NEXT_ARG(); - memset(ifname, 0, sizeof(ifname)); strncpy(ifname, *argv, sizeof(ifname) - 1); addattrstrz(n, MAX_MSG, TCA_FLOWER_INDEV, ifname); } else if (matches(*argv, "dst_mac") == 0) { diff --git a/tc/f_fw.c b/tc/f_fw.c index ff9648c51..29c985490 100644 --- a/tc/f_fw.c +++ b/tc/f_fw.c @@ -33,14 +33,11 @@ static void explain(void) static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) { - struct tc_police tp; struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tail; __u32 mask = 0; int mask_set = 0; - memset(&tp, 0, sizeof(tp)); - if (handle) { char *slash; @@ -94,9 +91,8 @@ static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **a } continue; } else if (strcmp(*argv, "indev") == 0) { - char d[IFNAMSIZ+1]; + char d[IFNAMSIZ+1] = {}; - memset(d, 0, sizeof(d)); argc--; argv++; if (argc < 1) { diff --git a/tc/f_route.c b/tc/f_route.c index 4d9f4dcef..5c600b9bd 100644 --- a/tc/f_route.c +++ b/tc/f_route.c @@ -36,14 +36,11 @@ static void explain(void) static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) { - struct tc_police tp; struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tail; __u32 fh = 0xFFFF8000; __u32 order = 0; - memset(&tp, 0, sizeof(tp)); - if (handle) { if (get_u32(&t->tcm_handle, handle, 0)) { fprintf(stderr, "Illegal \"handle\"\n"); diff --git a/tc/f_rsvp.c b/tc/f_rsvp.c index e7dcc774c..94bfbefe8 100644 --- a/tc/f_rsvp.c +++ b/tc/f_rsvp.c @@ -173,15 +173,11 @@ static int get_addr_and_pi(int *argc_p, char ***argv_p, inet_prefix *addr, 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; - struct tc_police tp; + struct tc_rsvp_pinfo pinfo = {}; struct tcmsg *t = NLMSG_DATA(n); int pinfo_ok = 0; struct rtattr *tail; - memset(&pinfo, 0, sizeof(pinfo)); - memset(&tp, 0, sizeof(tp)); - if (handle) { if (get_u32(&t->tcm_handle, handle, 0)) { fprintf(stderr, "Illegal \"handle\"\n"); diff --git a/tc/f_u32.c b/tc/f_u32.c index 0926461dc..0ad7ed2b6 100644 --- a/tc/f_u32.c +++ b/tc/f_u32.c @@ -988,7 +988,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, struct { struct tc_u32_sel sel; struct tc_u32_key keys[128]; - } sel; + } sel = {}; struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tail; int sel_ok = 0, terminal_ok = 0; @@ -997,8 +997,6 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, __u32 order = 0; __u32 flags = 0; - memset(&sel, 0, sizeof(sel)); - if (handle && get_u32_handle(&t->tcm_handle, handle)) { fprintf(stderr, "Illegal filter ID\n"); return -1; @@ -1093,12 +1091,11 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, } else if (strcmp(*argv, "sample") == 0) { __u32 hash; unsigned int divisor = 0x100; - struct { struct tc_u32_sel sel; struct tc_u32_key keys[4]; - } sel2; - memset(&sel2, 0, sizeof(sel2)); + } sel2 = {}; + NEXT_ARG(); if (parse_selector(&argc, &argv, &sel2.sel, n)) { fprintf(stderr, "Illegal \"sample\"\n"); @@ -1125,9 +1122,8 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, sample_ok = 1; continue; } else if (strcmp(*argv, "indev") == 0) { - char ind[IFNAMSIZ + 1]; + char ind[IFNAMSIZ + 1] = {}; - memset(ind, 0, sizeof(ind)); argc--; argv++; if (argc < 1) { diff --git a/tc/m_bpf.c b/tc/m_bpf.c index 37cd0d80b..20da11d07 100644 --- a/tc/m_bpf.c +++ b/tc/m_bpf.c @@ -63,7 +63,7 @@ static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv, int tca_id, struct nlmsghdr *n) { const char *bpf_obj = NULL, *bpf_uds_name = NULL; - struct tc_act_bpf parm; + struct tc_act_bpf parm = { .action = TC_ACT_PIPE }; bool seen_run = false; struct rtattr *tail; int argc, ret = 0; @@ -104,9 +104,6 @@ static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv, NEXT_ARG_FWD(); } - memset(&parm, 0, sizeof(parm)); - parm.action = TC_ACT_PIPE; - if (argc) { if (matches(*argv, "reclassify") == 0) { parm.action = TC_ACT_RECLASSIFY; diff --git a/tc/m_csum.c b/tc/m_csum.c index fb1183a98..047986efd 100644 --- a/tc/m_csum.c +++ b/tc/m_csum.c @@ -85,15 +85,13 @@ static int parse_csum(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { - struct tc_csum sel; + struct tc_csum sel = {}; int argc = *argc_p; char **argv = *argv_p; int ok = 0; struct rtattr *tail; - memset(&sel, 0, sizeof(sel)); - while (argc > 0) { if (matches(*argv, "csum") == 0) { NEXT_ARG(); diff --git a/tc/m_ematch.c b/tc/m_ematch.c index 251f5aa19..e18a395b0 100644 --- a/tc/m_ematch.c +++ b/tc/m_ematch.c @@ -177,9 +177,7 @@ static int parse_tree(struct nlmsghdr *n, struct ematch *tree) for (t = tree; t; t = t->next) { struct rtattr *tail = NLMSG_TAIL(n); - struct tcf_ematch_hdr hdr = { - .flags = t->relation - }; + struct tcf_ematch_hdr hdr = { .flags = t->relation }; if (t->inverted) hdr.flags |= TCF_EM_INVERT; diff --git a/tc/m_gact.c b/tc/m_gact.c index b22ce1915..ea2c9ec82 100644 --- a/tc/m_gact.c +++ b/tc/m_gact.c @@ -97,16 +97,13 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, char **argv = *argv_p; int ok = 0; int action = TC_POLICE_RECLASSIFY; - struct tc_gact p; + struct tc_gact p = { .action = TC_POLICE_RECLASSIFY }; #ifdef CONFIG_GACT_PROB int rd = 0; struct tc_gact_p pp; #endif struct rtattr *tail; - memset(&p, 0, sizeof(p)); - p.action = TC_POLICE_RECLASSIFY; - if (argc < 0) return -1; diff --git a/tc/m_ife.c b/tc/m_ife.c index c8ae04d30..eaab1cc85 100644 --- a/tc/m_ife.c +++ b/tc/m_ife.c @@ -56,7 +56,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, int argc = *argc_p; char **argv = *argv_p; int ok = 0; - struct tc_ife p; + struct tc_ife p = { .action = TC_ACT_PIPE }; /* good default */ struct rtattr *tail; struct rtattr *tail2; char dbuf[ETH_ALEN]; @@ -69,9 +69,6 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, char *daddr = NULL; char *saddr = NULL; - memset(&p, 0, sizeof(p)); - p.action = TC_ACT_PIPE; /* good default */ - if (argc <= 0) return -1; diff --git a/tc/m_mirred.c b/tc/m_mirred.c index 64aad4d22..0066905ac 100644 --- a/tc/m_mirred.c +++ b/tc/m_mirred.c @@ -69,12 +69,9 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, int argc = *argc_p; char **argv = *argv_p; int ok = 0, iok = 0, mirror = 0, redir = 0; - struct tc_mirred p; + struct tc_mirred p = {}; struct rtattr *tail; - char d[16]; - - memset(d, 0, sizeof(d)-1); - memset(&p, 0, sizeof(struct tc_mirred)); + char d[16] = {}; while (argc > 0) { diff --git a/tc/m_nat.c b/tc/m_nat.c index 4d1b1edfe..839fb8a05 100644 --- a/tc/m_nat.c +++ b/tc/m_nat.c @@ -84,15 +84,13 @@ parse_nat_args(int *argc_p, char ***argv_p, struct tc_nat *sel) static int parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { - struct tc_nat sel; + struct tc_nat sel = {}; int argc = *argc_p; char **argv = *argv_p; int ok = 0; struct rtattr *tail; - memset(&sel, 0, sizeof(sel)); - while (argc > 0) { if (matches(*argv, "nat") == 0) { NEXT_ARG(); diff --git a/tc/m_pedit.c b/tc/m_pedit.c index 64533060c..141c30fb6 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -392,7 +392,7 @@ int parse_offset(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, static int parse_munge(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel) { - struct tc_pedit_key tkey; + struct tc_pedit_key tkey = {}; int argc = *argc_p; char **argv = *argv_p; int res = -1; @@ -400,8 +400,6 @@ static int parse_munge(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel) if (argc <= 0) return -1; - memset(&tkey, 0, sizeof(tkey)); - if (matches(*argv, "offset") == 0) { NEXT_ARG(); res = parse_offset(&argc, &argv, sel, &tkey); @@ -442,15 +440,13 @@ int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct { struct tc_pedit_sel sel; struct tc_pedit_key keys[MAX_OFFS]; - } sel; + } sel = {}; int argc = *argc_p; char **argv = *argv_p; int ok = 0, iok = 0; struct rtattr *tail; - memset(&sel, 0, sizeof(sel)); - while (argc > 0) { if (pedit_debug > 1) fprintf(stderr, "while pedit (%d:%s)\n", argc, *argv); diff --git a/tc/m_police.c b/tc/m_police.c index a8b65dd9c..9ae25f288 100644 --- a/tc/m_police.c +++ b/tc/m_police.c @@ -127,7 +127,7 @@ int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p, char **argv = *argv_p; int res = -1; int ok = 0; - struct tc_police p; + struct tc_police p = { .action = TC_POLICE_RECLASSIFY }; __u32 rtab[256]; __u32 ptab[256]; __u32 avrate = 0; @@ -138,9 +138,6 @@ int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p, int Rcell_log = -1, Pcell_log = -1; struct rtattr *tail; - memset(&p, 0, sizeof(p)); - p.action = TC_POLICE_RECLASSIFY; - if (a) /* new way of doing things */ NEXT_ARG(); diff --git a/tc/q_atm.c b/tc/q_atm.c index a5b716fc5..01d46a3d4 100644 --- a/tc/q_atm.c +++ b/tc/q_atm.c @@ -47,7 +47,7 @@ static void explain(void) static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - struct sockaddr_atmsvc addr; + struct sockaddr_atmsvc addr = {}; struct atm_qos qos; struct atm_sap sap; unsigned char hdr[MAX_HDR_LEN]; @@ -58,7 +58,6 @@ static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, int set_clip = 0; int s; - memset(&addr, 0, sizeof(addr)); (void) text2qos("aal5,ubr:sdu=9180,rx:none", &qos, 0); (void) text2sap("blli:l2=iso8802", &sap, 0); while (argc > 0) { diff --git a/tc/q_cbq.c b/tc/q_cbq.c index faad73504..f148175cd 100644 --- a/tc/q_cbq.c +++ b/tc/q_cbq.c @@ -49,8 +49,8 @@ static void explain1(char *arg) static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - struct tc_ratespec r; - struct tc_cbq_lssopt lss; + struct tc_ratespec r = {}; + struct tc_cbq_lssopt lss = {}; __u32 rtab[256]; unsigned mpu = 0, avpkt = 0, allot = 0; unsigned short overhead = 0; @@ -59,9 +59,6 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl int ewma_log = -1; struct rtattr *tail; - memset(&lss, 0, sizeof(lss)); - memset(&r, 0, sizeof(r)); - while (argc > 0) { if (matches(*argv, "bandwidth") == 0 || matches(*argv, "rate") == 0) { @@ -183,11 +180,10 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { int wrr_ok = 0, fopt_ok = 0; - struct tc_ratespec r; - struct tc_cbq_lssopt lss; - struct tc_cbq_wrropt wrr; - struct tc_cbq_fopt fopt; - struct tc_cbq_ovl ovl; + struct tc_ratespec r = {}; + struct tc_cbq_lssopt lss = {}; + struct tc_cbq_wrropt wrr = {}; + struct tc_cbq_fopt fopt = {}; __u32 rtab[256]; unsigned mpu = 0; int cell_log = -1; @@ -198,12 +194,6 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ struct rtattr *tail; - memset(&r, 0, sizeof(r)); - memset(&lss, 0, sizeof(lss)); - memset(&wrr, 0, sizeof(wrr)); - memset(&fopt, 0, sizeof(fopt)); - memset(&ovl, 0, sizeof(ovl)); - while (argc > 0) { if (matches(*argv, "rate") == 0) { NEXT_ARG(); diff --git a/tc/q_choke.c b/tc/q_choke.c index e983bb50e..a234d2e01 100644 --- a/tc/q_choke.c +++ b/tc/q_choke.c @@ -34,7 +34,7 @@ static void explain(void) static int choke_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - struct tc_red_qopt opt; + struct tc_red_qopt opt = {}; unsigned int burst = 0; unsigned int avpkt = 1000; double probability = 0.02; @@ -45,8 +45,6 @@ static int choke_parse_opt(struct qdisc_util *qu, int argc, char **argv, __u32 max_P; struct rtattr *tail; - memset(&opt, 0, sizeof(opt)); - while (argc > 0) { if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); diff --git a/tc/q_codel.c b/tc/q_codel.c index 9221b48b6..09222a17e 100644 --- a/tc/q_codel.c +++ b/tc/q_codel.c @@ -175,7 +175,7 @@ static int codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) static int codel_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) { - struct tc_codel_xstats _st, *st; + struct tc_codel_xstats _st = {}, *st; SPRINT_BUF(b1); @@ -184,7 +184,6 @@ static int codel_print_xstats(struct qdisc_util *qu, FILE *f, st = RTA_DATA(xstats); if (RTA_PAYLOAD(xstats) < sizeof(*st)) { - memset(&_st, 0, sizeof(_st)); memcpy(&_st, st, RTA_PAYLOAD(xstats)); st = &_st; } diff --git a/tc/q_dsmark.c b/tc/q_dsmark.c index ab7b4d439..79dfd9a27 100644 --- a/tc/q_dsmark.c +++ b/tc/q_dsmark.c @@ -128,7 +128,6 @@ static int dsmark_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct rtattr *tb[TCA_DSMARK_MAX+1]; if (!opt) return 0; - memset(tb, 0, sizeof(tb)); parse_rtattr(tb, TCA_DSMARK_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt)); if (tb[TCA_DSMARK_MASK]) { if (!RTA_PAYLOAD(tb[TCA_DSMARK_MASK])) diff --git a/tc/q_fifo.c b/tc/q_fifo.c index f7fc88b38..3ee8ce9a9 100644 --- a/tc/q_fifo.c +++ b/tc/q_fifo.c @@ -31,9 +31,7 @@ static void explain(void) static int fifo_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { int ok = 0; - struct tc_fifo_qopt opt; - - memset(&opt, 0, sizeof(opt)); + struct tc_fifo_qopt opt = {}; while (argc > 0) { if (strcmp(*argv, "limit") == 0) { diff --git a/tc/q_fq_codel.c b/tc/q_fq_codel.c index f813badaa..500e6206e 100644 --- a/tc/q_fq_codel.c +++ b/tc/q_fq_codel.c @@ -220,7 +220,7 @@ static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) { - struct tc_fq_codel_xstats _st, *st; + struct tc_fq_codel_xstats _st = {}, *st; SPRINT_BUF(b1); @@ -229,7 +229,6 @@ static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, st = RTA_DATA(xstats); if (RTA_PAYLOAD(xstats) < sizeof(*st)) { - memset(&_st, 0, sizeof(_st)); memcpy(&_st, st, RTA_PAYLOAD(xstats)); st = &_st; } diff --git a/tc/q_hfsc.c b/tc/q_hfsc.c index 9ebe323ed..cf784f158 100644 --- a/tc/q_hfsc.c +++ b/tc/q_hfsc.c @@ -73,9 +73,7 @@ explain1(char *arg) static int hfsc_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - struct tc_hfsc_qopt qopt; - - memset(&qopt, 0, sizeof(qopt)); + struct tc_hfsc_qopt qopt = {}; while (argc > 0) { if (matches(*argv, "default") == 0) { @@ -146,15 +144,10 @@ static int hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - struct tc_service_curve rsc, fsc, usc; - int rsc_ok, fsc_ok, usc_ok; + struct tc_service_curve rsc = {}, fsc = {}, usc = {}; + int rsc_ok = 0, fsc_ok = 0, usc_ok = 0; struct rtattr *tail; - memset(&rsc, 0, sizeof(rsc)); - memset(&fsc, 0, sizeof(fsc)); - memset(&usc, 0, sizeof(usc)); - rsc_ok = fsc_ok = usc_ok = 0; - while (argc > 0) { if (matches(*argv, "rt") == 0) { NEXT_ARG(); diff --git a/tc/q_htb.c b/tc/q_htb.c index 9c1a4f86f..a811c2845 100644 --- a/tc/q_htb.c +++ b/tc/q_htb.c @@ -63,14 +63,13 @@ static void explain1(char *arg) static int htb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { unsigned int direct_qlen = ~0U; - struct tc_htb_glob opt; + struct tc_htb_glob opt = { + .rate2quantum = 10, + .version = 3, + }; struct rtattr *tail; unsigned int i; char *p; - memset(&opt, 0, sizeof(opt)); - opt.rate2quantum = 10; - opt.version = 3; - while (argc > 0) { if (matches(*argv, "r2q") == 0) { NEXT_ARG(); @@ -113,19 +112,17 @@ static int htb_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { int ok = 0; - struct tc_htb_opt opt; + struct tc_htb_opt opt = {}; __u32 rtab[256], ctab[256]; unsigned buffer = 0, cbuffer = 0; int cell_log = -1, ccell_log = -1; - unsigned int mtu; + unsigned int mtu = 1600; /* eth packet len */ unsigned short mpu = 0; unsigned short overhead = 0; unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */ struct rtattr *tail; __u64 ceil64 = 0, rate64 = 0; - memset(&opt, 0, sizeof(opt)); mtu = 1600; /* eth packet len */ - while (argc > 0) { if (matches(*argv, "prio") == 0) { NEXT_ARG(); diff --git a/tc/q_netem.c b/tc/q_netem.c index 8fe220416..0975ae111 100644 --- a/tc/q_netem.c +++ b/tc/q_netem.c @@ -175,23 +175,17 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, int dist_size = 0; struct rtattr *tail; struct tc_netem_qopt opt = { .limit = 1000 }; - struct tc_netem_corr cor; - struct tc_netem_reorder reorder; - struct tc_netem_corrupt corrupt; + struct tc_netem_corr cor = {}; + struct tc_netem_reorder reorder = {}; + struct tc_netem_corrupt corrupt = {}; struct tc_netem_gimodel gimodel; struct tc_netem_gemodel gemodel; - struct tc_netem_rate rate; + struct tc_netem_rate rate = {}; __s16 *dist_data = NULL; __u16 loss_type = NETEM_LOSS_UNSPEC; - int present[__TCA_NETEM_MAX]; + int present[__TCA_NETEM_MAX] = {}; __u64 rate64 = 0; - memset(&cor, 0, sizeof(cor)); - memset(&reorder, 0, sizeof(reorder)); - memset(&corrupt, 0, sizeof(corrupt)); - memset(&rate, 0, sizeof(rate)); - memset(present, 0, sizeof(present)); - for ( ; argc > 0; --argc, ++argv) { if (matches(*argv, "limit") == 0) { NEXT_ARG(); diff --git a/tc/q_red.c b/tc/q_red.c index e015cbdaf..ec706aaf2 100644 --- a/tc/q_red.c +++ b/tc/q_red.c @@ -35,7 +35,7 @@ static void explain(void) static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { - struct tc_red_qopt opt; + struct tc_red_qopt opt = {}; unsigned int burst = 0; unsigned int avpkt = 0; double probability = 0.02; @@ -45,8 +45,6 @@ static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl __u32 max_P; struct rtattr *tail; - memset(&opt, 0, sizeof(opt)); - while (argc > 0) { if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); diff --git a/tc/q_sfb.c b/tc/q_sfb.c index 3b6d45269..05c5f1325 100644 --- a/tc/q_sfb.c +++ b/tc/q_sfb.c @@ -51,17 +51,16 @@ 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 tc_sfb_qopt opt; + struct tc_sfb_qopt opt = { + .rehash_interval = 600*1000, + .warmup_time = 60*1000, + .penalty_rate = 10, + .penalty_burst = 20, + .increment = (SFB_MAX_PROB + 1000) / 2000, + .decrement = (SFB_MAX_PROB + 10000) / 20000, + }; struct rtattr *tail; - memset(&opt, 0, sizeof(opt)); - opt.rehash_interval = 600*1000; - opt.warmup_time = 60*1000; - opt.penalty_rate = 10; - opt.penalty_burst = 20; - opt.increment = (SFB_MAX_PROB + 1000) / 2000; - opt.decrement = (SFB_MAX_PROB + 10000) / 20000; - while (argc > 0) { if (strcmp(*argv, "rehash") == 0) { NEXT_ARG(); diff --git a/tc/q_sfq.c b/tc/q_sfq.c index 7d2165226..b5a989500 100644 --- a/tc/q_sfq.c +++ b/tc/q_sfq.c @@ -38,14 +38,12 @@ static void explain(void) static int sfq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n) { int ok = 0, red = 0; - struct tc_sfq_qopt_v1 opt; + struct tc_sfq_qopt_v1 opt = {}; unsigned int burst = 0; int wlog; unsigned int avpkt = 1000; double probability = 0.02; - memset(&opt, 0, sizeof(opt)); - while (argc > 0) { if (strcmp(*argv, "quantum") == 0) { NEXT_ARG(); diff --git a/tc/q_tbf.c b/tc/q_tbf.c index 4a0c5ac75..18b2193b4 100644 --- a/tc/q_tbf.c +++ b/tc/q_tbf.c @@ -39,7 +39,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) { int ok = 0; - struct tc_tbf_qopt opt; + struct tc_tbf_qopt opt = {}; __u32 rtab[256]; __u32 ptab[256]; unsigned buffer = 0, mtu = 0, mpu = 0, latency = 0; @@ -49,8 +49,6 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl struct rtattr *tail; __u64 rate64 = 0, prate64 = 0; - memset(&opt, 0, sizeof(opt)); - while (argc > 0) { if (matches(*argv, "limit") == 0) { NEXT_ARG(); diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index 7eb1cd74a..907393270 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -90,9 +90,8 @@ static int bpf(int cmd, union bpf_attr *attr, unsigned int size) static int bpf_map_update(int fd, const void *key, const void *value, uint64_t flags) { - union bpf_attr attr; + union bpf_attr attr = {}; - memset(&attr, 0, sizeof(attr)); attr.map_fd = fd; attr.key = bpf_ptr_to_u64(key); attr.value = bpf_ptr_to_u64(value); @@ -247,7 +246,7 @@ static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, int length) { char file[PATH_MAX], buff[4096]; - struct bpf_elf_map tmp, zero; + struct bpf_elf_map tmp = {}, zero = {}; unsigned int val; FILE *fp; @@ -259,7 +258,6 @@ static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, return -EIO; } - memset(&tmp, 0, sizeof(tmp)); while (fgets(buff, sizeof(buff), fp)) { if (sscanf(buff, "map_type:\t%u", &val) == 1) tmp.type = val; @@ -278,7 +276,6 @@ static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map, if (!memcmp(&tmp, map, length)) { return 0; } else { - memset(&zero, 0, sizeof(zero)); /* If kernel doesn't have eBPF-related fdinfo, we cannot do much, * so just accept it. We know we do have an eBPF fd and in this * case, everything is 0. It is guaranteed that no such map exists @@ -469,7 +466,7 @@ static const char *bpf_get_tc_dir(void) static int bpf_obj_get(const char *pathname) { - union bpf_attr attr; + union bpf_attr attr = {}; char tmp[PATH_MAX]; if (strlen(pathname) > 2 && pathname[0] == 'm' && @@ -479,7 +476,6 @@ static int bpf_obj_get(const char *pathname) pathname = tmp; } - memset(&attr, 0, sizeof(attr)); attr.pathname = bpf_ptr_to_u64(pathname); return bpf(BPF_OBJ_GET, &attr, sizeof(attr)); @@ -810,9 +806,8 @@ static int bpf_map_create(enum bpf_map_type type, uint32_t size_key, uint32_t size_value, uint32_t max_elem, uint32_t flags) { - union bpf_attr attr; + union bpf_attr attr = {}; - memset(&attr, 0, sizeof(attr)); attr.map_type = type; attr.key_size = size_key; attr.value_size = size_value; @@ -826,9 +821,8 @@ static 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) { - union bpf_attr attr; + union bpf_attr attr = {}; - memset(&attr, 0, sizeof(attr)); attr.prog_type = type; attr.insns = bpf_ptr_to_u64(insns); attr.insn_cnt = size_insns / sizeof(struct bpf_insn); @@ -845,9 +839,8 @@ static int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, static int bpf_obj_pin(int fd, const char *pathname) { - union bpf_attr attr; + union bpf_attr attr = {}; - memset(&attr, 0, sizeof(attr)); attr.pathname = bpf_ptr_to_u64(pathname); attr.bpf_fd = fd; @@ -1632,7 +1625,7 @@ static bool bpf_pinning_reserved(uint32_t pinning) static void bpf_hash_init(struct bpf_elf_ctx *ctx, const char *db_file) { struct bpf_hash_entry *entry; - char subpath[PATH_MAX]; + char subpath[PATH_MAX] = {}; uint32_t pinning; FILE *fp; int ret; @@ -1641,7 +1634,6 @@ static void bpf_hash_init(struct bpf_elf_ctx *ctx, const char *db_file) if (!fp) return; - memset(subpath, 0, sizeof(subpath)); while ((ret = bpf_read_pin_mapping(fp, &pinning, subpath))) { if (ret == -1) { fprintf(stderr, "Database %s is corrupted at: %s\n", @@ -1869,16 +1861,14 @@ static int bpf_map_set_send(int fd, struct sockaddr_un *addr, unsigned int addr_len, const struct bpf_map_data *aux, unsigned int entries) { - struct bpf_map_set_msg msg; + struct bpf_map_set_msg msg = { + .aux.uds_ver = BPF_SCM_AUX_VER, + .aux.num_ent = entries, + }; int *cmsg_buf, min_fd; char *amsg_buf; int i; - memset(&msg, 0, sizeof(msg)); - - msg.aux.uds_ver = BPF_SCM_AUX_VER; - msg.aux.num_ent = entries; - strncpy(msg.aux.obj_name, aux->obj, sizeof(msg.aux.obj_name)); memcpy(&msg.aux.obj_st, aux->st, sizeof(msg.aux.obj_st)); @@ -1952,8 +1942,13 @@ bpf_map_set_recv(int fd, int *fds, struct bpf_map_aux *aux, int bpf_send_map_fds(const char *path, const char *obj) { struct bpf_elf_ctx *ctx = &__ctx; - struct sockaddr_un addr; - struct bpf_map_data bpf_aux; + struct sockaddr_un addr = { .sun_family = AF_UNIX }; + struct bpf_map_data bpf_aux = { + .fds = ctx->map_fds, + .ent = ctx->maps, + .st = &ctx->stat, + .obj = obj, + }; int fd, ret; fd = socket(AF_UNIX, SOCK_DGRAM, 0); @@ -1963,8 +1958,6 @@ int bpf_send_map_fds(const char *path, const char *obj) return -1; } - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; strncpy(addr.sun_path, path, sizeof(addr.sun_path)); ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); @@ -1974,13 +1967,6 @@ int bpf_send_map_fds(const char *path, const char *obj) return -1; } - memset(&bpf_aux, 0, sizeof(bpf_aux)); - - bpf_aux.fds = ctx->map_fds; - bpf_aux.ent = ctx->maps; - bpf_aux.st = &ctx->stat; - bpf_aux.obj = obj; - ret = bpf_map_set_send(fd, &addr, sizeof(addr), &bpf_aux, bpf_maps_count(ctx)); if (ret < 0) @@ -1995,7 +1981,7 @@ int bpf_send_map_fds(const char *path, const char *obj) int bpf_recv_map_fds(const char *path, int *fds, struct bpf_map_aux *aux, unsigned int entries) { - struct sockaddr_un addr; + struct sockaddr_un addr = { .sun_family = AF_UNIX }; int fd, ret; fd = socket(AF_UNIX, SOCK_DGRAM, 0); @@ -2005,8 +1991,6 @@ int bpf_recv_map_fds(const char *path, int *fds, struct bpf_map_aux *aux, return -1; } - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; strncpy(addr.sun_path, path, sizeof(addr.sun_path)); ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); diff --git a/tc/tc_class.c b/tc/tc_class.c index 7747c8db3..ee9e945ac 100644 --- a/tc/tc_class.c +++ b/tc/tc_class.c @@ -61,21 +61,16 @@ static int tc_class_modify(int cmd, unsigned int flags, int argc, char **argv) struct nlmsghdr n; struct tcmsg t; char buf[4096]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .t.tcm_family = AF_UNSPEC, + }; struct qdisc_util *q = NULL; - struct tc_estimator est; - char d[16]; - char k[16]; - - memset(&req, 0, sizeof(req)); - memset(&est, 0, sizeof(est)); - memset(d, 0, sizeof(d)); - memset(k, 0, sizeof(k)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - req.t.tcm_family = AF_UNSPEC; + struct tc_estimator est = {}; + char d[16] = {}; + char k[16] = {}; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { @@ -395,14 +390,10 @@ int print_class(const struct sockaddr_nl *who, static int tc_class_list(int argc, char **argv) { - struct tcmsg t; - char d[16]; + struct tcmsg t = { .tcm_family = AF_UNSPEC }; + char d[16] = {}; char buf[1024] = {0}; - memset(&t, 0, sizeof(t)); - t.tcm_family = AF_UNSPEC; - memset(d, 0, sizeof(d)); - filter_qdisc = 0; filter_classid = 0; diff --git a/tc/tc_exec.c b/tc/tc_exec.c index 520801623..f69b6ba9f 100644 --- a/tc/tc_exec.c +++ b/tc/tc_exec.c @@ -85,7 +85,7 @@ static struct exec_util *get_exec_kind(const char *name) int do_exec(int argc, char **argv) { struct exec_util *eu; - char kind[16]; + char kind[16] = {}; if (argc < 1) { fprintf(stderr, "No command given, try \"tc exec help\".\n"); @@ -97,7 +97,6 @@ int do_exec(int argc, char **argv) return 0; } - memset(kind, 0, sizeof(kind)); strncpy(kind, *argv, sizeof(kind) - 1); eu = get_exec_kind(kind); diff --git a/tc/tc_filter.c b/tc/tc_filter.c index 66586634d..7e78e13ca 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -47,26 +47,20 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv) struct nlmsghdr n; struct tcmsg t; char buf[MAX_MSG]; - } req; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .t.tcm_family = AF_UNSPEC, + }; struct filter_util *q = NULL; __u32 prio = 0; __u32 protocol = 0; int protocol_set = 0; char *fhandle = NULL; - char d[16]; - char k[16]; - struct tc_estimator est; - - memset(&req, 0, sizeof(req)); - memset(&est, 0, sizeof(est)); - memset(d, 0, sizeof(d)); - memset(k, 0, sizeof(k)); - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - req.t.tcm_family = AF_UNSPEC; + char d[16] = {}; + char k[16] = {}; + struct tc_estimator est = {}; if (cmd == RTM_NEWTFILTER && flags & NLM_F_CREATE) protocol = htons(ETH_P_ALL); @@ -213,7 +207,6 @@ int print_filter(const struct sockaddr_nl *who, return -1; } - memset(tb, 0, sizeof(tb)); parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); if (tb[TCA_KIND] == NULL) { @@ -278,16 +271,12 @@ int print_filter(const struct sockaddr_nl *who, static int tc_filter_list(int argc, char **argv) { - struct tcmsg t; - char d[16]; + struct tcmsg t = { .tcm_family = AF_UNSPEC }; + char d[16] = {}; __u32 prio = 0; __u32 protocol = 0; char *fhandle = NULL; - memset(&t, 0, sizeof(t)); - t.tcm_family = AF_UNSPEC; - memset(d, 0, sizeof(d)); - while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index a63c47625..bc87aab11 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -49,25 +49,19 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv) struct { struct tc_sizespec szopts; __u16 *data; - } stab; - char d[16]; - char k[16]; + } stab = {}; + char d[16] = {}; + char k[16] = {}; struct { struct nlmsghdr n; struct tcmsg t; char buf[TCA_BUF_MAX]; - } req; - - memset(&req, 0, sizeof(req)); - memset(&stab, 0, sizeof(stab)); - memset(&est, 0, sizeof(est)); - memset(&d, 0, sizeof(d)); - memset(&k, 0, sizeof(k)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST|flags; - req.n.nlmsg_type = cmd; - req.t.tcm_family = AF_UNSPEC; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + .n.nlmsg_flags = NLM_F_REQUEST | flags, + .n.nlmsg_type = cmd, + .t.tcm_family = AF_UNSPEC, + }; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { @@ -227,7 +221,6 @@ int print_qdisc(const struct sockaddr_nl *who, if (filter_ifindex && filter_ifindex != t->tcm_ifindex) return 0; - memset(tb, 0, sizeof(tb)); parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); if (tb[TCA_KIND] == NULL) { @@ -287,12 +280,8 @@ int print_qdisc(const struct sockaddr_nl *who, static int tc_qdisc_list(int argc, char **argv) { - struct tcmsg t; - char d[16]; - - memset(&t, 0, sizeof(t)); - t.tcm_family = AF_UNSPEC; - memset(&d, 0, sizeof(d)); + struct tcmsg t = { .tcm_family = AF_UNSPEC }; + char d[16] = {}; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { diff --git a/tc/tc_stab.c b/tc/tc_stab.c index d7e00025c..dc20dd195 100644 --- a/tc/tc_stab.c +++ b/tc/tc_stab.c @@ -53,9 +53,7 @@ int parse_size_table(int *argcp, char ***argvp, struct tc_sizespec *sp) { char **argv = *argvp; int argc = *argcp; - struct tc_sizespec s; - - memset(&s, 0, sizeof(s)); + struct tc_sizespec s = {}; NEXT_ARG(); if (matches(*argv, "help") == 0) { diff --git a/tc/tc_util.c b/tc/tc_util.c index afc4cf5ac..fd6669f28 100644 --- a/tc/tc_util.c +++ b/tc/tc_util.c @@ -580,10 +580,9 @@ void print_tcstats_attr(FILE *fp, struct rtattr *tb[], char *prefix, struct rtat } /* backward compatibility */ if (tb[TCA_STATS]) { - struct tc_stats st; + struct tc_stats st = {}; /* handle case where kernel returns more/less than we know about */ - memset(&st, 0, sizeof(st)); memcpy(&st, RTA_DATA(tb[TCA_STATS]), MIN(RTA_PAYLOAD(tb[TCA_STATS]), sizeof(st))); fprintf(fp, "%sSent %llu bytes %u pkts (dropped %u, overlimits %u) ", From f89bb0210fcf7bc52f9bc743bbc92c811b1f578a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 18 Jul 2016 16:48:43 +0200 Subject: [PATCH 338/513] Replace malloc && memset by calloc This only replaces occurrences where the newly allocated memory is cleared completely afterwards, as in other cases it is a theoretical performance hit although code would be cleaner this way. Signed-off-by: Phil Sutter Acked-by: David Ahern --- genl/genl.c | 3 +-- lib/names.c | 7 ++----- misc/lnstat.c | 6 ++---- misc/lnstat_util.c | 4 +--- tc/em_canid.c | 4 ++-- tc/m_action.c | 3 +-- tc/m_ipt.c | 13 ++++--------- tc/m_pedit.c | 3 +-- tc/tc.c | 9 +++------ tc/tc_bpf.c | 4 +--- tc/tc_class.c | 3 +-- tc/tc_exec.c | 3 +-- 12 files changed, 20 insertions(+), 42 deletions(-) diff --git a/genl/genl.c b/genl/genl.c index e33fafdf2..747074b02 100644 --- a/genl/genl.c +++ b/genl/genl.c @@ -86,9 +86,8 @@ static struct genl_util *get_genl_kind(const char *str) return f; noexist: - f = malloc(sizeof(*f)); + f = calloc(1, sizeof(*f)); if (f) { - memset(f, 0, sizeof(*f)); strncpy(f->name, str, 15); f->parse_genlopt = parse_nofopt; f->print_genlopt = print_nofopt; diff --git a/lib/names.c b/lib/names.c index 3b5b0b1e1..fbd6503f2 100644 --- a/lib/names.c +++ b/lib/names.c @@ -54,15 +54,12 @@ struct db_names *db_names_alloc(void) { struct db_names *db; - db = malloc(sizeof(*db)); + db = calloc(1, sizeof(*db)); if (!db) return NULL; - memset(db, 0, sizeof(*db)); - db->size = MAX_ENTRIES; - db->hash = malloc(sizeof(struct db_entry *) * db->size); - memset(db->hash, 0, sizeof(struct db_entry *) * db->size); + db->hash = calloc(db->size, sizeof(struct db_entry *)); return db; } diff --git a/misc/lnstat.c b/misc/lnstat.c index 659a01bd6..863fd4d9f 100644 --- a/misc/lnstat.c +++ b/misc/lnstat.c @@ -182,10 +182,8 @@ static struct table_hdr *build_hdr_string(struct lnstat_file *lnstat_files, static struct table_hdr th; int ofs = 0; - for (i = 0; i < HDR_LINES; i++) { - th.hdr[i] = malloc(HDR_LINE_LENGTH); - memset(th.hdr[i], 0, HDR_LINE_LENGTH); - } + for (i = 0; i < HDR_LINES; i++) + th.hdr[i] = calloc(1, HDR_LINE_LENGTH); for (i = 0; i < fps->num; i++) { char *cname, *fname = fps->params[i].lf->name; diff --git a/misc/lnstat_util.c b/misc/lnstat_util.c index d91815128..cc54598fe 100644 --- a/misc/lnstat_util.c +++ b/misc/lnstat_util.c @@ -173,15 +173,13 @@ static struct lnstat_file *alloc_and_open(const char *path, const char *file) struct lnstat_file *lf; /* allocate */ - lf = malloc(sizeof(*lf)); + lf = calloc(1, sizeof(*lf)); if (!lf) { fprintf(stderr, "out of memory\n"); return NULL; } /* initialize */ - memset(lf, 0, sizeof(*lf)); - /* de->d_name is guaranteed to be <= NAME_MAX */ strcpy(lf->basename, file); strcpy(lf->path, path); diff --git a/tc/em_canid.c b/tc/em_canid.c index 16f6ed5c0..ceb64cb93 100644 --- a/tc/em_canid.c +++ b/tc/em_canid.c @@ -106,8 +106,8 @@ static int canid_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr, if (args == NULL) return PARSE_ERR(args, "canid: missing arguments"); - rules.rules_raw = malloc(sizeof(struct can_filter) * rules.rules_capacity); - memset(rules.rules_raw, 0, sizeof(struct can_filter) * rules.rules_capacity); + rules.rules_raw = calloc(rules.rules_capacity, + sizeof(struct can_filter)); do { if (!bstrcmp(args, "sff")) { diff --git a/tc/m_action.c b/tc/m_action.c index 806fdd197..24f8b5d85 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -126,9 +126,8 @@ static struct action_util *get_action_kind(char *str) goto restart_s; } #endif - a = malloc(sizeof(*a)); + a = calloc(1, sizeof(*a)); if (a) { - memset(a, 0, sizeof(*a)); strncpy(a->id, "noact", 15); a->parse_aopt = parse_noaopt; a->print_aopt = print_noaopt; diff --git a/tc/m_ipt.c b/tc/m_ipt.c index 098f610f9..d6f62bd6b 100644 --- a/tc/m_ipt.c +++ b/tc/m_ipt.c @@ -164,16 +164,11 @@ get_target_name(const char *name) return NULL; #endif - new_name = malloc(strlen(name) + 1); - lname = malloc(strlen(name) + 1); - if (new_name) - memset(new_name, '\0', strlen(name) + 1); - else + new_name = calloc(1, strlen(name) + 1); + lname = calloc(1, strlen(name) + 1); + if (!new_name) exit_error(PARAMETER_PROBLEM, "get_target_name"); - - if (lname) - memset(lname, '\0', strlen(name) + 1); - else + if (!lname) exit_error(PARAMETER_PROBLEM, "get_target_name"); strcpy(new_name, name); diff --git a/tc/m_pedit.c b/tc/m_pedit.c index 141c30fb6..35879b7fb 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -107,9 +107,8 @@ static struct m_pedit_util *get_pedit_kind(const char *str) return p; noexist: - p = malloc(sizeof(*p)); + p = calloc(1, sizeof(*p)); if (p) { - memset(p, 0, sizeof(*p)); strncpy(p->id, str, sizeof(p->id) - 1); p->parse_peopt = pedit_parse_nopopt; goto reg; diff --git a/tc/tc.c b/tc/tc.c index d0ddb939d..8e64a82b4 100644 --- a/tc/tc.c +++ b/tc/tc.c @@ -133,11 +133,9 @@ struct qdisc_util *get_qdisc_kind(const char *str) return q; noexist: - q = malloc(sizeof(*q)); + q = calloc(1, sizeof(*q)); if (q) { - - memset(q, 0, sizeof(*q)); - q->id = strcpy(malloc(strlen(str)+1), str); + q->id = strdup(str); q->parse_qopt = parse_noqopt; q->print_qopt = print_noqopt; goto reg; @@ -177,9 +175,8 @@ struct filter_util *get_filter_kind(const char *str) filter_list = q; return q; noexist: - q = malloc(sizeof(*q)); + q = calloc(1, sizeof(*q)); if (q) { - memset(q, 0, sizeof(*q)); strncpy(q->id, str, 15); q->parse_fopt = parse_nofopt; q->print_fopt = print_nofopt; diff --git a/tc/tc_bpf.c b/tc/tc_bpf.c index 907393270..b390f7e2b 100644 --- a/tc/tc_bpf.c +++ b/tc/tc_bpf.c @@ -112,12 +112,10 @@ static int bpf_parse_string(char *arg, bool from_file, __u16 *bpf_len, FILE *fp; tmp_len = sizeof("4096,") + BPF_MAXINSNS * op_len; - tmp_string = malloc(tmp_len); + tmp_string = calloc(1, tmp_len); if (tmp_string == NULL) return -ENOMEM; - memset(tmp_string, 0, tmp_len); - fp = fopen(arg, "r"); if (fp == NULL) { perror("Cannot fopen"); diff --git a/tc/tc_class.c b/tc/tc_class.c index ee9e945ac..1690ec1bb 100644 --- a/tc/tc_class.c +++ b/tc/tc_class.c @@ -163,9 +163,8 @@ __u32 filter_classid; static void graph_node_add(__u32 parent_id, __u32 id, void *data, int len) { - struct graph_node *node = malloc(sizeof(struct graph_node)); + struct graph_node *node = calloc(1, sizeof(struct graph_node)); - memset(node, 0, sizeof(*node)); node->id = id; node->parent_id = parent_id; diff --git a/tc/tc_exec.c b/tc/tc_exec.c index f69b6ba9f..d23a825db 100644 --- a/tc/tc_exec.c +++ b/tc/tc_exec.c @@ -71,9 +71,8 @@ static struct exec_util *get_exec_kind(const char *name) return eu; noexist: - eu = malloc(sizeof(*eu)); + eu = calloc(1, sizeof(*eu)); if (eu) { - memset(eu, 0, sizeof(*eu)); strncpy(eu->id, name, sizeof(eu->id) - 1); eu->parse_eopt = parse_noeopt; goto reg; From 30a8842c4971f4215733bc1a8ddc4b8315edb99b Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 18 Jul 2016 16:48:44 +0200 Subject: [PATCH 339/513] No need to initialize rtattr fields before parsing Since parse_rtattr_flags() calls memset already, there is no need for callers to do so themselves. Signed-off-by: Phil Sutter Acked-by: David Ahern --- ip/ipaddress.c | 2 +- tc/tc_class.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index cfcebe76a..60862c570 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -449,7 +449,7 @@ static void print_num(FILE *fp, unsigned int width, uint64_t count) static void print_vf_stats64(FILE *fp, struct rtattr *vfstats) { - struct rtattr *vf[IFLA_VF_STATS_MAX + 1] = {}; + struct rtattr *vf[IFLA_VF_STATS_MAX + 1]; if (vfstats->rta_type != IFLA_VF_STATS) { fprintf(stderr, "BUG: rta type is %d\n", vfstats->rta_type); diff --git a/tc/tc_class.c b/tc/tc_class.c index 1690ec1bb..f3864d22f 100644 --- a/tc/tc_class.c +++ b/tc/tc_class.c @@ -219,7 +219,7 @@ static void graph_cls_show(FILE *fp, char *buf, struct hlist_head *root_list, { struct hlist_node *n, *tmp_cls; char cls_id_str[256] = {}; - struct rtattr *tb[TCA_MAX + 1] = {}; + struct rtattr *tb[TCA_MAX + 1]; struct qdisc_util *q; char str[100] = {}; @@ -304,7 +304,7 @@ int print_class(const struct sockaddr_nl *who, FILE *fp = (FILE *)arg; struct tcmsg *t = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr *tb[TCA_MAX + 1] = {}; + struct rtattr *tb[TCA_MAX + 1]; struct qdisc_util *q; char abuf[256]; From 7ffa2b557a81dc6f40b93223442df3db66980d80 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 18 Jul 2016 16:48:45 +0200 Subject: [PATCH 340/513] Makefile: Allow to override CC This makes it easier to build iproute2 with a custom compiler. While at it, make HOSTCC default to the value of CC if not explicitly set elsewhere. Signed-off-by: Phil Sutter Acked-by: David Ahern --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 15c81ecfd..fa200ddb7 100644 --- a/Makefile +++ b/Makefile @@ -34,8 +34,8 @@ ADDLIB+=ipx_ntop.o ipx_pton.o #options for mpls ADDLIB+=mpls_ntop.o mpls_pton.o -CC = gcc -HOSTCC = gcc +CC := gcc +HOSTCC ?= $(CC) DEFINES += -D_GNU_SOURCE # Turn on transparent support for LFS DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE From 247ace611526e51d9f5a2f4b6e965c59b0f8b739 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 14 Jul 2016 23:10:53 +0200 Subject: [PATCH 341/513] tc: ematch: Ignore all-zero mask value when printing filters The optional mask which may be added to int values is considered by the kernel only if it is non-zero, therefore tc should only then also print it. Without this, not passing a mask value like so: | # tc filter add dev d0 parent 8001: \ | basic match meta\(vlan eq 1\) \ | classid 8001:1 Would lead to tc printing an all-zero mask later: | # tc filter show dev d0 | filter parent 8001: protocol all pref 49151 basic | filter parent 8001: protocol all pref 49151 basic handle 0x1 flowid 8001:1 | meta(vlan mask 0x00000000 eq 1) This is obviously confusing as an all-zero mask strictly means to eliminate all bits from the value, but the opposite is the case. Cc: Thomas Graf Signed-off-by: Phil Sutter --- tc/em_meta.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tc/em_meta.c b/tc/em_meta.c index b00dd3588..bf4709379 100644 --- a/tc/em_meta.c +++ b/tc/em_meta.c @@ -483,8 +483,9 @@ static int print_object(FILE *fd, struct tcf_meta_val *obj, struct rtattr *rta) if (RTA_PAYLOAD(rta) < sizeof(__u32)) goto size_mismatch; - fprintf(fd, " mask 0x%08x", - rta_getattr_u32(rta)); + if (rta_getattr_u32(rta)) + fprintf(fd, " mask 0x%08x", + rta_getattr_u32(rta)); } break; } From 6acf086c2bf3e94ceed984acd39936e216342e16 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 12 Jul 2016 09:56:16 +0200 Subject: [PATCH 342/513] ip-address.8: Document autojoin flag Description copied from related kernel support commit message with a little tailoring to fit. While at it, fix font of non-terminal CONFFLAG-LIST in synopsis. Signed-off-by: Phil Sutter --- man/man8/ip-address.8.in | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/man/man8/ip-address.8.in b/man/man8/ip-address.8.in index 7cb927173..7d6eb9b2b 100644 --- a/man/man8/ip-address.8.in +++ b/man/man8/ip-address.8.in @@ -77,14 +77,15 @@ ip-address \- protocol address management .IR FLAG " := " .RB "[ " permanent " | " dynamic " | " secondary " | " primary " |" .RB [ - ] tentative " | [" - ] deprecated " | [" - ] dadfailed " |" -.BR temporary " | " CONFFLAG-LIST " ]" +.BR temporary " |" +.IR CONFFLAG-LIST " ]" .ti -8 .IR CONFFLAG-LIST " := [ " CONFFLAG-LIST " ] " CONFFLAG .ti -8 .IR CONFFLAG " := " -.RB "[ " home " | " mngtmpaddr " | " nodad " | " noprefixroute " ]" +.RB "[ " home " | " mngtmpaddr " | " nodad " | " noprefixroute " | " autojoin " ]" .ti -8 .IR LIFETIME " := [ " @@ -249,6 +250,26 @@ address, and don't search for one to delete when removing the address. Changing an address to add this flag will remove the automatically added prefix route, changing it to remove this flag will create the prefix route automatically. +.TP +.B autojoin +Joining multicast groups on Ethernet level via +.B "ip maddr" +command does not work if connected to an Ethernet switch that does IGMP +snooping since the switch would not replicate multicast packets on ports that +did not have IGMP reports for the multicast addresses. + +Linux VXLAN interfaces created via +.B "ip link add vxlan" +have the +.B group +option that enables them to do the required join. + +Using the +.B autojoin +flag when adding a multicast address enables similar functionality for +Openvswitch VXLAN interfaces as well as other tunneling mechanisms that need to +receive multicast traffic. + .SS ip address delete - delete protocol address .B Arguments: coincide with the arguments of From ba91cd9d863947b512d77ce9d0221b5046cc0d7a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 20 Jul 2016 12:24:59 -0700 Subject: [PATCH 343/513] include: update net-next XDP headers --- include/linux/bpf.h | 23 +++++++++++++++++++++++ include/linux/if_ether.h | 1 + include/linux/if_link.h | 12 ++++++++++++ 3 files changed, 36 insertions(+) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 7c55533e7..546d4ceca 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -94,6 +94,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_SCHED_CLS, BPF_PROG_TYPE_SCHED_ACT, BPF_PROG_TYPE_TRACEPOINT, + BPF_PROG_TYPE_XDP, }; #define BPF_PSEUDO_MAP_FD 1 @@ -401,6 +402,8 @@ enum bpf_func_id { /* BPF_FUNC_perf_event_output and BPF_FUNC_perf_event_read flags. */ #define BPF_F_INDEX_MASK 0xffffffffULL #define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK +/* BPF_FUNC_perf_event_output for sk_buff input context. */ +#define BPF_F_CTXLEN_MASK (0xfffffULL << 32) /* user accessible mirror of in-kernel sk_buff. * new fields can only be added to the end of this structure @@ -437,4 +440,24 @@ struct bpf_tunnel_key { __u32 tunnel_label; }; +/* User return codes for XDP prog type. + * A valid XDP program must return one of these defined values. All other + * return codes are reserved for future use. Unknown return codes will result + * in packet drop. + */ +enum xdp_action { + XDP_ABORTED = 0, + XDP_DROP, + XDP_PASS, + XDP_TX, +}; + +/* user accessible metadata for XDP packet hook + * new fields must be added to the end of this structure + */ +struct xdp_md { + __u32 data; + __u32 data_end; +}; + #endif /* __LINUX_BPF_H__ */ diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index c396f3179..51898e048 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -87,6 +87,7 @@ #define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ #define ETH_P_MVRP 0x88F5 /* 802.1Q MVRP */ #define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ +#define ETH_P_NCSI 0x88F8 /* NCSI protocol */ #define ETH_P_PRP 0x88FB /* IEC 62439-3 PRP/HSRv0 */ #define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ #define ETH_P_TDLS 0x890D /* TDLS */ diff --git a/include/linux/if_link.h b/include/linux/if_link.h index af0b2d8a2..1feb70890 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -156,6 +156,7 @@ enum { IFLA_GSO_MAX_SEGS, IFLA_GSO_MAX_SIZE, IFLA_PAD, + IFLA_XDP, __IFLA_MAX }; @@ -841,4 +842,15 @@ enum { }; #define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1) +/* XDP section */ + +enum { + IFLA_XDP_UNSPEC, + IFLA_XDP_FD, + IFLA_XDP_ATTACHED, + __IFLA_XDP_MAX, +}; + +#define IFLA_XDP_MAX (__IFLA_XDP_MAX - 1) + #endif /* _LINUX_IF_LINK_H */ From 9bf9d05b235936d03e41abe4ab15cd7cd59053b8 Mon Sep 17 00:00:00 2001 From: Shanker Wang Date: Thu, 21 Jul 2016 18:59:10 +0800 Subject: [PATCH 344/513] l2tp: add udp checksum control flags Three options are added for the user to control whether the checksum is enabled Signed-off-by: Miao Wang --- ip/ipl2tp.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index 1f84c6149..9ebda135e 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -56,6 +56,8 @@ struct l2tp_parm { uint16_t pw_type; uint16_t mtu; + int udp6_csum_tx:1; + int udp6_csum_rx:1; int udp_csum:1; int recv_seq:1; int send_seq:1; @@ -117,6 +119,12 @@ static int create_tunnel(struct l2tp_parm *p) if (p->encap == L2TP_ENCAPTYPE_UDP) { addattr16(&req.n, 1024, L2TP_ATTR_UDP_SPORT, p->local_udp_port); addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port); + if (p->udp_csum) + addattr(&req.n, 1024, L2TP_ATTR_UDP_CSUM); + if (!p->udp6_csum_tx) + addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_TX); + if (!p->udp6_csum_rx) + addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_RX); } if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0) @@ -282,6 +290,12 @@ static int get_response(struct nlmsghdr *n, void *arg) p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]); p->udp_csum = !!attrs[L2TP_ATTR_UDP_CSUM]; + /* + * Not fetching from L2TP_ATTR_UDP_ZERO_CSUM6_{T,R}X because the + * kernel doesn't send it so just leave it as default value. + */ + p->udp6_csum_tx = 1; + p->udp6_csum_rx = 1; if (attrs[L2TP_ATTR_COOKIE]) memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]), p->cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_COOKIE])); @@ -459,6 +473,9 @@ static void usage(void) fprintf(stderr, " tunnel_id ID peer_tunnel_id ID\n"); fprintf(stderr, " [ encap { ip | udp } ]\n"); fprintf(stderr, " [ udp_sport PORT ] [ udp_dport PORT ]\n"); + fprintf(stderr, " [ udp_csum { on | off } ]\n"); + fprintf(stderr, " [ udp6_csum_tx { on | off } ]\n"); + fprintf(stderr, " [ udp6_csum_rx { on | off } ]\n"); fprintf(stderr, "Usage: ip l2tp add session [ name NAME ]\n"); fprintf(stderr, " tunnel_id ID\n"); fprintf(stderr, " session_id ID peer_session_id ID\n"); @@ -489,6 +506,8 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p) /* Defaults */ p->l2spec_type = L2TP_L2SPECTYPE_DEFAULT; p->l2spec_len = 4; + p->udp6_csum_rx = 1; + p->udp6_csum_tx = 1; while (argc > 0) { if (strcmp(*argv, "encap") == 0) { @@ -558,6 +577,32 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p) if (get_u16(&uval, *argv, 0)) invarg("invalid port\n", *argv); p->peer_udp_port = uval; + } else if (strcmp(*argv, "udp_csum") == 0) { + NEXT_ARG(); + if (strcmp(*argv, "on") == 0) + p->udp_csum = 1; + else if (strcmp(*argv, "off") == 0) + p->udp_csum = 0; + else + invarg("invalid option for udp_csum\n", *argv); + } else if (strcmp(*argv, "udp6_csum_rx") == 0) { + NEXT_ARG(); + if (strcmp(*argv, "on") == 0) + p->udp6_csum_rx = 1; + else if (strcmp(*argv, "off") == 0) + p->udp6_csum_rx = 0; + else + invarg("invalid option for udp6_csum_rx\n" + , *argv); + } else if (strcmp(*argv, "udp6_csum_tx") == 0) { + NEXT_ARG(); + if (strcmp(*argv, "on") == 0) + p->udp6_csum_tx = 1; + else if (strcmp(*argv, "off") == 0) + p->udp6_csum_tx = 0; + else + invarg("invalid option for udp6_csum_tx\n" + , *argv); } else if (strcmp(*argv, "offset") == 0) { __u8 uval; From 9ffc80b1e49c4264fb20851e179aaa8ec0bc0766 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 23 Jul 2016 13:28:07 +0200 Subject: [PATCH 345/513] tc: Reformat tc_util.h * Drop 'extern' keyword before function declarations. * Add parameter names where they were missing for matters of consistency. * Drop fancy indenting (e.g. tab between type and name). * Break long lines to not exceed 80 columns. Signed-off-by: Phil Sutter --- tc/tc_util.h | 149 +++++++++++++++++++++++++++------------------------ 1 file changed, 78 insertions(+), 71 deletions(-) diff --git a/tc/tc_util.h b/tc/tc_util.h index 61e60b1c5..744f18fdd 100644 --- a/tc/tc_util.h +++ b/tc/tc_util.h @@ -22,89 +22,96 @@ enum struct qdisc_util { struct qdisc_util *next; const char *id; - int (*parse_qopt)(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n); - 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); - int (*print_copt)(struct qdisc_util *qu, FILE *f, struct rtattr *opt); + int (*parse_qopt)(struct qdisc_util *qu, int argc, + char **argv, struct nlmsghdr *n); + 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); + int (*print_copt)(struct qdisc_util *qu, FILE *f, struct rtattr *opt); }; extern __u16 f_proto; struct filter_util { struct filter_util *next; - char id[16]; - int (*parse_fopt)(struct filter_util *qu, char *fhandle, int argc, - char **argv, struct nlmsghdr *n); - int (*print_fopt)(struct filter_util *qu, FILE *f, struct rtattr *opt, __u32 fhandle); + char id[16]; + int (*parse_fopt)(struct filter_util *qu, char *fhandle, + int argc, char **argv, struct nlmsghdr *n); + int (*print_fopt)(struct filter_util *qu, + FILE *f, struct rtattr *opt, __u32 fhandle); }; struct action_util { - struct action_util *next; - char id[16]; - 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); - int (*print_xstats)(struct action_util *au, FILE *f, struct rtattr *xstats); + struct action_util *next; + char id[16]; + 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); + int (*print_xstats)(struct action_util *au, + FILE *f, struct rtattr *xstats); }; struct exec_util { - struct exec_util *next; - char id[16]; - int (*parse_eopt)(struct exec_util *eu, int argc, char **argv); + struct exec_util *next; + char id[16]; + int (*parse_eopt)(struct exec_util *eu, int argc, char **argv); }; -extern const char *get_tc_lib(void); - -extern struct qdisc_util *get_qdisc_kind(const char *str); -extern struct filter_util *get_filter_kind(const char *str); - -extern int get_qdisc_handle(__u32 *h, const char *str); -extern int get_rate(unsigned *rate, const char *str); -extern int get_rate64(__u64 *rate, const char *str); -extern int get_size(unsigned *size, const char *str); -extern int get_size_and_cell(unsigned *size, int *cell_log, char *str); -extern int get_time(unsigned *time, const char *str); -extern int get_linklayer(unsigned *val, const char *arg); - -extern void print_rate(char *buf, int len, __u64 rate); -extern void print_size(char *buf, int len, __u32 size); -extern void print_qdisc_handle(char *buf, int len, __u32 h); -extern void print_time(char *buf, int len, __u32 time); -extern void print_linklayer(char *buf, int len, unsigned linklayer); - -extern char * sprint_rate(__u64 rate, char *buf); -extern char * sprint_size(__u32 size, char *buf); -extern char * sprint_qdisc_handle(__u32 h, char *buf); -extern char * sprint_tc_classid(__u32 h, char *buf); -extern char * sprint_time(__u32 time, char *buf); -extern char * sprint_ticks(__u32 ticks, char *buf); -extern char * sprint_linklayer(unsigned linklayer, char *buf); - -extern void print_tcstats_attr(FILE *fp, struct rtattr *tb[], char *prefix, struct rtattr **xstats); -extern void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtattr **xstats); - -extern int get_tc_classid(__u32 *h, const char *str); -extern int print_tc_classid(char *buf, int len, __u32 h); -extern char * sprint_tc_classid(__u32 h, char *buf); - -extern int tc_print_police(FILE *f, struct rtattr *tb); -extern int parse_police(int *, char ***, int, struct nlmsghdr *); - -extern char *action_n2a(int action, char *buf, int len); -extern int action_a2n(char *arg, int *result); -extern int act_parse_police(struct action_util *a,int *, char ***, int, struct nlmsghdr *); -extern int print_police(struct action_util *a, FILE *f, - struct rtattr *tb); -extern int police_print_xstats(struct action_util *a,FILE *f, - struct rtattr *tb); -extern int tc_print_action(FILE *f, const struct rtattr *tb); -extern int tc_print_ipt(FILE *f, const struct rtattr *tb); -extern int parse_action(int *, char ***, int, struct nlmsghdr *); -extern void print_tm(FILE *f, const struct tcf_t *tm); -extern int prio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt); - -extern int cls_names_init(char *path); -extern void cls_names_uninit(void); +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 get_qdisc_handle(__u32 *h, const char *str); +int get_rate(unsigned int *rate, const char *str); +int get_rate64(__u64 *rate, const char *str); +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); +int get_linklayer(unsigned int *val, const char *arg); + +void print_rate(char *buf, int len, __u64 rate); +void print_size(char *buf, int len, __u32 size); +void print_qdisc_handle(char *buf, int len, __u32 h); +void print_time(char *buf, int len, __u32 time); +void print_linklayer(char *buf, int len, unsigned int linklayer); + +char *sprint_rate(__u64 rate, char *buf); +char *sprint_size(__u32 size, char *buf); +char *sprint_qdisc_handle(__u32 h, char *buf); +char *sprint_tc_classid(__u32 h, char *buf); +char *sprint_time(__u32 time, char *buf); +char *sprint_ticks(__u32 ticks, char *buf); +char *sprint_linklayer(unsigned int linklayer, char *buf); + +void print_tcstats_attr(FILE *fp, struct rtattr *tb[], + char *prefix, struct rtattr **xstats); +void print_tcstats2_attr(FILE *fp, struct rtattr *rta, + char *prefix, struct rtattr **xstats); + +int get_tc_classid(__u32 *h, const char *str); +int print_tc_classid(char *buf, int len, __u32 h); +char *sprint_tc_classid(__u32 h, char *buf); + +int tc_print_police(FILE *f, struct rtattr *tb); +int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n); + +char *action_n2a(int action, char *buf, int len); +int action_a2n(char *arg, int *result); +int act_parse_police(struct action_util *a, int *argc_p, + char ***argv_p, int tca_id, struct nlmsghdr *n); +int print_police(struct action_util *a, FILE *f, struct rtattr *tb); +int police_print_xstats(struct action_util *a, FILE *f, struct rtattr *tb); +int tc_print_action(FILE *f, const struct rtattr *tb); +int tc_print_ipt(FILE *f, const struct rtattr *tb); +int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n); +void print_tm(FILE *f, const struct tcf_t *tm); +int prio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt); + +int cls_names_init(char *path); +void cls_names_uninit(void); #endif From 53aadc5286261fecb6e994918db8371515f9dd99 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 23 Jul 2016 13:28:08 +0200 Subject: [PATCH 346/513] tc: util: bore up action_a2n() It's a pitty this function is used nowhere, so let's polish it for use: * Loop over branch names, makes it clear that every former conditional was exactly identical. * Support 'pipe' branch name, too. * Make number parsing optional. Signed-off-by: Phil Sutter --- tc/tc_util.c | 56 ++++++++++++++++++++++++++++++++-------------------- tc/tc_util.h | 2 +- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/tc/tc_util.c b/tc/tc_util.c index fd6669f28..cd7b40b0a 100644 --- a/tc/tc_util.c +++ b/tc/tc_util.c @@ -435,29 +435,43 @@ char *action_n2a(int action, char *buf, int len) } } -int action_a2n(char *arg, int *result) +/* Convert action branch name into numeric format. + * + * Parameters: + * @arg - string to parse + * @result - pointer to output variable + * @allow_num - whether @arg may be in numeric format already + * + * In error case, returns -1 and does not touch @result. Otherwise returns 0. + */ +int action_a2n(char *arg, int *result, bool allow_num) { - int res; - - if (matches(arg, "continue") == 0) - res = -1; - else if (matches(arg, "drop") == 0) - res = TC_ACT_SHOT; - else if (matches(arg, "shot") == 0) - res = TC_ACT_SHOT; - else if (matches(arg, "pass") == 0) - res = TC_ACT_OK; - else if (strcmp(arg, "ok") == 0) - res = TC_ACT_OK; - else if (matches(arg, "reclassify") == 0) - res = TC_ACT_RECLASSIFY; - else { - char dummy; - - if (sscanf(arg, "%d%c", &res, &dummy) != 1) - return -1; + int n; + char dummy; + struct { + const char *a; + int n; + } a2n[] = { + {"continue", TC_ACT_UNSPEC}, + {"drop", TC_ACT_SHOT}, + {"shot", TC_ACT_SHOT}, + {"pass", TC_ACT_OK}, + {"ok", TC_ACT_OK}, + {"reclassify", TC_ACT_RECLASSIFY}, + {"pipe", TC_ACT_PIPE}, + { NULL }, + }, *iter; + + for (iter = a2n; iter->a; iter++) { + if (matches(arg, iter->a) != 0) + continue; + *result = iter->n; + return 0; } - *result = res; + if (!allow_num || sscanf(arg, "%d%c", &n, &dummy) != 1) + return -1; + + *result = n; return 0; } diff --git a/tc/tc_util.h b/tc/tc_util.h index 744f18fdd..e7613ab1b 100644 --- a/tc/tc_util.h +++ b/tc/tc_util.h @@ -100,7 +100,7 @@ int tc_print_police(FILE *f, struct rtattr *tb); int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n); char *action_n2a(int action, char *buf, int len); -int action_a2n(char *arg, int *result); +int action_a2n(char *arg, int *result, bool allow_num); int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n); int print_police(struct action_util *a, FILE *f, struct rtattr *tb); From 69f5aff63c770bd95607b33d5ee8ee183dc13a64 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 23 Jul 2016 13:28:09 +0200 Subject: [PATCH 347/513] tc: use action_a2n() everywhere Signed-off-by: Phil Sutter --- tc/m_bpf.c | 22 ++-------------------- tc/m_connmark.c | 27 ++------------------------- tc/m_csum.c | 27 ++------------------------- tc/m_gact.c | 17 ++++------------- tc/m_ife.c | 27 ++------------------------- tc/m_mirred.c | 25 +++---------------------- tc/m_nat.c | 27 ++------------------------- tc/m_pedit.c | 22 ++-------------------- tc/m_police.c | 32 ++------------------------------ tc/m_simple.c | 27 ++------------------------- tc/m_skbedit.c | 22 ++-------------------- tc/m_vlan.c | 27 ++------------------------- 12 files changed, 27 insertions(+), 275 deletions(-) diff --git a/tc/m_bpf.c b/tc/m_bpf.c index 20da11d07..275634e78 100644 --- a/tc/m_bpf.c +++ b/tc/m_bpf.c @@ -104,26 +104,8 @@ static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv, NEXT_ARG_FWD(); } - if (argc) { - if (matches(*argv, "reclassify") == 0) { - parm.action = TC_ACT_RECLASSIFY; - NEXT_ARG_FWD(); - } else if (matches(*argv, "pipe") == 0) { - parm.action = TC_ACT_PIPE; - NEXT_ARG_FWD(); - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - parm.action = TC_ACT_SHOT; - NEXT_ARG_FWD(); - } else if (matches(*argv, "continue") == 0) { - parm.action = TC_ACT_UNSPEC; - NEXT_ARG_FWD(); - } else if (matches(*argv, "pass") == 0 || - matches(*argv, "ok") == 0) { - parm.action = TC_ACT_OK; - NEXT_ARG_FWD(); - } - } + if (argc && !action_a2n(*argv, &parm.action, false)) + NEXT_ARG_FWD(); if (argc) { if (matches(*argv, "index") == 0) { diff --git a/tc/m_connmark.c b/tc/m_connmark.c index 143d75de6..20f98e4fd 100644 --- a/tc/m_connmark.c +++ b/tc/m_connmark.c @@ -81,31 +81,8 @@ parse_connmark(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, } sel.action = TC_ACT_PIPE; - if (argc) { - if (matches(*argv, "reclassify") == 0) { - sel.action = TC_ACT_RECLASSIFY; - argc--; - argv++; - } else if (matches(*argv, "pipe") == 0) { - sel.action = TC_ACT_PIPE; - argc--; - argv++; - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - sel.action = TC_ACT_SHOT; - argc--; - argv++; - } else if (matches(*argv, "continue") == 0) { - sel.action = TC_ACT_UNSPEC; - argc--; - argv++; - } else if (matches(*argv, "pass") == 0 || - matches(*argv, "ok") == 0) { - sel.action = TC_ACT_OK; - argc--; - argv++; - } - } + if (argc && !action_a2n(*argv, &sel.action, false)) + NEXT_ARG_FWD(); if (argc) { if (matches(*argv, "index") == 0) { diff --git a/tc/m_csum.c b/tc/m_csum.c index 047986efd..db7eed3ad 100644 --- a/tc/m_csum.c +++ b/tc/m_csum.c @@ -120,31 +120,8 @@ parse_csum(struct action_util *a, int *argc_p, return -1; } - if (argc) { - if (matches(*argv, "reclassify") == 0) { - sel.action = TC_ACT_RECLASSIFY; - argc--; - argv++; - } else if (matches(*argv, "pipe") == 0) { - sel.action = TC_ACT_PIPE; - argc--; - argv++; - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - sel.action = TC_ACT_SHOT; - argc--; - argv++; - } else if (matches(*argv, "continue") == 0) { - sel.action = TC_ACT_UNSPEC; - argc--; - argv++; - } else if (matches(*argv, "pass") == 0 || - matches(*argv, "ok") == 0) { - sel.action = TC_ACT_OK; - argc--; - argv++; - } - } + if (argc && !action_a2n(*argv, &sel.action, false)) + NEXT_ARG_FWD(); if (argc) { if (matches(*argv, "index") == 0) { diff --git a/tc/m_gact.c b/tc/m_gact.c index ea2c9ec82..9f31fdd32 100644 --- a/tc/m_gact.c +++ b/tc/m_gact.c @@ -71,22 +71,13 @@ usage(void) static int get_act(char ***argv_p) { - char **argv = *argv_p; + int n; - if (matches(*argv, "reclassify") == 0) { - return TC_ACT_RECLASSIFY; - } else if (matches(*argv, "drop") == 0 || matches(*argv, "shot") == 0) { - return TC_ACT_SHOT; - } else if (matches(*argv, "continue") == 0) { - return TC_ACT_UNSPEC; - } else if (matches(*argv, "pipe") == 0) { - return TC_ACT_PIPE; - } else if (matches(*argv, "pass") == 0 || matches(*argv, "ok") == 0) { - return TC_ACT_OK; - } else { - fprintf(stderr, "bad action type %s\n", *argv); + if (!action_a2n(**argv_p, &n, false)) { + fprintf(stderr, "bad action type %s\n", **argv_p); return -10; } + return n; } static int diff --git a/tc/m_ife.c b/tc/m_ife.c index eaab1cc85..5eee544b7 100644 --- a/tc/m_ife.c +++ b/tc/m_ife.c @@ -146,31 +146,8 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, argv++; } - if (argc) { - if (matches(*argv, "reclassify") == 0) { - p.action = TC_ACT_RECLASSIFY; - argc--; - argv++; - } else if (matches(*argv, "pipe") == 0) { - p.action = TC_ACT_PIPE; - argc--; - argv++; - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - p.action = TC_ACT_SHOT; - argc--; - argv++; - } else if (matches(*argv, "continue") == 0) { - p.action = TC_ACT_UNSPEC; - argc--; - argv++; - } else if (matches(*argv, "pass") == 0 || - matches(*argv, "ok") == 0) { - p.action = TC_ACT_OK; - argc--; - argv++; - } - } + if (argc && !action_a2n(*argv, &p.action, false)) + NEXT_ARG_FWD(); if (argc) { if (matches(*argv, "index") == 0) { diff --git a/tc/m_mirred.c b/tc/m_mirred.c index 0066905ac..61a84f575 100644 --- a/tc/m_mirred.c +++ b/tc/m_mirred.c @@ -154,28 +154,9 @@ parse_egress(struct action_util *a, int *argc_p, char ***argv_p, } - if (argc && p.eaction == TCA_EGRESS_MIRROR) { - - if (matches(*argv, "reclassify") == 0) { - p.action = TC_POLICE_RECLASSIFY; - NEXT_ARG(); - } else if (matches(*argv, "pipe") == 0) { - p.action = TC_POLICE_PIPE; - NEXT_ARG(); - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - p.action = TC_POLICE_SHOT; - NEXT_ARG(); - } else if (matches(*argv, "continue") == 0) { - p.action = TC_POLICE_UNSPEC; - NEXT_ARG(); - } else if (matches(*argv, "pass") == 0 || - matches(*argv, "ok") == 0) { - p.action = TC_POLICE_OK; - NEXT_ARG(); - } - - } + if (argc && p.eaction == TCA_EGRESS_MIRROR + && !action_a2n(*argv, &p.action, false)) + NEXT_ARG(); if (argc) { if (iok && matches(*argv, "index") == 0) { diff --git a/tc/m_nat.c b/tc/m_nat.c index 839fb8a05..52bafa79e 100644 --- a/tc/m_nat.c +++ b/tc/m_nat.c @@ -115,31 +115,8 @@ parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct return -1; } - if (argc) { - if (matches(*argv, "reclassify") == 0) { - sel.action = TC_ACT_RECLASSIFY; - argc--; - argv++; - } else if (matches(*argv, "pipe") == 0) { - sel.action = TC_ACT_PIPE; - argc--; - argv++; - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - sel.action = TC_ACT_SHOT; - argc--; - argv++; - } else if (matches(*argv, "continue") == 0) { - sel.action = TC_ACT_UNSPEC; - argc--; - argv++; - } else if (matches(*argv, "pass") == 0 || - matches(*argv, "ok") == 0) { - sel.action = TC_ACT_OK; - argc--; - argv++; - } - } + if (argc && !action_a2n(*argv, &sel.action, false)) + NEXT_ARG_FWD(); if (argc) { if (matches(*argv, "index") == 0) { diff --git a/tc/m_pedit.c b/tc/m_pedit.c index 35879b7fb..c28f2610a 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -481,26 +481,8 @@ int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, return -1; } - if (argc) { - if (matches(*argv, "reclassify") == 0) { - sel.sel.action = TC_ACT_RECLASSIFY; - NEXT_ARG(); - } else if (matches(*argv, "pipe") == 0) { - sel.sel.action = TC_ACT_PIPE; - NEXT_ARG(); - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - sel.sel.action = TC_ACT_SHOT; - NEXT_ARG(); - } else if (matches(*argv, "continue") == 0) { - sel.sel.action = TC_ACT_UNSPEC; - NEXT_ARG(); - } else if (matches(*argv, "pass") == 0 || - matches(*argv, "ok") == 0) { - sel.sel.action = TC_ACT_OK; - NEXT_ARG(); - } - } + if (argc && !action_a2n(*argv, &sel.sel.action, false)) + NEXT_ARG(); if (argc) { if (matches(*argv, "index") == 0) { diff --git a/tc/m_police.c b/tc/m_police.c index 9ae25f288..3ba580e4f 100644 --- a/tc/m_police.c +++ b/tc/m_police.c @@ -71,34 +71,6 @@ static const char *police_action_n2a(int action, char *buf, int len) } } -static int police_action_a2n(const char *arg, int *result) -{ - int res; - - if (matches(arg, "continue") == 0) - res = -1; - else if (matches(arg, "drop") == 0) - res = TC_POLICE_SHOT; - else if (matches(arg, "shot") == 0) - res = TC_POLICE_SHOT; - else if (matches(arg, "pass") == 0) - res = TC_POLICE_OK; - else if (strcmp(arg, "ok") == 0) - res = TC_POLICE_OK; - else if (matches(arg, "reclassify") == 0) - res = TC_POLICE_RECLASSIFY; - else if (matches(arg, "pipe") == 0) - res = TC_POLICE_PIPE; - else { - char dummy; - - if (sscanf(arg, "%d%c", &res, &dummy) != 1) - return -1; - } - *result = res; - return 0; -} - static int get_police_result(int *action, int *result, char *arg) { char *p = strchr(arg, '/'); @@ -106,7 +78,7 @@ static int get_police_result(int *action, int *result, char *arg) if (p) *p = 0; - if (police_action_a2n(arg, action)) { + if (action_a2n(arg, action, true)) { if (p) *p = '/'; return -1; @@ -114,7 +86,7 @@ static int get_police_result(int *action, int *result, char *arg) if (p) { *p = '/'; - if (police_action_a2n(p+1, result)) + if (action_a2n(p+1, result, true)) return -1; } return 0; diff --git a/tc/m_simple.c b/tc/m_simple.c index 27b3e5e40..732eaf1eb 100644 --- a/tc/m_simple.c +++ b/tc/m_simple.c @@ -120,31 +120,8 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, } } - if (argc) { - if (matches(*argv, "reclassify") == 0) { - sel.action = TC_ACT_RECLASSIFY; - argc--; - argv++; - } else if (matches(*argv, "pipe") == 0) { - sel.action = TC_ACT_PIPE; - argc--; - argv++; - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - sel.action = TC_ACT_SHOT; - argc--; - argv++; - } else if (matches(*argv, "continue") == 0) { - sel.action = TC_ACT_UNSPEC; - argc--; - argv++; - } else if (matches(*argv, "pass") == 0 || - matches(*argv, "ok") == 0) { - sel.action = TC_ACT_OK; - argc--; - argv++; - } - } + if (argc && !action_a2n(*argv, &sel.action, false)) + NEXT_ARG_FWD(); if (argc) { if (matches(*argv, "index") == 0) { diff --git a/tc/m_skbedit.c b/tc/m_skbedit.c index 9ba288c07..eca6a8ac7 100644 --- a/tc/m_skbedit.c +++ b/tc/m_skbedit.c @@ -100,26 +100,8 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, } sel.action = TC_ACT_PIPE; - if (argc) { - if (matches(*argv, "reclassify") == 0) { - sel.action = TC_ACT_RECLASSIFY; - NEXT_ARG(); - } else if (matches(*argv, "pipe") == 0) { - sel.action = TC_ACT_PIPE; - NEXT_ARG(); - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - sel.action = TC_ACT_SHOT; - NEXT_ARG(); - } else if (matches(*argv, "continue") == 0) { - sel.action = TC_ACT_UNSPEC; - NEXT_ARG(); - } else if (matches(*argv, "pass") == 0 || - matches(*argv, "ok") == 0) { - sel.action = TC_ACT_OK; - NEXT_ARG(); - } - } + if (argc && !action_a2n(*argv, &sel.action, false)) + NEXT_ARG(); if (argc) { if (matches(*argv, "index") == 0) { diff --git a/tc/m_vlan.c b/tc/m_vlan.c index c2684461b..82311dd69 100644 --- a/tc/m_vlan.c +++ b/tc/m_vlan.c @@ -101,31 +101,8 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, } parm.action = TC_ACT_PIPE; - if (argc) { - if (matches(*argv, "reclassify") == 0) { - parm.action = TC_ACT_RECLASSIFY; - argc--; - argv++; - } else if (matches(*argv, "pipe") == 0) { - parm.action = TC_ACT_PIPE; - argc--; - argv++; - } else if (matches(*argv, "drop") == 0 || - matches(*argv, "shot") == 0) { - parm.action = TC_ACT_SHOT; - argc--; - argv++; - } else if (matches(*argv, "continue") == 0) { - parm.action = TC_ACT_UNSPEC; - argc--; - argv++; - } else if (matches(*argv, "pass") == 0 || - matches(*argv, "ok") == 0) { - parm.action = TC_ACT_OK; - argc--; - argv++; - } - } + if (argc && !action_a2n(*argv, &parm.action, false)) + NEXT_ARG_FWD(); if (argc) { if (matches(*argv, "index") == 0) { From 709320061154c2d381aa91fc6a135eea96b32672 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 23 Jul 2016 13:28:10 +0200 Subject: [PATCH 348/513] tc: util: No need for action_n2a() to be reentrant This allows to remove some buffers here and there. While at it, make it return a const value. Signed-off-by: Phil Sutter --- tc/m_bpf.c | 5 +---- tc/m_csum.c | 4 +--- tc/m_gact.c | 7 +++---- tc/m_ife.c | 3 +-- tc/m_mirred.c | 5 ++--- tc/m_nat.c | 3 +-- tc/m_pedit.c | 4 +--- tc/m_police.c | 28 ++-------------------------- tc/m_vlan.c | 2 +- tc/tc_util.c | 12 ++++++------ tc/tc_util.h | 2 +- 11 files changed, 20 insertions(+), 55 deletions(-) diff --git a/tc/m_bpf.c b/tc/m_bpf.c index 275634e78..9bf2a85ea 100644 --- a/tc/m_bpf.c +++ b/tc/m_bpf.c @@ -136,8 +136,6 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg) struct rtattr *tb[TCA_ACT_BPF_MAX + 1]; struct tc_act_bpf *parm; - SPRINT_BUF(action_buf); - if (arg == NULL) return -1; @@ -162,8 +160,7 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg) fprintf(f, " "); } - fprintf(f, "default-action %s\n", action_n2a(parm->action, action_buf, - sizeof(action_buf))); + fprintf(f, "default-action %s\n", action_n2a(parm->action)); fprintf(f, "\tindex %d ref %d bind %d", parm->index, parm->refcnt, parm->bindcnt); diff --git a/tc/m_csum.c b/tc/m_csum.c index db7eed3ad..a6e4c1eb4 100644 --- a/tc/m_csum.c +++ b/tc/m_csum.c @@ -161,8 +161,6 @@ print_csum(struct action_util *au, FILE *f, struct rtattr *arg) char *uflag_5 = ""; char *uflag_6 = ""; - SPRINT_BUF(action_buf); - int uflag_count = 0; if (arg == NULL) @@ -200,7 +198,7 @@ print_csum(struct action_util *au, FILE *f, struct rtattr *arg) fprintf(f, "csum (%s%s%s%s%s%s) action %s\n", uflag_1, uflag_2, uflag_3, uflag_4, uflag_5, uflag_6, - action_n2a(sel->action, action_buf, sizeof(action_buf))); + action_n2a(sel->action)); fprintf(f, "\tindex %d ref %d bind %d", sel->index, sel->refcnt, sel->bindcnt); if (show_stats) { diff --git a/tc/m_gact.c b/tc/m_gact.c index 9f31fdd32..c0a938c71 100644 --- a/tc/m_gact.c +++ b/tc/m_gact.c @@ -194,9 +194,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) { - SPRINT_BUF(b1); #ifdef CONFIG_GACT_PROB - SPRINT_BUF(b2); struct tc_gact_p *pp = NULL; struct tc_gact_p pp_dummy; #endif @@ -214,7 +212,7 @@ print_gact(struct action_util *au, FILE * f, struct rtattr *arg) } p = RTA_DATA(tb[TCA_GACT_PARMS]); - fprintf(f, "gact action %s", action_n2a(p->action, b1, sizeof(b1))); + fprintf(f, "gact action %s", action_n2a(p->action)); #ifdef CONFIG_GACT_PROB if (tb[TCA_GACT_PROB] != NULL) { pp = RTA_DATA(tb[TCA_GACT_PROB]); @@ -223,7 +221,8 @@ 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 %s val %d", prob_n2a(pp->ptype), action_n2a(pp->paction, b2, sizeof (b2)), pp->pval); + fprintf(f, "\n\t random type %s %s val %d", + prob_n2a(pp->ptype), action_n2a(pp->paction), pp->pval); #endif fprintf(f, "\n\t index %d ref %d bind %d", p->index, p->refcnt, p->bindcnt); if (show_stats) { diff --git a/tc/m_ife.c b/tc/m_ife.c index 5eee544b7..0219760aa 100644 --- a/tc/m_ife.c +++ b/tc/m_ife.c @@ -215,7 +215,6 @@ static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg) __u32 mhash = 0; __u32 mprio = 0; int has_optional = 0; - SPRINT_BUF(b1); SPRINT_BUF(b2); if (arg == NULL) @@ -231,7 +230,7 @@ static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg) fprintf(f, "ife %s action %s ", (p->flags & IFE_ENCODE) ? "encode" : "decode", - action_n2a(p->action, b1, sizeof(b1))); + action_n2a(p->action)); if (tb[TCA_IFE_TYPE]) { ife_type = rta_getattr_u16(tb[TCA_IFE_TYPE]); diff --git a/tc/m_mirred.c b/tc/m_mirred.c index 61a84f575..11f4c9b46 100644 --- a/tc/m_mirred.c +++ b/tc/m_mirred.c @@ -235,8 +235,6 @@ print_mirred(struct action_util *au, FILE * f, struct rtattr *arg) struct rtattr *tb[TCA_MIRRED_MAX + 1]; const char *dev; - SPRINT_BUF(b1); - if (arg == NULL) return -1; @@ -258,7 +256,8 @@ print_mirred(struct action_util *au, FILE * f, struct rtattr *arg) return -1; } - fprintf(f, "mirred (%s to device %s) %s", mirred_n2a(p->eaction), dev, action_n2a(p->action, b1, sizeof (b1))); + fprintf(f, "mirred (%s to device %s) %s", + mirred_n2a(p->eaction), dev, action_n2a(p->action)); fprintf(f, "\n "); fprintf(f, "\tindex %d ref %d bind %d", p->index, p->refcnt, p->bindcnt); diff --git a/tc/m_nat.c b/tc/m_nat.c index 52bafa79e..525f185e2 100644 --- a/tc/m_nat.c +++ b/tc/m_nat.c @@ -148,7 +148,6 @@ print_nat(struct action_util *au, FILE * f, struct rtattr *arg) char buf1[256]; char buf2[256]; - SPRINT_BUF(buf3); int len; if (arg == NULL) @@ -170,7 +169,7 @@ print_nat(struct action_util *au, FILE * f, struct rtattr *arg) format_host_r(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)), len, format_host_r(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)), - action_n2a(sel->action, buf3, sizeof(buf3))); + action_n2a(sel->action)); if (show_stats) { if (tb[TCA_NAT_TM]) { diff --git a/tc/m_pedit.c b/tc/m_pedit.c index c28f2610a..891c2ec7b 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -514,8 +514,6 @@ int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg) struct tc_pedit_sel *sel; struct rtattr *tb[TCA_PEDIT_MAX + 1]; - SPRINT_BUF(b1); - if (arg == NULL) return -1; @@ -528,7 +526,7 @@ int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg) sel = RTA_DATA(tb[TCA_PEDIT_PARMS]); fprintf(f, " pedit action %s keys %d\n ", - action_n2a(sel->action, b1, sizeof(b1)), sel->nkeys); + action_n2a(sel->action), sel->nkeys); fprintf(f, "\t index %d ref %d bind %d", sel->index, sel->refcnt, sel->bindcnt); diff --git a/tc/m_police.c b/tc/m_police.c index 3ba580e4f..f0b179fcc 100644 --- a/tc/m_police.c +++ b/tc/m_police.c @@ -49,28 +49,6 @@ static void explain1(char *arg) fprintf(stderr, "Illegal \"%s\"\n", arg); } -static const char *police_action_n2a(int action, char *buf, int len) -{ - switch (action) { - case -1: - return "continue"; - break; - case TC_POLICE_OK: - return "pass"; - break; - case TC_POLICE_SHOT: - return "drop"; - break; - case TC_POLICE_RECLASSIFY: - return "reclassify"; - case TC_POLICE_PIPE: - return "pipe"; - default: - snprintf(buf, len, "%d", action); - return buf; - } -} - static int get_police_result(int *action, int *result, char *arg) { char *p = strchr(arg, '/'); @@ -339,14 +317,12 @@ int print_police(struct action_util *a, FILE *f, struct rtattr *arg) fprintf(f, "avrate %s ", sprint_rate(rta_getattr_u32(tb[TCA_POLICE_AVRATE]), b1)); - fprintf(f, "action %s", - police_action_n2a(p->action, b1, sizeof(b1))); + fprintf(f, "action %s", action_n2a(p->action)); if (tb[TCA_POLICE_RESULT]) { __u32 action = rta_getattr_u32(tb[TCA_POLICE_RESULT]); - fprintf(f, "/%s", - police_action_n2a(action, b1, sizeof(b1))); + fprintf(f, "/%s", action_n2a(action)); } else fprintf(f, " "); diff --git a/tc/m_vlan.c b/tc/m_vlan.c index 82311dd69..ac63d9ed0 100644 --- a/tc/m_vlan.c +++ b/tc/m_vlan.c @@ -182,7 +182,7 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) } break; } - fprintf(f, " %s", action_n2a(parm->action, b1, sizeof(b1))); + fprintf(f, " %s", action_n2a(parm->action)); fprintf(f, "\n\t index %d ref %d bind %d", parm->index, parm->refcnt, parm->bindcnt); diff --git a/tc/tc_util.c b/tc/tc_util.c index cd7b40b0a..15e49b7ba 100644 --- a/tc/tc_util.c +++ b/tc/tc_util.c @@ -411,18 +411,17 @@ char *sprint_qdisc_handle(__u32 h, char *buf) return buf; } -char *action_n2a(int action, char *buf, int len) +const char *action_n2a(int action) { + static char buf[64]; + switch (action) { - case -1: + case TC_ACT_UNSPEC: return "continue"; - break; case TC_ACT_OK: return "pass"; - break; case TC_ACT_SHOT: return "drop"; - break; case TC_ACT_RECLASSIFY: return "reclassify"; case TC_ACT_PIPE: @@ -430,7 +429,8 @@ char *action_n2a(int action, char *buf, int len) case TC_ACT_STOLEN: return "stolen"; default: - snprintf(buf, len, "%d", action); + snprintf(buf, 64, "%d", action); + buf[63] = '\0'; return buf; } } diff --git a/tc/tc_util.h b/tc/tc_util.h index e7613ab1b..f198a4ad5 100644 --- a/tc/tc_util.h +++ b/tc/tc_util.h @@ -99,7 +99,7 @@ char *sprint_tc_classid(__u32 h, char *buf); int tc_print_police(FILE *f, struct rtattr *tb); int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n); -char *action_n2a(int action, char *buf, int len); +const char *action_n2a(int action); int action_a2n(char *arg, int *result, bool allow_num); int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n); From bdd6104f52ad10c67d37bf4c6c36efa137d5d0ec Mon Sep 17 00:00:00 2001 From: Michal Soltys Date: Sun, 24 Jul 2016 02:00:29 +0200 Subject: [PATCH 349/513] man/man8/tc-flow.8: minor corrections - baseclass: major handle must match that of class's, Y defaults to 1 - flow map example: maps to 1-256, not 1-257 Signed-off-by: Michal Soltys --- man/man8/tc-flow.8 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/man/man8/tc-flow.8 b/man/man8/tc-flow.8 index f1b7e2a4f..54f6bf7db 100644 --- a/man/man8/tc-flow.8 +++ b/man/man8/tc-flow.8 @@ -73,8 +73,10 @@ An offset for the resulting class ID. .I ID may be .BR root ", " none -or a hexadecimal class ID in the form [\fIX\fB:\fR]\fIY\fR. If \fIX\fR is -omitted, it is assumed to be zero. +or a hexadecimal class ID in the form [\fIX\fB:\fR]\fIY\fR. \fIX\fR must +match qdisc's/class's major handle (if omitted, the correct value is chosen +automatically). If the whole \fBbaseclass\fR is omitted, \fIY\fR defaults +to 1. .TP .BI divisor " NUM" Number of buckets to use for sorting into. Keys are calculated modulo @@ -239,7 +241,7 @@ tc filter add ... flow hash \\ divisor 1024 .EE .TP -Map destination IPs of 192.168.0.0/24 to classids 1-257: +Map destination IPs of 192.168.0.0/24 to classids 1-256: .EX tc filter add ... flow map \\ From c0ab80a4907a102e48b3a8f4150e77671e5af81d Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Tue, 26 Jul 2016 11:03:18 +0200 Subject: [PATCH 350/513] man: macsec: fix macsec related typos - ip-macsec.8: fix wrong 'device' keyword in 'ip link add device eth0'; add missing description of 'validate' keyword; remove spurious bracket near 'encrypt' keyword; add missing reference to configuration of 'port' and 'sci' - ip-link.8 fix wrong 'es' and 'encoding' keywords in MACsec section Signed-off-by: Davide Caratti --- man/man8/ip-link.8.in | 8 ++++---- man/man8/ip-macsec.8 | 11 ++++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 2cd613372..c91ef95f9 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -925,14 +925,14 @@ the following additional arguments are supported: .BR encrypt " {" .BR on " | " off " } ] [ " .BR send_sci " { " on " | " off " } ] [" -.BR es " { " on " | " off " } ] [" +.BR end_station " { " on " | " off " } ] [" .BR scb " { " on " | " off " } ] [" .BR protect " { " on " | " off " } ] [" .BR replay " { " on " | " off " }" .BR window " { " .IR 0..2^32-1 " } ] [" .BR validate " { " strict " | " check " | " disabled " } ] [" -.BR encoding " { " +.BR encodingsa " { " .IR 0..3 " } ]" .in +8 @@ -957,7 +957,7 @@ the following additional arguments are supported: - specifies whether the SCI is included in every packet, or only when it is necessary. .sp -.BR "es on " or " es off" +.BR "end_station on " or " end_station off" - sets the End Station bit. .sp @@ -985,7 +985,7 @@ the following additional arguments are supported: - sets the validation mode on the device. .sp -.BI encoding " AN " +.BI encodingsa " AN " - sets the active secure association for transmission. .in -8 diff --git a/man/man8/ip-macsec.8 b/man/man8/ip-macsec.8 index e8455d77e..f928c43f3 100644 --- a/man/man8/ip-macsec.8 +++ b/man/man8/ip-macsec.8 @@ -3,10 +3,14 @@ ip-macsec \- MACsec device configuration .SH "SYNOPSIS" .BI "ip link add link " DEVICE " name " NAME " type macsec " -[ [ +[ +.BI port " PORT" +| +.BI sci " SCI" +] [ [ .BR cipher " { " default " | " gcm-aes-128 " } ] " .BI icvlen " ICVLEN" -] [ [ +] [ .BR encrypt " { " on " | " off " } ] [" .BR send_sci " { " on " | " off " } ] [" .BR end_station " { " on " | " off " } ] [" @@ -15,6 +19,7 @@ ip-macsec \- MACsec device configuration .BR replay " { " on " | " off " } ] [" .BI window " WINDOW" ] [ +.BR validate " { " strict " | " check " | " disabled " } ] [" .BI encodingsa " SA" ] @@ -74,7 +79,7 @@ type. .PP .SS Create a MACsec device on link eth0 .nf -# ip link add device eth0 macsec0 type macsec port 11 encrypt on +# ip link add link eth0 macsec0 type macsec port 11 encrypt on .PP .SS Configure a secure association on that device .nf From fd4df5b21180f9b32259d859e6fcbbb08d0e03c4 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Tue, 26 Jul 2016 11:03:19 +0200 Subject: [PATCH 351/513] ip {link,address}: add 'macsec' item to TYPE list fix output of "ip address help" and "ip link help". Update TYPE list in man pages ip-address.8 and ip-link.8 as well. Signed-off-by: Davide Caratti --- ip/ipaddress.c | 2 +- ip/iplink.c | 2 +- man/man8/ip-address.8.in | 3 ++- man/man8/ip-link.8.in | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 60862c570..ab4b1b148 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -97,7 +97,7 @@ static void usage(void) fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"); fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | lowpan |\n"); fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon | can |\n"); - fprintf(stderr, " bond_slave | ipvlan | geneve | bridge_slave | vrf | hsr}\n"); + fprintf(stderr, " bond_slave | ipvlan | geneve | bridge_slave | vrf | hsr | macsec }\n"); exit(-1); } diff --git a/ip/iplink.c b/ip/iplink.c index ef17fd9d2..f9a7e0909 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -96,7 +96,7 @@ void iplink_usage(void) fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"); fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n"); fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n"); - fprintf(stderr, " bond_slave | ipvlan | geneve | bridge_slave | vrf }\n"); + fprintf(stderr, " bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }\n"); } exit(-1); } diff --git a/man/man8/ip-address.8.in b/man/man8/ip-address.8.in index 7d6eb9b2b..43385813a 100644 --- a/man/man8/ip-address.8.in +++ b/man/man8/ip-address.8.in @@ -127,7 +127,8 @@ ip-address \- protocol address management .BR nlmon " |" .BR ipvlan " |" .BR lowpan " |" -.BR geneve " ]" +.BR geneve " |" +.BR macsec " ]" .SH "DESCRIPTION" The diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index c91ef95f9..ad49c9d28 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -184,7 +184,8 @@ ip-link \- network device configuration .BR ipvlan " |" .BR lowpan " |" .BR geneve " |" -.BR vrf " ]" +.BR vrf " |" +.BR macsec " ]" .ti -8 .IR ETYPE " := [ " TYPE " |" From 89bb6e673a6ae9dd9b6845ed95358dd6653c167e Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Tue, 26 Jul 2016 11:03:20 +0200 Subject: [PATCH 352/513] macsec: cipher and icvlen can be set separately since kernel driver has valid default values for 'cipher' and 'icvlen', there is no need for requiring users to specify both of them when a new link is added. Also, prompt an error message and exit with appropriate exit status in case of unsupported cipher suite. Signed-off-by: Davide Caratti --- ip/ipmacsec.c | 52 ++++++++++++++----------------------------- man/man8/ip-link.8.in | 6 +++++ man/man8/ip-macsec.8 | 4 ++-- 3 files changed, 25 insertions(+), 37 deletions(-) diff --git a/ip/ipmacsec.c b/ip/ipmacsec.c index 34ba341a8..329be00fb 100644 --- a/ip/ipmacsec.c +++ b/ip/ipmacsec.c @@ -1071,34 +1071,6 @@ static void macsec_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) } } - -static int do_cipher_suite(struct cipher_args *cipher, int *argcp, - char ***argvp) -{ - char **argv = *argvp; - int argc = *argcp; - - if (argc == 0) - return -1; - - if (strcmp(*argv, "default") == 0 || - strcmp(*argv, "gcm-aes-128") == 0 || - strcmp(*argv, "GCM-AES-128") == 0) - cipher->id = MACSEC_DEFAULT_CIPHER_ID; - NEXT_ARG(); - - if (strcmp(*argv, "icvlen") == 0) { - NEXT_ARG(); - if (cipher->icv_len != 0) - duparg2("icvlen", "icvlen"); - get_icvlen(&cipher->icv_len, *argv); - } - *argcp = argc; - *argvp = argv; - - return 0; -} - static bool check_txsc_flags(bool es, bool scb, bool sci) { if (sci && (es || scb)) @@ -1112,7 +1084,8 @@ static void usage(FILE *f) { fprintf(f, "Usage: ... macsec [ port PORT | sci SCI ]\n" - " [ cipher CIPHER_SUITE ]\n" + " [ cipher { default | gcm-aes-128 } ]\n" + " [ icvlen { 8..16 } ]\n" " [ encrypt { on | off } ]\n" " [ send_sci { on | off } ]\n" " [ end_station { on | off } ]\n" @@ -1122,7 +1095,6 @@ static void usage(FILE *f) " [ validate { strict | check | disabled } ]\n" " [ encodingsa { 0..3 } ]\n" ); - fprintf(f, "CIPHER_SUITE := [ default = gcm-aes-128 ] icvlen { 8..32 }\n"); } static int macsec_parse_opt(struct link_util *lu, int argc, char **argv, @@ -1154,11 +1126,21 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv, while (argc > 0) { if (strcmp(*argv, "cipher") == 0) { + NEXT_ARG(); if (cipher.id) - duparg2("cipher", "cipher"); + duparg("cipher", *argv); + if (strcmp(*argv, "default") == 0 || + strcmp(*argv, "gcm-aes-128") == 0 || + strcmp(*argv, "GCM-AES-128") == 0) + cipher.id = MACSEC_DEFAULT_CIPHER_ID; + else + invarg("expected: default or gcm-aes-128", + *argv); + } else if (strcmp(*argv, "icvlen") == 0) { NEXT_ARG(); - if (do_cipher_suite(&cipher, &argc, &argv)) - return -1; + if (cipher.icv_len) + duparg("icvlen", *argv); + get_icvlen(&cipher.icv_len, *argv); } else if (strcmp(*argv, "encrypt") == 0) { NEXT_ARG(); int i; @@ -1264,12 +1246,12 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv, return -1; } - if (cipher.id) { + if (cipher.id) addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_CIPHER_SUITE, &cipher.id, sizeof(cipher.id)); + if (cipher.icv_len) addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_ICV_LEN, &cipher.icv_len, sizeof(cipher.icv_len)); - } if (replay_protect != -1) { addattr32(hdr, MACSEC_BUFLEN, IFLA_MACSEC_WINDOW, window); diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index ad49c9d28..f4782ee5b 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -923,6 +923,8 @@ the following additional arguments are supported: ] [ .BI cipher " CIPHER_SUITE" ] [ +.BR icvlen " { " +.IR 8..16 " } ] [" .BR encrypt " {" .BR on " | " off " } ] [ " .BR send_sci " { " on " | " off " } ] [" @@ -949,6 +951,10 @@ the following additional arguments are supported: .BI cipher " CIPHER_SUITE " - defines the cipher suite to use. +.sp +.BI icvlen " LENGTH " +- sets the length of the Integrity Check Value (ICV). + .sp .BR "encrypt on " or " encrypt off" - switches between authenticated encryption, or authenticity mode only. diff --git a/man/man8/ip-macsec.8 b/man/man8/ip-macsec.8 index f928c43f3..105aeecd8 100644 --- a/man/man8/ip-macsec.8 +++ b/man/man8/ip-macsec.8 @@ -7,8 +7,8 @@ ip-macsec \- MACsec device configuration .BI port " PORT" | .BI sci " SCI" -] [ [ -.BR cipher " { " default " | " gcm-aes-128 " } ] " +] [ +.BR cipher " { " default " | " gcm-aes-128 " } ] [" .BI icvlen " ICVLEN" ] [ .BR encrypt " { " on " | " off " } ] [" From 7a9466dbcba1918a1c93de8f93b9ff3d62418fcf Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 22 Jul 2016 18:34:29 +0200 Subject: [PATCH 353/513] devlink: write usage help messages to stderr In order to not confuse reader, write help messages into stderr. Signed-off-by: Jiri Pirko --- devlink/devlink.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index ffefa86d2..f73ba9523 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -909,7 +909,7 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) static void cmd_dev_help(void) { - pr_out("Usage: devlink dev show [ DEV ]\n"); + pr_err("Usage: devlink dev show [ DEV ]\n"); } static void __pr_out_handle(const char *bus_name, const char *dev_name) @@ -1024,10 +1024,10 @@ static int cmd_dev(struct dl *dl) static void cmd_port_help(void) { - pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n"); - pr_out(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n"); - pr_out(" devlink port split DEV/PORT_INDEX count COUNT\n"); - pr_out(" devlink port unsplit DEV/PORT_INDEX\n"); + pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n"); + pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n"); + pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n"); + pr_err(" devlink port unsplit DEV/PORT_INDEX\n"); } static const char *port_type_name(uint32_t type) @@ -1174,22 +1174,22 @@ static int cmd_port(struct dl *dl) static void cmd_sb_help(void) { - pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); - pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); - pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); - pr_out(" size POOL_SIZE thtype { static | dynamic }\n"); - pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); - pr_out(" pool POOL_INDEX ]\n"); - pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); - pr_out(" pool POOL_INDEX th THRESHOLD\n"); - pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); - pr_out(" type { ingress | egress } ]\n"); - pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); - pr_out(" type { ingress | egress } pool POOL_INDEX\n"); - pr_out(" th THRESHOLD\n"); - pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); - pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); - pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); + pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); + pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); + pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); + pr_err(" size POOL_SIZE thtype { static | dynamic }\n"); + pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); + pr_err(" pool POOL_INDEX ]\n"); + pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); + pr_err(" pool POOL_INDEX th THRESHOLD\n"); + pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); + pr_err(" type { ingress | egress } ]\n"); + pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); + pr_err(" type { ingress | egress } pool POOL_INDEX\n"); + pr_err(" th THRESHOLD\n"); + pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); + pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); + pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); } static void pr_out_sb(struct nlattr **tb) @@ -1991,7 +1991,7 @@ static int cmd_mon_show(struct dl *dl) static void cmd_mon_help(void) { - pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n" + pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n" "where OBJECT-LIST := { dev | port }\n"); } @@ -2010,7 +2010,7 @@ static int cmd_mon(struct dl *dl) static void help(void) { - pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" + pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" "where OBJECT := { dev | port | sb | monitor }\n" " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); } From e3d0f0c0e3d8ac6432884e19aefd169e5c4ae179 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 22 Jul 2016 18:34:30 +0200 Subject: [PATCH 354/513] devlink: add option to generate JSON output For parsing by another app it is convenient to produce output in JSON format. Signed-off-by: Jiri Pirko --- devlink/devlink.c | 455 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 362 insertions(+), 93 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index f73ba9523..84fa51e89 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -24,6 +24,7 @@ #include "SNAPSHOT.h" #include "list.h" #include "mnlg.h" +#include "json_writer.h" #define pr_err(args...) fprintf(stderr, ##args) #define pr_out(args...) fprintf(stdout, ##args) @@ -151,6 +152,15 @@ struct dl { char **argv; bool no_nice_names; struct dl_opts opts; + json_writer_t *jw; + bool json_output; + bool pretty_output; + struct { + bool present; + char *bus_name; + char *dev_name; + uint32_t port_index; + } arr_last; }; static int dl_argc(struct dl *dl) @@ -912,52 +922,161 @@ static void cmd_dev_help(void) pr_err("Usage: devlink dev show [ DEV ]\n"); } -static void __pr_out_handle(const char *bus_name, const char *dev_name) +static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name, + const char *dev_name) { - pr_out("%s/%s", bus_name, dev_name); + if (!dl->arr_last.present) + return false; + return strcmp(dl->arr_last.bus_name, bus_name) == 0 && + strcmp(dl->arr_last.dev_name, dev_name) == 0; } -static void pr_out_handle(struct nlattr **tb) +static void arr_last_handle_set(struct dl *dl, const char *bus_name, + const char *dev_name) { - __pr_out_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), - mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME])); + dl->arr_last.present = true; + free(dl->arr_last.dev_name); + free(dl->arr_last.bus_name); + dl->arr_last.bus_name = strdup(bus_name); + dl->arr_last.dev_name = strdup(dev_name); } -static void __pr_out_port_handle(const char *bus_name, const char *dev_name, - uint32_t port_index) +static bool should_arr_last_handle_start(struct dl *dl, const char *bus_name, + const char *dev_name) { - __pr_out_handle(bus_name, dev_name); - pr_out("/%d", port_index); + return !cmp_arr_last_handle(dl, bus_name, dev_name); } -static void pr_out_port_handle(struct nlattr **tb) +static bool should_arr_last_handle_end(struct dl *dl, const char *bus_name, + const char *dev_name) { - __pr_out_port_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), - mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]), - mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); + return dl->arr_last.present && + !cmp_arr_last_handle(dl, bus_name, dev_name); } -static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name, - const char *dev_name, uint32_t port_index) +static void __pr_out_handle_start(struct dl *dl, struct nlattr **tb, + bool content, bool array) { - char *ifname; - int err; + const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); + const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); + char buf[32]; - if (dl->no_nice_names) - goto no_nice_names; + sprintf(buf, "%s/%s", bus_name, dev_name); - err = ifname_map_rev_lookup(dl, bus_name, dev_name, - port_index, &ifname); - if (err) - goto no_nice_names; - pr_out("%s", ifname); - return; + if (dl->json_output) { + if (array) { + if (should_arr_last_handle_end(dl, bus_name, dev_name)) + jsonw_end_array(dl->jw); + if (should_arr_last_handle_start(dl, bus_name, + dev_name)) { + jsonw_name(dl->jw, buf); + jsonw_start_array(dl->jw); + jsonw_start_object(dl->jw); + arr_last_handle_set(dl, bus_name, dev_name); + } else { + jsonw_start_object(dl->jw); + } + } else { + jsonw_name(dl->jw, buf); + jsonw_start_object(dl->jw); + } + } else { + pr_out("%s%s", buf, content ? ":" : ""); + } +} -no_nice_names: - __pr_out_port_handle(bus_name, dev_name, port_index); +static void pr_out_handle_start_arr(struct dl *dl, struct nlattr **tb) +{ + __pr_out_handle_start(dl, tb, true, true); } -static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) +static void pr_out_handle_end(struct dl *dl) +{ + if (dl->json_output) + jsonw_end_object(dl->jw); + else + pr_out("\n"); +} + +static void pr_out_handle(struct dl *dl, struct nlattr **tb) +{ + __pr_out_handle_start(dl, tb, false, false); + pr_out_handle_end(dl); +} + +static bool cmp_arr_last_port_handle(struct dl *dl, const char *bus_name, + const char *dev_name, uint32_t port_index) +{ + return cmp_arr_last_handle(dl, bus_name, dev_name) && + dl->arr_last.port_index == port_index; +} + +static void arr_last_port_handle_set(struct dl *dl, const char *bus_name, + const char *dev_name, uint32_t port_index) +{ + arr_last_handle_set(dl, bus_name, dev_name); + dl->arr_last.port_index = port_index; +} + +static bool should_arr_last_port_handle_start(struct dl *dl, + const char *bus_name, + const char *dev_name, + uint32_t port_index) +{ + return !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index); +} + +static bool should_arr_last_port_handle_end(struct dl *dl, + const char *bus_name, + const char *dev_name, + uint32_t port_index) +{ + return dl->arr_last.present && + !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index); +} + +static void __pr_out_port_handle_start(struct dl *dl, const char *bus_name, + const char *dev_name, + uint32_t port_index, bool try_nice, + bool array) +{ + static char buf[32]; + char *ifname = NULL; + + if (dl->no_nice_names || !try_nice || + ifname_map_rev_lookup(dl, bus_name, dev_name, + port_index, &ifname) != 0) + sprintf(buf, "%s/%s/%d", bus_name, dev_name, port_index); + else + sprintf(buf, "%s", ifname); + + if (dl->json_output) { + if (array) { + if (should_arr_last_port_handle_end(dl, bus_name, + dev_name, + port_index)) + jsonw_end_array(dl->jw); + if (should_arr_last_port_handle_start(dl, bus_name, + dev_name, + port_index)) { + jsonw_name(dl->jw, buf); + jsonw_start_array(dl->jw); + jsonw_start_object(dl->jw); + arr_last_port_handle_set(dl, bus_name, dev_name, + port_index); + } else { + jsonw_start_object(dl->jw); + } + } else { + jsonw_name(dl->jw, buf); + jsonw_start_object(dl->jw); + } + } else { + pr_out("%s:", buf); + } +} + +static void pr_out_port_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice) { const char *bus_name; const char *dev_name; @@ -966,25 +1085,80 @@ static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); + __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, false); +} + +static void pr_out_port_handle_start_arr(struct dl *dl, struct nlattr **tb, bool try_nice) +{ + const char *bus_name; + const char *dev_name; + uint32_t port_index; - __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index); + bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); + dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); + port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); + __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, true); } -static void pr_out_dev(struct nlattr **tb) +static void pr_out_port_handle_end(struct dl *dl) { - pr_out_handle(tb); - pr_out("\n"); + if (dl->json_output) + jsonw_end_object(dl->jw); + else + pr_out("\n"); +} + + +static void pr_out_str(struct dl *dl, const char *name, const char *val) +{ + if (dl->json_output) + jsonw_string_field(dl->jw, name, val); + else + pr_out(" %s %s", name, val); +} + +static void pr_out_uint(struct dl *dl, const char *name, unsigned int val) +{ + if (dl->json_output) + jsonw_uint_field(dl->jw, name, val); + else + pr_out(" %s %u", name, val); +} + +static void pr_out_dev(struct dl *dl, struct nlattr **tb) +{ + pr_out_handle(dl, tb); +} + +static void pr_out_section_start(struct dl *dl, const char *name) +{ + if (dl->json_output) { + jsonw_start_object(dl->jw); + jsonw_name(dl->jw, name); + jsonw_start_object(dl->jw); + } +} + +static void pr_out_section_end(struct dl *dl) +{ + if (dl->json_output) { + if (dl->arr_last.present) + jsonw_end_array(dl->jw); + jsonw_end_object(dl->jw); + jsonw_end_object(dl->jw); + } } static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data) { + struct dl *dl = data; struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) return MNL_CB_ERROR; - pr_out_dev(tb); + pr_out_dev(dl, tb); return MNL_CB_OK; } @@ -1005,7 +1179,10 @@ static int cmd_dev_show(struct dl *dl) return err; } - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, NULL); + pr_out_section_start(dl, "dev"); + err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, dl); + pr_out_section_end(dl); + return err; } static int cmd_dev(struct dl *dl) @@ -1041,38 +1218,39 @@ static const char *port_type_name(uint32_t type) } } -static void pr_out_port(struct nlattr **tb) +static void pr_out_port(struct dl *dl, struct nlattr **tb) { struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE]; struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE]; - pr_out_port_handle(tb); - pr_out(":"); + pr_out_port_handle_start(dl, tb, false); if (pt_attr) { uint16_t port_type = mnl_attr_get_u16(pt_attr); - pr_out(" type %s", port_type_name(port_type)); + pr_out_str(dl, "type", port_type_name(port_type)); if (dpt_attr) { uint16_t des_port_type = mnl_attr_get_u16(dpt_attr); if (port_type != des_port_type) - pr_out("(%s)", port_type_name(des_port_type)); + pr_out_str(dl, "des_type", + port_type_name(des_port_type)); } } if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) - pr_out(" netdev %s", - mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME])); + pr_out_str(dl, "netdev", + mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME])); if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME]) - pr_out(" ibdev %s", - mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME])); + pr_out_str(dl, "ibdev", + mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME])); if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]) - pr_out(" split_group %u", - mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])); - pr_out("\n"); + pr_out_uint(dl, "split_group", + mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])); + pr_out_port_handle_end(dl); } static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data) { + struct dl *dl = data; struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); @@ -1080,7 +1258,7 @@ static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data) if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || !tb[DEVLINK_ATTR_PORT_INDEX]) return MNL_CB_ERROR; - pr_out_port(tb); + pr_out_port(dl, tb); return MNL_CB_OK; } @@ -1101,7 +1279,10 @@ static int cmd_port_show(struct dl *dl) return err; } - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, NULL); + pr_out_section_start(dl, "port"); + err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl); + pr_out_section_end(dl); + return err; } static int cmd_port_set(struct dl *dl) @@ -1192,20 +1373,27 @@ static void cmd_sb_help(void) pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); } -static void pr_out_sb(struct nlattr **tb) +static void pr_out_sb(struct dl *dl, struct nlattr **tb) { - pr_out_handle(tb); - pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); + pr_out_handle_start_arr(dl, tb); + pr_out_uint(dl, "sb", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); + pr_out_uint(dl, "size", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE])); + pr_out_uint(dl, "ing_pools", + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT])); + pr_out_uint(dl, "eg_pools", + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT])); + pr_out_uint(dl, "ing_tcs", + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT])); + pr_out_uint(dl, "eg_tcs", + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); + pr_out_handle_end(dl); } static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) { + struct dl *dl = data; struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); @@ -1217,7 +1405,7 @@ static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] || !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]) return MNL_CB_ERROR; - pr_out_sb(tb); + pr_out_sb(dl, tb); return MNL_CB_OK; } @@ -1238,7 +1426,10 @@ static int cmd_sb_show(struct dl *dl) return err; } - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL); + pr_out_section_start(dl, "sb"); + err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, dl); + pr_out_section_end(dl); + return err; } static const char *pool_type_name(uint8_t type) @@ -1259,19 +1450,25 @@ static const char *threshold_type_name(uint8_t type) } } -static void pr_out_sb_pool(struct nlattr **tb) +static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb) { - pr_out_handle(tb); - pr_out(": sb %u pool %u type %s size %u thtype %s\n", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), - pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]), - threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); + pr_out_handle_start_arr(dl, tb); + pr_out_uint(dl, "sb", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); + pr_out_uint(dl, "pool", + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); + pr_out_str(dl, "type", + pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]))); + pr_out_uint(dl, "size", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE])); + pr_out_str(dl, "thtype", + threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); + pr_out_handle_end(dl); } static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) { + struct dl *dl = data; struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); @@ -1281,7 +1478,7 @@ static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] || !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) return MNL_CB_ERROR; - pr_out_sb_pool(tb); + pr_out_sb_pool(dl, tb); return MNL_CB_OK; } @@ -1303,7 +1500,10 @@ static int cmd_sb_pool_show(struct dl *dl) return err; } - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL); + pr_out_section_start(dl, "pool"); + err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, dl); + pr_out_section_end(dl); + return err; } static int cmd_sb_pool_set(struct dl *dl) @@ -1341,11 +1541,14 @@ static int cmd_sb_pool(struct dl *dl) static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb) { - pr_out_port_handle_nice(dl, tb); - pr_out(": sb %u pool %u threshold %u\n", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); + pr_out_port_handle_start_arr(dl, tb, true); + pr_out_uint(dl, "sb", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); + pr_out_uint(dl, "pool", + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); + pr_out_uint(dl, "threshold", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); + pr_out_port_handle_end(dl); } static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data) @@ -1382,7 +1585,10 @@ static int cmd_sb_port_pool_show(struct dl *dl) return err; } - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); + pr_out_section_start(dl, "port_pool"); + err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); + pr_out_section_end(dl); + return 0; } static int cmd_sb_port_pool_set(struct dl *dl) @@ -1433,13 +1639,18 @@ static int cmd_sb_port(struct dl *dl) static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb) { - pr_out_port_handle_nice(dl, tb); - pr_out(": sb %u tc %u type %s pool %u threshold %u\n", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]), - pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), + pr_out_port_handle_start_arr(dl, tb, true); + pr_out_uint(dl, "sb", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); + pr_out_uint(dl, "tc", + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX])); + pr_out_str(dl, "type", + pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]))); + pr_out_uint(dl, "pool", + mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); + pr_out_uint(dl, "threshold", mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); + pr_out_port_handle_end(dl); } static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data) @@ -1476,7 +1687,10 @@ static int cmd_sb_tc_bind_show(struct dl *dl) return err; } - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); + pr_out_section_start(dl, "tc_bind"); + err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); + pr_out_section_end(dl); + return err; } static int cmd_sb_tc_bind_set(struct dl *dl) @@ -1649,11 +1863,44 @@ static void pr_out_occ_show_item_list(const char *label, struct list_head *list, pr_out("\n"); } -static void pr_out_occ_show_port(struct occ_port *occ_port) +static void pr_out_json_occ_show_item_list(struct dl *dl, const char *label, + struct list_head *list, + bool bound_pool) +{ + struct occ_item *occ_item; + char buf[32]; + + jsonw_name(dl->jw, label); + jsonw_start_object(dl->jw); + list_for_each_entry(occ_item, list, list) { + sprintf(buf, "%u", occ_item->index); + jsonw_name(dl->jw, buf); + jsonw_start_object(dl->jw); + if (bound_pool) + jsonw_uint_field(dl->jw, "bound_pool", + occ_item->bound_pool_index); + jsonw_uint_field(dl->jw, "current", occ_item->cur); + jsonw_uint_field(dl->jw, "max", occ_item->max); + jsonw_end_object(dl->jw); + } + jsonw_end_object(dl->jw); +} + +static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port) { - pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); - pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); - pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); + if (dl->json_output) { + pr_out_json_occ_show_item_list(dl, "pool", + &occ_port->pool_list, false); + pr_out_json_occ_show_item_list(dl, "itc", + &occ_port->ing_tc_list, true); + pr_out_json_occ_show_item_list(dl, "etc", + &occ_port->eg_tc_list, true); + } else { + pr_out("\n"); + pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); + pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); + pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); + } } static void pr_out_occ_show(struct occ_show *occ_show) @@ -1663,10 +1910,10 @@ static void pr_out_occ_show(struct occ_show *occ_show) struct occ_port *occ_port; list_for_each_entry(occ_port, &occ_show->port_list, list) { - __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name, - occ_port->port_index); - pr_out(":\n"); - pr_out_occ_show_port(occ_port); + __pr_out_port_handle_start(dl, opts->bus_name, opts->dev_name, + occ_port->port_index, true, false); + pr_out_occ_show_port(dl, occ_port); + pr_out_port_handle_end(dl); } } @@ -1793,7 +2040,9 @@ static int cmd_sb_occ_show(struct dl *dl) if (err) goto out; + pr_out_section_start(dl, "occupancy"); pr_out_occ_show(occ_show); + pr_out_section_end(dl); out: occ_show_free(occ_show); @@ -1949,7 +2198,7 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data) if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) return MNL_CB_ERROR; pr_out_mon_header(genl->cmd); - pr_out_dev(tb); + pr_out_dev(dl, tb); break; case DEVLINK_CMD_PORT_GET: /* fall through */ case DEVLINK_CMD_PORT_SET: /* fall through */ @@ -1960,7 +2209,7 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data) !tb[DEVLINK_ATTR_PORT_INDEX]) return MNL_CB_ERROR; pr_out_mon_header(genl->cmd); - pr_out_port(tb); + pr_out_port(dl, tb); break; } return MNL_CB_OK; @@ -2055,8 +2304,18 @@ static int dl_init(struct dl *dl, int argc, char **argv) pr_err("Failed to create index map\n"); goto err_ifname_map_create; } + if (dl->json_output) { + dl->jw = jsonw_new(stdout); + if (!dl->jw) { + pr_err("Failed to create JSON writer\n"); + goto err_json_new; + } + jsonw_pretty(dl->jw, dl->pretty_output); + } return 0; +err_json_new: + ifname_map_fini(dl); err_ifname_map_create: mnlg_socket_close(dl->nlg); return err; @@ -2064,6 +2323,8 @@ static int dl_init(struct dl *dl, int argc, char **argv) static void dl_fini(struct dl *dl) { + if (dl->json_output) + jsonw_destroy(&dl->jw); ifname_map_fini(dl); mnlg_socket_close(dl->nlg); } @@ -2088,6 +2349,8 @@ int main(int argc, char **argv) static const struct option long_options[] = { { "Version", no_argument, NULL, 'V' }, { "no-nice-names", no_argument, NULL, 'n' }, + { "json", no_argument, NULL, 'j' }, + { "pretty", no_argument, NULL, 'p' }, { NULL, 0, NULL, 0 } }; struct dl *dl; @@ -2101,7 +2364,7 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - while ((opt = getopt_long(argc, argv, "Vn", + while ((opt = getopt_long(argc, argv, "Vnjp", long_options, NULL)) >= 0) { switch (opt) { @@ -2111,6 +2374,12 @@ int main(int argc, char **argv) case 'n': dl->no_nice_names = true; break; + case 'j': + dl->json_output = true; + break; + case 'p': + dl->pretty_output = true; + break; default: pr_err("Unknown option.\n"); help(); From 9579afb24e9c56c6fc4c89e2e99fe4b3de304200 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 3 Aug 2016 11:43:45 +0200 Subject: [PATCH 355/513] tc: Fix for missing estimator initialization When switching to C99 initializers, I forgot to add this one. This means that when trying to set an estimator value, tc would complain about spurious duplicate estimator parameter. But much worse, the random variable content is sent to the kernel regardless of whether an estimator was given or not. Fixes: d17b136f7d7dd ("Use C99 style initializers everywhere") Reported-by: Stas Nichiporovich Signed-off-by: Phil Sutter --- tc/tc_qdisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index bc87aab11..93c9a4c1d 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -45,7 +45,7 @@ static int usage(void) static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv) { struct qdisc_util *q = NULL; - struct tc_estimator est; + struct tc_estimator est = {}; struct { struct tc_sizespec szopts; __u16 *data; From 1eeb6fdac8707c5391f73830582344671310c5a1 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Sun, 7 Aug 2016 12:37:03 -0700 Subject: [PATCH 356/513] bridge: vlan json: skip ports with empty vlans The non-json output prints 'None' for such vlans. And this can garble json output. Fixes: d82a49ce85f0 ("bridge: add json support for bridge vlan show") Signed-off-by: Roopa Prabhu --- bridge/vlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bridge/vlan.c b/bridge/vlan.c index f262cc7f1..c2e635fce 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -212,7 +212,7 @@ static int print_vlan(const struct sockaddr_nl *who, /* if AF_SPEC isn't there, vlan table is not preset for this port */ if (!tb[IFLA_AF_SPEC]) { - if (!filter_vlan) + if (!filter_vlan && !jw_global) fprintf(fp, "%s\tNone\n", ll_index_to_name(ifm->ifi_index)); return 0; From 39c64df1c7c3c9ad9d9af89429448a3fab1f8dfe Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 2 Aug 2016 23:07:05 -0700 Subject: [PATCH 357/513] bridge: print_vlan: add missing check for json instance Also initialize vlan_flags Fixes: d82a49ce85f0 ("bridge: add json support for bridge vlan show") Signed-off-by: Roopa Prabhu --- bridge/vlan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bridge/vlan.c b/bridge/vlan.c index c2e635fce..d3505b59b 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -188,7 +188,7 @@ static int print_vlan(const struct sockaddr_nl *who, struct ifinfomsg *ifm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[IFLA_MAX+1]; - bool vlan_flags; + bool vlan_flags = false; if (n->nlmsg_type != RTM_NEWLINK) { fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n", @@ -276,7 +276,7 @@ static int print_vlan(const struct sockaddr_nl *who, fprintf(fp, " Egress Untagged"); } } - if (vlan_flags) { + if (jw_global && vlan_flags) { jsonw_end_array(jw_global); vlan_flags = false; } From dc00db9e84ff36fefe313ee4a3f5097b088567b9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 Aug 2016 08:51:22 -0700 Subject: [PATCH 358/513] update kernel headers --- include/linux/bpf.h | 10 ++++++++++ include/linux/if_macsec.h | 2 ++ include/linux/in6.h | 1 + include/linux/pkt_cls.h | 12 ++++++++++++ include/linux/tipc.h | 30 +++++++++++++++++++++++++---- include/linux/tipc_netlink.h | 37 ++++++++++++++++++++++++++++++++++++ 6 files changed, 88 insertions(+), 4 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 546d4ceca..19e0c36a4 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -365,6 +365,16 @@ enum bpf_func_id { */ BPF_FUNC_get_current_task, + /** + * bpf_probe_write_user(void *dst, void *src, int len) + * safely attempt to write to a location + * @dst: destination address in userspace + * @src: source address on stack + * @len: number of bytes to copy + * Return: 0 on success or negative error + */ + BPF_FUNC_probe_write_user, + __BPF_FUNC_MAX_ID, }; diff --git a/include/linux/if_macsec.h b/include/linux/if_macsec.h index cbd4faa35..22939a3ec 100644 --- a/include/linux/if_macsec.h +++ b/include/linux/if_macsec.h @@ -26,6 +26,8 @@ #define MACSEC_MIN_ICV_LEN 8 #define MACSEC_MAX_ICV_LEN 32 +/* upper limit for ICV length as recommended by IEEE802.1AE-2006 */ +#define MACSEC_STD_ICV_LEN 16 enum macsec_attrs { MACSEC_ATTR_UNSPEC, diff --git a/include/linux/in6.h b/include/linux/in6.h index aa5b66df6..45aaaa40f 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -143,6 +143,7 @@ struct in6_flowlabel_req { #define IPV6_TLV_PAD1 0 #define IPV6_TLV_PADN 1 #define IPV6_TLV_ROUTERALERT 5 +#define IPV6_TLV_CALIPSO 7 /* RFC 5570 */ #define IPV6_TLV_JUMBO 194 #define IPV6_TLV_HAO 201 /* home address option */ diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index 44cda2549..5e6c61e7f 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -379,6 +379,18 @@ enum { #define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) +/* Match-all classifier */ + +enum { + TCA_MATCHALL_UNSPEC, + TCA_MATCHALL_CLASSID, + TCA_MATCHALL_ACT, + TCA_MATCHALL_FLAGS, + __TCA_MATCHALL_MAX, +}; + +#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1) + /* Extended Matches */ struct tcf_ematch_tree_hdr { diff --git a/include/linux/tipc.h b/include/linux/tipc.h index ebd3b63ca..400430084 100644 --- a/include/linux/tipc.h +++ b/include/linux/tipc.h @@ -60,26 +60,48 @@ struct tipc_name_seq { __u32 upper; }; +/* TIPC Address Size, Offset, Mask specification for Z.C.N + */ +#define TIPC_NODE_BITS 12 +#define TIPC_CLUSTER_BITS 12 +#define TIPC_ZONE_BITS 8 + +#define TIPC_NODE_OFFSET 0 +#define TIPC_CLUSTER_OFFSET TIPC_NODE_BITS +#define TIPC_ZONE_OFFSET (TIPC_CLUSTER_OFFSET + TIPC_CLUSTER_BITS) + +#define TIPC_NODE_SIZE ((1UL << TIPC_NODE_BITS) - 1) +#define TIPC_CLUSTER_SIZE ((1UL << TIPC_CLUSTER_BITS) - 1) +#define TIPC_ZONE_SIZE ((1UL << TIPC_ZONE_BITS) - 1) + +#define TIPC_NODE_MASK (TIPC_NODE_SIZE << TIPC_NODE_OFFSET) +#define TIPC_CLUSTER_MASK (TIPC_CLUSTER_SIZE << TIPC_CLUSTER_OFFSET) +#define TIPC_ZONE_MASK (TIPC_ZONE_SIZE << TIPC_ZONE_OFFSET) + +#define TIPC_ZONE_CLUSTER_MASK (TIPC_ZONE_MASK | TIPC_CLUSTER_MASK) + static __inline__ __u32 tipc_addr(unsigned int zone, unsigned int cluster, unsigned int node) { - return (zone << 24) | (cluster << 12) | node; + return (zone << TIPC_ZONE_OFFSET) | + (cluster << TIPC_CLUSTER_OFFSET) | + node; } static __inline__ unsigned int tipc_zone(__u32 addr) { - return addr >> 24; + return addr >> TIPC_ZONE_OFFSET; } static __inline__ unsigned int tipc_cluster(__u32 addr) { - return (addr >> 12) & 0xfff; + return (addr & TIPC_CLUSTER_MASK) >> TIPC_CLUSTER_OFFSET; } static __inline__ unsigned int tipc_node(__u32 addr) { - return addr & 0xfff; + return addr & TIPC_NODE_MASK; } /* diff --git a/include/linux/tipc_netlink.h b/include/linux/tipc_netlink.h index d4c8f142b..5f3f6d09f 100644 --- a/include/linux/tipc_netlink.h +++ b/include/linux/tipc_netlink.h @@ -56,6 +56,9 @@ enum { TIPC_NL_NET_GET, TIPC_NL_NET_SET, TIPC_NL_NAME_TABLE_GET, + TIPC_NL_MON_SET, + TIPC_NL_MON_GET, + TIPC_NL_MON_PEER_GET, __TIPC_NL_CMD_MAX, TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 @@ -72,6 +75,8 @@ enum { TIPC_NLA_NODE, /* nest */ TIPC_NLA_NET, /* nest */ TIPC_NLA_NAME_TABLE, /* nest */ + TIPC_NLA_MON, /* nest */ + TIPC_NLA_MON_PEER, /* nest */ __TIPC_NLA_MAX, TIPC_NLA_MAX = __TIPC_NLA_MAX - 1 @@ -166,6 +171,20 @@ enum { TIPC_NLA_NAME_TABLE_MAX = __TIPC_NLA_NAME_TABLE_MAX - 1 }; +/* Monitor info */ +enum { + TIPC_NLA_MON_UNSPEC, + TIPC_NLA_MON_ACTIVATION_THRESHOLD, /* u32 */ + TIPC_NLA_MON_REF, /* u32 */ + TIPC_NLA_MON_ACTIVE, /* flag */ + TIPC_NLA_MON_BEARER_NAME, /* string */ + TIPC_NLA_MON_PEERCNT, /* u32 */ + TIPC_NLA_MON_LISTGEN, /* u32 */ + + __TIPC_NLA_MON_MAX, + TIPC_NLA_MON_MAX = __TIPC_NLA_MON_MAX - 1 +}; + /* Publication info */ enum { TIPC_NLA_PUBL_UNSPEC, @@ -182,6 +201,24 @@ enum { TIPC_NLA_PUBL_MAX = __TIPC_NLA_PUBL_MAX - 1 }; +/* Monitor peer info */ +enum { + TIPC_NLA_MON_PEER_UNSPEC, + + TIPC_NLA_MON_PEER_ADDR, /* u32 */ + TIPC_NLA_MON_PEER_DOMGEN, /* u32 */ + TIPC_NLA_MON_PEER_APPLIED, /* u32 */ + TIPC_NLA_MON_PEER_UPMAP, /* u64 */ + TIPC_NLA_MON_PEER_MEMBERS, /* tlv */ + TIPC_NLA_MON_PEER_UP, /* flag */ + TIPC_NLA_MON_PEER_HEAD, /* flag */ + TIPC_NLA_MON_PEER_LOCAL, /* flag */ + TIPC_NLA_MON_PEER_PAD, /* flag */ + + __TIPC_NLA_MON_PEER_MAX, + TIPC_NLA_MON_PEER_MAX = __TIPC_NLA_MON_PEER_MAX - 1 +}; + /* Nest, connection info */ enum { TIPC_NLA_CON_UNSPEC, From c15feb99a42d21ab7d9653bccc9555526a65e2da Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sun, 7 Aug 2016 13:19:01 +0200 Subject: [PATCH 359/513] tc/m_gact: Fix action_a2n() return code check The function returns zero on success. Reported-by: Mark Bloch Fixes: 69f5aff63c770b ("tc: use action_a2n() everywhere") Signed-off-by: Phil Sutter --- tc/m_gact.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tc/m_gact.c b/tc/m_gact.c index c0a938c71..2bfd9a7c3 100644 --- a/tc/m_gact.c +++ b/tc/m_gact.c @@ -73,7 +73,7 @@ get_act(char ***argv_p) { int n; - if (!action_a2n(**argv_p, &n, false)) { + if (action_a2n(**argv_p, &n, false)) { fprintf(stderr, "bad action type %s\n", **argv_p); return -10; } From 4ecc96f8b64e499973b50232d59a5bf4488e23a6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 8 Aug 2016 08:58:39 -0700 Subject: [PATCH 360/513] v4.7.0 --- include/SNAPSHOT.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/SNAPSHOT.h b/include/SNAPSHOT.h index cc67058f5..fdf318444 100644 --- a/include/SNAPSHOT.h +++ b/include/SNAPSHOT.h @@ -1 +1 @@ -static const char SNAPSHOT[] = "160518"; +static const char SNAPSHOT[] = "160808"; From e40d6b2b906a47e1be466b8e87e74ae30b24cff5 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 2 Aug 2016 23:07:05 -0700 Subject: [PATCH 361/513] bridge: print_vlan: add missing check for json instance Also initialize vlan_flags Fixes: d82a49ce85f0 ("bridge: add json support for bridge vlan show") Signed-off-by: Roopa Prabhu --- bridge/vlan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bridge/vlan.c b/bridge/vlan.c index c2e635fce..d3505b59b 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -188,7 +188,7 @@ static int print_vlan(const struct sockaddr_nl *who, struct ifinfomsg *ifm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[IFLA_MAX+1]; - bool vlan_flags; + bool vlan_flags = false; if (n->nlmsg_type != RTM_NEWLINK) { fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n", @@ -276,7 +276,7 @@ static int print_vlan(const struct sockaddr_nl *who, fprintf(fp, " Egress Untagged"); } } - if (vlan_flags) { + if (jw_global && vlan_flags) { jsonw_end_array(jw_global); vlan_flags = false; } From 6fcf36c9c66053f77aeab768c9c15c9a4868cb73 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Mon, 8 Aug 2016 16:24:45 -0700 Subject: [PATCH 362/513] tc: fix a misleading failure Before this patch: # ./tc/tc actions add action drop index 11 RTNETLINK answers: File exists We have an error talking to the kernel Command "(null)" is unknown, try "tc actions help". After this patch: # ./tc/tc actions add action drop index 11 RTNETLINK answers: File exists We have an error talking to the kernel Cc: Stephen Hemminger Cc: Jamal Hadi Salim Signed-off-by: Cong Wang --- tc/m_action.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tc/m_action.c b/tc/m_action.c index 24f8b5d85..bb19df882 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -623,14 +623,12 @@ int do_action(int argc, char **argv) act_usage(); return -1; } else { - - ret = -1; - } - - if (ret < 0) { fprintf(stderr, "Command \"%s\" is unknown, try \"tc actions help\".\n", *argv); return -1; } + + if (ret < 0) + return -1; } return 0; From ed67f83806538795a9d9f921c54cfece352f83cf Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Aug 2016 13:34:53 -0700 Subject: [PATCH 363/513] ila: Support for checksum neutral translation Add configuration of ila LWT tunnels for checksum mode including checksum neutral translation. Signed-off-by: Tom Herbert --- ip/iproute_lwtunnel.c | 58 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index bdbb15d2b..b65614327 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -90,6 +90,32 @@ static void print_encap_ip(FILE *fp, struct rtattr *encap) fprintf(fp, "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS])); } +static char *ila_csum_mode2name(__u8 csum_mode) +{ + switch (csum_mode) { + case ILA_CSUM_ADJUST_TRANSPORT: + return "adj-transport"; + case ILA_CSUM_NEUTRAL_MAP: + return "neutral-map"; + case ILA_CSUM_NO_ACTION: + return "no-action"; + default: + return "unknown"; + } +} + +static __u8 ila_csum_name2mode(char *name) +{ + if (strcmp(name, "adj-transport") == 0) + return ILA_CSUM_ADJUST_TRANSPORT; + else if (strcmp(name, "neutral-map") == 0) + return ILA_CSUM_NEUTRAL_MAP; + else if (strcmp(name, "no-action") == 0) + return ILA_CSUM_NO_ACTION; + else + return -1; +} + static void print_encap_ila(FILE *fp, struct rtattr *encap) { struct rtattr *tb[ILA_ATTR_MAX+1]; @@ -103,6 +129,10 @@ static void print_encap_ila(FILE *fp, struct rtattr *encap) abuf, sizeof(abuf)); fprintf(fp, " %s ", abuf); } + + if (tb[ILA_ATTR_CSUM_MODE]) + fprintf(fp, " csum-mode %s ", + ila_csum_mode2name(rta_getattr_u8(tb[ILA_ATTR_CSUM_MODE]))); } static void print_encap_ip6(FILE *fp, struct rtattr *encap) @@ -246,10 +276,34 @@ static int parse_encap_ila(struct rtattr *rta, size_t len, exit(1); } + argc--; argv++; + rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator); - *argcp = argc; - *argvp = argv; + while (argc > 0) { + if (strcmp(*argv, "csum-mode") == 0) { + __u8 csum_mode; + + NEXT_ARG(); + + csum_mode = ila_csum_name2mode(*argv); + if (csum_mode < 0) + invarg("\"csum-mode\" value is invalid\n", *argv); + + rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE, csum_mode); + + argc--; argv++; + } else { + break; + } + } + + /* argv is currently the first unparsed argument, + * but the lwt_parse_encap() caller will move to the next, + * so step back + */ + *argcp = argc + 1; + *argvp = argv - 1; return 0; } From ec71cae0bb7b1930f930979b974b5cb138f325d0 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Aug 2016 13:34:54 -0700 Subject: [PATCH 364/513] ila: Support for configuring ila to use netfilter hook Signed-off-by: Tom Herbert --- ip/Makefile | 2 +- ip/ip.c | 3 +- ip/ip_common.h | 1 + ip/ipila.c | 266 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 270 insertions(+), 2 deletions(-) create mode 100644 ip/ipila.c diff --git a/ip/Makefile b/ip/Makefile index 33e9286d4..86c8cdc07 100644 --- a/ip/Makefile +++ b/ip/Makefile @@ -7,7 +7,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \ iplink_vxlan.o tcp_metrics.o iplink_ipoib.o ipnetconf.o link_ip6tnl.o \ link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o \ iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \ - iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o + iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o ipila.o RTMONOBJ=rtmon.o diff --git a/ip/ip.c b/ip/ip.c index 166ef1749..cb3adcb3f 100644 --- a/ip/ip.c +++ b/ip/ip.c @@ -51,7 +51,7 @@ static void usage(void) " ip [ -force ] -batch filename\n" "where OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |\n" " tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |\n" -" netns | l2tp | fou | macsec | tcp_metrics | token | netconf }\n" +" netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila }\n" " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n" " -h[uman-readable] | -iec |\n" " -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n" @@ -84,6 +84,7 @@ static const struct cmd { { "link", do_iplink }, { "l2tp", do_ipl2tp }, { "fou", do_ipfou }, + { "ila", do_ipila }, { "macsec", do_ipmacsec }, { "tunnel", do_iptunnel }, { "tunl", do_iptunnel }, diff --git a/ip/ip_common.h b/ip/ip_common.h index c8188122a..93ff5bce4 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -52,6 +52,7 @@ int do_netns(int argc, char **argv); int do_xfrm(int argc, char **argv); int do_ipl2tp(int argc, char **argv); int do_ipfou(int argc, char **argv); +extern int do_ipila(int argc, char **argv); int do_tcp_metrics(int argc, char **argv); int do_ipnetconf(int argc, char **argv); int do_iptoken(int argc, char **argv); diff --git a/ip/ipila.c b/ip/ipila.c new file mode 100644 index 000000000..c30bdbf16 --- /dev/null +++ b/ip/ipila.c @@ -0,0 +1,266 @@ +/* + * ipila.c ILA (Identifier Locator Addressing) support + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Tom Herbert + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libgenl.h" +#include "utils.h" +#include "ip_common.h" + +static void usage(void) +{ + fprintf(stderr, "Usage: ip ila add loc_match LOCATOR_MATCH " + "loc LOCATOR [ dev DEV ]\n"); + fprintf(stderr, " ip ila del loc_match LOCATOR_MATCH " + "[ loc LOCATOR ] [ dev DEV ]\n"); + fprintf(stderr, " ip ila list\n"); + fprintf(stderr, "\n"); + + exit(-1); +} + +/* netlink socket */ +static struct rtnl_handle genl_rth = { .fd = -1 }; +static int genl_family = -1; + +#define ILA_REQUEST(_req, _bufsiz, _cmd, _flags) \ + GENL_REQUEST(_req, _bufsiz, genl_family, 0, \ + ILA_GENL_VERSION, _cmd, _flags) + +#define ILA_RTA(g) ((struct rtattr *)(((char *)(g)) + \ + NLMSG_ALIGN(sizeof(struct genlmsghdr)))) + +#define ADDR_BUF_SIZE sizeof("xxxx:xxxx:xxxx:xxxx") + +static int print_addr64(__u64 addr, char *buff, size_t len) +{ + __u16 *words = (__u16 *)&addr; + __u16 v; + int i, ret; + size_t written = 0; + char *sep = ":"; + + for (i = 0; i < 4; i++) { + v = ntohs(words[i]); + + if (i == 3) + sep = ""; + + ret = snprintf(&buff[written], len - written, "%x%s", v, sep); + if (ret < 0) + return ret; + + written += ret; + } + + return written; +} + +static void print_ila_locid(FILE *fp, int attr, struct rtattr *tb[], int space) +{ + char abuf[256]; + size_t blen; + int i; + + if (tb[attr]) { + blen = print_addr64(rta_getattr_u32(tb[attr]), + abuf, sizeof(abuf)); + fprintf(fp, "%s", abuf); + } else { + fprintf(fp, "-"); + blen = 1; + } + + for (i = 0; i < space - blen; i++) + fprintf(fp, " "); +} + +static int print_ila_mapping(const struct sockaddr_nl *who, + struct nlmsghdr *n, void *arg) +{ + FILE *fp = (FILE *)arg; + struct genlmsghdr *ghdr; + struct rtattr *tb[ILA_ATTR_MAX + 1]; + int len = n->nlmsg_len; + + if (n->nlmsg_type != genl_family) + return 0; + + len -= NLMSG_LENGTH(GENL_HDRLEN); + if (len < 0) + return -1; + + ghdr = NLMSG_DATA(n); + parse_rtattr(tb, ILA_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len); + + print_ila_locid(fp, ILA_ATTR_LOCATOR_MATCH, tb, ADDR_BUF_SIZE); + print_ila_locid(fp, ILA_ATTR_LOCATOR, tb, ADDR_BUF_SIZE); + + if (tb[ILA_ATTR_IFINDEX]) + fprintf(fp, "%s", ll_index_to_name(rta_getattr_u32(tb[ILA_ATTR_IFINDEX]))); + else + fprintf(fp, "-"); + fprintf(fp, "\n"); + + return 0; +} + +#define NLMSG_BUF_SIZE 4096 + +static int do_list(int argc, char **argv) +{ + ILA_REQUEST(req, 1024, ILA_CMD_GET, NLM_F_REQUEST | NLM_F_DUMP); + + if (argc > 0) { + fprintf(stderr, "\"ip ila show\" does not take " + "any arguments.\n"); + return -1; + } + + if (rtnl_send(&genl_rth, (void *)&req, req.n.nlmsg_len) < 0) { + perror("Cannot send dump request"); + exit(1); + } + + if (rtnl_dump_filter(&genl_rth, print_ila_mapping, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); + return 1; + } + + return 0; +} + +static int ila_parse_opt(int argc, char **argv, struct nlmsghdr *n, + bool adding) +{ + __u64 locator; + __u64 locator_match; + int ifindex = 0; + bool loc_set = false; + bool loc_match_set = false; + bool ifindex_set = false; + + while (argc > 0) { + if (!matches(*argv, "loc")) { + NEXT_ARG(); + + if (get_addr64(&locator, *argv) < 0) { + fprintf(stderr, "Bad locator: %s\n", *argv); + return -1; + } + loc_set = true; + } else if (!matches(*argv, "loc_match")) { + NEXT_ARG(); + + if (get_addr64(&locator_match, *argv) < 0) { + fprintf(stderr, "Bad locator to match: %s\n", + *argv); + return -1; + } + loc_match_set = true; + } else if (!matches(*argv, "dev")) { + NEXT_ARG(); + + ifindex = ll_name_to_index(*argv); + if (ifindex == 0) { + fprintf(stderr, "No such interface: %s\n", + *argv); + return -1; + } + ifindex_set = true; + } else { + usage(); + return -1; + } + argc--, argv++; + } + + if (adding) { + if (!loc_set) { + fprintf(stderr, "ila: missing locator\n"); + return -1; + } + if (!loc_match_set) { + fprintf(stderr, "ila: missing locator0match\n"); + return -1; + } + } + + addattr64(n, 1024, ILA_ATTR_LOCATOR_MATCH, locator_match); + addattr64(n, 1024, ILA_ATTR_LOCATOR, locator); + + if (ifindex_set) + addattr32(n, 1024, ILA_ATTR_IFINDEX, ifindex); + + return 0; +} + +static int do_add(int argc, char **argv) +{ + ILA_REQUEST(req, 1024, ILA_CMD_ADD, NLM_F_REQUEST); + + ila_parse_opt(argc, argv, &req.n, true); + + if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0) + return -2; + + return 0; +} + +static int do_del(int argc, char **argv) +{ + ILA_REQUEST(req, 1024, ILA_CMD_DEL, NLM_F_REQUEST); + + ila_parse_opt(argc, argv, &req.n, false); + + if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0) + return -2; + + return 0; +} + +int do_ipila(int argc, char **argv) +{ + if (genl_family < 0) { + if (rtnl_open_byproto(&genl_rth, 0, NETLINK_GENERIC) < 0) { + fprintf(stderr, "Cannot open generic netlink socket\n"); + exit(1); + } + + genl_family = genl_resolve_family(&genl_rth, ILA_GENL_NAME); + if (genl_family < 0) + exit(1); + } + + if (argc < 1) + usage(); + + if (matches(*argv, "add") == 0) + return do_add(argc-1, argv+1); + if (matches(*argv, "delete") == 0) + return do_del(argc-1, argv+1); + if (matches(*argv, "list") == 0) + return do_list(argc-1, argv+1); + if (matches(*argv, "help") == 0) + usage(); + + fprintf(stderr, "Command \"%s\" is unknown, try \"ip ila help\".\n", + *argv); + exit(-1); +} From 73516e128a5a7dc481feaed5affa50e65d5c05db Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Aug 2016 13:34:55 -0700 Subject: [PATCH 365/513] ip6tnl: Support for fou encapsulation Signed-off-by: Tom Herbert --- ip/link_ip6tnl.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c index 89861c643..59162a336 100644 --- a/ip/link_ip6tnl.c +++ b/ip/link_ip6tnl.c @@ -37,6 +37,9 @@ static void print_usage(FILE *f) fprintf(f, " [ dev PHYS_DEV ] [ encaplimit ELIM ]\n"); fprintf(f, " [ hoplimit HLIM ] [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n"); fprintf(f, " [ dscp inherit ] [ fwmark inherit ]\n"); + fprintf(f, " [ noencap ] [ encap { fou | gue | none } ]\n"); + fprintf(f, " [ encap-sport PORT ] [ encap-dport PORT ]\n"); + fprintf(f, " [ [no]encap-csum ] [ [no]encap-csum6 ] [ [no]encap-remcsum ]\n"); fprintf(f, "\n"); fprintf(f, "Where: NAME := STRING\n"); fprintf(f, " ADDR := IPV6_ADDRESS\n"); @@ -82,6 +85,10 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, __u32 flags = 0; __u32 link = 0; __u8 proto = 0; + __u16 encaptype = 0; + __u16 encapflags = TUNNEL_ENCAP_FLAG_CSUM6; + __u16 encapsport = 0; + __u16 encapdport = 0; if (!(n->nlmsg_flags & NLM_F_CREATE)) { if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { @@ -182,7 +189,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, if (get_u8(&uval, *argv, 0)) invarg("invalid HLIM", *argv); hop_limit = uval; - } else if (matches(*argv, "encaplimit") == 0) { + } else if (strcmp(*argv, "encaplimit") == 0) { NEXT_ARG(); if (strcmp(*argv, "none") == 0) { flags |= IP6_TNL_F_IGN_ENCAP_LIMIT; @@ -236,6 +243,40 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, if (strcmp(*argv, "inherit") != 0) invarg("not inherit", *argv); flags |= IP6_TNL_F_USE_ORIG_FWMARK; + } else if (strcmp(*argv, "noencap") == 0) { + encaptype = TUNNEL_ENCAP_NONE; + } else if (strcmp(*argv, "encap") == 0) { + NEXT_ARG(); + if (strcmp(*argv, "fou") == 0) + encaptype = TUNNEL_ENCAP_FOU; + else if (strcmp(*argv, "gue") == 0) + encaptype = TUNNEL_ENCAP_GUE; + else if (strcmp(*argv, "none") == 0) + encaptype = TUNNEL_ENCAP_NONE; + else + invarg("Invalid encap type.", *argv); + } else if (strcmp(*argv, "encap-sport") == 0) { + NEXT_ARG(); + if (strcmp(*argv, "auto") == 0) + encapsport = 0; + else if (get_u16(&encapsport, *argv, 0)) + invarg("Invalid source port.", *argv); + } else if (strcmp(*argv, "encap-dport") == 0) { + NEXT_ARG(); + if (get_u16(&encapdport, *argv, 0)) + invarg("Invalid destination port.", *argv); + } else if (strcmp(*argv, "encap-csum") == 0) { + encapflags |= TUNNEL_ENCAP_FLAG_CSUM; + } else if (strcmp(*argv, "noencap-csum") == 0) { + encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM; + } else if (strcmp(*argv, "encap-udp6-csum") == 0) { + encapflags |= TUNNEL_ENCAP_FLAG_CSUM6; + } else if (strcmp(*argv, "noencap-udp6-csum") == 0) { + encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM6; + } else if (strcmp(*argv, "encap-remcsum") == 0) { + encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM; + } else if (strcmp(*argv, "noencap-remcsum") == 0) { + encapflags |= ~TUNNEL_ENCAP_FLAG_REMCSUM; } else usage(); argc--, argv++; @@ -250,6 +291,11 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, addattr32(n, 1024, IFLA_IPTUN_FLAGS, flags); addattr32(n, 1024, IFLA_IPTUN_LINK, link); + addattr16(n, 1024, IFLA_IPTUN_ENCAP_TYPE, encaptype); + addattr16(n, 1024, IFLA_IPTUN_ENCAP_FLAGS, encapflags); + addattr16(n, 1024, IFLA_IPTUN_ENCAP_SPORT, htons(encapsport)); + addattr16(n, 1024, IFLA_IPTUN_ENCAP_DPORT, htons(encapdport)); + return 0; } @@ -334,6 +380,50 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb if (flags & IP6_TNL_F_USE_ORIG_FWMARK) fprintf(f, "fwmark inherit "); + + if (tb[IFLA_IPTUN_ENCAP_TYPE] && + rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_TYPE]) != + TUNNEL_ENCAP_NONE) { + __u16 type = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_TYPE]); + __u16 flags = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_FLAGS]); + __u16 sport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_SPORT]); + __u16 dport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_DPORT]); + + fputs("encap ", f); + switch (type) { + case TUNNEL_ENCAP_FOU: + fputs("fou ", f); + break; + case TUNNEL_ENCAP_GUE: + fputs("gue ", f); + break; + default: + fputs("unknown ", f); + break; + } + + if (sport == 0) + fputs("encap-sport auto ", f); + else + fprintf(f, "encap-sport %u", ntohs(sport)); + + fprintf(f, "encap-dport %u ", ntohs(dport)); + + if (flags & TUNNEL_ENCAP_FLAG_CSUM) + fputs("encap-csum ", f); + else + fputs("noencap-csum ", f); + + if (flags & TUNNEL_ENCAP_FLAG_CSUM6) + fputs("encap-csum6 ", f); + else + fputs("noencap-csum6 ", f); + + if (flags & TUNNEL_ENCAP_FLAG_REMCSUM) + fputs("encap-remcsum ", f); + else + fputs("noencap-remcsum ", f); + } } static void ip6tunnel_print_help(struct link_util *lu, int argc, char **argv, From 0b2fbb7358db9d1087c509ecbe78e7390c144dff Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Aug 2016 13:34:56 -0700 Subject: [PATCH 366/513] gre6: Support for fou encapsulation Signed-off-by: Tom Herbert --- ip/link_gre.c | 2 +- ip/link_gre6.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/ip/link_gre.c b/ip/link_gre.c index 5dc4067bc..3b99e56f4 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -429,7 +429,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fputs("external ", f); if (tb[IFLA_GRE_ENCAP_TYPE] && - *(__u16 *)RTA_DATA(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) { + rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) { __u16 type = rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]); __u16 flags = rta_getattr_u16(tb[IFLA_GRE_ENCAP_FLAGS]); __u16 sport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_SPORT]); diff --git a/ip/link_gre6.c b/ip/link_gre6.c index 6767ef64e..d00db1f89 100644 --- a/ip/link_gre6.c +++ b/ip/link_gre6.c @@ -38,6 +38,9 @@ static void print_usage(FILE *f) fprintf(f, " [ hoplimit TTL ] [ encaplimit ELIM ]\n"); fprintf(f, " [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n"); fprintf(f, " [ dscp inherit ] [ dev PHYS_DEV ]\n"); + fprintf(f, " [ noencap ] [ encap { fou | gue | none } ]\n"); + fprintf(f, " [ encap-sport PORT ] [ encap-dport PORT ]\n"); + fprintf(f, " [ [no]encap-csum ] [ [no]encap-csum6 ] [ [no]encap-remcsum ]\n"); fprintf(f, "\n"); fprintf(f, "Where: NAME := STRING\n"); fprintf(f, " ADDR := IPV6_ADDRESS\n"); @@ -86,6 +89,10 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, unsigned int flags = 0; __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT; __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; + __u16 encaptype = 0; + __u16 encapflags = TUNNEL_ENCAP_FLAG_CSUM6; + __u16 encapsport = 0; + __u16 encapdport = 0; int len; if (!(n->nlmsg_flags & NLM_F_CREATE)) { @@ -146,6 +153,18 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, if (greinfo[IFLA_GRE_FLAGS]) flags = rta_getattr_u32(greinfo[IFLA_GRE_FLAGS]); + + if (greinfo[IFLA_GRE_ENCAP_TYPE]) + encaptype = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_TYPE]); + + if (greinfo[IFLA_GRE_ENCAP_FLAGS]) + encapflags = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_FLAGS]); + + if (greinfo[IFLA_GRE_ENCAP_SPORT]) + encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]); + + if (greinfo[IFLA_GRE_ENCAP_DPORT]) + encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]); } while (argc > 0) { @@ -277,6 +296,40 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, if (strcmp(*argv, "inherit") != 0) invarg("not inherit", *argv); flags |= IP6_TNL_F_RCV_DSCP_COPY; + } else if (strcmp(*argv, "noencap") == 0) { + encaptype = TUNNEL_ENCAP_NONE; + } else if (strcmp(*argv, "encap") == 0) { + NEXT_ARG(); + if (strcmp(*argv, "fou") == 0) + encaptype = TUNNEL_ENCAP_FOU; + else if (strcmp(*argv, "gue") == 0) + encaptype = TUNNEL_ENCAP_GUE; + else if (strcmp(*argv, "none") == 0) + encaptype = TUNNEL_ENCAP_NONE; + else + invarg("Invalid encap type.", *argv); + } else if (strcmp(*argv, "encap-sport") == 0) { + NEXT_ARG(); + if (strcmp(*argv, "auto") == 0) + encapsport = 0; + else if (get_u16(&encapsport, *argv, 0)) + invarg("Invalid source port.", *argv); + } else if (strcmp(*argv, "encap-dport") == 0) { + NEXT_ARG(); + if (get_u16(&encapdport, *argv, 0)) + invarg("Invalid destination port.", *argv); + } else if (strcmp(*argv, "encap-csum") == 0) { + encapflags |= TUNNEL_ENCAP_FLAG_CSUM; + } else if (strcmp(*argv, "noencap-csum") == 0) { + encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM; + } else if (strcmp(*argv, "encap-udp6-csum") == 0) { + encapflags |= TUNNEL_ENCAP_FLAG_CSUM6; + } else if (strcmp(*argv, "noencap-udp6-csum") == 0) { + encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM6; + } else if (strcmp(*argv, "encap-remcsum") == 0) { + encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM; + } else if (strcmp(*argv, "noencap-remcsum") == 0) { + encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM; } else usage(); argc--; argv++; @@ -295,6 +348,11 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4); addattr_l(n, 1024, IFLA_GRE_FLAGS, &flowinfo, 4); + addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype); + addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags); + addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport)); + addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport)); + return 0; } @@ -393,6 +451,49 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fputs("icsum ", f); if (oflags & GRE_CSUM) fputs("ocsum ", f); + + if (tb[IFLA_GRE_ENCAP_TYPE] && + rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) { + __u16 type = rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]); + __u16 flags = rta_getattr_u16(tb[IFLA_GRE_ENCAP_FLAGS]); + __u16 sport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_SPORT]); + __u16 dport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_DPORT]); + + fputs("encap ", f); + switch (type) { + case TUNNEL_ENCAP_FOU: + fputs("fou ", f); + break; + case TUNNEL_ENCAP_GUE: + fputs("gue ", f); + break; + default: + fputs("unknown ", f); + break; + } + + if (sport == 0) + fputs("encap-sport auto ", f); + else + fprintf(f, "encap-sport %u", ntohs(sport)); + + fprintf(f, "encap-dport %u ", ntohs(dport)); + + if (flags & TUNNEL_ENCAP_FLAG_CSUM) + fputs("encap-csum ", f); + else + fputs("noencap-csum ", f); + + if (flags & TUNNEL_ENCAP_FLAG_CSUM6) + fputs("encap-csum6 ", f); + else + fputs("noencap-csum6 ", f); + + if (flags & TUNNEL_ENCAP_FLAG_REMCSUM) + fputs("encap-remcsum ", f); + else + fputs("noencap-remcsum ", f); + } } static void gre_print_help(struct link_util *lu, int argc, char **argv, From 8bd31d8db510bb7914428783c4ce8b592700d7ae Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 4 Aug 2016 13:34:57 -0700 Subject: [PATCH 367/513] fou: Allowing configuring IPv6 listener Signed-off-by: Tom Herbert --- ip/ipfou.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ip/ipfou.c b/ip/ipfou.c index 2a6ae1755..0673d11ff 100644 --- a/ip/ipfou.c +++ b/ip/ipfou.c @@ -25,8 +25,9 @@ static void usage(void) { - fprintf(stderr, "Usage: ip fou add port PORT { ipproto PROTO | gue }\n"); - fprintf(stderr, " ip fou del port PORT\n"); + fprintf(stderr, "Usage: ip fou add port PORT " + "{ ipproto PROTO | gue } [ -6 ]\n"); + fprintf(stderr, " ip fou del port PORT [ -6 ]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where: PROTO { ipproto-name | 1..255 }\n"); fprintf(stderr, " PORT { 1..65535 }\n"); @@ -50,6 +51,7 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n, __u8 ipproto, type; bool gue_set = false; int ipproto_set = 0; + unsigned short family = AF_INET; while (argc > 0) { if (!matches(*argv, "port")) { @@ -71,6 +73,8 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n, ipproto_set = 1; } else if (!matches(*argv, "gue")) { gue_set = true; + } else if (!matches(*argv, "-6")) { + family = AF_INET6; } else { fprintf(stderr, "fou: unknown command \"%s\"?\n", *argv); usage(); @@ -98,6 +102,7 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n, addattr16(n, 1024, FOU_ATTR_PORT, port); addattr8(n, 1024, FOU_ATTR_TYPE, type); + addattr16(n, 1024, FOU_ATTR_AF, family); if (ipproto_set) addattr8(n, 1024, FOU_ATTR_IPPROTO, ipproto); From 7e33b093318cd9281e3df3572ed64b57e12ba642 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 12 Aug 2016 01:17:12 +0200 Subject: [PATCH 368/513] man: ip-link.8: Document missing geneve options This adds missing documentation of geneve type options: - dstport - external - udpcsum - udp6zerocsumtx - udp6zerocsumrx The bits for the last three was just copy and pasted from vxlan section. Signed-off-by: Phil Sutter --- man/man8/ip-link.8.in | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index f4782ee5b..58247ced4 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -801,6 +801,16 @@ the following additional arguments are supported: .BI tos " TOS " ] [ .BI flowlabel " FLOWLABEL " +] [ +.BI dstport " PORT" +] [ +.RB [ no ] external +] [ +.RB [ no ] udpcsum +] [ +.RB [ no ] udp6zerocsumtx +] [ +.RB [ no ] udp6zerocsumrx ] .in +8 @@ -824,6 +834,32 @@ the following additional arguments are supported: .BI flowlabel " FLOWLABEL" - specifies the flow label to use in outgoing packets. +.sp +.BI dstport " PORT" +- select a destination port other than the default of 6081. + +.sp +.RB [ no ] external +- make this tunnel externally controlled (or not, which is the default). This +flag is mutually exclusive with the +.BR id , +.BR remote , +.BR ttl , +.BR tos " and " flowlabel +options. + +.sp +.RB [ no ] udpcsum +- specifies if UDP checksum is calculated for transmitted packets over IPv4. + +.sp +.RB [ no ] udp6zerocsumtx +- skip UDP checksum calculation for transmitted packets over IPv6. + +.sp +.RB [ no ] udp6zerocsumrx +- allow incoming UDP packets over IPv6 with zero checksum field. + .in -8 .TP From 2d01b393f4fcb005586b74741da70ffbe5f77970 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Mon, 15 Aug 2016 16:30:22 -0700 Subject: [PATCH 369/513] ipila: Fixed unitialized variables Initialize locator and locator_match to zero and only do addattr if they have been set. Signed-off-by: Tom Herbert --- ip/ipila.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ip/ipila.c b/ip/ipila.c index c30bdbf16..57f8c79ba 100644 --- a/ip/ipila.c +++ b/ip/ipila.c @@ -149,8 +149,8 @@ static int do_list(int argc, char **argv) static int ila_parse_opt(int argc, char **argv, struct nlmsghdr *n, bool adding) { - __u64 locator; - __u64 locator_match; + __u64 locator = 0; + __u64 locator_match = 0; int ifindex = 0; bool loc_set = false; bool loc_match_set = false; @@ -202,8 +202,11 @@ static int ila_parse_opt(int argc, char **argv, struct nlmsghdr *n, } } - addattr64(n, 1024, ILA_ATTR_LOCATOR_MATCH, locator_match); - addattr64(n, 1024, ILA_ATTR_LOCATOR, locator); + if (loc_match_set) + addattr64(n, 1024, ILA_ATTR_LOCATOR_MATCH, locator_match); + + if (loc_set) + addattr64(n, 1024, ILA_ATTR_LOCATOR, locator); if (ifindex_set) addattr32(n, 1024, ILA_ATTR_IFINDEX, ifindex); From ff77557957f75323409848cb2634e80d61edac3c Mon Sep 17 00:00:00 2001 From: Richard Alpe Date: Mon, 15 Aug 2016 10:24:31 +0200 Subject: [PATCH 370/513] tipc: fix UDP bearer synopsis Local ip is not required to identify a UDP bearer and shouldn't be passed to bearer disable, set or get. In this patch we remove the localip entry from the synopsis of these functions. Signed-off-by: Richard Alpe --- man/man8/tipc-bearer.8 | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/man/man8/tipc-bearer.8 b/man/man8/tipc-bearer.8 index 50a1ed245..846f1db0c 100644 --- a/man/man8/tipc-bearer.8 +++ b/man/man8/tipc-bearer.8 @@ -39,14 +39,12 @@ tipc-bearer \- show or modify TIPC bearers .B tipc bearer disable media .br .RB "{ { " eth " | " ib " } " device -.IR DEVICE +.IR "DEVICE " } .RB "|" .br .RB "{ " udp .B name -.IR NAME -.B localip -.IR LOCALIP " } }" +.IR NAME " }" .br .ti -8 @@ -65,9 +63,7 @@ tipc-bearer \- show or modify TIPC bearers .br .RB "{ " udp .B name -.IR NAME -.B localip -.IR LOCALIP " } }" +.IR NAME " }" .br .ti -8 @@ -80,9 +76,7 @@ tipc-bearer \- show or modify TIPC bearers .br .RB "{ " udp .B name -.IR NAME -.B localip -.IR LOCALIP " } }" +.IR NAME " }" .br .ti -8 From 50afc4dbf8724a43f90265d7ee12dc62565f2936 Mon Sep 17 00:00:00 2001 From: Richard Alpe Date: Mon, 15 Aug 2016 10:24:32 +0200 Subject: [PATCH 371/513] tipc: refactor bearer identification Introduce a generic function (nl_add_bearer_name()) that identifies a bearer and adds it to an existing netlink message. This reduces code complexity and makes the code a little bit easier to maintain. Signed-off-by: Richard Alpe --- tipc/bearer.c | 313 +++++++++++++++++--------------------------------- tipc/cmdl.h | 6 + 2 files changed, 114 insertions(+), 205 deletions(-) diff --git a/tipc/bearer.c b/tipc/bearer.c index 30b54d9fe..05dabe696 100644 --- a/tipc/bearer.c +++ b/tipc/bearer.c @@ -29,7 +29,7 @@ static void _print_bearer_opts(void) { fprintf(stderr, - "\nOPTIONS\n" + "OPTIONS\n" " priority - Bearer link priority\n" " tolerance - Bearer link tolerance\n" " window - Bearer link window\n"); @@ -44,43 +44,27 @@ static void _print_bearer_media(void) " eth - Ethernet\n"); } -static void cmd_bearer_enable_l2_help(struct cmdl *cmdl) +static void cmd_bearer_enable_l2_help(struct cmdl *cmdl, char *media) { fprintf(stderr, - "Usage: %s bearer enable media MEDIA device DEVICE [OPTIONS]\n" + "Usage: %s bearer enable media %s device DEVICE [OPTIONS]\n" "\nOPTIONS\n" " domain DOMAIN - Discovery domain\n" " priority PRIORITY - Bearer priority\n", - cmdl->argv[0]); + cmdl->argv[0], media); } -static void cmd_bearer_enable_udp_help(struct cmdl *cmdl) +static void cmd_bearer_enable_udp_help(struct cmdl *cmdl, char *media) { fprintf(stderr, - "Usage: %s bearer enable media udp name NAME localip IP [OPTIONS]\n" + "Usage: %s bearer enable media %s name NAME localip IP [OPTIONS]\n" "\nOPTIONS\n" " domain DOMAIN - Discovery domain\n" " priority PRIORITY - Bearer priority\n" " localport PORT - Local UDP port (default 6118)\n" " remoteip IP - Remote IP address\n" " remoteport IP - Remote UDP port (default 6118)\n", - cmdl->argv[0]); -} - -static int enable_l2_bearer(struct nlmsghdr *nlh, struct opt *opts, - struct cmdl *cmdl) -{ - struct opt *opt; - char id[TIPC_MAX_BEARER_NAME]; - - if (!(opt = get_opt(opts, "device"))) { - fprintf(stderr, "error: missing bearer device\n"); - return -EINVAL; - } - snprintf(id, sizeof(id), "eth:%s", opt->val); - mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id); - - return 0; + cmdl->argv[0], media); } static int get_netid_cb(const struct nlmsghdr *nlh, void *data) @@ -123,8 +107,8 @@ static int generate_multicast(short af, char *buf, int bufsize) return 0; } -static int enable_udp_bearer(struct nlmsghdr *nlh, struct opt *opts, - struct cmdl *cmdl) +static int nl_add_udp_enable_opts(struct nlmsghdr *nlh, struct opt *opts, + struct cmdl *cmdl) { int err; struct opt *opt; @@ -134,7 +118,6 @@ static int enable_udp_bearer(struct nlmsghdr *nlh, struct opt *opts, char *remport = "6118"; char *locip = NULL; char *remip = NULL; - char name[TIPC_MAX_BEARER_NAME]; struct addrinfo *loc = NULL; struct addrinfo *rem = NULL; struct addrinfo hints = { @@ -142,22 +125,9 @@ static int enable_udp_bearer(struct nlmsghdr *nlh, struct opt *opts, .ai_socktype = SOCK_DGRAM }; - if (help_flag) { - cmd_bearer_enable_udp_help(cmdl); - /* TODO find a better error code? */ - return -EINVAL; - } - - if (!(opt = get_opt(opts, "name"))) { - fprintf(stderr, "error, udp bearer name missing\n"); - cmd_bearer_enable_udp_help(cmdl); - return -EINVAL; - } - snprintf(name, sizeof(name), "udp:%s", opt->val); - if (!(opt = get_opt(opts, "localip"))) { fprintf(stderr, "error, udp bearer localip missing\n"); - cmd_bearer_enable_udp_help(cmdl); + cmd_bearer_enable_udp_help(cmdl, "udp"); return -EINVAL; } locip = opt->val; @@ -197,8 +167,6 @@ static int enable_udp_bearer(struct nlmsghdr *nlh, struct opt *opts, return -EINVAL; } - mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, name); - nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_UDP_OPTS); mnl_attr_put(nlh, TIPC_NLA_UDP_LOCAL, loc->ai_addrlen, loc->ai_addr); mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, rem->ai_addrlen, rem->ai_addr); @@ -210,6 +178,50 @@ static int enable_udp_bearer(struct nlmsghdr *nlh, struct opt *opts, return 0; } +static int nl_add_bearer_name(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, struct opt *opts, + struct tipc_sup_media sup_media[]) +{ + char id[TIPC_MAX_BEARER_NAME]; + char *media; + char *identifier; + struct opt *opt; + struct tipc_sup_media *entry; + + if (!(opt = get_opt(opts, "media"))) { + if (help_flag) + (cmd->help)(cmdl); + else + fprintf(stderr, "error, missing bearer media\n"); + return -EINVAL; + } + media = opt->val; + + for (entry = sup_media; entry->media; entry++) { + if (strcmp(entry->media, media)) + continue; + + if (!(opt = get_opt(opts, entry->identifier))) { + if (help_flag) + (entry->help)(cmdl, media); + else + fprintf(stderr, "error, missing bearer %s\n", + entry->identifier); + return -EINVAL; + } + + identifier = opt->val; + snprintf(id, sizeof(id), "%s:%s", media, identifier); + mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id); + + return 0; + } + + fprintf(stderr, "error, invalid media type %s\n", media); + + return -EINVAL; +} + static void cmd_bearer_enable_help(struct cmdl *cmdl) { fprintf(stderr, @@ -228,7 +240,6 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd, struct opt *opt; struct nlattr *nest; char buf[MNL_SOCKET_BUFFER_SIZE]; - char *media; struct opt opts[] = { { "device", NULL }, { "domain", NULL }, @@ -241,6 +252,12 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd, { "remoteport", NULL }, { NULL } }; + struct tipc_sup_media sup_media[] = { + { "udp", "name", cmd_bearer_enable_udp_help}, + { "eth", "device", cmd_bearer_enable_l2_help }, + { "ib", "device", cmd_bearer_enable_l2_help }, + { NULL, }, + }; if (parse_opts(opts, cmdl) < 0) { if (help_flag) @@ -248,15 +265,6 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - if (!(opt = get_opt(opts, "media"))) { - if (help_flag) - (cmd->help)(cmdl); - else - fprintf(stderr, "error, missing bearer media\n"); - return -EINVAL; - } - media = opt->val; - if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ENABLE))) { fprintf(stderr, "error: message initialisation failed\n"); return -1; @@ -274,72 +282,31 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd, mnl_attr_nest_end(nlh, props); } - if (strcmp(media, "udp") == 0) { - if (help_flag) { - cmd_bearer_enable_udp_help(cmdl); - return -EINVAL; - } - if ((err = enable_udp_bearer(nlh, opts, cmdl))) - return err; - } else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) { - if (help_flag) { - cmd_bearer_enable_l2_help(cmdl); - return -EINVAL; - } - if ((err = enable_l2_bearer(nlh, opts, cmdl))) + err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media); + if (err) + return err; + + opt = get_opt(opts, "media"); + if (strcmp(opt->val, "udp") == 0) { + err = nl_add_udp_enable_opts(nlh, opts, cmdl); + if (err) return err; - } else { - fprintf(stderr, "error, invalid media type \"%s\"\n", media); - return -EINVAL; } - mnl_attr_nest_end(nlh, nest); return msg_doit(nlh, NULL, NULL); } -static int add_l2_bearer(struct nlmsghdr *nlh, struct opt *opts) -{ - struct opt *opt; - char id[TIPC_MAX_BEARER_NAME]; - - if (!(opt = get_opt(opts, "device"))) { - fprintf(stderr, "error: missing bearer device\n"); - return -EINVAL; - } - snprintf(id, sizeof(id), "eth:%s", opt->val); - - mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id); - - return 0; -} - -static int add_udp_bearer(struct nlmsghdr *nlh, struct opt *opts) +static void cmd_bearer_disable_l2_help(struct cmdl *cmdl, char *media) { - struct opt *opt; - char id[TIPC_MAX_BEARER_NAME]; - - if (!(opt = get_opt(opts, "name"))) { - fprintf(stderr, "error: missing bearer name\n"); - return -EINVAL; - } - snprintf(id, sizeof(id), "udp:%s", opt->val); - - mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id); - - return 0; -} - -static void cmd_bearer_disable_l2_help(struct cmdl *cmdl) -{ - fprintf(stderr, "Usage: %s bearer disable media udp device DEVICE\n", - cmdl->argv[0]); + fprintf(stderr, "Usage: %s bearer disable media %s device DEVICE\n", + cmdl->argv[0], media); } -static void cmd_bearer_disable_udp_help(struct cmdl *cmdl) +static void cmd_bearer_disable_udp_help(struct cmdl *cmdl, char *media) { - fprintf(stderr, "Usage: %s bearer disable media udp name NAME\n", - cmdl->argv[0]); + fprintf(stderr, "Usage: %s bearer disable media %s name NAME\n", + cmdl->argv[0], media); } static void cmd_bearer_disable_help(struct cmdl *cmdl) @@ -353,16 +320,20 @@ static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { int err; - char *media; char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *nest; - struct opt *opt; struct opt opts[] = { { "device", NULL }, { "name", NULL }, { "media", NULL }, { NULL } }; + struct tipc_sup_media sup_media[] = { + { "udp", "name", cmd_bearer_disable_udp_help}, + { "eth", "device", cmd_bearer_disable_l2_help }, + { "ib", "device", cmd_bearer_disable_l2_help }, + { NULL, }, + }; if (parse_opts(opts, cmdl) < 0) { if (help_flag) @@ -370,40 +341,15 @@ static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - if (!(opt = get_opt(opts, "media"))) { - if (help_flag) - (cmd->help)(cmdl); - else - fprintf(stderr, "error, missing bearer media\n"); - return -EINVAL; - } - media = opt->val; - if (!(nlh = msg_init(buf, TIPC_NL_BEARER_DISABLE))) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER); - - if (strcmp(media, "udp") == 0) { - if (help_flag) { - cmd_bearer_disable_udp_help(cmdl); - return -EINVAL; - } - if ((err = add_udp_bearer(nlh, opts))) - return err; - } else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) { - if (help_flag) { - cmd_bearer_disable_l2_help(cmdl); - return -EINVAL; - } - if ((err = add_l2_bearer(nlh, opts))) - return err; - } else { - fprintf(stderr, "error, invalid media type \"%s\"\n", media); - return -EINVAL; - } + err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media); + if (err) + return err; mnl_attr_nest_end(nlh, nest); return msg_doit(nlh, NULL, NULL); @@ -418,10 +364,10 @@ static void cmd_bearer_set_help(struct cmdl *cmdl) _print_bearer_media(); } -static void cmd_bearer_set_udp_help(struct cmdl *cmdl) +static void cmd_bearer_set_udp_help(struct cmdl *cmdl, char *media) { - fprintf(stderr, "Usage: %s bearer set OPTION media udp name NAME\n\n", - cmdl->argv[0]); + fprintf(stderr, "Usage: %s bearer set OPTION media %s name NAME\n\n", + cmdl->argv[0], media); _print_bearer_opts(); } @@ -439,17 +385,21 @@ static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, int err; int val; int prop; - char *media; char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *props; struct nlattr *attrs; - struct opt *opt; struct opt opts[] = { { "device", NULL }, { "media", NULL }, { "name", NULL }, { NULL } }; + struct tipc_sup_media sup_media[] = { + { "udp", "name", cmd_bearer_set_udp_help}, + { "eth", "device", cmd_bearer_set_l2_help }, + { "ib", "device", cmd_bearer_set_l2_help }, + { NULL, }, + }; if (strcmp(cmd->cmd, "priority") == 0) prop = TIPC_NLA_PROP_PRIO; @@ -460,11 +410,6 @@ static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, else return -EINVAL; - if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; - } - if (cmdl->optind >= cmdl->argc) { fprintf(stderr, "error, missing value\n"); return -EINVAL; @@ -484,30 +429,10 @@ static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, mnl_attr_put_u32(nlh, prop, val); mnl_attr_nest_end(nlh, props); - if (!(opt = get_opt(opts, "media"))) { - fprintf(stderr, "error, missing media\n"); - return -EINVAL; - } - media = opt->val; + err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media); + if (err) + return err; - if (strcmp(media, "udp") == 0) { - if (help_flag) { - cmd_bearer_set_udp_help(cmdl); - return -EINVAL; - } - if ((err = add_udp_bearer(nlh, opts))) - return err; - } else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) { - if (help_flag) { - cmd_bearer_set_l2_help(cmdl, media); - return -EINVAL; - } - if ((err = add_l2_bearer(nlh, opts))) - return err; - } else { - fprintf(stderr, "error, invalid media type \"%s\"\n", media); - return -EINVAL; - } mnl_attr_nest_end(nlh, attrs); return msg_doit(nlh, NULL, NULL); @@ -534,17 +459,17 @@ static void cmd_bearer_get_help(struct cmdl *cmdl) _print_bearer_media(); } -static void cmd_bearer_get_udp_help(struct cmdl *cmdl) +static void cmd_bearer_get_udp_help(struct cmdl *cmdl, char *media) { - fprintf(stderr, "Usage: %s bearer get OPTION media udp name NAME\n\n", - cmdl->argv[0]); + fprintf(stderr, "Usage: %s bearer get OPTION media %s name NAME\n\n", + cmdl->argv[0], media); _print_bearer_opts(); } static void cmd_bearer_get_l2_help(struct cmdl *cmdl, char *media) { fprintf(stderr, - "Usage: %s bearer get [OPTION]... media %s device DEVICE\n", + "Usage: %s bearer get OPTION media %s device DEVICE\n", cmdl->argv[0], media); _print_bearer_opts(); } @@ -579,16 +504,20 @@ static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, { int err; int prop; - char *media; char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *attrs; - struct opt *opt; struct opt opts[] = { { "device", NULL }, { "media", NULL }, { "name", NULL }, { NULL } }; + struct tipc_sup_media sup_media[] = { + { "udp", "name", cmd_bearer_get_udp_help}, + { "eth", "device", cmd_bearer_get_l2_help }, + { "ib", "device", cmd_bearer_get_l2_help }, + { NULL, }, + }; if (strcmp(cmd->cmd, "priority") == 0) prop = TIPC_NLA_PROP_PRIO; @@ -599,11 +528,6 @@ static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, else return -EINVAL; - if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; - } - if (parse_opts(opts, cmdl) < 0) return -EINVAL; @@ -612,31 +536,10 @@ static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, return -1; } - if (!(opt = get_opt(opts, "media"))) { - fprintf(stderr, "error, missing media\n"); - return -EINVAL; - } - media = opt->val; - attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER); - if (strcmp(media, "udp") == 0) { - if (help_flag) { - cmd_bearer_get_udp_help(cmdl); - return -EINVAL; - } - if ((err = add_udp_bearer(nlh, opts))) - return err; - } else if ((strcmp(media, "eth") == 0) || (strcmp(media, "udp") == 0)) { - if (help_flag) { - cmd_bearer_get_l2_help(cmdl, media); - return -EINVAL; - } - if ((err = add_l2_bearer(nlh, opts))) - return err; - } else { - fprintf(stderr, "error, invalid media type \"%s\"\n", media); - return -EINVAL; - } + err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media); + if (err) + return err; mnl_attr_nest_end(nlh, attrs); return msg_doit(nlh, bearer_get_cb, &prop); diff --git a/tipc/cmdl.h b/tipc/cmdl.h index 9f2666f80..d4795cfe0 100644 --- a/tipc/cmdl.h +++ b/tipc/cmdl.h @@ -22,6 +22,12 @@ struct cmdl { char **argv; }; +struct tipc_sup_media { + char *media; + char *identifier; + void (*help)(struct cmdl *cmdl, char *media); +}; + struct cmd { const char *cmd; int (*func)(struct nlmsghdr *nlh, const struct cmd *cmd, From 08c0466b11b79107740226052a27279034eb3768 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 16 Aug 2016 16:08:38 +0200 Subject: [PATCH 372/513] ip-link: add missing {min,max}_tx_rate to help text These vf options are described in man page already, they're just missing in help output. Signed-off-by: Phil Sutter --- ip/iplink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ip/iplink.c b/ip/iplink.c index f9a7e0909..6b1db18a6 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -79,6 +79,8 @@ void iplink_usage(void) fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n"); fprintf(stderr, " [ rate TXRATE ]\n"); + fprintf(stderr, " [ max_tx_rate TXRATE ]\n"); + fprintf(stderr, " [ min_tx_rate TXRATE ]\n"); fprintf(stderr, " [ spoofchk { on | off} ]\n"); fprintf(stderr, " [ query_rss { on | off} ]\n"); From 2b68cb77cde32f5cba5f984e15fc402758edea76 Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Tue, 16 Aug 2016 16:26:55 +0200 Subject: [PATCH 373/513] libgenl: introduce genl_init_handle All users of genl have the same code to open a genl socket and resolve the family for their specific protocol. Introduce a helper to initialize the handle, and use it in all the genl code. Signed-off-by: Sabrina Dubroca --- include/libgenl.h | 2 ++ ip/ipfou.c | 12 ++---------- ip/ipila.c | 12 ++---------- ip/ipl2tp.c | 12 ++---------- ip/ipmacsec.c | 18 ++---------------- ip/tcp_metrics.c | 14 +++----------- lib/libgenl.c | 18 ++++++++++++++++++ 7 files changed, 31 insertions(+), 57 deletions(-) diff --git a/include/libgenl.h b/include/libgenl.h index 9db4bafd5..2dbb4b36a 100644 --- a/include/libgenl.h +++ b/include/libgenl.h @@ -21,5 +21,7 @@ struct { \ } extern int genl_resolve_family(struct rtnl_handle *grth, const char *family); +extern int genl_init_handle(struct rtnl_handle *grth, const char *family, + int *genl_family); #endif /* __LIBGENL_H__ */ diff --git a/ip/ipfou.c b/ip/ipfou.c index 0673d11ff..9f0911215 100644 --- a/ip/ipfou.c +++ b/ip/ipfou.c @@ -136,16 +136,8 @@ static int do_del(int argc, char **argv) int do_ipfou(int argc, char **argv) { - if (genl_family < 0) { - if (rtnl_open_byproto(&genl_rth, 0, NETLINK_GENERIC) < 0) { - fprintf(stderr, "Cannot open generic netlink socket\n"); - exit(1); - } - - genl_family = genl_resolve_family(&genl_rth, FOU_GENL_NAME); - if (genl_family < 0) - exit(1); - } + if (genl_init_handle(&genl_rth, FOU_GENL_NAME, &genl_family)) + exit(1); if (argc < 1) usage(); diff --git a/ip/ipila.c b/ip/ipila.c index 57f8c79ba..d75c46297 100644 --- a/ip/ipila.c +++ b/ip/ipila.c @@ -240,16 +240,8 @@ static int do_del(int argc, char **argv) int do_ipila(int argc, char **argv) { - if (genl_family < 0) { - if (rtnl_open_byproto(&genl_rth, 0, NETLINK_GENERIC) < 0) { - fprintf(stderr, "Cannot open generic netlink socket\n"); - exit(1); - } - - genl_family = genl_resolve_family(&genl_rth, ILA_GENL_NAME); - if (genl_family < 0) - exit(1); - } + if (genl_init_handle(&genl_rth, ILA_GENL_NAME, &genl_family)) + exit(1); if (argc < 1) usage(); diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index 9ebda135e..d3338acec 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -767,16 +767,8 @@ int do_ipl2tp(int argc, char **argv) if (argc < 1 || !matches(*argv, "help")) usage(); - if (genl_family < 0) { - if (rtnl_open_byproto(&genl_rth, 0, NETLINK_GENERIC) < 0) { - fprintf(stderr, "Cannot open generic netlink socket\n"); - exit(1); - } - - genl_family = genl_resolve_family(&genl_rth, L2TP_GENL_NAME); - if (genl_family < 0) - exit(1); - } + if (genl_init_handle(&genl_rth, L2TP_GENL_NAME, &genl_family)) + exit(1); if (matches(*argv, "add") == 0) return do_add(argc-1, argv+1); diff --git a/ip/ipmacsec.c b/ip/ipmacsec.c index 329be00fb..9eabfe241 100644 --- a/ip/ipmacsec.c +++ b/ip/ipmacsec.c @@ -79,21 +79,6 @@ static int genl_family = -1; _cmd, _flags) -static void init_genl(void) -{ - if (genl_family >= 0) - return; - - if (rtnl_open_byproto(&genl_rth, 0, NETLINK_GENERIC) < 0) { - fprintf(stderr, "Cannot open generic netlink socket\n"); - exit(1); - } - - genl_family = genl_resolve_family(&genl_rth, MACSEC_GENL_NAME); - if (genl_family < 0) - exit(1); -} - static void ipmacsec_usage(void) { fprintf(stderr, "Usage: ip macsec add DEV tx sa { 0..3 } [ OPTS ] key ID KEY\n"); @@ -1001,7 +986,8 @@ static int do_show(int argc, char **argv) int do_ipmacsec(int argc, char **argv) { - init_genl(); + if (genl_init_handle(&genl_rth, MACSEC_GENL_NAME, &genl_family)) + exit(1); if (argc < 1) ipmacsec_usage(); diff --git a/ip/tcp_metrics.c b/ip/tcp_metrics.c index ac2613a0a..8972acd05 100644 --- a/ip/tcp_metrics.c +++ b/ip/tcp_metrics.c @@ -398,17 +398,9 @@ static int tcpm_do_cmd(int cmd, int argc, char **argv) ack = 0; } - if (genl_family < 0) { - if (rtnl_open_byproto(&grth, 0, NETLINK_GENERIC) < 0) { - fprintf(stderr, "Cannot open generic netlink socket\n"); - exit(1); - } - genl_family = genl_resolve_family(&grth, - TCP_METRICS_GENL_NAME); - if (genl_family < 0) - exit(1); - req.n.nlmsg_type = genl_family; - } + if (genl_init_handle(&grth, TCP_METRICS_GENL_NAME, &genl_family)) + exit(1); + req.n.nlmsg_type = genl_family; if (!(cmd & CMD_FLUSH) && (atype >= 0 || (cmd & CMD_DEL))) { if (ack) diff --git a/lib/libgenl.c b/lib/libgenl.c index a1a37a440..50d2d9217 100644 --- a/lib/libgenl.c +++ b/lib/libgenl.c @@ -60,3 +60,21 @@ int genl_resolve_family(struct rtnl_handle *grth, const char *family) return genl_parse_getfamily(&req.n); } + +int genl_init_handle(struct rtnl_handle *grth, const char *family, + int *genl_family) +{ + if (*genl_family >= 0) + return 0; + + if (rtnl_open_byproto(grth, 0, NETLINK_GENERIC) < 0) { + fprintf(stderr, "Cannot open generic netlink socket\n"); + return -1; + } + + *genl_family = genl_resolve_family(grth, family); + if (*genl_family < 0) + return -1; + + return 0; +} From 688f9aa4f24ffac148f6b4127602f10a7837d4ba Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Tue, 16 Aug 2016 16:26:56 +0200 Subject: [PATCH 374/513] macsec: show usage even if the module is not available Currently, the `ip macsec` command tries to initialize a genl context even when we just want to see the help for the command, which doesn't require to talk to the kernel at all. Delay genl initialization, which can fail if the module isn't loaded, until the point where we will actually need it. Fixes: b26fc590ce62 ("ip: add MACsec support") Signed-off-by: Sabrina Dubroca --- ip/ipmacsec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ip/ipmacsec.c b/ip/ipmacsec.c index 9eabfe241..6bd1f54fb 100644 --- a/ip/ipmacsec.c +++ b/ip/ipmacsec.c @@ -986,15 +986,15 @@ static int do_show(int argc, char **argv) int do_ipmacsec(int argc, char **argv) { - if (genl_init_handle(&genl_rth, MACSEC_GENL_NAME, &genl_family)) - exit(1); - if (argc < 1) ipmacsec_usage(); if (matches(*argv, "help") == 0) ipmacsec_usage(); + if (genl_init_handle(&genl_rth, MACSEC_GENL_NAME, &genl_family)) + exit(1); + if (matches(*argv, "show") == 0) return do_show(argc-1, argv+1); From d240a0e174d54ae7613fd3034e281123968fdd9b Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Tue, 16 Aug 2016 16:26:57 +0200 Subject: [PATCH 375/513] fou: show usage even if the module is not available Currently, the `ip fou` command tries to initialize a genl context even when we just want to see the help for the command, which doesn't require to talk to the kernel at all. Delay genl initialization, which can fail if the module isn't loaded, until the point where we will actually need it. Fixes: 6928747b6e79 ("ip fou: Support to configure foo-over-udp RX") Signed-off-by: Sabrina Dubroca --- ip/ipfou.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ip/ipfou.c b/ip/ipfou.c index 9f0911215..00dbe1507 100644 --- a/ip/ipfou.c +++ b/ip/ipfou.c @@ -136,19 +136,19 @@ static int do_del(int argc, char **argv) int do_ipfou(int argc, char **argv) { - if (genl_init_handle(&genl_rth, FOU_GENL_NAME, &genl_family)) - exit(1); - if (argc < 1) usage(); + if (matches(*argv, "help") == 0) + usage(); + + if (genl_init_handle(&genl_rth, FOU_GENL_NAME, &genl_family)) + exit(1); + if (matches(*argv, "add") == 0) return do_add(argc-1, argv+1); if (matches(*argv, "delete") == 0) return do_del(argc-1, argv+1); - if (matches(*argv, "help") == 0) - usage(); - fprintf(stderr, "Command \"%s\" is unknown, try \"ip fou help\".\n", *argv); exit(-1); } From 9423a324bf67913f9dec4bafe1fcb28a7995c8f2 Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Tue, 16 Aug 2016 16:26:58 +0200 Subject: [PATCH 376/513] ila: show usage even if the module is not available Currently, the `ip ila` command tries to initialize a genl context even when we just want to see the help for the command, which doesn't require to talk to the kernel at all. Delay genl initialization, which can fail if the module isn't loaded, until the point where we will actually need it. Fixes: ec71cae0bb7b ("ila: Support for configuring ila to use netfilter hook") Signed-off-by: Sabrina Dubroca --- ip/ipila.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ip/ipila.c b/ip/ipila.c index d75c46297..843cc1652 100644 --- a/ip/ipila.c +++ b/ip/ipila.c @@ -240,20 +240,21 @@ static int do_del(int argc, char **argv) int do_ipila(int argc, char **argv) { - if (genl_init_handle(&genl_rth, ILA_GENL_NAME, &genl_family)) - exit(1); - if (argc < 1) usage(); + if (matches(*argv, "help") == 0) + usage(); + + if (genl_init_handle(&genl_rth, ILA_GENL_NAME, &genl_family)) + exit(1); + if (matches(*argv, "add") == 0) return do_add(argc-1, argv+1); if (matches(*argv, "delete") == 0) return do_del(argc-1, argv+1); if (matches(*argv, "list") == 0) return do_list(argc-1, argv+1); - if (matches(*argv, "help") == 0) - usage(); fprintf(stderr, "Command \"%s\" is unknown, try \"ip ila help\".\n", *argv); From c85703bb9fb778ca94a3f84343406a251d23f9ba Mon Sep 17 00:00:00 2001 From: Xin Long Date: Sun, 7 Aug 2016 17:12:30 +0800 Subject: [PATCH 377/513] ip route: restore_handler should check tb[RTA_PREFSRC] for local networks Prior to this patch, If one route entry's RTA_PREFSRC and RTA_GATEWAY both were NULL, it was supposed to be restored ONLY as a local address. But as it didn't check tb[RTA_PREFSRC] when restoring local networks, rtattr_cmp would return a success if it was NULL, this route entry would be restored again as a local network. This patch is to add tb[RTA_PREFSRC] check when restoring local networks. Fixes: 74af8dd9620e ("ip route: restore route entries in correct order") Signed-off-by: Xin Long Tested-by: Phil Sutter --- ip/iproute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/iproute.c b/ip/iproute.c index c52294d29..3da23af9f 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -1813,7 +1813,7 @@ static int restore_handler(const struct sockaddr_nl *nl, if (!prio && !tb[RTA_GATEWAY] && (!tb[RTA_PREFSRC] || !rtattr_cmp(tb[RTA_PREFSRC], tb[RTA_DST]))) goto restore; - else if (prio == 1 && !tb[RTA_GATEWAY] && + else if (prio == 1 && !tb[RTA_GATEWAY] && tb[RTA_PREFSRC] && rtattr_cmp(tb[RTA_PREFSRC], tb[RTA_DST])) goto restore; else if (prio == 2 && tb[RTA_GATEWAY]) From 6b376ebd6e3bfc0f1b3c75e491e4d40c5500d4fd Mon Sep 17 00:00:00 2001 From: Gustavo Zacarias Date: Sat, 20 Aug 2016 00:11:10 -0300 Subject: [PATCH 378/513] ss: fix build with musl libc UINT_MAX usage requires limits.h, so include it. Signed-off-by: Gustavo Zacarias --- misc/ss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/misc/ss.c b/misc/ss.c index e758f5720..3b268d999 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "utils.h" #include "rt_names.h" From 1acd208c0b2cdb4611b9de5f3b6990b65a7b5660 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 17 Aug 2016 14:39:21 -0700 Subject: [PATCH 379/513] ip: report IFLA_GSO_MAX_SIZE and IFLA_GSO_MAX_SEGS kernel support for these attributes was added in linux-4.6 Signed-off-by: Eric Dumazet --- ip/ipaddress.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index ab4b1b148..76bd7b356 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -901,6 +901,14 @@ int print_linkinfo(const struct sockaddr_nl *who, fprintf(fp, "numrxqueues %u ", rta_getattr_u32(tb[IFLA_NUM_RX_QUEUES])); + if (tb[IFLA_GSO_MAX_SIZE]) + fprintf(fp, "gso_max_size %u ", + rta_getattr_u32(tb[IFLA_GSO_MAX_SIZE])); + + if (tb[IFLA_GSO_MAX_SEGS]) + fprintf(fp, "gso_max_segs %u ", + rta_getattr_u32(tb[IFLA_GSO_MAX_SEGS])); + if (tb[IFLA_PHYS_PORT_NAME]) fprintf(fp, "portname %s ", rta_getattr_str(tb[IFLA_PHYS_PORT_NAME])); From 06be01f75def7be137640ca82ee64a4e233cd3a6 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Mon, 22 Aug 2016 07:17:33 -0400 Subject: [PATCH 380/513] tc classifiers: Modernize tcindex classifier Signed-off-by: Jamal Hadi Salim --- tc/f_tcindex.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tc/f_tcindex.c b/tc/f_tcindex.c index 280d1d4d6..32bccb0cf 100644 --- a/tc/f_tcindex.c +++ b/tc/f_tcindex.c @@ -23,7 +23,7 @@ static void explain(void) } static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc, - char **argv, struct nlmsghdr *n) + char **argv, struct nlmsghdr *n) { struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tail; @@ -49,7 +49,8 @@ static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc, explain(); return -1; } - addattr_l(n, 4096, TCA_TCINDEX_HASH, &hash, sizeof(hash)); + addattr_l(n, 4096, TCA_TCINDEX_HASH, &hash, + sizeof(hash)); } else if (!strcmp(*argv,"mask")) { __u16 mask; @@ -59,7 +60,8 @@ static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc, explain(); return -1; } - addattr_l(n, 4096, TCA_TCINDEX_MASK, &mask, sizeof(mask)); + addattr_l(n, 4096, TCA_TCINDEX_MASK, &mask, + sizeof(mask)); } else if (!strcmp(*argv,"shift")) { int shift; @@ -99,7 +101,7 @@ static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc, continue; } else if (!strcmp(*argv,"action")) { NEXT_ARG(); - if (parse_police(&argc, &argv, TCA_TCINDEX_ACT, n)) { + if (parse_action(&argc, &argv, TCA_TCINDEX_ACT, n)) { fprintf(stderr, "Illegal \"action\"\n"); return -1; } @@ -117,7 +119,7 @@ static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc, static int tcindex_print_opt(struct filter_util *qu, FILE *f, - struct rtattr *opt, __u32 handle) + struct rtattr *opt, __u32 handle) { struct rtattr *tb[TCA_TCINDEX_MAX+1]; @@ -171,7 +173,7 @@ static int tcindex_print_opt(struct filter_util *qu, FILE *f, } if (tb[TCA_TCINDEX_ACT]) { fprintf(f, "\n"); - tc_print_police(f, tb[TCA_TCINDEX_ACT]); + tc_print_action(f, tb[TCA_TCINDEX_ACT]); } return 0; } From 9f9e2bb88e9bf76c434992dda405dc8a83ad2f88 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 25 Aug 2016 08:46:25 -0700 Subject: [PATCH 381/513] update BPF headers --- include/linux/bpf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 19e0c36a4..766db7f15 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -339,7 +339,7 @@ enum bpf_func_id { BPF_FUNC_skb_change_type, /** - * bpf_skb_in_cgroup(skb, map, index) - Check cgroup2 membership of skb + * bpf_skb_under_cgroup(skb, map, index) - Check cgroup2 membership of skb * @skb: pointer to skb * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type * @index: index of the cgroup in the bpf_map @@ -348,7 +348,7 @@ enum bpf_func_id { * == 1 skb succeeded the cgroup2 descendant test * < 0 error */ - BPF_FUNC_skb_in_cgroup, + BPF_FUNC_skb_under_cgroup, /** * bpf_get_hash_recalc(skb) From 380656f8c44255e41c685ac38b496ec8921deed6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 25 Aug 2016 08:49:07 -0700 Subject: [PATCH 382/513] update headers to 4.8-rc2 net-next --- include/linux/bpf.h | 22 ++++++++++++++++++++++ include/linux/if_bridge.h | 2 +- include/linux/if_tunnel.h | 15 ++++++++++++++- include/linux/inet_diag.h | 6 ++++++ include/linux/pkt_cls.h | 3 +++ include/linux/tc_act/tc_vlan.h | 1 + include/linux/tipc_netlink.h | 1 + 7 files changed, 48 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 766db7f15..ee3ea150a 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -375,6 +375,28 @@ enum bpf_func_id { */ BPF_FUNC_probe_write_user, + /** + * bpf_current_task_under_cgroup(map, index) - Check cgroup2 membership of current task + * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type + * @index: index of the cgroup in the bpf_map + * Return: + * == 0 current failed the cgroup2 descendant test + * == 1 current succeeded the cgroup2 descendant test + * < 0 error + */ + BPF_FUNC_current_task_under_cgroup, + + /** + * bpf_skb_change_tail(skb, len, flags) + * The helper will resize the skb to the given new size, + * to be used f.e. with control messages. + * @skb: pointer to skb + * @len: new skb length + * @flags: reserved + * Return: 0 on success or negative error + */ + BPF_FUNC_skb_change_tail, + __BPF_FUNC_MAX_ID, }; diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index d9c76fe7a..b7393dd2b 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -140,7 +140,7 @@ struct bridge_vlan_xstats { __u64 tx_bytes; __u64 tx_packets; __u16 vid; - __u16 pad1; + __u16 flags; __u32 pad2; }; diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index 1fa343db4..1fbd86bfe 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -24,9 +24,22 @@ #define GRE_SEQ __cpu_to_be16(0x1000) #define GRE_STRICT __cpu_to_be16(0x0800) #define GRE_REC __cpu_to_be16(0x0700) -#define GRE_FLAGS __cpu_to_be16(0x00F8) +#define GRE_ACK __cpu_to_be16(0x0080) +#define GRE_FLAGS __cpu_to_be16(0x0078) #define GRE_VERSION __cpu_to_be16(0x0007) +#define GRE_IS_CSUM(f) ((f) & GRE_CSUM) +#define GRE_IS_ROUTING(f) ((f) & GRE_ROUTING) +#define GRE_IS_KEY(f) ((f) & GRE_KEY) +#define GRE_IS_SEQ(f) ((f) & GRE_SEQ) +#define GRE_IS_STRICT(f) ((f) & GRE_STRICT) +#define GRE_IS_REC(f) ((f) & GRE_REC) +#define GRE_IS_ACK(f) ((f) & GRE_ACK) + +#define GRE_VERSION_1 __cpu_to_be16(0x0001) +#define GRE_PROTO_PPP __cpu_to_be16(0x880b) +#define GRE_PPTP_KEY_MASK __cpu_to_be32(0xffff) + struct ip_tunnel_parm { char name[IFNAMSIZ]; int link; diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index beb74ee1f..408cebdad 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -73,6 +73,7 @@ enum { INET_DIAG_BC_S_COND, INET_DIAG_BC_D_COND, INET_DIAG_BC_DEV_COND, /* u32 ifindex */ + INET_DIAG_BC_MARK_COND, }; struct inet_diag_hostcond { @@ -82,6 +83,11 @@ struct inet_diag_hostcond { __be32 addr[0]; }; +struct inet_diag_markcond { + __u32 mark; + __u32 mask; +}; + /* Base info structure. It contains socket identity (addrs/ports/cookie) * and, alas, the information shown by netstat. */ struct inet_diag_msg { diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index 5e6c61e7f..a50bcc2f3 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -374,6 +374,9 @@ enum { TCA_FLOWER_KEY_UDP_DST, /* be16 */ TCA_FLOWER_FLAGS, + TCA_FLOWER_KEY_VLAN_ID, + TCA_FLOWER_KEY_VLAN_PRIO, + TCA_FLOWER_KEY_VLAN_ETH_TYPE, __TCA_FLOWER_MAX, }; diff --git a/include/linux/tc_act/tc_vlan.h b/include/linux/tc_act/tc_vlan.h index 31151ff62..be72b6e38 100644 --- a/include/linux/tc_act/tc_vlan.h +++ b/include/linux/tc_act/tc_vlan.h @@ -29,6 +29,7 @@ enum { TCA_VLAN_PUSH_VLAN_ID, TCA_VLAN_PUSH_VLAN_PROTOCOL, TCA_VLAN_PAD, + TCA_VLAN_PUSH_VLAN_PRIORITY, __TCA_VLAN_MAX, }; #define TCA_VLAN_MAX (__TCA_VLAN_MAX - 1) diff --git a/include/linux/tipc_netlink.h b/include/linux/tipc_netlink.h index 5f3f6d09f..bcb65ef72 100644 --- a/include/linux/tipc_netlink.h +++ b/include/linux/tipc_netlink.h @@ -59,6 +59,7 @@ enum { TIPC_NL_MON_SET, TIPC_NL_MON_GET, TIPC_NL_MON_PEER_GET, + TIPC_NL_PEER_REMOVE, __TIPC_NL_CMD_MAX, TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 From 535194a172d239b63a768e26ef9f688b401a8468 Mon Sep 17 00:00:00 2001 From: Richard Alpe Date: Mon, 22 Aug 2016 10:18:29 +0200 Subject: [PATCH 383/513] tipc: add peer remove functionality This enables a user to remove an offline peer from the kernel data structures. This could for example be useful when deliberately scaling in peer nodes in a cloud environment. This functionality was first merged in: f9dec657e4 (Richard Alpe tipc: add peer remove functionality) And later backed out (as the kernel counterpart was held up) in: 385caeb13b (Stephen Hemminger Revert "tipc: add peer remove functionality") Signed-off-by: Richard Alpe Reviewed-by: Jon Maloy Reviewed-by: Ying Xue --- man/man8/tipc-bearer.8 | 1 + man/man8/tipc-link.8 | 1 + man/man8/tipc-media.8 | 1 + man/man8/tipc-nametable.8 | 1 + man/man8/tipc-node.8 | 1 + man/man8/tipc-peer.8 | 52 ++++++++++++++++++++++ man/man8/tipc.8 | 1 + tipc/Makefile | 2 +- tipc/peer.c | 93 +++++++++++++++++++++++++++++++++++++++ tipc/peer.h | 21 +++++++++ tipc/tipc.c | 3 ++ 11 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 man/man8/tipc-peer.8 create mode 100644 tipc/peer.c create mode 100644 tipc/peer.h diff --git a/man/man8/tipc-bearer.8 b/man/man8/tipc-bearer.8 index 846f1db0c..488305a5d 100644 --- a/man/man8/tipc-bearer.8 +++ b/man/man8/tipc-bearer.8 @@ -212,6 +212,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-media (8), .BR tipc-nametable (8), .BR tipc-node (8), +.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-link.8 b/man/man8/tipc-link.8 index 3be8c9ad4..2ee03a0bd 100644 --- a/man/man8/tipc-link.8 +++ b/man/man8/tipc-link.8 @@ -213,6 +213,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-bearer (8), .BR tipc-nametable (8), .BR tipc-node (8), +.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-media.8 b/man/man8/tipc-media.8 index 6c6e2b152..4689cb3fa 100644 --- a/man/man8/tipc-media.8 +++ b/man/man8/tipc-media.8 @@ -74,6 +74,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-link (8), .BR tipc-nametable (8), .BR tipc-node (8), +.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-nametable.8 b/man/man8/tipc-nametable.8 index d3397f97d..4bcefe47f 100644 --- a/man/man8/tipc-nametable.8 +++ b/man/man8/tipc-nametable.8 @@ -87,6 +87,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-link (8), .BR tipc-media (8), .BR tipc-node (8), +.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-node.8 b/man/man8/tipc-node.8 index ef32ec7c8..a72a40991 100644 --- a/man/man8/tipc-node.8 +++ b/man/man8/tipc-node.8 @@ -59,6 +59,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-link (8), .BR tipc-media (8), .BR tipc-nametable (8), +.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/man/man8/tipc-peer.8 b/man/man8/tipc-peer.8 new file mode 100644 index 000000000..430651f7e --- /dev/null +++ b/man/man8/tipc-peer.8 @@ -0,0 +1,52 @@ +.TH TIPC-PEER 8 "04 Dec 2015" "iproute2" "Linux" + +.\" For consistency, please keep padding right aligned. +.\" For example '.B "foo " bar' and not '.B foo " bar"' + +.SH NAME +tipc-peer \- modify peer information + +.SH SYNOPSIS +.ad l +.in +8 + +.ti -8 +.B tipc peer remove address +.IR ADDRESS + +.SH OPTIONS +Options (flags) that can be passed anywhere in the command chain. +.TP +.BR "\-h" , " --help" +Show help about last valid command. For example +.B tipc peer --help +will show peer help and +.B tipc --help +will show general help. The position of the option in the string is irrelevant. +.SH DESCRIPTION + +.SS Peer remove +Remove an offline peer node from the local data structures. The peer is +identified by its +.B address + +.SH EXIT STATUS +Exit status is 0 if command was successful or a positive integer upon failure. + +.SH SEE ALSO +.BR tipc (8), +.BR tipc-bearer (8), +.BR tipc-link (8), +.BR tipc-media (8), +.BR tipc-nametable (8), +.BR tipc-node (8), +.BR tipc-socket (8) +.br +.SH REPORTING BUGS +Report any bugs to the Network Developers mailing list +.B +where the development and maintenance is primarily done. +You do not have to be subscribed to the list to send a message there. + +.SH AUTHOR +Richard Alpe diff --git a/man/man8/tipc.8 b/man/man8/tipc.8 index c11655238..32943fa50 100644 --- a/man/man8/tipc.8 +++ b/man/man8/tipc.8 @@ -87,6 +87,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .BR tipc-media (8), .BR tipc-nametable (8), .BR tipc-node (8), +.BR tipc-peer (8), .BR tipc-socket (8) .br .SH REPORTING BUGS diff --git a/tipc/Makefile b/tipc/Makefile index 868d13abf..87e3cac37 100644 --- a/tipc/Makefile +++ b/tipc/Makefile @@ -6,7 +6,7 @@ TIPCOBJ=bearer.o \ media.o misc.o \ msg.o nametable.o \ node.o socket.o \ - tipc.o + peer.o tipc.o include ../Config diff --git a/tipc/peer.c b/tipc/peer.c new file mode 100644 index 000000000..de0c73c31 --- /dev/null +++ b/tipc/peer.c @@ -0,0 +1,93 @@ +/* + * peer.c TIPC peer functionality. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Richard Alpe + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "cmdl.h" +#include "msg.h" +#include "misc.h" +#include "peer.h" + +static int cmd_peer_rm_addr(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, void *data) +{ + char *str; + uint32_t addr; + struct nlattr *nest; + char buf[MNL_SOCKET_BUFFER_SIZE]; + + if ((cmdl->argc != cmdl->optind + 1) || help_flag) { + fprintf(stderr, "Usage: %s peer remove address ADDRESS\n", + cmdl->argv[0]); + return -EINVAL; + } + + str = shift_cmdl(cmdl); + addr = str2addr(str); + if (!addr) + return -1; + + if (!(nlh = msg_init(buf, TIPC_NL_PEER_REMOVE))) { + fprintf(stderr, "error, message initialisation failed\n"); + return -1; + } + + nest = mnl_attr_nest_start(nlh, TIPC_NLA_NET); + mnl_attr_put_u32(nlh, TIPC_NLA_NET_ADDR, addr); + mnl_attr_nest_end(nlh, nest); + + return msg_doit(nlh, NULL, NULL); +} + +static void cmd_peer_rm_help(struct cmdl *cmdl) +{ + fprintf(stderr, "Usage: %s peer remove address ADDRESS\n", + cmdl->argv[0]); +} + +static int cmd_peer_rm(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, void *data) +{ + const struct cmd cmds[] = { + { "address", cmd_peer_rm_addr, cmd_peer_rm_help }, + { NULL } + }; + + return run_cmd(nlh, cmd, cmds, cmdl, NULL); +} + +void cmd_peer_help(struct cmdl *cmdl) +{ + fprintf(stderr, + "Usage: %s peer COMMAND [ARGS] ...\n\n" + "COMMANDS\n" + " remove - Remove an offline peer node\n", + cmdl->argv[0]); +} + +int cmd_peer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, + void *data) +{ + const struct cmd cmds[] = { + { "remove", cmd_peer_rm, cmd_peer_rm_help }, + { NULL } + }; + + return run_cmd(nlh, cmd, cmds, cmdl, NULL); +} diff --git a/tipc/peer.h b/tipc/peer.h new file mode 100644 index 000000000..897226165 --- /dev/null +++ b/tipc/peer.h @@ -0,0 +1,21 @@ +/* + * peer.h TIPC peer functionality. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Richard Alpe + */ + +#ifndef _TIPC_PEER_H +#define _TIPC_PEER_H + +extern int help_flag; + +int cmd_peer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, + void *data); +void cmd_peer_help(struct cmdl *cmdl); + +#endif diff --git a/tipc/tipc.c b/tipc/tipc.c index 44398052a..600d5e2a1 100644 --- a/tipc/tipc.c +++ b/tipc/tipc.c @@ -20,6 +20,7 @@ #include "socket.h" #include "media.h" #include "node.h" +#include "peer.h" #include "cmdl.h" int help_flag; @@ -39,6 +40,7 @@ static void about(struct cmdl *cmdl) " media - Show or modify media\n" " nametable - Show nametable\n" " node - Show or modify node related parameters\n" + " peer - Peer related operations\n" " socket - Show sockets\n", cmdl->argv[0]); } @@ -59,6 +61,7 @@ int main(int argc, char *argv[]) { "media", cmd_media, cmd_media_help}, { "nametable", cmd_nametable, cmd_nametable_help}, { "node", cmd_node, cmd_node_help}, + { "peer", cmd_peer, cmd_peer_help}, { "socket", cmd_socket, cmd_socket_help}, { NULL } }; From 7cc7cb8a888bf50c4e118b6bce4c6926321d0689 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 23 Aug 2016 11:52:45 +0200 Subject: [PATCH 384/513] ip-route: Prevent some double spaces in output The code is a bit messy, as it starts with space after text and at some point switches to space before text. But either way, printing space before *and* after text almost certainly leads to printing more whitespace than necessary. Signed-off-by: Phil Sutter --- ip/iproute.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ip/iproute.c b/ip/iproute.c index 3da23af9f..4d7da0233 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -417,22 +417,22 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "dev %s ", ll_index_to_name(*(int *)RTA_DATA(tb[RTA_OIF]))); if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb) - fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); + fprintf(fp, "table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); if (!(r->rtm_flags&RTM_F_CLONED)) { if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1) - fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1))); + fprintf(fp, "proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1))); if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1) - fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1))); + fprintf(fp, "scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1))); } if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) { /* Do not use format_host(). It is our local addr and symbolic name will not be useful. */ - fprintf(fp, " src %s ", + fprintf(fp, "src %s ", rt_addr_n2a_rta(r->rtm_family, tb[RTA_PREFSRC])); } if (tb[RTA_PRIORITY]) - fprintf(fp, " metric %u ", rta_getattr_u32(tb[RTA_PRIORITY])); + fprintf(fp, "metric %u ", rta_getattr_u32(tb[RTA_PRIORITY])); if (r->rtm_flags & RTNH_F_DEAD) fprintf(fp, "dead "); if (r->rtm_flags & RTNH_F_ONLINK) @@ -450,9 +450,9 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (mark) { if (mark >= 16) - fprintf(fp, " mark 0x%x", mark); + fprintf(fp, "mark 0x%x ", mark); else - fprintf(fp, " mark %u", mark); + fprintf(fp, "mark %u ", mark); } } From cef49e514a184dfd6cfa11192cfb0b723a418be0 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Sun, 28 Aug 2016 08:52:40 -0400 Subject: [PATCH 385/513] police: add extra space to improve police result printing Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- tc/m_police.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tc/m_police.c b/tc/m_police.c index f0b179fcc..d7fa8f665 100644 --- a/tc/m_police.c +++ b/tc/m_police.c @@ -322,7 +322,7 @@ int print_police(struct action_util *a, FILE *f, struct rtattr *arg) if (tb[TCA_POLICE_RESULT]) { __u32 action = rta_getattr_u32(tb[TCA_POLICE_RESULT]); - fprintf(f, "/%s", action_n2a(action)); + fprintf(f, "/%s ", action_n2a(action)); } else fprintf(f, " "); From 3de88c4b471185866268e0d338ff79a2bd33ec6b Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Sun, 28 Aug 2016 08:52:41 -0400 Subject: [PATCH 386/513] police: improve usage message Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- tc/m_police.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tc/m_police.c b/tc/m_police.c index d7fa8f665..226e20e4e 100644 --- a/tc/m_police.c +++ b/tc/m_police.c @@ -36,11 +36,12 @@ static void usage(void) { fprintf(stderr, "Usage: ... police rate BPS burst BYTES[/BYTES] [ mtu BYTES[/BYTES] ]\n"); fprintf(stderr, " [ peakrate BPS ] [ avrate BPS ] [ overhead BYTES ]\n"); - fprintf(stderr, " [ linklayer TYPE ] [ ACTIONTERM ]\n"); + fprintf(stderr, " [ linklayer TYPE ] [ CONTROL ]\n"); - fprintf(stderr, "New Syntax ACTIONTERM := conform-exceed [/NOTEXCEEDACT]\n"); - fprintf(stderr, "Where: *EXCEEDACT := pipe | ok | reclassify | drop | continue\n"); - fprintf(stderr, "Where: pipe is only valid for new syntax\n"); + fprintf(stderr, "Where: CONTROL := conform-exceed [/NOTEXCEEDACT]\n"); + fprintf(stderr, " Define how to handle packets which exceed ()\n"); + fprintf(stderr, " or conform () the configured bandwidth limit.\n"); + fprintf(stderr, " EXCEEDACT/NOTEXCEEDACT := { pipe | ok | reclassify | drop | continue }\n"); exit(-1); } From 27d2b08e23abc8427ad6b3977247d4670f689fcb Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Sun, 28 Aug 2016 08:52:42 -0400 Subject: [PATCH 387/513] police: bug fix man page Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- man/man8/tc-police.8 | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/man/man8/tc-police.8 b/man/man8/tc-police.8 index 5c5a63233..620c28813 100644 --- a/man/man8/tc-police.8 +++ b/man/man8/tc-police.8 @@ -26,10 +26,10 @@ police - policing action .ti -8 .IR CONTROL " :=" -.BI conform-exceed " EXCEEDACT\fR[\fB/\fIEXCEEDACT" +.BI conform-exceed " EXCEEDACT\fR[\fB/\fINOTEXCEEDACT" .ti -8 -.IR EXCEEDACT " := { " +.IR EXCEEDACT/NOTEXCEEDACT " := { " .BR pipe " | " ok " | " reclassify " | " drop " | " continue " }" .SH DESCRIPTION The @@ -94,11 +94,9 @@ Fine-tune the in-kernel packet rate estimator. are time values and control the frequency in which samples are taken and over what timespan an average is built. .TP -.BI conform-exceed " EXCEEDACT\fR[\fB/\fIEXCEEDACT\fR]" -Define how to handle packets which exceed (and, if the second -.I EXCEEDACT -is given, also those who don't), the configured bandwidth limit. Possible values -are: +.BI conform-exceed " EXCEEDACT\fR[\fB/\fINOTEXCEEDACT\fR]" +Define how to handle packets which exceed or conform the +configured bandwidth limit. Possible values are: .RS .IP continue Don't do anything, just continue with the next action in line. From 7abf5de677e32f39dcd908f5b69adb047feeb76a Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Thu, 25 Aug 2016 14:28:55 +0200 Subject: [PATCH 388/513] bridge: vlan: add support to display per-vlan statistics This patch adds support for the stats argument to the bridge vlan command which will display the per-vlan statistics and the device each vlan belongs to with its flags. The supported command filtering options are dev and vid. Also the man page is updated to explain the new option. The patch uses the new RTM_GETSTATS interface with a filter_mask to dump all bridges and ports vlans. Later we can add support for using the per-device dump and filter it in the kernel instead. Example: $ bridge -s vlan show port vlan id br0 1 Egress Untagged RX: 2536 bytes 20 packets TX: 2536 bytes 20 packets 101 RX: 43158 bytes 50 packets TX: 43158 bytes 50 packets eth1 1 Egress Untagged RX: 2536 bytes 20 packets TX: 2536 bytes 20 packets 100 RX: 0 bytes 0 packets TX: 0 bytes 0 packets 101 RX: 43158 bytes 50 packets TX: 43158 bytes 50 packets 102 RX: 16897 bytes 93 packets TX: 0 bytes 0 packets The format is the same as bridge vlan show but with stats, even though under the hood the calls done to the kernel are different. Signed-off-by: Nikolay Aleksandrov --- bridge/vlan.c | 154 +++++++++++++++++++++++++++++++++++++------ include/libnetlink.h | 8 +++ lib/libnetlink.c | 20 ++++++ man/man8/bridge.8 | 5 ++ 4 files changed, 167 insertions(+), 20 deletions(-) diff --git a/bridge/vlan.c b/bridge/vlan.c index d3505b59b..0b6c69077 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -15,14 +15,16 @@ #include "utils.h" static unsigned int filter_index, filter_vlan; +static int last_ifidx = -1; json_writer_t *jw_global = NULL; static void usage(void) { - fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid] [ untagged ]\n"); + fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid ] [ untagged ]\n"); fprintf(stderr, " [ self ] [ master ]\n"); fprintf(stderr, " bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n"); + fprintf(stderr, " bridge vlan { stats } [ dev DEV ] [ vid VLAN_ID ]\n"); exit(-1); } @@ -298,6 +300,88 @@ static int print_vlan(const struct sockaddr_nl *who, return 0; } +static void print_one_vlan_stats(FILE *fp, + const struct bridge_vlan_xstats *vstats, + int ifindex) +{ + const char *ifname = ""; + + if (filter_vlan && filter_vlan != vstats->vid) + return; + /* skip pure port entries, they'll be dumped via the slave stats call */ + if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) && + !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY)) + return; + + if (last_ifidx != ifindex) { + ifname = ll_index_to_name(ifindex); + last_ifidx = ifindex; + } + fprintf(fp, "%-16s %hu", ifname, vstats->vid); + if (vstats->flags & BRIDGE_VLAN_INFO_PVID) + fprintf(fp, " PVID"); + if (vstats->flags & BRIDGE_VLAN_INFO_UNTAGGED) + fprintf(fp, " Egress Untagged"); + fprintf(fp, "\n"); + fprintf(fp, "%-16s RX: %llu bytes %llu packets\n", + "", vstats->rx_bytes, vstats->rx_packets); + fprintf(fp, "%-16s TX: %llu bytes %llu packets\n", + "", vstats->tx_bytes, vstats->tx_packets); +} + +static void print_vlan_stats_attr(FILE *fp, struct rtattr *attr, int ifindex) +{ + struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1]; + struct rtattr *i, *list; + int rem; + + parse_rtattr(brtb, LINK_XSTATS_TYPE_MAX, RTA_DATA(attr), + RTA_PAYLOAD(attr)); + if (!brtb[LINK_XSTATS_TYPE_BRIDGE]) + return; + + list = brtb[LINK_XSTATS_TYPE_BRIDGE]; + rem = RTA_PAYLOAD(list); + for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { + if (i->rta_type != BRIDGE_XSTATS_VLAN) + continue; + print_one_vlan_stats(fp, RTA_DATA(i), ifindex); + } +} + +static int print_vlan_stats(const struct sockaddr_nl *who, + struct nlmsghdr *n, + void *arg) +{ + struct if_stats_msg *ifsm = NLMSG_DATA(n); + struct rtattr *tb[IFLA_STATS_MAX+1]; + int len = n->nlmsg_len; + FILE *fp = arg; + + len -= NLMSG_LENGTH(sizeof(*ifsm)); + if (len < 0) { + fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); + return -1; + } + + if (filter_index && filter_index != ifsm->ifindex) + return 0; + + parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len); + + /* We have to check if any of the two attrs are usable */ + if (tb[IFLA_STATS_LINK_XSTATS]) + print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS], + ifsm->ifindex); + + if (tb[IFLA_STATS_LINK_XSTATS_SLAVE]) + print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS_SLAVE], + ifsm->ifindex); + + fflush(fp); + return 0; +} + static int vlan_show(int argc, char **argv) { char *filter_dev = NULL; @@ -325,28 +409,58 @@ static int vlan_show(int argc, char **argv) } } - if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK, - (compress_vlans ? - RTEXT_FILTER_BRVLAN_COMPRESSED : - RTEXT_FILTER_BRVLAN)) < 0) { - perror("Cannont send dump request"); - exit(1); - } + if (!show_stats) { + if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK, + (compress_vlans ? + RTEXT_FILTER_BRVLAN_COMPRESSED : + RTEXT_FILTER_BRVLAN)) < 0) { + perror("Cannont send dump request"); + exit(1); + } + if (json_output) { + jw_global = jsonw_new(stdout); + if (!jw_global) { + fprintf(stderr, "Error allocation json object\n"); + exit(1); + } + jsonw_start_object(jw_global); + } else { + printf("port\tvlan ids\n"); + } - if (json_output) { - jw_global = jsonw_new(stdout); - if (!jw_global) { - fprintf(stderr, "Error allocation json object\n"); + if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) { + fprintf(stderr, "Dump ternminated\n"); exit(1); } - jsonw_start_object(jw_global); } else { - printf("port\tvlan ids\n"); - } + __u32 filt_mask; - if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) { - fprintf(stderr, "Dump ternminated\n"); - exit(1); + filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS); + if (rtnl_wilddump_stats_req_filter(&rth, AF_UNSPEC, + RTM_GETSTATS, + filt_mask) < 0) { + perror("Cannont send dump request"); + exit(1); + } + + printf("%-16s vlan id\n", "port"); + if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); + exit(1); + } + + filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS_SLAVE); + if (rtnl_wilddump_stats_req_filter(&rth, AF_UNSPEC, + RTM_GETSTATS, + filt_mask) < 0) { + perror("Cannont send slave dump request"); + exit(1); + } + + if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); + exit(1); + } } if (jw_global) { @@ -357,7 +471,6 @@ static int vlan_show(int argc, char **argv) return 0; } - int do_vlan(int argc, char **argv) { ll_init_map(&rth); @@ -373,8 +486,9 @@ int do_vlan(int argc, char **argv) return vlan_show(argc-1, argv+1); if (matches(*argv, "help") == 0) usage(); - } else + } else { return vlan_show(0, NULL); + } fprintf(stderr, "Command \"%s\" is unknown, try \"bridge vlan help\".\n", *argv); exit(-1); diff --git a/include/libnetlink.h b/include/libnetlink.h index f7b85dcce..483509ca9 100644 --- a/include/libnetlink.h +++ b/include/libnetlink.h @@ -44,6 +44,9 @@ typedef int (*req_filter_fn_t)(struct nlmsghdr *nlh, int reqlen); int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int fam, int type, req_filter_fn_t fn) __attribute__((warn_unused_result)); +int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type, + __u32 filt_mask) + __attribute__((warn_unused_result)); int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) __attribute__((warn_unused_result)); @@ -202,6 +205,11 @@ int rtnl_from_file(FILE *, rtnl_listen_filter_t handler, #define NETNS_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct rtgenmsg)) #endif +#ifndef IFLA_STATS_RTA +#define IFLA_STATS_RTA(r) \ + ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct if_stats_msg)))) +#endif + /* User defined nlmsg_type which is used mostly for logging netlink * messages from dump file */ #define NLMSG_TSTAMP 15 diff --git a/lib/libnetlink.c b/lib/libnetlink.c index a02cf9f0d..22799355e 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -152,6 +152,26 @@ int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int family, int type, return send(rth->fd, (void*)&req, sizeof(req), 0); } +int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type, + __u32 filt_mask) +{ + struct { + struct nlmsghdr nlh; + struct if_stats_msg ifsm; + } req; + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct if_stats_msg)); + req.nlh.nlmsg_type = type; + req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = rth->dump = ++rth->seq; + req.ifsm.family = fam; + req.ifsm.filter_mask = filt_mask; + + return send(rth->fd, (void *)&req, sizeof(req), 0); +} + int rtnl_send(struct rtnl_handle *rth, const void *buf, int len) { return send(rth->fd, buf, len, 0); diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index bb7044221..7bfb068b7 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -570,6 +570,11 @@ flags are ignored. This command displays the current VLAN filter table. +.PP +With the +.B -statistics +option, the command displays per-vlan traffic statistics. + .SH bridge monitor - state monitoring The From 60ba41ad7f141937135a61bec982de529083768e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 29 Aug 2016 11:06:02 -0700 Subject: [PATCH 389/513] update TIPC headers --- include/linux/tipc_netlink.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/tipc_netlink.h b/include/linux/tipc_netlink.h index bcb65ef72..f9edd20fe 100644 --- a/include/linux/tipc_netlink.h +++ b/include/linux/tipc_netlink.h @@ -60,6 +60,8 @@ enum { TIPC_NL_MON_GET, TIPC_NL_MON_PEER_GET, TIPC_NL_PEER_REMOVE, + TIPC_NL_BEARER_ADD, + TIPC_NL_UDP_GET_REMOTEIP, __TIPC_NL_CMD_MAX, TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 @@ -99,6 +101,7 @@ enum { TIPC_NLA_UDP_UNSPEC, TIPC_NLA_UDP_LOCAL, /* sockaddr_storage */ TIPC_NLA_UDP_REMOTE, /* sockaddr_storage */ + TIPC_NLA_UDP_MULTI_REMOTEIP, /* flag */ __TIPC_NLA_UDP_MAX, TIPC_NLA_UDP_MAX = __TIPC_NLA_UDP_MAX - 1 From f57856fab2e51047c833f5618f2af231f3a9fb5a Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 28 Aug 2016 16:35:21 +0300 Subject: [PATCH 390/513] devlink: Add e-switch support Implement kernel devlink e-switch interface. Currently we allow to get and set the device e-switch mode. Signed-off-by: Or Gerlitz Signed-off-by: Roi Dayan Acked-by: Jiri Pirko --- devlink/devlink.c | 122 +++++++++++++++++++++++++++++++++++++++++ man/man8/devlink-dev.8 | 34 ++++++++++++ 2 files changed, 156 insertions(+) diff --git a/devlink/devlink.c b/devlink/devlink.c index 84fa51e89..d69fc6b19 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -26,6 +26,9 @@ #include "mnlg.h" #include "json_writer.h" +#define ESWITCH_MODE_LEGACY "legacy" +#define ESWITCH_MODE_SWITCHDEV "switchdev" + #define pr_err(args...) fprintf(stderr, ##args) #define pr_out(args...) fprintf(stdout, ##args) #define pr_out_sp(num, args...) \ @@ -128,6 +131,7 @@ static void ifname_map_free(struct ifname_map *ifname_map) #define DL_OPT_SB_THTYPE BIT(8) #define DL_OPT_SB_TH BIT(9) #define DL_OPT_SB_TC BIT(10) +#define DL_OPT_ESWITCH_MODE BIT(11) struct dl_opts { uint32_t present; /* flags of present items */ @@ -143,6 +147,7 @@ struct dl_opts { enum devlink_sb_threshold_type sb_pool_thtype; uint32_t sb_threshold; uint16_t sb_tc_index; + enum devlink_eswitch_mode eswitch_mode; }; struct dl { @@ -297,6 +302,9 @@ static int attr_cb(const struct nlattr *attr, void *data) if (type == DEVLINK_ATTR_SB_OCC_MAX && mnl_attr_validate(attr, MNL_TYPE_U32) < 0) return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_ESWITCH_MODE && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; tb[type] = attr; return MNL_CB_OK; } @@ -661,6 +669,19 @@ static int threshold_type_get(const char *typestr, return 0; } +static int eswitch_mode_get(const char *typestr, enum devlink_eswitch_mode *p_mode) +{ + if (strcmp(typestr, ESWITCH_MODE_LEGACY) == 0) { + *p_mode = DEVLINK_ESWITCH_MODE_LEGACY; + } else if (strcmp(typestr, ESWITCH_MODE_SWITCHDEV) == 0) { + *p_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV; + } else { + pr_err("Unknown eswitch mode \"%s\"\n", typestr); + return -EINVAL; + } + return 0; +} + static int dl_argv_parse(struct dl *dl, uint32_t o_required, uint32_t o_optional) { @@ -770,6 +791,17 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, if (err) return err; o_found |= DL_OPT_SB_TC; + } else if (dl_argv_match(dl, "mode") && + (o_all & DL_OPT_ESWITCH_MODE)) { + const char *typestr; + dl_arg_inc(dl); + err = dl_argv_str(dl, &typestr); + if (err) + return err; + err = eswitch_mode_get(typestr, &opts->eswitch_mode); + if (err) + return err; + o_found |= DL_OPT_ESWITCH_MODE; } else { pr_err("Unknown option \"%s\"\n", dl_argv(dl)); return -EINVAL; @@ -823,6 +855,12 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, pr_err("TC index option expected.\n"); return -EINVAL; } + + if ((o_required & DL_OPT_ESWITCH_MODE) && !(o_found & DL_OPT_ESWITCH_MODE)) { + pr_err("E-Switch mode option expected.\n"); + return -EINVAL; + } + return 0; } @@ -866,6 +904,9 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) if (opts->present & DL_OPT_SB_TC) mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, opts->sb_tc_index); + if (opts->present & DL_OPT_ESWITCH_MODE) + mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE, + opts->eswitch_mode); } static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, @@ -1149,6 +1190,84 @@ static void pr_out_section_end(struct dl *dl) } } +static const char *eswitch_mode_name(uint32_t mode) +{ + switch (mode) { + case DEVLINK_ESWITCH_MODE_LEGACY: return ESWITCH_MODE_LEGACY; + case DEVLINK_ESWITCH_MODE_SWITCHDEV: return ESWITCH_MODE_SWITCHDEV; + default: return ""; + } +} + +static void pr_out_eswitch(struct dl *dl, struct nlattr **tb) +{ + __pr_out_handle_start(dl, tb, true, false); + + if (tb[DEVLINK_ATTR_ESWITCH_MODE]) + pr_out_str(dl, "mode", + eswitch_mode_name(mnl_attr_get_u16(tb[DEVLINK_ATTR_ESWITCH_MODE]))); + pr_out_handle_end(dl); +} + +static int cmd_dev_eswitch_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) + return MNL_CB_ERROR; + pr_out_eswitch(dl, tb); + return MNL_CB_OK; +} + +static int cmd_dev_eswitch_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_MODE_GET, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0); + if (err) + return err; + + pr_out_section_start(dl, "dev"); + err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_eswitch_show_cb, dl); + pr_out_section_end(dl); + return err; +} + +static int cmd_dev_eswitch_set(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_MODE_SET, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_ESWITCH_MODE, 0); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_dev_eswitch(struct dl *dl) +{ + if (dl_argv_match(dl, "set")) { + dl_arg_inc(dl); + return cmd_dev_eswitch_set(dl); + } else if (dl_argv_match(dl, "show")) { + dl_arg_inc(dl); + return cmd_dev_eswitch_show(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data) { struct dl *dl = data; @@ -1194,6 +1313,9 @@ static int cmd_dev(struct dl *dl) dl_argv_match(dl, "list") || dl_no_arg(dl)) { dl_arg_inc(dl); return cmd_dev_show(dl); + } else if (dl_argv_match(dl, "eswitch")) { + dl_arg_inc(dl); + return cmd_dev_eswitch(dl); } pr_err("Command \"%s\" not found\n", dl_argv(dl)); return -ENOENT; diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8 index 62bcead37..9ce319374 100644 --- a/man/man8/devlink-dev.8 +++ b/man/man8/devlink-dev.8 @@ -25,6 +25,17 @@ devlink-dev \- devlink device configuration .ti -8 .B devlink dev help +.ti -8 +.BR "devlink dev eswitch set" +.IR DEV +.RI "[ " +.BR mode " { " legacy " | " switchdev " } " +.RI "]" + +.ti -8 +.BR "devlink dev eswitch show" +.IR DEV + .SH "DESCRIPTION" .SS devlink dev show - display devlink device attributes @@ -38,6 +49,19 @@ Format is: .in +2 BUS_NAME/BUS_ADDRESS +.SS devlink dev eswitch show - display devlink device eswitch attributes +.SS devlink dev eswitch set - sets devlink device eswitch attributes + +.TP +.BR mode " { " legacy " | " switchdev " } " +set eswitch mode + +.I legacy +- Legacy SRIOV + +.I switchdev +- SRIOV switchdev offloads + .SH "EXAMPLES" .PP devlink dev show @@ -48,6 +72,16 @@ Shows the state of all devlink devices on the system. devlink dev show pci/0000:01:00.0 .RS 4 Shows the state of specified devlink device. +.RE +.PP +devlink dev eswitch show pci/0000:01:00.0 +.RS 4 +Shows the eswitch mode of specified devlink device. +.RE +.PP +devlink dev eswitch set pci/0000:01:00.0 mode switchdev +.RS 4 +Sets the eswitch mode of specified devlink device to switchdev. .SH SEE ALSO .BR devlink (8), From 7c55d7700f4320186784590516993a73183bc2f2 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 29 Aug 2016 11:17:38 -0700 Subject: [PATCH 391/513] devlink: whitespace cleanup Break long lines --- devlink/devlink.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index d69fc6b19..e91dc5007 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -669,7 +669,8 @@ static int threshold_type_get(const char *typestr, return 0; } -static int eswitch_mode_get(const char *typestr, enum devlink_eswitch_mode *p_mode) +static int eswitch_mode_get(const char *typestr, + enum devlink_eswitch_mode *p_mode) { if (strcmp(typestr, ESWITCH_MODE_LEGACY) == 0) { *p_mode = DEVLINK_ESWITCH_MODE_LEGACY; @@ -794,6 +795,7 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, } else if (dl_argv_match(dl, "mode") && (o_all & DL_OPT_ESWITCH_MODE)) { const char *typestr; + dl_arg_inc(dl); err = dl_argv_str(dl, &typestr); if (err) @@ -856,7 +858,8 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, return -EINVAL; } - if ((o_required & DL_OPT_ESWITCH_MODE) && !(o_found & DL_OPT_ESWITCH_MODE)) { + if ((o_required & DL_OPT_ESWITCH_MODE) && + !(o_found & DL_OPT_ESWITCH_MODE)) { pr_err("E-Switch mode option expected.\n"); return -EINVAL; } From f1f40cf77dbe80a397c4f16136c721cb9cfbaecd Mon Sep 17 00:00:00 2001 From: Richard Alpe Date: Tue, 30 Aug 2016 10:36:59 +0200 Subject: [PATCH 392/513] tipc: introduce bearer add for remoteip Introduce the ability to add remote IP addresses to an existing UDP bearer. On the kernel side, adding a "remoteip" to an existing bearer puts the bearer in "replicast" mode where TIPC multicast messages are send out to each configured remoteip using unicast. This is required for TIPC UDP bearers to work in environments where IP multicast is disabled. Signed-off-by: Richard Alpe Reviewed-by: Parthasarathy Bhuvaragan Acked-by: Jon Maloy --- man/man8/tipc-bearer.8 | 24 ++++++++ tipc/bearer.c | 125 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) diff --git a/man/man8/tipc-bearer.8 b/man/man8/tipc-bearer.8 index 488305a5d..32be64db9 100644 --- a/man/man8/tipc-bearer.8 +++ b/man/man8/tipc-bearer.8 @@ -10,6 +10,11 @@ tipc-bearer \- show or modify TIPC bearers .ad l .in +8 +.ti -8 +.B tipc bearer add media udp name +.IB "NAME " "remoteip " REMOTEIP +.br + .ti -8 .B tipc bearer enable .RB "[ " domain @@ -196,6 +201,25 @@ IP is specified the .B udp bearer runs in point-to-point mode. +Multiple +.B remoteip +addresses can be added via the +.B bearer add +command. Adding one or more unicast +.B remoteip +addresses to an existing +.B udp +bearer puts the bearer in replicast mode where IP +multicast is emulated by sending multiple unicast messages to each configured +.B remoteip. +When a peer sees a TIPC discovery message from an unknown peer the peer address +is automatically added to the +.B remoteip +(replicast) list, thus only one side of +a link needs to be manually configured. A +.B remoteip +address cannot be added to a multicast bearer. + .TP .BI "remoteport " REMOTEPORT .br diff --git a/tipc/bearer.c b/tipc/bearer.c index 05dabe696..a9fc1d2a6 100644 --- a/tipc/bearer.c +++ b/tipc/bearer.c @@ -222,6 +222,129 @@ static int nl_add_bearer_name(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } +static void cmd_bearer_add_udp_help(struct cmdl *cmdl, char *media) +{ + fprintf(stderr, "Usage: %s bearer add media %s name NAME remoteip REMOTEIP\n\n", + cmdl->argv[0], media); +} + +static void cmd_bearer_add_help(struct cmdl *cmdl) +{ + fprintf(stderr, "Usage: %s bearer add media udp name NAME remoteip REMOTEIP\n", + cmdl->argv[0]); +} + +static int udp_bearer_add(struct nlmsghdr *nlh, struct opt *opts, + struct cmdl *cmdl) +{ + int err; + struct opt *opt; + struct nlattr *opts_nest; + char *remport = "6118"; + + opts_nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_UDP_OPTS); + + if ((opt = get_opt(opts, "remoteport"))) + remport = opt->val; + + if ((opt = get_opt(opts, "remoteip"))) { + char *ip = opt->val; + struct addrinfo *addr = NULL; + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_DGRAM + }; + + if ((err = getaddrinfo(ip, remport, &hints, &addr))) { + fprintf(stderr, "UDP address error: %s\n", + gai_strerror(err)); + freeaddrinfo(addr); + return err; + } + + mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, addr->ai_addrlen, + addr->ai_addr); + freeaddrinfo(addr); + } else { + fprintf(stderr, "error, missing remoteip\n"); + return -EINVAL; + } + mnl_attr_nest_end(nlh, opts_nest); + + return 0; +} + +static int cmd_bearer_add_media(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, void *data) +{ + int err; + char *media; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct opt *opt; + struct nlattr *attrs; + struct opt opts[] = { + { "remoteip", NULL }, + { "remoteport", NULL }, + { "name", NULL }, + { "media", NULL }, + { NULL } + }; + struct tipc_sup_media sup_media[] = { + { "udp", "name", cmd_bearer_add_udp_help}, + { NULL, }, + }; + + /* Rewind optind to include media in the option list */ + cmdl->optind--; + if (parse_opts(opts, cmdl) < 0) + return -EINVAL; + + if (!(opt = get_opt(opts, "media"))) { + fprintf(stderr, "error, missing media value\n"); + return -EINVAL; + } + media = opt->val; + + if (strcmp(media, "udp") != 0) { + fprintf(stderr, "error, no \"%s\" media specific options available\n", + media); + return -EINVAL; + } + if (!(opt = get_opt(opts, "name"))) { + fprintf(stderr, "error, missing media name\n"); + return -EINVAL; + } + + if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ADD))) { + fprintf(stderr, "error, message initialisation failed\n"); + return -1; + } + + attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER); + err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media); + if (err) + return err; + + err = udp_bearer_add(nlh, opts, cmdl); + if (err) + return err; + + mnl_attr_nest_end(nlh, attrs); + + return msg_doit(nlh, NULL, NULL); +} + +static int cmd_bearer_add(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, void *data) +{ + const struct cmd cmds[] = { + { "media", cmd_bearer_add_media, cmd_bearer_add_help }, + { NULL } + }; + + return run_cmd(nlh, cmd, cmds, cmdl, NULL); +} + static void cmd_bearer_enable_help(struct cmdl *cmdl) { fprintf(stderr, @@ -605,6 +728,7 @@ void cmd_bearer_help(struct cmdl *cmdl) "Usage: %s bearer COMMAND [ARGS] ...\n" "\n" "COMMANDS\n" + " add - Add data to existing bearer\n" " enable - Enable a bearer\n" " disable - Disable a bearer\n" " set - Set various bearer properties\n" @@ -616,6 +740,7 @@ int cmd_bearer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { const struct cmd cmds[] = { + { "add", cmd_bearer_add, cmd_bearer_add_help }, { "disable", cmd_bearer_disable, cmd_bearer_disable_help }, { "enable", cmd_bearer_enable, cmd_bearer_enable_help }, { "get", cmd_bearer_get, cmd_bearer_get_help }, From ed81deabf2bf3694d0624b7063c8a99f3e2bc7d9 Mon Sep 17 00:00:00 2001 From: Richard Alpe Date: Tue, 30 Aug 2016 10:37:00 +0200 Subject: [PATCH 393/513] tipc: add the ability to get UDP bearer options In this patch we introduce the ability to get UDP specific bearer options such as remoteip, remoteport, localip and localport. After some discussions on tipc-discussion on how to handle media specific options we agreed to pass them after the media. For media generic bearer options we already do: $ tipc bearer get OPTION media MEDIA name|device NAME|DEVICE For the UDP media specific bearer options we introduce in this path: $ tipc bearer get media udp name NAME OPTION such as $ tipc bearer get media udp name NAME remoteip This allows bash-completion to tab complete only appropriate options, it makes more logical sense and it scales better. Even though it might look a little different to the user. In order to use the existing option parsing framework to do this we add a flag (OPT_KEY) to the option parsing function. If the UDP bearer has multiple remoteip addresses associated with it (replicast) we handle the TIPC_NLA_UDP_MULTI_REMOTEIP flag and send a TIPC_NL_UDP_GET_REMOTEIP query transparently to the user. Signed-off-by: Richard Alpe Reviewed-by: Parthasarathy Bhuvaragan Acked-by: Jon Maloy --- man/man8/tipc-bearer.8 | 5 +- tipc/bearer.c | 272 ++++++++++++++++++++++++++++++++++++----- tipc/cmdl.c | 15 ++- tipc/cmdl.h | 7 ++ tipc/link.c | 8 +- tipc/media.c | 4 +- 6 files changed, 271 insertions(+), 40 deletions(-) diff --git a/man/man8/tipc-bearer.8 b/man/man8/tipc-bearer.8 index 32be64db9..d95b1e1c0 100644 --- a/man/man8/tipc-bearer.8 +++ b/man/man8/tipc-bearer.8 @@ -73,7 +73,7 @@ tipc-bearer \- show or modify TIPC bearers .ti -8 .B tipc bearer get -.RB "{ " "priority" " | " tolerance " | " window " } " media +.RB "[ " "priority" " | " tolerance " | " window " ] " media .br .RB "{ { " eth " | " ib " } " device .IR "DEVICE" " }" @@ -81,7 +81,8 @@ tipc-bearer \- show or modify TIPC bearers .br .RB "{ " udp .B name -.IR NAME " }" +.IR NAME +.RB "[ " "localip " "| " "localport " "| " "remoteip " "| " "remoteport " "] }" .br .ti -8 diff --git a/tipc/bearer.c b/tipc/bearer.c index a9fc1d2a6..8729dad4a 100644 --- a/tipc/bearer.c +++ b/tipc/bearer.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,15 @@ #include "msg.h" #include "bearer.h" +#define UDP_PROP_IP 1 +#define UDP_PROP_PORT 2 + +struct cb_data { + int attr; + int prop; + struct nlmsghdr *nlh; +}; + static void _print_bearer_opts(void) { fprintf(stderr, @@ -57,14 +67,17 @@ static void cmd_bearer_enable_l2_help(struct cmdl *cmdl, char *media) static void cmd_bearer_enable_udp_help(struct cmdl *cmdl, char *media) { fprintf(stderr, - "Usage: %s bearer enable media %s name NAME localip IP [OPTIONS]\n" - "\nOPTIONS\n" + "Usage: %s bearer enable [OPTIONS] media %s name NAME localip IP [UDP OPTIONS]\n\n", + cmdl->argv[0], media); + fprintf(stderr, + "OPTIONS\n" " domain DOMAIN - Discovery domain\n" - " priority PRIORITY - Bearer priority\n" + " priority PRIORITY - Bearer priority\n\n"); + fprintf(stderr, + "UDP OPTIONS\n" " localport PORT - Local UDP port (default 6118)\n" " remoteip IP - Remote IP address\n" - " remoteport IP - Remote UDP port (default 6118)\n", - cmdl->argv[0], media); + " remoteport PORT - Remote UDP port (default 6118)\n"); } static int get_netid_cb(const struct nlmsghdr *nlh, void *data) @@ -283,10 +296,10 @@ static int cmd_bearer_add_media(struct nlmsghdr *nlh, const struct cmd *cmd, struct opt *opt; struct nlattr *attrs; struct opt opts[] = { - { "remoteip", NULL }, - { "remoteport", NULL }, - { "name", NULL }, - { "media", NULL }, + { "remoteip", OPT_KEYVAL, NULL }, + { "remoteport", OPT_KEYVAL, NULL }, + { "name", OPT_KEYVAL, NULL }, + { "media", OPT_KEYVAL, NULL }, { NULL } }; struct tipc_sup_media sup_media[] = { @@ -364,15 +377,15 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd, struct nlattr *nest; char buf[MNL_SOCKET_BUFFER_SIZE]; struct opt opts[] = { - { "device", NULL }, - { "domain", NULL }, - { "localip", NULL }, - { "localport", NULL }, - { "media", NULL }, - { "name", NULL }, - { "priority", NULL }, - { "remoteip", NULL }, - { "remoteport", NULL }, + { "device", OPT_KEYVAL, NULL }, + { "domain", OPT_KEYVAL, NULL }, + { "localip", OPT_KEYVAL, NULL }, + { "localport", OPT_KEYVAL, NULL }, + { "media", OPT_KEYVAL, NULL }, + { "name", OPT_KEYVAL, NULL }, + { "priority", OPT_KEYVAL, NULL }, + { "remoteip", OPT_KEYVAL, NULL }, + { "remoteport", OPT_KEYVAL, NULL }, { NULL } }; struct tipc_sup_media sup_media[] = { @@ -446,9 +459,9 @@ static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd, char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *nest; struct opt opts[] = { - { "device", NULL }, - { "name", NULL }, - { "media", NULL }, + { "device", OPT_KEYVAL, NULL }, + { "name", OPT_KEYVAL, NULL }, + { "media", OPT_KEYVAL, NULL }, { NULL } }; struct tipc_sup_media sup_media[] = { @@ -512,9 +525,9 @@ static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, struct nlattr *props; struct nlattr *attrs; struct opt opts[] = { - { "device", NULL }, - { "media", NULL }, - { "name", NULL }, + { "device", OPT_KEYVAL, NULL }, + { "media", OPT_KEYVAL, NULL }, + { "name", OPT_KEYVAL, NULL }, { NULL } }; struct tipc_sup_media sup_media[] = { @@ -576,7 +589,7 @@ static int cmd_bearer_set(struct nlmsghdr *nlh, const struct cmd *cmd, static void cmd_bearer_get_help(struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s bearer get OPTION media MEDIA ARGS...\n", + fprintf(stderr, "Usage: %s bearer get [OPTION] media MEDIA ARGS...\n", cmdl->argv[0]); _print_bearer_opts(); _print_bearer_media(); @@ -584,8 +597,14 @@ static void cmd_bearer_get_help(struct cmdl *cmdl) static void cmd_bearer_get_udp_help(struct cmdl *cmdl, char *media) { - fprintf(stderr, "Usage: %s bearer get OPTION media %s name NAME\n\n", + fprintf(stderr, "Usage: %s bearer get [OPTION] media %s name NAME [UDP OPTIONS]\n\n", cmdl->argv[0], media); + fprintf(stderr, + "UDP OPTIONS\n" + " remoteip - Remote ip address\n" + " remoteport - Remote port\n" + " localip - Local ip address\n" + " localport - Local port\n\n"); _print_bearer_opts(); } @@ -597,6 +616,115 @@ static void cmd_bearer_get_l2_help(struct cmdl *cmdl, char *media) _print_bearer_opts(); } + +static int bearer_dump_udp_cb(const struct nlmsghdr *nlh, void *data) +{ + struct sockaddr_storage *addr; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + struct nlattr *info[TIPC_NLA_UDP_MAX + 1] = {}; + + mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); + + if (!info[TIPC_NLA_UDP_REMOTE]) + return MNL_CB_ERROR; + + addr = mnl_attr_get_payload(info[TIPC_NLA_UDP_REMOTE]); + + if (addr->ss_family == AF_INET) { + struct sockaddr_in *ipv4 = (struct sockaddr_in *) addr; + + printf("%s\n", inet_ntoa(ipv4->sin_addr)); + } else if (addr->ss_family == AF_INET6) { + char straddr[INET6_ADDRSTRLEN]; + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) addr; + + if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr, + sizeof(straddr))) { + fprintf(stderr, "error, parsing IPv6 addr\n"); + return MNL_CB_ERROR; + } + printf("%s\n", straddr); + + } else { + return MNL_CB_ERROR; + } + + return MNL_CB_OK; +} + +static int bearer_get_udp_cb(const struct nlmsghdr *nlh, void *data) +{ + struct cb_data *cb_data = (struct cb_data *) data; + struct sockaddr_storage *addr; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + struct nlattr *info[TIPC_NLA_MAX + 1] = {}; + struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {}; + struct nlattr *opts[TIPC_NLA_UDP_MAX + 1] = {}; + + mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); + if (!info[TIPC_NLA_BEARER]) + return MNL_CB_ERROR; + + mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs); + if (!attrs[TIPC_NLA_BEARER_UDP_OPTS]) + return MNL_CB_ERROR; + + mnl_attr_parse_nested(attrs[TIPC_NLA_BEARER_UDP_OPTS], parse_attrs, opts); + if (!opts[TIPC_NLA_UDP_LOCAL]) + return MNL_CB_ERROR; + + if ((cb_data->attr == TIPC_NLA_UDP_REMOTE) && + (cb_data->prop == UDP_PROP_IP) && + opts[TIPC_NLA_UDP_MULTI_REMOTEIP]) { + struct genlmsghdr *genl = mnl_nlmsg_get_payload(cb_data->nlh); + + genl->cmd = TIPC_NL_UDP_GET_REMOTEIP; + return msg_dumpit(cb_data->nlh, bearer_dump_udp_cb, NULL); + } + + addr = mnl_attr_get_payload(opts[cb_data->attr]); + + if (addr->ss_family == AF_INET) { + struct sockaddr_in *ipv4 = (struct sockaddr_in *) addr; + + switch (cb_data->prop) { + case UDP_PROP_IP: + printf("%s\n", inet_ntoa(ipv4->sin_addr)); + break; + case UDP_PROP_PORT: + printf("%u\n", ntohs(ipv4->sin_port)); + break; + default: + return MNL_CB_ERROR; + } + + } else if (addr->ss_family == AF_INET6) { + char straddr[INET6_ADDRSTRLEN]; + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) addr; + + switch (cb_data->prop) { + case UDP_PROP_IP: + if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr, + sizeof(straddr))) { + fprintf(stderr, "error, parsing IPv6 addr\n"); + return MNL_CB_ERROR; + } + printf("%s\n", straddr); + break; + case UDP_PROP_PORT: + printf("%u\n", ntohs(ipv6->sin6_port)); + break; + default: + return MNL_CB_ERROR; + } + + } else { + return MNL_CB_ERROR; + } + + return MNL_CB_OK; +} + static int bearer_get_cb(const struct nlmsghdr *nlh, void *data) { int *prop = data; @@ -622,6 +750,86 @@ static int bearer_get_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } +static int cmd_bearer_get_media(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, void *data) +{ + int err; + char *media; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct opt *opt; + struct cb_data cb_data = {0}; + struct nlattr *attrs; + struct opt opts[] = { + { "localip", OPT_KEY, NULL }, + { "localport", OPT_KEY, NULL }, + { "remoteip", OPT_KEY, NULL }, + { "remoteport", OPT_KEY, NULL }, + { "name", OPT_KEYVAL, NULL }, + { "media", OPT_KEYVAL, NULL }, + { NULL } + }; + struct tipc_sup_media sup_media[] = { + { "udp", "name", cmd_bearer_get_udp_help}, + { NULL, }, + }; + + /* Rewind optind to include media in the option list */ + cmdl->optind--; + if (parse_opts(opts, cmdl) < 0) + return -EINVAL; + + if (!(opt = get_opt(opts, "media"))) { + fprintf(stderr, "error, missing media value\n"); + return -EINVAL; + } + media = opt->val; + + if (help_flag) { + cmd_bearer_get_udp_help(cmdl, media); + return -EINVAL; + } + if (strcmp(media, "udp") != 0) { + fprintf(stderr, "error, no \"%s\" media specific options\n", media); + return -EINVAL; + } + if (!(opt = get_opt(opts, "name"))) { + fprintf(stderr, "error, missing media name\n"); + return -EINVAL; + } + + if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) { + fprintf(stderr, "error, message initialisation failed\n"); + return -1; + } + + attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER); + err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media); + if (err) + return err; + mnl_attr_nest_end(nlh, attrs); + cb_data.nlh = nlh; + + if (has_opt(opts, "localip")) { + cb_data.attr = TIPC_NLA_UDP_LOCAL; + cb_data.prop = UDP_PROP_IP; + return msg_doit(nlh, bearer_get_udp_cb, &cb_data); + } else if (has_opt(opts, "localport")) { + cb_data.attr = TIPC_NLA_UDP_LOCAL; + cb_data.prop = UDP_PROP_PORT; + return msg_doit(nlh, bearer_get_udp_cb, &cb_data); + } else if (has_opt(opts, "remoteip")) { + cb_data.attr = TIPC_NLA_UDP_REMOTE; + cb_data.prop = UDP_PROP_IP; + return msg_doit(nlh, bearer_get_udp_cb, &cb_data); + } else if (has_opt(opts, "remoteport")) { + cb_data.attr = TIPC_NLA_UDP_REMOTE; + cb_data.prop = UDP_PROP_PORT; + return msg_doit(nlh, bearer_get_udp_cb, &cb_data); + } + fprintf(stderr, "error, missing UDP option\n"); + return -EINVAL; +} + static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { @@ -630,9 +838,9 @@ static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *attrs; struct opt opts[] = { - { "device", NULL }, - { "media", NULL }, - { "name", NULL }, + { "device", OPT_KEYVAL, NULL }, + { "media", OPT_KEYVAL, NULL }, + { "name", OPT_KEYVAL, NULL }, { NULL } }; struct tipc_sup_media sup_media[] = { @@ -642,6 +850,11 @@ static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, { NULL, }, }; + if (help_flag) { + (cmd->help)(cmdl); + return -EINVAL; + } + if (strcmp(cmd->cmd, "priority") == 0) prop = TIPC_NLA_PROP_PRIO; else if ((strcmp(cmd->cmd, "tolerance") == 0)) @@ -675,6 +888,7 @@ static int cmd_bearer_get(struct nlmsghdr *nlh, const struct cmd *cmd, { "priority", cmd_bearer_get_prop, cmd_bearer_get_help }, { "tolerance", cmd_bearer_get_prop, cmd_bearer_get_help }, { "window", cmd_bearer_get_prop, cmd_bearer_get_help }, + { "media", cmd_bearer_get_media, cmd_bearer_get_help }, { NULL } }; diff --git a/tipc/cmdl.c b/tipc/cmdl.c index b816f7d45..4a2f4fd92 100644 --- a/tipc/cmdl.c +++ b/tipc/cmdl.c @@ -62,6 +62,11 @@ struct opt *get_opt(struct opt *opts, char *key) return NULL; } +bool has_opt(struct opt *opts, char *key) +{ + return get_opt(opts, key) ? true : false; +} + char *shift_cmdl(struct cmdl *cmdl) { int next; @@ -80,7 +85,7 @@ int parse_opts(struct opt *opts, struct cmdl *cmdl) int i; int cnt = 0; - for (i = cmdl->optind; i < cmdl->argc; i += 2) { + for (i = cmdl->optind; i < cmdl->argc; i++) { struct opt *o; o = find_opt(opts, cmdl->argv[i]); @@ -89,9 +94,13 @@ int parse_opts(struct opt *opts, struct cmdl *cmdl) cmdl->argv[i]); return -EINVAL; } + if (o->flag & OPT_KEYVAL) { + cmdl->optind++; + i++; + } cnt++; - o->val = cmdl->argv[i + 1]; - cmdl->optind += 2; + o->val = cmdl->argv[i]; + cmdl->optind++; } return cnt; diff --git a/tipc/cmdl.h b/tipc/cmdl.h index d4795cfe0..d37239f85 100644 --- a/tipc/cmdl.h +++ b/tipc/cmdl.h @@ -16,6 +16,11 @@ extern int help_flag; +enum { + OPT_KEY = (1 << 0), + OPT_KEYVAL = (1 << 1), +}; + struct cmdl { int optind; int argc; @@ -37,10 +42,12 @@ struct cmd { struct opt { const char *key; + uint16_t flag; char *val; }; struct opt *get_opt(struct opt *opts, char *key); +bool has_opt(struct opt *opts, char *key); int parse_opts(struct opt *opts, struct cmdl *cmdl); char *shift_cmdl(struct cmdl *cmdl); diff --git a/tipc/link.c b/tipc/link.c index 89fb4ff4e..061b1c534 100644 --- a/tipc/link.c +++ b/tipc/link.c @@ -98,7 +98,7 @@ static int cmd_link_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, char buf[MNL_SOCKET_BUFFER_SIZE]; struct opt *opt; struct opt opts[] = { - { "link", NULL }, + { "link", OPT_KEYVAL, NULL }, { NULL } }; @@ -169,7 +169,7 @@ static int cmd_link_stat_reset(struct nlmsghdr *nlh, const struct cmd *cmd, struct opt *opt; struct nlattr *nest; struct opt opts[] = { - { "link", NULL }, + { "link", OPT_KEYVAL, NULL }, { NULL } }; @@ -365,7 +365,7 @@ static int cmd_link_stat_show(struct nlmsghdr *nlh, const struct cmd *cmd, char buf[MNL_SOCKET_BUFFER_SIZE]; struct opt *opt; struct opt opts[] = { - { "link", NULL }, + { "link", OPT_KEYVAL, NULL }, { NULL } }; @@ -429,7 +429,7 @@ static int cmd_link_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, struct nlattr *attrs; struct opt *opt; struct opt opts[] = { - { "link", NULL }, + { "link", OPT_KEYVAL, NULL }, { NULL } }; diff --git a/tipc/media.c b/tipc/media.c index a902ab78b..6e10c7e5d 100644 --- a/tipc/media.c +++ b/tipc/media.c @@ -93,7 +93,7 @@ static int cmd_media_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, struct nlattr *nest; struct opt *opt; struct opt opts[] = { - { "media", NULL }, + { "media", OPT_KEYVAL, NULL }, { NULL } }; @@ -173,7 +173,7 @@ static int cmd_media_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, struct nlattr *attrs; struct opt *opt; struct opt opts[] = { - { "media", NULL }, + { "media", OPT_KEYVAL, NULL }, { NULL } }; From d5cbf3ff0561b6c8158c3538c7fe1946add9dec3 Mon Sep 17 00:00:00 2001 From: Yotam Gigi Date: Wed, 31 Aug 2016 09:28:26 +0200 Subject: [PATCH 394/513] tc: Add support for the matchall traffic classifier. The matchall classifier matches every packet and allows the user to apply actions on it. In addition, it supports the skip_sw and skip_hw (as can be found on u32 and flower filter) that direct the kernel to skip the software/hardware processing of the actions. This filter is very useful in usecases where every packet should be matched. For example, packet mirroring (SPAN) can be setup very easily using that filter. Signed-off-by: Yotam Gigi Signed-off-by: Jiri Pirko --- tc/Makefile | 1 + tc/f_matchall.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 tc/f_matchall.c diff --git a/tc/Makefile b/tc/Makefile index 42747c517..8917eaf46 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -67,6 +67,7 @@ TCMODULES += q_pie.o TCMODULES += q_hhf.o TCMODULES += q_clsact.o TCMODULES += e_bpf.o +TCMODULES += f_matchall.o ifeq ($(TC_CONFIG_IPSET), y) ifeq ($(TC_CONFIG_XT), y) diff --git a/tc/f_matchall.c b/tc/f_matchall.c new file mode 100644 index 000000000..04e524e3b --- /dev/null +++ b/tc/f_matchall.c @@ -0,0 +1,143 @@ +/* + * f_matchall.c Match-all Classifier + * + * This program is free software; you can distribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Jiri Pirko , Yotam Gigi + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "tc_util.h" + +static void explain(void) +{ + fprintf(stderr, "Usage: ... matchall [skip_sw | skip_hw]\n"); + fprintf(stderr, " [ action ACTION_SPEC ] [ classid CLASSID ]\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n"); + fprintf(stderr, " FILTERID := X:Y:Z\n"); + fprintf(stderr, " ACTION_SPEC := ... look at individual actions\n"); + fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n"); +} + +static int matchall_parse_opt(struct filter_util *qu, char *handle, + int argc, char **argv, struct nlmsghdr *n) +{ + struct tcmsg *t = NLMSG_DATA(n); + struct rtattr *tail; + __u32 flags = 0; + long h = 0; + + if (handle) { + h = strtol(handle, NULL, 0); + if (h == LONG_MIN || h == LONG_MAX) { + fprintf(stderr, "Illegal handle \"%s\", must be numeric.\n", + handle); + return -1; + } + } + t->tcm_handle = h; + + if (argc == 0) + return 0; + + tail = (struct rtattr *)(((void *)n)+NLMSG_ALIGN(n->nlmsg_len)); + addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); + + while (argc > 0) { + if (matches(*argv, "classid") == 0 || + strcmp(*argv, "flowid") == 0) { + unsigned int handle; + + NEXT_ARG(); + if (get_tc_classid(&handle, *argv)) { + fprintf(stderr, "Illegal \"classid\"\n"); + return -1; + } + addattr_l(n, MAX_MSG, TCA_MATCHALL_CLASSID, &handle, 4); + } else if (matches(*argv, "action") == 0) { + NEXT_ARG(); + if (parse_action(&argc, &argv, TCA_MATCHALL_ACT, n)) { + fprintf(stderr, "Illegal \"action\"\n"); + return -1; + } + continue; + + } else if (strcmp(*argv, "skip_hw") == 0) { + NEXT_ARG(); + flags |= TCA_CLS_FLAGS_SKIP_HW; + continue; + } else if (strcmp(*argv, "skip_sw") == 0) { + NEXT_ARG(); + flags |= TCA_CLS_FLAGS_SKIP_SW; + continue; + } else if (strcmp(*argv, "help") == 0) { + explain(); + return -1; + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + explain(); + return -1; + } + argc--; argv++; + } + + if (flags) { + if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW | + TCA_CLS_FLAGS_SKIP_SW))) { + fprintf(stderr, + "skip_hw and skip_sw are mutually exclusive\n"); + return -1; + } + addattr_l(n, MAX_MSG, TCA_MATCHALL_FLAGS, &flags, 4); + } + + tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail; + return 0; +} + +static int matchall_print_opt(struct filter_util *qu, FILE *f, + struct rtattr *opt, __u32 handle) +{ + struct rtattr *tb[TCA_MATCHALL_MAX+1]; + + if (opt == NULL) + return 0; + + parse_rtattr_nested(tb, TCA_MATCHALL_MAX, opt); + + if (handle) + fprintf(f, "handle 0x%x ", handle); + + if (tb[TCA_MATCHALL_CLASSID]) { + SPRINT_BUF(b1); + fprintf(f, "flowid %s ", + sprint_tc_classid(rta_getattr_u32(tb[TCA_MATCHALL_CLASSID]), b1)); + } + + if (tb[TCA_MATCHALL_ACT]) + tc_print_action(f, tb[TCA_MATCHALL_ACT]); + + return 0; +} + +struct filter_util matchall_filter_util = { + .id = "matchall", + .parse_fopt = matchall_parse_opt, + .print_fopt = matchall_print_opt, +}; From 0501294bca39a19090dae302dc491684470b1a0d Mon Sep 17 00:00:00 2001 From: Yotam Gigi Date: Wed, 31 Aug 2016 09:28:27 +0200 Subject: [PATCH 395/513] tc: man: Add man entry for the matchall classifier. In addition to providing information about the mathcall filter and its configurations, the man entry contains examples for creating port mirorring entries. Signed-off-by: Yotam Gigi Signed-off-by: Jiri Pirko --- man/man8/Makefile | 2 +- man/man8/tc-matchall.8 | 76 ++++++++++++++++++++++++++++++++++++++++++ man/man8/tc.8 | 5 +++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 man/man8/tc-matchall.8 diff --git a/man/man8/Makefile b/man/man8/Makefile index 9badbed71..921376919 100644 --- a/man/man8/Makefile +++ b/man/man8/Makefile @@ -14,7 +14,7 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. tipc.8 tipc-bearer.8 tipc-link.8 tipc-media.8 tipc-nametable.8 \ tipc-node.8 tipc-socket.8 \ tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \ - tc-tcindex.8 tc-u32.8 \ + tc-tcindex.8 tc-u32.8 tc-matchall.8 \ tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 \ devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 diff --git a/man/man8/tc-matchall.8 b/man/man8/tc-matchall.8 new file mode 100644 index 000000000..f92092269 --- /dev/null +++ b/man/man8/tc-matchall.8 @@ -0,0 +1,76 @@ +.TH "Match-all classifier in tc" 8 "21 Oct 2015" "iproute2" "Linux" + +.SH NAME +matchall \- traffic control filter that matches every packet +.SH SYNOPSIS +.in +8 +.ti -8 +.BR tc " " filter " ... " matchall " [ " +.BR skip_sw " | " skip_hw +.R " ] [ " +.B action +.IR ACTION_SPEC " ] [ " +.B classid +.IR CLASSID " ]" +.SH DESCRIPTION +The +.B matchall +filter allows to classify every packet that flows on the port and run a +action on it. +.SH OPTIONS +.TP +.BI action " ACTION_SPEC" +Apply an action from the generic actions framework on matching packets. +.TP +.BI classid " CLASSID" +Push matching packets into the class identified by +.IR CLASSID . +.TP +.BI skip_sw +Do not process filter by software. If hardware has no offload support for this +filter, or TC offload is not enabled for the interface, operation will fail. +.TP +.BI skip_hw +Do not process filter by hardware. +.SH EXAMPLES +To create ingress mirroring from port eth1 to port eth2: +.RS +.EX + +tc qdisc add dev eth1 handle ffff: ingress +tc filter add dev eth1 parent ffff: \\ + matchall skip_sw \\ + action mirred egress mirror \\ + dev eth2 +.EE +.RE + +The first command creats an ingress qdisc with handle +.BR ffff: +on device +.BR eth1 +where the second command attaches a matchall filters on it that mirrors the +packets to device eth2. + +To create egress mirroring from port eth1 to port eth2: +.EX + +tc qdisc add dev eth1 handle 1: root prio +tc filter add dev eth1 parent 1: \\ + matchall skip_sw \\ + action mirred egress mirror \\ + dev eth2 +.EE +.RE + +The first command creats an egress qdisc with handle +.BR 1: +that replaces the root qdisc on device +.BR eth1 +where the second command attaches a matchall filters on it that mirrors the +packets to device eth2. + + +.EE +.SH SEE ALSO +.BR tc (8), diff --git a/man/man8/tc.8 b/man/man8/tc.8 index 4e99dcad5..7ee1c9c9d 100644 --- a/man/man8/tc.8 +++ b/man/man8/tc.8 @@ -187,6 +187,11 @@ u32 Generic filtering on arbitrary packet data, assisted by syntax to abstract common operations. See .BR tc-u32 (8) for details. +.TP +matchall +Traffic control filter that matches every packet. See +.BR tc-matchall (8) +for details. .SH CLASSLESS QDISCS The classless qdiscs are: From 745d91726006fcaa9006f491f9a596c4025cecf7 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Thu, 1 Sep 2016 09:45:47 +0300 Subject: [PATCH 396/513] tc: flower: Introduce vlan support Classification according to vlan id and vlan priority. Example script that adds vlan filter: # add ingress qdisc tc qdisc add dev ens4f0 ingress # add a flower filter with vlan id and priority classification tc filter add dev ens4f0 protocol 802.1Q parent ffff: \ flower \ indev ens4f0 \ vlan_ethtype ipv4 \ vlan_id 100 \ vlan_prio 3 \ action vlan pop Signed-off-by: Hadar Hen Zion Acked-by: Jiri Pirko --- man/man8/tc-flower.8 | 25 +++++++++++++- tc/f_flower.c | 78 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8 index 9ae10e6f8..74f766477 100644 --- a/man/man8/tc-flower.8 +++ b/man/man8/tc-flower.8 @@ -23,7 +23,13 @@ flower \- flow based traffic control filter .R " | { " .BR dst_mac " | " src_mac " } " .IR mac_address " | " -.BR eth_type " { " ipv4 " | " ipv6 " | " +.BR eth_type " { " ipv4 " | " ipv6 " | " 802.1Q " | " +.IR ETH_TYPE " } | " +.B vlan_id +.IR VID " | " +.B vlan_prio +.IR PRIORITY " | " +.BR vlan_eth_type " { " ipv4 " | " ipv6 " | " .IR ETH_TYPE " } | " .BR ip_proto " { " tcp " | " udp " | " .IR IP_PROTO " } | { " @@ -70,6 +76,23 @@ Do not process filter by hardware. Match on source or destination MAC address. .TP .BI eth_type " ETH_TYPE" +Match on the next protocol. +.I ETH_TYPE +may be either +.BR ipv4 , ipv6 , 802.1Q , +or an unsigned 16bit value in hexadecimal format. +.TP +.BI vlan_id " VID" +Match on vlan tag id. +.I VID +is an unsigned 12bit value in decimal format. +.TP +.BI vlan_prio " priority" +Match on vlan tag priority. +.I PRIORITY +is an unsigned 3bit value in decimal format. +.TP +.BI vlan_eth_type " VLAN_ETH_TYPE" Match on layer three protocol. .I ETH_TYPE may be either diff --git a/tc/f_flower.c b/tc/f_flower.c index 791ade7f8..2d31d1aa8 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "utils.h" #include "tc_util.h" @@ -30,6 +31,9 @@ static void explain(void) fprintf(stderr, "\n"); fprintf(stderr, "Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n"); fprintf(stderr, " MATCH := { indev DEV-NAME |\n"); + fprintf(stderr, " vlan_id VID |\n"); + fprintf(stderr, " vlan_prio PRIORITY |\n"); + fprintf(stderr, " vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"); fprintf(stderr, " dst_mac MAC-ADDR |\n"); fprintf(stderr, " src_mac MAC-ADDR |\n"); fprintf(stderr, " [ipv4 | ipv6 ] |\n"); @@ -61,6 +65,23 @@ static int flower_parse_eth_addr(char *str, int addr_type, int mask_type, return 0; } +static int flower_parse_vlan_eth_type(char *str, __be16 eth_type, int type, + __be16 *p_vlan_eth_type, struct nlmsghdr *n) +{ + __be16 vlan_eth_type; + + if (eth_type != htons(ETH_P_8021Q)) { + fprintf(stderr, "Can't set \"vlan_ethtype\" if ethertype isn't 802.1Q\n"); + return -1; + } + + if (ll_proto_a2n(&vlan_eth_type, str)) + invarg("invalid vlan_ethtype", str); + addattr16(n, MAX_MSG, type, vlan_eth_type); + *p_vlan_eth_type = vlan_eth_type; + return 0; +} + static int flower_parse_ip_proto(char *str, __be16 eth_type, int type, __u8 *p_ip_proto, struct nlmsghdr *n) { @@ -167,6 +188,7 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, struct tcmsg *t = NLMSG_DATA(n); struct rtattr *tail; __be16 eth_type = TC_H_MIN(t->tcm_info); + __be16 vlan_ethtype = 0; __u8 ip_proto = 0xff; __u32 flags = 0; @@ -208,6 +230,41 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, NEXT_ARG(); strncpy(ifname, *argv, sizeof(ifname) - 1); addattrstrz(n, MAX_MSG, TCA_FLOWER_INDEV, ifname); + } else if (matches(*argv, "vlan_id") == 0) { + __u16 vid; + + NEXT_ARG(); + if (eth_type != htons(ETH_P_8021Q)) { + fprintf(stderr, "Can't set \"vlan_id\" if ethertype isn't 802.1Q\n"); + return -1; + } + ret = get_u16(&vid, *argv, 10); + if (ret < 0 || vid & ~0xfff) { + fprintf(stderr, "Illegal \"vlan_id\"\n"); + return -1; + } + addattr16(n, MAX_MSG, TCA_FLOWER_KEY_VLAN_ID, vid); + } else if (matches(*argv, "vlan_prio") == 0) { + __u8 vlan_prio; + + NEXT_ARG(); + if (eth_type != htons(ETH_P_8021Q)) { + fprintf(stderr, "Can't set \"vlan_prio\" if ethertype isn't 802.1Q\n"); + return -1; + } + ret = get_u8(&vlan_prio, *argv, 10); + if (ret < 0 || vlan_prio & ~0x7) { + fprintf(stderr, "Illegal \"vlan_prio\"\n"); + return -1; + } + addattr8(n, MAX_MSG, TCA_FLOWER_KEY_VLAN_PRIO, vlan_prio); + } else if (matches(*argv, "vlan_ethtype") == 0) { + NEXT_ARG(); + ret = flower_parse_vlan_eth_type(*argv, eth_type, + TCA_FLOWER_KEY_VLAN_ETH_TYPE, + &vlan_ethtype, n); + if (ret < 0) + return -1; } else if (matches(*argv, "dst_mac") == 0) { NEXT_ARG(); ret = flower_parse_eth_addr(*argv, @@ -230,7 +287,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, } } else if (matches(*argv, "ip_proto") == 0) { NEXT_ARG(); - ret = flower_parse_ip_proto(*argv, eth_type, + ret = flower_parse_ip_proto(*argv, vlan_ethtype ? + vlan_ethtype : eth_type, TCA_FLOWER_KEY_IP_PROTO, &ip_proto, n); if (ret < 0) { @@ -239,7 +297,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, } } else if (matches(*argv, "dst_ip") == 0) { NEXT_ARG(); - ret = flower_parse_ip_addr(*argv, eth_type, + ret = flower_parse_ip_addr(*argv, vlan_ethtype ? + vlan_ethtype : eth_type, TCA_FLOWER_KEY_IPV4_DST, TCA_FLOWER_KEY_IPV4_DST_MASK, TCA_FLOWER_KEY_IPV6_DST, @@ -251,7 +310,8 @@ static int flower_parse_opt(struct filter_util *qu, char *handle, } } else if (matches(*argv, "src_ip") == 0) { NEXT_ARG(); - ret = flower_parse_ip_addr(*argv, eth_type, + ret = flower_parse_ip_addr(*argv, vlan_ethtype ? + vlan_ethtype : eth_type, TCA_FLOWER_KEY_IPV4_SRC, TCA_FLOWER_KEY_IPV4_SRC_MASK, TCA_FLOWER_KEY_IPV6_SRC, @@ -477,6 +537,18 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, fprintf(f, "\n indev %s", rta_getattr_str(attr)); } + 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)); + } + + 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)); + } + flower_print_eth_addr(f, "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], From 0e43ed9deae89f70b1babbe7c1cdc2653bb4124c Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Thu, 1 Sep 2016 09:45:48 +0300 Subject: [PATCH 397/513] tc: m_vlan: Add priority option to push vlan action The current vlan push action supports only vid and protocol options. Add priority option. Example script that adds vlan push action with vid and priority: tc filter add dev veth0 protocol ip parent ffff: \ flower \ indev veth0 \ action vlan push id 100 priority 5 Signed-off-by: Hadar Hen Zion Acked-by: Jiri Pirko --- man/man8/tc-vlan.8 | 5 +++++ tc/m_vlan.c | 22 +++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/man/man8/tc-vlan.8 b/man/man8/tc-vlan.8 index 4bfd72b12..4d0c5c8a1 100644 --- a/man/man8/tc-vlan.8 +++ b/man/man8/tc-vlan.8 @@ -12,6 +12,8 @@ vlan - vlan manipulation module .IR PUSH " := " .BR push " [ " protocol .IR VLANPROTO " ]" +.BR " [ " priority +.IR VLANPRIO " ] " .BI id " VLANID" .ti -8 @@ -55,6 +57,9 @@ for hexadecimal interpretation, etc.). Choose the VLAN protocol to use. At the time of writing, the kernel accepts only .BR 802.1Q " or " 802.1ad . .TP +.BI priority " VLANPRIO" +Choose the VLAN priority to use. Decimal number in range of 0-7. +.TP .I CONTROL How to continue after executing this action. .RS diff --git a/tc/m_vlan.c b/tc/m_vlan.c index ac63d9ed0..05a63b48f 100644 --- a/tc/m_vlan.c +++ b/tc/m_vlan.c @@ -22,7 +22,7 @@ static void explain(void) { fprintf(stderr, "Usage: vlan pop\n"); - fprintf(stderr, " vlan push [ protocol VLANPROTO ] id VLANID [CONTROL]\n"); + fprintf(stderr, " vlan push [ 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"); @@ -45,6 +45,8 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, int id_set = 0; __u16 proto; int proto_set = 0; + __u8 prio; + int prio_set = 0; struct tc_vlan parm = { 0 }; if (matches(*argv, "vlan") != 0) @@ -91,6 +93,17 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, if (ll_proto_a2n(&proto, *argv)) invarg("protocol is invalid", *argv); proto_set = 1; + } else if (matches(*argv, "priority") == 0) { + if (action != TCA_VLAN_ACT_PUSH) { + fprintf(stderr, "\"%s\" is only valid for push\n", + *argv); + explain(); + return -1; + } + NEXT_ARG(); + if (get_u8(&prio, *argv, 0) || (prio & ~0x7)) + invarg("prio is invalid", *argv); + prio_set = 1; } else if (matches(*argv, "help") == 0) { usage(); } else { @@ -138,6 +151,9 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, addattr_l(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_PROTOCOL, &proto, 2); } + if (prio_set) + addattr8(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_PRIORITY, prio); + tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; *argc_p = argc; @@ -180,6 +196,10 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) 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); + } break; } fprintf(f, " %s", action_n2a(parm->action)); From 56e3eb4c3400c5d857174c54c94f89ae7933301d Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Sat, 20 Aug 2016 14:53:10 +0200 Subject: [PATCH 398/513] ip: route: fix multicast route dumps If we have multicast routes and do ip route show table all we'll get the following output: ... multicast ???/32 from ???/32 table default proto static iif eth0 The "???" are because the rtm_family is set to RTNL_FAMILY_IPMR instead (or RTNL_FAMILY_IP6MR for ipv6). Add a simple workaround that returns the real family based on the rtm_type (always RTN_MULTICAST for ipmr routes) and the rtm_family. Similar workaround is already used in ipmroute, and we can use this helper there as well. After the patch the output is: multicast 239.10.10.10/32 from 0.0.0.0/32 table default proto static iif eth0 Also fix a minor whitespace error and switch to tabs. Reported-by: Satish Ashok Signed-off-by: Nikolay Aleksandrov --- include/utils.h | 1 + ip/ipmroute.c | 2 +- ip/iproute.c | 12 +++++++----- lib/utils.c | 9 +++++++++ 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/include/utils.h b/include/utils.h index 82f1aa7de..1b4f939cb 100644 --- a/include/utils.h +++ b/include/utils.h @@ -249,5 +249,6 @@ int do_each_netns(int (*func)(char *nsname, void *arg), void *arg, char *int_to_str(int val, char *buf); int get_guid(__u64 *guid, const char *arg); +int get_real_family(int rtm_type, int rtm_family); #endif /* __UTILS_H__ */ diff --git a/ip/ipmroute.c b/ip/ipmroute.c index 5d6922a23..133367a23 100644 --- a/ip/ipmroute.c +++ b/ip/ipmroute.c @@ -112,7 +112,7 @@ int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) return 0; } - family = r->rtm_family == RTNL_FAMILY_IPMR ? AF_INET : AF_INET6; + family = get_real_family(r->rtm_type, r->rtm_family); if (n->nlmsg_type == RTM_DELROUTE) fprintf(fp, "Deleted "); diff --git a/ip/iproute.c b/ip/iproute.c index 4d7da0233..0bc013686 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -311,7 +311,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[RTA_MAX+1]; - int host_len; + int host_len, family; __u32 table; SPRINT_BUF(b1); @@ -363,13 +363,14 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); if (tb[RTA_DST]) { + family = get_real_family(r->rtm_type, r->rtm_family); if (r->rtm_dst_len != host_len) { fprintf(fp, "%s/%u ", - rt_addr_n2a_rta(r->rtm_family, tb[RTA_DST]), + rt_addr_n2a_rta(family, tb[RTA_DST]), r->rtm_dst_len); } else { fprintf(fp, "%s ", - format_host_rta(r->rtm_family, tb[RTA_DST])); + format_host_rta(family, tb[RTA_DST])); } } else if (r->rtm_dst_len) { fprintf(fp, "0/%d ", r->rtm_dst_len); @@ -377,13 +378,14 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, "default "); } if (tb[RTA_SRC]) { + family = get_real_family(r->rtm_type, r->rtm_family); if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", - rt_addr_n2a_rta(r->rtm_family, tb[RTA_SRC]), + rt_addr_n2a_rta(family, tb[RTA_SRC]), r->rtm_src_len); } else { fprintf(fp, "from %s ", - format_host_rta(r->rtm_family, tb[RTA_SRC])); + format_host_rta(family, tb[RTA_SRC])); } } else if (r->rtm_src_len) { fprintf(fp, "from 0/%u ", r->rtm_src_len); diff --git a/lib/utils.c b/lib/utils.c index 966047460..9ada7737f 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -1156,3 +1156,12 @@ int get_guid(__u64 *guid, const char *arg) return 0; } + +/* This is a necessary workaround for multicast route dumps */ +int get_real_family(int rtm_type, int rtm_family) +{ + if (rtm_type != RTN_MULTICAST) + return rtm_family; + + return rtm_family == RTNL_FAMILY_IPMR ? AF_INET : AF_INET6; +} From 567e6960721b7e3b78cae7a46f8cd057b505ad9a Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Wed, 24 Aug 2016 20:08:25 +0200 Subject: [PATCH 399/513] iptuntap: show processes using tuntap interface Show which processes are using which tun/tap devices, e.g.: $ ip -d tuntap tun0: tun Attached to processes: vpnc(9531) vnet0: tap vnet_hdr Attached to processes: qemu-system-x86(10442) virbr0-nic: tap UNKNOWN_FLAGS:800 Attached to processes: Signed-off-by: Hannes Frederic Sowa --- ip/iptuntap.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/ip/iptuntap.c b/ip/iptuntap.c index 43774f96e..b5aa0542c 100644 --- a/ip/iptuntap.c +++ b/ip/iptuntap.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "rt_names.h" #include "utils.h" @@ -273,6 +274,109 @@ static void print_flags(long flags) printf(" UNKNOWN_FLAGS:%lx", flags); } +static char *pid_name(pid_t pid) +{ + char *comm; + FILE *f; + int err; + + err = asprintf(&comm, "/proc/%d/comm", pid); + if (err < 0) + return NULL; + + f = fopen(comm, "r"); + free(comm); + if (!f) { + perror("fopen"); + return NULL; + } + + if (fscanf(f, "%ms\n", &comm) != 1) { + perror("fscanf"); + comm = NULL; + } + + + if (fclose(f)) + perror("fclose"); + + return comm; +} + +static void show_processes(const char *name) +{ + glob_t globbuf = { }; + char **fd_path; + int err; + + err = glob("/proc/[0-9]*/fd/[0-9]*", GLOB_NOSORT, + NULL, &globbuf); + if (err) + return; + + fd_path = globbuf.gl_pathv; + while (*fd_path) { + const char *dev_net_tun = "/dev/net/tun"; + const size_t linkbuf_len = strlen(dev_net_tun) + 2; + char linkbuf[linkbuf_len], *fdinfo; + int pid, fd; + FILE *f; + + if (sscanf(*fd_path, "/proc/%d/fd/%d", &pid, &fd) != 2) + goto next; + + if (pid == getpid()) + goto next; + + err = readlink(*fd_path, linkbuf, linkbuf_len - 1); + if (err < 0) { + perror("readlink"); + goto next; + } + linkbuf[err] = '\0'; + if (strcmp(dev_net_tun, linkbuf)) + goto next; + + if (asprintf(&fdinfo, "/proc/%d/fdinfo/%d", pid, fd) < 0) + goto next; + + f = fopen(fdinfo, "r"); + free(fdinfo); + if (!f) { + perror("fopen"); + goto next; + } + + while (!feof(f)) { + char *key = NULL, *value = NULL; + + err = fscanf(f, "%m[^:]: %ms\n", &key, &value); + if (err == EOF) { + if (ferror(f)) + perror("fscanf"); + break; + } else if (err == 2 && + !strcmp("iff", key) && !strcmp(name, value)) { + char *pname = pid_name(pid); + printf(" %s(%d)", pname ? pname : "", pid); + free(pname); + } + + free(key); + free(value); + } + if (fclose(f)) + perror("fclose"); + +next: + ++fd_path; + } + + globfree(&globbuf); + return; +} + + static int do_show(int argc, char **argv) { DIR *dir; @@ -302,6 +406,11 @@ static int do_show(int argc, char **argv) if (group != -1) printf(" group %ld", group); printf("\n"); + if (show_details) { + printf("\tAttached to processes:"); + show_processes(d->d_name); + printf("\n"); + } } closedir(dir); return 0; From 67a990b8112611e5e4b64f2a5f6ee890422d7695 Mon Sep 17 00:00:00 2001 From: "Andrey Jr. Melnikov" Date: Wed, 24 Aug 2016 23:43:00 +0300 Subject: [PATCH 400/513] iproute: disallow ip rule del without parameters Disallow run `ip rule del` without any parameter to avoid delete any first rule from table. Signed-off-by: Andrey Jr. Melnikov --- ip/iprule.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ip/iprule.c b/ip/iprule.c index 8f242067f..70562c553 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -346,6 +346,11 @@ static int iprule_modify(int cmd, int argc, char **argv) req.r.rtm_type = RTN_UNICAST; } + if (cmd == RTM_DELRULE && argc == 0) { + fprintf(stderr, "\"ip rule del\" requires arguments.\n"); + return -1; + } + while (argc > 0) { if (strcmp(*argv, "not") == 0) { req.r.rtm_flags |= FIB_RULE_INVERT; From 4a564d914d8a4e8d5a4b0f0c00aa44813ba62db4 Mon Sep 17 00:00:00 2001 From: Iskren Chernev Date: Tue, 30 Aug 2016 17:08:54 -0700 Subject: [PATCH 401/513] iproute: fix documentation for ip rule scan order --- man/man8/ip-rule.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/ip-rule.8 b/man/man8/ip-rule.8 index 1774ae3ee..3508d8090 100644 --- a/man/man8/ip-rule.8 +++ b/man/man8/ip-rule.8 @@ -93,7 +93,7 @@ Each policy routing rule consists of a .B selector and an .B action predicate. -The RPDB is scanned in order of decreasing priority. The selector +The RPDB is scanned in order of increasing priority. The selector of each rule is applied to {source address, destination address, incoming interface, tos, fwmark} and, if the selector matches the packet, the action is performed. The action predicate may return with success. From ae810982ccd012e8566aca18b73842019806f872 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 1 Sep 2016 08:44:20 -0700 Subject: [PATCH 402/513] remove useless return statement Get rid of: void foo() { ... return; } --- ip/iptuntap.c | 1 - tc/tc_class.c | 1 - tc/tc_stab.c | 1 - 3 files changed, 3 deletions(-) diff --git a/ip/iptuntap.c b/ip/iptuntap.c index b5aa0542c..11db794f7 100644 --- a/ip/iptuntap.c +++ b/ip/iptuntap.c @@ -373,7 +373,6 @@ static void show_processes(const char *name) } globfree(&globbuf); - return; } diff --git a/tc/tc_class.c b/tc/tc_class.c index f3864d22f..1a1f1fa22 100644 --- a/tc/tc_class.c +++ b/tc/tc_class.c @@ -52,7 +52,6 @@ static void usage(void) fprintf(stderr, "Where:\n"); fprintf(stderr, "QDISC_KIND := { prio | cbq | etc. }\n"); fprintf(stderr, "OPTIONS := ... try tc class add help\n"); - return; } static int tc_class_modify(int cmd, unsigned int flags, int argc, char **argv) diff --git a/tc/tc_stab.c b/tc/tc_stab.c index dc20dd195..1a0a3e3f0 100644 --- a/tc/tc_stab.c +++ b/tc/tc_stab.c @@ -40,7 +40,6 @@ static void stab_help(void) " linklayer : adapting to a linklayer e.g. atm\n" "Example: ... stab overhead 20 linklayer atm\n"); - return; } int check_size_table_opts(struct tc_sizespec *s) From cc28aad1e6d4f1a5b9e2ba79342bd7fb769a8df3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 1 Sep 2016 09:03:40 -0700 Subject: [PATCH 403/513] ip: iptuntap cleanup Minor whitespace changes --- ip/iptuntap.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ip/iptuntap.c b/ip/iptuntap.c index 11db794f7..34fb0cf3b 100644 --- a/ip/iptuntap.c +++ b/ip/iptuntap.c @@ -105,7 +105,8 @@ static int tap_del_ioctl(struct ifreq *ifr) return ret; } -static int parse_args(int argc, char **argv, struct ifreq *ifr, uid_t *uid, gid_t *gid) +static int parse_args(int argc, char **argv, + struct ifreq *ifr, uid_t *uid, gid_t *gid) { int count = 0; @@ -356,9 +357,11 @@ static void show_processes(const char *name) perror("fscanf"); break; } else if (err == 2 && - !strcmp("iff", key) && !strcmp(name, value)) { + !strcmp("iff", key) && + !strcmp(name, value)) { char *pname = pid_name(pid); - printf(" %s(%d)", pname ? pname : "", pid); + + printf(" %s(%d)", pname ? : "", pid); free(pname); } From 5898bd667a483c12ba0ca53aa0ef39f9b98d2fc9 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Tue, 30 Aug 2016 13:23:12 +0200 Subject: [PATCH 404/513] macsec: fix input of 'port', improve documentation of 'address' remove hardcoded base 10 parsing of 'port' parameter, update man page and fix usage() functions as well. Fix misleading line in man page that theoretically allowed specifying 'port' keyword right after 'sci' keyword. Provide documentation of 'address' parameter in man pages and in usage() functions as well. Signed-off-by: Davide Caratti --- ip/ipmacsec.c | 6 +++--- man/man8/ip-link.8.in | 14 +++++++++++--- man/man8/ip-macsec.8 | 12 +++++++++--- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/ip/ipmacsec.c b/ip/ipmacsec.c index 6bd1f54fb..c75e9d3ca 100644 --- a/ip/ipmacsec.c +++ b/ip/ipmacsec.c @@ -95,7 +95,7 @@ static void ipmacsec_usage(void) fprintf(stderr, "where OPTS := [ pn ] [ on | off ]\n"); fprintf(stderr, " ID := 128-bit hex string\n"); fprintf(stderr, " KEY := 128-bit hex string\n"); - fprintf(stderr, " SCI := { sci | port address }\n"); + fprintf(stderr, " SCI := { sci | port { 1..2^16-1 } address }\n"); exit(-1); } @@ -139,7 +139,7 @@ static int get_sci(__u64 *sci, const char *arg) static int get_port(__be16 *port, const char *arg) { - return get_be16(port, arg, 10); + return get_be16(port, arg, 0); } #define _STR(a) #a @@ -1069,7 +1069,7 @@ static bool check_txsc_flags(bool es, bool scb, bool sci) static void usage(FILE *f) { fprintf(f, - "Usage: ... macsec [ port PORT | sci SCI ]\n" + "Usage: ... macsec [ [ address ] port { 1..2^16-1 } | sci ]\n" " [ cipher { default | gcm-aes-128 } ]\n" " [ icvlen { 8..16 } ]\n" " [ encrypt { on | off } ]\n" diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 58247ced4..6fb5ad6c0 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -952,7 +952,9 @@ For a link of type the following additional arguments are supported: .BI "ip link add link " DEVICE " name " NAME " type macsec" -[ +[ [ +.BI address " " +] .BI port " PORT" | .BI sci " SCI" @@ -976,8 +978,14 @@ the following additional arguments are supported: .in +8 .sp -.BI port " PORT " -- sets the port number for this MACsec device. +.BI address " " +- sets the system identifier component of secure channel for this MACsec device. + +.sp +.BI port " PORT " +- sets the port number component of secure channel for this MACsec device, in a +range from 1 to 65535 inclusive. Numbers with a leading " 0 " or " 0x " are +interpreted as octal and hexadecimal, respectively. .sp .BI sci " SCI " diff --git a/man/man8/ip-macsec.8 b/man/man8/ip-macsec.8 index 105aeecd8..1aca3bdca 100644 --- a/man/man8/ip-macsec.8 +++ b/man/man8/ip-macsec.8 @@ -3,10 +3,12 @@ ip-macsec \- MACsec device configuration .SH "SYNOPSIS" .BI "ip link add link " DEVICE " name " NAME " type macsec " -[ +[ [ +.BI address " " +] .BI port " PORT" | -.BI sci " SCI" +.BI sci " " ] [ .BR cipher " { " default " | " gcm-aes-128 " } ] [" .BI icvlen " ICVLEN" @@ -62,8 +64,12 @@ ip-macsec \- MACsec device configuration .IR SCI " := { " .B sci .IR " | " -.BI port " " address " " +.BI port +.IR PORT +.BI address " " } +.br +.IR PORT " := { " 1..2^16-1 " } " .SH DESCRIPTION From d0baa1389f3a5d216f8f7085ae579c2e6e4bfcce Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Tue, 30 Aug 2016 13:23:13 +0200 Subject: [PATCH 405/513] man: ip.8: add missing 'macsec' item to OBJECT list Signed-off-by: Davide Caratti --- man/man8/ip.8 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/man/man8/ip.8 b/man/man8/ip.8 index f11fc0b9c..8ecb1996d 100644 --- a/man/man8/ip.8 +++ b/man/man8/ip.8 @@ -21,7 +21,8 @@ ip \- show / manipulate routing, devices, policy routing and tunnels .IR OBJECT " := { " .BR link " | " address " | " addrlabel " | " route " | " rule " | " neigh " | "\ ntable " | " tunnel " | " tuntap " | " maddress " | " mroute " | " mrule " | "\ - monitor " | " xfrm " | " netns " | " l2tp " | " tcp_metrics " | " token " }" + monitor " | " xfrm " | " netns " | " l2tp " | " tcp_metrics " | " token " | "\ + macsec " }" .sp .ti -8 From 0330f49ea06eed134b51a6924faf64ec6b1bb3ed Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Tue, 30 Aug 2016 13:23:14 +0200 Subject: [PATCH 406/513] macsec: fix byte ordering on input/display of 'sci' use get_be64() in place of get_u64() when parsing input 'sci' parameter, so that 'sci' can be entered using network byte order regardless the endianness of target system; use ntohll() when printing out 'sci'. While at it, improve documentation of 'sci' in ip-link.8. Signed-off-by: Davide Caratti --- ip/ipmacsec.c | 8 ++++---- man/man8/ip-link.8.in | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ip/ipmacsec.c b/ip/ipmacsec.c index c75e9d3ca..2e670e9ec 100644 --- a/ip/ipmacsec.c +++ b/ip/ipmacsec.c @@ -134,7 +134,7 @@ static int get_an(__u8 *val, const char *arg) static int get_sci(__u64 *sci, const char *arg) { - return get_u64(sci, arg, 16); + return get_be64(sci, arg, 16); } static int get_port(__be16 *port, const char *arg) @@ -776,7 +776,7 @@ static void print_tx_sc(const char *prefix, __u64 sci, __u8 encoding_sa, struct rtattr *a; int rem; - printf("%sTXSC: %016llx on SA %d\n", prefix, sci, encoding_sa); + printf("%sTXSC: %016llx on SA %d\n", prefix, ntohll(sci), encoding_sa); print_secy_stats(prefix, secy_stats); print_txsc_stats(prefix, txsc_stats); @@ -845,7 +845,7 @@ static void print_rx_sc(const char *prefix, __u64 sci, __u8 active, struct rtattr *a; int rem; - printf("%sRXSC: %016llx, state %s\n", prefix, sci, + printf("%sRXSC: %016llx, state %s\n", prefix, ntohll(sci), values_on_off[!!active]); print_rxsc_stats(prefix, rxsc_stats); @@ -1018,7 +1018,7 @@ static void macsec_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_MACSEC_SCI]) { fprintf(f, "sci %016llx ", - rta_getattr_u64(tb[IFLA_MACSEC_SCI])); + ntohll(rta_getattr_u64(tb[IFLA_MACSEC_SCI]))); } print_flag(f, tb, "protect", IFLA_MACSEC_PROTECT); diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 6fb5ad6c0..ffc4160a1 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -989,7 +989,9 @@ interpreted as octal and hexadecimal, respectively. .sp .BI sci " SCI " -- sets the SCI for this MACsec device. +- sets the secure channel identifier for this MACsec device. +.I SCI +is a 64bit wide number in hexadecimal format. .sp .BI cipher " CIPHER_SUITE " From 3cad6e5f2576cdf903311e964efa2cced1b24c6c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 1 Sep 2016 09:10:43 -0700 Subject: [PATCH 407/513] update kernel headers from 4.8-rc4 --- include/linux/if_tunnel.h | 3 +++ include/linux/libc-compat.h | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index 1fa343db4..24aa17538 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -2,6 +2,9 @@ #define _IF_TUNNEL_H_ #include +#include +#include +#include #include diff --git a/include/linux/libc-compat.h b/include/linux/libc-compat.h index 2280d3f1c..f38571dab 100644 --- a/include/linux/libc-compat.h +++ b/include/linux/libc-compat.h @@ -139,6 +139,25 @@ #endif /* _NETINET_IN_H */ +/* Coordinate with glibc netipx/ipx.h header. */ +#if defined(__NETIPX_IPX_H) + +#define __UAPI_DEF_SOCKADDR_IPX 0 +#define __UAPI_DEF_IPX_ROUTE_DEFINITION 0 +#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 0 +#define __UAPI_DEF_IPX_CONFIG_DATA 0 +#define __UAPI_DEF_IPX_ROUTE_DEF 0 + +#else /* defined(__NETIPX_IPX_H) */ + +#define __UAPI_DEF_SOCKADDR_IPX 1 +#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1 +#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1 +#define __UAPI_DEF_IPX_CONFIG_DATA 1 +#define __UAPI_DEF_IPX_ROUTE_DEF 1 + +#endif /* defined(__NETIPX_IPX_H) */ + /* Definitions for xattr.h */ #if defined(_SYS_XATTR_H) #define __UAPI_DEF_XATTR 0 @@ -179,6 +198,13 @@ #define __UAPI_DEF_IN6_PKTINFO 1 #define __UAPI_DEF_IP6_MTUINFO 1 +/* Definitions for ipx.h */ +#define __UAPI_DEF_SOCKADDR_IPX 1 +#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1 +#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1 +#define __UAPI_DEF_IPX_CONFIG_DATA 1 +#define __UAPI_DEF_IPX_ROUTE_DEF 1 + /* Definitions for xattr.h */ #define __UAPI_DEF_XATTR 1 From 45a0dc164a8105701c24043a847050efd647a3cb Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Mon, 5 Sep 2016 11:35:02 +0800 Subject: [PATCH 408/513] nstat: add sctp snmp support SCTP module was not load by default. But this should be OK since we will not load table if fdopen() failed, also opening the proc file won't load SCTP kernel module. Signed-off-by: Hangbin Liu --- misc/nstat.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/misc/nstat.c b/misc/nstat.c index 6143719e3..1cb6c7eea 100644 --- a/misc/nstat.c +++ b/misc/nstat.c @@ -76,6 +76,11 @@ static int net_snmp6_open(void) return generic_proc_open("PROC_NET_SNMP6", "net/snmp6"); } +static int net_sctp_snmp_open(void) +{ + return generic_proc_open("PROC_NET_SCTP_SNMP", "net/sctp/snmp"); +} + struct nstat_ent { struct nstat_ent *next; char *id; @@ -247,6 +252,16 @@ static void load_ugly_table(FILE *fp) } } +static void load_sctp_snmp(void) +{ + FILE *fp = fdopen(net_sctp_snmp_open(), "r"); + + if (fp) { + load_good_table(fp); + fclose(fp); + } +} + static void load_snmp(void) { FILE *fp = fdopen(net_snmp_open(), "r"); @@ -391,6 +406,7 @@ static void update_db(int interval) load_netstat(); load_snmp6(); load_snmp(); + load_sctp_snmp(); h = kern_db; kern_db = n; @@ -450,6 +466,7 @@ static void server_loop(int fd) load_netstat(); load_snmp6(); load_snmp(); + load_sctp_snmp(); for (;;) { int status; @@ -706,6 +723,7 @@ int main(int argc, char *argv[]) load_netstat(); load_snmp6(); load_snmp(); + load_sctp_snmp(); if (info_source[0] == 0) strcpy(info_source, "kernel"); } From 12f92e2e4f027ba509275464e5b14ab0522cb258 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Tue, 6 Sep 2016 14:42:52 +0800 Subject: [PATCH 409/513] gitignore: Ignore 'tags' file generated by ctags Signed-off-by: Hangbin Liu --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ef03b1742..74a5496dd 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ Config # cscope cscope.* ncscope.* +tags TAGS # git files that we don't want to ignore even it they are dot-files From 113fab78e48c14c0d2a57ae8ada95a5921f70538 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 8 Sep 2016 14:56:34 +0200 Subject: [PATCH 410/513] tuntap: Add name attribute to usage text Signed-off-by: Thomas Graf --- ip/iptuntap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/iptuntap.c b/ip/iptuntap.c index 34fb0cf3b..451f7f0ea 100644 --- a/ip/iptuntap.c +++ b/ip/iptuntap.c @@ -39,7 +39,7 @@ static void usage(void) { fprintf(stderr, "Usage: ip tuntap { add | del | show | list | lst | help } [ dev PHYS_DEV ]\n"); fprintf(stderr, " [ mode { tun | tap } ] [ user USER ] [ group GROUP ]\n"); - fprintf(stderr, " [ one_queue ] [ pi ] [ vnet_hdr ] [ multi_queue ]\n"); + fprintf(stderr, " [ one_queue ] [ pi ] [ vnet_hdr ] [ multi_queue ] [ name NAME ]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Where: USER := { STRING | NUMBER }\n"); fprintf(stderr, " GROUP := { STRING | NUMBER }\n"); From 31a29009c5e921e81ff8419c482f826de5a1a493 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 8 Sep 2016 12:33:03 +0200 Subject: [PATCH 411/513] iproute: fix documentation for ip rule scan order Hi, On Thu, Sep 08, 2016 at 11:59:55AM +0200, Michal Kubecek wrote: > On Thu, Sep 01, 2016 at 09:04:54AM -0700, Stephen Hemminger wrote: > > On Tue, 30 Aug 2016 17:32:52 -0700 > > Iskren Chernev wrote: > > > > > From 416f45b62f33017d19a9b14e7b0179807c993cbe Mon Sep 17 00:00:00 2001 > > > From: Iskren Chernev > > > Date: Tue, 30 Aug 2016 17:08:54 -0700 > > > Subject: [PATCH bug-fix] iproute: fix documentation for ip rule scan order > > > > > > --- > > > man/man8/ip-rule.8 | 2 +- > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > > > diff --git a/man/man8/ip-rule.8 b/man/man8/ip-rule.8 > > > index 1774ae3..3508d80 100644 > > > --- a/man/man8/ip-rule.8 > > > +++ b/man/man8/ip-rule.8 > > > @@ -93,7 +93,7 @@ Each policy routing rule consists of a > > > .B selector > > > and an > > > .B action predicate. > > > -The RPDB is scanned in order of decreasing priority. The selector > > > +The RPDB is scanned in order of increasing priority. The selector > > > of each rule is applied to {source address, destination address, > > > incoming > > > interface, tos, fwmark} and, if the selector matches the packet, > > > the action is performed. The action predicate may return with success. > > > -- > > > 2.4.5 > > > > Applied > > I'm sorry I didn't notice before but this just reverts the change done > by commit 49572501664d ("iproute2: clarification of various man8 pages"). > IMHO the problem is that both versions are equally confusing as the word > "priority" can be understood in two different senses. > > How about more explicit formulation, e.g. > > ... in order of decreasing logical priority (i.e. increasing numeric > values). > > Would that be better? Looks like the real issue is missing definition of priority. What about this: --- man/man8/ip-rule.8 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/man/man8/ip-rule.8 b/man/man8/ip-rule.8 index 3508d8090..13fe9f7f8 100644 --- a/man/man8/ip-rule.8 +++ b/man/man8/ip-rule.8 @@ -93,7 +93,7 @@ Each policy routing rule consists of a .B selector and an .B action predicate. -The RPDB is scanned in order of increasing priority. The selector +The RPDB is scanned in order of decreasing priority. The selector of each rule is applied to {source address, destination address, incoming interface, tos, fwmark} and, if the selector matches the packet, the action is performed. The action predicate may return with success. @@ -221,8 +221,10 @@ value to match. .TP .BI priority " PREFERENCE" -the priority of this rule. Each rule should have an explicitly -set +the priority of this rule. +.I PREFERENCE +is an unsigned integer value, higher number means lower priority. Each rule +should have an explicitly set .I unique priority value. The options preference and order are synonyms with priority. From 5f944e47ea3ec458a1545ca26a42755dca18a9d3 Mon Sep 17 00:00:00 2001 From: Parthasarathy Bhuvaragan Date: Mon, 12 Sep 2016 17:17:15 +0200 Subject: [PATCH 412/513] tipc: remove dead code remove dead code and a newline. Signed-off-by: Parthasarathy Bhuvaragan --- tipc/link.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tipc/link.c b/tipc/link.c index 061b1c534..8bdc98224 100644 --- a/tipc/link.c +++ b/tipc/link.c @@ -90,7 +90,6 @@ static int link_get_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } - static int cmd_link_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { @@ -475,8 +474,6 @@ static int cmd_link_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, mnl_attr_nest_end(nlh, attrs); return msg_doit(nlh, link_get_cb, &prop); - - return 0; } static int cmd_link_set(struct nlmsghdr *nlh, const struct cmd *cmd, From b33a69005ec98e4555726476ff9abc0f19a58546 Mon Sep 17 00:00:00 2001 From: Parthasarathy Bhuvaragan Date: Mon, 12 Sep 2016 17:17:16 +0200 Subject: [PATCH 413/513] tipc: add link monitor set threshold The command sets the activation threshold for the new cluster ring supervision. A sample usage is shown below: $ tipc link monitor set threshold 4 $ tipc link monitor set -h Usage: tipc monitor set PPROPERTY PROPERTIES threshold SIZE - Set activation threshold for monitor Acked-by: Jon Maloy Tested-by: Jon Maloy Signed-off-by: Parthasarathy Bhuvaragan --- tipc/link.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/tipc/link.c b/tipc/link.c index 8bdc98224..3469cd302 100644 --- a/tipc/link.c +++ b/tipc/link.c @@ -489,6 +489,71 @@ static int cmd_link_set(struct nlmsghdr *nlh, const struct cmd *cmd, return run_cmd(nlh, cmd, cmds, cmdl, NULL); } +static int cmd_link_mon_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, void *data) +{ + int size; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlattr *attrs; + + if (cmdl->argc != cmdl->optind + 1) { + fprintf(stderr, "error, missing value\n"); + return -EINVAL; + } + size = atoi(shift_cmdl(cmdl)); + + if (!(nlh = msg_init(buf, TIPC_NL_MON_SET))) { + fprintf(stderr, "error, message initialisation failed\n"); + return -1; + } + attrs = mnl_attr_nest_start(nlh, TIPC_NLA_MON); + + mnl_attr_put_u32(nlh, TIPC_NLA_MON_ACTIVATION_THRESHOLD, size); + + mnl_attr_nest_end(nlh, attrs); + + return msg_doit(nlh, NULL, NULL); +} + +static void cmd_link_mon_set_help(struct cmdl *cmdl) +{ + fprintf(stderr, "Usage: %s monitor set PPROPERTY\n\n" + "PROPERTIES\n" + " threshold SIZE - Set monitor activation threshold\n", + cmdl->argv[0]); +} + +static int cmd_link_mon_set(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, void *data) +{ + const struct cmd cmds[] = { + { "threshold", cmd_link_mon_set_prop, NULL }, + { NULL } + }; + + return run_cmd(nlh, cmd, cmds, cmdl, NULL); +} + +static void cmd_link_mon_help(struct cmdl *cmdl) +{ + fprintf(stderr, + "Usage: %s montior COMMAND [ARGS] ...\n\n" + "COMMANDS\n" + " set - Set monitor properties\n", + cmdl->argv[0]); +} + +static int cmd_link_mon(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, + void *data) +{ + const struct cmd cmds[] = { + { "set", cmd_link_mon_set, cmd_link_mon_set_help }, + { NULL } + }; + + return run_cmd(nlh, cmd, cmds, cmdl, NULL); +} + void cmd_link_help(struct cmdl *cmdl) { fprintf(stderr, @@ -498,7 +563,8 @@ void cmd_link_help(struct cmdl *cmdl) " list - List links\n" " get - Get various link properties\n" " set - Set various link properties\n" - " statistics - Show or reset statistics\n", + " statistics - Show or reset statistics\n" + " monitor - Show or set link supervision\n", cmdl->argv[0]); } @@ -510,6 +576,7 @@ int cmd_link(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, { "list", cmd_link_list, NULL }, { "set", cmd_link_set, cmd_link_set_help }, { "statistics", cmd_link_stat, cmd_link_stat_help }, + { "monitor", cmd_link_mon, cmd_link_mon_help }, { NULL } }; From 7da7ef9bd879f73cb5359e4a20cb1bd8a98191bf Mon Sep 17 00:00:00 2001 From: Parthasarathy Bhuvaragan Date: Mon, 12 Sep 2016 17:17:17 +0200 Subject: [PATCH 414/513] tipc: add link monitor get threshold The command prints the monitor activation threshold. A sample usage is shown below: $ tipc link monitor get threshold 32 $ tipc link monitor get -h Usage: tipc monitor get PPROPERTY PROPERTIES threshold - Get monitor activation threshold Acked-by: Jon Maloy Tested-by: Jon Maloy Signed-off-by: Parthasarathy Bhuvaragan --- tipc/link.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/tipc/link.c b/tipc/link.c index 3469cd302..3f0c32106 100644 --- a/tipc/link.c +++ b/tipc/link.c @@ -534,12 +534,65 @@ static int cmd_link_mon_set(struct nlmsghdr *nlh, const struct cmd *cmd, return run_cmd(nlh, cmd, cmds, cmdl, NULL); } +static void cmd_link_mon_get_help(struct cmdl *cmdl) +{ + fprintf(stderr, "Usage: %s monitor get PPROPERTY \n\n" + "PROPERTIES\n" + " threshold - Get monitor activation threshold\n", + cmdl->argv[0]); +} + +static int link_mon_get_cb(const struct nlmsghdr *nlh, void *data) +{ + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + struct nlattr *info[TIPC_NLA_MAX + 1] = {}; + struct nlattr *attrs[TIPC_NLA_MON_MAX + 1] = {}; + + mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); + if (!info[TIPC_NLA_MON]) + return MNL_CB_ERROR; + + mnl_attr_parse_nested(info[TIPC_NLA_MON], parse_attrs, attrs); + if (!attrs[TIPC_NLA_MON_ACTIVATION_THRESHOLD]) + return MNL_CB_ERROR; + + printf("%u\n", + mnl_attr_get_u32(attrs[TIPC_NLA_MON_ACTIVATION_THRESHOLD])); + + return MNL_CB_OK; +} + +static int cmd_link_mon_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, void *data) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + + if (!(nlh = msg_init(buf, TIPC_NL_MON_GET))) { + fprintf(stderr, "error, message initialisation failed\n"); + return -1; + } + + return msg_doit(nlh, link_mon_get_cb, NULL); +} + +static int cmd_link_mon_get(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, void *data) +{ + const struct cmd cmds[] = { + { "threshold", cmd_link_mon_get_prop, NULL}, + { NULL } + }; + + return run_cmd(nlh, cmd, cmds, cmdl, NULL); +} + static void cmd_link_mon_help(struct cmdl *cmdl) { fprintf(stderr, "Usage: %s montior COMMAND [ARGS] ...\n\n" "COMMANDS\n" - " set - Set monitor properties\n", + " set - Set monitor properties\n" + " get - Get monitor properties\n", cmdl->argv[0]); } @@ -548,6 +601,7 @@ static int cmd_link_mon(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl { const struct cmd cmds[] = { { "set", cmd_link_mon_set, cmd_link_mon_set_help }, + { "get", cmd_link_mon_get, cmd_link_mon_get_help }, { NULL } }; From 80e9807dff78336a6233ed50631524c2561a8655 Mon Sep 17 00:00:00 2001 From: Parthasarathy Bhuvaragan Date: Mon, 12 Sep 2016 17:17:18 +0200 Subject: [PATCH 415/513] tipc: add link monitor summary The monitor summary command prints the basic attributes specific to the local node. A sample usage is shown below: $ tipc link monitor summary bearer eth:data0 table_generation 15 cluster_size 8 algorithm overlapping-ring bearer eth:data1 table_generation 15 cluster_size 8 algorithm overlapping-ring $ tipc link monitor summary -h Usage: tipc monitor summary Acked-by: Jon Maloy Tested-by: Jon Maloy Signed-off-by: Parthasarathy Bhuvaragan --- tipc/link.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/tipc/link.c b/tipc/link.c index 3f0c32106..df93409f2 100644 --- a/tipc/link.c +++ b/tipc/link.c @@ -515,6 +515,49 @@ static int cmd_link_mon_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, return msg_doit(nlh, NULL, NULL); } +static int link_mon_summary_cb(const struct nlmsghdr *nlh, void *data) +{ + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + struct nlattr *info[TIPC_NLA_MAX + 1] = {}; + struct nlattr *attrs[TIPC_NLA_MON_MAX + 1] = {}; + + mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); + if (!info[TIPC_NLA_MON]) + return MNL_CB_ERROR; + + mnl_attr_parse_nested(info[TIPC_NLA_MON], parse_attrs, attrs); + + printf("\nbearer %s\n", + mnl_attr_get_str(attrs[TIPC_NLA_MON_BEARER_NAME])); + + printf(" table_generation %u\n", + mnl_attr_get_u32(attrs[TIPC_NLA_MON_LISTGEN])); + printf(" cluster_size %u\n", + mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEERCNT])); + printf(" algorithm %s\n", + attrs[TIPC_NLA_MON_ACTIVE] ? "overlapping-ring" : "full-mesh"); + + return MNL_CB_OK; +} + +static int cmd_link_mon_summary(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, void *data) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + + if (help_flag) { + fprintf(stderr, "Usage: %s monitor summary\n", cmdl->argv[0]); + return -EINVAL; + } + + if (!(nlh = msg_init(buf, TIPC_NL_MON_GET))) { + fprintf(stderr, "error, message initialisation failed\n"); + return -1; + } + + return msg_dumpit(nlh, link_mon_summary_cb, NULL); +} + static void cmd_link_mon_set_help(struct cmdl *cmdl) { fprintf(stderr, "Usage: %s monitor set PPROPERTY\n\n" @@ -592,7 +635,8 @@ static void cmd_link_mon_help(struct cmdl *cmdl) "Usage: %s montior COMMAND [ARGS] ...\n\n" "COMMANDS\n" " set - Set monitor properties\n" - " get - Get monitor properties\n", + " get - Get monitor properties\n" + " summary - Show local node monitor summary\n", cmdl->argv[0]); } @@ -602,6 +646,7 @@ static int cmd_link_mon(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl const struct cmd cmds[] = { { "set", cmd_link_mon_set, cmd_link_mon_set_help }, { "get", cmd_link_mon_get, cmd_link_mon_get_help }, + { "summary", cmd_link_mon_summary, NULL }, { NULL } }; From d2ba0b0bbb14c3755a3104d13b98b4fbac5d3cde Mon Sep 17 00:00:00 2001 From: Parthasarathy Bhuvaragan Date: Mon, 12 Sep 2016 17:17:19 +0200 Subject: [PATCH 416/513] tipc: refractor bearer to facilitate link monitor In this commit, we: 1. Export print_bearer_media() 2. Move the bearer name handling from nl_add_bearer_name() into a new function cmd_get_unique_bearer_name(). These exported functions will be used by link monitor used in subsequent commits. Signed-off-by: Parthasarathy Bhuvaragan --- tipc/bearer.c | 75 ++++++++++++++++++++++++++++++--------------------- tipc/bearer.h | 4 +++ 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/tipc/bearer.c b/tipc/bearer.c index 8729dad4a..810344f67 100644 --- a/tipc/bearer.c +++ b/tipc/bearer.c @@ -45,7 +45,7 @@ static void _print_bearer_opts(void) " window - Bearer link window\n"); } -static void _print_bearer_media(void) +void print_bearer_media(void) { fprintf(stderr, "\nMEDIA\n" @@ -192,14 +192,28 @@ static int nl_add_udp_enable_opts(struct nlmsghdr *nlh, struct opt *opts, } static int nl_add_bearer_name(struct nlmsghdr *nlh, const struct cmd *cmd, - struct cmdl *cmdl, struct opt *opts, - struct tipc_sup_media sup_media[]) + struct cmdl *cmdl, struct opt *opts, + const struct tipc_sup_media *sup_media) +{ + char bname[TIPC_MAX_BEARER_NAME]; + int err; + + if ((err = cmd_get_unique_bearer_name(cmd, cmdl, opts, bname, sup_media))) + return err; + + mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, bname); + return 0; +} + +int cmd_get_unique_bearer_name(const struct cmd *cmd, struct cmdl *cmdl, + struct opt *opts, char *bname, + const struct tipc_sup_media *sup_media) { - char id[TIPC_MAX_BEARER_NAME]; char *media; char *identifier; struct opt *opt; - struct tipc_sup_media *entry; + const struct tipc_sup_media *entry; + if (!(opt = get_opt(opts, "media"))) { if (help_flag) @@ -219,13 +233,12 @@ static int nl_add_bearer_name(struct nlmsghdr *nlh, const struct cmd *cmd, (entry->help)(cmdl, media); else fprintf(stderr, "error, missing bearer %s\n", - entry->identifier); + entry->identifier); return -EINVAL; } identifier = opt->val; - snprintf(id, sizeof(id), "%s:%s", media, identifier); - mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id); + snprintf(bname, TIPC_MAX_BEARER_NAME, "%s:%s", media, identifier); return 0; } @@ -270,13 +283,13 @@ static int udp_bearer_add(struct nlmsghdr *nlh, struct opt *opts, if ((err = getaddrinfo(ip, remport, &hints, &addr))) { fprintf(stderr, "UDP address error: %s\n", - gai_strerror(err)); + gai_strerror(err)); freeaddrinfo(addr); return err; } mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, addr->ai_addrlen, - addr->ai_addr); + addr->ai_addr); freeaddrinfo(addr); } else { fprintf(stderr, "error, missing remoteip\n"); @@ -302,7 +315,7 @@ static int cmd_bearer_add_media(struct nlmsghdr *nlh, const struct cmd *cmd, { "media", OPT_KEYVAL, NULL }, { NULL } }; - struct tipc_sup_media sup_media[] = { + const struct tipc_sup_media sup_media[] = { { "udp", "name", cmd_bearer_add_udp_help}, { NULL, }, }; @@ -366,7 +379,7 @@ static void cmd_bearer_enable_help(struct cmdl *cmdl) " domain DOMAIN - Discovery domain\n" " priority PRIORITY - Bearer priority\n", cmdl->argv[0]); - _print_bearer_media(); + print_bearer_media(); } static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd, @@ -389,9 +402,9 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd, { NULL } }; struct tipc_sup_media sup_media[] = { - { "udp", "name", cmd_bearer_enable_udp_help}, - { "eth", "device", cmd_bearer_enable_l2_help }, - { "ib", "device", cmd_bearer_enable_l2_help }, + { "udp", "name", cmd_bearer_enable_udp_help}, + { "eth", "device", cmd_bearer_enable_l2_help }, + { "ib", "device", cmd_bearer_enable_l2_help }, { NULL, }, }; @@ -449,7 +462,7 @@ static void cmd_bearer_disable_help(struct cmdl *cmdl) { fprintf(stderr, "Usage: %s bearer disable media MEDIA ARGS...\n", cmdl->argv[0]); - _print_bearer_media(); + print_bearer_media(); } static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd, @@ -465,9 +478,9 @@ static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd, { NULL } }; struct tipc_sup_media sup_media[] = { - { "udp", "name", cmd_bearer_disable_udp_help}, - { "eth", "device", cmd_bearer_disable_l2_help }, - { "ib", "device", cmd_bearer_disable_l2_help }, + { "udp", "name", cmd_bearer_disable_udp_help}, + { "eth", "device", cmd_bearer_disable_l2_help }, + { "ib", "device", cmd_bearer_disable_l2_help }, { NULL, }, }; @@ -497,7 +510,7 @@ static void cmd_bearer_set_help(struct cmdl *cmdl) fprintf(stderr, "Usage: %s bearer set OPTION media MEDIA ARGS...\n", cmdl->argv[0]); _print_bearer_opts(); - _print_bearer_media(); + print_bearer_media(); } static void cmd_bearer_set_udp_help(struct cmdl *cmdl, char *media) @@ -516,7 +529,7 @@ static void cmd_bearer_set_l2_help(struct cmdl *cmdl, char *media) } static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, - struct cmdl *cmdl, void *data) + struct cmdl *cmdl, void *data) { int err; int val; @@ -531,9 +544,9 @@ static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, { NULL } }; struct tipc_sup_media sup_media[] = { - { "udp", "name", cmd_bearer_set_udp_help}, - { "eth", "device", cmd_bearer_set_l2_help }, - { "ib", "device", cmd_bearer_set_l2_help }, + { "udp", "name", cmd_bearer_set_udp_help}, + { "eth", "device", cmd_bearer_set_l2_help }, + { "ib", "device", cmd_bearer_set_l2_help }, { NULL, }, }; @@ -592,7 +605,7 @@ static void cmd_bearer_get_help(struct cmdl *cmdl) fprintf(stderr, "Usage: %s bearer get [OPTION] media MEDIA ARGS...\n", cmdl->argv[0]); _print_bearer_opts(); - _print_bearer_media(); + print_bearer_media(); } static void cmd_bearer_get_udp_help(struct cmdl *cmdl, char *media) @@ -639,7 +652,7 @@ static int bearer_dump_udp_cb(const struct nlmsghdr *nlh, void *data) struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *) addr; if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr, - sizeof(straddr))) { + sizeof(straddr))) { fprintf(stderr, "error, parsing IPv6 addr\n"); return MNL_CB_ERROR; } @@ -705,7 +718,7 @@ static int bearer_get_udp_cb(const struct nlmsghdr *nlh, void *data) switch (cb_data->prop) { case UDP_PROP_IP: if (!inet_ntop(AF_INET6, &ipv6->sin6_addr, straddr, - sizeof(straddr))) { + sizeof(straddr))) { fprintf(stderr, "error, parsing IPv6 addr\n"); return MNL_CB_ERROR; } @@ -769,7 +782,7 @@ static int cmd_bearer_get_media(struct nlmsghdr *nlh, const struct cmd *cmd, { NULL } }; struct tipc_sup_media sup_media[] = { - { "udp", "name", cmd_bearer_get_udp_help}, + { "udp", "name", cmd_bearer_get_udp_help}, { NULL, }, }; @@ -844,9 +857,9 @@ static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, { NULL } }; struct tipc_sup_media sup_media[] = { - { "udp", "name", cmd_bearer_get_udp_help}, - { "eth", "device", cmd_bearer_get_l2_help }, - { "ib", "device", cmd_bearer_get_l2_help }, + { "udp", "name", cmd_bearer_get_udp_help}, + { "eth", "device", cmd_bearer_get_l2_help }, + { "ib", "device", cmd_bearer_get_l2_help }, { NULL, }, }; diff --git a/tipc/bearer.h b/tipc/bearer.h index 9459d65eb..c0d099630 100644 --- a/tipc/bearer.h +++ b/tipc/bearer.h @@ -19,4 +19,8 @@ extern int help_flag; int cmd_bearer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data); void cmd_bearer_help(struct cmdl *cmdl); +void print_bearer_media(void); +int cmd_get_unique_bearer_name(const struct cmd *cmd, struct cmdl *cmdl, + struct opt *opts, char *bname, + const struct tipc_sup_media *sup_media); #endif From 5b748f094ba3bcac05bd41433bd2596b25726eba Mon Sep 17 00:00:00 2001 From: Parthasarathy Bhuvaragan Date: Mon, 12 Sep 2016 17:17:20 +0200 Subject: [PATCH 417/513] tipc: add link monitor list In this commit, we list the monitor attributes. By default it lists the attributes for all bearers, otherwise the specified bearer. A sample usage is shown below: $ tipc link monitor list bearer eth:data0 node status monitored generation applied_node_status [non_applied_node:status] 1.1.1 up direct 16 UU [] 1.1.2 up direct 16 UU [] 1.1.3 up direct 16 UU [] bearer eth:data1 node status monitored generation applied_node_status [non_applied_node:status] 1.1.1 up direct 2 UU [] 1.1.2 up direct 3 UU [] 1.1.3 up direct 3 UU [] $ tipc link monitor list media eth device data0 bearer eth:data0 node status monitored generation applied_node_status [non_applied_node:status] 1.1.1 up direct 16 UU [] 1.1.2 up direct 16 UU [] 1.1.3 up direct 16 UU [] $ tipc link monitor list -h Usage: tipc monitor list [ media MEDIA ARGS...] MEDIA udp - User Datagram Protocol ib - Infiniband eth - Ethernet Acked-by: Jon Maloy Tested-by: Jon Maloy Signed-off-by: Parthasarathy Bhuvaragan --- tipc/link.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) diff --git a/tipc/link.c b/tipc/link.c index df93409f2..0b5c0491a 100644 --- a/tipc/link.c +++ b/tipc/link.c @@ -22,6 +22,7 @@ #include "cmdl.h" #include "msg.h" #include "link.h" +#include "bearer.h" static int link_list_cb(const struct nlmsghdr *nlh, void *data) { @@ -558,6 +559,240 @@ static int cmd_link_mon_summary(struct nlmsghdr *nlh, const struct cmd *cmd, return msg_dumpit(nlh, link_mon_summary_cb, NULL); } +#define STATUS_WIDTH 7 +#define MAX_NODE_WIDTH 14 /* 255.4095.4095 */ +#define MAX_DOM_GEN_WIDTH 11 /* 65535 */ +#define DIRECTLY_MON_WIDTH 10 + +#define APPL_NODE_STATUS_WIDTH 5 + +static int map_get(uint64_t up_map, int i) +{ + return (up_map & (1 << i)) >> i; +} + +/* print the applied members, since we know the the members + * are listed in ascending order, we print only the state */ +static void link_mon_print_applied(uint16_t applied, uint64_t up_map) +{ + int i; + char state; + + for (i = 0; i < applied; i++) { + /* print the delimiter for every -n- entry */ + if (i && !(i % APPL_NODE_STATUS_WIDTH)) + printf(","); + + state = map_get(up_map, i) ? 'U' : 'D'; + printf("%c", state); + } +} + +/* print the non applied members, since we dont know + * the members, we print them along with the state */ +static void link_mon_print_non_applied(uint16_t applied, uint16_t member_cnt, + uint64_t up_map, uint32_t *members) +{ + int i; + char state; + + printf(" ["); + for (i = applied; i < member_cnt; i++) { + char addr_str[16]; + + /* print the delimiter for every entry */ + if (i != applied) + printf(","); + + sprintf(addr_str, "%u.%u.%u:", tipc_zone(members[i]), + tipc_cluster(members[i]), tipc_node(members[i])); + state = map_get(up_map, i) ? 'U' : 'D'; + printf("%s%c", addr_str, state); + } + printf("]"); +} + +static void link_mon_print_peer_state(const uint32_t addr, const char *status, + const char *monitored, + const uint32_t dom_gen) +{ + char addr_str[16]; + + sprintf(addr_str, "%u.%u.%u", tipc_zone(addr), tipc_cluster(addr), + tipc_node(addr)); + + printf("%-*s", MAX_NODE_WIDTH, addr_str); + printf("%-*s", STATUS_WIDTH, status); + printf("%-*s", DIRECTLY_MON_WIDTH, monitored); + printf("%-*u", MAX_DOM_GEN_WIDTH, dom_gen); +} + +static int link_mon_peer_list_cb(const struct nlmsghdr *nlh, void *data) +{ + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + struct nlattr *attrs[TIPC_NLA_MON_PEER_MAX + 1] = {}; + struct nlattr *info[TIPC_NLA_MAX + 1] = {}; + uint16_t member_cnt; + uint32_t applied; + uint32_t dom_gen; + uint64_t up_map; + char status[16]; + char monitored[16]; + + mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); + if (!info[TIPC_NLA_MON_PEER]) + return MNL_CB_ERROR; + + mnl_attr_parse_nested(info[TIPC_NLA_MON_PEER], parse_attrs, attrs); + + (attrs[TIPC_NLA_MON_PEER_LOCAL] || attrs[TIPC_NLA_MON_PEER_HEAD]) ? + strcpy(monitored, "direct") : + strcpy(monitored, "indirect"); + + attrs[TIPC_NLA_MON_PEER_UP] ? + strcpy(status, "up") : + strcpy(status, "down"); + + dom_gen = attrs[TIPC_NLA_MON_PEER_DOMGEN] ? + mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_DOMGEN]) : 0; + + link_mon_print_peer_state(mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_ADDR]), + status, monitored, dom_gen); + + applied = mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_APPLIED]); + + if (!applied) + goto exit; + + up_map = mnl_attr_get_u64(attrs[TIPC_NLA_MON_PEER_UPMAP]); + + member_cnt = mnl_attr_get_payload_len(attrs[TIPC_NLA_MON_PEER_MEMBERS]); + + /* each tipc address occupies 4 bytes of payload, hence compensate it */ + member_cnt /= sizeof(uint32_t); + + link_mon_print_applied(applied, up_map); + + link_mon_print_non_applied(applied, member_cnt, up_map, + mnl_attr_get_payload(attrs[TIPC_NLA_MON_PEER_MEMBERS])); + +exit: + printf("\n"); + + return MNL_CB_OK; +} + +static int link_mon_peer_list(uint32_t mon_ref) +{ + struct nlmsghdr *nlh; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlattr *nest; + + if (!(nlh = msg_init(buf, TIPC_NL_MON_PEER_GET))) { + fprintf(stderr, "error, message initialisation failed\n"); + return -1; + } + + nest = mnl_attr_nest_start(nlh, TIPC_NLA_MON); + mnl_attr_put_u32(nlh, TIPC_NLA_MON_REF, mon_ref); + mnl_attr_nest_end(nlh, nest); + + return msg_dumpit(nlh, link_mon_peer_list_cb, NULL); +} + +static int link_mon_list_cb(const struct nlmsghdr *nlh, void *data) +{ + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + struct nlattr *info[TIPC_NLA_MAX + 1] = {}; + struct nlattr *attrs[TIPC_NLA_MON_MAX + 1] = {}; + char *req_bearer = data; + const char *bname; + const char *title = "node status monitored generation " + "applied_node_status [non_applied_node:status]"; + + mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); + if (!info[TIPC_NLA_MON]) + return MNL_CB_ERROR; + + mnl_attr_parse_nested(info[TIPC_NLA_MON], parse_attrs, attrs); + + bname = mnl_attr_get_str(attrs[TIPC_NLA_MON_BEARER_NAME]); + + if (*req_bearer && (strcmp(req_bearer, bname) != 0)) + return MNL_CB_OK; + + printf("\nbearer %s\n", bname); + printf("%s\n", title); + + if (mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEERCNT])) + link_mon_peer_list(mnl_attr_get_u32(attrs[TIPC_NLA_MON_REF])); + + return MNL_CB_OK; +} + +static void cmd_link_mon_list_help(struct cmdl *cmdl) +{ + fprintf(stderr, "Usage: %s monitor list [ media MEDIA ARGS...] \n\n", + cmdl->argv[0]); + print_bearer_media(); +} + +static void cmd_link_mon_list_l2_help(struct cmdl *cmdl, char *media) +{ + fprintf(stderr, + "Usage: %s monitor list media %s device DEVICE [OPTIONS]\n", + cmdl->argv[0], media); +} + +static void cmd_link_mon_list_udp_help(struct cmdl *cmdl, char *media) +{ + fprintf(stderr, + "Usage: %s monitor list media udp name NAME \n\n", + cmdl->argv[0]); +} + +static int cmd_link_mon_list(struct nlmsghdr *nlh, const struct cmd *cmd, + struct cmdl *cmdl, void *data) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + char bname[TIPC_MAX_BEARER_NAME] = {0}; + struct opt opts[] = { + { "media", OPT_KEYVAL, NULL }, + { "device", OPT_KEYVAL, NULL }, + { "name", OPT_KEYVAL, NULL }, + { NULL } + }; + struct tipc_sup_media sup_media[] = { + { "udp", "name", cmd_link_mon_list_udp_help}, + { "eth", "device", cmd_link_mon_list_l2_help }, + { "ib", "device", cmd_link_mon_list_l2_help }, + { NULL, }, + }; + + int err; + + if (parse_opts(opts, cmdl) < 0) + return -EINVAL; + + if (get_opt(opts, "media")) { + if ((err = cmd_get_unique_bearer_name(cmd, cmdl, opts, bname, + sup_media))) + return err; + } + + if (help_flag) { + cmd->help(cmdl); + return -EINVAL; + } + + if (!(nlh = msg_init(buf, TIPC_NL_MON_GET))) { + fprintf(stderr, "error, message initialisation failed\n"); + return -1; + } + + return msg_dumpit(nlh, link_mon_list_cb, bname); +} + static void cmd_link_mon_set_help(struct cmdl *cmdl) { fprintf(stderr, "Usage: %s monitor set PPROPERTY\n\n" @@ -636,6 +871,7 @@ static void cmd_link_mon_help(struct cmdl *cmdl) "COMMANDS\n" " set - Set monitor properties\n" " get - Get monitor properties\n" + " list - List all cluster members\n" " summary - Show local node monitor summary\n", cmdl->argv[0]); } @@ -646,6 +882,7 @@ static int cmd_link_mon(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl const struct cmd cmds[] = { { "set", cmd_link_mon_set, cmd_link_mon_set_help }, { "get", cmd_link_mon_get, cmd_link_mon_get_help }, + { "list", cmd_link_mon_list, cmd_link_mon_list_help }, { "summary", cmd_link_mon_summary, NULL }, { NULL } }; From 76fee71bf3a067e94aa4ee5eacb62b68f5ca63f2 Mon Sep 17 00:00:00 2001 From: Parthasarathy Bhuvaragan Date: Mon, 12 Sep 2016 17:17:21 +0200 Subject: [PATCH 418/513] tipc: update man page for link monitor Add description for the new link monitor commands. Signed-off-by: Parthasarathy Bhuvaragan --- man/man8/tipc-link.8 | 104 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/man/man8/tipc-link.8 b/man/man8/tipc-link.8 index 2ee03a0bd..fee283e5c 100644 --- a/man/man8/tipc-link.8 +++ b/man/man8/tipc-link.8 @@ -39,6 +39,29 @@ tipc-link \- show links or modify link properties .B tipc link list .br +.ti -8 +.B tipc link monitor set +.RB "{ " "threshold" " } " + +.ti -8 +.B tipc link monitor get +.RB "{ " "threshold" " } " + +.ti -8 +.B tipc link monitor summary +.br + +.ti -8 +.B tipc link monitor list +.br +.RB "[ " "media " " { " eth " | " ib " } " device +.IR "DEVICE" " ]" +.RB "|" +.br +.RB "[ " "media udp name" +.IR NAME " ]" +.br + .SH OPTIONS Options (flags) that can be passed anywhere in the command chain. .TP @@ -204,6 +227,87 @@ The link window controls how many unacknowledged messages a link endpoint can have in its transmit queue before TIPC's congestion control mechanism is activated. +.SS Monitor properties + +.TP +.B threshold +.br +The threshold specifies the cluster size exceeding which the link monitoring +algorithm will switch from "full-mesh" to "overlapping-ring". +If set of 0 the overlapping-ring monitoring is always on and if set to a +value larger than anticipated cluster size the overlapping-ring is disabled. +The default value is 32. + +.SS Monitor information + +.TP +.B table_generation +.br +Represents the event count in a node's local monitoring list. It steps every +time something changes in the local monitor list, including changes in the +local domain. + +.TP +.B cluster_size +.br +Represents the current count of cluster members. + +.TP +.B algorithm +.br +The current supervision algorithm used for neighbour monitoring for the bearer. +Possible values are full-mesh or overlapping-ring. + +.TP +.B status +.br +The node status derived by the local node. +Possible status are up or down. + +.TP +.B monitored +.br +Represent the type of monitoring chosen by the local node. +Possible values are direct or indirect. + +.TP +.B generation +.br +Represents the domain generation which is the event count in a node's local +domain. Every time something changes (peer add/remove/up/down) the domain +generation is stepped and a new version of node record is sent to inform +the neighbors about this change. The domain generation helps the receiver +of a domain record to know if it should ignore or process the record. + +.TP +.B applied_node_status +.br +The node status reported by the peer node for the succeeding peers in +the node list. The Node list is a circular list of ascending addresses +starting with the local node. +Possible status are: U or D. The status U implies up and D down. + +.TP +.B [non_applied_node:status] +.br +Represents the nodes and their status as reported by the peer node. +These nodes were not applied to the monitoring list for this peer node. +They are usually transient and occur during the cluster startup phase +or network reconfiguration. +Possible status are: U or D. The status U implies up and D down. + +.SH EXAMPLES +.PP +tipc link monitor list +.RS 4 +Shows the link monitoring information for cluster members on device data0. +.RE +.PP +tipc link monitor summary +.RS 4 +The monitor summary command prints the basic attributes. +.RE + .SH EXIT STATUS Exit status is 0 if command was successful or a positive integer upon failure. From f3af3074fd72a870332e0d9ea96d63f7d6c807dd Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 20 Sep 2016 09:25:42 -0700 Subject: [PATCH 419/513] tipc: cleanup style issues Fix style issues reported by checkpatch. --- tipc/link.c | 68 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/tipc/link.c b/tipc/link.c index 0b5c0491a..4ae1c9153 100644 --- a/tipc/link.c +++ b/tipc/link.c @@ -58,7 +58,8 @@ static int cmd_link_list(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_LINK_GET))) { + nlh = msg_init(buf, TIPC_NL_LINK_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -119,12 +120,14 @@ static int cmd_link_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, if (parse_opts(opts, cmdl) < 0) return -EINVAL; - if (!(nlh = msg_init(buf, TIPC_NL_LINK_GET))) { + nlh = msg_init(buf, TIPC_NL_LINK_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } - if (!(opt = get_opt(opts, "link"))) { + opt = get_opt(opts, "link"); + if (!opt) { fprintf(stderr, "error, missing link\n"); return -EINVAL; } @@ -183,12 +186,14 @@ static int cmd_link_stat_reset(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_LINK_RESET_STATS))) { + nlh = msg_init(buf, TIPC_NL_LINK_RESET_STATS); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } - if (!(opt = get_opt(opts, "link"))) { + opt = get_opt(opts, "link"); + if (!opt) { fprintf(stderr, "error, missing link\n"); return -EINVAL; } @@ -245,8 +250,7 @@ static int _show_link_stat(struct nlattr *attrs[], struct nlattr *prop[], mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_CNT]), mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_TOT]) / proft); - printf(" 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% " - "-16384:%u%% -32768:%u%% -66000:%u%%\n", + printf(" 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% -16384:%u%% -32768:%u%% -66000:%u%%\n", perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P0]), proft), perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P1]), proft), perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P2]), proft), @@ -374,7 +378,8 @@ static int cmd_link_stat_show(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_LINK_GET))) { + nlh = msg_init(buf, TIPC_NL_LINK_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -382,7 +387,8 @@ static int cmd_link_stat_show(struct nlmsghdr *nlh, const struct cmd *cmd, if (parse_opts(opts, cmdl) < 0) return -EINVAL; - if ((opt = get_opt(opts, "link"))) + opt = get_opt(opts, "link"); + if (opt) link = opt->val; return msg_dumpit(nlh, link_stat_show_cb, link); @@ -456,13 +462,15 @@ static int cmd_link_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, if (parse_opts(opts, cmdl) < 0) return -EINVAL; - if (!(nlh = msg_init(buf, TIPC_NL_LINK_SET))) { + nlh = msg_init(buf, TIPC_NL_LINK_SET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } attrs = mnl_attr_nest_start(nlh, TIPC_NLA_LINK); - if (!(opt = get_opt(opts, "link"))) { + opt = get_opt(opts, "link"); + if (!opt) { fprintf(stderr, "error, missing link\n"); return -EINVAL; } @@ -503,7 +511,8 @@ static int cmd_link_mon_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, } size = atoi(shift_cmdl(cmdl)); - if (!(nlh = msg_init(buf, TIPC_NL_MON_SET))) { + nlh = msg_init(buf, TIPC_NL_MON_SET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -551,7 +560,8 @@ static int cmd_link_mon_summary(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_MON_GET))) { + nlh = msg_init(buf, TIPC_NL_MON_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -572,7 +582,8 @@ static int map_get(uint64_t up_map, int i) } /* print the applied members, since we know the the members - * are listed in ascending order, we print only the state */ + * are listed in ascending order, we print only the state + */ static void link_mon_print_applied(uint16_t applied, uint64_t up_map) { int i; @@ -589,7 +600,8 @@ static void link_mon_print_applied(uint16_t applied, uint64_t up_map) } /* print the non applied members, since we dont know - * the members, we print them along with the state */ + * the members, we print them along with the state + */ static void link_mon_print_non_applied(uint16_t applied, uint16_t member_cnt, uint64_t up_map, uint32_t *members) { @@ -688,7 +700,8 @@ static int link_mon_peer_list(uint32_t mon_ref) char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *nest; - if (!(nlh = msg_init(buf, TIPC_NL_MON_PEER_GET))) { + nlh = msg_init(buf, TIPC_NL_MON_PEER_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -707,8 +720,8 @@ static int link_mon_list_cb(const struct nlmsghdr *nlh, void *data) struct nlattr *attrs[TIPC_NLA_MON_MAX + 1] = {}; char *req_bearer = data; const char *bname; - const char *title = "node status monitored generation " - "applied_node_status [non_applied_node:status]"; + const char title[] = + "node status monitored generation applied_node_status [non_applied_node:status]"; mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); if (!info[TIPC_NLA_MON]) @@ -732,7 +745,7 @@ static int link_mon_list_cb(const struct nlmsghdr *nlh, void *data) static void cmd_link_mon_list_help(struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s monitor list [ media MEDIA ARGS...] \n\n", + fprintf(stderr, "Usage: %s monitor list [ media MEDIA ARGS...]\n\n", cmdl->argv[0]); print_bearer_media(); } @@ -747,7 +760,7 @@ static void cmd_link_mon_list_l2_help(struct cmdl *cmdl, char *media) static void cmd_link_mon_list_udp_help(struct cmdl *cmdl, char *media) { fprintf(stderr, - "Usage: %s monitor list media udp name NAME \n\n", + "Usage: %s monitor list media udp name NAME\n\n", cmdl->argv[0]); } @@ -775,8 +788,9 @@ static int cmd_link_mon_list(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; if (get_opt(opts, "media")) { - if ((err = cmd_get_unique_bearer_name(cmd, cmdl, opts, bname, - sup_media))) + err = cmd_get_unique_bearer_name(cmd, cmdl, opts, bname, + sup_media); + if (err) return err; } @@ -785,7 +799,8 @@ static int cmd_link_mon_list(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_MON_GET))) { + nlh = msg_init(buf, TIPC_NL_MON_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -814,9 +829,9 @@ static int cmd_link_mon_set(struct nlmsghdr *nlh, const struct cmd *cmd, static void cmd_link_mon_get_help(struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s monitor get PPROPERTY \n\n" + fprintf(stderr, "Usage: %s monitor get PPROPERTY\n\n" "PROPERTIES\n" - " threshold - Get monitor activation threshold\n", + " threshold - Get monitor activation threshold\n", cmdl->argv[0]); } @@ -845,7 +860,8 @@ static int cmd_link_mon_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, { char buf[MNL_SOCKET_BUFFER_SIZE]; - if (!(nlh = msg_init(buf, TIPC_NL_MON_GET))) { + nlh = msg_init(buf, TIPC_NL_MON_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } From e8a67bc4cf3cb35984ce394089ce89daee41ba81 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 20 Sep 2016 09:31:42 -0700 Subject: [PATCH 420/513] update kernel headers from net-next --- include/linux/bpf.h | 1 + include/linux/if_link.h | 11 +++++++++++ include/linux/if_tunnel.h | 1 + include/linux/inet_diag.h | 14 ++++++++++++++ include/linux/pkt_cls.h | 21 ++++++++++++++++++--- include/linux/pkt_sched.h | 2 ++ include/linux/tc_act/tc_ife.h | 3 ++- include/linux/tcp.h | 3 +++ 8 files changed, 52 insertions(+), 4 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index ee3ea150a..65baf0c62 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -95,6 +95,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_SCHED_ACT, BPF_PROG_TYPE_TRACEPOINT, BPF_PROG_TYPE_XDP, + BPF_PROG_TYPE_PERF_EVENT, }; #define BPF_PSEUDO_MAP_FD 1 diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 1feb70890..b9299e33f 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -316,6 +316,7 @@ enum { IFLA_BRPORT_FLUSH, IFLA_BRPORT_MULTICAST_ROUTER, IFLA_BRPORT_PAD, + IFLA_BRPORT_MCAST_FLOOD, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) @@ -461,6 +462,7 @@ enum { enum ipvlan_mode { IPVLAN_MODE_L2 = 0, IPVLAN_MODE_L3, + IPVLAN_MODE_L3S, IPVLAN_MODE_MAX }; @@ -823,6 +825,7 @@ enum { IFLA_STATS_LINK_64, IFLA_STATS_LINK_XSTATS, IFLA_STATS_LINK_XSTATS_SLAVE, + IFLA_STATS_LINK_OFFLOAD_XSTATS, __IFLA_STATS_MAX, }; @@ -842,6 +845,14 @@ enum { }; #define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1) +/* These are stats embedded into IFLA_STATS_LINK_OFFLOAD_XSTATS */ +enum { + IFLA_OFFLOAD_XSTATS_UNSPEC, + IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */ + __IFLA_OFFLOAD_XSTATS_MAX +}; +#define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1) + /* XDP section */ enum { diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index e0c3c0a30..777150fe8 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -73,6 +73,7 @@ enum { IFLA_IPTUN_ENCAP_FLAGS, IFLA_IPTUN_ENCAP_SPORT, IFLA_IPTUN_ENCAP_DPORT, + IFLA_IPTUN_COLLECT_METADATA, __IFLA_IPTUN_MAX, }; #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index 408cebdad..f5f5c1b8e 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -123,6 +123,8 @@ enum { INET_DIAG_LOCALS, INET_DIAG_PEERS, INET_DIAG_PAD, + INET_DIAG_MARK, + INET_DIAG_BBRINFO, __INET_DIAG_MAX, }; @@ -156,8 +158,20 @@ struct tcp_dctcp_info { __u32 dctcp_ab_tot; }; +/* INET_DIAG_BBRINFO */ + +struct tcp_bbr_info { + /* u64 bw: max-filtered BW (app throughput) estimate in Byte per sec: */ + __u32 bbr_bw_lo; /* lower 32 bits of bw */ + __u32 bbr_bw_hi; /* upper 32 bits of bw */ + __u32 bbr_min_rtt; /* min-filtered RTT in uSec */ + __u32 bbr_pacing_gain; /* pacing gain shifted left 8 bits */ + __u32 bbr_cwnd_gain; /* cwnd gain shifted left 8 bits */ +}; + union tcp_cc_info { struct tcpvegas_info vegas; struct tcp_dctcp_info dctcp; + struct tcp_bbr_info bbr; }; #endif /* _INET_DIAG_H_ */ diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index a50bcc2f3..5e6e903ab 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -374,9 +374,24 @@ enum { TCA_FLOWER_KEY_UDP_DST, /* be16 */ TCA_FLOWER_FLAGS, - TCA_FLOWER_KEY_VLAN_ID, - TCA_FLOWER_KEY_VLAN_PRIO, - TCA_FLOWER_KEY_VLAN_ETH_TYPE, + TCA_FLOWER_KEY_VLAN_ID, /* be16 */ + TCA_FLOWER_KEY_VLAN_PRIO, /* u8 */ + TCA_FLOWER_KEY_VLAN_ETH_TYPE, /* be16 */ + + TCA_FLOWER_KEY_ENC_KEY_ID, /* be32 */ + TCA_FLOWER_KEY_ENC_IPV4_SRC, /* be32 */ + TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,/* be32 */ + TCA_FLOWER_KEY_ENC_IPV4_DST, /* be32 */ + TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,/* be32 */ + TCA_FLOWER_KEY_ENC_IPV6_SRC, /* struct in6_addr */ + TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,/* struct in6_addr */ + TCA_FLOWER_KEY_ENC_IPV6_DST, /* struct in6_addr */ + TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,/* struct in6_addr */ + + TCA_FLOWER_KEY_TCP_SRC_MASK, /* be16 */ + TCA_FLOWER_KEY_TCP_DST_MASK, /* be16 */ + TCA_FLOWER_KEY_UDP_SRC_MASK, /* be16 */ + TCA_FLOWER_KEY_UDP_DST_MASK, /* be16 */ __TCA_FLOWER_MAX, }; diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index 2382eed50..f8e39dbaa 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -792,6 +792,8 @@ enum { TCA_FQ_ORPHAN_MASK, /* mask applied to orphaned skb hashes */ + TCA_FQ_LOW_RATE_THRESHOLD, /* per packet delay under this rate */ + __TCA_FQ_MAX }; diff --git a/include/linux/tc_act/tc_ife.h b/include/linux/tc_act/tc_ife.h index 4ece02a77..cd18360ec 100644 --- a/include/linux/tc_act/tc_ife.h +++ b/include/linux/tc_act/tc_ife.h @@ -32,8 +32,9 @@ enum { #define IFE_META_HASHID 2 #define IFE_META_PRIO 3 #define IFE_META_QMAP 4 +#define IFE_META_TCINDEX 5 /*Can be overridden at runtime by module option*/ -#define __IFE_META_MAX 5 +#define __IFE_META_MAX 6 #define IFE_META_MAX (__IFE_META_MAX - 1) #endif diff --git a/include/linux/tcp.h b/include/linux/tcp.h index f3dcdb777..cffa3bbee 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -167,6 +167,7 @@ struct tcp_info { __u8 tcpi_backoff; __u8 tcpi_options; __u8 tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4; + __u8 tcpi_delivery_rate_app_limited:1; __u32 tcpi_rto; __u32 tcpi_ato; @@ -211,6 +212,8 @@ struct tcp_info { __u32 tcpi_min_rtt; __u32 tcpi_data_segs_in; /* RFC4898 tcpEStatsDataSegsIn */ __u32 tcpi_data_segs_out; /* RFC4898 tcpEStatsDataSegsOut */ + + __u64 tcpi_delivery_rate; }; /* for TCP_MD5SIG socket option */ From 003f0fde6959b0f759fd1cc27201eb367753443e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 8 Sep 2016 12:33:03 +0200 Subject: [PATCH 421/513] iproute: fix documentation for ip rule scan order Looks like the real issue is missing definition of priority. --- man/man8/ip-rule.8 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/man/man8/ip-rule.8 b/man/man8/ip-rule.8 index 3508d8090..13fe9f7f8 100644 --- a/man/man8/ip-rule.8 +++ b/man/man8/ip-rule.8 @@ -93,7 +93,7 @@ Each policy routing rule consists of a .B selector and an .B action predicate. -The RPDB is scanned in order of increasing priority. The selector +The RPDB is scanned in order of decreasing priority. The selector of each rule is applied to {source address, destination address, incoming interface, tos, fwmark} and, if the selector matches the packet, the action is performed. The action predicate may return with success. @@ -221,8 +221,10 @@ value to match. .TP .BI priority " PREFERENCE" -the priority of this rule. Each rule should have an explicitly -set +the priority of this rule. +.I PREFERENCE +is an unsigned integer value, higher number means lower priority. Each rule +should have an explicitly set .I unique priority value. The options preference and order are synonyms with priority. From 087dec7fcfb18fc4e8a0ec68c9c0a84cb9f03e69 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Fri, 16 Sep 2016 10:30:00 +0200 Subject: [PATCH 422/513] tc: don't accept qdisc 'handle' greater than ffff since get_qdisc_handle() truncates the input value to 16 bit, return an error and prompt "invalid qdisc ID" in case input 'handle' parameter needs more than 16 bit to be stored. Signed-off-by: Davide Caratti Acked-by: Phil Sutter --- tc/tc_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tc/tc_util.c b/tc/tc_util.c index 15e49b7ba..24ca1f1c1 100644 --- a/tc/tc_util.c +++ b/tc/tc_util.c @@ -82,7 +82,7 @@ int get_qdisc_handle(__u32 *h, const char *str) if (strcmp(str, "none") == 0) goto ok; maj = strtoul(str, &p, 16); - if (p == str) + if (p == str || maj >= (1 << 16)) return -1; maj <<= 16; if (*p != ':' && *p != 0) From e2cfe5501f99ed17e883a02c6fe81b7f9ab6f2d7 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Mon, 5 Sep 2016 11:35:28 +0200 Subject: [PATCH 423/513] vxlan: group address requires net device This is now enforced in the kernel, check also in iproute to get a better error message. Signed-off-by: Jiri Benc --- ip/iplink_vxlan.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index 7ba68bc14..bff583a72 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -266,6 +266,11 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, return -1; } + if ((gaddr || !IN6_IS_ADDR_UNSPECIFIED(&gaddr6)) && !link) { + fprintf(stderr, "vxlan: 'group' requires 'dev' to be specified\n"); + return -1; + } + if (!dst_port_set && gpe) { dstport = 4790; } else if (!dst_port_set) { From f20f5f79909fdc6327fcd015a3850645a236729d Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Fri, 9 Sep 2016 16:02:22 +0200 Subject: [PATCH 424/513] macsec: fix input range of 'icvlen' parameter the maximum possible ICV length in a MACsec frame is 16 octects, not 32: fix get_icvlen() accordingly, so that a proper error message is displayed in case input 'icvlen' is greater than 16. Signed-off-by: Davide Caratti Acked-by: Phil Sutter Acked-by: Sabrina Dubroca --- ip/ipmacsec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ip/ipmacsec.c b/ip/ipmacsec.c index 2e670e9ec..127fa1e32 100644 --- a/ip/ipmacsec.c +++ b/ip/ipmacsec.c @@ -152,9 +152,9 @@ static void get_icvlen(__u8 *icvlen, char *arg) if (ret) invarg("expected ICV length", arg); - if (*icvlen < MACSEC_MIN_ICV_LEN || *icvlen > MACSEC_MAX_ICV_LEN) + if (*icvlen < MACSEC_MIN_ICV_LEN || *icvlen > MACSEC_STD_ICV_LEN) invarg("ICV length must be in the range {" - STR(MACSEC_MIN_ICV_LEN) ".." STR(MACSEC_MAX_ICV_LEN) + STR(MACSEC_MIN_ICV_LEN) ".." STR(MACSEC_STD_ICV_LEN) "}", arg); } From b7c148803434b0eb8b9425d581f61c9d9dbc0309 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Mon, 19 Sep 2016 14:39:40 -0700 Subject: [PATCH 425/513] ip: (ipvlan) introduce L3s mode The new mode 'l3s' can be set like - ip link add link dev type ipvlan mode l3s e.g. ip link add link eth0 dev ipvl0 type ipvlan mode l3s Also did some trivial code restructuring. Signed-off-by: Mahesh Bandewar --- ip/iplink_ipvlan.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/ip/iplink_ipvlan.c b/ip/iplink_ipvlan.c index a6273be88..f7735f3a1 100644 --- a/ip/iplink_ipvlan.c +++ b/ip/iplink_ipvlan.c @@ -20,18 +20,7 @@ static void ipvlan_explain(FILE *f) { - fprintf(f, "Usage: ... ipvlan [ mode { l2 | l3 } ]\n"); -} - -static void explain(void) -{ - ipvlan_explain(stderr); -} - -static int mode_arg(void) -{ - fprintf(stderr, "Error: argument of \"mode\" must be either \"l2\", or \"l3\"\n"); - return -1; + fprintf(f, "Usage: ... ipvlan [ mode { l2 | l3 | l3s } ]\n"); } static int ipvlan_parse_opt(struct link_util *lu, int argc, char **argv, @@ -47,20 +36,24 @@ static int ipvlan_parse_opt(struct link_util *lu, int argc, char **argv, mode = IPVLAN_MODE_L2; else if (strcmp(*argv, "l3") == 0) mode = IPVLAN_MODE_L3; - else - return mode_arg(); - + else if (strcmp(*argv, "l3s") == 0) + mode = IPVLAN_MODE_L3S; + else { + fprintf(stderr, "Error: argument of \"mode\" must be either \"l2\", \"l3\" or \"l3s\"\n"); + return -1; + } addattr16(n, 1024, IFLA_IPVLAN_MODE, mode); } else if (matches(*argv, "help") == 0) { - explain(); + ipvlan_explain(stderr); return -1; } else { fprintf(stderr, "ipvlan: unknown option \"%s\"?\n", *argv); - explain(); + ipvlan_explain(stderr); return -1; } - argc--, argv++; + argc--; + argv++; } return 0; @@ -78,7 +71,8 @@ static void ipvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fprintf(f, " mode %s ", mode == IPVLAN_MODE_L2 ? "l2" : - mode == IPVLAN_MODE_L3 ? "l3" : "unknown"); + mode == IPVLAN_MODE_L3 ? "l3" : + mode == IPVLAN_MODE_L3S ? "l3s" : "unknown"); } } } From bffb68b6c28a942d5341a912f5a11894f8bcf243 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Thu, 8 Sep 2016 10:26:57 +0800 Subject: [PATCH 426/513] ip route: check ftell, fseek return value ftell() may return -1 in error case, which is not handled and therefore pass a negative offset to fseek(). The return code of fseek() is also not checked. Reported-by: Phil Sutter Signed-off-by: Hangbin Liu --- ip/iproute.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ip/iproute.c b/ip/iproute.c index 0bc013686..98bfad6cb 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -1862,6 +1862,11 @@ static int iproute_restore(void) exit(-1); pos = ftell(stdin); + if (pos == -1) { + perror("Failed to restore: ftell"); + exit(-1); + } + for (prio = 0; prio < 3; prio++) { int err; @@ -1869,7 +1874,10 @@ static int iproute_restore(void) if (err) exit(err); - fseek(stdin, pos, SEEK_SET); + if (fseek(stdin, pos, SEEK_SET) == -1) { + perror("Failed to restore: fseek"); + exit(-1); + } } exit(0); From 16c2a51dc403d82b0987f2e2e45075e4339afebd Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 21 Sep 2016 16:28:56 -0700 Subject: [PATCH 427/513] update bpf.h --- include/linux/bpf.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 65baf0c62..b8486d142 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -398,6 +398,27 @@ enum bpf_func_id { */ BPF_FUNC_skb_change_tail, + /** + * bpf_skb_pull_data(skb, len) + * The helper will pull in non-linear data in case the + * skb is non-linear and not all of len are part of the + * linear section. Only needed for read/write with direct + * packet access. + * @skb: pointer to skb + * @len: len to make read/writeable + * Return: 0 on success or negative error + */ + BPF_FUNC_skb_pull_data, + + /** + * bpf_csum_update(skb, csum) + * Adds csum into skb->csum in case of CHECKSUM_COMPLETE. + * @skb: pointer to skb + * @csum: csum to add + * Return: csum on success or negative error + */ + BPF_FUNC_csum_update, + __BPF_FUNC_MAX_ID, }; From 2f0f9aef94129643133363b4503468cdccc481cc Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Tue, 20 Sep 2016 22:43:44 -0400 Subject: [PATCH 428/513] ss: output TCP BBR diag information Dump useful TCP BBR state information from a struct tcp_bbr_info that was grabbed using the inet_diag API. We tolerate info that is shorter or longer than expected, in case the kernel is older or newer than the ss binary. We simply print the minimum of what is expected from the kernel and what is provided from the kernel. We use the same trick as that used for struct tcp_info: when the info from the kernel is shorter than we hoped, we pad the end with zeroes, and don't print fields if they are zero. The BBR output looks like: bbr:(bw:1.2Mbps,mrtt:18.965,pacing_gain:2.88672,cwnd_gain:2.88672) The motivation here is to be consistent with DCTCP, which looks like: dctcp(ce_state:23,alpha:23,ab_ecn:23,ab_tot:23) Signed-off-by: Neal Cardwell Signed-off-by: Yuchung Cheng Signed-off-by: Eric Dumazet Signed-off-by: Soheil Hassas Yeganeh --- misc/ss.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/misc/ss.c b/misc/ss.c index 3b268d999..a36ad5af8 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -788,6 +788,7 @@ struct tcpstat { bool has_fastopen_opt; bool has_wscale_opt; struct dctcpstat *dctcp; + struct tcp_bbr_info *bbr_info; }; static void sock_state_print(struct sockstat *s, const char *sock_name) @@ -1783,6 +1784,25 @@ static void tcp_stats_print(struct tcpstat *s) printf(" dctcp:fallback_mode"); } + if (s->bbr_info) { + __u64 bw; + + bw = s->bbr_info->bbr_bw_hi; + bw <<= 32; + bw |= s->bbr_info->bbr_bw_lo; + + printf(" bbr:(bw:%sbps,mrtt:%g", + sprint_bw(b1, bw * 8.0), + (double)s->bbr_info->bbr_min_rtt / 1000.0); + if (s->bbr_info->bbr_pacing_gain) + printf(",pacing_gain:%g", + (double)s->bbr_info->bbr_pacing_gain / 256.0); + if (s->bbr_info->bbr_cwnd_gain) + printf(",cwnd_gain:%g", + (double)s->bbr_info->bbr_cwnd_gain / 256.0); + printf(")"); + } + if (s->send_bps) printf(" send %sbps", sprint_bw(b1, s->send_bps)); if (s->lastsnd) @@ -2061,6 +2081,16 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, s.dctcp = dctcp; } + if (tb[INET_DIAG_BBRINFO]) { + const void *bbr_info = RTA_DATA(tb[INET_DIAG_BBRINFO]); + int len = min(RTA_PAYLOAD(tb[INET_DIAG_BBRINFO]), + sizeof(*s.bbr_info)); + + s.bbr_info = calloc(1, sizeof(*s.bbr_info)); + if (s.bbr_info && bbr_info) + memcpy(s.bbr_info, bbr_info, len); + } + if (rtt > 0 && info->tcpi_snd_mss && info->tcpi_snd_cwnd) { s.send_bps = (double) info->tcpi_snd_cwnd * (double)info->tcpi_snd_mss * 8000000. / rtt; @@ -2085,6 +2115,7 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, s.min_rtt = (double) info->tcpi_min_rtt / 1000; tcp_stats_print(&s); free(s.dctcp); + free(s.bbr_info); } } From c44003f7e7254ac972eaa1b22a686471ea4ce2d7 Mon Sep 17 00:00:00 2001 From: Liping Zhang Date: Tue, 20 Sep 2016 02:09:02 -0700 Subject: [PATCH 429/513] ipmonitor: fix ip monitor can't work when NET_NS is not enabled In ip monitor, netns_map_init will check getnsid is supported or not. But when /proc/self/ns/net does not exist, we just print out error messages and exit. So user cannot use ip monitor anymore when CONFIG_NET_NS is disabled: # ip monitor open("/proc/self/ns/net"): No such file or directory If open "/proc/self/ns/net" failed, set have_rtnl_getnsid to false. Fixes: d652ccbf8195 ("netns: allow to dump and monitor nsid") Signed-off-by: Liping Zhang Acked-by: Nicolas Dichtel --- ip/ipnetns.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ip/ipnetns.c b/ip/ipnetns.c index af8706530..ccc652c13 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -72,8 +72,8 @@ static int ipnetns_have_nsid(void) if (have_rtnl_getnsid < 0) { fd = open("/proc/self/ns/net", O_RDONLY); if (fd < 0) { - perror("open(\"/proc/self/ns/net\")"); - exit(1); + have_rtnl_getnsid = 0; + return 0; } addattr32(&req.n, 1024, NETNSA_FD, fd); From 1f4c51c0e477b8c1dd9b567e434aa127d351989a Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Mon, 5 Sep 2016 11:35:27 +0200 Subject: [PATCH 430/513] tunnels: use macros for IPv6 address comparison Replace open coded comparison of IPv6 addresses with appropriate macros. Signed-off-by: Jiri Benc --- ip/ip6tunnel.c | 8 ++++---- ip/iplink_geneve.c | 6 +++--- ip/iplink_vxlan.c | 14 +++++++------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ip/ip6tunnel.c b/ip/ip6tunnel.c index ce760bd0b..b1c0ae629 100644 --- a/ip/ip6tunnel.c +++ b/ip/ip6tunnel.c @@ -313,10 +313,10 @@ static int ip6_tnl_parm_match(const struct ip6_tnl_parm2 *p1, { return ((!p1->link || p1->link == p2->link) && (!p1->name[0] || strcmp(p1->name, p2->name) == 0) && - (memcmp(&p1->laddr, &in6addr_any, sizeof(p1->laddr)) == 0 || - memcmp(&p1->laddr, &p2->laddr, sizeof(p1->laddr)) == 0) && - (memcmp(&p1->raddr, &in6addr_any, sizeof(p1->raddr)) == 0 || - memcmp(&p1->raddr, &p2->raddr, sizeof(p1->raddr)) == 0) && + (IN6_IS_ADDR_UNSPECIFIED(&p1->laddr) || + IN6_ARE_ADDR_EQUAL(&p1->laddr, &p2->laddr)) && + (IN6_IS_ADDR_UNSPECIFIED(&p1->raddr) || + IN6_ARE_ADDR_EQUAL(&p1->raddr, &p2->raddr)) && (!p1->proto || !p2->proto || p1->proto == p2->proto) && (!p1->encap_limit || p1->encap_limit == p2->encap_limit) && (!p1->hop_limit || p1->hop_limit == p2->hop_limit) && diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c index 65af6b35e..3bfba91c6 100644 --- a/ip/iplink_geneve.c +++ b/ip/iplink_geneve.c @@ -150,7 +150,7 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, return -1; } - if (!daddr && memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) == 0) { + if (!daddr && IN6_IS_ADDR_UNSPECIFIED(&daddr6)) { fprintf(stderr, "geneve: remote link partner not specified\n"); return -1; } @@ -159,7 +159,7 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, addattr32(n, 1024, IFLA_GENEVE_ID, vni); if (daddr) addattr_l(n, 1024, IFLA_GENEVE_REMOTE, &daddr, 4); - if (memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) != 0) + if (!IN6_IS_ADDR_UNSPECIFIED(&daddr6)) addattr_l(n, 1024, IFLA_GENEVE_REMOTE6, &daddr6, sizeof(struct in6_addr)); addattr32(n, 1024, IFLA_GENEVE_LABEL, label); addattr8(n, 1024, IFLA_GENEVE_TTL, ttl); @@ -203,7 +203,7 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) struct in6_addr addr; memcpy(&addr, RTA_DATA(tb[IFLA_GENEVE_REMOTE6]), sizeof(struct in6_addr)); - if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) { + if (!IN6_IS_ADDR_UNSPECIFIED(&addr)) { if (!IN6_IS_ADDR_MULTICAST(&addr)) fprintf(f, "remote %s ", format_host(AF_INET6, sizeof(struct in6_addr), &addr)); diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index bff583a72..93af979a1 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -260,8 +260,8 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, } if ((gaddr && daddr) || - (memcmp(&gaddr6, &in6addr_any, sizeof(gaddr6)) && - memcmp(&daddr6, &in6addr_any, sizeof(daddr6)))) { + (!IN6_IS_ADDR_UNSPECIFIED(&gaddr6) && + !IN6_IS_ADDR_UNSPECIFIED(&daddr6))) { fprintf(stderr, "vxlan: both group and remote cannot be specified\n"); return -1; } @@ -286,14 +286,14 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4); else if (daddr) addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4); - if (memcmp(&gaddr6, &in6addr_any, sizeof(gaddr6)) != 0) + if (!IN6_IS_ADDR_UNSPECIFIED(&gaddr6)) addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &gaddr6, sizeof(struct in6_addr)); - else if (memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) != 0) + else if (!IN6_IS_ADDR_UNSPECIFIED(&daddr6)) addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &daddr6, sizeof(struct in6_addr)); if (saddr) addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4); - else if (memcmp(&saddr6, &in6addr_any, sizeof(saddr6)) != 0) + else if (!IN6_IS_ADDR_UNSPECIFIED(&saddr6)) addattr_l(n, 1024, IFLA_VXLAN_LOCAL6, &saddr6, sizeof(struct in6_addr)); if (link) @@ -370,7 +370,7 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) struct in6_addr addr; memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_GROUP6]), sizeof(struct in6_addr)); - if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) { + if (!IN6_IS_ADDR_UNSPECIFIED(&addr)) { if (IN6_IS_ADDR_MULTICAST(&addr)) fprintf(f, "group %s ", format_host(AF_INET6, sizeof(struct in6_addr), &addr)); @@ -390,7 +390,7 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) struct in6_addr addr; memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_LOCAL6]), sizeof(struct in6_addr)); - if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) + if (!IN6_IS_ADDR_UNSPECIFIED(&addr)) fprintf(f, "local %s ", format_host(AF_INET6, sizeof(struct in6_addr), &addr)); } From 4bfe6825367010112853d1763a51bcf20f16565c Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Mon, 19 Sep 2016 17:03:14 -0700 Subject: [PATCH 431/513] iptnl: add support for collect_md flag in IPv4 and IPv6 tunnels Signed-off-by: Alexei Starovoitov --- ip/link_ip6tnl.c | 10 ++++++++++ ip/link_iptnl.c | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c index 59162a336..051c89f4f 100644 --- a/ip/link_ip6tnl.c +++ b/ip/link_ip6tnl.c @@ -40,6 +40,7 @@ static void print_usage(FILE *f) fprintf(f, " [ noencap ] [ encap { fou | gue | none } ]\n"); fprintf(f, " [ encap-sport PORT ] [ encap-dport PORT ]\n"); fprintf(f, " [ [no]encap-csum ] [ [no]encap-csum6 ] [ [no]encap-remcsum ]\n"); + fprintf(f, " [ external ]\n"); fprintf(f, "\n"); fprintf(f, "Where: NAME := STRING\n"); fprintf(f, " ADDR := IPV6_ADDRESS\n"); @@ -89,6 +90,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, __u16 encapflags = TUNNEL_ENCAP_FLAG_CSUM6; __u16 encapsport = 0; __u16 encapdport = 0; + __u8 metadata = 0; if (!(n->nlmsg_flags & NLM_F_CREATE)) { if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { @@ -141,6 +143,8 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, if (iptuninfo[IFLA_IPTUN_PROTO]) proto = rta_getattr_u8(iptuninfo[IFLA_IPTUN_PROTO]); + if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA]) + metadata = 1; } while (argc > 0) { @@ -277,12 +281,18 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM; } else if (strcmp(*argv, "noencap-remcsum") == 0) { encapflags |= ~TUNNEL_ENCAP_FLAG_REMCSUM; + } else if (strcmp(*argv, "external") == 0) { + metadata = 1; } else usage(); argc--, argv++; } addattr8(n, 1024, IFLA_IPTUN_PROTO, proto); + if (metadata) { + addattr_l(n, 1024, IFLA_IPTUN_COLLECT_METADATA, NULL, 0); + return 0; + } addattr_l(n, 1024, IFLA_IPTUN_LOCAL, &laddr, sizeof(laddr)); addattr_l(n, 1024, IFLA_IPTUN_REMOTE, &raddr, sizeof(raddr)); addattr8(n, 1024, IFLA_IPTUN_TTL, hop_limit); diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c index 7ec377791..1875348a2 100644 --- a/ip/link_iptnl.c +++ b/ip/link_iptnl.c @@ -36,6 +36,7 @@ static void print_usage(FILE *f, int sit) fprintf(f, " [ mode { ip6ip | ipip | any } ]\n"); fprintf(f, " [ isatap ]\n"); } + fprintf(f, " [ external ]\n"); fprintf(f, "\n"); fprintf(f, "Where: NAME := STRING\n"); fprintf(f, " ADDR := { IP_ADDRESS | any }\n"); @@ -85,6 +86,7 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, __u16 encapflags = 0; __u16 encapsport = 0; __u16 encapdport = 0; + __u8 metadata = 0; if (!(n->nlmsg_flags & NLM_F_CREATE)) { if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { @@ -161,6 +163,8 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) ip6rdrelayprefixlen = rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); + if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA]) + metadata = 1; } while (argc > 0) { @@ -257,6 +261,8 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM; } else if (strcmp(*argv, "noencap-remcsum") == 0) { encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM; + } else if (strcmp(*argv, "external") == 0) { + metadata = 1; } else if (strcmp(*argv, "6rd-prefix") == 0) { inet_prefix prefix; @@ -291,6 +297,11 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, exit(-1); } + if (metadata) { + addattr_l(n, 1024, IFLA_IPTUN_COLLECT_METADATA, NULL, 0); + return 0; + } + addattr32(n, 1024, IFLA_IPTUN_LINK, link); addattr32(n, 1024, IFLA_IPTUN_LOCAL, laddr); addattr32(n, 1024, IFLA_IPTUN_REMOTE, raddr); From ec75249b141e99b978e6494345d468595f5b829f Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 22 Sep 2016 01:02:50 +0900 Subject: [PATCH 432/513] ss: Support displaying and filtering on socket marks. This allows the user to dump sockets with a given mark (via "fwmark = 0x1234/0x1234" or "fwmark = 12345", etc.) , and to display the socket marks of dumped sockets. The relevant kernel commits are: d545caca827b ("net: inet: diag: expose the socket mark to privileged processes.") and - a52e95abf772 ("net: diag: allow socket bytecode filters to match socket marks") Signed-off-by: Lorenzo Colitti --- misc/ss.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ misc/ssfilter.h | 2 ++ misc/ssfilter.y | 23 ++++++++++++++++++++-- 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index a36ad5af8..7f8453418 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -737,6 +737,7 @@ struct sockstat { unsigned long long sk; char *name; char *peer_name; + __u32 mark; }; struct dctcpstat { @@ -808,6 +809,9 @@ static void sock_details_print(struct sockstat *s) printf(" ino:%u", s->ino); printf(" sk:%llx", s->sk); + + if (s->mark) + printf(" fwmark:0x%x", s->mark); } static void sock_addr_print_width(int addr_len, const char *addr, char *delim, @@ -1047,6 +1051,8 @@ struct aafilter { inet_prefix addr; int port; unsigned int iface; + __u32 mark; + __u32 mask; struct aafilter *next; }; @@ -1166,6 +1172,12 @@ static int run_ssfilter(struct ssfilter *f, struct sockstat *s) struct aafilter *a = (void *)f->pred; return s->iface == a->iface; + } + case SSF_MARKMASK: + { + struct aafilter *a = (void *)f->pred; + + return (s->mark & a->mask) == a->mark; } /* Yup. It is recursion. Sorry. */ case SSF_AND: @@ -1341,6 +1353,23 @@ static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode) { /* bytecompile for SSF_DEVCOND not supported yet */ return 0; + } + case SSF_MARKMASK: + { + struct aafilter *a = (void *)f->pred; + struct instr { + struct inet_diag_bc_op op; + struct inet_diag_markcond cond; + }; + int inslen = sizeof(struct instr); + + if (!(*bytecode = malloc(inslen))) abort(); + ((struct instr *)*bytecode)[0] = (struct instr) { + { INET_DIAG_BC_MARK_COND, inslen, inslen + 4 }, + { a->mark, a->mask}, + }; + + return inslen; } default: abort(); @@ -1621,6 +1650,25 @@ void *parse_hostcond(char *addr, bool is_port) return res; } +void *parse_markmask(const char *markmask) +{ + struct aafilter a, *res; + + if (strchr(markmask, '/')) { + if (sscanf(markmask, "%i/%i", &a.mark, &a.mask) != 2) + return NULL; + } else { + a.mask = 0xffffffff; + if (sscanf(markmask, "%i", &a.mark) != 1) + return NULL; + } + + res = malloc(sizeof(*res)); + if (res) + memcpy(res, &a, sizeof(a)); + return res; +} + static char *proto_name(int protocol) { switch (protocol) { @@ -2138,6 +2186,10 @@ static void parse_diag_msg(struct nlmsghdr *nlh, struct sockstat *s) s->iface = r->id.idiag_if; s->sk = cookie_sk_get(&r->id.idiag_cookie[0]); + s->mark = 0; + if (tb[INET_DIAG_MARK]) + s->mark = *(__u32 *) RTA_DATA(tb[INET_DIAG_MARK]); + if (s->local.family == AF_INET) s->local.bytelen = s->remote.bytelen = 4; else diff --git a/misc/ssfilter.h b/misc/ssfilter.h index c7db8eee9..dfc5b938c 100644 --- a/misc/ssfilter.h +++ b/misc/ssfilter.h @@ -9,6 +9,7 @@ #define SSF_S_LE 8 #define SSF_S_AUTO 9 #define SSF_DEVCOND 10 +#define SSF_MARKMASK 11 #include @@ -22,3 +23,4 @@ struct ssfilter int ssfilter_parse(struct ssfilter **f, int argc, char **argv, FILE *fp); void *parse_hostcond(char *addr, bool is_port); void *parse_devcond(char *name); +void *parse_markmask(const char *markmask); diff --git a/misc/ssfilter.y b/misc/ssfilter.y index 14bf9817f..ba82b65f7 100644 --- a/misc/ssfilter.y +++ b/misc/ssfilter.y @@ -36,7 +36,7 @@ static void yyerror(char *s) %} -%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND DEVCOND DEVNAME +%token HOSTCOND DCOND SCOND DPORT SPORT LEQ GEQ NEQ AUTOBOUND DEVCOND DEVNAME MARKMASK FWMARK %left '|' %left '&' %nonassoc '!' @@ -116,7 +116,14 @@ expr: DCOND HOSTCOND { $$ = alloc_node(SSF_NOT, alloc_node(SSF_DEVCOND, $3)); } - + | FWMARK '=' MARKMASK + { + $$ = alloc_node(SSF_MARKMASK, $3); + } + | FWMARK NEQ MARKMASK + { + $$ = alloc_node(SSF_NOT, alloc_node(SSF_MARKMASK, $3)); + } | AUTOBOUND { $$ = alloc_node(SSF_S_AUTO, NULL); @@ -249,6 +256,10 @@ int yylex(void) tok_type = DEVNAME; return DEVNAME; } + if (strcmp(curtok, "fwmark") == 0) { + tok_type = FWMARK; + return FWMARK; + } if (strcmp(curtok, ">=") == 0 || strcmp(curtok, "ge") == 0 || strcmp(curtok, "geq") == 0) @@ -283,6 +294,14 @@ int yylex(void) } return DEVCOND; } + if (tok_type == FWMARK) { + yylval = (void*)parse_markmask(curtok); + if (yylval == NULL) { + fprintf(stderr, "Cannot parse mark %s.\n", curtok); + exit(1); + } + return MARKMASK; + } yylval = (void*)parse_hostcond(curtok, tok_type == SPORT || tok_type == DPORT); if (yylval == NULL) { fprintf(stderr, "Cannot parse dst/src address.\n"); From d1f338b31858005b2550da05098d56ea4e8fd401 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Thu, 22 Sep 2016 16:40:28 +0800 Subject: [PATCH 433/513] misc/ss: tcp cwnd should be unsigned tcp->snd_cwd is a u32, but ss treats it like a signed int. This may results in negative bandwidth calculations. Signed-off-by: Hangbin Liu Acked-by: Phil Sutter --- misc/ss.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index 7f8453418..dd77b8153 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -755,11 +755,12 @@ struct tcpstat { int probes; char cong_alg[16]; double rto, ato, rtt, rttvar; - int qack, cwnd, ssthresh, backoff; + int qack, ssthresh, backoff; double send_bps; int snd_wscale; int rcv_wscale; int mss; + unsigned int cwnd; unsigned int lastsnd; unsigned int lastrcv; unsigned int lastack; @@ -1805,7 +1806,7 @@ static void tcp_stats_print(struct tcpstat *s) if (s->mss) printf(" mss:%d", s->mss); if (s->cwnd) - printf(" cwnd:%d", s->cwnd); + printf(" cwnd:%u", s->cwnd); if (s->ssthresh) printf(" ssthresh:%d", s->ssthresh); @@ -1924,7 +1925,7 @@ static int tcp_show_line(char *line, const struct filter *f, int family) return 0; opt[0] = 0; - n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %d %d %[^\n]\n", + n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %u %d %[^\n]\n", &s.ss.state, &s.ss.wq, &s.ss.rq, &s.timer, &s.timeout, &s.retrans, &s.ss.uid, &s.probes, &s.ss.ino, &s.ss.refcnt, &s.ss.sk, &rto, &ato, &s.qack, &s.cwnd, From 77089b583aee6128763a3277bf44d2f5d90f9035 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Thu, 22 Sep 2016 16:40:28 +0800 Subject: [PATCH 434/513] misc/ss: tcp cwnd should be unsigned tcp->snd_cwd is a u32, but ss treats it like a signed int. This may results in negative bandwidth calculations. Signed-off-by: Hangbin Liu Acked-by: Phil Sutter --- misc/ss.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index 3b268d999..f67557a6a 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -754,11 +754,12 @@ struct tcpstat { int probes; char cong_alg[16]; double rto, ato, rtt, rttvar; - int qack, cwnd, ssthresh, backoff; + int qack, ssthresh, backoff; double send_bps; int snd_wscale; int rcv_wscale; int mss; + unsigned int cwnd; unsigned int lastsnd; unsigned int lastrcv; unsigned int lastack; @@ -1756,7 +1757,7 @@ static void tcp_stats_print(struct tcpstat *s) if (s->mss) printf(" mss:%d", s->mss); if (s->cwnd) - printf(" cwnd:%d", s->cwnd); + printf(" cwnd:%u", s->cwnd); if (s->ssthresh) printf(" ssthresh:%d", s->ssthresh); @@ -1856,7 +1857,7 @@ static int tcp_show_line(char *line, const struct filter *f, int family) return 0; opt[0] = 0; - n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %d %d %[^\n]\n", + n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %u %d %[^\n]\n", &s.ss.state, &s.ss.wq, &s.ss.rq, &s.timer, &s.timeout, &s.retrans, &s.ss.uid, &s.probes, &s.ss.ino, &s.ss.refcnt, &s.ss.sk, &rto, &ato, &s.qack, &s.cwnd, From 22a84711f445ca48bf5633775a02278f066c7232 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Tue, 20 Sep 2016 18:02:12 +0800 Subject: [PATCH 435/513] ip: Use specific slave id The original bond/bridge/vrf and slaves use same id, which make people confused. Use bond/bridge/vrf_slave as id name will make code more clear. Acked-by: Phil Sutter Signed-off-by: Hangbin Liu --- ip/ip_common.h | 2 -- ip/ipaddress.c | 4 +++- ip/iplink.c | 36 +++++++----------------------------- ip/iplink_bond_slave.c | 3 +-- ip/iplink_bridge_slave.c | 3 +-- ip/iplink_vrf.c | 3 +-- ip/ipmacsec.c | 1 - 7 files changed, 13 insertions(+), 39 deletions(-) diff --git a/ip/ip_common.h b/ip/ip_common.h index 93ff5bce4..1c1cbdf0a 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -83,11 +83,9 @@ struct link_util { struct rtattr *); void (*print_help)(struct link_util *, int, char **, FILE *); - bool slave; }; struct link_util *get_link_kind(const char *kind); -struct link_util *get_link_slave_kind(const char *slave_kind); void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len); diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 76bd7b356..fcc3c538d 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -232,6 +232,7 @@ static void print_linktype(FILE *fp, struct rtattr *tb) struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct link_util *lu; struct link_util *slave_lu; + char slave[32]; char *kind; char *slave_kind; @@ -265,8 +266,9 @@ static void print_linktype(FILE *fp, struct rtattr *tb) fprintf(fp, "%s", _SL_); fprintf(fp, " %s_slave ", slave_kind); + snprintf(slave, sizeof(slave), "%s_slave", slave_kind); - slave_lu = get_link_slave_kind(slave_kind); + slave_lu = get_link_kind(slave); if (slave_lu && slave_lu->print_opt) { struct rtattr *attr[slave_lu->maxattr+1], **data = NULL; diff --git a/ip/iplink.c b/ip/iplink.c index 6b1db18a6..dec8268a0 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -119,15 +119,14 @@ static int on_off(const char *msg, const char *realval) static void *BODY; /* cached dlopen(NULL) handle */ static struct link_util *linkutil_list; -static struct link_util *__get_link_kind(const char *id, bool slave) +struct link_util *get_link_kind(const char *id) { void *dlh; char buf[256]; struct link_util *l; for (l = linkutil_list; l; l = l->next) - if (strcmp(l->id, id) == 0 && - l->slave == slave) + if (strcmp(l->id, id) == 0) return l; snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id); @@ -142,10 +141,7 @@ static struct link_util *__get_link_kind(const char *id, bool slave) } } - if (slave) - snprintf(buf, sizeof(buf), "%s_slave_link_util", id); - else - snprintf(buf, sizeof(buf), "%s_link_util", id); + snprintf(buf, sizeof(buf), "%s_link_util", id); l = dlsym(dlh, buf); if (l == NULL) return NULL; @@ -155,16 +151,6 @@ static struct link_util *__get_link_kind(const char *id, bool slave) return l; } -struct link_util *get_link_kind(const char *id) -{ - return __get_link_kind(id, false); -} - -struct link_util *get_link_slave_kind(const char *id) -{ - return __get_link_kind(id, true); -} - static int get_link_mode(const char *mode) { if (strcasecmp(mode, "default") == 0) @@ -872,26 +858,18 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) if (type) { struct rtattr *linkinfo; - char slavebuf[128], *ulinep = strchr(type, '_'); + char *ulinep = strchr(type, '_'); int iflatype; linkinfo = addattr_nest(&req.n, sizeof(req), IFLA_LINKINFO); addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type, strlen(type)); - if (ulinep && !strcmp(ulinep, "_slave")) { - strncpy(slavebuf, type, sizeof(slavebuf)); - slavebuf[sizeof(slavebuf) - 1] = '\0'; - ulinep = strchr(slavebuf, '_'); - /* check in case it was after sizeof(slavebuf) - 1*/ - if (ulinep) - *ulinep = '\0'; - lu = get_link_slave_kind(slavebuf); + lu = get_link_kind(type); + if (ulinep && !strcmp(ulinep, "_slave")) iflatype = IFLA_INFO_SLAVE_DATA; - } else { - lu = get_link_kind(type); + else iflatype = IFLA_INFO_DATA; - } if (lu && argc) { struct rtattr *data = addattr_nest(&req.n, sizeof(req), iflatype); diff --git a/ip/iplink_bond_slave.c b/ip/iplink_bond_slave.c index 9c60dea8a..877e2d9ef 100644 --- a/ip/iplink_bond_slave.c +++ b/ip/iplink_bond_slave.c @@ -130,10 +130,9 @@ static void bond_slave_print_help(struct link_util *lu, int argc, char **argv, } struct link_util bond_slave_link_util = { - .id = "bond", + .id = "bond_slave", .maxattr = IFLA_BOND_SLAVE_MAX, .print_opt = bond_slave_print_opt, .parse_opt = bond_slave_parse_opt, .print_help = bond_slave_print_help, - .slave = true, }; diff --git a/ip/iplink_bridge_slave.c b/ip/iplink_bridge_slave.c index a44d4e413..6c5c59a95 100644 --- a/ip/iplink_bridge_slave.c +++ b/ip/iplink_bridge_slave.c @@ -293,10 +293,9 @@ static void bridge_slave_print_help(struct link_util *lu, int argc, char **argv, } struct link_util bridge_slave_link_util = { - .id = "bridge", + .id = "bridge_slave", .maxattr = IFLA_BRPORT_MAX, .print_opt = bridge_slave_print_opt, .parse_opt = bridge_slave_parse_opt, .print_help = bridge_slave_print_help, - .slave = true, }; diff --git a/ip/iplink_vrf.c b/ip/iplink_vrf.c index 015b41e1e..a238b2906 100644 --- a/ip/iplink_vrf.c +++ b/ip/iplink_vrf.c @@ -91,10 +91,9 @@ struct link_util vrf_link_util = { }; struct link_util vrf_slave_link_util = { - .id = "vrf", + .id = "vrf_slave", .maxattr = IFLA_VRF_PORT_MAX, .print_opt = vrf_slave_print_opt, - .slave = true, }; /* returns table id if name is a VRF device */ diff --git a/ip/ipmacsec.c b/ip/ipmacsec.c index 127fa1e32..c9252bb24 100644 --- a/ip/ipmacsec.c +++ b/ip/ipmacsec.c @@ -1265,5 +1265,4 @@ struct link_util macsec_link_util = { .parse_opt = macsec_parse_opt, .print_help = macsec_print_help, .print_opt = macsec_print_opt, - .slave = false, }; From 6cf2609ddb724164cbfa746e388b7942d09a9d64 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Tue, 4 Oct 2016 13:16:55 +0300 Subject: [PATCH 436/513] fix netlink message length checks Signed-off-by: Igor Ryzhov --- ip/ipaddress.c | 2 +- lib/ll_map.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index fcc3c538d..361483762 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -1218,7 +1218,7 @@ static int print_selected_addrinfo(struct ifinfomsg *ifi, if (n->nlmsg_type != RTM_NEWADDR) continue; - if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa))) + if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifa))) return -1; if (ifa->ifa_index != ifi->ifi_index || diff --git a/lib/ll_map.c b/lib/ll_map.c index 571d11e1c..4e4556c9a 100644 --- a/lib/ll_map.c +++ b/lib/ll_map.c @@ -90,7 +90,7 @@ int ll_remember_index(const struct sockaddr_nl *who, if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) return 0; - if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) + if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi))) return -1; im = ll_get_by_index(ifi->ifi_index); From afd3921ea9805553bd51a7c00efe33a819e13e8e Mon Sep 17 00:00:00 2001 From: anuradhak Date: Fri, 7 Oct 2016 09:40:18 -0700 Subject: [PATCH 437/513] bridge: Fix garbled json output seen if a vlan filter is specified json objects were started but not completed if the fdb vlan did not match the specified filter vlan. Sample output: $ bridge -j fdb show vlan 111 [{ "mac": "44:38:39:00:69:88", "dev": "br0", "vlan": 111, "master": "br0", "state": "permanent" } ] $ bridge -j fdb show vlan 100 [] $ Signed-off-by: Anuradha Karuppiah --- bridge/fdb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bridge/fdb.c b/bridge/fdb.c index c6e03793a..90f4b154c 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -100,11 +100,6 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (filter_index && filter_index != r->ndm_ifindex) return 0; - if (jw_global) { - jsonw_pretty(jw_global, 1); - jsonw_start_object(jw_global); - } - parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); @@ -114,6 +109,11 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (filter_vlan && filter_vlan != vid) return 0; + if (jw_global) { + jsonw_pretty(jw_global, 1); + jsonw_start_object(jw_global); + } + if (n->nlmsg_type == RTM_DELNEIGH) { if (jw_global) jsonw_string_field(jw_global, "opCode", "deleted"); From 58d93d00309b56dee4fd4d77d2d615f32ec79d28 Mon Sep 17 00:00:00 2001 From: Sushma Sitaram Date: Wed, 28 Sep 2016 11:30:16 -0700 Subject: [PATCH 438/513] tc: f_u32: Fill in 'linkid' provided by user Currently, 'linkid' input by the user is parsed but 'handle' is appended to the netlink message. # tc filter add dev enp1s0f1 protocol ip parent ffff: prio 99 u32 ht 800: \ order 1 link 1: offset at 0 mask 0f00 shift 6 plus 0 eat match ip \ protocol 6 ff resulted in: filter protocol ip pref 99 u32 fh 800::1 order 1 key ht 800 bkt 0 match 00060000/00ff0000 at 8 offset 0f00>>6 at 0 eat This patch results in: filter protocol ip pref 99 u32 fh 800::1 order 1 key ht 800 bkt 0 link 1: match 00060000/00ff0000 at 8 offset 0f00>>6 at 0 eat Signed-off-by Sushma Sitaram: Sushma Sitaram --- tc/f_u32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tc/f_u32.c b/tc/f_u32.c index 0ad7ed2b6..92c1fcd45 100644 --- a/tc/f_u32.c +++ b/tc/f_u32.c @@ -1071,7 +1071,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle, fprintf(stderr, "\"link\" must be a hash table.\n"); return -1; } - addattr_l(n, MAX_MSG, TCA_U32_LINK, &handle, 4); + addattr_l(n, MAX_MSG, TCA_U32_LINK, &linkid, 4); } else if (strcmp(*argv, "ht") == 0) { unsigned int ht; From d99272470a0f691d592626d4d33fedf6cb647f92 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 9 Oct 2016 18:55:58 -0700 Subject: [PATCH 439/513] update headers from pre 4.9 (net-next) --- include/linux/bpf.h | 7 +++++++ include/linux/if_link.h | 19 ++++++++++++++++++- include/linux/if_tunnel.h | 1 + include/linux/pkt_cls.h | 1 + include/linux/pkt_sched.h | 2 +- include/linux/tc_act/tc_vlan.h | 1 + include/linux/xfrm.h | 2 +- 7 files changed, 30 insertions(+), 3 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index b8486d142..d4a6e1f91 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -419,6 +419,13 @@ enum bpf_func_id { */ BPF_FUNC_csum_update, + /** + * bpf_set_hash_invalid(skb) + * Invalidate current skb>hash. + * @skb: pointer to skb + */ + BPF_FUNC_set_hash_invalid, + __BPF_FUNC_MAX_ID, }; diff --git a/include/linux/if_link.h b/include/linux/if_link.h index b9299e33f..20965c9a6 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -617,7 +617,7 @@ enum { enum { IFLA_VF_UNSPEC, IFLA_VF_MAC, /* Hardware queue specific attributes */ - IFLA_VF_VLAN, + IFLA_VF_VLAN, /* VLAN ID and QoS */ IFLA_VF_TX_RATE, /* Max TX Bandwidth Allocation */ IFLA_VF_SPOOFCHK, /* Spoof Checking on/off switch */ IFLA_VF_LINK_STATE, /* link state enable/disable/auto switch */ @@ -629,6 +629,7 @@ enum { IFLA_VF_TRUST, /* Trust VF */ IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */ IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */ + IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */ __IFLA_VF_MAX, }; @@ -645,6 +646,22 @@ struct ifla_vf_vlan { __u32 qos; }; +enum { + IFLA_VF_VLAN_INFO_UNSPEC, + IFLA_VF_VLAN_INFO, /* VLAN ID, QoS and VLAN protocol */ + __IFLA_VF_VLAN_INFO_MAX, +}; + +#define IFLA_VF_VLAN_INFO_MAX (__IFLA_VF_VLAN_INFO_MAX - 1) +#define MAX_VLAN_LIST_LEN 1 + +struct ifla_vf_vlan_info { + __u32 vf; + __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */ + __u32 qos; + __be16 vlan_proto; /* VLAN protocol either 802.1Q or 802.1ad */ +}; + struct ifla_vf_tx_rate { __u32 vf; __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */ diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index 777150fe8..4f975f570 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -39,6 +39,7 @@ #define GRE_IS_REC(f) ((f) & GRE_REC) #define GRE_IS_ACK(f) ((f) & GRE_ACK) +#define GRE_VERSION_0 __cpu_to_be16(0x0000) #define GRE_VERSION_1 __cpu_to_be16(0x0001) #define GRE_PROTO_PPP __cpu_to_be16(0x880b) #define GRE_PPTP_KEY_MASK __cpu_to_be32(0xffff) diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index 5e6e903ab..b47ed3af2 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -342,6 +342,7 @@ enum { TCA_BPF_FD, TCA_BPF_NAME, TCA_BPF_FLAGS, + TCA_BPF_FLAGS_GEN, __TCA_BPF_MAX, }; diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index f8e39dbaa..df7451d35 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -811,7 +811,7 @@ struct tc_fq_qd_stats { __u32 flows; __u32 inactive_flows; __u32 throttled_flows; - __u32 pad; + __u32 unthrottle_latency_ns; }; /* Heavy-Hitter Filter */ diff --git a/include/linux/tc_act/tc_vlan.h b/include/linux/tc_act/tc_vlan.h index be72b6e38..bddb272b8 100644 --- a/include/linux/tc_act/tc_vlan.h +++ b/include/linux/tc_act/tc_vlan.h @@ -16,6 +16,7 @@ #define TCA_VLAN_ACT_POP 1 #define TCA_VLAN_ACT_PUSH 2 +#define TCA_VLAN_ACT_MODIFY 3 struct tc_vlan { tc_gen; diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index d09be24e0..d2dd1fd65 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -298,7 +298,7 @@ enum xfrm_attr_type_t { XFRMA_ALG_AUTH_TRUNC, /* struct xfrm_algo_auth */ XFRMA_MARK, /* struct xfrm_mark */ XFRMA_TFCPAD, /* __u32 */ - XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_esn */ + XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_state_esn */ XFRMA_SA_EXTRA_FLAGS, /* __u32 */ XFRMA_PROTO, /* __u8 */ XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */ From e29a8e0537c419aa0a612db39b0feb45148a8350 Mon Sep 17 00:00:00 2001 From: Anton Aksola Date: Tue, 20 Sep 2016 06:01:27 +0000 Subject: [PATCH 440/513] iproute2: build nsid-name cache only for commands that need it The calling of netns_map_init() before command parsing introduced a performance issue with large number of namespaces. As commands such as add, del and exec do not need to iterate through /var/run/netns it would be good not no build the cache before executing these commands. Example: unpatched: time seq 1 1000 | xargs -n 1 ip netns add real 0m16.832s user 0m1.350s sys 0m15.029s patched: time seq 1 1000 | xargs -n 1 ip netns add real 0m3.859s user 0m0.132s sys 0m3.205s Signed-off-by: Anton Aksola Acked-by: Nicolas Dichtel --- ip/ip_common.h | 1 + ip/ipmonitor.c | 1 + ip/ipnetns.c | 31 ++++++++++++++++------- testsuite/tests/ip/netns/set_nsid.t | 22 ++++++++++++++++ testsuite/tests/ip/netns/set_nsid_batch.t | 18 +++++++++++++ 5 files changed, 64 insertions(+), 9 deletions(-) create mode 100755 testsuite/tests/ip/netns/set_nsid.t create mode 100755 testsuite/tests/ip/netns/set_nsid_batch.t diff --git a/ip/ip_common.h b/ip/ip_common.h index 1c1cbdf0a..0147f45a7 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -31,6 +31,7 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg); void netns_map_init(void); +void netns_nsid_socket_init(void); int print_nsid(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); int do_ipaddr(int argc, char **argv); diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c index 2090a45d7..c892b8f1c 100644 --- a/ip/ipmonitor.c +++ b/ip/ipmonitor.c @@ -301,6 +301,7 @@ int do_ipmonitor(int argc, char **argv) exit(1); ll_init_map(&rth); + netns_nsid_socket_init(); netns_map_init(); if (rtnl_listen(&rth, accept_msg, stdout) < 0) diff --git a/ip/ipnetns.c b/ip/ipnetns.c index ccc652c13..bd1e90137 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -194,6 +194,18 @@ static void netns_map_del(struct nsid_cache *c) free(c); } +void netns_nsid_socket_init(void) +{ + if (rtnsh.fd > -1 || !ipnetns_have_nsid()) + return; + + if (rtnl_open(&rtnsh, 0) < 0) { + fprintf(stderr, "Cannot open rtnetlink\n"); + exit(1); + } + +} + void netns_map_init(void) { static int initialized; @@ -204,11 +216,6 @@ void netns_map_init(void) if (initialized || !ipnetns_have_nsid()) return; - if (rtnl_open(&rtnsh, 0) < 0) { - fprintf(stderr, "Cannot open rtnetlink\n"); - exit(1); - } - dir = opendir(NETNS_RUN_DIR); if (!dir) return; @@ -775,17 +782,23 @@ static int netns_monitor(int argc, char **argv) int do_netns(int argc, char **argv) { - netns_map_init(); + netns_nsid_socket_init(); - if (argc < 1) + if (argc < 1) { + netns_map_init(); return netns_list(0, NULL); + } if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) || - (matches(*argv, "lst") == 0)) + (matches(*argv, "lst") == 0)) { + netns_map_init(); return netns_list(argc-1, argv+1); + } - if ((matches(*argv, "list-id") == 0)) + if ((matches(*argv, "list-id") == 0)) { + netns_map_init(); return netns_list_id(argc-1, argv+1); + } if (matches(*argv, "help") == 0) return usage(); diff --git a/testsuite/tests/ip/netns/set_nsid.t b/testsuite/tests/ip/netns/set_nsid.t new file mode 100755 index 000000000..606d45abc --- /dev/null +++ b/testsuite/tests/ip/netns/set_nsid.t @@ -0,0 +1,22 @@ +#!/bin/sh + +source lib/generic.sh + +ts_log "[Testing netns nsid]" + +NS=testnsid +NSID=99 + +ts_ip "$0" "Add new netns $NS" netns add $NS +ts_ip "$0" "Set $NS nsid to $NSID" netns set $NS $NSID + +ts_ip "$0" "List netns" netns list +test_on "$NS \(id: $NSID\)" + +ts_ip "$0" "List netns without explicit list or show" netns +test_on "$NS \(id: $NSID\)" + +ts_ip "$0" "List nsid" netns list-id +test_on "$NSID \(iproute2 netns name: $NS\)" + +ts_ip "$0" "Delete netns $NS" netns del $NS diff --git a/testsuite/tests/ip/netns/set_nsid_batch.t b/testsuite/tests/ip/netns/set_nsid_batch.t new file mode 100755 index 000000000..abb3f1bb9 --- /dev/null +++ b/testsuite/tests/ip/netns/set_nsid_batch.t @@ -0,0 +1,18 @@ +#!/bin/sh + +source lib/generic.sh + +ts_log "[Testing netns nsid in batch mode]" + +NS=testnsid +NSID=99 +BATCHFILE=`mktemp` + +echo "netns add $NS" >> $BATCHFILE +echo "netns set $NS $NSID" >> $BATCHFILE +echo "netns list-id" >> $BATCHFILE +ts_ip "$0" "Add ns, set nsid and list in batch mode" -b $BATCHFILE +test_on "nsid $NSID \(iproute2 netns name: $NS\)" +rm -f $BATCHFILE + +ts_ip "$0" "Delete netns $NS" netns del $NS From 63ec17a3da8138e6e363e7d89cab4a797d90fa33 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 9 Oct 2016 19:00:11 -0700 Subject: [PATCH 441/513] v4.8.0 --- include/SNAPSHOT.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/SNAPSHOT.h b/include/SNAPSHOT.h index fdf318444..1b43a94c5 100644 --- a/include/SNAPSHOT.h +++ b/include/SNAPSHOT.h @@ -1 +1 @@ -static const char SNAPSHOT[] = "160808"; +static const char SNAPSHOT[] = "161009"; From 590bf22a3437e6d9e27accdd9aebe587c0672604 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 21 Sep 2016 11:45:58 +0200 Subject: [PATCH 442/513] ipmroute: add support for age dumping Add support to dump the mroute cache entry age if the show_stats (-s) switch is provided. Example: $ ip -s mroute (0.0.0.0, 239.10.10.10) Iif: eth0 Oifs: eth0 0 packets, 0 bytes, Age 245.44 Signed-off-by: Nikolay Aleksandrov --- ip/ipmroute.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ip/ipmroute.c b/ip/ipmroute.c index 133367a23..512afcd20 100644 --- a/ip/ipmroute.c +++ b/ip/ipmroute.c @@ -169,6 +169,13 @@ int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) fprintf(fp, ", %"PRIu64" arrived on wrong iif.", (uint64_t)mfcs->mfcs_wrong_if); } + if (show_stats && tb[RTA_EXPIRES]) { + struct timeval tv; + + __jiffies_to_tv(&tv, rta_getattr_u64(tb[RTA_EXPIRES])); + fprintf(fp, ", Age %4i.%.2i", (int)tv.tv_sec, + (int)tv.tv_usec/10000); + } fprintf(fp, "\n"); fflush(fp); return 0; From 4654173e90833a84c998ee2e6850cb90bdaf4f7d Mon Sep 17 00:00:00 2001 From: Shmulik Ladkani Date: Thu, 22 Sep 2016 21:01:05 +0300 Subject: [PATCH 443/513] tc: m_vlan: Add vlan modify action The 'vlan modify' action allows to replace an existing 802.1q tag according to user provided settings. It accepts same arguments as the 'vlan push' action. For example, this replaces vid 6 with vid 5: # tc filter add dev veth0 parent ffff: pref 1 protocol 802.1q \ basic match 'meta(vlan mask 0xfff eq 6)' \ action vlan modify id 5 continue Signed-off-by: Shmulik Ladkani --- man/man8/tc-vlan.8 | 25 +++++++++++++++++++------ tc/m_vlan.c | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/man/man8/tc-vlan.8 b/man/man8/tc-vlan.8 index 4d0c5c8a1..af3de1c54 100644 --- a/man/man8/tc-vlan.8 +++ b/man/man8/tc-vlan.8 @@ -6,7 +6,7 @@ vlan - vlan manipulation module .in +8 .ti -8 .BR tc " ... " "action vlan" " { " pop " |" -.IR PUSH " } [ " CONTROL " ]" +.IR PUSH " | " MODIFY " } [ " CONTROL " ]" .ti -8 .IR PUSH " := " @@ -16,6 +16,14 @@ vlan - vlan manipulation module .IR VLANPRIO " ] " .BI id " VLANID" +.ti -8 +.IR MODIFY " := " +.BR modify " [ " protocol +.IR VLANPROTO " ]" +.BR " [ " priority +.IR VLANPRIO " ] " +.BI id " VLANID" + .ti -8 .IR CONTROL " := { " .BR reclassify " | " pipe " | " drop " | " continue " | " pass " }" @@ -23,16 +31,16 @@ vlan - vlan manipulation module The .B vlan action allows to perform 802.1Q en- or decapsulation on a packet, reflected by -the two operation modes -.IR POP " and " PUSH . +the operation modes +.IR POP ", " PUSH " and " MODIFY . The .I POP mode is simple, as no further information is required to just drop the outer-most VLAN encapsulation. The -.I PUSH -mode on the other hand requires at least a +.IR PUSH " and " MODIFY +modes require at least a .I VLANID -and allows to optionally choose the +and allow to optionally choose the .I VLANPROTO to use. .SH OPTIONS @@ -45,6 +53,11 @@ Encapsulation mode. Requires at least .B id option. .TP +.B modify +Replace mode. Existing 802.1Q tag is replaced. Requires at least +.B id +option. +.TP .BI id " VLANID" Specify the VLAN ID to encapsulate into. .I VLANID diff --git a/tc/m_vlan.c b/tc/m_vlan.c index 05a63b48f..b32f74601 100644 --- a/tc/m_vlan.c +++ b/tc/m_vlan.c @@ -19,10 +19,17 @@ #include "tc_util.h" #include +static const char * const action_names[] = { + [TCA_VLAN_ACT_POP] = "pop", + [TCA_VLAN_ACT_PUSH] = "push", + [TCA_VLAN_ACT_MODIFY] = "modify", +}; + 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"); @@ -34,6 +41,11 @@ static void usage(void) exit(-1); } +static bool has_push_attribs(int action) +{ + return action == TCA_VLAN_ACT_PUSH || action == TCA_VLAN_ACT_MODIFY; +} + static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { @@ -71,9 +83,17 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, 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(); + return -1; + } + action = TCA_VLAN_ACT_MODIFY; } else if (matches(*argv, "id") == 0) { - if (action != TCA_VLAN_ACT_PUSH) { - fprintf(stderr, "\"%s\" is only valid for push\n", + if (!has_push_attribs(action)) { + fprintf(stderr, "\"%s\" is only valid for push/modify\n", *argv); explain(); return -1; @@ -83,8 +103,8 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, invarg("id is invalid", *argv); id_set = 1; } else if (matches(*argv, "protocol") == 0) { - if (action != TCA_VLAN_ACT_PUSH) { - fprintf(stderr, "\"%s\" is only valid for push\n", + if (!has_push_attribs(action)) { + fprintf(stderr, "\"%s\" is only valid for push/modify\n", *argv); explain(); return -1; @@ -94,8 +114,8 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, invarg("protocol is invalid", *argv); proto_set = 1; } else if (matches(*argv, "priority") == 0) { - if (action != TCA_VLAN_ACT_PUSH) { - fprintf(stderr, "\"%s\" is only valid for push\n", + if (!has_push_attribs(action)) { + fprintf(stderr, "\"%s\" is only valid for push/modify\n", *argv); explain(); return -1; @@ -129,8 +149,9 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, } } - if (action == TCA_VLAN_ACT_PUSH && !id_set) { - fprintf(stderr, "id needs to be set for push\n"); + if (has_push_attribs(action) && !id_set) { + fprintf(stderr, "id needs to be set for %s\n", + action_names[action]); explain(); return -1; } @@ -186,7 +207,8 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) fprintf(f, " pop"); break; case TCA_VLAN_ACT_PUSH: - fprintf(f, " 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); From 39f8caeb96ee123fcacd9281139da076d6117b16 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 28 Sep 2016 06:23:15 -0700 Subject: [PATCH 444/513] tc: fq: display unthrottle latency In linux-4.9 fq packet scheduler got a new stat : unthrottle_latency in nano second units. Gives a good indication of system load or timer implementation latencies. Signed-off-by: Eric Dumazet --- tc/q_fq.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tc/q_fq.c b/tc/q_fq.c index 90147a6aa..c9efbfc43 100644 --- a/tc/q_fq.c +++ b/tc/q_fq.c @@ -312,6 +312,9 @@ static int fq_print_xstats(struct qdisc_util *qu, FILE *f, fprintf(f, ", %llu throttled", st->throttled); + if (st->unthrottle_latency_ns) + fprintf(f, ", %u ns latency", st->unthrottle_latency_ns); + if (st->flows_plimit) fprintf(f, ", %llu flows_plimit", st->flows_plimit); From 56e9f0ab19e3226f799610fdb28a619d45ca0c99 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Wed, 28 Sep 2016 10:58:59 +0300 Subject: [PATCH 445/513] ip link: Add support to configure SR-IOV VF to vlan protocol 802.1ad (VST QinQ) Introduce a new API that exposes a list of vlans per VF (IFLA_VF_VLAN_LIST), giving the ability for user-space application to specify it for the VF as an option to support 802.1ad (VST QinQ). We introduce struct vf_vlan_info, which extends struct vf_vlan and adds an optional VF VLAN proto parameter. Default VLAN-protocol is 802.1Q. Add IFLA_VF_VLAN_LIST in addition to IFLA_VF_VLAN to keep backward compatibility with older kernel versions. Suitable ip link tool command examples: - Set vf vlan protocol 802.1ad (S-TAG) ip link set eth0 vf 1 vlan 100 proto 802.1ad - Set vf vlan S-TAG and vlan C-TAG (VST QinQ) ip link set eth0 vf 1 vlan 100 proto 802.1ad vlan 30 proto 802.1Q - Set vf to VST (802.1Q) mode ip link set eth0 vf 1 vlan 100 proto 802.1Q - Or by omitting the new parameter (backward compatible) ip link set eth0 vf 1 vlan 100 Signed-off-by: Moshe Shemesh Signed-off-by: Tariq Toukan --- ip/ipaddress.c | 35 ++++++++++++--- ip/iplink.c | 102 +++++++++++++++++++++++++++++++++++------- man/man8/ip-link.8.in | 30 +++++++++++-- 3 files changed, 140 insertions(+), 27 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 361483762..7f05258f4 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -321,7 +321,6 @@ static void print_vf_stats64(FILE *fp, struct rtattr *vfstats); static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) { struct ifla_vf_mac *vf_mac; - struct ifla_vf_vlan *vf_vlan; struct ifla_vf_tx_rate *vf_tx_rate; struct ifla_vf_spoofchk *vf_spoofchk; struct ifla_vf_link_state *vf_linkstate; @@ -338,7 +337,6 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) parse_rtattr_nested(vf, IFLA_VF_MAX, vfinfo); vf_mac = RTA_DATA(vf[IFLA_VF_MAC]); - vf_vlan = RTA_DATA(vf[IFLA_VF_VLAN]); vf_tx_rate = RTA_DATA(vf[IFLA_VF_TX_RATE]); /* Check if the spoof checking vf info type is supported by @@ -369,10 +367,35 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) fprintf(fp, "%s vf %d MAC %s", _SL_, vf_mac->vf, ll_addr_n2a((unsigned char *)&vf_mac->mac, ETH_ALEN, 0, b1, sizeof(b1))); - if (vf_vlan->vlan) - fprintf(fp, ", vlan %d", vf_vlan->vlan); - if (vf_vlan->qos) - fprintf(fp, ", qos %d", vf_vlan->qos); + if (vf[IFLA_VF_VLAN_LIST]) { + struct rtattr *i, *vfvlanlist = vf[IFLA_VF_VLAN_LIST]; + int rem = RTA_PAYLOAD(vfvlanlist); + + for (i = RTA_DATA(vfvlanlist); + RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { + struct ifla_vf_vlan_info *vf_vlan_info = + RTA_DATA(i); + SPRINT_BUF(b2); + + if (vf_vlan_info->vlan) + fprintf(fp, ", vlan %d", vf_vlan_info->vlan); + if (vf_vlan_info->qos) + fprintf(fp, ", qos %d", vf_vlan_info->qos); + if (vf_vlan_info->vlan_proto && + vf_vlan_info->vlan_proto != htons(ETH_P_8021Q)) + fprintf(fp, ", vlan protocol %s", + ll_proto_n2a(vf_vlan_info->vlan_proto, + b2, sizeof(b2))); + + } + } else { + struct ifla_vf_vlan *vf_vlan = RTA_DATA(vf[IFLA_VF_VLAN]); + + if (vf_vlan->vlan) + fprintf(fp, ", vlan %d", vf_vlan->vlan); + if (vf_vlan->qos) + fprintf(fp, ", qos %d", vf_vlan->qos); + } if (vf_tx_rate->rate) fprintf(fp, ", tx rate %d (Mbps)", vf_tx_rate->rate); diff --git a/ip/iplink.c b/ip/iplink.c index dec8268a0..cbfc9f334 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -76,7 +76,7 @@ void iplink_usage(void) fprintf(stderr, " [ link-netnsid ID ]\n"); fprintf(stderr, " [ alias NAME ]\n"); fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n"); - fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n"); + fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] [ proto VLAN-PROTO ] ]\n"); fprintf(stderr, " [ rate TXRATE ]\n"); fprintf(stderr, " [ max_tx_rate TXRATE ]\n"); @@ -255,6 +255,60 @@ static int nl_get_ll_addr_len(unsigned int dev_index) return RTA_PAYLOAD(tb[IFLA_ADDRESS]); } +static void iplink_parse_vf_vlan_info(int vf, int *argcp, char ***argvp, + struct ifla_vf_vlan_info *ivvip) +{ + int argc = *argcp; + char **argv = *argvp; + + NEXT_ARG(); + if (get_unsigned(&ivvip->vlan, *argv, 0)) + invarg("Invalid \"vlan\" value\n", *argv); + + ivvip->vf = vf; + ivvip->qos = 0; + ivvip->vlan_proto = htons(ETH_P_8021Q); + if (NEXT_ARG_OK()) { + NEXT_ARG(); + if (matches(*argv, "qos") == 0) { + NEXT_ARG(); + if (get_unsigned(&ivvip->qos, *argv, 0)) + invarg("Invalid \"qos\" value\n", *argv); + } else { + /* rewind arg */ + PREV_ARG(); + } + } + if (NEXT_ARG_OK()) { + NEXT_ARG(); + if (matches(*argv, "proto") == 0) { + NEXT_ARG(); + if (ll_proto_a2n(&ivvip->vlan_proto, *argv)) + invarg("protocol is invalid\n", *argv); + if (ivvip->vlan_proto != htons(ETH_P_8021AD) && + ivvip->vlan_proto != htons(ETH_P_8021Q)) { + SPRINT_BUF(b1); + SPRINT_BUF(b2); + char msg[64 + sizeof(b1) + sizeof(b2)]; + + sprintf(msg, "Invalid \"vlan protocol\"" + " value - supported %s, %s\n", + ll_proto_n2a(htons(ETH_P_8021Q), + b1, sizeof(b1)), + ll_proto_n2a(htons(ETH_P_8021AD), + b2, sizeof(b2))); + invarg(msg, *argv); + } + } else { + /* rewind arg */ + PREV_ARG(); + } + } + + *argcp = argc; + *argvp = argv; +} + static int iplink_parse_vf(int vf, int *argcp, char ***argvp, struct iplink_req *req, int dev_index) { @@ -308,27 +362,41 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp, addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm)); } else if (matches(*argv, "vlan") == 0) { - struct ifla_vf_vlan ivv; + struct ifla_vf_vlan_info ivvi; - NEXT_ARG(); - if (get_unsigned(&ivv.vlan, *argv, 0)) - invarg("Invalid \"vlan\" value\n", *argv); + iplink_parse_vf_vlan_info(vf, &argc, &argv, &ivvi); + /* support the old interface in case of older kernel*/ + if (ivvi.vlan_proto == htons(ETH_P_8021Q)) { + struct ifla_vf_vlan ivv; - ivv.vf = vf; - ivv.qos = 0; - if (NEXT_ARG_OK()) { - NEXT_ARG(); - if (matches(*argv, "qos") == 0) { + ivv.vf = ivvi.vf; + ivv.vlan = ivvi.vlan; + ivv.qos = ivvi.qos; + addattr_l(&req->n, sizeof(*req), + IFLA_VF_VLAN, &ivv, sizeof(ivv)); + } else { + struct rtattr *vfvlanlist; + + vfvlanlist = addattr_nest(&req->n, sizeof(*req), + IFLA_VF_VLAN_LIST); + addattr_l(&req->n, sizeof(*req), + IFLA_VF_VLAN_INFO, &ivvi, + sizeof(ivvi)); + + while (NEXT_ARG_OK()) { NEXT_ARG(); - if (get_unsigned(&ivv.qos, *argv, 0)) - invarg("Invalid \"qos\" value\n", *argv); - } else { - /* rewind arg */ - PREV_ARG(); + if (matches(*argv, "vlan") != 0) { + PREV_ARG(); + break; + } + iplink_parse_vf_vlan_info(vf, &argc, + &argv, &ivvi); + addattr_l(&req->n, sizeof(*req), + IFLA_VF_VLAN_INFO, &ivvi, + sizeof(ivvi)); } + addattr_nest_end(&req->n, vfvlanlist); } - addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, - &ivv, sizeof(ivv)); } else if (matches(*argv, "rate") == 0) { struct ifla_vf_tx_rate ivt; diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index ffc4160a1..4dfa43fc1 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -102,10 +102,7 @@ ip-link \- network device configuration .IR LLADDR " ]" .br .in +9 -.RB "[ " vlan -.IR VLANID " [ " -.B qos -.IR VLAN-QOS " ] ]" +.RI "[ " VFVLAN-LIST " ]" .br .RB "[ " rate .IR TXRATE " ]" @@ -191,6 +188,18 @@ ip-link \- network device configuration .IR ETYPE " := [ " TYPE " |" .BR bridge_slave " | " bond_slave " ]" +.ti -8 +.IR VFVLAN-LIST " := [ " VFVLAN-LIST " ] " VFVLAN + +.ti -8 +.IR VFVLAN " := " +.RB "[ " vlan +.IR VLANID " [ " +.B qos +.IR VLAN-QOS " ] [" +.B proto +.IR VLAN-PROTO " ] ]" + .SH "DESCRIPTION" .SS ip link add - add virtual link @@ -1237,6 +1246,19 @@ and .B qos as 0 disables VLAN tagging and filtering for the VF. +.sp +.BI proto " VLAN-PROTO" +- assign VLAN PROTOCOL for the VLAN tag, either 802.1Q or 802.1ad. +Setting to 802.1ad, all traffic sent from the VF will be tagged with VLAN S-Tag. +Incoming traffic will have VLAN S-Tags stripped before being passed to the VF. +Setting to 802.1ad also enables an option to concatenate another VLAN tag, so both +S-TAG and C-TAG will be inserted/stripped for outgoing/incoming traffic, respectively. +If not specified, the value is assumed to be 802.1Q. Both the +.B vf +and +.B vlan +parameters must be specified. + .sp .BI rate " TXRATE" -- change the allowed transmit bandwidth, in Mbps, for the specified VF. From 6773bcc227668192026a53dc9755681c7cf33a1a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 9 Oct 2016 19:24:38 -0700 Subject: [PATCH 446/513] iplink: cleanup style errors Fix long strings causing checkpatch warnings --- ip/iplink.c | 113 +++++++++++++++++++++++++++------------------------- 1 file changed, 58 insertions(+), 55 deletions(-) diff --git a/ip/iplink.c b/ip/iplink.c index cbfc9f334..a8b49c523 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -45,60 +45,62 @@ static int iplink_have_newlink(void); void iplink_usage(void) { if (iplink_have_newlink()) { - fprintf(stderr, "Usage: ip link add [link DEV] [ name ] NAME\n"); - fprintf(stderr, " [ txqueuelen PACKETS ]\n"); - fprintf(stderr, " [ address LLADDR ]\n"); - fprintf(stderr, " [ broadcast LLADDR ]\n"); - fprintf(stderr, " [ mtu MTU ] [index IDX ]\n"); - fprintf(stderr, " [ numtxqueues QUEUE_COUNT ]\n"); - fprintf(stderr, " [ numrxqueues QUEUE_COUNT ]\n"); - fprintf(stderr, " type TYPE [ ARGS ]\n"); - fprintf(stderr, " ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " ip link set { DEVICE | dev DEVICE | group DEVGROUP }\n"); - fprintf(stderr, " [ { up | down } ]\n"); - fprintf(stderr, " [ type TYPE ARGS ]\n"); + fprintf(stderr, + "Usage: ip link add [link DEV] [ name ] NAME\n" + " [ txqueuelen PACKETS ]\n" + " [ address LLADDR ]\n" + " [ broadcast LLADDR ]\n" + " [ mtu MTU ] [index IDX ]\n" + " [ numtxqueues QUEUE_COUNT ]\n" + " [ numrxqueues QUEUE_COUNT ]\n" + " type TYPE [ ARGS ]\n" + " ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n" + "\n" + " ip link set { DEVICE | dev DEVICE | group DEVGROUP }\n" + " [ { up | down } ]\n" + " [ type TYPE ARGS ]\n"); } else fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n"); - fprintf(stderr, " [ arp { on | off } ]\n"); - fprintf(stderr, " [ dynamic { on | off } ]\n"); - fprintf(stderr, " [ multicast { on | off } ]\n"); - fprintf(stderr, " [ allmulticast { on | off } ]\n"); - fprintf(stderr, " [ promisc { on | off } ]\n"); - fprintf(stderr, " [ trailers { on | off } ]\n"); - fprintf(stderr, " [ txqueuelen PACKETS ]\n"); - fprintf(stderr, " [ name NEWNAME ]\n"); - fprintf(stderr, " [ address LLADDR ]\n"); - fprintf(stderr, " [ broadcast LLADDR ]\n"); - fprintf(stderr, " [ mtu MTU ]\n"); - fprintf(stderr, " [ netns { PID | NAME } ]\n"); - fprintf(stderr, " [ link-netnsid ID ]\n"); - fprintf(stderr, " [ alias NAME ]\n"); - fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n"); - fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] [ proto VLAN-PROTO ] ]\n"); - - fprintf(stderr, " [ rate TXRATE ]\n"); - fprintf(stderr, " [ max_tx_rate TXRATE ]\n"); - fprintf(stderr, " [ min_tx_rate TXRATE ]\n"); - - fprintf(stderr, " [ spoofchk { on | off} ]\n"); - fprintf(stderr, " [ query_rss { on | off} ]\n"); - fprintf(stderr, " [ state { auto | enable | disable} ] ]\n"); - fprintf(stderr, " [ trust { on | off} ] ]\n"); - fprintf(stderr, " [ master DEVICE ][ vrf NAME ]\n"); - fprintf(stderr, " [ nomaster ]\n"); - fprintf(stderr, " [ addrgenmode { eui64 | none | stable_secret | random } ]\n"); - fprintf(stderr, " [ protodown { on | off } ]\n"); - fprintf(stderr, " ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n"); + fprintf(stderr, + " [ arp { on | off } ]\n" + " [ dynamic { on | off } ]\n" + " [ multicast { on | off } ]\n" + " [ allmulticast { on | off } ]\n" + " [ promisc { on | off } ]\n" + " [ trailers { on | off } ]\n" + " [ txqueuelen PACKETS ]\n" + " [ name NEWNAME ]\n" + " [ address LLADDR ]\n" + " [ broadcast LLADDR ]\n" + " [ mtu MTU ]\n" + " [ netns { PID | NAME } ]\n" + " [ link-netnsid ID ]\n" + " [ alias NAME ]\n" + " [ vf NUM [ mac LLADDR ]\n" + " [ vlan VLANID [ qos VLAN-QOS ] [ proto VLAN-PROTO ] ]\n" + + " [ rate TXRATE ]\n" + " [ max_tx_rate TXRATE ]\n" + " [ min_tx_rate TXRATE ]\n" + + " [ spoofchk { on | off} ]\n" + " [ query_rss { on | off} ]\n" + " [ state { auto | enable | disable} ] ]\n" + " [ trust { on | off} ] ]\n" + " [ master DEVICE ][ vrf NAME ]\n" + " [ nomaster ]\n" + " [ addrgenmode { eui64 | none | stable_secret | random } ]\n" + " [ protodown { on | off } ]\n" + " ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n"); if (iplink_have_newlink()) { - fprintf(stderr, " ip link help [ TYPE ]\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"); - fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n"); - fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n"); - fprintf(stderr, " bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }\n"); + fprintf(stderr, + " ip link help [ TYPE ]\n\n" + "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n" + " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n" + " gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n" + " bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }\n"); } exit(-1); } @@ -291,8 +293,7 @@ static void iplink_parse_vf_vlan_info(int vf, int *argcp, char ***argvp, SPRINT_BUF(b2); char msg[64 + sizeof(b1) + sizeof(b2)]; - sprintf(msg, "Invalid \"vlan protocol\"" - " value - supported %s, %s\n", + sprintf(msg, "Invalid \"vlan protocol\" value - supported %s, %s\n", ll_proto_n2a(htons(ETH_P_8021Q), b1, sizeof(b1)), ll_proto_n2a(htons(ETH_P_8021AD), @@ -859,8 +860,9 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) &group, sizeof(group)); else { if (argc) { - fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n", - *argv); + fprintf(stderr, + "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n", + *argv); return -1; } if (flags & NLM_F_CREATE) { @@ -950,8 +952,9 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) } else if (argc) { if (matches(*argv, "help") == 0) usage(); - fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n", - *argv); + fprintf(stderr, + "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n", + *argv); return -1; } addattr_nest_end(&req.n, linkinfo); From cb294a1de61266e00defab8e06af05ee15e072d5 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 23 Sep 2016 11:25:54 +0800 Subject: [PATCH 447/513] ip rule: merge ip rule flush and list, save together iprule_flush() and iprule_list_or_save() both call function rtnl_wilddump_request() and rtnl_dump_filter(). So merge them together just like other files do. Signed-off-by: Hangbin Liu --- ip/iprule.c | 121 +++++++++++++++++++++++----------------------------- 1 file changed, 54 insertions(+), 67 deletions(-) diff --git a/ip/iprule.c b/ip/iprule.c index 70562c553..e18505fd3 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -27,6 +27,12 @@ #include "utils.h" #include "ip_common.h" +enum list_action { + IPRULE_LIST, + IPRULE_FLUSH, + IPRULE_SAVE, +}; + extern struct rtnl_handle rth; static void usage(void) __attribute__((noreturn)); @@ -243,24 +249,61 @@ static int save_rule(const struct sockaddr_nl *who, return ret == n->nlmsg_len ? 0 : ret; } -static int iprule_list_or_save(int argc, char **argv, int save) +static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, + void *arg) +{ + struct rtnl_handle rth2; + struct rtmsg *r = NLMSG_DATA(n); + int len = n->nlmsg_len; + struct rtattr *tb[FRA_MAX+1]; + + len -= NLMSG_LENGTH(sizeof(*r)); + if (len < 0) + return -1; + + parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len); + + if (tb[FRA_PRIORITY]) { + n->nlmsg_type = RTM_DELRULE; + n->nlmsg_flags = NLM_F_REQUEST; + + if (rtnl_open(&rth2, 0) < 0) + return -1; + + if (rtnl_talk(&rth2, n, NULL, 0) < 0) + return -2; + + rtnl_close(&rth2); + } + + return 0; +} + +static int iprule_list_flush_or_save(int argc, char **argv, int action) { - rtnl_filter_t filter = print_rule; + rtnl_filter_t filter_fn; int af = preferred_family; if (af == AF_UNSPEC) af = AF_INET; if (argc > 0) { - fprintf(stderr, "\"ip rule %s\" does not take any arguments.\n", - save ? "save" : "show"); + fprintf(stderr, + "\"ip rule list/flush/save\" does not take any arguments\n"); return -1; } - if (save) { + switch (action) { + case IPRULE_SAVE: if (save_rule_prep()) return -1; - filter = save_rule; + filter_fn = save_rule; + break; + case IPRULE_FLUSH: + filter_fn = flush_rule; + break; + default: + filter_fn = print_rule; } if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) { @@ -268,7 +311,7 @@ static int iprule_list_or_save(int argc, char **argv, int save) return 1; } - if (rtnl_dump_filter(&rth, filter, stdout) < 0) { + if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); return 1; } @@ -511,72 +554,16 @@ static int iprule_modify(int cmd, int argc, char **argv) return 0; } - -static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, - void *arg) -{ - struct rtnl_handle rth2; - struct rtmsg *r = NLMSG_DATA(n); - int len = n->nlmsg_len; - struct rtattr *tb[FRA_MAX+1]; - - len -= NLMSG_LENGTH(sizeof(*r)); - if (len < 0) - return -1; - - parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len); - - if (tb[FRA_PRIORITY]) { - n->nlmsg_type = RTM_DELRULE; - n->nlmsg_flags = NLM_F_REQUEST; - - if (rtnl_open(&rth2, 0) < 0) - return -1; - - if (rtnl_talk(&rth2, n, NULL, 0) < 0) - return -2; - - rtnl_close(&rth2); - } - - return 0; -} - -static int iprule_flush(int argc, char **argv) -{ - int af = preferred_family; - - if (af == AF_UNSPEC) - af = AF_INET; - - if (argc > 0) { - fprintf(stderr, "\"ip rule flush\" does not allow arguments\n"); - return -1; - } - - if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) { - perror("Cannot send dump request"); - return 1; - } - - if (rtnl_dump_filter(&rth, flush_rule, NULL) < 0) { - fprintf(stderr, "Flush terminated\n"); - return 1; - } - - return 0; -} - int do_iprule(int argc, char **argv) { if (argc < 1) { - return iprule_list_or_save(0, NULL, 0); + return iprule_list_flush_or_save(0, NULL, IPRULE_LIST); } else if (matches(argv[0], "list") == 0 || matches(argv[0], "lst") == 0 || matches(argv[0], "show") == 0) { - return iprule_list_or_save(argc-1, argv+1, 0); + return iprule_list_flush_or_save(argc-1, argv+1, IPRULE_LIST); } else if (matches(argv[0], "save") == 0) { - return iprule_list_or_save(argc-1, argv+1, 1); + return iprule_list_flush_or_save(argc-1, argv+1, IPRULE_SAVE); } else if (matches(argv[0], "restore") == 0) { return iprule_restore(); } else if (matches(argv[0], "add") == 0) { @@ -584,7 +571,7 @@ int do_iprule(int argc, char **argv) } else if (matches(argv[0], "delete") == 0) { return iprule_modify(RTM_DELRULE, argc-1, argv+1); } else if (matches(argv[0], "flush") == 0) { - return iprule_flush(argc-1, argv+1); + return iprule_list_flush_or_save(argc-1, argv+1, IPRULE_FLUSH); } else if (matches(argv[0], "help") == 0) usage(); From ca89c521433d55d70fcd89322511abc3f524ac34 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 23 Sep 2016 11:25:55 +0800 Subject: [PATCH 448/513] ip rule: add selector support Signed-off-by: Hangbin Liu --- ip/iprule.c | 180 ++++++++++++++++++++++++++++++++++++++++++++- man/man8/ip-rule.8 | 6 +- 2 files changed, 180 insertions(+), 6 deletions(-) diff --git a/ip/iprule.c b/ip/iprule.c index e18505fd3..42fb6aff8 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -41,7 +42,7 @@ static void usage(void) { fprintf(stderr, "Usage: ip rule { add | del } SELECTOR ACTION\n"); fprintf(stderr, " ip rule { flush | save | restore }\n"); - fprintf(stderr, " ip rule [ list ]\n"); + fprintf(stderr, " ip rule [ list [ SELECTOR ]]\n"); fprintf(stderr, "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n"); fprintf(stderr, " [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n"); fprintf(stderr, "ACTION := [ table TABLE_ID ]\n"); @@ -55,6 +56,105 @@ static void usage(void) exit(-1); } +static struct +{ + int not; + int l3mdev; + int iifmask, oifmask; + unsigned int tb; + unsigned int tos, tosmask; + unsigned int pref, prefmask; + unsigned int fwmark, fwmask; + char iif[IFNAMSIZ]; + char oif[IFNAMSIZ]; + inet_prefix src; + inet_prefix dst; +} filter; + +static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) +{ + struct rtmsg *r = NLMSG_DATA(n); + inet_prefix src = { .family = r->rtm_family }; + inet_prefix dst = { .family = r->rtm_family }; + __u32 table; + + if (preferred_family != AF_UNSPEC && r->rtm_family != preferred_family) + return false; + + if (filter.prefmask && + filter.pref ^ (tb[FRA_PRIORITY] ? rta_getattr_u32(tb[FRA_PRIORITY]) : 0)) + return false; + if (filter.not && !(r->rtm_flags & FIB_RULE_INVERT)) + return false; + + if (filter.src.family) { + if (tb[FRA_SRC]) { + memcpy(&src.data, RTA_DATA(tb[FRA_SRC]), + (r->rtm_src_len + 7) / 8); + } + if (filter.src.family != r->rtm_family || + filter.src.bitlen > r->rtm_src_len || + inet_addr_match(&src, &filter.src, filter.src.bitlen)) + return false; + } + + if (filter.dst.family) { + if (tb[FRA_DST]) { + memcpy(&dst.data, RTA_DATA(tb[FRA_DST]), + (r->rtm_dst_len + 7) / 8); + } + if (filter.dst.family != r->rtm_family || + filter.dst.bitlen > r->rtm_dst_len || + inet_addr_match(&dst, &filter.dst, filter.dst.bitlen)) + return false; + } + + if (filter.tosmask && filter.tos ^ r->rtm_tos) + return false; + + if (filter.fwmark) { + __u32 mark = 0; + if (tb[FRA_FWMARK]) + mark = rta_getattr_u32(tb[FRA_FWMARK]); + if (filter.fwmark ^ mark) + return false; + } + if (filter.fwmask) { + __u32 mask = 0; + if (tb[FRA_FWMASK]) + mask = rta_getattr_u32(tb[FRA_FWMASK]); + if (filter.fwmask ^ mask) + return false; + } + + if (filter.iifmask) { + if (tb[FRA_IFNAME]) { + if (strcmp(filter.iif, rta_getattr_str(tb[FRA_IFNAME])) != 0) + return false; + } else { + return false; + } + } + + if (filter.oifmask) { + if (tb[FRA_OIFNAME]) { + if (strcmp(filter.oif, rta_getattr_str(tb[FRA_OIFNAME])) != 0) + return false; + } else { + return false; + } + } + + if (filter.l3mdev && !(tb[FRA_L3MDEV] && rta_getattr_u8(tb[FRA_L3MDEV]))) + return false; + + table = rtm_get_table(r, tb); + if (filter.tb > 0 && filter.tb ^ table) + return false; + + return true; +} + int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE *)arg; @@ -77,6 +177,9 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) host_len = af_bit_len(r->rtm_family); + if(!filter_nlmsg(n, tb, host_len)) + return 0; + if (n->nlmsg_type == RTM_DELRULE) fprintf(fp, "Deleted "); @@ -287,9 +390,9 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action) if (af == AF_UNSPEC) af = AF_INET; - if (argc > 0) { - fprintf(stderr, - "\"ip rule list/flush/save\" does not take any arguments\n"); + if (action != IPRULE_LIST && argc > 0) { + fprintf(stderr, "\"ip rule %s\" does not take any arguments.\n", + action == IPRULE_SAVE ? "save" : "flush"); return -1; } @@ -306,6 +409,75 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action) filter_fn = print_rule; } + memset(&filter, 0, sizeof(filter)); + + while (argc > 0) { + if (matches(*argv, "preference") == 0 || + matches(*argv, "order") == 0 || + matches(*argv, "priority") == 0) { + __u32 pref; + NEXT_ARG(); + if (get_u32(&pref, *argv, 0)) + invarg("preference value is invalid\n", *argv); + filter.pref = pref; + filter.prefmask = 1; + } else if (strcmp(*argv, "not") == 0) { + filter.not = 1; + } else if (strcmp(*argv, "tos") == 0) { + __u32 tos; + NEXT_ARG(); + if (rtnl_dsfield_a2n(&tos, *argv)) + invarg("TOS value is invalid\n", *argv); + filter.tos = tos; + filter.tosmask = 1; + } else if (strcmp(*argv, "fwmark") == 0) { + char *slash; + __u32 fwmark, fwmask; + NEXT_ARG(); + slash = strchr(*argv, '/'); + if (slash != NULL) + *slash = '\0'; + if (get_u32(&fwmark, *argv, 0)) + invarg("fwmark value is invalid\n", *argv); + filter.fwmark = fwmark; + if (slash) { + if (get_u32(&fwmask, slash+1, 0)) + invarg("fwmask value is invalid\n", + slash+1); + filter.fwmask = fwmask; + } + } else if (strcmp(*argv, "dev") == 0 || + strcmp(*argv, "iif") == 0) { + NEXT_ARG(); + strncpy(filter.iif, *argv, IFNAMSIZ); + filter.iifmask = 1; + } else if (strcmp(*argv, "oif") == 0) { + NEXT_ARG(); + strncpy(filter.oif, *argv, IFNAMSIZ); + filter.oifmask = 1; + } else if (strcmp(*argv, "l3mdev") == 0) { + filter.l3mdev = 1; + } else if (matches(*argv, "lookup") == 0 || + matches(*argv, "table") == 0 ) { + __u32 tid; + NEXT_ARG(); + if (rtnl_rttable_a2n(&tid, *argv)) + invarg("table id value is invalid\n", *argv); + filter.tb = tid; + } else if (matches(*argv, "from") == 0 || + matches(*argv, "src") == 0) { + NEXT_ARG(); + get_prefix(&filter.src, *argv, af); + } else { + if (matches(*argv, "dst") == 0 || + matches(*argv, "to") == 0) { + NEXT_ARG(); + } + get_prefix(&filter.dst, *argv, af); + } + argc--; argv++; + } + if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) { perror("Cannot send dump request"); return 1; diff --git a/man/man8/ip-rule.8 b/man/man8/ip-rule.8 index 13fe9f7f8..7de80f3e6 100644 --- a/man/man8/ip-rule.8 +++ b/man/man8/ip-rule.8 @@ -15,7 +15,8 @@ ip-rule \- routing policy database management .ti -8 .B ip rule -.RB "[ " list " ]" +.RB "[ " list +.RI "[ " SELECTOR " ]]" .ti -8 .B ip rule @@ -42,7 +43,8 @@ ip-rule \- routing policy database management .B oif .IR STRING " ] [ " .B pref -.IR NUMBER " ]" +.IR NUMBER " ] [ " +.BR l3mdev " ]" .ti -8 .IR ACTION " := [ " From e147161b1aa037a7150dc7c69d77f16ba6001717 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 9 Oct 2016 19:29:24 -0700 Subject: [PATCH 449/513] ip: iprule style cleanup Trivial whitespace cleanup to iprule --- ip/iprule.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/ip/iprule.c b/ip/iprule.c index 42fb6aff8..e61127e8b 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -40,19 +40,20 @@ static void usage(void) __attribute__((noreturn)); static void usage(void) { - fprintf(stderr, "Usage: ip rule { add | del } SELECTOR ACTION\n"); - fprintf(stderr, " ip rule { flush | save | restore }\n"); - fprintf(stderr, " ip rule [ list [ SELECTOR ]]\n"); - fprintf(stderr, "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n"); - fprintf(stderr, " [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n"); - fprintf(stderr, "ACTION := [ table TABLE_ID ]\n"); - fprintf(stderr, " [ nat ADDRESS ]\n"); - fprintf(stderr, " [ realms [SRCREALM/]DSTREALM ]\n"); - fprintf(stderr, " [ goto NUMBER ]\n"); - fprintf(stderr, " SUPPRESSOR\n"); - fprintf(stderr, "SUPPRESSOR := [ suppress_prefixlength NUMBER ]\n"); - fprintf(stderr, " [ suppress_ifgroup DEVGROUP ]\n"); - fprintf(stderr, "TABLE_ID := [ local | main | default | NUMBER ]\n"); + fprintf(stderr, + "Usage: ip rule { add | del } SELECTOR ACTION\n" + " ip rule { flush | save | restore }\n" + " ip rule [ list [ SELECTOR ]]\n" + "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n" + " [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n" + "ACTION := [ table TABLE_ID ]\n" + " [ nat ADDRESS ]\n" + " [ realms [SRCREALM/]DSTREALM ]\n" + " [ goto NUMBER ]\n" + " SUPPRESSOR\n" + "SUPPRESSOR := [ suppress_prefixlength NUMBER ]\n" + " [ suppress_ifgroup DEVGROUP ]\n" + "TABLE_ID := [ local | main | default | NUMBER ]\n"); exit(-1); } @@ -114,6 +115,7 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) if (filter.fwmark) { __u32 mark = 0; + if (tb[FRA_FWMARK]) mark = rta_getattr_u32(tb[FRA_FWMARK]); if (filter.fwmark ^ mark) @@ -121,6 +123,7 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) } if (filter.fwmask) { __u32 mask = 0; + if (tb[FRA_FWMASK]) mask = rta_getattr_u32(tb[FRA_FWMASK]); if (filter.fwmask ^ mask) @@ -177,7 +180,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) host_len = af_bit_len(r->rtm_family); - if(!filter_nlmsg(n, tb, host_len)) + if (!filter_nlmsg(n, tb, host_len)) return 0; if (n->nlmsg_type == RTM_DELRULE) @@ -416,6 +419,7 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action) matches(*argv, "order") == 0 || matches(*argv, "priority") == 0) { __u32 pref; + NEXT_ARG(); if (get_u32(&pref, *argv, 0)) invarg("preference value is invalid\n", *argv); @@ -425,6 +429,7 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action) filter.not = 1; } else if (strcmp(*argv, "tos") == 0) { __u32 tos; + NEXT_ARG(); if (rtnl_dsfield_a2n(&tos, *argv)) invarg("TOS value is invalid\n", *argv); @@ -433,6 +438,7 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action) } else if (strcmp(*argv, "fwmark") == 0) { char *slash; __u32 fwmark, fwmask; + NEXT_ARG(); slash = strchr(*argv, '/'); if (slash != NULL) @@ -458,8 +464,9 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action) } else if (strcmp(*argv, "l3mdev") == 0) { filter.l3mdev = 1; } else if (matches(*argv, "lookup") == 0 || - matches(*argv, "table") == 0 ) { + matches(*argv, "table") == 0) { __u32 tid; + NEXT_ARG(); if (rtnl_rttable_a2n(&tid, *argv)) invarg("table id value is invalid\n", *argv); From 9a56cca3f3b0332e94314d193d421fb6ae01df6c Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Tue, 11 Oct 2016 07:00:40 -0400 Subject: [PATCH 450/513] ife action: allow specifying index in hex Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- tc/m_ife.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tc/m_ife.c b/tc/m_ife.c index 0219760aa..a5a7516d8 100644 --- a/tc/m_ife.c +++ b/tc/m_ife.c @@ -152,7 +152,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, if (argc) { if (matches(*argv, "index") == 0) { NEXT_ARG(); - if (get_u32(&p.index, *argv, 10)) { + if (get_u32(&p.index, *argv, 0)) { fprintf(stderr, "ife: Illegal \"index\"\n"); return -1; } From 57ee4430f9fafd436e153f29e5046e41f1b6faa1 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Tue, 11 Oct 2016 07:00:41 -0400 Subject: [PATCH 451/513] ife: print prio, mark and hash as unsigned Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- tc/m_ife.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tc/m_ife.c b/tc/m_ife.c index a5a7516d8..588bad7fd 100644 --- a/tc/m_ife.c +++ b/tc/m_ife.c @@ -252,7 +252,7 @@ static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg) len = RTA_PAYLOAD(metalist[IFE_META_SKBMARK]); if (len) { mmark = rta_getattr_u32(metalist[IFE_META_SKBMARK]); - fprintf(f, "use mark %d ", mmark); + fprintf(f, "use mark %u ", mmark); } else fprintf(f, "allow mark "); } @@ -261,7 +261,7 @@ static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg) len = RTA_PAYLOAD(metalist[IFE_META_HASHID]); if (len) { mhash = rta_getattr_u32(metalist[IFE_META_HASHID]); - fprintf(f, "use hash %d ", mhash); + fprintf(f, "use hash %u ", mhash); } else fprintf(f, "allow hash "); } @@ -270,7 +270,7 @@ static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg) len = RTA_PAYLOAD(metalist[IFE_META_PRIO]); if (len) { mprio = rta_getattr_u32(metalist[IFE_META_PRIO]); - fprintf(f, "use prio %d ", mprio); + fprintf(f, "use prio %u ", mprio); } else fprintf(f, "allow prio "); } From 1b600f4b5429f864e8a867ae176bfc13742ea523 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Tue, 11 Oct 2016 07:00:42 -0400 Subject: [PATCH 452/513] ife: improve help text Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- tc/m_ife.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tc/m_ife.c b/tc/m_ife.c index 588bad7fd..862461bc2 100644 --- a/tc/m_ife.c +++ b/tc/m_ife.c @@ -29,12 +29,13 @@ static void ife_explain(void) { fprintf(stderr, - "Usage:... ife {decode|encode} {ALLOW|USE} [dst DMAC] [src SMAC] [type TYPE] [CONTROL] [index INDEX]\n"); + "Usage:... ife {decode|encode} [{ALLOW|USE} ATTR] [dst DMAC] [src SMAC] [type TYPE] [CONTROL] [index INDEX]\n"); fprintf(stderr, "\tALLOW := Encode direction. Allows encoding specified metadata\n" "\t\t e.g \"allow mark\"\n" "\tUSE := Encode direction. Enforce Static encoding of specified metadata\n" "\t\t e.g \"use mark 0x12\"\n" + "\tATTR := mark (32-bit), prio (32-bit), tcindex (16-bit)\n" "\tDMAC := 6 byte Destination MAC address to encode\n" "\tSMAC := optional 6 byte Source MAC address to encode\n" "\tTYPE := optional 16 bit ethertype to encode\n" From 8da6ff35cd2f03f84a0b7be82a508a36b87c8168 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Tue, 11 Oct 2016 07:00:43 -0400 Subject: [PATCH 453/513] actions ife: Introduce encoding and decoding of tcindex metadata Signed-off-by: Jamal Hadi Salim --- tc/m_ife.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/tc/m_ife.c b/tc/m_ife.c index 862461bc2..e6f61535e 100644 --- a/tc/m_ife.c +++ b/tc/m_ife.c @@ -67,6 +67,8 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, __u32 ife_prio_v = 0; __u32 ife_mark = 0; __u32 ife_mark_v = 0; + __u16 ife_tcindex = 0; + __u16 ife_tcindex_v = 0; char *daddr = NULL; char *saddr = NULL; @@ -89,6 +91,8 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, ife_mark = IFE_META_SKBMARK; } else if (matches(*argv, "prio") == 0) { ife_prio = IFE_META_PRIO; + } else if (matches(*argv, "tcindex") == 0) { + ife_prio = IFE_META_TCINDEX; } else { fprintf(stderr, "Illegal meta define <%s>\n", *argv); @@ -106,6 +110,11 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, if (get_u32(&ife_prio_v, *argv, 0)) invarg("ife prio val is invalid", *argv); + } else if (matches(*argv, "tcindex") == 0) { + NEXT_ARG(); + if (get_u16(&ife_tcindex_v, *argv, 0)) + invarg("ife tcindex val is invalid", + *argv); } else { fprintf(stderr, "Illegal meta use type <%s>\n", *argv); @@ -196,6 +205,13 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, else addattr_l(n, MAX_MSG, IFE_META_PRIO, NULL, 0); } + if (ife_tcindex || ife_tcindex_v) { + if (ife_tcindex_v) + addattr_l(n, MAX_MSG, IFE_META_TCINDEX, &ife_tcindex_v, + 2); + else + addattr_l(n, MAX_MSG, IFE_META_TCINDEX, NULL, 0); + } tail2->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail2; @@ -213,7 +229,7 @@ static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg) struct rtattr *tb[TCA_IFE_MAX + 1]; __u16 ife_type = 0; __u32 mmark = 0; - __u32 mhash = 0; + __u16 mtcindex = 0; __u32 mprio = 0; int has_optional = 0; SPRINT_BUF(b2); @@ -258,13 +274,14 @@ static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg) fprintf(f, "allow mark "); } - if (metalist[IFE_META_HASHID]) { - len = RTA_PAYLOAD(metalist[IFE_META_HASHID]); + if (metalist[IFE_META_TCINDEX]) { + len = RTA_PAYLOAD(metalist[IFE_META_TCINDEX]); if (len) { - mhash = rta_getattr_u32(metalist[IFE_META_HASHID]); - fprintf(f, "use hash %u ", mhash); + mtcindex = + rta_getattr_u16(metalist[IFE_META_TCINDEX]); + fprintf(f, "use tcindex %d ", mtcindex); } else - fprintf(f, "allow hash "); + fprintf(f, "allow tcindex "); } if (metalist[IFE_META_PRIO]) { From 883c6708e44f70589bcc67356a97ccc24756475d Mon Sep 17 00:00:00 2001 From: Craig Dillabaugh Date: Tue, 11 Oct 2016 07:00:44 -0400 Subject: [PATCH 454/513] action gact: list pipe as a valid action Signed-off-by: Craig Dillabaugh Signed-off-by: Jamal Hadi Salim --- tc/m_gact.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tc/m_gact.c b/tc/m_gact.c index 2bfd9a7c3..dc04b9fda 100644 --- a/tc/m_gact.c +++ b/tc/m_gact.c @@ -45,7 +45,7 @@ explain(void) #ifdef CONFIG_GACT_PROB fprintf(stderr, "Usage: ... gact [RAND] [INDEX]\n"); fprintf(stderr, - "Where: \tACTION := reclassify | drop | continue | pass\n" + "Where: \tACTION := reclassify | drop | continue | pass | pipe\n" "\tRAND := random \n" "\tRANDTYPE := netrand | determ\n" "\tVAL : = value not exceeding 10000\n" @@ -54,7 +54,7 @@ explain(void) #else fprintf(stderr, "Usage: ... gact [INDEX]\n"); fprintf(stderr, - "Where: \tACTION := reclassify | drop | continue | pass\n" + "Where: \tACTION := reclassify | drop | continue | pass | pipe\n" "\tINDEX := index value used\n" "\n"); #endif From da65128998af043158d181ce2ee647cd1070a4d3 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Tue, 11 Oct 2016 07:00:45 -0400 Subject: [PATCH 455/513] actions: add skbmod action This action is intended to be an upgrade from a usability perspective from pedit (as well as operational debugability). Compare this: sudo tc filter add dev $ETH parent 1: protocol ip prio 10 \ u32 match ip protocol 1 0xff flowid 1:2 \ action pedit munge offset -14 u8 set 0x02 \ munge offset -13 u8 set 0x15 \ munge offset -12 u8 set 0x15 \ munge offset -11 u8 set 0x15 \ munge offset -10 u16 set 0x1515 \ pipe to: sudo tc filter add dev $ETH parent 1: protocol ip prio 10 \ u32 match ip protocol 1 0xff flowid 1:2 \ action skbmod dmac 02:15:15:15:15:15 Or worse, try to debug a policy with destination mac, source mac and etherype. Then make that a hundred rules and you'll get my point. The most important ethernet use case at the moment is when redirecting or mirroring packets to a remote machine. The dst mac address needs a re-write so that it doesn't get dropped or confuse an interconnecting (learning) switch or dropped by a target machine (which looks at the dst mac). In the future common use cases on pedit can be migrated to this action (as an example different fields in ip v4/6, transports like tcp/udp/sctp etc). For this first cut, this allows modifying basic ethernet header. Signed-off-by: Jamal Hadi Salim --- tc/m_skbmod.c | 260 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 tc/m_skbmod.c diff --git a/tc/m_skbmod.c b/tc/m_skbmod.c new file mode 100644 index 000000000..b7f476571 --- /dev/null +++ b/tc/m_skbmod.c @@ -0,0 +1,260 @@ +/* + * m_skbmod.c skb modifier action module + * + * This program is free software; you can distribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: J Hadi Salim (jhs@mojatatu.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt_names.h" +#include "utils.h" +#include "tc_util.h" +#include + +static void skbmod_explain(void) +{ + fprintf(stderr, + "Usage:... skbmod {[set ] [swap ]} [CONTROL] [index INDEX]\n"); + fprintf(stderr, "where SETTABLE is: [dmac DMAC] [smac SMAC] [etype ETYPE] \n"); + fprintf(stderr, "where SWAPABLE is: \"mac\" to swap mac addresses\n"); + fprintf(stderr, "note: \"swap mac\" is done after any outstanding D/SMAC change\n"); + fprintf(stderr, + "\tDMAC := 6 byte Destination MAC address\n" + "\tSMAC := optional 6 byte Source MAC address\n" + "\tETYPE := optional 16 bit ethertype\n" + "\tCONTROL := reclassify|pipe|drop|continue|ok\n" + "\tINDEX := skbmod index value to use\n"); +} + +static void skbmod_usage(void) +{ + skbmod_explain(); + exit(-1); +} + +static int parse_skbmod(struct action_util *a, int *argc_p, char ***argv_p, + int tca_id, struct nlmsghdr *n) +{ + int argc = *argc_p; + char **argv = *argv_p; + int ok = 0; + struct tc_skbmod p; + struct rtattr *tail; + char dbuf[ETH_ALEN]; + char sbuf[ETH_ALEN]; + __u16 skbmod_etype = 0; + char *daddr = NULL; + char *saddr = NULL; + + memset(&p, 0, sizeof(p)); + p.action = TC_ACT_PIPE; /* good default */ + + if (argc <= 0) + return -1; + + while (argc > 0) { + if (matches(*argv, "skbmod") == 0) { + NEXT_ARG(); + continue; + } else if (matches(*argv, "swap") == 0) { + NEXT_ARG(); + continue; + } else if (matches(*argv, "mac") == 0) { + p.flags |= SKBMOD_F_SWAPMAC; + ok += 1; + } else if (matches(*argv, "set") == 0) { + NEXT_ARG(); + continue; + } else if (matches(*argv, "etype") == 0) { + NEXT_ARG(); + if (get_u16(&skbmod_etype, *argv, 0)) + invarg("ethertype is invalid", *argv); + fprintf(stderr, "skbmod etype 0x%x\n", skbmod_etype); + p.flags |= SKBMOD_F_ETYPE; + ok += 1; + } else if (matches(*argv, "dmac") == 0) { + NEXT_ARG(); + daddr = *argv; + if (sscanf(daddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + dbuf, dbuf + 1, dbuf + 2, + dbuf + 3, dbuf + 4, dbuf + 5) != 6) { + fprintf(stderr, "Invalid dst mac address %s\n", + daddr); + return -1; + } + p.flags |= SKBMOD_F_DMAC; + fprintf(stderr, "dst MAC address <%s>\n", daddr); + ok += 1; + + } else if (matches(*argv, "smac") == 0) { + NEXT_ARG(); + saddr = *argv; + if (sscanf(saddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + sbuf, sbuf + 1, sbuf + 2, + sbuf + 3, sbuf + 4, sbuf + 5) != 6) { + fprintf(stderr, "Invalid smac address %s\n", + saddr); + return -1; + } + p.flags |= SKBMOD_F_SMAC; + fprintf(stderr, "src MAC address <%s>\n", saddr); + ok += 1; + } else if (matches(*argv, "help") == 0) { + skbmod_usage(); + } else { + break; + } + + argc--; + argv++; + } + + if (argc) { + if (matches(*argv, "reclassify") == 0) { + p.action = TC_ACT_RECLASSIFY; + argc--; + argv++; + } else if (matches(*argv, "pipe") == 0) { + p.action = TC_ACT_PIPE; + argc--; + argv++; + } else if (matches(*argv, "drop") == 0 || + matches(*argv, "shot") == 0) { + p.action = TC_ACT_SHOT; + argc--; + argv++; + } else if (matches(*argv, "continue") == 0) { + p.action = TC_ACT_UNSPEC; + argc--; + argv++; + } else if (matches(*argv, "pass") == 0 || + matches(*argv, "ok") == 0) { + p.action = TC_ACT_OK; + argc--; + argv++; + } + } + + if (argc) { + if (matches(*argv, "index") == 0) { + NEXT_ARG(); + if (get_u32(&p.index, *argv, 0)) { + fprintf(stderr, "skbmod: Illegal \"index\"\n"); + return -1; + } + ok++; + argc--; + argv++; + } + } + + if (!ok) { + fprintf(stderr, "skbmod requires at least one option\n"); + skbmod_usage(); + } + + tail = NLMSG_TAIL(n); + addattr_l(n, MAX_MSG, tca_id, NULL, 0); + addattr_l(n, MAX_MSG, TCA_SKBMOD_PARMS, &p, sizeof(p)); + + if (daddr) + addattr_l(n, MAX_MSG, TCA_SKBMOD_DMAC, dbuf, ETH_ALEN); + if (skbmod_etype) + addattr16(n, MAX_MSG, TCA_SKBMOD_ETYPE, skbmod_etype); + if (saddr) + addattr_l(n, MAX_MSG, TCA_SKBMOD_SMAC, sbuf, ETH_ALEN); + + tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail; + + *argc_p = argc; + *argv_p = argv; + return 0; +} + +static int print_skbmod(struct action_util *au, FILE *f, struct rtattr *arg) +{ + struct tc_skbmod *p = NULL; + struct rtattr *tb[TCA_SKBMOD_MAX + 1]; + __u16 skbmod_etype = 0; + int has_optional = 0; + SPRINT_BUF(b1); + SPRINT_BUF(b2); + + if (arg == NULL) + return -1; + + parse_rtattr_nested(tb, TCA_SKBMOD_MAX, arg); + + if (tb[TCA_SKBMOD_PARMS] == NULL) { + fprintf(f, "[NULL skbmod parameters]"); + return -1; + } + + p = RTA_DATA(tb[TCA_SKBMOD_PARMS]); + + fprintf(f, "skbmod action %s ", action_n2a(p->action)); + + if (tb[TCA_SKBMOD_ETYPE]) { + skbmod_etype = rta_getattr_u16(tb[TCA_SKBMOD_ETYPE]); + has_optional = 1; + fprintf(f, "set etype 0x%X ", skbmod_etype); + } + + if (has_optional) + fprintf(f, "\n\t "); + + if (tb[TCA_SKBMOD_DMAC]) { + has_optional = 1; + fprintf(f, "set dmac %s ", + ll_addr_n2a(RTA_DATA(tb[TCA_SKBMOD_DMAC]), + RTA_PAYLOAD(tb[TCA_SKBMOD_DMAC]), 0, b1, + sizeof(b1))); + + } + + if (tb[TCA_SKBMOD_SMAC]) { + has_optional = 1; + fprintf(f, "set smac %s ", + ll_addr_n2a(RTA_DATA(tb[TCA_SKBMOD_SMAC]), + RTA_PAYLOAD(tb[TCA_SKBMOD_SMAC]), 0, b2, + sizeof(b2))); + } + + if (p->flags & SKBMOD_F_SWAPMAC) + fprintf(f, "swap mac "); + + fprintf(f, "\n\t index %d ref %d bind %d", p->index, p->refcnt, + p->bindcnt); + if (show_stats) { + if (tb[TCA_SKBMOD_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_SKBMOD_TM]); + + print_tm(f, tm); + } + } + + fprintf(f, "\n"); + + return 0; +} + +struct action_util skbmod_action_util = { + .id = "skbmod", + .parse_aopt = parse_skbmod, + .print_aopt = print_skbmod, +}; From d491a3480ff9af7e318fcdf53ec4eb94e75dd3d0 Mon Sep 17 00:00:00 2001 From: Lucas Bates Date: Tue, 11 Oct 2016 07:00:46 -0400 Subject: [PATCH 456/513] man pages: update ife action to include tcindex Signed-off-by: Lucas Bates Signed-off-by: Jamal Hadi Salim --- man/man8/tc-ife.8 | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/man/man8/tc-ife.8 b/man/man8/tc-ife.8 index 7b3601ee3..aaf0f97d5 100644 --- a/man/man8/tc-ife.8 +++ b/man/man8/tc-ife.8 @@ -5,8 +5,8 @@ IFE - encapsulate/decapsulate metadata .SH SYNOPSIS .in +8 .ti -8 -.BR tc " ... " action ife" -.I DIRECTION ACTION +.BR tc " ... " " action ife" +.IR DIRECTION " [ " ACTION " ] " .RB "[ " dst .IR DMAC " ] " .RB "[ " src @@ -24,7 +24,13 @@ IFE - encapsulate/decapsulate metadata .ti -8 .IR ACTION " := { " -.BR allow " | " use " }" +.BI allow " ATTR" +.RB "| " use +.IR "ATTR value" " }" + +.ti -8 +.IR ATTR " := { " +.BR mark " | " prio " | " tcindex " }" .ti -8 .IR CONTROL " := { " @@ -50,6 +56,23 @@ Encode direction only. Allows encoding specified metadata. .B use Encode direction only. Enforce static encoding of specified metadata. .TP +.BR mark " [ " +.IR u32_value " ]" +The value to set for the skb mark. The u32 value is required only when +.BR use " is specified." +.TP +.BR prio " [ " +.IR u32_value " ]" +The value to set for priority in the skb structure. The u32 value is required +only when +.BR use " is specified." +.TP +.BR tcindex " [" +.IR u16_value " ]" +Value to set for the traffic control index in the skb structure. The u16 value +is required only when +.BR use " is specified." +.TP .BI dmac " DMAC" .TQ .BI smac " SMAC" From 46871dc9c6de472c2e371cd9c6e5acb1e9b9cc69 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Tue, 11 Oct 2016 07:00:47 -0400 Subject: [PATCH 457/513] man pages: Add tc-ife to Makefile Signed-off-by: Jamal Hadi Salim --- man/man8/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/Makefile b/man/man8/Makefile index 921376919..4ad96ce41 100644 --- a/man/man8/Makefile +++ b/man/man8/Makefile @@ -16,7 +16,7 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \ tc-tcindex.8 tc-u32.8 tc-matchall.8 \ tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ - tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 \ + tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 tc-ife.8 \ devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 all: $(TARGETS) From 557b7054455e8ae0f938cf6d2ba543c87c9db12f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 12 Oct 2016 15:12:51 -0700 Subject: [PATCH 458/513] tc: skbmod style cleanup break long lines --- tc/m_skbmod.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tc/m_skbmod.c b/tc/m_skbmod.c index b7f476571..0c293fc0f 100644 --- a/tc/m_skbmod.c +++ b/tc/m_skbmod.c @@ -29,11 +29,10 @@ static void skbmod_explain(void) { fprintf(stderr, - "Usage:... skbmod {[set ] [swap ]} [CONTROL] [index INDEX]\n"); - fprintf(stderr, "where SETTABLE is: [dmac DMAC] [smac SMAC] [etype ETYPE] \n"); - fprintf(stderr, "where SWAPABLE is: \"mac\" to swap mac addresses\n"); - fprintf(stderr, "note: \"swap mac\" is done after any outstanding D/SMAC change\n"); - fprintf(stderr, + "Usage:... skbmod {[set ] [swap ]} [CONTROL] [index INDEX]\n" + "where SETTABLE is: [dmac DMAC] [smac SMAC] [etype ETYPE]\n" + "where SWAPABLE is: \"mac\" to swap mac addresses\n" + "note: \"swap mac\" is done after any outstanding D/SMAC change\n" "\tDMAC := 6 byte Destination MAC address\n" "\tSMAC := optional 6 byte Source MAC address\n" "\tETYPE := optional 16 bit ethertype\n" From 120f556d1528f3e99760b7efe05138480d8a9d2e Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Mon, 10 Oct 2016 12:45:14 -0400 Subject: [PATCH 459/513] tc filters: add support to get individual filters by handle sudo $TC filter add dev $ETH parent ffff: prio 2 protocol ip \ u32 match u32 0 0 flowid 1:1 \ action ok sudo $TC filter add dev $ETH parent ffff: prio 1 protocol ip \ u32 match ip protocol 1 0xff flowid 1:10 \ action ok now dump to see all rules.. $TC -s filter ls dev $ETH parent ffff: protocol ip .... filter pref 1 u32 filter pref 1 u32 fh 801: ht divisor 1 filter pref 1 u32 fh 801::800 order 2048 key ht 801 bkt 0 flowid 1:10 (rule hit 0 success 0) match 00010000/00ff0000 at 8 (success 0 ) action order 1: gact action drop random type none pass val 0 index 6 ref 1 bind 1 installed 4 sec used 4 sec Action statistics: Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 filter pref 2 u32 filter pref 2 u32 fh 800: ht divisor 1 filter pref 2 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 (rule hit 336 success 336) match 00000000/00000000 at 0 (success 336 ) action order 1: gact action pass random type none pass val 0 index 5 ref 1 bind 1 installed 38 sec used 4 sec Action statistics: Sent 24864 bytes 336 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 .... ..get filter 801::800 $TC -s filter get dev $ETH parent ffff: protocol ip \ handle 801:0:800 prio 2 u32 .... filter parent ffff: protocol ip pref 1 u32 fh 801::800 order 2048 key ht 801 bkt 0 flowid 1:10 (rule hit 260 success 130) match 00010000/00ff0000 at 8 (success 130 ) action order 1: gact action drop random type none pass val 0 index 6 ref 1 bind 1 installed 348 sec used 0 sec Action statistics: Sent 11440 bytes 130 pkt (dropped 130, overlimits 0 requeues 0) backlog 0b 0p requeues 0 .... ..get other one $TC -s filter get dev $ETH parent ffff: protocol ip \ handle 800:0:800 prio 2 u32 .... filter parent ffff: protocol ip pref 2 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 (rule hit 514 success 514) match 00000000/00000000 at 0 (success 514 ) action order 1: gact action pass random type none pass val 0 index 5 ref 1 bind 1 installed 506 sec used 4 sec Action statistics: Sent 35544 bytes 514 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 .... ..try something that doesnt exist $TC -s filter get dev $ETH parent ffff: protocol ip handle 800:0:803 prio 2 u32 ..... RTNETLINK answers: No such file or directory We have an error talking to the kernel ..... Note, added NLM_F_ECHO is for backward compatibility. old kernels never before Eric's patch will not respond without it and newer kernels (after Erics patch) will ignore it. In old kernels there is a side effect: In addition to a response to the GET you will receive an event (if you do tc mon). But this is still better than what it was before (not working at all). Signed-off-by: Jamal Hadi Salim --- tc/tc_filter.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 175 insertions(+), 10 deletions(-) diff --git a/tc/tc_filter.c b/tc/tc_filter.c index 7e78e13ca..2413cefa1 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -29,6 +29,7 @@ static void usage(void) { fprintf(stderr, "Usage: tc filter [ add | del | change | replace | show ] dev STRING\n"); + fprintf(stderr, "Usage: tc filter get dev STRING parent CLASSID protocol PROTO handle FILTERID pref PRIO FILTER_TYPE \n"); fprintf(stderr, " [ pref PRIO ] protocol PROTO\n"); fprintf(stderr, " [ estimator INTERVAL TIME_CONSTANT ]\n"); fprintf(stderr, " [ root | ingress | egress | parent CLASSID ]\n"); @@ -186,9 +187,7 @@ static __u32 filter_prio; static __u32 filter_protocol; __u16 f_proto; -int print_filter(const struct sockaddr_nl *who, - struct nlmsghdr *n, - void *arg) +int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE *)arg; struct tcmsg *t = NLMSG_DATA(n); @@ -197,8 +196,10 @@ int print_filter(const struct sockaddr_nl *who, struct filter_util *q; char abuf[256]; - if (n->nlmsg_type != RTM_NEWTFILTER && n->nlmsg_type != RTM_DELTFILTER) { - fprintf(stderr, "Not a filter\n"); + if (n->nlmsg_type != RTM_NEWTFILTER && + n->nlmsg_type != RTM_GETTFILTER && + n->nlmsg_type != RTM_DELTFILTER) { + fprintf(stderr, "Not a filter(cmd %d)\n", n->nlmsg_type); return 0; } len -= NLMSG_LENGTH(sizeof(*t)); @@ -269,6 +270,169 @@ int print_filter(const struct sockaddr_nl *who, return 0; } +static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv) +{ + struct { + struct nlmsghdr n; + struct tcmsg t; + char buf[MAX_MSG]; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)), + /* NLM_F_ECHO is for backward compatibility. old kernels never + * respond without it and newer kernels will ignore it. + * In old kernels there is a side effect: + * In addition to a response to the GET you will receive an + * event (if you do tc mon). + */ + .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ECHO | flags, + .n.nlmsg_type = cmd, + .t.tcm_parent = TC_H_UNSPEC, + .t.tcm_family = AF_UNSPEC, + }; + struct filter_util *q = NULL; + __u32 prio = 0; + __u32 protocol = 0; + int protocol_set = 0; + __u32 parent_handle = 0; + char *fhandle = NULL; + char d[16] = {}; + char k[16] = {}; + + while (argc > 0) { + if (strcmp(*argv, "dev") == 0) { + NEXT_ARG(); + if (d[0]) + duparg("dev", *argv); + strncpy(d, *argv, sizeof(d)-1); + } else if (strcmp(*argv, "root") == 0) { + if (req.t.tcm_parent) { + fprintf(stderr, "Error: \"root\" is duplicate parent ID\n"); + return -1; + } + req.t.tcm_parent = TC_H_ROOT; + } else if (strcmp(*argv, "ingress") == 0) { + if (req.t.tcm_parent) { + fprintf(stderr, "Error: \"ingress\" is duplicate parent ID\n"); + return -1; + } + req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT, + TC_H_MIN_INGRESS); + } else if (strcmp(*argv, "egress") == 0) { + if (req.t.tcm_parent) { + fprintf(stderr, "Error: \"egress\" is duplicate parent ID\n"); + return -1; + } + req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT, + TC_H_MIN_EGRESS); + } else if (strcmp(*argv, "parent") == 0) { + + NEXT_ARG(); + if (req.t.tcm_parent) + duparg("parent", *argv); + if (get_tc_classid(&parent_handle, *argv)) + invarg("Invalid parent ID", *argv); + req.t.tcm_parent = parent_handle; + } else if (strcmp(*argv, "handle") == 0) { + NEXT_ARG(); + if (fhandle) + duparg("handle", *argv); + fhandle = *argv; + } else if (matches(*argv, "preference") == 0 || + matches(*argv, "priority") == 0) { + NEXT_ARG(); + if (prio) + duparg("priority", *argv); + if (get_u32(&prio, *argv, 0) || prio > 0xFFFF) + invarg("invalid priority value", *argv); + } else if (matches(*argv, "protocol") == 0) { + __u16 id; + + NEXT_ARG(); + if (protocol_set) + duparg("protocol", *argv); + if (ll_proto_a2n(&id, *argv)) + invarg("invalid protocol", *argv); + protocol = id; + protocol_set = 1; + } else if (matches(*argv, "help") == 0) { + usage(); + return 0; + } else { + strncpy(k, *argv, sizeof(k)-1); + + q = get_filter_kind(k); + argc--; argv++; + break; + } + + argc--; argv++; + } + + if (!protocol_set) { + fprintf(stderr, "Must specify filter protocol\n"); + return -1; + } + + if (!prio) { + fprintf(stderr, "Must specify filter priority\n"); + return -1; + } + + req.t.tcm_info = TC_H_MAKE(prio<<16, protocol); + + if (req.t.tcm_parent == TC_H_UNSPEC) { + fprintf(stderr, "Must specify filter parent\n"); + return -1; + } + + if (k[0]) + addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1); + else { + fprintf(stderr, "Must specify filter type\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; + } + + if (argc) { + if (matches(*argv, "help") == 0) + usage(); + fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"tc filter help\".\n", + *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, &req.n, MAX_MSG) < 0) { + fprintf(stderr, "We have an error talking to the kernel\n"); + return 2; + } + + print_filter(NULL, &req.n, (void *)stdout); + + return 0; +} + static int tc_filter_list(int argc, char **argv) { struct tcmsg t = { .tcm_family = AF_UNSPEC }; @@ -377,17 +541,17 @@ int do_filter(int argc, char **argv) if (argc < 1) return tc_filter_list(0, NULL); if (matches(*argv, "add") == 0) - return tc_filter_modify(RTM_NEWTFILTER, NLM_F_EXCL|NLM_F_CREATE, argc-1, argv+1); + return tc_filter_modify(RTM_NEWTFILTER, NLM_F_EXCL|NLM_F_CREATE, + argc-1, argv+1); if (matches(*argv, "change") == 0) return tc_filter_modify(RTM_NEWTFILTER, 0, argc-1, argv+1); if (matches(*argv, "replace") == 0) - return tc_filter_modify(RTM_NEWTFILTER, NLM_F_CREATE, argc-1, argv+1); + return tc_filter_modify(RTM_NEWTFILTER, NLM_F_CREATE, argc-1, + argv+1); if (matches(*argv, "delete") == 0) return tc_filter_modify(RTM_DELTFILTER, 0, argc-1, argv+1); -#if 0 if (matches(*argv, "get") == 0) return tc_filter_get(RTM_GETTFILTER, 0, argc-1, argv+1); -#endif if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 || matches(*argv, "lst") == 0) return tc_filter_list(argc-1, argv+1); @@ -395,6 +559,7 @@ int do_filter(int argc, char **argv) usage(); return 0; } - fprintf(stderr, "Command \"%s\" is unknown, try \"tc filter help\".\n", *argv); + fprintf(stderr, "Command \"%s\" is unknown, try \"tc filter help\".\n", + *argv); return -1; } From ec2e005fe589179bd0f5b5f05632d9e2ef74d627 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 12 Oct 2016 15:21:13 -0700 Subject: [PATCH 460/513] tc_filter: style cleanup Break long lines and whtespace changes. --- tc/tc_filter.c | 72 +++++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/tc/tc_filter.c b/tc/tc_filter.c index 2413cefa1..932677a05 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -28,18 +28,19 @@ static void usage(void) { - fprintf(stderr, "Usage: tc filter [ add | del | change | replace | show ] dev STRING\n"); - fprintf(stderr, "Usage: tc filter get dev STRING parent CLASSID protocol PROTO handle FILTERID pref PRIO FILTER_TYPE \n"); - fprintf(stderr, " [ pref PRIO ] protocol PROTO\n"); - fprintf(stderr, " [ estimator INTERVAL TIME_CONSTANT ]\n"); - fprintf(stderr, " [ root | ingress | egress | parent CLASSID ]\n"); - fprintf(stderr, " [ handle FILTERID ] [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n"); - fprintf(stderr, "\n"); - fprintf(stderr, " tc filter show [ dev STRING ] [ root | ingress | egress | parent CLASSID ]\n"); - fprintf(stderr, "Where:\n"); - fprintf(stderr, "FILTER_TYPE := { rsvp | u32 | bpf | fw | route | etc. }\n"); - fprintf(stderr, "FILTERID := ... format depends on classifier, see there\n"); - fprintf(stderr, "OPTIONS := ... try tc filter add help\n"); + fprintf(stderr, + "Usage: tc filter [ add | del | change | replace | show ] dev STRING\n" + "Usage: tc filter get dev STRING parent CLASSID protocol PROTO handle FILTERID pref PRIO FILTER_TYPE\n" + " [ pref PRIO ] protocol PROTO\n" + " [ estimator INTERVAL TIME_CONSTANT ]\n" + " [ root | ingress | egress | parent CLASSID ]\n" + " [ handle FILTERID ] [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n" + "\n" + " tc filter show [ dev STRING ] [ root | ingress | egress | parent CLASSID ]\n" + "Where:\n" + "FILTER_TYPE := { rsvp | u32 | bpf | fw | route | etc. }\n" + "FILTERID := ... format depends on classifier, see there\n" + "OPTIONS := ... try tc filter add help\n"); } static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv) @@ -74,20 +75,23 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv) strncpy(d, *argv, sizeof(d)-1); } else if (strcmp(*argv, "root") == 0) { if (req.t.tcm_parent) { - fprintf(stderr, "Error: \"root\" is duplicate parent ID\n"); + fprintf(stderr, + "Error: \"root\" is duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_ROOT; } else if (strcmp(*argv, "ingress") == 0) { if (req.t.tcm_parent) { - fprintf(stderr, "Error: \"ingress\" is duplicate parent ID\n"); + fprintf(stderr, + "Error: \"ingress\" is duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); } else if (strcmp(*argv, "egress") == 0) { if (req.t.tcm_parent) { - fprintf(stderr, "Error: \"egress\" is duplicate parent ID\n"); + fprintf(stderr, + "Error: \"egress\" is duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT, @@ -150,13 +154,16 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv) return 1; } else { if (fhandle) { - fprintf(stderr, "Must specify filter type when using \"handle\"\n"); + fprintf(stderr, + "Must specify filter type when using \"handle\"\n"); return -1; } if (argc) { if (matches(*argv, "help") == 0) usage(); - fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"tc filter help\".\n", *argv); + fprintf(stderr, + "Garbage instead of arguments \"%s ...\". Try \"tc filter help\".\n", + *argv); return -1; } } @@ -167,7 +174,8 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv) if (d[0]) { ll_init_map(&rth); - if ((req.t.tcm_ifindex = ll_name_to_index(d)) == 0) { + 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; } @@ -306,20 +314,23 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv) strncpy(d, *argv, sizeof(d)-1); } else if (strcmp(*argv, "root") == 0) { if (req.t.tcm_parent) { - fprintf(stderr, "Error: \"root\" is duplicate parent ID\n"); + fprintf(stderr, + "Error: \"root\" is duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_ROOT; } else if (strcmp(*argv, "ingress") == 0) { if (req.t.tcm_parent) { - fprintf(stderr, "Error: \"ingress\" is duplicate parent ID\n"); + fprintf(stderr, + "Error: \"ingress\" is duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); } else if (strcmp(*argv, "egress") == 0) { if (req.t.tcm_parent) { - fprintf(stderr, "Error: \"egress\" is duplicate parent ID\n"); + fprintf(stderr, + "Error: \"egress\" is duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT, @@ -404,7 +415,8 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv) if (argc) { if (matches(*argv, "help") == 0) usage(); - fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"tc filter help\".\n", + fprintf(stderr, + "Garbage instead of arguments \"%s ...\". Try \"tc filter help\".\n", *argv); return -1; } @@ -449,13 +461,15 @@ static int tc_filter_list(int argc, char **argv) strncpy(d, *argv, sizeof(d)-1); } else if (strcmp(*argv, "root") == 0) { if (t.tcm_parent) { - fprintf(stderr, "Error: \"root\" is duplicate parent ID\n"); + fprintf(stderr, + "Error: \"root\" is duplicate parent ID\n"); return -1; } filter_parent = t.tcm_parent = TC_H_ROOT; } else if (strcmp(*argv, "ingress") == 0) { if (t.tcm_parent) { - fprintf(stderr, "Error: \"ingress\" is duplicate parent ID\n"); + fprintf(stderr, + "Error: \"ingress\" is duplicate parent ID\n"); return -1; } filter_parent = TC_H_MAKE(TC_H_CLSACT, @@ -463,7 +477,8 @@ static int tc_filter_list(int argc, char **argv) t.tcm_parent = filter_parent; } else if (strcmp(*argv, "egress") == 0) { if (t.tcm_parent) { - fprintf(stderr, "Error: \"egress\" is duplicate parent ID\n"); + fprintf(stderr, + "Error: \"egress\" is duplicate parent ID\n"); return -1; } filter_parent = TC_H_MAKE(TC_H_CLSACT, @@ -504,7 +519,9 @@ static int tc_filter_list(int argc, char **argv) } else if (matches(*argv, "help") == 0) { usage(); } else { - fprintf(stderr, " What is \"%s\"? Try \"tc filter help\"\n", *argv); + fprintf(stderr, + " What is \"%s\"? Try \"tc filter help\"\n", + *argv); return -1; } @@ -516,7 +533,8 @@ static int tc_filter_list(int argc, char **argv) ll_init_map(&rth); if (d[0]) { - if ((t.tcm_ifindex = ll_name_to_index(d)) == 0) { + t.tcm_ifindex = ll_name_to_index(d); + if (t.tcm_ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return 1; } From a40995d1c79e5a1b8711f6cd26eca9807fc4dd50 Mon Sep 17 00:00:00 2001 From: Lucas Bates Date: Tue, 11 Oct 2016 07:00:48 -0400 Subject: [PATCH 461/513] man pages: add man page for skbmod action Signed-off-by: Lucas Bates Signed-off-by: Jamal Hadi Salim --- man/man8/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/Makefile b/man/man8/Makefile index 4ad96ce41..de6f249bf 100644 --- a/man/man8/Makefile +++ b/man/man8/Makefile @@ -16,7 +16,7 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \ tc-tcindex.8 tc-u32.8 tc-matchall.8 \ tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ - tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 tc-ife.8 \ + tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 tc-ife.8 tc-skbmod.8 \ devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 all: $(TARGETS) From f33b7276102c019795c034816b91de72a26cdda3 Mon Sep 17 00:00:00 2001 From: "michael-dev@fami-braun.de" Date: Sun, 25 Sep 2016 21:08:55 +0200 Subject: [PATCH 462/513] iproute2: macvlan: add "source" mode Adjusting iproute2 utility to support new macvlan link type mode called "source". Example of commands that can be applied: ip link add link eth0 name macvlan0 type macvlan mode source ip link set link dev macvlan0 type macvlan macaddr add 00:11:11:11:11:11 ip link set link dev macvlan0 type macvlan macaddr del 00:11:11:11:11:11 ip link set link dev macvlan0 type macvlan macaddr flush ip -details link show dev macvlan0 Based on previous work of Stefan Gula Signed-off-by: Michael Braun Cc: steweg@gmail.com --- include/linux/if_link.h | 2 + ip/iplink_macvlan.c | 103 ++++++++++++++++++++++++++++++++++++++-- man/man8/ip-link.8.in | 57 ++++++++++++++++++++++ 3 files changed, 158 insertions(+), 4 deletions(-) diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 20965c9a6..34f816612 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -402,6 +402,8 @@ enum macvlan_macaddr_mode { }; #define MACVLAN_FLAG_NOPROMISC 1 +#define MACVLAN_FLAG_UNICAST 2 +#define MACVLAN_FLAG_UNICAST_ALL 4 /* VRF section */ enum { diff --git a/ip/iplink_macvlan.c b/ip/iplink_macvlan.c index 53cd4f472..d0f2f3df8 100644 --- a/ip/iplink_macvlan.c +++ b/ip/iplink_macvlan.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "rt_names.h" #include "utils.h" @@ -29,7 +30,11 @@ static void print_explain(struct link_util *lu, FILE *f) { fprintf(f, - "Usage: ... %s mode { private | vepa | bridge | passthru [nopromisc] }\n", + "Usage: ... %s mode MODE [flag MODE_FLAG] MODE_OPTS\n" + "MODE: private | vepa | bridge | passthru | source\n" + "MODE_FLAG: null | nopromisc | unicast | unicast_all\n" + "MODE_OPTS: for mode \"source\":\n" + "\tmacaddr { add | del | flush }\n", lu->id ); } @@ -41,7 +46,14 @@ static void explain(struct link_util *lu) static int mode_arg(const char *arg) { - fprintf(stderr, "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\" or \"passthru\", not \"%s\"\n", + fprintf(stderr, "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\", \"passthru\" or \"source\", not \"%s\"\n", + arg); + return -1; +} + +static int flag_arg(const char *arg) +{ + fprintf(stderr, "Error: argument of \"flag\" must be \"nopromisc\", \"unicast\", \"unicast_all\" or \"null\", not \"%s\"\n", arg); return -1; } @@ -51,6 +63,9 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, { __u32 mode = 0; __u16 flags = 0; + __u32 mac_mode = 0; + int len = 0; + char abuf[32]; while (argc > 0) { if (matches(*argv, "mode") == 0) { @@ -64,8 +79,45 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, mode = MACVLAN_MODE_BRIDGE; else if (strcmp(*argv, "passthru") == 0) mode = MACVLAN_MODE_PASSTHRU; + else if (strcmp(*argv, "source") == 0) + mode = MACVLAN_MODE_SOURCE; else return mode_arg(*argv); + } else if (matches(*argv, "flag") == 0) { + NEXT_ARG(); + + if (strcmp(*argv, "nopromisc") == 0) + flags |= MACVLAN_FLAG_NOPROMISC; + else if (strcmp(*argv, "unicast") == 0) + flags |= MACVLAN_FLAG_UNICAST; + else if (strcmp(*argv, "unicast_all") == 0) + flags |= MACVLAN_FLAG_UNICAST_ALL; + else if (strcmp(*argv, "null") == 0) + flags |= 0; + else + return flag_arg(*argv); + + } else if (matches(*argv, "macaddr") == 0) { + NEXT_ARG(); + + if (strcmp(*argv, "add") == 0) { + mac_mode = MACVLAN_MACADDR_ADD; + } else if (strcmp(*argv, "del") == 0) { + mac_mode = MACVLAN_MACADDR_DEL; + } else if (strcmp(*argv, "flush") == 0) { + mac_mode = MACVLAN_MACADDR_FLUSH; + } else { + explain(lu); + return -1; + } + + if (mac_mode != MACVLAN_MACADDR_FLUSH) { + NEXT_ARG(); + + len = ll_addr_a2n(abuf, sizeof(abuf), *argv); + if (len < 0) + return -1; + } } else if (matches(*argv, "nopromisc") == 0) { flags |= MACVLAN_FLAG_NOPROMISC; } else if (matches(*argv, "help") == 0) { @@ -91,6 +143,12 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, } addattr16(n, 1024, IFLA_MACVLAN_FLAGS, flags); } + + if (mac_mode) { + addattr32(n, 1024, IFLA_MACVLAN_MACADDR_MODE, mac_mode); + if (mac_mode != MACVLAN_MACADDR_FLUSH && len > 0) + addattr_l(n, 1024, IFLA_MACVLAN_MACADDR, abuf, len); + } return 0; } @@ -98,6 +156,10 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[] { __u32 mode; __u16 flags; + __u32 count; + unsigned char *addr; + int len; + struct rtattr *rta; if (!tb) return; @@ -112,15 +174,48 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[] : mode == MACVLAN_MODE_VEPA ? "vepa" : mode == MACVLAN_MODE_BRIDGE ? "bridge" : mode == MACVLAN_MODE_PASSTHRU ? "passthru" + : mode == MACVLAN_MODE_SOURCE ? "source" : "unknown"); if (!tb[IFLA_MACVLAN_FLAGS] || RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16)) - return; + flags = 0; + else + flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]); - flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]); if (flags & MACVLAN_FLAG_NOPROMISC) fprintf(f, "nopromisc "); + if (flags & MACVLAN_FLAG_UNICAST) + fprintf(f, "flag unicast "); + if (flags & MACVLAN_FLAG_UNICAST_ALL) + fprintf(f, "flag unicast_all "); + + /* in source mode, there are more options to print */ + + if (mode != MACVLAN_MODE_SOURCE) + return; + + if (!tb[IFLA_MACVLAN_MACADDR_COUNT] || + RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_COUNT]) < sizeof(__u32)) + return; + + count = rta_getattr_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]); + fprintf(f, " remotes (%d)", count); + + if (!tb[IFLA_MACVLAN_MACADDR_DATA]) + return; + + rta = RTA_DATA(tb[IFLA_MACVLAN_MACADDR_DATA]); + len = RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_DATA]); + + for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { + if (rta->rta_type != IFLA_MACVLAN_MACADDR || + RTA_PAYLOAD(rta) < 6) + continue; + addr = RTA_DATA(rta); + fprintf(f, " %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", addr[0], + addr[1], addr[2], addr[3], addr[4], addr[5]); + } } static void macvlan_print_help(struct link_util *lu, int argc, char **argv, diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 4dfa43fc1..6cb97ea9c 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -135,6 +135,9 @@ ip-link \- network device configuration .IR NAME " ]" .br .RB "[ " addrgenmode " { " eui64 " | " none " | " stable_secret " | " random " } ]" +.br +.B macaddr " |" +.IR "COMMAND MACADDR |" .ti -8 @@ -237,8 +240,46 @@ Link types: - IP over Infiniband device .sp .B macvlan +.I MODE - Virtual interface base on link layer address (MAC) .sp +Modes: +.in +8 +.B private +- The device never communicates with any other device on the same upper_dev. +This even includes frames coming back from a reflective relay, where supported +by the adjacent bridge. +.sp +.B vepa +- we assume that the adjacent bridge returns all frames where both source and +destination are local to the macvlan port, i.e. the bridge is set up as a +reflective relay. Broadcast frames coming in from the upper_dev get flooded to +all macvlan interfaces in VEPA mode. We never deliver any frames locally. +.sp +.B bridge +- behave as simple bridge between different macvlan interfaces on the same +port. Frames from one interface to another one get delivered directly and are +not sent out externally. Broadcast frames get flooded to all other bridge +ports and to the external interface, but when they come back from a reflective +relay, we don't deliver them again. Since we know all the MAC addresses, the +macvlan bridge mode does not require learning or STP like the bridge module +does. +.sp +.B passthru +- allows takeover of the underlying device and passing it to a guest using +virtio with macvtap backend. Only one macvlan device is allowed in passthru +mode and it inherits the mac address from the underlying device and sets it in +promiscuous mode to receive and forward all the packets. +.sp +.B source +- allows one to set a list of allowed mac address, which is used to match +against source mac address from received frames on underlying interface. This +allows creating mac based VLAN associations, instead of standard port or tag +based. The feature is useful to deploy 802.1x mac based behavior, +where drivers of underlying interfaces doesn't allows that. +.sp +.in -8 +.sp .B macvtap - Virtual interface based on link layer address (MAC) and TAP. .sp @@ -1083,6 +1124,22 @@ specifies the type of the device. .SS ip link set - change device attributes +.TP +.BI macaddr " COMMAND MACADDR" +add or removes MACADDR from allowed list for source mode macvlan type link +Commands: +.in +8 +.B add +- add MACADDR to allowed list +.sp +.B del +- remove MACADDR from allowed list +.sp +.B flush +- flush whole allowed list +.sp +.in -8 + .PP .B Warning: If multiple parameter changes are requested, From 7409334b871fada6993dcabc319e481aa40b0d44 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 12 Oct 2016 15:23:27 -0700 Subject: [PATCH 463/513] ip: macvlan style cleanup breaklong lines. --- ip/iplink_macvlan.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ip/iplink_macvlan.c b/ip/iplink_macvlan.c index d0f2f3df8..2adfc098d 100644 --- a/ip/iplink_macvlan.c +++ b/ip/iplink_macvlan.c @@ -46,14 +46,16 @@ static void explain(struct link_util *lu) static int mode_arg(const char *arg) { - fprintf(stderr, "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\", \"passthru\" or \"source\", not \"%s\"\n", + fprintf(stderr, + "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\", \"passthru\" or \"source\", not \"%s\"\n", arg); return -1; } static int flag_arg(const char *arg) { - fprintf(stderr, "Error: argument of \"flag\" must be \"nopromisc\", \"unicast\", \"unicast_all\" or \"null\", not \"%s\"\n", + fprintf(stderr, + "Error: argument of \"flag\" must be \"nopromisc\", \"unicast\", \"unicast_all\" or \"null\", not \"%s\"\n", arg); return -1; } From 660afec25f4150df9a3246ff5798244fc7ed2209 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 12 Oct 2016 15:02:28 +0200 Subject: [PATCH 464/513] bridge: vlan: remove wrong stats help When I did the per-vlan stats iproute2 support, I left out a hunk from a previous version of the patch that was using a special subcommand "stats". Since the latest version uses the -s switch remove the help for the stats subcommand. Fixes: 7abf5de677e32 ("bridge: vlan: add support to display per-vlan statistics") Signed-off-by: Nikolay Aleksandrov --- bridge/vlan.c | 1 - 1 file changed, 1 deletion(-) diff --git a/bridge/vlan.c b/bridge/vlan.c index 0b6c69077..ebcdacee3 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -24,7 +24,6 @@ static void usage(void) fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid ] [ untagged ]\n"); fprintf(stderr, " [ self ] [ master ]\n"); fprintf(stderr, " bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n"); - fprintf(stderr, " bridge vlan { stats } [ dev DEV ] [ vid VLAN_ID ]\n"); exit(-1); } From 87e46a51983007709e5d0f1e0fad638c1ba019a5 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 12 Oct 2016 16:46:36 +0100 Subject: [PATCH 465/513] tc: cls_bpf: handle skip_sw and skip_hw flags Add support for controling hardware offload using (now standard) skip_sw and skip_hw flags in cls_bpf. Signed-off-by: Jakub Kicinski Acked-by: Daniel Borkmann Reviewed-by: Simon Horman --- man/man8/tc-bpf.8 | 14 ++++++++++++++ tc/f_bpf.c | 21 +++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/man/man8/tc-bpf.8 b/man/man8/tc-bpf.8 index c8d5c5f94..e371964d0 100644 --- a/man/man8/tc-bpf.8 +++ b/man/man8/tc-bpf.8 @@ -14,6 +14,10 @@ CLS_NAME ] [ UDS_FILE ] [ .B verbose ] [ +.B skip_hw +| +.B skip_sw +] [ .B police POLICE_SPEC ] [ .B action @@ -137,6 +141,16 @@ if set, it will dump the eBPF verifier output, even if loading the eBPF program was successful. By default, only on error, the verifier log is being emitted to the user. +.SS skip_hw | skip_sw +hardware offload control flags. By default TC will try to offload +filters to hardware if possible. +.B skip_hw +explicitly disables the attempt to offload. +.B skip_sw +forces the offload and disables running the eBPF program in the kernel. +If hardware offload is not possible and this flag was set kernel will +report an error and filter will not be installed at all. + .SS police is an optional parameter for an eBPF/cBPF classifier that specifies a police in diff --git a/tc/f_bpf.c b/tc/f_bpf.c index 5c97c863d..665bc6612 100644 --- a/tc/f_bpf.c +++ b/tc/f_bpf.c @@ -37,8 +37,8 @@ static void explain(void) fprintf(stderr, "\n"); fprintf(stderr, "eBPF use case:\n"); fprintf(stderr, " object-file FILE [ section CLS_NAME ] [ export UDS_FILE ]"); - fprintf(stderr, " [ verbose ] [ direct-action ]\n"); - fprintf(stderr, " object-pinned FILE [ direct-action ]\n"); + fprintf(stderr, " [ verbose ] [ direct-action ] [ skip_hw | skip_sw ]\n"); + fprintf(stderr, " object-pinned FILE [ direct-action ] [ skip_hw | skip_sw ]\n"); fprintf(stderr, "\n"); fprintf(stderr, "Common remaining options:\n"); fprintf(stderr, " [ action ACTION_SPEC ]\n"); @@ -66,6 +66,7 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle, { const char *bpf_obj = NULL, *bpf_uds_name = NULL; struct tcmsg *t = NLMSG_DATA(n); + unsigned int bpf_gen_flags = 0; unsigned int bpf_flags = 0; bool seen_run = false; struct rtattr *tail; @@ -107,6 +108,10 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle, } else if (matches(*argv, "direct-action") == 0 || matches(*argv, "da") == 0) { bpf_flags |= TCA_BPF_FLAG_ACT_DIRECT; + } else if (matches(*argv, "skip_hw") == 0) { + bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_HW; + } else if (matches(*argv, "skip_sw") == 0) { + bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_SW; } else if (matches(*argv, "action") == 0) { NEXT_ARG(); if (parse_action(&argc, &argv, TCA_BPF_ACT, n)) { @@ -136,6 +141,8 @@ static int bpf_parse_opt(struct filter_util *qu, char *handle, NEXT_ARG_FWD(); } + if (bpf_gen_flags) + addattr32(n, MAX_MSG, TCA_BPF_FLAGS_GEN, bpf_gen_flags); if (bpf_obj && bpf_flags) addattr32(n, MAX_MSG, TCA_BPF_FLAGS, bpf_flags); @@ -178,6 +185,16 @@ static int bpf_print_opt(struct filter_util *qu, FILE *f, fprintf(f, "direct-action "); } + if (tb[TCA_BPF_FLAGS_GEN]) { + unsigned int flags = + rta_getattr_u32(tb[TCA_BPF_FLAGS_GEN]); + + if (flags & TCA_CLS_FLAGS_SKIP_HW) + fprintf(f, "skip_hw "); + if (flags & TCA_CLS_FLAGS_SKIP_SW) + fprintf(f, "skip_sw "); + } + if (tb[TCA_BPF_OPS] && tb[TCA_BPF_OPS_LEN]) { bpf_print_ops(f, tb[TCA_BPF_OPS], rta_getattr_u16(tb[TCA_BPF_OPS_LEN])); From 9208b4e7c983447368c43e4cdc3d2cfce9e19069 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Thu, 13 Oct 2016 17:54:20 +0200 Subject: [PATCH 466/513] bridge: add support for the multicast flood flag Recently a new per-port flag was added which controls the flooding of unknown multicast, this patch adds support for controlling it via iproute2. It also updates the man pages with information about the new flag. Signed-off-by: Nikolay Aleksandrov --- bridge/link.c | 12 ++++++++++++ ip/iplink_bridge_slave.c | 9 +++++++++ man/man8/bridge.8 | 7 ++++++- man/man8/ip-link.8.in | 7 ++++++- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/bridge/link.c b/bridge/link.c index 13f606c7d..93472ad36 100644 --- a/bridge/link.c +++ b/bridge/link.c @@ -195,6 +195,9 @@ int print_linkinfo(const struct sockaddr_nl *who, if (prtb[IFLA_BRPORT_UNICAST_FLOOD]) print_onoff(fp, "flood", rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD])); + if (prtb[IFLA_BRPORT_MCAST_FLOOD]) + print_onoff(fp, "mcast_flood", + rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_FLOOD])); } } else print_portstate(fp, rta_getattr_u8(tb[IFLA_PROTINFO])); @@ -227,6 +230,7 @@ static void usage(void) fprintf(stderr, " [ learning {on | off} ]\n"); fprintf(stderr, " [ learning_sync {on | off} ]\n"); fprintf(stderr, " [ flood {on | off} ]\n"); + fprintf(stderr, " [ mcast_flood {on | off} ]\n"); fprintf(stderr, " [ hwmode {vepa | veb} ]\n"); fprintf(stderr, " [ self ] [ master ]\n"); fprintf(stderr, " bridge link show [dev DEV]\n"); @@ -265,6 +269,7 @@ static int brlink_modify(int argc, char **argv) __s8 learning = -1; __s8 learning_sync = -1; __s8 flood = -1; + __s8 mcast_flood = -1; __s8 hairpin = -1; __s8 bpdu_guard = -1; __s8 fast_leave = -1; @@ -308,6 +313,10 @@ static int brlink_modify(int argc, char **argv) NEXT_ARG(); if (!on_off("flood", &flood, *argv)) return -1; + } else if (strcmp(*argv, "mcast_flood") == 0) { + NEXT_ARG(); + if (!on_off("mcast_flood", &mcast_flood, *argv)) + return -1; } else if (strcmp(*argv, "cost") == 0) { NEXT_ARG(); cost = atoi(*argv); @@ -380,6 +389,9 @@ static int brlink_modify(int argc, char **argv) addattr8(&req.n, sizeof(req), IFLA_BRPORT_PROTECT, root_block); if (flood >= 0) addattr8(&req.n, sizeof(req), IFLA_BRPORT_UNICAST_FLOOD, flood); + if (mcast_flood >= 0) + addattr8(&req.n, sizeof(req), IFLA_BRPORT_MCAST_FLOOD, + mcast_flood); if (learning >= 0) addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING, learning); if (learning_sync >= 0) diff --git a/ip/iplink_bridge_slave.c b/ip/iplink_bridge_slave.c index 6c5c59a95..fbb3f06e8 100644 --- a/ip/iplink_bridge_slave.c +++ b/ip/iplink_bridge_slave.c @@ -33,6 +33,7 @@ static void print_explain(FILE *f) " [ proxy_arp_wifi {on | off} ]\n" " [ mcast_router MULTICAST_ROUTER ]\n" " [ mcast_fast_leave {on | off} ]\n" + " [ mcast_flood {on | off} ]\n" ); } @@ -187,6 +188,10 @@ static void bridge_slave_print_opt(struct link_util *lu, FILE *f, if (tb[IFLA_BRPORT_FAST_LEAVE]) print_onoff(f, "mcast_fast_leave", rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE])); + + if (tb[IFLA_BRPORT_MCAST_FLOOD]) + print_onoff(f, "mcast_flood", + rta_getattr_u8(tb[IFLA_BRPORT_MCAST_FLOOD])); } static void bridge_slave_parse_on_off(char *arg_name, char *arg_val, @@ -251,6 +256,10 @@ static int bridge_slave_parse_opt(struct link_util *lu, int argc, char **argv, NEXT_ARG(); bridge_slave_parse_on_off("flood", *argv, n, IFLA_BRPORT_UNICAST_FLOOD); + } else if (matches(*argv, "mcast_flood") == 0) { + NEXT_ARG(); + bridge_slave_parse_on_off("mcast_flood", *argv, n, + IFLA_BRPORT_MCAST_FLOOD); } else if (matches(*argv, "proxy_arp") == 0) { NEXT_ARG(); bridge_slave_parse_on_off("proxy_arp", *argv, n, diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index 7bfb068b7..6617e188a 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -43,7 +43,8 @@ bridge \- show / manipulate bridge addresses and devices .BR learning_sync " { " on " | " off " } ] [ " .BR flood " { " on " | " off " } ] [ " .BR hwmode " { " vepa " | " veb " } ] [ " -.BR self " ] [ " master " ] " +.BR mcast_flood " { " on " | " off " } ] [ " +.BR self " ] [ " master " ]" .ti -8 .BR "bridge link" " [ " show " ] [ " @@ -309,6 +310,10 @@ switch. .B veb - bridging happens in hardware. +.TP +.BR "mcast_flood on " or " mcast_flood off " +Controls whether a given port will be flooded with multicast traffic for which there is no MDB entry. By default this flag is on. + .TP .BI self link setting is configured on specified physical device diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 6cb97ea9c..7c0d602b5 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -1431,7 +1431,9 @@ the following additional arguments are supported: ] [ .BI mcast_router " MULTICAST_ROUTER" ] [ -.BR mcast_fast_leave " { " on " | " off "} ]" +.BR mcast_fast_leave " { " on " | " off "}" +] [ +.BR mcast_flood " { " on " | " off " } ]" .in +8 .sp @@ -1500,6 +1502,9 @@ queries. .B fastleave option above. +.BR mcast_flood " { " on " | " off " }" +- controls whether a given port will be flooded with multicast traffic for which there is no MDB entry. + .in -8 .TP From 7a34b9d098fce6778a02c475fd877e0b34aa7a13 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Sun, 9 Oct 2016 10:14:18 +0800 Subject: [PATCH 467/513] devlink: Convert conditional in dl_argv_handle_port() to switch() Discovered by Phil's covscan. The final return statement is never reached. This is not inherently clear from looking at the code, so change the conditional to a switch() statement which should clarify this. CC: Phil Sutter Signed-off-by: Hangbin Liu Acked-by: Phil Sutter --- devlink/devlink.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index e91dc5007..ccca0fb39 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -524,19 +524,18 @@ static int dl_argv_handle_port(struct dl *dl, char **p_bus_name, return -EINVAL; } slash_count = strslashcount(str); - if (slash_count != 2 && slash_count != 0) { + switch (slash_count) { + case 0: + return __dl_argv_handle_port_ifname(dl, str, p_bus_name, + p_dev_name, p_port_index); + case 2: + return __dl_argv_handle_port(str, p_bus_name, + p_dev_name, p_port_index); + default: pr_err("Wrong port identification string format.\n"); pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n"); return -EINVAL; } - if (slash_count == 2) { - return __dl_argv_handle_port(str, p_bus_name, - p_dev_name, p_port_index); - } else if (slash_count == 0) { - return __dl_argv_handle_port_ifname(dl, str, p_bus_name, - p_dev_name, p_port_index); - } - return 0; } static int dl_argv_handle_both(struct dl *dl, char **p_bus_name, From 4710e46ec31837254346766ed286f484ee61f24f Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 18 Oct 2016 14:13:09 +0200 Subject: [PATCH 468/513] tc, ipt: don't enforce iproute2 dependency on iptables-devel Since 5cd1adba79d3 ("Update to current iptables headers") compilation of iproute2 broke for systems without iptables-devel package [1]. Reason is that even though we fall back to build m_ipt.c, the include depends on a xtables-version.h header, which only ships with iptables-devel. Machines not having this package fail compilation with: [...] CC m_ipt.o In file included from ../include/iptables.h:5:0, from m_ipt.c:17: ../include/xtables.h:34:29: fatal error: xtables-version.h: No such file or directory compilation terminated. ../Config:31: recipe for target 'm_ipt.o' failed make[1]: *** [m_ipt.o] Error 1 The configure script only barks that package xtables was not found in the pkg-config search path. The generated Config then only contains f.e. TC_CONFIG_IPSET. In tc's Makefile we thus fall back to adding m_ipt.o to TCMODULES. m_ipt.c then includes the local include/iptables.h header copy, which includes the include/xtables.h copy. Latter then includes xtables-version.h, which only ships with iptables-devel. One way to resolve this is to skip this whole mess when pkg-config has no xtables config available. I've carried something along these lines locally for a while now, but it's just too annyoing. :/ Build works fine now also when xtables.pc is not available. [1] http://www.spinics.net/lists/netdev/msg366162.html Fixes: 5cd1adba79d3 ("Update to current iptables headers") Signed-off-by: Daniel Borkmann --- configure | 33 ++++++++++++++++++++++++--------- tc/Makefile | 29 ++++++++++++++--------------- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/configure b/configure index 60eb6b51a..c978da34b 100755 --- a/configure +++ b/configure @@ -57,6 +57,14 @@ EOF rm -f $TMPDIR/atmtest.c $TMPDIR/atmtest } +check_xtables() +{ + if ! ${PKG_CONFIG} xtables --exists + then + echo "TC_CONFIG_NO_XT:=y" >>Config + fi +} + check_xt() { #check if we have xtables from iptables >= 1.4.5. @@ -353,18 +361,25 @@ echo "TC schedulers" echo -n " ATM " check_atm -echo -n " IPT " -check_xt -check_xt_old -check_xt_old_internal_h -check_ipt +check_xtables +if ! grep -q TC_CONFIG_NO_XT Config +then + echo -n " IPT " + check_xt + check_xt_old + check_xt_old_internal_h + check_ipt -echo -n " IPSET " -check_ipset + echo -n " IPSET " + check_ipset +fi echo -echo -n "iptables modules directory: " -check_ipt_lib_dir +if ! grep -q TC_CONFIG_NO_XT Config +then + echo -n "iptables modules directory: " + check_ipt_lib_dir +fi echo -n "libc has setns: " check_setns diff --git a/tc/Makefile b/tc/Makefile index 8917eaf46..dfa875b5e 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -69,28 +69,27 @@ TCMODULES += q_clsact.o TCMODULES += e_bpf.o TCMODULES += f_matchall.o -ifeq ($(TC_CONFIG_IPSET), y) - ifeq ($(TC_CONFIG_XT), y) - TCMODULES += em_ipset.o - endif -endif - TCSO := ifeq ($(TC_CONFIG_ATM),y) TCSO += q_atm.so endif -ifeq ($(TC_CONFIG_XT),y) - TCSO += m_xt.so -else - ifeq ($(TC_CONFIG_XT_OLD),y) - TCSO += m_xt_old.so +ifneq ($(TC_CONFIG_NO_XT),y) + ifeq ($(TC_CONFIG_XT),y) + TCSO += m_xt.so + ifeq ($(TC_CONFIG_IPSET),y) + TCMODULES += em_ipset.o + endif else - ifeq ($(TC_CONFIG_XT_OLD_H),y) - CFLAGS += -DTC_CONFIG_XT_H - TCSO += m_xt_old.so + ifeq ($(TC_CONFIG_XT_OLD),y) + TCSO += m_xt_old.so else - TCMODULES += m_ipt.o + ifeq ($(TC_CONFIG_XT_OLD_H),y) + CFLAGS += -DTC_CONFIG_XT_H + TCSO += m_xt_old.so + else + TCMODULES += m_ipt.o + endif endif endif endif From c07a36c3db54d45792ae14613fddc448378d5eaa Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 26 Oct 2016 11:15:09 -0700 Subject: [PATCH 469/513] Revert "iproute2: macvlan: add "source" mode" This reverts commit f33b7276102c019795c034816b91de72a26cdda3. The upstream changes are not in 4.9 --- include/linux/if_link.h | 2 - ip/iplink_macvlan.c | 97 +++-------------------------------------- man/man8/ip-link.8.in | 57 ------------------------ 3 files changed, 5 insertions(+), 151 deletions(-) diff --git a/include/linux/if_link.h b/include/linux/if_link.h index 34f816612..20965c9a6 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -402,8 +402,6 @@ enum macvlan_macaddr_mode { }; #define MACVLAN_FLAG_NOPROMISC 1 -#define MACVLAN_FLAG_UNICAST 2 -#define MACVLAN_FLAG_UNICAST_ALL 4 /* VRF section */ enum { diff --git a/ip/iplink_macvlan.c b/ip/iplink_macvlan.c index 2adfc098d..413254519 100644 --- a/ip/iplink_macvlan.c +++ b/ip/iplink_macvlan.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "rt_names.h" #include "utils.h" @@ -30,11 +29,7 @@ static void print_explain(struct link_util *lu, FILE *f) { fprintf(f, - "Usage: ... %s mode MODE [flag MODE_FLAG] MODE_OPTS\n" - "MODE: private | vepa | bridge | passthru | source\n" - "MODE_FLAG: null | nopromisc | unicast | unicast_all\n" - "MODE_OPTS: for mode \"source\":\n" - "\tmacaddr { add | del | flush }\n", + "Usage: ... %s mode { private | vepa | bridge | passthru [nopromisc] }\n", lu->id ); } @@ -46,6 +41,7 @@ static void explain(struct link_util *lu) static int mode_arg(const char *arg) { +<<<<<<< HEAD fprintf(stderr, "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\", \"passthru\" or \"source\", not \"%s\"\n", arg); @@ -55,7 +51,7 @@ static int mode_arg(const char *arg) static int flag_arg(const char *arg) { fprintf(stderr, - "Error: argument of \"flag\" must be \"nopromisc\", \"unicast\", \"unicast_all\" or \"null\", not \"%s\"\n", + "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\" or \"passthru\", not \"%s\"\n", arg); return -1; } @@ -65,9 +61,6 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, { __u32 mode = 0; __u16 flags = 0; - __u32 mac_mode = 0; - int len = 0; - char abuf[32]; while (argc > 0) { if (matches(*argv, "mode") == 0) { @@ -81,45 +74,8 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, mode = MACVLAN_MODE_BRIDGE; else if (strcmp(*argv, "passthru") == 0) mode = MACVLAN_MODE_PASSTHRU; - else if (strcmp(*argv, "source") == 0) - mode = MACVLAN_MODE_SOURCE; else return mode_arg(*argv); - } else if (matches(*argv, "flag") == 0) { - NEXT_ARG(); - - if (strcmp(*argv, "nopromisc") == 0) - flags |= MACVLAN_FLAG_NOPROMISC; - else if (strcmp(*argv, "unicast") == 0) - flags |= MACVLAN_FLAG_UNICAST; - else if (strcmp(*argv, "unicast_all") == 0) - flags |= MACVLAN_FLAG_UNICAST_ALL; - else if (strcmp(*argv, "null") == 0) - flags |= 0; - else - return flag_arg(*argv); - - } else if (matches(*argv, "macaddr") == 0) { - NEXT_ARG(); - - if (strcmp(*argv, "add") == 0) { - mac_mode = MACVLAN_MACADDR_ADD; - } else if (strcmp(*argv, "del") == 0) { - mac_mode = MACVLAN_MACADDR_DEL; - } else if (strcmp(*argv, "flush") == 0) { - mac_mode = MACVLAN_MACADDR_FLUSH; - } else { - explain(lu); - return -1; - } - - if (mac_mode != MACVLAN_MACADDR_FLUSH) { - NEXT_ARG(); - - len = ll_addr_a2n(abuf, sizeof(abuf), *argv); - if (len < 0) - return -1; - } } else if (matches(*argv, "nopromisc") == 0) { flags |= MACVLAN_FLAG_NOPROMISC; } else if (matches(*argv, "help") == 0) { @@ -145,12 +101,6 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, } addattr16(n, 1024, IFLA_MACVLAN_FLAGS, flags); } - - if (mac_mode) { - addattr32(n, 1024, IFLA_MACVLAN_MACADDR_MODE, mac_mode); - if (mac_mode != MACVLAN_MACADDR_FLUSH && len > 0) - addattr_l(n, 1024, IFLA_MACVLAN_MACADDR, abuf, len); - } return 0; } @@ -158,10 +108,6 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[] { __u32 mode; __u16 flags; - __u32 count; - unsigned char *addr; - int len; - struct rtattr *rta; if (!tb) return; @@ -176,48 +122,15 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[] : mode == MACVLAN_MODE_VEPA ? "vepa" : mode == MACVLAN_MODE_BRIDGE ? "bridge" : mode == MACVLAN_MODE_PASSTHRU ? "passthru" - : mode == MACVLAN_MODE_SOURCE ? "source" : "unknown"); if (!tb[IFLA_MACVLAN_FLAGS] || RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16)) - flags = 0; - else - flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]); + return; + flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]); if (flags & MACVLAN_FLAG_NOPROMISC) fprintf(f, "nopromisc "); - if (flags & MACVLAN_FLAG_UNICAST) - fprintf(f, "flag unicast "); - if (flags & MACVLAN_FLAG_UNICAST_ALL) - fprintf(f, "flag unicast_all "); - - /* in source mode, there are more options to print */ - - if (mode != MACVLAN_MODE_SOURCE) - return; - - if (!tb[IFLA_MACVLAN_MACADDR_COUNT] || - RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_COUNT]) < sizeof(__u32)) - return; - - count = rta_getattr_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]); - fprintf(f, " remotes (%d)", count); - - if (!tb[IFLA_MACVLAN_MACADDR_DATA]) - return; - - rta = RTA_DATA(tb[IFLA_MACVLAN_MACADDR_DATA]); - len = RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_DATA]); - - for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { - if (rta->rta_type != IFLA_MACVLAN_MACADDR || - RTA_PAYLOAD(rta) < 6) - continue; - addr = RTA_DATA(rta); - fprintf(f, " %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", addr[0], - addr[1], addr[2], addr[3], addr[4], addr[5]); - } } static void macvlan_print_help(struct link_util *lu, int argc, char **argv, diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index 7c0d602b5..ee1159da6 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -135,9 +135,6 @@ ip-link \- network device configuration .IR NAME " ]" .br .RB "[ " addrgenmode " { " eui64 " | " none " | " stable_secret " | " random " } ]" -.br -.B macaddr " |" -.IR "COMMAND MACADDR |" .ti -8 @@ -240,46 +237,8 @@ Link types: - IP over Infiniband device .sp .B macvlan -.I MODE - Virtual interface base on link layer address (MAC) .sp -Modes: -.in +8 -.B private -- The device never communicates with any other device on the same upper_dev. -This even includes frames coming back from a reflective relay, where supported -by the adjacent bridge. -.sp -.B vepa -- we assume that the adjacent bridge returns all frames where both source and -destination are local to the macvlan port, i.e. the bridge is set up as a -reflective relay. Broadcast frames coming in from the upper_dev get flooded to -all macvlan interfaces in VEPA mode. We never deliver any frames locally. -.sp -.B bridge -- behave as simple bridge between different macvlan interfaces on the same -port. Frames from one interface to another one get delivered directly and are -not sent out externally. Broadcast frames get flooded to all other bridge -ports and to the external interface, but when they come back from a reflective -relay, we don't deliver them again. Since we know all the MAC addresses, the -macvlan bridge mode does not require learning or STP like the bridge module -does. -.sp -.B passthru -- allows takeover of the underlying device and passing it to a guest using -virtio with macvtap backend. Only one macvlan device is allowed in passthru -mode and it inherits the mac address from the underlying device and sets it in -promiscuous mode to receive and forward all the packets. -.sp -.B source -- allows one to set a list of allowed mac address, which is used to match -against source mac address from received frames on underlying interface. This -allows creating mac based VLAN associations, instead of standard port or tag -based. The feature is useful to deploy 802.1x mac based behavior, -where drivers of underlying interfaces doesn't allows that. -.sp -.in -8 -.sp .B macvtap - Virtual interface based on link layer address (MAC) and TAP. .sp @@ -1124,22 +1083,6 @@ specifies the type of the device. .SS ip link set - change device attributes -.TP -.BI macaddr " COMMAND MACADDR" -add or removes MACADDR from allowed list for source mode macvlan type link -Commands: -.in +8 -.B add -- add MACADDR to allowed list -.sp -.B del -- remove MACADDR from allowed list -.sp -.B flush -- flush whole allowed list -.sp -.in -8 - .PP .B Warning: If multiple parameter changes are requested, From f3f339e9590a50a0a75be88f6e32c227e8623b25 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 26 Oct 2016 11:19:11 -0700 Subject: [PATCH 470/513] cleanup debris from revert Last revert didn't come out clean. --- ip/iplink_macvlan.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/ip/iplink_macvlan.c b/ip/iplink_macvlan.c index 413254519..83ff961b1 100644 --- a/ip/iplink_macvlan.c +++ b/ip/iplink_macvlan.c @@ -39,16 +39,8 @@ static void explain(struct link_util *lu) print_explain(lu, stderr); } -static int mode_arg(const char *arg) -{ -<<<<<<< HEAD - fprintf(stderr, - "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\", \"passthru\" or \"source\", not \"%s\"\n", - arg); - return -1; -} -static int flag_arg(const char *arg) +static int mode_arg(const char *arg) { fprintf(stderr, "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\" or \"passthru\", not \"%s\"\n", From 8ae2c5382bd9d98a8f7ddcb1faad1a978d773909 Mon Sep 17 00:00:00 2001 From: "stefan@datenfreihafen.org" Date: Fri, 28 Oct 2016 11:42:03 +0200 Subject: [PATCH 471/513] ip: update link types to show 6lowpan and ieee802.15.4 monitor Both types have been missing here and thus ip always showed only the numbers. Based on a suggestion from Alexander Aring. Signed-off-by: Stefan Schmidt --- lib/ll_types.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ll_types.c b/lib/ll_types.c index 2c5bf8b57..eca617f31 100644 --- a/lib/ll_types.c +++ b/lib/ll_types.c @@ -100,11 +100,13 @@ __PF(IEEE80211,ieee802.11) __PF(IEEE80211_PRISM,ieee802.11/prism) __PF(IEEE80211_RADIOTAP,ieee802.11/radiotap) __PF(IEEE802154, ieee802.15.4) +__PF(IEEE802154_MONITOR, ieee802.15.4/monitor) __PF(PHONET, phonet) __PF(PHONET_PIPE, phonet_pipe) __PF(CAIF, caif) __PF(IP6GRE, gre6) __PF(NETLINK, netlink) +__PF(6LOWPAN, 6lowpan) __PF(NONE, none) __PF(VOID,void) From 878dadc79d247aa37b67fb30608e58ef1f9ab9ff Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Sat, 29 Oct 2016 22:20:19 +0300 Subject: [PATCH 472/513] iproute2: ss: escape all null bytes in abstract unix domain socket Abstract unix domain socket may embed null characters, these should be translated to '@' when printed by ss the same way the null prefix is currently being translated. Signed-off-by: Isaac Boukris --- misc/ss.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/misc/ss.c b/misc/ss.c index dd77b8153..0e28998f5 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -2895,7 +2895,9 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh, memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len); name[len] = '\0'; if (name[0] == '\0') - name[0] = '@'; + for (int i = 0; i < len; i++) + if (name[i] == '\0') + name[i] = '@'; stat.name = &name[0]; memcpy(stat.local.data, &stat.name, sizeof(stat.name)); } From d9c3995ab7ce7fb523d50ca513283393066219ca Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Wed, 2 Nov 2016 17:09:58 +0200 Subject: [PATCH 473/513] tc: flower: Fix usage message Remove left over usage from removal of eth_type argument. Fixes: 488b41d020fb ('tc: flower no need to specify the ethertype') Signed-off-by: Paul Blakey Reviewed-by: Simon Horman --- man/man8/tc-flower.8 | 9 --------- tc/f_flower.c | 3 +-- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8 index 74f766477..16ef26179 100644 --- a/man/man8/tc-flower.8 +++ b/man/man8/tc-flower.8 @@ -23,8 +23,6 @@ flower \- flow based traffic control filter .R " | { " .BR dst_mac " | " src_mac " } " .IR mac_address " | " -.BR eth_type " { " ipv4 " | " ipv6 " | " 802.1Q " | " -.IR ETH_TYPE " } | " .B vlan_id .IR VID " | " .B vlan_prio @@ -75,13 +73,6 @@ Do not process filter by hardware. .BI src_mac " mac_address" Match on source or destination MAC address. .TP -.BI eth_type " ETH_TYPE" -Match on the next protocol. -.I ETH_TYPE -may be either -.BR ipv4 , ipv6 , 802.1Q , -or an unsigned 16bit value in hexadecimal format. -.TP .BI vlan_id " VID" Match on vlan tag id. .I VID diff --git a/tc/f_flower.c b/tc/f_flower.c index 2d31d1aa8..f39b1f7fd 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -36,7 +36,6 @@ static void explain(void) fprintf(stderr, " vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"); fprintf(stderr, " dst_mac MAC-ADDR |\n"); fprintf(stderr, " src_mac MAC-ADDR |\n"); - fprintf(stderr, " [ipv4 | ipv6 ] |\n"); fprintf(stderr, " ip_proto [tcp | udp | IP-PROTO ] |\n"); fprintf(stderr, " dst_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"); fprintf(stderr, " src_ip [ IPV4-ADDR | IPV6-ADDR ] |\n"); @@ -45,7 +44,7 @@ static void explain(void) fprintf(stderr, " FILTERID := X:Y:Z\n"); fprintf(stderr, " ACTION-SPEC := ... look at individual actions\n"); fprintf(stderr, "\n"); - fprintf(stderr, "NOTE: CLASSID, ETH-TYPE, IP-PROTO are parsed as hexadecimal input.\n"); + fprintf(stderr, "NOTE: CLASSID, IP-PROTO are parsed as hexadecimal input.\n"); fprintf(stderr, "NOTE: There can be only used one mask per one prio. If user needs\n"); fprintf(stderr, " to specify different mask, he has to use different prio.\n"); } From 5dec02d7b4b70128a661bab1ff991c605ba28b3f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 9 Nov 2016 12:12:23 +0100 Subject: [PATCH 474/513] include: Add linux/sctp.h Add sanitized UAPI linux/sctp.h header file. Signed-off-by: Phil Sutter --- include/linux/sctp.h | 1005 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1005 insertions(+) create mode 100644 include/linux/sctp.h diff --git a/include/linux/sctp.h b/include/linux/sctp.h new file mode 100644 index 000000000..eee08c066 --- /dev/null +++ b/include/linux/sctp.h @@ -0,0 +1,1005 @@ +/* SCTP kernel implementation + * (C) Copyright IBM Corp. 2001, 2004 + * Copyright (c) 1999-2000 Cisco, Inc. + * Copyright (c) 1999-2001 Motorola, Inc. + * Copyright (c) 2002 Intel Corp. + * + * This file is part of the SCTP kernel implementation + * + * This header represents the structures and constants needed to support + * the SCTP Extension to the Sockets API. + * + * This SCTP implementation is free software; + * you can redistribute it and/or modify it under the terms of + * the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This SCTP implementation is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * ************************ + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, see + * . + * + * Please send any bug reports or fixes you make to the + * email address(es): + * lksctp developers + * + * Or submit a bug report through the following website: + * http://www.sf.net/projects/lksctp + * + * Written or modified by: + * La Monte H.P. Yarroll + * R. Stewart + * K. Morneau + * Q. Xie + * Karl Knutson + * Jon Grimm + * Daisy Chang + * Ryan Layer + * Ardelle Fan + * Sridhar Samudrala + * Inaky Perez-Gonzalez + * Vlad Yasevich + * + * Any bugs reported given to us we will try to fix... any fixes shared will + * be incorporated into the next SCTP release. + */ + +#ifndef _SCTP_H +#define _SCTP_H + +#include +#include + +typedef __s32 sctp_assoc_t; + +/* The following symbols come from the Sockets API Extensions for + * SCTP . + */ +#define SCTP_RTOINFO 0 +#define SCTP_ASSOCINFO 1 +#define SCTP_INITMSG 2 +#define SCTP_NODELAY 3 /* Get/set nodelay option. */ +#define SCTP_AUTOCLOSE 4 +#define SCTP_SET_PEER_PRIMARY_ADDR 5 +#define SCTP_PRIMARY_ADDR 6 +#define SCTP_ADAPTATION_LAYER 7 +#define SCTP_DISABLE_FRAGMENTS 8 +#define SCTP_PEER_ADDR_PARAMS 9 +#define SCTP_DEFAULT_SEND_PARAM 10 +#define SCTP_EVENTS 11 +#define SCTP_I_WANT_MAPPED_V4_ADDR 12 /* Turn on/off mapped v4 addresses */ +#define SCTP_MAXSEG 13 /* Get/set maximum fragment. */ +#define SCTP_STATUS 14 +#define SCTP_GET_PEER_ADDR_INFO 15 +#define SCTP_DELAYED_ACK_TIME 16 +#define SCTP_DELAYED_ACK SCTP_DELAYED_ACK_TIME +#define SCTP_DELAYED_SACK SCTP_DELAYED_ACK_TIME +#define SCTP_CONTEXT 17 +#define SCTP_FRAGMENT_INTERLEAVE 18 +#define SCTP_PARTIAL_DELIVERY_POINT 19 /* Set/Get partial delivery point */ +#define SCTP_MAX_BURST 20 /* Set/Get max burst */ +#define SCTP_AUTH_CHUNK 21 /* Set only: add a chunk type to authenticate */ +#define SCTP_HMAC_IDENT 22 +#define SCTP_AUTH_KEY 23 +#define SCTP_AUTH_ACTIVE_KEY 24 +#define SCTP_AUTH_DELETE_KEY 25 +#define SCTP_PEER_AUTH_CHUNKS 26 /* Read only */ +#define SCTP_LOCAL_AUTH_CHUNKS 27 /* Read only */ +#define SCTP_GET_ASSOC_NUMBER 28 /* Read only */ +#define SCTP_GET_ASSOC_ID_LIST 29 /* Read only */ +#define SCTP_AUTO_ASCONF 30 +#define SCTP_PEER_ADDR_THLDS 31 +#define SCTP_RECVRCVINFO 32 +#define SCTP_RECVNXTINFO 33 +#define SCTP_DEFAULT_SNDINFO 34 + +/* Internal Socket Options. Some of the sctp library functions are + * implemented using these socket options. + */ +#define SCTP_SOCKOPT_BINDX_ADD 100 /* BINDX requests for adding addrs */ +#define SCTP_SOCKOPT_BINDX_REM 101 /* BINDX requests for removing addrs. */ +#define SCTP_SOCKOPT_PEELOFF 102 /* peel off association. */ +/* Options 104-106 are deprecated and removed. Do not use this space */ +#define SCTP_SOCKOPT_CONNECTX_OLD 107 /* CONNECTX old requests. */ +#define SCTP_GET_PEER_ADDRS 108 /* Get all peer address. */ +#define SCTP_GET_LOCAL_ADDRS 109 /* Get all local address. */ +#define SCTP_SOCKOPT_CONNECTX 110 /* CONNECTX requests. */ +#define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */ +#define SCTP_GET_ASSOC_STATS 112 /* Read only */ +#define SCTP_PR_SUPPORTED 113 +#define SCTP_DEFAULT_PRINFO 114 +#define SCTP_PR_ASSOC_STATUS 115 + +/* PR-SCTP policies */ +#define SCTP_PR_SCTP_NONE 0x0000 +#define SCTP_PR_SCTP_TTL 0x0010 +#define SCTP_PR_SCTP_RTX 0x0020 +#define SCTP_PR_SCTP_PRIO 0x0030 +#define SCTP_PR_SCTP_MAX SCTP_PR_SCTP_PRIO +#define SCTP_PR_SCTP_MASK 0x0030 + +#define __SCTP_PR_INDEX(x) ((x >> 4) - 1) +#define SCTP_PR_INDEX(x) __SCTP_PR_INDEX(SCTP_PR_SCTP_ ## x) + +#define SCTP_PR_POLICY(x) ((x) & SCTP_PR_SCTP_MASK) +#define SCTP_PR_SET_POLICY(flags, x) \ + do { \ + flags &= ~SCTP_PR_SCTP_MASK; \ + flags |= x; \ + } while (0) + +#define SCTP_PR_TTL_ENABLED(x) (SCTP_PR_POLICY(x) == SCTP_PR_SCTP_TTL) +#define SCTP_PR_RTX_ENABLED(x) (SCTP_PR_POLICY(x) == SCTP_PR_SCTP_RTX) +#define SCTP_PR_PRIO_ENABLED(x) (SCTP_PR_POLICY(x) == SCTP_PR_SCTP_PRIO) + +/* These are bit fields for msghdr->msg_flags. See section 5.1. */ +/* On user space Linux, these live in as an enum. */ +enum sctp_msg_flags { + MSG_NOTIFICATION = 0x8000, +#define MSG_NOTIFICATION MSG_NOTIFICATION +}; + +/* 5.3.1 SCTP Initiation Structure (SCTP_INIT) + * + * This cmsghdr structure provides information for initializing new + * SCTP associations with sendmsg(). The SCTP_INITMSG socket option + * uses this same data structure. This structure is not used for + * recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg + */ +struct sctp_initmsg { + __u16 sinit_num_ostreams; + __u16 sinit_max_instreams; + __u16 sinit_max_attempts; + __u16 sinit_max_init_timeo; +}; + +/* 5.3.2 SCTP Header Information Structure (SCTP_SNDRCV) + * + * This cmsghdr structure specifies SCTP options for sendmsg() and + * describes SCTP header information about a received message through + * recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ---------------------- + * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo + */ +struct sctp_sndrcvinfo { + __u16 sinfo_stream; + __u16 sinfo_ssn; + __u16 sinfo_flags; + __u32 sinfo_ppid; + __u32 sinfo_context; + __u32 sinfo_timetolive; + __u32 sinfo_tsn; + __u32 sinfo_cumtsn; + sctp_assoc_t sinfo_assoc_id; +}; + +/* 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO) + * + * This cmsghdr structure specifies SCTP options for sendmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ------------------- + * IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo + */ +struct sctp_sndinfo { + __u16 snd_sid; + __u16 snd_flags; + __u32 snd_ppid; + __u32 snd_context; + sctp_assoc_t snd_assoc_id; +}; + +/* 5.3.5 SCTP Receive Information Structure (SCTP_RCVINFO) + * + * This cmsghdr structure describes SCTP receive information + * about a received message through recvmsg(). + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ------------------- + * IPPROTO_SCTP SCTP_RCVINFO struct sctp_rcvinfo + */ +struct sctp_rcvinfo { + __u16 rcv_sid; + __u16 rcv_ssn; + __u16 rcv_flags; + __u32 rcv_ppid; + __u32 rcv_tsn; + __u32 rcv_cumtsn; + __u32 rcv_context; + sctp_assoc_t rcv_assoc_id; +}; + +/* 5.3.6 SCTP Next Receive Information Structure (SCTP_NXTINFO) + * + * This cmsghdr structure describes SCTP receive information + * of the next message that will be delivered through recvmsg() + * if this information is already available when delivering + * the current message. + * + * cmsg_level cmsg_type cmsg_data[] + * ------------ ------------ ------------------- + * IPPROTO_SCTP SCTP_NXTINFO struct sctp_nxtinfo + */ +struct sctp_nxtinfo { + __u16 nxt_sid; + __u16 nxt_flags; + __u32 nxt_ppid; + __u32 nxt_length; + sctp_assoc_t nxt_assoc_id; +}; + +/* + * sinfo_flags: 16 bits (unsigned integer) + * + * This field may contain any of the following flags and is composed of + * a bitwise OR of these values. + */ +enum sctp_sinfo_flags { + SCTP_UNORDERED = (1 << 0), /* Send/receive message unordered. */ + SCTP_ADDR_OVER = (1 << 1), /* Override the primary destination. */ + SCTP_ABORT = (1 << 2), /* Send an ABORT message to the peer. */ + SCTP_SACK_IMMEDIATELY = (1 << 3), /* SACK should be sent without delay. */ + SCTP_NOTIFICATION = MSG_NOTIFICATION, /* Next message is not user msg but notification. */ + SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. */ +}; + +typedef union { + __u8 raw; + struct sctp_initmsg init; + struct sctp_sndrcvinfo sndrcv; +} sctp_cmsg_data_t; + +/* These are cmsg_types. */ +typedef enum sctp_cmsg_type { + SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */ +#define SCTP_INIT SCTP_INIT + SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */ +#define SCTP_SNDRCV SCTP_SNDRCV + SCTP_SNDINFO, /* 5.3.4 SCTP Send Information Structure */ +#define SCTP_SNDINFO SCTP_SNDINFO + SCTP_RCVINFO, /* 5.3.5 SCTP Receive Information Structure */ +#define SCTP_RCVINFO SCTP_RCVINFO + SCTP_NXTINFO, /* 5.3.6 SCTP Next Receive Information Structure */ +#define SCTP_NXTINFO SCTP_NXTINFO +} sctp_cmsg_t; + +/* + * 5.3.1.1 SCTP_ASSOC_CHANGE + * + * Communication notifications inform the ULP that an SCTP association + * has either begun or ended. The identifier for a new association is + * provided by this notificaion. The notification information has the + * following format: + * + */ +struct sctp_assoc_change { + __u16 sac_type; + __u16 sac_flags; + __u32 sac_length; + __u16 sac_state; + __u16 sac_error; + __u16 sac_outbound_streams; + __u16 sac_inbound_streams; + sctp_assoc_t sac_assoc_id; + __u8 sac_info[0]; +}; + +/* + * sac_state: 32 bits (signed integer) + * + * This field holds one of a number of values that communicate the + * event that happened to the association. They include: + * + * Note: The following state names deviate from the API draft as + * the names clash too easily with other kernel symbols. + */ +enum sctp_sac_state { + SCTP_COMM_UP, + SCTP_COMM_LOST, + SCTP_RESTART, + SCTP_SHUTDOWN_COMP, + SCTP_CANT_STR_ASSOC, +}; + +/* + * 5.3.1.2 SCTP_PEER_ADDR_CHANGE + * + * When a destination address on a multi-homed peer encounters a change + * an interface details event is sent. The information has the + * following structure: + */ +struct sctp_paddr_change { + __u16 spc_type; + __u16 spc_flags; + __u32 spc_length; + struct sockaddr_storage spc_aaddr; + int spc_state; + int spc_error; + sctp_assoc_t spc_assoc_id; +} __attribute__((packed, aligned(4))); + +/* + * spc_state: 32 bits (signed integer) + * + * This field holds one of a number of values that communicate the + * event that happened to the address. They include: + */ +enum sctp_spc_state { + SCTP_ADDR_AVAILABLE, + SCTP_ADDR_UNREACHABLE, + SCTP_ADDR_REMOVED, + SCTP_ADDR_ADDED, + SCTP_ADDR_MADE_PRIM, + SCTP_ADDR_CONFIRMED, +}; + + +/* + * 5.3.1.3 SCTP_REMOTE_ERROR + * + * A remote peer may send an Operational Error message to its peer. + * This message indicates a variety of error conditions on an + * association. The entire error TLV as it appears on the wire is + * included in a SCTP_REMOTE_ERROR event. Please refer to the SCTP + * specification [SCTP] and any extensions for a list of possible + * error formats. SCTP error TLVs have the format: + */ +struct sctp_remote_error { + __u16 sre_type; + __u16 sre_flags; + __u32 sre_length; + __u16 sre_error; + sctp_assoc_t sre_assoc_id; + __u8 sre_data[0]; +}; + + +/* + * 5.3.1.4 SCTP_SEND_FAILED + * + * If SCTP cannot deliver a message it may return the message as a + * notification. + */ +struct sctp_send_failed { + __u16 ssf_type; + __u16 ssf_flags; + __u32 ssf_length; + __u32 ssf_error; + struct sctp_sndrcvinfo ssf_info; + sctp_assoc_t ssf_assoc_id; + __u8 ssf_data[0]; +}; + +/* + * ssf_flags: 16 bits (unsigned integer) + * + * The flag value will take one of the following values + * + * SCTP_DATA_UNSENT - Indicates that the data was never put on + * the wire. + * + * SCTP_DATA_SENT - Indicates that the data was put on the wire. + * Note that this does not necessarily mean that the + * data was (or was not) successfully delivered. + */ +enum sctp_ssf_flags { + SCTP_DATA_UNSENT, + SCTP_DATA_SENT, +}; + +/* + * 5.3.1.5 SCTP_SHUTDOWN_EVENT + * + * When a peer sends a SHUTDOWN, SCTP delivers this notification to + * inform the application that it should cease sending data. + */ +struct sctp_shutdown_event { + __u16 sse_type; + __u16 sse_flags; + __u32 sse_length; + sctp_assoc_t sse_assoc_id; +}; + +/* + * 5.3.1.6 SCTP_ADAPTATION_INDICATION + * + * When a peer sends a Adaptation Layer Indication parameter , SCTP + * delivers this notification to inform the application + * that of the peers requested adaptation layer. + */ +struct sctp_adaptation_event { + __u16 sai_type; + __u16 sai_flags; + __u32 sai_length; + __u32 sai_adaptation_ind; + sctp_assoc_t sai_assoc_id; +}; + +/* + * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT + * + * When a receiver is engaged in a partial delivery of a + * message this notification will be used to indicate + * various events. + */ +struct sctp_pdapi_event { + __u16 pdapi_type; + __u16 pdapi_flags; + __u32 pdapi_length; + __u32 pdapi_indication; + sctp_assoc_t pdapi_assoc_id; +}; + +enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, }; + +/* + * 5.3.1.8. SCTP_AUTHENTICATION_EVENT + * + * When a receiver is using authentication this message will provide + * notifications regarding new keys being made active as well as errors. + */ +struct sctp_authkey_event { + __u16 auth_type; + __u16 auth_flags; + __u32 auth_length; + __u16 auth_keynumber; + __u16 auth_altkeynumber; + __u32 auth_indication; + sctp_assoc_t auth_assoc_id; +}; + +enum { SCTP_AUTH_NEWKEY = 0, }; + +/* + * 6.1.9. SCTP_SENDER_DRY_EVENT + * + * When the SCTP stack has no more user data to send or retransmit, this + * notification is given to the user. Also, at the time when a user app + * subscribes to this event, if there is no data to be sent or + * retransmit, the stack will immediately send up this notification. + */ +struct sctp_sender_dry_event { + __u16 sender_dry_type; + __u16 sender_dry_flags; + __u32 sender_dry_length; + sctp_assoc_t sender_dry_assoc_id; +}; + +/* + * Described in Section 7.3 + * Ancillary Data and Notification Interest Options + */ +struct sctp_event_subscribe { + __u8 sctp_data_io_event; + __u8 sctp_association_event; + __u8 sctp_address_event; + __u8 sctp_send_failure_event; + __u8 sctp_peer_error_event; + __u8 sctp_shutdown_event; + __u8 sctp_partial_delivery_event; + __u8 sctp_adaptation_layer_event; + __u8 sctp_authentication_event; + __u8 sctp_sender_dry_event; +}; + +/* + * 5.3.1 SCTP Notification Structure + * + * The notification structure is defined as the union of all + * notification types. + * + */ +union sctp_notification { + struct { + __u16 sn_type; /* Notification type. */ + __u16 sn_flags; + __u32 sn_length; + } sn_header; + struct sctp_assoc_change sn_assoc_change; + struct sctp_paddr_change sn_paddr_change; + struct sctp_remote_error sn_remote_error; + struct sctp_send_failed sn_send_failed; + struct sctp_shutdown_event sn_shutdown_event; + struct sctp_adaptation_event sn_adaptation_event; + struct sctp_pdapi_event sn_pdapi_event; + struct sctp_authkey_event sn_authkey_event; + struct sctp_sender_dry_event sn_sender_dry_event; +}; + +/* Section 5.3.1 + * All standard values for sn_type flags are greater than 2^15. + * Values from 2^15 and down are reserved. + */ + +enum sctp_sn_type { + SCTP_SN_TYPE_BASE = (1<<15), + SCTP_ASSOC_CHANGE, +#define SCTP_ASSOC_CHANGE SCTP_ASSOC_CHANGE + SCTP_PEER_ADDR_CHANGE, +#define SCTP_PEER_ADDR_CHANGE SCTP_PEER_ADDR_CHANGE + SCTP_SEND_FAILED, +#define SCTP_SEND_FAILED SCTP_SEND_FAILED + SCTP_REMOTE_ERROR, +#define SCTP_REMOTE_ERROR SCTP_REMOTE_ERROR + SCTP_SHUTDOWN_EVENT, +#define SCTP_SHUTDOWN_EVENT SCTP_SHUTDOWN_EVENT + SCTP_PARTIAL_DELIVERY_EVENT, +#define SCTP_PARTIAL_DELIVERY_EVENT SCTP_PARTIAL_DELIVERY_EVENT + SCTP_ADAPTATION_INDICATION, +#define SCTP_ADAPTATION_INDICATION SCTP_ADAPTATION_INDICATION + SCTP_AUTHENTICATION_EVENT, +#define SCTP_AUTHENTICATION_INDICATION SCTP_AUTHENTICATION_EVENT + SCTP_SENDER_DRY_EVENT, +#define SCTP_SENDER_DRY_EVENT SCTP_SENDER_DRY_EVENT +}; + +/* Notification error codes used to fill up the error fields in some + * notifications. + * SCTP_PEER_ADDRESS_CHAGE : spc_error + * SCTP_ASSOC_CHANGE : sac_error + * These names should be potentially included in the draft 04 of the SCTP + * sockets API specification. + */ +typedef enum sctp_sn_error { + SCTP_FAILED_THRESHOLD, + SCTP_RECEIVED_SACK, + SCTP_HEARTBEAT_SUCCESS, + SCTP_RESPONSE_TO_USER_REQ, + SCTP_INTERNAL_ERROR, + SCTP_SHUTDOWN_GUARD_EXPIRES, + SCTP_PEER_FAULTY, +} sctp_sn_error_t; + +/* + * 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO) + * + * The protocol parameters used to initialize and bound retransmission + * timeout (RTO) are tunable. See [SCTP] for more information on how + * these parameters are used in RTO calculation. + */ +struct sctp_rtoinfo { + sctp_assoc_t srto_assoc_id; + __u32 srto_initial; + __u32 srto_max; + __u32 srto_min; +}; + +/* + * 7.1.2 Association Parameters (SCTP_ASSOCINFO) + * + * This option is used to both examine and set various association and + * endpoint parameters. + */ +struct sctp_assocparams { + sctp_assoc_t sasoc_assoc_id; + __u16 sasoc_asocmaxrxt; + __u16 sasoc_number_peer_destinations; + __u32 sasoc_peer_rwnd; + __u32 sasoc_local_rwnd; + __u32 sasoc_cookie_life; +}; + +/* + * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) + * + * Requests that the peer mark the enclosed address as the association + * primary. The enclosed address must be one of the association's + * locally bound addresses. The following structure is used to make a + * set primary request: + */ +struct sctp_setpeerprim { + sctp_assoc_t sspp_assoc_id; + struct sockaddr_storage sspp_addr; +} __attribute__((packed, aligned(4))); + +/* + * 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) + * + * Requests that the local SCTP stack use the enclosed peer address as + * the association primary. The enclosed address must be one of the + * association peer's addresses. The following structure is used to + * make a set peer primary request: + */ +struct sctp_prim { + sctp_assoc_t ssp_assoc_id; + struct sockaddr_storage ssp_addr; +} __attribute__((packed, aligned(4))); + +/* For backward compatibility use, define the old name too */ +#define sctp_setprim sctp_prim + +/* + * 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER) + * + * Requests that the local endpoint set the specified Adaptation Layer + * Indication parameter for all future INIT and INIT-ACK exchanges. + */ +struct sctp_setadaptation { + __u32 ssb_adaptation_ind; +}; + +/* + * 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) + * + * Applications can enable or disable heartbeats for any peer address + * of an association, modify an address's heartbeat interval, force a + * heartbeat to be sent immediately, and adjust the address's maximum + * number of retransmissions sent before an address is considered + * unreachable. The following structure is used to access and modify an + * address's parameters: + */ +enum sctp_spp_flags { + SPP_HB_ENABLE = 1<<0, /*Enable heartbeats*/ + SPP_HB_DISABLE = 1<<1, /*Disable heartbeats*/ + SPP_HB = SPP_HB_ENABLE | SPP_HB_DISABLE, + SPP_HB_DEMAND = 1<<2, /*Send heartbeat immediately*/ + SPP_PMTUD_ENABLE = 1<<3, /*Enable PMTU discovery*/ + SPP_PMTUD_DISABLE = 1<<4, /*Disable PMTU discovery*/ + SPP_PMTUD = SPP_PMTUD_ENABLE | SPP_PMTUD_DISABLE, + SPP_SACKDELAY_ENABLE = 1<<5, /*Enable SACK*/ + SPP_SACKDELAY_DISABLE = 1<<6, /*Disable SACK*/ + SPP_SACKDELAY = SPP_SACKDELAY_ENABLE | SPP_SACKDELAY_DISABLE, + SPP_HB_TIME_IS_ZERO = 1<<7, /* Set HB delay to 0 */ +}; + +struct sctp_paddrparams { + sctp_assoc_t spp_assoc_id; + struct sockaddr_storage spp_address; + __u32 spp_hbinterval; + __u16 spp_pathmaxrxt; + __u32 spp_pathmtu; + __u32 spp_sackdelay; + __u32 spp_flags; +} __attribute__((packed, aligned(4))); + +/* + * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) + * + * This set option adds a chunk type that the user is requesting to be + * received only in an authenticated way. Changes to the list of chunks + * will only effect future associations on the socket. + */ +struct sctp_authchunk { + __u8 sauth_chunk; +}; + +/* + * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) + * + * This option gets or sets the list of HMAC algorithms that the local + * endpoint requires the peer to use. + */ +/* This here is only used by user space as is. It might not be a good idea + * to export/reveal the whole structure with reserved fields etc. + */ +enum { + SCTP_AUTH_HMAC_ID_SHA1 = 1, + SCTP_AUTH_HMAC_ID_SHA256 = 3, +}; + +struct sctp_hmacalgo { + __u32 shmac_num_idents; + __u16 shmac_idents[]; +}; + +/* Sadly, user and kernel space have different names for + * this structure member, so this is to not break anything. + */ +#define shmac_number_of_idents shmac_num_idents + +/* + * 7.1.20. Set a shared key (SCTP_AUTH_KEY) + * + * This option will set a shared secret key which is used to build an + * association shared key. + */ +struct sctp_authkey { + sctp_assoc_t sca_assoc_id; + __u16 sca_keynumber; + __u16 sca_keylength; + __u8 sca_key[]; +}; + +/* + * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) + * + * This option will get or set the active shared key to be used to build + * the association shared key. + */ + +struct sctp_authkeyid { + sctp_assoc_t scact_assoc_id; + __u16 scact_keynumber; +}; + + +/* + * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) + * + * This option will effect the way delayed acks are performed. This + * option allows you to get or set the delayed ack time, in + * milliseconds. It also allows changing the delayed ack frequency. + * Changing the frequency to 1 disables the delayed sack algorithm. If + * the assoc_id is 0, then this sets or gets the endpoints default + * values. If the assoc_id field is non-zero, then the set or get + * effects the specified association for the one to many model (the + * assoc_id field is ignored by the one to one model). Note that if + * sack_delay or sack_freq are 0 when setting this option, then the + * current values will remain unchanged. + */ +struct sctp_sack_info { + sctp_assoc_t sack_assoc_id; + uint32_t sack_delay; + uint32_t sack_freq; +}; + +struct sctp_assoc_value { + sctp_assoc_t assoc_id; + uint32_t assoc_value; +}; + +/* + * 7.2.2 Peer Address Information + * + * Applications can retrieve information about a specific peer address + * of an association, including its reachability state, congestion + * window, and retransmission timer values. This information is + * read-only. The following structure is used to access this + * information: + */ +struct sctp_paddrinfo { + sctp_assoc_t spinfo_assoc_id; + struct sockaddr_storage spinfo_address; + __s32 spinfo_state; + __u32 spinfo_cwnd; + __u32 spinfo_srtt; + __u32 spinfo_rto; + __u32 spinfo_mtu; +} __attribute__((packed, aligned(4))); + +/* Peer addresses's state. */ +/* UNKNOWN: Peer address passed by the upper layer in sendmsg or connect[x] + * calls. + * UNCONFIRMED: Peer address received in INIT/INIT-ACK address parameters. + * Not yet confirmed by a heartbeat and not available for data + * transfers. + * ACTIVE : Peer address confirmed, active and available for data transfers. + * INACTIVE: Peer address inactive and not available for data transfers. + */ +enum sctp_spinfo_state { + SCTP_INACTIVE, + SCTP_PF, + SCTP_ACTIVE, + SCTP_UNCONFIRMED, + SCTP_UNKNOWN = 0xffff /* Value used for transport state unknown */ +}; + +/* + * 7.2.1 Association Status (SCTP_STATUS) + * + * Applications can retrieve current status information about an + * association, including association state, peer receiver window size, + * number of unacked data chunks, and number of data chunks pending + * receipt. This information is read-only. The following structure is + * used to access this information: + */ +struct sctp_status { + sctp_assoc_t sstat_assoc_id; + __s32 sstat_state; + __u32 sstat_rwnd; + __u16 sstat_unackdata; + __u16 sstat_penddata; + __u16 sstat_instrms; + __u16 sstat_outstrms; + __u32 sstat_fragmentation_point; + struct sctp_paddrinfo sstat_primary; +}; + +/* + * 7.2.3. Get the list of chunks the peer requires to be authenticated + * (SCTP_PEER_AUTH_CHUNKS) + * + * This option gets a list of chunks for a specified association that + * the peer requires to be received authenticated only. + */ +struct sctp_authchunks { + sctp_assoc_t gauth_assoc_id; + __u32 gauth_number_of_chunks; + uint8_t gauth_chunks[]; +}; + +/* The broken spelling has been released already in lksctp-tools header, + * so don't break anyone, now that it's fixed. + */ +#define guth_number_of_chunks gauth_number_of_chunks + +/* Association states. */ +enum sctp_sstat_state { + SCTP_EMPTY = 0, + SCTP_CLOSED = 1, + SCTP_COOKIE_WAIT = 2, + SCTP_COOKIE_ECHOED = 3, + SCTP_ESTABLISHED = 4, + SCTP_SHUTDOWN_PENDING = 5, + SCTP_SHUTDOWN_SENT = 6, + SCTP_SHUTDOWN_RECEIVED = 7, + SCTP_SHUTDOWN_ACK_SENT = 8, +}; + +/* + * 8.2.6. Get the Current Identifiers of Associations + * (SCTP_GET_ASSOC_ID_LIST) + * + * This option gets the current list of SCTP association identifiers of + * the SCTP associations handled by a one-to-many style socket. + */ +struct sctp_assoc_ids { + __u32 gaids_number_of_ids; + sctp_assoc_t gaids_assoc_id[]; +}; + +/* + * 8.3, 8.5 get all peer/local addresses in an association. + * This parameter struct is used by SCTP_GET_PEER_ADDRS and + * SCTP_GET_LOCAL_ADDRS socket options used internally to implement + * sctp_getpaddrs() and sctp_getladdrs() API. + */ +struct sctp_getaddrs_old { + sctp_assoc_t assoc_id; + int addr_num; + struct sockaddr *addrs; +}; + +struct sctp_getaddrs { + sctp_assoc_t assoc_id; /*input*/ + __u32 addr_num; /*output*/ + __u8 addrs[0]; /*output, variable size*/ +}; + +/* A socket user request obtained via SCTP_GET_ASSOC_STATS that retrieves + * association stats. All stats are counts except sas_maxrto and + * sas_obs_rto_ipaddr. maxrto is the max observed rto + transport since + * the last call. Will return 0 when RTO was not update since last call + */ +struct sctp_assoc_stats { + sctp_assoc_t sas_assoc_id; /* Input */ + /* Transport of observed max RTO */ + struct sockaddr_storage sas_obs_rto_ipaddr; + __u64 sas_maxrto; /* Maximum Observed RTO for period */ + __u64 sas_isacks; /* SACKs received */ + __u64 sas_osacks; /* SACKs sent */ + __u64 sas_opackets; /* Packets sent */ + __u64 sas_ipackets; /* Packets received */ + __u64 sas_rtxchunks; /* Retransmitted Chunks */ + __u64 sas_outofseqtsns;/* TSN received > next expected */ + __u64 sas_idupchunks; /* Dups received (ordered+unordered) */ + __u64 sas_gapcnt; /* Gap Acknowledgements Received */ + __u64 sas_ouodchunks; /* Unordered data chunks sent */ + __u64 sas_iuodchunks; /* Unordered data chunks received */ + __u64 sas_oodchunks; /* Ordered data chunks sent */ + __u64 sas_iodchunks; /* Ordered data chunks received */ + __u64 sas_octrlchunks; /* Control chunks sent */ + __u64 sas_ictrlchunks; /* Control chunks received */ +}; + +/* + * 8.1 sctp_bindx() + * + * The flags parameter is formed from the bitwise OR of zero or more of the + * following currently defined flags: + */ +#define SCTP_BINDX_ADD_ADDR 0x01 +#define SCTP_BINDX_REM_ADDR 0x02 + +/* This is the structure that is passed as an argument(optval) to + * getsockopt(SCTP_SOCKOPT_PEELOFF). + */ +typedef struct { + sctp_assoc_t associd; + int sd; +} sctp_peeloff_arg_t; + +/* + * Peer Address Thresholds socket option + */ +struct sctp_paddrthlds { + sctp_assoc_t spt_assoc_id; + struct sockaddr_storage spt_address; + __u16 spt_pathmaxrxt; + __u16 spt_pathpfthld; +}; + +/* + * Socket Option for Getting the Association/Stream-Specific PR-SCTP Status + */ +struct sctp_prstatus { + sctp_assoc_t sprstat_assoc_id; + __u16 sprstat_sid; + __u16 sprstat_policy; + __u64 sprstat_abandoned_unsent; + __u64 sprstat_abandoned_sent; +}; + +struct sctp_default_prinfo { + sctp_assoc_t pr_assoc_id; + __u32 pr_value; + __u16 pr_policy; +}; + +struct sctp_info { + __u32 sctpi_tag; + __u32 sctpi_state; + __u32 sctpi_rwnd; + __u16 sctpi_unackdata; + __u16 sctpi_penddata; + __u16 sctpi_instrms; + __u16 sctpi_outstrms; + __u32 sctpi_fragmentation_point; + __u32 sctpi_inqueue; + __u32 sctpi_outqueue; + __u32 sctpi_overall_error; + __u32 sctpi_max_burst; + __u32 sctpi_maxseg; + __u32 sctpi_peer_rwnd; + __u32 sctpi_peer_tag; + __u8 sctpi_peer_capable; + __u8 sctpi_peer_sack; + __u16 __reserved1; + + /* assoc status info */ + __u64 sctpi_isacks; + __u64 sctpi_osacks; + __u64 sctpi_opackets; + __u64 sctpi_ipackets; + __u64 sctpi_rtxchunks; + __u64 sctpi_outofseqtsns; + __u64 sctpi_idupchunks; + __u64 sctpi_gapcnt; + __u64 sctpi_ouodchunks; + __u64 sctpi_iuodchunks; + __u64 sctpi_oodchunks; + __u64 sctpi_iodchunks; + __u64 sctpi_octrlchunks; + __u64 sctpi_ictrlchunks; + + /* primary transport info */ + struct sockaddr_storage sctpi_p_address; + __s32 sctpi_p_state; + __u32 sctpi_p_cwnd; + __u32 sctpi_p_srtt; + __u32 sctpi_p_rto; + __u32 sctpi_p_hbinterval; + __u32 sctpi_p_pathmaxrxt; + __u32 sctpi_p_sackdelay; + __u32 sctpi_p_sackfreq; + __u32 sctpi_p_ssthresh; + __u32 sctpi_p_partial_bytes_acked; + __u32 sctpi_p_flight_size; + __u16 sctpi_p_error; + __u16 __reserved2; + + /* sctp sock info */ + __u32 sctpi_s_autoclose; + __u32 sctpi_s_adaptation_ind; + __u32 sctpi_s_pd_point; + __u8 sctpi_s_nodelay; + __u8 sctpi_s_disable_fragments; + __u8 sctpi_s_v4mapped; + __u8 sctpi_s_frag_interleave; + __u32 sctpi_s_type; + __u32 __reserved3; +}; + +#endif /* _SCTP_H */ From f89d46ad63f6f606f777da964205bc53b2197cfa Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 9 Nov 2016 12:12:24 +0100 Subject: [PATCH 475/513] ss: Add support for SCTP protocol This makes use of the sctp_diag interface recently added to the kernel. Joint work with Xin Long who provided the PoC implementation which I merely polished up a bit. Signed-off-by: Phil Sutter --- man/man8/ss.8 | 3 + misc/ss.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 207 insertions(+), 8 deletions(-) diff --git a/man/man8/ss.8 b/man/man8/ss.8 index 8911976fa..4ef11523b 100644 --- a/man/man8/ss.8 +++ b/man/man8/ss.8 @@ -122,6 +122,9 @@ Display RAW sockets. .B \-x, \-\-unix Display Unix domain sockets (alias for -f unix). .TP +.B \-S, \-\-sctp +Display SCTP sockets. +.TP .B \-f FAMILY, \-\-family=FAMILY Display sockets of type FAMILY. Currently the following families are supported: unix, inet, inet6, link, netlink. diff --git a/misc/ss.c b/misc/ss.c index 0e28998f5..a9654ee46 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -43,6 +43,7 @@ #include #include #include +#include #define MAGIC_SEQ 123456 @@ -102,6 +103,7 @@ int show_header = 1; /* If show_users & show_proc_ctx only do user_ent_hash_build() once */ int user_ent_hash_build_init; int follow_events; +int sctp_ino; int netid_width; int state_width; @@ -111,6 +113,7 @@ int serv_width; int screen_width; static const char *TCP_PROTO = "tcp"; +static const char *SCTP_PROTO = "sctp"; static const char *UDP_PROTO = "udp"; static const char *RAW_PROTO = "raw"; static const char *dg_proto; @@ -126,13 +129,14 @@ enum { PACKET_DG_DB, PACKET_R_DB, NETLINK_DB, + SCTP_DB, MAX_DB }; #define PACKET_DBM ((1<ino) + return false; + return true; +} + static void sock_state_print(struct sockstat *s, const char *sock_name) { if (netid_width) - printf("%-*s ", netid_width, sock_name); - if (state_width) - printf("%-*s ", state_width, sstate_name[s->state]); + printf("%-*s ", netid_width, + is_sctp_assoc(s, sock_name) ? "" : sock_name); + if (state_width) { + if (is_sctp_assoc(s, sock_name)) + printf("`- %-*s ", state_width - 3, + sctp_sstate_name[s->state]); + else + printf("%-*s ", state_width, sstate_name[s->state]); + } printf("%-6d %-6d ", s->rq, s->wq); } @@ -908,6 +957,8 @@ static void init_service_resolver(void) c->proto = TCP_PROTO; else if (strcmp(proto, UDP_PROTO) == 0) c->proto = UDP_PROTO; + else if (strcmp(proto, SCTP_PROTO) == 0) + c->proto = SCTP_PROTO; else c->proto = NULL; c->next = rlist; @@ -1679,6 +1730,8 @@ static char *proto_name(int protocol) return "udp"; case IPPROTO_TCP: return "tcp"; + case IPPROTO_SCTP: + return "sctp"; case IPPROTO_DCCP: return "dccp"; } @@ -1771,6 +1824,56 @@ static char *sprint_bw(char *buf, double bw) return buf; } +static void sctp_stats_print(struct sctp_info *s) +{ + if (s->sctpi_tag) + printf(" tag:%x", s->sctpi_tag); + if (s->sctpi_state) + printf(" state:%s", sctp_sstate_name[s->sctpi_state]); + if (s->sctpi_rwnd) + printf(" rwnd:%d", s->sctpi_rwnd); + if (s->sctpi_unackdata) + printf(" unackdata:%d", s->sctpi_unackdata); + if (s->sctpi_penddata) + printf(" penddata:%d", s->sctpi_penddata); + if (s->sctpi_instrms) + printf(" instrms:%d", s->sctpi_instrms); + if (s->sctpi_outstrms) + printf(" outstrms:%d", s->sctpi_outstrms); + if (s->sctpi_inqueue) + printf(" inqueue:%d", s->sctpi_inqueue); + if (s->sctpi_outqueue) + printf(" outqueue:%d", s->sctpi_outqueue); + if (s->sctpi_overall_error) + printf(" overerr:%d", s->sctpi_overall_error); + if (s->sctpi_max_burst) + printf(" maxburst:%d", s->sctpi_max_burst); + if (s->sctpi_maxseg) + printf(" maxseg:%d", s->sctpi_maxseg); + if (s->sctpi_peer_rwnd) + printf(" prwnd:%d", s->sctpi_peer_rwnd); + if (s->sctpi_peer_tag) + printf(" ptag:%x", s->sctpi_peer_tag); + if (s->sctpi_peer_capable) + printf(" pcapable:%d", s->sctpi_peer_capable); + if (s->sctpi_peer_sack) + printf(" psack:%d", s->sctpi_peer_sack); + if (s->sctpi_s_autoclose) + printf(" autoclose:%d", s->sctpi_s_autoclose); + if (s->sctpi_s_adaptation_ind) + printf(" adapind:%d", s->sctpi_s_adaptation_ind); + if (s->sctpi_s_pd_point) + printf(" pdpoint:%d", s->sctpi_s_pd_point); + if (s->sctpi_s_nodelay) + printf(" nodealy:%d", s->sctpi_s_nodelay); + if (s->sctpi_s_disable_fragments) + printf(" nofrag:%d", s->sctpi_s_disable_fragments); + if (s->sctpi_s_v4mapped) + printf(" v4mapped:%d", s->sctpi_s_v4mapped); + if (s->sctpi_s_frag_interleave) + printf(" fraginl:%d", s->sctpi_s_frag_interleave); +} + static void tcp_stats_print(struct tcpstat *s) { char b1[64]; @@ -1902,6 +2005,13 @@ static void tcp_timer_print(struct tcpstat *s) } } +static void sctp_timer_print(struct tcpstat *s) +{ + if (s->timer) + printf(" timer:(T3_RTX,%s,%d)", + print_ms_timer(s->timeout), s->retrans); +} + static int tcp_show_line(char *line, const struct filter *f, int family) { int rto = 0, ato = 0; @@ -2168,6 +2278,64 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, } } +static const char *format_host_sa(struct sockaddr_storage *sa) +{ + union { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } *saddr = (void *)sa; + + switch (sa->ss_family) { + case AF_INET: + return format_host(AF_INET, 4, &saddr->sin.sin_addr); + case AF_INET6: + return format_host(AF_INET6, 16, &saddr->sin6.sin6_addr); + default: + return ""; + } +} + +static void sctp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, + struct rtattr *tb[]) +{ + struct sockaddr_storage *sa; + int len; + + print_skmeminfo(tb, INET_DIAG_SKMEMINFO); + + if (tb[INET_DIAG_LOCALS]) { + len = RTA_PAYLOAD(tb[INET_DIAG_LOCALS]); + sa = RTA_DATA(tb[INET_DIAG_LOCALS]); + + printf("locals:%s", format_host_sa(sa)); + for (sa++, len -= sizeof(*sa); len > 0; sa++, len -= sizeof(*sa)) + printf(",%s", format_host_sa(sa)); + + } + if (tb[INET_DIAG_PEERS]) { + len = RTA_PAYLOAD(tb[INET_DIAG_PEERS]); + sa = RTA_DATA(tb[INET_DIAG_PEERS]); + + printf(" peers:%s", format_host_sa(sa)); + for (sa++, len -= sizeof(*sa); len > 0; sa++, len -= sizeof(*sa)) + printf(",%s", format_host_sa(sa)); + } + if (tb[INET_DIAG_INFO]) { + struct sctp_info *info; + len = RTA_PAYLOAD(tb[INET_DIAG_INFO]); + + /* workaround for older kernels with less fields */ + if (len < sizeof(*info)) { + info = alloca(sizeof(*info)); + memcpy(info, RTA_DATA(tb[INET_DIAG_INFO]), len); + memset((char *)info + len, 0, sizeof(*info) - len); + } else + info = RTA_DATA(tb[INET_DIAG_INFO]); + + sctp_stats_print(info); + } +} + static void parse_diag_msg(struct nlmsghdr *nlh, struct sockstat *s) { struct rtattr *tb[INET_DIAG_MAX+1]; @@ -2221,7 +2389,10 @@ static int inet_show_sock(struct nlmsghdr *nlh, t.timer = r->idiag_timer; t.timeout = r->idiag_expires; t.retrans = r->idiag_retrans; - tcp_timer_print(&t); + if (protocol == IPPROTO_SCTP) + sctp_timer_print(&t); + else + tcp_timer_print(&t); } if (show_details) { @@ -2242,8 +2413,12 @@ static int inet_show_sock(struct nlmsghdr *nlh, if (show_mem || show_tcpinfo) { printf("\n\t"); - tcp_show_info(nlh, r, tb); + if (protocol == IPPROTO_SCTP) + sctp_show_info(nlh, r, tb); + else + tcp_show_info(nlh, r, tb); } + sctp_ino = s->ino; printf("\n"); return 0; @@ -2627,6 +2802,17 @@ static int tcp_show(struct filter *f, int socktype) } while (0); } +static int sctp_show(struct filter *f) +{ + if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6)) + return 0; + + if (!getenv("PROC_NET_SCTP") && !getenv("PROC_ROOT") + && inet_show_netlink(f, NULL, IPPROTO_SCTP) == 0) + return 0; + + return 0; +} static int dgram_show_line(char *line, const struct filter *f, int family) { @@ -3740,6 +3926,7 @@ static void _usage(FILE *dest) " -6, --ipv6 display only IP version 6 sockets\n" " -0, --packet display PACKET sockets\n" " -t, --tcp display only TCP sockets\n" +" -S, --sctp display only SCTP sockets\n" " -u, --udp display only UDP sockets\n" " -d, --dccp display only DCCP sockets\n" " -w, --raw display only RAW sockets\n" @@ -3822,6 +4009,7 @@ static const struct option long_opts[] = { { "events", 0, 0, 'E' }, { "dccp", 0, 0, 'd' }, { "tcp", 0, 0, 't' }, + { "sctp", 0, 0, 'S' }, { "udp", 0, 0, 'u' }, { "raw", 0, 0, 'w' }, { "unix", 0, 0, 'x' }, @@ -3857,7 +4045,7 @@ int main(int argc, char *argv[]) int ch; int state_filter = 0; - while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:KH", + while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:KHS", long_opts, NULL)) != EOF) { switch (ch) { case 'n': @@ -3896,6 +4084,9 @@ int main(int argc, char *argv[]) case 't': filter_db_set(¤t_filter, TCP_DB); break; + case 'S': + filter_db_set(¤t_filter, SCTP_DB); + break; case 'u': filter_db_set(¤t_filter, UDP_DB); break; @@ -3960,6 +4151,7 @@ int main(int argc, char *argv[]) filter_db_set(¤t_filter, UDP_DB); filter_db_set(¤t_filter, DCCP_DB); filter_db_set(¤t_filter, TCP_DB); + filter_db_set(¤t_filter, SCTP_DB); filter_db_set(¤t_filter, RAW_DB); } else if (strcmp(p, "udp") == 0) { filter_db_set(¤t_filter, UDP_DB); @@ -3967,6 +4159,8 @@ int main(int argc, char *argv[]) filter_db_set(¤t_filter, DCCP_DB); } else if (strcmp(p, "tcp") == 0) { filter_db_set(¤t_filter, TCP_DB); + } else if (strcmp(p, "sctp") == 0) { + filter_db_set(¤t_filter, SCTP_DB); } else if (strcmp(p, "raw") == 0) { filter_db_set(¤t_filter, RAW_DB); } else if (strcmp(p, "unix") == 0) { @@ -4091,7 +4285,7 @@ int main(int argc, char *argv[]) filter_merge_defaults(¤t_filter); if (resolve_services && resolve_hosts && - (current_filter.dbs&(UNIX_DBM|(1< Date: Sun, 13 Nov 2016 09:59:15 +0300 Subject: [PATCH 476/513] ss: break really long lines --- misc/ss.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index a9654ee46..07dcd8c20 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -136,7 +136,8 @@ enum { #define PACKET_DBM ((1< Date: Tue, 8 Nov 2016 22:29:11 +0100 Subject: [PATCH 477/513] ipaddress: Simplify vf_info parsing Commit 7b8179c780a1a ("iproute2: Add new command to ip link to enable/disable VF spoof check") tried to add support for IFLA_VF_SPOOFCHK in a backwards-compatible manner, but aparently overdid it: parse_rtattr_nested() handles missing attributes perfectly fine in that it will leave the relevant field unassigned so calling code can just compare against NULL. There is no need to layback from the previous (IFLA_VF_TX_RATE) attribute to the next to check if IFLA_VF_SPOOFCHK is present or not. To the contrary, it establishes a potentially incorrect assumption of these two attributes directly following each other which may not be the case (although up to now, kernel aligns them this way). This patch cleans up the code to adhere to the common way of checking for attribute existence. It has been tested to return correct results regardless of whether the kernel exports IFLA_VF_SPOOFCHK or not. Signed-off-by: Phil Sutter Reviewed-by: Greg Rose --- ip/ipaddress.c | 44 ++++++++++---------------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 7f05258f4..df0f1b9c9 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -322,10 +322,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) { struct ifla_vf_mac *vf_mac; struct ifla_vf_tx_rate *vf_tx_rate; - struct ifla_vf_spoofchk *vf_spoofchk; - struct ifla_vf_link_state *vf_linkstate; struct rtattr *vf[IFLA_VF_MAX + 1] = {}; - struct rtattr *tmp; SPRINT_BUF(b1); @@ -339,31 +336,6 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) vf_mac = RTA_DATA(vf[IFLA_VF_MAC]); vf_tx_rate = RTA_DATA(vf[IFLA_VF_TX_RATE]); - /* Check if the spoof checking vf info type is supported by - * this kernel. - */ - tmp = (struct rtattr *)((char *)vf[IFLA_VF_TX_RATE] + - vf[IFLA_VF_TX_RATE]->rta_len); - - if (tmp->rta_type != IFLA_VF_SPOOFCHK) - vf_spoofchk = NULL; - else - vf_spoofchk = RTA_DATA(vf[IFLA_VF_SPOOFCHK]); - - if (vf_spoofchk) { - /* Check if the link state vf info type is supported by - * this kernel. - */ - tmp = (struct rtattr *)((char *)vf[IFLA_VF_SPOOFCHK] + - vf[IFLA_VF_SPOOFCHK]->rta_len); - - if (tmp->rta_type != IFLA_VF_LINK_STATE) - vf_linkstate = NULL; - else - vf_linkstate = RTA_DATA(vf[IFLA_VF_LINK_STATE]); - } else - vf_linkstate = NULL; - fprintf(fp, "%s vf %d MAC %s", _SL_, vf_mac->vf, ll_addr_n2a((unsigned char *)&vf_mac->mac, ETH_ALEN, 0, b1, sizeof(b1))); @@ -407,14 +379,18 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) if (vf_rate->min_tx_rate) fprintf(fp, ", min_tx_rate %dMbps", vf_rate->min_tx_rate); } + if (vf[IFLA_VF_SPOOFCHK]) { + struct ifla_vf_spoofchk *vf_spoofchk = + RTA_DATA(vf[IFLA_VF_SPOOFCHK]); - if (vf_spoofchk && vf_spoofchk->setting != -1) { - if (vf_spoofchk->setting) - fprintf(fp, ", spoof checking on"); - else - fprintf(fp, ", spoof checking off"); + if (vf_spoofchk->setting != -1) + fprintf(fp, ", spoof checking %s", + vf_spoofchk->setting ? "on" : "off"); } - if (vf_linkstate) { + if (vf[IFLA_VF_LINK_STATE]) { + struct ifla_vf_link_state *vf_linkstate = + RTA_DATA(vf[IFLA_VF_LINK_STATE]); + if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_AUTO) fprintf(fp, ", link-state auto"); else if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_ENABLE) From 468fa020f17d1e4a91af799d8d031b7b904b39d7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 14 Nov 2016 09:28:09 +0100 Subject: [PATCH 478/513] ip: style cleanup Make code more inline with current kernel style --- ip/ipaddress.c | 56 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index df0f1b9c9..b9cd255f9 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -148,11 +148,11 @@ static void print_operstate(FILE *f, __u8 state) fprintf(f, "state %#x ", state); } else if (brief) { color_fprintf(f, oper_state_color(state), - "%-14s ", oper_states[state]); + "%-14s ", oper_states[state]); } else { fprintf(f, "state "); color_fprintf(f, oper_state_color(state), - "%s ", oper_states[state]); + "%s ", oper_states[state]); } } @@ -385,7 +385,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) if (vf_spoofchk->setting != -1) fprintf(fp, ", spoof checking %s", - vf_spoofchk->setting ? "on" : "off"); + vf_spoofchk->setting ? "on" : "off"); } if (vf[IFLA_VF_LINK_STATE]) { struct ifla_vf_link_state *vf_linkstate = @@ -403,7 +403,7 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) if (vf_trust->setting != -1) fprintf(fp, ", trust %s", - vf_trust->setting ? "on" : "off"); + vf_trust->setting ? "on" : "off"); } if (vf[IFLA_VF_STATS] && show_stats) print_vf_stats64(fp, vf[IFLA_VF_STATS]); @@ -424,7 +424,8 @@ static void print_num(FILE *fp, unsigned int width, uint64_t count) } /* increase value by a factor of 1000/1024 and print - * if result is something a human can read */ + * if result is something a human can read + */ for (;;) { powi *= base; if (count / base < powi) @@ -667,9 +668,9 @@ int print_linkinfo_brief(const struct sockaddr_nl *who, return -1; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); - if (tb[IFLA_IFNAME] == NULL) { + if (tb[IFLA_IFNAME] == NULL) fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index); - } + if (filter.label && (!filter.family || filter.family == AF_PACKET) && fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)) @@ -763,9 +764,9 @@ int print_linkinfo(const struct sockaddr_nl *who, return 0; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); - if (tb[IFLA_IFNAME] == NULL) { + if (tb[IFLA_IFNAME] == NULL) fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index); - } + if (filter.label && (!filter.family || filter.family == AF_PACKET) && fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)) @@ -1094,16 +1095,16 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, if (rta_tb[IFA_LOCAL]) { color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s", - format_host_rta(ifa->ifa_family, - rta_tb[IFA_LOCAL])); + format_host_rta(ifa->ifa_family, + rta_tb[IFA_LOCAL])); if (rta_tb[IFA_ADDRESS] && memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), - RTA_DATA(rta_tb[IFA_LOCAL]), - ifa->ifa_family == AF_INET ? 4 : 16)) { + RTA_DATA(rta_tb[IFA_LOCAL]), + ifa->ifa_family == AF_INET ? 4 : 16)) { fprintf(fp, " peer "); color_fprintf(fp, ifa_family_color(ifa->ifa_family), - "%s", format_host_rta(ifa->ifa_family, - rta_tb[IFA_ADDRESS])); + "%s", format_host_rta(ifa->ifa_family, + rta_tb[IFA_ADDRESS])); } fprintf(fp, "/%d ", ifa->ifa_prefixlen); } @@ -1114,14 +1115,14 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, if (rta_tb[IFA_BROADCAST]) { fprintf(fp, "brd "); color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ", - format_host_rta(ifa->ifa_family, - rta_tb[IFA_BROADCAST])); + format_host_rta(ifa->ifa_family, + rta_tb[IFA_BROADCAST])); } if (rta_tb[IFA_ANYCAST]) { fprintf(fp, "any "); color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ", - format_host_rta(ifa->ifa_family, - rta_tb[IFA_ANYCAST])); + format_host_rta(ifa->ifa_family, + rta_tb[IFA_ANYCAST])); } fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1))); if (ifa_flags & IFA_F_SECONDARY) { @@ -1160,9 +1161,9 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, ifa_flags &= ~IFA_F_MCAUTOJOIN; fprintf(fp, "autojoin "); } - if (!(ifa_flags & IFA_F_PERMANENT)) { + if (!(ifa_flags & IFA_F_PERMANENT)) fprintf(fp, "dynamic "); - } else + else ifa_flags &= ~IFA_F_PERMANENT; if (ifa_flags & IFA_F_DADFAILED) { ifa_flags &= ~IFA_F_DADFAILED; @@ -1648,9 +1649,9 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action) filter.kind = *argv; } } else { - if (strcmp(*argv, "dev") == 0) { + if (strcmp(*argv, "dev") == 0) NEXT_ARG(); - } else if (matches(*argv, "help") == 0) + else if (matches(*argv, "help") == 0) usage(); if (filter_dev) duparg2("dev", *argv); @@ -1955,9 +1956,8 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv) } else if (strcmp(*argv, "autojoin") == 0) { ifa_flags |= IFA_F_MCAUTOJOIN; } else { - if (strcmp(*argv, "local") == 0) { + if (strcmp(*argv, "local") == 0) NEXT_ARG(); - } if (matches(*argv, "help") == 0) usage(); if (local_len) @@ -1988,9 +1988,9 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv) if (peer_len == 0 && local_len) { if (cmd == RTM_DELADDR && lcl.family == AF_INET && !(lcl.flags & PREFIXLEN_SPECIFIED)) { fprintf(stderr, - "Warning: Executing wildcard deletion to stay compatible with old scripts.\n" \ - " Explicitly specify the prefix length (%s/%d) to avoid this warning.\n" \ - " This special behaviour is likely to disappear in further releases,\n" \ + "Warning: Executing wildcard deletion to stay compatible with old scripts.\n" + " Explicitly specify the prefix length (%s/%d) to avoid this warning.\n" + " This special behaviour is likely to disappear in further releases,\n" " fix your scripts!\n", lcl_arg, local_len*8); } else { peer = lcl; From 7bdcc0d942dcdde75a3e57fd9a58c9f7578716e2 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Sun, 6 Nov 2016 21:27:38 -0500 Subject: [PATCH 479/513] tc: updated man page to reflect GET command to retrieve a single filter. Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- man/man8/tc.8 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/man/man8/tc.8 b/man/man8/tc.8 index 7ee1c9c9d..8a47a2b92 100644 --- a/man/man8/tc.8 +++ b/man/man8/tc.8 @@ -28,7 +28,7 @@ class-id ] qdisc .B tc .RI "[ " OPTIONS " ]" -.B filter [ add | change | replace | delete ] dev +.B filter [ add | change | replace | delete | get ] dev DEV .B [ parent qdisc-id @@ -575,6 +575,14 @@ replace Performs a nearly atomic remove/add on an existing node id. If the node does not exist yet it is created. +.TP +get +Displays a single filter given the interface, parent ID, priority, protocol and handle ID. + +.TP +show +Displays all filters attached to the given interface. A valid parent ID must be passed. + .TP link Only available for qdiscs and performs a replace where the node From 4fb4a10e120b16c292c215791decccc47dc14604 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 14 Nov 2016 09:29:54 +0100 Subject: [PATCH 480/513] ipaddress: Print IFLA_VF_QUERY_RSS_EN setting Signed-off-by: Phil Sutter --- ip/ipaddress.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index b9cd255f9..50897e6c8 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -405,6 +405,22 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) fprintf(fp, ", trust %s", vf_trust->setting ? "on" : "off"); } + if (vf[IFLA_VF_RSS_QUERY_EN]) { + struct ifla_vf_rss_query_en *rss_query = + RTA_DATA(vf[IFLA_VF_RSS_QUERY_EN]); + + if (rss_query->setting != -1) + fprintf(fp, ", query_rss %s", + rss_query->setting ? "on" : "off"); + } + if (vf[IFLA_VF_RSS_QUERY_EN]) { + struct ifla_vf_rss_query_en *rss_query = + RTA_DATA(vf[IFLA_VF_RSS_QUERY_EN]); + + if (rss_query->setting != -1) + fprintf(fp, ", query_rss %s", + rss_query->setting ? "on" : "off"); + } if (vf[IFLA_VF_STATS] && show_stats) print_vf_stats64(fp, vf[IFLA_VF_STATS]); } From 4b5451c4cde3f41cb9829ee53405393d8d91a555 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Thu, 10 Nov 2016 11:02:57 -0500 Subject: [PATCH 481/513] tc: improved usage help for fw classifier. Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- tc/f_fw.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tc/f_fw.c b/tc/f_fw.c index 29c985490..790bef960 100644 --- a/tc/f_fw.c +++ b/tc/f_fw.c @@ -25,10 +25,19 @@ static void explain(void) { - fprintf(stderr, "Usage: ... fw [ classid CLASSID ] [ action ACTION_SPEC ]\n"); - fprintf(stderr, " ACTION_SPEC := ... look at individual actions\n"); - fprintf(stderr, " CLASSID := X:Y\n"); - fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n"); + fprintf(stderr, + "Usage: ... fw [ classid CLASSID ] [ indev DEV ] [ action ACTION_SPEC ]\n"); + fprintf(stderr, + " CLASSID := Push matching packets to the class identified by CLASSID with format X:Y\n"); + fprintf(stderr, + " CLASSID is parsed as hexadecimal input.\n"); + fprintf(stderr, + " DEV := specify device for incoming device classification.\n"); + fprintf(stderr, + " ACTION_SPEC := Apply an action on matching packets.\n"); + fprintf(stderr, + " NOTE: handle is represented as HANDLE[/FWMASK].\n"); + fprintf(stderr, " FWMASK is 0xffffffff by default.\n"); } static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **argv, struct nlmsghdr *n) From d42e1444f2c0f48df0f1a188dcbe677d1a134710 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Mon, 14 Nov 2016 17:59:20 -0500 Subject: [PATCH 482/513] tc: print raw qdisc handle. This is v2 patch with fixed code indentation. Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- tc/tc_qdisc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index 93c9a4c1d..51320bd47 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -231,7 +231,14 @@ int print_qdisc(const struct sockaddr_nl *who, if (n->nlmsg_type == RTM_DELQDISC) fprintf(fp, "deleted "); - fprintf(fp, "qdisc %s %x: ", rta_getattr_str(tb[TCA_KIND]), t->tcm_handle>>16); + 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); + if (filter_ifindex == 0) fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex)); if (t->tcm_parent == TC_H_ROOT) From b932e6f3727598380dbff9d6941b379c058f23aa Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 15 Nov 2016 10:29:09 -0800 Subject: [PATCH 483/513] tc: cleanup style of qdisc code Get rid of lingering mismatches with kernel style. --- tc/tc_qdisc.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index 51320bd47..3a3701c20 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -182,7 +182,8 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv) 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; } @@ -198,8 +199,7 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv) static int filter_ifindex; int print_qdisc(const struct sockaddr_nl *who, - struct nlmsghdr *n, - void *arg) + struct nlmsghdr *n, void *arg) { FILE *fp = (FILE *)arg; struct tcmsg *t = NLMSG_DATA(n); @@ -241,18 +241,19 @@ int print_qdisc(const struct sockaddr_nl *who, if (filter_ifindex == 0) fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex)); + if (t->tcm_parent == TC_H_ROOT) fprintf(fp, "root "); else if (t->tcm_parent) { print_tc_classid(abuf, sizeof(abuf), t->tcm_parent); fprintf(fp, "parent %s ", abuf); } - if (t->tcm_info != 1) { + + if (t->tcm_info != 1) fprintf(fp, "refcnt %d ", t->tcm_info); - } - /* pfifo_fast is generic enough to warrant the hardcoding --JHS */ - if (0 == strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND]))) + /* pfifo_fast is generic enough to warrant the hardcoding --JHS */ + if (strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND])) == 0) q = get_qdisc_kind("prio"); else q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND])); @@ -264,10 +265,12 @@ int print_qdisc(const struct sockaddr_nl *who, fprintf(fp, "[cannot parse qdisc parameters]"); } fprintf(fp, "\n"); + if (show_details && tb[TCA_STAB]) { print_size_table(fp, " ", tb[TCA_STAB]); fprintf(fp, "\n"); } + if (show_stats) { struct rtattr *xstats = NULL; @@ -296,11 +299,11 @@ static int tc_qdisc_list(int argc, char **argv) strncpy(d, *argv, sizeof(d)-1); } else if (strcmp(*argv, "ingress") == 0 || strcmp(*argv, "clsact") == 0) { - if (t.tcm_parent) { - fprintf(stderr, "Duplicate parent ID\n"); - usage(); - } - t.tcm_parent = TC_H_INGRESS; + if (t.tcm_parent) { + fprintf(stderr, "Duplicate parent ID\n"); + usage(); + } + t.tcm_parent = TC_H_INGRESS; } else if (matches(*argv, "help") == 0) { usage(); } else { @@ -314,7 +317,8 @@ static int tc_qdisc_list(int argc, char **argv) ll_init_map(&rth); if (d[0]) { - if ((t.tcm_ifindex = ll_name_to_index(d)) == 0) { + t.tcm_ifindex = ll_name_to_index(d); + if (t.tcm_ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return 1; } From 6e2e71e16ec53b5fa1d229588fe03ffe6e93902e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 29 Nov 2016 11:36:47 -0800 Subject: [PATCH 484/513] update headers based on 4.9-rc7 --- include/linux/rtnetlink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 2d2e3e6c5..45aedafc5 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -350,7 +350,7 @@ struct rtnexthop { #define RTNH_F_OFFLOAD 8 /* offloaded route */ #define RTNH_F_LINKDOWN 16 /* carrier-down on nexthop */ -#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN) +#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD) /* Macros to handle hexthops */ From aa1b44ca773d10067f64594032cd2bf810892e03 Mon Sep 17 00:00:00 2001 From: "michael-dev@fami-braun.de" Date: Tue, 22 Nov 2016 11:59:13 +0100 Subject: [PATCH 485/513] iproute2: macvlan: add "source" mode Adjusting iproute2 utility to support new macvlan link type mode called "source". Example of commands that can be applied: ip link add link eth0 name macvlan0 type macvlan mode source ip link set link dev macvlan0 type macvlan macaddr add 00:11:11:11:11:11 ip link set link dev macvlan0 type macvlan macaddr del 00:11:11:11:11:11 ip link set link dev macvlan0 type macvlan macaddr flush ip -details link show dev macvlan0 Based on previous work of Stefan Gula Signed-off-by: Michael Braun Cc: steweg@gmail.com v5: - rebase and fix checkpatch v4: - add MACADDR_SET support - skip FLAG_UNICAST / FLAG_UNICAST_ALL as this is not upstream - fix man page --- ip/iplink_macvlan.c | 124 ++++++++++++++++++++++++++++++++++++++++-- man/man8/ip-link.8.in | 42 +++++++++++++- 2 files changed, 158 insertions(+), 8 deletions(-) diff --git a/ip/iplink_macvlan.c b/ip/iplink_macvlan.c index 83ff961b1..b9a146f27 100644 --- a/ip/iplink_macvlan.c +++ b/ip/iplink_macvlan.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "rt_names.h" #include "utils.h" @@ -29,7 +30,11 @@ static void print_explain(struct link_util *lu, FILE *f) { fprintf(f, - "Usage: ... %s mode { private | vepa | bridge | passthru [nopromisc] }\n", + "Usage: ... %s mode MODE [flag MODE_FLAG] MODE_OPTS\n" + "MODE: private | vepa | bridge | passthru | source\n" + "MODE_FLAG: null | nopromisc\n" + "MODE_OPTS: for mode \"source\":\n" + "\tmacaddr { { add | del } | set [ [ ... ] ] | flush }\n", lu->id ); } @@ -43,7 +48,15 @@ static void explain(struct link_util *lu) static int mode_arg(const char *arg) { fprintf(stderr, - "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\" or \"passthru\", not \"%s\"\n", + "Error: argument of \"mode\" must be \"private\", \"vepa\", \"bridge\", \"passthru\" or \"source\", not \"%s\"\n", + arg); + return -1; +} + +static int flag_arg(const char *arg) +{ + fprintf(stderr, + "Error: argument of \"flag\" must be \"nopromisc\" or \"null\", not \"%s\"\n", arg); return -1; } @@ -53,6 +66,10 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, { __u32 mode = 0; __u16 flags = 0; + __u32 mac_mode = 0; + int has_flags = 0; + char mac[ETH_ALEN]; + struct rtattr *nmac; while (argc > 0) { if (matches(*argv, "mode") == 0) { @@ -66,10 +83,72 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, mode = MACVLAN_MODE_BRIDGE; else if (strcmp(*argv, "passthru") == 0) mode = MACVLAN_MODE_PASSTHRU; + else if (strcmp(*argv, "source") == 0) + mode = MACVLAN_MODE_SOURCE; else return mode_arg(*argv); + } else if (matches(*argv, "flag") == 0) { + NEXT_ARG(); + + if (strcmp(*argv, "nopromisc") == 0) + flags |= MACVLAN_FLAG_NOPROMISC; + else if (strcmp(*argv, "null") == 0) + flags |= 0; + else + return flag_arg(*argv); + + has_flags = 1; + + } else if (matches(*argv, "macaddr") == 0) { + NEXT_ARG(); + + if (strcmp(*argv, "add") == 0) { + mac_mode = MACVLAN_MACADDR_ADD; + } else if (strcmp(*argv, "del") == 0) { + mac_mode = MACVLAN_MACADDR_DEL; + } else if (strcmp(*argv, "set") == 0) { + mac_mode = MACVLAN_MACADDR_SET; + } else if (strcmp(*argv, "flush") == 0) { + mac_mode = MACVLAN_MACADDR_FLUSH; + } else { + explain(lu); + return -1; + } + + addattr32(n, 1024, IFLA_MACVLAN_MACADDR_MODE, mac_mode); + + if (mac_mode == MACVLAN_MACADDR_ADD || + mac_mode == MACVLAN_MACADDR_DEL) { + NEXT_ARG(); + + if (ll_addr_a2n(mac, sizeof(mac), + *argv) != ETH_ALEN) + return -1; + + addattr_l(n, 1024, IFLA_MACVLAN_MACADDR, &mac, + ETH_ALEN); + } + + if (mac_mode == MACVLAN_MACADDR_SET) { + nmac = addattr_nest(n, 1024, + IFLA_MACVLAN_MACADDR_DATA); + while (NEXT_ARG_OK()) { + NEXT_ARG_FWD(); + + if (ll_addr_a2n(mac, sizeof(mac), + *argv) != ETH_ALEN) { + PREV_ARG(); + break; + } + + addattr_l(n, 1024, IFLA_MACVLAN_MACADDR, + &mac, ETH_ALEN); + } + addattr_nest_end(n, nmac); + } } else if (matches(*argv, "nopromisc") == 0) { flags |= MACVLAN_FLAG_NOPROMISC; + has_flags = 1; } else if (matches(*argv, "help") == 0) { explain(lu); return -1; @@ -84,7 +163,7 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, if (mode) addattr32(n, 1024, IFLA_MACVLAN_MODE, mode); - if (flags) { + if (has_flags) { if (flags & MACVLAN_FLAG_NOPROMISC && mode != MACVLAN_MODE_PASSTHRU) { pfx_err(lu, "nopromisc flag only valid in passthru mode"); @@ -100,6 +179,10 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[] { __u32 mode; __u16 flags; + __u32 count; + unsigned char *addr; + int len; + struct rtattr *rta; if (!tb) return; @@ -109,20 +192,49 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[] return; mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]); - fprintf(f, " mode %s ", + fprintf(f, "mode %s ", mode == MACVLAN_MODE_PRIVATE ? "private" : mode == MACVLAN_MODE_VEPA ? "vepa" : mode == MACVLAN_MODE_BRIDGE ? "bridge" : mode == MACVLAN_MODE_PASSTHRU ? "passthru" + : mode == MACVLAN_MODE_SOURCE ? "source" : "unknown"); if (!tb[IFLA_MACVLAN_FLAGS] || RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16)) - return; + flags = 0; + else + flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]); - flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]); if (flags & MACVLAN_FLAG_NOPROMISC) fprintf(f, "nopromisc "); + + /* in source mode, there are more options to print */ + + if (mode != MACVLAN_MODE_SOURCE) + return; + + if (!tb[IFLA_MACVLAN_MACADDR_COUNT] || + RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_COUNT]) < sizeof(__u32)) + return; + + count = rta_getattr_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]); + fprintf(f, "remotes (%d) ", count); + + if (!tb[IFLA_MACVLAN_MACADDR_DATA]) + return; + + rta = RTA_DATA(tb[IFLA_MACVLAN_MACADDR_DATA]); + len = RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_DATA]); + + for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { + if (rta->rta_type != IFLA_MACVLAN_MACADDR || + RTA_PAYLOAD(rta) < 6) + continue; + addr = RTA_DATA(rta); + fprintf(f, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ", addr[0], + addr[1], addr[2], addr[3], addr[4], addr[5]); + } } static void macvlan_print_help(struct link_util *lu, int argc, char **argv, diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index ee1159da6..18e941713 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -135,7 +135,12 @@ ip-link \- network device configuration .IR NAME " ]" .br .RB "[ " addrgenmode " { " eui64 " | " none " | " stable_secret " | " random " } ]" - +.br +.RB "[ " macaddr " { " flush " | { " add " | " del " } " +.IR MACADDR " | set [ " +.IR MACADDR " [ " +.IR MACADDR " [ ... ] ] ] } ]" +.br .ti -8 .B ip link show @@ -882,7 +887,7 @@ the following additional arguments are supported: .BI "ip link add link " DEVICE " name " NAME .BR type " { " macvlan " | " macvtap " } " .BR mode " { " private " | " vepa " | " bridge " | " passthru -.RB " [ " nopromisc " ] } " +.RB " [ " nopromisc " ] | " source " } " .in +8 .sp @@ -919,6 +924,13 @@ the interface or create vlan interfaces on top of it. By default, this mode forces the underlying interface into promiscuous mode. Passing the .BR nopromisc " flag prevents this, so the promisc flag may be controlled " using standard tools. + +.B mode source +- allows one to set a list of allowed mac address, which is used to match +against source mac address from received frames on underlying interface. This +allows creating mac based VLAN associations, instead of standard port or tag +based. The feature is useful to deploy 802.1x mac based behavior, +where drivers of underlying interfaces doesn't allows that. .in -8 .TP @@ -1468,6 +1480,32 @@ the following additional arguments are supported: .in -8 +.TP +MACVLAN and MACVTAP Support +Modify list of allowed macaddr for link in source mode. + +.B "ip link set type { macvlan | macvap } " +[ +.BI macaddr " " "" COMMAND " " MACADDR " ..." +] + +Commands: +.in +8 +.B add +- add MACADDR to allowed list +.sp +.B set +- replace allowed list +.sp +.B del +- remove MACADDR from allowed list +.sp +.B flush +- flush whole allowed list +.sp +.in -8 + + .SS ip link show - display device attributes .TP From 8be295581630b01a2b8ec718ccde2d158fcff4c8 Mon Sep 17 00:00:00 2001 From: david decotigny Date: Fri, 11 Nov 2016 10:55:36 -0800 Subject: [PATCH 486/513] iproute2: avoid exit in case of error. Be consistent with how non-0 print_route() return values are handled elesewhere: return -1. --- ip/iproute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/iproute.c b/ip/iproute.c index 98bfad6cb..dae793b75 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -1743,7 +1743,7 @@ static int iproute_get(int argc, char **argv) if (print_route(NULL, &req.n, (void *)stdout) < 0) { fprintf(stderr, "An error :-)\n"); - exit(1); + return -1; } if (req.n.nlmsg_type != RTM_NEWROUTE) { From ba7b97776e3a2e019de8d840f9714db89da60a94 Mon Sep 17 00:00:00 2001 From: david decotigny Date: Fri, 11 Nov 2016 10:55:37 -0800 Subject: [PATCH 487/513] iproute2: a non-expected rtnl message is an error --- ip/iproute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/iproute.c b/ip/iproute.c index dae793b75..10d0afe7b 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -320,7 +320,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { fprintf(stderr, "Not a route: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); - return 0; + return -1; } if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE) return 0; From 2d98dd482149aa1a2bf509122af089249644a89f Mon Sep 17 00:00:00 2001 From: Zhang Shengju Date: Fri, 18 Nov 2016 09:12:53 +0800 Subject: [PATCH 488/513] iproute2: fix the link group name getting error In the situation where more than one entry live in the same hash bucket, loop to get the correct one. Before: $ cat /etc/iproute2/group 0 default 256 test $ sudo ip link set group test dummy1 $ ip link show type dummy 11: dummy0: mtu 1500 qdisc noop state DOWN mode DEFAULT group 0 qlen 1000 link/ether 4e:3b:d3:6c:f0:e6 brd ff:ff:ff:ff:ff:ff 12: dummy1: mtu 1500 qdisc noop state DOWN mode DEFAULT group test qlen 1000 link/ether d6:9c:a4:1f:e7:e5 brd ff:ff:ff:ff:ff:ff After: $ ip link show type dummy 11: dummy0: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 4e:3b:d3:6c:f0:e6 brd ff:ff:ff:ff:ff:ff 12: dummy1: mtu 1500 qdisc noop state DOWN mode DEFAULT group test qlen 1000 link/ether d6:9c:a4:1f:e7:e5 brd ff:ff:ff:ff:ff:ff Signed-off-by: Zhang Shengju --- lib/rt_names.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/rt_names.c b/lib/rt_names.c index b665d3e92..c66cb1e43 100644 --- a/lib/rt_names.c +++ b/lib/rt_names.c @@ -559,8 +559,12 @@ const char *rtnl_group_n2a(int id, char *buf, int len) for (i = 0; i < 256; i++) { entry = rtnl_group_hash[i]; - if (entry && entry->id == id) - return entry->name; + + while (entry) { + if (entry->id == id) + return entry->name; + entry = entry->next; + } } snprintf(buf, len, "%d", id); From 1b109a30bf711833da0f674e46da8aaafa6a9e4f Mon Sep 17 00:00:00 2001 From: Zhang Shengju Date: Sat, 19 Nov 2016 23:50:13 +0800 Subject: [PATCH 489/513] libnetlink: reduce size of message sent to kernel Fixes commit 246f57c4086d99fa ("ip link: Add support for kernel side filtering"). This patch reduce the size of message sent to kernel space. Before this patch, for command: 'ip link show', we will sent 1056 bytes. With this patch, we only need to send 40 bytes. Signed-off-by: Zhang Shengju --- lib/libnetlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 22799355e..7f2a0d447 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -149,7 +149,7 @@ int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int family, int type, if (err) return err; - return send(rth->fd, (void*)&req, sizeof(req), 0); + return send(rth->fd, &req, req.nlh.nlmsg_len, 0); } int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type, From 2c500a4dc25047e3737ea6e9cc0afc5f12089626 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 29 Nov 2016 13:15:08 -0800 Subject: [PATCH 490/513] libnetlink: style cleanups Follow kernel style related cleanups: * break long lines * remove unnecessary void * cast --- lib/libnetlink.c | 119 +++++++++++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 44 deletions(-) diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 7f2a0d447..21a763632 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -43,7 +43,7 @@ void rtnl_close(struct rtnl_handle *rth) } } -int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, +int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions, int protocol) { socklen_t addr_len; @@ -58,12 +58,14 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, return -1; } - if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { + if (setsockopt(rth->fd, SOL_SOCKET, SO_SNDBUF, + &sndbuf, sizeof(sndbuf)) < 0) { perror("SO_SNDBUF"); return -1; } - if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) { + if (setsockopt(rth->fd, SOL_SOCKET, SO_RCVBUF, + &rcvbuf, sizeof(rcvbuf)) < 0) { perror("SO_RCVBUF"); return -1; } @@ -72,12 +74,14 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, rth->local.nl_family = AF_NETLINK; rth->local.nl_groups = subscriptions; - if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { + if (bind(rth->fd, (struct sockaddr *)&rth->local, + sizeof(rth->local)) < 0) { perror("Cannot bind netlink socket"); return -1; } addr_len = sizeof(rth->local); - if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { + if (getsockname(rth->fd, (struct sockaddr *)&rth->local, + &addr_len) < 0) { perror("Cannot getsockname"); return -1; } @@ -86,14 +90,15 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, return -1; } if (rth->local.nl_family != AF_NETLINK) { - fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family); + fprintf(stderr, "Wrong address family %d\n", + rth->local.nl_family); return -1; } rth->seq = time(NULL); return 0; } -int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) +int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions) { return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE); } @@ -123,7 +128,7 @@ int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int family, int type, .ext_filter_mask = filt_mask, }; - return send(rth->fd, (void*)&req, sizeof(req), 0); + return send(rth->fd, &req, sizeof(req), 0); } int rtnl_wilddump_req_filter_fn(struct rtnl_handle *rth, int family, int type, @@ -169,7 +174,7 @@ int rtnl_wilddump_stats_req_filter(struct rtnl_handle *rth, int fam, int type, req.ifsm.family = fam; req.ifsm.filter_mask = filt_mask; - return send(rth->fd, (void *)&req, sizeof(req), 0); + return send(rth->fd, &req, sizeof(req), 0); } int rtnl_send(struct rtnl_handle *rth, const void *buf, int len) @@ -198,7 +203,8 @@ int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len) for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status); h = NLMSG_NEXT(h, status)) { if (h->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h); + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) fprintf(stderr, "ERROR truncated\n"); else @@ -237,7 +243,7 @@ int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n) { struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; struct iovec iov = { - .iov_base = (void*) n, + .iov_base = n, .iov_len = n->nlmsg_len }; struct msghdr msg = { @@ -295,7 +301,8 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth, fwrite(buf, 1, NLMSG_ALIGN(status), rth->dump_fp); for (a = arg; a->filter; a++) { - struct nlmsghdr *h = (struct nlmsghdr*)buf; + struct nlmsghdr *h = (struct nlmsghdr *)buf; + msglen = status; while (NLMSG_OK(h, msglen)) { @@ -316,7 +323,8 @@ int rtnl_dump_filter_l(struct rtnl_handle *rth, break; /* process next filter */ } if (h->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h); + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { fprintf(stderr, "ERROR truncated\n"); @@ -377,11 +385,11 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, struct nlmsghdr *answer, size_t maxlen) { int status; - unsigned seq; + unsigned int seq; struct nlmsghdr *h; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; struct iovec iov = { - .iov_base = (void*) n, + .iov_base = n, .iov_len = n->nlmsg_len }; struct msghdr msg = { @@ -420,19 +428,23 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, return -1; } if (msg.msg_namelen != sizeof(nladdr)) { - fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); + fprintf(stderr, + "sender address length == %d\n", + msg.msg_namelen); exit(1); } - for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { + for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) { int len = h->nlmsg_len; int l = len - sizeof(*h); - if (l < 0 || len>status) { + if (l < 0 || len > status) { if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Truncated message\n"); return -1; } - fprintf(stderr, "!!!malformed message: len=%d\n", len); + fprintf(stderr, + "!!!malformed message: len=%d\n", + len); exit(1); } @@ -441,12 +453,13 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, h->nlmsg_seq != seq) { /* Don't forget to skip that message. */ status -= NLMSG_ALIGN(len); - h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); continue; } if (h->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h); + if (l < sizeof(struct nlmsgerr)) { fprintf(stderr, "ERROR truncated\n"); } else if (!err->error) { @@ -473,7 +486,7 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, fprintf(stderr, "Unexpected reply!!!\n"); status -= NLMSG_ALIGN(len); - h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); } if (msg.msg_flags & MSG_TRUNC) { @@ -545,7 +558,9 @@ int rtnl_listen(struct rtnl_handle *rtnl, return -1; } if (msg.msg_namelen != sizeof(nladdr)) { - fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen); + fprintf(stderr, + "Sender address length == %d\n", + msg.msg_namelen); exit(1); } @@ -563,17 +578,19 @@ int rtnl_listen(struct rtnl_handle *rtnl, } } - for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { + for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) { int err; int len = h->nlmsg_len; int l = len - sizeof(*h); - if (l<0 || len>status) { + if (l < 0 || len > status) { if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Truncated message\n"); return -1; } - fprintf(stderr, "!!!malformed message: len=%d\n", len); + fprintf(stderr, + "!!!malformed message: len=%d\n", + len); exit(1); } @@ -582,7 +599,7 @@ int rtnl_listen(struct rtnl_handle *rtnl, return err; status -= NLMSG_ALIGN(len); - h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); } if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Message truncated\n"); @@ -600,8 +617,8 @@ int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler, { int status; struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; - char buf[16384]; - struct nlmsghdr *h = (void*)buf; + char buf[16384]; + struct nlmsghdr *h = (struct nlmsghdr *)buf; while (1) { int err, len; @@ -621,7 +638,7 @@ int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler, len = h->nlmsg_len; l = len - sizeof(*h); - if (l<0 || len>sizeof(buf)) { + if (l < 0 || len > sizeof(buf)) { fprintf(stderr, "!!!malformed message: len=%d @%lu\n", len, ftell(rtnl)); return -1; @@ -681,7 +698,9 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, struct rtattr *rta; if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { - fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen); + fprintf(stderr, + "addattr_l ERROR: message exceeded bound of %d\n", + maxlen); return -1; } rta = NLMSG_TAIL(n); @@ -695,7 +714,9 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len) { if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) { - fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen); + fprintf(stderr, + "addraw_l ERROR: message exceeded bound of %d\n", + maxlen); return -1; } @@ -744,10 +765,12 @@ int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) struct rtattr *subrta; if (RTA_ALIGN(rta->rta_len) + len > maxlen) { - fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen); + fprintf(stderr, + "rta_addattr32: Error! max allowed bound %d exceeded\n", + maxlen); return -1; } - subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); + subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len)); subrta->rta_type = type; subrta->rta_len = len; memcpy(RTA_DATA(subrta), &data, 4); @@ -762,10 +785,12 @@ int rta_addattr_l(struct rtattr *rta, int maxlen, int type, int len = RTA_LENGTH(alen); if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) { - fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen); + fprintf(stderr, + "rta_addattr_l: Error! max allowed bound %d exceeded\n", + maxlen); return -1; } - subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); + subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len)); subrta->rta_type = type; subrta->rta_len = len; memcpy(RTA_DATA(subrta), data, alen); @@ -819,14 +844,16 @@ int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta, type = rta->rta_type & ~flags; if ((type <= max) && (!tb[type])) tb[type] = rta; - rta = RTA_NEXT(rta,len); + rta = RTA_NEXT(rta, len); } if (len) - fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); + fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", + len, rta->rta_len); return 0; } -int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len) +int parse_rtattr_byindex(struct rtattr *tb[], int max, + struct rtattr *rta, int len) { int i = 0; @@ -834,10 +861,11 @@ int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int l while (RTA_OK(rta, len)) { if (rta->rta_type <= max && i < max) tb[i++] = rta; - rta = RTA_NEXT(rta,len); + rta = RTA_NEXT(rta, len); } if (len) - fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); + fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", + len, rta->rta_len); return i; } @@ -848,13 +876,16 @@ struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len) return rta; rta = RTA_NEXT(rta, len); } + if (len) - fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); + fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", + len, rta->rta_len); return NULL; } -int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, - int len) +int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, + struct rtattr *rta, + int len) { if (RTA_PAYLOAD(rta) < len) return -1; From eca7a7421963a7f254282e13e505be9ebeaf9c9a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 15 Nov 2016 22:34:14 -0500 Subject: [PATCH 491/513] ifstat/nstat: fix help output alignment Some lines use tabs while others use spaces. Use spaces everywhere. Signed-off-by: Mike Frysinger --- misc/ifstat.c | 24 ++++++++++++------------ misc/nstat.c | 22 +++++++++++----------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/misc/ifstat.c b/misc/ifstat.c index d55197375..92d67b0c5 100644 --- a/misc/ifstat.c +++ b/misc/ifstat.c @@ -662,18 +662,18 @@ static void usage(void) { fprintf(stderr, "Usage: ifstat [OPTION] [ PATTERN [ PATTERN ] ]\n" -" -h, --help this message\n" -" -a, --ignore ignore history\n" -" -d, --scan=SECS sample every statistics every SECS\n" -" -e, --errors show errors\n" -" -j, --json format output in JSON\n" -" -n, --nooutput do history only\n" -" -p, --pretty pretty print\n" -" -r, --reset reset history\n" -" -s, --noupdate don\'t update history\n" -" -t, --interval=SECS report average over the last SECS\n" -" -V, --version output version information\n" -" -z, --zeros show entries with zero activity\n"); +" -h, --help this message\n" +" -a, --ignore ignore history\n" +" -d, --scan=SECS sample every statistics every SECS\n" +" -e, --errors show errors\n" +" -j, --json format output in JSON\n" +" -n, --nooutput do history only\n" +" -p, --pretty pretty print\n" +" -r, --reset reset history\n" +" -s, --noupdate don't update history\n" +" -t, --interval=SECS report average over the last SECS\n" +" -V, --version output version information\n" +" -z, --zeros show entries with zero activity\n"); exit(-1); } diff --git a/misc/nstat.c b/misc/nstat.c index 1cb6c7eea..1212b1f2c 100644 --- a/misc/nstat.c +++ b/misc/nstat.c @@ -526,17 +526,17 @@ static void usage(void) { fprintf(stderr, "Usage: nstat [OPTION] [ PATTERN [ PATTERN ] ]\n" -" -h, --help this message\n" -" -a, --ignore ignore history\n" -" -d, --scan=SECS sample every statistics every SECS\n" -" -j, --json format output in JSON\n" -" -n, --nooutput do history only\n" -" -p, --pretty pretty print\n" -" -r, --reset reset history\n" -" -s, --noupdate don\'t update history\n" -" -t, --interval=SECS report average over the last SECS\n" -" -V, --version output version information\n" -" -z, --zeros show entries with zero activity\n"); +" -h, --help this message\n" +" -a, --ignore ignore history\n" +" -d, --scan=SECS sample every statistics every SECS\n" +" -j, --json format output in JSON\n" +" -n, --nooutput do history only\n" +" -p, --pretty pretty print\n" +" -r, --reset reset history\n" +" -s, --noupdate don't update history\n" +" -t, --interval=SECS report average over the last SECS\n" +" -V, --version output version information\n" +" -z, --zeros show entries with zero activity\n"); exit(-1); } From 3a4df0391367c2e8f0e037f0e91384c5def0c2af Mon Sep 17 00:00:00 2001 From: Daniel Hopf Date: Tue, 29 Nov 2016 13:22:12 -0800 Subject: [PATCH 492/513] macsec: Nr. of packets and octets for macsec tx stats were swapped Acked-by: Rami Rosen Acked-by: Sabrina Dubroca Signed-off-by: Daniel Hopf --- ip/ipmacsec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ip/ipmacsec.c b/ip/ipmacsec.c index c9252bb24..aa89a00f5 100644 --- a/ip/ipmacsec.c +++ b/ip/ipmacsec.c @@ -634,10 +634,10 @@ static void print_one_stat(const char **names, struct rtattr **attr, int idx, } static const char *txsc_stats_names[NUM_MACSEC_TXSC_STATS_ATTR] = { - [MACSEC_TXSC_STATS_ATTR_OUT_PKTS_PROTECTED] = "OutOctetsProtected", - [MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED] = "OutOctetsEncrypted", - [MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED] = "OutPktsProtected", - [MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED] = "OutPktsEncrypted", + [MACSEC_TXSC_STATS_ATTR_OUT_PKTS_PROTECTED] = "OutPktsProtected", + [MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED] = "OutPktsEncrypted", + [MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED] = "OutOctetsProtected", + [MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED] = "OutOctetsEncrypted", }; static void print_txsc_stats(const char *prefix, struct rtattr *attr) From 98df0c81dac41bcd4ccad67ec6886dab25825be0 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Wed, 16 Nov 2016 17:30:20 -0500 Subject: [PATCH 493/513] tc: distinguish Add/Replace filter operations Signed-off-by: Roman Mashak Signed-off-by: Jamal Hadi Salim --- tc/tc_filter.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tc/tc_filter.c b/tc/tc_filter.c index 932677a05..ff8713b98 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -226,6 +226,16 @@ int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (n->nlmsg_type == RTM_DELTFILTER) fprintf(fp, "deleted "); + if (n->nlmsg_type == RTM_NEWTFILTER && + (n->nlmsg_flags & NLM_F_CREATE) && + !(n->nlmsg_flags & NLM_F_EXCL)) + fprintf(fp, "replaced "); + + if (n->nlmsg_type == RTM_NEWTFILTER && + (n->nlmsg_flags & NLM_F_CREATE) && + (n->nlmsg_flags & NLM_F_EXCL)) + fprintf(fp, "added "); + fprintf(fp, "filter "); if (!filter_ifindex || filter_ifindex != t->tcm_ifindex) fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex)); From 222c4dab8e37f77a9e8834b72ce0b02e5d928f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:18 +0000 Subject: [PATCH 494/513] man: ip-l2tp.8: fix l2spec_type documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Asbjørn Sloth Tønnesen --- man/man8/ip-l2tp.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/ip-l2tp.8 b/man/man8/ip-l2tp.8 index 5b7041f93..4a3bb20a4 100644 --- a/man/man8/ip-l2tp.8 +++ b/man/man8/ip-l2tp.8 @@ -239,7 +239,7 @@ find in received L2TP packets. Default is to use no cookie. set the layer2specific header type of the session. .br Valid values are: -.BR none ", " udp "." +.BR none ", " default "." .TP .BI offset " OFFSET" sets the byte offset from the L2TP header where user data starts in From d0baf5cac8730469050cef4034bd0f82c18965ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:19 +0000 Subject: [PATCH 495/513] man: ip-l2tp.8: remove non-existent tunnel parameter name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name parameter is only valid for sessions, not tunnels. Signed-off-by: Asbjørn Sloth Tønnesen --- man/man8/ip-l2tp.8 | 3 --- 1 file changed, 3 deletions(-) diff --git a/man/man8/ip-l2tp.8 b/man/man8/ip-l2tp.8 index 4a3bb20a4..991d09737 100644 --- a/man/man8/ip-l2tp.8 +++ b/man/man8/ip-l2tp.8 @@ -154,9 +154,6 @@ tunnels and sessions to be established and provides for detecting and acting upon network failures. .SS ip l2tp add tunnel - add a new tunnel .TP -.BI name " NAME " -sets the session network interface name. Default is l2tpethN. -.TP .BI tunnel_id " ID" set the tunnel id, which is a 32-bit integer value. Uniquely identifies the tunnel. The value used must match the peer_tunnel_id From 31f63e7c426f8b7098f87a9391748e8325dff3c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:20 +0000 Subject: [PATCH 496/513] l2tp: fix integers with too few significant bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit udp6_csum_{tx,rx}, tunnel and session are the only ones currently used. recv_seq, send_seq, lns_mode and data_seq are partially implemented in a useless way. Signed-off-by: Asbjørn Sloth Tønnesen --- ip/ipl2tp.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index d3338acec..2e0e9c745 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -56,15 +56,15 @@ struct l2tp_parm { uint16_t pw_type; uint16_t mtu; - int udp6_csum_tx:1; - int udp6_csum_rx:1; - int udp_csum:1; - int recv_seq:1; - int send_seq:1; - int lns_mode:1; - int data_seq:2; - int tunnel:1; - int session:1; + unsigned int udp6_csum_tx:1; + unsigned int udp6_csum_rx:1; + unsigned int udp_csum:1; + unsigned int recv_seq:1; + unsigned int send_seq:1; + unsigned int lns_mode:1; + unsigned int data_seq:2; + unsigned int tunnel:1; + unsigned int session:1; int reorder_timeout; const char *ifname; uint8_t l2spec_type; From 4d51b3331eae9cbd77e22272903f6f0efd0b4847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:21 +0000 Subject: [PATCH 497/513] l2tp: fix L2TP_ATTR_{RECV,SEND}_SEQ handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L2TP_ATTR_RECV_SEQ and L2TP_ATTR_SEND_SEQ are declared as NLA_U8 attributes in the kernel, so let's threat them accordingly. Signed-off-by: Asbjørn Sloth Tønnesen --- ip/ipl2tp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index 2e0e9c745..a7cbd669b 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -160,8 +160,8 @@ static int create_session(struct l2tp_parm *p) addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_LEN, p->l2spec_len); if (p->mtu) addattr16(&req.n, 1024, L2TP_ATTR_MTU, p->mtu); - if (p->recv_seq) addattr(&req.n, 1024, L2TP_ATTR_RECV_SEQ); - if (p->send_seq) addattr(&req.n, 1024, L2TP_ATTR_SEND_SEQ); + if (p->recv_seq) addattr8(&req.n, 1024, L2TP_ATTR_RECV_SEQ, 1); + if (p->send_seq) addattr8(&req.n, 1024, L2TP_ATTR_SEND_SEQ, 1); if (p->lns_mode) addattr(&req.n, 1024, L2TP_ATTR_LNS_MODE); if (p->data_seq) addattr8(&req.n, 1024, L2TP_ATTR_DATA_SEQ, p->data_seq); if (p->reorder_timeout) addattr64(&req.n, 1024, L2TP_ATTR_RECV_TIMEOUT, @@ -304,8 +304,10 @@ static int get_response(struct nlmsghdr *n, void *arg) memcpy(p->peer_cookie, RTA_DATA(attrs[L2TP_ATTR_PEER_COOKIE]), p->peer_cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_PEER_COOKIE])); - p->recv_seq = !!attrs[L2TP_ATTR_RECV_SEQ]; - p->send_seq = !!attrs[L2TP_ATTR_SEND_SEQ]; + if (attrs[L2TP_ATTR_RECV_SEQ]) + p->recv_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_RECV_SEQ]); + if (attrs[L2TP_ATTR_SEND_SEQ]) + p->send_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_SEND_SEQ]); if (attrs[L2TP_ATTR_RECV_TIMEOUT]) p->reorder_timeout = rta_getattr_u64(attrs[L2TP_ATTR_RECV_TIMEOUT]); From c73fad78603e130b80a10a498582ff701ac93515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:22 +0000 Subject: [PATCH 498/513] l2tp: fix L2TP_ATTR_UDP_CSUM handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L2TP_ATTR_UDP_CSUM is read by the kernel as a NLA_FLAG value, but is validated as a NLA_U8, so we will write it as an u8, but the value isn't actually being read by the kernel. It is written by the kernel as a NLA_U8, so we will read as such. Signed-off-by: Asbjørn Sloth Tønnesen --- ip/ipl2tp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index a7cbd669b..03ca0cc45 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -120,7 +120,7 @@ static int create_tunnel(struct l2tp_parm *p) addattr16(&req.n, 1024, L2TP_ATTR_UDP_SPORT, p->local_udp_port); addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port); if (p->udp_csum) - addattr(&req.n, 1024, L2TP_ATTR_UDP_CSUM); + addattr8(&req.n, 1024, L2TP_ATTR_UDP_CSUM, 1); if (!p->udp6_csum_tx) addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_TX); if (!p->udp6_csum_rx) @@ -289,7 +289,9 @@ static int get_response(struct nlmsghdr *n, void *arg) if (attrs[L2TP_ATTR_L2SPEC_LEN]) p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]); - p->udp_csum = !!attrs[L2TP_ATTR_UDP_CSUM]; + if (attrs[L2TP_ATTR_UDP_CSUM]) + p->udp_csum = !!rta_getattr_u8(attrs[L2TP_ATTR_UDP_CSUM]); + /* * Not fetching from L2TP_ATTR_UDP_ZERO_CSUM6_{T,R}X because the * kernel doesn't send it so just leave it as default value. From 35cc6ded4f1520de8db2169abdcb0a6fb034781c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:23 +0000 Subject: [PATCH 499/513] l2tp: read IPv6 UDP checksum attributes from kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case of an older kernel that doesn't set L2TP_ATTR_UDP_ZERO_CSUM6_{RX,TX} the old hard-coded value is being preserved, since the attribute flag will be missing. Signed-off-by: Asbjørn Sloth Tønnesen --- ip/ipl2tp.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index 03ca0cc45..f5d411393 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -292,12 +292,9 @@ static int get_response(struct nlmsghdr *n, void *arg) if (attrs[L2TP_ATTR_UDP_CSUM]) p->udp_csum = !!rta_getattr_u8(attrs[L2TP_ATTR_UDP_CSUM]); - /* - * Not fetching from L2TP_ATTR_UDP_ZERO_CSUM6_{T,R}X because the - * kernel doesn't send it so just leave it as default value. - */ - p->udp6_csum_tx = 1; - p->udp6_csum_rx = 1; + p->udp6_csum_tx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX]; + p->udp6_csum_rx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX]; + if (attrs[L2TP_ATTR_COOKIE]) memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]), p->cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_COOKIE])); From 8a11421a5d8ae95ba03453a56611b9b09e32c0b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:24 +0000 Subject: [PATCH 500/513] l2tp: support sequence numbering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch implement and documents the user interface for sequence numbering. Signed-off-by: Asbjørn Sloth Tønnesen --- ip/ipl2tp.c | 23 +++++++++++++++++++++++ man/man8/ip-l2tp.8 | 15 +++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index f5d411393..ab35023e2 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -246,6 +246,12 @@ static void print_session(struct l2tp_data *data) printf(" reorder timeout: %u\n", p->reorder_timeout); else printf("\n"); + if (p->send_seq || p->recv_seq) { + printf(" sequence numbering:"); + if (p->send_seq) printf(" send"); + if (p->recv_seq) printf(" recv"); + printf("\n"); + } } static int get_response(struct nlmsghdr *n, void *arg) @@ -482,6 +488,7 @@ static void usage(void) fprintf(stderr, " session_id ID peer_session_id ID\n"); fprintf(stderr, " [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n"); fprintf(stderr, " [ offset OFFSET ] [ peer_offset OFFSET ]\n"); + fprintf(stderr, " [ seq { none | send | recv | both } ]\n"); fprintf(stderr, " [ l2spec_type L2SPEC ]\n"); fprintf(stderr, " ip l2tp del tunnel tunnel_id ID\n"); fprintf(stderr, " ip l2tp del session tunnel_id ID session_id ID\n"); @@ -652,6 +659,22 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p) fprintf(stderr, "Unknown layer2specific header type \"%s\"\n", *argv); exit(-1); } + } else if (strcmp(*argv, "seq") == 0) { + NEXT_ARG(); + if (strcasecmp(*argv, "both") == 0) { + p->recv_seq = 1; + p->send_seq = 1; + } else if (strcasecmp(*argv, "recv") == 0) { + p->recv_seq = 1; + } else if (strcasecmp(*argv, "send") == 0) { + p->send_seq = 1; + } else if (strcasecmp(*argv, "none") == 0) { + p->recv_seq = 0; + p->send_seq = 0; + } else { + fprintf(stderr, "Unknown seq value \"%s\"\n", *argv); + exit(-1); + } } else if (strcmp(*argv, "tunnel") == 0) { p->tunnel = 1; } else if (strcmp(*argv, "session") == 0) { diff --git a/man/man8/ip-l2tp.8 b/man/man8/ip-l2tp.8 index 991d09737..d4e7270f2 100644 --- a/man/man8/ip-l2tp.8 +++ b/man/man8/ip-l2tp.8 @@ -51,6 +51,8 @@ ip-l2tp - L2TPv3 static unmanaged tunnel configuration .br .RB "[ " l2spec_type " { " none " | " default " } ]" .br +.RB "[ " seq " { " none " | " send " | " recv " | " both " } ]" +.br .RB "[ " offset .IR OFFSET .RB " ] [ " peer_offset @@ -238,6 +240,19 @@ set the layer2specific header type of the session. Valid values are: .BR none ", " default "." .TP +.BI seq " SEQ" +controls sequence numbering to prevent or detect out of order packets. +.B send +puts a sequence number in the default layer2specific header of each +outgoing packet. +.B recv +reorder packets if they are received out of order. +Default is +.BR none "." +.br +Valid values are: +.BR none ", " send ", " recv ", " both "." +.TP .BI offset " OFFSET" sets the byte offset from the L2TP header where user data starts in transmitted L2TP data packets. This is hardly ever used. If set, the From f7982f5c9574358c443e6175295dc36b29085003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:25 +0000 Subject: [PATCH 501/513] l2tp: show tunnel: expose UDP checksum state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Asbjørn Sloth Tønnesen --- ip/ipl2tp.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index ab35023e2..f2bbc0c3e 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -218,9 +218,24 @@ static void print_tunnel(const struct l2tp_data *data) printf(" Peer tunnel %u\n", p->peer_tunnel_id); - if (p->encap == L2TP_ENCAPTYPE_UDP) + if (p->encap == L2TP_ENCAPTYPE_UDP) { printf(" UDP source / dest ports: %hu/%hu\n", p->local_udp_port, p->peer_udp_port); + + switch (p->local_ip.family) { + case AF_INET: + printf(" UDP checksum: %s\n", + p->udp_csum ? "enabled" : "disabled"); + break; + case AF_INET6: + printf(" UDP checksum: %s%s%s%s\n", + p->udp6_csum_tx && p->udp6_csum_rx ? "enabled" : "", + p->udp6_csum_tx && !p->udp6_csum_rx ? "tx" : "", + !p->udp6_csum_tx && p->udp6_csum_rx ? "rx" : "", + !p->udp6_csum_tx && !p->udp6_csum_rx ? "disabled" : ""); + break; + } + } } static void print_session(struct l2tp_data *data) From 51a9d01aaa760a0e0887a7c3c701e5f180604950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Sloth=20T=C3=B8nnesen?= Date: Wed, 16 Nov 2016 22:45:26 +0000 Subject: [PATCH 502/513] man: ip-l2tp.8: document UDP checksum options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Asbjørn Sloth Tønnesen --- man/man8/ip-l2tp.8 | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/man/man8/ip-l2tp.8 b/man/man8/ip-l2tp.8 index d4e7270f2..8ce630a6e 100644 --- a/man/man8/ip-l2tp.8 +++ b/man/man8/ip-l2tp.8 @@ -30,6 +30,12 @@ ip-l2tp - L2TPv3 static unmanaged tunnel configuration .IR PORT .RB " ]" .br +.RB "[ " udp_csum " { " on " | " off " } ]" +.br +.RB "[ " udp6_csum_tx " { " on " | " off " } ]" +.br +.RB "[ " udp6_csum_rx " { " on " | " off " } ]" +.br .ti -8 .BR "ip l2tp add session" .RB "[ " name @@ -190,6 +196,33 @@ selected. set the UDP destination port to be used for the tunnel. Must be present when udp encapsulation is selected. Ignored when ip encapsulation is selected. +.TP +.BI udp_csum " STATE" +(IPv4 only) control if IPv4 UDP checksums should be calculated and checked for the +encapsulating UDP packets, when UDP encapsulating is selected. +Default is +.BR off "." +.br +Valid values are: +.BR on ", " off "." +.TP +.BI udp6_csum_tx " STATE" +(IPv6 only) control if IPv6 UDP checksums should be calculated for encapsulating +UDP packets, when UDP encapsulating is selected. +Default is +.BR on "." +.br +Valid values are: +.BR on ", " off "." +.TP +.BI udp6_csum_rx " STATE" +(IPv6 only) control if IPv6 UDP checksums should be checked for the encapsulating +UDP packets, when UDP encapsulating is selected. +Default is +.BR on "." +.br +Valid values are: +.BR on ", " off "." .SS ip l2tp del tunnel - destroy a tunnel .TP .BI tunnel_id " ID" From 281db53ff8be75b2b3590b24d0602774aa80fef4 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 29 Nov 2016 13:40:06 -0800 Subject: [PATCH 503/513] l2tp: style cleanup Make l2tp conform to kernel style guidelines --- ip/ipl2tp.c | 139 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 84 insertions(+), 55 deletions(-) diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index f2bbc0c3e..0f91aebff 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -110,11 +110,13 @@ static int create_tunnel(struct l2tp_parm *p) if (p->local_ip.family == AF_INET6) local_attr = L2TP_ATTR_IP6_SADDR; - addattr_l(&req.n, 1024, local_attr, &p->local_ip.data, p->local_ip.bytelen); + addattr_l(&req.n, 1024, local_attr, &p->local_ip.data, + p->local_ip.bytelen); if (p->peer_ip.family == AF_INET6) peer_attr = L2TP_ATTR_IP6_DADDR; - addattr_l(&req.n, 1024, peer_attr, &p->peer_ip.data, p->peer_ip.bytelen); + addattr_l(&req.n, 1024, peer_attr, &p->peer_ip.data, + p->peer_ip.bytelen); if (p->encap == L2TP_ENCAPTYPE_UDP) { addattr16(&req.n, 1024, L2TP_ATTR_UDP_SPORT, p->local_udp_port); @@ -159,18 +161,27 @@ static int create_session(struct l2tp_parm *p) addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_TYPE, p->l2spec_type); addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_LEN, p->l2spec_len); - if (p->mtu) addattr16(&req.n, 1024, L2TP_ATTR_MTU, p->mtu); - if (p->recv_seq) addattr8(&req.n, 1024, L2TP_ATTR_RECV_SEQ, 1); - if (p->send_seq) addattr8(&req.n, 1024, L2TP_ATTR_SEND_SEQ, 1); - if (p->lns_mode) addattr(&req.n, 1024, L2TP_ATTR_LNS_MODE); - if (p->data_seq) addattr8(&req.n, 1024, L2TP_ATTR_DATA_SEQ, p->data_seq); - if (p->reorder_timeout) addattr64(&req.n, 1024, L2TP_ATTR_RECV_TIMEOUT, + if (p->mtu) + addattr16(&req.n, 1024, L2TP_ATTR_MTU, p->mtu); + if (p->recv_seq) + addattr8(&req.n, 1024, L2TP_ATTR_RECV_SEQ, 1); + if (p->send_seq) + addattr8(&req.n, 1024, L2TP_ATTR_SEND_SEQ, 1); + if (p->lns_mode) + addattr(&req.n, 1024, L2TP_ATTR_LNS_MODE); + if (p->data_seq) + addattr8(&req.n, 1024, L2TP_ATTR_DATA_SEQ, p->data_seq); + if (p->reorder_timeout) + addattr64(&req.n, 1024, L2TP_ATTR_RECV_TIMEOUT, p->reorder_timeout); - if (p->offset) addattr16(&req.n, 1024, L2TP_ATTR_OFFSET, p->offset); - if (p->cookie_len) addattr_l(&req.n, 1024, L2TP_ATTR_COOKIE, - p->cookie, p->cookie_len); - if (p->peer_cookie_len) addattr_l(&req.n, 1024, L2TP_ATTR_PEER_COOKIE, - p->peer_cookie, p->peer_cookie_len); + if (p->offset) + addattr16(&req.n, 1024, L2TP_ATTR_OFFSET, p->offset); + if (p->cookie_len) + addattr_l(&req.n, 1024, L2TP_ATTR_COOKIE, + p->cookie, p->cookie_len); + if (p->peer_cookie_len) + addattr_l(&req.n, 1024, L2TP_ATTR_PEER_COOKIE, + p->peer_cookie, p->peer_cookie_len); if (p->ifname && p->ifname[0]) addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname); @@ -213,8 +224,12 @@ static void print_tunnel(const struct l2tp_data *data) p->tunnel_id, p->encap == L2TP_ENCAPTYPE_UDP ? "UDP" : p->encap == L2TP_ENCAPTYPE_IP ? "IP" : "??"); - printf(" From %s ", inet_ntop(p->local_ip.family, p->local_ip.data, buf, sizeof(buf))); - printf("to %s\n", inet_ntop(p->peer_ip.family, p->peer_ip.data, buf, sizeof(buf))); + printf(" From %s ", + inet_ntop(p->local_ip.family, p->local_ip.data, + buf, sizeof(buf))); + printf("to %s\n", + inet_ntop(p->peer_ip.family, p->peer_ip.data, + buf, sizeof(buf))); printf(" Peer tunnel %u\n", p->peer_tunnel_id); @@ -229,10 +244,14 @@ static void print_tunnel(const struct l2tp_data *data) break; case AF_INET6: printf(" UDP checksum: %s%s%s%s\n", - p->udp6_csum_tx && p->udp6_csum_rx ? "enabled" : "", - p->udp6_csum_tx && !p->udp6_csum_rx ? "tx" : "", - !p->udp6_csum_tx && p->udp6_csum_rx ? "rx" : "", - !p->udp6_csum_tx && !p->udp6_csum_rx ? "disabled" : ""); + p->udp6_csum_tx && p->udp6_csum_rx + ? "enabled" : "", + p->udp6_csum_tx && !p->udp6_csum_rx + ? "tx" : "", + !p->udp6_csum_tx && p->udp6_csum_rx + ? "rx" : "", + !p->udp6_csum_tx && !p->udp6_csum_rx + ? "disabled" : ""); break; } } @@ -247,9 +266,9 @@ static void print_session(struct l2tp_data *data) printf(" Peer session %u, tunnel %u\n", p->peer_session_id, p->peer_tunnel_id); - if (p->ifname != NULL) { + if (p->ifname != NULL) printf(" interface name: %s\n", p->ifname); - } + printf(" offset %u, peer offset %u\n", p->offset, p->peer_offset); if (p->cookie_len > 0) @@ -263,8 +282,10 @@ static void print_session(struct l2tp_data *data) printf("\n"); if (p->send_seq || p->recv_seq) { printf(" sequence numbering:"); - if (p->send_seq) printf(" send"); - if (p->recv_seq) printf(" recv"); + if (p->send_seq) + printf(" send"); + if (p->recv_seq) + printf(" recv"); printf("\n"); } } @@ -391,7 +412,8 @@ static int get_response(struct nlmsghdr *n, void *arg) return 0; } -static int session_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +static int session_nlmsg(const struct sockaddr_nl *who, + struct nlmsghdr *n, void *arg) { int ret = get_response(n, arg); @@ -411,7 +433,8 @@ static int get_session(struct l2tp_data *p) if (p->config.tunnel_id && p->config.session_id) { addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->config.tunnel_id); - addattr32(&req.n, 128, L2TP_ATTR_SESSION_ID, p->config.session_id); + addattr32(&req.n, 128, L2TP_ATTR_SESSION_ID, + p->config.session_id); } if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0) @@ -425,7 +448,8 @@ static int get_session(struct l2tp_data *p) return 0; } -static int tunnel_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +static int tunnel_nlmsg(const struct sockaddr_nl *who, + struct nlmsghdr *n, void *arg) { int ret = get_response(n, arg); @@ -490,32 +514,33 @@ static void usage(void) __attribute__((noreturn)); static void usage(void) { - fprintf(stderr, "Usage: ip l2tp add tunnel\n"); - fprintf(stderr, " remote ADDR local ADDR\n"); - fprintf(stderr, " tunnel_id ID peer_tunnel_id ID\n"); - fprintf(stderr, " [ encap { ip | udp } ]\n"); - fprintf(stderr, " [ udp_sport PORT ] [ udp_dport PORT ]\n"); - fprintf(stderr, " [ udp_csum { on | off } ]\n"); - fprintf(stderr, " [ udp6_csum_tx { on | off } ]\n"); - fprintf(stderr, " [ udp6_csum_rx { on | off } ]\n"); - fprintf(stderr, "Usage: ip l2tp add session [ name NAME ]\n"); - fprintf(stderr, " tunnel_id ID\n"); - fprintf(stderr, " session_id ID peer_session_id ID\n"); - fprintf(stderr, " [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n"); - fprintf(stderr, " [ offset OFFSET ] [ peer_offset OFFSET ]\n"); - fprintf(stderr, " [ seq { none | send | recv | both } ]\n"); - fprintf(stderr, " [ l2spec_type L2SPEC ]\n"); - fprintf(stderr, " ip l2tp del tunnel tunnel_id ID\n"); - fprintf(stderr, " ip l2tp del session tunnel_id ID session_id ID\n"); - fprintf(stderr, " ip l2tp show tunnel [ tunnel_id ID ]\n"); - fprintf(stderr, " ip l2tp show session [ tunnel_id ID ] [ session_id ID ]\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Where: NAME := STRING\n"); - fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n"); - fprintf(stderr, " PORT := { 0..65535 }\n"); - fprintf(stderr, " ID := { 1..4294967295 }\n"); - fprintf(stderr, " HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }\n"); - fprintf(stderr, " L2SPEC := { none | default }\n"); + fprintf(stderr, "Usage: ip l2tp add tunnel\n" + " remote ADDR local ADDR\n" + " tunnel_id ID peer_tunnel_id ID\n" + " [ encap { ip | udp } ]\n" + " [ udp_sport PORT ] [ udp_dport PORT ]\n" + " [ udp_csum { on | off } ]\n" + " [ udp6_csum_tx { on | off } ]\n" + " [ udp6_csum_rx { on | off } ]\n" + "Usage: ip l2tp add session [ name NAME ]\n" + " tunnel_id ID\n" + " session_id ID peer_session_id ID\n" + " [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n" + " [ offset OFFSET ] [ peer_offset OFFSET ]\n" + " [ seq { none | send | recv | both } ]\n" + " [ l2spec_type L2SPEC ]\n" + " ip l2tp del tunnel tunnel_id ID\n" + " ip l2tp del session tunnel_id ID session_id ID\n" + " ip l2tp show tunnel [ tunnel_id ID ]\n" + " ip l2tp show session [ tunnel_id ID ] [ session_id ID ]\n" + "\n" + "Where: NAME := STRING\n" + " ADDR := { IP_ADDRESS | any }\n" + " PORT := { 0..65535 }\n" + " ID := { 1..4294967295 }\n" + " HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }\n" + " L2SPEC := { none | default }\n"); + exit(-1); } @@ -671,7 +696,9 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p) p->l2spec_type = L2TP_L2SPECTYPE_NONE; p->l2spec_len = 0; } else { - fprintf(stderr, "Unknown layer2specific header type \"%s\"\n", *argv); + fprintf(stderr, + "Unknown layer2specific header type \"%s\"\n", + *argv); exit(-1); } } else if (strcmp(*argv, "seq") == 0) { @@ -687,7 +714,8 @@ static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p) p->recv_seq = 0; p->send_seq = 0; } else { - fprintf(stderr, "Unknown seq value \"%s\"\n", *argv); + fprintf(stderr, + "Unknown seq value \"%s\"\n", *argv); exit(-1); } } else if (strcmp(*argv, "tunnel") == 0) { @@ -818,6 +846,7 @@ int do_ipl2tp(int argc, char **argv) matches(*argv, "list") == 0) return do_show(argc-1, argv+1); - fprintf(stderr, "Command \"%s\" is unknown, try \"ip l2tp help\".\n", *argv); + fprintf(stderr, + "Command \"%s\" is unknown, try \"ip l2tp help\".\n", *argv); exit(-1); } From 6bd1ea28c53fd7b7d59a656796230c28c9dae65e Mon Sep 17 00:00:00 2001 From: Zhang Shengju Date: Fri, 25 Nov 2016 22:01:29 +0800 Subject: [PATCH 504/513] link: add team and team_slave link type Add missing team and team_slave link type. Signed-off-by: Zhang Shengju --- ip/iplink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ip/iplink.c b/ip/iplink.c index a8b49c523..1e603e705 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -98,8 +98,8 @@ void iplink_usage(void) fprintf(stderr, " ip link help [ TYPE ]\n\n" "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n" - " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n" - " gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n" + " bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n" + " gre | gretap | ip6gre | ip6gretap | vti | nlmon | team_slave |\n" " bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }\n"); } exit(-1); From 11f4cd31d2776bbffecceb6775d0210fe16cc04e Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 27 Nov 2016 13:21:02 +0200 Subject: [PATCH 505/513] devlink: Add usage help for eswitch subcommand Add missing usage help for devlink dev eswitch subcommand. Signed-off-by: Roi Dayan Reviewed-by: Or Gerlitz --- devlink/devlink.c | 7 ++++++- man/man8/devlink-dev.8 | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index ccca0fb39..673234fa7 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -963,6 +963,8 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) static void cmd_dev_help(void) { pr_err("Usage: devlink dev show [ DEV ]\n"); + pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n"); + pr_err(" devlink dev eswitch show DEV\n"); } static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name, @@ -1259,7 +1261,10 @@ static int cmd_dev_eswitch_set(struct dl *dl) static int cmd_dev_eswitch(struct dl *dl) { - if (dl_argv_match(dl, "set")) { + if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { + cmd_dev_help(); + return 0; + } else if (dl_argv_match(dl, "set")) { dl_arg_inc(dl); return cmd_dev_eswitch_set(dl); } else if (dl_argv_match(dl, "show")) { diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8 index 9ce319374..931e334da 100644 --- a/man/man8/devlink-dev.8 +++ b/man/man8/devlink-dev.8 @@ -54,7 +54,7 @@ BUS_NAME/BUS_ADDRESS .TP .BR mode " { " legacy " | " switchdev " } " -set eswitch mode +Set eswitch mode .I legacy - Legacy SRIOV From b9dcf9c2826cc193937e5c337dee96a4c111e56a Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 27 Nov 2016 13:21:03 +0200 Subject: [PATCH 506/513] devlink: Add option to set and show eswitch inline mode This is needed for some HWs to do proper macthing and steering. Possible values are none, link, network, transport. Signed-off-by: Roi Dayan Reviewed-by: Or Gerlitz --- devlink/devlink.c | 82 ++++++++++++++++++++++++++++++++++++++++- include/linux/devlink.h | 8 ++++ man/man8/devlink-dev.8 | 19 ++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index 673234fa7..23db9e7cd 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -28,6 +28,10 @@ #define ESWITCH_MODE_LEGACY "legacy" #define ESWITCH_MODE_SWITCHDEV "switchdev" +#define ESWITCH_INLINE_MODE_NONE "none" +#define ESWITCH_INLINE_MODE_LINK "link" +#define ESWITCH_INLINE_MODE_NETWORK "network" +#define ESWITCH_INLINE_MODE_TRANSPORT "transport" #define pr_err(args...) fprintf(stderr, ##args) #define pr_out(args...) fprintf(stdout, ##args) @@ -132,6 +136,7 @@ static void ifname_map_free(struct ifname_map *ifname_map) #define DL_OPT_SB_TH BIT(9) #define DL_OPT_SB_TC BIT(10) #define DL_OPT_ESWITCH_MODE BIT(11) +#define DL_OPT_ESWITCH_INLINE_MODE BIT(12) struct dl_opts { uint32_t present; /* flags of present items */ @@ -148,6 +153,7 @@ struct dl_opts { uint32_t sb_threshold; uint16_t sb_tc_index; enum devlink_eswitch_mode eswitch_mode; + enum devlink_eswitch_inline_mode eswitch_inline_mode; }; struct dl { @@ -305,6 +311,9 @@ static int attr_cb(const struct nlattr *attr, void *data) if (type == DEVLINK_ATTR_ESWITCH_MODE && mnl_attr_validate(attr, MNL_TYPE_U16) < 0) return MNL_CB_ERROR; + if (type == DEVLINK_ATTR_ESWITCH_INLINE_MODE && + mnl_attr_validate(attr, MNL_TYPE_U8) < 0) + return MNL_CB_ERROR; tb[type] = attr; return MNL_CB_OK; } @@ -682,6 +691,24 @@ static int eswitch_mode_get(const char *typestr, return 0; } +static int eswitch_inline_mode_get(const char *typestr, + enum devlink_eswitch_inline_mode *p_mode) +{ + if (strcmp(typestr, ESWITCH_INLINE_MODE_NONE) == 0) { + *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NONE; + } else if (strcmp(typestr, ESWITCH_INLINE_MODE_LINK) == 0) { + *p_mode = DEVLINK_ESWITCH_INLINE_MODE_LINK; + } else if (strcmp(typestr, ESWITCH_INLINE_MODE_NETWORK) == 0) { + *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK; + } else if (strcmp(typestr, ESWITCH_INLINE_MODE_TRANSPORT) == 0) { + *p_mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT; + } else { + pr_err("Unknown eswitch inline mode \"%s\"\n", typestr); + return -EINVAL; + } + return 0; +} + static int dl_argv_parse(struct dl *dl, uint32_t o_required, uint32_t o_optional) { @@ -803,6 +830,19 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, if (err) return err; o_found |= DL_OPT_ESWITCH_MODE; + } else if (dl_argv_match(dl, "inline-mode") && + (o_all & DL_OPT_ESWITCH_INLINE_MODE)) { + const char *typestr; + + dl_arg_inc(dl); + err = dl_argv_str(dl, &typestr); + if (err) + return err; + err = eswitch_inline_mode_get( + typestr, &opts->eswitch_inline_mode); + if (err) + return err; + o_found |= DL_OPT_ESWITCH_INLINE_MODE; } else { pr_err("Unknown option \"%s\"\n", dl_argv(dl)); return -EINVAL; @@ -863,6 +903,12 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, return -EINVAL; } + if ((o_required & DL_OPT_ESWITCH_INLINE_MODE) && + !(o_found & DL_OPT_ESWITCH_INLINE_MODE)) { + pr_err("E-Switch inline-mode option expected.\n"); + return -EINVAL; + } + return 0; } @@ -909,6 +955,9 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) if (opts->present & DL_OPT_ESWITCH_MODE) mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE, opts->eswitch_mode); + if (opts->present & DL_OPT_ESWITCH_INLINE_MODE) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE, + opts->eswitch_inline_mode); } static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, @@ -964,6 +1013,7 @@ static void cmd_dev_help(void) { pr_err("Usage: devlink dev show [ DEV ]\n"); pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n"); + pr_err(" [ inline-mode { none | link | network | transport } ]\n"); pr_err(" devlink dev eswitch show DEV\n"); } @@ -1203,6 +1253,22 @@ static const char *eswitch_mode_name(uint32_t mode) } } +static const char *eswitch_inline_mode_name(uint32_t mode) +{ + switch (mode) { + case DEVLINK_ESWITCH_INLINE_MODE_NONE: + return ESWITCH_INLINE_MODE_NONE; + case DEVLINK_ESWITCH_INLINE_MODE_LINK: + return ESWITCH_INLINE_MODE_LINK; + case DEVLINK_ESWITCH_INLINE_MODE_NETWORK: + return ESWITCH_INLINE_MODE_NETWORK; + case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT: + return ESWITCH_INLINE_MODE_TRANSPORT; + default: + return ""; + } +} + static void pr_out_eswitch(struct dl *dl, struct nlattr **tb) { __pr_out_handle_start(dl, tb, true, false); @@ -1210,6 +1276,12 @@ static void pr_out_eswitch(struct dl *dl, struct nlattr **tb) if (tb[DEVLINK_ATTR_ESWITCH_MODE]) pr_out_str(dl, "mode", eswitch_mode_name(mnl_attr_get_u16(tb[DEVLINK_ATTR_ESWITCH_MODE]))); + + if (tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) + pr_out_str(dl, "inline-mode", + eswitch_inline_mode_name(mnl_attr_get_u8( + tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE]))); + pr_out_handle_end(dl); } @@ -1252,10 +1324,18 @@ static int cmd_dev_eswitch_set(struct dl *dl) nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_MODE_SET, NLM_F_REQUEST | NLM_F_ACK); - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_ESWITCH_MODE, 0); + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, + DL_OPT_ESWITCH_MODE | + DL_OPT_ESWITCH_INLINE_MODE); + if (err) return err; + if (dl->opts.present == 1) { + pr_err("Need to set at least one option\n"); + return -ENOENT; + } + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); } diff --git a/include/linux/devlink.h b/include/linux/devlink.h index b7c1a0697..7c14d7731 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -102,6 +102,13 @@ enum devlink_eswitch_mode { DEVLINK_ESWITCH_MODE_SWITCHDEV, }; +enum devlink_eswitch_inline_mode { + DEVLINK_ESWITCH_INLINE_MODE_NONE, + DEVLINK_ESWITCH_INLINE_MODE_LINK, + DEVLINK_ESWITCH_INLINE_MODE_NETWORK, + DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT, +}; + enum devlink_attr { /* don't change the order or add anything between, this is ABI! */ DEVLINK_ATTR_UNSPEC, @@ -133,6 +140,7 @@ enum devlink_attr { DEVLINK_ATTR_SB_OCC_CUR, /* u32 */ DEVLINK_ATTR_SB_OCC_MAX, /* u32 */ DEVLINK_ATTR_ESWITCH_MODE, /* u16 */ + DEVLINK_ATTR_ESWITCH_INLINE_MODE, /* u8 */ /* add new attributes above here, update the policy in devlink.c */ diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8 index 931e334da..6bfe66f87 100644 --- a/man/man8/devlink-dev.8 +++ b/man/man8/devlink-dev.8 @@ -31,6 +31,9 @@ devlink-dev \- devlink device configuration .RI "[ " .BR mode " { " legacy " | " switchdev " } " .RI "]" +.RI "[ " +.BR inline-mode " { " none " | " link " | " network " | " transport " } " +.RI "]" .ti -8 .BR "devlink dev eswitch show" @@ -62,6 +65,22 @@ Set eswitch mode .I switchdev - SRIOV switchdev offloads +.TP +.BR inline-mode " { " none " | " link " | " network " | " transport " } " +Some HWs need the VF driver to put part of the packet headers on the TX descriptor so the e-switch can do proper matching and steering. + +.I none +- None + +.I link +- L2 mode + +.I network +- L3 mode + +.I transport +- L4 mode + .SH "EXAMPLES" .PP devlink dev show From f5f760b81250630da23a4021c30e802695be79d2 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 30 Nov 2016 09:29:48 +0100 Subject: [PATCH 507/513] man: ip-route.8: Add notes about dropped IPv4 route cache Signed-off-by: Phil Sutter --- man/man8/ip-route.8.in | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/man/man8/ip-route.8.in b/man/man8/ip-route.8.in index d4fae3cc7..c0acaa002 100644 --- a/man/man8/ip-route.8.in +++ b/man/man8/ip-route.8.in @@ -924,6 +924,12 @@ routes are left unchanged. Any routes specified in the data stream that already exist in the table will be ignored. .RE +.SH NOTES +Starting with Linux kernel version 3.6, there is no routing cache for IPv4 +anymore. Hence +.B "ip route show cached" +will never print any entries on systems with this or newer kernel versions. + .SH EXAMPLES .PP ip ro From 1dd0cca7faef1d0223347caa30589c7d36a6ad8f Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 2 Dec 2016 12:56:05 +0100 Subject: [PATCH 508/513] ss: initialise variables outside of for loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialise for loops outside of for loops. GCC flags this as being out of spec unless C99 or C11 mode is used. With this change the entire tree appears to compile cleanly with -Wall. $ gcc --version gcc (Debian 4.9.2-10) 4.9.2 ... $ make ... ss.c: In function ‘unix_show_sock’: ss.c:3128:4: error: ‘for’ loop initial declarations are only allowed in C99 or C11 mode ... Signed-off-by: Simon Horman --- misc/ss.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index 07dcd8c20..20b71f552 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -3081,10 +3081,12 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh, memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len); name[len] = '\0'; - if (name[0] == '\0') - for (int i = 0; i < len; i++) + if (name[0] == '\0') { + int i; + for (i = 0; i < len; i++) if (name[i] == '\0') name[i] = '@'; + } stat.name = &name[0]; memcpy(stat.local.data, &stat.name, sizeof(stat.name)); } From d64691699339b5d597b93b7fc8f95e314ac09ef6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 9 Dec 2016 12:37:19 -0800 Subject: [PATCH 509/513] Revert "devlink: Add option to set and show eswitch inline mode" This reverts commit b9dcf9c2826cc193937e5c337dee96a4c111e56a. Intended for net-next --- devlink/devlink.c | 82 +---------------------------------------- include/linux/devlink.h | 8 ---- man/man8/devlink-dev.8 | 19 ---------- 3 files changed, 1 insertion(+), 108 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index 23db9e7cd..673234fa7 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -28,10 +28,6 @@ #define ESWITCH_MODE_LEGACY "legacy" #define ESWITCH_MODE_SWITCHDEV "switchdev" -#define ESWITCH_INLINE_MODE_NONE "none" -#define ESWITCH_INLINE_MODE_LINK "link" -#define ESWITCH_INLINE_MODE_NETWORK "network" -#define ESWITCH_INLINE_MODE_TRANSPORT "transport" #define pr_err(args...) fprintf(stderr, ##args) #define pr_out(args...) fprintf(stdout, ##args) @@ -136,7 +132,6 @@ static void ifname_map_free(struct ifname_map *ifname_map) #define DL_OPT_SB_TH BIT(9) #define DL_OPT_SB_TC BIT(10) #define DL_OPT_ESWITCH_MODE BIT(11) -#define DL_OPT_ESWITCH_INLINE_MODE BIT(12) struct dl_opts { uint32_t present; /* flags of present items */ @@ -153,7 +148,6 @@ struct dl_opts { uint32_t sb_threshold; uint16_t sb_tc_index; enum devlink_eswitch_mode eswitch_mode; - enum devlink_eswitch_inline_mode eswitch_inline_mode; }; struct dl { @@ -311,9 +305,6 @@ static int attr_cb(const struct nlattr *attr, void *data) if (type == DEVLINK_ATTR_ESWITCH_MODE && mnl_attr_validate(attr, MNL_TYPE_U16) < 0) return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_ESWITCH_INLINE_MODE && - mnl_attr_validate(attr, MNL_TYPE_U8) < 0) - return MNL_CB_ERROR; tb[type] = attr; return MNL_CB_OK; } @@ -691,24 +682,6 @@ static int eswitch_mode_get(const char *typestr, return 0; } -static int eswitch_inline_mode_get(const char *typestr, - enum devlink_eswitch_inline_mode *p_mode) -{ - if (strcmp(typestr, ESWITCH_INLINE_MODE_NONE) == 0) { - *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NONE; - } else if (strcmp(typestr, ESWITCH_INLINE_MODE_LINK) == 0) { - *p_mode = DEVLINK_ESWITCH_INLINE_MODE_LINK; - } else if (strcmp(typestr, ESWITCH_INLINE_MODE_NETWORK) == 0) { - *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK; - } else if (strcmp(typestr, ESWITCH_INLINE_MODE_TRANSPORT) == 0) { - *p_mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT; - } else { - pr_err("Unknown eswitch inline mode \"%s\"\n", typestr); - return -EINVAL; - } - return 0; -} - static int dl_argv_parse(struct dl *dl, uint32_t o_required, uint32_t o_optional) { @@ -830,19 +803,6 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, if (err) return err; o_found |= DL_OPT_ESWITCH_MODE; - } else if (dl_argv_match(dl, "inline-mode") && - (o_all & DL_OPT_ESWITCH_INLINE_MODE)) { - const char *typestr; - - dl_arg_inc(dl); - err = dl_argv_str(dl, &typestr); - if (err) - return err; - err = eswitch_inline_mode_get( - typestr, &opts->eswitch_inline_mode); - if (err) - return err; - o_found |= DL_OPT_ESWITCH_INLINE_MODE; } else { pr_err("Unknown option \"%s\"\n", dl_argv(dl)); return -EINVAL; @@ -903,12 +863,6 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, return -EINVAL; } - if ((o_required & DL_OPT_ESWITCH_INLINE_MODE) && - !(o_found & DL_OPT_ESWITCH_INLINE_MODE)) { - pr_err("E-Switch inline-mode option expected.\n"); - return -EINVAL; - } - return 0; } @@ -955,9 +909,6 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) if (opts->present & DL_OPT_ESWITCH_MODE) mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE, opts->eswitch_mode); - if (opts->present & DL_OPT_ESWITCH_INLINE_MODE) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE, - opts->eswitch_inline_mode); } static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, @@ -1013,7 +964,6 @@ static void cmd_dev_help(void) { pr_err("Usage: devlink dev show [ DEV ]\n"); pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n"); - pr_err(" [ inline-mode { none | link | network | transport } ]\n"); pr_err(" devlink dev eswitch show DEV\n"); } @@ -1253,22 +1203,6 @@ static const char *eswitch_mode_name(uint32_t mode) } } -static const char *eswitch_inline_mode_name(uint32_t mode) -{ - switch (mode) { - case DEVLINK_ESWITCH_INLINE_MODE_NONE: - return ESWITCH_INLINE_MODE_NONE; - case DEVLINK_ESWITCH_INLINE_MODE_LINK: - return ESWITCH_INLINE_MODE_LINK; - case DEVLINK_ESWITCH_INLINE_MODE_NETWORK: - return ESWITCH_INLINE_MODE_NETWORK; - case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT: - return ESWITCH_INLINE_MODE_TRANSPORT; - default: - return ""; - } -} - static void pr_out_eswitch(struct dl *dl, struct nlattr **tb) { __pr_out_handle_start(dl, tb, true, false); @@ -1276,12 +1210,6 @@ static void pr_out_eswitch(struct dl *dl, struct nlattr **tb) if (tb[DEVLINK_ATTR_ESWITCH_MODE]) pr_out_str(dl, "mode", eswitch_mode_name(mnl_attr_get_u16(tb[DEVLINK_ATTR_ESWITCH_MODE]))); - - if (tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) - pr_out_str(dl, "inline-mode", - eswitch_inline_mode_name(mnl_attr_get_u8( - tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE]))); - pr_out_handle_end(dl); } @@ -1324,18 +1252,10 @@ static int cmd_dev_eswitch_set(struct dl *dl) nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_MODE_SET, NLM_F_REQUEST | NLM_F_ACK); - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, - DL_OPT_ESWITCH_MODE | - DL_OPT_ESWITCH_INLINE_MODE); - + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_ESWITCH_MODE, 0); if (err) return err; - if (dl->opts.present == 1) { - pr_err("Need to set at least one option\n"); - return -ENOENT; - } - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); } diff --git a/include/linux/devlink.h b/include/linux/devlink.h index 7c14d7731..b7c1a0697 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -102,13 +102,6 @@ enum devlink_eswitch_mode { DEVLINK_ESWITCH_MODE_SWITCHDEV, }; -enum devlink_eswitch_inline_mode { - DEVLINK_ESWITCH_INLINE_MODE_NONE, - DEVLINK_ESWITCH_INLINE_MODE_LINK, - DEVLINK_ESWITCH_INLINE_MODE_NETWORK, - DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT, -}; - enum devlink_attr { /* don't change the order or add anything between, this is ABI! */ DEVLINK_ATTR_UNSPEC, @@ -140,7 +133,6 @@ enum devlink_attr { DEVLINK_ATTR_SB_OCC_CUR, /* u32 */ DEVLINK_ATTR_SB_OCC_MAX, /* u32 */ DEVLINK_ATTR_ESWITCH_MODE, /* u16 */ - DEVLINK_ATTR_ESWITCH_INLINE_MODE, /* u8 */ /* add new attributes above here, update the policy in devlink.c */ diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8 index 6bfe66f87..931e334da 100644 --- a/man/man8/devlink-dev.8 +++ b/man/man8/devlink-dev.8 @@ -31,9 +31,6 @@ devlink-dev \- devlink device configuration .RI "[ " .BR mode " { " legacy " | " switchdev " } " .RI "]" -.RI "[ " -.BR inline-mode " { " none " | " link " | " network " | " transport " } " -.RI "]" .ti -8 .BR "devlink dev eswitch show" @@ -65,22 +62,6 @@ Set eswitch mode .I switchdev - SRIOV switchdev offloads -.TP -.BR inline-mode " { " none " | " link " | " network " | " transport " } " -Some HWs need the VF driver to put part of the packet headers on the TX descriptor so the e-switch can do proper matching and steering. - -.I none -- None - -.I link -- L2 mode - -.I network -- L3 mode - -.I transport -- L4 mode - .SH "EXAMPLES" .PP devlink dev show From b95e5c55a9aa35750f7e9241bda4b3f59050cbb0 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 9 Dec 2016 12:37:39 -0800 Subject: [PATCH 510/513] Revert "devlink: Add usage help for eswitch subcommand" This reverts commit 11f4cd31d2776bbffecceb6775d0210fe16cc04e. --- devlink/devlink.c | 7 +------ man/man8/devlink-dev.8 | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index 673234fa7..ccca0fb39 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -963,8 +963,6 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) static void cmd_dev_help(void) { pr_err("Usage: devlink dev show [ DEV ]\n"); - pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n"); - pr_err(" devlink dev eswitch show DEV\n"); } static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name, @@ -1261,10 +1259,7 @@ static int cmd_dev_eswitch_set(struct dl *dl) static int cmd_dev_eswitch(struct dl *dl) { - if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { - cmd_dev_help(); - return 0; - } else if (dl_argv_match(dl, "set")) { + if (dl_argv_match(dl, "set")) { dl_arg_inc(dl); return cmd_dev_eswitch_set(dl); } else if (dl_argv_match(dl, "show")) { diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8 index 931e334da..9ce319374 100644 --- a/man/man8/devlink-dev.8 +++ b/man/man8/devlink-dev.8 @@ -54,7 +54,7 @@ BUS_NAME/BUS_ADDRESS .TP .BR mode " { " legacy " | " switchdev " } " -Set eswitch mode +set eswitch mode .I legacy - Legacy SRIOV From e49aef96bb11a3d5e33146dcff61c6d901c2ccf5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 9 Dec 2016 12:38:35 -0800 Subject: [PATCH 511/513] update kernel headers --- include/linux/if.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/if.h b/include/linux/if.h index 5b8494821..bf33a3e8d 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -31,7 +31,7 @@ #include /* For glibc compatibility. An empty enum does not compile. */ -#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && \ +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || \ __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 /** * enum net_device_flags - &struct net_device flags @@ -99,7 +99,7 @@ enum net_device_flags { IFF_ECHO = 1<<18, /* __volatile__ */ #endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ }; -#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */ +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */ /* for compatibility with glibc net/if.h */ #if __UAPI_DEF_IF_NET_DEVICE_FLAGS From dc5622cb664cd6fb6f816e811a78d68f630ecdc3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 12 Dec 2016 15:05:59 -0800 Subject: [PATCH 512/513] update to 4.9 release headers Signed-off-by: Stephen Hemminger --- include/linux/can.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/can.h b/include/linux/can.h index 4af39b083..f7a810deb 100644 --- a/include/linux/can.h +++ b/include/linux/can.h @@ -196,5 +196,6 @@ struct can_filter { }; #define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */ +#define CAN_RAW_FILTER_MAX 512 /* maximum number of can_filter set via setsockopt() */ #endif /* !_UAPI_CAN_H */ From ae0969c89351de7f56387d857dc76a98b4258093 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 12 Dec 2016 15:07:42 -0800 Subject: [PATCH 513/513] v4.9.0 --- include/SNAPSHOT.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/SNAPSHOT.h b/include/SNAPSHOT.h index 1b43a94c5..8dd12370a 100644 --- a/include/SNAPSHOT.h +++ b/include/SNAPSHOT.h @@ -1 +1 @@ -static const char SNAPSHOT[] = "161009"; +static const char SNAPSHOT[] = "161212";