diff options
author | Petr Machata <petrm@nvidia.com> | 2022-04-22 10:30:57 +0200 |
---|---|---|
committer | David Ahern <dsahern@kernel.org> | 2022-04-27 20:12:42 -0600 |
commit | 179030fa6bc714b12776aa5e0a905fadf7f3e402 (patch) | |
tree | f055c01d46cde82af875e3a60467fe4cb1d5fd55 | |
parent | af5e7955273e47ee40b83f0b04c1879fe7ad92ae (diff) | |
download | iproute2-179030fa6bc714b12776aa5e0a905fadf7f3e402.tar.gz |
ipstats: Add offload subgroup "hw_stats_info"
Add into the group "offload" a subgroup "hw_stats_info" for showing
information about HW statistics counters.
For example:
# ip stats show dev swp1 group offload subgroup hw_stats_info
4178: swp1: group offload subgroup hw_stats_info
l3_stats on used off
# ip -j stats show dev swp1 group offload subgroup hw_stats_info | jq
[
{
"ifindex": 4178,
"ifname": "swp1",
"group": "offload",
"subgroup": "hw_stats_info",
"info": {
"l3_stats": {
"request": true,
"used": false
}
}
}
]
Signed-off-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
-rw-r--r-- | ip/ipstats.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/ip/ipstats.c b/ip/ipstats.c index 283fba4e1..4cdd5122a 100644 --- a/ip/ipstats.c +++ b/ip/ipstats.c @@ -164,6 +164,197 @@ static int ipstats_show_64(struct ipstats_stat_show_attrs *attrs, return 0; } +enum ipstats_maybe_on_off { + IPSTATS_MOO_OFF = -1, + IPSTATS_MOO_INVALID, + IPSTATS_MOO_ON, +}; + +static bool ipstats_moo_to_bool(enum ipstats_maybe_on_off moo) +{ + assert(moo != IPSTATS_MOO_INVALID); + return moo + 1; +} + +static int ipstats_print_moo(enum output_type t, const char *key, + const char *fmt, enum ipstats_maybe_on_off moo) +{ + if (!moo) + return 0; + return print_on_off(t, key, fmt, ipstats_moo_to_bool(moo)); +} + +struct ipstats_hw_s_info_one { + enum ipstats_maybe_on_off request; + enum ipstats_maybe_on_off used; +}; + +enum ipstats_hw_s_info_idx { + IPSTATS_HW_S_INFO_IDX_L3_STATS, + IPSTATS_HW_S_INFO_IDX_COUNT +}; + +static const char *const ipstats_hw_s_info_name[] = { + "l3_stats", +}; + +static_assert(ARRAY_SIZE(ipstats_hw_s_info_name) == + IPSTATS_HW_S_INFO_IDX_COUNT, + "mismatch: enum ipstats_hw_s_info_idx x ipstats_hw_s_info_name"); + +struct ipstats_hw_s_info { + /* Indexed by enum ipstats_hw_s_info_idx. */ + struct ipstats_hw_s_info_one *infos[IPSTATS_HW_S_INFO_IDX_COUNT]; +}; + +static enum ipstats_maybe_on_off ipstats_dissect_01(int value, const char *what) +{ + switch (value) { + case 0: + return IPSTATS_MOO_OFF; + case 1: + return IPSTATS_MOO_ON; + default: + fprintf(stderr, "Invalid value for %s: expected 0 or 1, got %d.\n", + what, value); + return IPSTATS_MOO_INVALID; + } +} + +static int ipstats_dissect_hw_s_info_one(const struct rtattr *at, + struct ipstats_hw_s_info_one *p_hwsio, + const char *what) +{ + int attr_id_request = IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST; + struct rtattr *tb[IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX + 1]; + int attr_id_used = IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED; + struct ipstats_hw_s_info_one hwsio = {}; + int err; + int v; + + err = parse_rtattr_nested(tb, IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX, at); + if (err) + return err; + + if (tb[attr_id_request]) { + v = rta_getattr_u8(tb[attr_id_request]); + hwsio.request = ipstats_dissect_01(v, "request"); + + /* This has to be present & valid. */ + if (!hwsio.request) + return -EINVAL; + } + + if (tb[attr_id_used]) { + v = rta_getattr_u8(tb[attr_id_used]); + hwsio.used = ipstats_dissect_01(v, "used"); + } + + *p_hwsio = hwsio; + return 0; +} + +static int ipstats_dissect_hw_s_info(const struct rtattr *at, + struct ipstats_hw_s_info *hwsi) +{ + struct rtattr *tb[IFLA_OFFLOAD_XSTATS_MAX + 1]; + int attr_id_l3 = IFLA_OFFLOAD_XSTATS_L3_STATS; + struct ipstats_hw_s_info_one *hwsio = NULL; + int err; + + err = parse_rtattr_nested(tb, IFLA_OFFLOAD_XSTATS_MAX, at); + if (err) + return err; + + *hwsi = (struct ipstats_hw_s_info){}; + + if (tb[attr_id_l3]) { + hwsio = malloc(sizeof(*hwsio)); + if (!hwsio) { + err = -ENOMEM; + goto out; + } + + err = ipstats_dissect_hw_s_info_one(tb[attr_id_l3], hwsio, "l3"); + if (err) + goto out; + + hwsi->infos[IPSTATS_HW_S_INFO_IDX_L3_STATS] = hwsio; + hwsio = NULL; + } + + return 0; + +out: + free(hwsio); + return err; +} + +static void ipstats_fini_hw_s_info(struct ipstats_hw_s_info *hwsi) +{ + int i; + + for (i = 0; i < IPSTATS_HW_S_INFO_IDX_COUNT; i++) + free(hwsi->infos[i]); +} + +static void +__ipstats_show_hw_s_info_one(const struct ipstats_hw_s_info_one *hwsio) +{ + if (hwsio == NULL) + return; + + ipstats_print_moo(PRINT_ANY, "request", " %s", hwsio->request); + ipstats_print_moo(PRINT_ANY, "used", " used %s", hwsio->used); +} + +static void +ipstats_show_hw_s_info_one(const struct ipstats_hw_s_info *hwsi, + enum ipstats_hw_s_info_idx idx) +{ + const struct ipstats_hw_s_info_one *hwsio = hwsi->infos[idx]; + const char *name = ipstats_hw_s_info_name[idx]; + + if (hwsio == NULL) + return; + + print_string(PRINT_FP, NULL, " %s", name); + open_json_object(name); + __ipstats_show_hw_s_info_one(hwsio); + close_json_object(); +} + +static int __ipstats_show_hw_s_info(const struct rtattr *at) +{ + struct ipstats_hw_s_info hwsi = {}; + int err; + + err = ipstats_dissect_hw_s_info(at, &hwsi); + if (err) + return err; + + open_json_object("info"); + ipstats_show_hw_s_info_one(&hwsi, IPSTATS_HW_S_INFO_IDX_L3_STATS); + close_json_object(); + + ipstats_fini_hw_s_info(&hwsi); + return 0; +} + +static int ipstats_show_hw_s_info(struct ipstats_stat_show_attrs *attrs, + unsigned int group, unsigned int subgroup) +{ + const struct rtattr *at; + int err; + + at = ipstats_stat_show_get_attr(attrs, group, subgroup, &err); + if (at == NULL) + return err; + + print_nl(); + return __ipstats_show_hw_s_info(at); +} + static void ipstats_stat_desc_pack_cpu_hit(struct ipstats_stat_dump_filters *filters, const struct ipstats_stat_desc *desc) @@ -189,8 +380,34 @@ static const struct ipstats_stat_desc ipstats_stat_desc_offload_cpu_hit = { .show = &ipstats_stat_desc_show_cpu_hit, }; +static void +ipstats_stat_desc_pack_hw_stats_info(struct ipstats_stat_dump_filters *filters, + const struct ipstats_stat_desc *desc) +{ + ipstats_stat_desc_enable_bit(filters, + IFLA_STATS_LINK_OFFLOAD_XSTATS, + IFLA_OFFLOAD_XSTATS_HW_S_INFO); +} + +static int +ipstats_stat_desc_show_hw_stats_info(struct ipstats_stat_show_attrs *attrs, + const struct ipstats_stat_desc *desc) +{ + return ipstats_show_hw_s_info(attrs, + IFLA_STATS_LINK_OFFLOAD_XSTATS, + IFLA_OFFLOAD_XSTATS_HW_S_INFO); +} + +static const struct ipstats_stat_desc ipstats_stat_desc_offload_hw_s_info = { + .name = "hw_stats_info", + .kind = IPSTATS_STAT_DESC_KIND_LEAF, + .pack = &ipstats_stat_desc_pack_hw_stats_info, + .show = &ipstats_stat_desc_show_hw_stats_info, +}; + static const struct ipstats_stat_desc *ipstats_stat_desc_offload_subs[] = { &ipstats_stat_desc_offload_cpu_hit, + &ipstats_stat_desc_offload_hw_s_info, }; static const struct ipstats_stat_desc ipstats_stat_desc_offload_group = { |