1 /* Copyright (c) 2017 Facebook
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.
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>
20 #include <linux/ipv6.h>
21 #include <linux/tcp.h>
24 #include <sys/resource.h>
25 #include <sys/types.h>
28 #include <linux/bpf.h>
29 #include <linux/err.h>
31 #include <bpf/libbpf.h>
32 #include "test_iptunnel_common.h"
34 #include "bpf_endian.h"
36 static int error_cnt
, pass_cnt
;
38 #define MAGIC_BYTES 123
40 /* ipv4 test vector */
46 .eth
.h_proto
= bpf_htons(ETH_P_IP
),
49 .iph
.tot_len
= bpf_htons(MAGIC_BYTES
),
53 /* ipv6 test vector */
59 .eth
.h_proto
= bpf_htons(ETH_P_IPV6
),
61 .iph
.payload_len
= bpf_htons(MAGIC_BYTES
),
65 #define CHECK(condition, tag, format...) ({ \
66 int __ret = !!(condition); \
69 printf("%s:FAIL:%s ", __func__, tag); \
73 printf("%s:PASS:%s %d nsec\n", __func__, tag, duration);\
78 static int bpf_prog_load(const char *file
, enum bpf_prog_type type
,
79 struct bpf_object
**pobj
, int *prog_fd
)
81 struct bpf_program
*prog
;
82 struct bpf_object
*obj
;
85 obj
= bpf_object__open(file
);
91 prog
= bpf_program__next(NULL
, obj
);
93 bpf_object__close(obj
);
98 bpf_program__set_type(prog
, type
);
99 err
= bpf_object__load(obj
);
101 bpf_object__close(obj
);
107 *prog_fd
= bpf_program__fd(prog
);
111 static int bpf_find_map(const char *test
, struct bpf_object
*obj
,
116 map
= bpf_object__find_map_by_name(obj
, name
);
118 printf("%s:FAIL:map '%s' not found\n", test
, name
);
122 return bpf_map__fd(map
);
125 static void test_pkt_access(void)
127 const char *file
= "./test_pkt_access.o";
128 struct bpf_object
*obj
;
129 __u32 duration
, retval
;
132 err
= bpf_prog_load(file
, BPF_PROG_TYPE_SCHED_CLS
, &obj
, &prog_fd
);
136 err
= bpf_prog_test_run(prog_fd
, 100000, &pkt_v4
, sizeof(pkt_v4
),
137 NULL
, NULL
, &retval
, &duration
);
138 CHECK(err
|| errno
|| retval
, "ipv4",
139 "err %d errno %d retval %d duration %d\n",
140 err
, errno
, retval
, duration
);
142 err
= bpf_prog_test_run(prog_fd
, 100000, &pkt_v6
, sizeof(pkt_v6
),
143 NULL
, NULL
, &retval
, &duration
);
144 CHECK(err
|| errno
|| retval
, "ipv6",
145 "err %d errno %d retval %d duration %d\n",
146 err
, errno
, retval
, duration
);
147 bpf_object__close(obj
);
150 static void test_xdp(void)
152 struct vip key4
= {.protocol
= 6, .family
= AF_INET
};
153 struct vip key6
= {.protocol
= 6, .family
= AF_INET6
};
154 struct iptnl_info value4
= {.family
= AF_INET
};
155 struct iptnl_info value6
= {.family
= AF_INET6
};
156 const char *file
= "./test_xdp.o";
157 struct bpf_object
*obj
;
159 struct ipv6hdr
*iph6
= (void *)buf
+ sizeof(struct ethhdr
);
160 struct iphdr
*iph
= (void *)buf
+ sizeof(struct ethhdr
);
161 __u32 duration
, retval
, size
;
162 int err
, prog_fd
, map_fd
;
164 err
= bpf_prog_load(file
, BPF_PROG_TYPE_XDP
, &obj
, &prog_fd
);
168 map_fd
= bpf_find_map(__func__
, obj
, "vip2tnl");
171 bpf_map_update_elem(map_fd
, &key4
, &value4
, 0);
172 bpf_map_update_elem(map_fd
, &key6
, &value6
, 0);
174 err
= bpf_prog_test_run(prog_fd
, 1, &pkt_v4
, sizeof(pkt_v4
),
175 buf
, &size
, &retval
, &duration
);
177 CHECK(err
|| errno
|| retval
!= XDP_TX
|| size
!= 74 ||
178 iph
->protocol
!= IPPROTO_IPIP
, "ipv4",
179 "err %d errno %d retval %d size %d\n",
180 err
, errno
, retval
, size
);
182 err
= bpf_prog_test_run(prog_fd
, 1, &pkt_v6
, sizeof(pkt_v6
),
183 buf
, &size
, &retval
, &duration
);
184 CHECK(err
|| errno
|| retval
!= XDP_TX
|| size
!= 114 ||
185 iph6
->nexthdr
!= IPPROTO_IPV6
, "ipv6",
186 "err %d errno %d retval %d size %d\n",
187 err
, errno
, retval
, size
);
189 bpf_object__close(obj
);
192 #define MAGIC_VAL 0x1234
193 #define NUM_ITER 100000
196 static void test_l4lb(void)
198 unsigned int nr_cpus
= bpf_num_possible_cpus();
199 const char *file
= "./test_l4lb.o";
200 struct vip key
= {.protocol
= 6};
204 } value
= {.vip_num
= VIP_NUM
};
205 __u32 stats_key
= VIP_NUM
;
210 struct real_definition
{
216 } real_def
= {.dst
= MAGIC_VAL
};
217 __u32 ch_key
= 11, real_num
= 3;
218 __u32 duration
, retval
, size
;
219 int err
, i
, prog_fd
, map_fd
;
220 __u64 bytes
= 0, pkts
= 0;
221 struct bpf_object
*obj
;
223 u32
*magic
= (u32
*)buf
;
225 err
= bpf_prog_load(file
, BPF_PROG_TYPE_SCHED_CLS
, &obj
, &prog_fd
);
229 map_fd
= bpf_find_map(__func__
, obj
, "vip_map");
232 bpf_map_update_elem(map_fd
, &key
, &value
, 0);
234 map_fd
= bpf_find_map(__func__
, obj
, "ch_rings");
237 bpf_map_update_elem(map_fd
, &ch_key
, &real_num
, 0);
239 map_fd
= bpf_find_map(__func__
, obj
, "reals");
242 bpf_map_update_elem(map_fd
, &real_num
, &real_def
, 0);
244 err
= bpf_prog_test_run(prog_fd
, NUM_ITER
, &pkt_v4
, sizeof(pkt_v4
),
245 buf
, &size
, &retval
, &duration
);
246 CHECK(err
|| errno
|| retval
!= 7/*TC_ACT_REDIRECT*/ || size
!= 54 ||
247 *magic
!= MAGIC_VAL
, "ipv4",
248 "err %d errno %d retval %d size %d magic %x\n",
249 err
, errno
, retval
, size
, *magic
);
251 err
= bpf_prog_test_run(prog_fd
, NUM_ITER
, &pkt_v6
, sizeof(pkt_v6
),
252 buf
, &size
, &retval
, &duration
);
253 CHECK(err
|| errno
|| retval
!= 7/*TC_ACT_REDIRECT*/ || size
!= 74 ||
254 *magic
!= MAGIC_VAL
, "ipv6",
255 "err %d errno %d retval %d size %d magic %x\n",
256 err
, errno
, retval
, size
, *magic
);
258 map_fd
= bpf_find_map(__func__
, obj
, "stats");
261 bpf_map_lookup_elem(map_fd
, &stats_key
, stats
);
262 for (i
= 0; i
< nr_cpus
; i
++) {
263 bytes
+= stats
[i
].bytes
;
264 pkts
+= stats
[i
].pkts
;
266 if (bytes
!= MAGIC_BYTES
* NUM_ITER
* 2 || pkts
!= NUM_ITER
* 2) {
268 printf("test_l4lb:FAIL:stats %lld %lld\n", bytes
, pkts
);
271 bpf_object__close(obj
);
274 static void test_tcp_estats(void)
276 const char *file
= "./test_tcp_estats.o";
278 struct bpf_object
*obj
;
281 err
= bpf_prog_load(file
, BPF_PROG_TYPE_TRACEPOINT
, &obj
, &prog_fd
);
282 CHECK(err
, "", "err %d errno %d\n", err
, errno
);
286 bpf_object__close(obj
);
289 static inline __u64
ptr_to_u64(const void *ptr
)
291 return (__u64
) (unsigned long) ptr
;
294 static void test_bpf_obj_id(void)
296 const __u64 array_magic_value
= 0xfaceb00c;
297 const __u32 array_key
= 0;
298 const int nr_iters
= 2;
299 const char *file
= "./test_obj_id.o";
300 const char *jit_sysctl
= "/proc/sys/net/core/bpf_jit_enable";
302 struct bpf_object
*objs
[nr_iters
];
303 int prog_fds
[nr_iters
], map_fds
[nr_iters
];
304 /* +1 to test for the info_len returned by kernel */
305 struct bpf_prog_info prog_infos
[nr_iters
+ 1];
306 struct bpf_map_info map_infos
[nr_iters
+ 1];
307 char jited_insns
[128], xlated_insns
[128];
308 __u32 i
, next_id
, info_len
, nr_id_found
, duration
= 0;
309 int sysctl_fd
, jit_enabled
= 0, err
= 0;
312 sysctl_fd
= open(jit_sysctl
, 0, O_RDONLY
);
313 if (sysctl_fd
!= -1) {
316 if (read(sysctl_fd
, &tmpc
, sizeof(tmpc
)) == 1)
317 jit_enabled
= (tmpc
!= '0');
321 err
= bpf_prog_get_fd_by_id(0);
322 CHECK(err
>= 0 || errno
!= ENOENT
,
323 "get-fd-by-notexist-prog-id", "err %d errno %d\n", err
, errno
);
325 err
= bpf_map_get_fd_by_id(0);
326 CHECK(err
>= 0 || errno
!= ENOENT
,
327 "get-fd-by-notexist-map-id", "err %d errno %d\n", err
, errno
);
329 for (i
= 0; i
< nr_iters
; i
++)
332 /* Check bpf_obj_get_info_by_fd() */
333 for (i
= 0; i
< nr_iters
; i
++) {
334 err
= bpf_prog_load(file
, BPF_PROG_TYPE_SOCKET_FILTER
,
335 &objs
[i
], &prog_fds
[i
]);
336 /* test_obj_id.o is a dumb prog. It should never fail
341 /* Check getting prog info */
342 info_len
= sizeof(struct bpf_prog_info
) * 2;
343 bzero(&prog_infos
[i
], info_len
);
344 prog_infos
[i
].jited_prog_insns
= ptr_to_u64(jited_insns
);
345 prog_infos
[i
].jited_prog_len
= sizeof(jited_insns
);
346 prog_infos
[i
].xlated_prog_insns
= ptr_to_u64(xlated_insns
);
347 prog_infos
[i
].xlated_prog_len
= sizeof(xlated_insns
);
348 err
= bpf_obj_get_info_by_fd(prog_fds
[i
], &prog_infos
[i
],
351 prog_infos
[i
].type
!= BPF_PROG_TYPE_SOCKET_FILTER
||
352 info_len
!= sizeof(struct bpf_prog_info
) ||
353 (jit_enabled
&& !prog_infos
[i
].jited_prog_len
) ||
354 !prog_infos
[i
].xlated_prog_len
,
356 "err %d errno %d i %d type %d(%d) info_len %u(%lu) jit_enabled %d jited_prog_len %u xlated_prog_len %u\n",
358 prog_infos
[i
].type
, BPF_PROG_TYPE_SOCKET_FILTER
,
359 info_len
, sizeof(struct bpf_prog_info
),
361 prog_infos
[i
].jited_prog_len
,
362 prog_infos
[i
].xlated_prog_len
))
365 map_fds
[i
] = bpf_find_map(__func__
, objs
[i
], "test_map_id");
366 assert(map_fds
[i
] >= 0);
367 err
= bpf_map_update_elem(map_fds
[i
], &array_key
,
368 &array_magic_value
, 0);
371 /* Check getting map info */
372 info_len
= sizeof(struct bpf_map_info
) * 2;
373 bzero(&map_infos
[i
], info_len
);
374 err
= bpf_obj_get_info_by_fd(map_fds
[i
], &map_infos
[i
],
377 map_infos
[i
].type
!= BPF_MAP_TYPE_ARRAY
||
378 map_infos
[i
].key_size
!= sizeof(__u32
) ||
379 map_infos
[i
].value_size
!= sizeof(__u64
) ||
380 map_infos
[i
].max_entries
!= 1 ||
381 map_infos
[i
].map_flags
!= 0 ||
382 info_len
!= sizeof(struct bpf_map_info
),
384 "err %d errno %d type %d(%d) info_len %u(%lu) key_size %u value_size %u max_entries %u map_flags %X\n",
386 map_infos
[i
].type
, BPF_MAP_TYPE_ARRAY
,
387 info_len
, sizeof(struct bpf_map_info
),
388 map_infos
[i
].key_size
,
389 map_infos
[i
].value_size
,
390 map_infos
[i
].max_entries
,
391 map_infos
[i
].map_flags
))
395 /* Check bpf_prog_get_next_id() */
398 while (!bpf_prog_get_next_id(next_id
, &next_id
)) {
399 struct bpf_prog_info prog_info
= {};
402 info_len
= sizeof(prog_info
);
404 prog_fd
= bpf_prog_get_fd_by_id(next_id
);
405 if (prog_fd
< 0 && errno
== ENOENT
)
406 /* The bpf_prog is in the dead row */
408 if (CHECK(prog_fd
< 0, "get-prog-fd(next_id)",
409 "prog_fd %d next_id %d errno %d\n",
410 prog_fd
, next_id
, errno
))
413 for (i
= 0; i
< nr_iters
; i
++)
414 if (prog_infos
[i
].id
== next_id
)
422 err
= bpf_obj_get_info_by_fd(prog_fd
, &prog_info
, &info_len
);
423 prog_infos
[i
].jited_prog_insns
= 0;
424 prog_infos
[i
].xlated_prog_insns
= 0;
425 CHECK(err
|| info_len
!= sizeof(struct bpf_prog_info
) ||
426 memcmp(&prog_info
, &prog_infos
[i
], info_len
),
427 "get-prog-info(next_id->fd)",
428 "err %d errno %d info_len %u(%lu) memcmp %d\n",
429 err
, errno
, info_len
, sizeof(struct bpf_prog_info
),
430 memcmp(&prog_info
, &prog_infos
[i
], info_len
));
434 CHECK(nr_id_found
!= nr_iters
,
435 "check total prog id found by get_next_id",
436 "nr_id_found %u(%u)\n",
437 nr_id_found
, nr_iters
);
439 /* Check bpf_map_get_next_id() */
442 while (!bpf_map_get_next_id(next_id
, &next_id
)) {
443 struct bpf_map_info map_info
= {};
446 info_len
= sizeof(map_info
);
448 map_fd
= bpf_map_get_fd_by_id(next_id
);
449 if (map_fd
< 0 && errno
== ENOENT
)
450 /* The bpf_map is in the dead row */
452 if (CHECK(map_fd
< 0, "get-map-fd(next_id)",
453 "map_fd %d next_id %u errno %d\n",
454 map_fd
, next_id
, errno
))
457 for (i
= 0; i
< nr_iters
; i
++)
458 if (map_infos
[i
].id
== next_id
)
466 err
= bpf_map_lookup_elem(map_fd
, &array_key
, &array_value
);
469 err
= bpf_obj_get_info_by_fd(map_fd
, &map_info
, &info_len
);
470 CHECK(err
|| info_len
!= sizeof(struct bpf_map_info
) ||
471 memcmp(&map_info
, &map_infos
[i
], info_len
) ||
472 array_value
!= array_magic_value
,
473 "check get-map-info(next_id->fd)",
474 "err %d errno %d info_len %u(%lu) memcmp %d array_value %llu(%llu)\n",
475 err
, errno
, info_len
, sizeof(struct bpf_map_info
),
476 memcmp(&map_info
, &map_infos
[i
], info_len
),
477 array_value
, array_magic_value
);
481 CHECK(nr_id_found
!= nr_iters
,
482 "check total map id found by get_next_id",
483 "nr_id_found %u(%u)\n",
484 nr_id_found
, nr_iters
);
487 for (i
= 0; i
< nr_iters
; i
++)
488 bpf_object__close(objs
[i
]);
491 static void test_pkt_md_access(void)
493 const char *file
= "./test_pkt_md_access.o";
494 struct bpf_object
*obj
;
495 __u32 duration
, retval
;
498 err
= bpf_prog_load(file
, BPF_PROG_TYPE_SCHED_CLS
, &obj
, &prog_fd
);
502 err
= bpf_prog_test_run(prog_fd
, 10, &pkt_v4
, sizeof(pkt_v4
),
503 NULL
, NULL
, &retval
, &duration
);
504 CHECK(err
|| retval
, "",
505 "err %d errno %d retval %d duration %d\n",
506 err
, errno
, retval
, duration
);
508 bpf_object__close(obj
);
513 struct rlimit rinf
= { RLIM_INFINITY
, RLIM_INFINITY
};
515 setrlimit(RLIMIT_MEMLOCK
, &rinf
);
522 test_pkt_md_access();
524 printf("Summary: %d PASSED, %d FAILED\n", pass_cnt
, error_cnt
);
525 return error_cnt
? EXIT_FAILURE
: EXIT_SUCCESS
;