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