From 15322f46c3427a7d065b41fc5b0e513755329295 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 16 Dec 2019 15:43:37 +0900 Subject: [PATCH 01/23] json_print: Remove declaration without implementation Fixes: 6377572f0aa8 ("ip: ip_print: add new API to print JSON or regular format output") Signed-off-by: Benjamin Poirier Signed-off-by: Stephen Hemminger --- include/json_print.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/json_print.h b/include/json_print.h index fe92d14c..6695654f 100644 --- a/include/json_print.h +++ b/include/json_print.h @@ -34,8 +34,6 @@ void delete_json_obj(void); bool is_json_context(void); -void fflush_fp(void); - void open_json_object(const char *str); void close_json_object(void); void open_json_array(enum output_type type, const char *delim); From d88a6a98e86da9446487ecc4f1fea435323ef21d Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 16 Dec 2019 15:43:38 +0900 Subject: [PATCH 02/23] testsuite: Fix line count test a substring match is not enough, ex: 10 != 1 Fixes: 30383b074de1 ("tests: Add output testing") Signed-off-by: Benjamin Poirier Signed-off-by: Stephen Hemminger --- testsuite/lib/generic.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testsuite/lib/generic.sh b/testsuite/lib/generic.sh index f92260fc..e909008a 100644 --- a/testsuite/lib/generic.sh +++ b/testsuite/lib/generic.sh @@ -121,7 +121,7 @@ test_on_not() test_lines_count() { echo -n "test on lines count ($1): " - if cat "$STD_OUT" | wc -l | grep -q "$1" + if [ $(cat "$STD_OUT" | wc -l) -eq "$1" ] then pr_success else From 43b0b6ec840c27bd9b8d014f338d0235cb2618a0 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 16 Dec 2019 15:43:39 +0900 Subject: [PATCH 03/23] bridge: Fix typo in error messages Fixes: 9eff0e5cc447 ("bridge: Add vlan configuration support") Fixes: 7abf5de677e3 ("bridge: vlan: add support to display per-vlan statistics") Signed-off-by: Benjamin Poirier Signed-off-by: Stephen Hemminger --- bridge/vlan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bridge/vlan.c b/bridge/vlan.c index 6d33b0a9..6dc694b6 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -576,7 +576,7 @@ static int vlan_show(int argc, char **argv) (compress_vlans ? RTEXT_FILTER_BRVLAN_COMPRESSED : RTEXT_FILTER_BRVLAN)) < 0) { - perror("Cannont send dump request"); + perror("Cannot send dump request"); exit(1); } @@ -601,7 +601,7 @@ static int vlan_show(int argc, char **argv) filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS); if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask) < 0) { - perror("Cannont send dump request"); + perror("Cannot send dump request"); exit(1); } @@ -615,7 +615,7 @@ static int vlan_show(int argc, char **argv) filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS_SLAVE); if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask) < 0) { - perror("Cannont send slave dump request"); + perror("Cannot send slave dump request"); exit(1); } From df1262155c4b3102e6d01ec082ad123377248019 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 16 Dec 2019 15:43:40 +0900 Subject: [PATCH 04/23] bridge: Fix src_vni argument in man page "SRC VNI" is only one argument and should appear as such. Moreover, this argument to the src_vni option is documented under three forms: "SRC_VNI", "SRC VNI" and "VNI" in different places. Consistenly use the simplest form, "VNI". Fixes: c5b176e5ba1f ("bridge: fdb: add support for src_vni option") Signed-off-by: Benjamin Poirier Signed-off-by: Stephen Hemminger --- man/man8/bridge.8 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index 10f6cf0e..1804f0b4 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -71,7 +71,7 @@ bridge \- show / manipulate bridge addresses and devices .B dst .IR IPADDR " ] [ " .B src_vni -.IR SRC_VNI " ] [" +.IR VNI " ] [" .B vni .IR VNI " ] [" .B port @@ -498,7 +498,7 @@ the IP address of the destination VXLAN tunnel endpoint where the Ethernet MAC ADDRESS resides. .TP -.BI src_vni " SRC VNI" +.BI src_vni " VNI" the src VNI Network Identifier (or VXLAN Segment ID) this entry belongs to. Used only when the vxlan device is in external or collect metadata mode. If omitted the value specified at From 1f53ba7297a8b8189fd6853c480de2f6bf9ac787 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 16 Dec 2019 15:43:41 +0900 Subject: [PATCH 05/23] bridge: Fix BRIDGE_VLAN_TUNNEL attribute sizes As per the kernel's vlan_tunnel_policy, IFLA_BRIDGE_VLAN_TUNNEL_VID and IFLA_BRIDGE_VLAN_TUNNEL_FLAGS have type NLA_U16. Fixes: 8652eeb3ab12 ("bridge: vlan: support for per vlan tunnel info") Signed-off-by: Benjamin Poirier Signed-off-by: Stephen Hemminger --- bridge/vlan.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bridge/vlan.c b/bridge/vlan.c index 6dc694b6..c0294aa6 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -71,8 +71,8 @@ static int add_tunnel_info(struct nlmsghdr *n, int reqsize, tinfo = addattr_nest(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_INFO); addattr32(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_ID, tun_id); - addattr32(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_VID, vid); - addattr32(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, flags); + addattr16(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_VID, vid); + addattr16(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, flags); addattr_nest_end(n, tinfo); @@ -304,7 +304,7 @@ static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex) if (ttb[IFLA_BRIDGE_VLAN_TUNNEL_VID]) tunnel_vid = - rta_getattr_u32(ttb[IFLA_BRIDGE_VLAN_TUNNEL_VID]); + rta_getattr_u16(ttb[IFLA_BRIDGE_VLAN_TUNNEL_VID]); else continue; @@ -314,7 +314,7 @@ static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex) if (ttb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]) tunnel_flags = - rta_getattr_u32(ttb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]); + rta_getattr_u16(ttb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]); if (!(tunnel_flags & BRIDGE_VLAN_INFO_RANGE_END)) { last_vid_start = tunnel_vid; From dfa13e2273b206419ec0199a11c92122f2e8ea33 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 16 Dec 2019 15:43:42 +0900 Subject: [PATCH 06/23] bridge: Fix vni printing Since commit c7c1a1ef51ae ("bridge: colorize output and use JSON print library"), print_range() is used for vid (16bits) and vni. However, the latter are 32bits so they get truncated. They got truncated even before that commit though. Fixes: 8652eeb3ab12 ("bridge: vlan: support for per vlan tunnel info") Signed-off-by: Benjamin Poirier Signed-off-by: Stephen Hemminger --- bridge/vlan.c | 6 +++--- testsuite/Makefile | 3 ++- testsuite/lib/generic.sh | 6 +++++- testsuite/tests/bridge/vlan/tunnelshow.t | 24 ++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 5 deletions(-) create mode 100755 testsuite/tests/bridge/vlan/tunnelshow.t diff --git a/bridge/vlan.c b/bridge/vlan.c index c0294aa6..428eeee3 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -266,15 +266,15 @@ static void close_vlan_port(void) close_json_object(); } -static void print_range(const char *name, __u16 start, __u16 id) +static void print_range(const char *name, __u32 start, __u32 id) { char end[64]; snprintf(end, sizeof(end), "%sEnd", name); - print_hu(PRINT_ANY, name, "\t %hu", start); + print_uint(PRINT_ANY, name, "\t %u", start); if (start != id) - print_hu(PRINT_ANY, end, "-%hu", id); + print_uint(PRINT_ANY, end, "-%u", id); } diff --git a/testsuite/Makefile b/testsuite/Makefile index 4451f316..fb50f618 100644 --- a/testsuite/Makefile +++ b/testsuite/Makefile @@ -82,7 +82,8 @@ endif 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" \ + TC="$$i/tc/tc" IP="$$i/ip/ip" SS=$$i/misc/ss BRIDGE="$$i/bridge/bridge" \ + DEV="$(DEV)" IPVER="$@" SNAME="$$i" \ ERRF="$(RESULTS_DIR)/$@.$$o.err" $(PREFIX) tests/$@ > $(RESULTS_DIR)/$@.$$o.out; \ if [ "$$?" = "127" ]; then \ printf "\033[1;35mSKIPPED\033[0m\n"; \ diff --git a/testsuite/lib/generic.sh b/testsuite/lib/generic.sh index e909008a..8b339ec1 100644 --- a/testsuite/lib/generic.sh +++ b/testsuite/lib/generic.sh @@ -1,4 +1,3 @@ - export DEST="127.0.0.1" ts_log() @@ -66,6 +65,11 @@ ts_ss() __ts_cmd "$SS" "$@" } +ts_bridge() +{ + __ts_cmd "$BRIDGE" "$@" +} + ts_qdisc_available() { HELPOUT=`$TC qdisc add $1 help 2>&1` diff --git a/testsuite/tests/bridge/vlan/tunnelshow.t b/testsuite/tests/bridge/vlan/tunnelshow.t new file mode 100755 index 00000000..1583abb9 --- /dev/null +++ b/testsuite/tests/bridge/vlan/tunnelshow.t @@ -0,0 +1,24 @@ +#!/bin/sh + +. lib/generic.sh + +ts_log "[Testing tunnelshow]" + +BR_DEV="$(rand_dev)" +VX_DEV="$(rand_dev)" + +ts_ip "$0" "Add $BR_DEV bridge interface" link add $BR_DEV type bridge + +ts_ip "$0" "Add $VX_DEV vxlan interface" \ + link add $VX_DEV type vxlan dstport 4789 external +ts_ip "$0" "Enslave $VX_DEV under $BR_DEV" \ + link set dev $VX_DEV master $BR_DEV +ts_ip "$0" "Set vlan_tunnel on $VX_DEV" \ + link set dev $VX_DEV type bridge_slave vlan_tunnel on + +ts_bridge "$0" "Add single vlan" vlan add dev $VX_DEV vid 1030 +ts_bridge "$0" "Add tunnel with vni > 16k" \ + vlan add dev $VX_DEV vid 1030 tunnel_info id 65556 + +ts_bridge "$0" "Show tunnel info" vlan tunnelshow dev $VX_DEV +test_on "1030\s+65556" From 955a20be027d2ff47b0c6fab3353c85cee614b90 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 16 Dec 2019 15:43:43 +0900 Subject: [PATCH 07/23] bridge: Deduplicate vlan show functions print_vlan() and print_vlan_tunnel() are almost identical copies, save for a missing newline in the latter which leads to broken output of "vlan tunnelshow" in normal mode. Fixes: c7c1a1ef51ae ("bridge: colorize output and use JSON print library") Signed-off-by: Benjamin Poirier Signed-off-by: Stephen Hemminger --- bridge/vlan.c | 91 +++++++----------------- testsuite/tests/bridge/vlan/tunnelshow.t | 7 ++ 2 files changed, 34 insertions(+), 64 deletions(-) diff --git a/bridge/vlan.c b/bridge/vlan.c index 428eeee3..19283bca 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -16,7 +16,11 @@ #include "utils.h" static unsigned int filter_index, filter_vlan; -static int show_vlan_tunnel_info = 0; + +enum vlan_show_subject { + VLAN_SHOW_VLAN, + VLAN_SHOW_TUNNELINFO, +}; static void usage(void) { @@ -278,7 +282,7 @@ static void print_range(const char *name, __u32 start, __u32 id) } -static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex) +static void print_vlan_tunnel_info(struct rtattr *tb, int ifindex) { struct rtattr *i, *list = tb; int rem = RTA_PAYLOAD(list); @@ -347,52 +351,9 @@ static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex) close_vlan_port(); } -static int print_vlan_tunnel(struct nlmsghdr *n, void *arg) -{ - struct ifinfomsg *ifm = NLMSG_DATA(n); - struct rtattr *tb[IFLA_MAX+1]; - int len = n->nlmsg_len; - FILE *fp = arg; - - if (n->nlmsg_type != RTM_NEWLINK) { - fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n", - n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); - return 0; - } - - len -= NLMSG_LENGTH(sizeof(*ifm)); - if (len < 0) { - fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); - return -1; - } - - if (ifm->ifi_family != AF_BRIDGE) - return 0; - - if (filter_index && filter_index != ifm->ifi_index) - return 0; - - parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len); - - /* if AF_SPEC isn't there, vlan table is not preset for this port */ - if (!tb[IFLA_AF_SPEC]) { - if (!filter_vlan && !is_json_context()) { - color_fprintf(fp, COLOR_IFNAME, "%s", - ll_index_to_name(ifm->ifi_index)); - fprintf(fp, "\tNone\n"); - } - return 0; - } - - print_vlan_tunnel_info(fp, tb[IFLA_AF_SPEC], ifm->ifi_index); - - fflush(fp); - return 0; -} - static int print_vlan(struct nlmsghdr *n, void *arg) { - FILE *fp = arg; + enum vlan_show_subject *subject = arg; struct ifinfomsg *ifm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[IFLA_MAX+1]; @@ -420,17 +381,24 @@ static int print_vlan(struct nlmsghdr *n, void *arg) /* if AF_SPEC isn't there, vlan table is not preset for this port */ if (!tb[IFLA_AF_SPEC]) { if (!filter_vlan && !is_json_context()) { - color_fprintf(fp, COLOR_IFNAME, "%s", + color_fprintf(stdout, COLOR_IFNAME, "%s", ll_index_to_name(ifm->ifi_index)); - fprintf(fp, "\tNone\n"); + fprintf(stdout, "\tNone\n"); } return 0; } - print_vlan_info(tb[IFLA_AF_SPEC], ifm->ifi_index); + switch (*subject) { + case VLAN_SHOW_VLAN: + print_vlan_info(tb[IFLA_AF_SPEC], ifm->ifi_index); + break; + case VLAN_SHOW_TUNNELINFO: + print_vlan_tunnel_info(tb[IFLA_AF_SPEC], ifm->ifi_index); + break; + } print_string(PRINT_FP, NULL, "%s", _SL_); - fflush(fp); + fflush(stdout); return 0; } @@ -543,7 +511,7 @@ static int print_vlan_stats(struct nlmsghdr *n, void *arg) return 0; } -static int vlan_show(int argc, char **argv) +static int vlan_show(int argc, char **argv, int subject) { char *filter_dev = NULL; int ret = 0; @@ -581,17 +549,13 @@ static int vlan_show(int argc, char **argv) } if (!is_json_context()) { - if (show_vlan_tunnel_info) - printf("port\tvlan ids\ttunnel id\n"); - else - printf("port\tvlan ids\n"); + printf("port\tvlan ids"); + if (subject == VLAN_SHOW_TUNNELINFO) + printf("\ttunnel id"); + printf("\n"); } - if (show_vlan_tunnel_info) - ret = rtnl_dump_filter(&rth, print_vlan_tunnel, - stdout); - else - ret = rtnl_dump_filter(&rth, print_vlan, stdout); + ret = rtnl_dump_filter(&rth, print_vlan, &subject); if (ret < 0) { fprintf(stderr, "Dump ternminated\n"); exit(1); @@ -677,15 +641,14 @@ int do_vlan(int argc, char **argv) if (matches(*argv, "show") == 0 || matches(*argv, "lst") == 0 || matches(*argv, "list") == 0) - return vlan_show(argc-1, argv+1); + return vlan_show(argc-1, argv+1, VLAN_SHOW_VLAN); if (matches(*argv, "tunnelshow") == 0) { - show_vlan_tunnel_info = 1; - return vlan_show(argc-1, argv+1); + return vlan_show(argc-1, argv+1, VLAN_SHOW_TUNNELINFO); } if (matches(*argv, "help") == 0) usage(); } else { - return vlan_show(0, NULL); + return vlan_show(0, NULL, VLAN_SHOW_VLAN); } fprintf(stderr, "Command \"%s\" is unknown, try \"bridge vlan help\".\n", *argv); diff --git a/testsuite/tests/bridge/vlan/tunnelshow.t b/testsuite/tests/bridge/vlan/tunnelshow.t index 1583abb9..b2141e7c 100755 --- a/testsuite/tests/bridge/vlan/tunnelshow.t +++ b/testsuite/tests/bridge/vlan/tunnelshow.t @@ -16,9 +16,16 @@ ts_ip "$0" "Enslave $VX_DEV under $BR_DEV" \ ts_ip "$0" "Set vlan_tunnel on $VX_DEV" \ link set dev $VX_DEV type bridge_slave vlan_tunnel on +ts_bridge "$0" "Add single vlan" vlan add dev $VX_DEV vid 1000 +ts_bridge "$0" "Add single tunnel" \ + vlan add dev $VX_DEV vid 1000 tunnel_info id 1000 +ts_bridge "$0" "Add vlan range" vlan add dev $VX_DEV vid 1010-1020 +ts_bridge "$0" "Add tunnel range" \ + vlan add dev $VX_DEV vid 1010-1020 tunnel_info id 1010-1020 ts_bridge "$0" "Add single vlan" vlan add dev $VX_DEV vid 1030 ts_bridge "$0" "Add tunnel with vni > 16k" \ vlan add dev $VX_DEV vid 1030 tunnel_info id 65556 ts_bridge "$0" "Show tunnel info" vlan tunnelshow dev $VX_DEV test_on "1030\s+65556" +test_lines_count 5 From 1a500c78aef0d4fd33c1700dbfcf435ea2c53847 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Mon, 16 Dec 2019 15:43:44 +0900 Subject: [PATCH 08/23] bridge: Fix tunnelshow json output repeats for "vlan tunnelshow" what commit 0f36267485e3 ("bridge: fix vlan show formatting") did for "vlan show". This fixes problems in json output. Note that the resulting json output format of "vlan tunnelshow" is not the same as the original, introduced in commit 8652eeb3ab12 ("bridge: vlan: support for per vlan tunnel info"). Changes similar to the ones done for "vlan show" in commit 0f36267485e3 ("bridge: fix vlan show formatting") are carried over to "vlan tunnelshow". Fixes: c7c1a1ef51ae ("bridge: colorize output and use JSON print library") Fixes: 0f36267485e3 ("bridge: fix vlan show formatting") Signed-off-by: Benjamin Poirier Signed-off-by: Stephen Hemminger --- bridge/vlan.c | 27 +++++++----------------- testsuite/tests/bridge/vlan/tunnelshow.t | 2 ++ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/bridge/vlan.c b/bridge/vlan.c index 19283bca..205851e4 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -256,12 +256,14 @@ static int filter_vlan_check(__u16 vid, __u16 flags) return 1; } -static void open_vlan_port(int ifi_index, const char *fmt) +static void open_vlan_port(int ifi_index, const char *fmt, + enum vlan_show_subject subject) { open_json_object(NULL); print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname", fmt, ll_index_to_name(ifi_index)); - open_json_array(PRINT_JSON, "vlans"); + open_json_array(PRINT_JSON, + subject == VLAN_SHOW_VLAN ? "vlans": "tunnels"); } static void close_vlan_port(void) @@ -289,10 +291,8 @@ static void print_vlan_tunnel_info(struct rtattr *tb, int ifindex) __u16 last_vid_start = 0; __u32 last_tunid_start = 0; - if (!filter_vlan) - open_vlan_port(ifindex, "%s"); + open_vlan_port(ifindex, "%s", VLAN_SHOW_TUNNELINFO); - open_json_array(PRINT_JSON, "tunnel"); for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { struct rtattr *ttb[IFLA_BRIDGE_VLAN_TUNNEL_MAX+1]; __u32 tunnel_id = 0; @@ -331,24 +331,13 @@ static void print_vlan_tunnel_info(struct rtattr *tb, int ifindex) else if (vcheck_ret == 0) continue; - if (tunnel_flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) - continue; - - if (filter_vlan) - open_vlan_port(ifindex, "%s"); - open_json_object(NULL); print_range("vlan", last_vid_start, tunnel_vid); print_range("tunid", last_tunid_start, tunnel_id); close_json_object(); - print_string(PRINT_FP, NULL, "%s", _SL_); - if (filter_vlan) - close_vlan_port(); } - - if (!filter_vlan) - close_vlan_port(); + close_vlan_port(); } static int print_vlan(struct nlmsghdr *n, void *arg) @@ -467,7 +456,7 @@ static void print_vlan_stats_attr(struct rtattr *attr, int ifindex) /* found vlan stats, first time print the interface name */ if (!found_vlan) { - open_vlan_port(ifindex, "%-16s"); + open_vlan_port(ifindex, "%-16s", VLAN_SHOW_VLAN); found_vlan = true; } else { print_string(PRINT_FP, NULL, "%-16s", ""); @@ -600,7 +589,7 @@ void print_vlan_info(struct rtattr *tb, int ifindex) int rem = RTA_PAYLOAD(list); __u16 last_vid_start = 0; - open_vlan_port(ifindex, "%s"); + open_vlan_port(ifindex, "%s", VLAN_SHOW_VLAN); for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { struct bridge_vlan_info *vinfo; diff --git a/testsuite/tests/bridge/vlan/tunnelshow.t b/testsuite/tests/bridge/vlan/tunnelshow.t index b2141e7c..fd41bfcb 100755 --- a/testsuite/tests/bridge/vlan/tunnelshow.t +++ b/testsuite/tests/bridge/vlan/tunnelshow.t @@ -29,3 +29,5 @@ ts_bridge "$0" "Add tunnel with vni > 16k" \ ts_bridge "$0" "Show tunnel info" vlan tunnelshow dev $VX_DEV test_on "1030\s+65556" test_lines_count 5 + +ts_bridge "$0" "Dump tunnel info" -j vlan tunnelshow dev $VX_DEV From f678a2d08e9793fbd5996d206061b94aa3b8d88a Mon Sep 17 00:00:00 2001 From: Aya Levin Date: Wed, 11 Dec 2019 17:45:34 +0200 Subject: [PATCH 09/23] devlink: Print health reporter's dump time-stamp in a helper function Add pr_out_dump_reporter prefix to the helper function's name and encapsulate the print in it. Fixes: 2f1242efe9d0 ("devlink: Add devlink health show command") Signed-off-by: Aya Levin Acked-by: Jiri Pirko Signed-off-by: Tariq Toukan Signed-off-by: Stephen Hemminger --- devlink/devlink.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index 0b8985f3..aee6c87c 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -6654,8 +6654,11 @@ static const char *health_state_name(uint8_t state) } } -static void format_logtime(uint64_t time_ms, char *ts_date, char *ts_time) +static void pr_out_dump_reporter_format_logtime(struct dl *dl, const struct nlattr *attr) { + char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN]; + char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN]; + uint64_t time_ms = mnl_attr_get_u64(attr); struct sysinfo s_info; struct tm *info; time_t now, sec; @@ -6673,16 +6676,16 @@ static void format_logtime(uint64_t time_ms, char *ts_date, char *ts_time) sec = now - s_info.uptime + time_ms / 1000; info = localtime(&sec); out: - strftime(ts_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", info); - strftime(ts_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", info); + strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", info); + strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", info); + pr_out_str(dl, "last_dump_date", dump_date); + pr_out_str(dl, "last_dump_time", dump_time); } static void pr_out_health(struct dl *dl, struct nlattr **tb_health) { struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; enum devlink_health_reporter_state state; - const struct nlattr *attr; - uint64_t time_ms; int err; err = mnl_attr_parse_nested(tb_health[DEVLINK_ATTR_HEALTH_REPORTER], @@ -6710,17 +6713,8 @@ static void pr_out_health(struct dl *dl, struct nlattr **tb_health) mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT])); pr_out_u64(dl, "recover", mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT])); - if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]) { - char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN]; - char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN]; - - attr = tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]; - time_ms = mnl_attr_get_u64(attr); - format_logtime(time_ms, dump_date, dump_time); - - pr_out_str(dl, "last_dump_date", dump_date); - pr_out_str(dl, "last_dump_time", dump_time); - } + if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]) + pr_out_dump_reporter_format_logtime(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]); if (tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]) pr_out_u64(dl, "grace_period", mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])); From 746b66b005782dc9621f4fc84d0a1859300a6d01 Mon Sep 17 00:00:00 2001 From: Aya Levin Date: Wed, 11 Dec 2019 17:45:35 +0200 Subject: [PATCH 10/23] devlink: Add a new time-stamp format for health reporter's dump Introduce a new attribute representing a new time-stamp format: current time in ns (to comply with y2038) instead of jiffies. If the new attribute was received, translate the time-stamp accordingly (ns). Fixes: 2f1242efe9d0 ("devlink: Add devlink health show command") Signed-off-by: Aya Levin Acked-by: Jiri Pirko Signed-off-by: Tariq Toukan Signed-off-by: Stephen Hemminger --- devlink/devlink.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index aee6c87c..f0181e41 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -6682,6 +6682,25 @@ out: pr_out_str(dl, "last_dump_time", dump_time); } +static void pr_out_dump_report_timestamp(struct dl *dl, const struct nlattr *attr) +{ + char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN]; + char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN]; + time_t tv_sec; + struct tm *tm; + uint64_t ts; + + ts = mnl_attr_get_u64(attr); + tv_sec = ts / 1000000000; + tm = localtime(&tv_sec); + + strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", tm); + strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", tm); + + pr_out_str(dl, "last_dump_date", dump_date); + pr_out_str(dl, "last_dump_time", dump_time); +} + static void pr_out_health(struct dl *dl, struct nlattr **tb_health) { struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; @@ -6713,7 +6732,9 @@ static void pr_out_health(struct dl *dl, struct nlattr **tb_health) mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT])); pr_out_u64(dl, "recover", mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT])); - if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]) + if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS]) + pr_out_dump_report_timestamp(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS]); + else if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]) pr_out_dump_reporter_format_logtime(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]); if (tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]) pr_out_u64(dl, "grace_period", From af646bf95381964187d1128999c3265073609fe3 Mon Sep 17 00:00:00 2001 From: Aya Levin Date: Wed, 11 Dec 2019 17:45:36 +0200 Subject: [PATCH 11/23] devlink: Fix fmsg nesting in non JSON output When an object or an array opening follows a name (label), add a new line and indentation before printing the label. When name (label) is followed by a value, print both at the same line. Prior to this patch nesting was not visible in a non JSON output: JSON: { "Common config": { "SQ": { "stride size": 64, "size": 1024 }, "CQ": { "stride size": 64, "size": 1024 } }, "SQs": [ { "channel ix": 0, "sqn": 10, "HW state": 1, "stopped": false, "cc": 0, "pc": 0, "CQ": { "cqn": 6, "HW status": 0 } },{ "channel ix": 0, "sqn": 14, "HW state": 1, "stopped": false, "cc": 0, "pc": 0, "CQ": { "cqn": 10, "HW status": 0 } } ] } Before this patch: Common Config: SQ: stride size: 64 size: 1024 CQ: stride size: 64 size: 1024 SQs: channel ix: 0 tc: 0 txq ix: 0 sqn: 10 HW state: 1 stopped: false cc: 0 pc: 0 CQ: cqn: 6 HW status: 0 channel ix: 1 tc: 0 txq ix: 1 sqn: 14 HW state: 1 stopped: false cc: 0 pc: 0 CQ: cqn: 10 HW status: 0 With this patch: Common config: SQ: stride size: 64 size: 1024 CQ: stride size: 64 size: 1024 SQs: channel ix: 0 sqn: 10 HW state: 1 stopped: false cc: 0 pc: 0 CQ: cqn: 6 HW status: 0 channel ix: 1 sqn: 14 HW state: 1 stopped: false cc: 0 pc: 0 CQ: cqn: 10 HW status: 0 Fixes: 7b8baf834d5e ("devlink: Add devlink health diagnose command") Signed-off-by: Aya Levin Acked-by: Jiri Pirko Signed-off-by: Tariq Toukan Signed-off-by: Stephen Hemminger --- devlink/devlink.c | 106 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 18 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index f0181e41..95f05a0b 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -6463,12 +6463,23 @@ static int fmsg_value_show(struct dl *dl, int type, struct nlattr *nl_data) return MNL_CB_OK; } +static void pr_out_fmsg_name(struct dl *dl, char **name) +{ + if (!*name) + return; + + pr_out_name(dl, *name); + free(*name); + *name = NULL; +} + struct nest_entry { int attr_type; struct list_head list; }; struct fmsg_cb_data { + char *name; struct dl *dl; uint8_t value_type; struct list_head entry_list; @@ -6498,6 +6509,56 @@ static int cmd_fmsg_nest_queue(struct fmsg_cb_data *fmsg_data, return MNL_CB_OK; } +static void pr_out_fmsg_group_start(struct dl *dl, char **name) +{ + __pr_out_newline(); + pr_out_fmsg_name(dl, name); + __pr_out_newline(); + __pr_out_indent_inc(); +} + +static void pr_out_fmsg_group_end(struct dl *dl) +{ + __pr_out_newline(); + __pr_out_indent_dec(); +} + +static void pr_out_fmsg_start_object(struct dl *dl, char **name) +{ + if (dl->json_output) { + pr_out_fmsg_name(dl, name); + jsonw_start_object(dl->jw); + } else { + pr_out_fmsg_group_start(dl, name); + } +} + +static void pr_out_fmsg_end_object(struct dl *dl) +{ + if (dl->json_output) + jsonw_end_object(dl->jw); + else + pr_out_fmsg_group_end(dl); +} + +static void pr_out_fmsg_start_array(struct dl *dl, char **name) +{ + if (dl->json_output) { + pr_out_fmsg_name(dl, name); + jsonw_start_array(dl->jw); + } else { + pr_out_fmsg_group_start(dl, name); + } +} + +static void pr_out_fmsg_end_array(struct dl *dl) +{ + if (dl->json_output) + jsonw_end_array(dl->jw); + else + pr_out_fmsg_group_end(dl); +} + static int cmd_fmsg_nest(struct fmsg_cb_data *fmsg_data, uint8_t nest_value, bool start) { @@ -6512,26 +6573,17 @@ static int cmd_fmsg_nest(struct fmsg_cb_data *fmsg_data, uint8_t nest_value, switch (value) { case DEVLINK_ATTR_FMSG_OBJ_NEST_START: if (start) - pr_out_entry_start(dl); + pr_out_fmsg_start_object(dl, &fmsg_data->name); else - pr_out_entry_end(dl); + pr_out_fmsg_end_object(dl); break; case DEVLINK_ATTR_FMSG_PAIR_NEST_START: break; case DEVLINK_ATTR_FMSG_ARR_NEST_START: - if (dl->json_output) { - if (start) - jsonw_start_array(dl->jw); - else - jsonw_end_array(dl->jw); - } else { - if (start) { - __pr_out_newline(); - __pr_out_indent_inc(); - } else { - __pr_out_indent_dec(); - } - } + if (start) + pr_out_fmsg_start_array(dl, &fmsg_data->name); + else + pr_out_fmsg_end_array(dl); break; default: return -EINVAL; @@ -6569,12 +6621,16 @@ static int cmd_fmsg_object_cb(const struct nlmsghdr *nlh, void *data) return err; break; case DEVLINK_ATTR_FMSG_OBJ_NAME: - pr_out_name(dl, mnl_attr_get_str(nla_object)); + free(fmsg_data->name); + fmsg_data->name = strdup(mnl_attr_get_str(nla_object)); + if (!fmsg_data->name) + return -ENOMEM; break; case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE: fmsg_data->value_type = mnl_attr_get_u8(nla_object); break; case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA: + pr_out_fmsg_name(dl, &fmsg_data->name); err = fmsg_value_show(dl, fmsg_data->value_type, nla_object); if (err != MNL_CB_OK) @@ -6587,6 +6643,20 @@ static int cmd_fmsg_object_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } +static void cmd_fmsg_init(struct dl *dl, struct fmsg_cb_data *data) +{ + /* FMSG is dynamic: opening of an object or array causes a + * newline. JSON starts with an { or [, but plain text should + * not start with a new line. Ensure this by setting + * g_new_line_count to 1: avoiding newline before the first + * print. + */ + g_new_line_count = 1; + data->name = NULL; + data->dl = dl; + INIT_LIST_HEAD(&data->entry_list); +} + static int cmd_health_object_common(struct dl *dl, uint8_t cmd, uint16_t flags) { struct fmsg_cb_data data; @@ -6600,9 +6670,9 @@ static int cmd_health_object_common(struct dl *dl, uint8_t cmd, uint16_t flags) if (err) return err; - data.dl = dl; - INIT_LIST_HEAD(&data.entry_list); + cmd_fmsg_init(dl, &data); err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_fmsg_object_cb, &data); + free(data.name); return err; } From 2cf4d7af72e308fe40acef5788d1890b6b966035 Mon Sep 17 00:00:00 2001 From: Antony Antony Date: Thu, 19 Dec 2019 15:18:03 +0100 Subject: [PATCH 12/23] ip: xfrm if_id -ve value is error if_id is u32, error on -ve values instead of setting to 0 after : ip link add ipsec1 type xfrm dev lo if_id -10 Error: argument "-10" is wrong: if_id value is invalid before : note xfrm if_id 0 ip link add ipsec1 type xfrm dev lo if_id -10 ip -d link show dev ipsec1 9: ipsec1@lo: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/none 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 1500 xfrm if_id 0 addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 Fixes: 286446c1e8c ("ip: support for xfrm interfaces") Signed-off-by: Antony Antony Signed-off-by: Stephen Hemminger --- ip/link_xfrm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ip/link_xfrm.c b/ip/link_xfrm.c index a28f308d..7dbfb13f 100644 --- a/ip/link_xfrm.c +++ b/ip/link_xfrm.c @@ -37,7 +37,9 @@ static int xfrm_parse_opt(struct link_util *lu, int argc, char **argv, exit(nodev(*argv)); } else if (!matches(*argv, "if_id")) { NEXT_ARG(); - if (!get_u32(&if_id, *argv, 0)) + if (get_u32(&if_id, *argv, 0)) + invarg("if_id value is invalid", *argv); + else addattr32(n, 1024, IFLA_XFRM_IF_ID, if_id); } else { xfrm_print_help(lu, argc, argv, stderr); From 2dda733f6d7b8273a7564f9b2717554df6e95230 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 29 Dec 2019 09:53:09 -0800 Subject: [PATCH 13/23] utils: fix indentation Signed-off-by: Stephen Hemminger --- lib/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils.c b/lib/utils.c index bbb3bdcf..c6f19ce1 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -1451,7 +1451,7 @@ int get_guid(__u64 *guid, const char *arg) if (tmp > 255) return -1; - *guid |= tmp << (56 - 8 * i); + *guid |= tmp << (56 - 8 * i); } return 0; From d8f673074bba4727bfba642e46bfab91462b8d9d Mon Sep 17 00:00:00 2001 From: Leslie Monis Date: Thu, 26 Dec 2019 00:34:09 +0530 Subject: [PATCH 14/23] tc: cbs: add support for JSON output Enable proper JSON output for the CBS Qdisc. Signed-off-by: Leslie Monis Signed-off-by: Stephen Hemminger --- tc/q_cbs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tc/q_cbs.c b/tc/q_cbs.c index 9515a1f7..13bb08e9 100644 --- a/tc/q_cbs.c +++ b/tc/q_cbs.c @@ -125,11 +125,11 @@ static int cbs_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (RTA_PAYLOAD(tb[TCA_CBS_PARMS]) < sizeof(*qopt)) return -1; - fprintf(f, "hicredit %d ", qopt->hicredit); - fprintf(f, "locredit %d ", qopt->locredit); - fprintf(f, "sendslope %d ", qopt->sendslope); - fprintf(f, "idleslope %d ", qopt->idleslope); - fprintf(f, "offload %d ", qopt->offload); + print_int(PRINT_ANY, "hicredit", "hicredit %d ", qopt->hicredit); + print_int(PRINT_ANY, "locredit", "locredit %d ", qopt->locredit); + print_int(PRINT_ANY, "sendslope", "sendslope %d ", qopt->sendslope); + print_int(PRINT_ANY, "idleslope", "idleslope %d ", qopt->idleslope); + print_int(PRINT_ANY, "offload", "offload %d ", qopt->offload); return 0; } From d3136b1e807af74a54279ac96da34028962e5561 Mon Sep 17 00:00:00 2001 From: Leslie Monis Date: Thu, 26 Dec 2019 00:34:10 +0530 Subject: [PATCH 15/23] tc: choke: add support for JSON output Enable proper JSON output for the choke Qdisc. Also, use the long double format specifier to print the value of "probability". Signed-off-by: Leslie Monis Signed-off-by: Stephen Hemminger --- tc/q_choke.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tc/q_choke.c b/tc/q_choke.c index 648d9ad7..570c3599 100644 --- a/tc/q_choke.c +++ b/tc/q_choke.c @@ -186,18 +186,23 @@ static int choke_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) RTA_PAYLOAD(tb[TCA_CHOKE_MAX_P]) >= sizeof(__u32)) max_P = rta_getattr_u32(tb[TCA_CHOKE_MAX_P]); - fprintf(f, "limit %up min %up max %up ", - qopt->limit, qopt->qth_min, qopt->qth_max); + print_uint(PRINT_ANY, "limit", "limit %up ", qopt->limit); + print_uint(PRINT_ANY, "min", "min %up ", qopt->qth_min); + print_uint(PRINT_ANY, "max", "max %up ", qopt->qth_max); tc_red_print_flags(qopt->flags); if (show_details) { - fprintf(f, "ewma %u ", qopt->Wlog); + print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt->Wlog); + if (max_P) - fprintf(f, "probability %g ", max_P / pow(2, 32)); + print_float(PRINT_ANY, "probability", + "probability %lg ", max_P / pow(2, 32)); else - fprintf(f, "Plog %u ", qopt->Plog); - fprintf(f, "Scell_log %u", qopt->Scell_log); + print_uint(PRINT_ANY, "Plog", "Plog %u ", qopt->Plog); + + print_uint(PRINT_ANY, "Scell_log", "Scell_log %u", + qopt->Scell_log); } return 0; } @@ -214,8 +219,13 @@ static int choke_print_xstats(struct qdisc_util *qu, FILE *f, return -1; st = RTA_DATA(xstats); - fprintf(f, " marked %u early %u pdrop %u other %u matched %u", - st->marked, st->early, st->pdrop, st->other, st->matched); + + print_uint(PRINT_ANY, "marked", " marked %u", st->marked); + print_uint(PRINT_ANY, "early", " early %u", st->early); + print_uint(PRINT_ANY, "pdrop", " pdrop %u", st->pdrop); + print_uint(PRINT_ANY, "other", " other %u", st->other); + print_uint(PRINT_ANY, "matched", " matched %u", st->matched); + return 0; } From 90a50a6fa23f0443d52793157aaca9d33beef491 Mon Sep 17 00:00:00 2001 From: Leslie Monis Date: Thu, 26 Dec 2019 00:34:11 +0530 Subject: [PATCH 16/23] tc: codel: add support for JSON output Enable proper JSON output for the CoDel Qdisc. Signed-off-by: Leslie Monis Signed-off-by: Stephen Hemminger --- tc/q_codel.c | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/tc/q_codel.c b/tc/q_codel.c index 849cc040..c72a5779 100644 --- a/tc/q_codel.c +++ b/tc/q_codel.c @@ -144,28 +144,34 @@ static int codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (tb[TCA_CODEL_LIMIT] && RTA_PAYLOAD(tb[TCA_CODEL_LIMIT]) >= sizeof(__u32)) { limit = rta_getattr_u32(tb[TCA_CODEL_LIMIT]); - fprintf(f, "limit %up ", limit); + print_uint(PRINT_ANY, "limit", "limit %up ", limit); } if (tb[TCA_CODEL_TARGET] && RTA_PAYLOAD(tb[TCA_CODEL_TARGET]) >= sizeof(__u32)) { target = rta_getattr_u32(tb[TCA_CODEL_TARGET]); - fprintf(f, "target %s ", sprint_time(target, b1)); + print_uint(PRINT_JSON, "target", NULL, target); + print_string(PRINT_FP, NULL, "target %s ", + sprint_time(target, b1)); } if (tb[TCA_CODEL_CE_THRESHOLD] && RTA_PAYLOAD(tb[TCA_CODEL_CE_THRESHOLD]) >= sizeof(__u32)) { ce_threshold = rta_getattr_u32(tb[TCA_CODEL_CE_THRESHOLD]); - fprintf(f, "ce_threshold %s ", sprint_time(ce_threshold, b1)); + print_uint(PRINT_JSON, "ce_threshold", NULL, ce_threshold); + print_string(PRINT_FP, NULL, "ce_threshold %s ", + sprint_time(ce_threshold, b1)); } if (tb[TCA_CODEL_INTERVAL] && RTA_PAYLOAD(tb[TCA_CODEL_INTERVAL]) >= sizeof(__u32)) { interval = rta_getattr_u32(tb[TCA_CODEL_INTERVAL]); - fprintf(f, "interval %s ", sprint_time(interval, b1)); + print_uint(PRINT_JSON, "interval", NULL, interval); + print_string(PRINT_FP, NULL, "interval %s ", + sprint_time(interval, b1)); } if (tb[TCA_CODEL_ECN] && RTA_PAYLOAD(tb[TCA_CODEL_ECN]) >= sizeof(__u32)) { ecn = rta_getattr_u32(tb[TCA_CODEL_ECN]); if (ecn) - fprintf(f, "ecn "); + print_bool(PRINT_ANY, "ecn", "ecn ", true); } return 0; @@ -187,18 +193,31 @@ static int codel_print_xstats(struct qdisc_util *qu, FILE *f, st = &_st; } - fprintf(f, " count %u lastcount %u ldelay %s", - st->count, st->lastcount, sprint_time(st->ldelay, b1)); + print_uint(PRINT_ANY, "count", " count %u", st->count); + print_uint(PRINT_ANY, "lastcount", " lastcount %u", st->lastcount); + print_uint(PRINT_JSON, "ldelay", NULL, st->ldelay); + print_string(PRINT_FP, NULL, " ldelay %s", sprint_time(st->ldelay, b1)); + if (st->dropping) - fprintf(f, " dropping"); + print_bool(PRINT_ANY, "dropping", " dropping", true); + + print_int(PRINT_JSON, "drop_next", NULL, st->drop_next); if (st->drop_next < 0) - fprintf(f, " drop_next -%s", sprint_time(-st->drop_next, b1)); + print_string(PRINT_FP, NULL, " drop_next -%s", + sprint_time(-st->drop_next, b1)); else - fprintf(f, " drop_next %s", sprint_time(st->drop_next, b1)); - fprintf(f, "\n maxpacket %u ecn_mark %u drop_overlimit %u", - st->maxpacket, st->ecn_mark, st->drop_overlimit); + print_string(PRINT_FP, NULL, " drop_next %s", + sprint_time(st->drop_next, b1)); + + print_nl(); + print_uint(PRINT_ANY, "maxpacket", " maxpacket %u", st->maxpacket); + print_uint(PRINT_ANY, "ecn_mark", " ecn_mark %u", st->ecn_mark); + print_uint(PRINT_ANY, "drop_overlimit", " drop_overlimit %u", + st->drop_overlimit); + if (st->ce_mark) - fprintf(f, " ce_mark %u", st->ce_mark); + print_uint(PRINT_ANY, "ce_mark", " ce_mark %u", st->ce_mark); + return 0; } From d15e2bfc042b30f8a5b465edef95bebd922df2b7 Mon Sep 17 00:00:00 2001 From: Leslie Monis Date: Thu, 26 Dec 2019 00:34:12 +0530 Subject: [PATCH 17/23] tc: fq: add support for JSON output Enable proper JSON output for the FQ Qdisc. Use the "KEY VALUE" format for oneline output of statistics instead of "VALUE KEY", and remove unnecessary commas from the output. Use sprint_size() to print size values in fq_print_opt(). Use sprint_time64() to print time values in fq_print_xstats(). Also, update the man page to reflect the changes in the output format. Cc: Eric Dumazet Signed-off-by: Leslie Monis Signed-off-by: Stephen Hemminger --- man/man8/tc-fq.8 | 14 +++---- tc/q_fq.c | 106 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 82 insertions(+), 38 deletions(-) diff --git a/man/man8/tc-fq.8 b/man/man8/tc-fq.8 index 1febe62b..27385aae 100644 --- a/man/man8/tc-fq.8 +++ b/man/man8/tc-fq.8 @@ -90,15 +90,15 @@ Experienced. This is useful for DCTCP-style congestion control algorithms that require marking at very shallow queueing thresholds. .SH EXAMPLES -#tc qdisc add dev eth0 root est 1sec 4sec fq ce_threshold 4ms +#tc qdisc add dev eth0 root fq ce_threshold 4ms .br -#tc -s -d qdisc sh dev eth0 +#tc -s -d qdisc show dev eth0 .br -qdisc fq 800e: root refcnt 9 limit 10000p flow_limit 1000p buckets 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 low_rate_threshold 550Kbit refill_delay 40.0ms ce_threshold 4.0ms - Sent 533368436185 bytes 352296695 pkt (dropped 0, overlimits 0 requeues 1339864) - rate 39220Mbit 3238202pps backlog 12417828b 358p requeues 1339864 - 1052 flows (852 inactive, 0 throttled) - 112 gc, 0 highprio, 212 throttled, 21501 ns latency, 470241 ce_mark +qdisc fq 8001: dev eth0 root refcnt 2 limit 10000p flow_limit 100p buckets 1024 orphan_mask 1023 quantum 3028b initial_quantum 15140b low_rate_threshold 550Kbit refill_delay 40.0ms ce_threshold 4.0ms + Sent 72149092 bytes 48062 pkt (dropped 2176, overlimits 0 requeues 0) + backlog 1937920b 1280p requeues 0 + flows 34 (inactive 17 throttled 0) + gc 0 highprio 0 throttled 0 ce_mark 47622 flows_plimit 2176 .br .SH SEE ALSO .BR tc (8), diff --git a/tc/q_fq.c b/tc/q_fq.c index caf232ec..44d8a7e0 100644 --- a/tc/q_fq.c +++ b/tc/q_fq.c @@ -265,71 +265,94 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (tb[TCA_FQ_PLIMIT] && RTA_PAYLOAD(tb[TCA_FQ_PLIMIT]) >= sizeof(__u32)) { plimit = rta_getattr_u32(tb[TCA_FQ_PLIMIT]); - fprintf(f, "limit %up ", plimit); + print_uint(PRINT_ANY, "limit", "limit %up ", plimit); } if (tb[TCA_FQ_FLOW_PLIMIT] && RTA_PAYLOAD(tb[TCA_FQ_FLOW_PLIMIT]) >= sizeof(__u32)) { flow_plimit = rta_getattr_u32(tb[TCA_FQ_FLOW_PLIMIT]); - fprintf(f, "flow_limit %up ", flow_plimit); + print_uint(PRINT_ANY, "flow_limit", "flow_limit %up ", + flow_plimit); } if (tb[TCA_FQ_BUCKETS_LOG] && RTA_PAYLOAD(tb[TCA_FQ_BUCKETS_LOG]) >= sizeof(__u32)) { buckets_log = rta_getattr_u32(tb[TCA_FQ_BUCKETS_LOG]); - fprintf(f, "buckets %u ", 1U << buckets_log); + print_uint(PRINT_ANY, "buckets", "buckets %u ", + 1U << buckets_log); } if (tb[TCA_FQ_ORPHAN_MASK] && RTA_PAYLOAD(tb[TCA_FQ_ORPHAN_MASK]) >= sizeof(__u32)) { orphan_mask = rta_getattr_u32(tb[TCA_FQ_ORPHAN_MASK]); - fprintf(f, "orphan_mask %u ", orphan_mask); + print_uint(PRINT_ANY, "orphan_mask", "orphan_mask %u ", + orphan_mask); } if (tb[TCA_FQ_RATE_ENABLE] && RTA_PAYLOAD(tb[TCA_FQ_RATE_ENABLE]) >= sizeof(int)) { pacing = rta_getattr_u32(tb[TCA_FQ_RATE_ENABLE]); if (pacing == 0) - fprintf(f, "nopacing "); + print_bool(PRINT_ANY, "pacing", "nopacing ", false); } if (tb[TCA_FQ_QUANTUM] && RTA_PAYLOAD(tb[TCA_FQ_QUANTUM]) >= sizeof(__u32)) { quantum = rta_getattr_u32(tb[TCA_FQ_QUANTUM]); - fprintf(f, "quantum %u ", quantum); + print_uint(PRINT_JSON, "quantum", NULL, quantum); + print_string(PRINT_FP, NULL, "quantum %s ", + sprint_size(quantum, b1)); } if (tb[TCA_FQ_INITIAL_QUANTUM] && RTA_PAYLOAD(tb[TCA_FQ_INITIAL_QUANTUM]) >= sizeof(__u32)) { quantum = rta_getattr_u32(tb[TCA_FQ_INITIAL_QUANTUM]); - fprintf(f, "initial_quantum %u ", quantum); + print_uint(PRINT_JSON, "initial_quantum", NULL, quantum); + print_string(PRINT_FP, NULL, "initial_quantum %s ", + sprint_size(quantum, b1)); } if (tb[TCA_FQ_FLOW_MAX_RATE] && RTA_PAYLOAD(tb[TCA_FQ_FLOW_MAX_RATE]) >= sizeof(__u32)) { rate = rta_getattr_u32(tb[TCA_FQ_FLOW_MAX_RATE]); - if (rate != ~0U) - fprintf(f, "maxrate %s ", sprint_rate(rate, b1)); + if (rate != ~0U) { + print_uint(PRINT_JSON, "maxrate", NULL, rate); + print_string(PRINT_FP, NULL, "maxrate %s ", + sprint_rate(rate, b1)); + } } if (tb[TCA_FQ_FLOW_DEFAULT_RATE] && RTA_PAYLOAD(tb[TCA_FQ_FLOW_DEFAULT_RATE]) >= sizeof(__u32)) { rate = rta_getattr_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE]); - if (rate != 0) - fprintf(f, "defrate %s ", sprint_rate(rate, b1)); + if (rate != 0) { + print_uint(PRINT_JSON, "defrate", NULL, rate); + print_string(PRINT_FP, NULL, "defrate %s ", + sprint_rate(rate, b1)); + } } if (tb[TCA_FQ_LOW_RATE_THRESHOLD] && RTA_PAYLOAD(tb[TCA_FQ_LOW_RATE_THRESHOLD]) >= sizeof(__u32)) { rate = rta_getattr_u32(tb[TCA_FQ_LOW_RATE_THRESHOLD]); - if (rate != 0) - fprintf(f, "low_rate_threshold %s ", sprint_rate(rate, b1)); + if (rate != 0) { + print_uint(PRINT_JSON, "low_rate_threshold", NULL, + rate); + print_string(PRINT_FP, NULL, "low_rate_threshold %s ", + sprint_rate(rate, b1)); + } } if (tb[TCA_FQ_FLOW_REFILL_DELAY] && RTA_PAYLOAD(tb[TCA_FQ_FLOW_REFILL_DELAY]) >= sizeof(__u32)) { refill_delay = rta_getattr_u32(tb[TCA_FQ_FLOW_REFILL_DELAY]); - fprintf(f, "refill_delay %s ", sprint_time(refill_delay, b1)); + print_uint(PRINT_JSON, "refill_delay", NULL, refill_delay); + print_string(PRINT_FP, NULL, "refill_delay %s ", + sprint_time(refill_delay, b1)); } if (tb[TCA_FQ_CE_THRESHOLD] && RTA_PAYLOAD(tb[TCA_FQ_CE_THRESHOLD]) >= sizeof(__u32)) { ce_threshold = rta_getattr_u32(tb[TCA_FQ_CE_THRESHOLD]); - if (ce_threshold != ~0U) - fprintf(f, "ce_threshold %s ", sprint_time(ce_threshold, b1)); + if (ce_threshold != ~0U) { + print_uint(PRINT_JSON, "ce_threshold", NULL, + ce_threshold); + print_string(PRINT_FP, NULL, "ce_threshold %s ", + sprint_time(ce_threshold, b1)); + } } return 0; @@ -340,6 +363,8 @@ static int fq_print_xstats(struct qdisc_util *qu, FILE *f, { struct tc_fq_qd_stats *st, _st; + SPRINT_BUF(b1); + if (xstats == NULL) return 0; @@ -348,32 +373,51 @@ static int fq_print_xstats(struct qdisc_util *qu, FILE *f, st = &_st; - fprintf(f, " %u flows (%u inactive, %u throttled)", - st->flows, st->inactive_flows, st->throttled_flows); + print_uint(PRINT_ANY, "flows", " flows %u", st->flows); + print_uint(PRINT_ANY, "inactive", " (inactive %u", st->inactive_flows); + print_uint(PRINT_ANY, "throttled", " throttled %u)", + st->throttled_flows); - if (st->time_next_delayed_flow > 0) - fprintf(f, ", next packet delay %llu ns", st->time_next_delayed_flow); + if (st->time_next_delayed_flow > 0) { + print_lluint(PRINT_JSON, "next_packet_delay", NULL, + st->time_next_delayed_flow); + print_string(PRINT_FP, NULL, " next_packet_delay %s", + sprint_time64(st->time_next_delayed_flow, b1)); + } - fprintf(f, "\n %llu gc, %llu highprio", - st->gc_flows, st->highprio_packets); + print_nl(); + print_lluint(PRINT_ANY, "gc", " gc %llu", st->gc_flows); + print_lluint(PRINT_ANY, "highprio", " highprio %llu", + st->highprio_packets); if (st->tcp_retrans) - fprintf(f, ", %llu retrans", st->tcp_retrans); + print_lluint(PRINT_ANY, "retrans", " retrans %llu", + st->tcp_retrans); - fprintf(f, ", %llu throttled", st->throttled); + print_lluint(PRINT_ANY, "throttled", " throttled %llu", st->throttled); - if (st->unthrottle_latency_ns) - fprintf(f, ", %u ns latency", st->unthrottle_latency_ns); + if (st->unthrottle_latency_ns) { + print_uint(PRINT_JSON, "latency", NULL, + st->unthrottle_latency_ns); + print_string(PRINT_FP, NULL, " latency %s", + sprint_time64(st->unthrottle_latency_ns, b1)); + } if (st->ce_mark) - fprintf(f, ", %llu ce_mark", st->ce_mark); + print_lluint(PRINT_ANY, "ce_mark", " ce_mark %llu", + st->ce_mark); if (st->flows_plimit) - fprintf(f, ", %llu flows_plimit", st->flows_plimit); + print_lluint(PRINT_ANY, "flows_plimit", " flows_plimit %llu", + st->flows_plimit); - if (st->pkts_too_long || st->allocation_errors) - fprintf(f, "\n %llu too long pkts, %llu alloc errors\n", - st->pkts_too_long, st->allocation_errors); + if (st->pkts_too_long || st->allocation_errors) { + print_nl(); + print_lluint(PRINT_ANY, "pkts_too_long", + " pkts_too_long %llu", st->pkts_too_long); + print_lluint(PRINT_ANY, "alloc_errors", " alloc_erros %llu", + st->allocation_errors); + } return 0; } From f6564ed60d8cc4697934bc351ef3aa631fda8b97 Mon Sep 17 00:00:00 2001 From: Leslie Monis Date: Thu, 26 Dec 2019 00:34:13 +0530 Subject: [PATCH 18/23] tc: hhf: add support for JSON output Enable proper JSON output for the HHF Qdisc. Also, use sprint_size() to print size values. Signed-off-by: Leslie Monis Signed-off-by: Stephen Hemminger --- tc/q_hhf.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/tc/q_hhf.c b/tc/q_hhf.c index 5ee6642f..f8888011 100644 --- a/tc/q_hhf.c +++ b/tc/q_hhf.c @@ -138,37 +138,46 @@ static int hhf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (tb[TCA_HHF_BACKLOG_LIMIT] && RTA_PAYLOAD(tb[TCA_HHF_BACKLOG_LIMIT]) >= sizeof(__u32)) { limit = rta_getattr_u32(tb[TCA_HHF_BACKLOG_LIMIT]); - fprintf(f, "limit %up ", limit); + print_uint(PRINT_ANY, "limit", "limit %up ", limit); } if (tb[TCA_HHF_QUANTUM] && RTA_PAYLOAD(tb[TCA_HHF_QUANTUM]) >= sizeof(__u32)) { quantum = rta_getattr_u32(tb[TCA_HHF_QUANTUM]); - fprintf(f, "quantum %u ", quantum); + print_uint(PRINT_JSON, "quantum", NULL, quantum); + print_string(PRINT_FP, NULL, "quantum %s ", + sprint_size(quantum, b1)); } if (tb[TCA_HHF_HH_FLOWS_LIMIT] && RTA_PAYLOAD(tb[TCA_HHF_HH_FLOWS_LIMIT]) >= sizeof(__u32)) { hh_limit = rta_getattr_u32(tb[TCA_HHF_HH_FLOWS_LIMIT]); - fprintf(f, "hh_limit %u ", hh_limit); + print_uint(PRINT_ANY, "hh_limit", "hh_limit %u ", hh_limit); } if (tb[TCA_HHF_RESET_TIMEOUT] && RTA_PAYLOAD(tb[TCA_HHF_RESET_TIMEOUT]) >= sizeof(__u32)) { reset_timeout = rta_getattr_u32(tb[TCA_HHF_RESET_TIMEOUT]); - fprintf(f, "reset_timeout %s ", sprint_time(reset_timeout, b1)); + print_uint(PRINT_JSON, "reset_timeout", NULL, reset_timeout); + print_string(PRINT_FP, NULL, "reset_timeout %s ", + sprint_time(reset_timeout, b1)); } if (tb[TCA_HHF_ADMIT_BYTES] && RTA_PAYLOAD(tb[TCA_HHF_ADMIT_BYTES]) >= sizeof(__u32)) { admit_bytes = rta_getattr_u32(tb[TCA_HHF_ADMIT_BYTES]); - fprintf(f, "admit_bytes %u ", admit_bytes); + print_uint(PRINT_JSON, "admit_bytes", NULL, admit_bytes); + print_string(PRINT_FP, NULL, "admit_bytes %s ", + sprint_size(admit_bytes, b1)); } if (tb[TCA_HHF_EVICT_TIMEOUT] && RTA_PAYLOAD(tb[TCA_HHF_EVICT_TIMEOUT]) >= sizeof(__u32)) { evict_timeout = rta_getattr_u32(tb[TCA_HHF_EVICT_TIMEOUT]); - fprintf(f, "evict_timeout %s ", sprint_time(evict_timeout, b1)); + print_uint(PRINT_JSON, "evict_timeout", NULL, evict_timeout); + print_string(PRINT_FP, NULL, "evict_timeout %s ", + sprint_time(evict_timeout, b1)); } if (tb[TCA_HHF_NON_HH_WEIGHT] && RTA_PAYLOAD(tb[TCA_HHF_NON_HH_WEIGHT]) >= sizeof(__u32)) { non_hh_weight = rta_getattr_u32(tb[TCA_HHF_NON_HH_WEIGHT]); - fprintf(f, "non_hh_weight %u ", non_hh_weight); + print_uint(PRINT_ANY, "non_hh_weight", "non_hh_weight %u ", + non_hh_weight); } return 0; } @@ -186,9 +195,13 @@ static int hhf_print_xstats(struct qdisc_util *qu, FILE *f, st = RTA_DATA(xstats); - fprintf(f, " drop_overlimit %u hh_overlimit %u tot_hh %u cur_hh %u", - st->drop_overlimit, st->hh_overlimit, - st->hh_tot_count, st->hh_cur_count); + print_uint(PRINT_ANY, "drop_overlimit", " drop_overlimit %u", + st->drop_overlimit); + print_uint(PRINT_ANY, "hh_overlimit", " hh_overlimit %u", + st->hh_overlimit); + print_uint(PRINT_ANY, "tot_hh", " tot_hh %u", st->hh_tot_count); + print_uint(PRINT_ANY, "cur_hh", " cur_hh %u", st->hh_cur_count); + return 0; } From 0154d096c5f8de695dcbed0ae9e484a2d928b2b3 Mon Sep 17 00:00:00 2001 From: Leslie Monis Date: Thu, 26 Dec 2019 00:34:14 +0530 Subject: [PATCH 19/23] tc: pie: add support for JSON output Enable proper JSON output for the PIE Qdisc. Use sprint_time() to print the value of tc_pie_xstats->delay. Use the long double format specifier to print tc_pie_xstats->prob. Also, fix the indentation in the oneline output of statistics and update the man page to reflect this change. Signed-off-by: Leslie Monis Signed-off-by: Stephen Hemminger --- man/man8/tc-pie.8 | 16 ++++++++-------- tc/q_pie.c | 47 ++++++++++++++++++++++++++++++----------------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/man/man8/tc-pie.8 b/man/man8/tc-pie.8 index bdcfba51..0db97d13 100644 --- a/man/man8/tc-pie.8 +++ b/man/man8/tc-pie.8 @@ -107,32 +107,32 @@ is turned off. qdisc pie 8036: dev eth0 root refcnt 2 limit 1000p target 15.0ms tupdate 16.0ms alpha 2 beta 20 Sent 31216108 bytes 20800 pkt (dropped 80, overlimits 0 requeues 0) backlog 16654b 11p requeues 0 - prob 0.006161 delay 15666us - pkts_in 20811 overlimit 0 dropped 80 maxq 50 ecn_mark 0 + prob 0.006161 delay 15666us + pkts_in 20811 overlimit 0 dropped 80 maxq 50 ecn_mark 0 # tc qdisc add dev eth0 root pie dq_rate_estimator # tc -s qdisc show qdisc pie 8036: dev eth0 root refcnt 2 limit 1000p target 15.0ms tupdate 16.0ms alpha 2 beta 20 Sent 63947420 bytes 42414 pkt (dropped 41, overlimits 0 requeues 0) backlog 271006b 179p requeues 0 - prob 0.000092 delay 22200us avg_dq_rate 12145996 - pkts_in 41 overlimit 343 dropped 0 maxq 50 ecn_mark 0 + prob 0.000092 delay 22200us avg_dq_rate 12145996 + pkts_in 41 overlimit 343 dropped 0 maxq 50 ecn_mark 0 # tc qdisc add dev eth0 root pie limit 100 target 20ms tupdate 30ms ecn # tc -s qdisc show qdisc pie 8036: dev eth0 root refcnt 2 limit 100p target 20.0ms tupdate 32.0ms alpha 2 beta 20 ecn Sent 6591724 bytes 4442 pkt (dropped 27, overlimits 0 requeues 0) backlog 18168b 12p requeues 0 - prob 0.008845 delay 11348us - pkts_in 4454 overlimit 0 dropped 27 maxq 65 ecn_mark 0 + prob 0.008845 delay 11348us + pkts_in 4454 overlimit 0 dropped 27 maxq 65 ecn_mark 0 # tc qdisc add dev eth0 root pie limit 100 target 50ms tupdate 30ms bytemode # tc -s qdisc show qdisc pie 8036: dev eth0 root refcnt 2 limit 100p target 50.0ms tupdate 32.0ms alpha 2 beta 20 bytemode Sent 1616274 bytes 1137 pkt (dropped 0, overlimits 0 requeues 0) backlog 13626b 9p requeues 0 - prob 0.000000 delay 0us - pkts_in 1146 overlimit 0 dropped 0 maxq 23 ecn_mark 0 + prob 0.000000 delay 0us + pkts_in 1146 overlimit 0 dropped 0 maxq 23 ecn_mark 0 .SH SEE ALSO .BR tc (8), diff --git a/tc/q_pie.c b/tc/q_pie.c index fda98a71..709a78b4 100644 --- a/tc/q_pie.c +++ b/tc/q_pie.c @@ -156,40 +156,44 @@ static int pie_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (tb[TCA_PIE_LIMIT] && RTA_PAYLOAD(tb[TCA_PIE_LIMIT]) >= sizeof(__u32)) { limit = rta_getattr_u32(tb[TCA_PIE_LIMIT]); - fprintf(f, "limit %up ", limit); + print_uint(PRINT_ANY, "limit", "limit %up ", limit); } if (tb[TCA_PIE_TARGET] && RTA_PAYLOAD(tb[TCA_PIE_TARGET]) >= sizeof(__u32)) { target = rta_getattr_u32(tb[TCA_PIE_TARGET]); - fprintf(f, "target %s ", sprint_time(target, b1)); + print_uint(PRINT_JSON, "target", NULL, target); + print_string(PRINT_FP, NULL, "target %s ", + sprint_time(target, b1)); } if (tb[TCA_PIE_TUPDATE] && RTA_PAYLOAD(tb[TCA_PIE_TUPDATE]) >= sizeof(__u32)) { tupdate = rta_getattr_u32(tb[TCA_PIE_TUPDATE]); - fprintf(f, "tupdate %s ", sprint_time(tupdate, b1)); + print_uint(PRINT_JSON, "tupdate", NULL, tupdate); + print_string(PRINT_FP, NULL, "tupdate %s ", + sprint_time(tupdate, b1)); } if (tb[TCA_PIE_ALPHA] && RTA_PAYLOAD(tb[TCA_PIE_ALPHA]) >= sizeof(__u32)) { alpha = rta_getattr_u32(tb[TCA_PIE_ALPHA]); - fprintf(f, "alpha %u ", alpha); + print_uint(PRINT_ANY, "alpha", "alpha %u ", alpha); } if (tb[TCA_PIE_BETA] && RTA_PAYLOAD(tb[TCA_PIE_BETA]) >= sizeof(__u32)) { beta = rta_getattr_u32(tb[TCA_PIE_BETA]); - fprintf(f, "beta %u ", beta); + print_uint(PRINT_ANY, "beta", "beta %u ", beta); } if (tb[TCA_PIE_ECN] && RTA_PAYLOAD(tb[TCA_PIE_ECN]) >= sizeof(__u32)) { ecn = rta_getattr_u32(tb[TCA_PIE_ECN]); if (ecn) - fprintf(f, "ecn "); + print_bool(PRINT_ANY, "ecn", "ecn ", true); } if (tb[TCA_PIE_BYTEMODE] && RTA_PAYLOAD(tb[TCA_PIE_BYTEMODE]) >= sizeof(__u32)) { bytemode = rta_getattr_u32(tb[TCA_PIE_BYTEMODE]); if (bytemode) - fprintf(f, "bytemode "); + print_bool(PRINT_ANY, "bytemode", "bytemode ", true); } if (tb[TCA_PIE_DQ_RATE_ESTIMATOR] && @@ -197,7 +201,8 @@ static int pie_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) dq_rate_estimator = rta_getattr_u32(tb[TCA_PIE_DQ_RATE_ESTIMATOR]); if (dq_rate_estimator) - fprintf(f, "dq_rate_estimator "); + print_bool(PRINT_ANY, "dq_rate_estimator", + "dq_rate_estimator ", true); } return 0; @@ -208,6 +213,8 @@ static int pie_print_xstats(struct qdisc_util *qu, FILE *f, { struct tc_pie_xstats *st; + SPRINT_BUF(b1); + if (xstats == NULL) return 0; @@ -215,18 +222,24 @@ static int pie_print_xstats(struct qdisc_util *qu, FILE *f, return -1; st = RTA_DATA(xstats); - /*prob is returned as a fracion of maximum integer value */ - fprintf(f, "prob %f delay %uus", - (double)st->prob / (double)UINT64_MAX, st->delay); + + /* prob is returned as a fracion of maximum integer value */ + print_float(PRINT_ANY, "prob", " prob %lg", + (double)st->prob / (double)UINT64_MAX); + print_uint(PRINT_JSON, "delay", NULL, st->delay); + print_string(PRINT_FP, NULL, " delay %s", sprint_time(st->delay, b1)); if (st->dq_rate_estimating) - fprintf(f, " avg_dq_rate %u\n", st->avg_dq_rate); - else - fprintf(f, "\n"); + print_uint(PRINT_ANY, "avg_dq_rate", " avg_dq_rate %u", + st->avg_dq_rate); + + print_nl(); + print_uint(PRINT_ANY, "pkts_in", " pkts_in %u", st->packets_in); + print_uint(PRINT_ANY, "overlimit", " overlimit %u", st->overlimit); + print_uint(PRINT_ANY, "dropped", " dropped %u", st->dropped); + print_uint(PRINT_ANY, "maxq", " maxq %u", st->maxq); + print_uint(PRINT_ANY, "ecn_mark", " ecn_mark %u", st->ecn_mark); - fprintf(f, "pkts_in %u overlimit %u dropped %u maxq %u ecn_mark %u\n", - st->packets_in, st->overlimit, st->dropped, st->maxq, - st->ecn_mark); return 0; } From 46d032d002223cf5fbdb9df5602ef4dc6d0c4914 Mon Sep 17 00:00:00 2001 From: Leslie Monis Date: Thu, 26 Dec 2019 00:34:15 +0530 Subject: [PATCH 20/23] tc: sfb: add support for JSON output Enable proper JSON output for the SFB Qdisc. Make the output for options "rehash" and "db" explicit. Use the long double format specifier to print probability values. Use sprint_time() to print time values. Also, fix the indentation in sfb_print_opt(). Signed-off-by: Leslie Monis Signed-off-by: Stephen Hemminger --- tc/q_sfb.c | 67 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/tc/q_sfb.c b/tc/q_sfb.c index 7f48c6e0..8af55d98 100644 --- a/tc/q_sfb.c +++ b/tc/q_sfb.c @@ -143,6 +143,8 @@ static int sfb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct rtattr *tb[__TCA_SFB_MAX]; struct tc_sfb_qopt *qopt; + SPRINT_BUF(b1); + if (opt == NULL) return 0; @@ -153,14 +155,27 @@ static int sfb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (RTA_PAYLOAD(tb[TCA_SFB_PARMS]) < sizeof(*qopt)) return -1; - fprintf(f, - "limit %d max %d target %d\n" - " 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, - qopt->penalty_rate, qopt->penalty_burst, - qopt->rehash_interval, qopt->warmup_time); + print_uint(PRINT_JSON, "rehash", NULL, qopt->rehash_interval * 1000); + print_string(PRINT_FP, NULL, "rehash %s ", + sprint_time(qopt->rehash_interval * 1000, b1)); + + print_uint(PRINT_JSON, "db", NULL, qopt->warmup_time * 1000); + print_string(PRINT_FP, NULL, "db %s ", + sprint_time(qopt->warmup_time * 1000, b1)); + + print_uint(PRINT_ANY, "limit", "limit %up ", qopt->limit); + print_uint(PRINT_ANY, "max", "max %up ", qopt->max); + print_uint(PRINT_ANY, "target", "target %up ", qopt->bin_size); + + print_float(PRINT_ANY, "increment", "increment %lg ", + (double)qopt->increment / SFB_MAX_PROB); + print_float(PRINT_ANY, "decrement", "decrement %lg ", + (double)qopt->decrement / SFB_MAX_PROB); + + print_uint(PRINT_ANY, "penalty_rate", "penalty_rate %upps ", + qopt->penalty_rate); + print_uint(PRINT_ANY, "penalty_burst", "penalty_burst %up ", + qopt->penalty_burst); return 0; } @@ -168,24 +183,32 @@ static int sfb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) static int sfb_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats) { - struct tc_sfb_xstats *st; + struct tc_sfb_xstats *st; - if (xstats == NULL) - return 0; + if (xstats == NULL) + return 0; - if (RTA_PAYLOAD(xstats) < sizeof(*st)) - return -1; + if (RTA_PAYLOAD(xstats) < sizeof(*st)) + return -1; - st = RTA_DATA(xstats); - fprintf(f, - " earlydrop %u penaltydrop %u bucketdrop %u queuedrop %u childdrop %u marked %u\n" - " maxqlen %u maxprob %.5f avgprob %.5f ", - st->earlydrop, st->penaltydrop, st->bucketdrop, st->queuedrop, st->childdrop, - st->marked, - st->maxqlen, (double)st->maxprob / SFB_MAX_PROB, - (double)st->avgprob / SFB_MAX_PROB); + st = RTA_DATA(xstats); - return 0; + print_uint(PRINT_ANY, "earlydrop", " earlydrop %u", st->earlydrop); + print_uint(PRINT_ANY, "penaltydrop", " penaltydrop %u", + st->penaltydrop); + print_uint(PRINT_ANY, "bucketdrop", " bucketdrop %u", st->bucketdrop); + print_uint(PRINT_ANY, "queuedrop", " queuedrop %u", st->queuedrop); + print_uint(PRINT_ANY, "childdrop", " childdrop %u", st->childdrop); + print_uint(PRINT_ANY, "marked", " marked %u", st->marked); + print_nl(); + print_uint(PRINT_ANY, "maxqlen", " maxqlen %u", st->maxqlen); + + print_float(PRINT_ANY, "maxprob", " maxprob %lg", + (double)st->maxprob / SFB_MAX_PROB); + print_float(PRINT_ANY, "avgprob", " avgprob %lg", + (double)st->avgprob / SFB_MAX_PROB); + + return 0; } struct qdisc_util sfb_qdisc_util = { From 85fdef052b148b69507a7cf87c22825f556578fe Mon Sep 17 00:00:00 2001 From: Leslie Monis Date: Thu, 26 Dec 2019 00:34:16 +0530 Subject: [PATCH 21/23] tc: sfq: add support for JSON output Enable proper JSON output for the SFQ Qdisc. Use the long double format specifier to print the value of "probability". Also, fix the indentation in the online output of the contents in the tc_sfqred_stats structure. Signed-off-by: Leslie Monis Signed-off-by: Stephen Hemminger --- tc/q_sfq.c | 70 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/tc/q_sfq.c b/tc/q_sfq.c index 4998921d..2b9bbcd2 100644 --- a/tc/q_sfq.c +++ b/tc/q_sfq.c @@ -217,35 +217,53 @@ static int sfq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (RTA_PAYLOAD(opt) >= sizeof(*qopt_ext)) qopt_ext = RTA_DATA(opt); qopt = RTA_DATA(opt); - fprintf(f, "limit %up ", qopt->limit); - fprintf(f, "quantum %s ", sprint_size(qopt->quantum, b1)); - if (qopt_ext && qopt_ext->depth) - fprintf(f, "depth %u ", qopt_ext->depth); - if (qopt_ext && qopt_ext->headdrop) - fprintf(f, "headdrop "); - if (show_details) { - fprintf(f, "flows %u/%u ", qopt->flows, qopt->divisor); - } - fprintf(f, "divisor %u ", qopt->divisor); + print_uint(PRINT_ANY, "limit", "limit %up ", qopt->limit); + print_uint(PRINT_JSON, "quantum", NULL, qopt->quantum); + print_string(PRINT_FP, NULL, "quantum %s ", + sprint_size(qopt->quantum, b1)); + + if (qopt_ext && qopt_ext->depth) + print_uint(PRINT_ANY, "depth", "depth %u ", qopt_ext->depth); + if (qopt_ext && qopt_ext->headdrop) + print_bool(PRINT_ANY, "headdrop", "headdrop ", true); + if (show_details) + print_uint(PRINT_ANY, "flows", "flows %u ", qopt->flows); + + print_uint(PRINT_ANY, "divisor", "divisor %u ", qopt->divisor); + if (qopt->perturb_period) - fprintf(f, "perturb %dsec ", qopt->perturb_period); + print_int(PRINT_ANY, "perturb", "perturb %dsec ", + qopt->perturb_period); if (qopt_ext && qopt_ext->qth_min) { - fprintf(f, "\n ewma %u ", qopt_ext->Wlog); - fprintf(f, "min %s max %s probability %g ", - sprint_size(qopt_ext->qth_min, b2), - sprint_size(qopt_ext->qth_max, b3), - qopt_ext->max_P / pow(2, 32)); + print_uint(PRINT_ANY, "ewma", "ewma %u ", qopt_ext->Wlog); + print_uint(PRINT_JSON, "min", NULL, qopt_ext->qth_min); + print_string(PRINT_FP, NULL, "min %s ", + sprint_size(qopt_ext->qth_min, b2)); + print_uint(PRINT_JSON, "max", NULL, qopt_ext->qth_max); + print_string(PRINT_FP, NULL, "max %s ", + sprint_size(qopt_ext->qth_max, b3)); + print_float(PRINT_ANY, "probability", "probability %lg ", + qopt_ext->max_P / pow(2, 32)); tc_red_print_flags(qopt_ext->flags); if (show_stats) { - fprintf(f, "\n prob_mark %u prob_mark_head %u prob_drop %u", - qopt_ext->stats.prob_mark, - qopt_ext->stats.prob_mark_head, - qopt_ext->stats.prob_drop); - fprintf(f, "\n forced_mark %u forced_mark_head %u forced_drop %u", - qopt_ext->stats.forced_mark, - qopt_ext->stats.forced_mark_head, - qopt_ext->stats.forced_drop); + print_nl(); + print_uint(PRINT_ANY, "prob_mark", " prob_mark %u", + qopt_ext->stats.prob_mark); + print_uint(PRINT_ANY, "prob_mark_head", + " prob_mark_head %u", + qopt_ext->stats.prob_mark_head); + print_uint(PRINT_ANY, "prob_drop", " prob_drop %u", + qopt_ext->stats.prob_drop); + print_nl(); + print_uint(PRINT_ANY, "forced_mark", + " forced_mark %u", + qopt_ext->stats.forced_mark); + print_uint(PRINT_ANY, "forced_mark_head", + " forced_mark_head %u", + qopt_ext->stats.forced_mark_head); + print_uint(PRINT_ANY, "forced_drop", " forced_drop %u", + qopt_ext->stats.forced_drop); } } return 0; @@ -262,8 +280,8 @@ static int sfq_print_xstats(struct qdisc_util *qu, FILE *f, return -1; st = RTA_DATA(xstats); - fprintf(f, " allot %d ", st->allot); - fprintf(f, "\n"); + print_int(PRINT_ANY, "allot", " allot %d", st->allot); + return 0; } From 669314e817113ad25f03deb0efdb9ef54a658c03 Mon Sep 17 00:00:00 2001 From: Leslie Monis Date: Thu, 26 Dec 2019 00:34:17 +0530 Subject: [PATCH 22/23] tc: tbf: add support for JSON output Enable proper JSON output for the TBF Qdisc. Also, fix the style of the statement that's calculating "latency" in tbf_print_opt(). Signed-off-by: Leslie Monis Signed-off-by: Stephen Hemminger --- tc/q_tbf.c | 68 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/tc/q_tbf.c b/tc/q_tbf.c index 57a9736c..5135b1d6 100644 --- a/tc/q_tbf.c +++ b/tc/q_tbf.c @@ -264,7 +264,7 @@ static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) struct tc_tbf_qopt *qopt; unsigned int linklayer; double buffer, mtu; - double latency; + double latency, lat2; __u64 rate64 = 0, prate64 = 0; SPRINT_BUF(b1); @@ -286,53 +286,79 @@ static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (tb[TCA_TBF_RATE64] && RTA_PAYLOAD(tb[TCA_TBF_RATE64]) >= sizeof(rate64)) rate64 = rta_getattr_u64(tb[TCA_TBF_RATE64]); - fprintf(f, "rate %s ", sprint_rate(rate64, b1)); + print_u64(PRINT_JSON, "rate", NULL, rate64); + print_string(PRINT_FP, NULL, "rate %s ", sprint_rate(rate64, b1)); buffer = tc_calc_xmitsize(rate64, qopt->buffer); if (show_details) { - fprintf(f, "burst %s/%u mpu %s ", sprint_size(buffer, b1), - 1<rate.cell_log, sprint_size(qopt->rate.mpu, b2)); + sprintf(b1, "%s/%u", sprint_size(buffer, b2), + 1 << qopt->rate.cell_log); + print_string(PRINT_ANY, "burst", "burst %s ", b1); + print_uint(PRINT_JSON, "mpu", NULL, qopt->rate.mpu); + print_string(PRINT_FP, NULL, "mpu %s ", + sprint_size(qopt->rate.mpu, b1)); } else { - fprintf(f, "burst %s ", sprint_size(buffer, b1)); + print_u64(PRINT_JSON, "burst", NULL, buffer); + print_string(PRINT_FP, NULL, "burst %s ", + sprint_size(buffer, b1)); } if (show_raw) - fprintf(f, "[%08x] ", qopt->buffer); + print_hex(PRINT_ANY, "burst_raw", "[%08x] ", qopt->buffer); prate64 = qopt->peakrate.rate; if (tb[TCA_TBF_PRATE64] && RTA_PAYLOAD(tb[TCA_TBF_PRATE64]) >= sizeof(prate64)) prate64 = rta_getattr_u64(tb[TCA_TBF_PRATE64]); if (prate64) { - fprintf(f, "peakrate %s ", sprint_rate(prate64, b1)); + print_u64(PRINT_JSON, "peakrate", NULL, prate64); + print_string(PRINT_FP, NULL, "peakrate %s ", + sprint_rate(prate64, b1)); if (qopt->mtu || qopt->peakrate.mpu) { mtu = tc_calc_xmitsize(prate64, qopt->mtu); if (show_details) { - fprintf(f, "mtu %s/%u mpu %s ", sprint_size(mtu, b1), - 1<peakrate.cell_log, sprint_size(qopt->peakrate.mpu, b2)); + sprintf(b1, "%s/%u", sprint_size(mtu, b2), + 1 << qopt->peakrate.cell_log); + print_string(PRINT_ANY, "mtu", "mtu %s ", b1); + print_uint(PRINT_JSON, "mpu", NULL, + qopt->peakrate.mpu); + print_string(PRINT_FP, NULL, "mpu %s ", + sprint_size(qopt->peakrate.mpu, + b1)); } else { - fprintf(f, "minburst %s ", sprint_size(mtu, b1)); + print_u64(PRINT_JSON, "minburst", NULL, mtu); + print_string(PRINT_FP, NULL, "minburst %s ", + sprint_size(mtu, b1)); } if (show_raw) - fprintf(f, "[%08x] ", qopt->mtu); + print_hex(PRINT_ANY, "mtu_raw", "[%08x] ", + qopt->mtu); } } - latency = TIME_UNITS_PER_SEC*(qopt->limit/(double)rate64) - tc_core_tick2time(qopt->buffer); + 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); + lat2 = TIME_UNITS_PER_SEC * (qopt->limit / (double)prate64) - + tc_core_tick2time(qopt->mtu); if (lat2 > latency) latency = lat2; } - if (latency >= 0.0) - fprintf(f, "lat %s ", sprint_time(latency, b1)); - if (show_raw || latency < 0.0) - fprintf(f, "limit %s ", sprint_size(qopt->limit, b1)); - - if (qopt->rate.overhead) { - fprintf(f, "overhead %d", qopt->rate.overhead); + if (latency >= 0.0) { + print_u64(PRINT_JSON, "lat", NULL, latency); + print_string(PRINT_FP, NULL, "lat %s ", + sprint_time(latency, b1)); } + if (show_raw || latency < 0.0) { + print_uint(PRINT_JSON, "limit", NULL, qopt->limit); + print_string(PRINT_FP, NULL, "limit %s ", + sprint_size(qopt->limit, b1)); + } + if (qopt->rate.overhead) + print_int(PRINT_ANY, "overhead", "overhead %d ", + qopt->rate.overhead); linklayer = (qopt->rate.linklayer & TC_LINKLAYER_MASK); if (linklayer > TC_LINKLAYER_ETHERNET || show_details) - fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b3)); + print_string(PRINT_ANY, "linklayer", "linklayer %s ", + sprint_linklayer(linklayer, b3)); return 0; } From e819d3a03dd19ed3dd0f50bd128f62f972e8240f Mon Sep 17 00:00:00 2001 From: Leslie Monis Date: Thu, 26 Dec 2019 00:34:18 +0530 Subject: [PATCH 23/23] tc: fq_codel: fix missing statistic in JSON output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print JSON object even if tc_fq_codel_xstats->class_stats.drop_next is negative. Cc: Toke Høiland-Jørgensen Fixes: 997f2dc19378 ("tc: Add JSON output of fq_codel stats") Signed-off-by: Leslie Monis Signed-off-by: Stephen Hemminger --- tc/q_fq_codel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tc/q_fq_codel.c b/tc/q_fq_codel.c index 376ac50d..d002940d 100644 --- a/tc/q_fq_codel.c +++ b/tc/q_fq_codel.c @@ -275,12 +275,12 @@ static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, sprint_time(st->class_stats.ldelay, b1)); if (st->class_stats.dropping) { print_bool(PRINT_ANY, "dropping", " dropping", true); + print_int(PRINT_JSON, "drop_next", NULL, + st->class_stats.drop_next); if (st->class_stats.drop_next < 0) print_string(PRINT_FP, NULL, " drop_next -%s", sprint_time(-st->class_stats.drop_next, b1)); else { - print_uint(PRINT_JSON, "drop_next", NULL, - st->class_stats.drop_next); print_string(PRINT_FP, NULL, " drop_next %s", sprint_time(st->class_stats.drop_next, b1)); }