mirror of
https://github.com/torvalds/linux.git
synced 2024-11-29 23:51:37 +00:00
selftests/bpf: add bpf_spin_lock C test
add bpf_spin_lock C based test that requires latest llvm with BTF support Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
parent
b4d4556c32
commit
ab963beb9f
@ -35,7 +35,7 @@ BPF_OBJ_FILES = \
|
||||
sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \
|
||||
get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \
|
||||
test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o test_xdp_vlan.o \
|
||||
xdp_dummy.o test_map_in_map.o
|
||||
xdp_dummy.o test_map_in_map.o test_spin_lock.o
|
||||
|
||||
# Objects are built with default compilation flags and with sub-register
|
||||
# code-gen enabled.
|
||||
|
@ -172,6 +172,10 @@ static int (*bpf_skb_vlan_pop)(void *ctx) =
|
||||
(void *) BPF_FUNC_skb_vlan_pop;
|
||||
static int (*bpf_rc_pointer_rel)(void *ctx, int rel_x, int rel_y) =
|
||||
(void *) BPF_FUNC_rc_pointer_rel;
|
||||
static void (*bpf_spin_lock)(struct bpf_spin_lock *lock) =
|
||||
(void *) BPF_FUNC_spin_lock;
|
||||
static void (*bpf_spin_unlock)(struct bpf_spin_lock *lock) =
|
||||
(void *) BPF_FUNC_spin_unlock;
|
||||
|
||||
/* llvm builtin functions that eBPF C program may use to
|
||||
* emit BPF_LD_ABS and BPF_LD_IND instructions
|
||||
|
@ -28,7 +28,7 @@ typedef __u16 __sum16;
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/err.h>
|
||||
#include <bpf/bpf.h>
|
||||
@ -1985,6 +1985,46 @@ static void test_flow_dissector(void)
|
||||
bpf_object__close(obj);
|
||||
}
|
||||
|
||||
static void *test_spin_lock(void *arg)
|
||||
{
|
||||
__u32 duration, retval;
|
||||
int err, prog_fd = *(u32 *) arg;
|
||||
|
||||
err = bpf_prog_test_run(prog_fd, 10000, &pkt_v4, sizeof(pkt_v4),
|
||||
NULL, NULL, &retval, &duration);
|
||||
CHECK(err || retval, "",
|
||||
"err %d errno %d retval %d duration %d\n",
|
||||
err, errno, retval, duration);
|
||||
pthread_exit(arg);
|
||||
}
|
||||
|
||||
static void test_spinlock(void)
|
||||
{
|
||||
const char *file = "./test_spin_lock.o";
|
||||
pthread_t thread_id[4];
|
||||
struct bpf_object *obj;
|
||||
int prog_fd;
|
||||
int err = 0, i;
|
||||
void *ret;
|
||||
|
||||
err = bpf_prog_load(file, BPF_PROG_TYPE_CGROUP_SKB, &obj, &prog_fd);
|
||||
if (err) {
|
||||
printf("test_spin_lock:bpf_prog_load errno %d\n", errno);
|
||||
goto close_prog;
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
assert(pthread_create(&thread_id[i], NULL,
|
||||
&test_spin_lock, &prog_fd) == 0);
|
||||
for (i = 0; i < 4; i++)
|
||||
assert(pthread_join(thread_id[i], &ret) == 0 &&
|
||||
ret == (void *)&prog_fd);
|
||||
goto close_prog_noerr;
|
||||
close_prog:
|
||||
error_cnt++;
|
||||
close_prog_noerr:
|
||||
bpf_object__close(obj);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
srand(time(NULL));
|
||||
@ -2013,6 +2053,7 @@ int main(void)
|
||||
test_queue_stack_map(QUEUE);
|
||||
test_queue_stack_map(STACK);
|
||||
test_flow_dissector();
|
||||
test_spinlock();
|
||||
|
||||
printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt);
|
||||
return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
|
108
tools/testing/selftests/bpf/test_spin_lock.c
Normal file
108
tools/testing/selftests/bpf/test_spin_lock.c
Normal file
@ -0,0 +1,108 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Facebook
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/version.h>
|
||||
#include "bpf_helpers.h"
|
||||
|
||||
struct hmap_elem {
|
||||
volatile int cnt;
|
||||
struct bpf_spin_lock lock;
|
||||
int test_padding;
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") hmap = {
|
||||
.type = BPF_MAP_TYPE_HASH,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(struct hmap_elem),
|
||||
.max_entries = 1,
|
||||
};
|
||||
|
||||
BPF_ANNOTATE_KV_PAIR(hmap, int, struct hmap_elem);
|
||||
|
||||
|
||||
struct cls_elem {
|
||||
struct bpf_spin_lock lock;
|
||||
volatile int cnt;
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") cls_map = {
|
||||
.type = BPF_MAP_TYPE_CGROUP_STORAGE,
|
||||
.key_size = sizeof(struct bpf_cgroup_storage_key),
|
||||
.value_size = sizeof(struct cls_elem),
|
||||
};
|
||||
|
||||
BPF_ANNOTATE_KV_PAIR(cls_map, struct bpf_cgroup_storage_key,
|
||||
struct cls_elem);
|
||||
|
||||
struct bpf_vqueue {
|
||||
struct bpf_spin_lock lock;
|
||||
/* 4 byte hole */
|
||||
unsigned long long lasttime;
|
||||
int credit;
|
||||
unsigned int rate;
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps") vqueue = {
|
||||
.type = BPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(int),
|
||||
.value_size = sizeof(struct bpf_vqueue),
|
||||
.max_entries = 1,
|
||||
};
|
||||
|
||||
BPF_ANNOTATE_KV_PAIR(vqueue, int, struct bpf_vqueue);
|
||||
#define CREDIT_PER_NS(delta, rate) (((delta) * rate) >> 20)
|
||||
|
||||
SEC("spin_lock_demo")
|
||||
int bpf_sping_lock_test(struct __sk_buff *skb)
|
||||
{
|
||||
volatile int credit = 0, max_credit = 100, pkt_len = 64;
|
||||
struct hmap_elem zero = {}, *val;
|
||||
unsigned long long curtime;
|
||||
struct bpf_vqueue *q;
|
||||
struct cls_elem *cls;
|
||||
int key = 0;
|
||||
int err = 0;
|
||||
|
||||
val = bpf_map_lookup_elem(&hmap, &key);
|
||||
if (!val) {
|
||||
bpf_map_update_elem(&hmap, &key, &zero, 0);
|
||||
val = bpf_map_lookup_elem(&hmap, &key);
|
||||
if (!val) {
|
||||
err = 1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
/* spin_lock in hash map run time test */
|
||||
bpf_spin_lock(&val->lock);
|
||||
if (val->cnt)
|
||||
val->cnt--;
|
||||
else
|
||||
val->cnt++;
|
||||
if (val->cnt != 0 && val->cnt != 1)
|
||||
err = 1;
|
||||
bpf_spin_unlock(&val->lock);
|
||||
|
||||
/* spin_lock in array. virtual queue demo */
|
||||
q = bpf_map_lookup_elem(&vqueue, &key);
|
||||
if (!q)
|
||||
goto err;
|
||||
curtime = bpf_ktime_get_ns();
|
||||
bpf_spin_lock(&q->lock);
|
||||
q->credit += CREDIT_PER_NS(curtime - q->lasttime, q->rate);
|
||||
q->lasttime = curtime;
|
||||
if (q->credit > max_credit)
|
||||
q->credit = max_credit;
|
||||
q->credit -= pkt_len;
|
||||
credit = q->credit;
|
||||
bpf_spin_unlock(&q->lock);
|
||||
|
||||
/* spin_lock in cgroup local storage */
|
||||
cls = bpf_get_local_storage(&cls_map, 0);
|
||||
bpf_spin_lock(&cls->lock);
|
||||
cls->cnt++;
|
||||
bpf_spin_unlock(&cls->lock);
|
||||
|
||||
err:
|
||||
return err;
|
||||
}
|
||||
char _license[] SEC("license") = "GPL";
|
Loading…
Reference in New Issue
Block a user