* [pve-devel] [PATCH pve-network 01/38] vnets: add subnets
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 02/38] add subnets verifications hooks Alexandre Derumier
` (37 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/VnetPlugin.pm | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/PVE/Network/SDN/VnetPlugin.pm b/PVE/Network/SDN/VnetPlugin.pm
index 384358c..47ca50b 100644
--- a/PVE/Network/SDN/VnetPlugin.pm
+++ b/PVE/Network/SDN/VnetPlugin.pm
@@ -68,16 +68,11 @@ sub properties {
description => "alias name of the vnet",
optional => 1,
},
- ipv4 => {
- description => "Anycast router ipv4 address.",
- type => 'string', format => 'CIDRv4',
- optional => 1,
- },
- ipv6 => {
- description => "Anycast router ipv6 address.",
- type => 'string', format => 'CIDRv6',
+ subnets => {
+ type => 'string',
+ description => "Subnets list",
optional => 1,
- },
+ },
mac => {
type => 'string',
description => "Anycast router mac address",
@@ -91,8 +86,7 @@ sub options {
zone => { optional => 0},
tag => { optional => 1},
alias => { optional => 1 },
- ipv4 => { optional => 1 },
- ipv6 => { optional => 1 },
+ subnets => { optional => 1 },
mac => { optional => 1 },
vlanaware => { optional => 1 },
};
@@ -105,7 +99,7 @@ sub on_delete_hook {
}
sub on_update_hook {
- my ($class, $vnetid, $vnet_cfg) = @_;
+ my ($class, $vnetid, $vnet_cfg, $subnet_cfg) = @_;
# verify that tag is not already defined in another vnet
if (defined($vnet_cfg->{ids}->{$vnetid}->{tag})) {
my $tag = $vnet_cfg->{ids}->{$vnetid}->{tag};
@@ -117,6 +111,10 @@ sub on_update_hook {
}
}
}
+ #verify subnet
+ my $subnets = $vnet_cfg->{ids}->{$vnetid}->{subnets};
+ my @subnets = PVE::Tools::split_list($vnet_cfg->{ids}->{$vnetid}->{subnets}) if $plugin_config->{'peers'};
+
}
1;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 02/38] add subnets verifications hooks
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 01/38] vnets: add subnets Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 03/38] zones: simple|evpn: add gateway ip from subnets to vnet Alexandre Derumier
` (36 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN/Subnets.pm | 5 ++++-
PVE/API2/Network/SDN/Vnets.pm | 9 +++++++--
PVE/Network/SDN/SubnetPlugin.pm | 15 +++++++++++++++
PVE/Network/SDN/VnetPlugin.pm | 8 +++++---
4 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index 26b2aa5..3ef1d11 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -9,6 +9,7 @@ use PVE::Cluster qw(cfs_read_file cfs_write_file);
use PVE::Network::SDN;
use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::SubnetPlugin;
+use PVE::Network::SDN::Vnets;
use Storable qw(dclone);
use PVE::JSONSchema qw(get_standard_option);
@@ -204,9 +205,11 @@ __PACKAGE__->register_method ({
my $scfg = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id);
- my $subnet_cfg = PVE::Network::SDN::Subnets::config();
+ my $subnets_cfg = PVE::Network::SDN::Subnets::config();
+ my $vnets_cfg = PVE::Network::SDN::Vnets::config();
delete $cfg->{ids}->{$id};
+ PVE::Network::SDN::SubnetPlugin->on_delete_hook($id, $subnets_cfg, $vnets_cfg);
PVE::Network::SDN::Subnets::write_config($cfg);
PVE::Network::SDN::increase_version();
diff --git a/PVE/API2/Network/SDN/Vnets.pm b/PVE/API2/Network/SDN/Vnets.pm
index c5860c8..23bc8bb 100644
--- a/PVE/API2/Network/SDN/Vnets.pm
+++ b/PVE/API2/Network/SDN/Vnets.pm
@@ -11,6 +11,7 @@ use PVE::Network::SDN::Zones;
use PVE::Network::SDN::Zones::Plugin;
use PVE::Network::SDN::Vnets;
use PVE::Network::SDN::VnetPlugin;
+use PVE::Network::SDN::Subnets;
use Storable qw(dclone);
use PVE::JSONSchema qw(get_standard_option);
@@ -132,7 +133,9 @@ __PACKAGE__->register_method ({
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
$plugin->verify_tag($opts->{tag});
- PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg);
+ my $subnet_cfg = PVE::Network::SDN::Subnets::config();
+
+ PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg, $subnet_cfg);
PVE::Network::SDN::Vnets::write_config($cfg);
PVE::Network::SDN::increase_version();
@@ -173,7 +176,9 @@ __PACKAGE__->register_method ({
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
$plugin->verify_tag($opts->{tag});
- PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg);
+ my $subnet_cfg = PVE::Network::SDN::Subnets::config();
+
+ PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg, $subnet_cfg);
PVE::Network::SDN::Vnets::write_config($cfg);
PVE::Network::SDN::increase_version();
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index 8900681..1b790a6 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -112,4 +112,19 @@ sub on_update_hook {
raise_param_exc({ gateway => "$gateway is not in subnet $subnet"}) if $gateway && !$subnet_matcher->($gateway);
}
+sub on_delete_hook {
+ my ($class, $subnetid, $subnet_cfg, $vnet_cfg) = @_;
+
+ #verify if vnets have subnet
+ foreach my $id (keys %{$vnet_cfg->{ids}}) {
+ my $vnet = $vnet_cfg->{ids}->{$id};
+ my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
+ foreach my $subnet (@subnets) {
+ raise_param_exc({ subnet => "$subnet is attached to vnet $id"}) if $subnet eq $subnetid;
+ }
+ }
+
+ return;
+}
+
1;
diff --git a/PVE/Network/SDN/VnetPlugin.pm b/PVE/Network/SDN/VnetPlugin.pm
index 47ca50b..430b3bf 100644
--- a/PVE/Network/SDN/VnetPlugin.pm
+++ b/PVE/Network/SDN/VnetPlugin.pm
@@ -111,10 +111,12 @@ sub on_update_hook {
}
}
}
- #verify subnet
- my $subnets = $vnet_cfg->{ids}->{$vnetid}->{subnets};
- my @subnets = PVE::Tools::split_list($vnet_cfg->{ids}->{$vnetid}->{subnets}) if $plugin_config->{'peers'};
+ #verify subnet
+ my @subnets = PVE::Tools::split_list($vnet_cfg->{ids}->{$vnetid}->{subnets}) if $vnet_cfg->{ids}->{$vnetid}->{subnets};
+ foreach my $subnet (@subnets) {
+ raise_param_exc({ subnet => "$subnet not existing"}) if !$subnet_cfg->{ids}->{$subnet};
+ }
}
1;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 03/38] zones: simple|evpn: add gateway ip from subnets to vnet
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 01/38] vnets: add subnets Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 02/38] add subnets verifications hooks Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 04/38] zone: add vnet_update_hook Alexandre Derumier
` (35 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/Zones.pm | 4 +++-
PVE/Network/SDN/Zones/EvpnPlugin.pm | 11 ++++++++---
PVE/Network/SDN/Zones/Plugin.pm | 2 +-
PVE/Network/SDN/Zones/QinQPlugin.pm | 2 +-
PVE/Network/SDN/Zones/SimplePlugin.pm | 11 ++++++++---
PVE/Network/SDN/Zones/VlanPlugin.pm | 2 +-
PVE/Network/SDN/Zones/VxlanPlugin.pm | 8 +-------
7 files changed, 23 insertions(+), 17 deletions(-)
diff --git a/PVE/Network/SDN/Zones.pm b/PVE/Network/SDN/Zones.pm
index 143d6e5..25af088 100644
--- a/PVE/Network/SDN/Zones.pm
+++ b/PVE/Network/SDN/Zones.pm
@@ -11,6 +11,7 @@ use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
use PVE::Network;
use PVE::Network::SDN::Vnets;
+use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::Zones::VlanPlugin;
use PVE::Network::SDN::Zones::QinQPlugin;
use PVE::Network::SDN::Zones::VxlanPlugin;
@@ -78,6 +79,7 @@ sub generate_etc_network_config {
my $version = PVE::Cluster::cfs_read_file('sdn/.version');
my $vnet_cfg = PVE::Cluster::cfs_read_file('sdn/vnets.cfg');
my $zone_cfg = PVE::Cluster::cfs_read_file('sdn/zones.cfg');
+ my $subnet_cfg = PVE::Network::SDN::Subnets::config();
my $controller_cfg = PVE::Cluster::cfs_read_file('sdn/controllers.cfg');
return if !$vnet_cfg && !$zone_cfg;
@@ -112,7 +114,7 @@ sub generate_etc_network_config {
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
eval {
- $plugin->generate_sdn_config($plugin_config, $zone, $id, $vnet, $controller, $interfaces_config, $config);
+ $plugin->generate_sdn_config($plugin_config, $zone, $id, $vnet, $controller, $subnet_cfg, $interfaces_config, $config);
};
if (my $err = $@) {
warn "zone $zone : vnet $id : $err\n";
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index a916579..83ceb3a 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -38,7 +38,7 @@ sub options {
# Plugin implementation
sub generate_sdn_config {
- my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_;
+ my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $subnet_cfg, $interfaces_config, $config) = @_;
my $tag = $vnet->{tag};
my $alias = $vnet->{alias};
@@ -72,8 +72,13 @@ sub generate_sdn_config {
#vnet bridge
@iface_config = ();
- push @iface_config, "address $ipv4" if $ipv4;
- push @iface_config, "address $ipv6" if $ipv6;
+
+ my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
+ foreach my $subnet (@subnets) {
+ next if !defined($subnet_cfg->{ids}->{$subnet});
+ push @iface_config, "address $subnet_cfg->{ids}->{$subnet}->{gateway}" if $subnet_cfg->{ids}->{$subnet}->{gateway};
+ }
+
push @iface_config, "hwaddress $mac" if $mac;
push @iface_config, "bridge_ports $vxlan_iface";
push @iface_config, "bridge_stp off";
diff --git a/PVE/Network/SDN/Zones/Plugin.pm b/PVE/Network/SDN/Zones/Plugin.pm
index d96e069..451699f 100644
--- a/PVE/Network/SDN/Zones/Plugin.pm
+++ b/PVE/Network/SDN/Zones/Plugin.pm
@@ -94,7 +94,7 @@ sub parse_section_header {
}
sub generate_sdn_config {
- my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_;
+ my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $subnet_cfg, $interfaces_config, $config) = @_;
die "please implement inside plugin";
}
diff --git a/PVE/Network/SDN/Zones/QinQPlugin.pm b/PVE/Network/SDN/Zones/QinQPlugin.pm
index b39732a..5fffd15 100644
--- a/PVE/Network/SDN/Zones/QinQPlugin.pm
+++ b/PVE/Network/SDN/Zones/QinQPlugin.pm
@@ -45,7 +45,7 @@ sub options {
# Plugin implementation
sub generate_sdn_config {
- my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_;
+ my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $subnet_cfg, $interfaces_config, $config) = @_;
my $stag = $plugin_config->{tag};
my $mtu = $plugin_config->{mtu};
diff --git a/PVE/Network/SDN/Zones/SimplePlugin.pm b/PVE/Network/SDN/Zones/SimplePlugin.pm
index 6137062..312dcbf 100644
--- a/PVE/Network/SDN/Zones/SimplePlugin.pm
+++ b/PVE/Network/SDN/Zones/SimplePlugin.pm
@@ -20,7 +20,7 @@ sub options {
# Plugin implementation
sub generate_sdn_config {
- my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_;
+ my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $subnet_cfg, $interfaces_config, $config) = @_;
return $config if$config->{$vnetid}; # nothing to do
@@ -32,8 +32,13 @@ sub generate_sdn_config {
# vnet bridge
my @iface_config = ();
- push @iface_config, "address $ipv4" if $ipv4;
- push @iface_config, "address $ipv6" if $ipv6;
+
+ my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
+ foreach my $subnet (@subnets) {
+ next if !defined($subnet_cfg->{ids}->{$subnet});
+ push @iface_config, "address $subnet_cfg->{ids}->{$subnet}->{gateway}" if $subnet_cfg->{ids}->{$subnet}->{gateway};
+ }
+
push @iface_config, "hwaddress $mac" if $mac;
push @iface_config, "bridge_ports none";
push @iface_config, "bridge_stp off";
diff --git a/PVE/Network/SDN/Zones/VlanPlugin.pm b/PVE/Network/SDN/Zones/VlanPlugin.pm
index db719a0..8485ae1 100644
--- a/PVE/Network/SDN/Zones/VlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VlanPlugin.pm
@@ -39,7 +39,7 @@ sub options {
# Plugin implementation
sub generate_sdn_config {
- my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_;
+ my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $subnet_cfg, $interfaces_config, $config) = @_;
my $bridge = $plugin_config->{bridge};
die "can't find bridge $bridge" if !-d "/sys/class/net/$bridge";
diff --git a/PVE/Network/SDN/Zones/VxlanPlugin.pm b/PVE/Network/SDN/Zones/VxlanPlugin.pm
index a256268..8386c43 100644
--- a/PVE/Network/SDN/Zones/VxlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VxlanPlugin.pm
@@ -43,13 +43,10 @@ sub options {
# Plugin implementation
sub generate_sdn_config {
- my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $interfaces_config, $config) = @_;
+ my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $controller, $subnet_cfg, $interfaces_config, $config) = @_;
my $tag = $vnet->{tag};
my $alias = $vnet->{alias};
- my $ipv4 = $vnet->{ipv4};
- my $ipv6 = $vnet->{ipv6};
- my $mac = $vnet->{mac};
my $multicastaddress = $plugin_config->{'multicast-address'};
my @peers;
@peers = PVE::Tools::split_list($plugin_config->{'peers'}) if $plugin_config->{'peers'};
@@ -78,9 +75,6 @@ sub generate_sdn_config {
#vnet bridge
@iface_config = ();
- push @iface_config, "address $ipv4" if $ipv4;
- push @iface_config, "address $ipv6" if $ipv6;
- push @iface_config, "hwaddress $mac" if $mac;
push @iface_config, "bridge_ports $vxlan_iface";
push @iface_config, "bridge_stp off";
push @iface_config, "bridge_fd 0";
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 04/38] zone: add vnet_update_hook
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (2 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 03/38] zones: simple|evpn: add gateway ip from subnets to vnet Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 05/38] vnets: subnets: use cidr Alexandre Derumier
` (34 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
move verify_tag code in this hook
add mac address generation for simple && evpn plugin
---
PVE/API2/Network/SDN/Vnets.pm | 4 ++--
PVE/Network/SDN/Zones/EvpnPlugin.pm | 19 +++++++++++++++----
PVE/Network/SDN/Zones/Plugin.pm | 5 +++--
PVE/Network/SDN/Zones/QinQPlugin.pm | 8 ++++----
PVE/Network/SDN/Zones/SimplePlugin.pm | 14 +++++++++++---
PVE/Network/SDN/Zones/VlanPlugin.pm | 8 ++++----
PVE/Network/SDN/Zones/VxlanPlugin.pm | 8 ++++----
7 files changed, 43 insertions(+), 23 deletions(-)
diff --git a/PVE/API2/Network/SDN/Vnets.pm b/PVE/API2/Network/SDN/Vnets.pm
index 23bc8bb..58ec21f 100644
--- a/PVE/API2/Network/SDN/Vnets.pm
+++ b/PVE/API2/Network/SDN/Vnets.pm
@@ -131,7 +131,7 @@ __PACKAGE__->register_method ({
my $zoneid = $cfg->{ids}->{$id}->{zone};
my $plugin_config = $zone_cfg->{ids}->{$zoneid};
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
- $plugin->verify_tag($opts->{tag});
+ $plugin->vnet_update_hook($cfg->{ids}->{$id});
my $subnet_cfg = PVE::Network::SDN::Subnets::config();
@@ -174,7 +174,7 @@ __PACKAGE__->register_method ({
my $zoneid = $cfg->{ids}->{$id}->{zone};
my $plugin_config = $zone_cfg->{ids}->{$zoneid};
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
- $plugin->verify_tag($opts->{tag});
+ $plugin->vnet_update_hook($cfg->{ids}->{$id});
my $subnet_cfg = PVE::Network::SDN::Subnets::config();
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index 83ceb3a..0ebe13e 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -5,6 +5,9 @@ use warnings;
use PVE::Network::SDN::Zones::VxlanPlugin;
use PVE::Tools qw($IPV4RE);
use PVE::INotify;
+use PVE::Cluster;
+use PVE::Tools;
+
use PVE::Network::SDN::Controllers::EvpnPlugin;
use base('PVE::Network::SDN::Zones::VxlanPlugin');
@@ -143,15 +146,23 @@ sub on_update_hook {
die "vrf-vxlan $vrfvxlan is already declared in $id"
if (defined($zone_cfg->{ids}->{$id}->{'vrf-vxlan'}) && $zone_cfg->{ids}->{$id}->{'vrf-vxlan'} eq $vrfvxlan);
}
+
}
-sub verify_tag {
- my ($class, $tag) = @_;
- raise_param_exc({ tag => "missing vxlan tag"}) if !defined($tag);
- raise_param_exc({ tag => "vxlan tag max value is 16777216"}) if $tag > 16777216;
+sub vnet_update_hook {
+ my ($class, $vnet) = @_;
+
+ raise_param_exc({ tag => "missing vxlan tag"}) if !defined($vnet->{tag});
+ raise_param_exc({ tag => "vxlan tag max value is 16777216"}) if $vnet->{tag} > 16777216;
+
+ if (!defined($vnet->{mac})) {
+ my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
+ $vnet->{mac} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
+ }
}
+
1;
diff --git a/PVE/Network/SDN/Zones/Plugin.pm b/PVE/Network/SDN/Zones/Plugin.pm
index 451699f..7f6db0e 100644
--- a/PVE/Network/SDN/Zones/Plugin.pm
+++ b/PVE/Network/SDN/Zones/Plugin.pm
@@ -139,8 +139,9 @@ sub on_update_hook {
# do nothing by default
}
-sub verify_tag {
- my ($class, $tag) = @_;
+sub vnet_update_hook {
+ my ($class, $vnet) = @_;
+
# do nothing by default
}
diff --git a/PVE/Network/SDN/Zones/QinQPlugin.pm b/PVE/Network/SDN/Zones/QinQPlugin.pm
index 5fffd15..c828af4 100644
--- a/PVE/Network/SDN/Zones/QinQPlugin.pm
+++ b/PVE/Network/SDN/Zones/QinQPlugin.pm
@@ -211,11 +211,11 @@ sub status {
return $err_msg;
}
-sub verify_tag {
- my ($class, $tag) = @_;
+sub vnet_update_hook {
+ my ($class, $vnet) = @_;
- raise_param_exc({ tag => "missing vlan tag"}) if !defined($tag);
- raise_param_exc({ tag => "vlan tag max value is 4096"}) if $tag > 4096;
+ raise_param_exc({ tag => "missing vlan tag"}) if !defined($vnet->{tag});
+ raise_param_exc({ tag => "vlan tag max value is 4096"}) if $vnet->{tag} > 4096;
}
1;
diff --git a/PVE/Network/SDN/Zones/SimplePlugin.pm b/PVE/Network/SDN/Zones/SimplePlugin.pm
index 312dcbf..7006b13 100644
--- a/PVE/Network/SDN/Zones/SimplePlugin.pm
+++ b/PVE/Network/SDN/Zones/SimplePlugin.pm
@@ -4,6 +4,8 @@ use strict;
use warnings;
use PVE::Network::SDN::Zones::Plugin;
use PVE::Exception qw(raise raise_param_exc);
+use PVE::Cluster;
+use PVE::Tools;
use base('PVE::Network::SDN::Zones::Plugin');
@@ -71,10 +73,16 @@ sub status {
return $err_msg;
}
-sub verify_tag {
- my ($class, $tag) = @_;
- raise_param_exc({ tag => "vlan tag is not allowed on simple bridge"}) if defined($tag);
+sub vnet_update_hook {
+ my ($class, $vnet) = @_;
+
+ raise_param_exc({ tag => "vlan tag is not allowed on simple bridge"}) if defined($vnet->{tag});
+
+ if (!defined($vnet->{mac})) {
+ my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
+ $vnet->{mac} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
+ }
}
1;
diff --git a/PVE/Network/SDN/Zones/VlanPlugin.pm b/PVE/Network/SDN/Zones/VlanPlugin.pm
index 8485ae1..7f90d31 100644
--- a/PVE/Network/SDN/Zones/VlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VlanPlugin.pm
@@ -170,11 +170,11 @@ sub status {
return $err_msg;
}
-sub verify_tag {
- my ($class, $tag) = @_;
+sub vnet_update_hook {
+ my ($class, $vnet) = @_;
- raise_param_exc({ tag => "missing vlan tag"}) if !defined($tag);
- raise_param_exc({ tag => "vlan tag max value is 4096"}) if $tag > 4096;
+ raise_param_exc({ tag => "missing vlan tag"}) if !defined($vnet->{tag});
+ raise_param_exc({ tag => "vlan tag max value is 4096"}) if $vnet->{tag} > 4096;
}
1;
diff --git a/PVE/Network/SDN/Zones/VxlanPlugin.pm b/PVE/Network/SDN/Zones/VxlanPlugin.pm
index 8386c43..79af054 100644
--- a/PVE/Network/SDN/Zones/VxlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VxlanPlugin.pm
@@ -89,11 +89,11 @@ sub generate_sdn_config {
return $config;
}
-sub verify_tag {
- my ($class, $tag) = @_;
+sub vnet_update_hook {
+ my ($class, $vnet) = @_;
- raise_param_exc({ tag => "missing vxlan tag"}) if !defined($tag);
- raise_param_exc({ tag => "vxlan tag max value is 16777216"}) if $tag > 16777216;
+ raise_param_exc({ tag => "missing vxlan tag"}) if !defined($vnet->{tag});
+ raise_param_exc({ tag => "vxlan tag max value is 16777216"}) if $vnet->{tag} > 16777216;
}
1;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 05/38] vnets: subnets: use cidr
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (3 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 04/38] zone: add vnet_update_hook Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 06/38] subnet: fix on_delete_hook Alexandre Derumier
` (33 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/SubnetPlugin.pm | 3 ++-
PVE/Network/SDN/VnetPlugin.pm | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index 1b790a6..c555314 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -120,7 +120,8 @@ sub on_delete_hook {
my $vnet = $vnet_cfg->{ids}->{$id};
my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
foreach my $subnet (@subnets) {
- raise_param_exc({ subnet => "$subnet is attached to vnet $id"}) if $subnet eq $subnetid;
+ my $id = $subnet =~ s/\//-/r;
+ raise_param_exc({ subnet => "$subnet is attached to vnet $id"}) if $id eq $subnetid;
}
}
diff --git a/PVE/Network/SDN/VnetPlugin.pm b/PVE/Network/SDN/VnetPlugin.pm
index 430b3bf..6b2bcc8 100644
--- a/PVE/Network/SDN/VnetPlugin.pm
+++ b/PVE/Network/SDN/VnetPlugin.pm
@@ -115,7 +115,8 @@ sub on_update_hook {
#verify subnet
my @subnets = PVE::Tools::split_list($vnet_cfg->{ids}->{$vnetid}->{subnets}) if $vnet_cfg->{ids}->{$vnetid}->{subnets};
foreach my $subnet (@subnets) {
- raise_param_exc({ subnet => "$subnet not existing"}) if !$subnet_cfg->{ids}->{$subnet};
+ my $id = $subnet =~ s/\//-/r;
+ raise_param_exc({ subnet => "$subnet not existing"}) if !$subnet_cfg->{ids}->{$id};
}
}
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 06/38] subnet: fix on_delete_hook
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (4 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 05/38] vnets: subnets: use cidr Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 07/38] api2: subnet create: convert cidr to subnetid Alexandre Derumier
` (32 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/SubnetPlugin.pm | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index c555314..ea47684 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -116,12 +116,12 @@ sub on_delete_hook {
my ($class, $subnetid, $subnet_cfg, $vnet_cfg) = @_;
#verify if vnets have subnet
- foreach my $id (keys %{$vnet_cfg->{ids}}) {
- my $vnet = $vnet_cfg->{ids}->{$id};
+ foreach my $vnetid (keys %{$vnet_cfg->{ids}}) {
+ my $vnet = $vnet_cfg->{ids}->{$vnetid};
my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
foreach my $subnet (@subnets) {
my $id = $subnet =~ s/\//-/r;
- raise_param_exc({ subnet => "$subnet is attached to vnet $id"}) if $id eq $subnetid;
+ raise_param_exc({ subnet => "$subnet is attached to vnet $vnetid"}) if $id eq $subnetid;
}
}
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 07/38] api2: subnet create: convert cidr to subnetid
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (5 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 06/38] subnet: fix on_delete_hook Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 08/38] api2: increase version on apply/reload only Alexandre Derumier
` (31 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN/Subnets.pm | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index 3ef1d11..d18cf90 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -24,6 +24,7 @@ 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;
@@ -112,7 +113,8 @@ __PACKAGE__->register_method ({
my ($param) = @_;
my $type = extract_param($param, 'type');
- my $id = extract_param($param, 'subnet');
+ my $cidr = extract_param($param, 'subnet');
+ my $id = $cidr =~ s/\//-/r;
# create /etc/pve/sdn directory
PVE::Cluster::check_cfs_quorum();
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 08/38] api2: increase version on apply/reload only
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (6 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 07/38] api2: subnet create: convert cidr to subnetid Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 09/38] add ipams plugins Alexandre Derumier
` (30 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN.pm | 3 +++
PVE/API2/Network/SDN/Controllers.pm | 6 ------
PVE/API2/Network/SDN/Subnets.pm | 3 ---
PVE/API2/Network/SDN/Vnets.pm | 3 ---
PVE/API2/Network/SDN/Zones.pm | 6 ------
5 files changed, 3 insertions(+), 18 deletions(-)
diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm
index 38af746..175f76f 100644
--- a/PVE/API2/Network/SDN.pm
+++ b/PVE/API2/Network/SDN.pm
@@ -10,6 +10,7 @@ use PVE::RESTHandler;
use PVE::RPCEnvironment;
use PVE::SafeSyslog;
use PVE::Tools qw(run_command);
+use PVE::Network::SDN;
use PVE::API2::Network::SDN::Controllers;
use PVE::API2::Network::SDN::Vnets;
@@ -111,6 +112,8 @@ __PACKAGE__->register_method ({
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
+ PVE::Network::SDN::increase_version();
+
my $code = sub {
$rpcenv->{type} = 'priv'; # to start tasks in background
PVE::Cluster::check_cfs_quorum();
diff --git a/PVE/API2/Network/SDN/Controllers.pm b/PVE/API2/Network/SDN/Controllers.pm
index 9bc3075..919d343 100644
--- a/PVE/API2/Network/SDN/Controllers.pm
+++ b/PVE/API2/Network/SDN/Controllers.pm
@@ -152,8 +152,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::Controllers::write_config($controller_cfg);
- PVE::Network::SDN::increase_version();
-
}, "create sdn controller object failed");
return undef;
@@ -196,8 +194,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::Controllers::write_config($controller_cfg);
- PVE::Network::SDN::increase_version();
-
}, "update sdn controller object failed");
@@ -243,8 +239,6 @@ __PACKAGE__->register_method ({
delete $cfg->{ids}->{$id};
PVE::Network::SDN::Controllers::write_config($cfg);
- PVE::Network::SDN::increase_version();
-
}, "delete sdn controller object failed");
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index d18cf90..d9cb9e9 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -134,7 +134,6 @@ __PACKAGE__->register_method ({
$cfg->{ids}->{$id} = $opts;
PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $cfg);
PVE::Network::SDN::Subnets::write_config($cfg);
- PVE::Network::SDN::increase_version();
}, "create sdn subnet object failed");
@@ -170,7 +169,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $cfg);
PVE::Network::SDN::Subnets::write_config($cfg);
- PVE::Network::SDN::increase_version();
}, "update sdn subnet object failed");
@@ -213,7 +211,6 @@ __PACKAGE__->register_method ({
delete $cfg->{ids}->{$id};
PVE::Network::SDN::SubnetPlugin->on_delete_hook($id, $subnets_cfg, $vnets_cfg);
PVE::Network::SDN::Subnets::write_config($cfg);
- PVE::Network::SDN::increase_version();
}, "delete sdn subnet object failed");
diff --git a/PVE/API2/Network/SDN/Vnets.pm b/PVE/API2/Network/SDN/Vnets.pm
index 58ec21f..b585c9c 100644
--- a/PVE/API2/Network/SDN/Vnets.pm
+++ b/PVE/API2/Network/SDN/Vnets.pm
@@ -138,7 +138,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg, $subnet_cfg);
PVE::Network::SDN::Vnets::write_config($cfg);
- PVE::Network::SDN::increase_version();
}, "create sdn vnet object failed");
@@ -181,7 +180,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg, $subnet_cfg);
PVE::Network::SDN::Vnets::write_config($cfg);
- PVE::Network::SDN::increase_version();
}, "update sdn vnet object failed");
@@ -221,7 +219,6 @@ __PACKAGE__->register_method ({
delete $cfg->{ids}->{$id};
PVE::Network::SDN::Vnets::write_config($cfg);
- PVE::Network::SDN::increase_version();
}, "delete sdn vnet object failed");
diff --git a/PVE/API2/Network/SDN/Zones.pm b/PVE/API2/Network/SDN/Zones.pm
index f629f43..a37df3d 100644
--- a/PVE/API2/Network/SDN/Zones.pm
+++ b/PVE/API2/Network/SDN/Zones.pm
@@ -161,8 +161,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::Zones::write_config($zone_cfg);
- PVE::Network::SDN::increase_version();
-
}, "create sdn zone object failed");
return undef;
@@ -206,8 +204,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::Zones::write_config($zone_cfg);
- PVE::Network::SDN::increase_version();
-
}, "update sdn zone object failed");
return undef;
@@ -252,8 +248,6 @@ __PACKAGE__->register_method ({
delete $cfg->{ids}->{$id};
PVE::Network::SDN::Zones::write_config($cfg);
- PVE::Network::SDN::increase_version();
-
}, "delete sdn zone object failed");
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 09/38] add ipams plugins
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (7 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 08/38] api2: increase version on apply/reload only Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 10/38] add pve internal ipam plugin Alexandre Derumier
` (29 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN.pm | 7 +
PVE/API2/Network/SDN/Ipams.pm | 241 +++++++++++++++++++++++++
PVE/API2/Network/SDN/Makefile | 2 +-
PVE/API2/Network/SDN/Subnets.pm | 47 ++++-
PVE/Network/SDN/Ipams.pm | 78 ++++++++
PVE/Network/SDN/Ipams/Makefile | 8 +
PVE/Network/SDN/Ipams/NetboxPlugin.pm | 169 +++++++++++++++++
PVE/Network/SDN/Ipams/PhpIpamPlugin.pm | 189 +++++++++++++++++++
PVE/Network/SDN/Ipams/Plugin.pm | 127 +++++++++++++
PVE/Network/SDN/Makefile | 3 +-
PVE/Network/SDN/SubnetPlugin.pm | 5 +-
PVE/Network/SDN/Vnets.pm | 25 +++
12 files changed, 895 insertions(+), 6 deletions(-)
create mode 100644 PVE/API2/Network/SDN/Ipams.pm
create mode 100644 PVE/Network/SDN/Ipams.pm
create mode 100644 PVE/Network/SDN/Ipams/Makefile
create mode 100644 PVE/Network/SDN/Ipams/NetboxPlugin.pm
create mode 100644 PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
create mode 100644 PVE/Network/SDN/Ipams/Plugin.pm
diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm
index 175f76f..6055fe5 100644
--- a/PVE/API2/Network/SDN.pm
+++ b/PVE/API2/Network/SDN.pm
@@ -16,6 +16,7 @@ use PVE::API2::Network::SDN::Controllers;
use PVE::API2::Network::SDN::Vnets;
use PVE::API2::Network::SDN::Zones;
use PVE::API2::Network::SDN::Subnets;
+use PVE::API2::Network::SDN::Ipams;
use base qw(PVE::RESTHandler);
@@ -39,6 +40,11 @@ __PACKAGE__->register_method ({
path => 'subnets',
});
+__PACKAGE__->register_method ({
+ subclass => "PVE::API2::Network::SDN::Ipams",
+ path => 'ipams',
+});
+
__PACKAGE__->register_method({
name => 'index',
path => '',
@@ -69,6 +75,7 @@ __PACKAGE__->register_method({
{ id => 'zones' },
{ id => 'controllers' },
{ id => 'subnets' },
+ { id => 'ipams' },
];
return $res;
diff --git a/PVE/API2/Network/SDN/Ipams.pm b/PVE/API2/Network/SDN/Ipams.pm
new file mode 100644
index 0000000..f8665a1
--- /dev/null
+++ b/PVE/API2/Network/SDN/Ipams.pm
@@ -0,0 +1,241 @@
+package PVE::API2::Network::SDN::Ipams;
+
+use strict;
+use warnings;
+
+use PVE::SafeSyslog;
+use PVE::Tools qw(extract_param);
+use PVE::Cluster qw(cfs_read_file cfs_write_file);
+use PVE::Network::SDN;
+use PVE::Network::SDN::Ipams;
+use PVE::Network::SDN::Ipams::Plugin;
+use PVE::Network::SDN::Ipams::PhpIpamPlugin;
+use PVE::Network::SDN::Ipams::NetboxPlugin;
+
+use Storable qw(dclone);
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::RPCEnvironment;
+
+use PVE::RESTHandler;
+
+use base qw(PVE::RESTHandler);
+
+my $sdn_ipams_type_enum = PVE::Network::SDN::Ipams::Plugin->lookup_types();
+
+my $api_sdn_ipams_config = sub {
+ my ($cfg, $id) = @_;
+
+ my $scfg = dclone(PVE::Network::SDN::Ipams::sdn_ipams_config($cfg, $id));
+ $scfg->{ipam} = $id;
+ $scfg->{digest} = $cfg->{digest};
+
+ return $scfg;
+};
+
+__PACKAGE__->register_method ({
+ name => 'index',
+ path => '',
+ method => 'GET',
+ description => "SDN ipams index.",
+ permissions => {
+ description => "Only list entries where you have 'SDN.Audit' or 'SDN.Allocate' permissions on '/sdn/ipams/<ipam>'",
+ user => 'all',
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ type => {
+ description => "Only list sdn ipams of specific type",
+ type => 'string',
+ enum => $sdn_ipams_type_enum,
+ optional => 1,
+ },
+ },
+ },
+ returns => {
+ type => 'array',
+ items => {
+ type => "object",
+ properties => { ipam => { type => 'string'},
+ type => { type => 'string'},
+ },
+ },
+ links => [ { rel => 'child', href => "{ipam}" } ],
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $rpcenv = PVE::RPCEnvironment::get();
+ my $authuser = $rpcenv->get_user();
+
+
+ my $cfg = PVE::Network::SDN::Ipams::config();
+
+ my @sids = PVE::Network::SDN::Ipams::sdn_ipams_ids($cfg);
+ my $res = [];
+ foreach my $id (@sids) {
+ my $privs = [ 'SDN.Audit', 'SDN.Allocate' ];
+ next if !$rpcenv->check_any($authuser, "/sdn/ipams/$id", $privs, 1);
+
+ my $scfg = &$api_sdn_ipams_config($cfg, $id);
+ next if $param->{type} && $param->{type} ne $scfg->{type};
+
+ my $plugin_config = $cfg->{ids}->{$id};
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+ push @$res, $scfg;
+ }
+
+ return $res;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'read',
+ path => '{ipam}',
+ method => 'GET',
+ description => "Read sdn ipam configuration.",
+ permissions => {
+ check => ['perm', '/sdn/ipams/{ipam}', ['SDN.Allocate']],
+ },
+
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ ipam => get_standard_option('pve-sdn-ipam-id'),
+ },
+ },
+ returns => { type => 'object' },
+ code => sub {
+ my ($param) = @_;
+
+ my $cfg = PVE::Network::SDN::Ipams::config();
+
+ return &$api_sdn_ipams_config($cfg, $param->{ipam});
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'create',
+ protected => 1,
+ path => '',
+ method => 'POST',
+ description => "Create a new sdn ipam object.",
+ permissions => {
+ check => ['perm', '/sdn/ipams', ['SDN.Allocate']],
+ },
+ parameters => PVE::Network::SDN::Ipams::Plugin->createSchema(),
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $type = extract_param($param, 'type');
+ my $id = extract_param($param, 'ipam');
+
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($type);
+ my $opts = $plugin->check_config($id, $param, 1, 1);
+
+ # create /etc/pve/sdn directory
+ PVE::Cluster::check_cfs_quorum();
+ mkdir("/etc/pve/sdn");
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ my $controller_cfg = PVE::Network::SDN::Controllers::config();
+
+ my $scfg = undef;
+ if ($scfg = PVE::Network::SDN::Ipams::sdn_ipams_config($ipam_cfg, $id, 1)) {
+ die "sdn ipam object ID '$id' already defined\n";
+ }
+
+ $ipam_cfg->{ids}->{$id} = $opts;
+
+ PVE::Network::SDN::Ipams::write_config($ipam_cfg);
+
+ }, "create sdn ipam object failed");
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'update',
+ protected => 1,
+ path => '{ipam}',
+ method => 'PUT',
+ description => "Update sdn ipam object configuration.",
+ permissions => {
+ check => ['perm', '/sdn/ipams', ['SDN.Allocate']],
+ },
+ parameters => PVE::Network::SDN::Ipams::Plugin->updateSchema(),
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $id = extract_param($param, 'ipam');
+ my $digest = extract_param($param, 'digest');
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+
+ PVE::SectionConfig::assert_if_modified($ipam_cfg, $digest);
+
+ my $scfg = PVE::Network::SDN::Ipams::sdn_ipams_config($ipam_cfg, $id);
+
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($scfg->{type});
+ my $opts = $plugin->check_config($id, $param, 0, 1);
+
+ foreach my $k (%$opts) {
+ $scfg->{$k} = $opts->{$k};
+ }
+
+ PVE::Network::SDN::Ipams::write_config($ipam_cfg);
+
+ }, "update sdn ipam object failed");
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'delete',
+ protected => 1,
+ path => '{ipam}',
+ method => 'DELETE',
+ description => "Delete sdn ipam object configuration.",
+ permissions => {
+ check => ['perm', '/sdn/ipams', ['SDN.Allocate']],
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ ipam => get_standard_option('pve-sdn-ipam-id', {
+ completion => \&PVE::Network::SDN::Ipams::complete_sdn_ipams,
+ }),
+ },
+ },
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $id = extract_param($param, 'ipam');
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+
+ my $cfg = PVE::Network::SDN::Ipams::config();
+
+ my $scfg = PVE::Network::SDN::Ipams::sdn_ipams_config($cfg, $id);
+
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($scfg->{type});
+
+ my $vnet_cfg = PVE::Network::SDN::Vnets::config();
+
+ delete $cfg->{ids}->{$id};
+ PVE::Network::SDN::Ipams::write_config($cfg);
+
+ }, "delete sdn zone object failed");
+
+ return undef;
+ }});
+
+1;
diff --git a/PVE/API2/Network/SDN/Makefile b/PVE/API2/Network/SDN/Makefile
index 59626fa..1117dfa 100644
--- a/PVE/API2/Network/SDN/Makefile
+++ b/PVE/API2/Network/SDN/Makefile
@@ -1,4 +1,4 @@
-SOURCES=Vnets.pm Zones.pm Controllers.pm Subnets.pm
+SOURCES=Vnets.pm Zones.pm Controllers.pm Subnets.pm Ipams.pm
PERL5DIR=${DESTDIR}/usr/share/perl5
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index d9cb9e9..b60db3d 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -6,10 +6,13 @@ use warnings;
use PVE::SafeSyslog;
use PVE::Tools qw(extract_param);
use PVE::Cluster qw(cfs_read_file cfs_write_file);
+use PVE::Exception qw(raise raise_param_exc);
use PVE::Network::SDN;
use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::SubnetPlugin;
use PVE::Network::SDN::Vnets;
+use PVE::Network::SDN::Ipams;
+use PVE::Network::SDN::Ipams::Plugin;
use Storable qw(dclone);
use PVE::JSONSchema qw(get_standard_option);
@@ -133,6 +136,17 @@ __PACKAGE__->register_method ({
$cfg->{ids}->{$id} = $opts;
PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $cfg);
+
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ my $ipam = $cfg->{ids}->{$id}->{ipam};
+ if ($ipam) {
+ raise_param_exc({ ipam => "$ipam not existing"}) if !$ipam_cfg->{ids}->{$ipam};
+ my $plugin_config = $ipam_cfg->{ids}->{$ipam};
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+ $plugin->add_subnet($plugin_config, $id, $cfg->{ids}->{$id});
+ $plugin->add_ip($plugin_config, $id, $opts->{gateway}, 1) if $opts->{gateway};
+ }
+
PVE::Network::SDN::Subnets::write_config($cfg);
}, "create sdn subnet object failed");
@@ -161,6 +175,7 @@ __PACKAGE__->register_method ({
sub {
my $cfg = PVE::Network::SDN::Subnets::config();
+ my $scfg = &$api_sdn_subnets_config($cfg, $id);
PVE::SectionConfig::assert_if_modified($cfg, $digest);
@@ -168,6 +183,24 @@ __PACKAGE__->register_method ({
$cfg->{ids}->{$id} = $opts;
PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $cfg);
+
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ my $ipam = $cfg->{ids}->{$id}->{ipam};
+ if ($ipam) {
+ raise_param_exc({ ipam => "$ipam not existing"}) if !$ipam_cfg->{ids}->{$ipam};
+ my $plugin_config = $ipam_cfg->{ids}->{$ipam};
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+ $plugin->add_subnet($plugin_config, $id, $cfg->{ids}->{$id});
+
+ if($opts->{gateway} && $scfg->{gateway} && $opts->{gateway} ne $scfg->{gateway}) {
+ $plugin->del_ip($plugin_config, $scfg->{gateway});
+ }
+ if (!defined($opts->{gateway}) && $scfg->{gateway}) {
+ $plugin->del_ip($plugin_config, $scfg->{gateway});
+ }
+ $plugin->add_ip($plugin_config, $id, $opts->{gateway}, 1) if $opts->{gateway};
+ }
+
PVE::Network::SDN::Subnets::write_config($cfg);
}, "update sdn subnet object failed");
@@ -200,7 +233,6 @@ __PACKAGE__->register_method ({
PVE::Network::SDN::lock_sdn_config(
sub {
-
my $cfg = PVE::Network::SDN::Subnets::config();
my $scfg = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id);
@@ -208,8 +240,19 @@ __PACKAGE__->register_method ({
my $subnets_cfg = PVE::Network::SDN::Subnets::config();
my $vnets_cfg = PVE::Network::SDN::Vnets::config();
- delete $cfg->{ids}->{$id};
PVE::Network::SDN::SubnetPlugin->on_delete_hook($id, $subnets_cfg, $vnets_cfg);
+
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ my $ipam = $cfg->{ids}->{$id}->{ipam};
+ if ($ipam) {
+ raise_param_exc({ ipam => "$ipam not existing"}) if !$ipam_cfg->{ids}->{$ipam};
+ my $plugin_config = $ipam_cfg->{ids}->{$ipam};
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+ $plugin->del_subnet($plugin_config, $id, $scfg);
+ }
+
+ delete $cfg->{ids}->{$id};
+
PVE::Network::SDN::Subnets::write_config($cfg);
}, "delete sdn subnet object failed");
diff --git a/PVE/Network/SDN/Ipams.pm b/PVE/Network/SDN/Ipams.pm
new file mode 100644
index 0000000..3d33632
--- /dev/null
+++ b/PVE/Network/SDN/Ipams.pm
@@ -0,0 +1,78 @@
+package PVE::Network::SDN::Ipams;
+
+use strict;
+use warnings;
+
+use Data::Dumper;
+use JSON;
+
+use PVE::Tools qw(extract_param dir_glob_regex run_command);
+use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+use PVE::Network;
+
+use PVE::Network::SDN::Ipams::NetboxPlugin;
+use PVE::Network::SDN::Ipams::PhpIpamPlugin;
+use PVE::Network::SDN::Ipams::Plugin;
+
+PVE::Network::SDN::Ipams::NetboxPlugin->register();
+PVE::Network::SDN::Ipams::PhpIpamPlugin->register();
+PVE::Network::SDN::Ipams::Plugin->init();
+
+
+sub sdn_ipams_config {
+ my ($cfg, $id, $noerr) = @_;
+
+ die "no sdn ipam ID specified\n" if !$id;
+
+ my $scfg = $cfg->{ids}->{$id};
+ die "sdn '$id' does not exist\n" if (!$noerr && !$scfg);
+
+ return $scfg;
+}
+
+sub config {
+ my $config = cfs_read_file("sdn/ipams.cfg");
+ return $config;
+}
+
+sub get_plugin_config {
+ my ($vnet) = @_;
+ my $ipamid = $vnet->{ipam};
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ return $ipam_cfg->{ids}->{$ipamid};
+}
+
+sub write_config {
+ my ($cfg) = @_;
+
+ cfs_write_file("sdn/ipams.cfg", $cfg);
+}
+
+sub sdn_ipams_ids {
+ my ($cfg) = @_;
+
+ return keys %{$cfg->{ids}};
+}
+
+sub complete_sdn_vnet {
+ my ($cmdname, $pname, $cvalue) = @_;
+
+ my $cfg = PVE::Network::SDN::Ipams::config();
+
+ return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::Vnets::sdn_ipams_ids($cfg) ];
+}
+
+sub next_free_ip {
+ my ($subnetid, $subnet) = @_;
+
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ my $ipamid = $subnet->{ipam};
+ return if !$ipamid;
+
+ my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+ my $ip = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet);
+ return $ip;
+}
+1;
+
diff --git a/PVE/Network/SDN/Ipams/Makefile b/PVE/Network/SDN/Ipams/Makefile
new file mode 100644
index 0000000..884c47a
--- /dev/null
+++ b/PVE/Network/SDN/Ipams/Makefile
@@ -0,0 +1,8 @@
+SOURCES=Plugin.pm PhpIpamPlugin.pm NetboxPlugin.pm
+
+
+PERL5DIR=${DESTDIR}/usr/share/perl5
+
+.PHONY: install
+install:
+ for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/Network/SDN/Ipams/$$i; done
diff --git a/PVE/Network/SDN/Ipams/NetboxPlugin.pm b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
new file mode 100644
index 0000000..ccc1184
--- /dev/null
+++ b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
@@ -0,0 +1,169 @@
+package PVE::Network::SDN::Ipams::NetboxPlugin;
+
+use strict;
+use warnings;
+use PVE::INotify;
+use PVE::Cluster;
+use PVE::Tools;
+
+use base('PVE::Network::SDN::Ipams::Plugin');
+
+sub type {
+ return 'netbox';
+}
+
+sub properties {
+ return {
+ };
+}
+
+sub options {
+
+ return {
+ url => { optional => 0},
+ token => { optional => 0 },
+ };
+}
+
+# Plugin implementation
+
+sub add_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $gateway = $subnet->{gateway};
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
+
+ my $internalid = get_prefix_id($url, $cidr, $headers);
+
+ #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: $@";
+ }
+ }
+
+}
+
+sub del_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $gateway = $subnet->{gateway};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
+
+ 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, $gateway) if $gateway;
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/ipam/prefixes/$internalid/", $headers);
+ };
+ if ($@) {
+ die "error deleting subnet from ipam: $@";
+ }
+
+}
+
+sub add_ip {
+ my ($class, $plugin_config, $subnetid, $ip, $is_gateway) = @_;
+
+ my ($network, $mask) = split(/-/, $subnetid);
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $section = $plugin_config->{section};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
+
+ my $params = { address => "$ip/$mask" };
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("POST", "$url/ipam/ip-addresses/", $headers, $params);
+ };
+
+ if ($@) {
+ die "error add subnet ip to ipam: ip already exist: $@";
+ }
+}
+
+sub add_next_freeip {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
+
+ my $internalid = get_prefix_id($url, $cidr, $headers);
+
+ my $params = {};
+
+ my $ip = undef;
+ eval {
+ my $result = PVE::Network::SDN::Ipams::Plugin::api_request("POST", "$url/ipam/prefixes/$internalid/available-ips/", $headers, $params);
+ $ip = $result->{address};
+ };
+
+ if ($@) {
+ die "can't find free ip in subnet $cidr: $@";
+ }
+
+ return $ip;
+}
+
+sub del_ip {
+ my ($class, $plugin_config, $ip) = @_;
+
+ return if !$ip;
+
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
+
+ my $ip_id = get_ip_id($url, $ip, $headers);
+ die "can't find ip $ip in ipam" if !$ip_id;
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/ipam/ip-addresses/$ip_id/", $headers);
+ };
+ if ($@) {
+ die "error delete ip $ip";
+ }
+}
+
+#helpers
+
+sub get_prefix_id {
+ my ($url, $cidr, $headers) = @_;
+
+ my $result = PVE::Network::SDN::Ipams::Plugin::api_request("GET", "$url/ipam/prefixes/?q=$cidr", $headers);
+ my $data = @{$result->{results}}[0];
+ my $internalid = $data->{id};
+ return $internalid;
+}
+
+sub get_ip_id {
+ my ($url, $ip, $headers) = @_;
+ my $result = PVE::Network::SDN::Ipams::Plugin::api_request("GET", "$url/ipam/ip-addresses/?q=$ip", $headers);
+ my $data = @{$result->{results}}[0];
+ my $ip_id = $data->{id};
+ return $ip_id;
+}
+
+
+1;
+
+
diff --git a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
new file mode 100644
index 0000000..7380bf3
--- /dev/null
+++ b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
@@ -0,0 +1,189 @@
+package PVE::Network::SDN::Ipams::PhpIpamPlugin;
+
+use strict;
+use warnings;
+use PVE::INotify;
+use PVE::Cluster;
+use PVE::Tools;
+
+use base('PVE::Network::SDN::Ipams::Plugin');
+
+sub type {
+ return 'phpipam';
+}
+
+sub properties {
+ return {
+ url => {
+ type => 'string',
+ },
+ token => {
+ type => 'string',
+ },
+ section => {
+ type => 'integer',
+ },
+ };
+}
+
+sub options {
+
+ return {
+ url => { optional => 0},
+ token => { optional => 0 },
+ section => { optional => 0 },
+ };
+}
+
+# Plugin implementation
+
+sub add_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $gateway = $subnet->{gateway};
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $section = $plugin_config->{section};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token];
+
+ #search subnet
+ my $internalid = get_internalid($url, $cidr, $headers);
+
+ #create subnet
+ if (!$internalid) {
+ my ($network, $mask) = split(/-/, $subnetid);
+
+ my $params = { subnet => $network,
+ mask => $mask,
+ sectionId => $section,
+ };
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("POST", "$url/subnets/", $headers, $params);
+ };
+ if ($@) {
+ die "error add subnet to ipam: $@";
+ }
+ }
+
+}
+
+sub del_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $section = $plugin_config->{section};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token];
+
+ my $internalid = get_internalid($url, $cidr, $headers);
+ return if !$internalid;
+
+ #fixme: check that prefix is empty exluding gateway, before delete
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/subnets/$internalid", $headers);
+ };
+ if ($@) {
+ die "error deleting subnet from ipam: $@";
+ }
+
+}
+
+sub add_ip {
+ my ($class, $plugin_config, $subnetid, $ip, $is_gateway) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $section = $plugin_config->{section};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token];
+
+ my $internalid = get_internalid($url, $cidr, $headers);
+
+ my $params = { ip => $ip,
+ subnetId => $internalid,
+ is_gateway => $is_gateway,
+ };
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("POST", "$url/addresses/", $headers, $params);
+ };
+
+ if ($@) {
+ die "error add subnet ip to ipam: ip $ip already exist: $@";
+ }
+}
+
+sub add_next_freeip {
+ my ($class, $plugin_config, $subnetid, $subnet, $internalid, $hostname) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $section = $plugin_config->{section};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token];
+
+ $internalid = get_internalid($url, $cidr, $headers) if !$internalid;
+
+ my $params = {};
+
+ my $ip = undef;
+ eval {
+ my $result = PVE::Network::SDN::Ipams::Plugin::api_request("POST", "$url/addresses/first_free/$internalid/", $headers, $params);
+ $ip = $result->{data};
+ };
+
+ if ($@) {
+ die "can't find free ip in subnet $cidr: $@";
+ }
+
+ my ($network, $mask) = split(/-/, $subnetid);
+ return "$ip/$mask";
+}
+
+sub del_ip {
+ my ($class, $plugin_config, $ip) = @_;
+
+ return if !$ip;
+
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token];
+
+ my $ip_id = get_ip_id($url, $ip, $headers);
+ return if !$ip_id;
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/addresses/$ip_id", $headers);
+ };
+ if ($@) {
+ die "error delete ip $ip";
+ }
+}
+
+
+#helpers
+
+sub get_internalid {
+ my ($url, $cidr, $headers) = @_;
+
+ my $result = PVE::Network::SDN::Ipams::Plugin::api_request("GET", "$url/subnets/cidr/$cidr", $headers);
+ my $data = @{$result->{data}}[0];
+ my $internalid = $data->{id};
+ return $internalid;
+}
+
+sub get_ip_id {
+ my ($url, $ip, $headers) = @_;
+ my $result = PVE::Network::SDN::Ipams::Plugin::api_request("GET", "$url/addresses/search/$ip", $headers);
+ my $data = @{$result->{data}}[0];
+ my $ip_id = $data->{id};
+ return $ip_id;
+}
+
+1;
+
+
diff --git a/PVE/Network/SDN/Ipams/Plugin.pm b/PVE/Network/SDN/Ipams/Plugin.pm
new file mode 100644
index 0000000..8a44090
--- /dev/null
+++ b/PVE/Network/SDN/Ipams/Plugin.pm
@@ -0,0 +1,127 @@
+package PVE::Network::SDN::Ipams::Plugin;
+
+use strict;
+use warnings;
+
+use PVE::Tools qw(run_command);
+use PVE::JSONSchema;
+use PVE::Cluster;
+use HTTP::Request;
+use LWP::UserAgent;
+use JSON;
+
+use Data::Dumper;
+use PVE::JSONSchema qw(get_standard_option);
+use base qw(PVE::SectionConfig);
+
+PVE::Cluster::cfs_register_file('sdn/ipams.cfg',
+ sub { __PACKAGE__->parse_config(@_); },
+ sub { __PACKAGE__->write_config(@_); });
+
+PVE::JSONSchema::register_standard_option('pve-sdn-ipam-id', {
+ description => "The SDN ipam object identifier.",
+ type => 'string', format => 'pve-sdn-ipam-id',
+});
+
+PVE::JSONSchema::register_format('pve-sdn-ipam-id', \&parse_sdn_ipam_id);
+sub parse_sdn_ipam_id {
+ my ($id, $noerr) = @_;
+
+ if ($id !~ m/^[a-z][a-z0-9]*[a-z0-9]$/i) {
+ return undef if $noerr;
+ die "ipam ID '$id' contains illegal characters\n";
+ }
+ return $id;
+}
+
+my $defaultData = {
+
+ propertyList => {
+ type => {
+ description => "Plugin type.",
+ type => 'string', format => 'pve-configid',
+ type => 'string',
+ },
+ ipam => get_standard_option('pve-sdn-ipam-id',
+ { completion => \&PVE::Network::SDN::Ipams::complete_sdn_ipam }),
+ },
+};
+
+sub private {
+ return $defaultData;
+}
+
+sub parse_section_header {
+ my ($class, $line) = @_;
+
+ if ($line =~ m/^(\S+):\s*(\S+)\s*$/) {
+ my ($type, $id) = (lc($1), $2);
+ my $errmsg = undef; # set if you want to skip whole section
+ eval { PVE::JSONSchema::pve_verify_configid($type); };
+ $errmsg = $@ if $@;
+ my $config = {}; # to return additional attributes
+ return ($type, $id, $errmsg, $config);
+ }
+ return undef;
+}
+
+
+sub add_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+}
+
+sub del_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+}
+
+sub add_ip {
+ my ($class, $plugin_config, $subnetid, $subnet, $internalid, $ip, $hostname, $is_gateway) = @_;
+
+}
+
+sub add_next_freeip {
+ my ($class, $plugin_config) = @_;
+}
+
+sub del_ip {
+ my ($class, $plugin_config, $ip) = @_;
+}
+
+
+#helpers
+sub api_request {
+ my ($method, $url, $headers, $data) = @_;
+
+ my $encoded_data = to_json($data) if $data;
+
+ my $req = HTTP::Request->new($method,$url, $headers, $encoded_data);
+
+ my $ua = LWP::UserAgent->new(protocols_allowed => ['http', 'https'], timeout => 30);
+ my $proxy = undef;
+
+ if ($proxy) {
+ $ua->proxy(['http', 'https'], $proxy);
+ } else {
+ $ua->env_proxy;
+ }
+
+ $ua->ssl_opts(verify_hostname => 0, SSL_verify_mode => 0x00);
+
+ my $response = $ua->request($req);
+ my $code = $response->code;
+
+ if ($code !~ /2(\d+)$/) {
+ my $msg = $response->message || 'unknown';
+ die "Invalid response from server: $code $msg\n";
+ }
+
+ my $raw = '';
+ if (defined($response->decoded_content)) {
+ $raw = $response->decoded_content;
+ } else {
+ $raw = $response->content;
+ }
+ return from_json($raw) if $raw ne '';
+}
+
+1;
diff --git a/PVE/Network/SDN/Makefile b/PVE/Network/SDN/Makefile
index 59f8c34..fb68856 100644
--- a/PVE/Network/SDN/Makefile
+++ b/PVE/Network/SDN/Makefile
@@ -1,4 +1,4 @@
-SOURCES=Vnets.pm VnetPlugin.pm Zones.pm Controllers.pm Subnets.pm SubnetPlugin.pm
+SOURCES=Vnets.pm VnetPlugin.pm Zones.pm Controllers.pm Subnets.pm SubnetPlugin.pm Ipams.pm
PERL5DIR=${DESTDIR}/usr/share/perl5
@@ -8,4 +8,5 @@ install:
for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/Network/SDN/$$i; done
make -C Controllers install
make -C Zones install
+ make -C Ipams install
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index ea47684..6224065 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -82,7 +82,7 @@ sub properties {
type => 'string',
description => "Develop some dns registrations plugins (powerdns,...)",
},
- ipam_driver => {
+ ipam => {
type => 'string',
description => "use a specific ipam",
},
@@ -98,7 +98,7 @@ sub options {
snat => { optional => 1 },
dhcp => { optional => 1 },
dns_driver => { optional => 1 },
- ipam_driver => { optional => 1 },
+ ipam => { optional => 1 },
};
}
@@ -110,6 +110,7 @@ sub on_update_hook {
my $gateway = $subnet_cfg->{ids}->{$subnetid}->{gateway};
raise_param_exc({ gateway => "$gateway is not in subnet $subnet"}) if $gateway && !$subnet_matcher->($gateway);
+
}
sub on_delete_hook {
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index 073ab80..d474037 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -4,6 +4,8 @@ use strict;
use warnings;
use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+use PVE::Network::SDN::Subnets;
+use PVE::Network::SDN::Ipams;
use PVE::Network::SDN::VnetPlugin;
PVE::Network::SDN::VnetPlugin->register();
@@ -52,4 +54,27 @@ sub get_vnet {
return $vnet;
}
+sub get_next_free_ip {
+ my ($vnetid) = @_;
+
+ my $vnets_cfg = PVE::Network::SDN::Vnets::config();
+ my $subnets_cfg = PVE::Network::SDN::Subnets::config();
+ my $vnet = $vnets_cfg->{ids}->{$vnetid};
+ my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
+ my $ip = undef;
+ foreach my $s (@subnets) {
+ my $subnetid = $s =~ s/\//-/r;
+ my $subnet = $subnets_cfg->{ids}->{$subnetid};
+ if ($subnet && $subnet->{ipam}) {
+ eval {
+ $ip = PVE::Network::SDN::Ipams::next_free_ip($subnetid, $subnet);
+ };
+ warn $@ if $@;
+ }
+ last if $ip;
+ }
+ die "can't find any ip" if !$ip;
+ return $ip;
+}
+
1;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 10/38] add pve internal ipam plugin
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (8 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 09/38] add ipams plugins Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 11/38] vnets: find_free_ip : add ipversion detection Alexandre Derumier
` (28 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN/Ipams.pm | 1 +
PVE/API2/Network/SDN/Subnets.pm | 4 +-
PVE/Network/SDN/Ipams.pm | 2 +
PVE/Network/SDN/Ipams/Makefile | 2 +-
PVE/Network/SDN/Ipams/NetboxPlugin.pm | 4 +-
PVE/Network/SDN/Ipams/PVEPlugin.pm | 166 +++++++++++++++++++++++++
PVE/Network/SDN/Ipams/PhpIpamPlugin.pm | 2 +-
PVE/Network/SDN/Ipams/Plugin.pm | 2 +-
debian/control | 1 +
9 files changed, 177 insertions(+), 7 deletions(-)
create mode 100644 PVE/Network/SDN/Ipams/PVEPlugin.pm
diff --git a/PVE/API2/Network/SDN/Ipams.pm b/PVE/API2/Network/SDN/Ipams.pm
index f8665a1..0d567c8 100644
--- a/PVE/API2/Network/SDN/Ipams.pm
+++ b/PVE/API2/Network/SDN/Ipams.pm
@@ -9,6 +9,7 @@ use PVE::Cluster qw(cfs_read_file cfs_write_file);
use PVE::Network::SDN;
use PVE::Network::SDN::Ipams;
use PVE::Network::SDN::Ipams::Plugin;
+use PVE::Network::SDN::Ipams::PVEPlugin;
use PVE::Network::SDN::Ipams::PhpIpamPlugin;
use PVE::Network::SDN::Ipams::NetboxPlugin;
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index b60db3d..094401c 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -193,10 +193,10 @@ __PACKAGE__->register_method ({
$plugin->add_subnet($plugin_config, $id, $cfg->{ids}->{$id});
if($opts->{gateway} && $scfg->{gateway} && $opts->{gateway} ne $scfg->{gateway}) {
- $plugin->del_ip($plugin_config, $scfg->{gateway});
+ $plugin->del_ip($plugin_config, $id, $scfg->{gateway});
}
if (!defined($opts->{gateway}) && $scfg->{gateway}) {
- $plugin->del_ip($plugin_config, $scfg->{gateway});
+ $plugin->del_ip($plugin_config, $id, $scfg->{gateway});
}
$plugin->add_ip($plugin_config, $id, $opts->{gateway}, 1) if $opts->{gateway};
}
diff --git a/PVE/Network/SDN/Ipams.pm b/PVE/Network/SDN/Ipams.pm
index 3d33632..b634020 100644
--- a/PVE/Network/SDN/Ipams.pm
+++ b/PVE/Network/SDN/Ipams.pm
@@ -10,10 +10,12 @@ use PVE::Tools qw(extract_param dir_glob_regex run_command);
use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
use PVE::Network;
+use PVE::Network::SDN::Ipams::PVEPlugin;
use PVE::Network::SDN::Ipams::NetboxPlugin;
use PVE::Network::SDN::Ipams::PhpIpamPlugin;
use PVE::Network::SDN::Ipams::Plugin;
+PVE::Network::SDN::Ipams::PVEPlugin->register();
PVE::Network::SDN::Ipams::NetboxPlugin->register();
PVE::Network::SDN::Ipams::PhpIpamPlugin->register();
PVE::Network::SDN::Ipams::Plugin->init();
diff --git a/PVE/Network/SDN/Ipams/Makefile b/PVE/Network/SDN/Ipams/Makefile
index 884c47a..4e7d65f 100644
--- a/PVE/Network/SDN/Ipams/Makefile
+++ b/PVE/Network/SDN/Ipams/Makefile
@@ -1,4 +1,4 @@
-SOURCES=Plugin.pm PhpIpamPlugin.pm NetboxPlugin.pm
+SOURCES=Plugin.pm PhpIpamPlugin.pm NetboxPlugin.pm PVEPlugin.pm
PERL5DIR=${DESTDIR}/usr/share/perl5
diff --git a/PVE/Network/SDN/Ipams/NetboxPlugin.pm b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
index ccc1184..c25f451 100644
--- a/PVE/Network/SDN/Ipams/NetboxPlugin.pm
+++ b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
@@ -68,7 +68,7 @@ sub del_subnet {
return if !$internalid;
#fixme: check that prefix is empty exluding gateway, before delete
- PVE::Network::SDN::Ipams::NetboxPlugin::del_ip($class, $plugin_config, $gateway) if $gateway;
+ PVE::Network::SDN::Ipams::NetboxPlugin::del_ip($class, $plugin_config, $subnetid, $gateway) if $gateway;
eval {
PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/ipam/prefixes/$internalid/", $headers);
@@ -125,7 +125,7 @@ sub add_next_freeip {
}
sub del_ip {
- my ($class, $plugin_config, $ip) = @_;
+ my ($class, $plugin_config, $subnetid, $ip) = @_;
return if !$ip;
diff --git a/PVE/Network/SDN/Ipams/PVEPlugin.pm b/PVE/Network/SDN/Ipams/PVEPlugin.pm
new file mode 100644
index 0000000..0dfc8a4
--- /dev/null
+++ b/PVE/Network/SDN/Ipams/PVEPlugin.pm
@@ -0,0 +1,166 @@
+package PVE::Network::SDN::Ipams::PVEPlugin;
+
+use strict;
+use warnings;
+use PVE::INotify;
+use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_register_file cfs_lock_file);
+use PVE::Tools;
+use JSON;
+use Net::IP;
+use Digest::SHA;
+
+use base('PVE::Network::SDN::Ipams::Plugin');
+
+
+my $ipamdb_file = "priv/ipam.db";
+
+PVE::Cluster::cfs_register_file($ipamdb_file,
+ sub { PVE::Network::SDN::Ipams::PVEPlugin->parse_config(@_); },
+ sub { PVE::Network::SDN::Ipams::PVEPlugin->write_config(@_); });
+
+sub type {
+ return 'pve';
+}
+
+sub properties {
+}
+
+sub options {
+}
+
+# Plugin implementation
+
+sub add_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ 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);
+ }
+ });
+ die "$@" if $@;
+}
+
+sub del_subnet {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+
+ cfs_lock_file($ipamdb_file, undef, sub {
+
+ my $db = read_db();
+ my $ips = $db->{subnets}->{$cidr}->{ips};
+ die "can't delete subnet, not empty" if keys %{$ips} > 0;
+ delete $db->{subnets}->{$cidr};
+ write_db($db);
+ });
+ die "$@" if $@;
+
+}
+
+sub add_ip {
+ my ($class, $plugin_config, $subnetid, $ip, $is_gateway) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+
+ cfs_lock_file($ipamdb_file, undef, sub {
+
+ my $db = read_db();
+ my $s = $db->{subnets}->{$cidr};
+
+ die "ip already exist" if defined($s->{ips}->{$ip});
+
+ #verify that ip is valid for this subnet
+ $s->{ips}->{$ip} = 1;
+ write_db($db);
+ });
+ die "$@" if $@;
+}
+
+sub add_next_freeip {
+ my ($class, $plugin_config, $subnetid, $subnet) = @_;
+
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $freeip = undef;
+
+ cfs_lock_file($ipamdb_file, undef, sub {
+
+ my $db = read_db();
+ my $s = $db->{subnets}->{$cidr};
+
+ my $iplist = new Net::IP($cidr);
+
+ while(1) {
+ my $ip = $iplist->ip();
+ ++$iplist;
+ print "nextip: $ip\n";
+ next if defined($s->{ips}->{$ip});
+ $freeip = $ip;
+ last;
+ }
+
+ die "can't find free ip in subnet $cidr" if !$freeip;
+
+ $s->{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 $cidr = $subnetid =~ s/-/\//r;
+
+ cfs_lock_file($ipamdb_file, undef, sub {
+
+ my $db = read_db();
+ my $s = $db->{subnets}->{$cidr};
+ return if !$ip;
+
+ die "ip does not exist in pam" if !defined($s->{ips}->{$ip});
+ delete $s->{ips}->{$ip};
+ write_db($db);
+ });
+ die "$@" if $@;
+}
+
+#helpers
+
+sub read_db {
+ my $db = cfs_read_file($ipamdb_file);
+ return $db;
+}
+
+sub write_db {
+ my ($cfg) = @_;
+
+ my $json = to_json($cfg);
+ cfs_write_file($ipamdb_file, $json);
+}
+
+sub write_config {
+ my ($class, $filename, $cfg) = @_;
+
+ return $cfg;
+}
+
+sub parse_config {
+ my ($class, $filename, $raw) = @_;
+
+ $raw = '{}' if !defined($raw) ||$raw eq '';
+ my $cfg = from_json($raw);
+
+ return $cfg;
+}
+
+1;
diff --git a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
index 7380bf3..d7ba3ed 100644
--- a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
+++ b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
@@ -145,7 +145,7 @@ sub add_next_freeip {
}
sub del_ip {
- my ($class, $plugin_config, $ip) = @_;
+ my ($class, $plugin_config, $subnetid, $ip) = @_;
return if !$ip;
diff --git a/PVE/Network/SDN/Ipams/Plugin.pm b/PVE/Network/SDN/Ipams/Plugin.pm
index 8a44090..fc736b8 100644
--- a/PVE/Network/SDN/Ipams/Plugin.pm
+++ b/PVE/Network/SDN/Ipams/Plugin.pm
@@ -84,7 +84,7 @@ sub add_next_freeip {
}
sub del_ip {
- my ($class, $plugin_config, $ip) = @_;
+ my ($class, $plugin_config, $subnetid, $ip) = @_;
}
diff --git a/debian/control b/debian/control
index 8b67d74..c54f8bc 100644
--- a/debian/control
+++ b/debian/control
@@ -17,6 +17,7 @@ Depends: libpve-common-perl (>= 5.0-45),
perl (>= 5.6.0-16),
pve-cluster (>= 5.0-32),
libnet-subnet-perl,
+ libnet-ip-perl,
${misc:Depends},
${perl:Depends},
Recommends: frr-pythontools, ifupdown2
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 11/38] vnets: find_free_ip : add ipversion detection
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (9 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 10/38] add pve internal ipam plugin Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 12/38] vnets: add add_ip Alexandre Derumier
` (27 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/Vnets.pm | 33 +++++++++++++++++++++------------
1 file changed, 21 insertions(+), 12 deletions(-)
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index d474037..0de3fd5 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -4,6 +4,7 @@ use strict;
use warnings;
use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+use Net::IP;
use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::Ipams;
@@ -55,26 +56,34 @@ sub get_vnet {
}
sub get_next_free_ip {
- my ($vnetid) = @_;
+ my ($vnetid, $ipversion) = @_;
+ $ipversion = 4 if !$ipversion;
my $vnets_cfg = PVE::Network::SDN::Vnets::config();
my $subnets_cfg = PVE::Network::SDN::Subnets::config();
my $vnet = $vnets_cfg->{ids}->{$vnetid};
my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
my $ip = undef;
+ my $subnet = undef;
+ my $subnetcount = 0;
foreach my $s (@subnets) {
- my $subnetid = $s =~ s/\//-/r;
- my $subnet = $subnets_cfg->{ids}->{$subnetid};
- if ($subnet && $subnet->{ipam}) {
- eval {
- $ip = PVE::Network::SDN::Ipams::next_free_ip($subnetid, $subnet);
- };
- warn $@ if $@;
- }
- last if $ip;
+ my $subnetid = $s =~ s/\//-/r;
+ my ($network, $mask) = split(/-/, $subnetid);
+ next if $ipversion != Net::IP::ip_get_version($network);
+ $subnetcount++;
+ $subnet = $subnets_cfg->{ids}->{$subnetid};
+ if ($subnet && $subnet->{ipam}) {
+ eval {
+ $ip = PVE::Network::SDN::Ipams::next_free_ip($subnetid, $subnet);
+ };
+ warn $@ if $@;
+ }
+ last if $ip;
}
- die "can't find any ip" if !$ip;
- return $ip;
+ die "can't find any free ip" if !$ip && $subnetcount > 0;
+
+ $subnet->{freeip} = $ip;
+ return $subnet;
}
1;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 12/38] vnets: add add_ip
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (10 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 11/38] vnets: find_free_ip : add ipversion detection Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 13/38] vnets: add del_ip + rework add_ip/find_free_ip Alexandre Derumier
` (26 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/Vnets.pm | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index 0de3fd5..07bc9ff 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -4,7 +4,9 @@ use strict;
use warnings;
use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+use PVE::Exception qw(raise_param_exc raise_perm_exc raise);
use Net::IP;
+use Net::Subnet qw(subnet_matcher);
use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::Ipams;
@@ -86,4 +88,35 @@ sub get_next_free_ip {
return $subnet;
}
+sub add_ip {
+ my ($vnetid, $cidr, $name) = @_;
+
+ my $vnets_cfg = PVE::Network::SDN::Vnets::config();
+ my $subnets_cfg = PVE::Network::SDN::Subnets::config();
+ my $vnet = $vnets_cfg->{ids}->{$vnetid};
+ my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
+ my $subnet = undef;
+ my $subnetid = undef;
+ my ($ip, $mask) = split(/\//, $cidr);
+
+ foreach my $s (@subnets) {
+ my $subnet_matcher = subnet_matcher($s);
+ next if !$subnet_matcher->($ip);
+ $subnetid = $s =~ s/\//-/r;
+ $subnet = $subnets_cfg->{ids}->{$subnetid};
+ last;
+ }
+ raise_param_exc({'ip' => "can't find any subnet attached to vnet $vnetid for ip $ip"}) if !$subnet;
+ return if !$subnet->{ipam};
+
+ eval {
+ my $ipamid = $subnet->{ipam};
+ 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->add_ip($plugin_config, $subnetid, $ip);
+ };
+ raise_param_exc({'ip' => $@}) if $@;
+}
+
1;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 13/38] vnets: add del_ip + rework add_ip/find_free_ip
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (11 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 12/38] vnets: add add_ip Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 14/38] add dns plugin Alexandre Derumier
` (25 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/Ipams.pm | 12 --------
PVE/Network/SDN/Subnets.pm | 60 ++++++++++++++++++++++++++++++++++++++
PVE/Network/SDN/Vnets.pm | 47 ++++++++++-------------------
3 files changed, 75 insertions(+), 44 deletions(-)
diff --git a/PVE/Network/SDN/Ipams.pm b/PVE/Network/SDN/Ipams.pm
index b634020..a979d46 100644
--- a/PVE/Network/SDN/Ipams.pm
+++ b/PVE/Network/SDN/Ipams.pm
@@ -64,17 +64,5 @@ sub complete_sdn_vnet {
return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::Vnets::sdn_ipams_ids($cfg) ];
}
-sub next_free_ip {
- my ($subnetid, $subnet) = @_;
-
- my $ipam_cfg = PVE::Network::SDN::Ipams::config();
- my $ipamid = $subnet->{ipam};
- return if !$ipamid;
-
- my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
- my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
- my $ip = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet);
- return $ip;
-}
1;
diff --git a/PVE/Network/SDN/Subnets.pm b/PVE/Network/SDN/Subnets.pm
index 454a9cf..3ce2d44 100644
--- a/PVE/Network/SDN/Subnets.pm
+++ b/PVE/Network/SDN/Subnets.pm
@@ -3,8 +3,10 @@ package PVE::Network::SDN::Subnets;
use strict;
use warnings;
+use Net::Subnet qw(subnet_matcher);
use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+use PVE::Network::SDN::Ipams;
use PVE::Network::SDN::SubnetPlugin;
PVE::Network::SDN::SubnetPlugin->register();
PVE::Network::SDN::SubnetPlugin->init();
@@ -52,4 +54,62 @@ sub get_subnet {
return $subnet;
}
+sub find_ip_subnet {
+ my ($ip, $subnetslist) = @_;
+
+ my $subnets_cfg = PVE::Network::SDN::Subnets::config();
+ my @subnets = PVE::Tools::split_list($subnetslist) if $subnetslist;
+
+ my $subnet = undef;
+ my $subnetid = undef;
+
+ foreach my $s (@subnets) {
+ my $subnet_matcher = subnet_matcher($s);
+ next if !$subnet_matcher->($ip);
+ $subnetid = $s =~ s/\//-/r;
+ $subnet = $subnets_cfg->{ids}->{$subnetid};
+ last;
+ }
+ die "can't find any subnet for ip $ip" if !$subnet;
+
+ return ($subnetid, $subnet);
+}
+
+sub next_free_ip {
+ my ($subnetid, $subnet) = @_;
+
+ my $ipamid = $subnet->{ipam};
+ return if !$ipamid;
+
+ 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});
+ my $ip = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet);
+ return $ip;
+}
+
+sub add_ip {
+ my ($subnetid, $subnet, $ip) = @_;
+
+ my $ipamid = $subnet->{ipam};
+ return if !$ipamid;
+
+ 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->add_ip($plugin_config, $subnetid, $ip);
+}
+
+sub del_ip {
+ my ($subnetid, $subnet, $ip) = @_;
+
+ my $ipamid = $subnet->{ipam};
+ return if !$ipamid;
+
+ 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);
+}
+
1;
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index 07bc9ff..6ea3a9a 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -4,11 +4,8 @@ use strict;
use warnings;
use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
-use PVE::Exception qw(raise_param_exc raise_perm_exc raise);
use Net::IP;
-use Net::Subnet qw(subnet_matcher);
use PVE::Network::SDN::Subnets;
-use PVE::Network::SDN::Ipams;
use PVE::Network::SDN::VnetPlugin;
PVE::Network::SDN::VnetPlugin->register();
@@ -58,12 +55,10 @@ sub get_vnet {
}
sub get_next_free_ip {
- my ($vnetid, $ipversion) = @_;
+ my ($vnet, $ipversion) = @_;
$ipversion = 4 if !$ipversion;
- my $vnets_cfg = PVE::Network::SDN::Vnets::config();
my $subnets_cfg = PVE::Network::SDN::Subnets::config();
- my $vnet = $vnets_cfg->{ids}->{$vnetid};
my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
my $ip = undef;
my $subnet = undef;
@@ -76,7 +71,7 @@ sub get_next_free_ip {
$subnet = $subnets_cfg->{ids}->{$subnetid};
if ($subnet && $subnet->{ipam}) {
eval {
- $ip = PVE::Network::SDN::Ipams::next_free_ip($subnetid, $subnet);
+ $ip = PVE::Network::SDN::Subnets::next_free_ip($subnetid, $subnet);
};
warn $@ if $@;
}
@@ -84,39 +79,27 @@ sub get_next_free_ip {
}
die "can't find any free ip" if !$ip && $subnetcount > 0;
- $subnet->{freeip} = $ip;
- return $subnet;
+ return $ip;
}
sub add_ip {
- my ($vnetid, $cidr, $name) = @_;
+ my ($vnet, $cidr, $name) = @_;
- my $vnets_cfg = PVE::Network::SDN::Vnets::config();
- my $subnets_cfg = PVE::Network::SDN::Subnets::config();
- my $vnet = $vnets_cfg->{ids}->{$vnetid};
- my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
- my $subnet = undef;
- my $subnetid = undef;
my ($ip, $mask) = split(/\//, $cidr);
+ my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $vnet->{subnets});
+ return if !$subnet->{ipam};
- foreach my $s (@subnets) {
- my $subnet_matcher = subnet_matcher($s);
- next if !$subnet_matcher->($ip);
- $subnetid = $s =~ s/\//-/r;
- $subnet = $subnets_cfg->{ids}->{$subnetid};
- last;
- }
- raise_param_exc({'ip' => "can't find any subnet attached to vnet $vnetid for ip $ip"}) if !$subnet;
+ PVE::Network::SDN::Subnets::add_ip($subnetid, $subnet, $ip);
+}
+
+sub del_ip {
+ my ($vnet, $cidr) = @_;
+
+ my ($ip, $mask) = split(/\//, $cidr);
+ my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $vnet->{subnets});
return if !$subnet->{ipam};
- eval {
- my $ipamid = $subnet->{ipam};
- 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->add_ip($plugin_config, $subnetid, $ip);
- };
- raise_param_exc({'ip' => $@}) if $@;
+ PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip);
}
1;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 14/38] add dns plugin
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (12 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 13/38] vnets: add del_ip + rework add_ip/find_free_ip Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 15/38] Fix vnet gateway for routed setup + /32 pointopoint subnet Alexandre Derumier
` (24 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN.pm | 7 +
PVE/API2/Network/SDN/Dns.pm | 242 ++++++++++++++++++++++++++
PVE/API2/Network/SDN/Makefile | 2 +-
PVE/Network/SDN/Dns.pm | 57 ++++++
PVE/Network/SDN/Dns/Makefile | 8 +
PVE/Network/SDN/Dns/Plugin.pm | 117 +++++++++++++
PVE/Network/SDN/Dns/PowerdnsPlugin.pm | 201 +++++++++++++++++++++
PVE/Network/SDN/Ipams/PVEPlugin.pm | 1 -
PVE/Network/SDN/Ipams/Plugin.pm | 2 +-
PVE/Network/SDN/Makefile | 3 +-
PVE/Network/SDN/SubnetPlugin.pm | 53 ++++--
PVE/Network/SDN/Subnets.pm | 156 +++++++++++++++--
PVE/Network/SDN/Vnets.pm | 12 +-
13 files changed, 814 insertions(+), 47 deletions(-)
create mode 100644 PVE/API2/Network/SDN/Dns.pm
create mode 100644 PVE/Network/SDN/Dns.pm
create mode 100644 PVE/Network/SDN/Dns/Makefile
create mode 100644 PVE/Network/SDN/Dns/Plugin.pm
create mode 100644 PVE/Network/SDN/Dns/PowerdnsPlugin.pm
diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm
index 6055fe5..0a5fa33 100644
--- a/PVE/API2/Network/SDN.pm
+++ b/PVE/API2/Network/SDN.pm
@@ -17,6 +17,7 @@ use PVE::API2::Network::SDN::Vnets;
use PVE::API2::Network::SDN::Zones;
use PVE::API2::Network::SDN::Subnets;
use PVE::API2::Network::SDN::Ipams;
+use PVE::API2::Network::SDN::Dns;
use base qw(PVE::RESTHandler);
@@ -45,6 +46,11 @@ __PACKAGE__->register_method ({
path => 'ipams',
});
+__PACKAGE__->register_method ({
+ subclass => "PVE::API2::Network::SDN::Dns",
+ path => 'dns',
+});
+
__PACKAGE__->register_method({
name => 'index',
path => '',
@@ -76,6 +82,7 @@ __PACKAGE__->register_method({
{ id => 'controllers' },
{ id => 'subnets' },
{ id => 'ipams' },
+ { id => 'dns' },
];
return $res;
diff --git a/PVE/API2/Network/SDN/Dns.pm b/PVE/API2/Network/SDN/Dns.pm
new file mode 100644
index 0000000..ea26af3
--- /dev/null
+++ b/PVE/API2/Network/SDN/Dns.pm
@@ -0,0 +1,242 @@
+package PVE::API2::Network::SDN::Dns;
+
+use strict;
+use warnings;
+
+use PVE::SafeSyslog;
+use PVE::Tools qw(extract_param);
+use PVE::Cluster qw(cfs_read_file cfs_write_file);
+use PVE::Network::SDN;
+use PVE::Network::SDN::Dns;
+use PVE::Network::SDN::Dns::Plugin;
+use PVE::Network::SDN::Dns::PowerdnsPlugin;
+
+use Storable qw(dclone);
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::RPCEnvironment;
+
+use PVE::RESTHandler;
+
+use base qw(PVE::RESTHandler);
+
+my $sdn_dns_type_enum = PVE::Network::SDN::Dns::Plugin->lookup_types();
+
+my $api_sdn_dns_config = sub {
+ my ($cfg, $id) = @_;
+
+ my $scfg = dclone(PVE::Network::SDN::Dns::sdn_dns_config($cfg, $id));
+ $scfg->{dns} = $id;
+ $scfg->{digest} = $cfg->{digest};
+
+ return $scfg;
+};
+
+__PACKAGE__->register_method ({
+ name => 'index',
+ path => '',
+ method => 'GET',
+ description => "SDN dns index.",
+ permissions => {
+ description => "Only list entries where you have 'SDN.Audit' or 'SDN.Allocate' permissions on '/sdn/dns/<dns>'",
+ user => 'all',
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ type => {
+ description => "Only list sdn dns of specific type",
+ type => 'string',
+ enum => $sdn_dns_type_enum,
+ optional => 1,
+ },
+ },
+ },
+ returns => {
+ type => 'array',
+ items => {
+ type => "object",
+ properties => { dns => { type => 'string'},
+ type => { type => 'string'},
+ },
+ },
+ links => [ { rel => 'child', href => "{dns}" } ],
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $rpcenv = PVE::RPCEnvironment::get();
+ my $authuser = $rpcenv->get_user();
+
+
+ my $cfg = PVE::Network::SDN::Dns::config();
+
+ my @sids = PVE::Network::SDN::Dns::sdn_dns_ids($cfg);
+ my $res = [];
+ foreach my $id (@sids) {
+ my $privs = [ 'SDN.Audit', 'SDN.Allocate' ];
+ next if !$rpcenv->check_any($authuser, "/sdn/dns/$id", $privs, 1);
+
+ my $scfg = &$api_sdn_dns_config($cfg, $id);
+ next if $param->{type} && $param->{type} ne $scfg->{type};
+
+ my $plugin_config = $cfg->{ids}->{$id};
+ my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($plugin_config->{type});
+ push @$res, $scfg;
+ }
+
+ return $res;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'read',
+ path => '{dns}',
+ method => 'GET',
+ description => "Read sdn dns configuration.",
+ permissions => {
+ check => ['perm', '/sdn/dns/{dns}', ['SDN.Allocate']],
+ },
+
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ dns => get_standard_option('pve-sdn-dns-id'),
+ },
+ },
+ returns => { type => 'object' },
+ code => sub {
+ my ($param) = @_;
+
+ my $cfg = PVE::Network::SDN::Dns::config();
+
+ return &$api_sdn_dns_config($cfg, $param->{dns});
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'create',
+ protected => 1,
+ path => '',
+ method => 'POST',
+ description => "Create a new sdn dns object.",
+ permissions => {
+ check => ['perm', '/sdn/dns', ['SDN.Allocate']],
+ },
+ parameters => PVE::Network::SDN::Dns::Plugin->createSchema(),
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $type = extract_param($param, 'type');
+ my $id = extract_param($param, 'dns');
+
+ my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($type);
+ my $opts = $plugin->check_config($id, $param, 1, 1);
+
+ # create /etc/pve/sdn directory
+ PVE::Cluster::check_cfs_quorum();
+ mkdir("/etc/pve/sdn");
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+
+ my $dns_cfg = PVE::Network::SDN::Dns::config();
+
+ my $scfg = undef;
+ if ($scfg = PVE::Network::SDN::Dns::sdn_dns_config($dns_cfg, $id, 1)) {
+ die "sdn dns object ID '$id' already defined\n";
+ }
+
+ $dns_cfg->{ids}->{$id} = $opts;
+
+ my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($scfg->{type});
+ $plugin->on_update_hook($opts);
+
+ PVE::Network::SDN::Dns::write_config($dns_cfg);
+
+ }, "create sdn dns object failed");
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'update',
+ protected => 1,
+ path => '{dns}',
+ method => 'PUT',
+ description => "Update sdn dns object configuration.",
+ permissions => {
+ check => ['perm', '/sdn/dns', ['SDN.Allocate']],
+ },
+ parameters => PVE::Network::SDN::Dns::Plugin->updateSchema(),
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $id = extract_param($param, 'dns');
+ my $digest = extract_param($param, 'digest');
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+
+ my $dns_cfg = PVE::Network::SDN::Dns::config();
+
+ PVE::SectionConfig::assert_if_modified($dns_cfg, $digest);
+
+ my $scfg = PVE::Network::SDN::Dns::sdn_dns_config($dns_cfg, $id);
+
+ my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($scfg->{type});
+ my $opts = $plugin->check_config($id, $param, 0, 1);
+
+ foreach my $k (%$opts) {
+ $scfg->{$k} = $opts->{$k};
+ }
+
+ $plugin->on_update_hook($scfg);
+
+ PVE::Network::SDN::Dns::write_config($dns_cfg);
+
+ }, "update sdn dns object failed");
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'delete',
+ protected => 1,
+ path => '{dns}',
+ method => 'DELETE',
+ description => "Delete sdn dns object configuration.",
+ permissions => {
+ check => ['perm', '/sdn/dns', ['SDN.Allocate']],
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ dns => get_standard_option('pve-sdn-dns-id', {
+ completion => \&PVE::Network::SDN::Dns::complete_sdn_dns,
+ }),
+ },
+ },
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $id = extract_param($param, 'dns');
+
+ PVE::Network::SDN::lock_sdn_config(
+ sub {
+
+ my $cfg = PVE::Network::SDN::Dns::config();
+
+ my $scfg = PVE::Network::SDN::Dns::sdn_dns_config($cfg, $id);
+
+ my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($scfg->{type});
+
+ delete $cfg->{ids}->{$id};
+ PVE::Network::SDN::Dns::write_config($cfg);
+
+ }, "delete sdn dns object failed");
+
+ return undef;
+ }});
+
+1;
diff --git a/PVE/API2/Network/SDN/Makefile b/PVE/API2/Network/SDN/Makefile
index 1117dfa..3683fa4 100644
--- a/PVE/API2/Network/SDN/Makefile
+++ b/PVE/API2/Network/SDN/Makefile
@@ -1,4 +1,4 @@
-SOURCES=Vnets.pm Zones.pm Controllers.pm Subnets.pm Ipams.pm
+SOURCES=Vnets.pm Zones.pm Controllers.pm Subnets.pm Ipams.pm Dns.pm
PERL5DIR=${DESTDIR}/usr/share/perl5
diff --git a/PVE/Network/SDN/Dns.pm b/PVE/Network/SDN/Dns.pm
new file mode 100644
index 0000000..c2e153a
--- /dev/null
+++ b/PVE/Network/SDN/Dns.pm
@@ -0,0 +1,57 @@
+package PVE::Network::SDN::Dns;
+
+use strict;
+use warnings;
+
+use Data::Dumper;
+use JSON;
+
+use PVE::Tools qw(extract_param dir_glob_regex run_command);
+use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+use PVE::Network;
+
+use PVE::Network::SDN::Dns::PowerdnsPlugin;
+use PVE::Network::SDN::Dns::Plugin;
+
+PVE::Network::SDN::Dns::PowerdnsPlugin->register();
+PVE::Network::SDN::Dns::Plugin->init();
+
+
+sub sdn_dns_config {
+ my ($cfg, $id, $noerr) = @_;
+
+ die "no sdn dns ID specified\n" if !$id;
+
+ my $scfg = $cfg->{ids}->{$id};
+ die "sdn '$id' does not exist\n" if (!$noerr && !$scfg);
+
+ return $scfg;
+}
+
+sub config {
+ my $config = cfs_read_file("sdn/dns.cfg");
+ return $config;
+}
+
+sub write_config {
+ my ($cfg) = @_;
+
+ cfs_write_file("sdn/dns.cfg", $cfg);
+}
+
+sub sdn_dns_ids {
+ my ($cfg) = @_;
+
+ return keys %{$cfg->{ids}};
+}
+
+sub complete_sdn_dns {
+ my ($cmdname, $pname, $cvalue) = @_;
+
+ my $cfg = PVE::Network::SDN::Dns::config();
+
+ return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::Dns::sdn_dns_ids($cfg) ];
+}
+
+1;
+
diff --git a/PVE/Network/SDN/Dns/Makefile b/PVE/Network/SDN/Dns/Makefile
new file mode 100644
index 0000000..81cd2a1
--- /dev/null
+++ b/PVE/Network/SDN/Dns/Makefile
@@ -0,0 +1,8 @@
+SOURCES=Plugin.pm PowerdnsPlugin.pm
+
+
+PERL5DIR=${DESTDIR}/usr/share/perl5
+
+.PHONY: install
+install:
+ for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/Network/SDN/Dns/$$i; done
diff --git a/PVE/Network/SDN/Dns/Plugin.pm b/PVE/Network/SDN/Dns/Plugin.pm
new file mode 100644
index 0000000..baa9316
--- /dev/null
+++ b/PVE/Network/SDN/Dns/Plugin.pm
@@ -0,0 +1,117 @@
+package PVE::Network::SDN::Dns::Plugin;
+
+use strict;
+use warnings;
+
+use PVE::Tools qw(run_command);
+use PVE::JSONSchema;
+use PVE::Cluster;
+use HTTP::Request;
+use LWP::UserAgent;
+use JSON;
+
+use Data::Dumper;
+use PVE::JSONSchema qw(get_standard_option);
+use base qw(PVE::SectionConfig);
+
+PVE::Cluster::cfs_register_file('sdn/dns.cfg',
+ sub { __PACKAGE__->parse_config(@_); },
+ sub { __PACKAGE__->write_config(@_); });
+
+PVE::JSONSchema::register_standard_option('pve-sdn-dns-id', {
+ description => "The SDN dns object identifier.",
+ type => 'string', format => 'pve-sdn-dns-id',
+});
+
+PVE::JSONSchema::register_format('pve-sdn-dns-id', \&parse_sdn_dns_id);
+sub parse_sdn_dns_id {
+ my ($id, $noerr) = @_;
+
+ if ($id !~ m/^[a-z][a-z0-9]*[a-z0-9]$/i) {
+ return undef if $noerr;
+ die "dns ID '$id' contains illegal characters\n";
+ }
+ return $id;
+}
+
+my $defaultData = {
+
+ propertyList => {
+ type => {
+ description => "Plugin type.",
+ type => 'string', format => 'pve-configid',
+ },
+ ttl => { type => 'integer', optional => 1 },
+ dns => get_standard_option('pve-sdn-dns-id',
+ { completion => \&PVE::Network::SDN::Dns::complete_sdn_dns }),
+ },
+};
+
+sub private {
+ return $defaultData;
+}
+
+sub parse_section_header {
+ my ($class, $line) = @_;
+
+ if ($line =~ m/^(\S+):\s*(\S+)\s*$/) {
+ my ($type, $id) = (lc($1), $2);
+ my $errmsg = undef; # set if you want to skip whole section
+ eval { PVE::JSONSchema::pve_verify_configid($type); };
+ $errmsg = $@ if $@;
+ my $config = {}; # to return additional attributes
+ return ($type, $id, $errmsg, $config);
+ }
+ return undef;
+}
+
+
+sub add_a_record {
+ my ($class, $plugin_config, $type, $zone, $reversezone, $hostname, $ip) = @_;
+}
+
+sub del_a_record {
+ my ($class, $plugin_config, $hostname, $ip) = @_;
+}
+
+sub on_update_hook {
+ my ($class, $plugin_config) = @_;
+}
+
+#helpers
+sub api_request {
+ my ($method, $url, $headers, $data) = @_;
+
+ my $encoded_data = to_json($data) if $data;
+
+ my $req = HTTP::Request->new($method,$url, $headers, $encoded_data);
+
+ my $ua = LWP::UserAgent->new(protocols_allowed => ['http', 'https'], timeout => 30);
+ my $proxy = undef;
+
+ if ($proxy) {
+ $ua->proxy(['http', 'https'], $proxy);
+ } else {
+ $ua->env_proxy;
+ }
+
+ $ua->ssl_opts(verify_hostname => 0, SSL_verify_mode => 0x00);
+
+ my $response = $ua->request($req);
+ my $code = $response->code;
+
+ if ($code !~ /^2(\d+)$/) {
+ my $msg = $response->message || 'unknown';
+ die "Invalid response from server: $code $msg\n";
+ }
+
+ my $raw = '';
+ if (defined($response->decoded_content)) {
+ $raw = $response->decoded_content;
+ } else {
+ $raw = $response->content;
+ }
+ return from_json($raw) if $raw ne '';
+}
+
+1;
diff --git a/PVE/Network/SDN/Dns/PowerdnsPlugin.pm b/PVE/Network/SDN/Dns/PowerdnsPlugin.pm
new file mode 100644
index 0000000..8c5dd90
--- /dev/null
+++ b/PVE/Network/SDN/Dns/PowerdnsPlugin.pm
@@ -0,0 +1,201 @@
+package PVE::Network::SDN::Dns::PowerdnsPlugin;
+
+use strict;
+use warnings;
+use PVE::INotify;
+use PVE::Cluster;
+use PVE::Tools;
+use JSON;
+use Net::IP;
+
+use base('PVE::Network::SDN::Dns::Plugin');
+
+sub type {
+ return 'powerdns';
+}
+
+sub properties {
+ return {
+ url => {
+ type => 'string',
+ },
+ key => {
+ type => 'string',
+ },
+ };
+}
+
+sub options {
+
+ return {
+ url => { optional => 0},
+ key => { optional => 0 },
+ ttl => { optional => 1 },
+ };
+}
+
+# Plugin implementation
+
+sub add_a_record {
+ my ($class, $plugin_config, $zone, $hostname, $ip) = @_;
+
+ my $url = $plugin_config->{url};
+ my $key = $plugin_config->{key};
+ my $ttl = $plugin_config->{ttl} ? $plugin_config->{ttl} : 14400;
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
+
+ my $type = Net::IP::ip_is_ipv6($ip) ? "AAAA" : "A";
+ my $fqdn = $hostname.".".$zone.".";
+
+
+ my $record = { content => $ip,
+ disabled => JSON::false,
+ name => $fqdn,
+ type => $type,
+ priority => 0 };
+
+ my $rrset = { name => $fqdn,
+ type => $type,
+ ttl => $ttl,
+ changetype => "REPLACE",
+ records => [ $record ] };
+
+
+ my $params = { rrsets => [ $rrset ] };
+
+ eval {
+ PVE::Network::SDN::Dns::Plugin::api_request("PATCH", "$url/zones/$zone", $headers, $params);
+ };
+
+ if ($@) {
+ die "error add $fqdn to zone $zone: $@";
+ }
+}
+
+sub add_ptr_record {
+ my ($class, $plugin_config, $zone, $hostname, $ip) = @_;
+
+ my $url = $plugin_config->{url};
+ my $key = $plugin_config->{key};
+ my $ttl = $plugin_config->{ttl} ? $plugin_config->{ttl} : 14400;
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
+
+ my $reverseip = join(".", reverse(split(/\./, $ip)))."in-addr.arpa.";
+ my $fqdn = $hostname.".".$zone.".";
+ my $type = "PTR";
+
+ my $record = { content => $fqdn,
+ disabled => JSON::false,
+ name => $reverseip,
+ type => $type,
+ priority => 0 };
+
+ my $rrset = { name => $reverseip,
+ type => $type,
+ ttl => $ttl,
+ changetype => "REPLACE",
+ records => [ $record ] };
+
+
+ my $params = { rrsets => [ $rrset ] };
+
+ eval {
+ PVE::Network::SDN::Dns::Plugin::api_request("PATCH", "$url/zones/$zone", $headers, $params);
+ };
+
+ if ($@) {
+ die "error add $reverseip to zone $zone: $@";
+ }
+}
+
+sub del_a_record {
+ my ($class, $plugin_config, $zone, $hostname) = @_;
+
+ my $url = $plugin_config->{url};
+ my $key = $plugin_config->{key};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
+ my $fqdn = $hostname.".".$zone.".";
+ my $type = "PTR";
+
+ my $rrset = { name => $fqdn,
+ type => $type,
+ changetype => "DELETE",
+ records => [] };
+
+ my $params = { rrsets => [ $rrset ] };
+
+ eval {
+ PVE::Network::SDN::Dns::Plugin::api_request("PATCH", "$url/zones/$zone", $headers, $params);
+ };
+
+ if ($@) {
+ die "error delete $fqdn from zone $zone: $@";
+ }
+}
+
+sub del_ptr_record {
+ my ($class, $plugin_config, $zone, $ip) = @_;
+
+ my $url = $plugin_config->{url};
+ my $key = $plugin_config->{key};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
+
+ my $reverseip = join(".", reverse(split(/\./, $ip)))."in-addr.arpa.";
+ my $type = "PTR";
+
+ my $rrset = { name => $reverseip,
+ type => $type,
+ changetype => "DELETE",
+ records => [] };
+
+ my $params = { rrsets => [ $rrset ] };
+
+ eval {
+ PVE::Network::SDN::Dns::Plugin::api_request("PATCH", "$url/zones/$zone", $headers, $params);
+ };
+
+ if ($@) {
+ die "error delete $reverseip from zone $zone: $@";
+ }
+}
+
+sub verify_zone {
+ my ($class, $plugin_config, $zone) = @_;
+
+ #verify that api is working
+
+ my $url = $plugin_config->{url};
+ my $key = $plugin_config->{key};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
+
+ eval {
+ PVE::Network::SDN::Dns::Plugin::api_request("GET", "$url/zones/$zone", $headers);
+ };
+
+ if ($@) {
+ die "can't read zone $zone: $@";
+ }
+}
+
+
+sub on_update_hook {
+ my ($class, $plugin_config) = @_;
+
+ #verify that api is working
+
+ my $url = $plugin_config->{url};
+ my $key = $plugin_config->{key};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
+
+ eval {
+ PVE::Network::SDN::Dns::Plugin::api_request("GET", "$url", $headers);
+ };
+
+ if ($@) {
+ die "dns api error: $@";
+ }
+}
+
+1;
+
+
diff --git a/PVE/Network/SDN/Ipams/PVEPlugin.pm b/PVE/Network/SDN/Ipams/PVEPlugin.pm
index 0dfc8a4..99af0ed 100644
--- a/PVE/Network/SDN/Ipams/PVEPlugin.pm
+++ b/PVE/Network/SDN/Ipams/PVEPlugin.pm
@@ -99,7 +99,6 @@ sub add_next_freeip {
while(1) {
my $ip = $iplist->ip();
++$iplist;
- print "nextip: $ip\n";
next if defined($s->{ips}->{$ip});
$freeip = $ip;
last;
diff --git a/PVE/Network/SDN/Ipams/Plugin.pm b/PVE/Network/SDN/Ipams/Plugin.pm
index fc736b8..683346c 100644
--- a/PVE/Network/SDN/Ipams/Plugin.pm
+++ b/PVE/Network/SDN/Ipams/Plugin.pm
@@ -110,7 +110,7 @@ sub api_request {
my $response = $ua->request($req);
my $code = $response->code;
- if ($code !~ /2(\d+)$/) {
+ if ($code !~ /^2(\d+)$/) {
my $msg = $response->message || 'unknown';
die "Invalid response from server: $code $msg\n";
}
diff --git a/PVE/Network/SDN/Makefile b/PVE/Network/SDN/Makefile
index fb68856..92cfcd0 100644
--- a/PVE/Network/SDN/Makefile
+++ b/PVE/Network/SDN/Makefile
@@ -1,4 +1,4 @@
-SOURCES=Vnets.pm VnetPlugin.pm Zones.pm Controllers.pm Subnets.pm SubnetPlugin.pm Ipams.pm
+SOURCES=Vnets.pm VnetPlugin.pm Zones.pm Controllers.pm Subnets.pm SubnetPlugin.pm Ipams.pm Dns.pm
PERL5DIR=${DESTDIR}/usr/share/perl5
@@ -9,4 +9,5 @@ install:
make -C Controllers install
make -C Zones install
make -C Ipams install
+ make -C Dns install
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index 6224065..3769e04 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -65,22 +65,25 @@ sub properties {
type => 'string',
description => "static routes [network=<network>:gateway=<ip>,network=<network>:gateway=<ip>,... ]",
},
- #cloudinit, dhcp options
- nameservers => {
- type => 'string', format => 'address-list',
- description => " dns nameserver",
+ dns => {
+ type => 'string',
+ description => "dns api server",
},
- #cloudinit, dhcp options
- searchdomain => {
+ reversedns => {
type => 'string',
+ description => "reverse dns api server",
},
- dhcp => {
- type => 'boolean',
- description => "enable dhcp for this subnet",
+ dnszone => {
+ type => 'string',
+ description => "dns domain zone ex: mydomain.com",
},
- dns_driver => {
+ reversednszone => {
type => 'string',
- description => "Develop some dns registrations plugins (powerdns,...)",
+ description => "reverse dns zone ex: 0.168.192.in-addr.arpa",
+ },
+ dnszoneprefix => {
+ type => 'string',
+ description => "dns domain zone prefix ex: 'adm' -> <hostname>.adm.mydomain.com",
},
ipam => {
type => 'string',
@@ -93,11 +96,12 @@ sub options {
return {
gateway => { optional => 1 },
routes => { optional => 1 },
- nameservers => { optional => 1 },
- searchdomain => { optional => 1 },
snat => { optional => 1 },
- dhcp => { optional => 1 },
- dns_driver => { optional => 1 },
+ dns => { optional => 1 },
+ reversedns => { optional => 1 },
+ dnszone => { optional => 1 },
+ reversednszone => { optional => 1 },
+ dnszoneprefix => { optional => 1 },
ipam => { optional => 1 },
};
}
@@ -105,12 +109,25 @@ sub options {
sub on_update_hook {
my ($class, $subnetid, $subnet_cfg) = @_;
- my $subnet = $subnetid =~ s/-/\//r;
- my $subnet_matcher = subnet_matcher($subnet);
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $subnet_matcher = subnet_matcher($cidr);
+
+ my $subnet = $subnet_cfg->{ids}->{$subnetid};
- my $gateway = $subnet_cfg->{ids}->{$subnetid}->{gateway};
+ my $gateway = $subnet->{gateway};
+ my $dns = $subnet->{dns};
+ my $dnszone = $subnet->{dnszone};
+ my $reversedns = $subnet->{reversedns};
+ my $reversednszone = $subnet->{reversednszone};
+
+ #to: for /32 pointotoping, allow gateway outside the subnet
raise_param_exc({ gateway => "$gateway is not in subnet $subnet"}) if $gateway && !$subnet_matcher->($gateway);
+ raise_param_exc({ dns => "missing dns provider"}) if $dnszone && !$dns;
+ raise_param_exc({ dnszone => "missing dns zone"}) if $dns && !$dnszone;
+ raise_param_exc({ reversedns => "missing dns provider"}) if $reversednszone && !$reversedns;
+ raise_param_exc({ reversednszone => "missing dns zone"}) if $reversedns && !$reversednszone;
+
}
sub on_delete_hook {
diff --git a/PVE/Network/SDN/Subnets.pm b/PVE/Network/SDN/Subnets.pm
index 3ce2d44..4e8353e 100644
--- a/PVE/Network/SDN/Subnets.pm
+++ b/PVE/Network/SDN/Subnets.pm
@@ -5,8 +5,10 @@ use warnings;
use Net::Subnet qw(subnet_matcher);
use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+use Net::IP;
use PVE::Network::SDN::Ipams;
+use PVE::Network::SDN::Dns;
use PVE::Network::SDN::SubnetPlugin;
PVE::Network::SDN::SubnetPlugin->register();
PVE::Network::SDN::SubnetPlugin->init();
@@ -75,41 +77,157 @@ sub find_ip_subnet {
return ($subnetid, $subnet);
}
+my $verify_dns_zone = sub {
+ my ($zone, $dns) = @_;
+
+ return if !$zone || !$dns;
+
+ 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->verify_zone($plugin_config, $zone);
+};
+
+my $add_dns_record = sub {
+ my ($zone, $dns, $hostname, $dnszoneprefix, $ip, $reverse) = @_;
+
+ return if !$zone || !$dns || !$hostname || !$ip;
+
+ $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
+
+ 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});
+ if($reverse) {
+ $plugin->add_ptr_record($plugin_config, $zone, $hostname, $ip);
+ } else {
+ $plugin->add_a_record($plugin_config, $zone, $hostname, $ip);
+ }
+};
+
+my $del_dns_record = sub {
+ my ($zone, $dns, $hostname, $dnszoneprefix, $ip, $reverse) = @_;
+
+ return if !$zone || !$dns || !$hostname || !$ip;
+
+ $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
+
+ 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});
+ if($reverse) {
+ $plugin->del_ptr_record($plugin_config, $zone, $ip);
+ } else {
+ $plugin->del_a_record($plugin_config, $zone, $hostname);
+ }
+};
+
sub next_free_ip {
- my ($subnetid, $subnet) = @_;
+ my ($subnetid, $subnet, $hostname) = @_;
+
+ my $cidr = undef;
+ my $ip = undef;
my $ipamid = $subnet->{ipam};
- return if !$ipamid;
+ my $dns = $subnet->{dns};
+ my $dnszone = $subnet->{dnszone};
+ my $reversedns = $subnet->{reversedns};
+ my $reversednszone = $subnet->{reversednszone};
+ my $dnszoneprefix = $subnet->{dnszoneprefix};
+
+ #verify dns zones before ipam
+ &$verify_dns_zone($dnszone, $dns);
+ &$verify_dns_zone($reversednszone, $reversedns);
+
+ if($ipamid) {
+ 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});
+ $cidr = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet);
+ ($ip, undef) = split(/\//, $cidr);
+ }
- 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});
- my $ip = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet);
- return $ip;
+ eval {
+ #add dns
+ &$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
+ #add reverse dns
+ &$add_dns_record($reversednszone, $reversedns, $hostname, $dnszoneprefix, $ip, 1);
+ };
+ if ($@) {
+ #rollback
+ my $err = $@;
+ eval {
+ PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip, $hostname)
+ };
+ die $err;
+ }
+ return $cidr;
}
sub add_ip {
- my ($subnetid, $subnet, $ip) = @_;
+ my ($subnetid, $subnet, $ip, $hostname) = @_;
my $ipamid = $subnet->{ipam};
- return if !$ipamid;
+ my $dns = $subnet->{dns};
+ my $dnszone = $subnet->{dnszone};
+ my $reversedns = $subnet->{reversedns};
+ my $reversednszone = $subnet->{reversednszone};
+ my $dnszoneprefix = $subnet->{dnszoneprefix};
+
+ #verify dns zones before ipam
+ &$verify_dns_zone($dnszone, $dns);
+ &$verify_dns_zone($reversednszone, $reversedns);
+
+ if ($ipamid) {
+ 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->add_ip($plugin_config, $subnetid, $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->add_ip($plugin_config, $subnetid, $ip);
+ eval {
+ #add dns
+ &$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
+ #add reverse dns
+ &$add_dns_record($reversednszone, $reversedns, $hostname, $dnszoneprefix, $ip, 1);
+ };
+ if ($@) {
+ #rollback
+ my $err = $@;
+ eval {
+ PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip, $hostname)
+ };
+ die $err;
+ }
}
sub del_ip {
- my ($subnetid, $subnet, $ip) = @_;
+ my ($subnetid, $subnet, $ip, $hostname) = @_;
my $ipamid = $subnet->{ipam};
- return if !$ipamid;
+ my $dns = $subnet->{dns};
+ my $dnszone = $subnet->{dnszone};
+ my $reversedns = $subnet->{reversedns};
+ my $reversednszone = $subnet->{reversednszone};
+ my $dnszoneprefix = $subnet->{dnszoneprefix};
+
+ &$verify_dns_zone($dnszone, $dns);
+ &$verify_dns_zone($reversednszone, $reversedns);
+
+ if ($ipamid) {
+ 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);
+ }
- 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);
+ eval {
+ &$del_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
+ &$del_dns_record($reversednszone, $reversedns, $hostname, $dnszoneprefix, $ip, 1);
+ };
+ if ($@) {
+ warn $@;
+ }
}
1;
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index 6ea3a9a..c9916b1 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -55,7 +55,7 @@ sub get_vnet {
}
sub get_next_free_ip {
- my ($vnet, $ipversion) = @_;
+ my ($vnet, $hostname, $ipversion) = @_;
$ipversion = 4 if !$ipversion;
my $subnets_cfg = PVE::Network::SDN::Subnets::config();
@@ -71,7 +71,7 @@ sub get_next_free_ip {
$subnet = $subnets_cfg->{ids}->{$subnetid};
if ($subnet && $subnet->{ipam}) {
eval {
- $ip = PVE::Network::SDN::Subnets::next_free_ip($subnetid, $subnet);
+ $ip = PVE::Network::SDN::Subnets::next_free_ip($subnetid, $subnet, $hostname);
};
warn $@ if $@;
}
@@ -83,23 +83,23 @@ sub get_next_free_ip {
}
sub add_ip {
- my ($vnet, $cidr, $name) = @_;
+ my ($vnet, $cidr, $hostname) = @_;
my ($ip, $mask) = split(/\//, $cidr);
my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $vnet->{subnets});
return if !$subnet->{ipam};
- PVE::Network::SDN::Subnets::add_ip($subnetid, $subnet, $ip);
+ PVE::Network::SDN::Subnets::add_ip($subnetid, $subnet, $ip, $hostname);
}
sub del_ip {
- my ($vnet, $cidr) = @_;
+ my ($vnet, $cidr, $hostname) = @_;
my ($ip, $mask) = split(/\//, $cidr);
my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $vnet->{subnets});
return if !$subnet->{ipam};
- PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip);
+ PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip, $hostname);
}
1;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 15/38] Fix vnet gateway for routed setup + /32 pointopoint subnet
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (13 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 14/38] add dns plugin Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 16/38] ipam : pveplugin : fix find_next_free_ip Alexandre Derumier
` (23 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/SubnetPlugin.pm | 6 ++++--
PVE/Network/SDN/Zones/EvpnPlugin.pm | 10 ++++++++--
PVE/Network/SDN/Zones/SimplePlugin.pm | 13 +++++++++++--
test/generateconfig.pl | 3 ++-
4 files changed, 25 insertions(+), 7 deletions(-)
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index 3769e04..bc66b82 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -120,8 +120,10 @@ sub on_update_hook {
my $reversedns = $subnet->{reversedns};
my $reversednszone = $subnet->{reversednszone};
- #to: for /32 pointotoping, allow gateway outside the subnet
- raise_param_exc({ gateway => "$gateway is not in subnet $subnet"}) if $gateway && !$subnet_matcher->($gateway);
+ my ($ip, $mask) = split(/\//, $cidr);
+
+ #for /32 pointopoint, we allow gateway outside the subnet
+ raise_param_exc({ gateway => "$gateway is not in subnet $subnet"}) if $gateway && !$subnet_matcher->($gateway) && $mask != 32;
raise_param_exc({ dns => "missing dns provider"}) if $dnszone && !$dns;
raise_param_exc({ dnszone => "missing dns zone"}) if $dns && !$dnszone;
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index 0ebe13e..17c9262 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -77,9 +77,15 @@ sub generate_sdn_config {
@iface_config = ();
my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
+ my $address = {};
foreach my $subnet (@subnets) {
- next if !defined($subnet_cfg->{ids}->{$subnet});
- push @iface_config, "address $subnet_cfg->{ids}->{$subnet}->{gateway}" if $subnet_cfg->{ids}->{$subnet}->{gateway};
+ my $subnetid = $subnet =~ s/\//-/r;
+ next if !defined($subnet_cfg->{ids}->{$subnetid});
+ my $gateway = $subnet_cfg->{ids}->{$subnetid}->{gateway};
+ if ($gateway) {
+ push @iface_config, "address $gateway" if !defined($address->{$gateway});
+ $address->{$gateway} = 1;
+ }
}
push @iface_config, "hwaddress $mac" if $mac;
diff --git a/PVE/Network/SDN/Zones/SimplePlugin.pm b/PVE/Network/SDN/Zones/SimplePlugin.pm
index 7006b13..a1733d5 100644
--- a/PVE/Network/SDN/Zones/SimplePlugin.pm
+++ b/PVE/Network/SDN/Zones/SimplePlugin.pm
@@ -36,9 +36,18 @@ sub generate_sdn_config {
my @iface_config = ();
my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
+ my $address = {};
foreach my $subnet (@subnets) {
- next if !defined($subnet_cfg->{ids}->{$subnet});
- push @iface_config, "address $subnet_cfg->{ids}->{$subnet}->{gateway}" if $subnet_cfg->{ids}->{$subnet}->{gateway};
+ my $subnetid = $subnet =~ s/\//-/r;
+ next if !defined($subnet_cfg->{ids}->{$subnetid});
+ my $gateway = $subnet_cfg->{ids}->{$subnetid}->{gateway};
+ if ($gateway) {
+ push @iface_config, "address $gateway" if !defined($address->{$gateway});
+ $address->{$gateway} = 1;
+ }
+ #add route for /32 pointtopoint
+ my ($ip, $mask) = split(/\//, $subnet);
+ push @iface_config, "up ip route add $subnet dev $vnetid" if $mask == 32;
}
push @iface_config, "hwaddress $mac" if $mac;
diff --git a/test/generateconfig.pl b/test/generateconfig.pl
index 36880ba..92108ec 100644
--- a/test/generateconfig.pl
+++ b/test/generateconfig.pl
@@ -3,17 +3,18 @@ use warnings;
use File::Copy;
use PVE::Cluster qw(cfs_read_file);
+use PVE::Network::SDN;
use PVE::Network::SDN::Zones;
use PVE::Network::SDN::Controllers;
use Data::Dumper;
my $network_config = PVE::Network::SDN::Zones::generate_etc_network_config();
+
PVE::Network::SDN::Zones::write_etc_network_config($network_config);
print "/etc/network/interfaces.d/sdn\n";
print $network_config;
print "\n";
-
my $controller_config = PVE::Network::SDN::Controllers::generate_controller_config();
if ($controller_config) {
print Dumper($controller_config);
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 16/38] ipam : pveplugin : fix find_next_free_ip
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (14 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 15/38] Fix vnet gateway for routed setup + /32 pointopoint subnet Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 17/38] add vnet to subnets && remove subnetlist from vnet Alexandre Derumier
` (22 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
skip network && broadcast address
---
PVE/Network/SDN/Ipams/PVEPlugin.pm | 11 ++++++-----
debian/control | 1 +
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/PVE/Network/SDN/Ipams/PVEPlugin.pm b/PVE/Network/SDN/Ipams/PVEPlugin.pm
index 99af0ed..741a680 100644
--- a/PVE/Network/SDN/Ipams/PVEPlugin.pm
+++ b/PVE/Network/SDN/Ipams/PVEPlugin.pm
@@ -6,7 +6,7 @@ use PVE::INotify;
use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_register_file cfs_lock_file);
use PVE::Tools;
use JSON;
-use Net::IP;
+use NetAddr::IP;
use Digest::SHA;
use base('PVE::Network::SDN::Ipams::Plugin');
@@ -93,12 +93,13 @@ sub add_next_freeip {
my $db = read_db();
my $s = $db->{subnets}->{$cidr};
-
- my $iplist = new Net::IP($cidr);
+ my $iplist = new NetAddr::IP($cidr);
+ my $broadcast = $iplist->broadcast();
while(1) {
- my $ip = $iplist->ip();
- ++$iplist;
+ $iplist++;
+ last if $iplist eq $broadcast;
+ my $ip = $iplist->addr();
next if defined($s->{ips}->{$ip});
$freeip = $ip;
last;
diff --git a/debian/control b/debian/control
index c54f8bc..b2e3614 100644
--- a/debian/control
+++ b/debian/control
@@ -18,6 +18,7 @@ Depends: libpve-common-perl (>= 5.0-45),
pve-cluster (>= 5.0-32),
libnet-subnet-perl,
libnet-ip-perl,
+ libnetaddr-ip-perl,
${misc:Depends},
${perl:Depends},
Recommends: frr-pythontools, ifupdown2
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 17/38] add vnet to subnets && remove subnetlist from vnet
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (15 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 16/38] ipam : pveplugin : fix find_next_free_ip Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 18/38] zones: evpn|simple: add snat iptables rules Alexandre Derumier
` (21 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN/Subnets.pm | 31 +-------------
PVE/Network/SDN/SubnetPlugin.pm | 59 ++++++++++++++++++++-------
PVE/Network/SDN/Subnets.pm | 34 +++++++++------
PVE/Network/SDN/VnetPlugin.pm | 23 ++++-------
PVE/Network/SDN/Vnets.pm | 43 ++++++++++++-------
PVE/Network/SDN/Zones/EvpnPlugin.pm | 10 ++---
PVE/Network/SDN/Zones/SimplePlugin.pm | 16 ++++----
7 files changed, 117 insertions(+), 99 deletions(-)
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index 094401c..728b939 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -135,17 +135,7 @@ __PACKAGE__->register_method ({
}
$cfg->{ids}->{$id} = $opts;
- PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $cfg);
-
- my $ipam_cfg = PVE::Network::SDN::Ipams::config();
- my $ipam = $cfg->{ids}->{$id}->{ipam};
- if ($ipam) {
- raise_param_exc({ ipam => "$ipam not existing"}) if !$ipam_cfg->{ids}->{$ipam};
- my $plugin_config = $ipam_cfg->{ids}->{$ipam};
- my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
- $plugin->add_subnet($plugin_config, $id, $cfg->{ids}->{$id});
- $plugin->add_ip($plugin_config, $id, $opts->{gateway}, 1) if $opts->{gateway};
- }
+ PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $opts);
PVE::Network::SDN::Subnets::write_config($cfg);
@@ -182,24 +172,7 @@ __PACKAGE__->register_method ({
my $opts = PVE::Network::SDN::SubnetPlugin->check_config($id, $param, 0, 1);
$cfg->{ids}->{$id} = $opts;
- PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $cfg);
-
- my $ipam_cfg = PVE::Network::SDN::Ipams::config();
- my $ipam = $cfg->{ids}->{$id}->{ipam};
- if ($ipam) {
- raise_param_exc({ ipam => "$ipam not existing"}) if !$ipam_cfg->{ids}->{$ipam};
- my $plugin_config = $ipam_cfg->{ids}->{$ipam};
- my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
- $plugin->add_subnet($plugin_config, $id, $cfg->{ids}->{$id});
-
- if($opts->{gateway} && $scfg->{gateway} && $opts->{gateway} ne $scfg->{gateway}) {
- $plugin->del_ip($plugin_config, $id, $scfg->{gateway});
- }
- if (!defined($opts->{gateway}) && $scfg->{gateway}) {
- $plugin->del_ip($plugin_config, $id, $scfg->{gateway});
- }
- $plugin->add_ip($plugin_config, $id, $opts->{gateway}, 1) if $opts->{gateway};
- }
+ PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $opts, $scfg);
PVE::Network::SDN::Subnets::write_config($cfg);
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index bc66b82..84303d1 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -8,6 +8,8 @@ use base qw(PVE::SectionConfig);
use PVE::JSONSchema qw(get_standard_option);
use PVE::Exception qw(raise raise_param_exc);
use Net::Subnet qw(subnet_matcher);
+use PVE::Network::SDN::Vnets;
+use PVE::Network::SDN::Ipams;
PVE::Cluster::cfs_register_file('sdn/subnets.cfg',
sub { __PACKAGE__->parse_config(@_); },
@@ -52,6 +54,10 @@ sub private {
sub properties {
return {
+ vnet => {
+ type => 'string',
+ description => "associated vnet",
+ },
gateway => {
type => 'string', format => 'ip',
description => "Subnet Gateway: Will be assign on vnet for layer3 zones",
@@ -94,6 +100,7 @@ sub properties {
sub options {
return {
+ vnet => { optional => 1 },
gateway => { optional => 1 },
routes => { optional => 1 },
snat => { optional => 1 },
@@ -107,44 +114,66 @@ sub options {
}
sub on_update_hook {
- my ($class, $subnetid, $subnet_cfg) = @_;
+ my ($class, $subnetid, $subnet, $old_subnet) = @_;
my $cidr = $subnetid =~ s/-/\//r;
my $subnet_matcher = subnet_matcher($cidr);
- my $subnet = $subnet_cfg->{ids}->{$subnetid};
-
+ my $vnetid = $subnet->{vnet};
my $gateway = $subnet->{gateway};
+ my $ipam = $subnet->{ipam};
my $dns = $subnet->{dns};
my $dnszone = $subnet->{dnszone};
my $reversedns = $subnet->{reversedns};
my $reversednszone = $subnet->{reversednszone};
- my ($ip, $mask) = split(/\//, $cidr);
+ my $old_gateway = $old_subnet->{gateway} if $old_subnet;
+ if($vnetid) {
+ my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
+ raise_param_exc({ vnet => "$vnetid don't exist"}) if !$vnet;
+ }
+
+ my ($ip, $mask) = split(/\//, $cidr);
#for /32 pointopoint, we allow gateway outside the subnet
- raise_param_exc({ gateway => "$gateway is not in subnet $subnet"}) if $gateway && !$subnet_matcher->($gateway) && $mask != 32;
+ raise_param_exc({ gateway => "$gateway is not in subnet $subnetid"}) if $gateway && !$subnet_matcher->($gateway) && $mask != 32;
raise_param_exc({ dns => "missing dns provider"}) if $dnszone && !$dns;
raise_param_exc({ dnszone => "missing dns zone"}) if $dns && !$dnszone;
raise_param_exc({ reversedns => "missing dns provider"}) if $reversednszone && !$reversedns;
raise_param_exc({ reversednszone => "missing dns zone"}) if $reversedns && !$reversednszone;
+ if ($ipam) {
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ my $plugin_config = $ipam_cfg->{ids}->{$ipam};
+ raise_param_exc({ ipam => "$ipam not existing"}) if !$plugin_config;
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+ $plugin->add_subnet($plugin_config, $subnetid, $subnet);
+
+ #delete on removal
+ if (!defined($gateway) && $old_gateway) {
+ eval {
+ PVE::Network::SDN::Subnets::del_ip($subnetid, $old_subnet, $old_gateway);
+ };
+ warn if $@;
+ }
+ if(!$old_gateway || $gateway && $gateway ne $old_gateway) {
+ PVE::Network::SDN::Subnets::add_ip($subnetid, $subnet, $gateway);
+ }
+
+ #delete old ip after update
+ if($gateway && $old_gateway && $gateway ne $old_gateway) {
+ eval {
+ PVE::Network::SDN::Subnets::del_ip($subnetid, $old_subnet, $old_gateway);
+ };
+ warn if $@;
+ }
+ }
}
sub on_delete_hook {
my ($class, $subnetid, $subnet_cfg, $vnet_cfg) = @_;
- #verify if vnets have subnet
- foreach my $vnetid (keys %{$vnet_cfg->{ids}}) {
- my $vnet = $vnet_cfg->{ids}->{$vnetid};
- my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
- foreach my $subnet (@subnets) {
- my $id = $subnet =~ s/\//-/r;
- raise_param_exc({ subnet => "$subnet is attached to vnet $vnetid"}) if $id eq $subnetid;
- }
- }
-
return;
}
diff --git a/PVE/Network/SDN/Subnets.pm b/PVE/Network/SDN/Subnets.pm
index 4e8353e..d20af9e 100644
--- a/PVE/Network/SDN/Subnets.pm
+++ b/PVE/Network/SDN/Subnets.pm
@@ -57,20 +57,18 @@ sub get_subnet {
}
sub find_ip_subnet {
- my ($ip, $subnetslist) = @_;
-
- my $subnets_cfg = PVE::Network::SDN::Subnets::config();
- my @subnets = PVE::Tools::split_list($subnetslist) if $subnetslist;
+ my ($ip, $subnets) = @_;
my $subnet = undef;
my $subnetid = undef;
- foreach my $s (@subnets) {
- my $subnet_matcher = subnet_matcher($s);
- next if !$subnet_matcher->($ip);
- $subnetid = $s =~ s/\//-/r;
- $subnet = $subnets_cfg->{ids}->{$subnetid};
- last;
+ foreach my $id (sort keys %{$subnets}) {
+ my $cidr = $id =~ s/-/\//r;
+ my $subnet_matcher = subnet_matcher($cidr);
+ next if !$subnet_matcher->($ip);
+ $subnet = $subnets->{$id};
+ $subnetid = $id;
+ last;
}
die "can't find any subnet for ip $ip" if !$subnet;
@@ -143,8 +141,11 @@ sub next_free_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});
- $cidr = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet);
- ($ip, undef) = split(/\//, $cidr);
+ eval {
+ $cidr = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet);
+ ($ip, undef) = split(/\//, $cidr);
+ };
+ die $@ if $@;
}
eval {
@@ -167,6 +168,8 @@ sub next_free_ip {
sub add_ip {
my ($subnetid, $subnet, $ip, $hostname) = @_;
+ return if !$subnet;
+
my $ipamid = $subnet->{ipam};
my $dns = $subnet->{dns};
my $dnszone = $subnet->{dnszone};
@@ -182,7 +185,10 @@ sub add_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->add_ip($plugin_config, $subnetid, $ip);
+ eval {
+ $plugin->add_ip($plugin_config, $subnetid, $ip);
+ };
+ die $@ if $@;
}
eval {
@@ -204,6 +210,8 @@ sub add_ip {
sub del_ip {
my ($subnetid, $subnet, $ip, $hostname) = @_;
+ return if !$subnet;
+
my $ipamid = $subnet->{ipam};
my $dns = $subnet->{dns};
my $dnszone = $subnet->{dnszone};
diff --git a/PVE/Network/SDN/VnetPlugin.pm b/PVE/Network/SDN/VnetPlugin.pm
index 6b2bcc8..47fd4d4 100644
--- a/PVE/Network/SDN/VnetPlugin.pm
+++ b/PVE/Network/SDN/VnetPlugin.pm
@@ -68,11 +68,6 @@ sub properties {
description => "alias name of the vnet",
optional => 1,
},
- subnets => {
- type => 'string',
- description => "Subnets list",
- optional => 1,
- },
mac => {
type => 'string',
description => "Anycast router mac address",
@@ -86,16 +81,21 @@ sub options {
zone => { optional => 0},
tag => { optional => 1},
alias => { optional => 1 },
- subnets => { optional => 1 },
mac => { optional => 1 },
vlanaware => { optional => 1 },
};
}
sub on_delete_hook {
- my ($class, $sdnid, $vnet_cfg) = @_;
+ my ($class, $vnetid, $vnet_cfg) = @_;
- return;
+ #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;
}
sub on_update_hook {
@@ -111,13 +111,6 @@ sub on_update_hook {
}
}
}
-
- #verify subnet
- my @subnets = PVE::Tools::split_list($vnet_cfg->{ids}->{$vnetid}->{subnets}) if $vnet_cfg->{ids}->{$vnetid}->{subnets};
- foreach my $subnet (@subnets) {
- my $id = $subnet =~ s/\//-/r;
- raise_param_exc({ subnet => "$subnet not existing"}) if !$subnet_cfg->{ids}->{$id};
- }
}
1;
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index c9916b1..7cec418 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -54,22 +54,35 @@ sub get_vnet {
return $vnet;
}
+sub get_subnets {
+ my ($vnetid) = @_;
+
+ my $subnets = {};
+ my $subnets_cfg = PVE::Network::SDN::Subnets::config();
+ foreach my $subnetid (sort keys %{$subnets_cfg->{ids}}) {
+ my $subnet = $subnets_cfg->{ids}->{$subnetid};
+ next if !$subnet->{vnet} || $subnet->{vnet} ne $vnetid;
+ $subnets->{$subnetid} = $subnet;
+ }
+ return $subnets;
+
+}
+
sub get_next_free_ip {
- my ($vnet, $hostname, $ipversion) = @_;
+ my ($vnetid, $hostname, $ipversion) = @_;
$ipversion = 4 if !$ipversion;
- my $subnets_cfg = PVE::Network::SDN::Subnets::config();
- my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
+ my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
my $ip = undef;
- my $subnet = undef;
my $subnetcount = 0;
- foreach my $s (@subnets) {
- my $subnetid = $s =~ s/\//-/r;
+
+ foreach my $subnetid (sort keys %{$subnets}) {
+ my $subnet = $subnets->{$subnetid};
my ($network, $mask) = split(/-/, $subnetid);
+
next if $ipversion != Net::IP::ip_get_version($network);
$subnetcount++;
- $subnet = $subnets_cfg->{ids}->{$subnetid};
- if ($subnet && $subnet->{ipam}) {
+ if ($subnet->{ipam}) {
eval {
$ip = PVE::Network::SDN::Subnets::next_free_ip($subnetid, $subnet, $hostname);
};
@@ -83,21 +96,23 @@ sub get_next_free_ip {
}
sub add_ip {
- my ($vnet, $cidr, $hostname) = @_;
+ my ($vnetid, $cidr, $hostname) = @_;
+
+ my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
my ($ip, $mask) = split(/\//, $cidr);
- my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $vnet->{subnets});
- return if !$subnet->{ipam};
+ my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $subnets);
PVE::Network::SDN::Subnets::add_ip($subnetid, $subnet, $ip, $hostname);
}
sub del_ip {
- my ($vnet, $cidr, $hostname) = @_;
+ my ($vnetid, $cidr, $hostname) = @_;
+
+ my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
my ($ip, $mask) = split(/\//, $cidr);
- my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $vnet->{subnets});
- return if !$subnet->{ipam};
+ my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $subnets);
PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip, $hostname);
}
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index 17c9262..ff25f12 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -76,12 +76,12 @@ sub generate_sdn_config {
#vnet bridge
@iface_config = ();
- my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
my $address = {};
- foreach my $subnet (@subnets) {
- my $subnetid = $subnet =~ s/\//-/r;
- next if !defined($subnet_cfg->{ids}->{$subnetid});
- my $gateway = $subnet_cfg->{ids}->{$subnetid}->{gateway};
+ my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
+ foreach my $subnetid (sort keys %{$subnets}) {
+ my $subnet = $subnets->{$subnetid};
+ my $cidr = $subnetid =~ s/-/\//r;
+ my $gateway = $subnet->{gateway};
if ($gateway) {
push @iface_config, "address $gateway" if !defined($address->{$gateway});
$address->{$gateway} = 1;
diff --git a/PVE/Network/SDN/Zones/SimplePlugin.pm b/PVE/Network/SDN/Zones/SimplePlugin.pm
index a1733d5..a4299dd 100644
--- a/PVE/Network/SDN/Zones/SimplePlugin.pm
+++ b/PVE/Network/SDN/Zones/SimplePlugin.pm
@@ -35,19 +35,19 @@ sub generate_sdn_config {
# vnet bridge
my @iface_config = ();
- my @subnets = PVE::Tools::split_list($vnet->{subnets}) if $vnet->{subnets};
my $address = {};
- foreach my $subnet (@subnets) {
- my $subnetid = $subnet =~ s/\//-/r;
- next if !defined($subnet_cfg->{ids}->{$subnetid});
- my $gateway = $subnet_cfg->{ids}->{$subnetid}->{gateway};
- if ($gateway) {
+ my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
+ foreach my $subnetid (sort keys %{$subnets}) {
+ my $subnet = $subnets->{$subnetid};
+ my $cidr = $subnetid =~ s/-/\//r;
+ 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(/\//, $subnet);
- push @iface_config, "up ip route add $subnet dev $vnetid" if $mask == 32;
+ my ($ip, $mask) = split(/\//, $cidr);
+ push @iface_config, "up ip route add $cidr dev $vnetid" if $mask == 32;
}
push @iface_config, "hwaddress $mac" if $mac;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 18/38] zones: evpn|simple: add snat iptables rules
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (16 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 17/38] add vnet to subnets && remove subnetlist from vnet Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 19/38] subnet: disable route option for now and add dns domain format Alexandre Derumier
` (20 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
(use snat instead masquerade for performance)
---
PVE/Network/SDN/Zones/EvpnPlugin.pm | 18 ++++++++++++++++++
PVE/Network/SDN/Zones/SimplePlugin.pm | 12 ++++++++++++
2 files changed, 30 insertions(+)
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index ff25f12..b89f4b1 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -51,6 +51,7 @@ sub generate_sdn_config {
my $vrf_iface = "vrf_$zoneid";
my $vrfvxlan = $plugin_config->{'vrf-vxlan'};
+ my $local_node = PVE::INotify::nodename();
die "missing vxlan tag" if !$tag;
warn "vlan-aware vnet can't be enabled with evpn plugin" if $vnet->{vlanaware};
@@ -86,6 +87,23 @@ sub generate_sdn_config {
push @iface_config, "address $gateway" if !defined($address->{$gateway});
$address->{$gateway} = 1;
}
+ if ($subnet->{snat}) {
+ my $gatewaynodes = $controller->{'gateway-nodes'};
+ my $is_evpn_gateway = "";
+ foreach my $evpn_gatewaynode (PVE::Tools::split_list($gatewaynodes)) {
+ $is_evpn_gateway = 1 if $evpn_gatewaynode eq $local_node;
+ }
+ #find outgoing interface
+ my ($outip, $outiface) = PVE::Network::SDN::Zones::Plugin::get_local_route_ip('8.8.8.8');
+ if ($outip && $outiface && $is_evpn_gateway) {
+ #use snat, faster than masquerade
+ push @iface_config, "post-up iptables -t nat -A POSTROUTING -s '$cidr' -o $outiface -j SNAT --to-source $outip";
+ push @iface_config, "post-down iptables -t nat -D POSTROUTING -s '$cidr' -o $outiface -j SNAT --to-source $outip";
+ #add conntrack zone once on outgoing interface
+ push @iface_config, "post-up iptables -t raw -I PREROUTING -i fwbr+ -j CT --zone 1";
+ push @iface_config, "post-down iptables -t raw -D PREROUTING -i fwbr+ -j CT --zone 1";
+ }
+ }
}
push @iface_config, "hwaddress $mac" if $mac;
diff --git a/PVE/Network/SDN/Zones/SimplePlugin.pm b/PVE/Network/SDN/Zones/SimplePlugin.pm
index a4299dd..c58ae87 100644
--- a/PVE/Network/SDN/Zones/SimplePlugin.pm
+++ b/PVE/Network/SDN/Zones/SimplePlugin.pm
@@ -48,6 +48,18 @@ sub generate_sdn_config {
#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
+ my ($outip, $outiface) = PVE::Network::SDN::Zones::Plugin::get_local_route_ip('8.8.8.8');
+ if ($outip && $outiface) {
+ #use snat, faster than masquerade
+ push @iface_config, "post-up iptables -t nat -A POSTROUTING -s '$cidr' -o $outiface -j SNAT --to-source $outip";
+ push @iface_config, "post-down iptables -t nat -D POSTROUTING -s '$cidr' -o $outiface -j SNAT --to-source $outip";
+ #add conntrack zone once on outgoing interface
+ push @iface_config, "post-up iptables -t raw -I PREROUTING -i fwbr+ -j CT --zone 1";
+ push @iface_config, "post-down iptables -t raw -D PREROUTING -i fwbr+ -j CT --zone 1";
+ }
+ }
}
push @iface_config, "hwaddress $mac" if $mac;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 19/38] subnet: disable route option for now and add dns domain format
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (17 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 18/38] zones: evpn|simple: add snat iptables rules Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 20/38] dns: fix reverse dns Alexandre Derumier
` (19 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/SubnetPlugin.pm | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index 84303d1..6237867 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -66,11 +66,11 @@ sub properties {
type => 'boolean',
description => "enable masquerade for this subnet if pve-firewall",
},
- #cloudinit, dhcp options
- routes => {
- type => 'string',
- description => "static routes [network=<network>:gateway=<ip>,network=<network>:gateway=<ip>,... ]",
- },
+# #cloudinit, dhcp options
+# routes => {
+# type => 'string',
+# description => "static routes [network=<network>:gateway=<ip>,network=<network>:gateway=<ip>,... ]",
+# },
dns => {
type => 'string',
description => "dns api server",
@@ -80,15 +80,15 @@ sub properties {
description => "reverse dns api server",
},
dnszone => {
- type => 'string',
+ type => 'string', format => 'dns-name',
description => "dns domain zone ex: mydomain.com",
},
reversednszone => {
- type => 'string',
+ type => 'string', format => 'dns-name',
description => "reverse dns zone ex: 0.168.192.in-addr.arpa",
},
dnszoneprefix => {
- type => 'string',
+ type => 'string', format => 'dns-name',
description => "dns domain zone prefix ex: 'adm' -> <hostname>.adm.mydomain.com",
},
ipam => {
@@ -102,7 +102,7 @@ sub options {
return {
vnet => { optional => 1 },
gateway => { optional => 1 },
- routes => { optional => 1 },
+# routes => { optional => 1 },
snat => { optional => 1 },
dns => { optional => 1 },
reversedns => { optional => 1 },
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 20/38] dns: fix reverse dns
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (18 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 19/38] subnet: disable route option for now and add dns domain format Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 21/38] subnets: move api to /sdn/vnet/<vnet>/subnets && make vnet option not optionnal Alexandre Derumier
` (18 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/Dns/PowerdnsPlugin.pm | 12 +++----
PVE/Network/SDN/SubnetPlugin.pm | 1 +
PVE/Network/SDN/Subnets.pm | 50 ++++++++++++++++++---------
3 files changed, 40 insertions(+), 23 deletions(-)
diff --git a/PVE/Network/SDN/Dns/PowerdnsPlugin.pm b/PVE/Network/SDN/Dns/PowerdnsPlugin.pm
index 8c5dd90..f02c2f1 100644
--- a/PVE/Network/SDN/Dns/PowerdnsPlugin.pm
+++ b/PVE/Network/SDN/Dns/PowerdnsPlugin.pm
@@ -79,12 +79,12 @@ sub add_ptr_record {
my $key = $plugin_config->{key};
my $ttl = $plugin_config->{ttl} ? $plugin_config->{ttl} : 14400;
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
+ $hostname .= ".";
- my $reverseip = join(".", reverse(split(/\./, $ip)))."in-addr.arpa.";
- my $fqdn = $hostname.".".$zone.".";
+ my $reverseip = join(".", reverse(split(/\./, $ip))).".in-addr.arpa.";
my $type = "PTR";
- my $record = { content => $fqdn,
+ my $record = { content => $hostname,
disabled => JSON::false,
name => $reverseip,
type => $type,
@@ -109,13 +109,13 @@ sub add_ptr_record {
}
sub del_a_record {
- my ($class, $plugin_config, $zone, $hostname) = @_;
+ my ($class, $plugin_config, $zone, $hostname, $ip) = @_;
my $url = $plugin_config->{url};
my $key = $plugin_config->{key};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
my $fqdn = $hostname.".".$zone.".";
- my $type = "PTR";
+ my $type = Net::IP::ip_is_ipv6($ip) ? "AAAA" : "A";
my $rrset = { name => $fqdn,
type => $type,
@@ -140,7 +140,7 @@ sub del_ptr_record {
my $key = $plugin_config->{key};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
- my $reverseip = join(".", reverse(split(/\./, $ip)))."in-addr.arpa.";
+ my $reverseip = join(".", reverse(split(/\./, $ip))).".in-addr.arpa.";
my $type = "PTR";
my $rrset = { name => $reverseip,
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index 6237867..b236c3f 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -142,6 +142,7 @@ sub on_update_hook {
raise_param_exc({ dnszone => "missing dns zone"}) if $dns && !$dnszone;
raise_param_exc({ reversedns => "missing dns provider"}) if $reversednszone && !$reversedns;
raise_param_exc({ reversednszone => "missing dns zone"}) if $reversedns && !$reversednszone;
+ raise_param_exc({ reversedns => "missing forward dns zone"}) if $reversednszone && !$dnszone;
if ($ipam) {
my $ipam_cfg = PVE::Network::SDN::Ipams::config();
diff --git a/PVE/Network/SDN/Subnets.pm b/PVE/Network/SDN/Subnets.pm
index d20af9e..626b71d 100644
--- a/PVE/Network/SDN/Subnets.pm
+++ b/PVE/Network/SDN/Subnets.pm
@@ -87,24 +87,33 @@ my $verify_dns_zone = sub {
};
my $add_dns_record = sub {
- my ($zone, $dns, $hostname, $dnszoneprefix, $ip, $reverse) = @_;
-
- return if !$zone || !$dns || !$hostname || !$ip;
+ my ($zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
+ return if !$zone || !$dns || !$hostname || !$ip;
$hostname .= ".$dnszoneprefix" if $dnszoneprefix;
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});
- if($reverse) {
- $plugin->add_ptr_record($plugin_config, $zone, $hostname, $ip);
- } else {
- $plugin->add_a_record($plugin_config, $zone, $hostname, $ip);
- }
+ $plugin->add_a_record($plugin_config, $zone, $hostname, $ip);
+
+};
+
+my $add_dns_ptr_record = sub {
+ my ($reversezone, $zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
+
+ return if !$zone || !$reversezone || !$dns || !$hostname || !$ip;
+
+ $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
+ $hostname .= ".$zone";
+ 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->add_ptr_record($plugin_config, $reversezone, $hostname, $ip);
};
my $del_dns_record = sub {
- my ($zone, $dns, $hostname, $dnszoneprefix, $ip, $reverse) = @_;
+ my ($zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
return if !$zone || !$dns || !$hostname || !$ip;
@@ -113,11 +122,18 @@ my $del_dns_record = sub {
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});
- if($reverse) {
- $plugin->del_ptr_record($plugin_config, $zone, $ip);
- } else {
- $plugin->del_a_record($plugin_config, $zone, $hostname);
- }
+ $plugin->del_a_record($plugin_config, $zone, $hostname, $ip);
+};
+
+my $del_dns_ptr_record = sub {
+ my ($reversezone, $dns, $ip) = @_;
+
+ return if !$reversezone || !$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->del_ptr_record($plugin_config, $reversezone, $ip);
};
sub next_free_ip {
@@ -152,7 +168,7 @@ sub next_free_ip {
#add dns
&$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
#add reverse dns
- &$add_dns_record($reversednszone, $reversedns, $hostname, $dnszoneprefix, $ip, 1);
+ &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $dnszoneprefix, $ip);
};
if ($@) {
#rollback
@@ -195,7 +211,7 @@ sub add_ip {
#add dns
&$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
#add reverse dns
- &$add_dns_record($reversednszone, $reversedns, $hostname, $dnszoneprefix, $ip, 1);
+ &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $dnszoneprefix, $ip);
};
if ($@) {
#rollback
@@ -231,7 +247,7 @@ sub del_ip {
eval {
&$del_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
- &$del_dns_record($reversednszone, $reversedns, $hostname, $dnszoneprefix, $ip, 1);
+ &$del_dns_ptr_record($reversednszone, $reversedns, $ip);
};
if ($@) {
warn $@;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 21/38] subnets: move api to /sdn/vnet/<vnet>/subnets && make vnet option not optionnal
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (19 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 20/38] dns: fix reverse dns Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 22/38] zones: evpn : fix raise exception Alexandre Derumier
` (17 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN.pm | 7 -------
PVE/API2/Network/SDN/Subnets.pm | 23 +++++++++++++++++------
PVE/API2/Network/SDN/Vnets.pm | 6 ++++++
PVE/Network/SDN/SubnetPlugin.pm | 2 +-
4 files changed, 24 insertions(+), 14 deletions(-)
diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm
index 0a5fa33..fcda11f 100644
--- a/PVE/API2/Network/SDN.pm
+++ b/PVE/API2/Network/SDN.pm
@@ -15,7 +15,6 @@ use PVE::Network::SDN;
use PVE::API2::Network::SDN::Controllers;
use PVE::API2::Network::SDN::Vnets;
use PVE::API2::Network::SDN::Zones;
-use PVE::API2::Network::SDN::Subnets;
use PVE::API2::Network::SDN::Ipams;
use PVE::API2::Network::SDN::Dns;
@@ -36,11 +35,6 @@ __PACKAGE__->register_method ({
path => 'controllers',
});
-__PACKAGE__->register_method ({
- subclass => "PVE::API2::Network::SDN::Subnets",
- path => 'subnets',
-});
-
__PACKAGE__->register_method ({
subclass => "PVE::API2::Network::SDN::Ipams",
path => 'ipams',
@@ -80,7 +74,6 @@ __PACKAGE__->register_method({
{ id => 'vnets' },
{ id => 'zones' },
{ id => 'controllers' },
- { id => 'subnets' },
{ id => 'ipams' },
{ id => 'dns' },
];
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index 728b939..ab4117c 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -44,6 +44,10 @@ __PACKAGE__->register_method ({
},
parameters => {
additionalProperties => 0,
+ properties => {
+ vnet => get_standard_option('pve-sdn-vnet-id'),
+ },
+
},
returns => {
type => 'array',
@@ -59,6 +63,7 @@ __PACKAGE__->register_method ({
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
+ my $vnetid = $param->{vnet};
my $cfg = PVE::Network::SDN::Subnets::config();
@@ -66,9 +71,10 @@ __PACKAGE__->register_method ({
my $res = [];
foreach my $id (@sids) {
my $privs = [ 'SDN.Audit', 'SDN.Allocate' ];
- next if !$rpcenv->check_any($authuser, "/sdn/subnets/$id", $privs, 1);
+ next if !$rpcenv->check_any($authuser, "/sdn/vnets/$vnetid/subnets/$id", $privs, 1);
my $scfg = &$api_sdn_subnets_config($cfg, $id);
+ next if !$scfg->{vnet} || $scfg->{vnet} ne $vnetid;
push @$res, $scfg;
}
@@ -81,12 +87,13 @@ __PACKAGE__->register_method ({
method => 'GET',
description => "Read sdn subnet configuration.",
permissions => {
- check => ['perm', '/sdn/subnets/{subnet}', ['SDN.Allocate']],
+ check => ['perm', '/sdn/vnets/{vnet}/subnets/{subnet}', ['SDN.Allocate']],
},
parameters => {
additionalProperties => 0,
properties => {
+ vnet => get_standard_option('pve-sdn-vnet-id'),
subnet => get_standard_option('pve-sdn-subnet-id', {
completion => \&PVE::Network::SDN::Subnets::complete_sdn_subnets,
}),
@@ -97,8 +104,11 @@ __PACKAGE__->register_method ({
my ($param) = @_;
my $cfg = PVE::Network::SDN::Subnets::config();
+ my $scfg = &$api_sdn_subnets_config($cfg, $param->{subnet});
+
+ raise_param_exc({ vnet => "wrong vnet"}) if $param->{vnet} ne $scfg->{vnet};
- return &$api_sdn_subnets_config($cfg, $param->{subnet});
+ return $scfg;
}});
__PACKAGE__->register_method ({
@@ -108,7 +118,7 @@ __PACKAGE__->register_method ({
method => 'POST',
description => "Create a new sdn subnet object.",
permissions => {
- check => ['perm', '/sdn/subnets', ['SDN.Allocate']],
+ check => ['perm', '/sdn/vnets/{vnet}/subnets', ['SDN.Allocate']],
},
parameters => PVE::Network::SDN::SubnetPlugin->createSchema(),
returns => { type => 'null' },
@@ -151,7 +161,7 @@ __PACKAGE__->register_method ({
method => 'PUT',
description => "Update sdn subnet object configuration.",
permissions => {
- check => ['perm', '/sdn/subnets', ['SDN.Allocate']],
+ check => ['perm', '/sdn/vnets/{vnet}/subnets', ['SDN.Allocate']],
},
parameters => PVE::Network::SDN::SubnetPlugin->updateSchema(),
returns => { type => 'null' },
@@ -188,11 +198,12 @@ __PACKAGE__->register_method ({
method => 'DELETE',
description => "Delete sdn subnet object configuration.",
permissions => {
- check => ['perm', '/sdn/subnets', ['SDN.Allocate']],
+ check => ['perm', '/sdn/vnets/{vnet}/subnets', ['SDN.Allocate']],
},
parameters => {
additionalProperties => 0,
properties => {
+ vnet => get_standard_option('pve-sdn-vnet-id'),
subnet => get_standard_option('pve-sdn-subnet-id', {
completion => \&PVE::Network::SDN::Subnets::complete_sdn_subnets,
}),
diff --git a/PVE/API2/Network/SDN/Vnets.pm b/PVE/API2/Network/SDN/Vnets.pm
index b585c9c..0fbb747 100644
--- a/PVE/API2/Network/SDN/Vnets.pm
+++ b/PVE/API2/Network/SDN/Vnets.pm
@@ -12,6 +12,7 @@ use PVE::Network::SDN::Zones::Plugin;
use PVE::Network::SDN::Vnets;
use PVE::Network::SDN::VnetPlugin;
use PVE::Network::SDN::Subnets;
+use PVE::API2::Network::SDN::Subnets;
use Storable qw(dclone);
use PVE::JSONSchema qw(get_standard_option);
@@ -21,6 +22,11 @@ use PVE::RESTHandler;
use base qw(PVE::RESTHandler);
+__PACKAGE__->register_method ({
+ subclass => "PVE::API2::Network::SDN::Subnets",
+ path => '{vnet}/subnets',
+});
+
my $api_sdn_vnets_config = sub {
my ($cfg, $id) = @_;
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index b236c3f..97d8cb8 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -100,7 +100,7 @@ sub properties {
sub options {
return {
- vnet => { optional => 1 },
+ vnet => { optional => 0 },
gateway => { optional => 1 },
# routes => { optional => 1 },
snat => { optional => 1 },
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 22/38] zones: evpn : fix raise exception
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (20 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 21/38] subnets: move api to /sdn/vnet/<vnet>/subnets && make vnet option not optionnal Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 23/38] subnet: make ipam not optionnal and use pve ipam as default Alexandre Derumier
` (16 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/Zones/EvpnPlugin.pm | 1 +
1 file changed, 1 insertion(+)
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index b89f4b1..d5ee56b 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -3,6 +3,7 @@ package PVE::Network::SDN::Zones::EvpnPlugin;
use strict;
use warnings;
use PVE::Network::SDN::Zones::VxlanPlugin;
+use PVE::Exception qw(raise raise_param_exc);
use PVE::Tools qw($IPV4RE);
use PVE::INotify;
use PVE::Cluster;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 23/38] subnet: make ipam not optionnal and use pve ipam as default
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (21 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 22/38] zones: evpn : fix raise exception Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 24/38] don't allow subnets on vlanware vnet Alexandre Derumier
` (15 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN/Subnets.pm | 2 ++
PVE/Network/SDN/Ipams.pm | 2 ++
PVE/Network/SDN/SubnetPlugin.pm | 2 +-
3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index ab4117c..2dd80a3 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -182,6 +182,8 @@ __PACKAGE__->register_method ({
my $opts = PVE::Network::SDN::SubnetPlugin->check_config($id, $param, 0, 1);
$cfg->{ids}->{$id} = $opts;
+ 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($id, $opts, $scfg);
PVE::Network::SDN::Subnets::write_config($cfg);
diff --git a/PVE/Network/SDN/Ipams.pm b/PVE/Network/SDN/Ipams.pm
index a979d46..302c4d2 100644
--- a/PVE/Network/SDN/Ipams.pm
+++ b/PVE/Network/SDN/Ipams.pm
@@ -34,6 +34,8 @@ sub sdn_ipams_config {
sub config {
my $config = cfs_read_file("sdn/ipams.cfg");
+ #add default internal pve
+ $config->{ids}->{pve}->{type} = 'pve';
return $config;
}
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index 97d8cb8..341e9e0 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -109,7 +109,7 @@ sub options {
dnszone => { optional => 1 },
reversednszone => { optional => 1 },
dnszoneprefix => { optional => 1 },
- ipam => { optional => 1 },
+ ipam => { optional => 0 },
};
}
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 24/38] don't allow subnets on vlanware vnet
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (22 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 23/38] subnet: make ipam not optionnal and use pve ipam as default Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 25/38] generate sdn/.running-config on apply Alexandre Derumier
` (14 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/SubnetPlugin.pm | 1 +
1 file changed, 1 insertion(+)
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index 341e9e0..8a216b6 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -132,6 +132,7 @@ sub on_update_hook {
if($vnetid) {
my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
raise_param_exc({ vnet => "$vnetid don't exist"}) if !$vnet;
+ raise_param_exc({ vnet => "you can't add a subnet on a vlanaware vnet"}) if $vnet->{vlanaware};
}
my ($ip, $mask) = split(/\//, $cidr);
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 25/38] generate sdn/.running-config on apply
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (23 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 24/38] don't allow subnets on vlanware vnet Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 26/38] api: add running/pending zones/vnets/subnets/controllers Alexandre Derumier
` (13 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
This is the source configuration for generate local configuration
/sdn/*.cfg are pending configs
---
PVE/API2/Network/SDN.pm | 2 +-
PVE/Network/SDN.pm | 57 +++++++++++++++++++--------
PVE/Network/SDN/Controllers.pm | 12 ++++--
PVE/Network/SDN/Subnets.pm | 11 +++++-
PVE/Network/SDN/Vnets.pm | 18 ++++++---
PVE/Network/SDN/Zones.pm | 27 +++++++------
PVE/Network/SDN/Zones/EvpnPlugin.pm | 2 +-
PVE/Network/SDN/Zones/SimplePlugin.pm | 2 +-
test/generateconfig.pl | 2 +
9 files changed, 91 insertions(+), 42 deletions(-)
diff --git a/PVE/API2/Network/SDN.pm b/PVE/API2/Network/SDN.pm
index fcda11f..f129d60 100644
--- a/PVE/API2/Network/SDN.pm
+++ b/PVE/API2/Network/SDN.pm
@@ -119,7 +119,7 @@ __PACKAGE__->register_method ({
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
- PVE::Network::SDN::increase_version();
+ PVE::Network::SDN::commit_config();
my $code = sub {
$rpcenv->{type} = 'priv'; # to start tasks in background
diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm
index 85faca0..f21de15 100644
--- a/PVE/Network/SDN.pm
+++ b/PVE/Network/SDN.pm
@@ -8,32 +8,39 @@ use JSON;
use PVE::Network::SDN::Vnets;
use PVE::Network::SDN::Zones;
+use PVE::Network::SDN::Controllers;
+use PVE::Network::SDN::Subnets;
use PVE::Tools qw(extract_param dir_glob_regex run_command);
use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
-my $version_cfg = "sdn/.version";
+my $running_cfg = "sdn/.running-config";
-my $parse_version_cfg = sub {
+my $parse_running_cfg = sub {
my ($filename, $raw) = @_;
- return 0 if !defined($raw) || $raw eq '';
+ my $cfg = {};
- warn "invalid sdn version '$raw'" if $raw !~ m/\d+$/;
+ return $cfg if !defined($raw) || $raw eq '';
- return $raw,
+ eval {
+ $cfg = from_json($raw);
+ };
+ return {} if $@;
+
+ return $cfg;
};
-my $write_version_cfg = sub {
- my ($filename, $version) = @_;
+my $write_running_cfg = sub {
+ my ($filename, $cfg) = @_;
- warn "invalid sdn version" if $version !~ m/\d+$/;
+ my $json = to_json($cfg);
- return $version;
+ return $json;
};
-PVE::Cluster::cfs_register_file($version_cfg, $parse_version_cfg, $write_version_cfg);
+PVE::Cluster::cfs_register_file($running_cfg, $parse_running_cfg, $write_running_cfg);
# improve me : move status code inside plugins ?
@@ -70,23 +77,40 @@ sub status {
return($zone_status, $vnet_status);
}
+sub config {
+ return cfs_read_file($running_cfg);
+}
+
+sub commit_config {
-sub increase_version {
+ my $cfg = cfs_read_file($running_cfg);
+ my $version = $cfg->{version};
- my $version = cfs_read_file($version_cfg);
if ($version) {
$version++;
} else {
$version = 1;
}
- cfs_write_file($version_cfg, $version);
+ my $vnets_cfg = PVE::Network::SDN::Vnets::config();
+ my $zones_cfg = PVE::Network::SDN::Zones::config();
+ my $controllers_cfg = PVE::Network::SDN::Controllers::config();
+ my $subnets_cfg = PVE::Network::SDN::Subnets::config();
+
+ my $vnets = { ids => $vnets_cfg->{ids} };
+ my $zones = { ids => $zones_cfg->{ids} };
+ my $controllers = { ids => $controllers_cfg->{ids} };
+ my $subnets = { ids => $subnets_cfg->{ids} };
+
+ $cfg = { version => $version, vnets => $vnets, zones => $zones, controllers => $controllers, subnets => $subnets };
+
+ cfs_write_file($running_cfg, $cfg);
}
sub lock_sdn_config {
my ($code, $errmsg) = @_;
- cfs_lock_file($version_cfg, undef, $code);
+ cfs_lock_file($running_cfg, undef, $code);
if (my $err = $@) {
$errmsg ? die "$errmsg: $err" : die $err;
@@ -101,8 +125,9 @@ sub get_local_vnets {
my $nodename = PVE::INotify::nodename();
- my $vnets_cfg = PVE::Network::SDN::Vnets::config();
- my $zones_cfg = PVE::Network::SDN::Zones::config();
+ my $cfg = PVE::Network::SDN::config();
+ my $vnets_cfg = $cfg->{vnets};
+ my $zones_cfg = $cfg->{zones};
my @vnetids = PVE::Network::SDN::Vnets::sdn_vnets_ids($vnets_cfg);
diff --git a/PVE/Network/SDN/Controllers.pm b/PVE/Network/SDN/Controllers.pm
index 91a74d8..c210516 100644
--- a/PVE/Network/SDN/Controllers.pm
+++ b/PVE/Network/SDN/Controllers.pm
@@ -68,9 +68,11 @@ sub complete_sdn_controller {
sub generate_controller_config {
- my $vnet_cfg = PVE::Cluster::cfs_read_file('sdn/vnets.cfg');
- my $zone_cfg = PVE::Cluster::cfs_read_file('sdn/zones.cfg');
- my $controller_cfg = PVE::Cluster::cfs_read_file('sdn/controllers.cfg');
+ my $cfg = PVE::Network::SDN::config();
+ my $vnet_cfg = $cfg->{vnets};
+ my $zone_cfg = $cfg->{zones};
+ my $controller_cfg = $cfg->{controllers};
+
return if !$vnet_cfg && !$zone_cfg && !$controller_cfg;
#read main config for physical interfaces
@@ -131,7 +133,9 @@ sub generate_controller_config {
sub reload_controller {
- my $controller_cfg = PVE::Cluster::cfs_read_file('sdn/controllers.cfg');
+ my $cfg = PVE::Network::SDN::config();
+ my $controller_cfg = $cfg->{controllers};
+
return if !$controller_cfg;
foreach my $id (keys %{$controller_cfg->{ids}}) {
diff --git a/PVE/Network/SDN/Subnets.pm b/PVE/Network/SDN/Subnets.pm
index 626b71d..5b99c91 100644
--- a/PVE/Network/SDN/Subnets.pm
+++ b/PVE/Network/SDN/Subnets.pm
@@ -49,9 +49,16 @@ sub complete_sdn_subnet {
}
sub get_subnet {
- my ($subnetid) = @_;
+ my ($subnetid, $running) = @_;
+
+ my $cfg = {};
+ if($running) {
+ my $cfg = PVE::Network::SDN::config();
+ $cfg = $cfg->{subnets};
+ } else {
+ $cfg = PVE::Network::SDN::Subnets::config();
+ }
- my $cfg = PVE::Network::SDN::Subnets::config();
my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $subnetid, 1);
return $subnet;
}
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index 7cec418..d45ef2a 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -47,10 +47,18 @@ sub complete_sdn_vnet {
}
sub get_vnet {
- my ($vnetid) = @_;
+ my ($vnetid, $running) = @_;
+
+ my $cfg = {};
+ if($running) {
+ my $cfg = PVE::Network::SDN::config();
+ $cfg = $cfg->{vnets};
+ } else {
+ $cfg = PVE::Network::SDN::Vnets::config();
+ }
- my $cfg = PVE::Network::SDN::Vnets::config();
my $vnet = PVE::Network::SDN::Vnets::sdn_vnets_config($cfg, $vnetid, 1);
+
return $vnet;
}
@@ -72,7 +80,7 @@ sub get_next_free_ip {
my ($vnetid, $hostname, $ipversion) = @_;
$ipversion = 4 if !$ipversion;
- my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
+ my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
my $ip = undef;
my $subnetcount = 0;
@@ -98,7 +106,7 @@ sub get_next_free_ip {
sub add_ip {
my ($vnetid, $cidr, $hostname) = @_;
- my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
+ my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
my ($ip, $mask) = split(/\//, $cidr);
my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $subnets);
@@ -109,7 +117,7 @@ sub add_ip {
sub del_ip {
my ($vnetid, $cidr, $hostname) = @_;
- my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
+ my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
my ($ip, $mask) = split(/\//, $cidr);
my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $subnets);
diff --git a/PVE/Network/SDN/Zones.pm b/PVE/Network/SDN/Zones.pm
index 25af088..75f3233 100644
--- a/PVE/Network/SDN/Zones.pm
+++ b/PVE/Network/SDN/Zones.pm
@@ -11,7 +11,6 @@ use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
use PVE::Network;
use PVE::Network::SDN::Vnets;
-use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::Zones::VlanPlugin;
use PVE::Network::SDN::Zones::QinQPlugin;
use PVE::Network::SDN::Zones::VxlanPlugin;
@@ -76,11 +75,13 @@ sub complete_sdn_zone {
sub generate_etc_network_config {
- my $version = PVE::Cluster::cfs_read_file('sdn/.version');
- my $vnet_cfg = PVE::Cluster::cfs_read_file('sdn/vnets.cfg');
- my $zone_cfg = PVE::Cluster::cfs_read_file('sdn/zones.cfg');
- my $subnet_cfg = PVE::Network::SDN::Subnets::config();
- my $controller_cfg = PVE::Cluster::cfs_read_file('sdn/controllers.cfg');
+ my $cfg = PVE::Network::SDN::config();
+
+ my $version = $cfg->{version};
+ my $vnet_cfg = $cfg->{vnets};
+ my $zone_cfg = $cfg->{zones};
+ my $subnet_cfg = $cfg->{subnets};
+ my $controller_cfg = $cfg->{controllers};
return if !$vnet_cfg && !$zone_cfg;
my $interfaces_config = PVE::INotify::read_file('interfaces');
@@ -188,7 +189,8 @@ sub status {
my $err_config = undef;
my $local_version = PVE::Network::SDN::Zones::read_etc_network_config_version();
- my $sdn_version = PVE::Cluster::cfs_read_file('sdn/.version');
+ my $cfg = PVE::Network::SDN::config();
+ my $sdn_version = $cfg->{version};
return if !$sdn_version;
@@ -210,8 +212,9 @@ sub status {
my $status = ifquery_check();
- my $vnet_cfg = PVE::Cluster::cfs_read_file('sdn/vnets.cfg');
- my $zone_cfg = PVE::Cluster::cfs_read_file('sdn/zones.cfg');
+
+ my $vnet_cfg = $cfg->{vnets};
+ my $zone_cfg = $cfg->{zones};
my $nodename = PVE::INotify::nodename();
my $vnet_status = {};
@@ -253,7 +256,7 @@ sub status {
sub tap_create {
my ($iface, $bridge) = @_;
- my $vnet = PVE::Network::SDN::Vnets::get_vnet($bridge);
+ my $vnet = PVE::Network::SDN::Vnets::get_vnet($bridge, 1);
if (!$vnet) { # fallback for classic bridge
PVE::Network::tap_create($iface, $bridge);
return;
@@ -267,7 +270,7 @@ sub tap_create {
sub veth_create {
my ($veth, $vethpeer, $bridge, $hwaddr) = @_;
- my $vnet = PVE::Network::SDN::Vnets::get_vnet($bridge);
+ my $vnet = PVE::Network::SDN::Vnets::get_vnet($bridge, 1);
if (!$vnet) { # fallback for classic bridge
PVE::Network::veth_create($veth, $vethpeer, $bridge, $hwaddr);
return;
@@ -281,7 +284,7 @@ sub veth_create {
sub tap_plug {
my ($iface, $bridge, $tag, $firewall, $trunks, $rate) = @_;
- my $vnet = PVE::Network::SDN::Vnets::get_vnet($bridge);
+ my $vnet = PVE::Network::SDN::Vnets::get_vnet($bridge, 1);
if (!$vnet) { # fallback for classic bridge
PVE::Network::tap_plug($iface, $bridge, $tag, $firewall, $trunks, $rate);
return;
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index d5ee56b..2191008 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -79,7 +79,7 @@ sub generate_sdn_config {
@iface_config = ();
my $address = {};
- my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
+ 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;
diff --git a/PVE/Network/SDN/Zones/SimplePlugin.pm b/PVE/Network/SDN/Zones/SimplePlugin.pm
index c58ae87..c0ab1fe 100644
--- a/PVE/Network/SDN/Zones/SimplePlugin.pm
+++ b/PVE/Network/SDN/Zones/SimplePlugin.pm
@@ -36,7 +36,7 @@ sub generate_sdn_config {
my @iface_config = ();
my $address = {};
- my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
+ 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;
diff --git a/test/generateconfig.pl b/test/generateconfig.pl
index 92108ec..250db43 100644
--- a/test/generateconfig.pl
+++ b/test/generateconfig.pl
@@ -8,6 +8,7 @@ use PVE::Network::SDN::Zones;
use PVE::Network::SDN::Controllers;
use Data::Dumper;
+PVE::Network::SDN::commit_config();
my $network_config = PVE::Network::SDN::Zones::generate_etc_network_config();
PVE::Network::SDN::Zones::write_etc_network_config($network_config);
@@ -16,6 +17,7 @@ print $network_config;
print "\n";
my $controller_config = PVE::Network::SDN::Controllers::generate_controller_config();
+
if ($controller_config) {
print Dumper($controller_config);
PVE::Network::SDN::Controllers::write_controller_config($controller_config);
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 26/38] api: add running/pending zones/vnets/subnets/controllers
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (24 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 25/38] generate sdn/.running-config on apply Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 27/38] small bugfixes Alexandre Derumier
` (12 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN/Controllers.pm | 53 +++++++++++++++++++++---
PVE/API2/Network/SDN/Subnets.pm | 45 ++++++++++++++++++++-
PVE/API2/Network/SDN/Vnets.pm | 62 +++++++++++++++++++++++++++--
PVE/API2/Network/SDN/Zones.pm | 54 +++++++++++++++++++++++--
PVE/Network/SDN.pm | 45 +++++++++++++++++++++
5 files changed, 245 insertions(+), 14 deletions(-)
diff --git a/PVE/API2/Network/SDN/Controllers.pm b/PVE/API2/Network/SDN/Controllers.pm
index 919d343..75beb6b 100644
--- a/PVE/API2/Network/SDN/Controllers.pm
+++ b/PVE/API2/Network/SDN/Controllers.pm
@@ -51,15 +51,27 @@ __PACKAGE__->register_method ({
enum => $sdn_controllers_type_enum,
optional => 1,
},
+ running => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display running config.",
+ },
+ pending => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display pending config.",
+ },
},
},
returns => {
type => 'array',
items => {
type => "object",
- properties => { controller => { type => 'string'},
- type => { type => 'string'},
- },
+ properties => { controller => { type => 'string' },
+ type => { type => 'string' },
+ state => { type => 'string', optional => 1 },
+ pending => { optional => 1},
+ },
},
links => [ { rel => 'child', href => "{controller}" } ],
},
@@ -69,8 +81,17 @@ __PACKAGE__->register_method ({
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
-
- my $cfg = PVE::Network::SDN::Controllers::config();
+ my $cfg = {};
+ if($param->{pending}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ my $config = PVE::Network::SDN::Controllers::config();
+ $cfg = PVE::Network::SDN::pending_config($running_cfg, $config, 'controllers');
+ } elsif ($param->{running}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ $cfg = $running_cfg->{controllers};
+ } else {
+ $cfg = PVE::Network::SDN::Controllers::config();
+ }
my @sids = PVE::Network::SDN::Controllers::sdn_controllers_ids($cfg);
my $res = [];
@@ -102,13 +123,33 @@ __PACKAGE__->register_method ({
additionalProperties => 0,
properties => {
controller => get_standard_option('pve-sdn-controller-id'),
+ running => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display running config.",
+ },
+ pending => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display pending config.",
+ },
},
},
returns => { type => 'object' },
code => sub {
my ($param) = @_;
- my $cfg = PVE::Network::SDN::Controllers::config();
+ my $cfg = {};
+ if($param->{pending}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ my $config = PVE::Network::SDN::Controllers::config();
+ $cfg = PVE::Network::SDN::pending_config($running_cfg, $config, 'controllers');
+ } elsif ($param->{running}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ $cfg = $running_cfg->{controllers};
+ } else {
+ $cfg = PVE::Network::SDN::Controllers::config();
+ }
return &$api_sdn_controllers_config($cfg, $param->{controller});
}});
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index 2dd80a3..34fb714 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -46,6 +46,16 @@ __PACKAGE__->register_method ({
additionalProperties => 0,
properties => {
vnet => get_standard_option('pve-sdn-vnet-id'),
+ running => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display running config.",
+ },
+ pending => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display pending config.",
+ },
},
},
@@ -65,7 +75,17 @@ __PACKAGE__->register_method ({
my $vnetid = $param->{vnet};
- my $cfg = PVE::Network::SDN::Subnets::config();
+ my $cfg = {};
+ if($param->{pending}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ my $config = PVE::Network::SDN::Subnets::config();
+ $cfg = PVE::Network::SDN::pending_config($running_cfg, $config, 'subnets');
+ } elsif ($param->{running}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ $cfg = $running_cfg->{subnets};
+ } else {
+ $cfg = PVE::Network::SDN::Subnets::config();
+ }
my @sids = PVE::Network::SDN::Subnets::sdn_subnets_ids($cfg);
my $res = [];
@@ -97,13 +117,34 @@ __PACKAGE__->register_method ({
subnet => get_standard_option('pve-sdn-subnet-id', {
completion => \&PVE::Network::SDN::Subnets::complete_sdn_subnets,
}),
+ running => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display running config.",
+ },
+ pending => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display pending config.",
+ },
},
},
returns => { type => 'object' },
code => sub {
my ($param) = @_;
- my $cfg = PVE::Network::SDN::Subnets::config();
+ my $cfg = {};
+ if($param->{pending}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ my $config = PVE::Network::SDN::Subnets::config();
+ $cfg = PVE::Network::SDN::pending_config($running_cfg, $config, 'subnets');
+ } elsif ($param->{running}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ $cfg = $running_cfg->{subnets};
+ } else {
+ $cfg = PVE::Network::SDN::Subnets::config();
+ }
+
my $scfg = &$api_sdn_subnets_config($cfg, $param->{subnet});
raise_param_exc({ vnet => "wrong vnet"}) if $param->{vnet} ne $scfg->{vnet};
diff --git a/PVE/API2/Network/SDN/Vnets.pm b/PVE/API2/Network/SDN/Vnets.pm
index 0fbb747..6ff61c5 100644
--- a/PVE/API2/Network/SDN/Vnets.pm
+++ b/PVE/API2/Network/SDN/Vnets.pm
@@ -3,6 +3,8 @@ package PVE::API2::Network::SDN::Vnets;
use strict;
use warnings;
+use Hash::Diff qw( diff );
+
use PVE::SafeSyslog;
use PVE::Tools qw(extract_param);
use PVE::Cluster qw(cfs_read_file cfs_write_file);
@@ -33,10 +35,22 @@ my $api_sdn_vnets_config = sub {
my $scfg = dclone(PVE::Network::SDN::Vnets::sdn_vnets_config($cfg, $id));
$scfg->{vnet} = $id;
$scfg->{digest} = $cfg->{digest};
-
+
return $scfg;
};
+my $api_sdn_vnets_deleted_config = sub {
+ my ($cfg, $running_cfg, $id) = @_;
+
+ if (!$cfg->{ids}->{$id}) {
+
+ my $vnet_cfg = dclone(PVE::Network::SDN::Vnets::sdn_vnets_config($running_cfg->{vnets}, $id));
+ $vnet_cfg->{state} = "deleted";
+ $vnet_cfg->{vnet} = $id;
+ return $vnet_cfg;
+ }
+};
+
__PACKAGE__->register_method ({
name => 'index',
path => '',
@@ -49,6 +63,18 @@ __PACKAGE__->register_method ({
},
parameters => {
additionalProperties => 0,
+ properties => {
+ running => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display running config.",
+ },
+ pending => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display pending config.",
+ },
+ },
},
returns => {
type => 'array',
@@ -64,7 +90,17 @@ __PACKAGE__->register_method ({
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
- my $cfg = PVE::Network::SDN::Vnets::config();
+ my $cfg = {};
+ if($param->{pending}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ my $config = PVE::Network::SDN::Vnets::config();
+ $cfg = PVE::Network::SDN::pending_config($running_cfg, $config, 'vnets');
+ } elsif ($param->{running}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ $cfg = $running_cfg->{vnets};
+ } else {
+ $cfg = PVE::Network::SDN::Vnets::config();
+ }
my @sids = PVE::Network::SDN::Vnets::sdn_vnets_ids($cfg);
my $res = [];
@@ -93,13 +129,33 @@ __PACKAGE__->register_method ({
vnet => get_standard_option('pve-sdn-vnet-id', {
completion => \&PVE::Network::SDN::Vnets::complete_sdn_vnets,
}),
+ running => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display running config.",
+ },
+ pending => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display pending config.",
+ },
},
},
returns => { type => 'object' },
code => sub {
my ($param) = @_;
- my $cfg = PVE::Network::SDN::Vnets::config();
+ my $cfg = {};
+ if($param->{pending}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ my $config = PVE::Network::SDN::Vnets::config();
+ $cfg = PVE::Network::SDN::pending_config($running_cfg, $config, 'vnets');
+ } elsif ($param->{running}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ $cfg = $running_cfg->{vnets};
+ } else {
+ $cfg = PVE::Network::SDN::Vnets::config();
+ }
return $api_sdn_vnets_config->($cfg, $param->{vnet});
}});
diff --git a/PVE/API2/Network/SDN/Zones.pm b/PVE/API2/Network/SDN/Zones.pm
index a37df3d..512945c 100644
--- a/PVE/API2/Network/SDN/Zones.pm
+++ b/PVE/API2/Network/SDN/Zones.pm
@@ -38,6 +38,11 @@ my $api_sdn_zones_config = sub {
$scfg->{nodes} = PVE::Network::SDN::Zones::Plugin->encode_value($scfg->{type}, 'nodes', $scfg->{nodes});
}
+ my $pending = $scfg->{pending};
+ if ($pending->{nodes}) {
+ $pending->{nodes} = PVE::Network::SDN::Zones::Plugin->encode_value($scfg->{type}, 'nodes', $pending->{nodes});
+ }
+
return $scfg;
};
@@ -59,6 +64,16 @@ __PACKAGE__->register_method ({
enum => $sdn_zones_type_enum,
optional => 1,
},
+ running => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display running config.",
+ },
+ pending => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display pending config.",
+ },
},
},
returns => {
@@ -67,6 +82,10 @@ __PACKAGE__->register_method ({
type => "object",
properties => { zone => { type => 'string'},
type => { type => 'string'},
+ mtu => { type => 'integer', optional => 1 },
+ pending => { optional => 1},
+ state => { type => 'string', optional => 1},
+ nodes => { type => 'string', optional => 1},
},
},
links => [ { rel => 'child', href => "{zone}" } ],
@@ -77,8 +96,17 @@ __PACKAGE__->register_method ({
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
-
- my $cfg = PVE::Network::SDN::Zones::config();
+ my $cfg = {};
+ if($param->{pending}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ my $config = PVE::Network::SDN::Zones::config();
+ $cfg = PVE::Network::SDN::pending_config($running_cfg, $config, 'zones');
+ } elsif ($param->{running}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ $cfg = $running_cfg->{zones};
+ } else {
+ $cfg = PVE::Network::SDN::Zones::config();
+ }
my @sids = PVE::Network::SDN::Zones::sdn_zones_ids($cfg);
my $res = [];
@@ -110,13 +138,33 @@ __PACKAGE__->register_method ({
additionalProperties => 0,
properties => {
zone => get_standard_option('pve-sdn-zone-id'),
+ running => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display running config.",
+ },
+ pending => {
+ type => 'boolean',
+ optional => 1,
+ description => "Display pending config.",
+ }
},
},
returns => { type => 'object' },
code => sub {
my ($param) = @_;
- my $cfg = PVE::Network::SDN::Zones::config();
+ my $cfg = {};
+ if($param->{pending}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ my $config = PVE::Network::SDN::Zones::config();
+ $cfg = PVE::Network::SDN::pending_config($running_cfg, $config, 'zones');
+ } elsif ($param->{running}) {
+ my $running_cfg = PVE::Network::SDN::config();
+ $cfg = $running_cfg->{zones};
+ } else {
+ $cfg = PVE::Network::SDN::Zones::config();
+ }
return &$api_sdn_zones_config($cfg, $param->{zone});
}});
diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm
index f21de15..3cd73ff 100644
--- a/PVE/Network/SDN.pm
+++ b/PVE/Network/SDN.pm
@@ -81,6 +81,51 @@ sub config {
return cfs_read_file($running_cfg);
}
+sub pending_config {
+ my ($running_cfg, $cfg, $type) = @_;
+
+ my $pending = {};
+
+ my $running_objects = $running_cfg->{$type}->{ids};
+ my $config_objects = $cfg->{ids};
+
+ foreach my $id (sort keys %{$running_objects}) {
+ my $running_object = $running_objects->{$id};
+ my $config_object = $config_objects->{$id};
+ foreach my $key (sort keys %{$running_object}) {
+ $pending->{$id}->{$key} = $running_object->{$key};
+ if(!keys %{$config_object}) {
+ $pending->{$id}->{state} = "deleted";
+ } elsif ($running_object->{$key} ne $config_object->{$key}) {
+ $pending->{$id}->{state} = "changed";
+ }
+ }
+ }
+
+ foreach my $id (sort keys %{$config_objects}) {
+ my $running_object = $running_objects->{$id};
+ my $config_object = $config_objects->{$id};
+
+ foreach my $key (sort keys %{$config_object}) {
+ my $config_value = $config_object->{$key} if $config_object->{$key};
+ my $running_value = $running_object->{$key} if $running_object->{$key};
+ if($key eq 'type' || $key eq 'vnet') {
+ $pending->{$id}->{$key} = $config_value;
+ } else {
+ $pending->{$id}->{"pending"}->{$key} = $config_value if !defined($running_value) || ($config_value ne $running_value);
+ }
+ if(!keys %{$running_object}) {
+ $pending->{$id}->{state} = "new";
+ } elsif (!defined($running_value) && defined($config_value)) {
+ $pending->{$id}->{state} = "changed";
+ }
+ }
+ }
+
+ return {ids => $pending};
+
+}
+
sub commit_config {
my $cfg = cfs_read_file($running_cfg);
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 27/38] small bugfixes
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (25 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 26/38] api: add running/pending zones/vnets/subnets/controllers Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 28/38] move dns options from subnets to zone Alexandre Derumier
` (11 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN/Dns.pm | 2 +-
PVE/Network/SDN/Controllers.pm | 2 +-
PVE/Network/SDN/Ipams/PVEPlugin.pm | 6 +++---
PVE/Network/SDN/Subnets.pm | 4 ++--
PVE/Network/SDN/Vnets.pm | 2 +-
PVE/Network/SDN/Zones.pm | 2 +-
6 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/PVE/API2/Network/SDN/Dns.pm b/PVE/API2/Network/SDN/Dns.pm
index ea26af3..3d08552 100644
--- a/PVE/API2/Network/SDN/Dns.pm
+++ b/PVE/API2/Network/SDN/Dns.pm
@@ -147,7 +147,7 @@ __PACKAGE__->register_method ({
$dns_cfg->{ids}->{$id} = $opts;
- my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($scfg->{type});
+ my $plugin = PVE::Network::SDN::Dns::Plugin->lookup($opts->{type});
$plugin->on_update_hook($opts);
PVE::Network::SDN::Dns::write_config($dns_cfg);
diff --git a/PVE/Network/SDN/Controllers.pm b/PVE/Network/SDN/Controllers.pm
index c210516..f652d7f 100644
--- a/PVE/Network/SDN/Controllers.pm
+++ b/PVE/Network/SDN/Controllers.pm
@@ -55,7 +55,7 @@ sub lock_sdn_controllers_config {
sub sdn_controllers_ids {
my ($cfg) = @_;
- return keys %{$cfg->{ids}};
+ return sort keys %{$cfg->{ids}};
}
sub complete_sdn_controller {
diff --git a/PVE/Network/SDN/Ipams/PVEPlugin.pm b/PVE/Network/SDN/Ipams/PVEPlugin.pm
index 741a680..a3ad3d6 100644
--- a/PVE/Network/SDN/Ipams/PVEPlugin.pm
+++ b/PVE/Network/SDN/Ipams/PVEPlugin.pm
@@ -56,7 +56,7 @@ sub del_subnet {
my $db = read_db();
my $ips = $db->{subnets}->{$cidr}->{ips};
- die "can't delete subnet, not empty" if keys %{$ips} > 0;
+ die "can't delete subnet $cidr , not empty" if keys %{$ips} > 0;
delete $db->{subnets}->{$cidr};
write_db($db);
});
@@ -74,7 +74,7 @@ sub add_ip {
my $db = read_db();
my $s = $db->{subnets}->{$cidr};
- die "ip already exist" if defined($s->{ips}->{$ip});
+ die "ip $ip already exist" if defined($s->{ips}->{$ip});
#verify that ip is valid for this subnet
$s->{ips}->{$ip} = 1;
@@ -127,7 +127,7 @@ sub del_ip {
my $s = $db->{subnets}->{$cidr};
return if !$ip;
- die "ip does not exist in pam" if !defined($s->{ips}->{$ip});
+ die "ip $ip does not exist in pam" if !defined($s->{ips}->{$ip});
delete $s->{ips}->{$ip};
write_db($db);
});
diff --git a/PVE/Network/SDN/Subnets.pm b/PVE/Network/SDN/Subnets.pm
index 5b99c91..0f14f6f 100644
--- a/PVE/Network/SDN/Subnets.pm
+++ b/PVE/Network/SDN/Subnets.pm
@@ -37,7 +37,7 @@ sub write_config {
sub sdn_subnets_ids {
my ($cfg) = @_;
- return keys %{$cfg->{ids}};
+ return sort keys %{$cfg->{ids}};
}
sub complete_sdn_subnet {
@@ -191,7 +191,7 @@ sub next_free_ip {
sub add_ip {
my ($subnetid, $subnet, $ip, $hostname) = @_;
- return if !$subnet;
+ return if !$subnet || !$ip;
my $ipamid = $subnet->{ipam};
my $dns = $subnet->{dns};
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index d45ef2a..96aa422 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -35,7 +35,7 @@ sub write_config {
sub sdn_vnets_ids {
my ($cfg) = @_;
- return keys %{$cfg->{ids}};
+ return sort keys %{$cfg->{ids}};
}
sub complete_sdn_vnet {
diff --git a/PVE/Network/SDN/Zones.pm b/PVE/Network/SDN/Zones.pm
index 75f3233..cef4dd2 100644
--- a/PVE/Network/SDN/Zones.pm
+++ b/PVE/Network/SDN/Zones.pm
@@ -61,7 +61,7 @@ sub write_config {
sub sdn_zones_ids {
my ($cfg) = @_;
- return keys %{$cfg->{ids}};
+ return sort keys %{$cfg->{ids}};
}
sub complete_sdn_zone {
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 28/38] move dns options from subnets to zone
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (26 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 27/38] small bugfixes Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 29/38] move ipam option from subnet " Alexandre Derumier
` (10 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN/Subnets.pm | 17 +++++++-
PVE/API2/Network/SDN/Zones.pm | 21 ++++++++++
PVE/Network/SDN/Dns/Plugin.pm | 1 +
PVE/Network/SDN/Dns/PowerdnsPlugin.pm | 58 ++++++++++++++++++++++++++-
PVE/Network/SDN/SubnetPlugin.pm | 41 ++++---------------
PVE/Network/SDN/Subnets.pm | 43 ++++++++++++--------
PVE/Network/SDN/VnetPlugin.pm | 5 +++
PVE/Network/SDN/Vnets.pm | 17 ++++++--
PVE/Network/SDN/Zones.pm | 16 ++++++++
PVE/Network/SDN/Zones/EvpnPlugin.pm | 3 ++
PVE/Network/SDN/Zones/FaucetPlugin.pm | 3 ++
PVE/Network/SDN/Zones/QinQPlugin.pm | 3 ++
PVE/Network/SDN/Zones/SimplePlugin.pm | 22 +++++++++-
PVE/Network/SDN/Zones/VlanPlugin.pm | 5 ++-
PVE/Network/SDN/Zones/VxlanPlugin.pm | 3 ++
15 files changed, 199 insertions(+), 59 deletions(-)
diff --git a/PVE/API2/Network/SDN/Subnets.pm b/PVE/API2/Network/SDN/Subnets.pm
index 34fb714..5ea4fc4 100644
--- a/PVE/API2/Network/SDN/Subnets.pm
+++ b/PVE/API2/Network/SDN/Subnets.pm
@@ -11,6 +11,7 @@ use PVE::Network::SDN;
use PVE::Network::SDN::Subnets;
use PVE::Network::SDN::SubnetPlugin;
use PVE::Network::SDN::Vnets;
+use PVE::Network::SDN::Zones;
use PVE::Network::SDN::Ipams;
use PVE::Network::SDN::Ipams::Plugin;
@@ -178,6 +179,12 @@ __PACKAGE__->register_method ({
sub {
my $cfg = PVE::Network::SDN::Subnets::config();
+ my $zone_cfg = PVE::Network::SDN::Zones::config();
+ my $vnet_cfg = PVE::Network::SDN::Vnets::config();
+ my $vnet = $param->{vnet};
+ my $zoneid = $vnet_cfg->{ids}->{$vnet}->{zone};
+ my $zone = $zone_cfg->{ids}->{$zoneid};
+
my $opts = PVE::Network::SDN::SubnetPlugin->check_config($id, $param, 1, 1);
my $scfg = undef;
@@ -186,7 +193,7 @@ __PACKAGE__->register_method ({
}
$cfg->{ids}->{$id} = $opts;
- PVE::Network::SDN::SubnetPlugin->on_update_hook($id, $opts);
+ PVE::Network::SDN::SubnetPlugin->on_update_hook($zone, $id, $opts);
PVE::Network::SDN::Subnets::write_config($cfg);
@@ -216,6 +223,12 @@ __PACKAGE__->register_method ({
sub {
my $cfg = PVE::Network::SDN::Subnets::config();
+ my $zone_cfg = PVE::Network::SDN::Zones::config();
+ my $vnet_cfg = PVE::Network::SDN::Vnets::config();
+ my $vnet = $param->{vnet};
+ my $zoneid = $vnet_cfg->{ids}->{$vnet}->{zone};
+ my $zone = $zone_cfg->{ids}->{$zoneid};
+
my $scfg = &$api_sdn_subnets_config($cfg, $id);
PVE::SectionConfig::assert_if_modified($cfg, $digest);
@@ -225,7 +238,7 @@ __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($id, $opts, $scfg);
+ PVE::Network::SDN::SubnetPlugin->on_update_hook($zone, $id, $opts, $scfg);
PVE::Network::SDN::Subnets::write_config($cfg);
diff --git a/PVE/API2/Network/SDN/Zones.pm b/PVE/API2/Network/SDN/Zones.pm
index 512945c..cbfa9fe 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::Dns;
use PVE::Network::SDN::Zones::Plugin;
use PVE::Network::SDN::Zones::VlanPlugin;
use PVE::Network::SDN::Zones::QinQPlugin;
@@ -20,6 +21,7 @@ use PVE::Network::SDN::Zones::SimplePlugin;
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;
@@ -83,6 +85,9 @@ __PACKAGE__->register_method ({
properties => { zone => { type => 'string'},
type => { type => 'string'},
mtu => { type => 'integer', optional => 1 },
+ dns => { type => 'string', optional => 1},
+ reversedns => { type => 'string', optional => 1},
+ dnszone => { type => 'string', optional => 1},
pending => { optional => 1},
state => { type => 'string', optional => 1},
nodes => { type => 'string', optional => 1},
@@ -198,11 +203,19 @@ __PACKAGE__->register_method ({
my $zone_cfg = PVE::Network::SDN::Zones::config();
my $controller_cfg = PVE::Network::SDN::Controllers::config();
+ my $dns_cfg = PVE::Network::SDN::Dns::config();
my $scfg = undef;
if ($scfg = PVE::Network::SDN::Zones::sdn_zones_config($zone_cfg, $id, 1)) {
die "sdn zone object ID '$id' already defined\n";
}
+
+ my $dnsserver = $opts->{dns};
+ my $reversednsserver = $opts->{reversedns};
+ my $dnszone = $opts->{dnszone};
+ raise_param_exc({ dns => "$dnsserver don't exist"}) if $dnsserver && !$dns_cfg->{ids}->{$dnsserver};
+ raise_param_exc({ reversedns => "$reversednsserver don't exist"}) if $reversednsserver && !$dns_cfg->{ids}->{$reversednsserver};
+ raise_param_exc({ dnszone => "missing dns server"}) if $dnszone && !$dnsserver;
$zone_cfg->{ids}->{$id} = $opts;
$plugin->on_update_hook($id, $zone_cfg, $controller_cfg);
@@ -236,6 +249,7 @@ __PACKAGE__->register_method ({
my $zone_cfg = PVE::Network::SDN::Zones::config();
my $controller_cfg = PVE::Network::SDN::Controllers::config();
+ my $dns_cfg = PVE::Network::SDN::Dns::config();
PVE::SectionConfig::assert_if_modified($zone_cfg, $digest);
@@ -248,6 +262,13 @@ __PACKAGE__->register_method ({
$scfg->{$k} = $opts->{$k};
}
+ my $dnsserver = $opts->{dns};
+ my $reversednsserver = $opts->{reversedns};
+ my $dnszone = $opts->{dnszone};
+ raise_param_exc({ dns => "$dnsserver don't exist"}) if $dnsserver && !$dns_cfg->{ids}->{$dnsserver};
+ raise_param_exc({ reversedns => "$reversednsserver don't exist"}) if $reversednsserver && !$dns_cfg->{ids}->{$reversednsserver};
+ raise_param_exc({ dnszone => "missing dns server"}) if $dnszone && !$dnsserver;
+
$plugin->on_update_hook($id, $zone_cfg, $controller_cfg);
PVE::Network::SDN::Zones::write_config($zone_cfg);
diff --git a/PVE/Network/SDN/Dns/Plugin.pm b/PVE/Network/SDN/Dns/Plugin.pm
index baa9316..be399b0 100644
--- a/PVE/Network/SDN/Dns/Plugin.pm
+++ b/PVE/Network/SDN/Dns/Plugin.pm
@@ -42,6 +42,7 @@ my $defaultData = {
type => 'string', format => 'pve-configid',
},
ttl => { type => 'integer', optional => 1 },
+ reversev6mask => { type => 'integer', optional => 1 },
dns => get_standard_option('pve-sdn-dns-id',
{ completion => \&PVE::Network::SDN::Dns::complete_sdn_dns }),
},
diff --git a/PVE/Network/SDN/Dns/PowerdnsPlugin.pm b/PVE/Network/SDN/Dns/PowerdnsPlugin.pm
index f02c2f1..5b98e87 100644
--- a/PVE/Network/SDN/Dns/PowerdnsPlugin.pm
+++ b/PVE/Network/SDN/Dns/PowerdnsPlugin.pm
@@ -7,6 +7,7 @@ use PVE::Cluster;
use PVE::Tools;
use JSON;
use Net::IP;
+use NetAddr::IP;
use base('PVE::Network::SDN::Dns::Plugin');
@@ -22,6 +23,9 @@ sub properties {
key => {
type => 'string',
},
+ reversemaskv6 => {
+ type => 'integer'
+ },
};
}
@@ -31,6 +35,8 @@ sub options {
url => { optional => 0},
key => { optional => 0 },
ttl => { optional => 1 },
+ reversemaskv6 => { optional => 1, description => "force a different netmask for the ipv6 reverse zone name." },
+
};
}
@@ -81,7 +87,8 @@ sub add_ptr_record {
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
$hostname .= ".";
- my $reverseip = join(".", reverse(split(/\./, $ip))).".in-addr.arpa.";
+ my $reverseip = Net::IP->new($ip)->reverse_ip();
+
my $type = "PTR";
my $record = { content => $hostname,
@@ -140,7 +147,8 @@ sub del_ptr_record {
my $key = $plugin_config->{key};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
- my $reverseip = join(".", reverse(split(/\./, $ip))).".in-addr.arpa.";
+ my $reverseip = Net::IP->new($ip)->reverse_ip();
+
my $type = "PTR";
my $rrset = { name => $reverseip,
@@ -177,6 +185,52 @@ sub verify_zone {
}
}
+sub get_reversedns_zone {
+ my ($class, $plugin_config, $subnetid, $ip) = @_;
+
+ my ($network, $mask) = split(/-/, $subnetid);
+
+ my $cidr = "$ip/$mask";
+ my $zone = "";
+
+ if (Net::IP::ip_is_ipv4($ip)) {
+ my ($ipblock1, $ipblock2, $ipblock3, $ipblock4) = split(/\./, $ip);
+
+ my $ipv4 = new NetAddr::IP($cidr);
+ #private addresse #powerdns built-in private zone : serve-rfc1918
+ if($ipv4->is_rfc1918()) {
+ if ($ipblock1 == 192) {
+ $zone = "168.192.in-addr.arpa.";
+ } elsif ($ipblock1 == 172) {
+ $zone = "16-31.172.in-addr.arpa.";
+ } elsif ($ipblock1 == 10) {
+ $zone = "10.in-addr.arpa.";
+ }
+
+ } else {
+ #public ipv4 : RIPE,ARIN,AFRNIC
+ #. Delegations can be managed in IPv4 on bit boundaries (/8, /16 or /24s), and IPv6 networks can be managed on nibble boundaries (every 4 bits of the IPv6 address)
+ #One or more /24 type zones need to be created if your address space has a prefix length between /17 and /24.
+ # If your prefix length is between /16 and /9 you will have to request one or more delegations for /16 type zones.
+
+ if ($mask <= 24) {
+ $zone = "$ipblock3.$ipblock2.$ipblock1.in-addr.arpa.";
+ } elsif ($mask <= 16) {
+ $zone = "$ipblock2.$ipblock1.in-addr.arpa.";
+ } elsif ($mask <= 8) {
+ $zone = "$ipblock1.in-addr.arpa.";
+ }
+ }
+ } else {
+ $mask = $plugin_config->{reversemaskv6} if $plugin_config->{reversemaskv6};
+ die "reverse dns zone mask need to be a multiple of 4" if ($mask % 4);
+ my $networkv6 = NetAddr::IP->new($cidr)->network();
+ $zone = Net::IP->new($networkv6)->reverse_ip();
+ }
+
+ return $zone;
+}
+
sub on_update_hook {
my ($class, $plugin_config) = @_;
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index 8a216b6..f57a5e9 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -71,22 +71,6 @@ sub properties {
# type => 'string',
# description => "static routes [network=<network>:gateway=<ip>,network=<network>:gateway=<ip>,... ]",
# },
- dns => {
- type => 'string',
- description => "dns api server",
- },
- reversedns => {
- type => 'string',
- description => "reverse dns api server",
- },
- dnszone => {
- type => 'string', format => 'dns-name',
- description => "dns domain zone ex: mydomain.com",
- },
- reversednszone => {
- type => 'string', format => 'dns-name',
- description => "reverse dns zone ex: 0.168.192.in-addr.arpa",
- },
dnszoneprefix => {
type => 'string', format => 'dns-name',
description => "dns domain zone prefix ex: 'adm' -> <hostname>.adm.mydomain.com",
@@ -104,17 +88,13 @@ sub options {
gateway => { optional => 1 },
# routes => { optional => 1 },
snat => { optional => 1 },
- dns => { optional => 1 },
- reversedns => { optional => 1 },
- dnszone => { optional => 1 },
- reversednszone => { optional => 1 },
dnszoneprefix => { optional => 1 },
ipam => { optional => 0 },
};
}
sub on_update_hook {
- my ($class, $subnetid, $subnet, $old_subnet) = @_;
+ my ($class, $zone, $subnetid, $subnet, $old_subnet) = @_;
my $cidr = $subnetid =~ s/-/\//r;
my $subnet_matcher = subnet_matcher($cidr);
@@ -122,10 +102,9 @@ sub on_update_hook {
my $vnetid = $subnet->{vnet};
my $gateway = $subnet->{gateway};
my $ipam = $subnet->{ipam};
- my $dns = $subnet->{dns};
- my $dnszone = $subnet->{dnszone};
- my $reversedns = $subnet->{reversedns};
- my $reversednszone = $subnet->{reversednszone};
+ my $dns = $zone->{dns};
+ my $dnszone = $zone->{dnszone};
+ my $reversedns = $zone->{reversedns};
my $old_gateway = $old_subnet->{gateway} if $old_subnet;
@@ -139,12 +118,6 @@ sub on_update_hook {
#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({ dns => "missing dns provider"}) if $dnszone && !$dns;
- raise_param_exc({ dnszone => "missing dns zone"}) if $dns && !$dnszone;
- raise_param_exc({ reversedns => "missing dns provider"}) if $reversednszone && !$reversedns;
- raise_param_exc({ reversednszone => "missing dns zone"}) if $reversedns && !$reversednszone;
- raise_param_exc({ reversedns => "missing forward dns zone"}) if $reversednszone && !$dnszone;
-
if ($ipam) {
my $ipam_cfg = PVE::Network::SDN::Ipams::config();
my $plugin_config = $ipam_cfg->{ids}->{$ipam};
@@ -155,18 +128,18 @@ sub on_update_hook {
#delete on removal
if (!defined($gateway) && $old_gateway) {
eval {
- PVE::Network::SDN::Subnets::del_ip($subnetid, $old_subnet, $old_gateway);
+ PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $old_subnet, $old_gateway);
};
warn if $@;
}
if(!$old_gateway || $gateway && $gateway ne $old_gateway) {
- PVE::Network::SDN::Subnets::add_ip($subnetid, $subnet, $gateway);
+ PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $gateway);
}
#delete old ip after update
if($gateway && $old_gateway && $gateway ne $old_gateway) {
eval {
- PVE::Network::SDN::Subnets::del_ip($subnetid, $old_subnet, $old_gateway);
+ PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $old_subnet, $old_gateway);
};
warn if $@;
}
diff --git a/PVE/Network/SDN/Subnets.pm b/PVE/Network/SDN/Subnets.pm
index 0f14f6f..aa7c6c1 100644
--- a/PVE/Network/SDN/Subnets.pm
+++ b/PVE/Network/SDN/Subnets.pm
@@ -93,6 +93,17 @@ my $verify_dns_zone = sub {
$plugin->verify_zone($plugin_config, $zone);
};
+my $get_reversedns_zone = sub {
+ my ($subnetid, $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);
+};
+
my $add_dns_record = sub {
my ($zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
return if !$zone || !$dns || !$hostname || !$ip;
@@ -144,21 +155,19 @@ my $del_dns_ptr_record = sub {
};
sub next_free_ip {
- my ($subnetid, $subnet, $hostname) = @_;
+ my ($zone, $subnetid, $subnet, $hostname) = @_;
my $cidr = undef;
my $ip = undef;
my $ipamid = $subnet->{ipam};
- my $dns = $subnet->{dns};
- my $dnszone = $subnet->{dnszone};
- my $reversedns = $subnet->{reversedns};
- my $reversednszone = $subnet->{reversednszone};
+ my $dns = $zone->{dns};
+ my $dnszone = $zone->{dnszone};
+ my $reversedns = $zone->{reversedns};
my $dnszoneprefix = $subnet->{dnszoneprefix};
#verify dns zones before ipam
&$verify_dns_zone($dnszone, $dns);
- &$verify_dns_zone($reversednszone, $reversedns);
if($ipamid) {
my $ipam_cfg = PVE::Network::SDN::Ipams::config();
@@ -172,6 +181,8 @@ sub next_free_ip {
}
eval {
+ my $reversednszone = &$get_reversedns_zone($subnetid, $reversedns, $ip);
+
#add dns
&$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
#add reverse dns
@@ -189,15 +200,15 @@ sub next_free_ip {
}
sub add_ip {
- my ($subnetid, $subnet, $ip, $hostname) = @_;
+ my ($zone, $subnetid, $subnet, $ip, $hostname) = @_;
return if !$subnet || !$ip;
my $ipamid = $subnet->{ipam};
- my $dns = $subnet->{dns};
- my $dnszone = $subnet->{dnszone};
- my $reversedns = $subnet->{reversedns};
- my $reversednszone = $subnet->{reversednszone};
+ my $dns = $zone->{dns};
+ my $dnszone = $zone->{dnszone};
+ my $reversedns = $zone->{reversedns};
+ my $reversednszone = &$get_reversedns_zone($subnetid, $reversedns, $ip);
my $dnszoneprefix = $subnet->{dnszoneprefix};
#verify dns zones before ipam
@@ -231,15 +242,15 @@ sub add_ip {
}
sub del_ip {
- my ($subnetid, $subnet, $ip, $hostname) = @_;
+ my ($zone, $subnetid, $subnet, $ip, $hostname) = @_;
return if !$subnet;
my $ipamid = $subnet->{ipam};
- my $dns = $subnet->{dns};
- my $dnszone = $subnet->{dnszone};
- my $reversedns = $subnet->{reversedns};
- my $reversednszone = $subnet->{reversednszone};
+ my $dns = $zone->{dns};
+ my $dnszone = $zone->{dnszone};
+ my $reversedns = $zone->{reversedns};
+ my $reversednszone = &$get_reversedns_zone($subnetid, $reversedns, $ip);
my $dnszoneprefix = $subnet->{dnszoneprefix};
&$verify_dns_zone($dnszone, $dns);
diff --git a/PVE/Network/SDN/VnetPlugin.pm b/PVE/Network/SDN/VnetPlugin.pm
index 47fd4d4..8481f0d 100644
--- a/PVE/Network/SDN/VnetPlugin.pm
+++ b/PVE/Network/SDN/VnetPlugin.pm
@@ -100,6 +100,11 @@ sub on_delete_hook {
sub on_update_hook {
my ($class, $vnetid, $vnet_cfg, $subnet_cfg) = @_;
+
+ #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};
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index 96aa422..3b49ada 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -6,6 +6,7 @@ use warnings;
use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
use Net::IP;
use PVE::Network::SDN::Subnets;
+use PVE::Network::SDN::Zones;
use PVE::Network::SDN::VnetPlugin;
PVE::Network::SDN::VnetPlugin->register();
@@ -79,6 +80,10 @@ sub get_subnets {
sub get_next_free_ip {
my ($vnetid, $hostname, $ipversion) = @_;
+ my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
+ my $zoneid = $vnet->{zone};
+ my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
+
$ipversion = 4 if !$ipversion;
my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
my $ip = undef;
@@ -92,7 +97,7 @@ sub get_next_free_ip {
$subnetcount++;
if ($subnet->{ipam}) {
eval {
- $ip = PVE::Network::SDN::Subnets::next_free_ip($subnetid, $subnet, $hostname);
+ $ip = PVE::Network::SDN::Subnets::next_free_ip($zone, $subnetid, $subnet, $hostname);
};
warn $@ if $@;
}
@@ -107,22 +112,28 @@ sub add_ip {
my ($vnetid, $cidr, $hostname) = @_;
my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
+ my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
+ my $zoneid = $vnet->{zone};
+ my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
my ($ip, $mask) = split(/\//, $cidr);
my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $subnets);
- PVE::Network::SDN::Subnets::add_ip($subnetid, $subnet, $ip, $hostname);
+ PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $ip, $hostname);
}
sub del_ip {
my ($vnetid, $cidr, $hostname) = @_;
my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
+ my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
+ my $zoneid = $vnet->{zone};
+ my $zone = PVE::Network::SDN::Zones::get_zone($zoneid);
my ($ip, $mask) = split(/\//, $cidr);
my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $subnets);
- PVE::Network::SDN::Subnets::del_ip($subnetid, $subnet, $ip, $hostname);
+ PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname);
}
1;
diff --git a/PVE/Network/SDN/Zones.pm b/PVE/Network/SDN/Zones.pm
index cef4dd2..1f225dc 100644
--- a/PVE/Network/SDN/Zones.pm
+++ b/PVE/Network/SDN/Zones.pm
@@ -72,6 +72,22 @@ sub complete_sdn_zone {
return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::sdn_zones_ids($cfg) ];
}
+sub get_zone {
+ my ($zoneid, $running) = @_;
+
+ my $cfg = {};
+ if($running) {
+ my $cfg = PVE::Network::SDN::config();
+ $cfg = $cfg->{vnets};
+ } else {
+ $cfg = PVE::Network::SDN::Zones::config();
+ }
+
+ my $zone = PVE::Network::SDN::Zones::sdn_zones_config($cfg, $zoneid, 1);
+
+ return $zone;
+}
+
sub generate_etc_network_config {
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index 2191008..3cb083b 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -37,6 +37,9 @@ sub options {
'vrf-vxlan' => { optional => 0 },
'controller' => { optional => 0 },
mtu => { optional => 1 },
+ dns => { optional => 1 },
+ reversedns => { optional => 1 },
+ dnszone => { optional => 1 },
};
}
diff --git a/PVE/Network/SDN/Zones/FaucetPlugin.pm b/PVE/Network/SDN/Zones/FaucetPlugin.pm
index ef422ca..1b70a57 100644
--- a/PVE/Network/SDN/Zones/FaucetPlugin.pm
+++ b/PVE/Network/SDN/Zones/FaucetPlugin.pm
@@ -26,6 +26,9 @@ sub options {
'dp-id' => { optional => 0 },
# 'uplink-id' => { optional => 0 },
'controller' => { optional => 0 },
+ dns => { optional => 1 },
+ reversedns => { optional => 1 },
+ dnszone => { optional => 1 },
};
}
diff --git a/PVE/Network/SDN/Zones/QinQPlugin.pm b/PVE/Network/SDN/Zones/QinQPlugin.pm
index c828af4..8507ae6 100644
--- a/PVE/Network/SDN/Zones/QinQPlugin.pm
+++ b/PVE/Network/SDN/Zones/QinQPlugin.pm
@@ -40,6 +40,9 @@ sub options {
'bridge' => { optional => 0 },
'mtu' => { optional => 1 },
'vlan-protocol' => { optional => 1 },
+ dns => { optional => 1 },
+ reversedns => { optional => 1 },
+ dnszone => { optional => 1 },
};
}
diff --git a/PVE/Network/SDN/Zones/SimplePlugin.pm b/PVE/Network/SDN/Zones/SimplePlugin.pm
index c0ab1fe..58cc1af 100644
--- a/PVE/Network/SDN/Zones/SimplePlugin.pm
+++ b/PVE/Network/SDN/Zones/SimplePlugin.pm
@@ -13,10 +13,30 @@ sub type {
return 'simple';
}
+sub properties {
+ return {
+ dns => {
+ type => 'string',
+ description => "dns api server",
+ },
+ reversedns => {
+ type => 'string',
+ description => "reverse dns api server",
+ },
+ dnszone => {
+ type => 'string', format => 'dns-name',
+ description => "dns domain zone ex: mydomain.com",
+ },
+ };
+}
+
sub options {
return {
nodes => { optional => 1},
- mtu => { optional => 1 }
+ mtu => { optional => 1 },
+ dns => { optional => 1 },
+ reversedns => { optional => 1 },
+ dnszone => { optional => 1 },
};
}
diff --git a/PVE/Network/SDN/Zones/VlanPlugin.pm b/PVE/Network/SDN/Zones/VlanPlugin.pm
index 7f90d31..fd750c9 100644
--- a/PVE/Network/SDN/Zones/VlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VlanPlugin.pm
@@ -33,7 +33,10 @@ sub options {
return {
nodes => { optional => 1},
'bridge' => { optional => 0 },
- mtu => { optional => 1 }
+ mtu => { optional => 1 },
+ dns => { optional => 1 },
+ reversedns => { optional => 1 },
+ dnszone => { optional => 1 },
};
}
diff --git a/PVE/Network/SDN/Zones/VxlanPlugin.pm b/PVE/Network/SDN/Zones/VxlanPlugin.pm
index 79af054..7a6687a 100644
--- a/PVE/Network/SDN/Zones/VxlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VxlanPlugin.pm
@@ -38,6 +38,9 @@ sub options {
nodes => { optional => 1},
peers => { optional => 0 },
mtu => { optional => 1 },
+ dns => { optional => 1 },
+ reversedns => { optional => 1 },
+ dnszone => { optional => 1 },
};
}
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 29/38] move ipam option from subnet to zone
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (27 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 28/38] move dns options from subnets to zone Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 30/38] subnets/ipam: allow same subnet on different zones Alexandre Derumier
` (9 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN/Zones.pm | 9 +++++++++
PVE/Network/SDN/SubnetPlugin.pm | 8 +-------
PVE/Network/SDN/Subnets.pm | 6 +++---
PVE/Network/SDN/Vnets.pm | 2 +-
PVE/Network/SDN/Zones/EvpnPlugin.pm | 1 +
PVE/Network/SDN/Zones/FaucetPlugin.pm | 1 +
PVE/Network/SDN/Zones/Plugin.pm | 4 ++++
PVE/Network/SDN/Zones/QinQPlugin.pm | 1 +
PVE/Network/SDN/Zones/SimplePlugin.pm | 3 ++-
PVE/Network/SDN/Zones/VlanPlugin.pm | 1 +
PVE/Network/SDN/Zones/VxlanPlugin.pm | 1 +
11 files changed, 25 insertions(+), 12 deletions(-)
diff --git a/PVE/API2/Network/SDN/Zones.pm b/PVE/API2/Network/SDN/Zones.pm
index cbfa9fe..54f087d 100644
--- a/PVE/API2/Network/SDN/Zones.pm
+++ b/PVE/API2/Network/SDN/Zones.pm
@@ -88,6 +88,7 @@ __PACKAGE__->register_method ({
dns => { type => 'string', optional => 1},
reversedns => { type => 'string', optional => 1},
dnszone => { type => 'string', optional => 1},
+ ipam => { type => 'string', optional => 1},
pending => { optional => 1},
state => { type => 'string', optional => 1},
nodes => { type => 'string', optional => 1},
@@ -217,6 +218,10 @@ __PACKAGE__->register_method ({
raise_param_exc({ reversedns => "$reversednsserver don't exist"}) if $reversednsserver && !$dns_cfg->{ids}->{$reversednsserver};
raise_param_exc({ dnszone => "missing dns server"}) if $dnszone && !$dnsserver;
+ my $ipam = $opts->{ipam};
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ raise_param_exc({ ipam => "$ipam not existing"}) if $ipam && !$ipam_cfg->{ids}->{$ipam};
+
$zone_cfg->{ids}->{$id} = $opts;
$plugin->on_update_hook($id, $zone_cfg, $controller_cfg);
@@ -269,6 +274,10 @@ __PACKAGE__->register_method ({
raise_param_exc({ reversedns => "$reversednsserver don't exist"}) if $reversednsserver && !$dns_cfg->{ids}->{$reversednsserver};
raise_param_exc({ dnszone => "missing dns server"}) if $dnszone && !$dnsserver;
+ my $ipam = $opts->{ipam};
+ my $ipam_cfg = PVE::Network::SDN::Ipams::config();
+ raise_param_exc({ ipam => "$ipam not existing"}) if $ipam && !$ipam_cfg->{ids}->{$ipam};
+
$plugin->on_update_hook($id, $zone_cfg, $controller_cfg);
PVE::Network::SDN::Zones::write_config($zone_cfg);
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index f57a5e9..a5d03f6 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -75,10 +75,6 @@ sub properties {
type => 'string', format => 'dns-name',
description => "dns domain zone prefix ex: 'adm' -> <hostname>.adm.mydomain.com",
},
- ipam => {
- type => 'string',
- description => "use a specific ipam",
- },
};
}
@@ -89,7 +85,6 @@ sub options {
# routes => { optional => 1 },
snat => { optional => 1 },
dnszoneprefix => { optional => 1 },
- ipam => { optional => 0 },
};
}
@@ -101,7 +96,7 @@ sub on_update_hook {
my $vnetid = $subnet->{vnet};
my $gateway = $subnet->{gateway};
- my $ipam = $subnet->{ipam};
+ my $ipam = $zone->{ipam};
my $dns = $zone->{dns};
my $dnszone = $zone->{dnszone};
my $reversedns = $zone->{reversedns};
@@ -121,7 +116,6 @@ sub on_update_hook {
if ($ipam) {
my $ipam_cfg = PVE::Network::SDN::Ipams::config();
my $plugin_config = $ipam_cfg->{ids}->{$ipam};
- raise_param_exc({ ipam => "$ipam not existing"}) if !$plugin_config;
my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
$plugin->add_subnet($plugin_config, $subnetid, $subnet);
diff --git a/PVE/Network/SDN/Subnets.pm b/PVE/Network/SDN/Subnets.pm
index aa7c6c1..50130d5 100644
--- a/PVE/Network/SDN/Subnets.pm
+++ b/PVE/Network/SDN/Subnets.pm
@@ -160,7 +160,7 @@ sub next_free_ip {
my $cidr = undef;
my $ip = undef;
- my $ipamid = $subnet->{ipam};
+ my $ipamid = $zone->{ipam};
my $dns = $zone->{dns};
my $dnszone = $zone->{dnszone};
my $reversedns = $zone->{reversedns};
@@ -204,7 +204,7 @@ sub add_ip {
return if !$subnet || !$ip;
- my $ipamid = $subnet->{ipam};
+ my $ipamid = $zone->{ipam};
my $dns = $zone->{dns};
my $dnszone = $zone->{dnszone};
my $reversedns = $zone->{reversedns};
@@ -246,7 +246,7 @@ sub del_ip {
return if !$subnet;
- my $ipamid = $subnet->{ipam};
+ my $ipamid = $zone->{ipam};
my $dns = $zone->{dns};
my $dnszone = $zone->{dnszone};
my $reversedns = $zone->{reversedns};
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index 3b49ada..d08db51 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -95,7 +95,7 @@ sub get_next_free_ip {
next if $ipversion != Net::IP::ip_get_version($network);
$subnetcount++;
- if ($subnet->{ipam}) {
+ if ($zone->{ipam}) {
eval {
$ip = PVE::Network::SDN::Subnets::next_free_ip($zone, $subnetid, $subnet, $hostname);
};
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index 3cb083b..723b3cc 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -40,6 +40,7 @@ sub options {
dns => { optional => 1 },
reversedns => { optional => 1 },
dnszone => { optional => 1 },
+ ipam => { optional => 0 },
};
}
diff --git a/PVE/Network/SDN/Zones/FaucetPlugin.pm b/PVE/Network/SDN/Zones/FaucetPlugin.pm
index 1b70a57..a9f119c 100644
--- a/PVE/Network/SDN/Zones/FaucetPlugin.pm
+++ b/PVE/Network/SDN/Zones/FaucetPlugin.pm
@@ -29,6 +29,7 @@ sub options {
dns => { optional => 1 },
reversedns => { optional => 1 },
dnszone => { optional => 1 },
+ ipam => { optional => 0 },
};
}
diff --git a/PVE/Network/SDN/Zones/Plugin.pm b/PVE/Network/SDN/Zones/Plugin.pm
index 7f6db0e..1f24269 100644
--- a/PVE/Network/SDN/Zones/Plugin.pm
+++ b/PVE/Network/SDN/Zones/Plugin.pm
@@ -44,6 +44,10 @@ my $defaultData = {
nodes => get_standard_option('pve-node-list', { optional => 1 }),
zone => get_standard_option('pve-sdn-zone-id',
{ completion => \&PVE::Network::SDN::Zones::complete_sdn_zone }),
+ ipam => {
+ type => 'string',
+ description => "use a specific ipam",
+ },
},
};
diff --git a/PVE/Network/SDN/Zones/QinQPlugin.pm b/PVE/Network/SDN/Zones/QinQPlugin.pm
index 8507ae6..aadfd27 100644
--- a/PVE/Network/SDN/Zones/QinQPlugin.pm
+++ b/PVE/Network/SDN/Zones/QinQPlugin.pm
@@ -43,6 +43,7 @@ sub options {
dns => { optional => 1 },
reversedns => { optional => 1 },
dnszone => { optional => 1 },
+ ipam => { optional => 0 },
};
}
diff --git a/PVE/Network/SDN/Zones/SimplePlugin.pm b/PVE/Network/SDN/Zones/SimplePlugin.pm
index 58cc1af..fe0f20f 100644
--- a/PVE/Network/SDN/Zones/SimplePlugin.pm
+++ b/PVE/Network/SDN/Zones/SimplePlugin.pm
@@ -26,7 +26,7 @@ sub properties {
dnszone => {
type => 'string', format => 'dns-name',
description => "dns domain zone ex: mydomain.com",
- },
+ }
};
}
@@ -37,6 +37,7 @@ sub options {
dns => { optional => 1 },
reversedns => { optional => 1 },
dnszone => { optional => 1 },
+ ipam => { optional => 0 },
};
}
diff --git a/PVE/Network/SDN/Zones/VlanPlugin.pm b/PVE/Network/SDN/Zones/VlanPlugin.pm
index fd750c9..e1ae75b 100644
--- a/PVE/Network/SDN/Zones/VlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VlanPlugin.pm
@@ -37,6 +37,7 @@ sub options {
dns => { optional => 1 },
reversedns => { optional => 1 },
dnszone => { optional => 1 },
+ ipam => { optional => 0 },
};
}
diff --git a/PVE/Network/SDN/Zones/VxlanPlugin.pm b/PVE/Network/SDN/Zones/VxlanPlugin.pm
index 7a6687a..e8870a0 100644
--- a/PVE/Network/SDN/Zones/VxlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VxlanPlugin.pm
@@ -41,6 +41,7 @@ sub options {
dns => { optional => 1 },
reversedns => { optional => 1 },
dnszone => { optional => 1 },
+ ipam => { optional => 0 },
};
}
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 30/38] subnets/ipam: allow same subnet on different zones
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (28 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 29/38] move ipam option from subnet " Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 31/38] vnets: allow duplicate tags in differents zones Alexandre Derumier
` (8 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
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
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 31/38] vnets: allow duplicate tags in differents zones
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (29 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 30/38] subnets/ipam: allow same subnet on different zones Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 32/38] ipam: verify api access on create/update Alexandre Derumier
` (7 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
only vxlan need to be unique globally.
---
PVE/API2/Network/SDN/Vnets.pm | 4 ++--
PVE/Network/SDN/VnetPlugin.pm | 9 ---------
PVE/Network/SDN/Zones/EvpnPlugin.pm | 20 +++++++++++++++++---
PVE/Network/SDN/Zones/Plugin.pm | 2 +-
PVE/Network/SDN/Zones/QinQPlugin.pm | 14 +++++++++++++-
PVE/Network/SDN/Zones/SimplePlugin.pm | 7 +++++--
PVE/Network/SDN/Zones/VlanPlugin.pm | 14 +++++++++++++-
PVE/Network/SDN/Zones/VxlanPlugin.pm | 20 +++++++++++++++++---
8 files changed, 68 insertions(+), 22 deletions(-)
diff --git a/PVE/API2/Network/SDN/Vnets.pm b/PVE/API2/Network/SDN/Vnets.pm
index 3f99f58..84cf433 100644
--- a/PVE/API2/Network/SDN/Vnets.pm
+++ b/PVE/API2/Network/SDN/Vnets.pm
@@ -194,7 +194,7 @@ __PACKAGE__->register_method ({
my $zoneid = $cfg->{ids}->{$id}->{zone};
my $plugin_config = $zone_cfg->{ids}->{$zoneid};
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
- $plugin->vnet_update_hook($cfg->{ids}->{$id});
+ $plugin->vnet_update_hook($cfg, $id, $zone_cfg);
PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg);
@@ -239,7 +239,7 @@ __PACKAGE__->register_method ({
my $zoneid = $cfg->{ids}->{$id}->{zone};
my $plugin_config = $zone_cfg->{ids}->{$zoneid};
my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
- $plugin->vnet_update_hook($cfg->{ids}->{$id});
+ $plugin->vnet_update_hook($cfg, $id, $zone_cfg);
PVE::Network::SDN::VnetPlugin->on_update_hook($id, $cfg);
diff --git a/PVE/Network/SDN/VnetPlugin.pm b/PVE/Network/SDN/VnetPlugin.pm
index 518d2dd..cac578a 100644
--- a/PVE/Network/SDN/VnetPlugin.pm
+++ b/PVE/Network/SDN/VnetPlugin.pm
@@ -106,15 +106,6 @@ sub on_update_hook {
my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid);
raise_param_exc({ vlanaware => "vlanaware vnet is not compatible with subnets"}) if $subnets;
}
-
- # verify that tag is not already defined in another vnet
- if (defined($tag)) {
- foreach my $id (keys %{$vnet_cfg->{ids}}) {
- next if $id eq $vnetid;
- my $othervnettag = $vnet_cfg->{ids}->{$id}->{tag};
- raise_param_exc({ tag => "tag $tag already exist in vnet $id"}) if $othervnettag && $tag eq $othervnettag;
- }
- }
}
1;
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index 62ab817..5338a1b 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -181,10 +181,24 @@ sub on_update_hook {
sub vnet_update_hook {
- my ($class, $vnet) = @_;
+ my ($class, $vnet_cfg, $vnetid, $zone_cfg) = @_;
- raise_param_exc({ tag => "missing vxlan tag"}) if !defined($vnet->{tag});
- raise_param_exc({ tag => "vxlan tag max value is 16777216"}) if $vnet->{tag} > 16777216;
+ my $vnet = $vnet_cfg->{ids}->{$vnetid};
+ my $tag = $vnet->{tag};
+
+ raise_param_exc({ tag => "missing vxlan tag"}) if !defined($tag);
+ raise_param_exc({ tag => "vxlan tag max value is 16777216"}) if $tag > 16777216;
+
+ # verify that tag is not already defined globally (vxlan-id are unique)
+ foreach my $id (keys %{$vnet_cfg->{ids}}) {
+ next if $id eq $vnetid;
+ my $othervnet = $vnet_cfg->{ids}->{$id};
+ my $other_tag = $othervnet->{tag};
+ my $other_zoneid = $othervnet->{zone};
+ my $other_zone = $zone_cfg->{ids}->{$other_zoneid};
+ next if $other_zone->{type} ne 'vxlan' && $other_zone->{type} ne 'evpn';
+ raise_param_exc({ tag => "vxlan tag $tag already exist in vnet $id in zone $other_zoneid "}) if $other_tag && $tag eq $other_tag;
+ }
if (!defined($vnet->{mac})) {
my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
diff --git a/PVE/Network/SDN/Zones/Plugin.pm b/PVE/Network/SDN/Zones/Plugin.pm
index 1f24269..6fc13eb 100644
--- a/PVE/Network/SDN/Zones/Plugin.pm
+++ b/PVE/Network/SDN/Zones/Plugin.pm
@@ -144,7 +144,7 @@ sub on_update_hook {
}
sub vnet_update_hook {
- my ($class, $vnet) = @_;
+ my ($class, $vnet_cfg, $vnetid, $zone_cfg) = @_;
# do nothing by default
}
diff --git a/PVE/Network/SDN/Zones/QinQPlugin.pm b/PVE/Network/SDN/Zones/QinQPlugin.pm
index aadfd27..5d40db8 100644
--- a/PVE/Network/SDN/Zones/QinQPlugin.pm
+++ b/PVE/Network/SDN/Zones/QinQPlugin.pm
@@ -216,10 +216,22 @@ sub status {
}
sub vnet_update_hook {
- my ($class, $vnet) = @_;
+ my ($class, $vnet_cfg, $vnetid, $zone_cfg) = @_;
+
+ my $vnet = $vnet_cfg->{ids}->{$vnetid};
+ my $tag = $vnet->{tag};
raise_param_exc({ tag => "missing vlan tag"}) if !defined($vnet->{tag});
raise_param_exc({ tag => "vlan tag max value is 4096"}) if $vnet->{tag} > 4096;
+
+ # verify that tag is not already defined in another vnet on same zone
+ foreach my $id (keys %{$vnet_cfg->{ids}}) {
+ next if $id eq $vnetid;
+ my $othervnet = $vnet_cfg->{ids}->{$id};
+ my $other_tag = $othervnet->{tag};
+ next if $vnet->{zone} ne $othervnet->{zone};
+ raise_param_exc({ tag => "tag $tag already exist in vnet $id"}) if $other_tag && $tag eq $other_tag;
+ }
}
1;
diff --git a/PVE/Network/SDN/Zones/SimplePlugin.pm b/PVE/Network/SDN/Zones/SimplePlugin.pm
index 5294485..c4f4475 100644
--- a/PVE/Network/SDN/Zones/SimplePlugin.pm
+++ b/PVE/Network/SDN/Zones/SimplePlugin.pm
@@ -118,9 +118,12 @@ sub status {
sub vnet_update_hook {
- my ($class, $vnet) = @_;
+ my ($class, $vnet_cfg, $vnetid, $zone_cfg) = @_;
- raise_param_exc({ tag => "vlan tag is not allowed on simple bridge"}) if defined($vnet->{tag});
+ my $vnet = $vnet_cfg->{ids}->{$vnetid};
+ my $tag = $vnet->{tag};
+
+ raise_param_exc({ tag => "vlan tag is not allowed on simple zone"}) if defined($tag);
if (!defined($vnet->{mac})) {
my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
diff --git a/PVE/Network/SDN/Zones/VlanPlugin.pm b/PVE/Network/SDN/Zones/VlanPlugin.pm
index e1ae75b..7af9b2c 100644
--- a/PVE/Network/SDN/Zones/VlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VlanPlugin.pm
@@ -175,10 +175,22 @@ sub status {
}
sub vnet_update_hook {
- my ($class, $vnet) = @_;
+ my ($class, $vnet_cfg, $vnetid, $zone_cfg) = @_;
+
+ my $vnet = $vnet_cfg->{ids}->{$vnetid};
+ my $tag = $vnet->{tag};
raise_param_exc({ tag => "missing vlan tag"}) if !defined($vnet->{tag});
raise_param_exc({ tag => "vlan tag max value is 4096"}) if $vnet->{tag} > 4096;
+
+ # verify that tag is not already defined in another vnet on same zone
+ foreach my $id (keys %{$vnet_cfg->{ids}}) {
+ next if $id eq $vnetid;
+ my $othervnet = $vnet_cfg->{ids}->{$id};
+ my $other_tag = $othervnet->{tag};
+ next if $vnet->{zone} ne $othervnet->{zone};
+ raise_param_exc({ tag => "tag $tag already exist in vnet $id"}) if $other_tag && $tag eq $other_tag;
+ }
}
1;
diff --git a/PVE/Network/SDN/Zones/VxlanPlugin.pm b/PVE/Network/SDN/Zones/VxlanPlugin.pm
index e8870a0..1fe16b8 100644
--- a/PVE/Network/SDN/Zones/VxlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VxlanPlugin.pm
@@ -94,10 +94,24 @@ sub generate_sdn_config {
}
sub vnet_update_hook {
- my ($class, $vnet) = @_;
+ my ($class, $vnet_cfg, $vnetid, $zone_cfg) = @_;
- raise_param_exc({ tag => "missing vxlan tag"}) if !defined($vnet->{tag});
- raise_param_exc({ tag => "vxlan tag max value is 16777216"}) if $vnet->{tag} > 16777216;
+ my $vnet = $vnet_cfg->{ids}->{$vnetid};
+ my $tag = $vnet->{tag};
+
+ raise_param_exc({ tag => "missing vxlan tag"}) if !defined($tag);
+ raise_param_exc({ tag => "vxlan tag max value is 16777216"}) if $tag > 16777216;
+
+ # verify that tag is not already defined globally (vxlan-id are unique)
+ foreach my $id (keys %{$vnet_cfg->{ids}}) {
+ next if $id eq $vnetid;
+ my $othervnet = $vnet_cfg->{ids}->{$id};
+ my $other_tag = $othervnet->{tag};
+ my $other_zoneid = $othervnet->{zone};
+ my $other_zone = $zone_cfg->{ids}->{$other_zoneid};
+ next if $other_zone->{type} ne 'vxlan' && $other_zone->{type} ne 'evpn';
+ raise_param_exc({ tag => "vxlan tag $tag already exist in vnet $id in zone $other_zoneid "}) if $other_tag && $tag eq $other_tag;
+ }
}
1;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 32/38] ipam: verify api access on create/update
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (30 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 31/38] vnets: allow duplicate tags in differents zones Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 33/38] ipam: add hostname/description to ipam db Alexandre Derumier
` (6 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN/Ipams.pm | 6 ++++++
PVE/Network/SDN/Ipams/NetboxPlugin.pm | 24 +++++++++++++++++++++++-
PVE/Network/SDN/Ipams/PhpIpamPlugin.pm | 24 +++++++++++++++++++++++-
PVE/Network/SDN/Ipams/Plugin.pm | 4 ++++
4 files changed, 56 insertions(+), 2 deletions(-)
diff --git a/PVE/API2/Network/SDN/Ipams.pm b/PVE/API2/Network/SDN/Ipams.pm
index 0d567c8..6410e8e 100644
--- a/PVE/API2/Network/SDN/Ipams.pm
+++ b/PVE/API2/Network/SDN/Ipams.pm
@@ -150,6 +150,10 @@ __PACKAGE__->register_method ({
$ipam_cfg->{ids}->{$id} = $opts;
+ my $plugin_config = $opts;
+ my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
+ $plugin->on_update_hook($plugin_config);
+
PVE::Network::SDN::Ipams::write_config($ipam_cfg);
}, "create sdn ipam object failed");
@@ -190,6 +194,8 @@ __PACKAGE__->register_method ({
$scfg->{$k} = $opts->{$k};
}
+ $plugin->on_update_hook($scfg);
+
PVE::Network::SDN::Ipams::write_config($ipam_cfg);
}, "update sdn ipam object failed");
diff --git a/PVE/Network/SDN/Ipams/NetboxPlugin.pm b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
index 8695b7d..d696b08 100644
--- a/PVE/Network/SDN/Ipams/NetboxPlugin.pm
+++ b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
@@ -138,10 +138,32 @@ sub del_ip {
PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/ipam/ip-addresses/$ip_id/", $headers);
};
if ($@) {
- die "error delete ip $ip";
+ die "error delete ip $ip : $@";
}
}
+sub verify_api {
+ my ($class, $plugin_config) = @_;
+
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
+
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("GET", "$url/ipam/aggregates/", $headers);
+ };
+ if ($@) {
+ die "Can't connect to netbox api: $@";
+ }
+}
+
+sub on_update_hook {
+ my ($class, $plugin_config) = @_;
+
+ PVE::Network::SDN::Ipams::NetboxPlugin::verify_api($class, $plugin_config);
+}
+
#helpers
sub get_prefix_id {
diff --git a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
index 324f1b2..f89ef29 100644
--- a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
+++ b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
@@ -162,10 +162,32 @@ sub del_ip {
PVE::Network::SDN::Ipams::Plugin::api_request("DELETE", "$url/addresses/$ip_id", $headers);
};
if ($@) {
- die "error delete ip $ip";
+ die "error delete ip $ip: $@";
}
}
+sub verify_api {
+ my ($class, $plugin_config) = @_;
+
+ my $url = $plugin_config->{url};
+ my $token = $plugin_config->{token};
+ my $sectionid = $plugin_config->{section};
+ my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token];
+
+ eval {
+ PVE::Network::SDN::Ipams::Plugin::api_request("GET", "$url/sections/$sectionid", $headers);
+ };
+ if ($@) {
+ die "Can't connect to phpipam api: $@";
+ }
+}
+
+sub on_update_hook {
+ my ($class, $plugin_config) = @_;
+
+ PVE::Network::SDN::Ipams::PhpIpamPlugin::verify_api($class, $plugin_config);
+}
+
#helpers
diff --git a/PVE/Network/SDN/Ipams/Plugin.pm b/PVE/Network/SDN/Ipams/Plugin.pm
index a2ade3b..4c68287 100644
--- a/PVE/Network/SDN/Ipams/Plugin.pm
+++ b/PVE/Network/SDN/Ipams/Plugin.pm
@@ -87,6 +87,10 @@ sub del_ip {
my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_;
}
+sub on_update_hook {
+ my ($class, $plugin_config) = @_;
+}
+
#helpers
sub api_request {
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 33/38] ipam: add hostname/description to ipam db
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (31 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 32/38] ipam: verify api access on create/update Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 34/38] update documentation Alexandre Derumier
` (5 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/Ipams/NetboxPlugin.pm | 8 +++---
PVE/Network/SDN/Ipams/PVEPlugin.pm | 16 ++++++++----
PVE/Network/SDN/Ipams/PhpIpamPlugin.pm | 12 ++++++---
PVE/Network/SDN/Ipams/Plugin.pm | 2 +-
PVE/Network/SDN/SubnetPlugin.pm | 4 ++-
PVE/Network/SDN/Subnets.pm | 36 ++++++++++++++------------
PVE/Network/SDN/Vnets.pm | 8 +++---
7 files changed, 50 insertions(+), 36 deletions(-)
diff --git a/PVE/Network/SDN/Ipams/NetboxPlugin.pm b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
index d696b08..298634d 100644
--- a/PVE/Network/SDN/Ipams/NetboxPlugin.pm
+++ b/PVE/Network/SDN/Ipams/NetboxPlugin.pm
@@ -77,7 +77,7 @@ sub del_subnet {
}
sub add_ip {
- my ($class, $plugin_config, $subnetid, $subnet, $ip, $is_gateway) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $ip, $hostname, $description, $is_gateway) = @_;
my $mask = $subnet->{mask};
my $url = $plugin_config->{url};
@@ -85,7 +85,7 @@ sub add_ip {
my $section = $plugin_config->{section};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
- my $params = { address => "$ip/$mask" };
+ my $params = { address => "$ip/$mask", dns_name => $hostname, description => $description };
eval {
PVE::Network::SDN::Ipams::Plugin::api_request("POST", "$url/ipam/ip-addresses/", $headers, $params);
@@ -97,7 +97,7 @@ sub add_ip {
}
sub add_next_freeip {
- my ($class, $plugin_config, $subnetid, $subnet) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $hostname, $description) = @_;
my $cidr = $subnet->{cidr};
@@ -107,7 +107,7 @@ sub add_next_freeip {
my $internalid = get_prefix_id($url, $cidr, $headers);
- my $params = {};
+ my $params = { dns_name => $hostname, description => $description };
my $ip = undef;
eval {
diff --git a/PVE/Network/SDN/Ipams/PVEPlugin.pm b/PVE/Network/SDN/Ipams/PVEPlugin.pm
index 601ad26..b0fd72f 100644
--- a/PVE/Network/SDN/Ipams/PVEPlugin.pm
+++ b/PVE/Network/SDN/Ipams/PVEPlugin.pm
@@ -78,7 +78,7 @@ sub del_subnet {
}
sub add_ip {
- my ($class, $plugin_config, $subnetid, $subnet, $ip, $is_gateway) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $ip, $hostname, $description, $is_gateway) = @_;
my $cidr = $subnet->{cidr};
my $zone = $subnet->{zone};
@@ -93,14 +93,17 @@ sub add_ip {
my $dbsubnet = $dbzone->{subnets}->{$cidr};
die "ip $ip already exist" if defined($dbsubnet->{ips}->{$ip});
- $dbsubnet->{ips}->{$ip} = 1;
+ my $dbip = {};
+ $dbip->{hostname} = $hostname;
+ $dbip->{description} = $description;
+ $dbsubnet->{ips}->{$ip} = $dbip;
write_db($db);
});
die "$@" if $@;
}
sub add_next_freeip {
- my ($class, $plugin_config, $subnetid, $subnet) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $hostname, $description) = @_;
my $cidr = $subnet->{cidr};
my $network = $subnet->{network};
@@ -135,8 +138,11 @@ sub add_next_freeip {
}
die "can't find free ip in subnet $cidr" if !$freeip;
-
- $dbsubnet->{ips}->{$freeip} = 1;
+
+ my $dbip = {};
+ $dbip->{hostname} = $hostname;
+ $dbip->{description} = $description;
+ $dbsubnet->{ips}->{$freeip} = $dbip;
write_db($db);
});
die "$@" if $@;
diff --git a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
index f89ef29..6261764 100644
--- a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
+++ b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm
@@ -95,7 +95,7 @@ sub del_subnet {
}
sub add_ip {
- my ($class, $plugin_config, $subnetid, $subnet, $ip, $is_gateway) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $ip, $hostname, $description, $is_gateway) = @_;
my $cidr = $subnet->{cidr};
my $url = $plugin_config->{url};
@@ -108,6 +108,8 @@ sub add_ip {
my $params = { ip => $ip,
subnetId => $internalid,
is_gateway => $is_gateway,
+ hostname => $hostname,
+ description => $description,
};
eval {
@@ -120,7 +122,7 @@ sub add_ip {
}
sub add_next_freeip {
- my ($class, $plugin_config, $subnetid, $subnet, $internalid, $hostname) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $hostname, $description) = @_;
my $cidr = $subnet->{cidr};
my $mask = $subnet->{mask};
@@ -129,9 +131,11 @@ sub add_next_freeip {
my $section = $plugin_config->{section};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token];
- $internalid = get_internalid($url, $cidr, $headers) if !$internalid;
+ my $internalid = get_internalid($url, $cidr, $headers);
- my $params = {};
+ my $params = { hostname => $hostname,
+ description => $description,
+ };
my $ip = undef;
eval {
diff --git a/PVE/Network/SDN/Ipams/Plugin.pm b/PVE/Network/SDN/Ipams/Plugin.pm
index 4c68287..065225c 100644
--- a/PVE/Network/SDN/Ipams/Plugin.pm
+++ b/PVE/Network/SDN/Ipams/Plugin.pm
@@ -75,7 +75,7 @@ sub del_subnet {
}
sub add_ip {
- my ($class, $plugin_config, $subnetid, $subnet, $ip, $is_gateway) = @_;
+ my ($class, $plugin_config, $subnetid, $subnet, $ip, $hostname, $description, $is_gateway) = @_;
}
diff --git a/PVE/Network/SDN/SubnetPlugin.pm b/PVE/Network/SDN/SubnetPlugin.pm
index 1444262..cb0f4ef 100644
--- a/PVE/Network/SDN/SubnetPlugin.pm
+++ b/PVE/Network/SDN/SubnetPlugin.pm
@@ -141,7 +141,9 @@ sub on_update_hook {
warn if $@;
}
if(!$old_gateway || $gateway && $gateway ne $old_gateway) {
- PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $gateway);
+ my $hostname = "$vnetid-gw";
+ my $description = "$vnetid gw";
+ PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $gateway, $hostname, $description, 1);
}
#delete old gateway after update
diff --git a/PVE/Network/SDN/Subnets.pm b/PVE/Network/SDN/Subnets.pm
index bd1eb36..09aa942 100644
--- a/PVE/Network/SDN/Subnets.pm
+++ b/PVE/Network/SDN/Subnets.pm
@@ -115,11 +115,9 @@ my $get_reversedns_zone = sub {
};
my $add_dns_record = sub {
- my ($zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
+ my ($zone, $dns, $hostname, $ip) = @_;
return if !$zone || !$dns || !$hostname || !$ip;
- $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
-
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});
@@ -128,11 +126,10 @@ my $add_dns_record = sub {
};
my $add_dns_ptr_record = sub {
- my ($reversezone, $zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
+ my ($reversezone, $zone, $dns, $hostname, $ip) = @_;
return if !$zone || !$reversezone || !$dns || !$hostname || !$ip;
- $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
$hostname .= ".$zone";
my $dns_cfg = PVE::Network::SDN::Dns::config();
my $plugin_config = $dns_cfg->{ids}->{$dns};
@@ -141,12 +138,10 @@ my $add_dns_ptr_record = sub {
};
my $del_dns_record = sub {
- my ($zone, $dns, $hostname, $dnszoneprefix, $ip) = @_;
+ my ($zone, $dns, $hostname, $ip) = @_;
return if !$zone || !$dns || !$hostname || !$ip;
- $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
-
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});
@@ -165,10 +160,11 @@ my $del_dns_ptr_record = sub {
};
sub next_free_ip {
- my ($zone, $subnetid, $subnet, $hostname) = @_;
+ my ($zone, $subnetid, $subnet, $hostname, $description) = @_;
my $cidr = undef;
my $ip = undef;
+ $description = '' if !$description;
my $ipamid = $zone->{ipam};
my $dns = $zone->{dns};
@@ -176,6 +172,8 @@ sub next_free_ip {
my $reversedns = $zone->{reversedns};
my $dnszoneprefix = $subnet->{dnszoneprefix};
+ $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
+
#verify dns zones before ipam
&$verify_dns_zone($dnszone, $dns);
@@ -184,7 +182,7 @@ sub next_free_ip {
my $plugin_config = $ipam_cfg->{ids}->{$ipamid};
my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type});
eval {
- $cidr = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet);
+ $cidr = $plugin->add_next_freeip($plugin_config, $subnetid, $subnet, $hostname, $description);
($ip, undef) = split(/\//, $cidr);
};
die $@ if $@;
@@ -194,9 +192,9 @@ sub next_free_ip {
my $reversednszone = &$get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
#add dns
- &$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
+ &$add_dns_record($dnszone, $dns, $hostname, $ip);
#add reverse dns
- &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $dnszoneprefix, $ip);
+ &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $ip);
};
if ($@) {
#rollback
@@ -210,7 +208,7 @@ sub next_free_ip {
}
sub add_ip {
- my ($zone, $subnetid, $subnet, $ip, $hostname) = @_;
+ my ($zone, $subnetid, $subnet, $ip, $hostname, $description) = @_;
return if !$subnet || !$ip;
@@ -221,6 +219,8 @@ sub add_ip {
my $reversednszone = &$get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
my $dnszoneprefix = $subnet->{dnszoneprefix};
+ $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
+
#verify dns zones before ipam
&$verify_dns_zone($dnszone, $dns);
&$verify_dns_zone($reversednszone, $reversedns);
@@ -230,16 +230,16 @@ 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, $subnet, $ip);
+ $plugin->add_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $description);
};
die $@ if $@;
}
eval {
#add dns
- &$add_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
+ &$add_dns_record($dnszone, $dns, $hostname, $ip);
#add reverse dns
- &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $dnszoneprefix, $ip);
+ &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $ip);
};
if ($@) {
#rollback
@@ -262,6 +262,8 @@ sub del_ip {
my $reversedns = $zone->{reversedns};
my $reversednszone = &$get_reversedns_zone($subnetid, $subnet, $reversedns, $ip);
my $dnszoneprefix = $subnet->{dnszoneprefix};
+ $hostname .= ".$dnszoneprefix" if $dnszoneprefix;
+
&$verify_dns_zone($dnszone, $dns);
&$verify_dns_zone($reversednszone, $reversedns);
@@ -274,7 +276,7 @@ sub del_ip {
}
eval {
- &$del_dns_record($dnszone, $dns, $hostname, $dnszoneprefix, $ip);
+ &$del_dns_record($dnszone, $dns, $hostname, $ip);
&$del_dns_ptr_record($reversednszone, $reversedns, $ip);
};
if ($@) {
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
index 6d11003..5616419 100644
--- a/PVE/Network/SDN/Vnets.pm
+++ b/PVE/Network/SDN/Vnets.pm
@@ -78,7 +78,7 @@ sub get_subnets {
}
sub get_next_free_cidr {
- my ($vnetid, $hostname, $ipversion) = @_;
+ my ($vnetid, $hostname, $description, $ipversion) = @_;
my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
my $zoneid = $vnet->{zone};
@@ -97,7 +97,7 @@ sub get_next_free_cidr {
$subnetcount++;
if ($zone->{ipam}) {
eval {
- $ip = PVE::Network::SDN::Subnets::next_free_ip($zone, $subnetid, $subnet, $hostname);
+ $ip = PVE::Network::SDN::Subnets::next_free_ip($zone, $subnetid, $subnet, $hostname, $description);
};
warn $@ if $@;
}
@@ -109,7 +109,7 @@ sub get_next_free_cidr {
}
sub add_cidr {
- my ($vnetid, $cidr, $hostname) = @_;
+ my ($vnetid, $cidr, $hostname, $description) = @_;
my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1);
my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid);
@@ -120,7 +120,7 @@ sub add_cidr {
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);
+ PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $ip, $hostname, $description);
}
sub del_cidr {
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 34/38] update documentation
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (32 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 33/38] ipam: add hostname/description to ipam db Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 35/38] vnets: remove unused hash:diff Alexandre Derumier
` (4 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
test/documentation.txt | 33 ++++++++++++++++++++++++++-------
1 file changed, 26 insertions(+), 7 deletions(-)
diff --git a/test/documentation.txt b/test/documentation.txt
index 316e5af..7886966 100644
--- a/test/documentation.txt
+++ b/test/documentation.txt
@@ -2,28 +2,47 @@ Here a sample of command with pvesh to manage the sdn.
#create a vlan transportzone
-pvesh create /cluster/sdn/zones/ --zone vlanzone --type vlan --bridge vmbr0
+pvesh create /cluster/sdn/zones/ --zone vlanzone --type vlan --ipam pve --bridge vmbr0
+#create a vnet on vlanzone
+pvesh create /cluster/sdn/vnets/ --vnet vnet100 --type vnet --zone vlanzone --tag 100
+#create a subnet on vlanzone
+pvesh create /cluster/sdn/vnets/vnet100/subnets/ --type subnet --subnet 192.168.0.0/24 --gateway 192.168.0.1
#create a layer2 vxlan unicast transportzone
-pvesh create /cluster/sdn/zones/ --zone vxlanunicastzone --type vxlan --peers 192.168.0.1,192.168.0.2,192.168.0.3
+pvesh create /cluster/sdn/zones/ --zone vxlanunicastzone --type vxlan --ipam pve --peers 192.168.0.1,192.168.0.2,192.168.0.3
#create an controller
pvesh create /cluster/sdn/controllers/ --controller frrrouter1 --type evpn --peers 192.168.0.1,192.168.0.2,192.168.0.3 --asn 1234 --gateway-nodes pxnode1,pxnode2 --gateway-external-peers 192.168.0.253,192.168.0.254
#create a layer2 vxlan bgpevpn transportzone
-pvesh create /cluster/sdn/zones/ --zone layer2evpnzone --type evpn --controller frrrouter1
+pvesh create /cluster/sdn/zones/ --zone layer2evpnzone --type evpn --ipam pve --controller frrrouter1
#create a layer3 routable vxlan bgpevpn transportzone
-pvesh create /cluster/sdn/zones/ --zone layer3evpnzone --type evpn --controller frrrouter1 --vrf-vxlan 4000
+pvesh create /cluster/sdn/zones/ --zone layer3evpnzone --type evpn --ipam pve --controller frrrouter1 --vrf-vxlan 4000
#create a vnet in the transportzone
pvesh create /cluster/sdn/vnets/ --vnet vnet10 --type vnet --zone vlanzone --tag 10
-#create a vnet in the transportzone with ip for evpn routing
-pvesh create /cluster/sdn/vnets/ --vnet vnet11 --type vnet --zone layer3evpnzone --tag 11 --ipv4 10.0.0.1/24 --mac c8:1f:66:f8:62:8d
-pvesh create /cluster/sdn/vnets/ --vnet vnet12 --type vnet --zone layer3evpnzone --tag 12 --ipv4 10.0.1.1/24 --mac c8:1f:66:f8:62:8e
+#create a vnet in the transportzone with subnets for evpn routing
+pvesh create /cluster/sdn/vnets/ --vnet vnet11 --type vnet --zone layer3evpnzone --tag 11 --mac c8:1f:66:f8:62:8d
+pvesh create /cluster/sdn/vnets/vnet11/subnets/ --type subnet --subnet 10.0.0.0/24 --gateway 10.0.0.1
+pvesh create /cluster/sdn/vnets/ --vnet vnet12 --type vnet --zone layer3evpnzone --tag 12 --mac c8:1f:66:f8:62:8e
+pvesh create /cluster/sdn/vnets/vnet11/subnets/ --type subnet --subnet 10.0.1.0/24 --gateway 10.0.1.1
+
+#display running configuration
+pvesh get /cluster/sdn/vnets --running
+pvesh get /cluster/sdn/zones --running
+pvesh get /cluster/sdn/controllers --running
+pvesh get /cluster/sdn/vnets/vnetX/subnets --running
+
+
+#display pending configuration
+pvesh get /cluster/sdn/vnets --pending
+pvesh get /cluster/sdn/zones --pending
+pvesh get /cluster/sdn/controllers --pending
+pvesh get /cluster/sdn/vnets/vnetX/subnets --pending
#apply changes from /etc/pve/sdn.cfg.new to /etc/pve/sdn.cfg
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 35/38] vnets: remove unused hash:diff
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (33 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 34/38] update documentation Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 36/38] zones: auto find controller Alexandre Derumier
` (3 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/API2/Network/SDN/Vnets.pm | 2 --
1 file changed, 2 deletions(-)
diff --git a/PVE/API2/Network/SDN/Vnets.pm b/PVE/API2/Network/SDN/Vnets.pm
index 84cf433..16959dc 100644
--- a/PVE/API2/Network/SDN/Vnets.pm
+++ b/PVE/API2/Network/SDN/Vnets.pm
@@ -3,8 +3,6 @@ package PVE::API2::Network::SDN::Vnets;
use strict;
use warnings;
-use Hash::Diff qw( diff );
-
use PVE::SafeSyslog;
use PVE::Tools qw(extract_param);
use PVE::Cluster qw(cfs_read_file cfs_write_file);
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 36/38] zones: auto find controller
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (34 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 35/38] vnets: remove unused hash:diff Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 37/38] sdn: controllers : add ebgp support Alexandre Derumier
` (2 subsequent siblings)
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
We can have only 1 controller of same type by node, avoid to define it in zone plugin.
This allow to define a global controller definition for all nodes,
and if needed, allow to redefine a controller for a specific node.
(for evpn with Ebgp, where we need to be able change peers/AS or other options by node)
---
PVE/Network/SDN/Controllers.pm | 33 +++++++++++++++--------
PVE/Network/SDN/Controllers/EvpnPlugin.pm | 10 ++++++-
PVE/Network/SDN/Controllers/Plugin.pm | 1 +
PVE/Network/SDN/Zones.pm | 6 ++++-
PVE/Network/SDN/Zones/EvpnPlugin.pm | 28 ++++++++++++-------
PVE/Network/SDN/Zones/Plugin.pm | 5 ++++
6 files changed, 61 insertions(+), 22 deletions(-)
diff --git a/PVE/Network/SDN/Controllers.pm b/PVE/Network/SDN/Controllers.pm
index f652d7f..be110b7 100644
--- a/PVE/Network/SDN/Controllers.pm
+++ b/PVE/Network/SDN/Controllers.pm
@@ -95,19 +95,25 @@ sub generate_controller_config {
#generate configuration
my $config = {};
- foreach my $id (keys %{$controller_cfg->{ids}}) {
- my $plugin_config = $controller_cfg->{ids}->{$id};
- my $plugin = PVE::Network::SDN::Controllers::Plugin->lookup($plugin_config->{type});
- $plugin->generate_controller_config($plugin_config, $plugin_config, $id, $uplinks, $config);
- }
+ my $nodename = PVE::INotify::nodename();
+ my $generated_controller_config = {};
foreach my $id (keys %{$zone_cfg->{ids}}) {
my $plugin_config = $zone_cfg->{ids}->{$id};
- my $controllerid = $plugin_config->{controller};
- next if !$controllerid;
- my $controller = $controller_cfg->{ids}->{$controllerid};
+ my $controller;
+ my $controllerid;
+ if ($controllerid = $plugin_config->{controller}) {
+ $controller = $controller_cfg->{ids}->{$controllerid};
+ } else {
+ my $zone_plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
+ $controllerid = $zone_plugin->find_controller($plugin_config, $nodename, $controller_cfg);
+ $controller = $controller_cfg->{ids}->{$controllerid} if $controllerid;
+ }
if ($controller) {
my $controller_plugin = PVE::Network::SDN::Controllers::Plugin->lookup($controller->{type});
+
+ $controller_plugin->generate_controller_config($controller, $controller, $controllerid, $uplinks, $config) if !$generated_controller_config->{$controllerid};
+ $generated_controller_config->{$controllerid} = 1;
$controller_plugin->generate_controller_zone_config($plugin_config, $controller, $id, $uplinks, $config);
}
}
@@ -118,9 +124,14 @@ sub generate_controller_config {
next if !$zoneid;
my $zone = $zone_cfg->{ids}->{$zoneid};
next if !$zone;
- my $controllerid = $zone->{controller};
- next if !$controllerid;
- my $controller = $controller_cfg->{ids}->{$controllerid};
+ my $controller;
+ if (my $controllerid = $plugin_config->{controller}) {
+ $controller = $controller_cfg->{ids}->{$controllerid};
+ } else {
+ my $zone_plugin = PVE::Network::SDN::Zones::Plugin->lookup($zone->{type});
+ my $controllerid = $zone_plugin->find_controller($zone, $nodename, $controller_cfg);
+ $controller = $controller_cfg->{ids}->{$controllerid} if $controllerid;
+ }
if ($controller) {
my $controller_plugin = PVE::Network::SDN::Controllers::Plugin->lookup($controller->{type});
$controller_plugin->generate_controller_vnet_config($plugin_config, $controller, $zoneid, $id, $config);
diff --git a/PVE/Network/SDN/Controllers/EvpnPlugin.pm b/PVE/Network/SDN/Controllers/EvpnPlugin.pm
index d82de2a..ca7be5b 100644
--- a/PVE/Network/SDN/Controllers/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Controllers/EvpnPlugin.pm
@@ -36,6 +36,7 @@ sub properties {
sub options {
return {
+ 'node' => { optional => 1 },
'asn' => { optional => 0 },
'peers' => { optional => 0 },
'gateway-nodes' => { optional => 1 },
@@ -165,10 +166,17 @@ sub on_update_hook {
# we can only have 1 evpn controller / 1 asn by server
+ my $current_controller = $controller_cfg->{ids}->{$controllerid};
+
foreach my $id (keys %{$controller_cfg->{ids}}) {
next if $id eq $controllerid;
my $controller = $controller_cfg->{ids}->{$id};
- die "only 1 evpn controller can be defined" if $controller->{type} eq "evpn";
+ next if $controller->{type} ne "evpn";
+ if(!$controller->{node} && !$current_controller->{node}) {
+ die "only 1 global evpn controller can be defined";
+ } else {
+ die "only 1 evpn controller can be defined for a specific node" if $controller->{node} eq $current_controller->{node};
+ }
}
}
diff --git a/PVE/Network/SDN/Controllers/Plugin.pm b/PVE/Network/SDN/Controllers/Plugin.pm
index 06cd576..acdfda0 100644
--- a/PVE/Network/SDN/Controllers/Plugin.pm
+++ b/PVE/Network/SDN/Controllers/Plugin.pm
@@ -40,6 +40,7 @@ my $defaultData = {
type => 'string', format => 'pve-configid',
type => 'string',
},
+ node => get_standard_option('pve-node', { optional => 1 }),
controller => get_standard_option('pve-sdn-controller-id',
{ completion => \&PVE::Network::SDN::complete_sdn_controller }),
},
diff --git a/PVE/Network/SDN/Zones.pm b/PVE/Network/SDN/Zones.pm
index 1f225dc..bff5cd7 100644
--- a/PVE/Network/SDN/Zones.pm
+++ b/PVE/Network/SDN/Zones.pm
@@ -124,12 +124,16 @@ sub generate_etc_network_config {
next if defined($plugin_config->{nodes}) && !$plugin_config->{nodes}->{$nodename};
+ my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
+
my $controller;
if (my $controllerid = $plugin_config->{controller}) {
$controller = $controller_cfg->{ids}->{$controllerid};
+ } else {
+ my $controllerid = $plugin->find_controller($plugin_config, $nodename, $controller_cfg);
+ $controller = $controller_cfg->{ids}->{$controllerid} if $controllerid;
}
- my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
eval {
$plugin->generate_sdn_config($plugin_config, $zone, $id, $vnet, $controller, $subnet_cfg, $interfaces_config, $config);
};
diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
index 5338a1b..495d134 100644
--- a/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -35,7 +35,6 @@ sub options {
return {
nodes => { optional => 1},
'vrf-vxlan' => { optional => 0 },
- 'controller' => { optional => 0 },
mtu => { optional => 1 },
dns => { optional => 1 },
reversedns => { optional => 1 },
@@ -156,17 +155,28 @@ sub generate_sdn_config {
return $config;
}
+sub find_controller {
+ my ($class, $plugin_config, $nodename, $controller_cfg) = @_;
+
+ #return global controller or more precise if node is defined
+ my $found_controller = undef;
+ foreach my $id (keys %{$controller_cfg->{ids}}) {
+ my $controller = $controller_cfg->{ids}->{$id};
+ next if $controller->{type} ne 'evpn';
+ if(!$controller->{node}) {
+ $found_controller = $id if !$found_controller;
+ } else {
+ next if $controller->{node} ne $nodename;
+ $found_controller = $id;
+ }
+ }
+ die "can't find any evpn controller" if !$found_controller;
+ return $found_controller;
+}
+
sub on_update_hook {
my ($class, $zoneid, $zone_cfg, $controller_cfg) = @_;
- # verify that controller exist
- my $controller = $zone_cfg->{ids}->{$zoneid}->{controller};
- if (!defined($controller_cfg->{ids}->{$controller})) {
- die "controller $controller don't exist";
- } else {
- die "$controller is not a evpn controller type" if $controller_cfg->{ids}->{$controller}->{type} ne 'evpn';
- }
-
#vrf-vxlan need to be defined
my $vrfvxlan = $zone_cfg->{ids}->{$zoneid}->{'vrf-vxlan'};
diff --git a/PVE/Network/SDN/Zones/Plugin.pm b/PVE/Network/SDN/Zones/Plugin.pm
index 6fc13eb..bd46e45 100644
--- a/PVE/Network/SDN/Zones/Plugin.pm
+++ b/PVE/Network/SDN/Zones/Plugin.pm
@@ -126,6 +126,11 @@ sub controller_reload {
die "please implement inside plugin";
}
+sub find_controller {
+ my ($class, $plugin_config, $nodename, $controller_cfg) = @_;
+ return undef;
+}
+
sub on_delete_hook {
my ($class, $zoneid, $vnet_cfg) = @_;
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 37/38] sdn: controllers : add ebgp support
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (35 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 36/38] zones: auto find controller Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 38/38] update test documentation Alexandre Derumier
2020-11-22 18:17 ` [pve-devel] [PATCH pve-network 00/38] add subnet plugin Thomas Lamprecht
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
PVE/Network/SDN/Controllers/EvpnPlugin.pm | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/PVE/Network/SDN/Controllers/EvpnPlugin.pm b/PVE/Network/SDN/Controllers/EvpnPlugin.pm
index ca7be5b..e88e60a 100644
--- a/PVE/Network/SDN/Controllers/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Controllers/EvpnPlugin.pm
@@ -26,6 +26,11 @@ sub properties {
description => "peers address list.",
type => 'string', format => 'ip-list'
},
+ ebgp => {
+ type => 'boolean',
+ optional => 1,
+ description => "Enable ebgp. (remote-as external)",
+ },
'gateway-nodes' => get_standard_option('pve-node-list'),
'gateway-external-peers' => {
description => "upstream bgp peers address list.",
@@ -39,6 +44,7 @@ sub options {
'node' => { optional => 1 },
'asn' => { optional => 0 },
'peers' => { optional => 0 },
+ 'ebgp' => { optional => 1 },
'gateway-nodes' => { optional => 1 },
'gateway-external-peers' => { optional => 1 },
};
@@ -52,6 +58,7 @@ sub generate_controller_config {
@peers = PVE::Tools::split_list($plugin_config->{'peers'}) if $plugin_config->{'peers'};
my $asn = $plugin_config->{asn};
+ my $ebgp = $plugin_config->{ebgp};
my $gatewaynodes = $plugin_config->{'gateway-nodes'};
my @gatewaypeers;
@gatewaypeers = PVE::Tools::split_list($plugin_config->{'gateway-external-peers'}) if $plugin_config->{'gateway-external-peers'};
@@ -75,9 +82,11 @@ sub generate_controller_config {
"coalesce-time 1000",
);
+ my $remoteas = $ebgp ? "external" : $asn;
+
foreach my $address (@peers) {
next if $address eq $ifaceip;
- push @controller_config, "neighbor $address remote-as $asn";
+ push @controller_config, "neighbor $address remote-as $remoteas";
}
if ($is_gateway) {
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* [pve-devel] [PATCH pve-network 38/38] update test documentation
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (36 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 37/38] sdn: controllers : add ebgp support Alexandre Derumier
@ 2020-11-08 14:19 ` Alexandre Derumier
2020-11-22 18:17 ` [pve-devel] [PATCH pve-network 00/38] add subnet plugin Thomas Lamprecht
38 siblings, 0 replies; 41+ messages in thread
From: Alexandre Derumier @ 2020-11-08 14:19 UTC (permalink / raw)
To: pve-devel
---
test/documentation.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/documentation.txt b/test/documentation.txt
index 7886966..2a858fa 100644
--- a/test/documentation.txt
+++ b/test/documentation.txt
@@ -16,10 +16,10 @@ pvesh create /cluster/sdn/zones/ --zone vxlanunicastzone --type vxlan --ipam pve
pvesh create /cluster/sdn/controllers/ --controller frrrouter1 --type evpn --peers 192.168.0.1,192.168.0.2,192.168.0.3 --asn 1234 --gateway-nodes pxnode1,pxnode2 --gateway-external-peers 192.168.0.253,192.168.0.254
#create a layer2 vxlan bgpevpn transportzone
-pvesh create /cluster/sdn/zones/ --zone layer2evpnzone --type evpn --ipam pve --controller frrrouter1
+pvesh create /cluster/sdn/zones/ --zone layer2evpnzone --type evpn --ipam pve
#create a layer3 routable vxlan bgpevpn transportzone
-pvesh create /cluster/sdn/zones/ --zone layer3evpnzone --type evpn --ipam pve --controller frrrouter1 --vrf-vxlan 4000
+pvesh create /cluster/sdn/zones/ --zone layer3evpnzone --type evpn --ipam pve --vrf-vxlan 4000
#create a vnet in the transportzone
--
2.20.1
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [pve-devel] [PATCH pve-network 00/38] add subnet plugin
2020-11-08 14:19 [pve-devel] [PATCH pve-network 00/38] add subnet plugin Alexandre Derumier
` (37 preceding siblings ...)
2020-11-08 14:19 ` [pve-devel] [PATCH pve-network 38/38] update test documentation Alexandre Derumier
@ 2020-11-22 18:17 ` Thomas Lamprecht
2020-11-23 10:04 ` alexandre derumier
38 siblings, 1 reply; 41+ messages in thread
From: Thomas Lamprecht @ 2020-11-22 18:17 UTC (permalink / raw)
To: Proxmox VE development discussion, Alexandre Derumier
On 08.11.20 15:19, Alexandre Derumier wrote:
> This patch series add basic subnets managements.
This did not apply, seems like the "add subnet plugin" stuff missed in general.
But, I had the previous version v10 somewhat cleaned up here (reduced to 25 patches)
from a month ago or so, so I pushed that one - as it seemed like there was only a
bit on top (I dropped the unused hash diff use statement already, so it should be
mostly "evpn plugin improvements" which is now missing.
You could diff a branch with that current version and the now pushed master
to see if anything bigger is now missing - sorry if that's the case.
> (need pve-cluster V5 patch series)
I'm onto that, actually, I'll see if I can do the merge tomorrow, else I'd
use it as is.
Anyway, huge thanks for your patience and sorry for the long delay.
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [pve-devel] [PATCH pve-network 00/38] add subnet plugin
2020-11-22 18:17 ` [pve-devel] [PATCH pve-network 00/38] add subnet plugin Thomas Lamprecht
@ 2020-11-23 10:04 ` alexandre derumier
0 siblings, 0 replies; 41+ messages in thread
From: alexandre derumier @ 2020-11-23 10:04 UTC (permalink / raw)
To: Thomas Lamprecht, Proxmox VE development discussion
On 22/11/2020 19:17, Thomas Lamprecht wrote:
> This did not apply, seems like the "add subnet plugin" stuff missed in general.
>
> But, I had the previous version v10 somewhat cleaned up here (reduced to 25 patches)
> from a month ago or so, so I pushed that one - as it seemed like there was only a
> bit on top (I dropped the unused hash diff use statement already, so it should be
> mostly "evpn plugin improvements" which is now missing.
>
> You could diff a branch with that current version and the now pushed master
> to see if anything bigger is now missing - sorry if that's the case.
oh, sorry, I didn't see that you have commited previous patch series
last month ! Thanks!
indeed, the last patches was only evpn plugin improvements.
I'll rebase them (and also have new evpn improvements)
^ permalink raw reply [flat|nested] 41+ messages in thread