all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Alexandre Derumier <aderumier@odiso.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [RFC pve-network 3/9] vnet|subnet: add_next_free_ip : implement dhcprange ipam search
Date: Mon, 13 Nov 2023 11:04:11 +0100	[thread overview]
Message-ID: <20231113100419.3317478-8-aderumier@odiso.com> (raw)
In-Reply-To: <20231113100419.3317478-1-aderumier@odiso.com>

Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
 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




  parent reply	other threads:[~2023-11-13 10:05 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-cluster 1/1] add priv/macs.db Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 1/9] define dhcpplugin in zone Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC qemu-server 1/5] don't remove dhcp mapping on stop Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 2/9] dhcp : add|del_ip_mapping: only add|del dhcp reservervation Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC qemu-server 2/5] vmnic add|remove : add|del ip in ipam Alexandre Derumier
2023-11-13 16:14   ` Stefan Hanreich
2023-11-13 10:04 ` [pve-devel] [RFC qemu-server 3/5] vm_start : vm-network-scripts: get ip from ipam and add dhcp reservation Alexandre Derumier
2023-11-13 10:04 ` Alexandre Derumier [this message]
2023-11-13 10:04 ` [pve-devel] [RFC qemu-server 4/5] api2: create|restore|clone: add_free_ip Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 4/9] ipam : add macs.db for fast mac lookup Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 5/9] ipam : add get_ips_from_mac Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC qemu-server 5/5] vm_destroy: delete ip from ipam && dhcp Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 6/9] vnets: rename del|add|update_cidr to ip Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 7/9] vnets: add del_ips_from_mac Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 8/9] ipams : pveplugin: remove del_dhcp_ip Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 9/9] dhcp : dnsmasq: add_mapping: remove old mac, ip before append Alexandre Derumier
2023-11-13 10:35 ` [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Stefan Hanreich
2023-11-13 15:44   ` DERUMIER, Alexandre
2023-11-13 16:11     ` Stefan Hanreich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231113100419.3317478-8-aderumier@odiso.com \
    --to=aderumier@odiso.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal