1214 lines
36 KiB
Bash
Executable File
1214 lines
36 KiB
Bash
Executable File
#!/bin/bash
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
#
|
|
# author: Andrea Mayer <andrea.mayer@uniroma2.it>
|
|
# author: Paolo Lungaroni <paolo.lungaroni@uniroma2.it>
|
|
#
|
|
# This script is designed for testing the support of NEXT-C-SID flavor for SRv6
|
|
# End.X behavior.
|
|
# A basic knowledge of SRv6 architecture [1] and of the compressed SID approach
|
|
# [2] is assumed for the reader.
|
|
#
|
|
# The network topology used in the selftest is depicted hereafter, composed of
|
|
# two hosts and four routers. Hosts hs-1 and hs-2 are connected through an
|
|
# IPv4/IPv6 L3 VPN service, offered by routers rt-1, rt-2, rt-3 and rt-4 using
|
|
# the NEXT-C-SID flavor. The key components for such VPNs are:
|
|
#
|
|
# i) The SRv6 H.Encaps/H.Encaps.Red behaviors [1] apply SRv6 Policies on
|
|
# traffic received by connected hosts, initiating the VPN tunnel;
|
|
#
|
|
# ii) The SRv6 End.X behavior [1] (Endpoint with L3 cross connect) is a
|
|
# variant of SRv6 End behavior. It advances the active SID in the SID
|
|
# List carried by the SRH and forwards the packet to an L3 adjacency;
|
|
#
|
|
# iii) The NEXT-C-SID mechanism [2] offers the possibility of encoding several
|
|
# SRv6 segments within a single 128-bit SID address, referred to as a
|
|
# Compressed SID (C-SID) container. In this way, the length of the SID
|
|
# List can be drastically reduced.
|
|
# The NEXT-C-SID is provided as a "flavor" of the SRv6 End.X behavior
|
|
# which advances the current C-SID (i.e. the Locator-Node Function defined
|
|
# in [2]) with the next one carried in the Argument, if available.
|
|
# When no more C-SIDs are available in the Argument, the SRv6 End.X
|
|
# behavior will apply the End.X function selecting the next SID in the SID
|
|
# List;
|
|
#
|
|
# iv) The SRv6 End.DT46 behavior [1] is used for removing the SRv6 Policy and,
|
|
# thus, it terminates the VPN tunnel. Such a behavior is capable of
|
|
# handling, at the same time, both tunneled IPv4 and IPv6 traffic.
|
|
#
|
|
# [1] https://datatracker.ietf.org/doc/html/rfc8986
|
|
# [2] https://datatracker.ietf.org/doc/html/draft-ietf-spring-srv6-srh-compression
|
|
#
|
|
#
|
|
# cafe::1 cafe::2
|
|
# 10.0.0.1 10.0.0.2
|
|
# +--------+ +--------+
|
|
# | | | |
|
|
# | hs-1 | | hs-2 |
|
|
# | | | |
|
|
# +---+----+ +----+---+
|
|
# cafe::/64 | | cafe::/64
|
|
# 10.0.0.0/24 | | 10.0.0.0/24
|
|
# +---+----+ +----+---+
|
|
# | | fcf0:0:1:2::/64 | |
|
|
# | rt-1 +-------------------+ rt-2 |
|
|
# | | | |
|
|
# +---+----+ +----+---+
|
|
# | . . |
|
|
# | fcf0:0:1:3::/64 . |
|
|
# | . . |
|
|
# | . . |
|
|
# fcf0:0:1:4::/64 | . | fcf0:0:2:3::/64
|
|
# | . . |
|
|
# | . . |
|
|
# | fcf0:0:2:4::/64 . |
|
|
# | . . |
|
|
# +---+----+ +----+---+
|
|
# | | | |
|
|
# | rt-4 +-------------------+ rt-3 |
|
|
# | | fcf0:0:3:4::/64 | |
|
|
# +---+----+ +----+---+
|
|
#
|
|
# Every fcf0:0:x:y::/64 network interconnects the SRv6 routers rt-x with rt-y in
|
|
# the selftest network.
|
|
#
|
|
# Local SID/C-SID table
|
|
# =====================
|
|
#
|
|
# Each SRv6 router is configured with a Local SID/C-SID table in which
|
|
# SIDs/C-SIDs are stored. Considering an SRv6 router rt-x, SIDs/C-SIDs are
|
|
# configured in the Local SID/C-SIDs table as follows:
|
|
#
|
|
# Local SID/C-SID table for SRv6 router rt-x
|
|
# +-----------------------------------------------------------+
|
|
# |fcff:x::d46 is associated with the non-compressed SRv6 |
|
|
# | End.DT46 behavior |
|
|
# +-----------------------------------------------------------+
|
|
# |fcbb:0:0x00::/48 is associated with the NEXT-C-SID flavor |
|
|
# | of SRv6 End.X behavior |
|
|
# +-----------------------------------------------------------+
|
|
# |fcbb:0:0x00:d46::/64 is associated with the SRv6 End.DT46 |
|
|
# | behavior when NEXT-C-SID compression is turned on |
|
|
# +-----------------------------------------------------------+
|
|
#
|
|
# The fcff::/16 prefix is reserved for implementing SRv6 services with regular
|
|
# (non compressed) SIDs. Reachability of SIDs is ensured by proper configuration
|
|
# of the IPv6 routing tables in the routers.
|
|
# Similarly, the fcbb:0::/32 prefix is reserved for implementing SRv6 VPN
|
|
# services leveraging the NEXT-C-SID compression mechanism. Indeed, the
|
|
# fcbb:0::/32 is used for encoding the Locator-Block while the Locator-Node
|
|
# Function is encoded with 16 bits.
|
|
#
|
|
# Incoming traffic classification and application of SRv6 Policies
|
|
# ================================================================
|
|
#
|
|
# An SRv6 ingress router applies different SRv6 Policies to the traffic received
|
|
# from a connected host, considering the IPv4 or IPv6 destination address.
|
|
# SRv6 policy enforcement consists of encapsulating the received traffic into a
|
|
# new IPv6 packet with a given SID List contained in the SRH.
|
|
# When the SID List contains only one SID, the SRH could be omitted completely
|
|
# and that SID is stored directly in the IPv6 Destination Address (DA) (this is
|
|
# called "reduced" encapsulation).
|
|
#
|
|
# Test cases for NEXT-C-SID
|
|
# =========================
|
|
#
|
|
# We consider two test cases for NEXT-C-SID: i) single SID and ii) double SID.
|
|
#
|
|
# In the single SID test case we have a number of segments that are all
|
|
# contained in a single Compressed SID (C-SID) container. Therefore the
|
|
# resulting SID List has only one SID. Using the reduced encapsulation format
|
|
# this will result in a packet with no SRH.
|
|
#
|
|
# In the double SID test case we have one segment carried in a Compressed SID
|
|
# (C-SID) container, followed by a regular (non compressed) SID. The resulting
|
|
# SID List has two segments and it is possible to test the advance to the next
|
|
# SID when all the C-SIDs in a C-SID container have been processed. Using the
|
|
# reduced encapsulation format this will result in a packet with an SRH
|
|
# containing 1 segment.
|
|
#
|
|
# For the single SID test case, we use the IPv6 addresses of hs-1 and hs-2, for
|
|
# the double SID test case, we use their IPv4 addresses. This is only done to
|
|
# simplify the test setup and avoid adding other hosts or multiple addresses on
|
|
# the same interface of a host.
|
|
#
|
|
# Traffic from hs-1 to hs-2
|
|
# -------------------------
|
|
#
|
|
# Packets generated from hs-1 and directed towards hs-2 are handled by rt-1
|
|
# which applies the SRv6 Policies as follows:
|
|
#
|
|
# i) IPv6 DA=cafe::2, H.Encaps.Red with SID List=fcbb:0:0300:0200:d46::
|
|
# ii) IPv4 DA=10.0.0.2, H.Encaps.Red with SID List=fcbb:0:0300::,fcff:2::d46
|
|
#
|
|
# ### i) single SID
|
|
#
|
|
# The router rt-1 is configured to enforce the given Policy through the SRv6
|
|
# H.Encaps.Red behavior which avoids the presence of the SRH at all, since it
|
|
# pushes the single SID directly in the IPv6 DA. Such a SID encodes a whole
|
|
# C-SID container carrying several C-SIDs (e.g. 0300, 0200, etc).
|
|
#
|
|
# As the packet reaches the router rt-3, the enabled NEXT-C-SID SRv6 End.X
|
|
# behavior (associated with fcbb:0:0300::/48) is triggered. This behavior
|
|
# analyzes the IPv6 DA and checks whether the Argument of the C-SID container
|
|
# is zero or not. In this case, the Argument is *NOT* zero and the IPv6 DA is
|
|
# updated as follows:
|
|
#
|
|
# +-----------------------------------------------------------------+
|
|
# | Before applying the rt-3 enabled NEXT-C-SID SRv6 End.X behavior |
|
|
# +-----------------------------------------------------------------+
|
|
# | +---------- Argument |
|
|
# | vvvvvvvvvv |
|
|
# | IPv6 DA fcbb:0:0300:0200:d46:: |
|
|
# | ^^^^ <-- shifting |
|
|
# | | |
|
|
# | Locator-Node Function |
|
|
# +-----------------------------------------------------------------+
|
|
# | After applying the rt-3 enabled NEXT-C-SID SRv6 End.X behavior |
|
|
# +-----------------------------------------------------------------+
|
|
# | +---------- Argument |
|
|
# | vvvvvv |
|
|
# | IPv6 DA fcbb:0:0200:d46:: |
|
|
# | ^^^^ |
|
|
# | | |
|
|
# | Locator-Node Function |
|
|
# +-----------------------------------------------------------------+
|
|
#
|
|
# After having applied the enabled NEXT-C-SID SRv6 End.X behavior, the packet
|
|
# is sent to rt-4 node using the L3 adjacency address fcf0:0:3:4::4.
|
|
#
|
|
# The node rt-4 performs a plain IPv6 forward to the rt-2 router according to
|
|
# its Local SID table and using the IPv6 DA fcbb:0:0200:d46:: .
|
|
#
|
|
# The router rt-2 is configured for decapsulating the inner IPv6 packet and,
|
|
# for this reason, it applies the SRv6 End.DT46 behavior on the received
|
|
# packet. It is worth noting that the SRv6 End.DT46 behavior does not require
|
|
# the presence of the SRH: it is fully capable to operate properly on
|
|
# IPv4/IPv6-in-IPv6 encapsulations.
|
|
# At the end of the decap operation, the packet is sent to the host hs-2.
|
|
#
|
|
# ### ii) double SID
|
|
#
|
|
# The router rt-1 is configured to enforce the given Policy through the SRv6
|
|
# H.Encaps.Red. As a result, the first SID fcbb:0:0300:: is stored into the
|
|
# IPv6 DA, while the SRH pushed into the packet is made of only one SID, i.e.
|
|
# fcff:2::d46. Hence, the packet sent by hs-1 to hs-2 is encapsulated in an
|
|
# outer IPv6 header plus the SRH.
|
|
#
|
|
# As the packet reaches the node rt-3, the router applies the enabled NEXT-C-SID
|
|
# SRv6 End.X behavior.
|
|
#
|
|
# +-----------------------------------------------------------------+
|
|
# | Before applying the rt-3 enabled NEXT-C-SID SRv6 End.X behavior |
|
|
# +-----------------------------------------------------------------+
|
|
# | +---------- Argument |
|
|
# | vvvv (Argument is all filled with zeros) |
|
|
# | IPv6 DA fcbb:0:0300:: |
|
|
# | ^^^^ |
|
|
# | | |
|
|
# | Locator-Node Function |
|
|
# +-----------------------------------------------------------------+
|
|
# | After applying the rt-3 enabled NEXT-C-SID SRv6 End.X behavior |
|
|
# +-----------------------------------------------------------------+
|
|
# | |
|
|
# | IPv6 DA fcff:2::d46 |
|
|
# | ^^^^^^^^^^^ |
|
|
# | | |
|
|
# | SID copied from the SID List contained in the SRH |
|
|
# +-----------------------------------------------------------------+
|
|
#
|
|
# Since the Argument of the C-SID container is zero, the behavior can not
|
|
# update the Locator-Node function with the next C-SID carried in the Argument
|
|
# itself. Thus, the enabled NEXT-C-SID SRv6 End.X behavior operates as the
|
|
# traditional End.X behavior: it updates the IPv6 DA by copying the next
|
|
# available SID in the SID List carried by the SRH. Next, the packet is
|
|
# forwarded to the rt-4 node using the L3 adjacency fcf0:3:4::4 previously
|
|
# configured for this behavior.
|
|
#
|
|
# The node rt-4 performs a plain IPv6 forward to the rt-2 router according to
|
|
# its Local SID table and using the IPv6 DA fcff:2::d46.
|
|
#
|
|
# Once the packet is received by rt-2, the router decapsulates the inner IPv4
|
|
# packet using the SRv6 End.DT46 behavior (associated with the SID fcff:2::d46)
|
|
# and sends it to the host hs-2.
|
|
#
|
|
# Traffic from hs-2 to hs-1
|
|
# -------------------------
|
|
#
|
|
# Packets generated from hs-2 and directed towards hs-1 are handled by rt-2
|
|
# which applies the SRv6 Policies as follows:
|
|
#
|
|
# i) IPv6 DA=cafe::1, SID List=fcbb:0:0400:0100:d46::
|
|
# ii) IPv4 DA=10.0.0.1, SID List=fcbb:0:0300::,fcff:1::d46
|
|
#
|
|
# ### i) single SID
|
|
#
|
|
# The node hs-2 sends an IPv6 packet directed to node hs-1. The router rt-2 is
|
|
# directly connected to hs-2 and receives the packet. Rt-2 applies the
|
|
# H.Encap.Red behavior with policy i) described above. Since there is only one
|
|
# SID, the SRH header is omitted and the policy is inserted directly into the DA
|
|
# of IPv6 packet.
|
|
#
|
|
# The packet reaches the router rt-4 and the enabled NEXT-C-SID SRv6 End.X
|
|
# behavior (associated with fcbb:0:0400::/48) is triggered. This behavior
|
|
# analyzes the IPv6 DA and checks whether the Argument of the C-SID container
|
|
# is zero or not. The Argument is *NOT* zero and the C-SID in the IPv6 DA is
|
|
# advanced. At this point, the current IPv6 DA is fcbb:0:0100:d46:: .
|
|
# The enabled NEXT-C-SID SRv6 End.X behavior is configured with the L3 adjacency
|
|
# fcf0:0:1:4::1, used to route traffic to the rt-1 node.
|
|
#
|
|
# The router rt-1 is configured for decapsulating the inner packet. It applies
|
|
# the SRv6 End.DT46 behavior on the received packet. Decapsulation does not
|
|
# require the presence of the SRH. At the end of the decap operation, the packet
|
|
# is sent to the host hs-1.
|
|
#
|
|
# ### ii) double SID
|
|
#
|
|
# The router rt-2 is configured to enforce the given Policy through the SRv6
|
|
# H.Encaps.Red. As a result, the first SID fcbb:0:0300:: is stored into the
|
|
# IPv6 DA, while the SRH pushed into the packet is made of only one SID, i.e.
|
|
# fcff:1::d46. Hence, the packet sent by hs-2 to hs-1 is encapsulated in an
|
|
# outer IPv6 header plus the SRH.
|
|
#
|
|
# As the packet reaches the node rt-3, the enabled NEXT-C-SID SRv6 End.X
|
|
# behavior bound to the SID fcbb:0:0300::/48 is triggered.
|
|
# Since the Argument of the C-SID container is zero, the behavior can not
|
|
# update the Locator-Node function with the next C-SID carried in the Argument
|
|
# itself. Thus, the enabled NEXT-C-SID SRv6 End-X behavior operates as the
|
|
# traditional End.X behavior: it updates the IPv6 DA by copying the next
|
|
# available SID in the SID List carried by the SRH. After that, the packet is
|
|
# forwarded to the rt-4 node using the L3 adjacency (fcf0:3:4::4) previously
|
|
# configured for this behavior.
|
|
#
|
|
# The node rt-4 performs a plain IPv6 forward to the rt-1 router according to
|
|
# its Local SID table, considering the IPv6 DA fcff:1::d46.
|
|
#
|
|
# Once the packet is received by rt-1, the router decapsulates the inner IPv4
|
|
# packet using the SRv6 End.DT46 behavior (associated with the SID fcff:1::d46)
|
|
# and sends it to the host hs-1.
|
|
|
|
# Kselftest framework requirement - SKIP code is 4.
|
|
readonly ksft_skip=4
|
|
|
|
readonly RDMSUFF="$(mktemp -u XXXXXXXX)"
|
|
readonly DUMMY_DEVNAME="dum0"
|
|
readonly VRF_TID=100
|
|
readonly VRF_DEVNAME="vrf-${VRF_TID}"
|
|
readonly RT2HS_DEVNAME="veth-t${VRF_TID}"
|
|
readonly LOCALSID_TABLE_ID=90
|
|
readonly IPv6_RT_NETWORK=fcf0:0
|
|
readonly IPv6_HS_NETWORK=cafe
|
|
readonly IPv4_HS_NETWORK=10.0.0
|
|
readonly VPN_LOCATOR_SERVICE=fcff
|
|
readonly DT46_FUNC=0d46
|
|
readonly HEADEND_ENCAP="encap.red"
|
|
|
|
# do not add ':' as separator
|
|
readonly LCBLOCK_ADDR=fcbb0000
|
|
readonly LCBLOCK_BLEN=32
|
|
# do not add ':' as separator
|
|
readonly LCNODEFUNC_FMT="0%d00"
|
|
readonly LCNODEFUNC_BLEN=16
|
|
|
|
readonly LCBLOCK_NODEFUNC_BLEN=$((LCBLOCK_BLEN + LCNODEFUNC_BLEN))
|
|
|
|
readonly CSID_CNTR_PREFIX="dead:beaf::/32"
|
|
# ID of the router used for testing the C-SID container cfgs
|
|
readonly CSID_CNTR_RT_ID_TEST=1
|
|
# Routing table used for testing the C-SID container cfgs
|
|
readonly CSID_CNTR_RT_TABLE=91
|
|
|
|
# C-SID container configurations to be tested
|
|
#
|
|
# An entry of the array is defined as "a,b,c" where:
|
|
# - 'a' and 'b' elements represent respectively the Locator-Block length
|
|
# (lblen) in bits and the Locator-Node Function length (nflen) in bits.
|
|
# 'a' and 'b' can be set to default values using the placeholder "d" which
|
|
# indicates the default kernel values (32 for lblen and 16 for nflen);
|
|
# otherwise, any numeric value is accepted;
|
|
# - 'c' indicates whether the C-SID configuration provided by the values 'a'
|
|
# and 'b' should be considered valid ("y") or invalid ("n").
|
|
declare -ra CSID_CONTAINER_CFGS=(
|
|
"d,d,y"
|
|
"d,16,y"
|
|
"16,d,y"
|
|
"16,32,y"
|
|
"32,16,y"
|
|
"48,8,y"
|
|
"8,48,y"
|
|
"d,0,n"
|
|
"0,d,n"
|
|
"32,0,n"
|
|
"0,32,n"
|
|
"17,d,n"
|
|
"d,17,n"
|
|
"120,16,n"
|
|
"16,120,n"
|
|
"0,128,n"
|
|
"128,0,n"
|
|
"130,0,n"
|
|
"0,130,n"
|
|
"0,0,n"
|
|
)
|
|
|
|
PING_TIMEOUT_SEC=4
|
|
PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
|
|
|
|
# IDs of routers and hosts are initialized during the setup of the testing
|
|
# network
|
|
ROUTERS=''
|
|
HOSTS=''
|
|
|
|
SETUP_ERR=1
|
|
|
|
ret=${ksft_skip}
|
|
nsuccess=0
|
|
nfail=0
|
|
|
|
log_test()
|
|
{
|
|
local rc="$1"
|
|
local expected="$2"
|
|
local msg="$3"
|
|
|
|
if [ "${rc}" -eq "${expected}" ]; then
|
|
nsuccess=$((nsuccess+1))
|
|
printf "\n TEST: %-60s [ OK ]\n" "${msg}"
|
|
else
|
|
ret=1
|
|
nfail=$((nfail+1))
|
|
printf "\n TEST: %-60s [FAIL]\n" "${msg}"
|
|
if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
|
|
echo
|
|
echo "hit enter to continue, 'q' to quit"
|
|
read a
|
|
[ "$a" = "q" ] && exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
print_log_test_results()
|
|
{
|
|
printf "\nTests passed: %3d\n" "${nsuccess}"
|
|
printf "Tests failed: %3d\n" "${nfail}"
|
|
|
|
# when a test fails, the value of 'ret' is set to 1 (error code).
|
|
# Conversely, when all tests are passed successfully, the 'ret' value
|
|
# is set to 0 (success code).
|
|
if [ "${ret}" -ne 1 ]; then
|
|
ret=0
|
|
fi
|
|
}
|
|
|
|
log_section()
|
|
{
|
|
echo
|
|
echo "################################################################################"
|
|
echo "TEST SECTION: $*"
|
|
echo "################################################################################"
|
|
}
|
|
|
|
test_command_or_ksft_skip()
|
|
{
|
|
local cmd="$1"
|
|
|
|
if [ ! -x "$(command -v "${cmd}")" ]; then
|
|
echo "SKIP: Could not run test without \"${cmd}\" tool";
|
|
exit "${ksft_skip}"
|
|
fi
|
|
}
|
|
|
|
get_nodename()
|
|
{
|
|
local name="$1"
|
|
|
|
echo "${name}-${RDMSUFF}"
|
|
}
|
|
|
|
get_rtname()
|
|
{
|
|
local rtid="$1"
|
|
|
|
get_nodename "rt-${rtid}"
|
|
}
|
|
|
|
get_hsname()
|
|
{
|
|
local hsid="$1"
|
|
|
|
get_nodename "hs-${hsid}"
|
|
}
|
|
|
|
__create_namespace()
|
|
{
|
|
local name="$1"
|
|
|
|
ip netns add "${name}"
|
|
}
|
|
|
|
create_router()
|
|
{
|
|
local rtid="$1"
|
|
local nsname
|
|
|
|
nsname="$(get_rtname "${rtid}")"
|
|
|
|
__create_namespace "${nsname}"
|
|
|
|
ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
|
|
ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
|
|
ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.forwarding=1
|
|
|
|
ip netns exec "${nsname}" sysctl -wq net.ipv4.conf.all.rp_filter=0
|
|
ip netns exec "${nsname}" sysctl -wq net.ipv4.conf.default.rp_filter=0
|
|
ip netns exec "${nsname}" sysctl -wq net.ipv4.ip_forward=1
|
|
}
|
|
|
|
create_host()
|
|
{
|
|
local hsid="$1"
|
|
local nsname
|
|
|
|
nsname="$(get_hsname "${hsid}")"
|
|
|
|
__create_namespace "${nsname}"
|
|
}
|
|
|
|
cleanup()
|
|
{
|
|
local nsname
|
|
local i
|
|
|
|
# destroy routers
|
|
for i in ${ROUTERS}; do
|
|
nsname="$(get_rtname "${i}")"
|
|
|
|
ip netns del "${nsname}" &>/dev/null || true
|
|
done
|
|
|
|
# destroy hosts
|
|
for i in ${HOSTS}; do
|
|
nsname="$(get_hsname "${i}")"
|
|
|
|
ip netns del "${nsname}" &>/dev/null || true
|
|
done
|
|
|
|
# check whether the setup phase was completed successfully or not. In
|
|
# case of an error during the setup phase of the testing environment,
|
|
# the selftest is considered as "skipped".
|
|
if [ "${SETUP_ERR}" -ne 0 ]; then
|
|
echo "SKIP: Setting up the testing environment failed"
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
exit "${ret}"
|
|
}
|
|
|
|
add_link_rt_pairs()
|
|
{
|
|
local rt="$1"
|
|
local rt_neighs="$2"
|
|
local neigh
|
|
local nsname
|
|
local neigh_nsname
|
|
|
|
nsname="$(get_rtname "${rt}")"
|
|
|
|
for neigh in ${rt_neighs}; do
|
|
neigh_nsname="$(get_rtname "${neigh}")"
|
|
|
|
ip link add "veth-rt-${rt}-${neigh}" netns "${nsname}" \
|
|
type veth peer name "veth-rt-${neigh}-${rt}" \
|
|
netns "${neigh_nsname}"
|
|
done
|
|
}
|
|
|
|
get_network_prefix()
|
|
{
|
|
local rt="$1"
|
|
local neigh="$2"
|
|
local p="${rt}"
|
|
local q="${neigh}"
|
|
|
|
if [ "${p}" -gt "${q}" ]; then
|
|
p="${q}"; q="${rt}"
|
|
fi
|
|
|
|
echo "${IPv6_RT_NETWORK}:${p}:${q}"
|
|
}
|
|
|
|
# Setup the basic networking for the routers
|
|
setup_rt_networking()
|
|
{
|
|
local rt="$1"
|
|
local rt_neighs="$2"
|
|
local nsname
|
|
local net_prefix
|
|
local devname
|
|
local neigh
|
|
|
|
nsname="$(get_rtname "${rt}")"
|
|
|
|
for neigh in ${rt_neighs}; do
|
|
devname="veth-rt-${rt}-${neigh}"
|
|
|
|
net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
|
|
|
|
ip -netns "${nsname}" addr \
|
|
add "${net_prefix}::${rt}/64" dev "${devname}" nodad
|
|
|
|
ip -netns "${nsname}" link set "${devname}" up
|
|
done
|
|
|
|
ip -netns "${nsname}" link add "${DUMMY_DEVNAME}" type dummy
|
|
|
|
ip -netns "${nsname}" link set "${DUMMY_DEVNAME}" up
|
|
ip -netns "${nsname}" link set lo up
|
|
}
|
|
|
|
# build an ipv6 prefix/address based on the input string
|
|
# Note that the input string does not contain ':' and '::' which are considered
|
|
# to be implicit.
|
|
# e.g.:
|
|
# - input: fbcc00000400300
|
|
# - output: fbcc:0000:0400:0300:0000:0000:0000:0000
|
|
# ^^^^^^^^^^^^^^^^^^^
|
|
# fill the address with 0s
|
|
build_ipv6_addr()
|
|
{
|
|
local addr="$1"
|
|
local out=""
|
|
local strlen="${#addr}"
|
|
local padn
|
|
local i
|
|
|
|
# add ":" every 4 digits (16 bits)
|
|
for (( i = 0; i < strlen; i++ )); do
|
|
if (( i > 0 && i < 32 && (i % 4) == 0 )); then
|
|
out="${out}:"
|
|
fi
|
|
|
|
out="${out}${addr:$i:1}"
|
|
done
|
|
|
|
# fill the remaining bits of the address with 0s
|
|
padn=$((32 - strlen))
|
|
for (( i = padn; i > 0; i-- )); do
|
|
if (( i > 0 && i < 32 && (i % 4) == 0 )); then
|
|
out="${out}:"
|
|
fi
|
|
|
|
out="${out}0"
|
|
done
|
|
|
|
printf "${out}"
|
|
}
|
|
|
|
build_csid()
|
|
{
|
|
local nodeid="$1"
|
|
|
|
printf "${LCNODEFUNC_FMT}" "${nodeid}"
|
|
}
|
|
|
|
build_lcnode_func_prefix()
|
|
{
|
|
local nodeid="$1"
|
|
local lcnodefunc
|
|
local prefix
|
|
local out
|
|
|
|
lcnodefunc="$(build_csid "${nodeid}")"
|
|
prefix="$(build_ipv6_addr "${LCBLOCK_ADDR}${lcnodefunc}")"
|
|
|
|
out="${prefix}/${LCBLOCK_NODEFUNC_BLEN}"
|
|
|
|
echo "${out}"
|
|
}
|
|
|
|
set_end_x_nextcsid()
|
|
{
|
|
local rt="$1"
|
|
local adj="$2"
|
|
|
|
nsname="$(get_rtname "${rt}")"
|
|
net_prefix="$(get_network_prefix "${rt}" "${adj}")"
|
|
lcnode_func_prefix="$(build_lcnode_func_prefix "${rt}")"
|
|
|
|
# enabled NEXT-C-SID SRv6 End.X behavior (note that "dev" is the dummy
|
|
# dum0 device chosen for the sake of simplicity).
|
|
ip -netns "${nsname}" -6 route \
|
|
replace "${lcnode_func_prefix}" \
|
|
table "${LOCALSID_TABLE_ID}" \
|
|
encap seg6local action End.X nh6 "${net_prefix}::${adj}" \
|
|
flavors next-csid lblen "${LCBLOCK_BLEN}" \
|
|
nflen "${LCNODEFUNC_BLEN}" dev "${DUMMY_DEVNAME}"
|
|
}
|
|
|
|
set_underlay_sids_reachability()
|
|
{
|
|
local rt="$1"
|
|
local rt_neighs="$2"
|
|
|
|
nsname="$(get_rtname "${rt}")"
|
|
|
|
for neigh in ${rt_neighs}; do
|
|
devname="veth-rt-${rt}-${neigh}"
|
|
|
|
net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
|
|
|
|
# set underlay network routes for SIDs reachability
|
|
ip -netns "${nsname}" -6 route \
|
|
replace "${VPN_LOCATOR_SERVICE}:${neigh}::/32" \
|
|
table "${LOCALSID_TABLE_ID}" \
|
|
via "${net_prefix}::${neigh}" dev "${devname}"
|
|
|
|
# set the underlay network for C-SIDs reachability
|
|
lcnode_func_prefix="$(build_lcnode_func_prefix "${neigh}")"
|
|
|
|
ip -netns "${nsname}" -6 route \
|
|
replace "${lcnode_func_prefix}" \
|
|
table "${LOCALSID_TABLE_ID}" \
|
|
via "${net_prefix}::${neigh}" dev "${devname}"
|
|
done
|
|
}
|
|
|
|
# Setup local SIDs for an SRv6 router
|
|
setup_rt_local_sids()
|
|
{
|
|
local rt="$1"
|
|
local rt_neighs="$2"
|
|
local net_prefix
|
|
local devname
|
|
local nsname
|
|
local neigh
|
|
local lcnode_func_prefix
|
|
local lcblock_prefix
|
|
|
|
nsname="$(get_rtname "${rt}")"
|
|
|
|
set_underlay_sids_reachability "${rt}" "${rt_neighs}"
|
|
|
|
# all SIDs for VPNs start with a common locator. Routes and SRv6
|
|
# Endpoint behavior instaces are grouped together in the 'localsid'
|
|
# table.
|
|
ip -netns "${nsname}" -6 rule \
|
|
add to "${VPN_LOCATOR_SERVICE}::/16" \
|
|
lookup "${LOCALSID_TABLE_ID}" prio 999
|
|
|
|
# common locator block for NEXT-C-SIDS compression mechanism.
|
|
lcblock_prefix="$(build_ipv6_addr "${LCBLOCK_ADDR}")"
|
|
ip -netns "${nsname}" -6 rule \
|
|
add to "${lcblock_prefix}/${LCBLOCK_BLEN}" \
|
|
lookup "${LOCALSID_TABLE_ID}" prio 999
|
|
}
|
|
|
|
# build and install the SRv6 policy into the ingress SRv6 router as well as the
|
|
# decap SID in the egress one.
|
|
# args:
|
|
# $1 - src host (evaluate automatically the ingress router)
|
|
# $2 - dst host (evaluate automatically the egress router)
|
|
# $3 - SRv6 routers configured for steering traffic (End.X behaviors)
|
|
# $4 - single SID or double SID
|
|
# $5 - traffic type (IPv6 or IPv4)
|
|
__setup_l3vpn()
|
|
{
|
|
local src="$1"
|
|
local dst="$2"
|
|
local end_rts="$3"
|
|
local mode="$4"
|
|
local traffic="$5"
|
|
local nsname
|
|
local policy
|
|
local container
|
|
local decapsid
|
|
local lcnfunc
|
|
local dt
|
|
local n
|
|
local rtsrc_nsname
|
|
local rtdst_nsname
|
|
|
|
rtsrc_nsname="$(get_rtname "${src}")"
|
|
rtdst_nsname="$(get_rtname "${dst}")"
|
|
|
|
container="${LCBLOCK_ADDR}"
|
|
|
|
# build first SID (C-SID container)
|
|
for n in ${end_rts}; do
|
|
lcnfunc="$(build_csid "${n}")"
|
|
|
|
container="${container}${lcnfunc}"
|
|
done
|
|
|
|
if [ "${mode}" -eq 1 ]; then
|
|
# single SID policy
|
|
dt="$(build_csid "${dst}")${DT46_FUNC}"
|
|
container="${container}${dt}"
|
|
# build the full ipv6 address for the container
|
|
policy="$(build_ipv6_addr "${container}")"
|
|
|
|
# build the decap SID used in the decap node
|
|
container="${LCBLOCK_ADDR}${dt}"
|
|
decapsid="$(build_ipv6_addr "${container}")"
|
|
else
|
|
# double SID policy
|
|
decapsid="${VPN_LOCATOR_SERVICE}:${dst}::${DT46_FUNC}"
|
|
|
|
policy="$(build_ipv6_addr "${container}"),${decapsid}"
|
|
fi
|
|
|
|
# apply encap policy
|
|
if [ "${traffic}" -eq 6 ]; then
|
|
ip -netns "${rtsrc_nsname}" -6 route \
|
|
add "${IPv6_HS_NETWORK}::${dst}" vrf "${VRF_DEVNAME}" \
|
|
encap seg6 mode "${HEADEND_ENCAP}" segs "${policy}" \
|
|
dev "${VRF_DEVNAME}"
|
|
|
|
ip -netns "${rtsrc_nsname}" -6 neigh \
|
|
add proxy "${IPv6_HS_NETWORK}::${dst}" \
|
|
dev "${RT2HS_DEVNAME}"
|
|
else
|
|
# "dev" must be different from the one where the packet is
|
|
# received, otherwise the proxy arp does not work.
|
|
ip -netns "${rtsrc_nsname}" -4 route \
|
|
add "${IPv4_HS_NETWORK}.${dst}" vrf "${VRF_DEVNAME}" \
|
|
encap seg6 mode "${HEADEND_ENCAP}" segs "${policy}" \
|
|
dev "${VRF_DEVNAME}"
|
|
fi
|
|
|
|
# apply decap
|
|
# Local End.DT46 behavior (decap)
|
|
ip -netns "${rtdst_nsname}" -6 route \
|
|
add "${decapsid}" \
|
|
table "${LOCALSID_TABLE_ID}" \
|
|
encap seg6local action End.DT46 vrftable "${VRF_TID}" \
|
|
dev "${VRF_DEVNAME}"
|
|
}
|
|
|
|
# see __setup_l3vpn()
|
|
setup_ipv4_vpn_2sids()
|
|
{
|
|
__setup_l3vpn "$1" "$2" "$3" 2 4
|
|
}
|
|
|
|
# see __setup_l3vpn()
|
|
setup_ipv6_vpn_1sid()
|
|
{
|
|
__setup_l3vpn "$1" "$2" "$3" 1 6
|
|
}
|
|
|
|
setup_hs()
|
|
{
|
|
local hs="$1"
|
|
local rt="$2"
|
|
local hsname
|
|
local rtname
|
|
|
|
hsname="$(get_hsname "${hs}")"
|
|
rtname="$(get_rtname "${rt}")"
|
|
|
|
ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
|
|
ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
|
|
|
|
ip -netns "${hsname}" link add veth0 type veth \
|
|
peer name "${RT2HS_DEVNAME}" netns "${rtname}"
|
|
|
|
ip -netns "${hsname}" addr \
|
|
add "${IPv6_HS_NETWORK}::${hs}/64" dev veth0 nodad
|
|
ip -netns "${hsname}" addr add "${IPv4_HS_NETWORK}.${hs}/24" dev veth0
|
|
|
|
ip -netns "${hsname}" link set veth0 up
|
|
ip -netns "${hsname}" link set lo up
|
|
|
|
# configure the VRF on the router which is directly connected to the
|
|
# source host.
|
|
ip -netns "${rtname}" link \
|
|
add "${VRF_DEVNAME}" type vrf table "${VRF_TID}"
|
|
ip -netns "${rtname}" link set "${VRF_DEVNAME}" up
|
|
|
|
# enslave the veth interface connecting the router with the host to the
|
|
# VRF in the access router
|
|
ip -netns "${rtname}" link \
|
|
set "${RT2HS_DEVNAME}" master "${VRF_DEVNAME}"
|
|
|
|
# set default routes to unreachable for both ipv6 and ipv4
|
|
ip -netns "${rtname}" -6 route \
|
|
add unreachable default metric 4278198272 \
|
|
vrf "${VRF_DEVNAME}"
|
|
ip -netns "${rtname}" -4 route \
|
|
add unreachable default metric 4278198272 \
|
|
vrf "${VRF_DEVNAME}"
|
|
|
|
ip -netns "${rtname}" addr \
|
|
add "${IPv6_HS_NETWORK}::254/64" dev "${RT2HS_DEVNAME}" nodad
|
|
ip -netns "${rtname}" addr \
|
|
add "${IPv4_HS_NETWORK}.254/24" dev "${RT2HS_DEVNAME}"
|
|
|
|
ip -netns "${rtname}" link set "${RT2HS_DEVNAME}" up
|
|
|
|
ip netns exec "${rtname}" \
|
|
sysctl -wq net.ipv6.conf."${RT2HS_DEVNAME}".proxy_ndp=1
|
|
ip netns exec "${rtname}" \
|
|
sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".proxy_arp=1
|
|
|
|
# disable the rp_filter otherwise the kernel gets confused about how
|
|
# to route decap ipv4 packets.
|
|
ip netns exec "${rtname}" \
|
|
sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".rp_filter=0
|
|
|
|
ip netns exec "${rtname}" sh -c "echo 1 > /proc/sys/net/vrf/strict_mode"
|
|
}
|
|
|
|
setup()
|
|
{
|
|
local i
|
|
|
|
# create routers
|
|
ROUTERS="1 2 3 4"; readonly ROUTERS
|
|
for i in ${ROUTERS}; do
|
|
create_router "${i}"
|
|
done
|
|
|
|
# create hosts
|
|
HOSTS="1 2"; readonly HOSTS
|
|
for i in ${HOSTS}; do
|
|
create_host "${i}"
|
|
done
|
|
|
|
# set up the links for connecting routers
|
|
add_link_rt_pairs 1 "2 3 4"
|
|
add_link_rt_pairs 2 "3 4"
|
|
add_link_rt_pairs 3 "4"
|
|
|
|
# set up the basic connectivity of routers and routes required for
|
|
# reachability of SIDs.
|
|
setup_rt_networking 1 "2 3 4"
|
|
setup_rt_networking 2 "1 3 4"
|
|
setup_rt_networking 3 "1 2 4"
|
|
setup_rt_networking 4 "1 2 3"
|
|
|
|
# set up the hosts connected to routers
|
|
setup_hs 1 1
|
|
setup_hs 2 2
|
|
|
|
# set up default SRv6 Endpoints (i.e. SRv6 End and SRv6 End.DT46)
|
|
setup_rt_local_sids 1 "2 3 4"
|
|
setup_rt_local_sids 2 "1 3 4"
|
|
setup_rt_local_sids 3 "1 2 4"
|
|
setup_rt_local_sids 4 "1 2 3"
|
|
|
|
# set up SRv6 Policies
|
|
|
|
# create an IPv6 VPN between hosts hs-1 and hs-2.
|
|
#
|
|
# Direction hs-1 -> hs-2
|
|
# - rt-1 encap (H.Encaps.Red)
|
|
# - rt-3 SRv6 End.X behavior adj rt-4 (NEXT-C-SID flavor)
|
|
# - rt-4 Plain IPv6 Forwarding to rt-2
|
|
# - rt-2 SRv6 End.DT46 behavior
|
|
setup_ipv6_vpn_1sid 1 2 "3"
|
|
|
|
# Direction hs2 -> hs-1
|
|
# - rt-2 encap (H.Encaps.Red)
|
|
# - rt-4 SRv6 End.X behavior adj rt-1 (NEXT-C-SID flavor)
|
|
# - rt-1 SRv6 End.DT46 behavior
|
|
setup_ipv6_vpn_1sid 2 1 "4"
|
|
|
|
# create an IPv4 VPN between hosts hs-1 and hs-2
|
|
#
|
|
# Direction hs-1 -> hs-2
|
|
# - rt-1 encap (H.Encaps.Red)
|
|
# - rt-3 SRv6 End.X behavior adj rt-4 (NEXT-C-SID flavor)
|
|
# - rt-4 Plain IPv6 Forwarding to rt-2
|
|
# - rt-2 SRv6 End.DT46 behavior
|
|
setup_ipv4_vpn_2sids 1 2 "3"
|
|
|
|
# Direction hs-2 -> hs-1
|
|
# - rt-2 encap (H.Encaps.Red)
|
|
# - rt-3 SRv6 End.X behavior adj rt-4 (NEXT-C-SID flavor)
|
|
# - rt-4 Plain IPv6 Forwarding to rt-1
|
|
# - rt-1 SRv6 End.DT46 behavior
|
|
setup_ipv4_vpn_2sids 2 1 "3"
|
|
|
|
# Setup the adjacencies in the SRv6 aware routers
|
|
# - rt-3 SRv6 End.X adjacency with rt-4
|
|
# - rt-4 SRv6 End.X adjacency with rt-1
|
|
set_end_x_nextcsid 3 4
|
|
set_end_x_nextcsid 4 1
|
|
|
|
# testing environment was set up successfully
|
|
SETUP_ERR=0
|
|
}
|
|
|
|
check_rt_connectivity()
|
|
{
|
|
local rtsrc="$1"
|
|
local rtdst="$2"
|
|
local prefix
|
|
local rtsrc_nsname
|
|
|
|
rtsrc_nsname="$(get_rtname "${rtsrc}")"
|
|
|
|
prefix="$(get_network_prefix "${rtsrc}" "${rtdst}")"
|
|
|
|
ip netns exec "${rtsrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
|
|
"${prefix}::${rtdst}" >/dev/null 2>&1
|
|
}
|
|
|
|
check_and_log_rt_connectivity()
|
|
{
|
|
local rtsrc="$1"
|
|
local rtdst="$2"
|
|
|
|
check_rt_connectivity "${rtsrc}" "${rtdst}"
|
|
log_test $? 0 "Routers connectivity: rt-${rtsrc} -> rt-${rtdst}"
|
|
}
|
|
|
|
check_hs_ipv6_connectivity()
|
|
{
|
|
local hssrc="$1"
|
|
local hsdst="$2"
|
|
local hssrc_nsname
|
|
|
|
hssrc_nsname="$(get_hsname "${hssrc}")"
|
|
|
|
ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
|
|
"${IPv6_HS_NETWORK}::${hsdst}" >/dev/null 2>&1
|
|
}
|
|
|
|
check_hs_ipv4_connectivity()
|
|
{
|
|
local hssrc="$1"
|
|
local hsdst="$2"
|
|
local hssrc_nsname
|
|
|
|
hssrc_nsname="$(get_hsname "${hssrc}")"
|
|
|
|
ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
|
|
"${IPv4_HS_NETWORK}.${hsdst}" >/dev/null 2>&1
|
|
}
|
|
|
|
check_and_log_hs2gw_connectivity()
|
|
{
|
|
local hssrc="$1"
|
|
|
|
check_hs_ipv6_connectivity "${hssrc}" 254
|
|
log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> gw"
|
|
|
|
check_hs_ipv4_connectivity "${hssrc}" 254
|
|
log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> gw"
|
|
}
|
|
|
|
check_and_log_hs_ipv6_connectivity()
|
|
{
|
|
local hssrc="$1"
|
|
local hsdst="$2"
|
|
|
|
check_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
|
|
log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"
|
|
}
|
|
|
|
check_and_log_hs_ipv4_connectivity()
|
|
{
|
|
local hssrc="$1"
|
|
local hsdst="$2"
|
|
|
|
check_hs_ipv4_connectivity "${hssrc}" "${hsdst}"
|
|
log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"
|
|
}
|
|
|
|
router_tests()
|
|
{
|
|
local i
|
|
local j
|
|
|
|
log_section "IPv6 routers connectivity test"
|
|
|
|
for i in ${ROUTERS}; do
|
|
for j in ${ROUTERS}; do
|
|
if [ "${i}" -eq "${j}" ]; then
|
|
continue
|
|
fi
|
|
|
|
check_and_log_rt_connectivity "${i}" "${j}"
|
|
done
|
|
done
|
|
}
|
|
|
|
host2gateway_tests()
|
|
{
|
|
local hs
|
|
|
|
log_section "IPv4/IPv6 connectivity test among hosts and gateways"
|
|
|
|
for hs in ${HOSTS}; do
|
|
check_and_log_hs2gw_connectivity "${hs}"
|
|
done
|
|
}
|
|
|
|
host_vpn_tests()
|
|
{
|
|
log_section "SRv6 VPN connectivity test hosts (h1 <-> h2, IPv6)"
|
|
|
|
check_and_log_hs_ipv6_connectivity 1 2
|
|
check_and_log_hs_ipv6_connectivity 2 1
|
|
|
|
log_section "SRv6 VPN connectivity test hosts (h1 <-> h2, IPv4)"
|
|
|
|
check_and_log_hs_ipv4_connectivity 1 2
|
|
check_and_log_hs_ipv4_connectivity 2 1
|
|
}
|
|
|
|
__nextcsid_end_x_behavior_test()
|
|
{
|
|
local nsname="$1"
|
|
local cmd="$2"
|
|
local blen="$3"
|
|
local flen="$4"
|
|
local layout=""
|
|
|
|
if [ "${blen}" != "d" ]; then
|
|
layout="${layout} lblen ${blen}"
|
|
fi
|
|
|
|
if [ "${flen}" != "d" ]; then
|
|
layout="${layout} nflen ${flen}"
|
|
fi
|
|
|
|
ip -netns "${nsname}" -6 route \
|
|
"${cmd}" "${CSID_CNTR_PREFIX}" \
|
|
table "${CSID_CNTR_RT_TABLE}" \
|
|
encap seg6local action End.X nh6 :: \
|
|
flavors next-csid ${layout} \
|
|
dev "${DUMMY_DEVNAME}" &>/dev/null
|
|
|
|
return "$?"
|
|
}
|
|
|
|
rt_x_nextcsid_end_x_behavior_test()
|
|
{
|
|
local rt="$1"
|
|
local blen="$2"
|
|
local flen="$3"
|
|
local nsname
|
|
local ret
|
|
|
|
nsname="$(get_rtname "${rt}")"
|
|
|
|
__nextcsid_end_x_behavior_test "${nsname}" "add" "${blen}" "${flen}"
|
|
ret="$?"
|
|
__nextcsid_end_x_behavior_test "${nsname}" "del" "${blen}" "${flen}"
|
|
|
|
return "${ret}"
|
|
}
|
|
|
|
__parse_csid_container_cfg()
|
|
{
|
|
local cfg="$1"
|
|
local index="$2"
|
|
local out
|
|
|
|
echo "${cfg}" | cut -d',' -f"${index}"
|
|
}
|
|
|
|
csid_container_cfg_tests()
|
|
{
|
|
local valid
|
|
local blen
|
|
local flen
|
|
local cfg
|
|
local ret
|
|
|
|
log_section "C-SID Container config tests (legend: d='kernel default')"
|
|
|
|
for cfg in "${CSID_CONTAINER_CFGS[@]}"; do
|
|
blen="$(__parse_csid_container_cfg "${cfg}" 1)"
|
|
flen="$(__parse_csid_container_cfg "${cfg}" 2)"
|
|
valid="$(__parse_csid_container_cfg "${cfg}" 3)"
|
|
|
|
rt_x_nextcsid_end_x_behavior_test \
|
|
"${CSID_CNTR_RT_ID_TEST}" \
|
|
"${blen}" \
|
|
"${flen}"
|
|
ret="$?"
|
|
|
|
if [ "${valid}" == "y" ]; then
|
|
log_test "${ret}" 0 \
|
|
"Accept valid C-SID container cfg (lblen=${blen}, nflen=${flen})"
|
|
else
|
|
log_test "${ret}" 2 \
|
|
"Reject invalid C-SID container cfg (lblen=${blen}, nflen=${flen})"
|
|
fi
|
|
done
|
|
}
|
|
|
|
test_iproute2_supp_or_ksft_skip()
|
|
{
|
|
if ! ip route help 2>&1 | grep -qo "next-csid"; then
|
|
echo "SKIP: Missing SRv6 NEXT-C-SID flavor support in iproute2"
|
|
exit "${ksft_skip}"
|
|
fi
|
|
}
|
|
|
|
test_dummy_dev_or_ksft_skip()
|
|
{
|
|
local test_netns
|
|
|
|
test_netns="dummy-$(mktemp -u XXXXXXXX)"
|
|
|
|
if ! ip netns add "${test_netns}"; then
|
|
echo "SKIP: Cannot set up netns for testing dummy dev support"
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
modprobe dummy &>/dev/null || true
|
|
if ! ip -netns "${test_netns}" link \
|
|
add "${DUMMY_DEVNAME}" type dummy; then
|
|
echo "SKIP: dummy dev not supported"
|
|
|
|
ip netns del "${test_netns}"
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
ip netns del "${test_netns}"
|
|
}
|
|
|
|
test_vrf_or_ksft_skip()
|
|
{
|
|
modprobe vrf &>/dev/null || true
|
|
if [ ! -e /proc/sys/net/vrf/strict_mode ]; then
|
|
echo "SKIP: vrf sysctl does not exist"
|
|
exit "${ksft_skip}"
|
|
fi
|
|
}
|
|
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
echo "SKIP: Need root privileges"
|
|
exit "${ksft_skip}"
|
|
fi
|
|
|
|
# required programs to carry out this selftest
|
|
test_command_or_ksft_skip ip
|
|
test_command_or_ksft_skip ping
|
|
test_command_or_ksft_skip sysctl
|
|
test_command_or_ksft_skip grep
|
|
test_command_or_ksft_skip cut
|
|
|
|
test_iproute2_supp_or_ksft_skip
|
|
test_dummy_dev_or_ksft_skip
|
|
test_vrf_or_ksft_skip
|
|
|
|
set -e
|
|
trap cleanup EXIT
|
|
|
|
setup
|
|
set +e
|
|
|
|
csid_container_cfg_tests
|
|
|
|
router_tests
|
|
host2gateway_tests
|
|
host_vpn_tests
|
|
|
|
print_log_test_results
|