From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pl0-f67.google.com ([209.85.160.67]:38996 "EHLO mail-pl0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752106AbeBTTYP (ORCPT ); Tue, 20 Feb 2018 14:24:15 -0500 Received: by mail-pl0-f67.google.com with SMTP id s13so7967762plq.6 for ; Tue, 20 Feb 2018 11:24:15 -0800 (PST) From: Stephen Hemminger To: netdev@vger.kernel.org Cc: Stephen Hemminger , Stephen Hemminger Subject: [PATCH v2 iproute2-next 2/5] bridge: colorize output and use JSON print library Date: Tue, 20 Feb 2018 11:24:05 -0800 Message-Id: <20180220192408.19763-3-stephen@networkplumber.org> In-Reply-To: <20180220192408.19763-1-stephen@networkplumber.org> References: <20180220192408.19763-1-stephen@networkplumber.org> Sender: netdev-owner@vger.kernel.org List-ID: 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)); } -static void start_json_vlan_flags_array(bool *vlan_flags) +static void print_range(const char *name, __u16 start, __u16 id) { - if (*vlan_flags) - return; - jsonw_name(jw_global, "flags"); - jsonw_start_array(jw_global); - *vlan_flags = true; + char end[64]; + + snprintf(end, sizeof(end), "%sEnd", name); + + print_hu(PRINT_ANY, name, "\t %hu", start); + if (start != id) + print_hu(PRINT_ANY, end, "-%hu", id); + } static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex) { - bool jsonw_end_parray = false; struct rtattr *i, *list = tb; int rem = RTA_PAYLOAD(list); __u16 last_vid_start = 0; __u32 last_tunid_start = 0; - if (!filter_vlan) { + if (!filter_vlan) print_vlan_port(fp, ifindex); - jsonw_end_parray = 1; - } + open_json_array(PRINT_JSON, "tunnel"); for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { struct rtattr *ttb[IFLA_BRIDGE_VLAN_TUNNEL_MAX+1]; __u32 tunnel_id = 0; @@ -320,6 +312,7 @@ static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex) last_vid_start = tunnel_vid; last_tunid_start = tunnel_id; } + vcheck_ret = filter_vlan_check(tunnel_vid, tunnel_flags); if (vcheck_ret == -1) break; @@ -329,52 +322,19 @@ static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex) if (tunnel_flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) continue; - if (filter_vlan) { + if (filter_vlan) print_vlan_port(fp, ifindex); - jsonw_end_parray = 1; - } - if (jw_global) { - jsonw_start_object(jw_global); - jsonw_uint_field(jw_global, "vlan", - last_vid_start); - } else { - fprintf(fp, "\t %hu", last_vid_start); - } - if (last_vid_start != tunnel_vid) { - if (jw_global) - jsonw_uint_field(jw_global, "vlanEnd", - tunnel_vid); - else - fprintf(fp, "-%hu", tunnel_vid); - } + open_json_object(NULL); + print_range("vlan", last_vid_start, tunnel_vid); + print_range("tunid", last_tunid_start, tunnel_id); + close_json_object(); - if (jw_global) { - jsonw_uint_field(jw_global, "tunid", - last_tunid_start); - } else { - fprintf(fp, "\t %hu", last_tunid_start); - } - if (last_vid_start != tunnel_vid) { - if (jw_global) - jsonw_uint_field(jw_global, "tunidEnd", - tunnel_id); - else - fprintf(fp, "-%hu", tunnel_id); - } - - if (jw_global) - jsonw_end_object(jw_global); - else + if (!is_json_context()) fprintf(fp, "\n"); - } - if (jsonw_end_parray) { - if (jw_global) - jsonw_end_array(jw_global); - else - fprintf(fp, "\n"); } + close_json_array(PRINT_JSON, NULL); } static int print_vlan_tunnel(const struct sockaddr_nl *who, @@ -408,9 +368,11 @@ static int print_vlan_tunnel(const struct sockaddr_nl *who, /* if AF_SPEC isn't there, vlan table is not preset for this port */ if (!tb[IFLA_AF_SPEC]) { - if (!filter_vlan && !jw_global) - fprintf(fp, "%s\tNone\n", - ll_index_to_name(ifm->ifi_index)); + if (!filter_vlan && !is_json_context()) { + color_fprintf(fp, COLOR_IFNAME, "%s", + ll_index_to_name(ifm->ifi_index)); + fprintf(fp, "\tNone\n"); + } return 0; } @@ -451,48 +413,51 @@ static int print_vlan(const struct sockaddr_nl *who, /* if AF_SPEC isn't there, vlan table is not preset for this port */ if (!tb[IFLA_AF_SPEC]) { - if (!filter_vlan && !jw_global) - fprintf(fp, "%s\tNone\n", - ll_index_to_name(ifm->ifi_index)); + if (!filter_vlan && !is_json_context()) { + color_fprintf(fp, COLOR_IFNAME, "%s", + ll_index_to_name(ifm->ifi_index)); + fprintf(fp, "\tNone\n"); + } return 0; } - print_vlan_info(fp, tb[IFLA_AF_SPEC], ifm->ifi_index); + print_vlan_port(fp, ifm->ifi_index); + print_vlan_info(fp, tb[IFLA_AF_SPEC]); fflush(fp); return 0; } -static void print_one_vlan_stats(FILE *fp, - const struct bridge_vlan_xstats *vstats, - int ifindex) +static void print_vlan_flags(__u16 flags) { - const char *ifname = ""; + if (flags & BRIDGE_VLAN_INFO_PVID) + print_null(PRINT_ANY, "pvid", " %s", "PVID"); - if (filter_vlan && filter_vlan != vstats->vid) - return; - /* skip pure port entries, they'll be dumped via the slave stats call */ - if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) && - !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY)) - return; + if (flags & BRIDGE_VLAN_INFO_UNTAGGED) + print_null(PRINT_ANY, "untagged", " %s", "untagged"); +} - if (last_ifidx != ifindex) { - ifname = ll_index_to_name(ifindex); - last_ifidx = ifindex; - } - fprintf(fp, "%-16s %hu", ifname, vstats->vid); - if (vstats->flags & BRIDGE_VLAN_INFO_PVID) - fprintf(fp, " PVID"); - if (vstats->flags & BRIDGE_VLAN_INFO_UNTAGGED) - fprintf(fp, " Egress Untagged"); - fprintf(fp, "\n"); - fprintf(fp, "%-16s RX: %llu bytes %llu packets\n", - "", vstats->rx_bytes, vstats->rx_packets); - fprintf(fp, "%-16s TX: %llu bytes %llu packets\n", - "", vstats->tx_bytes, vstats->tx_packets); +static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats) +{ + open_json_object(NULL); + print_hu(PRINT_ANY, "vid", " %hu", vstats->vid); + + print_vlan_flags(vstats->flags); + + print_lluint(PRINT_ANY, "rx_bytes", + "\n RX: %llu bytes", + vstats->rx_bytes); + print_lluint(PRINT_ANY, "rx_packets", " %llu packets\n", + vstats->rx_packets); + print_lluint(PRINT_ANY, "tx_bytes", + " TX: %llu bytes", + vstats->tx_bytes); + print_lluint(PRINT_ANY, "tx_packets", " %llu packets", + vstats->tx_packets); + close_json_object(); } -static void print_vlan_stats_attr(FILE *fp, struct rtattr *attr, int ifindex) +static void print_vlan_stats_attr(struct rtattr *attr, int ifindex) { struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1]; struct rtattr *i, *list; @@ -505,11 +470,33 @@ static void print_vlan_stats_attr(FILE *fp, struct rtattr *attr, int ifindex) list = brtb[LINK_XSTATS_TYPE_BRIDGE]; rem = RTA_PAYLOAD(list); + + open_json_object(NULL); + + print_color_string(PRINT_ANY, COLOR_IFNAME, + "dev", "%-16s", + ll_index_to_name(ifindex)); + + open_json_array(PRINT_JSON, "xstats"); for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { + const struct bridge_vlan_xstats *vstats = RTA_DATA(i); + if (i->rta_type != BRIDGE_XSTATS_VLAN) continue; - print_one_vlan_stats(fp, RTA_DATA(i), ifindex); + + if (filter_vlan && filter_vlan != vstats->vid) + continue; + + /* skip pure port entries, they'll be dumped via the slave stats call */ + if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) && + !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY)) + continue; + + print_one_vlan_stats(vstats); } + close_json_array(PRINT_ANY, "\n"); + close_json_object(); + } static int print_vlan_stats(const struct sockaddr_nl *who, @@ -534,11 +521,11 @@ static int print_vlan_stats(const struct sockaddr_nl *who, /* We have to check if any of the two attrs are usable */ if (tb[IFLA_STATS_LINK_XSTATS]) - print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS], + print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS], ifsm->ifindex); if (tb[IFLA_STATS_LINK_XSTATS_SLAVE]) - print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS_SLAVE], + print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS_SLAVE], ifsm->ifindex); fflush(fp); @@ -574,6 +561,8 @@ static int vlan_show(int argc, char **argv) } } + new_json_obj(json); + if (!show_stats) { if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK, (compress_vlans ? @@ -583,17 +572,7 @@ static int vlan_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_object(jw_global); - } else { + if (!is_json_context()) { if (show_vlan_tunnel_info) printf("port\tvlan ids\ttunnel id\n"); else @@ -605,7 +584,6 @@ static int vlan_show(int argc, char **argv) stdout); else ret = rtnl_dump_filter(&rth, print_vlan, stdout); - if (ret < 0) { fprintf(stderr, "Dump ternminated\n"); exit(1); @@ -621,7 +599,9 @@ static int vlan_show(int argc, char **argv) exit(1); } - printf("%-16s vlan id\n", "port"); + if (!is_json_context()) + printf("%-16s vlan id\n", "port"); + if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); @@ -641,26 +621,21 @@ static int vlan_show(int argc, char **argv) } } - if (jw_global) { - jsonw_end_object(jw_global); - jsonw_destroy(&jw_global); - } - + delete_json_obj(); + fflush(stdout); return 0; } -void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex) +void print_vlan_info(FILE *fp, struct rtattr *tb) { struct rtattr *i, *list = tb; int rem = RTA_PAYLOAD(list); __u16 last_vid_start = 0; - bool vlan_flags = false; - bool jsonw_end_parray = false; - if (!filter_vlan) { - print_vlan_port(fp, ifindex); - jsonw_end_parray = true; - } + if (!is_json_context()) + fprintf(fp, "%s", _SL_); + + open_json_array(PRINT_JSON, "vlan"); for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { struct bridge_vlan_info *vinfo; @@ -679,61 +654,14 @@ void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex) else if (vcheck_ret == 0) continue; - if (filter_vlan) { - print_vlan_port(fp, ifindex); - jsonw_end_parray = true; - } - if (jw_global) { - jsonw_start_object(jw_global); - jsonw_uint_field(jw_global, "vlan", - last_vid_start); - if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) - continue; - } else { - fprintf(fp, "\t %hu", last_vid_start); - } - if (last_vid_start != vinfo->vid) { - if (jw_global) - jsonw_uint_field(jw_global, "vlanEnd", - vinfo->vid); - else - fprintf(fp, "-%hu", vinfo->vid); - } - if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) { - if (jw_global) { - start_json_vlan_flags_array(&vlan_flags); - jsonw_string(jw_global, "PVID"); - } else { - fprintf(fp, " PVID"); - } - } - if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) { - if (jw_global) { - start_json_vlan_flags_array(&vlan_flags); - jsonw_string(jw_global, - "Egress Untagged"); - } else { - fprintf(fp, " Egress Untagged"); - } - } - if (jw_global && vlan_flags) { - jsonw_end_array(jw_global); - vlan_flags = false; - } + open_json_object(NULL); + print_range("vlan", last_vid_start, vinfo->vid); - if (jw_global) - jsonw_end_object(jw_global); - else - fprintf(fp, "\n"); + print_vlan_flags(vinfo->flags); + close_json_object(); } - if (jsonw_end_parray) { - if (jw_global) - jsonw_end_array(jw_global); - else - fprintf(fp, "\n"); - - } + close_json_array(PRINT_ANY, "\n"); } int do_vlan(int argc, char **argv) -- 2.16.1