* [pve-devel] [PATCH guest-common, network, container, qemu-server 0/4] fix #5900: enhance SDN auto-dhcp behaviour
@ 2024-12-05 16:33 Daniel Herzig
2024-12-05 16:33 ` [pve-devel] [PATCH guest-common 1/4] fix #5900: add helper function Daniel Herzig
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Daniel Herzig @ 2024-12-05 16:33 UTC (permalink / raw)
To: pve-devel
This patch series prevents containers and vms to be created when their bridges are within an SDN zone,
that is set to deploy IPs automatically via dnsmasq, while the dhcp range is exhausted.
Currently adding a bridge under these circumstances is already impossible, however on VM or container
creation, this is overridden, which can lead to confusing behaviour as described in detail on bugzilla.
*** BLURB HERE ***
guest-common: Daniel Herzig (1):
fix #5900: add helper function
src/PVE/GuestHelpers.pm | 11 +++++++++++
1 file changed, 11 insertions(+)
network: Daniel Herzig (1):
fix #5900: add helper functions
src/PVE/Network/SDN/Dhcp.pm | 83 +++++++++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+)
container: Daniel Herzig (1):
fix #5900: do not create container if dhcp range is exhausted
src/PVE/API2/LXC.pm | 12 ++++++++++++
1 file changed, 12 insertions(+)
qemu-server: Daniel Herzig (1):
fix #5900: do not create vm if dhcp range is exhausted
PVE/API2/Qemu.pm | 12 ++++++++++++
1 file changed, 12 insertions(+)
--
2.39.5
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* [pve-devel] [PATCH guest-common 1/4] fix #5900: add helper function
2024-12-05 16:33 [pve-devel] [PATCH guest-common, network, container, qemu-server 0/4] fix #5900: enhance SDN auto-dhcp behaviour Daniel Herzig
@ 2024-12-05 16:33 ` Daniel Herzig
2024-12-12 17:12 ` Stefan Hanreich
2024-12-05 16:33 ` [pve-devel] [PATCH network 2/4] fix #5900: add helper functions Daniel Herzig
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Daniel Herzig @ 2024-12-05 16:33 UTC (permalink / raw)
To: pve-devel
This patch adds a small helper function to retrieve the bridge name
from the netN parameter string of a container or VM configuration.
Signed-off-by: Daniel Herzig <d.herzig@proxmox.com>
---
src/PVE/GuestHelpers.pm | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/src/PVE/GuestHelpers.pm b/src/PVE/GuestHelpers.pm
index 592b4a8..c6006ba 100644
--- a/src/PVE/GuestHelpers.pm
+++ b/src/PVE/GuestHelpers.pm
@@ -450,4 +450,15 @@ sub abort_guest_tasks {
return $aborted_tasks;
}
+sub get_bridge {
+ my $net_params = shift;
+ my $param_array = [ split(/,/, $net_params) ];
+ my $bridge;
+ for my $net_param (@$param_array) {
+ $bridge = $net_param if ($net_param =~ /bridge\=/);
+ $bridge =~ s|bridge\=|| if (defined($bridge));
+ }
+ return $bridge;
+}
+
1;
--
2.39.5
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* [pve-devel] [PATCH network 2/4] fix #5900: add helper functions
2024-12-05 16:33 [pve-devel] [PATCH guest-common, network, container, qemu-server 0/4] fix #5900: enhance SDN auto-dhcp behaviour Daniel Herzig
2024-12-05 16:33 ` [pve-devel] [PATCH guest-common 1/4] fix #5900: add helper function Daniel Herzig
@ 2024-12-05 16:33 ` Daniel Herzig
2024-12-12 17:06 ` Stefan Hanreich
2024-12-05 16:33 ` [pve-devel] [PATCH container 3/4] fix #5900: do not create container if dhcp range is exhausted Daniel Herzig
2024-12-05 16:33 ` [pve-devel] [PATCH qemu-server 4/4] fix #5900: do not create vm " Daniel Herzig
3 siblings, 1 reply; 9+ messages in thread
From: Daniel Herzig @ 2024-12-05 16:33 UTC (permalink / raw)
To: pve-devel
This patch adds helper functions to evaluate if a vnet (bridge) associated
with a zone under SDN's auto-dhcp control via dnsmasq can retrieve a
dhcp lease.
Signed-off-by: Daniel Herzig <d.herzig@proxmox.com>
---
src/PVE/Network/SDN/Dhcp.pm | 83 +++++++++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+)
diff --git a/src/PVE/Network/SDN/Dhcp.pm b/src/PVE/Network/SDN/Dhcp.pm
index d48de34..4ddd128 100644
--- a/src/PVE/Network/SDN/Dhcp.pm
+++ b/src/PVE/Network/SDN/Dhcp.pm
@@ -128,4 +128,87 @@ sub regenerate_config {
}
}
+sub defined_dhcp_ip_count_in_zone {
+ my $zone_id = shift;
+ my $vnets_in_zone = PVE::Network::SDN::Zones::get_vnets($zone_id);
+ my $range_count_array;
+ my $res;
+ for my $vnet_id (keys %$vnets_in_zone) {
+ my $subnets_in_vnet = PVE::Network::SDN::Vnets::get_subnets($vnet_id);
+ for my $subnet (keys %$subnets_in_vnet) {
+ my $dhcp_ranges = PVE::Network::SDN::Subnets::get_dhcp_ranges(${subnets_in_vnet}->{$subnet});
+ if (scalar @$dhcp_ranges) {
+ for my $dhcp_range (@$dhcp_ranges) {
+ my $start_ip = ${dhcp_range}->{'start-address'};
+ my $end_ip = ${dhcp_range}->{'end-address'};
+ my $subnet_ip_count = new Net::IP("$start_ip - $end_ip")->size();
+ push (@$range_count_array, $subnet_ip_count);
+ }
+ }
+ }
+ }
+ if ($range_count_array) {
+ $res = eval join '+', @$range_count_array;
+ }
+ return $res;
+}
+
+sub used_dhcp_ips_in_zone {
+ my $zone_id = shift;
+ my $pve_ipam_db = PVE::Network::SDN::Ipams::PVEPlugin::read_db();
+ my $subnets_in_zone = $pve_ipam_db->{'zones'}->{$zone_id}->{'subnets'};
+ my $res;
+ for my $subnet_in_zone (keys %$subnets_in_zone) {
+ my $ips_in_subnet = ${subnets_in_zone}->{$subnet_in_zone}->{'ips'};
+ if (scalar (keys %$ips_in_subnet)) {
+ for my $leased_ip (keys %$ips_in_subnet) {
+ $res++ if (!exists ${ips_in_subnet}->{$leased_ip}->{'gateway'});
+ }
+ }
+ }
+ return $res;
+}
+
+sub available_dhcp_ips_in_zone {
+ my $zone_id = shift;
+ my $available_ip_count = defined_dhcp_ip_count_in_zone($zone_id);
+ my $used_ip_count = used_dhcp_ips_in_zone($zone_id);
+ if (!defined($available_ip_count)) {
+ $available_ip_count = 0;
+ }
+ if (!defined($used_ip_count)) {
+ $used_ip_count = 0;
+ }
+ my $res = $available_ip_count - $used_ip_count;
+ return $res;
+}
+
+sub test_bridge_for_sdn_dnsmasq {
+ my $bridge = shift;
+ my $vnets_cfg = PVE::Network::SDN::Vnets::config();
+ my $vnet_ids = [ PVE::Network::SDN::Vnets::sdn_vnets_ids($vnets_cfg) ];
+ my $zones_cfg = PVE::Network::SDN::Zones::config();
+ my $zone_ids = [ PVE::Network::SDN::Zones::sdn_zones_ids($zones_cfg) ];
+ my $dhcp_dnsmasq_zones;
+ my $vnets_in_dhcp_dnsmasq_zones;
+ for my $zone (@$zone_ids) {
+ push(@$dhcp_dnsmasq_zones, $zone)
+ if (defined(${zones_cfg}->{'ids'}->{$zone}->{'dhcp'}) &&
+ (${zones_cfg}->{'ids'}->{$zone}->{'dhcp'} eq 'dnsmasq'))
+ }
+ for my $vnet (@$vnet_ids) {
+ my $vnet_zone = ${vnets_cfg}->{'ids'}->{$vnet}->{'zone'};
+ push(@$vnets_in_dhcp_dnsmasq_zones, $vnet)
+ if ("@$dhcp_dnsmasq_zones" =~ /$vnet_zone/)
+ }
+ if (("@$vnets_in_dhcp_dnsmasq_zones" =~ /$bridge/)) {
+ my $zone_id = ${vnets_cfg}->{'ids'}->{$bridge}->{'zone'};
+ if ((PVE::Network::SDN::Dhcp::available_dhcp_ips_in_zone($zone_id)) lt 1) {
+ die "No DHCP leases left in zone '$zone_id' for bridge '$bridge', please check your SDN config.\n";
+ }
+ }
+}
+
+
+
1;
--
2.39.5
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* [pve-devel] [PATCH container 3/4] fix #5900: do not create container if dhcp range is exhausted
2024-12-05 16:33 [pve-devel] [PATCH guest-common, network, container, qemu-server 0/4] fix #5900: enhance SDN auto-dhcp behaviour Daniel Herzig
2024-12-05 16:33 ` [pve-devel] [PATCH guest-common 1/4] fix #5900: add helper function Daniel Herzig
2024-12-05 16:33 ` [pve-devel] [PATCH network 2/4] fix #5900: add helper functions Daniel Herzig
@ 2024-12-05 16:33 ` Daniel Herzig
2024-12-05 16:33 ` [pve-devel] [PATCH qemu-server 4/4] fix #5900: do not create vm " Daniel Herzig
3 siblings, 0 replies; 9+ messages in thread
From: Daniel Herzig @ 2024-12-05 16:33 UTC (permalink / raw)
To: pve-devel
This patch prevents containers to be created if their bridge is
associated with a SDN zone with dnsmasq automatic dhcp enabled, and if
the dhcp-range is exhausted or unset.
Signed-off-by: Daniel Herzig <d.herzig@proxmox.com>
---
src/PVE/API2/LXC.pm | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/src/PVE/API2/LXC.pm b/src/PVE/API2/LXC.pm
index 213e518..35fb0a6 100644
--- a/src/PVE/API2/LXC.pm
+++ b/src/PVE/API2/LXC.pm
@@ -244,6 +244,18 @@ __PACKAGE__->register_method({
PVE::LXC::Config->check_protection($conf, "unable to restore CT $vmid");
}
+ for my $opt (keys %$param) {
+ if ($opt =~ /net/) {
+ my $bridge_err;
+ my $bridge = PVE::GuestHelpers::get_bridge(${param}->{$opt});
+ if (defined($bridge)) {
+ eval { PVE::Network::SDN::Dhcp::test_bridge_for_sdn_dnsmasq($bridge) };
+ ${bridge_err}->{$opt} = $@ if $@;
+ raise_param_exc($bridge_err) if $bridge_err;
+ }
+ }
+ }
+
my $password = extract_param($param, 'password');
my $ssh_keys = extract_param($param, 'ssh-public-keys');
PVE::Tools::validate_ssh_public_keys($ssh_keys) if defined($ssh_keys);
--
2.39.5
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* [pve-devel] [PATCH qemu-server 4/4] fix #5900: do not create vm if dhcp range is exhausted
2024-12-05 16:33 [pve-devel] [PATCH guest-common, network, container, qemu-server 0/4] fix #5900: enhance SDN auto-dhcp behaviour Daniel Herzig
` (2 preceding siblings ...)
2024-12-05 16:33 ` [pve-devel] [PATCH container 3/4] fix #5900: do not create container if dhcp range is exhausted Daniel Herzig
@ 2024-12-05 16:33 ` Daniel Herzig
3 siblings, 0 replies; 9+ messages in thread
From: Daniel Herzig @ 2024-12-05 16:33 UTC (permalink / raw)
To: pve-devel
This patch prevents VMs to be created if their bridge is
associated with a SDN zone with dnsmasq automatic dhcp enabled, and if
the dhcp-range is exhausted or unset.
Signed-off-by: Daniel Herzig <d.herzig@proxmox.com>
---
PVE/API2/Qemu.pm | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index ec45d5ff..73580c64 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -1065,6 +1065,18 @@ __PACKAGE__->register_method({
raise_perm_exc();
}
+ for my $opt (keys %$param) {
+ if ($opt =~ /net/) {
+ my $bridge_err;
+ my $bridge = PVE::GuestHelpers::get_bridge(${param}->{$opt});
+ if (defined($bridge)) {
+ eval { PVE::Network::SDN::Dhcp::test_bridge_for_sdn_dnsmasq($bridge) };
+ ${bridge_err}->{$opt} = $@ if $@;
+ raise_param_exc($bridge_err) if $bridge_err;
+ }
+ }
+ }
+
if ($archive) {
for my $opt (sort keys $param->%*) {
if (PVE::QemuServer::Drive::is_valid_drivename($opt)) {
--
2.39.5
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [pve-devel] [PATCH network 2/4] fix #5900: add helper functions
2024-12-05 16:33 ` [pve-devel] [PATCH network 2/4] fix #5900: add helper functions Daniel Herzig
@ 2024-12-12 17:06 ` Stefan Hanreich
2024-12-16 8:35 ` Daniel Herzig
0 siblings, 1 reply; 9+ messages in thread
From: Stefan Hanreich @ 2024-12-12 17:06 UTC (permalink / raw)
To: Proxmox VE development discussion, Daniel Herzig
I think in this case it is a lot easier to ask for forgiveness rather
than asking for permission. One could just try to allocate the IP and
check if that fails, avoiding the need to implement a complete check for
the IP allocation.
Checking beforehand also leads to some TOCTOU issues (admittedly small,
since in the window between the check and the actual IP allocation the
state of the IPAM could change).
I talked with Daniel off-list and the initial implementation actually
did only try to allocate and then error out, but the reasoning for
implementing it this way was: If you create a VM and then allocating an
IP fails the wizard closes, but the task fails. The user would then have
to create the VM configuration completely from scratch, which is bad UX.
So the tradeoff here is UX vs some technical reasons (TOCTOU,
implementation complexity).
I think Daniel also talked to you off-list @Aaron, so it'd be great if
you could chime in here.
Nevertheless I have added some notes on the Perl code, regardless of
which option we choose, although I think we could do completely without
implementing a manual check which would obsolete this commit. But the
general ideas apply for future patch series as well, so I thought they'd
help either way. Some general notes on the architecture:
If we do it this way (see top-level discussion), I think we should
abstract this into the IpamPlugins itself, since this implementation is
specific to the PVE Plugin, but that's just one type of IPAM plugin.
Something like:
Add a abstract method in the base Ipam plugin
(Network/SDN/Ipams/Plugin.pm), i.e.
PVE::Network::SDN::Ipams::Plugin::vnet_has_free_ip($range, $ipversions)
Then implement it for every IPAM Plugin separately.
Add a helper method to the VNet that selects the correct plugin based on
the zone setting and then iterates over all its subnets to check for
free IPs - something like:
PVE::Network::SDN::Vnets::has_free_ip($range, $ipversions)
The current implementation only works for the PVE plugin and would
actually break on zones using Netbox / Phpipam (if my brain compiler is
correct).
On 12/5/24 17:33, Daniel Herzig wrote:
> This patch adds helper functions to evaluate if a vnet (bridge) associated
> with a zone under SDN's auto-dhcp control via dnsmasq can retrieve a
> dhcp lease.
>
> Signed-off-by: Daniel Herzig <d.herzig@proxmox.com>
> ---
> src/PVE/Network/SDN/Dhcp.pm | 83 +++++++++++++++++++++++++++++++++++++
> 1 file changed, 83 insertions(+)
>
> diff --git a/src/PVE/Network/SDN/Dhcp.pm b/src/PVE/Network/SDN/Dhcp.pm
> index d48de34..4ddd128 100644
> --- a/src/PVE/Network/SDN/Dhcp.pm
> +++ b/src/PVE/Network/SDN/Dhcp.pm
> @@ -128,4 +128,87 @@ sub regenerate_config {
> }
> }
>
> +sub defined_dhcp_ip_count_in_zone {
> + my $zone_id = shift;
even with 1 argument I think we prefer `my ($arg) = @_;`, but I haven't
actually found a definitive answer in our style guide.
> + my $vnets_in_zone = PVE::Network::SDN::Zones::get_vnets($zone_id);
> + my $range_count_array;
> + my $res;
> + for my $vnet_id (keys %$vnets_in_zone) {
> + my $subnets_in_vnet = PVE::Network::SDN::Vnets::get_subnets($vnet_id);
> + for my $subnet (keys %$subnets_in_vnet) {
> + my $dhcp_ranges = PVE::Network::SDN::Subnets::get_dhcp_ranges(${subnets_in_vnet}->{$subnet});
> + if (scalar @$dhcp_ranges) {
> + for my $dhcp_range (@$dhcp_ranges) {
You can just iterate over @$dhcp_ranges, get_dhcp_ranges() always
returns an array reference. If it is empty, then there are just 0
iterations of the loop, no need to check for existence.
> + my $start_ip = ${dhcp_range}->{'start-address'};
$dhcp_range is fine instead of ${dhcp_range}
> + my $end_ip = ${dhcp_range}->{'end-address'};
> + my $subnet_ip_count = new Net::IP("$start_ip - $end_ip")->size();
> + push (@$range_count_array, $subnet_ip_count);
> + }
> + }
> + }
> + }
> + if ($range_count_array) {
> + $res = eval join '+', @$range_count_array;
I think it would be easier to just define the variable at the top to be 0:
my $res = 0;
and then add the size to it during the loop:
$count += new Net::IP("$start_ip - $end_ip")->size();
> + }
> + return $res;
> +}
> +> +sub used_dhcp_ips_in_zone {
> + my $zone_id = shift;
> + my $pve_ipam_db = PVE::Network::SDN::Ipams::PVEPlugin::read_db();
> + my $subnets_in_zone = $pve_ipam_db->{'zones'}->{$zone_id}->{'subnets'};
> + my $res;
similarly to the above method we could define res as 0 here
> + for my $subnet_in_zone (keys %$subnets_in_zone) {
> + my $ips_in_subnet = ${subnets_in_zone}->{$subnet_in_zone}->{'ips'};
After moving this to PVEPlugin, this could maybe also be split into some
helper functions like
PVEPlugin::get_ips_for_subnet()
or something.
> + if (scalar (keys %$ips_in_subnet)) {
> + for my $leased_ip (keys %$ips_in_subnet) {
> + $res++ if (!exists ${ips_in_subnet}->{$leased_ip}->{'gateway'});
> + }
> + }
> + }
> + return $res;
> +}
> +
> +sub available_dhcp_ips_in_zone {
> + my $zone_id = shift;
> + my $available_ip_count = defined_dhcp_ip_count_in_zone($zone_id);
> + my $used_ip_count = used_dhcp_ips_in_zone($zone_id);
> + if (!defined($available_ip_count)) {
> + $available_ip_count = 0;
> + }
> + if (!defined($used_ip_count)) {
> + $used_ip_count = 0;
> + }
If you define $res to be 0 as suggested above, then those checks become
unnecessary, since 0 becomes the default value.
> + my $res = $available_ip_count - $used_ip_count;
> + return $res;
> +}
> +
> +sub test_bridge_for_sdn_dnsmasq {
this function would basically be the helper inside the VNet - it just
needs to consider the IPAM plugin as well.
> + my $bridge = shift;
> + my $vnets_cfg = PVE::Network::SDN::Vnets::config();
config() takes $running as parameter. With SDN we have a running config
and a 'normal' config (that stores all changes you make before applying
them). In this case we need to use the running config rather than the
normal config.
> + my $vnet_ids = [ PVE::Network::SDN::Vnets::sdn_vnets_ids($vnets_cfg) ];
no need for selecting the ids, you can directly iterate over the VNets:
my $vnets = PVE::Network::SDN::Vnets::config(1);
foreach my $vnet_id (sort keys %{$vnets->{ids}}) {
$vnet = PVE::Network::SDN::Vnets::sdn_vnets_config($vnets,$vnet_id);
}
With Vnets there is no difference, but with Subnets there is a subtle
difference, since it generates some additional keys from the section_id
(see Subnets.pm). So it is preferable to go via this function
-----
An even easier solution - using the fact that VNet names are always
equivalent to the bridge names:
my $vnet = PVE::Network::SDN::Vnets::get_vnet($bridge)
This would give you the respective VNet (or undef if it isn't a VNet)
that corresponds to the bridge.
Then you just need to get the zone for the VNet:
my $zone = PVE::Network::SDN::Zones::get_zone($vnet->{zone});
and then you could just easily check if that zone has DHCP enabled,
saving you both loops.
> + my $zones_cfg = PVE::Network::SDN::Zones::config();
> + my $zone_ids = [ PVE::Network::SDN::Zones::sdn_zones_ids($zones_cfg) ];
same as above - maybe even just defining a helper would be even better?
> + my $dhcp_dnsmasq_zones;
> + my $vnets_in_dhcp_dnsmasq_zones;
> + for my $zone (@$zone_ids) {
> + push(@$dhcp_dnsmasq_zones, $zone)
> + if (defined(${zones_cfg}->{'ids'}->{$zone}->{'dhcp'}) &&
> + (${zones_cfg}->{'ids'}->{$zone}->{'dhcp'} eq 'dnsmasq'))
> + }
> + for my $vnet (@$vnet_ids) {
> + my $vnet_zone = ${vnets_cfg}->{'ids'}->{$vnet}->{'zone'};
> + push(@$vnets_in_dhcp_dnsmasq_zones, $vnet)
> + if ("@$dhcp_dnsmasq_zones" =~ /$vnet_zone/)
If you want to check for containment in an array it is preferable to use
grep:
my @array = (1, 2, 3);
if (grep {$_ eq 1} @array)
> + }
> + if (("@$vnets_in_dhcp_dnsmasq_zones" =~ /$bridge/)) {
same
> + my $zone_id = ${vnets_cfg}->{'ids'}->{$bridge}->{'zone'};
> + if ((PVE::Network::SDN::Dhcp::available_dhcp_ips_in_zone($zone_id)) lt 1) {
> + die "No DHCP leases left in zone '$zone_id' for bridge '$bridge', please check your SDN config.\n";
> + }
> + }
> +}
> +
> +
> +
> 1;
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [pve-devel] [PATCH guest-common 1/4] fix #5900: add helper function
2024-12-05 16:33 ` [pve-devel] [PATCH guest-common 1/4] fix #5900: add helper function Daniel Herzig
@ 2024-12-12 17:12 ` Stefan Hanreich
2024-12-16 8:38 ` Daniel Herzig
0 siblings, 1 reply; 9+ messages in thread
From: Stefan Hanreich @ 2024-12-12 17:12 UTC (permalink / raw)
To: Proxmox VE development discussion, Daniel Herzig
On 12/5/24 17:33, Daniel Herzig wrote:
> This patch adds a small helper function to retrieve the bridge name
> from the netN parameter string of a container or VM configuration.
>
> Signed-off-by: Daniel Herzig <d.herzig@proxmox.com>
> ---
> src/PVE/GuestHelpers.pm | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/src/PVE/GuestHelpers.pm b/src/PVE/GuestHelpers.pm
> index 592b4a8..c6006ba 100644
> --- a/src/PVE/GuestHelpers.pm
> +++ b/src/PVE/GuestHelpers.pm
> @@ -450,4 +450,15 @@ sub abort_guest_tasks {
> return $aborted_tasks;
> }
>
> +sub get_bridge {
> + my $net_params = shift;
> + my $param_array = [ split(/,/, $net_params) ];
> + my $bridge;
> + for my $net_param (@$param_array) {
> + $bridge = $net_param if ($net_param =~ /bridge\=/);
> + $bridge =~ s|bridge\=|| if (defined($bridge));
> + }
> + return $bridge;
> +}
> +
> 1;
net is a property string, if you want to parse it there are helpers for
that in PVE::JSONSchema.
For VMs as well as CTs we already have helpers for parsing the network
property string defined:
PVE::QemuServer::parse_net
PVE::LXC::Config::parse_lxc_network
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [pve-devel] [PATCH network 2/4] fix #5900: add helper functions
2024-12-12 17:06 ` Stefan Hanreich
@ 2024-12-16 8:35 ` Daniel Herzig
0 siblings, 0 replies; 9+ messages in thread
From: Daniel Herzig @ 2024-12-16 8:35 UTC (permalink / raw)
To: Stefan Hanreich; +Cc: Proxmox VE development discussion
Hey Stefan,
thanks for the feedback!
Stefan Hanreich <s.hanreich@proxmox.com> writes:
>
> If we do it this way (see top-level discussion), I think we should
> abstract this into the IpamPlugins itself, since this implementation is
> specific to the PVE Plugin, but that's just one type of IPAM plugin.
> Something like:
>
> Add a abstract method in the base Ipam plugin
> (Network/SDN/Ipams/Plugin.pm), i.e.
>
> PVE::Network::SDN::Ipams::Plugin::vnet_has_free_ip($range, $ipversions)
>
> Then implement it for every IPAM Plugin separately.
>
> Add a helper method to the VNet that selects the correct plugin based on
> the zone setting and then iterates over all its subnets to check for
> free IPs - something like:
>
> PVE::Network::SDN::Vnets::has_free_ip($range, $ipversions)
>
I like this thought a lot, sounds like a much cleaner and modular
solution.
>
>
> The current implementation only works for the PVE plugin and would
> actually break on zones using Netbox / Phpipam (if my brain compiler is
> correct).
>
>
Thanks for the hint -- I need to do some research on that! The code
assumes the ~key: value~ of ~dhcp: dnsmasq~ to be exclusive for IPAM
PVE.
```
for my $zone (@$zone_ids) {
push(@$dhcp_dnsmasq_zones, $zone)
if (defined(${zones_cfg}->{'ids'}->{$zone}->{'dhcp'}) &&
(${zones_cfg}->{'ids'}->{$zone}->{'dhcp'} eq 'dnsmasq'))
}
```
If this is not the case, it will affect (and not ignore as intended)
zones with Netbox/Phpipam indeed. That would be bad.
A check for ~ipam: pve~ could however be easily implemented in the same section.
>>
>> +sub defined_dhcp_ip_count_in_zone {
>> + my $zone_id = shift;
>
> even with 1 argument I think we prefer `my ($arg) = @_;`, but I haven't
> actually found a definitive answer in our style guide.
Thanks, not having any feelings here.
>
>> + my $vnets_in_zone = PVE::Network::SDN::Zones::get_vnets($zone_id);
>> + my $range_count_array;
>> + my $res;
>> + for my $vnet_id (keys %$vnets_in_zone) {
>> + my $subnets_in_vnet = PVE::Network::SDN::Vnets::get_subnets($vnet_id);
>> + for my $subnet (keys %$subnets_in_vnet) {
>> + my $dhcp_ranges = PVE::Network::SDN::Subnets::get_dhcp_ranges(${subnets_in_vnet}->{$subnet});
>> + if (scalar @$dhcp_ranges) {
>> + for my $dhcp_range (@$dhcp_ranges) {
>
> You can just iterate over @$dhcp_ranges, get_dhcp_ranges() always
> returns an array reference. If it is empty, then there are just 0
> iterations of the loop, no need to check for existence.
>
Right, this is too timid indeed :)
>> +
>> +sub available_dhcp_ips_in_zone {
>> + my $zone_id = shift;
>> + my $available_ip_count = defined_dhcp_ip_count_in_zone($zone_id);
>> + my $used_ip_count = used_dhcp_ips_in_zone($zone_id);
>> + if (!defined($available_ip_count)) {
>> + $available_ip_count = 0;
>> + }
>> + if (!defined($used_ip_count)) {
>> + $used_ip_count = 0;
>> + }
>
> If you define $res to be 0 as suggested above, then those checks become
> unnecessary, since 0 becomes the default value.
>
Very cool, thank you, I did not see that.
>> + my $vnet_ids = [ PVE::Network::SDN::Vnets::sdn_vnets_ids($vnets_cfg) ];
>
> no need for selecting the ids, you can directly iterate over the VNets:
>
Thank you for your insights and the hints very much. I cannot claim that I'm exactly happy about
the current implementation of this patch from an aesthetical point of
view by now! I will act on it further, if we consider the
'ask-for-permission' approach in general.
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [pve-devel] [PATCH guest-common 1/4] fix #5900: add helper function
2024-12-12 17:12 ` Stefan Hanreich
@ 2024-12-16 8:38 ` Daniel Herzig
0 siblings, 0 replies; 9+ messages in thread
From: Daniel Herzig @ 2024-12-16 8:38 UTC (permalink / raw)
To: Stefan Hanreich; +Cc: Proxmox VE development discussion
Hi Stefan,
thanks for the feedback.
Thanks for hinting at ~PVE::LXC::Config::parse_lxc_network~. I oversaw
that and did not want to pull ~PVE::QemuServer::parse_net~ into LXC's
deps.
Stefan Hanreich <s.hanreich@proxmox.com> writes:
> On 12/5/24 17:33, Daniel Herzig wrote:
>> This patch adds a small helper function to retrieve the bridge name
>> from the netN parameter string of a container or VM configuration.
>>
>> Signed-off-by: Daniel Herzig <d.herzig@proxmox.com>
>> ---
>> src/PVE/GuestHelpers.pm | 11 +++++++++++
>> 1 file changed, 11 insertions(+)
>>
>> diff --git a/src/PVE/GuestHelpers.pm b/src/PVE/GuestHelpers.pm
>> index 592b4a8..c6006ba 100644
>> --- a/src/PVE/GuestHelpers.pm
>> +++ b/src/PVE/GuestHelpers.pm
>> @@ -450,4 +450,15 @@ sub abort_guest_tasks {
>> return $aborted_tasks;
>> }
>>
>> +sub get_bridge {
>> + my $net_params = shift;
>> + my $param_array = [ split(/,/, $net_params) ];
>> + my $bridge;
>> + for my $net_param (@$param_array) {
>> + $bridge = $net_param if ($net_param =~ /bridge\=/);
>> + $bridge =~ s|bridge\=|| if (defined($bridge));
>> + }
>> + return $bridge;
>> +}
>> +
>> 1;
>
> net is a property string, if you want to parse it there are helpers for
> that in PVE::JSONSchema.
>
> For VMs as well as CTs we already have helpers for parsing the network
> property string defined:
>
> PVE::QemuServer::parse_net
> PVE::LXC::Config::parse_lxc_network
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2024-12-16 8:39 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-12-05 16:33 [pve-devel] [PATCH guest-common, network, container, qemu-server 0/4] fix #5900: enhance SDN auto-dhcp behaviour Daniel Herzig
2024-12-05 16:33 ` [pve-devel] [PATCH guest-common 1/4] fix #5900: add helper function Daniel Herzig
2024-12-12 17:12 ` Stefan Hanreich
2024-12-16 8:38 ` Daniel Herzig
2024-12-05 16:33 ` [pve-devel] [PATCH network 2/4] fix #5900: add helper functions Daniel Herzig
2024-12-12 17:06 ` Stefan Hanreich
2024-12-16 8:35 ` Daniel Herzig
2024-12-05 16:33 ` [pve-devel] [PATCH container 3/4] fix #5900: do not create container if dhcp range is exhausted Daniel Herzig
2024-12-05 16:33 ` [pve-devel] [PATCH qemu-server 4/4] fix #5900: do not create vm " Daniel Herzig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox