[pve-devel] [PATCH 2/2] setup DHCP server at vm_start

Alexandre DERUMIER aderumier at odiso.com
Tue Sep 3 04:10:18 CEST 2013


+ # fixme: howto pass gateway for that pool 
--dhcp-option='option:router,192.168.2.1'

+ # fixme: howto pass additional dhcp options 
+ 
--dhcp-option='option:optionnumber,optionvalue'



I'm thinking if restarting the dnsmasq daemon at each vm start is good ?
(what happen if multiple vm stop/start at same time, can we loose some dhcp requests?)

Maybe can we restart it only if ressources changes (ip pool, range).
and use dhcp-script option to give leases without need to restart daemon ?


----- Mail original ----- 

De: "Dietmar Maurer" <dietmar at proxmox.com> 
À: pve-devel at pve.proxmox.com 
Envoyé: Lundi 2 Septembre 2013 10:11:12 
Objet: [pve-devel] [PATCH 2/2] setup DHCP server at vm_start 


Signed-off-by: Dietmar Maurer <dietmar at proxmox.com> 
--- 
PVE/DHCP.pm | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 
PVE/Makefile | 1 + 
PVE/QemuServer.pm | 6 ++ 
3 files changed, 177 insertions(+) 
create mode 100755 PVE/DHCP.pm 

diff --git a/PVE/DHCP.pm b/PVE/DHCP.pm 
new file mode 100755 
index 0000000..ba307cb 
--- /dev/null 
+++ b/PVE/DHCP.pm 
@@ -0,0 +1,170 @@ 
+package PVE::DHCP; 
+ 
+use strict; 
+use warnings; 
+ 
+use Time::HiRes qw(usleep); 
+use PVE::ProcFSTools; 
+use PVE::INotify; 
+use PVE::RPCEnvironment; 
+use PVE::QemuServer; 
+use PVE::Cluster qw(cfs_read_file cfs_write_file); 
+use PVE::Resource; 
+use Net::IP; 
+ 
+use Data::Dumper; 
+ 
+#fixme: this already exists in PVE::JSONSchema 
+my $ipv4_mask_hash = { 
+ '128.0.0.0' => 1, 
+ '192.0.0.0' => 2, 
+ '224.0.0.0' => 3, 
+ '240.0.0.0' => 4, 
+ '248.0.0.0' => 5, 
+ '252.0.0.0' => 6, 
+ '254.0.0.0' => 7, 
+ '255.0.0.0' => 8, 
+ '255.128.0.0' => 9, 
+ '255.192.0.0' => 10, 
+ '255.224.0.0' => 11, 
+ '255.240.0.0' => 12, 
+ '255.248.0.0' => 13, 
+ '255.252.0.0' => 14, 
+ '255.254.0.0' => 15, 
+ '255.255.0.0' => 16, 
+ '255.255.128.0' => 17, 
+ '255.255.192.0' => 18, 
+ '255.255.224.0' => 19, 
+ '255.255.240.0' => 20, 
+ '255.255.248.0' => 21, 
+ '255.255.252.0' => 22, 
+ '255.255.254.0' => 23, 
+ '255.255.255.0' => 24, 
+ '255.255.255.128' => 25, 
+ '255.255.255.192' => 26, 
+ '255.255.255.224' => 27, 
+ '255.255.255.240' => 28, 
+ '255.255.255.248' => 29, 
+ '255.255.255.252' => 30 
+}; 
+ 
+sub get_dhcp_ifaces { 
+ my ($ifaces) = @_; 
+ 
+ my $dhcp_ifaces = {}; 
+ foreach my $iface (keys %$ifaces) { 
+ next if $iface eq 'lo'; 
+ my $d = $ifaces->{$iface}; 
+ next if $d->{method} ne 'static'; 
+ next if !$d->{address}; 
+ next if !$d->{netmask}; 
+ next if !$d->{gateway}; 
+ 
+ my $binip = Net::IP::ip_iptobin($d->{address}, 4); 
+ my $binmask = Net::IP::ip_iptobin($d->{netmask}, 4); 
+ my $network = Net::IP::ip_bintoip($binip & $binmask, 4); 
+ my $prefixlen = $ipv4_mask_hash->{$d->{netmask}} || next; 
+ 
+ $d->{netobj} = Net::IP->new("$network/$prefixlen") || next; 
+ 
+ $dhcp_ifaces->{$iface} = $d; 
+ } 
+ 
+ return $dhcp_ifaces; 
+} 
+ 
+my $dhcpd_conf_fn = "/tmp/pve-dhcpd.conf"; 
+my $dhcpd_pid_fn = "/tmp/pve-dhcpd.pid"; 
+ 
+sub restart_dnsmasq_daemon { 
+ 
+ # Note: there is no wqay to reload dnsmasq config (author 
+ # claims this is a security feature). 
+ 
+ if (my $pid = PVE::Tools::file_read_firstline($dhcpd_pid_fn)) { 
+ # fixme: do it in a safer way! (dont kill wrong process) 
+ kill 9, $pid; 
+ unlink $dhcpd_pid_fn; 
+ my $count = 0; 
+ while (PVE::ProcFSTools::check_process_running($pid)) { 
+ usleep(100000); 
+ die "unable to stop dnsmasq (retry count == $count)\n" 
+ if ++$count > 100; 
+ } 
+ } 
+ 
+ my $cmd = ['dnsmasq', "--pid-file=$dhcpd_pid_fn", "--conf-file=$dhcpd_conf_fn"]; 
+ push @$cmd, "--log-queries"; # fixme: for debug 
+ PVE::Tools::run_command($cmd); 
+} 
+ 
+sub setup_dhcpd { 
+ 
+ my $rc = cfs_read_file('resource.cfg'); 
+ #print Dumper($rc); 
+ 
+ my $ippools = {}; 
+ # detect what interfaces have ippools with dhcp enabled 
+ foreach my $name (keys %{$rc->{ids}}) { 
+ my $d = $rc->{ids}->{$name}; 
+ next if $d->{type} ne 'ippool'; 
+ next if !$d->{dhcp}; 
+ $d->{name} = $name; 
+ $d->{iprangeobj} = Net::IP->new($d->{iprange}); 
+ push @{$ippools->{$d->{dhcp}}}, $d; 
+ } 
+ 
+ my $ifaces = PVE::INotify::read_file("interfaces"); 
+ 
+ my $dhcp_ifaces = get_dhcp_ifaces($ifaces); # interface with address/netmask/gateway 
+ 
+ #print Dumper($dhcp_ifaces); 
+ 
+ my $raw = ''; # dnsmasq configuration 
+ $raw .= "# autogenerate by Proxmox VE - Please no not edit this file\n\n"; 
+ 
+ $raw .= "port=0\n"; # disable DNS 
+ $raw .= "except-interface=lo\n"; 
+ $raw .= "bind-interfaces\n"; 
+ $raw .= "dhcp-ignore=tag:!known\n"; 
+ 
+ my $vmlist = PVE::QemuServer::vzlist(); 
+ my $vmconfhash = {}; 
+ foreach my $vmid (keys %$vmlist) { 
+ my $cfspath = PVE::QemuServer::cfs_config_path($vmid); 
+ $vmconfhash->{$vmid} = PVE::Cluster::cfs_read_file($cfspath) || {}; 
+ } 
+ 
+ foreach my $iface (keys %$dhcp_ifaces) { 
+ my $ifdata = $dhcp_ifaces->{$iface}; 
+ next if !$ippools->{$iface}; 
+ foreach my $ippool (@{$ippools->{$iface}}) { 
+ $raw .= "\n# interface '$iface', IP pool '$ippool->{name}'\n\n"; 
+ $raw .= "interface=$iface\n"; 
+ $raw .= "listen-address=$ifdata->{address}\n"; 
+ # fixme: howto pass gateway for that pool 
+ # fixme: howto pass additional dhcp options 
+ 
+ my $startip = $ippool->{iprangeobj}->ip(); 
+ my $endip = $ippool->{iprangeobj}->last_ip(); 
+ $raw .= "dhcp-range=interface:$iface,$startip,$endip,static,$ifdata->{netmask},8h\n"; 
+ 
+ my $MAX_NETS = 32; #fixme 
+ foreach my $vmid (keys %$vmconfhash) { 
+ my $conf = $vmconfhash->{$vmid}; 
+ for (my $i = 0; $i < $MAX_NETS; $i++) { 
+ next if !$conf->{"net$i"}; 
+ my $d = PVE::QemuServer::parse_net($conf->{"net$i"}); 
+ next if !$d || !$d->{ip} || !$d->{macaddr}; 
+ if ($ippool->{iprangeobj}->overlaps(Net::IP->new($d->{ip})) == $IP_B_IN_A_OVERLAP) { 
+ $raw .= "dhcp-host=$d->{macaddr},$d->{ip}\n"; 
+ } 
+ } 
+ } 
+ } 
+ } 
+ 
+ PVE::Tools::file_set_contents($dhcpd_conf_fn, $raw); 
+} 
+ 
+1; 
diff --git a/PVE/Makefile b/PVE/Makefile 
index 232c881..fa55b8d 100644 
--- a/PVE/Makefile 
+++ b/PVE/Makefile 
@@ -1,4 +1,5 @@ 
PERLSOURCE = \ 
+ DHCP.pm \ 
QemuServer.pm \ 
QemuMigrate.pm \ 
QMPClient.pm 
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm 
index 2a4f683..b7845c1 100644 
--- a/PVE/QemuServer.pm 
+++ b/PVE/QemuServer.pm 
@@ -28,6 +28,8 @@ use PVE::INotify; 
use PVE::ProcFSTools; 
use PVE::QMPClient; 
use PVE::RPCEnvironment; 
+use PVE::DHCP; 
+ 
use Time::HiRes qw(gettimeofday); 

my $cpuinfo = PVE::ProcFSTools::read_cpuinfo(); 
@@ -3061,6 +3063,10 @@ sub vm_start { 
# set environment variable useful inside network script 
$ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom; 

+ # setup DHCP server 
+ PVE::DHCP::setup_dhcpd(); 
+ PVE::DHCP::restart_dnsmasq_daemon(); 
+ 
my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine); 

my $migrate_port = 0; 
-- 
1.7.10.4 

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


More information about the pve-devel mailing list