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