[pve-devel] [RFC pve-network 5/9] ipam : add get_ips_from_mac

Alexandre Derumier aderumier at odiso.com
Mon Nov 13 11:04:14 CET 2023


First look ip mac.db cache
if not, lookup in ipam , and cache result in mac.db

Signed-off-by: Alexandre Derumier <aderumier at 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





More information about the pve-devel mailing list