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
next prev 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox