xref: /linux/tools/testing/selftests/bpf/test_progs.c (revision e58e871becec2d3b04ed91c0c16fe8deac9c9dfa)
1 /* Copyright (c) 2017 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 <stdio.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <assert.h>
12 #include <stdlib.h>
13 
14 #include <linux/types.h>
15 typedef __u16 __sum16;
16 #include <arpa/inet.h>
17 #include <linux/if_ether.h>
18 #include <linux/if_packet.h>
19 #include <linux/ip.h>
20 #include <linux/ipv6.h>
21 #include <linux/tcp.h>
22 
23 #include <sys/wait.h>
24 #include <sys/resource.h>
25 
26 #include <linux/bpf.h>
27 #include <linux/err.h>
28 #include <bpf/bpf.h>
29 #include <bpf/libbpf.h>
30 #include "test_iptunnel_common.h"
31 #include "bpf_util.h"
32 #include "bpf_endian.h"
33 
34 static int error_cnt, pass_cnt;
35 
36 #define MAGIC_BYTES 123
37 
38 /* ipv4 test vector */
39 static struct {
40 	struct ethhdr eth;
41 	struct iphdr iph;
42 	struct tcphdr tcp;
43 } __packed pkt_v4 = {
44 	.eth.h_proto = bpf_htons(ETH_P_IP),
45 	.iph.ihl = 5,
46 	.iph.protocol = 6,
47 	.iph.tot_len = bpf_htons(MAGIC_BYTES),
48 	.tcp.urg_ptr = 123,
49 };
50 
51 /* ipv6 test vector */
52 static struct {
53 	struct ethhdr eth;
54 	struct ipv6hdr iph;
55 	struct tcphdr tcp;
56 } __packed pkt_v6 = {
57 	.eth.h_proto = bpf_htons(ETH_P_IPV6),
58 	.iph.nexthdr = 6,
59 	.iph.payload_len = bpf_htons(MAGIC_BYTES),
60 	.tcp.urg_ptr = 123,
61 };
62 
63 #define CHECK(condition, tag, format...) ({				\
64 	int __ret = !!(condition);					\
65 	if (__ret) {							\
66 		error_cnt++;						\
67 		printf("%s:FAIL:%s ", __func__, tag);			\
68 		printf(format);						\
69 	} else {							\
70 		pass_cnt++;						\
71 		printf("%s:PASS:%s %d nsec\n", __func__, tag, duration);\
72 	}								\
73 })
74 
75 static int bpf_prog_load(const char *file, enum bpf_prog_type type,
76 			 struct bpf_object **pobj, int *prog_fd)
77 {
78 	struct bpf_program *prog;
79 	struct bpf_object *obj;
80 	int err;
81 
82 	obj = bpf_object__open(file);
83 	if (IS_ERR(obj)) {
84 		error_cnt++;
85 		return -ENOENT;
86 	}
87 
88 	prog = bpf_program__next(NULL, obj);
89 	if (!prog) {
90 		bpf_object__close(obj);
91 		error_cnt++;
92 		return -ENOENT;
93 	}
94 
95 	bpf_program__set_type(prog, type);
96 	err = bpf_object__load(obj);
97 	if (err) {
98 		bpf_object__close(obj);
99 		error_cnt++;
100 		return -EINVAL;
101 	}
102 
103 	*pobj = obj;
104 	*prog_fd = bpf_program__fd(prog);
105 	return 0;
106 }
107 
108 static int bpf_find_map(const char *test, struct bpf_object *obj,
109 			const char *name)
110 {
111 	struct bpf_map *map;
112 
113 	map = bpf_object__find_map_by_name(obj, name);
114 	if (!map) {
115 		printf("%s:FAIL:map '%s' not found\n", test, name);
116 		error_cnt++;
117 		return -1;
118 	}
119 	return bpf_map__fd(map);
120 }
121 
122 static void test_pkt_access(void)
123 {
124 	const char *file = "./test_pkt_access.o";
125 	struct bpf_object *obj;
126 	__u32 duration, retval;
127 	int err, prog_fd;
128 
129 	err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
130 	if (err)
131 		return;
132 
133 	err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4),
134 				NULL, NULL, &retval, &duration);
135 	CHECK(err || errno || retval, "ipv4",
136 	      "err %d errno %d retval %d duration %d\n",
137 	      err, errno, retval, duration);
138 
139 	err = bpf_prog_test_run(prog_fd, 100000, &pkt_v6, sizeof(pkt_v6),
140 				NULL, NULL, &retval, &duration);
141 	CHECK(err || errno || retval, "ipv6",
142 	      "err %d errno %d retval %d duration %d\n",
143 	      err, errno, retval, duration);
144 	bpf_object__close(obj);
145 }
146 
147 static void test_xdp(void)
148 {
149 	struct vip key4 = {.protocol = 6, .family = AF_INET};
150 	struct vip key6 = {.protocol = 6, .family = AF_INET6};
151 	struct iptnl_info value4 = {.family = AF_INET};
152 	struct iptnl_info value6 = {.family = AF_INET6};
153 	const char *file = "./test_xdp.o";
154 	struct bpf_object *obj;
155 	char buf[128];
156 	struct ipv6hdr *iph6 = (void *)buf + sizeof(struct ethhdr);
157 	struct iphdr *iph = (void *)buf + sizeof(struct ethhdr);
158 	__u32 duration, retval, size;
159 	int err, prog_fd, map_fd;
160 
161 	err = bpf_prog_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
162 	if (err)
163 		return;
164 
165 	map_fd = bpf_find_map(__func__, obj, "vip2tnl");
166 	if (map_fd < 0)
167 		goto out;
168 	bpf_map_update_elem(map_fd, &key4, &value4, 0);
169 	bpf_map_update_elem(map_fd, &key6, &value6, 0);
170 
171 	err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
172 				buf, &size, &retval, &duration);
173 
174 	CHECK(err || errno || retval != XDP_TX || size != 74 ||
175 	      iph->protocol != IPPROTO_IPIP, "ipv4",
176 	      "err %d errno %d retval %d size %d\n",
177 	      err, errno, retval, size);
178 
179 	err = bpf_prog_test_run(prog_fd, 1, &pkt_v6, sizeof(pkt_v6),
180 				buf, &size, &retval, &duration);
181 	CHECK(err || errno || retval != XDP_TX || size != 114 ||
182 	      iph6->nexthdr != IPPROTO_IPV6, "ipv6",
183 	      "err %d errno %d retval %d size %d\n",
184 	      err, errno, retval, size);
185 out:
186 	bpf_object__close(obj);
187 }
188 
189 #define MAGIC_VAL 0x1234
190 #define NUM_ITER 100000
191 #define VIP_NUM 5
192 
193 static void test_l4lb(void)
194 {
195 	unsigned int nr_cpus = bpf_num_possible_cpus();
196 	const char *file = "./test_l4lb.o";
197 	struct vip key = {.protocol = 6};
198 	struct vip_meta {
199 		__u32 flags;
200 		__u32 vip_num;
201 	} value = {.vip_num = VIP_NUM};
202 	__u32 stats_key = VIP_NUM;
203 	struct vip_stats {
204 		__u64 bytes;
205 		__u64 pkts;
206 	} stats[nr_cpus];
207 	struct real_definition {
208 		union {
209 			__be32 dst;
210 			__be32 dstv6[4];
211 		};
212 		__u8 flags;
213 	} real_def = {.dst = MAGIC_VAL};
214 	__u32 ch_key = 11, real_num = 3;
215 	__u32 duration, retval, size;
216 	int err, i, prog_fd, map_fd;
217 	__u64 bytes = 0, pkts = 0;
218 	struct bpf_object *obj;
219 	char buf[128];
220 	u32 *magic = (u32 *)buf;
221 
222 	err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
223 	if (err)
224 		return;
225 
226 	map_fd = bpf_find_map(__func__, obj, "vip_map");
227 	if (map_fd < 0)
228 		goto out;
229 	bpf_map_update_elem(map_fd, &key, &value, 0);
230 
231 	map_fd = bpf_find_map(__func__, obj, "ch_rings");
232 	if (map_fd < 0)
233 		goto out;
234 	bpf_map_update_elem(map_fd, &ch_key, &real_num, 0);
235 
236 	map_fd = bpf_find_map(__func__, obj, "reals");
237 	if (map_fd < 0)
238 		goto out;
239 	bpf_map_update_elem(map_fd, &real_num, &real_def, 0);
240 
241 	err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v4, sizeof(pkt_v4),
242 				buf, &size, &retval, &duration);
243 	CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 54 ||
244 	      *magic != MAGIC_VAL, "ipv4",
245 	      "err %d errno %d retval %d size %d magic %x\n",
246 	      err, errno, retval, size, *magic);
247 
248 	err = bpf_prog_test_run(prog_fd, NUM_ITER, &pkt_v6, sizeof(pkt_v6),
249 				buf, &size, &retval, &duration);
250 	CHECK(err || errno || retval != 7/*TC_ACT_REDIRECT*/ || size != 74 ||
251 	      *magic != MAGIC_VAL, "ipv6",
252 	      "err %d errno %d retval %d size %d magic %x\n",
253 	      err, errno, retval, size, *magic);
254 
255 	map_fd = bpf_find_map(__func__, obj, "stats");
256 	if (map_fd < 0)
257 		goto out;
258 	bpf_map_lookup_elem(map_fd, &stats_key, stats);
259 	for (i = 0; i < nr_cpus; i++) {
260 		bytes += stats[i].bytes;
261 		pkts += stats[i].pkts;
262 	}
263 	if (bytes != MAGIC_BYTES * NUM_ITER * 2 || pkts != NUM_ITER * 2) {
264 		error_cnt++;
265 		printf("test_l4lb:FAIL:stats %lld %lld\n", bytes, pkts);
266 	}
267 out:
268 	bpf_object__close(obj);
269 }
270 
271 static void test_tcp_estats(void)
272 {
273 	const char *file = "./test_tcp_estats.o";
274 	int err, prog_fd;
275 	struct bpf_object *obj;
276 	__u32 duration = 0;
277 
278 	err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd);
279 	CHECK(err, "", "err %d errno %d\n", err, errno);
280 	if (err)
281 		return;
282 
283 	bpf_object__close(obj);
284 }
285 
286 int main(void)
287 {
288 	struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
289 
290 	setrlimit(RLIMIT_MEMLOCK, &rinf);
291 
292 	test_pkt_access();
293 	test_xdp();
294 	test_l4lb();
295 	test_tcp_estats();
296 
297 	printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt);
298 	return 0;
299 }
300