From: Dumitru Ceara <dce...@redhat.com>

This adds a multinode test that verifies OVN's integration with a
BGP-L2EVPN provider (FRR).  The test ensures that:
- Remote EVPN VTEPs are learned properly.
- OVN owned MACs are advertised to the remote BGP speakers
  through EVPN.
- Traffic flows properly between the OVN node and hosts connected
  to the external BGP speaker.

Reported-at: https://issues.redhat.com/browse/FDP-1542
Co-Authored-by: Ales Musil <amu...@redhat.com>
Signed-off-by: Ales Musil <amu...@redhat.com>
Signed-off-by: Dumitru Ceara <dce...@redhat.com>
---
Changes in v2:
- Improved test to check EVPN macs before and after the workload is
  running.
---
 tests/multinode-bgp-macros.at | 166 +++++++++++++++++++++++++++++++++-
 tests/multinode.at            | 134 ++++++++++++++++++++++++++-
 2 files changed, 293 insertions(+), 7 deletions(-)

diff --git a/tests/multinode-bgp-macros.at b/tests/multinode-bgp-macros.at
index 803aef909..4545d570c 100644
--- a/tests/multinode-bgp-macros.at
+++ b/tests/multinode-bgp-macros.at
@@ -4,13 +4,50 @@
 
 OVS_START_SHELL_HELPERS
 
-# m_setup_external_frr_router NODE BGP_AS BGP_IP
+# m_setup_external_frr_vrf NODE VNI LOCAL_IP NETNS
+#
+# Sets up a VRF in NETNS so that it can be used by FRR running in that
+# namespace to advertise EVPN routes.
+m_setup_external_frr_vrf() {
+    local node=$1 vni=$2 local_ip=$3 ns=$4
+
+    local ns_prefix="ip netns exec $ns "
+    local vrf=vrf-$vni
+    local br=br-$vni
+    local vxlan=vxlan-$vni
+    local lo=lo-$vni
+
+    check m_as $node $ns_prefix ip link add $vrf type vrf table $vni
+    on_exit "m_as $node $ns_prefix ip link del $vrf"
+    check m_as $node $ns_prefix ip link set $vrf up
+
+    # Add VNI bridge.
+    check m_as $node $ns_prefix ip link add $br type bridge
+    on_exit "m_as $node $ns_prefix ip link del $br"
+    check m_as $node $ns_prefix ip link set $br master $vrf addrgenmode none
+    check m_as $node $ns_prefix ip link set dev $br up
+
+    # Add VXLAN VTEP for the VNI.
+    check m_as $node $ns_prefix ip link add $vxlan type vxlan id $vni dstport 
4789 local $local_ip nolearning
+    on_exit "m_as $node $ns_prefix ip link del $vxlan"
+    check m_as $node $ns_prefix ip link set dev $vxlan up
+    check m_as $node $ns_prefix ip link set $vxlan master $br
+
+    # Add a dummy loopback to the VNI bridge to be used for advertising local
+    # MACs.
+    check m_as $node $ns_prefix ip link add name $lo type dummy
+    on_exit "m_as $node $ns_prefix ip link del $lo"
+    check m_as $node $ns_prefix ip link set $lo master $br
+    check m_as $node $ns_prefix ip link set $lo up
+}
+
+# m_setup_external_frr_router NODE BGP_AS BGP_ROUTER_ID BGP_IP [VNI]
 #
 # Sets up an external FRR BGP speaker 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
 m_setup_external_frr_router() {
-    local node=$1 bgp_as=$2 bgp_ip=$3
+    local node=$1 bgp_as=$2 bgp_router_id=$3 bgp_ip=$4 vni=$5
     local br_name=br-$node
 
     check m_as $node ovs-vsctl add-br $br_name
@@ -55,27 +92,38 @@ m_setup_external_frr_router() {
     on_exit "m_as $node systemctl stop frr"
     check m_as $node systemctl start frr
 
-    local frr_flags="-N frr-ns"
+    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
 
     router bgp $bgp_as
-      bgp router-id $bgp_ip
+      bgp router-id $bgp_router_id
+      no bgp ebgp-requires-policy
       neighbor ext1 interface remote-as external
       address-family ipv4 unicast
         neighbor ext1 soft-reconfiguration inbound
         neighbor ext1 prefix-list accept-all in
       exit-address-family
-      !
       address-family ipv6 unicast
         neighbor ext1 soft-reconfiguration inbound
         neighbor ext1 activate
       exit-address-family
+      address-family l2vpn evpn
+        neighbor ext1 activate
+        advertise-all-vni
+      exit-address-family
     " | podman exec -i $node vtysh $frr_flags
+
+    # Configure VRF, if any provided.
+    bgp_ip=$(echo $bgp_ip | cut -f 1 -d '/')
+    if [[[ -n "$vni" ]]]; then
+        m_setup_external_frr_vrf $node $vni $bgp_ip frr-ns
+    fi
 }
 
 # m_ovn_frr_router_name NODE
@@ -218,4 +266,112 @@ m_setup_ovn_frr_router() {
     " | podman exec -i $node vtysh
 }
 
+# m_setup_host_frr_vrf NODE VNI LOCAL_IP
+#
+# Sets up a VRF in the default net namespace so that it can be used by OVN
+# and FRR to advertise EVPN routes.
+m_setup_host_frr_vrf() {
+    local node=$1 vni=$2 local_ip=$3
+
+    local vrf=vrf-$vni
+    local br=br-$vni
+    local vxlan=vxlan-$vni
+    local lo=lo-$vni
+    local vxlan_port=4789
+
+    # Create a VXLAN tunnel OVS interface to be used by ovn-controller for
+    # forwarding/receiving traffic from dynamic remote VTEPs.
+    check m_as $node ovs-vsctl add-port br-int vxlan-ovs                     \
+            -- set interface vxlan-ovs type=vxlan                            \
+               options:local_ip=flow options:remote_ip=flow options:key=flow \
+               options:dst_port=$vxlan_port
+
+    # Setup a VRF for the VNI.
+    check m_as $node ip link add $vrf type vrf table $vni
+    on_exit "m_as $node ip link del $vrf"
+    check m_as $node ip link set $vrf up
+
+    # Add VNI bridge.
+    check m_as $node ip link add $br type bridge
+    on_exit "m_as $node ip link del $br"
+    check m_as $node ip link set $br master $vrf addrgenmode none
+    check m_as $node ip link set dev $br up
+
+    # Add VXLAN VTEP for the VNI (linked to the OVS vxlan_sys_<port> 
interface).
+    # Use a dstport different than the one used by OVS.
+    # This is fine because we don't actually want traffic to pass through
+    # the $vxlan interface.  FRR should read the dstport from the linked
+    # vxlan_sys_${vxlan_port} device.
+    local dstport=$((60000 + $vni))
+    check m_as $node ip link add $vxlan type vxlan   \
+        dev vxlan_sys_${vxlan_port}                  \
+        id $vni dstport $dstport local $local_ip nolearning
+    on_exit "m_as $node ip link del $vxlan"
+    check m_as $node ip link set dev $vxlan up
+    check m_as $node ip link set $vxlan master $br
+
+    # Add a dummy loopback to the VNI bridge to be used for advertising local
+    # MACs.
+    check m_as $node ip link add name $lo type dummy
+    on_exit "m_as $node ip link del $lo"
+    check m_as $node ip link set $lo master $br
+    check m_as $node ip link set $lo up
+}
+
+# m_setup_host_frr_router NODE BGP_AS BGP_ROUTER_ID BGP_IP VNI
+#
+# Sets up an FRR BGP speaker 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_setup_host_frr_router() {
+    local node=$1 bgp_as=$2 bgp_router_id=$3 bgp_ip=$4 vni=$5
+
+    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)
+
+    # Configure the BGP IP on the bridge LOCAL interface.
+    check m_as $node ip addr add $bgp_ip dev $br_name
+    check m_as $node ip link set $br_name up
+
+    # NOTE: we set "no bgp ebgp-requires-policy" to simplify EVPN deployments.
+    echo "configure
+    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 ipv4 unicast
+        redistribute kernel
+        neighbor $br_name prefix-list no-default out
+      exit-address-family
+      address-family ipv6 unicast
+        neighbor $br_name soft-reconfiguration inbound
+        neighbor $br_name prefix-list no-default out
+        redistribute kernel
+        neighbor $br_name activate
+      exit-address-family
+      address-family l2vpn evpn
+        neighbor $br_name activate
+        advertise-all-vni
+      exit-address-family
+    " | podman exec -i $node vtysh
+
+    # Configure VRF.
+    bgp_ip=$(echo $bgp_ip | cut -f 1 -d '/')
+    m_setup_host_frr_vrf $node $vni $bgp_ip
+}
+
 OVS_END_SHELL_HELPERS
diff --git a/tests/multinode.at b/tests/multinode.at
index 8ac625b6b..f217e5c46 100644
--- a/tests/multinode.at
+++ b/tests/multinode.at
@@ -3055,10 +3055,10 @@ add_guest_vm_and_connections() {
         $default_route $default_route_gw $lrp_guest_join
 }
 
-m_setup_external_frr_router ovn-gw-1 4200000100 41.41.41.41
+m_setup_external_frr_router ovn-gw-1 4200000100 41.41.41.41 41.41.41.41/32
 m_setup_ovn_frr_router      ovn-gw-1 4210000000 14.14.14.14 12:fb:d6:66:99:1c 
10
 
-m_setup_external_frr_router ovn-gw-2 4200000200 42.42.42.42
+m_setup_external_frr_router ovn-gw-2 4200000200 42.42.42.42 42.42.42.42/32
 m_setup_ovn_frr_router      ovn-gw-2 4210000000 24.24.24.24 22:fb:d6:66:99:2c 
20
 
 OVS_WAIT_UNTIL([m_as ovn-gw-2 vtysh -c 'show bgp vrf ovnvrf20 neighbors' | 
grep -qE 'Connections established 1'])
@@ -3613,3 +3613,133 @@ check_migration_between_gw1_and_gw2 "kill_gw1"
 
 AT_CLEANUP
 ])
+
+AT_SETUP([ovn multinode bgp L2 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.42.$vni.11
+host_bgp_ip_gw1=42.42.$vni.12
+ext_bgp_ip_gw2=42.42.$vni.21
+host_bgp_ip_gw2=42.42.$vni.22
+
+m_setup_external_frr_router ovn-gw-1 4200000100 $ext_bgp_ip_gw1 
$ext_bgp_ip_gw1/24 $vni
+m_setup_host_frr_router     ovn-gw-1 4210000000 $host_bgp_ip_gw1 
$host_bgp_ip_gw1/24 $vni
+
+m_setup_external_frr_router ovn-gw-2 4200000200 $ext_bgp_ip_gw2 
$ext_bgp_ip_gw2/24 $vni
+m_setup_host_frr_router     ovn-gw-2 4210000000 $host_bgp_ip_gw2 
$host_bgp_ip_gw2/24 $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'])
+
+# 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
+
+check multinode_nbctl 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
+
+# Configure "workloads" (VIF LSPs) on both chassis.
+check multinode_nbctl lsp-add ls w1                       \
+    -- lsp-set-addresses w1 "00:00:00:00:00:01 10.0.0.11"
+check multinode_nbctl lsp-add ls w2                       \
+    -- lsp-set-addresses w2 "00:00:00:00:00:02 10.0.0.12"
+
+check m_as ovn-gw-1 /data/create_fake_vm.sh w1 w1 00:00:00:00:00:01 1500 
10.0.0.11 24 10.0.0.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 
10.0.0.12 24 10.0.0.1 1000::12/64 1000::1
+m_wait_for_ports_up
+
+# Enable EVPN support for the distributed logical switch and redistribute
+# local FDBs.
+check multinode_nbctl set logical_switch ls       \
+    other_config:dynamic-routing-vni=$vni         \
+    other_config:dynamic-routing-redistribute=fdb
+check multinode_nbctl --wait=hv sync
+
+OVS_WAIT_UNTIL([m_as ovn-gw-1 bridge fdb | grep vxlan-10 | grep -q 
"00:00:00:00:00:00"])
+OVS_WAIT_UNTIL([m_as ovn-gw-2 bridge fdb | grep vxlan-10 | grep -q 
"00:00:00:00:00:00"])
+
+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
+])
+
+AS_BOX([Check traffic to "fabric" hosts - simulate external workloads])
+check m_as ovn-gw-1 ip link add evpn_host type veth peer evpn_host_peer
+on_exit "m_as ovn-gw-1 ip link del evpn_host"
+check m_as ovn-gw-1 ip link set netns frr-ns evpn_host_peer
+check m_as ovn-gw-1 ip netns exec frr-ns ip link set evpn_host_peer master 
br-10
+check m_as ovn-gw-1 ip netns exec frr-ns ip link set evpn_host_peer up
+check m_as ovn-gw-1 ip link set evpn_host addr 00:00:00:00:01:00
+check m_as ovn-gw-1 ip addr add dev evpn_host 10.0.0.41/24
+check m_as ovn-gw-1 ip link set evpn_host up
+
+check m_as ovn-gw-2 ip link add evpn_host type veth peer evpn_host_peer
+on_exit "m_as ovn-gw-2 ip link del evpn_host"
+check m_as ovn-gw-2 ip link set netns frr-ns evpn_host_peer
+check m_as ovn-gw-2 ip netns exec frr-ns ip link set evpn_host_peer master 
br-10
+check m_as ovn-gw-2 ip netns exec frr-ns ip link set evpn_host_peer up
+check m_as ovn-gw-2 ip link set evpn_host addr 00:00:00:00:02:00
+check m_as ovn-gw-2 ip addr add dev evpn_host 10.0.0.42/24
+check m_as ovn-gw-2 ip link set evpn_host up
+
+AS_BOX([Checking EVPN MACs on External BGP host])
+OVS_WAIT_FOR_OUTPUT([m_as ovn-gw-1 ip netns exec frr-ns vtysh --vty_socket 
/run/frr/frr-ns -c 'show evpn mac vni all'], [0], [dnl
+
+VNI 10 #MACs (local and remote) 2
+
+Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy
+MAC               Type   Flags Intf/Remote ES/VTEP            VLAN  Seq #'s
+00:00:00:00:00:01 remote       42.42.10.12                          0/0
+00:00:00:00:01:00 local        evpn_host_peer                       0/0
+])
+
+OVS_WAIT_FOR_OUTPUT([m_as ovn-gw-2 ip netns exec frr-ns vtysh --vty_socket 
/run/frr/frr-ns -c 'show evpn mac vni all'], [0], [dnl
+
+VNI 10 #MACs (local and remote) 2
+
+Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy
+MAC               Type   Flags Intf/Remote ES/VTEP            VLAN  Seq #'s
+00:00:00:00:00:02 remote       42.42.10.22                          0/0
+00:00:00:00:02:00 local        evpn_host_peer                       0/0
+])
+
+AS_BOX([Check traffic to "fabric" hosts - ping from fabric])
+OVS_WAIT_UNTIL([m_as ovn-gw-1 ping -W 1 -c 1 10.0.0.11])
+OVS_WAIT_UNTIL([m_as ovn-gw-2 ping -W 1 -c 1 10.0.0.12])
+
+# Remove "workloads" (VIF LSPs) on both chassis.
+check multinode_nbctl --wait=hv lsp-del w1 -- lsp-del w2
+
+AS_BOX([Checking EVPN MACs on External BGP host])
+OVS_WAIT_FOR_OUTPUT([m_as ovn-gw-1 ip netns exec frr-ns vtysh --vty_socket 
/run/frr/frr-ns -c 'show evpn mac vni all'], [0], [dnl
+
+VNI 10 #MACs (local and remote) 1
+
+Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy
+MAC               Type   Flags Intf/Remote ES/VTEP            VLAN  Seq #'s
+00:00:00:00:01:00 local        evpn_host_peer                       0/0
+])
+
+OVS_WAIT_FOR_OUTPUT([m_as ovn-gw-2 ip netns exec frr-ns vtysh --vty_socket 
/run/frr/frr-ns -c 'show evpn mac vni all'], [0], [dnl
+
+VNI 10 #MACs (local and remote) 1
+
+Flags: N=sync-neighs, I=local-inactive, P=peer-active, X=peer-proxy
+MAC               Type   Flags Intf/Remote ES/VTEP            VLAN  Seq #'s
+00:00:00:00:02:00 local        evpn_host_peer                       0/0
+])
+
+AT_CLEANUP
-- 
2.50.1

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to