]> git.proxmox.com Git - pve-network.git/commitdiff
make sdn controller plugin generic
authorAlexandre Derumier <aderumier@odiso.com>
Mon, 30 Sep 2019 09:03:32 +0000 (11:03 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Thu, 17 Oct 2019 17:25:49 +0000 (19:25 +0200)
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@odiso.com>
PVE/Network/SDN.pm
PVE/Network/SDN/FrrPlugin.pm
PVE/Network/SDN/Plugin.pm
PVE/Network/SDN/VlanPlugin.pm
PVE/Network/SDN/VnetPlugin.pm
PVE/Network/SDN/VxlanPlugin.pm
test/documentation.txt
test/generateconfig.pl

index 101464b0a47c7ffc6bf20ed9cf53d12c327003a6..1e5ba676a660af5f3b5da5dcfd46acdfbc5b7a7c 100644 (file)
@@ -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";
index b0e36fadba26d50ae533f1106a4211645719ddce..455b1852fc9ea24a5700f37158707e52377d50a8 100644 (file)
@@ -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;
 
index 1c580498d6ab18485c5c99d85c5d35843ad73d19..9428aead72e76a7851042f00606dc8b7e36774c7 100644 (file)
@@ -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) = @_;
 
index 2af24b7b5d83512f816f2377b9b71dfdaf21e64b..60782064a11bc3e24c450b074e13baf8b5860f07 100644 (file)
@@ -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) = @_;
index e8aa2042002fd0efbeebd5bbae71df50615d07e2..e9185645116ceb1f1d8303e3f493ad8954292233 100644 (file)
@@ -12,6 +12,12 @@ sub type {
     return 'vnet';
 }
 
+sub plugindata {
+    return {
+        role => 'vnet',
+    };
+}
+
 sub properties {
     return {
        transportzone => {
index 1860490fd63aaa4bbcab3e5a795cc4f053a05c8e..986a250a7629357c8a273effd38a8cc11fa80b8f 100644 (file)
@@ -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;
index ecaf4bd2f80b56aa3612255ccef0290b886331d5..785b21c6b9ee263122a66b6c8f0c2988d3526358 100644 (file)
@@ -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
index dda9b8e810c2da1578b9c15c27816e2e90f1ccc0..da826727a229d0caaac7b73acf971e98bbb704c6 100644 (file)
@@ -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;
 }