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