[pve-devel] [PATCH pve-network 1/3] split transport/controllers/vnet to separate plugins
Alexandre Derumier
aderumier at odiso.com
Tue Oct 22 16:59:04 CEST 2019
Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
PVE/Network/SDN.pm | 297 +-----------------
PVE/Network/SDN/Controllers.pm | 158 ++++++++++
.../FaucetPlugin.pm} | 14 +-
.../FrrEvpnPlugin.pm} | 21 +-
PVE/Network/SDN/Controllers/Makefile | 8 +
PVE/Network/SDN/Controllers/Plugin.pm | 133 ++++++++
PVE/Network/SDN/Makefile | 4 +-
PVE/Network/SDN/VnetPlugin.pm | 92 ------
PVE/Network/SDN/Vnets.pm | 59 ++++
PVE/Network/SDN/Zones.pm | 227 +++++++++++++
PVE/Network/SDN/{ => Zones}/EvpnPlugin.pm | 10 +-
PVE/Network/SDN/{ => Zones}/FaucetPlugin.pm | 6 +-
PVE/Network/SDN/Zones/Makefile | 8 +
PVE/Network/SDN/{ => Zones}/Plugin.pm | 32 +-
PVE/Network/SDN/{ => Zones}/QinQPlugin.pm | 16 +-
PVE/Network/SDN/{ => Zones}/VlanPlugin.pm | 16 +-
PVE/Network/SDN/{ => Zones}/VxlanPlugin.pm | 18 +-
test/generateconfig.pl | 15 +-
18 files changed, 663 insertions(+), 471 deletions(-)
create mode 100644 PVE/Network/SDN/Controllers.pm
rename PVE/Network/SDN/{FaucetControllerPlugin.pm => Controllers/FaucetPlugin.pm} (90%)
rename PVE/Network/SDN/{EvpnControllerPlugin.pm => Controllers/FrrEvpnPlugin.pm} (95%)
create mode 100644 PVE/Network/SDN/Controllers/Makefile
create mode 100644 PVE/Network/SDN/Controllers/Plugin.pm
delete mode 100644 PVE/Network/SDN/VnetPlugin.pm
create mode 100644 PVE/Network/SDN/Vnets.pm
create mode 100644 PVE/Network/SDN/Zones.pm
rename PVE/Network/SDN/{ => Zones}/EvpnPlugin.pm (94%)
rename PVE/Network/SDN/{ => Zones}/FaucetPlugin.pm (92%)
create mode 100644 PVE/Network/SDN/Zones/Makefile
rename PVE/Network/SDN/{ => Zones}/Plugin.pm (79%)
rename PVE/Network/SDN/{ => Zones}/QinQPlugin.pm (88%)
rename PVE/Network/SDN/{ => Zones}/VlanPlugin.pm (89%)
rename PVE/Network/SDN/{ => Zones}/VxlanPlugin.pm (93%)
diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm
index 96f76d1..4088221 100644
--- a/PVE/Network/SDN.pm
+++ b/PVE/Network/SDN.pm
@@ -6,74 +6,12 @@ use warnings;
use Data::Dumper;
use JSON;
+use PVE::Network::SDN::Zones;
+
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::SDN::Plugin;
-use PVE::Network::SDN::VnetPlugin;
-use PVE::Network::SDN::VlanPlugin;
-use PVE::Network::SDN::VxlanPlugin;
-use PVE::Network::SDN::FaucetPlugin;
-use PVE::Network::SDN::FaucetControllerPlugin;
-use PVE::Network::SDN::EvpnPlugin;
-use PVE::Network::SDN::EvpnControllerPlugin;
-use PVE::Network::SDN::QinQPlugin;
-
-PVE::Network::SDN::VnetPlugin->register();
-PVE::Network::SDN::VlanPlugin->register();
-PVE::Network::SDN::VxlanPlugin->register();
-PVE::Network::SDN::FaucetControllerPlugin->register();
-PVE::Network::SDN::FaucetPlugin->register();
-PVE::Network::SDN::EvpnPlugin->register();
-PVE::Network::SDN::EvpnControllerPlugin->register();
-PVE::Network::SDN::QinQPlugin->register();
-PVE::Network::SDN::Plugin->init();
-
-
-sub sdn_config {
- my ($cfg, $sdnid, $noerr) = @_;
-
- die "no sdn ID specified\n" if !$sdnid;
-
- my $scfg = $cfg->{ids}->{$sdnid};
- die "sdn '$sdnid' does not exists\n" if (!$noerr && !$scfg);
-
- return $scfg;
-}
-
-sub config {
- my $config = cfs_read_file("sdn.cfg.new");
- $config = cfs_read_file("sdn.cfg") if !keys %{$config->{ids}};
- return $config;
-}
-
-sub write_config {
- my ($cfg) = @_;
-
- cfs_write_file("sdn.cfg.new", $cfg);
-}
-
-sub lock_sdn_config {
- my ($code, $errmsg) = @_;
-
- cfs_lock_file("sdn.cfg.new", undef, $code);
- if (my $err = $@) {
- $errmsg ? die "$errmsg: $err" : die $err;
- }
-}
-
-sub sdn_ids {
- my ($cfg) = @_;
-
- return keys %{$cfg->{ids}};
-}
-sub complete_sdn {
- my ($cmdname, $pname, $cvalue) = @_;
-
- my $cfg = PVE::Network::SDN::config();
-
- return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::sdn_ids($cfg) ];
-}
+# improve me : move status code inside plugins ?
sub ifquery_check {
@@ -101,236 +39,9 @@ sub ifquery_check {
return $interfaces;
}
-
-sub generate_etc_network_config {
-
- my $sdn_cfg = PVE::Cluster::cfs_read_file('sdn.cfg');
- return if !$sdn_cfg;
-
- #read main config for physical interfaces
- my $current_config_file = "/etc/network/interfaces";
- my $fh = IO::File->new($current_config_file);
- my $interfaces_config = PVE::INotify::read_etc_network_interfaces(1,$fh);
- $fh->close();
-
- #check uplinks
- my $uplinks = {};
- foreach my $id (keys %{$interfaces_config->{ifaces}}) {
- my $interface = $interfaces_config->{ifaces}->{$id};
- if (my $uplink = $interface->{'uplink-id'}) {
- die "uplink-id $uplink is already defined on $uplinks->{$uplink}" if $uplinks->{$uplink};
- $interface->{name} = $id;
- $uplinks->{$interface->{'uplink-id'}} = $interface;
- }
- }
-
- my $vnet_cfg = undef;
- my $transport_cfg = undef;
-
- foreach my $id (keys %{$sdn_cfg->{ids}}) {
- if ($sdn_cfg->{ids}->{$id}->{type} eq 'vnet') {
- $vnet_cfg->{ids}->{$id} = $sdn_cfg->{ids}->{$id};
- } else {
- $transport_cfg->{ids}->{$id} = $sdn_cfg->{ids}->{$id};
- }
- }
-
- #generate configuration
- my $config = {};
- foreach my $id (keys %{$vnet_cfg->{ids}}) {
- my $vnet = $vnet_cfg->{ids}->{$id};
- my $zone = $vnet->{transportzone};
-
- if(!$zone) {
- warn "can't generate vnet $vnet : zone $zone don't exist";
- next;
- }
-
- my $plugin_config = $transport_cfg->{ids}->{$zone};
-
- if (!defined($plugin_config)) {
- warn "can't generate vnet $vnet : zone $zone don't exist";
- next;
- }
-
- my $plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type});
- $plugin->generate_sdn_config($plugin_config, $zone, $id, $vnet, $uplinks, $config);
- }
-
- my $raw_network_config = "";
- foreach my $iface (keys %$config) {
- $raw_network_config .= "\n";
- $raw_network_config .= "auto $iface\n";
- $raw_network_config .= "iface $iface\n";
- foreach my $option (@{$config->{$iface}}) {
- $raw_network_config .= "\t$option\n";
- }
- }
-
- return $raw_network_config;
-}
-
-sub generate_controller_config {
-
- my $sdn_cfg = PVE::Cluster::cfs_read_file('sdn.cfg');
- return if !$sdn_cfg;
-
- #read main config for physical interfaces
- my $current_config_file = "/etc/network/interfaces";
- my $fh = IO::File->new($current_config_file);
- my $interfaces_config = PVE::INotify::read_etc_network_interfaces(1,$fh);
- $fh->close();
-
- #check uplinks
- my $uplinks = {};
- foreach my $id (keys %{$interfaces_config->{ifaces}}) {
- my $interface = $interfaces_config->{ifaces}->{$id};
- if (my $uplink = $interface->{'uplink-id'}) {
- die "uplink-id $uplink is already defined on $uplinks->{$uplink}" if $uplinks->{$uplink};
- $interface->{name} = $id;
- $uplinks->{$interface->{'uplink-id'}} = $interface;
- }
- }
-
- #generate configuration
- my $config = {};
-
- foreach my $id (keys %{$sdn_cfg->{ids}}) {
- my $plugin_config = $sdn_cfg->{ids}->{$id};
- my $plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type});
- my $pd = $plugin->plugindata();
- my $role = $pd->{role};
- if ($role eq 'controller') {
- $plugin->generate_controller_config($plugin_config, $plugin_config, $id, $uplinks, $config);
- } elsif ($role eq 'transport') {
- my $controllerid = $plugin_config->{controller};
- if ($controllerid) {
- my $controller = $sdn_cfg->{ids}->{$controllerid};
- if ($controller) {
- my $controller_plugin = PVE::Network::SDN::Plugin->lookup($controller->{type});
- $controller_plugin->generate_controller_transport_config($plugin_config, $controller, $id, $uplinks, $config);
- }
- }
- } elsif ($role eq 'vnet') {
- my $transportid = $plugin_config->{transportzone};
- if ($transportid) {
- my $transport = $sdn_cfg->{ids}->{$transportid};
- if ($transport) {
- my $controllerid = $transport->{controller};
- if ($controllerid) {
- my $controller = $sdn_cfg->{ids}->{$controllerid};
- if ($controller) {
- my $controller_plugin = PVE::Network::SDN::Plugin->lookup($controller->{type});
- $controller_plugin->generate_controller_vnet_config($plugin_config, $controller, $transportid, $id, $config);
- }
- }
- }
- }
- }
- }
-
- return $config;
-}
-
-
-sub reload_controller {
-
- my $sdn_cfg = PVE::Cluster::cfs_read_file('sdn.cfg');
- return if !$sdn_cfg;
-
- foreach my $id (keys %{$sdn_cfg->{ids}}) {
- my $plugin_config = $sdn_cfg->{ids}->{$id};
- my $plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type});
- my $pd = $plugin->plugindata();
- my $role = $pd->{role};
- if ($role eq 'controller') {
- $plugin->reload_controller();
- }
- }
-}
-
-sub write_etc_network_config {
- my ($rawconfig) = @_;
-
- return if !$rawconfig;
- my $sdn_interfaces_file = "/etc/network/interfaces.d/sdn";
-
- my $writefh = IO::File->new($sdn_interfaces_file,">");
- print $writefh $rawconfig;
- $writefh->close();
-}
-
-sub write_controller_config {
- my ($config) = @_;
-
- my $sdn_cfg = PVE::Cluster::cfs_read_file('sdn.cfg');
- return if !$sdn_cfg;
-
- foreach my $id (keys %{$sdn_cfg->{ids}}) {
- my $plugin_config = $sdn_cfg->{ids}->{$id};
- my $plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type});
- my $pd = $plugin->plugindata();
- my $role = $pd->{role};
- if ($role eq 'controller') {
- $plugin->write_controller_config($plugin_config, $config);
- }
- }
-}
-
sub status {
- my $cluster_sdn_file = "/etc/pve/sdn.cfg";
- my $local_sdn_file = "/etc/network/interfaces.d/sdn";
- my $err_config = undef;
-
- return if !-e $cluster_sdn_file;
-
- if (!-e $local_sdn_file) {
- warn "local sdn network configuration is not yet generated, please reload";
- $err_config = 'pending';
- } else {
- # fixme : use some kind of versioning info?
- my $cluster_sdn_timestamp = (stat($cluster_sdn_file))[9];
- my $local_sdn_timestamp = (stat($local_sdn_file))[9];
-
- if ($local_sdn_timestamp < $cluster_sdn_timestamp) {
- warn "local sdn network configuration is too old, please reload";
- $err_config = 'unknown';
- }
- }
-
- my $status = ifquery_check();
-
- my $network_cfg = PVE::Cluster::cfs_read_file('sdn.cfg');
- my $vnet_cfg = undef;
- my $transport_cfg = undef;
-
- my $vnet_status = {};
- my $transport_status = {};
-
- foreach my $id (keys %{$network_cfg->{ids}}) {
- if ($network_cfg->{ids}->{$id}->{type} eq 'vnet') {
- my $transportzone = $network_cfg->{ids}->{$id}->{transportzone};
- $vnet_status->{$id}->{transportzone} = $transportzone;
- $transport_status->{$transportzone}->{status} = 'available' if !defined($transport_status->{$transportzone}->{status});
-
- if($err_config) {
- $vnet_status->{$id}->{status} = $err_config;
- $transport_status->{$transportzone}->{status} = $err_config;
- } elsif ($status->{$id}->{status} && $status->{$id}->{status} eq 'pass') {
- $vnet_status->{$id}->{status} = 'available';
- my $bridgeport = $status->{$id}->{config}->{'bridge-ports'};
-
- if ($status->{$bridgeport}->{status} && $status->{$bridgeport}->{status} ne 'pass') {
- $vnet_status->{$id}->{status} = 'error';
- $transport_status->{$transportzone}->{status} = 'error';
- }
- } else {
- $vnet_status->{$id}->{status} = 'error';
- $transport_status->{$transportzone}->{status} = 'error';
- }
- }
- }
+ my ($transport_status, $vnet_status) = PVE::Network::SDN::Zones::status();
return($transport_status, $vnet_status);
}
diff --git a/PVE/Network/SDN/Controllers.pm b/PVE/Network/SDN/Controllers.pm
new file mode 100644
index 0000000..19ad15a
--- /dev/null
+++ b/PVE/Network/SDN/Controllers.pm
@@ -0,0 +1,158 @@
+package PVE::Network::SDN::Controllers;
+
+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::SDN::Vnets;
+use PVE::Network::SDN::Zones;
+
+use PVE::Network::SDN::Controllers::FrrEvpnPlugin;
+use PVE::Network::SDN::Controllers::FaucetPlugin;
+use PVE::Network::SDN::Controllers::Plugin;
+PVE::Network::SDN::Controllers::FrrEvpnPlugin->register();
+PVE::Network::SDN::Controllers::FaucetPlugin->register();
+PVE::Network::SDN::Controllers::Plugin->init();
+
+
+sub sdn_controllers_config {
+ my ($cfg, $id, $noerr) = @_;
+
+ die "no sdn controller ID specified\n" if !$id;
+
+ my $scfg = $cfg->{ids}->{$id};
+ die "sdn '$id' does not exists\n" if (!$noerr && !$scfg);
+
+ return $scfg;
+}
+
+sub config {
+ my $config = cfs_read_file("sdn/controllers.cfg.new");
+ $config = cfs_read_file("sdn/controllers.cfg") if !keys %{$config->{ids}};
+ return $config;
+}
+
+sub write_config {
+ my ($cfg) = @_;
+
+ cfs_write_file("sdn/controllers.cfg.new", $cfg);
+}
+
+sub lock_sdn_controllers_config {
+ my ($code, $errmsg) = @_;
+
+ cfs_lock_file("sdn/controllers.cfg.new", undef, $code);
+ if (my $err = $@) {
+ $errmsg ? die "$errmsg: $err" : die $err;
+ }
+}
+
+sub sdn_controllers_ids {
+ my ($cfg) = @_;
+
+ return keys %{$cfg->{ids}};
+}
+
+sub complete_sdn_controller {
+ my ($cmdname, $pname, $cvalue) = @_;
+
+ my $cfg = PVE::Network::SDN::config();
+
+ return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::sdn_controllers_ids($cfg) ];
+}
+
+sub generate_controller_config {
+
+ my $vnet_cfg = PVE::Cluster::cfs_read_file('sdn/vnets.cfg');
+ my $transport_cfg = PVE::Cluster::cfs_read_file('sdn/zones.cfg');
+ my $controller_cfg = PVE::Cluster::cfs_read_file('sdn/controllers.cfg');
+ return if !$vnet_cfg && !$transport_cfg && !$controller_cfg;
+
+ #read main config for physical interfaces
+ my $current_config_file = "/etc/network/interfaces";
+ my $fh = IO::File->new($current_config_file);
+ my $interfaces_config = PVE::INotify::read_etc_network_interfaces(1,$fh);
+ $fh->close();
+
+ #check uplinks
+ my $uplinks = {};
+ foreach my $id (keys %{$interfaces_config->{ifaces}}) {
+ my $interface = $interfaces_config->{ifaces}->{$id};
+ if (my $uplink = $interface->{'uplink-id'}) {
+ die "uplink-id $uplink is already defined on $uplinks->{$uplink}" if $uplinks->{$uplink};
+ $interface->{name} = $id;
+ $uplinks->{$interface->{'uplink-id'}} = $interface;
+ }
+ }
+
+ #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);
+ }
+
+ foreach my $id (keys %{$transport_cfg->{ids}}) {
+ my $plugin_config = $transport_cfg->{ids}->{$id};
+ my $controllerid = $plugin_config->{controller};
+ next if !$controllerid;
+ my $controller = $transport_cfg->{ids}->{$controllerid};
+ if ($controller) {
+ my $controller_plugin = PVE::Network::SDN::Controllers::Plugin->lookup($controller->{type});
+ $controller_plugin->generate_controller_transport_config($plugin_config, $controller, $id, $uplinks, $config);
+ }
+ }
+
+ foreach my $id (keys %{$vnet_cfg->{ids}}) {
+ my $plugin_config = $vnet_cfg->{ids}->{$id};
+ my $transportid = $plugin_config->{transportzone};
+ next if !$transportid;
+ my $transport = $transport_cfg->{ids}->{$transportid};
+ next if !$transport;
+ my $controllerid = $transport->{controller};
+ next if !$controllerid;
+ my $controller = $controller_cfg->{ids}->{$controllerid};
+ if ($controller) {
+ my $controller_plugin = PVE::Network::SDN::Controllers::Plugin->lookup($controller->{type});
+ $controller_plugin->generate_controller_vnet_config($plugin_config, $controller, $transportid, $id, $config);
+ }
+ }
+
+ return $config;
+}
+
+
+sub reload_controller {
+
+ my $controller_cfg = PVE::Cluster::cfs_read_file('sdn/controllers.cfg');
+ return if !$controller_cfg;
+
+ 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->reload_controller();
+ }
+}
+
+sub write_controller_config {
+ my ($config) = @_;
+
+ my $controller_cfg = PVE::Cluster::cfs_read_file('sdn/controllers.cfg');
+ return if !$controller_cfg;
+
+ 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->write_controller_config($plugin_config, $config);
+ }
+}
+
+1;
+
diff --git a/PVE/Network/SDN/FaucetControllerPlugin.pm b/PVE/Network/SDN/Controllers/FaucetPlugin.pm
similarity index 90%
rename from PVE/Network/SDN/FaucetControllerPlugin.pm
rename to PVE/Network/SDN/Controllers/FaucetPlugin.pm
index ee15bdf..38f9abf 100644
--- a/PVE/Network/SDN/FaucetControllerPlugin.pm
+++ b/PVE/Network/SDN/Controllers/FaucetPlugin.pm
@@ -1,24 +1,18 @@
-package PVE::Network::SDN::FaucetControllerPlugin;
+package PVE::Network::SDN::Controllers::FaucetPlugin;
use strict;
use warnings;
-use PVE::Network::SDN::Plugin;
+use PVE::Network::SDN::Controllers::Plugin;
use PVE::Tools;
use PVE::INotify;
use PVE::JSONSchema qw(get_standard_option);
use CPAN::Meta::YAML;
use Encode;
-use base('PVE::Network::SDN::Plugin');
+use base('PVE::Network::SDN::Controllers::Plugin');
sub type {
- return 'faucetcontroller';
-}
-
-sub plugindata {
- return {
- role => 'controller',
- };
+ return 'faucet';
}
sub properties {
diff --git a/PVE/Network/SDN/EvpnControllerPlugin.pm b/PVE/Network/SDN/Controllers/FrrEvpnPlugin.pm
similarity index 95%
rename from PVE/Network/SDN/EvpnControllerPlugin.pm
rename to PVE/Network/SDN/Controllers/FrrEvpnPlugin.pm
index b2c9345..052c77e 100644
--- a/PVE/Network/SDN/EvpnControllerPlugin.pm
+++ b/PVE/Network/SDN/Controllers/FrrEvpnPlugin.pm
@@ -1,26 +1,25 @@
-package PVE::Network::SDN::EvpnControllerPlugin;
+package PVE::Network::SDN::Controllers::FrrEvpnPlugin;
use strict;
use warnings;
-use PVE::Network::SDN::Plugin;
+use PVE::Network::SDN::Controllers::Plugin;
use PVE::Tools;
use PVE::INotify;
use PVE::JSONSchema qw(get_standard_option);
-use base('PVE::Network::SDN::Plugin');
+use base('PVE::Network::SDN::Controllers::Plugin');
sub type {
- return 'evpncontroller';
-}
-
-sub plugindata {
- return {
- role => 'controller',
- };
+ return 'frrevpn';
}
sub properties {
return {
+ 'uplink-id' => {
+ type => 'integer',
+ minimum => 1, maximum => 4096,
+ description => 'Uplink interface',
+ },
'asn' => {
type => 'integer',
description => "autonomous system number",
@@ -66,7 +65,7 @@ sub generate_controller_config {
if($uplinks->{$uplink}->{name}) {
$iface = $uplinks->{$uplink}->{name};
- $ifaceip = PVE::Network::SDN::Plugin::get_first_local_ipv4_from_interface($iface);
+ $ifaceip = PVE::Network::SDN::Controllers::Plugin::get_first_local_ipv4_from_interface($iface);
}
my $is_gateway = undef;
diff --git a/PVE/Network/SDN/Controllers/Makefile b/PVE/Network/SDN/Controllers/Makefile
new file mode 100644
index 0000000..73c3b7b
--- /dev/null
+++ b/PVE/Network/SDN/Controllers/Makefile
@@ -0,0 +1,8 @@
+SOURCES=Plugin.pm FaucetPlugin.pm FrrEvpnPlugin.pm
+
+
+PERL5DIR=${DESTDIR}/usr/share/perl5
+
+.PHONY: install
+install:
+ for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/Network/SDN/Controllers/$$i; done
diff --git a/PVE/Network/SDN/Controllers/Plugin.pm b/PVE/Network/SDN/Controllers/Plugin.pm
new file mode 100644
index 0000000..df385f1
--- /dev/null
+++ b/PVE/Network/SDN/Controllers/Plugin.pm
@@ -0,0 +1,133 @@
+package PVE::Network::SDN::Controllers::Plugin;
+
+use strict;
+use warnings;
+
+use PVE::Tools;
+use PVE::JSONSchema;
+use PVE::Cluster;
+
+use Data::Dumper;
+use PVE::JSONSchema qw(get_standard_option);
+use base qw(PVE::SectionConfig);
+
+PVE::Cluster::cfs_register_file('sdn/controllers.cfg',
+ sub { __PACKAGE__->parse_config(@_); });
+
+PVE::Cluster::cfs_register_file('sdn/controllers.cfg.new',
+ sub { __PACKAGE__->parse_config(@_); },
+ sub { __PACKAGE__->write_config(@_); });
+
+PVE::JSONSchema::register_standard_option('pve-sdn-controller-id', {
+ description => "The SDN controller object identifier.",
+ type => 'string', format => 'pve-sdn-controller-id',
+});
+
+PVE::JSONSchema::register_format('pve-sdn-controller-id', \&parse_sdn_controller_id);
+sub parse_sdn_controller_id {
+ my ($id, $noerr) = @_;
+
+ if ($id !~ m/^[a-z][a-z0-9\-\_\.]*[a-z0-9]$/i) {
+ return undef if $noerr;
+ die "SDN controller object ID '$id' contains illegal characters\n";
+ }
+ return $id;
+}
+
+my $defaultData = {
+
+ propertyList => {
+ type => {
+ description => "Plugin type.",
+ type => 'string', format => 'pve-configid',
+ type => 'string',
+ },
+ controller => get_standard_option('pve-sdn-controller-id',
+ { completion => \&PVE::Network::SDN::complete_sdn_controller }),
+ },
+};
+
+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 generate_sdn_config {
+ my ($class, $plugin_config, $node, $data, $ctime) = @_;
+
+ die "please implement inside plugin";
+}
+
+sub generate_controller_config {
+ my ($class, $plugin_config, $router, $id, $uplinks, $config) = @_;
+
+ die "please implement inside plugin";
+}
+
+sub generate_controller_vnet_config {
+ my ($class, $plugin_config, $controller, $transportid, $vnetid, $config) = @_;
+
+}
+
+sub write_controller_config {
+ my ($class, $plugin_config, $config) = @_;
+
+ die "please implement inside plugin";
+}
+
+sub controller_reload {
+ my ($class) = @_;
+
+ die "please implement inside plugin";
+}
+
+sub on_delete_hook {
+ my ($class, $sndid, $scfg) = @_;
+
+ # do nothing by default
+}
+
+sub on_update_hook {
+ my ($class, $sdnid, $scfg) = @_;
+
+ # do nothing by default
+}
+
+#helpers
+
+#to be move to Network.pm helper
+sub get_first_local_ipv4_from_interface {
+ my ($interface) = @_;
+
+ my $cmd = ['/sbin/ip', 'address', 'show', 'dev', $interface];
+
+ my $IP = "";
+
+ my $code = sub {
+ my $line = shift;
+
+ if ($line =~ m!^\s*inet\s+($PVE::Tools::IPRE)(?:/\d+|\s+peer\s+)!) {
+ $IP = $1;
+ return;
+ }
+ };
+
+ PVE::Tools::run_command($cmd, outfunc => $code);
+
+ return $IP;
+}
+
+1;
diff --git a/PVE/Network/SDN/Makefile b/PVE/Network/SDN/Makefile
index 232db52..7622255 100644
--- a/PVE/Network/SDN/Makefile
+++ b/PVE/Network/SDN/Makefile
@@ -1,4 +1,4 @@
-SOURCES=Plugin.pm VnetPlugin.pm VlanPlugin.pm VxlanPlugin.pm FaucetControllerPlugin.pm FaucetPlugin.pm EvpnPlugin.pm EvpnControllerPlugin.pm QinQPlugin.pm
+SOURCES=Vnets.pm VnetPlugin.pm Zones.pm Controllers.pm
PERL5DIR=${DESTDIR}/usr/share/perl5
@@ -6,4 +6,6 @@ PERL5DIR=${DESTDIR}/usr/share/perl5
.PHONY: install
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
diff --git a/PVE/Network/SDN/VnetPlugin.pm b/PVE/Network/SDN/VnetPlugin.pm
deleted file mode 100644
index e918564..0000000
--- a/PVE/Network/SDN/VnetPlugin.pm
+++ /dev/null
@@ -1,92 +0,0 @@
-package PVE::Network::SDN::VnetPlugin;
-
-use strict;
-use warnings;
-use PVE::Network::SDN::Plugin;
-
-use base('PVE::Network::SDN::Plugin');
-
-use PVE::Cluster;
-
-sub type {
- return 'vnet';
-}
-
-sub plugindata {
- return {
- role => 'vnet',
- };
-}
-
-sub properties {
- return {
- transportzone => {
- type => 'string',
- description => "transportzone id",
- },
- tag => {
- type => 'integer',
- description => "vlan or vxlan id",
- },
- alias => {
- type => 'string',
- description => "alias name of the vnet",
- optional => 1,
- },
- mtu => {
- type => 'integer',
- description => "mtu",
- optional => 1,
- },
- ipv4 => {
- description => "Anycast router ipv4 address.",
- type => 'string', format => 'CIDRv4',
- optional => 1,
- },
- ipv6 => {
- description => "Anycast router ipv6 address.",
- type => 'string', format => 'CIDRv6',
- optional => 1,
- },
- mac => {
- type => 'string',
- description => "Anycast router mac address",
- optional => 1, format => 'mac-addr'
- }
- };
-}
-
-sub options {
- return {
- transportzone => { optional => 0},
- tag => { optional => 0},
- alias => { optional => 1 },
- ipv4 => { optional => 1 },
- ipv6 => { optional => 1 },
- mtu => { optional => 1 },
- mac => { optional => 1 },
- };
-}
-
-sub on_delete_hook {
- my ($class, $sdnid, $sdn_cfg) = @_;
-
- return;
-}
-
-sub on_update_hook {
- my ($class, $sdnid, $sdn_cfg) = @_;
- # verify that tag is not already defined in another vnet
- if (defined($sdn_cfg->{ids}->{$sdnid}->{tag})) {
- my $tag = $sdn_cfg->{ids}->{$sdnid}->{tag};
- foreach my $id (keys %{$sdn_cfg->{ids}}) {
- next if $id eq $sdnid;
- my $sdn = $sdn_cfg->{ids}->{$id};
- if ($sdn->{type} eq 'vnet' && defined($sdn->{tag})) {
- die "tag $tag already exist in vnet $id" if $tag eq $sdn->{tag};
- }
- }
- }
-}
-
-1;
diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm
new file mode 100644
index 0000000..95a74f5
--- /dev/null
+++ b/PVE/Network/SDN/Vnets.pm
@@ -0,0 +1,59 @@
+package PVE::Network::SDN::Vnets;
+
+use strict;
+use warnings;
+
+use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_lock_file);
+
+
+use PVE::Network::SDN::VnetPlugin;
+PVE::Network::SDN::VnetPlugin->register();
+PVE::Network::SDN::VnetPlugin->init();
+
+sub sdn_vnets_config {
+ my ($cfg, $id, $noerr) = @_;
+
+ die "no sdn vnet ID specified\n" if !$id;
+
+ my $scfg = $cfg->{ids}->{$id};
+ die "sdn vnet '$id' does not exists\n" if (!$noerr && !$scfg);
+
+ return $scfg;
+}
+
+sub config {
+ my $config = cfs_read_file("sdn/vnets.cfg.new");
+ $config = cfs_read_file("sdn/vnets.cfg") if !keys %{$config->{ids}};
+ return $config;
+}
+
+sub write_config {
+ my ($cfg) = @_;
+
+ cfs_write_file("sdn/vnets.cfg.new", $cfg);
+}
+
+sub lock_sdn_vnets_config {
+ my ($code, $errmsg) = @_;
+
+ cfs_lock_file("sdn/vnets.cfg.new", undef, $code);
+ if (my $err = $@) {
+ $errmsg ? die "$errmsg: $err" : die $err;
+ }
+}
+
+sub sdn_vnets_ids {
+ my ($cfg) = @_;
+
+ return keys %{$cfg->{ids}};
+}
+
+sub complete_sdn_vnet {
+ my ($cmdname, $pname, $cvalue) = @_;
+
+ my $cfg = PVE::Network::SDN::Vnets::config();
+
+ return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::Vnets::sdn_vnet_ids($cfg) ];
+}
+
+1;
diff --git a/PVE/Network/SDN/Zones.pm b/PVE/Network/SDN/Zones.pm
new file mode 100644
index 0000000..a3634ac
--- /dev/null
+++ b/PVE/Network/SDN/Zones.pm
@@ -0,0 +1,227 @@
+package PVE::Network::SDN::Zones;
+
+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::SDN::Vnets;
+use PVE::Network::SDN::Zones::VlanPlugin;
+use PVE::Network::SDN::Zones::QinQPlugin;
+use PVE::Network::SDN::Zones::VxlanPlugin;
+use PVE::Network::SDN::Zones::EvpnPlugin;
+use PVE::Network::SDN::Zones::FaucetPlugin;
+use PVE::Network::SDN::Zones::Plugin;
+
+PVE::Network::SDN::Zones::VlanPlugin->register();
+PVE::Network::SDN::Zones::QinQPlugin->register();
+PVE::Network::SDN::Zones::VxlanPlugin->register();
+PVE::Network::SDN::Zones::EvpnPlugin->register();
+PVE::Network::SDN::Zones::FaucetPlugin->register();
+PVE::Network::SDN::Zones::Plugin->init();
+
+
+sub sdn_zones_config {
+ my ($cfg, $id, $noerr) = @_;
+
+ die "no sdn zone ID specified\n" if !$id;
+
+ my $scfg = $cfg->{ids}->{$id};
+ die "sdn '$id' does not exists\n" if (!$noerr && !$scfg);
+
+ return $scfg;
+}
+
+sub config {
+ my $config = cfs_read_file("sdn/zones.cfg.new");
+ $config = cfs_read_file("sdn/zones.cfg") if !keys %{$config->{ids}};
+ return $config;
+}
+
+sub write_config {
+ my ($cfg) = @_;
+
+ cfs_write_file("sdn/zones.cfg.new", $cfg);
+}
+
+sub lock_sdn_zones_config {
+ my ($code, $errmsg) = @_;
+
+ cfs_lock_file("sdn/zones.cfg.new", undef, $code);
+ if (my $err = $@) {
+ $errmsg ? die "$errmsg: $err" : die $err;
+ }
+}
+
+sub sdn_zones_ids {
+ my ($cfg) = @_;
+
+ return keys %{$cfg->{ids}};
+}
+
+sub complete_sdn_zone {
+ my ($cmdname, $pname, $cvalue) = @_;
+
+ my $cfg = PVE::Network::SDN::config();
+
+ return $cmdname eq 'add' ? [] : [ PVE::Network::SDN::sdn_zones_ids($cfg) ];
+}
+
+
+sub generate_etc_network_config {
+
+ my $vnet_cfg = PVE::Cluster::cfs_read_file('sdn/vnets.cfg');
+ my $transport_cfg = PVE::Cluster::cfs_read_file('sdn/zones.cfg');
+ return if !$vnet_cfg && !$transport_cfg;
+
+ #read main config for physical interfaces
+ my $current_config_file = "/etc/network/interfaces";
+ my $fh = IO::File->new($current_config_file);
+ my $interfaces_config = PVE::INotify::read_etc_network_interfaces(1,$fh);
+ $fh->close();
+
+ #check uplinks
+ my $uplinks = {};
+ foreach my $id (keys %{$interfaces_config->{ifaces}}) {
+ my $interface = $interfaces_config->{ifaces}->{$id};
+ if (my $uplink = $interface->{'uplink-id'}) {
+ die "uplink-id $uplink is already defined on $uplinks->{$uplink}" if $uplinks->{$uplink};
+ $interface->{name} = $id;
+ $uplinks->{$interface->{'uplink-id'}} = $interface;
+ }
+ }
+
+ #generate configuration
+ my $config = {};
+ foreach my $id (keys %{$vnet_cfg->{ids}}) {
+ my $vnet = $vnet_cfg->{ids}->{$id};
+ my $zone = $vnet->{transportzone};
+
+ if(!$zone) {
+ warn "can't generate vnet $vnet : zone $zone don't exist";
+ next;
+ }
+
+ my $plugin_config = $transport_cfg->{ids}->{$zone};
+
+ if (!defined($plugin_config)) {
+ warn "can't generate vnet $vnet : zone $zone don't exist";
+ next;
+ }
+
+ my $plugin = PVE::Network::SDN::Zones::Plugin->lookup($plugin_config->{type});
+ $plugin->generate_sdn_config($plugin_config, $zone, $id, $vnet, $uplinks, $config);
+ }
+
+ my $raw_network_config = "";
+ foreach my $iface (keys %$config) {
+ $raw_network_config .= "\n";
+ $raw_network_config .= "auto $iface\n";
+ $raw_network_config .= "iface $iface\n";
+ foreach my $option (@{$config->{$iface}}) {
+ $raw_network_config .= "\t$option\n";
+ }
+ }
+
+ return $raw_network_config;
+}
+
+sub write_etc_network_config {
+ my ($rawconfig) = @_;
+
+ return if !$rawconfig;
+ my $sdn_interfaces_file = "/etc/network/interfaces.d/sdn";
+
+ my $writefh = IO::File->new($sdn_interfaces_file,">");
+ print $writefh $rawconfig;
+ $writefh->close();
+}
+
+sub ifquery_check {
+
+ my $cmd = ['ifquery', '-a', '-c', '-o','json'];
+
+ my $result = '';
+ my $reader = sub { $result .= shift };
+
+ eval {
+ run_command($cmd, outfunc => $reader);
+ };
+
+ my $resultjson = decode_json($result);
+ my $interfaces = {};
+
+ foreach my $interface (@$resultjson) {
+ my $name = $interface->{name};
+ $interfaces->{$name} = {
+ status => $interface->{status},
+ config => $interface->{config},
+ config_status => $interface->{config_status},
+ };
+ }
+
+ return $interfaces;
+}
+
+# improve me : move status code inside plugins ?
+sub status {
+
+ my $cluster_vnet_file = "/etc/pve/sdn/vnets.cfg";
+ my $cluster_transport_file = "/etc/pve/sdn/zones.cfg";
+ my $local_sdn_file = "/etc/network/interfaces.d/sdn";
+ my $err_config = undef;
+
+ return if !-e $cluster_vnet_file && !-e $cluster_transport_file;
+
+ if (!-e $local_sdn_file) {
+ warn "local sdn network configuration is not yet generated, please reload";
+ $err_config = 'pending';
+ } else {
+ # fixme : use some kind of versioning info?
+ my $cluster_vnet_timestamp = (stat($cluster_vnet_file))[9];
+ my $cluster_transport_timestamp = (stat($cluster_transport_file))[9];
+ my $local_sdn_timestamp = (stat($local_sdn_file))[9];
+
+ if ($local_sdn_timestamp < $cluster_vnet_timestamp || $local_sdn_timestamp < $cluster_transport_timestamp) {
+ warn "local sdn network configuration is too old, please reload";
+ $err_config = 'unknown';
+ }
+ }
+
+ my $status = ifquery_check();
+
+ my $vnet_cfg = PVE::Cluster::cfs_read_file('sdn/vnets.cfg');
+
+ my $vnet_status = {};
+ my $transport_status = {};
+
+ foreach my $id (keys %{$vnet_cfg->{ids}}) {
+ my $transportzone = $vnet_cfg->{ids}->{$id}->{transportzone};
+ $vnet_status->{$id}->{transportzone} = $transportzone;
+ $transport_status->{$transportzone}->{status} = 'available' if !defined($transport_status->{$transportzone}->{status});
+
+ if($err_config) {
+ $vnet_status->{$id}->{status} = $err_config;
+ $transport_status->{$transportzone}->{status} = $err_config;
+ } elsif ($status->{$id}->{status} && $status->{$id}->{status} eq 'pass') {
+ $vnet_status->{$id}->{status} = 'available';
+ my $bridgeport = $status->{$id}->{config}->{'bridge-ports'};
+
+ if ($status->{$bridgeport}->{status} && $status->{$bridgeport}->{status} ne 'pass') {
+ $vnet_status->{$id}->{status} = 'error';
+ $transport_status->{$transportzone}->{status} = 'error';
+ }
+ } else {
+ $vnet_status->{$id}->{status} = 'error';
+ $transport_status->{$transportzone}->{status} = 'error';
+ }
+ }
+ return($transport_status, $vnet_status);
+}
+
+1;
+
diff --git a/PVE/Network/SDN/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm
similarity index 94%
rename from PVE/Network/SDN/EvpnPlugin.pm
rename to PVE/Network/SDN/Zones/EvpnPlugin.pm
index f570f2f..179ecc1 100644
--- a/PVE/Network/SDN/EvpnPlugin.pm
+++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -1,12 +1,12 @@
-package PVE::Network::SDN::EvpnPlugin;
+package PVE::Network::SDN::Zones::EvpnPlugin;
use strict;
use warnings;
-use PVE::Network::SDN::Plugin;
+use PVE::Network::SDN::Zones::VxlanPlugin;
use PVE::Tools qw($IPV4RE);
use PVE::INotify;
-use base('PVE::Network::SDN::VxlanPlugin');
+use base('PVE::Network::SDN::Zones::VxlanPlugin');
sub type {
return 'evpn';
@@ -67,7 +67,7 @@ sub generate_sdn_config {
if($uplinks->{$uplink}->{name}) {
$iface = $uplinks->{$uplink}->{name};
- $ifaceip = PVE::Network::SDN::Plugin::get_first_local_ipv4_from_interface($iface);
+ $ifaceip = PVE::Network::SDN::Zones::Plugin::get_first_local_ipv4_from_interface($iface);
}
my $mtu = 1450;
@@ -149,7 +149,7 @@ sub on_update_hook {
if(defined($sdn->{transportzone}) && $sdn->{transportzone} eq $transportid) {
my $tag = $sdn->{tag};
eval {
- PVE::Network::SDN::Plugin::parse_tag_number_or_range($vxlanallowed, '16777216', $tag);
+ PVE::Network::SDN::Zones::Plugin::parse_tag_number_or_range($vxlanallowed, '16777216', $tag);
};
if($@) {
die "vnet $id - vlan $tag is not allowed in transport $transportid";
diff --git a/PVE/Network/SDN/FaucetPlugin.pm b/PVE/Network/SDN/Zones/FaucetPlugin.pm
similarity index 92%
rename from PVE/Network/SDN/FaucetPlugin.pm
rename to PVE/Network/SDN/Zones/FaucetPlugin.pm
index 9422ee7..e914d4d 100644
--- a/PVE/Network/SDN/FaucetPlugin.pm
+++ b/PVE/Network/SDN/Zones/FaucetPlugin.pm
@@ -1,10 +1,10 @@
-package PVE::Network::SDN::FaucetPlugin;
+package PVE::Network::SDN::Zones::FaucetPlugin;
use strict;
use warnings;
-use PVE::Network::SDN::VlanPlugin;
+use PVE::Network::SDN::Zones::VlanPlugin;
-use base('PVE::Network::SDN::VlanPlugin');
+use base('PVE::Network::SDN::Zones::VlanPlugin');
sub type {
return 'faucet';
diff --git a/PVE/Network/SDN/Zones/Makefile b/PVE/Network/SDN/Zones/Makefile
new file mode 100644
index 0000000..ba9a4b5
--- /dev/null
+++ b/PVE/Network/SDN/Zones/Makefile
@@ -0,0 +1,8 @@
+SOURCES=Plugin.pm VlanPlugin.pm VxlanPlugin.pm FaucetPlugin.pm EvpnPlugin.pm QinQPlugin.pm
+
+
+PERL5DIR=${DESTDIR}/usr/share/perl5
+
+.PHONY: install
+install:
+ for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/Network/SDN/Zones/$$i; done
diff --git a/PVE/Network/SDN/Plugin.pm b/PVE/Network/SDN/Zones/Plugin.pm
similarity index 79%
rename from PVE/Network/SDN/Plugin.pm
rename to PVE/Network/SDN/Zones/Plugin.pm
index 0c6eaf0..7e820cd 100644
--- a/PVE/Network/SDN/Plugin.pm
+++ b/PVE/Network/SDN/Zones/Plugin.pm
@@ -1,4 +1,4 @@
-package PVE::Network::SDN::Plugin;
+package PVE::Network::SDN::Zones::Plugin;
use strict;
use warnings;
@@ -11,27 +11,27 @@ use Data::Dumper;
use PVE::JSONSchema qw(get_standard_option);
use base qw(PVE::SectionConfig);
-PVE::Cluster::cfs_register_file('sdn.cfg',
+PVE::Cluster::cfs_register_file('sdn/zones.cfg',
sub { __PACKAGE__->parse_config(@_); });
-PVE::Cluster::cfs_register_file('sdn.cfg.new',
+PVE::Cluster::cfs_register_file('sdn/zones.cfg.new',
sub { __PACKAGE__->parse_config(@_); },
sub { __PACKAGE__->write_config(@_); });
-PVE::JSONSchema::register_standard_option('pve-sdn-id', {
- description => "The SDN object identifier.",
- type => 'string', format => 'pve-sdn-id',
+PVE::JSONSchema::register_standard_option('pve-sdn-zone-id', {
+ description => "The SDN zone object identifier.",
+ type => 'string', format => 'pve-sdn-zone-id',
});
-PVE::JSONSchema::register_format('pve-sdn-id', \&parse_sdn_id);
-sub parse_sdn_id {
- my ($sdnid, $noerr) = @_;
+PVE::JSONSchema::register_format('pve-sdn-zone-id', \&parse_sdn_zone_id);
+sub parse_sdn_zone_id {
+ my ($id, $noerr) = @_;
- if ($sdnid !~ m/^[a-z][a-z0-9\-\_\.]*[a-z0-9]$/i) {
+ if ($id !~ m/^[a-z][a-z0-9\-\_\.]*[a-z0-9]$/i) {
return undef if $noerr;
- die "SDN object ID '$sdnid' contains illegal characters\n";
+ die "SDN zone object ID '$id' contains illegal characters\n";
}
- return $sdnid;
+ return $id;
}
my $defaultData = {
@@ -42,8 +42,8 @@ my $defaultData = {
type => 'string', format => 'pve-configid',
type => 'string',
},
- sdn => get_standard_option('pve-sdn-id',
- { completion => \&PVE::Network::SDN::complete_sdn }),
+ zone => get_standard_option('pve-sdn-zone-id',
+ { completion => \&PVE::Network::SDN::Zones::complete_sdn_zone }),
},
};
@@ -55,12 +55,12 @@ sub parse_section_header {
my ($class, $line) = @_;
if ($line =~ m/^(\S+):\s*(\S+)\s*$/) {
- my ($type, $sdnid) = (lc($1), $2);
+ 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, $sdnid, $errmsg, $config);
+ return ($type, $id, $errmsg, $config);
}
return undef;
}
diff --git a/PVE/Network/SDN/QinQPlugin.pm b/PVE/Network/SDN/Zones/QinQPlugin.pm
similarity index 88%
rename from PVE/Network/SDN/QinQPlugin.pm
rename to PVE/Network/SDN/Zones/QinQPlugin.pm
index 9f40e84..d90382c 100644
--- a/PVE/Network/SDN/QinQPlugin.pm
+++ b/PVE/Network/SDN/Zones/QinQPlugin.pm
@@ -1,23 +1,21 @@
-package PVE::Network::SDN::QinQPlugin;
+package PVE::Network::SDN::Zones::QinQPlugin;
use strict;
use warnings;
-use PVE::Network::SDN::VlanPlugin;
+use PVE::Network::SDN::Zones::VlanPlugin;
-use base('PVE::Network::SDN::VlanPlugin');
+use base('PVE::Network::SDN::Zones::VlanPlugin');
sub type {
return 'qinq';
}
-sub plugindata {
- return {
- role => 'transport',
- };
-}
-
sub properties {
return {
+ tag => {
+ type => 'integer',
+ description => "vlan tag",
+ },
'vlan-protocol' => {
type => 'string',
enum => ['802.1q', '802.1ad'],
diff --git a/PVE/Network/SDN/VlanPlugin.pm b/PVE/Network/SDN/Zones/VlanPlugin.pm
similarity index 89%
rename from PVE/Network/SDN/VlanPlugin.pm
rename to PVE/Network/SDN/Zones/VlanPlugin.pm
index 5a38f59..ab46d32 100644
--- a/PVE/Network/SDN/VlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VlanPlugin.pm
@@ -1,26 +1,20 @@
-package PVE::Network::SDN::VlanPlugin;
+package PVE::Network::SDN::Zones::VlanPlugin;
use strict;
use warnings;
-use PVE::Network::SDN::Plugin;
+use PVE::Network::SDN::Zones::Plugin;
-use base('PVE::Network::SDN::Plugin');
+use base('PVE::Network::SDN::Zones::Plugin');
sub type {
return 'vlan';
}
-sub plugindata {
- return {
- role => 'transport',
- };
-}
-
PVE::JSONSchema::register_format('pve-sdn-vlanrange', \&pve_verify_sdn_vlanrange);
sub pve_verify_sdn_vlanrange {
my ($vlanstr) = @_;
- PVE::Network::SDN::Plugin::parse_tag_number_or_range($vlanstr, '4096');
+ PVE::Network::SDN::Zones::Plugin::parse_tag_number_or_range($vlanstr, '4096');
return $vlanstr;
}
@@ -106,7 +100,7 @@ sub on_update_hook {
if(defined($sdn->{transportzone}) && $sdn->{transportzone} eq $transportid) {
my $tag = $sdn->{tag};
eval {
- PVE::Network::SDN::Plugin::parse_tag_number_or_range($vlanallowed, '4096', $tag);
+ PVE::Network::SDN::Zones::Plugin::parse_tag_number_or_range($vlanallowed, '4096', $tag);
};
if($@) {
die "vlan $tag is not allowed in transport $transportid";
diff --git a/PVE/Network/SDN/VxlanPlugin.pm b/PVE/Network/SDN/Zones/VxlanPlugin.pm
similarity index 93%
rename from PVE/Network/SDN/VxlanPlugin.pm
rename to PVE/Network/SDN/Zones/VxlanPlugin.pm
index 5a259b0..cccf93a 100644
--- a/PVE/Network/SDN/VxlanPlugin.pm
+++ b/PVE/Network/SDN/Zones/VxlanPlugin.pm
@@ -1,18 +1,18 @@
-package PVE::Network::SDN::VxlanPlugin;
+package PVE::Network::SDN::Zones::VxlanPlugin;
use strict;
use warnings;
-use PVE::Network::SDN::Plugin;
+use PVE::Network::SDN::Zones::Plugin;
use PVE::Tools qw($IPV4RE);
use PVE::INotify;
-use base('PVE::Network::SDN::Plugin');
+use base('PVE::Network::SDN::Zones::Plugin');
PVE::JSONSchema::register_format('pve-sdn-vxlanrange', \&pve_verify_sdn_vxlanrange);
sub pve_verify_sdn_vxlanrange {
my ($vxlanstr) = @_;
- PVE::Network::SDN::Plugin::parse_tag_number_or_range($vxlanstr, '16777216');
+ PVE::Network::SDN::Zones::Plugin::parse_tag_number_or_range($vxlanstr, '16777216');
return $vxlanstr;
}
@@ -40,12 +40,6 @@ sub type {
return 'vxlan';
}
-sub plugindata {
- return {
- role => 'transport',
- };
-}
-
sub properties {
return {
'vxlan-allowed' => {
@@ -94,7 +88,7 @@ sub generate_sdn_config {
if($uplinks->{$uplink}->{name}) {
$iface = $uplinks->{$uplink}->{name};
- $ifaceip = PVE::Network::SDN::Plugin::get_first_local_ipv4_from_interface($iface);
+ $ifaceip = PVE::Network::SDN::Zones::Plugin::get_first_local_ipv4_from_interface($iface);
}
my $mtu = 1450;
@@ -161,7 +155,7 @@ sub on_update_hook {
if(defined($sdn->{transportzone}) && $sdn->{transportzone} eq $transportid) {
my $tag = $sdn->{tag};
eval {
- PVE::Network::SDN::Plugin::parse_tag_number_or_range($vxlanallowed, '16777216', $tag);
+ PVE::Network::SDN::Zones::Plugin::parse_tag_number_or_range($vxlanallowed, '16777216', $tag);
};
if($@) {
die "vnet $id - vlan $tag is not allowed in transport $transportid";
diff --git a/test/generateconfig.pl b/test/generateconfig.pl
index da82672..36880ba 100644
--- a/test/generateconfig.pl
+++ b/test/generateconfig.pl
@@ -3,20 +3,19 @@ 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::generate_etc_network_config();
-PVE::Network::SDN::write_etc_network_config($network_config);
-print "/etc/network/interfaces\n";
+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::generate_controller_config();
+my $controller_config = PVE::Network::SDN::Controllers::generate_controller_config();
if ($controller_config) {
print Dumper($controller_config);
- PVE::Network::SDN::write_controller_config($controller_config);
- print "/etc/frr/frr.conf\n";
+ PVE::Network::SDN::Controllers::write_controller_config($controller_config);
}
--
2.20.1
More information about the pve-devel
mailing list