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