ip: bridge: add xstats json support

Add json support for bridge's xstats output.
The plain text output format should remain the same.
Note that this patch pulls the interface out of the attribute
loop, this was an oversight when the set was upstreamed. This does not
change the output format, but fixes it when new xstats attributes show
up.

Example:
$ ip -p -j link xstats type bridge
  [ {
        "ifname": "br0",
        "multicast": {
            "igmp_queries": {
                "rx_v1": 0,
                "rx_v2": 32,
                "rx_v3": 0,
                "tx_v1": 0,
                "tx_v2": 0,
                "tx_v3": 0
            },
            "igmp_reports": {
                "rx_v1": 0,
                "rx_v2": 32,
                "rx_v3": 0,
                "tx_v1": 0,
                "tx_v2": 0,
                "tx_v3": 0
            },
            "igmp_leaves": {
                "rx": 0,
                "tx": 0
            },
            "igmp_parse_errors": 0,
            "mld_queries": {
                "rx_v1": 33,
                "rx_v2": 0,
                "tx_v1": 0,
                "tx_v2": 0
            },
            "mld_reports": {
                "rx_v1": 66,
                "rx_v2": 2,
                "tx_v1": 0,
                "tx_v2": 0
            },
            "mld_leaves": {
                "rx": 0,
                "tx": 0
            },
            "mld_parse_errors": 0
        }
    } ]

Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
Nikolay Aleksandrov 2019-03-12 18:41:27 +02:00 committed by David Ahern
parent 8ff3d1d3a3
commit a9bc23a792

View File

@ -670,7 +670,7 @@ static void bridge_print_xstats_help(struct link_util *lu, FILE *f)
fprintf(f, "Usage: ... %s [ igmp ] [ dev DEVICE ]\n", lu->id); fprintf(f, "Usage: ... %s [ igmp ] [ dev DEVICE ]\n", lu->id);
} }
static void bridge_print_stats_attr(FILE *f, struct rtattr *attr, int ifindex) static void bridge_print_stats_attr(struct rtattr *attr, int ifindex)
{ {
struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1]; struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
struct br_mcast_stats *mstats; struct br_mcast_stats *mstats;
@ -685,76 +685,116 @@ static void bridge_print_stats_attr(FILE *f, struct rtattr *attr, int ifindex)
list = brtb[LINK_XSTATS_TYPE_BRIDGE]; list = brtb[LINK_XSTATS_TYPE_BRIDGE];
rem = RTA_PAYLOAD(list); rem = RTA_PAYLOAD(list);
open_json_object(NULL);
ifname = ll_index_to_name(ifindex);
print_string(PRINT_ANY, "ifname", "%-16s\n", ifname);
for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
if (xstats_print_attr && i->rta_type != xstats_print_attr) if (xstats_print_attr && i->rta_type != xstats_print_attr)
continue; continue;
switch (i->rta_type) { switch (i->rta_type) {
case BRIDGE_XSTATS_MCAST: case BRIDGE_XSTATS_MCAST:
mstats = RTA_DATA(i); mstats = RTA_DATA(i);
ifname = ll_index_to_name(ifindex); open_json_object("multicast");
fprintf(f, "%-16s\n", ifname); open_json_object("igmp_queries");
fprintf(f, "%-16s IGMP queries:\n", ""); print_string(PRINT_FP, NULL,
fprintf(f, "%-16s RX: v1 %llu v2 %llu v3 %llu\n", "%-16s IGMP queries:\n", "");
"", print_string(PRINT_FP, NULL, "%-16s ", "");
mstats->igmp_v1queries[BR_MCAST_DIR_RX], print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
mstats->igmp_v2queries[BR_MCAST_DIR_RX], mstats->igmp_v1queries[BR_MCAST_DIR_RX]);
mstats->igmp_v3queries[BR_MCAST_DIR_RX]); print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
fprintf(f, "%-16s TX: v1 %llu v2 %llu v3 %llu\n", mstats->igmp_v2queries[BR_MCAST_DIR_RX]);
"", print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
mstats->igmp_v1queries[BR_MCAST_DIR_TX], mstats->igmp_v3queries[BR_MCAST_DIR_RX]);
mstats->igmp_v2queries[BR_MCAST_DIR_TX], print_string(PRINT_FP, NULL, "%-16s ", "");
mstats->igmp_v3queries[BR_MCAST_DIR_TX]); print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
mstats->igmp_v1queries[BR_MCAST_DIR_TX]);
print_u64(PRINT_ANY, "tx_v2", "v2 %llu ",
mstats->igmp_v2queries[BR_MCAST_DIR_TX]);
print_u64(PRINT_ANY, "tx_v3", "v3 %llu\n",
mstats->igmp_v3queries[BR_MCAST_DIR_TX]);
close_json_object();
fprintf(f, "%-16s IGMP reports:\n", ""); open_json_object("igmp_reports");
fprintf(f, "%-16s RX: v1 %llu v2 %llu v3 %llu\n", print_string(PRINT_FP, NULL,
"", "%-16s IGMP reports:\n", "");
mstats->igmp_v1reports[BR_MCAST_DIR_RX], print_string(PRINT_FP, NULL, "%-16s ", "");
mstats->igmp_v2reports[BR_MCAST_DIR_RX], print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
mstats->igmp_v3reports[BR_MCAST_DIR_RX]); mstats->igmp_v1reports[BR_MCAST_DIR_RX]);
fprintf(f, "%-16s TX: v1 %llu v2 %llu v3 %llu\n", print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
"", mstats->igmp_v2reports[BR_MCAST_DIR_RX]);
mstats->igmp_v1reports[BR_MCAST_DIR_TX], print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
mstats->igmp_v2reports[BR_MCAST_DIR_TX], mstats->igmp_v3reports[BR_MCAST_DIR_RX]);
mstats->igmp_v3reports[BR_MCAST_DIR_TX]); print_string(PRINT_FP, NULL, "%-16s ", "");
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
mstats->igmp_v1reports[BR_MCAST_DIR_TX]);
print_u64(PRINT_ANY, "tx_v2", "v2 %llu",
mstats->igmp_v2reports[BR_MCAST_DIR_TX]);
print_u64(PRINT_ANY, "tx_v3", "v3 %llu\n",
mstats->igmp_v3reports[BR_MCAST_DIR_TX]);
close_json_object();
fprintf(f, "%-16s IGMP leaves: RX: %llu TX: %llu\n", open_json_object("igmp_leaves");
"", print_string(PRINT_FP, NULL,
mstats->igmp_leaves[BR_MCAST_DIR_RX], "%-16s IGMP leaves: ", "");
mstats->igmp_leaves[BR_MCAST_DIR_TX]); print_u64(PRINT_ANY, "rx", "RX: %llu ",
mstats->igmp_leaves[BR_MCAST_DIR_RX]);
print_u64(PRINT_ANY, "tx", "TX: %llu\n",
mstats->igmp_leaves[BR_MCAST_DIR_TX]);
close_json_object();
fprintf(f, "%-16s IGMP parse errors: %llu\n", print_string(PRINT_FP, NULL,
"", mstats->igmp_parse_errors); "%-16s IGMP parse errors: ", "");
print_u64(PRINT_ANY, "igmp_parse_errors", "%llu\n",
mstats->igmp_parse_errors);
fprintf(f, "%-16s MLD queries:\n", ""); open_json_object("mld_queries");
fprintf(f, "%-16s RX: v1 %llu v2 %llu\n", print_string(PRINT_FP, NULL,
"", "%-16s MLD queries:\n", "");
mstats->mld_v1queries[BR_MCAST_DIR_RX], print_string(PRINT_FP, NULL, "%-16s ", "");
mstats->mld_v2queries[BR_MCAST_DIR_RX]); print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
fprintf(f, "%-16s TX: v1 %llu v2 %llu\n", mstats->mld_v1queries[BR_MCAST_DIR_RX]);
"", print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
mstats->mld_v1queries[BR_MCAST_DIR_TX], mstats->mld_v2queries[BR_MCAST_DIR_RX]);
mstats->mld_v2queries[BR_MCAST_DIR_TX]); print_string(PRINT_FP, NULL, "%-16s ", "");
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
mstats->mld_v1queries[BR_MCAST_DIR_TX]);
print_u64(PRINT_ANY, "tx_v2", "v2 %llu\n",
mstats->mld_v2queries[BR_MCAST_DIR_TX]);
close_json_object();
fprintf(f, "%-16s MLD reports:\n", ""); open_json_object("mld_reports");
fprintf(f, "%-16s RX: v1 %llu v2 %llu\n", print_string(PRINT_FP, NULL,
"", "%-16s MLD reports:\n", "");
mstats->mld_v1reports[BR_MCAST_DIR_RX], print_string(PRINT_FP, NULL, "%-16s ", "");
mstats->mld_v2reports[BR_MCAST_DIR_RX]); print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
fprintf(f, "%-16s TX: v1 %llu v2 %llu\n", mstats->mld_v1reports[BR_MCAST_DIR_RX]);
"", print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
mstats->mld_v1reports[BR_MCAST_DIR_TX], mstats->mld_v2reports[BR_MCAST_DIR_RX]);
mstats->mld_v2reports[BR_MCAST_DIR_TX]); print_string(PRINT_FP, NULL, "%-16s ", "");
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
mstats->mld_v1reports[BR_MCAST_DIR_TX]);
print_u64(PRINT_ANY, "tx_v2", "v2 %llu\n",
mstats->mld_v2reports[BR_MCAST_DIR_TX]);
close_json_object();
fprintf(f, "%-16s MLD leaves: RX: %llu TX: %llu\n", open_json_object("mld_leaves");
"", print_string(PRINT_FP, NULL,
mstats->mld_leaves[BR_MCAST_DIR_RX], "%-16s MLD leaves: ", "");
mstats->mld_leaves[BR_MCAST_DIR_TX]); print_u64(PRINT_ANY, "rx", "RX: %llu ",
mstats->mld_leaves[BR_MCAST_DIR_RX]);
print_u64(PRINT_ANY, "tx", "TX: %llu\n",
mstats->mld_leaves[BR_MCAST_DIR_TX]);
close_json_object();
fprintf(f, "%-16s MLD parse errors: %llu\n", print_string(PRINT_FP, NULL,
"", mstats->mld_parse_errors); "%-16s MLD parse errors: ", "");
print_u64(PRINT_ANY, "mld_parse_errors", "%llu\n",
mstats->mld_parse_errors);
close_json_object();
break; break;
} }
} }
close_json_object();
} }
int bridge_print_xstats(struct nlmsghdr *n, void *arg) int bridge_print_xstats(struct nlmsghdr *n, void *arg)
@ -762,7 +802,6 @@ int bridge_print_xstats(struct nlmsghdr *n, void *arg)
struct if_stats_msg *ifsm = NLMSG_DATA(n); struct if_stats_msg *ifsm = NLMSG_DATA(n);
struct rtattr *tb[IFLA_STATS_MAX+1]; struct rtattr *tb[IFLA_STATS_MAX+1];
int len = n->nlmsg_len; int len = n->nlmsg_len;
FILE *fp = arg;
len -= NLMSG_LENGTH(sizeof(*ifsm)); len -= NLMSG_LENGTH(sizeof(*ifsm));
if (len < 0) { if (len < 0) {
@ -774,11 +813,11 @@ int bridge_print_xstats(struct nlmsghdr *n, void *arg)
parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len); parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
if (tb[IFLA_STATS_LINK_XSTATS]) if (tb[IFLA_STATS_LINK_XSTATS])
bridge_print_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS], bridge_print_stats_attr(tb[IFLA_STATS_LINK_XSTATS],
ifsm->ifindex); ifsm->ifindex);
if (tb[IFLA_STATS_LINK_XSTATS_SLAVE]) if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
bridge_print_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS_SLAVE], bridge_print_stats_attr(tb[IFLA_STATS_LINK_XSTATS_SLAVE],
ifsm->ifindex); ifsm->ifindex);
return 0; return 0;