From: Stephen Hemminger <step...@networkplumber.org> Add JSON and color output formatting to ip route command. Similar to existing address and link output.
Signed-off-by: Stephen Hemminger <step...@networkplumber.org> --- include/utils.h | 5 + ip/iproute.c | 376 +++++++++++++++++++++++++++++++++++--------------- ip/iproute_lwtunnel.c | 129 ++++++++++------- 3 files changed, 348 insertions(+), 162 deletions(-) diff --git a/include/utils.h b/include/utils.h index 8b8ee2e55ab8..4dc514d66ad1 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 3c56240f1291..e4809a4383d9 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -339,72 +339,95 @@ 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_cache_flags(FILE *fp, __u32 flags) { + json_writer_t *jw = get_json_writer(); flags &= ~0xFFFF; - fprintf(fp, "%s cache ", _SL_); - - if (flags == 0) - return; - - putc('<', fp); + if (jw) { + jsonw_name(jw, "cache"); + jsonw_start_array(jw); + } else { + fprintf(fp, "%s cache ", _SL_); + if (flags == 0) + return; + putc('<', fp); + } #define PRTFL(fl, flname) \ if (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"); @@ -424,7 +447,12 @@ static void print_cache_flags(FILE *fp, __u32 flags) #undef PRTFL 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) @@ -433,23 +461,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) @@ -459,13 +498,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, @@ -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); - 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, @@ -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); - 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) @@ -500,6 +578,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]) @@ -517,13 +597,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: @@ -541,16 +623,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, @@ -566,16 +656,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), @@ -602,8 +694,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); @@ -622,7 +713,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; @@ -668,39 +759,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]) @@ -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]); 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) @@ -721,25 +829,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); @@ -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]); 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); } } @@ -758,20 +895,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_cache_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_cache_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]) @@ -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])); 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; } @@ -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) { fprintf(stderr, "Dump terminated\n"); return -2; } + delete_json_obj(); + fflush(stdout); return 0; } diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index f7fbc6287932..fa3feaea7436 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -94,20 +94,28 @@ static void print_srh(FILE *fp, struct ipv6_sr_hdr *srh) { 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--) - fprintf(fp, "%s ", - rt_addr_n2a(AF_INET6, 16, &srh->segments[i])); + print_color_string(PRINT_ANY, COLOR_INET6, + 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)) { unsigned int offset = ((srh->hdrlen + 1) << 3) - 40; struct sr6_tlv_hmac *tlv; 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; 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); } @@ -205,36 +214,41 @@ static void print_encap_seg6local(FILE *fp, struct rtattr *encap) 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]) { - fprintf(fp, "srh "); + open_json_object("srh"); print_srh(fp, RTA_DATA(tb[SEG6_LOCAL_SRH])); + close_json_object(); } 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]) { - fprintf(fp, "nh4 %s ", - rt_addr_n2a_rta(AF_INET, tb[SEG6_LOCAL_NH4])); + print_string(PRINT_ANY, "nh4", + "nh4 %s ", rt_addr_n2a_rta(AF_INET, tb[SEG6_LOCAL_NH4])); } if (tb[SEG6_LOCAL_NH6]) { - fprintf(fp, "nh6 %s ", - rt_addr_n2a_rta(AF_INET6, tb[SEG6_LOCAL_NH6])); + print_string(PRINT_ANY, "nh6", + "nh6 %s ", rt_addr_n2a_rta(AF_INET6, tb[SEG6_LOCAL_NH6])); } if (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]) { 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); if (tb[MPLS_IPTUNNEL_DST]) - fprintf(fp, " %s ", + print_string(PRINT_ANY, "dst", " %s ", format_host_rta(AF_MPLS, tb[MPLS_IPTUNNEL_DST])); if (tb[MPLS_IPTUNNEL_TTL]) - fprintf(fp, "ttl %u ", + print_uint(PRINT_ANY, "ttl", "ttl %u ", 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); if (tb[LWTUNNEL_IP_ID]) - fprintf(fp, "id %llu ", - ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID]))); + print_uint(PRINT_ANY, "id", "id %llu ", + ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID]))); if (tb[LWTUNNEL_IP_SRC]) - fprintf(fp, "src %s ", - rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC])); + print_color_string(PRINT_ANY, COLOR_INET, + "src", "src %s ", + rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC])); if (tb[LWTUNNEL_IP_DST]) - fprintf(fp, "dst %s ", - rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST])); + print_color_string(PRINT_ANY, COLOR_INET, + "dst", "dst %s ", + rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST])); 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]) - 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) @@ -288,23 +306,24 @@ static void print_encap_ila(FILE *fp, struct rtattr *encap) addr64_n2a(rta_getattr_u64(tb[ILA_ATTR_LOCATOR]), abuf, sizeof(abuf)); - fprintf(fp, " %s ", abuf); + print_string(PRINT_ANY, "locator", + " %s ", abuf); } if (tb[ILA_ATTR_CSUM_MODE]) - fprintf(fp, " csum-mode %s ", - ila_csum_mode2name(rta_getattr_u8( - tb[ILA_ATTR_CSUM_MODE]))); + print_string(PRINT_ANY, "csum_mode", + " csum-mode %s ", + ila_csum_mode2name(rta_getattr_u8(tb[ILA_ATTR_CSUM_MODE]))); if (tb[ILA_ATTR_IDENT_TYPE]) - fprintf(fp, " ident-type %s ", - ila_ident_type2name(rta_getattr_u8( - tb[ILA_ATTR_IDENT_TYPE]))); + print_string(PRINT_ANY, "ident_type", + " ident-type %s ", + ila_ident_type2name(rta_getattr_u8(tb[ILA_ATTR_IDENT_TYPE]))); if (tb[ILA_ATTR_HOOK_TYPE]) - fprintf(fp, " hook-type %s ", - ila_hook_type2name(rta_getattr_u8( - tb[ILA_ATTR_HOOK_TYPE]))); + print_string(PRINT_ANY, "hook_type", + " hook-type %s ", + ila_hook_type2name(rta_getattr_u8(tb[ILA_ATTR_HOOK_TYPE]))); } 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); if (tb[LWTUNNEL_IP6_ID]) - fprintf(fp, "id %llu ", - ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID]))); + print_uint(PRINT_ANY, "id", "id %llu ", + ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID]))); if (tb[LWTUNNEL_IP6_SRC]) - fprintf(fp, "src %s ", - rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC])); + print_color_string(PRINT_ANY, COLOR_INET6, + "src", "src %s ", + rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC])); if (tb[LWTUNNEL_IP6_DST]) - fprintf(fp, "dst %s ", - rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST])); + print_color_string(PRINT_ANY, COLOR_INET6, + "dst", "dst %s ", + rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST])); if (tb[LWTUNNEL_IP6_HOPLIMIT]) - fprintf(fp, "hoplimit %u ", - rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT])); + print_uint(PRINT_ANY, "hoplimit", + "hoplimit %u ", + rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT])); 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, const char *str) { struct rtattr *tb[LWT_BPF_PROG_MAX+1]; + const char *progname = NULL; parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap); - fprintf(fp, "%s ", str); 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) @@ -358,7 +390,8 @@ static void print_encap_bpf(FILE *fp, struct rtattr *encap) if (tb[LWT_BPF_XMIT]) print_encap_bpf_prog(fp, tb[LWT_BPF_XMIT], "xmit"); 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, @@ -371,7 +404,7 @@ void lwt_print_encap(FILE *fp, struct rtattr *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) { case LWTUNNEL_ENCAP_MPLS: -- 2.15.1