[pve-devel] [PATCH common] support for predictable network interface device names

Igor Vlasenko ivlasenko at gmail.com
Thu May 12 10:42:29 CEST 2016


On Wed, May 11, 2016 at 10:56 PM, Igor Vlasenko <ivlasenko at gmail.com> wrote:
> This is an improved version of my previous patch
> [ support for udev-style physical interface names (like enp3s0),
>  http://pve.proxmox.com/pipermail/pve-devel/2016-May/020958.html ]
> thanks to Wolfgang.

Yesterday I finished coding just before going to sleep, so I was a bit
muddleheaded and
left a few mistakes :( Here I fixed them and added a test case to verify.


Signed-off-by: Igor Vlasenko <viy at altlinux.org>
---
 src/Makefile                                       |  1 +
 src/PVE/INotify.pm                                 | 10 +++--
 src/PVE/Network.pm                                 |  7 ++-
 src/PVE/NetworkInterfaces.pm                       | 50 ++++++++++++++++++++++
 src/PVE/Tools.pm                                   | 11 +++++
 .../t.is_physical_interface.pl                     | 50 ++++++++++++++++++++++
 6 files changed, 123 insertions(+), 6 deletions(-)
 create mode 100644 src/PVE/NetworkInterfaces.pm
 create mode 100644 test/etc_network_interfaces/t.is_physical_interface.pl

diff --git a/src/Makefile b/src/Makefile
index a07e2e4..02265e0 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -10,6 +10,7 @@ LIB_SOURCES=            \
     Daemon.pm        \
     SectionConfig.pm    \
     Network.pm        \
+    NetworkInterfaces.pm    \
     ProcFSTools.pm        \
     CLIHandler.pm        \
     RESTHandler.pm        \
diff --git a/src/PVE/INotify.pm b/src/PVE/INotify.pm
index 74a0fe1..ce83c16 100644
--- a/src/PVE/INotify.pm
+++ b/src/PVE/INotify.pm
@@ -14,6 +14,7 @@ use Fcntl qw(:DEFAULT :flock);
 use PVE::SafeSyslog;
 use PVE::Exception qw(raise_param_exc);
 use PVE::Tools;
+use PVE::NetworkInterfaces;
 use Storable qw(dclone);
 use Linux::Inotify2;
 use base 'Exporter';
@@ -800,7 +801,8 @@ sub __read_etc_network_interfaces {

     if ($proc_net_dev) {
     while (defined ($line = <$proc_net_dev>)) {
-        if ($line =~ m/^\s*(eth\d+):.*/) {
+        if ($line =~ m/^\s*([^:]+):.*/
+        and PVE::NetworkInterfaces::is_physical_interface($1)) {
         $ifaces->{$1}->{exists} = 1;
         }
     }
@@ -973,7 +975,7 @@ sub __read_etc_network_interfaces {
         $ifaces->{$1}->{exists} = 0;
         $d->{exists} = 0;
         }
-    } elsif ($iface =~ m/^eth\d+$/) {
+    } elsif (PVE::NetworkInterfaces::is_physical_interface($iface)) {
         if (!$d->{ovs_type}) {
         $d->{type} = 'eth';
         } elsif ($d->{ovs_type} eq 'OVSPort') {
@@ -1200,7 +1202,7 @@ sub __write_etc_network_interfaces {
         $d->{type} eq 'OVSBond') {
         my $brname = $used_ports->{$iface};
         if (!$brname || !$ifaces->{$brname}) {
-        if ($iface =~ /^eth/) {
+        if (PVE::NetworkInterfaces::is_physical_interface($iface)) {
             $ifaces->{$iface} = { type => 'eth',
                       exists => 1,
                       method => 'manual',
@@ -1289,7 +1291,7 @@ NETWORKDOC
     my $pri;
     if ($iface eq 'lo') {
         $pri = $if_type_hash->{loopback};
-    } elsif ($iface =~ m/^eth\d+$/) {
+    } elsif (PVE::NetworkInterfaces::is_physical_interface($iface)) {
         $pri = $if_type_hash->{eth} + $child;
     } elsif ($iface =~ m/^bond\d+$/) {
         $pri = $if_type_hash->{bond} + $child;
diff --git a/src/PVE/Network.pm b/src/PVE/Network.pm
index be26132..1d15990 100644
--- a/src/PVE/Network.pm
+++ b/src/PVE/Network.pm
@@ -4,6 +4,7 @@ use strict;
 use warnings;
 use PVE::Tools qw(run_command);
 use PVE::ProcFSTools;
+use PVE::NetworkInterfaces;
 use PVE::INotify;
 use File::Basename;
 use IO::Socket::IP;
@@ -440,8 +441,10 @@ sub activate_bridge_vlan {

     my @ifaces = ();
     my $dir = "/sys/class/net/$bridge/brif";
-    PVE::Tools::dir_glob_foreach($dir, '((eth|bond)\d+(\.\d+)?)', sub {
-        push @ifaces, $_[0];
+    PVE::Tools::dir_lambda_foreach($dir, sub {
+    push @ifaces, $_[0] if $_[0] =~ /^(?:bond|eth)\d+(\.\d+)?/
+        or PVE::NetworkInterfaces::is_physical_interface($_[0]);
+    }
     });

     die "no physical interface on bridge '$bridge'\n" if scalar(@ifaces) == 0;
diff --git a/src/PVE/NetworkInterfaces.pm b/src/PVE/NetworkInterfaces.pm
new file mode 100644
index 0000000..80daf31
--- /dev/null
+++ b/src/PVE/NetworkInterfaces.pm
@@ -0,0 +1,50 @@
+package PVE::NetworkInterfaces;
+
+use strict;
+use warnings;
+
+# alternatively, on the linux kernel we can readlink /sys/class/net/$iface
+# and check whether it points to ../../devices/virtual/...
+
+# physical network interface pattern matching.
+# matching for predictable network interface device names is based on
+# https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-net_id.c
+# http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
+sub is_physical_interface {
+    my ($iface) = @_;
+    return $iface =~
+    /^(?:
+    # legacy interface names
+    eth\d+
+
+    | # predictable network interface device names
+
+    # two character prefixes:
+    # en — Ethernet
+    # sl — serial line IP (slip)
+    # wl — wlan
+    # ww — wwan
+    (?:en|sl|wl|ww)
+
+    # type of names:
+    (?:
+    # b<number> — BCMA bus core number
+      b\d+
+    # c<bus_id> — CCW bus group name, without leading zeros [s390]
+    | c\d+
+    # o<index>[d<dev_port>] — on-board device index number
+    | o\d+(?:d\d+)?
+    # s<slot>[f<function>][d<dev_port>] — hotplug slot index number
+    | s\d+(?:f\d+)?(?:d\d+)?
+    # x<MAC> — MAC address
+    | x[\da-f]{12}
+    # [P<domain>]p<bus>s<slot>[f<function>][d<dev_port>] — PCI
geographical location
+    | (?:P\d+)?p\d+s\d+(?:f\d+)?(?:d\d+)?
+    # [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
— USB port number chain
+    | (?:P\d+)?p\d+s\d+(?:f\d+)?(?:u\d+)*(?:c\d+)?(?:i\d+)?
+    )
+    )$/x;
+}
+
+1;
+
diff --git a/src/PVE/Tools.pm b/src/PVE/Tools.pm
index 8c7f373..24f0567 100644
--- a/src/PVE/Tools.pm
+++ b/src/PVE/Tools.pm
@@ -1125,6 +1125,17 @@ sub dir_glob_foreach {
     }
 }

+sub dir_lambda_foreach {
+    my ($dir, $func) = @_;
+
+    my $dh = IO::Dir->new ($dir);
+    if (defined $dh) {
+    while (defined(my $tmp = $dh->read)) {
+        &$func ($tmp);
+    }
+    }
+}
+
 sub assert_if_modified {
     my ($digest1, $digest2) = @_;

diff --git a/test/etc_network_interfaces/t.is_physical_interface.pl
b/test/etc_network_interfaces/t.is_physical_interface.pl
new file mode 100644
index 0000000..4518feb
--- /dev/null
+++ b/test/etc_network_interfaces/t.is_physical_interface.pl
@@ -0,0 +1,50 @@
+use lib '../../src';
+use PVE::NetworkInterfaces;
+
+map {die if PVE::NetworkInterfaces::is_physical_interface($_)} qw/
+wlan0 tap8 testiface4 br0 bond3
+/;
+
+map {die if! PVE::NetworkInterfaces::is_physical_interface($_)} qw/
+eth3 eno1 enp5s0 ens1 enx78e7d1ea46da enx000000000466 enp2s0f0
+enp2s0f1 wlx0024d7e31130 wlp3s0 wwx028037ec0200 wwp0s29u1u4i6
+enxd626b3450fb5 enp0s29u1u2
+/;
+
+
+1;
+
+__END__
+ * PCI Ethernet card with firmware index "1":
+ *   ID_NET_NAME_ONBOARD=eno1
+ *   ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
+ *
+ * PCI Ethernet card in hotplug slot with firmware index number:
+ *   /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
+ *   ID_NET_NAME_MAC=enx000000000466
+ *   ID_NET_NAME_PATH=enp5s0
+ *   ID_NET_NAME_SLOT=ens1
+ *
+ * PCI Ethernet multi-function card with 2 ports:
+ *   /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
+ *   ID_NET_NAME_MAC=enx78e7d1ea46da
+ *   ID_NET_NAME_PATH=enp2s0f0
+ *   /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1
+ *   ID_NET_NAME_MAC=enx78e7d1ea46dc
+ *   ID_NET_NAME_PATH=enp2s0f1
+ *
+ * PCI wlan card:
+ *   /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
+ *   ID_NET_NAME_MAC=wlx0024d7e31130
+ *   ID_NET_NAME_PATH=wlp3s0
+ *
+ * USB built-in 3G modem:
+ *   /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
+ *   ID_NET_NAME_MAC=wwx028037ec0200
+ *   ID_NET_NAME_PATH=wwp0s29u1u4i6
+ *
+ * USB Android phone:
+ *   /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
+ *   ID_NET_NAME_MAC=enxd626b3450fb5
+ *   ID_NET_NAME_PATH=enp0s29u1u2
+ */
-- 
2.6.5



More information about the pve-devel mailing list