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