DPDK patches and discussions
 help / color / mirror / Atom feed
From: Konstantin Ananyev <konstantin.ananyev@huawei.com>
To: Stephen Hemminger <stephen@networkplumber.org>,
	"dev@dpdk.org" <dev@dpdk.org>
Cc: Marat Khalili <marat.khalili@huawei.com>
Subject: RE: [PATCH v6 1/2] bpf: add a test for BPF ELF load
Date: Wed, 12 Nov 2025 15:06:31 +0000	[thread overview]
Message-ID: <55beaa9ba60c421a9dce6989432439e6@huawei.com> (raw)
In-Reply-To: <20251111225719.540140-2-stephen@networkplumber.org>



> Create an ELF file to load using clang.
> Repackage the object into an array using xdd.
> Write a test to see load and run the BPF.
> 
> If libelf library is not available, then DPDK bpf
> will return -ENOTSUP to the test and the test will be skipped.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> Acked-by: Marat Khalili <marat.khalili@huawei.com>
> ---
>  app/test/bpf/load.c      |  51 +++++++++++++
>  app/test/bpf/meson.build |  52 +++++++++++++
>  app/test/meson.build     |   2 +
>  app/test/test_bpf.c      | 159 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 264 insertions(+)
>  create mode 100644 app/test/bpf/load.c
>  create mode 100644 app/test/bpf/meson.build
> 
> diff --git a/app/test/bpf/load.c b/app/test/bpf/load.c
> new file mode 100644
> index 0000000000..a4d3d61d7a
> --- /dev/null
> +++ b/app/test/bpf/load.c
> @@ -0,0 +1,51 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + *
> + * BPF program for testing rte_bpf_elf_load
> + */
> +
> +typedef unsigned char uint8_t;
> +typedef unsigned short uint16_t;
> +typedef unsigned int uint32_t;
> +typedef unsigned long uint64_t;
> +
> +/* Match the structures from test_bpf.c */
> +struct dummy_offset {
> +	uint64_t u64;
> +	uint32_t u32;
> +	uint16_t u16;
> +	uint8_t  u8;
> +} __attribute__((packed));
> +
> +struct dummy_vect8 {
> +	struct dummy_offset in[8];
> +	struct dummy_offset out[8];
> +};
> +
> +/* External function declaration - provided by test via xsym */
> +extern void dummy_func1(const void *p, uint32_t *v32, uint64_t *v64);
> +
> +/*
> + * Test BPF function that will be loaded from ELF
> + * This function is compiled version of code used in test_call1
> + */
> +__attribute__((section("call1"), used))
> +uint64_t
> +test_call1(struct dummy_vect8 *arg)
> +{
> +	uint32_t v32;
> +	uint64_t v64;
> +
> +	/* Load input values */
> +	v32 = arg->in[0].u32;
> +	v64 = arg->in[0].u64;
> +
> +	/* Call external function */
> +	dummy_func1(arg, &v32, &v64);
> +
> +	/* Store results */
> +	arg->out[0].u32 = v32;
> +	arg->out[0].u64 = v64;
> +
> +	v64 += v32;
> +	return v64;
> +}
> diff --git a/app/test/bpf/meson.build b/app/test/bpf/meson.build
> new file mode 100644
> index 0000000000..b4f54aa976
> --- /dev/null
> +++ b/app/test/bpf/meson.build
> @@ -0,0 +1,52 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright 2025 Stephen Hemminger <stephen@networkplumber.org>
> +
> +bpf_test_hdrs = [ ]
> +
> +# use clang to compile to bpf
> +clang_supports_bpf = false
> +clang = find_program('clang', required: false)
> +if clang.found()
> +    clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-
> cpus',
> +                                     check: false).returncode() == 0
> +endif
> +
> +if not clang_supports_bpf
> +    message('app/test_bpf: no BPF load tests missing clang BPF support')
> +    subdir_done()
> +
> +endif
> +
> +xxd = find_program('xxd', required: false)
> +if not xxd.found()
> +    message('app/test_bpf: missing xxd required to convert object to array')
> +    subdir_done()
> +endif
> +
> +# BPF compiler flags
> +bpf_cflags = [ '-O2', '-target', 'bpf', '-g', '-c']
> +
> +# Enable test in test_bpf.c
> +cflags += '-DTEST_BPF_ELF_LOAD'
> +
> +# BPF sources to compile
> +bpf_progs = {
> +    'load' : 'test_bpf_load',
> +}
> +
> +foreach bpf_src, bpf_hdr : bpf_progs
> +    # Compile BPF C source to object file
> +    bpf_obj = custom_target(bpf_src + '_o',
> +        input: bpf_src + '.c',
> +        output: bpf_src + '.o',
> +        command: [ clang, bpf_cflags, '@INPUT@', '-o', '@OUTPUT@'])
> +
> +    # Convert object file to C header using xxd
> +    bpf_test_h = custom_target(bpf_src + '_h',
> +        input: bpf_obj,
> +        output: bpf_hdr + '.h',
> +        command: [ xxd, '-i', '@INPUT@', '@OUTPUT@'])
> +
> +    resources += bpf_test_h
> +
> +endforeach
> diff --git a/app/test/meson.build b/app/test/meson.build
> index 8df8d3edd1..efec42a6bf 100644
> --- a/app/test/meson.build
> +++ b/app/test/meson.build
> @@ -281,6 +281,8 @@ if not is_windows
>              install: false)
>  endif
> 
> +subdir('bpf')
> +
>  subdir('test_cfgfiles')
> 
>  resources += test_cfgfile_h
> diff --git a/app/test/test_bpf.c b/app/test/test_bpf.c
> index 90e10d7d2c..c460002358 100644
> --- a/app/test/test_bpf.c
> +++ b/app/test/test_bpf.c
> @@ -6,6 +6,7 @@
>  #include <string.h>
>  #include <stdint.h>
>  #include <inttypes.h>
> +#include <unistd.h>
> 
>  #include <rte_memory.h>
>  #include <rte_debug.h>
> @@ -14,6 +15,7 @@
>  #include <rte_random.h>
>  #include <rte_byteorder.h>
>  #include <rte_errno.h>
> +
>  #include "test.h"
> 
>  #if !defined(RTE_LIB_BPF)
> @@ -3278,6 +3280,163 @@ test_bpf(void)
> 
>  REGISTER_FAST_TEST(bpf_autotest, true, true, test_bpf);
> 
> +#ifdef TEST_BPF_ELF_LOAD
> +
> +/*
> + * Helper function to write BPF object data to temporary file.
> + * Returns temp file path on success, NULL on failure.
> + * Caller must free the returned path and unlink the file.
> + */
> +static char *
> +create_temp_bpf_file(const uint8_t *data, size_t size, const char *name)
> +{
> +	char *tmpfile = NULL;
> +	int fd;
> +	ssize_t written;
> +
> +	if (asprintf(&tmpfile, "/tmp/dpdk_bpf_%s_XXXXXX.o", name) < 0) {
> +		printf("%s@%d: asprintf failed: %s\n",
> +		       __func__, __LINE__, strerror(errno));
> +		return NULL;
> +	}
> +
> +	/* Create and open temp file */
> +	fd = mkstemps(tmpfile, strlen(".o"));
> +	if (fd < 0) {
> +		printf("%s@%d: mkstemps(%s) failed: %s\n",
> +		       __func__, __LINE__, tmpfile, strerror(errno));
> +		free(tmpfile);
> +		return NULL;
> +	}
> +
> +	/* Write BPF object data */
> +	written = write(fd, data, size);
> +	close(fd);
> +
> +	if (written != (ssize_t)size) {
> +		printf("%s@%d: write failed: %s\n",
> +		       __func__, __LINE__, strerror(errno));
> +		unlink(tmpfile);
> +		free(tmpfile);
> +		return NULL;
> +	}
> +
> +	return tmpfile;
> +}
> +
> +#include "test_bpf_load.h"
> +
> +/*
> + * Test loading BPF program from an object file.
> + * This test uses same arguments as previous test_call1 example.
> + */
> +static int
> +test_bpf_elf_load(void)
> +{
> +	static const char test_section[] = "call1";
> +	uint8_t tbuf[sizeof(struct dummy_vect8)];
> +	const struct rte_bpf_xsym xsym[] = {
> +		{
> +			.name = RTE_STR(dummy_func1),
> +			.type = RTE_BPF_XTYPE_FUNC,
> +			.func = {
> +				.val = (void *)dummy_func1,
> +				.nb_args = 3,
> +				.args = {
> +					[0] = {
> +						.type = RTE_BPF_ARG_PTR,
> +						.size = sizeof(struct
> dummy_offset),
> +					},
> +					[1] = {
> +						.type = RTE_BPF_ARG_PTR,
> +						.size = sizeof(uint32_t),
> +					},
> +					[2] = {
> +						.type = RTE_BPF_ARG_PTR,
> +						.size = sizeof(uint64_t),
> +					},
> +				},
> +			},
> +		},
> +	};
> +	int ret;
> +
> +	/* Create temp file from embedded BPF object */
> +	char *tmpfile = create_temp_bpf_file(app_test_bpf_load_o,
> +					     app_test_bpf_load_o_len,
> +					     "load");
> +	if (tmpfile == NULL)
> +		return -1;
> +
> +	/* Try to load BPF program from temp file */
> +	const struct rte_bpf_prm prm = {
> +		.xsym = xsym,
> +		.nb_xsym = RTE_DIM(xsym),
> +		.prog_arg = {
> +			.type = RTE_BPF_ARG_PTR,
> +			.size = sizeof(tbuf),
> +		},
> +	};
> +
> +	struct rte_bpf *bpf = rte_bpf_elf_load(&prm, tmpfile, test_section);
> +	unlink(tmpfile);
> +	free(tmpfile);
> +
> +	/* If libelf support is not available */
> +	if (bpf == NULL && rte_errno == ENOTSUP)
> +		return TEST_SKIPPED;
> +
> +	TEST_ASSERT(bpf != NULL, "failed to load BPF %d:%s", rte_errno,
> strerror(rte_errno));
> +
> +	/* Prepare test data */
> +	struct dummy_vect8 *dv = (struct dummy_vect8 *)tbuf;
> +
> +	memset(dv, 0, sizeof(*dv));
> +	dv->in[0].u64 = (int32_t)TEST_FILL_1;
> +	dv->in[0].u32 = dv->in[0].u64;
> +	dv->in[0].u16 = dv->in[0].u64;
> +	dv->in[0].u8 = dv->in[0].u64;
> +
> +	/* Execute loaded BPF program */
> +	uint64_t rc = rte_bpf_exec(bpf, tbuf);
> +	ret = test_call1_check(rc, tbuf);
> +	TEST_ASSERT(ret == 0, "test_call1_check failed: %d", ret);
> +
> +	/* Test JIT if available */
> +	struct rte_bpf_jit jit;
> +	ret = rte_bpf_get_jit(bpf, &jit);
> +	TEST_ASSERT(ret == 0, "rte_bpf_get_jit failed: %d", ret);
> +
> +	if (jit.func != NULL) {
> +		memset(dv, 0, sizeof(*dv));
> +		dv->in[0].u64 = (int32_t)TEST_FILL_1;
> +		dv->in[0].u32 = dv->in[0].u64;
> +		dv->in[0].u16 = dv->in[0].u64;
> +		dv->in[0].u8 = dv->in[0].u64;
> +
> +		rc = jit.func(tbuf);
> +		ret = test_call1_check(rc, tbuf);
> +		TEST_ASSERT(ret == 0, "jit test_call1_check failed: %d", ret);
> +	}
> +
> +	rte_bpf_destroy(bpf);
> +
> +	printf("%s: ELF load test passed\n", __func__);
> +	return TEST_SUCCESS;
> +}
> +#else
> +
> +static int
> +test_bpf_elf_load(void)
> +{
> +	printf("BPF compile not supported, skipping test\n");
> +	return TEST_SKIPPED;
> +}
> +
> +#endif /* !TEST_BPF_ELF_LOAD */
> +
> +REGISTER_FAST_TEST(bpf_elf_load_autotest, true, true, test_bpf_elf_load);
> +
>  #ifndef RTE_HAS_LIBPCAP
> 
>  static int
> --

Acked-by: Konstantin Ananyev <konstantin.ananyev@huawei.com>
 

> 2.51.0


  reply	other threads:[~2025-11-12 15:06 UTC|newest]

Thread overview: 60+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-30 17:34 [PATCH 0/5] bpf enhancements Stephen Hemminger
2025-10-30 17:34 ` [PATCH 1/5] bpf: add allocation annotations to functions Stephen Hemminger
2025-10-30 17:34 ` [PATCH 2/5] bpf: use rte_pktmbuf_free_bulk Stephen Hemminger
2025-10-30 17:34 ` [PATCH 3/5] bpf: add a test for BPF ELF load Stephen Hemminger
2025-10-30 17:34 ` [PATCH 4/5] bpf: add test for rx and tx filtering Stephen Hemminger
2025-10-30 17:34 ` [PATCH 5/5] bpf: remove use of vla Stephen Hemminger
2025-10-31 11:39 ` [PATCH 0/5] bpf enhancements Marat Khalili
2025-10-31 16:37   ` Stephen Hemminger
2025-10-31 16:41 ` [PATCH v2 0/5] BPF enhancements Stephen Hemminger
2025-10-31 16:41   ` [PATCH v2 1/5] bpf: add allocation annotations to functions Stephen Hemminger
2025-10-31 16:41   ` [PATCH v2 2/5] bpf: use bulk free on filtered packets Stephen Hemminger
2025-10-31 16:41   ` [PATCH v2 3/5] bpf: add a test for BPF ELF load Stephen Hemminger
2025-10-31 16:41   ` [PATCH v2 4/5] bpf: add test for Rx and Tx filtering Stephen Hemminger
2025-10-31 16:41   ` [PATCH v2 5/5] bpf: remove use of VLA Stephen Hemminger
2025-11-01 18:04 ` [PATCH v3 0/5] BPF enhancements Stephen Hemminger
2025-11-01 18:04   ` [PATCH v3 1/5] bpf: add allocation annotations to functions Stephen Hemminger
2025-11-02 21:42     ` Konstantin Ananyev
2025-11-01 18:04   ` [PATCH v3 2/5] bpf: use bulk free on filtered packets Stephen Hemminger
2025-11-01 18:04   ` [PATCH v3 3/5] bpf: add a test for BPF ELF load Stephen Hemminger
2025-11-01 18:04   ` [PATCH v3 4/5] bpf: add test for Rx and Tx filtering Stephen Hemminger
2025-11-01 18:04   ` [PATCH v3 5/5] bpf: remove use of VLA Stephen Hemminger
2025-11-03  9:21     ` Konstantin Ananyev
2025-11-04 16:07 ` [PATCH v4 0/5] BPF enhancements Stephen Hemminger
2025-11-04 16:07   ` [PATCH v4 1/5] bpf: add allocation annotations to functions Stephen Hemminger
2025-11-07 17:35     ` Marat Khalili
2025-11-04 16:07   ` [PATCH v4 2/5] bpf: use bulk free on filtered packets Stephen Hemminger
2025-11-06  7:25     ` Konstantin Ananyev
2025-11-07 17:36     ` Marat Khalili
2025-11-04 16:07   ` [PATCH v4 3/5] bpf: add a test for BPF ELF load Stephen Hemminger
2025-11-07 17:33     ` Marat Khalili
2025-11-07 17:45       ` Marat Khalili
2025-11-08  1:09         ` Stephen Hemminger
2025-11-10 15:34           ` Marat Khalili
2025-11-08  1:08       ` Stephen Hemminger
2025-11-04 16:07   ` [PATCH v4 4/5] bpf: add test for Rx and Tx filtering Stephen Hemminger
2025-11-07 17:30     ` Marat Khalili
2025-11-08  1:11       ` Stephen Hemminger
2025-11-10 15:43         ` Marat Khalili
2025-11-04 16:07   ` [PATCH v4 5/5] bpf: replace use of VLA Stephen Hemminger
2025-11-06  7:26     ` Konstantin Ananyev
2025-11-07 17:36     ` Marat Khalili
2025-11-09 20:07 ` [PATCH v5 0/5] BPF cleanup and tests Stephen Hemminger
2025-11-09 20:07   ` [PATCH v5 1/5] bpf: add allocation annotations to functions Stephen Hemminger
2025-11-09 20:07   ` [PATCH v5 2/5] bpf: use bulk free on filtered packets Stephen Hemminger
2025-11-09 20:07   ` [PATCH v5 3/5] bpf: add a test for BPF ELF load Stephen Hemminger
2025-11-10 16:38     ` Marat Khalili
2025-11-10 17:07       ` Stephen Hemminger
2025-11-10 17:17         ` Marat Khalili
2025-11-10 17:08       ` Stephen Hemminger
2025-11-11  9:46     ` Marat Khalili
2025-11-09 20:07   ` [PATCH v5 4/5] bpf: add test for Rx and Tx filtering Stephen Hemminger
2025-11-11  9:46     ` Marat Khalili
2025-11-09 20:07   ` [PATCH v5 5/5] bpf: replace use of VLA Stephen Hemminger
2025-11-11 12:13   ` [PATCH v5 0/5] BPF cleanup and tests Thomas Monjalon
2025-11-11 22:55   ` [PATCH v6 0/2] BPF tests Stephen Hemminger
2025-11-11 22:55     ` [PATCH v6 1/2] bpf: add a test for BPF ELF load Stephen Hemminger
2025-11-12 15:06       ` Konstantin Ananyev [this message]
2025-11-11 22:55     ` [PATCH v6 2/2] bpf: add test for Rx and Tx filtering Stephen Hemminger
2025-11-12 15:08       ` Konstantin Ananyev
2025-11-12 15:03     ` [PATCH v6 0/2] BPF tests Marat Khalili

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=55beaa9ba60c421a9dce6989432439e6@huawei.com \
    --to=konstantin.ananyev@huawei.com \
    --cc=dev@dpdk.org \
    --cc=marat.khalili@huawei.com \
    --cc=stephen@networkplumber.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).