From nobody Sun Feb 8 14:52:00 2026 Received: from smtpout-02.galae.net (smtpout-02.galae.net [185.246.84.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8E2C32ED141; Fri, 23 Jan 2026 08:30:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.84.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769157033; cv=none; b=QaJW2XR9ikEHd6i+CXyT5D3VoL+xfvJPD7+SZKPNJDs2YboPhxUfynZXY50LZyS67PwDSQb24QPZvh/WmebbOYjhCZdMrEHAFTwF3FylHcTSfQOL4GQCV+MqMB5cTEw6JJBcrroQWWQVeYLV6SBC9HmeHLjtfNR6MSXpCkSJKno= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769157033; c=relaxed/simple; bh=V9yT36JCXEAEUzrKiqDcGsLFxRl2puYXRir6/ZGVpJk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=D23JBBobekt57j2CJrV60q/2QIhXyKDMizP7lRJNKcNo5U6qq9ZRKjw3hbSZDoVHzBL/+f3BjSyd3RvZ0PtEtHea9JXtdSpVv3gW6hbkmOKHDlvWqwXi7alzYIadX4oejPvE08hF6p4a9QPVo7pUzEIO9wsHNvAwD9Yu2nf5auw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=N8/9QoB6; arc=none smtp.client-ip=185.246.84.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="N8/9QoB6" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id C0D241A2AD4; Fri, 23 Jan 2026 08:30:28 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 978726070A; Fri, 23 Jan 2026 08:30:28 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id E1D27119A8793; Fri, 23 Jan 2026 09:30:24 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1769157027; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=p7bg6whDFXQul25qxlc3E8G0uS5es0ZG+5jKN9BYXdM=; b=N8/9QoB6j4rp3oQQh+6gVcT6mMHDNZ250jBUWY5uCRb+hD6jvFJvo9SMg93xaZhBDakO2N oYiuyI8Drusi1y0rF69PVRTbrNoNaJNFpkRiqFWWGNxgMOTSv3mM8Kt8KThAQeN2oIHLyS Vv1oBJ+jM4pRPzwdl9DYg5Ab234PP/gaBz+GdMRged656I2cXiyRmwdRl7tQlaARrP6KOn ZZkh7Rbc99MM+3CRLOQ+50RDXTviFy1VWl606+d5/1r8Q3Gdke6qotSuBcIC6RFOhAUOqV G+j1fkVEcQJu7/ERf9XYlXTP010B6i7dzmeOSrxWUD3Le1yeJVF9yCY5x6XIfA== From: =?utf-8?q?Alexis_Lothor=C3=A9_=28eBPF_Foundation=29?= Date: Fri, 23 Jan 2026 09:30:09 +0100 Subject: [PATCH bpf-next v4 2/3] selftests/bpf: convert test_bpftool_metadata.sh into test_progs framework Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260123-bpftool-tests-v4-2-a6653a7f28e7@bootlin.com> References: <20260123-bpftool-tests-v4-0-a6653a7f28e7@bootlin.com> In-Reply-To: <20260123-bpftool-tests-v4-0-a6653a7f28e7@bootlin.com> To: Andrii Nakryiko , Eduard Zingerman , Alexei Starovoitov , Daniel Borkmann , Martin KaFai Lau , Song Liu , Yonghong Song , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , Shuah Khan , Quentin Monnet Cc: ebpf@linuxfoundation.org, Bastien Curutchet , Thomas Petazzoni , linux-kernel@vger.kernel.org, bpf@vger.kernel.org, linux-kselftest@vger.kernel.org, =?utf-8?q?Alexis_Lothor=C3=A9_=28eBPF_Foundation=29?= X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 The test_bpftool_metadata.sh script validates that bpftool properly returns in its ouptput any metadata generated by bpf programs through some .rodata sections. Port this test to the test_progs framework so that it can be executed automatically in CI. The new test, similarly to the former script, checks that valid data appears both for textual output and json output, as well as for both data not used at all and used data. For the json check part, the expected json string is hardcoded to avoid bringing a new external dependency (eg: a json deserializer) for test_progs. As the test is now converted into test_progs, remove the former script. The newly converted test brings two new subtests: #37/1 bpftool_metadata/metadata_unused:OK #37/2 bpftool_metadata/metadata_used:OK #37 bpftool_metadata:OK Summary: 1/2 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: Alexis Lothor=C3=A9 (eBPF Foundation) --- Changes in v4: - add missing test checking access to the metadata map Changes in v2: - move the new test in prog_tests directory - use power of 2 for bpftool output buffer size - check snprintf return when building commands - target program by pin path rather than prog name - remove a few blank lines --- tools/testing/selftests/bpf/Makefile | 1 - .../selftests/bpf/prog_tests/bpftool_metadata.c | 144 +++++++++++++++++= ++++ .../testing/selftests/bpf/test_bpftool_metadata.sh | 85 ------------ 3 files changed, 144 insertions(+), 86 deletions(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests= /bpf/Makefile index 2cc559ecc723..1bb7db1ed6ea 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -109,7 +109,6 @@ TEST_PROGS :=3D test_kmod.sh \ test_bpftool_build.sh \ test_bpftool.sh \ test_bpftool_map.sh \ - test_bpftool_metadata.sh \ test_doc_build.sh \ test_xsk.sh \ test_xdp_features.sh diff --git a/tools/testing/selftests/bpf/prog_tests/bpftool_metadata.c b/to= ols/testing/selftests/bpf/prog_tests/bpftool_metadata.c new file mode 100644 index 000000000000..408ace90dc7e --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/bpftool_metadata.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include +#include +#include +#include + +#define BPFFS_DIR "/sys/fs/bpf/test_metadata" +#define BPFFS_USED BPFFS_DIR "/used" +#define BPFFS_UNUSED BPFFS_DIR "/unused" + +#define BPF_FILE_USED "metadata_used.bpf.o" +#define BPF_FILE_UNUSED "metadata_unused.bpf.o" +#define METADATA_MAP_NAME "metadata.rodata" + +#define MAX_BPFTOOL_OUTPUT_LEN (64*1024) + +#define MAX_TOKENS_TO_CHECK 3 +static char output[MAX_BPFTOOL_OUTPUT_LEN]; + +struct test_desc { + char *name; + char *bpf_prog; + char *bpffs_path; + char *expected_output[MAX_TOKENS_TO_CHECK]; + char *expected_output_json[MAX_TOKENS_TO_CHECK]; + char *metadata_map_name; +}; + +static int setup(struct test_desc *test) +{ + return mkdir(BPFFS_DIR, 0700); +} + +static void cleanup(struct test_desc *test) +{ + unlink(test->bpffs_path); + rmdir(BPFFS_DIR); +} + +static int check_metadata(char *buf, char * const *tokens, int count) +{ + int i; + + for (i =3D 0; i < count && tokens[i]; i++) + if (!strstr(buf, tokens[i])) + return 1; + + return 0; +} + +static void run_test(struct test_desc *test) +{ + int ret; + char cmd[MAX_BPFTOOL_CMD_LEN]; + + ret =3D snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "prog load %s %s", + test->bpf_prog, test->bpffs_path); + if (!ASSERT_GT(ret, 0, "format prog insert command")) + return; + ret =3D run_bpftool_command(cmd); + if (!ASSERT_OK(ret, "load program")) + return; + + /* Check output with default format */ + ret =3D snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "prog show pinned %s", + test->bpffs_path); + if (!ASSERT_GT(ret, 0, "format pinned prog check command")) + return; + ret =3D get_bpftool_command_output(cmd, output, + MAX_BPFTOOL_OUTPUT_LEN); + if (ASSERT_OK(ret, "get program info")) { + ret =3D check_metadata(output, test->expected_output, + ARRAY_SIZE(test->expected_output)); + ASSERT_OK(ret, "find metadata"); + } + + /* Check output with json format */ + ret =3D snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "prog -j show pinned %s", + test->bpffs_path); + if (!ASSERT_GT(ret, 0, "format pinned prog check command in json")) + return; + ret =3D get_bpftool_command_output(cmd, output, + MAX_BPFTOOL_OUTPUT_LEN); + if (ASSERT_OK(ret, "get program info in json")) { + ret =3D check_metadata(output, test->expected_output_json, + ARRAY_SIZE(test->expected_output_json)); + ASSERT_OK(ret, "find metadata in json"); + } + + /* Check that the corresponding map can be found and accessed */ + ret =3D snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "map show name %s", + test->metadata_map_name); + if (!ASSERT_GT(ret, 0, "format map check command")) + return; + ASSERT_OK(run_bpftool_command(cmd), "access metadata map"); +} + +static struct test_desc tests[] =3D { + { + .name =3D "metadata_unused", + .bpf_prog =3D BPF_FILE_UNUSED, + .bpffs_path =3D BPFFS_UNUSED, + .expected_output =3D { + "a =3D \"foo\"", + "b =3D 1" + }, + .expected_output_json =3D { + "\"metadata\":{\"a\":\"foo\",\"b\":1}" + }, + .metadata_map_name =3D METADATA_MAP_NAME + }, + { + .name =3D "metadata_used", + .bpf_prog =3D BPF_FILE_USED, + .bpffs_path =3D BPFFS_USED, + .expected_output =3D { + "a =3D \"bar\"", + "b =3D 2" + }, + .expected_output_json =3D { + "\"metadata\":{\"a\":\"bar\",\"b\":2}" + }, + .metadata_map_name =3D METADATA_MAP_NAME + } +}; +static const int tests_count =3D ARRAY_SIZE(tests); + +void test_bpftool_metadata(void) +{ + int i; + + for (i =3D 0; i < tests_count; i++) { + if (!test__start_subtest(tests[i].name)) + continue; + if (ASSERT_OK(setup(&tests[i]), "setup bpffs pin dir")) { + run_test(&tests[i]); + cleanup(&tests[i]); + } + } +} diff --git a/tools/testing/selftests/bpf/test_bpftool_metadata.sh b/tools/t= esting/selftests/bpf/test_bpftool_metadata.sh deleted file mode 100755 index b5520692f41b..000000000000 --- a/tools/testing/selftests/bpf/test_bpftool_metadata.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 - -# Kselftest framework requirement - SKIP code is 4. -ksft_skip=3D4 - -BPF_FILE_USED=3D"metadata_used.bpf.o" -BPF_FILE_UNUSED=3D"metadata_unused.bpf.o" - -TESTNAME=3Dbpftool_metadata -BPF_FS=3D$(awk '$3 =3D=3D "bpf" {print $2; exit}' /proc/mounts) -BPF_DIR=3D$BPF_FS/test_$TESTNAME - -_cleanup() -{ - set +e - rm -rf $BPF_DIR 2> /dev/null -} - -cleanup_skip() -{ - echo "selftests: $TESTNAME [SKIP]" - _cleanup - - exit $ksft_skip -} - -cleanup() -{ - if [ "$?" =3D 0 ]; then - echo "selftests: $TESTNAME [PASS]" - else - echo "selftests: $TESTNAME [FAILED]" - fi - _cleanup -} - -if [ $(id -u) -ne 0 ]; then - echo "selftests: $TESTNAME [SKIP] Need root privileges" - exit $ksft_skip -fi - -if [ -z "$BPF_FS" ]; then - echo "selftests: $TESTNAME [SKIP] Could not run test without bpffs mounte= d" - exit $ksft_skip -fi - -if ! bpftool version > /dev/null 2>&1; then - echo "selftests: $TESTNAME [SKIP] Could not run test without bpftool" - exit $ksft_skip -fi - -set -e - -trap cleanup_skip EXIT - -mkdir $BPF_DIR - -trap cleanup EXIT - -bpftool prog load $BPF_FILE_UNUSED $BPF_DIR/unused - -METADATA_PLAIN=3D"$(bpftool prog)" -echo "$METADATA_PLAIN" | grep 'a =3D "foo"' > /dev/null -echo "$METADATA_PLAIN" | grep 'b =3D 1' > /dev/null - -bpftool prog --json | grep '"metadata":{"a":"foo","b":1}' > /dev/null - -bpftool map | grep 'metadata.rodata' > /dev/null - -rm $BPF_DIR/unused - -bpftool prog load $BPF_FILE_USED $BPF_DIR/used - -METADATA_PLAIN=3D"$(bpftool prog)" -echo "$METADATA_PLAIN" | grep 'a =3D "bar"' > /dev/null -echo "$METADATA_PLAIN" | grep 'b =3D 2' > /dev/null - -bpftool prog --json | grep '"metadata":{"a":"bar","b":2}' > /dev/null - -bpftool map | grep 'metadata.rodata' > /dev/null - -rm $BPF_DIR/used - -exit 0 --=20 2.52.0