Back to home page

OSCL-LXR

 
 

    


0001 #!/bin/bash
0002 # SPDX-License-Identifier: GPL-2.0
0003 #
0004 # author: Andrea Mayer <andrea.mayer@uniroma2.it>
0005 #
0006 # This script is designed for testing the SRv6 H.Encaps.Red behavior.
0007 #
0008 # Below is depicted the IPv6 network of an operator which offers advanced
0009 # IPv4/IPv6 VPN services to hosts, enabling them to communicate with each
0010 # other.
0011 # In this example, hosts hs-1 and hs-2 are connected through an IPv4/IPv6 VPN
0012 # service, while hs-3 and hs-4 are connected using an IPv6 only VPN.
0013 #
0014 # Routers rt-1,rt-2,rt-3 and rt-4 implement IPv4/IPv6 L3 VPN services
0015 # leveraging the SRv6 architecture. The key components for such VPNs are:
0016 #
0017 #   i) The SRv6 H.Encaps.Red behavior applies SRv6 Policies on traffic received
0018 #      by connected hosts, initiating the VPN tunnel. Such a behavior is an
0019 #      optimization of the SRv6 H.Encap aiming to reduce the length of the SID
0020 #      List carried in the pushed SRH. Specifically, the H.Encaps.Red removes
0021 #      the first SID contained in the SID List (i.e. SRv6 Policy) by storing it
0022 #      into the IPv6 Destination Address. When a SRv6 Policy is made of only one
0023 #      SID, the SRv6 H.Encaps.Red behavior omits the SRH at all and pushes that
0024 #      SID directly into the IPv6 DA;
0025 #
0026 #  ii) The SRv6 End behavior advances the active SID in the SID List carried by
0027 #      the SRH;
0028 #
0029 # iii) The SRv6 End.DT46 behavior is used for removing the SRv6 Policy and,
0030 #      thus, it terminates the VPN tunnel. Such a behavior is capable of
0031 #      handling, at the same time, both tunneled IPv4 and IPv6 traffic.
0032 #
0033 #
0034 #               cafe::1                      cafe::2
0035 #              10.0.0.1                     10.0.0.2
0036 #             +--------+                   +--------+
0037 #             |        |                   |        |
0038 #             |  hs-1  |                   |  hs-2  |
0039 #             |        |                   |        |
0040 #             +---+----+                   +--- +---+
0041 #    cafe::/64    |                             |      cafe::/64
0042 #  10.0.0.0/24    |                             |    10.0.0.0/24
0043 #             +---+----+                   +----+---+
0044 #             |        |  fcf0:0:1:2::/64  |        |
0045 #             |  rt-1  +-------------------+  rt-2  |
0046 #             |        |                   |        |
0047 #             +---+----+                   +----+---+
0048 #                 |      .               .      |
0049 #                 |  fcf0:0:1:3::/64   .        |
0050 #                 |          .       .          |
0051 #                 |            .   .            |
0052 # fcf0:0:1:4::/64 |              .              | fcf0:0:2:3::/64
0053 #                 |            .   .            |
0054 #                 |          .       .          |
0055 #                 |  fcf0:0:2:4::/64   .        |
0056 #                 |      .               .      |
0057 #             +---+----+                   +----+---+
0058 #             |        |                   |        |
0059 #             |  rt-4  +-------------------+  rt-3  |
0060 #             |        |  fcf0:0:3:4::/64  |        |
0061 #             +---+----+                   +----+---+
0062 #    cafe::/64    |                             |      cafe::/64
0063 #  10.0.0.0/24    |                             |    10.0.0.0/24
0064 #             +---+----+                   +--- +---+
0065 #             |        |                   |        |
0066 #             |  hs-4  |                   |  hs-3  |
0067 #             |        |                   |        |
0068 #             +--------+                   +--------+
0069 #               cafe::4                      cafe::3
0070 #              10.0.0.4                     10.0.0.3
0071 #
0072 #
0073 # Every fcf0:0:x:y::/64 network interconnects the SRv6 routers rt-x with rt-y
0074 # in the IPv6 operator network.
0075 #
0076 # Local SID table
0077 # ===============
0078 #
0079 # Each SRv6 router is configured with a Local SID table in which SIDs are
0080 # stored. Considering the given SRv6 router rt-x, at least two SIDs are
0081 # configured in the Local SID table:
0082 #
0083 #   Local SID table for SRv6 router rt-x
0084 #   +----------------------------------------------------------+
0085 #   |fcff:x::e is associated with the SRv6 End behavior        |
0086 #   |fcff:x::d46 is associated with the SRv6 End.DT46 behavior |
0087 #   +----------------------------------------------------------+
0088 #
0089 # The fcff::/16 prefix is reserved by the operator for implementing SRv6 VPN
0090 # services. Reachability of SIDs is ensured by proper configuration of the IPv6
0091 # operator's network and SRv6 routers.
0092 #
0093 # # SRv6 Policies
0094 # ===============
0095 #
0096 # An SRv6 ingress router applies SRv6 policies to the traffic received from a
0097 # connected host. SRv6 policy enforcement consists of encapsulating the
0098 # received traffic into a new IPv6 packet with a given SID List contained in
0099 # the SRH.
0100 #
0101 # IPv4/IPv6 VPN between hs-1 and hs-2
0102 # -----------------------------------
0103 #
0104 # Hosts hs-1 and hs-2 are connected using dedicated IPv4/IPv6 VPNs.
0105 # Specifically, packets generated from hs-1 and directed towards hs-2 are
0106 # handled by rt-1 which applies the following SRv6 Policies:
0107 #
0108 #   i.a) IPv6 traffic, SID List=fcff:3::e,fcff:4::e,fcff:2::d46
0109 #  ii.a) IPv4 traffic, SID List=fcff:2::d46
0110 #
0111 # Policy (i.a) steers tunneled IPv6 traffic through SRv6 routers
0112 # rt-3,rt-4,rt-2. Instead, Policy (ii.a) steers tunneled IPv4 traffic through
0113 # rt-2.
0114 # The H.Encaps.Red reduces the SID List (i.a) carried in SRH by removing the
0115 # first SID (fcff:3::e) and pushing it into the IPv6 DA. In case of IPv4
0116 # traffic, the H.Encaps.Red omits the presence of SRH at all, since the SID
0117 # List (ii.a) consists of only one SID that can be stored directly in the IPv6
0118 # DA.
0119 #
0120 # On the reverse path (i.e. from hs-2 to hs-1), rt-2 applies the following
0121 # policies:
0122 #
0123 #   i.b) IPv6 traffic, SID List=fcff:1::d46
0124 #  ii.b) IPv4 traffic, SID List=fcff:4::e,fcff:3::e,fcff:1::d46
0125 #
0126 # Policy (i.b) steers tunneled IPv6 traffic through the SRv6 router rt-1.
0127 # Conversely, Policy (ii.b) steers tunneled IPv4 traffic through SRv6 routers
0128 # rt-4,rt-3,rt-1.
0129 # The H.Encaps.Red omits the SRH at all in case of (i.b) by pushing the single
0130 # SID (fcff::1::d46) inside the IPv6 DA.
0131 # The H.Encaps.Red reduces the SID List (ii.b) in the SRH by removing the first
0132 # SID (fcff:4::e) and pushing it into the IPv6 DA.
0133 #
0134 # In summary:
0135 #  hs-1->hs-2 |IPv6 DA=fcff:3::e|SRH SIDs=fcff:4::e,fcff:2::d46|IPv6|...| (i.a)
0136 #  hs-1->hs-2 |IPv6 DA=fcff:2::d46|IPv4|...|                              (ii.a)
0137 #
0138 #  hs-2->hs-1 |IPv6 DA=fcff:1::d46|IPv6|...|                              (i.b)
0139 #  hs-2->hs-1 |IPv6 DA=fcff:4::e|SRH SIDs=fcff:3::e,fcff:1::d46|IPv4|...| (ii.b)
0140 #
0141 #
0142 # IPv6 VPN between hs-3 and hs-4
0143 # ------------------------------
0144 #
0145 # Hosts hs-3 and hs-4 are connected using a dedicated IPv6 only VPN.
0146 # Specifically, packets generated from hs-3 and directed towards hs-4 are
0147 # handled by rt-3 which applies the following SRv6 Policy:
0148 #
0149 #  i.c) IPv6 traffic, SID List=fcff:2::e,fcff:4::d46
0150 #
0151 # Policy (i.c) steers tunneled IPv6 traffic through SRv6 routers rt-2,rt-4.
0152 # The H.Encaps.Red reduces the SID List (i.c) carried in SRH by pushing the
0153 # first SID (fcff:2::e) in the IPv6 DA.
0154 #
0155 # On the reverse path (i.e. from hs-4 to hs-3) the router rt-4 applies the
0156 # following SRv6 Policy:
0157 #
0158 #  i.d) IPv6 traffic, SID List=fcff:1::e,fcff:3::d46.
0159 #
0160 # Policy (i.d) steers tunneled IPv6 traffic through SRv6 routers rt-1,rt-3.
0161 # The H.Encaps.Red reduces the SID List (i.d) carried in SRH by pushing the
0162 # first SID (fcff:1::e) in the IPv6 DA.
0163 #
0164 # In summary:
0165 #  hs-3->hs-4 |IPv6 DA=fcff:2::e|SRH SIDs=fcff:4::d46|IPv6|...| (i.c)
0166 #  hs-4->hs-3 |IPv6 DA=fcff:1::e|SRH SIDs=fcff:3::d46|IPv6|...| (i.d)
0167 #
0168 
0169 # Kselftest framework requirement - SKIP code is 4.
0170 readonly ksft_skip=4
0171 
0172 readonly RDMSUFF="$(mktemp -u XXXXXXXX)"
0173 readonly VRF_TID=100
0174 readonly VRF_DEVNAME="vrf-${VRF_TID}"
0175 readonly RT2HS_DEVNAME="veth-t${VRF_TID}"
0176 readonly LOCALSID_TABLE_ID=90
0177 readonly IPv6_RT_NETWORK=fcf0:0
0178 readonly IPv6_HS_NETWORK=cafe
0179 readonly IPv4_HS_NETWORK=10.0.0
0180 readonly VPN_LOCATOR_SERVICE=fcff
0181 readonly END_FUNC=000e
0182 readonly DT46_FUNC=0d46
0183 
0184 PING_TIMEOUT_SEC=4
0185 PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
0186 
0187 # IDs of routers and hosts are initialized during the setup of the testing
0188 # network
0189 ROUTERS=''
0190 HOSTS=''
0191 
0192 SETUP_ERR=1
0193 
0194 ret=${ksft_skip}
0195 nsuccess=0
0196 nfail=0
0197 
0198 log_test()
0199 {
0200         local rc="$1"
0201         local expected="$2"
0202         local msg="$3"
0203 
0204         if [ "${rc}" -eq "${expected}" ]; then
0205                 nsuccess=$((nsuccess+1))
0206                 printf "\n    TEST: %-60s  [ OK ]\n" "${msg}"
0207         else
0208                 ret=1
0209                 nfail=$((nfail+1))
0210                 printf "\n    TEST: %-60s  [FAIL]\n" "${msg}"
0211                 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
0212                         echo
0213                         echo "hit enter to continue, 'q' to quit"
0214                         read a
0215                         [ "$a" = "q" ] && exit 1
0216                 fi
0217         fi
0218 }
0219 
0220 print_log_test_results()
0221 {
0222         printf "\nTests passed: %3d\n" "${nsuccess}"
0223         printf "Tests failed: %3d\n"   "${nfail}"
0224 
0225         # when a test fails, the value of 'ret' is set to 1 (error code).
0226         # Conversely, when all tests are passed successfully, the 'ret' value
0227         # is set to 0 (success code).
0228         if [ "${ret}" -ne 1 ]; then
0229                 ret=0
0230         fi
0231 }
0232 
0233 log_section()
0234 {
0235         echo
0236         echo "################################################################################"
0237         echo "TEST SECTION: $*"
0238         echo "################################################################################"
0239 }
0240 
0241 test_command_or_ksft_skip()
0242 {
0243         local cmd="$1"
0244 
0245         if [ ! -x "$(command -v "${cmd}")" ]; then
0246                 echo "SKIP: Could not run test without \"${cmd}\" tool";
0247                 exit "${ksft_skip}"
0248         fi
0249 }
0250 
0251 get_nodename()
0252 {
0253         local name="$1"
0254 
0255         echo "${name}-${RDMSUFF}"
0256 }
0257 
0258 get_rtname()
0259 {
0260         local rtid="$1"
0261 
0262         get_nodename "rt-${rtid}"
0263 }
0264 
0265 get_hsname()
0266 {
0267         local hsid="$1"
0268 
0269         get_nodename "hs-${hsid}"
0270 }
0271 
0272 __create_namespace()
0273 {
0274         local name="$1"
0275 
0276         ip netns add "${name}"
0277 }
0278 
0279 create_router()
0280 {
0281         local rtid="$1"
0282         local nsname
0283 
0284         nsname="$(get_rtname "${rtid}")"
0285 
0286         __create_namespace "${nsname}"
0287 }
0288 
0289 create_host()
0290 {
0291         local hsid="$1"
0292         local nsname
0293 
0294         nsname="$(get_hsname "${hsid}")"
0295 
0296         __create_namespace "${nsname}"
0297 }
0298 
0299 cleanup()
0300 {
0301         local nsname
0302         local i
0303 
0304         # destroy routers
0305         for i in ${ROUTERS}; do
0306                 nsname="$(get_rtname "${i}")"
0307 
0308                 ip netns del "${nsname}" &>/dev/null || true
0309         done
0310 
0311         # destroy hosts
0312         for i in ${HOSTS}; do
0313                 nsname="$(get_hsname "${i}")"
0314 
0315                 ip netns del "${nsname}" &>/dev/null || true
0316         done
0317 
0318         # check whether the setup phase was completed successfully or not. In
0319         # case of an error during the setup phase of the testing environment,
0320         # the selftest is considered as "skipped".
0321         if [ "${SETUP_ERR}" -ne 0 ]; then
0322                 echo "SKIP: Setting up the testing environment failed"
0323                 exit "${ksft_skip}"
0324         fi
0325 
0326         exit "${ret}"
0327 }
0328 
0329 add_link_rt_pairs()
0330 {
0331         local rt="$1"
0332         local rt_neighs="$2"
0333         local neigh
0334         local nsname
0335         local neigh_nsname
0336 
0337         nsname="$(get_rtname "${rt}")"
0338 
0339         for neigh in ${rt_neighs}; do
0340                 neigh_nsname="$(get_rtname "${neigh}")"
0341 
0342                 ip link add "veth-rt-${rt}-${neigh}" netns "${nsname}" \
0343                         type veth peer name "veth-rt-${neigh}-${rt}" \
0344                         netns "${neigh_nsname}"
0345         done
0346 }
0347 
0348 get_network_prefix()
0349 {
0350         local rt="$1"
0351         local neigh="$2"
0352         local p="${rt}"
0353         local q="${neigh}"
0354 
0355         if [ "${p}" -gt "${q}" ]; then
0356                 p="${q}"; q="${rt}"
0357         fi
0358 
0359         echo "${IPv6_RT_NETWORK}:${p}:${q}"
0360 }
0361 
0362 # Setup the basic networking for the routers
0363 setup_rt_networking()
0364 {
0365         local rt="$1"
0366         local rt_neighs="$2"
0367         local nsname
0368         local net_prefix
0369         local devname
0370         local neigh
0371 
0372         nsname="$(get_rtname "${rt}")"
0373 
0374         for neigh in ${rt_neighs}; do
0375                 devname="veth-rt-${rt}-${neigh}"
0376 
0377                 net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
0378 
0379                 ip -netns "${nsname}" addr \
0380                         add "${net_prefix}::${rt}/64" dev "${devname}" nodad
0381 
0382                 ip -netns "${nsname}" link set "${devname}" up
0383         done
0384 
0385         ip -netns "${nsname}" link set lo up
0386 
0387         ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
0388         ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
0389         ip netns exec "${nsname}" sysctl -wq net.ipv6.conf.all.forwarding=1
0390 
0391         ip netns exec "${nsname}" sysctl -wq net.ipv4.conf.all.rp_filter=0
0392         ip netns exec "${nsname}" sysctl -wq net.ipv4.conf.default.rp_filter=0
0393         ip netns exec "${nsname}" sysctl -wq net.ipv4.ip_forward=1
0394 }
0395 
0396 # Setup local SIDs for an SRv6 router
0397 setup_rt_local_sids()
0398 {
0399         local rt="$1"
0400         local rt_neighs="$2"
0401         local net_prefix
0402         local devname
0403         local nsname
0404         local neigh
0405 
0406         nsname="$(get_rtname "${rt}")"
0407 
0408         for neigh in ${rt_neighs}; do
0409                 devname="veth-rt-${rt}-${neigh}"
0410 
0411                 net_prefix="$(get_network_prefix "${rt}" "${neigh}")"
0412 
0413                 # set underlay network routes for SIDs reachability
0414                 ip -netns "${nsname}" -6 route \
0415                         add "${VPN_LOCATOR_SERVICE}:${neigh}::/32" \
0416                         table "${LOCALSID_TABLE_ID}" \
0417                         via "${net_prefix}::${neigh}" dev "${devname}"
0418         done
0419 
0420         # Local End behavior (note that "dev" is dummy and the VRF is chosen
0421         # for the sake of simplicity).
0422         ip -netns "${nsname}" -6 route \
0423                 add "${VPN_LOCATOR_SERVICE}:${rt}::${END_FUNC}" \
0424                 table "${LOCALSID_TABLE_ID}" \
0425                 encap seg6local action End dev "${VRF_DEVNAME}"
0426 
0427         # Local End.DT46 behavior
0428         ip -netns "${nsname}" -6 route \
0429                 add "${VPN_LOCATOR_SERVICE}:${rt}::${DT46_FUNC}" \
0430                 table "${LOCALSID_TABLE_ID}" \
0431                 encap seg6local action End.DT46 vrftable "${VRF_TID}" \
0432                 dev "${VRF_DEVNAME}"
0433 
0434         # all SIDs for VPNs start with a common locator. Routes and SRv6
0435         # Endpoint behavior instaces are grouped together in the 'localsid'
0436         # table.
0437         ip -netns "${nsname}" -6 rule \
0438                 add to "${VPN_LOCATOR_SERVICE}::/16" \
0439                 lookup "${LOCALSID_TABLE_ID}" prio 999
0440 
0441         # set default routes to unreachable for both ipv4 and ipv6
0442         ip -netns "${nsname}" -6 route \
0443                 add unreachable default metric 4278198272 \
0444                 vrf "${VRF_DEVNAME}"
0445 
0446         ip -netns "${nsname}" -4 route \
0447                 add unreachable default metric 4278198272 \
0448                 vrf "${VRF_DEVNAME}"
0449 }
0450 
0451 # build and install the SRv6 policy into the ingress SRv6 router.
0452 # args:
0453 #  $1 - destination host (i.e. cafe::x host)
0454 #  $2 - SRv6 router configured for enforcing the SRv6 Policy
0455 #  $3 - SRv6 routers configured for steering traffic (End behaviors)
0456 #  $4 - SRv6 router configured for removing the SRv6 Policy (router connected
0457 #       to the destination host)
0458 #  $5 - encap mode (full or red)
0459 #  $6 - traffic type (IPv6 or IPv4)
0460 __setup_rt_policy()
0461 {
0462         local dst="$1"
0463         local encap_rt="$2"
0464         local end_rts="$3"
0465         local dec_rt="$4"
0466         local mode="$5"
0467         local traffic="$6"
0468         local nsname
0469         local policy=''
0470         local n
0471 
0472         nsname="$(get_rtname "${encap_rt}")"
0473 
0474         for n in ${end_rts}; do
0475                 policy="${policy}${VPN_LOCATOR_SERVICE}:${n}::${END_FUNC},"
0476         done
0477 
0478         policy="${policy}${VPN_LOCATOR_SERVICE}:${dec_rt}::${DT46_FUNC}"
0479 
0480         # add SRv6 policy to incoming traffic sent by connected hosts
0481         if [ "${traffic}" -eq 6 ]; then
0482                 ip -netns "${nsname}" -6 route \
0483                         add "${IPv6_HS_NETWORK}::${dst}" vrf "${VRF_DEVNAME}" \
0484                         encap seg6 mode "${mode}" segs "${policy}" \
0485                         dev "${VRF_DEVNAME}"
0486 
0487                 ip -netns "${nsname}" -6 neigh \
0488                         add proxy "${IPv6_HS_NETWORK}::${dst}" \
0489                         dev "${RT2HS_DEVNAME}"
0490         else
0491                 # "dev" must be different from the one where the packet is
0492                 # received, otherwise the proxy arp does not work.
0493                 ip -netns "${nsname}" -4 route \
0494                         add "${IPv4_HS_NETWORK}.${dst}" vrf "${VRF_DEVNAME}" \
0495                         encap seg6 mode "${mode}" segs "${policy}" \
0496                         dev "${VRF_DEVNAME}"
0497         fi
0498 }
0499 
0500 # see __setup_rt_policy
0501 setup_rt_policy_ipv6()
0502 {
0503         __setup_rt_policy "$1" "$2" "$3" "$4" "$5" 6
0504 }
0505 
0506 #see __setup_rt_policy
0507 setup_rt_policy_ipv4()
0508 {
0509         __setup_rt_policy "$1" "$2" "$3" "$4" "$5" 4
0510 }
0511 
0512 setup_hs()
0513 {
0514         local hs="$1"
0515         local rt="$2"
0516         local hsname
0517         local rtname
0518 
0519         hsname="$(get_hsname "${hs}")"
0520         rtname="$(get_rtname "${rt}")"
0521 
0522         ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
0523         ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
0524 
0525         ip -netns "${hsname}" link add veth0 type veth \
0526                 peer name "${RT2HS_DEVNAME}" netns "${rtname}"
0527 
0528         ip -netns "${hsname}" addr \
0529                 add "${IPv6_HS_NETWORK}::${hs}/64" dev veth0 nodad
0530         ip -netns "${hsname}" addr add "${IPv4_HS_NETWORK}.${hs}/24" dev veth0
0531 
0532         ip -netns "${hsname}" link set veth0 up
0533         ip -netns "${hsname}" link set lo up
0534 
0535         # configure the VRF on the router which is directly connected to the
0536         # source host.
0537         ip -netns "${rtname}" link \
0538                 add "${VRF_DEVNAME}" type vrf table "${VRF_TID}"
0539         ip -netns "${rtname}" link set "${VRF_DEVNAME}" up
0540 
0541         # enslave the veth interface connecting the router with the host to the
0542         # VRF in the access router
0543         ip -netns "${rtname}" link \
0544                 set "${RT2HS_DEVNAME}" master "${VRF_DEVNAME}"
0545 
0546         ip -netns "${rtname}" addr \
0547                 add "${IPv6_HS_NETWORK}::254/64" dev "${RT2HS_DEVNAME}" nodad
0548         ip -netns "${rtname}" addr \
0549                 add "${IPv4_HS_NETWORK}.254/24" dev "${RT2HS_DEVNAME}"
0550 
0551         ip -netns "${rtname}" link set "${RT2HS_DEVNAME}" up
0552 
0553         ip netns exec "${rtname}" \
0554                 sysctl -wq net.ipv6.conf."${RT2HS_DEVNAME}".proxy_ndp=1
0555         ip netns exec "${rtname}" \
0556                 sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".proxy_arp=1
0557 
0558         # disable the rp_filter otherwise the kernel gets confused about how
0559         # to route decap ipv4 packets.
0560         ip netns exec "${rtname}" \
0561                 sysctl -wq net.ipv4.conf."${RT2HS_DEVNAME}".rp_filter=0
0562 
0563         ip netns exec "${rtname}" sh -c "echo 1 > /proc/sys/net/vrf/strict_mode"
0564 }
0565 
0566 setup()
0567 {
0568         local i
0569 
0570         # create routers
0571         ROUTERS="1 2 3 4"; readonly ROUTERS
0572         for i in ${ROUTERS}; do
0573                 create_router "${i}"
0574         done
0575 
0576         # create hosts
0577         HOSTS="1 2 3 4"; readonly HOSTS
0578         for i in ${HOSTS}; do
0579                 create_host "${i}"
0580         done
0581 
0582         # set up the links for connecting routers
0583         add_link_rt_pairs 1 "2 3 4"
0584         add_link_rt_pairs 2 "3 4"
0585         add_link_rt_pairs 3 "4"
0586 
0587         # set up the basic connectivity of routers and routes required for
0588         # reachability of SIDs.
0589         setup_rt_networking 1 "2 3 4"
0590         setup_rt_networking 2 "1 3 4"
0591         setup_rt_networking 3 "1 2 4"
0592         setup_rt_networking 4 "1 2 3"
0593 
0594         # set up the hosts connected to routers
0595         setup_hs 1 1
0596         setup_hs 2 2
0597         setup_hs 3 3
0598         setup_hs 4 4
0599 
0600         # set up default SRv6 Endpoints (i.e. SRv6 End and SRv6 End.DT46)
0601         setup_rt_local_sids 1 "2 3 4"
0602         setup_rt_local_sids 2 "1 3 4"
0603         setup_rt_local_sids 3 "1 2 4"
0604         setup_rt_local_sids 4 "1 2 3"
0605 
0606         # set up SRv6 policies
0607 
0608         # create an IPv6 VPN between hosts hs-1 and hs-2.
0609         # the network path between hs-1 and hs-2 traverses several routers
0610         # depending on the direction of traffic.
0611         #
0612         # Direction hs-1 -> hs-2 (H.Encaps.Red)
0613         #  - rt-3,rt-4 (SRv6 End behaviors)
0614         #  - rt-2 (SRv6 End.DT46 behavior)
0615         #
0616         # Direction hs-2 -> hs-1 (H.Encaps.Red)
0617         #  - rt-1 (SRv6 End.DT46 behavior)
0618         setup_rt_policy_ipv6 2 1 "3 4" 2 encap.red
0619         setup_rt_policy_ipv6 1 2 "" 1 encap.red
0620 
0621         # create an IPv4 VPN between hosts hs-1 and hs-2
0622         # the network path between hs-1 and hs-2 traverses several routers
0623         # depending on the direction of traffic.
0624         #
0625         # Direction hs-1 -> hs-2 (H.Encaps.Red)
0626         # - rt-2 (SRv6 End.DT46 behavior)
0627         #
0628         # Direction hs-2 -> hs-1 (H.Encaps.Red)
0629         #  - rt-4,rt-3 (SRv6 End behaviors)
0630         #  - rt-1 (SRv6 End.DT46 behavior)
0631         setup_rt_policy_ipv4 2 1 "" 2 encap.red
0632         setup_rt_policy_ipv4 1 2 "4 3" 1 encap.red
0633 
0634         # create an IPv6 VPN between hosts hs-3 and hs-4
0635         # the network path between hs-3 and hs-4 traverses several routers
0636         # depending on the direction of traffic.
0637         #
0638         # Direction hs-3 -> hs-4 (H.Encaps.Red)
0639         # - rt-2 (SRv6 End Behavior)
0640         # - rt-4 (SRv6 End.DT46 behavior)
0641         #
0642         # Direction hs-4 -> hs-3 (H.Encaps.Red)
0643         #  - rt-1 (SRv6 End behavior)
0644         #  - rt-3 (SRv6 End.DT46 behavior)
0645         setup_rt_policy_ipv6 4 3 "2" 4 encap.red
0646         setup_rt_policy_ipv6 3 4 "1" 3 encap.red
0647 
0648         # testing environment was set up successfully
0649         SETUP_ERR=0
0650 }
0651 
0652 check_rt_connectivity()
0653 {
0654         local rtsrc="$1"
0655         local rtdst="$2"
0656         local prefix
0657         local rtsrc_nsname
0658 
0659         rtsrc_nsname="$(get_rtname "${rtsrc}")"
0660 
0661         prefix="$(get_network_prefix "${rtsrc}" "${rtdst}")"
0662 
0663         ip netns exec "${rtsrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
0664                 "${prefix}::${rtdst}" >/dev/null 2>&1
0665 }
0666 
0667 check_and_log_rt_connectivity()
0668 {
0669         local rtsrc="$1"
0670         local rtdst="$2"
0671 
0672         check_rt_connectivity "${rtsrc}" "${rtdst}"
0673         log_test $? 0 "Routers connectivity: rt-${rtsrc} -> rt-${rtdst}"
0674 }
0675 
0676 check_hs_ipv6_connectivity()
0677 {
0678         local hssrc="$1"
0679         local hsdst="$2"
0680         local hssrc_nsname
0681 
0682         hssrc_nsname="$(get_hsname "${hssrc}")"
0683 
0684         ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
0685                 "${IPv6_HS_NETWORK}::${hsdst}" >/dev/null 2>&1
0686 }
0687 
0688 check_hs_ipv4_connectivity()
0689 {
0690         local hssrc="$1"
0691         local hsdst="$2"
0692         local hssrc_nsname
0693 
0694         hssrc_nsname="$(get_hsname "${hssrc}")"
0695 
0696         ip netns exec "${hssrc_nsname}" ping -c 1 -W "${PING_TIMEOUT_SEC}" \
0697                 "${IPv4_HS_NETWORK}.${hsdst}" >/dev/null 2>&1
0698 }
0699 
0700 check_and_log_hs2gw_connectivity()
0701 {
0702         local hssrc="$1"
0703 
0704         check_hs_ipv6_connectivity "${hssrc}" 254
0705         log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> gw"
0706 
0707         check_hs_ipv4_connectivity "${hssrc}" 254
0708         log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> gw"
0709 }
0710 
0711 check_and_log_hs_ipv6_connectivity()
0712 {
0713         local hssrc="$1"
0714         local hsdst="$2"
0715 
0716         check_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
0717         log_test $? 0 "IPv6 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"
0718 }
0719 
0720 check_and_log_hs_ipv4_connectivity()
0721 {
0722         local hssrc="$1"
0723         local hsdst="$2"
0724 
0725         check_hs_ipv4_connectivity "${hssrc}" "${hsdst}"
0726         log_test $? 0 "IPv4 Hosts connectivity: hs-${hssrc} -> hs-${hsdst}"
0727 }
0728 
0729 check_and_log_hs_connectivity()
0730 {
0731         local hssrc="$1"
0732         local hsdst="$2"
0733 
0734         check_and_log_hs_ipv4_connectivity "${hssrc}" "${hsdst}"
0735         check_and_log_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
0736 }
0737 
0738 check_and_log_hs_ipv6_isolation()
0739 {
0740         local hssrc="$1"
0741         local hsdst="$2"
0742 
0743         # in this case, the connectivity test must fail
0744         check_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
0745         log_test $? 1 "IPv6 Hosts isolation: hs-${hssrc} -X-> hs-${hsdst}"
0746 }
0747 
0748 check_and_log_hs_ipv4_isolation()
0749 {
0750         local hssrc="$1"
0751         local hsdst="$2"
0752 
0753         # in this case, the connectivity test must fail
0754         check_hs_ipv4_connectivity "${hssrc}" "${hsdst}"
0755         log_test $? 1 "IPv4 Hosts isolation: hs-${hssrc} -X-> hs-${hsdst}"
0756 }
0757 
0758 check_and_log_hs_isolation()
0759 {
0760         local hssrc="$1"
0761         local hsdst="$2"
0762 
0763         check_and_log_hs_ipv6_isolation "${hssrc}" "${hsdst}"
0764         check_and_log_hs_ipv4_isolation "${hssrc}" "${hsdst}"
0765 }
0766 
0767 router_tests()
0768 {
0769         local i
0770         local j
0771 
0772         log_section "IPv6 routers connectivity test"
0773 
0774         for i in ${ROUTERS}; do
0775                 for j in ${ROUTERS}; do
0776                         if [ "${i}" -eq "${j}" ]; then
0777                                 continue
0778                         fi
0779 
0780                         check_and_log_rt_connectivity "${i}" "${j}"
0781                 done
0782         done
0783 }
0784 
0785 host2gateway_tests()
0786 {
0787         local hs
0788 
0789         log_section "IPv4/IPv6 connectivity test among hosts and gateways"
0790 
0791         for hs in ${HOSTS}; do
0792                 check_and_log_hs2gw_connectivity "${hs}"
0793         done
0794 }
0795 
0796 host_vpn_tests()
0797 {
0798         log_section "SRv6 VPN connectivity test hosts (h1 <-> h2, IPv4/IPv6)"
0799 
0800         check_and_log_hs_connectivity 1 2
0801         check_and_log_hs_connectivity 2 1
0802 
0803         log_section "SRv6 VPN connectivity test hosts (h3 <-> h4, IPv6 only)"
0804 
0805         check_and_log_hs_ipv6_connectivity 3 4
0806         check_and_log_hs_ipv6_connectivity 4 3
0807 }
0808 
0809 host_vpn_isolation_tests()
0810 {
0811         local l1="1 2"
0812         local l2="3 4"
0813         local tmp
0814         local i
0815         local j
0816         local k
0817 
0818         log_section "SRv6 VPN isolation test among hosts"
0819 
0820         for k in 0 1; do
0821                 for i in ${l1}; do
0822                         for j in ${l2}; do
0823                                 check_and_log_hs_isolation "${i}" "${j}"
0824                         done
0825                 done
0826 
0827                 # let us test the reverse path
0828                 tmp="${l1}"; l1="${l2}"; l2="${tmp}"
0829         done
0830 
0831         log_section "SRv6 VPN isolation test among hosts (h2 <-> h4, IPv4 only)"
0832 
0833         check_and_log_hs_ipv4_isolation 2 4
0834         check_and_log_hs_ipv4_isolation 4 2
0835 }
0836 
0837 test_iproute2_supp_or_ksft_skip()
0838 {
0839         if ! ip route help 2>&1 | grep -qo "encap.red"; then
0840                 echo "SKIP: Missing SRv6 encap.red support in iproute2"
0841                 exit "${ksft_skip}"
0842         fi
0843 }
0844 
0845 test_vrf_or_ksft_skip()
0846 {
0847         modprobe vrf &>/dev/null || true
0848         if [ ! -e /proc/sys/net/vrf/strict_mode ]; then
0849                 echo "SKIP: vrf sysctl does not exist"
0850                 exit "${ksft_skip}"
0851         fi
0852 }
0853 
0854 if [ "$(id -u)" -ne 0 ]; then
0855         echo "SKIP: Need root privileges"
0856         exit "${ksft_skip}"
0857 fi
0858 
0859 # required programs to carry out this selftest
0860 test_command_or_ksft_skip ip
0861 test_command_or_ksft_skip ping
0862 test_command_or_ksft_skip sysctl
0863 test_command_or_ksft_skip grep
0864 
0865 test_iproute2_supp_or_ksft_skip
0866 test_vrf_or_ksft_skip
0867 
0868 set -e
0869 trap cleanup EXIT
0870 
0871 setup
0872 set +e
0873 
0874 router_tests
0875 host2gateway_tests
0876 host_vpn_tests
0877 host_vpn_isolation_tests
0878 
0879 print_log_test_results