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