From: Stephen Hemminger <sthem...@microsoft.com> Use json_print to provide json (and color) support to ip neigh command.
Example: $ ip -j -p neigh [ { "dst": "192.168.1.29", "dev": "enp12s0", "state": [ "FAILED" ] },{ "dst": "192.168.1.130", "dev": "enp12s0", "state": [ "FAILED" ] },{ "dst": "192.168.1.131", "dev": "enp12s0", "lladdr": "00:15:5d:2a:16:4f", "state": [ "STALE" ] } ... Signed-off-by: Stephen Hemminger <step...@networkplumber.org> --- ip/ipneigh.c | 140 +++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 93 insertions(+), 47 deletions(-) diff --git a/ip/ipneigh.c b/ip/ipneigh.c index 0735424900f6..925494dbe324 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 (tb[NDA_PROBES] && show_stats) { - __u32 p = rta_getattr_u32(tb[NDA_PROBES]); + if (!is_json_context()) + fprintf(fp, "lladdr "); - fprintf(fp, " probes %u", p); + print_color_string(PRINT_ANY, COLOR_MAC, + "lladdr", "%s", lladdr); } - if (r->ndm_state) { - int nud = r->ndm_state; - - fprintf(fp, " "); - -#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 + if (r->ndm_flags & NTF_ROUTER) + print_null(PRINT_ANY, "router", " %s", "router"); + + 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])); } - fprintf(fp, "\n"); - fflush(fp); + if (r->ndm_state) + print_neigh_state(r->ndm_state); + + print_string(PRINT_FP, NULL, "\n", ""); + close_json_object(); + fflush(stdout); + 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; } -- 2.16.1