From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id E125D9B363 for ; Tue, 17 Oct 2023 15:55:43 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id A51553432A for ; Tue, 17 Oct 2023 15:55:13 +0200 (CEST) Received: from lana.proxmox.com (unknown [94.136.29.99]) by firstgate.proxmox.com (Proxmox) with ESMTP for ; Tue, 17 Oct 2023 15:55:11 +0200 (CEST) Received: by lana.proxmox.com (Postfix, from userid 10043) id 131CB2C253C; Tue, 17 Oct 2023 15:55:10 +0200 (CEST) From: Stefan Hanreich To: pve-devel@lists.proxmox.com Date: Tue, 17 Oct 2023 15:55:04 +0200 Message-Id: <20231017135507.2220948-8-s.hanreich@proxmox.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231017135507.2220948-1-s.hanreich@proxmox.com> References: <20231017135507.2220948-1-s.hanreich@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.457 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Subject: [pve-devel] [WIP v2 pve-network 07/10] dhcp: regenerate config for DHCP servers on reload X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 17 Oct 2023 13:55:43 -0000 Regenerate the configuration files for the different DHCP server plugins when applying SDN settings by calling the respective hooks of the plugin responsible for configuring a DHCP instance. Signed-off-by: Stefan Hanreich --- src/PVE/Network/SDN.pm | 11 +- src/PVE/Network/SDN/Dhcp.pm | 192 +++++++++++++++++++++++++++++++++++ src/PVE/Network/SDN/Makefile | 2 +- 3 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 src/PVE/Network/SDN/Dhcp.pm diff --git a/src/PVE/Network/SDN.pm b/src/PVE/Network/SDN.pm index 057034f..5c059bc 100644 --- a/src/PVE/Network/SDN.pm +++ b/src/PVE/Network/SDN.pm @@ -12,6 +12,7 @@ use PVE::Network::SDN::Vnets; use PVE::Network::SDN::Zones; use PVE::Network::SDN::Controllers; use PVE::Network::SDN::Subnets; +use PVE::Network::SDN::Dhcp; use PVE::Tools qw(extract_param dir_glob_regex run_command); use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file); @@ -149,13 +150,15 @@ sub commit_config { my $zones_cfg = PVE::Network::SDN::Zones::config(); my $controllers_cfg = PVE::Network::SDN::Controllers::config(); my $subnets_cfg = PVE::Network::SDN::Subnets::config(); + my $dhcp_cfg = PVE::Network::SDN::Dhcp::config(); my $vnets = { ids => $vnets_cfg->{ids} }; my $zones = { ids => $zones_cfg->{ids} }; my $controllers = { ids => $controllers_cfg->{ids} }; my $subnets = { ids => $subnets_cfg->{ids} }; + my $dhcp = { ids => $dhcp_cfg->{ids} }; - $cfg = { version => $version, vnets => $vnets, zones => $zones, controllers => $controllers, subnets => $subnets }; + $cfg = { version => $version, vnets => $vnets, zones => $zones, controllers => $controllers, subnets => $subnets, dhcps => $dhcp }; cfs_write_file($running_cfg, $cfg); } @@ -231,6 +234,12 @@ sub generate_controller_config { PVE::Network::SDN::Controllers::reload_controller() if $reload; } +sub generate_dhcp_config { + my ($reload) = @_; + + PVE::Network::SDN::Dhcp::regenerate_config($reload); +} + sub encode_value { my ($type, $key, $value) = @_; diff --git a/src/PVE/Network/SDN/Dhcp.pm b/src/PVE/Network/SDN/Dhcp.pm new file mode 100644 index 0000000..b92c73a --- /dev/null +++ b/src/PVE/Network/SDN/Dhcp.pm @@ -0,0 +1,192 @@ +package PVE::Network::SDN::Dhcp; + +use strict; +use warnings; + +use PVE::Cluster qw(cfs_read_file); + +use PVE::Network::SDN; +use PVE::Network::SDN::Ipams::Plugin; +use PVE::Network::SDN::SubnetPlugin; +use PVE::Network::SDN::Dhcp qw(config); +use PVE::Network::SDN::Subnets qw(sdn_subnets_config config); +use PVE::Network::SDN::Dhcp::Plugin; +use PVE::Network::SDN::Dhcp::Dnsmasq; + +use PVE::INotify qw(nodename); + +PVE::Network::SDN::Dhcp::Plugin->init(); + +PVE::Network::SDN::Dhcp::Dnsmasq->register(); +PVE::Network::SDN::Dhcp::Dnsmasq->init(); + +sub config { + my ($running) = @_; + + if ($running) { + my $cfg = PVE::Network::SDN::running_config(); + return $cfg->{dhcps}; + } + + return cfs_read_file('sdn/dhcp.cfg'); +} + +sub sdn_dhcps_config { + my ($cfg, $id, $noerr) = @_; + + die "No DHCP ID specified!\n" if !$id; + + my $dhcp_config = $cfg->{ids}->{$id}; + die "SDN DHCP '$id' does not exist!\n" if (!$noerr && !$dhcp_config); + + if ($dhcp_config) { + $dhcp_config->{id} = $id; + } + + return $dhcp_config; +} + +sub get_dhcp { + my ($dhcp_id, $running) = @_; + + return if !$dhcp_id; + + my $cfg = PVE::Network::SDN::Dhcp::config($running); + return PVE::Network::SDN::Dhcp::sdn_dhcps_config($cfg, $dhcp_id, 1); +} + +sub add_mapping { + my ($vmid, $vnet, $mac) = @_; + + my $vnet_config = PVE::Network::SDN::Vnets::get_vnet($vnet, 1); + return if !$vnet_config; + + my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnet, 1); + + for my $subnet_id (keys %{$subnets}) { + my $subnet_config = $subnets->{$subnet_id}; + + next if !$subnet_config->{'dhcp-range'}; + + foreach my $dhcp_range (@{$subnet_config->{'dhcp-range'}}) { + my $dhcp_config = PVE::Network::SDN::Dhcp::get_dhcp($dhcp_range->{server}); + + if (!$dhcp_config) { + warn "Cannot find configuration for DHCP server $dhcp_range->{server}"; + next; + } + + my $ipam_plugin = PVE::Network::SDN::Ipams::Plugin->lookup('pve'); + + my $data = { + vmid => $vmid, + mac => $mac, + }; + + my $ip = $ipam_plugin->add_dhcp_ip($subnet_config, $dhcp_range, $data); + + next if !$ip; + + my $dhcp_plugin = PVE::Network::SDN::Dhcp::Plugin->lookup($dhcp_config->{type}); + $dhcp_plugin->add_ip_mapping($dhcp_config, $mac, $ip); + + return $ip; + } + } +} + +sub remove_mapping { + my ($vnet, $mac) = @_; + + my $vnet_config = PVE::Network::SDN::Vnets::get_vnet($vnet, 1); + return if !$vnet_config; + + my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnet, 1); + + for my $subnet_id (keys %{$subnets}) { + my $subnet_config = $subnets->{$subnet_id}; + next if !$subnet_config->{'dhcp-range'}; + + my $ipam_plugin = PVE::Network::SDN::Ipams::Plugin->lookup('pve'); + $ipam_plugin->del_dhcp_ip($subnet_config, $mac); + + foreach my $dhcp_range (@{$subnet_config->{'dhcp-range'}}) { + my $dhcp_config = PVE::Network::SDN::Dhcp::get_dhcp($dhcp_range->{server}); + + if (!$dhcp_config) { + warn "Cannot find configuration for DHCP server $dhcp_range->{server}"; + next; + } + + my $dhcp_plugin = PVE::Network::SDN::Dhcp::Plugin->lookup($dhcp_config->{type}); + $dhcp_plugin->del_ip_mapping($dhcp_config, $mac); + } + } +} + +sub regenerate_config { + my ($reload) = @_; + + my $dhcps = PVE::Network::SDN::Dhcp::config(); + my $subnets = PVE::Network::SDN::Subnets::config(); + + my $plugins = PVE::Network::SDN::Dhcp::Plugin->lookup_types(); + + my $nodename = PVE::INotify::nodename(); + + foreach my $plugin_name (@$plugins) { + my $plugin = PVE::Network::SDN::Dhcp::Plugin->lookup($plugin_name); + + eval { $plugin->before_regenerate() }; + die "Could not run before_regenerate for DHCP plugin $plugin_name $@\n" if $@; + } + + foreach my $dhcp_id (keys %{$dhcps->{ids}}) { + my $dhcp_config = PVE::Network::SDN::Dhcp::sdn_dhcps_config($dhcps, $dhcp_id); + my $plugin = PVE::Network::SDN::Dhcp::Plugin->lookup($dhcp_config->{type}); + + eval { $plugin->before_configure($dhcp_config) }; + die "Could not run before_configure for DHCP server $dhcp_id $@\n" if $@; + } + + foreach my $subnet_id (keys %{$subnets->{ids}}) { + my $subnet_config = PVE::Network::SDN::Subnets::sdn_subnets_config($subnets, $subnet_id); + next if !$subnet_config->{'dhcp-range'}; + + my @configured_servers = (); + + foreach my $dhcp_range (@{$subnet_config->{'dhcp-range'}}) { + my $dhcp_config = PVE::Network::SDN::Dhcp::sdn_dhcps_config($dhcps, $dhcp_range->{server}); + my $plugin = PVE::Network::SDN::Dhcp::Plugin->lookup($dhcp_config->{type}); + + next if $dhcp_config->{node} && !grep(/^$nodename$/, @{$dhcp_config->{node}}); + + if (!grep(/^$subnet_id$/, @configured_servers)) { + eval { $plugin->configure_subnet($dhcp_config, $subnet_config) }; + warn "Could not configure Subnet $subnet_id: $@\n" if $@; + + push @configured_servers, $subnet_id; + } + + eval { $plugin->configure_range($dhcp_config, $subnet_config, $dhcp_range) }; + warn "Could not configure DHCP range for $subnet_id: $@\n" if $@; + } + } + + foreach my $dhcp_id (keys %{$dhcps->{ids}}) { + my $dhcp_config = PVE::Network::SDN::Dhcp::sdn_dhcps_config($dhcps, $dhcp_id); + my $plugin = PVE::Network::SDN::Dhcp::Plugin->lookup($dhcp_config->{type}); + + eval { $plugin->after_configure($dhcp_config) }; + warn "Could not run after_configure for DHCP server $dhcp_id $@\n" if $@; + } + + foreach my $plugin_name (@$plugins) { + my $plugin = PVE::Network::SDN::Dhcp::Plugin->lookup($plugin_name); + + eval { $plugin->after_regenerate() }; + warn "Could not run after_regenerate for DHCP plugin $plugin_name $@\n" if $@; + } +} + +1; diff --git a/src/PVE/Network/SDN/Makefile b/src/PVE/Network/SDN/Makefile index 848f7d4..3e6e5fb 100644 --- a/src/PVE/Network/SDN/Makefile +++ b/src/PVE/Network/SDN/Makefile @@ -1,4 +1,4 @@ -SOURCES=Vnets.pm VnetPlugin.pm Zones.pm Controllers.pm Subnets.pm SubnetPlugin.pm Ipams.pm Dns.pm +SOURCES=Vnets.pm VnetPlugin.pm Zones.pm Controllers.pm Subnets.pm SubnetPlugin.pm Ipams.pm Dns.pm Dhcp.pm PERL5DIR=${DESTDIR}/usr/share/perl5 -- 2.39.2