bpf: add selftest for bpf's (set|get)_sockopt for SAVE_SYN
authorNikita V. Shirokov <tehnerd@fb.com>
Fri, 31 Aug 2018 16:43:47 +0000 (09:43 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Fri, 31 Aug 2018 23:37:00 +0000 (01:37 +0200)
adding selftest for feature, introduced in commit 9452048c79404 ("bpf:
add TCP_SAVE_SYN/TCP_SAVED_SYN options for bpf_(set|get)sockopt").

Signed-off-by: Nikita V. Shirokov <tehnerd@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
tools/testing/selftests/bpf/test_tcpbpf_kern.c
tools/testing/selftests/bpf/test_tcpbpf_user.c

index 4b7fd54..74f73b3 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
 #include <linux/ip.h>
+#include <linux/ipv6.h>
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/tcp.h>
@@ -17,6 +18,13 @@ struct bpf_map_def SEC("maps") global_map = {
        .type = BPF_MAP_TYPE_ARRAY,
        .key_size = sizeof(__u32),
        .value_size = sizeof(struct tcpbpf_globals),
+       .max_entries = 4,
+};
+
+struct bpf_map_def SEC("maps") sockopt_results = {
+       .type = BPF_MAP_TYPE_ARRAY,
+       .key_size = sizeof(__u32),
+       .value_size = sizeof(int),
        .max_entries = 2,
 };
 
@@ -45,11 +53,14 @@ int _version SEC("version") = 1;
 SEC("sockops")
 int bpf_testcb(struct bpf_sock_ops *skops)
 {
-       int rv = -1;
-       int bad_call_rv = 0;
+       char header[sizeof(struct ipv6hdr) + sizeof(struct tcphdr)];
+       struct tcphdr *thdr;
        int good_call_rv = 0;
-       int op;
+       int bad_call_rv = 0;
+       int save_syn = 1;
+       int rv = -1;
        int v = 0;
+       int op;
 
        op = (int) skops->op;
 
@@ -82,6 +93,21 @@ int bpf_testcb(struct bpf_sock_ops *skops)
                v = 0xff;
                rv = bpf_setsockopt(skops, SOL_IPV6, IPV6_TCLASS, &v,
                                    sizeof(v));
+               if (skops->family == AF_INET6) {
+                       v = bpf_getsockopt(skops, IPPROTO_TCP, TCP_SAVED_SYN,
+                                          header, (sizeof(struct ipv6hdr) +
+                                                   sizeof(struct tcphdr)));
+                       if (!v) {
+                               int offset = sizeof(struct ipv6hdr);
+
+                               thdr = (struct tcphdr *)(header + offset);
+                               v = thdr->syn;
+                               __u32 key = 1;
+
+                               bpf_map_update_elem(&sockopt_results, &key, &v,
+                                                   BPF_ANY);
+                       }
+               }
                break;
        case BPF_SOCK_OPS_RTO_CB:
                break;
@@ -111,6 +137,12 @@ int bpf_testcb(struct bpf_sock_ops *skops)
                break;
        case BPF_SOCK_OPS_TCP_LISTEN_CB:
                bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG);
+               v = bpf_setsockopt(skops, IPPROTO_TCP, TCP_SAVE_SYN,
+                                  &save_syn, sizeof(save_syn));
+               /* Update global map w/ result of setsock opt */
+               __u32 key = 0;
+
+               bpf_map_update_elem(&sockopt_results, &key, &v, BPF_ANY);
                break;
        default:
                rv = -1;
index a275c29..e6eebda 100644 (file)
@@ -54,6 +54,26 @@ err:
        return -1;
 }
 
+int verify_sockopt_result(int sock_map_fd)
+{
+       __u32 key = 0;
+       int res;
+       int rv;
+
+       /* check setsockopt for SAVE_SYN */
+       rv = bpf_map_lookup_elem(sock_map_fd, &key, &res);
+       EXPECT_EQ(0, rv, "d");
+       EXPECT_EQ(0, res, "d");
+       key = 1;
+       /* check getsockopt for SAVED_SYN */
+       rv = bpf_map_lookup_elem(sock_map_fd, &key, &res);
+       EXPECT_EQ(0, rv, "d");
+       EXPECT_EQ(1, res, "d");
+       return 0;
+err:
+       return -1;
+}
+
 static int bpf_find_map(const char *test, struct bpf_object *obj,
                        const char *name)
 {
@@ -70,11 +90,11 @@ static int bpf_find_map(const char *test, struct bpf_object *obj,
 int main(int argc, char **argv)
 {
        const char *file = "test_tcpbpf_kern.o";
+       int prog_fd, map_fd, sock_map_fd;
        struct tcpbpf_globals g = {0};
        const char *cg_path = "/foo";
        int error = EXIT_FAILURE;
        struct bpf_object *obj;
-       int prog_fd, map_fd;
        int cg_fd = -1;
        __u32 key = 0;
        int rv;
@@ -110,6 +130,10 @@ int main(int argc, char **argv)
        if (map_fd < 0)
                goto err;
 
+       sock_map_fd = bpf_find_map(__func__, obj, "sockopt_results");
+       if (sock_map_fd < 0)
+               goto err;
+
        rv = bpf_map_lookup_elem(map_fd, &key, &g);
        if (rv != 0) {
                printf("FAILED: bpf_map_lookup_elem returns %d\n", rv);
@@ -121,6 +145,11 @@ int main(int argc, char **argv)
                goto err;
        }
 
+       if (verify_sockopt_result(sock_map_fd)) {
+               printf("FAILED: Wrong sockopt stats\n");
+               goto err;
+       }
+
        printf("PASSED!\n");
        error = 0;
 err: