Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d232924

Browse files
liuhangbinborkmann
authored andcommitted
selftests/bpf: Add xdp_redirect_multi test
Add a bpf selftest for new helper xdp_redirect_map_multi(). In this test there are 3 forward groups and 1 exclude group. The test will redirect each interface's packets to all the interfaces in the forward group, and exclude the interface in exclude map. Two maps (DEVMAP, DEVMAP_HASH) and two xdp modes (generic, drive) will be tested. XDP egress program will also be tested by setting pkt src MAC to egress interface's MAC address. For more test details, you can find it in the test script. Here is the test result. ]# time ./test_xdp_redirect_multi.sh Pass: xdpgeneric arp(F_BROADCAST) ns1-1 Pass: xdpgeneric arp(F_BROADCAST) ns1-2 Pass: xdpgeneric arp(F_BROADCAST) ns1-3 Pass: xdpgeneric IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-1 Pass: xdpgeneric IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-2 Pass: xdpgeneric IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-3 Pass: xdpgeneric IPv6 (no flags) ns1-1 Pass: xdpgeneric IPv6 (no flags) ns1-2 Pass: xdpdrv arp(F_BROADCAST) ns1-1 Pass: xdpdrv arp(F_BROADCAST) ns1-2 Pass: xdpdrv arp(F_BROADCAST) ns1-3 Pass: xdpdrv IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-1 Pass: xdpdrv IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-2 Pass: xdpdrv IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-3 Pass: xdpdrv IPv6 (no flags) ns1-1 Pass: xdpdrv IPv6 (no flags) ns1-2 Pass: xdpegress mac ns1-2 Pass: xdpegress mac ns1-3 Summary: PASS 18, FAIL 0 real 1m18.321s user 0m0.123s sys 0m0.350s Signed-off-by: Hangbin Liu <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Toke Høiland-Jørgensen <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent e48cfe4 commit d232924

File tree

4 files changed

+526
-1
lines changed

4 files changed

+526
-1
lines changed

tools/testing/selftests/bpf/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ TEST_FILES = xsk_prereqs.sh \
5454
# Order correspond to 'make run_tests' order
5555
TEST_PROGS := test_kmod.sh \
5656
test_xdp_redirect.sh \
57+
test_xdp_redirect_multi.sh \
5758
test_xdp_meta.sh \
5859
test_xdp_veth.sh \
5960
test_offload.py \
@@ -84,7 +85,7 @@ TEST_PROGS_EXTENDED := with_addr.sh \
8485
TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \
8586
flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \
8687
test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \
87-
xdpxceiver
88+
xdpxceiver xdp_redirect_multi
8889

8990
TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read
9091

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#define KBUILD_MODNAME "foo"
3+
#include <string.h>
4+
#include <linux/in.h>
5+
#include <linux/if_ether.h>
6+
#include <linux/if_packet.h>
7+
#include <linux/ip.h>
8+
#include <linux/ipv6.h>
9+
10+
#include <linux/bpf.h>
11+
#include <bpf/bpf_helpers.h>
12+
#include <bpf/bpf_endian.h>
13+
14+
/* One map use devmap, another one use devmap_hash for testing */
15+
struct {
16+
__uint(type, BPF_MAP_TYPE_DEVMAP);
17+
__uint(key_size, sizeof(int));
18+
__uint(value_size, sizeof(int));
19+
__uint(max_entries, 1024);
20+
} map_all SEC(".maps");
21+
22+
struct {
23+
__uint(type, BPF_MAP_TYPE_DEVMAP_HASH);
24+
__uint(key_size, sizeof(int));
25+
__uint(value_size, sizeof(struct bpf_devmap_val));
26+
__uint(max_entries, 128);
27+
} map_egress SEC(".maps");
28+
29+
/* map to store egress interfaces mac addresses */
30+
struct {
31+
__uint(type, BPF_MAP_TYPE_HASH);
32+
__type(key, __u32);
33+
__type(value, __be64);
34+
__uint(max_entries, 128);
35+
} mac_map SEC(".maps");
36+
37+
SEC("xdp_redirect_map_multi")
38+
int xdp_redirect_map_multi_prog(struct xdp_md *ctx)
39+
{
40+
void *data_end = (void *)(long)ctx->data_end;
41+
void *data = (void *)(long)ctx->data;
42+
int if_index = ctx->ingress_ifindex;
43+
struct ethhdr *eth = data;
44+
__u16 h_proto;
45+
__u64 nh_off;
46+
47+
nh_off = sizeof(*eth);
48+
if (data + nh_off > data_end)
49+
return XDP_DROP;
50+
51+
h_proto = eth->h_proto;
52+
53+
/* Using IPv4 for (BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS) testing */
54+
if (h_proto == bpf_htons(ETH_P_IP))
55+
return bpf_redirect_map(&map_all, 0,
56+
BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS);
57+
/* Using IPv6 for none flag testing */
58+
else if (h_proto == bpf_htons(ETH_P_IPV6))
59+
return bpf_redirect_map(&map_all, if_index, 0);
60+
/* All others for BPF_F_BROADCAST testing */
61+
else
62+
return bpf_redirect_map(&map_all, 0, BPF_F_BROADCAST);
63+
}
64+
65+
/* The following 2 progs are for 2nd devmap prog testing */
66+
SEC("xdp_redirect_map_ingress")
67+
int xdp_redirect_map_all_prog(struct xdp_md *ctx)
68+
{
69+
return bpf_redirect_map(&map_egress, 0,
70+
BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS);
71+
}
72+
73+
SEC("xdp_devmap/map_prog")
74+
int xdp_devmap_prog(struct xdp_md *ctx)
75+
{
76+
void *data_end = (void *)(long)ctx->data_end;
77+
void *data = (void *)(long)ctx->data;
78+
__u32 key = ctx->egress_ifindex;
79+
struct ethhdr *eth = data;
80+
__u64 nh_off;
81+
__be64 *mac;
82+
83+
nh_off = sizeof(*eth);
84+
if (data + nh_off > data_end)
85+
return XDP_DROP;
86+
87+
mac = bpf_map_lookup_elem(&mac_map, &key);
88+
if (mac)
89+
__builtin_memcpy(eth->h_source, mac, ETH_ALEN);
90+
91+
return XDP_PASS;
92+
}
93+
94+
char _license[] SEC("license") = "GPL";
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
#!/bin/bash
2+
# SPDX-License-Identifier: GPL-2.0
3+
#
4+
# Test topology:
5+
# - - - - - - - - - - - - - - - - - - - - - - - - -
6+
# | veth1 veth2 veth3 | ... init net
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
29+
NUM=3
30+
IFACES=""
31+
DRV_MODE="xdpgeneric xdpdrv xdpegress"
32+
PASS=0
33+
FAIL=0
34+
35+
test_pass()
36+
{
37+
echo "Pass: $@"
38+
PASS=$((PASS + 1))
39+
}
40+
41+
test_fail()
42+
{
43+
echo "fail: $@"
44+
FAIL=$((FAIL + 1))
45+
}
46+
47+
clean_up()
48+
{
49+
for i in $(seq $NUM); do
50+
ip link del veth$i 2> /dev/null
51+
ip netns del ns$i 2> /dev/null
52+
done
53+
}
54+
55+
# Kselftest framework requirement - SKIP code is 4.
56+
check_env()
57+
{
58+
ip link set dev lo xdpgeneric off &>/dev/null
59+
if [ $? -ne 0 ];then
60+
echo "selftests: [SKIP] Could not run test without the ip xdpgeneric support"
61+
exit 4
62+
fi
63+
64+
which tcpdump &>/dev/null
65+
if [ $? -ne 0 ];then
66+
echo "selftests: [SKIP] Could not run test without tcpdump"
67+
exit 4
68+
fi
69+
}
70+
71+
setup_ns()
72+
{
73+
local mode=$1
74+
IFACES=""
75+
76+
if [ "$mode" = "xdpegress" ]; then
77+
mode="xdpdrv"
78+
fi
79+
80+
for i in $(seq $NUM); do
81+
ip netns add ns$i
82+
ip link add veth$i type veth peer name veth0 netns ns$i
83+
ip link set veth$i up
84+
ip -n ns$i link set veth0 up
85+
86+
ip -n ns$i addr add 192.0.2.$i/24 dev veth0
87+
ip -n ns$i addr add 2001:db8::$i/64 dev veth0
88+
# Add a neigh entry for IPv4 ping test
89+
ip -n ns$i neigh add 192.0.2.253 lladdr 00:00:00:00:00:01 dev veth0
90+
ip -n ns$i link set veth0 $mode obj \
91+
xdp_dummy.o sec xdp_dummy &> /dev/null || \
92+
{ test_fail "Unable to load dummy xdp" && exit 1; }
93+
IFACES="$IFACES veth$i"
94+
veth_mac[$i]=$(ip link show veth$i | awk '/link\/ether/ {print $2}')
95+
done
96+
}
97+
98+
do_egress_tests()
99+
{
100+
local mode=$1
101+
102+
# mac test
103+
ip netns exec ns2 tcpdump -e -i veth0 -nn -l -e &> mac_ns1-2_${mode}.log &
104+
ip netns exec ns3 tcpdump -e -i veth0 -nn -l -e &> mac_ns1-3_${mode}.log &
105+
sleep 0.5
106+
ip netns exec ns1 ping 192.0.2.254 -i 0.1 -c 4 &> /dev/null
107+
sleep 0.5
108+
pkill -9 tcpdump
109+
110+
# mac check
111+
grep -q "${veth_mac[2]} > ff:ff:ff:ff:ff:ff" mac_ns1-2_${mode}.log && \
112+
test_pass "$mode mac ns1-2" || test_fail "$mode mac ns1-2"
113+
grep -q "${veth_mac[3]} > ff:ff:ff:ff:ff:ff" mac_ns1-3_${mode}.log && \
114+
test_pass "$mode mac ns1-3" || test_fail "$mode mac ns1-3"
115+
}
116+
117+
do_ping_tests()
118+
{
119+
local mode=$1
120+
121+
# ping6 test: echo request should be redirect back to itself, not others
122+
ip netns exec ns1 ip neigh add 2001:db8::2 dev veth0 lladdr 00:00:00:00:00:02
123+
124+
ip netns exec ns1 tcpdump -i veth0 -nn -l -e &> ns1-1_${mode}.log &
125+
ip netns exec ns2 tcpdump -i veth0 -nn -l -e &> ns1-2_${mode}.log &
126+
ip netns exec ns3 tcpdump -i veth0 -nn -l -e &> ns1-3_${mode}.log &
127+
sleep 0.5
128+
# ARP test
129+
ip netns exec ns1 ping 192.0.2.254 -i 0.1 -c 4 &> /dev/null
130+
# IPv4 test
131+
ip netns exec ns1 ping 192.0.2.253 -i 0.1 -c 4 &> /dev/null
132+
# IPv6 test
133+
ip netns exec ns1 ping6 2001:db8::2 -i 0.1 -c 2 &> /dev/null
134+
sleep 0.5
135+
pkill -9 tcpdump
136+
137+
# All netns should receive the redirect arp requests
138+
[ $(grep -c "who-has 192.0.2.254" ns1-1_${mode}.log) -gt 4 ] && \
139+
test_pass "$mode arp(F_BROADCAST) ns1-1" || \
140+
test_fail "$mode arp(F_BROADCAST) ns1-1"
141+
[ $(grep -c "who-has 192.0.2.254" ns1-2_${mode}.log) -le 4 ] && \
142+
test_pass "$mode arp(F_BROADCAST) ns1-2" || \
143+
test_fail "$mode arp(F_BROADCAST) ns1-2"
144+
[ $(grep -c "who-has 192.0.2.254" ns1-3_${mode}.log) -le 4 ] && \
145+
test_pass "$mode arp(F_BROADCAST) ns1-3" || \
146+
test_fail "$mode arp(F_BROADCAST) ns1-3"
147+
148+
# ns1 should not receive the redirect echo request, others should
149+
[ $(grep -c "ICMP echo request" ns1-1_${mode}.log) -eq 4 ] && \
150+
test_pass "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-1" || \
151+
test_fail "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-1"
152+
[ $(grep -c "ICMP echo request" ns1-2_${mode}.log) -eq 4 ] && \
153+
test_pass "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-2" || \
154+
test_fail "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-2"
155+
[ $(grep -c "ICMP echo request" ns1-3_${mode}.log) -eq 4 ] && \
156+
test_pass "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-3" || \
157+
test_fail "$mode IPv4 (F_BROADCAST|F_EXCLUDE_INGRESS) ns1-3"
158+
159+
# ns1 should receive the echo request, ns2 should not
160+
[ $(grep -c "ICMP6, echo request" ns1-1_${mode}.log) -eq 4 ] && \
161+
test_pass "$mode IPv6 (no flags) ns1-1" || \
162+
test_fail "$mode IPv6 (no flags) ns1-1"
163+
[ $(grep -c "ICMP6, echo request" ns1-2_${mode}.log) -eq 0 ] && \
164+
test_pass "$mode IPv6 (no flags) ns1-2" || \
165+
test_fail "$mode IPv6 (no flags) ns1-2"
166+
}
167+
168+
do_tests()
169+
{
170+
local mode=$1
171+
local drv_p
172+
173+
case ${mode} in
174+
xdpdrv) drv_p="-N";;
175+
xdpegress) drv_p="-X";;
176+
xdpgeneric) drv_p="-S";;
177+
esac
178+
179+
./xdp_redirect_multi $drv_p $IFACES &> xdp_redirect_${mode}.log &
180+
xdp_pid=$!
181+
sleep 1
182+
183+
if [ "$mode" = "xdpegress" ]; then
184+
do_egress_tests $mode
185+
else
186+
do_ping_tests $mode
187+
fi
188+
189+
kill $xdp_pid
190+
}
191+
192+
trap clean_up 0 2 3 6 9
193+
194+
check_env
195+
rm -f xdp_redirect_*.log ns*.log mac_ns*.log
196+
197+
for mode in ${DRV_MODE}; do
198+
setup_ns $mode
199+
do_tests $mode
200+
clean_up
201+
done
202+
203+
echo "Summary: PASS $PASS, FAIL $FAIL"
204+
[ $FAIL -eq 0 ] && exit 0 || exit 1

0 commit comments

Comments
 (0)