Skip to content

Commit 8df839a

Browse files
Alexei Starovoitovanakryiko
authored andcommitted
selftests/bpf: Add bpf_arena_htab test.
bpf_arena_htab.h - hash table implemented as bpf program Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 9f2c156 commit 8df839a

File tree

6 files changed

+243
-0
lines changed

6 files changed

+243
-0
lines changed

tools/testing/selftests/bpf/DENYLIST.aarch64

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ fill_link_info/kretprobe_multi_link_info # bpf_program__attach_kprobe_mu
1111
fill_link_info/kprobe_multi_invalid_ubuff # bpf_program__attach_kprobe_multi_opts unexpected error: -95
1212
missed/kprobe_recursion # missed_kprobe_recursion__attach unexpected error: -95 (errno 95)
1313
verifier_arena # JIT does not support arena
14+
arena_htab # JIT does not support arena

tools/testing/selftests/bpf/DENYLIST.s390x

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ get_stack_raw_tp # user_stack corrupted user stack
55
stacktrace_build_id # compare_map_keys stackid_hmap vs. stackmap err -2 errno 2 (?)
66
verifier_iterating_callbacks
77
verifier_arena # JIT does not support arena
8+
arena_htab # JIT does not support arena
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
2+
/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
3+
#pragma once
4+
#include <errno.h>
5+
#include "bpf_arena_alloc.h"
6+
#include "bpf_arena_list.h"
7+
8+
struct htab_bucket {
9+
struct arena_list_head head;
10+
};
11+
typedef struct htab_bucket __arena htab_bucket_t;
12+
13+
struct htab {
14+
htab_bucket_t *buckets;
15+
int n_buckets;
16+
};
17+
typedef struct htab __arena htab_t;
18+
19+
static inline htab_bucket_t *__select_bucket(htab_t *htab, __u32 hash)
20+
{
21+
htab_bucket_t *b = htab->buckets;
22+
23+
cast_kern(b);
24+
return &b[hash & (htab->n_buckets - 1)];
25+
}
26+
27+
static inline arena_list_head_t *select_bucket(htab_t *htab, __u32 hash)
28+
{
29+
return &__select_bucket(htab, hash)->head;
30+
}
31+
32+
struct hashtab_elem {
33+
int hash;
34+
int key;
35+
int value;
36+
struct arena_list_node hash_node;
37+
};
38+
typedef struct hashtab_elem __arena hashtab_elem_t;
39+
40+
static hashtab_elem_t *lookup_elem_raw(arena_list_head_t *head, __u32 hash, int key)
41+
{
42+
hashtab_elem_t *l;
43+
44+
list_for_each_entry(l, head, hash_node)
45+
if (l->hash == hash && l->key == key)
46+
return l;
47+
48+
return NULL;
49+
}
50+
51+
static int htab_hash(int key)
52+
{
53+
return key;
54+
}
55+
56+
__weak int htab_lookup_elem(htab_t *htab __arg_arena, int key)
57+
{
58+
hashtab_elem_t *l_old;
59+
arena_list_head_t *head;
60+
61+
cast_kern(htab);
62+
head = select_bucket(htab, key);
63+
l_old = lookup_elem_raw(head, htab_hash(key), key);
64+
if (l_old)
65+
return l_old->value;
66+
return 0;
67+
}
68+
69+
__weak int htab_update_elem(htab_t *htab __arg_arena, int key, int value)
70+
{
71+
hashtab_elem_t *l_new = NULL, *l_old;
72+
arena_list_head_t *head;
73+
74+
cast_kern(htab);
75+
head = select_bucket(htab, key);
76+
l_old = lookup_elem_raw(head, htab_hash(key), key);
77+
78+
l_new = bpf_alloc(sizeof(*l_new));
79+
if (!l_new)
80+
return -ENOMEM;
81+
l_new->key = key;
82+
l_new->hash = htab_hash(key);
83+
l_new->value = value;
84+
85+
list_add_head(&l_new->hash_node, head);
86+
if (l_old) {
87+
list_del(&l_old->hash_node);
88+
bpf_free(l_old);
89+
}
90+
return 0;
91+
}
92+
93+
void htab_init(htab_t *htab)
94+
{
95+
void __arena *buckets = bpf_arena_alloc_pages(&arena, NULL, 2, NUMA_NO_NODE, 0);
96+
97+
cast_user(buckets);
98+
htab->buckets = buckets;
99+
htab->n_buckets = 2 * PAGE_SIZE / sizeof(struct htab_bucket);
100+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
3+
#include <test_progs.h>
4+
#include <sys/mman.h>
5+
#include <network_helpers.h>
6+
7+
#include "arena_htab_asm.skel.h"
8+
#include "arena_htab.skel.h"
9+
10+
#define PAGE_SIZE 4096
11+
12+
#include "bpf_arena_htab.h"
13+
14+
static void test_arena_htab_common(struct htab *htab)
15+
{
16+
int i;
17+
18+
printf("htab %p buckets %p n_buckets %d\n", htab, htab->buckets, htab->n_buckets);
19+
ASSERT_OK_PTR(htab->buckets, "htab->buckets shouldn't be NULL");
20+
for (i = 0; htab->buckets && i < 16; i += 4) {
21+
/*
22+
* Walk htab buckets and link lists since all pointers are correct,
23+
* though they were written by bpf program.
24+
*/
25+
int val = htab_lookup_elem(htab, i);
26+
27+
ASSERT_EQ(i, val, "key == value");
28+
}
29+
}
30+
31+
static void test_arena_htab_llvm(void)
32+
{
33+
LIBBPF_OPTS(bpf_test_run_opts, opts);
34+
struct arena_htab *skel;
35+
struct htab *htab;
36+
size_t arena_sz;
37+
void *area;
38+
int ret;
39+
40+
skel = arena_htab__open_and_load();
41+
if (!ASSERT_OK_PTR(skel, "arena_htab__open_and_load"))
42+
return;
43+
44+
area = bpf_map__initial_value(skel->maps.arena, &arena_sz);
45+
/* fault-in a page with pgoff == 0 as sanity check */
46+
*(volatile int *)area = 0x55aa;
47+
48+
/* bpf prog will allocate more pages */
49+
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.arena_htab_llvm), &opts);
50+
ASSERT_OK(ret, "ret");
51+
ASSERT_OK(opts.retval, "retval");
52+
if (skel->bss->skip) {
53+
printf("%s:SKIP:compiler doesn't support arena_cast\n", __func__);
54+
test__skip();
55+
goto out;
56+
}
57+
htab = skel->bss->htab_for_user;
58+
test_arena_htab_common(htab);
59+
out:
60+
arena_htab__destroy(skel);
61+
}
62+
63+
static void test_arena_htab_asm(void)
64+
{
65+
LIBBPF_OPTS(bpf_test_run_opts, opts);
66+
struct arena_htab_asm *skel;
67+
struct htab *htab;
68+
int ret;
69+
70+
skel = arena_htab_asm__open_and_load();
71+
if (!ASSERT_OK_PTR(skel, "arena_htab_asm__open_and_load"))
72+
return;
73+
74+
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.arena_htab_asm), &opts);
75+
ASSERT_OK(ret, "ret");
76+
ASSERT_OK(opts.retval, "retval");
77+
htab = skel->bss->htab_for_user;
78+
test_arena_htab_common(htab);
79+
arena_htab_asm__destroy(skel);
80+
}
81+
82+
void test_arena_htab(void)
83+
{
84+
if (test__start_subtest("arena_htab_llvm"))
85+
test_arena_htab_llvm();
86+
if (test__start_subtest("arena_htab_asm"))
87+
test_arena_htab_asm();
88+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
3+
#include <vmlinux.h>
4+
#include <bpf/bpf_helpers.h>
5+
#include <bpf/bpf_tracing.h>
6+
#include <bpf/bpf_core_read.h>
7+
#include "bpf_experimental.h"
8+
9+
struct {
10+
__uint(type, BPF_MAP_TYPE_ARENA);
11+
__uint(map_flags, BPF_F_MMAPABLE);
12+
__uint(max_entries, 100); /* number of pages */
13+
} arena SEC(".maps");
14+
15+
#include "bpf_arena_htab.h"
16+
17+
void __arena *htab_for_user;
18+
bool skip = false;
19+
20+
int zero = 0;
21+
22+
SEC("syscall")
23+
int arena_htab_llvm(void *ctx)
24+
{
25+
#if defined(__BPF_FEATURE_ARENA_CAST) || defined(BPF_ARENA_FORCE_ASM)
26+
struct htab __arena *htab;
27+
__u64 i;
28+
29+
htab = bpf_alloc(sizeof(*htab));
30+
cast_kern(htab);
31+
htab_init(htab);
32+
33+
/* first run. No old elems in the table */
34+
for (i = zero; i < 1000; i++)
35+
htab_update_elem(htab, i, i);
36+
37+
/* should replace all elems with new ones */
38+
for (i = zero; i < 1000; i++)
39+
htab_update_elem(htab, i, i);
40+
cast_user(htab);
41+
htab_for_user = htab;
42+
#else
43+
skip = true;
44+
#endif
45+
return 0;
46+
}
47+
48+
char _license[] SEC("license") = "GPL";
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
3+
#define BPF_ARENA_FORCE_ASM
4+
#define arena_htab_llvm arena_htab_asm
5+
#include "arena_htab.c"

0 commit comments

Comments
 (0)