net: dsa: use NET_NAME_PREDICTABLE for user ports with name given in DT

Message ID 20221111161729.915233-1-linux@rasmusvillemoes.dk
State New
Headers
Series net: dsa: use NET_NAME_PREDICTABLE for user ports with name given in DT |

Commit Message

Rasmus Villemoes Nov. 11, 2022, 4:17 p.m. UTC
  When a user port has a label in device tree, the corresponding
netdevice is "predictably named by the kernel".

Expose that information properly for the benefit of userspace tools
that make decisions based on the name_assign_type attribute,
e.g. a systemd-udev rule with "kernel" in NamePolicy.

Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
---
 net/dsa/dsa2.c  |  3 ---
 net/dsa/slave.c | 13 +++++++++++--
 2 files changed, 11 insertions(+), 5 deletions(-)
  

Comments

Andrew Lunn Nov. 11, 2022, 5:10 p.m. UTC | #1
> diff --git a/net/dsa/slave.c b/net/dsa/slave.c
> index a9fde48cffd4..dfefcc4a9ccf 100644
> --- a/net/dsa/slave.c
> +++ b/net/dsa/slave.c
> @@ -2374,16 +2374,25 @@ int dsa_slave_create(struct dsa_port *port)
>  {
>  	struct net_device *master = dsa_port_to_master(port);
>  	struct dsa_switch *ds = port->ds;
> -	const char *name = port->name;
>  	struct net_device *slave_dev;
>  	struct dsa_slave_priv *p;
> +	const char *name;
> +	int assign_type;
>  	int ret;
>  
>  	if (!ds->num_tx_queues)
>  		ds->num_tx_queues = 1;
>  
> +	if (port->name) {
> +		name = port->name;
> +		assign_type = NET_NAME_PREDICTABLE;
> +	} else {
> +		name = "eth%d";
> +		assign_type = NET_NAME_UNKNOWN;
> +	}

I know it is a change in behaviour, but it seems like NET_NAME_ENUM
should be used, not NET_NAME_UNKNOWN. alloc_etherdev_mqs() uses
NET_NAME_ENUM.

https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/netdevice.h#L42
says that NET_NAME_UNKNOWN does not get passed to user space, but i
assume NET_NAME_ENUM does. So maybe changing it would be an ABI
change?

Humm, i don't know what the right thing is...

      Andrew
  
Rasmus Villemoes Nov. 13, 2022, 8:03 p.m. UTC | #2
On 11/11/2022 18.10, Andrew Lunn wrote:
>> diff --git a/net/dsa/slave.c b/net/dsa/slave.c
>> index a9fde48cffd4..dfefcc4a9ccf 100644
>> --- a/net/dsa/slave.c
>> +++ b/net/dsa/slave.c
>> @@ -2374,16 +2374,25 @@ int dsa_slave_create(struct dsa_port *port)
>>  {
>>  	struct net_device *master = dsa_port_to_master(port);
>>  	struct dsa_switch *ds = port->ds;
>> -	const char *name = port->name;
>>  	struct net_device *slave_dev;
>>  	struct dsa_slave_priv *p;
>> +	const char *name;
>> +	int assign_type;
>>  	int ret;
>>  
>>  	if (!ds->num_tx_queues)
>>  		ds->num_tx_queues = 1;
>>  
>> +	if (port->name) {
>> +		name = port->name;
>> +		assign_type = NET_NAME_PREDICTABLE;
>> +	} else {
>> +		name = "eth%d";
>> +		assign_type = NET_NAME_UNKNOWN;
>> +	}
> 
> I know it is a change in behaviour, but it seems like NET_NAME_ENUM
> should be used, not NET_NAME_UNKNOWN. alloc_etherdev_mqs() uses
> NET_NAME_ENUM.

I don't really have any strong opinion on the case where we fall back to
eth%d, as its not relevant to any board I've worked on.

> https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/netdevice.h#L42
> says that NET_NAME_UNKNOWN does not get passed to user space, but i
> assume NET_NAME_ENUM does. So maybe changing it would be an ABI
> change?

Well, the name_assign_type ABI is kind of silly. I mean, userspace knows
that when one gets EINVAL trying to read the value, that really means
that the value is NET_NAME_UNKNOWN. But I won't propose changing that.

However, what I do propose here is obviously already an ABI change; I
_want_ to expose more proper information in the case where the port has
a label, and just kept the NET_NAME_UNKNOWN for the eth%d case to make
the minimal change. But if people want to change that to NET_NAME_ENUM
while we're here, I can certainly do that. I can't think of any real
scenario where NET_NAME_ENUM would be treated differently than
NET_NAME_UNKNOWN - in both cases, userspace don't know that the name can
be trusted to be predictable.

Rasmus
  
Jakub Kicinski Nov. 15, 2022, 2:17 a.m. UTC | #3
On Sun, 13 Nov 2022 21:03:52 +0100 Rasmus Villemoes wrote:
> > I know it is a change in behaviour, but it seems like NET_NAME_ENUM
> > should be used, not NET_NAME_UNKNOWN. alloc_etherdev_mqs() uses
> > NET_NAME_ENUM.  
> 
> I don't really have any strong opinion on the case where we fall back to
> eth%d, as its not relevant to any board I've worked on.
> 
> > https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/netdevice.h#L42
> > says that NET_NAME_UNKNOWN does not get passed to user space, but i
> > assume NET_NAME_ENUM does. So maybe changing it would be an ABI
> > change?  
> 
> Well, the name_assign_type ABI is kind of silly. I mean, userspace knows
> that when one gets EINVAL trying to read the value, that really means
> that the value is NET_NAME_UNKNOWN. But I won't propose changing that.
> 
> However, what I do propose here is obviously already an ABI change; I
> _want_ to expose more proper information in the case where the port has
> a label, and just kept the NET_NAME_UNKNOWN for the eth%d case to make
> the minimal change. But if people want to change that to NET_NAME_ENUM
> while we're here, I can certainly do that. I can't think of any real
> scenario where NET_NAME_ENUM would be treated differently than
> NET_NAME_UNKNOWN - in both cases, userspace don't know that the name can
> be trusted to be predictable.

Apparently there may be a reason, see commit e9f656b7a214 ("net:
ethernet: set default assignment identifier to NET_NAME_ENUM")
so let's switch to ENUM while at it.
  
Andrew Lunn Nov. 15, 2022, 3:02 p.m. UTC | #4
> Apparently there may be a reason, see commit e9f656b7a214 ("net:
> ethernet: set default assignment identifier to NET_NAME_ENUM")
> so let's switch to ENUM while at it.

I would recommend two patches, making it easier to revert if we find
something in userspace breaks.

	  Andrew
  

Patch

diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index e504a18fc125..522fc1b6e8c6 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -1364,9 +1364,6 @@  static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index)
 
 static int dsa_port_parse_user(struct dsa_port *dp, const char *name)
 {
-	if (!name)
-		name = "eth%d";
-
 	dp->type = DSA_PORT_TYPE_USER;
 	dp->name = name;
 
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index a9fde48cffd4..dfefcc4a9ccf 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -2374,16 +2374,25 @@  int dsa_slave_create(struct dsa_port *port)
 {
 	struct net_device *master = dsa_port_to_master(port);
 	struct dsa_switch *ds = port->ds;
-	const char *name = port->name;
 	struct net_device *slave_dev;
 	struct dsa_slave_priv *p;
+	const char *name;
+	int assign_type;
 	int ret;
 
 	if (!ds->num_tx_queues)
 		ds->num_tx_queues = 1;
 
+	if (port->name) {
+		name = port->name;
+		assign_type = NET_NAME_PREDICTABLE;
+	} else {
+		name = "eth%d";
+		assign_type = NET_NAME_UNKNOWN;
+	}
+
 	slave_dev = alloc_netdev_mqs(sizeof(struct dsa_slave_priv), name,
-				     NET_NAME_UNKNOWN, ether_setup,
+				     assign_type, ether_setup,
 				     ds->num_tx_queues, 1);
 	if (slave_dev == NULL)
 		return -ENOMEM;