* [pve-devel] [RFC pve-cluster 1/1] add priv/macs.db
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
@ 2023-11-13 10:04 ` Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 1/9] define dhcpplugin in zone Alexandre Derumier
` (14 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
use to cache mac-ip list association.
can be use by external ipam, firewall,etc for fast lookup
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
src/PVE/Cluster.pm | 1 +
src/pmxcfs/status.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/src/PVE/Cluster.pm b/src/PVE/Cluster.pm
index cfa2583..80c4bc0 100644
--- a/src/PVE/Cluster.pm
+++ b/src/PVE/Cluster.pm
@@ -62,6 +62,7 @@ my $observed = {
'priv/token.cfg' => 1,
'priv/acme/plugins.cfg' => 1,
'priv/ipam.db' => 1,
+ 'priv/macs.db' => 1,
'/qemu-server/' => 1,
'/openvz/' => 1,
'/lxc/' => 1,
diff --git a/src/pmxcfs/status.c b/src/pmxcfs/status.c
index c8094ac..078602e 100644
--- a/src/pmxcfs/status.c
+++ b/src/pmxcfs/status.c
@@ -89,6 +89,7 @@ static memdb_change_t memdb_change_array[] = {
{ .path = "priv/tfa.cfg" },
{ .path = "priv/token.cfg" },
{ .path = "priv/ipam.db" },
+ { .path = "priv/macs.db" },
{ .path = "datacenter.cfg" },
{ .path = "vzdump.cron" },
{ .path = "vzdump.conf" },
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC pve-network 1/9] define dhcpplugin in zone
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 ` Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC qemu-server 1/5] don't remove dhcp mapping on stop Alexandre Derumier
` (13 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
simple: zone1
ipam pve
dhcp dnsmasq
simple: zone2
ipam pve
dhcp dnsmasq
This generate 1 dhcp by zone/vrf.
Don't use dhcp.cfg anymore
It's reuse node filtering from zone.
same subnets in 2 differents zones can't use
same dhcp server
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
src/PVE/API2/Network/SDN/Zones.pm | 1 +
src/PVE/Network/SDN.pm | 4 +-
src/PVE/Network/SDN/Dhcp.pm | 91 +++++++----------------
src/PVE/Network/SDN/Dhcp/Dnsmasq.pm | 32 ++++----
src/PVE/Network/SDN/Dhcp/Plugin.pm | 28 ++-----
src/PVE/Network/SDN/SubnetPlugin.pm | 4 -
src/PVE/Network/SDN/Zones/SimplePlugin.pm | 7 +-
7 files changed, 54 insertions(+), 113 deletions(-)
diff --git a/src/PVE/API2/Network/SDN/Zones.pm b/src/PVE/API2/Network/SDN/Zones.pm
index 4c8b7e1..1c3356e 100644
--- a/src/PVE/API2/Network/SDN/Zones.pm
+++ b/src/PVE/API2/Network/SDN/Zones.pm
@@ -99,6 +99,7 @@ __PACKAGE__->register_method ({
reversedns => { type => 'string', optional => 1},
dnszone => { type => 'string', optional => 1},
ipam => { type => 'string', optional => 1},
+ dhcp => { type => 'string', optional => 1},
pending => { optional => 1},
state => { type => 'string', optional => 1},
nodes => { type => 'string', optional => 1},
diff --git a/src/PVE/Network/SDN.pm b/src/PVE/Network/SDN.pm
index 5c059bc..c306527 100644
--- a/src/PVE/Network/SDN.pm
+++ b/src/PVE/Network/SDN.pm
@@ -150,15 +150,13 @@ 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, dhcps => $dhcp };
+ $cfg = { version => $version, vnets => $vnets, zones => $zones, controllers => $controllers, subnets => $subnets };
cfs_write_file($running_cfg, $cfg);
}
diff --git a/src/PVE/Network/SDN/Dhcp.pm b/src/PVE/Network/SDN/Dhcp.pm
index b92c73a..e4c4078 100644
--- a/src/PVE/Network/SDN/Dhcp.pm
+++ b/src/PVE/Network/SDN/Dhcp.pm
@@ -20,41 +20,6 @@ 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) = @_;
@@ -127,58 +92,52 @@ sub remove_mapping {
sub regenerate_config {
my ($reload) = @_;
- my $dhcps = PVE::Network::SDN::Dhcp::config();
- my $subnets = PVE::Network::SDN::Subnets::config();
+ my $cfg = PVE::Network::SDN::running_config();
- my $plugins = PVE::Network::SDN::Dhcp::Plugin->lookup_types();
+ my $zone_cfg = $cfg->{zones};
+ my $subnet_cfg = $cfg->{subnets};
+ return if !$zone_cfg && !$subnet_cfg;
my $nodename = PVE::INotify::nodename();
+ my $plugins = PVE::Network::SDN::Dhcp::Plugin->lookup_types();
+
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});
+ foreach my $zoneid (sort keys %{$zone_cfg->{ids}}) {
+ my $zone = $zone_cfg->{ids}->{$zoneid};
+ next if defined($zone->{nodes}) && !$zone->{nodes}->{$nodename};
- eval { $plugin->before_configure($dhcp_config) };
- die "Could not run before_configure for DHCP server $dhcp_id $@\n" if $@;
- }
+ my $dhcp_plugin_name = $zone->{dhcp};
+ my $dhcp_plugin = PVE::Network::SDN::Dhcp::Plugin->lookup($dhcp_plugin_name);
- 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'};
+ eval { $dhcp_plugin->before_configure($zoneid) };
+ die "Could not run before_configure for DHCP server $zoneid $@\n" if $@;
- 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});
+ foreach my $subnet_id (keys %{$subnet_cfg->{ids}}) {
+ my $subnet_config = PVE::Network::SDN::Subnets::sdn_subnets_config($subnet_cfg, $subnet_id);
+ my ($zone, $subnet_network, $subnet_mask) = split(/-/, $subnet_id);
+ next if $zone ne $zoneid;
+ next if !$subnet_config->{'dhcp-range'};
- next if $dhcp_config->{node} && !grep(/^$nodename$/, @{$dhcp_config->{node}});
+ eval { $dhcp_plugin->configure_subnet($zoneid, $subnet_config) };
+ warn "Could not configure subnet $subnet_id: $@\n" if $@;
- 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;
+ foreach my $dhcp_range (@{$subnet_config->{'dhcp-range'}}) {
+ eval { $dhcp_plugin->configure_range($zoneid, $subnet_config, $dhcp_range) };
+ warn "Could not configure DHCP range for $subnet_id: $@\n" if $@;
}
-
- 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 { $dhcp_plugin->after_configure($zoneid) };
+ warn "Could not run after_configure for DHCP server $zoneid $@\n" if $@;
- eval { $plugin->after_configure($dhcp_config) };
- warn "Could not run after_configure for DHCP server $dhcp_id $@\n" if $@;
}
foreach my $plugin_name (@$plugins) {
diff --git a/src/PVE/Network/SDN/Dhcp/Dnsmasq.pm b/src/PVE/Network/SDN/Dhcp/Dnsmasq.pm
index af109b8..64895ef 100644
--- a/src/PVE/Network/SDN/Dhcp/Dnsmasq.pm
+++ b/src/PVE/Network/SDN/Dhcp/Dnsmasq.pm
@@ -19,9 +19,9 @@ sub type {
}
sub del_ip_mapping {
- my ($class, $dhcp_config, $mac) = @_;
+ my ($class, $dhcpid, $mac) = @_;
- my $ethers_file = "$DNSMASQ_CONFIG_ROOT/$dhcp_config->{id}/ethers";
+ my $ethers_file = "$DNSMASQ_CONFIG_ROOT/$dhcpid/ethers";
my $ethers_tmp_file = "$ethers_file.tmp";
my $removeFn = sub {
@@ -48,13 +48,13 @@ sub del_ip_mapping {
return;
}
- my $service_name = "dnsmasq\@$dhcp_config->{id}";
+ my $service_name = "dnsmasq\@$dhcpid";
PVE::Tools::run_command(['systemctl', 'reload', $service_name]);
}
sub add_ip_mapping {
- my ($class, $dhcp_config, $mac, $ip) = @_;
- my $ethers_file = "$DNSMASQ_CONFIG_ROOT/$dhcp_config->{id}/ethers";
+ my ($class, $dhcpid, $mac, $ip) = @_;
+ my $ethers_file = "$DNSMASQ_CONFIG_ROOT/$dhcpid/ethers";
my $appendFn = sub {
open(my $fh, '>>', $ethers_file) or die "Could not open file '$ethers_file' $!\n";
@@ -69,12 +69,12 @@ sub add_ip_mapping {
return;
}
- my $service_name = "dnsmasq\@$dhcp_config->{id}";
+ my $service_name = "dnsmasq\@$dhcpid";
PVE::Tools::run_command(['systemctl', 'reload', $service_name]);
}
sub configure_subnet {
- my ($class, $dhcp_config, $subnet_config) = @_;
+ my ($class, $dhcpid, $subnet_config) = @_;
die "No gateway defined for subnet $subnet_config->{id}"
if !$subnet_config->{gateway};
@@ -98,15 +98,15 @@ sub configure_subnet {
if $subnet_config->{'dhcp-dns-server'};
PVE::Tools::file_set_contents(
- "$DNSMASQ_CONFIG_ROOT/$dhcp_config->{id}/10-$subnet_config->{id}.conf",
+ "$DNSMASQ_CONFIG_ROOT/$dhcpid/10-$subnet_config->{id}.conf",
join("\n", @dnsmasq_config) . "\n"
);
}
sub configure_range {
- my ($class, $dhcp_config, $subnet_config, $range_config) = @_;
+ my ($class, $dhcpid, $subnet_config, $range_config) = @_;
- my $range_file = "$DNSMASQ_CONFIG_ROOT/$dhcp_config->{id}/10-$subnet_config->{id}.ranges.conf",
+ my $range_file = "$DNSMASQ_CONFIG_ROOT/$dhcpid/10-$subnet_config->{id}.ranges.conf",
my $tag = $subnet_config->{id};
open(my $fh, '>>', $range_file) or die "Could not open file '$range_file' $!\n";
@@ -115,9 +115,9 @@ sub configure_range {
}
sub before_configure {
- my ($class, $dhcp_config) = @_;
+ my ($class, $dhcpid) = @_;
- my $config_directory = "$DNSMASQ_CONFIG_ROOT/$dhcp_config->{id}";
+ my $config_directory = "$DNSMASQ_CONFIG_ROOT/$dhcpid";
mkdir($config_directory, 755) if !-d $config_directory;
@@ -127,7 +127,7 @@ DNSMASQ_OPTS="--conf-file=/dev/null"
CFG
PVE::Tools::file_set_contents(
- "$DNSMASQ_DEFAULT_ROOT/dnsmasq.$dhcp_config->{id}",
+ "$DNSMASQ_DEFAULT_ROOT/dnsmasq.$dhcpid",
$default_config
);
@@ -136,7 +136,7 @@ except-interface=lo
bind-dynamic
no-resolv
no-hosts
-dhcp-leasefile=$DNSMASQ_LEASE_ROOT/dnsmasq.$dhcp_config->{id}.leases
+dhcp-leasefile=$DNSMASQ_LEASE_ROOT/dnsmasq.$dhcpid.leases
dhcp-hostsfile=$config_directory/ethers
dhcp-ignore=tag:!known
@@ -163,9 +163,9 @@ CFG
}
sub after_configure {
- my ($class, $dhcp_config) = @_;
+ my ($class, $dhcpid) = @_;
- my $service_name = "dnsmasq\@$dhcp_config->{id}";
+ my $service_name = "dnsmasq\@$dhcpid";
PVE::Tools::run_command(['systemctl', 'enable', $service_name]);
PVE::Tools::run_command(['systemctl', 'restart', $service_name]);
diff --git a/src/PVE/Network/SDN/Dhcp/Plugin.pm b/src/PVE/Network/SDN/Dhcp/Plugin.pm
index 75979e8..7b9e9b7 100644
--- a/src/PVE/Network/SDN/Dhcp/Plugin.pm
+++ b/src/PVE/Network/SDN/Dhcp/Plugin.pm
@@ -8,23 +8,13 @@ use PVE::JSONSchema qw(get_standard_option);
use base qw(PVE::SectionConfig);
-PVE::Cluster::cfs_register_file('sdn/dhcp.cfg',
- sub { __PACKAGE__->parse_config(@_); },
- sub { __PACKAGE__->write_config(@_); },
-);
-
my $defaultData = {
propertyList => {
- type => {
- description => "Plugin type.",
- format => 'pve-configid',
- type => 'string',
- },
- node => {
- type => 'array',
- description => 'A list of nodes where this DHCP server should be deployed',
- items => get_standard_option('pve-node'),
- },
+ type => {
+ description => "Plugin type.",
+ format => 'pve-configid',
+ type => 'string',
+ },
},
};
@@ -32,14 +22,6 @@ sub private {
return $defaultData;
}
-sub options {
- return {
- node => {
- optional => 1,
- },
- };
-}
-
sub add_ip_mapping {
my ($class, $dhcp_config, $mac, $ip) = @_;
die 'implement in sub class';
diff --git a/src/PVE/Network/SDN/SubnetPlugin.pm b/src/PVE/Network/SDN/SubnetPlugin.pm
index 47b8406..8447ece 100644
--- a/src/PVE/Network/SDN/SubnetPlugin.pm
+++ b/src/PVE/Network/SDN/SubnetPlugin.pm
@@ -62,10 +62,6 @@ sub private {
}
my $dhcp_range_fmt = {
- server => {
- type => 'pve-configid',
- description => 'ID of the DHCP server responsible for managing this range',
- },
'start-address' => {
type => 'ip',
description => 'Start address for the DHCP IP range',
diff --git a/src/PVE/Network/SDN/Zones/SimplePlugin.pm b/src/PVE/Network/SDN/Zones/SimplePlugin.pm
index 4922903..f30278c 100644
--- a/src/PVE/Network/SDN/Zones/SimplePlugin.pm
+++ b/src/PVE/Network/SDN/Zones/SimplePlugin.pm
@@ -26,7 +26,11 @@ sub properties {
dnszone => {
type => 'string', format => 'dns-name',
description => "dns domain zone ex: mydomain.com",
- }
+ },
+ dhcp => {
+ type => 'pve-configid',
+ description => 'ID of the DHCP server responsible for managing this range',
+ },
};
}
@@ -38,6 +42,7 @@ sub options {
reversedns => { optional => 1 },
dnszone => { optional => 1 },
ipam => { optional => 1 },
+ dhcp => { optional => 1 },
};
}
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC qemu-server 1/5] don't remove dhcp mapping on stop
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 ` 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
` (12 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
vm-network-scripts/pve-bridgedown | 19 -------------------
1 file changed, 19 deletions(-)
diff --git a/vm-network-scripts/pve-bridgedown b/vm-network-scripts/pve-bridgedown
index a220660..d18d88f 100755
--- a/vm-network-scripts/pve-bridgedown
+++ b/vm-network-scripts/pve-bridgedown
@@ -4,13 +4,6 @@ use strict;
use warnings;
use PVE::Network;
-my $have_sdn;
-eval {
- require PVE::Network::SDN::Zones;
- require PVE::Network::SDN::Dhcp;
- $have_sdn = 1;
-};
-
my $iface = shift;
die "no interface specified\n" if !$iface;
@@ -18,18 +11,6 @@ die "no interface specified\n" if !$iface;
die "got strange interface name '$iface'\n"
if $iface !~ m/^tap(\d+)i(\d+)$/;
-my $vmid = $1;
-my $netid = "net$2";
-
-my $conf = PVE::QemuConfig->load_config($vmid);
-
-my $netconf = $conf->{$netid};
-my $net = PVE::QemuServer::parse_net($netconf);
-
-if ($have_sdn) {
- PVE::Network::SDN::Dhcp::remove_mapping($net->{bridge}, $net->{macaddr});
-}
-
PVE::Network::tap_unplug($iface);
exit 0;
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC pve-network 2/9] dhcp : add|del_ip_mapping: only add|del dhcp reservervation
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
` (2 preceding siblings ...)
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 ` Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC qemu-server 2/5] vmnic add|remove : add|del ip in ipam Alexandre Derumier
` (11 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
don't try to add|del ip from ipam here
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
src/PVE/Network/SDN/Dhcp.pm | 75 +++++++++----------------------------
1 file changed, 18 insertions(+), 57 deletions(-)
diff --git a/src/PVE/Network/SDN/Dhcp.pm b/src/PVE/Network/SDN/Dhcp.pm
index e4c4078..1c32fec 100644
--- a/src/PVE/Network/SDN/Dhcp.pm
+++ b/src/PVE/Network/SDN/Dhcp.pm
@@ -21,72 +21,33 @@ PVE::Network::SDN::Dhcp::Dnsmasq->register();
PVE::Network::SDN::Dhcp::Dnsmasq->init();
sub add_mapping {
- my ($vmid, $vnet, $mac) = @_;
+ my ($vmid, $vnetid, $mac, $ip) = @_;
- my $vnet_config = PVE::Network::SDN::Vnets::get_vnet($vnet, 1);
- return if !$vnet_config;
+ my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
+ my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
+ my $zoneid = $vnet->{zone};
+ my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
- my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnet, 1);
+ my $dhcptype = $zone->{dhcp};
+ return if !$dhcptype;
- 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;
- }
- }
+ my $dhcp_plugin = PVE::Network::SDN::Dhcp::Plugin->lookup($dhcptype);
+ $dhcp_plugin->add_ip_mapping($zoneid, $mac, $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 ($vnetid, $mac) = @_;
- my $ipam_plugin = PVE::Network::SDN::Ipams::Plugin->lookup('pve');
- $ipam_plugin->del_dhcp_ip($subnet_config, $mac);
+ my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
+ my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
+ my $zoneid = $vnet->{zone};
+ my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
- foreach my $dhcp_range (@{$subnet_config->{'dhcp-range'}}) {
- my $dhcp_config = PVE::Network::SDN::Dhcp::get_dhcp($dhcp_range->{server});
+ my $dhcptype = $zone->{dhcp};
+ return if !$dhcptype;
- 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);
- }
- }
+ my $dhcp_plugin = PVE::Network::SDN::Dhcp::Plugin->lookup($dhcptype);
+ $dhcp_plugin->del_ip_mapping($zoneid, $mac);
}
sub regenerate_config {
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC qemu-server 2/5] vmnic add|remove : add|del ip in ipam
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
` (3 preceding siblings ...)
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 ` 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
` (10 subsequent siblings)
15 siblings, 1 reply; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
PVE/QemuServer.pm | 38 +++++++++++++++++++++++++++++++++++
vm-network-scripts/pve-bridge | 2 +-
2 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 31e3919..5c109b1 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -64,6 +64,8 @@ use PVE::QemuServer::USB;
my $have_sdn;
eval {
require PVE::Network::SDN::Zones;
+ require PVE::Network::SDN::Vnets;
+ require PVE::Network::SDN::Dhcp;
$have_sdn = 1;
};
@@ -4991,6 +4993,11 @@ sub vmconfig_hotplug_pending {
} elsif ($opt =~ m/^net(\d+)$/) {
die "skip\n" if !$hotplug_features->{network};
vm_deviceunplug($vmid, $conf, $opt);
+ if($have_sdn) {
+ my $net = PVE::QemuServer::parse_net($conf->{$opt});
+ PVE::Network::SDN::Dhcp::remove_mapping($net->{bridge}, $net->{macaddr});
+ PVE::Network::SDN::Vnets::del_ips_from_mac($net->{bridge}, $net->{macaddr}, $conf->{name});
+ }
} elsif (is_valid_drivename($opt)) {
die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
vm_deviceunplug($vmid, $conf, $opt);
@@ -5196,6 +5203,12 @@ sub vmconfig_apply_pending {
die "internal error";
} elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
+ } elsif (defined($conf->{$opt}) && $opt =~ m/^net\d+$/) {
+ if($have_sdn) {
+ my $net = PVE::QemuServer::parse_net($conf->{$opt});
+ PVE::Network::SDN::Dhcp::remove_mapping($net->{bridge}, $net->{macaddr});
+ PVE::Network::SDN::Vnets::del_ips_from_mac($net->{bridge}, $net->{macaddr}, $conf->{name});
+ }
}
};
if (my $err = $@) {
@@ -5215,6 +5228,21 @@ sub vmconfig_apply_pending {
eval {
if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
+ } elsif (defined($conf->{pending}->{$opt}) && $opt =~ m/^net\d+$/) {
+ if($have_sdn) {
+ my $new_net = PVE::QemuServer::parse_net($conf->{pending}->{$opt});
+ if ($conf->{$opt}){
+ my $old_net = PVE::QemuServer::parse_net($conf->{$opt});
+
+ if ($old_net->{bridge} ne $new_net->{bridge} ||
+ $old_net->{macaddr} ne $new_net->{macaddr}) {
+ PVE::Network::SDN::Dhcp::remove_mapping($old_net->{bridge}, $old_net->{macaddr});
+ PVE::Network::SDN::Vnets::del_ips_from_mac($old_net->{bridge}, $old_net->{macaddr}, $conf->{name});
+ }
+ }
+ #fixme: reuse ip if mac change && same bridge
+ PVE::Network::SDN::Vnets::add_next_free_cidr($new_net->{bridge}, $conf->{name}, $new_net->{macaddr}, "vmid:$vmid", undef, 1);
+ }
}
};
if (my $err = $@) {
@@ -5258,6 +5286,13 @@ sub vmconfig_update_net {
# for non online change, we try to hot-unplug
die "skip\n" if !$hotplug;
vm_deviceunplug($vmid, $conf, $opt);
+
+ # fixme: force device_unplug on bridge change if mac is present in dhcp, to force guest os to retrieve a new ip
+ if($have_sdn) {
+ PVE::Network::SDN::Dhcp::remove_mapping($oldnet->{bridge}, $oldnet->{macaddr});
+ PVE::Network::SDN::Vnets::del_ips_from_mac($oldnet->{bridge}, $oldnet->{macaddr}, $conf->{name});
+ }
+
} else {
die "internal error" if $opt !~ m/net(\d+)/;
@@ -5289,6 +5324,9 @@ sub vmconfig_update_net {
}
if ($hotplug) {
+ if ($have_sdn) {
+ PVE::Network::SDN::Vnets::add_next_free_cidr($newnet->{bridge}, $conf->{name}, $newnet->{macaddr}, "vmid:$vmid", undef, 1);
+ }
vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
} else {
die "skip\n";
diff --git a/vm-network-scripts/pve-bridge b/vm-network-scripts/pve-bridge
index 5c8acdf..c6b3ea8 100755
--- a/vm-network-scripts/pve-bridge
+++ b/vm-network-scripts/pve-bridge
@@ -45,7 +45,7 @@ my $net = PVE::QemuServer::parse_net($netconf);
die "unable to parse network config '$netid'\n" if !$net;
if ($have_sdn) {
- PVE::Network::SDN::Dhcp::add_mapping($vmid, $net->{bridge}, $net->{macaddr});
+ PVE::Network::SDN::Dhcp::add_mapping($net->{bridge}, $net->{macaddr});
PVE::Network::SDN::Zones::tap_create($iface, $net->{bridge});
PVE::Network::SDN::Zones::tap_plug($iface, $net->{bridge}, $net->{tag}, $net->{firewall}, $net->{trunks}, $net->{rate});
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [pve-devel] [RFC qemu-server 2/5] vmnic add|remove : add|del ip in ipam
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
0 siblings, 0 replies; 20+ messages in thread
From: Stefan Hanreich @ 2023-11-13 16:14 UTC (permalink / raw)
To: Proxmox VE development discussion, Alexandre Derumier
On 11/13/23 11:04, Alexandre Derumier wrote:
> if ($have_sdn) {
> - PVE::Network::SDN::Dhcp::add_mapping($vmid, $net->{bridge}, $net->{macaddr});
> + PVE::Network::SDN::Dhcp::add_mapping($net->{bridge}, $net->{macaddr});
>
> PVE::Network::SDN::Zones::tap_create($iface, $net->{bridge});
> PVE::Network::SDN::Zones::tap_plug($iface, $net->{bridge}, $net->{tag}, $net->{firewall}, $net->{trunks}, $net->{rate});
This call will fail if you have SDN enabled, but want to add a NIC on a
non-simple zone or a NIC on a Linux bridge. I have already fixed this
issue in my version of the patch series, so no need for you to do anything.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC qemu-server 3/5] vm_start : vm-network-scripts: get ip from ipam and add dhcp reservation
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
` (4 preceding siblings ...)
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 10:04 ` Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 3/9] vnet|subnet: add_next_free_ip : implement dhcprange ipam search Alexandre Derumier
` (9 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
vm-network-scripts/pve-bridge | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/vm-network-scripts/pve-bridge b/vm-network-scripts/pve-bridge
index c6b3ea8..24efaad 100755
--- a/vm-network-scripts/pve-bridge
+++ b/vm-network-scripts/pve-bridge
@@ -10,6 +10,7 @@ use PVE::Network;
my $have_sdn;
eval {
require PVE::Network::SDN::Zones;
+ require PVE::Network::SDN::Vnets;
require PVE::Network::SDN::Dhcp;
$have_sdn = 1;
};
@@ -45,7 +46,8 @@ my $net = PVE::QemuServer::parse_net($netconf);
die "unable to parse network config '$netid'\n" if !$net;
if ($have_sdn) {
- PVE::Network::SDN::Dhcp::add_mapping($net->{bridge}, $net->{macaddr});
+ my ($ip4, $ip6) = PVE::Network::SDN::Vnets::get_ips_from_mac($net->{bridge}, $net->{macaddr});
+ PVE::Network::SDN::Dhcp::add_mapping($net->{bridge}, $net->{macaddr}, $ip4, $ip6);
PVE::Network::SDN::Zones::tap_create($iface, $net->{bridge});
PVE::Network::SDN::Zones::tap_plug($iface, $net->{bridge}, $net->{tag}, $net->{firewall}, $net->{trunks}, $net->{rate});
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC pve-network 3/9] vnet|subnet: add_next_free_ip : implement dhcprange ipam search
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
` (5 preceding siblings ...)
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
2023-11-13 10:04 ` [pve-devel] [RFC qemu-server 4/5] api2: create|restore|clone: add_free_ip Alexandre Derumier
` (8 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
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
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC qemu-server 4/5] api2: create|restore|clone: add_free_ip
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
` (6 preceding siblings ...)
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 3/9] vnet|subnet: add_next_free_ip : implement dhcprange ipam search Alexandre Derumier
@ 2023-11-13 10:04 ` Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 4/9] ipam : add macs.db for fast mac lookup Alexandre Derumier
` (7 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
PVE/API2/Qemu.pm | 6 ++++++
PVE/QemuServer.pm | 15 +++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 38bdaab..a0f8243 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -991,6 +991,8 @@ __PACKAGE__->register_method({
eval { PVE::QemuServer::template_create($vmid, $restored_conf) };
warn $@ if $@;
}
+
+ PVE::QemuServer::create_ifaces_ipams_ips($restored_conf, $vmid) if $unique;
};
# ensure no old replication state are exists
@@ -1066,6 +1068,8 @@ __PACKAGE__->register_method({
}
PVE::AccessControl::add_vm_to_pool($vmid, $pool) if $pool;
+
+ PVE::QemuServer::create_ifaces_ipams_ips($conf, $vmid);
};
PVE::QemuConfig->lock_config_full($vmid, 1, $realcmd);
@@ -3763,6 +3767,8 @@ __PACKAGE__->register_method({
PVE::QemuConfig->write_config($newid, $newconf);
+ PVE::QemuServer::create_ifaces_ipams_ips($newconf, $vmid);
+
if ($target) {
# always deactivate volumes - avoid lvm LVs to be active on several nodes
PVE::Storage::deactivate_volumes($storecfg, $vollist, $snapname) if !$running;
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 5c109b1..511f644 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -8624,4 +8624,19 @@ sub del_nets_bridge_fdb {
}
}
+sub create_ifaces_ipams_ips {
+ my ($conf, $vmid) = @_;
+
+ return if !$have_sdn;
+
+ foreach my $opt (keys %$conf) {
+ if ($opt =~ m/^net(\d+)$/) {
+ my $value = $conf->{$opt};
+ my $net = PVE::QemuServer::parse_net($value);
+ eval { PVE::Network::SDN::Vnets::add_next_free_cidr($net->{bridge}, $conf->{name}, $net->{macaddr}, "vmid: $vmid", undef, 1) };
+ warn $@ if $@;
+ }
+ }
+}
+
1;
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC pve-network 4/9] ipam : add macs.db for fast mac lookup
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
` (7 preceding siblings ...)
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 ` Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 5/9] ipam : add get_ips_from_mac Alexandre Derumier
` (6 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
src/PVE/Network/SDN/Ipams.pm | 61 +++++++++++++++++++++++++-
src/PVE/Network/SDN/Ipams/PVEPlugin.pm | 4 +-
src/PVE/Network/SDN/Subnets.pm | 8 +++-
src/test/run_test_subnets.pl | 6 +++
4 files changed, 75 insertions(+), 4 deletions(-)
diff --git a/src/PVE/Network/SDN/Ipams.pm b/src/PVE/Network/SDN/Ipams.pm
index e8a4b0b..a459441 100644
--- a/src/PVE/Network/SDN/Ipams.pm
+++ b/src/PVE/Network/SDN/Ipams.pm
@@ -4,9 +4,10 @@ use strict;
use warnings;
use JSON;
+use Net::IP;
use PVE::Tools qw(extract_param dir_glob_regex run_command);
-use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
use PVE::Network;
use PVE::Network::SDN::Ipams::PVEPlugin;
@@ -19,6 +20,64 @@ PVE::Network::SDN::Ipams::NetboxPlugin->register();
PVE::Network::SDN::Ipams::PhpIpamPlugin->register();
PVE::Network::SDN::Ipams::Plugin->init();
+my $macdb_filename = 'priv/macs.db';
+
+cfs_register_file($macdb_filename, \&json_reader, \&json_writer);
+
+sub json_reader {
+ my ($filename, $data) = @_;
+
+ return defined($data) && length($data) > 0 ? decode_json($data) : {};
+}
+
+sub json_writer {
+ my ($filename, $data) = @_;
+
+ return encode_json($data);
+}
+
+sub read_macdb {
+ my () = @_;
+
+ return cfs_read_file($macdb_filename);
+}
+
+sub write_macdb {
+ my ($data) = @_;
+
+ cfs_write_file($macdb_filename, $data);
+}
+
+sub add_cache_mac_ip {
+ my ($mac, $ip) = @_;
+
+ cfs_lock_file($macdb_filename, undef, sub {
+ my $db = read_macdb();
+ if (Net::IP::ip_is_ipv4($ip)) {
+ $db->{macs}->{$mac}->{ip4} = $ip;
+ } else {
+ $db->{macs}->{$mac}->{ip6} = $ip;
+ }
+ write_macdb($db);
+ });
+ warn "$@" if $@;
+}
+
+sub del_cache_mac_ip {
+ my ($mac, $ip) = @_;
+
+ cfs_lock_file($macdb_filename, undef, sub {
+ my $db = read_macdb();
+ if (Net::IP::ip_is_ipv4($ip)) {
+ delete $db->{macs}->{$mac}->{ip4};
+ } else {
+ delete $db->{macs}->{$mac}->{ip6};
+ }
+ delete $db->{macs}->{$mac} if !defined($db->{macs}->{$mac}->{ip4}) && !defined($db->{macs}->{$mac}->{ip6});
+ write_macdb($db);
+ });
+ warn "$@" if $@;
+}
sub sdn_ipams_config {
my ($cfg, $id, $noerr) = @_;
diff --git a/src/PVE/Network/SDN/Ipams/PVEPlugin.pm b/src/PVE/Network/SDN/Ipams/PVEPlugin.pm
index 37b47e4..5790715 100644
--- a/src/PVE/Network/SDN/Ipams/PVEPlugin.pm
+++ b/src/PVE/Network/SDN/Ipams/PVEPlugin.pm
@@ -173,13 +173,14 @@ sub add_range_next_freeip {
my $ip = new Net::IP ("$range->{'start-address'} - $range->{'end-address'}")
or die "Invalid IP address(es) in Range!\n";
+ my $mac = $data->{mac};
do {
my $ip_address = $ip->ip();
if (!$dbsubnet->{ips}->{$ip_address}) {
$dbsubnet->{ips}->{$ip_address} = $data;
write_db($db);
-
+
return $ip_address;
}
} while (++$ip);
@@ -236,7 +237,6 @@ sub del_ip {
die "IP '$ip' does not exist in IPAM DB\n" if !defined($dbsubnet->{ips}->{$ip});
delete $dbsubnet->{ips}->{$ip};
-
write_db($db);
});
die "$@" if $@;
diff --git a/src/PVE/Network/SDN/Subnets.pm b/src/PVE/Network/SDN/Subnets.pm
index 9f953a6..b2125a1 100644
--- a/src/PVE/Network/SDN/Subnets.pm
+++ b/src/PVE/Network/SDN/Subnets.pm
@@ -240,6 +240,9 @@ sub add_next_free_ip {
};
die $@ if $@;
+
+ eval { PVE::Network::SDN::Ipams::add_cache_mac_ip($mac, $ip); };
+ warn $@ if $@;
}
eval {
@@ -364,7 +367,7 @@ sub update_ip {
}
sub del_ip {
- my ($zone, $subnetid, $subnet, $ip, $hostname, $skipdns) = @_;
+ my ($zone, $subnetid, $subnet, $ip, $hostname, $mac, $skipdns) = @_;
return if !$subnet || !$ip;
@@ -389,6 +392,9 @@ sub del_ip {
my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
$plugin->del_ip($plugin_config, $subnetid, $subnet, $ip);
+
+ eval { PVE::Network::SDN::Ipams::del_cache_mac_ip($mac, $ip); };
+ warn $@ if $@;
}
eval {
diff --git a/src/test/run_test_subnets.pl b/src/test/run_test_subnets.pl
index 9692f4c..c98359a 100755
--- a/src/test/run_test_subnets.pl
+++ b/src/test/run_test_subnets.pl
@@ -109,6 +109,12 @@ foreach my $path (@plugins) {
my $ipam_config = read_sdn_config ("$path/ipam_config");
return $ipam_config;
},
+ add_cache_mac_ip => sub {
+ return;
+ },
+ del_cache_mac_ip => sub {
+ return;
+ }
);
## add_subnet
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC pve-network 5/9] ipam : add get_ips_from_mac
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
` (8 preceding siblings ...)
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 ` Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC qemu-server 5/5] vm_destroy: delete ip from ipam && dhcp Alexandre Derumier
` (5 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
First look ip mac.db cache
if not, lookup in ipam , and cache result in mac.db
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
src/PVE/Network/SDN/Dhcp.pm | 8 ++----
src/PVE/Network/SDN/Ipams.pm | 19 +++++++++++--
src/PVE/Network/SDN/Ipams/NetboxPlugin.pm | 25 +++++++++++++++++
src/PVE/Network/SDN/Ipams/PVEPlugin.pm | 32 ++++++++++++++++++++++
src/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm | 29 ++++++++++++++++++++
src/PVE/Network/SDN/Ipams/Plugin.pm | 6 ++++
src/PVE/Network/SDN/Vnets.pm | 11 ++++++++
7 files changed, 123 insertions(+), 7 deletions(-)
diff --git a/src/PVE/Network/SDN/Dhcp.pm b/src/PVE/Network/SDN/Dhcp.pm
index 1c32fec..b3c2751 100644
--- a/src/PVE/Network/SDN/Dhcp.pm
+++ b/src/PVE/Network/SDN/Dhcp.pm
@@ -6,7 +6,6 @@ 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);
@@ -21,9 +20,8 @@ PVE::Network::SDN::Dhcp::Dnsmasq->register();
PVE::Network::SDN::Dhcp::Dnsmasq->init();
sub add_mapping {
- my ($vmid, $vnetid, $mac, $ip) = @_;
+ my ($vnetid, $mac, $ip4, $ip6) = @_;
- my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
my $zoneid = $vnet->{zone};
my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
@@ -32,13 +30,13 @@ sub add_mapping {
return if !$dhcptype;
my $dhcp_plugin = PVE::Network::SDN::Dhcp::Plugin->lookup($dhcptype);
- $dhcp_plugin->add_ip_mapping($zoneid, $mac, $ip);
+ $dhcp_plugin->add_ip_mapping($zoneid, $mac, $ip4) if $ip4;
+ $dhcp_plugin->add_ip_mapping($zoneid, $mac, $ip6) if $ip6;
}
sub remove_mapping {
my ($vnetid, $mac) = @_;
- my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
my $zoneid = $vnet->{zone};
my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
diff --git a/src/PVE/Network/SDN/Ipams.pm b/src/PVE/Network/SDN/Ipams.pm
index a459441..926df90 100644
--- a/src/PVE/Network/SDN/Ipams.pm
+++ b/src/PVE/Network/SDN/Ipams.pm
@@ -98,8 +98,8 @@ sub config {
}
sub get_plugin_config {
- my ($vnet) = @_;
- my $ipamid = $vnet->{ipam};
+ my ($zone) = @_;
+ my $ipamid = $zone->{ipam};
my $ipam_cfg = PVE::Network::SDN::Ipams::config();
return $ipam_cfg->{ids}->{$ipamid};
}
@@ -124,5 +124,20 @@ sub complete_sdn_vnet {
return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::Vnets::sdn_ipams_ids($cfg) ];
}
+sub get_ips_from_mac {
+ my ($mac, $zoneid, $zone) = @_;
+
+ my $macdb = read_macdb();
+ return ($macdb->{macs}->{$mac}->{ip4}, $macdb->{macs}->{$mac}->{ip6}) if $macdb->{macs}->{$mac};
+
+ my $plugin_config = get_plugin_config($zone);
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+ ($macdb->{macs}->{$mac}->{ip4}, $macdb->{macs}->{$mac}->{ip6}) = $plugin->get_ips_from_mac($plugin_config, $mac, $zoneid);
+
+ write_macdb($macdb);
+
+ return ($macdb->{macs}->{$mac}->{ip4}, $macdb->{macs}->{$mac}->{ip6});
+}
+
1;
diff --git a/src/PVE/Network/SDN/Ipams/NetboxPlugin.pm b/src/PVE/Network/SDN/Ipams/NetboxPlugin.pm
index 2099a7f..e6cc647 100644
--- a/src/PVE/Network/SDN/Ipams/NetboxPlugin.pm
+++ b/src/PVE/Network/SDN/Ipams/NetboxPlugin.pm
@@ -198,6 +198,31 @@ sub del_ip {
}
}
+sub get_ips_from_mac {
+ my ($class, $plugin_config, $mac, $zoneid) = @_;
+
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
+
+ my $ip4 = undef;
+ my $ip6 = undef;
+
+ my $data = PVE::Network::SDN::api_request("GET", "$url/ipam/ip-addresses/?description__ic=$mac", $headers);
+ for my $ip (@{$data->{results}}) {
+ if ($ip->{family}->{value} == 4 && !$ip4) {
+ ($ip4, undef) = split(/\//, $ip->{address});
+ }
+
+ if ($ip->{family}->{value} == 6 && !$ip6) {
+ ($ip6, undef) = split(/\//, $ip->{address});
+ }
+ }
+
+ return ($ip4, $ip6);
+}
+
+
sub verify_api {
my ($class, $plugin_config) = @_;
diff --git a/src/PVE/Network/SDN/Ipams/PVEPlugin.pm b/src/PVE/Network/SDN/Ipams/PVEPlugin.pm
index 5790715..0bc2b65 100644
--- a/src/PVE/Network/SDN/Ipams/PVEPlugin.pm
+++ b/src/PVE/Network/SDN/Ipams/PVEPlugin.pm
@@ -242,6 +242,38 @@ sub del_ip {
die "$@" if $@;
}
+sub get_ips_from_mac {
+ my ($class, $plugin_config, $mac, $zoneid) = @_;
+
+ #just in case, as this should already be cached in local macs.db
+
+ my $ip4 = undef;
+ my $ip6 = undef;
+
+ my $db = read_db();
+ die "zone $zoneid don't exist in ipam db" if !$db->{zones}->{$zoneid};
+ my $dbzone = $db->{zones}->{$zoneid};
+ my $subnets = $dbzone->{subnets};
+
+ for my $subnet ( keys %$subnets) {
+ next if Net::IP::ip_is_ipv4($subnet) && $ip4;
+ next if $ip6;
+ my $ips = $subnets->{$subnet}->{ips};
+ for my $ip (keys %$ips) {
+ my $ipobject = $ips->{$ip};
+ if ($ipobject->{mac} && $ipobject->{mac} eq $mac) {
+ if (Net::IP::ip_is_ipv4($ip)) {
+ $ip4 = $ip;
+ } else {
+ $ip6 = $ip;
+ }
+ }
+ }
+ last if $ip4 && $ip6;
+ }
+ return ($ip4, $ip6);
+}
+
#helpers
sub read_db {
diff --git a/src/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm b/src/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
index ad5286b..1b7b666 100644
--- a/src/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
+++ b/src/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
@@ -204,6 +204,35 @@ sub del_ip {
}
}
+sub get_ips_from_mac {
+ my ($class, $plugin_config, $mac, $zoneid) = @_;
+
+
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token];
+
+ my $ip4 = undef;
+ my $ip6 = undef;
+
+ my $ips = PVE::Network::SDN::api_request("GET", "$url/addresses/search_mac/$mac", $headers);
+
+ #fixme
+ die "parsing of result not yet implemented";
+
+ for my $ip (@$ips) {
+# if ($ip->{family}->{value} == 4 && !$ip4) {
+# ($ip4, undef) = split(/\//, $ip->{address});
+# }
+#
+# if ($ip->{family}->{value} == 6 && !$ip6) {
+# ($ip6, undef) = split(/\//, $ip->{address});
+# }
+ }
+
+ return ($ip4, $ip6);
+}
+
sub verify_api {
my ($class, $plugin_config) = @_;
diff --git a/src/PVE/Network/SDN/Ipams/Plugin.pm b/src/PVE/Network/SDN/Ipams/Plugin.pm
index 4d85b81..59c7e31 100644
--- a/src/PVE/Network/SDN/Ipams/Plugin.pm
+++ b/src/PVE/Network/SDN/Ipams/Plugin.pm
@@ -111,6 +111,12 @@ sub del_ip {
die "please implement inside plugin";
}
+sub get_ips_from_mac {
+ my ($class, $plugin_config, $mac, $zone) = @_;
+
+ die "please implement inside plugin";
+}
+
sub on_update_hook {
my ($class, $plugin_config) = @_;
}
diff --git a/src/PVE/Network/SDN/Vnets.pm b/src/PVE/Network/SDN/Vnets.pm
index 76a6caf..9ba1a1e 100644
--- a/src/PVE/Network/SDN/Vnets.pm
+++ b/src/PVE/Network/SDN/Vnets.pm
@@ -155,6 +155,17 @@ sub del_cidr {
PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname, $skipdns);
}
+sub get_ips_from_mac {
+ my ($vnetid, $mac) = @_;
+ my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
+ my $zoneid = $vnet->{zone};
+ my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
+
+ my $ipam = $zone->{ipam};
+ return if !$ipam;
+
+ return PVE::Network::SDN::Ipams::get_ips_from_mac($mac, $zoneid, $zone);
+}
1;
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC qemu-server 5/5] vm_destroy: delete ip from ipam && dhcp
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
` (9 preceding siblings ...)
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 ` Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 6/9] vnets: rename del|add|update_cidr to ip Alexandre Derumier
` (4 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
PVE/QemuServer.pm | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 511f644..e4cc80d 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -2339,6 +2339,9 @@ sub destroy_vm {
});
}
+ eval { delete_ifaces_ipams_ips($conf, $vmid)};
+ warn $@ if $@;
+
if (defined $replacement_conf) {
PVE::QemuConfig->write_config($vmid, $replacement_conf);
} else {
@@ -8639,4 +8642,20 @@ sub create_ifaces_ipams_ips {
}
}
+sub delete_ifaces_ipams_ips {
+ my ($conf, $vmid) = @_;
+
+ return if !$have_sdn;
+
+ foreach my $opt (keys %$conf) {
+ if ($opt =~ m/^net(\d+)$/) {
+ my $net = PVE::QemuServer::parse_net($conf->{$opt});
+ eval { PVE::Network::SDN::Dhcp::remove_mapping($net->{bridge}, $net->{macaddr}) };
+ warn $@ if $@;
+ eval { PVE::Network::SDN::Vnets::del_ips_from_mac($net->{bridge}, $net->{macaddr}, $conf->{name}) };
+ warn $@ if $@;
+ }
+ }
+}
+
1;
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC pve-network 6/9] vnets: rename del|add|update_cidr to ip
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
` (10 preceding siblings ...)
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 ` Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 7/9] vnets: add del_ips_from_mac Alexandre Derumier
` (3 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
src/PVE/Network/SDN/Subnets.pm | 4 +---
src/PVE/Network/SDN/Vnets.pm | 27 ++++++++++++---------------
2 files changed, 13 insertions(+), 18 deletions(-)
diff --git a/src/PVE/Network/SDN/Subnets.pm b/src/PVE/Network/SDN/Subnets.pm
index b2125a1..905ec77 100644
--- a/src/PVE/Network/SDN/Subnets.pm
+++ b/src/PVE/Network/SDN/Subnets.pm
@@ -93,14 +93,12 @@ sub get_subnet {
}
sub find_ip_subnet {
- my ($ip, $mask, $subnets) = @_;
+ my ($ip, $subnets) = @_;
my $subnet = undef;
my $subnetid = undef;
foreach my $id (sort keys %{$subnets}) {
-
- next if $mask ne $subnets->{$id}->{mask};
my $cidr = $subnets->{$id}->{cidr};
my $subnet_matcher = subnet_matcher($cidr);
next if !$subnet_matcher->($ip);
diff --git a/src/PVE/Network/SDN/Vnets.pm b/src/PVE/Network/SDN/Vnets.pm
index 9ba1a1e..2f42da6 100644
--- a/src/PVE/Network/SDN/Vnets.pm
+++ b/src/PVE/Network/SDN/Vnets.pm
@@ -80,18 +80,15 @@ sub get_subnets {
return $subnets;
}
-sub get_subnet_from_vnet_cidr {
- my ($vnetid, $cidr) = @_;
+sub get_subnet_from_vnet_ip {
+ my ($vnetid, $ip) = @_;
my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
my $zoneid = $vnet->{zone};
my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
- my ($ip, $mask) = split(/\//, $cidr);
- die "ip address is not in cidr format" if !$mask;
-
- my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $mask, $subnets);
+ my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $subnets);
return ($zone, $subnetid, $subnet, $ip);
}
@@ -128,30 +125,30 @@ sub add_next_free_cidr {
}
}
-sub add_cidr {
- my ($vnetid, $cidr, $hostname, $mac, $description, $skipdns) = @_;
+sub add_ip {
+ my ($vnetid, $ip, $hostname, $mac, $description, $skipdns) = @_;
return if !$vnetid;
- my ($zone, $subnetid, $subnet, $ip) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_cidr($vnetid, $cidr);
+ my ($zone, $subnetid, $subnet) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_ip($vnetid, $ip);
PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $ip, $hostname, $mac, $description, undef, $skipdns);
}
-sub update_cidr {
- my ($vnetid, $cidr, $hostname, $oldhostname, $mac, $description, $skipdns) = @_;
+sub update_ip {
+ my ($vnetid, $ip, $hostname, $oldhostname, $mac, $description, $skipdns) = @_;
return if !$vnetid;
- my ($zone, $subnetid, $subnet, $ip) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_cidr($vnetid, $cidr);
+ my ($zone, $subnetid, $subnet) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_ip($vnetid, $ip);
PVE::Network::SDN::Subnets::update_ip($zone, $subnetid, $subnet, $ip, $hostname, $oldhostname, $mac, $description, $skipdns);
}
-sub del_cidr {
- my ($vnetid, $cidr, $hostname, $skipdns) = @_;
+sub del_ip {
+ my ($vnetid, $ip, $hostname, $skipdns) = @_;
return if !$vnetid;
- my ($zone, $subnetid, $subnet, $ip) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_cidr($vnetid, $cidr);
+ my ($zone, $subnetid, $subnet) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_ip($vnetid, $ip);
PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname, $skipdns);
}
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC pve-network 7/9] vnets: add del_ips_from_mac
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
` (11 preceding siblings ...)
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 ` Alexandre Derumier
2023-11-13 10:04 ` [pve-devel] [RFC pve-network 8/9] ipams : pveplugin: remove del_dhcp_ip Alexandre Derumier
` (2 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
src/PVE/Network/SDN/Subnets.pm | 4 ++--
src/PVE/Network/SDN/Vnets.pm | 12 ++++++++++--
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/src/PVE/Network/SDN/Subnets.pm b/src/PVE/Network/SDN/Subnets.pm
index 905ec77..2bd1ec8 100644
--- a/src/PVE/Network/SDN/Subnets.pm
+++ b/src/PVE/Network/SDN/Subnets.pm
@@ -257,7 +257,7 @@ sub add_next_free_ip {
#rollback
my $err = $@;
eval {
- PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname)
+ PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname, $mac)
};
die $err;
}
@@ -311,7 +311,7 @@ sub add_ip {
#rollback
my $err = $@;
eval {
- PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname)
+ PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname, $mac)
};
die $err;
}
diff --git a/src/PVE/Network/SDN/Vnets.pm b/src/PVE/Network/SDN/Vnets.pm
index 2f42da6..6047c98 100644
--- a/src/PVE/Network/SDN/Vnets.pm
+++ b/src/PVE/Network/SDN/Vnets.pm
@@ -144,12 +144,12 @@ sub update_ip {
}
sub del_ip {
- my ($vnetid, $ip, $hostname, $skipdns) = @_;
+ my ($vnetid, $ip, $hostname, $mac, $skipdns) = @_;
return if !$vnetid;
my ($zone, $subnetid, $subnet) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_ip($vnetid, $ip);
- PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname, $skipdns);
+ PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname, $mac, $skipdns);
}
sub get_ips_from_mac {
@@ -165,4 +165,12 @@ sub get_ips_from_mac {
return PVE::Network::SDN::Ipams::get_ips_from_mac($mac, $zoneid, $zone);
}
+sub del_ips_from_mac {
+ my ($vnetid, $mac, $hostname) = @_;
+
+ my ($ip4, $ip6) = PVE::Network::SDN::Vnets::get_ips_from_mac($vnetid, $mac);
+ PVE::Network::SDN::Vnets::del_ip($vnetid, $ip4, $hostname, $mac) if $ip4;
+ PVE::Network::SDN::Vnets::del_ip($vnetid, $ip6, $hostname, $mac) if $ip6;
+}
+
1;
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC pve-network 8/9] ipams : pveplugin: remove del_dhcp_ip
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
` (12 preceding siblings ...)
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 ` 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
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
src/PVE/Network/SDN/Ipams/PVEPlugin.pm | 32 --------------------------
1 file changed, 32 deletions(-)
diff --git a/src/PVE/Network/SDN/Ipams/PVEPlugin.pm b/src/PVE/Network/SDN/Ipams/PVEPlugin.pm
index 0bc2b65..776eff8 100644
--- a/src/PVE/Network/SDN/Ipams/PVEPlugin.pm
+++ b/src/PVE/Network/SDN/Ipams/PVEPlugin.pm
@@ -189,38 +189,6 @@ sub add_range_next_freeip {
});
}
-sub del_dhcp_ip {
- my ($class, $subnet, $mac) = @_;
-
- my $cidr = $subnet->{cidr};
- my $zone = $subnet->{zone};
-
- my $returned_ip = undef;
-
- cfs_lock_file($ipamdb_file, undef, sub {
- my $db = read_db();
-
- die "zone $zone don't exist in ipam db" if !$db->{zones}->{$zone};
- my $dbzone = $db->{zones}->{$zone};
-
- die "subnet $cidr don't exist in ipam db" if !$dbzone->{subnets}->{$cidr};
- my $dbsubnet = $dbzone->{subnets}->{$cidr};
-
- foreach my $ip_address (keys %{$dbsubnet->{ips}}) {
- my $data = $dbsubnet->{ips}->{$ip_address};
- next if !$data->{mac} || $data->{mac} ne $mac;
-
- delete $dbsubnet->{ips}->{$ip_address};
- write_db($db);
-
- $returned_ip = $ip_address;
- }
- });
- die "$@" if $@;
-
- return $returned_ip;
-}
-
sub del_ip {
my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_;
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* [pve-devel] [RFC pve-network 9/9] dhcp : dnsmasq: add_mapping: remove old mac, ip before append
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
` (13 preceding siblings ...)
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 ` Alexandre Derumier
2023-11-13 10:35 ` [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Stefan Hanreich
15 siblings, 0 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
---
src/PVE/Network/SDN/Dhcp/Dnsmasq.pm | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/src/PVE/Network/SDN/Dhcp/Dnsmasq.pm b/src/PVE/Network/SDN/Dhcp/Dnsmasq.pm
index 64895ef..21a6ddd 100644
--- a/src/PVE/Network/SDN/Dhcp/Dnsmasq.pm
+++ b/src/PVE/Network/SDN/Dhcp/Dnsmasq.pm
@@ -54,12 +54,24 @@ sub del_ip_mapping {
sub add_ip_mapping {
my ($class, $dhcpid, $mac, $ip) = @_;
+
my $ethers_file = "$DNSMASQ_CONFIG_ROOT/$dhcpid/ethers";
+ my $ethers_tmp_file = "$ethers_file.tmp";
my $appendFn = sub {
- open(my $fh, '>>', $ethers_file) or die "Could not open file '$ethers_file' $!\n";
- print $fh "$mac,$ip\n";
- close $fh;
+ open(my $in, '<', $ethers_file) or die "Could not open file '$ethers_file' $!\n";
+ open(my $out, '>', $ethers_tmp_file) or die "Could not open file '$ethers_tmp_file' $!\n";
+
+ while (my $line = <$in>) {
+ next if $line =~ m/^$mac/;
+ print $out $line;
+ }
+
+ print $out "$mac,$ip\n";
+ close $in;
+ close $out;
+ move $ethers_tmp_file, $ethers_file;
+ chmod 0644, $ethers_file;
};
PVE::Tools::lock_file($ethers_file, 10, $appendFn);
--
2.39.2
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP
2023-11-13 10:04 [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP Alexandre Derumier
` (14 preceding siblings ...)
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 ` Stefan Hanreich
2023-11-13 15:44 ` DERUMIER, Alexandre
15 siblings, 1 reply; 20+ messages in thread
From: Stefan Hanreich @ 2023-11-13 10:35 UTC (permalink / raw)
To: Proxmox VE development discussion, Alexandre Derumier
On 11/13/23 11:04, Alexandre Derumier wrote:
> I have splitted the ipam add|del , from the dhcp lease reservation.
>
> The ipam add|del ip is done when creating|deleting vm, or add|del a vm nic
>
> The dhcp reservation is done at vm start.
>
> The delete of dhcp reservation is done at vm destroy.
>
> (This can be easily extend for ephemeral ip)
>
> At vm start, we search ip associated with mac address.
Thanks very much, that looks like a very good solution! From what I can
tell migration would also work with this?
> I have only implemented calls in qemu-server for now
Do you plan on checking out pve-container as well? Or should I look into
this?
I integrated it into my branch and will be giving it a test drive now.
I've been working on a UI integration in the meanwhile and it's getting
along quite well although it will need to cook for another day or two.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP
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
0 siblings, 1 reply; 20+ messages in thread
From: DERUMIER, Alexandre @ 2023-11-13 15:44 UTC (permalink / raw)
To: pve-devel, aderumier, s.hanreich
Hi Stefan !
On 11/13/23 11:04, Alexandre Derumier wrote:
> I have splitted the ipam add|del , from the dhcp lease reservation.
>
> The ipam add|del ip is done when creating|deleting vm, or add|del a
> vm nic
>
> The dhcp reservation is done at vm start.
>
> The delete of dhcp reservation is done at vm destroy.
>
> (This can be easily extend for ephemeral ip)
>
> At vm start, we search ip associated with mac address.
>>Thanks very much, that looks like a very good solution! From what I
>>can
>>tell migration would also work with this?
yes sure ! (and also remote migration to another cluster with same
external ipam)
> I have only implemented calls in qemu-server for now
>>Do you plan on checking out pve-container as well? Or should I look
>>into this?
I was waiting comments before doing pve-container, but if you are ok,
no problem,I'll work on it.
I'll try also to improve dnsmasq reload, as we don't always need to
reload it (if nothing change), and maximum once by vm start. (currently
it's always done for each interface)
I don't have tested yet ipv6 with dnsmasq, but the ips are correctly
set in ethers file.
>>I integrated it into my branch and will be giving it a test drive
now.
Thanks. I have spare time theses next 2 weeks for help/fix/bug.
>>I've been working on a UI integration in the meanwhile and it's
>>getting
>>along quite well although it will need to cook for another day or
two.
I think it also need api to add dhcp-range in subnet, as for external
ipam like netbox, It need to call netbox api to add the ip range.
So, maybe a button in subnet panel :"add dhcp-range", allowing to add
multiple range.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP
2023-11-13 15:44 ` DERUMIER, Alexandre
@ 2023-11-13 16:11 ` Stefan Hanreich
0 siblings, 0 replies; 20+ messages in thread
From: Stefan Hanreich @ 2023-11-13 16:11 UTC (permalink / raw)
To: DERUMIER, Alexandre, pve-devel, aderumier
On 11/13/23 16:44, DERUMIER, Alexandre wrote:
> I think it also need api to add dhcp-range in subnet, as for external
> ipam like netbox, It need to call netbox api to add the ip range.
>
> So, maybe a button in subnet panel :"add dhcp-range", allowing to add
> multiple range.
Yes, that's what I've been working on. For now I have added a Tab in the
Subnete edit dialogue where you can edit the DHCP Ranges. Additionally I
have also created a view to inspect the status of the PVE IPAM.
Also I have added a checkbox for activating DHCP in the Zone edit dialogue.
^ permalink raw reply [flat|nested] 20+ messages in thread