lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 29 Jan 2018 12:29:08 -0800
From:   Stephen Hemminger <stephen@...workplumber.org>
To:     netdev@...r.kernel.org
Cc:     Stephen Hemminger <sthemmin@...rosoft.com>
Subject: [RFC] iproute2: add json and color support

This patch makes ip route command have json and color output in
a similar fashion of ip link and address.

The printing is split into functions and duplicate code
removed.

Probably incomplete, and has formatting glitches.

---
 include/utils.h |   4 +
 ip/iproute.c    | 764 ++++++++++++++++++++++++++++++++++----------------------
 2 files changed, 469 insertions(+), 299 deletions(-)

diff --git a/include/utils.h b/include/utils.h
index 0394268e1276..e35ea32c1d3b 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -155,6 +155,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 bf886fda9d76..b07d1ac7b7c9 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c
@@ -340,12 +340,346 @@ 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)
+		print_null(PRINT_ANY, "dead", "dead ", NULL);
+	if (flags & RTNH_F_ONLINK)
+		print_null(PRINT_ANY, "onlink", "onlink ", NULL);
+	if (flags & RTNH_F_PERVASIVE)
+		print_null(PRINT_ANY, "pervasive", "pervasive ", NULL);
+	if (flags & RTNH_F_OFFLOAD)
+		print_null(PRINT_ANY, "offload", "offload ", NULL);
+	if (flags & RTM_F_NOTIFY)
+		print_null(PRINT_ANY, "notify", "notify ", NULL);
+	if (flags & RTNH_F_LINKDOWN)
+		print_null(PRINT_ANY, "linkdown", "linkdown ", NULL);
+	if (flags & RTNH_F_UNRESOLVED)
+		print_null(PRINT_ANY, "unresolved", "unresolved ", NULL);
+
+	close_json_array(PRINT_JSON, NULL);
+}
+
+static void print_rt_metrics(FILE *fp, struct rtattr *rtm)
+{
+	struct rtattr *mxrta[RTAX_MAX+1];
+	unsigned int mxlock = 0;
+	int i;
+
+	open_json_array(PRINT_JSON, "metrics");
+
+	parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(rtm),
+		     RTA_PAYLOAD(rtm));
+
+	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 (!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 ");
+		}
+
+		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 (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:
+			print_string(PRINT_ANY, "congestion",
+				     "%s ", rta_getattr_str(mxrta[i]));
+			break;
+		}
+	}
+
+	close_json_array(PRINT_JSON, NULL);
+}
+
+static void print_rt_if(FILE *fp, struct rtattr *rif,
+			const char *tag, const char *prefix)
+{
+	const char *ifname = ll_index_to_name(rta_getattr_u32(rif));
+
+	if (is_json_context())
+		print_string(PRINT_JSON, tag, NULL, ifname);
+	else {
+		fprintf(fp, "%s ", prefix);
+		color_fprintf(fp, COLOR_IFNAME, "%s", ifname);
+		fprintf(fp, " ");
+	}
+}
+
+static void print_ipv4_flags(FILE *fp,
+			     const struct rtmsg *r)
+{
+	__u32 flags = r->rtm_flags & ~0xFFFF;
+
+	if (!is_json_context())
+		fprintf(fp, "%s", _SL_);
+
+	open_json_array(PRINT_ANY,
+			is_json_context() ? "cache"
+			: "    cache <");
+
+#define PRTFL(fl, flname)						\
+	if (flags & RTCF_##fl) {					\
+		flags &= ~RTCF_##fl;					\
+		print_string(PRINT_ANY, NULL, flags ? "%s," : "%s", flname); \
+	}								\
+
+	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)
+		print_hex(PRINT_ANY, NULL, "%x", flags);
+	close_json_array(PRINT_ANY, "> ");
+}
+
+static void print_cacheinfo(FILE *fp,
+			    const struct rta_cacheinfo *ci)
+{
+	static int hz;
+
+	if (!hz)
+		hz = get_user_hz();
+
+	if (ci->rta_expires != 0)
+		print_uint(PRINT_ANY, "expires",
+			   "expires %usec ", ci->rta_expires/hz);
+	if (ci->rta_error != 0)
+		print_uint(PRINT_ANY, "error",
+			   "error %u ", ci->rta_error);
+
+	if (show_stats) {
+		if (ci->rta_clntref)
+			print_uint(PRINT_ANY, "users",
+				   "users %u ", ci->rta_clntref);
+		if (ci->rta_used != 0)
+			print_uint(PRINT_ANY, "used",
+				   "used %u ", ci->rta_used);
+		if (ci->rta_lastuse != 0)
+			print_uint(PRINT_ANY, "age",
+				   "age %usec ", ci->rta_lastuse/hz);
+	}
+	if (ci->rta_id)
+		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)
+{
+	__u32 to = rta_getattr_u32(rta);
+	__u32 from = to >> 16;
+	SPRINT_BUF(b1);
+
+	to &= 0xFFFF;
+	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)));
+	}
+}
+
+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);
+
+	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,
+			     const struct rtattr *rta)
+{
+	const char *gateway = format_host_rta(r->rtm_family, rta);
+
+	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);
+
+	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_multipath(FILE *fp, const struct rtmsg *r,
+			    struct rtattr *rta)
+{
+	const struct rtnexthop *nh = RTA_DATA(rta);
+	int len = RTA_PAYLOAD(rta);
+	int first = 0;
+
+	while (len > sizeof(*nh)) {
+		struct rtattr *tb[RTA_MAX + 1];
+
+		if (nh->rtnh_len > len)
+			break;
+
+		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))
+			continue;
+
+		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)
@@ -354,12 +688,11 @@ 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;
 
 	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",
@@ -401,376 +734,202 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	}
 
 	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 ",
+			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);
-	}
-	if (tb[RTA_NEWDST]) {
-		fprintf(fp, "as to %s ",
-		        format_host_rta(r->rtm_family, tb[RTA_NEWDST]));
+		snprintf(b1, sizeof(b1), "0/%u", r->rtm_src_len);
+
+		print_string(PRINT_ANY, "src", "from %s ", b1);
 	}
 
+	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]);
 
 	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) {
-		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])));
+		print_rt_if(fp, tb[RTA_OIF], "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]));
-	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_uint(PRINT_ANY, "metric", "metric %u ",
+			   rta_getattr_u32(tb[RTA_PRIORITY]));
+
+	print_rt_flags(fp, r->rtm_flags);
+
 	if (tb[RTA_MARK]) {
 		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);
 		}
 	}
 
-	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]));
-
-	if ((r->rtm_flags&RTM_F_CLONED) && r->rtm_family == AF_INET) {
-		__u32 flags = r->rtm_flags&~0xFFFF;
-		int first = 1;
-
-		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]);
-
-			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);
+		print_uint(PRINT_ANY, "uid", "uid %u ",
+			   rta_getattr_u32(tb[RTA_UID]));
+
+	if (r->rtm_family == AF_INET) {
+		if (r->rtm_flags & RTM_F_CLONED) {
+			print_ipv4_flags(fp, r);
+
+			if (tb[RTA_CACHEINFO])
+				print_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
 		}
 	} else if (r->rtm_family == AF_INET6) {
-		struct rta_cacheinfo *ci = NULL;
-
-		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);
+		if (r->rtm_flags & RTM_F_CLONED) {
+			if (tb[RTA_CACHEINFO])
+				print_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 (tb[RTA_METRICS])
+		print_rt_metrics(fp, tb[RTA_METRICS]);
 
-			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;
-			}
-		}
-	}
-	if (tb[RTA_IIF] && filter.iifmask != -1) {
-		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;
+	if (tb[RTA_IIF] && filter.iifmask != -1)
+		print_rt_if(fp, tb[RTA_IIF], "iif", "iif");
 
-		len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
+	if (tb[RTA_MULTIPATH])
+		print_multipath(fp, r, 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]) {
-					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_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 (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);
-			}
-			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 ");
-			len -= NLMSG_ALIGN(nh->rtnh_len);
-			nh = RTNH_NEXT(nh);
-		}
-	}
 	if (tb[RTA_PREF]) {
 		unsigned int pref = rta_getattr_u8(tb[RTA_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);
 		}
 	}
+
 	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");
-	fflush(fp);
+
 	return 0;
 }
 
@@ -1709,23 +1868,30 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
 		}
 	}
 
+	new_json_obj(json);
+
 	if (!filter.cloned) {
 		if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
 			perror("Cannot send dump request");
+			delete_json_obj();
 			return -2;
 		}
 	} else {
 		if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
 			perror("Cannot send dump request");
+			delete_json_obj();
 			return -2;
 		}
 	}
 
 	if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
 		fprintf(stderr, "Dump terminated\n");
+		delete_json_obj();
 		return -2;
 	}
 
+	close_json_object();
+	fflush(stdout);
 	return 0;
 }
 
-- 
2.15.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ