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