Extend srv6_end_flavors_test.sh with tests for the SRv6 End behavior
with both the NEXT-C-SID and PSP flavors.

The tests use two SRv6 Policies with C-SID containers, where every
router after the ingress one applies End with the NEXT-C-SID and PSP
flavors. To check PSP, set net.ipv6.conf.all.seg6_enabled to 0 on the
hosts in setup_hs(). The hosts then drop any packet that still carries
an SRH, and a ping to an address on the loopback of a host succeeds
only if the router connected to that host has removed the SRH. The tests
fail when PSP is not applied together with NEXT-C-SID.

Signed-off-by: Andrea Mayer <[email protected]>
---
 .../selftests/net/srv6_end_flavors_test.sh    | 229 +++++++++++++++++-
 1 file changed, 226 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/net/srv6_end_flavors_test.sh 
b/tools/testing/selftests/net/srv6_end_flavors_test.sh
index 30a939392eea..baa1b09a1aab 100755
--- a/tools/testing/selftests/net/srv6_end_flavors_test.sh
+++ b/tools/testing/selftests/net/srv6_end_flavors_test.sh
@@ -16,8 +16,9 @@
 #
 # The End, End.X, and End.T behaviors can support these flavors either
 # individually or in combinations.
-# Currently in this selftest we consider only the PSP flavor for the SRv6 End
-# behavior. However, it is possible to extend the script as soon as other
+# Currently in this selftest we consider the PSP flavor for the SRv6 End
+# behavior, both alone and combined with the NEXT-C-SID flavor defined in
+# RFC9800 [2]. However, it is possible to extend the script as soon as other
 # flavors will be supported in the kernel.
 #
 # The purpose of the PSP flavor consists in instructing the penultimate node
@@ -47,7 +48,20 @@
 #    "standard" End packet processing, ignoring the configured PSP flavor at
 #    all.
 #
+# The NEXT-C-SID flavor (referred to as NEXT-CSID in RFC9800 [2]) and the
+# C-SID containers are described in srv6_end_next_csid_l3vpn_test.sh, which
+# also tests this flavor for the SRv6 End behavior.
+#
+# When the NEXT-C-SID flavor is combined with the PSP, USP or USD flavors, 
these
+# flavors are left unchanged [2]. The NEXT-C-SID processing comes first: with a
+# non-zero Argument, the IPv6 DA is updated with the next C-SID and the packet
+# is forwarded without changing the SRH, if any. The packet goes through the 
End
+# behavior with the other flavors only when the Argument is zero, i.e. when the
+# IPv6 DA carries no further C-SID. For example, the PSP operation takes place
+# only for a C-SID container with a zero Argument and SL=1.
+#
 # [1] RFC8986: https://datatracker.ietf.org/doc/html/rfc8986
+# [2] RFC9800: https://datatracker.ietf.org/doc/html/rfc9800
 #
 # Network topology
 # ================
@@ -115,12 +129,30 @@
 #   +---------------------------------------------------------------------+
 #   |fcff:x::e is associated with the SRv6 End behavior                   |
 #   |fcff:x::ef1 is associated with the SRv6 End behavior with PSP flavor |
+#   |fcbb:0:0xyy::/48 is associated with the SRv6 behavior and the        |
+#   |   flavors of the Function yy                                        |
 #   +---------------------------------------------------------------------+
 #
 # The fcff::/16 prefix is reserved by the operator for the SIDs. Reachability 
of
 # SIDs is ensured by proper configuration of the IPv6 operator's network and
 # SRv6 routers.
 #
+# Similarly, the fcbb:0::/32 prefix is reserved by the operator for the C-SID
+# containers and it is used as their Locator-Block.
+# A C-SID (16 bits) is made of the Locator-Node (8 bits), i.e. the ID of the
+# router, followed by the Function (8 bits). The first digit of the Function
+# selects the SRv6 behavior and the second one the flavors combined with
+# NEXT-C-SID:
+#
+#   +----------+----------+--------------------+
+#   | Function | behavior | flavors            |
+#   +----------+----------+--------------------+
+#   | a1       | End      | NEXT-C-SID and PSP |
+#   +----------+----------+--------------------+
+#
+# For example, fcbb:0:04a1:02a1:: is a C-SID container carrying the C-SID of
+# rt-4 followed by the C-SID of rt-2, both with the NEXT-C-SID and PSP flavors.
+#
 #
 # SRv6 Policies
 # =============
@@ -193,6 +225,39 @@
 # set with the last SID; iii) the SRH is removed from the extension headers
 # after the IPv6 header. At this point, the packet with IPv6 DA=cafe::1 is sent
 # to the destination, i.e. hs-1.
+#
+# Traffic to the loopback addresses of the hosts
+# ----------------------------------------------
+#
+# Each host has an address on its loopback, cafe::x:a1. The traffic from the
+# other host towards this address is steered with C-SID containers: after the
+# ingress router, every router crossed applies the SRv6 End behavior with the
+# NEXT-C-SID and PSP flavors. The following SRv6 Policies are applied by rt-1
+# to the traffic towards cafe::2:a1 (i.c) and by rt-2 to the traffic towards
+# cafe::1:a1 (i.d):
+#
+#   i.c) IPv6 traffic, SID List=fcbb:0:03a1::,fcbb:0:04a1:02a1::,cafe::2:a1
+#   i.d) IPv6 traffic, SID List=fcbb:0:04a1:03a1:01a1::,cafe::1:a1
+#
+# In the Policy (i.c), rt-3 receives a zero Argument with SL=2 and applies the
+# "standard" End processing. rt-4 receives a non-zero Argument with SL=1: it
+# advances to the next C-SID and does *NOT* apply the PSP operation. rt-2
+# receives a zero Argument with SL=1 and applies the PSP operation.
+#
+# In the Policy (i.d), a single C-SID container carries three C-SIDs. rt-4 and
+# rt-3 receive a non-zero Argument with SL=1: they advance to the next C-SID 
and
+# do *NOT* apply the PSP operation. rt-1 receives a zero Argument with SL=1
+# and applies the PSP operation.
+#
+# The hosts use cafe::x as the source address, not the loopback address. The
+# replies are sent to cafe::x and follow the Policies (i.a) and (i.b), which
+# are tested first. This way, each ping checks a single Policy with the
+# NEXT-C-SID flavor, and a failure points directly to that Policy.
+#
+# The hosts drop the packets that carry an SRH (seg6_enabled is set to 0 on
+# the hosts). The loopback address of a host is reached only through the
+# router connected to that host: the ping succeeds only if the SRH is removed
+# by that router.
 
 # shellcheck source=lib.sh
 source lib.sh
@@ -207,6 +272,17 @@ readonly IPv6_TESTS_ADDR=2001:db8::1
 readonly LOCATOR_SERVICE=fcff
 readonly END_FUNC=000e
 readonly END_PSP_FUNC=0ef1
+readonly END_CSID_PSP_FUNC=a1
+
+readonly LCBLOCK_ADDR=fcbb:0
+readonly LCBLOCK_BLEN=32
+# do not add ':' as separator
+readonly LCNODE_FMT="0%d"
+readonly LCNODE_BLEN=8
+readonly LCNODEFUNC_BLEN=16
+
+readonly LCBLOCK_NODE_BLEN=$((LCBLOCK_BLEN + LCNODE_BLEN))
+readonly LCBLOCK_NODEFUNC_BLEN=$((LCBLOCK_BLEN + LCNODEFUNC_BLEN))
 
 PING_TIMEOUT_SEC=4
 PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
@@ -397,6 +473,40 @@ __get_srv6_rtcfg_op()
                xargs | sed 's/ /,/g'
 }
 
+# Given the ID of a router and a Function, the function returns the C-SID made
+# of the Locator-Node (8 bits), i.e. the ID of the router, followed by the
+# Function (8 bits).
+# e.g. input: "4" "a1"
+#      output: "04a1"
+build_csid()
+{
+       local nodeid="$1"
+       local func="$2"
+
+       printf "${LCNODE_FMT}%s" "${nodeid}" "${func}"
+}
+
+# Given the <nodeid> token of a "next-csid,<flavors>" element, i.e. a
+# comma-separated list of node IDs, and a Function, the function returns the
+# C-SID container carrying the C-SIDs of these nodes.
+# e.g. input: "4,2" "a1"
+#      output: "fcbb:0:04a1:02a1::"
+build_csid_container()
+{
+       local nodeids="$1"
+       local func="$2"
+       local csids=''
+       local nodes
+       local node
+
+       nodes="$(echo "${nodeids}" | sed 's/,/ /g')"
+       for node in ${nodes}; do
+               csids="${csids}:$(build_csid "${node}" "${func}")"
+       done
+
+       echo "${LCBLOCK_ADDR}${csids}::"
+}
+
 # Setup the basic networking for the routers
 setup_rt_networking()
 {
@@ -439,6 +549,7 @@ setup_rt_local_sids()
        local devname
        local nsname
        local neigh
+       local csid
 
        nsname="$(get_rtname "${rt}")"
 
@@ -452,6 +563,14 @@ setup_rt_local_sids()
                        add "${LOCATOR_SERVICE}:${neigh}::/32" \
                        table "${LOCALSID_TABLE_ID}" \
                        via "${net_prefix}::${neigh}" dev "${devname}"
+
+               # set underlay network routes to reach the C-SID containers
+               # that start with a C-SID of the neighbor, for any Function.
+               csid="$(build_csid "${neigh}" 00)"
+               ip -netns "${nsname}" -6 route \
+                       add "${LCBLOCK_ADDR}:${csid}::/${LCBLOCK_NODE_BLEN}" \
+                       table "${LOCALSID_TABLE_ID}" \
+                       via "${net_prefix}::${neigh}" dev "${devname}"
        done
 
        # Local End behavior (note that "dev" is a dummy interface chosen for
@@ -461,6 +580,17 @@ setup_rt_local_sids()
                table "${LOCALSID_TABLE_ID}" \
                encap seg6local action End dev "${DUMMY_DEVNAME}"
 
+       # Local End behavior with the NEXT-C-SID and PSP flavors, bound to the
+       # C-SID of the router (e.g. fcbb:0:04a1::/48 on rt-4). The /48 prefix
+       # covers every C-SID container whose first C-SID is this one, whatever
+       # the Argument that follows.
+       csid="$(build_csid "${rt}" "${END_CSID_PSP_FUNC}")"
+       ip -netns "${nsname}" -6 route \
+               add "${LCBLOCK_ADDR}:${csid}::/${LCBLOCK_NODEFUNC_BLEN}" \
+               table "${LOCALSID_TABLE_ID}" \
+               encap seg6local action End flavors next-csid,psp \
+               lblen "${LCBLOCK_BLEN}" nflen "${LCNODEFUNC_BLEN}" \
+               dev "${DUMMY_DEVNAME}"
 
        # all SIDs start with a common locator. Routes and SRv6 Endpoint
        # behavior instances are grouped together in the 'localsid' table.
@@ -468,6 +598,12 @@ setup_rt_local_sids()
                add to "${LOCATOR_SERVICE}::/16" \
                lookup "${LOCALSID_TABLE_ID}" prio 999
 
+       # the C-SID containers use their own Locator-Block. Their routes and
+       # SRv6 Endpoint behavior instances are in the 'localsid' table too.
+       ip -netns "${nsname}" -6 rule \
+               add to "${LCBLOCK_ADDR}::/${LCBLOCK_BLEN}" \
+               lookup "${LOCALSID_TABLE_ID}" prio 999
+
        # set default routes to unreachable
        ip -netns "${nsname}" -6 route \
                add unreachable default metric 4278198272 \
@@ -479,12 +615,16 @@ setup_rt_local_sids()
 # configures the SRv6 nodes specified in the SID List to process the traffic
 # according to the operations required by the Policy itself.
 # args:
-#  $1 - destination host (i.e. cafe::x host)
+#  $1 - destination host (i.e. cafe::x host), or x:a1 for the address
+#       cafe::x:a1 on the loopback of the host
 #  $2 - SRv6 router configured for enforcing the SRv6 Policy
 #  $3 - compact way to represent a list of SRv6 routers with their operations
 #       (i.e. behaviors) that each of them needs to perform. Every <nodeid:op>
 #       element constructs a SID that is associated with the behavior <op> on
 #       the <nodeid> node. The list of such elements forms an SRv6 Policy.
+#       For "next-csid,psp", <nodeid> is a comma-separated list of node IDs.
+#       The element constructs a C-SID container with the C-SIDs of these
+#       nodes, e.g. "4,2:next-csid,psp" gives fcbb:0:04a1:02a1::.
 __setup_rt_policy()
 {
        local dst="$1"
@@ -494,6 +634,7 @@ __setup_rt_policy()
        local in_nsname
        local rt_nsname
        local policy=''
+       local container
        local function
        local fullsid
        local op_type
@@ -520,6 +661,15 @@ __setup_rt_policy()
                        behavior_cfg="End flavors psp"
                        ;;
 
+               "next-csid,psp")
+                       # the behavior is already set up on every router by
+                       # setup_rt_local_sids.
+                       container="$(build_csid_container "${node}" \
+                               "${END_CSID_PSP_FUNC}")"
+                       policy="${policy}${container},"
+                       continue
+                       ;;
+
                *)
                        break
                        ;;
@@ -571,6 +721,7 @@ setup_hs()
 
        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 exec "${hsname}" sysctl -wq net.ipv6.conf.all.seg6_enabled=0
 
        ip -netns "${hsname}" link add veth0 type veth \
                peer name "${RT2HS_DEVNAME}" netns "${rtname}"
@@ -590,6 +741,33 @@ setup_hs()
                sysctl -wq net.ipv6.conf."${RT2HS_DEVNAME}".proxy_ndp=1
 }
 
+# Set up an address on the loopback of a host, and the route towards it on the
+# router connected to the host.
+# args:
+#  $1 - host
+#  $2 - router connected to the host
+#  $3 - suffix of the address (i.e. cafe::<host>:<suffix>)
+setup_hs_lo_addr()
+{
+       local hs="$1"
+       local rt="$2"
+       local suffix="$3"
+       local hsname
+       local rtname
+       local addr
+
+       hsname="$(get_hsname "${hs}")"
+       rtname="$(get_rtname "${rt}")"
+       addr="${IPv6_HS_NETWORK}::${hs}:${suffix}"
+
+       ip -netns "${hsname}" addr \
+               add "${addr}/128" dev lo nodad
+
+       ip -netns "${rtname}" -6 route \
+               add "${addr}" \
+               via "${IPv6_HS_NETWORK}::${hs}" dev "${RT2HS_DEVNAME}"
+}
+
 setup()
 {
        local i
@@ -622,6 +800,11 @@ setup()
        setup_hs 1 1
        setup_hs 2 2
 
+       # set up the loopback addresses of the hosts used by the Policies (i.c)
+       # and (i.d).
+       setup_hs_lo_addr 1 1 "${END_CSID_PSP_FUNC}"
+       setup_hs_lo_addr 2 2 "${END_CSID_PSP_FUNC}"
+
        # set up default SRv6 Endpoints (i.e. SRv6 End behavior)
        setup_rt_local_sids 1 "2 3 4"
        setup_rt_local_sids 2 "1 3 4"
@@ -645,6 +828,21 @@ setup()
        setup_rt_policy_ipv6 2 1 "3:noflv 4:psp 2:psp"
        setup_rt_policy_ipv6 1 2 "1:psp"
 
+       # Direction hs-1 -> hs-2 (cafe::2:a1, NEXT-C-SID and PSP flavors)
+       #  - rt-1 (SRv6 H.Insert policy)
+       #  - rt-3 (Argument=0 and SL>1, acting as an End behavior)
+       #  - rt-4 (Argument!=0 and SL=1, advancing the C-SID)
+       #  - rt-2 (Argument=0 and SL=1, PSP)
+       #
+       # Direction hs-2 -> hs-1 (cafe::1:a1, NEXT-C-SID and PSP flavors)
+       #  - rt-2 (SRv6 H.Insert policy)
+       #  - rt-4 (Argument!=0 and SL=1, advancing the C-SID)
+       #  - rt-3 (Argument!=0 and SL=1, advancing the C-SID)
+       #  - rt-1 (Argument=0 and SL=1, PSP)
+       setup_rt_policy_ipv6 "2:${END_CSID_PSP_FUNC}" 1 \
+               "3:next-csid,psp 4,2:next-csid,psp"
+       setup_rt_policy_ipv6 "1:${END_CSID_PSP_FUNC}" 2 "4,3,1:next-csid,psp"
+
        # testing environment was set up successfully
        SETUP_ERR=0
 }
@@ -710,6 +908,20 @@ check_and_log_hs_connectivity()
        check_and_log_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
 }
 
+check_and_log_hs_lo_addr_connectivity()
+{
+       local hssrc="$1"
+       local hsdst="$2"
+       local suffix="$3"
+       local dst
+
+       dst="${IPv6_HS_NETWORK}::${hsdst}:${suffix}"
+
+       check_hs_ipv6_connectivity "${hssrc}" "${hsdst}:${suffix}"
+       log_test $? 0 \
+               "IPv6 Hosts connectivity: hs-${hssrc} -> hs-${hsdst} (${dst})"
+}
+
 router_tests()
 {
        local i
@@ -747,6 +959,14 @@ host_srv6_end_flv_psp_tests()
        check_and_log_hs_connectivity 2 1
 }
 
+host_srv6_end_flv_next_csid_psp_tests()
+{
+       log_section "SRv6 connectivity test hosts (h1 <-> h2, NEXT-C-SID,PSP)"
+
+       check_and_log_hs_lo_addr_connectivity 1 2 "${END_CSID_PSP_FUNC}"
+       check_and_log_hs_lo_addr_connectivity 2 1 "${END_CSID_PSP_FUNC}"
+}
+
 test_iproute2_supp_or_ksft_skip()
 {
        local flavor="$1"
@@ -836,6 +1056,8 @@ test_command_or_ksft_skip sort
 test_command_or_ksft_skip xargs
 
 test_dummy_dev_or_ksft_skip
+# NEXT-C-SID is not checked: every kernel and iproute2 version that
+# supports PSP also supports NEXT-C-SID.
 test_iproute2_supp_or_ksft_skip psp
 test_kernel_supp_or_ksft_skip psp
 
@@ -848,5 +1070,6 @@ set +e
 router_tests
 host2gateway_tests
 host_srv6_end_flv_psp_tests
+host_srv6_end_flv_next_csid_psp_tests
 
 print_log_test_results
-- 
2.43.0


Reply via email to