NIPA tries to make sure that HW tests don't modify system state. It saves the state of page pools, too. Now that I write this commit message I realize that this is impractical since page pool IDs and state will get legitimately changed by the tests. But I already spent a couple of hours implementing the filtering, so.. Signed-off-by: Jakub Kicinski --- v3: - regen with latest YNL v2: https://lore.kernel.org/20260504214336.613107-1-kuba@kernel.org - adjust ynltool to pass empty req pointer now v1: https://lore.kernel.org/20260319035649.2396137-1-kuba@kernel.org --- CC: donald.hunter@gmail.com CC: matttbe@kernel.org CC: chuck.lever@oracle.com CC: daniel@iogearbox.net CC: skhawaja@google.com CC: sdf@fomichev.me CC: hawk@kernel.org --- Documentation/netlink/specs/netdev.yaml | 6 ++++ net/core/netdev-genl-gen.c | 38 ++++++++++++++------ net/core/page_pool_user.c | 47 +++++++++++++++++++++++-- tools/net/ynl/ynltool/page-pool.c | 6 ++-- 4 files changed, 82 insertions(+), 15 deletions(-) diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index b93beb247a11..a1f4c5a561e9 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -649,6 +649,9 @@ doc: >- - dmabuf - io-uring dump: + request: + attributes: + - ifindex reply: *pp-reply config-cond: page-pool - @@ -692,6 +695,9 @@ doc: >- - recycle-ring-full - recycle-released-refcnt dump: + request: + attributes: + - info reply: *pp-stats-reply config-cond: page-pool-stats - diff --git a/net/core/netdev-genl-gen.c b/net/core/netdev-genl-gen.c index 81aecb5d3bc5..c7e138bfe345 100644 --- a/net/core/netdev-genl-gen.c +++ b/net/core/netdev-genl-gen.c @@ -51,14 +51,28 @@ static const struct nla_policy netdev_dev_get_nl_policy[NETDEV_A_DEV_IFINDEX + 1 /* NETDEV_CMD_PAGE_POOL_GET - do */ #ifdef CONFIG_PAGE_POOL -static const struct nla_policy netdev_page_pool_get_nl_policy[NETDEV_A_PAGE_POOL_ID + 1] = { +static const struct nla_policy netdev_page_pool_get_do_nl_policy[NETDEV_A_PAGE_POOL_ID + 1] = { [NETDEV_A_PAGE_POOL_ID] = NLA_POLICY_FULL_RANGE(NLA_UINT, &netdev_a_page_pool_id_range), }; #endif /* CONFIG_PAGE_POOL */ +/* NETDEV_CMD_PAGE_POOL_GET - dump */ +#ifdef CONFIG_PAGE_POOL +static const struct nla_policy netdev_page_pool_get_dump_nl_policy[NETDEV_A_PAGE_POOL_IFINDEX + 1] = { + [NETDEV_A_PAGE_POOL_IFINDEX] = NLA_POLICY_FULL_RANGE(NLA_U32, &netdev_a_page_pool_ifindex_range), +}; +#endif /* CONFIG_PAGE_POOL */ + /* NETDEV_CMD_PAGE_POOL_STATS_GET - do */ #ifdef CONFIG_PAGE_POOL_STATS -static const struct nla_policy netdev_page_pool_stats_get_nl_policy[NETDEV_A_PAGE_POOL_STATS_INFO + 1] = { +static const struct nla_policy netdev_page_pool_stats_get_do_nl_policy[NETDEV_A_PAGE_POOL_STATS_INFO + 1] = { + [NETDEV_A_PAGE_POOL_STATS_INFO] = NLA_POLICY_NESTED(netdev_page_pool_info_nl_policy), +}; +#endif /* CONFIG_PAGE_POOL_STATS */ + +/* NETDEV_CMD_PAGE_POOL_STATS_GET - dump */ +#ifdef CONFIG_PAGE_POOL_STATS +static const struct nla_policy netdev_page_pool_stats_get_dump_nl_policy[NETDEV_A_PAGE_POOL_STATS_INFO + 1] = { [NETDEV_A_PAGE_POOL_STATS_INFO] = NLA_POLICY_NESTED(netdev_page_pool_info_nl_policy), }; #endif /* CONFIG_PAGE_POOL_STATS */ @@ -138,28 +152,32 @@ static const struct genl_split_ops netdev_nl_ops[] = { { .cmd = NETDEV_CMD_PAGE_POOL_GET, .doit = netdev_nl_page_pool_get_doit, - .policy = netdev_page_pool_get_nl_policy, + .policy = netdev_page_pool_get_do_nl_policy, .maxattr = NETDEV_A_PAGE_POOL_ID, .flags = GENL_CMD_CAP_DO, }, { - .cmd = NETDEV_CMD_PAGE_POOL_GET, - .dumpit = netdev_nl_page_pool_get_dumpit, - .flags = GENL_CMD_CAP_DUMP, + .cmd = NETDEV_CMD_PAGE_POOL_GET, + .dumpit = netdev_nl_page_pool_get_dumpit, + .policy = netdev_page_pool_get_dump_nl_policy, + .maxattr = NETDEV_A_PAGE_POOL_IFINDEX, + .flags = GENL_CMD_CAP_DUMP, }, #endif /* CONFIG_PAGE_POOL */ #ifdef CONFIG_PAGE_POOL_STATS { .cmd = NETDEV_CMD_PAGE_POOL_STATS_GET, .doit = netdev_nl_page_pool_stats_get_doit, - .policy = netdev_page_pool_stats_get_nl_policy, + .policy = netdev_page_pool_stats_get_do_nl_policy, .maxattr = NETDEV_A_PAGE_POOL_STATS_INFO, .flags = GENL_CMD_CAP_DO, }, { - .cmd = NETDEV_CMD_PAGE_POOL_STATS_GET, - .dumpit = netdev_nl_page_pool_stats_get_dumpit, - .flags = GENL_CMD_CAP_DUMP, + .cmd = NETDEV_CMD_PAGE_POOL_STATS_GET, + .dumpit = netdev_nl_page_pool_stats_get_dumpit, + .policy = netdev_page_pool_stats_get_dump_nl_policy, + .maxattr = NETDEV_A_PAGE_POOL_STATS_INFO, + .flags = GENL_CMD_CAP_DUMP, }, #endif /* CONFIG_PAGE_POOL_STATS */ { diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c index ee5060d8eec0..01509d1b3cba 100644 --- a/net/core/page_pool_user.c +++ b/net/core/page_pool_user.c @@ -79,7 +79,7 @@ struct page_pool_dump_cb { static int netdev_nl_page_pool_get_dump(struct sk_buff *skb, struct netlink_callback *cb, - pp_nl_fill_cb fill) + pp_nl_fill_cb fill, struct nlattr *ifindex_attr) { struct page_pool_dump_cb *state = (void *)cb->ctx; const struct genl_info *info = genl_info_dump(cb); @@ -88,9 +88,17 @@ netdev_nl_page_pool_get_dump(struct sk_buff *skb, struct netlink_callback *cb, struct page_pool *pool; int err = 0; + if (ifindex_attr) + state->ifindex = nla_get_u32(ifindex_attr); + rtnl_lock(); mutex_lock(&page_pools_lock); for_each_netdev_dump(net, netdev, state->ifindex) { + /* Either the provided ifindex doesn't exist or done dumping */ + if (ifindex_attr && + netdev->ifindex != nla_get_u32(ifindex_attr)) + break; + hlist_for_each_entry(pool, &netdev->page_pools, user.list) { if (state->pp_id && state->pp_id < pool->user.id) continue; @@ -206,10 +214,40 @@ int netdev_nl_page_pool_stats_get_doit(struct sk_buff *skb, return netdev_nl_page_pool_get_do(info, id, page_pool_nl_stats_fill); } +static const struct netlink_range_validation page_pool_ifindex_range = { + .min = 1ULL, + .max = S32_MAX, +}; + +static const struct nla_policy +page_pool_stat_info_policy[NETDEV_A_PAGE_POOL_IFINDEX + 1] = { + [NETDEV_A_PAGE_POOL_IFINDEX] = + NLA_POLICY_FULL_RANGE(NLA_U32, &page_pool_ifindex_range), +}; + int netdev_nl_page_pool_stats_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { - return netdev_nl_page_pool_get_dump(skb, cb, page_pool_nl_stats_fill); + struct nlattr *tb[ARRAY_SIZE(page_pool_stat_info_policy)]; + const struct genl_info *info = genl_info_dump(cb); + struct nlattr *ifindex_attr = NULL; + + if (info->attrs[NETDEV_A_PAGE_POOL_STATS_INFO]) { + struct nlattr *nest; + int err; + + nest = info->attrs[NETDEV_A_PAGE_POOL_STATS_INFO]; + err = nla_parse_nested(tb, ARRAY_SIZE(tb) - 1, nest, + page_pool_stat_info_policy, + info->extack); + if (err) + return err; + + ifindex_attr = tb[NETDEV_A_PAGE_POOL_IFINDEX]; + } + + return netdev_nl_page_pool_get_dump(skb, cb, page_pool_nl_stats_fill, + ifindex_attr); } static int @@ -305,7 +343,10 @@ int netdev_nl_page_pool_get_doit(struct sk_buff *skb, struct genl_info *info) int netdev_nl_page_pool_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { - return netdev_nl_page_pool_get_dump(skb, cb, page_pool_nl_fill); + const struct genl_info *info = genl_info_dump(cb); + + return netdev_nl_page_pool_get_dump(skb, cb, page_pool_nl_fill, + info->attrs[NETDEV_A_PAGE_POOL_IFINDEX]); } int page_pool_list(struct page_pool *pool) diff --git a/tools/net/ynl/ynltool/page-pool.c b/tools/net/ynl/ynltool/page-pool.c index 4b24492abab7..9487eda6b3aa 100644 --- a/tools/net/ynl/ynltool/page-pool.c +++ b/tools/net/ynl/ynltool/page-pool.c @@ -327,7 +327,9 @@ static void aggregate_device_stats(struct pp_stats_array *a, static int do_stats(int argc, char **argv) { + struct netdev_page_pool_stats_get_req_dump pp_stat_req = {}; struct netdev_page_pool_stats_get_list *pp_stats; + struct netdev_page_pool_get_req_dump pp_req = {}; struct netdev_page_pool_get_list *pools; enum { GROUP_BY_DEVICE, @@ -374,14 +376,14 @@ static int do_stats(int argc, char **argv) return -1; } - pools = netdev_page_pool_get_dump(ys); + pools = netdev_page_pool_get_dump(ys, &pp_req); if (!pools) { p_err("failed to get page pools: %s", ys->err.msg); ret = -1; goto exit_close; } - pp_stats = netdev_page_pool_stats_get_dump(ys); + pp_stats = netdev_page_pool_stats_get_dump(ys, &pp_stat_req); if (!pp_stats) { p_err("failed to get page pool stats: %s", ys->err.msg); ret = -1; -- 2.54.0