[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