From 847f51445231e827bfa6b5c81ac38ae80fd89e05 Mon Sep 17 00:00:00 2001 From: Alexandre Derumier Date: Fri, 11 Feb 2022 10:33:26 +0100 Subject: [PATCH] controllers: evpn/bgp : add exitnodes-primary && rework route-map exitnodes-primary option force traffic to a primary node A route-map is used to increase metric on backup nodes. This can be usefull for snat or avoid asymetric routing. Route-map is rework to handle multiple sequences of route map. Signed-off-by: Alexandre Derumier --- PVE/Network/SDN/Controllers/BgpPlugin.pm | 7 ++- PVE/Network/SDN/Controllers/EvpnPlugin.pm | 33 +++++++++- PVE/Network/SDN/Zones/EvpnPlugin.pm | 3 + .../expected_controller_config | 3 + .../expected_controller_config | 3 + .../evpn/ebgp/expected_controller_config | 3 + .../ebgp_loopback/expected_controller_config | 3 + .../evpn/exitnode/expected_controller_config | 3 + .../expected_controller_config | 3 + .../expected_controller_config | 61 +++++++++++++++++++ .../exitnode_primary/expected_sdn_interfaces | 41 +++++++++++++ test/zones/evpn/exitnode_primary/interfaces | 7 +++ test/zones/evpn/exitnode_primary/sdn_config | 26 ++++++++ .../exitnode_snat/expected_controller_config | 3 + .../evpn/ipv4/expected_controller_config | 3 + .../evpn/ipv4ipv6/expected_controller_config | 3 + .../expected_controller_config | 3 + .../evpn/ipv6/expected_controller_config | 3 + .../expected_controller_config | 3 + 19 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 test/zones/evpn/exitnode_primary/expected_controller_config create mode 100644 test/zones/evpn/exitnode_primary/expected_sdn_interfaces create mode 100644 test/zones/evpn/exitnode_primary/interfaces create mode 100644 test/zones/evpn/exitnode_primary/sdn_config diff --git a/PVE/Network/SDN/Controllers/BgpPlugin.pm b/PVE/Network/SDN/Controllers/BgpPlugin.pm index 1e4e708..70c7264 100644 --- a/PVE/Network/SDN/Controllers/BgpPlugin.pm +++ b/PVE/Network/SDN/Controllers/BgpPlugin.pm @@ -122,8 +122,11 @@ sub generate_controller_config { if ($loopback) { push(@{$config->{frr}->{''}}, "ip prefix-list loopbacks_ips seq 10 permit 0.0.0.0/0 le 32"); push(@{$config->{frr}->{''}}, "ip protocol bgp route-map correct_src"); - push(@{$config->{frr}->{'route-map'}->{'correct_src permit 1'}}, "match ip address prefix-list loopbacks_ips"); - push(@{$config->{frr}->{'route-map'}->{'correct_src permit 1'}}, "set src $ifaceip"); + + my $routemap_config = []; + push @{$routemap_config}, "match ip address prefix-list loopbacks_ips"; + push @{$routemap_config}, "set src $ifaceip"; + push(@{$config->{frr_routemap}->{'correct_src'}}, $routemap_config); } return $config; diff --git a/PVE/Network/SDN/Controllers/EvpnPlugin.pm b/PVE/Network/SDN/Controllers/EvpnPlugin.pm index d02bdf7..2b48e9a 100644 --- a/PVE/Network/SDN/Controllers/EvpnPlugin.pm +++ b/PVE/Network/SDN/Controllers/EvpnPlugin.pm @@ -99,11 +99,14 @@ sub generate_controller_config { # address-family l2vpn @controller_config = (); + push @controller_config, "neighbor VTEP route-map MAP_VTEP_OUT out"; push @controller_config, "neighbor VTEP activate"; push @controller_config, "advertise-all-vni"; push @controller_config, "autort as $autortas" if $autortas; push(@{$bgp->{"address-family"}->{"l2vpn evpn"}}, @controller_config); + push(@{$config->{frr_routemap}->{'MAP_VTEP_OUT'}}, []); + return $config; } @@ -115,6 +118,7 @@ sub generate_controller_zone_config { my $vrf = "vrf_$id"; my $vrfvxlan = $plugin_config->{'vrf-vxlan'}; my $exitnodes = $plugin_config->{'exitnodes'}; + my $exitnodes_primary = $plugin_config->{'exitnodes-primary'}; my $advertisesubnets = $plugin_config->{'advertise-subnets'}; my $exitnodes_local_routing = $plugin_config->{'exitnodes-local-routing'}; @@ -152,6 +156,14 @@ sub generate_controller_zone_config { if ($is_gateway) { + if($exitnodes_primary && $exitnodes_primary ne $local_node) { + my $routemap_config = (); + push @{$routemap_config}, "match evpn vni $vrfvxlan"; + push @{$routemap_config}, "match evpn route-type prefix"; + push @{$routemap_config}, "set metric 200"; + unshift(@{$config->{frr_routemap}->{'MAP_VTEP_OUT'}}, $routemap_config); + } + if (!$exitnodes_local_routing) { @controller_config = (); #import /32 routes of evpn network from vrf1 to default vrf (for packet return) @@ -260,7 +272,6 @@ sub sort_frr_config { $order->{'ipv4 unicast'} = 1; $order->{'ipv6 unicast'} = 2; $order->{'l2vpn evpn'} = 3; - $order->{'route-map'} = 200; my $a_val = 100; my $b_val = 100; @@ -286,7 +297,6 @@ sub generate_frr_recurse{ $keylist->{vrf} = 1; $keylist->{'address-family'} = 1; $keylist->{router} = 1; - $keylist->{'route-map'} = 1; my $exitkeylist = {}; $exitkeylist->{vrf} = 1; @@ -324,6 +334,23 @@ sub generate_frr_recurse{ } } +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++; + my @config = (); + push @config, "!"; + push @config, "route-map $id permit $order"; + push @config, map { " $_" } @$seq; + push @{$final_config}, @config; + } + } +} sub generate_controller_rawconfig { my ($class, $plugin_config, $config) = @_; @@ -340,6 +367,7 @@ sub generate_controller_rawconfig { if (-e "/etc/frr/frr.conf.local") { generate_frr_recurse($final_config, $config->{frr}->{vrf}, "vrf", 1); + generate_frr_routemap($final_config, $config->{frr_routemap}); push @{$final_config}, "!"; my $local_conf = file_get_contents("/etc/frr/frr.conf.local"); @@ -347,6 +375,7 @@ sub generate_controller_rawconfig { push @{$final_config}, $local_conf; } else { generate_frr_recurse($final_config, $config->{frr}, undef, 0); + generate_frr_routemap($final_config, $config->{frr_routemap}); } push @{$final_config}, "!"; diff --git a/PVE/Network/SDN/Zones/EvpnPlugin.pm b/PVE/Network/SDN/Zones/EvpnPlugin.pm index 50ea619..62c968c 100644 --- a/PVE/Network/SDN/Zones/EvpnPlugin.pm +++ b/PVE/Network/SDN/Zones/EvpnPlugin.pm @@ -40,6 +40,8 @@ sub properties { description => "Allow exitnodes to connect to evpn guests", optional => 1 }, + 'exitnodes-primary' => get_standard_option('pve-node', { + description => "Force traffic to this exitnode first."}), 'advertise-subnets' => { type => 'boolean', description => "Advertise evpn subnets if you have silent hosts", @@ -60,6 +62,7 @@ sub options { controller => { optional => 0 }, exitnodes => { optional => 1 }, 'exitnodes-local-routing' => { optional => 1 }, + 'exitnodes-primary' => { optional => 1 }, 'advertise-subnets' => { optional => 1 }, 'disable-arp-nd-suppression' => { optional => 1 }, mtu => { optional => 1 }, diff --git a/test/zones/evpn/advertise_subnets/expected_controller_config b/test/zones/evpn/advertise_subnets/expected_controller_config index aa6b3bd..cdaf0d4 100644 --- a/test/zones/evpn/advertise_subnets/expected_controller_config +++ b/test/zones/evpn/advertise_subnets/expected_controller_config @@ -21,6 +21,7 @@ router bgp 65000 neighbor 192.168.0.3 peer-group VTEP ! address-family l2vpn evpn + neighbor VTEP route-map MAP_VTEP_OUT out neighbor VTEP activate advertise-all-vni exit-address-family @@ -40,5 +41,7 @@ router bgp 65000 vrf vrf_myzone advertise ipv6 unicast exit-address-family ! +route-map MAP_VTEP_OUT permit 1 +! line vty ! \ No newline at end of file diff --git a/test/zones/evpn/disable_arp_nd_suppression/expected_controller_config b/test/zones/evpn/disable_arp_nd_suppression/expected_controller_config index c0ca898..e1d425f 100644 --- a/test/zones/evpn/disable_arp_nd_suppression/expected_controller_config +++ b/test/zones/evpn/disable_arp_nd_suppression/expected_controller_config @@ -21,11 +21,14 @@ router bgp 65000 neighbor 192.168.0.3 peer-group VTEP ! address-family l2vpn evpn + neighbor VTEP route-map MAP_VTEP_OUT out neighbor VTEP activate advertise-all-vni exit-address-family ! router bgp 65000 vrf vrf_myzone ! +route-map MAP_VTEP_OUT permit 1 +! line vty ! \ No newline at end of file diff --git a/test/zones/evpn/ebgp/expected_controller_config b/test/zones/evpn/ebgp/expected_controller_config index be3e1af..f6c8f18 100644 --- a/test/zones/evpn/ebgp/expected_controller_config +++ b/test/zones/evpn/ebgp/expected_controller_config @@ -33,6 +33,7 @@ router bgp 65001 exit-address-family ! address-family l2vpn evpn + neighbor VTEP route-map MAP_VTEP_OUT out neighbor VTEP activate advertise-all-vni autort as 65000 @@ -46,5 +47,7 @@ router bgp 65001 vrf vrf_myzone route-target export 65000:1000 exit-address-family ! +route-map MAP_VTEP_OUT permit 1 +! line vty ! \ No newline at end of file diff --git a/test/zones/evpn/ebgp_loopback/expected_controller_config b/test/zones/evpn/ebgp_loopback/expected_controller_config index 01cb2c2..64dff4e 100644 --- a/test/zones/evpn/ebgp_loopback/expected_controller_config +++ b/test/zones/evpn/ebgp_loopback/expected_controller_config @@ -38,6 +38,7 @@ router bgp 65001 exit-address-family ! address-family l2vpn evpn + neighbor VTEP route-map MAP_VTEP_OUT out neighbor VTEP activate advertise-all-vni autort as 65000 @@ -51,6 +52,8 @@ router bgp 65001 vrf vrf_myzone route-target export 65000:1000 exit-address-family ! +route-map MAP_VTEP_OUT permit 1 +! route-map correct_src permit 1 match ip address prefix-list loopbacks_ips set src 192.168.0.1 diff --git a/test/zones/evpn/exitnode/expected_controller_config b/test/zones/evpn/exitnode/expected_controller_config index 57ff6ff..8a535b3 100644 --- a/test/zones/evpn/exitnode/expected_controller_config +++ b/test/zones/evpn/exitnode/expected_controller_config @@ -29,6 +29,7 @@ router bgp 65000 exit-address-family ! address-family l2vpn evpn + neighbor VTEP route-map MAP_VTEP_OUT out neighbor VTEP activate advertise-all-vni exit-address-family @@ -48,5 +49,7 @@ router bgp 65000 vrf vrf_myzone default-originate ipv6 exit-address-family ! +route-map MAP_VTEP_OUT permit 1 +! line vty ! \ No newline at end of file diff --git a/test/zones/evpn/exitnode_local_routing/expected_controller_config b/test/zones/evpn/exitnode_local_routing/expected_controller_config index abd065b..876da86 100644 --- a/test/zones/evpn/exitnode_local_routing/expected_controller_config +++ b/test/zones/evpn/exitnode_local_routing/expected_controller_config @@ -22,6 +22,7 @@ router bgp 65000 neighbor 192.168.0.3 peer-group VTEP ! address-family l2vpn evpn + neighbor VTEP route-map MAP_VTEP_OUT out neighbor VTEP activate advertise-all-vni exit-address-family @@ -33,5 +34,7 @@ router bgp 65000 vrf vrf_myzone default-originate ipv6 exit-address-family ! +route-map MAP_VTEP_OUT permit 1 +! line vty ! \ No newline at end of file diff --git a/test/zones/evpn/exitnode_primary/expected_controller_config b/test/zones/evpn/exitnode_primary/expected_controller_config new file mode 100644 index 0000000..5306645 --- /dev/null +++ b/test/zones/evpn/exitnode_primary/expected_controller_config @@ -0,0 +1,61 @@ +log syslog informational +ip forwarding +ipv6 forwarding +frr defaults datacenter +service integrated-vtysh-config +hostname localhost +! +! +vrf vrf_myzone + vni 1000 +exit-vrf +! +router bgp 65000 + bgp router-id 192.168.0.1 + no bgp default ipv4-unicast + coalesce-time 1000 + neighbor VTEP peer-group + neighbor VTEP remote-as 65000 + neighbor VTEP bfd + neighbor 192.168.0.2 peer-group VTEP + neighbor 192.168.0.3 peer-group VTEP + ! + address-family ipv4 unicast + import vrf vrf_myzone + exit-address-family + ! + address-family ipv6 unicast + import vrf vrf_myzone + exit-address-family + ! + address-family l2vpn evpn + neighbor VTEP route-map MAP_VTEP_OUT out + neighbor VTEP activate + advertise-all-vni + exit-address-family +! +router bgp 65000 vrf vrf_myzone + bgp router-id 192.168.0.1 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family + ! + address-family ipv6 unicast + redistribute connected + exit-address-family + ! + address-family l2vpn evpn + default-originate ipv4 + default-originate ipv6 + exit-address-family +! +route-map MAP_VTEP_OUT permit 1 + match evpn vni 1000 + match evpn route-type prefix + set metric 200 +! +route-map MAP_VTEP_OUT permit 2 +! +line vty +! \ No newline at end of file diff --git a/test/zones/evpn/exitnode_primary/expected_sdn_interfaces b/test/zones/evpn/exitnode_primary/expected_sdn_interfaces new file mode 100644 index 0000000..5ab3084 --- /dev/null +++ b/test/zones/evpn/exitnode_primary/expected_sdn_interfaces @@ -0,0 +1,41 @@ +#version:1 + +auto myvnet +iface myvnet + address 10.0.0.1/24 + bridge_ports vxlan_myvnet + bridge_stp off + bridge_fd 0 + mtu 1450 + ip-forward on + arp-accept on + vrf vrf_myzone + +auto vrf_myzone +iface vrf_myzone + vrf-table auto + post-up ip route del vrf vrf_myzone unreachable default metric 4278198272 + +auto vrfbr_myzone +iface vrfbr_myzone + bridge-ports vrfvx_myzone + bridge_stp off + bridge_fd 0 + mtu 1450 + vrf vrf_myzone + +auto vrfvx_myzone +iface vrfvx_myzone + vxlan-id 1000 + vxlan-local-tunnelip 192.168.0.1 + bridge-learning off + bridge-arp-nd-suppress on + mtu 1450 + +auto vxlan_myvnet +iface vxlan_myvnet + vxlan-id 100 + vxlan-local-tunnelip 192.168.0.1 + bridge-learning off + bridge-arp-nd-suppress on + mtu 1450 diff --git a/test/zones/evpn/exitnode_primary/interfaces b/test/zones/evpn/exitnode_primary/interfaces new file mode 100644 index 0000000..66bb826 --- /dev/null +++ b/test/zones/evpn/exitnode_primary/interfaces @@ -0,0 +1,7 @@ +auto vmbr0 +iface vmbr0 inet static + address 192.168.0.1/24 + gateway 192.168.0.254 + bridge-ports eth0 + bridge-stp off + bridge-fd 0 diff --git a/test/zones/evpn/exitnode_primary/sdn_config b/test/zones/evpn/exitnode_primary/sdn_config new file mode 100644 index 0000000..bfeafc5 --- /dev/null +++ b/test/zones/evpn/exitnode_primary/sdn_config @@ -0,0 +1,26 @@ +{ + version => 1, + vnets => { + ids => { + myvnet => { tag => "100", type => "vnet", zone => "myzone" }, + }, + }, + + zones => { + ids => { myzone => { ipam => "pve", type => "evpn", controller => "evpnctl", 'vrf-vxlan' => 1000, 'exitnodes-primary' => "othernode", exitnodes => { 'localhost' => 1 } } }, + }, + controllers => { + ids => { evpnctl => { type => "evpn", 'peers' => '192.168.0.1,192.168.0.2,192.168.0.3', asn => "65000" } }, + }, + + subnets => { + ids => { 'myzone-10.0.0.0-24' => { + 'type' => 'subnet', + 'vnet' => 'myvnet', + 'gateway' => '10.0.0.1', + } + } + } +} + + diff --git a/test/zones/evpn/exitnode_snat/expected_controller_config b/test/zones/evpn/exitnode_snat/expected_controller_config index 57ff6ff..8a535b3 100644 --- a/test/zones/evpn/exitnode_snat/expected_controller_config +++ b/test/zones/evpn/exitnode_snat/expected_controller_config @@ -29,6 +29,7 @@ router bgp 65000 exit-address-family ! address-family l2vpn evpn + neighbor VTEP route-map MAP_VTEP_OUT out neighbor VTEP activate advertise-all-vni exit-address-family @@ -48,5 +49,7 @@ router bgp 65000 vrf vrf_myzone default-originate ipv6 exit-address-family ! +route-map MAP_VTEP_OUT permit 1 +! line vty ! \ No newline at end of file diff --git a/test/zones/evpn/ipv4/expected_controller_config b/test/zones/evpn/ipv4/expected_controller_config index c0ca898..e1d425f 100644 --- a/test/zones/evpn/ipv4/expected_controller_config +++ b/test/zones/evpn/ipv4/expected_controller_config @@ -21,11 +21,14 @@ router bgp 65000 neighbor 192.168.0.3 peer-group VTEP ! address-family l2vpn evpn + neighbor VTEP route-map MAP_VTEP_OUT out neighbor VTEP activate advertise-all-vni exit-address-family ! router bgp 65000 vrf vrf_myzone ! +route-map MAP_VTEP_OUT permit 1 +! line vty ! \ No newline at end of file diff --git a/test/zones/evpn/ipv4ipv6/expected_controller_config b/test/zones/evpn/ipv4ipv6/expected_controller_config index c0ca898..e1d425f 100644 --- a/test/zones/evpn/ipv4ipv6/expected_controller_config +++ b/test/zones/evpn/ipv4ipv6/expected_controller_config @@ -21,11 +21,14 @@ router bgp 65000 neighbor 192.168.0.3 peer-group VTEP ! address-family l2vpn evpn + neighbor VTEP route-map MAP_VTEP_OUT out neighbor VTEP activate advertise-all-vni exit-address-family ! router bgp 65000 vrf vrf_myzone ! +route-map MAP_VTEP_OUT permit 1 +! line vty ! \ No newline at end of file diff --git a/test/zones/evpn/ipv4ipv6nogateway/expected_controller_config b/test/zones/evpn/ipv4ipv6nogateway/expected_controller_config index c0ca898..e1d425f 100644 --- a/test/zones/evpn/ipv4ipv6nogateway/expected_controller_config +++ b/test/zones/evpn/ipv4ipv6nogateway/expected_controller_config @@ -21,11 +21,14 @@ router bgp 65000 neighbor 192.168.0.3 peer-group VTEP ! address-family l2vpn evpn + neighbor VTEP route-map MAP_VTEP_OUT out neighbor VTEP activate advertise-all-vni exit-address-family ! router bgp 65000 vrf vrf_myzone ! +route-map MAP_VTEP_OUT permit 1 +! line vty ! \ No newline at end of file diff --git a/test/zones/evpn/ipv6/expected_controller_config b/test/zones/evpn/ipv6/expected_controller_config index c0ca898..e1d425f 100644 --- a/test/zones/evpn/ipv6/expected_controller_config +++ b/test/zones/evpn/ipv6/expected_controller_config @@ -21,11 +21,14 @@ router bgp 65000 neighbor 192.168.0.3 peer-group VTEP ! address-family l2vpn evpn + neighbor VTEP route-map MAP_VTEP_OUT out neighbor VTEP activate advertise-all-vni exit-address-family ! router bgp 65000 vrf vrf_myzone ! +route-map MAP_VTEP_OUT permit 1 +! line vty ! \ No newline at end of file diff --git a/test/zones/evpn/multipath_relax/expected_controller_config b/test/zones/evpn/multipath_relax/expected_controller_config index 38cc836..18095ec 100644 --- a/test/zones/evpn/multipath_relax/expected_controller_config +++ b/test/zones/evpn/multipath_relax/expected_controller_config @@ -33,11 +33,14 @@ router bgp 65000 exit-address-family ! address-family l2vpn evpn + neighbor VTEP route-map MAP_VTEP_OUT out neighbor VTEP activate advertise-all-vni exit-address-family ! router bgp 65000 vrf vrf_myzone ! +route-map MAP_VTEP_OUT permit 1 +! line vty ! \ No newline at end of file -- 2.39.2