xref: /linux/tools/testing/selftests/net/srv6_hencap_red_l3vpn_test.sh (revision 746680ec6696585e30db3e18c93a63df9cbec39c)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# author: Andrea Mayer <andrea.mayer@uniroma2.it>
5#
6# This script is designed for testing the SRv6 H.Encaps.Red behavior.
7#
8# Below is depicted the IPv6 network of an operator which offers advanced
9# IPv4/IPv6 VPN services to hosts, enabling them to communicate with each
10# other.
11# In this example, hosts hs-1 and hs-2 are connected through an IPv4/IPv6 VPN
12# service, while hs-3 and hs-4 are connected using an IPv6 only VPN.
13#
14# Routers rt-1,rt-2,rt-3 and rt-4 implement IPv4/IPv6 L3 VPN services
15# leveraging the SRv6 architecture. The key components for such VPNs are:
16#
17#   i) The SRv6 H.Encaps.Red behavior applies SRv6 Policies on traffic received
18#      by connected hosts, initiating the VPN tunnel. Such a behavior is an
19#      optimization of the SRv6 H.Encap aiming to reduce the length of the SID
20#      List carried in the pushed SRH. Specifically, the H.Encaps.Red removes
21#      the first SID contained in the SID List (i.e. SRv6 Policy) by storing it
22#      into the IPv6 Destination Address. When a SRv6 Policy is made of only one
23#      SID, the SRv6 H.Encaps.Red behavior omits the SRH at all and pushes that
24#      SID directly into the IPv6 DA;
25#
26#  ii) The SRv6 End behavior advances the active SID in the SID List carried by
27#      the SRH;
28#
29# iii) The SRv6 End.DT46 behavior is used for removing the SRv6 Policy and,
30#      thus, it terminates the VPN tunnel. Such a behavior is capable of
31#      handling, at the same time, both tunneled IPv4 and IPv6 traffic.
32#
33#
34#               cafe::1                      cafe::2
35#              10.0.0.1                     10.0.0.2
36#             +--------+                   +--------+
37#             |        |                   |        |
38#             |  hs-1  |                   |  hs-2  |
39#             |        |                   |        |
40#             +---+----+                   +--- +---+
41#    cafe::/64    |                             |      cafe::/64
42#  10.0.0.0/24    |                             |    10.0.0.0/24
43#             +---+----+                   +----+---+
44#             |        |  fcf0:0:1:2::/64  |        |
45#             |  rt-1  +-------------------+  rt-2  |
46#             |        |                   |        |
47#             +---+----+                   +----+---+
48#                 |      .               .      |
49#                 |  fcf0:0:1:3::/64   .        |
50#                 |          .       .          |
51#                 |            .   .            |
52# fcf0:0:1:4::/64 |              .              | fcf0:0:2:3::/64
53#                 |            .   .            |
54#                 |          .       .          |
55#                 |  fcf0:0:2:4::/64   .        |
56#                 |      .               .      |
57#             +---+----+                   +----+---+
58#             |        |                   |        |
59#             |  rt-4  +-------------------+  rt-3  |
60#             |        |  fcf0:0:3:4::/64  |        |
61#             +---+----+                   +----+---+
62#    cafe::/64    |                             |      cafe::/64
63#  10.0.0.0/24    |                             |    10.0.0.0/24
64#             +---+----+                   +--- +---+
65#             |        |                   |        |
66#             |  hs-4  |                   |  hs-3  |
67#             |        |                   |        |
68#             +--------+                   +--------+
69#               cafe::4                      cafe::3
70#              10.0.0.4                     10.0.0.3
71#
72#
73# Every fcf0:0:x:y::/64 network interconnects the SRv6 routers rt-x with rt-y
74# in the IPv6 operator network.
75#
76# Local SID table
77# ===============
78#
79# Each SRv6 router is configured with a Local SID table in which SIDs are
80# stored. Considering the given SRv6 router rt-x, at least two SIDs are
81# configured in the Local SID table:
82#
83#   Local SID table for SRv6 router rt-x
84#   +----------------------------------------------------------+
85#   |fcff:x::e is associated with the SRv6 End behavior        |
86#   |fcff:x::d46 is associated with the SRv6 End.DT46 behavior |
87#   +----------------------------------------------------------+
88#
89# The fcff::/16 prefix is reserved by the operator for implementing SRv6 VPN
90# services. Reachability of SIDs is ensured by proper configuration of the IPv6
91# operator's network and SRv6 routers.
92#
93# # SRv6 Policies
94# ===============
95#
96# An SRv6 ingress router applies SRv6 policies to the traffic received from a
97# connected host. SRv6 policy enforcement consists of encapsulating the
98# received traffic into a new IPv6 packet with a given SID List contained in
99# the SRH.
100#
101# IPv4/IPv6 VPN between hs-1 and hs-2
102# -----------------------------------
103#
104# Hosts hs-1 and hs-2 are connected using dedicated IPv4/IPv6 VPNs.
105# Specifically, packets generated from hs-1 and directed towards hs-2 are
106# handled by rt-1 which applies the following SRv6 Policies:
107#
108#   i.a) IPv6 traffic, SID List=fcff:3::e,fcff:4::e,fcff:2::d46
109#  ii.a) IPv4 traffic, SID List=fcff:2::d46
110#
111# Policy (i.a) steers tunneled IPv6 traffic through SRv6 routers
112# rt-3,rt-4,rt-2. Instead, Policy (ii.a) steers tunneled IPv4 traffic through
113# rt-2.
114# The H.Encaps.Red reduces the SID List (i.a) carried in SRH by removing the
115# first SID (fcff:3::e) and pushing it into the IPv6 DA. In case of IPv4
116# traffic, the H.Encaps.Red omits the presence of SRH at all, since the SID
117# List (ii.a) consists of only one SID that can be stored directly in the IPv6
118# DA.
119#
120# On the reverse path (i.e. from hs-2 to hs-1), rt-2 applies the following
121# policies:
122#
123#   i.b) IPv6 traffic, SID List=fcff:1::d46
124#  ii.b) IPv4 traffic, SID List=fcff:4::e,fcff:3::e,fcff:1::d46
125#
126# Policy (i.b) steers tunneled IPv6 traffic through the SRv6 router rt-1.
127# Conversely, Policy (ii.b) steers tunneled IPv4 traffic through SRv6 routers
128# rt-4,rt-3,rt-1.
129# The H.Encaps.Red omits the SRH at all in case of (i.b) by pushing the single
130# SID (fcff::1::d46) inside the IPv6 DA.
131# The H.Encaps.Red reduces the SID List (ii.b) in the SRH by removing the first
132# SID (fcff:4::e) and pushing it into the IPv6 DA.
133#
134# In summary:
135#  hs-1->hs-2 |IPv6 DA=fcff:3::e|SRH SIDs=fcff:4::e,fcff:2::d46|IPv6|...| (i.a)
136#  hs-1->hs-2 |IPv6 DA=fcff:2::d46|IPv4|...|                              (ii.a)
137#
138#  hs-2->hs-1 |IPv6 DA=fcff:1::d46|IPv6|...|                              (i.b)
139#  hs-2->hs-1 |IPv6 DA=fcff:4::e|SRH SIDs=fcff:3::e,fcff:1::d46|IPv4|...| (ii.b)
140#
141#
142# IPv6 VPN between hs-3 and hs-4
143# ------------------------------
144#
145# Hosts hs-3 and hs-4 are connected using a dedicated IPv6 only VPN.
146# Specifically, packets generated from hs-3 and directed towards hs-4 are
147# handled by rt-3 which applies the following SRv6 Policy:
148#
149#  i.c) IPv6 traffic, SID List=fcff:2::e,fcff:4::d46
150#
151# Policy (i.c) steers tunneled IPv6 traffic through SRv6 routers rt-2,rt-4.
152# The H.Encaps.Red reduces the SID List (i.c) carried in SRH by pushing the
153# first SID (fcff:2::e) in the IPv6 DA.
154#
155# On the reverse path (i.e. from hs-4 to hs-3) the router rt-4 applies the
156# following SRv6 Policy:
157#
158#  i.d) IPv6 traffic, SID List=fcff:1::e,fcff:3::d46.
159#
160# Policy (i.d) steers tunneled IPv6 traffic through SRv6 routers rt-1,rt-3.
161# The H.Encaps.Red reduces the SID List (i.d) carried in SRH by pushing the
162# first SID (fcff:1::e) in the IPv6 DA.
163#
164# In summary:
165#  hs-3->hs-4 |IPv6 DA=fcff:2::e|SRH SIDs=fcff:4::d46|IPv6|...| (i.c)
166#  hs-4->hs-3 |IPv6 DA=fcff:1::e|SRH SIDs=fcff:3::d46|IPv6|...| (i.d)
167#
168
169source lib.sh
170
171readonly VRF_TID=100
172readonly VRF_DEVNAME="vrf-${VRF_TID}"
173readonly RT2HS_DEVNAME="veth-t${VRF_TID}"
174readonly LOCALSID_TABLE_ID=90
175readonly IPv6_RT_NETWORK=fcf0:0
176readonly IPv6_HS_NETWORK=cafe
177readonly IPv4_HS_NETWORK=10.0.0
178readonly VPN_LOCATOR_SERVICE=fcff
179readonly END_FUNC=000e
180readonly DT46_FUNC=0d46
181
182PING_TIMEOUT_SEC=4
183PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
184
185# IDs of routers and hosts are initialized during the setup of the testing
186# network
187ROUTERS=''
188HOSTS=''
189
190SETUP_ERR=1
191
192ret=${ksft_skip}
193nsuccess=0
194nfail=0
195
196log_test()
197{
198	local rc="$1"
199	local expected="$2"
200	local msg="$3"
201
202	if [ "${rc}" -eq "${expected}" ]; then
203		nsuccess=$((nsuccess+1))
204		printf "\n    TEST: %-60s  [ OK ]\n" "${msg}"
205	else
206		ret=1
207		nfail=$((nfail+1))
208		printf "\n    TEST: %-60s  [FAIL]\n" "${msg}"
209		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
210			echo
211			echo "hit enter to continue, 'q' to quit"
212			read a
213			[ "$a" = "q" ] && exit 1
214		fi
215	fi
216}
217
218print_log_test_results()
219{
220	printf "\nTests passed: %3d\n" "${nsuccess}"
221	printf "Tests failed: %3d\n"   "${nfail}"
222
223	# when a test fails, the value of 'ret' is set to 1 (error code).
224	# Conversely, when all tests are passed successfully, the 'ret' value
225	# is set to 0 (success code).
226	if [ "${ret}" -ne 1 ]; then
227		ret=0
228	fi
229}
230
231log_section()
232{
233	echo
234	echo "################################################################################"
235	echo "TEST SECTION: $*"
236	echo "################################################################################"
237}
238
239test_command_or_ksft_skip()
240{
241	local cmd="$1"
242
243	if [ ! -x "$(command -v "${cmd}")" ]; then
244		echo "SKIP: Could not run test without \"${cmd}\" tool";
245		exit "${ksft_skip}"
246	fi
247}
248
249get_rtname()
250{
251	local rtid="$1"
252
253	echo "rt_${rtid}"
254}
255
256get_hsname()
257{
258	local hsid="$1"
259
260	echo "hs_${hsid}"
261}
262
263create_router()
264{
265	local rtid="$1"
266	local nsname
267
268	nsname="$(get_rtname "${rtid}")"
269	setup_ns "${nsname}"
270}
271
272create_host()
273{
274	local hsid="$1"
275	local nsname
276
277	nsname="$(get_hsname "${hsid}")"
278	setup_ns "${nsname}"
279}
280
281cleanup()
282{
283	cleanup_all_ns
284	# check whether the setup phase was completed successfully or not. In
285	# case of an error during the setup phase of the testing environment,
286	# the selftest is considered as "skipped".
287	if [ "${SETUP_ERR}" -ne 0 ]; then
288		echo "SKIP: Setting up the testing environment failed"
289		exit "${ksft_skip}"
290	fi
291
292	exit "${ret}"
293}
294
295add_link_rt_pairs()
296{
297	local rt="$1"
298	local rt_neighs="$2"
299	local neigh
300	local nsname
301	local neigh_nsname
302
303	eval nsname=\${$(get_rtname "${rt}")}
304
305	for neigh in ${rt_neighs}; do
306		eval neigh_nsname=\${$(get_rtname "${neigh}")}
307
308		ip link add "veth-rt-${rt}-${neigh}" netns "${nsname}" \
309			type veth peer name "veth-rt-${neigh}-${rt}" \
310			netns "${neigh_nsname}"
311	done
312}
313
314get_network_prefix()
315{
316	local rt="$1"
317	local neigh="$2"
318	local p="${rt}"
319	local q="${neigh}"
320
321	if [ "${p}" -gt "${q}" ]; then
322		p="${q}"; q="${rt}"
323	fi
324
325	echo "${IPv6_RT_NETWORK}:${p}:${q}"
326}
327
328# Setup the basic networking for the routers
329setup_rt_networking()
330{
331	local rt="$1"
332	local rt_neighs="$2"
333	local nsname
334	local net_prefix
335	local devname
336	local neigh
337
338	eval nsname=\${$(get_rtname "${rt}")}
339
340	for neigh in ${rt_neighs}; do
341		devname="veth-rt-${rt}-${neigh}"
342
343		net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
344
345		ip -netns "${nsname}" addr \
346			add "${net_prefix}::${rt}/64" dev "${devname}" nodad
347
348		ip -netns "${nsname}" link set "${devname}" up
349	done
350
351	ip -netns "${nsname}" link set lo up
352
353	ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
354	ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
355	ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.forwarding=1
356	ip netns exec "${nsname}" sysctl -wq net.ipv4.ip_forward=1
357}
358
359# Setup local SIDs for an SRv6 router
360setup_rt_local_sids()
361{
362	local rt="$1"
363	local rt_neighs="$2"
364	local net_prefix
365	local devname
366	local nsname
367	local neigh
368
369	eval nsname=\${$(get_rtname "${rt}")}
370
371	for neigh in ${rt_neighs}; do
372		devname="veth-rt-${rt}-${neigh}"
373
374		net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
375
376		# set underlay network routes for SIDs reachability
377		ip -netns "${nsname}" -6 route \
378			add "${VPN_LOCATOR_SERVICE}:${neigh}::/32" \
379			table "${LOCALSID_TABLE_ID}" \
380			via "${net_prefix}::${neigh}" dev "${devname}"
381	done
382
383	# Local End behavior (note that "dev" is dummy and the VRF is chosen
384	# for the sake of simplicity).
385	ip -netns "${nsname}" -6 route \
386		add "${VPN_LOCATOR_SERVICE}:${rt}::${END_FUNC}" \
387		table "${LOCALSID_TABLE_ID}" \
388		encap seg6local action End dev "${VRF_DEVNAME}"
389
390	# Local End.DT46 behavior
391	ip -netns "${nsname}" -6 route \
392		add "${VPN_LOCATOR_SERVICE}:${rt}::${DT46_FUNC}" \
393		table "${LOCALSID_TABLE_ID}" \
394		encap seg6local action End.DT46 vrftable "${VRF_TID}" \
395		dev "${VRF_DEVNAME}"
396
397	# all SIDs for VPNs start with a common locator. Routes and SRv6
398	# Endpoint behavior instances are grouped together in the 'localsid'
399	# table.
400	ip -netns "${nsname}" -6 rule \
401		add to "${VPN_LOCATOR_SERVICE}::/16" \
402		lookup "${LOCALSID_TABLE_ID}" prio 999
403
404	# set default routes to unreachable for both ipv4 and ipv6
405	ip -netns "${nsname}" -6 route \
406		add unreachable default metric 4278198272 \
407		vrf "${VRF_DEVNAME}"
408
409	ip -netns "${nsname}" -4 route \
410		add unreachable default metric 4278198272 \
411		vrf "${VRF_DEVNAME}"
412}
413
414# build and install the SRv6 policy into the ingress SRv6 router.
415# args:
416#  $1 - destination host (i.e. cafe::x host)
417#  $2 - SRv6 router configured for enforcing the SRv6 Policy
418#  $3 - SRv6 routers configured for steering traffic (End behaviors)
419#  $4 - SRv6 router configured for removing the SRv6 Policy (router connected
420#       to the destination host)
421#  $5 - encap mode (full or red)
422#  $6 - traffic type (IPv6 or IPv4)
423__setup_rt_policy()
424{
425	local dst="$1"
426	local encap_rt="$2"
427	local end_rts="$3"
428	local dec_rt="$4"
429	local mode="$5"
430	local traffic="$6"
431	local nsname
432	local policy=''
433	local n
434
435	eval nsname=\${$(get_rtname "${encap_rt}")}
436
437	for n in ${end_rts}; do
438		policy="${policy}${VPN_LOCATOR_SERVICE}:${n}::${END_FUNC},"
439	done
440
441	policy="${policy}${VPN_LOCATOR_SERVICE}:${dec_rt}::${DT46_FUNC}"
442
443	# add SRv6 policy to incoming traffic sent by connected hosts
444	if [ "${traffic}" -eq 6 ]; then
445		ip -netns "${nsname}" -6 route \
446			add "${IPv6_HS_NETWORK}::${dst}" vrf "${VRF_DEVNAME}" \
447			encap seg6 mode "${mode}" segs "${policy}" \
448			dev "${VRF_DEVNAME}"
449
450		ip -netns "${nsname}" -6 neigh \
451			add proxy "${IPv6_HS_NETWORK}::${dst}" \
452			dev "${RT2HS_DEVNAME}"
453	else
454		# "dev" must be different from the one where the packet is
455		# received, otherwise the proxy arp does not work.
456		ip -netns "${nsname}" -4 route \
457			add "${IPv4_HS_NETWORK}.${dst}" vrf "${VRF_DEVNAME}" \
458			encap seg6 mode "${mode}" segs "${policy}" \
459			dev "${VRF_DEVNAME}"
460	fi
461}
462
463# see __setup_rt_policy
464setup_rt_policy_ipv6()
465{
466	__setup_rt_policy "$1" "$2" "$3" "$4" "$5" 6
467}
468
469#see __setup_rt_policy
470setup_rt_policy_ipv4()
471{
472	__setup_rt_policy "$1" "$2" "$3" "$4" "$5" 4
473}
474
475setup_hs()
476{
477	local hs="$1"
478	local rt="$2"
479	local hsname
480	local rtname
481
482	eval hsname=\${$(get_hsname "${hs}")}
483	eval rtname=\${$(get_rtname "${rt}")}
484
485	ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
486	ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
487
488	ip -netns "${hsname}" link add veth0 type veth \
489		peer name "${RT2HS_DEVNAME}" netns "${rtname}"
490
491	ip -netns "${hsname}" addr \
492		add "${IPv6_HS_NETWORK}::${hs}/64" dev veth0 nodad
493	ip -netns "${hsname}" addr add "${IPv4_HS_NETWORK}.${hs}/24" dev veth0
494
495	ip -netns "${hsname}" link set veth0 up
496	ip -netns "${hsname}" link set lo up
497
498	# configure the VRF on the router which is directly connected to the
499	# source host.
500	ip -netns "${rtname}" link \
501		add "${VRF_DEVNAME}" type vrf table "${VRF_TID}"
502	ip -netns "${rtname}" link set "${VRF_DEVNAME}" up
503
504	# enslave the veth interface connecting the router with the host to the
505	# VRF in the access router
506	ip -netns "${rtname}" link \
507		set "${RT2HS_DEVNAME}" master "${VRF_DEVNAME}"
508
509	ip -netns "${rtname}" addr \
510		add "${IPv6_HS_NETWORK}::254/64" dev "${RT2HS_DEVNAME}" nodad
511	ip -netns "${rtname}" addr \
512		add "${IPv4_HS_NETWORK}.254/24" dev "${RT2HS_DEVNAME}"
513
514	ip -netns "${rtname}" link set "${RT2HS_DEVNAME}" up
515
516	ip netns exec "${rtname}" \
517		sysctl -wq net.ipv6.conf."${RT2HS_DEVNAME}".proxy_ndp=1
518	ip netns exec "${rtname}" \
519		sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".proxy_arp=1
520
521	ip netns exec "${rtname}" sh -c "echo 1 > /proc/sys/net/vrf/strict_mode"
522}
523
524setup()
525{
526	local i
527
528	# create routers
529	ROUTERS="1 2 3 4"; readonly ROUTERS
530	for i in ${ROUTERS}; do
531		create_router "${i}"
532	done
533
534	# create hosts
535	HOSTS="1 2 3 4"; readonly HOSTS
536	for i in ${HOSTS}; do
537		create_host "${i}"
538	done
539
540	# set up the links for connecting routers
541	add_link_rt_pairs 1 "2 3 4"
542	add_link_rt_pairs 2 "3 4"
543	add_link_rt_pairs 3 "4"
544
545	# set up the basic connectivity of routers and routes required for
546	# reachability of SIDs.
547	setup_rt_networking 1 "2 3 4"
548	setup_rt_networking 2 "1 3 4"
549	setup_rt_networking 3 "1 2 4"
550	setup_rt_networking 4 "1 2 3"
551
552	# set up the hosts connected to routers
553	setup_hs 1 1
554	setup_hs 2 2
555	setup_hs 3 3
556	setup_hs 4 4
557
558	# set up default SRv6 Endpoints (i.e. SRv6 End and SRv6 End.DT46)
559	setup_rt_local_sids 1 "2 3 4"
560	setup_rt_local_sids 2 "1 3 4"
561	setup_rt_local_sids 3 "1 2 4"
562	setup_rt_local_sids 4 "1 2 3"
563
564	# set up SRv6 policies
565
566	# create an IPv6 VPN between hosts hs-1 and hs-2.
567	# the network path between hs-1 and hs-2 traverses several routers
568	# depending on the direction of traffic.
569	#
570	# Direction hs-1 -> hs-2 (H.Encaps.Red)
571	#  - rt-3,rt-4 (SRv6 End behaviors)
572	#  - rt-2 (SRv6 End.DT46 behavior)
573	#
574	# Direction hs-2 -> hs-1 (H.Encaps.Red)
575	#  - rt-1 (SRv6 End.DT46 behavior)
576	setup_rt_policy_ipv6 2 1 "3 4" 2 encap.red
577	setup_rt_policy_ipv6 1 2 "" 1 encap.red
578
579	# create an IPv4 VPN between hosts hs-1 and hs-2
580	# the network path between hs-1 and hs-2 traverses several routers
581	# depending on the direction of traffic.
582	#
583	# Direction hs-1 -> hs-2 (H.Encaps.Red)
584	# - rt-2 (SRv6 End.DT46 behavior)
585	#
586	# Direction hs-2 -> hs-1 (H.Encaps.Red)
587	#  - rt-4,rt-3 (SRv6 End behaviors)
588	#  - rt-1 (SRv6 End.DT46 behavior)
589	setup_rt_policy_ipv4 2 1 "" 2 encap.red
590	setup_rt_policy_ipv4 1 2 "4 3" 1 encap.red
591
592	# create an IPv6 VPN between hosts hs-3 and hs-4
593	# the network path between hs-3 and hs-4 traverses several routers
594	# depending on the direction of traffic.
595	#
596	# Direction hs-3 -> hs-4 (H.Encaps.Red)
597	# - rt-2 (SRv6 End Behavior)
598	# - rt-4 (SRv6 End.DT46 behavior)
599	#
600	# Direction hs-4 -> hs-3 (H.Encaps.Red)
601	#  - rt-1 (SRv6 End behavior)
602	#  - rt-3 (SRv6 End.DT46 behavior)
603	setup_rt_policy_ipv6 4 3 "2" 4 encap.red
604	setup_rt_policy_ipv6 3 4 "1" 3 encap.red
605
606	# testing environment was set up successfully
607	SETUP_ERR=0
608}
609
610check_rt_connectivity()
611{
612	local rtsrc="$1"
613	local rtdst="$2"
614	local prefix
615	local rtsrc_nsname
616
617	eval rtsrc_nsname=\${$(get_rtname "${rtsrc}")}
618
619	prefix="$(get_network_prefix "${rtsrc}" "${rtdst}")"
620
621	ip netns exec "${rtsrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
622		"${prefix}::${rtdst}" >/dev/null 2>&1
623}
624
625check_and_log_rt_connectivity()
626{
627	local rtsrc="$1"
628	local rtdst="$2"
629
630	check_rt_connectivity "${rtsrc}" "${rtdst}"
631	log_test $? 0 "Routers connectivity: rt-${rtsrc} -> rt-${rtdst}"
632}
633
634check_hs_ipv6_connectivity()
635{
636	local hssrc="$1"
637	local hsdst="$2"
638	local hssrc_nsname
639
640	eval hssrc_nsname=\${$(get_hsname "${hssrc}")}
641
642	ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
643		"${IPv6_HS_NETWORK}::${hsdst}" >/dev/null 2>&1
644}
645
646check_hs_ipv4_connectivity()
647{
648	local hssrc="$1"
649	local hsdst="$2"
650	local hssrc_nsname
651
652	eval hssrc_nsname=\${$(get_hsname "${hssrc}")}
653
654	ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
655		"${IPv4_HS_NETWORK}.${hsdst}" >/dev/null 2>&1
656}
657
658check_and_log_hs2gw_connectivity()
659{
660	local hssrc="$1"
661
662	check_hs_ipv6_connectivity "${hssrc}" 254
663	log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> gw"
664
665	check_hs_ipv4_connectivity "${hssrc}" 254
666	log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> gw"
667}
668
669check_and_log_hs_ipv6_connectivity()
670{
671	local hssrc="$1"
672	local hsdst="$2"
673
674	check_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
675	log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"
676}
677
678check_and_log_hs_ipv4_connectivity()
679{
680	local hssrc="$1"
681	local hsdst="$2"
682
683	check_hs_ipv4_connectivity "${hssrc}" "${hsdst}"
684	log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"
685}
686
687check_and_log_hs_connectivity()
688{
689	local hssrc="$1"
690	local hsdst="$2"
691
692	check_and_log_hs_ipv4_connectivity "${hssrc}" "${hsdst}"
693	check_and_log_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
694}
695
696check_and_log_hs_ipv6_isolation()
697{
698	local hssrc="$1"
699	local hsdst="$2"
700
701	# in this case, the connectivity test must fail
702	check_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
703	log_test $? 1 "IPv6 Hosts isolation: hs-${hssrc} -X-> hs-${hsdst}"
704}
705
706check_and_log_hs_ipv4_isolation()
707{
708	local hssrc="$1"
709	local hsdst="$2"
710
711	# in this case, the connectivity test must fail
712	check_hs_ipv4_connectivity "${hssrc}" "${hsdst}"
713	log_test $? 1 "IPv4 Hosts isolation: hs-${hssrc} -X-> hs-${hsdst}"
714}
715
716check_and_log_hs_isolation()
717{
718	local hssrc="$1"
719	local hsdst="$2"
720
721	check_and_log_hs_ipv6_isolation "${hssrc}" "${hsdst}"
722	check_and_log_hs_ipv4_isolation "${hssrc}" "${hsdst}"
723}
724
725router_tests()
726{
727	local i
728	local j
729
730	log_section "IPv6 routers connectivity test"
731
732	for i in ${ROUTERS}; do
733		for j in ${ROUTERS}; do
734			if [ "${i}" -eq "${j}" ]; then
735				continue
736			fi
737
738			check_and_log_rt_connectivity "${i}" "${j}"
739		done
740	done
741}
742
743host2gateway_tests()
744{
745	local hs
746
747	log_section "IPv4/IPv6 connectivity test among hosts and gateways"
748
749	for hs in ${HOSTS}; do
750		check_and_log_hs2gw_connectivity "${hs}"
751	done
752}
753
754host_vpn_tests()
755{
756	log_section "SRv6 VPN connectivity test hosts (h1 <-> h2, IPv4/IPv6)"
757
758	check_and_log_hs_connectivity 1 2
759	check_and_log_hs_connectivity 2 1
760
761	log_section "SRv6 VPN connectivity test hosts (h3 <-> h4, IPv6 only)"
762
763	check_and_log_hs_ipv6_connectivity 3 4
764	check_and_log_hs_ipv6_connectivity 4 3
765}
766
767host_vpn_isolation_tests()
768{
769	local l1="1 2"
770	local l2="3 4"
771	local tmp
772	local i
773	local j
774	local k
775
776	log_section "SRv6 VPN isolation test among hosts"
777
778	for k in 0 1; do
779		for i in ${l1}; do
780			for j in ${l2}; do
781				check_and_log_hs_isolation "${i}" "${j}"
782			done
783		done
784
785		# let us test the reverse path
786		tmp="${l1}"; l1="${l2}"; l2="${tmp}"
787	done
788
789	log_section "SRv6 VPN isolation test among hosts (h2 <-> h4, IPv4 only)"
790
791	check_and_log_hs_ipv4_isolation 2 4
792	check_and_log_hs_ipv4_isolation 4 2
793}
794
795test_iproute2_supp_or_ksft_skip()
796{
797	if ! ip route help 2>&1 | grep -qo "encap.red"; then
798		echo "SKIP: Missing SRv6 encap.red support in iproute2"
799		exit "${ksft_skip}"
800	fi
801}
802
803test_vrf_or_ksft_skip()
804{
805	modprobe vrf &>/dev/null || true
806	if [ ! -e /proc/sys/net/vrf/strict_mode ]; then
807		echo "SKIP: vrf sysctl does not exist"
808		exit "${ksft_skip}"
809	fi
810}
811
812if [ "$(id -u)" -ne 0 ]; then
813	echo "SKIP: Need root privileges"
814	exit "${ksft_skip}"
815fi
816
817# required programs to carry out this selftest
818test_command_or_ksft_skip ip
819test_command_or_ksft_skip ping
820test_command_or_ksft_skip sysctl
821test_command_or_ksft_skip grep
822
823test_iproute2_supp_or_ksft_skip
824test_vrf_or_ksft_skip
825
826set -e
827trap cleanup EXIT
828
829setup
830set +e
831
832router_tests
833host2gateway_tests
834host_vpn_tests
835host_vpn_isolation_tests
836
837print_log_test_results
838