1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# 4# author: Andrea Mayer <andrea.mayer@uniroma2.it> 5 6# This test evaluates the SRv6 encap "lookup" attribute. After encapsulation 7# the router looks up the route for the first SID, that is the outer IPv6 8# destination of the encapsulated packet. The attribute selects the FIB table 9# used for this post-encap SID route lookup. 10# 11# Two routers (rt-1, rt-2) provide L3 VPN services over an IPv6 underlay 12# (fd00::/64). Each router uses a separate VRF per tenant, with default 13# blackhole routes (IPv4 and IPv6) to prevent traffic from leaking out of 14# the VRF. Tenant traffic is encapsulated, then decapsulated with an 15# End.DT46. Each router proxies both NDP and ARP. 16# 17# The routes that match the first SIDs are installed in a dedicated underlay 18# table (500) rather than the main table (254). The encap routes use 19# "lookup 500" to select this table for the post-encap SID route lookup. 20# 21# Without the "lookup" attribute, the route for the first SID cannot be found: 22# - on the input path (forwarded traffic), the lookup stays in the VRF 23# and hits the blackhole; 24# - on the output path (locally originated traffic), the lookup falls 25# through to the main table, with no route to the first SID. 26# 27# 28# Legend (specific per-tenant addresses are in the instantiation tables below): 29# X = tenant id and VRF table id; two tenants: 100 and 200 30# ("tX" means tenant X, e.g. t100, t200) 31# a, b = the two host ids of the tenant 32# HA, HB = addresses of host a, host b 33# RLO1, RLO2 = rlo-X router loopback address on rt-1, rt-2 (tenant gateway 34# for the output path, dual-stack) 35# vrf-X = per-tenant VRF on each router (table X) 36# 37# Constants (same for every tenant): 38# underlay = table 500; post-encap SID route lookup (via "lookup 500") 39# localsid = table 90; holds the decap SIDs (End.DT46) 40# fd00::/64 = underlay link between rt-1 and rt-2 41# veth-tX = cafe::254/10.0.0.254 (tenant gateway on veth, both routers) 42# 43# 44# +-------------------+ +-------------------+ 45# | | | | 46# | hs-tX-a netns | | hs-tX-b netns | 47# | | | | 48# | +-------------+ | | +-------------+ | 49# | | veth0 | | | | veth0 | | 50# | | HA | | | | HB | | 51# | +-------------+ | | +-------------+ | 52# | . | | . | 53# +-------------------+ +-------------------+ 54# . . 55# . . 56# +-----------------------------------+ +-----------------------------------+ 57# | . | | . | 58# | +---------------+ | | +---------------+ | 59# | | veth-tX | +----------+ | | +----------+ | veth-tX | | 60# | | ::254/.254 | | localsid | | | | localsid | | ::254/.254 | | 61# | +-------+-------+ +----------+ | | +----------+ +-------+-------+ | 62# | | +----------+ | | +----------+ | | 63# | +----+----+ | underlay | | | | underlay | +----+----+ | 64# | | vrf-X | +----------+ | | +----------+ | vrf-X | | 65# | +----+----+ | | +----+----+ | 66# | | | | | | 67# | +-----+----+ +------------+ | | +------------+ +----+-----+ | 68# | | rlo-X | | veth0 | | | | veth0 | | rlo-X | | 69# | | RLO1 | | fd00::1/64 |..|...|..| fd00::2/64 | | RLO2 | | 70# | +----------+ +------------+ | | +------------+ +----------+ | 71# | rt-1 netns | | rt-2 netns | 72# +-----------------------------------+ +-----------------------------------+ 73# 74# 75# Per-tenant instantiation: 76# +-----+------+-------------------+-------------------+ 77# | X | a, b | HA | HB | 78# +-----+------+-------------------+-------------------+ 79# | 100 | 1, 2 | cafe::1, 10.0.0.1 | cafe::2, 10.0.0.2 | 80# | 200 | 3, 4 | cafe::3, 10.0.0.3 | cafe::4, 10.0.0.4 | 81# +-----+------+-------------------+-------------------+ 82# 83# Router loopback (rlo-X) addresses, per tenant: 84# +-----+-----------------------+-----------------------+ 85# | X | RLO1 (rt-1) | RLO2 (rt-2) | 86# +-----+-----------------------+-----------------------+ 87# | 100 | cafe::101, 10.0.0.101 | cafe::102, 10.0.0.102 | 88# | 200 | cafe::201, 10.0.0.201 | cafe::202, 10.0.0.202 | 89# +-----+-----------------------+-----------------------+ 90# 91# 92# Network configuration 93# ===================== 94# 95# rt-1: localsid table (table 90) 96# +--------+--------------------+----------------------------------+ 97# | tenant | SID | Action | 98# +--------+--------------------+----------------------------------+ 99# | 100 | fc00:2:1:100::0d46 | apply SRv6 End.DT46 vrftable 100 | 100# | 200 | fc00:2:1:200::0d46 | apply SRv6 End.DT46 vrftable 200 | 101# +--------+--------------------+----------------------------------+ 102# 103# rt-1: underlay table (table 500) - post-encap SID route lookup 104# +--------+--------------------+-------------------------------+ 105# | tenant | SID | Action | 106# +--------+--------------------+-------------------------------+ 107# | 100 | fc00:1:2:100::0d46 | forward via fd00::2 dev veth0 | 108# | 200 | fc00:1:2:200::0d46 | forward via fd00::2 dev veth0 | 109# +--------+--------------------+-------------------------------+ 110# 111# rt-1: VRF tables (per tenant: vrf-X = table X) 112# +--------+------------+------------------------------------------+ 113# | tenant | dst | encap action | 114# +--------+------------+------------------------------------------+ 115# | 100 | cafe::2 | encap segs fc00:1:2:100::0d46 lookup 500 | 116# | | 10.0.0.2 | | 117# | | cafe::102 | | 118# | | 10.0.0.102 | | 119# | 200 | cafe::4 | encap segs fc00:1:2:200::0d46 lookup 500 | 120# | | 10.0.0.4 | | 121# | | cafe::202 | | 122# | | 10.0.0.202 | | 123# +--------+------------+------------------------------------------+ 124# 125# 126# rt-2: localsid table (table 90) 127# +--------+--------------------+----------------------------------+ 128# | tenant | SID | Action | 129# +--------+--------------------+----------------------------------+ 130# | 100 | fc00:1:2:100::0d46 | apply SRv6 End.DT46 vrftable 100 | 131# | 200 | fc00:1:2:200::0d46 | apply SRv6 End.DT46 vrftable 200 | 132# +--------+--------------------+----------------------------------+ 133# 134# rt-2: underlay table (table 500) - post-encap SID route lookup 135# +--------+--------------------+-------------------------------+ 136# | tenant | SID | Action | 137# +--------+--------------------+-------------------------------+ 138# | 100 | fc00:2:1:100::0d46 | forward via fd00::1 dev veth0 | 139# | 200 | fc00:2:1:200::0d46 | forward via fd00::1 dev veth0 | 140# +--------+--------------------+-------------------------------+ 141# 142# rt-2: VRF tables (per tenant: vrf-X = table X) 143# +--------+------------+------------------------------------------+ 144# | tenant | dst | encap action | 145# +--------+------------+------------------------------------------+ 146# | 100 | cafe::1 | encap segs fc00:2:1:100::0d46 lookup 500 | 147# | | 10.0.0.1 | | 148# | | cafe::101 | | 149# | | 10.0.0.101 | | 150# | 200 | cafe::3 | encap segs fc00:2:1:200::0d46 lookup 500 | 151# | | 10.0.0.3 | | 152# | | cafe::201 | | 153# | | 10.0.0.201 | | 154# +--------+------------+------------------------------------------+ 155# Within a tenant, a single SID reaches the adjacent router (its loopback) 156# and the remote host connected to it, in both IPv4 and IPv6. 157# 158# For both rt-1 and rt-2, each VRF also has the connected host prefix (cafe::/64 159# or 10.0.0.0/24) and a default blackhole (IPv4 and IPv6). 160# 161# 162# Locally originated traffic (output path) 163# ======================================== 164# 165# The configuration above covers forwarded traffic, where packets arrive from 166# a host and are encapsulated by the router. To also test router-originated 167# traffic, each router pings the other router's loopback address through 168# the VPN. 169# 170# Example (tenant 100), rt-1 pings cafe::102 (rt-2's loopback): 171# 1. rt-1 looks up cafe::102 in vrf-100 and encapsulates it (SID 172# fc00:1:2:100::0d46), then "lookup 500" finds the route for the SID in the 173# underlay table (next hop fd00::2) and forwards it; 174# 2. rt-2 decapsulates it (localsid, End.DT46) and delivers it locally 175# (cafe::102 is on the rlo-100 interface); 176# 3. rt-2 replies with destination cafe::101 (rt-1's loopback). rt-2 looks up 177# cafe::101 in vrf-100 and encapsulates it back to rt-1 (again via "lookup 178# 500"). rt-1 decapsulates it and delivers it. 179 180# shellcheck source=lib.sh 181source lib.sh 182 183readonly LOCALSID_TABLE_ID=90 184readonly UNDERLAY_TABLE_ID=500 185readonly IPv6_RT_NETWORK=fd00 186readonly IPv6_HS_NETWORK=cafe 187readonly IPv4_HS_NETWORK=10.0.0 188readonly VPN_LOCATOR_SERVICE=fc00 189readonly DT46_FUNC=0d46 190readonly DUMMY_DEVNAME=dum0 191readonly IPv6_TESTS_ADDR=2001:db8::1 192readonly TESTS_TABLE_ID=54321 193PING_TIMEOUT_SEC=4 194 195SETUP_ERR=1 196 197ret=${ksft_skip} 198nsuccess=0 199nfail=0 200 201PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} 202 203log_test() 204{ 205 local rc="$1" 206 local expected="$2" 207 local msg="$3" 208 209 if [ "${rc}" -eq "${expected}" ]; then 210 nsuccess=$((nsuccess+1)) 211 printf "\n TEST: %-60s [ OK ]\n" "${msg}" 212 else 213 ret=1 214 nfail=$((nfail+1)) 215 printf "\n TEST: %-60s [FAIL]\n" "${msg}" 216 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then 217 echo 218 echo "hit enter to continue, 'q' to quit" 219 read -r a 220 [ "$a" = "q" ] && exit 1 221 fi 222 fi 223} 224 225print_log_test_results() 226{ 227 printf "\nTests passed: %3d\n" "${nsuccess}" 228 printf "Tests failed: %3d\n" "${nfail}" 229 230 # when a test fails, the value of 'ret' is set to 1 (error code). 231 # Conversely, when all tests are passed successfully, the 'ret' value 232 # is set to 0 (success code). 233 if [ "${ret}" -ne 1 ]; then 234 ret=0 235 fi 236} 237 238log_section() 239{ 240 echo 241 echo "################################################################################" 242 echo "TEST SECTION: $*" 243 echo "################################################################################" 244} 245 246get_rtname() 247{ 248 local rtid="$1" 249 250 echo "rt_${rtid}" 251} 252 253get_rt_nsname() 254{ 255 local rtid="$1" 256 local varname 257 258 varname="$(get_rtname "${rtid}")" 259 echo "${!varname}" 260} 261 262get_hsname() 263{ 264 local tid="$1" 265 local hsid="$2" 266 267 echo "hs_t${tid}_${hsid}" 268} 269 270get_hs_nsname() 271{ 272 local tid="$1" 273 local hsid="$2" 274 local varname 275 276 varname="$(get_hsname "${tid}" "${hsid}")" 277 echo "${!varname}" 278} 279 280cleanup() 281{ 282 ip link del veth-rt-1 2>/dev/null || true 283 ip link del veth-rt-2 2>/dev/null || true 284 285 cleanup_all_ns 286 287 # check whether the setup phase was completed successfully or not. In 288 # case of an error during the setup phase of the testing environment, 289 # the selftest is considered as "skipped". 290 if [ "${SETUP_ERR}" -ne 0 ]; then 291 echo "SKIP: Setting up the testing environment failed" 292 exit "${ksft_skip}" 293 fi 294 295 exit "${ret}" 296} 297 298# Host id of the router loopback (rlo) for a (router, tenant) pair. 299# E.g. rt-1/tenant 100 -> 101, rt-2/tenant 200 -> 202. 300get_rlo_hostid() 301{ 302 local rtid="$1" 303 local tid="$2" 304 305 echo "$((tid + rtid))" 306} 307 308build_vpn_sid() 309{ 310 local rtsrc="$1" 311 local rtdst="$2" 312 local tid="$3" 313 314 echo "${VPN_LOCATOR_SERVICE}:${rtsrc}:${rtdst}:${tid}::${DT46_FUNC}" 315} 316 317# Install a dual-stack (IPv6 and IPv4) encap route in a VRF on the given 318# router. 319# args: 320# $1 - router id 321# $2 - host part of the IPv6 destination 322# $3 - host part of the IPv4 destination 323# $4 - SRv6 SID used as the encap destination 324# $5 - tenant id 325# $6 - if "true", add the "lookup" attribute to the encap route 326__set_encap_route() 327{ 328 local rt="$1" 329 local dst6="$2" 330 local dst4="$3" 331 local sid="$4" 332 local tid="$5" 333 local use_lookup="$6" 334 local lookup='' 335 local rtname 336 337 rtname="$(get_rt_nsname "${rt}")" 338 339 if [ "${use_lookup}" = "true" ]; then 340 lookup="lookup ${UNDERLAY_TABLE_ID}" 341 fi 342 343 # shellcheck disable=SC2086 344 ip -netns "${rtname}" -6 route replace \ 345 "${IPv6_HS_NETWORK}::${dst6}/128" vrf "vrf-${tid}" \ 346 encap seg6 mode encap segs "${sid}" ${lookup} dev veth0 347 348 # shellcheck disable=SC2086 349 ip -netns "${rtname}" -4 route replace \ 350 "${IPv4_HS_NETWORK}.${dst4}/32" vrf "vrf-${tid}" \ 351 encap seg6 mode encap segs "${sid}" ${lookup} dev veth0 352} 353 354# Install the dual-stack encap route for a tenant host on rt, with the 355# "lookup" attribute so the first SID is looked up in the underlay table. 356# args: 357# $1 - router id where the encap route is installed 358# $2 - host destination id (host part of cafe::<id>/128 and 10.0.0.<id>/32) 359# $3 - SRv6 SID used as the encap destination 360# $4 - tenant id 361set_host_encap_route() 362{ 363 local rt="$1" 364 local hsdst="$2" 365 local sid="$3" 366 local tid="$4" 367 368 __set_encap_route "${rt}" "${hsdst}" "${hsdst}" "${sid}" "${tid}" true 369} 370 371set_host_encap_route_nolookup() 372{ 373 local rt="$1" 374 local hsdst="$2" 375 local sid="$3" 376 local tid="$4" 377 378 __set_encap_route "${rt}" "${hsdst}" "${hsdst}" "${sid}" "${tid}" false 379} 380 381# Install the dual-stack encap route on rtsrc toward rtdst's rlo loopback 382# (RLO1 or RLO2, see header), with the "lookup" attribute so the first 383# SID is looked up in the underlay table. 384# args: 385# $1 - router id where the encap route is installed 386# $2 - router id whose loopback address is the route destination 387# $3 - SRv6 SID used as the encap destination 388# $4 - tenant id 389set_gw_encap_route() 390{ 391 local rtsrc="$1" 392 local rtdst="$2" 393 local sid="$3" 394 local tid="$4" 395 local dst 396 397 dst="$(get_rlo_hostid "${rtdst}" "${tid}")" 398 399 __set_encap_route "${rtsrc}" "${dst}" "${dst}" "${sid}" "${tid}" true 400} 401 402set_gw_encap_route_nolookup() 403{ 404 local rtsrc="$1" 405 local rtdst="$2" 406 local sid="$3" 407 local tid="$4" 408 local dst 409 410 dst="$(get_rlo_hostid "${rtdst}" "${tid}")" 411 412 __set_encap_route "${rtsrc}" "${dst}" "${dst}" "${sid}" "${tid}" false 413} 414 415# Setup the basic networking for a router 416setup_rt_networking() 417{ 418 local id="$1" 419 local nsname 420 421 nsname="$(get_rt_nsname "${id}")" 422 423 ip link set "veth-rt-${id}" netns "${nsname}" 424 ip -netns "${nsname}" link set "veth-rt-${id}" name veth0 425 426 ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0 427 ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0 428 429 ip -netns "${nsname}" addr add "${IPv6_RT_NETWORK}::${id}/64" dev veth0 nodad 430 ip -netns "${nsname}" link set veth0 up 431 432 ip netns exec "${nsname}" sysctl -wq net.ipv4.ip_forward=1 433 ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.forwarding=1 434} 435 436# Setup a host namespace and attach it to its gateway 437setup_hs() 438{ 439 local hid="$1" 440 local rid="$2" 441 local tid="$3" 442 local rtveth="veth-t${tid}" 443 local hsname 444 local rtname 445 446 hsname="$(get_hs_nsname "${tid}" "${hid}")" 447 rtname="$(get_rt_nsname "${rid}")" 448 449 ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0 450 ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0 451 452 ip -netns "${hsname}" link add veth0 type veth peer name "${rtveth}" 453 ip -netns "${hsname}" link set "${rtveth}" netns "${rtname}" 454 455 ip -netns "${hsname}" addr add \ 456 "${IPv6_HS_NETWORK}::${hid}/64" dev veth0 nodad 457 ip -netns "${hsname}" addr add \ 458 "${IPv4_HS_NETWORK}.${hid}/24" dev veth0 459 460 ip -netns "${hsname}" link set veth0 up 461} 462 463# Setup the per-tenant VRF on a router (gateway, loopback, blackhole) 464setup_rt() 465{ 466 local rid="$1" 467 local tid="$2" 468 local rtveth="veth-t${tid}" 469 local rlo_dev="rlo-${tid}" 470 local rtname 471 local gw_addr_v6 472 local gw_addr_v4 473 474 rtname="$(get_rt_nsname "${rid}")" 475 476 gw_addr_v6="${IPv6_HS_NETWORK}::$(get_rlo_hostid "${rid}" "${tid}")" 477 gw_addr_v4="${IPv4_HS_NETWORK}.$(get_rlo_hostid "${rid}" "${tid}")" 478 479 ip -netns "${rtname}" link add "vrf-${tid}" type vrf table "${tid}" 480 ip -netns "${rtname}" link set "vrf-${tid}" up 481 482 ip -netns "${rtname}" link set "${rtveth}" master "vrf-${tid}" 483 484 ip -netns "${rtname}" addr add \ 485 "${IPv6_HS_NETWORK}::254/64" dev "${rtveth}" nodad 486 ip -netns "${rtname}" addr add \ 487 "${IPv4_HS_NETWORK}.254/24" dev "${rtveth}" 488 489 ip -netns "${rtname}" link set "${rtveth}" up 490 491 ip netns exec "${rtname}" \ 492 sysctl -wq "net.ipv6.conf.${rtveth}.proxy_ndp=1" 493 ip netns exec "${rtname}" \ 494 sysctl -wq "net.ipv4.conf.${rtveth}.proxy_arp=1" 495 496 ip netns exec "${rtname}" sh -c "echo 1 > /proc/sys/net/vrf/strict_mode" 497 498 # router loopback interface for locally originated traffic 499 ip -netns "${rtname}" link add "${rlo_dev}" type dummy 500 ip -netns "${rtname}" link set "${rlo_dev}" master "vrf-${tid}" 501 502 ip -netns "${rtname}" addr add "${gw_addr_v6}/128" \ 503 dev "${rlo_dev}" nodad 504 ip -netns "${rtname}" addr add "${gw_addr_v4}/32" \ 505 dev "${rlo_dev}" 506 507 ip -netns "${rtname}" link set "${rlo_dev}" up 508 509 # default blackhole routes in the VRF: any traffic that does not match 510 # a specific route is dropped. Without the "lookup" attribute on the 511 # encap route, the route for the first SID cannot be found from within 512 # the VRF. 513 ip -netns "${rtname}" -6 route add blackhole default metric 4278198272 \ 514 vrf "vrf-${tid}" 515 ip -netns "${rtname}" -4 route add blackhole default metric 4278198272 \ 516 vrf "vrf-${tid}" 517} 518 519# Configure a one-way VPN path towards hsdst (on rtdst) for tenant tid. 520# The encap side is set up on rtsrc and the decap side on rtdst. 521# args: 522# $1 - router id where the encap side is set up 523# $2 - host id of the destination host 524# $3 - router id of the destination router (connected to the destination host) 525# $4 - tenant id 526setup_vpn_config() 527{ 528 local rtsrc="$1" 529 local hsdst="$2" 530 local rtdst="$3" 531 local tid="$4" 532 local rtveth="veth-t${tid}" 533 local rtsrc_name 534 local rtdst_name 535 local vpn_sid 536 537 rtsrc_name="$(get_rt_nsname "${rtsrc}")" 538 rtdst_name="$(get_rt_nsname "${rtdst}")" 539 vpn_sid="$(build_vpn_sid "${rtsrc}" "${rtdst}" "${tid}")" 540 541 ip -netns "${rtsrc_name}" -6 neigh add proxy \ 542 "${IPv6_HS_NETWORK}::${hsdst}" dev "${rtveth}" 543 set_host_encap_route "${rtsrc}" "${hsdst}" "${vpn_sid}" "${tid}" 544 545 ip -netns "${rtsrc_name}" -6 route add "${vpn_sid}/128" \ 546 table "${UNDERLAY_TABLE_ID}" \ 547 via "fd00::${rtdst}" dev veth0 548 549 # set the decap route for decapsulating packets arriving from rtsrc 550 # and destined to hsdst 551 ip -netns "${rtdst_name}" -6 route add "${vpn_sid}/128" \ 552 table "${LOCALSID_TABLE_ID}" \ 553 encap seg6local action End.DT46 \ 554 vrftable "${tid}" dev "vrf-${tid}" 555 556 # all SIDs for VPNs start with a common locator which is fc00::/16. 557 # Routes for handling the SRv6 End.DT* behavior instances are grouped 558 # together in the 'localsid' table. 559 # 560 # NOTE: added only once 561 if ! ip -netns "${rtdst_name}" -6 rule show | \ 562 grep -q "to ${VPN_LOCATOR_SERVICE}::/16 lookup ${LOCALSID_TABLE_ID}"; then 563 ip -netns "${rtdst_name}" -6 rule add \ 564 to "${VPN_LOCATOR_SERVICE}::/16" \ 565 lookup "${LOCALSID_TABLE_ID}" prio 999 566 fi 567} 568 569# Configure rtsrc to reach rtdst's loopback address through the VPN. 570# args: 571# $1 - router id where the encap route is installed 572# $2 - router id whose loopback is the destination 573# $3 - tenant id 574setup_vpn_gw_encap() 575{ 576 local rtsrc="$1" 577 local rtdst="$2" 578 local tid="$3" 579 local sid 580 581 sid="$(build_vpn_sid "${rtsrc}" "${rtdst}" "${tid}")" 582 583 set_gw_encap_route "${rtsrc}" "${rtdst}" "${sid}" "${tid}" 584} 585 586setup() 587{ 588 ip link add veth-rt-1 type veth peer name veth-rt-2 589 setup_ns rt_1 rt_2 590 setup_rt_networking 1 591 setup_rt_networking 2 592 593 # setup two hosts for the tenant 100. 594 # - host hs-t100-1 is directly connected to the router rt-1; 595 # - host hs-t100-2 is directly connected to the router rt-2. 596 setup_ns hs_t100_1 hs_t100_2 597 setup_hs 1 1 100 598 setup_hs 2 2 100 599 600 # setup two hosts for the tenant 200. 601 # - host hs-t200-3 is directly connected to the router rt-1; 602 # - host hs-t200-4 is directly connected to the router rt-2. 603 setup_ns hs_t200_3 hs_t200_4 604 setup_hs 3 1 200 605 setup_hs 4 2 200 606 607 # configure each router for each tenant: VRF, blackhole routes, 608 # router loopback interface 609 setup_rt 1 100 610 setup_rt 2 100 611 setup_rt 1 200 612 setup_rt 2 200 613 614 # setup the L3 VPN which connects the host hs-t100-1 and host hs-t100-2 615 # within the same tenant 100. 616 setup_vpn_config 1 2 2 100 617 setup_vpn_config 2 1 1 100 618 619 # setup the L3 VPN which connects the host hs-t200-3 and host hs-t200-4 620 # within the same tenant 200. 621 setup_vpn_config 1 4 2 200 622 setup_vpn_config 2 3 1 200 623 624 # allow each router to reach the other's loopback through the VPN 625 setup_vpn_gw_encap 2 1 100 626 setup_vpn_gw_encap 1 2 100 627 setup_vpn_gw_encap 2 1 200 628 setup_vpn_gw_encap 1 2 200 629 630 # testing environment was set up successfully 631 SETUP_ERR=0 632} 633 634check_rt_connectivity() 635{ 636 local rtsrc="$1" 637 local rtdst="$2" 638 local nsname 639 640 nsname="$(get_rt_nsname "${rtsrc}")" 641 642 ip netns exec "${nsname}" ping -c 1 -W 1 "${IPv6_RT_NETWORK}::${rtdst}" \ 643 >/dev/null 2>&1 644} 645 646check_and_log_rt_connectivity() 647{ 648 local rtsrc="$1" 649 local rtdst="$2" 650 651 check_rt_connectivity "${rtsrc}" "${rtdst}" 652 log_test $? 0 "Routers connectivity: rt-${rtsrc} -> rt-${rtdst}" 653} 654 655check_hs_ipv6_connectivity() 656{ 657 local hssrc="$1" 658 local hsdst="$2" 659 local tid="$3" 660 local nsname 661 662 nsname="$(get_hs_nsname "${tid}" "${hssrc}")" 663 664 ip netns exec "${nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \ 665 "${IPv6_HS_NETWORK}::${hsdst}" >/dev/null 2>&1 666} 667 668check_hs_ipv4_connectivity() 669{ 670 local hssrc="$1" 671 local hsdst="$2" 672 local tid="$3" 673 local nsname 674 675 nsname="$(get_hs_nsname "${tid}" "${hssrc}")" 676 677 ip netns exec "${nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \ 678 "${IPv4_HS_NETWORK}.${hsdst}" >/dev/null 2>&1 679} 680 681check_and_log_hs_connectivity() 682{ 683 local hssrc="$1" 684 local hsdst="$2" 685 local tid="$3" 686 687 check_hs_ipv6_connectivity "${hssrc}" "${hsdst}" "${tid}" 688 log_test $? 0 "IPv6 connectivity: hs-t${tid}-${hssrc} -> hs-t${tid}-${hsdst} (tenant ${tid})" 689 690 check_hs_ipv4_connectivity "${hssrc}" "${hsdst}" "${tid}" 691 log_test $? 0 "IPv4 connectivity: hs-t${tid}-${hssrc} -> hs-t${tid}-${hsdst} (tenant ${tid})" 692} 693 694check_and_log_hs_isolation() 695{ 696 local hssrc="$1" 697 local tidsrc="$2" 698 local hsdst="$3" 699 local tiddst="$4" 700 701 check_hs_ipv6_connectivity "${hssrc}" "${hsdst}" "${tidsrc}" 702 log_test $? 1 "IPv6 isolation: hs-t${tidsrc}-${hssrc} -X-> hs-t${tiddst}-${hsdst}" 703 704 check_hs_ipv4_connectivity "${hssrc}" "${hsdst}" "${tidsrc}" 705 log_test $? 1 "IPv4 isolation: hs-t${tidsrc}-${hssrc} -X-> hs-t${tiddst}-${hsdst}" 706} 707 708check_and_log_hs2gw_connectivity() 709{ 710 local hssrc="$1" 711 local tid="$2" 712 713 check_hs_ipv6_connectivity "${hssrc}" 254 "${tid}" 714 log_test $? 0 "IPv6 connectivity: hs-t${tid}-${hssrc} -> gw (tenant ${tid})" 715 716 check_hs_ipv4_connectivity "${hssrc}" 254 "${tid}" 717 log_test $? 0 "IPv4 connectivity: hs-t${tid}-${hssrc} -> gw (tenant ${tid})" 718} 719 720router_tests() 721{ 722 log_section "IPv6 routers connectivity test" 723 724 check_and_log_rt_connectivity 1 2 725 check_and_log_rt_connectivity 2 1 726} 727 728host2gateway_tests() 729{ 730 log_section "Connectivity test among hosts and gateway" 731 732 check_and_log_hs2gw_connectivity 1 100 733 check_and_log_hs2gw_connectivity 2 100 734 735 check_and_log_hs2gw_connectivity 3 200 736 check_and_log_hs2gw_connectivity 4 200 737} 738 739host_vpn_tests() 740{ 741 log_section "SRv6 VPN connectivity test among hosts in the same tenant" 742 743 check_and_log_hs_connectivity 1 2 100 744 check_and_log_hs_connectivity 2 1 100 745 746 check_and_log_hs_connectivity 3 4 200 747 check_and_log_hs_connectivity 4 3 200 748} 749 750host_vpn_isolation_tests() 751{ 752 local l1="1 2" 753 local l2="3 4" 754 local t1=100 755 local t2=200 756 local i 757 local j 758 local tmp 759 760 log_section "SRv6 VPN isolation test among hosts in different tenants" 761 762 for _ in 0 1; do 763 for i in ${l1}; do 764 for j in ${l2}; do 765 check_and_log_hs_isolation "${i}" "${t1}" "${j}" "${t2}" 766 done 767 done 768 769 # let us test the reverse path 770 tmp="${l1}"; l1="${l2}"; l2="${tmp}" 771 tmp=${t1}; t1=${t2}; t2=${tmp} 772 done 773} 774 775__test_nolookup() 776{ 777 local hssrc="$1" 778 local hsdst="$2" 779 local rtsrc="$3" 780 local rtdst="$4" 781 local tid="$5" 782 local vpn_sid 783 784 vpn_sid="$(build_vpn_sid "${rtsrc}" "${rtdst}" "${tid}")" 785 786 # replace encap route(s) without "lookup" attribute 787 set_host_encap_route_nolookup "${rtsrc}" "${hsdst}" "${vpn_sid}" "${tid}" 788 789 check_hs_ipv6_connectivity "${hssrc}" "${hsdst}" "${tid}" 790 log_test $? 1 "IPv6 w/o lookup: hs-t${tid}-${hssrc} -X-> hs-t${tid}-${hsdst} (tenant ${tid})" 791 792 check_hs_ipv4_connectivity "${hssrc}" "${hsdst}" "${tid}" 793 log_test $? 1 "IPv4 w/o lookup: hs-t${tid}-${hssrc} -X-> hs-t${tid}-${hsdst} (tenant ${tid})" 794 795 # restore encap route(s) with "lookup" for subsequent tests 796 set_host_encap_route "${rtsrc}" "${hsdst}" "${vpn_sid}" "${tid}" 797} 798 799host_vpn_nolookup_tests() 800{ 801 log_section "SRv6 VPN connectivity test among hosts w/o lookup" 802 803 __test_nolookup 1 2 1 2 100 804 __test_nolookup 2 1 2 1 100 805 806 __test_nolookup 3 4 1 2 200 807 __test_nolookup 4 3 2 1 200 808} 809 810check_gw_ipv6_connectivity() 811{ 812 local rtsrc="$1" 813 local rtdst="$2" 814 local tidsrc="$3" 815 local tiddst="$4" 816 local rtname 817 local src_v6 818 local dst_v6 819 820 rtname="$(get_rt_nsname "${rtsrc}")" 821 src_v6="${IPv6_HS_NETWORK}::$(get_rlo_hostid "${rtsrc}" "${tidsrc}")" 822 dst_v6="${IPv6_HS_NETWORK}::$(get_rlo_hostid "${rtdst}" "${tiddst}")" 823 824 ip netns exec "${rtname}" ip vrf exec "vrf-${tidsrc}" \ 825 ping -c 1 -W "${PING_TIMEOUT_SEC}" \ 826 -I "${src_v6}" "${dst_v6}" >/dev/null 2>&1 827} 828 829check_gw_ipv4_connectivity() 830{ 831 local rtsrc="$1" 832 local rtdst="$2" 833 local tidsrc="$3" 834 local tiddst="$4" 835 local rtname 836 local src_v4 837 local dst_v4 838 839 rtname="$(get_rt_nsname "${rtsrc}")" 840 src_v4="${IPv4_HS_NETWORK}.$(get_rlo_hostid "${rtsrc}" "${tidsrc}")" 841 dst_v4="${IPv4_HS_NETWORK}.$(get_rlo_hostid "${rtdst}" "${tiddst}")" 842 843 ip netns exec "${rtname}" ip vrf exec "vrf-${tidsrc}" \ 844 ping -c 1 -W "${PING_TIMEOUT_SEC}" \ 845 -I "${src_v4}" "${dst_v4}" >/dev/null 2>&1 846} 847 848check_and_log_gw_connectivity() 849{ 850 local rtsrc="$1" 851 local rtdst="$2" 852 local tid="$3" 853 854 check_gw_ipv6_connectivity "${rtsrc}" "${rtdst}" "${tid}" "${tid}" 855 log_test $? 0 "IPv6 connectivity: rt-${rtsrc} -> rt-${rtdst} (tenant ${tid})" 856 857 check_gw_ipv4_connectivity "${rtsrc}" "${rtdst}" "${tid}" "${tid}" 858 log_test $? 0 "IPv4 connectivity: rt-${rtsrc} -> rt-${rtdst} (tenant ${tid})" 859} 860 861check_and_log_gw_isolation() 862{ 863 local rtsrc="$1" 864 local rtdst="$2" 865 local tidsrc="$3" 866 local tiddst="$4" 867 868 check_gw_ipv6_connectivity "${rtsrc}" "${rtdst}" "${tidsrc}" "${tiddst}" 869 log_test $? 1 "IPv6 isolation: rt-${rtsrc} -X-> rt-${rtdst} (tenants ${tidsrc}/${tiddst})" 870 871 check_gw_ipv4_connectivity "${rtsrc}" "${rtdst}" "${tidsrc}" "${tiddst}" 872 log_test $? 1 "IPv4 isolation: rt-${rtsrc} -X-> rt-${rtdst} (tenants ${tidsrc}/${tiddst})" 873} 874 875gw_vpn_isolation_tests() 876{ 877 log_section "SRv6 VPN isolation test among routers in different tenants" 878 879 check_and_log_gw_isolation 1 2 100 200 880 check_and_log_gw_isolation 2 1 100 200 881 882 check_and_log_gw_isolation 1 2 200 100 883 check_and_log_gw_isolation 2 1 200 100 884} 885 886gw_vpn_tests() 887{ 888 log_section "SRv6 VPN connectivity test among routers in the same tenant" 889 890 check_and_log_gw_connectivity 1 2 100 891 check_and_log_gw_connectivity 2 1 100 892 893 check_and_log_gw_connectivity 1 2 200 894 check_and_log_gw_connectivity 2 1 200 895} 896 897__test_gw_nolookup() 898{ 899 local rtsrc="$1" 900 local rtdst="$2" 901 local tid="$3" 902 local sid 903 904 sid="$(build_vpn_sid "${rtsrc}" "${rtdst}" "${tid}")" 905 906 # replace gw encap route without "lookup" attribute 907 set_gw_encap_route_nolookup "${rtsrc}" "${rtdst}" "${sid}" "${tid}" 908 909 check_gw_ipv6_connectivity "${rtsrc}" "${rtdst}" "${tid}" "${tid}" 910 log_test $? 1 "IPv6 w/o lookup: rt-${rtsrc} -X-> rt-${rtdst} (tenant ${tid})" 911 912 check_gw_ipv4_connectivity "${rtsrc}" "${rtdst}" "${tid}" "${tid}" 913 log_test $? 1 "IPv4 w/o lookup: rt-${rtsrc} -X-> rt-${rtdst} (tenant ${tid})" 914 915 # restore gw encap route with "lookup" for subsequent tests 916 set_gw_encap_route "${rtsrc}" "${rtdst}" "${sid}" "${tid}" 917} 918 919gw_vpn_nolookup_tests() 920{ 921 log_section "SRv6 VPN connectivity test among routers w/o lookup" 922 923 __test_gw_nolookup 1 2 100 924 __test_gw_nolookup 2 1 100 925 926 __test_gw_nolookup 1 2 200 927 __test_gw_nolookup 2 1 200 928} 929 930test_command_or_ksft_skip() 931{ 932 local cmd="$1" 933 934 if [ ! -x "$(command -v "${cmd}")" ]; then 935 echo "SKIP: Could not run test without \"${cmd}\" tool" 936 exit "${ksft_skip}" 937 fi 938} 939 940test_vrf_or_ksft_skip() 941{ 942 modprobe vrf &>/dev/null || true 943 if [ ! -e /proc/sys/net/vrf/strict_mode ]; then 944 echo "SKIP: vrf sysctl does not exist" 945 exit "${ksft_skip}" 946 fi 947} 948 949test_dummy_dev_or_ksft_skip() 950{ 951 local test_netns 952 953 setup_ns test_netns 954 955 modprobe dummy &>/dev/null || true 956 if ! ip -netns "${test_netns}" link add "${DUMMY_DEVNAME}" \ 957 type dummy; then 958 cleanup_ns "${test_netns}" 959 echo "SKIP: dummy dev not supported" 960 exit "${ksft_skip}" 961 fi 962 963 cleanup_ns "${test_netns}" 964} 965 966test_encap_lookup_supp_or_ksft_skip() 967{ 968 local nsname 969 970 setup_ns nsname 971 972 ip -netns "${nsname}" link add "${DUMMY_DEVNAME}" type dummy 973 ip -netns "${nsname}" link set "${DUMMY_DEVNAME}" up 974 975 if ! ip -netns "${nsname}" -6 route add "${IPv6_TESTS_ADDR}/128" \ 976 encap seg6 mode encap segs fc00::1 \ 977 lookup "${TESTS_TABLE_ID}" \ 978 dev "${DUMMY_DEVNAME}" 2>/dev/null; then 979 cleanup_ns "${nsname}" 980 echo "SKIP: seg6 encap lookup attribute not supported" 981 exit "${ksft_skip}" 982 fi 983 984 # An old kernel with a recent iproute2 accepts the route but 985 # silently ignores the lookup attribute. Dump the route and check 986 # the attribute is really there, otherwise the test falsely passes. 987 if ! ip -netns "${nsname}" -6 route show "${IPv6_TESTS_ADDR}/128" | \ 988 grep -q "lookup ${TESTS_TABLE_ID}"; then 989 cleanup_ns "${nsname}" 990 echo "SKIP: seg6 encap lookup attribute not supported" 991 exit "${ksft_skip}" 992 fi 993 994 cleanup_ns "${nsname}" 995} 996 997if [ "$(id -u)" -ne 0 ]; then 998 echo "SKIP: Need root privileges" 999 exit "${ksft_skip}" 1000fi 1001 1002# required programs to carry out this selftest 1003test_command_or_ksft_skip ip 1004test_command_or_ksft_skip ping 1005test_command_or_ksft_skip sysctl 1006test_command_or_ksft_skip grep 1007 1008test_dummy_dev_or_ksft_skip 1009test_vrf_or_ksft_skip 1010test_encap_lookup_supp_or_ksft_skip 1011 1012set -e 1013trap cleanup EXIT 1014 1015setup 1016set +e 1017 1018router_tests 1019host2gateway_tests 1020host_vpn_tests 1021host_vpn_isolation_tests 1022host_vpn_nolookup_tests 1023gw_vpn_tests 1024gw_vpn_isolation_tests 1025gw_vpn_nolookup_tests 1026 1027print_log_test_results 1028