All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH iproute2-next v2 00/12] ip more JSON
@ 2018-03-06 21:07 Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 01/12] ipneigh: add color and json support Stephen Hemminger
                   ` (12 more replies)
  0 siblings, 13 replies; 14+ messages in thread
From: Stephen Hemminger @ 2018-03-06 21:07 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 (12):
  ipneigh: add color and json support
  ipaddrlabel: add json support
  iprule: add json support
  ipntable: add json support
  ipnetconf: add JSON support
  tcp_metrics; make tables const
  tcp_metrics: add json support
  ipsr: add json support
  token: support JSON
  tuntap: support JSON output
  fou: break long lines
  fou: support JSON output

v2:
  - fix output format for ip rule
  - break lines more compactly
  - add fou, token, tuntap, and sr sub-commands

 ip/ipaddrlabel.c |  40 ++++--
 ip/ipfou.c       |  56 +++++---
 ip/ipneigh.c     | 140 ++++++++++++-------
 ip/ipnetconf.c   |  69 +++++-----
 ip/ipntable.c    | 402 +++++++++++++++++++++++++++++--------------------------
 ip/iprule.c      | 184 ++++++++++++++-----------
 ip/ipseg6.c      |  93 +++++++------
 ip/iptoken.c     |  18 ++-
 ip/iptuntap.c    |  57 ++++++--
 ip/tcp_metrics.c | 188 ++++++++++++++++----------
 10 files changed, 744 insertions(+), 503 deletions(-)

-- 
2.16.1

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

* [PATCH iproute2-next v2 01/12] ipneigh: add color and json support
  2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
@ 2018-03-06 21:07 ` Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 02/12] ipaddrlabel: add " Stephen Hemminger
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2018-03-06 21:07 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.

Example:
$ ip -j -p neigh
[ {
        "dst": "192.168.1.29",
        "dev": "enp12s0",
        "state": [ "FAILED" ]
    },{
        "dst": "192.168.1.130",
        "dev": "enp12s0",
        "state": [ "FAILED" ]
    },{
        "dst": "192.168.1.131",
        "dev": "enp12s0",
        "lladdr": "00:15:5d:2a:16:4f",
        "state": [ "STALE" ]
    }
...

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

diff --git a/ip/ipneigh.c b/ip/ipneigh.c
index 0735424900f6..925494dbe324 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,46 @@ 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)
 {
@@ -221,7 +262,7 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	if (!(filter.state&r->ndm_state) &&
 	    !(r->ndm_flags & NTF_PROXY) &&
 	    (r->ndm_state || !(filter.state&0x100)) &&
-	     (r->ndm_family != AF_DECnet))
+	    (r->ndm_family != AF_DECnet))
 		return 0;
 
 	if (filter.master && !(n->nlmsg_flags & NLM_F_DUMP_FILTERED)) {
@@ -262,65 +303,68 @@ 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])
+			print_uint(PRINT_ANY, "probes", " probes %u",
+				   rta_getattr_u32(tb[NDA_PROBES]));
 	}
-	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 +523,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] 14+ messages in thread

* [PATCH iproute2-next v2 02/12] ipaddrlabel: add json support
  2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 01/12] ipneigh: add color and json support Stephen Hemminger
@ 2018-03-06 21:07 ` Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 03/12] iprule: " Stephen Hemminger
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2018-03-06 21:07 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

Example:
$ ip -j -p addrlabel
[ {
        "address": "::1",
        "prefixlen": 128,
        "label": 56
    },{
        "address": "::",
        "prefixlen": 96,
        "label": 56
    },{
...

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] 14+ messages in thread

* [PATCH iproute2-next v2 03/12] iprule: add json support
  2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 01/12] ipneigh: add color and json support Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 02/12] ipaddrlabel: add " Stephen Hemminger
@ 2018-03-06 21:07 ` Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 04/12] ipntable: " Stephen Hemminger
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2018-03-06 21:07 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 | 184 +++++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 109 insertions(+), 75 deletions(-)

diff --git a/ip/iprule.c b/ip/iprule.c
index 6fdc9b5efa00..a49753e640d9 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,54 @@ 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 (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_string(PRINT_FP, NULL, "from ", NULL);
+		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
+			print_string(PRINT_FP, NULL, " ", NULL);
 	} else if (frh->src_len) {
-		fprintf(fp, "from 0/%d ", frh->src_len);
+		print_string(PRINT_ANY, "src", "from %s", "0");
+		print_uint(PRINT_ANY, "srclen", "/%u ", frh->src_len);
 	} else {
-		fprintf(fp, "from all ");
+		print_string(PRINT_ANY, "src", "from %s ", "all");
 	}
 
 	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_string(PRINT_FP, NULL, "to ", NULL);
+		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
+			print_string(PRINT_FP, NULL, " ", NULL);
 	} else if (frh->dst_len) {
-		fprintf(fp, "to 0/%d ", frh->dst_len);
+		print_string(PRINT_ANY, "dst", "to %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 +259,76 @@ 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 +338,52 @@ 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)));
+		if ((protocol && protocol != RTPROT_KERNEL) || show_details > 0) {
+			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 +586,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] 14+ messages in thread

* [PATCH iproute2-next v2 04/12] ipntable: add json support
  2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
                   ` (2 preceding siblings ...)
  2018-03-06 21:07 ` [PATCH iproute2-next v2 03/12] iprule: " Stephen Hemminger
@ 2018-03-06 21:07 ` Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 05/12] ipnetconf: add JSON support Stephen Hemminger
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2018-03-06 21:07 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 | 402 +++++++++++++++++++++++++++++++---------------------------
 1 file changed, 213 insertions(+), 189 deletions(-)

diff --git a/ip/ipntable.c b/ip/ipntable.c
index 2f72c989f35d..92024864a784 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,295 @@ 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, "    ");
+		print_uint(PRINT_ANY, "base_reachable",
+			   "base_reachable %llu ", breachable);
+	}
 
-	if (tb[NDTA_THRESH1]) {
-		__u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]);
+	if (tpb[NDTPA_RETRANS_TIME]) {
+		__u64 retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]);
 
-		fprintf(fp, "thresh1 %u ", thresh1);
+		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 (filter.name && strcmp(filter.name, name))
+			return 0;
+	}
 
-		if (tpb[NDTPA_ANYCAST_DELAY]) {
-			unsigned long long anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]);
+	if (tb[NDTA_PARMS]) {
+		parse_rtattr(tpb, NDTPA_MAX, RTA_DATA(tb[NDTA_PARMS]),
+			     RTA_PAYLOAD(tb[NDTA_PARMS]));
 
-			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 (tpb[NDTPA_IFINDEX]) {
+			__u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
 
-			fprintf(fp, "proxy_delay %llu ", proxy_delay);
+			if (filter.index && filter.index != ifindex)
+				return 0;
+		} else {
+			if (filter.index && filter.index != NONE_DEV)
+				return 0;
 		}
-		if (tpb[NDTPA_PROXY_QLEN]) {
-			__u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]);
+	}
 
-			fprintf(fp, "proxy_queue %u ", pqueue);
-		}
-		if (tpb[NDTPA_LOCKTIME]) {
-			unsigned long long locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]);
+	open_json_object(NULL);
+	print_string(PRINT_ANY, "family",
+		     "%s ", family_name(ndtm->ndtm_family));
 
-			fprintf(fp, "locktime %llu ", locktime);
-		}
+	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 +665,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] 14+ messages in thread

* [PATCH iproute2-next v2 05/12] ipnetconf: add JSON support
  2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
                   ` (3 preceding siblings ...)
  2018-03-06 21:07 ` [PATCH iproute2-next v2 04/12] ipntable: " Stephen Hemminger
@ 2018-03-06 21:07 ` Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 06/12] tcp_metrics; make tables const Stephen Hemminger
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2018-03-06 21:07 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] 14+ messages in thread

* [PATCH iproute2-next v2 06/12] tcp_metrics; make tables const
  2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
                   ` (4 preceding siblings ...)
  2018-03-06 21:07 ` [PATCH iproute2-next v2 05/12] ipnetconf: add JSON support Stephen Hemminger
@ 2018-03-06 21:07 ` Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 07/12] tcp_metrics: add json support Stephen Hemminger
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2018-03-06 21:07 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] 14+ messages in thread

* [PATCH iproute2-next v2 07/12] tcp_metrics: add json support
  2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
                   ` (5 preceding siblings ...)
  2018-03-06 21:07 ` [PATCH iproute2-next v2 06/12] tcp_metrics; make tables const Stephen Hemminger
@ 2018-03-06 21:07 ` Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 08/12] ipsr: " Stephen Hemminger
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2018-03-06 21:07 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] 14+ messages in thread

* [PATCH iproute2-next v2 08/12] ipsr: add json support
  2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
                   ` (6 preceding siblings ...)
  2018-03-06 21:07 ` [PATCH iproute2-next v2 07/12] tcp_metrics: add json support Stephen Hemminger
@ 2018-03-06 21:07 ` Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 09/12] token: support JSON Stephen Hemminger
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2018-03-06 21:07 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Add json flag to ip sr command outputs.

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

diff --git a/ip/ipseg6.c b/ip/ipseg6.c
index e3ab31a516b8..6f5ae4d239f7 100644
--- a/ip/ipseg6.c
+++ b/ip/ipseg6.c
@@ -26,6 +26,7 @@
 #include "utils.h"
 #include "ip_common.h"
 #include "libgenl.h"
+#include "json_print.h"
 
 #define HMAC_KEY_PROMPT "Enter secret for HMAC key ID (blank to delete): "
 
@@ -55,12 +56,54 @@ static struct {
 	__u8 alg_id;
 } opts;
 
+static void print_dumphmac(struct rtattr *attrs[])
+{
+	char secret[64];
+	char *algstr;
+	__u8 slen = rta_getattr_u8(attrs[SEG6_ATTR_SECRETLEN]);
+	__u8 alg_id = rta_getattr_u8(attrs[SEG6_ATTR_ALGID]);
+
+	memset(secret, 0, 64);
+
+	if (slen > 63) {
+		fprintf(stderr, "HMAC secret length %d > 63, truncated\n", slen);
+		slen = 63;
+	}
+
+	memcpy(secret, RTA_DATA(attrs[SEG6_ATTR_SECRET]), slen);
+
+	switch (alg_id) {
+	case SEG6_HMAC_ALGO_SHA1:
+		algstr = "sha1";
+		break;
+	case SEG6_HMAC_ALGO_SHA256:
+		algstr = "sha256";
+		break;
+	default:
+		algstr = "<unknown>";
+	}
+
+	print_uint(PRINT_ANY, "hmac", "hmac %u ",
+		   rta_getattr_u32(attrs[SEG6_ATTR_HMACKEYID]));
+	print_string(PRINT_ANY, "algo", "algo %s ", algstr);
+	print_string(PRINT_ANY, "secret", "secret \"%s\"\n", secret);
+}
+
+static void print_tunsrc(struct rtattr *attrs[])
+{
+	const char *dst
+		= rt_addr_n2a(AF_INET6, 16,
+			      RTA_DATA(attrs[SEG6_ATTR_DST]));
+
+	print_string(PRINT_ANY, "tunsrc",
+		     "tunsrc addr %s\n", dst);
+}
+
 static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
 		       void *arg)
 {
 	struct rtattr *attrs[SEG6_ATTR_MAX + 1];
 	struct genlmsghdr *ghdr;
-	FILE *fp = (FILE *)arg;
 	int len = n->nlmsg_len;
 
 	if (n->nlmsg_type != genl_family)
@@ -74,50 +117,17 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
 
 	parse_rtattr(attrs, SEG6_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);
 
+	open_json_object(NULL);
 	switch (ghdr->cmd) {
 	case SEG6_CMD_DUMPHMAC:
-	{
-		char secret[64];
-		char *algstr;
-		__u8 slen = rta_getattr_u8(attrs[SEG6_ATTR_SECRETLEN]);
-		__u8 alg_id = rta_getattr_u8(attrs[SEG6_ATTR_ALGID]);
-
-		memset(secret, 0, 64);
-
-		if (slen > 63) {
-			fprintf(stderr, "HMAC secret length %d > 63, "
-					"truncated\n", slen);
-			slen = 63;
-		}
-		memcpy(secret, RTA_DATA(attrs[SEG6_ATTR_SECRET]), slen);
-
-		switch (alg_id) {
-		case SEG6_HMAC_ALGO_SHA1:
-			algstr = "sha1";
-			break;
-		case SEG6_HMAC_ALGO_SHA256:
-			algstr = "sha256";
-			break;
-		default:
-			algstr = "<unknown>";
-		}
-
-		fprintf(fp, "hmac %u ",
-			rta_getattr_u32(attrs[SEG6_ATTR_HMACKEYID]));
-		fprintf(fp, "algo %s ", algstr);
-		fprintf(fp, "secret \"%s\" ", secret);
-
-		fprintf(fp, "\n");
+		print_dumphmac(attrs);
 		break;
-	}
+
 	case SEG6_CMD_GET_TUNSRC:
-	{
-		fprintf(fp, "tunsrc addr %s\n",
-			rt_addr_n2a(AF_INET6, 16,
-				    RTA_DATA(attrs[SEG6_ATTR_DST])));
+		print_tunsrc(attrs);
 		break;
 	}
-	}
+	close_json_object();
 
 	return 0;
 }
@@ -169,10 +179,12 @@ static int seg6_do_cmd(void)
 	} else if (repl) {
 		if (rtnl_talk(&grth, &req.n, &answer) < 0)
 			return -2;
+		new_json_obj(json);
 		if (process_msg(NULL, answer, stdout) < 0) {
 			fprintf(stderr, "Error parsing reply\n");
 			exit(1);
 		}
+		delete_json_obj();
 		free(answer);
 	} else {
 		req.n.nlmsg_flags |= NLM_F_DUMP;
@@ -182,10 +194,13 @@ static int seg6_do_cmd(void)
 			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();
+		fflush(stdout);
 	}
 
 	return 0;
-- 
2.16.1

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

* [PATCH iproute2-next v2 09/12] token: support JSON
  2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
                   ` (7 preceding siblings ...)
  2018-03-06 21:07 ` [PATCH iproute2-next v2 08/12] ipsr: " Stephen Hemminger
@ 2018-03-06 21:07 ` Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 10/12] tuntap: support JSON output Stephen Hemminger
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2018-03-06 21:07 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Add JSON output to ip token command.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/iptoken.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/ip/iptoken.c b/ip/iptoken.c
index 48cc14b502c6..fb64da4ec262 100644
--- a/ip/iptoken.c
+++ b/ip/iptoken.c
@@ -25,6 +25,7 @@
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 extern struct rtnl_handle rth;
 
@@ -77,9 +78,17 @@ static int print_token(const struct sockaddr_nl *who, struct nlmsghdr *n, void *
 		return -1;
 	}
 
-	fprintf(fp, "token %s dev %s\n",
-	        format_host_rta(ifi->ifi_family, ltb[IFLA_INET6_TOKEN]),
-	        ll_index_to_name(ifi->ifi_index));
+	open_json_object(NULL);
+	print_string(PRINT_FP, NULL, "token ", NULL);
+	print_color_string(PRINT_ANY,
+			   ifa_family_color(ifi->ifi_family),
+			   "token", "%s",
+			   format_host_rta(ifi->ifi_family, ltb[IFLA_INET6_TOKEN]));
+	print_string(PRINT_FP, NULL, " dev ", NULL);
+	print_color_string(PRINT_ANY, COLOR_IFNAME,
+			   "ifname", "%s\n",
+			   ll_index_to_name(ifi->ifi_index));
+	close_json_object();
 	fflush(fp);
 
 	return 0;
@@ -105,10 +114,13 @@ static int iptoken_list(int argc, char **argv)
 		return -1;
 	}
 
+	new_json_obj(json);
 	if (rtnl_dump_filter(&rth, print_token, &da) < 0) {
+		delete_json_obj();
 		fprintf(stderr, "Dump terminated\n");
 		return -1;
 	}
+	delete_json_obj();
 
 	return 0;
 }
-- 
2.16.1

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

* [PATCH iproute2-next v2 10/12] tuntap: support JSON output
  2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
                   ` (8 preceding siblings ...)
  2018-03-06 21:07 ` [PATCH iproute2-next v2 09/12] token: support JSON Stephen Hemminger
@ 2018-03-06 21:07 ` Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 11/12] fou: break long lines Stephen Hemminger
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2018-03-06 21:07 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/iptuntap.c | 57 +++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 43 insertions(+), 14 deletions(-)

diff --git a/ip/iptuntap.c b/ip/iptuntap.c
index 2f49ff6d9281..6c5a7259d155 100644
--- a/ip/iptuntap.c
+++ b/ip/iptuntap.c
@@ -228,24 +228,35 @@ static int do_del(int argc, char **argv)
 
 static void print_flags(long flags)
 {
+	open_json_array(PRINT_JSON, "flags");
+
 	if (flags & IFF_TUN)
-		printf(" tun");
+		print_string(PRINT_ANY, NULL, " %s", "tun");
 
 	if (flags & IFF_TAP)
-		printf(" tap");
+		print_string(PRINT_ANY, NULL, " %s", "tap");
 
 	if (!(flags & IFF_NO_PI))
-		printf(" pi");
+		print_string(PRINT_ANY, NULL, " %s", "pi");
 
 	if (flags & IFF_ONE_QUEUE)
-		printf(" one_queue");
+		print_string(PRINT_ANY, NULL, " %s", "one_queue");
 
 	if (flags & IFF_VNET_HDR)
-		printf(" vnet_hdr");
+		print_string(PRINT_ANY, NULL, " %s", "vnet_hdr");
+
+	if (flags & IFF_PERSIST)
+		print_string(PRINT_ANY, NULL, " %s", "persist");
+
+	if (!(flags & IFF_NOFILTER))
+		print_string(PRINT_ANY, NULL, " %s", "filter");
 
-	flags &= ~(IFF_TUN|IFF_TAP|IFF_NO_PI|IFF_ONE_QUEUE|IFF_VNET_HDR);
+	flags &= ~(IFF_TUN | IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE |
+		   IFF_VNET_HDR | IFF_PERSIST | IFF_NOFILTER);
 	if (flags)
-		printf(" UNKNOWN_FLAGS:%lx", flags);
+		print_0xhex(PRINT_ANY, NULL, "%#x", flags);
+
+	close_json_array(PRINT_JSON, NULL);
 }
 
 static char *pid_name(pid_t pid)
@@ -288,6 +299,8 @@ static void show_processes(const char *name)
 	if (err)
 		return;
 
+	open_json_array(PRINT_JSON, "processes");
+
 	fd_path = globbuf.gl_pathv;
 	while (*fd_path) {
 		const char *dev_net_tun = "/dev/net/tun";
@@ -334,7 +347,11 @@ static void show_processes(const char *name)
 				   !strcmp(name, value)) {
 				char *pname = pid_name(pid);
 
-				printf(" %s(%d)", pname ? : "<NULL>", pid);
+				print_string(PRINT_ANY, "name",
+					     "%s", pname ? : "<NULL>");
+
+				print_uint(PRINT_ANY, "pid",
+					   "(%d)", pid);
 				free(pname);
 			}
 
@@ -347,6 +364,7 @@ static void show_processes(const char *name)
 next:
 		++fd_path;
 	}
+	close_json_array(PRINT_JSON, NULL);
 
 	globfree(&globbuf);
 }
@@ -417,18 +435,24 @@ static int print_tuntap(const struct sockaddr_nl *who,
 	if (read_prop(name, "group", &group))
 		return 0;
 
-	printf("%s:", name);
+	open_json_object(NULL);
+	print_color_string(PRINT_ANY, COLOR_IFNAME,
+			   "ifname", "%s:", name);
 	print_flags(flags);
 	if (owner != -1)
-		printf(" user %ld", owner);
+		print_uint(PRINT_ANY, "user",
+			   " user %ld", owner);
 	if (group != -1)
-		printf(" group %ld", group);
-	fputc('\n', stdout);
+		print_uint(PRINT_ANY, "group",
+			   " group %ld", group);
+
 	if (show_details) {
-		printf("\tAttached to processes:");
+		print_string(PRINT_FP, NULL,
+			     "%s\tAttached to processes:", _SL_);
 		show_processes(name);
-		fputc('\n', stdout);
 	}
+	close_json_object();
+	print_string(PRINT_FP, NULL, "%s", "\n");
 
 	return 0;
 }
@@ -441,11 +465,16 @@ static int do_show(int argc, char **argv)
 		return -1;
 	}
 
+	new_json_obj(json);
+
 	if (rtnl_dump_filter(&rth, print_tuntap, NULL) < 0) {
 		fprintf(stderr, "Dump terminated\n");
 		return -1;
 	}
 
+	delete_json_obj();
+	fflush(stdout);
+
 	return 0;
 }
 
-- 
2.16.1

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

* [PATCH iproute2-next v2 11/12] fou: break long lines
  2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
                   ` (9 preceding siblings ...)
  2018-03-06 21:07 ` [PATCH iproute2-next v2 10/12] tuntap: support JSON output Stephen Hemminger
@ 2018-03-06 21:07 ` Stephen Hemminger
  2018-03-06 21:07 ` [PATCH iproute2-next v2 12/12] fou: support JSON output Stephen Hemminger
  2018-03-06 23:51 ` [PATCH iproute2-next v2 00/12] ip more JSON David Ahern
  12 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2018-03-06 21:07 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Split up long lines.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/ipfou.c | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/ip/ipfou.c b/ip/ipfou.c
index 1f392adea29d..a5d1a4bbe30a 100644
--- a/ip/ipfou.c
+++ b/ip/ipfou.c
@@ -25,13 +25,13 @@
 
 static void usage(void)
 {
-	fprintf(stderr, "Usage: ip fou add port PORT "
-		"{ ipproto PROTO  | gue } [ -6 ]\n");
-	fprintf(stderr, "       ip fou del port PORT [ -6 ]\n");
-	fprintf(stderr, "       ip fou show\n");
-	fprintf(stderr, "\n");
-	fprintf(stderr, "Where: PROTO { ipproto-name | 1..255 }\n");
-	fprintf(stderr, "       PORT { 1..65535 }\n");
+	fprintf(stderr,
+		"Usage: ip fou add port PORT { ipproto PROTO  | gue } [ -6 ]\n"
+		"       ip fou del port PORT [ -6 ]\n"
+		"       ip fou show\n"
+		"\n"
+		"Where: PROTO { ipproto-name | 1..255 }\n"
+		"       PORT { 1..65535 }\n");
 
 	exit(-1);
 }
@@ -77,7 +77,8 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
 		} else if (!matches(*argv, "-6")) {
 			family = AF_INET6;
 		} else {
-			fprintf(stderr, "fou: unknown command \"%s\"?\n", *argv);
+			fprintf(stderr
+				, "fou: unknown command \"%s\"?\n", *argv);
 			usage();
 			return -1;
 		}
@@ -142,7 +143,7 @@ static int print_fou_mapping(const struct sockaddr_nl *who,
 	struct genlmsghdr *ghdr;
 	struct rtattr *tb[FOU_ATTR_MAX + 1];
 	int len = n->nlmsg_len;
-	unsigned family;
+	unsigned int family;
 
 	if (n->nlmsg_type != genl_family)
 		return 0;
@@ -175,7 +176,8 @@ static int do_show(int argc, char **argv)
 	FOU_REQUEST(req, 4096, FOU_CMD_GET, NLM_F_REQUEST | NLM_F_DUMP);
 
 	if (argc > 0) {
-		fprintf(stderr, "\"ip fou show\" does not take any arguments.\n");
+		fprintf(stderr,
+			"\"ip fou show\" does not take any arguments.\n");
 		return -1;
 	}
 
@@ -209,6 +211,8 @@ int do_ipfou(int argc, char **argv)
 		return do_del(argc-1, argv+1);
 	if (matches(*argv, "show") == 0)
 		return do_show(argc-1, argv+1);
-	fprintf(stderr, "Command \"%s\" is unknown, try \"ip fou help\".\n", *argv);
+
+	fprintf(stderr,
+		"Command \"%s\" is unknown, try \"ip fou help\".\n", *argv);
 	exit(-1);
 }
-- 
2.16.1

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

* [PATCH iproute2-next v2 12/12] fou: support JSON output
  2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
                   ` (10 preceding siblings ...)
  2018-03-06 21:07 ` [PATCH iproute2-next v2 11/12] fou: break long lines Stephen Hemminger
@ 2018-03-06 21:07 ` Stephen Hemminger
  2018-03-06 23:51 ` [PATCH iproute2-next v2 00/12] ip more JSON David Ahern
  12 siblings, 0 replies; 14+ messages in thread
From: Stephen Hemminger @ 2018-03-06 21:07 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/ipfou.c | 32 +++++++++++++++++++++++---------
 1 file changed, 23 insertions(+), 9 deletions(-)

diff --git a/ip/ipfou.c b/ip/ipfou.c
index a5d1a4bbe30a..0cb5e3c7a0c7 100644
--- a/ip/ipfou.c
+++ b/ip/ipfou.c
@@ -22,6 +22,7 @@
 #include "libgenl.h"
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 static void usage(void)
 {
@@ -139,11 +140,9 @@ static int do_del(int argc, char **argv)
 static int print_fou_mapping(const struct sockaddr_nl *who,
 				 struct nlmsghdr *n, void *arg)
 {
-	FILE *fp = (FILE *)arg;
 	struct genlmsghdr *ghdr;
 	struct rtattr *tb[FOU_ATTR_MAX + 1];
 	int len = n->nlmsg_len;
-	unsigned int family;
 
 	if (n->nlmsg_type != genl_family)
 		return 0;
@@ -155,18 +154,30 @@ static int print_fou_mapping(const struct sockaddr_nl *who,
 	ghdr = NLMSG_DATA(n);
 	parse_rtattr(tb, FOU_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len);
 
+	open_json_object(NULL);
 	if (tb[FOU_ATTR_PORT])
-		fprintf(fp, "port %u", ntohs(rta_getattr_u16(tb[FOU_ATTR_PORT])));
-	if (tb[FOU_ATTR_TYPE] && rta_getattr_u8(tb[FOU_ATTR_TYPE]) == FOU_ENCAP_GUE)
-		fprintf(fp, " gue");
+		print_uint(PRINT_ANY, "port", "port %u",
+			   ntohs(rta_getattr_u16(tb[FOU_ATTR_PORT])));
+
+	if (tb[FOU_ATTR_TYPE] &&
+	    rta_getattr_u8(tb[FOU_ATTR_TYPE]) == FOU_ENCAP_GUE)
+		print_null(PRINT_ANY, "gue", " gue", NULL);
 	else if (tb[FOU_ATTR_IPPROTO])
-		fprintf(fp, " ipproto %u", rta_getattr_u8(tb[FOU_ATTR_IPPROTO]));
+		print_uint(PRINT_ANY, "ipproto",
+			   " ipproto %u", rta_getattr_u8(tb[FOU_ATTR_IPPROTO]));
+
 	if (tb[FOU_ATTR_AF]) {
-		family = rta_getattr_u8(tb[FOU_ATTR_AF]);
+		__u8 family = rta_getattr_u8(tb[FOU_ATTR_AF]);
+
+		print_string(PRINT_JSON, "family", NULL,
+			     family_name(family));
+
 		if (family == AF_INET6)
-			fprintf(fp, " -6");
+			print_string(PRINT_FP, NULL,
+				     " -6", NULL);
 	}
-	fprintf(fp, "\n");
+	print_string(PRINT_FP, NULL, "\n", NULL);
+	close_json_object();
 
 	return 0;
 }
@@ -186,10 +197,13 @@ static int do_show(int argc, char **argv)
 		exit(1);
 	}
 
+	new_json_obj(json);
 	if (rtnl_dump_filter(&genl_rth, print_fou_mapping, stdout) < 0) {
 		fprintf(stderr, "Dump terminated\n");
 		return 1;
 	}
+	delete_json_obj();
+	fflush(stdout);
 
 	return 0;
 }
-- 
2.16.1

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

* Re: [PATCH iproute2-next v2 00/12] ip more JSON
  2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
                   ` (11 preceding siblings ...)
  2018-03-06 21:07 ` [PATCH iproute2-next v2 12/12] fou: support JSON output Stephen Hemminger
@ 2018-03-06 23:51 ` David Ahern
  12 siblings, 0 replies; 14+ messages in thread
From: David Ahern @ 2018-03-06 23:51 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, Stephen Hemminger

On 3/6/18 2:07 PM, Stephen Hemminger wrote:
> 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 (12):
>   ipneigh: add color and json support
>   ipaddrlabel: add json support
>   iprule: add json support
>   ipntable: add json support
>   ipnetconf: add JSON support
>   tcp_metrics; make tables const
>   tcp_metrics: add json support
>   ipsr: add json support
>   token: support JSON
>   tuntap: support JSON output
>   fou: break long lines
>   fou: support JSON output
> 

applied to iproute2-next.

glad to see the json support. Thanks for working on it.

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

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

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-06 21:07 [PATCH iproute2-next v2 00/12] ip more JSON Stephen Hemminger
2018-03-06 21:07 ` [PATCH iproute2-next v2 01/12] ipneigh: add color and json support Stephen Hemminger
2018-03-06 21:07 ` [PATCH iproute2-next v2 02/12] ipaddrlabel: add " Stephen Hemminger
2018-03-06 21:07 ` [PATCH iproute2-next v2 03/12] iprule: " Stephen Hemminger
2018-03-06 21:07 ` [PATCH iproute2-next v2 04/12] ipntable: " Stephen Hemminger
2018-03-06 21:07 ` [PATCH iproute2-next v2 05/12] ipnetconf: add JSON support Stephen Hemminger
2018-03-06 21:07 ` [PATCH iproute2-next v2 06/12] tcp_metrics; make tables const Stephen Hemminger
2018-03-06 21:07 ` [PATCH iproute2-next v2 07/12] tcp_metrics: add json support Stephen Hemminger
2018-03-06 21:07 ` [PATCH iproute2-next v2 08/12] ipsr: " Stephen Hemminger
2018-03-06 21:07 ` [PATCH iproute2-next v2 09/12] token: support JSON Stephen Hemminger
2018-03-06 21:07 ` [PATCH iproute2-next v2 10/12] tuntap: support JSON output Stephen Hemminger
2018-03-06 21:07 ` [PATCH iproute2-next v2 11/12] fou: break long lines Stephen Hemminger
2018-03-06 21:07 ` [PATCH iproute2-next v2 12/12] fou: support JSON output Stephen Hemminger
2018-03-06 23:51 ` [PATCH iproute2-next v2 00/12] ip more JSON David Ahern

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.