From f68439b16e7d16fd400a0b833256c9ea0c18065c Mon Sep 17 00:00:00 2001 From: Samuel Benko Date: Thu, 23 Apr 2026 10:40:33 +0200 Subject: [PATCH 1/3] chore: rename example Signed-off-by: Samuel Benko --- sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/.gitignore | 0 sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/README.md | 0 .../routers/router1/r1-1.vtysh | 0 .../routers/router1/r1-2.vtysh | 0 .../routers/router1/r1-vxlan.cmd | 0 .../routers/router1/r1-vxlan2.cmd | 0 .../routers/router2/r2-1.vtysh | 0 .../routers/router2/r2-2.vtysh | 0 .../routers/router2/r2-vxlan.cmd | 0 .../routers/router2/r2-vxlan2.cmd | 0 sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/run.sh | 0 sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/run2.sh | 0 .../scripts/PC-interfaces2.sh | 0 .../scripts/step1-interfaces.sh | 0 .../sonic-vpp01.clab.yml | 0 .../sonic-vpp02.clab.yml | 0 sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/stop.sh | 0 sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/stop2.sh | 0 18 files changed, 0 insertions(+), 0 deletions(-) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/.gitignore (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/README.md (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/routers/router1/r1-1.vtysh (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/routers/router1/r1-2.vtysh (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/routers/router1/r1-vxlan.cmd (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/routers/router1/r1-vxlan2.cmd (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/routers/router2/r2-1.vtysh (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/routers/router2/r2-2.vtysh (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/routers/router2/r2-vxlan.cmd (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/routers/router2/r2-vxlan2.cmd (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/run.sh (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/run2.sh (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/scripts/PC-interfaces2.sh (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/scripts/step1-interfaces.sh (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/sonic-vpp01.clab.yml (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/sonic-vpp02.clab.yml (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/stop.sh (100%) rename sonic-vpp/{sonic-vpp-L3-BGPEVPN => sonic-vpp-BGPEVPN}/stop2.sh (100%) diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/.gitignore b/sonic-vpp/sonic-vpp-BGPEVPN/.gitignore similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/.gitignore rename to sonic-vpp/sonic-vpp-BGPEVPN/.gitignore diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/README.md b/sonic-vpp/sonic-vpp-BGPEVPN/README.md similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/README.md rename to sonic-vpp/sonic-vpp-BGPEVPN/README.md diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router1/r1-1.vtysh b/sonic-vpp/sonic-vpp-BGPEVPN/routers/router1/r1-1.vtysh similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router1/r1-1.vtysh rename to sonic-vpp/sonic-vpp-BGPEVPN/routers/router1/r1-1.vtysh diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router1/r1-2.vtysh b/sonic-vpp/sonic-vpp-BGPEVPN/routers/router1/r1-2.vtysh similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router1/r1-2.vtysh rename to sonic-vpp/sonic-vpp-BGPEVPN/routers/router1/r1-2.vtysh diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router1/r1-vxlan.cmd b/sonic-vpp/sonic-vpp-BGPEVPN/routers/router1/r1-vxlan.cmd similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router1/r1-vxlan.cmd rename to sonic-vpp/sonic-vpp-BGPEVPN/routers/router1/r1-vxlan.cmd diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router1/r1-vxlan2.cmd b/sonic-vpp/sonic-vpp-BGPEVPN/routers/router1/r1-vxlan2.cmd similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router1/r1-vxlan2.cmd rename to sonic-vpp/sonic-vpp-BGPEVPN/routers/router1/r1-vxlan2.cmd diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router2/r2-1.vtysh b/sonic-vpp/sonic-vpp-BGPEVPN/routers/router2/r2-1.vtysh similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router2/r2-1.vtysh rename to sonic-vpp/sonic-vpp-BGPEVPN/routers/router2/r2-1.vtysh diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router2/r2-2.vtysh b/sonic-vpp/sonic-vpp-BGPEVPN/routers/router2/r2-2.vtysh similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router2/r2-2.vtysh rename to sonic-vpp/sonic-vpp-BGPEVPN/routers/router2/r2-2.vtysh diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router2/r2-vxlan.cmd b/sonic-vpp/sonic-vpp-BGPEVPN/routers/router2/r2-vxlan.cmd similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router2/r2-vxlan.cmd rename to sonic-vpp/sonic-vpp-BGPEVPN/routers/router2/r2-vxlan.cmd diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router2/r2-vxlan2.cmd b/sonic-vpp/sonic-vpp-BGPEVPN/routers/router2/r2-vxlan2.cmd similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/routers/router2/r2-vxlan2.cmd rename to sonic-vpp/sonic-vpp-BGPEVPN/routers/router2/r2-vxlan2.cmd diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/run.sh b/sonic-vpp/sonic-vpp-BGPEVPN/run.sh similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/run.sh rename to sonic-vpp/sonic-vpp-BGPEVPN/run.sh diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/run2.sh b/sonic-vpp/sonic-vpp-BGPEVPN/run2.sh similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/run2.sh rename to sonic-vpp/sonic-vpp-BGPEVPN/run2.sh diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/scripts/PC-interfaces2.sh b/sonic-vpp/sonic-vpp-BGPEVPN/scripts/PC-interfaces2.sh similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/scripts/PC-interfaces2.sh rename to sonic-vpp/sonic-vpp-BGPEVPN/scripts/PC-interfaces2.sh diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/scripts/step1-interfaces.sh b/sonic-vpp/sonic-vpp-BGPEVPN/scripts/step1-interfaces.sh similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/scripts/step1-interfaces.sh rename to sonic-vpp/sonic-vpp-BGPEVPN/scripts/step1-interfaces.sh diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/sonic-vpp01.clab.yml b/sonic-vpp/sonic-vpp-BGPEVPN/sonic-vpp01.clab.yml similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/sonic-vpp01.clab.yml rename to sonic-vpp/sonic-vpp-BGPEVPN/sonic-vpp01.clab.yml diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/sonic-vpp02.clab.yml b/sonic-vpp/sonic-vpp-BGPEVPN/sonic-vpp02.clab.yml similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/sonic-vpp02.clab.yml rename to sonic-vpp/sonic-vpp-BGPEVPN/sonic-vpp02.clab.yml diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/stop.sh b/sonic-vpp/sonic-vpp-BGPEVPN/stop.sh similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/stop.sh rename to sonic-vpp/sonic-vpp-BGPEVPN/stop.sh diff --git a/sonic-vpp/sonic-vpp-L3-BGPEVPN/stop2.sh b/sonic-vpp/sonic-vpp-BGPEVPN/stop2.sh similarity index 100% rename from sonic-vpp/sonic-vpp-L3-BGPEVPN/stop2.sh rename to sonic-vpp/sonic-vpp-BGPEVPN/stop2.sh From 9799b8723445c048e52bab5d25af13c644628d8e Mon Sep 17 00:00:00 2001 From: Samuel Benko Date: Fri, 24 Apr 2026 09:53:30 +0200 Subject: [PATCH 2/3] refactor sonic-vpp-BGPEVPN example for clarity Signed-off-by: Samuel Benko --- sonic-vpp/sonic-vpp-BGPEVPN/.gitignore | 15 +- sonic-vpp/sonic-vpp-BGPEVPN/lib/common.sh | 113 +++++ ...onic-vpp02.clab.yml => multi-vni.clab.yml} | 2 +- .../router1/{r1-2.vtysh => bgp-evpn.vtysh} | 0 .../{r1-1.vtysh => bgp-underlay.vtysh} | 0 .../{r1-vxlan2.cmd => vxlan-multi-vni.cmd} | 2 +- .../{r1-vxlan.cmd => vxlan-single-vni.cmd} | 4 +- .../router2/{r2-2.vtysh => bgp-evpn.vtysh} | 0 .../{r2-1.vtysh => bgp-underlay.vtysh} | 0 .../{r2-vxlan2.cmd => vxlan-multi-vni.cmd} | 0 .../{r2-vxlan.cmd => vxlan-single-vni.cmd} | 0 sonic-vpp/sonic-vpp-BGPEVPN/run-multi-vni.sh | 53 +++ sonic-vpp/sonic-vpp-BGPEVPN/run-single-vni.sh | 48 ++ sonic-vpp/sonic-vpp-BGPEVPN/run.sh | 105 ----- sonic-vpp/sonic-vpp-BGPEVPN/run2.sh | 88 ---- .../scripts/PC-interfaces2.sh | 33 -- .../scripts/setup-multi-vni.sh | 44 ++ .../scripts/setup-single-vni.sh | 31 ++ .../scripts/step1-interfaces.sh | 24 - ...nic-vpp01.clab.yml => single-vni.clab.yml} | 8 +- sonic-vpp/sonic-vpp-BGPEVPN/stop-multi-vni.sh | 2 + .../sonic-vpp-BGPEVPN/stop-single-vni.sh | 2 + sonic-vpp/sonic-vpp-BGPEVPN/stop.sh | 3 - sonic-vpp/sonic-vpp-BGPEVPN/stop2.sh | 3 - .../tests/test_l2_vxlan_advanced.sh | 326 +++++++++++++ .../tests/test_multi_vlan_vxlan.sh | 431 ++++++++++++++++++ 26 files changed, 1065 insertions(+), 272 deletions(-) create mode 100644 sonic-vpp/sonic-vpp-BGPEVPN/lib/common.sh rename sonic-vpp/sonic-vpp-BGPEVPN/{sonic-vpp02.clab.yml => multi-vni.clab.yml} (97%) rename sonic-vpp/sonic-vpp-BGPEVPN/routers/router1/{r1-2.vtysh => bgp-evpn.vtysh} (100%) rename sonic-vpp/sonic-vpp-BGPEVPN/routers/router1/{r1-1.vtysh => bgp-underlay.vtysh} (100%) rename sonic-vpp/sonic-vpp-BGPEVPN/routers/router1/{r1-vxlan2.cmd => vxlan-multi-vni.cmd} (86%) rename sonic-vpp/sonic-vpp-BGPEVPN/routers/router1/{r1-vxlan.cmd => vxlan-single-vni.cmd} (57%) rename sonic-vpp/sonic-vpp-BGPEVPN/routers/router2/{r2-2.vtysh => bgp-evpn.vtysh} (100%) rename sonic-vpp/sonic-vpp-BGPEVPN/routers/router2/{r2-1.vtysh => bgp-underlay.vtysh} (100%) rename sonic-vpp/sonic-vpp-BGPEVPN/routers/router2/{r2-vxlan2.cmd => vxlan-multi-vni.cmd} (100%) rename sonic-vpp/sonic-vpp-BGPEVPN/routers/router2/{r2-vxlan.cmd => vxlan-single-vni.cmd} (100%) create mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/run-multi-vni.sh create mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/run-single-vni.sh delete mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/run.sh delete mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/run2.sh delete mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/scripts/PC-interfaces2.sh create mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/scripts/setup-multi-vni.sh create mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/scripts/setup-single-vni.sh delete mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/scripts/step1-interfaces.sh rename sonic-vpp/sonic-vpp-BGPEVPN/{sonic-vpp01.clab.yml => single-vni.clab.yml} (60%) create mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/stop-multi-vni.sh create mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/stop-single-vni.sh delete mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/stop.sh delete mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/stop2.sh create mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/tests/test_l2_vxlan_advanced.sh create mode 100755 sonic-vpp/sonic-vpp-BGPEVPN/tests/test_multi_vlan_vxlan.sh diff --git a/sonic-vpp/sonic-vpp-BGPEVPN/.gitignore b/sonic-vpp/sonic-vpp-BGPEVPN/.gitignore index c7f1bf9..f602a00 100644 --- a/sonic-vpp/sonic-vpp-BGPEVPN/.gitignore +++ b/sonic-vpp/sonic-vpp-BGPEVPN/.gitignore @@ -1,13 +1,10 @@ -# IDE specific files # -###################### +# ContainerLab runtime state +/clab-* + +# Backups and editor junk +*.bak .idea/ -# Sensitive files # -########## +# Sensitive files *.env *.key - -# Project Build Related # -############################ -/clab-* -*.bak diff --git a/sonic-vpp/sonic-vpp-BGPEVPN/lib/common.sh b/sonic-vpp/sonic-vpp-BGPEVPN/lib/common.sh new file mode 100644 index 0000000..0e1b0f4 --- /dev/null +++ b/sonic-vpp/sonic-vpp-BGPEVPN/lib/common.sh @@ -0,0 +1,113 @@ +#!/bin/bash +# +# common.sh — Shared helpers for SONiC-VPP BGP EVPN examples. +# Source this from run-*.sh scripts; do not execute directly. + +# ----------------------------------------------------------------------------- +# Prerequisites +# ----------------------------------------------------------------------------- +check_prereqs() { + if ! command -v docker &> /dev/null; then + echo "Docker is not installed. See https://docs.docker.com/engine/install/" + exit 1 + fi + + if ! command -v clab &> /dev/null; then + echo "Containerlab is not installed. See https://containerlab.dev/install/" + exit 1 + fi + + if ! command -v sshpass &> /dev/null; then + echo "sshpass is not installed. Install it with: sudo apt-get install sshpass" + exit 1 + fi + + if ! groups "$USER" | grep -q '\bdocker\b'; then + echo "You are not a member of the docker group. Run:" + echo " sudo usermod -aG docker $USER" + echo "Then log out and back in for the changes to take effect." + exit 1 + fi +} + +# ----------------------------------------------------------------------------- +# Topology deployment +# ----------------------------------------------------------------------------- +deploy_topology() { + local topo_file="$1" + + if ! sudo clab deploy --topo "$topo_file"; then + echo "Deploy failed. To retry from a clean state:" + echo " sudo clab destroy --topo $topo_file" + echo "Then rerun this script." + exit 1 + fi +} + +# ----------------------------------------------------------------------------- +# Wait until the expected number of nodes report as healthy. +# +# Args: +# $1 — topology file (passed to `clab inspect`) +# $2 — number of nodes expected to be healthy +# ----------------------------------------------------------------------------- +wait_for_healthy() { + local topo_file="$1" + local target="$2" + local retry_interval=10 + local max_retries=20 + + for ((i=1; i<=max_retries; i++)); do + echo "Attempt $i of $max_retries..." + local healthy + healthy=$(clab inspect --topo "$topo_file" -f json \ + | grep -o '"status": *"healthy"' | wc -l) + + if [ "$healthy" -ge "$target" ]; then + echo "Success: $healthy nodes are healthy. Continuing..." + return 0 + fi + + echo "Currently $healthy healthy nodes. Waiting for $target..." + if [ "$i" -eq "$max_retries" ]; then + echo "Error: Timeout waiting for $target healthy nodes." + exit 1 + fi + sleep "$retry_interval" + done +} + +# ----------------------------------------------------------------------------- +# you can set any log level for any component here +# ----------------------------------------------------------------------------- +set_swss_log_level() { + local ssh_cmd="$1" + $ssh_cmd swssloglevel -l ERROR -a + $ssh_cmd swssloglevel -l SAI_LOG_LEVEL_INFO -s -a +} + +# ----------------------------------------------------------------------------- +# Apply a config file to a router. +# +# Args: +# $1 — SSH command prefix (e.g. "sshpass -p admin ssh admin@...") +# $2 — path to config file (relative to the caller's working directory) +# ----------------------------------------------------------------------------- +execute() { + local ssh_cmd="$1" + local file="$2" + + if [[ "$file" == *.vtysh ]]; then + $ssh_cmd bash < /dev/null; then - echo "Docker is not installed. Please install Docker (https://docs.docker.com/engine/install/) and try again." - exit 1 -fi - -# Check if clab is installed -if ! command -v clab &> /dev/null; then - echo "Containerlab is not installed. Please install Containerlab (https://containerlab.dev/install/) and try again." - exit 1 -fi - -# Check if the user is part of the docker group -if ! groups $USER | grep -q '\bdocker\b'; then - echo "You are not a member of the docker group. Please add yourself to the docker group using:" - echo "sudo usermod -aG docker $USER" - echo "Then log out and back in for the changes to take effect." - exit 1 -fi - -set -x - -ROUTER1="sshpass -p admin ssh admin@clab-sonic-vpp01-router1" -ROUTER2="sshpass -p admin ssh admin@clab-sonic-vpp01-router2" - -if ! sudo clab deploy --topo sonic-vpp01.clab.yml; then - { set +x; } > /dev/null 2>&1 - echo "Alternatively, you can manually destroy the existing containers using 'sudo clab destroy --topo sonic-vpp01.clab.yml' and rerun this script." - exit 1 -fi - - -#Let's wait for the VMs to boot up - -RETRY_INTERVAL=10 # seconds -MAX_RETRIES=20 -TARGET_HEALTHY_COUNT=2 - -for ((i=1; i<=MAX_RETRIES; i++)); do - echo "Attempt $i of $MAX_RETRIES..." - - # Run the containerlab inspect and count 'healthy' statuses - HEALTHY_COUNT=$(clab inspect --topo sonic-vpp01.clab.yml -f json | grep -o '"status": *"healthy"' | wc -l) - - if [ "$HEALTHY_COUNT" -ge "$TARGET_HEALTHY_COUNT" ]; then - echo "Success: $HEALTHY_COUNT nodes are healthy. Continuing..." - break - else - echo "Currently $HEALTHY_COUNT healthy nodes. Waiting for $TARGET_HEALTHY_COUNT..." - if [ "$i" -eq "$MAX_RETRIES" ]; then - echo "Error: Timeout reached. Not all containers are healthy." - exit 1 - fi - sleep $RETRY_INTERVAL - fi -done - -set_swss_log_level() { - $1 swssloglevel -l ERROR -a - $1 swssloglevel -l SAI_LOG_LEVEL_INFO -s -a -} - -set_swss_log_level "$ROUTER1" -set_swss_log_level "$ROUTER2" - -./scripts/step1-interfaces.sh - -execute() { - local host=$1 - local file=$2 - - if [[ "$file" == *.vtysh ]]; then - # Send all commands in the file to vtysh via heredoc inside ssh - $1 bash < /dev/null; then - echo "Docker is not installed. Please install Docker and try again." - exit 1 -fi - -if ! command -v clab &> /dev/null; then - echo "Containerlab is not installed. Please install Containerlab and try again." - exit 1 -fi - -set -x - -ROUTER1="sshpass -p admin ssh admin@clab-sonic-vpp02-router1" -ROUTER2="sshpass -p admin ssh admin@clab-sonic-vpp02-router2" - -if ! sudo clab deploy --topo sonic-vpp02.clab.yml; then - { set +x; } > /dev/null 2>&1 - echo "Deploy failed. You can manually destroy with 'sudo clab destroy --topo sonic-vpp02.clab.yml' and retry." - exit 1 -fi - -# Wait for VMs to boot up -RETRY_INTERVAL=10 -MAX_RETRIES=20 -TARGET_HEALTHY_COUNT=2 - -for ((i=1; i<=MAX_RETRIES; i++)); do - echo "Attempt $i of $MAX_RETRIES..." - HEALTHY_COUNT=$(clab inspect --topo sonic-vpp02.clab.yml -f json | grep -o '"status": *"healthy"' | wc -l) - - if [ "$HEALTHY_COUNT" -ge "$TARGET_HEALTHY_COUNT" ]; then - echo "Success: $HEALTHY_COUNT nodes are healthy. Continuing..." - break - else - echo "Currently $HEALTHY_COUNT healthy nodes. Waiting for $TARGET_HEALTHY_COUNT..." - if [ "$i" -eq "$MAX_RETRIES" ]; then - echo "Error: Timeout reached. Not all containers are healthy." - exit 1 - fi - sleep $RETRY_INTERVAL - fi -done - -set_swss_log_level() { - $1 swssloglevel -l ERROR -a - $1 swssloglevel -l SAI_LOG_LEVEL_INFO -s -a -} - -set_swss_log_level "$ROUTER1" -set_swss_log_level "$ROUTER2" - -./scripts/PC-interfaces2.sh - -execute() { - local host=$1 - local file=$2 - - if [[ "$file" == *.vtysh ]]; then - $1 bash </dev/null || true + +sudo docker exec -d clab-${LAB}-PC2 ip link set dev eth2 address aa:aa:aa:aa:aa:02 +sudo docker exec -d clab-${LAB}-PC2 ip link set eth2 up +sudo docker exec -d clab-${LAB}-PC2 ip addr add 10.100.1.2/24 dev eth2 +sudo docker exec clab-${LAB}-PC2 ip route del default 2>/dev/null || true + +# ---- PCs on VNI 2000 / VLAN 200 ----------------------------------------- +sudo docker exec -d clab-${LAB}-PC3 ip link set dev eth2 address bb:bb:bb:bb:bb:03 +sudo docker exec -d clab-${LAB}-PC3 ip link set eth2 up +sudo docker exec -d clab-${LAB}-PC3 ip addr add 10.200.1.1/24 dev eth2 +sudo docker exec clab-${LAB}-PC3 ip route del default 2>/dev/null || true + +sudo docker exec -d clab-${LAB}-PC4 ip link set dev eth2 address bb:bb:bb:bb:bb:04 +sudo docker exec -d clab-${LAB}-PC4 ip link set eth2 up +sudo docker exec -d clab-${LAB}-PC4 ip addr add 10.200.1.2/24 dev eth2 +sudo docker exec clab-${LAB}-PC4 ip route del default 2>/dev/null || true + +# ---- Router underlay interfaces ----------------------------------------- +${ROUTER1} sudo config interface ip add Ethernet0 10.0.1.1/31 +${ROUTER1} sudo config interface startup Ethernet0 +${ROUTER1} sudo config interface startup Ethernet4 +${ROUTER1} sudo config interface startup Ethernet8 + +${ROUTER2} sudo config interface ip add Ethernet0 10.0.1.0/31 +${ROUTER2} sudo config interface startup Ethernet0 +${ROUTER2} sudo config interface startup Ethernet4 +${ROUTER2} sudo config interface startup Ethernet8 diff --git a/sonic-vpp/sonic-vpp-BGPEVPN/scripts/setup-single-vni.sh b/sonic-vpp/sonic-vpp-BGPEVPN/scripts/setup-single-vni.sh new file mode 100755 index 0000000..2a39dbf --- /dev/null +++ b/sonic-vpp/sonic-vpp-BGPEVPN/scripts/setup-single-vni.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# +# Configure PC interfaces and router underlay IPs for the single-VNI lab. + +set -e + +LAB="sonic-vpp-single-vni" +ROUTER1="sshpass -p admin ssh admin@clab-${LAB}-router1" +ROUTER2="sshpass -p admin ssh admin@clab-${LAB}-router2" + +# ---- PCs on VNI 1000 / VLAN 100 ----------------------------------------- +sudo docker exec -d clab-${LAB}-PC1 ip link set dev eth2 address aa:aa:aa:aa:aa:aa +sudo docker exec -d clab-${LAB}-PC1 ip link set eth2 up +sudo docker exec -d clab-${LAB}-PC1 ip addr add 168.95.10.2/16 dev eth2 +# Drop clab mgmt default route so non-VXLAN traffic fails cleanly +# instead of escaping via eth0 (172.20.20.0/24). +sudo docker exec clab-${LAB}-PC1 ip route del default 2>/dev/null || true + +sudo docker exec -d clab-${LAB}-PC2 ip link set dev eth2 address be:ef:be:ef:be:ef +sudo docker exec -d clab-${LAB}-PC2 ip link set eth2 up +sudo docker exec -d clab-${LAB}-PC2 ip addr add 168.95.10.1/16 dev eth2 +sudo docker exec clab-${LAB}-PC2 ip route del default 2>/dev/null || true + +# ---- Router underlay interfaces ----------------------------------------- +${ROUTER1} sudo config interface ip add Ethernet0 10.0.1.1/31 +${ROUTER1} sudo config interface startup Ethernet0 +${ROUTER1} sudo config interface startup Ethernet4 + +${ROUTER2} sudo config interface ip add Ethernet0 10.0.1.0/31 +${ROUTER2} sudo config interface startup Ethernet0 +${ROUTER2} sudo config interface startup Ethernet4 diff --git a/sonic-vpp/sonic-vpp-BGPEVPN/scripts/step1-interfaces.sh b/sonic-vpp/sonic-vpp-BGPEVPN/scripts/step1-interfaces.sh deleted file mode 100755 index db9c991..0000000 --- a/sonic-vpp/sonic-vpp-BGPEVPN/scripts/step1-interfaces.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -set -x - -ROUTER1="sshpass -p admin ssh admin@clab-sonic-vpp01-router1" -ROUTER2="sshpass -p admin ssh admin@clab-sonic-vpp01-router2" - - -sudo docker exec -d clab-sonic-vpp01-PC1 ip link set dev eth2 address aa:aa:aa:aa:aa:aa -sudo docker exec -d clab-sonic-vpp01-PC1 ip link set eth2 up -sudo docker exec -d clab-sonic-vpp01-PC1 ip addr add 168.95.10.2/16 dev eth2 -#sudo docker exec -d clab-sonic-vpp01-PC1 ip route add 0.0.0.0/0 dev eth2 - -sudo docker exec -d clab-sonic-vpp01-PC2 ip link set dev eth2 address be:ef:be:ef:be:ef -sudo docker exec -d clab-sonic-vpp01-PC2 ip link set eth2 up -sudo docker exec -d clab-sonic-vpp01-PC2 ip addr add 168.95.10.1/16 dev eth2 - -${ROUTER1} sudo config interface ip add Ethernet0 10.0.1.1/31 -${ROUTER1} sudo config interface startup Ethernet0 -${ROUTER1} sudo config interface startup Ethernet4 - -${ROUTER2} sudo config interface ip add Ethernet0 10.0.1.0/31 -${ROUTER2} sudo config interface startup Ethernet0 -${ROUTER2} sudo config interface startup Ethernet4 diff --git a/sonic-vpp/sonic-vpp-BGPEVPN/sonic-vpp01.clab.yml b/sonic-vpp/sonic-vpp-BGPEVPN/single-vni.clab.yml similarity index 60% rename from sonic-vpp/sonic-vpp-BGPEVPN/sonic-vpp01.clab.yml rename to sonic-vpp/sonic-vpp-BGPEVPN/single-vni.clab.yml index 8411b06..b47538d 100644 --- a/sonic-vpp/sonic-vpp-BGPEVPN/sonic-vpp01.clab.yml +++ b/sonic-vpp/sonic-vpp-BGPEVPN/single-vni.clab.yml @@ -1,13 +1,13 @@ -name: sonic-vpp01 +name: sonic-vpp-single-vni topology: nodes: router1: kind: sonic-vm - image: ghcr.io/pantheontech/sonic-vpp-vs:vxlan-poc-260225 + image: ghcr.io/pantheontech/sonic-vpp-vs:vxlan-poc-260421 router2: kind: sonic-vm - image: ghcr.io/pantheontech/sonic-vpp-vs:vxlan-poc-260225 + image: ghcr.io/pantheontech/sonic-vpp-vs:vxlan-poc-260421 PC1: kind: linux image: praqma/network-multitool:latest @@ -16,6 +16,8 @@ topology: image: praqma/network-multitool:latest links: + # Router-to-router underlay (Ethernet0 on both) - endpoints: ["router1:eth1", "router2:eth1"] + # VLAN 100 / VNI 1000: PC1 on R1, PC2 on R2 - endpoints: ["PC1:eth2", "router1:eth2"] - endpoints: ["PC2:eth2", "router2:eth2"] diff --git a/sonic-vpp/sonic-vpp-BGPEVPN/stop-multi-vni.sh b/sonic-vpp/sonic-vpp-BGPEVPN/stop-multi-vni.sh new file mode 100755 index 0000000..72c0ae5 --- /dev/null +++ b/sonic-vpp/sonic-vpp-BGPEVPN/stop-multi-vni.sh @@ -0,0 +1,2 @@ +#!/bin/bash +sudo clab destroy --topo multi-vni.clab.yml diff --git a/sonic-vpp/sonic-vpp-BGPEVPN/stop-single-vni.sh b/sonic-vpp/sonic-vpp-BGPEVPN/stop-single-vni.sh new file mode 100755 index 0000000..4aa783f --- /dev/null +++ b/sonic-vpp/sonic-vpp-BGPEVPN/stop-single-vni.sh @@ -0,0 +1,2 @@ +#!/bin/bash +sudo clab destroy --topo single-vni.clab.yml diff --git a/sonic-vpp/sonic-vpp-BGPEVPN/stop.sh b/sonic-vpp/sonic-vpp-BGPEVPN/stop.sh deleted file mode 100755 index 054ba68..0000000 --- a/sonic-vpp/sonic-vpp-BGPEVPN/stop.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -sudo clab destroy --topo sonic-vpp01.clab.yml diff --git a/sonic-vpp/sonic-vpp-BGPEVPN/stop2.sh b/sonic-vpp/sonic-vpp-BGPEVPN/stop2.sh deleted file mode 100755 index 191979b..0000000 --- a/sonic-vpp/sonic-vpp-BGPEVPN/stop2.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -sudo clab destroy --topo sonic-vpp02.clab.yml diff --git a/sonic-vpp/sonic-vpp-BGPEVPN/tests/test_l2_vxlan_advanced.sh b/sonic-vpp/sonic-vpp-BGPEVPN/tests/test_l2_vxlan_advanced.sh new file mode 100755 index 0000000..59ee2da --- /dev/null +++ b/sonic-vpp/sonic-vpp-BGPEVPN/tests/test_l2_vxlan_advanced.sh @@ -0,0 +1,326 @@ +#!/bin/bash +# +# test_l2_vxlan_advanced.sh — Advanced behavior tests for multi-VNI L2 VXLAN +# +# Covers: +# - MAC learning over VXLAN (VPP L2 FIB + SONiC MAC table + FRR EVPN Type-2) +# - BUM flooding (broadcast, ARP resolution over VXLAN) +# - Dynamic VNI hot-add with concurrent traffic +# - Scale test (5 VNIs simultaneously) +# - Underlay link flap recovery +# - Log verification + +set -u + +LAB="sonic-vpp-multi-vni" + +SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o ServerAliveInterval=5 -o ServerAliveCountMax=3 -o LogLevel=ERROR" +ROUTER1="sshpass -p admin ssh $SSH_OPTS admin@clab-${LAB}-router1" +ROUTER2="sshpass -p admin ssh $SSH_OPTS admin@clab-${LAB}-router2" +PC1="sudo docker exec clab-${LAB}-PC1" +PC2="sudo docker exec clab-${LAB}-PC2" +PC3="sudo docker exec clab-${LAB}-PC3" +PC4="sudo docker exec clab-${LAB}-PC4" + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +PASS=0 +FAIL=0 + +pass() { echo -e " ${GREEN}✓ PASS${NC}: $1"; ((PASS++)); } +fail() { echo -e " ${RED}✗ FAIL${NC}: $1"; ((FAIL++)); } +warn() { echo -e " ${YELLOW}⚠ WARN${NC}: $1"; } + +header() { + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo " $1" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +} + +check_syncd() { + local router_cmd="$1" + $router_cmd docker exec syncd supervisorctl status syncd 2>/dev/null | grep -q "RUNNING" +} + +ping_test() { + local src_cmd="$1" + local dst_ip="$2" + local count="${3:-5}" + $src_cmd ping -c "$count" -W 2 "$dst_ip" > /dev/null 2>&1 +} + +ping_test_retry() { + local src_cmd="$1" + local dst_ip="$2" + local label="$3" + local max_attempts="${4:-3}" + local wait_secs="${5:-10}" + + for attempt in $(seq 1 "$max_attempts"); do + if ping_test "$src_cmd" "$dst_ip" 5; then + pass "$label (attempt $attempt)" + return 0 + else + [ "$attempt" -lt "$max_attempts" ] && { echo " Attempt $attempt failed, waiting ${wait_secs}s..."; sleep "$wait_secs"; } + fi + done + fail "$label (all $max_attempts attempts failed)" + return 1 +} + +vpp_tunnel_count() { + local router_cmd="$1" + timeout 10 $router_cmd 'sudo docker exec syncd vppctl show vxlan tunnel' 2>/dev/null | grep -c "vni" || echo 0 +} + +# ========================================================================= +header "PHASE 0: Pre-flight — verify baseline connectivity" +# ========================================================================= + +echo "Verifying VNI 1000 (PC1 → PC2)..." +if ping_test "$PC1" "10.100.1.2" 5; then pass "VNI 1000 baseline OK"; else fail "VNI 1000 baseline broken — aborting"; exit 1; fi + +echo "Verifying VNI 2000 (PC3 → PC4)..." +if ping_test "$PC3" "10.200.1.2" 5; then pass "VNI 2000 baseline OK"; else fail "VNI 2000 baseline broken — aborting"; exit 1; fi + +# ========================================================================= +header "PHASE 1: MAC learning over VXLAN" +# ========================================================================= + +echo "Generating traffic to trigger MAC learning..." +$PC1 ping -c 3 -W 2 10.100.1.2 > /dev/null 2>&1 +$PC2 ping -c 3 -W 2 10.100.1.1 > /dev/null 2>&1 +$PC3 ping -c 3 -W 2 10.200.1.2 > /dev/null 2>&1 +$PC4 ping -c 3 -W 2 10.200.1.1 > /dev/null 2>&1 +sleep 3 + +echo "" +echo "Checking VPP L2 FIB on Router1 for remote MACs..." +VPP_FIB_R1=$($ROUTER1 "sudo docker exec syncd vppctl show l2fib" 2>/dev/null || echo "") +if echo "$VPP_FIB_R1" | grep -qi "aa:aa:aa:aa:aa:02"; then + pass "R1 learned PC2 MAC (aa:aa:aa:aa:aa:02) via VXLAN" +else + warn "R1 did not learn PC2 MAC — may use flooding path" +fi +if echo "$VPP_FIB_R1" | grep -qi "bb:bb:bb:bb:bb:04"; then + pass "R1 learned PC4 MAC (bb:bb:bb:bb:bb:04) via VXLAN" +else + warn "R1 did not learn PC4 MAC — may use flooding path" +fi + +echo "" +echo "Checking VPP L2 FIB on Router2 for remote MACs..." +VPP_FIB_R2=$($ROUTER2 "sudo docker exec syncd vppctl show l2fib" 2>/dev/null || echo "") +if echo "$VPP_FIB_R2" | grep -qi "aa:aa:aa:aa:aa:01"; then + pass "R2 learned PC1 MAC (aa:aa:aa:aa:aa:01) via VXLAN" +else + warn "R2 did not learn PC1 MAC" +fi +if echo "$VPP_FIB_R2" | grep -qi "bb:bb:bb:bb:bb:03"; then + pass "R2 learned PC3 MAC (bb:bb:bb:bb:bb:03) via VXLAN" +else + warn "R2 did not learn PC3 MAC" +fi + +echo "" +echo "Checking SONiC MAC table on Router1..." +$ROUTER1 "show mac 2>/dev/null | head -20" || true + +echo "" +echo "Checking FRR EVPN MAC info on Router1..." +$ROUTER1 "vtysh -c 'show evpn mac vni all' 2>/dev/null | head -30" || true + +# ========================================================================= +header "PHASE 2: BUM flooding — broadcast and ARP" +# ========================================================================= + +echo "Testing ARP resolution over VXLAN (PC1 → PC2)..." +$PC1 ip neigh flush all 2>/dev/null || true +$PC2 ip neigh flush all 2>/dev/null || true +sleep 2 + +if ping_test "$PC1" "10.100.1.2" 3; then pass "ARP resolution works over VXLAN (VNI 1000)"; else fail "ARP resolution failed"; fi + +echo "" +echo "Verifying ARP entry was re-learned..." +ARP_ENTRY=$($PC1 ip neigh show 10.100.1.2 2>/dev/null || echo "") +if echo "$ARP_ENTRY" | grep -qi "aa:aa:aa:aa:aa:02"; then + pass "PC1 re-learned PC2 MAC via ARP over VXLAN" +else + warn "PC1 ARP entry unclear: $ARP_ENTRY" +fi + +echo "" +echo "Testing ARP resolution on VNI 2000 (PC3 → PC4)..." +$PC3 ip neigh flush all 2>/dev/null || true +sleep 1 +if ping_test "$PC3" "10.200.1.2" 3; then pass "ARP resolution works over VXLAN (VNI 2000)"; else fail "ARP resolution failed"; fi + +# ========================================================================= +header "PHASE 3: Add 3rd VNI while traffic flows" +# ========================================================================= + +echo "Starting background traffic on VNI 1000 and VNI 2000..." +$PC1 ping -c 60 -i 0.5 -W 2 10.100.1.2 > /tmp/vni1000_bg.log 2>&1 & +BG1=$! +$PC3 ping -c 60 -i 0.5 -W 2 10.200.1.2 > /tmp/vni2000_bg.log 2>&1 & +BG2=$! + +echo "Adding VLAN 300 and VNI 3000 on both routers while traffic flows..." +$ROUTER1 sudo config vlan add 300 2>&1 || true +$ROUTER2 sudo config vlan add 300 2>&1 || true +sleep 2 +$ROUTER1 sudo config vxlan map add vtep 300 3000 +$ROUTER2 sudo config vxlan map add vtep 300 3000 +sleep 10 + +if check_syncd "$ROUTER1"; then pass "R1 syncd RUNNING after adding VNI 3000"; else fail "R1 syncd CRASHED"; fi +if check_syncd "$ROUTER2"; then pass "R2 syncd RUNNING after adding VNI 3000"; else fail "R2 syncd CRASHED"; fi + +echo "" +echo "Checking VNI 3000 appears in EVPN..." +VNI_INFO=$($ROUTER1 "vtysh -c 'show evpn vni'" 2>/dev/null || echo "") +if echo "$VNI_INFO" | grep -q "3000"; then pass "VNI 3000 present in EVPN"; else warn "VNI 3000 not yet visible in EVPN"; fi + +echo "" +R1_TUNNELS=$(vpp_tunnel_count "$ROUTER1") +echo "R1 VPP tunnel count: $R1_TUNNELS" +if [ "$R1_TUNNELS" -ge 3 ]; then pass "R1 has $R1_TUNNELS VPP tunnels (expected ≥3)"; else warn "R1 has $R1_TUNNELS tunnels (expected ≥3 with VNI 3000)"; fi + +echo "" +echo "Waiting for background traffic to finish..." +wait $BG1; R1_LOSS=$? +wait $BG2; R2_LOSS=$? + +if [ $R1_LOSS -eq 0 ]; then pass "VNI 1000 traffic uninterrupted during VNI 3000 add"; else warn "VNI 1000 had some loss during hot-add (exit=$R1_LOSS)"; fi +if [ $R2_LOSS -eq 0 ]; then pass "VNI 2000 traffic uninterrupted during VNI 3000 add"; else warn "VNI 2000 had some loss during hot-add (exit=$R2_LOSS)"; fi + +echo "" +echo "Cleaning up VNI 3000..." +$ROUTER1 sudo config vxlan map del vtep 300 3000 2>&1 || true +$ROUTER2 sudo config vxlan map del vtep 300 3000 2>&1 || true +sleep 2 +$ROUTER1 sudo config vlan del 300 2>&1 || true +$ROUTER2 sudo config vlan del 300 2>&1 || true +sleep 5 + +echo "Verifying original VNIs still work after cleanup..." +if ping_test "$PC1" "10.100.1.2" 3; then pass "VNI 1000 OK after VNI 3000 cleanup"; else fail "VNI 1000 broken"; fi +if ping_test "$PC3" "10.200.1.2" 3; then pass "VNI 2000 OK after VNI 3000 cleanup"; else fail "VNI 2000 broken"; fi + +# ========================================================================= +header "PHASE 4: Scale — 5 VNIs simultaneously" +# ========================================================================= + +echo "Adding VNIs 3000, 4000, 5000 (VLANs 300, 400, 500)..." +for vlan_vni in "300:3000" "400:4000" "500:5000"; do + vlan="${vlan_vni%%:*}" + vni="${vlan_vni##*:}" + $ROUTER1 sudo config vlan add $vlan 2>&1 || true + $ROUTER2 sudo config vlan add $vlan 2>&1 || true + $ROUTER1 sudo config vxlan map add vtep $vlan $vni 2>&1 || true + $ROUTER2 sudo config vxlan map add vtep $vlan $vni 2>&1 || true +done +sleep 15 + +if check_syncd "$ROUTER1"; then pass "R1 syncd RUNNING with 5 VNIs"; else fail "R1 syncd CRASHED with 5 VNIs"; fi +if check_syncd "$ROUTER2"; then pass "R2 syncd RUNNING with 5 VNIs"; else fail "R2 syncd CRASHED with 5 VNIs"; fi + +echo "" +R1_TUNNELS=$(vpp_tunnel_count "$ROUTER1") +R2_TUNNELS=$(vpp_tunnel_count "$ROUTER2") +if [ "$R1_TUNNELS" -ge 5 ]; then pass "R1 has $R1_TUNNELS VPP tunnels (5 VNIs)"; else warn "R1 has $R1_TUNNELS tunnels (expected ≥5)"; fi +if [ "$R2_TUNNELS" -ge 5 ]; then pass "R2 has $R2_TUNNELS VPP tunnels (5 VNIs)"; else warn "R2 has $R2_TUNNELS tunnels (expected ≥5)"; fi + +echo "" +echo "Verifying original VNIs still work with 5 VNIs active..." +if ping_test "$PC1" "10.100.1.2" 3; then pass "VNI 1000 OK with 5 VNIs"; else fail "VNI 1000 broken"; fi +if ping_test "$PC3" "10.200.1.2" 3; then pass "VNI 2000 OK with 5 VNIs"; else fail "VNI 2000 broken"; fi + +echo "" +echo "Cleaning up extra VNIs..." +for vlan_vni in "300:3000" "400:4000" "500:5000"; do + vlan="${vlan_vni%%:*}" + vni="${vlan_vni##*:}" + $ROUTER1 sudo config vxlan map del vtep $vlan $vni 2>&1 || true + $ROUTER2 sudo config vxlan map del vtep $vlan $vni 2>&1 || true + $ROUTER1 sudo config vlan del $vlan 2>&1 || true + $ROUTER2 sudo config vlan del $vlan 2>&1 || true +done +sleep 10 + +R1_TUNNELS=$(vpp_tunnel_count "$ROUTER1") +echo "R1 tunnel count after cleanup: $R1_TUNNELS" +if ping_test "$PC1" "10.100.1.2" 3; then pass "VNI 1000 OK after scale cleanup"; else fail "VNI 1000 broken"; fi +if ping_test "$PC3" "10.200.1.2" 3; then pass "VNI 2000 OK after scale cleanup"; else fail "VNI 2000 broken"; fi + +# ========================================================================= +header "PHASE 5: Underlay link flap recovery" +# ========================================================================= + +echo "Shutting down underlay interface Ethernet0 on Router1..." +$ROUTER1 sudo config interface shutdown Ethernet0 +sleep 5 + +echo "Verifying VXLAN traffic fails during underlay outage..." +if ping_test "$PC1" "10.100.1.2" 3; then + warn "VNI 1000 still works with underlay down (unexpected)" +else + pass "VNI 1000 correctly unreachable with underlay down" +fi + +echo "" +echo "Bringing underlay back up..." +$ROUTER1 sudo config interface startup Ethernet0 +echo "Waiting 20s for BGP EVPN to re-converge..." +sleep 20 + +echo "Verifying VXLAN traffic recovers..." +ping_test_retry "$PC1" "10.100.1.2" "VNI 1000 recovered after underlay flap" +ping_test_retry "$PC3" "10.200.1.2" "VNI 2000 recovered after underlay flap" + +# ========================================================================= +header "PHASE 6: Log verification and final health" +# ========================================================================= + +echo "Checking for segfaults..." +for router_label in "Router1:$ROUTER1" "Router2:$ROUTER2"; do + label="${router_label%%:*}" + cmd="${router_label#*:}" + SYSLOG=$(timeout 15 $cmd bash -c '{ + sudo docker logs syncd 2>&1 + grep -a "" /var/log/syslog /var/log/syslog.1 2>/dev/null + } | grep -i "segfault\|SIGSEGV" | tail -5' 2>/dev/null || echo "") + + if [ -n "$SYSLOG" ] && echo "$SYSLOG" | grep -qi "segfault\|SIGSEGV"; then + fail "SIGSEGV detected in $label logs!" + else + pass "No segfault in $label logs" + fi +done + +echo "" +echo "Final syncd health..." +if check_syncd "$ROUTER1"; then pass "R1 syncd healthy"; else fail "R1 syncd not healthy"; fi +if check_syncd "$ROUTER2"; then pass "R2 syncd healthy"; else fail "R2 syncd not healthy"; fi + +# ========================================================================= +header "TEST SUMMARY" +# ========================================================================= + +echo "" +echo -e " ${GREEN}Passed${NC}: $PASS" +echo -e " ${RED}Failed${NC}: $FAIL" +echo "" + +if [ "$FAIL" -eq 0 ]; then + echo -e " ${GREEN}ALL TESTS PASSED${NC}" + exit 0 +else + echo -e " ${RED}SOME TESTS FAILED${NC} — check output above" + exit 1 +fi diff --git a/sonic-vpp/sonic-vpp-BGPEVPN/tests/test_multi_vlan_vxlan.sh b/sonic-vpp/sonic-vpp-BGPEVPN/tests/test_multi_vlan_vxlan.sh new file mode 100755 index 0000000..ff5b1fe --- /dev/null +++ b/sonic-vpp/sonic-vpp-BGPEVPN/tests/test_multi_vlan_vxlan.sh @@ -0,0 +1,431 @@ +#!/bin/bash +# +# test_multi_vlan_vxlan.sh — Multi-VLAN / Multi-VNI test (4 PCs, 2 routers) +# +# Topology: +# VLAN 100 / VNI 1000: PC1 (10.100.1.1) on R1 <--> PC2 (10.100.1.2) on R2 +# VLAN 200 / VNI 2000: PC3 (10.200.1.1) on R1 <--> PC4 (10.200.1.2) on R2 + +set -u + +LAB="sonic-vpp-multi-vni" + +SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o ServerAliveInterval=5 -o ServerAliveCountMax=3 -o LogLevel=ERROR" +ROUTER1="sshpass -p admin ssh $SSH_OPTS admin@clab-${LAB}-router1" +ROUTER2="sshpass -p admin ssh $SSH_OPTS admin@clab-${LAB}-router2" +PC1="sudo docker exec clab-${LAB}-PC1" +PC2="sudo docker exec clab-${LAB}-PC2" +PC3="sudo docker exec clab-${LAB}-PC3" +PC4="sudo docker exec clab-${LAB}-PC4" + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +PASS=0 +FAIL=0 + +pass() { echo -e " ${GREEN}✓ PASS${NC}: $1"; ((PASS++)); } +fail() { echo -e " ${RED}✗ FAIL${NC}: $1"; ((FAIL++)); } +warn() { echo -e " ${YELLOW}⚠ WARN${NC}: $1"; } + +header() { + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo " $1" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +} + +check_syncd() { + local router_cmd="$1" + local status + status=$($router_cmd docker exec syncd supervisorctl status syncd 2>/dev/null || echo "FAILED") + echo "$status" | grep -q "RUNNING" +} + +ping_test() { + local src_cmd="$1" + local dst_ip="$2" + local count="${3:-5}" + $src_cmd ping -c "$count" -W 2 "$dst_ip" > /dev/null 2>&1 +} + +ping_test_retry() { + local src_cmd="$1" + local dst_ip="$2" + local label="$3" + local max_attempts="${4:-3}" + local wait_secs="${5:-10}" + + for attempt in $(seq 1 "$max_attempts"); do + if ping_test "$src_cmd" "$dst_ip" 5; then + pass "$label (attempt $attempt)" + return 0 + else + if [ "$attempt" -lt "$max_attempts" ]; then + echo " Attempt $attempt failed, waiting ${wait_secs}s..." + sleep "$wait_secs" + fi + fi + done + fail "$label (all $max_attempts attempts failed)" + return 1 +} + +vpp_tunnel_count() { + local router_cmd="$1" + local count + count=$(timeout 10 $router_cmd 'sudo docker exec syncd vppctl show vxlan tunnel' 2>/dev/null | grep -c "vni" || true) + echo "$count" +} + +# Full VXLAN teardown (reverse order: maps → evpn_nvo → tunnel) +full_vxlan_teardown() { + local router_cmd="$1" + $router_cmd sudo config vxlan map del vtep 100 1000 2>&1 || true + $router_cmd sudo config vxlan map del vtep 200 2000 2>&1 || true + sleep 2 + $router_cmd sudo config vxlan evpn_nvo del nvo 2>&1 || true + sleep 1 + $router_cmd sudo config vxlan del vtep 2>&1 || true +} + +# Full VXLAN setup (forward order: tunnel → evpn_nvo → maps) +full_vxlan_setup() { + local router_cmd="$1" + local vtep_ip="$2" + $router_cmd sudo config vxlan add vtep "$vtep_ip" + $router_cmd sudo config vxlan evpn_nvo add nvo vtep + $router_cmd sudo config vxlan map add vtep 100 1000 + $router_cmd sudo config vxlan map add vtep 200 2000 +} + +# ========================================================================= +header "PHASE 0: Pre-flight checks" +# ========================================================================= + +echo "Checking router accessibility..." +if $ROUTER1 echo "ok" > /dev/null 2>&1; then + pass "Router1 SSH accessible" +else + fail "Router1 SSH not accessible"; exit 1 +fi +if $ROUTER2 echo "ok" > /dev/null 2>&1; then + pass "Router2 SSH accessible" +else + fail "Router2 SSH not accessible"; exit 1 +fi + +echo "" +echo "Checking syncd health..." +if check_syncd "$ROUTER1"; then pass "Router1 syncd RUNNING"; else fail "Router1 syncd NOT running"; fi +if check_syncd "$ROUTER2"; then pass "Router2 syncd RUNNING"; else fail "Router2 syncd NOT running"; fi + +echo "" +echo "Checking BGP EVPN peering..." +BGP_STATE=$(timeout 10 $ROUTER1 "vtysh -c 'show bgp l2vpn evpn summary'" 2>/dev/null || echo "") +if echo "$BGP_STATE" | grep -q "10.0.1.0"; then + pass "BGP EVPN neighbor 10.0.1.0 present on Router1" +else + warn "Could not verify BGP EVPN neighbor (will be confirmed by ping tests)" +fi + +echo "" +echo "Checking VXLAN VNI mappings..." +VNI_INFO=$(timeout 10 $ROUTER1 "vtysh -c 'show evpn vni'" 2>/dev/null || echo "") +echo "$VNI_INFO" +if echo "$VNI_INFO" | grep -q "1000"; then pass "VNI 1000 present"; else warn "VNI 1000 not visible"; fi +if echo "$VNI_INFO" | grep -q "2000"; then pass "VNI 2000 present"; else warn "VNI 2000 not visible"; fi + +echo "" +echo "Checking VPP VXLAN tunnels..." +R1_TUNNELS=$(vpp_tunnel_count "$ROUTER1") +R2_TUNNELS=$(vpp_tunnel_count "$ROUTER2") +if [ "$R1_TUNNELS" -ge 2 ]; then pass "R1 has $R1_TUNNELS VPP VXLAN tunnels"; else warn "R1 has $R1_TUNNELS tunnels (expected 2)"; fi +if [ "$R2_TUNNELS" -ge 2 ]; then pass "R2 has $R2_TUNNELS VPP VXLAN tunnels"; else warn "R2 has $R2_TUNNELS tunnels (expected 2)"; fi + +# ========================================================================= +header "PHASE 1: VNI 1000 connectivity (PC1 <-> PC2)" +# ========================================================================= + +echo "Testing PC1 (10.100.1.1) → PC2 (10.100.1.2)..." +ping_test_retry "$PC1" "10.100.1.2" "PC1 → PC2 (VNI 1000)" + +echo "" +echo "Testing PC2 (10.100.1.2) → PC1 (10.100.1.1)..." +if ping_test "$PC2" "10.100.1.1" 3; then pass "PC2 → PC1 (VNI 1000)"; else fail "PC2 → PC1 (VNI 1000)"; fi + +# ========================================================================= +header "PHASE 2: VNI 2000 connectivity (PC3 <-> PC4)" +# ========================================================================= + +echo "Testing PC3 (10.200.1.1) → PC4 (10.200.1.2)..." +ping_test_retry "$PC3" "10.200.1.2" "PC3 → PC4 (VNI 2000)" + +echo "" +echo "Testing PC4 (10.200.1.2) → PC3 (10.200.1.1)..." +if ping_test "$PC4" "10.200.1.1" 3; then pass "PC4 → PC3 (VNI 2000)"; else fail "PC4 → PC3 (VNI 2000)"; fi + +# ========================================================================= +header "PHASE 3: Cross-VNI isolation (remote)" +# ========================================================================= + +echo "PC1 (VNI 1000) → PC3 (VNI 2000) — should FAIL..." +if ping_test "$PC1" "10.200.1.1" 3; then fail "PC1 can reach PC3"; else pass "PC1 cannot reach PC3"; fi + +echo "" +echo "PC1 (VNI 1000) → PC4 (VNI 2000) — should FAIL..." +if ping_test "$PC1" "10.200.1.2" 3; then fail "PC1 can reach PC4"; else pass "PC1 cannot reach PC4"; fi + +echo "" +echo "PC3 (VNI 2000) → PC2 (VNI 1000) — should FAIL..." +if ping_test "$PC3" "10.100.1.2" 3; then fail "PC3 can reach PC2"; else pass "PC3 cannot reach PC2"; fi + +echo "" +echo "PC4 (VNI 2000) → PC1 (VNI 1000) — should FAIL..." +if ping_test "$PC4" "10.100.1.1" 3; then fail "PC4 can reach PC1"; else pass "PC4 cannot reach PC1"; fi + +# ========================================================================= +header "PHASE 4: Same-router cross-VLAN isolation" +# ========================================================================= + +echo "PC1 and PC3 are both on Router1 but different VLANs..." +echo "" +echo "PC1 (R1, VNI 1000) → PC3 (R1, VNI 2000) — should FAIL..." +if ping_test "$PC1" "10.200.1.1" 3; then fail "Same-router leak: PC1 → PC3"; else pass "Same-router isolated: PC1 → PC3"; fi + +echo "" +echo "PC3 (R1, VNI 2000) → PC1 (R1, VNI 1000) — should FAIL..." +if ping_test "$PC3" "10.100.1.1" 3; then fail "Same-router leak: PC3 → PC1"; else pass "Same-router isolated: PC3 → PC1"; fi + +echo "" +echo "PC2 and PC4 are both on Router2 but different VLANs..." +echo "" +echo "PC2 (R2, VNI 1000) → PC4 (R2, VNI 2000) — should FAIL..." +if ping_test "$PC2" "10.200.1.2" 3; then fail "Same-router leak: PC2 → PC4"; else pass "Same-router isolated: PC2 → PC4"; fi + +echo "" +echo "PC4 (R2, VNI 2000) → PC2 (R2, VNI 1000) — should FAIL..." +if ping_test "$PC4" "10.100.1.2" 3; then fail "Same-router leak: PC4 → PC2"; else pass "Same-router isolated: PC4 → PC2"; fi + +# ========================================================================= +header "PHASE 5: Delete VNI 2000 map — verify VNI 1000 unaffected" +# ========================================================================= + +echo "Deleting VXLAN map for VNI 2000 on both routers..." +$ROUTER1 sudo config vxlan map del vtep 200 2000 2>&1 || true +sleep 3 +$ROUTER2 sudo config vxlan map del vtep 200 2000 2>&1 || true +sleep 5 + +if check_syncd "$ROUTER1"; then pass "R1 syncd RUNNING after VNI 2000 map delete"; else fail "R1 syncd CRASHED"; fi +if check_syncd "$ROUTER2"; then pass "R2 syncd RUNNING after VNI 2000 map delete"; else fail "R2 syncd CRASHED"; fi + +echo "" +echo "Verifying VNI 1000 still works (PC1 → PC2)..." +if ping_test "$PC1" "10.100.1.2" 5; then pass "VNI 1000 unaffected"; else fail "VNI 1000 broken"; fi + +# ========================================================================= +header "PHASE 6: Re-add VNI 2000 map — verify recovery" +# ========================================================================= + +echo "Re-adding VXLAN map for VNI 2000..." +$ROUTER1 sudo config vxlan map add vtep 200 2000 +$ROUTER2 sudo config vxlan map add vtep 200 2000 +sleep 5 + +if check_syncd "$ROUTER1"; then pass "R1 syncd RUNNING after VNI 2000 map re-add"; else fail "R1 syncd CRASHED"; fi +if check_syncd "$ROUTER2"; then pass "R2 syncd RUNNING after VNI 2000 map re-add"; else fail "R2 syncd CRASHED"; fi + +echo "" +echo "Waiting 15s for BGP EVPN re-convergence..." +sleep 15 + +ping_test_retry "$PC3" "10.200.1.2" "VNI 2000 recovered (PC3 → PC4)" + +echo "" +if ping_test "$PC1" "10.100.1.2" 3; then pass "VNI 1000 still operational"; else fail "VNI 1000 broken"; fi + +# ========================================================================= +header "PHASE 7: Delete VNI 1000 map — verify VNI 2000 unaffected" +# ========================================================================= + +echo "Deleting VXLAN map for VNI 1000 on both routers..." +$ROUTER1 sudo config vxlan map del vtep 100 1000 2>&1 || true +sleep 3 +$ROUTER2 sudo config vxlan map del vtep 100 1000 2>&1 || true +sleep 5 + +if check_syncd "$ROUTER1"; then pass "R1 syncd RUNNING after VNI 1000 map delete"; else fail "R1 syncd CRASHED"; fi +if check_syncd "$ROUTER2"; then pass "R2 syncd RUNNING after VNI 1000 map delete"; else fail "R2 syncd CRASHED"; fi + +echo "" +if ping_test "$PC3" "10.200.1.2" 5; then pass "VNI 2000 unaffected"; else fail "VNI 2000 broken"; fi + +# ========================================================================= +header "PHASE 8: Re-add VNI 1000 map — verify full recovery" +# ========================================================================= + +echo "Re-adding VXLAN map for VNI 1000..." +$ROUTER1 sudo config vxlan map add vtep 100 1000 +$ROUTER2 sudo config vxlan map add vtep 100 1000 +sleep 5 + +if check_syncd "$ROUTER1"; then pass "R1 syncd RUNNING after VNI 1000 map re-add"; else fail "R1 syncd CRASHED"; fi +if check_syncd "$ROUTER2"; then pass "R2 syncd RUNNING after VNI 1000 map re-add"; else fail "R2 syncd CRASHED"; fi + +echo "" +echo "Waiting 15s for BGP EVPN re-convergence..." +sleep 15 + +ping_test_retry "$PC1" "10.100.1.2" "VNI 1000 recovered (PC1 → PC2)" + +echo "" +if ping_test "$PC3" "10.200.1.2" 3; then pass "VNI 2000 still operational"; else fail "VNI 2000 broken"; fi + +# ========================================================================= +header "PHASE 9: Full tunnel teardown and re-creation" +# ========================================================================= + +echo "Full teardown: del maps → del evpn_nvo → del tunnel..." +full_vxlan_teardown "$ROUTER1" +full_vxlan_teardown "$ROUTER2" +sleep 10 + +if check_syncd "$ROUTER1"; then pass "R1 syncd RUNNING after full teardown"; else fail "R1 syncd CRASHED"; fi +if check_syncd "$ROUTER2"; then pass "R2 syncd RUNNING after full teardown"; else fail "R2 syncd CRASHED"; fi + +echo "" +R1_TUNNELS=$(vpp_tunnel_count "$ROUTER1") +if [ "$R1_TUNNELS" -eq 0 ]; then pass "R1 has 0 VPP tunnels after full teardown"; else warn "R1 has $R1_TUNNELS tunnels (expected 0)"; fi + +echo "" +echo "Full setup: add tunnel → add evpn_nvo → add maps..." +full_vxlan_setup "$ROUTER1" "10.0.1.1" +full_vxlan_setup "$ROUTER2" "10.0.1.0" +sleep 5 + +if check_syncd "$ROUTER1"; then pass "R1 syncd RUNNING after full setup"; else fail "R1 syncd CRASHED"; fi +if check_syncd "$ROUTER2"; then pass "R2 syncd RUNNING after full setup"; else fail "R2 syncd CRASHED"; fi + +echo "" +echo "Waiting 20s for BGP EVPN to fully converge..." +sleep 20 + +R1_TUNNELS=$(vpp_tunnel_count "$ROUTER1") +if [ "$R1_TUNNELS" -eq 2 ]; then pass "R1 has 2 VPP tunnels after full setup"; else warn "R1 has $R1_TUNNELS tunnels (expected 2)"; fi + +echo "" +ping_test_retry "$PC1" "10.100.1.2" "VNI 1000 works after full cycle" +ping_test_retry "$PC3" "10.200.1.2" "VNI 2000 works after full cycle" + +# ========================================================================= +header "PHASE 10: Rapid map delete/re-add stress test" +# ========================================================================= + +STRESS_CYCLES=3 +echo "Running $STRESS_CYCLES rapid map delete/re-add cycles on VNI 2000..." +echo "" + +for cycle in $(seq 1 "$STRESS_CYCLES"); do + echo " Cycle $cycle/$STRESS_CYCLES: delete map..." + $ROUTER1 sudo config vxlan map del vtep 200 2000 2>&1 || true + $ROUTER2 sudo config vxlan map del vtep 200 2000 2>&1 || true + sleep 3 + + echo " Cycle $cycle/$STRESS_CYCLES: re-add map..." + $ROUTER1 sudo config vxlan map add vtep 200 2000 + $ROUTER2 sudo config vxlan map add vtep 200 2000 + sleep 3 +done + +sleep 15 + +if check_syncd "$ROUTER1"; then pass "R1 syncd RUNNING after $STRESS_CYCLES rapid cycles"; else fail "R1 syncd CRASHED"; fi +if check_syncd "$ROUTER2"; then pass "R2 syncd RUNNING after $STRESS_CYCLES rapid cycles"; else fail "R2 syncd CRASHED"; fi + +echo "" +echo "Verifying connectivity after stress test..." +ping_test_retry "$PC1" "10.100.1.2" "VNI 1000 works after stress test" +ping_test_retry "$PC3" "10.200.1.2" "VNI 2000 works after stress test" + +# ========================================================================= +header "PHASE 11: Simultaneous bidirectional traffic" +# ========================================================================= + +echo "Sending pings on both VNIs concurrently (10 packets each)..." +$PC1 ping -c 10 -W 2 10.100.1.2 > /dev/null 2>&1 & +PID1=$! +$PC2 ping -c 10 -W 2 10.100.1.1 > /dev/null 2>&1 & +PID2=$! +$PC3 ping -c 10 -W 2 10.200.1.2 > /dev/null 2>&1 & +PID3=$! +$PC4 ping -c 10 -W 2 10.200.1.1 > /dev/null 2>&1 & +PID4=$! + +wait $PID1; R1=$? +wait $PID2; R2=$? +wait $PID3; R3=$? +wait $PID4; R4=$? +echo "" + +if [ $R1 -eq 0 ]; then pass "Concurrent: PC1 → PC2 (VNI 1000)"; else fail "Concurrent: PC1 → PC2 (VNI 1000)"; fi +if [ $R2 -eq 0 ]; then pass "Concurrent: PC2 → PC1 (VNI 1000)"; else fail "Concurrent: PC2 → PC1 (VNI 1000)"; fi +if [ $R3 -eq 0 ]; then pass "Concurrent: PC3 → PC4 (VNI 2000)"; else fail "Concurrent: PC3 → PC4 (VNI 2000)"; fi +if [ $R4 -eq 0 ]; then pass "Concurrent: PC4 → PC3 (VNI 2000)"; else fail "Concurrent: PC4 → PC3 (VNI 2000)"; fi + +# ========================================================================= +header "PHASE 12: Final isolation re-check" +# ========================================================================= + +echo "Cross-VNI (remote)..." +if ping_test "$PC1" "10.200.1.2" 3; then fail "PC1 → PC4 leak"; else pass "PC1 → PC4 isolated"; fi +if ping_test "$PC3" "10.100.1.2" 3; then fail "PC3 → PC2 leak"; else pass "PC3 → PC2 isolated"; fi + +echo "" +echo "Cross-VLAN same-router..." +if ping_test "$PC1" "10.200.1.1" 3; then fail "PC1 → PC3 same-router leak"; else pass "PC1 → PC3 same-router isolated"; fi +if ping_test "$PC2" "10.200.1.2" 3; then fail "PC2 → PC4 same-router leak"; else pass "PC2 → PC4 same-router isolated"; fi + +# ========================================================================= +header "PHASE 13: Log verification and final health" +# ========================================================================= + +echo "Checking for segfaults..." +for router_label in "Router1:$ROUTER1" "Router2:$ROUTER2"; do + label="${router_label%%:*}" + cmd="${router_label#*:}" + SYSLOG=$(timeout 15 $cmd bash -c '{ + sudo docker logs syncd 2>&1 + grep -a "" /var/log/syslog /var/log/syslog.1 2>/dev/null + } | grep -i "segfault\|SIGSEGV" | tail -5' 2>/dev/null || echo "") + + if [ -n "$SYSLOG" ] && echo "$SYSLOG" | grep -qi "segfault\|SIGSEGV"; then + fail "SIGSEGV detected in $label logs!" + else + pass "No segfault in $label logs" + fi +done + +echo "" +echo "Final syncd health..." +if check_syncd "$ROUTER1"; then pass "R1 syncd healthy"; else fail "R1 syncd not healthy"; fi +if check_syncd "$ROUTER2"; then pass "R2 syncd healthy"; else fail "R2 syncd not healthy"; fi + +# ========================================================================= +header "TEST SUMMARY" +# ========================================================================= + +echo "" +echo -e " ${GREEN}Passed${NC}: $PASS" +echo -e " ${RED}Failed${NC}: $FAIL" +echo "" + +if [ "$FAIL" -eq 0 ]; then + echo -e " ${GREEN}ALL TESTS PASSED${NC}" + exit 0 +else + echo -e " ${RED}SOME TESTS FAILED${NC} — check output above" + exit 1 +fi From 2bd20564ba08c841ebe7004dff3a040afd38dd97 Mon Sep 17 00:00:00 2001 From: Samuel Benko Date: Tue, 28 Apr 2026 16:38:11 +0200 Subject: [PATCH 3/3] docs: edit README based on the refactored example Signed-off-by: Samuel Benko --- sonic-vpp/sonic-vpp-BGPEVPN/README.md | 151 ++++++++++++++++++++------ 1 file changed, 119 insertions(+), 32 deletions(-) diff --git a/sonic-vpp/sonic-vpp-BGPEVPN/README.md b/sonic-vpp/sonic-vpp-BGPEVPN/README.md index e205544..2d53533 100644 --- a/sonic-vpp/sonic-vpp-BGPEVPN/README.md +++ b/sonic-vpp/sonic-vpp-BGPEVPN/README.md @@ -1,10 +1,10 @@ -# SONiC-VPP L3 BGP EVPN +# SONiC-VPP BGP EVPN This example demonstrates the integration of a high-performance software data plane ([VPP](https://fd.io/)) with a standardized network operating system ([SONiC](https://sonicfoundation.dev/)) to run advanced data center fabric protocols ([BGP EVPN](https://pantheon.tech/blog-news/what-is-bgp-evpn/)). -You will see a 2-site EVPN-VXLAN lab using **SONiC** + **VPP** data plane. The lab shows how: -- **BGP EVPN** routes are signaled between two router nodes -- How VPP-created VXLAN tunnels forward L2 traffic so remote PCs appear on the same L2 VNI +You will see two 2-site EVPN-VXLAN labs using **SONiC** + **VPP** data plane: +- **Single-VNI** — two router nodes, one L2 VNI (1000 / VLAN 100), two PCs sharing one broadcast domain +- **Multi-VNI** — two router nodes, two L2 VNIs (1000 / VLAN 100 and 2000 / VLAN 200), four PCs across two isolated broadcast domains ## Prerequisites - This example was successfully replicated on an **Ubuntu (24.04.2 LTS) WSL** instance in Windows @@ -14,10 +14,21 @@ You will see a 2-site EVPN-VXLAN lab using **SONiC** + **VPP** data plane. The l **Files to inspect** -- Topology: [sonic-vpp-L3-BGPEVPN/sonic-vpp01.clab.yml](sonic-vpp-L3-BGPEVPN/sonic-vpp01.clab.yml) -- Launch script: [sonic-vpp-L3-BGPEVPN/run.sh](sonic-vpp-L3-BGPEVPN/run.sh) -- Interface helper: [sonic-vpp-L3-BGPEVPN/scripts/step1-interfaces.sh](sonic-vpp-L3-BGPEVPN/scripts/step1-interfaces.sh) -- Router configs and VXLAN commands: [sonic-vpp-L3-BGPEVPN/routers](sonic-vpp-L3-BGPEVPN/routers) +Single-VNI: +- Topology: [single-vni.clab.yml](single-vni.clab.yml) +- Launch script: [run-single-vni.sh](run-single-vni.sh) +- Interface helper: [scripts/setup-single-vni.sh](scripts/setup-single-vni.sh) +- Router VXLAN commands: [routers/router1/vxlan-single-vni.cmd](routers/router1/vxlan-single-vni.cmd), [routers/router2/vxlan-single-vni.cmd](routers/router2/vxlan-single-vni.cmd) + +Multi-VNI: +- Topology: [multi-vni.clab.yml](multi-vni.clab.yml) +- Launch script: [run-multi-vni.sh](run-multi-vni.sh) +- Interface helper: [scripts/setup-multi-vni.sh](scripts/setup-multi-vni.sh) +- Router VXLAN commands: [routers/router1/vxlan-multi-vni.cmd](routers/router1/vxlan-multi-vni.cmd), [routers/router2/vxlan-multi-vni.cmd](routers/router2/vxlan-multi-vni.cmd) + +Shared (used by both labs): +- BGP underlay & EVPN configs: [routers/router1](routers/router1), [routers/router2](routers/router2) +- Common shell helpers: [lib/common.sh](lib/common.sh) ## Running the example First, clone the repository so you have a local copy: @@ -26,23 +37,26 @@ First, clone the repository so you have a local copy: git clone https://github.com/PANTHEONtech/cnf-examples.git ``` -To launch the example, simply execute the *run.sh* script within the folder you downloaded the example to: +### Single-VNI + +To launch the single-VNI lab, simply execute the *run-single-vni.sh* script within the folder you downloaded the example to: ```bash -cd /cnf-examples/sonic-vpp/sonic-vpp-L3-BGPEVPN -./run.sh +cd /cnf-examples/sonic-vpp/sonic-vpp-BGPEVPN +./run-single-vni.sh ``` -The run.sh script orchestrates the setup and configuration of the VXLAN environment. +The run-single-vni.sh script orchestrates the setup and configuration of the VXLAN environment. **Configuration flow** -The `run.sh` script performs these high-level actions: +The `run-single-vni.sh` script performs these high-level actions: -1. Deploy the ContainerLab topology from `sonic-vpp01.clab.yml` -2. Configure host interfaces using `scripts/step1-interfaces.sh` -3. Apply FRR/`vtysh` configurations in `routers/*/*.vtysh` to establish BGP EVPN sessions -4. Apply VPP VXLAN commands in `routers/*/*-vxlan.cmd` to create VXLAN tunnels on each router +1. Deploy the ContainerLab topology from `single-vni.clab.yml` +2. Configure host interfaces and router underlay IPs using `scripts/setup-single-vni.sh` +3. Apply FRR/`vtysh` underlay configurations in `routers/*/bgp-underlay.vtysh` to bring up the IPv4 underlay +4. Apply VPP VXLAN commands in `routers/*/vxlan-single-vni.cmd` to create the VTEP and the VLAN-to-VNI mapping (VLAN 100 → VNI 1000) +5. Apply FRR/`vtysh` BGP EVPN configurations in `routers/*/bgp-evpn.vtysh` to activate the BGP EVPN address-family **Verification** @@ -56,45 +70,118 @@ docker ps 2. Check BGP peerings and EVPN routes ```bash -sshpass -p admin ssh admin@clab-sonic-vpp01-router1 "vtysh -c 'show bgp summary'" -sshpass -p admin ssh admin@clab-sonic-vpp01-router2 "vtysh -c 'show bgp summary'" +sshpass -p admin ssh admin@clab-sonic-vpp-single-vni-router1 "vtysh -c 'show bgp summary'" +sshpass -p admin ssh admin@clab-sonic-vpp-single-vni-router2 "vtysh -c 'show bgp summary'" -sshpass -p admin ssh admin@clab-sonic-vpp01-router1 "vtysh -c 'show bgp l2vpn evpn'" -sshpass -p admin ssh admin@clab-sonic-vpp01-router2 "vtysh -c 'show bgp l2vpn evpn'" +sshpass -p admin ssh admin@clab-sonic-vpp-single-vni-router1 "vtysh -c 'show bgp l2vpn evpn'" +sshpass -p admin ssh admin@clab-sonic-vpp-single-vni-router2 "vtysh -c 'show bgp l2vpn evpn'" ``` 3. Check VXLAN interfaces on SONiC and VPP: ```bash -sshpass -p admin ssh admin@clab-sonic-vpp01-router1 "show vxlan tunnel" -sshpass -p admin ssh admin@clab-sonic-vpp01-router2 "show vxlan tunnel" +sshpass -p admin ssh admin@clab-sonic-vpp-single-vni-router1 "show vxlan tunnel" +sshpass -p admin ssh admin@clab-sonic-vpp-single-vni-router2 "show vxlan tunnel" -sshpass -p admin ssh admin@clab-sonic-vpp01-router1 "docker exec syncd vppctl show vxlan tunnel" -sshpass -p admin ssh admin@clab-sonic-vpp01-router2 "docker exec syncd vppctl show vxlan tunnel" +sshpass -p admin ssh admin@clab-sonic-vpp-single-vni-router1 "docker exec syncd vppctl show vxlan tunnel" +sshpass -p admin ssh admin@clab-sonic-vpp-single-vni-router2 "docker exec syncd vppctl show vxlan tunnel" ``` 4. Test L2 connectivity between PCs (run from host with `clab exec`): ```bash -docker exec clab-sonic-vpp01-PC1 ping -c 5 168.95.10.1 +docker exec clab-sonic-vpp-single-vni-PC1 ping -c 5 168.95.10.1 +``` + +5. To stop and destroy the example, simply execute the *stop-single-vni.sh* script within the folder you downloaded the example to: + +```bash +./stop-single-vni.sh +``` + +### Multi-VNI + +To launch the multi-VNI lab, simply execute the *run-multi-vni.sh* script within the folder you downloaded the example to: + +```bash +cd /cnf-examples/sonic-vpp/sonic-vpp-BGPEVPN +./run-multi-vni.sh +``` + +The run-multi-vni.sh script orchestrates the setup of two simultaneous VXLAN VNIs. + +**Configuration flow** + +The `run-multi-vni.sh` script performs these high-level actions: + +1. Deploy the ContainerLab topology from `multi-vni.clab.yml` (two routers, four PCs across two VLANs) +2. Configure host interfaces and router underlay IPs using `scripts/setup-multi-vni.sh` +3. Apply FRR/`vtysh` underlay configurations in `routers/*/bgp-underlay.vtysh` to bring up the IPv4 underlay +4. Apply VPP VXLAN commands in `routers/*/vxlan-multi-vni.cmd` to create the VTEP and both VLAN-to-VNI mappings (VLAN 100 → VNI 1000 and VLAN 200 → VNI 2000) +5. Apply FRR/`vtysh` BGP EVPN configurations in `routers/*/bgp-evpn.vtysh` to activate the BGP EVPN address-family + +**Verification** + +1. Start with topology and container checks (use `clab` first, fall back to `docker`): + +```bash +clab inspect +docker ps +``` + +2. Check BGP peerings and EVPN routes (Type-2 / Type-3 entries should appear for both VNIs): + +```bash +sshpass -p admin ssh admin@clab-sonic-vpp-multi-vni-router1 "vtysh -c 'show bgp summary'" +sshpass -p admin ssh admin@clab-sonic-vpp-multi-vni-router2 "vtysh -c 'show bgp summary'" + +sshpass -p admin ssh admin@clab-sonic-vpp-multi-vni-router1 "vtysh -c 'show bgp l2vpn evpn'" +sshpass -p admin ssh admin@clab-sonic-vpp-multi-vni-router2 "vtysh -c 'show bgp l2vpn evpn'" +``` + +3. Check VXLAN interfaces on SONiC and VPP (both VNI 1000 and VNI 2000 should be visible): + +```bash +sshpass -p admin ssh admin@clab-sonic-vpp-multi-vni-router1 "show vxlan tunnel" +sshpass -p admin ssh admin@clab-sonic-vpp-multi-vni-router2 "show vxlan tunnel" + +sshpass -p admin ssh admin@clab-sonic-vpp-multi-vni-router1 "docker exec syncd vppctl show vxlan tunnel" +sshpass -p admin ssh admin@clab-sonic-vpp-multi-vni-router2 "docker exec syncd vppctl show vxlan tunnel" +``` + +4. Test L2 connectivity within each VNI — cross-VNI traffic should fail by design, since the two VNIs are isolated L2 broadcast domains: + +```bash +# VNI 1000 — PC1 ↔ PC2 +docker exec clab-sonic-vpp-multi-vni-PC1 ping -c 5 10.100.1.2 + +# VNI 2000 — PC3 ↔ PC4 +docker exec clab-sonic-vpp-multi-vni-PC3 ping -c 5 10.200.1.2 +``` + +5. Run the included test suites for end-to-end validation (multi-VLAN reachability, MAC learning, BUM flooding, dynamic VNI hot-add, scale, link-flap recovery): + +```bash +./tests/test_multi_vlan_vxlan.sh +./tests/test_l2_vxlan_advanced.sh ``` -5. To stop and destroy the example, simply execute the *stop.sh* script within the folder you downloaded the example to: +6. To stop and destroy the example, simply execute the *stop-multi-vni.sh* script within the folder you downloaded the example to: ```bash -./stop.sh +./stop-multi-vni.sh ``` ## Packet tracing -To trace packets in VPP on Router1: +To trace packets in VPP on Router1 (single-VNI lab shown — substitute `clab-sonic-vpp-multi-vni-router1` and the appropriate PC/IP for the multi-VNI lab): ```bash -sshpass -p admin ssh admin@clab-sonic-vpp01-router1 "docker exec syncd vppctl trace add dpdk-input 10" +sshpass -p admin ssh admin@clab-sonic-vpp-single-vni-router1 "docker exec syncd vppctl trace add dpdk-input 10" # Generate traffic (from PC1): -docker exec clab-sonic-vpp01-PC1 ping -c 5 168.95.10.1 +docker exec clab-sonic-vpp-single-vni-PC1 ping -c 5 168.95.10.1 # View trace results: -sshpass -p admin ssh admin@clab-sonic-vpp01-router1 "docker exec syncd vppctl show trace" +sshpass -p admin ssh admin@clab-sonic-vpp-single-vni-router1 "docker exec syncd vppctl show trace" ``` # About