diff options
author | Petr Machata <petrm@nvidia.com> | 2024-03-14 15:52:13 +0100 |
---|---|---|
committer | David Ahern <dsahern@kernel.org> | 2024-03-15 15:03:09 +0000 |
commit | 529ada74c401f0f80adcba12dfc023bf84eedc82 (patch) | |
tree | 8d6e9089688f001ef4b621e8ee19a6f538ab9b8e | |
parent | 95836fbf35d352f7c031ddac2e6093a935308cc9 (diff) | |
download | iproute2-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.c | 89 | ||||
-rw-r--r-- | ip/nh_common.h | 6 |
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, |