-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests/bpf: Add test case for atomic htab update
Add a test case to verify the atomic update of existing element in hash map. The test proceeds in three steps: 1) fill the map with keys in the range [0, 63] 2) create 8 threads to lookup these keys concurrently 3) create 2 threads to overwrite these keys concurrently Without atomic update support, the lookup operation may return -ENOENT error and the test will fail. After the atomic-update change, the lookup operation will always return 0 and the test will succeed. Signed-off-by: Hou Tao <[email protected]>
- Loading branch information
Showing
2 changed files
with
143 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,130 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
#define _GNU_SOURCE | ||
#include <stdbool.h> | ||
#include <test_progs.h> | ||
#include "htab_lookup.skel.h" | ||
|
||
struct htab_op_ctx { | ||
int fd; | ||
int loop; | ||
unsigned int entries; | ||
bool stop; | ||
}; | ||
|
||
static void *htab_lookup_fn(void *arg) | ||
{ | ||
struct htab_op_ctx *ctx = arg; | ||
int i = 0; | ||
|
||
while (i++ < ctx->loop && !ctx->stop) { | ||
unsigned int j; | ||
|
||
for (j = 0; j < ctx->entries; j++) { | ||
unsigned long key = j, value; | ||
int err; | ||
|
||
err = bpf_map_lookup_elem(ctx->fd, &key, &value); | ||
if (err) { | ||
ctx->stop = true; | ||
return (void *)(long)err; | ||
} | ||
} | ||
} | ||
|
||
return NULL; | ||
} | ||
|
||
static void *htab_update_fn(void *arg) | ||
{ | ||
struct htab_op_ctx *ctx = arg; | ||
int i = 0; | ||
|
||
while (i++ < ctx->loop && !ctx->stop) { | ||
unsigned int j; | ||
|
||
for (j = 0; j < ctx->entries; j++) { | ||
unsigned long key = j, value = j; | ||
int err; | ||
|
||
err = bpf_map_update_elem(ctx->fd, &key, &value, BPF_EXIST); | ||
if (err) { | ||
if (err == -ENOMEM) | ||
continue; | ||
ctx->stop = true; | ||
return (void *)(long)err; | ||
} | ||
} | ||
} | ||
|
||
return NULL; | ||
} | ||
|
||
static int setup_htab(int fd, unsigned int entries) | ||
{ | ||
unsigned int i; | ||
|
||
for (i = 0; i < entries; i++) { | ||
unsigned long key = i, value = i; | ||
int err; | ||
|
||
err = bpf_map_update_elem(fd, &key, &value, 0); | ||
if (!ASSERT_OK(err, "init update")) | ||
return -1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
void test_htab_lookup(void) | ||
{ | ||
unsigned int i, wr_nr = 2, rd_nr = 8; | ||
pthread_t tids[wr_nr + rd_nr]; | ||
struct htab_lookup *skel; | ||
struct htab_op_ctx ctx; | ||
int err; | ||
|
||
skel = htab_lookup__open_and_load(); | ||
if (!ASSERT_OK_PTR(skel, "htab_lookup__open_and_load")) | ||
return; | ||
|
||
ctx.fd = bpf_map__fd(skel->maps.htab); | ||
ctx.loop = 50; | ||
ctx.stop = false; | ||
ctx.entries = 64; | ||
|
||
err = setup_htab(ctx.fd, ctx.entries); | ||
if (err) | ||
goto destroy; | ||
|
||
memset(tids, 0, sizeof(tids)); | ||
for (i = 0; i < wr_nr; i++) { | ||
err = pthread_create(&tids[i], NULL, htab_update_fn, &ctx); | ||
if (!ASSERT_OK(err, "pthread_create")) { | ||
ctx.stop = true; | ||
goto reap; | ||
} | ||
} | ||
for (i = 0; i < rd_nr; i++) { | ||
err = pthread_create(&tids[i + wr_nr], NULL, htab_lookup_fn, &ctx); | ||
if (!ASSERT_OK(err, "pthread_create")) { | ||
ctx.stop = true; | ||
goto reap; | ||
} | ||
} | ||
|
||
reap: | ||
for (i = 0; i < wr_nr + rd_nr; i++) { | ||
void *ret = NULL; | ||
char desc[32]; | ||
|
||
if (!tids[i]) | ||
continue; | ||
|
||
snprintf(desc, sizeof(desc), "thread %u", i + 1); | ||
err = pthread_join(tids[i], &ret); | ||
ASSERT_OK(err, desc); | ||
ASSERT_EQ(ret, NULL, desc); | ||
} | ||
destroy: | ||
htab_lookup__destroy(skel); | ||
} |
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,13 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
#include <linux/bpf.h> | ||
#include <bpf/bpf_helpers.h> | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_HASH); | ||
__uint(max_entries, 64); | ||
__type(key, unsigned long); | ||
__type(value, unsigned long); | ||
__uint(map_flags, BPF_F_NO_PREALLOC); | ||
} htab SEC(".maps"); |