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