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_constant_htons(ETH_P_IP
),
49 .iph
.tot_len
= __bpf_constant_htons(MAGIC_BYTES
),
53 /* ipv6 test vector */
59 .eth
.h_proto
= __bpf_constant_htons(ETH_P_IPV6
),
61 .iph
.payload_len
= __bpf_constant_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_find_map(const char *test
, struct bpf_object
*obj
,
83 map
= bpf_object__find_map_by_name(obj
, name
);
85 printf("%s:FAIL:map '%s' not found\n", test
, name
);
89 return bpf_map__fd(map
);
92 static void test_pkt_access(void)
94 const char *file
= "./test_pkt_access.o";
95 struct bpf_object
*obj
;
96 __u32 duration
, retval
;
99 err
= bpf_prog_load(file
, BPF_PROG_TYPE_SCHED_CLS
, &obj
, &prog_fd
);
105 err
= bpf_prog_test_run(prog_fd
, 100000, &pkt_v4
, sizeof(pkt_v4
),
106 NULL
, NULL
, &retval
, &duration
);
107 CHECK(err
|| errno
|| retval
, "ipv4",
108 "err %d errno %d retval %d duration %d\n",
109 err
, errno
, retval
, duration
);
111 err
= bpf_prog_test_run(prog_fd
, 100000, &pkt_v6
, sizeof(pkt_v6
),
112 NULL
, NULL
, &retval
, &duration
);
113 CHECK(err
|| errno
|| retval
, "ipv6",
114 "err %d errno %d retval %d duration %d\n",
115 err
, errno
, retval
, duration
);
116 bpf_object__close(obj
);
119 static void test_xdp(void)
121 struct vip key4
= {.protocol
= 6, .family
= AF_INET
};
122 struct vip key6
= {.protocol
= 6, .family
= AF_INET6
};
123 struct iptnl_info value4
= {.family
= AF_INET
};
124 struct iptnl_info value6
= {.family
= AF_INET6
};
125 const char *file
= "./test_xdp.o";
126 struct bpf_object
*obj
;
128 struct ipv6hdr
*iph6
= (void *)buf
+ sizeof(struct ethhdr
);
129 struct iphdr
*iph
= (void *)buf
+ sizeof(struct ethhdr
);
130 __u32 duration
, retval
, size
;
131 int err
, prog_fd
, map_fd
;
133 err
= bpf_prog_load(file
, BPF_PROG_TYPE_XDP
, &obj
, &prog_fd
);
139 map_fd
= bpf_find_map(__func__
, obj
, "vip2tnl");
142 bpf_map_update_elem(map_fd
, &key4
, &value4
, 0);
143 bpf_map_update_elem(map_fd
, &key6
, &value6
, 0);
145 err
= bpf_prog_test_run(prog_fd
, 1, &pkt_v4
, sizeof(pkt_v4
),
146 buf
, &size
, &retval
, &duration
);
148 CHECK(err
|| errno
|| retval
!= XDP_TX
|| size
!= 74 ||
149 iph
->protocol
!= IPPROTO_IPIP
, "ipv4",
150 "err %d errno %d retval %d size %d\n",
151 err
, errno
, retval
, size
);
153 err
= bpf_prog_test_run(prog_fd
, 1, &pkt_v6
, sizeof(pkt_v6
),
154 buf
, &size
, &retval
, &duration
);
155 CHECK(err
|| errno
|| retval
!= XDP_TX
|| size
!= 114 ||
156 iph6
->nexthdr
!= IPPROTO_IPV6
, "ipv6",
157 "err %d errno %d retval %d size %d\n",
158 err
, errno
, retval
, size
);
160 bpf_object__close(obj
);
163 #define MAGIC_VAL 0x1234
164 #define NUM_ITER 100000
167 static void test_l4lb(void)
169 unsigned int nr_cpus
= bpf_num_possible_cpus();
170 const char *file
= "./test_l4lb.o";
171 struct vip key
= {.protocol
= 6};
175 } value
= {.vip_num
= VIP_NUM
};
176 __u32 stats_key
= VIP_NUM
;
181 struct real_definition
{
187 } real_def
= {.dst
= MAGIC_VAL
};
188 __u32 ch_key
= 11, real_num
= 3;
189 __u32 duration
, retval
, size
;
190 int err
, i
, prog_fd
, map_fd
;
191 __u64 bytes
= 0, pkts
= 0;
192 struct bpf_object
*obj
;
194 u32
*magic
= (u32
*)buf
;
196 err
= bpf_prog_load(file
, BPF_PROG_TYPE_SCHED_CLS
, &obj
, &prog_fd
);
202 map_fd
= bpf_find_map(__func__
, obj
, "vip_map");
205 bpf_map_update_elem(map_fd
, &key
, &value
, 0);
207 map_fd
= bpf_find_map(__func__
, obj
, "ch_rings");
210 bpf_map_update_elem(map_fd
, &ch_key
, &real_num
, 0);
212 map_fd
= bpf_find_map(__func__
, obj
, "reals");
215 bpf_map_update_elem(map_fd
, &real_num
, &real_def
, 0);
217 err
= bpf_prog_test_run(prog_fd
, NUM_ITER
, &pkt_v4
, sizeof(pkt_v4
),
218 buf
, &size
, &retval
, &duration
);
219 CHECK(err
|| errno
|| retval
!= 7/*TC_ACT_REDIRECT*/ || size
!= 54 ||
220 *magic
!= MAGIC_VAL
, "ipv4",
221 "err %d errno %d retval %d size %d magic %x\n",
222 err
, errno
, retval
, size
, *magic
);
224 err
= bpf_prog_test_run(prog_fd
, NUM_ITER
, &pkt_v6
, sizeof(pkt_v6
),
225 buf
, &size
, &retval
, &duration
);
226 CHECK(err
|| errno
|| retval
!= 7/*TC_ACT_REDIRECT*/ || size
!= 74 ||
227 *magic
!= MAGIC_VAL
, "ipv6",
228 "err %d errno %d retval %d size %d magic %x\n",
229 err
, errno
, retval
, size
, *magic
);
231 map_fd
= bpf_find_map(__func__
, obj
, "stats");
234 bpf_map_lookup_elem(map_fd
, &stats_key
, stats
);
235 for (i
= 0; i
< nr_cpus
; i
++) {
236 bytes
+= stats
[i
].bytes
;
237 pkts
+= stats
[i
].pkts
;
239 if (bytes
!= MAGIC_BYTES
* NUM_ITER
* 2 || pkts
!= NUM_ITER
* 2) {
241 printf("test_l4lb:FAIL:stats %lld %lld\n", bytes
, pkts
);
244 bpf_object__close(obj
);
247 static void test_tcp_estats(void)
249 const char *file
= "./test_tcp_estats.o";
251 struct bpf_object
*obj
;
254 err
= bpf_prog_load(file
, BPF_PROG_TYPE_TRACEPOINT
, &obj
, &prog_fd
);
255 CHECK(err
, "", "err %d errno %d\n", err
, errno
);
261 bpf_object__close(obj
);
264 static inline __u64
ptr_to_u64(const void *ptr
)
266 return (__u64
) (unsigned long) ptr
;
269 static void test_bpf_obj_id(void)
271 const __u64 array_magic_value
= 0xfaceb00c;
272 const __u32 array_key
= 0;
273 const int nr_iters
= 2;
274 const char *file
= "./test_obj_id.o";
275 const char *jit_sysctl
= "/proc/sys/net/core/bpf_jit_enable";
277 struct bpf_object
*objs
[nr_iters
];
278 int prog_fds
[nr_iters
], map_fds
[nr_iters
];
279 /* +1 to test for the info_len returned by kernel */
280 struct bpf_prog_info prog_infos
[nr_iters
+ 1];
281 struct bpf_map_info map_infos
[nr_iters
+ 1];
282 char jited_insns
[128], xlated_insns
[128], zeros
[128];
283 __u32 i
, next_id
, info_len
, nr_id_found
, duration
= 0;
284 int sysctl_fd
, jit_enabled
= 0, err
= 0;
287 sysctl_fd
= open(jit_sysctl
, 0, O_RDONLY
);
288 if (sysctl_fd
!= -1) {
291 if (read(sysctl_fd
, &tmpc
, sizeof(tmpc
)) == 1)
292 jit_enabled
= (tmpc
!= '0');
296 err
= bpf_prog_get_fd_by_id(0);
297 CHECK(err
>= 0 || errno
!= ENOENT
,
298 "get-fd-by-notexist-prog-id", "err %d errno %d\n", err
, errno
);
300 err
= bpf_map_get_fd_by_id(0);
301 CHECK(err
>= 0 || errno
!= ENOENT
,
302 "get-fd-by-notexist-map-id", "err %d errno %d\n", err
, errno
);
304 for (i
= 0; i
< nr_iters
; i
++)
307 /* Check bpf_obj_get_info_by_fd() */
308 bzero(zeros
, sizeof(zeros
));
309 for (i
= 0; i
< nr_iters
; i
++) {
310 err
= bpf_prog_load(file
, BPF_PROG_TYPE_SOCKET_FILTER
,
311 &objs
[i
], &prog_fds
[i
]);
312 /* test_obj_id.o is a dumb prog. It should never fail
319 /* Check getting prog info */
320 info_len
= sizeof(struct bpf_prog_info
) * 2;
321 bzero(&prog_infos
[i
], info_len
);
322 bzero(jited_insns
, sizeof(jited_insns
));
323 bzero(xlated_insns
, sizeof(xlated_insns
));
324 prog_infos
[i
].jited_prog_insns
= ptr_to_u64(jited_insns
);
325 prog_infos
[i
].jited_prog_len
= sizeof(jited_insns
);
326 prog_infos
[i
].xlated_prog_insns
= ptr_to_u64(xlated_insns
);
327 prog_infos
[i
].xlated_prog_len
= sizeof(xlated_insns
);
328 err
= bpf_obj_get_info_by_fd(prog_fds
[i
], &prog_infos
[i
],
331 prog_infos
[i
].type
!= BPF_PROG_TYPE_SOCKET_FILTER
||
332 info_len
!= sizeof(struct bpf_prog_info
) ||
333 (jit_enabled
&& !prog_infos
[i
].jited_prog_len
) ||
335 !memcmp(jited_insns
, zeros
, sizeof(zeros
))) ||
336 !prog_infos
[i
].xlated_prog_len
||
337 !memcmp(xlated_insns
, zeros
, sizeof(zeros
)),
339 "err %d errno %d i %d type %d(%d) info_len %u(%lu) jit_enabled %d jited_prog_len %u xlated_prog_len %u jited_prog %d xlated_prog %d\n",
341 prog_infos
[i
].type
, BPF_PROG_TYPE_SOCKET_FILTER
,
342 info_len
, sizeof(struct bpf_prog_info
),
344 prog_infos
[i
].jited_prog_len
,
345 prog_infos
[i
].xlated_prog_len
,
346 !!memcmp(jited_insns
, zeros
, sizeof(zeros
)),
347 !!memcmp(xlated_insns
, zeros
, sizeof(zeros
))))
350 map_fds
[i
] = bpf_find_map(__func__
, objs
[i
], "test_map_id");
351 assert(map_fds
[i
] >= 0);
352 err
= bpf_map_update_elem(map_fds
[i
], &array_key
,
353 &array_magic_value
, 0);
356 /* Check getting map info */
357 info_len
= sizeof(struct bpf_map_info
) * 2;
358 bzero(&map_infos
[i
], info_len
);
359 err
= bpf_obj_get_info_by_fd(map_fds
[i
], &map_infos
[i
],
362 map_infos
[i
].type
!= BPF_MAP_TYPE_ARRAY
||
363 map_infos
[i
].key_size
!= sizeof(__u32
) ||
364 map_infos
[i
].value_size
!= sizeof(__u64
) ||
365 map_infos
[i
].max_entries
!= 1 ||
366 map_infos
[i
].map_flags
!= 0 ||
367 info_len
!= sizeof(struct bpf_map_info
),
369 "err %d errno %d type %d(%d) info_len %u(%lu) key_size %u value_size %u max_entries %u map_flags %X\n",
371 map_infos
[i
].type
, BPF_MAP_TYPE_ARRAY
,
372 info_len
, sizeof(struct bpf_map_info
),
373 map_infos
[i
].key_size
,
374 map_infos
[i
].value_size
,
375 map_infos
[i
].max_entries
,
376 map_infos
[i
].map_flags
))
380 /* Check bpf_prog_get_next_id() */
383 while (!bpf_prog_get_next_id(next_id
, &next_id
)) {
384 struct bpf_prog_info prog_info
= {};
387 info_len
= sizeof(prog_info
);
389 prog_fd
= bpf_prog_get_fd_by_id(next_id
);
390 if (prog_fd
< 0 && errno
== ENOENT
)
391 /* The bpf_prog is in the dead row */
393 if (CHECK(prog_fd
< 0, "get-prog-fd(next_id)",
394 "prog_fd %d next_id %d errno %d\n",
395 prog_fd
, next_id
, errno
))
398 for (i
= 0; i
< nr_iters
; i
++)
399 if (prog_infos
[i
].id
== next_id
)
407 err
= bpf_obj_get_info_by_fd(prog_fd
, &prog_info
, &info_len
);
408 prog_infos
[i
].jited_prog_insns
= 0;
409 prog_infos
[i
].xlated_prog_insns
= 0;
410 CHECK(err
|| info_len
!= sizeof(struct bpf_prog_info
) ||
411 memcmp(&prog_info
, &prog_infos
[i
], info_len
),
412 "get-prog-info(next_id->fd)",
413 "err %d errno %d info_len %u(%lu) memcmp %d\n",
414 err
, errno
, info_len
, sizeof(struct bpf_prog_info
),
415 memcmp(&prog_info
, &prog_infos
[i
], info_len
));
419 CHECK(nr_id_found
!= nr_iters
,
420 "check total prog id found by get_next_id",
421 "nr_id_found %u(%u)\n",
422 nr_id_found
, nr_iters
);
424 /* Check bpf_map_get_next_id() */
427 while (!bpf_map_get_next_id(next_id
, &next_id
)) {
428 struct bpf_map_info map_info
= {};
431 info_len
= sizeof(map_info
);
433 map_fd
= bpf_map_get_fd_by_id(next_id
);
434 if (map_fd
< 0 && errno
== ENOENT
)
435 /* The bpf_map is in the dead row */
437 if (CHECK(map_fd
< 0, "get-map-fd(next_id)",
438 "map_fd %d next_id %u errno %d\n",
439 map_fd
, next_id
, errno
))
442 for (i
= 0; i
< nr_iters
; i
++)
443 if (map_infos
[i
].id
== next_id
)
451 err
= bpf_map_lookup_elem(map_fd
, &array_key
, &array_value
);
454 err
= bpf_obj_get_info_by_fd(map_fd
, &map_info
, &info_len
);
455 CHECK(err
|| info_len
!= sizeof(struct bpf_map_info
) ||
456 memcmp(&map_info
, &map_infos
[i
], info_len
) ||
457 array_value
!= array_magic_value
,
458 "check get-map-info(next_id->fd)",
459 "err %d errno %d info_len %u(%lu) memcmp %d array_value %llu(%llu)\n",
460 err
, errno
, info_len
, sizeof(struct bpf_map_info
),
461 memcmp(&map_info
, &map_infos
[i
], info_len
),
462 array_value
, array_magic_value
);
466 CHECK(nr_id_found
!= nr_iters
,
467 "check total map id found by get_next_id",
468 "nr_id_found %u(%u)\n",
469 nr_id_found
, nr_iters
);
472 for (i
= 0; i
< nr_iters
; i
++)
473 bpf_object__close(objs
[i
]);
476 static void test_pkt_md_access(void)
478 const char *file
= "./test_pkt_md_access.o";
479 struct bpf_object
*obj
;
480 __u32 duration
, retval
;
483 err
= bpf_prog_load(file
, BPF_PROG_TYPE_SCHED_CLS
, &obj
, &prog_fd
);
489 err
= bpf_prog_test_run(prog_fd
, 10, &pkt_v4
, sizeof(pkt_v4
),
490 NULL
, NULL
, &retval
, &duration
);
491 CHECK(err
|| retval
, "",
492 "err %d errno %d retval %d duration %d\n",
493 err
, errno
, retval
, duration
);
495 bpf_object__close(obj
);
500 struct rlimit rinf
= { RLIM_INFINITY
, RLIM_INFINITY
};
502 setrlimit(RLIMIT_MEMLOCK
, &rinf
);
509 test_pkt_md_access();
511 printf("Summary: %d PASSED, %d FAILED\n", pass_cnt
, error_cnt
);
512 return error_cnt
? EXIT_FAILURE
: EXIT_SUCCESS
;