iplink: bridge: add support for displaying xstats
Add support for the new parse/print_ifla_xstats callbacks and use them to
print the per-bridge multicast stats.
Example:
$ ip link xstats type bridge
br0
IGMP queries:
RX: v1 0 v2 0 v3 0
TX: v1 0 v2 0 v3 0
IGMP reports:
RX: v1 0 v2 0 v3 0
TX: v1 0 v2 0 v3 0
IGMP leaves: RX: 0 TX: 0
IGMP parse errors: 0
MLD queries:
RX: v1 0 v2 0
TX: v1 0 v2 0
MLD reports:
RX: v1 0 v2 0
TX: v1 0 v2 0
MLD leaves: RX: 0 TX: 0
MLD parse errors: 0
Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
This commit is contained in:
parent
94f1a22aa7
commit
60ec0ecf0f
|
|
@ -12,13 +12,19 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <linux/if_link.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <netinet/ether.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "rt_names.h"
|
||||
#include "utils.h"
|
||||
#include "ip_common.h"
|
||||
|
||||
static unsigned int xstats_print_attr;
|
||||
static int filter_index;
|
||||
|
||||
static void print_explain(FILE *f)
|
||||
{
|
||||
fprintf(f,
|
||||
|
|
@ -582,10 +588,157 @@ static void bridge_print_help(struct link_util *lu, int argc, char **argv,
|
|||
print_explain(f);
|
||||
}
|
||||
|
||||
static void bridge_print_xstats_help(struct link_util *lu, FILE *f)
|
||||
{
|
||||
fprintf(f, "Usage: ... %s [ igmp ] [ dev DEVICE ]\n", lu->id);
|
||||
}
|
||||
|
||||
static void bridge_print_stats_attr(FILE *f, struct rtattr *attr, int ifindex)
|
||||
{
|
||||
struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
|
||||
struct br_mcast_stats *mstats;
|
||||
struct rtattr *i, *list;
|
||||
const char *ifname = "";
|
||||
int rem;
|
||||
|
||||
parse_rtattr(brtb, LINK_XSTATS_TYPE_MAX, RTA_DATA(attr),
|
||||
RTA_PAYLOAD(attr));
|
||||
if (!brtb[LINK_XSTATS_TYPE_BRIDGE])
|
||||
return;
|
||||
|
||||
list = brtb[LINK_XSTATS_TYPE_BRIDGE];
|
||||
rem = RTA_PAYLOAD(list);
|
||||
for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
|
||||
if (xstats_print_attr && i->rta_type != xstats_print_attr)
|
||||
continue;
|
||||
switch (i->rta_type) {
|
||||
case BRIDGE_XSTATS_MCAST:
|
||||
mstats = RTA_DATA(i);
|
||||
ifname = ll_index_to_name(ifindex);
|
||||
fprintf(f, "%-16s\n", ifname);
|
||||
fprintf(f, "%-16s IGMP queries:\n", "");
|
||||
fprintf(f, "%-16s RX: v1 %llu v2 %llu v3 %llu\n",
|
||||
"",
|
||||
mstats->igmp_v1queries[BR_MCAST_DIR_RX],
|
||||
mstats->igmp_v2queries[BR_MCAST_DIR_RX],
|
||||
mstats->igmp_v3queries[BR_MCAST_DIR_RX]);
|
||||
fprintf(f, "%-16s TX: v1 %llu v2 %llu v3 %llu\n",
|
||||
"",
|
||||
mstats->igmp_v1queries[BR_MCAST_DIR_TX],
|
||||
mstats->igmp_v2queries[BR_MCAST_DIR_TX],
|
||||
mstats->igmp_v3queries[BR_MCAST_DIR_TX]);
|
||||
|
||||
fprintf(f, "%-16s IGMP reports:\n", "");
|
||||
fprintf(f, "%-16s RX: v1 %llu v2 %llu v3 %llu\n",
|
||||
"",
|
||||
mstats->igmp_v1reports[BR_MCAST_DIR_RX],
|
||||
mstats->igmp_v2reports[BR_MCAST_DIR_RX],
|
||||
mstats->igmp_v3reports[BR_MCAST_DIR_RX]);
|
||||
fprintf(f, "%-16s TX: v1 %llu v2 %llu v3 %llu\n",
|
||||
"",
|
||||
mstats->igmp_v1reports[BR_MCAST_DIR_TX],
|
||||
mstats->igmp_v2reports[BR_MCAST_DIR_TX],
|
||||
mstats->igmp_v3reports[BR_MCAST_DIR_TX]);
|
||||
|
||||
fprintf(f, "%-16s IGMP leaves: RX: %llu TX: %llu\n",
|
||||
"",
|
||||
mstats->igmp_leaves[BR_MCAST_DIR_RX],
|
||||
mstats->igmp_leaves[BR_MCAST_DIR_TX]);
|
||||
|
||||
fprintf(f, "%-16s IGMP parse errors: %llu\n",
|
||||
"", mstats->igmp_parse_errors);
|
||||
|
||||
fprintf(f, "%-16s MLD queries:\n", "");
|
||||
fprintf(f, "%-16s RX: v1 %llu v2 %llu\n",
|
||||
"",
|
||||
mstats->mld_v1queries[BR_MCAST_DIR_RX],
|
||||
mstats->mld_v2queries[BR_MCAST_DIR_RX]);
|
||||
fprintf(f, "%-16s TX: v1 %llu v2 %llu\n",
|
||||
"",
|
||||
mstats->mld_v1queries[BR_MCAST_DIR_TX],
|
||||
mstats->mld_v2queries[BR_MCAST_DIR_TX]);
|
||||
|
||||
fprintf(f, "%-16s MLD reports:\n", "");
|
||||
fprintf(f, "%-16s RX: v1 %llu v2 %llu\n",
|
||||
"",
|
||||
mstats->mld_v1reports[BR_MCAST_DIR_RX],
|
||||
mstats->mld_v2reports[BR_MCAST_DIR_RX]);
|
||||
fprintf(f, "%-16s TX: v1 %llu v2 %llu\n",
|
||||
"",
|
||||
mstats->mld_v1reports[BR_MCAST_DIR_TX],
|
||||
mstats->mld_v2reports[BR_MCAST_DIR_TX]);
|
||||
|
||||
fprintf(f, "%-16s MLD leaves: RX: %llu TX: %llu\n",
|
||||
"",
|
||||
mstats->mld_leaves[BR_MCAST_DIR_RX],
|
||||
mstats->mld_leaves[BR_MCAST_DIR_TX]);
|
||||
|
||||
fprintf(f, "%-16s MLD parse errors: %llu\n",
|
||||
"", mstats->mld_parse_errors);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int bridge_print_xstats(const struct sockaddr_nl *who,
|
||||
struct nlmsghdr *n, void *arg)
|
||||
{
|
||||
struct if_stats_msg *ifsm = NLMSG_DATA(n);
|
||||
struct rtattr *tb[IFLA_STATS_MAX+1];
|
||||
int len = n->nlmsg_len;
|
||||
FILE *fp = arg;
|
||||
|
||||
len -= NLMSG_LENGTH(sizeof(*ifsm));
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
|
||||
return -1;
|
||||
}
|
||||
if (filter_index && filter_index != ifsm->ifindex)
|
||||
return 0;
|
||||
|
||||
parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
|
||||
if (tb[IFLA_STATS_LINK_XSTATS])
|
||||
bridge_print_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS],
|
||||
ifsm->ifindex);
|
||||
|
||||
if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
|
||||
bridge_print_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS_SLAVE],
|
||||
ifsm->ifindex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bridge_parse_xstats(struct link_util *lu, int argc, char **argv)
|
||||
{
|
||||
while (argc > 0) {
|
||||
if (strcmp(*argv, "igmp") == 0 || strcmp(*argv, "mcast") == 0) {
|
||||
xstats_print_attr = BRIDGE_XSTATS_MCAST;
|
||||
} else if (strcmp(*argv, "dev") == 0) {
|
||||
NEXT_ARG();
|
||||
filter_index = if_nametoindex(*argv);
|
||||
if (filter_index == 0) {
|
||||
fprintf(stderr, "Cannot find device \"%s\"\n",
|
||||
*argv);
|
||||
return -1;
|
||||
}
|
||||
} else if (strcmp(*argv, "help") == 0) {
|
||||
bridge_print_xstats_help(lu, stdout);
|
||||
exit(0);
|
||||
} else {
|
||||
invarg("unknown attribute", *argv);
|
||||
}
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct link_util bridge_link_util = {
|
||||
.id = "bridge",
|
||||
.maxattr = IFLA_BR_MAX,
|
||||
.parse_opt = bridge_parse_opt,
|
||||
.print_opt = bridge_print_opt,
|
||||
.print_help = bridge_print_help,
|
||||
.parse_ifla_xstats = bridge_parse_xstats,
|
||||
.print_ifla_xstats = bridge_print_xstats,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue