While the previous strategy was enough for ipv6, ipv4 has
the concept of primary and secondary addresses (and
permanent, deprecated, ...), and so adding additional ip
addresses marked them as 'secondary'. The side effect of
this is that deleting the primary ip deletes all other ip
addresses within the same subnet. To avoid this we need to
temporarily set /proc/sys/net/ipv4/conf/promote_secondaries
to 1 before deleting the old IP address.
---
 src/PVE/LXC.pm | 31 +++++++++++++++++++++++--------
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm
index 98b73be..bea70cc 100644
--- a/src/PVE/LXC.pm
+++ b/src/PVE/LXC.pm
@@ -1356,10 +1356,11 @@ sub update_ipconfig {
     my $optdata = $conf->{$opt};
     my $deleted = [];
     my $added = [];
-    my $netcmd = sub {
-       my $cmd = ['lxc-attach', '-n', $vmid, '-s', 'NETWORK', '--', 
'/sbin/ip', @_];
-       PVE::Tools::run_command($cmd);
+    my $nscmd = sub {
+       my $cmdargs = shift;
+       PVE::Tools::run_command(['lxc-attach', '-n', $vmid, '-s', 'NETWORK', 
'--', @_], %$cmdargs);
     };
+    my $ipcmd = sub { &$nscmd({}, '/sbin/ip', @_) };
 
     my $change_ip_config = sub {
        my ($ipversion) = @_;
@@ -1380,7 +1381,7 @@ sub update_ipconfig {
 
        # step 1: add new IP, if this fails we cancel
        if ($change_ip && $newip && $newip !~ /^(?:auto|dhcp)$/) {
-           eval { &$netcmd($family_opt, 'addr', 'add', $newip, 'dev', $eth); };
+           eval { &$ipcmd($family_opt, 'addr', 'add', $newip, 'dev', $eth); };
            if (my $err = $@) {
                warn $err;
                return;
@@ -1394,19 +1395,19 @@ sub update_ipconfig {
        # Note: 'ip route replace' can add
        if ($change_gw) {
            if ($newgw) {
-               eval { &$netcmd($family_opt, 'route', 'replace', 'default', 
'via', $newgw); };
+               eval { &$ipcmd($family_opt, 'route', 'replace', 'default', 
'via', $newgw); };
                if (my $err = $@) {
                    warn $err;
                    # the route was not replaced, the old IP is still available
                    # rollback (delete new IP) and cancel
                    if ($change_ip) {
-                       eval { &$netcmd($family_opt, 'addr', 'del', $newip, 
'dev', $eth); };
+                       eval { &$ipcmd($family_opt, 'addr', 'del', $newip, 
'dev', $eth); };
                        warn $@ if $@; # no need to die here
                    }
                    return;
                }
            } else {
-               eval { &$netcmd($family_opt, 'route', 'del', 'default'); };
+               eval { &$ipcmd($family_opt, 'route', 'del', 'default'); };
                # if the route was not deleted, the guest might have deleted it 
manually
                # warn and continue
                warn $@ if $@;
@@ -1416,8 +1417,22 @@ sub update_ipconfig {
        # from this point on we save the configuration
        # step 3: delete old IP ignoring errors
        if ($change_ip && $oldip && $oldip !~ /^(?:auto|dhcp)$/) {
-           eval { &$netcmd($family_opt, 'addr', 'del', $oldip, 'dev', $eth); };
+           # We need to enable promote_secondaries, otherwise our newly added
+           # address will be removed along with the old one.
+           my $promote = 0;
+           eval {
+               if ($ipversion == 4) {
+                   &$nscmd({ outfunc => sub { $promote = int(shift) } },
+                           'cat', 
"/proc/sys/net/ipv4/conf/$eth/promote_secondaries");
+                   &$nscmd({}, 'sysctl', 
"net.ipv4.conf.$eth.promote_secondaries=1");
+               }
+               &$ipcmd($family_opt, 'addr', 'del', $oldip, 'dev', $eth);
+           };
            warn $@ if $@; # no need to die here
+
+           if ($ipversion == 4) {
+               &$nscmd({}, 'sysctl', 
"net.ipv4.conf.$eth.promote_secondaries=$promote");
+           }
        }
 
        foreach my $property ($ip, $gw) {
-- 
2.1.4


_______________________________________________
pve-devel mailing list
pve-devel@pve.proxmox.com
http://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to