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 8struct hmap_elem { 9 volatile int cnt; 10 struct bpf_spin_lock lock; 11 int test_padding; 12}; 13 14struct { 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 21struct cls_elem { 22 struct bpf_spin_lock lock; 23 volatile int cnt; 24}; 25 26struct { 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 32struct 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 40struct { 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 49SEC("cgroup_skb/ingress") 50int 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 101err: 102 return err; 103} 104 105struct bpf_spin_lock lockA __hidden SEC(".data.A"); 106 107__noinline 108static 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 118static 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 128static 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 137SEC("tc") 138int 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 149SEC("tc") 150int 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 159SEC("tc") 160int 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 169char _license[] SEC("license") = "GPL"; 170