aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2017-06-08 13:06:25 -0400
committerDavid S. Miller <davem@davemloft.net>2017-06-08 16:17:29 -0400
commit78a5a93c1eeb4e6933d1f62b33e5496d53b46c5a (patch)
treeb392175b2e83ff6956f5dad12b5e9ecbc13ad73c /tools
parent297fb414d0d190ca82bf0b46fb19d7fda1598737 (diff)
bpf, tests: fix endianness selection
I noticed that test_l4lb was failing in selftests: # ./test_progs test_pkt_access:PASS:ipv4 77 nsec test_pkt_access:PASS:ipv6 44 nsec test_xdp:PASS:ipv4 2933 nsec test_xdp:PASS:ipv6 1500 nsec test_l4lb:PASS:ipv4 377 nsec test_l4lb:PASS:ipv6 544 nsec test_l4lb:FAIL:stats 6297600000 200000 test_tcp_estats:PASS: 0 nsec Summary: 7 PASSED, 1 FAILED Tracking down the issue actually revealed that endianness selection in bpf_endian.h is broken when compiled with clang with bpf target. test_pkt_access.c, test_l4lb.c is compiled with __BYTE_ORDER as __BIG_ENDIAN, test_xdp.c as __LITTLE_ENDIAN! test_l4lb noticeably fails, because the test accounts bytes via bpf_ntohs(ip6h->payload_len) and bpf_ntohs(iph->tot_len), and compares them against a defined value and given a wrong endianness, the test outcome is different, of course. Turns out that there are actually two bugs: i) when we do __BYTE_ORDER comparison with __LITTLE_ENDIAN/__BIG_ENDIAN, then depending on the include order we see different outcomes. Reason is that __BYTE_ORDER is undefined due to missing endian.h include. Before we include the asm/byteorder.h (e.g. through linux/in.h), then __BYTE_ORDER equals __LITTLE_ENDIAN since both are undefined, after the include which correctly pulls in linux/byteorder/little_endian.h, __LITTLE_ENDIAN is defined, but given __BYTE_ORDER is still undefined, we match on __BYTE_ORDER equals to __BIG_ENDIAN since __BIG_ENDIAN is also undefined at that point, sigh. ii) But even that would be wrong, since when compiling the test cases with clang, one can select between bpfeb and bpfel targets for cross compilation. Hence, we can also not rely on what the system's endian.h provides, but we need to look at the compiler's defined endianness. The compiler defines __BYTE_ORDER__, and we can match __ORDER_LITTLE_ENDIAN__ and __ORDER_BIG_ENDIAN__, which also reflects targets bpf (native), bpfel, bpfeb correctly, thus really only rely on that. After patch: # ./test_progs test_pkt_access:PASS:ipv4 74 nsec test_pkt_access:PASS:ipv6 42 nsec test_xdp:PASS:ipv4 2340 nsec test_xdp:PASS:ipv6 1461 nsec test_l4lb:PASS:ipv4 400 nsec test_l4lb:PASS:ipv6 530 nsec test_tcp_estats:PASS: 0 nsec Summary: 7 PASSED, 0 FAILED Fixes: 43bcf707ccdc ("bpf: fix _htons occurences in test_progs") Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'tools')
-rw-r--r--tools/testing/selftests/bpf/bpf_endian.h41
1 files changed, 30 insertions, 11 deletions
diff --git a/tools/testing/selftests/bpf/bpf_endian.h b/tools/testing/selftests/bpf/bpf_endian.h
index 19d0604f8694..487cbfb89beb 100644
--- a/tools/testing/selftests/bpf/bpf_endian.h
+++ b/tools/testing/selftests/bpf/bpf_endian.h
@@ -1,23 +1,42 @@
1#ifndef __BPF_ENDIAN__ 1#ifndef __BPF_ENDIAN__
2#define __BPF_ENDIAN__ 2#define __BPF_ENDIAN__
3 3
4#include <asm/byteorder.h> 4#include <linux/swab.h>
5 5
6#if __BYTE_ORDER == __LITTLE_ENDIAN 6/* LLVM's BPF target selects the endianness of the CPU
7# define __bpf_ntohs(x) __builtin_bswap16(x) 7 * it compiles on, or the user specifies (bpfel/bpfeb),
8# define __bpf_htons(x) __builtin_bswap16(x) 8 * respectively. The used __BYTE_ORDER__ is defined by
9#elif __BYTE_ORDER == __BIG_ENDIAN 9 * the compiler, we cannot rely on __BYTE_ORDER from
10# define __bpf_ntohs(x) (x) 10 * libc headers, since it doesn't reflect the actual
11# define __bpf_htons(x) (x) 11 * requested byte order.
12 *
13 * Note, LLVM's BPF target has different __builtin_bswapX()
14 * semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE
15 * in bpfel and bpfeb case, which means below, that we map
16 * to cpu_to_be16(). We could use it unconditionally in BPF
17 * case, but better not rely on it, so that this header here
18 * can be used from application and BPF program side, which
19 * use different targets.
20 */
21#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
22# define __bpf_ntohs(x) __builtin_bswap16(x)
23# define __bpf_htons(x) __builtin_bswap16(x)
24# define __bpf_constant_ntohs(x) ___constant_swab16(x)
25# define __bpf_constant_htons(x) ___constant_swab16(x)
26#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
27# define __bpf_ntohs(x) (x)
28# define __bpf_htons(x) (x)
29# define __bpf_constant_ntohs(x) (x)
30# define __bpf_constant_htons(x) (x)
12#else 31#else
13# error "Fix your __BYTE_ORDER?!" 32# error "Fix your compiler's __BYTE_ORDER__?!"
14#endif 33#endif
15 34
16#define bpf_htons(x) \ 35#define bpf_htons(x) \
17 (__builtin_constant_p(x) ? \ 36 (__builtin_constant_p(x) ? \
18 __constant_htons(x) : __bpf_htons(x)) 37 __bpf_constant_htons(x) : __bpf_htons(x))
19#define bpf_ntohs(x) \ 38#define bpf_ntohs(x) \
20 (__builtin_constant_p(x) ? \ 39 (__builtin_constant_p(x) ? \
21 __constant_ntohs(x) : __bpf_ntohs(x)) 40 __bpf_constant_ntohs(x) : __bpf_ntohs(x))
22 41
23#endif 42#endif /* __BPF_ENDIAN__ */