Containers that do not use the default `/sbin/init` entrypoint may lack in‑container network management. A previous commit already handles static IP addresses. Now this commit also handles DHCP. This is done using a `dhclient` process for each network interface.
Signed-off-by: Filip Schauer <f.scha...@proxmox.com> --- src/PVE/LXC.pm | 74 ++++++++++++++++++++++++++++++++++++++++--- src/PVE/LXC/Config.pm | 6 +++- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm index 0131ac3..e91b53a 100644 --- a/src/PVE/LXC.pm +++ b/src/PVE/LXC.pm @@ -1004,6 +1004,8 @@ sub vm_stop_cleanup { PVE::Storage::deactivate_volumes($storage_cfg, $vollist); }; warn $@ if $@; # avoid errors - just warn + + kill_dhclients($vmid, '*') if (PVE::LXC::Config->get_entrypoint($conf) ne "/sbin/init"); } sub net_tap_plug : prototype($$) { @@ -1189,6 +1191,34 @@ sub get_interfaces { return $res; } +sub manage_dhclient { + my ($action, $vmid, $ipversion, $eth, $rootdir) = @_; + + File::Path::make_path("/var/lib/lxc/$vmid/hook") if $action eq 'start'; + my $pidfile = "/var/lib/lxc/$vmid/hook/dhclient$ipversion-$eth.pid"; + my $leasefile = "/var/lib/lxc/$vmid/hook/dhclient$ipversion-$eth.leases"; + my $scriptfile = '/usr/share/lxc/hooks/dhclient-script'; + PVE::Tools::run_command([ + 'lxc-attach', '-n', $vmid, '-s', 'NETWORK|UTSNAME', '--', + 'aa-exec', '-p', 'unconfined', + '/sbin/dhclient', $action eq 'start' ? '-1' : '-r', "-$ipversion", + '-pf', $pidfile, '-lf', $leasefile, '-e', "ROOTFS=$rootdir", '-sf', $scriptfile, $eth + ]); +} + +sub kill_dhclients { + my ($vmid, $eth) = @_; + + foreach my $pidfile (glob("/var/lib/lxc/$vmid/hook/dhclient*-$eth.pid")) { + my $pid = eval { file_get_contents($pidfile) }; + if (!$@) { + chomp $pid; + kill 9, $pid if ($pid =~ m/^\d+$/); + unlink($pidfile); + } + } +} + sub update_ipconfig { my ($vmid, $conf, $opt, $eth, $newnet, $rootdir) = @_; @@ -1223,11 +1253,21 @@ sub update_ipconfig { # step 1: add new IP, if this fails we cancel my $is_real_ip = ($newip && $newip !~ /^(?:auto|dhcp|manual)$/); - if ($change_ip && $is_real_ip) { - eval { &$ipcmd($family_opt, 'addr', 'add', $newip, 'dev', $eth); }; - if (my $err = $@) { - warn $err; - return; + if ($change_ip) { + if (PVE::LXC::Config->get_entrypoint($conf) ne "/sbin/init") { + if ($newip && $newip eq 'dhcp') { + manage_dhclient('start', $vmid, $ipversion, $eth, $rootdir); + } elsif ($oldip && $oldip eq 'dhcp') { + manage_dhclient('stop', $vmid, $ipversion, $eth, $rootdir); + } + } + + if ($is_real_ip) { + eval { &$ipcmd($family_opt, 'addr', 'add', $newip, 'dev', $eth); }; + if (my $err = $@) { + warn $err; + return; + } } } @@ -2707,6 +2747,30 @@ sub vm_start { } PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start'); + my @dhcpv4_interfaces = (); + my @dhcpv6_interfaces = (); + foreach my $k (sort keys %$conf) { + next if $k !~ m/^net(\d+)$/; + my $d = PVE::LXC::Config->parse_lxc_network($conf->{$k}); + push @dhcpv4_interfaces, $d->{name} if $d->{ip} && $d->{ip} eq 'dhcp'; + push @dhcpv6_interfaces, $d->{name} if $d->{ip6} && $d->{ip6} eq 'dhcp'; + } + + my $pid = PVE::LXC::find_lxc_pid($vmid); + my $rootdir = "/proc/$pid/root"; + + if (PVE::LXC::Config->get_entrypoint($conf) ne "/sbin/init") { + foreach my $eth (@dhcpv4_interfaces) { + eval { manage_dhclient('start', $vmid, 4, $eth, $rootdir) }; + PVE::RESTEnvironment::log_warn("DHCP failed - $@") if $@; + } + + foreach my $eth (@dhcpv6_interfaces) { + eval { manage_dhclient('stop', $vmid, 6, $eth, $rootdir) }; + PVE::RESTEnvironment::log_warn("DHCP failed - $@") if $@; + } + } + return; } diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm index d7d8b6a..854e711 100644 --- a/src/PVE/LXC/Config.pm +++ b/src/PVE/LXC/Config.pm @@ -1490,9 +1490,13 @@ sub vmconfig_hotplug_pending { $cgroup->change_cpu_shares(undef); } elsif ($opt =~ m/^net(\d)$/) { my $netid = $1; + my $net = PVE::LXC::Config->parse_lxc_network($conf->{$opt}); + if (PVE::LXC::Config->get_entrypoint($conf) ne "/sbin/init") { + PVE::LXC::kill_dhclients($vmid, $net->{name}); + } + PVE::Network::veth_delete("veth${vmid}i$netid"); if ($have_sdn) { - my $net = PVE::LXC::Config->parse_lxc_network($conf->{$opt}); print "delete ips from $opt\n"; eval { PVE::Network::SDN::Vnets::del_ips_from_mac($net->{bridge}, $net->{hwaddr}, $conf->{hostname}) }; warn $@ if $@; -- 2.39.5 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel