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/bpf_helpers.h> 6 #include "bpf_misc.h" 7 8 struct hmap_elem { 9 volatile int cnt; 10 struct bpf_spin_lock lock; 11 int test_padding; 12 }; 13 14 struct { 15 __uint(type, BPF_MAP_TYPE_HASH); 16 __uint(max_entries, 1); 17 __type(key, int); 18 __type(value, struct hmap_elem); 19 } hmap SEC(".maps"); 20 21 struct cls_elem { 22 struct bpf_spin_lock lock; 23 volatile int cnt; 24 }; 25 26 struct { 27 __uint(type, BPF_MAP_TYPE_CGROUP_STORAGE); 28 __type(key, struct bpf_cgroup_storage_key); 29 __type(value, struct cls_elem); 30 } cls_map SEC(".maps"); 31 32 struct bpf_vqueue { 33 struct bpf_spin_lock lock; 34 /* 4 byte hole */ 35 unsigned long long lasttime; 36 int credit; 37 unsigned int rate; 38 }; 39 40 struct { 41 __uint(type, BPF_MAP_TYPE_ARRAY); 42 __uint(max_entries, 1); 43 __type(key, int); 44 __type(value, struct bpf_vqueue); 45 } vqueue SEC(".maps"); 46 47 #define CREDIT_PER_NS(delta, rate) (((delta) * rate) >> 20) 48 49 SEC("cgroup_skb/ingress") 50 int bpf_spin_lock_test(struct __sk_buff *skb) 51 { 52 volatile int credit = 0, max_credit = 100, pkt_len = 64; 53 struct hmap_elem zero = {}, *val; 54 unsigned long long curtime; 55 struct bpf_vqueue *q; 56 struct cls_elem *cls; 57 int key = 0; 58 int err = 0; 59 60 val = bpf_map_lookup_elem(&hmap, &key); 61 if (!val) { 62 bpf_map_update_elem(&hmap, &key, &zero, 0); 63 val = bpf_map_lookup_elem(&hmap, &key); 64 if (!val) { 65 err = 1; 66 goto err; 67 } 68 } 69 /* spin_lock in hash map run time test */ 70 bpf_spin_lock(&val->lock); 71 if (val->cnt) 72 val->cnt--; 73 else 74 val->cnt++; 75 if (val->cnt != 0 && val->cnt != 1) 76 err = 1; 77 bpf_spin_unlock(&val->lock); 78 79 /* spin_lock in array. virtual queue demo */ 80 q = bpf_map_lookup_elem(&vqueue, &key); 81 if (!q) 82 goto err; 83 curtime = bpf_ktime_get_ns(); 84 bpf_spin_lock(&q->lock); 85 q->credit += CREDIT_PER_NS(curtime - q->lasttime, q->rate); 86 q->lasttime = curtime; 87 if (q->credit > max_credit) 88 q->credit = max_credit; 89 q->credit -= pkt_len; 90 credit = q->credit; 91 bpf_spin_unlock(&q->lock); 92 93 __sink(credit); 94 95 /* spin_lock in cgroup local storage */ 96 cls = bpf_get_local_storage(&cls_map, 0); 97 bpf_spin_lock(&cls->lock); 98 cls->cnt++; 99 bpf_spin_unlock(&cls->lock); 100 101 err: 102 return err; 103 } 104 105 struct bpf_spin_lock lockA __hidden SEC(".data.A"); 106 107 __noinline 108 static int static_subprog(struct __sk_buff *ctx) 109 { 110 volatile int ret = 0; 111 112 if (ctx->protocol) 113 return ret; 114 return ret + ctx->len; 115 } 116 117 __noinline 118 static int static_subprog_lock(struct __sk_buff *ctx) 119 { 120 volatile int ret = 0; 121 122 ret = static_subprog(ctx); 123 bpf_spin_lock(&lockA); 124 return ret + ctx->len; 125 } 126 127 __noinline 128 static int static_subprog_unlock(struct __sk_buff *ctx) 129 { 130 volatile int ret = 0; 131 132 ret = static_subprog(ctx); 133 bpf_spin_unlock(&lockA); 134 return ret + ctx->len; 135 } 136 137 SEC("tc") 138 int lock_static_subprog_call(struct __sk_buff *ctx) 139 { 140 int ret = 0; 141 142 bpf_spin_lock(&lockA); 143 if (ctx->mark == 42) 144 ret = static_subprog(ctx); 145 bpf_spin_unlock(&lockA); 146 return ret; 147 } 148 149 SEC("tc") 150 int lock_static_subprog_lock(struct __sk_buff *ctx) 151 { 152 int ret = 0; 153 154 ret = static_subprog_lock(ctx); 155 bpf_spin_unlock(&lockA); 156 return ret; 157 } 158 159 SEC("tc") 160 int lock_static_subprog_unlock(struct __sk_buff *ctx) 161 { 162 int ret = 0; 163 164 bpf_spin_lock(&lockA); 165 ret = static_subprog_unlock(ctx); 166 return ret; 167 } 168 169 char _license[] SEC("license") = "GPL"; 170