brintos

brintos / linux-shallow public Read only

0
0
Text · 32.5 KiB · 87e414c Raw
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