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 BD6639884C for ; Mon, 13 Nov 2023 11:05:03 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id EC75E10A8D for ; Mon, 13 Nov 2023 11:04:39 +0100 (CET) Received: from bastionodiso.odiso.net (bastionodiso.odiso.net [IPv6:2a0a:1580:2000::2d]) (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 firstgate.proxmox.com (Proxmox) with ESMTPS for ; Mon, 13 Nov 2023 11:04:34 +0100 (CET) Received: from kvmformation3.odiso.net (formationkvm3.odiso.net [10.3.94.12]) by bastionodiso.odiso.net (Postfix) with ESMTP id 1ADC17B8B; Mon, 13 Nov 2023 11:04:22 +0100 (CET) Received: by kvmformation3.odiso.net (Postfix, from userid 0) id 19C3313AC02; Mon, 13 Nov 2023 11:04:22 +0100 (CET) From: Alexandre Derumier To: pve-devel@lists.proxmox.com Date: Mon, 13 Nov 2023 11:04:11 +0100 Message-Id: <20231113100419.3317478-8-aderumier@odiso.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231113100419.3317478-1-aderumier@odiso.com> References: <20231113100419.3317478-1-aderumier@odiso.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.020 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 HEADER_FROM_DIFFERENT_DOMAINS 0.249 From and EnvelopeFrom 2nd level mail domains are different 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 SPF_NONE 0.001 SPF: sender does not publish an SPF Record T_SCC_BODY_TEXT_LINE -0.01 - T_SPF_HELO_TEMPERROR 0.01 SPF: test of HELO record failed (temperror) Subject: [pve-devel] [RFC pve-network 3/9] vnet|subnet: add_next_free_ip : implement dhcprange ipam search 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: Mon, 13 Nov 2023 10:05:03 -0000 Signed-off-by: Alexandre Derumier --- src/PVE/Network/SDN/Ipams/NetboxPlugin.pm | 36 ++++++++++++++++++++ src/PVE/Network/SDN/Ipams/PVEPlugin.pm | 12 +++---- src/PVE/Network/SDN/Ipams/Plugin.pm | 7 ++++ src/PVE/Network/SDN/Subnets.pm | 21 +++++++++--- src/PVE/Network/SDN/Vnets.pm | 40 +++++++++++------------ src/test/run_test_subnets.pl | 2 +- src/test/run_test_vnets.pl | 4 +-- 7 files changed, 88 insertions(+), 34 deletions(-) diff --git a/src/PVE/Network/SDN/Ipams/NetboxPlugin.pm b/src/PVE/Network/SDN/Ipams/NetboxPlugin.pm index f0e7168..2099a7f 100644 --- a/src/PVE/Network/SDN/Ipams/NetboxPlugin.pm +++ b/src/PVE/Network/SDN/Ipams/NetboxPlugin.pm @@ -151,6 +151,33 @@ sub add_next_freeip { return $ip; } +sub add_range_next_freeip { + my ($class, $plugin_config, $subnet, $range, $data, $noerr) = @_; + + my $url = $plugin_config->{url}; + my $token = $plugin_config->{token}; + my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; + + my $internalid = get_iprange_id($url, $range, $headers); + my $description = "mac:$data->{mac}" if $data->{mac}; + + my $params = { dns_name => $data->{hostname}, description => $description }; + + my $ip = undef; + eval { + my $result = PVE::Network::SDN::api_request("POST", "$url/ipam/ip-ranges/$internalid/available-ips/", $headers, $params); + $ip = $result->{address}; + print "found ip free $ip in range $range->{'start-address'}-$range->{'end-address'}\n" if $ip; + }; + + if ($@) { + die "can't find free ip in range $range->{'start-address'}-$range->{'end-address'}: $@" if !$noerr; + } + + return $ip; + +} + sub del_ip { my ($class, $plugin_config, $subnetid, $subnet, $ip, $noerr) = @_; @@ -204,6 +231,15 @@ sub get_prefix_id { return $internalid; } +sub get_iprange_id { + my ($url, $range, $headers) = @_; + + my $result = PVE::Network::SDN::api_request("GET", "$url/ipam/ip-ranges/?start_address=$range->{'start-address'}&end_address=$range->{'end-address'}", $headers); + my $data = @{$result->{results}}[0]; + my $internalid = $data->{id}; + return $internalid; +} + sub get_ip_id { my ($url, $ip, $headers) = @_; my $result = PVE::Network::SDN::api_request("GET", "$url/ipam/ip-addresses/?q=$ip", $headers); diff --git a/src/PVE/Network/SDN/Ipams/PVEPlugin.pm b/src/PVE/Network/SDN/Ipams/PVEPlugin.pm index fcc8282..37b47e4 100644 --- a/src/PVE/Network/SDN/Ipams/PVEPlugin.pm +++ b/src/PVE/Network/SDN/Ipams/PVEPlugin.pm @@ -110,7 +110,7 @@ sub update_ip { } sub add_next_freeip { - my ($class, $plugin_config, $subnetid, $subnet, $hostname, $mac, $description) = @_; + my ($class, $plugin_config, $subnetid, $subnet, $hostname, $mac, $description, $noerr) = @_; my $cidr = $subnet->{cidr}; my $network = $subnet->{network}; @@ -156,8 +156,8 @@ sub add_next_freeip { return "$freeip/$mask"; } -sub add_dhcp_ip { - my ($class, $subnet, $dhcp_range, $data) = @_; +sub add_range_next_freeip { + my ($class, $plugin_config, $subnet, $range, $data, $noerr) = @_; my $cidr = $subnet->{cidr}; my $zone = $subnet->{zone}; @@ -171,8 +171,8 @@ sub add_dhcp_ip { my $dbsubnet = $dbzone->{subnets}->{$cidr}; die "subnet '$cidr' doesn't exist in IPAM DB\n" if !$dbsubnet; - my $ip = new Net::IP ("$dhcp_range->{'start-address'} - $dhcp_range->{'end-address'}") - or die "Invalid IP address(es) in DHCP Range!\n"; + my $ip = new Net::IP ("$range->{'start-address'} - $range->{'end-address'}") + or die "Invalid IP address(es) in Range!\n"; do { my $ip_address = $ip->ip(); @@ -184,7 +184,7 @@ sub add_dhcp_ip { } } while (++$ip); - die "No free IP left in DHCP Range $dhcp_range->{'start-address'}:$dhcp_range->{'end-address'}}\n"; + die "No free IP left in Range $range->{'start-address'}:$range->{'end-address'}}\n"; }); } diff --git a/src/PVE/Network/SDN/Ipams/Plugin.pm b/src/PVE/Network/SDN/Ipams/Plugin.pm index c96eeda..4d85b81 100644 --- a/src/PVE/Network/SDN/Ipams/Plugin.pm +++ b/src/PVE/Network/SDN/Ipams/Plugin.pm @@ -98,6 +98,13 @@ sub add_next_freeip { die "please implement inside plugin"; } + +sub add_range_next_freeip { + my ($class, $plugin_config, $subnet, $range, $data, $noerr) = @_; + + die "please implement inside plugin"; +} + sub del_ip { my ($class, $plugin_config, $subnetid, $subnet, $ip, $noerr) = @_; diff --git a/src/PVE/Network/SDN/Subnets.pm b/src/PVE/Network/SDN/Subnets.pm index dd9e697..9f953a6 100644 --- a/src/PVE/Network/SDN/Subnets.pm +++ b/src/PVE/Network/SDN/Subnets.pm @@ -202,8 +202,8 @@ sub del_subnet { $plugin->del_subnet($plugin_config, $subnetid, $subnet); } -sub next_free_ip { - my ($zone, $subnetid, $subnet, $hostname, $mac, $description, $skipdns) = @_; +sub add_next_free_ip { + my ($zone, $subnetid, $subnet, $hostname, $mac, $description, $skipdns, $dhcprange) = @_; my $cidr = undef; my $ip = undef; @@ -225,9 +225,20 @@ sub next_free_ip { my $plugin_config = $ipam_cfg->{ids}->{$ipamid}; my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type}); eval { - $cidr = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet, $hostname, $mac, $description); - ($ip, undef) = split(/\//, $cidr); + if ($dhcprange) { + my $data = { + mac => $mac, + hostname => $hostname, + }; + foreach my $range (@{$subnet->{'dhcp-range'}}) { + $ip = $plugin->add_range_next_freeip($plugin_config, $subnet, $range, $data); + next if !$ip; + } + } else { + $ip = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet, $hostname, $mac, $description); + } }; + die $@ if $@; } @@ -249,7 +260,7 @@ sub next_free_ip { }; die $err; } - return $cidr; + return $ip; } sub add_ip { diff --git a/src/PVE/Network/SDN/Vnets.pm b/src/PVE/Network/SDN/Vnets.pm index 39bdda0..76a6caf 100644 --- a/src/PVE/Network/SDN/Vnets.pm +++ b/src/PVE/Network/SDN/Vnets.pm @@ -96,8 +96,8 @@ sub get_subnet_from_vnet_cidr { return ($zone, $subnetid, $subnet, $ip); } -sub get_next_free_cidr { - my ($vnetid, $hostname, $mac, $description, $ipversion, $skipdns) = @_; +sub add_next_free_cidr { + my ($vnetid, $hostname, $mac, $description, $skipdns, $dhcprange) = @_; my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid); my $zoneid = $vnet->{zone}; @@ -105,27 +105,27 @@ sub get_next_free_cidr { return if !$zone->{ipam}; - $ipversion = 4 if !$ipversion; my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1); - my $ip = undef; - my $subnetcount = 0; - foreach my $subnetid (sort keys %{$subnets}) { - my $subnet = $subnets->{$subnetid}; - my $network = $subnet->{network}; - - next if $ipversion != Net::IP::ip_get_version($network); - $subnetcount++; - - eval { - $ip = PVE::Network::SDN::Subnets::next_free_ip($zone, $subnetid, $subnet, $hostname, $mac, $description, $skipdns); - }; - warn $@ if $@; - last if $ip; + my @ipversions = qw/ 4 6 /; + for my $ipversion (@ipversions) { + my $ip = undef; + my $subnetcount = 0; + foreach my $subnetid (sort keys %{$subnets}) { + my $subnet = $subnets->{$subnetid}; + my $network = $subnet->{network}; + + next if Net::IP::ip_get_version($network) != $ipversion; + $subnetcount++; + + eval { + $ip = PVE::Network::SDN::Subnets::add_next_free_ip($zone, $subnetid, $subnet, $hostname, $mac, $description, $skipdns, $dhcprange); + }; + die $@ if $@; + last if $ip; + } + die "can't find any free ip" if !$ip && $subnetcount > 0; } - die "can't find any free ip" if !$ip && $subnetcount > 0; - - return $ip; } sub add_cidr { diff --git a/src/test/run_test_subnets.pl b/src/test/run_test_subnets.pl index f6564e1..9692f4c 100755 --- a/src/test/run_test_subnets.pl +++ b/src/test/run_test_subnets.pl @@ -192,7 +192,7 @@ foreach my $path (@plugins) { $expected = '{"zones":{"myzone":{"subnets":{"'.$subnet_cidr.'":{"ips":{"'.$ip.'":{"gateway":1},"'.$ipnextfree.'":{},"'.$ip2.'":{}}}}}}}'; eval { - $ip3 = PVE::Network::SDN::Subnets::next_free_ip($zone, $subnetid, $subnet, $hostname, $mac, $description); + $ip3 = PVE::Network::SDN::Subnets::add_next_free_ip($zone, $subnetid, $subnet, $hostname, $mac, $description); }; if ($@) { diff --git a/src/test/run_test_vnets.pl b/src/test/run_test_vnets.pl index 5aeb676..dc9da67 100755 --- a/src/test/run_test_vnets.pl +++ b/src/test/run_test_vnets.pl @@ -231,7 +231,7 @@ foreach my $path (@plugins) { $expected = $ipam ? $cidr3 : undef; eval { - $result = PVE::Network::SDN::Vnets::get_next_free_cidr($vnetid, $hostname, $mac, $description, $ipversion); + $result = PVE::Network::SDN::Vnets::add_next_free_cidr($vnetid, $hostname, $mac, $description); }; if ($@) { @@ -309,7 +309,7 @@ foreach my $path (@plugins) { $expected = $ipam ? $cidr1 : undef; eval { - $result = PVE::Network::SDN::Vnets::get_next_free_cidr($vnetid, $hostname, $mac, $description, $ipversion); + $result = PVE::Network::SDN::Vnets::add_next_free_cidr($vnetid, $hostname, $mac, $description); }; if ($@) { -- 2.39.2