diff mbox series

[net-next,v2,5/9] netdev-genl: Add netlink framework functions for napi

Message ID 169266033666.10199.3744908214828788701.stgit@anambiarhost.jf.intel.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series Introduce NAPI queues support | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1332 this patch: 1332
netdev/cc_maintainers warning 3 maintainers not CCed: pabeni@redhat.com ast@kernel.org edumazet@google.com
netdev/build_clang success Errors and warnings before: 1353 this patch: 1353
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1355 this patch: 1355
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 197 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline fail Was 0 now: 1

Commit Message

Nambiar, Amritha Aug. 21, 2023, 11:25 p.m. UTC
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
queue[s] can be retrieved this way.

Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
---
 net/core/netdev-genl.c |  165 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 162 insertions(+), 3 deletions(-)

Comments

Jakub Kicinski Aug. 23, 2023, 12:51 a.m. UTC | #1
On Mon, 21 Aug 2023 16:25:36 -0700 Amritha Nambiar wrote:
> 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
> queue[s] can be retrieved this way.
> 
> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>

> @@ -119,14 +134,158 @@ 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)
> +{
> +	struct netdev_rx_queue *rx_queue, *rxq;
> +	struct netdev_queue *tx_queue, *txq;
> +	unsigned int rx_qid, tx_qid;
> +	void *hdr;
> +
> +	if (!napi->dev)
> +		return -EINVAL;

WARN_ON_ONCE()? If this can be assumed not to happen.

> +	hdr = genlmsg_iput(rsp, info);
> +	if (!hdr)
> +		return -EMSGSIZE;
> +
> +	if (nla_put_u32(rsp, NETDEV_A_NAPI_NAPI_ID, napi->napi_id))

napi_id can be zero.

> +		goto nla_put_failure;
> +
> +	if (nla_put_u32(rsp, NETDEV_A_NAPI_IFINDEX, napi->dev->ifindex))
> +		goto nla_put_failure;

>  int netdev_nl_napi_get_doit(struct sk_buff *skb, struct genl_info *info)
>  {
> -	return -EOPNOTSUPP;
> +	struct net_device *netdev;
> +	struct sk_buff *rsp;
> +	u32 napi_id;
> +	int err;
> +
> +	if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_NAPI_NAPI_ID))
> +		return -EINVAL;
> +
> +	napi_id = nla_get_u32(info->attrs[NETDEV_A_NAPI_NAPI_ID]);
> +
> +	rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
> +	if (!rsp)
> +		return -ENOMEM;
> +
> +	rtnl_lock();
> +
> +	netdev = dev_get_by_napi_id(napi_id);

Why lookup the dev and not the NAPI?

> +	if (netdev)
> +		err  = netdev_nl_napi_fill(netdev, rsp, info, napi_id);
> +	else
> +		err = -ENODEV;
> +
> +	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, int *start)
> +{
> +	struct napi_struct *napi, *n;
> +	int err = 0;
> +	int i = 0;
> +
> +	list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) {

Why _safe()? I think you need _rcu() instead?

> +		if (i < *start) {
> +			i++;
> +			continue;
> +		}
> +		err = netdev_nl_napi_fill_one(rsp, napi, info);
> +		if (err)
> +			break;
> +		*start = ++i;

Why count them instead of relying on the IDs?

>  int netdev_nl_napi_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
>  {
> -	return -EOPNOTSUPP;
> +	const struct genl_dumpit_info *info = genl_dumpit_info(cb);

You can get genl_info_dump(cb) here, you don't use the genl_dumpit_info
AFAICT, only info->info.
Nambiar, Amritha Aug. 23, 2023, 11:53 p.m. UTC | #2
On 8/22/2023 5:51 PM, Jakub Kicinski wrote:
> On Mon, 21 Aug 2023 16:25:36 -0700 Amritha Nambiar wrote:
>> 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
>> queue[s] can be retrieved this way.
>>
>> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
> 
>> @@ -119,14 +134,158 @@ 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)
>> +{
>> +	struct netdev_rx_queue *rx_queue, *rxq;
>> +	struct netdev_queue *tx_queue, *txq;
>> +	unsigned int rx_qid, tx_qid;
>> +	void *hdr;
>> +
>> +	if (!napi->dev)
>> +		return -EINVAL;
> 
> WARN_ON_ONCE()? If this can be assumed not to happen.

Okay. Will fix in v3.

> 
>> +	hdr = genlmsg_iput(rsp, info);
>> +	if (!hdr)
>> +		return -EMSGSIZE;
>> +
>> +	if (nla_put_u32(rsp, NETDEV_A_NAPI_NAPI_ID, napi->napi_id))
> 
> napi_id can be zero.

Will fix in v3.

> 
>> +		goto nla_put_failure;
>> +
>> +	if (nla_put_u32(rsp, NETDEV_A_NAPI_IFINDEX, napi->dev->ifindex))
>> +		goto nla_put_failure;
> 
>>   int netdev_nl_napi_get_doit(struct sk_buff *skb, struct genl_info *info)
>>   {
>> -	return -EOPNOTSUPP;
>> +	struct net_device *netdev;
>> +	struct sk_buff *rsp;
>> +	u32 napi_id;
>> +	int err;
>> +
>> +	if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_NAPI_NAPI_ID))
>> +		return -EINVAL;
>> +
>> +	napi_id = nla_get_u32(info->attrs[NETDEV_A_NAPI_NAPI_ID]);
>> +
>> +	rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
>> +	if (!rsp)
>> +		return -ENOMEM;
>> +
>> +	rtnl_lock();
>> +
>> +	netdev = dev_get_by_napi_id(napi_id);
> 
> Why lookup the dev and not the NAPI?

Agree. Will fix in v3.

> 
>> +	if (netdev)
>> +		err  = netdev_nl_napi_fill(netdev, rsp, info, napi_id);
>> +	else
>> +		err = -ENODEV;
>> +
>> +	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, int *start)
>> +{
>> +	struct napi_struct *napi, *n;
>> +	int err = 0;
>> +	int i = 0;
>> +
>> +	list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) {
> 
> Why _safe()? I think you need _rcu() instead?

Agree. This is called within rtnl_lock. Will fix.

> 
>> +		if (i < *start) {
>> +			i++;
>> +			continue;
>> +		}
>> +		err = netdev_nl_napi_fill_one(rsp, napi, info);
>> +		if (err)
>> +			break;
>> +		*start = ++i;
> 
> Why count them instead of relying on the IDs?

Makes sense. Will fix.

> 
>>   int netdev_nl_napi_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
>>   {
>> -	return -EOPNOTSUPP;
>> +	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
> 
> You can get genl_info_dump(cb) here, you don't use the genl_dumpit_info
> AFAICT, only info->info.

Will fix in v3.
diff mbox series

Patch

diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
index b146679d6112..4bc6aa756001 100644
--- a/net/core/netdev-genl.c
+++ b/net/core/netdev-genl.c
@@ -5,9 +5,23 @@ 
 #include <linux/rtnetlink.h>
 #include <net/net_namespace.h>
 #include <net/sock.h>
+#include <net/netdev_rx_queue.h>
 
 #include "netdev-genl-gen.h"
 
+struct netdev_nl_dump_ctx {
+	unsigned long	ifindex;
+	int		napi_idx;
+};
+
+static inline struct netdev_nl_dump_ctx *
+netdev_dump_ctx(struct netlink_callback *cb)
+{
+	NL_ASSERT_DUMP_CTX_FITS(struct netdev_nl_dump_ctx);
+
+	return (struct netdev_nl_dump_ctx *)cb->ctx;
+}
+
 static int
 netdev_nl_dev_fill(struct net_device *netdev, struct sk_buff *rsp,
 		   const struct genl_info *info)
@@ -101,12 +115,13 @@  int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info)
 
 int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
 {
+	struct netdev_nl_dump_ctx *ctx = netdev_dump_ctx(cb);
 	struct net *net = sock_net(skb->sk);
 	struct net_device *netdev;
 	int err = 0;
 
 	rtnl_lock();
-	for_each_netdev_dump(net, netdev, cb->args[0]) {
+	for_each_netdev_dump(net, netdev, ctx->ifindex) {
 		err = netdev_nl_dev_fill(netdev, skb, genl_info_dump(cb));
 		if (err < 0)
 			break;
@@ -119,14 +134,158 @@  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)
+{
+	struct netdev_rx_queue *rx_queue, *rxq;
+	struct netdev_queue *tx_queue, *txq;
+	unsigned int rx_qid, tx_qid;
+	void *hdr;
+
+	if (!napi->dev)
+		return -EINVAL;
+
+	hdr = genlmsg_iput(rsp, info);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	if (nla_put_u32(rsp, NETDEV_A_NAPI_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;
+
+	list_for_each_entry_safe(rx_queue, rxq, &napi->napi_rxq_list, q_list) {
+		rx_qid = get_netdev_rx_queue_index(rx_queue);
+		if (nla_put_u32(rsp, NETDEV_A_NAPI_RX_QUEUES, rx_qid))
+			goto nla_put_failure;
+	}
+
+	list_for_each_entry_safe(tx_queue, txq, &napi->napi_txq_list, q_list) {
+		tx_qid = get_netdev_queue_index(tx_queue);
+		if (nla_put_u32(rsp, NETDEV_A_NAPI_TX_QUEUES, tx_qid))
+			goto nla_put_failure;
+	}
+
+	genlmsg_end(rsp, hdr);
+	return 0;
+
+nla_put_failure:
+	genlmsg_cancel(rsp, hdr);
+	return -EMSGSIZE;
+}
+
+static int
+netdev_nl_napi_fill(struct net_device *netdev, struct sk_buff *rsp,
+		    const struct genl_info *info, u32 napi_id)
+{
+	struct napi_struct *napi, *n;
+
+	list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) {
+		if (napi->napi_id == napi_id)
+			return netdev_nl_napi_fill_one(rsp, napi, info);
+	}
+	return -EINVAL;
+}
+
 int netdev_nl_napi_get_doit(struct sk_buff *skb, struct genl_info *info)
 {
-	return -EOPNOTSUPP;
+	struct net_device *netdev;
+	struct sk_buff *rsp;
+	u32 napi_id;
+	int err;
+
+	if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_NAPI_NAPI_ID))
+		return -EINVAL;
+
+	napi_id = nla_get_u32(info->attrs[NETDEV_A_NAPI_NAPI_ID]);
+
+	rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!rsp)
+		return -ENOMEM;
+
+	rtnl_lock();
+
+	netdev = dev_get_by_napi_id(napi_id);
+	if (netdev)
+		err  = netdev_nl_napi_fill(netdev, rsp, info, napi_id);
+	else
+		err = -ENODEV;
+
+	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, int *start)
+{
+	struct napi_struct *napi, *n;
+	int err = 0;
+	int i = 0;
+
+	list_for_each_entry_safe(napi, n, &netdev->napi_list, dev_list) {
+		if (i < *start) {
+			i++;
+			continue;
+		}
+		err = netdev_nl_napi_fill_one(rsp, napi, info);
+		if (err)
+			break;
+		*start = ++i;
+	}
+	return err;
 }
 
 int netdev_nl_napi_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	return -EOPNOTSUPP;
+	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
+	struct netdev_nl_dump_ctx *ctx = netdev_dump_ctx(cb);
+	struct net *net = sock_net(skb->sk);
+	struct net_device *netdev;
+	int n_idx = ctx->napi_idx;
+	u32 ifindex = 0;
+	int err = 0;
+
+	if (info->info.attrs[NETDEV_A_NAPI_IFINDEX])
+		ifindex = nla_get_u32(info->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,
+						      genl_info_dump(cb),
+						      &n_idx);
+		else
+			err = -ENODEV;
+	} else {
+		for_each_netdev_dump(net, netdev, ctx->ifindex) {
+			err = netdev_nl_napi_dump_one(netdev, skb,
+						      genl_info_dump(cb),
+						      &n_idx);
+			if (!err)
+				n_idx = 0;
+			if (err < 0)
+				break;
+		}
+	}
+	rtnl_unlock();
+
+	if (err != -EMSGSIZE)
+		return err;
+
+	ctx->napi_idx = n_idx;
+	return skb->len;
 }
 
 static int netdev_genl_netdevice_event(struct notifier_block *nb,