File Index
Files and directories
Sign in
FILE

srv6_end_x_next_csid_l3vpn_test.sh

File preview with syntax highlighting.

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