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 <[email protected]>
---
 Documentation/netlink/specs/netdev.yaml |  6 ++++
 net/core/netdev-genl-gen.c              | 30 ++++++++++++----
 net/core/page_pool_user.c               | 47 +++++++++++++++++++++++--
 3 files changed, 74 insertions(+), 9 deletions(-)

diff --git a/Documentation/netlink/specs/netdev.yaml 
b/Documentation/netlink/specs/netdev.yaml
index 596c306ce52b..f998cc64323c 100644
--- a/Documentation/netlink/specs/netdev.yaml
+++ b/Documentation/netlink/specs/netdev.yaml
@@ -620,6 +620,9 @@ doc: >-
             - dmabuf
             - io-uring
       dump:
+        request:
+          attributes:
+            - ifindex
         reply: *pp-reply
       config-cond: page-pool
     -
@@ -663,6 +666,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 ba673e81716f..22cbbdc40c6a 100644
--- a/net/core/netdev-genl-gen.c
+++ b/net/core/netdev-genl-gen.c
@@ -48,6 +48,11 @@ static const struct nla_policy 
netdev_dev_get_nl_policy[NETDEV_A_DEV_IFINDEX + 1
 static const struct nla_policy 
netdev_page_pool_get_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),
 };
+
+/* NETDEV_CMD_PAGE_POOL_GET - dump */
+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 */
@@ -55,6 +60,15 @@ static const struct nla_policy 
netdev_page_pool_get_nl_policy[NETDEV_A_PAGE_POOL
 static const struct nla_policy 
netdev_page_pool_stats_get_nl_policy[NETDEV_A_PAGE_POOL_STATS_INFO + 1] = {
        [NETDEV_A_PAGE_POOL_STATS_INFO] = 
NLA_POLICY_NESTED(netdev_page_pool_info_nl_policy),
 };
+
+/* NETDEV_CMD_PAGE_POOL_STATS_GET - dump */
+static const struct nla_policy 
netdev_page_pool_stats_get_dump_info_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),
+};
+
+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_stats_get_dump_info_nl_policy),
+};
 #endif /* CONFIG_PAGE_POOL_STATS */
 
 /* NETDEV_CMD_QUEUE_GET - do */
@@ -130,9 +144,11 @@ static const struct genl_split_ops netdev_nl_ops[] = {
                .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
@@ -144,9 +160,11 @@ static const struct genl_split_ops netdev_nl_ops[] = {
                .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)
-- 
2.53.0


Reply via email to