public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [pve-network 0/4] updates
@ 2021-06-04 11:24 Alexandre Derumier
  2021-06-04 11:24 ` [pve-devel] [pve-network 1/4] sdn: get_local_vnets : add ipam && vlanaware values Alexandre Derumier
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Alexandre Derumier @ 2021-06-04 11:24 UTC (permalink / raw)
  To: pve-devel

This is a resend of previous sended patches
+ a new patch fixing subnets/ipam is_gateway value

Alexandre Derumier (4):
  sdn: get_local_vnets : add ipam && vlanaware values
  add vnets test + ipam fixes
  vnets: subroutines: return if !$vnetid
  subnets/ipam : fix is_gateway

 PVE/Network/SDN.pm                            |   4 +-
 PVE/Network/SDN/Ipams/NetboxPlugin.pm         |  14 +-
 PVE/Network/SDN/Ipams/PVEPlugin.pm            |  17 +-
 PVE/Network/SDN/Ipams/PhpIpamPlugin.pm        |  18 +-
 PVE/Network/SDN/SubnetPlugin.pm               |   2 +-
 PVE/Network/SDN/Subnets.pm                    |   4 +-
 PVE/Network/SDN/Vnets.pm                      |  23 +-
 test/ipams/netbox/expected.add_ip_notgateway  |   9 +
 test/ipams/phpipam/expected.add_ip_notgateway |  12 +
 test/run_test_ipams.pl                        |  18 +-
 test/run_test_subnets.pl                      |  24 +-
 test/run_test_vnets.pl                        | 355 ++++++++++++++++++
 test/vnets/ipv4/ipam.db                       |  17 +
 test/vnets/ipv4/ipam_config                   |   7 +
 test/vnets/ipv4/sdn_config                    |  26 ++
 test/vnets/ipv4noipam/ipam.db                 |  17 +
 test/vnets/ipv4noipam/ipam_config             |   7 +
 test/vnets/ipv4noipam/sdn_config              |  26 ++
 test/vnets/ipv6/ipam.db                       |  16 +
 test/vnets/ipv6/ipam_config                   |   7 +
 test/vnets/ipv6/sdn_config                    |  26 ++
 21 files changed, 614 insertions(+), 35 deletions(-)
 create mode 100644 test/ipams/netbox/expected.add_ip_notgateway
 create mode 100644 test/ipams/phpipam/expected.add_ip_notgateway
 create mode 100755 test/run_test_vnets.pl
 create mode 100644 test/vnets/ipv4/ipam.db
 create mode 100644 test/vnets/ipv4/ipam_config
 create mode 100644 test/vnets/ipv4/sdn_config
 create mode 100644 test/vnets/ipv4noipam/ipam.db
 create mode 100644 test/vnets/ipv4noipam/ipam_config
 create mode 100644 test/vnets/ipv4noipam/sdn_config
 create mode 100644 test/vnets/ipv6/ipam.db
 create mode 100644 test/vnets/ipv6/ipam_config
 create mode 100644 test/vnets/ipv6/sdn_config

-- 
2.20.1




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

* [pve-devel] [pve-network 1/4] sdn: get_local_vnets : add ipam && vlanaware values
  2021-06-04 11:24 [pve-devel] [pve-network 0/4] updates Alexandre Derumier
@ 2021-06-04 11:24 ` Alexandre Derumier
  2021-06-04 11:24 ` [pve-devel] [pve-network 2/4] add vnets test + ipam fixes Alexandre Derumier
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Alexandre Derumier @ 2021-06-04 11:24 UTC (permalink / raw)
  To: pve-devel

to be able to use them in ui bridgeselector
---
 PVE/Network/SDN.pm | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm
index 314b515..d3399ce 100644
--- a/PVE/Network/SDN.pm
+++ b/PVE/Network/SDN.pm
@@ -198,7 +198,9 @@ sub get_local_vnets {
 	my $zone_config = PVE::Network::SDN::Zones::sdn_zones_config($zones_cfg, $zoneid);
 
 	next if defined($zone_config->{nodes}) && !$zone_config->{nodes}->{$nodename};
-	$vnets->{$vnetid} = { type => 'vnet', active => '1', comments => $comments };
+	my $ipam = $zone_config->{ipam} ? 1 : 0;
+	my $vlanaware = $vnet->{vlanaware} ? 1 : 0;
+	$vnets->{$vnetid} = { type => 'vnet', active => '1', ipam => $ipam, vlanaware => $vlanaware, comments => $comments };
     }
 
     return $vnets;
-- 
2.20.1




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

* [pve-devel] [pve-network 2/4] add vnets test + ipam fixes
  2021-06-04 11:24 [pve-devel] [pve-network 0/4] updates Alexandre Derumier
  2021-06-04 11:24 ` [pve-devel] [pve-network 1/4] sdn: get_local_vnets : add ipam && vlanaware values Alexandre Derumier
@ 2021-06-04 11:24 ` Alexandre Derumier
  2021-06-04 11:24 ` [pve-devel] [pve-network 3/4] vnets: subroutines: return if !$vnetid Alexandre Derumier
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Alexandre Derumier @ 2021-06-04 11:24 UTC (permalink / raw)
  To: pve-devel

- add vnets tests with multiple subnets
- fix pve ipam ipv6 with next_free_ip (ipv6 don't have network && broadcast address)
- fix vnet next_free_ip with no ipam
---
 PVE/Network/SDN/Ipams/PVEPlugin.pm |  13 +-
 PVE/Network/SDN/Vnets.pm           |  13 +-
 test/run_test_subnets.pl           |  16 +-
 test/run_test_vnets.pl             | 355 +++++++++++++++++++++++++++++
 test/vnets/ipv4/ipam.db            |  17 ++
 test/vnets/ipv4/ipam_config        |   7 +
 test/vnets/ipv4/sdn_config         |  26 +++
 test/vnets/ipv4noipam/ipam.db      |  17 ++
 test/vnets/ipv4noipam/ipam_config  |   7 +
 test/vnets/ipv4noipam/sdn_config   |  26 +++
 test/vnets/ipv6/ipam.db            |  16 ++
 test/vnets/ipv6/ipam_config        |   7 +
 test/vnets/ipv6/sdn_config         |  26 +++
 13 files changed, 526 insertions(+), 20 deletions(-)
 create mode 100755 test/run_test_vnets.pl
 create mode 100644 test/vnets/ipv4/ipam.db
 create mode 100644 test/vnets/ipv4/ipam_config
 create mode 100644 test/vnets/ipv4/sdn_config
 create mode 100644 test/vnets/ipv4noipam/ipam.db
 create mode 100644 test/vnets/ipv4noipam/ipam_config
 create mode 100644 test/vnets/ipv4noipam/sdn_config
 create mode 100644 test/vnets/ipv6/ipam.db
 create mode 100644 test/vnets/ipv6/ipam_config
 create mode 100644 test/vnets/ipv6/sdn_config

diff --git a/PVE/Network/SDN/Ipams/PVEPlugin.pm b/PVE/Network/SDN/Ipams/PVEPlugin.pm
index 7e2fb77..8fe5bbb 100644
--- a/PVE/Network/SDN/Ipams/PVEPlugin.pm
+++ b/PVE/Network/SDN/Ipams/PVEPlugin.pm
@@ -90,7 +90,6 @@ sub add_ip {
     cfs_lock_file($ipamdb_file, undef, sub {
 
 	my $db = read_db();
-
 	my $dbzone = $db->{zones}->{$zone};
 	die "zone '$zone' doesn't exist in IPAM DB\n" if !$dbzone;
 	my $dbsubnet = $dbzone->{subnets}->{$cidr};
@@ -132,13 +131,15 @@ sub add_next_freeip {
 	    $freeip = $network;
 	} else {
 	    my $iplist = NetAddr::IP->new($cidr);
-	    my $broadcast = $iplist->broadcast();
-
+	    my $lastip = $iplist->last()->canon();
+	    $iplist++ if Net::IP::ip_is_ipv4($network); #skip network address for ipv4
 	    while(1) {
-		$iplist++;
-		last if $iplist eq $broadcast;
 		my $ip = $iplist->canon();
-		next if defined($dbsubnet->{ips}->{$ip});
+		if (defined($dbsubnet->{ips}->{$ip})) {
+		    last if $ip eq $lastip;
+		    $iplist++;
+		    next;
+		} 
 		$freeip = $ip;
 		last;
 	    }
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index 9d9b155..8c9629d 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -102,6 +102,8 @@ sub get_next_free_cidr {
     my $zoneid = $vnet->{zone};
     my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
 
+    return if !$zone->{ipam};
+
     $ipversion = 4 if !$ipversion;
     my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
     my $ip = undef;
@@ -113,12 +115,11 @@ sub get_next_free_cidr {
 
 	next if $ipversion != Net::IP::ip_get_version($network);
 	$subnetcount++;
-	if ($zone->{ipam}) {
-	    eval {
-		$ip = PVE::Network::SDN::Subnets::next_free_ip($zone, $subnetid, $subnet, $hostname, $mac, $description);
-	    };
-	    warn $@ if $@;
-	}
+
+	eval {
+	    $ip = PVE::Network::SDN::Subnets::next_free_ip($zone, $subnetid, $subnet, $hostname, $mac, $description);
+	};
+	warn $@ if $@;
 	last if $ip;
     }
     die "can't find any free ip" if !$ip && $subnetcount > 0;
diff --git a/test/run_test_subnets.pl b/test/run_test_subnets.pl
index 364baa6..9fca202 100755
--- a/test/run_test_subnets.pl
+++ b/test/run_test_subnets.pl
@@ -69,7 +69,7 @@ foreach my $path (@plugins) {
 
     my $subnet_cidr = $subnet->{cidr};
     my $iplist = NetAddr::IP->new($subnet_cidr);
-    $iplist++;
+    $iplist++ if Net::IP::ip_is_ipv4($iplist->canon()); #skip network address for ipv4
     my $ip = $iplist->canon();
     $iplist++;
     my $ipnextfree = $iplist->canon();
@@ -112,7 +112,7 @@ foreach my $path (@plugins) {
     );
 
     ## add_subnet
-    my $test = "add_subnet";
+    my $test = "add_subnet $subnetid";
     my $name = "$testid $test";
     my $result = undef;
     my $expected = '{"zones":{"myzone":{"subnets":{"'.$subnet_cidr.'":{"ips":{}}}}}}';
@@ -132,7 +132,7 @@ foreach my $path (@plugins) {
     }
 
     ## add_ip
-    $test = "add_ip";
+    $test = "add_ip $ip";
     $name = "$testid $test";
     $result = undef;
     $expected = '{"zones":{"myzone":{"subnets":{"'.$subnet_cidr.'":{"ips":{"'.$ip.'":{}}}}}}}';
@@ -152,7 +152,7 @@ foreach my $path (@plugins) {
 
     if($ipam) {
 	## add_already_exist_ip
-	$test = "add_already_exist_ip";
+	$test = "add_already_exist_ip $ip";
 	$name = "$testid $test";
 
 	eval {
@@ -167,7 +167,7 @@ foreach my $path (@plugins) {
     }
 
     ## add_second_ip
-    $test = "add_second_ip";
+    $test = "add_second_ip $ip2";
     $name = "$testid $test";
     $result = undef;
     $expected = '{"zones":{"myzone":{"subnets":{"'.$subnet_cidr.'":{"ips":{"'.$ip.'":{},"'.$ip2.'":{}}}}}}}';
@@ -186,7 +186,7 @@ foreach my $path (@plugins) {
     }
 
     ## add_next_free
-    $test = "add_next_freeip";
+    $test = "find_next_freeip ($ipnextfree)";
     $name = "$testid $test";
     $result = undef;
     $expected = '{"zones":{"myzone":{"subnets":{"'.$subnet_cidr.'":{"ips":{"'.$ip.'":{},"'.$ipnextfree.'":{},"'.$ip2.'":{}}}}}}}';
@@ -203,7 +203,7 @@ foreach my $path (@plugins) {
     }
 
     ## del_ip
-    $test = "del_ip";
+    $test = "del_ip $ip";
     $name = "$testid $test";
     $result = undef;
     $expected = '{"zones":{"myzone":{"subnets":{"'.$subnet_cidr.'":{"ips":{"'.$ipnextfree.'":{},"'.$ip2.'":{}}}}}}}';
@@ -223,7 +223,7 @@ foreach my $path (@plugins) {
 
     if($ipam){
 	## del_subnet_not_empty
-	$test = "del_subnet_not_empty";
+	$test = "del_subnet_not_empty $subnetid";
 	$name = "$testid $test";
 	$result = undef;
 	$expected = undef;
diff --git a/test/run_test_vnets.pl b/test/run_test_vnets.pl
new file mode 100755
index 0000000..5aeb676
--- /dev/null
+++ b/test/run_test_vnets.pl
@@ -0,0 +1,355 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use lib qw(..);
+use File::Slurp;
+use NetAddr::IP qw(:lower);
+
+use Test::More;
+use Test::MockModule;
+
+use PVE::Network::SDN;
+use PVE::Network::SDN::Zones;
+use PVE::Network::SDN::Controllers;
+use PVE::INotify;
+use JSON;
+
+use Data::Dumper qw(Dumper);
+$Data::Dumper::Sortkeys = 1;
+
+sub read_sdn_config {
+    my ($file) = @_;
+    # Read structure back in again
+    open my $in, '<', $file or die $!;
+    my $sdn_config;
+    {
+	local $/;    # slurp mode
+	$sdn_config = eval <$in>;
+    }
+    close $in;
+    return $sdn_config;
+}
+
+
+my @plugins = read_dir( './vnets/', prefix => 1 ) ;
+
+foreach my $path (@plugins) {
+
+    my (undef, $testid) = split(/\//, $path);
+
+    print "test: $testid\n";
+    my $sdn_config = read_sdn_config ("$path/sdn_config");
+
+    my $pve_sdn_zones;
+    $pve_sdn_zones = Test::MockModule->new('PVE::Network::SDN::Zones');
+    $pve_sdn_zones->mock(
+	config => sub {
+	    return $sdn_config->{zones};
+	},
+    );
+
+    my $pve_sdn_vnets;
+    $pve_sdn_vnets = Test::MockModule->new('PVE::Network::SDN::Vnets');
+    $pve_sdn_vnets->mock(
+	config => sub {
+	    return $sdn_config->{vnets};
+	},
+    );
+
+    my $pve_sdn_subnets;
+    $pve_sdn_subnets = Test::MockModule->new('PVE::Network::SDN::Subnets');
+    $pve_sdn_subnets->mock(
+	config => sub {
+	    return $sdn_config->{subnets};
+	},
+	verify_dns_zone => sub {
+	    return;
+	},
+	add_dns_record => sub {
+	    return;
+	}
+    );
+
+    my $js = JSON->new;
+    $js->canonical(1);
+  
+    #test params;
+    #test params;
+    my $subnets = $sdn_config->{subnets}->{ids};
+
+    my $subnetid = (sort keys %{$subnets})[0];
+    my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($sdn_config->{subnets}, $subnetid, 1);
+    my $subnet_cidr = $subnet->{cidr};
+    my $iplist = NetAddr::IP->new($subnet_cidr);
+    my $mask = $iplist->masklen();
+    my $ipversion = undef;
+
+    if (Net::IP::ip_is_ipv4($iplist->canon())){
+	$iplist++; #skip network address for ipv4
+	$ipversion = 4;
+    } else { 
+	$ipversion = 6;
+    }
+
+    my $cidr1 = $iplist->canon()."/$mask";
+    $iplist++;
+    my $cidr2 = $iplist->canon()."/$mask";
+    my $cidr_outofrange = '8.8.8.8/8';
+
+    my $subnetid2 = (sort keys %{$subnets})[1];
+    my $subnet2 = PVE::Network::SDN::Subnets::sdn_subnets_config($sdn_config->{subnets}, $subnetid2, 1);
+    my $subnet2_cidr = $subnet2->{cidr};
+    my $iplist2 = NetAddr::IP->new($subnet2_cidr);
+    $iplist2++;
+    my $cidr3 = $iplist2->canon()."/$mask";
+    $iplist2++;
+    my $cidr4 = $iplist2->canon()."/$mask";
+
+    my $hostname = "myhostname";
+    my $mac = "da:65:8f:18:9b:6f";
+    my $description = "mydescription";
+    my $ipamdb = read_sdn_config ("$path/ipam.db");
+
+    my $zone = $sdn_config->{zones}->{ids}->{"myzone"};
+    my $ipam = $zone->{ipam};
+
+    my $plugin;
+    my $sdn_ipam_plugin;
+    if($ipam) {
+	$plugin = PVE::Network::SDN::Ipams::Plugin->lookup($ipam);
+	$sdn_ipam_plugin = Test::MockModule->new($plugin);
+	$sdn_ipam_plugin->mock(
+	    read_db => sub {
+		return $ipamdb;
+	    },
+	    write_db => sub {
+		my ($cfg) = @_;
+		$ipamdb = $cfg;
+	    }
+	);
+    }
+
+    my $pve_sdn_ipams;
+    $pve_sdn_ipams = Test::MockModule->new('PVE::Network::SDN::Ipams');
+    $pve_sdn_ipams->mock(
+	config => sub {
+	    my $ipam_config = read_sdn_config ("$path/ipam_config");
+	    return $ipam_config;
+	},
+    );
+
+    my $vnetid = "myvnet";
+
+    ## add_ip
+    my $test = "add_cidr $cidr1";
+    my $name = "$testid $test";
+    my $result = undef;
+    my $expected = '';
+
+    eval {
+	PVE::Network::SDN::Vnets::add_cidr($vnetid, $cidr1, $hostname, $mac, $description);
+    };
+
+    if ($@) {
+        fail("$name : $@");
+    } else {
+        is (undef, undef, $name);
+    }
+
+    ## add_ip
+    $test = "add_already_exist_cidr $cidr1";
+    $name = "$testid $test";
+    $result = undef;
+    $expected = '';
+
+    eval {
+	PVE::Network::SDN::Vnets::add_cidr($vnetid, $cidr1, $hostname, $mac, $description);
+    };
+
+    if ($@) {
+        is (undef, undef, $name);
+    } elsif($ipam) {
+        fail("$name : $@");
+    } else {
+        is (undef, undef, $name);
+    }
+
+    ## add_ip
+    $test = "add_cidr $cidr2";
+    $name = "$testid $test";
+    $result = undef;
+    $expected = '';
+
+    eval {
+	PVE::Network::SDN::Vnets::add_cidr($vnetid, $cidr2, $hostname, $mac, $description);
+    };
+
+    if ($@) {
+        fail("$name : $@");
+    } else {
+        is (undef, undef, $name);
+    }
+
+    ## add_ip
+    $test = "add_ip_out_of_range_subnets $cidr_outofrange";
+    $name = "$testid $test";
+    $result = undef;
+    $expected = '';
+
+    eval {
+	PVE::Network::SDN::Vnets::add_cidr($vnetid, $cidr_outofrange, $hostname, $mac, $description);
+    };
+
+    if ($@) {
+        is (undef, undef, $name);
+    } else {
+        fail("$name : $@");
+    }
+
+    ## add_ip
+    $test = "add_cidr $cidr4";
+    $name = "$testid $test";
+    $result = undef;
+    $expected = '';
+
+    eval {
+	PVE::Network::SDN::Vnets::add_cidr($vnetid, $cidr4, $hostname, $mac, $description);
+    };
+
+    if ($@) {
+        fail("$name : $@");
+    } else {
+        is (undef, undef, $name);
+    }
+
+
+    $test = "find_next_free_cidr_in_second_subnet ($cidr3)";
+    $name = "$testid $test";
+    $result = undef;
+    $expected = $ipam ? $cidr3 : undef;
+
+    eval {
+	$result = PVE::Network::SDN::Vnets::get_next_free_cidr($vnetid, $hostname, $mac, $description, $ipversion);
+    };
+
+    if ($@) {
+        fail("$name : $@");
+    } else {
+        is ($result, $expected, $name);
+    }
+
+
+    $test = "del_cidr $cidr1";
+    $name = "$testid $test";
+    $result = undef;
+    $expected = undef;
+
+    eval {
+	$result = PVE::Network::SDN::Vnets::del_cidr($vnetid, $cidr1, $hostname);
+    };
+
+    if ($@) {
+        fail("$name : $@");
+    } else {
+        is (undef, undef, $name);
+    }
+
+    $test = "del_cidr $cidr3";
+    $name = "$testid $test";
+    $result = undef;
+    $expected = undef;
+
+    eval {
+	$result = PVE::Network::SDN::Vnets::del_cidr($vnetid, $cidr3, $hostname);
+    };
+
+    if ($@) {
+        fail("$name : $@");
+    } else {
+        is (undef, undef, $name);
+    }
+
+    $test = "del_cidr not exist $cidr1";
+    $name = "$testid $test";
+    $result = undef;
+    $expected = undef;
+
+    eval {
+	$result = PVE::Network::SDN::Vnets::del_cidr($vnetid, $cidr1, $hostname);
+    };
+
+    if ($@) {
+        is (undef, undef, $name);
+    } elsif($ipam) {
+        fail("$name : $@");
+    } else {
+        is (undef, undef, $name);
+    }
+
+    $test = "del_cidr outofrange $cidr_outofrange";
+    $name = "$testid $test";
+    $result = undef;
+    $expected = undef;
+
+    eval {
+	$result = PVE::Network::SDN::Vnets::del_cidr($vnetid, $cidr_outofrange, $hostname);
+    };
+
+    if ($@) {
+        is (undef, undef, $name);
+    } else {
+        fail("$name : $@");
+    }
+
+    $test = "find_next_free_cidr_in_first_subnet ($cidr1)";
+    $name = "$testid $test";
+    $result = undef;
+    $expected = $ipam ? $cidr1 : undef;
+
+    eval {
+	$result = PVE::Network::SDN::Vnets::get_next_free_cidr($vnetid, $hostname, $mac, $description, $ipversion);
+    };
+
+    if ($@) {
+        fail("$name : $@");
+    } else {
+        is ($result, $expected, $name);
+    }
+
+    $test = "update_cidr $cidr1";
+    $name = "$testid $test";
+    $result = undef;
+    $expected = undef;
+
+    eval {
+	$result = PVE::Network::SDN::Vnets::update_cidr($vnetid, $cidr1, $hostname, $hostname, $mac, $description);
+    };
+
+    if ($@) {
+        fail("$name : $@");
+    } else {
+        is (undef, undef, $name);
+    }
+
+    $test = "update_cidr deleted $cidr3";
+    $name = "$testid $test";
+    $result = undef;
+    $expected = undef;
+
+    eval {
+	$result = PVE::Network::SDN::Vnets::update_cidr($vnetid, $cidr1, $hostname, $hostname, $mac, $description);
+    };
+
+    if ($@) {
+        fail("$name : $@");
+    } else {
+        is (undef, undef, $name);
+    }
+
+}
+
+done_testing();
+
+
diff --git a/test/vnets/ipv4/ipam.db b/test/vnets/ipv4/ipam.db
new file mode 100644
index 0000000..ef3fa93
--- /dev/null
+++ b/test/vnets/ipv4/ipam.db
@@ -0,0 +1,17 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	}
+    }
+}
+
diff --git a/test/vnets/ipv4/ipam_config b/test/vnets/ipv4/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/test/vnets/ipv4/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/test/vnets/ipv4/sdn_config b/test/vnets/ipv4/sdn_config
new file mode 100644
index 0000000..ee11fd1
--- /dev/null
+++ b/test/vnets/ipv4/sdn_config
@@ -0,0 +1,26 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                      },
+             },
+
+  zones   => {
+               ids => { myzone => { ipam => "pve", type =>"simple" } },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+                     }
+
+             }
+}
diff --git a/test/vnets/ipv4noipam/ipam.db b/test/vnets/ipv4noipam/ipam.db
new file mode 100644
index 0000000..ef3fa93
--- /dev/null
+++ b/test/vnets/ipv4noipam/ipam.db
@@ -0,0 +1,17 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"192.168.0.0/30" => {
+		    "ips" =>{
+		    }
+		},
+		"192.168.1.0/30" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	}
+    }
+}
+
diff --git a/test/vnets/ipv4noipam/ipam_config b/test/vnets/ipv4noipam/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/test/vnets/ipv4noipam/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/test/vnets/ipv4noipam/sdn_config b/test/vnets/ipv4noipam/sdn_config
new file mode 100644
index 0000000..470c1ae
--- /dev/null
+++ b/test/vnets/ipv4noipam/sdn_config
@@ -0,0 +1,26 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                      },
+             },
+
+  zones   => {
+               ids => { myzone => { type =>"simple" } },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-192.168.0.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-192.168.1.0-30' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+                     }
+
+             }
+}
diff --git a/test/vnets/ipv6/ipam.db b/test/vnets/ipv6/ipam.db
new file mode 100644
index 0000000..d3f2ce9
--- /dev/null
+++ b/test/vnets/ipv6/ipam.db
@@ -0,0 +1,16 @@
+{
+   "zones" => {
+	"myzone" => {
+	    "subnets" => {
+		"2001:db8:85a3::8a2e:370:7334/127" => {
+		    "ips" =>{
+		    }
+		},
+		"2001:db8:85a3::8a2e:371:7334/127" => {
+		    "ips" =>{
+		    }
+		},
+	    }
+	}
+    }
+}
diff --git a/test/vnets/ipv6/ipam_config b/test/vnets/ipv6/ipam_config
new file mode 100644
index 0000000..f5f36ad
--- /dev/null
+++ b/test/vnets/ipv6/ipam_config
@@ -0,0 +1,7 @@
+{
+          'ids' => {
+                     'pve' => {
+                                'type' => 'pve'
+                              },
+                   },
+}
diff --git a/test/vnets/ipv6/sdn_config b/test/vnets/ipv6/sdn_config
new file mode 100644
index 0000000..231ca8a
--- /dev/null
+++ b/test/vnets/ipv6/sdn_config
@@ -0,0 +1,26 @@
+{
+  version => 1,
+  vnets   => {
+               ids => {
+                        myvnet => { type => "vnet", zone => "myzone" },
+                      },
+             },
+
+  zones   => {
+               ids => { myzone => { ipam => "pve", type =>"simple" } },
+             },
+
+  subnets => {
+              ids => { 
+			'myzone-2001:db8:85a3::8a2e:370:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+			'myzone-2001:db8:85a3::8a2e:371:7334-127' => {
+                                                        'type' => 'subnet',
+                                                        'vnet' => 'myvnet',
+                                                  },
+                     }
+
+             }
+}
-- 
2.20.1




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

* [pve-devel] [pve-network 3/4] vnets: subroutines: return if !$vnetid
  2021-06-04 11:24 [pve-devel] [pve-network 0/4] updates Alexandre Derumier
  2021-06-04 11:24 ` [pve-devel] [pve-network 1/4] sdn: get_local_vnets : add ipam && vlanaware values Alexandre Derumier
  2021-06-04 11:24 ` [pve-devel] [pve-network 2/4] add vnets test + ipam fixes Alexandre Derumier
@ 2021-06-04 11:24 ` Alexandre Derumier
  2021-06-04 11:25 ` [pve-devel] [pve-network 4/4] subnets/ipam : fix is_gateway Alexandre Derumier
  2021-06-18 16:30 ` [pve-devel] applied-series: [pve-network 0/4] updates Thomas Lamprecht
  4 siblings, 0 replies; 6+ messages in thread
From: Alexandre Derumier @ 2021-06-04 11:24 UTC (permalink / raw)
  To: pve-devel

---
 PVE/Network/SDN/Vnets.pm | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index 8c9629d..86967a3 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -52,6 +52,8 @@ sub complete_sdn_vnet {
 sub get_vnet {
     my ($vnetid, $running) = @_;
 
+    return if !$vnetid;
+
     my $cfg = {};
     if($running) {
 	my $cfg = PVE::Network::SDN::running_config();
@@ -68,6 +70,8 @@ sub get_vnet {
 sub get_subnets {
     my ($vnetid) = @_;
 
+    return if !$vnetid;
+
     my $subnets = undef;
     my $subnets_cfg = PVE::Network::SDN::Subnets::config();
     foreach my $subnetid (sort keys %{$subnets_cfg->{ids}}) {
@@ -130,6 +134,8 @@ sub get_next_free_cidr {
 sub add_cidr {
     my ($vnetid, $cidr, $hostname, $mac, $description) = @_;
 
+    return if !$vnetid;
+    
     my ($zone, $subnetid, $subnet, $ip) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_cidr($vnetid, $cidr);
     PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $ip, $hostname, $mac, $description);
 }
@@ -137,6 +143,8 @@ sub add_cidr {
 sub update_cidr {
     my ($vnetid, $cidr, $hostname, $oldhostname, $mac, $description) = @_;
 
+    return if !$vnetid;
+
     my ($zone, $subnetid, $subnet, $ip) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_cidr($vnetid, $cidr);
     PVE::Network::SDN::Subnets::update_ip($zone, $subnetid, $subnet, $ip, $hostname, $oldhostname, $mac, $description);
 }
@@ -144,6 +152,8 @@ sub update_cidr {
 sub del_cidr {
     my ($vnetid, $cidr, $hostname) = @_;
 
+    return if !$vnetid;
+
     my ($zone, $subnetid, $subnet, $ip) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_cidr($vnetid, $cidr);
     PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname);
 }
-- 
2.20.1




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

* [pve-devel] [pve-network 4/4] subnets/ipam : fix is_gateway
  2021-06-04 11:24 [pve-devel] [pve-network 0/4] updates Alexandre Derumier
                   ` (2 preceding siblings ...)
  2021-06-04 11:24 ` [pve-devel] [pve-network 3/4] vnets: subroutines: return if !$vnetid Alexandre Derumier
@ 2021-06-04 11:25 ` Alexandre Derumier
  2021-06-18 16:30 ` [pve-devel] applied-series: [pve-network 0/4] updates Thomas Lamprecht
  4 siblings, 0 replies; 6+ messages in thread
From: Alexandre Derumier @ 2021-06-04 11:25 UTC (permalink / raw)
  To: pve-devel

- add lost is_gateway in subnets subnet when creating subnet
- allow reuse ip as gateway in subnet create if it's already flagged gateway in the ipamdb
- add tests
---
 PVE/Network/SDN/Ipams/NetboxPlugin.pm         | 14 +++++++++++++-
 PVE/Network/SDN/Ipams/PVEPlugin.pm            |  4 ++--
 PVE/Network/SDN/Ipams/PhpIpamPlugin.pm        | 18 +++++++++++++++---
 PVE/Network/SDN/SubnetPlugin.pm               |  2 +-
 PVE/Network/SDN/Subnets.pm                    |  4 ++--
 test/ipams/netbox/expected.add_ip_notgateway  |  9 +++++++++
 test/ipams/phpipam/expected.add_ip_notgateway | 12 ++++++++++++
 test/run_test_ipams.pl                        | 18 +++++++++++++++++-
 test/run_test_subnets.pl                      |  8 ++++----
 9 files changed, 75 insertions(+), 14 deletions(-)
 create mode 100644 test/ipams/netbox/expected.add_ip_notgateway
 create mode 100644 test/ipams/phpipam/expected.add_ip_notgateway

diff --git a/PVE/Network/SDN/Ipams/NetboxPlugin.pm b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
index 5a03f39..f0e7168 100644
--- a/PVE/Network/SDN/Ipams/NetboxPlugin.pm
+++ b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
@@ -93,7 +93,11 @@ sub add_ip {
     };
 
     if ($@) {
-	die "error add subnet ip to ipam: ip already exist: $@" if !$noerr;
+        if($is_gateway) {
+           die "error add subnet ip to ipam: ip $ip already exist: $@" if !is_ip_gateway($url, $ip, $headers) && !$noerr;
+        } else {
+	    die "error add subnet ip to ipam: ip already exist: $@" if !$noerr;
+	}
     }
 }
 
@@ -208,6 +212,14 @@ sub get_ip_id {
     return $ip_id;
 }
 
+sub is_ip_gateway {
+    my ($url, $ip, $headers) = @_;
+    my $result = PVE::Network::SDN::api_request("GET", "$url/addresses/search/$ip", $headers);
+    my $data = @{$result->{data}}[0];
+    my $description = $data->{description};
+    my $is_gateway = 1 if $description eq 'gateway';
+    return $is_gateway;
+}
 
 1;
 
diff --git a/PVE/Network/SDN/Ipams/PVEPlugin.pm b/PVE/Network/SDN/Ipams/PVEPlugin.pm
index 8fe5bbb..3e8ffc5 100644
--- a/PVE/Network/SDN/Ipams/PVEPlugin.pm
+++ b/PVE/Network/SDN/Ipams/PVEPlugin.pm
@@ -95,9 +95,9 @@ sub add_ip {
 	my $dbsubnet = $dbzone->{subnets}->{$cidr};
 	die "subnet '$cidr' doesn't exist in IPAM DB\n" if !$dbsubnet;
 
-	die "IP '$ip' already exist\n" if defined($dbsubnet->{ips}->{$ip});
-
+	die "IP '$ip' already exist\n" if (!$is_gateway && defined($dbsubnet->{ips}->{$ip})) || ($is_gateway && defined($dbsubnet->{ips}->{$ip}) && !defined($dbsubnet->{ips}->{$ip}->{gateway}));
 	$dbsubnet->{ips}->{$ip} = {};
+	$dbsubnet->{ips}->{$ip} = {gateway => 1} if $is_gateway;
 
 	write_db($db);
     });
diff --git a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
index ed66ea9..ad5286b 100644
--- a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
+++ b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
@@ -106,10 +106,10 @@ sub add_ip {
 
     my $params = { ip => $ip,
 		   subnetId => $internalid,
-		   is_gateway => $is_gateway,
 		   hostname => $hostname,
 		   description => $description,
 		  };
+    $params->{is_gateway} = 1 if $is_gateway;
     $params->{mac} = $mac if $mac;
 
     eval {
@@ -117,7 +117,11 @@ sub add_ip {
     };
 
     if ($@) {
-	die "error add subnet ip to ipam: ip $ip already exist: $@" if !$noerr;
+	if($is_gateway) {
+	    die "error add subnet ip to ipam: ip $ip already exist: $@" if !is_ip_gateway($url, $ip, $headers) && !$noerr;
+	} else {
+	    die "error add subnet ip to ipam: ip $ip already exist: $@" if !$noerr;
+	}
     }
 }
 
@@ -134,10 +138,10 @@ sub update_ip {
     die "can't find ip addresse in ipam" if !$ip_id;
 
     my $params = { 
-		   is_gateway => $is_gateway,
 		   hostname => $hostname,
 		   description => $description,
 		  };
+    $params->{is_gateway} = 1 if $is_gateway;
     $params->{mac} = $mac if $mac;
 
     eval {
@@ -242,6 +246,14 @@ sub get_ip_id {
     return $ip_id;
 }
 
+sub is_ip_gateway {
+    my ($url, $ip, $headers) = @_;
+    my $result = PVE::Network::SDN::api_request("GET", "$url/addresses/search/$ip", $headers);
+    my $data = @{$result->{data}}[0];
+    my $is_gateway = $data->{is_gateway};
+    return $is_gateway;
+}
+
 1;
 
 
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index b4c8954..15b370f 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -143,7 +143,7 @@ sub on_update_hook {
 	}
         if(!$old_gateway || $gateway && $gateway ne $old_gateway) {
 	    my $hostname = "$vnetid-gw";
-	    my $description = "$vnetid gw";
+	    my $description = "gateway";
 	    PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $gateway, $hostname, $mac, $description, 1);
 	}
 
diff --git a/PVE/Network/SDN/Subnets.pm b/PVE/Network/SDN/Subnets.pm
index 46d9830..0231822 100644
--- a/PVE/Network/SDN/Subnets.pm
+++ b/PVE/Network/SDN/Subnets.pm
@@ -232,7 +232,7 @@ sub next_free_ip {
 }
 
 sub add_ip {
-    my ($zone, $subnetid, $subnet, $ip, $hostname, $mac, $description) = @_;
+    my ($zone, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway) = @_;
 
     return if !$subnet || !$ip; 
 
@@ -259,7 +259,7 @@ sub add_ip {
 	my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
 
 	eval {
-	    $plugin->add_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description);
+	    $plugin->add_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway);
 	};
 	die $@ if $@;
     }
diff --git a/test/ipams/netbox/expected.add_ip_notgateway b/test/ipams/netbox/expected.add_ip_notgateway
new file mode 100644
index 0000000..ae876f2
--- /dev/null
+++ b/test/ipams/netbox/expected.add_ip_notgateway
@@ -0,0 +1,9 @@
+bless( {
+                  '_content' => '{"address":"10.0.0.1/24","description":"mydescription mac:da:65:8f:18:9b:6f","dns_name":"myhostname"}',
+                  '_headers' => bless( {
+                                         'authorization' => 'token 0123456789abcdef0123456789abcdef01234567',
+                                         'content-type' => 'application/json; charset=UTF-8'
+                                       }, 'HTTP::Headers' ),
+                  '_method' => 'POST',
+                  '_uri' => bless( do{\(my $o = 'http://localhost:8000/api/ipam/ip-addresses/')}, 'URI::http' )
+                }, 'HTTP::Request' );
diff --git a/test/ipams/phpipam/expected.add_ip_notgateway b/test/ipams/phpipam/expected.add_ip_notgateway
new file mode 100644
index 0000000..7a91359
--- /dev/null
+++ b/test/ipams/phpipam/expected.add_ip_notgateway
@@ -0,0 +1,12 @@
+bless( {
+                  '_content' => '{"description":"mydescription","hostname":"myhostname","ip":"10.0.0.1","mac":"da:65:8f:18:9b:6f","subnetId":1}',
+                  '_headers' => bless( {
+                                         '::std_case' => {
+                                                           'token' => 'Token'
+                                                         },
+                                         'content-type' => 'application/json; charset=UTF-8',
+                                         'token' => 'JPHkPSLB4O_XL-GQz4qtEFmNpx-99Htw'
+                                       }, 'HTTP::Headers' ),
+                  '_method' => 'POST',
+                  '_uri' => bless( do{\(my $o = 'https://localhost/api/apiadmin/addresses/')}, 'URI::https' )
+                }, 'HTTP::Request' );
diff --git a/test/run_test_ipams.pl b/test/run_test_ipams.pl
index 6743eff..27bd441 100755
--- a/test/run_test_ipams.pl
+++ b/test/run_test_ipams.pl
@@ -99,6 +99,9 @@ foreach my $path (@plugins) {
 	},
 	get_ip_id => sub {
 	    return 1;
+	},
+	is_ip_gateway => sub {
+	    return 1;
 	}
     );
 
@@ -146,9 +149,22 @@ foreach my $path (@plugins) {
     $test = "update_ip";
     $expected = Dumper read_sdn_config("$path/expected.$test");
     $name = "$ipamid $test";
-
     $plugin->update_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway, 1);
 
+    if ($@) {
+	is ($@, $expected, $name);
+    } else {
+	fail($name);
+    }
+
+    ## add_ip_notgateway
+    $is_gateway = undef;
+    $test = "add_ip_notgateway";
+    $expected = Dumper read_sdn_config("$path/expected.$test");
+    $name = "$ipamid $test";
+
+    $plugin->add_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway, 1);
+
     if ($@) {
 	is ($@, $expected, $name);
     } else {
diff --git a/test/run_test_subnets.pl b/test/run_test_subnets.pl
index 9fca202..f6564e1 100755
--- a/test/run_test_subnets.pl
+++ b/test/run_test_subnets.pl
@@ -135,10 +135,10 @@ foreach my $path (@plugins) {
     $test = "add_ip $ip";
     $name = "$testid $test";
     $result = undef;
-    $expected = '{"zones":{"myzone":{"subnets":{"'.$subnet_cidr.'":{"ips":{"'.$ip.'":{}}}}}}}';
+    $expected = '{"zones":{"myzone":{"subnets":{"'.$subnet_cidr.'":{"ips":{"'.$ip.'":{"gateway":1}}}}}}}';
 
     eval {
-	PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $ip, $hostname, $mac, $description);
+	PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway);
     };
 
     if ($@) {
@@ -170,7 +170,7 @@ foreach my $path (@plugins) {
     $test = "add_second_ip $ip2";
     $name = "$testid $test";
     $result = undef;
-    $expected = '{"zones":{"myzone":{"subnets":{"'.$subnet_cidr.'":{"ips":{"'.$ip.'":{},"'.$ip2.'":{}}}}}}}';
+    $expected = '{"zones":{"myzone":{"subnets":{"'.$subnet_cidr.'":{"ips":{"'.$ip.'":{"gateway":1},"'.$ip2.'":{}}}}}}}';
 
     eval {
 	PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $ip2, $hostname, $mac, $description);
@@ -189,7 +189,7 @@ foreach my $path (@plugins) {
     $test = "find_next_freeip ($ipnextfree)";
     $name = "$testid $test";
     $result = undef;
-    $expected = '{"zones":{"myzone":{"subnets":{"'.$subnet_cidr.'":{"ips":{"'.$ip.'":{},"'.$ipnextfree.'":{},"'.$ip2.'":{}}}}}}}';
+    $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);
-- 
2.20.1




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

* [pve-devel] applied-series:  [pve-network 0/4] updates
  2021-06-04 11:24 [pve-devel] [pve-network 0/4] updates Alexandre Derumier
                   ` (3 preceding siblings ...)
  2021-06-04 11:25 ` [pve-devel] [pve-network 4/4] subnets/ipam : fix is_gateway Alexandre Derumier
@ 2021-06-18 16:30 ` Thomas Lamprecht
  4 siblings, 0 replies; 6+ messages in thread
From: Thomas Lamprecht @ 2021-06-18 16:30 UTC (permalink / raw)
  To: Proxmox VE development discussion, Alexandre Derumier

On 04.06.21 13:24, Alexandre Derumier wrote:
> This is a resend of previous sended patches
> + a new patch fixing subnets/ipam is_gateway value
> 
> Alexandre Derumier (4):
>   sdn: get_local_vnets : add ipam && vlanaware values
>   add vnets test + ipam fixes
>   vnets: subroutines: return if !$vnetid
>   subnets/ipam : fix is_gateway


applied series, thanks!




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

end of thread, other threads:[~2021-06-18 16:30 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-04 11:24 [pve-devel] [pve-network 0/4] updates Alexandre Derumier
2021-06-04 11:24 ` [pve-devel] [pve-network 1/4] sdn: get_local_vnets : add ipam && vlanaware values Alexandre Derumier
2021-06-04 11:24 ` [pve-devel] [pve-network 2/4] add vnets test + ipam fixes Alexandre Derumier
2021-06-04 11:24 ` [pve-devel] [pve-network 3/4] vnets: subroutines: return if !$vnetid Alexandre Derumier
2021-06-04 11:25 ` [pve-devel] [pve-network 4/4] subnets/ipam : fix is_gateway Alexandre Derumier
2021-06-18 16:30 ` [pve-devel] applied-series: [pve-network 0/4] updates Thomas Lamprecht

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