Skip to content

Commit 3cd56fe

Browse files
liuhangbinkernel-patches-bot
authored andcommitted
selftests/bpf: add xdp_redirect_multi test
Add a bpf selftest for new helper xdp_redirect_map_multi(). In this test we have 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. We will also test both DEVMAP and DEVMAP_HASH with xdp generic and drv. For more test details, you can find it in the test script. Here is the test result. ]# ./test_xdp_redirect_multi.sh Pass: xdpgeneric arp ns1-2 Pass: xdpgeneric arp ns1-3 Pass: xdpgeneric arp ns1-4 Pass: xdpgeneric ping ns1-2 Pass: xdpgeneric ping ns1-3 Pass: xdpgeneric ping ns1-4 Pass: xdpgeneric ping6 ns2-1 Pass: xdpgeneric ping6 ns2-3 Pass: xdpgeneric ping6 ns2-4 Pass: xdpdrv arp ns1-2 Pass: xdpdrv arp ns1-3 Pass: xdpdrv arp ns1-4 Pass: xdpdrv ping ns1-2 Pass: xdpdrv ping ns1-3 Pass: xdpdrv ping ns1-4 Pass: xdpdrv ping6 ns2-1 Pass: xdpdrv ping6 ns2-3 Pass: xdpdrv ping6 ns2-4 Pass: xdpegress mac ns1-2 Pass: xdpegress mac ns1-3 Pass: xdpegress mac ns1-4 Pass: xdpegress ping ns1-2 Pass: xdpegress ping ns1-3 Pass: xdpegress ping ns1-4 Summary: PASS 24, FAIL 0 Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
1 parent d43ebe1 commit 3cd56fe

File tree

4 files changed

+582
-1
lines changed

4 files changed

+582
-1
lines changed

tools/testing/selftests/bpf/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ TEST_FILES = xsk_prereqs.sh \
5151
# Order correspond to 'make run_tests' order
5252
TEST_PROGS := test_kmod.sh \
5353
test_xdp_redirect.sh \
54+
test_xdp_redirect_multi.sh \
5455
test_xdp_meta.sh \
5556
test_xdp_veth.sh \
5657
test_offload.py \
@@ -80,7 +81,7 @@ TEST_PROGS_EXTENDED := with_addr.sh \
8081
TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \
8182
flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \
8283
test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \
83-
xdpxceiver
84+
xdpxceiver xdp_redirect_multi
8485

8586
TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read
8687

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/* SPDX-License-Identifier: GPL-2.0
2+
*
3+
* modify it under the terms of version 2 of the GNU General Public
4+
* License as published by the Free Software Foundation.
5+
*
6+
* This program is distributed in the hope that it will be useful, but
7+
* WITHOUT ANY WARRANTY; without even the implied warranty of
8+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9+
* General Public License for more details.
10+
*/
11+
#define KBUILD_MODNAME "foo"
12+
#include <string.h>
13+
#include <linux/in.h>
14+
#include <linux/if_ether.h>
15+
#include <linux/if_packet.h>
16+
#include <linux/ip.h>
17+
#include <linux/ipv6.h>
18+
19+
#include <linux/bpf.h>
20+
#include <bpf/bpf_helpers.h>
21+
#include <bpf/bpf_endian.h>
22+
23+
struct {
24+
__uint(type, BPF_MAP_TYPE_DEVMAP);
25+
__uint(key_size, sizeof(int));
26+
__uint(value_size, sizeof(int));
27+
__uint(max_entries, 128);
28+
} forward_map_v4 SEC(".maps");
29+
30+
struct {
31+
__uint(type, BPF_MAP_TYPE_DEVMAP_HASH);
32+
__uint(key_size, sizeof(int));
33+
__uint(value_size, sizeof(int));
34+
__uint(max_entries, 128);
35+
} forward_map_v6 SEC(".maps");
36+
37+
struct {
38+
__uint(type, BPF_MAP_TYPE_DEVMAP_HASH);
39+
__uint(key_size, sizeof(int));
40+
__uint(value_size, sizeof(int));
41+
__uint(max_entries, 128);
42+
} forward_map_all SEC(".maps");
43+
44+
struct {
45+
__uint(type, BPF_MAP_TYPE_DEVMAP_HASH);
46+
__uint(key_size, sizeof(int));
47+
__uint(value_size, sizeof(struct bpf_devmap_val));
48+
__uint(max_entries, 128);
49+
} forward_map_egress SEC(".maps");
50+
51+
struct {
52+
__uint(type, BPF_MAP_TYPE_DEVMAP_HASH);
53+
__uint(key_size, sizeof(int));
54+
__uint(value_size, sizeof(int));
55+
__uint(max_entries, 128);
56+
} exclude_map SEC(".maps");
57+
58+
/* map to stroe egress interfaces mac addresses */
59+
struct {
60+
__uint(type, BPF_MAP_TYPE_HASH);
61+
__type(key, __u32);
62+
__type(value, __be64);
63+
__uint(max_entries, 128);
64+
} mac_map SEC(".maps");
65+
66+
SEC("xdp_redirect_map_multi")
67+
int xdp_redirect_map_multi_prog(struct xdp_md *ctx)
68+
{
69+
void *data_end = (void *)(long)ctx->data_end;
70+
void *data = (void *)(long)ctx->data;
71+
struct ethhdr *eth = data;
72+
__u16 h_proto;
73+
__u64 nh_off;
74+
75+
nh_off = sizeof(*eth);
76+
if (data + nh_off > data_end)
77+
return XDP_DROP;
78+
79+
h_proto = eth->h_proto;
80+
81+
if (h_proto == bpf_htons(ETH_P_IP))
82+
return bpf_redirect_map_multi(&forward_map_v4, &exclude_map,
83+
BPF_F_EXCLUDE_INGRESS);
84+
else if (h_proto == bpf_htons(ETH_P_IPV6))
85+
return bpf_redirect_map_multi(&forward_map_v6, &exclude_map,
86+
BPF_F_EXCLUDE_INGRESS);
87+
else
88+
return bpf_redirect_map_multi(&forward_map_all, NULL,
89+
BPF_F_EXCLUDE_INGRESS);
90+
}
91+
92+
/* The following 2 progs are for 2nd devmap prog testing */
93+
SEC("xdp_redirect_map_ingress")
94+
int xdp_redirect_map_all_prog(struct xdp_md *ctx)
95+
{
96+
return bpf_redirect_map_multi(&forward_map_egress, NULL, BPF_F_EXCLUDE_INGRESS);
97+
}
98+
99+
SEC("xdp_devmap/map_prog")
100+
int xdp_devmap_prog(struct xdp_md *ctx)
101+
{
102+
void *data_end = (void *)(long)ctx->data_end;
103+
void *data = (void *)(long)ctx->data;
104+
__u32 key = ctx->egress_ifindex;
105+
struct ethhdr *eth = data;
106+
__u64 nh_off;
107+
__be64 *mac;
108+
109+
nh_off = sizeof(*eth);
110+
if (data + nh_off > data_end)
111+
return XDP_DROP;
112+
113+
mac = bpf_map_lookup_elem(&mac_map, &key);
114+
if (mac)
115+
__builtin_memcpy(eth->h_source, mac, ETH_ALEN);
116+
117+
return XDP_PASS;
118+
}
119+
120+
char _license[] SEC("license") = "GPL";
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
#!/bin/bash
2+
# SPDX-License-Identifier: GPL-2.0
3+
#
4+
# Test topology:
5+
# - - - - - - - - - - - - - - - - - - - - - - - - -
6+
# | veth1 veth2 veth3 veth4 | ... init net
7+
# - -| - - - - - - | - - - - - - | - - - - - - | - -
8+
# --------- --------- --------- ---------
9+
# | veth0 | | veth0 | | veth0 | | veth0 | ...
10+
# --------- --------- --------- ---------
11+
# ns1 ns2 ns3 ns4
12+
#
13+
# Forward maps:
14+
# Forward map_all has interfaces: veth1, veth2, veth3, veth4, ... (All traffic except IPv4, IPv6)
15+
# Forward map_v4 has interfaces: veth1, veth3, veth4, ... (For IPv4 traffic only)
16+
# Forward map_v6 has interfaces: veth2, veth3, veth4, ... (For IPv6 traffic only)
17+
# Forward map_egress has all interfaces and redirect all pkts
18+
# Exclude Groups:
19+
# Exclude map: veth3 (assume ns3 is in black list)
20+
# Map type:
21+
# map_v4 use DEVMAP, others use DEVMAP_HASH
22+
#
23+
# Test modules:
24+
# XDP modes: generic, native, native + egress_prog
25+
#
26+
# Test cases:
27+
# ARP(we didn't block ARP for ns3):
28+
# ns1 -> gw: ns2, ns3, ns4 should receive the arp request
29+
# IPv4:
30+
# ns1 -> ns2 (block), ns1 -> ns3 (block), ns1 -> ns4 (pass)
31+
# IPv6
32+
# ns2 -> ns1 (block), ns2 -> ns3 (block), ns2 -> ns4 (pass)
33+
# egress_prog:
34+
# all ping test should pass, the src mac should be egress interface's mac
35+
#
36+
37+
38+
# netns numbers
39+
NUM=4
40+
IFACES=""
41+
DRV_MODE="xdpgeneric xdpdrv xdpegress"
42+
PASS=0
43+
FAIL=0
44+
45+
test_pass()
46+
{
47+
echo "Pass: $@"
48+
PASS=$((PASS + 1))
49+
}
50+
51+
test_fail()
52+
{
53+
echo "fail: $@"
54+
FAIL=$((FAIL + 1))
55+
}
56+
57+
clean_up()
58+
{
59+
for i in $(seq $NUM); do
60+
ip link del veth$i 2> /dev/null
61+
ip netns del ns$i 2> /dev/null
62+
done
63+
}
64+
65+
# Kselftest framework requirement - SKIP code is 4.
66+
check_env()
67+
{
68+
ip link set dev lo xdpgeneric off &>/dev/null
69+
if [ $? -ne 0 ];then
70+
echo "selftests: [SKIP] Could not run test without the ip xdpgeneric support"
71+
exit 4
72+
fi
73+
74+
which tcpdump &>/dev/null
75+
if [ $? -ne 0 ];then
76+
echo "selftests: [SKIP] Could not run test without tcpdump"
77+
exit 4
78+
fi
79+
}
80+
81+
setup_ns()
82+
{
83+
local mode=$1
84+
IFACES=""
85+
86+
if [ "$mode" = "xdpegress" ]; then
87+
mode="xdpdrv"
88+
fi
89+
90+
for i in $(seq $NUM); do
91+
ip netns add ns$i
92+
ip link add veth$i type veth peer name veth0 netns ns$i
93+
ip link set veth$i up
94+
ip -n ns$i link set veth0 up
95+
96+
ip -n ns$i addr add 192.0.2.$i/24 dev veth0
97+
ip -n ns$i addr add 2001:db8::$i/64 dev veth0
98+
ip -n ns$i link set veth0 $mode obj \
99+
xdp_dummy.o sec xdp_dummy &> /dev/null || \
100+
{ test_fail "Unable to load dummy xdp" && exit 1; }
101+
IFACES="$IFACES veth$i"
102+
veth_mac[$i]=$(ip link show veth$i | awk '/link\/ether/ {print $2}')
103+
done
104+
}
105+
106+
do_egress_tests()
107+
{
108+
local mode=$1
109+
110+
# mac test
111+
ip netns exec ns2 tcpdump -e -i veth0 -nn -l -e &> mac_ns1-2_${mode}.log &
112+
ip netns exec ns3 tcpdump -e -i veth0 -nn -l -e &> mac_ns1-3_${mode}.log &
113+
ip netns exec ns4 tcpdump -e -i veth0 -nn -l -e &> mac_ns1-4_${mode}.log &
114+
ip netns exec ns1 ping 192.0.2.254 -c 4 &> /dev/null
115+
sleep 2
116+
pkill -9 tcpdump
117+
118+
# mac check
119+
grep -q "${veth_mac[2]} > ff:ff:ff:ff:ff:ff" mac_ns1-2_${mode}.log && \
120+
test_pass "$mode mac ns1-2" || test_fail "$mode mac ns1-2"
121+
grep -q "${veth_mac[3]} > ff:ff:ff:ff:ff:ff" mac_ns1-3_${mode}.log && \
122+
test_pass "$mode mac ns1-3" || test_fail "$mode mac ns1-3"
123+
grep -q "${veth_mac[4]} > ff:ff:ff:ff:ff:ff" mac_ns1-4_${mode}.log && \
124+
test_pass "$mode mac ns1-4" || test_fail "$mode mac ns1-4"
125+
126+
# ping test
127+
ip netns exec ns1 ping 192.0.2.2 -c 4 &> /dev/null && \
128+
test_pass "$mode ping ns1-2" || test_fail "$mode ping ns1-2"
129+
ip netns exec ns1 ping 192.0.2.3 -c 4 &> /dev/null && \
130+
test_pass "$mode ping ns1-3" || test_fail "$mode ping ns1-3"
131+
ip netns exec ns1 ping 192.0.2.4 -c 4 &> /dev/null && \
132+
test_pass "$mode ping ns1-4" || test_fail "$mode ping ns1-4"
133+
}
134+
135+
do_ping_tests()
136+
{
137+
local mode=$1
138+
139+
# arp test
140+
ip netns exec ns2 tcpdump -i veth0 -nn -l -e &> arp_ns1-2_${mode}.log &
141+
ip netns exec ns3 tcpdump -i veth0 -nn -l -e &> arp_ns1-3_${mode}.log &
142+
ip netns exec ns4 tcpdump -i veth0 -nn -l -e &> arp_ns1-4_${mode}.log &
143+
ip netns exec ns1 ping 192.0.2.254 -c 4 &> /dev/null
144+
sleep 2
145+
pkill -9 tcpdump
146+
grep -q "Request who-has 192.0.2.254 tell 192.0.2.1" arp_ns1-2_${mode}.log && \
147+
test_pass "$mode arp ns1-2" || test_fail "$mode arp ns1-2"
148+
grep -q "Request who-has 192.0.2.254 tell 192.0.2.1" arp_ns1-3_${mode}.log && \
149+
test_pass "$mode arp ns1-3" || test_fail "$mode arp ns1-3"
150+
grep -q "Request who-has 192.0.2.254 tell 192.0.2.1" arp_ns1-4_${mode}.log && \
151+
test_pass "$mode arp ns1-4" || test_fail "$mode arp ns1-4"
152+
153+
# ping test
154+
ip netns exec ns1 ping 192.0.2.2 -c 4 &> /dev/null && \
155+
test_fail "$mode ping ns1-2" || test_pass "$mode ping ns1-2"
156+
ip netns exec ns1 ping 192.0.2.3 -c 4 &> /dev/null && \
157+
test_fail "$mode ping ns1-3" || test_pass "$mode ping ns1-3"
158+
ip netns exec ns1 ping 192.0.2.4 -c 4 &> /dev/null && \
159+
test_pass "$mode ping ns1-4" || test_fail "$mode ping ns1-4"
160+
161+
# ping6 test
162+
ip netns exec ns2 ping6 2001:db8::1 -c 4 &> /dev/null && \
163+
test_fail "$mode ping6 ns2-1" || test_pass "$mode ping6 ns2-1"
164+
ip netns exec ns2 ping6 2001:db8::3 -c 4 &> /dev/null && \
165+
test_fail "$mode ping6 ns2-3" || test_pass "$mode ping6 ns2-3"
166+
ip netns exec ns2 ping6 2001:db8::4 -c 4 &> /dev/null && \
167+
test_pass "$mode ping6 ns2-4" || test_fail "$mode ping6 ns2-4"
168+
}
169+
170+
do_tests()
171+
{
172+
local mode=$1
173+
local drv_p
174+
175+
case ${mode} in
176+
xdpdrv) drv_p="-N";;
177+
xdpegress) drv_p="-X";;
178+
xdpgeneric) drv_p="-S";;
179+
esac
180+
181+
./xdp_redirect_multi $drv_p $IFACES &> xdp_redirect_${mode}.log &
182+
xdp_pid=$!
183+
sleep 10
184+
185+
if [ "$mode" = "xdpegress" ]; then
186+
do_egress_tests $mode
187+
else
188+
do_ping_tests $mode
189+
fi
190+
191+
kill $xdp_pid
192+
}
193+
194+
trap clean_up 0 2 3 6 9
195+
196+
check_env
197+
rm -f xdp_redirect_*.log arp_ns*.log mac_ns*.log
198+
199+
for mode in ${DRV_MODE}; do
200+
setup_ns $mode
201+
do_tests $mode
202+
sleep 10
203+
clean_up
204+
sleep 5
205+
done
206+
207+
echo "Summary: PASS $PASS, FAIL $FAIL"
208+
[ $FAIL -eq 0 ] && exit 0 || exit 1

0 commit comments

Comments
 (0)