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 to test the support for "flavors" in the SRv6 End
8# behavior.
9#
10# Flavors defined in RFC8986 [1] represent additional operations that can modify
11# or extend the existing SRv6 End, End.X and End.T behaviors. For the sake of
12# convenience, we report the list of flavors described in [1] hereafter:
13#   - Penultimate Segment Pop (PSP);
14#   - Ultimate Segment Pop (USP);
15#   - Ultimate Segment Decapsulation (USD).
16#
17# The End, End.X, and End.T behaviors can support these flavors either
18# individually or in combinations.
19# Currently in this selftest we consider only the PSP flavor for the SRv6 End
20# behavior. However, it is possible to extend the script as soon as other
21# flavors will be supported in the kernel.
22#
23# The purpose of the PSP flavor consists in instructing the penultimate node
24# listed in the SRv6 policy to remove (i.e. pop) the outermost SRH from the IPv6
25# header.
26# A PSP enabled SRv6 End behavior instance processes the SRH by:
27#  - decrementing the Segment Left (SL) value from 1 to 0;
28#  - copying the last SID from the SID List into the IPv6 Destination Address
29#    (DA);
30#  - removing the SRH from the extension headers following the IPv6 header.
31#
32# Once the SRH is removed, the IPv6 packet is forwarded to the destination using
33# the IPv6 DA updated during the PSP operation (i.e. the IPv6 DA corresponding
34# to the last SID carried by the removed SRH).
35#
36# Although the PSP flavor can be set for any SRv6 End behavior instance on any
37# SR node, it will be active only on such behaviors bound to a penultimate SID
38# for a given SRv6 policy.
39#                                                SL=2 SL=1 SL=0
40#                                                  |    |    |
41# For example, given the SRv6 policy (SID List := <X,   Y,   Z>):
42#  - a PSP enabled SRv6 End behavior bound to SID Y will apply the PSP operation
43#    as Segment Left (SL) is 1, corresponding to the Penultimate Segment of the
44#    SID List;
45#  - a PSP enabled SRv6 End behavior bound to SID X will *NOT* apply the PSP
46#    operation as the Segment Left is 2. This behavior instance will apply the
47#    "standard" End packet processing, ignoring the configured PSP flavor at
48#    all.
49#
50# [1] RFC8986: https://datatracker.ietf.org/doc/html/rfc8986
51#
52# Network topology
53# ================
54#
55# The network topology used in this selftest is depicted hereafter, composed by
56# two hosts (hs-1, hs-2) and four routers (rt-1, rt-2, rt-3, rt-4).
57# Hosts hs-1 and hs-2 are connected to routers rt-1 and rt-2, respectively,
58# allowing them to communicate with each other.
59# Traffic exchanged between hs-1 and hs-2 can follow different network paths.
60# The network operator, through specific SRv6 Policies can steer traffic to one
61# path rather than another. In this selftest this is implemented as follows:
62#
63#   i) The SRv6 H.Insert behavior applies SRv6 Policies on traffic received by
64#      connected hosts. It pushes the Segment Routing Header (SRH) after the
65#      IPv6 header. The SRH contains the SID List (i.e. SRv6 Policy) needed for
66#      steering traffic across the segments/waypoints specified in that list;
67#
68#  ii) The SRv6 End behavior advances the active SID in the SID List carried by
69#      the SRH;
70#
71# iii) The PSP enabled SRv6 End behavior is used to remove the SRH when such
72#      behavior is configured on a node bound to the Penultimate Segment carried
73#      by the SID List.
74#
75#                cafe::1                      cafe::2
76#              +--------+                   +--------+
77#              |        |                   |        |
78#              |  hs-1  |                   |  hs-2  |
79#              |        |                   |        |
80#              +---+----+                   +--- +---+
81#     cafe::/64    |                             |      cafe::/64
82#                  |                             |
83#              +---+----+                   +----+---+
84#              |        |  fcf0:0:1:2::/64  |        |
85#              |  rt-1  +-------------------+  rt-2  |
86#              |        |                   |        |
87#              +---+----+                   +----+---+
88#                  |      .               .      |
89#                  |  fcf0:0:1:3::/64   .        |
90#                  |          .       .          |
91#                  |            .   .            |
92#  fcf0:0:1:4::/64 |              .              | fcf0:0:2:3::/64
93#                  |            .   .            |
94#                  |          .       .          |
95#                  |  fcf0:0:2:4::/64   .        |
96#                  |      .               .      |
97#              +---+----+                   +----+---+
98#              |        |                   |        |
99#              |  rt-4  +-------------------+  rt-3  |
100#              |        |  fcf0:0:3:4::/64  |        |
101#              +---+----+                   +----+---+
102#
103# Every fcf0:0:x:y::/64 network interconnects the SRv6 routers rt-x with rt-y in
104# the IPv6 operator network.
105#
106#
107# Local SID table
108# ===============
109#
110# Each SRv6 router is configured with a Local SID table in which SIDs are
111# stored. Considering the given SRv6 router rt-x, at least two SIDs are
112# configured in the Local SID table:
113#
114#   Local SID table for SRv6 router rt-x
115#   +---------------------------------------------------------------------+
116#   |fcff:x::e is associated with the SRv6 End behavior                   |
117#   |fcff:x::ef1 is associated with the SRv6 End behavior with PSP flavor |
118#   +---------------------------------------------------------------------+
119#
120# The fcff::/16 prefix is reserved by the operator for the SIDs. Reachability of
121# SIDs is ensured by proper configuration of the IPv6 operator's network and
122# SRv6 routers.
123#
124#
125# SRv6 Policies
126# =============
127#
128# An SRv6 ingress router applies different SRv6 Policies to the traffic received
129# from connected hosts on the basis of the destination addresses.
130# In case of SRv6 H.Insert behavior, the SRv6 Policy enforcement consists of
131# pushing the SRH (carrying a given SID List) after the existing IPv6 header.
132# Note that in the inserting mode, there is no encapsulation at all.
133#
134#   Before applying an SRv6 Policy using the SRv6 H.Insert behavior
135#   +------+---------+
136#   | IPv6 | Payload |
137#   +------+---------+
138#
139#   After applying an SRv6 Policy using the SRv6 H.Insert behavior
140#   +------+-----+---------+
141#   | IPv6 | SRH | Payload |
142#   +------+-----+---------+
143#
144# Traffic from hs-1 to hs-2
145# -------------------------
146#
147# Packets generated from hs-1 and directed towards hs-2 are
148# handled by rt-1 which applies the following SRv6 Policy:
149#
150#   i.a) IPv6 traffic, SID List=fcff:3::e,fcff:4::ef1,fcff:2::ef1,cafe::2
151#
152# Router rt-1 is configured to enforce the Policy (i.a) through the SRv6
153# H.Insert behavior which pushes the SRH after the existing IPv6 header. This
154# Policy steers the traffic from hs-1 across rt-3, rt-4, rt-2 and finally to the
155# destination hs-2.
156#
157# As the packet reaches the router rt-3, the SRv6 End behavior bound to SID
158# fcff:3::e is triggered. The behavior updates the Segment Left (from SL=3 to
159# SL=2) in the SRH, the IPv6 DA with fcff:4::ef1 and forwards the packet to the
160# next router on the path, i.e. rt-4.
161#
162# When router rt-4 receives the packet, the PSP enabled SRv6 End behavior bound
163# to SID fcff:4::ef1 is executed. Since the SL=2, the PSP operation is *NOT*
164# kicked in and the behavior applies the default End processing: the Segment
165# Left is decreased (from SL=2 to SL=1), the IPv6 DA is updated with the SID
166# fcff:2::ef1 and the packet is forwarded to router rt-2.
167#
168# The PSP enabled SRv6 End behavior on rt-2 is associated with SID fcff:2::ef1
169# and is executed as the packet is received. Because SL=1, the behavior applies
170# the PSP processing on the packet as follows: i) SL is decreased, i.e. from
171# SL=1 to SL=0; ii) last SID (cafe::2) is copied into the IPv6 DA; iii) the
172# outermost SRH is removed from the extension headers following the IPv6 header.
173# Once the PSP processing is completed, the packet is forwarded to the host hs-2
174# (destination).
175#
176# Traffic from hs-2 to hs-1
177# -------------------------
178#
179# Packets generated from hs-2 and directed to hs-1 are handled by rt-2 which
180# applies the following SRv6 Policy:
181#
182#   i.b) IPv6 traffic, SID List=fcff:1::ef1,cafe::1
183#
184# Router rt-2 is configured to enforce the Policy (i.b) through the SRv6
185# H.Insert behavior which pushes the SRH after the existing IPv6 header. This
186# Policy steers the traffic from hs-2 across rt-1 and finally to the
187# destination hs-1
188#
189#
190# When the router rt-1 receives the packet, the PSP enabled SRv6 End behavior
191# associated with the SID fcff:1::ef1 is triggered. Since the SL=1,
192# the PSP operation takes place: i) the SL is decremented; ii) the IPv6 DA is
193# set with the last SID; iii) the SRH is removed from the extension headers
194# after the IPv6 header. At this point, the packet with IPv6 DA=cafe::1 is sent
195# to the destination, i.e. hs-1.
196
197# Kselftest framework requirement - SKIP code is 4.
198readonly ksft_skip=4
199
200readonly RDMSUFF="$(mktemp -u XXXXXXXX)"
201readonly DUMMY_DEVNAME="dum0"
202readonly RT2HS_DEVNAME="veth1"
203readonly LOCALSID_TABLE_ID=90
204readonly IPv6_RT_NETWORK=fcf0:0
205readonly IPv6_HS_NETWORK=cafe
206readonly IPv6_TESTS_ADDR=2001:db8::1
207readonly LOCATOR_SERVICE=fcff
208readonly END_FUNC=000e
209readonly END_PSP_FUNC=0ef1
210
211PING_TIMEOUT_SEC=4
212PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
213
214# IDs of routers and hosts are initialized during the setup of the testing
215# network
216ROUTERS=''
217HOSTS=''
218
219SETUP_ERR=1
220
221ret=${ksft_skip}
222nsuccess=0
223nfail=0
224
225log_test()
226{
227	local rc="$1"
228	local expected="$2"
229	local msg="$3"
230
231	if [ "${rc}" -eq "${expected}" ]; then
232		nsuccess=$((nsuccess+1))
233		printf "\n    TEST: %-60s  [ OK ]\n" "${msg}"
234	else
235		ret=1
236		nfail=$((nfail+1))
237		printf "\n    TEST: %-60s  [FAIL]\n" "${msg}"
238		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
239			echo
240			echo "hit enter to continue, 'q' to quit"
241			read a
242			[ "$a" = "q" ] && exit 1
243		fi
244	fi
245}
246
247print_log_test_results()
248{
249	printf "\nTests passed: %3d\n" "${nsuccess}"
250	printf "Tests failed: %3d\n"   "${nfail}"
251
252	# when a test fails, the value of 'ret' is set to 1 (error code).
253	# Conversely, when all tests are passed successfully, the 'ret' value
254	# is set to 0 (success code).
255	if [ "${ret}" -ne 1 ]; then
256		ret=0
257	fi
258}
259
260log_section()
261{
262	echo
263	echo "################################################################################"
264	echo "TEST SECTION: $*"
265	echo "################################################################################"
266}
267
268test_command_or_ksft_skip()
269{
270	local cmd="$1"
271
272	if [ ! -x "$(command -v "${cmd}")" ]; then
273		echo "SKIP: Could not run test without \"${cmd}\" tool";
274		exit "${ksft_skip}"
275	fi
276}
277
278get_nodename()
279{
280	local name="$1"
281
282	echo "${name}-${RDMSUFF}"
283}
284
285get_rtname()
286{
287	local rtid="$1"
288
289	get_nodename "rt-${rtid}"
290}
291
292get_hsname()
293{
294	local hsid="$1"
295
296	get_nodename "hs-${hsid}"
297}
298
299__create_namespace()
300{
301	local name="$1"
302
303	ip netns add "${name}"
304}
305
306create_router()
307{
308	local rtid="$1"
309	local nsname
310
311	nsname="$(get_rtname "${rtid}")"
312
313	__create_namespace "${nsname}"
314}
315
316create_host()
317{
318	local hsid="$1"
319	local nsname
320
321	nsname="$(get_hsname "${hsid}")"
322
323	__create_namespace "${nsname}"
324}
325
326cleanup()
327{
328	local nsname
329	local i
330
331	# destroy routers
332	for i in ${ROUTERS}; do
333		nsname="$(get_rtname "${i}")"
334
335		ip netns del "${nsname}" &>/dev/null || true
336	done
337
338	# destroy hosts
339	for i in ${HOSTS}; do
340		nsname="$(get_hsname "${i}")"
341
342		ip netns del "${nsname}" &>/dev/null || true
343	done
344
345	# check whether the setup phase was completed successfully or not. In
346	# case of an error during the setup phase of the testing environment,
347	# the selftest is considered as "skipped".
348	if [ "${SETUP_ERR}" -ne 0 ]; then
349		echo "SKIP: Setting up the testing environment failed"
350		exit "${ksft_skip}"
351	fi
352
353	exit "${ret}"
354}
355
356add_link_rt_pairs()
357{
358	local rt="$1"
359	local rt_neighs="$2"
360	local neigh
361	local nsname
362	local neigh_nsname
363
364	nsname="$(get_rtname "${rt}")"
365
366	for neigh in ${rt_neighs}; do
367		neigh_nsname="$(get_rtname "${neigh}")"
368
369		ip link add "veth-rt-${rt}-${neigh}" netns "${nsname}" \
370			type veth peer name "veth-rt-${neigh}-${rt}" \
371			netns "${neigh_nsname}"
372	done
373}
374
375get_network_prefix()
376{
377	local rt="$1"
378	local neigh="$2"
379	local p="${rt}"
380	local q="${neigh}"
381
382	if [ "${p}" -gt "${q}" ]; then
383		p="${q}"; q="${rt}"
384	fi
385
386	echo "${IPv6_RT_NETWORK}:${p}:${q}"
387}
388
389# Given the description of a router <id:op> as an input, the function returns
390# the <id> token which represents the ID of the router.
391# i.e. input: "12:psp"
392#      output: "12"
393__get_srv6_rtcfg_id()
394{
395	local element="$1"
396
397	echo "${element}" | cut -d':' -f1
398}
399
400# Given the description of a router <id:op> as an input, the function returns
401# the <op> token which represents the operation (e.g. End behavior with or
402# withouth flavors) configured for the node.
403
404# Note that when the operation represents an End behavior with a list of
405# flavors, the output is the ordered version of that list.
406# i.e. input: "5:usp,psp,usd"
407#      output: "psp,usd,usp"
408__get_srv6_rtcfg_op()
409{
410	local element="$1"
411
412	# return the lexicographically ordered flavors
413	echo "${element}" | cut -d':' -f2 | sed 's/,/\n/g' | sort | \
414		xargs | sed 's/ /,/g'
415}
416
417# Setup the basic networking for the routers
418setup_rt_networking()
419{
420	local rt="$1"
421	local rt_neighs="$2"
422	local nsname
423	local net_prefix
424	local devname
425	local neigh
426
427	nsname="$(get_rtname "${rt}")"
428
429	for neigh in ${rt_neighs}; do
430		devname="veth-rt-${rt}-${neigh}"
431
432		net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
433
434		ip -netns "${nsname}" addr \
435			add "${net_prefix}::${rt}/64" dev "${devname}" nodad
436
437		ip -netns "${nsname}" link set "${devname}" up
438	done
439
440	ip -netns "${nsname}" link set lo up
441
442	ip -netns "${nsname}" link add ${DUMMY_DEVNAME} type dummy
443	ip -netns "${nsname}" link set ${DUMMY_DEVNAME} up
444
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}
449
450# Setup local SIDs for an SRv6 router
451setup_rt_local_sids()
452{
453	local rt="$1"
454	local rt_neighs="$2"
455	local net_prefix
456	local devname
457	local nsname
458	local neigh
459
460	nsname="$(get_rtname "${rt}")"
461
462	for neigh in ${rt_neighs}; do
463		devname="veth-rt-${rt}-${neigh}"
464
465		net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
466
467		# set underlay network routes for SIDs reachability
468		ip -netns "${nsname}" -6 route \
469			add "${LOCATOR_SERVICE}:${neigh}::/32" \
470			table "${LOCALSID_TABLE_ID}" \
471			via "${net_prefix}::${neigh}" dev "${devname}"
472	done
473
474	# Local End behavior (note that "dev" is a dummy interface chosen for
475	# the sake of simplicity).
476	ip -netns "${nsname}" -6 route \
477		add "${LOCATOR_SERVICE}:${rt}::${END_FUNC}" \
478		table "${LOCALSID_TABLE_ID}" \
479		encap seg6local action End dev "${DUMMY_DEVNAME}"
480
481
482	# all SIDs start with a common locator. Routes and SRv6 Endpoint
483	# behavior instaces are grouped together in the 'localsid' table.
484	ip -netns "${nsname}" -6 rule \
485		add to "${LOCATOR_SERVICE}::/16" \
486		lookup "${LOCALSID_TABLE_ID}" prio 999
487
488	# set default routes to unreachable
489	ip -netns "${nsname}" -6 route \
490		add unreachable default metric 4278198272 \
491		dev "${DUMMY_DEVNAME}"
492}
493
494# This helper function builds and installs the SID List (i.e. SRv6 Policy)
495# to be applied on incoming packets at the ingress node. Moreover, it
496# configures the SRv6 nodes specified in the SID List to process the traffic
497# according to the operations required by the Policy itself.
498# args:
499#  $1 - destination host (i.e. cafe::x host)
500#  $2 - SRv6 router configured for enforcing the SRv6 Policy
501#  $3 - compact way to represent a list of SRv6 routers with their operations
502#       (i.e. behaviors) that each of them needs to perform. Every <nodeid:op>
503#       element constructs a SID that is associated with the behavior <op> on
504#       the <nodeid> node. The list of such elements forms an SRv6 Policy.
505__setup_rt_policy()
506{
507	local dst="$1"
508	local encap_rt="$2"
509	local policy_rts="$3"
510	local behavior_cfg
511	local in_nsname
512	local rt_nsname
513	local policy=''
514	local function
515	local fullsid
516	local op_type
517	local node
518	local n
519
520	in_nsname="$(get_rtname "${encap_rt}")"
521
522	for n in ${policy_rts}; do
523		node="$(__get_srv6_rtcfg_id "${n}")"
524		op_type="$(__get_srv6_rtcfg_op "${n}")"
525		rt_nsname="$(get_rtname "${node}")"
526
527		case "${op_type}" in
528		"noflv")
529			policy="${policy}${LOCATOR_SERVICE}:${node}::${END_FUNC},"
530			function="${END_FUNC}"
531			behavior_cfg="End"
532			;;
533
534		"psp")
535			policy="${policy}${LOCATOR_SERVICE}:${node}::${END_PSP_FUNC},"
536			function="${END_PSP_FUNC}"
537			behavior_cfg="End flavors psp"
538			;;
539
540		*)
541			break
542			;;
543		esac
544
545		fullsid="${LOCATOR_SERVICE}:${node}::${function}"
546
547		# add SRv6 Endpoint behavior to the selected router
548		if ! ip -netns "${rt_nsname}" -6 route get "${fullsid}" \
549			&>/dev/null; then
550			ip -netns "${rt_nsname}" -6 route \
551				add "${fullsid}" \
552				table "${LOCALSID_TABLE_ID}" \
553				encap seg6local action ${behavior_cfg} \
554				dev "${DUMMY_DEVNAME}"
555		fi
556	done
557
558	# we need to remove the trailing comma to avoid inserting an empty
559	# address (::0) in the SID List.
560	policy="${policy%,}"
561
562	# add SRv6 policy to incoming traffic sent by connected hosts
563	ip -netns "${in_nsname}" -6 route \
564		add "${IPv6_HS_NETWORK}::${dst}" \
565		encap seg6 mode inline segs "${policy}" \
566		dev "${DUMMY_DEVNAME}"
567
568	ip -netns "${in_nsname}" -6 neigh \
569		add proxy "${IPv6_HS_NETWORK}::${dst}" \
570		dev "${RT2HS_DEVNAME}"
571}
572
573# see __setup_rt_policy
574setup_rt_policy_ipv6()
575{
576	__setup_rt_policy "$1" "$2" "$3"
577}
578
579setup_hs()
580{
581	local hs="$1"
582	local rt="$2"
583	local hsname
584	local rtname
585
586	hsname="$(get_hsname "${hs}")"
587	rtname="$(get_rtname "${rt}")"
588
589	ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
590	ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
591
592	ip -netns "${hsname}" link add veth0 type veth \
593		peer name "${RT2HS_DEVNAME}" netns "${rtname}"
594
595	ip -netns "${hsname}" addr \
596		add "${IPv6_HS_NETWORK}::${hs}/64" dev veth0 nodad
597
598	ip -netns "${hsname}" link set veth0 up
599	ip -netns "${hsname}" link set lo up
600
601	ip -netns "${rtname}" addr \
602		add "${IPv6_HS_NETWORK}::254/64" dev "${RT2HS_DEVNAME}" nodad
603
604	ip -netns "${rtname}" link set "${RT2HS_DEVNAME}" up
605
606	ip netns exec "${rtname}" \
607		sysctl -wq net.ipv6.conf."${RT2HS_DEVNAME}".proxy_ndp=1
608}
609
610setup()
611{
612	local i
613
614	# create routers
615	ROUTERS="1 2 3 4"; readonly ROUTERS
616	for i in ${ROUTERS}; do
617		create_router "${i}"
618	done
619
620	# create hosts
621	HOSTS="1 2"; readonly HOSTS
622	for i in ${HOSTS}; do
623		create_host "${i}"
624	done
625
626	# set up the links for connecting routers
627	add_link_rt_pairs 1 "2 3 4"
628	add_link_rt_pairs 2 "3 4"
629	add_link_rt_pairs 3 "4"
630
631	# set up the basic connectivity of routers and routes required for
632	# reachability of SIDs.
633	setup_rt_networking 1 "2 3 4"
634	setup_rt_networking 2 "1 3 4"
635	setup_rt_networking 3 "1 2 4"
636	setup_rt_networking 4 "1 2 3"
637
638	# set up the hosts connected to routers
639	setup_hs 1 1
640	setup_hs 2 2
641
642	# set up default SRv6 Endpoints (i.e. SRv6 End behavior)
643	setup_rt_local_sids 1 "2 3 4"
644	setup_rt_local_sids 2 "1 3 4"
645	setup_rt_local_sids 3 "1 2 4"
646	setup_rt_local_sids 4 "1 2 3"
647
648	# set up SRv6 policies
649	# create a connection between hosts hs-1 and hs-2.
650	# The path between hs-1 and hs-2 traverses SRv6 aware routers.
651	# For each direction two path are chosen:
652	#
653	# Direction hs-1 -> hs-2 (PSP flavor)
654	#  - rt-1 (SRv6 H.Insert policy)
655	#  - rt-3 (SRv6 End behavior)
656	#  - rt-4 (SRv6 End flavor PSP with SL>1, acting as End behavior)
657	#  - rt-2 (SRv6 End flavor PSP with SL=1)
658	#
659	# Direction hs-2 -> hs-1 (PSP flavor)
660	#  - rt-2 (SRv6 H.Insert policy)
661	#  - rt-1 (SRv6 End flavor PSP with SL=1)
662	setup_rt_policy_ipv6 2 1 "3:noflv 4:psp 2:psp"
663	setup_rt_policy_ipv6 1 2 "1:psp"
664
665	# testing environment was set up successfully
666	SETUP_ERR=0
667}
668
669check_rt_connectivity()
670{
671	local rtsrc="$1"
672	local rtdst="$2"
673	local prefix
674	local rtsrc_nsname
675
676	rtsrc_nsname="$(get_rtname "${rtsrc}")"
677
678	prefix="$(get_network_prefix "${rtsrc}" "${rtdst}")"
679
680	ip netns exec "${rtsrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
681		"${prefix}::${rtdst}" >/dev/null 2>&1
682}
683
684check_and_log_rt_connectivity()
685{
686	local rtsrc="$1"
687	local rtdst="$2"
688
689	check_rt_connectivity "${rtsrc}" "${rtdst}"
690	log_test $? 0 "Routers connectivity: rt-${rtsrc} -> rt-${rtdst}"
691}
692
693check_hs_ipv6_connectivity()
694{
695	local hssrc="$1"
696	local hsdst="$2"
697	local hssrc_nsname
698
699	hssrc_nsname="$(get_hsname "${hssrc}")"
700
701	ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
702		"${IPv6_HS_NETWORK}::${hsdst}" >/dev/null 2>&1
703}
704
705check_and_log_hs2gw_connectivity()
706{
707	local hssrc="$1"
708
709	check_hs_ipv6_connectivity "${hssrc}" 254
710	log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> gw"
711}
712
713check_and_log_hs_ipv6_connectivity()
714{
715	local hssrc="$1"
716	local hsdst="$2"
717
718	check_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
719	log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"
720}
721
722check_and_log_hs_connectivity()
723{
724	local hssrc="$1"
725	local hsdst="$2"
726
727	check_and_log_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
728}
729
730router_tests()
731{
732	local i
733	local j
734
735	log_section "IPv6 routers connectivity test"
736
737	for i in ${ROUTERS}; do
738		for j in ${ROUTERS}; do
739			if [ "${i}" -eq "${j}" ]; then
740				continue
741			fi
742
743			check_and_log_rt_connectivity "${i}" "${j}"
744		done
745	done
746}
747
748host2gateway_tests()
749{
750	local hs
751
752	log_section "IPv6 connectivity test among hosts and gateways"
753
754	for hs in ${HOSTS}; do
755		check_and_log_hs2gw_connectivity "${hs}"
756	done
757}
758
759host_srv6_end_flv_psp_tests()
760{
761	log_section "SRv6 connectivity test hosts (h1 <-> h2, PSP flavor)"
762
763	check_and_log_hs_connectivity 1 2
764	check_and_log_hs_connectivity 2 1
765}
766
767test_iproute2_supp_or_ksft_skip()
768{
769	local flavor="$1"
770
771	if ! ip route help 2>&1 | grep -qo "${flavor}"; then
772		echo "SKIP: Missing SRv6 ${flavor} flavor support in iproute2"
773		exit "${ksft_skip}"
774	fi
775}
776
777test_kernel_supp_or_ksft_skip()
778{
779	local flavor="$1"
780	local test_netns
781
782	test_netns="kflv-$(mktemp -u XXXXXXXX)"
783
784	if ! ip netns add "${test_netns}"; then
785		echo "SKIP: Cannot set up netns to test kernel support for flavors"
786		exit "${ksft_skip}"
787	fi
788
789	if ! ip -netns "${test_netns}" link \
790		add "${DUMMY_DEVNAME}" type dummy; then
791		echo "SKIP: Cannot set up dummy dev to test kernel support for flavors"
792
793		ip netns del "${test_netns}"
794		exit "${ksft_skip}"
795	fi
796
797	if ! ip -netns "${test_netns}" link \
798		set "${DUMMY_DEVNAME}" up; then
799		echo "SKIP: Cannot activate dummy dev to test kernel support for flavors"
800
801		ip netns del "${test_netns}"
802		exit "${ksft_skip}"
803	fi
804
805	if ! ip -netns "${test_netns}" -6 route \
806		add "${IPv6_TESTS_ADDR}" encap seg6local \
807		action End flavors "${flavor}" dev "${DUMMY_DEVNAME}"; then
808		echo "SKIP: ${flavor} flavor not supported in kernel"
809
810		ip netns del "${test_netns}"
811		exit "${ksft_skip}"
812	fi
813
814	ip netns del "${test_netns}"
815}
816
817test_dummy_dev_or_ksft_skip()
818{
819	local test_netns
820
821	test_netns="dummy-$(mktemp -u XXXXXXXX)"
822
823	if ! ip netns add "${test_netns}"; then
824		echo "SKIP: Cannot set up netns for testing dummy dev support"
825		exit "${ksft_skip}"
826	fi
827
828	modprobe dummy &>/dev/null || true
829	if ! ip -netns "${test_netns}" link \
830		add "${DUMMY_DEVNAME}" type dummy; then
831		echo "SKIP: dummy dev not supported"
832
833		ip netns del "${test_netns}"
834		exit "${ksft_skip}"
835	fi
836
837	ip netns del "${test_netns}"
838}
839
840if [ "$(id -u)" -ne 0 ]; then
841	echo "SKIP: Need root privileges"
842	exit "${ksft_skip}"
843fi
844
845# required programs to carry out this selftest
846test_command_or_ksft_skip ip
847test_command_or_ksft_skip ping
848test_command_or_ksft_skip sysctl
849test_command_or_ksft_skip grep
850test_command_or_ksft_skip cut
851test_command_or_ksft_skip sed
852test_command_or_ksft_skip sort
853test_command_or_ksft_skip xargs
854
855test_dummy_dev_or_ksft_skip
856test_iproute2_supp_or_ksft_skip psp
857test_kernel_supp_or_ksft_skip psp
858
859set -e
860trap cleanup EXIT
861
862setup
863set +e
864
865router_tests
866host2gateway_tests
867host_srv6_end_flv_psp_tests
868
869print_log_test_results
870