iproute: implement JSON and color output

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>
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
Stephen Hemminger 2018-02-08 08:26:25 -08:00 committed by David Ahern
parent 6cbd9465bc
commit 663c3cb231
3 changed files with 348 additions and 162 deletions

View File

@ -23,6 +23,7 @@ extern int resolve_hosts;
extern int oneline; extern int oneline;
extern int brief; extern int brief;
extern int json; extern int json;
extern int pretty;
extern int timestamp; extern int timestamp;
extern int timestamp_short; extern int timestamp_short;
extern const char * _SL_; 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, const char *format_host_r(int af, int len, const void *addr,
char *buf, int buflen); 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); const char *format_host(int af, int lne, const void *addr);
#define format_host_rta(af, rta) \ #define format_host_rta(af, rta) \
format_host(af, RTA_PAYLOAD(rta), RTA_DATA(rta)) format_host(af, RTA_PAYLOAD(rta), RTA_DATA(rta))

View File

@ -339,72 +339,95 @@ static void print_rtax_features(FILE *fp, unsigned int features)
unsigned int of = features; unsigned int of = features;
if (features & RTAX_FEATURE_ECN) { if (features & RTAX_FEATURE_ECN) {
fprintf(fp, "ecn "); print_null(PRINT_ANY, "ecn", "ecn ", NULL);
features &= ~RTAX_FEATURE_ECN; features &= ~RTAX_FEATURE_ECN;
} }
if (features) 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) static void print_rt_flags(FILE *fp, unsigned int flags)
{ {
open_json_array(PRINT_JSON,
is_json_context() ? "flags" : "");
if (flags & RTNH_F_DEAD) if (flags & RTNH_F_DEAD)
fprintf(fp, "dead "); print_string(PRINT_ANY, NULL, "%s ", "dead");
if (flags & RTNH_F_ONLINK) if (flags & RTNH_F_ONLINK)
fprintf(fp, "onlink "); print_string(PRINT_ANY, NULL, "%s ", "onlink");
if (flags & RTNH_F_PERVASIVE) if (flags & RTNH_F_PERVASIVE)
fprintf(fp, "pervasive "); print_string(PRINT_ANY, NULL, "%s ", "pervasive");
if (flags & RTNH_F_OFFLOAD) 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) if (flags & RTNH_F_LINKDOWN)
fprintf(fp, "linkdown "); print_string(PRINT_ANY, NULL, "%s ", "linkdown");
if (flags & RTNH_F_UNRESOLVED) 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) static void print_rt_pref(FILE *fp, unsigned int pref)
{ {
fprintf(fp, "pref ");
switch (pref) { switch (pref) {
case ICMPV6_ROUTER_PREF_LOW: case ICMPV6_ROUTER_PREF_LOW:
fprintf(fp, "low"); print_string(PRINT_ANY,
"pref", "pref %s", "low");
break; break;
case ICMPV6_ROUTER_PREF_MEDIUM: case ICMPV6_ROUTER_PREF_MEDIUM:
fprintf(fp, "medium"); print_string(PRINT_ANY,
"pref", "pref %s", "medium");
break; break;
case ICMPV6_ROUTER_PREF_HIGH: case ICMPV6_ROUTER_PREF_HIGH:
fprintf(fp, "high"); print_string(PRINT_ANY,
"pref", "pref %s", "high");
break; break;
default: default:
fprintf(fp, "%u", pref); print_uint(PRINT_ANY,
"pref", "%u", pref);
} }
} }
static void print_rta_if(FILE *fp, const struct rtattr *rta, 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)); 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_cache_flags(FILE *fp, __u32 flags) static void print_cache_flags(FILE *fp, __u32 flags)
{ {
json_writer_t *jw = get_json_writer();
flags &= ~0xFFFF; flags &= ~0xFFFF;
fprintf(fp, "%s cache ", _SL_); if (jw) {
jsonw_name(jw, "cache");
if (flags == 0) jsonw_start_array(jw);
return; } else {
fprintf(fp, "%s cache ", _SL_);
putc('<', fp); if (flags == 0)
return;
putc('<', fp);
}
#define PRTFL(fl, flname) \ #define PRTFL(fl, flname) \
if (flags & RTCF_##fl) { \ if (flags & RTCF_##fl) { \
flags &= ~RTCF_##fl; \ flags &= ~RTCF_##fl; \
fprintf(fp, "%s%s", flname, flags ? "," : "> "); \ if (jw) \
jsonw_string(jw, flname); \
else \
fprintf(fp, "%s%s", flname, flags ? "," : "> "); \
} }
PRTFL(LOCAL, "local"); PRTFL(LOCAL, "local");
@ -424,7 +447,12 @@ static void print_cache_flags(FILE *fp, __u32 flags)
#undef PRTFL #undef PRTFL
if (flags) if (flags)
fprintf(fp, "%#x> ", flags); print_hex(PRINT_ANY, "flags", "%x>", flags);
if (jw) {
jsonw_end_array(jw);
jsonw_destroy(&jw);
}
} }
static void print_rta_cacheinfo(FILE *fp, const struct rta_cacheinfo *ci) static void print_rta_cacheinfo(FILE *fp, const struct rta_cacheinfo *ci)
@ -433,23 +461,34 @@ static void print_rta_cacheinfo(FILE *fp, const struct rta_cacheinfo *ci)
if (!hz) if (!hz)
hz = get_user_hz(); hz = get_user_hz();
if (ci->rta_expires != 0) 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) 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 (show_stats) {
if (ci->rta_clntref) 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) 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) 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) if (ci->rta_id)
fprintf(fp, "ipid 0x%04x ", ci->rta_id); print_0xhex(PRINT_ANY, "ipid",
if (ci->rta_ts || ci->rta_tsage) "ipid 0x%04x ", ci->rta_id);
fprintf(fp, "ts 0x%x tsage %dsec ", if (ci->rta_ts || ci->rta_tsage) {
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) static void print_rta_flow(FILE *fp, const struct rtattr *rta)
@ -459,13 +498,24 @@ static void print_rta_flow(FILE *fp, const struct rtattr *rta)
SPRINT_BUF(b1); SPRINT_BUF(b1);
to &= 0xFFFF; to &= 0xFFFF;
fprintf(fp, "realm%s ", from ? "s" : ""); if (is_json_context()) {
if (from) { open_json_object("flow");
fprintf(fp, "%s/",
rtnl_rtrealm_n2a(from, b1, sizeof(b1))); 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, static void print_rta_newdst(FILE *fp, const struct rtmsg *r,
@ -473,7 +523,14 @@ static void print_rta_newdst(FILE *fp, const struct rtmsg *r,
{ {
const char *newdst = format_host_rta(r->rtm_family, rta); 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, static void print_rta_gateway(FILE *fp, const struct rtmsg *r,
@ -481,17 +538,38 @@ static void print_rta_gateway(FILE *fp, const struct rtmsg *r,
{ {
const char *gateway = format_host_rta(r->rtm_family, rta); 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) 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); const struct rtvia *via = RTA_DATA(rta);
size_t len = RTA_PAYLOAD(rta);
fprintf(fp, "via %s %s ", if (is_json_context()) {
family_name(via->rtvia_family), open_json_object("via");
format_host(via->rtvia_family, len, via->rtvia_addr)); 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) static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
@ -500,6 +578,8 @@ static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
unsigned int mxlock = 0; unsigned int mxlock = 0;
int i; int i;
open_json_array(PRINT_JSON, "metrics");
parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)); parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta));
if (mxrta[RTAX_LOCK]) if (mxrta[RTAX_LOCK])
@ -517,13 +597,15 @@ static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
if (i == RTAX_HOPLIMIT && (int)val == -1) if (i == RTAX_HOPLIMIT && (int)val == -1)
continue; continue;
if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i]) if (!is_json_context()) {
fprintf(fp, "%s ", mx_names[i]); if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i])
else fprintf(fp, "%s ", mx_names[i]);
fprintf(fp, "metric %d ", i); else
fprintf(fp, "metric %d ", i);
if (mxlock & (1<<i)) if (mxlock & (1<<i))
fprintf(fp, "lock "); fprintf(fp, "lock ");
}
switch (i) { switch (i) {
case RTAX_FEATURES: case RTAX_FEATURES:
@ -541,16 +623,24 @@ static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
else if (i == RTAX_RTTVAR) else if (i == RTAX_RTTVAR)
val /= 4; val /= 4;
if (val >= 1000) if (is_json_context())
fprintf(fp, "%gs ", val/1e3); print_uint(PRINT_JSON, mx_names[i],
else NULL, val);
fprintf(fp, "%ums ", val); else {
if (val >= 1000)
fprintf(fp, "%gs ", val/1e3);
else
fprintf(fp, "%ums ", val);
}
break; break;
case RTAX_CC_ALGO: case RTAX_CC_ALGO:
fprintf(fp, "%s ", rta_getattr_str(mxrta[i])); print_string(PRINT_ANY, "congestion",
"%s ", rta_getattr_str(mxrta[i]));
break; break;
} }
} }
close_json_array(PRINT_JSON, NULL);
} }
static void print_rta_multipath(FILE *fp, const struct rtmsg *r, static void print_rta_multipath(FILE *fp, const struct rtmsg *r,
@ -566,16 +656,18 @@ static void print_rta_multipath(FILE *fp, const struct rtmsg *r,
if (nh->rtnh_len > len) if (nh->rtnh_len > len)
break; break;
if ((r->rtm_flags & RTM_F_CLONED) && if (!is_json_context()) {
r->rtm_type == RTN_MULTICAST) { if ((r->rtm_flags & RTM_F_CLONED) &&
if (first) { r->rtm_type == RTN_MULTICAST) {
fprintf(fp, "Oifs: "); if (first) {
first = 0; fprintf(fp, "Oifs: ");
} else { first = 0;
fprintf(fp, " "); } else {
} fprintf(fp, " ");
} else }
fprintf(fp, "%s\tnexthop ", _SL_); } else
fprintf(fp, "%s\tnexthop ", _SL_);
}
if (nh->rtnh_len > sizeof(*nh)) { if (nh->rtnh_len > sizeof(*nh)) {
parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh), parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh),
@ -602,8 +694,7 @@ static void print_rta_multipath(FILE *fp, const struct rtmsg *r,
fprintf(fp, "(ttl>%d)", nh->rtnh_hops); fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
fprintf(fp, " "); fprintf(fp, " ");
} else { } else {
fprintf(fp, "dev %s ", fprintf(fp, "dev %s ", ll_index_to_name(nh->rtnh_ifindex));
ll_index_to_name(nh->rtnh_ifindex));
if (r->rtm_family != AF_MPLS) if (r->rtm_family != AF_MPLS)
fprintf(fp, "weight %d ", fprintf(fp, "weight %d ",
nh->rtnh_hops+1); nh->rtnh_hops+1);
@ -622,7 +713,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
struct rtmsg *r = NLMSG_DATA(n); struct rtmsg *r = NLMSG_DATA(n);
int len = n->nlmsg_len; int len = n->nlmsg_len;
struct rtattr *tb[RTA_MAX+1]; struct rtattr *tb[RTA_MAX+1];
int host_len, family; int family, color, host_len;
__u32 table; __u32 table;
int ret; int ret;
@ -668,39 +759,56 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
return 0; return 0;
} }
open_json_object(NULL);
if (n->nlmsg_type == RTM_DELROUTE) 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) && if ((r->rtm_type != RTN_UNICAST || show_details > 0) &&
(!filter.typemask || (filter.typemask & (1 << r->rtm_type)))) (!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]) { if (tb[RTA_DST]) {
family = get_real_family(r->rtm_type, r->rtm_family); family = get_real_family(r->rtm_type, r->rtm_family);
color = ifa_family_color(family);
if (r->rtm_dst_len != host_len) { if (r->rtm_dst_len != host_len) {
fprintf(fp, "%s/%u ", snprintf(b1, sizeof(b1),
rt_addr_n2a_rta(family, tb[RTA_DST]), "%s/%u", rt_addr_n2a_rta(family, tb[RTA_DST]),
r->rtm_dst_len); r->rtm_dst_len);
} else { } else {
fprintf(fp, "%s ", format_host_rta_r(family, tb[RTA_DST],
format_host_rta(family, tb[RTA_DST])); b1, sizeof(b1));
} }
} else if (r->rtm_dst_len) { } 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 { } else {
fprintf(fp, "default "); strncpy(b1, "default", sizeof(b1));
} }
print_color_string(PRINT_ANY, color,
"dst", "%s ", b1);
if (tb[RTA_SRC]) { if (tb[RTA_SRC]) {
family = get_real_family(r->rtm_type, r->rtm_family); family = get_real_family(r->rtm_type, r->rtm_family);
color = ifa_family_color(family);
if (r->rtm_src_len != host_len) { if (r->rtm_src_len != host_len) {
fprintf(fp, "from %s/%u ", snprintf(b1, sizeof(b1),
rt_addr_n2a_rta(family, tb[RTA_SRC]), "%s/%u",
r->rtm_src_len); rt_addr_n2a_rta(family, tb[RTA_SRC]),
r->rtm_src_len);
} else { } else {
fprintf(fp, "from %s ", format_host_rta_r(family, tb[RTA_SRC],
format_host_rta(family, tb[RTA_SRC])); b1, sizeof(b1));
} }
print_color_string(PRINT_ANY, color,
"from", "from %s ", b1);
} else if (r->rtm_src_len) { } 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]) if (tb[RTA_NEWDST])
@ -710,8 +818,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]); lwt_print_encap(fp, tb[RTA_ENCAP_TYPE], tb[RTA_ENCAP]);
if (r->rtm_tos && filter.tosmask != -1) { if (r->rtm_tos && filter.tosmask != -1) {
SPRINT_BUF(b1); print_string(PRINT_ANY, "tos", "tos %s ",
fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
} }
if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len)
@ -721,25 +829,50 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
print_rta_via(fp, tb[RTA_VIA]); print_rta_via(fp, tb[RTA_VIA]);
if (tb[RTA_OIF] && filter.oifmask != -1) 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) 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_flags & RTM_F_CLONED)) {
if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1) if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) &&
fprintf(fp, "proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1))); filter.protocolmask != -1)
if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1) print_string(PRINT_ANY,
fprintf(fp, "scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1))); "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) { 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 /* Do not use format_host(). It is our local addr
and symbolic name will not be useful. and symbolic name will not be useful.
*/ */
fprintf(fp, "src %s ", if (is_json_context())
rt_addr_n2a_rta(r->rtm_family, tb[RTA_PREFSRC])); 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) 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); print_rt_flags(fp, r->rtm_flags);
@ -747,10 +880,14 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
unsigned int mark = rta_getattr_u32(tb[RTA_MARK]); unsigned int mark = rta_getattr_u32(tb[RTA_MARK]);
if (mark) { if (mark) {
if (mark >= 16) if (is_json_context())
fprintf(fp, "mark 0x%x ", mark); print_uint(PRINT_JSON, "mark", NULL, mark);
else if (mark >= 16)
print_0xhex(PRINT_FP, NULL,
"mark 0x%x ", mark);
else else
fprintf(fp, "mark %u ", mark); print_uint(PRINT_FP, NULL,
"mark %u ", mark);
} }
} }
@ -758,20 +895,21 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
print_rta_flow(fp, tb[RTA_FLOW]); print_rta_flow(fp, tb[RTA_FLOW]);
if (tb[RTA_UID]) if (tb[RTA_UID])
fprintf(fp, "uid %u ", rta_getattr_u32(tb[RTA_UID])); print_uint(PRINT_ANY, "uid", "uid %u ",
rta_getattr_u32(tb[RTA_UID]));
if ((r->rtm_flags & RTM_F_CLONED) && r->rtm_family == AF_INET) { if (r->rtm_family == AF_INET) {
print_cache_flags(fp, r->rtm_flags); if (r->rtm_flags & RTM_F_CLONED) {
print_cache_flags(fp, r->rtm_flags);
if (tb[RTA_CACHEINFO])
print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
if (tb[RTA_CACHEINFO])
print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
}
} else if (r->rtm_family == AF_INET6) { } else if (r->rtm_family == AF_INET6) {
if (r->rtm_flags & RTM_F_CLONED) 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 (tb[RTA_CACHEINFO]) }
print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
} }
if (tb[RTA_METRICS]) if (tb[RTA_METRICS])
@ -787,13 +925,19 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
print_rt_pref(fp, rta_getattr_u8(tb[RTA_PREF])); print_rt_pref(fp, rta_getattr_u8(tb[RTA_PREF]));
if (tb[RTA_TTL_PROPAGATE]) { if (tb[RTA_TTL_PROPAGATE]) {
fprintf(fp, "ttl-propagate "); bool propogate = rta_getattr_u8(tb[RTA_TTL_PROPAGATE]);
if (rta_getattr_u8(tb[RTA_TTL_PROPAGATE]))
fprintf(fp, "enabled"); if (is_json_context())
print_bool(PRINT_JSON, "ttl-propogate", NULL,
propogate);
else 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); fflush(fp);
return 0; return 0;
} }
@ -1756,11 +1900,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) { if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
fprintf(stderr, "Dump terminated\n"); fprintf(stderr, "Dump terminated\n");
return -2; return -2;
} }
delete_json_obj();
fflush(stdout);
return 0; return 0;
} }

View File

@ -94,20 +94,28 @@ static void print_srh(FILE *fp, struct ipv6_sr_hdr *srh)
{ {
int i; int i;
fprintf(fp, "segs %d [ ", srh->first_segment + 1); if (is_json_context())
open_json_array(PRINT_JSON, "segs");
else
fprintf(fp, "segs %d [ ", srh->first_segment + 1);
for (i = srh->first_segment; i >= 0; i--) for (i = srh->first_segment; i >= 0; i--)
fprintf(fp, "%s ", print_color_string(PRINT_ANY, COLOR_INET6,
rt_addr_n2a(AF_INET6, 16, &srh->segments[i])); NULL, "%s ",
rt_addr_n2a(AF_INET6, 16, &srh->segments[i]));
fprintf(fp, "] "); if (is_json_context())
close_json_array(PRINT_JSON, NULL);
else
fprintf(fp, "] ");
if (sr_has_hmac(srh)) { if (sr_has_hmac(srh)) {
unsigned int offset = ((srh->hdrlen + 1) << 3) - 40; unsigned int offset = ((srh->hdrlen + 1) << 3) - 40;
struct sr6_tlv_hmac *tlv; struct sr6_tlv_hmac *tlv;
tlv = (struct sr6_tlv_hmac *)((char *)srh + offset); tlv = (struct sr6_tlv_hmac *)((char *)srh + offset);
fprintf(fp, "hmac 0x%X ", ntohl(tlv->hmackeyid)); print_0xhex(PRINT_ANY, "hmac",
"hmac 0x%X ", ntohl(tlv->hmackeyid));
} }
} }
@ -148,7 +156,8 @@ static void print_encap_seg6(FILE *fp, struct rtattr *encap)
return; return;
tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]); tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]);
fprintf(fp, "mode %s ", format_seg6mode_type(tuninfo->mode)); print_string(PRINT_ANY, "mode",
"mode %s ", format_seg6mode_type(tuninfo->mode));
print_srh(fp, tuninfo->srh); print_srh(fp, tuninfo->srh);
} }
@ -205,36 +214,41 @@ static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
action = rta_getattr_u32(tb[SEG6_LOCAL_ACTION]); action = rta_getattr_u32(tb[SEG6_LOCAL_ACTION]);
fprintf(fp, "action %s ", format_action_type(action)); print_string(PRINT_ANY, "action",
"action %s ", format_action_type(action));
if (tb[SEG6_LOCAL_SRH]) { if (tb[SEG6_LOCAL_SRH]) {
fprintf(fp, "srh "); open_json_object("srh");
print_srh(fp, RTA_DATA(tb[SEG6_LOCAL_SRH])); print_srh(fp, RTA_DATA(tb[SEG6_LOCAL_SRH]));
close_json_object();
} }
if (tb[SEG6_LOCAL_TABLE]) if (tb[SEG6_LOCAL_TABLE])
fprintf(fp, "table %u ", rta_getattr_u32(tb[SEG6_LOCAL_TABLE])); print_uint(PRINT_ANY, "table",
"table %u ", rta_getattr_u32(tb[SEG6_LOCAL_TABLE]));
if (tb[SEG6_LOCAL_NH4]) { if (tb[SEG6_LOCAL_NH4]) {
fprintf(fp, "nh4 %s ", print_string(PRINT_ANY, "nh4",
rt_addr_n2a_rta(AF_INET, tb[SEG6_LOCAL_NH4])); "nh4 %s ", rt_addr_n2a_rta(AF_INET, tb[SEG6_LOCAL_NH4]));
} }
if (tb[SEG6_LOCAL_NH6]) { if (tb[SEG6_LOCAL_NH6]) {
fprintf(fp, "nh6 %s ", print_string(PRINT_ANY, "nh6",
rt_addr_n2a_rta(AF_INET6, tb[SEG6_LOCAL_NH6])); "nh6 %s ", rt_addr_n2a_rta(AF_INET6, tb[SEG6_LOCAL_NH6]));
} }
if (tb[SEG6_LOCAL_IIF]) { if (tb[SEG6_LOCAL_IIF]) {
int iif = rta_getattr_u32(tb[SEG6_LOCAL_IIF]); int iif = rta_getattr_u32(tb[SEG6_LOCAL_IIF]);
fprintf(fp, "iif %s ", ll_index_to_name(iif)); print_string(PRINT_ANY, "iif",
"iif %s ", ll_index_to_name(iif));
} }
if (tb[SEG6_LOCAL_OIF]) { if (tb[SEG6_LOCAL_OIF]) {
int oif = rta_getattr_u32(tb[SEG6_LOCAL_OIF]); int oif = rta_getattr_u32(tb[SEG6_LOCAL_OIF]);
fprintf(fp, "oif %s ", ll_index_to_name(oif)); print_string(PRINT_ANY, "oif",
"oif %s ", ll_index_to_name(oif));
} }
} }
@ -245,10 +259,10 @@ static void print_encap_mpls(FILE *fp, struct rtattr *encap)
parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap); parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap);
if (tb[MPLS_IPTUNNEL_DST]) if (tb[MPLS_IPTUNNEL_DST])
fprintf(fp, " %s ", print_string(PRINT_ANY, "dst", " %s ",
format_host_rta(AF_MPLS, tb[MPLS_IPTUNNEL_DST])); format_host_rta(AF_MPLS, tb[MPLS_IPTUNNEL_DST]));
if (tb[MPLS_IPTUNNEL_TTL]) if (tb[MPLS_IPTUNNEL_TTL])
fprintf(fp, "ttl %u ", print_uint(PRINT_ANY, "ttl", "ttl %u ",
rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL])); rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL]));
} }
@ -259,22 +273,26 @@ static void print_encap_ip(FILE *fp, struct rtattr *encap)
parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap); parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
if (tb[LWTUNNEL_IP_ID]) if (tb[LWTUNNEL_IP_ID])
fprintf(fp, "id %llu ", print_uint(PRINT_ANY, "id", "id %llu ",
ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID]))); ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
if (tb[LWTUNNEL_IP_SRC]) if (tb[LWTUNNEL_IP_SRC])
fprintf(fp, "src %s ", print_color_string(PRINT_ANY, COLOR_INET,
rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC])); "src", "src %s ",
rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC]));
if (tb[LWTUNNEL_IP_DST]) if (tb[LWTUNNEL_IP_DST])
fprintf(fp, "dst %s ", print_color_string(PRINT_ANY, COLOR_INET,
rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST])); "dst", "dst %s ",
rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST]));
if (tb[LWTUNNEL_IP_TTL]) if (tb[LWTUNNEL_IP_TTL])
fprintf(fp, "ttl %u ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL])); print_uint(PRINT_ANY, "ttl",
"ttl %u ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL]));
if (tb[LWTUNNEL_IP_TOS]) if (tb[LWTUNNEL_IP_TOS])
fprintf(fp, "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS])); print_uint(PRINT_ANY, "tos",
"tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
} }
static void print_encap_ila(FILE *fp, struct rtattr *encap) static void print_encap_ila(FILE *fp, struct rtattr *encap)
@ -288,23 +306,24 @@ static void print_encap_ila(FILE *fp, struct rtattr *encap)
addr64_n2a(rta_getattr_u64(tb[ILA_ATTR_LOCATOR]), addr64_n2a(rta_getattr_u64(tb[ILA_ATTR_LOCATOR]),
abuf, sizeof(abuf)); abuf, sizeof(abuf));
fprintf(fp, " %s ", abuf); print_string(PRINT_ANY, "locator",
" %s ", abuf);
} }
if (tb[ILA_ATTR_CSUM_MODE]) if (tb[ILA_ATTR_CSUM_MODE])
fprintf(fp, " csum-mode %s ", print_string(PRINT_ANY, "csum_mode",
ila_csum_mode2name(rta_getattr_u8( " csum-mode %s ",
tb[ILA_ATTR_CSUM_MODE]))); ila_csum_mode2name(rta_getattr_u8(tb[ILA_ATTR_CSUM_MODE])));
if (tb[ILA_ATTR_IDENT_TYPE]) if (tb[ILA_ATTR_IDENT_TYPE])
fprintf(fp, " ident-type %s ", print_string(PRINT_ANY, "ident_type",
ila_ident_type2name(rta_getattr_u8( " ident-type %s ",
tb[ILA_ATTR_IDENT_TYPE]))); ila_ident_type2name(rta_getattr_u8(tb[ILA_ATTR_IDENT_TYPE])));
if (tb[ILA_ATTR_HOOK_TYPE]) if (tb[ILA_ATTR_HOOK_TYPE])
fprintf(fp, " hook-type %s ", print_string(PRINT_ANY, "hook_type",
ila_hook_type2name(rta_getattr_u8( " hook-type %s ",
tb[ILA_ATTR_HOOK_TYPE]))); ila_hook_type2name(rta_getattr_u8(tb[ILA_ATTR_HOOK_TYPE])));
} }
static void print_encap_ip6(FILE *fp, struct rtattr *encap) static void print_encap_ip6(FILE *fp, struct rtattr *encap)
@ -314,35 +333,48 @@ static void print_encap_ip6(FILE *fp, struct rtattr *encap)
parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap); parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
if (tb[LWTUNNEL_IP6_ID]) if (tb[LWTUNNEL_IP6_ID])
fprintf(fp, "id %llu ", print_uint(PRINT_ANY, "id", "id %llu ",
ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID]))); ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
if (tb[LWTUNNEL_IP6_SRC]) if (tb[LWTUNNEL_IP6_SRC])
fprintf(fp, "src %s ", print_color_string(PRINT_ANY, COLOR_INET6,
rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC])); "src", "src %s ",
rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
if (tb[LWTUNNEL_IP6_DST]) if (tb[LWTUNNEL_IP6_DST])
fprintf(fp, "dst %s ", print_color_string(PRINT_ANY, COLOR_INET6,
rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST])); "dst", "dst %s ",
rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
if (tb[LWTUNNEL_IP6_HOPLIMIT]) if (tb[LWTUNNEL_IP6_HOPLIMIT])
fprintf(fp, "hoplimit %u ", print_uint(PRINT_ANY, "hoplimit",
rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT])); "hoplimit %u ",
rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
if (tb[LWTUNNEL_IP6_TC]) if (tb[LWTUNNEL_IP6_TC])
fprintf(fp, "tc %d ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC])); print_uint(PRINT_ANY, "tc",
"tc %u ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
} }
static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap, static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap,
const char *str) const char *str)
{ {
struct rtattr *tb[LWT_BPF_PROG_MAX+1]; struct rtattr *tb[LWT_BPF_PROG_MAX+1];
const char *progname = NULL;
parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap); parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap);
fprintf(fp, "%s ", str);
if (tb[LWT_BPF_PROG_NAME]) if (tb[LWT_BPF_PROG_NAME])
fprintf(fp, "%s ", rta_getattr_str(tb[LWT_BPF_PROG_NAME])); progname = rta_getattr_str(tb[LWT_BPF_PROG_NAME]);
if (is_json_context())
print_string(PRINT_JSON, str, NULL,
progname ? : "<unknown>");
else {
fprintf(fp, "%s ", str);
if (progname)
fprintf(fp, "%s ", progname);
}
} }
static void print_encap_bpf(FILE *fp, struct rtattr *encap) static void print_encap_bpf(FILE *fp, struct rtattr *encap)
@ -358,7 +390,8 @@ static void print_encap_bpf(FILE *fp, struct rtattr *encap)
if (tb[LWT_BPF_XMIT]) if (tb[LWT_BPF_XMIT])
print_encap_bpf_prog(fp, tb[LWT_BPF_XMIT], "xmit"); print_encap_bpf_prog(fp, tb[LWT_BPF_XMIT], "xmit");
if (tb[LWT_BPF_XMIT_HEADROOM]) if (tb[LWT_BPF_XMIT_HEADROOM])
fprintf(fp, "%d ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM])); print_uint(PRINT_ANY, "headroom",
" %u ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
} }
void lwt_print_encap(FILE *fp, struct rtattr *encap_type, void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
@ -371,7 +404,7 @@ void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
et = rta_getattr_u16(encap_type); et = rta_getattr_u16(encap_type);
fprintf(fp, " encap %s ", format_encap_type(et)); print_string(PRINT_ANY, "encap", " encap %s ", format_encap_type(et));
switch (et) { switch (et) {
case LWTUNNEL_ENCAP_MPLS: case LWTUNNEL_ENCAP_MPLS: