[pve-devel] [PATCH v10 pve-network 31/35] subnets/ipam: allow same subnet on different zones
Alexandre Derumier
aderumier at odiso.com
Mon Oct 5 17:09:08 CEST 2020
Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
PVE/API2/Network/SDN/Subnets.pm | 13 ++--
PVE/API2/Network/SDN/Vnets.pm | 14 ++--
PVE/API2/Network/SDN/Zones.pm | 11 +++
PVE/Network/SDN/Dns/PowerdnsPlugin.pm | 6 +-
PVE/Network/SDN/Ipams/NetboxPlugin.pm | 18 ++---
PVE/Network/SDN/Ipams/PVEPlugin.pm | 102 ++++++++++++++++---------
PVE/Network/SDN/Ipams/PhpIpamPlugin.pm | 20 ++---
PVE/Network/SDN/Ipams/Plugin.pm | 6 +-
PVE/Network/SDN/SubnetPlugin.pm | 26 +++++--
PVE/Network/SDN/Subnets.pm | 28 ++++---
PVE/Network/SDN/VnetPlugin.pm | 31 ++++----
PVE/Network/SDN/Vnets.pm | 18 +++--
PVE/Network/SDN/Zones/EvpnPlugin.pm | 3 +-
PVE/Network/SDN/Zones/SimplePlugin.pm | 5 +-
14 files changed, 188 insertions(+), 113 deletions(-)
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index 5ea4fc4..0fb9420 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -28,7 +28,6 @@ my $api_sdn_subnets_config = sub {
my $scfg = dclone(PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id));
$scfg->{subnet} = $id;
- $scfg->{cidr} = $id =~ s/-/\//r;
$scfg->{digest} = $cfg->{digest};
return $scfg;
@@ -169,7 +168,6 @@ __PACKAGE__->register_method ({
my $type = extract_param($param, 'type');
my $cidr = extract_param($param, 'subnet');
- my $id = $cidr =~ s/\//-/r;
# create /etc/pve/sdn directory
PVE::Cluster::check_cfs_quorum();
@@ -184,7 +182,9 @@ __PACKAGE__->register_method ({
my $vnet = $param->{vnet};
my $zoneid = $vnet_cfg->{ids}->{$vnet}->{zone};
my $zone = $zone_cfg->{ids}->{$zoneid};
-
+ my $id = $cidr =~ s/\//-/r;
+ $id = "$zoneid-$id";
+
my $opts = PVE::Network::SDN::SubnetPlugin->check_config($id, $param, 1, 1);
my $scfg = undef;
@@ -193,7 +193,9 @@ __PACKAGE__->register_method ({
}
$cfg->{ids}->{$id} = $opts;
- PVE::Network::SDN::SubnetPlugin->on_update_hook($zone, $id, $opts);
+
+ my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id);
+ PVE::Network::SDN::SubnetPlugin->on_update_hook($zone, $id, $subnet);
PVE::Network::SDN::Subnets::write_config($cfg);
@@ -238,7 +240,8 @@ __PACKAGE__->register_method ({
raise_param_exc({ ipam => "you can't change ipam"}) if $opts->{ipam} && $scfg->{ipam} && $opts->{ipam} ne $scfg->{ipam};
- PVE::Network::SDN::SubnetPlugin->on_update_hook($zone, $id, $opts, $scfg);
+ my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id);
+ PVE::Network::SDN::SubnetPlugin->on_update_hook($zone, $id, $subnet);
PVE::Network::SDN::Subnets::write_config($cfg);
diff --git a/PVE/API2/Network/SDN/Vnets.pm b/PVE/API2/Network/SDN/Vnets.pm
index 6ff61c5..3f99f58 100644
--- a/PVE/API2/Network/SDN/Vnets.pm
+++ b/PVE/API2/Network/SDN/Vnets.pm
@@ -19,6 +19,7 @@ use PVE::API2::Network::SDN::Subnets;
use Storable qw(dclone);
use PVE::JSONSchema qw(get_standard_option);
use PVE::RPCEnvironment;
+use PVE::Exception qw(raise raise_param_exc);
use PVE::RESTHandler;
@@ -195,9 +196,7 @@ __PACKAGE__->register_method ({
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
$plugin->vnet_update_hook($cfg->{ids}->{$id});
- my $subnet_cfg = PVE::Network::SDN::Subnets::config();
-
- PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg, $subnet_cfg);
+ PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg);
PVE::Network::SDN::Vnets::write_config($cfg);
@@ -228,7 +227,12 @@ __PACKAGE__->register_method ({
PVE::SectionConfig::assert_if_modified($cfg, $digest);
+
my $opts = PVE::Network::SDN::VnetPlugin->check_config($id, $param, 0, 1);
+ raise_param_exc({ zone => "missing zone"}) if !$opts->{zone};
+ my $subnets = PVE::Network::SDN::Vnets::get_subnets($id);
+ raise_param_exc({ zone => "can't change zone if subnets exists"}) if($subnets && $opts->{zone} ne $cfg->{ids}->{$id}->{zone});
+
$cfg->{ids}->{$id} = $opts;
my $zone_cfg = PVE::Network::SDN::Zones::config();
@@ -237,9 +241,7 @@ __PACKAGE__->register_method ({
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
$plugin->vnet_update_hook($cfg->{ids}->{$id});
- my $subnet_cfg = PVE::Network::SDN::Subnets::config();
-
- PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg, $subnet_cfg);
+ PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg);
PVE::Network::SDN::Vnets::write_config($cfg);
diff --git a/PVE/API2/Network/SDN/Zones.pm b/PVE/API2/Network/SDN/Zones.pm
index 54f087d..5ae577b 100644
--- a/PVE/API2/Network/SDN/Zones.pm
+++ b/PVE/API2/Network/SDN/Zones.pm
@@ -9,6 +9,7 @@ use PVE::Cluster qw(cfs_read_file cfs_write_file);
use PVE::Network::SDN;
use PVE::Network::SDN::Vnets;
use PVE::Network::SDN::Zones;
+use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::Dns;
use PVE::Network::SDN::Zones::Plugin;
use PVE::Network::SDN::Zones::VlanPlugin;
@@ -263,6 +264,16 @@ __PACKAGE__->register_method ({
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($scfg->{type});
my $opts = $plugin->check_config($id, $param, 0, 1);
+ if($opts->{ipam} ne $scfg->{ipam}) {
+
+ #don't allow ipam change if subnet are defined
+ my $subnets_cfg = PVE::Network::SDN::Subnets::config();
+ foreach my $subnetid (sort keys %{$subnets_cfg->{ids}}) {
+ my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($subnets_cfg, $subnetid);
+ raise_param_exc({ ipam => "can't change ipam if subnet if already defined for this zone"}) if $subnet->{zone} eq $id;
+ }
+ }
+
foreach my $k (%$opts) {
$scfg->{$k} = $opts->{$k};
}
diff --git a/PVE/Network/SDN/Dns/PowerdnsPlugin.pm b/PVE/Network/SDN/Dns/PowerdnsPlugin.pm
index 5b98e87..b00432e 100644
--- a/PVE/Network/SDN/Dns/PowerdnsPlugin.pm
+++ b/PVE/Network/SDN/Dns/PowerdnsPlugin.pm
@@ -186,11 +186,11 @@ sub verify_zone {
}
sub get_reversedns_zone {
- my ($class, $plugin_config, $subnetid, $ip) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_;
- my ($network, $mask) = split(/-/, $subnetid);
+ my $cidr = $subnet->{cidr};
+ my $mask = $subnet->{mask};
- my $cidr = "$ip/$mask";
my $zone = "";
if (Net::IP::ip_is_ipv4($ip)) {
diff --git a/PVE/Network/SDN/Ipams/NetboxPlugin.pm b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
index c25f451..8695b7d 100644
--- a/PVE/Network/SDN/Ipams/NetboxPlugin.pm
+++ b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
@@ -30,7 +30,7 @@ sub options {
sub add_subnet {
my ($class, $plugin_config, $subnetid, $subnet) = @_;
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
my $gateway = $subnet->{gateway};
my $url = $plugin_config->{url};
my $token = $plugin_config->{token};
@@ -40,13 +40,11 @@ sub add_subnet {
#create subnet
if (!$internalid) {
- my ($network, $mask) = split(/-/, $subnetid);
my $params = { prefix => $cidr };
eval {
my $result = PVE::Network::SDN::Ipams::Plugin::api_request("POST", "$url/ipam/prefixes/", $headers, $params);
- $subnet->{ipamid} = $result->{id} if defined($result->{id});
};
if ($@) {
die "error add subnet to ipam: $@";
@@ -58,7 +56,7 @@ sub add_subnet {
sub del_subnet {
my ($class, $plugin_config, $subnetid, $subnet) = @_;
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
my $url = $plugin_config->{url};
my $token = $plugin_config->{token};
my $gateway = $subnet->{gateway};
@@ -66,9 +64,8 @@ sub del_subnet {
my $internalid = get_prefix_id($url, $cidr, $headers);
return if !$internalid;
- #fixme: check that prefix is empty exluding gateway, before delete
- PVE::Network::SDN::Ipams::NetboxPlugin::del_ip($class, $plugin_config, $subnetid, $gateway) if $gateway;
+ return; #fixme: check that prefix is empty exluding gateway, before delete
eval {
PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/ipam/prefixes/$internalid/", $headers);
@@ -80,9 +77,9 @@ sub del_subnet {
}
sub add_ip {
- my ($class, $plugin_config, $subnetid, $ip, $is_gateway) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $ip, $is_gateway) = @_;
- my ($network, $mask) = split(/-/, $subnetid);
+ my $mask = $subnet->{mask};
my $url = $plugin_config->{url};
my $token = $plugin_config->{token};
my $section = $plugin_config->{section};
@@ -102,7 +99,8 @@ sub add_ip {
sub add_next_freeip {
my ($class, $plugin_config, $subnetid, $subnet) = @_;
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
+
my $url = $plugin_config->{url};
my $token = $plugin_config->{token};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
@@ -125,7 +123,7 @@ sub add_next_freeip {
}
sub del_ip {
- my ($class, $plugin_config, $subnetid, $ip) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_;
return if !$ip;
diff --git a/PVE/Network/SDN/Ipams/PVEPlugin.pm b/PVE/Network/SDN/Ipams/PVEPlugin.pm
index a3ad3d6..601ad26 100644
--- a/PVE/Network/SDN/Ipams/PVEPlugin.pm
+++ b/PVE/Network/SDN/Ipams/PVEPlugin.pm
@@ -7,6 +7,7 @@ use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_register_file cfs_lock_file
use PVE::Tools;
use JSON;
use NetAddr::IP;
+use Net::IP;
use Digest::SHA;
use base('PVE::Network::SDN::Ipams::Plugin');
@@ -33,15 +34,22 @@ sub options {
sub add_subnet {
my ($class, $plugin_config, $subnetid, $subnet) = @_;
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
+ my $zone = $subnet->{zone};
my $gateway = $subnet->{gateway};
+
cfs_lock_file($ipamdb_file, undef, sub {
- my $config = read_db();
- #create subnet
- if (!defined($config->{subnets}->{$cidr})) {
- $config->{subnets}->{$cidr}->{ips} = {};
- write_db($config);
+ my $db = {};
+ $db = read_db();
+
+ $db->{zones}->{$zone} = {} if !$db->{zones}->{$zone};
+ my $zonedb = $db->{zones}->{$zone};
+
+ if(!$zonedb->{subnets}->{$cidr}) {
+ #create subnet
+ $zonedb->{subnets}->{$cidr}->{ips} = {};
+ write_db($db);
}
});
die "$@" if $@;
@@ -50,14 +58,19 @@ sub add_subnet {
sub del_subnet {
my ($class, $plugin_config, $subnetid, $subnet) = @_;
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
+ my $zone = $subnet->{zone};
cfs_lock_file($ipamdb_file, undef, sub {
my $db = read_db();
- my $ips = $db->{subnets}->{$cidr}->{ips};
+ 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};
+ my $ips = $dbsubnet->{ips};
die "can't delete subnet $cidr , not empty" if keys %{$ips} > 0;
- delete $db->{subnets}->{$cidr};
+ delete $dbzone->{subnets}->{$cidr};
write_db($db);
});
die "$@" if $@;
@@ -65,19 +78,22 @@ sub del_subnet {
}
sub add_ip {
- my ($class, $plugin_config, $subnetid, $ip, $is_gateway) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $ip, $is_gateway) = @_;
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
+ my $zone = $subnet->{zone};
cfs_lock_file($ipamdb_file, undef, sub {
my $db = read_db();
- my $s = $db->{subnets}->{$cidr};
- die "ip $ip already exist" if defined($s->{ips}->{$ip});
+ 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};
- #verify that ip is valid for this subnet
- $s->{ips}->{$ip} = 1;
+ die "ip $ip already exist" if defined($dbsubnet->{ips}->{$ip});
+ $dbsubnet->{ips}->{$ip} = 1;
write_db($db);
});
die "$@" if $@;
@@ -86,49 +102,65 @@ sub add_ip {
sub add_next_freeip {
my ($class, $plugin_config, $subnetid, $subnet) = @_;
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
+ my $network = $subnet->{network};
+ my $zone = $subnet->{zone};
+ my $mask = $subnet->{mask};
my $freeip = undef;
cfs_lock_file($ipamdb_file, undef, sub {
my $db = read_db();
- my $s = $db->{subnets}->{$cidr};
- my $iplist = new NetAddr::IP($cidr);
- my $broadcast = $iplist->broadcast();
-
- while(1) {
- $iplist++;
- last if $iplist eq $broadcast;
- my $ip = $iplist->addr();
- next if defined($s->{ips}->{$ip});
- $freeip = $ip;
- last;
+ 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};
+
+ if (Net::IP::ip_is_ipv4($network) && $mask == 32) {
+ die "can't find free ip in subnet $cidr" if defined($dbsubnet->{ips}->{$network});
+ $freeip = $network;
+ } else {
+
+ my $iplist = new NetAddr::IP($cidr);
+ my $broadcast = $iplist->broadcast();
+
+ while(1) {
+ $iplist++;
+ last if $iplist eq $broadcast;
+ my $ip = $iplist->addr();
+ next if defined($dbsubnet->{ips}->{$ip});
+ $freeip = $ip;
+ last;
+ }
}
die "can't find free ip in subnet $cidr" if !$freeip;
- $s->{ips}->{$freeip} = 1;
+ $dbsubnet->{ips}->{$freeip} = 1;
write_db($db);
});
die "$@" if $@;
- my ($network, $mask) = split(/-/, $subnetid);
return "$freeip/$mask";
}
sub del_ip {
- my ($class, $plugin_config, $subnetid, $ip) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_;
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
+ my $zone = $subnet->{zone};
cfs_lock_file($ipamdb_file, undef, sub {
my $db = read_db();
- my $s = $db->{subnets}->{$cidr};
- return if !$ip;
+ 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};
+
+ die "ip $ip does not exist in pam" if !defined($dbsubnet->{ips}->{$ip});
+ delete $dbsubnet->{ips}->{$ip};
- die "ip $ip does not exist in pam" if !defined($s->{ips}->{$ip});
- delete $s->{ips}->{$ip};
write_db($db);
});
die "$@" if $@;
diff --git a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
index d7ba3ed..324f1b2 100644
--- a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
+++ b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
@@ -40,7 +40,10 @@ sub options {
sub add_subnet {
my ($class, $plugin_config, $subnetid, $subnet) = @_;
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
+ my $network = $subnet->{network};
+ my $mask = $subnet->{mask};
+
my $gateway = $subnet->{gateway};
my $url = $plugin_config->{url};
my $token = $plugin_config->{token};
@@ -52,7 +55,6 @@ sub add_subnet {
#create subnet
if (!$internalid) {
- my ($network, $mask) = split(/-/, $subnetid);
my $params = { subnet => $network,
mask => $mask,
@@ -72,7 +74,7 @@ sub add_subnet {
sub del_subnet {
my ($class, $plugin_config, $subnetid, $subnet) = @_;
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
my $url = $plugin_config->{url};
my $token = $plugin_config->{token};
my $section = $plugin_config->{section};
@@ -81,7 +83,7 @@ sub del_subnet {
my $internalid = get_internalid($url, $cidr, $headers);
return if !$internalid;
- #fixme: check that prefix is empty exluding gateway, before delete
+ return; #fixme: check that prefix is empty exluding gateway, before delete
eval {
PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/subnets/$internalid", $headers);
@@ -93,9 +95,9 @@ sub del_subnet {
}
sub add_ip {
- my ($class, $plugin_config, $subnetid, $ip, $is_gateway) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $ip, $is_gateway) = @_;
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
my $url = $plugin_config->{url};
my $token = $plugin_config->{token};
my $section = $plugin_config->{section};
@@ -120,7 +122,8 @@ sub add_ip {
sub add_next_freeip {
my ($class, $plugin_config, $subnetid, $subnet, $internalid, $hostname) = @_;
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
+ my $mask = $subnet->{mask};
my $url = $plugin_config->{url};
my $token = $plugin_config->{token};
my $section = $plugin_config->{section};
@@ -140,12 +143,11 @@ sub add_next_freeip {
die "can't find free ip in subnet $cidr: $@";
}
- my ($network, $mask) = split(/-/, $subnetid);
return "$ip/$mask";
}
sub del_ip {
- my ($class, $plugin_config, $subnetid, $ip) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_;
return if !$ip;
diff --git a/PVE/Network/SDN/Ipams/Plugin.pm b/PVE/Network/SDN/Ipams/Plugin.pm
index 683346c..a2ade3b 100644
--- a/PVE/Network/SDN/Ipams/Plugin.pm
+++ b/PVE/Network/SDN/Ipams/Plugin.pm
@@ -75,16 +75,16 @@ sub del_subnet {
}
sub add_ip {
- my ($class, $plugin_config, $subnetid, $subnet, $internalid, $ip, $hostname, $is_gateway) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $ip, $is_gateway) = @_;
}
sub add_next_freeip {
- my ($class, $plugin_config) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
}
sub del_ip {
- my ($class, $plugin_config, $subnetid, $ip) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_;
}
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index a5d03f6..1444262 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -10,6 +10,7 @@ use PVE::Exception qw(raise raise_param_exc);
use Net::Subnet qw(subnet_matcher);
use PVE::Network::SDN::Vnets;
use PVE::Network::SDN::Ipams;
+use Net::IP;
PVE::Cluster::cfs_register_file('sdn/subnets.cfg',
sub { __PACKAGE__->parse_config(@_); },
@@ -25,7 +26,13 @@ PVE::JSONSchema::register_format('pve-sdn-subnet-id', \&parse_sdn_subnet_id);
sub parse_sdn_subnet_id {
my ($id, $noerr) = @_;
- my $cidr = $id =~ s/-/\//r;
+ my $cidr = "";
+ if($id =~ /\//) {
+ $cidr = $id;
+ } else {
+ my ($zone, $ip, $mask) = split(/-/, $id);
+ $cidr = "$ip/$mask";
+ }
if (!(PVE::JSONSchema::pve_verify_cidrv4($cidr, 1) ||
PVE::JSONSchema::pve_verify_cidrv6($cidr, 1)))
@@ -91,7 +98,9 @@ sub options {
sub on_update_hook {
my ($class, $zone, $subnetid, $subnet, $old_subnet) = @_;
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
+ my $mask = $subnet->{mask};
+
my $subnet_matcher = subnet_matcher($cidr);
my $vnetid = $subnet->{vnet};
@@ -109,9 +118,11 @@ sub on_update_hook {
raise_param_exc({ vnet => "you can't add a subnet on a vlanaware vnet"}) if $vnet->{vlanaware};
}
- my ($ip, $mask) = split(/\//, $cidr);
+ my $pointopoint = 1 if Net::IP::ip_is_ipv4($gateway) && $mask == 32;
+
#for /32 pointopoint, we allow gateway outside the subnet
- raise_param_exc({ gateway => "$gateway is not in subnet $subnetid"}) if $gateway && !$subnet_matcher->($gateway) && $mask != 32;
+ raise_param_exc({ gateway => "$gateway is not in subnet $cidr"}) if $gateway && !$subnet_matcher->($gateway) && !$pointopoint;
+
if ($ipam) {
my $ipam_cfg = PVE::Network::SDN::Ipams::config();
@@ -119,7 +130,10 @@ sub on_update_hook {
my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
$plugin->add_subnet($plugin_config, $subnetid, $subnet);
- #delete on removal
+ #don't register gateway for pointopoint
+ return if $pointopoint;
+
+ #delete gateway on removal
if (!defined($gateway) && $old_gateway) {
eval {
PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $old_subnet, $old_gateway);
@@ -130,7 +144,7 @@ sub on_update_hook {
PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $gateway);
}
- #delete old ip after update
+ #delete old gateway after update
if($gateway && $old_gateway && $gateway ne $old_gateway) {
eval {
PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $old_subnet, $old_gateway);
diff --git a/PVE/Network/SDN/Subnets.pm b/PVE/Network/SDN/Subnets.pm
index 50130d5..bd1eb36 100644
--- a/PVE/Network/SDN/Subnets.pm
+++ b/PVE/Network/SDN/Subnets.pm
@@ -21,6 +21,14 @@ sub sdn_subnets_config {
my $scfg = $cfg->{ids}->{$id};
die "sdn subnet '$id' does not exist\n" if (!$noerr && !$scfg);
+ if($scfg) {
+ my ($zone, $network, $mask) = split(/-/, $id);
+ $scfg->{cidr} = "$network/$mask";
+ $scfg->{zone} = $zone;
+ $scfg->{network} = $network;
+ $scfg->{mask} = $mask;
+ }
+
return $scfg;
}
@@ -64,13 +72,15 @@ sub get_subnet {
}
sub find_ip_subnet {
- my ($ip, $subnets) = @_;
+ my ($ip, $mask, $subnets) = @_;
my $subnet = undef;
my $subnetid = undef;
foreach my $id (sort keys %{$subnets}) {
- my $cidr = $id =~ s/-/\//r;
+
+ next if $mask ne $subnets->{$id}->{mask};
+ my $cidr = $subnets->{$id}->{cidr};
my $subnet_matcher = subnet_matcher($cidr);
next if !$subnet_matcher->($ip);
$subnet = $subnets->{$id};
@@ -94,14 +104,14 @@ my $verify_dns_zone = sub {
};
my $get_reversedns_zone = sub {
- my ($subnetid, $dns, $ip) = @_;
+ my ($subnetid, $subnet, $dns, $ip) = @_;
return if !$subnetid || !$dns || !$ip;
my $dns_cfg = PVE::Network::SDN::Dns::config();
my $plugin_config = $dns_cfg->{ids}->{$dns};
my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
- $plugin->get_reversedns_zone($plugin_config, $subnetid, $ip);
+ $plugin->get_reversedns_zone($plugin_config, $subnetid, $subnet, $ip);
};
my $add_dns_record = sub {
@@ -181,7 +191,7 @@ sub next_free_ip {
}
eval {
- my $reversednszone = &$get_reversedns_zone($subnetid, $reversedns, $ip);
+ my $reversednszone = &$get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
#add dns
&$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
@@ -208,7 +218,7 @@ sub add_ip {
my $dns = $zone->{dns};
my $dnszone = $zone->{dnszone};
my $reversedns = $zone->{reversedns};
- my $reversednszone = &$get_reversedns_zone($subnetid, $reversedns, $ip);
+ my $reversednszone = &$get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
my $dnszoneprefix = $subnet->{dnszoneprefix};
#verify dns zones before ipam
@@ -220,7 +230,7 @@ sub add_ip {
my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
eval {
- $plugin->add_ip($plugin_config, $subnetid, $ip);
+ $plugin->add_ip($plugin_config, $subnetid, $subnet, $ip);
};
die $@ if $@;
}
@@ -250,7 +260,7 @@ sub del_ip {
my $dns = $zone->{dns};
my $dnszone = $zone->{dnszone};
my $reversedns = $zone->{reversedns};
- my $reversednszone = &$get_reversedns_zone($subnetid, $reversedns, $ip);
+ my $reversednszone = &$get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
my $dnszoneprefix = $subnet->{dnszoneprefix};
&$verify_dns_zone($dnszone, $dns);
@@ -260,7 +270,7 @@ sub del_ip {
my $ipam_cfg = PVE::Network::SDN::Ipams::config();
my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
- $plugin->del_ip($plugin_config, $subnetid, $ip);
+ $plugin->del_ip($plugin_config, $subnetid, $subnet, $ip);
}
eval {
diff --git a/PVE/Network/SDN/VnetPlugin.pm b/PVE/Network/SDN/VnetPlugin.pm
index 8481f0d..518d2dd 100644
--- a/PVE/Network/SDN/VnetPlugin.pm
+++ b/PVE/Network/SDN/VnetPlugin.pm
@@ -91,29 +91,28 @@ sub on_delete_hook {
#verify if subnets are associated
my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
- my @subnetlist = ();
- foreach my $subnetid (sort keys %{$subnets}) {
- push @subnetlist, $subnetid;
- }
- raise_param_exc({ vnet => "Vnet is attached to following subnets:". join(',', @subnetlist)}) if @subnetlist > 0;
+ raise_param_exc({ vnet => "Can't delete vnet if subnets exists"}) if $subnets;
}
sub on_update_hook {
- my ($class, $vnetid, $vnet_cfg, $subnet_cfg) = @_;
+ my ($class, $vnetid, $vnet_cfg) = @_;
+
+ my $vnet = $vnet_cfg->{ids}->{$vnetid};
+ my $tag = $vnet->{tag};
+ my $vlanaware = $vnet->{vlanaware};
+
+ #don't allow vlanaware change if subnets are defined
+ if($vnet->{vlanaware}) {
+ my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
+ raise_param_exc({ vlanaware => "vlanaware vnet is not compatible with subnets"}) if $subnets;
+ }
- #fixme : don't allow change zone if subnets are defined
- #fixme : don't vlanaware change if subnets are defined
-# my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
-
# verify that tag is not already defined in another vnet
- if (defined($vnet_cfg->{ids}->{$vnetid}->{tag})) {
- my $tag = $vnet_cfg->{ids}->{$vnetid}->{tag};
+ if (defined($tag)) {
foreach my $id (keys %{$vnet_cfg->{ids}}) {
next if $id eq $vnetid;
- my $vnet = $vnet_cfg->{ids}->{$id};
- if ($vnet->{type} eq 'vnet' && defined($vnet->{tag})) {
- raise_param_exc({ tag => "tag $tag already exist in vnet $id"}) if $tag eq $vnet->{tag};
- }
+ my $othervnettag = $vnet_cfg->{ids}->{$id}->{tag};
+ raise_param_exc({ tag => "tag $tag already exist in vnet $id"}) if $othervnettag && $tag eq $othervnettag;
}
}
}
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index d08db51..6d11003 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -66,10 +66,10 @@ sub get_vnet {
sub get_subnets {
my ($vnetid) = @_;
- my $subnets = {};
+ my $subnets = undef;
my $subnets_cfg = PVE::Network::SDN::Subnets::config();
foreach my $subnetid (sort keys %{$subnets_cfg->{ids}}) {
- my $subnet = $subnets_cfg->{ids}->{$subnetid};
+ my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($subnets_cfg, $subnetid);
next if !$subnet->{vnet} || $subnet->{vnet} ne $vnetid;
$subnets->{$subnetid} = $subnet;
}
@@ -77,7 +77,7 @@ sub get_subnets {
}
-sub get_next_free_ip {
+sub get_next_free_cidr {
my ($vnetid, $hostname, $ipversion) = @_;
my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
@@ -91,7 +91,7 @@ sub get_next_free_ip {
foreach my $subnetid (sort keys %{$subnets}) {
my $subnet = $subnets->{$subnetid};
- my ($network, $mask) = split(/-/, $subnetid);
+ my $network = $subnet->{network};
next if $ipversion != Net::IP::ip_get_version($network);
$subnetcount++;
@@ -108,7 +108,7 @@ sub get_next_free_ip {
return $ip;
}
-sub add_ip {
+sub add_cidr {
my ($vnetid, $cidr, $hostname) = @_;
my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
@@ -117,12 +117,13 @@ sub add_ip {
my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
my ($ip, $mask) = split(/\//, $cidr);
- my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $subnets);
+ die "ip address is not in cidr format" if !$mask;
+ my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $mask, $subnets);
PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $ip, $hostname);
}
-sub del_ip {
+sub del_cidr {
my ($vnetid, $cidr, $hostname) = @_;
my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
@@ -131,7 +132,8 @@ sub del_ip {
my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
my ($ip, $mask) = split(/\//, $cidr);
- my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $subnets);
+ die "ip address is not in cidr format" if !$mask;
+ my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $mask, $subnets);
PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname);
}
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index 723b3cc..62ab817 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -86,7 +86,8 @@ sub generate_sdn_config {
my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
foreach my $subnetid (sort keys %{$subnets}) {
my $subnet = $subnets->{$subnetid};
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
+
my $gateway = $subnet->{gateway};
if ($gateway) {
push @iface_config, "address $gateway" if !defined($address->{$gateway});
diff --git a/PVE/Network/SDN/Zones/SimplePlugin.pm b/PVE/Network/SDN/Zones/SimplePlugin.pm
index fe0f20f..5294485 100644
--- a/PVE/Network/SDN/Zones/SimplePlugin.pm
+++ b/PVE/Network/SDN/Zones/SimplePlugin.pm
@@ -60,14 +60,15 @@ sub generate_sdn_config {
my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
foreach my $subnetid (sort keys %{$subnets}) {
my $subnet = $subnets->{$subnetid};
- my $cidr = $subnetid =~ s/-/\//r;
+ my $cidr = $subnet->{cidr};
+ my $mask = $subnet->{mask};
+
my $gateway = $subnet->{gateway};
if ($gateway) {
push @iface_config, "address $gateway" if !defined($address->{$gateway});
$address->{$gateway} = 1;
}
#add route for /32 pointtopoint
- my ($ip, $mask) = split(/\//, $cidr);
push @iface_config, "up ip route add $cidr dev $vnetid" if $mask == 32;
if ($subnet->{snat}) {
#find outgoing interface
--
2.20.1
More information about the pve-devel
mailing list