diff mbox series

[net-next,v3,04/10] netdev-genl: Add netlink framework functions for queue

Message ID 169516245672.7377.15243846195860899954.stgit@anambiarhost.jf.intel.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series Introduce queue and NAPI support in netdev-genl (Was: 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: 1342 this patch: 1342
netdev/cc_maintainers warning 4 maintainers not CCed: ast@kernel.org edumazet@google.com pabeni@redhat.com davem@davemloft.net
netdev/build_clang success Errors and warnings before: 1364 this patch: 1364
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: 1365 this patch: 1365
netdev/checkpatch warning WARNING: line length of 84 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline fail Was 0 now: 1

Commit Message

Nambiar, Amritha Sept. 19, 2023, 10:27 p.m. UTC
Implement the netdev netlink framework functions for
exposing queue information.

Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
---
 net/core/netdev-genl.c |  207 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 204 insertions(+), 3 deletions(-)

Comments

Paolo Abeni Oct. 10, 2023, 9:08 a.m. UTC | #1
On Tue, 2023-09-19 at 15:27 -0700, Amritha Nambiar wrote:
> Implement the netdev netlink framework functions for
> exposing queue information.
> 
> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
> Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
> ---
>  net/core/netdev-genl.c |  207 +++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 204 insertions(+), 3 deletions(-)
> 
> diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
> index 336c608e6a6b..ceb7d1722f7c 100644
> --- a/net/core/netdev-genl.c
> +++ b/net/core/netdev-genl.c
[...] 
>  int netdev_nl_queue_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);
> +	unsigned int rxq_idx = ctx->rxq_idx;
> +	unsigned int txq_idx = ctx->txq_idx;
> +	struct net_device *netdev;
> +	u32 ifindex = 0;
> +	int err = 0;
> +
> +	if (info->attrs[NETDEV_A_QUEUE_IFINDEX])
> +		ifindex = nla_get_u32(info->attrs[NETDEV_A_QUEUE_IFINDEX]);
> +
> +	rtnl_lock();
> +	if (ifindex) {
> +		netdev = __dev_get_by_index(net, ifindex);
> +		if (netdev)
> +			err = netdev_nl_queue_dump_one(netdev, skb, info,
> +						       &rxq_idx, &txq_idx);
> +		else
> +			err = -ENODEV;
> +	} else {
> +		for_each_netdev_dump(net, netdev, ctx->ifindex) {
> +			err = netdev_nl_queue_dump_one(netdev, skb, info,
> +						       &rxq_idx, &txq_idx);
> +
> +			if (err < 0)
> +				break;
> +			if (!err) {
> +				rxq_idx = 0;
> +				txq_idx = 0;

AFAICS, above 'err' can be either < 0 or == 0. The second test: '!err'
should be unneeded and is a bit confusing.

Cheers,

Paolo
Nambiar, Amritha Oct. 10, 2023, 7:57 p.m. UTC | #2
On 10/10/2023 2:08 AM, Paolo Abeni wrote:
> On Tue, 2023-09-19 at 15:27 -0700, Amritha Nambiar wrote:
>> Implement the netdev netlink framework functions for
>> exposing queue information.
>>
>> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
>> Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
>> ---
>>   net/core/netdev-genl.c |  207 +++++++++++++++++++++++++++++++++++++++++++++++-
>>   1 file changed, 204 insertions(+), 3 deletions(-)
>>
>> diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
>> index 336c608e6a6b..ceb7d1722f7c 100644
>> --- a/net/core/netdev-genl.c
>> +++ b/net/core/netdev-genl.c
> [...]
>>   int netdev_nl_queue_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);
>> +	unsigned int rxq_idx = ctx->rxq_idx;
>> +	unsigned int txq_idx = ctx->txq_idx;
>> +	struct net_device *netdev;
>> +	u32 ifindex = 0;
>> +	int err = 0;
>> +
>> +	if (info->attrs[NETDEV_A_QUEUE_IFINDEX])
>> +		ifindex = nla_get_u32(info->attrs[NETDEV_A_QUEUE_IFINDEX]);
>> +
>> +	rtnl_lock();
>> +	if (ifindex) {
>> +		netdev = __dev_get_by_index(net, ifindex);
>> +		if (netdev)
>> +			err = netdev_nl_queue_dump_one(netdev, skb, info,
>> +						       &rxq_idx, &txq_idx);
>> +		else
>> +			err = -ENODEV;
>> +	} else {
>> +		for_each_netdev_dump(net, netdev, ctx->ifindex) {
>> +			err = netdev_nl_queue_dump_one(netdev, skb, info,
>> +						       &rxq_idx, &txq_idx);
>> +
>> +			if (err < 0)
>> +				break;
>> +			if (!err) {
>> +				rxq_idx = 0;
>> +				txq_idx = 0;
> 
> AFAICS, above 'err' can be either < 0 or == 0. The second test: '!err'
> should be unneeded and is a bit confusing.

Sure, will fix and submit v5. Just checking, this comment is on v3 
series, I had submitted a v4 addressing your previous comments.

> 
> Cheers,
> 
> Paolo
>
diff mbox series

Patch

diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
index 336c608e6a6b..ceb7d1722f7c 100644
--- a/net/core/netdev-genl.c
+++ b/net/core/netdev-genl.c
@@ -6,9 +6,24 @@ 
 #include <net/net_namespace.h>
 #include <net/sock.h>
 #include <net/xdp.h>
+#include <net/netdev_rx_queue.h>
 
 #include "netdev-genl-gen.h"
 
+struct netdev_nl_dump_ctx {
+	unsigned long	ifindex;
+	unsigned int	rxq_idx;
+	unsigned int	txq_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)
@@ -111,12 +126,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;
@@ -129,14 +145,199 @@  int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
 	return skb->len;
 }
 
+static int
+netdev_nl_queue_fill_one(struct sk_buff *rsp, struct net_device *netdev,
+			 u32 q_idx, u32 q_type, const struct genl_info *info)
+{
+	struct netdev_rx_queue *rxq;
+	struct netdev_queue *txq;
+	void *hdr;
+
+	hdr = genlmsg_iput(rsp, info);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	if (nla_put_u32(rsp, NETDEV_A_QUEUE_Q_ID, q_idx))
+		goto nla_put_failure;
+
+	if (nla_put_u32(rsp, NETDEV_A_QUEUE_Q_TYPE, q_type))
+		goto nla_put_failure;
+
+	if (nla_put_u32(rsp, NETDEV_A_QUEUE_IFINDEX, netdev->ifindex))
+		goto nla_put_failure;
+
+	switch (q_type) {
+	case NETDEV_QUEUE_TYPE_RX:
+		rxq = __netif_get_rx_queue(netdev, q_idx);
+		if (rxq->napi && nla_put_u32(rsp, NETDEV_A_QUEUE_NAPI_ID,
+					     rxq->napi->napi_id))
+			goto nla_put_failure;
+		break;
+	case NETDEV_QUEUE_TYPE_TX:
+		txq = netdev_get_tx_queue(netdev, q_idx);
+		if (txq->napi && nla_put_u32(rsp, NETDEV_A_QUEUE_NAPI_ID,
+					     txq->napi->napi_id))
+			goto nla_put_failure;
+
+		if (nla_put_u32(rsp, NETDEV_A_QUEUE_TX_MAXRATE,
+				txq->tx_maxrate))
+			goto nla_put_failure;
+		break;
+	}
+
+	genlmsg_end(rsp, hdr);
+
+	return 0;
+
+nla_put_failure:
+	genlmsg_cancel(rsp, hdr);
+	return -EMSGSIZE;
+}
+
+static int netdev_nl_queue_validate(struct net_device *netdev, u32 q_id, u32 q_type)
+{
+	switch (q_type) {
+	case NETDEV_QUEUE_TYPE_RX:
+		if (q_id >= netdev->real_num_rx_queues)
+			return -EINVAL;
+		return 0;
+	case NETDEV_QUEUE_TYPE_TX:
+		if (q_id >= netdev->real_num_tx_queues)
+			return -EINVAL;
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int
+netdev_nl_queue_fill(struct sk_buff *rsp, struct net_device *netdev, u32 q_idx,
+		     u32 q_type, const struct genl_info *info)
+{
+	int err;
+
+	err = netdev_nl_queue_validate(netdev, q_idx, q_type);
+	if (err)
+		return err;
+
+	return netdev_nl_queue_fill_one(rsp, netdev, q_idx, q_type, info);
+}
+
 int netdev_nl_queue_get_doit(struct sk_buff *skb, struct genl_info *info)
 {
-	return -EOPNOTSUPP;
+	u32 q_id, q_type, ifindex;
+	struct net_device *netdev;
+	struct sk_buff *rsp;
+	int err;
+
+	if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_QUEUE_Q_ID))
+		return -EINVAL;
+
+	if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_QUEUE_Q_TYPE))
+		return -EINVAL;
+
+	if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_QUEUE_IFINDEX))
+		return -EINVAL;
+
+	q_id = nla_get_u32(info->attrs[NETDEV_A_QUEUE_Q_ID]);
+
+	q_type = nla_get_u32(info->attrs[NETDEV_A_QUEUE_Q_TYPE]);
+
+	ifindex = nla_get_u32(info->attrs[NETDEV_A_QUEUE_IFINDEX]);
+
+	rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!rsp)
+		return -ENOMEM;
+
+	rtnl_lock();
+
+	netdev = __dev_get_by_index(genl_info_net(info), ifindex);
+	if (netdev)
+		err  = netdev_nl_queue_fill(rsp, netdev, q_id, q_type, info);
+	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_queue_dump_one(struct net_device *netdev, struct sk_buff *rsp,
+			 const struct genl_info *info, unsigned int *start_rx,
+			 unsigned int *start_tx)
+{
+	int err = 0;
+	int i;
+
+	for (i = *start_rx; i < netdev->real_num_rx_queues;) {
+		err = netdev_nl_queue_fill_one(rsp, netdev, i,
+					       NETDEV_QUEUE_TYPE_RX, info);
+		if (err)
+			goto out_err;
+		*start_rx = i++;
+	}
+	for (i = *start_tx; i < netdev->real_num_tx_queues;) {
+		err = netdev_nl_queue_fill_one(rsp, netdev, i,
+					       NETDEV_QUEUE_TYPE_TX, info);
+		if (err)
+			goto out_err;
+		*start_tx = i++;
+	}
+out_err:
+	return err;
 }
 
 int netdev_nl_queue_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);
+	unsigned int rxq_idx = ctx->rxq_idx;
+	unsigned int txq_idx = ctx->txq_idx;
+	struct net_device *netdev;
+	u32 ifindex = 0;
+	int err = 0;
+
+	if (info->attrs[NETDEV_A_QUEUE_IFINDEX])
+		ifindex = nla_get_u32(info->attrs[NETDEV_A_QUEUE_IFINDEX]);
+
+	rtnl_lock();
+	if (ifindex) {
+		netdev = __dev_get_by_index(net, ifindex);
+		if (netdev)
+			err = netdev_nl_queue_dump_one(netdev, skb, info,
+						       &rxq_idx, &txq_idx);
+		else
+			err = -ENODEV;
+	} else {
+		for_each_netdev_dump(net, netdev, ctx->ifindex) {
+			err = netdev_nl_queue_dump_one(netdev, skb, info,
+						       &rxq_idx, &txq_idx);
+
+			if (err < 0)
+				break;
+			if (!err) {
+				rxq_idx = 0;
+				txq_idx = 0;
+			}
+		}
+	}
+	rtnl_unlock();
+
+	if (err != -EMSGSIZE)
+		return err;
+
+	ctx->rxq_idx = rxq_idx;
+	ctx->txq_idx = txq_idx;
+	return skb->len;
 }
 
 static int netdev_genl_netdevice_event(struct notifier_block *nb,