From: Tianyi Chen <[email protected]>
The hash, array and LPM trie batch validators mark visited entries by
output position, making the subsequent completeness checks always
succeed. Duplicate keys with matching values can therefore hide
missing entries.
Check each returned key against the set populated by the test and
index the visited array by key. This detects missing entries while
preserving unordered results and existing per-CPU value validation.
For LPM trie keys, check the /32 prefix and complete IPv4 address
before using the host octet as the index. Compare the address directly
in host byte order instead of parsing its textual representation.
Fixes: 30ff3c59137d ("selftests/bpf: Add batch ops testing for htab and
htab_percpu map")
Fixes: f0fac2cec286 ("selftests/bpf: Add batch ops testing to array bpf map")
Fixes: e9bd8cbd970b ("bpf: selftests: Add tests for batched ops in LPM trie
maps")
Assisted-by: LLM
Signed-off-by: Tianyi Chen <[email protected]>
---
Changes in v3:
- Rebase onto current bpf/master; the v2 test logic is unchanged.
Validation: test_maps passed in an x86-64 KVM guest running the rebuilt
bpf/master kernel (Linux 7.3.0-rc2), with LLVM 20-built selftests.
The hash, array and LPM batch tests passed; test_maps reported 0 skipped
and returned 0.
The v2 CI PR expired after repeated "Patch is empty" reports without
conflicting hunks. This patch applies cleanly to the current tree and is
sent in a new thread with git format-patch and git send-email.
v2:
https://lore.kernel.org/r/[email protected]
.../bpf/map_tests/array_map_batch_ops.c | 5 ++++-
.../bpf/map_tests/htab_map_batch_ops.c | 4 +++-
.../bpf/map_tests/lpm_trie_map_batch_ops.c | 19 ++++++++++---------
3 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/tools/testing/selftests/bpf/map_tests/array_map_batch_ops.c
b/tools/testing/selftests/bpf/map_tests/array_map_batch_ops.c
index b595556315bc..76d3800a82af 100644
--- a/tools/testing/selftests/bpf/map_tests/array_map_batch_ops.c
+++ b/tools/testing/selftests/bpf/map_tests/array_map_batch_ops.c
@@ -45,6 +45,9 @@ static void map_batch_verify(int *visited, __u32 max_entries,
int *keys,
memset(visited, 0, max_entries * sizeof(*visited));
for (i = 0; i < max_entries; i++) {
+ CHECK(keys[i] < 0 || keys[i] >= max_entries, "key checking",
+ "error: i %d key %d out of range\n", i, keys[i]);
+
if (is_pcpu) {
cpu_offset = i * nr_cpus;
for (j = 0; j < nr_cpus; j++) {
@@ -59,7 +62,7 @@ static void map_batch_verify(int *visited, __u32 max_entries,
int *keys,
"error: i %d key %d value %lld\n", i, keys[i],
values[i]);
}
- visited[i] = 1;
+ visited[keys[i]] = 1;
}
for (i = 0; i < max_entries; i++) {
CHECK(visited[i] != 1, "visited checking",
diff --git a/tools/testing/selftests/bpf/map_tests/htab_map_batch_ops.c
b/tools/testing/selftests/bpf/map_tests/htab_map_batch_ops.c
index 5da493b94ae2..430949f9691d 100644
--- a/tools/testing/selftests/bpf/map_tests/htab_map_batch_ops.c
+++ b/tools/testing/selftests/bpf/map_tests/htab_map_batch_ops.c
@@ -50,6 +50,8 @@ static void map_batch_verify(int *visited, __u32 max_entries,
memset(visited, 0, max_entries * sizeof(*visited));
for (i = 0; i < max_entries; i++) {
+ CHECK(keys[i] < 1 || keys[i] > max_entries, "key checking",
+ "error: i %d key %d out of range\n", i, keys[i]);
if (is_pcpu) {
for (j = 0; j < bpf_num_possible_cpus(); j++) {
@@ -65,7 +67,7 @@ static void map_batch_verify(int *visited, __u32 max_entries,
((int *)values)[i]);
}
- visited[i] = 1;
+ visited[keys[i] - 1] = 1;
}
for (i = 0; i < max_entries; i++) {
diff --git a/tools/testing/selftests/bpf/map_tests/lpm_trie_map_batch_ops.c
b/tools/testing/selftests/bpf/map_tests/lpm_trie_map_batch_ops.c
index fe3e19f96244..3b51670b3cd4 100644
--- a/tools/testing/selftests/bpf/map_tests/lpm_trie_map_batch_ops.c
+++ b/tools/testing/selftests/bpf/map_tests/lpm_trie_map_batch_ops.c
@@ -44,18 +44,19 @@ static void map_batch_update(int map_fd, __u32 max_entries,
static void map_batch_verify(int *visited, __u32 max_entries,
struct test_lpm_key *keys, int *values)
{
- char buff[16] = { 0 };
- int lower_byte = 0;
- __u32 i;
+ __u32 i, ipv4, key;
memset(visited, 0, max_entries * sizeof(*visited));
for (i = 0; i < max_entries; i++) {
- inet_ntop(AF_INET, &keys[i].ipv4, buff, 32);
- CHECK(sscanf(buff, "192.168.1.%d", &lower_byte) == EOF,
- "sscanf()", "error: i %d\n", i);
- CHECK(lower_byte != values[i], "key/value checking",
- "error: i %d key %s value %d\n", i, buff, values[i]);
- visited[i] = 1;
+ ipv4 = ntohl(keys[i].ipv4.s_addr);
+ key = ipv4 & 0xff;
+ /* Expected keys are 192.168.1.1..max_entries with a /32
prefix. */
+ CHECK(keys[i].prefix != 32 || (ipv4 & 0xffffff00) != 0xc0a80100
||
+ key == 0 || key > max_entries, "key checking",
+ "error: i %u prefix %u ipv4 %#x\n", i, keys[i].prefix,
ipv4);
+ CHECK(key != values[i], "key/value checking",
+ "error: i %u key %u value %d\n", i, key, values[i]);
+ visited[key - 1] = 1;
}
for (i = 0; i < max_entries; i++) {
CHECK(visited[i] != 1, "visited checking",
base-commit: 15071f2a1263e82150c77eeb1e94dbfc31950a8e
--
2.55.0