| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- #!/bin/bash
- # SPDX-License-Identifier: GPL-2.0
- #
- # author: Andrea Mayer <andrea.mayer@uniroma2.it>
- # This test verifies that the seg6 lwtunnel does not share the dst_cache
- # between the input (forwarding) and output (locally generated) paths.
- #
- # A shared dst_cache allows a forwarded packet to populate the cache and a
- # subsequent locally generated packet to silently reuse that entry, bypassing
- # its own route lookup. To expose this, the SID is made reachable only for
- # forwarded traffic (via an ip rule matching iif) and blackholed for everything
- # else. A local ping on ns_router must always hit the blackhole;
- # if it succeeds after a forwarded packet has populated the
- # cache, the bug is confirmed.
- #
- # Both forwarded and local packets are pinned to the same CPU with taskset,
- # since dst_cache is per-cpu.
- #
- #
- # +--------------------+ +--------------------+
- # | ns_src | | ns_dst |
- # | | | |
- # | veth-s0 | | veth-d0 |
- # | fd00::1/64 | | fd01::2/64 |
- # +-------+------------+ +----------+---------+
- # | |
- # | +--------------------+ |
- # | | ns_router | |
- # | | | |
- # +------------+ veth-r0 veth-r1 +--------------+
- # | fd00::2 fd01::1 |
- # +--------------------+
- #
- #
- # ns_router: encap (main table)
- # +---------+---------------------------------------+
- # | dst | action |
- # +---------+---------------------------------------+
- # | cafe::1 | encap seg6 mode encap segs fc00::100 |
- # +---------+---------------------------------------+
- #
- # ns_router: post-encap SID resolution
- # +-------+------------+----------------------------+
- # | table | dst | action |
- # +-------+------------+----------------------------+
- # | 100 | fc00::100 | via fd01::2 dev veth-r1 |
- # +-------+------------+----------------------------+
- # | main | fc00::100 | blackhole |
- # +-------+------------+----------------------------+
- #
- # ns_router: ip rule
- # +------------------+------------------------------+
- # | match | action |
- # +------------------+------------------------------+
- # | iif veth-r0 | lookup 100 |
- # +------------------+------------------------------+
- #
- # ns_dst: SRv6 decap (main table)
- # +--------------+----------------------------------+
- # | SID | action |
- # +--------------+----------------------------------+
- # | fc00::100 | End.DT6 table 255 (local) |
- # +--------------+----------------------------------+
- source lib.sh
- readonly SID="fc00::100"
- readonly DEST="cafe::1"
- readonly SRC_MAC="02:00:00:00:00:01"
- readonly RTR_R0_MAC="02:00:00:00:00:02"
- readonly RTR_R1_MAC="02:00:00:00:00:03"
- readonly DST_MAC="02:00:00:00:00:04"
- cleanup()
- {
- cleanup_ns "${NS_SRC}" "${NS_RTR}" "${NS_DST}"
- }
- check_prerequisites()
- {
- if ! command -v ip &>/dev/null; then
- echo "SKIP: ip tool not found"
- exit "${ksft_skip}"
- fi
- if ! command -v ping &>/dev/null; then
- echo "SKIP: ping not found"
- exit "${ksft_skip}"
- fi
- if ! command -v sysctl &>/dev/null; then
- echo "SKIP: sysctl not found"
- exit "${ksft_skip}"
- fi
- if ! command -v taskset &>/dev/null; then
- echo "SKIP: taskset not found"
- exit "${ksft_skip}"
- fi
- }
- setup()
- {
- setup_ns NS_SRC NS_RTR NS_DST
- ip link add veth-s0 netns "${NS_SRC}" type veth \
- peer name veth-r0 netns "${NS_RTR}"
- ip link add veth-r1 netns "${NS_RTR}" type veth \
- peer name veth-d0 netns "${NS_DST}"
- ip -n "${NS_SRC}" link set veth-s0 address "${SRC_MAC}"
- ip -n "${NS_RTR}" link set veth-r0 address "${RTR_R0_MAC}"
- ip -n "${NS_RTR}" link set veth-r1 address "${RTR_R1_MAC}"
- ip -n "${NS_DST}" link set veth-d0 address "${DST_MAC}"
- # ns_src
- ip -n "${NS_SRC}" link set veth-s0 up
- ip -n "${NS_SRC}" addr add fd00::1/64 dev veth-s0 nodad
- ip -n "${NS_SRC}" -6 route add "${DEST}"/128 via fd00::2
- # ns_router
- ip -n "${NS_RTR}" link set veth-r0 up
- ip -n "${NS_RTR}" addr add fd00::2/64 dev veth-r0 nodad
- ip -n "${NS_RTR}" link set veth-r1 up
- ip -n "${NS_RTR}" addr add fd01::1/64 dev veth-r1 nodad
- ip netns exec "${NS_RTR}" sysctl -qw net.ipv6.conf.all.forwarding=1
- ip -n "${NS_RTR}" -6 route add "${DEST}"/128 \
- encap seg6 mode encap segs "${SID}" dev veth-r0
- ip -n "${NS_RTR}" -6 route add "${SID}"/128 table 100 \
- via fd01::2 dev veth-r1
- ip -n "${NS_RTR}" -6 route add blackhole "${SID}"/128
- ip -n "${NS_RTR}" -6 rule add iif veth-r0 lookup 100
- # ns_dst
- ip -n "${NS_DST}" link set veth-d0 up
- ip -n "${NS_DST}" addr add fd01::2/64 dev veth-d0 nodad
- ip -n "${NS_DST}" addr add "${DEST}"/128 dev lo nodad
- ip -n "${NS_DST}" -6 route add "${SID}"/128 \
- encap seg6local action End.DT6 table 255 dev veth-d0
- ip -n "${NS_DST}" -6 route add fd00::/64 via fd01::1
- # static neighbors
- ip -n "${NS_SRC}" -6 neigh add fd00::2 dev veth-s0 \
- lladdr "${RTR_R0_MAC}" nud permanent
- ip -n "${NS_RTR}" -6 neigh add fd00::1 dev veth-r0 \
- lladdr "${SRC_MAC}" nud permanent
- ip -n "${NS_RTR}" -6 neigh add fd01::2 dev veth-r1 \
- lladdr "${DST_MAC}" nud permanent
- ip -n "${NS_DST}" -6 neigh add fd01::1 dev veth-d0 \
- lladdr "${RTR_R1_MAC}" nud permanent
- }
- test_cache_isolation()
- {
- RET=0
- # local ping with empty cache: must fail (SID is blackholed)
- if ip netns exec "${NS_RTR}" taskset -c 0 \
- ping -c 1 -W 2 "${DEST}" &>/dev/null; then
- echo "SKIP: local ping succeeded, topology broken"
- exit "${ksft_skip}"
- fi
- # forward from ns_src to populate the input cache
- if ! ip netns exec "${NS_SRC}" taskset -c 0 \
- ping -c 1 -W 2 "${DEST}" &>/dev/null; then
- echo "SKIP: forwarded ping failed, topology broken"
- exit "${ksft_skip}"
- fi
- # local ping again: must still fail; if the output path reuses
- # the input cache, it bypasses the blackhole and the ping succeeds
- if ip netns exec "${NS_RTR}" taskset -c 0 \
- ping -c 1 -W 2 "${DEST}" &>/dev/null; then
- echo "FAIL: output path used dst cached by input path"
- RET="${ksft_fail}"
- else
- echo "PASS: output path dst_cache is independent"
- fi
- return "${RET}"
- }
- if [ "$(id -u)" -ne 0 ]; then
- echo "SKIP: Need root privileges"
- exit "${ksft_skip}"
- fi
- trap cleanup EXIT
- check_prerequisites
- setup
- test_cache_isolation
- exit "${RET}"
|