net: page_pool: support dumping pps of a specific ifindex via Netlink

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..

Link: https://patch.msgid.link/20260506034821.1710113-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-05-05 20:48:20 -07:00
parent 6a4c4656b0
commit c93799de1b
4 changed files with 82 additions and 15 deletions

View File

@ -649,6 +649,9 @@ operations:
- dmabuf
- io-uring
dump:
request:
attributes:
- ifindex
reply: *pp-reply
config-cond: page-pool
-
@ -692,6 +695,9 @@ operations:
- recycle-ring-full
- recycle-released-refcnt
dump:
request:
attributes:
- info
reply: *pp-stats-reply
config-cond: page-pool-stats
-

View File

@ -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 */
{

View File

@ -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)

View File

@ -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;