summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/bpf/test_maps.c
diff options
context:
space:
mode:
authorJohn Fastabend <john.fastabend@gmail.com>2017-08-15 22:34:22 -0700
committerDavid S. Miller <davem@davemloft.net>2017-08-16 11:27:53 -0700
commit6f6d33f3b3d0f53799d120d28abd13ad90041549 (patch)
treedbd263882c3bc49c8bc1d7a08b7d0eadd0f4ddb3 /tools/testing/selftests/bpf/test_maps.c
parent41bc94f535ef454e325a6d4db085ec345376de6c (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.c308
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();