All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH iproute2-next 0/7] ip: more JSON
@ 2018-03-06  3:04 Stephen Hemminger
  2018-03-06  3:04 ` [PATCH iproute2-next 1/7] ip: add color and json support to neigh Stephen Hemminger
                   ` (6 more replies)
  0 siblings, 7 replies; 12+ messages in thread
From: Stephen Hemminger @ 2018-03-06  3:04 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

The ip command implementation of JSON was very spotty. Only address
and link were originally implemented. After doing route for next,
went ahead and implemented it for a bunch of the other sub commands.

Hopefully will reach full coverage soon.

Stephen Hemminger (7):
  ip: add color and json support to neigh
  ip: add json support to addrlabel
  ip: add json support to ip rule
  ip: add json support to ntable
  ip: add JSON support to netconf
  tcp_metrics; make tables const
  ip: jsonify tcp_metrics

 ip/ipaddrlabel.c |  40 ++++--
 ip/ipneigh.c     | 143 +++++++++++++------
 ip/ipnetconf.c   |  69 +++++----
 ip/ipntable.c    | 415 ++++++++++++++++++++++++++++++-------------------------
 ip/iprule.c      | 203 +++++++++++++++++----------
 ip/tcp_metrics.c | 188 +++++++++++++++----------
 6 files changed, 633 insertions(+), 425 deletions(-)

-- 
2.16.1

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH iproute2-next 1/7] ip: add color and json support to neigh
  2018-03-06  3:04 [PATCH iproute2-next 0/7] ip: more JSON Stephen Hemminger
@ 2018-03-06  3:04 ` Stephen Hemminger
  2018-03-06 16:38   ` David Ahern
  2018-03-06  3:04 ` [PATCH iproute2-next 2/7] ip: add json support to addrlabel Stephen Hemminger
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Stephen Hemminger @ 2018-03-06  3:04 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Use json_print to provide json (and color) support to
ip neigh command.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/ipneigh.c | 143 ++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 97 insertions(+), 46 deletions(-)

diff --git a/ip/ipneigh.c b/ip/ipneigh.c
index 0735424900f6..1f550e98e003 100644
--- a/ip/ipneigh.c
+++ b/ip/ipneigh.c
@@ -23,6 +23,7 @@
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 #define NUD_VALID	(NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
 #define MAX_ROUNDS	10
@@ -189,6 +190,48 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
 	return 0;
 }
 
+static void print_cacheinfo(const struct nda_cacheinfo *ci)
+{
+	static int hz;
+
+	if (!hz)
+		hz = get_user_hz();
+
+	if (ci->ndm_refcnt)
+		print_uint(PRINT_ANY, "refcnt",
+				" ref %u", ci->ndm_refcnt);
+
+	print_uint(PRINT_ANY,
+			 "used", " used %u", ci->ndm_used / hz);
+	print_uint(PRINT_ANY,
+			 "confirmed", "/%u", ci->ndm_confirmed / hz);
+	print_uint(PRINT_ANY,
+			 "updated", "/u", ci->ndm_updated / hz);
+}
+
+static void print_neigh_state(unsigned int nud)
+{
+
+	open_json_array(PRINT_JSON,
+			is_json_context() ?  "state" : "");
+
+#define PRINT_FLAG(f)						\
+	if (nud & NUD_##f) {					\
+		nud &= ~NUD_##f;				\
+		print_string(PRINT_ANY, NULL, " %s", #f);	\
+	}
+
+	PRINT_FLAG(INCOMPLETE);
+	PRINT_FLAG(REACHABLE);
+	PRINT_FLAG(STALE);
+	PRINT_FLAG(DELAY);
+	PRINT_FLAG(PROBE);
+	PRINT_FLAG(FAILED);
+	PRINT_FLAG(NOARP);
+	PRINT_FLAG(PERMANENT);
+#undef PRINT_FLAG
+	close_json_array(PRINT_JSON, NULL);
+}
 
 int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
@@ -262,65 +305,71 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 			return 0;
 	}
 
+	open_json_object(NULL);
 	if (n->nlmsg_type == RTM_DELNEIGH)
-		fprintf(fp, "Deleted ");
+		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 	else if (n->nlmsg_type == RTM_GETNEIGH)
-		fprintf(fp, "miss ");
+		print_null(PRINT_ANY, "miss", "%s ", "miss");
+
 	if (tb[NDA_DST]) {
-		fprintf(fp, "%s ",
-			format_host_rta(r->ndm_family, tb[NDA_DST]));
+		const char *dst;
+
+		dst = format_host_rta(r->ndm_family, tb[NDA_DST]);
+		print_color_string(PRINT_ANY,
+				   ifa_family_color(r->ndm_family),
+				   "dst", "%s ", dst);
 	}
-	if (!filter.index && r->ndm_ifindex)
-		fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex));
+
+	if (!filter.index && r->ndm_ifindex) {
+		if (!is_json_context())
+			fprintf(fp, "dev ");
+
+		print_color_string(PRINT_ANY, COLOR_IFNAME,
+				   "dev", "%s ",
+				   ll_index_to_name(r->ndm_ifindex));
+	}
+
 	if (tb[NDA_LLADDR]) {
+		const char *lladdr;
 		SPRINT_BUF(b1);
-		fprintf(fp, "lladdr %s", ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
-					      RTA_PAYLOAD(tb[NDA_LLADDR]),
-					      ll_index_to_type(r->ndm_ifindex),
-					      b1, sizeof(b1)));
-	}
-	if (r->ndm_flags & NTF_ROUTER) {
-		fprintf(fp, " router");
-	}
-	if (r->ndm_flags & NTF_PROXY) {
-		fprintf(fp, " proxy");
-	}
-	if (tb[NDA_CACHEINFO] && show_stats) {
-		struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
-		int hz = get_user_hz();
 
-		if (ci->ndm_refcnt)
-			printf(" ref %d", ci->ndm_refcnt);
-		fprintf(fp, " used %d/%d/%d", ci->ndm_used/hz,
-		       ci->ndm_confirmed/hz, ci->ndm_updated/hz);
-	}
+		lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
+				     RTA_PAYLOAD(tb[NDA_LLADDR]),
+				     ll_index_to_type(r->ndm_ifindex),
+				     b1, sizeof(b1));
 
-	if (tb[NDA_PROBES] && show_stats) {
-		__u32 p = rta_getattr_u32(tb[NDA_PROBES]);
+		if (!is_json_context())
+			fprintf(fp, "lladdr ");
 
-		fprintf(fp, " probes %u", p);
+		print_color_string(PRINT_ANY, COLOR_MAC,
+				   "lladdr", "%s", lladdr);
 	}
 
-	if (r->ndm_state) {
-		int nud = r->ndm_state;
-
-		fprintf(fp, " ");
-
-#define PRINT_FLAG(f) if (nud & NUD_##f) { \
-	nud &= ~NUD_##f; fprintf(fp, #f "%s", nud ? "," : ""); }
-		PRINT_FLAG(INCOMPLETE);
-		PRINT_FLAG(REACHABLE);
-		PRINT_FLAG(STALE);
-		PRINT_FLAG(DELAY);
-		PRINT_FLAG(PROBE);
-		PRINT_FLAG(FAILED);
-		PRINT_FLAG(NOARP);
-		PRINT_FLAG(PERMANENT);
-#undef PRINT_FLAG
+	if (r->ndm_flags & NTF_ROUTER)
+		print_null(PRINT_ANY, "router", " %s", "router");
+
+	if (r->ndm_flags & NTF_PROXY)
+		print_null(PRINT_ANY, "proxy", " %s", "proxy");
+
+	if (show_stats) {
+		if (tb[NDA_CACHEINFO])
+			print_cacheinfo(RTA_DATA(tb[NDA_CACHEINFO]));
+
+		if (tb[NDA_PROBES]) {
+			__u32 p = rta_getattr_u32(tb[NDA_PROBES]);
+
+			print_uint(PRINT_ANY, "probes",
+					 " probes %u", p);
+		}
 	}
-	fprintf(fp, "\n");
 
-	fflush(fp);
+	if (r->ndm_state)
+		print_neigh_state(r->ndm_state);
+
+	print_string(PRINT_FP, NULL, "\n", "");
+	close_json_object();
+	fflush(stdout);
+
 	return 0;
 }
 
@@ -479,10 +528,12 @@ static int do_show_or_flush(int argc, char **argv, int flush)
 		exit(1);
 	}
 
+	new_json_obj(json);
 	if (rtnl_dump_filter(&rth, print_neigh, stdout) < 0) {
 		fprintf(stderr, "Dump terminated\n");
 		exit(1);
 	}
+	delete_json_obj();
 
 	return 0;
 }
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH iproute2-next 2/7] ip: add json support to addrlabel
  2018-03-06  3:04 [PATCH iproute2-next 0/7] ip: more JSON Stephen Hemminger
  2018-03-06  3:04 ` [PATCH iproute2-next 1/7] ip: add color and json support to neigh Stephen Hemminger
@ 2018-03-06  3:04 ` Stephen Hemminger
  2018-03-06  3:04 ` [PATCH iproute2-next 3/7] ip: add json support to ip rule Stephen Hemminger
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Stephen Hemminger @ 2018-03-06  3:04 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Add missing json and color support to addrlabel display

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/ipaddrlabel.c | 40 +++++++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 13 deletions(-)

diff --git a/ip/ipaddrlabel.c b/ip/ipaddrlabel.c
index 7200bf542929..2f79c56dcead 100644
--- a/ip/ipaddrlabel.c
+++ b/ip/ipaddrlabel.c
@@ -38,6 +38,7 @@
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 #define IFAL_RTA(r)	((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))))
 #define IFAL_PAYLOAD(n)	NLMSG_PAYLOAD(n, sizeof(struct ifaddrlblmsg))
@@ -55,7 +56,6 @@ static void usage(void)
 
 int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
-	FILE *fp = (FILE *)arg;
 	struct ifaddrlblmsg *ifal = NLMSG_DATA(n);
 	int len = n->nlmsg_len;
 	struct rtattr *tb[IFAL_MAX+1];
@@ -69,28 +69,40 @@ int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg
 
 	parse_rtattr(tb, IFAL_MAX, IFAL_RTA(ifal), len);
 
+	open_json_object(NULL);
 	if (n->nlmsg_type == RTM_DELADDRLABEL)
-		fprintf(fp, "Deleted ");
+		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
 	if (tb[IFAL_ADDRESS]) {
-		fprintf(fp, "prefix %s/%u ",
-			format_host_rta(ifal->ifal_family,
-		                        tb[IFAL_ADDRESS]),
-			ifal->ifal_prefixlen);
+		const char *host
+			= format_host_rta(ifal->ifal_family,
+					  tb[IFAL_ADDRESS]);
+
+		print_string(PRINT_FP, NULL, "prefix ", NULL);
+		print_color_string(PRINT_ANY,
+				   ifa_family_color(ifal->ifal_family),
+				   "address", "%s", host);
+
+		print_uint(PRINT_ANY, "prefixlen", "/%u ",
+			   ifal->ifal_prefixlen);
 	}
 
-	if (ifal->ifal_index)
-		fprintf(fp, "dev %s ", ll_index_to_name(ifal->ifal_index));
+	if (ifal->ifal_index) {
+		print_string(PRINT_FP, NULL, "dev ", NULL);
+		print_color_string(PRINT_ANY, COLOR_IFNAME,
+				   "ifname", "%s ",
+				   ll_index_to_name(ifal->ifal_index));
+	}
 
 	if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(uint32_t)) {
-		uint32_t label;
+		uint32_t label = rta_getattr_u32(RTA_DATA(tb[IFAL_LABEL]));
 
-		memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label));
-		fprintf(fp, "label %u ", label);
+		print_uint(PRINT_ANY,
+			   "label", "label %u ", label);
 	}
+	print_string(PRINT_FP, NULL, "\n", "");
+	close_json_object();
 
-	fprintf(fp, "\n");
-	fflush(fp);
 	return 0;
 }
 
@@ -111,10 +123,12 @@ static int ipaddrlabel_list(int argc, char **argv)
 		return 1;
 	}
 
+	new_json_obj(json);
 	if (rtnl_dump_filter(&rth, print_addrlabel, stdout) < 0) {
 		fprintf(stderr, "Dump terminated\n");
 		return 1;
 	}
+	delete_json_obj();
 
 	return 0;
 }
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH iproute2-next 3/7] ip: add json support to ip rule
  2018-03-06  3:04 [PATCH iproute2-next 0/7] ip: more JSON Stephen Hemminger
  2018-03-06  3:04 ` [PATCH iproute2-next 1/7] ip: add color and json support to neigh Stephen Hemminger
  2018-03-06  3:04 ` [PATCH iproute2-next 2/7] ip: add json support to addrlabel Stephen Hemminger
@ 2018-03-06  3:04 ` Stephen Hemminger
  2018-03-06 16:51   ` David Ahern
  2018-03-06  3:04 ` [PATCH iproute2-next 4/7] ip: add json support to ntable Stephen Hemminger
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Stephen Hemminger @ 2018-03-06  3:04 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

More JSON and colorizing.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/iprule.c | 203 ++++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 130 insertions(+), 73 deletions(-)

diff --git a/ip/iprule.c b/ip/iprule.c
index 6fdc9b5efa00..ab1e0c15f877 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -26,6 +26,7 @@
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 enum list_action {
 	IPRULE_LIST,
@@ -179,13 +180,12 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 
 int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
-	FILE *fp = (FILE *)arg;
+	FILE *fp = arg;
 	struct fib_rule_hdr *frh = NLMSG_DATA(n);
 	int len = n->nlmsg_len;
 	int host_len = -1;
-	__u32 table;
+	__u32 table, prio = 0;
 	struct rtattr *tb[FRA_MAX+1];
-
 	SPRINT_BUF(b1);
 
 	if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE)
@@ -202,50 +202,66 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	if (!filter_nlmsg(n, tb, host_len))
 		return 0;
 
+	open_json_object(NULL);
 	if (n->nlmsg_type == RTM_DELRULE)
-		fprintf(fp, "Deleted ");
+		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
 	if (tb[FRA_PRIORITY])
-		fprintf(fp, "%u:\t",
-			rta_getattr_u32(tb[FRA_PRIORITY]));
-	else
-		fprintf(fp, "0:\t");
+		prio = rta_getattr_u32(tb[FRA_PRIORITY]);
+
+	print_uint(PRINT_ANY, "priority",
+		   "%u:\t", prio);
 
 	if (frh->flags & FIB_RULE_INVERT)
-		fprintf(fp, "not ");
+		print_null(PRINT_ANY, "not", "not ", NULL);
+
+	if (!is_json_context())
+		fprintf(fp, "from ");
 
 	if (tb[FRA_SRC]) {
-		if (frh->src_len != host_len) {
-			fprintf(fp, "from %s/%u ",
-				rt_addr_n2a_rta(frh->family, tb[FRA_SRC]),
-				frh->src_len);
-		} else {
-			fprintf(fp, "from %s ",
-				format_host_rta(frh->family, tb[FRA_SRC]));
-		}
+		const char *src
+			= rt_addr_n2a_rta(frh->family, tb[FRA_SRC]);
+
+		print_color_string(PRINT_ANY,
+				   ifa_family_color(frh->family),
+				   "src", "%s", src);
+		if (frh->src_len != host_len)
+			print_uint(PRINT_ANY, "srclen",
+				   "/%u", frh->src_len);
 	} else if (frh->src_len) {
-		fprintf(fp, "from 0/%d ", frh->src_len);
+		print_string(PRINT_ANY,
+			     "src", "%s", "0");
+		print_uint(PRINT_ANY,
+			   "srclen", "/%u", frh->src_len);
 	} else {
-		fprintf(fp, "from all ");
+		print_string(PRINT_ANY,
+			     "src", "%s", "all");
 	}
 
+	if (!is_json_context())
+		fprintf(fp, " to ");
+
 	if (tb[FRA_DST]) {
-		if (frh->dst_len != host_len) {
-			fprintf(fp, "to %s/%u ",
-				rt_addr_n2a_rta(frh->family, tb[FRA_DST]),
-				frh->dst_len);
-		} else {
-			fprintf(fp, "to %s ",
-				format_host_rta(frh->family, tb[FRA_DST]));
-		}
+		const char *dst
+			= rt_addr_n2a_rta(frh->family, tb[FRA_DST]);
+
+		print_color_string(PRINT_ANY,
+				   ifa_family_color(frh->family),
+				   "dst", "%s", dst);
+		if (frh->dst_len != host_len)
+			print_uint(PRINT_ANY, "dstlen",
+				   "/%u ", frh->dst_len);
 	} else if (frh->dst_len) {
-		fprintf(fp, "to 0/%d ", frh->dst_len);
+		print_string(PRINT_ANY,
+			     "dst", "%s", "0");
+		print_uint(PRINT_ANY,
+			   "dstlen", "/%u ", frh->dst_len);
 	}
 
 	if (frh->tos) {
-		SPRINT_BUF(b1);
-		fprintf(fp, "tos %s ",
-			rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1)));
+		print_string(PRINT_ANY, "tos",
+			     "tos %s ",
+			     rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1)));
 	}
 
 	if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
@@ -255,53 +271,82 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 			mark = rta_getattr_u32(tb[FRA_FWMARK]);
 
 		if (tb[FRA_FWMASK] &&
-		    (mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF)
-			fprintf(fp, "fwmark 0x%x/0x%x ", mark, mask);
-		else
-			fprintf(fp, "fwmark 0x%x ", mark);
+		    (mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF) {
+			print_0xhex(PRINT_ANY, "fwmark",
+				    "fwmark 0x%x", mark);
+			print_0xhex(PRINT_ANY, "fwmask",
+				    "/0x%x ",  mask);
+		} else {
+			print_0xhex(PRINT_ANY, "fwmark",
+				    "fwmark 0x%x ", mark);
+		}
 	}
 
 	if (tb[FRA_IFNAME]) {
-		fprintf(fp, "iif %s ", rta_getattr_str(tb[FRA_IFNAME]));
+		if (!is_json_context())
+			fprintf(fp, "iif ");
+		print_color_string(PRINT_ANY, COLOR_IFNAME,
+				   "iif", "%s ",
+				   rta_getattr_str(tb[FRA_IFNAME]));
+
 		if (frh->flags & FIB_RULE_IIF_DETACHED)
-			fprintf(fp, "[detached] ");
+			print_null(PRINT_ANY, "iif_detached",
+				   "[detached] ", NULL);
 	}
 
 	if (tb[FRA_OIFNAME]) {
-		fprintf(fp, "oif %s ", rta_getattr_str(tb[FRA_OIFNAME]));
+		if (!is_json_context())
+			fprintf(fp, "oif ");
+
+		print_color_string(PRINT_ANY, COLOR_IFNAME,
+				   "oif", "%s ",
+				   rta_getattr_str(tb[FRA_OIFNAME]));
+
 		if (frh->flags & FIB_RULE_OIF_DETACHED)
-			fprintf(fp, "[detached] ");
+			print_null(PRINT_ANY, "oif_detached",
+				   "[detached] ", NULL);
 	}
 
 	if (tb[FRA_L3MDEV]) {
-		if (rta_getattr_u8(tb[FRA_L3MDEV]))
-			fprintf(fp, "lookup [l3mdev-table] ");
+		__u8 mdev = rta_getattr_u8(tb[FRA_L3MDEV]);
+
+		if (mdev)
+			print_null(PRINT_ANY, "l3mdev",
+				   "lookup [l3mdev-table] ", NULL);
 	}
 
 	if (tb[FRA_UID_RANGE]) {
 		struct fib_rule_uid_range *r = RTA_DATA(tb[FRA_UID_RANGE]);
 
-		fprintf(fp, "uidrange %u-%u ", r->start, r->end);
+		print_uint(PRINT_ANY, "uid_start",
+			   "uidrange %u", r->start);
+		print_uint(PRINT_ANY, "uid_end",
+			   "-%u ", r->end);
 	}
 
 	table = frh_get_table(frh, tb);
 	if (table) {
-		fprintf(fp, "lookup %s ",
-			rtnl_rttable_n2a(table, b1, sizeof(b1)));
+		print_string(PRINT_ANY, "table",
+			     "lookup %s ",
+			     rtnl_rttable_n2a(table, b1, sizeof(b1)));
 
 		if (tb[FRA_SUPPRESS_PREFIXLEN]) {
 			int pl = rta_getattr_u32(tb[FRA_SUPPRESS_PREFIXLEN]);
 
 			if (pl != -1)
-				fprintf(fp, "suppress_prefixlength %d ", pl);
+				print_int(PRINT_ANY, "suppress_prefixlen",
+					  "suppress_prefixlength %d ", pl);
 		}
+
 		if (tb[FRA_SUPPRESS_IFGROUP]) {
 			int group = rta_getattr_u32(tb[FRA_SUPPRESS_IFGROUP]);
 
 			if (group != -1) {
-				SPRINT_BUF(b1);
-				fprintf(fp, "suppress_ifgroup %s ",
-					rtnl_group_n2a(group, b1, sizeof(b1)));
+				const char *grname
+					= rtnl_group_n2a(group, b1, sizeof(b1));
+
+				print_string(PRINT_ANY, "suppress_ifgroup",
+					     "suppress_ifgroup %s ", grname);
 			}
 		}
 	}
@@ -311,47 +356,57 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		__u32 from = to>>16;
 
 		to &= 0xFFFF;
-		if (from) {
-			fprintf(fp, "realms %s/",
-				rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
-		}
-		fprintf(fp, "%s ",
-			rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
+		if (from)
+			print_string(PRINT_ANY,
+				     "flow_from", "realms %s/",
+				     rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+
+		print_string(PRINT_ANY, "flow_to", "%s ",
+			     rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
 	}
 
 	if (frh->action == RTN_NAT) {
 		if (tb[RTA_GATEWAY]) {
-			fprintf(fp, "map-to %s ",
-				format_host_rta(frh->family,
-						tb[RTA_GATEWAY]));
-		} else
-			fprintf(fp, "masquerade");
+			const char *gateway;
+
+			gateway = format_host_rta(frh->family, tb[RTA_GATEWAY]);
+
+			print_string(PRINT_ANY, "nat_gateway",
+				     "map-to %s ", gateway);
+		} else {
+			print_null(PRINT_ANY, "masquerade", "masquerade", NULL);
+		}
 	} else if (frh->action == FR_ACT_GOTO) {
-		fprintf(fp, "goto ");
 		if (tb[FRA_GOTO])
-			fprintf(fp, "%u", rta_getattr_u32(tb[FRA_GOTO]));
+			print_uint(PRINT_ANY, "goto",
+				   "goto %u", rta_getattr_u32(tb[FRA_GOTO]));
 		else
-			fprintf(fp, "none");
+			print_string(PRINT_ANY, "goto",
+				     "goto %s", "none");
+
 		if (frh->flags & FIB_RULE_UNRESOLVED)
-			fprintf(fp, " [unresolved]");
-	} else if (frh->action == FR_ACT_NOP)
-		fprintf(fp, "nop");
-	else if (frh->action != FR_ACT_TO_TBL)
-		fprintf(fp, "%s",
-			rtnl_rtntype_n2a(frh->action,
-					 b1, sizeof(b1)));
+			print_null(PRINT_ANY, "unresolved", "unresolved", NULL);
+	} else if (frh->action == FR_ACT_NOP) {
+		print_null(PRINT_ANY, "nop", "nop", NULL);
+	} else if (frh->action != FR_ACT_TO_TBL) {
+		print_string(PRINT_ANY, "to_tbl",
+			     "%s",
+			     rtnl_rtntype_n2a(frh->action,
+					      b1, sizeof(b1)));
+	}
 
 	if (tb[FRA_PROTOCOL]) {
 		__u8 protocol = rta_getattr_u8(tb[FRA_PROTOCOL]);
 
 		if ((protocol && protocol != RTPROT_KERNEL) ||
 		    show_details > 0) {
-			fprintf(fp, " proto %s ",
-				rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
+			print_string(PRINT_ANY, "protocol",
+				     " proto %s ",
+				     rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
 		}
 	}
-
-	fprintf(fp, "\n");
+	print_string(PRINT_FP, NULL, "\n", "");
+	close_json_object();
 	fflush(fp);
 	return 0;
 }
@@ -554,10 +609,12 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
 		return 1;
 	}
 
+	new_json_obj(json);
 	if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
 		fprintf(stderr, "Dump terminated\n");
 		return 1;
 	}
+	delete_json_obj();
 
 	return 0;
 }
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH iproute2-next 4/7] ip: add json support to ntable
  2018-03-06  3:04 [PATCH iproute2-next 0/7] ip: more JSON Stephen Hemminger
                   ` (2 preceding siblings ...)
  2018-03-06  3:04 ` [PATCH iproute2-next 3/7] ip: add json support to ip rule Stephen Hemminger
@ 2018-03-06  3:04 ` Stephen Hemminger
  2018-03-06 16:53   ` David Ahern
  2018-03-06  3:04 ` [PATCH iproute2-next 5/7] ip: add JSON support to netconf Stephen Hemminger
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Stephen Hemminger @ 2018-03-06  3:04 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Add JSON (and limited color) to ip neighbor table parameter output.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/ipntable.c | 415 ++++++++++++++++++++++++++++++++--------------------------
 1 file changed, 226 insertions(+), 189 deletions(-)

diff --git a/ip/ipntable.c b/ip/ipntable.c
index 2f72c989f35d..f6dff28ecbb2 100644
--- a/ip/ipntable.c
+++ b/ip/ipntable.c
@@ -31,6 +31,7 @@
 
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 static struct
 {
@@ -338,274 +339,308 @@ static const char *ntable_strtime_delta(__u32 msec)
 	return str;
 }
 
-static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+static void print_ndtconfig(const struct ndt_config *ndtc)
 {
-	FILE *fp = (FILE *)arg;
-	struct ndtmsg *ndtm = NLMSG_DATA(n);
-	int len = n->nlmsg_len;
-	struct rtattr *tb[NDTA_MAX+1];
-	struct rtattr *tpb[NDTPA_MAX+1];
-	int ret;
 
-	if (n->nlmsg_type != RTM_NEWNEIGHTBL) {
-		fprintf(stderr, "Not NEIGHTBL: %08x %08x %08x\n",
-			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
-		return 0;
-	}
-	len -= NLMSG_LENGTH(sizeof(*ndtm));
-	if (len < 0) {
-		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
-		return -1;
-	}
+	print_uint(PRINT_ANY, "key_length",
+		     "    config key_len %u ", ndtc->ndtc_key_len);
+	print_uint(PRINT_ANY, "entry_size",
+		     "entry_size %u ", ndtc->ndtc_entry_size);
+	print_uint(PRINT_ANY, "entries",
+		   "entries %u ", ndtc->ndtc_entries);
 
-	if (preferred_family && preferred_family != ndtm->ndtm_family)
-		return 0;
+	print_string(PRINT_FP, NULL, "%s", _SL_);
 
-	parse_rtattr(tb, NDTA_MAX, NDTA_RTA(ndtm),
-		     n->nlmsg_len - NLMSG_LENGTH(sizeof(*ndtm)));
+	print_string(PRINT_ANY, "last_flush",
+		     "        last_flush %s ",
+		     ntable_strtime_delta(ndtc->ndtc_last_flush));
+	print_string(PRINT_ANY, "last_rand",
+		     "last_rand %s ",
+		     ntable_strtime_delta(ndtc->ndtc_last_rand));
 
-	if (tb[NDTA_NAME]) {
-		const char *name = rta_getattr_str(tb[NDTA_NAME]);
+	print_string(PRINT_FP, NULL, "%s", _SL_);
 
-		if (filter.name && strcmp(filter.name, name))
-			return 0;
-	}
-	if (tb[NDTA_PARMS]) {
-		parse_rtattr(tpb, NDTPA_MAX, RTA_DATA(tb[NDTA_PARMS]),
-			     RTA_PAYLOAD(tb[NDTA_PARMS]));
+	print_uint(PRINT_ANY, "hash_rnd",
+		   "        hash_rnd %u ", ndtc->ndtc_hash_rnd);
+	print_0xhex(PRINT_ANY, "hash_mask",
+		    "hash_mask %08x ", ndtc->ndtc_hash_mask);
 
-		if (tpb[NDTPA_IFINDEX]) {
-			__u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
+	print_uint(PRINT_ANY, "hash_chain_gc",
+		   "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc);
+	print_uint(PRINT_ANY, "proxy_qlen",
+		   "proxy_qlen %u ", ndtc->ndtc_proxy_qlen);
 
-			if (filter.index && filter.index != ifindex)
-				return 0;
-		} else {
-			if (filter.index && filter.index != NONE_DEV)
-				return 0;
-		}
+	print_string(PRINT_FP, NULL, "%s", _SL_);
+}
+
+static void print_ndtparams(struct rtattr *tpb[])
+{
+
+	if (tpb[NDTPA_IFINDEX]) {
+		__u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
+
+		print_string(PRINT_FP, NULL, "    dev ", NULL);
+		print_color_string(PRINT_ANY, COLOR_IFNAME,
+				   "dev", "%s ", ll_index_to_name(ifindex));
+		print_string(PRINT_FP, NULL, "%s", _SL_);
 	}
 
-	if (ndtm->ndtm_family == AF_INET)
-		fprintf(fp, "inet ");
-	else if (ndtm->ndtm_family == AF_INET6)
-		fprintf(fp, "inet6 ");
-	else if (ndtm->ndtm_family == AF_DECnet)
-		fprintf(fp, "dnet ");
-	else
-		fprintf(fp, "(%d) ", ndtm->ndtm_family);
+	print_string(PRINT_FP, NULL, "    ", NULL);
+	if (tpb[NDTPA_REFCNT]) {
+		__u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]);
 
-	if (tb[NDTA_NAME]) {
-		const char *name = rta_getattr_str(tb[NDTA_NAME]);
+		print_uint(PRINT_ANY, "refcnt", "refcnt %u ", refcnt);
+	}
 
-		fprintf(fp, "%s ", name);
+	if (tpb[NDTPA_REACHABLE_TIME]) {
+		__u64 reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]);
+
+		print_uint(PRINT_ANY, "reachable",
+			     "reachable %llu ", reachable);
 	}
 
-	fprintf(fp, "%s", _SL_);
+	if (tpb[NDTPA_BASE_REACHABLE_TIME]) {
+		__u64 breachable
+			= rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]);
 
-	ret = (tb[NDTA_THRESH1] || tb[NDTA_THRESH2] || tb[NDTA_THRESH3] ||
-	       tb[NDTA_GC_INTERVAL]);
-	if (ret)
-		fprintf(fp, "    ");
 
-	if (tb[NDTA_THRESH1]) {
-		__u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]);
+		print_uint(PRINT_ANY, "base_reachable",
+			     "base_reachable %llu ", breachable);
+	}
 
-		fprintf(fp, "thresh1 %u ", thresh1);
+	if (tpb[NDTPA_RETRANS_TIME]) {
+		__u64 retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]);
+
+		print_uint(PRINT_ANY, "retrans", "retrans %llu ", retrans);
 	}
-	if (tb[NDTA_THRESH2]) {
-		__u32 thresh2 = rta_getattr_u32(tb[NDTA_THRESH2]);
 
-		fprintf(fp, "thresh2 %u ", thresh2);
+	print_string(PRINT_FP, NULL, "%s    ", _SL_);
+
+	if (tpb[NDTPA_GC_STALETIME]) {
+		__u64 gc_stale
+			= rta_getattr_u64(tpb[NDTPA_GC_STALETIME]);
+
+		print_uint(PRINT_ANY, "gc_stale", "gc_stale %llu ", gc_stale);
 	}
-	if (tb[NDTA_THRESH3]) {
-		__u32 thresh3 = rta_getattr_u32(tb[NDTA_THRESH3]);
 
-		fprintf(fp, "thresh3 %u ", thresh3);
+	if (tpb[NDTPA_DELAY_PROBE_TIME]) {
+		__u64 delay_probe
+			= rta_getattr_u64(tpb[NDTPA_DELAY_PROBE_TIME]);
+
+		print_uint(PRINT_ANY, "delay_probe",
+			     "delay_probe %llu ", delay_probe);
 	}
-	if (tb[NDTA_GC_INTERVAL]) {
-		unsigned long long gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]);
 
-		fprintf(fp, "gc_int %llu ", gc_int);
+	if (tpb[NDTPA_QUEUE_LEN]) {
+		__u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]);
+
+		print_uint(PRINT_ANY, "queue", "queue %u ", queue);
 	}
 
-	if (ret)
-		fprintf(fp, "%s", _SL_);
+	print_string(PRINT_FP, NULL, "%s    ", _SL_);
 
-	if (tb[NDTA_CONFIG] && show_stats) {
-		struct ndt_config *ndtc = RTA_DATA(tb[NDTA_CONFIG]);
+	if (tpb[NDTPA_APP_PROBES]) {
+		__u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]);
 
-		fprintf(fp, "    ");
-		fprintf(fp, "config ");
+		print_uint(PRINT_ANY, "app_probes",
+			   "app_probes %u ", aprobe);
+	}
 
-		fprintf(fp, "key_len %u ", ndtc->ndtc_key_len);
-		fprintf(fp, "entry_size %u ", ndtc->ndtc_entry_size);
-		fprintf(fp, "entries %u ", ndtc->ndtc_entries);
+	if (tpb[NDTPA_UCAST_PROBES]) {
+		__u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]);
 
-		fprintf(fp, "%s", _SL_);
-		fprintf(fp, "        ");
+		print_uint(PRINT_ANY, "ucast_probes",
+			   "ucast_probes %u ", uprobe);
+	}
 
-		fprintf(fp, "last_flush %s ",
-			ntable_strtime_delta(ndtc->ndtc_last_flush));
-		fprintf(fp, "last_rand %s ",
-			ntable_strtime_delta(ndtc->ndtc_last_rand));
+	if (tpb[NDTPA_MCAST_PROBES]) {
+		__u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]);
 
-		fprintf(fp, "%s", _SL_);
-		fprintf(fp, "        ");
+		print_uint(PRINT_ANY, "mcast_probes",
+			   "mcast_probes %u ", mprobe);
+	}
 
-		fprintf(fp, "hash_rnd %u ", ndtc->ndtc_hash_rnd);
-		fprintf(fp, "hash_mask %08x ", ndtc->ndtc_hash_mask);
+	print_string(PRINT_FP, NULL, "%s    ", _SL_);
 
-		fprintf(fp, "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc);
-		fprintf(fp, "proxy_qlen %u ", ndtc->ndtc_proxy_qlen);
+	if (tpb[NDTPA_ANYCAST_DELAY]) {
+		__u64 anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]);
 
-		fprintf(fp, "%s", _SL_);
+		print_uint(PRINT_ANY, "anycast_delay",
+			     "anycast_delay %llu ", anycast_delay);
 	}
 
-	if (tb[NDTA_PARMS]) {
-		if (tpb[NDTPA_IFINDEX]) {
-			__u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
+	if (tpb[NDTPA_PROXY_DELAY]) {
+		__u64 proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]);
 
-			fprintf(fp, "    ");
-			fprintf(fp, "dev %s ", ll_index_to_name(ifindex));
-			fprintf(fp, "%s", _SL_);
-		}
+		print_uint(PRINT_ANY, "proxy_delay",
+			     "proxy_delay %llu ", proxy_delay);
+	}
 
-		fprintf(fp, "    ");
+	if (tpb[NDTPA_PROXY_QLEN]) {
+		__u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]);
 
-		if (tpb[NDTPA_REFCNT]) {
-			__u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]);
+		print_uint(PRINT_ANY, "proxy_queue", "proxy_queue %u ", pqueue);
+	}
 
-			fprintf(fp, "refcnt %u ", refcnt);
-		}
-		if (tpb[NDTPA_REACHABLE_TIME]) {
-			unsigned long long reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]);
+	if (tpb[NDTPA_LOCKTIME]) {
+		__u64 locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]);
 
-			fprintf(fp, "reachable %llu ", reachable);
-		}
-		if (tpb[NDTPA_BASE_REACHABLE_TIME]) {
-			unsigned long long breachable = rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]);
+		print_uint(PRINT_ANY, "locktime",
+			     "locktime %llu ", locktime);
+	}
 
-			fprintf(fp, "base_reachable %llu ", breachable);
-		}
-		if (tpb[NDTPA_RETRANS_TIME]) {
-			unsigned long long retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]);
+	print_string(PRINT_FP, NULL, "%s", _SL_);
+}
 
-			fprintf(fp, "retrans %llu ", retrans);
-		}
+static void print_ndtstats(const struct ndt_stats *ndts)
+{
 
-		fprintf(fp, "%s", _SL_);
+	print_string(PRINT_FP, NULL, "    stats ", NULL);
 
-		fprintf(fp, "    ");
+	print_uint(PRINT_ANY, "allocs", "allocs %llu ",
+		     ndts->ndts_allocs);
+	print_uint(PRINT_ANY, "destroys", "destroys %llu ",
+		     ndts->ndts_destroys);
+	print_uint(PRINT_ANY, "hash_grows", "hash_grows %llu ",
+		     ndts->ndts_hash_grows);
 
-		if (tpb[NDTPA_GC_STALETIME]) {
-			unsigned long long gc_stale = rta_getattr_u64(tpb[NDTPA_GC_STALETIME]);
+	print_string(PRINT_FP, NULL, "%s    ", _SL_);
 
-			fprintf(fp, "gc_stale %llu ", gc_stale);
-		}
-		if (tpb[NDTPA_DELAY_PROBE_TIME]) {
-			unsigned long long delay_probe = rta_getattr_u64(tpb[NDTPA_DELAY_PROBE_TIME]);
+	print_uint(PRINT_ANY, "res_failed", "res_failed %llu ",
+		     ndts->ndts_res_failed);
+	print_uint(PRINT_ANY, "lookups", "lookups %llu ",
+		     ndts->ndts_lookups);
+	print_uint(PRINT_ANY, "hits", "hits %llu ",
+		     ndts->ndts_hits);
 
-			fprintf(fp, "delay_probe %llu ", delay_probe);
-		}
-		if (tpb[NDTPA_QUEUE_LEN]) {
-			__u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]);
+	print_string(PRINT_FP, NULL, "%s    ", _SL_);
 
-			fprintf(fp, "queue %u ", queue);
-		}
+	print_uint(PRINT_ANY, "rcv_probes_mcast", "rcv_probes_mcast %llu ",
+		     ndts->ndts_rcv_probes_mcast);
+	print_uint(PRINT_ANY, "rcv_probes_ucast", "rcv_probes_ucast %llu ",
+		     ndts->ndts_rcv_probes_ucast);
 
-		fprintf(fp, "%s", _SL_);
+	print_string(PRINT_FP, NULL, "%s    ", _SL_);
 
-		fprintf(fp, "    ");
+	print_uint(PRINT_ANY, "periodic_gc_runs", "periodic_gc_runs %llu ",
+		     ndts->ndts_periodic_gc_runs);
+	print_uint(PRINT_ANY, "forced_gc_runs", "forced_gc_runs %llu ",
+		     ndts->ndts_forced_gc_runs);
 
-		if (tpb[NDTPA_APP_PROBES]) {
-			__u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]);
+	print_string(PRINT_FP, NULL, "%s", _SL_);
+}
 
-			fprintf(fp, "app_probes %u ", aprobe);
-		}
-		if (tpb[NDTPA_UCAST_PROBES]) {
-			__u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]);
+static int print_ntable(const struct sockaddr_nl *who,
+			struct nlmsghdr *n, void *arg)
+{
+	FILE *fp = (FILE *)arg;
+	struct ndtmsg *ndtm = NLMSG_DATA(n);
+	int len = n->nlmsg_len;
+	struct rtattr *tb[NDTA_MAX+1];
+	struct rtattr *tpb[NDTPA_MAX+1];
+	int ret;
 
-			fprintf(fp, "ucast_probes %u ", uprobe);
-		}
-		if (tpb[NDTPA_MCAST_PROBES]) {
-			__u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]);
+	if (n->nlmsg_type != RTM_NEWNEIGHTBL) {
+		fprintf(stderr, "Not NEIGHTBL: %08x %08x %08x\n",
+			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+		return 0;
+	}
+	len -= NLMSG_LENGTH(sizeof(*ndtm));
+	if (len < 0) {
+		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+		return -1;
+	}
 
-			fprintf(fp, "mcast_probes %u ", mprobe);
-		}
+	if (preferred_family && preferred_family != ndtm->ndtm_family)
+		return 0;
 
-		fprintf(fp, "%s", _SL_);
+	parse_rtattr(tb, NDTA_MAX, NDTA_RTA(ndtm),
+		     n->nlmsg_len - NLMSG_LENGTH(sizeof(*ndtm)));
 
-		fprintf(fp, "    ");
+	if (tb[NDTA_NAME]) {
+		const char *name = rta_getattr_str(tb[NDTA_NAME]);
 
-		if (tpb[NDTPA_ANYCAST_DELAY]) {
-			unsigned long long anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]);
+		if (filter.name && strcmp(filter.name, name))
+			return 0;
+	}
 
-			fprintf(fp, "anycast_delay %llu ", anycast_delay);
-		}
-		if (tpb[NDTPA_PROXY_DELAY]) {
-			unsigned long long proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]);
+	if (tb[NDTA_PARMS]) {
+		parse_rtattr(tpb, NDTPA_MAX, RTA_DATA(tb[NDTA_PARMS]),
+			     RTA_PAYLOAD(tb[NDTA_PARMS]));
 
-			fprintf(fp, "proxy_delay %llu ", proxy_delay);
-		}
-		if (tpb[NDTPA_PROXY_QLEN]) {
-			__u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]);
+		if (tpb[NDTPA_IFINDEX]) {
+			__u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
 
-			fprintf(fp, "proxy_queue %u ", pqueue);
+			if (filter.index && filter.index != ifindex)
+				return 0;
+		} else {
+			if (filter.index && filter.index != NONE_DEV)
+				return 0;
 		}
-		if (tpb[NDTPA_LOCKTIME]) {
-			unsigned long long locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]);
+	}
 
-			fprintf(fp, "locktime %llu ", locktime);
-		}
+	open_json_object(NULL);
+	print_string(PRINT_ANY, "family",
+		     "%s ", family_name(ndtm->ndtm_family));
+
+	if (tb[NDTA_NAME]) {
+		const char *name = rta_getattr_str(tb[NDTA_NAME]);
 
-		fprintf(fp, "%s", _SL_);
+		print_string(PRINT_ANY, "name",
+			     "%s ", name);
 	}
 
-	if (tb[NDTA_STATS] && show_stats) {
-		struct ndt_stats *ndts = RTA_DATA(tb[NDTA_STATS]);
+	print_string(PRINT_FP, NULL, "%s", _SL_);
 
-		fprintf(fp, "    ");
-		fprintf(fp, "stats ");
+	ret = (tb[NDTA_THRESH1] || tb[NDTA_THRESH2] || tb[NDTA_THRESH3] ||
+	       tb[NDTA_GC_INTERVAL]);
+	if (ret)
+		print_string(PRINT_FP, NULL, "    ", NULL);
 
-		fprintf(fp, "allocs %llu ",
-			(unsigned long long) ndts->ndts_allocs);
-		fprintf(fp, "destroys %llu ",
-			(unsigned long long) ndts->ndts_destroys);
-		fprintf(fp, "hash_grows %llu ",
-			(unsigned long long) ndts->ndts_hash_grows);
+	if (tb[NDTA_THRESH1]) {
+		__u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]);
 
-		fprintf(fp, "%s", _SL_);
-		fprintf(fp, "        ");
+		print_uint(PRINT_ANY, "thresh1",
+			   "thresh1 %u ", thresh1);
+	}
 
-		fprintf(fp, "res_failed %llu ",
-			(unsigned long long) ndts->ndts_res_failed);
-		fprintf(fp, "lookups %llu ",
-			(unsigned long long) ndts->ndts_lookups);
-		fprintf(fp, "hits %llu ",
-			(unsigned long long) ndts->ndts_hits);
+	if (tb[NDTA_THRESH2]) {
+		__u32 thresh2 = rta_getattr_u32(tb[NDTA_THRESH2]);
 
-		fprintf(fp, "%s", _SL_);
-		fprintf(fp, "        ");
+		print_uint(PRINT_ANY, "thresh2",
+			   "thresh2 %u ", thresh2);
+	}
 
-		fprintf(fp, "rcv_probes_mcast %llu ",
-			(unsigned long long) ndts->ndts_rcv_probes_mcast);
-		fprintf(fp, "rcv_probes_ucast %llu ",
-			(unsigned long long) ndts->ndts_rcv_probes_ucast);
+	if (tb[NDTA_THRESH3]) {
+		__u32 thresh3 = rta_getattr_u32(tb[NDTA_THRESH3]);
 
-		fprintf(fp, "%s", _SL_);
-		fprintf(fp, "        ");
+		print_uint(PRINT_ANY, "thresh3",
+			   "thresh3 %u ", thresh3);
+	}
 
-		fprintf(fp, "periodic_gc_runs %llu ",
-			(unsigned long long) ndts->ndts_periodic_gc_runs);
-		fprintf(fp, "forced_gc_runs %llu ",
-			(unsigned long long) ndts->ndts_forced_gc_runs);
+	if (tb[NDTA_GC_INTERVAL]) {
+		__u64 gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]);
 
-		fprintf(fp, "%s", _SL_);
+		print_uint(PRINT_ANY, "gc_interval",
+			   "gc_int %llu ", gc_int);
 	}
 
-	fprintf(fp, "\n");
+	if (ret)
+		print_string(PRINT_FP, NULL, "%s", _SL_);
 
+	if (tb[NDTA_CONFIG] && show_stats)
+		print_ndtconfig(RTA_DATA(tb[NDTA_CONFIG]));
+
+	if (tb[NDTA_PARMS])
+		print_ndtparams(tpb);
+
+	if (tb[NDTA_STATS] && show_stats)
+		print_ndtstats(RTA_DATA(tb[NDTA_STATS]));
+
+	print_string(PRINT_FP, NULL, "\n", "");
+	close_json_object();
 	fflush(fp);
+
 	return 0;
 }
 
@@ -643,10 +678,12 @@ static int ipntable_show(int argc, char **argv)
 		exit(1);
 	}
 
+	new_json_obj(json);
 	if (rtnl_dump_filter(&rth, print_ntable, stdout) < 0) {
 		fprintf(stderr, "Dump terminated\n");
 		exit(1);
 	}
+	delete_json_obj();
 
 	return 0;
 }
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH iproute2-next 5/7] ip: add JSON support to netconf
  2018-03-06  3:04 [PATCH iproute2-next 0/7] ip: more JSON Stephen Hemminger
                   ` (3 preceding siblings ...)
  2018-03-06  3:04 ` [PATCH iproute2-next 4/7] ip: add json support to ntable Stephen Hemminger
@ 2018-03-06  3:04 ` Stephen Hemminger
  2018-03-06  3:05 ` [PATCH iproute2-next 6/7] tcp_metrics; make tables const Stephen Hemminger
  2018-03-06  3:05 ` [PATCH iproute2-next 7/7] ip: jsonify tcp_metrics Stephen Hemminger
  6 siblings, 0 replies; 12+ messages in thread
From: Stephen Hemminger @ 2018-03-06  3:04 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Basic JSON support for ip netconf command.
Also cleanup some checkpatch warnings about long lines.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/ipnetconf.c | 69 +++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 39 insertions(+), 30 deletions(-)

diff --git a/ip/ipnetconf.c b/ip/ipnetconf.c
index 76e639a813e4..03f98ace9145 100644
--- a/ip/ipnetconf.c
+++ b/ip/ipnetconf.c
@@ -29,6 +29,10 @@ static struct {
 	int ifindex;
 } filter;
 
+static const char * const rp_filter_names[] = {
+	"off", "strict", "loose"
+};
+
 static void usage(void) __attribute__((noreturn));
 
 static void usage(void)
@@ -37,9 +41,12 @@ static void usage(void)
 	exit(-1);
 }
 
-static void print_onoff(FILE *f, const char *flag, __u32 val)
+static void print_onoff(FILE *fp, const char *flag, __u32 val)
 {
-	fprintf(f, "%s %s ", flag, val ? "on" : "off");
+	if (is_json_context())
+		print_bool(PRINT_JSON, flag, NULL, val);
+	else
+		fprintf(fp, "%s %s ", flag, val ? "on" : "off");
 }
 
 static struct rtattr *netconf_rta(struct netconfmsg *ncm)
@@ -83,50 +90,44 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
 	if (filter.ifindex && filter.ifindex != ifindex)
 		return 0;
 
-	switch (ncm->ncm_family) {
-	case AF_INET:
-		fprintf(fp, "ipv4 ");
-		break;
-	case AF_INET6:
-		fprintf(fp, "ipv6 ");
-		break;
-	case AF_MPLS:
-		fprintf(fp, "mpls ");
-		break;
-	default:
-		fprintf(fp, "unknown ");
-		break;
-	}
+	open_json_object(NULL);
+	print_string(PRINT_ANY, "family",
+		     "%s ", family_name(ncm->ncm_family));
 
 	if (tb[NETCONFA_IFINDEX]) {
+		const char *dev;
+
 		switch (ifindex) {
 		case NETCONFA_IFINDEX_ALL:
-			fprintf(fp, "all ");
+			dev = "all";
 			break;
 		case NETCONFA_IFINDEX_DEFAULT:
-			fprintf(fp, "default ");
+			dev = "default";
 			break;
 		default:
-			fprintf(fp, "dev %s ", ll_index_to_name(ifindex));
+			dev = ll_index_to_name(ifindex);
 			break;
 		}
+		print_color_string(PRINT_ANY, COLOR_IFNAME,
+				   "interface", "%s ", dev);
 	}
 
 	if (tb[NETCONFA_FORWARDING])
 		print_onoff(fp, "forwarding",
 				rta_getattr_u32(tb[NETCONFA_FORWARDING]));
+
 	if (tb[NETCONFA_RP_FILTER]) {
 		__u32 rp_filter = rta_getattr_u32(tb[NETCONFA_RP_FILTER]);
 
-		if (rp_filter == 0)
-			fprintf(fp, "rp_filter off ");
-		else if (rp_filter == 1)
-			fprintf(fp, "rp_filter strict ");
-		else if (rp_filter == 2)
-			fprintf(fp, "rp_filter loose ");
+		if (rp_filter < ARRAY_SIZE(rp_filter_names))
+			print_string(PRINT_ANY, "rp_filter",
+				     "rp_filter %s ",
+				     rp_filter_names[rp_filter]);
 		else
-			fprintf(fp, "rp_filter unknown mode ");
+			print_uint(PRINT_ANY, "rp_filter",
+				   "rp_filter %u ", rp_filter);
 	}
+
 	if (tb[NETCONFA_MC_FORWARDING])
 		print_onoff(fp, "mc_forwarding",
 				rta_getattr_u32(tb[NETCONFA_MC_FORWARDING]));
@@ -142,7 +143,8 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
 	if (tb[NETCONFA_INPUT])
 		print_onoff(fp, "input", rta_getattr_u32(tb[NETCONFA_INPUT]));
 
-	fprintf(fp, "\n");
+	close_json_object();
+	print_string(PRINT_FP, NULL, "\n", NULL);
 	fflush(fp);
 	return 0;
 }
@@ -179,7 +181,8 @@ static int do_show(int argc, char **argv)
 			NEXT_ARG();
 			filter.ifindex = ll_name_to_index(*argv);
 			if (filter.ifindex <= 0) {
-				fprintf(stderr, "Device \"%s\" does not exist.\n",
+				fprintf(stderr,
+					"Device \"%s\" does not exist.\n",
 					*argv);
 				return -1;
 			}
@@ -202,10 +205,13 @@ static int do_show(int argc, char **argv)
 	} else {
 		rth.flags = RTNL_HANDLE_F_SUPPRESS_NLERR;
 dump:
-		if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNETCONF) < 0) {
+		if (rtnl_wilddump_request(&rth, filter.family,
+					  RTM_GETNETCONF) < 0) {
 			perror("Cannot send dump request");
 			exit(1);
 		}
+
+		new_json_obj(json);
 		if (rtnl_dump_filter(&rth, print_netconf2, stdout) < 0) {
 			/* kernel does not support netconf dump on AF_UNSPEC;
 			 * fall back to requesting by family
@@ -219,6 +225,7 @@ dump:
 			fprintf(stderr, "Dump terminated\n");
 			exit(1);
 		}
+		delete_json_obj();
 		if (preferred_family == AF_UNSPEC && filter.family == AF_INET) {
 			preferred_family = AF_INET6;
 			filter.family = AF_INET6;
@@ -240,6 +247,8 @@ int do_ipnetconf(int argc, char **argv)
 	} else
 		return do_show(0, NULL);
 
-	fprintf(stderr, "Command \"%s\" is unknown, try \"ip netconf help\".\n", *argv);
+	fprintf(stderr,
+		"Command \"%s\" is unknown, try \"ip netconf help\".\n",
+		*argv);
 	exit(-1);
 }
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH iproute2-next 6/7] tcp_metrics; make tables const
  2018-03-06  3:04 [PATCH iproute2-next 0/7] ip: more JSON Stephen Hemminger
                   ` (4 preceding siblings ...)
  2018-03-06  3:04 ` [PATCH iproute2-next 5/7] ip: add JSON support to netconf Stephen Hemminger
@ 2018-03-06  3:05 ` Stephen Hemminger
  2018-03-06  3:05 ` [PATCH iproute2-next 7/7] ip: jsonify tcp_metrics Stephen Hemminger
  6 siblings, 0 replies; 12+ messages in thread
From: Stephen Hemminger @ 2018-03-06  3:05 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/tcp_metrics.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/ip/tcp_metrics.c b/ip/tcp_metrics.c
index 7e2d9eb34b79..5f394765c62b 100644
--- a/ip/tcp_metrics.c
+++ b/ip/tcp_metrics.c
@@ -47,8 +47,8 @@ static int genl_family = -1;
 #define CMD_DEL		0x0002	/* delete, remove		*/
 #define CMD_FLUSH	0x0004	/* flush			*/
 
-static struct {
-	char	*name;
+static const struct {
+	const char *name;
 	int	code;
 } cmds[] = {
 	{	"list",		CMD_LIST	},
@@ -59,7 +59,7 @@ static struct {
 	{	"flush",	CMD_FLUSH	},
 };
 
-static char *metric_name[TCP_METRIC_MAX + 1] = {
+static const char *metric_name[TCP_METRIC_MAX + 1] = {
 	[TCP_METRIC_RTT]		= "rtt",
 	[TCP_METRIC_RTTVAR]		= "rttvar",
 	[TCP_METRIC_SSTHRESH]		= "ssthresh",
@@ -67,8 +67,7 @@ static char *metric_name[TCP_METRIC_MAX + 1] = {
 	[TCP_METRIC_REORDERING]		= "reordering",
 };
 
-static struct
-{
+static struct {
 	int flushed;
 	char *flushb;
 	int flushp;
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH iproute2-next 7/7] ip: jsonify tcp_metrics
  2018-03-06  3:04 [PATCH iproute2-next 0/7] ip: more JSON Stephen Hemminger
                   ` (5 preceding siblings ...)
  2018-03-06  3:05 ` [PATCH iproute2-next 6/7] tcp_metrics; make tables const Stephen Hemminger
@ 2018-03-06  3:05 ` Stephen Hemminger
  6 siblings, 0 replies; 12+ messages in thread
From: Stephen Hemminger @ 2018-03-06  3:05 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Add JSON support to the ip tcp_metrics output.

$ ip -j -p tcp_metrics show
[ {
        "dst": "192.18.1.11",
        "age": 23617.8,
        "ssthresh": 7,
        "cwnd": 3,
        "rtt": 0.039176,
        "rttvar": 0.039176,
        "source": "192.18.1.2"
    }
...

The JSON output does scale values differently since there is no good
way to indicate units. The rtt values are displayed in seconds in
JSON and microseconds in the original (non JSON) mode. In the example
above the output in without the -j flag, the output would be
 ... rtt 39176us rttvar 39176us

I did this since all the other values in the JSON record are also in
floating point seconds.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/tcp_metrics.c | 179 ++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 110 insertions(+), 69 deletions(-)

diff --git a/ip/tcp_metrics.c b/ip/tcp_metrics.c
index 5f394765c62b..72dc980c92a6 100644
--- a/ip/tcp_metrics.c
+++ b/ip/tcp_metrics.c
@@ -38,6 +38,7 @@ static void usage(void)
 /* netlink socket */
 static struct rtnl_handle grth = { .fd = -1 };
 static int genl_family = -1;
+static const double usec_per_sec = 1000000.;
 
 #define TCPM_REQUEST(_req, _bufsiz, _cmd, _flags) \
 	GENL_REQUEST(_req, _bufsiz, genl_family, 0, \
@@ -87,15 +88,84 @@ static int flush_update(void)
 	return 0;
 }
 
+static void print_tcp_metrics(struct rtattr *a)
+{
+	struct rtattr *m[TCP_METRIC_MAX + 1 + 1];
+	unsigned long rtt = 0, rttvar = 0;
+	int i;
+
+	parse_rtattr_nested(m, TCP_METRIC_MAX + 1, a);
+
+	for (i = 0; i < TCP_METRIC_MAX + 1; i++) {
+		const char *name;
+		__u32 val;
+		SPRINT_BUF(b1);
+
+		a = m[i + 1];
+		if (!a)
+			continue;
+
+		val = rta_getattr_u32(a);
+
+		switch (i) {
+		case TCP_METRIC_RTT:
+			if (!rtt)
+				rtt = (val * 1000UL) >> 3;
+			continue;
+		case TCP_METRIC_RTTVAR:
+			if (!rttvar)
+				rttvar = (val * 1000UL) >> 2;
+			continue;
+		case TCP_METRIC_RTT_US:
+			rtt = val >> 3;
+			continue;
+
+		case TCP_METRIC_RTTVAR_US:
+			rttvar = val >> 2;
+			continue;
+
+		case TCP_METRIC_SSTHRESH:
+		case TCP_METRIC_CWND:
+		case TCP_METRIC_REORDERING:
+			name = metric_name[i];
+			break;
+
+		default:
+			snprintf(b1, sizeof(b1),
+				 " metric_%d ", i);
+			name = b1;
+		}
+
+
+		print_uint(PRINT_JSON, name, NULL, val);
+		print_string(PRINT_FP, NULL, " %s ", name);
+		print_uint(PRINT_FP, NULL, "%lu", val);
+	}
+
+	if (rtt) {
+		print_float(PRINT_JSON, "rtt", NULL,
+			    (double)rtt / usec_per_sec);
+		print_uint(PRINT_FP, NULL,
+			   " rtt %luus", rtt);
+	}
+	if (rttvar) {
+		print_float(PRINT_JSON, "rttvar", NULL,
+			    (double) rttvar / usec_per_sec);
+		print_uint(PRINT_FP, NULL,
+			   " rttvar %luus", rttvar);
+	}
+}
+
 static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
 		       void *arg)
 {
 	FILE *fp = (FILE *) arg;
 	struct genlmsghdr *ghdr;
 	struct rtattr *attrs[TCP_METRICS_ATTR_MAX + 1], *a;
+	const char *h;
 	int len = n->nlmsg_len;
 	inet_prefix daddr, saddr;
-	int i, atype, stype;
+	int atype, stype;
 
 	if (n->nlmsg_type != genl_family)
 		return -1;
@@ -185,96 +255,60 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
 			return 0;
 	}
 
+	open_json_object(NULL);
 	if (f.cmd & (CMD_DEL | CMD_FLUSH))
-		fprintf(fp, "Deleted ");
+		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
-	fprintf(fp, "%s",
-		format_host(daddr.family, daddr.bytelen, daddr.data));
+	h = format_host(daddr.family, daddr.bytelen, daddr.data);
+	print_color_string(PRINT_ANY,
+			   ifa_family_color(daddr.family),
+			   "dst", "%s", h);
 
 	a = attrs[TCP_METRICS_ATTR_AGE];
 	if (a) {
-		unsigned long long val = rta_getattr_u64(a);
+		__u64 val = rta_getattr_u64(a);
+		double age = val / 1000.;
 
-		fprintf(fp, " age %llu.%03llusec",
-			val / 1000, val % 1000);
+		print_float(PRINT_ANY, "age",
+			     " age %.03fsec", age);
 	}
 
 	a = attrs[TCP_METRICS_ATTR_TW_TS_STAMP];
 	if (a) {
 		__s32 val = (__s32) rta_getattr_u32(a);
 		__u32 tsval;
+		char tw_ts[64];
 
 		a = attrs[TCP_METRICS_ATTR_TW_TSVAL];
 		tsval = a ? rta_getattr_u32(a) : 0;
-		fprintf(fp, " tw_ts %u/%dsec ago", tsval, val);
+		snprintf(tw_ts, sizeof(tw_ts),
+			 "%u/%d", tsval, val);
+		print_string(PRINT_ANY, "tw_ts_stamp",
+		     " tw_ts %s ago", tw_ts);
 	}
 
-	a = attrs[TCP_METRICS_ATTR_VALS];
-	if (a) {
-		struct rtattr *m[TCP_METRIC_MAX + 1 + 1];
-		unsigned long rtt = 0, rttvar = 0;
-
-		parse_rtattr_nested(m, TCP_METRIC_MAX + 1, a);
-
-		for (i = 0; i < TCP_METRIC_MAX + 1; i++) {
-			unsigned long val;
-
-			a = m[i + 1];
-			if (!a)
-				continue;
-			if (i != TCP_METRIC_RTT &&
-			    i != TCP_METRIC_RTT_US &&
-			    i != TCP_METRIC_RTTVAR &&
-			    i != TCP_METRIC_RTTVAR_US) {
-				if (metric_name[i])
-					fprintf(fp, " %s ", metric_name[i]);
-				else
-					fprintf(fp, " metric_%d ", i);
-			}
-			val = rta_getattr_u32(a);
-			switch (i) {
-			case TCP_METRIC_RTT:
-				if (!rtt)
-					rtt = (val * 1000UL) >> 3;
-				break;
-			case TCP_METRIC_RTTVAR:
-				if (!rttvar)
-					rttvar = (val * 1000UL) >> 2;
-				break;
-			case TCP_METRIC_RTT_US:
-				rtt = val >> 3;
-				break;
-			case TCP_METRIC_RTTVAR_US:
-				rttvar = val >> 2;
-				break;
-			case TCP_METRIC_SSTHRESH:
-			case TCP_METRIC_CWND:
-			case TCP_METRIC_REORDERING:
-			default:
-				fprintf(fp, "%lu", val);
-				break;
-			}
-		}
-		if (rtt)
-			fprintf(fp, " rtt %luus", rtt);
-		if (rttvar)
-			fprintf(fp, " rttvar %luus", rttvar);
-	}
+	if (attrs[TCP_METRICS_ATTR_VALS])
+		print_tcp_metrics(attrs[TCP_METRICS_ATTR_VALS]);
 
 	a = attrs[TCP_METRICS_ATTR_FOPEN_MSS];
-	if (a)
-		fprintf(fp, " fo_mss %u", rta_getattr_u16(a));
+	if (a) {
+		print_uint(PRINT_ANY, "fopen_miss", " fo_mss %u",
+			   rta_getattr_u16(a));
+	}
 
 	a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROPS];
 	if (a) {
 		__u16 syn_loss = rta_getattr_u16(a);
-		unsigned long long ts;
+		double ts;
 
 		a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS];
 		ts = a ? rta_getattr_u64(a) : 0;
 
-		fprintf(fp, " fo_syn_drops %u/%llu.%03llusec ago",
-			syn_loss, ts / 1000, ts % 1000);
+		print_uint(PRINT_ANY, "fopen_syn_drops",
+			   " fo_syn_drops %u", syn_loss);
+		print_float(PRINT_ANY, "fopen_syn_drop_ts",
+			     "/%.03fusec ago",
+			     ts / 1000000.);
 	}
 
 	a = attrs[TCP_METRICS_ATTR_FOPEN_COOKIE];
@@ -288,16 +322,21 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
 		cookie[0] = 0;
 		for (i = 0; i < max; i++)
 			sprintf(cookie + i + i, "%02x", ptr[i]);
-		fprintf(fp, " fo_cookie %s", cookie);
+
+		print_string(PRINT_ANY, "fo_cookie",
+			     " fo_cookie %s", cookie);
 	}
 
 	if (saddr.family) {
-		fprintf(fp, " source %s",
-			format_host(saddr.family, saddr.bytelen, saddr.data));
-	}
+		const char *src;
 
-	fprintf(fp, "\n");
+		src = format_host(saddr.family, saddr.bytelen, saddr.data);
+		print_string(PRINT_ANY, "source",
+			     " source %s", src);
+	}
 
+	print_string(PRINT_FP, NULL, "\n", "");
+	close_json_object();
 	fflush(fp);
 	return 0;
 }
@@ -474,10 +513,12 @@ static int tcpm_do_cmd(int cmd, int argc, char **argv)
 			exit(1);
 		}
 
+		new_json_obj(json);
 		if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) {
 			fprintf(stderr, "Dump terminated\n");
 			exit(1);
 		}
+		delete_json_obj();
 	}
 	return 0;
 }
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH iproute2-next 1/7] ip: add color and json support to neigh
  2018-03-06  3:04 ` [PATCH iproute2-next 1/7] ip: add color and json support to neigh Stephen Hemminger
@ 2018-03-06 16:38   ` David Ahern
  0 siblings, 0 replies; 12+ messages in thread
From: David Ahern @ 2018-03-06 16:38 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, Stephen Hemminger

On 3/5/18 8:04 PM, Stephen Hemminger wrote:
> From: Stephen Hemminger <sthemmin@microsoft.com>
> 
> Use json_print to provide json (and color) support to
> ip neigh command.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
>  ip/ipneigh.c | 143 ++++++++++++++++++++++++++++++++++++++++-------------------
>  1 file changed, 97 insertions(+), 46 deletions(-)
> 
> diff --git a/ip/ipneigh.c b/ip/ipneigh.c
> index 0735424900f6..1f550e98e003 100644
> --- a/ip/ipneigh.c
> +++ b/ip/ipneigh.c
> @@ -23,6 +23,7 @@
>  #include "rt_names.h"
>  #include "utils.h"
>  #include "ip_common.h"
> +#include "json_print.h"
>  
>  #define NUD_VALID	(NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
>  #define MAX_ROUNDS	10
> @@ -189,6 +190,48 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
>  	return 0;
>  }
>  
> +static void print_cacheinfo(const struct nda_cacheinfo *ci)
> +{
> +	static int hz;
> +
> +	if (!hz)
> +		hz = get_user_hz();
> +
> +	if (ci->ndm_refcnt)
> +		print_uint(PRINT_ANY, "refcnt",
> +				" ref %u", ci->ndm_refcnt);
> +
> +	print_uint(PRINT_ANY,
> +			 "used", " used %u", ci->ndm_used / hz);
> +	print_uint(PRINT_ANY,
> +			 "confirmed", "/%u", ci->ndm_confirmed / hz);
> +	print_uint(PRINT_ANY,
> +			 "updated", "/u", ci->ndm_updated / hz);

alignment is off in the above and it looks like all of them can be on 1
line and not exceed 80 col.


> +}
> +
> +static void print_neigh_state(unsigned int nud)
> +{
> +
> +	open_json_array(PRINT_JSON,
> +			is_json_context() ?  "state" : "");
> +
> +#define PRINT_FLAG(f)						\
> +	if (nud & NUD_##f) {					\
> +		nud &= ~NUD_##f;				\
> +		print_string(PRINT_ANY, NULL, " %s", #f);	\
> +	}
> +
> +	PRINT_FLAG(INCOMPLETE);
> +	PRINT_FLAG(REACHABLE);
> +	PRINT_FLAG(STALE);
> +	PRINT_FLAG(DELAY);
> +	PRINT_FLAG(PROBE);
> +	PRINT_FLAG(FAILED);
> +	PRINT_FLAG(NOARP);
> +	PRINT_FLAG(PERMANENT);
> +#undef PRINT_FLAG
> +	close_json_array(PRINT_JSON, NULL);
> +}
>  
>  int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
>  {
> @@ -262,65 +305,71 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
>  			return 0;
>  	}
>  
> +	open_json_object(NULL);
>  	if (n->nlmsg_type == RTM_DELNEIGH)
> -		fprintf(fp, "Deleted ");
> +		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
>  	else if (n->nlmsg_type == RTM_GETNEIGH)
> -		fprintf(fp, "miss ");
> +		print_null(PRINT_ANY, "miss", "%s ", "miss");
> +
>  	if (tb[NDA_DST]) {
> -		fprintf(fp, "%s ",
> -			format_host_rta(r->ndm_family, tb[NDA_DST]));
> +		const char *dst;
> +
> +		dst = format_host_rta(r->ndm_family, tb[NDA_DST]);
> +		print_color_string(PRINT_ANY,
> +				   ifa_family_color(r->ndm_family),
> +				   "dst", "%s ", dst);
>  	}
> -	if (!filter.index && r->ndm_ifindex)
> -		fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex));
> +
> +	if (!filter.index && r->ndm_ifindex) {
> +		if (!is_json_context())
> +			fprintf(fp, "dev ");
> +
> +		print_color_string(PRINT_ANY, COLOR_IFNAME,
> +				   "dev", "%s ",
> +				   ll_index_to_name(r->ndm_ifindex));
> +	}
> +
>  	if (tb[NDA_LLADDR]) {
> +		const char *lladdr;
>  		SPRINT_BUF(b1);
> -		fprintf(fp, "lladdr %s", ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
> -					      RTA_PAYLOAD(tb[NDA_LLADDR]),
> -					      ll_index_to_type(r->ndm_ifindex),
> -					      b1, sizeof(b1)));
> -	}
> -	if (r->ndm_flags & NTF_ROUTER) {
> -		fprintf(fp, " router");
> -	}
> -	if (r->ndm_flags & NTF_PROXY) {
> -		fprintf(fp, " proxy");
> -	}
> -	if (tb[NDA_CACHEINFO] && show_stats) {
> -		struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
> -		int hz = get_user_hz();
>  
> -		if (ci->ndm_refcnt)
> -			printf(" ref %d", ci->ndm_refcnt);
> -		fprintf(fp, " used %d/%d/%d", ci->ndm_used/hz,
> -		       ci->ndm_confirmed/hz, ci->ndm_updated/hz);
> -	}
> +		lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
> +				     RTA_PAYLOAD(tb[NDA_LLADDR]),
> +				     ll_index_to_type(r->ndm_ifindex),
> +				     b1, sizeof(b1));
>  
> -	if (tb[NDA_PROBES] && show_stats) {
> -		__u32 p = rta_getattr_u32(tb[NDA_PROBES]);
> +		if (!is_json_context())
> +			fprintf(fp, "lladdr ");
>  
> -		fprintf(fp, " probes %u", p);
> +		print_color_string(PRINT_ANY, COLOR_MAC,
> +				   "lladdr", "%s", lladdr);
>  	}
>  
> -	if (r->ndm_state) {
> -		int nud = r->ndm_state;
> -
> -		fprintf(fp, " ");
> -
> -#define PRINT_FLAG(f) if (nud & NUD_##f) { \
> -	nud &= ~NUD_##f; fprintf(fp, #f "%s", nud ? "," : ""); }
> -		PRINT_FLAG(INCOMPLETE);
> -		PRINT_FLAG(REACHABLE);
> -		PRINT_FLAG(STALE);
> -		PRINT_FLAG(DELAY);
> -		PRINT_FLAG(PROBE);
> -		PRINT_FLAG(FAILED);
> -		PRINT_FLAG(NOARP);
> -		PRINT_FLAG(PERMANENT);
> -#undef PRINT_FLAG
> +	if (r->ndm_flags & NTF_ROUTER)
> +		print_null(PRINT_ANY, "router", " %s", "router");
> +
> +	if (r->ndm_flags & NTF_PROXY)
> +		print_null(PRINT_ANY, "proxy", " %s", "proxy");
> +
> +	if (show_stats) {
> +		if (tb[NDA_CACHEINFO])
> +			print_cacheinfo(RTA_DATA(tb[NDA_CACHEINFO]));
> +
> +		if (tb[NDA_PROBES]) {
> +			__u32 p = rta_getattr_u32(tb[NDA_PROBES]);
> +
> +			print_uint(PRINT_ANY, "probes",
> +					 " probes %u", p);

alignment on the above as well.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH iproute2-next 3/7] ip: add json support to ip rule
  2018-03-06  3:04 ` [PATCH iproute2-next 3/7] ip: add json support to ip rule Stephen Hemminger
@ 2018-03-06 16:51   ` David Ahern
  2018-03-06 16:57     ` Stephen Hemminger
  0 siblings, 1 reply; 12+ messages in thread
From: David Ahern @ 2018-03-06 16:51 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, Stephen Hemminger

On 3/5/18 8:04 PM, Stephen Hemminger wrote:
> @@ -202,50 +202,66 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
>  	if (!filter_nlmsg(n, tb, host_len))
>  		return 0;
>  
> +	open_json_object(NULL);
>  	if (n->nlmsg_type == RTM_DELRULE)
> -		fprintf(fp, "Deleted ");
> +		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
>  
>  	if (tb[FRA_PRIORITY])
> -		fprintf(fp, "%u:\t",
> -			rta_getattr_u32(tb[FRA_PRIORITY]));
> -	else
> -		fprintf(fp, "0:\t");
> +		prio = rta_getattr_u32(tb[FRA_PRIORITY]);
> +
> +	print_uint(PRINT_ANY, "priority",
> +		   "%u:\t", prio);

This one has a lot of instances where the print_* can be put on one line.


>  
>  	if (frh->flags & FIB_RULE_INVERT)
> -		fprintf(fp, "not ");
> +		print_null(PRINT_ANY, "not", "not ", NULL);
> +
> +	if (!is_json_context())
> +		fprintf(fp, "from ");
>  
>  	if (tb[FRA_SRC]) {
> -		if (frh->src_len != host_len) {
> -			fprintf(fp, "from %s/%u ",
> -				rt_addr_n2a_rta(frh->family, tb[FRA_SRC]),
> -				frh->src_len);
> -		} else {
> -			fprintf(fp, "from %s ",
> -				format_host_rta(frh->family, tb[FRA_SRC]));
> -		}
> +		const char *src
> +			= rt_addr_n2a_rta(frh->family, tb[FRA_SRC]);
> +
> +		print_color_string(PRINT_ANY,
> +				   ifa_family_color(frh->family),
> +				   "src", "%s", src);
> +		if (frh->src_len != host_len)
> +			print_uint(PRINT_ANY, "srclen",
> +				   "/%u", frh->src_len);
>  	} else if (frh->src_len) {
> -		fprintf(fp, "from 0/%d ", frh->src_len);
> +		print_string(PRINT_ANY,
> +			     "src", "%s", "0");
> +		print_uint(PRINT_ANY,
> +			   "srclen", "/%u", frh->src_len);
>  	} else {
> -		fprintf(fp, "from all ");
> +		print_string(PRINT_ANY,
> +			     "src", "%s", "all");
>  	}
>  
> +	if (!is_json_context())
> +		fprintf(fp, " to ");
> +
>  	if (tb[FRA_DST]) {
> -		if (frh->dst_len != host_len) {
> -			fprintf(fp, "to %s/%u ",
> -				rt_addr_n2a_rta(frh->family, tb[FRA_DST]),
> -				frh->dst_len);
> -		} else {
> -			fprintf(fp, "to %s ",
> -				format_host_rta(frh->family, tb[FRA_DST]));
> -		}
> +		const char *dst
> +			= rt_addr_n2a_rta(frh->family, tb[FRA_DST]);
> +
> +		print_color_string(PRINT_ANY,
> +				   ifa_family_color(frh->family),
> +				   "dst", "%s", dst);
> +		if (frh->dst_len != host_len)
> +			print_uint(PRINT_ANY, "dstlen",
> +				   "/%u ", frh->dst_len);
>  	} else if (frh->dst_len) {
> -		fprintf(fp, "to 0/%d ", frh->dst_len);
> +		print_string(PRINT_ANY,
> +			     "dst", "%s", "0");
> +		print_uint(PRINT_ANY,
> +			   "dstlen", "/%u ", frh->dst_len);
>  	}
>  
>  	if (frh->tos) {
> -		SPRINT_BUF(b1);
> -		fprintf(fp, "tos %s ",
> -			rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1)));
> +		print_string(PRINT_ANY, "tos",
> +			     "tos %s ",
> +			     rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1)));
>  	}
>  
>  	if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
> @@ -255,53 +271,82 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
>  			mark = rta_getattr_u32(tb[FRA_FWMARK]);
>  
>  		if (tb[FRA_FWMASK] &&
> -		    (mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF)
> -			fprintf(fp, "fwmark 0x%x/0x%x ", mark, mask);
> -		else
> -			fprintf(fp, "fwmark 0x%x ", mark);
> +		    (mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF) {
> +			print_0xhex(PRINT_ANY, "fwmark",
> +				    "fwmark 0x%x", mark);
> +			print_0xhex(PRINT_ANY, "fwmask",
> +				    "/0x%x ",  mask);
> +		} else {
> +			print_0xhex(PRINT_ANY, "fwmark",
> +				    "fwmark 0x%x ", mark);
> +		}
>  	}
>  
>  	if (tb[FRA_IFNAME]) {
> -		fprintf(fp, "iif %s ", rta_getattr_str(tb[FRA_IFNAME]));
> +		if (!is_json_context())
> +			fprintf(fp, "iif ");
> +		print_color_string(PRINT_ANY, COLOR_IFNAME,
> +				   "iif", "%s ",
> +				   rta_getattr_str(tb[FRA_IFNAME]));
> +
>  		if (frh->flags & FIB_RULE_IIF_DETACHED)
> -			fprintf(fp, "[detached] ");
> +			print_null(PRINT_ANY, "iif_detached",
> +				   "[detached] ", NULL);
>  	}
>  
>  	if (tb[FRA_OIFNAME]) {
> -		fprintf(fp, "oif %s ", rta_getattr_str(tb[FRA_OIFNAME]));
> +		if (!is_json_context())
> +			fprintf(fp, "oif ");
> +
> +		print_color_string(PRINT_ANY, COLOR_IFNAME,
> +				   "oif", "%s ",
> +				   rta_getattr_str(tb[FRA_OIFNAME]));
> +
>  		if (frh->flags & FIB_RULE_OIF_DETACHED)
> -			fprintf(fp, "[detached] ");
> +			print_null(PRINT_ANY, "oif_detached",
> +				   "[detached] ", NULL);

NULL for detached value seems weird.
[ {
        "priority": 998,
        "src": "all",
        "iif": "dummy2",
        "iif_detached": null,
        "table": "1"
    },

Is that normal for json for fields that only exist when a value is true?


>  	}
>  
>  	if (tb[FRA_L3MDEV]) {
> -		if (rta_getattr_u8(tb[FRA_L3MDEV]))
> -			fprintf(fp, "lookup [l3mdev-table] ");
> +		__u8 mdev = rta_getattr_u8(tb[FRA_L3MDEV]);
> +
> +		if (mdev)
> +			print_null(PRINT_ANY, "l3mdev",
> +				   "lookup [l3mdev-table] ", NULL);
>  	}
>  
>  	if (tb[FRA_UID_RANGE]) {
>  		struct fib_rule_uid_range *r = RTA_DATA(tb[FRA_UID_RANGE]);
>  
> -		fprintf(fp, "uidrange %u-%u ", r->start, r->end);
> +		print_uint(PRINT_ANY, "uid_start",
> +			   "uidrange %u", r->start);
> +		print_uint(PRINT_ANY, "uid_end",
> +			   "-%u ", r->end);
>  	}
>  
>  	table = frh_get_table(frh, tb);
>  	if (table) {
> -		fprintf(fp, "lookup %s ",
> -			rtnl_rttable_n2a(table, b1, sizeof(b1)));
> +		print_string(PRINT_ANY, "table",
> +			     "lookup %s ",
> +			     rtnl_rttable_n2a(table, b1, sizeof(b1)));

dropped a space in the non-json output:
# ip   ru ls
998:	from all to iif dummy2 [detached] lookup 1
998:	from all to 9.9.9.9lookup 2
999:	from all to 8.8.8.8lookup main

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH iproute2-next 4/7] ip: add json support to ntable
  2018-03-06  3:04 ` [PATCH iproute2-next 4/7] ip: add json support to ntable Stephen Hemminger
@ 2018-03-06 16:53   ` David Ahern
  0 siblings, 0 replies; 12+ messages in thread
From: David Ahern @ 2018-03-06 16:53 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, Stephen Hemminger

On 3/5/18 8:04 PM, Stephen Hemminger wrote:
> @@ -338,274 +339,308 @@ static const char *ntable_strtime_delta(__u32 msec)
>  	return str;
>  }
>  
> -static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
> +static void print_ndtconfig(const struct ndt_config *ndtc)
>  {
> -	FILE *fp = (FILE *)arg;
> -	struct ndtmsg *ndtm = NLMSG_DATA(n);
> -	int len = n->nlmsg_len;
> -	struct rtattr *tb[NDTA_MAX+1];
> -	struct rtattr *tpb[NDTPA_MAX+1];
> -	int ret;
>  
> -	if (n->nlmsg_type != RTM_NEWNEIGHTBL) {
> -		fprintf(stderr, "Not NEIGHTBL: %08x %08x %08x\n",
> -			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
> -		return 0;
> -	}
> -	len -= NLMSG_LENGTH(sizeof(*ndtm));
> -	if (len < 0) {
> -		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
> -		return -1;
> -	}
> +	print_uint(PRINT_ANY, "key_length",
> +		     "    config key_len %u ", ndtc->ndtc_key_len);
> +	print_uint(PRINT_ANY, "entry_size",
> +		     "entry_size %u ", ndtc->ndtc_entry_size);

this one has a number of places where the second line is misaligned.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH iproute2-next 3/7] ip: add json support to ip rule
  2018-03-06 16:51   ` David Ahern
@ 2018-03-06 16:57     ` Stephen Hemminger
  0 siblings, 0 replies; 12+ messages in thread
From: Stephen Hemminger @ 2018-03-06 16:57 UTC (permalink / raw)
  To: David Ahern; +Cc: netdev, Stephen Hemminger

On Tue, 6 Mar 2018 09:51:29 -0700
David Ahern <dsahern@gmail.com> wrote:

> NULL for detached value seems weird.
> [ {
>         "priority": 998,
>         "src": "all",
>         "iif": "dummy2",
>         "iif_detached": null,
>         "table": "1"
>     },
> 
> Is that normal for json for fields that only exist when a value is true?

null is the best way to indicate a value with presence having a meaning.

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2018-03-06 16:57 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-06  3:04 [PATCH iproute2-next 0/7] ip: more JSON Stephen Hemminger
2018-03-06  3:04 ` [PATCH iproute2-next 1/7] ip: add color and json support to neigh Stephen Hemminger
2018-03-06 16:38   ` David Ahern
2018-03-06  3:04 ` [PATCH iproute2-next 2/7] ip: add json support to addrlabel Stephen Hemminger
2018-03-06  3:04 ` [PATCH iproute2-next 3/7] ip: add json support to ip rule Stephen Hemminger
2018-03-06 16:51   ` David Ahern
2018-03-06 16:57     ` Stephen Hemminger
2018-03-06  3:04 ` [PATCH iproute2-next 4/7] ip: add json support to ntable Stephen Hemminger
2018-03-06 16:53   ` David Ahern
2018-03-06  3:04 ` [PATCH iproute2-next 5/7] ip: add JSON support to netconf Stephen Hemminger
2018-03-06  3:05 ` [PATCH iproute2-next 6/7] tcp_metrics; make tables const Stephen Hemminger
2018-03-06  3:05 ` [PATCH iproute2-next 7/7] ip: jsonify tcp_metrics Stephen Hemminger

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.