]> git.proxmox.com Git - pve-common.git/blobdiff - src/PVE/INotify.pm
network_interfaces: use allow-ovs for OVSBridge
[pve-common.git] / src / PVE / INotify.pm
index c52d99255c98d93e474e9a93f5e7621d99c25b71..b3e5ab05fd22763f63c6dd51798fa2273b7a9dde 100644 (file)
@@ -16,6 +16,7 @@ use PVE::Exception qw(raise_param_exc);
 use PVE::Network;
 use PVE::Tools;
 use PVE::ProcFSTools;
+use PVE::JSONSchema;
 use Clone qw(clone);
 use Linux::Inotify2;
 use base 'Exporter';
@@ -83,15 +84,15 @@ sub ccache_info {
                    $cp->{$k} = $v;
                }
                $ccache->{$filename} = $cp;
-           } 
+           }
            return ($ccache->{$filename}, $filename);
        }
     }
+
     $filename = $ccachemap->{$filename} if defined ($ccachemap->{$filename});
 
     die "file '$filename' not added :ERROR" if !defined ($ccache->{$filename});
-   
+
     return ($ccache->{$filename}, $filename);
 }
 
@@ -134,7 +135,7 @@ sub write_file {
     if (!rename($tmpname, $realname)) {
        my $msg = "close (rename) atomic file '$filename' failed: $!\n";
        unlink $tmpname;
-       die $msg;       
+       die $msg;
     }
 
     my $diff;
@@ -167,7 +168,7 @@ sub update_file {
     my $code = sub {
 
        $fd = IO::File->new ($filename, "r");
-       
+
        my $new = &$update($filename, $fd, $data, @args);
 
        if (defined($new)) {
@@ -215,9 +216,9 @@ sub read_file {
     my $parser;
 
     my ($ccinfo, $filename) = ccache_info($fileid);
-     
+
     $parser = $ccinfo->{parser};
+
     my $fd;
     my $shadow;
 
@@ -237,7 +238,7 @@ sub read_file {
 
     if (!$fd) {
        $ccinfo->{version} = undef;
-       $ccinfo->{data} = undef; 
+       $ccinfo->{data} = undef;
        $ccinfo->{diff} = undef;
        return undef if !$acp;
     }
@@ -259,7 +260,7 @@ sub read_file {
            $ret->{data} = $ccinfo->{data};
        }
        $ret->{changes} = $ccinfo->{diff};
-       
+
        return $full ? $ret : $ret->{data};
     }
 
@@ -292,7 +293,7 @@ sub read_file {
     $ret->{changes} = $ccinfo->{diff};
 
     return $full ? $ret : $ret->{data};
-}    
+}
 
 sub parse_ccache_options {
     my ($ccinfo, %options) = @_;
@@ -336,7 +337,7 @@ sub register_file {
     $ccinfo->{update} = $update;
 
     parse_ccache_options($ccinfo, %options);
-    
+
     if ($options{shadow}) {
        $shadowfiles->{$filename} = $options{shadow};
     }
@@ -352,7 +353,7 @@ sub register_regex {
 
     my $uid = "$dir/$regex";
     die "regular expression '$uid' already added :ERROR" if defined ($ccacheregex->{$uid});
+
     my $ccinfo = {};
 
     $ccinfo->{dir} = $dir;
@@ -416,7 +417,7 @@ sub inotify_init {
 
     foreach my $uid (keys %$ccacheregex) {
        my $ccinfo = $ccacheregex->{$uid};
-       $dirhash->{$ccinfo->{dir}}->{_regex} = 1;       
+       $dirhash->{$ccinfo->{dir}}->{_regex} = 1;
     }
 
     $inotify_pid = $$;
@@ -446,7 +447,7 @@ sub inotify_init {
                syslog ('err', "got 'unmount' event on '$name' - disabling inotify");
                $inotify = undef;
            }
-           if ($e->IN_IGNORED) { 
+           if ($e->IN_IGNORED) {
                syslog ('err', "got 'ignored' event on '$name' - disabling inotify");
                $inotify = undef;
            }
@@ -479,7 +480,7 @@ sub inotify_init {
                    next if $dir ne $ccinfo->{dir};
                    my $re = $ccinfo->{regex};
                    if (my $fd = IO::Dir->new ($dir)) {
-                       while (defined(my $de = $fd->read)) { 
+                       while (defined(my $de = $fd->read)) {
                            if ($de =~ m/^$re$/) {
                                my $fn = "$dir/$de";
                                $versions->{$fn}++; # init with version
@@ -534,8 +535,8 @@ sub write_etc_hostname {
     return $hostname;
 }
 
-register_file('hostname', "/etc/hostname",  
-             \&read_etc_hostname, 
+register_file('hostname', "/etc/hostname",
+             \&read_etc_hostname,
              \&write_etc_hostname);
 
 sub read_etc_hosts {
@@ -628,12 +629,12 @@ sub update_etc_resolv_conf {
        next if $line =~ m/^(search|domain|nameserver)\s+/;
        $data .= $line
     }
-    
+
     return $data;
 }
 
-register_file('resolvconf', "/etc/resolv.conf", 
-             \&read_etc_resolv_conf, undef, 
+register_file('resolvconf', "/etc/resolv.conf",
+             \&read_etc_resolv_conf, undef,
              \&update_etc_resolv_conf);
 
 sub read_etc_timezone {
@@ -663,8 +664,8 @@ sub write_etc_timezone {
 
 }
 
-register_file('timezone', "/etc/timezone", 
-             \&read_etc_timezone, 
+register_file('timezone', "/etc/timezone",
+             \&read_etc_timezone,
              \&write_etc_timezone);
 
 sub read_active_workers {
@@ -672,7 +673,7 @@ sub read_active_workers {
 
     return [] if !$fh;
 
-    my $res = []; 
+    my $res = [];
     while (defined (my $line = <$fh>)) {
        if ($line =~ m/^(\S+)\s(0|1)(\s([0-9A-Za-z]{8})(\s(\s*\S.*))?)?$/) {
            my $upid = $1;
@@ -716,7 +717,7 @@ sub write_active_workers {
     PVE::Tools::safe_print($filename, $fh, $raw) if $raw;
 }
 
-register_file('active', "/var/log/pve/tasks/active", 
+register_file('active', "/var/log/pve/tasks/active",
              \&read_active_workers,
              \&write_active_workers);
 
@@ -734,7 +735,7 @@ my $ovs_bond_modes = {
     'active-backup' => 1,
     'balance-slb' => 1,
     'lacp-balance-slb' => 1,
-    'lacp-balance-tcp' => 1, 
+    'lacp-balance-tcp' => 1,
 };
 
 #sub get_bond_modes {
@@ -895,12 +896,12 @@ sub __read_etc_network_interfaces {
     }
 
     # we try to keep order inside the file
-    my $priority = 2; # 1 is reserved for lo 
+    my $priority = 2; # 1 is reserved for lo
 
     SECTION: while (defined ($line = <$fh>)) {
        chomp ($line);
        next if $line =~ m/^\s*#/;
+
        if ($line =~ m/^\s*auto\s+(.*)$/) {
            my @aa = split (/\s+/, $1);
 
@@ -954,6 +955,7 @@ sub __read_etc_network_interfaces {
                        'bridge-multicast-flood' => 1,
                        'bond_miimon' => 1,
                        'bond_xmit_hash_policy' => 1,
+                       'uplink-id' => 1,
                        'vlan-protocol' => 1,
                        'vxlan-id' => 1,
                        'vxlan-svcnodeip' => 1,
@@ -1103,6 +1105,33 @@ sub __read_etc_network_interfaces {
            }
        }
 
+       # map address and netmask to cidr
+       if ($d->{address}) {
+           if ($d->{netmask} && $d->{netmask} =~ m/^\d+$/) { # e.g. netmask 20
+               $d->{cidr} = $d->{address} . "/" . $d->{netmask};
+           } elsif ($d->{netmask} &&
+                    (my $cidr = PVE::JSONSchema::get_netmask_bits($d->{netmask}))) { # e.g. netmask 255.255.255.0
+               $d->{cidr} = $d->{address} . "/" . $cidr;
+           } elsif ($d->{address} =~ m!^(.*)/(\d+)$!) {
+               $d->{cidr} = $d->{address};
+               $d->{address} = $1;
+               $d->{netmask} = $2;
+           } else {
+               $d->{cidr} = $d->{address};
+           }
+       }
+
+       # map address6 and netmask6 to cidr6
+       if ($d->{address6}) {
+           $d->{cidr6} = $d->{address6};
+           if ($d->{netmask6}) {
+               $d->{cidr6} .= "/" . $d->{netmask6};
+           } elsif ($d->{address6} =~ m!^(.*)/(\d+)$!) {
+               $d->{address6} = $1;
+               $d->{netmask6} = $2;
+           }
+       }
+
        $d->{method} = 'manual' if !$d->{method};
        $d->{method6} = 'manual' if !$d->{method6};
 
@@ -1113,7 +1142,9 @@ sub __read_etc_network_interfaces {
     # from the {options} hash for them to be removed correctly.
     @$options = grep {defined($_)} map {
        my ($pri, $line) = @$_;
-       if ($line =~ /^allow-(\S+)\s+(.*)$/) {
+       if ($line =~ /^allow-ovs\s+(.*)$/) {
+           undef;
+       } elsif ($line =~ /^allow-(\S+)\s+(.*)$/) {
            my $bridge = $1;
            my @ports = split(/\s+/, $2);
            if (defined(my $br = $ifaces->{$bridge})) {
@@ -1155,7 +1186,7 @@ sub __interface_to_string {
                 comments => 1, autostart => 1, options => 1,
                 address => 1, netmask => 1, gateway => 1, broadcast => 1,
                 method6 => 1, families => 1, options6 => 1,
-                address6 => 1, netmask6 => 1, gateway6 => 1, broadcast6 => 1 };
+                address6 => 1, netmask6 => 1, gateway6 => 1, broadcast6 => 1, 'uplink-id' => 1 };
 
     if (!$first_block) {
        # not printing out options
@@ -1181,7 +1212,7 @@ sub __interface_to_string {
        }
        $done->{bridge_vlan_aware} = 1;
        $done->{bridge_vids} = 1;
-    
+
     } elsif ($d->{type} eq 'bond') {
 
        $d->{slaves} =~ s/[;,\s]+/ /g;
@@ -1203,9 +1234,9 @@ sub __interface_to_string {
        }
        $done->{'bond_xmit_hash_policy'} = 1;
     } elsif ($d->{type} eq 'vlan') {
-       die "$iface: wrong vlan-protocol $d->{'vlan-protocol'}\n" 
+       die "$iface: wrong vlan-protocol $d->{'vlan-protocol'}\n"
            if $d->{'vlan-protocol'} && $d->{'vlan-protocol'} ne '802.1ad' && $d->{'vlan-protocol'} ne '802.1q';
-       
+
     } elsif ($d->{type} eq 'vxlan') {
 
        foreach my $k (qw(vxlan-id vxlan-svcnodeip vxlan-physdev vxlan-local-tunnelip)) {
@@ -1225,6 +1256,7 @@ sub __interface_to_string {
        $done->{ovs_type} = 1;
 
        $raw .= "\tovs_ports $d->{ovs_ports}\n" if $d->{ovs_ports};
+
        $done->{ovs_ports} = 1;
     } elsif ($d->{type} eq 'OVSPort' || $d->{type} eq 'OVSIntPort' ||
             $d->{type} eq 'OVSBond') {
@@ -1264,12 +1296,7 @@ sub __interface_to_string {
 
        if ($d->{ovs_bridge}) {
 
-           if ($ifupdown2) {
-               $raw = "auto $iface\n$raw";
-           } else {
-               $raw = "allow-$d->{ovs_bridge} $iface\n$raw";
-           }
-
+           $raw = "allow-$d->{ovs_bridge} $iface\n$raw";
            $raw .= "\tovs_bridge $d->{ovs_bridge}\n";
            $done->{ovs_bridge} = 1;
        }
@@ -1317,6 +1344,9 @@ sub __write_etc_network_interfaces {
     foreach my $iface (keys %$ifaces) {
        my $d = $ifaces->{$iface};
 
+       delete $d->{cidr};
+       delete $d->{cidr6};
+
        my $ports = '';
        foreach my $k (qw(bridge_ports ovs_ports slaves ovs_bonds)) {
            $ports .= " $d->{$k}" if $d->{$k};
@@ -1456,6 +1486,21 @@ sub __write_etc_network_interfaces {
        }
     }
 
+    # check uplink
+    my $uplinks = {};
+    foreach my $iface (keys %$ifaces) {
+       my $d = $ifaces->{$iface};
+       if (my $uplinkid = $d->{'uplink-id'}) {
+           die "iface '$iface' - uplink-id $uplinkid is only allowed on physical and linux bond interfaces\n"
+               if $d->{type} ne 'eth' && $d->{type} ne 'bond';
+
+           die "iface '$iface' - uplink-id $uplinkid is already assigned on '$uplinks->{$uplinkid}'\n"
+               if $uplinks->{$uplinkid};
+
+           $uplinks->{$uplinkid} = $iface;
+       }
+    }
+
     # check bridgeport option
     my $bridgeports = {};
     my $bridges = {};
@@ -1545,7 +1590,6 @@ NETWORKDOC
        return $a cmp $b;
     } keys %$ifaces) {
        next if $printed->{$iface};
-
        my $d = $ifaces->{$iface};
        my $pri = $d->{priority} // 0;
        if (@options && $options[0]->[0] < $pri) {
@@ -1556,7 +1600,12 @@ NETWORKDOC
        }
 
        $printed->{$iface} = 1;
-       $raw .= "auto $iface\n" if $d->{autostart};
+        if ($d->{type} eq 'OVSBridge') {
+           $raw .= "allow-ovs $iface\n";
+       } elsif ($d->{autostart}) {
+           $raw .= "auto $iface\n" if $d->{autostart};
+       }
+
        my $i = 0; # some options should be printed only once
        $raw .= __interface_to_string($iface, $d, $_, !$i++, $ifupdown2) foreach @{$d->{families}};
     }
@@ -1582,7 +1631,7 @@ sub read_iscsi_initiatorname {
     return 'undefined';
 }
 
-register_file('initiatorname', "/etc/iscsi/initiatorname.iscsi",  
+register_file('initiatorname', "/etc/iscsi/initiatorname.iscsi",
              \&read_iscsi_initiatorname);
 
 sub read_apt_auth {
@@ -1594,7 +1643,7 @@ sub read_apt_auth {
 
     $raw =~ s/^\s+//;
 
+
     my @tokens = split(/\s+/, $raw);
 
     my $data = {};
@@ -1635,7 +1684,7 @@ sub write_apt_auth {
     my $raw = &$format_apt_auth_data($data);
 
     die "write failed: $!" unless print $fh "$raw\n";
-   
+
     return $data;
 }
 
@@ -1651,7 +1700,7 @@ sub update_apt_auth {
     return &$format_apt_auth_data($orig);
 }
 
-register_file('apt-auth', "/etc/apt/auth.conf",  
+register_file('apt-auth', "/etc/apt/auth.conf",
              \&read_apt_auth, \&write_apt_auth,
              \&update_apt_auth, perm => 0640);