2 # SPDX-License-Identifier: GPL-2.0
7 # This script is designed for testing the support of NEXT-C-SID flavor for SRv6
9 # A basic knowledge of SRv6 architecture [1] and of the compressed SID approach
10 # [2] is assumed for the reader.
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:
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;
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;
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
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.
39 # [1] https://datatracker.ietf.org/doc/html/rfc8986
40 # [2] https://datatracker.ietf.org/doc/html/draft-ietf-spring-srv6-srh-compression
45 # +--------+ +--------+
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 |
56 # +---+----+ +----+---+
58 # | fcf0:0:1:3::/64 . |
61 # fcf0:0:1:4::/64 | . | fcf0:0:2:3::/64
64 # | fcf0:0:2:4::/64 . |
66 # +---+----+ +----+---+
68 # | rt-4 +-------------------+ rt-3 |
69 # | | fcf0:0:3:4::/64 | |
70 # +---+----+ +----+---+
72 # Every fcf0:0:x:y::/64 network interconnects the SRv6 routers rt-x with rt-y in
73 # the selftest network.
75 # Local SID/C-SID table
76 # =====================
78 # Each SRv6 router is configured with a Local SID/C-SID table in which
79 # SIDs/C-SIDs are stored. Considering an SRv6 router rt-x, SIDs/C-SIDs are
80 # configured in the Local SID/C-SIDs table as follows:
82 # Local SID/C-SID table for SRv6 router rt-x
83 # +-----------------------------------------------------------+
84 # |fcff:x::d46 is associated with the non-compressed SRv6 |
85 # | End.DT46 behavior |
86 # +-----------------------------------------------------------+
87 # |fcbb:0:0x00::/48 is associated with the NEXT-C-SID flavor |
88 # | of SRv6 End.X behavior |
89 # +-----------------------------------------------------------+
90 # |fcbb:0:0x00:d46::/64 is associated with the SRv6 End.DT46 |
91 # | behavior when NEXT-C-SID compression is turned on |
92 # +-----------------------------------------------------------+
94 # The fcff::/16 prefix is reserved for implementing SRv6 services with regular
95 # (non compressed) SIDs. Reachability of SIDs is ensured by proper configuration
96 # of the IPv6 routing tables in the routers.
97 # Similarly, the fcbb:0::/32 prefix is reserved for implementing SRv6 VPN
98 # services leveraging the NEXT-C-SID compression mechanism. Indeed, the
99 # fcbb:0::/32 is used for encoding the Locator-Block while the Locator-Node
100 # Function is encoded with 16 bits.
102 # Incoming traffic classification and application of SRv6 Policies
103 # ================================================================
105 # An SRv6 ingress router applies different SRv6 Policies to the traffic received
106 # from a connected host, considering the IPv4 or IPv6 destination address.
107 # SRv6 policy enforcement consists of encapsulating the received traffic into a
108 # new IPv6 packet with a given SID List contained in the SRH.
109 # When the SID List contains only one SID, the SRH could be omitted completely
110 # and that SID is stored directly in the IPv6 Destination Address (DA) (this is
111 # called "reduced" encapsulation).
113 # Test cases for NEXT-C-SID
114 # =========================
116 # We consider two test cases for NEXT-C-SID: i) single SID and ii) double SID.
118 # In the single SID test case we have a number of segments that are all
119 # contained in a single Compressed SID (C-SID) container. Therefore the
120 # resulting SID List has only one SID. Using the reduced encapsulation format
121 # this will result in a packet with no SRH.
123 # In the double SID test case we have one segment carried in a Compressed SID
124 # (C-SID) container, followed by a regular (non compressed) SID. The resulting
125 # SID List has two segments and it is possible to test the advance to the next
126 # SID when all the C-SIDs in a C-SID container have been processed. Using the
127 # reduced encapsulation format this will result in a packet with an SRH
128 # containing 1 segment.
130 # For the single SID test case, we use the IPv6 addresses of hs-1 and hs-2, for
131 # the double SID test case, we use their IPv4 addresses. This is only done to
132 # simplify the test setup and avoid adding other hosts or multiple addresses on
133 # the same interface of a host.
135 # Traffic from hs-1 to hs-2
136 # -------------------------
138 # Packets generated from hs-1 and directed towards hs-2 are handled by rt-1
139 # which applies the SRv6 Policies as follows:
141 # i) IPv6 DA=cafe::2, H.Encaps.Red with SID List=fcbb:0:0300:0200:d46::
142 # ii) IPv4 DA=10.0.0.2, H.Encaps.Red with SID List=fcbb:0:0300::,fcff:2::d46
146 # The router rt-1 is configured to enforce the given Policy through the SRv6
147 # H.Encaps.Red behavior which avoids the presence of the SRH at all, since it
148 # pushes the single SID directly in the IPv6 DA. Such a SID encodes a whole
149 # C-SID container carrying several C-SIDs (e.g. 0300, 0200, etc).
151 # As the packet reaches the router rt-3, the enabled NEXT-C-SID SRv6 End.X
152 # behavior (associated with fcbb:0:0300::/48) is triggered. This behavior
153 # analyzes the IPv6 DA and checks whether the Argument of the C-SID container
154 # is zero or not. In this case, the Argument is *NOT* zero and the IPv6 DA is
155 # updated as follows:
157 # +-----------------------------------------------------------------+
158 # | Before applying the rt-3 enabled NEXT-C-SID SRv6 End.X behavior |
159 # +-----------------------------------------------------------------+
160 # | +---------- Argument |
162 # | IPv6 DA fcbb:0:0300:0200:d46:: |
163 # | ^^^^ <-- shifting |
165 # | Locator-Node Function |
166 # +-----------------------------------------------------------------+
167 # | After applying the rt-3 enabled NEXT-C-SID SRv6 End.X behavior |
168 # +-----------------------------------------------------------------+
169 # | +---------- Argument |
171 # | IPv6 DA fcbb:0:0200:d46:: |
174 # | Locator-Node Function |
175 # +-----------------------------------------------------------------+
177 # After having applied the enabled NEXT-C-SID SRv6 End.X behavior, the packet
178 # is sent to rt-4 node using the L3 adjacency address fcf0:0:3:4::4.
180 # The node rt-4 performs a plain IPv6 forward to the rt-2 router according to
181 # its Local SID table and using the IPv6 DA fcbb:0:0200:d46:: .
183 # The router rt-2 is configured for decapsulating the inner IPv6 packet and,
184 # for this reason, it applies the SRv6 End.DT46 behavior on the received
185 # packet. It is worth noting that the SRv6 End.DT46 behavior does not require
186 # the presence of the SRH: it is fully capable to operate properly on
187 # IPv4/IPv6-in-IPv6 encapsulations.
188 # At the end of the decap operation, the packet is sent to the host hs-2.
192 # The router rt-1 is configured to enforce the given Policy through the SRv6
193 # H.Encaps.Red. As a result, the first SID fcbb:0:0300:: is stored into the
194 # IPv6 DA, while the SRH pushed into the packet is made of only one SID, i.e.
195 # fcff:2::d46. Hence, the packet sent by hs-1 to hs-2 is encapsulated in an
196 # outer IPv6 header plus the SRH.
198 # As the packet reaches the node rt-3, the router applies the enabled NEXT-C-SID
199 # SRv6 End.X behavior.
201 # +-----------------------------------------------------------------+
202 # | Before applying the rt-3 enabled NEXT-C-SID SRv6 End.X behavior |
203 # +-----------------------------------------------------------------+
204 # | +---------- Argument |
205 # | vvvv (Argument is all filled with zeros) |
206 # | IPv6 DA fcbb:0:0300:: |
209 # | Locator-Node Function |
210 # +-----------------------------------------------------------------+
211 # | After applying the rt-3 enabled NEXT-C-SID SRv6 End.X behavior |
212 # +-----------------------------------------------------------------+
214 # | IPv6 DA fcff:2::d46 |
217 # | SID copied from the SID List contained in the SRH |
218 # +-----------------------------------------------------------------+
220 # Since the Argument of the C-SID container is zero, the behavior can not
221 # update the Locator-Node function with the next C-SID carried in the Argument
222 # itself. Thus, the enabled NEXT-C-SID SRv6 End.X behavior operates as the
223 # traditional End.X behavior: it updates the IPv6 DA by copying the next
224 # available SID in the SID List carried by the SRH. Next, the packet is
225 # forwarded to the rt-4 node using the L3 adjacency fcf0:3:4::4 previously
226 # configured for this behavior.
228 # The node rt-4 performs a plain IPv6 forward to the rt-2 router according to
229 # its Local SID table and using the IPv6 DA fcff:2::d46.
231 # Once the packet is received by rt-2, the router decapsulates the inner IPv4
232 # packet using the SRv6 End.DT46 behavior (associated with the SID fcff:2::d46)
233 # and sends it to the host hs-2.
235 # Traffic from hs-2 to hs-1
236 # -------------------------
238 # Packets generated from hs-2 and directed towards hs-1 are handled by rt-2
239 # which applies the SRv6 Policies as follows:
241 # i) IPv6 DA=cafe::1, SID List=fcbb:0:0400:0100:d46::
242 # ii) IPv4 DA=10.0.0.1, SID List=fcbb:0:0300::,fcff:1::d46
246 # The node hs-2 sends an IPv6 packet directed to node hs-1. The router rt-2 is
247 # directly connected to hs-2 and receives the packet. Rt-2 applies the
248 # H.Encap.Red behavior with policy i) described above. Since there is only one
249 # SID, the SRH header is omitted and the policy is inserted directly into the DA
252 # The packet reaches the router rt-4 and the enabled NEXT-C-SID SRv6 End.X
253 # behavior (associated with fcbb:0:0400::/48) is triggered. This behavior
254 # analyzes the IPv6 DA and checks whether the Argument of the C-SID container
255 # is zero or not. The Argument is *NOT* zero and the C-SID in the IPv6 DA is
256 # advanced. At this point, the current IPv6 DA is fcbb:0:0100:d46:: .
257 # The enabled NEXT-C-SID SRv6 End.X behavior is configured with the L3 adjacency
258 # fcf0:0:1:4::1, used to route traffic to the rt-1 node.
260 # The router rt-1 is configured for decapsulating the inner packet. It applies
261 # the SRv6 End.DT46 behavior on the received packet. Decapsulation does not
262 # require the presence of the SRH. At the end of the decap operation, the packet
263 # is sent to the host hs-1.
267 # The router rt-2 is configured to enforce the given Policy through the SRv6
268 # H.Encaps.Red. As a result, the first SID fcbb:0:0300:: is stored into the
269 # IPv6 DA, while the SRH pushed into the packet is made of only one SID, i.e.
270 # fcff:1::d46. Hence, the packet sent by hs-2 to hs-1 is encapsulated in an
271 # outer IPv6 header plus the SRH.
273 # As the packet reaches the node rt-3, the enabled NEXT-C-SID SRv6 End.X
274 # behavior bound to the SID fcbb:0:0300::/48 is triggered.
275 # Since the Argument of the C-SID container is zero, the behavior can not
276 # update the Locator-Node function with the next C-SID carried in the Argument
277 # itself. Thus, the enabled NEXT-C-SID SRv6 End-X behavior operates as the
278 # traditional End.X behavior: it updates the IPv6 DA by copying the next
279 # available SID in the SID List carried by the SRH. After that, the packet is
280 # forwarded to the rt-4 node using the L3 adjacency (fcf0:3:4::4) previously
281 # configured for this behavior.
283 # The node rt-4 performs a plain IPv6 forward to the rt-1 router according to
284 # its Local SID table, considering the IPv6 DA fcff:1::d46.
286 # Once the packet is received by rt-1, the router decapsulates the inner IPv4
287 # packet using the SRv6 End.DT46 behavior (associated with the SID fcff:1::d46)
288 # and sends it to the host hs-1.
290 # Kselftest framework requirement - SKIP code is 4.
293 readonly RDMSUFF="$(mktemp -u XXXXXXXX)"
294 readonly DUMMY_DEVNAME="dum0"
296 readonly VRF_DEVNAME="vrf-${VRF_TID}"
297 readonly RT2HS_DEVNAME="veth-t${VRF_TID}"
298 readonly LOCALSID_TABLE_ID=90
299 readonly IPv6_RT_NETWORK=fcf0:0
300 readonly IPv6_HS_NETWORK=cafe
301 readonly IPv4_HS_NETWORK=10.0.0
302 readonly VPN_LOCATOR_SERVICE=fcff
303 readonly DT46_FUNC=0d46
304 readonly HEADEND_ENCAP="encap.red"
306 # do not add ':' as separator
307 readonly LCBLOCK_ADDR=fcbb0000
308 readonly LCBLOCK_BLEN=32
309 # do not add ':' as separator
310 readonly LCNODEFUNC_FMT="0%d00"
311 readonly LCNODEFUNC_BLEN=16
313 readonly LCBLOCK_NODEFUNC_BLEN=$((LCBLOCK_BLEN + LCNODEFUNC_BLEN))
315 readonly CSID_CNTR_PREFIX="dead:beaf::/32"
316 # ID of the router used for testing the C-SID container cfgs
317 readonly CSID_CNTR_RT_ID_TEST=1
318 # Routing table used for testing the C-SID container cfgs
319 readonly CSID_CNTR_RT_TABLE=91
321 # C-SID container configurations to be tested
323 # An entry of the array is defined as "a,b,c" where:
324 # - 'a' and 'b' elements represent respectively the Locator-Block length
325 # (lblen) in bits and the Locator-Node Function length (nflen) in bits.
326 # 'a' and 'b' can be set to default values using the placeholder "d" which
327 # indicates the default kernel values (32 for lblen and 16 for nflen);
328 # otherwise, any numeric value is accepted;
329 # - 'c' indicates whether the C-SID configuration provided by the values 'a'
330 # and 'b' should be considered valid ("y") or invalid ("n").
331 declare -ra CSID_CONTAINER_CFGS=(
355 PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
357 # IDs of routers and hosts are initialized during the setup of the testing
374 if [ "${rc}" -eq "${expected}" ]; then
375 nsuccess=$((nsuccess+1))
376 printf "\n TEST: %-60s [ OK ]\n" "${msg}"
380 printf "\n TEST: %-60s [FAIL]\n" "${msg}"
381 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
383 echo "hit enter to continue, 'q' to quit"
385 [ "$a" = "q" ] && exit 1
390 print_log_test_results()
392 printf "\nTests passed: %3d\n" "${nsuccess}"
393 printf "Tests failed: %3d\n" "${nfail}"
395 # when a test fails, the value of 'ret' is set to 1 (error code).
396 # Conversely, when all tests are passed successfully, the 'ret' value
397 # is set to 0 (success code).
398 if [ "${ret}" -ne 1 ]; then
406 echo "################################################################################"
407 echo "TEST SECTION: $*"
408 echo "################################################################################"
411 test_command_or_ksft_skip()
415 if [ ! -x "$(command -v "${cmd}")" ]; then
416 echo "SKIP: Could not run test without \"${cmd}\" tool";
425 echo "${name}-${RDMSUFF}"
432 get_nodename "rt-${rtid}"
439 get_nodename "hs-${hsid}"
446 ip netns add "${name}"
454 nsname="$(get_rtname "${rtid}")"
456 __create_namespace "${nsname}"
458 ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
459 ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
460 ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.forwarding=1
462 ip netns exec "${nsname}" sysctl -wq net.ipv4.conf.all.rp_filter=0
463 ip netns exec "${nsname}" sysctl -wq net.ipv4.conf.default.rp_filter=0
464 ip netns exec "${nsname}" sysctl -wq net.ipv4.ip_forward=1
472 nsname="$(get_hsname "${hsid}")"
474 __create_namespace "${nsname}"
483 for i in ${ROUTERS}; do
484 nsname="$(get_rtname "${i}")"
486 ip netns del "${nsname}" &>/dev/null || true
490 for i in ${HOSTS}; do
491 nsname="$(get_hsname "${i}")"
493 ip netns del "${nsname}" &>/dev/null || true
496 # check whether the setup phase was completed successfully or not. In
497 # case of an error during the setup phase of the testing environment,
498 # the selftest is considered as "skipped".
499 if [ "${SETUP_ERR}" -ne 0 ]; then
500 echo "SKIP: Setting up the testing environment failed"
515 nsname="$(get_rtname "${rt}")"
517 for neigh in ${rt_neighs}; do
518 neigh_nsname="$(get_rtname "${neigh}")"
520 ip link add "veth-rt-${rt}-${neigh}" netns "${nsname}" \
521 type veth peer name "veth-rt-${neigh}-${rt}" \
522 netns "${neigh_nsname}"
533 if [ "${p}" -gt "${q}" ]; then
537 echo "${IPv6_RT_NETWORK}:${p}:${q}"
540 # Setup the basic networking for the routers
541 setup_rt_networking()
550 nsname="$(get_rtname "${rt}")"
552 for neigh in ${rt_neighs}; do
553 devname="veth-rt-${rt}-${neigh}"
555 net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
557 ip -netns "${nsname}" addr \
558 add "${net_prefix}::${rt}/64" dev "${devname}" nodad
560 ip -netns "${nsname}" link set "${devname}" up
563 ip -netns "${nsname}" link add "${DUMMY_DEVNAME}" type dummy
565 ip -netns "${nsname}" link set "${DUMMY_DEVNAME}" up
566 ip -netns "${nsname}" link set lo up
569 # build an ipv6 prefix/address based on the input string
570 # Note that the input string does not contain ':' and '::' which are considered
573 # - input: fbcc00000400300
574 # - output: fbcc:0000:0400:0300:0000:0000:0000:0000
575 # ^^^^^^^^^^^^^^^^^^^
576 # fill the address with 0s
581 local strlen="${#addr}"
585 # add ":" every 4 digits (16 bits)
586 for (( i = 0; i < strlen; i++ )); do
587 if (( i > 0 && i < 32 && (i % 4) == 0 )); then
591 out="${out}${addr:$i:1}"
594 # fill the remaining bits of the address with 0s
595 padn=$((32 - strlen))
596 for (( i = padn; i > 0; i-- )); do
597 if (( i > 0 && i < 32 && (i % 4) == 0 )); then
611 printf "${LCNODEFUNC_FMT}" "${nodeid}"
614 build_lcnode_func_prefix()
621 lcnodefunc="$(build_csid "${nodeid}")"
622 prefix="$(build_ipv6_addr "${LCBLOCK_ADDR}${lcnodefunc}")"
624 out="${prefix}/${LCBLOCK_NODEFUNC_BLEN}"
634 nsname="$(get_rtname "${rt}")"
635 net_prefix="$(get_network_prefix "${rt}" "${adj}")"
636 lcnode_func_prefix="$(build_lcnode_func_prefix "${rt}")"
638 # enabled NEXT-C-SID SRv6 End.X behavior (note that "dev" is the dummy
639 # dum0 device chosen for the sake of simplicity).
640 ip -netns "${nsname}" -6 route \
641 replace "${lcnode_func_prefix}" \
642 table "${LOCALSID_TABLE_ID}" \
643 encap seg6local action End.X nh6 "${net_prefix}::${adj}" \
644 flavors next-csid lblen "${LCBLOCK_BLEN}" \
645 nflen "${LCNODEFUNC_BLEN}" dev "${DUMMY_DEVNAME}"
648 set_underlay_sids_reachability()
653 nsname="$(get_rtname "${rt}")"
655 for neigh in ${rt_neighs}; do
656 devname="veth-rt-${rt}-${neigh}"
658 net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
660 # set underlay network routes for SIDs reachability
661 ip -netns "${nsname}" -6 route \
662 replace "${VPN_LOCATOR_SERVICE}:${neigh}::/32" \
663 table "${LOCALSID_TABLE_ID}" \
664 via "${net_prefix}::${neigh}" dev "${devname}"
666 # set the underlay network for C-SIDs reachability
667 lcnode_func_prefix="$(build_lcnode_func_prefix "${neigh}")"
669 ip -netns "${nsname}" -6 route \
670 replace "${lcnode_func_prefix}" \
671 table "${LOCALSID_TABLE_ID}" \
672 via "${net_prefix}::${neigh}" dev "${devname}"
676 # Setup local SIDs for an SRv6 router
677 setup_rt_local_sids()
685 local lcnode_func_prefix
688 nsname="$(get_rtname "${rt}")"
690 set_underlay_sids_reachability "${rt}" "${rt_neighs}"
692 # all SIDs for VPNs start with a common locator. Routes and SRv6
693 # Endpoint behavior instaces are grouped together in the 'localsid'
695 ip -netns "${nsname}" -6 rule \
696 add to "${VPN_LOCATOR_SERVICE}::/16" \
697 lookup "${LOCALSID_TABLE_ID}" prio 999
699 # common locator block for NEXT-C-SIDS compression mechanism.
700 lcblock_prefix="$(build_ipv6_addr "${LCBLOCK_ADDR}")"
701 ip -netns "${nsname}" -6 rule \
702 add to "${lcblock_prefix}/${LCBLOCK_BLEN}" \
703 lookup "${LOCALSID_TABLE_ID}" prio 999
706 # build and install the SRv6 policy into the ingress SRv6 router as well as the
707 # decap SID in the egress one.
709 # $1 - src host (evaluate automatically the ingress router)
710 # $2 - dst host (evaluate automatically the egress router)
711 # $3 - SRv6 routers configured for steering traffic (End.X behaviors)
712 # $4 - single SID or double SID
713 # $5 - traffic type (IPv6 or IPv4)
731 rtsrc_nsname="$(get_rtname "${src}")"
732 rtdst_nsname="$(get_rtname "${dst}")"
734 container="${LCBLOCK_ADDR}"
736 # build first SID (C-SID container)
737 for n in ${end_rts}; do
738 lcnfunc="$(build_csid "${n}")"
740 container="${container}${lcnfunc}"
743 if [ "${mode}" -eq 1 ]; then
745 dt="$(build_csid "${dst}")${DT46_FUNC}"
746 container="${container}${dt}"
747 # build the full ipv6 address for the container
748 policy="$(build_ipv6_addr "${container}")"
750 # build the decap SID used in the decap node
751 container="${LCBLOCK_ADDR}${dt}"
752 decapsid="$(build_ipv6_addr "${container}")"
755 decapsid="${VPN_LOCATOR_SERVICE}:${dst}::${DT46_FUNC}"
757 policy="$(build_ipv6_addr "${container}"),${decapsid}"
761 if [ "${traffic}" -eq 6 ]; then
762 ip -netns "${rtsrc_nsname}" -6 route \
763 add "${IPv6_HS_NETWORK}::${dst}" vrf "${VRF_DEVNAME}" \
764 encap seg6 mode "${HEADEND_ENCAP}" segs "${policy}" \
767 ip -netns "${rtsrc_nsname}" -6 neigh \
768 add proxy "${IPv6_HS_NETWORK}::${dst}" \
769 dev "${RT2HS_DEVNAME}"
771 # "dev" must be different from the one where the packet is
772 # received, otherwise the proxy arp does not work.
773 ip -netns "${rtsrc_nsname}" -4 route \
774 add "${IPv4_HS_NETWORK}.${dst}" vrf "${VRF_DEVNAME}" \
775 encap seg6 mode "${HEADEND_ENCAP}" segs "${policy}" \
780 # Local End.DT46 behavior (decap)
781 ip -netns "${rtdst_nsname}" -6 route \
783 table "${LOCALSID_TABLE_ID}" \
784 encap seg6local action End.DT46 vrftable "${VRF_TID}" \
788 # see __setup_l3vpn()
789 setup_ipv4_vpn_2sids()
791 __setup_l3vpn "$1" "$2" "$3" 2 4
794 # see __setup_l3vpn()
795 setup_ipv6_vpn_1sid()
797 __setup_l3vpn "$1" "$2" "$3" 1 6
807 hsname="$(get_hsname "${hs}")"
808 rtname="$(get_rtname "${rt}")"
810 ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
811 ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
813 ip -netns "${hsname}" link add veth0 type veth \
814 peer name "${RT2HS_DEVNAME}" netns "${rtname}"
816 ip -netns "${hsname}" addr \
817 add "${IPv6_HS_NETWORK}::${hs}/64" dev veth0 nodad
818 ip -netns "${hsname}" addr add "${IPv4_HS_NETWORK}.${hs}/24" dev veth0
820 ip -netns "${hsname}" link set veth0 up
821 ip -netns "${hsname}" link set lo up
823 # configure the VRF on the router which is directly connected to the
825 ip -netns "${rtname}" link \
826 add "${VRF_DEVNAME}" type vrf table "${VRF_TID}"
827 ip -netns "${rtname}" link set "${VRF_DEVNAME}" up
829 # enslave the veth interface connecting the router with the host to the
830 # VRF in the access router
831 ip -netns "${rtname}" link \
832 set "${RT2HS_DEVNAME}" master "${VRF_DEVNAME}"
834 # set default routes to unreachable for both ipv6 and ipv4
835 ip -netns "${rtname}" -6 route \
836 add unreachable default metric 4278198272 \
838 ip -netns "${rtname}" -4 route \
839 add unreachable default metric 4278198272 \
842 ip -netns "${rtname}" addr \
843 add "${IPv6_HS_NETWORK}::254/64" dev "${RT2HS_DEVNAME}" nodad
844 ip -netns "${rtname}" addr \
845 add "${IPv4_HS_NETWORK}.254/24" dev "${RT2HS_DEVNAME}"
847 ip -netns "${rtname}" link set "${RT2HS_DEVNAME}" up
849 ip netns exec "${rtname}" \
850 sysctl -wq net.ipv6.conf."${RT2HS_DEVNAME}".proxy_ndp=1
851 ip netns exec "${rtname}" \
852 sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".proxy_arp=1
854 # disable the rp_filter otherwise the kernel gets confused about how
855 # to route decap ipv4 packets.
856 ip netns exec "${rtname}" \
857 sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".rp_filter=0
859 ip netns exec "${rtname}" sh -c "echo 1 > /proc/sys/net/vrf/strict_mode"
867 ROUTERS="1 2 3 4"; readonly ROUTERS
868 for i in ${ROUTERS}; do
873 HOSTS="1 2"; readonly HOSTS
874 for i in ${HOSTS}; do
878 # set up the links for connecting routers
879 add_link_rt_pairs 1 "2 3 4"
880 add_link_rt_pairs 2 "3 4"
881 add_link_rt_pairs 3 "4"
883 # set up the basic connectivity of routers and routes required for
884 # reachability of SIDs.
885 setup_rt_networking 1 "2 3 4"
886 setup_rt_networking 2 "1 3 4"
887 setup_rt_networking 3 "1 2 4"
888 setup_rt_networking 4 "1 2 3"
890 # set up the hosts connected to routers
894 # set up default SRv6 Endpoints (i.e. SRv6 End and SRv6 End.DT46)
895 setup_rt_local_sids 1 "2 3 4"
896 setup_rt_local_sids 2 "1 3 4"
897 setup_rt_local_sids 3 "1 2 4"
898 setup_rt_local_sids 4 "1 2 3"
900 # set up SRv6 Policies
902 # create an IPv6 VPN between hosts hs-1 and hs-2.
904 # Direction hs-1 -> hs-2
905 # - rt-1 encap (H.Encaps.Red)
906 # - rt-3 SRv6 End.X behavior adj rt-4 (NEXT-C-SID flavor)
907 # - rt-4 Plain IPv6 Forwarding to rt-2
908 # - rt-2 SRv6 End.DT46 behavior
909 setup_ipv6_vpn_1sid 1 2 "3"
911 # Direction hs2 -> hs-1
912 # - rt-2 encap (H.Encaps.Red)
913 # - rt-4 SRv6 End.X behavior adj rt-1 (NEXT-C-SID flavor)
914 # - rt-1 SRv6 End.DT46 behavior
915 setup_ipv6_vpn_1sid 2 1 "4"
917 # create an IPv4 VPN between hosts hs-1 and hs-2
919 # Direction hs-1 -> hs-2
920 # - rt-1 encap (H.Encaps.Red)
921 # - rt-3 SRv6 End.X behavior adj rt-4 (NEXT-C-SID flavor)
922 # - rt-4 Plain IPv6 Forwarding to rt-2
923 # - rt-2 SRv6 End.DT46 behavior
924 setup_ipv4_vpn_2sids 1 2 "3"
926 # Direction hs-2 -> hs-1
927 # - rt-2 encap (H.Encaps.Red)
928 # - rt-3 SRv6 End.X behavior adj rt-4 (NEXT-C-SID flavor)
929 # - rt-4 Plain IPv6 Forwarding to rt-1
930 # - rt-1 SRv6 End.DT46 behavior
931 setup_ipv4_vpn_2sids 2 1 "3"
933 # Setup the adjacencies in the SRv6 aware routers
934 # - rt-3 SRv6 End.X adjacency with rt-4
935 # - rt-4 SRv6 End.X adjacency with rt-1
936 set_end_x_nextcsid 3 4
937 set_end_x_nextcsid 4 1
939 # testing environment was set up successfully
943 check_rt_connectivity()
950 rtsrc_nsname="$(get_rtname "${rtsrc}")"
952 prefix="$(get_network_prefix "${rtsrc}" "${rtdst}")"
954 ip netns exec "${rtsrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
955 "${prefix}::${rtdst}" >/dev/null 2>&1
958 check_and_log_rt_connectivity()
963 check_rt_connectivity "${rtsrc}" "${rtdst}"
964 log_test $? 0 "Routers connectivity: rt-${rtsrc} -> rt-${rtdst}"
967 check_hs_ipv6_connectivity()
973 hssrc_nsname="$(get_hsname "${hssrc}")"
975 ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
976 "${IPv6_HS_NETWORK}::${hsdst}" >/dev/null 2>&1
979 check_hs_ipv4_connectivity()
985 hssrc_nsname="$(get_hsname "${hssrc}")"
987 ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
988 "${IPv4_HS_NETWORK}.${hsdst}" >/dev/null 2>&1
991 check_and_log_hs2gw_connectivity()
995 check_hs_ipv6_connectivity "${hssrc}" 254
996 log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> gw"
998 check_hs_ipv4_connectivity "${hssrc}" 254
999 log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> gw"
1002 check_and_log_hs_ipv6_connectivity()
1007 check_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
1008 log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"
1011 check_and_log_hs_ipv4_connectivity()
1016 check_hs_ipv4_connectivity "${hssrc}" "${hsdst}"
1017 log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"
1025 log_section "IPv6 routers connectivity test"
1027 for i in ${ROUTERS}; do
1028 for j in ${ROUTERS}; do
1029 if [ "${i}" -eq "${j}" ]; then
1033 check_and_log_rt_connectivity "${i}" "${j}"
1038 host2gateway_tests()
1042 log_section "IPv4/IPv6 connectivity test among hosts and gateways"
1044 for hs in ${HOSTS}; do
1045 check_and_log_hs2gw_connectivity "${hs}"
1051 log_section "SRv6 VPN connectivity test hosts (h1 <-> h2, IPv6)"
1053 check_and_log_hs_ipv6_connectivity 1 2
1054 check_and_log_hs_ipv6_connectivity 2 1
1056 log_section "SRv6 VPN connectivity test hosts (h1 <-> h2, IPv4)"
1058 check_and_log_hs_ipv4_connectivity 1 2
1059 check_and_log_hs_ipv4_connectivity 2 1
1062 __nextcsid_end_x_behavior_test()
1070 if [ "${blen}" != "d" ]; then
1071 layout="${layout} lblen ${blen}"
1074 if [ "${flen}" != "d" ]; then
1075 layout="${layout} nflen ${flen}"
1078 ip -netns "${nsname}" -6 route \
1079 "${cmd}" "${CSID_CNTR_PREFIX}" \
1080 table "${CSID_CNTR_RT_TABLE}" \
1081 encap seg6local action End.X nh6 :: \
1082 flavors next-csid ${layout} \
1083 dev "${DUMMY_DEVNAME}" &>/dev/null
1088 rt_x_nextcsid_end_x_behavior_test()
1096 nsname="$(get_rtname "${rt}")"
1098 __nextcsid_end_x_behavior_test "${nsname}" "add" "${blen}" "${flen}"
1100 __nextcsid_end_x_behavior_test "${nsname}" "del" "${blen}" "${flen}"
1105 __parse_csid_container_cfg()
1111 echo "${cfg}" | cut -d',' -f"${index}"
1114 csid_container_cfg_tests()
1122 log_section "C-SID Container config tests (legend: d='kernel default')"
1124 for cfg in "${CSID_CONTAINER_CFGS[@]}"; do
1125 blen="$(__parse_csid_container_cfg "${cfg}" 1)"
1126 flen="$(__parse_csid_container_cfg "${cfg}" 2)"
1127 valid="$(__parse_csid_container_cfg "${cfg}" 3)"
1129 rt_x_nextcsid_end_x_behavior_test \
1130 "${CSID_CNTR_RT_ID_TEST}" \
1135 if [ "${valid}" == "y" ]; then
1136 log_test "${ret}" 0 \
1137 "Accept valid C-SID container cfg (lblen=${blen}, nflen=${flen})"
1139 log_test "${ret}" 2 \
1140 "Reject invalid C-SID container cfg (lblen=${blen}, nflen=${flen})"
1145 test_iproute2_supp_or_ksft_skip()
1147 if ! ip route help 2>&1 | grep -qo "next-csid"; then
1148 echo "SKIP: Missing SRv6 NEXT-C-SID flavor support in iproute2"
1153 test_dummy_dev_or_ksft_skip()
1157 test_netns="dummy-$(mktemp -u XXXXXXXX)"
1159 if ! ip netns add "${test_netns}"; then
1160 echo "SKIP: Cannot set up netns for testing dummy dev support"
1164 modprobe dummy &>/dev/null || true
1165 if ! ip -netns "${test_netns}" link \
1166 add "${DUMMY_DEVNAME}" type dummy; then
1167 echo "SKIP: dummy dev not supported"
1169 ip netns del "${test_netns}"
1173 ip netns del "${test_netns}"
1176 test_vrf_or_ksft_skip()
1178 modprobe vrf &>/dev/null || true
1179 if [ ! -e /proc/sys/net/vrf/strict_mode ]; then
1180 echo "SKIP: vrf sysctl does not exist"
1185 if [ "$(id -u)" -ne 0 ]; then
1186 echo "SKIP: Need root privileges"
1190 # required programs to carry out this selftest
1191 test_command_or_ksft_skip ip
1192 test_command_or_ksft_skip ping
1193 test_command_or_ksft_skip sysctl
1194 test_command_or_ksft_skip grep
1195 test_command_or_ksft_skip cut
1197 test_iproute2_supp_or_ksft_skip
1198 test_dummy_dev_or_ksft_skip
1199 test_vrf_or_ksft_skip
1207 csid_container_cfg_tests
1213 print_log_test_results