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

Igor Vlasenko ivlasenko at gmail.com
Wed May 11 21:56:01 CEST 2016


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.
The resulting regex is large, so it is wrapped as a common subroutine.

Signed-off-by: Igor Vlasenko <viy at altlinux.org>
---
 src/Makefile                |  1 +
 src/PVE/INotify.pm          | 10 +++++----
 src/PVE/Network.pm          |  7 +++++--
 src/PVE/NetworkInterface.pm | 49 +++++++++++++++++++++++++++++++++++++++++++++
 src/PVE/Tools.pm            | 11 ++++++++++
 5 files changed, 72 insertions(+), 6 deletions(-)
 create mode 100644 src/PVE/NetworkInterface.pm

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/NetworkInterface.pm b/src/PVE/NetworkInterface.pm
new file mode 100644
index 0000000..1c7dcc5
--- /dev/null
+++ b/src/PVE/NetworkInterface.pm
@@ -0,0 +1,49 @@
+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;
+}
+
+__END__
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) = @_;

-- 
2.6.5



More information about the pve-devel mailing list