Merge tag 'phy-for-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy
[linux-block.git] / tools / testing / selftests / net / srv6_hencap_red_l3vpn_test.sh
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
169 # Kselftest framework requirement - SKIP code is 4.
170 readonly ksft_skip=4
171
172 readonly RDMSUFF="$(mktemp -u XXXXXXXX)"
173 readonly VRF_TID=100
174 readonly VRF_DEVNAME="vrf-${VRF_TID}"
175 readonly RT2HS_DEVNAME="veth-t${VRF_TID}"
176 readonly LOCALSID_TABLE_ID=90
177 readonly IPv6_RT_NETWORK=fcf0:0
178 readonly IPv6_HS_NETWORK=cafe
179 readonly IPv4_HS_NETWORK=10.0.0
180 readonly VPN_LOCATOR_SERVICE=fcff
181 readonly END_FUNC=000e
182 readonly DT46_FUNC=0d46
183
184 PING_TIMEOUT_SEC=4
185 PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
186
187 # IDs of routers and hosts are initialized during the setup of the testing
188 # network
189 ROUTERS=''
190 HOSTS=''
191
192 SETUP_ERR=1
193
194 ret=${ksft_skip}
195 nsuccess=0
196 nfail=0
197
198 log_test()
199 {
200         local rc="$1"
201         local expected="$2"
202         local msg="$3"
203
204         if [ "${rc}" -eq "${expected}" ]; then
205                 nsuccess=$((nsuccess+1))
206                 printf "\n    TEST: %-60s  [ OK ]\n" "${msg}"
207         else
208                 ret=1
209                 nfail=$((nfail+1))
210                 printf "\n    TEST: %-60s  [FAIL]\n" "${msg}"
211                 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
212                         echo
213                         echo "hit enter to continue, 'q' to quit"
214                         read a
215                         [ "$a" = "q" ] && exit 1
216                 fi
217         fi
218 }
219
220 print_log_test_results()
221 {
222         printf "\nTests passed: %3d\n" "${nsuccess}"
223         printf "Tests failed: %3d\n"   "${nfail}"
224
225         # when a test fails, the value of 'ret' is set to 1 (error code).
226         # Conversely, when all tests are passed successfully, the 'ret' value
227         # is set to 0 (success code).
228         if [ "${ret}" -ne 1 ]; then
229                 ret=0
230         fi
231 }
232
233 log_section()
234 {
235         echo
236         echo "################################################################################"
237         echo "TEST SECTION: $*"
238         echo "################################################################################"
239 }
240
241 test_command_or_ksft_skip()
242 {
243         local cmd="$1"
244
245         if [ ! -x "$(command -v "${cmd}")" ]; then
246                 echo "SKIP: Could not run test without \"${cmd}\" tool";
247                 exit "${ksft_skip}"
248         fi
249 }
250
251 get_nodename()
252 {
253         local name="$1"
254
255         echo "${name}-${RDMSUFF}"
256 }
257
258 get_rtname()
259 {
260         local rtid="$1"
261
262         get_nodename "rt-${rtid}"
263 }
264
265 get_hsname()
266 {
267         local hsid="$1"
268
269         get_nodename "hs-${hsid}"
270 }
271
272 __create_namespace()
273 {
274         local name="$1"
275
276         ip netns add "${name}"
277 }
278
279 create_router()
280 {
281         local rtid="$1"
282         local nsname
283
284         nsname="$(get_rtname "${rtid}")"
285
286         __create_namespace "${nsname}"
287 }
288
289 create_host()
290 {
291         local hsid="$1"
292         local nsname
293
294         nsname="$(get_hsname "${hsid}")"
295
296         __create_namespace "${nsname}"
297 }
298
299 cleanup()
300 {
301         local nsname
302         local i
303
304         # destroy routers
305         for i in ${ROUTERS}; do
306                 nsname="$(get_rtname "${i}")"
307
308                 ip netns del "${nsname}" &>/dev/null || true
309         done
310
311         # destroy hosts
312         for i in ${HOSTS}; do
313                 nsname="$(get_hsname "${i}")"
314
315                 ip netns del "${nsname}" &>/dev/null || true
316         done
317
318         # check whether the setup phase was completed successfully or not. In
319         # case of an error during the setup phase of the testing environment,
320         # the selftest is considered as "skipped".
321         if [ "${SETUP_ERR}" -ne 0 ]; then
322                 echo "SKIP: Setting up the testing environment failed"
323                 exit "${ksft_skip}"
324         fi
325
326         exit "${ret}"
327 }
328
329 add_link_rt_pairs()
330 {
331         local rt="$1"
332         local rt_neighs="$2"
333         local neigh
334         local nsname
335         local neigh_nsname
336
337         nsname="$(get_rtname "${rt}")"
338
339         for neigh in ${rt_neighs}; do
340                 neigh_nsname="$(get_rtname "${neigh}")"
341
342                 ip link add "veth-rt-${rt}-${neigh}" netns "${nsname}" \
343                         type veth peer name "veth-rt-${neigh}-${rt}" \
344                         netns "${neigh_nsname}"
345         done
346 }
347
348 get_network_prefix()
349 {
350         local rt="$1"
351         local neigh="$2"
352         local p="${rt}"
353         local q="${neigh}"
354
355         if [ "${p}" -gt "${q}" ]; then
356                 p="${q}"; q="${rt}"
357         fi
358
359         echo "${IPv6_RT_NETWORK}:${p}:${q}"
360 }
361
362 # Setup the basic networking for the routers
363 setup_rt_networking()
364 {
365         local rt="$1"
366         local rt_neighs="$2"
367         local nsname
368         local net_prefix
369         local devname
370         local neigh
371
372         nsname="$(get_rtname "${rt}")"
373
374         for neigh in ${rt_neighs}; do
375                 devname="veth-rt-${rt}-${neigh}"
376
377                 net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
378
379                 ip -netns "${nsname}" addr \
380                         add "${net_prefix}::${rt}/64" dev "${devname}" nodad
381
382                 ip -netns "${nsname}" link set "${devname}" up
383         done
384
385         ip -netns "${nsname}" link set lo up
386
387         ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
388         ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
389         ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.forwarding=1
390
391         ip netns exec "${nsname}" sysctl -wq net.ipv4.conf.all.rp_filter=0
392         ip netns exec "${nsname}" sysctl -wq net.ipv4.conf.default.rp_filter=0
393         ip netns exec "${nsname}" sysctl -wq net.ipv4.ip_forward=1
394 }
395
396 # Setup local SIDs for an SRv6 router
397 setup_rt_local_sids()
398 {
399         local rt="$1"
400         local rt_neighs="$2"
401         local net_prefix
402         local devname
403         local nsname
404         local neigh
405
406         nsname="$(get_rtname "${rt}")"
407
408         for neigh in ${rt_neighs}; do
409                 devname="veth-rt-${rt}-${neigh}"
410
411                 net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
412
413                 # set underlay network routes for SIDs reachability
414                 ip -netns "${nsname}" -6 route \
415                         add "${VPN_LOCATOR_SERVICE}:${neigh}::/32" \
416                         table "${LOCALSID_TABLE_ID}" \
417                         via "${net_prefix}::${neigh}" dev "${devname}"
418         done
419
420         # Local End behavior (note that "dev" is dummy and the VRF is chosen
421         # for the sake of simplicity).
422         ip -netns "${nsname}" -6 route \
423                 add "${VPN_LOCATOR_SERVICE}:${rt}::${END_FUNC}" \
424                 table "${LOCALSID_TABLE_ID}" \
425                 encap seg6local action End dev "${VRF_DEVNAME}"
426
427         # Local End.DT46 behavior
428         ip -netns "${nsname}" -6 route \
429                 add "${VPN_LOCATOR_SERVICE}:${rt}::${DT46_FUNC}" \
430                 table "${LOCALSID_TABLE_ID}" \
431                 encap seg6local action End.DT46 vrftable "${VRF_TID}" \
432                 dev "${VRF_DEVNAME}"
433
434         # all SIDs for VPNs start with a common locator. Routes and SRv6
435         # Endpoint behavior instaces are grouped together in the 'localsid'
436         # table.
437         ip -netns "${nsname}" -6 rule \
438                 add to "${VPN_LOCATOR_SERVICE}::/16" \
439                 lookup "${LOCALSID_TABLE_ID}" prio 999
440
441         # set default routes to unreachable for both ipv4 and ipv6
442         ip -netns "${nsname}" -6 route \
443                 add unreachable default metric 4278198272 \
444                 vrf "${VRF_DEVNAME}"
445
446         ip -netns "${nsname}" -4 route \
447                 add unreachable default metric 4278198272 \
448                 vrf "${VRF_DEVNAME}"
449 }
450
451 # build and install the SRv6 policy into the ingress SRv6 router.
452 # args:
453 #  $1 - destination host (i.e. cafe::x host)
454 #  $2 - SRv6 router configured for enforcing the SRv6 Policy
455 #  $3 - SRv6 routers configured for steering traffic (End behaviors)
456 #  $4 - SRv6 router configured for removing the SRv6 Policy (router connected
457 #       to the destination host)
458 #  $5 - encap mode (full or red)
459 #  $6 - traffic type (IPv6 or IPv4)
460 __setup_rt_policy()
461 {
462         local dst="$1"
463         local encap_rt="$2"
464         local end_rts="$3"
465         local dec_rt="$4"
466         local mode="$5"
467         local traffic="$6"
468         local nsname
469         local policy=''
470         local n
471
472         nsname="$(get_rtname "${encap_rt}")"
473
474         for n in ${end_rts}; do
475                 policy="${policy}${VPN_LOCATOR_SERVICE}:${n}::${END_FUNC},"
476         done
477
478         policy="${policy}${VPN_LOCATOR_SERVICE}:${dec_rt}::${DT46_FUNC}"
479
480         # add SRv6 policy to incoming traffic sent by connected hosts
481         if [ "${traffic}" -eq 6 ]; then
482                 ip -netns "${nsname}" -6 route \
483                         add "${IPv6_HS_NETWORK}::${dst}" vrf "${VRF_DEVNAME}" \
484                         encap seg6 mode "${mode}" segs "${policy}" \
485                         dev "${VRF_DEVNAME}"
486
487                 ip -netns "${nsname}" -6 neigh \
488                         add proxy "${IPv6_HS_NETWORK}::${dst}" \
489                         dev "${RT2HS_DEVNAME}"
490         else
491                 # "dev" must be different from the one where the packet is
492                 # received, otherwise the proxy arp does not work.
493                 ip -netns "${nsname}" -4 route \
494                         add "${IPv4_HS_NETWORK}.${dst}" vrf "${VRF_DEVNAME}" \
495                         encap seg6 mode "${mode}" segs "${policy}" \
496                         dev "${VRF_DEVNAME}"
497         fi
498 }
499
500 # see __setup_rt_policy
501 setup_rt_policy_ipv6()
502 {
503         __setup_rt_policy "$1" "$2" "$3" "$4" "$5" 6
504 }
505
506 #see __setup_rt_policy
507 setup_rt_policy_ipv4()
508 {
509         __setup_rt_policy "$1" "$2" "$3" "$4" "$5" 4
510 }
511
512 setup_hs()
513 {
514         local hs="$1"
515         local rt="$2"
516         local hsname
517         local rtname
518
519         hsname="$(get_hsname "${hs}")"
520         rtname="$(get_rtname "${rt}")"
521
522         ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
523         ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
524
525         ip -netns "${hsname}" link add veth0 type veth \
526                 peer name "${RT2HS_DEVNAME}" netns "${rtname}"
527
528         ip -netns "${hsname}" addr \
529                 add "${IPv6_HS_NETWORK}::${hs}/64" dev veth0 nodad
530         ip -netns "${hsname}" addr add "${IPv4_HS_NETWORK}.${hs}/24" dev veth0
531
532         ip -netns "${hsname}" link set veth0 up
533         ip -netns "${hsname}" link set lo up
534
535         # configure the VRF on the router which is directly connected to the
536         # source host.
537         ip -netns "${rtname}" link \
538                 add "${VRF_DEVNAME}" type vrf table "${VRF_TID}"
539         ip -netns "${rtname}" link set "${VRF_DEVNAME}" up
540
541         # enslave the veth interface connecting the router with the host to the
542         # VRF in the access router
543         ip -netns "${rtname}" link \
544                 set "${RT2HS_DEVNAME}" master "${VRF_DEVNAME}"
545
546         ip -netns "${rtname}" addr \
547                 add "${IPv6_HS_NETWORK}::254/64" dev "${RT2HS_DEVNAME}" nodad
548         ip -netns "${rtname}" addr \
549                 add "${IPv4_HS_NETWORK}.254/24" dev "${RT2HS_DEVNAME}"
550
551         ip -netns "${rtname}" link set "${RT2HS_DEVNAME}" up
552
553         ip netns exec "${rtname}" \
554                 sysctl -wq net.ipv6.conf."${RT2HS_DEVNAME}".proxy_ndp=1
555         ip netns exec "${rtname}" \
556                 sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".proxy_arp=1
557
558         # disable the rp_filter otherwise the kernel gets confused about how
559         # to route decap ipv4 packets.
560         ip netns exec "${rtname}" \
561                 sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".rp_filter=0
562
563         ip netns exec "${rtname}" sh -c "echo 1 > /proc/sys/net/vrf/strict_mode"
564 }
565
566 setup()
567 {
568         local i
569
570         # create routers
571         ROUTERS="1 2 3 4"; readonly ROUTERS
572         for i in ${ROUTERS}; do
573                 create_router "${i}"
574         done
575
576         # create hosts
577         HOSTS="1 2 3 4"; readonly HOSTS
578         for i in ${HOSTS}; do
579                 create_host "${i}"
580         done
581
582         # set up the links for connecting routers
583         add_link_rt_pairs 1 "2 3 4"
584         add_link_rt_pairs 2 "3 4"
585         add_link_rt_pairs 3 "4"
586
587         # set up the basic connectivity of routers and routes required for
588         # reachability of SIDs.
589         setup_rt_networking 1 "2 3 4"
590         setup_rt_networking 2 "1 3 4"
591         setup_rt_networking 3 "1 2 4"
592         setup_rt_networking 4 "1 2 3"
593
594         # set up the hosts connected to routers
595         setup_hs 1 1
596         setup_hs 2 2
597         setup_hs 3 3
598         setup_hs 4 4
599
600         # set up default SRv6 Endpoints (i.e. SRv6 End and SRv6 End.DT46)
601         setup_rt_local_sids 1 "2 3 4"
602         setup_rt_local_sids 2 "1 3 4"
603         setup_rt_local_sids 3 "1 2 4"
604         setup_rt_local_sids 4 "1 2 3"
605
606         # set up SRv6 policies
607
608         # create an IPv6 VPN between hosts hs-1 and hs-2.
609         # the network path between hs-1 and hs-2 traverses several routers
610         # depending on the direction of traffic.
611         #
612         # Direction hs-1 -> hs-2 (H.Encaps.Red)
613         #  - rt-3,rt-4 (SRv6 End behaviors)
614         #  - rt-2 (SRv6 End.DT46 behavior)
615         #
616         # Direction hs-2 -> hs-1 (H.Encaps.Red)
617         #  - rt-1 (SRv6 End.DT46 behavior)
618         setup_rt_policy_ipv6 2 1 "3 4" 2 encap.red
619         setup_rt_policy_ipv6 1 2 "" 1 encap.red
620
621         # create an IPv4 VPN between hosts hs-1 and hs-2
622         # the network path between hs-1 and hs-2 traverses several routers
623         # depending on the direction of traffic.
624         #
625         # Direction hs-1 -> hs-2 (H.Encaps.Red)
626         # - rt-2 (SRv6 End.DT46 behavior)
627         #
628         # Direction hs-2 -> hs-1 (H.Encaps.Red)
629         #  - rt-4,rt-3 (SRv6 End behaviors)
630         #  - rt-1 (SRv6 End.DT46 behavior)
631         setup_rt_policy_ipv4 2 1 "" 2 encap.red
632         setup_rt_policy_ipv4 1 2 "4 3" 1 encap.red
633
634         # create an IPv6 VPN between hosts hs-3 and hs-4
635         # the network path between hs-3 and hs-4 traverses several routers
636         # depending on the direction of traffic.
637         #
638         # Direction hs-3 -> hs-4 (H.Encaps.Red)
639         # - rt-2 (SRv6 End Behavior)
640         # - rt-4 (SRv6 End.DT46 behavior)
641         #
642         # Direction hs-4 -> hs-3 (H.Encaps.Red)
643         #  - rt-1 (SRv6 End behavior)
644         #  - rt-3 (SRv6 End.DT46 behavior)
645         setup_rt_policy_ipv6 4 3 "2" 4 encap.red
646         setup_rt_policy_ipv6 3 4 "1" 3 encap.red
647
648         # testing environment was set up successfully
649         SETUP_ERR=0
650 }
651
652 check_rt_connectivity()
653 {
654         local rtsrc="$1"
655         local rtdst="$2"
656         local prefix
657         local rtsrc_nsname
658
659         rtsrc_nsname="$(get_rtname "${rtsrc}")"
660
661         prefix="$(get_network_prefix "${rtsrc}" "${rtdst}")"
662
663         ip netns exec "${rtsrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
664                 "${prefix}::${rtdst}" >/dev/null 2>&1
665 }
666
667 check_and_log_rt_connectivity()
668 {
669         local rtsrc="$1"
670         local rtdst="$2"
671
672         check_rt_connectivity "${rtsrc}" "${rtdst}"
673         log_test $? 0 "Routers connectivity: rt-${rtsrc} -> rt-${rtdst}"
674 }
675
676 check_hs_ipv6_connectivity()
677 {
678         local hssrc="$1"
679         local hsdst="$2"
680         local hssrc_nsname
681
682         hssrc_nsname="$(get_hsname "${hssrc}")"
683
684         ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
685                 "${IPv6_HS_NETWORK}::${hsdst}" >/dev/null 2>&1
686 }
687
688 check_hs_ipv4_connectivity()
689 {
690         local hssrc="$1"
691         local hsdst="$2"
692         local hssrc_nsname
693
694         hssrc_nsname="$(get_hsname "${hssrc}")"
695
696         ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
697                 "${IPv4_HS_NETWORK}.${hsdst}" >/dev/null 2>&1
698 }
699
700 check_and_log_hs2gw_connectivity()
701 {
702         local hssrc="$1"
703
704         check_hs_ipv6_connectivity "${hssrc}" 254
705         log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> gw"
706
707         check_hs_ipv4_connectivity "${hssrc}" 254
708         log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> gw"
709 }
710
711 check_and_log_hs_ipv6_connectivity()
712 {
713         local hssrc="$1"
714         local hsdst="$2"
715
716         check_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
717         log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"
718 }
719
720 check_and_log_hs_ipv4_connectivity()
721 {
722         local hssrc="$1"
723         local hsdst="$2"
724
725         check_hs_ipv4_connectivity "${hssrc}" "${hsdst}"
726         log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"
727 }
728
729 check_and_log_hs_connectivity()
730 {
731         local hssrc="$1"
732         local hsdst="$2"
733
734         check_and_log_hs_ipv4_connectivity "${hssrc}" "${hsdst}"
735         check_and_log_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
736 }
737
738 check_and_log_hs_ipv6_isolation()
739 {
740         local hssrc="$1"
741         local hsdst="$2"
742
743         # in this case, the connectivity test must fail
744         check_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
745         log_test $? 1 "IPv6 Hosts isolation: hs-${hssrc} -X-> hs-${hsdst}"
746 }
747
748 check_and_log_hs_ipv4_isolation()
749 {
750         local hssrc="$1"
751         local hsdst="$2"
752
753         # in this case, the connectivity test must fail
754         check_hs_ipv4_connectivity "${hssrc}" "${hsdst}"
755         log_test $? 1 "IPv4 Hosts isolation: hs-${hssrc} -X-> hs-${hsdst}"
756 }
757
758 check_and_log_hs_isolation()
759 {
760         local hssrc="$1"
761         local hsdst="$2"
762
763         check_and_log_hs_ipv6_isolation "${hssrc}" "${hsdst}"
764         check_and_log_hs_ipv4_isolation "${hssrc}" "${hsdst}"
765 }
766
767 router_tests()
768 {
769         local i
770         local j
771
772         log_section "IPv6 routers connectivity test"
773
774         for i in ${ROUTERS}; do
775                 for j in ${ROUTERS}; do
776                         if [ "${i}" -eq "${j}" ]; then
777                                 continue
778                         fi
779
780                         check_and_log_rt_connectivity "${i}" "${j}"
781                 done
782         done
783 }
784
785 host2gateway_tests()
786 {
787         local hs
788
789         log_section "IPv4/IPv6 connectivity test among hosts and gateways"
790
791         for hs in ${HOSTS}; do
792                 check_and_log_hs2gw_connectivity "${hs}"
793         done
794 }
795
796 host_vpn_tests()
797 {
798         log_section "SRv6 VPN connectivity test hosts (h1 <-> h2, IPv4/IPv6)"
799
800         check_and_log_hs_connectivity 1 2
801         check_and_log_hs_connectivity 2 1
802
803         log_section "SRv6 VPN connectivity test hosts (h3 <-> h4, IPv6 only)"
804
805         check_and_log_hs_ipv6_connectivity 3 4
806         check_and_log_hs_ipv6_connectivity 4 3
807 }
808
809 host_vpn_isolation_tests()
810 {
811         local l1="1 2"
812         local l2="3 4"
813         local tmp
814         local i
815         local j
816         local k
817
818         log_section "SRv6 VPN isolation test among hosts"
819
820         for k in 0 1; do
821                 for i in ${l1}; do
822                         for j in ${l2}; do
823                                 check_and_log_hs_isolation "${i}" "${j}"
824                         done
825                 done
826
827                 # let us test the reverse path
828                 tmp="${l1}"; l1="${l2}"; l2="${tmp}"
829         done
830
831         log_section "SRv6 VPN isolation test among hosts (h2 <-> h4, IPv4 only)"
832
833         check_and_log_hs_ipv4_isolation 2 4
834         check_and_log_hs_ipv4_isolation 4 2
835 }
836
837 test_iproute2_supp_or_ksft_skip()
838 {
839         if ! ip route help 2>&1 | grep -qo "encap.red"; then
840                 echo "SKIP: Missing SRv6 encap.red support in iproute2"
841                 exit "${ksft_skip}"
842         fi
843 }
844
845 test_vrf_or_ksft_skip()
846 {
847         modprobe vrf &>/dev/null || true
848         if [ ! -e /proc/sys/net/vrf/strict_mode ]; then
849                 echo "SKIP: vrf sysctl does not exist"
850                 exit "${ksft_skip}"
851         fi
852 }
853
854 if [ "$(id -u)" -ne 0 ]; then
855         echo "SKIP: Need root privileges"
856         exit "${ksft_skip}"
857 fi
858
859 # required programs to carry out this selftest
860 test_command_or_ksft_skip ip
861 test_command_or_ksft_skip ping
862 test_command_or_ksft_skip sysctl
863 test_command_or_ksft_skip grep
864
865 test_iproute2_supp_or_ksft_skip
866 test_vrf_or_ksft_skip
867
868 set -e
869 trap cleanup EXIT
870
871 setup
872 set +e
873
874 router_tests
875 host2gateway_tests
876 host_vpn_tests
877 host_vpn_isolation_tests
878
879 print_log_test_results