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