aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Machata <petrm@nvidia.com>2022-04-22 10:30:57 +0200
committerDavid Ahern <dsahern@kernel.org>2022-04-27 20:12:42 -0600
commit179030fa6bc714b12776aa5e0a905fadf7f3e402 (patch)
treef055c01d46cde82af875e3a60467fe4cb1d5fd55
parentaf5e7955273e47ee40b83f0b04c1879fe7ad92ae (diff)
downloadiproute2-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.c217
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 = {