Skip to content

Commit 41b01a0

Browse files
Tropicaoanakryiko
authored andcommitted
selftests/bpf: Integrate test_xdp_veth into test_progs
test_xdp_veth.sh tests that XDP return codes work as expected, by bringing up multiple veth pairs isolated in different namespaces, attaching specific xdp programs to each interface, and ensuring that the whole chain allows to ping one end interface from the first one. The test runs well but is currently not integrated in test_progs, which prevents it from being run automatically in the CI infrastructure. Rewrite it as a C test relying on libbpf to allow running it in the CI infrastructure. The new code brings up the same network infrastructure and reuses the same eBPF programs as test_xdp_veth.sh, for which skeletons are already generated by the bpf tests makefile. Signed-off-by: Alexis Lothoré (eBPF Foundation) <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Stanislav Fomichev <[email protected]> Link: https://lore.kernel.org/bpf/[email protected] Signed-off-by: Andrii Nakryiko <[email protected]>
1 parent 0bfdda9 commit 41b01a0

File tree

3 files changed

+213
-122
lines changed

3 files changed

+213
-122
lines changed

tools/testing/selftests/bpf/Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ TEST_PROGS := test_kmod.sh \
115115
test_xdp_redirect.sh \
116116
test_xdp_redirect_multi.sh \
117117
test_xdp_meta.sh \
118-
test_xdp_veth.sh \
119118
test_tunnel.sh \
120119
test_lwt_seg6local.sh \
121120
test_lirc_mode2.sh \
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
/* Create 3 namespaces with 3 veth peers, and forward packets in-between using
4+
* native XDP
5+
*
6+
* XDP_TX
7+
* NS1(veth11) NS2(veth22) NS3(veth33)
8+
* | | |
9+
* | | |
10+
* (veth1, (veth2, (veth3,
11+
* id:111) id:122) id:133)
12+
* ^ | ^ | ^ |
13+
* | | XDP_REDIRECT | | XDP_REDIRECT | |
14+
* | ------------------ ------------------ |
15+
* -----------------------------------------
16+
* XDP_REDIRECT
17+
*/
18+
19+
#define _GNU_SOURCE
20+
#include <net/if.h>
21+
#include "test_progs.h"
22+
#include "network_helpers.h"
23+
#include "xdp_dummy.skel.h"
24+
#include "xdp_redirect_map.skel.h"
25+
#include "xdp_tx.skel.h"
26+
27+
#define VETH_PAIRS_COUNT 3
28+
#define NS_SUFFIX_LEN 6
29+
#define VETH_NAME_MAX_LEN 16
30+
#define IP_SRC "10.1.1.11"
31+
#define IP_DST "10.1.1.33"
32+
#define IP_CMD_MAX_LEN 128
33+
34+
struct skeletons {
35+
struct xdp_dummy *xdp_dummy;
36+
struct xdp_tx *xdp_tx;
37+
struct xdp_redirect_map *xdp_redirect_maps;
38+
};
39+
40+
struct veth_configuration {
41+
char local_veth[VETH_NAME_MAX_LEN]; /* Interface in main namespace */
42+
char remote_veth[VETH_NAME_MAX_LEN]; /* Peer interface in dedicated namespace*/
43+
const char *namespace; /* Namespace for the remote veth */
44+
char next_veth[VETH_NAME_MAX_LEN]; /* Local interface to redirect traffic to */
45+
char *remote_addr; /* IP address of the remote veth */
46+
};
47+
48+
static struct veth_configuration config[VETH_PAIRS_COUNT] = {
49+
{
50+
.local_veth = "veth1",
51+
.remote_veth = "veth11",
52+
.next_veth = "veth2",
53+
.remote_addr = IP_SRC,
54+
.namespace = "ns-veth11"
55+
},
56+
{
57+
.local_veth = "veth2",
58+
.remote_veth = "veth22",
59+
.next_veth = "veth3",
60+
.remote_addr = NULL,
61+
.namespace = "ns-veth22"
62+
},
63+
{
64+
.local_veth = "veth3",
65+
.remote_veth = "veth33",
66+
.next_veth = "veth1",
67+
.remote_addr = IP_DST,
68+
.namespace = "ns-veth33"
69+
}
70+
};
71+
72+
static int attach_programs_to_veth_pair(struct skeletons *skeletons, int index)
73+
{
74+
struct bpf_program *local_prog, *remote_prog;
75+
struct bpf_link **local_link, **remote_link;
76+
struct nstoken *nstoken;
77+
struct bpf_link *link;
78+
int interface;
79+
80+
switch (index) {
81+
case 0:
82+
local_prog = skeletons->xdp_redirect_maps->progs.xdp_redirect_map_0;
83+
local_link = &skeletons->xdp_redirect_maps->links.xdp_redirect_map_0;
84+
remote_prog = skeletons->xdp_dummy->progs.xdp_dummy_prog;
85+
remote_link = &skeletons->xdp_dummy->links.xdp_dummy_prog;
86+
break;
87+
case 1:
88+
local_prog = skeletons->xdp_redirect_maps->progs.xdp_redirect_map_1;
89+
local_link = &skeletons->xdp_redirect_maps->links.xdp_redirect_map_1;
90+
remote_prog = skeletons->xdp_tx->progs.xdp_tx;
91+
remote_link = &skeletons->xdp_tx->links.xdp_tx;
92+
break;
93+
case 2:
94+
local_prog = skeletons->xdp_redirect_maps->progs.xdp_redirect_map_2;
95+
local_link = &skeletons->xdp_redirect_maps->links.xdp_redirect_map_2;
96+
remote_prog = skeletons->xdp_dummy->progs.xdp_dummy_prog;
97+
remote_link = &skeletons->xdp_dummy->links.xdp_dummy_prog;
98+
break;
99+
}
100+
interface = if_nametoindex(config[index].local_veth);
101+
if (!ASSERT_NEQ(interface, 0, "non zero interface index"))
102+
return -1;
103+
link = bpf_program__attach_xdp(local_prog, interface);
104+
if (!ASSERT_OK_PTR(link, "attach xdp program to local veth"))
105+
return -1;
106+
*local_link = link;
107+
nstoken = open_netns(config[index].namespace);
108+
if (!ASSERT_OK_PTR(nstoken, "switch to remote veth namespace"))
109+
return -1;
110+
interface = if_nametoindex(config[index].remote_veth);
111+
if (!ASSERT_NEQ(interface, 0, "non zero interface index")) {
112+
close_netns(nstoken);
113+
return -1;
114+
}
115+
link = bpf_program__attach_xdp(remote_prog, interface);
116+
*remote_link = link;
117+
close_netns(nstoken);
118+
if (!ASSERT_OK_PTR(link, "attach xdp program to remote veth"))
119+
return -1;
120+
121+
return 0;
122+
}
123+
124+
static int configure_network(struct skeletons *skeletons)
125+
{
126+
int interface_id;
127+
int map_fd;
128+
int err;
129+
int i = 0;
130+
131+
/* First create and configure all interfaces */
132+
for (i = 0; i < VETH_PAIRS_COUNT; i++) {
133+
SYS(fail, "ip netns add %s", config[i].namespace);
134+
SYS(fail, "ip link add %s type veth peer name %s netns %s",
135+
config[i].local_veth, config[i].remote_veth, config[i].namespace);
136+
SYS(fail, "ip link set dev %s up", config[i].local_veth);
137+
if (config[i].remote_addr)
138+
SYS(fail, "ip -n %s addr add %s/24 dev %s", config[i].namespace,
139+
config[i].remote_addr, config[i].remote_veth);
140+
SYS(fail, "ip -n %s link set dev %s up", config[i].namespace,
141+
config[i].remote_veth);
142+
}
143+
144+
/* Then configure the redirect map and attach programs to interfaces */
145+
map_fd = bpf_map__fd(skeletons->xdp_redirect_maps->maps.tx_port);
146+
if (!ASSERT_GE(map_fd, 0, "open redirect map"))
147+
goto fail;
148+
for (i = 0; i < VETH_PAIRS_COUNT; i++) {
149+
interface_id = if_nametoindex(config[i].next_veth);
150+
if (!ASSERT_NEQ(interface_id, 0, "non zero interface index"))
151+
goto fail;
152+
err = bpf_map_update_elem(map_fd, &i, &interface_id, BPF_ANY);
153+
if (!ASSERT_OK(err, "configure interface redirection through map"))
154+
goto fail;
155+
if (attach_programs_to_veth_pair(skeletons, i))
156+
goto fail;
157+
}
158+
159+
return 0;
160+
161+
fail:
162+
return -1;
163+
}
164+
165+
static void cleanup_network(void)
166+
{
167+
int i;
168+
169+
/* Deleting namespaces is enough to automatically remove veth pairs as well
170+
*/
171+
for (i = 0; i < VETH_PAIRS_COUNT; i++)
172+
SYS_NOFAIL("ip netns del %s", config[i].namespace);
173+
}
174+
175+
static int check_ping(struct skeletons *skeletons)
176+
{
177+
/* Test: if all interfaces are properly configured, we must be able to ping
178+
* veth33 from veth11
179+
*/
180+
return SYS_NOFAIL("ip netns exec %s ping -c 1 -W 1 %s > /dev/null",
181+
config[0].namespace, IP_DST);
182+
}
183+
184+
void test_xdp_veth_redirect(void)
185+
{
186+
struct skeletons skeletons = {};
187+
188+
skeletons.xdp_dummy = xdp_dummy__open_and_load();
189+
if (!ASSERT_OK_PTR(skeletons.xdp_dummy, "xdp_dummy__open_and_load"))
190+
return;
191+
192+
skeletons.xdp_tx = xdp_tx__open_and_load();
193+
if (!ASSERT_OK_PTR(skeletons.xdp_tx, "xdp_tx__open_and_load"))
194+
goto destroy_xdp_dummy;
195+
196+
skeletons.xdp_redirect_maps = xdp_redirect_map__open_and_load();
197+
if (!ASSERT_OK_PTR(skeletons.xdp_redirect_maps, "xdp_redirect_map__open_and_load"))
198+
goto destroy_xdp_tx;
199+
200+
if (configure_network(&skeletons))
201+
goto destroy_xdp_redirect_map;
202+
203+
ASSERT_OK(check_ping(&skeletons), "ping");
204+
205+
destroy_xdp_redirect_map:
206+
xdp_redirect_map__destroy(skeletons.xdp_redirect_maps);
207+
destroy_xdp_tx:
208+
xdp_tx__destroy(skeletons.xdp_tx);
209+
destroy_xdp_dummy:
210+
xdp_dummy__destroy(skeletons.xdp_dummy);
211+
212+
cleanup_network();
213+
}

tools/testing/selftests/bpf/test_xdp_veth.sh

Lines changed: 0 additions & 121 deletions
This file was deleted.

0 commit comments

Comments
 (0)