xref: /linux/tools/testing/selftests/bpf/progs/test_spin_lock.c (revision f6d08d9d8543c8ee494b307804b28e2750ffedb9)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2019 Facebook
3 #include <linux/bpf.h>
4 #include <linux/version.h>
5 #include "bpf_helpers.h"
6 
7 struct hmap_elem {
8 	volatile int cnt;
9 	struct bpf_spin_lock lock;
10 	int test_padding;
11 };
12 
13 struct {
14 	__u32 type;
15 	__u32 max_entries;
16 	int *key;
17 	struct hmap_elem *value;
18 } hmap SEC(".maps") = {
19 	.type = BPF_MAP_TYPE_HASH,
20 	.max_entries = 1,
21 };
22 
23 struct cls_elem {
24 	struct bpf_spin_lock lock;
25 	volatile int cnt;
26 };
27 
28 struct {
29 	__u32 type;
30 	struct bpf_cgroup_storage_key *key;
31 	struct cls_elem *value;
32 } cls_map SEC(".maps") = {
33 	.type = BPF_MAP_TYPE_CGROUP_STORAGE,
34 };
35 
36 struct bpf_vqueue {
37 	struct bpf_spin_lock lock;
38 	/* 4 byte hole */
39 	unsigned long long lasttime;
40 	int credit;
41 	unsigned int rate;
42 };
43 
44 struct {
45 	__u32 type;
46 	__u32 max_entries;
47 	int *key;
48 	struct bpf_vqueue *value;
49 } vqueue SEC(".maps") = {
50 	.type = BPF_MAP_TYPE_ARRAY,
51 	.max_entries = 1,
52 };
53 
54 #define CREDIT_PER_NS(delta, rate) (((delta) * rate) >> 20)
55 
56 SEC("spin_lock_demo")
57 int bpf_sping_lock_test(struct __sk_buff *skb)
58 {
59 	volatile int credit = 0, max_credit = 100, pkt_len = 64;
60 	struct hmap_elem zero = {}, *val;
61 	unsigned long long curtime;
62 	struct bpf_vqueue *q;
63 	struct cls_elem *cls;
64 	int key = 0;
65 	int err = 0;
66 
67 	val = bpf_map_lookup_elem(&hmap, &key);
68 	if (!val) {
69 		bpf_map_update_elem(&hmap, &key, &zero, 0);
70 		val = bpf_map_lookup_elem(&hmap, &key);
71 		if (!val) {
72 			err = 1;
73 			goto err;
74 		}
75 	}
76 	/* spin_lock in hash map run time test */
77 	bpf_spin_lock(&val->lock);
78 	if (val->cnt)
79 		val->cnt--;
80 	else
81 		val->cnt++;
82 	if (val->cnt != 0 && val->cnt != 1)
83 		err = 1;
84 	bpf_spin_unlock(&val->lock);
85 
86 	/* spin_lock in array. virtual queue demo */
87 	q = bpf_map_lookup_elem(&vqueue, &key);
88 	if (!q)
89 		goto err;
90 	curtime = bpf_ktime_get_ns();
91 	bpf_spin_lock(&q->lock);
92 	q->credit += CREDIT_PER_NS(curtime - q->lasttime, q->rate);
93 	q->lasttime = curtime;
94 	if (q->credit > max_credit)
95 		q->credit = max_credit;
96 	q->credit -= pkt_len;
97 	credit = q->credit;
98 	bpf_spin_unlock(&q->lock);
99 
100 	/* spin_lock in cgroup local storage */
101 	cls = bpf_get_local_storage(&cls_map, 0);
102 	bpf_spin_lock(&cls->lock);
103 	cls->cnt++;
104 	bpf_spin_unlock(&cls->lock);
105 
106 err:
107 	return err;
108 }
109 char _license[] SEC("license") = "GPL";
110