diff options
Diffstat (limited to 'src/PVE/Network')
| -rw-r--r-- | src/PVE/Network/SDN/Controllers/EvpnPlugin.pm | 147 | ||||
| -rw-r--r-- | src/PVE/Network/SDN/Zones/EvpnPlugin.pm | 65 |
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 |
