]> Git Repo - linux.git/blob - tools/testing/selftests/net/srv6_end_x_next_csid_l3vpn_test.sh
x86/kaslr: Expose and use the end of the physical memory address space
[linux.git] / tools / testing / selftests / net / srv6_end_x_next_csid_l3vpn_test.sh
1 #!/bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 #
4 # author: Andrea Mayer <[email protected]>
5 # author: Paolo Lungaroni <[email protected]>
6 #
7 # This script is designed for testing the support of NEXT-C-SID flavor for SRv6
8 # End.X behavior.
9 # A basic knowledge of SRv6 architecture [1] and of the compressed SID approach
10 # [2] is assumed for the reader.
11 #
12 # The network topology used in the selftest is depicted hereafter, composed of
13 # two hosts and four routers. Hosts hs-1 and hs-2 are connected through an
14 # IPv4/IPv6 L3 VPN service, offered by routers rt-1, rt-2, rt-3 and rt-4 using
15 # the NEXT-C-SID flavor. The key components for such VPNs are:
16 #
17 #    i) The SRv6 H.Encaps/H.Encaps.Red behaviors [1] apply SRv6 Policies on
18 #       traffic received by connected hosts, initiating the VPN tunnel;
19 #
20 #   ii) The SRv6 End.X behavior [1] (Endpoint with L3 cross connect) is a
21 #       variant of SRv6 End behavior. It advances the active SID in the SID
22 #       List carried by the SRH and forwards the packet to an L3 adjacency;
23 #
24 #  iii) The NEXT-C-SID mechanism [2] offers the possibility of encoding several
25 #       SRv6 segments within a single 128-bit SID address, referred to as a
26 #       Compressed SID (C-SID) container. In this way, the length of the SID
27 #       List can be drastically reduced.
28 #       The NEXT-C-SID is provided as a "flavor" of the SRv6 End.X behavior
29 #       which advances the current C-SID (i.e. the Locator-Node Function defined
30 #       in [2]) with the next one carried in the Argument, if available.
31 #       When no more C-SIDs are available in the Argument, the SRv6 End.X
32 #       behavior will apply the End.X function selecting the next SID in the SID
33 #       List;
34 #
35 #   iv) The SRv6 End.DT46 behavior [1] is used for removing the SRv6 Policy and,
36 #       thus, it terminates the VPN tunnel. Such a behavior is capable of
37 #       handling, at the same time, both tunneled IPv4 and IPv6 traffic.
38 #
39 # [1] https://datatracker.ietf.org/doc/html/rfc8986
40 # [2] https://datatracker.ietf.org/doc/html/draft-ietf-spring-srv6-srh-compression
41 #
42 #
43 #               cafe::1                      cafe::2
44 #              10.0.0.1                     10.0.0.2
45 #             +--------+                   +--------+
46 #             |        |                   |        |
47 #             |  hs-1  |                   |  hs-2  |
48 #             |        |                   |        |
49 #             +---+----+                   +----+---+
50 #    cafe::/64    |                             |      cafe::/64
51 #  10.0.0.0/24    |                             |    10.0.0.0/24
52 #             +---+----+                   +----+---+
53 #             |        |  fcf0:0:1:2::/64  |        |
54 #             |  rt-1  +-------------------+  rt-2  |
55 #             |        |                   |        |
56 #             +---+----+                   +----+---+
57 #                 |      .               .      |
58 #                 |  fcf0:0:1:3::/64   .        |
59 #                 |          .       .          |
60 #                 |            .   .            |
61 # fcf0:0:1:4::/64 |              .              | fcf0:0:2:3::/64
62 #                 |            .   .            |
63 #                 |          .       .          |
64 #                 |  fcf0:0:2:4::/64   .        |
65 #                 |      .               .      |
66 #             +---+----+                   +----+---+
67 #             |        |                   |        |
68 #             |  rt-4  +-------------------+  rt-3  |
69 #             |        |  fcf0:0:3:4::/64  |        |
70 #             +---+----+                   +----+---+
71 #
72 # Every fcf0:0:x:y::/64 network interconnects the SRv6 routers rt-x with rt-y in
73 # the selftest network.
74 #
75 # Local SID/C-SID table
76 # =====================
77 #
78 # Each SRv6 router is configured with a Local SID/C-SID table in which
79 # SIDs/C-SIDs are stored. Considering an SRv6 router rt-x, SIDs/C-SIDs are
80 # configured in the Local SID/C-SIDs table as follows:
81 #
82 #   Local SID/C-SID table for SRv6 router rt-x
83 #   +-----------------------------------------------------------+
84 #   |fcff:x::d46 is associated with the non-compressed SRv6     |
85 #   |   End.DT46 behavior                                       |
86 #   +-----------------------------------------------------------+
87 #   |fcbb:0:0x00::/48 is associated with the NEXT-C-SID flavor  |
88 #   |   of SRv6 End.X behavior                                  |
89 #   +-----------------------------------------------------------+
90 #   |fcbb:0:0x00:d46::/64 is associated with the SRv6 End.DT46  |
91 #   |   behavior when NEXT-C-SID compression is turned on       |
92 #   +-----------------------------------------------------------+
93 #
94 # The fcff::/16 prefix is reserved for implementing SRv6 services with regular
95 # (non compressed) SIDs. Reachability of SIDs is ensured by proper configuration
96 # of the IPv6 routing tables in the routers.
97 # Similarly, the fcbb:0::/32 prefix is reserved for implementing SRv6 VPN
98 # services leveraging the NEXT-C-SID compression mechanism. Indeed, the
99 # fcbb:0::/32 is used for encoding the Locator-Block while the Locator-Node
100 # Function is encoded with 16 bits.
101 #
102 # Incoming traffic classification and application of SRv6 Policies
103 # ================================================================
104 #
105 # An SRv6 ingress router applies different SRv6 Policies to the traffic received
106 # from a connected host, considering the IPv4 or IPv6 destination address.
107 # SRv6 policy enforcement consists of encapsulating the received traffic into a
108 # new IPv6 packet with a given SID List contained in the SRH.
109 # When the SID List contains only one SID, the SRH could be omitted completely
110 # and that SID is stored directly in the IPv6 Destination Address (DA) (this is
111 # called "reduced" encapsulation).
112 #
113 # Test cases for NEXT-C-SID
114 # =========================
115 #
116 # We consider two test cases for NEXT-C-SID: i) single SID and ii) double SID.
117 #
118 # In the single SID test case we have a number of segments that are all
119 # contained in a single Compressed SID (C-SID) container. Therefore the
120 # resulting SID List has only one SID. Using the reduced encapsulation format
121 # this will result in a packet with no SRH.
122 #
123 # In the double SID test case we have one segment carried in a Compressed SID
124 # (C-SID) container, followed by a regular (non compressed) SID. The resulting
125 # SID List has two segments and it is possible to test the advance to the next
126 # SID when all the C-SIDs in a C-SID container have been processed. Using the
127 # reduced encapsulation format this will result in a packet with an SRH
128 # containing 1 segment.
129 #
130 # For the single SID test case, we use the IPv6 addresses of hs-1 and hs-2, for
131 # the double SID test case, we use their IPv4 addresses. This is only done to
132 # simplify the test setup and avoid adding other hosts or multiple addresses on
133 # the same interface of a host.
134 #
135 # Traffic from hs-1 to hs-2
136 # -------------------------
137 #
138 # Packets generated from hs-1 and directed towards hs-2 are handled by rt-1
139 # which applies the SRv6 Policies as follows:
140 #
141 #   i) IPv6 DA=cafe::2, H.Encaps.Red with SID List=fcbb:0:0300:0200:d46::
142 #  ii) IPv4 DA=10.0.0.2, H.Encaps.Red with SID List=fcbb:0:0300::,fcff:2::d46
143 #
144 # ### i) single SID
145 #
146 # The router rt-1 is configured to enforce the given Policy through the SRv6
147 # H.Encaps.Red behavior which avoids the presence of the SRH at all, since it
148 # pushes the single SID directly in the IPv6 DA. Such a SID encodes a whole
149 # C-SID container carrying several C-SIDs (e.g. 0300, 0200, etc).
150 #
151 # As the packet reaches the router rt-3, the enabled NEXT-C-SID SRv6 End.X
152 # behavior (associated with fcbb:0:0300::/48) is triggered. This behavior
153 # analyzes the IPv6 DA and checks whether the Argument of the C-SID container
154 # is zero or not. In this case, the Argument is *NOT* zero and the IPv6 DA is
155 # updated as follows:
156 #
157 # +-----------------------------------------------------------------+
158 # | Before applying the rt-3 enabled NEXT-C-SID SRv6 End.X behavior |
159 # +-----------------------------------------------------------------+
160 # |                            +---------- Argument                 |
161 # |                     vvvvvvvvvv                                  |
162 # | IPv6 DA fcbb:0:0300:0200:d46::                                  |
163 # |                ^^^^    <-- shifting                             |
164 # |                  |                                              |
165 # |          Locator-Node Function                                  |
166 # +-----------------------------------------------------------------+
167 # | After applying the rt-3 enabled NEXT-C-SID SRv6 End.X behavior  |
168 # +-----------------------------------------------------------------+
169 # |                          +---------- Argument                   |
170 # |                    vvvvvv                                       |
171 # | IPv6 DA fcbb:0:0200:d46::                                       |
172 # |                ^^^^                                             |
173 # |                  |                                              |
174 # |          Locator-Node Function                                  |
175 # +-----------------------------------------------------------------+
176 #
177 # After having applied the enabled NEXT-C-SID SRv6 End.X behavior, the packet
178 # is sent to rt-4 node using the L3 adjacency address fcf0:0:3:4::4.
179 #
180 # The node rt-4 performs a plain IPv6 forward to the rt-2 router according to
181 # its Local SID table and using the IPv6 DA fcbb:0:0200:d46:: .
182 #
183 # The router rt-2 is configured for decapsulating the inner IPv6 packet and,
184 # for this reason, it applies the SRv6 End.DT46 behavior on the received
185 # packet. It is worth noting that the SRv6 End.DT46 behavior does not require
186 # the presence of the SRH: it is fully capable to operate properly on
187 # IPv4/IPv6-in-IPv6 encapsulations.
188 # At the end of the decap operation, the packet is sent to the host hs-2.
189 #
190 # ### ii) double SID
191 #
192 # The router rt-1 is configured to enforce the given Policy through the SRv6
193 # H.Encaps.Red. As a result, the first SID fcbb:0:0300:: is stored into the
194 # IPv6 DA, while the SRH pushed into the packet is made of only one SID, i.e.
195 # fcff:2::d46. Hence, the packet sent by hs-1 to hs-2 is encapsulated in an
196 # outer IPv6 header plus the SRH.
197 #
198 # As the packet reaches the node rt-3, the router applies the enabled NEXT-C-SID
199 # SRv6 End.X behavior.
200 #
201 # +-----------------------------------------------------------------+
202 # | Before applying the rt-3 enabled NEXT-C-SID SRv6 End.X behavior |
203 # +-----------------------------------------------------------------+
204 # |                      +---------- Argument                       |
205 # |                      vvvv (Argument is all filled with zeros)   |
206 # | IPv6 DA fcbb:0:0300::                                           |
207 # |                ^^^^                                             |
208 # |                  |                                              |
209 # |          Locator-Node Function                                  |
210 # +-----------------------------------------------------------------+
211 # | After applying the rt-3 enabled NEXT-C-SID SRv6 End.X behavior  |
212 # +-----------------------------------------------------------------+
213 # |                                                                 |
214 # | IPv6 DA fcff:2::d46                                             |
215 # |         ^^^^^^^^^^^                                             |
216 # |              |                                                  |
217 # |        SID copied from the SID List contained in the SRH        |
218 # +-----------------------------------------------------------------+
219 #
220 # Since the Argument of the C-SID container is zero, the behavior can not
221 # update the Locator-Node function with the next C-SID carried in the Argument
222 # itself. Thus, the enabled NEXT-C-SID SRv6 End.X behavior operates as the
223 # traditional End.X behavior: it updates the IPv6 DA by copying the next
224 # available SID in the SID List carried by the SRH. Next, the packet is
225 # forwarded to the rt-4 node using the L3 adjacency fcf0:3:4::4 previously
226 # configured for this behavior.
227 #
228 # The node rt-4 performs a plain IPv6 forward to the rt-2 router according to
229 # its Local SID table and using the IPv6 DA fcff:2::d46.
230 #
231 # Once the packet is received by rt-2, the router decapsulates the inner IPv4
232 # packet using the SRv6 End.DT46 behavior (associated with the SID fcff:2::d46)
233 # and sends it to the host hs-2.
234 #
235 # Traffic from hs-2 to hs-1
236 # -------------------------
237 #
238 # Packets generated from hs-2 and directed towards hs-1 are handled by rt-2
239 # which applies the SRv6 Policies as follows:
240 #
241 #   i) IPv6 DA=cafe::1, SID List=fcbb:0:0400:0100:d46::
242 #  ii) IPv4 DA=10.0.0.1, SID List=fcbb:0:0300::,fcff:1::d46
243 #
244 # ### i) single SID
245 #
246 # The node hs-2 sends an IPv6 packet directed to node hs-1. The router rt-2 is
247 # directly connected to hs-2 and receives the packet. Rt-2 applies the
248 # H.Encap.Red behavior with policy i) described above. Since there is only one
249 # SID, the SRH header is omitted and the policy is inserted directly into the DA
250 # of IPv6 packet.
251 #
252 # The packet reaches the router rt-4 and the enabled NEXT-C-SID SRv6 End.X
253 # behavior (associated with fcbb:0:0400::/48) is triggered. This behavior
254 # analyzes the IPv6 DA and checks whether the Argument of the C-SID container
255 # is zero or not. The Argument is *NOT* zero and the C-SID in the IPv6 DA is
256 # advanced. At this point, the current IPv6 DA is fcbb:0:0100:d46:: .
257 # The enabled NEXT-C-SID SRv6 End.X behavior is configured with the L3 adjacency
258 # fcf0:0:1:4::1, used to route traffic to the rt-1 node.
259 #
260 # The router rt-1 is configured for decapsulating the inner packet. It applies
261 # the SRv6 End.DT46 behavior on the received packet. Decapsulation does not
262 # require the presence of the SRH. At the end of the decap operation, the packet
263 # is sent to the host hs-1.
264 #
265 # ### ii) double SID
266 #
267 # The router rt-2 is configured to enforce the given Policy through the SRv6
268 # H.Encaps.Red. As a result, the first SID fcbb:0:0300:: is stored into the
269 # IPv6 DA, while the SRH pushed into the packet is made of only one SID, i.e.
270 # fcff:1::d46. Hence, the packet sent by hs-2 to hs-1 is encapsulated in an
271 # outer IPv6 header plus the SRH.
272 #
273 # As the packet reaches the node rt-3, the enabled NEXT-C-SID SRv6 End.X
274 # behavior bound to the SID fcbb:0:0300::/48 is triggered.
275 # Since the Argument of the C-SID container is zero, the behavior can not
276 # update the Locator-Node function with the next C-SID carried in the Argument
277 # itself. Thus, the enabled NEXT-C-SID SRv6 End-X behavior operates as the
278 # traditional End.X behavior: it updates the IPv6 DA by copying the next
279 # available SID in the SID List carried by the SRH. After that, the packet is
280 # forwarded to the rt-4 node using the L3 adjacency (fcf0:3:4::4) previously
281 # configured for this behavior.
282 #
283 # The node rt-4 performs a plain IPv6 forward to the rt-1 router according to
284 # its Local SID table, considering the IPv6 DA fcff:1::d46.
285 #
286 # Once the packet is received by rt-1, the router decapsulates the inner IPv4
287 # packet using the SRv6 End.DT46 behavior (associated with the SID fcff:1::d46)
288 # and sends it to the host hs-1.
289
290 # Kselftest framework requirement - SKIP code is 4.
291 readonly ksft_skip=4
292
293 readonly RDMSUFF="$(mktemp -u XXXXXXXX)"
294 readonly DUMMY_DEVNAME="dum0"
295 readonly VRF_TID=100
296 readonly VRF_DEVNAME="vrf-${VRF_TID}"
297 readonly RT2HS_DEVNAME="veth-t${VRF_TID}"
298 readonly LOCALSID_TABLE_ID=90
299 readonly IPv6_RT_NETWORK=fcf0:0
300 readonly IPv6_HS_NETWORK=cafe
301 readonly IPv4_HS_NETWORK=10.0.0
302 readonly VPN_LOCATOR_SERVICE=fcff
303 readonly DT46_FUNC=0d46
304 readonly HEADEND_ENCAP="encap.red"
305
306 # do not add ':' as separator
307 readonly LCBLOCK_ADDR=fcbb0000
308 readonly LCBLOCK_BLEN=32
309 # do not add ':' as separator
310 readonly LCNODEFUNC_FMT="0%d00"
311 readonly LCNODEFUNC_BLEN=16
312
313 readonly LCBLOCK_NODEFUNC_BLEN=$((LCBLOCK_BLEN + LCNODEFUNC_BLEN))
314
315 readonly CSID_CNTR_PREFIX="dead:beaf::/32"
316 # ID of the router used for testing the C-SID container cfgs
317 readonly CSID_CNTR_RT_ID_TEST=1
318 # Routing table used for testing the C-SID container cfgs
319 readonly CSID_CNTR_RT_TABLE=91
320
321 # C-SID container configurations to be tested
322 #
323 # An entry of the array is defined as "a,b,c" where:
324 # - 'a' and 'b' elements represent respectively the Locator-Block length
325 #   (lblen) in bits and the Locator-Node Function length (nflen) in bits.
326 #   'a' and 'b' can be set to default values using the placeholder "d" which
327 #   indicates the default kernel values (32 for lblen and 16 for nflen);
328 #   otherwise, any numeric value is accepted;
329 # - 'c' indicates whether the C-SID configuration provided by the values 'a'
330 #   and 'b' should be considered valid ("y") or invalid ("n").
331 declare -ra CSID_CONTAINER_CFGS=(
332         "d,d,y"
333         "d,16,y"
334         "16,d,y"
335         "16,32,y"
336         "32,16,y"
337         "48,8,y"
338         "8,48,y"
339         "d,0,n"
340         "0,d,n"
341         "32,0,n"
342         "0,32,n"
343         "17,d,n"
344         "d,17,n"
345         "120,16,n"
346         "16,120,n"
347         "0,128,n"
348         "128,0,n"
349         "130,0,n"
350         "0,130,n"
351         "0,0,n"
352 )
353
354 PING_TIMEOUT_SEC=4
355 PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
356
357 # IDs of routers and hosts are initialized during the setup of the testing
358 # network
359 ROUTERS=''
360 HOSTS=''
361
362 SETUP_ERR=1
363
364 ret=${ksft_skip}
365 nsuccess=0
366 nfail=0
367
368 log_test()
369 {
370         local rc="$1"
371         local expected="$2"
372         local msg="$3"
373
374         if [ "${rc}" -eq "${expected}" ]; then
375                 nsuccess=$((nsuccess+1))
376                 printf "\n    TEST: %-60s  [ OK ]\n" "${msg}"
377         else
378                 ret=1
379                 nfail=$((nfail+1))
380                 printf "\n    TEST: %-60s  [FAIL]\n" "${msg}"
381                 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
382                         echo
383                         echo "hit enter to continue, 'q' to quit"
384                         read a
385                         [ "$a" = "q" ] && exit 1
386                 fi
387         fi
388 }
389
390 print_log_test_results()
391 {
392         printf "\nTests passed: %3d\n" "${nsuccess}"
393         printf "Tests failed: %3d\n"   "${nfail}"
394
395         # when a test fails, the value of 'ret' is set to 1 (error code).
396         # Conversely, when all tests are passed successfully, the 'ret' value
397         # is set to 0 (success code).
398         if [ "${ret}" -ne 1 ]; then
399                 ret=0
400         fi
401 }
402
403 log_section()
404 {
405         echo
406         echo "################################################################################"
407         echo "TEST SECTION: $*"
408         echo "################################################################################"
409 }
410
411 test_command_or_ksft_skip()
412 {
413         local cmd="$1"
414
415         if [ ! -x "$(command -v "${cmd}")" ]; then
416                 echo "SKIP: Could not run test without \"${cmd}\" tool";
417                 exit "${ksft_skip}"
418         fi
419 }
420
421 get_nodename()
422 {
423         local name="$1"
424
425         echo "${name}-${RDMSUFF}"
426 }
427
428 get_rtname()
429 {
430         local rtid="$1"
431
432         get_nodename "rt-${rtid}"
433 }
434
435 get_hsname()
436 {
437         local hsid="$1"
438
439         get_nodename "hs-${hsid}"
440 }
441
442 __create_namespace()
443 {
444         local name="$1"
445
446         ip netns add "${name}"
447 }
448
449 create_router()
450 {
451         local rtid="$1"
452         local nsname
453
454         nsname="$(get_rtname "${rtid}")"
455
456         __create_namespace "${nsname}"
457
458         ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
459         ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
460         ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.forwarding=1
461
462         ip netns exec "${nsname}" sysctl -wq net.ipv4.conf.all.rp_filter=0
463         ip netns exec "${nsname}" sysctl -wq net.ipv4.conf.default.rp_filter=0
464         ip netns exec "${nsname}" sysctl -wq net.ipv4.ip_forward=1
465 }
466
467 create_host()
468 {
469         local hsid="$1"
470         local nsname
471
472         nsname="$(get_hsname "${hsid}")"
473
474         __create_namespace "${nsname}"
475 }
476
477 cleanup()
478 {
479         local nsname
480         local i
481
482         # destroy routers
483         for i in ${ROUTERS}; do
484                 nsname="$(get_rtname "${i}")"
485
486                 ip netns del "${nsname}" &>/dev/null || true
487         done
488
489         # destroy hosts
490         for i in ${HOSTS}; do
491                 nsname="$(get_hsname "${i}")"
492
493                 ip netns del "${nsname}" &>/dev/null || true
494         done
495
496         # check whether the setup phase was completed successfully or not. In
497         # case of an error during the setup phase of the testing environment,
498         # the selftest is considered as "skipped".
499         if [ "${SETUP_ERR}" -ne 0 ]; then
500                 echo "SKIP: Setting up the testing environment failed"
501                 exit "${ksft_skip}"
502         fi
503
504         exit "${ret}"
505 }
506
507 add_link_rt_pairs()
508 {
509         local rt="$1"
510         local rt_neighs="$2"
511         local neigh
512         local nsname
513         local neigh_nsname
514
515         nsname="$(get_rtname "${rt}")"
516
517         for neigh in ${rt_neighs}; do
518                 neigh_nsname="$(get_rtname "${neigh}")"
519
520                 ip link add "veth-rt-${rt}-${neigh}" netns "${nsname}" \
521                         type veth peer name "veth-rt-${neigh}-${rt}" \
522                         netns "${neigh_nsname}"
523         done
524 }
525
526 get_network_prefix()
527 {
528         local rt="$1"
529         local neigh="$2"
530         local p="${rt}"
531         local q="${neigh}"
532
533         if [ "${p}" -gt "${q}" ]; then
534                 p="${q}"; q="${rt}"
535         fi
536
537         echo "${IPv6_RT_NETWORK}:${p}:${q}"
538 }
539
540 # Setup the basic networking for the routers
541 setup_rt_networking()
542 {
543         local rt="$1"
544         local rt_neighs="$2"
545         local nsname
546         local net_prefix
547         local devname
548         local neigh
549
550         nsname="$(get_rtname "${rt}")"
551
552         for neigh in ${rt_neighs}; do
553                 devname="veth-rt-${rt}-${neigh}"
554
555                 net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
556
557                 ip -netns "${nsname}" addr \
558                         add "${net_prefix}::${rt}/64" dev "${devname}" nodad
559
560                 ip -netns "${nsname}" link set "${devname}" up
561         done
562
563         ip -netns "${nsname}" link add "${DUMMY_DEVNAME}" type dummy
564
565         ip -netns "${nsname}" link set "${DUMMY_DEVNAME}" up
566         ip -netns "${nsname}" link set lo up
567 }
568
569 # build an ipv6 prefix/address based on the input string
570 # Note that the input string does not contain ':' and '::' which are considered
571 # to be implicit.
572 # e.g.:
573 #  - input:  fbcc00000400300
574 #  - output: fbcc:0000:0400:0300:0000:0000:0000:0000
575 #                                ^^^^^^^^^^^^^^^^^^^
576 #                              fill the address with 0s
577 build_ipv6_addr()
578 {
579         local addr="$1"
580         local out=""
581         local strlen="${#addr}"
582         local padn
583         local i
584
585         # add ":" every 4 digits (16 bits)
586         for (( i = 0; i < strlen; i++ )); do
587                 if (( i > 0 && i < 32 && (i % 4) == 0 )); then
588                         out="${out}:"
589                 fi
590
591                 out="${out}${addr:$i:1}"
592         done
593
594         # fill the remaining bits of the address with 0s
595         padn=$((32 - strlen))
596         for (( i = padn; i > 0; i-- )); do
597                 if (( i > 0 && i < 32 && (i % 4) == 0 )); then
598                         out="${out}:"
599                 fi
600
601                 out="${out}0"
602         done
603
604         printf "${out}"
605 }
606
607 build_csid()
608 {
609         local nodeid="$1"
610
611         printf "${LCNODEFUNC_FMT}" "${nodeid}"
612 }
613
614 build_lcnode_func_prefix()
615 {
616         local nodeid="$1"
617         local lcnodefunc
618         local prefix
619         local out
620
621         lcnodefunc="$(build_csid "${nodeid}")"
622         prefix="$(build_ipv6_addr "${LCBLOCK_ADDR}${lcnodefunc}")"
623
624         out="${prefix}/${LCBLOCK_NODEFUNC_BLEN}"
625
626         echo "${out}"
627 }
628
629 set_end_x_nextcsid()
630 {
631         local rt="$1"
632         local adj="$2"
633
634         nsname="$(get_rtname "${rt}")"
635         net_prefix="$(get_network_prefix "${rt}" "${adj}")"
636         lcnode_func_prefix="$(build_lcnode_func_prefix "${rt}")"
637
638         # enabled NEXT-C-SID SRv6 End.X behavior (note that "dev" is the dummy
639         # dum0 device chosen for the sake of simplicity).
640         ip -netns "${nsname}" -6 route \
641                 replace "${lcnode_func_prefix}" \
642                 table "${LOCALSID_TABLE_ID}" \
643                 encap seg6local action End.X nh6 "${net_prefix}::${adj}" \
644                 flavors next-csid lblen "${LCBLOCK_BLEN}" \
645                 nflen "${LCNODEFUNC_BLEN}" dev "${DUMMY_DEVNAME}"
646 }
647
648 set_underlay_sids_reachability()
649 {
650         local rt="$1"
651         local rt_neighs="$2"
652
653         nsname="$(get_rtname "${rt}")"
654
655         for neigh in ${rt_neighs}; do
656                 devname="veth-rt-${rt}-${neigh}"
657
658                 net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
659
660                 # set underlay network routes for SIDs reachability
661                 ip -netns "${nsname}" -6 route \
662                         replace "${VPN_LOCATOR_SERVICE}:${neigh}::/32" \
663                         table "${LOCALSID_TABLE_ID}" \
664                         via "${net_prefix}::${neigh}" dev "${devname}"
665
666                 # set the underlay network for C-SIDs reachability
667                 lcnode_func_prefix="$(build_lcnode_func_prefix "${neigh}")"
668
669                 ip -netns "${nsname}" -6 route \
670                         replace "${lcnode_func_prefix}" \
671                         table "${LOCALSID_TABLE_ID}" \
672                         via "${net_prefix}::${neigh}" dev "${devname}"
673         done
674 }
675
676 # Setup local SIDs for an SRv6 router
677 setup_rt_local_sids()
678 {
679         local rt="$1"
680         local rt_neighs="$2"
681         local net_prefix
682         local devname
683         local nsname
684         local neigh
685         local lcnode_func_prefix
686         local lcblock_prefix
687
688         nsname="$(get_rtname "${rt}")"
689
690         set_underlay_sids_reachability "${rt}" "${rt_neighs}"
691
692         # all SIDs for VPNs start with a common locator. Routes and SRv6
693         # Endpoint behavior instaces are grouped together in the 'localsid'
694         # table.
695         ip -netns "${nsname}" -6 rule \
696                 add to "${VPN_LOCATOR_SERVICE}::/16" \
697                 lookup "${LOCALSID_TABLE_ID}" prio 999
698
699         # common locator block for NEXT-C-SIDS compression mechanism.
700         lcblock_prefix="$(build_ipv6_addr "${LCBLOCK_ADDR}")"
701         ip -netns "${nsname}" -6 rule \
702                 add to "${lcblock_prefix}/${LCBLOCK_BLEN}" \
703                 lookup "${LOCALSID_TABLE_ID}" prio 999
704 }
705
706 # build and install the SRv6 policy into the ingress SRv6 router as well as the
707 # decap SID in the egress one.
708 # args:
709 #  $1 - src host (evaluate automatically the ingress router)
710 #  $2 - dst host (evaluate automatically the egress router)
711 #  $3 - SRv6 routers configured for steering traffic (End.X behaviors)
712 #  $4 - single SID or double SID
713 #  $5 - traffic type (IPv6 or IPv4)
714 __setup_l3vpn()
715 {
716         local src="$1"
717         local dst="$2"
718         local end_rts="$3"
719         local mode="$4"
720         local traffic="$5"
721         local nsname
722         local policy
723         local container
724         local decapsid
725         local lcnfunc
726         local dt
727         local n
728         local rtsrc_nsname
729         local rtdst_nsname
730
731         rtsrc_nsname="$(get_rtname "${src}")"
732         rtdst_nsname="$(get_rtname "${dst}")"
733
734         container="${LCBLOCK_ADDR}"
735
736         # build first SID (C-SID container)
737         for n in ${end_rts}; do
738                 lcnfunc="$(build_csid "${n}")"
739
740                 container="${container}${lcnfunc}"
741         done
742
743         if [ "${mode}" -eq 1 ]; then
744                 # single SID policy
745                 dt="$(build_csid "${dst}")${DT46_FUNC}"
746                 container="${container}${dt}"
747                 # build the full ipv6 address for the container
748                 policy="$(build_ipv6_addr "${container}")"
749
750                 # build the decap SID used in the decap node
751                 container="${LCBLOCK_ADDR}${dt}"
752                 decapsid="$(build_ipv6_addr "${container}")"
753         else
754                 # double SID policy
755                 decapsid="${VPN_LOCATOR_SERVICE}:${dst}::${DT46_FUNC}"
756
757                 policy="$(build_ipv6_addr "${container}"),${decapsid}"
758         fi
759
760         # apply encap policy
761         if [ "${traffic}" -eq 6 ]; then
762                 ip -netns "${rtsrc_nsname}" -6 route \
763                         add "${IPv6_HS_NETWORK}::${dst}" vrf "${VRF_DEVNAME}" \
764                         encap seg6 mode "${HEADEND_ENCAP}" segs "${policy}" \
765                         dev "${VRF_DEVNAME}"
766
767                 ip -netns "${rtsrc_nsname}" -6 neigh \
768                         add proxy "${IPv6_HS_NETWORK}::${dst}" \
769                         dev "${RT2HS_DEVNAME}"
770         else
771                 # "dev" must be different from the one where the packet is
772                 # received, otherwise the proxy arp does not work.
773                 ip -netns "${rtsrc_nsname}" -4 route \
774                         add "${IPv4_HS_NETWORK}.${dst}" vrf "${VRF_DEVNAME}" \
775                         encap seg6 mode "${HEADEND_ENCAP}" segs "${policy}" \
776                         dev "${VRF_DEVNAME}"
777         fi
778
779         # apply decap
780         # Local End.DT46 behavior (decap)
781         ip -netns "${rtdst_nsname}" -6 route \
782                 add "${decapsid}" \
783                 table "${LOCALSID_TABLE_ID}" \
784                 encap seg6local action End.DT46 vrftable "${VRF_TID}" \
785                 dev "${VRF_DEVNAME}"
786 }
787
788 # see __setup_l3vpn()
789 setup_ipv4_vpn_2sids()
790 {
791         __setup_l3vpn "$1" "$2" "$3" 2 4
792 }
793
794 # see __setup_l3vpn()
795 setup_ipv6_vpn_1sid()
796 {
797         __setup_l3vpn "$1" "$2" "$3" 1 6
798 }
799
800 setup_hs()
801 {
802         local hs="$1"
803         local rt="$2"
804         local hsname
805         local rtname
806
807         hsname="$(get_hsname "${hs}")"
808         rtname="$(get_rtname "${rt}")"
809
810         ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
811         ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
812
813         ip -netns "${hsname}" link add veth0 type veth \
814                 peer name "${RT2HS_DEVNAME}" netns "${rtname}"
815
816         ip -netns "${hsname}" addr \
817                 add "${IPv6_HS_NETWORK}::${hs}/64" dev veth0 nodad
818         ip -netns "${hsname}" addr add "${IPv4_HS_NETWORK}.${hs}/24" dev veth0
819
820         ip -netns "${hsname}" link set veth0 up
821         ip -netns "${hsname}" link set lo up
822
823         # configure the VRF on the router which is directly connected to the
824         # source host.
825         ip -netns "${rtname}" link \
826                 add "${VRF_DEVNAME}" type vrf table "${VRF_TID}"
827         ip -netns "${rtname}" link set "${VRF_DEVNAME}" up
828
829         # enslave the veth interface connecting the router with the host to the
830         # VRF in the access router
831         ip -netns "${rtname}" link \
832                 set "${RT2HS_DEVNAME}" master "${VRF_DEVNAME}"
833
834         # set default routes to unreachable for both ipv6 and ipv4
835         ip -netns "${rtname}" -6 route \
836                 add unreachable default metric 4278198272 \
837                 vrf "${VRF_DEVNAME}"
838         ip -netns "${rtname}" -4 route \
839                 add unreachable default metric 4278198272 \
840                 vrf "${VRF_DEVNAME}"
841
842         ip -netns "${rtname}" addr \
843                 add "${IPv6_HS_NETWORK}::254/64" dev "${RT2HS_DEVNAME}" nodad
844         ip -netns "${rtname}" addr \
845                 add "${IPv4_HS_NETWORK}.254/24" dev "${RT2HS_DEVNAME}"
846
847         ip -netns "${rtname}" link set "${RT2HS_DEVNAME}" up
848
849         ip netns exec "${rtname}" \
850                 sysctl -wq net.ipv6.conf."${RT2HS_DEVNAME}".proxy_ndp=1
851         ip netns exec "${rtname}" \
852                 sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".proxy_arp=1
853
854         # disable the rp_filter otherwise the kernel gets confused about how
855         # to route decap ipv4 packets.
856         ip netns exec "${rtname}" \
857                 sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".rp_filter=0
858
859         ip netns exec "${rtname}" sh -c "echo 1 > /proc/sys/net/vrf/strict_mode"
860 }
861
862 setup()
863 {
864         local i
865
866         # create routers
867         ROUTERS="1 2 3 4"; readonly ROUTERS
868         for i in ${ROUTERS}; do
869                 create_router "${i}"
870         done
871
872         # create hosts
873         HOSTS="1 2"; readonly HOSTS
874         for i in ${HOSTS}; do
875                 create_host "${i}"
876         done
877
878         # set up the links for connecting routers
879         add_link_rt_pairs 1 "2 3 4"
880         add_link_rt_pairs 2 "3 4"
881         add_link_rt_pairs 3 "4"
882
883         # set up the basic connectivity of routers and routes required for
884         # reachability of SIDs.
885         setup_rt_networking 1 "2 3 4"
886         setup_rt_networking 2 "1 3 4"
887         setup_rt_networking 3 "1 2 4"
888         setup_rt_networking 4 "1 2 3"
889
890         # set up the hosts connected to routers
891         setup_hs 1 1
892         setup_hs 2 2
893
894         # set up default SRv6 Endpoints (i.e. SRv6 End and SRv6 End.DT46)
895         setup_rt_local_sids 1 "2 3 4"
896         setup_rt_local_sids 2 "1 3 4"
897         setup_rt_local_sids 3 "1 2 4"
898         setup_rt_local_sids 4 "1 2 3"
899
900         # set up SRv6 Policies
901
902         # create an IPv6 VPN between hosts hs-1 and hs-2.
903         #
904         # Direction hs-1 -> hs-2
905         # - rt-1 encap (H.Encaps.Red)
906         # - rt-3 SRv6 End.X behavior adj rt-4 (NEXT-C-SID flavor)
907         # - rt-4 Plain IPv6 Forwarding to rt-2
908         # - rt-2 SRv6 End.DT46 behavior
909         setup_ipv6_vpn_1sid 1 2 "3"
910
911         # Direction hs2 -> hs-1
912         # - rt-2 encap (H.Encaps.Red)
913         # - rt-4 SRv6 End.X behavior adj rt-1 (NEXT-C-SID flavor)
914         # - rt-1 SRv6 End.DT46 behavior
915         setup_ipv6_vpn_1sid 2 1 "4"
916
917         # create an IPv4 VPN between hosts hs-1 and hs-2
918         #
919         # Direction hs-1 -> hs-2
920         # - rt-1 encap (H.Encaps.Red)
921         # - rt-3 SRv6 End.X behavior adj rt-4 (NEXT-C-SID flavor)
922         # - rt-4 Plain IPv6 Forwarding to rt-2
923         # - rt-2 SRv6 End.DT46 behavior
924         setup_ipv4_vpn_2sids 1 2 "3"
925
926         # Direction hs-2 -> hs-1
927         # - rt-2 encap (H.Encaps.Red)
928         # - rt-3 SRv6 End.X behavior adj rt-4 (NEXT-C-SID flavor)
929         # - rt-4 Plain IPv6 Forwarding to rt-1
930         # - rt-1 SRv6 End.DT46 behavior
931         setup_ipv4_vpn_2sids 2 1 "3"
932
933         # Setup the adjacencies in the SRv6 aware routers
934         # - rt-3 SRv6 End.X adjacency with rt-4
935         # - rt-4 SRv6 End.X adjacency with rt-1
936         set_end_x_nextcsid 3 4
937         set_end_x_nextcsid 4 1
938
939         # testing environment was set up successfully
940         SETUP_ERR=0
941 }
942
943 check_rt_connectivity()
944 {
945         local rtsrc="$1"
946         local rtdst="$2"
947         local prefix
948         local rtsrc_nsname
949
950         rtsrc_nsname="$(get_rtname "${rtsrc}")"
951
952         prefix="$(get_network_prefix "${rtsrc}" "${rtdst}")"
953
954         ip netns exec "${rtsrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
955                 "${prefix}::${rtdst}" >/dev/null 2>&1
956 }
957
958 check_and_log_rt_connectivity()
959 {
960         local rtsrc="$1"
961         local rtdst="$2"
962
963         check_rt_connectivity "${rtsrc}" "${rtdst}"
964         log_test $? 0 "Routers connectivity: rt-${rtsrc} -> rt-${rtdst}"
965 }
966
967 check_hs_ipv6_connectivity()
968 {
969         local hssrc="$1"
970         local hsdst="$2"
971         local hssrc_nsname
972
973         hssrc_nsname="$(get_hsname "${hssrc}")"
974
975         ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
976                 "${IPv6_HS_NETWORK}::${hsdst}" >/dev/null 2>&1
977 }
978
979 check_hs_ipv4_connectivity()
980 {
981         local hssrc="$1"
982         local hsdst="$2"
983         local hssrc_nsname
984
985         hssrc_nsname="$(get_hsname "${hssrc}")"
986
987         ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
988                 "${IPv4_HS_NETWORK}.${hsdst}" >/dev/null 2>&1
989 }
990
991 check_and_log_hs2gw_connectivity()
992 {
993         local hssrc="$1"
994
995         check_hs_ipv6_connectivity "${hssrc}" 254
996         log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> gw"
997
998         check_hs_ipv4_connectivity "${hssrc}" 254
999         log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> gw"
1000 }
1001
1002 check_and_log_hs_ipv6_connectivity()
1003 {
1004         local hssrc="$1"
1005         local hsdst="$2"
1006
1007         check_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
1008         log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"
1009 }
1010
1011 check_and_log_hs_ipv4_connectivity()
1012 {
1013         local hssrc="$1"
1014         local hsdst="$2"
1015
1016         check_hs_ipv4_connectivity "${hssrc}" "${hsdst}"
1017         log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"
1018 }
1019
1020 router_tests()
1021 {
1022         local i
1023         local j
1024
1025         log_section "IPv6 routers connectivity test"
1026
1027         for i in ${ROUTERS}; do
1028                 for j in ${ROUTERS}; do
1029                         if [ "${i}" -eq "${j}" ]; then
1030                                 continue
1031                         fi
1032
1033                         check_and_log_rt_connectivity "${i}" "${j}"
1034                 done
1035         done
1036 }
1037
1038 host2gateway_tests()
1039 {
1040         local hs
1041
1042         log_section "IPv4/IPv6 connectivity test among hosts and gateways"
1043
1044         for hs in ${HOSTS}; do
1045                 check_and_log_hs2gw_connectivity "${hs}"
1046         done
1047 }
1048
1049 host_vpn_tests()
1050 {
1051         log_section "SRv6 VPN connectivity test hosts (h1 <-> h2, IPv6)"
1052
1053         check_and_log_hs_ipv6_connectivity 1 2
1054         check_and_log_hs_ipv6_connectivity 2 1
1055
1056         log_section "SRv6 VPN connectivity test hosts (h1 <-> h2, IPv4)"
1057
1058         check_and_log_hs_ipv4_connectivity 1 2
1059         check_and_log_hs_ipv4_connectivity 2 1
1060 }
1061
1062 __nextcsid_end_x_behavior_test()
1063 {
1064         local nsname="$1"
1065         local cmd="$2"
1066         local blen="$3"
1067         local flen="$4"
1068         local layout=""
1069
1070         if [ "${blen}" != "d" ]; then
1071                 layout="${layout} lblen ${blen}"
1072         fi
1073
1074         if [ "${flen}" != "d" ]; then
1075                 layout="${layout} nflen ${flen}"
1076         fi
1077
1078         ip -netns "${nsname}" -6 route \
1079                 "${cmd}" "${CSID_CNTR_PREFIX}" \
1080                 table "${CSID_CNTR_RT_TABLE}" \
1081                 encap seg6local action End.X nh6 :: \
1082                 flavors next-csid ${layout} \
1083                 dev "${DUMMY_DEVNAME}" &>/dev/null
1084
1085         return "$?"
1086 }
1087
1088 rt_x_nextcsid_end_x_behavior_test()
1089 {
1090         local rt="$1"
1091         local blen="$2"
1092         local flen="$3"
1093         local nsname
1094         local ret
1095
1096         nsname="$(get_rtname "${rt}")"
1097
1098         __nextcsid_end_x_behavior_test "${nsname}" "add" "${blen}" "${flen}"
1099         ret="$?"
1100         __nextcsid_end_x_behavior_test "${nsname}" "del" "${blen}" "${flen}"
1101
1102         return "${ret}"
1103 }
1104
1105 __parse_csid_container_cfg()
1106 {
1107         local cfg="$1"
1108         local index="$2"
1109         local out
1110
1111         echo "${cfg}" | cut -d',' -f"${index}"
1112 }
1113
1114 csid_container_cfg_tests()
1115 {
1116         local valid
1117         local blen
1118         local flen
1119         local cfg
1120         local ret
1121
1122         log_section "C-SID Container config tests (legend: d='kernel default')"
1123
1124         for cfg in "${CSID_CONTAINER_CFGS[@]}"; do
1125                 blen="$(__parse_csid_container_cfg "${cfg}" 1)"
1126                 flen="$(__parse_csid_container_cfg "${cfg}" 2)"
1127                 valid="$(__parse_csid_container_cfg "${cfg}" 3)"
1128
1129                 rt_x_nextcsid_end_x_behavior_test \
1130                         "${CSID_CNTR_RT_ID_TEST}" \
1131                         "${blen}" \
1132                         "${flen}"
1133                 ret="$?"
1134
1135                 if [ "${valid}" == "y" ]; then
1136                         log_test "${ret}" 0 \
1137                                 "Accept valid C-SID container cfg (lblen=${blen}, nflen=${flen})"
1138                 else
1139                         log_test "${ret}" 2 \
1140                                 "Reject invalid C-SID container cfg (lblen=${blen}, nflen=${flen})"
1141                 fi
1142         done
1143 }
1144
1145 test_iproute2_supp_or_ksft_skip()
1146 {
1147         if ! ip route help 2>&1 | grep -qo "next-csid"; then
1148                 echo "SKIP: Missing SRv6 NEXT-C-SID flavor support in iproute2"
1149                 exit "${ksft_skip}"
1150         fi
1151 }
1152
1153 test_dummy_dev_or_ksft_skip()
1154 {
1155         local test_netns
1156
1157         test_netns="dummy-$(mktemp -u XXXXXXXX)"
1158
1159         if ! ip netns add "${test_netns}"; then
1160                 echo "SKIP: Cannot set up netns for testing dummy dev support"
1161                 exit "${ksft_skip}"
1162         fi
1163
1164         modprobe dummy &>/dev/null || true
1165         if ! ip -netns "${test_netns}" link \
1166                 add "${DUMMY_DEVNAME}" type dummy; then
1167                 echo "SKIP: dummy dev not supported"
1168
1169                 ip netns del "${test_netns}"
1170                 exit "${ksft_skip}"
1171         fi
1172
1173         ip netns del "${test_netns}"
1174 }
1175
1176 test_vrf_or_ksft_skip()
1177 {
1178         modprobe vrf &>/dev/null || true
1179         if [ ! -e /proc/sys/net/vrf/strict_mode ]; then
1180                 echo "SKIP: vrf sysctl does not exist"
1181                 exit "${ksft_skip}"
1182         fi
1183 }
1184
1185 if [ "$(id -u)" -ne 0 ]; then
1186         echo "SKIP: Need root privileges"
1187         exit "${ksft_skip}"
1188 fi
1189
1190 # required programs to carry out this selftest
1191 test_command_or_ksft_skip ip
1192 test_command_or_ksft_skip ping
1193 test_command_or_ksft_skip sysctl
1194 test_command_or_ksft_skip grep
1195 test_command_or_ksft_skip cut
1196
1197 test_iproute2_supp_or_ksft_skip
1198 test_dummy_dev_or_ksft_skip
1199 test_vrf_or_ksft_skip
1200
1201 set -e
1202 trap cleanup EXIT
1203
1204 setup
1205 set +e
1206
1207 csid_container_cfg_tests
1208
1209 router_tests
1210 host2gateway_tests
1211 host_vpn_tests
1212
1213 print_log_test_results
This page took 0.104815 seconds and 4 git commands to generate.