lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <dd842cbd-5282-423c-85cd-a8969da6e814@intel.com>
Date: Mon, 8 Apr 2024 12:45:49 -0700
From: "Nambiar, Amritha" <amritha.nambiar@...el.com>
To: David Wei <dw@...idwei.uk>, <netdev@...r.kernel.org>, <kuba@...nel.org>,
	<davem@...emloft.net>
CC: <edumazet@...gle.com>, <pabeni@...hat.com>, <ast@...nel.org>,
	<sdf@...gle.com>, <lorenzo@...nel.org>, <tariqt@...dia.com>,
	<daniel@...earbox.net>, <anthony.l.nguyen@...el.com>, <lucien.xin@...il.com>,
	<hawk@...nel.org>, <sridhar.samudrala@...el.com>
Subject: Re: [net-next, RFC PATCH 2/5] netdev-genl: Add netlink framework
 functions for queue-set NAPI

On 4/5/2024 5:20 PM, David Wei wrote:
> On 2024-04-05 13:09, Amritha Nambiar wrote:
>> Implement the netdev netlink framework functions for associating
>> a queue with NAPI ID.
>>
>> Signed-off-by: Amritha Nambiar <amritha.nambiar@...el.com>
>> ---
>>   include/linux/netdevice.h |    7 +++
>>   net/core/netdev-genl.c    |  117 +++++++++++++++++++++++++++++++++++++++------
>>   2 files changed, 108 insertions(+), 16 deletions(-)
>>
>> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>> index 0c198620ac93..70df1cec4a60 100644
>> --- a/include/linux/netdevice.h
>> +++ b/include/linux/netdevice.h
>> @@ -1351,6 +1351,10 @@ struct netdev_net_notifier {
>>    *			   struct kernel_hwtstamp_config *kernel_config,
>>    *			   struct netlink_ext_ack *extack);
>>    *	Change the hardware timestamping parameters for NIC device.
>> + *
>> + * int (*ndo_queue_set_napi)(struct net_device *dev, u32 q_idx, u32 q_type,
>> + *			     struct napi_struct *napi);
>> + *	Change the NAPI instance associated with the queue.
>>    */
>>   struct net_device_ops {
>>   	int			(*ndo_init)(struct net_device *dev);
>> @@ -1596,6 +1600,9 @@ struct net_device_ops {
>>   	int			(*ndo_hwtstamp_set)(struct net_device *dev,
>>   						    struct kernel_hwtstamp_config *kernel_config,
>>   						    struct netlink_ext_ack *extack);
>> +	int			(*ndo_queue_set_napi)(struct net_device *dev,
>> +						      u32 q_idx, u32 q_type,
>> +						      struct napi_struct *napi);
>>   };
>>   
>>   /**
>> diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
>> index d5b2e90e5709..6b3d3165d76e 100644
>> --- a/net/core/netdev-genl.c
>> +++ b/net/core/netdev-genl.c
>> @@ -288,12 +288,29 @@ int netdev_nl_napi_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
>>   	return err;
>>   }
>>   
>> +/* must be called under rtnl_lock() */
>> +static struct napi_struct *
>> +napi_get_by_queue(struct net_device *netdev, u32 q_idx, u32 q_type)
>> +{
>> +	struct netdev_rx_queue *rxq;
>> +	struct netdev_queue *txq;
>> +
>> +	switch (q_type) {
>> +	case NETDEV_QUEUE_TYPE_RX:
>> +		rxq = __netif_get_rx_queue(netdev, q_idx);
>> +		return rxq->napi;
>> +	case NETDEV_QUEUE_TYPE_TX:
>> +		txq = netdev_get_tx_queue(netdev, q_idx);
>> +		return txq->napi;
>> +	}
>> +	return NULL;
>> +}
>> +
>>   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;
>> +	struct napi_struct *napi;
>>   	void *hdr;
>>   
>>   	hdr = genlmsg_iput(rsp, info);
>> @@ -305,19 +322,9 @@ netdev_nl_queue_fill_one(struct sk_buff *rsp, struct net_device *netdev,
>>   	    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;
>> -	}
>> +	napi = napi_get_by_queue(netdev, q_idx, q_type);
>> +	if (napi && nla_put_u32(rsp, NETDEV_A_QUEUE_NAPI_ID, napi->napi_id))
>> +		goto nla_put_failure;
>>   
>>   	genlmsg_end(rsp, hdr);
>>   
>> @@ -674,9 +681,87 @@ int netdev_nl_qstats_get_dumpit(struct sk_buff *skb,
>>   	return err;
>>   }
>>   
>> +static int
>> +netdev_nl_queue_set_napi(struct sk_buff *rsp, struct net_device *netdev,
>> +			 u32 q_idx, u32 q_type, u32 napi_id,
>> +			 const struct genl_info *info)
>> +{
>> +	struct napi_struct *napi, *old_napi;
>> +	int err;
>> +
>> +	if (!(netdev->flags & IFF_UP))
>> +		return 0;
> 
> Should this be an error code?

Thought I can return 0 like the _get_ functions as this is a noop and 
not really an error.

> 
>> +
>> +	err = netdev_nl_queue_validate(netdev, q_idx, q_type);
>> +	if (err)
>> +		return err;
>> +
>> +	old_napi = napi_get_by_queue(netdev, q_idx, q_type);
>> +	if (old_napi && old_napi->napi_id == napi_id)
>> +		return 0;
> 
> Same as above, I think this should be an error.

I was thinking I can follow the ethtool semantics here, when there's no 
update/parameter values are not modified, it is a noop and proceed to 
display the current values instead of throwing error.

> 
>> +
>> +	napi = napi_by_id(napi_id);
>> +	if (!napi)
>> +		return -EINVAL;
>> +
>> +	err = netdev->netdev_ops->ndo_queue_set_napi(netdev, q_idx, q_type, napi);
>> +
>> +	return err;
> 
> nit: return ndo_queue_set_napi() would save two lines.

Sure, will fix in the next version.

> 
>> +}
>> +
>>   int netdev_nl_queue_set_doit(struct sk_buff *skb, struct genl_info *info)
>>   {
>> -	return -EOPNOTSUPP;
>> +	u32 q_id, q_type, ifindex;
> 
> nit: q_idx for consistency?

Sure, will fix.

> 
>> +	struct net_device *netdev;
>> +	struct sk_buff *rsp;
>> +	u32 napi_id = 0;
>> +	int err = 0;
>> +
>> +	if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_QUEUE_ID) ||
>> +	    GENL_REQ_ATTR_CHECK(info, NETDEV_A_QUEUE_TYPE) ||
>> +	    GENL_REQ_ATTR_CHECK(info, NETDEV_A_QUEUE_IFINDEX))
>> +		return -EINVAL;
>> +
>> +	q_id = nla_get_u32(info->attrs[NETDEV_A_QUEUE_ID]);
>> +	q_type = nla_get_u32(info->attrs[NETDEV_A_QUEUE_TYPE]);
>> +	ifindex = nla_get_u32(info->attrs[NETDEV_A_QUEUE_IFINDEX]);
>> +
>> +	if (info->attrs[NETDEV_A_QUEUE_NAPI_ID]) {
>> +		napi_id = nla_get_u32(info->attrs[NETDEV_A_QUEUE_NAPI_ID]);
>> +		if (napi_id < MIN_NAPI_ID)
>> +			return -EINVAL;
>> +	}
>> +
>> +	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) {
>> +		if (!napi_id)
>> +			GENL_SET_ERR_MSG(info, "No queue parameters changed\n");
> 
> Could this be checked earlier outside of rtnl_lock? I feel like not
> setting a napi_id here is EINVAL.
> 

I agree this part is a little ambiguous as I was trying to handle a few 
things here that I was not really sure of. The idea was that 
netdev_nl_queue_set_doit() could be the one function to handle all set 
params for the queue object. Today, only napi-id is supported. In 
future, there may be additional configurable attributes for the queue 
object beyond napi-id. So, it should be possible to set those params as 
well from netdev_nl_queue_set_doit(), which implies that, not setting 
napi-id is not EINVAL, as some other param could be set. If none of the 
configurable params are set, display the message and the current 
settings for the queue.
So the code today handles this; if the user has given a napi-id and it 
is valid, then proceed to the ndo callback. If the user has not 
specified a napi-id to update, it is not an error case, display the 
current settings, same as ethtool-set params does (although it's done in 
the userspace in case of ethtool). Ideally, this should be handled in 
the userspace for netdev-genl, maybe some tricks in the YAML can achieve 
this for the set command to check for the presence of atleast one 
configurable attribute in netdev-user.c.
I think, the following in YAML would make napi-id mandatory:
name: napi-id
checks:
   min: 1

But, that's not exactly what we want for set any params, what I was 
aiming for was to have any one attribute required from among a group of 
attributes.

>> +		else
>> +			err = netdev_nl_queue_set_napi(rsp, netdev, q_id,
>> +						       q_type, napi_id, info);
>> +		if (!err)
>> +			err = netdev_nl_queue_fill_one(rsp, netdev, q_id,
>> +						       q_type, info);
>> +	} else {
>> +		err = -ENODEV;
> 
> Could be less nesty (completely untested):
> 

Sure, thanks. I'll make this less nesty.

> 	if (!netdev) {
> 		err = -ENODEV;
> 		goto err_rtnl_unlock;
> 	}
> 
> 	if (!napi_id) {
> 		GENL_SET_ERR_MSG(info, "No queue parameters changed\n");
> 		goto err_nonapi;
> 	}
> 
> 	err = netdev_nl_queue_set_napi(rsp, netdev, q_id,
> 				       q_type, napi_id, info);
> 	if (err)
> 		goto err_rtnl_unlock;
> 
> err_nonapi:
> 	err = netdev_nl_queue_fill_one(rsp, netdev, q_id,
> 				       q_type, info);
> 
> err_rtnl_unlock:
> 	rtnl_unlock();
> 
> 	if (!err)
> 		return genlmsg_reply(rsp, info);
> 
> err_free_msg:
> 	nlmsg_free(rsp);
> 	return err;
> 
>> +	}
>> +
>> +	rtnl_unlock();
>> +
>> +	if (err)
>> +		goto err_free_msg;
>> +
>> +	return genlmsg_reply(rsp, info);
>> +
>> +err_free_msg:
>> +	nlmsg_free(rsp);
>> +	return err;
>>   }
>>   
>>   static int netdev_genl_netdevice_event(struct notifier_block *nb,
>>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ