1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# 4# author: Andrea Mayer <andrea.mayer@uniroma2.it> 5# 6# This script is designed for testing the support of NEXT-C-SID flavor for SRv6 7# End behavior. 8# A basic knowledge of SRv6 architecture [1] and of the compressed SID approach 9# [2] is assumed for the reader. 10# 11# The network topology used in the selftest is depicted hereafter, composed by 12# two hosts and four routers. Hosts hs-1 and hs-2 are connected through an 13# IPv4/IPv6 L3 VPN service, offered by routers rt-1, rt-2, rt-3 and rt-4 using 14# the NEXT-C-SID flavor. The key components for such VPNs are: 15# 16# i) The SRv6 H.Encaps/H.Encaps.Red behaviors [1] apply SRv6 Policies on 17# traffic received by connected hosts, initiating the VPN tunnel; 18# 19# ii) The SRv6 End behavior [1] advances the active SID in the SID List 20# carried by the SRH; 21# 22# iii) The NEXT-C-SID mechanism [2] offers the possibility of encoding several 23# SRv6 segments within a single 128-bit SID address, referred to as a 24# Compressed SID (C-SID) container. In this way, the length of the SID 25# List can be drastically reduced. 26# The NEXT-C-SID is provided as a "flavor" of the SRv6 End behavior 27# which advances the current C-SID (i.e. the Locator-Node Function defined 28# in [2]) with the next one carried in the Argument, if available. 29# When no more C-SIDs are available in the Argument, the SRv6 End behavior 30# will apply the End function selecting the next SID in the SID List. 31# 32# iv) The SRv6 End.DT46 behavior [1] is used for removing the SRv6 Policy and, 33# thus, it terminates the VPN tunnel. Such a behavior is capable of 34# handling, at the same time, both tunneled IPv4 and IPv6 traffic. 35# 36# [1] https://datatracker.ietf.org/doc/html/rfc8986 37# [2] https://datatracker.ietf.org/doc/html/draft-ietf-spring-srv6-srh-compression 38# 39# 40# cafe::1 cafe::2 41# 10.0.0.1 10.0.0.2 42# +--------+ +--------+ 43# | | | | 44# | hs-1 | | hs-2 | 45# | | | | 46# +---+----+ +----+---+ 47# cafe::/64 | | cafe::/64 48# 10.0.0.0/24 | | 10.0.0.0/24 49# +---+----+ +----+---+ 50# | | fcf0:0:1:2::/64 | | 51# | rt-1 +-------------------+ rt-2 | 52# | | | | 53# +---+----+ +----+---+ 54# | . . | 55# | fcf0:0:1:3::/64 . | 56# | . . | 57# | . . | 58# fcf0:0:1:4::/64 | . | fcf0:0:2:3::/64 59# | . . | 60# | . . | 61# | fcf0:0:2:4::/64 . | 62# | . . | 63# +---+----+ +----+---+ 64# | | | | 65# | rt-4 +-------------------+ rt-3 | 66# | | fcf0:0:3:4::/64 | | 67# +---+----+ +----+---+ 68# 69# Every fcf0:0:x:y::/64 network interconnects the SRv6 routers rt-x with rt-y in 70# the selftest network. 71# 72# Local SID/C-SID table 73# ===================== 74# 75# Each SRv6 router is configured with a Local SID/C-SID table in which 76# SIDs/C-SIDs are stored. Considering an SRv6 router rt-x, SIDs/C-SIDs are 77# configured in the Local SID/C-SIDs table as follows: 78# 79# Local SID/C-SID table for SRv6 router rt-x 80# +-----------------------------------------------------------+ 81# |fcff:x::d46 is associated with the non-compressed SRv6 | 82# | End.DT46 behavior | 83# +-----------------------------------------------------------+ 84# |fcbb:0:0x00::/48 is associated with the NEXT-C-SID flavor | 85# | of SRv6 End behavior | 86# +-----------------------------------------------------------+ 87# |fcbb:0:0x00:d46::/64 is associated with the SRv6 End.DT46 | 88# | behavior when NEXT-C-SID compression is turned on | 89# +-----------------------------------------------------------+ 90# 91# The fcff::/16 prefix is reserved for implementing SRv6 services with regular 92# (non compressed) SIDs. Reachability of SIDs is ensured by proper configuration 93# of the IPv6 routing tables in the routers. 94# Similarly, the fcbb:0::/32 prefix is reserved for implementing SRv6 VPN 95# services leveraging the NEXT-C-SID compression mechanism. Indeed, the 96# fcbb:0::/32 is used for encoding the Locator-Block while the Locator-Node 97# Function is encoded with 16 bits. 98# 99# Incoming traffic classification and application of SRv6 Policies 100# ================================================================ 101# 102# An SRv6 ingress router applies different SRv6 Policies to the traffic received 103# from a connected host, considering the IPv4 or IPv6 destination address. 104# SRv6 policy enforcement consists of encapsulating the received traffic into a 105# new IPv6 packet with a given SID List contained in the SRH. 106# When the SID List contains only one SID, the SRH could be omitted completely 107# and that SID is stored directly in the IPv6 Destination Address (DA) (this is 108# called "reduced" encapsulation). 109# 110# Test cases for NEXT-C-SID 111# ========================= 112# 113# We consider two test cases for NEXT-C-SID: i) single SID and ii) double SID. 114# 115# In the single SID test case we have a number of segments that are all 116# contained in a single Compressed SID (C-SID) container. Therefore the 117# resulting SID List has only one SID. Using the reduced encapsulation format 118# this will result in a packet with no SRH. 119# 120# In the double SID test case we have one segment carried in a Compressed SID 121# (C-SID) container, followed by a regular (non compressed) SID. The resulting 122# SID List has two segments and it is possible to test the advance to the next 123# SID when all the C-SIDs in a C-SID container have been processed. Using the 124# reduced encapsulation format this will result in a packet with an SRH 125# containing 1 segment. 126# 127# For the single SID test case, we use the IPv4 addresses of hs-1 and hs-2, for 128# the double SID test case, we use their IPv6 addresses. This is only done to 129# simplify the test setup and avoid adding other hosts or multiple addresses on 130# the same interface of a host. 131# 132# Traffic from hs-1 to hs-2 133# ------------------------- 134# 135# Packets generated from hs-1 and directed towards hs-2 are handled by rt-1 136# which applies the SRv6 Policies as follows: 137# 138# i) IPv6 DA=cafe::2, H.Encaps.Red with SID List=fcbb:0:0400:0300:0200:d46:: 139# ii) IPv4 DA=10.0.0.2, H.Encaps.Red with SID List=fcbb:0:0300::,fcff:2::d46 140# 141# ### i) single SID 142# 143# The router rt-1 is configured to enforce the given Policy through the SRv6 144# H.Encaps.Red behavior which avoids the presence of the SRH at all, since it 145# pushes the single SID directly in the IPv6 DA. Such a SID encodes a whole 146# C-SID container carrying several C-SIDs (e.g. 0400, 0300, etc). 147# 148# As the packet reaches the router rt-4, the enabled NEXT-C-SID SRv6 End 149# behavior (associated with fcbb:0:0400::/48) is triggered. This behavior 150# analyzes the IPv6 DA and checks whether the Argument of the C-SID container 151# is zero or not. In this case, the Argument is *NOT* zero and the IPv6 DA is 152# updated as follows: 153# 154# +---------------------------------------------------------------+ 155# | Before applying the rt-4 enabled NEXT-C-SID SRv6 End behavior | 156# +---------------------------------------------------------------+ 157# | +---------- Argument | 158# | vvvvvvvvvvvvvvvv | 159# | IPv6 DA fcbb:0:0400:0300:0200:d46:: | 160# | ^^^^ <-- shifting | 161# | | | 162# | Locator-Node Function | 163# +---------------------------------------------------------------+ 164# | After applying the rt-4 enabled NEXT-C-SID SRv6 End behavior | 165# +---------------------------------------------------------------+ 166# | +---------- Argument | 167# | vvvvvvvvvvvv | 168# | IPv6 DA fcbb:0:0300:0200:d46:: | 169# | ^^^^ | 170# | | | 171# | Locator-Node Function | 172# +---------------------------------------------------------------+ 173# 174# After having applied the enabled NEXT-C-SID SRv6 End behavior, the packet is 175# sent to the next node, i.e. rt-3. 176# 177# The enabled NEXT-C-SID SRv6 End behavior on rt-3 is executed as the packet is 178# received. This behavior processes the packet and updates the IPv6 DA with 179# fcbb:0:0200:d46::, since the Argument is *NOT* zero. Then, the packet is sent 180# to the router rt-2. 181# 182# The router rt-2 is configured for decapsulating the inner IPv6 packet and, 183# for this reason, it applies the SRv6 End.DT46 behavior on the received 184# packet. It is worth noting that the SRv6 End.DT46 behavior does not require 185# the presence of the SRH: it is fully capable to operate properly on 186# IPv4/IPv6-in-IPv6 encapsulations. 187# At the end of the decap operation, the packet is sent to the 188# host hs-2. 189# 190# ### ii) double SID 191# 192# The router rt-1 is configured to enforce the given Policy through the SRv6 193# H.Encaps.Red. As a result, the first SID fcbb:0:0300:: is stored into the 194# IPv6 DA, while the SRH pushed into the packet is made of only one SID, i.e. 195# fcff:2::d46. Hence, the packet sent by hs-1 to hs-2 is encapsulated in an 196# outer IPv6 header plus the SRH. 197# 198# As the packet reaches the node rt-3, the router applies the enabled NEXT-C-SID 199# SRv6 End behavior. 200# 201# +---------------------------------------------------------------+ 202# | Before applying the rt-3 enabled NEXT-C-SID SRv6 End behavior | 203# +---------------------------------------------------------------+ 204# | +---------- Argument | 205# | vvvv (Argument is all filled with zeros) | 206# | IPv6 DA fcbb:0:0300:: | 207# | ^^^^ | 208# | | | 209# | Locator-Node Function | 210# +---------------------------------------------------------------+ 211# | After applying the rt-3 enabled NEXT-C-SID SRv6 End behavior | 212# +---------------------------------------------------------------+ 213# | | 214# | IPv6 DA fcff:2::d46 | 215# | ^^^^^^^^^^^ | 216# | | | 217# | SID copied from the SID List contained in the SRH | 218# +---------------------------------------------------------------+ 219# 220# Since the Argument of the C-SID container is zero, the behavior can not 221# update the Locator-Node function with the next C-SID carried in the Argument 222# itself. Thus, the enabled NEXT-C-SID SRv6 End behavior operates as the 223# traditional End behavior: it updates the IPv6 DA by copying the next 224# available SID in the SID List carried by the SRH. After that, the packet is 225# sent to the node rt-2. 226# 227# Once the packet is received by rt-2, the router decapsulates the inner IPv6 228# packet using the SRv6 End.DT46 behavior (associated with the SID fcff:2::d46) 229# and sends it to the host hs-2. 230# 231# Traffic from hs-2 to hs-1 232# ------------------------- 233# 234# Packets generated from hs-2 and directed towards hs-1 are handled by rt-2 235# which applies the SRv6 Policies as follows: 236# 237# i) IPv6 DA=cafe::1, SID List=fcbb:0:0300:0400:0100:d46:: 238# ii) IPv4 DA=10.0.0.1, SID List=fcbb:0:0300::,fcff:1::d46 239# 240# For simplicity, such SRv6 Policies were chosen so that, in both use cases (i) 241# and (ii), the network paths crossed by traffic from hs-2 to hs-1 are the same 242# as those taken by traffic from hs-1 to hs-2. 243# In this way, traffic from hs-2 to hs-1 is processed similarly to traffic from 244# hs-1 to hs-2. So, the traffic processing scheme turns out to be the same as 245# that adopted in the use cases already examined (of course, it is necessary to 246# consider the different SIDs/C-SIDs). 247 248source lib.sh 249 250readonly DUMMY_DEVNAME="dum0" 251readonly VRF_TID=100 252readonly VRF_DEVNAME="vrf-${VRF_TID}" 253readonly RT2HS_DEVNAME="veth-t${VRF_TID}" 254readonly LOCALSID_TABLE_ID=90 255readonly IPv6_RT_NETWORK=fcf0:0 256readonly IPv6_HS_NETWORK=cafe 257readonly IPv4_HS_NETWORK=10.0.0 258readonly VPN_LOCATOR_SERVICE=fcff 259readonly DT46_FUNC=0d46 260readonly HEADEND_ENCAP="encap.red" 261 262# do not add ':' as separator 263readonly LCBLOCK_ADDR=fcbb0000 264readonly LCBLOCK_BLEN=32 265# do not add ':' as separator 266readonly LCNODEFUNC_FMT="0%d00" 267readonly LCNODEFUNC_BLEN=16 268 269readonly LCBLOCK_NODEFUNC_BLEN=$((LCBLOCK_BLEN + LCNODEFUNC_BLEN)) 270 271readonly CSID_CNTR_PREFIX="dead:beaf::/32" 272# ID of the router used for testing the C-SID container cfgs 273readonly CSID_CNTR_RT_ID_TEST=1 274# Routing table used for testing the C-SID container cfgs 275readonly CSID_CNTR_RT_TABLE=91 276 277# C-SID container configurations to be tested 278# 279# An entry of the array is defined as "a,b,c" where: 280# - 'a' and 'b' elements represent respectively the Locator-Block length 281# (lblen) in bits and the Locator-Node Function length (nflen) in bits. 282# 'a' and 'b' can be set to default values using the placeholder "d" which 283# indicates the default kernel values (32 for lblen and 16 for nflen); 284# otherwise, any numeric value is accepted; 285# - 'c' indicates whether the C-SID configuration provided by the values 'a' 286# and 'b' should be considered valid ("y") or invalid ("n"). 287declare -ra CSID_CONTAINER_CFGS=( 288 "d,d,y" 289 "d,16,y" 290 "16,d,y" 291 "16,32,y" 292 "32,16,y" 293 "48,8,y" 294 "8,48,y" 295 "d,0,n" 296 "0,d,n" 297 "32,0,n" 298 "0,32,n" 299 "17,d,n" 300 "d,17,n" 301 "120,16,n" 302 "16,120,n" 303 "0,128,n" 304 "128,0,n" 305 "130,0,n" 306 "0,130,n" 307 "0,0,n" 308) 309 310PING_TIMEOUT_SEC=4 311PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} 312 313# IDs of routers and hosts are initialized during the setup of the testing 314# network 315ROUTERS='' 316HOSTS='' 317 318SETUP_ERR=1 319 320ret=${ksft_skip} 321nsuccess=0 322nfail=0 323 324log_test() 325{ 326 local rc="$1" 327 local expected="$2" 328 local msg="$3" 329 330 if [ "${rc}" -eq "${expected}" ]; then 331 nsuccess=$((nsuccess+1)) 332 printf "\n TEST: %-60s [ OK ]\n" "${msg}" 333 else 334 ret=1 335 nfail=$((nfail+1)) 336 printf "\n TEST: %-60s [FAIL]\n" "${msg}" 337 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then 338 echo 339 echo "hit enter to continue, 'q' to quit" 340 read a 341 [ "$a" = "q" ] && exit 1 342 fi 343 fi 344} 345 346print_log_test_results() 347{ 348 printf "\nTests passed: %3d\n" "${nsuccess}" 349 printf "Tests failed: %3d\n" "${nfail}" 350 351 # when a test fails, the value of 'ret' is set to 1 (error code). 352 # Conversely, when all tests are passed successfully, the 'ret' value 353 # is set to 0 (success code). 354 if [ "${ret}" -ne 1 ]; then 355 ret=0 356 fi 357} 358 359log_section() 360{ 361 echo 362 echo "################################################################################" 363 echo "TEST SECTION: $*" 364 echo "################################################################################" 365} 366 367test_command_or_ksft_skip() 368{ 369 local cmd="$1" 370 371 if [ ! -x "$(command -v "${cmd}")" ]; then 372 echo "SKIP: Could not run test without \"${cmd}\" tool"; 373 exit "${ksft_skip}" 374 fi 375} 376 377get_rtname() 378{ 379 local rtid="$1" 380 381 echo "rt_${rtid}" 382} 383 384get_hsname() 385{ 386 local hsid="$1" 387 388 echo "hs_${hsid}" 389} 390 391create_router() 392{ 393 local rtid="$1" 394 local nsname 395 396 nsname="$(get_rtname "${rtid}")" 397 setup_ns "${nsname}" 398} 399 400create_host() 401{ 402 local hsid="$1" 403 local nsname 404 405 nsname="$(get_hsname "${hsid}")" 406 setup_ns "${nsname}" 407} 408 409cleanup() 410{ 411 cleanup_all_ns 412 413 # check whether the setup phase was completed successfully or not. In 414 # case of an error during the setup phase of the testing environment, 415 # the selftest is considered as "skipped". 416 if [ "${SETUP_ERR}" -ne 0 ]; then 417 echo "SKIP: Setting up the testing environment failed" 418 exit "${ksft_skip}" 419 fi 420 421 exit "${ret}" 422} 423 424add_link_rt_pairs() 425{ 426 local rt="$1" 427 local rt_neighs="$2" 428 local neigh 429 local nsname 430 local neigh_nsname 431 432 eval nsname=\${$(get_rtname "${rt}")} 433 434 for neigh in ${rt_neighs}; do 435 eval neigh_nsname=\${$(get_rtname "${neigh}")} 436 437 ip link add "veth-rt-${rt}-${neigh}" netns "${nsname}" \ 438 type veth peer name "veth-rt-${neigh}-${rt}" \ 439 netns "${neigh_nsname}" 440 done 441} 442 443get_network_prefix() 444{ 445 local rt="$1" 446 local neigh="$2" 447 local p="${rt}" 448 local q="${neigh}" 449 450 if [ "${p}" -gt "${q}" ]; then 451 p="${q}"; q="${rt}" 452 fi 453 454 echo "${IPv6_RT_NETWORK}:${p}:${q}" 455} 456 457# Setup the basic networking for the routers 458setup_rt_networking() 459{ 460 local rt="$1" 461 local rt_neighs="$2" 462 local nsname 463 local net_prefix 464 local devname 465 local neigh 466 467 eval nsname=\${$(get_rtname "${rt}")} 468 469 for neigh in ${rt_neighs}; do 470 devname="veth-rt-${rt}-${neigh}" 471 472 net_prefix="$(get_network_prefix "${rt}" "${neigh}")" 473 474 ip -netns "${nsname}" addr \ 475 add "${net_prefix}::${rt}/64" dev "${devname}" nodad 476 477 ip -netns "${nsname}" link set "${devname}" up 478 done 479 480 ip -netns "${nsname}" link add "${DUMMY_DEVNAME}" type dummy 481 482 ip -netns "${nsname}" link set "${DUMMY_DEVNAME}" up 483 ip -netns "${nsname}" link set lo up 484 485 ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0 486 ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0 487 ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.forwarding=1 488 ip netns exec "${nsname}" sysctl -wq net.ipv4.ip_forward=1 489} 490 491# build an ipv6 prefix/address based on the input string 492# Note that the input string does not contain ':' and '::' which are considered 493# to be implicit. 494# e.g.: 495# - input: fbcc00000400300 496# - output: fbcc:0000:0400:0300:0000:0000:0000:0000 497# ^^^^^^^^^^^^^^^^^^^ 498# fill the address with 0s 499build_ipv6_addr() 500{ 501 local addr="$1" 502 local out="" 503 local strlen="${#addr}" 504 local padn 505 local i 506 507 # add ":" every 4 digits (16 bits) 508 for (( i = 0; i < strlen; i++ )); do 509 if (( i > 0 && i < 32 && (i % 4) == 0 )); then 510 out="${out}:" 511 fi 512 513 out="${out}${addr:$i:1}" 514 done 515 516 # fill the remaining bits of the address with 0s 517 padn=$((32 - strlen)) 518 for (( i = padn; i > 0; i-- )); do 519 if (( i > 0 && i < 32 && (i % 4) == 0 )); then 520 out="${out}:" 521 fi 522 523 out="${out}0" 524 done 525 526 printf "${out}" 527} 528 529build_csid() 530{ 531 local nodeid="$1" 532 533 printf "${LCNODEFUNC_FMT}" "${nodeid}" 534} 535 536build_lcnode_func_prefix() 537{ 538 local nodeid="$1" 539 local lcnodefunc 540 local prefix 541 local out 542 543 lcnodefunc="$(build_csid "${nodeid}")" 544 prefix="$(build_ipv6_addr "${LCBLOCK_ADDR}${lcnodefunc}")" 545 546 out="${prefix}/${LCBLOCK_NODEFUNC_BLEN}" 547 548 echo "${out}" 549} 550 551# Setup local SIDs for an SRv6 router 552setup_rt_local_sids() 553{ 554 local rt="$1" 555 local rt_neighs="$2" 556 local net_prefix 557 local devname 558 local nsname 559 local neigh 560 local lcnode_func_prefix 561 local lcblock_prefix 562 563 eval nsname=\${$(get_rtname "${rt}")} 564 565 for neigh in ${rt_neighs}; do 566 devname="veth-rt-${rt}-${neigh}" 567 568 net_prefix="$(get_network_prefix "${rt}" "${neigh}")" 569 570 # set underlay network routes for SIDs reachability 571 ip -netns "${nsname}" -6 route \ 572 add "${VPN_LOCATOR_SERVICE}:${neigh}::/32" \ 573 table "${LOCALSID_TABLE_ID}" \ 574 via "${net_prefix}::${neigh}" dev "${devname}" 575 576 # set the underlay network for C-SIDs reachability 577 lcnode_func_prefix="$(build_lcnode_func_prefix "${neigh}")" 578 579 ip -netns "${nsname}" -6 route \ 580 add "${lcnode_func_prefix}" \ 581 table "${LOCALSID_TABLE_ID}" \ 582 via "${net_prefix}::${neigh}" dev "${devname}" 583 done 584 585 lcnode_func_prefix="$(build_lcnode_func_prefix "${rt}")" 586 587 # enabled NEXT-C-SID SRv6 End behavior (note that "dev" is the dummy 588 # dum0 device chosen for the sake of simplicity). 589 ip -netns "${nsname}" -6 route \ 590 add "${lcnode_func_prefix}" \ 591 table "${LOCALSID_TABLE_ID}" \ 592 encap seg6local action End flavors next-csid \ 593 lblen "${LCBLOCK_BLEN}" nflen "${LCNODEFUNC_BLEN}" \ 594 dev "${DUMMY_DEVNAME}" 595 596 # all SIDs for VPNs start with a common locator. Routes and SRv6 597 # Endpoint behavior instances are grouped together in the 'localsid' 598 # table. 599 ip -netns "${nsname}" -6 rule \ 600 add to "${VPN_LOCATOR_SERVICE}::/16" \ 601 lookup "${LOCALSID_TABLE_ID}" prio 999 602 603 # common locator block for NEXT-C-SIDS compression mechanism. 604 lcblock_prefix="$(build_ipv6_addr "${LCBLOCK_ADDR}")" 605 ip -netns "${nsname}" -6 rule \ 606 add to "${lcblock_prefix}/${LCBLOCK_BLEN}" \ 607 lookup "${LOCALSID_TABLE_ID}" prio 999 608} 609 610# build and install the SRv6 policy into the ingress SRv6 router as well as the 611# decap SID in the egress one. 612# args: 613# $1 - src host (evaluate automatically the ingress router) 614# $2 - dst host (evaluate automatically the egress router) 615# $3 - SRv6 routers configured for steering traffic (End behaviors) 616# $4 - single SID or double SID 617# $5 - traffic type (IPv6 or IPv4) 618__setup_l3vpn() 619{ 620 local src="$1" 621 local dst="$2" 622 local end_rts="$3" 623 local mode="$4" 624 local traffic="$5" 625 local nsname 626 local policy 627 local container 628 local decapsid 629 local lcnfunc 630 local dt 631 local n 632 local rtsrc_nsname 633 local rtdst_nsname 634 635 eval rtsrc_nsname=\${$(get_rtname "${src}")} 636 eval rtdst_nsname=\${$(get_rtname "${dst}")} 637 638 container="${LCBLOCK_ADDR}" 639 640 # build first SID (C-SID container) 641 for n in ${end_rts}; do 642 lcnfunc="$(build_csid "${n}")" 643 644 container="${container}${lcnfunc}" 645 done 646 647 if [ "${mode}" -eq 1 ]; then 648 # single SID policy 649 dt="$(build_csid "${dst}")${DT46_FUNC}" 650 container="${container}${dt}" 651 # build the full ipv6 address for the container 652 policy="$(build_ipv6_addr "${container}")" 653 654 # build the decap SID used in the decap node 655 container="${LCBLOCK_ADDR}${dt}" 656 decapsid="$(build_ipv6_addr "${container}")" 657 else 658 # double SID policy 659 decapsid="${VPN_LOCATOR_SERVICE}:${dst}::${DT46_FUNC}" 660 661 policy="$(build_ipv6_addr "${container}"),${decapsid}" 662 fi 663 664 # apply encap policy 665 if [ "${traffic}" -eq 6 ]; then 666 ip -netns "${rtsrc_nsname}" -6 route \ 667 add "${IPv6_HS_NETWORK}::${dst}" vrf "${VRF_DEVNAME}" \ 668 encap seg6 mode "${HEADEND_ENCAP}" segs "${policy}" \ 669 dev "${VRF_DEVNAME}" 670 671 ip -netns "${rtsrc_nsname}" -6 neigh \ 672 add proxy "${IPv6_HS_NETWORK}::${dst}" \ 673 dev "${RT2HS_DEVNAME}" 674 else 675 # "dev" must be different from the one where the packet is 676 # received, otherwise the proxy arp does not work. 677 ip -netns "${rtsrc_nsname}" -4 route \ 678 add "${IPv4_HS_NETWORK}.${dst}" vrf "${VRF_DEVNAME}" \ 679 encap seg6 mode "${HEADEND_ENCAP}" segs "${policy}" \ 680 dev "${VRF_DEVNAME}" 681 fi 682 683 # apply decap 684 # Local End.DT46 behavior (decap) 685 ip -netns "${rtdst_nsname}" -6 route \ 686 add "${decapsid}" \ 687 table "${LOCALSID_TABLE_ID}" \ 688 encap seg6local action End.DT46 vrftable "${VRF_TID}" \ 689 dev "${VRF_DEVNAME}" 690} 691 692# see __setup_l3vpn() 693setup_ipv4_vpn_2sids() 694{ 695 __setup_l3vpn "$1" "$2" "$3" 2 4 696} 697 698# see __setup_l3vpn() 699setup_ipv6_vpn_1sid() 700{ 701 __setup_l3vpn "$1" "$2" "$3" 1 6 702} 703 704setup_hs() 705{ 706 local hs="$1" 707 local rt="$2" 708 local hsname 709 local rtname 710 711 eval hsname=\${$(get_hsname "${hs}")} 712 eval rtname=\${$(get_rtname "${rt}")} 713 714 ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0 715 ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0 716 717 ip -netns "${hsname}" link add veth0 type veth \ 718 peer name "${RT2HS_DEVNAME}" netns "${rtname}" 719 720 ip -netns "${hsname}" addr \ 721 add "${IPv6_HS_NETWORK}::${hs}/64" dev veth0 nodad 722 ip -netns "${hsname}" addr add "${IPv4_HS_NETWORK}.${hs}/24" dev veth0 723 724 ip -netns "${hsname}" link set veth0 up 725 ip -netns "${hsname}" link set lo up 726 727 # configure the VRF on the router which is directly connected to the 728 # source host. 729 ip -netns "${rtname}" link \ 730 add "${VRF_DEVNAME}" type vrf table "${VRF_TID}" 731 ip -netns "${rtname}" link set "${VRF_DEVNAME}" up 732 733 # enslave the veth interface connecting the router with the host to the 734 # VRF in the access router 735 ip -netns "${rtname}" link \ 736 set "${RT2HS_DEVNAME}" master "${VRF_DEVNAME}" 737 738 # set default routes to unreachable for both ipv6 and ipv4 739 ip -netns "${rtname}" -6 route \ 740 add unreachable default metric 4278198272 \ 741 vrf "${VRF_DEVNAME}" 742 ip -netns "${rtname}" -4 route \ 743 add unreachable default metric 4278198272 \ 744 vrf "${VRF_DEVNAME}" 745 746 ip -netns "${rtname}" addr \ 747 add "${IPv6_HS_NETWORK}::254/64" dev "${RT2HS_DEVNAME}" nodad 748 ip -netns "${rtname}" addr \ 749 add "${IPv4_HS_NETWORK}.254/24" dev "${RT2HS_DEVNAME}" 750 751 ip -netns "${rtname}" link set "${RT2HS_DEVNAME}" up 752 753 ip netns exec "${rtname}" \ 754 sysctl -wq net.ipv6.conf."${RT2HS_DEVNAME}".proxy_ndp=1 755 ip netns exec "${rtname}" \ 756 sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".proxy_arp=1 757 758 ip netns exec "${rtname}" sh -c "echo 1 > /proc/sys/net/vrf/strict_mode" 759} 760 761setup() 762{ 763 local i 764 765 # create routers 766 ROUTERS="1 2 3 4"; readonly ROUTERS 767 for i in ${ROUTERS}; do 768 create_router "${i}" 769 done 770 771 # create hosts 772 HOSTS="1 2"; readonly HOSTS 773 for i in ${HOSTS}; do 774 create_host "${i}" 775 done 776 777 # set up the links for connecting routers 778 add_link_rt_pairs 1 "2 3 4" 779 add_link_rt_pairs 2 "3 4" 780 add_link_rt_pairs 3 "4" 781 782 # set up the basic connectivity of routers and routes required for 783 # reachability of SIDs. 784 setup_rt_networking 1 "2 3 4" 785 setup_rt_networking 2 "1 3 4" 786 setup_rt_networking 3 "1 2 4" 787 setup_rt_networking 4 "1 2 3" 788 789 # set up the hosts connected to routers 790 setup_hs 1 1 791 setup_hs 2 2 792 793 # set up default SRv6 Endpoints (i.e. SRv6 End and SRv6 End.DT46) 794 setup_rt_local_sids 1 "2 3 4" 795 setup_rt_local_sids 2 "1 3 4" 796 setup_rt_local_sids 3 "1 2 4" 797 setup_rt_local_sids 4 "1 2 3" 798 799 # set up SRv6 Policies 800 801 # create an IPv6 VPN between hosts hs-1 and hs-2. 802 # 803 # Direction hs-1 -> hs-2 804 # - rt-1 encap (H.Encaps.Red) 805 # - rt-4 SRv6 End behavior (NEXT-C-SID flavor) 806 # - rt-3 SRv6 End behavior (NEXT-C-SID flavor) 807 # - rt-2 SRv6 End.DT46 behavior 808 setup_ipv6_vpn_1sid 1 2 "4 3" 809 810 # Direction hs2 -> hs-1 811 # - rt-2 encap (H.Encaps.Red) 812 # - rt-3 SRv6 End behavior (NEXT-C-SID flavor) 813 # - rt-4 SRv6 End behavior (NEXT-C-SID flavor) 814 # - rt-1 SRv6 End.DT46 behavior 815 setup_ipv6_vpn_1sid 2 1 "3 4" 816 817 # create an IPv4 VPN between hosts hs-1 and hs-2 818 # 819 # Direction hs-1 -> hs-2 820 # - rt-1 encap (H.Encaps.Red) 821 # - rt-3 SRv6 End behavior (NEXT-C-SID flavor) 822 # - rt-2 SRv6 End.DT46 behavior 823 setup_ipv4_vpn_2sids 1 2 "3" 824 825 # Direction hs-2 -> hs-1 826 # - rt-2 encap (H.Encaps.Red) 827 # - rt-3 SRv6 End behavior (NEXT-C-SID flavor) 828 # - rt-1 SRv6 End.DT46 behavior 829 setup_ipv4_vpn_2sids 2 1 "3" 830 831 # testing environment was set up successfully 832 SETUP_ERR=0 833} 834 835check_rt_connectivity() 836{ 837 local rtsrc="$1" 838 local rtdst="$2" 839 local prefix 840 local rtsrc_nsname 841 842 eval rtsrc_nsname=\${$(get_rtname "${rtsrc}")} 843 844 prefix="$(get_network_prefix "${rtsrc}" "${rtdst}")" 845 846 ip netns exec "${rtsrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \ 847 "${prefix}::${rtdst}" >/dev/null 2>&1 848} 849 850check_and_log_rt_connectivity() 851{ 852 local rtsrc="$1" 853 local rtdst="$2" 854 855 check_rt_connectivity "${rtsrc}" "${rtdst}" 856 log_test $? 0 "Routers connectivity: rt-${rtsrc} -> rt-${rtdst}" 857} 858 859check_hs_ipv6_connectivity() 860{ 861 local hssrc="$1" 862 local hsdst="$2" 863 local hssrc_nsname 864 865 eval hssrc_nsname=\${$(get_hsname "${hssrc}")} 866 867 ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \ 868 "${IPv6_HS_NETWORK}::${hsdst}" >/dev/null 2>&1 869} 870 871check_hs_ipv4_connectivity() 872{ 873 local hssrc="$1" 874 local hsdst="$2" 875 local hssrc_nsname 876 877 eval hssrc_nsname=\${$(get_hsname "${hssrc}")} 878 879 ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \ 880 "${IPv4_HS_NETWORK}.${hsdst}" >/dev/null 2>&1 881} 882 883check_and_log_hs2gw_connectivity() 884{ 885 local hssrc="$1" 886 887 check_hs_ipv6_connectivity "${hssrc}" 254 888 log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> gw" 889 890 check_hs_ipv4_connectivity "${hssrc}" 254 891 log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> gw" 892} 893 894check_and_log_hs_ipv6_connectivity() 895{ 896 local hssrc="$1" 897 local hsdst="$2" 898 899 check_hs_ipv6_connectivity "${hssrc}" "${hsdst}" 900 log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}" 901} 902 903check_and_log_hs_ipv4_connectivity() 904{ 905 local hssrc="$1" 906 local hsdst="$2" 907 908 check_hs_ipv4_connectivity "${hssrc}" "${hsdst}" 909 log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}" 910} 911 912router_tests() 913{ 914 local i 915 local j 916 917 log_section "IPv6 routers connectivity test" 918 919 for i in ${ROUTERS}; do 920 for j in ${ROUTERS}; do 921 if [ "${i}" -eq "${j}" ]; then 922 continue 923 fi 924 925 check_and_log_rt_connectivity "${i}" "${j}" 926 done 927 done 928} 929 930host2gateway_tests() 931{ 932 local hs 933 934 log_section "IPv4/IPv6 connectivity test among hosts and gateways" 935 936 for hs in ${HOSTS}; do 937 check_and_log_hs2gw_connectivity "${hs}" 938 done 939} 940 941host_vpn_tests() 942{ 943 log_section "SRv6 VPN connectivity test hosts (h1 <-> h2, IPv6)" 944 945 check_and_log_hs_ipv6_connectivity 1 2 946 check_and_log_hs_ipv6_connectivity 2 1 947 948 log_section "SRv6 VPN connectivity test hosts (h1 <-> h2, IPv4)" 949 950 check_and_log_hs_ipv4_connectivity 1 2 951 check_and_log_hs_ipv4_connectivity 2 1 952} 953 954__nextcsid_end_behavior_test() 955{ 956 local nsname="$1" 957 local cmd="$2" 958 local blen="$3" 959 local flen="$4" 960 local layout="" 961 962 if [ "${blen}" != "d" ]; then 963 layout="${layout} lblen ${blen}" 964 fi 965 966 if [ "${flen}" != "d" ]; then 967 layout="${layout} nflen ${flen}" 968 fi 969 970 ip -netns "${nsname}" -6 route \ 971 "${cmd}" "${CSID_CNTR_PREFIX}" \ 972 table "${CSID_CNTR_RT_TABLE}" \ 973 encap seg6local action End flavors next-csid ${layout} \ 974 dev "${DUMMY_DEVNAME}" &>/dev/null 975 976 return "$?" 977} 978 979rt_x_nextcsid_end_behavior_test() 980{ 981 local rt="$1" 982 local blen="$2" 983 local flen="$3" 984 local nsname 985 local ret 986 987 eval nsname=\${$(get_rtname "${rt}")} 988 989 __nextcsid_end_behavior_test "${nsname}" "add" "${blen}" "${flen}" 990 ret="$?" 991 __nextcsid_end_behavior_test "${nsname}" "del" "${blen}" "${flen}" 992 993 return "${ret}" 994} 995 996__parse_csid_container_cfg() 997{ 998 local cfg="$1" 999 local index="$2" 1000 local out 1001 1002 echo "${cfg}" | cut -d',' -f"${index}" 1003} 1004 1005csid_container_cfg_tests() 1006{ 1007 local valid 1008 local blen 1009 local flen 1010 local cfg 1011 local ret 1012 1013 log_section "C-SID Container config tests (legend: d='kernel default')" 1014 1015 for cfg in "${CSID_CONTAINER_CFGS[@]}"; do 1016 blen="$(__parse_csid_container_cfg "${cfg}" 1)" 1017 flen="$(__parse_csid_container_cfg "${cfg}" 2)" 1018 valid="$(__parse_csid_container_cfg "${cfg}" 3)" 1019 1020 rt_x_nextcsid_end_behavior_test \ 1021 "${CSID_CNTR_RT_ID_TEST}" \ 1022 "${blen}" \ 1023 "${flen}" 1024 ret="$?" 1025 1026 if [ "${valid}" == "y" ]; then 1027 log_test "${ret}" 0 \ 1028 "Accept valid C-SID container cfg (lblen=${blen}, nflen=${flen})" 1029 else 1030 log_test "${ret}" 2 \ 1031 "Reject invalid C-SID container cfg (lblen=${blen}, nflen=${flen})" 1032 fi 1033 done 1034} 1035 1036test_iproute2_supp_or_ksft_skip() 1037{ 1038 if ! ip route help 2>&1 | grep -qo "next-csid"; then 1039 echo "SKIP: Missing SRv6 NEXT-C-SID flavor support in iproute2" 1040 exit "${ksft_skip}" 1041 fi 1042} 1043 1044test_dummy_dev_or_ksft_skip() 1045{ 1046 local test_netns 1047 1048 test_netns="dummy-$(mktemp -u XXXXXXXX)" 1049 1050 if ! ip netns add "${test_netns}"; then 1051 echo "SKIP: Cannot set up netns for testing dummy dev support" 1052 exit "${ksft_skip}" 1053 fi 1054 1055 modprobe dummy &>/dev/null || true 1056 if ! ip -netns "${test_netns}" link \ 1057 add "${DUMMY_DEVNAME}" type dummy; then 1058 echo "SKIP: dummy dev not supported" 1059 1060 ip netns del "${test_netns}" 1061 exit "${ksft_skip}" 1062 fi 1063 1064 ip netns del "${test_netns}" 1065} 1066 1067test_vrf_or_ksft_skip() 1068{ 1069 modprobe vrf &>/dev/null || true 1070 if [ ! -e /proc/sys/net/vrf/strict_mode ]; then 1071 echo "SKIP: vrf sysctl does not exist" 1072 exit "${ksft_skip}" 1073 fi 1074} 1075 1076if [ "$(id -u)" -ne 0 ]; then 1077 echo "SKIP: Need root privileges" 1078 exit "${ksft_skip}" 1079fi 1080 1081# required programs to carry out this selftest 1082test_command_or_ksft_skip ip 1083test_command_or_ksft_skip ping 1084test_command_or_ksft_skip sysctl 1085test_command_or_ksft_skip grep 1086test_command_or_ksft_skip cut 1087 1088test_iproute2_supp_or_ksft_skip 1089test_dummy_dev_or_ksft_skip 1090test_vrf_or_ksft_skip 1091 1092set -e 1093trap cleanup EXIT 1094 1095setup 1096set +e 1097 1098csid_container_cfg_tests 1099 1100router_tests 1101host2gateway_tests 1102host_vpn_tests 1103 1104print_log_test_results 1105