diff --git a/ip/ipaddrlabel.c b/ip/ipaddrlabel.c index 7200bf54..2f79c56d 100644 --- a/ip/ipaddrlabel.c +++ b/ip/ipaddrlabel.c @@ -38,6 +38,7 @@ #include "rt_names.h" #include "utils.h" #include "ip_common.h" +#include "json_print.h" #define IFAL_RTA(r) ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg)))) #define IFAL_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct ifaddrlblmsg)) @@ -55,7 +56,6 @@ static void usage(void) int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE *)arg; struct ifaddrlblmsg *ifal = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[IFAL_MAX+1]; @@ -69,28 +69,40 @@ int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg parse_rtattr(tb, IFAL_MAX, IFAL_RTA(ifal), len); + open_json_object(NULL); if (n->nlmsg_type == RTM_DELADDRLABEL) - fprintf(fp, "Deleted "); + print_bool(PRINT_ANY, "deleted", "Deleted ", true); if (tb[IFAL_ADDRESS]) { - fprintf(fp, "prefix %s/%u ", - format_host_rta(ifal->ifal_family, - tb[IFAL_ADDRESS]), - ifal->ifal_prefixlen); + const char *host + = format_host_rta(ifal->ifal_family, + tb[IFAL_ADDRESS]); + + print_string(PRINT_FP, NULL, "prefix ", NULL); + print_color_string(PRINT_ANY, + ifa_family_color(ifal->ifal_family), + "address", "%s", host); + + print_uint(PRINT_ANY, "prefixlen", "/%u ", + ifal->ifal_prefixlen); } - if (ifal->ifal_index) - fprintf(fp, "dev %s ", ll_index_to_name(ifal->ifal_index)); + if (ifal->ifal_index) { + print_string(PRINT_FP, NULL, "dev ", NULL); + print_color_string(PRINT_ANY, COLOR_IFNAME, + "ifname", "%s ", + ll_index_to_name(ifal->ifal_index)); + } if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(uint32_t)) { - uint32_t label; + uint32_t label = rta_getattr_u32(RTA_DATA(tb[IFAL_LABEL])); - memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label)); - fprintf(fp, "label %u ", label); + print_uint(PRINT_ANY, + "label", "label %u ", label); } + print_string(PRINT_FP, NULL, "\n", ""); + close_json_object(); - fprintf(fp, "\n"); - fflush(fp); return 0; } @@ -111,10 +123,12 @@ static int ipaddrlabel_list(int argc, char **argv) return 1; } + new_json_obj(json); if (rtnl_dump_filter(&rth, print_addrlabel, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); return 1; } + delete_json_obj(); return 0; } diff --git a/ip/ipfou.c b/ip/ipfou.c index 1f392ade..0cb5e3c7 100644 --- a/ip/ipfou.c +++ b/ip/ipfou.c @@ -22,16 +22,17 @@ #include "libgenl.h" #include "utils.h" #include "ip_common.h" +#include "json_print.h" static void usage(void) { - fprintf(stderr, "Usage: ip fou add port PORT " - "{ ipproto PROTO | gue } [ -6 ]\n"); - fprintf(stderr, " ip fou del port PORT [ -6 ]\n"); - fprintf(stderr, " ip fou show\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Where: PROTO { ipproto-name | 1..255 }\n"); - fprintf(stderr, " PORT { 1..65535 }\n"); + fprintf(stderr, + "Usage: ip fou add port PORT { ipproto PROTO | gue } [ -6 ]\n" + " ip fou del port PORT [ -6 ]\n" + " ip fou show\n" + "\n" + "Where: PROTO { ipproto-name | 1..255 }\n" + " PORT { 1..65535 }\n"); exit(-1); } @@ -77,7 +78,8 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n, } else if (!matches(*argv, "-6")) { family = AF_INET6; } else { - fprintf(stderr, "fou: unknown command \"%s\"?\n", *argv); + fprintf(stderr + , "fou: unknown command \"%s\"?\n", *argv); usage(); return -1; } @@ -138,11 +140,9 @@ static int do_del(int argc, char **argv) static int print_fou_mapping(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE *)arg; struct genlmsghdr *ghdr; struct rtattr *tb[FOU_ATTR_MAX + 1]; int len = n->nlmsg_len; - unsigned family; if (n->nlmsg_type != genl_family) return 0; @@ -154,18 +154,30 @@ static int print_fou_mapping(const struct sockaddr_nl *who, ghdr = NLMSG_DATA(n); parse_rtattr(tb, FOU_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len); + open_json_object(NULL); if (tb[FOU_ATTR_PORT]) - fprintf(fp, "port %u", ntohs(rta_getattr_u16(tb[FOU_ATTR_PORT]))); - if (tb[FOU_ATTR_TYPE] && rta_getattr_u8(tb[FOU_ATTR_TYPE]) == FOU_ENCAP_GUE) - fprintf(fp, " gue"); + print_uint(PRINT_ANY, "port", "port %u", + ntohs(rta_getattr_u16(tb[FOU_ATTR_PORT]))); + + if (tb[FOU_ATTR_TYPE] && + rta_getattr_u8(tb[FOU_ATTR_TYPE]) == FOU_ENCAP_GUE) + print_null(PRINT_ANY, "gue", " gue", NULL); else if (tb[FOU_ATTR_IPPROTO]) - fprintf(fp, " ipproto %u", rta_getattr_u8(tb[FOU_ATTR_IPPROTO])); + print_uint(PRINT_ANY, "ipproto", + " ipproto %u", rta_getattr_u8(tb[FOU_ATTR_IPPROTO])); + if (tb[FOU_ATTR_AF]) { - family = rta_getattr_u8(tb[FOU_ATTR_AF]); + __u8 family = rta_getattr_u8(tb[FOU_ATTR_AF]); + + print_string(PRINT_JSON, "family", NULL, + family_name(family)); + if (family == AF_INET6) - fprintf(fp, " -6"); + print_string(PRINT_FP, NULL, + " -6", NULL); } - fprintf(fp, "\n"); + print_string(PRINT_FP, NULL, "\n", NULL); + close_json_object(); return 0; } @@ -175,7 +187,8 @@ static int do_show(int argc, char **argv) FOU_REQUEST(req, 4096, FOU_CMD_GET, NLM_F_REQUEST | NLM_F_DUMP); if (argc > 0) { - fprintf(stderr, "\"ip fou show\" does not take any arguments.\n"); + fprintf(stderr, + "\"ip fou show\" does not take any arguments.\n"); return -1; } @@ -184,10 +197,13 @@ static int do_show(int argc, char **argv) exit(1); } + new_json_obj(json); if (rtnl_dump_filter(&genl_rth, print_fou_mapping, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); return 1; } + delete_json_obj(); + fflush(stdout); return 0; } @@ -209,6 +225,8 @@ int do_ipfou(int argc, char **argv) return do_del(argc-1, argv+1); if (matches(*argv, "show") == 0) return do_show(argc-1, argv+1); - fprintf(stderr, "Command \"%s\" is unknown, try \"ip fou help\".\n", *argv); + + fprintf(stderr, + "Command \"%s\" is unknown, try \"ip fou help\".\n", *argv); exit(-1); } diff --git a/ip/ipneigh.c b/ip/ipneigh.c index 07354249..925494db 100644 --- a/ip/ipneigh.c +++ b/ip/ipneigh.c @@ -23,6 +23,7 @@ #include "rt_names.h" #include "utils.h" #include "ip_common.h" +#include "json_print.h" #define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY) #define MAX_ROUNDS 10 @@ -189,6 +190,46 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv) return 0; } +static void print_cacheinfo(const struct nda_cacheinfo *ci) +{ + static int hz; + + if (!hz) + hz = get_user_hz(); + + if (ci->ndm_refcnt) + print_uint(PRINT_ANY, "refcnt", + " ref %u", ci->ndm_refcnt); + + print_uint(PRINT_ANY, "used", " used %u", ci->ndm_used / hz); + print_uint(PRINT_ANY, "confirmed", "/%u", ci->ndm_confirmed / hz); + print_uint(PRINT_ANY, "updated", "/u", ci->ndm_updated / hz); +} + +static void print_neigh_state(unsigned int nud) +{ + + open_json_array(PRINT_JSON, + is_json_context() ? "state" : ""); + +#define PRINT_FLAG(f) \ + if (nud & NUD_##f) { \ + nud &= ~NUD_##f; \ + print_string(PRINT_ANY, NULL, " %s", #f); \ + } + + PRINT_FLAG(INCOMPLETE); + PRINT_FLAG(REACHABLE); + PRINT_FLAG(STALE); + PRINT_FLAG(DELAY); + PRINT_FLAG(PROBE); + PRINT_FLAG(FAILED); + PRINT_FLAG(NOARP); + PRINT_FLAG(PERMANENT); +#undef PRINT_FLAG + + close_json_array(PRINT_JSON, NULL); +} int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { @@ -221,7 +262,7 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (!(filter.state&r->ndm_state) && !(r->ndm_flags & NTF_PROXY) && (r->ndm_state || !(filter.state&0x100)) && - (r->ndm_family != AF_DECnet)) + (r->ndm_family != AF_DECnet)) return 0; if (filter.master && !(n->nlmsg_flags & NLM_F_DUMP_FILTERED)) { @@ -262,65 +303,68 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) return 0; } + open_json_object(NULL); if (n->nlmsg_type == RTM_DELNEIGH) - fprintf(fp, "Deleted "); + print_bool(PRINT_ANY, "deleted", "Deleted ", true); else if (n->nlmsg_type == RTM_GETNEIGH) - fprintf(fp, "miss "); + print_null(PRINT_ANY, "miss", "%s ", "miss"); + if (tb[NDA_DST]) { - fprintf(fp, "%s ", - format_host_rta(r->ndm_family, tb[NDA_DST])); + const char *dst; + + dst = format_host_rta(r->ndm_family, tb[NDA_DST]); + print_color_string(PRINT_ANY, + ifa_family_color(r->ndm_family), + "dst", "%s ", dst); } - if (!filter.index && r->ndm_ifindex) - fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex)); + + if (!filter.index && r->ndm_ifindex) { + if (!is_json_context()) + fprintf(fp, "dev "); + + print_color_string(PRINT_ANY, COLOR_IFNAME, + "dev", "%s ", + ll_index_to_name(r->ndm_ifindex)); + } + if (tb[NDA_LLADDR]) { + const char *lladdr; SPRINT_BUF(b1); - fprintf(fp, "lladdr %s", ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]), - RTA_PAYLOAD(tb[NDA_LLADDR]), - ll_index_to_type(r->ndm_ifindex), - b1, sizeof(b1))); - } - if (r->ndm_flags & NTF_ROUTER) { - fprintf(fp, " router"); - } - if (r->ndm_flags & NTF_PROXY) { - fprintf(fp, " proxy"); - } - if (tb[NDA_CACHEINFO] && show_stats) { - struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]); - int hz = get_user_hz(); - if (ci->ndm_refcnt) - printf(" ref %d", ci->ndm_refcnt); - fprintf(fp, " used %d/%d/%d", ci->ndm_used/hz, - ci->ndm_confirmed/hz, ci->ndm_updated/hz); + lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]), + RTA_PAYLOAD(tb[NDA_LLADDR]), + ll_index_to_type(r->ndm_ifindex), + b1, sizeof(b1)); + + if (!is_json_context()) + fprintf(fp, "lladdr "); + + print_color_string(PRINT_ANY, COLOR_MAC, + "lladdr", "%s", lladdr); } - if (tb[NDA_PROBES] && show_stats) { - __u32 p = rta_getattr_u32(tb[NDA_PROBES]); + if (r->ndm_flags & NTF_ROUTER) + print_null(PRINT_ANY, "router", " %s", "router"); - fprintf(fp, " probes %u", p); + if (r->ndm_flags & NTF_PROXY) + print_null(PRINT_ANY, "proxy", " %s", "proxy"); + + if (show_stats) { + if (tb[NDA_CACHEINFO]) + print_cacheinfo(RTA_DATA(tb[NDA_CACHEINFO])); + + if (tb[NDA_PROBES]) + print_uint(PRINT_ANY, "probes", " probes %u", + rta_getattr_u32(tb[NDA_PROBES])); } - if (r->ndm_state) { - int nud = r->ndm_state; + if (r->ndm_state) + print_neigh_state(r->ndm_state); - fprintf(fp, " "); + print_string(PRINT_FP, NULL, "\n", ""); + close_json_object(); + fflush(stdout); -#define PRINT_FLAG(f) if (nud & NUD_##f) { \ - nud &= ~NUD_##f; fprintf(fp, #f "%s", nud ? "," : ""); } - PRINT_FLAG(INCOMPLETE); - PRINT_FLAG(REACHABLE); - PRINT_FLAG(STALE); - PRINT_FLAG(DELAY); - PRINT_FLAG(PROBE); - PRINT_FLAG(FAILED); - PRINT_FLAG(NOARP); - PRINT_FLAG(PERMANENT); -#undef PRINT_FLAG - } - fprintf(fp, "\n"); - - fflush(fp); return 0; } @@ -479,10 +523,12 @@ static int do_show_or_flush(int argc, char **argv, int flush) exit(1); } + new_json_obj(json); if (rtnl_dump_filter(&rth, print_neigh, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } + delete_json_obj(); return 0; } diff --git a/ip/ipnetconf.c b/ip/ipnetconf.c index 76e639a8..03f98ace 100644 --- a/ip/ipnetconf.c +++ b/ip/ipnetconf.c @@ -29,6 +29,10 @@ static struct { int ifindex; } filter; +static const char * const rp_filter_names[] = { + "off", "strict", "loose" +}; + static void usage(void) __attribute__((noreturn)); static void usage(void) @@ -37,9 +41,12 @@ static void usage(void) exit(-1); } -static void print_onoff(FILE *f, const char *flag, __u32 val) +static void print_onoff(FILE *fp, const char *flag, __u32 val) { - fprintf(f, "%s %s ", flag, val ? "on" : "off"); + if (is_json_context()) + print_bool(PRINT_JSON, flag, NULL, val); + else + fprintf(fp, "%s %s ", flag, val ? "on" : "off"); } static struct rtattr *netconf_rta(struct netconfmsg *ncm) @@ -83,50 +90,44 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, if (filter.ifindex && filter.ifindex != ifindex) return 0; - switch (ncm->ncm_family) { - case AF_INET: - fprintf(fp, "ipv4 "); - break; - case AF_INET6: - fprintf(fp, "ipv6 "); - break; - case AF_MPLS: - fprintf(fp, "mpls "); - break; - default: - fprintf(fp, "unknown "); - break; - } + open_json_object(NULL); + print_string(PRINT_ANY, "family", + "%s ", family_name(ncm->ncm_family)); if (tb[NETCONFA_IFINDEX]) { + const char *dev; + switch (ifindex) { case NETCONFA_IFINDEX_ALL: - fprintf(fp, "all "); + dev = "all"; break; case NETCONFA_IFINDEX_DEFAULT: - fprintf(fp, "default "); + dev = "default"; break; default: - fprintf(fp, "dev %s ", ll_index_to_name(ifindex)); + dev = ll_index_to_name(ifindex); break; } + print_color_string(PRINT_ANY, COLOR_IFNAME, + "interface", "%s ", dev); } if (tb[NETCONFA_FORWARDING]) print_onoff(fp, "forwarding", rta_getattr_u32(tb[NETCONFA_FORWARDING])); + if (tb[NETCONFA_RP_FILTER]) { __u32 rp_filter = rta_getattr_u32(tb[NETCONFA_RP_FILTER]); - if (rp_filter == 0) - fprintf(fp, "rp_filter off "); - else if (rp_filter == 1) - fprintf(fp, "rp_filter strict "); - else if (rp_filter == 2) - fprintf(fp, "rp_filter loose "); + if (rp_filter < ARRAY_SIZE(rp_filter_names)) + print_string(PRINT_ANY, "rp_filter", + "rp_filter %s ", + rp_filter_names[rp_filter]); else - fprintf(fp, "rp_filter unknown mode "); + print_uint(PRINT_ANY, "rp_filter", + "rp_filter %u ", rp_filter); } + if (tb[NETCONFA_MC_FORWARDING]) print_onoff(fp, "mc_forwarding", rta_getattr_u32(tb[NETCONFA_MC_FORWARDING])); @@ -142,7 +143,8 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, if (tb[NETCONFA_INPUT]) print_onoff(fp, "input", rta_getattr_u32(tb[NETCONFA_INPUT])); - fprintf(fp, "\n"); + close_json_object(); + print_string(PRINT_FP, NULL, "\n", NULL); fflush(fp); return 0; } @@ -179,7 +181,8 @@ static int do_show(int argc, char **argv) NEXT_ARG(); filter.ifindex = ll_name_to_index(*argv); if (filter.ifindex <= 0) { - fprintf(stderr, "Device \"%s\" does not exist.\n", + fprintf(stderr, + "Device \"%s\" does not exist.\n", *argv); return -1; } @@ -202,10 +205,13 @@ static int do_show(int argc, char **argv) } else { rth.flags = RTNL_HANDLE_F_SUPPRESS_NLERR; dump: - if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNETCONF) < 0) { + if (rtnl_wilddump_request(&rth, filter.family, + RTM_GETNETCONF) < 0) { perror("Cannot send dump request"); exit(1); } + + new_json_obj(json); if (rtnl_dump_filter(&rth, print_netconf2, stdout) < 0) { /* kernel does not support netconf dump on AF_UNSPEC; * fall back to requesting by family @@ -219,6 +225,7 @@ dump: fprintf(stderr, "Dump terminated\n"); exit(1); } + delete_json_obj(); if (preferred_family == AF_UNSPEC && filter.family == AF_INET) { preferred_family = AF_INET6; filter.family = AF_INET6; @@ -240,6 +247,8 @@ int do_ipnetconf(int argc, char **argv) } else return do_show(0, NULL); - fprintf(stderr, "Command \"%s\" is unknown, try \"ip netconf help\".\n", *argv); + fprintf(stderr, + "Command \"%s\" is unknown, try \"ip netconf help\".\n", + *argv); exit(-1); } diff --git a/ip/ipntable.c b/ip/ipntable.c index 2f72c989..92024864 100644 --- a/ip/ipntable.c +++ b/ip/ipntable.c @@ -31,6 +31,7 @@ #include "utils.h" #include "ip_common.h" +#include "json_print.h" static struct { @@ -338,7 +339,191 @@ static const char *ntable_strtime_delta(__u32 msec) return str; } -static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +static void print_ndtconfig(const struct ndt_config *ndtc) +{ + + print_uint(PRINT_ANY, "key_length", + " config key_len %u ", ndtc->ndtc_key_len); + print_uint(PRINT_ANY, "entry_size", + "entry_size %u ", ndtc->ndtc_entry_size); + print_uint(PRINT_ANY, "entries", "entries %u ", ndtc->ndtc_entries); + + print_string(PRINT_FP, NULL, "%s", _SL_); + + print_string(PRINT_ANY, "last_flush", + " last_flush %s ", + ntable_strtime_delta(ndtc->ndtc_last_flush)); + print_string(PRINT_ANY, "last_rand", + "last_rand %s ", + ntable_strtime_delta(ndtc->ndtc_last_rand)); + + print_string(PRINT_FP, NULL, "%s", _SL_); + + print_uint(PRINT_ANY, "hash_rnd", + " hash_rnd %u ", ndtc->ndtc_hash_rnd); + print_0xhex(PRINT_ANY, "hash_mask", + "hash_mask %08x ", ndtc->ndtc_hash_mask); + + print_uint(PRINT_ANY, "hash_chain_gc", + "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc); + print_uint(PRINT_ANY, "proxy_qlen", + "proxy_qlen %u ", ndtc->ndtc_proxy_qlen); + + print_string(PRINT_FP, NULL, "%s", _SL_); +} + +static void print_ndtparams(struct rtattr *tpb[]) +{ + + if (tpb[NDTPA_IFINDEX]) { + __u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]); + + print_string(PRINT_FP, NULL, " dev ", NULL); + print_color_string(PRINT_ANY, COLOR_IFNAME, + "dev", "%s ", ll_index_to_name(ifindex)); + print_string(PRINT_FP, NULL, "%s", _SL_); + } + + print_string(PRINT_FP, NULL, " ", NULL); + if (tpb[NDTPA_REFCNT]) { + __u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]); + + print_uint(PRINT_ANY, "refcnt", "refcnt %u ", refcnt); + } + + if (tpb[NDTPA_REACHABLE_TIME]) { + __u64 reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]); + + print_uint(PRINT_ANY, "reachable", + "reachable %llu ", reachable); + } + + if (tpb[NDTPA_BASE_REACHABLE_TIME]) { + __u64 breachable + = rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]); + + print_uint(PRINT_ANY, "base_reachable", + "base_reachable %llu ", breachable); + } + + if (tpb[NDTPA_RETRANS_TIME]) { + __u64 retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]); + + print_uint(PRINT_ANY, "retrans", "retrans %llu ", retrans); + } + + print_string(PRINT_FP, NULL, "%s ", _SL_); + + if (tpb[NDTPA_GC_STALETIME]) { + __u64 gc_stale = rta_getattr_u64(tpb[NDTPA_GC_STALETIME]); + + print_uint(PRINT_ANY, "gc_stale", "gc_stale %llu ", gc_stale); + } + + if (tpb[NDTPA_DELAY_PROBE_TIME]) { + __u64 delay_probe + = rta_getattr_u64(tpb[NDTPA_DELAY_PROBE_TIME]); + + print_uint(PRINT_ANY, "delay_probe", + "delay_probe %llu ", delay_probe); + } + + if (tpb[NDTPA_QUEUE_LEN]) { + __u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]); + + print_uint(PRINT_ANY, "queue", "queue %u ", queue); + } + + print_string(PRINT_FP, NULL, "%s ", _SL_); + + if (tpb[NDTPA_APP_PROBES]) { + __u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]); + + print_uint(PRINT_ANY, "app_probes", "app_probes %u ", aprobe); + } + + if (tpb[NDTPA_UCAST_PROBES]) { + __u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]); + + print_uint(PRINT_ANY, "ucast_probes", + "ucast_probes %u ", uprobe); + } + + if (tpb[NDTPA_MCAST_PROBES]) { + __u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]); + + print_uint(PRINT_ANY, "mcast_probes", + "mcast_probes %u ", mprobe); + } + + print_string(PRINT_FP, NULL, "%s ", _SL_); + + if (tpb[NDTPA_ANYCAST_DELAY]) { + __u64 anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]); + + print_uint(PRINT_ANY, "anycast_delay", + "anycast_delay %llu ", anycast_delay); + } + + if (tpb[NDTPA_PROXY_DELAY]) { + __u64 proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]); + + print_uint(PRINT_ANY, "proxy_delay", + "proxy_delay %llu ", proxy_delay); + } + + if (tpb[NDTPA_PROXY_QLEN]) { + __u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]); + + print_uint(PRINT_ANY, "proxy_queue", "proxy_queue %u ", pqueue); + } + + if (tpb[NDTPA_LOCKTIME]) { + __u64 locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]); + + print_uint(PRINT_ANY, "locktime", "locktime %llu ", locktime); + } + + print_string(PRINT_FP, NULL, "%s", _SL_); +} + +static void print_ndtstats(const struct ndt_stats *ndts) +{ + + print_string(PRINT_FP, NULL, " stats ", NULL); + + print_uint(PRINT_ANY, "allocs", "allocs %llu ", ndts->ndts_allocs); + print_uint(PRINT_ANY, "destroys", "destroys %llu ", + ndts->ndts_destroys); + print_uint(PRINT_ANY, "hash_grows", "hash_grows %llu ", + ndts->ndts_hash_grows); + + print_string(PRINT_FP, NULL, "%s ", _SL_); + + print_uint(PRINT_ANY, "res_failed", "res_failed %llu ", + ndts->ndts_res_failed); + print_uint(PRINT_ANY, "lookups", "lookups %llu ", ndts->ndts_lookups); + print_uint(PRINT_ANY, "hits", "hits %llu ", ndts->ndts_hits); + + print_string(PRINT_FP, NULL, "%s ", _SL_); + + print_uint(PRINT_ANY, "rcv_probes_mcast", "rcv_probes_mcast %llu ", + ndts->ndts_rcv_probes_mcast); + print_uint(PRINT_ANY, "rcv_probes_ucast", "rcv_probes_ucast %llu ", + ndts->ndts_rcv_probes_ucast); + + print_string(PRINT_FP, NULL, "%s ", _SL_); + + print_uint(PRINT_ANY, "periodic_gc_runs", "periodic_gc_runs %llu ", + ndts->ndts_periodic_gc_runs); + print_uint(PRINT_ANY, "forced_gc_runs", "forced_gc_runs %llu ", + ndts->ndts_forced_gc_runs); + + print_string(PRINT_FP, NULL, "%s", _SL_); +} + +static int print_ntable(const struct sockaddr_nl *who, + struct nlmsghdr *n, void *arg) { FILE *fp = (FILE *)arg; struct ndtmsg *ndtm = NLMSG_DATA(n); @@ -370,6 +555,7 @@ static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void if (filter.name && strcmp(filter.name, name)) return 0; } + if (tb[NDTA_PARMS]) { parse_rtattr(tpb, NDTPA_MAX, RTA_DATA(tb[NDTA_PARMS]), RTA_PAYLOAD(tb[NDTA_PARMS])); @@ -385,227 +571,63 @@ static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void } } - if (ndtm->ndtm_family == AF_INET) - fprintf(fp, "inet "); - else if (ndtm->ndtm_family == AF_INET6) - fprintf(fp, "inet6 "); - else if (ndtm->ndtm_family == AF_DECnet) - fprintf(fp, "dnet "); - else - fprintf(fp, "(%d) ", ndtm->ndtm_family); + open_json_object(NULL); + print_string(PRINT_ANY, "family", + "%s ", family_name(ndtm->ndtm_family)); if (tb[NDTA_NAME]) { const char *name = rta_getattr_str(tb[NDTA_NAME]); - fprintf(fp, "%s ", name); + print_string(PRINT_ANY, "name", "%s ", name); } - fprintf(fp, "%s", _SL_); + print_string(PRINT_FP, NULL, "%s", _SL_); ret = (tb[NDTA_THRESH1] || tb[NDTA_THRESH2] || tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]); if (ret) - fprintf(fp, " "); + print_string(PRINT_FP, NULL, " ", NULL); if (tb[NDTA_THRESH1]) { __u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]); - fprintf(fp, "thresh1 %u ", thresh1); + print_uint(PRINT_ANY, "thresh1", "thresh1 %u ", thresh1); } + if (tb[NDTA_THRESH2]) { __u32 thresh2 = rta_getattr_u32(tb[NDTA_THRESH2]); - fprintf(fp, "thresh2 %u ", thresh2); + print_uint(PRINT_ANY, "thresh2", "thresh2 %u ", thresh2); } + if (tb[NDTA_THRESH3]) { __u32 thresh3 = rta_getattr_u32(tb[NDTA_THRESH3]); - fprintf(fp, "thresh3 %u ", thresh3); + print_uint(PRINT_ANY, "thresh3", "thresh3 %u ", thresh3); } - if (tb[NDTA_GC_INTERVAL]) { - unsigned long long gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]); - fprintf(fp, "gc_int %llu ", gc_int); + if (tb[NDTA_GC_INTERVAL]) { + __u64 gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]); + + print_uint(PRINT_ANY, "gc_interval", "gc_int %llu ", gc_int); } if (ret) - fprintf(fp, "%s", _SL_); + print_string(PRINT_FP, NULL, "%s", _SL_); - if (tb[NDTA_CONFIG] && show_stats) { - struct ndt_config *ndtc = RTA_DATA(tb[NDTA_CONFIG]); + if (tb[NDTA_CONFIG] && show_stats) + print_ndtconfig(RTA_DATA(tb[NDTA_CONFIG])); - fprintf(fp, " "); - fprintf(fp, "config "); + if (tb[NDTA_PARMS]) + print_ndtparams(tpb); - fprintf(fp, "key_len %u ", ndtc->ndtc_key_len); - fprintf(fp, "entry_size %u ", ndtc->ndtc_entry_size); - fprintf(fp, "entries %u ", ndtc->ndtc_entries); - - fprintf(fp, "%s", _SL_); - fprintf(fp, " "); - - fprintf(fp, "last_flush %s ", - ntable_strtime_delta(ndtc->ndtc_last_flush)); - fprintf(fp, "last_rand %s ", - ntable_strtime_delta(ndtc->ndtc_last_rand)); - - fprintf(fp, "%s", _SL_); - fprintf(fp, " "); - - fprintf(fp, "hash_rnd %u ", ndtc->ndtc_hash_rnd); - fprintf(fp, "hash_mask %08x ", ndtc->ndtc_hash_mask); - - fprintf(fp, "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc); - fprintf(fp, "proxy_qlen %u ", ndtc->ndtc_proxy_qlen); - - fprintf(fp, "%s", _SL_); - } - - if (tb[NDTA_PARMS]) { - if (tpb[NDTPA_IFINDEX]) { - __u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]); - - fprintf(fp, " "); - fprintf(fp, "dev %s ", ll_index_to_name(ifindex)); - fprintf(fp, "%s", _SL_); - } - - fprintf(fp, " "); - - if (tpb[NDTPA_REFCNT]) { - __u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]); - - fprintf(fp, "refcnt %u ", refcnt); - } - if (tpb[NDTPA_REACHABLE_TIME]) { - unsigned long long reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]); - - fprintf(fp, "reachable %llu ", reachable); - } - if (tpb[NDTPA_BASE_REACHABLE_TIME]) { - unsigned long long breachable = rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]); - - fprintf(fp, "base_reachable %llu ", breachable); - } - if (tpb[NDTPA_RETRANS_TIME]) { - unsigned long long retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]); - - fprintf(fp, "retrans %llu ", retrans); - } - - fprintf(fp, "%s", _SL_); - - fprintf(fp, " "); - - if (tpb[NDTPA_GC_STALETIME]) { - unsigned long long gc_stale = rta_getattr_u64(tpb[NDTPA_GC_STALETIME]); - - fprintf(fp, "gc_stale %llu ", gc_stale); - } - if (tpb[NDTPA_DELAY_PROBE_TIME]) { - unsigned long long delay_probe = rta_getattr_u64(tpb[NDTPA_DELAY_PROBE_TIME]); - - fprintf(fp, "delay_probe %llu ", delay_probe); - } - if (tpb[NDTPA_QUEUE_LEN]) { - __u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]); - - fprintf(fp, "queue %u ", queue); - } - - fprintf(fp, "%s", _SL_); - - fprintf(fp, " "); - - if (tpb[NDTPA_APP_PROBES]) { - __u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]); - - fprintf(fp, "app_probes %u ", aprobe); - } - if (tpb[NDTPA_UCAST_PROBES]) { - __u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]); - - fprintf(fp, "ucast_probes %u ", uprobe); - } - if (tpb[NDTPA_MCAST_PROBES]) { - __u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]); - - fprintf(fp, "mcast_probes %u ", mprobe); - } - - fprintf(fp, "%s", _SL_); - - fprintf(fp, " "); - - if (tpb[NDTPA_ANYCAST_DELAY]) { - unsigned long long anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]); - - fprintf(fp, "anycast_delay %llu ", anycast_delay); - } - if (tpb[NDTPA_PROXY_DELAY]) { - unsigned long long proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]); - - fprintf(fp, "proxy_delay %llu ", proxy_delay); - } - if (tpb[NDTPA_PROXY_QLEN]) { - __u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]); - - fprintf(fp, "proxy_queue %u ", pqueue); - } - if (tpb[NDTPA_LOCKTIME]) { - unsigned long long locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]); - - fprintf(fp, "locktime %llu ", locktime); - } - - fprintf(fp, "%s", _SL_); - } - - if (tb[NDTA_STATS] && show_stats) { - struct ndt_stats *ndts = RTA_DATA(tb[NDTA_STATS]); - - fprintf(fp, " "); - fprintf(fp, "stats "); - - fprintf(fp, "allocs %llu ", - (unsigned long long) ndts->ndts_allocs); - fprintf(fp, "destroys %llu ", - (unsigned long long) ndts->ndts_destroys); - fprintf(fp, "hash_grows %llu ", - (unsigned long long) ndts->ndts_hash_grows); - - fprintf(fp, "%s", _SL_); - fprintf(fp, " "); - - fprintf(fp, "res_failed %llu ", - (unsigned long long) ndts->ndts_res_failed); - fprintf(fp, "lookups %llu ", - (unsigned long long) ndts->ndts_lookups); - fprintf(fp, "hits %llu ", - (unsigned long long) ndts->ndts_hits); - - fprintf(fp, "%s", _SL_); - fprintf(fp, " "); - - fprintf(fp, "rcv_probes_mcast %llu ", - (unsigned long long) ndts->ndts_rcv_probes_mcast); - fprintf(fp, "rcv_probes_ucast %llu ", - (unsigned long long) ndts->ndts_rcv_probes_ucast); - - fprintf(fp, "%s", _SL_); - fprintf(fp, " "); - - fprintf(fp, "periodic_gc_runs %llu ", - (unsigned long long) ndts->ndts_periodic_gc_runs); - fprintf(fp, "forced_gc_runs %llu ", - (unsigned long long) ndts->ndts_forced_gc_runs); - - fprintf(fp, "%s", _SL_); - } - - fprintf(fp, "\n"); + if (tb[NDTA_STATS] && show_stats) + print_ndtstats(RTA_DATA(tb[NDTA_STATS])); + print_string(PRINT_FP, NULL, "\n", ""); + close_json_object(); fflush(fp); + return 0; } @@ -643,10 +665,12 @@ static int ipntable_show(int argc, char **argv) exit(1); } + new_json_obj(json); if (rtnl_dump_filter(&rth, print_ntable, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } + delete_json_obj(); return 0; } diff --git a/ip/iprule.c b/ip/iprule.c index 6fdc9b5e..a49753e6 100644 --- a/ip/iprule.c +++ b/ip/iprule.c @@ -26,6 +26,7 @@ #include "rt_names.h" #include "utils.h" #include "ip_common.h" +#include "json_print.h" enum list_action { IPRULE_LIST, @@ -179,13 +180,12 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len) int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { - FILE *fp = (FILE *)arg; + FILE *fp = arg; struct fib_rule_hdr *frh = NLMSG_DATA(n); int len = n->nlmsg_len; int host_len = -1; - __u32 table; + __u32 table, prio = 0; struct rtattr *tb[FRA_MAX+1]; - SPRINT_BUF(b1); if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE) @@ -202,50 +202,54 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) if (!filter_nlmsg(n, tb, host_len)) return 0; + open_json_object(NULL); if (n->nlmsg_type == RTM_DELRULE) - fprintf(fp, "Deleted "); + print_bool(PRINT_ANY, "deleted", "Deleted ", true); if (tb[FRA_PRIORITY]) - fprintf(fp, "%u:\t", - rta_getattr_u32(tb[FRA_PRIORITY])); - else - fprintf(fp, "0:\t"); + prio = rta_getattr_u32(tb[FRA_PRIORITY]); + + print_uint(PRINT_ANY, "priority", "%u:\t", prio); if (frh->flags & FIB_RULE_INVERT) - fprintf(fp, "not "); + print_null(PRINT_ANY, "not", "not ", NULL); if (tb[FRA_SRC]) { - if (frh->src_len != host_len) { - fprintf(fp, "from %s/%u ", - rt_addr_n2a_rta(frh->family, tb[FRA_SRC]), - frh->src_len); - } else { - fprintf(fp, "from %s ", - format_host_rta(frh->family, tb[FRA_SRC])); - } + const char *src = rt_addr_n2a_rta(frh->family, tb[FRA_SRC]); + + print_string(PRINT_FP, NULL, "from ", NULL); + print_color_string(PRINT_ANY, ifa_family_color(frh->family), + "src", "%s", src); + if (frh->src_len != host_len) + print_uint(PRINT_ANY, "srclen", "/%u ", frh->src_len); + else + print_string(PRINT_FP, NULL, " ", NULL); } else if (frh->src_len) { - fprintf(fp, "from 0/%d ", frh->src_len); + print_string(PRINT_ANY, "src", "from %s", "0"); + print_uint(PRINT_ANY, "srclen", "/%u ", frh->src_len); } else { - fprintf(fp, "from all "); + print_string(PRINT_ANY, "src", "from %s ", "all"); } if (tb[FRA_DST]) { - if (frh->dst_len != host_len) { - fprintf(fp, "to %s/%u ", - rt_addr_n2a_rta(frh->family, tb[FRA_DST]), - frh->dst_len); - } else { - fprintf(fp, "to %s ", - format_host_rta(frh->family, tb[FRA_DST])); - } + const char *dst = rt_addr_n2a_rta(frh->family, tb[FRA_DST]); + + print_string(PRINT_FP, NULL, "to ", NULL); + print_color_string(PRINT_ANY, ifa_family_color(frh->family), + "dst", "%s ", dst); + if (frh->dst_len != host_len) + print_uint(PRINT_ANY, "dstlen", "/%u ", frh->dst_len); + else + print_string(PRINT_FP, NULL, " ", NULL); } else if (frh->dst_len) { - fprintf(fp, "to 0/%d ", frh->dst_len); + print_string(PRINT_ANY, "dst", "to %s", "0"); + print_uint(PRINT_ANY, "dstlen", "/%u ", frh->dst_len); } if (frh->tos) { - SPRINT_BUF(b1); - fprintf(fp, "tos %s ", - rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1))); + print_string(PRINT_ANY, "tos", + "tos %s ", + rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1))); } if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) { @@ -255,53 +259,76 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) mark = rta_getattr_u32(tb[FRA_FWMARK]); if (tb[FRA_FWMASK] && - (mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF) - fprintf(fp, "fwmark 0x%x/0x%x ", mark, mask); - else - fprintf(fp, "fwmark 0x%x ", mark); + (mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF) { + print_0xhex(PRINT_ANY, "fwmark", "fwmark 0x%x", mark); + print_0xhex(PRINT_ANY, "fwmask", "/0x%x ", mask); + } else { + print_0xhex(PRINT_ANY, "fwmark", "fwmark 0x%x ", mark); + } } if (tb[FRA_IFNAME]) { - fprintf(fp, "iif %s ", rta_getattr_str(tb[FRA_IFNAME])); + if (!is_json_context()) + fprintf(fp, "iif "); + print_color_string(PRINT_ANY, COLOR_IFNAME, + "iif", "%s ", + rta_getattr_str(tb[FRA_IFNAME])); + if (frh->flags & FIB_RULE_IIF_DETACHED) - fprintf(fp, "[detached] "); + print_null(PRINT_ANY, "iif_detached", "[detached] ", + NULL); } if (tb[FRA_OIFNAME]) { - fprintf(fp, "oif %s ", rta_getattr_str(tb[FRA_OIFNAME])); + if (!is_json_context()) + fprintf(fp, "oif "); + + print_color_string(PRINT_ANY, COLOR_IFNAME, "oif", "%s ", + rta_getattr_str(tb[FRA_OIFNAME])); + if (frh->flags & FIB_RULE_OIF_DETACHED) - fprintf(fp, "[detached] "); + print_null(PRINT_ANY, "oif_detached", "[detached] ", + NULL); } if (tb[FRA_L3MDEV]) { - if (rta_getattr_u8(tb[FRA_L3MDEV])) - fprintf(fp, "lookup [l3mdev-table] "); + __u8 mdev = rta_getattr_u8(tb[FRA_L3MDEV]); + + if (mdev) + print_null(PRINT_ANY, "l3mdev", + "lookup [l3mdev-table] ", NULL); } if (tb[FRA_UID_RANGE]) { struct fib_rule_uid_range *r = RTA_DATA(tb[FRA_UID_RANGE]); - fprintf(fp, "uidrange %u-%u ", r->start, r->end); + print_uint(PRINT_ANY, "uid_start", "uidrange %u", r->start); + print_uint(PRINT_ANY, "uid_end", "-%u ", r->end); } table = frh_get_table(frh, tb); if (table) { - fprintf(fp, "lookup %s ", - rtnl_rttable_n2a(table, b1, sizeof(b1))); + print_string(PRINT_ANY, "table", + "lookup %s ", + rtnl_rttable_n2a(table, b1, sizeof(b1))); if (tb[FRA_SUPPRESS_PREFIXLEN]) { int pl = rta_getattr_u32(tb[FRA_SUPPRESS_PREFIXLEN]); if (pl != -1) - fprintf(fp, "suppress_prefixlength %d ", pl); + print_int(PRINT_ANY, "suppress_prefixlen", + "suppress_prefixlength %d ", pl); } + if (tb[FRA_SUPPRESS_IFGROUP]) { int group = rta_getattr_u32(tb[FRA_SUPPRESS_IFGROUP]); if (group != -1) { - SPRINT_BUF(b1); - fprintf(fp, "suppress_ifgroup %s ", - rtnl_group_n2a(group, b1, sizeof(b1))); + const char *grname + = rtnl_group_n2a(group, b1, sizeof(b1)); + + print_string(PRINT_ANY, "suppress_ifgroup", + "suppress_ifgroup %s ", grname); } } } @@ -311,47 +338,52 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) __u32 from = to>>16; to &= 0xFFFF; - if (from) { - fprintf(fp, "realms %s/", - rtnl_rtrealm_n2a(from, b1, sizeof(b1))); - } - fprintf(fp, "%s ", - rtnl_rtrealm_n2a(to, b1, sizeof(b1))); + if (from) + print_string(PRINT_ANY, + "flow_from", "realms %s/", + rtnl_rtrealm_n2a(from, b1, sizeof(b1))); + + print_string(PRINT_ANY, "flow_to", "%s ", + rtnl_rtrealm_n2a(to, b1, sizeof(b1))); } if (frh->action == RTN_NAT) { if (tb[RTA_GATEWAY]) { - fprintf(fp, "map-to %s ", - format_host_rta(frh->family, - tb[RTA_GATEWAY])); - } else - fprintf(fp, "masquerade"); + const char *gateway; + + gateway = format_host_rta(frh->family, tb[RTA_GATEWAY]); + + print_string(PRINT_ANY, "nat_gateway", + "map-to %s ", gateway); + } else { + print_null(PRINT_ANY, "masquerade", "masquerade", NULL); + } } else if (frh->action == FR_ACT_GOTO) { - fprintf(fp, "goto "); if (tb[FRA_GOTO]) - fprintf(fp, "%u", rta_getattr_u32(tb[FRA_GOTO])); + print_uint(PRINT_ANY, "goto", "goto %u", + rta_getattr_u32(tb[FRA_GOTO])); else - fprintf(fp, "none"); + print_string(PRINT_ANY, "goto", "goto %s", "none"); + if (frh->flags & FIB_RULE_UNRESOLVED) - fprintf(fp, " [unresolved]"); - } else if (frh->action == FR_ACT_NOP) - fprintf(fp, "nop"); - else if (frh->action != FR_ACT_TO_TBL) - fprintf(fp, "%s", - rtnl_rtntype_n2a(frh->action, - b1, sizeof(b1))); + print_null(PRINT_ANY, "unresolved", "unresolved", NULL); + } else if (frh->action == FR_ACT_NOP) { + print_null(PRINT_ANY, "nop", "nop", NULL); + } else if (frh->action != FR_ACT_TO_TBL) { + print_string(PRINT_ANY, "to_tbl", "%s", + rtnl_rtntype_n2a(frh->action, b1, sizeof(b1))); + } if (tb[FRA_PROTOCOL]) { __u8 protocol = rta_getattr_u8(tb[FRA_PROTOCOL]); - if ((protocol && protocol != RTPROT_KERNEL) || - show_details > 0) { - fprintf(fp, " proto %s ", - rtnl_rtprot_n2a(protocol, b1, sizeof(b1))); + if ((protocol && protocol != RTPROT_KERNEL) || show_details > 0) { + print_string(PRINT_ANY, "protocol", " proto %s ", + rtnl_rtprot_n2a(protocol, b1, sizeof(b1))); } } - - fprintf(fp, "\n"); + print_string(PRINT_FP, NULL, "\n", ""); + close_json_object(); fflush(fp); return 0; } @@ -554,10 +586,12 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action) return 1; } + new_json_obj(json); if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); return 1; } + delete_json_obj(); return 0; } diff --git a/ip/ipseg6.c b/ip/ipseg6.c index e3ab31a5..6f5ae4d2 100644 --- a/ip/ipseg6.c +++ b/ip/ipseg6.c @@ -26,6 +26,7 @@ #include "utils.h" #include "ip_common.h" #include "libgenl.h" +#include "json_print.h" #define HMAC_KEY_PROMPT "Enter secret for HMAC key ID (blank to delete): " @@ -55,12 +56,54 @@ static struct { __u8 alg_id; } opts; +static void print_dumphmac(struct rtattr *attrs[]) +{ + char secret[64]; + char *algstr; + __u8 slen = rta_getattr_u8(attrs[SEG6_ATTR_SECRETLEN]); + __u8 alg_id = rta_getattr_u8(attrs[SEG6_ATTR_ALGID]); + + memset(secret, 0, 64); + + if (slen > 63) { + fprintf(stderr, "HMAC secret length %d > 63, truncated\n", slen); + slen = 63; + } + + memcpy(secret, RTA_DATA(attrs[SEG6_ATTR_SECRET]), slen); + + switch (alg_id) { + case SEG6_HMAC_ALGO_SHA1: + algstr = "sha1"; + break; + case SEG6_HMAC_ALGO_SHA256: + algstr = "sha256"; + break; + default: + algstr = ""; + } + + print_uint(PRINT_ANY, "hmac", "hmac %u ", + rta_getattr_u32(attrs[SEG6_ATTR_HMACKEYID])); + print_string(PRINT_ANY, "algo", "algo %s ", algstr); + print_string(PRINT_ANY, "secret", "secret \"%s\"\n", secret); +} + +static void print_tunsrc(struct rtattr *attrs[]) +{ + const char *dst + = rt_addr_n2a(AF_INET6, 16, + RTA_DATA(attrs[SEG6_ATTR_DST])); + + print_string(PRINT_ANY, "tunsrc", + "tunsrc addr %s\n", dst); +} + static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct rtattr *attrs[SEG6_ATTR_MAX + 1]; struct genlmsghdr *ghdr; - FILE *fp = (FILE *)arg; int len = n->nlmsg_len; if (n->nlmsg_type != genl_family) @@ -74,50 +117,17 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, parse_rtattr(attrs, SEG6_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len); + open_json_object(NULL); switch (ghdr->cmd) { case SEG6_CMD_DUMPHMAC: - { - char secret[64]; - char *algstr; - __u8 slen = rta_getattr_u8(attrs[SEG6_ATTR_SECRETLEN]); - __u8 alg_id = rta_getattr_u8(attrs[SEG6_ATTR_ALGID]); - - memset(secret, 0, 64); - - if (slen > 63) { - fprintf(stderr, "HMAC secret length %d > 63, " - "truncated\n", slen); - slen = 63; - } - memcpy(secret, RTA_DATA(attrs[SEG6_ATTR_SECRET]), slen); - - switch (alg_id) { - case SEG6_HMAC_ALGO_SHA1: - algstr = "sha1"; - break; - case SEG6_HMAC_ALGO_SHA256: - algstr = "sha256"; - break; - default: - algstr = ""; - } - - fprintf(fp, "hmac %u ", - rta_getattr_u32(attrs[SEG6_ATTR_HMACKEYID])); - fprintf(fp, "algo %s ", algstr); - fprintf(fp, "secret \"%s\" ", secret); - - fprintf(fp, "\n"); + print_dumphmac(attrs); break; - } + case SEG6_CMD_GET_TUNSRC: - { - fprintf(fp, "tunsrc addr %s\n", - rt_addr_n2a(AF_INET6, 16, - RTA_DATA(attrs[SEG6_ATTR_DST]))); + print_tunsrc(attrs); break; } - } + close_json_object(); return 0; } @@ -169,10 +179,12 @@ static int seg6_do_cmd(void) } else if (repl) { if (rtnl_talk(&grth, &req.n, &answer) < 0) return -2; + new_json_obj(json); if (process_msg(NULL, answer, stdout) < 0) { fprintf(stderr, "Error parsing reply\n"); exit(1); } + delete_json_obj(); free(answer); } else { req.n.nlmsg_flags |= NLM_F_DUMP; @@ -182,10 +194,13 @@ static int seg6_do_cmd(void) exit(1); } + new_json_obj(json); if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } + delete_json_obj(); + fflush(stdout); } return 0; diff --git a/ip/iptoken.c b/ip/iptoken.c index 48cc14b5..fb64da4e 100644 --- a/ip/iptoken.c +++ b/ip/iptoken.c @@ -25,6 +25,7 @@ #include "rt_names.h" #include "utils.h" #include "ip_common.h" +#include "json_print.h" extern struct rtnl_handle rth; @@ -77,9 +78,17 @@ static int print_token(const struct sockaddr_nl *who, struct nlmsghdr *n, void * return -1; } - fprintf(fp, "token %s dev %s\n", - format_host_rta(ifi->ifi_family, ltb[IFLA_INET6_TOKEN]), - ll_index_to_name(ifi->ifi_index)); + open_json_object(NULL); + print_string(PRINT_FP, NULL, "token ", NULL); + print_color_string(PRINT_ANY, + ifa_family_color(ifi->ifi_family), + "token", "%s", + format_host_rta(ifi->ifi_family, ltb[IFLA_INET6_TOKEN])); + print_string(PRINT_FP, NULL, " dev ", NULL); + print_color_string(PRINT_ANY, COLOR_IFNAME, + "ifname", "%s\n", + ll_index_to_name(ifi->ifi_index)); + close_json_object(); fflush(fp); return 0; @@ -105,10 +114,13 @@ static int iptoken_list(int argc, char **argv) return -1; } + new_json_obj(json); if (rtnl_dump_filter(&rth, print_token, &da) < 0) { + delete_json_obj(); fprintf(stderr, "Dump terminated\n"); return -1; } + delete_json_obj(); return 0; } diff --git a/ip/iptuntap.c b/ip/iptuntap.c index 2f49ff6d..6c5a7259 100644 --- a/ip/iptuntap.c +++ b/ip/iptuntap.c @@ -228,24 +228,35 @@ static int do_del(int argc, char **argv) static void print_flags(long flags) { + open_json_array(PRINT_JSON, "flags"); + if (flags & IFF_TUN) - printf(" tun"); + print_string(PRINT_ANY, NULL, " %s", "tun"); if (flags & IFF_TAP) - printf(" tap"); + print_string(PRINT_ANY, NULL, " %s", "tap"); if (!(flags & IFF_NO_PI)) - printf(" pi"); + print_string(PRINT_ANY, NULL, " %s", "pi"); if (flags & IFF_ONE_QUEUE) - printf(" one_queue"); + print_string(PRINT_ANY, NULL, " %s", "one_queue"); if (flags & IFF_VNET_HDR) - printf(" vnet_hdr"); + print_string(PRINT_ANY, NULL, " %s", "vnet_hdr"); - flags &= ~(IFF_TUN|IFF_TAP|IFF_NO_PI|IFF_ONE_QUEUE|IFF_VNET_HDR); + if (flags & IFF_PERSIST) + print_string(PRINT_ANY, NULL, " %s", "persist"); + + if (!(flags & IFF_NOFILTER)) + print_string(PRINT_ANY, NULL, " %s", "filter"); + + flags &= ~(IFF_TUN | IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE | + IFF_VNET_HDR | IFF_PERSIST | IFF_NOFILTER); if (flags) - printf(" UNKNOWN_FLAGS:%lx", flags); + print_0xhex(PRINT_ANY, NULL, "%#x", flags); + + close_json_array(PRINT_JSON, NULL); } static char *pid_name(pid_t pid) @@ -288,6 +299,8 @@ static void show_processes(const char *name) if (err) return; + open_json_array(PRINT_JSON, "processes"); + fd_path = globbuf.gl_pathv; while (*fd_path) { const char *dev_net_tun = "/dev/net/tun"; @@ -334,7 +347,11 @@ static void show_processes(const char *name) !strcmp(name, value)) { char *pname = pid_name(pid); - printf(" %s(%d)", pname ? : "", pid); + print_string(PRINT_ANY, "name", + "%s", pname ? : ""); + + print_uint(PRINT_ANY, "pid", + "(%d)", pid); free(pname); } @@ -347,6 +364,7 @@ static void show_processes(const char *name) next: ++fd_path; } + close_json_array(PRINT_JSON, NULL); globfree(&globbuf); } @@ -417,18 +435,24 @@ static int print_tuntap(const struct sockaddr_nl *who, if (read_prop(name, "group", &group)) return 0; - printf("%s:", name); + open_json_object(NULL); + print_color_string(PRINT_ANY, COLOR_IFNAME, + "ifname", "%s:", name); print_flags(flags); if (owner != -1) - printf(" user %ld", owner); + print_uint(PRINT_ANY, "user", + " user %ld", owner); if (group != -1) - printf(" group %ld", group); - fputc('\n', stdout); + print_uint(PRINT_ANY, "group", + " group %ld", group); + if (show_details) { - printf("\tAttached to processes:"); + print_string(PRINT_FP, NULL, + "%s\tAttached to processes:", _SL_); show_processes(name); - fputc('\n', stdout); } + close_json_object(); + print_string(PRINT_FP, NULL, "%s", "\n"); return 0; } @@ -441,11 +465,16 @@ static int do_show(int argc, char **argv) return -1; } + new_json_obj(json); + if (rtnl_dump_filter(&rth, print_tuntap, NULL) < 0) { fprintf(stderr, "Dump terminated\n"); return -1; } + delete_json_obj(); + fflush(stdout); + return 0; } diff --git a/ip/tcp_metrics.c b/ip/tcp_metrics.c index 7e2d9eb3..72dc980c 100644 --- a/ip/tcp_metrics.c +++ b/ip/tcp_metrics.c @@ -38,6 +38,7 @@ static void usage(void) /* netlink socket */ static struct rtnl_handle grth = { .fd = -1 }; static int genl_family = -1; +static const double usec_per_sec = 1000000.; #define TCPM_REQUEST(_req, _bufsiz, _cmd, _flags) \ GENL_REQUEST(_req, _bufsiz, genl_family, 0, \ @@ -47,8 +48,8 @@ static int genl_family = -1; #define CMD_DEL 0x0002 /* delete, remove */ #define CMD_FLUSH 0x0004 /* flush */ -static struct { - char *name; +static const struct { + const char *name; int code; } cmds[] = { { "list", CMD_LIST }, @@ -59,7 +60,7 @@ static struct { { "flush", CMD_FLUSH }, }; -static char *metric_name[TCP_METRIC_MAX + 1] = { +static const char *metric_name[TCP_METRIC_MAX + 1] = { [TCP_METRIC_RTT] = "rtt", [TCP_METRIC_RTTVAR] = "rttvar", [TCP_METRIC_SSTHRESH] = "ssthresh", @@ -67,8 +68,7 @@ static char *metric_name[TCP_METRIC_MAX + 1] = { [TCP_METRIC_REORDERING] = "reordering", }; -static struct -{ +static struct { int flushed; char *flushb; int flushp; @@ -88,15 +88,84 @@ static int flush_update(void) return 0; } +static void print_tcp_metrics(struct rtattr *a) +{ + struct rtattr *m[TCP_METRIC_MAX + 1 + 1]; + unsigned long rtt = 0, rttvar = 0; + int i; + + parse_rtattr_nested(m, TCP_METRIC_MAX + 1, a); + + for (i = 0; i < TCP_METRIC_MAX + 1; i++) { + const char *name; + __u32 val; + SPRINT_BUF(b1); + + a = m[i + 1]; + if (!a) + continue; + + val = rta_getattr_u32(a); + + switch (i) { + case TCP_METRIC_RTT: + if (!rtt) + rtt = (val * 1000UL) >> 3; + continue; + case TCP_METRIC_RTTVAR: + if (!rttvar) + rttvar = (val * 1000UL) >> 2; + continue; + case TCP_METRIC_RTT_US: + rtt = val >> 3; + continue; + + case TCP_METRIC_RTTVAR_US: + rttvar = val >> 2; + continue; + + case TCP_METRIC_SSTHRESH: + case TCP_METRIC_CWND: + case TCP_METRIC_REORDERING: + name = metric_name[i]; + break; + + default: + snprintf(b1, sizeof(b1), + " metric_%d ", i); + name = b1; + } + + + print_uint(PRINT_JSON, name, NULL, val); + print_string(PRINT_FP, NULL, " %s ", name); + print_uint(PRINT_FP, NULL, "%lu", val); + } + + if (rtt) { + print_float(PRINT_JSON, "rtt", NULL, + (double)rtt / usec_per_sec); + print_uint(PRINT_FP, NULL, + " rtt %luus", rtt); + } + if (rttvar) { + print_float(PRINT_JSON, "rttvar", NULL, + (double) rttvar / usec_per_sec); + print_uint(PRINT_FP, NULL, + " rttvar %luus", rttvar); + } +} + static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE *) arg; struct genlmsghdr *ghdr; struct rtattr *attrs[TCP_METRICS_ATTR_MAX + 1], *a; + const char *h; int len = n->nlmsg_len; inet_prefix daddr, saddr; - int i, atype, stype; + int atype, stype; if (n->nlmsg_type != genl_family) return -1; @@ -186,96 +255,60 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, return 0; } + open_json_object(NULL); if (f.cmd & (CMD_DEL | CMD_FLUSH)) - fprintf(fp, "Deleted "); + print_bool(PRINT_ANY, "deleted", "Deleted ", true); - fprintf(fp, "%s", - format_host(daddr.family, daddr.bytelen, daddr.data)); + h = format_host(daddr.family, daddr.bytelen, daddr.data); + print_color_string(PRINT_ANY, + ifa_family_color(daddr.family), + "dst", "%s", h); a = attrs[TCP_METRICS_ATTR_AGE]; if (a) { - unsigned long long val = rta_getattr_u64(a); + __u64 val = rta_getattr_u64(a); + double age = val / 1000.; - fprintf(fp, " age %llu.%03llusec", - val / 1000, val % 1000); + print_float(PRINT_ANY, "age", + " age %.03fsec", age); } a = attrs[TCP_METRICS_ATTR_TW_TS_STAMP]; if (a) { __s32 val = (__s32) rta_getattr_u32(a); __u32 tsval; + char tw_ts[64]; a = attrs[TCP_METRICS_ATTR_TW_TSVAL]; tsval = a ? rta_getattr_u32(a) : 0; - fprintf(fp, " tw_ts %u/%dsec ago", tsval, val); + snprintf(tw_ts, sizeof(tw_ts), + "%u/%d", tsval, val); + print_string(PRINT_ANY, "tw_ts_stamp", + " tw_ts %s ago", tw_ts); } - a = attrs[TCP_METRICS_ATTR_VALS]; - if (a) { - struct rtattr *m[TCP_METRIC_MAX + 1 + 1]; - unsigned long rtt = 0, rttvar = 0; - - parse_rtattr_nested(m, TCP_METRIC_MAX + 1, a); - - for (i = 0; i < TCP_METRIC_MAX + 1; i++) { - unsigned long val; - - a = m[i + 1]; - if (!a) - continue; - if (i != TCP_METRIC_RTT && - i != TCP_METRIC_RTT_US && - i != TCP_METRIC_RTTVAR && - i != TCP_METRIC_RTTVAR_US) { - if (metric_name[i]) - fprintf(fp, " %s ", metric_name[i]); - else - fprintf(fp, " metric_%d ", i); - } - val = rta_getattr_u32(a); - switch (i) { - case TCP_METRIC_RTT: - if (!rtt) - rtt = (val * 1000UL) >> 3; - break; - case TCP_METRIC_RTTVAR: - if (!rttvar) - rttvar = (val * 1000UL) >> 2; - break; - case TCP_METRIC_RTT_US: - rtt = val >> 3; - break; - case TCP_METRIC_RTTVAR_US: - rttvar = val >> 2; - break; - case TCP_METRIC_SSTHRESH: - case TCP_METRIC_CWND: - case TCP_METRIC_REORDERING: - default: - fprintf(fp, "%lu", val); - break; - } - } - if (rtt) - fprintf(fp, " rtt %luus", rtt); - if (rttvar) - fprintf(fp, " rttvar %luus", rttvar); - } + if (attrs[TCP_METRICS_ATTR_VALS]) + print_tcp_metrics(attrs[TCP_METRICS_ATTR_VALS]); a = attrs[TCP_METRICS_ATTR_FOPEN_MSS]; - if (a) - fprintf(fp, " fo_mss %u", rta_getattr_u16(a)); + if (a) { + print_uint(PRINT_ANY, "fopen_miss", " fo_mss %u", + rta_getattr_u16(a)); + } a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROPS]; if (a) { __u16 syn_loss = rta_getattr_u16(a); - unsigned long long ts; + double ts; a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS]; ts = a ? rta_getattr_u64(a) : 0; - fprintf(fp, " fo_syn_drops %u/%llu.%03llusec ago", - syn_loss, ts / 1000, ts % 1000); + print_uint(PRINT_ANY, "fopen_syn_drops", + " fo_syn_drops %u", syn_loss); + print_float(PRINT_ANY, "fopen_syn_drop_ts", + "/%.03fusec ago", + ts / 1000000.); } a = attrs[TCP_METRICS_ATTR_FOPEN_COOKIE]; @@ -289,16 +322,21 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, cookie[0] = 0; for (i = 0; i < max; i++) sprintf(cookie + i + i, "%02x", ptr[i]); - fprintf(fp, " fo_cookie %s", cookie); + + print_string(PRINT_ANY, "fo_cookie", + " fo_cookie %s", cookie); } if (saddr.family) { - fprintf(fp, " source %s", - format_host(saddr.family, saddr.bytelen, saddr.data)); + const char *src; + + src = format_host(saddr.family, saddr.bytelen, saddr.data); + print_string(PRINT_ANY, "source", + " source %s", src); } - fprintf(fp, "\n"); - + print_string(PRINT_FP, NULL, "\n", ""); + close_json_object(); fflush(fp); return 0; } @@ -475,10 +513,12 @@ static int tcpm_do_cmd(int cmd, int argc, char **argv) exit(1); } + new_json_obj(json); if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } + delete_json_obj(); } return 0; }