This adds a multinode test that verifies OVN's integration with a BGP-L3EVPN provider (FRR). The test ensures that: - Remote EVPN VTEPs are learned properly. - OVN properly learns Type-5 EVPN routes (IP prefix routes). - Traffic flows properly between the OVN node and hosts connected to the external BGP speaker.
NOTE: There's a FIXME in the test tracking the fact that OVN currently doesn't support advertising OVN IPs via EVPN. Once that part is implemented the new test will have to slightly be adjusted as the blackhole route it currently adds will not be needed anymore. Reported-at: https://issues.redhat.com/browse/FDP-1391 Signed-off-by: Dumitru Ceara <[email protected]> --- tests/multinode-bgp-macros.at | 141 +++++++++++++++++++++++++++++++-- tests/multinode.at | 144 ++++++++++++++++++++++++++++++++++ 2 files changed, 280 insertions(+), 5 deletions(-) diff --git a/tests/multinode-bgp-macros.at b/tests/multinode-bgp-macros.at index 06d1806eae..01fe3da503 100644 --- a/tests/multinode-bgp-macros.at +++ b/tests/multinode-bgp-macros.at @@ -4,6 +4,20 @@ OVS_START_SHELL_HELPERS +# m_frr_ns_flags NETNS +# +# Builds the argument flags string to be passed to FRR when running in a +# network namespace. +m_frr_ns_flags() { + local ns=$1 + + if m_is_fedora; then + echo "--vty_socket /run/frr/$ns" + else + echo "-N $ns" + fi +} + # m_setup_external_frr_vrf NODE VNI VXLAN_IP LOCAL_MAC LOCAL_IP NETNS # # Sets up a VRF in NETNS so that it can be used by FRR running in that @@ -104,13 +118,9 @@ m_setup_external_frr_router() { # address. m_config_external_frr_router() { local node=$1 bgp_as=$2 bgp_router_id=$3 bgp_ip=$4 bgp_mac=$5 vni=$6 + local frr_flags=$(m_frr_ns_flags frr-ns) local br_name=br-$node - frr_flags="-N frr-ns" - if m_is_fedora; then - frr_flags="--vty_socket /run/frr/frr-ns" - fi - # NOTE: we set "no bgp ebgp-requires-policy" to simplify EVPN deployments. echo "configure ip prefix-list accept-all seq 5 permit any @@ -140,6 +150,64 @@ m_config_external_frr_router() { fi } +# m_config_external_frr_router_l3 NODE BGP_AS BGP_ROUTER_ID BGP_IP BGP_MAC VNI +# +# Configures an external FRR BGP speaker for L3 EVPN in a network namespace +# on the ovn-fake-multinode node NODE. The BGP autonomous system is +# configured to be BGP_AS. The speaker uses as BGP IP address, BGP_IP and +# BGP_MAC as mac address. +m_config_external_frr_router_l3() { + local node=$1 bgp_as=$2 bgp_router_id=$3 bgp_ip=$4 bgp_mac=$5 vni=$6 + local frr_flags=$(m_frr_ns_flags frr-ns) + local br_name=br-$node + + # NOTE: we set "no bgp ebgp-requires-policy" to simplify EVPN deployments. + echo "configure + ip prefix-list accept-all seq 5 permit any + + vrf vrf-$vni + vni $vni + exit-vrf + + router bgp $bgp_as + bgp router-id $bgp_router_id + no bgp ebgp-requires-policy + + neighbor ext1 soft-reconfiguration inbound + neighbor ext1 interface remote-as external + + address-family l2vpn evpn + neighbor ext1 activate + advertise-all-vni + advertise-svi-ip + exit-address-family + exit + + router bgp $bgp_as vrf vrf-$vni + bgp router-id $bgp_router_id + no bgp ebgp-requires-policy + + address-family ipv4 unicast + redistribute kernel + redistribute connected + exit-address-family + + address-family ipv6 unicast + redistribute kernel + redistribute connected + exit-address-family + + address-family l2vpn evpn + advertise ipv4 unicast + exit-address-family + exit + " | podman exec -i $node vtysh $frr_flags + + # Configure VRF, if any provided. + vxlan_ip=$(echo $bgp_ip | cut -f 1 -d '/') + m_setup_external_frr_vrf $node $vni $vxlan_ip $bgp_mac $bgp_ip frr-ns +} + # m_ovn_frr_router_name NODE m_ovn_frr_router_name() { local node=$1 @@ -415,4 +483,67 @@ m_config_host_frr_router() { m_setup_host_frr_vrf $node $vni $vxlan_ip $bgp_mac $bgp_ip } +# m_config_host_frr_router_l3 NODE BGP_AS BGP_ROUTER_ID BGP_IP BGP_MAC VNI +# +# Sets up an FRR BGP speaker speaker for L3 EVPN in the default network +# namespace on the ovn-fake-multinode node NODE. This speaker is running on +# a ovs bridge interface (simulating the fabric connection). +# +# The BGP autonomous system is configured to be BGP_AS and the FRR instance +# runs in vrf-VNI. +m_config_host_frr_router_l3() { + local node=$1 bgp_as=$2 bgp_router_id=$3 bgp_ip=$4 bgp_mac=$5 vni=$6 + + local br_name=br-$node physnet=physnet_${node}_ext0 + local lr=$(m_ovn_frr_router_name $node) + local lrp=$(m_ovn_frr_router_port_name $node) + local ls=$(m_ovn_frr_switch_name $node) + local lsp=$(m_ovn_frr_switch_port_name $node) + local lsp_bgp=$(m_ovn_frr_switch_bgp_port_name $node) + local lsp_ln=$(m_ovn_frr_switch_localnet_port_name $node) + + # NOTE: we set "no bgp ebgp-requires-policy" to simplify EVPN deployments. + echo "configure + vrf vrf-$vni + vni $vni + exit-vrf + + ip prefix-list no-default seq 5 deny 0.0.0.0/0 + ip prefix-list no-default seq 10 permit 0.0.0.0/0 le 32 + + ipv6 prefix-list no-default seq 5 deny ::/0 + ipv6 prefix-list no-default seq 10 permit ::/0 le 128 + + router bgp ${bgp_as} + bgp router-id $bgp_router_id + no bgp ebgp-requires-policy + neighbor $br_name interface remote-as external + + address-family l2vpn evpn + neighbor $br_name activate + advertise-all-vni + advertise-svi-ip + exit-address-family + exit + + router bgp ${bgp_as} vrf vrf-$vni + bgp router-id $bgp_router_id + no bgp ebgp-requires-policy + + address-family ipv4 unicast + redistribute kernel + redistribute connected + exit-address-family + + address-family l2vpn evpn + advertise ipv4 unicast + exit-address-family + exit + " | podman exec -i $node vtysh + + # Configure VRF. + vxlan_ip=$(echo $bgp_ip | cut -f 1 -d '/') + m_setup_host_frr_vrf $node $vni $vxlan_ip $bgp_mac $bgp_ip +} + OVS_END_SHELL_HELPERS diff --git a/tests/multinode.at b/tests/multinode.at index 604a9bd0f2..c7541aea44 100644 --- a/tests/multinode.at +++ b/tests/multinode.at @@ -3864,6 +3864,150 @@ OVS_WAIT_FOR_OUTPUT([m_as ovn-gw-2 ovs-ofctl dump-flows br-int table=OFTABLE_GET AT_CLEANUP +AT_SETUP([ovn multinode bgp L3 EVPN]) +check_fake_multinode_setup + +# Delete the multinode NB and OVS resources before starting the test. +cleanup_multinode_resources + +CHECK_VRF() + +vni=10 +ext_bgp_ip_gw1=42.10.$vni.11 +ext_bgp_mac_gw1=00:00:01:00:00:$vni +host_bgp_ip_gw1=42.10.$vni.12 +host_bgp_mac_gw1=00:00:00:01:00:$vni +ext_bgp_ip_gw2=42.20.$vni.21 +ext_bgp_mac_gw2=00:00:02:00:00:$vni +host_bgp_ip_gw2=42.20.$vni.22 +host_bgp_mac_gw2=00:00:00:02:00:$vni + +# Create an flat, distributed OVN localnet switch, with EVPN configured. + check m_as ovn-gw-1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex + check m_as ovn-gw-2 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex + check m_as ovn-gw-1 ovs-vsctl set open . external-ids:ovn-evpn-local-ip=$host_bgp_ip_gw1 + check m_as ovn-gw-2 ovs-vsctl set open . external-ids:ovn-evpn-local-ip=$host_bgp_ip_gw2 + # The tunnels need to be created before the call to "m_setup_host_frr_router()". + check m_as ovn-gw-1 ovs-vsctl set open . external-ids:ovn-evpn-vxlan-ports=4789 + check m_as ovn-gw-2 ovs-vsctl set open . external-ids:ovn-evpn-vxlan-ports=4789 + +m_setup_external_frr_router ovn-gw-1 $ext_bgp_ip_gw1/24 +m_config_external_frr_router_l3 ovn-gw-1 4200000100 $ext_bgp_ip_gw1 $ext_bgp_ip_gw1/24 $ext_bgp_mac_gw1 $vni +m_setup_host_frr_router ovn-gw-1 4210000000 $host_bgp_ip_gw1 $host_bgp_ip_gw1/24 $host_bgp_mac_gw1 $vni +m_config_host_frr_router_l3 ovn-gw-1 4210000000 $host_bgp_ip_gw1 $host_bgp_ip_gw1/24 $host_bgp_mac_gw1 $vni + +m_setup_external_frr_router ovn-gw-2 $ext_bgp_ip_gw2/24 +m_config_external_frr_router_l3 ovn-gw-2 4200000200 $ext_bgp_ip_gw2 $ext_bgp_ip_gw2/24 $ext_bgp_mac_gw2 $vni +m_setup_host_frr_router ovn-gw-2 4210000000 $host_bgp_ip_gw2 $host_bgp_ip_gw2/24 $host_bgp_mac_gw2 $vni +m_config_host_frr_router_l3 ovn-gw-2 4210000000 $host_bgp_ip_gw2 $host_bgp_ip_gw2/24 $host_bgp_mac_gw2 $vni + +OVS_WAIT_UNTIL([m_as ovn-gw-1 vtysh -c 'show bgp neighbors' | grep -qE 'Connections established 1']) +OVS_WAIT_UNTIL([m_as ovn-gw-2 vtysh -c 'show bgp neighbors' | grep -qE 'Connections established 1']) + +AS_BOX([Simulate external "fabric" hosts]) +check m_as ovn-gw-1 ip link add name lo-wl-$vni type dummy +on_exit "m_as ovn-gw-1 ip link del lo-wl-$vni" +check m_as ovn-gw-1 ip link set lo-wl-$vni address 00:01:01:01:01:$vni +check m_as ovn-gw-1 ip link set lo-wl-$vni master vrf-$vni +check m_as ovn-gw-1 ip a a dev lo-wl-$vni 77.77.1.$vni/32 +check m_as ovn-gw-1 ip link set lo-wl-$vni up + +check m_as ovn-gw-2 ip link add name lo-wl-$vni type dummy +on_exit "m_as ovn-gw-2 ip link del lo-wl-$vni" +check m_as ovn-gw-2 ip link set lo-wl-$vni address 00:02:02:02:02:$vni +check m_as ovn-gw-2 ip link set lo-wl-$vni master vrf-$vni +check m_as ovn-gw-2 ip a a dev lo-wl-$vni 77.77.2.$vni/32 +check m_as ovn-gw-2 ip link set lo-wl-$vni up + +check multinode_nbctl \ + -- lr-add lr \ + -- set logical_router lr options:dynamic-routing=true \ + options:requested-tnl-key=$vni \ + -- lrp-add lr lr-gw1 $host_bgp_mac_gw1 $host_bgp_ip_gw1/24 \ + -- lrp-set-gateway-chassis lr-gw1 ovn-gw-1 10 \ + -- lrp-add lr lr-gw2 $host_bgp_mac_gw2 $host_bgp_ip_gw2/24 \ + -- lrp-set-gateway-chassis lr-gw2 ovn-gw-2 10 \ + -- lrp-add lr lr-int1 00:00:00:00:01:02 30.0.1.1/24 \ + -- lrp-set-options lr-int1 dynamic-routing-redistribute=connected \ + -- lrp-add lr lr-int2 00:00:00:00:01:02 30.0.2.1/24 \ + -- lrp-set-options lr-int2 dynamic-routing-redistribute=connected \ + -- ls-add ls \ + -- lsp-add ls ls-ln \ + -- lsp-set-type ls-ln localnet \ + -- lsp-set-addresses ls-ln unknown \ + -- lsp-set-options ls-ln network_name=public \ + -- lsp-add ls ls-lr-gw1 \ + -- lsp-set-type ls-lr-gw1 router \ + -- lsp-set-options ls-lr-gw1 router-port=lr-gw1 \ + -- lsp-set-addresses ls-lr-gw1 router \ + -- lsp-add ls ls-lr-gw2 \ + -- lsp-set-type ls-lr-gw2 router \ + -- lsp-set-options ls-lr-gw2 router-port=lr-gw2 \ + -- lsp-set-addresses ls-lr-gw2 router \ + -- ls-add ls-int1 \ + -- lsp-add ls-int1 ls-int1-lr \ + -- lsp-set-type ls-int1-lr router \ + -- lsp-set-options ls-int1-lr router-port=lr-int1 \ + -- lsp-set-addresses ls-int1-lr router \ + -- ls-add ls-int2 \ + -- lsp-add ls-int2 ls-int2-lr \ + -- lsp-set-type ls-int2-lr router \ + -- lsp-set-options ls-int2-lr router-port=lr-int2 \ + -- lsp-set-addresses ls-int2-lr router + +check multinode_nbctl \ + -- lsp-add ls-int1 w1 \ + -- lsp-set-addresses w1 "00:00:00:00:00:01 30.0.1.11" \ + -- lsp-add ls-int2 w2 \ + -- lsp-set-addresses w2 "00:00:00:00:00:02 30.0.2.11" + +check m_as ovn-gw-1 /data/create_fake_vm.sh w1 w1 \ + 00:00:00:00:00:01 1500 30.0.1.11 24 30.0.1.1 1000::11/64 1000::1 +check m_as ovn-gw-2 /data/create_fake_vm.sh w2 w2 \ + 00:00:00:00:00:02 1500 30.0.2.11 24 30.0.2.1 1000::11/64 1000::1 + +m_wait_for_ports_up + +# Enable EVPN support for the distributed logical switch. +check multinode_nbctl set logical_switch ls \ + other_config:dynamic-routing-vni=$vni + +check multinode_nbctl --wait=hv sync +dp_key=$(m_fetch_column Datapath_Binding tunnel_key external_ids:name=ls) + +OVS_WAIT_UNTIL([m_as ovn-gw-1 bridge fdb | grep vxlan-10 | grep -q "$ext_bgp_mac_gw1"]) +OVS_WAIT_UNTIL([m_as ovn-gw-2 bridge fdb | grep vxlan-10 | grep -q "$ext_bgp_mac_gw2"]) + +AS_BOX([Checking Remote VTEPs learned in OVN]) +OVS_WAIT_FOR_OUTPUT_UNQUOTED([m_as ovn-gw-1 ovn-appctl evpn/remote-vtep-list | sort], [0], [dnl +IP: $ext_bgp_ip_gw1, port: 4789, vni: 10 +]) +OVS_WAIT_FOR_OUTPUT_UNQUOTED([m_as ovn-gw-2 ovn-appctl evpn/remote-vtep-list | sort], [0], [dnl +IP: $ext_bgp_ip_gw2, port: 4789, vni: 10 +]) + +# TODO FIXME: https://issues.redhat.com/browse/FDP-1390 +# OVN should support advertising router IPs on EVPN logical switches connected +# to logical routers. Until then simulate that with a blackhole route. +check m_as ovn-gw-1 ip route add table $vni blackhole $host_bgp_ip_gw1/32 +on_exit "m_as ovn-gw-1 ip route del table $vni $host_bgp_ip_gw1/32" +check m_as ovn-gw-2 ip route add table $vni blackhole $host_bgp_ip_gw2/32 +on_exit "m_as ovn-gw-2 ip route del table $vni $host_bgp_ip_gw2/32" + +AS_BOX([Check traffic to "fabric" hosts - ping from fabric]) +OVS_WAIT_UNTIL([m_as ovn-gw-1 ip netns exec frr-ns ip vrf exec vrf-$vni ping -c1 30.0.1.11]) +OVS_WAIT_UNTIL([m_as ovn-gw-2 ip netns exec frr-ns ip vrf exec vrf-$vni ping -c1 30.0.2.11]) + +# Check that OVN learned the ARPs. +OVS_WAIT_FOR_OUTPUT_UNQUOTED([m_as ovn-gw-1 ovn-appctl evpn/vtep-arp-list | cut -d',' -f2- | sort], [0], [dnl + VNI: $vni, MAC: 00:00:01:00:00:10, IP: 42.10.10.11, dp_key: $dp_key +]) +OVS_WAIT_FOR_OUTPUT_UNQUOTED([m_as ovn-gw-2 ovn-appctl evpn/vtep-arp-list | cut -d',' -f2- | sort], [0], [dnl + VNI: $vni, MAC: 00:00:02:00:00:10, IP: 42.20.10.21, dp_key: $dp_key +]) + +AT_CLEANUP + AT_SETUP([redirect-bridged to non-gw destination switch port]) check_fake_multinode_setup -- 2.51.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
