Add some simple loop examples. For now I just load these using bpftool but eventually they should have a loader simliar to test_verifier except for C snippets.
We want to use C files here instead of BPF because most users will be using C clang/llvm and want to test how well this works with the code generated by the actual tools instead of hand-crafted BPF. --- tools/testing/selftests/bpf/Makefile | 5 ++ tools/testing/selftests/bpf/test_bad_loop1.c | 47 ++++++++++++++++++++++ tools/testing/selftests/bpf/test_bad_loop2.c | 45 +++++++++++++++++++++ tools/testing/selftests/bpf/test_bad_loop3.c | 47 ++++++++++++++++++++++ tools/testing/selftests/bpf/test_basic_loop1.c | 44 +++++++++++++++++++++ tools/testing/selftests/bpf/test_basic_loop2.c | 48 +++++++++++++++++++++++ tools/testing/selftests/bpf/test_basic_loop3.c | 51 ++++++++++++++++++++++++ 7 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/test_bad_loop1.c create mode 100644 tools/testing/selftests/bpf/test_bad_loop2.c create mode 100644 tools/testing/selftests/bpf/test_bad_loop3.c create mode 100644 tools/testing/selftests/bpf/test_basic_loop1.c create mode 100644 tools/testing/selftests/bpf/test_basic_loop2.c create mode 100644 tools/testing/selftests/bpf/test_basic_loop3.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index a1b66da..0cf7bd1 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -34,7 +34,10 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test sockmap_tcp_msg_prog.o connect4_prog.o connect6_prog.o test_adjust_tail.o \ test_btf_haskv.o test_btf_nokv.o test_sockmap_kern.o test_tunnel_kern.o \ test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \ - test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o + test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o \ + test_basic_loop1.o test_basic_loop2.o test_basic_loop3.o \ + test_bad_loop1.o test_bad_loop2.o test_bad_loop3.o + # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ diff --git a/tools/testing/selftests/bpf/test_bad_loop1.c b/tools/testing/selftests/bpf/test_bad_loop1.c new file mode 100644 index 0000000..88e8cfb --- /dev/null +++ b/tools/testing/selftests/bpf/test_bad_loop1.c @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2018 Covalent IO + */ +#include <stddef.h> +#include <stdbool.h> +#include <string.h> +#include <linux/pkt_cls.h> +#include <linux/bpf.h> +#include <linux/in.h> +#include <linux/if_ether.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/icmp.h> +#include <linux/icmpv6.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include "bpf_helpers.h" +#include "test_iptunnel_common.h" +#include "bpf_endian.h" + + +/* Test packet access out of bounds */ + +int _version SEC("version") = 1; +SEC("classifier_tc_loop1") +int _tc_loop(struct __sk_buff *ctx) +{ + void *data = (void *)(unsigned long)ctx->data; + void *data_end = (void *)(unsigned long)ctx->data_end; + __u8 i = 0, j = 0, k = 0, *p; + + p = data; + if (data + 50 > data_end) + return TC_ACT_OK; + +#pragma nounroll + while (i < 100) { + k += p[i]; + p[i] = k; + i++; + } + ctx->mark = k; + + return TC_ACT_OK; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_bad_loop2.c b/tools/testing/selftests/bpf/test_bad_loop2.c new file mode 100644 index 0000000..fff005e --- /dev/null +++ b/tools/testing/selftests/bpf/test_bad_loop2.c @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2018 Covalent IO + */ +#include <stddef.h> +#include <stdbool.h> +#include <string.h> +#include <linux/pkt_cls.h> +#include <linux/bpf.h> +#include <linux/in.h> +#include <linux/if_ether.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/icmp.h> +#include <linux/icmpv6.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include "bpf_helpers.h" +#include "test_iptunnel_common.h" +#include "bpf_endian.h" + +/* Test non-terminating loops */ +int _version SEC("version") = 1; +SEC("classifier_tc_loop1") +int _tc_loop(struct __sk_buff *ctx) +{ + void *data = (void *)(unsigned long)ctx->data; + void *data_end = (void *)(unsigned long)ctx->data_end; + int i = 0, j = 0, k = 0, *p; + + p = data; + if (data + 101 > data_end) + return TC_ACT_OK; + +#pragma nounroll + while (i < 100) { + k += p[i]; + p[i] = k; + i--; + } + ctx->mark = k; + + return TC_ACT_OK; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_bad_loop3.c b/tools/testing/selftests/bpf/test_bad_loop3.c new file mode 100644 index 0000000..4015366 --- /dev/null +++ b/tools/testing/selftests/bpf/test_bad_loop3.c @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2018 Covalent IO + */ +#include <stddef.h> +#include <stdbool.h> +#include <string.h> +#include <linux/pkt_cls.h> +#include <linux/bpf.h> +#include <linux/in.h> +#include <linux/if_ether.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/icmp.h> +#include <linux/icmpv6.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include "bpf_helpers.h" +#include "test_iptunnel_common.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; +SEC("classifier_tc_loop1") +int _tc_loop(struct __sk_buff *ctx) +{ + void *data = (void *)(unsigned long)ctx->data; + void *data_end = (void *)(unsigned long)ctx->data_end; + __u8 i = 0, j = 0, k = 0, *p; + + p = data; + if (data + 101 > data_end) + return TC_ACT_OK; + +head: +#pragma nounroll + while (i < 100) { + k += p[i]; + p[i] = k; + i++; + if (k < 100) + goto head; + } + ctx->mark = k; + + return TC_ACT_OK; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_basic_loop1.c b/tools/testing/selftests/bpf/test_basic_loop1.c new file mode 100644 index 0000000..63dc4a4 --- /dev/null +++ b/tools/testing/selftests/bpf/test_basic_loop1.c @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2018 Covalent IO + */ +#include <stddef.h> +#include <stdbool.h> +#include <string.h> +#include <linux/pkt_cls.h> +#include <linux/bpf.h> +#include <linux/in.h> +#include <linux/if_ether.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/icmp.h> +#include <linux/icmpv6.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include "bpf_helpers.h" +#include "test_iptunnel_common.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; +SEC("classifier_tc_loop1") +int _tc_loop(struct __sk_buff *ctx) +{ + void *data = (void *)(unsigned long)ctx->data; + void *data_end = (void *)(unsigned long)ctx->data_end; + __u8 i = 0, j = 0, k = 0, *p; + + p = data; + if (data + 101 > data_end) + return TC_ACT_OK; + +#pragma nounroll + while (i < 100) { + k += p[i]; + p[i] = k; + i++; + } + ctx->mark = k; + + return TC_ACT_OK; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_basic_loop2.c b/tools/testing/selftests/bpf/test_basic_loop2.c new file mode 100644 index 0000000..fb774dc --- /dev/null +++ b/tools/testing/selftests/bpf/test_basic_loop2.c @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2018 Covalent IO + */ +#include <stddef.h> +#include <stdbool.h> +#include <string.h> +#include <linux/pkt_cls.h> +#include <linux/bpf.h> +#include <linux/in.h> +#include <linux/if_ether.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/icmp.h> +#include <linux/icmpv6.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include "bpf_helpers.h" +#include "test_iptunnel_common.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; +SEC("classifier_tc_loop1") +int _tc_loop(struct __sk_buff *ctx) +{ + void *data = (void *)(unsigned long)ctx->data; + void *data_end = (void *)(unsigned long)ctx->data_end; + __u8 i = 0, j = 0, k = 0, *p; + + p = data; + if (data + 101 > data_end) + return TC_ACT_OK; + +#pragma nounroll + while (i < 100) { + k += p[i]; + if (k < 100) { + p[i] = 'a'; + } else { + p[i] = 'b'; + } + i++; + } + ctx->mark = k; + + return TC_ACT_OK; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_basic_loop3.c b/tools/testing/selftests/bpf/test_basic_loop3.c new file mode 100644 index 0000000..dd7dd1b --- /dev/null +++ b/tools/testing/selftests/bpf/test_basic_loop3.c @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 + * Copyright (c) 2018 Covalent IO + */ +#include <stddef.h> +#include <stdbool.h> +#include <string.h> +#include <linux/pkt_cls.h> +#include <linux/bpf.h> +#include <linux/in.h> +#include <linux/if_ether.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/icmp.h> +#include <linux/icmpv6.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include "bpf_helpers.h" +#include "test_iptunnel_common.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; +SEC("classifier_tc_loop1") +int _tc_loop(struct __sk_buff *ctx) +{ + void *data = (void *)(unsigned long)ctx->data; + void *data_end = (void *)(unsigned long)ctx->data_end; + __u8 i = 0, j = 0, k = 0, *p; + + if (data + 2 > data_end) + return TC_ACT_OK; + + p = data; + j = p[0]; + + if (data + 101 > data_end) + return TC_ACT_OK; + + if (j < 100) + return TC_ACT_OK; + +#pragma nounroll + while (i < j) { + k += p[i]; + i++; + } + ctx->mark = k; + + return TC_ACT_OK; +} + +char _license[] SEC("license") = "GPL";