Skip to content

Commit

Permalink
selftests/bpf: test_xdp_veth: Add XDP program on egress test
Browse files Browse the repository at this point in the history
XDP programs loaded on egress is tested by test_xdp_redirect_multi.sh
but not by the test_progs framework.

Add a test case in test_xdp_veth.c to test the XDP program on egress.
Use the same BPF program than test_xdp_redirect_multi.sh that replaces
the source MAC address by one provided through a BPF map.
Use a BPF program that stores the source MAC of received packets in a
map to check the test results.

Signed-off-by: Bastien Curutchet (eBPF Foundation) <bastien.curutchet@bootlin.com>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20250212-redirect-multi-v5-5-fd0d39fca6e6@bootlin.com
  • Loading branch information
Bastien Curutchet (eBPF Foundation) authored and Martin KaFai Lau committed Feb 18, 2025
1 parent 1e7e634 commit a93bfd8
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 0 deletions.
132 changes: 132 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/test_xdp_veth.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
* -> echo request received by all except veth11
* - IPv4 ping : BPF_F_BROADCAST
* -> echo request received by all veth
* - [test_xdp_veth_egress]:
* - all src mac should be the magic mac
*
* veth11 veth22 veth33
* (XDP_PASS) (XDP_PASS) (XDP_PASS)
Expand Down Expand Up @@ -431,6 +433,124 @@ static void xdp_veth_broadcast_redirect(u32 attach_flags, u64 redirect_flags)
cleanup_network(&net_config);
}

#define VETH_EGRESS_SKEL_NB 3
static void xdp_veth_egress(u32 flags)
{
struct prog_configuration prog_cfg[VETH_PAIRS_COUNT] = {
{
.local_name = "xdp_redirect_map_all_prog",
.remote_name = "xdp_dummy_prog",
.local_flags = flags,
.remote_flags = flags,
},
{
.local_name = "xdp_redirect_map_all_prog",
.remote_name = "store_mac_1",
.local_flags = flags,
.remote_flags = flags,
},
{
.local_name = "xdp_redirect_map_all_prog",
.remote_name = "store_mac_2",
.local_flags = flags,
.remote_flags = flags,
}
};
const char magic_mac[6] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
struct xdp_redirect_multi_kern *xdp_redirect_multi_kern;
struct bpf_object *bpf_objs[VETH_EGRESS_SKEL_NB];
struct xdp_redirect_map *xdp_redirect_map;
struct bpf_devmap_val devmap_val = {};
struct net_configuration net_config;
int mac_map, egress_map, res_map;
struct nstoken *nstoken = NULL;
struct xdp_dummy *xdp_dummy;
int err;
int i;

xdp_dummy = xdp_dummy__open_and_load();
if (!ASSERT_OK_PTR(xdp_dummy, "xdp_dummy__open_and_load"))
return;

xdp_redirect_multi_kern = xdp_redirect_multi_kern__open_and_load();
if (!ASSERT_OK_PTR(xdp_redirect_multi_kern, "xdp_redirect_multi_kern__open_and_load"))
goto destroy_xdp_dummy;

xdp_redirect_map = xdp_redirect_map__open_and_load();
if (!ASSERT_OK_PTR(xdp_redirect_map, "xdp_redirect_map__open_and_load"))
goto destroy_xdp_redirect_multi_kern;

if (!ASSERT_OK(create_network(&net_config), "create network"))
goto destroy_xdp_redirect_map;

mac_map = bpf_map__fd(xdp_redirect_multi_kern->maps.mac_map);
if (!ASSERT_OK_FD(mac_map, "open mac_map"))
goto destroy_xdp_redirect_map;

egress_map = bpf_map__fd(xdp_redirect_multi_kern->maps.map_egress);
if (!ASSERT_OK_FD(egress_map, "open map_egress"))
goto destroy_xdp_redirect_map;

devmap_val.bpf_prog.fd = bpf_program__fd(xdp_redirect_multi_kern->progs.xdp_devmap_prog);

bpf_objs[0] = xdp_dummy->obj;
bpf_objs[1] = xdp_redirect_multi_kern->obj;
bpf_objs[2] = xdp_redirect_map->obj;

nstoken = open_netns(net_config.ns0_name);
if (!ASSERT_OK_PTR(nstoken, "open NS0"))
goto destroy_xdp_redirect_map;

for (i = 0; i < VETH_PAIRS_COUNT; i++) {
int ifindex = if_nametoindex(net_config.veth_cfg[i].local_veth);

SYS(destroy_xdp_redirect_map,
"ip -n %s neigh add %s lladdr 00:00:00:00:00:01 dev %s",
net_config.veth_cfg[i].namespace, IP_NEIGH, net_config.veth_cfg[i].remote_veth);

if (attach_programs_to_veth_pair(bpf_objs, VETH_REDIRECT_SKEL_NB,
&net_config, prog_cfg, i))
goto destroy_xdp_redirect_map;

err = bpf_map_update_elem(mac_map, &ifindex, magic_mac, 0);
if (!ASSERT_OK(err, "bpf_map_update_elem"))
goto destroy_xdp_redirect_map;

devmap_val.ifindex = ifindex;
err = bpf_map_update_elem(egress_map, &ifindex, &devmap_val, 0);
if (!ASSERT_OK(err, "bpf_map_update_elem"))
goto destroy_xdp_redirect_map;
}

SYS_NOFAIL("ip netns exec %s ping %s -i 0.1 -c 4 -W1 > /dev/null ",
net_config.veth_cfg[0].namespace, IP_NEIGH);

res_map = bpf_map__fd(xdp_redirect_map->maps.rx_mac);
if (!ASSERT_OK_FD(res_map, "open rx_map"))
goto destroy_xdp_redirect_map;

for (i = 0; i < 2; i++) {
u32 key = i;
u64 res;

err = bpf_map_lookup_elem(res_map, &key, &res);
if (!ASSERT_OK(err, "get MAC res"))
goto destroy_xdp_redirect_map;

ASSERT_STRNEQ((const char *)&res, magic_mac, ETH_ALEN, "compare mac");
}

destroy_xdp_redirect_map:
close_netns(nstoken);
xdp_redirect_map__destroy(xdp_redirect_map);
destroy_xdp_redirect_multi_kern:
xdp_redirect_multi_kern__destroy(xdp_redirect_multi_kern);
destroy_xdp_dummy:
xdp_dummy__destroy(xdp_dummy);

cleanup_network(&net_config);
}

void test_xdp_veth_redirect(void)
{
if (test__start_subtest("0"))
Expand Down Expand Up @@ -465,3 +585,15 @@ void test_xdp_veth_broadcast_redirect(void)
xdp_veth_broadcast_redirect(XDP_FLAGS_SKB_MODE,
BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS);
}

void test_xdp_veth_egress(void)
{
if (test__start_subtest("0/egress"))
xdp_veth_egress(0);

if (test__start_subtest("DRV_MODE/egress"))
xdp_veth_egress(XDP_FLAGS_DRV_MODE);

if (test__start_subtest("SKB_MODE/egress"))
xdp_veth_egress(XDP_FLAGS_SKB_MODE);
}
40 changes: 40 additions & 0 deletions tools/testing/selftests/bpf/progs/xdp_redirect_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,44 @@ int xdp_count_2(struct xdp_md *xdp)
return xdp_count(xdp, 2);
}

struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 2);
__type(key, __u32);
__type(value, __be64);
} rx_mac SEC(".maps");

static int store_mac(struct xdp_md *xdp, __u32 id)
{
void *data_end = (void *)(long)xdp->data_end;
void *data = (void *)(long)xdp->data;
struct ethhdr *eth = data;
__u32 key = id;
__be64 mac = 0;

if (data + sizeof(*eth) > data_end)
return XDP_DROP;

/* Only store IPv4 MAC to avoid being polluted by IPv6 packets */
if (eth->h_proto == bpf_htons(ETH_P_IP)) {
__builtin_memcpy(&mac, eth->h_source, ETH_ALEN);
bpf_map_update_elem(&rx_mac, &key, &mac, 0);
bpf_printk("%s - %x", __func__, mac);
}

return XDP_PASS;
}

SEC("xdp")
int store_mac_1(struct xdp_md *xdp)
{
return store_mac(xdp, 0);
}

SEC("xdp")
int store_mac_2(struct xdp_md *xdp)
{
return store_mac(xdp, 1);
}

char _license[] SEC("license") = "GPL";

0 comments on commit a93bfd8

Please sign in to comment.