1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# 4# Test topology: 5# - - - - - - - - - - - - - - - - - - - 6# | veth1 veth2 veth3 | ns0 7# - -| - - - - - - | - - - - - - | - - 8# --------- --------- --------- 9# | veth0 | | veth0 | | veth0 | 10# --------- --------- --------- 11# ns1 ns2 ns3 12# 13# Test modules: 14# XDP modes: generic, native, native + egress_prog 15# 16# Test cases: 17# ARP: Testing BPF_F_BROADCAST, the ingress interface also should receive 18# the redirects. 19# ns1 -> gw: ns1, ns2, ns3, should receive the arp request 20# IPv4: Testing BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS, the ingress 21# interface should not receive the redirects. 22# ns1 -> gw: ns1 should not receive, ns2, ns3 should receive redirects. 23# IPv6: Testing none flag, all the pkts should be redirected back 24# ping test: ns1 -> ns2 (block), echo requests will be redirect back 25# egress_prog: 26# all src mac should be egress interface's mac 27 28# netns numbers 29NUM=3 30IFACES="" 31DRV_MODE="xdpgeneric xdpdrv xdpegress" 32PASS=0 33FAIL=0 34LOG_DIR=$(mktemp -d) 35declare -a NS 36NS[0]="ns0-$(mktemp -u XXXXXX)" 37NS[1]="ns1-$(mktemp -u XXXXXX)" 38NS[2]="ns2-$(mktemp -u XXXXXX)" 39NS[3]="ns3-$(mktemp -u XXXXXX)" 40 41test_pass() 42{ 43 echo "Pass: $@" 44 PASS=$((PASS + 1)) 45} 46 47test_fail() 48{ 49 echo "fail: $@" 50 FAIL=$((FAIL + 1)) 51} 52 53clean_up() 54{ 55 for i in $(seq 0 $NUM); do 56 ip netns del ${NS[$i]} 2> /dev/null 57 done 58} 59 60# Kselftest framework requirement - SKIP code is 4. 61check_env() 62{ 63 ip link set dev lo xdpgeneric off &>/dev/null 64 if [ $? -ne 0 ];then 65 echo "selftests: [SKIP] Could not run test without the ip xdpgeneric support" 66 exit 4 67 fi 68 69 which tcpdump &>/dev/null 70 if [ $? -ne 0 ];then 71 echo "selftests: [SKIP] Could not run test without tcpdump" 72 exit 4 73 fi 74} 75 76setup_ns() 77{ 78 local mode=$1 79 IFACES="" 80 81 if [ "$mode" = "xdpegress" ]; then 82 mode="xdpdrv" 83 fi 84 85 ip netns add ${NS[0]} 86 for i in $(seq $NUM); do 87 ip netns add ${NS[$i]} 88 ip -n ${NS[$i]} link add veth0 type veth peer name veth$i netns ${NS[0]} 89 ip -n ${NS[$i]} link set veth0 up 90 ip -n ${NS[0]} link set veth$i up 91 92 ip -n ${NS[$i]} addr add 192.0.2.$i/24 dev veth0 93 ip -n ${NS[$i]} addr add 2001:db8::$i/64 dev veth0 94 # Add a neigh entry for IPv4 ping test 95 ip -n ${NS[$i]} neigh add 192.0.2.253 lladdr 00:00:00:00:00:01 dev veth0 96 ip -n ${NS[$i]} link set veth0 $mode obj \ 97 xdp_dummy.bpf.o sec xdp &> /dev/null || \ 98 { test_fail "Unable to load dummy xdp" && exit 1; } 99 IFACES="$IFACES veth$i" 100 veth_mac[$i]=$(ip -n ${NS[0]} link show veth$i | awk '/link\/ether/ {print $2}') 101 done 102} 103 104do_egress_tests() 105{ 106 local mode=$1 107 108 # mac test 109 ip netns exec ${NS[2]} tcpdump -e -i veth0 -nn -l -e &> ${LOG_DIR}/mac_ns1-2_${mode}.log & 110 ip netns exec ${NS[3]} tcpdump -e -i veth0 -nn -l -e &> ${LOG_DIR}/mac_ns1-3_${mode}.log & 111 sleep 0.5 112 ip netns exec ${NS[1]} ping 192.0.2.254 -i 0.1 -c 4 &> /dev/null 113 sleep 0.5 114 pkill tcpdump 115 116 # mac check 117 grep -q "${veth_mac[2]} > ff:ff:ff:ff:ff:ff" ${LOG_DIR}/mac_ns1-2_${mode}.log && \ 118 test_pass "$mode mac ns1-2" || test_fail "$mode mac ns1-2" 119 grep -q "${veth_mac[3]} > ff:ff:ff:ff:ff:ff" ${LOG_DIR}/mac_ns1-3_${mode}.log && \ 120 test_pass "$mode mac ns1-3" || test_fail "$mode mac ns1-3" 121} 122 123do_ping_tests() 124{ 125 local mode=$1 126 127 # ping6 test: echo request should be redirect back to itself, not others 128 ip netns exec ${NS[1]} ip neigh add 2001:db8::2 dev veth0 lladdr 00:00:00:00:00:02 129 130 ip netns exec ${NS[1]} tcpdump -i veth0 -nn -l -e &> ${LOG_DIR}/ns1-1_${mode}.log & 131 ip netns exec ${NS[2]} tcpdump -i veth0 -nn -l -e &> ${LOG_DIR}/ns1-2_${mode}.log & 132 ip netns exec ${NS[3]} tcpdump -i veth0 -nn -l -e &> ${LOG_DIR}/ns1-3_${mode}.log & 133 sleep 0.5 134 # ARP test 135 ip netns exec ${NS[1]} arping -q -c 2 -I veth0 192.0.2.254 136 # IPv4 test 137 ip netns exec ${NS[1]} ping 192.0.2.253 -i 0.1 -c 4 &> /dev/null 138 # IPv6 test 139 ip netns exec ${NS[1]} ping6 2001:db8::2 -i 0.1 -c 2 &> /dev/null 140 sleep 0.5 141 pkill tcpdump 142 143 # All netns should receive the redirect arp requests 144 [ $(grep -cF "who-has 192.0.2.254" ${LOG_DIR}/ns1-1_${mode}.log) -eq 4 ] && \ 145 test_pass "$mode arp(F_BROADCAST) ns1-1" || \ 146 test_fail "$mode arp(F_BROADCAST) ns1-1" 147 [ $(grep -cF "who-has 192.0.2.254" ${LOG_DIR}/ns1-2_${mode}.log) -eq 2 ] && \ 148 test_pass "$mode arp(F_BROADCAST) ns1-2" || \ 149 test_fail "$mode arp(F_BROADCAST) ns1-2" 150 [ $(grep -cF "who-has 192.0.2.254" ${LOG_DIR}/ns1-3_${mode}.log) -eq 2 ] && \ 151 test_pass "$mode arp(F_BROADCAST) ns1-3" || \ 152 test_fail "$mode arp(F_BROADCAST) ns1-3" 153 154 # ns1 should not receive the redirect echo request, others should 155 [ $(grep -c "ICMP echo request" ${LOG_DIR}/ns1-1_${mode}.log) -eq 4 ] && \ 156 test_pass "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-1" || \ 157 test_fail "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-1" 158 [ $(grep -c "ICMP echo request" ${LOG_DIR}/ns1-2_${mode}.log) -eq 4 ] && \ 159 test_pass "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-2" || \ 160 test_fail "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-2" 161 [ $(grep -c "ICMP echo request" ${LOG_DIR}/ns1-3_${mode}.log) -eq 4 ] && \ 162 test_pass "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-3" || \ 163 test_fail "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-3" 164 165 # ns1 should receive the echo request, ns2 should not 166 [ $(grep -c "ICMP6, echo request" ${LOG_DIR}/ns1-1_${mode}.log) -eq 4 ] && \ 167 test_pass "$mode IPv6 (no flags) ns1-1" || \ 168 test_fail "$mode IPv6 (no flags) ns1-1" 169 [ $(grep -c "ICMP6, echo request" ${LOG_DIR}/ns1-2_${mode}.log) -eq 0 ] && \ 170 test_pass "$mode IPv6 (no flags) ns1-2" || \ 171 test_fail "$mode IPv6 (no flags) ns1-2" 172} 173 174do_tests() 175{ 176 local mode=$1 177 local drv_p 178 179 case ${mode} in 180 xdpdrv) drv_p="-N";; 181 xdpegress) drv_p="-X";; 182 xdpgeneric) drv_p="-S";; 183 esac 184 185 ip netns exec ${NS[0]} ./xdp_redirect_multi $drv_p $IFACES &> ${LOG_DIR}/xdp_redirect_${mode}.log & 186 xdp_pid=$! 187 sleep 1 188 if ! ps -p $xdp_pid > /dev/null; then 189 test_fail "$mode xdp_redirect_multi start failed" 190 return 1 191 fi 192 193 if [ "$mode" = "xdpegress" ]; then 194 do_egress_tests $mode 195 else 196 do_ping_tests $mode 197 fi 198 199 kill $xdp_pid 200} 201 202check_env 203 204trap clean_up EXIT 205 206for mode in ${DRV_MODE}; do 207 setup_ns $mode 208 do_tests $mode 209 clean_up 210done 211rm -rf ${LOG_DIR} 212 213echo "Summary: PASS $PASS, FAIL $FAIL" 214[ $FAIL -eq 0 ] && exit 0 || exit 1 215