[pve-devel] [PATCH pve-network 1/8] make sdn controller plugin generic
Alexandre Derumier
aderumier at odiso.com
Mon Sep 30 11:03:32 CEST 2019
move all code for frr to frrplugin,
rename router option to controller.
This will allow to manage more controller in the future (ovn, faucet,....)
Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
PVE/Network/SDN.pm | 148 +++++++--------------------------
PVE/Network/SDN/FrrPlugin.pm | 114 +++++++++++++++++++++++--
PVE/Network/SDN/Plugin.pm | 8 +-
PVE/Network/SDN/VlanPlugin.pm | 6 ++
PVE/Network/SDN/VnetPlugin.pm | 6 ++
PVE/Network/SDN/VxlanPlugin.pm | 24 ++++--
test/documentation.txt | 6 +-
test/generateconfig.pl | 10 +--
8 files changed, 179 insertions(+), 143 deletions(-)
diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm
index 101464b..1e5ba67 100644
--- a/PVE/Network/SDN.pm
+++ b/PVE/Network/SDN.pm
@@ -162,7 +162,7 @@ sub generate_etc_network_config {
return $raw_network_config;
}
-sub generate_frr_config {
+sub generate_controller_config {
my $sdn_cfg = PVE::Cluster::cfs_read_file('sdn.cfg');
return if !$sdn_cfg;
@@ -184,124 +184,31 @@ sub generate_frr_config {
}
}
- my $frr_cfg = undef;
- my $transport_cfg = undef;
-
- foreach my $id (keys %{$sdn_cfg->{ids}}) {
- if ($sdn_cfg->{ids}->{$id}->{type} eq 'frr') {
- $frr_cfg->{ids}->{$id} = $sdn_cfg->{ids}->{$id};
- } elsif ($sdn_cfg->{ids}->{$id}->{type} ne 'vnet') {
- $transport_cfg->{ids}->{$id} = $sdn_cfg->{ids}->{$id};
- }
- }
-
- return undef if !$frr_cfg;
-
#generate configuration
my $config = {};
- foreach my $id (sort keys %{$frr_cfg->{ids}}) {
- my $plugin_config = $frr_cfg->{ids}->{$id};
+ foreach my $id (keys %{$sdn_cfg->{ids}}) {
+ my $plugin_config = $sdn_cfg->{ids}->{$id};
my $plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type});
- $plugin->generate_frr_config($plugin_config, $plugin_config, $id, $uplinks, $config);
- }
-
- foreach my $id (sort keys %{$transport_cfg->{ids}}) {
- my $plugin_config = $transport_cfg->{ids}->{$id};
- my $routerid = $plugin_config->{router};
- if ($routerid) {
- my $router = $frr_cfg->{ids}->{$routerid};
- if ($router) {
- my $plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type});
- $plugin->generate_frr_config($plugin_config, $router, $id, $uplinks, $config);
+ 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($plugin_config->{type});
+ $controller_plugin->generate_controller_config($plugin_config, $controller, $id, $uplinks, $config);
+ }
}
}
}
- my $final_config = [];
- push @{$final_config}, "log syslog informational";
- push @{$final_config}, "!";
-
- generate_frr_recurse($final_config, $config, undef, 0);
-
- push @{$final_config}, "!";
- push @{$final_config}, "line vty";
- push @{$final_config}, "!";
-
- my $raw_frr_config = join("\n", @{$final_config});
- return $raw_frr_config;
-}
-
-sub sort_frr_config {
- my $order = {};
- $order->{''} = 0;
- $order->{'vrf'} = 1;
- $order->{'ipv4 unicast'} = 1;
- $order->{'ipv6 unicast'} = 2;
- $order->{'l2vpn evpn'} = 3;
-
- my $a_val = 100;
- my $b_val = 100;
-
- $a_val = $order->{$a} if defined($order->{$a});
- $b_val = $order->{$b} if defined($order->{$b});
-
- if($a =~ /bgp (\d+)$/) {
- $a_val = 2;
- }
-
- if($b =~ /bgp (\d+)$/) {
- $b_val = 2;
- }
-
- return $a_val <=> $b_val;
+ return $config;
}
-sub generate_frr_recurse{
- my ($final_config, $content, $parentkey, $level) = @_;
-
- my $keylist = {};
- $keylist->{vrf} = 1;
- $keylist->{'address-family'} = 1;
- $keylist->{router} = 1;
-
- my $exitkeylist = {};
- $exitkeylist->{vrf} = 1;
- $exitkeylist->{'address-family'} = 1;
-
- #fix me, make this generic
- my $paddinglevel = undef;
- if($level == 1 || $level == 2) {
- $paddinglevel = $level - 1;
- } elsif ($level == 3 || $level == 4) {
- $paddinglevel = $level - 2;
- }
-
- my $padding = "";
- $padding = ' ' x ($paddinglevel) if $paddinglevel;
-
- if (ref $content eq ref {}) {
- foreach my $key (sort sort_frr_config keys %$content) {
- if ($parentkey && defined($keylist->{$parentkey})) {
- push @{$final_config}, $padding."!";
- push @{$final_config}, $padding."$parentkey $key";
- } else {
- push @{$final_config}, $padding."$key" if $key ne '' && !defined($keylist->{$key});
- }
-
- my $option = $content->{$key};
- generate_frr_recurse($final_config, $option, $key, $level+1);
-
- push @{$final_config}, $padding."exit-$parentkey" if $parentkey && defined($exitkeylist->{$parentkey});
- }
- }
-
- if (ref $content eq 'ARRAY') {
- foreach my $value (@$content) {
- push @{$final_config}, $padding."$value";
- }
- }
-}
sub write_etc_network_config {
my ($rawconfig) = @_;
@@ -313,20 +220,23 @@ sub write_etc_network_config {
$writefh->close();
}
-sub write_frr_config {
- my ($rawconfig) = @_;
+sub write_controller_config {
+ my ($config) = @_;
- return if !$rawconfig;
- return if !-d "/etc/frr";
-
- my $frr_config_file = "/etc/frr/frr.conf";
+ my $sdn_cfg = PVE::Cluster::cfs_read_file('sdn.cfg');
+ return if !$sdn_cfg;
- my $writefh = IO::File->new($frr_config_file,">");
- print $writefh $rawconfig;
- $writefh->close();
+ 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";
diff --git a/PVE/Network/SDN/FrrPlugin.pm b/PVE/Network/SDN/FrrPlugin.pm
index b0e36fa..455b185 100644
--- a/PVE/Network/SDN/FrrPlugin.pm
+++ b/PVE/Network/SDN/FrrPlugin.pm
@@ -13,6 +13,12 @@ sub type {
return 'frr';
}
+sub plugindata {
+ return {
+ role => 'controller',
+ };
+}
+
sub properties {
return {
'asn' => {
@@ -43,7 +49,7 @@ sub options {
}
# Plugin implementation
-sub generate_frr_config {
+sub generate_controller_config {
my ($class, $plugin_config, $router, $id, $uplinks, $config) = @_;
my @peers = split(',', $plugin_config->{'peers'}) if $plugin_config->{'peers'};
@@ -86,7 +92,7 @@ sub generate_frr_config {
push @router_config, "neighbor $address remote-as external";
}
}
- push(@{$config->{router}->{"bgp $asn"}->{""}}, @router_config);
+ push(@{$config->{frr}->{router}->{"bgp $asn"}->{""}}, @router_config);
@router_config = ();
foreach my $address (@peers) {
@@ -94,7 +100,7 @@ sub generate_frr_config {
push @router_config, "neighbor $address activate";
}
push @router_config, "advertise-all-vni";
- push(@{$config->{router}->{"bgp $asn"}->{"address-family"}->{"l2vpn evpn"}}, @router_config);
+ push(@{$config->{frr}->{router}->{"bgp $asn"}->{"address-family"}->{"l2vpn evpn"}}, @router_config);
if ($is_gateway) {
@@ -105,8 +111,8 @@ sub generate_frr_config {
foreach my $address (@gatewaypeers) {
push @router_config, "neighbor $address activate";
}
- push(@{$config->{router}->{"bgp $asn"}->{"address-family"}->{"ipv4 unicast"}}, @router_config);
- push(@{$config->{router}->{"bgp $asn"}->{"address-family"}->{"ipv6 unicast"}}, @router_config);
+ push(@{$config->{frr}->{router}->{"bgp $asn"}->{"address-family"}->{"ipv4 unicast"}}, @router_config);
+ push(@{$config->{frr}->{router}->{"bgp $asn"}->{"address-family"}->{"ipv6 unicast"}}, @router_config);
}
@@ -137,6 +143,102 @@ sub on_update_hook {
}
}
-1;
+sub sort_frr_config {
+ my $order = {};
+ $order->{''} = 0;
+ $order->{'vrf'} = 1;
+ $order->{'ipv4 unicast'} = 1;
+ $order->{'ipv6 unicast'} = 2;
+ $order->{'l2vpn evpn'} = 3;
+
+ my $a_val = 100;
+ my $b_val = 100;
+
+ $a_val = $order->{$a} if defined($order->{$a});
+ $b_val = $order->{$b} if defined($order->{$b});
+
+ if($a =~ /bgp (\d+)$/) {
+ $a_val = 2;
+ }
+
+ if($b =~ /bgp (\d+)$/) {
+ $b_val = 2;
+ }
+
+ return $a_val <=> $b_val;
+}
+
+sub generate_frr_recurse{
+ my ($final_config, $content, $parentkey, $level) = @_;
+
+ my $keylist = {};
+ $keylist->{vrf} = 1;
+ $keylist->{'address-family'} = 1;
+ $keylist->{router} = 1;
+
+ my $exitkeylist = {};
+ $exitkeylist->{vrf} = 1;
+ $exitkeylist->{'address-family'} = 1;
+
+ #fix me, make this generic
+ my $paddinglevel = undef;
+ if($level == 1 || $level == 2) {
+ $paddinglevel = $level - 1;
+ } elsif ($level == 3 || $level == 4) {
+ $paddinglevel = $level - 2;
+ }
+
+ my $padding = "";
+ $padding = ' ' x ($paddinglevel) if $paddinglevel;
+
+ if (ref $content eq ref {}) {
+ foreach my $key (sort sort_frr_config keys %$content) {
+ if ($parentkey && defined($keylist->{$parentkey})) {
+ push @{$final_config}, $padding."!";
+ push @{$final_config}, $padding."$parentkey $key";
+ } else {
+ push @{$final_config}, $padding."$key" if $key ne '' && !defined($keylist->{$key});
+ }
+
+ my $option = $content->{$key};
+ generate_frr_recurse($final_config, $option, $key, $level+1);
+
+ push @{$final_config}, $padding."exit-$parentkey" if $parentkey && defined($exitkeylist->{$parentkey});
+ }
+ }
+ if (ref $content eq 'ARRAY') {
+ foreach my $value (@$content) {
+ push @{$final_config}, $padding."$value";
+ }
+ }
+}
+
+sub write_controller_config {
+ my ($class, $plugin_config, $config) = @_;
+
+ my $final_config = [];
+ push @{$final_config}, "log syslog informational";
+ push @{$final_config}, "!";
+
+ generate_frr_recurse($final_config, $config->{frr}, undef, 0);
+
+ push @{$final_config}, "!";
+ push @{$final_config}, "line vty";
+ push @{$final_config}, "!";
+
+ my $rawconfig = join("\n", @{$final_config});
+
+
+ return if !$rawconfig;
+ return if !-d "/etc/frr";
+
+ my $frr_config_file = "/etc/frr/frr.conf";
+
+ my $writefh = IO::File->new($frr_config_file,">");
+ print $writefh $rawconfig;
+ $writefh->close();
+}
+
+1;
diff --git a/PVE/Network/SDN/Plugin.pm b/PVE/Network/SDN/Plugin.pm
index 1c58049..9428aea 100644
--- a/PVE/Network/SDN/Plugin.pm
+++ b/PVE/Network/SDN/Plugin.pm
@@ -71,12 +71,18 @@ sub generate_sdn_config {
die "please implement inside plugin";
}
-sub generate_frr_config {
+sub generate_controller_config {
my ($class, $plugin_config, $router, $id, $uplinks, $config) = @_;
die "please implement inside plugin";
}
+sub write_controller_config {
+ my ($class, $plugin_config, $config) = @_;
+
+ die "please implement inside plugin";
+}
+
sub on_delete_hook {
my ($class, $sndid, $scfg) = @_;
diff --git a/PVE/Network/SDN/VlanPlugin.pm b/PVE/Network/SDN/VlanPlugin.pm
index 2af24b7..6078206 100644
--- a/PVE/Network/SDN/VlanPlugin.pm
+++ b/PVE/Network/SDN/VlanPlugin.pm
@@ -10,6 +10,12 @@ 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) = @_;
diff --git a/PVE/Network/SDN/VnetPlugin.pm b/PVE/Network/SDN/VnetPlugin.pm
index e8aa204..e918564 100644
--- a/PVE/Network/SDN/VnetPlugin.pm
+++ b/PVE/Network/SDN/VnetPlugin.pm
@@ -12,6 +12,12 @@ sub type {
return 'vnet';
}
+sub plugindata {
+ return {
+ role => 'vnet',
+ };
+}
+
sub properties {
return {
transportzone => {
diff --git a/PVE/Network/SDN/VxlanPlugin.pm b/PVE/Network/SDN/VxlanPlugin.pm
index 1860490..986a250 100644
--- a/PVE/Network/SDN/VxlanPlugin.pm
+++ b/PVE/Network/SDN/VxlanPlugin.pm
@@ -40,6 +40,12 @@ sub type {
return 'vxlan';
}
+sub plugindata {
+ return {
+ role => 'transport',
+ };
+}
+
sub properties {
return {
'vxlan-allowed' => {
@@ -62,7 +68,7 @@ sub properties {
type => 'integer',
description => "l3vni.",
},
- 'router' => {
+ 'controller' => {
type => 'string',
description => "Frr router name",
},
@@ -78,7 +84,7 @@ sub options {
'vxlan-allowed' => { optional => 1 },
'vrf' => { optional => 1 },
'vrf-vxlan' => { optional => 1 },
- 'router' => { optional => 1 },
+ 'controller' => { optional => 1 },
};
}
@@ -182,7 +188,7 @@ sub generate_sdn_config {
return $config;
}
-sub generate_frr_config {
+sub generate_controller_config {
my ($class, $plugin_config, $router, $id, $uplinks, $config) = @_;
my $vrf = $plugin_config->{'vrf'};
@@ -195,7 +201,7 @@ sub generate_frr_config {
#vrf
my @router_config = ();
push @router_config, "vni $vrfvxlan";
- push(@{$config->{vrf}->{"$vrf"}}, @router_config);
+ push(@{$config->{frr}->{vrf}->{"$vrf"}}, @router_config);
@router_config = ();
@@ -213,20 +219,20 @@ sub generate_frr_config {
#frr 7.1 tag is bugged -> works fine with 7.1 stable branch(20190829-02-g6ba76bbc1)
#https://github.com/FRRouting/frr/issues/4905
push @router_config, "import vrf $vrf";
- push(@{$config->{router}->{"bgp $asn"}->{"address-family"}->{"ipv4 unicast"}}, @router_config);
- push(@{$config->{router}->{"bgp $asn"}->{"address-family"}->{"ipv6 unicast"}}, @router_config);
+ push(@{$config->{frr}->{router}->{"bgp $asn"}->{"address-family"}->{"ipv4 unicast"}}, @router_config);
+ push(@{$config->{frr}->{router}->{"bgp $asn"}->{"address-family"}->{"ipv6 unicast"}}, @router_config);
@router_config = ();
#redistribute connected to be able to route to local vms on the gateway
push @router_config, "redistribute connected";
- push(@{$config->{router}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"ipv4 unicast"}}, @router_config);
- push(@{$config->{router}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"ipv6 unicast"}}, @router_config);
+ push(@{$config->{frr}->{router}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"ipv4 unicast"}}, @router_config);
+ push(@{$config->{frr}->{router}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"ipv6 unicast"}}, @router_config);
@router_config = ();
#add default originate to announce 0.0.0.0/0 type5 route in evpn
push @router_config, "default-originate ipv4";
push @router_config, "default-originate ipv6";
- push(@{$config->{router}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"l2vpn evpn"}}, @router_config);
+ push(@{$config->{frr}->{router}->{"bgp $asn vrf $vrf"}->{"address-family"}->{"l2vpn evpn"}}, @router_config);
}
return $config;
diff --git a/test/documentation.txt b/test/documentation.txt
index ecaf4bd..785b21c 100644
--- a/test/documentation.txt
+++ b/test/documentation.txt
@@ -11,14 +11,14 @@ pvesh create /cluster/sdn/ --sdn vxlanmulticastzone --type vxlan --uplink-id 1 -
#create a layer2 vxlan unicast transportzone
pvesh create /cluster/sdn/ --sdn vxlanunicastzone --type vxlan --uplink-id 1 --unicast-address 192.168.0.1,192.168.0.2,192.168.0.3
-#create a frr router
+#create a frr controller
pvesh create /cluster/sdn/ --sdn frrrouter1 --type frr --uplink-id 1 --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/ --sdn layer2evpnzone --type vxlan --uplink-id 1 --router frrrouter1
+pvesh create /cluster/sdn/ --sdn layer2evpnzone --type vxlan --uplink-id 1 --controller frrrouter1
#create a layer3 routable vxlan bgpevpn transportzone
-pvesh create /cluster/sdn/ --sdn layer3evpnzone --type vxlan --uplink-id 1 --router frrrouter1 --vrf vrf1 --vrf-vxlan 4000
+pvesh create /cluster/sdn/ --sdn layer3evpnzone --type vxlan --uplink-id 1 --controller frrrouter1 --vrf vrf1 --vrf-vxlan 4000
#create a vnet in the transportzone
diff --git a/test/generateconfig.pl b/test/generateconfig.pl
index dda9b8e..da82672 100644
--- a/test/generateconfig.pl
+++ b/test/generateconfig.pl
@@ -4,7 +4,7 @@ use File::Copy;
use PVE::Cluster qw(cfs_read_file);
use PVE::Network::SDN;
-
+use Data::Dumper;
my $network_config = PVE::Network::SDN::generate_etc_network_config();
@@ -14,9 +14,9 @@ print $network_config;
print "\n";
-my $frr_config = PVE::Network::SDN::generate_frr_config();
-if ($frr_config) {
- PVE::Network::SDN::write_frr_config($frr_config);
+my $controller_config = PVE::Network::SDN::generate_controller_config();
+if ($controller_config) {
+ print Dumper($controller_config);
+ PVE::Network::SDN::write_controller_config($controller_config);
print "/etc/frr/frr.conf\n";
- print $frr_config;
}
--
2.20.1
More information about the pve-devel
mailing list