All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 iproute2-next 0/5] bridge: json and color support
@ 2018-02-20 19:24 Stephen Hemminger
  2018-02-20 19:24 ` [PATCH v2 iproute2-next 1/5] bridge: implement json pretty print flag Stephen Hemminger
                   ` (5 more replies)
  0 siblings, 6 replies; 10+ messages in thread
From: Stephen Hemminger @ 2018-02-20 19:24 UTC (permalink / raw)
  To: netdev; +Cc: Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

This set of patches adds color and full JSON support to bridge command.

The output format for bridge link command changes so that 
  $ bridge link show
and
  $ ip link show
use same basic format.

The "-c" flag to bridge changes from shortened form of "-compressvlan"
to shortened form of "-color".  Once again this is so that ip
and bridge command take similar options.

Lastly the JSON output format changes slightly but this
could not impact any real user, because in several cases
the current format was invalid JSON!

v2
  rebase to updated iproute2-next
  use common pretty flag
  use common print_name_and_link

Stephen Hemminger (5):
  bridge: implement json pretty print flag
  bridge: colorize output and use JSON print library
  bridge: add json support for link command
  bridge: update man page for new color and json changes
  ip: always print interface name in color

 bridge/br_common.h |   4 +-
 bridge/bridge.c    |  16 ++-
 bridge/fdb.c       | 279 ++++++++++++++++-------------------------
 bridge/link.c      | 245 +++++++++++++++++++-----------------
 bridge/mdb.c       | 354 ++++++++++++++++++++++-------------------------------
 bridge/vlan.c      | 279 ++++++++++++++++-------------------------
 include/utils.h    |   2 +-
 ip/ipaddress.c     |   4 +-
 lib/utils.c        |   4 +-
 man/man8/bridge.8  |  15 ++-
 10 files changed, 521 insertions(+), 681 deletions(-)

-- 
2.16.1

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

* [PATCH v2 iproute2-next 1/5] bridge: implement json pretty print flag
  2018-02-20 19:24 [PATCH v2 iproute2-next 0/5] bridge: json and color support Stephen Hemminger
@ 2018-02-20 19:24 ` Stephen Hemminger
  2018-02-20 19:24 ` [PATCH v2 iproute2-next 2/5] bridge: colorize output and use JSON print library Stephen Hemminger
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Stephen Hemminger @ 2018-02-20 19:24 UTC (permalink / raw)
  To: netdev; +Cc: Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Make bridge work like other iproute2 commands and accept
same json and pretty flags.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 bridge/br_common.h |  2 +-
 bridge/bridge.c    |  8 +++++---
 bridge/fdb.c       | 10 ++++++----
 bridge/mdb.c       | 12 ++++++++++--
 bridge/vlan.c      | 11 +++++++----
 man/man8/bridge.8  |  6 ++++++
 6 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/bridge/br_common.h b/bridge/br_common.h
index f07c7d1c9090..b25f61e50e05 100644
--- a/bridge/br_common.h
+++ b/bridge/br_common.h
@@ -26,5 +26,5 @@ extern int show_stats;
 extern int show_details;
 extern int timestamp;
 extern int compress_vlans;
-extern int json_output;
+extern int json;
 extern struct rtnl_handle rth;
diff --git a/bridge/bridge.c b/bridge/bridge.c
index 48fe1c8b2ef1..4b112e3b8da9 100644
--- a/bridge/bridge.c
+++ b/bridge/bridge.c
@@ -23,7 +23,7 @@ int oneline;
 int show_stats;
 int show_details;
 int compress_vlans;
-int json_output;
+int json;
 int timestamp;
 char *batch_file;
 int force;
@@ -39,7 +39,7 @@ static void usage(void)
 "where	OBJECT := { link | fdb | mdb | vlan | monitor }\n"
 "	OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
 "		     -o[neline] | -t[imestamp] | -n[etns] name |\n"
-"		     -c[ompressvlans] -j{son} }\n");
+"		     -c[ompressvlans] -p[retty] -j{son} }\n");
 	exit(-1);
 }
 
@@ -175,7 +175,9 @@ main(int argc, char **argv)
 		} else if (matches(opt, "-force") == 0) {
 			++force;
 		} else if (matches(opt, "-json") == 0) {
-			++json_output;
+			++json;
+		} else if (matches(opt, "-pretty") == 0) {
+			++pretty;
 		} else if (matches(opt, "-batch") == 0) {
 			argc--;
 			argv++;
diff --git a/bridge/fdb.c b/bridge/fdb.c
index 8b133f9c1c8d..93b5b2e694e3 100644
--- a/bridge/fdb.c
+++ b/bridge/fdb.c
@@ -132,10 +132,8 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	if (filter_vlan && filter_vlan != vid)
 		return 0;
 
-	if (jw_global) {
-		jsonw_pretty(jw_global, 1);
+	if (jw_global)
 		jsonw_start_object(jw_global);
-	}
 
 	if (n->nlmsg_type == RTM_DELNEIGH) {
 		if (jw_global)
@@ -388,14 +386,18 @@ static int fdb_show(int argc, char **argv)
 		exit(1);
 	}
 
-	if (json_output) {
+	if (json) {
 		jw_global = jsonw_new(stdout);
 		if (!jw_global) {
 			fprintf(stderr, "Error allocation json object\n");
 			exit(1);
 		}
+		if (pretty)
+			jsonw_pretty(jw_global, 1);
+
 		jsonw_start_array(jw_global);
 	}
+
 	if (rtnl_dump_filter(&rth, print_fdb, stdout) < 0) {
 		fprintf(stderr, "Dump terminated\n");
 		exit(1);
diff --git a/bridge/mdb.c b/bridge/mdb.c
index 62dc8a0c58c3..da0282fdc91c 100644
--- a/bridge/mdb.c
+++ b/bridge/mdb.c
@@ -325,7 +325,7 @@ static int mdb_show(int argc, char **argv)
 		return -1;
 	}
 
-	if (!json_output) {
+	if (!json) {
 		/* Normal output */
 		if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
 			fprintf(stderr, "Dump terminated\n");
@@ -333,9 +333,17 @@ static int mdb_show(int argc, char **argv)
 		}
 		return 0;
 	}
+
 	/* Json output */
 	jw_global = jsonw_new(stdout);
-	jsonw_pretty(jw_global, 1);
+	if (!jw_global) {
+		fprintf(stderr, "Error allocation json object\n");
+		exit(1);
+	}
+
+	if (pretty)
+		jsonw_pretty(jw_global, 1);
+
 	jsonw_start_object(jw_global);
 	jsonw_name(jw_global, "mdb");
 	jsonw_start_array(jw_global);
diff --git a/bridge/vlan.c b/bridge/vlan.c
index f42d7e6ba244..7c8b3ad54857 100644
--- a/bridge/vlan.c
+++ b/bridge/vlan.c
@@ -258,7 +258,6 @@ static int filter_vlan_check(__u16 vid, __u16 flags)
 static void print_vlan_port(FILE *fp, int ifi_index)
 {
 	if (jw_global) {
-		jsonw_pretty(jw_global, 1);
 		jsonw_name(jw_global,
 			   ll_index_to_name(ifi_index));
 		jsonw_start_array(jw_global);
@@ -578,17 +577,21 @@ static int vlan_show(int argc, char **argv)
 	if (!show_stats) {
 		if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
 					     (compress_vlans ?
-						RTEXT_FILTER_BRVLAN_COMPRESSED :
-						RTEXT_FILTER_BRVLAN)) < 0) {
+					      RTEXT_FILTER_BRVLAN_COMPRESSED :
+					      RTEXT_FILTER_BRVLAN)) < 0) {
 			perror("Cannont send dump request");
 			exit(1);
 		}
-		if (json_output) {
+
+		if (json) {
 			jw_global = jsonw_new(stdout);
 			if (!jw_global) {
 				fprintf(stderr, "Error allocation json object\n");
 				exit(1);
 			}
+			if (pretty)
+				jsonw_pretty(jw_global, 1);
+
 			jsonw_start_object(jw_global);
 		} else {
 			if (show_vlan_tunnel_info)
diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index d6baa819020a..490ef58da16c 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -22,6 +22,7 @@ bridge \- show / manipulate bridge addresses and devices
 \fB\-s\fR[\fItatistics\fR] |
 \fB\-n\fR[\fIetns\fR] name |
 \fB\-b\fR[\fIatch\fR] filename |
+\fB\-p\fR[\fIretty\fR] |
 \fB\-j\fR[\fIson\fR] }
 
 .ti -8
@@ -171,6 +172,11 @@ return code will be non zero.
 .BR "\-json"
 Display results in JSON format. Currently available for vlan and fdb.
 
+.TP
+.BR "\-pretty"
+When combined with -j generate a pretty JSON output.
+
+
 .SH BRIDGE - COMMAND SYNTAX
 
 .SS
-- 
2.16.1

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

* [PATCH v2 iproute2-next 2/5] bridge: colorize output and use JSON print library
  2018-02-20 19:24 [PATCH v2 iproute2-next 0/5] bridge: json and color support Stephen Hemminger
  2018-02-20 19:24 ` [PATCH v2 iproute2-next 1/5] bridge: implement json pretty print flag Stephen Hemminger
@ 2018-02-20 19:24 ` Stephen Hemminger
  2018-07-15  1:41   ` Roopa Prabhu
  2018-02-20 19:24 ` [PATCH v2 iproute2-next 3/5] bridge: add json support for link command Stephen Hemminger
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 10+ messages in thread
From: Stephen Hemminger @ 2018-02-20 19:24 UTC (permalink / raw)
  To: netdev; +Cc: Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Use new functions from json_print to simplify code.
Provide standard flag for colorizing output.

The shortened -c flag is ambiguous it could mean color or
compressvlan; it is now changed to mean color for consistency
with other iproute2 commands.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 bridge/br_common.h |   2 +-
 bridge/bridge.c    |  10 +-
 bridge/fdb.c       | 281 +++++++++++++++--------------------------
 bridge/mdb.c       | 362 ++++++++++++++++++++++-------------------------------
 bridge/vlan.c      | 276 +++++++++++++++-------------------------
 5 files changed, 363 insertions(+), 568 deletions(-)

diff --git a/bridge/br_common.h b/bridge/br_common.h
index b25f61e50e05..2f1cb8fd9f3d 100644
--- a/bridge/br_common.h
+++ b/bridge/br_common.h
@@ -6,7 +6,7 @@
 #define MDB_RTR_RTA(r) \
 		((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(__u32))))
 
-extern void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex);
+extern void print_vlan_info(FILE *fp, struct rtattr *tb);
 extern int print_linkinfo(const struct sockaddr_nl *who,
 			  struct nlmsghdr *n,
 			  void *arg);
diff --git a/bridge/bridge.c b/bridge/bridge.c
index 4b112e3b8da9..e5b4c3c2198f 100644
--- a/bridge/bridge.c
+++ b/bridge/bridge.c
@@ -16,12 +16,15 @@
 #include "utils.h"
 #include "br_common.h"
 #include "namespace.h"
+#include "color.h"
 
 struct rtnl_handle rth = { .fd = -1 };
 int preferred_family = AF_UNSPEC;
 int oneline;
 int show_stats;
 int show_details;
+int show_pretty;
+int color;
 int compress_vlans;
 int json;
 int timestamp;
@@ -39,7 +42,7 @@ static void usage(void)
 "where	OBJECT := { link | fdb | mdb | vlan | monitor }\n"
 "	OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
 "		     -o[neline] | -t[imestamp] | -n[etns] name |\n"
-"		     -c[ompressvlans] -p[retty] -j{son} }\n");
+"		     -c[ompressvlans] -color -p[retty] -j{son} }\n");
 	exit(-1);
 }
 
@@ -170,6 +173,8 @@ main(int argc, char **argv)
 			NEXT_ARG();
 			if (netns_switch(argv[1]))
 				exit(-1);
+		} else if (matches(opt, "-color") == 0) {
+			enable_color();
 		} else if (matches(opt, "-compressvlans") == 0) {
 			++compress_vlans;
 		} else if (matches(opt, "-force") == 0) {
@@ -195,6 +200,9 @@ main(int argc, char **argv)
 
 	_SL_ = oneline ? "\\" : "\n";
 
+	if (json)
+		check_if_color_enabled();
+
 	if (batch_file)
 		return batch(batch_file);
 
diff --git a/bridge/fdb.c b/bridge/fdb.c
index 93b5b2e694e3..b4f6e8b3a01b 100644
--- a/bridge/fdb.c
+++ b/bridge/fdb.c
@@ -22,9 +22,9 @@
 #include <linux/neighbour.h>
 #include <string.h>
 #include <limits.h>
-#include <json_writer.h>
 #include <stdbool.h>
 
+#include "json_print.h"
 #include "libnetlink.h"
 #include "br_common.h"
 #include "rt_names.h"
@@ -32,8 +32,6 @@
 
 static unsigned int filter_index, filter_vlan, filter_state;
 
-json_writer_t *jw_global;
-
 static void usage(void)
 {
 	fprintf(stderr,
@@ -83,13 +81,46 @@ static int state_a2n(unsigned int *s, const char *arg)
 	return 0;
 }
 
-static void start_json_fdb_flags_array(bool *fdb_flags)
+static void fdb_print_flags(FILE *fp, unsigned int flags)
+{
+	open_json_array(PRINT_JSON,
+			is_json_context() ?  "flags" : "");
+
+	if (flags & NTF_SELF)
+		print_string(PRINT_ANY, NULL, "%s ", "self");
+
+	if (flags & NTF_ROUTER)
+		print_string(PRINT_ANY, NULL, "%s ", "router");
+
+	if (flags & NTF_EXT_LEARNED)
+		print_string(PRINT_ANY, NULL, "%s ", "extern_learn");
+
+	if (flags & NTF_OFFLOADED)
+		print_string(PRINT_ANY, NULL, "%s ", "offload");
+
+	if (flags & NTF_MASTER)
+		print_string(PRINT_ANY, NULL, "%s ", "master");
+
+	close_json_array(PRINT_JSON, NULL);
+}
+
+static void fdb_print_stats(FILE *fp, const struct nda_cacheinfo *ci)
 {
-	if (*fdb_flags)
-		return;
-	jsonw_name(jw_global, "flags");
-	jsonw_start_array(jw_global);
-	*fdb_flags = true;
+	static int hz;
+
+	if (!hz)
+		hz = get_user_hz();
+
+	if (is_json_context()) {
+		print_uint(PRINT_JSON, "used", NULL,
+				 ci->ndm_used / hz);
+		print_uint(PRINT_JSON, "updated", NULL,
+				ci->ndm_updated / hz);
+	} else {
+		fprintf(fp, "used %d/%d ", ci->ndm_used / hz,
+					ci->ndm_updated / hz);
+
+	}
 }
 
 int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
@@ -99,8 +130,6 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	int len = n->nlmsg_len;
 	struct rtattr *tb[NDA_MAX+1];
 	__u16 vid = 0;
-	bool fdb_flags = false;
-	const char *state_s;
 
 	if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) {
 		fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
@@ -132,189 +161,98 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	if (filter_vlan && filter_vlan != vid)
 		return 0;
 
-	if (jw_global)
-		jsonw_start_object(jw_global);
-
-	if (n->nlmsg_type == RTM_DELNEIGH) {
-		if (jw_global)
-			jsonw_string_field(jw_global, "opCode", "deleted");
-		else
-			fprintf(fp, "Deleted ");
-	}
+	open_json_object(NULL);
+	if (n->nlmsg_type == RTM_DELNEIGH)
+		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
 	if (tb[NDA_LLADDR]) {
+		const char *lladdr;
 		SPRINT_BUF(b1);
-		ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
-			    RTA_PAYLOAD(tb[NDA_LLADDR]),
-			    ll_index_to_type(r->ndm_ifindex),
-			    b1, sizeof(b1));
-		if (jw_global)
-			jsonw_string_field(jw_global, "mac", b1);
-		else
-			fprintf(fp, "%s ", b1);
+
+		lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
+				     RTA_PAYLOAD(tb[NDA_LLADDR]),
+				     ll_index_to_type(r->ndm_ifindex),
+				     b1, sizeof(b1));
+
+		print_color_string(PRINT_ANY, COLOR_MAC,
+				   "mac", "%s ", lladdr);
 	}
 
 	if (!filter_index && r->ndm_ifindex) {
-		if (jw_global)
-			jsonw_string_field(jw_global, "dev",
-					   ll_index_to_name(r->ndm_ifindex));
-		else
-			fprintf(fp, "dev %s ",
-				ll_index_to_name(r->ndm_ifindex));
+		if (!is_json_context())
+			fprintf(fp, "dev ");
+		print_color_string(PRINT_ANY, COLOR_IFNAME,
+				   "ifname", "%s ",
+				   ll_index_to_name(r->ndm_ifindex));
 	}
 
 	if (tb[NDA_DST]) {
 		int family = AF_INET;
-		const char *abuf_s;
+		const char *dst;
 
 		if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
 			family = AF_INET6;
 
-		abuf_s = format_host(family,
-				     RTA_PAYLOAD(tb[NDA_DST]),
-				     RTA_DATA(tb[NDA_DST]));
-		if (jw_global)
-			jsonw_string_field(jw_global, "dst", abuf_s);
-		else
-			fprintf(fp, "dst %s ", abuf_s);
-	}
+		dst = format_host(family,
+				  RTA_PAYLOAD(tb[NDA_DST]),
+				  RTA_DATA(tb[NDA_DST]));
 
-	if (vid) {
-		if (jw_global)
-			jsonw_uint_field(jw_global, "vlan", vid);
-		else
-			fprintf(fp, "vlan %hu ", vid);
+		print_color_string(PRINT_ANY,
+				   ifa_family_color(family),
+				    "dst", "%s ", dst);
 	}
 
-	if (tb[NDA_PORT]) {
-		if (jw_global)
-			jsonw_uint_field(jw_global, "port",
-					 rta_getattr_be16(tb[NDA_PORT]));
-		else
-			fprintf(fp, "port %d ",
-				rta_getattr_be16(tb[NDA_PORT]));
-	}
+	if (vid)
+		print_uint(PRINT_ANY,
+				 "vlan", "vlan %hu ", vid);
 
-	if (tb[NDA_VNI]) {
-		if (jw_global)
-			jsonw_uint_field(jw_global, "vni",
-					 rta_getattr_u32(tb[NDA_VNI]));
-		else
-			fprintf(fp, "vni %d ",
-				rta_getattr_u32(tb[NDA_VNI]));
-	}
+	if (tb[NDA_PORT])
+		print_uint(PRINT_ANY,
+				 "port", "port %u ",
+				 rta_getattr_be16(tb[NDA_PORT]));
 
-	if (tb[NDA_SRC_VNI]) {
-		if (jw_global)
-			jsonw_uint_field(jw_global, "src_vni",
-					 rta_getattr_u32(tb[NDA_SRC_VNI]));
-		else
-			fprintf(fp, "src_vni %d ",
+	if (tb[NDA_VNI])
+		print_uint(PRINT_ANY,
+				 "vni", "vni %u ",
+				 rta_getattr_u32(tb[NDA_VNI]));
+
+	if (tb[NDA_SRC_VNI])
+		print_uint(PRINT_ANY,
+				 "src_vni", "src_vni %u ",
 				rta_getattr_u32(tb[NDA_SRC_VNI]));
-	}
 
 	if (tb[NDA_IFINDEX]) {
 		unsigned int ifindex = rta_getattr_u32(tb[NDA_IFINDEX]);
 
-		if (ifindex) {
-			if (!tb[NDA_LINK_NETNSID]) {
-				const char *ifname = ll_index_to_name(ifindex);
-
-				if (jw_global)
-					jsonw_string_field(jw_global, "viaIf",
-							   ifname);
-				else
-					fprintf(fp, "via %s ", ifname);
-			} else {
-				if (jw_global)
-					jsonw_uint_field(jw_global, "viaIfIndex",
-							 ifindex);
-				else
-					fprintf(fp, "via ifindex %u ", ifindex);
-			}
-		}
-	}
-
-	if (tb[NDA_LINK_NETNSID]) {
-		if (jw_global)
-			jsonw_uint_field(jw_global, "linkNetNsId",
-					 rta_getattr_u32(tb[NDA_LINK_NETNSID]));
+		if (tb[NDA_LINK_NETNSID])
+			print_uint(PRINT_ANY,
+					 "viaIfIndex", "via ifindex %u ",
+					 ifindex);
 		else
-			fprintf(fp, "link-netnsid %d ",
-				rta_getattr_u32(tb[NDA_LINK_NETNSID]));
+			print_string(PRINT_ANY,
+					   "viaIf", "via %s ",
+					   ll_index_to_name(ifindex));
 	}
 
-	if (show_stats && tb[NDA_CACHEINFO]) {
-		struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
-		int hz = get_user_hz();
+	if (tb[NDA_LINK_NETNSID])
+		print_uint(PRINT_ANY,
+				 "linkNetNsId", "link-netnsid %d ",
+				 rta_getattr_u32(tb[NDA_LINK_NETNSID]));
 
-		if (jw_global) {
-			jsonw_uint_field(jw_global, "used",
-				ci->ndm_used/hz);
-			jsonw_uint_field(jw_global, "updated",
-				ci->ndm_updated/hz);
-		} else {
-			fprintf(fp, "used %d/%d ", ci->ndm_used/hz,
-					ci->ndm_updated/hz);
-		}
-	}
+	if (show_stats && tb[NDA_CACHEINFO])
+		fdb_print_stats(fp, RTA_DATA(tb[NDA_CACHEINFO]));
 
-	if (jw_global) {
-		if (r->ndm_flags & NTF_SELF) {
-			start_json_fdb_flags_array(&fdb_flags);
-			jsonw_string(jw_global, "self");
-		}
-		if (r->ndm_flags & NTF_ROUTER) {
-			start_json_fdb_flags_array(&fdb_flags);
-			jsonw_string(jw_global, "router");
-		}
-		if (r->ndm_flags & NTF_EXT_LEARNED) {
-			start_json_fdb_flags_array(&fdb_flags);
-			jsonw_string(jw_global, "extern_learn");
-		}
-		if (r->ndm_flags & NTF_OFFLOADED) {
-			start_json_fdb_flags_array(&fdb_flags);
-			jsonw_string(jw_global, "offload");
-		}
-		if (r->ndm_flags & NTF_MASTER)
-			jsonw_string(jw_global, "master");
-		if (fdb_flags)
-			jsonw_end_array(jw_global);
+	fdb_print_flags(fp, r->ndm_flags);
 
-		if (tb[NDA_MASTER])
-			jsonw_string_field(jw_global,
-					   "master",
-					   ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
 
-	} else {
-		if (r->ndm_flags & NTF_SELF)
-			fprintf(fp, "self ");
-		if (r->ndm_flags & NTF_ROUTER)
-			fprintf(fp, "router ");
-		if (r->ndm_flags & NTF_EXT_LEARNED)
-			fprintf(fp, "extern_learn ");
-		if (r->ndm_flags & NTF_OFFLOADED)
-			fprintf(fp, "offload ");
-		if (tb[NDA_MASTER]) {
-			fprintf(fp, "master %s ",
-				ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
-		} else if (r->ndm_flags & NTF_MASTER) {
-			fprintf(fp, "master ");
-		}
-	}
-
-	state_s = state_n2a(r->ndm_state);
-	if (jw_global) {
-		if (state_s[0])
-			jsonw_string_field(jw_global, "state", state_s);
-
-		jsonw_end_object(jw_global);
-	} else {
-		fprintf(fp, "%s\n", state_s);
-
-		fflush(fp);
-	}
+	if (tb[NDA_MASTER])
+		print_string(PRINT_ANY, "master", "%s ",
+			     ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
 
+	print_string(PRINT_ANY, "state", "%s\n",
+			   state_n2a(r->ndm_state));
+	close_json_object();
+	fflush(fp);
 	return 0;
 }
 
@@ -386,26 +324,13 @@ static int fdb_show(int argc, char **argv)
 		exit(1);
 	}
 
-	if (json) {
-		jw_global = jsonw_new(stdout);
-		if (!jw_global) {
-			fprintf(stderr, "Error allocation json object\n");
-			exit(1);
-		}
-		if (pretty)
-			jsonw_pretty(jw_global, 1);
-
-		jsonw_start_array(jw_global);
-	}
-
+	new_json_obj(json);
 	if (rtnl_dump_filter(&rth, print_fdb, stdout) < 0) {
 		fprintf(stderr, "Dump terminated\n");
 		exit(1);
 	}
-	if (jw_global) {
-		jsonw_end_array(jw_global);
-		jsonw_destroy(&jw_global);
-	}
+	delete_json_obj();
+	fflush(stdout);
 
 	return 0;
 }
diff --git a/bridge/mdb.c b/bridge/mdb.c
index da0282fdc91c..8c08baf570ec 100644
--- a/bridge/mdb.c
+++ b/bridge/mdb.c
@@ -14,12 +14,12 @@
 #include <linux/if_ether.h>
 #include <string.h>
 #include <arpa/inet.h>
-#include <json_writer.h>
 
 #include "libnetlink.h"
 #include "br_common.h"
 #include "rt_names.h"
 #include "utils.h"
+#include "json_print.h"
 
 #ifndef MDBA_RTA
 #define MDBA_RTA(r) \
@@ -27,9 +27,6 @@
 #endif
 
 static unsigned int filter_index, filter_vlan;
-json_writer_t *jw_global;
-static bool print_mdb_entries = true;
-static bool print_mdb_router = true;
 
 static void usage(void)
 {
@@ -43,162 +40,131 @@ static bool is_temp_mcast_rtr(__u8 type)
 	return type == MDB_RTR_TYPE_TEMP_QUERY || type == MDB_RTR_TYPE_TEMP;
 }
 
+static const char *format_timer(__u32 ticks)
+{
+	struct timeval tv;
+	static char tbuf[32];
+
+	__jiffies_to_tv(&tv, ticks);
+	snprintf(tbuf, sizeof(tbuf), "%4lu.%.2lu",
+		 (unsigned long)tv.tv_sec,
+		 (unsigned long)tv.tv_usec / 10000);
+
+	return tbuf;
+}
+
 static void __print_router_port_stats(FILE *f, struct rtattr *pattr)
 {
 	struct rtattr *tb[MDBA_ROUTER_PATTR_MAX + 1];
-	struct timeval tv;
-	__u8 type;
 
 	parse_rtattr(tb, MDBA_ROUTER_PATTR_MAX, MDB_RTR_RTA(RTA_DATA(pattr)),
 		     RTA_PAYLOAD(pattr) - RTA_ALIGN(sizeof(uint32_t)));
+
 	if (tb[MDBA_ROUTER_PATTR_TIMER]) {
-		__jiffies_to_tv(&tv,
-				rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]));
-		if (jw_global) {
-			char formatted_time[9];
-
-			snprintf(formatted_time, sizeof(formatted_time),
-				 "%4i.%.2i", (int)tv.tv_sec,
-				 (int)tv.tv_usec/10000);
-			jsonw_string_field(jw_global, "timer", formatted_time);
-		} else {
-			fprintf(f, " %4i.%.2i",
-				(int)tv.tv_sec, (int)tv.tv_usec/10000);
-		}
+		__u32 timer = rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]);
+
+		print_string(PRINT_ANY, "timer", " %s",
+			     format_timer(timer));
 	}
+
 	if (tb[MDBA_ROUTER_PATTR_TYPE]) {
-		type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
-		if (jw_global)
-			jsonw_string_field(jw_global, "type",
-				is_temp_mcast_rtr(type) ? "temp" : "permanent");
-		else
-			fprintf(f, " %s",
-				is_temp_mcast_rtr(type) ? "temp" : "permanent");
+		__u8 type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
+
+		print_string(PRINT_ANY, "type", " %s",
+			     is_temp_mcast_rtr(type) ? "temp" : "permanent");
 	}
 }
 
-static void br_print_router_ports(FILE *f, struct rtattr *attr, __u32 brifidx)
+static void br_print_router_ports(FILE *f, struct rtattr *attr,
+				  const char *brifname)
 {
-	uint32_t *port_ifindex;
+	int rem = RTA_PAYLOAD(attr);
 	struct rtattr *i;
-	int rem;
 
-	rem = RTA_PAYLOAD(attr);
-	if (jw_global) {
-		jsonw_name(jw_global, ll_index_to_name(brifidx));
-		jsonw_start_array(jw_global);
-		for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
-			port_ifindex = RTA_DATA(i);
-			jsonw_start_object(jw_global);
-			jsonw_string_field(jw_global,
-					   "port",
-					   ll_index_to_name(*port_ifindex));
+	if (is_json_context())
+		open_json_array(PRINT_JSON, brifname);
+	else if (!show_stats)
+		fprintf(f, "router ports on %s: ", brifname);
+
+	for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+		uint32_t *port_ifindex = RTA_DATA(i);
+		const char *port_ifname = ll_index_to_name(*port_ifindex);
+
+		if (is_json_context()) {
+			open_json_object(NULL);
+			print_string(PRINT_JSON, "port", NULL, port_ifname);
+
 			if (show_stats)
 				__print_router_port_stats(f, i);
-			jsonw_end_object(jw_global);
-		}
-		jsonw_end_array(jw_global);
-	} else {
-		if (!show_stats)
-			fprintf(f, "router ports on %s: ",
-				ll_index_to_name(brifidx));
-		for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
-			port_ifindex = RTA_DATA(i);
-			if (show_stats) {
-				fprintf(f, "router ports on %s: %s",
-					ll_index_to_name(brifidx),
-					ll_index_to_name(*port_ifindex));
-				__print_router_port_stats(f, i);
-				fprintf(f, "\n");
-			} else{
-				fprintf(f, "%s ",
-					ll_index_to_name(*port_ifindex));
-			}
-		}
-		if (!show_stats)
+			close_json_object();
+		} else if (show_stats) {
+			fprintf(f, "router ports on %s: %s",
+				brifname, port_ifname);
+
+			__print_router_port_stats(f, i);
 			fprintf(f, "\n");
+		} else {
+			fprintf(f, "%s ", port_ifname);
+		}
 	}
+	close_json_array(PRINT_JSON, NULL);
 }
 
-static void start_json_mdb_flags_array(bool *mdb_flags)
-{
-	if (*mdb_flags)
-		return;
-	jsonw_name(jw_global, "flags");
-	jsonw_start_array(jw_global);
-	*mdb_flags = true;
-}
-
-static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e,
+static void print_mdb_entry(FILE *f, int ifindex, const struct br_mdb_entry *e,
 			    struct nlmsghdr *n, struct rtattr **tb)
 {
 	SPRINT_BUF(abuf);
+	const char *dev;
 	const void *src;
 	int af;
-	bool mdb_flags = false;
 
 	if (filter_vlan && e->vid != filter_vlan)
 		return;
+
 	af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6;
 	src = af == AF_INET ? (const void *)&e->addr.u.ip4 :
 			      (const void *)&e->addr.u.ip6;
-	if (jw_global)
-		jsonw_start_object(jw_global);
-	if (n->nlmsg_type == RTM_DELMDB) {
-		if (jw_global)
-			jsonw_string_field(jw_global, "opCode", "deleted");
-		else
-			fprintf(f, "Deleted ");
-	}
-	if (jw_global) {
-		jsonw_string_field(jw_global, "dev", ll_index_to_name(ifindex));
-		jsonw_string_field(jw_global,
-				   "port",
-				   ll_index_to_name(e->ifindex));
-		jsonw_string_field(jw_global, "grp", inet_ntop(af, src,
-			abuf, sizeof(abuf)));
-		jsonw_string_field(jw_global, "state",
-			(e->state & MDB_PERMANENT) ? "permanent" : "temp");
-		if (e->flags & MDB_FLAGS_OFFLOAD) {
-			start_json_mdb_flags_array(&mdb_flags);
-			jsonw_string(jw_global, "offload");
-		}
-		if (mdb_flags)
-			jsonw_end_array(jw_global);
-	} else{
-		fprintf(f, "dev %s port %s grp %s %s %s",
-			ll_index_to_name(ifindex),
-			ll_index_to_name(e->ifindex),
-			inet_ntop(af, src, abuf, sizeof(abuf)),
-			(e->state & MDB_PERMANENT) ? "permanent" : "temp",
-			(e->flags & MDB_FLAGS_OFFLOAD) ? "offload" : "");
-	}
-	if (e->vid) {
-		if (jw_global)
-			jsonw_uint_field(jw_global, "vid", e->vid);
-		else
-			fprintf(f, " vid %hu", e->vid);
+	dev = ll_index_to_name(ifindex);
+
+	open_json_object(NULL);
+
+	if (n->nlmsg_type == RTM_DELMDB)
+		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
+
+
+	if (is_json_context()) {
+		print_int(PRINT_JSON, "index", NULL, ifindex);
+		print_string(PRINT_JSON, "dev", NULL, dev);
+	} else {
+		fprintf(f, "%u: ", ifindex);
+		color_fprintf(f, COLOR_IFNAME, "%s ", dev);
 	}
-	if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
-		struct timeval tv;
 
-		__jiffies_to_tv(&tv, rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]));
-		if (jw_global) {
-			char formatted_time[9];
+	print_string(PRINT_ANY, "port", " %s ",
+		     ll_index_to_name(e->ifindex));
 
-			snprintf(formatted_time, sizeof(formatted_time),
-				 "%4i.%.2i", (int)tv.tv_sec,
-				 (int)tv.tv_usec/10000);
-			jsonw_string_field(jw_global, "timer", formatted_time);
-		} else {
-			fprintf(f, "%4i.%.2i", (int)tv.tv_sec,
-				(int)tv.tv_usec/10000);
-		}
+	print_color_string(PRINT_ANY, ifa_family_color(af),
+			    "grp", " %s ",
+			    inet_ntop(af, src, abuf, sizeof(abuf)));
+
+	print_string(PRINT_ANY, "state", " %s ",
+			   (e->state & MDB_PERMANENT) ? "permanent" : "temp");
+
+	open_json_array(PRINT_JSON, "flags");
+	if (e->flags & MDB_FLAGS_OFFLOAD)
+		print_string(PRINT_ANY, NULL, "%s ", "offload");
+	close_json_array(PRINT_JSON, NULL);
+
+	if (e->vid)
+		print_uint(PRINT_ANY, "vid", " vid %u", e->vid);
+
+	if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
+		__u32 timer = rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]);
+
+		print_string(PRINT_ANY, "timer", " %s",
+			     format_timer(timer));
 	}
-	if (jw_global)
-		jsonw_end_object(jw_global);
-	else
-		fprintf(f, "\n");
+	close_json_object();
 }
 
 static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
@@ -218,15 +184,60 @@ static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
 	}
 }
 
+static void print_mdb_entries(FILE *fp, struct nlmsghdr *n,
+			      int ifindex,  struct rtattr *mdb)
+{
+	int rem = RTA_PAYLOAD(mdb);
+	struct rtattr *i;
+
+	open_json_array(PRINT_JSON, "mdb");
+	for (i = RTA_DATA(mdb); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
+		br_print_mdb_entry(fp, ifindex, i, n);
+	close_json_array(PRINT_JSON, NULL);
+}
+
+static void print_router_entries(FILE *fp, struct nlmsghdr *n,
+				 int ifindex, struct rtattr *router)
+{
+	const char *brifname = ll_index_to_name(ifindex);
+
+	open_json_array(PRINT_JSON, "router");
+	if (n->nlmsg_type == RTM_GETMDB) {
+		if (show_details)
+			br_print_router_ports(fp, router, brifname);
+	} else {
+		struct rtattr *i = RTA_DATA(router);
+		uint32_t *port_ifindex = RTA_DATA(i);
+
+		if (is_json_context()) {
+			open_json_array(PRINT_JSON, brifname);
+			open_json_object(NULL);
+
+			print_string(PRINT_JSON, "port", NULL,
+				     ll_index_to_name(*port_ifindex));
+			close_json_object();
+			close_json_array(PRINT_JSON, NULL);
+		} else {
+			fprintf(fp, "router port dev %s master %s\n",
+				ll_index_to_name(*port_ifindex),
+				brifname);
+		}
+	}
+	close_json_array(PRINT_JSON, NULL);
+}
+
 int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = arg;
 	struct br_port_msg *r = NLMSG_DATA(n);
 	int len = n->nlmsg_len;
-	struct rtattr *tb[MDBA_MAX+1], *i;
+	struct rtattr *tb[MDBA_MAX+1];
 
-	if (n->nlmsg_type != RTM_GETMDB && n->nlmsg_type != RTM_NEWMDB && n->nlmsg_type != RTM_DELMDB) {
-		fprintf(stderr, "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
+	if (n->nlmsg_type != RTM_GETMDB &&
+	    n->nlmsg_type != RTM_NEWMDB &&
+	    n->nlmsg_type != RTM_DELMDB) {
+		fprintf(stderr,
+			"Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
 			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
 
 		return 0;
@@ -243,50 +254,14 @@ int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 
 	parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
 
-	if (tb[MDBA_MDB] && print_mdb_entries) {
-		int rem = RTA_PAYLOAD(tb[MDBA_MDB]);
+	if (n->nlmsg_type == RTM_DELMDB)
+		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
-		for (i = RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
-			br_print_mdb_entry(fp, r->ifindex, i, n);
-	}
+	if (tb[MDBA_MDB])
+		print_mdb_entries(fp, n, r->ifindex, tb[MDBA_MDB]);
 
-	if (tb[MDBA_ROUTER] && print_mdb_router) {
-		if (n->nlmsg_type == RTM_GETMDB) {
-			if (show_details)
-				br_print_router_ports(fp, tb[MDBA_ROUTER],
-						      r->ifindex);
-		} else {
-			uint32_t *port_ifindex;
-
-			i = RTA_DATA(tb[MDBA_ROUTER]);
-			port_ifindex = RTA_DATA(i);
-			if (n->nlmsg_type == RTM_DELMDB) {
-				if (jw_global)
-					jsonw_string_field(jw_global,
-							   "opCode",
-							   "deleted");
-				else
-					fprintf(fp, "Deleted ");
-			}
-			if (jw_global) {
-				jsonw_name(jw_global,
-					   ll_index_to_name(r->ifindex));
-				jsonw_start_array(jw_global);
-				jsonw_start_object(jw_global);
-				jsonw_string_field(jw_global, "port",
-					ll_index_to_name(*port_ifindex));
-				jsonw_end_object(jw_global);
-				jsonw_end_array(jw_global);
-			} else {
-				fprintf(fp, "router port dev %s master %s\n",
-					ll_index_to_name(*port_ifindex),
-					ll_index_to_name(r->ifindex));
-			}
-		}
-	}
-
-	if (!jw_global)
-		fflush(fp);
+	if (tb[MDBA_ROUTER])
+		print_router_entries(fp, n, r->ifindex, tb[MDBA_ROUTER]);
 
 	return 0;
 }
@@ -319,62 +294,21 @@ static int mdb_show(int argc, char **argv)
 		}
 	}
 
+	new_json_obj(json);
+
 	/* get mdb entries*/
 	if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
 		perror("Cannot send dump request");
 		return -1;
 	}
 
-	if (!json) {
-		/* Normal output */
-		if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
-			fprintf(stderr, "Dump terminated\n");
-			return -1;
-		}
-		return 0;
-	}
-
-	/* Json output */
-	jw_global = jsonw_new(stdout);
-	if (!jw_global) {
-		fprintf(stderr, "Error allocation json object\n");
-		exit(1);
-	}
-
-	if (pretty)
-		jsonw_pretty(jw_global, 1);
-
-	jsonw_start_object(jw_global);
-	jsonw_name(jw_global, "mdb");
-	jsonw_start_array(jw_global);
-
-	/* print mdb entries */
-	print_mdb_entries = true;
-	print_mdb_router = false;
 	if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
 		fprintf(stderr, "Dump terminated\n");
 		return -1;
 	}
-	jsonw_end_array(jw_global);
-
-	/* get router ports */
-	if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
-		perror("Cannot send dump request");
-		return -1;
-	}
-	jsonw_name(jw_global, "router");
-	jsonw_start_object(jw_global);
 
-	/* print router ports */
-	print_mdb_entries = false;
-	print_mdb_router = true;
-	if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
-		fprintf(stderr, "Dump terminated\n");
-		return -1;
-	}
-	jsonw_end_object(jw_global);
-	jsonw_end_object(jw_global);
-	jsonw_destroy(&jw_global);
+	delete_json_obj();
+	fflush(stdout);
 
 	return 0;
 }
diff --git a/bridge/vlan.c b/bridge/vlan.c
index 7c8b3ad54857..9f4a7a2be55c 100644
--- a/bridge/vlan.c
+++ b/bridge/vlan.c
@@ -8,19 +8,16 @@
 #include <netinet/in.h>
 #include <linux/if_bridge.h>
 #include <linux/if_ether.h>
-#include <json_writer.h>
 #include <string.h>
 
+#include "json_print.h"
 #include "libnetlink.h"
 #include "br_common.h"
 #include "utils.h"
 
 static unsigned int filter_index, filter_vlan;
-static int last_ifidx = -1;
 static int show_vlan_tunnel_info = 0;
 
-json_writer_t *jw_global;
-
 static void usage(void)
 {
 	fprintf(stderr,
@@ -257,38 +254,33 @@ static int filter_vlan_check(__u16 vid, __u16 flags)
 
 static void print_vlan_port(FILE *fp, int ifi_index)
 {
-	if (jw_global) {
-		jsonw_name(jw_global,
-			   ll_index_to_name(ifi_index));
-		jsonw_start_array(jw_global);
-	} else {
-		fprintf(fp, "%s",
-			ll_index_to_name(ifi_index));
-	}
+	print_string(PRINT_ANY, NULL, "%s",
+		     ll_index_to_name(ifi_index));
 }
 
-static void start_json_vlan_flags_array(bool *vlan_flags)
+static void print_range(const char *name, __u16 start, __u16 id)
 {
-	if (*vlan_flags)
-		return;
-	jsonw_name(jw_global, "flags");
-	jsonw_start_array(jw_global);
-	*vlan_flags = true;
+	char end[64];
+
+	snprintf(end, sizeof(end), "%sEnd", name);
+
+	print_hu(PRINT_ANY, name, "\t %hu", start);
+	if (start != id)
+		print_hu(PRINT_ANY, end, "-%hu", id);
+
 }
 
 static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex)
 {
-	bool jsonw_end_parray = false;
 	struct rtattr *i, *list = tb;
 	int rem = RTA_PAYLOAD(list);
 	__u16 last_vid_start = 0;
 	__u32 last_tunid_start = 0;
 
-	if (!filter_vlan) {
+	if (!filter_vlan)
 		print_vlan_port(fp, ifindex);
-		jsonw_end_parray = 1;
-	}
 
+	open_json_array(PRINT_JSON, "tunnel");
 	for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
 		struct rtattr *ttb[IFLA_BRIDGE_VLAN_TUNNEL_MAX+1];
 		__u32 tunnel_id = 0;
@@ -320,6 +312,7 @@ static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex)
 			last_vid_start = tunnel_vid;
 			last_tunid_start = tunnel_id;
 		}
+
 		vcheck_ret = filter_vlan_check(tunnel_vid, tunnel_flags);
 		if (vcheck_ret == -1)
 			break;
@@ -329,52 +322,19 @@ static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex)
 		if (tunnel_flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
 			continue;
 
-		if (filter_vlan) {
+		if (filter_vlan)
 			print_vlan_port(fp, ifindex);
-			jsonw_end_parray = 1;
-		}
 
-		if (jw_global) {
-			jsonw_start_object(jw_global);
-			jsonw_uint_field(jw_global, "vlan",
-					 last_vid_start);
-		} else {
-			fprintf(fp, "\t %hu", last_vid_start);
-		}
-		if (last_vid_start != tunnel_vid) {
-			if (jw_global)
-				jsonw_uint_field(jw_global, "vlanEnd",
-						 tunnel_vid);
-			else
-				fprintf(fp, "-%hu", tunnel_vid);
-		}
+		open_json_object(NULL);
+		print_range("vlan", last_vid_start, tunnel_vid);
+		print_range("tunid", last_tunid_start, tunnel_id);
+		close_json_object();
 
-		if (jw_global) {
-			jsonw_uint_field(jw_global, "tunid",
-					 last_tunid_start);
-		} else {
-			fprintf(fp, "\t %hu", last_tunid_start);
-		}
-		if (last_vid_start != tunnel_vid) {
-			if (jw_global)
-				jsonw_uint_field(jw_global, "tunidEnd",
-						 tunnel_id);
-			else
-				fprintf(fp, "-%hu", tunnel_id);
-		}
-
-		if (jw_global)
-			jsonw_end_object(jw_global);
-		else
+		if (!is_json_context())
 			fprintf(fp, "\n");
-	}
 
-	if (jsonw_end_parray) {
-		if (jw_global)
-			jsonw_end_array(jw_global);
-		else
-			fprintf(fp, "\n");
 	}
+	close_json_array(PRINT_JSON, NULL);
 }
 
 static int print_vlan_tunnel(const struct sockaddr_nl *who,
@@ -408,9 +368,11 @@ static int print_vlan_tunnel(const struct sockaddr_nl *who,
 
 	/* if AF_SPEC isn't there, vlan table is not preset for this port */
 	if (!tb[IFLA_AF_SPEC]) {
-		if (!filter_vlan && !jw_global)
-			fprintf(fp, "%s\tNone\n",
-				ll_index_to_name(ifm->ifi_index));
+		if (!filter_vlan && !is_json_context()) {
+			color_fprintf(fp, COLOR_IFNAME, "%s",
+				      ll_index_to_name(ifm->ifi_index));
+			fprintf(fp, "\tNone\n");
+		}
 		return 0;
 	}
 
@@ -451,48 +413,51 @@ static int print_vlan(const struct sockaddr_nl *who,
 
 	/* if AF_SPEC isn't there, vlan table is not preset for this port */
 	if (!tb[IFLA_AF_SPEC]) {
-		if (!filter_vlan && !jw_global)
-			fprintf(fp, "%s\tNone\n",
-				ll_index_to_name(ifm->ifi_index));
+		if (!filter_vlan && !is_json_context()) {
+			color_fprintf(fp, COLOR_IFNAME, "%s",
+				      ll_index_to_name(ifm->ifi_index));
+			fprintf(fp, "\tNone\n");
+		}
 		return 0;
 	}
 
-	print_vlan_info(fp, tb[IFLA_AF_SPEC], ifm->ifi_index);
+	print_vlan_port(fp, ifm->ifi_index);
+	print_vlan_info(fp, tb[IFLA_AF_SPEC]);
 
 	fflush(fp);
 	return 0;
 }
 
-static void print_one_vlan_stats(FILE *fp,
-				 const struct bridge_vlan_xstats *vstats,
-				 int ifindex)
+static void print_vlan_flags(__u16 flags)
 {
-	const char *ifname = "";
+	if (flags & BRIDGE_VLAN_INFO_PVID)
+		print_null(PRINT_ANY, "pvid", " %s", "PVID");
 
-	if (filter_vlan && filter_vlan != vstats->vid)
-		return;
-	/* skip pure port entries, they'll be dumped via the slave stats call */
-	if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) &&
-	    !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY))
-		return;
+	if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
+		print_null(PRINT_ANY, "untagged", " %s", "untagged");
+}
 
-	if (last_ifidx != ifindex) {
-		ifname = ll_index_to_name(ifindex);
-		last_ifidx = ifindex;
-	}
-	fprintf(fp, "%-16s  %hu", ifname, vstats->vid);
-	if (vstats->flags & BRIDGE_VLAN_INFO_PVID)
-		fprintf(fp, " PVID");
-	if (vstats->flags & BRIDGE_VLAN_INFO_UNTAGGED)
-		fprintf(fp, " Egress Untagged");
-	fprintf(fp, "\n");
-	fprintf(fp, "%-16s    RX: %llu bytes %llu packets\n",
-		"", vstats->rx_bytes, vstats->rx_packets);
-	fprintf(fp, "%-16s    TX: %llu bytes %llu packets\n",
-		"", vstats->tx_bytes, vstats->tx_packets);
+static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
+{
+	open_json_object(NULL);
+	print_hu(PRINT_ANY, "vid", " %hu", vstats->vid);
+
+	print_vlan_flags(vstats->flags);
+
+	print_lluint(PRINT_ANY, "rx_bytes",
+		     "\n                   RX: %llu bytes",
+		     vstats->rx_bytes);
+	print_lluint(PRINT_ANY, "rx_packets", " %llu packets\n",
+		vstats->rx_packets);
+	print_lluint(PRINT_ANY, "tx_bytes",
+		     "                   TX: %llu bytes",
+		     vstats->tx_bytes);
+	print_lluint(PRINT_ANY, "tx_packets", " %llu packets",
+		vstats->tx_packets);
+	close_json_object();
 }
 
-static void print_vlan_stats_attr(FILE *fp, struct rtattr *attr, int ifindex)
+static void print_vlan_stats_attr(struct rtattr *attr, int ifindex)
 {
 	struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
 	struct rtattr *i, *list;
@@ -505,11 +470,33 @@ static void print_vlan_stats_attr(FILE *fp, struct rtattr *attr, int ifindex)
 
 	list = brtb[LINK_XSTATS_TYPE_BRIDGE];
 	rem = RTA_PAYLOAD(list);
+
+	open_json_object(NULL);
+
+	print_color_string(PRINT_ANY, COLOR_IFNAME,
+			   "dev", "%-16s",
+			   ll_index_to_name(ifindex));
+
+	open_json_array(PRINT_JSON, "xstats");
 	for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+		const struct bridge_vlan_xstats *vstats = RTA_DATA(i);
+
 		if (i->rta_type != BRIDGE_XSTATS_VLAN)
 			continue;
-		print_one_vlan_stats(fp, RTA_DATA(i), ifindex);
+
+		if (filter_vlan && filter_vlan != vstats->vid)
+			continue;
+
+		/* skip pure port entries, they'll be dumped via the slave stats call */
+		if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) &&
+		    !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY))
+			continue;
+
+		print_one_vlan_stats(vstats);
 	}
+	close_json_array(PRINT_ANY, "\n");
+	close_json_object();
+
 }
 
 static int print_vlan_stats(const struct sockaddr_nl *who,
@@ -534,11 +521,11 @@ static int print_vlan_stats(const struct sockaddr_nl *who,
 
 	/* We have to check if any of the two attrs are usable */
 	if (tb[IFLA_STATS_LINK_XSTATS])
-		print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS],
+		print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS],
 				      ifsm->ifindex);
 
 	if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
-		print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS_SLAVE],
+		print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS_SLAVE],
 				      ifsm->ifindex);
 
 	fflush(fp);
@@ -574,6 +561,8 @@ static int vlan_show(int argc, char **argv)
 		}
 	}
 
+	new_json_obj(json);
+
 	if (!show_stats) {
 		if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
 					     (compress_vlans ?
@@ -583,17 +572,7 @@ static int vlan_show(int argc, char **argv)
 			exit(1);
 		}
 
-		if (json) {
-			jw_global = jsonw_new(stdout);
-			if (!jw_global) {
-				fprintf(stderr, "Error allocation json object\n");
-				exit(1);
-			}
-			if (pretty)
-				jsonw_pretty(jw_global, 1);
-
-			jsonw_start_object(jw_global);
-		} else {
+		if (!is_json_context()) {
 			if (show_vlan_tunnel_info)
 				printf("port\tvlan ids\ttunnel id\n");
 			else
@@ -605,7 +584,6 @@ static int vlan_show(int argc, char **argv)
 					       stdout);
 		else
 			ret = rtnl_dump_filter(&rth, print_vlan, stdout);
-
 		if (ret < 0) {
 			fprintf(stderr, "Dump ternminated\n");
 			exit(1);
@@ -621,7 +599,9 @@ static int vlan_show(int argc, char **argv)
 			exit(1);
 		}
 
-		printf("%-16s vlan id\n", "port");
+		if (!is_json_context())
+			printf("%-16s vlan id\n", "port");
+
 		if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
 			fprintf(stderr, "Dump terminated\n");
 			exit(1);
@@ -641,26 +621,21 @@ static int vlan_show(int argc, char **argv)
 		}
 	}
 
-	if (jw_global) {
-		jsonw_end_object(jw_global);
-		jsonw_destroy(&jw_global);
-	}
-
+	delete_json_obj();
+	fflush(stdout);
 	return 0;
 }
 
-void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex)
+void print_vlan_info(FILE *fp, struct rtattr *tb)
 {
 	struct rtattr *i, *list = tb;
 	int rem = RTA_PAYLOAD(list);
 	__u16 last_vid_start = 0;
-	bool vlan_flags = false;
-	bool jsonw_end_parray = false;
 
-	if (!filter_vlan) {
-		print_vlan_port(fp, ifindex);
-		jsonw_end_parray = true;
-	}
+	if (!is_json_context())
+		fprintf(fp, "%s", _SL_);
+
+	open_json_array(PRINT_JSON, "vlan");
 
 	for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
 		struct bridge_vlan_info *vinfo;
@@ -679,61 +654,14 @@ void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex)
 		else if (vcheck_ret == 0)
 			continue;
 
-		if (filter_vlan) {
-			print_vlan_port(fp, ifindex);
-			jsonw_end_parray = true;
-		}
-		if (jw_global) {
-			jsonw_start_object(jw_global);
-			jsonw_uint_field(jw_global, "vlan",
-					 last_vid_start);
-			if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
-				continue;
-		} else {
-			fprintf(fp, "\t %hu", last_vid_start);
-		}
-		if (last_vid_start != vinfo->vid) {
-			if (jw_global)
-				jsonw_uint_field(jw_global, "vlanEnd",
-						 vinfo->vid);
-			else
-				fprintf(fp, "-%hu", vinfo->vid);
-		}
-		if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) {
-			if (jw_global) {
-				start_json_vlan_flags_array(&vlan_flags);
-				jsonw_string(jw_global, "PVID");
-			} else {
-				fprintf(fp, " PVID");
-			}
-		}
-		if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) {
-			if (jw_global) {
-				start_json_vlan_flags_array(&vlan_flags);
-				jsonw_string(jw_global,
-					     "Egress Untagged");
-			} else {
-				fprintf(fp, " Egress Untagged");
-			}
-		}
-		if (jw_global && vlan_flags) {
-			jsonw_end_array(jw_global);
-			vlan_flags = false;
-		}
+		open_json_object(NULL);
+		print_range("vlan", last_vid_start, vinfo->vid);
 
-		if (jw_global)
-			jsonw_end_object(jw_global);
-		else
-			fprintf(fp, "\n");
+		print_vlan_flags(vinfo->flags);
+		close_json_object();
 	}
 
-	if (jsonw_end_parray) {
-		if (jw_global)
-			jsonw_end_array(jw_global);
-		else
-			fprintf(fp, "\n");
-
-	}
+	close_json_array(PRINT_ANY, "\n");
 }
 
 int do_vlan(int argc, char **argv)
-- 
2.16.1

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

* [PATCH v2 iproute2-next 3/5] bridge: add json support for link command
  2018-02-20 19:24 [PATCH v2 iproute2-next 0/5] bridge: json and color support Stephen Hemminger
  2018-02-20 19:24 ` [PATCH v2 iproute2-next 1/5] bridge: implement json pretty print flag Stephen Hemminger
  2018-02-20 19:24 ` [PATCH v2 iproute2-next 2/5] bridge: colorize output and use JSON print library Stephen Hemminger
@ 2018-02-20 19:24 ` Stephen Hemminger
  2018-02-20 19:24 ` [PATCH v2 iproute2-next 4/5] bridge: update man page for new color and json changes Stephen Hemminger
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Stephen Hemminger @ 2018-02-20 19:24 UTC (permalink / raw)
  To: netdev; +Cc: Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Add json output for bridge link show command and reuse code
from ip command to display interface information.

This also changes the output format slightly for the non JSON case so
that it has same format as the ip link show command.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 bridge/link.c | 245 +++++++++++++++++++++++++++++++---------------------------
 1 file changed, 132 insertions(+), 113 deletions(-)

diff --git a/bridge/link.c b/bridge/link.c
index 90c9734d9da1..e7ad5c61fa1e 100644
--- a/bridge/link.c
+++ b/bridge/link.c
@@ -12,6 +12,7 @@
 #include <string.h>
 #include <stdbool.h>
 
+#include "json_print.h"
 #include "libnetlink.h"
 #include "utils.h"
 #include "br_common.h"
@@ -26,15 +27,21 @@ static const char *port_states[] = {
 	[BR_STATE_BLOCKING] = "blocking",
 };
 
-static void print_link_flags(FILE *fp, unsigned int flags)
+static const char *hw_mode[] = {
+	"VEB", "VEPA"
+};
+
+static void print_link_flags(FILE *fp, unsigned int flags, unsigned int mdown)
 {
-	fprintf(fp, "<");
+	open_json_array(PRINT_ANY, is_json_context() ? "flags" : "<");
 	if (flags & IFF_UP && !(flags & IFF_RUNNING))
-		fprintf(fp, "NO-CARRIER%s", flags ? "," : "");
+		print_string(PRINT_ANY, NULL,
+			     flags ? "%s," : "%s", "NO-CARRIER");
 	flags &= ~IFF_RUNNING;
-#define _PF(f) if (flags&IFF_##f) { \
-		  flags &= ~IFF_##f ; \
-		  fprintf(fp, #f "%s", flags ? "," : ""); }
+
+#define _PF(f) if (flags&IFF_##f) {					\
+		flags &= ~IFF_##f ;					\
+		print_string(PRINT_ANY, NULL, flags ? "%s," : "%s", #f); }
 	_PF(LOOPBACK);
 	_PF(BROADCAST);
 	_PF(POINTOPOINT);
@@ -55,44 +62,119 @@ static void print_link_flags(FILE *fp, unsigned int flags)
 	_PF(ECHO);
 #undef _PF
 	if (flags)
-		fprintf(fp, "%x", flags);
-	fprintf(fp, "> ");
+		print_hex(PRINT_ANY, NULL, "%x", flags);
+	if (mdown)
+		print_string(PRINT_ANY, NULL, ",%s", "M-DOWN");
+	close_json_array(PRINT_ANY, "> ");
 }
 
-static const char *oper_states[] = {
-	"UNKNOWN", "NOTPRESENT", "DOWN", "LOWERLAYERDOWN",
-	"TESTING", "DORMANT",	 "UP"
-};
-
-static const char *hw_mode[] = {"VEB", "VEPA"};
+static void print_portstate(__u8 state)
+{
+	if (state <= BR_STATE_BLOCKING)
+		print_string(PRINT_ANY, "state",
+			     "state %s ", port_states[state]);
+	else
+		print_uint(PRINT_ANY, "state",
+			     "state (%d) ", state);
+}
 
-static void print_operstate(FILE *f, __u8 state)
+static void print_onoff(FILE *fp, const char *flag, __u8 val)
 {
-	if (state >= ARRAY_SIZE(oper_states))
-		fprintf(f, "state %#x ", state);
+	if (is_json_context())
+		print_bool(PRINT_JSON, flag, NULL, val);
 	else
-		fprintf(f, "state %s ", oper_states[state]);
+		fprintf(fp, "%s %s ", flag, val ? "on" : "off");
 }
 
-static void print_portstate(FILE *f, __u8 state)
+static void print_hwmode(__u16 mode)
 {
-	if (state <= BR_STATE_BLOCKING)
-		fprintf(f, "state %s ", port_states[state]);
+	if (mode >= ARRAY_SIZE(hw_mode))
+		print_0xhex(PRINT_ANY, "hwmode",
+			    "hwmode %#hx ", mode);
 	else
-		fprintf(f, "state (%d) ", state);
+		print_string(PRINT_ANY, "hwmode",
+			     "hwmode %s ", hw_mode[mode]);
 }
 
-static void print_onoff(FILE *f, char *flag, __u8 val)
+static void print_protinfo(FILE *fp, struct rtattr *attr)
 {
-	fprintf(f, "%s %s ", flag, val ? "on" : "off");
+	if (attr->rta_type & NLA_F_NESTED) {
+		struct rtattr *prtb[IFLA_BRPORT_MAX + 1];
+
+		parse_rtattr_nested(prtb, IFLA_BRPORT_MAX, attr);
+
+		if (prtb[IFLA_BRPORT_STATE])
+			print_portstate(rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
+
+		if (prtb[IFLA_BRPORT_PRIORITY])
+			print_uint(PRINT_ANY, "priority",
+				   "priority %u ",
+				   rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY]));
+
+		if (prtb[IFLA_BRPORT_COST])
+			print_uint(PRINT_ANY, "cost",
+				   "cost %u ",
+				   rta_getattr_u32(prtb[IFLA_BRPORT_COST]));
+
+		if (!show_details)
+			return;
+
+		if (!is_json_context())
+			fprintf(fp, "%s    ", _SL_);
+
+		if (prtb[IFLA_BRPORT_MODE])
+			print_onoff(fp, "hairpin",
+				    rta_getattr_u8(prtb[IFLA_BRPORT_MODE]));
+		if (prtb[IFLA_BRPORT_GUARD])
+			print_onoff(fp, "guard",
+				    rta_getattr_u8(prtb[IFLA_BRPORT_GUARD]));
+		if (prtb[IFLA_BRPORT_PROTECT])
+			print_onoff(fp, "root_block",
+				    rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT]));
+		if (prtb[IFLA_BRPORT_FAST_LEAVE])
+			print_onoff(fp, "fastleave",
+				    rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE]));
+		if (prtb[IFLA_BRPORT_LEARNING])
+			print_onoff(fp, "learning",
+				    rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING]));
+		if (prtb[IFLA_BRPORT_LEARNING_SYNC])
+			print_onoff(fp, "learning_sync",
+				    rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC]));
+		if (prtb[IFLA_BRPORT_UNICAST_FLOOD])
+			print_onoff(fp, "flood",
+				    rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD]));
+		if (prtb[IFLA_BRPORT_MCAST_FLOOD])
+			print_onoff(fp, "mcast_flood",
+				    rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_FLOOD]));
+		if (prtb[IFLA_BRPORT_NEIGH_SUPPRESS])
+			print_onoff(fp, "neigh_suppress",
+				    rta_getattr_u8(prtb[IFLA_BRPORT_NEIGH_SUPPRESS]));
+		if (prtb[IFLA_BRPORT_VLAN_TUNNEL])
+			print_onoff(fp, "vlan_tunnel",
+				    rta_getattr_u8(prtb[IFLA_BRPORT_VLAN_TUNNEL]));
+	} else
+		print_portstate(rta_getattr_u8(attr));
 }
 
-static void print_hwmode(FILE *f, __u16 mode)
+
+/*
+ * This is reported by HW devices that have some bridging
+ * capabilities.
+ */
+static void print_af_spec(FILE *fp, struct rtattr *attr)
 {
-	if (mode >= ARRAY_SIZE(hw_mode))
-		fprintf(f, "hwmode %#hx ", mode);
-	else
-		fprintf(f, "hwmode %s ", hw_mode[mode]);
+	struct rtattr *aftb[IFLA_BRIDGE_MAX+1];
+
+	parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, attr);
+
+	if (aftb[IFLA_BRIDGE_MODE])
+		print_hwmode(rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
+
+	if (!show_details)
+		return;
+
+	if (aftb[IFLA_BRIDGE_VLAN_INFO])
+		print_vlan_info(fp, aftb[IFLA_BRIDGE_VLAN_INFO]);
 }
 
 int print_linkinfo(const struct sockaddr_nl *who,
@@ -101,6 +183,7 @@ int print_linkinfo(const struct sockaddr_nl *who,
 	FILE *fp = arg;
 	struct ifinfomsg *ifi = NLMSG_DATA(n);
 	struct rtattr *tb[IFLA_MAX+1];
+	unsigned int m_flag = 0;
 	int len = n->nlmsg_len;
 	const char *name;
 
@@ -122,102 +205,34 @@ int print_linkinfo(const struct sockaddr_nl *who,
 	if (!name)
 		return -1;
 
+	open_json_object(NULL);
 	if (n->nlmsg_type == RTM_DELLINK)
-		fprintf(fp, "Deleted ");
-
-	fprintf(fp, "%d: ", ifi->ifi_index);
-
-	print_name_and_link("%s: ", COLOR_NONE, name, tb);
+		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
-	if (tb[IFLA_OPERSTATE])
-		print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
-
-	print_link_flags(fp, ifi->ifi_flags);
+	print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index);
+	m_flag = print_name_and_link("%s: ", COLOR_IFNAME, name, tb);
+	print_link_flags(fp, ifi->ifi_flags, m_flag);
 
 	if (tb[IFLA_MTU])
-		fprintf(fp, "mtu %u ", rta_getattr_u32(tb[IFLA_MTU]));
+		print_int(PRINT_ANY,
+			  "mtu", "mtu %u ",
+			  rta_getattr_u32(tb[IFLA_MTU]));
 
 	if (tb[IFLA_MASTER]) {
 		int master = rta_getattr_u32(tb[IFLA_MASTER]);
 
-		fprintf(fp, "master %s ", ll_index_to_name(master));
+		print_string(PRINT_ANY, "master", "master %s ",
+			     ll_index_to_name(master));
 	}
 
-	if (tb[IFLA_PROTINFO]) {
-		if (tb[IFLA_PROTINFO]->rta_type & NLA_F_NESTED) {
-			struct rtattr *prtb[IFLA_BRPORT_MAX+1];
-
-			parse_rtattr_nested(prtb, IFLA_BRPORT_MAX,
-					    tb[IFLA_PROTINFO]);
-
-			if (prtb[IFLA_BRPORT_STATE])
-				print_portstate(fp,
-						rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
-			if (prtb[IFLA_BRPORT_PRIORITY])
-				fprintf(fp, "priority %hu ",
-					rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY]));
-			if (prtb[IFLA_BRPORT_COST])
-				fprintf(fp, "cost %u ",
-					rta_getattr_u32(prtb[IFLA_BRPORT_COST]));
-
-			if (show_details) {
-				fprintf(fp, "%s    ", _SL_);
-
-				if (prtb[IFLA_BRPORT_MODE])
-					print_onoff(fp, "hairpin",
-						    rta_getattr_u8(prtb[IFLA_BRPORT_MODE]));
-				if (prtb[IFLA_BRPORT_GUARD])
-					print_onoff(fp, "guard",
-						    rta_getattr_u8(prtb[IFLA_BRPORT_GUARD]));
-				if (prtb[IFLA_BRPORT_PROTECT])
-					print_onoff(fp, "root_block",
-						    rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT]));
-				if (prtb[IFLA_BRPORT_FAST_LEAVE])
-					print_onoff(fp, "fastleave",
-						    rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE]));
-				if (prtb[IFLA_BRPORT_LEARNING])
-					print_onoff(fp, "learning",
-						    rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING]));
-				if (prtb[IFLA_BRPORT_LEARNING_SYNC])
-					print_onoff(fp, "learning_sync",
-						    rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC]));
-				if (prtb[IFLA_BRPORT_UNICAST_FLOOD])
-					print_onoff(fp, "flood",
-						    rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD]));
-				if (prtb[IFLA_BRPORT_MCAST_FLOOD])
-					print_onoff(fp, "mcast_flood",
-						    rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_FLOOD]));
-				if (prtb[IFLA_BRPORT_NEIGH_SUPPRESS])
-					print_onoff(fp, "neigh_suppress",
-						    rta_getattr_u8(prtb[IFLA_BRPORT_NEIGH_SUPPRESS]));
-				if (prtb[IFLA_BRPORT_VLAN_TUNNEL])
-					print_onoff(fp, "vlan_tunnel",
-						    rta_getattr_u8(prtb[IFLA_BRPORT_VLAN_TUNNEL]));
-			}
-		} else
-			print_portstate(fp, rta_getattr_u8(tb[IFLA_PROTINFO]));
-	}
+	if (tb[IFLA_PROTINFO])
+		print_protinfo(fp, tb[IFLA_PROTINFO]);
 
-	if (tb[IFLA_AF_SPEC]) {
-		/* This is reported by HW devices that have some bridging
-		 * capabilities.
-		 */
-		struct rtattr *aftb[IFLA_BRIDGE_MAX+1];
-
-		parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, tb[IFLA_AF_SPEC]);
-
-		if (aftb[IFLA_BRIDGE_MODE])
-			print_hwmode(fp, rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
-		if (show_details) {
-			if (aftb[IFLA_BRIDGE_VLAN_INFO]) {
-				fprintf(fp, "\n");
-				print_vlan_info(fp, tb[IFLA_AF_SPEC],
-						ifi->ifi_index);
-			}
-		}
-	}
+	if (tb[IFLA_AF_SPEC])
+		print_af_spec(fp, tb[IFLA_AF_SPEC]);
 
-	fprintf(fp, "\n");
+	print_string(PRINT_FP, NULL, "%s", "\n");
+	close_json_object();
 	fflush(fp);
 	return 0;
 }
@@ -492,10 +507,14 @@ static int brlink_show(int argc, char **argv)
 		}
 	}
 
+	new_json_obj(json);
 	if (rtnl_dump_filter(&rth, print_linkinfo, 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] 10+ messages in thread

* [PATCH v2 iproute2-next 4/5] bridge: update man page for new color and json changes
  2018-02-20 19:24 [PATCH v2 iproute2-next 0/5] bridge: json and color support Stephen Hemminger
                   ` (2 preceding siblings ...)
  2018-02-20 19:24 ` [PATCH v2 iproute2-next 3/5] bridge: add json support for link command Stephen Hemminger
@ 2018-02-20 19:24 ` Stephen Hemminger
  2018-02-20 19:24 ` [PATCH v2 iproute2-next 5/5] ip: always print interface name in color Stephen Hemminger
  2018-02-21 16:48 ` [PATCH v2 iproute2-next 0/5] bridge: json and color support David Ahern
  5 siblings, 0 replies; 10+ messages in thread
From: Stephen Hemminger @ 2018-02-20 19:24 UTC (permalink / raw)
  To: netdev; +Cc: Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Document color option, and no longer have restriction on json

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 man/man8/bridge.8 | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index 490ef58da16c..05512b029fb9 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -22,6 +22,7 @@ bridge \- show / manipulate bridge addresses and devices
 \fB\-s\fR[\fItatistics\fR] |
 \fB\-n\fR[\fIetns\fR] name |
 \fB\-b\fR[\fIatch\fR] filename |
+\fB\-c\fR[\folor\fR] |
 \fB\-p\fR[\fIretty\fR] |
 \fB\-j\fR[\fIson\fR] }
 
@@ -169,11 +170,15 @@ If there were any errors during execution of the commands, the application
 return code will be non zero.
 
 .TP
-.BR "\-json"
-Display results in JSON format. Currently available for vlan and fdb.
+.BR "\-c" , " -color"
+Use color output.
 
 .TP
-.BR "\-pretty"
+.BR "\-j", " \-json"
+Output results in JavaScript Object Notation (JSON).
+
+.TP
+.BR "\-p", " \-pretty"
 When combined with -j generate a pretty JSON output.
 
 
-- 
2.16.1

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

* [PATCH v2 iproute2-next 5/5] ip: always print interface name in color
  2018-02-20 19:24 [PATCH v2 iproute2-next 0/5] bridge: json and color support Stephen Hemminger
                   ` (3 preceding siblings ...)
  2018-02-20 19:24 ` [PATCH v2 iproute2-next 4/5] bridge: update man page for new color and json changes Stephen Hemminger
@ 2018-02-20 19:24 ` Stephen Hemminger
  2018-02-21 16:48 ` [PATCH v2 iproute2-next 0/5] bridge: json and color support David Ahern
  5 siblings, 0 replies; 10+ messages in thread
From: Stephen Hemminger @ 2018-02-20 19:24 UTC (permalink / raw)
  To: netdev; +Cc: Stephen Hemminger, Stephen Hemminger

From: Stephen Hemminger <sthemmin@microsoft.com>

Even in brief mode the interface name should be printed
in color if desired. This makes output consistent across
regular and brief mode.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 bridge/link.c   | 2 +-
 include/utils.h | 2 +-
 ip/ipaddress.c  | 4 ++--
 lib/utils.c     | 4 ++--
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/bridge/link.c b/bridge/link.c
index e7ad5c61fa1e..69c08ec77797 100644
--- a/bridge/link.c
+++ b/bridge/link.c
@@ -210,7 +210,7 @@ int print_linkinfo(const struct sockaddr_nl *who,
 		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
 	print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index);
-	m_flag = print_name_and_link("%s: ", COLOR_IFNAME, name, tb);
+	m_flag = print_name_and_link("%s: ", name, tb);
 	print_link_flags(fp, ifi->ifi_flags, m_flag);
 
 	if (tb[IFLA_MTU])
diff --git a/include/utils.h b/include/utils.h
index 75ddb4aec3fc..6bc77e74e51d 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -251,7 +251,7 @@ void print_escape_buf(const __u8 *buf, size_t len, const char *escape);
 int print_timestamp(FILE *fp);
 void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n);
 
-unsigned int print_name_and_link(const char *fmt, enum color_attr color,
+unsigned int print_name_and_link(const char *fmt,
 				 const char *name, struct rtattr *tb[]);
 
 #define BIT(nr)                 (1UL << (nr))
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 1380453984d5..9b3c1bc4555d 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -758,7 +758,7 @@ static int print_linkinfo_brief(FILE *fp, const char *name,
 {
 	unsigned int m_flag = 0;
 
-	m_flag = print_name_and_link("%-16s ", COLOR_NONE, name, tb);
+	m_flag = print_name_and_link("%-16s ", name, tb);
 
 	if (tb[IFLA_OPERSTATE])
 		print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
@@ -871,7 +871,7 @@ int print_linkinfo(const struct sockaddr_nl *who,
 
 	print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index);
 
-	m_flag = print_name_and_link("%s: ", COLOR_IFNAME, name, tb);
+	m_flag = print_name_and_link("%s: ", name, tb);
 	print_link_flags(fp, ifi->ifi_flags, m_flag);
 
 	if (tb[IFLA_MTU])
diff --git a/lib/utils.c b/lib/utils.c
index 61af123e9922..24aeddd8e2f1 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -1262,7 +1262,7 @@ int print_timestamp(FILE *fp)
 	return 0;
 }
 
-unsigned int print_name_and_link(const char *fmt, enum color_attr color,
+unsigned int print_name_and_link(const char *fmt,
 				 const char *name, struct rtattr *tb[])
 {
 	const char *link = NULL;
@@ -1305,7 +1305,7 @@ unsigned int print_name_and_link(const char *fmt, enum color_attr color,
 		}
 	}
 
-	print_color_string(PRINT_ANY, color, "ifname", fmt, name);
+	print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname", fmt, name);
 
 	return m_flag;
 }
-- 
2.16.1

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

* Re: [PATCH v2 iproute2-next 0/5] bridge: json and color support
  2018-02-20 19:24 [PATCH v2 iproute2-next 0/5] bridge: json and color support Stephen Hemminger
                   ` (4 preceding siblings ...)
  2018-02-20 19:24 ` [PATCH v2 iproute2-next 5/5] ip: always print interface name in color Stephen Hemminger
@ 2018-02-21 16:48 ` David Ahern
  5 siblings, 0 replies; 10+ messages in thread
From: David Ahern @ 2018-02-21 16:48 UTC (permalink / raw)
  To: Stephen Hemminger, netdev; +Cc: Stephen Hemminger

On 2/20/18 12:24 PM, Stephen Hemminger wrote:
> From: Stephen Hemminger <sthemmin@microsoft.com>
> 
> This set of patches adds color and full JSON support to bridge command.
> 
> The output format for bridge link command changes so that 
>   $ bridge link show
> and
>   $ ip link show
> use same basic format.
> 
> The "-c" flag to bridge changes from shortened form of "-compressvlan"
> to shortened form of "-color".  Once again this is so that ip
> and bridge command take similar options.
> 
> Lastly the JSON output format changes slightly but this
> could not impact any real user, because in several cases
> the current format was invalid JSON!
> 
> v2
>   rebase to updated iproute2-next
>   use common pretty flag
>   use common print_name_and_link
> 
> Stephen Hemminger (5):
>   bridge: implement json pretty print flag
>   bridge: colorize output and use JSON print library
>   bridge: add json support for link command
>   bridge: update man page for new color and json changes
>   ip: always print interface name in color
> 
>  bridge/br_common.h |   4 +-
>  bridge/bridge.c    |  16 ++-
>  bridge/fdb.c       | 279 ++++++++++++++++-------------------------
>  bridge/link.c      | 245 +++++++++++++++++++-----------------
>  bridge/mdb.c       | 354 ++++++++++++++++++++++-------------------------------
>  bridge/vlan.c      | 279 ++++++++++++++++-------------------------
>  include/utils.h    |   2 +-
>  ip/ipaddress.c     |   4 +-
>  lib/utils.c        |   4 +-
>  man/man8/bridge.8  |  15 ++-
>  10 files changed, 521 insertions(+), 681 deletions(-)
> 

series applied to iproute2-next.

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

* Re: [PATCH v2 iproute2-next 2/5] bridge: colorize output and use JSON print library
  2018-02-20 19:24 ` [PATCH v2 iproute2-next 2/5] bridge: colorize output and use JSON print library Stephen Hemminger
@ 2018-07-15  1:41   ` Roopa Prabhu
  2018-08-29  1:17     ` Roopa Prabhu
  2018-08-29 15:04     ` Stephen Hemminger
  0 siblings, 2 replies; 10+ messages in thread
From: Roopa Prabhu @ 2018-07-15  1:41 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, Stephen Hemminger, Julien Fortin, David Ahern

On Tue, Feb 20, 2018 at 11:24 AM, Stephen Hemminger
<stephen@networkplumber.org> wrote:
> From: Stephen Hemminger <sthemmin@microsoft.com>
>
> Use new functions from json_print to simplify code.
> Provide standard flag for colorizing output.
>
> The shortened -c flag is ambiguous it could mean color or
> compressvlan; it is now changed to mean color for consistency
> with other iproute2 commands.
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
>  bridge/br_common.h |   2 +-
>  bridge/bridge.c    |  10 +-
>  bridge/fdb.c       | 281 +++++++++++++++--------------------------
>  bridge/mdb.c       | 362 ++++++++++++++++++++++-------------------------------
>  bridge/vlan.c      | 276 +++++++++++++++-------------------------
>  5 files changed, 363 insertions(+), 568 deletions(-)
>
> diff --git a/bridge/br_common.h b/bridge/br_common.h
> index b25f61e50e05..2f1cb8fd9f3d 100644
> --- a/bridge/br_common.h
> +++ b/bridge/br_common.h
> @@ -6,7 +6,7 @@
>  #define MDB_RTR_RTA(r) \
>                 ((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(__u32))))
>
> -extern void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex);
> +extern void print_vlan_info(FILE *fp, struct rtattr *tb);
>  extern int print_linkinfo(const struct sockaddr_nl *who,
>                           struct nlmsghdr *n,
>                           void *arg);
> diff --git a/bridge/bridge.c b/bridge/bridge.c
> index 4b112e3b8da9..e5b4c3c2198f 100644
> --- a/bridge/bridge.c
> +++ b/bridge/bridge.c
> @@ -16,12 +16,15 @@
>  #include "utils.h"
>  #include "br_common.h"
>  #include "namespace.h"
> +#include "color.h"
>
>  struct rtnl_handle rth = { .fd = -1 };
>  int preferred_family = AF_UNSPEC;
>  int oneline;
>  int show_stats;
>  int show_details;
> +int show_pretty;
> +int color;
>  int compress_vlans;
>  int json;
>  int timestamp;
> @@ -39,7 +42,7 @@ static void usage(void)
>  "where OBJECT := { link | fdb | mdb | vlan | monitor }\n"
>  "      OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
>  "                   -o[neline] | -t[imestamp] | -n[etns] name |\n"
> -"                   -c[ompressvlans] -p[retty] -j{son} }\n");
> +"                   -c[ompressvlans] -color -p[retty] -j{son} }\n");
>         exit(-1);
>  }
>
> @@ -170,6 +173,8 @@ main(int argc, char **argv)
>                         NEXT_ARG();
>                         if (netns_switch(argv[1]))
>                                 exit(-1);
> +               } else if (matches(opt, "-color") == 0) {
> +                       enable_color();
>                 } else if (matches(opt, "-compressvlans") == 0) {
>                         ++compress_vlans;
>                 } else if (matches(opt, "-force") == 0) {
> @@ -195,6 +200,9 @@ main(int argc, char **argv)
>
>         _SL_ = oneline ? "\\" : "\n";
>
> +       if (json)
> +               check_if_color_enabled();
> +
>         if (batch_file)
>                 return batch(batch_file);
>
> diff --git a/bridge/fdb.c b/bridge/fdb.c
> index 93b5b2e694e3..b4f6e8b3a01b 100644
> --- a/bridge/fdb.c
> +++ b/bridge/fdb.c
> @@ -22,9 +22,9 @@
>  #include <linux/neighbour.h>
>  #include <string.h>
>  #include <limits.h>
> -#include <json_writer.h>
>  #include <stdbool.h>
>
> +#include "json_print.h"
>  #include "libnetlink.h"
>  #include "br_common.h"
>  #include "rt_names.h"
> @@ -32,8 +32,6 @@
>
>  static unsigned int filter_index, filter_vlan, filter_state;
>
> -json_writer_t *jw_global;
> -
>  static void usage(void)
>  {
>         fprintf(stderr,
> @@ -83,13 +81,46 @@ static int state_a2n(unsigned int *s, const char *arg)
>         return 0;
>  }
>
> -static void start_json_fdb_flags_array(bool *fdb_flags)
> +static void fdb_print_flags(FILE *fp, unsigned int flags)
> +{
> +       open_json_array(PRINT_JSON,
> +                       is_json_context() ?  "flags" : "");
> +
> +       if (flags & NTF_SELF)
> +               print_string(PRINT_ANY, NULL, "%s ", "self");
> +
> +       if (flags & NTF_ROUTER)
> +               print_string(PRINT_ANY, NULL, "%s ", "router");
> +
> +       if (flags & NTF_EXT_LEARNED)
> +               print_string(PRINT_ANY, NULL, "%s ", "extern_learn");
> +
> +       if (flags & NTF_OFFLOADED)
> +               print_string(PRINT_ANY, NULL, "%s ", "offload");
> +
> +       if (flags & NTF_MASTER)
> +               print_string(PRINT_ANY, NULL, "%s ", "master");
> +
> +       close_json_array(PRINT_JSON, NULL);
> +}
> +
> +static void fdb_print_stats(FILE *fp, const struct nda_cacheinfo *ci)
>  {
> -       if (*fdb_flags)
> -               return;
> -       jsonw_name(jw_global, "flags");
> -       jsonw_start_array(jw_global);
> -       *fdb_flags = true;
> +       static int hz;
> +
> +       if (!hz)
> +               hz = get_user_hz();
> +
> +       if (is_json_context()) {
> +               print_uint(PRINT_JSON, "used", NULL,
> +                                ci->ndm_used / hz);
> +               print_uint(PRINT_JSON, "updated", NULL,
> +                               ci->ndm_updated / hz);
> +       } else {
> +               fprintf(fp, "used %d/%d ", ci->ndm_used / hz,
> +                                       ci->ndm_updated / hz);
> +
> +       }
>  }
>
>  int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
> @@ -99,8 +130,6 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
>         int len = n->nlmsg_len;
>         struct rtattr *tb[NDA_MAX+1];
>         __u16 vid = 0;
> -       bool fdb_flags = false;
> -       const char *state_s;
>
>         if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) {
>                 fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
> @@ -132,189 +161,98 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
>         if (filter_vlan && filter_vlan != vid)
>                 return 0;
>
> -       if (jw_global)
> -               jsonw_start_object(jw_global);
> -
> -       if (n->nlmsg_type == RTM_DELNEIGH) {
> -               if (jw_global)
> -                       jsonw_string_field(jw_global, "opCode", "deleted");
> -               else
> -                       fprintf(fp, "Deleted ");
> -       }
> +       open_json_object(NULL);
> +       if (n->nlmsg_type == RTM_DELNEIGH)
> +               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
>
>         if (tb[NDA_LLADDR]) {
> +               const char *lladdr;
>                 SPRINT_BUF(b1);
> -               ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
> -                           RTA_PAYLOAD(tb[NDA_LLADDR]),
> -                           ll_index_to_type(r->ndm_ifindex),
> -                           b1, sizeof(b1));
> -               if (jw_global)
> -                       jsonw_string_field(jw_global, "mac", b1);
> -               else
> -                       fprintf(fp, "%s ", b1);
> +
> +               lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
> +                                    RTA_PAYLOAD(tb[NDA_LLADDR]),
> +                                    ll_index_to_type(r->ndm_ifindex),
> +                                    b1, sizeof(b1));
> +
> +               print_color_string(PRINT_ANY, COLOR_MAC,
> +                                  "mac", "%s ", lladdr);
>         }
>
>         if (!filter_index && r->ndm_ifindex) {
> -               if (jw_global)
> -                       jsonw_string_field(jw_global, "dev",
> -                                          ll_index_to_name(r->ndm_ifindex));
> -               else
> -                       fprintf(fp, "dev %s ",
> -                               ll_index_to_name(r->ndm_ifindex));
> +               if (!is_json_context())
> +                       fprintf(fp, "dev ");
> +               print_color_string(PRINT_ANY, COLOR_IFNAME,
> +                                  "ifname", "%s ",
> +                                  ll_index_to_name(r->ndm_ifindex));
>         }
>
>         if (tb[NDA_DST]) {
>                 int family = AF_INET;
> -               const char *abuf_s;
> +               const char *dst;
>
>                 if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
>                         family = AF_INET6;
>
> -               abuf_s = format_host(family,
> -                                    RTA_PAYLOAD(tb[NDA_DST]),
> -                                    RTA_DATA(tb[NDA_DST]));
> -               if (jw_global)
> -                       jsonw_string_field(jw_global, "dst", abuf_s);
> -               else
> -                       fprintf(fp, "dst %s ", abuf_s);
> -       }
> +               dst = format_host(family,
> +                                 RTA_PAYLOAD(tb[NDA_DST]),
> +                                 RTA_DATA(tb[NDA_DST]));
>
> -       if (vid) {
> -               if (jw_global)
> -                       jsonw_uint_field(jw_global, "vlan", vid);
> -               else
> -                       fprintf(fp, "vlan %hu ", vid);
> +               print_color_string(PRINT_ANY,
> +                                  ifa_family_color(family),
> +                                   "dst", "%s ", dst);
>         }
>
> -       if (tb[NDA_PORT]) {
> -               if (jw_global)
> -                       jsonw_uint_field(jw_global, "port",
> -                                        rta_getattr_be16(tb[NDA_PORT]));
> -               else
> -                       fprintf(fp, "port %d ",
> -                               rta_getattr_be16(tb[NDA_PORT]));
> -       }
> +       if (vid)
> +               print_uint(PRINT_ANY,
> +                                "vlan", "vlan %hu ", vid);
>
> -       if (tb[NDA_VNI]) {
> -               if (jw_global)
> -                       jsonw_uint_field(jw_global, "vni",
> -                                        rta_getattr_u32(tb[NDA_VNI]));
> -               else
> -                       fprintf(fp, "vni %d ",
> -                               rta_getattr_u32(tb[NDA_VNI]));
> -       }
> +       if (tb[NDA_PORT])
> +               print_uint(PRINT_ANY,
> +                                "port", "port %u ",
> +                                rta_getattr_be16(tb[NDA_PORT]));
>
> -       if (tb[NDA_SRC_VNI]) {
> -               if (jw_global)
> -                       jsonw_uint_field(jw_global, "src_vni",
> -                                        rta_getattr_u32(tb[NDA_SRC_VNI]));
> -               else
> -                       fprintf(fp, "src_vni %d ",
> +       if (tb[NDA_VNI])
> +               print_uint(PRINT_ANY,
> +                                "vni", "vni %u ",
> +                                rta_getattr_u32(tb[NDA_VNI]));
> +
> +       if (tb[NDA_SRC_VNI])
> +               print_uint(PRINT_ANY,
> +                                "src_vni", "src_vni %u ",
>                                 rta_getattr_u32(tb[NDA_SRC_VNI]));
> -       }
>
>         if (tb[NDA_IFINDEX]) {
>                 unsigned int ifindex = rta_getattr_u32(tb[NDA_IFINDEX]);
>
> -               if (ifindex) {
> -                       if (!tb[NDA_LINK_NETNSID]) {
> -                               const char *ifname = ll_index_to_name(ifindex);
> -
> -                               if (jw_global)
> -                                       jsonw_string_field(jw_global, "viaIf",
> -                                                          ifname);
> -                               else
> -                                       fprintf(fp, "via %s ", ifname);
> -                       } else {
> -                               if (jw_global)
> -                                       jsonw_uint_field(jw_global, "viaIfIndex",
> -                                                        ifindex);
> -                               else
> -                                       fprintf(fp, "via ifindex %u ", ifindex);
> -                       }
> -               }
> -       }
> -
> -       if (tb[NDA_LINK_NETNSID]) {
> -               if (jw_global)
> -                       jsonw_uint_field(jw_global, "linkNetNsId",
> -                                        rta_getattr_u32(tb[NDA_LINK_NETNSID]));
> +               if (tb[NDA_LINK_NETNSID])
> +                       print_uint(PRINT_ANY,
> +                                        "viaIfIndex", "via ifindex %u ",
> +                                        ifindex);
>                 else
> -                       fprintf(fp, "link-netnsid %d ",
> -                               rta_getattr_u32(tb[NDA_LINK_NETNSID]));
> +                       print_string(PRINT_ANY,
> +                                          "viaIf", "via %s ",
> +                                          ll_index_to_name(ifindex));
>         }
>
> -       if (show_stats && tb[NDA_CACHEINFO]) {
> -               struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
> -               int hz = get_user_hz();
> +       if (tb[NDA_LINK_NETNSID])
> +               print_uint(PRINT_ANY,
> +                                "linkNetNsId", "link-netnsid %d ",
> +                                rta_getattr_u32(tb[NDA_LINK_NETNSID]));
>
> -               if (jw_global) {
> -                       jsonw_uint_field(jw_global, "used",
> -                               ci->ndm_used/hz);
> -                       jsonw_uint_field(jw_global, "updated",
> -                               ci->ndm_updated/hz);
> -               } else {
> -                       fprintf(fp, "used %d/%d ", ci->ndm_used/hz,
> -                                       ci->ndm_updated/hz);
> -               }
> -       }
> +       if (show_stats && tb[NDA_CACHEINFO])
> +               fdb_print_stats(fp, RTA_DATA(tb[NDA_CACHEINFO]));
>
> -       if (jw_global) {
> -               if (r->ndm_flags & NTF_SELF) {
> -                       start_json_fdb_flags_array(&fdb_flags);
> -                       jsonw_string(jw_global, "self");
> -               }
> -               if (r->ndm_flags & NTF_ROUTER) {
> -                       start_json_fdb_flags_array(&fdb_flags);
> -                       jsonw_string(jw_global, "router");
> -               }
> -               if (r->ndm_flags & NTF_EXT_LEARNED) {
> -                       start_json_fdb_flags_array(&fdb_flags);
> -                       jsonw_string(jw_global, "extern_learn");
> -               }
> -               if (r->ndm_flags & NTF_OFFLOADED) {
> -                       start_json_fdb_flags_array(&fdb_flags);
> -                       jsonw_string(jw_global, "offload");
> -               }
> -               if (r->ndm_flags & NTF_MASTER)
> -                       jsonw_string(jw_global, "master");
> -               if (fdb_flags)
> -                       jsonw_end_array(jw_global);
> +       fdb_print_flags(fp, r->ndm_flags);
>
> -               if (tb[NDA_MASTER])
> -                       jsonw_string_field(jw_global,
> -                                          "master",
> -                                          ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
>
> -       } else {
> -               if (r->ndm_flags & NTF_SELF)
> -                       fprintf(fp, "self ");
> -               if (r->ndm_flags & NTF_ROUTER)
> -                       fprintf(fp, "router ");
> -               if (r->ndm_flags & NTF_EXT_LEARNED)
> -                       fprintf(fp, "extern_learn ");
> -               if (r->ndm_flags & NTF_OFFLOADED)
> -                       fprintf(fp, "offload ");
> -               if (tb[NDA_MASTER]) {
> -                       fprintf(fp, "master %s ",
> -                               ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
> -               } else if (r->ndm_flags & NTF_MASTER) {
> -                       fprintf(fp, "master ");
> -               }
> -       }
> -
> -       state_s = state_n2a(r->ndm_state);
> -       if (jw_global) {
> -               if (state_s[0])
> -                       jsonw_string_field(jw_global, "state", state_s);
> -
> -               jsonw_end_object(jw_global);
> -       } else {
> -               fprintf(fp, "%s\n", state_s);
> -
> -               fflush(fp);
> -       }
> +       if (tb[NDA_MASTER])
> +               print_string(PRINT_ANY, "master", "%s ",
> +                            ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
>
> +       print_string(PRINT_ANY, "state", "%s\n",
> +                          state_n2a(r->ndm_state));
> +       close_json_object();
> +       fflush(fp);
>         return 0;
>  }
>
> @@ -386,26 +324,13 @@ static int fdb_show(int argc, char **argv)
>                 exit(1);
>         }
>
> -       if (json) {
> -               jw_global = jsonw_new(stdout);
> -               if (!jw_global) {
> -                       fprintf(stderr, "Error allocation json object\n");
> -                       exit(1);
> -               }
> -               if (pretty)
> -                       jsonw_pretty(jw_global, 1);
> -
> -               jsonw_start_array(jw_global);
> -       }
> -
> +       new_json_obj(json);
>         if (rtnl_dump_filter(&rth, print_fdb, stdout) < 0) {
>                 fprintf(stderr, "Dump terminated\n");
>                 exit(1);
>         }
> -       if (jw_global) {
> -               jsonw_end_array(jw_global);
> -               jsonw_destroy(&jw_global);
> -       }
> +       delete_json_obj();
> +       fflush(stdout);
>
>         return 0;
>  }
> diff --git a/bridge/mdb.c b/bridge/mdb.c
> index da0282fdc91c..8c08baf570ec 100644
> --- a/bridge/mdb.c
> +++ b/bridge/mdb.c
> @@ -14,12 +14,12 @@
>  #include <linux/if_ether.h>
>  #include <string.h>
>  #include <arpa/inet.h>
> -#include <json_writer.h>
>
>  #include "libnetlink.h"
>  #include "br_common.h"
>  #include "rt_names.h"
>  #include "utils.h"
> +#include "json_print.h"
>
>  #ifndef MDBA_RTA
>  #define MDBA_RTA(r) \
> @@ -27,9 +27,6 @@
>  #endif
>
>  static unsigned int filter_index, filter_vlan;
> -json_writer_t *jw_global;
> -static bool print_mdb_entries = true;
> -static bool print_mdb_router = true;
>
>  static void usage(void)
>  {
> @@ -43,162 +40,131 @@ static bool is_temp_mcast_rtr(__u8 type)
>         return type == MDB_RTR_TYPE_TEMP_QUERY || type == MDB_RTR_TYPE_TEMP;
>  }
>
> +static const char *format_timer(__u32 ticks)
> +{
> +       struct timeval tv;
> +       static char tbuf[32];
> +
> +       __jiffies_to_tv(&tv, ticks);
> +       snprintf(tbuf, sizeof(tbuf), "%4lu.%.2lu",
> +                (unsigned long)tv.tv_sec,
> +                (unsigned long)tv.tv_usec / 10000);
> +
> +       return tbuf;
> +}
> +
>  static void __print_router_port_stats(FILE *f, struct rtattr *pattr)
>  {
>         struct rtattr *tb[MDBA_ROUTER_PATTR_MAX + 1];
> -       struct timeval tv;
> -       __u8 type;
>
>         parse_rtattr(tb, MDBA_ROUTER_PATTR_MAX, MDB_RTR_RTA(RTA_DATA(pattr)),
>                      RTA_PAYLOAD(pattr) - RTA_ALIGN(sizeof(uint32_t)));
> +
>         if (tb[MDBA_ROUTER_PATTR_TIMER]) {
> -               __jiffies_to_tv(&tv,
> -                               rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]));
> -               if (jw_global) {
> -                       char formatted_time[9];
> -
> -                       snprintf(formatted_time, sizeof(formatted_time),
> -                                "%4i.%.2i", (int)tv.tv_sec,
> -                                (int)tv.tv_usec/10000);
> -                       jsonw_string_field(jw_global, "timer", formatted_time);
> -               } else {
> -                       fprintf(f, " %4i.%.2i",
> -                               (int)tv.tv_sec, (int)tv.tv_usec/10000);
> -               }
> +               __u32 timer = rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]);
> +
> +               print_string(PRINT_ANY, "timer", " %s",
> +                            format_timer(timer));
>         }
> +
>         if (tb[MDBA_ROUTER_PATTR_TYPE]) {
> -               type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
> -               if (jw_global)
> -                       jsonw_string_field(jw_global, "type",
> -                               is_temp_mcast_rtr(type) ? "temp" : "permanent");
> -               else
> -                       fprintf(f, " %s",
> -                               is_temp_mcast_rtr(type) ? "temp" : "permanent");
> +               __u8 type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
> +
> +               print_string(PRINT_ANY, "type", " %s",
> +                            is_temp_mcast_rtr(type) ? "temp" : "permanent");
>         }
>  }
>
> -static void br_print_router_ports(FILE *f, struct rtattr *attr, __u32 brifidx)
> +static void br_print_router_ports(FILE *f, struct rtattr *attr,
> +                                 const char *brifname)
>  {
> -       uint32_t *port_ifindex;
> +       int rem = RTA_PAYLOAD(attr);
>         struct rtattr *i;
> -       int rem;
>
> -       rem = RTA_PAYLOAD(attr);
> -       if (jw_global) {
> -               jsonw_name(jw_global, ll_index_to_name(brifidx));
> -               jsonw_start_array(jw_global);
> -               for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
> -                       port_ifindex = RTA_DATA(i);
> -                       jsonw_start_object(jw_global);
> -                       jsonw_string_field(jw_global,
> -                                          "port",
> -                                          ll_index_to_name(*port_ifindex));
> +       if (is_json_context())
> +               open_json_array(PRINT_JSON, brifname);
> +       else if (!show_stats)
> +               fprintf(f, "router ports on %s: ", brifname);
> +
> +       for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
> +               uint32_t *port_ifindex = RTA_DATA(i);
> +               const char *port_ifname = ll_index_to_name(*port_ifindex);
> +
> +               if (is_json_context()) {
> +                       open_json_object(NULL);
> +                       print_string(PRINT_JSON, "port", NULL, port_ifname);
> +
>                         if (show_stats)
>                                 __print_router_port_stats(f, i);
> -                       jsonw_end_object(jw_global);
> -               }
> -               jsonw_end_array(jw_global);
> -       } else {
> -               if (!show_stats)
> -                       fprintf(f, "router ports on %s: ",
> -                               ll_index_to_name(brifidx));
> -               for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
> -                       port_ifindex = RTA_DATA(i);
> -                       if (show_stats) {
> -                               fprintf(f, "router ports on %s: %s",
> -                                       ll_index_to_name(brifidx),
> -                                       ll_index_to_name(*port_ifindex));
> -                               __print_router_port_stats(f, i);
> -                               fprintf(f, "\n");
> -                       } else{
> -                               fprintf(f, "%s ",
> -                                       ll_index_to_name(*port_ifindex));
> -                       }
> -               }
> -               if (!show_stats)
> +                       close_json_object();
> +               } else if (show_stats) {
> +                       fprintf(f, "router ports on %s: %s",
> +                               brifname, port_ifname);
> +
> +                       __print_router_port_stats(f, i);
>                         fprintf(f, "\n");
> +               } else {
> +                       fprintf(f, "%s ", port_ifname);
> +               }
>         }
> +       close_json_array(PRINT_JSON, NULL);
>  }
>
> -static void start_json_mdb_flags_array(bool *mdb_flags)
> -{
> -       if (*mdb_flags)
> -               return;
> -       jsonw_name(jw_global, "flags");
> -       jsonw_start_array(jw_global);
> -       *mdb_flags = true;
> -}
> -
> -static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e,
> +static void print_mdb_entry(FILE *f, int ifindex, const struct br_mdb_entry *e,
>                             struct nlmsghdr *n, struct rtattr **tb)
>  {
>         SPRINT_BUF(abuf);
> +       const char *dev;
>         const void *src;
>         int af;
> -       bool mdb_flags = false;
>
>         if (filter_vlan && e->vid != filter_vlan)
>                 return;
> +
>         af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6;
>         src = af == AF_INET ? (const void *)&e->addr.u.ip4 :
>                               (const void *)&e->addr.u.ip6;
> -       if (jw_global)
> -               jsonw_start_object(jw_global);
> -       if (n->nlmsg_type == RTM_DELMDB) {
> -               if (jw_global)
> -                       jsonw_string_field(jw_global, "opCode", "deleted");
> -               else
> -                       fprintf(f, "Deleted ");
> -       }
> -       if (jw_global) {
> -               jsonw_string_field(jw_global, "dev", ll_index_to_name(ifindex));
> -               jsonw_string_field(jw_global,
> -                                  "port",
> -                                  ll_index_to_name(e->ifindex));
> -               jsonw_string_field(jw_global, "grp", inet_ntop(af, src,
> -                       abuf, sizeof(abuf)));
> -               jsonw_string_field(jw_global, "state",
> -                       (e->state & MDB_PERMANENT) ? "permanent" : "temp");
> -               if (e->flags & MDB_FLAGS_OFFLOAD) {
> -                       start_json_mdb_flags_array(&mdb_flags);
> -                       jsonw_string(jw_global, "offload");
> -               }
> -               if (mdb_flags)
> -                       jsonw_end_array(jw_global);
> -       } else{
> -               fprintf(f, "dev %s port %s grp %s %s %s",
> -                       ll_index_to_name(ifindex),
> -                       ll_index_to_name(e->ifindex),
> -                       inet_ntop(af, src, abuf, sizeof(abuf)),
> -                       (e->state & MDB_PERMANENT) ? "permanent" : "temp",
> -                       (e->flags & MDB_FLAGS_OFFLOAD) ? "offload" : "");
> -       }
> -       if (e->vid) {
> -               if (jw_global)
> -                       jsonw_uint_field(jw_global, "vid", e->vid);
> -               else
> -                       fprintf(f, " vid %hu", e->vid);
> +       dev = ll_index_to_name(ifindex);
> +
> +       open_json_object(NULL);
> +
> +       if (n->nlmsg_type == RTM_DELMDB)
> +               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
> +
> +
> +       if (is_json_context()) {
> +               print_int(PRINT_JSON, "index", NULL, ifindex);
> +               print_string(PRINT_JSON, "dev", NULL, dev);
> +       } else {
> +               fprintf(f, "%u: ", ifindex);
> +               color_fprintf(f, COLOR_IFNAME, "%s ", dev);
>         }
> -       if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
> -               struct timeval tv;
>
> -               __jiffies_to_tv(&tv, rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]));
> -               if (jw_global) {
> -                       char formatted_time[9];
> +       print_string(PRINT_ANY, "port", " %s ",
> +                    ll_index_to_name(e->ifindex));
>
> -                       snprintf(formatted_time, sizeof(formatted_time),
> -                                "%4i.%.2i", (int)tv.tv_sec,
> -                                (int)tv.tv_usec/10000);
> -                       jsonw_string_field(jw_global, "timer", formatted_time);
> -               } else {
> -                       fprintf(f, "%4i.%.2i", (int)tv.tv_sec,
> -                               (int)tv.tv_usec/10000);
> -               }
> +       print_color_string(PRINT_ANY, ifa_family_color(af),
> +                           "grp", " %s ",
> +                           inet_ntop(af, src, abuf, sizeof(abuf)));
> +
> +       print_string(PRINT_ANY, "state", " %s ",
> +                          (e->state & MDB_PERMANENT) ? "permanent" : "temp");
> +
> +       open_json_array(PRINT_JSON, "flags");
> +       if (e->flags & MDB_FLAGS_OFFLOAD)
> +               print_string(PRINT_ANY, NULL, "%s ", "offload");
> +       close_json_array(PRINT_JSON, NULL);
> +
> +       if (e->vid)
> +               print_uint(PRINT_ANY, "vid", " vid %u", e->vid);
> +
> +       if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
> +               __u32 timer = rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]);
> +
> +               print_string(PRINT_ANY, "timer", " %s",
> +                            format_timer(timer));
>         }
> -       if (jw_global)
> -               jsonw_end_object(jw_global);
> -       else
> -               fprintf(f, "\n");
> +       close_json_object();
>  }
>
>  static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
> @@ -218,15 +184,60 @@ static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
>         }
>  }
>
> +static void print_mdb_entries(FILE *fp, struct nlmsghdr *n,
> +                             int ifindex,  struct rtattr *mdb)
> +{
> +       int rem = RTA_PAYLOAD(mdb);
> +       struct rtattr *i;
> +
> +       open_json_array(PRINT_JSON, "mdb");
> +       for (i = RTA_DATA(mdb); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
> +               br_print_mdb_entry(fp, ifindex, i, n);
> +       close_json_array(PRINT_JSON, NULL);
> +}
> +
> +static void print_router_entries(FILE *fp, struct nlmsghdr *n,
> +                                int ifindex, struct rtattr *router)
> +{
> +       const char *brifname = ll_index_to_name(ifindex);
> +
> +       open_json_array(PRINT_JSON, "router");
> +       if (n->nlmsg_type == RTM_GETMDB) {
> +               if (show_details)
> +                       br_print_router_ports(fp, router, brifname);
> +       } else {
> +               struct rtattr *i = RTA_DATA(router);
> +               uint32_t *port_ifindex = RTA_DATA(i);
> +
> +               if (is_json_context()) {
> +                       open_json_array(PRINT_JSON, brifname);
> +                       open_json_object(NULL);
> +
> +                       print_string(PRINT_JSON, "port", NULL,
> +                                    ll_index_to_name(*port_ifindex));
> +                       close_json_object();
> +                       close_json_array(PRINT_JSON, NULL);
> +               } else {
> +                       fprintf(fp, "router port dev %s master %s\n",
> +                               ll_index_to_name(*port_ifindex),
> +                               brifname);
> +               }
> +       }
> +       close_json_array(PRINT_JSON, NULL);
> +}
> +
>  int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
>  {
>         FILE *fp = arg;
>         struct br_port_msg *r = NLMSG_DATA(n);
>         int len = n->nlmsg_len;
> -       struct rtattr *tb[MDBA_MAX+1], *i;
> +       struct rtattr *tb[MDBA_MAX+1];
>
> -       if (n->nlmsg_type != RTM_GETMDB && n->nlmsg_type != RTM_NEWMDB && n->nlmsg_type != RTM_DELMDB) {
> -               fprintf(stderr, "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
> +       if (n->nlmsg_type != RTM_GETMDB &&
> +           n->nlmsg_type != RTM_NEWMDB &&
> +           n->nlmsg_type != RTM_DELMDB) {
> +               fprintf(stderr,
> +                       "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
>                         n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
>
>                 return 0;
> @@ -243,50 +254,14 @@ int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
>
>         parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
>
> -       if (tb[MDBA_MDB] && print_mdb_entries) {
> -               int rem = RTA_PAYLOAD(tb[MDBA_MDB]);
> +       if (n->nlmsg_type == RTM_DELMDB)
> +               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
>
> -               for (i = RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
> -                       br_print_mdb_entry(fp, r->ifindex, i, n);
> -       }
> +       if (tb[MDBA_MDB])
> +               print_mdb_entries(fp, n, r->ifindex, tb[MDBA_MDB]);
>
> -       if (tb[MDBA_ROUTER] && print_mdb_router) {
> -               if (n->nlmsg_type == RTM_GETMDB) {
> -                       if (show_details)
> -                               br_print_router_ports(fp, tb[MDBA_ROUTER],
> -                                                     r->ifindex);
> -               } else {
> -                       uint32_t *port_ifindex;
> -
> -                       i = RTA_DATA(tb[MDBA_ROUTER]);
> -                       port_ifindex = RTA_DATA(i);
> -                       if (n->nlmsg_type == RTM_DELMDB) {
> -                               if (jw_global)
> -                                       jsonw_string_field(jw_global,
> -                                                          "opCode",
> -                                                          "deleted");
> -                               else
> -                                       fprintf(fp, "Deleted ");
> -                       }
> -                       if (jw_global) {
> -                               jsonw_name(jw_global,
> -                                          ll_index_to_name(r->ifindex));
> -                               jsonw_start_array(jw_global);
> -                               jsonw_start_object(jw_global);
> -                               jsonw_string_field(jw_global, "port",
> -                                       ll_index_to_name(*port_ifindex));
> -                               jsonw_end_object(jw_global);
> -                               jsonw_end_array(jw_global);
> -                       } else {
> -                               fprintf(fp, "router port dev %s master %s\n",
> -                                       ll_index_to_name(*port_ifindex),
> -                                       ll_index_to_name(r->ifindex));
> -                       }
> -               }
> -       }
> -
> -       if (!jw_global)
> -               fflush(fp);
> +       if (tb[MDBA_ROUTER])
> +               print_router_entries(fp, n, r->ifindex, tb[MDBA_ROUTER]);
>
>         return 0;
>  }
> @@ -319,62 +294,21 @@ static int mdb_show(int argc, char **argv)
>                 }
>         }
>
> +       new_json_obj(json);
> +
>         /* get mdb entries*/
>         if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
>                 perror("Cannot send dump request");
>                 return -1;
>         }
>
> -       if (!json) {
> -               /* Normal output */
> -               if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
> -                       fprintf(stderr, "Dump terminated\n");
> -                       return -1;
> -               }
> -               return 0;
> -       }
> -
> -       /* Json output */
> -       jw_global = jsonw_new(stdout);
> -       if (!jw_global) {
> -               fprintf(stderr, "Error allocation json object\n");
> -               exit(1);
> -       }
> -
> -       if (pretty)
> -               jsonw_pretty(jw_global, 1);
> -
> -       jsonw_start_object(jw_global);
> -       jsonw_name(jw_global, "mdb");
> -       jsonw_start_array(jw_global);
> -
> -       /* print mdb entries */
> -       print_mdb_entries = true;
> -       print_mdb_router = false;
>         if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
>                 fprintf(stderr, "Dump terminated\n");
>                 return -1;
>         }
> -       jsonw_end_array(jw_global);
> -
> -       /* get router ports */
> -       if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
> -               perror("Cannot send dump request");
> -               return -1;
> -       }
> -       jsonw_name(jw_global, "router");
> -       jsonw_start_object(jw_global);
>
> -       /* print router ports */
> -       print_mdb_entries = false;
> -       print_mdb_router = true;
> -       if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
> -               fprintf(stderr, "Dump terminated\n");
> -               return -1;
> -       }
> -       jsonw_end_object(jw_global);
> -       jsonw_end_object(jw_global);
> -       jsonw_destroy(&jw_global);
> +       delete_json_obj();
> +       fflush(stdout);
>
>         return 0;
>  }
> diff --git a/bridge/vlan.c b/bridge/vlan.c
> index 7c8b3ad54857..9f4a7a2be55c 100644
> --- a/bridge/vlan.c
> +++ b/bridge/vlan.c
> @@ -8,19 +8,16 @@
>  #include <netinet/in.h>
>  #include <linux/if_bridge.h>
>  #include <linux/if_ether.h>
> -#include <json_writer.h>
>  #include <string.h>
>
> +#include "json_print.h"
>  #include "libnetlink.h"
>  #include "br_common.h"
>  #include "utils.h"
>
>  static unsigned int filter_index, filter_vlan;
> -static int last_ifidx = -1;
>  static int show_vlan_tunnel_info = 0;
>
> -json_writer_t *jw_global;
> -
>  static void usage(void)
>  {
>         fprintf(stderr,
> @@ -257,38 +254,33 @@ static int filter_vlan_check(__u16 vid, __u16 flags)
>
>  static void print_vlan_port(FILE *fp, int ifi_index)
>  {
> -       if (jw_global) {
> -               jsonw_name(jw_global,
> -                          ll_index_to_name(ifi_index));
> -               jsonw_start_array(jw_global);
> -       } else {
> -               fprintf(fp, "%s",
> -                       ll_index_to_name(ifi_index));
> -       }
> +       print_string(PRINT_ANY, NULL, "%s",
> +                    ll_index_to_name(ifi_index));
>  }
>

Stephen, this seems to have broken both json and non-json output.

Here is some output before and after the patch (same thing for tunnelshow):

before:
$bridge vlan show
port    vlan ids
hostbond4        1000
         1001 PVID Egress Untagged
         1002
         1003
         1004

hostbond3        1000 PVID Egress Untagged
         1001
         1002
         1003
         1004

bridge   1 PVID Egress Untagged
         1000
         1001
         1002
         1003
         1004

vxlan0   1 PVID Egress Untagged
         1000
         1001
         1002
         1003
         1004


$ bridge -j -c vlan show
{
    "hostbond4": [{
            "vlan": 1000
        },{
            "vlan": 1001,
            "flags": ["PVID","Egress Untagged"
            ]
        },{
            "vlan": 1002,
            "vlanEnd": 1004
        }
    ],
    "hostbond3": [{
            "vlan": 1000,
            "flags": ["PVID","Egress Untagged"
            ]
        },{
            "vlan": 1001,
            "vlanEnd": 1004
        }
    ],
    "bridge": [{
            "vlan": 1,
            "flags": ["PVID","Egress Untagged"
            ]
        },{
            "vlan": 1000,
            "vlanEnd": 1004
        }
    ],
        "vxlan0": [{
            "vlan": 1,
            "flags": ["PVID","Egress Untagged"
            ]
        },{
            "vlan": 1000,
            "vlanEnd": 1004
        }
    ]
}


after:
====

$bridge vlan show
port    vlan ids
hostbond4
         1000    1001 PVID untagged      1002    1003    1004
hostbond3
         1000 PVID untagged      1001    1002    1003    1004
bridge
         1 PVID untagged         1000    1001    1002    1003    1004
vxlan0
         1 PVID untagged         1000    1001    1002    1003    1004

$bridge -j -c vlan show
["hostbond4","vlan":[{"vlan":1000},{"vlan":1001,"pvid":null,"untagged":null},{"vlan":1002},{"vlan":1003},{"vlan":1004}],"hostbond3","vlan":[{"vlan":1000,"pvid":null,"untagged":null},{"vlan":1001},{"vlan":1002},{"vlan":1003},{"vlan":1004}],"bridge","vlan":[{"vlan":1,"pvid":null,"untagged":null},{"vlan":1000},{"vlan":1001},{"vlan":1002},{"vlan":1003},{"vlan":1004}],"vxlan0","vlan":[{"vlan":1,"pvid":null,"untagged":null},{"vlan":1000},{"vlan":1001},{"vlan":1002},{"vlan":1003},{"vlan":1004}]]

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

* Re: [PATCH v2 iproute2-next 2/5] bridge: colorize output and use JSON print library
  2018-07-15  1:41   ` Roopa Prabhu
@ 2018-08-29  1:17     ` Roopa Prabhu
  2018-08-29 15:04     ` Stephen Hemminger
  1 sibling, 0 replies; 10+ messages in thread
From: Roopa Prabhu @ 2018-08-29  1:17 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, Stephen Hemminger, Julien Fortin, David Ahern

On Sat, Jul 14, 2018 at 6:41 PM, Roopa Prabhu <roopa@cumulusnetworks.com> wrote:
> On Tue, Feb 20, 2018 at 11:24 AM, Stephen Hemminger
> <stephen@networkplumber.org> wrote:
>> From: Stephen Hemminger <sthemmin@microsoft.com>
>>
>> Use new functions from json_print to simplify code.
>> Provide standard flag for colorizing output.
>>
>> The shortened -c flag is ambiguous it could mean color or
>> compressvlan; it is now changed to mean color for consistency
>> with other iproute2 commands.
>>
>> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
>> ---

[snip]

>
> Stephen, this seems to have broken both json and non-json output.
>
> Here is some output before and after the patch (same thing for tunnelshow):
>
> before:
> $bridge vlan show
> port    vlan ids
> hostbond4        1000
>          1001 PVID Egress Untagged
>          1002
>          1003
>          1004
>
> hostbond3        1000 PVID Egress Untagged
>          1001
>          1002
>          1003
>          1004
>
> bridge   1 PVID Egress Untagged
>          1000
>          1001
>          1002
>          1003
>          1004
>
> vxlan0   1 PVID Egress Untagged
>          1000
>          1001
>          1002
>          1003
>          1004
>
>
> $ bridge -j -c vlan show
> {
>     "hostbond4": [{
>             "vlan": 1000
>         },{
>             "vlan": 1001,
>             "flags": ["PVID","Egress Untagged"
>             ]
>         },{
>             "vlan": 1002,
>             "vlanEnd": 1004
>         }
>     ],
>     "hostbond3": [{
>             "vlan": 1000,
>             "flags": ["PVID","Egress Untagged"
>             ]
>         },{
>             "vlan": 1001,
>             "vlanEnd": 1004
>         }
>     ],
>     "bridge": [{
>             "vlan": 1,
>             "flags": ["PVID","Egress Untagged"
>             ]
>         },{
>             "vlan": 1000,
>             "vlanEnd": 1004
>         }
>     ],
>         "vxlan0": [{
>             "vlan": 1,
>             "flags": ["PVID","Egress Untagged"
>             ]
>         },{
>             "vlan": 1000,
>             "vlanEnd": 1004
>         }
>     ]
> }
>
>
> after:
> ====
>
> $bridge vlan show
> port    vlan ids
> hostbond4
>          1000    1001 PVID untagged      1002    1003    1004
> hostbond3
>          1000 PVID untagged      1001    1002    1003    1004
> bridge
>          1 PVID untagged         1000    1001    1002    1003    1004
> vxlan0
>          1 PVID untagged         1000    1001    1002    1003    1004
>
> $bridge -j -c vlan show
> ["hostbond4","vlan":[{"vlan":1000},{"vlan":1001,"pvid":null,"untagged":null},{"vlan":1002},{"vlan":1003},{"vlan":1004}],"hostbond3","vlan":[{"vlan":1000,"pvid":null,"untagged":null},{"vlan":1001},{"vlan":1002},{"vlan":1003},{"vlan":1004}],"bridge","vlan":[{"vlan":1,"pvid":null,"untagged":null},{"vlan":1000},{"vlan":1001},{"vlan":1002},{"vlan":1003},{"vlan":1004}],"vxlan0","vlan":[{"vlan":1,"pvid":null,"untagged":null},{"vlan":1000},{"vlan":1001},{"vlan":1002},{"vlan":1003},{"vlan":1004}]]


Stephen, ping again...

I was trying to fix it ...but its not trivial enough for the time I
have right now.
If this cannot be fixed soon, I request you to please revert the patch
as it has broken the json output completely.

Thanks.

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

* Re: [PATCH v2 iproute2-next 2/5] bridge: colorize output and use JSON print library
  2018-07-15  1:41   ` Roopa Prabhu
  2018-08-29  1:17     ` Roopa Prabhu
@ 2018-08-29 15:04     ` Stephen Hemminger
  1 sibling, 0 replies; 10+ messages in thread
From: Stephen Hemminger @ 2018-08-29 15:04 UTC (permalink / raw)
  To: Roopa Prabhu; +Cc: netdev, Stephen Hemminger, Julien Fortin, David Ahern

On Sat, 14 Jul 2018 18:41:03 -0700
Roopa Prabhu <roopa@cumulusnetworks.com> wrote:

> On Tue, Feb 20, 2018 at 11:24 AM, Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> > From: Stephen Hemminger <sthemmin@microsoft.com>
> >
> > Use new functions from json_print to simplify code.
> > Provide standard flag for colorizing output.
> >
> > The shortened -c flag is ambiguous it could mean color or
> > compressvlan; it is now changed to mean color for consistency
> > with other iproute2 commands.
> >
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> > ---
> >  bridge/br_common.h |   2 +-
> >  bridge/bridge.c    |  10 +-
> >  bridge/fdb.c       | 281 +++++++++++++++--------------------------
> >  bridge/mdb.c       | 362 ++++++++++++++++++++++-------------------------------
> >  bridge/vlan.c      | 276 +++++++++++++++-------------------------
> >  5 files changed, 363 insertions(+), 568 deletions(-)
> >
> > diff --git a/bridge/br_common.h b/bridge/br_common.h
> > index b25f61e50e05..2f1cb8fd9f3d 100644
> > --- a/bridge/br_common.h
> > +++ b/bridge/br_common.h
> > @@ -6,7 +6,7 @@
> >  #define MDB_RTR_RTA(r) \
> >                 ((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(__u32))))
> >
> > -extern void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex);
> > +extern void print_vlan_info(FILE *fp, struct rtattr *tb);
> >  extern int print_linkinfo(const struct sockaddr_nl *who,
> >                           struct nlmsghdr *n,
> >                           void *arg);
> > diff --git a/bridge/bridge.c b/bridge/bridge.c
> > index 4b112e3b8da9..e5b4c3c2198f 100644
> > --- a/bridge/bridge.c
> > +++ b/bridge/bridge.c
> > @@ -16,12 +16,15 @@
> >  #include "utils.h"
> >  #include "br_common.h"
> >  #include "namespace.h"
> > +#include "color.h"
> >
> >  struct rtnl_handle rth = { .fd = -1 };
> >  int preferred_family = AF_UNSPEC;
> >  int oneline;
> >  int show_stats;
> >  int show_details;
> > +int show_pretty;
> > +int color;
> >  int compress_vlans;
> >  int json;
> >  int timestamp;
> > @@ -39,7 +42,7 @@ static void usage(void)
> >  "where OBJECT := { link | fdb | mdb | vlan | monitor }\n"
> >  "      OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
> >  "                   -o[neline] | -t[imestamp] | -n[etns] name |\n"
> > -"                   -c[ompressvlans] -p[retty] -j{son} }\n");
> > +"                   -c[ompressvlans] -color -p[retty] -j{son} }\n");
> >         exit(-1);
> >  }
> >
> > @@ -170,6 +173,8 @@ main(int argc, char **argv)
> >                         NEXT_ARG();
> >                         if (netns_switch(argv[1]))
> >                                 exit(-1);
> > +               } else if (matches(opt, "-color") == 0) {
> > +                       enable_color();
> >                 } else if (matches(opt, "-compressvlans") == 0) {
> >                         ++compress_vlans;
> >                 } else if (matches(opt, "-force") == 0) {
> > @@ -195,6 +200,9 @@ main(int argc, char **argv)
> >
> >         _SL_ = oneline ? "\\" : "\n";
> >
> > +       if (json)
> > +               check_if_color_enabled();
> > +
> >         if (batch_file)
> >                 return batch(batch_file);
> >
> > diff --git a/bridge/fdb.c b/bridge/fdb.c
> > index 93b5b2e694e3..b4f6e8b3a01b 100644
> > --- a/bridge/fdb.c
> > +++ b/bridge/fdb.c
> > @@ -22,9 +22,9 @@
> >  #include <linux/neighbour.h>
> >  #include <string.h>
> >  #include <limits.h>
> > -#include <json_writer.h>
> >  #include <stdbool.h>
> >
> > +#include "json_print.h"
> >  #include "libnetlink.h"
> >  #include "br_common.h"
> >  #include "rt_names.h"
> > @@ -32,8 +32,6 @@
> >
> >  static unsigned int filter_index, filter_vlan, filter_state;
> >
> > -json_writer_t *jw_global;
> > -
> >  static void usage(void)
> >  {
> >         fprintf(stderr,
> > @@ -83,13 +81,46 @@ static int state_a2n(unsigned int *s, const char *arg)
> >         return 0;
> >  }
> >
> > -static void start_json_fdb_flags_array(bool *fdb_flags)
> > +static void fdb_print_flags(FILE *fp, unsigned int flags)
> > +{
> > +       open_json_array(PRINT_JSON,
> > +                       is_json_context() ?  "flags" : "");
> > +
> > +       if (flags & NTF_SELF)
> > +               print_string(PRINT_ANY, NULL, "%s ", "self");
> > +
> > +       if (flags & NTF_ROUTER)
> > +               print_string(PRINT_ANY, NULL, "%s ", "router");
> > +
> > +       if (flags & NTF_EXT_LEARNED)
> > +               print_string(PRINT_ANY, NULL, "%s ", "extern_learn");
> > +
> > +       if (flags & NTF_OFFLOADED)
> > +               print_string(PRINT_ANY, NULL, "%s ", "offload");
> > +
> > +       if (flags & NTF_MASTER)
> > +               print_string(PRINT_ANY, NULL, "%s ", "master");
> > +
> > +       close_json_array(PRINT_JSON, NULL);
> > +}
> > +
> > +static void fdb_print_stats(FILE *fp, const struct nda_cacheinfo *ci)
> >  {
> > -       if (*fdb_flags)
> > -               return;
> > -       jsonw_name(jw_global, "flags");
> > -       jsonw_start_array(jw_global);
> > -       *fdb_flags = true;
> > +       static int hz;
> > +
> > +       if (!hz)
> > +               hz = get_user_hz();
> > +
> > +       if (is_json_context()) {
> > +               print_uint(PRINT_JSON, "used", NULL,
> > +                                ci->ndm_used / hz);
> > +               print_uint(PRINT_JSON, "updated", NULL,
> > +                               ci->ndm_updated / hz);
> > +       } else {
> > +               fprintf(fp, "used %d/%d ", ci->ndm_used / hz,
> > +                                       ci->ndm_updated / hz);
> > +
> > +       }
> >  }
> >
> >  int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
> > @@ -99,8 +130,6 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
> >         int len = n->nlmsg_len;
> >         struct rtattr *tb[NDA_MAX+1];
> >         __u16 vid = 0;
> > -       bool fdb_flags = false;
> > -       const char *state_s;
> >
> >         if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) {
> >                 fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
> > @@ -132,189 +161,98 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
> >         if (filter_vlan && filter_vlan != vid)
> >                 return 0;
> >
> > -       if (jw_global)
> > -               jsonw_start_object(jw_global);
> > -
> > -       if (n->nlmsg_type == RTM_DELNEIGH) {
> > -               if (jw_global)
> > -                       jsonw_string_field(jw_global, "opCode", "deleted");
> > -               else
> > -                       fprintf(fp, "Deleted ");
> > -       }
> > +       open_json_object(NULL);
> > +       if (n->nlmsg_type == RTM_DELNEIGH)
> > +               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
> >
> >         if (tb[NDA_LLADDR]) {
> > +               const char *lladdr;
> >                 SPRINT_BUF(b1);
> > -               ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
> > -                           RTA_PAYLOAD(tb[NDA_LLADDR]),
> > -                           ll_index_to_type(r->ndm_ifindex),
> > -                           b1, sizeof(b1));
> > -               if (jw_global)
> > -                       jsonw_string_field(jw_global, "mac", b1);
> > -               else
> > -                       fprintf(fp, "%s ", b1);
> > +
> > +               lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
> > +                                    RTA_PAYLOAD(tb[NDA_LLADDR]),
> > +                                    ll_index_to_type(r->ndm_ifindex),
> > +                                    b1, sizeof(b1));
> > +
> > +               print_color_string(PRINT_ANY, COLOR_MAC,
> > +                                  "mac", "%s ", lladdr);
> >         }
> >
> >         if (!filter_index && r->ndm_ifindex) {
> > -               if (jw_global)
> > -                       jsonw_string_field(jw_global, "dev",
> > -                                          ll_index_to_name(r->ndm_ifindex));
> > -               else
> > -                       fprintf(fp, "dev %s ",
> > -                               ll_index_to_name(r->ndm_ifindex));
> > +               if (!is_json_context())
> > +                       fprintf(fp, "dev ");
> > +               print_color_string(PRINT_ANY, COLOR_IFNAME,
> > +                                  "ifname", "%s ",
> > +                                  ll_index_to_name(r->ndm_ifindex));
> >         }
> >
> >         if (tb[NDA_DST]) {
> >                 int family = AF_INET;
> > -               const char *abuf_s;
> > +               const char *dst;
> >
> >                 if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
> >                         family = AF_INET6;
> >
> > -               abuf_s = format_host(family,
> > -                                    RTA_PAYLOAD(tb[NDA_DST]),
> > -                                    RTA_DATA(tb[NDA_DST]));
> > -               if (jw_global)
> > -                       jsonw_string_field(jw_global, "dst", abuf_s);
> > -               else
> > -                       fprintf(fp, "dst %s ", abuf_s);
> > -       }
> > +               dst = format_host(family,
> > +                                 RTA_PAYLOAD(tb[NDA_DST]),
> > +                                 RTA_DATA(tb[NDA_DST]));
> >
> > -       if (vid) {
> > -               if (jw_global)
> > -                       jsonw_uint_field(jw_global, "vlan", vid);
> > -               else
> > -                       fprintf(fp, "vlan %hu ", vid);
> > +               print_color_string(PRINT_ANY,
> > +                                  ifa_family_color(family),
> > +                                   "dst", "%s ", dst);
> >         }
> >
> > -       if (tb[NDA_PORT]) {
> > -               if (jw_global)
> > -                       jsonw_uint_field(jw_global, "port",
> > -                                        rta_getattr_be16(tb[NDA_PORT]));
> > -               else
> > -                       fprintf(fp, "port %d ",
> > -                               rta_getattr_be16(tb[NDA_PORT]));
> > -       }
> > +       if (vid)
> > +               print_uint(PRINT_ANY,
> > +                                "vlan", "vlan %hu ", vid);
> >
> > -       if (tb[NDA_VNI]) {
> > -               if (jw_global)
> > -                       jsonw_uint_field(jw_global, "vni",
> > -                                        rta_getattr_u32(tb[NDA_VNI]));
> > -               else
> > -                       fprintf(fp, "vni %d ",
> > -                               rta_getattr_u32(tb[NDA_VNI]));
> > -       }
> > +       if (tb[NDA_PORT])
> > +               print_uint(PRINT_ANY,
> > +                                "port", "port %u ",
> > +                                rta_getattr_be16(tb[NDA_PORT]));
> >
> > -       if (tb[NDA_SRC_VNI]) {
> > -               if (jw_global)
> > -                       jsonw_uint_field(jw_global, "src_vni",
> > -                                        rta_getattr_u32(tb[NDA_SRC_VNI]));
> > -               else
> > -                       fprintf(fp, "src_vni %d ",
> > +       if (tb[NDA_VNI])
> > +               print_uint(PRINT_ANY,
> > +                                "vni", "vni %u ",
> > +                                rta_getattr_u32(tb[NDA_VNI]));
> > +
> > +       if (tb[NDA_SRC_VNI])
> > +               print_uint(PRINT_ANY,
> > +                                "src_vni", "src_vni %u ",
> >                                 rta_getattr_u32(tb[NDA_SRC_VNI]));
> > -       }
> >
> >         if (tb[NDA_IFINDEX]) {
> >                 unsigned int ifindex = rta_getattr_u32(tb[NDA_IFINDEX]);
> >
> > -               if (ifindex) {
> > -                       if (!tb[NDA_LINK_NETNSID]) {
> > -                               const char *ifname = ll_index_to_name(ifindex);
> > -
> > -                               if (jw_global)
> > -                                       jsonw_string_field(jw_global, "viaIf",
> > -                                                          ifname);
> > -                               else
> > -                                       fprintf(fp, "via %s ", ifname);
> > -                       } else {
> > -                               if (jw_global)
> > -                                       jsonw_uint_field(jw_global, "viaIfIndex",
> > -                                                        ifindex);
> > -                               else
> > -                                       fprintf(fp, "via ifindex %u ", ifindex);
> > -                       }
> > -               }
> > -       }
> > -
> > -       if (tb[NDA_LINK_NETNSID]) {
> > -               if (jw_global)
> > -                       jsonw_uint_field(jw_global, "linkNetNsId",
> > -                                        rta_getattr_u32(tb[NDA_LINK_NETNSID]));
> > +               if (tb[NDA_LINK_NETNSID])
> > +                       print_uint(PRINT_ANY,
> > +                                        "viaIfIndex", "via ifindex %u ",
> > +                                        ifindex);
> >                 else
> > -                       fprintf(fp, "link-netnsid %d ",
> > -                               rta_getattr_u32(tb[NDA_LINK_NETNSID]));
> > +                       print_string(PRINT_ANY,
> > +                                          "viaIf", "via %s ",
> > +                                          ll_index_to_name(ifindex));
> >         }
> >
> > -       if (show_stats && tb[NDA_CACHEINFO]) {
> > -               struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
> > -               int hz = get_user_hz();
> > +       if (tb[NDA_LINK_NETNSID])
> > +               print_uint(PRINT_ANY,
> > +                                "linkNetNsId", "link-netnsid %d ",
> > +                                rta_getattr_u32(tb[NDA_LINK_NETNSID]));
> >
> > -               if (jw_global) {
> > -                       jsonw_uint_field(jw_global, "used",
> > -                               ci->ndm_used/hz);
> > -                       jsonw_uint_field(jw_global, "updated",
> > -                               ci->ndm_updated/hz);
> > -               } else {
> > -                       fprintf(fp, "used %d/%d ", ci->ndm_used/hz,
> > -                                       ci->ndm_updated/hz);
> > -               }
> > -       }
> > +       if (show_stats && tb[NDA_CACHEINFO])
> > +               fdb_print_stats(fp, RTA_DATA(tb[NDA_CACHEINFO]));
> >
> > -       if (jw_global) {
> > -               if (r->ndm_flags & NTF_SELF) {
> > -                       start_json_fdb_flags_array(&fdb_flags);
> > -                       jsonw_string(jw_global, "self");
> > -               }
> > -               if (r->ndm_flags & NTF_ROUTER) {
> > -                       start_json_fdb_flags_array(&fdb_flags);
> > -                       jsonw_string(jw_global, "router");
> > -               }
> > -               if (r->ndm_flags & NTF_EXT_LEARNED) {
> > -                       start_json_fdb_flags_array(&fdb_flags);
> > -                       jsonw_string(jw_global, "extern_learn");
> > -               }
> > -               if (r->ndm_flags & NTF_OFFLOADED) {
> > -                       start_json_fdb_flags_array(&fdb_flags);
> > -                       jsonw_string(jw_global, "offload");
> > -               }
> > -               if (r->ndm_flags & NTF_MASTER)
> > -                       jsonw_string(jw_global, "master");
> > -               if (fdb_flags)
> > -                       jsonw_end_array(jw_global);
> > +       fdb_print_flags(fp, r->ndm_flags);
> >
> > -               if (tb[NDA_MASTER])
> > -                       jsonw_string_field(jw_global,
> > -                                          "master",
> > -                                          ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
> >
> > -       } else {
> > -               if (r->ndm_flags & NTF_SELF)
> > -                       fprintf(fp, "self ");
> > -               if (r->ndm_flags & NTF_ROUTER)
> > -                       fprintf(fp, "router ");
> > -               if (r->ndm_flags & NTF_EXT_LEARNED)
> > -                       fprintf(fp, "extern_learn ");
> > -               if (r->ndm_flags & NTF_OFFLOADED)
> > -                       fprintf(fp, "offload ");
> > -               if (tb[NDA_MASTER]) {
> > -                       fprintf(fp, "master %s ",
> > -                               ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
> > -               } else if (r->ndm_flags & NTF_MASTER) {
> > -                       fprintf(fp, "master ");
> > -               }
> > -       }
> > -
> > -       state_s = state_n2a(r->ndm_state);
> > -       if (jw_global) {
> > -               if (state_s[0])
> > -                       jsonw_string_field(jw_global, "state", state_s);
> > -
> > -               jsonw_end_object(jw_global);
> > -       } else {
> > -               fprintf(fp, "%s\n", state_s);
> > -
> > -               fflush(fp);
> > -       }
> > +       if (tb[NDA_MASTER])
> > +               print_string(PRINT_ANY, "master", "%s ",
> > +                            ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
> >
> > +       print_string(PRINT_ANY, "state", "%s\n",
> > +                          state_n2a(r->ndm_state));
> > +       close_json_object();
> > +       fflush(fp);
> >         return 0;
> >  }
> >
> > @@ -386,26 +324,13 @@ static int fdb_show(int argc, char **argv)
> >                 exit(1);
> >         }
> >
> > -       if (json) {
> > -               jw_global = jsonw_new(stdout);
> > -               if (!jw_global) {
> > -                       fprintf(stderr, "Error allocation json object\n");
> > -                       exit(1);
> > -               }
> > -               if (pretty)
> > -                       jsonw_pretty(jw_global, 1);
> > -
> > -               jsonw_start_array(jw_global);
> > -       }
> > -
> > +       new_json_obj(json);
> >         if (rtnl_dump_filter(&rth, print_fdb, stdout) < 0) {
> >                 fprintf(stderr, "Dump terminated\n");
> >                 exit(1);
> >         }
> > -       if (jw_global) {
> > -               jsonw_end_array(jw_global);
> > -               jsonw_destroy(&jw_global);
> > -       }
> > +       delete_json_obj();
> > +       fflush(stdout);
> >
> >         return 0;
> >  }
> > diff --git a/bridge/mdb.c b/bridge/mdb.c
> > index da0282fdc91c..8c08baf570ec 100644
> > --- a/bridge/mdb.c
> > +++ b/bridge/mdb.c
> > @@ -14,12 +14,12 @@
> >  #include <linux/if_ether.h>
> >  #include <string.h>
> >  #include <arpa/inet.h>
> > -#include <json_writer.h>
> >
> >  #include "libnetlink.h"
> >  #include "br_common.h"
> >  #include "rt_names.h"
> >  #include "utils.h"
> > +#include "json_print.h"
> >
> >  #ifndef MDBA_RTA
> >  #define MDBA_RTA(r) \
> > @@ -27,9 +27,6 @@
> >  #endif
> >
> >  static unsigned int filter_index, filter_vlan;
> > -json_writer_t *jw_global;
> > -static bool print_mdb_entries = true;
> > -static bool print_mdb_router = true;
> >
> >  static void usage(void)
> >  {
> > @@ -43,162 +40,131 @@ static bool is_temp_mcast_rtr(__u8 type)
> >         return type == MDB_RTR_TYPE_TEMP_QUERY || type == MDB_RTR_TYPE_TEMP;
> >  }
> >
> > +static const char *format_timer(__u32 ticks)
> > +{
> > +       struct timeval tv;
> > +       static char tbuf[32];
> > +
> > +       __jiffies_to_tv(&tv, ticks);
> > +       snprintf(tbuf, sizeof(tbuf), "%4lu.%.2lu",
> > +                (unsigned long)tv.tv_sec,
> > +                (unsigned long)tv.tv_usec / 10000);
> > +
> > +       return tbuf;
> > +}
> > +
> >  static void __print_router_port_stats(FILE *f, struct rtattr *pattr)
> >  {
> >         struct rtattr *tb[MDBA_ROUTER_PATTR_MAX + 1];
> > -       struct timeval tv;
> > -       __u8 type;
> >
> >         parse_rtattr(tb, MDBA_ROUTER_PATTR_MAX, MDB_RTR_RTA(RTA_DATA(pattr)),
> >                      RTA_PAYLOAD(pattr) - RTA_ALIGN(sizeof(uint32_t)));
> > +
> >         if (tb[MDBA_ROUTER_PATTR_TIMER]) {
> > -               __jiffies_to_tv(&tv,
> > -                               rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]));
> > -               if (jw_global) {
> > -                       char formatted_time[9];
> > -
> > -                       snprintf(formatted_time, sizeof(formatted_time),
> > -                                "%4i.%.2i", (int)tv.tv_sec,
> > -                                (int)tv.tv_usec/10000);
> > -                       jsonw_string_field(jw_global, "timer", formatted_time);
> > -               } else {
> > -                       fprintf(f, " %4i.%.2i",
> > -                               (int)tv.tv_sec, (int)tv.tv_usec/10000);
> > -               }
> > +               __u32 timer = rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]);
> > +
> > +               print_string(PRINT_ANY, "timer", " %s",
> > +                            format_timer(timer));
> >         }
> > +
> >         if (tb[MDBA_ROUTER_PATTR_TYPE]) {
> > -               type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
> > -               if (jw_global)
> > -                       jsonw_string_field(jw_global, "type",
> > -                               is_temp_mcast_rtr(type) ? "temp" : "permanent");
> > -               else
> > -                       fprintf(f, " %s",
> > -                               is_temp_mcast_rtr(type) ? "temp" : "permanent");
> > +               __u8 type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
> > +
> > +               print_string(PRINT_ANY, "type", " %s",
> > +                            is_temp_mcast_rtr(type) ? "temp" : "permanent");
> >         }
> >  }
> >
> > -static void br_print_router_ports(FILE *f, struct rtattr *attr, __u32 brifidx)
> > +static void br_print_router_ports(FILE *f, struct rtattr *attr,
> > +                                 const char *brifname)
> >  {
> > -       uint32_t *port_ifindex;
> > +       int rem = RTA_PAYLOAD(attr);
> >         struct rtattr *i;
> > -       int rem;
> >
> > -       rem = RTA_PAYLOAD(attr);
> > -       if (jw_global) {
> > -               jsonw_name(jw_global, ll_index_to_name(brifidx));
> > -               jsonw_start_array(jw_global);
> > -               for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
> > -                       port_ifindex = RTA_DATA(i);
> > -                       jsonw_start_object(jw_global);
> > -                       jsonw_string_field(jw_global,
> > -                                          "port",
> > -                                          ll_index_to_name(*port_ifindex));
> > +       if (is_json_context())
> > +               open_json_array(PRINT_JSON, brifname);
> > +       else if (!show_stats)
> > +               fprintf(f, "router ports on %s: ", brifname);
> > +
> > +       for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
> > +               uint32_t *port_ifindex = RTA_DATA(i);
> > +               const char *port_ifname = ll_index_to_name(*port_ifindex);
> > +
> > +               if (is_json_context()) {
> > +                       open_json_object(NULL);
> > +                       print_string(PRINT_JSON, "port", NULL, port_ifname);
> > +
> >                         if (show_stats)
> >                                 __print_router_port_stats(f, i);
> > -                       jsonw_end_object(jw_global);
> > -               }
> > -               jsonw_end_array(jw_global);
> > -       } else {
> > -               if (!show_stats)
> > -                       fprintf(f, "router ports on %s: ",
> > -                               ll_index_to_name(brifidx));
> > -               for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
> > -                       port_ifindex = RTA_DATA(i);
> > -                       if (show_stats) {
> > -                               fprintf(f, "router ports on %s: %s",
> > -                                       ll_index_to_name(brifidx),
> > -                                       ll_index_to_name(*port_ifindex));
> > -                               __print_router_port_stats(f, i);
> > -                               fprintf(f, "\n");
> > -                       } else{
> > -                               fprintf(f, "%s ",
> > -                                       ll_index_to_name(*port_ifindex));
> > -                       }
> > -               }
> > -               if (!show_stats)
> > +                       close_json_object();
> > +               } else if (show_stats) {
> > +                       fprintf(f, "router ports on %s: %s",
> > +                               brifname, port_ifname);
> > +
> > +                       __print_router_port_stats(f, i);
> >                         fprintf(f, "\n");
> > +               } else {
> > +                       fprintf(f, "%s ", port_ifname);
> > +               }
> >         }
> > +       close_json_array(PRINT_JSON, NULL);
> >  }
> >
> > -static void start_json_mdb_flags_array(bool *mdb_flags)
> > -{
> > -       if (*mdb_flags)
> > -               return;
> > -       jsonw_name(jw_global, "flags");
> > -       jsonw_start_array(jw_global);
> > -       *mdb_flags = true;
> > -}
> > -
> > -static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e,
> > +static void print_mdb_entry(FILE *f, int ifindex, const struct br_mdb_entry *e,
> >                             struct nlmsghdr *n, struct rtattr **tb)
> >  {
> >         SPRINT_BUF(abuf);
> > +       const char *dev;
> >         const void *src;
> >         int af;
> > -       bool mdb_flags = false;
> >
> >         if (filter_vlan && e->vid != filter_vlan)
> >                 return;
> > +
> >         af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6;
> >         src = af == AF_INET ? (const void *)&e->addr.u.ip4 :
> >                               (const void *)&e->addr.u.ip6;
> > -       if (jw_global)
> > -               jsonw_start_object(jw_global);
> > -       if (n->nlmsg_type == RTM_DELMDB) {
> > -               if (jw_global)
> > -                       jsonw_string_field(jw_global, "opCode", "deleted");
> > -               else
> > -                       fprintf(f, "Deleted ");
> > -       }
> > -       if (jw_global) {
> > -               jsonw_string_field(jw_global, "dev", ll_index_to_name(ifindex));
> > -               jsonw_string_field(jw_global,
> > -                                  "port",
> > -                                  ll_index_to_name(e->ifindex));
> > -               jsonw_string_field(jw_global, "grp", inet_ntop(af, src,
> > -                       abuf, sizeof(abuf)));
> > -               jsonw_string_field(jw_global, "state",
> > -                       (e->state & MDB_PERMANENT) ? "permanent" : "temp");
> > -               if (e->flags & MDB_FLAGS_OFFLOAD) {
> > -                       start_json_mdb_flags_array(&mdb_flags);
> > -                       jsonw_string(jw_global, "offload");
> > -               }
> > -               if (mdb_flags)
> > -                       jsonw_end_array(jw_global);
> > -       } else{
> > -               fprintf(f, "dev %s port %s grp %s %s %s",
> > -                       ll_index_to_name(ifindex),
> > -                       ll_index_to_name(e->ifindex),
> > -                       inet_ntop(af, src, abuf, sizeof(abuf)),
> > -                       (e->state & MDB_PERMANENT) ? "permanent" : "temp",
> > -                       (e->flags & MDB_FLAGS_OFFLOAD) ? "offload" : "");
> > -       }
> > -       if (e->vid) {
> > -               if (jw_global)
> > -                       jsonw_uint_field(jw_global, "vid", e->vid);
> > -               else
> > -                       fprintf(f, " vid %hu", e->vid);
> > +       dev = ll_index_to_name(ifindex);
> > +
> > +       open_json_object(NULL);
> > +
> > +       if (n->nlmsg_type == RTM_DELMDB)
> > +               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
> > +
> > +
> > +       if (is_json_context()) {
> > +               print_int(PRINT_JSON, "index", NULL, ifindex);
> > +               print_string(PRINT_JSON, "dev", NULL, dev);
> > +       } else {
> > +               fprintf(f, "%u: ", ifindex);
> > +               color_fprintf(f, COLOR_IFNAME, "%s ", dev);
> >         }
> > -       if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
> > -               struct timeval tv;
> >
> > -               __jiffies_to_tv(&tv, rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]));
> > -               if (jw_global) {
> > -                       char formatted_time[9];
> > +       print_string(PRINT_ANY, "port", " %s ",
> > +                    ll_index_to_name(e->ifindex));
> >
> > -                       snprintf(formatted_time, sizeof(formatted_time),
> > -                                "%4i.%.2i", (int)tv.tv_sec,
> > -                                (int)tv.tv_usec/10000);
> > -                       jsonw_string_field(jw_global, "timer", formatted_time);
> > -               } else {
> > -                       fprintf(f, "%4i.%.2i", (int)tv.tv_sec,
> > -                               (int)tv.tv_usec/10000);
> > -               }
> > +       print_color_string(PRINT_ANY, ifa_family_color(af),
> > +                           "grp", " %s ",
> > +                           inet_ntop(af, src, abuf, sizeof(abuf)));
> > +
> > +       print_string(PRINT_ANY, "state", " %s ",
> > +                          (e->state & MDB_PERMANENT) ? "permanent" : "temp");
> > +
> > +       open_json_array(PRINT_JSON, "flags");
> > +       if (e->flags & MDB_FLAGS_OFFLOAD)
> > +               print_string(PRINT_ANY, NULL, "%s ", "offload");
> > +       close_json_array(PRINT_JSON, NULL);
> > +
> > +       if (e->vid)
> > +               print_uint(PRINT_ANY, "vid", " vid %u", e->vid);
> > +
> > +       if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
> > +               __u32 timer = rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]);
> > +
> > +               print_string(PRINT_ANY, "timer", " %s",
> > +                            format_timer(timer));
> >         }
> > -       if (jw_global)
> > -               jsonw_end_object(jw_global);
> > -       else
> > -               fprintf(f, "\n");
> > +       close_json_object();
> >  }
> >
> >  static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
> > @@ -218,15 +184,60 @@ static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
> >         }
> >  }
> >
> > +static void print_mdb_entries(FILE *fp, struct nlmsghdr *n,
> > +                             int ifindex,  struct rtattr *mdb)
> > +{
> > +       int rem = RTA_PAYLOAD(mdb);
> > +       struct rtattr *i;
> > +
> > +       open_json_array(PRINT_JSON, "mdb");
> > +       for (i = RTA_DATA(mdb); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
> > +               br_print_mdb_entry(fp, ifindex, i, n);
> > +       close_json_array(PRINT_JSON, NULL);
> > +}
> > +
> > +static void print_router_entries(FILE *fp, struct nlmsghdr *n,
> > +                                int ifindex, struct rtattr *router)
> > +{
> > +       const char *brifname = ll_index_to_name(ifindex);
> > +
> > +       open_json_array(PRINT_JSON, "router");
> > +       if (n->nlmsg_type == RTM_GETMDB) {
> > +               if (show_details)
> > +                       br_print_router_ports(fp, router, brifname);
> > +       } else {
> > +               struct rtattr *i = RTA_DATA(router);
> > +               uint32_t *port_ifindex = RTA_DATA(i);
> > +
> > +               if (is_json_context()) {
> > +                       open_json_array(PRINT_JSON, brifname);
> > +                       open_json_object(NULL);
> > +
> > +                       print_string(PRINT_JSON, "port", NULL,
> > +                                    ll_index_to_name(*port_ifindex));
> > +                       close_json_object();
> > +                       close_json_array(PRINT_JSON, NULL);
> > +               } else {
> > +                       fprintf(fp, "router port dev %s master %s\n",
> > +                               ll_index_to_name(*port_ifindex),
> > +                               brifname);
> > +               }
> > +       }
> > +       close_json_array(PRINT_JSON, NULL);
> > +}
> > +
> >  int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
> >  {
> >         FILE *fp = arg;
> >         struct br_port_msg *r = NLMSG_DATA(n);
> >         int len = n->nlmsg_len;
> > -       struct rtattr *tb[MDBA_MAX+1], *i;
> > +       struct rtattr *tb[MDBA_MAX+1];
> >
> > -       if (n->nlmsg_type != RTM_GETMDB && n->nlmsg_type != RTM_NEWMDB && n->nlmsg_type != RTM_DELMDB) {
> > -               fprintf(stderr, "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
> > +       if (n->nlmsg_type != RTM_GETMDB &&
> > +           n->nlmsg_type != RTM_NEWMDB &&
> > +           n->nlmsg_type != RTM_DELMDB) {
> > +               fprintf(stderr,
> > +                       "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
> >                         n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
> >
> >                 return 0;
> > @@ -243,50 +254,14 @@ int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
> >
> >         parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
> >
> > -       if (tb[MDBA_MDB] && print_mdb_entries) {
> > -               int rem = RTA_PAYLOAD(tb[MDBA_MDB]);
> > +       if (n->nlmsg_type == RTM_DELMDB)
> > +               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
> >
> > -               for (i = RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
> > -                       br_print_mdb_entry(fp, r->ifindex, i, n);
> > -       }
> > +       if (tb[MDBA_MDB])
> > +               print_mdb_entries(fp, n, r->ifindex, tb[MDBA_MDB]);
> >
> > -       if (tb[MDBA_ROUTER] && print_mdb_router) {
> > -               if (n->nlmsg_type == RTM_GETMDB) {
> > -                       if (show_details)
> > -                               br_print_router_ports(fp, tb[MDBA_ROUTER],
> > -                                                     r->ifindex);
> > -               } else {
> > -                       uint32_t *port_ifindex;
> > -
> > -                       i = RTA_DATA(tb[MDBA_ROUTER]);
> > -                       port_ifindex = RTA_DATA(i);
> > -                       if (n->nlmsg_type == RTM_DELMDB) {
> > -                               if (jw_global)
> > -                                       jsonw_string_field(jw_global,
> > -                                                          "opCode",
> > -                                                          "deleted");
> > -                               else
> > -                                       fprintf(fp, "Deleted ");
> > -                       }
> > -                       if (jw_global) {
> > -                               jsonw_name(jw_global,
> > -                                          ll_index_to_name(r->ifindex));
> > -                               jsonw_start_array(jw_global);
> > -                               jsonw_start_object(jw_global);
> > -                               jsonw_string_field(jw_global, "port",
> > -                                       ll_index_to_name(*port_ifindex));
> > -                               jsonw_end_object(jw_global);
> > -                               jsonw_end_array(jw_global);
> > -                       } else {
> > -                               fprintf(fp, "router port dev %s master %s\n",
> > -                                       ll_index_to_name(*port_ifindex),
> > -                                       ll_index_to_name(r->ifindex));
> > -                       }
> > -               }
> > -       }
> > -
> > -       if (!jw_global)
> > -               fflush(fp);
> > +       if (tb[MDBA_ROUTER])
> > +               print_router_entries(fp, n, r->ifindex, tb[MDBA_ROUTER]);
> >
> >         return 0;
> >  }
> > @@ -319,62 +294,21 @@ static int mdb_show(int argc, char **argv)
> >                 }
> >         }
> >
> > +       new_json_obj(json);
> > +
> >         /* get mdb entries*/
> >         if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
> >                 perror("Cannot send dump request");
> >                 return -1;
> >         }
> >
> > -       if (!json) {
> > -               /* Normal output */
> > -               if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
> > -                       fprintf(stderr, "Dump terminated\n");
> > -                       return -1;
> > -               }
> > -               return 0;
> > -       }
> > -
> > -       /* Json output */
> > -       jw_global = jsonw_new(stdout);
> > -       if (!jw_global) {
> > -               fprintf(stderr, "Error allocation json object\n");
> > -               exit(1);
> > -       }
> > -
> > -       if (pretty)
> > -               jsonw_pretty(jw_global, 1);
> > -
> > -       jsonw_start_object(jw_global);
> > -       jsonw_name(jw_global, "mdb");
> > -       jsonw_start_array(jw_global);
> > -
> > -       /* print mdb entries */
> > -       print_mdb_entries = true;
> > -       print_mdb_router = false;
> >         if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
> >                 fprintf(stderr, "Dump terminated\n");
> >                 return -1;
> >         }
> > -       jsonw_end_array(jw_global);
> > -
> > -       /* get router ports */
> > -       if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
> > -               perror("Cannot send dump request");
> > -               return -1;
> > -       }
> > -       jsonw_name(jw_global, "router");
> > -       jsonw_start_object(jw_global);
> >
> > -       /* print router ports */
> > -       print_mdb_entries = false;
> > -       print_mdb_router = true;
> > -       if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
> > -               fprintf(stderr, "Dump terminated\n");
> > -               return -1;
> > -       }
> > -       jsonw_end_object(jw_global);
> > -       jsonw_end_object(jw_global);
> > -       jsonw_destroy(&jw_global);
> > +       delete_json_obj();
> > +       fflush(stdout);
> >
> >         return 0;
> >  }
> > diff --git a/bridge/vlan.c b/bridge/vlan.c
> > index 7c8b3ad54857..9f4a7a2be55c 100644
> > --- a/bridge/vlan.c
> > +++ b/bridge/vlan.c
> > @@ -8,19 +8,16 @@
> >  #include <netinet/in.h>
> >  #include <linux/if_bridge.h>
> >  #include <linux/if_ether.h>
> > -#include <json_writer.h>
> >  #include <string.h>
> >
> > +#include "json_print.h"
> >  #include "libnetlink.h"
> >  #include "br_common.h"
> >  #include "utils.h"
> >
> >  static unsigned int filter_index, filter_vlan;
> > -static int last_ifidx = -1;
> >  static int show_vlan_tunnel_info = 0;
> >
> > -json_writer_t *jw_global;
> > -
> >  static void usage(void)
> >  {
> >         fprintf(stderr,
> > @@ -257,38 +254,33 @@ static int filter_vlan_check(__u16 vid, __u16 flags)
> >
> >  static void print_vlan_port(FILE *fp, int ifi_index)
> >  {
> > -       if (jw_global) {
> > -               jsonw_name(jw_global,
> > -                          ll_index_to_name(ifi_index));
> > -               jsonw_start_array(jw_global);
> > -       } else {
> > -               fprintf(fp, "%s",
> > -                       ll_index_to_name(ifi_index));
> > -       }
> > +       print_string(PRINT_ANY, NULL, "%s",
> > +                    ll_index_to_name(ifi_index));
> >  }
> >  
> 
> Stephen, this seems to have broken both json and non-json output.
> 
> Here is some output before and after the patch (same thing for tunnelshow):
> 
> before:
> $bridge vlan show
> port    vlan ids
> hostbond4        1000
>          1001 PVID Egress Untagged
>          1002
>          1003
>          1004
> 
> hostbond3        1000 PVID Egress Untagged
>          1001
>          1002
>          1003
>          1004
> 
> bridge   1 PVID Egress Untagged
>          1000
>          1001
>          1002
>          1003
>          1004
> 
> vxlan0   1 PVID Egress Untagged
>          1000
>          1001
>          1002
>          1003
>          1004
> 
> 
> $ bridge -j -c vlan show
> {
>     "hostbond4": [{
>             "vlan": 1000
>         },{
>             "vlan": 1001,
>             "flags": ["PVID","Egress Untagged"
>             ]
>         },{
>             "vlan": 1002,
>             "vlanEnd": 1004
>         }
>     ],
>     "hostbond3": [{
>             "vlan": 1000,
>             "flags": ["PVID","Egress Untagged"
>             ]
>         },{
>             "vlan": 1001,
>             "vlanEnd": 1004
>         }
>     ],
>     "bridge": [{
>             "vlan": 1,
>             "flags": ["PVID","Egress Untagged"
>             ]
>         },{
>             "vlan": 1000,
>             "vlanEnd": 1004
>         }
>     ],
>         "vxlan0": [{
>             "vlan": 1,
>             "flags": ["PVID","Egress Untagged"
>             ]
>         },{
>             "vlan": 1000,
>             "vlanEnd": 1004
>         }
>     ]
> }
> 
> 
> after:
> ====
> 
> $bridge vlan show
> port    vlan ids
> hostbond4
>          1000    1001 PVID untagged      1002    1003    1004
> hostbond3
>          1000 PVID untagged      1001    1002    1003    1004
> bridge
>          1 PVID untagged         1000    1001    1002    1003    1004
> vxlan0
>          1 PVID untagged         1000    1001    1002    1003    1004
> 
> $bridge -j -c vlan show
> ["hostbond4","vlan":[{"vlan":1000},{"vlan":1001,"pvid":null,"untagged":null},{"vlan":1002},{"vlan":1003},{"vlan":1004}],"hostbond3","vlan":[{"vlan":1000,"pvid":null,"untagged":null},{"vlan":1001},{"vlan":1002},{"vlan":1003},{"vlan":1004}],"bridge","vlan":[{"vlan":1,"pvid":null,"untagged":null},{"vlan":1000},{"vlan":1001},{"vlan":1002},{"vlan":1003},{"vlan":1004}],"vxlan0","vlan":[{"vlan":1,"pvid":null,"untagged":null},{"vlan":1000},{"vlan":1001},{"vlan":1002},{"vlan":1003},{"vlan":1004}]]

I can fix it. 

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

end of thread, other threads:[~2018-08-29 19:02 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-20 19:24 [PATCH v2 iproute2-next 0/5] bridge: json and color support Stephen Hemminger
2018-02-20 19:24 ` [PATCH v2 iproute2-next 1/5] bridge: implement json pretty print flag Stephen Hemminger
2018-02-20 19:24 ` [PATCH v2 iproute2-next 2/5] bridge: colorize output and use JSON print library Stephen Hemminger
2018-07-15  1:41   ` Roopa Prabhu
2018-08-29  1:17     ` Roopa Prabhu
2018-08-29 15:04     ` Stephen Hemminger
2018-02-20 19:24 ` [PATCH v2 iproute2-next 3/5] bridge: add json support for link command Stephen Hemminger
2018-02-20 19:24 ` [PATCH v2 iproute2-next 4/5] bridge: update man page for new color and json changes Stephen Hemminger
2018-02-20 19:24 ` [PATCH v2 iproute2-next 5/5] ip: always print interface name in color Stephen Hemminger
2018-02-21 16:48 ` [PATCH v2 iproute2-next 0/5] bridge: json and color support 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.