From mboxrd@z Thu Jan 1 00:00:00 1970 From: Stephen Hemminger Subject: Re: [PATCH v2 iproute2-next 2/5] bridge: colorize output and use JSON print library Date: Wed, 29 Aug 2018 08:04:53 -0700 Message-ID: <20180829080453.0026d52b@xeon-e3> References: <20180220192408.19763-1-stephen@networkplumber.org> <20180220192408.19763-3-stephen@networkplumber.org> Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Cc: netdev , Stephen Hemminger , Julien Fortin , David Ahern To: Roopa Prabhu Return-path: Received: from mail-pg1-f173.google.com ([209.85.215.173]:38821 "EHLO mail-pg1-f173.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727508AbeH2TCX (ORCPT ); Wed, 29 Aug 2018 15:02:23 -0400 Received: by mail-pg1-f173.google.com with SMTP id e2-v6so2451816pgv.5 for ; Wed, 29 Aug 2018 08:05:01 -0700 (PDT) In-Reply-To: Sender: netdev-owner@vger.kernel.org List-ID: On Sat, 14 Jul 2018 18:41:03 -0700 Roopa Prabhu wrote: > On Tue, Feb 20, 2018 at 11:24 AM, Stephen Hemminger > wrote: > > From: Stephen Hemminger > > > > Use new functions from json_print to simplify code. > > Provide standard flag for colorizing output. > > > > The shortened -c flag is ambiguous it could mean color or > > compressvlan; it is now changed to mean color for consistency > > with other iproute2 commands. > > > > Signed-off-by: Stephen Hemminger > > --- > > bridge/br_common.h | 2 +- > > bridge/bridge.c | 10 +- > > bridge/fdb.c | 281 +++++++++++++++-------------------------- > > bridge/mdb.c | 362 ++++++++++++++++++++++------------------------------- > > bridge/vlan.c | 276 +++++++++++++++------------------------- > > 5 files changed, 363 insertions(+), 568 deletions(-) > > > > diff --git a/bridge/br_common.h b/bridge/br_common.h > > index b25f61e50e05..2f1cb8fd9f3d 100644 > > --- a/bridge/br_common.h > > +++ b/bridge/br_common.h > > @@ -6,7 +6,7 @@ > > #define MDB_RTR_RTA(r) \ > > ((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(__u32)))) > > > > -extern void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex); > > +extern void print_vlan_info(FILE *fp, struct rtattr *tb); > > extern int print_linkinfo(const struct sockaddr_nl *who, > > struct nlmsghdr *n, > > void *arg); > > diff --git a/bridge/bridge.c b/bridge/bridge.c > > index 4b112e3b8da9..e5b4c3c2198f 100644 > > --- a/bridge/bridge.c > > +++ b/bridge/bridge.c > > @@ -16,12 +16,15 @@ > > #include "utils.h" > > #include "br_common.h" > > #include "namespace.h" > > +#include "color.h" > > > > struct rtnl_handle rth = { .fd = -1 }; > > int preferred_family = AF_UNSPEC; > > int oneline; > > int show_stats; > > int show_details; > > +int show_pretty; > > +int color; > > int compress_vlans; > > int json; > > int timestamp; > > @@ -39,7 +42,7 @@ static void usage(void) > > "where OBJECT := { link | fdb | mdb | vlan | monitor }\n" > > " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n" > > " -o[neline] | -t[imestamp] | -n[etns] name |\n" > > -" -c[ompressvlans] -p[retty] -j{son} }\n"); > > +" -c[ompressvlans] -color -p[retty] -j{son} }\n"); > > exit(-1); > > } > > > > @@ -170,6 +173,8 @@ main(int argc, char **argv) > > NEXT_ARG(); > > if (netns_switch(argv[1])) > > exit(-1); > > + } else if (matches(opt, "-color") == 0) { > > + enable_color(); > > } else if (matches(opt, "-compressvlans") == 0) { > > ++compress_vlans; > > } else if (matches(opt, "-force") == 0) { > > @@ -195,6 +200,9 @@ main(int argc, char **argv) > > > > _SL_ = oneline ? "\\" : "\n"; > > > > + if (json) > > + check_if_color_enabled(); > > + > > if (batch_file) > > return batch(batch_file); > > > > diff --git a/bridge/fdb.c b/bridge/fdb.c > > index 93b5b2e694e3..b4f6e8b3a01b 100644 > > --- a/bridge/fdb.c > > +++ b/bridge/fdb.c > > @@ -22,9 +22,9 @@ > > #include > > #include > > #include > > -#include > > #include > > > > +#include "json_print.h" > > #include "libnetlink.h" > > #include "br_common.h" > > #include "rt_names.h" > > @@ -32,8 +32,6 @@ > > > > static unsigned int filter_index, filter_vlan, filter_state; > > > > -json_writer_t *jw_global; > > - > > static void usage(void) > > { > > fprintf(stderr, > > @@ -83,13 +81,46 @@ static int state_a2n(unsigned int *s, const char *arg) > > return 0; > > } > > > > -static void start_json_fdb_flags_array(bool *fdb_flags) > > +static void fdb_print_flags(FILE *fp, unsigned int flags) > > +{ > > + open_json_array(PRINT_JSON, > > + is_json_context() ? "flags" : ""); > > + > > + if (flags & NTF_SELF) > > + print_string(PRINT_ANY, NULL, "%s ", "self"); > > + > > + if (flags & NTF_ROUTER) > > + print_string(PRINT_ANY, NULL, "%s ", "router"); > > + > > + if (flags & NTF_EXT_LEARNED) > > + print_string(PRINT_ANY, NULL, "%s ", "extern_learn"); > > + > > + if (flags & NTF_OFFLOADED) > > + print_string(PRINT_ANY, NULL, "%s ", "offload"); > > + > > + if (flags & NTF_MASTER) > > + print_string(PRINT_ANY, NULL, "%s ", "master"); > > + > > + close_json_array(PRINT_JSON, NULL); > > +} > > + > > +static void fdb_print_stats(FILE *fp, const struct nda_cacheinfo *ci) > > { > > - if (*fdb_flags) > > - return; > > - jsonw_name(jw_global, "flags"); > > - jsonw_start_array(jw_global); > > - *fdb_flags = true; > > + static int hz; > > + > > + if (!hz) > > + hz = get_user_hz(); > > + > > + if (is_json_context()) { > > + print_uint(PRINT_JSON, "used", NULL, > > + ci->ndm_used / hz); > > + print_uint(PRINT_JSON, "updated", NULL, > > + ci->ndm_updated / hz); > > + } else { > > + fprintf(fp, "used %d/%d ", ci->ndm_used / hz, > > + ci->ndm_updated / hz); > > + > > + } > > } > > > > int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) > > @@ -99,8 +130,6 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) > > int len = n->nlmsg_len; > > struct rtattr *tb[NDA_MAX+1]; > > __u16 vid = 0; > > - bool fdb_flags = false; > > - const char *state_s; > > > > if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) { > > fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n", > > @@ -132,189 +161,98 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) > > if (filter_vlan && filter_vlan != vid) > > return 0; > > > > - if (jw_global) > > - jsonw_start_object(jw_global); > > - > > - if (n->nlmsg_type == RTM_DELNEIGH) { > > - if (jw_global) > > - jsonw_string_field(jw_global, "opCode", "deleted"); > > - else > > - fprintf(fp, "Deleted "); > > - } > > + open_json_object(NULL); > > + if (n->nlmsg_type == RTM_DELNEIGH) > > + print_bool(PRINT_ANY, "deleted", "Deleted ", true); > > > > if (tb[NDA_LLADDR]) { > > + const char *lladdr; > > SPRINT_BUF(b1); > > - ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]), > > - RTA_PAYLOAD(tb[NDA_LLADDR]), > > - ll_index_to_type(r->ndm_ifindex), > > - b1, sizeof(b1)); > > - if (jw_global) > > - jsonw_string_field(jw_global, "mac", b1); > > - else > > - fprintf(fp, "%s ", b1); > > + > > + lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]), > > + RTA_PAYLOAD(tb[NDA_LLADDR]), > > + ll_index_to_type(r->ndm_ifindex), > > + b1, sizeof(b1)); > > + > > + print_color_string(PRINT_ANY, COLOR_MAC, > > + "mac", "%s ", lladdr); > > } > > > > if (!filter_index && r->ndm_ifindex) { > > - if (jw_global) > > - jsonw_string_field(jw_global, "dev", > > - ll_index_to_name(r->ndm_ifindex)); > > - else > > - fprintf(fp, "dev %s ", > > - ll_index_to_name(r->ndm_ifindex)); > > + if (!is_json_context()) > > + fprintf(fp, "dev "); > > + print_color_string(PRINT_ANY, COLOR_IFNAME, > > + "ifname", "%s ", > > + ll_index_to_name(r->ndm_ifindex)); > > } > > > > if (tb[NDA_DST]) { > > int family = AF_INET; > > - const char *abuf_s; > > + const char *dst; > > > > if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr)) > > family = AF_INET6; > > > > - abuf_s = format_host(family, > > - RTA_PAYLOAD(tb[NDA_DST]), > > - RTA_DATA(tb[NDA_DST])); > > - if (jw_global) > > - jsonw_string_field(jw_global, "dst", abuf_s); > > - else > > - fprintf(fp, "dst %s ", abuf_s); > > - } > > + dst = format_host(family, > > + RTA_PAYLOAD(tb[NDA_DST]), > > + RTA_DATA(tb[NDA_DST])); > > > > - if (vid) { > > - if (jw_global) > > - jsonw_uint_field(jw_global, "vlan", vid); > > - else > > - fprintf(fp, "vlan %hu ", vid); > > + print_color_string(PRINT_ANY, > > + ifa_family_color(family), > > + "dst", "%s ", dst); > > } > > > > - if (tb[NDA_PORT]) { > > - if (jw_global) > > - jsonw_uint_field(jw_global, "port", > > - rta_getattr_be16(tb[NDA_PORT])); > > - else > > - fprintf(fp, "port %d ", > > - rta_getattr_be16(tb[NDA_PORT])); > > - } > > + if (vid) > > + print_uint(PRINT_ANY, > > + "vlan", "vlan %hu ", vid); > > > > - if (tb[NDA_VNI]) { > > - if (jw_global) > > - jsonw_uint_field(jw_global, "vni", > > - rta_getattr_u32(tb[NDA_VNI])); > > - else > > - fprintf(fp, "vni %d ", > > - rta_getattr_u32(tb[NDA_VNI])); > > - } > > + if (tb[NDA_PORT]) > > + print_uint(PRINT_ANY, > > + "port", "port %u ", > > + rta_getattr_be16(tb[NDA_PORT])); > > > > - if (tb[NDA_SRC_VNI]) { > > - if (jw_global) > > - jsonw_uint_field(jw_global, "src_vni", > > - rta_getattr_u32(tb[NDA_SRC_VNI])); > > - else > > - fprintf(fp, "src_vni %d ", > > + if (tb[NDA_VNI]) > > + print_uint(PRINT_ANY, > > + "vni", "vni %u ", > > + rta_getattr_u32(tb[NDA_VNI])); > > + > > + if (tb[NDA_SRC_VNI]) > > + print_uint(PRINT_ANY, > > + "src_vni", "src_vni %u ", > > rta_getattr_u32(tb[NDA_SRC_VNI])); > > - } > > > > if (tb[NDA_IFINDEX]) { > > unsigned int ifindex = rta_getattr_u32(tb[NDA_IFINDEX]); > > > > - if (ifindex) { > > - if (!tb[NDA_LINK_NETNSID]) { > > - const char *ifname = ll_index_to_name(ifindex); > > - > > - if (jw_global) > > - jsonw_string_field(jw_global, "viaIf", > > - ifname); > > - else > > - fprintf(fp, "via %s ", ifname); > > - } else { > > - if (jw_global) > > - jsonw_uint_field(jw_global, "viaIfIndex", > > - ifindex); > > - else > > - fprintf(fp, "via ifindex %u ", ifindex); > > - } > > - } > > - } > > - > > - if (tb[NDA_LINK_NETNSID]) { > > - if (jw_global) > > - jsonw_uint_field(jw_global, "linkNetNsId", > > - rta_getattr_u32(tb[NDA_LINK_NETNSID])); > > + if (tb[NDA_LINK_NETNSID]) > > + print_uint(PRINT_ANY, > > + "viaIfIndex", "via ifindex %u ", > > + ifindex); > > else > > - fprintf(fp, "link-netnsid %d ", > > - rta_getattr_u32(tb[NDA_LINK_NETNSID])); > > + print_string(PRINT_ANY, > > + "viaIf", "via %s ", > > + ll_index_to_name(ifindex)); > > } > > > > - if (show_stats && tb[NDA_CACHEINFO]) { > > - struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]); > > - int hz = get_user_hz(); > > + if (tb[NDA_LINK_NETNSID]) > > + print_uint(PRINT_ANY, > > + "linkNetNsId", "link-netnsid %d ", > > + rta_getattr_u32(tb[NDA_LINK_NETNSID])); > > > > - if (jw_global) { > > - jsonw_uint_field(jw_global, "used", > > - ci->ndm_used/hz); > > - jsonw_uint_field(jw_global, "updated", > > - ci->ndm_updated/hz); > > - } else { > > - fprintf(fp, "used %d/%d ", ci->ndm_used/hz, > > - ci->ndm_updated/hz); > > - } > > - } > > + if (show_stats && tb[NDA_CACHEINFO]) > > + fdb_print_stats(fp, RTA_DATA(tb[NDA_CACHEINFO])); > > > > - if (jw_global) { > > - if (r->ndm_flags & NTF_SELF) { > > - start_json_fdb_flags_array(&fdb_flags); > > - jsonw_string(jw_global, "self"); > > - } > > - if (r->ndm_flags & NTF_ROUTER) { > > - start_json_fdb_flags_array(&fdb_flags); > > - jsonw_string(jw_global, "router"); > > - } > > - if (r->ndm_flags & NTF_EXT_LEARNED) { > > - start_json_fdb_flags_array(&fdb_flags); > > - jsonw_string(jw_global, "extern_learn"); > > - } > > - if (r->ndm_flags & NTF_OFFLOADED) { > > - start_json_fdb_flags_array(&fdb_flags); > > - jsonw_string(jw_global, "offload"); > > - } > > - if (r->ndm_flags & NTF_MASTER) > > - jsonw_string(jw_global, "master"); > > - if (fdb_flags) > > - jsonw_end_array(jw_global); > > + fdb_print_flags(fp, r->ndm_flags); > > > > - if (tb[NDA_MASTER]) > > - jsonw_string_field(jw_global, > > - "master", > > - ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER]))); > > > > - } else { > > - if (r->ndm_flags & NTF_SELF) > > - fprintf(fp, "self "); > > - if (r->ndm_flags & NTF_ROUTER) > > - fprintf(fp, "router "); > > - if (r->ndm_flags & NTF_EXT_LEARNED) > > - fprintf(fp, "extern_learn "); > > - if (r->ndm_flags & NTF_OFFLOADED) > > - fprintf(fp, "offload "); > > - if (tb[NDA_MASTER]) { > > - fprintf(fp, "master %s ", > > - ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER]))); > > - } else if (r->ndm_flags & NTF_MASTER) { > > - fprintf(fp, "master "); > > - } > > - } > > - > > - state_s = state_n2a(r->ndm_state); > > - if (jw_global) { > > - if (state_s[0]) > > - jsonw_string_field(jw_global, "state", state_s); > > - > > - jsonw_end_object(jw_global); > > - } else { > > - fprintf(fp, "%s\n", state_s); > > - > > - fflush(fp); > > - } > > + if (tb[NDA_MASTER]) > > + print_string(PRINT_ANY, "master", "%s ", > > + ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER]))); > > > > + print_string(PRINT_ANY, "state", "%s\n", > > + state_n2a(r->ndm_state)); > > + close_json_object(); > > + fflush(fp); > > return 0; > > } > > > > @@ -386,26 +324,13 @@ static int fdb_show(int argc, char **argv) > > exit(1); > > } > > > > - if (json) { > > - jw_global = jsonw_new(stdout); > > - if (!jw_global) { > > - fprintf(stderr, "Error allocation json object\n"); > > - exit(1); > > - } > > - if (pretty) > > - jsonw_pretty(jw_global, 1); > > - > > - jsonw_start_array(jw_global); > > - } > > - > > + new_json_obj(json); > > if (rtnl_dump_filter(&rth, print_fdb, stdout) < 0) { > > fprintf(stderr, "Dump terminated\n"); > > exit(1); > > } > > - if (jw_global) { > > - jsonw_end_array(jw_global); > > - jsonw_destroy(&jw_global); > > - } > > + delete_json_obj(); > > + fflush(stdout); > > > > return 0; > > } > > diff --git a/bridge/mdb.c b/bridge/mdb.c > > index da0282fdc91c..8c08baf570ec 100644 > > --- a/bridge/mdb.c > > +++ b/bridge/mdb.c > > @@ -14,12 +14,12 @@ > > #include > > #include > > #include > > -#include > > > > #include "libnetlink.h" > > #include "br_common.h" > > #include "rt_names.h" > > #include "utils.h" > > +#include "json_print.h" > > > > #ifndef MDBA_RTA > > #define MDBA_RTA(r) \ > > @@ -27,9 +27,6 @@ > > #endif > > > > static unsigned int filter_index, filter_vlan; > > -json_writer_t *jw_global; > > -static bool print_mdb_entries = true; > > -static bool print_mdb_router = true; > > > > static void usage(void) > > { > > @@ -43,162 +40,131 @@ static bool is_temp_mcast_rtr(__u8 type) > > return type == MDB_RTR_TYPE_TEMP_QUERY || type == MDB_RTR_TYPE_TEMP; > > } > > > > +static const char *format_timer(__u32 ticks) > > +{ > > + struct timeval tv; > > + static char tbuf[32]; > > + > > + __jiffies_to_tv(&tv, ticks); > > + snprintf(tbuf, sizeof(tbuf), "%4lu.%.2lu", > > + (unsigned long)tv.tv_sec, > > + (unsigned long)tv.tv_usec / 10000); > > + > > + return tbuf; > > +} > > + > > static void __print_router_port_stats(FILE *f, struct rtattr *pattr) > > { > > struct rtattr *tb[MDBA_ROUTER_PATTR_MAX + 1]; > > - struct timeval tv; > > - __u8 type; > > > > parse_rtattr(tb, MDBA_ROUTER_PATTR_MAX, MDB_RTR_RTA(RTA_DATA(pattr)), > > RTA_PAYLOAD(pattr) - RTA_ALIGN(sizeof(uint32_t))); > > + > > if (tb[MDBA_ROUTER_PATTR_TIMER]) { > > - __jiffies_to_tv(&tv, > > - rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER])); > > - if (jw_global) { > > - char formatted_time[9]; > > - > > - snprintf(formatted_time, sizeof(formatted_time), > > - "%4i.%.2i", (int)tv.tv_sec, > > - (int)tv.tv_usec/10000); > > - jsonw_string_field(jw_global, "timer", formatted_time); > > - } else { > > - fprintf(f, " %4i.%.2i", > > - (int)tv.tv_sec, (int)tv.tv_usec/10000); > > - } > > + __u32 timer = rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]); > > + > > + print_string(PRINT_ANY, "timer", " %s", > > + format_timer(timer)); > > } > > + > > if (tb[MDBA_ROUTER_PATTR_TYPE]) { > > - type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]); > > - if (jw_global) > > - jsonw_string_field(jw_global, "type", > > - is_temp_mcast_rtr(type) ? "temp" : "permanent"); > > - else > > - fprintf(f, " %s", > > - is_temp_mcast_rtr(type) ? "temp" : "permanent"); > > + __u8 type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]); > > + > > + print_string(PRINT_ANY, "type", " %s", > > + is_temp_mcast_rtr(type) ? "temp" : "permanent"); > > } > > } > > > > -static void br_print_router_ports(FILE *f, struct rtattr *attr, __u32 brifidx) > > +static void br_print_router_ports(FILE *f, struct rtattr *attr, > > + const char *brifname) > > { > > - uint32_t *port_ifindex; > > + int rem = RTA_PAYLOAD(attr); > > struct rtattr *i; > > - int rem; > > > > - rem = RTA_PAYLOAD(attr); > > - if (jw_global) { > > - jsonw_name(jw_global, ll_index_to_name(brifidx)); > > - jsonw_start_array(jw_global); > > - for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { > > - port_ifindex = RTA_DATA(i); > > - jsonw_start_object(jw_global); > > - jsonw_string_field(jw_global, > > - "port", > > - ll_index_to_name(*port_ifindex)); > > + if (is_json_context()) > > + open_json_array(PRINT_JSON, brifname); > > + else if (!show_stats) > > + fprintf(f, "router ports on %s: ", brifname); > > + > > + for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { > > + uint32_t *port_ifindex = RTA_DATA(i); > > + const char *port_ifname = ll_index_to_name(*port_ifindex); > > + > > + if (is_json_context()) { > > + open_json_object(NULL); > > + print_string(PRINT_JSON, "port", NULL, port_ifname); > > + > > if (show_stats) > > __print_router_port_stats(f, i); > > - jsonw_end_object(jw_global); > > - } > > - jsonw_end_array(jw_global); > > - } else { > > - if (!show_stats) > > - fprintf(f, "router ports on %s: ", > > - ll_index_to_name(brifidx)); > > - for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { > > - port_ifindex = RTA_DATA(i); > > - if (show_stats) { > > - fprintf(f, "router ports on %s: %s", > > - ll_index_to_name(brifidx), > > - ll_index_to_name(*port_ifindex)); > > - __print_router_port_stats(f, i); > > - fprintf(f, "\n"); > > - } else{ > > - fprintf(f, "%s ", > > - ll_index_to_name(*port_ifindex)); > > - } > > - } > > - if (!show_stats) > > + close_json_object(); > > + } else if (show_stats) { > > + fprintf(f, "router ports on %s: %s", > > + brifname, port_ifname); > > + > > + __print_router_port_stats(f, i); > > fprintf(f, "\n"); > > + } else { > > + fprintf(f, "%s ", port_ifname); > > + } > > } > > + close_json_array(PRINT_JSON, NULL); > > } > > > > -static void start_json_mdb_flags_array(bool *mdb_flags) > > -{ > > - if (*mdb_flags) > > - return; > > - jsonw_name(jw_global, "flags"); > > - jsonw_start_array(jw_global); > > - *mdb_flags = true; > > -} > > - > > -static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e, > > +static void print_mdb_entry(FILE *f, int ifindex, const struct br_mdb_entry *e, > > struct nlmsghdr *n, struct rtattr **tb) > > { > > SPRINT_BUF(abuf); > > + const char *dev; > > const void *src; > > int af; > > - bool mdb_flags = false; > > > > if (filter_vlan && e->vid != filter_vlan) > > return; > > + > > af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6; > > src = af == AF_INET ? (const void *)&e->addr.u.ip4 : > > (const void *)&e->addr.u.ip6; > > - if (jw_global) > > - jsonw_start_object(jw_global); > > - if (n->nlmsg_type == RTM_DELMDB) { > > - if (jw_global) > > - jsonw_string_field(jw_global, "opCode", "deleted"); > > - else > > - fprintf(f, "Deleted "); > > - } > > - if (jw_global) { > > - jsonw_string_field(jw_global, "dev", ll_index_to_name(ifindex)); > > - jsonw_string_field(jw_global, > > - "port", > > - ll_index_to_name(e->ifindex)); > > - jsonw_string_field(jw_global, "grp", inet_ntop(af, src, > > - abuf, sizeof(abuf))); > > - jsonw_string_field(jw_global, "state", > > - (e->state & MDB_PERMANENT) ? "permanent" : "temp"); > > - if (e->flags & MDB_FLAGS_OFFLOAD) { > > - start_json_mdb_flags_array(&mdb_flags); > > - jsonw_string(jw_global, "offload"); > > - } > > - if (mdb_flags) > > - jsonw_end_array(jw_global); > > - } else{ > > - fprintf(f, "dev %s port %s grp %s %s %s", > > - ll_index_to_name(ifindex), > > - ll_index_to_name(e->ifindex), > > - inet_ntop(af, src, abuf, sizeof(abuf)), > > - (e->state & MDB_PERMANENT) ? "permanent" : "temp", > > - (e->flags & MDB_FLAGS_OFFLOAD) ? "offload" : ""); > > - } > > - if (e->vid) { > > - if (jw_global) > > - jsonw_uint_field(jw_global, "vid", e->vid); > > - else > > - fprintf(f, " vid %hu", e->vid); > > + dev = ll_index_to_name(ifindex); > > + > > + open_json_object(NULL); > > + > > + if (n->nlmsg_type == RTM_DELMDB) > > + print_bool(PRINT_ANY, "deleted", "Deleted ", true); > > + > > + > > + if (is_json_context()) { > > + print_int(PRINT_JSON, "index", NULL, ifindex); > > + print_string(PRINT_JSON, "dev", NULL, dev); > > + } else { > > + fprintf(f, "%u: ", ifindex); > > + color_fprintf(f, COLOR_IFNAME, "%s ", dev); > > } > > - if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) { > > - struct timeval tv; > > > > - __jiffies_to_tv(&tv, rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER])); > > - if (jw_global) { > > - char formatted_time[9]; > > + print_string(PRINT_ANY, "port", " %s ", > > + ll_index_to_name(e->ifindex)); > > > > - snprintf(formatted_time, sizeof(formatted_time), > > - "%4i.%.2i", (int)tv.tv_sec, > > - (int)tv.tv_usec/10000); > > - jsonw_string_field(jw_global, "timer", formatted_time); > > - } else { > > - fprintf(f, "%4i.%.2i", (int)tv.tv_sec, > > - (int)tv.tv_usec/10000); > > - } > > + print_color_string(PRINT_ANY, ifa_family_color(af), > > + "grp", " %s ", > > + inet_ntop(af, src, abuf, sizeof(abuf))); > > + > > + print_string(PRINT_ANY, "state", " %s ", > > + (e->state & MDB_PERMANENT) ? "permanent" : "temp"); > > + > > + open_json_array(PRINT_JSON, "flags"); > > + if (e->flags & MDB_FLAGS_OFFLOAD) > > + print_string(PRINT_ANY, NULL, "%s ", "offload"); > > + close_json_array(PRINT_JSON, NULL); > > + > > + if (e->vid) > > + print_uint(PRINT_ANY, "vid", " vid %u", e->vid); > > + > > + if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) { > > + __u32 timer = rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]); > > + > > + print_string(PRINT_ANY, "timer", " %s", > > + format_timer(timer)); > > } > > - if (jw_global) > > - jsonw_end_object(jw_global); > > - else > > - fprintf(f, "\n"); > > + close_json_object(); > > } > > > > static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr, > > @@ -218,15 +184,60 @@ static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr, > > } > > } > > > > +static void print_mdb_entries(FILE *fp, struct nlmsghdr *n, > > + int ifindex, struct rtattr *mdb) > > +{ > > + int rem = RTA_PAYLOAD(mdb); > > + struct rtattr *i; > > + > > + open_json_array(PRINT_JSON, "mdb"); > > + for (i = RTA_DATA(mdb); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) > > + br_print_mdb_entry(fp, ifindex, i, n); > > + close_json_array(PRINT_JSON, NULL); > > +} > > + > > +static void print_router_entries(FILE *fp, struct nlmsghdr *n, > > + int ifindex, struct rtattr *router) > > +{ > > + const char *brifname = ll_index_to_name(ifindex); > > + > > + open_json_array(PRINT_JSON, "router"); > > + if (n->nlmsg_type == RTM_GETMDB) { > > + if (show_details) > > + br_print_router_ports(fp, router, brifname); > > + } else { > > + struct rtattr *i = RTA_DATA(router); > > + uint32_t *port_ifindex = RTA_DATA(i); > > + > > + if (is_json_context()) { > > + open_json_array(PRINT_JSON, brifname); > > + open_json_object(NULL); > > + > > + print_string(PRINT_JSON, "port", NULL, > > + ll_index_to_name(*port_ifindex)); > > + close_json_object(); > > + close_json_array(PRINT_JSON, NULL); > > + } else { > > + fprintf(fp, "router port dev %s master %s\n", > > + ll_index_to_name(*port_ifindex), > > + brifname); > > + } > > + } > > + close_json_array(PRINT_JSON, NULL); > > +} > > + > > int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) > > { > > FILE *fp = arg; > > struct br_port_msg *r = NLMSG_DATA(n); > > int len = n->nlmsg_len; > > - struct rtattr *tb[MDBA_MAX+1], *i; > > + struct rtattr *tb[MDBA_MAX+1]; > > > > - if (n->nlmsg_type != RTM_GETMDB && n->nlmsg_type != RTM_NEWMDB && n->nlmsg_type != RTM_DELMDB) { > > - fprintf(stderr, "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n", > > + if (n->nlmsg_type != RTM_GETMDB && > > + n->nlmsg_type != RTM_NEWMDB && > > + n->nlmsg_type != RTM_DELMDB) { > > + fprintf(stderr, > > + "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n", > > n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); > > > > return 0; > > @@ -243,50 +254,14 @@ int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) > > > > parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); > > > > - if (tb[MDBA_MDB] && print_mdb_entries) { > > - int rem = RTA_PAYLOAD(tb[MDBA_MDB]); > > + if (n->nlmsg_type == RTM_DELMDB) > > + print_bool(PRINT_ANY, "deleted", "Deleted ", true); > > > > - for (i = RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) > > - br_print_mdb_entry(fp, r->ifindex, i, n); > > - } > > + if (tb[MDBA_MDB]) > > + print_mdb_entries(fp, n, r->ifindex, tb[MDBA_MDB]); > > > > - if (tb[MDBA_ROUTER] && print_mdb_router) { > > - if (n->nlmsg_type == RTM_GETMDB) { > > - if (show_details) > > - br_print_router_ports(fp, tb[MDBA_ROUTER], > > - r->ifindex); > > - } else { > > - uint32_t *port_ifindex; > > - > > - i = RTA_DATA(tb[MDBA_ROUTER]); > > - port_ifindex = RTA_DATA(i); > > - if (n->nlmsg_type == RTM_DELMDB) { > > - if (jw_global) > > - jsonw_string_field(jw_global, > > - "opCode", > > - "deleted"); > > - else > > - fprintf(fp, "Deleted "); > > - } > > - if (jw_global) { > > - jsonw_name(jw_global, > > - ll_index_to_name(r->ifindex)); > > - jsonw_start_array(jw_global); > > - jsonw_start_object(jw_global); > > - jsonw_string_field(jw_global, "port", > > - ll_index_to_name(*port_ifindex)); > > - jsonw_end_object(jw_global); > > - jsonw_end_array(jw_global); > > - } else { > > - fprintf(fp, "router port dev %s master %s\n", > > - ll_index_to_name(*port_ifindex), > > - ll_index_to_name(r->ifindex)); > > - } > > - } > > - } > > - > > - if (!jw_global) > > - fflush(fp); > > + if (tb[MDBA_ROUTER]) > > + print_router_entries(fp, n, r->ifindex, tb[MDBA_ROUTER]); > > > > return 0; > > } > > @@ -319,62 +294,21 @@ static int mdb_show(int argc, char **argv) > > } > > } > > > > + new_json_obj(json); > > + > > /* get mdb entries*/ > > if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) { > > perror("Cannot send dump request"); > > return -1; > > } > > > > - if (!json) { > > - /* Normal output */ > > - if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) { > > - fprintf(stderr, "Dump terminated\n"); > > - return -1; > > - } > > - return 0; > > - } > > - > > - /* Json output */ > > - jw_global = jsonw_new(stdout); > > - if (!jw_global) { > > - fprintf(stderr, "Error allocation json object\n"); > > - exit(1); > > - } > > - > > - if (pretty) > > - jsonw_pretty(jw_global, 1); > > - > > - jsonw_start_object(jw_global); > > - jsonw_name(jw_global, "mdb"); > > - jsonw_start_array(jw_global); > > - > > - /* print mdb entries */ > > - print_mdb_entries = true; > > - print_mdb_router = false; > > if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) { > > fprintf(stderr, "Dump terminated\n"); > > return -1; > > } > > - jsonw_end_array(jw_global); > > - > > - /* get router ports */ > > - if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) { > > - perror("Cannot send dump request"); > > - return -1; > > - } > > - jsonw_name(jw_global, "router"); > > - jsonw_start_object(jw_global); > > > > - /* print router ports */ > > - print_mdb_entries = false; > > - print_mdb_router = true; > > - if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) { > > - fprintf(stderr, "Dump terminated\n"); > > - return -1; > > - } > > - jsonw_end_object(jw_global); > > - jsonw_end_object(jw_global); > > - jsonw_destroy(&jw_global); > > + delete_json_obj(); > > + fflush(stdout); > > > > return 0; > > } > > diff --git a/bridge/vlan.c b/bridge/vlan.c > > index 7c8b3ad54857..9f4a7a2be55c 100644 > > --- a/bridge/vlan.c > > +++ b/bridge/vlan.c > > @@ -8,19 +8,16 @@ > > #include > > #include > > #include > > -#include > > #include > > > > +#include "json_print.h" > > #include "libnetlink.h" > > #include "br_common.h" > > #include "utils.h" > > > > static unsigned int filter_index, filter_vlan; > > -static int last_ifidx = -1; > > static int show_vlan_tunnel_info = 0; > > > > -json_writer_t *jw_global; > > - > > static void usage(void) > > { > > fprintf(stderr, > > @@ -257,38 +254,33 @@ static int filter_vlan_check(__u16 vid, __u16 flags) > > > > static void print_vlan_port(FILE *fp, int ifi_index) > > { > > - if (jw_global) { > > - jsonw_name(jw_global, > > - ll_index_to_name(ifi_index)); > > - jsonw_start_array(jw_global); > > - } else { > > - fprintf(fp, "%s", > > - ll_index_to_name(ifi_index)); > > - } > > + print_string(PRINT_ANY, NULL, "%s", > > + ll_index_to_name(ifi_index)); > > } > > > > Stephen, this seems to have broken both json and non-json output. > > Here is some output before and after the patch (same thing for tunnelshow): > > before: > $bridge vlan show > port vlan ids > hostbond4 1000 > 1001 PVID Egress Untagged > 1002 > 1003 > 1004 > > hostbond3 1000 PVID Egress Untagged > 1001 > 1002 > 1003 > 1004 > > bridge 1 PVID Egress Untagged > 1000 > 1001 > 1002 > 1003 > 1004 > > vxlan0 1 PVID Egress Untagged > 1000 > 1001 > 1002 > 1003 > 1004 > > > $ bridge -j -c vlan show > { > "hostbond4": [{ > "vlan": 1000 > },{ > "vlan": 1001, > "flags": ["PVID","Egress Untagged" > ] > },{ > "vlan": 1002, > "vlanEnd": 1004 > } > ], > "hostbond3": [{ > "vlan": 1000, > "flags": ["PVID","Egress Untagged" > ] > },{ > "vlan": 1001, > "vlanEnd": 1004 > } > ], > "bridge": [{ > "vlan": 1, > "flags": ["PVID","Egress Untagged" > ] > },{ > "vlan": 1000, > "vlanEnd": 1004 > } > ], > "vxlan0": [{ > "vlan": 1, > "flags": ["PVID","Egress Untagged" > ] > },{ > "vlan": 1000, > "vlanEnd": 1004 > } > ] > } > > > after: > ==== > > $bridge vlan show > port vlan ids > hostbond4 > 1000 1001 PVID untagged 1002 1003 1004 > hostbond3 > 1000 PVID untagged 1001 1002 1003 1004 > bridge > 1 PVID untagged 1000 1001 1002 1003 1004 > vxlan0 > 1 PVID untagged 1000 1001 1002 1003 1004 > > $bridge -j -c vlan show > ["hostbond4","vlan":[{"vlan":1000},{"vlan":1001,"pvid":null,"untagged":null},{"vlan":1002},{"vlan":1003},{"vlan":1004}],"hostbond3","vlan":[{"vlan":1000,"pvid":null,"untagged":null},{"vlan":1001},{"vlan":1002},{"vlan":1003},{"vlan":1004}],"bridge","vlan":[{"vlan":1,"pvid":null,"untagged":null},{"vlan":1000},{"vlan":1001},{"vlan":1002},{"vlan":1003},{"vlan":1004}],"vxlan0","vlan":[{"vlan":1,"pvid":null,"untagged":null},{"vlan":1000},{"vlan":1001},{"vlan":1002},{"vlan":1003},{"vlan":1004}]] I can fix it.