]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: page_pool: support dumping pps of a specific ifindex via Netlink
authorJakub Kicinski <kuba@kernel.org>
Wed, 6 May 2026 03:48:20 +0000 (20:48 -0700)
committerJakub Kicinski <kuba@kernel.org>
Fri, 8 May 2026 21:54:55 +0000 (14:54 -0700)
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>
Documentation/netlink/specs/netdev.yaml
net/core/netdev-genl-gen.c
net/core/page_pool_user.c
tools/net/ynl/ynltool/page-pool.c

index b93beb247a112c5bb05796ee3f5dadcd5fdcce5c..a1f4c5a561e9d1f344e69b55517681dc76af05e5 100644 (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
     -
index 81aecb5d3bc5d09546b2d5836831dcfebe894f85..c7e138bfe34574559c0c1460573601b27b1dfcf1 100644 (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 */
        {
index ee5060d8eec0eb7bab7c2262933de0d6fd19bd34..01509d1b3cbaac88bd216a2d5b3e0eb067870406 100644 (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)
index 4b24492abab7889bed984f1558c58464520279b0..9487eda6b3aab8e0e8a5aa604f259d96152acf3c 100644 (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;