diff options
author | John Fastabend <john.fastabend@gmail.com> | 2017-08-15 22:34:22 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-08-16 11:27:53 -0700 |
commit | 6f6d33f3b3d0f53799d120d28abd13ad90041549 (patch) | |
tree | dbd263882c3bc49c8bc1d7a08b7d0eadd0f4ddb3 /tools/testing/selftests/bpf/test_maps.c | |
parent | 41bc94f535ef454e325a6d4db085ec345376de6c (diff) |
bpf: selftests add sockmap tests
This generates a set of sockets, attaches BPF programs, and sends some
simple traffic using basic send/recv pattern. Additionally, we do a bunch
of negative tests to ensure adding/removing socks out of the sockmap fail
correctly.
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'tools/testing/selftests/bpf/test_maps.c')
-rw-r--r-- | tools/testing/selftests/bpf/test_maps.c | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index c991ab69a720..40b2d1faf02b 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c @@ -22,6 +22,7 @@ #include <linux/bpf.h> #include <bpf/bpf.h> +#include <bpf/libbpf.h> #include "bpf_util.h" static int map_flags; @@ -453,6 +454,312 @@ static void test_devmap(int task, void *data) close(fd); } +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <sys/select.h> +#include <linux/err.h> +#define SOCKMAP_PARSE_PROG "./sockmap_parse_prog.o" +#define SOCKMAP_VERDICT_PROG "./sockmap_verdict_prog.o" +static void test_sockmap(int task, void *data) +{ + int ports[] = {50200, 50201, 50202, 50204}; + int err, i, fd, sfd[6] = {0xdeadbeef}; + char buf[] = "hello sockmap user\n"; + int one = 1, map_fd, s, sc, rc; + int parse_prog, verdict_prog; + struct bpf_map *bpf_map; + struct sockaddr_in addr; + struct bpf_object *obj; + struct timeval to; + __u32 key, value; + fd_set w; + + /* Create some sockets to use with sockmap */ + for (i = 0; i < 2; i++) { + sfd[i] = socket(AF_INET, SOCK_STREAM, 0); + if (sfd[i] < 0) + goto out; + err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR, + (char *)&one, sizeof(one)); + if (err) { + printf("failed to setsockopt\n"); + goto out; + } + err = ioctl(sfd[i], FIONBIO, (char *)&one); + if (err < 0) { + printf("failed to ioctl\n"); + goto out; + } + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + addr.sin_port = htons(ports[i]); + err = bind(sfd[i], (struct sockaddr *)&addr, sizeof(addr)); + if (err < 0) { + printf("failed to bind: err %i: %i:%i\n", + err, i, sfd[i]); + goto out; + } + err = listen(sfd[i], 32); + if (err < 0) { + printf("failed to listeen\n"); + goto out; + } + } + + for (i = 2; i < 4; i++) { + sfd[i] = socket(AF_INET, SOCK_STREAM, 0); + if (sfd[i] < 0) + goto out; + err = setsockopt(sfd[i], SOL_SOCKET, SO_REUSEADDR, + (char *)&one, sizeof(one)); + if (err) { + printf("set sock opt\n"); + goto out; + } + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + addr.sin_port = htons(ports[i - 2]); + err = connect(sfd[i], (struct sockaddr *)&addr, sizeof(addr)); + if (err) { + printf("failed to conenct\n"); + goto out; + } + } + + + for (i = 4; i < 6; i++) { + sfd[i] = accept(sfd[i - 4], NULL, NULL); + if (sfd[i] < 0) { + printf("accept failed\n"); + goto out; + } + } + + /* Test sockmap with connected sockets */ + fd = bpf_create_map(BPF_MAP_TYPE_SOCKMAP, + sizeof(key), sizeof(value), + 6, 0); + if (fd < 0) { + printf("Failed to create sockmap %i\n", fd); + goto out_sockmap; + } + + /* Nothing attached so these should fail */ + for (i = 0; i < 6; i++) { + err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY); + if (!err) { + printf("Failed invalid update sockmap '%i:%i'\n", + i, sfd[i]); + goto out_sockmap; + } + } + + /* Test attaching bad fds */ + err = __bpf_prog_attach(-1, -2, fd, BPF_CGROUP_SMAP_INGRESS, 0); + if (!err) { + printf("Failed invalid prog attach\n"); + goto out_sockmap; + } + + /* Load SK_SKB program and Attach */ + err = bpf_prog_load(SOCKMAP_PARSE_PROG, + BPF_PROG_TYPE_SK_SKB, &obj, &parse_prog); + if (err) { + printf("Failed to load SK_SKB parse prog\n"); + goto out_sockmap; + } + + err = bpf_prog_load(SOCKMAP_VERDICT_PROG, + BPF_PROG_TYPE_SK_SKB, &obj, &verdict_prog); + if (err) { + printf("Failed to load SK_SKB verdict prog\n"); + goto out_sockmap; + } + + bpf_map = bpf_object__find_map_by_name(obj, "sock_map"); + if (IS_ERR(bpf_map)) { + printf("Failed to load map from verdict prog\n"); + goto out_sockmap; + } + + map_fd = bpf_map__fd(bpf_map); + if (map_fd < 0) { + printf("Failed to get map fd\n"); + goto out_sockmap; + } + + err = __bpf_prog_attach(parse_prog, verdict_prog, map_fd, + BPF_CGROUP_SMAP_INGRESS, 0); + if (err) { + printf("Failed bpf prog attach\n"); + goto out_sockmap; + } + + /* Test map update elem */ + for (i = 0; i < 6; i++) { + err = bpf_map_update_elem(map_fd, &i, &sfd[i], BPF_ANY); + if (err) { + printf("Failed map_fd update sockmap %i '%i:%i'\n", + err, i, sfd[i]); + goto out_sockmap; + } + } + + /* Test map delete elem and remove send/recv sockets */ + for (i = 2; i < 4; i++) { + err = bpf_map_delete_elem(map_fd, &i); + if (err) { + printf("Failed delete sockmap %i '%i:%i'\n", + err, i, sfd[i]); + goto out_sockmap; + } + } + + /* Test map send/recv */ + sc = send(sfd[2], buf, 10, 0); + if (sc < 0) { + printf("Failed sockmap send\n"); + goto out_sockmap; + } + + FD_ZERO(&w); + FD_SET(sfd[3], &w); + to.tv_sec = 1; + to.tv_usec = 0; + s = select(sfd[3] + 1, &w, NULL, NULL, &to); + if (s == -1) { + perror("Failed sockmap select()"); + goto out_sockmap; + } else if (!s) { + printf("Failed sockmap unexpected timeout\n"); + goto out_sockmap; + } + + if (!FD_ISSET(sfd[3], &w)) { + printf("Failed sockmap select/recv\n"); + goto out_sockmap; + } + + rc = recv(sfd[3], buf, sizeof(buf), 0); + if (rc < 0) { + printf("Failed sockmap recv\n"); + goto out_sockmap; + } + + /* Delete the reset of the elems include some NULL elems */ + for (i = 0; i < 6; i++) { + err = bpf_map_delete_elem(map_fd, &i); + if (err && (i == 0 || i == 1 || i >= 4)) { + printf("Failed delete sockmap %i '%i:%i'\n", + err, i, sfd[i]); + goto out_sockmap; + } else if (!err && (i == 2 || i == 3)) { + printf("Failed null delete sockmap %i '%i:%i'\n", + err, i, sfd[i]); + goto out_sockmap; + } + } + + /* Test having multiple SMAPs open and active on same fds */ + err = __bpf_prog_attach(parse_prog, verdict_prog, fd, + BPF_CGROUP_SMAP_INGRESS, 0); + if (err) { + printf("Failed fd bpf prog attach\n"); + goto out_sockmap; + } + + for (i = 0; i < 6; i++) { + err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY); + if (err) { + printf("Failed fd update sockmap %i '%i:%i'\n", + err, i, sfd[i]); + goto out_sockmap; + } + } + + /* Test duplicate socket add of NOEXIST, ANY and EXIST */ + i = 0; + err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST); + if (!err) { + printf("Failed BPF_NOEXIST create\n"); + goto out_sockmap; + } + + err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY); + if (err) { + printf("Failed sockmap update BPF_ANY\n"); + goto out_sockmap; + } + + err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST); + if (err) { + printf("Failed sockmap update BPF_EXIST\n"); + goto out_sockmap; + } + + /* The above were pushing fd into same slot try different slot now */ + i = 2; + err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_NOEXIST); + if (!err) { + printf("Failed BPF_NOEXIST create\n"); + goto out_sockmap; + } + + err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_ANY); + if (err) { + printf("Failed sockmap update BPF_ANY\n"); + goto out_sockmap; + } + + err = bpf_map_update_elem(fd, &i, &sfd[i], BPF_EXIST); + if (err) { + printf("Failed sockmap update BPF_EXIST\n"); + goto out_sockmap; + } + + /* Try pushing fd into different map, this is not allowed at the + * moment. Which programs would we use? + */ + err = bpf_map_update_elem(map_fd, &i, &sfd[i], BPF_NOEXIST); + if (!err) { + printf("Failed BPF_NOEXIST create\n"); + goto out_sockmap; + } + + err = bpf_map_update_elem(map_fd, &i, &sfd[i], BPF_ANY); + if (!err) { + printf("Failed sockmap update BPF_ANY\n"); + goto out_sockmap; + } + + err = bpf_map_update_elem(map_fd, &i, &sfd[i], BPF_EXIST); + if (!err) { + printf("Failed sockmap update BPF_EXIST\n"); + goto out_sockmap; + } + + /* Test map close sockets */ + for (i = 0; i < 6; i++) + close(sfd[i]); + close(fd); + close(map_fd); + bpf_object__close(obj); + return; +out: + for (i = 0; i < 6; i++) + close(sfd[i]); + printf("Failed to create sockmap '%i:%s'!\n", i, strerror(errno)); + exit(1); +out_sockmap: + for (i = 0; i < 6; i++) + close(sfd[i]); + close(fd); + exit(1); +} + #define MAP_SIZE (32 * 1024) static void test_map_large(void) @@ -621,6 +928,7 @@ static void run_all_tests(void) test_arraymap_percpu_many_keys(); test_devmap(0, NULL); + test_sockmap(0, NULL); test_map_large(); test_map_parallel(); |