]> git.proxmox.com Git - pve-container.git/commitdiff
LXC: more compact network configuration
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Wed, 1 Jul 2015 10:58:17 +0000 (12:58 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Thu, 2 Jul 2015 05:43:53 +0000 (07:43 +0200)
Deduplicated network setup code.
Using 'ip route replace' to replace or add the route.
This strategy can be rolled back safely:
1) add new ip (no harm done, old ip still exists)
2) replace route
  on error:
    Delete the new ip, old one is still in place.
    If deleting the new ip fails, it was already modified
    from within the container, so we only warn about it.
  on success do (3):
3) delete old ip
  New IP + gateway are in place, old IP can be deleted.
  If deletion fails, we only warn like in the error case.

src/PVE/LXC.pm

index 36c39957435e86d7b8d0f33c9fda8ecce6c37811..4bea2f6a4652aaadd3328b903aa7645d67b530ef 100644 (file)
@@ -1246,99 +1246,80 @@ sub update_ipconfig {
 
     my $lxc_setup = PVE::LXCSetup->new($conf, $rootdir);
 
-    my $update_gateway;
-    if (&$safe_string_ne($conf->{$opt}->{gw}, $newnet->{gw})) {
-
-       $update_gateway = 1;
-       if ($conf->{$opt}->{gw}) {
-           my $cmd = ['lxc-attach', '-n', $vmid, '-s', 'NETWORK', '--', '/sbin/ip', 'route', 'del', 'default', 'via', $conf->{$opt}->{gw} ];
-           eval { PVE::Tools::run_command($cmd); };
-           warn $@ if $@; # ignore errors here
-           delete $conf->{$opt}->{gw};
-           PVE::LXC::write_config($vmid, $conf);
-           $lxc_setup->setup_network($conf);
-       }
-    }
+    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);
+    };
 
-    if (&$safe_string_ne($conf->{$opt}->{ip}, $newnet->{ip})) {
+    my $change_ip_config = sub {
+       my ($family_opt, $suffix) = @_;
+       $suffix = '' if !$suffix;
+       my $gw= "gw$suffix";
+       my $ip= "ip$suffix";
 
-       if ($conf->{$opt}->{ip}) {
-           my $cmd = ['lxc-attach', '-n', $vmid, '-s', 'NETWORK', '--', '/sbin/ip', 'addr', 'del', $conf->{$opt}->{ip}, 'dev', $eth  ];
-           eval { PVE::Tools::run_command($cmd); };
-           warn $@ if $@; # ignore errors here
-           delete $conf->{$opt}->{ip};
-           PVE::LXC::write_config($vmid, $conf);
-           $lxc_setup->setup_network($conf);
-       }
+       my $change_ip = &$safe_string_ne($optdata->{$ip}, $newnet->{$ip});
+       my $change_gw = &$safe_string_ne($optdata->{$gw}, $newnet->{$gw});
 
-       if ($newnet->{ip}) {
-           my $cmd = ['lxc-attach', '-n', $vmid, '-s', 'NETWORK', '--', '/sbin/ip', 'addr', 'add', $newnet->{ip}, 'dev', $eth  ];
-           PVE::Tools::run_command($cmd);
+       return if !$change_ip && !$change_gw;
 
-           $conf->{$opt}->{ip} = $newnet->{ip};
-           PVE::LXC::write_config($vmid, $conf);
-           $lxc_setup->setup_network($conf);
+       # step 1: add new IP, if this fails we cancel
+       if ($change_ip && $newnet->{$ip}) {
+           eval { &$netcmd($family_opt, 'addr', 'add', $newnet->{$ip}, 'dev', $eth); };
+           if (my $err = $@) {
+               warn $err;
+               return;
+           }
        }
-    }
-
-    if ($update_gateway) {
-
-       if ($newnet->{gw}) {
-           my $cmd = ['lxc-attach', '-n', $vmid, '-s', 'NETWORK', '--', '/sbin/ip', 'route', 'add', 'default', 'via', $newnet->{gw} ];
-           PVE::Tools::run_command($cmd);
 
-           $conf->{$opt}->{gw} = $newnet->{gw};
-           PVE::LXC::write_config($vmid, $conf);
-           $lxc_setup->setup_network($conf);
-        }
-    }
-
-    my $update_gateway6;
-    if (&$safe_string_ne($conf->{$opt}->{gw6}, $newnet->{gw6})) {
-       
-       $update_gateway6 = 1;
-       if ($conf->{$opt}->{gw6}) {
-           my $cmd = ['lxc-attach', '-n', $vmid, '-s', 'NETWORK', '--', '/sbin/ip', 'route', 'del', 'default', 'via', $conf->{$opt}->{gw6} ];
-           eval { PVE::Tools::run_command($cmd); };
-           warn $@ if $@; # ignore errors here
-           delete $conf->{$opt}->{gw6};
-           PVE::LXC::write_config($vmid, $conf);
-           $lxc_setup->setup_network($conf);
+       # step 2: replace gateway
+       #   If this fails we delete the added IP and cancel.
+       #   If it succeeds we save the config and delete the old IP, ignoring
+       #   errors. The config is then saved.
+       # Note: 'ip route replace' can add
+       if ($change_gw) {
+           if ($newnet->{$gw}) {
+               eval { &$netcmd($family_opt, 'route', 'replace', 'default', 'via', $newnet->{$gw}); };
+               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', $newnet->{$ip}, 'dev', $eth); };
+                       warn $@ if $@; # no need to die here
+                   }
+                   return;
+               }
+           } else {
+               eval { &$netcmd($family_opt, 'route', 'del', 'default'); };
+               # if the route was not deleted, the guest might have deleted it manually
+               # warn and continue
+               warn $@ if $@;
+           }
        }
-    }
 
-    if (&$safe_string_ne($conf->{$opt}->{ip6}, $newnet->{ip6})) {
-
-       if ($conf->{$opt}->{ip6}) {
-           my $cmd = ['lxc-attach', '-n', $vmid, '-s', 'NETWORK', '--', '/sbin/ip', 'addr', 'del', $conf->{$opt}->{ip6}, 'dev', $eth  ];
-           eval { PVE::Tools::run_command($cmd); };
-           warn $@ if $@; # ignore errors here
-           delete $conf->{$opt}->{ip6};
-           PVE::LXC::write_config($vmid, $conf);
-           $lxc_setup->setup_network($conf);
+       # from this point on we safe the configuration
+       # step 3: delete old IP ignoring errors
+       if ($change_ip && $optdata->{$ip}) {
+           eval { &$netcmd($family_opt, 'addr', 'del', $optdata->{$ip}, 'dev', $eth); };
+           warn $@ if $@; # no need to die here
        }
 
-       if ($newnet->{ip6}) {
-           my $cmd = ['lxc-attach', '-n', $vmid, '-s', 'NETWORK', '--', '/sbin/ip', 'addr', 'add', $newnet->{ip6}, 'dev', $eth  ];
-           PVE::Tools::run_command($cmd);
-
-           $conf->{$opt}->{ip6} = $newnet->{ip6};
-           PVE::LXC::write_config($vmid, $conf);
-           $lxc_setup->setup_network($conf);
+       foreach my $property ($ip, $gw) {
+           if ($newnet->{$property}) {
+               $optdata->{$property} = $newnet->{$property};
+           } else {
+               delete $optdata->{$property};
+           }
        }
-    }
-
-    if ($update_gateway6) {
-
-       if ($newnet->{gw6}) {
-           my $cmd = ['lxc-attach', '-n', $vmid, '-s', 'NETWORK', '--', '/sbin/ip', 'route', 'add', 'default', 'via', $newnet->{gw6} ];
-           PVE::Tools::run_command($cmd);
+       PVE::LXC::write_config($vmid, $conf);
+       $lxc_setup->setup_network($conf);
+    };
 
-           $conf->{$opt}->{gw6} = $newnet->{gw6};
-           PVE::LXC::write_config($vmid, $conf);
-           $lxc_setup->setup_network($conf);
-        }
-    }
+    &$change_ip_config('-4');
+    &$change_ip_config('-6', '6');
 }
 
 1;