netdev-genl: Add netlink framework functions for napi
authorAmritha Nambiar <amritha.nambiar@intel.com>
Fri, 1 Dec 2023 23:28:56 +0000 (15:28 -0800)
committerJakub Kicinski <kuba@kernel.org>
Tue, 5 Dec 2023 02:04:05 +0000 (18:04 -0800)
Implement the netdev netlink framework functions for
napi support. The netdev structure tracks all the napi
instances and napi fields. The napi instances and associated
parameters can be retrieved this way.

Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Link: https://lore.kernel.org/r/170147333637.5260.14807433239805550815.stgit@anambiarhost.jf.intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/dev.c
net/core/dev.h
net/core/netdev-genl.c

index 0a2eecbeef3884be801609be3afa86054b93e1df..13c9d1580e628c270aecf8143e2bbefc71d57af1 100644 (file)
@@ -165,7 +165,6 @@ static int netif_rx_internal(struct sk_buff *skb);
 static int call_netdevice_notifiers_extack(unsigned long val,
                                           struct net_device *dev,
                                           struct netlink_ext_ack *extack);
-static struct napi_struct *napi_by_id(unsigned int napi_id);
 
 /*
  * The @dev_base_head list is protected by @dev_base_lock and the rtnl
@@ -6139,7 +6138,7 @@ bool napi_complete_done(struct napi_struct *n, int work_done)
 EXPORT_SYMBOL(napi_complete_done);
 
 /* must be called under rcu_read_lock(), as we dont take a reference */
-static struct napi_struct *napi_by_id(unsigned int napi_id)
+struct napi_struct *napi_by_id(unsigned int napi_id)
 {
        unsigned int hash = napi_id % HASH_SIZE(napi_hash);
        struct napi_struct *napi;
index 5aa45f0fd4ae549ae986f8007cecd2a9e8ec1e14..7795b8ad841d5e9c5041f07bf09d0c49648cdf84 100644 (file)
@@ -145,4 +145,6 @@ void xdp_do_check_flushed(struct napi_struct *napi);
 #else
 static inline void xdp_do_check_flushed(struct napi_struct *napi) { }
 #endif
+
+struct napi_struct *napi_by_id(unsigned int napi_id);
 #endif
index 4c8ea6a4f015264dc6306b112215571737a46377..d55c92f9f26c99c79219e652a8f0ea095eadbc6b 100644 (file)
@@ -8,13 +8,16 @@
 #include <net/xdp.h>
 #include <net/xdp_sock.h>
 #include <net/netdev_rx_queue.h>
+#include <net/busy_poll.h>
 
 #include "netdev-genl-gen.h"
+#include "dev.h"
 
 struct netdev_nl_dump_ctx {
        unsigned long   ifindex;
        unsigned int    rxq_idx;
        unsigned int    txq_idx;
+       unsigned int    napi_id;
 };
 
 static struct netdev_nl_dump_ctx *netdev_dump_ctx(struct netlink_callback *cb)
@@ -155,14 +158,128 @@ int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
        return skb->len;
 }
 
+static int
+netdev_nl_napi_fill_one(struct sk_buff *rsp, struct napi_struct *napi,
+                       const struct genl_info *info)
+{
+       void *hdr;
+
+       if (WARN_ON_ONCE(!napi->dev))
+               return -EINVAL;
+       if (!(napi->dev->flags & IFF_UP))
+               return 0;
+
+       hdr = genlmsg_iput(rsp, info);
+       if (!hdr)
+               return -EMSGSIZE;
+
+       if (napi->napi_id >= MIN_NAPI_ID &&
+           nla_put_u32(rsp, NETDEV_A_NAPI_ID, napi->napi_id))
+               goto nla_put_failure;
+
+       if (nla_put_u32(rsp, NETDEV_A_NAPI_IFINDEX, napi->dev->ifindex))
+               goto nla_put_failure;
+
+       genlmsg_end(rsp, hdr);
+       return 0;
+
+nla_put_failure:
+       genlmsg_cancel(rsp, hdr);
+       return -EMSGSIZE;
+}
+
 int netdev_nl_napi_get_doit(struct sk_buff *skb, struct genl_info *info)
 {
-       return -EOPNOTSUPP;
+       struct napi_struct *napi;
+       struct sk_buff *rsp;
+       u32 napi_id;
+       int err;
+
+       if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_NAPI_ID))
+               return -EINVAL;
+
+       napi_id = nla_get_u32(info->attrs[NETDEV_A_NAPI_ID]);
+
+       rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!rsp)
+               return -ENOMEM;
+
+       rtnl_lock();
+
+       napi = napi_by_id(napi_id);
+       if (napi)
+               err = netdev_nl_napi_fill_one(rsp, napi, info);
+       else
+               err = -EINVAL;
+
+       rtnl_unlock();
+
+       if (err)
+               goto err_free_msg;
+
+       return genlmsg_reply(rsp, info);
+
+err_free_msg:
+       nlmsg_free(rsp);
+       return err;
+}
+
+static int
+netdev_nl_napi_dump_one(struct net_device *netdev, struct sk_buff *rsp,
+                       const struct genl_info *info,
+                       struct netdev_nl_dump_ctx *ctx)
+{
+       struct napi_struct *napi;
+       int err = 0;
+
+       if (!(netdev->flags & IFF_UP))
+               return err;
+
+       list_for_each_entry(napi, &netdev->napi_list, dev_list) {
+               if (ctx->napi_id && napi->napi_id >= ctx->napi_id)
+                       continue;
+
+               err = netdev_nl_napi_fill_one(rsp, napi, info);
+               if (err)
+                       return err;
+               ctx->napi_id = napi->napi_id;
+       }
+       return err;
 }
 
 int netdev_nl_napi_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       return -EOPNOTSUPP;
+       struct netdev_nl_dump_ctx *ctx = netdev_dump_ctx(cb);
+       const struct genl_info *info = genl_info_dump(cb);
+       struct net *net = sock_net(skb->sk);
+       struct net_device *netdev;
+       u32 ifindex = 0;
+       int err = 0;
+
+       if (info->attrs[NETDEV_A_NAPI_IFINDEX])
+               ifindex = nla_get_u32(info->attrs[NETDEV_A_NAPI_IFINDEX]);
+
+       rtnl_lock();
+       if (ifindex) {
+               netdev = __dev_get_by_index(net, ifindex);
+               if (netdev)
+                       err = netdev_nl_napi_dump_one(netdev, skb, info, ctx);
+               else
+                       err = -ENODEV;
+       } else {
+               for_each_netdev_dump(net, netdev, ctx->ifindex) {
+                       err = netdev_nl_napi_dump_one(netdev, skb, info, ctx);
+                       if (err < 0)
+                               break;
+                       ctx->napi_id = 0;
+               }
+       }
+       rtnl_unlock();
+
+       if (err != -EMSGSIZE)
+               return err;
+
+       return skb->len;
 }
 
 static int