diff --git a/Makefile b/Makefile index 651d2a50..ea2f797c 100644 --- a/Makefile +++ b/Makefile @@ -96,7 +96,7 @@ snapshot: > include/SNAPSHOT.h clean: - @for i in $(SUBDIRS); \ + @for i in $(SUBDIRS) testsuite; \ do $(MAKE) $(MFLAGS) -C $$i clean; done clobber: diff --git a/bridge/br_common.h b/bridge/br_common.h index 2f1cb8fd..7bf15e95 100644 --- a/bridge/br_common.h +++ b/bridge/br_common.h @@ -6,20 +6,20 @@ #define MDB_RTR_RTA(r) \ ((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(__u32)))) -extern void print_vlan_info(FILE *fp, struct rtattr *tb); -extern int print_linkinfo(const struct sockaddr_nl *who, +void print_vlan_info(FILE *fp, struct rtattr *tb); +int print_linkinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); -extern int print_fdb(const struct sockaddr_nl *who, +int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); -extern int print_mdb(const struct sockaddr_nl *who, +int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); -extern int do_fdb(int argc, char **argv); -extern int do_mdb(int argc, char **argv); -extern int do_monitor(int argc, char **argv); -extern int do_vlan(int argc, char **argv); -extern int do_link(int argc, char **argv); +int do_fdb(int argc, char **argv); +int do_mdb(int argc, char **argv); +int do_monitor(int argc, char **argv); +int do_vlan(int argc, char **argv); +int do_link(int argc, char **argv); extern int preferred_family; extern int show_stats; diff --git a/bridge/bridge.c b/bridge/bridge.c index 451d684e..663a35b2 100644 --- a/bridge/bridge.c +++ b/bridge/bridge.c @@ -42,7 +42,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] -color -p[retty] -j{son} }\n"); +" -c[ompressvlans] -color -p[retty] -j[son] }\n"); exit(-1); } @@ -173,8 +173,7 @@ main(int argc, char **argv) NEXT_ARG(); if (netns_switch(argv[1])) exit(-1); - } else if (matches(opt, "-color") == 0) { - ++color; + } else if (matches_color(opt, &color)) { } else if (matches(opt, "-compressvlans") == 0) { ++compress_vlans; } else if (matches(opt, "-force") == 0) { diff --git a/devlink/devlink.c b/devlink/devlink.c index 784bb84b..519ee257 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -5426,7 +5426,7 @@ static void help(void) pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" " devlink [ -f[orce] ] -b[atch] filename\n" "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region }\n" - " OPTIONS := { -V[ersion] | -n[no-nice-names] | -j[json] | -p[pretty] | -v[verbose] }\n"); + " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] }\n"); } static int dl_cmd(struct dl *dl, int argc, char **argv) diff --git a/genl/genl.c b/genl/genl.c index 20ecb8b6..253c4450 100644 --- a/genl/genl.c +++ b/genl/genl.c @@ -26,12 +26,12 @@ #include "utils.h" #include "genl_utils.h" -int show_stats = 0; -int show_details = 0; -int show_raw = 0; +int show_stats; +int show_details; +int show_raw; static void *BODY; -static struct genl_util * genl_list; +static struct genl_util *genl_list; static int print_nofopt(const struct sockaddr_nl *who, struct nlmsghdr *n, @@ -44,8 +44,9 @@ static int print_nofopt(const struct sockaddr_nl *who, struct nlmsghdr *n, static int parse_nofopt(struct genl_util *f, int argc, char **argv) { if (argc) { - fprintf(stderr, "Unknown genl \"%s\", hence option \"%s\" " - "is unparsable\n", f->name, *argv); + fprintf(stderr, + "Unknown genl \"%s\", hence option \"%s\" is unparsable\n", + f->name, *argv); return -1; } @@ -98,9 +99,10 @@ static void usage(void) __attribute__((noreturn)); static void usage(void) { - fprintf(stderr, "Usage: genl [ OPTIONS ] OBJECT | help }\n" - "where OBJECT := { ctrl etc }\n" - " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] }\n"); + fprintf(stderr, + "Usage: genl [ OPTIONS ] OBJECT [help] }\n" + "where OBJECT := { ctrl etc }\n" + " OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -V[ersion] | -h[elp] }\n"); exit(-1); } @@ -122,19 +124,21 @@ int main(int argc, char **argv) } else if (matches(argv[1], "-help") == 0) { usage(); } else { - fprintf(stderr, "Option \"%s\" is unknown, try " - "\"genl -help\".\n", argv[1]); + fprintf(stderr, + "Option \"%s\" is unknown, try \"genl -help\".\n", + argv[1]); exit(-1); } argc--; argv++; } if (argc > 1) { + struct genl_util *a; int ret; - struct genl_util *a = NULL; + a = get_genl_kind(argv[1]); if (!a) { - fprintf(stderr,"bad genl %s\n", argv[1]); + fprintf(stderr, "bad genl %s\n", argv[1]); exit(-1); } diff --git a/genl/genl_utils.h b/genl/genl_utils.h index 6e6f4450..3de0da34 100644 --- a/genl/genl_utils.h +++ b/genl/genl_utils.h @@ -10,9 +10,10 @@ struct genl_util struct genl_util *next; char name[16]; int (*parse_genlopt)(struct genl_util *fu, int argc, char **argv); - int (*print_genlopt)(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); + int (*print_genlopt)(const struct sockaddr_nl *who, + struct nlmsghdr *n, void *arg); }; -extern int genl_ctrl_resolve_family(const char *family); +int genl_ctrl_resolve_family(const char *family); #endif diff --git a/include/color.h b/include/color.h index 4f2c918d..e30f28c5 100644 --- a/include/color.h +++ b/include/color.h @@ -2,6 +2,8 @@ #ifndef __COLOR_H__ #define __COLOR_H__ 1 +#include + enum color_attr { COLOR_IFNAME, COLOR_MAC, @@ -12,8 +14,15 @@ enum color_attr { COLOR_NONE }; +enum color_opt { + COLOR_OPT_NEVER = 0, + COLOR_OPT_AUTO = 1, + COLOR_OPT_ALWAYS = 2 +}; + void enable_color(void); -int check_enable_color(int color, int json); +bool check_enable_color(int color, int json); +bool matches_color(const char *arg, int *val); void set_color_palette(void); int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...); enum color_attr ifa_family_color(__u8 ifa_family); diff --git a/include/json_writer.h b/include/json_writer.h index 9ab88e1d..0c8831c1 100644 --- a/include/json_writer.h +++ b/include/json_writer.h @@ -29,6 +29,7 @@ void jsonw_pretty(json_writer_t *self, bool on); void jsonw_name(json_writer_t *self, const char *name); /* Add value */ +__attribute__((format(printf, 2, 3))) void jsonw_printf(json_writer_t *self, const char *fmt, ...); void jsonw_string(json_writer_t *self, const char *value); void jsonw_bool(json_writer_t *self, bool value); @@ -59,8 +60,6 @@ void jsonw_luint_field(json_writer_t *self, const char *prop, unsigned long int num); void jsonw_lluint_field(json_writer_t *self, const char *prop, unsigned long long int num); -void jsonw_float_field_fmt(json_writer_t *self, const char *prop, - const char *fmt, double val); /* Collections */ void jsonw_start_object(json_writer_t *self); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 4bbe7e5d..8eb284d2 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -126,6 +126,7 @@ enum bpf_map_type { BPF_MAP_TYPE_XSKMAP, BPF_MAP_TYPE_SOCKHASH, BPF_MAP_TYPE_CGROUP_STORAGE, + BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, }; enum bpf_prog_type { @@ -150,6 +151,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_PROG_TYPE_LWT_SEG6LOCAL, BPF_PROG_TYPE_LIRC_MODE2, + BPF_PROG_TYPE_SK_REUSEPORT, }; enum bpf_attach_type { @@ -2091,6 +2093,24 @@ union bpf_attr { * Return * The id is returned or 0 in case the id could not be retrieved. * + * u64 bpf_skb_ancestor_cgroup_id(struct sk_buff *skb, int ancestor_level) + * Description + * Return id of cgroup v2 that is ancestor of cgroup associated + * with the *skb* at the *ancestor_level*. The root cgroup is at + * *ancestor_level* zero and each step down the hierarchy + * increments the level. If *ancestor_level* == level of cgroup + * associated with *skb*, then return value will be same as that + * of **bpf_skb_cgroup_id**\ (). + * + * The helper is useful to implement policies based on cgroups + * that are upper in hierarchy than immediate cgroup associated + * with *skb*. + * + * The format of returned id and helper limitations are same as in + * **bpf_skb_cgroup_id**\ (). + * Return + * The id is returned or 0 in case the id could not be retrieved. + * * u64 bpf_get_current_cgroup_id(void) * Return * A 64-bit integer containing the current cgroup id based @@ -2113,6 +2133,14 @@ union bpf_attr { * the shared data. * Return * Pointer to the local storage area. + * + * int bpf_sk_select_reuseport(struct sk_reuseport_md *reuse, struct bpf_map *map, void *key, u64 flags) + * Description + * Select a SO_REUSEPORT sk from a BPF_MAP_TYPE_REUSEPORT_ARRAY map + * It checks the selected sk is matching the incoming + * request in the skb. + * Return + * 0 on success, or a negative error in case of failure. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -2196,7 +2224,9 @@ union bpf_attr { FN(rc_keydown), \ FN(skb_cgroup_id), \ FN(get_current_cgroup_id), \ - FN(get_local_storage), + FN(get_local_storage), \ + FN(sk_select_reuseport), \ + FN(skb_ancestor_cgroup_id), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call @@ -2413,6 +2443,30 @@ struct sk_msg_md { __u32 local_port; /* stored in host byte order */ }; +struct sk_reuseport_md { + /* + * Start of directly accessible data. It begins from + * the tcp/udp header. + */ + void *data; + void *data_end; /* End of directly accessible data */ + /* + * Total length of packet (starting from the tcp/udp header). + * Note that the directly accessible bytes (data_end - data) + * could be less than this "len". Those bytes could be + * indirectly read by a helper "bpf_skb_load_bytes()". + */ + __u32 len; + /* + * Eth protocol in the mac header (network byte order). e.g. + * ETH_P_IP(0x0800) and ETH_P_IPV6(0x86DD) + */ + __u32 eth_protocol; + __u32 ip_protocol; /* IP protocol. e.g. IPPROTO_TCP, IPPROTO_UDP */ + __u32 bind_inany; /* Is sock bound to an INANY address? */ + __u32 hash; /* A hash of the packet 4 tuples */ +}; + #define BPF_TAG_SIZE 8 struct bpf_prog_info { diff --git a/ip/ip.c b/ip/ip.c index 38eac5ec..58c643df 100644 --- a/ip/ip.c +++ b/ip/ip.c @@ -55,7 +55,7 @@ static void usage(void) " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n" " -h[uman-readable] | -iec | -j[son] | -p[retty] |\n" " -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n" -" -4 | -6 | -I | -D | -B | -0 |\n" +" -4 | -6 | -I | -D | -M | -B | -0 |\n" " -l[oops] { maximum-addr-flush-attempts } | -br[ief] |\n" " -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n" " -rc[vbuf] [size] | -n[etns] name | -a[ll] | -c[olor]}\n"); @@ -283,8 +283,7 @@ int main(int argc, char **argv) exit(-1); } rcvbuf = size; - } else if (matches(opt, "-color") == 0) { - ++color; + } else if (matches_color(opt, &color)) { } else if (matches(opt, "-help") == 0) { usage(); } else if (matches(opt, "-netns") == 0) { diff --git a/ip/ip_common.h b/ip/ip_common.h index 4d3227cb..200be5e2 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -82,7 +82,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_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/iplink_can.c b/ip/iplink_can.c index 587413da..c0deeb1f 100644 --- a/ip/iplink_can.c +++ b/ip/iplink_can.c @@ -316,11 +316,14 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) struct can_bittiming *bt = RTA_DATA(tb[IFLA_CAN_BITTIMING]); if (is_json_context()) { + json_writer_t *jw; + open_json_object("bittiming"); print_int(PRINT_ANY, "bitrate", NULL, bt->bitrate); - jsonw_float_field_fmt(get_json_writer(), - "sample_point", "%.3f", - (float) bt->sample_point / 1000.); + jw = get_json_writer(); + jsonw_name(jw, "sample_point"); + jsonw_printf(jw, "%.3f", + (float) bt->sample_point / 1000); print_int(PRINT_ANY, "tq", NULL, bt->tq); print_int(PRINT_ANY, "prop_seg", NULL, bt->prop_seg); print_int(PRINT_ANY, "phase_seg1", @@ -415,12 +418,14 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]); if (is_json_context()) { + json_writer_t *jw; + open_json_object("data_bittiming"); print_int(PRINT_JSON, "bitrate", NULL, dbt->bitrate); - jsonw_float_field_fmt(get_json_writer(), - "sample_point", - "%.3f", - (float) dbt->sample_point / 1000.); + jw = get_json_writer(); + jsonw_name(jw, "sample_point"); + jsonw_printf(jw, "%.3f", + (float) dbt->sample_point / 1000.); print_int(PRINT_JSON, "tq", NULL, dbt->tq); print_int(PRINT_JSON, "prop_seg", NULL, dbt->prop_seg); print_int(PRINT_JSON, "phase_seg1", diff --git a/ip/ipmaddr.c b/ip/ipmaddr.c index a4849902..abf83784 100644 --- a/ip/ipmaddr.c +++ b/ip/ipmaddr.c @@ -289,6 +289,7 @@ static int multiaddr_list(int argc, char **argv) static int multiaddr_modify(int cmd, int argc, char **argv) { struct ifreq ifr = {}; + int family; int fd; if (cmd == RTM_NEWADDR) @@ -324,7 +325,17 @@ static int multiaddr_modify(int cmd, int argc, char **argv) exit(-1); } - fd = socket(AF_INET, SOCK_DGRAM, 0); + switch (preferred_family) { + case AF_INET6: + case AF_PACKET: + case AF_INET: + family = preferred_family; + break; + default: + family = AF_INET; + } + + fd = socket(family, SOCK_DGRAM, 0); if (fd < 0) { perror("Cannot create socket"); exit(1); diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c index 8b017341..a93b62cd 100644 --- a/ip/ipmonitor.c +++ b/ip/ipmonitor.c @@ -58,7 +58,9 @@ static int accept_msg(const struct sockaddr_nl *who, { FILE *fp = (FILE *)arg; - if (n->nlmsg_type == RTM_NEWROUTE || n->nlmsg_type == RTM_DELROUTE) { + switch (n->nlmsg_type) { + case RTM_NEWROUTE: + case RTM_DELROUTE: { struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)); @@ -82,24 +84,28 @@ static int accept_msg(const struct sockaddr_nl *who, } } - if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) { + case RTM_NEWLINK: + case RTM_DELLINK: ll_remember_index(who, n, NULL); print_headers(fp, "[LINK]", ctrl); print_linkinfo(who, n, arg); return 0; - } - if (n->nlmsg_type == RTM_NEWADDR || n->nlmsg_type == RTM_DELADDR) { + + case RTM_NEWADDR: + case RTM_DELADDR: print_headers(fp, "[ADDR]", ctrl); print_addrinfo(who, n, arg); return 0; - } - if (n->nlmsg_type == RTM_NEWADDRLABEL || n->nlmsg_type == RTM_DELADDRLABEL) { + + case RTM_NEWADDRLABEL: + case RTM_DELADDRLABEL: print_headers(fp, "[ADDRLABEL]", ctrl); print_addrlabel(who, n, arg); return 0; - } - if (n->nlmsg_type == RTM_NEWNEIGH || n->nlmsg_type == RTM_DELNEIGH || - n->nlmsg_type == RTM_GETNEIGH) { + + case RTM_NEWNEIGH: + case RTM_DELNEIGH: + case RTM_GETNEIGH: if (preferred_family) { struct ndmsg *r = NLMSG_DATA(n); @@ -110,34 +116,42 @@ static int accept_msg(const struct sockaddr_nl *who, print_headers(fp, "[NEIGH]", ctrl); print_neigh(who, n, arg); return 0; - } - if (n->nlmsg_type == RTM_NEWPREFIX) { + + case RTM_NEWPREFIX: print_headers(fp, "[PREFIX]", ctrl); print_prefix(who, n, arg); return 0; - } - if (n->nlmsg_type == RTM_NEWRULE || n->nlmsg_type == RTM_DELRULE) { + + case RTM_NEWRULE: + case RTM_DELRULE: print_headers(fp, "[RULE]", ctrl); print_rule(who, n, arg); return 0; - } - if (n->nlmsg_type == RTM_NEWNETCONF) { + + case NLMSG_TSTAMP: + print_nlmsg_timestamp(fp, n); + return 0; + + case RTM_NEWNETCONF: + case RTM_DELNETCONF: print_headers(fp, "[NETCONF]", ctrl); print_netconf(who, ctrl, n, arg); return 0; - } - if (n->nlmsg_type == NLMSG_TSTAMP) { - print_nlmsg_timestamp(fp, n); - return 0; - } - if (n->nlmsg_type == RTM_NEWNSID || n->nlmsg_type == RTM_DELNSID) { + + case RTM_DELNSID: + case RTM_NEWNSID: print_headers(fp, "[NSID]", ctrl); print_nsid(who, n, arg); return 0; - } - 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", + + case NLMSG_ERROR: + case NLMSG_NOOP: + case NLMSG_DONE: + break; /* ignore */ + + default: + fprintf(stderr, + "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); diff --git a/ip/ipnetconf.c b/ip/ipnetconf.c index 03f98ace..04c4d608 100644 --- a/ip/ipnetconf.c +++ b/ip/ipnetconf.c @@ -66,8 +66,10 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, if (n->nlmsg_type == NLMSG_ERROR) return -1; - if (n->nlmsg_type != RTM_NEWNETCONF) { - fprintf(stderr, "Not RTM_NEWNETCONF: %08x %08x %08x\n", + + if (n->nlmsg_type != RTM_NEWNETCONF && + n->nlmsg_type != RTM_DELNETCONF) { + fprintf(stderr, "Not a netconf message: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return -1; @@ -91,6 +93,9 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, return 0; open_json_object(NULL); + if (n->nlmsg_type == RTM_DELNETCONF) + print_bool(PRINT_ANY, "deleted", "Deleted ", true); + print_string(PRINT_ANY, "family", "%s ", family_name(ncm->ncm_family)); diff --git a/ip/iprule.c b/ip/iprule.c index 8b942143..744d6d88 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -239,7 +239,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) print_string(PRINT_FP, NULL, "to ", NULL); print_color_string(PRINT_ANY, ifa_family_color(frh->family), - "dst", "%s ", dst); + "dst", "%s", dst); if (frh->dst_len != host_len) print_uint(PRINT_ANY, "dstlen", "/%u ", frh->dst_len); else diff --git a/ip/rtmon.c b/ip/rtmon.c index acc11df4..0e795f74 100644 --- a/ip/rtmon.c +++ b/ip/rtmon.c @@ -63,7 +63,9 @@ static int dump_msg2(const struct sockaddr_nl *who, static void usage(void) { - fprintf(stderr, "Usage: rtmon file FILE [ all | LISTofOBJECTS]\n"); + fprintf(stderr, "Usage: rtmon [ OPTIONS ] file FILE [ all | LISTofOBJECTS ]\n"); + fprintf(stderr, "OPTIONS := { -f[amily] { inet | inet6 | link | help } |\n" + " -4 | -6 | -0 | -V[ersion] }\n"); fprintf(stderr, "LISTofOBJECTS := [ link ] [ address ] [ route ]\n"); exit(-1); } diff --git a/lib/color.c b/lib/color.c index edf96e5c..e5406294 100644 --- a/lib/color.c +++ b/lib/color.c @@ -3,11 +3,13 @@ #include #include #include +#include #include #include #include #include "color.h" +#include "utils.h" enum color { C_RED, @@ -77,13 +79,42 @@ void enable_color(void) set_color_palette(); } -int check_enable_color(int color, int json) +bool check_enable_color(int color, int json) { - if (color && !json) { + if (json || color == COLOR_OPT_NEVER) + return false; + + if (color == COLOR_OPT_ALWAYS || isatty(fileno(stdout))) { enable_color(); - return 0; + return true; } - return 1; + return false; +} + +bool matches_color(const char *arg, int *val) +{ + char *dup, *p; + + if (!val) + return false; + + dup = strdupa(arg); + p = strchrnul(dup, '='); + if (*p) + *(p++) = '\0'; + + if (matches(dup, "-color")) + return false; + + if (*p == '\0' || !strcmp(p, "always")) + *val = COLOR_OPT_ALWAYS; + else if (!strcmp(p, "auto")) + *val = COLOR_OPT_AUTO; + else if (!strcmp(p, "never")) + *val = COLOR_OPT_NEVER; + else + return false; + return true; } void set_color_palette(void) @@ -101,6 +132,7 @@ void set_color_palette(void) is_dark_bg = 1; } +__attribute__((format(printf, 3, 4))) int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...) { int ret = 0; diff --git a/lib/json_print.c b/lib/json_print.c index 5dc41bfa..77902824 100644 --- a/lib/json_print.c +++ b/lib/json_print.c @@ -100,6 +100,7 @@ void close_json_array(enum output_type type, const char *str) * functions handling different types */ #define _PRINT_FUNC(type_name, type) \ + __attribute__((format(printf, 4, 0))) \ void print_color_##type_name(enum output_type t, \ enum color_attr color, \ const char *key, \ diff --git a/lib/json_writer.c b/lib/json_writer.c index aa9ce1c6..68890b34 100644 --- a/lib/json_writer.c +++ b/lib/json_writer.c @@ -152,6 +152,7 @@ void jsonw_name(json_writer_t *self, const char *name) putc(' ', self->out); } +__attribute__((format(printf, 2, 3))) void jsonw_printf(json_writer_t *self, const char *fmt, ...) { va_list ap; @@ -205,11 +206,6 @@ void jsonw_null(json_writer_t *self) jsonw_printf(self, "null"); } -void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num) -{ - jsonw_printf(self, fmt, num); -} - void jsonw_float(json_writer_t *self, double num) { jsonw_printf(self, "%g", num); @@ -274,15 +270,6 @@ void jsonw_float_field(json_writer_t *self, const char *prop, double val) jsonw_float(self, val); } -void jsonw_float_field_fmt(json_writer_t *self, - const char *prop, - const char *fmt, - double val) -{ - jsonw_name(self, prop); - jsonw_float_fmt(self, fmt, val); -} - void jsonw_uint_field(json_writer_t *self, const char *prop, unsigned int num) { jsonw_name(self, prop); diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index f6d228c5..53cd3d0a 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -24,7 +24,8 @@ bridge \- show / manipulate bridge addresses and devices \fB\-b\fR[\fIatch\fR] filename | \fB\-c\fR[\folor\fR] | \fB\-p\fR[\fIretty\fR] | -\fB\-j\fR[\fIson\fR] } +\fB\-j\fR[\fIson\fR] | +\fB\-o\fR[\fIneline\fr] } .ti -8 .BR "bridge link set" @@ -171,8 +172,17 @@ If there were any errors during execution of the commands, the application return code will be non zero. .TP -.BR "\-c" , " -color" -Use color output. +.BR \-c [ color ][ = { always | auto | never } +Configure color output. If parameter is omitted or +.BR always , +color output is enabled regardless of stdout state. If parameter is +.BR auto , +stdout is checked to be a terminal before enabling color output. If parameter is +.BR never , +color output is disabled. If specified multiple times, the last one takes +precedence. This flag is ignored if +.B \-json +is also given. .TP .BR "\-j", " \-json" @@ -182,6 +192,18 @@ Output results in JavaScript Object Notation (JSON). .BR "\-p", " \-pretty" When combined with -j generate a pretty JSON output. +.TP +.BR "\-o", " \-oneline" +output each record on a single line, replacing line feeds +with the +.B '\e' +character. This is convenient when you want to count records +with +.BR wc (1) +or to +.BR grep (1) +the output. + .SH BRIDGE - COMMAND SYNTAX diff --git a/man/man8/devlink.8 b/man/man8/devlink.8 index ac61b6ad..360031f7 100644 --- a/man/man8/devlink.8 +++ b/man/man8/devlink.8 @@ -47,6 +47,10 @@ Generate JSON output. .BR "\-p" , " --pretty" When combined with -j generate a pretty JSON output. +.TP +.BR "\-v" , " --verbose" +Turn on verbose output. + .SS .I OBJECT diff --git a/man/man8/ifstat.8 b/man/man8/ifstat.8 index 3ba0088d..8cd164dd 100644 --- a/man/man8/ifstat.8 +++ b/man/man8/ifstat.8 @@ -48,6 +48,14 @@ Report average over the last SECS seconds. .B \-z, \-\-zeros Show entries with zero activity. .TP +.B \-j, \-\-json +Display results in JSON format +.TP +.B \-p, \-\-pretty +If combined with +.BR \-\-json , +pretty print the output. +.TP .B \-x, \-\-extended=TYPE Show extended stats of TYPE. Supported types are: diff --git a/man/man8/ip.8 b/man/man8/ip.8 index 0087d18b..1d358879 100644 --- a/man/man8/ip.8 +++ b/man/man8/ip.8 @@ -187,8 +187,17 @@ to executes specified command over all objects, it depends if command supports this option. .TP -.BR "\-c" , " -color" -Use color output. +.BR \-c [ color ][ = { always | auto | never } +Configure color output. If parameter is omitted or +.BR always , +color output is enabled regardless of stdout state. If parameter is +.BR auto , +stdout is checked to be a terminal before enabling color output. If parameter is +.BR never , +color output is disabled. If specified multiple times, the last one takes +precedence. This flag is ignored if +.B \-json +is also given. .TP .BR "\-t" , " \-timestamp" diff --git a/man/man8/rtacct.8 b/man/man8/rtacct.8 index 01321e6d..ccdbf6ca 100644 --- a/man/man8/rtacct.8 +++ b/man/man8/rtacct.8 @@ -4,7 +4,7 @@ nstat, rtacct - network statistics tools. .SH SYNOPSIS -Usage: nstat [ -h?vVzrnasd:t: ] [ PATTERN [ PATTERN ] ] +Usage: nstat [ -h?vVzrnasd:t:jp ] [ PATTERN [ PATTERN ] ] .br Usage: rtacct [ -h?vVzrnasd:t: ] [ ListOfRealms ] @@ -21,7 +21,7 @@ Print help .B \-V, \-\-version Print version .TP -.B \-z, \-\-zero +.B \-z, \-\-zeros Dump zero counters too. By default they are not shown. .TP .B \-r, \-\-reset @@ -39,12 +39,16 @@ Do not update history, so that the next time you will see counters including val .B \-j, \-\-json Display results in JSON format. .TP -.B \-d, \-\-interval +.B \-p, \-\-pretty +When combined with +.BR \-\-json , +pretty print the output. +.TP +.B \-d, \-\-scan Run in daemon mode collecting statistics. is interval between measurements in seconds. .TP - +.B \-t, \-\-interval Time interval to average rates. Default value is 60 seconds. -.TP .SH SEE ALSO lnstat(8) diff --git a/man/man8/ss.8 b/man/man8/ss.8 index 28033d8f..7a6572b1 100644 --- a/man/man8/ss.8 +++ b/man/man8/ss.8 @@ -242,6 +242,9 @@ 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 that parsing /proc/net/tcp is painful. .TP +.B \-E, \-\-events +Continually display sockets as they are destroyed +.TP .B \-Z, \-\-context As the .B \-p diff --git a/man/man8/tc-cake.8 b/man/man8/tc-cake.8 index c1e751d6..c62e5547 100644 --- a/man/man8/tc-cake.8 +++ b/man/man8/tc-cake.8 @@ -569,6 +569,61 @@ possible latency. At link speeds higher than 10 Gbps, setting the no-split-gso parameter can increase the maximum achievable throughput by retaining the full GSO packets. +.SH OVERRIDING CLASSIFICATION WITH TC FILTERS + +CAKE supports overriding of its internal classification of packets through the +tc filter mechanism. Packets can be assigned to different priority tins by +setting the +.B priority +field on the skb, and the flow hashing can be overridden by setting the +.B classid +parameter. + +.PP +.B Tin override + +.br + To assign a priority tin, the major number of the priority field needs +to match the qdisc handle of the cake instance; if it does, the minor number +will be interpreted as the tin index. For example, to classify all ICMP packets +as 'bulk', the following filter can be used: + +.br + # tc qdisc replace dev eth0 handle 1: root cake diffserv3 + # tc filter add dev eth0 parent 1: protocol ip prio 1 \\ + u32 match icmp type 0 0 action skbedit priority 1:1 + +.PP +.B Flow hash override + +.br + To override flow hashing, the classid can be set. CAKE will interpret +the major number of the classid as the host hash used in host isolation mode, +and the minor number as the flow hash used for flow-based queueing. One or both +of those can be set, and will be used if the relevant flow isolation parameter +is set (i.e., the major number will be ignored if CAKE is not configured in +hosts mode, and the minor number will be ignored if CAKE is not configured in +flows mode). + +.br +This example will assign all ICMP packets to the first queue: + +.br + # tc qdisc replace dev eth0 handle 1: root cake + # tc filter add dev eth0 parent 1: protocol ip prio 1 \\ + u32 match icmp type 0 0 classid 0:1 + +.br +If only one of the host and flow overrides is set, CAKE will compute the other +hash from the packet as normal. Note, however, that the host isolation mode +works by assigning a host ID to the flow queue; so if overriding both host and +flow, the same flow cannot have more than one host assigned. In addition, it is +not possible to assign different source and destination host IDs through the +override mechanism; if a host ID is assigned, it will be used as both source and +destination host. + + + .SH EXAMPLES # tc qdisc delete root dev eth0 .br diff --git a/man/man8/tc.8 b/man/man8/tc.8 index fd33f9b2..f98398a3 100644 --- a/man/man8/tc.8 +++ b/man/man8/tc.8 @@ -755,8 +755,17 @@ option was specified. Classes can be filtered only by option. .TP -.BR "\ -color" -Use color output. +.BR \-c [ color ][ = { always | auto | never } +Configure color output. If parameter is omitted or +.BR always , +color output is enabled regardless of stdout state. If parameter is +.BR auto , +stdout is checked to be a terminal before enabling color output. If parameter is +.BR never , +color output is disabled. If specified multiple times, the last one takes +precedence. This flag is ignored if +.B \-json +is also given. .TP .BR "\-j", " \-json" diff --git a/misc/ss.c b/misc/ss.c index 41e7762b..f99b6874 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -976,6 +977,7 @@ static int buf_update(int len) } /* Append content to buffer as part of the current field */ +__attribute__((format(printf, 1, 2))) static void out(const char *fmt, ...) { struct column *f = current_field; @@ -1093,7 +1095,7 @@ static void print_header(void) { while (!field_is_last(current_field)) { if (!current_field->disabled) - out(current_field->header); + out("%s", current_field->header); field_next(); } } @@ -3604,6 +3606,21 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh, out(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>'); } + if (tb[UNIX_DIAG_VFS]) { + struct unix_diag_vfs *uv = RTA_DATA(tb[UNIX_DIAG_VFS]); + + out(" ino:%u dev:%u/%u", uv->udiag_vfs_ino, major(uv->udiag_vfs_dev), + minor(uv->udiag_vfs_dev)); + } + if (tb[UNIX_DIAG_ICONS]) { + int len = RTA_PAYLOAD(tb[UNIX_DIAG_ICONS]); + __u32 *peers = RTA_DATA(tb[UNIX_DIAG_ICONS]); + int i; + + out(" peers:"); + for (i = 0; i < len / sizeof(__u32); i++) + out(" %u", peers[i]); + } } return 0; @@ -3641,6 +3658,8 @@ static int unix_show_netlink(struct filter *f) req.r.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UDIAG_SHOW_RQLEN; if (show_mem) req.r.udiag_show |= UDIAG_SHOW_MEMINFO; + if (show_details) + req.r.udiag_show |= UDIAG_SHOW_VFS | UDIAG_SHOW_ICONS; return handle_netlink_request(f, &req.nlh, sizeof(req), unix_show_sock); } diff --git a/tc/m_ematch.c b/tc/m_ematch.c index ace4b3dd..a524b520 100644 --- a/tc/m_ematch.c +++ b/tc/m_ematch.c @@ -277,6 +277,7 @@ static int flatten_tree(struct ematch *head, struct ematch *tree) return count; } +__attribute__((format(printf, 5, 6))) int em_parse_error(int err, struct bstr *args, struct bstr *carg, struct ematch_util *e, char *fmt, ...) { diff --git a/tc/m_ematch.h b/tc/m_ematch.h index f634f191..356f2ede 100644 --- a/tc/m_ematch.h +++ b/tc/m_ematch.h @@ -12,17 +12,16 @@ #define EMATCHKINDSIZ 16 -struct bstr -{ +struct bstr { char *data; unsigned int len; int quoted; struct bstr *next; }; -extern struct bstr * bstr_alloc(const char *text); +struct bstr *bstr_alloc(const char *text); -static inline struct bstr * bstr_new(char *data, unsigned int len) +static inline struct bstr *bstr_new(char *data, unsigned int len) { struct bstr *b = calloc(1, sizeof(*b)); @@ -35,7 +34,7 @@ static inline struct bstr * bstr_new(char *data, unsigned int len) return b; } -static inline int bstrcmp(struct bstr *b, const char *text) +static inline int bstrcmp(const struct bstr *b, const char *text) { int len = strlen(text); int d = b->len - len; @@ -51,12 +50,10 @@ static inline struct bstr *bstr_next(struct bstr *b) return b->next; } -extern unsigned long bstrtoul(const struct bstr *b); -extern void bstr_print(FILE *fd, const struct bstr *b, int ascii); +unsigned long bstrtoul(const struct bstr *b); +void bstr_print(FILE *fd, const struct bstr *b, int ascii); - -struct ematch -{ +struct ematch { struct bstr *args; int index; int inverted; @@ -66,7 +63,7 @@ struct ematch struct ematch *next; }; -static inline struct ematch * new_ematch(struct bstr *args, int inverted) +static inline struct ematch *new_ematch(struct bstr *args, int inverted) { struct ematch *e = calloc(1, sizeof(*e)); @@ -79,14 +76,12 @@ static inline struct ematch * new_ematch(struct bstr *args, int inverted) return e; } -extern void print_ematch_tree(const struct ematch *tree); +void print_ematch_tree(const struct ematch *tree); - -struct ematch_util -{ +struct ematch_util { char kind[EMATCHKINDSIZ]; int kind_num; - int (*parse_eopt)(struct nlmsghdr *,struct tcf_ematch_hdr *, + int (*parse_eopt)(struct nlmsghdr *, struct tcf_ematch_hdr *, struct bstr *); int (*parse_eopt_argv)(struct nlmsghdr *, struct tcf_ematch_hdr *, int, char **); @@ -95,7 +90,7 @@ struct ematch_util struct ematch_util *next; }; -static inline int parse_layer(struct bstr *b) +static inline int parse_layer(const struct bstr *b) { if (*((char *) b->data) == 'l') return TCF_LAYER_LINK; @@ -107,9 +102,10 @@ static inline int parse_layer(struct bstr *b) return INT_MAX; } -extern int em_parse_error(int err, struct bstr *args, struct bstr *carg, +__attribute__((format(printf, 5, 6))) +int em_parse_error(int err, struct bstr *args, struct bstr *carg, struct ematch_util *, char *fmt, ...); -extern int print_ematch(FILE *, const struct rtattr *); -extern int parse_ematch(int *, char ***, int, struct nlmsghdr *); +int print_ematch(FILE *, const struct rtattr *); +int parse_ematch(int *, char ***, int, struct nlmsghdr *); #endif diff --git a/tc/m_pedit.h b/tc/m_pedit.h index a8b06958..b6b274bd 100644 --- a/tc/m_pedit.h +++ b/tc/m_pedit.h @@ -71,23 +71,22 @@ struct m_pedit_util { struct m_pedit_key *tkey); }; -extern int pack_key(struct m_pedit_sel *sel, struct m_pedit_key *tkey); -extern int pack_key32(__u32 retain, struct m_pedit_sel *sel, - struct m_pedit_key *tkey); -extern int pack_key16(__u32 retain, struct m_pedit_sel *sel, - struct m_pedit_key *tkey); -extern int pack_key8(__u32 retain, struct m_pedit_sel *sel, +int pack_key(struct m_pedit_sel *sel, struct m_pedit_key *tkey); +int pack_key32(__u32 retain, struct m_pedit_sel *sel, + struct m_pedit_key *tkey); +int pack_key16(__u32 retain, struct m_pedit_sel *sel, + struct m_pedit_key *tkey); +int pack_key8(__u32 retain, struct m_pedit_sel *sel, struct m_pedit_key *tkey); -extern int parse_val(int *argc_p, char ***argv_p, __u32 *val, int type); -extern int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, - __u32 retain, - struct m_pedit_sel *sel, struct m_pedit_key *tkey); -extern int parse_offset(int *argc_p, char ***argv_p, - struct m_pedit_sel *sel, struct m_pedit_key *tkey); +int 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 m_pedit_sel *sel, struct m_pedit_key *tkey); +int parse_offset(int *argc_p, char ***argv_p, + struct m_pedit_sel *sel, struct m_pedit_key *tkey); int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n); -extern int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg); -extern int pedit_print_xstats(struct action_util *au, FILE *f, - struct rtattr *xstats); - +int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg); +int pedit_print_xstats(struct action_util *au, FILE *f, + struct rtattr *xstats); #endif diff --git a/tc/q_htb.c b/tc/q_htb.c index b93d31d4..c8b2941d 100644 --- a/tc/q_htb.c +++ b/tc/q_htb.c @@ -109,7 +109,6 @@ static int htb_parse_opt(struct qdisc_util *qu, int argc, static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) { - int ok = 0; struct tc_htb_opt opt = {}; __u32 rtab[256], ctab[256]; unsigned buffer = 0, cbuffer = 0; @@ -127,7 +126,6 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str if (get_u32(&opt.prio, *argv, 10)) { explain1("prio"); return -1; } - ok++; } else if (matches(*argv, "mtu") == 0) { NEXT_ARG(); if (get_u32(&mtu, *argv, 10)) { @@ -161,7 +159,6 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str explain1("buffer"); return -1; } - ok++; } else if (matches(*argv, "cburst") == 0 || strcmp(*argv, "cbuffer") == 0 || strcmp(*argv, "cmaxburst") == 0) { @@ -170,7 +167,6 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str explain1("cbuffer"); return -1; } - ok++; } else if (strcmp(*argv, "ceil") == 0) { NEXT_ARG(); if (ceil64) { @@ -186,7 +182,6 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str explain1("ceil"); return -1; } - ok++; } else if (strcmp(*argv, "rate") == 0) { NEXT_ARG(); if (rate64) { @@ -202,7 +197,6 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str explain1("rate"); return -1; } - ok++; } else if (strcmp(*argv, "help") == 0) { explain(); return -1; @@ -214,9 +208,6 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str argc--; argv++; } - /* if (!ok) - return 0;*/ - if (!rate64) { fprintf(stderr, "\"rate\" is required.\n"); return -1; diff --git a/tc/tc.c b/tc/tc.c index 4c7a128c..4b28e9b1 100644 --- a/tc/tc.c +++ b/tc/tc.c @@ -496,8 +496,7 @@ int main(int argc, char **argv) matches(argv[1], "-conf") == 0) { NEXT_ARG(); conf_file = argv[1]; - } else if (matches(argv[1], "-color") == 0) { - ++color; + } else if (matches_color(argv[1], &color)) { } else if (matches(argv[1], "-timestamp") == 0) { timestamp++; } else if (matches(argv[1], "-tshort") == 0) { diff --git a/tc/tc_common.h b/tc/tc_common.h index 272d1727..371ca7d0 100644 --- a/tc/tc_common.h +++ b/tc/tc_common.h @@ -5,26 +5,26 @@ extern struct rtnl_handle rth; -extern int do_qdisc(int argc, char **argv); -extern int do_class(int argc, char **argv); -extern int do_filter(int argc, char **argv, void *buf, size_t buflen); -extern int do_chain(int argc, char **argv, void *buf, size_t buflen); -extern int do_action(int argc, char **argv, void *buf, size_t buflen); -extern int do_tcmonitor(int argc, char **argv); -extern int do_exec(int argc, char **argv); +int do_qdisc(int argc, char **argv); +int do_class(int argc, char **argv); +int do_filter(int argc, char **argv, void *buf, size_t buflen); +int do_chain(int argc, char **argv, void *buf, size_t buflen); +int do_action(int argc, char **argv, void *buf, size_t buflen); +int do_tcmonitor(int argc, char **argv); +int do_exec(int argc, char **argv); -extern int print_action(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); -extern int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); -extern int print_qdisc(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); -extern int print_class(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); -extern void print_size_table(FILE *fp, const char *prefix, struct rtattr *rta); +int print_action(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); +int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); +int print_qdisc(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); +int print_class(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); +void print_size_table(FILE *fp, const char *prefix, struct rtattr *rta); struct tc_estimator; -extern int parse_estimator(int *p_argc, char ***p_argv, struct tc_estimator *est); +int parse_estimator(int *p_argc, char ***p_argv, struct tc_estimator *est); struct tc_sizespec; -extern int parse_size_table(int *p_argc, char ***p_argv, struct tc_sizespec *s); -extern int check_size_table_opts(struct tc_sizespec *s); +int parse_size_table(int *p_argc, char ***p_argv, struct tc_sizespec *s); +int check_size_table_opts(struct tc_sizespec *s); extern int show_graph; extern bool use_names; diff --git a/tc/tc_red.h b/tc/tc_red.h index 88fba58b..6c6e6b03 100644 --- a/tc/tc_red.h +++ b/tc/tc_red.h @@ -2,8 +2,9 @@ #ifndef _TC_RED_H_ #define _TC_RED_H_ 1 -extern int tc_red_eval_P(unsigned qmin, unsigned qmax, double prob); -extern int tc_red_eval_ewma(unsigned qmin, unsigned burst, unsigned avpkt); -extern int tc_red_eval_idle_damping(int wlog, unsigned avpkt, unsigned bandwidth, __u8 *sbuf); +int tc_red_eval_P(unsigned qmin, unsigned qmax, double prob); +int tc_red_eval_ewma(unsigned qmin, unsigned burst, unsigned avpkt); +int tc_red_eval_idle_damping(int wlog, unsigned avpkt, unsigned bandwidth, + __u8 *sbuf); #endif diff --git a/testsuite/Makefile b/testsuite/Makefile index 8fcbc557..d1ac997d 100644 --- a/testsuite/Makefile +++ b/testsuite/Makefile @@ -14,15 +14,13 @@ TESTS_DIR := $(dir $(TESTS)) IPVERS := $(filter-out iproute2/Makefile,$(wildcard iproute2/*)) +KENVFN := $(shell mktemp /tmp/tc_testkenv.XXXXXX) ifneq (,$(wildcard /proc/config.gz)) - KENV := $(shell cat /proc/config.gz | gunzip | grep ^CONFIG) + KCPATH := /proc/config.gz else KVER := $(shell uname -r) KCPATHS := /lib/modules/$(KVER)/config /boot/config-$(KVER) KCPATH := $(firstword $(wildcard $(KCPATHS))) -ifneq (,$(KCPATH)) - KENV := $(shell cat ${KCPATH} | grep ^CONFIG) -endif endif .PHONY: compile listtests alltests configure $(TESTS) @@ -32,6 +30,7 @@ configure: compile: configure echo "Entering iproute2" && cd iproute2 && $(MAKE) && cd ..; + $(MAKE) -C tools listtests: @for t in $(TESTS); do \ @@ -43,6 +42,9 @@ alltests: $(TESTS) clean: @echo "Removing $(RESULTS_DIR) dir ..." @rm -rf $(RESULTS_DIR) + @rm -f iproute2/iproute2-this + @rm -f tests/ip/link/dev_wo_vf_rate.nl + $(MAKE) -C tools clean distclean: clean echo "Entering iproute2" && cd iproute2 && $(MAKE) distclean && cd ..; @@ -59,14 +61,22 @@ endif mkdir -p $(RESULTS_DIR)/$$d; \ done + @if [ "$(KCPATH)" = "/proc/config.gz" ]; then \ + gunzip -c $(KCPATH) >$(KENVFN); \ + elif [ "$(KCPATH)" != "" ]; then \ + cat $(KCPATH) >$(KENVFN); \ + fi + @sed -i -e 's/^CONFIG_/export CONFIG_/' $(KENVFN) + @for i in $(IPVERS); do \ o=`echo $$i | sed -e 's/iproute2\///'`; \ echo -n "Running $@ [$$o/`uname -r`]: "; \ TMP_ERR=`mktemp /tmp/tc_testsuite.XXXXXX`; \ TMP_OUT=`mktemp /tmp/tc_testsuite.XXXXXX`; \ + . $(KENVFN); \ STD_ERR="$$TMP_ERR" STD_OUT="$$TMP_OUT" \ TC="$$i/tc/tc" IP="$$i/ip/ip" SS=$$i/misc/ss DEV="$(DEV)" IPVER="$@" SNAME="$$i" \ - ERRF="$(RESULTS_DIR)/$@.$$o.err" $(KENV) $(PREFIX) tests/$@ > $(RESULTS_DIR)/$@.$$o.out; \ + ERRF="$(RESULTS_DIR)/$@.$$o.err" $(PREFIX) tests/$@ > $(RESULTS_DIR)/$@.$$o.out; \ if [ "$$?" = "127" ]; then \ echo "SKIPPED"; \ elif [ -e "$(RESULTS_DIR)/$@.$$o.err" ]; then \ @@ -75,5 +85,5 @@ endif echo "PASS"; \ fi; \ rm "$$TMP_ERR" "$$TMP_OUT"; \ - dmesg > $(RESULTS_DIR)/$@.$$o.dmesg; \ + sudo dmesg > $(RESULTS_DIR)/$@.$$o.dmesg; \ done diff --git a/testsuite/tools/Makefile b/testsuite/tools/Makefile index f2cdc980..c936af71 100644 --- a/testsuite/tools/Makefile +++ b/testsuite/tools/Makefile @@ -1,3 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 +include ../../config.mk + generate_nlmsg: generate_nlmsg.c ../../lib/libnetlink.c - $(CC) -o $@ $^ + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDLIBS) $(EXTRA_CFLAGS) -I../../include -include../../include/uapi/linux/netlink.h -o $@ $^ + +clean: + rm -f generate_nlmsg