Skip to content

Commit

Permalink
Merge branch 'netdev-altnames'
Browse files Browse the repository at this point in the history
Jiri Pirko says:

====================
net: introduce alternative names for network interfaces

In the past, there was repeatedly discussed the IFNAMSIZ (16) limit for
netdevice name length. Now when we have PF and VF representors
with port names like "pfXvfY", it became quite common to hit this limit:
0123456789012345
enp131s0f1npf0vf6
enp131s0f1npf0vf22

Udev cannot rename these interfaces out-of-the-box and user needs to
create custom rules to handle them.

Also, udev has multiple schemes of netdev names. From udev code:
 * Type of names:
 *   b<number>                             - BCMA bus core number
 *   c<bus_id>                             - bus id of a grouped CCW or CCW device,
 *                                           with all leading zeros stripped [s390]
 *   o<index>[n<phys_port_name>|d<dev_port>]
 *                                         - on-board device index number
 *   s<slot>[f<function>][n<phys_port_name>|d<dev_port>]
 *                                         - hotplug slot index number
 *   x<MAC>                                - MAC address
 *   [P<domain>]p<bus>s<slot>[f<function>][n<phys_port_name>|d<dev_port>]
 *                                         - PCI geographical location
 *   [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
 *                                         - USB port number chain
 *   v<slot>                               - VIO slot number (IBM PowerVM)
 *   a<vendor><model>i<instance>           - Platform bus ACPI instance id
 *   i<addr>n<phys_port_name>              - Netdevsim bus address and port name

One device can be often renamed by multiple patterns at the
same time (e.g. pci address/mac).

This patchset introduces alternative names for network interfaces.
Main goal is to:
1) Overcome the IFNAMSIZ limitation (altname limitation is 128 bytes)
2) Allow to have multiple names at the same time (multiple udev patterns)
3) Allow to use alternative names as handle for commands

The patchset introduces two new commands to add/delete list of properties.
Currently only alternative names are implemented but the ifrastructure
could be easily extended later on. This is very similar to the list of vlan
and tunnels being added/deleted to/from bridge ports.

See following examples.

$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether ae:67:a9:67:46:86 brd ff:ff:ff:ff:ff:ff

-> Add alternative names for dummy0:

$ ip link prop add dummy0 altname someothername
$ ip link prop add dummy0 altname someotherveryveryveryverylongname
$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether ae:67:a9:67:46:86 brd ff:ff:ff:ff:ff:ff
    altname someothername
    altname someotherveryveryveryverylongname
$ ip link show someotherveryveryveryverylongname
2: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether ae:67:a9:67:46:86 brd ff:ff:ff:ff:ff:ff
    altname someothername
    altname someotherveryveryveryverylongname

-> Add bridge brx, add it's alternative name and use alternative names to
   do enslavement.

$ ip link add name brx type bridge
$ ip link prop add brx altname mypersonalsuperspecialbridge
$ ip link set someotherveryveryveryverylongname master mypersonalsuperspecialbridge
$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop master brx state DOWN mode DEFAULT group default qlen 1000
    link/ether ae:67:a9:67:46:86 brd ff:ff:ff:ff:ff:ff
    altname someothername
    altname someotherveryveryveryverylongname
3: brx: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether ae:67:a9:67:46:86 brd ff:ff:ff:ff:ff:ff
    altname mypersonalsuperspecialbridge

-> Add ipv4 address to the bridge using alternative name:

$ ip addr add 192.168.0.1/24 dev mypersonalsuperspecialbridge
$ ip addr show mypersonalsuperspecialbridge
3: brx: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether ae:67:a9:67:46:86 brd ff:ff:ff:ff:ff:ff
    altname mypersonalsuperspecialbridge
    inet 192.168.0.1/24 scope global brx
       valid_lft forever preferred_lft forever

-> Delete one of dummy0 alternative names:

$ ip link prop del dummy0 altname someotherveryveryveryverylongname
$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop master brx state DOWN mode DEFAULT group default qlen 1000
    link/ether ae:67:a9:67:46:86 brd ff:ff:ff:ff:ff:ff
    altname someothername
3: brx: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether ae:67:a9:67:46:86 brd ff:ff:ff:ff:ff:ff
    altname mypersonalsuperspecialbridge

-> Add multiple alternative names at once

$ ip link prop add dummy0 altname a altname b altname c altname d
$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop master brx state DOWN mode DEFAULT group default qlen 1000
    link/ether ae:67:a9:67:46:86 brd ff:ff:ff:ff:ff:ff
    altname someothername
    altname a
    altname b
    altname c
    altname d
3: brx: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether ae:67:a9:67:46:86 brd ff:ff:ff:ff:ff:ff
    altname mypersonalsuperspecialbridge
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
davem330 committed Oct 1, 2019
2 parents be2644a + 76c9ac0 commit 7a56493
Show file tree
Hide file tree
Showing 8 changed files with 348 additions and 43 deletions.
14 changes: 12 additions & 2 deletions include/linux/netdevice.h
Expand Up @@ -925,6 +925,16 @@ struct dev_ifalias {
struct devlink;
struct tlsdev_ops;

struct netdev_name_node {
struct hlist_node hlist;
struct list_head list;
struct net_device *dev;
const char *name;
};

int netdev_name_node_alt_create(struct net_device *dev, const char *name);
int netdev_name_node_alt_destroy(struct net_device *dev, const char *name);

/*
* This structure defines the management hooks for network devices.
* The following hooks can be defined; unless noted otherwise, they are
Expand Down Expand Up @@ -1564,7 +1574,7 @@ enum netdev_priv_flags {
* (i.e. as seen by users in the "Space.c" file). It is the name
* of the interface.
*
* @name_hlist: Device name hash chain, please keep it close to name[]
* @name_node: Name hashlist node
* @ifalias: SNMP alias
* @mem_end: Shared memory end
* @mem_start: Shared memory start
Expand Down Expand Up @@ -1774,7 +1784,7 @@ enum netdev_priv_flags {

struct net_device {
char name[IFNAMSIZ];
struct hlist_node name_hlist;
struct netdev_name_node *name_node;
struct dev_ifalias __rcu *ifalias;
/*
* I/O specific fields
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/if.h
Expand Up @@ -33,6 +33,7 @@
#define IFNAMSIZ 16
#endif /* __UAPI_DEF_IF_IFNAMSIZ */
#define IFALIASZ 256
#define ALTIFNAMSIZ 128
#include <linux/hdlc/ioctl.h>

/* For glibc compatibility. An empty enum does not compile. */
Expand Down
2 changes: 2 additions & 0 deletions include/uapi/linux/if_link.h
Expand Up @@ -167,6 +167,8 @@ enum {
IFLA_NEW_IFINDEX,
IFLA_MIN_MTU,
IFLA_MAX_MTU,
IFLA_PROP_LIST,
IFLA_ALT_IFNAME, /* Alternative ifname */
__IFLA_MAX
};

Expand Down
7 changes: 7 additions & 0 deletions include/uapi/linux/rtnetlink.h
Expand Up @@ -164,6 +164,13 @@ enum {
RTM_GETNEXTHOP,
#define RTM_GETNEXTHOP RTM_GETNEXTHOP

RTM_NEWLINKPROP = 108,
#define RTM_NEWLINKPROP RTM_NEWLINKPROP
RTM_DELLINKPROP,
#define RTM_DELLINKPROP RTM_DELLINKPROP
RTM_GETLINKPROP,
#define RTM_GETLINKPROP RTM_GETLINKPROP

__RTM_MAX,
#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
};
Expand Down
153 changes: 135 additions & 18 deletions net/core/dev.c
Expand Up @@ -228,6 +228,122 @@ static inline void rps_unlock(struct softnet_data *sd)
#endif
}

static struct netdev_name_node *netdev_name_node_alloc(struct net_device *dev,
const char *name)
{
struct netdev_name_node *name_node;

name_node = kmalloc(sizeof(*name_node), GFP_KERNEL);
if (!name_node)
return NULL;
INIT_HLIST_NODE(&name_node->hlist);
name_node->dev = dev;
name_node->name = name;
return name_node;
}

static struct netdev_name_node *
netdev_name_node_head_alloc(struct net_device *dev)
{
struct netdev_name_node *name_node;

name_node = netdev_name_node_alloc(dev, dev->name);
if (!name_node)
return NULL;
INIT_LIST_HEAD(&name_node->list);
return name_node;
}

static void netdev_name_node_free(struct netdev_name_node *name_node)
{
kfree(name_node);
}

static void netdev_name_node_add(struct net *net,
struct netdev_name_node *name_node)
{
hlist_add_head_rcu(&name_node->hlist,
dev_name_hash(net, name_node->name));
}

static void netdev_name_node_del(struct netdev_name_node *name_node)
{
hlist_del_rcu(&name_node->hlist);
}

static struct netdev_name_node *netdev_name_node_lookup(struct net *net,
const char *name)
{
struct hlist_head *head = dev_name_hash(net, name);
struct netdev_name_node *name_node;

hlist_for_each_entry(name_node, head, hlist)
if (!strcmp(name_node->name, name))
return name_node;
return NULL;
}

static struct netdev_name_node *netdev_name_node_lookup_rcu(struct net *net,
const char *name)
{
struct hlist_head *head = dev_name_hash(net, name);
struct netdev_name_node *name_node;

hlist_for_each_entry_rcu(name_node, head, hlist)
if (!strcmp(name_node->name, name))
return name_node;
return NULL;
}

int netdev_name_node_alt_create(struct net_device *dev, const char *name)
{
struct netdev_name_node *name_node;
struct net *net = dev_net(dev);

name_node = netdev_name_node_lookup(net, name);
if (name_node)
return -EEXIST;
name_node = netdev_name_node_alloc(dev, name);
if (!name_node)
return -ENOMEM;
netdev_name_node_add(net, name_node);
/* The node that holds dev->name acts as a head of per-device list. */
list_add_tail(&name_node->list, &dev->name_node->list);

return 0;
}
EXPORT_SYMBOL(netdev_name_node_alt_create);

static void __netdev_name_node_alt_destroy(struct netdev_name_node *name_node)
{
list_del(&name_node->list);
netdev_name_node_del(name_node);
kfree(name_node->name);
netdev_name_node_free(name_node);
}

int netdev_name_node_alt_destroy(struct net_device *dev, const char *name)
{
struct netdev_name_node *name_node;
struct net *net = dev_net(dev);

name_node = netdev_name_node_lookup(net, name);
if (!name_node)
return -ENOENT;
__netdev_name_node_alt_destroy(name_node);

return 0;
}
EXPORT_SYMBOL(netdev_name_node_alt_destroy);

static void netdev_name_node_alt_flush(struct net_device *dev)
{
struct netdev_name_node *name_node, *tmp;

list_for_each_entry_safe(name_node, tmp, &dev->name_node->list, list)
__netdev_name_node_alt_destroy(name_node);
}

/* Device list insertion */
static void list_netdevice(struct net_device *dev)
{
Expand All @@ -237,7 +353,7 @@ static void list_netdevice(struct net_device *dev)

write_lock_bh(&dev_base_lock);
list_add_tail_rcu(&dev->dev_list, &net->dev_base_head);
hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name));
netdev_name_node_add(net, dev->name_node);
hlist_add_head_rcu(&dev->index_hlist,
dev_index_hash(net, dev->ifindex));
write_unlock_bh(&dev_base_lock);
Expand All @@ -255,7 +371,7 @@ static void unlist_netdevice(struct net_device *dev)
/* Unlink dev from the device chain */
write_lock_bh(&dev_base_lock);
list_del_rcu(&dev->dev_list);
hlist_del_rcu(&dev->name_hlist);
netdev_name_node_del(dev->name_node);
hlist_del_rcu(&dev->index_hlist);
write_unlock_bh(&dev_base_lock);

Expand Down Expand Up @@ -733,14 +849,10 @@ EXPORT_SYMBOL_GPL(dev_fill_metadata_dst);

struct net_device *__dev_get_by_name(struct net *net, const char *name)
{
struct net_device *dev;
struct hlist_head *head = dev_name_hash(net, name);

hlist_for_each_entry(dev, head, name_hlist)
if (!strncmp(dev->name, name, IFNAMSIZ))
return dev;
struct netdev_name_node *node_name;

return NULL;
node_name = netdev_name_node_lookup(net, name);
return node_name ? node_name->dev : NULL;
}
EXPORT_SYMBOL(__dev_get_by_name);

Expand All @@ -758,14 +870,10 @@ EXPORT_SYMBOL(__dev_get_by_name);

struct net_device *dev_get_by_name_rcu(struct net *net, const char *name)
{
struct net_device *dev;
struct hlist_head *head = dev_name_hash(net, name);

hlist_for_each_entry_rcu(dev, head, name_hlist)
if (!strncmp(dev->name, name, IFNAMSIZ))
return dev;
struct netdev_name_node *node_name;

return NULL;
node_name = netdev_name_node_lookup_rcu(net, name);
return node_name ? node_name->dev : NULL;
}
EXPORT_SYMBOL(dev_get_by_name_rcu);

Expand Down Expand Up @@ -1232,13 +1340,13 @@ int dev_change_name(struct net_device *dev, const char *newname)
netdev_adjacent_rename_links(dev, oldname);

write_lock_bh(&dev_base_lock);
hlist_del_rcu(&dev->name_hlist);
netdev_name_node_del(dev->name_node);
write_unlock_bh(&dev_base_lock);

synchronize_rcu();

write_lock_bh(&dev_base_lock);
hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name));
netdev_name_node_add(net, dev->name_node);
write_unlock_bh(&dev_base_lock);

ret = call_netdevice_notifiers(NETDEV_CHANGENAME, dev);
Expand Down Expand Up @@ -8264,6 +8372,9 @@ static void rollback_registered_many(struct list_head *head)
dev_uc_flush(dev);
dev_mc_flush(dev);

netdev_name_node_alt_flush(dev);
netdev_name_node_free(dev->name_node);

if (dev->netdev_ops->ndo_uninit)
dev->netdev_ops->ndo_uninit(dev);

Expand Down Expand Up @@ -8706,6 +8817,10 @@ int register_netdevice(struct net_device *dev)
if (ret < 0)
goto out;

dev->name_node = netdev_name_node_head_alloc(dev);
if (!dev->name_node)
goto out;

/* Init, if this function is available */
if (dev->netdev_ops->ndo_init) {
ret = dev->netdev_ops->ndo_init(dev);
Expand Down Expand Up @@ -8827,6 +8942,8 @@ int register_netdevice(struct net_device *dev)
return ret;

err_uninit:
if (dev->name_node)
netdev_name_node_free(dev->name_node);
if (dev->netdev_ops->ndo_uninit)
dev->netdev_ops->ndo_uninit(dev);
if (dev->priv_destructor)
Expand Down
4 changes: 2 additions & 2 deletions net/core/net-procfs.c
Expand Up @@ -20,8 +20,8 @@ static inline struct net_device *dev_from_same_bucket(struct seq_file *seq, loff
struct hlist_head *h;
unsigned int count = 0, offset = get_offset(*pos);

h = &net->dev_name_head[get_bucket(*pos)];
hlist_for_each_entry_rcu(dev, h, name_hlist) {
h = &net->dev_index_head[get_bucket(*pos)];
hlist_for_each_entry_rcu(dev, h, index_hlist) {
if (++count == offset)
return dev;
}
Expand Down

0 comments on commit 7a56493

Please sign in to comment.