1 | #include "bpf_experimental.h" |
2 | |
3 | struct val_t { |
4 | long b, c, d; |
5 | }; |
6 | |
7 | struct elem { |
8 | long sum; |
9 | struct val_t __percpu_kptr *pc; |
10 | }; |
11 | |
12 | struct { |
13 | __uint(type, BPF_MAP_TYPE_ARRAY); |
14 | __uint(max_entries, 1); |
15 | __type(key, int); |
16 | __type(value, struct elem); |
17 | } array SEC(".maps" ); |
18 | |
19 | void bpf_rcu_read_lock(void) __ksym; |
20 | void bpf_rcu_read_unlock(void) __ksym; |
21 | |
22 | const volatile int nr_cpus; |
23 | |
24 | /* Initialize the percpu object */ |
25 | SEC("?fentry/bpf_fentry_test1" ) |
26 | int BPF_PROG(test_array_map_1) |
27 | { |
28 | struct val_t __percpu_kptr *p; |
29 | struct elem *e; |
30 | int index = 0; |
31 | |
32 | e = bpf_map_lookup_elem(&array, &index); |
33 | if (!e) |
34 | return 0; |
35 | |
36 | p = bpf_percpu_obj_new(struct val_t); |
37 | if (!p) |
38 | return 0; |
39 | |
40 | p = bpf_kptr_xchg(&e->pc, p); |
41 | if (p) |
42 | bpf_percpu_obj_drop(p); |
43 | |
44 | return 0; |
45 | } |
46 | |
47 | /* Update percpu data */ |
48 | SEC("?fentry/bpf_fentry_test2" ) |
49 | int BPF_PROG(test_array_map_2) |
50 | { |
51 | struct val_t __percpu_kptr *p; |
52 | struct val_t *v; |
53 | struct elem *e; |
54 | int index = 0; |
55 | |
56 | e = bpf_map_lookup_elem(&array, &index); |
57 | if (!e) |
58 | return 0; |
59 | |
60 | p = e->pc; |
61 | if (!p) |
62 | return 0; |
63 | |
64 | v = bpf_per_cpu_ptr(p, 0); |
65 | if (!v) |
66 | return 0; |
67 | v->c = 1; |
68 | v->d = 2; |
69 | |
70 | return 0; |
71 | } |
72 | |
73 | int cpu0_field_d, sum_field_c; |
74 | int my_pid; |
75 | |
76 | /* Summarize percpu data */ |
77 | SEC("?fentry/bpf_fentry_test3" ) |
78 | int BPF_PROG(test_array_map_3) |
79 | { |
80 | struct val_t __percpu_kptr *p; |
81 | int i, index = 0; |
82 | struct val_t *v; |
83 | struct elem *e; |
84 | |
85 | if ((bpf_get_current_pid_tgid() >> 32) != my_pid) |
86 | return 0; |
87 | |
88 | e = bpf_map_lookup_elem(&array, &index); |
89 | if (!e) |
90 | return 0; |
91 | |
92 | p = e->pc; |
93 | if (!p) |
94 | return 0; |
95 | |
96 | bpf_for(i, 0, nr_cpus) { |
97 | v = bpf_per_cpu_ptr(p, i); |
98 | if (v) { |
99 | if (i == 0) |
100 | cpu0_field_d = v->d; |
101 | sum_field_c += v->c; |
102 | } |
103 | } |
104 | |
105 | return 0; |
106 | } |
107 | |
108 | /* Explicitly free allocated percpu data */ |
109 | SEC("?fentry/bpf_fentry_test4" ) |
110 | int BPF_PROG(test_array_map_4) |
111 | { |
112 | struct val_t __percpu_kptr *p; |
113 | struct elem *e; |
114 | int index = 0; |
115 | |
116 | e = bpf_map_lookup_elem(&array, &index); |
117 | if (!e) |
118 | return 0; |
119 | |
120 | /* delete */ |
121 | p = bpf_kptr_xchg(&e->pc, NULL); |
122 | if (p) { |
123 | bpf_percpu_obj_drop(p); |
124 | } |
125 | |
126 | return 0; |
127 | } |
128 | |
129 | SEC("?fentry.s/bpf_fentry_test1" ) |
130 | int BPF_PROG(test_array_map_10) |
131 | { |
132 | struct val_t __percpu_kptr *p, *p1; |
133 | int i, index = 0; |
134 | struct val_t *v; |
135 | struct elem *e; |
136 | |
137 | if ((bpf_get_current_pid_tgid() >> 32) != my_pid) |
138 | return 0; |
139 | |
140 | e = bpf_map_lookup_elem(&array, &index); |
141 | if (!e) |
142 | return 0; |
143 | |
144 | bpf_rcu_read_lock(); |
145 | p = e->pc; |
146 | if (!p) { |
147 | p = bpf_percpu_obj_new(struct val_t); |
148 | if (!p) |
149 | goto out; |
150 | |
151 | p1 = bpf_kptr_xchg(&e->pc, p); |
152 | if (p1) { |
153 | /* race condition */ |
154 | bpf_percpu_obj_drop(p1); |
155 | } |
156 | } |
157 | |
158 | v = bpf_this_cpu_ptr(p); |
159 | v->c = 3; |
160 | v = bpf_this_cpu_ptr(p); |
161 | v->c = 0; |
162 | |
163 | v = bpf_per_cpu_ptr(p, 0); |
164 | if (!v) |
165 | goto out; |
166 | v->c = 1; |
167 | v->d = 2; |
168 | |
169 | /* delete */ |
170 | p1 = bpf_kptr_xchg(&e->pc, NULL); |
171 | if (!p1) |
172 | goto out; |
173 | |
174 | bpf_for(i, 0, nr_cpus) { |
175 | v = bpf_per_cpu_ptr(p, i); |
176 | if (v) { |
177 | if (i == 0) |
178 | cpu0_field_d = v->d; |
179 | sum_field_c += v->c; |
180 | } |
181 | } |
182 | |
183 | /* finally release p */ |
184 | bpf_percpu_obj_drop(p1); |
185 | out: |
186 | bpf_rcu_read_unlock(); |
187 | return 0; |
188 | } |
189 | |
190 | char _license[] SEC("license" ) = "GPL" ; |
191 | |