public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [RFC series pve-network/pve-cluster/qemu-server] DHCP
@ 2023-11-13 10:04 Alexandre Derumier
  2023-11-13 10:04 ` [pve-devel] [RFC pve-cluster 1/1] add priv/macs.db Alexandre Derumier
                   ` (15 more replies)
  0 siblings, 16 replies; 20+ messages in thread
From: Alexandre Derumier @ 2023-11-13 10:04 UTC (permalink / raw)
  To: pve-devel

Here my current work, based on wip2 Stefan Hanreich

Changes:

I have removed dhcp.cfg extra file, and now we can simply define dhcptype in the zone

So, we'll have 1 dhcp server for each zone, could be in different vrf with same subnet reuse.

/etc/pve/sdn/zones.cfg

simple: simpve
        dhcp dnsmasq
        ipam pve

simple: netbox
        dhcp dnsmasq
        ipam netbox

/etc/pve/sdn/vnets.cfg

vnet: vnetpve
        zone simpve

vnet: vnetbox
        zone netbox

/etc/pve/sdn/subnets.cfg

subnet: simple-172.16.0.0-24
        vnet netbox
        dhcp-range start-address=172.16.0.10,end-address=172.16.0.20
        dnszoneprefix odiso.net
        gateway 172.16.0.1

subnet: simpve-192.168.2.0-24
        vnet vnetpve
        dhcp-range start-address=192.168.2.10,end-address=192.168.2.20
        dhcp-range start-address=192.168.2.40,end-address=192.168.2.50
        gateway 192.168.2.1

subnet: netbox-172.16.0.0-24
        vnet vnetbox
        gateway 172.16.0.1
        dhcp-range start-address=172.16.0.10,end-address=172.16.0.20

subnet: netbox-2a05:71c0::-120
        vnet vnetbox
        dhcp-range start-address=2a05:71c0::10,end-address=2a05:71c0::20


I have implement netbox plugin to find a new ip in dhcp range (Don't seem possible
with phpipam, but we could define a full range with all ips).

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.

To avoid to call ipam each time, I have implemented an extra macs.db file, with a
mac-ip hash for fast lookup. This cache is populated with adding an ip in ipam (at vm creation, nic add),
it can also be populated at vm_start if mac is not yet cached.  (for example, if ip is pre-reserved manually in external ipam)

I have reused/improve my previous ipam code, so ipv6 is supported && dns plugin is also used if defined.


I have only implemented calls in qemu-server for now


pve-network:

Alexandre Derumier (9):
  define dhcpplugin in zone
  dhcp : add|del_ip_mapping: only add|del dhcp reservervation
  vnet|subnet: add_next_free_ip : implement dhcprange ipam search
  ipam : add macs.db for fast mac lookup
  ipam : add get_ips_from_mac
  vnets: rename del|add|update_cidr to ip
  vnets: add del_ips_from_mac
  ipams : pveplugin: remove del_dhcp_ip
  dhcp : dnsmasq: add_mapping: remove old mac,ip before append

 src/PVE/API2/Network/SDN/Zones.pm          |   1 +
 src/PVE/Network/SDN.pm                     |   4 +-
 src/PVE/Network/SDN/Dhcp.pm                | 166 ++++++---------------
 src/PVE/Network/SDN/Dhcp/Dnsmasq.pm        |  50 ++++---
 src/PVE/Network/SDN/Dhcp/Plugin.pm         |  28 +---
 src/PVE/Network/SDN/Ipams.pm               |  80 +++++++++-
 src/PVE/Network/SDN/Ipams/NetboxPlugin.pm  |  61 ++++++++
 src/PVE/Network/SDN/Ipams/PVEPlugin.pm     |  80 +++++-----
 src/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm |  29 ++++
 src/PVE/Network/SDN/Ipams/Plugin.pm        |  13 ++
 src/PVE/Network/SDN/SubnetPlugin.pm        |   4 -
 src/PVE/Network/SDN/Subnets.pm             |  37 +++--
 src/PVE/Network/SDN/Vnets.pm               |  88 ++++++-----
 src/PVE/Network/SDN/Zones/SimplePlugin.pm  |   7 +-
 src/test/run_test_subnets.pl               |   8 +-
 src/test/run_test_vnets.pl                 |   4 +-
 16 files changed, 393 insertions(+), 267 deletions(-)

pve-cluster:

Alexandre Derumier (1):
  add priv/macs.db

 src/PVE/Cluster.pm  | 1 +
 src/pmxcfs/status.c | 1 +
 2 files changed, 2 insertions(+)

qemu-server:

Alexandre Derumier (5):
  don't remove dhcp mapping on stop
  vmnic add|remove : add|del ip in ipam
  vm_start : vm-network-scripts: get ip from ipam and add dhcp
    reservation
  api2: create|restore|clone: add_free_ip
  vm_destroy: delete ip from ipam && dhcp

 PVE/API2/Qemu.pm                  |  6 +++
 PVE/QemuServer.pm                 | 72 +++++++++++++++++++++++++++++++
 vm-network-scripts/pve-bridge     |  4 +-
 vm-network-scripts/pve-bridgedown | 19 --------
 4 files changed, 81 insertions(+), 20 deletions(-)

-- 
2.39.2




^ permalink raw reply	[flat|nested] 20+ messages in thread

* [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

* [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

* 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

end of thread, other threads:[~2023-11-13 16:14 UTC | newest]

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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal