aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Machata <petrm@nvidia.com>2024-03-14 15:52:13 +0100
committerDavid Ahern <dsahern@kernel.org>2024-03-15 15:03:09 +0000
commit529ada74c401f0f80adcba12dfc023bf84eedc82 (patch)
tree8d6e9089688f001ef4b621e8ee19a6f538ab9b8e
parent95836fbf35d352f7c031ddac2e6093a935308cc9 (diff)
downloadiproute2-next-529ada74c401f0f80adcba12dfc023bf84eedc82.tar.gz
ip: ipnexthop: Support dumping next hop group stats
Next hop group stats allow verification of balancedness of a next hop group. The feature was merged in kernel commit 7cf497e5a122 ("Merge branch 'nexthop-group-stats'"). Add to ip the corresponding support. The statistics are requested if "ip nexthop" is started with -s. Signed-off-by: Petr Machata <petrm@nvidia.com> Signed-off-by: David Ahern <dsahern@kernel.org>
-rw-r--r--ip/ipnexthop.c89
-rw-r--r--ip/nh_common.h6
2 files changed, 95 insertions, 0 deletions
diff --git a/ip/ipnexthop.c b/ip/ipnexthop.c
index e946d6f94..cba3d934e 100644
--- a/ip/ipnexthop.c
+++ b/ip/ipnexthop.c
@@ -25,6 +25,7 @@ static struct {
unsigned int fdb;
unsigned int id;
unsigned int nhid;
+ unsigned int op_flags;
} filter;
enum {
@@ -92,6 +93,14 @@ static int nh_dump_filter(struct nlmsghdr *nlh, int reqlen)
return err;
}
+ if (filter.op_flags) {
+ __u32 op_flags = filter.op_flags;
+
+ err = addattr32(nlh, reqlen, NHA_OP_FLAGS, op_flags);
+ if (err)
+ return err;
+ }
+
return 0;
}
@@ -296,6 +305,31 @@ static void parse_nh_res_group_rta(const struct rtattr *res_grp_attr,
}
}
+static void parse_nh_group_stats_rta(const struct rtattr *grp_stats_attr,
+ struct nh_entry *nhe)
+{
+ const struct rtattr *pos;
+ int i = 0;
+
+ rtattr_for_each_nested(pos, grp_stats_attr) {
+ struct nh_grp_stats *nh_grp_stats = &nhe->nh_grp_stats[i++];
+ struct rtattr *tb[NHA_GROUP_STATS_ENTRY_MAX + 1];
+ struct rtattr *rta;
+
+ parse_rtattr_nested(tb, NHA_GROUP_STATS_ENTRY_MAX, pos);
+
+ if (tb[NHA_GROUP_STATS_ENTRY_ID]) {
+ rta = tb[NHA_GROUP_STATS_ENTRY_ID];
+ nh_grp_stats->nh_id = rta_getattr_u32(rta);
+ }
+
+ if (tb[NHA_GROUP_STATS_ENTRY_PACKETS]) {
+ rta = tb[NHA_GROUP_STATS_ENTRY_PACKETS];
+ nh_grp_stats->packets = rta_getattr_uint(rta);
+ }
+ }
+}
+
static void print_nh_res_group(const struct nha_res_grp *res_grp)
{
struct timeval tv;
@@ -343,8 +377,35 @@ static void print_nh_res_bucket(FILE *fp, const struct rtattr *res_bucket_attr)
close_json_object();
}
+static void print_nh_grp_stats(const struct nh_entry *nhe)
+{
+ int i;
+
+ if (!show_stats)
+ return;
+
+ open_json_array(PRINT_JSON, "group_stats");
+ print_nl();
+ print_string(PRINT_FP, NULL, " stats:", NULL);
+ print_nl();
+ for (i = 0; i < nhe->nh_groups_cnt; i++) {
+ open_json_object(NULL);
+
+ print_uint(PRINT_ANY, "id", " id %u",
+ nhe->nh_grp_stats[i].nh_id);
+ print_u64(PRINT_ANY, "packets", " packets %llu",
+ nhe->nh_grp_stats[i].packets);
+
+ if (i != nhe->nh_groups_cnt - 1)
+ print_nl();
+ close_json_object();
+ }
+ close_json_array(PRINT_JSON, NULL);
+}
+
static void ipnh_destroy_entry(struct nh_entry *nhe)
{
+ free(nhe->nh_grp_stats);
free(nhe->nh_encap);
free(nhe->nh_groups);
}
@@ -418,6 +479,16 @@ static int ipnh_parse_nhmsg(FILE *fp, const struct nhmsg *nhm, int len,
nhe->nh_has_res_grp = true;
}
+ if (tb[NHA_GROUP_STATS]) {
+ nhe->nh_grp_stats = calloc(nhe->nh_groups_cnt,
+ sizeof(*nhe->nh_grp_stats));
+ if (!nhe->nh_grp_stats) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+ parse_nh_group_stats_rta(tb[NHA_GROUP_STATS], nhe);
+ }
+
nhe->nh_blackhole = !!tb[NHA_BLACKHOLE];
nhe->nh_fdb = !!tb[NHA_FDB];
@@ -484,9 +555,23 @@ static void __print_nexthop_entry(FILE *fp, const char *jsobj,
if (nhe->nh_fdb)
print_null(PRINT_ANY, "fdb", "fdb", NULL);
+ if (nhe->nh_grp_stats)
+ print_nh_grp_stats(nhe);
+
close_json_object();
}
+static __u32 ipnh_get_op_flags(void)
+{
+ __u32 op_flags = 0;
+
+ if (show_stats) {
+ op_flags |= NHA_OP_FLAG_DUMP_STATS;
+ }
+
+ return op_flags;
+}
+
static int __ipnh_get_id(struct rtnl_handle *rthp, __u32 nh_id,
struct nlmsghdr **answer)
{
@@ -500,8 +585,10 @@ static int __ipnh_get_id(struct rtnl_handle *rthp, __u32 nh_id,
.n.nlmsg_type = RTM_GETNEXTHOP,
.nhm.nh_family = preferred_family,
};
+ __u32 op_flags = ipnh_get_op_flags();
addattr32(&req.n, sizeof(req), NHA_ID, nh_id);
+ addattr32(&req.n, sizeof(req), NHA_OP_FLAGS, op_flags);
return rtnl_talk(rthp, &req.n, answer);
}
@@ -1093,6 +1180,8 @@ static int ipnh_list_flush(int argc, char **argv, int action)
argc--; argv++;
}
+ filter.op_flags = ipnh_get_op_flags();
+
if (action == IPNH_FLUSH)
return ipnh_flush(all);
diff --git a/ip/nh_common.h b/ip/nh_common.h
index 4d6677e62..e2f74ec5a 100644
--- a/ip/nh_common.h
+++ b/ip/nh_common.h
@@ -13,6 +13,11 @@ struct nha_res_grp {
__u64 unbalanced_time;
};
+struct nh_grp_stats {
+ __u32 nh_id;
+ __u64 packets;
+};
+
struct nh_entry {
struct hlist_node nh_hash;
@@ -44,6 +49,7 @@ struct nh_entry {
int nh_groups_cnt;
struct nexthop_grp *nh_groups;
+ struct nh_grp_stats *nh_grp_stats;
};
void print_cache_nexthop_id(FILE *fp, const char *fp_prefix, const char *jsobj,