[pve-devel] [PATCH v2 pve-network 10/13] sdn: add generate_frr_config

Alexandre Derumier aderumier at odiso.com
Thu Aug 29 12:32:51 CEST 2019


Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
 PVE/Network/SDN.pm             | 94 ++++++++++++++++++++++++++++++----
 PVE/Network/SDN/FrrPlugin.pm   | 15 ++----
 PVE/Network/SDN/VlanPlugin.pm  |  4 +-
 PVE/Network/SDN/VxlanPlugin.pm | 55 ++++++++++++++++++--
 test/generateconfig.pl         |  5 +-
 5 files changed, 145 insertions(+), 28 deletions(-)

diff --git a/PVE/Network/SDN.pm b/PVE/Network/SDN.pm
index 9d8006e..80a70d8 100644
--- a/PVE/Network/SDN.pm
+++ b/PVE/Network/SDN.pm
@@ -149,27 +149,103 @@ sub generate_etc_network_config {
 	$plugin->generate_sdn_config($plugin_config, $zone, $id, $vnet, $uplinks, $config);
     }
 
-    my $network_config = $config->{network};
     my $raw_network_config = "";
-    foreach my $iface (keys %$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 (@{$network_config->{$iface}}) {
+	foreach my $option (@{$config->{$iface}}) {
 	    $raw_network_config .= "\t$option\n";
 	}
     }
 
-    my $frr_config = $config->{frr};
-    my $raw_frr_config = "";
-    foreach my $asn (keys %$frr_config) {
-	$raw_frr_config .= "router bgp $asn";
-	foreach my $option (@{$frr_config->{$asn}}) {
+    return $raw_network_config;
+}
+
+sub generate_frr_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 $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};
+	}
+    }
+
+    #generate configuration
+    my $config = {};
+
+    foreach my $id (keys %{$frr_cfg->{ids}}) {
+	my $plugin_config = $frr_cfg->{ids}->{$id};
+	my $asn = $plugin_config->{asn};
+	if ($asn) {
+	    my $plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type});
+	    $plugin->generate_frr_config($plugin_config, $asn, $id, $uplinks, $config);
+	}
+    }
+
+    foreach my $id (keys %{$transport_cfg->{ids}}) {
+	my $plugin_config = $transport_cfg->{ids}->{$id};
+	my $router = $plugin_config->{router};
+	if ($router) {
+	    my $asn = $frr_cfg->{ids}->{$router}->{asn};
+	    if ($asn) {
+		my $plugin = PVE::Network::SDN::Plugin->lookup($plugin_config->{type});
+		$plugin->generate_frr_config($plugin_config, $asn, $id, $uplinks, $config);
+	    }
+	}
+    }
+
+    my $raw_frr_config = "log syslog informational\n";
+    $raw_frr_config .= "!\n";
+
+    #vrf first
+    my $vrfconfig = $config->{vrf};
+    foreach my $vrf (sort keys %$vrfconfig) {
+	$raw_frr_config .= "$vrf\n";
+	foreach my $option (@{$vrfconfig->{$vrf}}) {
 	    $raw_frr_config .= " $option\n";
 	}
+	$raw_frr_config .= "!\n";
     }
 
-    return wantarray ? ($raw_network_config, $raw_frr_config) : $raw_network_config;
+    #routers
+    my $routerconfig = $config->{router};
+    foreach my $router (sort keys %$routerconfig) {
+	$raw_frr_config .= "$router\n";
+	foreach my $option (@{$routerconfig->{$router}}) {
+	    $raw_frr_config .= " $option\n";
+	}
+	$raw_frr_config .= "!\n";
+    }
+
+    $raw_frr_config .= "line vty\n";
+    $raw_frr_config .= "!\n";
+
+    return $raw_frr_config;
 }
 
 sub write_etc_network_config {
diff --git a/PVE/Network/SDN/FrrPlugin.pm b/PVE/Network/SDN/FrrPlugin.pm
index 80ca417..0ea6d48 100644
--- a/PVE/Network/SDN/FrrPlugin.pm
+++ b/PVE/Network/SDN/FrrPlugin.pm
@@ -34,27 +34,23 @@ sub options {
 }
 
 # Plugin implementation
-sub generate_sdn_config {
-    my ($class, $plugin_config, $zoneid, $vnetid, $vnet, $uplinks, $config) = @_;
+sub generate_frr_config {
+    my ($class, $plugin_config, $asn, $id, $uplinks, $config) = @_;
 
-    my $asn = $plugin_config->{'asn'};
     my @peers = split(',', $plugin_config->{'peers'}) if $plugin_config->{'peers'};
 
     my $uplink = $plugin_config->{'uplink-id'};
 
-    die "missing peers" if !$plugin_config->{'peers'};
-
     my $iface = "uplink$uplink";
     my $ifaceip = "";
 
     if($uplinks->{$uplink}->{name}) {
 	$iface = $uplinks->{$uplink}->{name};
-	$ifaceip = get_first_local_ipv4_from_interface($iface);
+        $ifaceip = PVE::Network::SDN::Plugin::get_first_local_ipv4_from_interface($iface);
     }
 
     my @router_config = ();
 
-    push @router_config, "router bgp $asn";
     push @router_config, "bgp router-id $ifaceip";
     push @router_config, "coalesce-time 1000";
 
@@ -70,11 +66,8 @@ sub generate_sdn_config {
     }
     push @router_config, " advertise-all-vni";
     push @router_config, "exit-address-family";
-    push @router_config, "!";
-    push @router_config, "line vty";
-    push @router_config, "!";
 
-    push(@{$config->{frr}->{$asn}}, @router_config);
+    push(@{$config->{router}->{"router bgp $asn"}}, @router_config);
 
     return $config;
 }
diff --git a/PVE/Network/SDN/VlanPlugin.pm b/PVE/Network/SDN/VlanPlugin.pm
index d2b7475..2af24b7 100644
--- a/PVE/Network/SDN/VlanPlugin.pm
+++ b/PVE/Network/SDN/VlanPlugin.pm
@@ -77,7 +77,7 @@ sub generate_sdn_config {
     my @iface_config = ();
     push @iface_config, "vlan-protocol $vlanprotocol" if $vlanprotocol;
     push @iface_config, "mtu $mtu" if $mtu;
-    push(@{$config->{network}->{$iface}}, @iface_config) if !$config->{network}->{$iface};
+    push(@{$config->{$iface}}, @iface_config) if !$config->{$iface};
 
     #vnet bridge
     @iface_config = ();
@@ -87,7 +87,7 @@ sub generate_sdn_config {
     push @iface_config, "bridge-vlan-aware yes" if $vlanaware;
     push @iface_config, "mtu $mtu" if $mtu;
     push @iface_config, "alias $alias" if $alias;
-    push(@{$config->{network}->{$vnetid}}, @iface_config) if !$config->{network}->{$vnetid};
+    push(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid};
 
     return $config;
 }
diff --git a/PVE/Network/SDN/VxlanPlugin.pm b/PVE/Network/SDN/VxlanPlugin.pm
index 6e247a7..99cd2af 100644
--- a/PVE/Network/SDN/VxlanPlugin.pm
+++ b/PVE/Network/SDN/VxlanPlugin.pm
@@ -42,6 +42,10 @@ sub properties {
 	    type => 'integer',
 	    description => "l3vni.",
 	},
+	'router' => {
+	    type => 'string',
+	    description => "Frr router name",
+	},
     };
 }
 
@@ -54,6 +58,7 @@ sub options {
         'vxlan-allowed' => { optional => 1 },
         'vrf' => { optional => 1 },
         'vrf-vxlan' => { optional => 1 },
+        'router' => { optional => 1 },
     };
 }
 
@@ -107,7 +112,7 @@ sub generate_sdn_config {
     }
 
     push @iface_config, "mtu $mtu" if $mtu;
-    push(@{$config->{network}->{"vxlan$vnetid"}}, @iface_config) if !$config->{network}->{"vxlan$vnetid"};
+    push(@{$config->{"vxlan$vnetid"}}, @iface_config) if !$config->{"vxlan$vnetid"};
 
     #vnet bridge
     @iface_config = ();
@@ -120,13 +125,13 @@ sub generate_sdn_config {
     push @iface_config, "mtu $mtu" if $mtu;
     push @iface_config, "alias $alias" if $alias;
     push @iface_config, "vrf $vrf" if $vrf;
-    push(@{$config->{network}->{$vnetid}}, @iface_config) if !$config->{network}->{$vnetid};
+    push(@{$config->{$vnetid}}, @iface_config) if !$config->{$vnetid};
 
     if ($vrf) {
 	#vrf intreface
 	@iface_config = ();
 	push @iface_config, "vrf-table auto";
-	push(@{$config->{network}->{$vrf}}, @iface_config) if !$config->{network}->{$vrf};
+	push(@{$config->{$vrf}}, @iface_config) if !$config->{$vrf};
 
 	if ($vrfvxlan) {
 	    #l3vni vxlan interface
@@ -137,7 +142,7 @@ sub generate_sdn_config {
 	    push @iface_config, "bridge-learning off";
 	    push @iface_config, "bridge-arp-nd-suppress on";
 	    push @iface_config, "mtu $mtu" if $mtu;
-	    push(@{$config->{network}->{$iface_vxlan}}, @iface_config) if !$config->{network}->{$iface_vxlan};
+	    push(@{$config->{$iface_vxlan}}, @iface_config) if !$config->{$iface_vxlan};
 
 	    #l3vni bridge
 	    my $brvrf = "br$vrf";
@@ -147,13 +152,53 @@ sub generate_sdn_config {
 	    push @iface_config, "bridge_fd 0";
 	    push @iface_config, "mtu $mtu" if $mtu;
 	    push @iface_config, "vrf $vrf";
-	    push(@{$config->{network}->{$brvrf}}, @iface_config) if !$config->{network}->{$brvrf};
+	    push(@{$config->{$brvrf}}, @iface_config) if !$config->{$brvrf};
 	}
     }
 
     return $config;
 }
 
+sub generate_frr_config {
+    my ($class, $plugin_config, $asn, $id, $uplinks, $config) = @_;
+
+    my $vrf = $plugin_config->{'vrf'};
+    my $vrfvxlan = $plugin_config->{'vrf-vxlan'};
+    return if !$vrf || !$vrfvxlan;
+
+    my $uplink = $plugin_config->{'uplink-id'};
+
+    my $iface = "uplink$uplink";
+    my $ifaceip = "";
+
+    if($uplinks->{$uplink}->{name}) {
+        $iface = $uplinks->{$uplink}->{name};
+        $ifaceip = PVE::Network::SDN::Plugin::get_first_local_ipv4_from_interface($iface);
+    }
+
+    #vrf
+    my @router_config = ();
+    push @router_config, "vni $vrfvxlan";
+    push @router_config, "exit-vrf";
+    push(@{$config->{vrf}->{"vrf $vrf"}}, @router_config);
+
+
+    #vrf router
+    @router_config = ();
+    push @router_config, "bgp router-id $ifaceip";
+    push @router_config, "!";
+    push @router_config, "address-family ipv4 unicast";
+    push @router_config, " redistribute connected";
+    push @router_config, "exit-address-family";
+    push @router_config, "!";
+    push @router_config, "address-family l2vpn evpn";
+    push @router_config, " advertise ipv4 unicast";
+    push @router_config, "exit-address-family";
+    push(@{$config->{router}->{"router bgp $asn vrf $vrf"}}, @router_config);
+
+    return $config;
+}
+
 sub on_delete_hook {
     my ($class, $transportid, $sdn_cfg) = @_;
 
diff --git a/test/generateconfig.pl b/test/generateconfig.pl
index 6d8b80a..6003f94 100644
--- a/test/generateconfig.pl
+++ b/test/generateconfig.pl
@@ -6,7 +6,10 @@ use PVE::Cluster qw(cfs_read_file);
 use PVE::Network::SDN;
 
 
-my ($network_config, $frr_config) = PVE::Network::SDN::generate_etc_network_config();
+my $network_config = PVE::Network::SDN::generate_etc_network_config();
 PVE::Network::SDN::write_etc_network_config($network_config);
 print $network_config;
+
+
+my $frr_config = PVE::Network::SDN::generate_frr_config();
 print $frr_config;
-- 
2.20.1



More information about the pve-devel mailing list