Skip to content

Commit

Permalink
selftests/bpf: add bpf_spin_lock C test
Browse files Browse the repository at this point in the history
add bpf_spin_lock C based test that requires latest llvm with BTF support

Signed-off-by: Alexei Starovoitov <[email protected]>
Signed-off-by: Daniel Borkmann <[email protected]>
  • Loading branch information
Alexei Starovoitov authored and borkmann committed Feb 1, 2019
1 parent b4d4556 commit ab963be
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 2 deletions.
2 changes: 1 addition & 1 deletion tools/testing/selftests/bpf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions tools/testing/selftests/bpf/bpf_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
43 changes: 42 additions & 1 deletion tools/testing/selftests/bpf/test_progs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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;
Expand Down
108 changes: 108 additions & 0 deletions tools/testing/selftests/bpf/test_spin_lock.c
Original file line number Diff line number Diff line change
@@ -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";

0 comments on commit ab963be

Please sign in to comment.