diff --git a/bridge/link.c b/bridge/link.c index 90c9734d..e7ad5c61 100644 --- a/bridge/link.c +++ b/bridge/link.c @@ -12,6 +12,7 @@ #include #include +#include "json_print.h" #include "libnetlink.h" #include "utils.h" #include "br_common.h" @@ -26,15 +27,21 @@ static const char *port_states[] = { [BR_STATE_BLOCKING] = "blocking", }; -static void print_link_flags(FILE *fp, unsigned int flags) +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 +62,119 @@ 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]); -} - -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, @@ -101,6 +183,7 @@ int print_linkinfo(const struct sockaddr_nl *who, FILE *fp = arg; struct ifinfomsg *ifi = NLMSG_DATA(n); struct rtattr *tb[IFLA_MAX+1]; + unsigned int m_flag = 0; int len = n->nlmsg_len; const char *name; @@ -122,102 +205,34 @@ int print_linkinfo(const struct sockaddr_nl *who, if (!name) return -1; + open_json_object(NULL); if (n->nlmsg_type == RTM_DELLINK) - fprintf(fp, "Deleted "); + print_bool(PRINT_ANY, "deleted", "Deleted ", true); - fprintf(fp, "%d: ", ifi->ifi_index); - - print_name_and_link("%s: ", COLOR_NONE, name, tb); - - if (tb[IFLA_OPERSTATE]) - print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE])); - - print_link_flags(fp, ifi->ifi_flags); + print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index); + m_flag = print_name_and_link("%s: ", COLOR_IFNAME, name, tb); + print_link_flags(fp, ifi->ifi_flags, m_flag); 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]); - fprintf(fp, "master %s ", ll_index_to_name(master)); + print_string(PRINT_ANY, "master", "master %s ", + ll_index_to_name(master)); } - if (tb[IFLA_PROTINFO]) { - if (tb[IFLA_PROTINFO]->rta_type & NLA_F_NESTED) { - struct rtattr *prtb[IFLA_BRPORT_MAX+1]; + if (tb[IFLA_PROTINFO]) + print_protinfo(fp, tb[IFLA_PROTINFO]); - parse_rtattr_nested(prtb, IFLA_BRPORT_MAX, - tb[IFLA_PROTINFO]); + if (tb[IFLA_AF_SPEC]) + print_af_spec(fp, tb[IFLA_AF_SPEC]); - 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_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); - } - } - } - - fprintf(fp, "\n"); + print_string(PRINT_FP, NULL, "%s", "\n"); + close_json_object(); fflush(fp); return 0; } @@ -492,10 +507,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; }