mirror of
https://git.kernel.org/pub/scm/network/iproute2/iproute2.git
synced 2024-11-15 05:55:11 +08:00
Merge branch 'support-xstats-afstats' into next
Petr Machata says: ==================== The RTM_GETSTATS response attributes IFLA_STATS_LINK_XSTATS and IFLA_STATS_LINK_XSTATS_SLAVE are used to carry statistics related to, respectively, netdevices of a certain type, and netdevices enslaved to netdevices of a certain type. IFLA_STATS_AF_SPEC are similarly used to carry statistics specific to a certain address family. In this patch set, add support for three new stats groups that cover the above attributes: xstats, xstats_slave and afstats. Add bridge and bond subgroups to the former two groups, and mpls subgroup to the latter one. Now "group" is used for selecting the top-level attribute, and subgroup for the link-type or address-family nest below it (bridge, bond, mpls in this patchset). But xstats (both master and slave) are further subdivided. E.g. in the case of bridge statistics, the two subdivisions are called "stp" and "mcast". To make it possible to pick these sets, add to the two selector levels of group and subgroup a third level, suite, which is filtered in the userspace. ==================== Signed-off-by: David Ahern <dsahern@kernel.org>
This commit is contained in:
commit
5a179c7217
@ -3,6 +3,7 @@
|
||||
#define _IP_COMMON_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <linux/mpls.h>
|
||||
|
||||
#include "json_print.h"
|
||||
|
||||
@ -141,9 +142,14 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type);
|
||||
void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len);
|
||||
int bridge_parse_xstats(struct link_util *lu, int argc, char **argv);
|
||||
int bridge_print_xstats(struct nlmsghdr *n, void *arg);
|
||||
extern const struct ipstats_stat_desc ipstats_stat_desc_xstats_bridge_group;
|
||||
extern const struct ipstats_stat_desc ipstats_stat_desc_xstats_slave_bridge_group;
|
||||
|
||||
/* iplink_bond.c */
|
||||
int bond_parse_xstats(struct link_util *lu, int argc, char **argv);
|
||||
int bond_print_xstats(struct nlmsghdr *n, void *arg);
|
||||
extern const struct ipstats_stat_desc ipstats_stat_desc_xstats_bond_group;
|
||||
extern const struct ipstats_stat_desc ipstats_stat_desc_xstats_slave_bond_group;
|
||||
|
||||
/* iproute_lwtunnel.c */
|
||||
int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp,
|
||||
@ -185,6 +191,20 @@ struct ipstats_stat_desc {
|
||||
};
|
||||
};
|
||||
|
||||
struct ipstats_stat_desc_xstats {
|
||||
const struct ipstats_stat_desc desc;
|
||||
int xstats_at;
|
||||
int link_type_at;
|
||||
int inner_max;
|
||||
int inner_at;
|
||||
void (*show_cb)(const struct rtattr *at);
|
||||
};
|
||||
|
||||
void ipstats_stat_desc_pack_xstats(struct ipstats_stat_dump_filters *filters,
|
||||
const struct ipstats_stat_desc *desc);
|
||||
int ipstats_stat_desc_show_xstats(struct ipstats_stat_show_attrs *attrs,
|
||||
const struct ipstats_stat_desc *desc);
|
||||
|
||||
#ifndef INFINITY_LIFE_TIME
|
||||
#define INFINITY_LIFE_TIME 0xFFFFFFFFU
|
||||
#endif
|
||||
@ -202,4 +222,6 @@ void print_rta_gateway(FILE *fp, unsigned char family,
|
||||
void size_columns(unsigned int cols[], unsigned int n, ...);
|
||||
void print_stats64(FILE *fp, struct rtnl_link_stats64 *s,
|
||||
const struct rtattr *carrier_changes, const char *what);
|
||||
void print_mpls_link_stats(FILE *fp, const struct mpls_link_stats *stats,
|
||||
const char *indent);
|
||||
#endif /* _IP_COMMON_H_ */
|
||||
|
75
ip/iplink.c
75
ip/iplink.c
@ -1517,6 +1517,65 @@ static int do_set(int argc, char **argv)
|
||||
}
|
||||
#endif /* IPLINK_IOCTL_COMPAT */
|
||||
|
||||
void print_mpls_link_stats(FILE *fp, const struct mpls_link_stats *stats,
|
||||
const char *indent)
|
||||
{
|
||||
unsigned int cols[] = {
|
||||
strlen("*X: bytes"),
|
||||
strlen("packets"),
|
||||
strlen("errors"),
|
||||
strlen("dropped"),
|
||||
strlen("noroute"),
|
||||
};
|
||||
|
||||
if (is_json_context()) {
|
||||
/* RX stats */
|
||||
open_json_object("rx");
|
||||
print_u64(PRINT_JSON, "bytes", NULL, stats->rx_bytes);
|
||||
print_u64(PRINT_JSON, "packets", NULL, stats->rx_packets);
|
||||
print_u64(PRINT_JSON, "errors", NULL, stats->rx_errors);
|
||||
print_u64(PRINT_JSON, "dropped", NULL, stats->rx_dropped);
|
||||
print_u64(PRINT_JSON, "noroute", NULL, stats->rx_noroute);
|
||||
close_json_object();
|
||||
|
||||
/* TX stats */
|
||||
open_json_object("tx");
|
||||
print_u64(PRINT_JSON, "bytes", NULL, stats->tx_bytes);
|
||||
print_u64(PRINT_JSON, "packets", NULL, stats->tx_packets);
|
||||
print_u64(PRINT_JSON, "errors", NULL, stats->tx_errors);
|
||||
print_u64(PRINT_JSON, "dropped", NULL, stats->tx_dropped);
|
||||
close_json_object();
|
||||
} else {
|
||||
size_columns(cols, ARRAY_SIZE(cols), stats->rx_bytes,
|
||||
stats->rx_packets, stats->rx_errors,
|
||||
stats->rx_dropped, stats->rx_noroute);
|
||||
size_columns(cols, ARRAY_SIZE(cols), stats->tx_bytes,
|
||||
stats->tx_packets, stats->tx_errors,
|
||||
stats->tx_dropped, 0);
|
||||
|
||||
fprintf(fp, "%sRX: %*s %*s %*s %*s %*s%s", indent,
|
||||
cols[0] - 4, "bytes", cols[1], "packets",
|
||||
cols[2], "errors", cols[3], "dropped",
|
||||
cols[4], "noroute", _SL_);
|
||||
fprintf(fp, "%s", indent);
|
||||
print_num(fp, cols[0], stats->rx_bytes);
|
||||
print_num(fp, cols[1], stats->rx_packets);
|
||||
print_num(fp, cols[2], stats->rx_errors);
|
||||
print_num(fp, cols[3], stats->rx_dropped);
|
||||
print_num(fp, cols[4], stats->rx_noroute);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "%sTX: %*s %*s %*s %*s%s", indent,
|
||||
cols[0] - 4, "bytes", cols[1], "packets",
|
||||
cols[2], "errors", cols[3], "dropped", _SL_);
|
||||
fprintf(fp, "%s", indent);
|
||||
print_num(fp, cols[0], stats->tx_bytes);
|
||||
print_num(fp, cols[1], stats->tx_packets);
|
||||
print_num(fp, cols[2], stats->tx_errors);
|
||||
print_num(fp, cols[3], stats->tx_dropped);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_mpls_stats(FILE *fp, struct rtattr *attr)
|
||||
{
|
||||
struct rtattr *mrtb[MPLS_STATS_MAX+1];
|
||||
@ -1528,22 +1587,8 @@ static void print_mpls_stats(FILE *fp, struct rtattr *attr)
|
||||
return;
|
||||
|
||||
stats = RTA_DATA(mrtb[MPLS_STATS_LINK]);
|
||||
|
||||
fprintf(fp, " mpls:\n");
|
||||
fprintf(fp, " RX: bytes packets errors dropped noroute\n");
|
||||
fprintf(fp, " ");
|
||||
print_num(fp, 10, stats->rx_bytes);
|
||||
print_num(fp, 8, stats->rx_packets);
|
||||
print_num(fp, 7, stats->rx_errors);
|
||||
print_num(fp, 8, stats->rx_dropped);
|
||||
print_num(fp, 7, stats->rx_noroute);
|
||||
fprintf(fp, "\n");
|
||||
fprintf(fp, " TX: bytes packets errors dropped\n");
|
||||
fprintf(fp, " ");
|
||||
print_num(fp, 10, stats->tx_bytes);
|
||||
print_num(fp, 8, stats->tx_packets);
|
||||
print_num(fp, 7, stats->tx_errors);
|
||||
print_num(fp, 7, stats->tx_dropped);
|
||||
print_mpls_link_stats(fp, stats, " ");
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <string.h>
|
||||
#include <linux/if_bonding.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "rt_names.h"
|
||||
#include "utils.h"
|
||||
#include "ip_common.h"
|
||||
@ -761,7 +762,7 @@ static void bond_print_xstats_help(struct link_util *lu, FILE *f)
|
||||
fprintf(f, "Usage: ... %s [ 802.3ad ] [ dev DEVICE ]\n", lu->id);
|
||||
}
|
||||
|
||||
static void bond_print_3ad_stats(struct rtattr *lacpattr)
|
||||
static void bond_print_3ad_stats(const struct rtattr *lacpattr)
|
||||
{
|
||||
struct rtattr *lacptb[BOND_3AD_STAT_MAX+1];
|
||||
__u64 val;
|
||||
@ -912,7 +913,6 @@ int bond_parse_xstats(struct link_util *lu, int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct link_util bond_link_util = {
|
||||
.id = "bond",
|
||||
.maxattr = IFLA_BOND_MAX,
|
||||
@ -922,3 +922,54 @@ struct link_util bond_link_util = {
|
||||
.parse_ifla_xstats = bond_parse_xstats,
|
||||
.print_ifla_xstats = bond_print_xstats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc ipstats_stat_desc_bond_tmpl_lacp = {
|
||||
.name = "802.3ad",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_LEAF,
|
||||
.show = &ipstats_stat_desc_show_xstats,
|
||||
.pack = &ipstats_stat_desc_pack_xstats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc_xstats
|
||||
ipstats_stat_desc_xstats_bond_lacp = {
|
||||
.desc = ipstats_stat_desc_bond_tmpl_lacp,
|
||||
.xstats_at = IFLA_STATS_LINK_XSTATS,
|
||||
.link_type_at = LINK_XSTATS_TYPE_BOND,
|
||||
.inner_max = BOND_XSTATS_MAX,
|
||||
.inner_at = BOND_XSTATS_3AD,
|
||||
.show_cb = &bond_print_3ad_stats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc *
|
||||
ipstats_stat_desc_xstats_bond_subs[] = {
|
||||
&ipstats_stat_desc_xstats_bond_lacp.desc,
|
||||
};
|
||||
|
||||
const struct ipstats_stat_desc ipstats_stat_desc_xstats_bond_group = {
|
||||
.name = "bond",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_GROUP,
|
||||
.subs = ipstats_stat_desc_xstats_bond_subs,
|
||||
.nsubs = ARRAY_SIZE(ipstats_stat_desc_xstats_bond_subs),
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc_xstats
|
||||
ipstats_stat_desc_xstats_slave_bond_lacp = {
|
||||
.desc = ipstats_stat_desc_bond_tmpl_lacp,
|
||||
.xstats_at = IFLA_STATS_LINK_XSTATS_SLAVE,
|
||||
.link_type_at = LINK_XSTATS_TYPE_BOND,
|
||||
.inner_max = BOND_XSTATS_MAX,
|
||||
.inner_at = BOND_XSTATS_3AD,
|
||||
.show_cb = &bond_print_3ad_stats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc *
|
||||
ipstats_stat_desc_xstats_slave_bond_subs[] = {
|
||||
&ipstats_stat_desc_xstats_slave_bond_lacp.desc,
|
||||
};
|
||||
|
||||
const struct ipstats_stat_desc ipstats_stat_desc_xstats_slave_bond_group = {
|
||||
.name = "bond",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_GROUP,
|
||||
.subs = ipstats_stat_desc_xstats_slave_bond_subs,
|
||||
.nsubs = ARRAY_SIZE(ipstats_stat_desc_xstats_slave_bond_subs),
|
||||
};
|
||||
|
@ -714,11 +714,140 @@ 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_mcast(const struct rtattr *attr)
|
||||
{
|
||||
struct br_mcast_stats *mstats;
|
||||
|
||||
mstats = RTA_DATA(attr);
|
||||
open_json_object("multicast");
|
||||
open_json_object("igmp_queries");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP queries:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->igmp_v1queries[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
|
||||
mstats->igmp_v2queries[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
|
||||
mstats->igmp_v3queries[BR_MCAST_DIR_RX]);
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
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();
|
||||
|
||||
open_json_object("igmp_reports");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP reports:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->igmp_v1reports[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
|
||||
mstats->igmp_v2reports[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
|
||||
mstats->igmp_v3reports[BR_MCAST_DIR_RX]);
|
||||
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();
|
||||
|
||||
open_json_object("igmp_leaves");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP leaves: ", "");
|
||||
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();
|
||||
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP parse errors: ", "");
|
||||
print_u64(PRINT_ANY, "igmp_parse_errors", "%llu\n",
|
||||
mstats->igmp_parse_errors);
|
||||
|
||||
open_json_object("mld_queries");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD queries:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->mld_v1queries[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
|
||||
mstats->mld_v2queries[BR_MCAST_DIR_RX]);
|
||||
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();
|
||||
|
||||
open_json_object("mld_reports");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD reports:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->mld_v1reports[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
|
||||
mstats->mld_v2reports[BR_MCAST_DIR_RX]);
|
||||
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();
|
||||
|
||||
open_json_object("mld_leaves");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD leaves: ", "");
|
||||
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();
|
||||
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD parse errors: ", "");
|
||||
print_u64(PRINT_ANY, "mld_parse_errors", "%llu\n",
|
||||
mstats->mld_parse_errors);
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
static void bridge_print_stats_stp(const struct rtattr *attr)
|
||||
{
|
||||
struct bridge_stp_xstats *sstats;
|
||||
|
||||
sstats = RTA_DATA(attr);
|
||||
open_json_object("stp");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s STP BPDU: ", "");
|
||||
print_u64(PRINT_ANY, "rx_bpdu", "RX: %llu ",
|
||||
sstats->rx_bpdu);
|
||||
print_u64(PRINT_ANY, "tx_bpdu", "TX: %llu\n",
|
||||
sstats->tx_bpdu);
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s STP TCN: ", "");
|
||||
print_u64(PRINT_ANY, "rx_tcn", "RX: %llu ",
|
||||
sstats->rx_tcn);
|
||||
print_u64(PRINT_ANY, "tx_tcn", "TX: %llu\n",
|
||||
sstats->tx_tcn);
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s STP Transitions: ", "");
|
||||
print_u64(PRINT_ANY, "transition_blk", "Blocked: %llu ",
|
||||
sstats->transition_blk);
|
||||
print_u64(PRINT_ANY, "transition_fwd", "Forwarding: %llu\n",
|
||||
sstats->transition_fwd);
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
static void bridge_print_stats_attr(struct rtattr *attr, int ifindex)
|
||||
{
|
||||
struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
|
||||
struct bridge_stp_xstats *sstats;
|
||||
struct br_mcast_stats *mstats;
|
||||
struct rtattr *i, *list;
|
||||
const char *ifname = "";
|
||||
int rem;
|
||||
@ -738,127 +867,10 @@ static void bridge_print_stats_attr(struct rtattr *attr, int ifindex)
|
||||
continue;
|
||||
switch (i->rta_type) {
|
||||
case BRIDGE_XSTATS_MCAST:
|
||||
mstats = RTA_DATA(i);
|
||||
open_json_object("multicast");
|
||||
open_json_object("igmp_queries");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP queries:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->igmp_v1queries[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
|
||||
mstats->igmp_v2queries[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
|
||||
mstats->igmp_v3queries[BR_MCAST_DIR_RX]);
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
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();
|
||||
|
||||
open_json_object("igmp_reports");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP reports:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->igmp_v1reports[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
|
||||
mstats->igmp_v2reports[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
|
||||
mstats->igmp_v3reports[BR_MCAST_DIR_RX]);
|
||||
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();
|
||||
|
||||
open_json_object("igmp_leaves");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP leaves: ", "");
|
||||
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();
|
||||
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP parse errors: ", "");
|
||||
print_u64(PRINT_ANY, "igmp_parse_errors", "%llu\n",
|
||||
mstats->igmp_parse_errors);
|
||||
|
||||
open_json_object("mld_queries");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD queries:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->mld_v1queries[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
|
||||
mstats->mld_v2queries[BR_MCAST_DIR_RX]);
|
||||
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();
|
||||
|
||||
open_json_object("mld_reports");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD reports:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->mld_v1reports[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
|
||||
mstats->mld_v2reports[BR_MCAST_DIR_RX]);
|
||||
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();
|
||||
|
||||
open_json_object("mld_leaves");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD leaves: ", "");
|
||||
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();
|
||||
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD parse errors: ", "");
|
||||
print_u64(PRINT_ANY, "mld_parse_errors", "%llu\n",
|
||||
mstats->mld_parse_errors);
|
||||
close_json_object();
|
||||
bridge_print_stats_mcast(i);
|
||||
break;
|
||||
case BRIDGE_XSTATS_STP:
|
||||
sstats = RTA_DATA(i);
|
||||
open_json_object("stp");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s STP BPDU: ", "");
|
||||
print_u64(PRINT_ANY, "rx_bpdu", "RX: %llu ",
|
||||
sstats->rx_bpdu);
|
||||
print_u64(PRINT_ANY, "tx_bpdu", "TX: %llu\n",
|
||||
sstats->tx_bpdu);
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s STP TCN: ", "");
|
||||
print_u64(PRINT_ANY, "rx_tcn", "RX: %llu ",
|
||||
sstats->rx_tcn);
|
||||
print_u64(PRINT_ANY, "tx_tcn", "TX: %llu\n",
|
||||
sstats->tx_tcn);
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s STP Transitions: ", "");
|
||||
print_u64(PRINT_ANY, "transition_blk", "Blocked: %llu ",
|
||||
sstats->transition_blk);
|
||||
print_u64(PRINT_ANY, "transition_fwd", "Forwarding: %llu\n",
|
||||
sstats->transition_fwd);
|
||||
close_json_object();
|
||||
bridge_print_stats_stp(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -924,3 +936,83 @@ struct link_util bridge_link_util = {
|
||||
.parse_ifla_xstats = bridge_parse_xstats,
|
||||
.print_ifla_xstats = bridge_print_xstats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc ipstats_stat_desc_bridge_tmpl_stp = {
|
||||
.name = "stp",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_LEAF,
|
||||
.show = &ipstats_stat_desc_show_xstats,
|
||||
.pack = &ipstats_stat_desc_pack_xstats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc ipstats_stat_desc_bridge_tmpl_mcast = {
|
||||
.name = "mcast",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_LEAF,
|
||||
.show = &ipstats_stat_desc_show_xstats,
|
||||
.pack = &ipstats_stat_desc_pack_xstats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc_xstats
|
||||
ipstats_stat_desc_xstats_bridge_stp = {
|
||||
.desc = ipstats_stat_desc_bridge_tmpl_stp,
|
||||
.xstats_at = IFLA_STATS_LINK_XSTATS,
|
||||
.link_type_at = LINK_XSTATS_TYPE_BRIDGE,
|
||||
.inner_max = BRIDGE_XSTATS_MAX,
|
||||
.inner_at = BRIDGE_XSTATS_STP,
|
||||
.show_cb = &bridge_print_stats_stp,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc_xstats
|
||||
ipstats_stat_desc_xstats_bridge_mcast = {
|
||||
.desc = ipstats_stat_desc_bridge_tmpl_mcast,
|
||||
.xstats_at = IFLA_STATS_LINK_XSTATS,
|
||||
.link_type_at = LINK_XSTATS_TYPE_BRIDGE,
|
||||
.inner_max = BRIDGE_XSTATS_MAX,
|
||||
.inner_at = BRIDGE_XSTATS_MCAST,
|
||||
.show_cb = &bridge_print_stats_mcast,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc *
|
||||
ipstats_stat_desc_xstats_bridge_subs[] = {
|
||||
&ipstats_stat_desc_xstats_bridge_stp.desc,
|
||||
&ipstats_stat_desc_xstats_bridge_mcast.desc,
|
||||
};
|
||||
|
||||
const struct ipstats_stat_desc ipstats_stat_desc_xstats_bridge_group = {
|
||||
.name = "bridge",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_GROUP,
|
||||
.subs = ipstats_stat_desc_xstats_bridge_subs,
|
||||
.nsubs = ARRAY_SIZE(ipstats_stat_desc_xstats_bridge_subs),
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc_xstats
|
||||
ipstats_stat_desc_xstats_slave_bridge_stp = {
|
||||
.desc = ipstats_stat_desc_bridge_tmpl_stp,
|
||||
.xstats_at = IFLA_STATS_LINK_XSTATS_SLAVE,
|
||||
.link_type_at = LINK_XSTATS_TYPE_BRIDGE,
|
||||
.inner_max = BRIDGE_XSTATS_MAX,
|
||||
.inner_at = BRIDGE_XSTATS_STP,
|
||||
.show_cb = &bridge_print_stats_stp,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc_xstats
|
||||
ipstats_stat_desc_xstats_slave_bridge_mcast = {
|
||||
.desc = ipstats_stat_desc_bridge_tmpl_mcast,
|
||||
.xstats_at = IFLA_STATS_LINK_XSTATS_SLAVE,
|
||||
.link_type_at = LINK_XSTATS_TYPE_BRIDGE,
|
||||
.inner_max = BRIDGE_XSTATS_MAX,
|
||||
.inner_at = BRIDGE_XSTATS_MCAST,
|
||||
.show_cb = &bridge_print_stats_mcast,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc *
|
||||
ipstats_stat_desc_xstats_slave_bridge_subs[] = {
|
||||
&ipstats_stat_desc_xstats_slave_bridge_stp.desc,
|
||||
&ipstats_stat_desc_xstats_slave_bridge_mcast.desc,
|
||||
};
|
||||
|
||||
const struct ipstats_stat_desc ipstats_stat_desc_xstats_slave_bridge_group = {
|
||||
.name = "bridge",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_GROUP,
|
||||
.subs = ipstats_stat_desc_xstats_slave_bridge_subs,
|
||||
.nsubs = ARRAY_SIZE(ipstats_stat_desc_xstats_slave_bridge_subs),
|
||||
};
|
||||
|
126
ip/ipstats.c
126
ip/ipstats.c
@ -2,6 +2,7 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "utils.h"
|
||||
#include "ip_common.h"
|
||||
|
||||
@ -34,6 +35,7 @@ struct ipstats_stat_show_attrs {
|
||||
static const char *const ipstats_levels[] = {
|
||||
"group",
|
||||
"subgroup",
|
||||
"suite",
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -566,6 +568,66 @@ static const struct ipstats_stat_desc ipstats_stat_desc_offload_group = {
|
||||
.nsubs = ARRAY_SIZE(ipstats_stat_desc_offload_subs),
|
||||
};
|
||||
|
||||
void ipstats_stat_desc_pack_xstats(struct ipstats_stat_dump_filters *filters,
|
||||
const struct ipstats_stat_desc *desc)
|
||||
{
|
||||
struct ipstats_stat_desc_xstats *xdesc;
|
||||
|
||||
xdesc = container_of(desc, struct ipstats_stat_desc_xstats, desc);
|
||||
ipstats_stat_desc_enable_bit(filters, xdesc->xstats_at, 0);
|
||||
}
|
||||
|
||||
int ipstats_stat_desc_show_xstats(struct ipstats_stat_show_attrs *attrs,
|
||||
const struct ipstats_stat_desc *desc)
|
||||
{
|
||||
struct ipstats_stat_desc_xstats *xdesc;
|
||||
const struct rtattr *at;
|
||||
struct rtattr **tb;
|
||||
int err;
|
||||
|
||||
xdesc = container_of(desc, struct ipstats_stat_desc_xstats, desc);
|
||||
at = ipstats_stat_show_get_attr(attrs,
|
||||
xdesc->xstats_at,
|
||||
xdesc->link_type_at, &err);
|
||||
if (at == NULL)
|
||||
return err;
|
||||
|
||||
tb = alloca(sizeof(*tb) * (xdesc->inner_max + 1));
|
||||
err = parse_rtattr_nested(tb, xdesc->inner_max, at);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
if (tb[xdesc->inner_at] != NULL) {
|
||||
print_nl();
|
||||
xdesc->show_cb(tb[xdesc->inner_at]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ipstats_stat_desc *ipstats_stat_desc_xstats_subs[] = {
|
||||
&ipstats_stat_desc_xstats_bridge_group,
|
||||
&ipstats_stat_desc_xstats_bond_group,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc ipstats_stat_desc_xstats_group = {
|
||||
.name = "xstats",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_GROUP,
|
||||
.subs = ipstats_stat_desc_xstats_subs,
|
||||
.nsubs = ARRAY_SIZE(ipstats_stat_desc_xstats_subs),
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc *ipstats_stat_desc_xstats_slave_subs[] = {
|
||||
&ipstats_stat_desc_xstats_slave_bridge_group,
|
||||
&ipstats_stat_desc_xstats_slave_bond_group,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc ipstats_stat_desc_xstats_slave_group = {
|
||||
.name = "xstats_slave",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_GROUP,
|
||||
.subs = ipstats_stat_desc_xstats_slave_subs,
|
||||
.nsubs = ARRAY_SIZE(ipstats_stat_desc_xstats_slave_subs),
|
||||
};
|
||||
|
||||
static void
|
||||
ipstats_stat_desc_pack_link(struct ipstats_stat_dump_filters *filters,
|
||||
const struct ipstats_stat_desc *desc)
|
||||
@ -589,9 +651,65 @@ static const struct ipstats_stat_desc ipstats_stat_desc_toplev_link = {
|
||||
.show = &ipstats_stat_desc_show_link,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc ipstats_stat_desc_afstats_group;
|
||||
|
||||
static void
|
||||
ipstats_stat_desc_pack_afstats(struct ipstats_stat_dump_filters *filters,
|
||||
const struct ipstats_stat_desc *desc)
|
||||
{
|
||||
ipstats_stat_desc_enable_bit(filters, IFLA_STATS_AF_SPEC, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
ipstats_stat_desc_show_afstats_mpls(struct ipstats_stat_show_attrs *attrs,
|
||||
const struct ipstats_stat_desc *desc)
|
||||
{
|
||||
struct rtattr *mrtb[MPLS_STATS_MAX+1];
|
||||
struct mpls_link_stats stats;
|
||||
const struct rtattr *at;
|
||||
int err;
|
||||
|
||||
at = ipstats_stat_show_get_attr(attrs, IFLA_STATS_AF_SPEC,
|
||||
AF_MPLS, &err);
|
||||
if (at == NULL)
|
||||
return err;
|
||||
|
||||
parse_rtattr_nested(mrtb, MPLS_STATS_MAX, at);
|
||||
if (mrtb[MPLS_STATS_LINK] == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
IPSTATS_RTA_PAYLOAD(stats, mrtb[MPLS_STATS_LINK]);
|
||||
|
||||
print_nl();
|
||||
open_json_object("mpls_stats");
|
||||
print_mpls_link_stats(stdout, &stats, " ");
|
||||
close_json_object();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ipstats_stat_desc ipstats_stat_desc_afstats_mpls = {
|
||||
.name = "mpls",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_LEAF,
|
||||
.pack = &ipstats_stat_desc_pack_afstats,
|
||||
.show = &ipstats_stat_desc_show_afstats_mpls,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc *ipstats_stat_desc_afstats_subs[] = {
|
||||
&ipstats_stat_desc_afstats_mpls,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc ipstats_stat_desc_afstats_group = {
|
||||
.name = "afstats",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_GROUP,
|
||||
.subs = ipstats_stat_desc_afstats_subs,
|
||||
.nsubs = ARRAY_SIZE(ipstats_stat_desc_afstats_subs),
|
||||
};
|
||||
static const struct ipstats_stat_desc *ipstats_stat_desc_toplev_subs[] = {
|
||||
&ipstats_stat_desc_toplev_link,
|
||||
&ipstats_stat_desc_xstats_group,
|
||||
&ipstats_stat_desc_xstats_slave_group,
|
||||
&ipstats_stat_desc_offload_group,
|
||||
&ipstats_stat_desc_afstats_group,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc ipstats_stat_desc_toplev_group = {
|
||||
@ -970,7 +1088,7 @@ static int do_help(void)
|
||||
|
||||
fprintf(stderr,
|
||||
"Usage: ip stats help\n"
|
||||
" ip stats show [ dev DEV ] [ group GROUP [ subgroup SUBGROUP ] ... ] ...\n"
|
||||
" ip stats show [ dev DEV ] [ group GROUP [ subgroup SUBGROUP [ suite SUITE ] ... ] ... ] ...\n"
|
||||
" ip stats set dev DEV l3_stats { on | off }\n"
|
||||
);
|
||||
|
||||
@ -994,6 +1112,8 @@ static int do_help(void)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < desc->nsubs; j++) {
|
||||
size_t k;
|
||||
|
||||
if (j == 0)
|
||||
fprintf(stderr, "%s SUBGROUP := {", desc->name);
|
||||
else
|
||||
@ -1003,6 +1123,10 @@ static int do_help(void)
|
||||
|
||||
if (desc->subs[j]->kind != IPSTATS_STAT_DESC_KIND_GROUP)
|
||||
continue;
|
||||
|
||||
for (k = 0; k < desc->subs[j]->nsubs; k++)
|
||||
fprintf(stderr, " [ suite %s ]",
|
||||
desc->subs[j]->subs[k]->name);
|
||||
}
|
||||
if (opened)
|
||||
fprintf(stderr, " }\n");
|
||||
|
@ -19,7 +19,8 @@ ip-stats \- manage and show interface statistics
|
||||
.RB "[ " group
|
||||
.IR GROUP " [ "
|
||||
.BI subgroup " SUBGROUP"
|
||||
.R " ] ... ] ..."
|
||||
.RB " [ " suite
|
||||
.IR " SUITE" " ] ... ] ... ] ..."
|
||||
|
||||
.ti -8
|
||||
.BR "ip stats set"
|
||||
@ -67,6 +68,20 @@ The following groups are recognized:
|
||||
- A group that contains a number of HW-oriented statistics. See below for
|
||||
individual subgroups within this group.
|
||||
|
||||
.ti 14
|
||||
.B group xstats
|
||||
- Extended statistics. A subgroup identifies the type of netdevice to show the
|
||||
statistics for.
|
||||
|
||||
.ti 14
|
||||
.B group xstats_slave
|
||||
- Extended statistics for the slave of a netdevice of a given type. A subgroup
|
||||
identifies the type of master netdevice.
|
||||
|
||||
.ti 14
|
||||
.B group afstats
|
||||
- A group for address-family specific netdevice statistics.
|
||||
|
||||
.TQ
|
||||
.BR "group offload " subgroups:
|
||||
.in 21
|
||||
@ -132,6 +147,39 @@ For example:
|
||||
|
||||
Note how the l3_stats_info for the selected group is also part of the dump.
|
||||
|
||||
.TQ
|
||||
.BR "group xstats " and " group xstats_slave " subgroups:
|
||||
.in 21
|
||||
|
||||
.ti 14
|
||||
.B subgroup bridge \fR[\fB suite stp \fR] [\fB suite mcast \fR]
|
||||
- Statistics for STP and, respectively, IGMP / MLD (under the keyword
|
||||
\fBmcast\fR) traffic on bridges and their slaves.
|
||||
|
||||
.ti 14
|
||||
.B subgroup bond \fR[\fB suite 802.3ad \fR]
|
||||
- Statistics for LACP traffic on bond devices and their slaves.
|
||||
|
||||
.TQ
|
||||
.BR "group afstats " subgroups:
|
||||
.in 21
|
||||
|
||||
.ti 14
|
||||
.B subgroup mpls
|
||||
- Statistics for MPLS traffic seen on the netdevice. For example:
|
||||
|
||||
# ip stats show dev veth01 group afstats subgroup mpls
|
||||
.br
|
||||
3: veth01: group afstats subgroup mpls
|
||||
.br
|
||||
RX: bytes packets errors dropped noroute
|
||||
.br
|
||||
0 0 0 0 0
|
||||
.br
|
||||
TX: bytes packets errors dropped
|
||||
.br
|
||||
216 2 0 0
|
||||
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
# ip stats set dev swp1 l3_stats on
|
||||
|
Loading…
Reference in New Issue
Block a user