[pve-devel] [PATCH network] sdn: factor out frr config generation and writing
Gabriel Goller
g.goller at proxmox.com
Wed Feb 5 17:13:40 CET 2025
Previously the frr config generation and writing was only done in the
evpn plugin. This means that it was not possible to create a standalone
bgp and isis plugin without an evpn plugin in place. (The config would
just never be written.) To fix this, factor out the frr generation and
writing into a separate module and check if a frr-type-plugin is being
used. This also paves the way for the fabrics, which would get the
config from rust and then use this frr helper.
Signed-off-by: Gabriel Goller <g.goller at proxmox.com>
---
src/PVE/Network/SDN/Controllers.pm | 47 ++-
src/PVE/Network/SDN/Controllers/BgpPlugin.pm | 18 +-
src/PVE/Network/SDN/Controllers/EvpnPlugin.pm | 289 +----------------
src/PVE/Network/SDN/Controllers/Frr.pm | 296 ++++++++++++++++++
src/PVE/Network/SDN/Controllers/IsisPlugin.pm | 18 +-
src/PVE/Network/SDN/Controllers/Makefile | 2 +-
src/PVE/Network/SDN/Zones/EvpnPlugin.pm | 15 +
7 files changed, 383 insertions(+), 302 deletions(-)
create mode 100644 src/PVE/Network/SDN/Controllers/Frr.pm
diff --git a/src/PVE/Network/SDN/Controllers.pm b/src/PVE/Network/SDN/Controllers.pm
index fd7ad54ac38c..43f154b7338e 100644
--- a/src/PVE/Network/SDN/Controllers.pm
+++ b/src/PVE/Network/SDN/Controllers.pm
@@ -12,6 +12,7 @@ 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::Frr;
use PVE::Network::SDN::Controllers::EvpnPlugin;
use PVE::Network::SDN::Controllers::BgpPlugin;
use PVE::Network::SDN::Controllers::IsisPlugin;
@@ -148,10 +149,22 @@ sub reload_controller {
return if !$controller_cfg;
+ my $frr_reload = 0;
+
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();
+ my $type = $plugin_config->{type};
+ my @frr_types = ("bgp", "isis", "evpn");
+ if (grep {$type} @frr_types) {
+ $frr_reload = 1;
+ } else {
+ my $plugin = PVE::Network::SDN::Controllers::Plugin->lookup($type);
+ $plugin->reload_controller();
+ }
+ }
+
+ if ($frr_reload) {
+ PVE::Network::SDN::Controllers::Frr::reload_controller();
}
}
@@ -161,12 +174,22 @@ sub generate_controller_rawconfig {
my $cfg = PVE::Network::SDN::running_config();
my $controller_cfg = $cfg->{controllers};
return if !$controller_cfg;
+ my $frr_generate = 0;
my $rawconfig = "";
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});
- $rawconfig .= $plugin->generate_controller_rawconfig($plugin_config, $config);
+ my $type = $plugin_config->{type};
+ my @frr_types = ("bgp", "isis", "evpn");
+ if (grep {$type} @frr_types) {
+ $frr_generate = 1;
+ } else {
+ my $plugin = PVE::Network::SDN::Controllers::Plugin->lookup($type);
+ $rawconfig .= $plugin->generate_controller_rawconfig($plugin_config, $config);
+ }
+ }
+ if ($frr_generate) {
+ $rawconfig .= PVE::Network::SDN::Controllers::Frr::generate_controller_rawconfig($config);
}
return $rawconfig;
}
@@ -178,10 +201,22 @@ sub write_controller_config {
my $controller_cfg = $cfg->{controllers};
return if !$controller_cfg;
+ my $frr_reload = 0;
+
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);
+ my $type = $plugin_config->{type};
+ my @frr_types = ("bgp", "isis", "evpn");
+ if (grep {$type} @frr_types) {
+ $frr_reload = 1;
+ } else {
+ my $plugin = PVE::Network::SDN::Controllers::Plugin->lookup($type);
+ $plugin->write_controller_config($plugin_config, $config);
+ }
+ }
+
+ if ($frr_reload) {
+ PVE::Network::SDN::Controllers::Frr::write_controller_config($config);
}
}
diff --git a/src/PVE/Network/SDN/Controllers/BgpPlugin.pm b/src/PVE/Network/SDN/Controllers/BgpPlugin.pm
index 53963e5ad7f4..a4d3e9990647 100644
--- a/src/PVE/Network/SDN/Controllers/BgpPlugin.pm
+++ b/src/PVE/Network/SDN/Controllers/BgpPlugin.pm
@@ -7,6 +7,7 @@ use PVE::INotify;
use PVE::JSONSchema qw(get_standard_option);
use PVE::Tools qw(run_command file_set_contents file_get_contents);
+use PVE::Network::SDN::Controllers::Frr;
use PVE::Network::SDN::Controllers::Plugin;
use PVE::Network::SDN::Zones::Plugin;
use Net::IP;
@@ -164,19 +165,22 @@ sub on_update_hook {
}
}
+sub reload_controller {
+ my ($class) = @_;
+ #return PVE::Network::SDN::Controllers::Frr::reload_controller($class);
+ die "implemented in the Frr helper";
+}
+
sub generate_controller_rawconfig {
my ($class, $plugin_config, $config) = @_;
- return "";
+ #return PVE::Network::SDN::Controllers::Frr::generate_controller_rawconfig($class, $plugin_config, $config);
+ die "implemented in the Frr helper";
}
sub write_controller_config {
my ($class, $plugin_config, $config) = @_;
- return;
-}
-
-sub reload_controller {
- my ($class) = @_;
- return;
+ #return PVE::Network::SDN::Controllers::Frr::write_controller_config($class, $plugin_config, $config);
+ die "implemented in the Frr helper";
}
1;
diff --git a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
index c245ea29cf90..6f875cb5dbf9 100644
--- a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
@@ -9,6 +9,7 @@ use PVE::Tools qw(run_command file_set_contents file_get_contents);
use PVE::RESTEnvironment qw(log_warn);
use PVE::Network::SDN::Controllers::Plugin;
+use PVE::Network::SDN::Controllers::Frr;
use PVE::Network::SDN::Zones::Plugin;
use Net::IP;
@@ -109,6 +110,7 @@ sub generate_controller_config {
push @controller_config, "neighbor VTEP route-map MAP_VTEP_IN in";
push @controller_config, "neighbor VTEP route-map MAP_VTEP_OUT out";
push @controller_config, "advertise-all-vni";
+ # https://datatracker.ietf.org/doc/html/rfc8365#section-5.1.2.1
push @controller_config, "autort as $autortas" if $autortas;
push(@{$bgp->{"address-family"}->{"l2vpn evpn"}}, @controller_config);
@@ -195,7 +197,7 @@ sub generate_controller_zone_config {
push @controller_config, "no bgp hard-administrative-reset";
push @controller_config, "no bgp graceful-restart notification";
-# push @controller_config, "!";
+ #push @controller_config, "!";
push(@{$config->{frr}->{router}->{"bgp $asn vrf $vrf"}->{""}}, @controller_config);
if ($autortas) {
@@ -204,7 +206,6 @@ sub generate_controller_zone_config {
}
if ($is_gateway) {
-
$config->{frr_prefix_list}->{'only_default'}->{1} = "permit 0.0.0.0/0";
$config->{frr_prefix_list_v6}->{'only_default_v6'}->{1} = "permit ::/0";
@@ -356,291 +357,17 @@ sub find_isis_controller {
return $res;
}
-sub generate_frr_recurse{
- my ($final_config, $content, $parentkey, $level) = @_;
-
- my $keylist = {};
- $keylist->{'address-family'} = 1;
- $keylist->{router} = 1;
-
- my $exitkeylist = {};
- $exitkeylist->{'address-family'} = 1;
-
- my $simple_exitkeylist = {};
- $simple_exitkeylist->{router} = 1;
-
- # FIXME: 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 'HASH') {
- foreach my $key (sort keys %$content) {
- next if $key eq 'vrf';
- if ($parentkey && defined($keylist->{$parentkey})) {
- push @{$final_config}, $padding."!";
- push @{$final_config}, $padding."$parentkey $key";
- } elsif ($key ne '' && !defined($keylist->{$key})) {
- push @{$final_config}, $padding."$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});
- push @{$final_config}, $padding."exit" if $parentkey && defined($simple_exitkeylist->{$parentkey});
- }
- }
-
- if (ref $content eq 'ARRAY') {
- push @{$final_config}, map { $padding . "$_" } @$content;
- }
-}
-
-sub generate_frr_vrf {
- my ($final_config, $vrfs) = @_;
-
- return if !$vrfs;
-
- my @config = ();
-
- foreach my $id (sort keys %$vrfs) {
- my $vrf = $vrfs->{$id};
- push @config, "!";
- push @config, "vrf $id";
- foreach my $rule (@$vrf) {
- push @config, " $rule";
-
- }
- push @config, "exit-vrf";
- }
-
- push @{$final_config}, @config;
-}
-
-sub generate_frr_simple_list {
- my ($final_config, $rules) = @_;
-
- return if !$rules;
-
- my @config = ();
- push @{$final_config}, "!";
- foreach my $rule (sort @$rules) {
- push @{$final_config}, $rule;
- }
-}
-
-sub generate_frr_interfaces {
- my ($final_config, $interfaces) = @_;
-
- foreach my $k (sort keys %$interfaces) {
- my $iface = $interfaces->{$k};
- push @{$final_config}, "!";
- push @{$final_config}, "interface $k";
- foreach my $rule (sort @$iface) {
- push @{$final_config}, " $rule";
- }
- }
-}
-
-sub generate_frr_routemap {
- my ($final_config, $routemaps) = @_;
-
- foreach my $id (sort keys %$routemaps) {
-
- my $routemap = $routemaps->{$id};
- my $order = 0;
- foreach my $seq (@$routemap) {
- $order++;
- next if !defined($seq->{action});
- my @config = ();
- push @config, "!";
- push @config, "route-map $id $seq->{action} $order";
- my $rule = $seq->{rule};
- push @config, map { " $_" } @$rule;
- push @{$final_config}, @config;
- push @{$final_config}, "exit";
- }
- }
-}
-
-sub generate_frr_list {
- my ($final_config, $lists, $type) = @_;
-
- my $config = [];
-
- for my $id (sort keys %$lists) {
- my $list = $lists->{$id};
-
- for my $seq (sort keys %$list) {
- my $rule = $list->{$seq};
- push @$config, "$type $id seq $seq $rule";
- }
- }
-
- if (@$config > 0) {
- push @{$final_config}, "!", @$config;
- }
-}
-
-sub read_local_frr_config {
- if (-e "/etc/frr/frr.conf.local") {
- return file_get_contents("/etc/frr/frr.conf.local");
- }
-};
-
sub generate_controller_rawconfig {
my ($class, $plugin_config, $config) = @_;
-
- my $nodename = PVE::INotify::nodename();
-
- my $final_config = [];
- push @{$final_config}, "frr version 8.5.2";
- push @{$final_config}, "frr defaults datacenter";
- push @{$final_config}, "hostname $nodename";
- push @{$final_config}, "log syslog informational";
- push @{$final_config}, "service integrated-vtysh-config";
- push @{$final_config}, "!";
-
- my $local_conf = read_local_frr_config();
- if ($local_conf) {
- parse_merge_frr_local_config($config, $local_conf);
- }
-
- generate_frr_vrf($final_config, $config->{frr}->{vrf});
- generate_frr_interfaces($final_config, $config->{frr_interfaces});
- generate_frr_recurse($final_config, $config->{frr}, undef, 0);
- generate_frr_list($final_config, $config->{frr_access_list}, "access-list");
- generate_frr_list($final_config, $config->{frr_prefix_list}, "ip prefix-list");
- generate_frr_list($final_config, $config->{frr_prefix_list_v6}, "ipv6 prefix-list");
- generate_frr_simple_list($final_config, $config->{frr_bgp_community_list});
- generate_frr_routemap($final_config, $config->{frr_routemap});
- generate_frr_simple_list($final_config, $config->{frr_ip_protocol});
-
- push @{$final_config}, "!";
- push @{$final_config}, "line vty";
- push @{$final_config}, "!";
-
- my $rawconfig = join("\n", @{$final_config});
-
- return if !$rawconfig;
- return $rawconfig;
-}
-
-sub parse_merge_frr_local_config {
- my ($config, $local_conf) = @_;
-
- my $section = \$config->{""};
- my $router = undef;
- my $routemap = undef;
- my $routemap_config = ();
- my $routemap_action = undef;
-
- while ($local_conf =~ /^\s*(.+?)\s*$/gm) {
- my $line = $1;
- $line =~ s/^\s+|\s+$//g;
-
- if ($line =~ m/^router (.+)$/) {
- $router = $1;
- $section = \$config->{'frr'}->{'router'}->{$router}->{""};
- next;
- } elsif ($line =~ m/^vrf (.+)$/) {
- $section = \$config->{'frr'}->{'vrf'}->{$1};
- next;
- } elsif ($line =~ m/^interface (.+)$/) {
- $section = \$config->{'frr_interfaces'}->{$1};
- next;
- } elsif ($line =~ m/^bgp community-list (.+)$/) {
- push(@{$config->{'frr_bgp_community_list'}}, $line);
- next;
- } elsif ($line =~ m/address-family (.+)$/) {
- $section = \$config->{'frr'}->{'router'}->{$router}->{'address-family'}->{$1};
- next;
- } elsif ($line =~ m/^route-map (.+) (permit|deny) (\d+)/) {
- $routemap = $1;
- $routemap_config = ();
- $routemap_action = $2;
- $section = \$config->{'frr_routemap'}->{$routemap};
- next;
- } elsif ($line =~ m/^access-list (.+) seq (\d+) (.+)$/) {
- $config->{'frr_access_list'}->{$1}->{$2} = $3;
- next;
- } elsif ($line =~ m/^ip prefix-list (.+) seq (\d+) (.*)$/) {
- $config->{'frr_prefix_list'}->{$1}->{$2} = $3;
- next;
- } elsif ($line =~ m/^ipv6 prefix-list (.+) seq (\d+) (.*)$/) {
- $config->{'frr_prefix_list_v6'}->{$1}->{$2} = $3;
- next;
- } elsif($line =~ m/^exit-address-family$/) {
- next;
- } elsif($line =~ m/^exit$/) {
- if($router) {
- $section = \$config->{''};
- $router = undef;
- } elsif($routemap) {
- push(@{$$section}, { rule => $routemap_config, action => $routemap_action });
- $section = \$config->{''};
- $routemap = undef;
- $routemap_action = undef;
- $routemap_config = ();
- }
- next;
- } elsif($line =~ m/!/) {
- next;
- }
-
- next if !$section;
- if($routemap) {
- push(@{$routemap_config}, $line);
- } else {
- push(@{$$section}, $line);
- }
- }
+ #return PVE::Network::SDN::Controllers::Frr::generate_controller_rawconfig($class, $plugin_config, $config);
+ die "implemented in the Frr helper";
}
sub write_controller_config {
my ($class, $plugin_config, $config) = @_;
-
- my $rawconfig = $class->generate_controller_rawconfig($plugin_config, $config);
- return if !$rawconfig;
- return if !-d "/etc/frr";
-
- file_set_contents("/etc/frr/frr.conf", $rawconfig);
-}
-
-sub reload_controller {
- my ($class) = @_;
-
- my $conf_file = "/etc/frr/frr.conf";
- my $bin_path = "/usr/lib/frr/frr-reload.py";
-
- if (!-e $bin_path) {
- log_warn("missing $bin_path. Please install frr-pythontools package");
- return;
- }
-
- my $err = sub {
- my $line = shift;
- if ($line =~ /ERROR:/) {
- warn "$line \n";
- }
- };
-
- if (-e $conf_file && -e $bin_path) {
- eval {
- run_command([$bin_path, '--stdout', '--reload', $conf_file], outfunc => {}, errfunc => $err);
- };
- if ($@) {
- warn "frr reload command fail. Restarting frr.";
- eval { run_command(['systemctl', 'restart', 'frr']); };
- }
- }
+
+ #return PVE::Network::SDN::Controllers::Frr::write_controller_config($class, $plugin_config, $config);
+ die "implemented in the Frr helper";
}
1;
diff --git a/src/PVE/Network/SDN/Controllers/Frr.pm b/src/PVE/Network/SDN/Controllers/Frr.pm
new file mode 100644
index 000000000000..386dcae543e8
--- /dev/null
+++ b/src/PVE/Network/SDN/Controllers/Frr.pm
@@ -0,0 +1,296 @@
+package PVE::Network::SDN::Controllers::Frr;
+
+use strict;
+use warnings;
+
+use PVE::RESTEnvironment qw(log_warn);
+use PVE::Tools qw(file_get_contents file_set_contents);
+
+sub read_local_frr_config {
+ if (-e "/etc/frr/frr.conf.local") {
+ return file_get_contents("/etc/frr/frr.conf.local");
+ }
+};
+
+sub reload_controller {
+ my $conf_file = "/etc/frr/frr.conf";
+ my $bin_path = "/usr/lib/frr/frr-reload.py";
+
+ if (!-e $bin_path) {
+ log_warn("missing $bin_path. Please install frr-pythontools package");
+ return;
+ }
+
+ my $err = sub {
+ my $line = shift;
+ if ($line =~ /ERROR:/) {
+ warn "$line \n";
+ }
+ };
+
+ if (-e $conf_file && -e $bin_path) {
+ eval {
+ run_command([$bin_path, '--stdout', '--reload', $conf_file], outfunc => {}, errfunc => $err);
+ };
+ if ($@) {
+ warn "frr reload command fail. Restarting frr.";
+ eval { run_command(['systemctl', 'restart', 'frr']); };
+ }
+ }
+}
+
+sub generate_controller_rawconfig {
+ my ($config) = @_;
+
+ my $nodename = PVE::INotify::nodename();
+
+ my $final_config = [];
+ push @{$final_config}, "frr version 8.5.2";
+ push @{$final_config}, "frr defaults datacenter";
+ push @{$final_config}, "hostname $nodename";
+ push @{$final_config}, "log syslog informational";
+ push @{$final_config}, "service integrated-vtysh-config";
+ push @{$final_config}, "!";
+
+ my $local_conf = read_local_frr_config();
+ if ($local_conf) {
+ parse_merge_frr_local_config($config, $local_conf);
+ }
+
+ generate_frr_vrf($final_config, $config->{frr}->{vrf});
+ generate_frr_interfaces($final_config, $config->{frr_interfaces});
+ generate_frr_recurse($final_config, $config->{frr}, undef, 0);
+ generate_frr_list($final_config, $config->{frr_access_list}, "access-list");
+ generate_frr_list($final_config, $config->{frr_prefix_list}, "ip prefix-list");
+ generate_frr_list($final_config, $config->{frr_prefix_list_v6}, "ipv6 prefix-list");
+ generate_frr_simple_list($final_config, $config->{frr_bgp_community_list});
+ generate_frr_routemap($final_config, $config->{frr_routemap});
+ generate_frr_simple_list($final_config, $config->{frr_ip_protocol});
+
+ push @{$final_config}, "!";
+ push @{$final_config}, "line vty";
+ push @{$final_config}, "!";
+
+ my $rawconfig = join("\n", @{$final_config});
+
+ return if !$rawconfig;
+ return $rawconfig;
+}
+
+sub parse_merge_frr_local_config {
+ my ($config, $local_conf) = @_;
+
+ my $section = \$config->{""};
+ my $router = undef;
+ my $routemap = undef;
+ my $routemap_config = ();
+ my $routemap_action = undef;
+
+ while ($local_conf =~ /^\s*(.+?)\s*$/gm) {
+ my $line = $1;
+ $line =~ s/^\s+|\s+$//g;
+
+ if ($line =~ m/^router (.+)$/) {
+ $router = $1;
+ $section = \$config->{'frr'}->{'router'}->{$router}->{""};
+ next;
+ } elsif ($line =~ m/^vrf (.+)$/) {
+ $section = \$config->{'frr'}->{'vrf'}->{$1};
+ next;
+ } elsif ($line =~ m/^interface (.+)$/) {
+ $section = \$config->{'frr_interfaces'}->{$1};
+ next;
+ } elsif ($line =~ m/^bgp community-list (.+)$/) {
+ push(@{$config->{'frr_bgp_community_list'}}, $line);
+ next;
+ } elsif ($line =~ m/address-family (.+)$/) {
+ $section = \$config->{'frr'}->{'router'}->{$router}->{'address-family'}->{$1};
+ next;
+ } elsif ($line =~ m/^route-map (.+) (permit|deny) (\d+)/) {
+ $routemap = $1;
+ $routemap_config = ();
+ $routemap_action = $2;
+ $section = \$config->{'frr_routemap'}->{$routemap};
+ next;
+ } elsif ($line =~ m/^access-list (.+) seq (\d+) (.+)$/) {
+ $config->{'frr_access_list'}->{$1}->{$2} = $3;
+ next;
+ } elsif ($line =~ m/^ip prefix-list (.+) seq (\d+) (.*)$/) {
+ $config->{'frr_prefix_list'}->{$1}->{$2} = $3;
+ next;
+ } elsif ($line =~ m/^ipv6 prefix-list (.+) seq (\d+) (.*)$/) {
+ $config->{'frr_prefix_list_v6'}->{$1}->{$2} = $3;
+ next;
+ } elsif($line =~ m/^exit-address-family$/) {
+ next;
+ } elsif($line =~ m/^exit$/) {
+ if($router) {
+ $section = \$config->{''};
+ $router = undef;
+ } elsif($routemap) {
+ push(@{$$section}, { rule => $routemap_config, action => $routemap_action });
+ $section = \$config->{''};
+ $routemap = undef;
+ $routemap_action = undef;
+ $routemap_config = ();
+ }
+ next;
+ } elsif($line =~ m/!/) {
+ next;
+ }
+
+ next if !$section;
+ if($routemap) {
+ push(@{$routemap_config}, $line);
+ } else {
+ push(@{$$section}, $line);
+ }
+ }
+}
+
+sub write_controller_config {
+ my ($config) = @_;
+
+ my $rawconfig = generate_controller_rawconfig($config);
+ return if !$rawconfig;
+ return if !-d "/etc/frr";
+
+ file_set_contents("/etc/frr/frr.conf", $rawconfig);
+}
+
+
+sub generate_frr_recurse{
+ my ($final_config, $content, $parentkey, $level) = @_;
+
+ my $keylist = {};
+ $keylist->{'address-family'} = 1;
+ $keylist->{router} = 1;
+
+ my $exitkeylist = {};
+ $exitkeylist->{'address-family'} = 1;
+
+ my $simple_exitkeylist = {};
+ $simple_exitkeylist->{router} = 1;
+
+ # FIXME: 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 'HASH') {
+ foreach my $key (sort keys %$content) {
+ next if $key eq 'vrf';
+ if ($parentkey && defined($keylist->{$parentkey})) {
+ push @{$final_config}, $padding."!";
+ push @{$final_config}, $padding."$parentkey $key";
+ } elsif ($key ne '' && !defined($keylist->{$key})) {
+ push @{$final_config}, $padding."$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});
+ push @{$final_config}, $padding."exit" if $parentkey && defined($simple_exitkeylist->{$parentkey});
+ }
+ }
+
+ if (ref $content eq 'ARRAY') {
+ push @{$final_config}, map { $padding . "$_" } @$content;
+ }
+}
+
+sub generate_frr_vrf {
+ my ($final_config, $vrfs) = @_;
+
+ return if !$vrfs;
+
+ my @config = ();
+
+ foreach my $id (sort keys %$vrfs) {
+ my $vrf = $vrfs->{$id};
+ push @config, "!";
+ push @config, "vrf $id";
+ foreach my $rule (@$vrf) {
+ push @config, " $rule";
+
+ }
+ push @config, "exit-vrf";
+ }
+
+ push @{$final_config}, @config;
+}
+
+sub generate_frr_simple_list {
+ my ($final_config, $rules) = @_;
+
+ return if !$rules;
+
+ my @config = ();
+ push @{$final_config}, "!";
+ foreach my $rule (sort @$rules) {
+ push @{$final_config}, $rule;
+ }
+}
+
+sub generate_frr_list {
+ my ($final_config, $lists, $type) = @_;
+
+ my $config = [];
+
+ for my $id (sort keys %$lists) {
+ my $list = $lists->{$id};
+
+ for my $seq (sort keys %$list) {
+ my $rule = $list->{$seq};
+ push @$config, "$type $id seq $seq $rule";
+ }
+ }
+
+ if (@$config > 0) {
+ push @{$final_config}, "!", @$config;
+ }
+}
+
+
+sub generate_frr_interfaces {
+ my ($final_config, $interfaces) = @_;
+
+ foreach my $k (sort keys %$interfaces) {
+ my $iface = $interfaces->{$k};
+ push @{$final_config}, "!";
+ push @{$final_config}, "interface $k";
+ foreach my $rule (sort @$iface) {
+ push @{$final_config}, " $rule";
+ }
+ }
+}
+
+sub generate_frr_routemap {
+ my ($final_config, $routemaps) = @_;
+
+ foreach my $id (sort keys %$routemaps) {
+
+ my $routemap = $routemaps->{$id};
+ my $order = 0;
+ foreach my $seq (@$routemap) {
+ $order++;
+ next if !defined($seq->{action});
+ my @config = ();
+ push @config, "!";
+ push @config, "route-map $id $seq->{action} $order";
+ my $rule = $seq->{rule};
+ push @config, map { " $_" } @$rule;
+ push @{$final_config}, @config;
+ push @{$final_config}, "exit";
+ }
+ }
+}
+
+1;
diff --git a/src/PVE/Network/SDN/Controllers/IsisPlugin.pm b/src/PVE/Network/SDN/Controllers/IsisPlugin.pm
index 97c6876db303..50a11742fff6 100644
--- a/src/PVE/Network/SDN/Controllers/IsisPlugin.pm
+++ b/src/PVE/Network/SDN/Controllers/IsisPlugin.pm
@@ -7,6 +7,7 @@ use PVE::INotify;
use PVE::JSONSchema qw(get_standard_option);
use PVE::Tools qw(run_command file_set_contents file_get_contents);
+use PVE::Network::SDN::Controllers::Frr;
use PVE::Network::SDN::Controllers::Plugin;
use PVE::Network::SDN::Zones::Plugin;
use Net::IP;
@@ -113,19 +114,22 @@ sub on_update_hook {
}
}
+sub reload_controller {
+ my ($class) = @_;
+ #return PVE::Network::SDN::Controllers::Frr::reload_controller($class);
+ die "implemented in the Frr helper";
+}
+
sub generate_controller_rawconfig {
my ($class, $plugin_config, $config) = @_;
- return "";
+ #return PVE::Network::SDN::Controllers::Frr::generate_controller_rawconfig($class, $plugin_config, $config);
+ die "implemented in the Frr helper";
}
sub write_controller_config {
my ($class, $plugin_config, $config) = @_;
- return;
-}
-
-sub reload_controller {
- my ($class) = @_;
- return;
+ #return PVE::Network::SDN::Controllers::Frr::write_controller_config($class, $plugin_config, $config);
+ die "implemented in the Frr helper";
}
1;
diff --git a/src/PVE/Network/SDN/Controllers/Makefile b/src/PVE/Network/SDN/Controllers/Makefile
index fd9f881a0ad2..3b0387913cdc 100644
--- a/src/PVE/Network/SDN/Controllers/Makefile
+++ b/src/PVE/Network/SDN/Controllers/Makefile
@@ -1,4 +1,4 @@
-SOURCES=Plugin.pm FaucetPlugin.pm EvpnPlugin.pm BgpPlugin.pm IsisPlugin.pm
+SOURCES=Plugin.pm FaucetPlugin.pm EvpnPlugin.pm BgpPlugin.pm IsisPlugin.pm Frr.pm
PERL5DIR=${DESTDIR}/usr/share/perl5
diff --git a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
index 4843756a75bd..6212ba0a02d9 100644
--- a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -323,6 +323,21 @@ sub vnet_update_hook {
}
}
+sub reload_controller {
+ my ($class) = @_;
+ die "implemented in the Frr helper";
+}
+
+sub generate_controller_rawconfig {
+ my ($class, $config) = @_;
+ die "implemented in the Frr helper";
+}
+
+sub write_controller_config {
+ my ($class, $config) = @_;
+ die "implemented in the Frr helper";
+}
+
1;
--
2.39.5
More information about the pve-devel
mailing list