Add json output for bridge link show command.
This also changes the output format slightly for the non JSON case so
that it has same format as the ip link show command.

Signed-off-by: Stephen Hemminger <step...@networkplumber.org>
---
 bridge/link.c | 304 ++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 188 insertions(+), 116 deletions(-)

diff --git a/bridge/link.c b/bridge/link.c
index 870ebe050477..12cc995e05e3 100644
--- a/bridge/link.c
+++ b/bridge/link.c
@@ -12,6 +12,7 @@
 #include <string.h>
 #include <stdbool.h>
 
+#include "json_print.h"
 #include "libnetlink.h"
 #include "utils.h"
 #include "br_common.h"
@@ -26,15 +27,27 @@ static const char *port_states[] = {
        [BR_STATE_BLOCKING] = "blocking",
 };
 
-static void print_link_flags(FILE *fp, unsigned int flags)
+
+static const char *oper_states[] = {
+       "UNKNOWN", "NOTPRESENT", "DOWN", "LOWERLAYERDOWN",
+       "TESTING", "DORMANT",    "UP"
+};
+
+static const char *hw_mode[] = {
+       "VEB", "VEPA"
+};
+
+static void print_link_flags(FILE *fp, unsigned int flags, unsigned int mdown)
 {
-       fprintf(fp, "<");
+       open_json_array(PRINT_ANY, is_json_context() ? "flags" : "<");
        if (flags & IFF_UP && !(flags & IFF_RUNNING))
-               fprintf(fp, "NO-CARRIER%s", flags ? "," : "");
+               print_string(PRINT_ANY, NULL,
+                            flags ? "%s," : "%s", "NO-CARRIER");
        flags &= ~IFF_RUNNING;
-#define _PF(f) if (flags&IFF_##f) { \
-                 flags &= ~IFF_##f ; \
-                 fprintf(fp, #f "%s", flags ? "," : ""); }
+
+#define _PF(f) if (flags&IFF_##f) {                                    \
+               flags &= ~IFF_##f ;                                     \
+               print_string(PRINT_ANY, NULL, flags ? "%s," : "%s", #f); }
        _PF(LOOPBACK);
        _PF(BROADCAST);
        _PF(POINTOPOINT);
@@ -55,44 +68,136 @@ static void print_link_flags(FILE *fp, unsigned int flags)
        _PF(ECHO);
 #undef _PF
        if (flags)
-               fprintf(fp, "%x", flags);
-       fprintf(fp, "> ");
+               print_hex(PRINT_ANY, NULL, "%x", flags);
+       if (mdown)
+               print_string(PRINT_ANY, NULL, ",%s", "M-DOWN");
+       close_json_array(PRINT_ANY, "> ");
 }
 
-static const char *oper_states[] = {
-       "UNKNOWN", "NOTPRESENT", "DOWN", "LOWERLAYERDOWN",
-       "TESTING", "DORMANT",    "UP"
-};
-
-static const char *hw_mode[] = {"VEB", "VEPA"};
-
 static void print_operstate(FILE *f, __u8 state)
 {
-       if (state >= ARRAY_SIZE(oper_states))
-               fprintf(f, "state %#x ", state);
-       else
-               fprintf(f, "state %s ", oper_states[state]);
+       if (state >= ARRAY_SIZE(oper_states)) {
+               print_0xhex(PRINT_ANY, "operstate", "operstat %#x", state);
+       } else {
+               if (is_json_context())
+                       print_string(PRINT_JSON,
+                                    "operstate",
+                                    NULL, oper_states[state]);
+               else {
+                       fprintf(f, "state ");
+                       color_fprintf(f, oper_state_color(state),
+                                     "%s ", oper_states[state]);
+               }
+       }
 }
 
-static void print_portstate(FILE *f, __u8 state)
+static void print_portstate(__u8 state)
 {
        if (state <= BR_STATE_BLOCKING)
-               fprintf(f, "state %s ", port_states[state]);
+               print_string(PRINT_ANY, "state",
+                            "state %s ", port_states[state]);
        else
-               fprintf(f, "state (%d) ", state);
+               print_uint(PRINT_ANY, "state",
+                            "state (%d) ", state);
 }
 
-static void print_onoff(FILE *f, char *flag, __u8 val)
+static void print_onoff(FILE *fp, const char *flag, __u8 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 void print_hwmode(FILE *f, __u16 mode)
+static void print_hwmode(__u16 mode)
 {
        if (mode >= ARRAY_SIZE(hw_mode))
-               fprintf(f, "hwmode %#hx ", mode);
+               print_0xhex(PRINT_ANY, "hwmode",
+                           "hwmode %#hx ", mode);
        else
-               fprintf(f, "hwmode %s ", hw_mode[mode]);
+               print_string(PRINT_ANY, "hwmode",
+                            "hwmode %s ", hw_mode[mode]);
+}
+
+static void print_protinfo(FILE *fp, struct rtattr *attr)
+{
+       if (attr->rta_type & NLA_F_NESTED) {
+               struct rtattr *prtb[IFLA_BRPORT_MAX + 1];
+
+               parse_rtattr_nested(prtb, IFLA_BRPORT_MAX, attr);
+
+               if (prtb[IFLA_BRPORT_STATE])
+                       
print_portstate(rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
+
+               if (prtb[IFLA_BRPORT_PRIORITY])
+                       print_uint(PRINT_ANY, "priority",
+                                  "priority %u ",
+                                  rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY]));
+
+               if (prtb[IFLA_BRPORT_COST])
+                       print_uint(PRINT_ANY, "cost",
+                                  "cost %u ",
+                                  rta_getattr_u32(prtb[IFLA_BRPORT_COST]));
+
+               if (!show_details)
+                       return;
+
+               if (!is_json_context())
+                       fprintf(fp, "%s    ", _SL_);
+
+               if (prtb[IFLA_BRPORT_MODE])
+                       print_onoff(fp, "hairpin",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_MODE]));
+               if (prtb[IFLA_BRPORT_GUARD])
+                       print_onoff(fp, "guard",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_GUARD]));
+               if (prtb[IFLA_BRPORT_PROTECT])
+                       print_onoff(fp, "root_block",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT]));
+               if (prtb[IFLA_BRPORT_FAST_LEAVE])
+                       print_onoff(fp, "fastleave",
+                                   
rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE]));
+               if (prtb[IFLA_BRPORT_LEARNING])
+                       print_onoff(fp, "learning",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING]));
+               if (prtb[IFLA_BRPORT_LEARNING_SYNC])
+                       print_onoff(fp, "learning_sync",
+                                   
rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC]));
+               if (prtb[IFLA_BRPORT_UNICAST_FLOOD])
+                       print_onoff(fp, "flood",
+                                   
rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD]));
+               if (prtb[IFLA_BRPORT_MCAST_FLOOD])
+                       print_onoff(fp, "mcast_flood",
+                                   
rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_FLOOD]));
+               if (prtb[IFLA_BRPORT_NEIGH_SUPPRESS])
+                       print_onoff(fp, "neigh_suppress",
+                                   
rta_getattr_u8(prtb[IFLA_BRPORT_NEIGH_SUPPRESS]));
+               if (prtb[IFLA_BRPORT_VLAN_TUNNEL])
+                       print_onoff(fp, "vlan_tunnel",
+                                   
rta_getattr_u8(prtb[IFLA_BRPORT_VLAN_TUNNEL]));
+       } else
+               print_portstate(rta_getattr_u8(attr));
+}
+
+
+/*
+ * This is reported by HW devices that have some bridging
+ * capabilities.
+ */
+static void print_af_spec(FILE *fp, struct rtattr *attr)
+{
+       struct rtattr *aftb[IFLA_BRIDGE_MAX+1];
+
+       parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, attr);
+
+       if (aftb[IFLA_BRIDGE_MODE])
+               print_hwmode(rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
+
+       if (!show_details)
+               return;
+
+       if (aftb[IFLA_BRIDGE_VLAN_INFO])
+               print_vlan_info(fp, aftb[IFLA_BRIDGE_VLAN_INFO]);
 }
 
 int print_linkinfo(const struct sockaddr_nl *who,
@@ -102,6 +207,7 @@ int print_linkinfo(const struct sockaddr_nl *who,
        int len = n->nlmsg_len;
        struct ifinfomsg *ifi = NLMSG_DATA(n);
        struct rtattr *tb[IFLA_MAX+1];
+       unsigned int m_flag = 0;
 
        len -= NLMSG_LENGTH(sizeof(*ifi));
        if (len < 0) {
@@ -118,113 +224,75 @@ int print_linkinfo(const struct sockaddr_nl *who,
        parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len, NLA_F_NESTED);
 
        if (tb[IFLA_IFNAME] == NULL) {
-               fprintf(stderr, "BUG: nil ifname\n");
+               fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n",
+                       ifi->ifi_index);
                return -1;
        }
 
+       open_json_object(NULL);
        if (n->nlmsg_type == RTM_DELLINK)
-               fprintf(fp, "Deleted ");
-
-       fprintf(fp, "%d: %s ", ifi->ifi_index,
-               tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>");
-
-       if (tb[IFLA_OPERSTATE])
-               print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
+
+       print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index);
+       if (tb[IFLA_IFNAME]) {
+               print_color_string(PRINT_ANY,
+                                  COLOR_IFNAME,
+                                  "ifname", "%s",
+                                  rta_getattr_str(tb[IFLA_IFNAME]));
+       } else {
+               print_null(PRINT_JSON, "ifname", NULL, NULL);
+               print_color_null(PRINT_FP, COLOR_IFNAME,
+                                "ifname", "%s", "<nil>");
+       }
 
        if (tb[IFLA_LINK]) {
                int iflink = rta_getattr_u32(tb[IFLA_LINK]);
 
-               fprintf(fp, "@%s: ",
-                       iflink ? ll_index_to_name(iflink) : "NONE");
-       } else
-               fprintf(fp, ": ");
+               if (iflink == 0)
+                       print_null(PRINT_ANY, "link", "@%s: ", "NONE");
+               else {
+                       if (tb[IFLA_LINK_NETNSID])
+                               print_int(PRINT_ANY,
+                                         "link_index", "@if%d: ", iflink);
+                       else {
+                               SPRINT_BUF(b1);
+
+                               print_string(PRINT_ANY,
+                                            "link",
+                                            "@%s: ",
+                                            ll_idx_n2a(iflink, b1));
+                               m_flag = ll_index_to_flags(iflink);
+                               m_flag = !(m_flag & IFF_UP);
+                       }
+               }
+       } else {
+               print_string(PRINT_FP, NULL, ": ", NULL);
+       }
+       print_link_flags(fp, ifi->ifi_flags, m_flag);
 
-       print_link_flags(fp, ifi->ifi_flags);
+       if (tb[IFLA_OPERSTATE])
+               print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
 
        if (tb[IFLA_MTU])
-               fprintf(fp, "mtu %u ", rta_getattr_u32(tb[IFLA_MTU]));
+               print_int(PRINT_ANY,
+                         "mtu", "mtu %u ",
+                         rta_getattr_u32(tb[IFLA_MTU]));
 
        if (tb[IFLA_MASTER]) {
-               int master = rta_getattr_u32(tb[IFLA_MASTER]);
+               SPRINT_BUF(b1);
 
-               fprintf(fp, "master %s ", ll_index_to_name(master));
+               print_string(PRINT_ANY, "master", "master %s ",
+                            ll_idx_n2a(rta_getattr_u32(tb[IFLA_MASTER]), b1));
        }
 
-       if (tb[IFLA_PROTINFO]) {
-               if (tb[IFLA_PROTINFO]->rta_type & NLA_F_NESTED) {
-                       struct rtattr *prtb[IFLA_BRPORT_MAX+1];
-
-                       parse_rtattr_nested(prtb, IFLA_BRPORT_MAX,
-                                           tb[IFLA_PROTINFO]);
-
-                       if (prtb[IFLA_BRPORT_STATE])
-                               print_portstate(fp,
-                                               
rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
-                       if (prtb[IFLA_BRPORT_PRIORITY])
-                               fprintf(fp, "priority %hu ",
-                                       
rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY]));
-                       if (prtb[IFLA_BRPORT_COST])
-                               fprintf(fp, "cost %u ",
-                                       
rta_getattr_u32(prtb[IFLA_BRPORT_COST]));
-
-                       if (show_details) {
-                               fprintf(fp, "%s    ", _SL_);
-
-                               if (prtb[IFLA_BRPORT_MODE])
-                                       print_onoff(fp, "hairpin",
-                                                   
rta_getattr_u8(prtb[IFLA_BRPORT_MODE]));
-                               if (prtb[IFLA_BRPORT_GUARD])
-                                       print_onoff(fp, "guard",
-                                                   
rta_getattr_u8(prtb[IFLA_BRPORT_GUARD]));
-                               if (prtb[IFLA_BRPORT_PROTECT])
-                                       print_onoff(fp, "root_block",
-                                                   
rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT]));
-                               if (prtb[IFLA_BRPORT_FAST_LEAVE])
-                                       print_onoff(fp, "fastleave",
-                                                   
rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE]));
-                               if (prtb[IFLA_BRPORT_LEARNING])
-                                       print_onoff(fp, "learning",
-                                                   
rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING]));
-                               if (prtb[IFLA_BRPORT_LEARNING_SYNC])
-                                       print_onoff(fp, "learning_sync",
-                                                   
rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC]));
-                               if (prtb[IFLA_BRPORT_UNICAST_FLOOD])
-                                       print_onoff(fp, "flood",
-                                                   
rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD]));
-                               if (prtb[IFLA_BRPORT_MCAST_FLOOD])
-                                       print_onoff(fp, "mcast_flood",
-                                                   
rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_FLOOD]));
-                               if (prtb[IFLA_BRPORT_NEIGH_SUPPRESS])
-                                       print_onoff(fp, "neigh_suppress",
-                                                   
rta_getattr_u8(prtb[IFLA_BRPORT_NEIGH_SUPPRESS]));
-                               if (prtb[IFLA_BRPORT_VLAN_TUNNEL])
-                                       print_onoff(fp, "vlan_tunnel",
-                                                   
rta_getattr_u8(prtb[IFLA_BRPORT_VLAN_TUNNEL]));
-                       }
-               } else
-                       print_portstate(fp, rta_getattr_u8(tb[IFLA_PROTINFO]));
-       }
+       if (tb[IFLA_PROTINFO])
+               print_protinfo(fp, tb[IFLA_PROTINFO]);
 
-       if (tb[IFLA_AF_SPEC]) {
-               /* This is reported by HW devices that have some bridging
-                * capabilities.
-                */
-               struct rtattr *aftb[IFLA_BRIDGE_MAX+1];
-
-               parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, tb[IFLA_AF_SPEC]);
-
-               if (aftb[IFLA_BRIDGE_MODE])
-                       print_hwmode(fp, 
rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
-               if (show_details) {
-                       if (aftb[IFLA_BRIDGE_VLAN_INFO]) {
-                               fprintf(fp, "\n");
-                               print_vlan_info(fp, tb[IFLA_AF_SPEC],
-                                               ifi->ifi_index);
-                       }
-               }
-       }
+       if (tb[IFLA_AF_SPEC])
+               print_af_spec(fp, tb[IFLA_AF_SPEC]);
 
-       fprintf(fp, "\n");
+       print_string(PRINT_FP, NULL, "%s", "\n");
+       close_json_object();
        fflush(fp);
        return 0;
 }
@@ -499,10 +567,14 @@ static int brlink_show(int argc, char **argv)
                }
        }
 
+       new_json_obj(json);
        if (rtnl_dump_filter(&rth, print_linkinfo, stdout) < 0) {
                fprintf(stderr, "Dump terminated\n");
                exit(1);
        }
+
+       delete_json_obj();
+       fflush(stdout);
        return 0;
 }
 
-- 
2.16.1

Reply via email to