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
 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;
 
 #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)
        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