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