1146 lines · bash
1#!/bin/bash2# SPDX-License-Identifier: GPL-2.03#4# author: Andrea Mayer <andrea.mayer@uniroma2.it>5#6# This script is designed for testing the support of NEXT-C-SID flavor for SRv67# End behavior.8# A basic knowledge of SRv6 architecture [1] and of the compressed SID approach9# [2] is assumed for the reader.10#11# The network topology used in the selftest is depicted hereafter, composed by12# two hosts and four routers. Hosts hs-1 and hs-2 are connected through an13# IPv4/IPv6 L3 VPN service, offered by routers rt-1, rt-2, rt-3 and rt-4 using14# 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 on17# traffic received by connected hosts, initiating the VPN tunnel;18#19# ii) The SRv6 End behavior [1] advances the active SID in the SID List20# carried by the SRH;21#22# iii) The NEXT-C-SID mechanism [2] offers the possibility of encoding several23# SRv6 segments within a single 128-bit SID address, referred to as a24# Compressed SID (C-SID) container. In this way, the length of the SID25# List can be drastically reduced.26# The NEXT-C-SID is provided as a "flavor" of the SRv6 End behavior27# which advances the current C-SID (i.e. the Locator-Node Function defined28# 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 behavior30# 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 of34# handling, at the same time, both tunneled IPv4 and IPv6 traffic.35#36# [1] https://datatracker.ietf.org/doc/html/rfc898637# [2] https://datatracker.ietf.org/doc/html/draft-ietf-spring-srv6-srh-compression38#39#40# cafe::1 cafe::241# 10.0.0.1 10.0.0.242# +--------+ +--------+43# | | | |44# | hs-1 | | hs-2 |45# | | | |46# +---+----+ +----+---+47# cafe::/64 | | cafe::/6448# 10.0.0.0/24 | | 10.0.0.0/2449# +---+----+ +----+---+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::/6459# | . . |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 in70# the selftest network.71#72# Local SID/C-SID table73# =====================74#75# Each SRv6 router is configured with a Local SID/C-SID table in which76# SIDs/C-SIDs are stored. Considering an SRv6 router rt-x, SIDs/C-SIDs are77# configured in the Local SID/C-SIDs table as follows:78#79# Local SID/C-SID table for SRv6 router rt-x80# +-----------------------------------------------------------+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 regular92# (non compressed) SIDs. Reachability of SIDs is ensured by proper configuration93# of the IPv6 routing tables in the routers.94# Similarly, the fcbb:0::/32 prefix is reserved for implementing SRv6 VPN95# services leveraging the NEXT-C-SID compression mechanism. Indeed, the96# fcbb:0::/32 is used for encoding the Locator-Block while the Locator-Node97# Function is encoded with 16 bits.98#99# Incoming traffic classification and application of SRv6 Policies100# ================================================================101#102# An SRv6 ingress router applies different SRv6 Policies to the traffic received103# from a connected host, considering the IPv4 or IPv6 destination address.104# SRv6 policy enforcement consists of encapsulating the received traffic into a105# 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 completely107# and that SID is stored directly in the IPv6 Destination Address (DA) (this is108# called "reduced" encapsulation).109#110# Test cases for NEXT-C-SID111# =========================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 all116# contained in a single Compressed SID (C-SID) container. Therefore the117# resulting SID List has only one SID. Using the reduced encapsulation format118# 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 SID121# (C-SID) container, followed by a regular (non compressed) SID. The resulting122# SID List has two segments and it is possible to test the advance to the next123# SID when all the C-SIDs in a C-SID container have been processed. Using the124# reduced encapsulation format this will result in a packet with an SRH125# containing 1 segment.126#127# For the single SID test case, we use the IPv4 addresses of hs-1 and hs-2, for128# the double SID test case, we use their IPv6 addresses. This is only done to129# simplify the test setup and avoid adding other hosts or multiple addresses on130# the same interface of a host.131#132# Traffic from hs-1 to hs-2133# -------------------------134#135# Packets generated from hs-1 and directed towards hs-2 are handled by rt-1136# 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::d46140#141# ### i) single SID142#143# The router rt-1 is configured to enforce the given Policy through the SRv6144# H.Encaps.Red behavior which avoids the presence of the SRH at all, since it145# pushes the single SID directly in the IPv6 DA. Such a SID encodes a whole146# 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 End149# behavior (associated with fcbb:0:0400::/48) is triggered. This behavior150# analyzes the IPv6 DA and checks whether the Argument of the C-SID container151# is zero or not. In this case, the Argument is *NOT* zero and the IPv6 DA is152# 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 is175# 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 is178# received. This behavior processes the packet and updates the IPv6 DA with179# fcbb:0:0200:d46::, since the Argument is *NOT* zero. Then, the packet is sent180# 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 received184# packet. It is worth noting that the SRv6 End.DT46 behavior does not require185# the presence of the SRH: it is fully capable to operate properly on186# IPv4/IPv6-in-IPv6 encapsulations.187# At the end of the decap operation, the packet is sent to the188# host hs-2.189#190# ### ii) double SID191#192# The router rt-1 is configured to enforce the given Policy through the SRv6193# H.Encaps.Red. As a result, the first SID fcbb:0:0300:: is stored into the194# 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 an196# outer IPv6 header plus the SRH.197#198# As the packet reaches the node rt-3, the router applies the enabled NEXT-C-SID199# 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 not221# update the Locator-Node function with the next C-SID carried in the Argument222# itself. Thus, the enabled NEXT-C-SID SRv6 End behavior operates as the223# traditional End behavior: it updates the IPv6 DA by copying the next224# available SID in the SID List carried by the SRH. After that, the packet is225# sent to the node rt-2.226#227# Once the packet is received by rt-2, the router decapsulates the inner IPv6228# 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-1232# -------------------------233#234# Packets generated from hs-2 and directed towards hs-1 are handled by rt-2235# 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::d46239#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 same242# 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 from244# hs-1 to hs-2. So, the traffic processing scheme turns out to be the same as245# that adopted in the use cases already examined (of course, it is necessary to246# consider the different SIDs/C-SIDs).247 248# Kselftest framework requirement - SKIP code is 4.249readonly ksft_skip=4250 251readonly RDMSUFF="$(mktemp -u XXXXXXXX)"252readonly DUMMY_DEVNAME="dum0"253readonly VRF_TID=100254readonly VRF_DEVNAME="vrf-${VRF_TID}"255readonly RT2HS_DEVNAME="veth-t${VRF_TID}"256readonly LOCALSID_TABLE_ID=90257readonly IPv6_RT_NETWORK=fcf0:0258readonly IPv6_HS_NETWORK=cafe259readonly IPv4_HS_NETWORK=10.0.0260readonly VPN_LOCATOR_SERVICE=fcff261readonly DT46_FUNC=0d46262readonly HEADEND_ENCAP="encap.red"263 264# do not add ':' as separator265readonly LCBLOCK_ADDR=fcbb0000266readonly LCBLOCK_BLEN=32267# do not add ':' as separator268readonly LCNODEFUNC_FMT="0%d00"269readonly LCNODEFUNC_BLEN=16270 271readonly LCBLOCK_NODEFUNC_BLEN=$((LCBLOCK_BLEN + LCNODEFUNC_BLEN))272 273readonly CSID_CNTR_PREFIX="dead:beaf::/32"274# ID of the router used for testing the C-SID container cfgs275readonly CSID_CNTR_RT_ID_TEST=1276# Routing table used for testing the C-SID container cfgs277readonly CSID_CNTR_RT_TABLE=91278 279# C-SID container configurations to be tested280#281# An entry of the array is defined as "a,b,c" where:282# - 'a' and 'b' elements represent respectively the Locator-Block length283# (lblen) in bits and the Locator-Node Function length (nflen) in bits.284# 'a' and 'b' can be set to default values using the placeholder "d" which285# indicates the default kernel values (32 for lblen and 16 for nflen);286# otherwise, any numeric value is accepted;287# - 'c' indicates whether the C-SID configuration provided by the values 'a'288# and 'b' should be considered valid ("y") or invalid ("n").289declare -ra CSID_CONTAINER_CFGS=(290 "d,d,y"291 "d,16,y"292 "16,d,y"293 "16,32,y"294 "32,16,y"295 "48,8,y"296 "8,48,y"297 "d,0,n"298 "0,d,n"299 "32,0,n"300 "0,32,n"301 "17,d,n"302 "d,17,n"303 "120,16,n"304 "16,120,n"305 "0,128,n"306 "128,0,n"307 "130,0,n"308 "0,130,n"309 "0,0,n"310)311 312PING_TIMEOUT_SEC=4313PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}314 315# IDs of routers and hosts are initialized during the setup of the testing316# network317ROUTERS=''318HOSTS=''319 320SETUP_ERR=1321 322ret=${ksft_skip}323nsuccess=0324nfail=0325 326log_test()327{328 local rc="$1"329 local expected="$2"330 local msg="$3"331 332 if [ "${rc}" -eq "${expected}" ]; then333 nsuccess=$((nsuccess+1))334 printf "\n TEST: %-60s [ OK ]\n" "${msg}"335 else336 ret=1337 nfail=$((nfail+1))338 printf "\n TEST: %-60s [FAIL]\n" "${msg}"339 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then340 echo341 echo "hit enter to continue, 'q' to quit"342 read a343 [ "$a" = "q" ] && exit 1344 fi345 fi346}347 348print_log_test_results()349{350 printf "\nTests passed: %3d\n" "${nsuccess}"351 printf "Tests failed: %3d\n" "${nfail}"352 353 # when a test fails, the value of 'ret' is set to 1 (error code).354 # Conversely, when all tests are passed successfully, the 'ret' value355 # is set to 0 (success code).356 if [ "${ret}" -ne 1 ]; then357 ret=0358 fi359}360 361log_section()362{363 echo364 echo "################################################################################"365 echo "TEST SECTION: $*"366 echo "################################################################################"367}368 369test_command_or_ksft_skip()370{371 local cmd="$1"372 373 if [ ! -x "$(command -v "${cmd}")" ]; then374 echo "SKIP: Could not run test without \"${cmd}\" tool";375 exit "${ksft_skip}"376 fi377}378 379get_nodename()380{381 local name="$1"382 383 echo "${name}-${RDMSUFF}"384}385 386get_rtname()387{388 local rtid="$1"389 390 get_nodename "rt-${rtid}"391}392 393get_hsname()394{395 local hsid="$1"396 397 get_nodename "hs-${hsid}"398}399 400__create_namespace()401{402 local name="$1"403 404 ip netns add "${name}"405}406 407create_router()408{409 local rtid="$1"410 local nsname411 412 nsname="$(get_rtname "${rtid}")"413 414 __create_namespace "${nsname}"415}416 417create_host()418{419 local hsid="$1"420 local nsname421 422 nsname="$(get_hsname "${hsid}")"423 424 __create_namespace "${nsname}"425}426 427cleanup()428{429 local nsname430 local i431 432 # destroy routers433 for i in ${ROUTERS}; do434 nsname="$(get_rtname "${i}")"435 436 ip netns del "${nsname}" &>/dev/null || true437 done438 439 # destroy hosts440 for i in ${HOSTS}; do441 nsname="$(get_hsname "${i}")"442 443 ip netns del "${nsname}" &>/dev/null || true444 done445 446 # check whether the setup phase was completed successfully or not. In447 # case of an error during the setup phase of the testing environment,448 # the selftest is considered as "skipped".449 if [ "${SETUP_ERR}" -ne 0 ]; then450 echo "SKIP: Setting up the testing environment failed"451 exit "${ksft_skip}"452 fi453 454 exit "${ret}"455}456 457add_link_rt_pairs()458{459 local rt="$1"460 local rt_neighs="$2"461 local neigh462 local nsname463 local neigh_nsname464 465 nsname="$(get_rtname "${rt}")"466 467 for neigh in ${rt_neighs}; do468 neigh_nsname="$(get_rtname "${neigh}")"469 470 ip link add "veth-rt-${rt}-${neigh}" netns "${nsname}" \471 type veth peer name "veth-rt-${neigh}-${rt}" \472 netns "${neigh_nsname}"473 done474}475 476get_network_prefix()477{478 local rt="$1"479 local neigh="$2"480 local p="${rt}"481 local q="${neigh}"482 483 if [ "${p}" -gt "${q}" ]; then484 p="${q}"; q="${rt}"485 fi486 487 echo "${IPv6_RT_NETWORK}:${p}:${q}"488}489 490# Setup the basic networking for the routers491setup_rt_networking()492{493 local rt="$1"494 local rt_neighs="$2"495 local nsname496 local net_prefix497 local devname498 local neigh499 500 nsname="$(get_rtname "${rt}")"501 502 for neigh in ${rt_neighs}; do503 devname="veth-rt-${rt}-${neigh}"504 505 net_prefix="$(get_network_prefix "${rt}" "${neigh}")"506 507 ip -netns "${nsname}" addr \508 add "${net_prefix}::${rt}/64" dev "${devname}" nodad509 510 ip -netns "${nsname}" link set "${devname}" up511 done512 513 ip -netns "${nsname}" link add "${DUMMY_DEVNAME}" type dummy514 515 ip -netns "${nsname}" link set "${DUMMY_DEVNAME}" up516 ip -netns "${nsname}" link set lo up517 518 ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0519 ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0520 ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.forwarding=1521 522 ip netns exec "${nsname}" sysctl -wq net.ipv4.conf.all.rp_filter=0523 ip netns exec "${nsname}" sysctl -wq net.ipv4.conf.default.rp_filter=0524 ip netns exec "${nsname}" sysctl -wq net.ipv4.ip_forward=1525}526 527# build an ipv6 prefix/address based on the input string528# Note that the input string does not contain ':' and '::' which are considered529# to be implicit.530# e.g.:531# - input: fbcc00000400300532# - output: fbcc:0000:0400:0300:0000:0000:0000:0000533# ^^^^^^^^^^^^^^^^^^^534# fill the address with 0s535build_ipv6_addr()536{537 local addr="$1"538 local out=""539 local strlen="${#addr}"540 local padn541 local i542 543 # add ":" every 4 digits (16 bits)544 for (( i = 0; i < strlen; i++ )); do545 if (( i > 0 && i < 32 && (i % 4) == 0 )); then546 out="${out}:"547 fi548 549 out="${out}${addr:$i:1}"550 done551 552 # fill the remaining bits of the address with 0s553 padn=$((32 - strlen))554 for (( i = padn; i > 0; i-- )); do555 if (( i > 0 && i < 32 && (i % 4) == 0 )); then556 out="${out}:"557 fi558 559 out="${out}0"560 done561 562 printf "${out}"563}564 565build_csid()566{567 local nodeid="$1"568 569 printf "${LCNODEFUNC_FMT}" "${nodeid}"570}571 572build_lcnode_func_prefix()573{574 local nodeid="$1"575 local lcnodefunc576 local prefix577 local out578 579 lcnodefunc="$(build_csid "${nodeid}")"580 prefix="$(build_ipv6_addr "${LCBLOCK_ADDR}${lcnodefunc}")"581 582 out="${prefix}/${LCBLOCK_NODEFUNC_BLEN}"583 584 echo "${out}"585}586 587# Setup local SIDs for an SRv6 router588setup_rt_local_sids()589{590 local rt="$1"591 local rt_neighs="$2"592 local net_prefix593 local devname594 local nsname595 local neigh596 local lcnode_func_prefix597 local lcblock_prefix598 599 nsname="$(get_rtname "${rt}")"600 601 for neigh in ${rt_neighs}; do602 devname="veth-rt-${rt}-${neigh}"603 604 net_prefix="$(get_network_prefix "${rt}" "${neigh}")"605 606 # set underlay network routes for SIDs reachability607 ip -netns "${nsname}" -6 route \608 add "${VPN_LOCATOR_SERVICE}:${neigh}::/32" \609 table "${LOCALSID_TABLE_ID}" \610 via "${net_prefix}::${neigh}" dev "${devname}"611 612 # set the underlay network for C-SIDs reachability613 lcnode_func_prefix="$(build_lcnode_func_prefix "${neigh}")"614 615 ip -netns "${nsname}" -6 route \616 add "${lcnode_func_prefix}" \617 table "${LOCALSID_TABLE_ID}" \618 via "${net_prefix}::${neigh}" dev "${devname}"619 done620 621 lcnode_func_prefix="$(build_lcnode_func_prefix "${rt}")"622 623 # enabled NEXT-C-SID SRv6 End behavior (note that "dev" is the dummy624 # dum0 device chosen for the sake of simplicity).625 ip -netns "${nsname}" -6 route \626 add "${lcnode_func_prefix}" \627 table "${LOCALSID_TABLE_ID}" \628 encap seg6local action End flavors next-csid \629 lblen "${LCBLOCK_BLEN}" nflen "${LCNODEFUNC_BLEN}" \630 dev "${DUMMY_DEVNAME}"631 632 # all SIDs for VPNs start with a common locator. Routes and SRv6633 # Endpoint behavior instaces are grouped together in the 'localsid'634 # table.635 ip -netns "${nsname}" -6 rule \636 add to "${VPN_LOCATOR_SERVICE}::/16" \637 lookup "${LOCALSID_TABLE_ID}" prio 999638 639 # common locator block for NEXT-C-SIDS compression mechanism.640 lcblock_prefix="$(build_ipv6_addr "${LCBLOCK_ADDR}")"641 ip -netns "${nsname}" -6 rule \642 add to "${lcblock_prefix}/${LCBLOCK_BLEN}" \643 lookup "${LOCALSID_TABLE_ID}" prio 999644}645 646# build and install the SRv6 policy into the ingress SRv6 router as well as the647# decap SID in the egress one.648# args:649# $1 - src host (evaluate automatically the ingress router)650# $2 - dst host (evaluate automatically the egress router)651# $3 - SRv6 routers configured for steering traffic (End behaviors)652# $4 - single SID or double SID653# $5 - traffic type (IPv6 or IPv4)654__setup_l3vpn()655{656 local src="$1"657 local dst="$2"658 local end_rts="$3"659 local mode="$4"660 local traffic="$5"661 local nsname662 local policy663 local container664 local decapsid665 local lcnfunc666 local dt667 local n668 local rtsrc_nsname669 local rtdst_nsname670 671 rtsrc_nsname="$(get_rtname "${src}")"672 rtdst_nsname="$(get_rtname "${dst}")"673 674 container="${LCBLOCK_ADDR}"675 676 # build first SID (C-SID container)677 for n in ${end_rts}; do678 lcnfunc="$(build_csid "${n}")"679 680 container="${container}${lcnfunc}"681 done682 683 if [ "${mode}" -eq 1 ]; then684 # single SID policy685 dt="$(build_csid "${dst}")${DT46_FUNC}"686 container="${container}${dt}"687 # build the full ipv6 address for the container688 policy="$(build_ipv6_addr "${container}")"689 690 # build the decap SID used in the decap node691 container="${LCBLOCK_ADDR}${dt}"692 decapsid="$(build_ipv6_addr "${container}")"693 else694 # double SID policy695 decapsid="${VPN_LOCATOR_SERVICE}:${dst}::${DT46_FUNC}"696 697 policy="$(build_ipv6_addr "${container}"),${decapsid}"698 fi699 700 # apply encap policy701 if [ "${traffic}" -eq 6 ]; then702 ip -netns "${rtsrc_nsname}" -6 route \703 add "${IPv6_HS_NETWORK}::${dst}" vrf "${VRF_DEVNAME}" \704 encap seg6 mode "${HEADEND_ENCAP}" segs "${policy}" \705 dev "${VRF_DEVNAME}"706 707 ip -netns "${rtsrc_nsname}" -6 neigh \708 add proxy "${IPv6_HS_NETWORK}::${dst}" \709 dev "${RT2HS_DEVNAME}"710 else711 # "dev" must be different from the one where the packet is712 # received, otherwise the proxy arp does not work.713 ip -netns "${rtsrc_nsname}" -4 route \714 add "${IPv4_HS_NETWORK}.${dst}" vrf "${VRF_DEVNAME}" \715 encap seg6 mode "${HEADEND_ENCAP}" segs "${policy}" \716 dev "${VRF_DEVNAME}"717 fi718 719 # apply decap720 # Local End.DT46 behavior (decap)721 ip -netns "${rtdst_nsname}" -6 route \722 add "${decapsid}" \723 table "${LOCALSID_TABLE_ID}" \724 encap seg6local action End.DT46 vrftable "${VRF_TID}" \725 dev "${VRF_DEVNAME}"726}727 728# see __setup_l3vpn()729setup_ipv4_vpn_2sids()730{731 __setup_l3vpn "$1" "$2" "$3" 2 4732}733 734# see __setup_l3vpn()735setup_ipv6_vpn_1sid()736{737 __setup_l3vpn "$1" "$2" "$3" 1 6738}739 740setup_hs()741{742 local hs="$1"743 local rt="$2"744 local hsname745 local rtname746 747 hsname="$(get_hsname "${hs}")"748 rtname="$(get_rtname "${rt}")"749 750 ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0751 ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0752 753 ip -netns "${hsname}" link add veth0 type veth \754 peer name "${RT2HS_DEVNAME}" netns "${rtname}"755 756 ip -netns "${hsname}" addr \757 add "${IPv6_HS_NETWORK}::${hs}/64" dev veth0 nodad758 ip -netns "${hsname}" addr add "${IPv4_HS_NETWORK}.${hs}/24" dev veth0759 760 ip -netns "${hsname}" link set veth0 up761 ip -netns "${hsname}" link set lo up762 763 # configure the VRF on the router which is directly connected to the764 # source host.765 ip -netns "${rtname}" link \766 add "${VRF_DEVNAME}" type vrf table "${VRF_TID}"767 ip -netns "${rtname}" link set "${VRF_DEVNAME}" up768 769 # enslave the veth interface connecting the router with the host to the770 # VRF in the access router771 ip -netns "${rtname}" link \772 set "${RT2HS_DEVNAME}" master "${VRF_DEVNAME}"773 774 # set default routes to unreachable for both ipv6 and ipv4775 ip -netns "${rtname}" -6 route \776 add unreachable default metric 4278198272 \777 vrf "${VRF_DEVNAME}"778 ip -netns "${rtname}" -4 route \779 add unreachable default metric 4278198272 \780 vrf "${VRF_DEVNAME}"781 782 ip -netns "${rtname}" addr \783 add "${IPv6_HS_NETWORK}::254/64" dev "${RT2HS_DEVNAME}" nodad784 ip -netns "${rtname}" addr \785 add "${IPv4_HS_NETWORK}.254/24" dev "${RT2HS_DEVNAME}"786 787 ip -netns "${rtname}" link set "${RT2HS_DEVNAME}" up788 789 ip netns exec "${rtname}" \790 sysctl -wq net.ipv6.conf."${RT2HS_DEVNAME}".proxy_ndp=1791 ip netns exec "${rtname}" \792 sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".proxy_arp=1793 794 # disable the rp_filter otherwise the kernel gets confused about how795 # to route decap ipv4 packets.796 ip netns exec "${rtname}" \797 sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".rp_filter=0798 799 ip netns exec "${rtname}" sh -c "echo 1 > /proc/sys/net/vrf/strict_mode"800}801 802setup()803{804 local i805 806 # create routers807 ROUTERS="1 2 3 4"; readonly ROUTERS808 for i in ${ROUTERS}; do809 create_router "${i}"810 done811 812 # create hosts813 HOSTS="1 2"; readonly HOSTS814 for i in ${HOSTS}; do815 create_host "${i}"816 done817 818 # set up the links for connecting routers819 add_link_rt_pairs 1 "2 3 4"820 add_link_rt_pairs 2 "3 4"821 add_link_rt_pairs 3 "4"822 823 # set up the basic connectivity of routers and routes required for824 # reachability of SIDs.825 setup_rt_networking 1 "2 3 4"826 setup_rt_networking 2 "1 3 4"827 setup_rt_networking 3 "1 2 4"828 setup_rt_networking 4 "1 2 3"829 830 # set up the hosts connected to routers831 setup_hs 1 1832 setup_hs 2 2833 834 # set up default SRv6 Endpoints (i.e. SRv6 End and SRv6 End.DT46)835 setup_rt_local_sids 1 "2 3 4"836 setup_rt_local_sids 2 "1 3 4"837 setup_rt_local_sids 3 "1 2 4"838 setup_rt_local_sids 4 "1 2 3"839 840 # set up SRv6 Policies841 842 # create an IPv6 VPN between hosts hs-1 and hs-2.843 #844 # Direction hs-1 -> hs-2845 # - rt-1 encap (H.Encaps.Red)846 # - rt-4 SRv6 End behavior (NEXT-C-SID flavor)847 # - rt-3 SRv6 End behavior (NEXT-C-SID flavor)848 # - rt-2 SRv6 End.DT46 behavior849 setup_ipv6_vpn_1sid 1 2 "4 3"850 851 # Direction hs2 -> hs-1852 # - rt-2 encap (H.Encaps.Red)853 # - rt-3 SRv6 End behavior (NEXT-C-SID flavor)854 # - rt-4 SRv6 End behavior (NEXT-C-SID flavor)855 # - rt-1 SRv6 End.DT46 behavior856 setup_ipv6_vpn_1sid 2 1 "3 4"857 858 # create an IPv4 VPN between hosts hs-1 and hs-2859 #860 # Direction hs-1 -> hs-2861 # - rt-1 encap (H.Encaps.Red)862 # - rt-3 SRv6 End behavior (NEXT-C-SID flavor)863 # - rt-2 SRv6 End.DT46 behavior864 setup_ipv4_vpn_2sids 1 2 "3"865 866 # Direction hs-2 -> hs-1867 # - rt-2 encap (H.Encaps.Red)868 # - rt-3 SRv6 End behavior (NEXT-C-SID flavor)869 # - rt-1 SRv6 End.DT46 behavior870 setup_ipv4_vpn_2sids 2 1 "3"871 872 # testing environment was set up successfully873 SETUP_ERR=0874}875 876check_rt_connectivity()877{878 local rtsrc="$1"879 local rtdst="$2"880 local prefix881 local rtsrc_nsname882 883 rtsrc_nsname="$(get_rtname "${rtsrc}")"884 885 prefix="$(get_network_prefix "${rtsrc}" "${rtdst}")"886 887 ip netns exec "${rtsrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \888 "${prefix}::${rtdst}" >/dev/null 2>&1889}890 891check_and_log_rt_connectivity()892{893 local rtsrc="$1"894 local rtdst="$2"895 896 check_rt_connectivity "${rtsrc}" "${rtdst}"897 log_test $? 0 "Routers connectivity: rt-${rtsrc} -> rt-${rtdst}"898}899 900check_hs_ipv6_connectivity()901{902 local hssrc="$1"903 local hsdst="$2"904 local hssrc_nsname905 906 hssrc_nsname="$(get_hsname "${hssrc}")"907 908 ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \909 "${IPv6_HS_NETWORK}::${hsdst}" >/dev/null 2>&1910}911 912check_hs_ipv4_connectivity()913{914 local hssrc="$1"915 local hsdst="$2"916 local hssrc_nsname917 918 hssrc_nsname="$(get_hsname "${hssrc}")"919 920 ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \921 "${IPv4_HS_NETWORK}.${hsdst}" >/dev/null 2>&1922}923 924check_and_log_hs2gw_connectivity()925{926 local hssrc="$1"927 928 check_hs_ipv6_connectivity "${hssrc}" 254929 log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> gw"930 931 check_hs_ipv4_connectivity "${hssrc}" 254932 log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> gw"933}934 935check_and_log_hs_ipv6_connectivity()936{937 local hssrc="$1"938 local hsdst="$2"939 940 check_hs_ipv6_connectivity "${hssrc}" "${hsdst}"941 log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"942}943 944check_and_log_hs_ipv4_connectivity()945{946 local hssrc="$1"947 local hsdst="$2"948 949 check_hs_ipv4_connectivity "${hssrc}" "${hsdst}"950 log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"951}952 953router_tests()954{955 local i956 local j957 958 log_section "IPv6 routers connectivity test"959 960 for i in ${ROUTERS}; do961 for j in ${ROUTERS}; do962 if [ "${i}" -eq "${j}" ]; then963 continue964 fi965 966 check_and_log_rt_connectivity "${i}" "${j}"967 done968 done969}970 971host2gateway_tests()972{973 local hs974 975 log_section "IPv4/IPv6 connectivity test among hosts and gateways"976 977 for hs in ${HOSTS}; do978 check_and_log_hs2gw_connectivity "${hs}"979 done980}981 982host_vpn_tests()983{984 log_section "SRv6 VPN connectivity test hosts (h1 <-> h2, IPv6)"985 986 check_and_log_hs_ipv6_connectivity 1 2987 check_and_log_hs_ipv6_connectivity 2 1988 989 log_section "SRv6 VPN connectivity test hosts (h1 <-> h2, IPv4)"990 991 check_and_log_hs_ipv4_connectivity 1 2992 check_and_log_hs_ipv4_connectivity 2 1993}994 995__nextcsid_end_behavior_test()996{997 local nsname="$1"998 local cmd="$2"999 local blen="$3"1000 local flen="$4"1001 local layout=""1002 1003 if [ "${blen}" != "d" ]; then1004 layout="${layout} lblen ${blen}"1005 fi1006 1007 if [ "${flen}" != "d" ]; then1008 layout="${layout} nflen ${flen}"1009 fi1010 1011 ip -netns "${nsname}" -6 route \1012 "${cmd}" "${CSID_CNTR_PREFIX}" \1013 table "${CSID_CNTR_RT_TABLE}" \1014 encap seg6local action End flavors next-csid ${layout} \1015 dev "${DUMMY_DEVNAME}" &>/dev/null1016 1017 return "$?"1018}1019 1020rt_x_nextcsid_end_behavior_test()1021{1022 local rt="$1"1023 local blen="$2"1024 local flen="$3"1025 local nsname1026 local ret1027 1028 nsname="$(get_rtname "${rt}")"1029 1030 __nextcsid_end_behavior_test "${nsname}" "add" "${blen}" "${flen}"1031 ret="$?"1032 __nextcsid_end_behavior_test "${nsname}" "del" "${blen}" "${flen}"1033 1034 return "${ret}"1035}1036 1037__parse_csid_container_cfg()1038{1039 local cfg="$1"1040 local index="$2"1041 local out1042 1043 echo "${cfg}" | cut -d',' -f"${index}"1044}1045 1046csid_container_cfg_tests()1047{1048 local valid1049 local blen1050 local flen1051 local cfg1052 local ret1053 1054 log_section "C-SID Container config tests (legend: d='kernel default')"1055 1056 for cfg in "${CSID_CONTAINER_CFGS[@]}"; do1057 blen="$(__parse_csid_container_cfg "${cfg}" 1)"1058 flen="$(__parse_csid_container_cfg "${cfg}" 2)"1059 valid="$(__parse_csid_container_cfg "${cfg}" 3)"1060 1061 rt_x_nextcsid_end_behavior_test \1062 "${CSID_CNTR_RT_ID_TEST}" \1063 "${blen}" \1064 "${flen}"1065 ret="$?"1066 1067 if [ "${valid}" == "y" ]; then1068 log_test "${ret}" 0 \1069 "Accept valid C-SID container cfg (lblen=${blen}, nflen=${flen})"1070 else1071 log_test "${ret}" 2 \1072 "Reject invalid C-SID container cfg (lblen=${blen}, nflen=${flen})"1073 fi1074 done1075}1076 1077test_iproute2_supp_or_ksft_skip()1078{1079 if ! ip route help 2>&1 | grep -qo "next-csid"; then1080 echo "SKIP: Missing SRv6 NEXT-C-SID flavor support in iproute2"1081 exit "${ksft_skip}"1082 fi1083}1084 1085test_dummy_dev_or_ksft_skip()1086{1087 local test_netns1088 1089 test_netns="dummy-$(mktemp -u XXXXXXXX)"1090 1091 if ! ip netns add "${test_netns}"; then1092 echo "SKIP: Cannot set up netns for testing dummy dev support"1093 exit "${ksft_skip}"1094 fi1095 1096 modprobe dummy &>/dev/null || true1097 if ! ip -netns "${test_netns}" link \1098 add "${DUMMY_DEVNAME}" type dummy; then1099 echo "SKIP: dummy dev not supported"1100 1101 ip netns del "${test_netns}"1102 exit "${ksft_skip}"1103 fi1104 1105 ip netns del "${test_netns}"1106}1107 1108test_vrf_or_ksft_skip()1109{1110 modprobe vrf &>/dev/null || true1111 if [ ! -e /proc/sys/net/vrf/strict_mode ]; then1112 echo "SKIP: vrf sysctl does not exist"1113 exit "${ksft_skip}"1114 fi1115}1116 1117if [ "$(id -u)" -ne 0 ]; then1118 echo "SKIP: Need root privileges"1119 exit "${ksft_skip}"1120fi1121 1122# required programs to carry out this selftest1123test_command_or_ksft_skip ip1124test_command_or_ksft_skip ping1125test_command_or_ksft_skip sysctl1126test_command_or_ksft_skip grep1127test_command_or_ksft_skip cut1128 1129test_iproute2_supp_or_ksft_skip1130test_dummy_dev_or_ksft_skip1131test_vrf_or_ksft_skip1132 1133set -e1134trap cleanup EXIT1135 1136setup1137set +e1138 1139csid_container_cfg_tests1140 1141router_tests1142host2gateway_tests1143host_vpn_tests1144 1145print_log_test_results1146