summaryrefslogtreecommitdiff
path: root/src/PVE/Network/SDN
diff options
context:
space:
mode:
Diffstat (limited to 'src/PVE/Network/SDN')
-rw-r--r--src/PVE/Network/SDN/Controllers/EvpnPlugin.pm147
-rw-r--r--src/PVE/Network/SDN/Zones/EvpnPlugin.pm65
2 files changed, 176 insertions, 36 deletions
diff --git a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
index 63d209d..021673b 100644
--- a/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Controllers/EvpnPlugin.pm
@@ -10,6 +10,7 @@ use PVE::RESTEnvironment qw(log_warn);
use PVE::Network::SDN::Controllers::Plugin;
use PVE::Network::SDN::Zones::Plugin;
+use PVE::Network::SDN::Fabrics;
use Net::IP;
use base('PVE::Network::SDN::Controllers::Plugin');
@@ -26,6 +27,11 @@ sub properties {
minimum => 0,
maximum => 4294967296,
},
+ fabric => {
+ description => "SDN fabric to use as underlay for this EVPN controller.",
+ type => 'string',
+ format => 'pve-sdn-fabric-id',
+ },
peers => {
description => "peers address list.",
type => 'string',
@@ -37,7 +43,8 @@ sub properties {
sub options {
return {
'asn' => { optional => 0 },
- 'peers' => { optional => 0 },
+ 'peers' => { optional => 1 },
+ 'fabric' => { optional => 1 },
};
}
@@ -45,35 +52,79 @@ sub options {
sub generate_frr_config {
my ($class, $plugin_config, $controller_cfg, $id, $uplinks, $config) = @_;
- my @peers;
- @peers = PVE::Tools::split_list($plugin_config->{'peers'}) if $plugin_config->{'peers'};
-
my $local_node = PVE::INotify::nodename();
+ my @peers;
my $asn = $plugin_config->{asn};
my $ebgp = undef;
my $loopback = undef;
my $autortas = undef;
+ my $ifaceip = undef;
+ my $routerid = undef;
+
my $bgprouter = find_bgp_controller($local_node, $controller_cfg);
my $isisrouter = find_isis_controller($local_node, $controller_cfg);
+ if ($plugin_config->{'fabric'}) {
+ my $config = PVE::Network::SDN::Fabrics::config(1);
+
+ my $fabric = eval { $config->get_fabric($plugin_config->{fabric}) };
+ if ($@) {
+ log_warn("could not configure EVPN controller $plugin_config->{id}: $@");
+ return;
+ }
+
+ my $nodes = $config->list_nodes_fabric($plugin_config->{fabric});
+
+ my $current_node = eval { $config->get_node($plugin_config->{fabric}, $local_node) };
+ if ($@) {
+ log_warn("could not configure EVPN controller $plugin_config->{id}: $@");
+ return;
+ }
+
+ if (!$current_node->{ip}) {
+ log_warn(
+ "Node $local_node requires an IP in the fabric $fabric->{id} to configure the EVPN controller"
+ );
+ return;
+ }
+
+ for my $node_id (sort keys %$nodes) {
+ my $node = $nodes->{$node_id};
+ push @peers, $node->{ip} if $node->{ip};
+ }
+
+ $loopback = "dummy_$fabric->{id}";
+
+ $ifaceip = $current_node->{ip};
+ $routerid = $current_node->{ip};
+
+ } elsif ($plugin_config->{'peers'}) {
+ @peers = PVE::Tools::split_list($plugin_config->{'peers'});
+
+ if ($bgprouter) {
+ $loopback = $bgprouter->{loopback} if $bgprouter->{loopback};
+ } elsif ($isisrouter) {
+ $loopback = $isisrouter->{loopback} if $isisrouter->{loopback};
+ }
+
+ ($ifaceip, my $interface) =
+ PVE::Network::SDN::Zones::Plugin::find_local_ip_interface_peers(\@peers, $loopback);
+ $routerid = PVE::Network::SDN::Controllers::Plugin::get_router_id($ifaceip, $interface);
+ } else {
+ log_warn("neither fabric nor peers configured for EVPN controller $plugin_config->{id}");
+ return;
+ }
+
if ($bgprouter) {
$ebgp = 1 if $plugin_config->{'asn'} ne $bgprouter->{asn};
- $loopback = $bgprouter->{loopback} if $bgprouter->{loopback};
$asn = $bgprouter->{asn} if $bgprouter->{asn};
$autortas = $plugin_config->{'asn'} if $ebgp;
- } elsif ($isisrouter) {
- $loopback = $isisrouter->{loopback} if $isisrouter->{loopback};
}
- return if !$asn;
-
+ return if !$asn || !$routerid;
my $bgp = $config->{frr}->{router}->{"bgp $asn"} //= {};
- my ($ifaceip, $interface) =
- PVE::Network::SDN::Zones::Plugin::find_local_ip_interface_peers(\@peers, $loopback);
- my $routerid = PVE::Network::SDN::Controllers::Plugin::get_router_id($ifaceip, $interface);
-
my $remoteas = $ebgp ? "external" : $asn;
#global options
@@ -137,29 +188,76 @@ sub generate_zone_frr_config {
if $plugin_config->{'rt-import'};
my $asn = $controller->{asn};
+
my @peers;
- @peers = PVE::Tools::split_list($controller->{'peers'}) if $controller->{'peers'};
my $ebgp = undef;
my $loopback = undef;
+ my $ifaceip = undef;
my $autortas = undef;
+ my $routerid = undef;
+
my $bgprouter = find_bgp_controller($local_node, $controller_cfg);
my $isisrouter = find_isis_controller($local_node, $controller_cfg);
+ if ($controller->{fabric}) {
+ my $config = PVE::Network::SDN::Fabrics::config(1);
+
+ my $fabric = eval { $config->get_fabric($controller->{fabric}) };
+ if ($@) {
+ log_warn("could not configure EVPN controller $controller->{id}: $@");
+ return;
+ }
+
+ my $nodes = $config->list_nodes_fabric($controller->{fabric});
+
+ my $current_node = eval { $config->get_node($controller->{fabric}, $local_node) };
+ if ($@) {
+ log_warn("could not configure EVPN controller $controller->{id}: $@");
+ return;
+ }
+
+ if (!$current_node->{ip}) {
+ log_warn(
+ "Node $local_node requires an IP in the fabric $fabric->{id} to configure the EVPN controller"
+ );
+ return;
+ }
+
+ for my $node (values %$nodes) {
+ push @peers, $node->{ip} if $node->{ip};
+ }
+
+ $loopback = "dummy_$fabric->{id}";
+
+ $ifaceip = $current_node->{ip};
+ $routerid = $current_node->{ip};
+
+ } elsif ($controller->{peers}) {
+ @peers = PVE::Tools::split_list($controller->{'peers'}) if $controller->{'peers'};
+
+ if ($bgprouter) {
+ $loopback = $bgprouter->{loopback} if $bgprouter->{loopback};
+ } elsif ($isisrouter) {
+ $loopback = $isisrouter->{loopback} if $isisrouter->{loopback};
+ }
+
+ ($ifaceip, my $interface) =
+ PVE::Network::SDN::Zones::Plugin::find_local_ip_interface_peers(\@peers, $loopback);
+ $routerid = PVE::Network::SDN::Controllers::Plugin::get_router_id($ifaceip, $interface);
+
+ } else {
+ log_warn("neither fabric nor peers configured for EVPN controller $controller->{id}");
+ return;
+ }
+
if ($bgprouter) {
$ebgp = 1 if $controller->{'asn'} ne $bgprouter->{asn};
- $loopback = $bgprouter->{loopback} if $bgprouter->{loopback};
$asn = $bgprouter->{asn} if $bgprouter->{asn};
$autortas = $controller->{'asn'} if $ebgp;
- } elsif ($isisrouter) {
- $loopback = $isisrouter->{loopback} if $isisrouter->{loopback};
}
return if !$vrf || !$vrfvxlan || !$asn;
- my ($ifaceip, $interface) =
- PVE::Network::SDN::Zones::Plugin::find_local_ip_interface_peers(\@peers, $loopback);
- my $routerid = PVE::Network::SDN::Controllers::Plugin::get_router_id($ifaceip, $interface);
-
my $is_gateway = $exitnodes->{$local_node};
# vrf
@@ -393,6 +491,13 @@ sub on_update_hook {
$controllernb++;
die "only 1 global evpn controller can be defined" if $controllernb >= 1;
}
+
+ my $controller = $controller_cfg->{ids}->{$controllerid};
+ if ($controller->{type} eq 'evpn') {
+ die "must have exactly one of peers / fabric defined"
+ if ($controller->{peers} && $controller->{fabric})
+ || !($controller->{peers} || $controller->{fabric});
+ }
}
sub find_bgp_controller {
diff --git a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
index 7d26e1b..0153364 100644
--- a/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
+++ b/src/PVE/Network/SDN/Zones/EvpnPlugin.pm
@@ -135,28 +135,63 @@ sub generate_sdn_config {
die "missing vxlan tag" if !$tag;
die "missing controller" if !$controller;
- my @peers = PVE::Tools::split_list($controller->{'peers'});
-
+ my @peers;
my $loopback = undef;
- my $bgprouter = PVE::Network::SDN::Controllers::EvpnPlugin::find_bgp_controller(
- $local_node, $controller_cfg,
- );
- my $isisrouter = PVE::Network::SDN::Controllers::EvpnPlugin::find_isis_controller(
- $local_node, $controller_cfg,
- );
- if ($bgprouter->{loopback}) {
- $loopback = $bgprouter->{loopback};
- } elsif ($isisrouter->{loopback}) {
- $loopback = $isisrouter->{loopback};
+ my $ifaceip = undef;
+ my $iface = undef;
+ my $routerid = undef;
+
+ if ($controller->{peers}) {
+ @peers = PVE::Tools::split_list($controller->{'peers'});
+
+ my $bgprouter = PVE::Network::SDN::Controllers::EvpnPlugin::find_bgp_controller(
+ $local_node, $controller_cfg,
+ );
+ my $isisrouter = PVE::Network::SDN::Controllers::EvpnPlugin::find_isis_controller(
+ $local_node, $controller_cfg,
+ );
+
+ if ($bgprouter->{loopback}) {
+ $loopback = $bgprouter->{loopback};
+ } elsif ($isisrouter->{loopback}) {
+ $loopback = $isisrouter->{loopback};
+ }
+
+ ($ifaceip, $iface) =
+ PVE::Network::SDN::Zones::Plugin::find_local_ip_interface_peers(\@peers, $loopback);
+ } elsif ($controller->{fabric}) {
+ my $config = PVE::Network::SDN::Fabrics::config(1);
+
+ my $fabric = eval { $config->get_fabric($controller->{fabric}) };
+ die "could not configure EVPN zone $plugin_config->{id}: $@" if $@;
+
+ my $nodes = $config->list_nodes_fabric($controller->{fabric});
+
+ my $current_node = eval { $config->get_node($controller->{fabric}, $local_node) };
+ die "could not configure EVPN zone $plugin_config->{id}: $@" if $@;
+
+ die "Node $local_node requires an IP in the fabric $fabric->{id} to configure the EVPN zone"
+ if !$current_node->{ip};
+
+ for my $node (values %$nodes) {
+ push @peers, $node->{ip} if $node->{ip};
+ }
+
+ $loopback = "dummy_$fabric->{id}";
+
+ $ifaceip = $current_node->{ip};
+ $routerid = $current_node->{ip};
+ } else {
+ die "neither fabric nor peers configured for EVPN controller $controller->{id}";
}
- my ($ifaceip, $iface) =
- PVE::Network::SDN::Zones::Plugin::find_local_ip_interface_peers(\@peers, $loopback);
my $is_evpn_gateway = $plugin_config->{'exitnodes'}->{$local_node};
my $exitnodes_local_routing = $plugin_config->{'exitnodes-local-routing'};
my $mtu = 1450;
- $mtu = $interfaces_config->{$iface}->{mtu} - 50 if $interfaces_config->{$iface}->{mtu};
+ if ($iface) {
+ $mtu = $interfaces_config->{$iface}->{mtu} - 50 if $interfaces_config->{$iface}->{mtu};
+ }
$mtu = $plugin_config->{mtu} if $plugin_config->{mtu};
#vxlan interface