1 /* Copyright (c) 2016 Facebook
2  *
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of version 2 of the GNU General Public
5  * License as published by the Free Software Foundation.
6  */
7 #include "vmlinux.h"
8 #include <errno.h>
9 #include <linux/version.h>
10 #include <bpf/bpf_helpers.h>
11 #include <bpf/bpf_tracing.h>
12 #include <bpf/bpf_core_read.h>
13 
14 #define MAX_ENTRIES 1000
15 #define MAX_NR_CPUS 1024
16 
17 struct {
18 	__uint(type, BPF_MAP_TYPE_HASH);
19 	__type(key, u32);
20 	__type(value, long);
21 	__uint(max_entries, MAX_ENTRIES);
22 } hash_map SEC(".maps");
23 
24 struct {
25 	__uint(type, BPF_MAP_TYPE_LRU_HASH);
26 	__type(key, u32);
27 	__type(value, long);
28 	__uint(max_entries, 10000);
29 } lru_hash_map SEC(".maps");
30 
31 struct {
32 	__uint(type, BPF_MAP_TYPE_LRU_HASH);
33 	__type(key, u32);
34 	__type(value, long);
35 	__uint(max_entries, 10000);
36 	__uint(map_flags, BPF_F_NO_COMMON_LRU);
37 } nocommon_lru_hash_map SEC(".maps");
38 
39 struct inner_lru {
40 	__uint(type, BPF_MAP_TYPE_LRU_HASH);
41 	__type(key, u32);
42 	__type(value, long);
43 	__uint(max_entries, MAX_ENTRIES);
44 	__uint(map_flags, BPF_F_NUMA_NODE);
45 	__uint(numa_node, 0);
46 } inner_lru_hash_map SEC(".maps");
47 
48 struct {
49 	__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
50 	__uint(max_entries, MAX_NR_CPUS);
51 	__uint(key_size, sizeof(u32));
52 	__array(values, struct inner_lru); /* use inner_lru as inner map */
53 } array_of_lru_hashs SEC(".maps") = {
54 	/* statically initialize the first element */
55 	.values = { &inner_lru_hash_map },
56 };
57 
58 struct {
59 	__uint(type, BPF_MAP_TYPE_PERCPU_HASH);
60 	__uint(key_size, sizeof(u32));
61 	__uint(value_size, sizeof(long));
62 	__uint(max_entries, MAX_ENTRIES);
63 } percpu_hash_map SEC(".maps");
64 
65 struct {
66 	__uint(type, BPF_MAP_TYPE_HASH);
67 	__type(key, u32);
68 	__type(value, long);
69 	__uint(max_entries, MAX_ENTRIES);
70 	__uint(map_flags, BPF_F_NO_PREALLOC);
71 } hash_map_alloc SEC(".maps");
72 
73 struct {
74 	__uint(type, BPF_MAP_TYPE_PERCPU_HASH);
75 	__uint(key_size, sizeof(u32));
76 	__uint(value_size, sizeof(long));
77 	__uint(max_entries, MAX_ENTRIES);
78 	__uint(map_flags, BPF_F_NO_PREALLOC);
79 } percpu_hash_map_alloc SEC(".maps");
80 
81 struct {
82 	__uint(type, BPF_MAP_TYPE_LPM_TRIE);
83 	__uint(key_size, 8);
84 	__uint(value_size, sizeof(long));
85 	__uint(max_entries, 10000);
86 	__uint(map_flags, BPF_F_NO_PREALLOC);
87 } lpm_trie_map_alloc SEC(".maps");
88 
89 struct {
90 	__uint(type, BPF_MAP_TYPE_ARRAY);
91 	__type(key, u32);
92 	__type(value, long);
93 	__uint(max_entries, MAX_ENTRIES);
94 } array_map SEC(".maps");
95 
96 struct {
97 	__uint(type, BPF_MAP_TYPE_LRU_HASH);
98 	__type(key, u32);
99 	__type(value, long);
100 	__uint(max_entries, MAX_ENTRIES);
101 } lru_hash_lookup_map SEC(".maps");
102 
103 SEC("ksyscall/getuid")
104 int BPF_KSYSCALL(stress_hmap)
105 {
106 	u32 key = bpf_get_current_pid_tgid();
107 	long init_val = 1;
108 	long *value;
109 	int i;
110 
111 	for (i = 0; i < 10; i++) {
112 		bpf_map_update_elem(&hash_map, &key, &init_val, BPF_ANY);
113 		value = bpf_map_lookup_elem(&hash_map, &key);
114 		if (value)
115 			bpf_map_delete_elem(&hash_map, &key);
116 	}
117 
118 	return 0;
119 }
120 
121 SEC("ksyscall/geteuid")
122 int BPF_KSYSCALL(stress_percpu_hmap)
123 {
124 	u32 key = bpf_get_current_pid_tgid();
125 	long init_val = 1;
126 	long *value;
127 	int i;
128 
129 	for (i = 0; i < 10; i++) {
130 		bpf_map_update_elem(&percpu_hash_map, &key, &init_val, BPF_ANY);
131 		value = bpf_map_lookup_elem(&percpu_hash_map, &key);
132 		if (value)
133 			bpf_map_delete_elem(&percpu_hash_map, &key);
134 	}
135 	return 0;
136 }
137 
138 SEC("ksyscall/getgid")
139 int BPF_KSYSCALL(stress_hmap_alloc)
140 {
141 	u32 key = bpf_get_current_pid_tgid();
142 	long init_val = 1;
143 	long *value;
144 	int i;
145 
146 	for (i = 0; i < 10; i++) {
147 		bpf_map_update_elem(&hash_map_alloc, &key, &init_val, BPF_ANY);
148 		value = bpf_map_lookup_elem(&hash_map_alloc, &key);
149 		if (value)
150 			bpf_map_delete_elem(&hash_map_alloc, &key);
151 	}
152 	return 0;
153 }
154 
155 SEC("ksyscall/getegid")
156 int BPF_KSYSCALL(stress_percpu_hmap_alloc)
157 {
158 	u32 key = bpf_get_current_pid_tgid();
159 	long init_val = 1;
160 	long *value;
161 	int i;
162 
163 	for (i = 0; i < 10; i++) {
164 		bpf_map_update_elem(&percpu_hash_map_alloc, &key, &init_val, BPF_ANY);
165 		value = bpf_map_lookup_elem(&percpu_hash_map_alloc, &key);
166 		if (value)
167 			bpf_map_delete_elem(&percpu_hash_map_alloc, &key);
168 	}
169 	return 0;
170 }
171 SEC("ksyscall/connect")
172 int BPF_KSYSCALL(stress_lru_hmap_alloc, int fd, struct sockaddr_in *uservaddr,
173 		 int addrlen)
174 {
175 	char fmt[] = "Failed at stress_lru_hmap_alloc. ret:%dn";
176 	union {
177 		u16 dst6[8];
178 		struct {
179 			u16 magic0;
180 			u16 magic1;
181 			u16 tcase;
182 			u16 unused16;
183 			u32 unused32;
184 			u32 key;
185 		};
186 	} test_params;
187 	struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)uservaddr;
188 	u16 test_case;
189 	long val = 1;
190 	u32 key = 0;
191 	int ret;
192 
193 	if (addrlen != sizeof(*in6))
194 		return 0;
195 
196 	ret = bpf_probe_read_user(test_params.dst6, sizeof(test_params.dst6),
197 				  &in6->sin6_addr);
198 	if (ret)
199 		goto done;
200 
201 	if (test_params.magic0 != 0xdead ||
202 	    test_params.magic1 != 0xbeef)
203 		return 0;
204 
205 	test_case = test_params.tcase;
206 	if (test_case != 3)
207 		key = bpf_get_prandom_u32();
208 
209 	if (test_case == 0) {
210 		ret = bpf_map_update_elem(&lru_hash_map, &key, &val, BPF_ANY);
211 	} else if (test_case == 1) {
212 		ret = bpf_map_update_elem(&nocommon_lru_hash_map, &key, &val,
213 					  BPF_ANY);
214 	} else if (test_case == 2) {
215 		void *nolocal_lru_map;
216 		int cpu = bpf_get_smp_processor_id();
217 
218 		nolocal_lru_map = bpf_map_lookup_elem(&array_of_lru_hashs,
219 						      &cpu);
220 		if (!nolocal_lru_map) {
221 			ret = -ENOENT;
222 			goto done;
223 		}
224 
225 		ret = bpf_map_update_elem(nolocal_lru_map, &key, &val,
226 					  BPF_ANY);
227 	} else if (test_case == 3) {
228 		u32 i;
229 
230 		key = test_params.key;
231 
232 #pragma clang loop unroll(full)
233 		for (i = 0; i < 32; i++) {
234 			bpf_map_lookup_elem(&lru_hash_lookup_map, &key);
235 			key++;
236 		}
237 	} else {
238 		ret = -EINVAL;
239 	}
240 
241 done:
242 	if (ret)
243 		bpf_trace_printk(fmt, sizeof(fmt), ret);
244 
245 	return 0;
246 }
247 
248 SEC("ksyscall/gettid")
249 int BPF_KSYSCALL(stress_lpm_trie_map_alloc)
250 {
251 	union {
252 		u32 b32[2];
253 		u8 b8[8];
254 	} key;
255 	unsigned int i;
256 
257 	key.b32[0] = 32;
258 	key.b8[4] = 192;
259 	key.b8[5] = 168;
260 	key.b8[6] = 0;
261 	key.b8[7] = 1;
262 
263 #pragma clang loop unroll(full)
264 	for (i = 0; i < 32; ++i)
265 		bpf_map_lookup_elem(&lpm_trie_map_alloc, &key);
266 
267 	return 0;
268 }
269 
270 SEC("ksyscall/getpgid")
271 int BPF_KSYSCALL(stress_hash_map_lookup)
272 {
273 	u32 key = 1, i;
274 	long *value;
275 
276 #pragma clang loop unroll(full)
277 	for (i = 0; i < 64; ++i)
278 		value = bpf_map_lookup_elem(&hash_map, &key);
279 
280 	return 0;
281 }
282 
283 SEC("ksyscall/getppid")
284 int BPF_KSYSCALL(stress_array_map_lookup)
285 {
286 	u32 key = 1, i;
287 	long *value;
288 
289 #pragma clang loop unroll(full)
290 	for (i = 0; i < 64; ++i)
291 		value = bpf_map_lookup_elem(&array_map, &key);
292 
293 	return 0;
294 }
295 
296 char _license[] SEC("license") = "GPL";
297 u32 _version SEC("version") = LINUX_VERSION_CODE;
298