Signed-off-by: Alexandre Derumier <aderum...@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 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel