This repository has been archived by the owner on Jun 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests/bpf: Tests using bpf_check_mtu BPF-helper
Adding selftest for BPF-helper bpf_check_mtu(). Making sure it can be used from both XDP and TC. V16: - Fix 'void' function definition V11: - Addresse nitpicks from Andrii Nakryiko V10: - Remove errno non-zero test in CHECK_ATTR() - Addresse comments from Andrii Nakryiko Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/161287791989.790810.13612620012522164562.stgit@firesoul
- Loading branch information
1 parent
6b8838b
commit b62eba5
Showing
2 changed files
with
414 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2020 Jesper Dangaard Brouer */ | ||
|
||
#include <linux/if_link.h> /* before test_progs.h, avoid bpf_util.h redefines */ | ||
#include <test_progs.h> | ||
#include "test_check_mtu.skel.h" | ||
#include "network_helpers.h" | ||
|
||
#include <stdlib.h> | ||
#include <inttypes.h> | ||
|
||
#define IFINDEX_LO 1 | ||
|
||
static __u32 duration; /* Hint: needed for CHECK macro */ | ||
|
||
static int read_mtu_device_lo(void) | ||
{ | ||
const char *filename = "/sys/class/net/lo/mtu"; | ||
char buf[11] = {}; | ||
int value, n, fd; | ||
|
||
fd = open(filename, 0, O_RDONLY); | ||
if (fd == -1) | ||
return -1; | ||
|
||
n = read(fd, buf, sizeof(buf)); | ||
close(fd); | ||
|
||
if (n == -1) | ||
return -2; | ||
|
||
value = strtoimax(buf, NULL, 10); | ||
if (errno == ERANGE) | ||
return -3; | ||
|
||
return value; | ||
} | ||
|
||
static void test_check_mtu_xdp_attach(void) | ||
{ | ||
struct bpf_link_info link_info; | ||
__u32 link_info_len = sizeof(link_info); | ||
struct test_check_mtu *skel; | ||
struct bpf_program *prog; | ||
struct bpf_link *link; | ||
int err = 0; | ||
int fd; | ||
|
||
skel = test_check_mtu__open_and_load(); | ||
if (CHECK(!skel, "open and load skel", "failed")) | ||
return; /* Exit if e.g. helper unknown to kernel */ | ||
|
||
prog = skel->progs.xdp_use_helper_basic; | ||
|
||
link = bpf_program__attach_xdp(prog, IFINDEX_LO); | ||
if (CHECK(IS_ERR(link), "link_attach", "failed: %ld\n", PTR_ERR(link))) | ||
goto out; | ||
skel->links.xdp_use_helper_basic = link; | ||
|
||
memset(&link_info, 0, sizeof(link_info)); | ||
fd = bpf_link__fd(link); | ||
err = bpf_obj_get_info_by_fd(fd, &link_info, &link_info_len); | ||
if (CHECK(err, "link_info", "failed: %d\n", err)) | ||
goto out; | ||
|
||
CHECK(link_info.type != BPF_LINK_TYPE_XDP, "link_type", | ||
"got %u != exp %u\n", link_info.type, BPF_LINK_TYPE_XDP); | ||
CHECK(link_info.xdp.ifindex != IFINDEX_LO, "link_ifindex", | ||
"got %u != exp %u\n", link_info.xdp.ifindex, IFINDEX_LO); | ||
|
||
err = bpf_link__detach(link); | ||
CHECK(err, "link_detach", "failed %d\n", err); | ||
|
||
out: | ||
test_check_mtu__destroy(skel); | ||
} | ||
|
||
static void test_check_mtu_run_xdp(struct test_check_mtu *skel, | ||
struct bpf_program *prog, | ||
__u32 mtu_expect) | ||
{ | ||
const char *prog_name = bpf_program__name(prog); | ||
int retval_expect = XDP_PASS; | ||
__u32 mtu_result = 0; | ||
char buf[256] = {}; | ||
int err; | ||
struct bpf_prog_test_run_attr tattr = { | ||
.repeat = 1, | ||
.data_in = &pkt_v4, | ||
.data_size_in = sizeof(pkt_v4), | ||
.data_out = buf, | ||
.data_size_out = sizeof(buf), | ||
.prog_fd = bpf_program__fd(prog), | ||
}; | ||
|
||
err = bpf_prog_test_run_xattr(&tattr); | ||
CHECK_ATTR(err != 0, "bpf_prog_test_run", | ||
"prog_name:%s (err %d errno %d retval %d)\n", | ||
prog_name, err, errno, tattr.retval); | ||
|
||
CHECK(tattr.retval != retval_expect, "retval", | ||
"progname:%s unexpected retval=%d expected=%d\n", | ||
prog_name, tattr.retval, retval_expect); | ||
|
||
/* Extract MTU that BPF-prog got */ | ||
mtu_result = skel->bss->global_bpf_mtu_xdp; | ||
ASSERT_EQ(mtu_result, mtu_expect, "MTU-compare-user"); | ||
} | ||
|
||
|
||
static void test_check_mtu_xdp(__u32 mtu, __u32 ifindex) | ||
{ | ||
struct test_check_mtu *skel; | ||
int err; | ||
|
||
skel = test_check_mtu__open(); | ||
if (CHECK(!skel, "skel_open", "failed")) | ||
return; | ||
|
||
/* Update "constants" in BPF-prog *BEFORE* libbpf load */ | ||
skel->rodata->GLOBAL_USER_MTU = mtu; | ||
skel->rodata->GLOBAL_USER_IFINDEX = ifindex; | ||
|
||
err = test_check_mtu__load(skel); | ||
if (CHECK(err, "skel_load", "failed: %d\n", err)) | ||
goto cleanup; | ||
|
||
test_check_mtu_run_xdp(skel, skel->progs.xdp_use_helper, mtu); | ||
test_check_mtu_run_xdp(skel, skel->progs.xdp_exceed_mtu, mtu); | ||
test_check_mtu_run_xdp(skel, skel->progs.xdp_minus_delta, mtu); | ||
|
||
cleanup: | ||
test_check_mtu__destroy(skel); | ||
} | ||
|
||
static void test_check_mtu_run_tc(struct test_check_mtu *skel, | ||
struct bpf_program *prog, | ||
__u32 mtu_expect) | ||
{ | ||
const char *prog_name = bpf_program__name(prog); | ||
int retval_expect = BPF_OK; | ||
__u32 mtu_result = 0; | ||
char buf[256] = {}; | ||
int err; | ||
struct bpf_prog_test_run_attr tattr = { | ||
.repeat = 1, | ||
.data_in = &pkt_v4, | ||
.data_size_in = sizeof(pkt_v4), | ||
.data_out = buf, | ||
.data_size_out = sizeof(buf), | ||
.prog_fd = bpf_program__fd(prog), | ||
}; | ||
|
||
err = bpf_prog_test_run_xattr(&tattr); | ||
CHECK_ATTR(err != 0, "bpf_prog_test_run", | ||
"prog_name:%s (err %d errno %d retval %d)\n", | ||
prog_name, err, errno, tattr.retval); | ||
|
||
CHECK(tattr.retval != retval_expect, "retval", | ||
"progname:%s unexpected retval=%d expected=%d\n", | ||
prog_name, tattr.retval, retval_expect); | ||
|
||
/* Extract MTU that BPF-prog got */ | ||
mtu_result = skel->bss->global_bpf_mtu_tc; | ||
ASSERT_EQ(mtu_result, mtu_expect, "MTU-compare-user"); | ||
} | ||
|
||
|
||
static void test_check_mtu_tc(__u32 mtu, __u32 ifindex) | ||
{ | ||
struct test_check_mtu *skel; | ||
int err; | ||
|
||
skel = test_check_mtu__open(); | ||
if (CHECK(!skel, "skel_open", "failed")) | ||
return; | ||
|
||
/* Update "constants" in BPF-prog *BEFORE* libbpf load */ | ||
skel->rodata->GLOBAL_USER_MTU = mtu; | ||
skel->rodata->GLOBAL_USER_IFINDEX = ifindex; | ||
|
||
err = test_check_mtu__load(skel); | ||
if (CHECK(err, "skel_load", "failed: %d\n", err)) | ||
goto cleanup; | ||
|
||
test_check_mtu_run_tc(skel, skel->progs.tc_use_helper, mtu); | ||
test_check_mtu_run_tc(skel, skel->progs.tc_exceed_mtu, mtu); | ||
test_check_mtu_run_tc(skel, skel->progs.tc_exceed_mtu_da, mtu); | ||
test_check_mtu_run_tc(skel, skel->progs.tc_minus_delta, mtu); | ||
cleanup: | ||
test_check_mtu__destroy(skel); | ||
} | ||
|
||
void test_check_mtu(void) | ||
{ | ||
__u32 mtu_lo; | ||
|
||
if (test__start_subtest("bpf_check_mtu XDP-attach")) | ||
test_check_mtu_xdp_attach(); | ||
|
||
mtu_lo = read_mtu_device_lo(); | ||
if (CHECK(mtu_lo < 0, "reading MTU value", "failed (err:%d)", mtu_lo)) | ||
return; | ||
|
||
if (test__start_subtest("bpf_check_mtu XDP-run")) | ||
test_check_mtu_xdp(mtu_lo, 0); | ||
|
||
if (test__start_subtest("bpf_check_mtu XDP-run ifindex-lookup")) | ||
test_check_mtu_xdp(mtu_lo, IFINDEX_LO); | ||
|
||
if (test__start_subtest("bpf_check_mtu TC-run")) | ||
test_check_mtu_tc(mtu_lo, 0); | ||
|
||
if (test__start_subtest("bpf_check_mtu TC-run ifindex-lookup")) | ||
test_check_mtu_tc(mtu_lo, IFINDEX_LO); | ||
} |
Oops, something went wrong.