netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC iproute2-next 00/16] iproute printing enhancements
@ 2018-02-02  1:19 Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 01/16] iproute: refactor printing flags Stephen Hemminger
                   ` (17 more replies)
  0 siblings, 18 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger

The first group of patches refactor the printout to breakup
excessively long print_route function and the last few implement
JSON and color output format for routes.

The one thing that maybe controversial is changing the default
json output format to be compact. The value of JSON is for programattic
output therefore pretty-printing should be an option.

One change I didn't make (but considered) is not calling fflush
after every single entry. When dumping millions of routes, letting
stdio buffer output would be a performance win.

Stephen Hemminger (16):
  iproute: refactor printing flags
  iproute: make printing icmpv6 a function
  iproute: make printing IPv4 cache flags a function
  iproute: refactor cacheinfo printing
  iproute: refactor metrics print
  iproute: refactor printing flow info
  iproute2: refactor newdst, gateway and via printing
  iproute: refactor multipath print
  iproute: refactor printing of interface
  iproute: whitespace fixes
  iproute: don't do assignment in condition
  iproute: make flush a separate function
  iproute: implement JSON and color output
  json: make pretty printing optional
  man: add documentation for json and pretty flags
  json: fix newline at end of array

 include/json_print.h |   2 +
 include/utils.h      |   4 +
 ip/ip.c              |   7 +-
 ip/iproute.c         | 943 ++++++++++++++++++++++++++++++---------------------
 lib/json_print.c     |   5 +-
 lib/json_writer.c    |   5 +
 man/man8/ip.8        |  18 +-
 man/man8/tc.8        |   3 +-
 tc/tc.c              |   3 +
 9 files changed, 598 insertions(+), 392 deletions(-)

-- 
2.15.1

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

* [RFC iproute2-next 01/16] iproute: refactor printing flags
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 02/16] iproute: make printing icmpv6 a function Stephen Hemminger
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

Both next hop and route need to decode flags.

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

diff --git a/ip/iproute.c b/ip/iproute.c
index bf886fda9d76..a343187ff90e 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -348,6 +348,22 @@ static void print_rtax_features(FILE *fp, unsigned int features)
 		fprintf(fp, "0x%x ", of);
 }
 
+static void print_rt_flags(FILE *fp, unsigned int flags)
+{
+	if (flags & RTNH_F_DEAD)
+		fprintf(fp, "dead ");
+	if (flags & RTNH_F_ONLINK)
+		fprintf(fp, "onlink ");
+	if (flags & RTNH_F_PERVASIVE)
+		fprintf(fp, "pervasive ");
+	if (flags & RTNH_F_OFFLOAD)
+		fprintf(fp, "offload ");
+	if (flags & RTNH_F_LINKDOWN)
+		fprintf(fp, "linkdown ");
+	if (flags & RTNH_F_UNRESOLVED)
+		fprintf(fp, "unresolved ");
+}
+
 int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE *)arg;
@@ -479,20 +495,9 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	}
 	if (tb[RTA_PRIORITY] && filter.metricmask != -1)
 		fprintf(fp, "metric %u ", rta_getattr_u32(tb[RTA_PRIORITY]));
-	if (r->rtm_flags & RTNH_F_DEAD)
-		fprintf(fp, "dead ");
-	if (r->rtm_flags & RTNH_F_ONLINK)
-		fprintf(fp, "onlink ");
-	if (r->rtm_flags & RTNH_F_PERVASIVE)
-		fprintf(fp, "pervasive ");
-	if (r->rtm_flags & RTNH_F_OFFLOAD)
-		fprintf(fp, "offload ");
-	if (r->rtm_flags & RTM_F_NOTIFY)
-		fprintf(fp, "notify ");
-	if (r->rtm_flags & RTNH_F_LINKDOWN)
-		fprintf(fp, "linkdown ");
-	if (r->rtm_flags & RTNH_F_UNRESOLVED)
-		fprintf(fp, "unresolved ");
+
+	print_rt_flags(fp, r->rtm_flags);
+
 	if (tb[RTA_MARK]) {
 		unsigned int mark = rta_getattr_u32(tb[RTA_MARK]);
 
@@ -729,16 +734,9 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 					fprintf(fp, "weight %d ",
 						nh->rtnh_hops+1);
 			}
-			if (nh->rtnh_flags & RTNH_F_DEAD)
-				fprintf(fp, "dead ");
-			if (nh->rtnh_flags & RTNH_F_ONLINK)
-				fprintf(fp, "onlink ");
-			if (nh->rtnh_flags & RTNH_F_PERVASIVE)
-				fprintf(fp, "pervasive ");
-			if (nh->rtnh_flags & RTNH_F_OFFLOAD)
-				fprintf(fp, "offload ");
-			if (nh->rtnh_flags & RTNH_F_LINKDOWN)
-				fprintf(fp, "linkdown ");
+
+			print_rt_flags(fp, nh->rtnh_flags);
+
 			len -= NLMSG_ALIGN(nh->rtnh_len);
 			nh = RTNH_NEXT(nh);
 		}
-- 
2.15.1

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

* [RFC iproute2-next 02/16] iproute: make printing icmpv6 a function
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 01/16] iproute: refactor printing flags Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 03/16] iproute: make printing IPv4 cache flags " Stephen Hemminger
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

Refactor to reduce size of print_route and improve
readability.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/iproute.c | 38 +++++++++++++++++++++-----------------
 1 file changed, 21 insertions(+), 17 deletions(-)

diff --git a/ip/iproute.c b/ip/iproute.c
index a343187ff90e..472e4135c5d9 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -364,6 +364,25 @@ static void print_rt_flags(FILE *fp, unsigned int flags)
 		fprintf(fp, "unresolved ");
 }
 
+static void print_rt_pref(FILE *fp, unsigned int pref)
+{
+	fprintf(fp, "pref ");
+
+	switch (pref) {
+	case ICMPV6_ROUTER_PREF_LOW:
+		fprintf(fp, "low");
+		break;
+	case ICMPV6_ROUTER_PREF_MEDIUM:
+		fprintf(fp, "medium");
+		break;
+	case ICMPV6_ROUTER_PREF_HIGH:
+		fprintf(fp, "high");
+		break;
+	default:
+		fprintf(fp, "%u", pref);
+	}
+}
+
 int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE *)arg;
@@ -741,25 +760,10 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 			nh = RTNH_NEXT(nh);
 		}
 	}
-	if (tb[RTA_PREF]) {
-		unsigned int pref = rta_getattr_u8(tb[RTA_PREF]);
 
-		fprintf(fp, "pref ");
+	if (tb[RTA_PREF])
+		print_rt_pref(fp, rta_getattr_u8(tb[RTA_PREF]));
 
-		switch (pref) {
-		case ICMPV6_ROUTER_PREF_LOW:
-			fprintf(fp, "low");
-			break;
-		case ICMPV6_ROUTER_PREF_MEDIUM:
-			fprintf(fp, "medium");
-			break;
-		case ICMPV6_ROUTER_PREF_HIGH:
-			fprintf(fp, "high");
-			break;
-		default:
-			fprintf(fp, "%u", pref);
-		}
-	}
 	if (tb[RTA_TTL_PROPAGATE]) {
 		fprintf(fp, "ttl-propagate ");
 		if (rta_getattr_u8(tb[RTA_TTL_PROPAGATE]))
-- 
2.15.1

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

* [RFC iproute2-next 03/16] iproute: make printing IPv4 cache flags a function
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 01/16] iproute: refactor printing flags Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 02/16] iproute: make printing icmpv6 a function Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 04/16] iproute: refactor cacheinfo printing Stephen Hemminger
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

More refactoring prior to JSON support.

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

diff --git a/ip/iproute.c b/ip/iproute.c
index 472e4135c5d9..d9c25c05966c 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -383,6 +383,41 @@ static void print_rt_pref(FILE *fp, unsigned int pref)
 	}
 }
 
+static void print_ipv4_flags(FILE *fp, __u32 flags)
+{
+	int first = 1;
+
+	flags &= ~0xFFFF;
+
+	fprintf(fp, "%s    cache ", _SL_);
+
+#define PRTFL(fl, flname)					\
+	if (flags&RTCF_##fl) {					\
+		flags &= ~RTCF_##fl;				\
+		fprintf(fp, "%s" flname "%s",			\
+			first ? "<" : "", flags ? "," : "> ");	\
+		first = 0; }
+
+	PRTFL(LOCAL, "local");
+	PRTFL(REJECT, "reject");
+	PRTFL(MULTICAST, "mc");
+	PRTFL(BROADCAST, "brd");
+	PRTFL(DNAT, "dst-nat");
+	PRTFL(SNAT, "src-nat");
+	PRTFL(MASQ, "masq");
+	PRTFL(DIRECTDST, "dst-direct");
+	PRTFL(DIRECTSRC, "src-direct");
+	PRTFL(REDIRECTED, "redirected");
+	PRTFL(DOREDIRECT, "redirect");
+	PRTFL(FAST, "fastroute");
+	PRTFL(NOTIFY, "notify");
+	PRTFL(TPROXY, "proxy");
+#undef PRTFL
+
+	if (flags)
+		fprintf(fp, "%s%x> ", first ? "<" : "", flags);
+}
+
 int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE *)arg;
@@ -545,33 +580,9 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	if (tb[RTA_UID])
 		fprintf(fp, "uid %u ", rta_getattr_u32(tb[RTA_UID]));
 
-	if ((r->rtm_flags&RTM_F_CLONED) && r->rtm_family == AF_INET) {
-		__u32 flags = r->rtm_flags&~0xFFFF;
-		int first = 1;
+	if ((r->rtm_flags & RTM_F_CLONED) && r->rtm_family == AF_INET) {
+		print_ipv4_flags(fp, r->rtm_flags);
 
-		fprintf(fp, "%s    cache ", _SL_);
-
-#define PRTFL(fl, flname) if (flags&RTCF_##fl) { \
-  flags &= ~RTCF_##fl; \
-  fprintf(fp, "%s" flname "%s", first ? "<" : "", flags ? "," : "> "); \
-  first = 0; }
-		PRTFL(LOCAL, "local");
-		PRTFL(REJECT, "reject");
-		PRTFL(MULTICAST, "mc");
-		PRTFL(BROADCAST, "brd");
-		PRTFL(DNAT, "dst-nat");
-		PRTFL(SNAT, "src-nat");
-		PRTFL(MASQ, "masq");
-		PRTFL(DIRECTDST, "dst-direct");
-		PRTFL(DIRECTSRC, "src-direct");
-		PRTFL(REDIRECTED, "redirected");
-		PRTFL(DOREDIRECT, "redirect");
-		PRTFL(FAST, "fastroute");
-		PRTFL(NOTIFY, "notify");
-		PRTFL(TPROXY, "proxy");
-
-		if (flags)
-			fprintf(fp, "%s%x> ", first ? "<" : "", flags);
 		if (tb[RTA_CACHEINFO]) {
 			struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]);
 
-- 
2.15.1

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

* [RFC iproute2-next 04/16] iproute: refactor cacheinfo printing
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (2 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 03/16] iproute: make printing IPv4 cache flags " Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 05/16] iproute: refactor metrics print Stephen Hemminger
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

Make common function for decoding cacheinfo.
This code may print more info than old version in some cases.

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

diff --git a/ip/iproute.c b/ip/iproute.c
index d9c25c05966c..76a564922b5c 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -418,6 +418,31 @@ static void print_ipv4_flags(FILE *fp, __u32 flags)
 		fprintf(fp, "%s%x> ", first ? "<" : "", flags);
 }
 
+static void print_rta_cacheinfo(FILE *fp, const struct rta_cacheinfo *ci)
+{
+	static int hz;
+
+	if (!hz)
+		hz = get_user_hz();
+	if (ci->rta_expires != 0)
+		fprintf(fp, "expires %dsec ", ci->rta_expires/hz);
+	if (ci->rta_error != 0)
+		fprintf(fp, "error %d ", ci->rta_error);
+	if (show_stats) {
+		if (ci->rta_clntref)
+			fprintf(fp, "users %d ", ci->rta_clntref);
+		if (ci->rta_used != 0)
+			fprintf(fp, "used %d ", ci->rta_used);
+		if (ci->rta_lastuse != 0)
+			fprintf(fp, "age %dsec ", ci->rta_lastuse/hz);
+	}
+	if (ci->rta_id)
+		fprintf(fp, "ipid 0x%04x ", ci->rta_id);
+	if (ci->rta_ts || ci->rta_tsage)
+		fprintf(fp, "ts 0x%x tsage %dsec ",
+			ci->rta_ts, ci->rta_tsage);
+}
+
 int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE *)arg;
@@ -429,7 +454,6 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	int ret;
 
 	SPRINT_BUF(b1);
-	static int hz;
 
 	if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
 		fprintf(stderr, "Not a route: %08x %08x %08x\n",
@@ -583,56 +607,18 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	if ((r->rtm_flags & RTM_F_CLONED) && r->rtm_family == AF_INET) {
 		print_ipv4_flags(fp, r->rtm_flags);
 
-		if (tb[RTA_CACHEINFO]) {
-			struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]);
+		if (tb[RTA_CACHEINFO])
+			print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
 
-			if (!hz)
-				hz = get_user_hz();
-			if (ci->rta_expires != 0)
-				fprintf(fp, "expires %dsec ", ci->rta_expires/hz);
-			if (ci->rta_error != 0)
-				fprintf(fp, "error %d ", ci->rta_error);
-			if (show_stats) {
-				if (ci->rta_clntref)
-					fprintf(fp, "users %d ", ci->rta_clntref);
-				if (ci->rta_used != 0)
-					fprintf(fp, "used %d ", ci->rta_used);
-				if (ci->rta_lastuse != 0)
-					fprintf(fp, "age %dsec ", ci->rta_lastuse/hz);
-			}
-			if (ci->rta_id)
-				fprintf(fp, "ipid 0x%04x ", ci->rta_id);
-			if (ci->rta_ts || ci->rta_tsage)
-				fprintf(fp, "ts 0x%x tsage %dsec ",
-					ci->rta_ts, ci->rta_tsage);
-		}
 	} else if (r->rtm_family == AF_INET6) {
-		struct rta_cacheinfo *ci = NULL;
+
+		if (r->rtm_flags & RTM_F_CLONED)
+			fprintf(fp, "%s    cache ", _SL_);
 
 		if (tb[RTA_CACHEINFO])
-			ci = RTA_DATA(tb[RTA_CACHEINFO]);
-		if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
-			if (!hz)
-				hz = get_user_hz();
-			if (r->rtm_flags & RTM_F_CLONED)
-				fprintf(fp, "%s    cache ", _SL_);
-			if (ci->rta_expires)
-				fprintf(fp, "expires %dsec ", ci->rta_expires/hz);
-			if (ci->rta_error != 0)
-				fprintf(fp, "error %d ", ci->rta_error);
-			if (show_stats) {
-				if (ci->rta_clntref)
-					fprintf(fp, "users %d ", ci->rta_clntref);
-				if (ci->rta_used != 0)
-					fprintf(fp, "used %d ", ci->rta_used);
-				if (ci->rta_lastuse != 0)
-					fprintf(fp, "age %dsec ", ci->rta_lastuse/hz);
-			}
-		} else if (ci) {
-			if (ci->rta_error != 0)
-				fprintf(fp, "error %d ", ci->rta_error);
-		}
+			print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
 	}
+
 	if (tb[RTA_METRICS]) {
 		int i;
 		unsigned int mxlock = 0;
-- 
2.15.1

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

* [RFC iproute2-next 05/16] iproute: refactor metrics print
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (3 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 04/16] iproute: refactor cacheinfo printing Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 06/16] iproute: refactor printing flow info Stephen Hemminger
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger

Make a separate function to improve readability and enable
easier JSON conversion.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
 ip/iproute.c | 117 +++++++++++++++++++++++++++++++----------------------------
 1 file changed, 61 insertions(+), 56 deletions(-)

diff --git a/ip/iproute.c b/ip/iproute.c
index 76a564922b5c..42d1678b9690 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -443,6 +443,65 @@ static void print_rta_cacheinfo(FILE *fp, const struct rta_cacheinfo *ci)
 			ci->rta_ts, ci->rta_tsage);
 }
 
+static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
+{
+	struct rtattr *mxrta[RTAX_MAX+1];
+	unsigned int mxlock = 0;
+	int i;
+
+	parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta));
+
+	if (mxrta[RTAX_LOCK])
+		mxlock = rta_getattr_u32(mxrta[RTAX_LOCK]);
+
+	for (i = 2; i <= RTAX_MAX; i++) {
+		__u32 val = 0U;
+
+		if (mxrta[i] == NULL && !(mxlock & (1 << i)))
+			continue;
+
+		if (mxrta[i] != NULL && i != RTAX_CC_ALGO)
+			val = rta_getattr_u32(mxrta[i]);
+
+		if (i == RTAX_HOPLIMIT && (int)val == -1)
+			continue;
+
+		if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i])
+			fprintf(fp, "%s ", mx_names[i]);
+		else
+			fprintf(fp, "metric %d ", i);
+
+		if (mxlock & (1<<i))
+			fprintf(fp, "lock ");
+
+		switch (i) {
+		case RTAX_FEATURES:
+			print_rtax_features(fp, val);
+			break;
+		default:
+			fprintf(fp, "%u ", val);
+			break;
+
+		case RTAX_RTT:
+		case RTAX_RTTVAR:
+		case RTAX_RTO_MIN:
+			if (i == RTAX_RTT)
+				val /= 8;
+			else if (i == RTAX_RTTVAR)
+				val /= 4;
+
+			if (val >= 1000)
+				fprintf(fp, "%gs ", val/1e3);
+			else
+				fprintf(fp, "%ums ", val);
+			break;
+		case RTAX_CC_ALGO:
+			fprintf(fp, "%s ", rta_getattr_str(mxrta[i]));
+			break;
+		}
+	}
+}
+
 int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE *)arg;
@@ -619,63 +678,9 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 			print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
 	}
 
-	if (tb[RTA_METRICS]) {
-		int i;
-		unsigned int mxlock = 0;
-		struct rtattr *mxrta[RTAX_MAX+1];
-
-		parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
-			    RTA_PAYLOAD(tb[RTA_METRICS]));
-		if (mxrta[RTAX_LOCK])
-			mxlock = rta_getattr_u32(mxrta[RTAX_LOCK]);
-
-		for (i = 2; i <= RTAX_MAX; i++) {
-			__u32 val = 0U;
-
-			if (mxrta[i] == NULL && !(mxlock & (1 << i)))
-				continue;
-
-			if (mxrta[i] != NULL && i != RTAX_CC_ALGO)
-				val = rta_getattr_u32(mxrta[i]);
-
-			if (i == RTAX_HOPLIMIT && (int)val == -1)
-				continue;
-
-			if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i])
-				fprintf(fp, "%s ", mx_names[i]);
-			else
-				fprintf(fp, "metric %d ", i);
-
-			if (mxlock & (1<<i))
-				fprintf(fp, "lock ");
+	if (tb[RTA_METRICS])
+		print_rta_metrics(fp, tb[RTA_METRICS]);
 
-			switch (i) {
-			case RTAX_FEATURES:
-				print_rtax_features(fp, val);
-				break;
-			default:
-				fprintf(fp, "%u ", val);
-				break;
-
-			case RTAX_RTT:
-			case RTAX_RTTVAR:
-			case RTAX_RTO_MIN:
-				if (i == RTAX_RTT)
-					val /= 8;
-				else if (i == RTAX_RTTVAR)
-					val /= 4;
-
-				if (val >= 1000)
-					fprintf(fp, "%gs ", val/1e3);
-				else
-					fprintf(fp, "%ums ", val);
-				break;
-			case RTAX_CC_ALGO:
-				fprintf(fp, "%s ", rta_getattr_str(mxrta[i]));
-				break;
-			}
-		}
-	}
 	if (tb[RTA_IIF] && filter.iifmask != -1) {
 		fprintf(fp, "iif %s ",
 			ll_index_to_name(rta_getattr_u32(tb[RTA_IIF])));
-- 
2.15.1

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

* [RFC iproute2-next 06/16] iproute: refactor printing flow info
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (4 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 05/16] iproute: refactor metrics print Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 07/16] iproute2: refactor newdst, gateway and via printing Stephen Hemminger
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger

Use common code for printing flow info.

Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
 ip/iproute.c | 46 ++++++++++++++++++++--------------------------
 1 file changed, 20 insertions(+), 26 deletions(-)

diff --git a/ip/iproute.c b/ip/iproute.c
index 42d1678b9690..7482f04c1852 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -443,6 +443,22 @@ static void print_rta_cacheinfo(FILE *fp, const struct rta_cacheinfo *ci)
 			ci->rta_ts, ci->rta_tsage);
 }
 
+static void print_rta_flow(FILE *fp, const struct rtattr *rta)
+{
+	__u32 to = rta_getattr_u32(rta);
+	__u32 from = to >> 16;
+	SPRINT_BUF(b1);
+
+	to &= 0xFFFF;
+	fprintf(fp, "realm%s ", from ? "s" : "");
+	if (from) {
+		fprintf(fp, "%s/",
+			rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+	}
+	fprintf(fp, "%s ",
+		rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
+}
+
 static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
 {
 	struct rtattr *mxrta[RTAX_MAX+1];
@@ -646,19 +662,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		}
 	}
 
-	if (tb[RTA_FLOW] && filter.realmmask != ~0U) {
-		__u32 to = rta_getattr_u32(tb[RTA_FLOW]);
-		__u32 from = to>>16;
-
-		to &= 0xFFFF;
-		fprintf(fp, "realm%s ", from ? "s" : "");
-		if (from) {
-			fprintf(fp, "%s/",
-				rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
-		}
-		fprintf(fp, "%s ",
-			rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
-	}
+	if (tb[RTA_FLOW] && filter.realmmask != ~0U)
+		print_rta_flow(fp, tb[RTA_FLOW]);
 
 	if (tb[RTA_UID])
 		fprintf(fp, "uid %u ", rta_getattr_u32(tb[RTA_UID]));
@@ -730,19 +735,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 						family_name(via->rtvia_family),
 						format_host(via->rtvia_family, len, via->rtvia_addr));
 				}
-				if (tb[RTA_FLOW]) {
-					__u32 to = rta_getattr_u32(tb[RTA_FLOW]);
-					__u32 from = to>>16;
-
-					to &= 0xFFFF;
-					fprintf(fp, "realm%s ", from ? "s" : "");
-					if (from) {
-						fprintf(fp, "%s/",
-							rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
-					}
-					fprintf(fp, "%s ",
-						rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
-				}
+				if (tb[RTA_FLOW])
+					print_rta_flow(fp, tb[RTA_FLOW]);
 			}
 			if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
 				fprintf(fp, "%s", ll_index_to_name(nh->rtnh_ifindex));
-- 
2.15.1

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

* [RFC iproute2-next 07/16] iproute2: refactor newdst, gateway and via printing
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (5 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 06/16] iproute: refactor printing flow info Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 08/16] iproute: refactor multipath print Stephen Hemminger
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

Since these fields are printed in both route and multipath case;
avoid duplicating code.

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

diff --git a/ip/iproute.c b/ip/iproute.c
index 7482f04c1852..3f8238b7f457 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -459,6 +459,32 @@ static void print_rta_flow(FILE *fp, const struct rtattr *rta)
 		rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
 }
 
+static void print_rta_newdst(FILE *fp, const struct rtmsg *r,
+			     const struct rtattr *rta)
+{
+	const char *newdst = format_host_rta(r->rtm_family, rta);
+
+	fprintf(fp, "as to %s ", newdst);
+}
+
+static void print_rta_gateway(FILE *fp, const struct rtmsg *r,
+			      const struct rtattr *rta)
+{
+	const char *gateway = format_host_rta(r->rtm_family, rta);
+
+	fprintf(fp, "via %s ", gateway);
+}
+
+static void print_rta_via(FILE *fp, const struct rtattr *rta)
+{
+	const struct rtvia *via = RTA_DATA(rta);
+	size_t len = RTA_PAYLOAD(rta);
+
+	fprintf(fp, "via %s %s ",
+		family_name(via->rtvia_family),
+		format_host(via->rtvia_family, len, via->rtvia_addr));
+}
+
 static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
 {
 	struct rtattr *mxrta[RTAX_MAX+1];
@@ -603,10 +629,9 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	} else if (r->rtm_src_len) {
 		fprintf(fp, "from 0/%u ", r->rtm_src_len);
 	}
-	if (tb[RTA_NEWDST]) {
-		fprintf(fp, "as to %s ",
-		        format_host_rta(r->rtm_family, tb[RTA_NEWDST]));
-	}
+
+	if (tb[RTA_NEWDST])
+		print_rta_newdst(fp, r, tb[RTA_NEWDST]);
 
 	if (tb[RTA_ENCAP])
 		lwt_print_encap(fp, tb[RTA_ENCAP_TYPE], tb[RTA_ENCAP]);
@@ -616,18 +641,12 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
 	}
 
-	if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
-		fprintf(fp, "via %s ",
-		        format_host_rta(r->rtm_family, tb[RTA_GATEWAY]));
-	}
-	if (tb[RTA_VIA]) {
-		size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
-		struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
+	if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len)
+		print_rta_gateway(fp, r, tb[RTA_GATEWAY]);
+
+	if (tb[RTA_VIA])
+		print_rta_via(fp, tb[RTA_VIA]);
 
-		fprintf(fp, "via %s %s ",
-			family_name(via->rtvia_family),
-			format_host(via->rtvia_family, len, via->rtvia_addr));
-	}
 	if (tb[RTA_OIF] && filter.oifmask != -1)
 		fprintf(fp, "dev %s ", ll_index_to_name(rta_getattr_u32(tb[RTA_OIF])));
 
@@ -717,24 +736,12 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 					lwt_print_encap(fp,
 							tb[RTA_ENCAP_TYPE],
 							tb[RTA_ENCAP]);
-				if (tb[RTA_NEWDST]) {
-					fprintf(fp, "as to %s ",
-						format_host_rta(r->rtm_family,
-								tb[RTA_NEWDST]));
-				}
-				if (tb[RTA_GATEWAY]) {
-					fprintf(fp, "via %s ",
-						format_host_rta(r->rtm_family,
-								tb[RTA_GATEWAY]));
-				}
-				if (tb[RTA_VIA]) {
-					size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
-					struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
-
-					fprintf(fp, "via %s %s ",
-						family_name(via->rtvia_family),
-						format_host(via->rtvia_family, len, via->rtvia_addr));
-				}
+				if (tb[RTA_NEWDST])
+					print_rta_newdst(fp, r, tb[RTA_NEWDST]);
+				if (tb[RTA_GATEWAY])
+					print_rta_gateway(fp, r, tb[RTA_GATEWAY]);
+				if (tb[RTA_VIA])
+					print_rta_via(fp, tb[RTA_VIA]);
 				if (tb[RTA_FLOW])
 					print_rta_flow(fp, tb[RTA_FLOW]);
 			}
-- 
2.15.1

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

* [RFC iproute2-next 08/16] iproute: refactor multipath print
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (6 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 07/16] iproute2: refactor newdst, gateway and via printing Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 09/16] iproute: refactor printing of interface Stephen Hemminger
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

Make printing of multipath attributes a function to improve
readability.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/iproute.c | 116 ++++++++++++++++++++++++++++++++---------------------------
 1 file changed, 63 insertions(+), 53 deletions(-)

diff --git a/ip/iproute.c b/ip/iproute.c
index 3f8238b7f457..b2eea4be9c37 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -544,6 +544,67 @@ static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
 	}
 }
 
+static void print_rta_multipath(FILE *fp, const struct rtmsg *r,
+				struct rtattr *rta)
+{
+	const struct rtnexthop *nh = RTA_DATA(rta);
+	int len = RTA_PAYLOAD(rta);
+	int first = 1;
+
+	while (len > sizeof(*nh)) {
+		struct rtattr *tb[RTA_MAX + 1];
+
+		if (nh->rtnh_len > len)
+			break;
+
+		if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
+			if (first) {
+				fprintf(fp, "Oifs: ");
+				first = 0;
+			} else {
+				fprintf(fp, " ");
+			}
+		} else
+			fprintf(fp, "%s\tnexthop ", _SL_);
+
+		if (nh->rtnh_len > sizeof(*nh)) {
+			parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh),
+				     nh->rtnh_len - sizeof(*nh));
+
+			if (tb[RTA_ENCAP])
+				lwt_print_encap(fp,
+						tb[RTA_ENCAP_TYPE],
+						tb[RTA_ENCAP]);
+			if (tb[RTA_NEWDST])
+				print_rta_newdst(fp, r, tb[RTA_NEWDST]);
+			if (tb[RTA_GATEWAY])
+				print_rta_gateway(fp, r, tb[RTA_GATEWAY]);
+			if (tb[RTA_VIA])
+				print_rta_via(fp, tb[RTA_VIA]);
+			if (tb[RTA_FLOW])
+				print_rta_flow(fp, tb[RTA_FLOW]);
+		}
+
+		if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
+			fprintf(fp, "%s", ll_index_to_name(nh->rtnh_ifindex));
+			if (nh->rtnh_hops != 1)
+				fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
+			fprintf(fp, " ");
+		} else {
+			fprintf(fp, "dev %s ",
+				ll_index_to_name(nh->rtnh_ifindex));
+			if (r->rtm_family != AF_MPLS)
+				fprintf(fp, "weight %d ",
+					nh->rtnh_hops+1);
+		}
+
+		print_rt_flags(fp, nh->rtnh_flags);
+
+		len -= NLMSG_ALIGN(nh->rtnh_len);
+		nh = RTNH_NEXT(nh);
+	}
+}
+
 int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE *)arg;
@@ -709,60 +770,9 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		fprintf(fp, "iif %s ",
 			ll_index_to_name(rta_getattr_u32(tb[RTA_IIF])));
 	}
-	if (tb[RTA_MULTIPATH]) {
-		struct rtnexthop *nh = RTA_DATA(tb[RTA_MULTIPATH]);
-		int first = 1;
-
-		len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
 
-		for (;;) {
-			if (len < sizeof(*nh))
-				break;
-			if (nh->rtnh_len > len)
-				break;
-			if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
-				if (first) {
-					fprintf(fp, "Oifs: ");
-					first = 0;
-				} else {
-					fprintf(fp, " ");
-				}
-			} else
-				fprintf(fp, "%s\tnexthop ", _SL_);
-			if (nh->rtnh_len > sizeof(*nh)) {
-				parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh), nh->rtnh_len - sizeof(*nh));
-
-				if (tb[RTA_ENCAP])
-					lwt_print_encap(fp,
-							tb[RTA_ENCAP_TYPE],
-							tb[RTA_ENCAP]);
-				if (tb[RTA_NEWDST])
-					print_rta_newdst(fp, r, tb[RTA_NEWDST]);
-				if (tb[RTA_GATEWAY])
-					print_rta_gateway(fp, r, tb[RTA_GATEWAY]);
-				if (tb[RTA_VIA])
-					print_rta_via(fp, tb[RTA_VIA]);
-				if (tb[RTA_FLOW])
-					print_rta_flow(fp, tb[RTA_FLOW]);
-			}
-			if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
-				fprintf(fp, "%s", ll_index_to_name(nh->rtnh_ifindex));
-				if (nh->rtnh_hops != 1)
-					fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
-				fprintf(fp, " ");
-			} else {
-				fprintf(fp, "dev %s ", ll_index_to_name(nh->rtnh_ifindex));
-				if (r->rtm_family != AF_MPLS)
-					fprintf(fp, "weight %d ",
-						nh->rtnh_hops+1);
-			}
-
-			print_rt_flags(fp, nh->rtnh_flags);
-
-			len -= NLMSG_ALIGN(nh->rtnh_len);
-			nh = RTNH_NEXT(nh);
-		}
-	}
+	if (tb[RTA_MULTIPATH])
+		print_rta_multipath(fp, r, tb[RTA_MULTIPATH]);
 
 	if (tb[RTA_PREF])
 		print_rt_pref(fp, rta_getattr_u8(tb[RTA_PREF]));
-- 
2.15.1

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

* [RFC iproute2-next 09/16] iproute: refactor printing of interface
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (7 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 08/16] iproute: refactor multipath print Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 10/16] iproute: whitespace fixes Stephen Hemminger
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

For JSON and colorization, make common code a function.

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

diff --git a/ip/iproute.c b/ip/iproute.c
index b2eea4be9c37..a9842cfc8205 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -383,6 +383,14 @@ static void print_rt_pref(FILE *fp, unsigned int pref)
 	}
 }
 
+static void print_rta_if(FILE *fp, const struct rtattr *rta,
+			 const char *prefix)
+{
+	const char *ifname = ll_index_to_name(rta_getattr_u32(rta));
+
+	fprintf(fp, "%s %s ", prefix, ifname);
+}
+
 static void print_ipv4_flags(FILE *fp, __u32 flags)
 {
 	int first = 1;
@@ -709,7 +717,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		print_rta_via(fp, tb[RTA_VIA]);
 
 	if (tb[RTA_OIF] && filter.oifmask != -1)
-		fprintf(fp, "dev %s ", ll_index_to_name(rta_getattr_u32(tb[RTA_OIF])));
+		print_rta_if(fp,  tb[RTA_OIF], "dev");
 
 	if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
 		fprintf(fp, "table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
@@ -766,10 +774,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	if (tb[RTA_METRICS])
 		print_rta_metrics(fp, tb[RTA_METRICS]);
 
-	if (tb[RTA_IIF] && filter.iifmask != -1) {
-		fprintf(fp, "iif %s ",
-			ll_index_to_name(rta_getattr_u32(tb[RTA_IIF])));
-	}
+	if (tb[RTA_IIF] && filter.iifmask != -1)
+		print_rta_if(fp, tb[RTA_IIF], "iif");
 
 	if (tb[RTA_MULTIPATH])
 		print_rta_multipath(fp, r, tb[RTA_MULTIPATH]);
-- 
2.15.1

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

* [RFC iproute2-next 10/16] iproute: whitespace fixes
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (8 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 09/16] iproute: refactor printing of interface Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 11/16] iproute: don't do assignment in condition Stephen Hemminger
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

Add whitespace arount operators for consistency.

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

diff --git a/ip/iproute.c b/ip/iproute.c
index a9842cfc8205..b466f9eb8cad 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -163,7 +163,7 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 	if (r->rtm_family == AF_INET6 && table != RT_TABLE_MAIN)
 		ip6_multiple_tables = 1;
 
-	if (filter.cloned == !(r->rtm_flags&RTM_F_CLONED))
+	if (filter.cloned == !(r->rtm_flags & RTM_F_CLONED))
 		return 0;
 
 	if (r->rtm_family == AF_INET6 && !ip6_multiple_tables) {
@@ -565,7 +565,8 @@ static void print_rta_multipath(FILE *fp, const struct rtmsg *r,
 		if (nh->rtnh_len > len)
 			break;
 
-		if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
+		if ((r->rtm_flags & RTM_F_CLONED) &&
+		    r->rtm_type == RTN_MULTICAST) {
 			if (first) {
 				fprintf(fp, "Oifs: ");
 				first = 0;
@@ -593,7 +594,8 @@ static void print_rta_multipath(FILE *fp, const struct rtmsg *r,
 				print_rta_flow(fp, tb[RTA_FLOW]);
 		}
 
-		if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
+		if ((r->rtm_flags & RTM_F_CLONED) &&
+		    r->rtm_type == RTN_MULTICAST) {
 			fprintf(fp, "%s", ll_index_to_name(nh->rtnh_ifindex));
 			if (nh->rtnh_hops != 1)
 				fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
@@ -675,7 +677,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		if (r->rtm_dst_len != host_len) {
 			fprintf(fp, "%s/%u ",
 				rt_addr_n2a_rta(family, tb[RTA_DST]),
-			        r->rtm_dst_len);
+				r->rtm_dst_len);
 		} else {
 			fprintf(fp, "%s ",
 				format_host_rta(family, tb[RTA_DST]));
@@ -690,7 +692,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		if (r->rtm_src_len != host_len) {
 			fprintf(fp, "from %s/%u ",
 				rt_addr_n2a_rta(family, tb[RTA_SRC]),
-			        r->rtm_src_len);
+				r->rtm_src_len);
 		} else {
 			fprintf(fp, "from %s ",
 				format_host_rta(family, tb[RTA_SRC]));
@@ -721,7 +723,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 
 	if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
 		fprintf(fp, "table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
-	if (!(r->rtm_flags&RTM_F_CLONED)) {
+	if (!(r->rtm_flags & RTM_F_CLONED)) {
 		if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1)
 			fprintf(fp, "proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
 		if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1)
@@ -763,7 +765,6 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 			print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
 
 	} else if (r->rtm_family == AF_INET6) {
-
 		if (r->rtm_flags & RTM_F_CLONED)
 			fprintf(fp, "%s    cache ", _SL_);
 
@@ -1576,8 +1577,8 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
 				invarg("invalid mark value", *argv);
 			filter.markmask = -1;
 		} else if (matches(*argv, "metric") == 0 ||
-		           matches(*argv, "priority") == 0 ||
-		           strcmp(*argv, "preference") == 0) {
+			   matches(*argv, "priority") == 0 ||
+			   strcmp(*argv, "preference") == 0) {
 			__u32 metric;
 
 			NEXT_ARG();
@@ -2116,6 +2117,8 @@ int do_iproute(int argc, char **argv)
 		return iproute_showdump();
 	if (matches(*argv, "help") == 0)
 		usage();
-	fprintf(stderr, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv);
+
+	fprintf(stderr,
+		"Command \"%s\" is unknown, try \"ip route help\".\n", *argv);
 	exit(-1);
 }
-- 
2.15.1

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

* [RFC iproute2-next 11/16] iproute: don't do assignment in condition
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (9 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 10/16] iproute: whitespace fixes Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 12/16] iproute: make flush a separate function Stephen Hemminger
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

Fix checkpatch complaints about assignment in conditions.

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

diff --git a/ip/iproute.c b/ip/iproute.c
index b466f9eb8cad..55b2f51e3987 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -652,7 +652,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		struct nlmsghdr *fn;
 
 		if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
-			if ((ret = flush_update()) < 0)
+			ret = flush_update();
+			if (ret < 0)
 				return ret;
 		}
 		fn = (struct nlmsghdr *)(filter.flushb + NLMSG_ALIGN(filter.flushp));
@@ -826,7 +827,8 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
 			}
 		} else if (strcmp(*argv, "dev") == 0) {
 			NEXT_ARG();
-			if ((rtnh->rtnh_ifindex = ll_name_to_index(*argv)) == 0) {
+			rtnh->rtnh_ifindex = ll_name_to_index(*argv);
+			if (rtnh->rtnh_ifindex == 0) {
 				fprintf(stderr, "Cannot find device \"%s\"\n", *argv);
 				return -1;
 			}
@@ -1325,9 +1327,9 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
 		usage();
 
 	if (d) {
-		int idx;
+		int idx = ll_name_to_index(d);
 
-		if ((idx = ll_name_to_index(d)) == 0) {
+		if (idx == 0) {
 			fprintf(stderr, "Cannot find device \"%s\"\n", d);
 			return -1;
 		}
@@ -1657,7 +1659,8 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
 		int idx;
 
 		if (id) {
-			if ((idx = ll_name_to_index(id)) == 0) {
+			idx = ll_name_to_index(id);
+			if (idx == 0) {
 				fprintf(stderr, "Cannot find device \"%s\"\n", id);
 				return -1;
 			}
@@ -1665,7 +1668,8 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
 			filter.iifmask = -1;
 		}
 		if (od) {
-			if ((idx = ll_name_to_index(od)) == 0) {
+			idx = ll_name_to_index(od);
+			if (idx == 0) {
 				fprintf(stderr, "Cannot find device \"%s\"\n", od);
 				return -1;
 			}
@@ -1715,7 +1719,8 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
 				return 0;
 			}
 			round++;
-			if ((ret = flush_update()) < 0)
+			ret = flush_update();
+			if (ret < 0)
 				return ret;
 
 			if (time(0) - start > 30) {
@@ -1866,14 +1871,16 @@ static int iproute_get(int argc, char **argv)
 		int idx;
 
 		if (idev) {
-			if ((idx = ll_name_to_index(idev)) == 0) {
+			idx = ll_name_to_index(idev);
+			if (idx == 0) {
 				fprintf(stderr, "Cannot find device \"%s\"\n", idev);
 				return -1;
 			}
 			addattr32(&req.n, sizeof(req), RTA_IIF, idx);
 		}
 		if (odev) {
-			if ((idx = ll_name_to_index(odev)) == 0) {
+			idx = ll_name_to_index(odev);
+			if (idx == 0) {
 				fprintf(stderr, "Cannot find device \"%s\"\n", odev);
 				return -1;
 			}
-- 
2.15.1

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

* [RFC iproute2-next 12/16] iproute: make flush a separate function
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (10 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 11/16] iproute: don't do assignment in condition Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 13/16] iproute: implement JSON and color output Stephen Hemminger
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

Minor refactoring to make function size smaller and reduce
depth of nesting.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/iproute.c | 121 +++++++++++++++++++++++++++++++----------------------------
 1 file changed, 64 insertions(+), 57 deletions(-)

diff --git a/ip/iproute.c b/ip/iproute.c
index 55b2f51e3987..650e3e8b00ee 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -1472,6 +1472,68 @@ static int save_route_prep(void)
 	return 0;
 }
 
+static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
+{
+	time_t start = time(0);
+	char flushb[4096-512];
+	int round = 0;
+	int ret;
+
+	if (filter.cloned) {
+		if (do_ipv6 != AF_INET6) {
+			iproute_flush_cache();
+			if (show_stats)
+				printf("*** IPv4 routing cache is flushed.\n");
+		}
+		if (do_ipv6 == AF_INET)
+			return 0;
+	}
+
+	filter.flushb = flushb;
+	filter.flushp = 0;
+	filter.flushe = sizeof(flushb);
+
+	for (;;) {
+		if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
+			perror("Cannot send dump request");
+			return -2;
+		}
+		filter.flushed = 0;
+		if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
+			fprintf(stderr, "Flush terminated\n");
+			return -2;
+		}
+		if (filter.flushed == 0) {
+			if (show_stats) {
+				if (round == 0 &&
+				    (!filter.cloned || do_ipv6 == AF_INET6))
+					printf("Nothing to flush.\n");
+				else
+					printf("*** Flush is complete after %d round%s ***\n",
+					       round, round > 1 ? "s" : "");
+			}
+			fflush(stdout);
+			return 0;
+		}
+		round++;
+		ret = flush_update();
+		if (ret < 0)
+			return ret;
+
+		if (time(0) - start > 30) {
+			printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
+			       (long)(time(0) - start), filter.flushed);
+			return -1;
+		}
+
+		if (show_stats) {
+			printf("\n*** Round %d, deleting %d entries ***\n",
+			       round, filter.flushed);
+			fflush(stdout);
+		}
+	}
+}
+
 static int iproute_list_flush_or_save(int argc, char **argv, int action)
 {
 	int do_ipv6 = preferred_family;
@@ -1479,7 +1541,6 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
 	char *od = NULL;
 	unsigned int mark = 0;
 	rtnl_filter_t filter_fn;
-	int ret;
 
 	if (action == IPROUTE_SAVE) {
 		if (save_route_prep())
@@ -1679,62 +1740,8 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
 	}
 	filter.mark = mark;
 
-	if (action == IPROUTE_FLUSH) {
-		int round = 0;
-		char flushb[4096-512];
-		time_t start = time(0);
-
-		if (filter.cloned) {
-			if (do_ipv6 != AF_INET6) {
-				iproute_flush_cache();
-				if (show_stats)
-					printf("*** IPv4 routing cache is flushed.\n");
-			}
-			if (do_ipv6 == AF_INET)
-				return 0;
-		}
-
-		filter.flushb = flushb;
-		filter.flushp = 0;
-		filter.flushe = sizeof(flushb);
-
-		for (;;) {
-			if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
-				perror("Cannot send dump request");
-				return -2;
-			}
-			filter.flushed = 0;
-			if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
-				fprintf(stderr, "Flush terminated\n");
-				return -2;
-			}
-			if (filter.flushed == 0) {
-				if (show_stats) {
-					if (round == 0 && (!filter.cloned || do_ipv6 == AF_INET6))
-						printf("Nothing to flush.\n");
-					else
-						printf("*** Flush is complete after %d round%s ***\n", round, round > 1?"s":"");
-				}
-				fflush(stdout);
-				return 0;
-			}
-			round++;
-			ret = flush_update();
-			if (ret < 0)
-				return ret;
-
-			if (time(0) - start > 30) {
-				printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
-				       (long)(time(0) - start), filter.flushed);
-				return -1;
-			}
-
-			if (show_stats) {
-				printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed);
-				fflush(stdout);
-			}
-		}
-	}
+	if (action == IPROUTE_FLUSH)
+		return iproute_flush(do_ipv6, filter_fn);
 
 	if (!filter.cloned) {
 		if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
-- 
2.15.1

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

* [RFC iproute2-next 13/16] iproute: implement JSON and color output
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (11 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 12/16] iproute: make flush a separate function Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 14/16] json: make pretty printing optional Stephen Hemminger
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

Add JSON and color output formatting to ip route command.
Similar to existing address and link output.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 include/utils.h |   5 +
 ip/iproute.c    | 367 +++++++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 259 insertions(+), 113 deletions(-)

diff --git a/include/utils.h b/include/utils.h
index 0394268e1276..27ba37c5cd2f 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -23,6 +23,7 @@ extern int resolve_hosts;
 extern int oneline;
 extern int brief;
 extern int json;
+extern int pretty;
 extern int timestamp;
 extern int timestamp_short;
 extern const char * _SL_;
@@ -155,6 +156,10 @@ int af_byte_len(int af);
 
 const char *format_host_r(int af, int len, const void *addr,
 			       char *buf, int buflen);
+#define format_host_rta_r(af, rta, buf, buflen)	\
+	format_host_r(af, RTA_PAYLOAD(rta), RTA_DATA(rta), \
+		      buf, buflen)
+
 const char *format_host(int af, int lne, const void *addr);
 #define format_host_rta(af, rta) \
 	format_host(af, RTA_PAYLOAD(rta), RTA_DATA(rta))
diff --git a/ip/iproute.c b/ip/iproute.c
index 650e3e8b00ee..79950522c2b3 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -340,71 +340,91 @@ static void print_rtax_features(FILE *fp, unsigned int features)
 	unsigned int of = features;
 
 	if (features & RTAX_FEATURE_ECN) {
-		fprintf(fp, "ecn ");
+		print_null(PRINT_ANY, "ecn", "ecn ", NULL);
 		features &= ~RTAX_FEATURE_ECN;
 	}
 
 	if (features)
-		fprintf(fp, "0x%x ", of);
+		print_0xhex(PRINT_ANY,
+			    "features", "0x%x ", of);
 }
 
 static void print_rt_flags(FILE *fp, unsigned int flags)
 {
+	open_json_array(PRINT_JSON,
+			is_json_context() ?  "flags" : "");
+
 	if (flags & RTNH_F_DEAD)
-		fprintf(fp, "dead ");
+		print_string(PRINT_ANY, NULL, "%s ", "dead");
 	if (flags & RTNH_F_ONLINK)
-		fprintf(fp, "onlink ");
+		print_string(PRINT_ANY, NULL, "%s ", "onlink");
 	if (flags & RTNH_F_PERVASIVE)
-		fprintf(fp, "pervasive ");
+		print_string(PRINT_ANY, NULL, "%s ", "pervasive");
 	if (flags & RTNH_F_OFFLOAD)
-		fprintf(fp, "offload ");
+		print_string(PRINT_ANY, NULL, "%s ", "offload");
+	if (flags & RTM_F_NOTIFY)
+		print_string(PRINT_ANY, NULL, "%s ", "notify");
 	if (flags & RTNH_F_LINKDOWN)
-		fprintf(fp, "linkdown ");
+		print_string(PRINT_ANY, NULL, "%s ", "linkdown");
 	if (flags & RTNH_F_UNRESOLVED)
-		fprintf(fp, "unresolved ");
+		print_string(PRINT_ANY, NULL, "%s ", "unresolved");
+
+	close_json_array(PRINT_JSON, NULL);
 }
 
 static void print_rt_pref(FILE *fp, unsigned int pref)
 {
-	fprintf(fp, "pref ");
 
 	switch (pref) {
 	case ICMPV6_ROUTER_PREF_LOW:
-		fprintf(fp, "low");
+		print_string(PRINT_ANY,
+			     "pref", "pref %s", "low");
 		break;
 	case ICMPV6_ROUTER_PREF_MEDIUM:
-		fprintf(fp, "medium");
+		print_string(PRINT_ANY,
+			     "pref", "pref %s", "medium");
 		break;
 	case ICMPV6_ROUTER_PREF_HIGH:
-		fprintf(fp, "high");
+		print_string(PRINT_ANY,
+			     "pref", "pref %s", "high");
 		break;
 	default:
-		fprintf(fp, "%u", pref);
+		print_uint(PRINT_ANY,
+			   "pref", "%u", pref);
 	}
 }
 
 static void print_rta_if(FILE *fp, const struct rtattr *rta,
-			 const char *prefix)
+			const char *prefix)
 {
 	const char *ifname = ll_index_to_name(rta_getattr_u32(rta));
 
-	fprintf(fp, "%s %s ", prefix, ifname);
+	if (is_json_context())
+		print_string(PRINT_JSON, prefix, NULL, ifname);
+	else {
+		fprintf(fp, "%s ", prefix);
+		color_fprintf(fp, COLOR_IFNAME, "%s ", ifname);
+	}
 }
 
 static void print_ipv4_flags(FILE *fp, __u32 flags)
 {
-	int first = 1;
-
 	flags &= ~0xFFFF;
 
-	fprintf(fp, "%s    cache ", _SL_);
+	if (is_json_context())
+		open_json_array(PRINT_JSON, "cache");
+	else {
+		fprintf(fp, "%s    cache ", _SL_);
+		if (flags == 0)
+			return;
+		fprintf(fp, "<");
+	}
 
 #define PRTFL(fl, flname)					\
 	if (flags&RTCF_##fl) {					\
 		flags &= ~RTCF_##fl;				\
-		fprintf(fp, "%s" flname "%s",			\
-			first ? "<" : "", flags ? "," : "> ");	\
-		first = 0; }
+		print_string(PRINT_ANY, NULL, "%s ", flname);	\
+	}							\
 
 	PRTFL(LOCAL, "local");
 	PRTFL(REJECT, "reject");
@@ -423,7 +443,8 @@ static void print_ipv4_flags(FILE *fp, __u32 flags)
 #undef PRTFL
 
 	if (flags)
-		fprintf(fp, "%s%x> ", first ? "<" : "", flags);
+		print_hex(PRINT_ANY, "flags", "%x", flags);
+	close_json_array(PRINT_ANY, "> ");
 }
 
 static void print_rta_cacheinfo(FILE *fp, const struct rta_cacheinfo *ci)
@@ -432,23 +453,34 @@ static void print_rta_cacheinfo(FILE *fp, const struct rta_cacheinfo *ci)
 
 	if (!hz)
 		hz = get_user_hz();
+
 	if (ci->rta_expires != 0)
-		fprintf(fp, "expires %dsec ", ci->rta_expires/hz);
+		print_uint(PRINT_ANY, "expires",
+			   "expires %usec ", ci->rta_expires/hz);
 	if (ci->rta_error != 0)
-		fprintf(fp, "error %d ", ci->rta_error);
+		print_uint(PRINT_ANY, "error",
+			   "error %u ", ci->rta_error);
+
 	if (show_stats) {
 		if (ci->rta_clntref)
-			fprintf(fp, "users %d ", ci->rta_clntref);
+			print_uint(PRINT_ANY, "users",
+				   "users %u ", ci->rta_clntref);
 		if (ci->rta_used != 0)
-			fprintf(fp, "used %d ", ci->rta_used);
+			print_uint(PRINT_ANY, "used",
+				   "used %u ", ci->rta_used);
 		if (ci->rta_lastuse != 0)
-			fprintf(fp, "age %dsec ", ci->rta_lastuse/hz);
+			print_uint(PRINT_ANY, "age",
+				   "age %usec ", ci->rta_lastuse/hz);
 	}
 	if (ci->rta_id)
-		fprintf(fp, "ipid 0x%04x ", ci->rta_id);
-	if (ci->rta_ts || ci->rta_tsage)
-		fprintf(fp, "ts 0x%x tsage %dsec ",
-			ci->rta_ts, ci->rta_tsage);
+		print_0xhex(PRINT_ANY, "ipid",
+			    "ipid 0x%04x ", ci->rta_id);
+	if (ci->rta_ts || ci->rta_tsage) {
+		print_0xhex(PRINT_ANY, "ts",
+			    "ts 0x%x", ci->rta_ts);
+		print_uint(PRINT_ANY, "tsage",
+			   "tsage %usec ", ci->rta_tsage);
+	}
 }
 
 static void print_rta_flow(FILE *fp, const struct rtattr *rta)
@@ -458,13 +490,24 @@ static void print_rta_flow(FILE *fp, const struct rtattr *rta)
 	SPRINT_BUF(b1);
 
 	to &= 0xFFFF;
-	fprintf(fp, "realm%s ", from ? "s" : "");
-	if (from) {
-		fprintf(fp, "%s/",
-			rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+	if (is_json_context()) {
+		open_json_object("flow");
+
+		if (from)
+			print_string(PRINT_JSON, "from", NULL,
+				     rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+		print_string(PRINT_JSON, "to", NULL,
+			     rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
+		close_json_object();
+	} else {
+		fprintf(fp, "realm%s ", from ? "s" : "");
+
+		if (from)
+			print_string(PRINT_FP, NULL, "%s/",
+				     rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+		print_string(PRINT_FP, NULL, "%s ",
+			     rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
 	}
-	fprintf(fp, "%s ",
-		rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
 }
 
 static void print_rta_newdst(FILE *fp, const struct rtmsg *r,
@@ -472,7 +515,14 @@ static void print_rta_newdst(FILE *fp, const struct rtmsg *r,
 {
 	const char *newdst = format_host_rta(r->rtm_family, rta);
 
-	fprintf(fp, "as to %s ", newdst);
+	if (is_json_context())
+		print_string(PRINT_JSON, "to", NULL, newdst);
+	else {
+		fprintf(fp, "as to ");
+		print_color_string(PRINT_FP,
+				   ifa_family_color(r->rtm_family),
+				   NULL, "%s ", newdst);
+	}
 }
 
 static void print_rta_gateway(FILE *fp, const struct rtmsg *r,
@@ -480,17 +530,38 @@ static void print_rta_gateway(FILE *fp, const struct rtmsg *r,
 {
 	const char *gateway = format_host_rta(r->rtm_family, rta);
 
-	fprintf(fp, "via %s ", gateway);
+	if (is_json_context())
+		print_string(PRINT_JSON, "gateway", NULL, gateway);
+	else {
+		fprintf(fp, "via ");
+		print_color_string(PRINT_FP,
+				   ifa_family_color(r->rtm_family),
+				   NULL, "%s ", gateway);
+	}
 }
 
 static void print_rta_via(FILE *fp, const struct rtattr *rta)
 {
+	size_t len = RTA_PAYLOAD(rta) - 2;
 	const struct rtvia *via = RTA_DATA(rta);
-	size_t len = RTA_PAYLOAD(rta);
 
-	fprintf(fp, "via %s %s ",
-		family_name(via->rtvia_family),
-		format_host(via->rtvia_family, len, via->rtvia_addr));
+	if (is_json_context()) {
+		open_json_object("via");
+		print_string(PRINT_JSON, "family", NULL,
+			     family_name(via->rtvia_family));
+		print_string(PRINT_JSON, "host", NULL,
+			     format_host(via->rtvia_family, len,
+					 via->rtvia_addr));
+		close_json_object();
+	} else {
+		print_string(PRINT_FP, NULL, "via %s ",
+			     family_name(via->rtvia_family));
+		print_color_string(PRINT_FP,
+				   ifa_family_color(via->rtvia_family),
+				   NULL, "%s ",
+				   format_host(via->rtvia_family,
+					       len, via->rtvia_addr));
+	}
 }
 
 static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
@@ -499,6 +570,8 @@ static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
 	unsigned int mxlock = 0;
 	int i;
 
+	open_json_array(PRINT_JSON, "metrics");
+
 	parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta));
 
 	if (mxrta[RTAX_LOCK])
@@ -516,13 +589,15 @@ static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
 		if (i == RTAX_HOPLIMIT && (int)val == -1)
 			continue;
 
-		if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i])
-			fprintf(fp, "%s ", mx_names[i]);
-		else
-			fprintf(fp, "metric %d ", i);
+		if (!is_json_context()) {
+			if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i])
+				fprintf(fp, "%s ", mx_names[i]);
+			else
+				fprintf(fp, "metric %d ", i);
 
-		if (mxlock & (1<<i))
-			fprintf(fp, "lock ");
+			if (mxlock & (1<<i))
+				fprintf(fp, "lock ");
+		}
 
 		switch (i) {
 		case RTAX_FEATURES:
@@ -540,16 +615,24 @@ static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
 			else if (i == RTAX_RTTVAR)
 				val /= 4;
 
-			if (val >= 1000)
-				fprintf(fp, "%gs ", val/1e3);
-			else
-				fprintf(fp, "%ums ", val);
+			if (is_json_context())
+				print_uint(PRINT_JSON, mx_names[i],
+					   NULL, val);
+			else {
+				if (val >= 1000)
+					fprintf(fp, "%gs ", val/1e3);
+				else
+					fprintf(fp, "%ums ", val);
+			}
 			break;
 		case RTAX_CC_ALGO:
-			fprintf(fp, "%s ", rta_getattr_str(mxrta[i]));
+			print_string(PRINT_ANY, "congestion",
+				     "%s ", rta_getattr_str(mxrta[i]));
 			break;
 		}
 	}
+
+	close_json_array(PRINT_JSON, NULL);
 }
 
 static void print_rta_multipath(FILE *fp, const struct rtmsg *r,
@@ -565,16 +648,18 @@ static void print_rta_multipath(FILE *fp, const struct rtmsg *r,
 		if (nh->rtnh_len > len)
 			break;
 
-		if ((r->rtm_flags & RTM_F_CLONED) &&
-		    r->rtm_type == RTN_MULTICAST) {
-			if (first) {
-				fprintf(fp, "Oifs: ");
-				first = 0;
-			} else {
-				fprintf(fp, " ");
-			}
-		} else
-			fprintf(fp, "%s\tnexthop ", _SL_);
+		if (!is_json_context()) {
+			if ((r->rtm_flags & RTM_F_CLONED) &&
+			    r->rtm_type == RTN_MULTICAST) {
+				if (first) {
+					fprintf(fp, "Oifs: ");
+					first = 0;
+				} else {
+					fprintf(fp, " ");
+				}
+			} else
+				fprintf(fp, "%s\tnexthop ", _SL_);
+		}
 
 		if (nh->rtnh_len > sizeof(*nh)) {
 			parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh),
@@ -601,8 +686,7 @@ static void print_rta_multipath(FILE *fp, const struct rtmsg *r,
 				fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
 			fprintf(fp, " ");
 		} else {
-			fprintf(fp, "dev %s ",
-				ll_index_to_name(nh->rtnh_ifindex));
+			fprintf(fp, "dev %s ", ll_index_to_name(nh->rtnh_ifindex));
 			if (r->rtm_family != AF_MPLS)
 				fprintf(fp, "weight %d ",
 					nh->rtnh_hops+1);
@@ -621,7 +705,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	struct rtmsg *r = NLMSG_DATA(n);
 	int len = n->nlmsg_len;
 	struct rtattr *tb[RTA_MAX+1];
-	int host_len, family;
+	int family, color, host_len;
 	__u32 table;
 	int ret;
 
@@ -667,39 +751,56 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 			return 0;
 	}
 
+	open_json_object(NULL);
 	if (n->nlmsg_type == RTM_DELROUTE)
-		fprintf(fp, "Deleted ");
+		print_bool(PRINT_ANY, "deleted", "Deleted ", true);
+
 	if ((r->rtm_type != RTN_UNICAST || show_details > 0) &&
 	    (!filter.typemask || (filter.typemask & (1 << r->rtm_type))))
-		fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
+		print_string(PRINT_ANY, NULL, "%s ",
+			     rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
 
+	color = COLOR_NONE;
 	if (tb[RTA_DST]) {
 		family = get_real_family(r->rtm_type, r->rtm_family);
+		color = ifa_family_color(family);
+
 		if (r->rtm_dst_len != host_len) {
-			fprintf(fp, "%s/%u ",
-				rt_addr_n2a_rta(family, tb[RTA_DST]),
-				r->rtm_dst_len);
+			snprintf(b1, sizeof(b1),
+				 "%s/%u", rt_addr_n2a_rta(family, tb[RTA_DST]),
+				 r->rtm_dst_len);
 		} else {
-			fprintf(fp, "%s ",
-				format_host_rta(family, tb[RTA_DST]));
+			format_host_rta_r(family, tb[RTA_DST],
+					  b1, sizeof(b1));
+
 		}
 	} else if (r->rtm_dst_len) {
-		fprintf(fp, "0/%d ", r->rtm_dst_len);
+		snprintf(b1, sizeof(b1), "0/%d ", r->rtm_dst_len);
 	} else {
-		fprintf(fp, "default ");
+		strncpy(b1, "default", sizeof(b1));
 	}
+	print_color_string(PRINT_ANY, color,
+			   "dst", "%s ", b1);
+
 	if (tb[RTA_SRC]) {
 		family = get_real_family(r->rtm_type, r->rtm_family);
+		color = ifa_family_color(family);
+
 		if (r->rtm_src_len != host_len) {
-			fprintf(fp, "from %s/%u ",
-				rt_addr_n2a_rta(family, tb[RTA_SRC]),
-				r->rtm_src_len);
+			snprintf(b1, sizeof(b1),
+				 "%s/%u",
+				 rt_addr_n2a_rta(family, tb[RTA_SRC]),
+				 r->rtm_src_len);
 		} else {
-			fprintf(fp, "from %s ",
-				format_host_rta(family, tb[RTA_SRC]));
+			format_host_rta_r(family, tb[RTA_SRC],
+					  b1, sizeof(b1));
 		}
+		print_color_string(PRINT_ANY, color,
+				   "from", "from %s ", b1);
 	} else if (r->rtm_src_len) {
-		fprintf(fp, "from 0/%u ", r->rtm_src_len);
+		snprintf(b1, sizeof(b1), "0/%u", r->rtm_src_len);
+
+		print_string(PRINT_ANY, "src", "from %s ", b1);
 	}
 
 	if (tb[RTA_NEWDST])
@@ -709,8 +810,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		lwt_print_encap(fp, tb[RTA_ENCAP_TYPE], tb[RTA_ENCAP]);
 
 	if (r->rtm_tos && filter.tosmask != -1) {
-		SPRINT_BUF(b1);
-		fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
+		print_string(PRINT_ANY, "tos", "tos %s ",
+			     rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
 	}
 
 	if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len)
@@ -720,25 +821,50 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		print_rta_via(fp, tb[RTA_VIA]);
 
 	if (tb[RTA_OIF] && filter.oifmask != -1)
-		print_rta_if(fp,  tb[RTA_OIF], "dev");
+		print_rta_if(fp, tb[RTA_OIF], "dev");
 
 	if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
-		fprintf(fp, "table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
+		print_string(PRINT_ANY,
+			     "table", "table %s ",
+			     rtnl_rttable_n2a(table, b1, sizeof(b1)));
+
 	if (!(r->rtm_flags & RTM_F_CLONED)) {
-		if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1)
-			fprintf(fp, "proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
-		if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1)
-			fprintf(fp, "scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1)));
+		if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) &&
+		    filter.protocolmask != -1)
+			print_string(PRINT_ANY,
+				     "protocol", "proto %s ",
+				     rtnl_rtprot_n2a(r->rtm_protocol,
+						     b1, sizeof(b1)));
+
+		if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) &&
+		    filter.scopemask != -1)
+			print_string(PRINT_ANY,
+				     "scope", "scope %s ",
+				     rtnl_rtscope_n2a(r->rtm_scope,
+						      b1, sizeof(b1)));
 	}
+
 	if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
+		const char *psrc
+			= rt_addr_n2a_rta(r->rtm_family, tb[RTA_PREFSRC]);
+
 		/* Do not use format_host(). It is our local addr
 		   and symbolic name will not be useful.
-		 */
-		fprintf(fp, "src %s ",
-			rt_addr_n2a_rta(r->rtm_family, tb[RTA_PREFSRC]));
+		*/
+		if (is_json_context())
+			print_string(PRINT_JSON, "prefsrc", NULL, psrc);
+		else {
+			fprintf(fp, "src ");
+			print_color_string(PRINT_FP,
+					   ifa_family_color(r->rtm_family),
+					   NULL, "%s ", psrc);
+		}
+
 	}
+
 	if (tb[RTA_PRIORITY] && filter.metricmask != -1)
-		fprintf(fp, "metric %u ", rta_getattr_u32(tb[RTA_PRIORITY]));
+		print_uint(PRINT_ANY, "metric", "metric %u ",
+			   rta_getattr_u32(tb[RTA_PRIORITY]));
 
 	print_rt_flags(fp, r->rtm_flags);
 
@@ -746,10 +872,14 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		unsigned int mark = rta_getattr_u32(tb[RTA_MARK]);
 
 		if (mark) {
-			if (mark >= 16)
-				fprintf(fp, "mark 0x%x ", mark);
+			if (is_json_context())
+				print_uint(PRINT_JSON, "mark", NULL, mark);
+			else if (mark >= 16)
+				print_0xhex(PRINT_FP, NULL,
+					    "mark 0x%x ", mark);
 			else
-				fprintf(fp, "mark %u ", mark);
+				print_uint(PRINT_FP, NULL,
+					   "mark %u ", mark);
 		}
 	}
 
@@ -757,20 +887,21 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		print_rta_flow(fp, tb[RTA_FLOW]);
 
 	if (tb[RTA_UID])
-		fprintf(fp, "uid %u ", rta_getattr_u32(tb[RTA_UID]));
-
-	if ((r->rtm_flags & RTM_F_CLONED) && r->rtm_family == AF_INET) {
-		print_ipv4_flags(fp, r->rtm_flags);
+		print_uint(PRINT_ANY, "uid", "uid %u ",
+			   rta_getattr_u32(tb[RTA_UID]));
 
-		if (tb[RTA_CACHEINFO])
-			print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
+	if (r->rtm_family == AF_INET) {
+		if (r->rtm_flags & RTM_F_CLONED) {
+			print_ipv4_flags(fp, r->rtm_flags);
 
+			if (tb[RTA_CACHEINFO])
+				print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
+		}
 	} else if (r->rtm_family == AF_INET6) {
-		if (r->rtm_flags & RTM_F_CLONED)
-			fprintf(fp, "%s    cache ", _SL_);
-
-		if (tb[RTA_CACHEINFO])
-			print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
+		if (r->rtm_flags & RTM_F_CLONED) {
+			if (tb[RTA_CACHEINFO])
+				print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
+		}
 	}
 
 	if (tb[RTA_METRICS])
@@ -786,13 +917,19 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		print_rt_pref(fp, rta_getattr_u8(tb[RTA_PREF]));
 
 	if (tb[RTA_TTL_PROPAGATE]) {
-		fprintf(fp, "ttl-propagate ");
-		if (rta_getattr_u8(tb[RTA_TTL_PROPAGATE]))
-			fprintf(fp, "enabled");
+		bool propogate = rta_getattr_u8(tb[RTA_TTL_PROPAGATE]);
+
+		if (is_json_context())
+			print_bool(PRINT_JSON, "ttl-propogate", NULL,
+				   propogate);
 		else
-			fprintf(fp, "disabled");
+			print_string(PRINT_FP, NULL,
+				     "ttl-propogate %s",
+				     propogate ? "enabled" : "disabled");
 	}
-	fprintf(fp, "\n");
+
+	print_string(PRINT_FP, NULL, "\n", NULL);
+	close_json_object();
 	fflush(fp);
 	return 0;
 }
@@ -1755,11 +1892,15 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
 		}
 	}
 
+	new_json_obj(json);
+
 	if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
 		fprintf(stderr, "Dump terminated\n");
 		return -2;
 	}
 
+	delete_json_obj();
+	fflush(stdout);
 	return 0;
 }
 
-- 
2.15.1

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

* [RFC iproute2-next 14/16] json: make pretty printing optional
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (12 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 13/16] iproute: implement JSON and color output Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 15/16] man: add documentation for json and pretty flags Stephen Hemminger
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

Since JSON is intended for programmatic consumption, it makes
sense for the default output format to be concise as possible.

For programmer and other uses, it is helpful to keep the pretty
whitespace format; therefore enable it with -p flag.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 include/json_print.h | 2 ++
 include/utils.h      | 1 -
 ip/ip.c              | 3 +++
 lib/json_print.c     | 3 ++-
 tc/tc.c              | 3 +++
 5 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/include/json_print.h b/include/json_print.h
index 2ca7830adbd6..45a817ce6b9a 100644
--- a/include/json_print.h
+++ b/include/json_print.h
@@ -15,6 +15,8 @@
 #include "json_writer.h"
 #include "color.h"
 
+extern int show_pretty;
+
 json_writer_t *get_json_writer(void);
 
 /*
diff --git a/include/utils.h b/include/utils.h
index 27ba37c5cd2f..e35ea32c1d3b 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -23,7 +23,6 @@ extern int resolve_hosts;
 extern int oneline;
 extern int brief;
 extern int json;
-extern int pretty;
 extern int timestamp;
 extern int timestamp_short;
 extern const char * _SL_;
diff --git a/ip/ip.c b/ip/ip.c
index b15e6b66b3f6..a6611292808d 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -31,6 +31,7 @@ int show_stats;
 int show_details;
 int oneline;
 int brief;
+int show_pretty;
 int json;
 int timestamp;
 const char *_SL_;
@@ -259,6 +260,8 @@ int main(int argc, char **argv)
 			++brief;
 		} else if (matches(opt, "-json") == 0) {
 			++json;
+		} else if (matches(opt, "-pretty") == 0) {
+			++show_pretty;
 		} else if (matches(opt, "-rcvbuf") == 0) {
 			unsigned int size;
 
diff --git a/lib/json_print.c b/lib/json_print.c
index 6518ba98f5bf..e3da1bdfd5b0 100644
--- a/lib/json_print.c
+++ b/lib/json_print.c
@@ -28,7 +28,8 @@ void new_json_obj(int json)
 			perror("json object");
 			exit(1);
 		}
-		jsonw_pretty(_jw, true);
+		if (show_pretty)
+			jsonw_pretty(_jw, true);
 		jsonw_start_array(_jw);
 	}
 }
diff --git a/tc/tc.c b/tc/tc.c
index 63e64fece87d..aba5c101739c 100644
--- a/tc/tc.c
+++ b/tc/tc.c
@@ -42,6 +42,7 @@ int use_iec;
 int force;
 bool use_names;
 int json;
+int pretty;
 
 static char *conf_file;
 
@@ -484,6 +485,8 @@ int main(int argc, char **argv)
 			++timestamp_short;
 		} else if (matches(argv[1], "-json") == 0) {
 			++json;
+		} else if (matches(argv[1], "-pretty") == 0) {
+			++pretty;
 		} else {
 			fprintf(stderr, "Option \"%s\" is unknown, try \"tc -help\".\n", argv[1]);
 			return -1;
-- 
2.15.1

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

* [RFC iproute2-next 15/16] man: add documentation for json and pretty flags
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (13 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 14/16] json: make pretty printing optional Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  1:19 ` [RFC iproute2-next 16/16] json: fix newline at end of array Stephen Hemminger
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

New options were added without documentation or usage.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/ip.c       |  4 ++--
 man/man8/ip.8 | 18 ++++++++++++++----
 man/man8/tc.8 |  3 ++-
 3 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/ip/ip.c b/ip/ip.c
index a6611292808d..233a9d772492 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -54,12 +54,12 @@ static void usage(void)
 "                   netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila |\n"
 "                   vrf | sr }\n"
 "       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
-"                    -h[uman-readable] | -iec |\n"
+"                    -h[uman-readable] | -iec | -j[son] | -p[retty] |\n"
 "                    -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n"
 "                    -4 | -6 | -I | -D | -B | -0 |\n"
 "                    -l[oops] { maximum-addr-flush-attempts } | -br[ief] |\n"
 "                    -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n"
-"                    -rc[vbuf] [size] | -n[etns] name | -a[ll] | -c[olor]}\n");
+"                    -rc[vbuf] [size] | -n[etns] name | -a[ll] | -c[olor]}\n");
 	exit(-1);
 }
 
diff --git a/man/man8/ip.8 b/man/man8/ip.8
index 7f26582db795..0087d18b7470 100644
--- a/man/man8/ip.8
+++ b/man/man8/ip.8
@@ -48,9 +48,10 @@ ip \- show / manipulate routing, network devices, interfaces and tunnels
 \fB\-ts\fR[\fIhort\fR] |
 \fB\-n\fR[\fIetns\fR] name |
 \fB\-a\fR[\fIll\fR] |
-\fB\-c\fR[\fIolor\fR]
-\fB\-br\fR[\fIief\fR] }
-
+\fB\-c\fR[\fIolor\fR] |
+\fB\-br\fR[\fIief\fR] |
+\fB\-j\fR[son\fR] |
+\fB\-p\fR[retty\fR] }
 
 .SH OPTIONS
 
@@ -208,10 +209,19 @@ Set the netlink socket receive buffer size, defaults to 1MB.
 print human readable rates in IEC units (e.g. 1Ki = 1024).
 
 .TP
-.BR "\-br" , "\-brief"
+.BR "\-br" , " \-brief"
 Print only basic information in a tabular format for better readability. This option is currently only supported by
 .BR "ip addr show " and " ip link show " commands.
 
+.TP
+.BR "\-j", " \-json"
+Output results in JavaScript Object Notation (JSON).
+
+.TP
+.BR "\-p", " \-pretty"
+The default JSON format is compact and more efficient to parse but hard for most users to read.
+This flag adds indentation for readability.
+
 .SH IP - COMMAND SYNTAX
 
 .SS
diff --git a/man/man8/tc.8 b/man/man8/tc.8
index 5ffea373d18b..a58f46542340 100644
--- a/man/man8/tc.8
+++ b/man/man8/tc.8
@@ -670,7 +670,8 @@ output raw hex values for handles.
 
 .TP
 .BR "\-p", " \-pretty"
-decode filter offset and mask values to equivalent filter commands based on TCP/IP.
+for u32 filter, decode offset and mask values to equivalent filter commands based on TCP/IP.
+In JSON output, add whitespace to improve readability.
 
 .TP
 .BR "\-iec"
-- 
2.15.1

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

* [RFC iproute2-next 16/16] json: fix newline at end of array
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (14 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 15/16] man: add documentation for json and pretty flags Stephen Hemminger
@ 2018-02-02  1:19 ` Stephen Hemminger
  2018-02-02  2:59 ` [RFC iproute2-next 00/16] iproute printing enhancements David Ahern
  2018-02-02  3:08 ` David Ahern
  17 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02  1:19 UTC (permalink / raw)
  To: dsahern; +Cc: netdev, Stephen Hemminger, Stephen Hemminger

The json print library was toggling pretty print at the end of
an array to workaround a bug in underlying json_writer.
Instead, just fix json_writer to pretty print array correctly.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 lib/json_print.c  | 2 --
 lib/json_writer.c | 5 +++++
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/lib/json_print.c b/lib/json_print.c
index e3da1bdfd5b0..b507b14ba27f 100644
--- a/lib/json_print.c
+++ b/lib/json_print.c
@@ -89,9 +89,7 @@ void open_json_array(enum output_type type, const char *str)
 void close_json_array(enum output_type type, const char *str)
 {
 	if (_IS_JSON_CONTEXT(type)) {
-		jsonw_pretty(_jw, false);
 		jsonw_end_array(_jw);
-		jsonw_pretty(_jw, true);
 	} else if (_IS_FP_CONTEXT(type)) {
 		printf("%s", str);
 	}
diff --git a/lib/json_writer.c b/lib/json_writer.c
index f3eeaf7bc479..0d910dc068b5 100644
--- a/lib/json_writer.c
+++ b/lib/json_writer.c
@@ -180,10 +180,15 @@ void jsonw_end_object(json_writer_t *self)
 void jsonw_start_array(json_writer_t *self)
 {
 	jsonw_begin(self, '[');
+	if (self->pretty)
+		putc(' ', self->out);
 }
 
 void jsonw_end_array(json_writer_t *self)
 {
+	if (self->pretty && self->sep)
+		putc(' ', self->out);
+	self->sep = '\0';
 	jsonw_end(self, ']');
 }
 
-- 
2.15.1

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

* Re: [RFC iproute2-next 00/16] iproute printing enhancements
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (15 preceding siblings ...)
  2018-02-02  1:19 ` [RFC iproute2-next 16/16] json: fix newline at end of array Stephen Hemminger
@ 2018-02-02  2:59 ` David Ahern
  2018-02-02  3:08 ` David Ahern
  17 siblings, 0 replies; 20+ messages in thread
From: David Ahern @ 2018-02-02  2:59 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, Stephen Hemminger

On 2/1/18 6:19 PM, Stephen Hemminger wrote:
> The first group of patches refactor the printout to breakup
> excessively long print_route function and the last few implement
> JSON and color output format for routes.

If I knew you were going to refactor route printing, I would have
pointed you to these:
  https://github.com/dsahern/iproute2/commits/route-match

too many patches I never sent.

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

* Re: [RFC iproute2-next 00/16] iproute printing enhancements
  2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
                   ` (16 preceding siblings ...)
  2018-02-02  2:59 ` [RFC iproute2-next 00/16] iproute printing enhancements David Ahern
@ 2018-02-02  3:08 ` David Ahern
  2018-02-02 22:24   ` Stephen Hemminger
  17 siblings, 1 reply; 20+ messages in thread
From: David Ahern @ 2018-02-02  3:08 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev, Stephen Hemminger

On 2/1/18 6:19 PM, Stephen Hemminger wrote:
> The first group of patches refactor the printout to breakup
> excessively long print_route function and the last few implement
> JSON and color output format for routes.
> 
> The one thing that maybe controversial is changing the default
> json output format to be compact. The value of JSON is for programattic
> output therefore pretty-printing should be an option.
> 
> One change I didn't make (but considered) is not calling fflush
> after every single entry. When dumping millions of routes, letting
> stdio buffer output would be a performance win.
> 
> Stephen Hemminger (16):
>   iproute: refactor printing flags
>   iproute: make printing icmpv6 a function
>   iproute: make printing IPv4 cache flags a function
>   iproute: refactor cacheinfo printing
>   iproute: refactor metrics print
>   iproute: refactor printing flow info
>   iproute2: refactor newdst, gateway and via printing
>   iproute: refactor multipath print
>   iproute: refactor printing of interface
>   iproute: whitespace fixes
>   iproute: don't do assignment in condition
>   iproute: make flush a separate function
>   iproute: implement JSON and color output
>   json: make pretty printing optional
>   man: add documentation for json and pretty flags
>   json: fix newline at end of array
> 

The first 12 look fine to me; familiar territory. Why not send those
outside of the json patches which require a closer look?

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

* Re: [RFC iproute2-next 00/16] iproute printing enhancements
  2018-02-02  3:08 ` David Ahern
@ 2018-02-02 22:24   ` Stephen Hemminger
  0 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2018-02-02 22:24 UTC (permalink / raw)
  To: David Ahern; +Cc: netdev, Stephen Hemminger

On Thu, 1 Feb 2018 20:08:37 -0700
David Ahern <dsahern@gmail.com> wrote:

> On 2/1/18 6:19 PM, Stephen Hemminger wrote:
> > The first group of patches refactor the printout to breakup
> > excessively long print_route function and the last few implement
> > JSON and color output format for routes.
> > 
> > The one thing that maybe controversial is changing the default
> > json output format to be compact. The value of JSON is for programattic
> > output therefore pretty-printing should be an option.
> > 
> > One change I didn't make (but considered) is not calling fflush
> > after every single entry. When dumping millions of routes, letting
> > stdio buffer output would be a performance win.
> > 
> > Stephen Hemminger (16):
> >   iproute: refactor printing flags
> >   iproute: make printing icmpv6 a function
> >   iproute: make printing IPv4 cache flags a function
> >   iproute: refactor cacheinfo printing
> >   iproute: refactor metrics print
> >   iproute: refactor printing flow info
> >   iproute2: refactor newdst, gateway and via printing
> >   iproute: refactor multipath print
> >   iproute: refactor printing of interface
> >   iproute: whitespace fixes
> >   iproute: don't do assignment in condition
> >   iproute: make flush a separate function
> >   iproute: implement JSON and color output
> >   json: make pretty printing optional
> >   man: add documentation for json and pretty flags
> >   json: fix newline at end of array
> >   
> 
> The first 12 look fine to me; familiar territory. Why not send those
> outside of the json patches which require a closer look?
> 

When I submit final version, will break into three sets.
First is refactoring (including doing flags better), then
color/json. Lastly, the pretty print change.

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

end of thread, other threads:[~2018-02-02 22:24 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-02  1:19 [RFC iproute2-next 00/16] iproute printing enhancements Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 01/16] iproute: refactor printing flags Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 02/16] iproute: make printing icmpv6 a function Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 03/16] iproute: make printing IPv4 cache flags " Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 04/16] iproute: refactor cacheinfo printing Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 05/16] iproute: refactor metrics print Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 06/16] iproute: refactor printing flow info Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 07/16] iproute2: refactor newdst, gateway and via printing Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 08/16] iproute: refactor multipath print Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 09/16] iproute: refactor printing of interface Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 10/16] iproute: whitespace fixes Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 11/16] iproute: don't do assignment in condition Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 12/16] iproute: make flush a separate function Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 13/16] iproute: implement JSON and color output Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 14/16] json: make pretty printing optional Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 15/16] man: add documentation for json and pretty flags Stephen Hemminger
2018-02-02  1:19 ` [RFC iproute2-next 16/16] json: fix newline at end of array Stephen Hemminger
2018-02-02  2:59 ` [RFC iproute2-next 00/16] iproute printing enhancements David Ahern
2018-02-02  3:08 ` David Ahern
2018-02-02 22:24   ` Stephen Hemminger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).