All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stanislav Fomichev <sdf@google.com>
To: netdev@vger.kernel.org, bpf@vger.kernel.org
Cc: davem@davemloft.net, ast@kernel.org, daniel@iogearbox.net,
	Stanislav Fomichev <sdf@google.com>, Martin Lau <kafai@fb.com>
Subject: [PATCH bpf-next v6 7/9] selftests/bpf: add sockopt test that exercises BPF_F_ALLOW_MULTI
Date: Mon, 17 Jun 2019 11:01:07 -0700	[thread overview]
Message-ID: <20190617180109.34950-8-sdf@google.com> (raw)
In-Reply-To: <20190617180109.34950-1-sdf@google.com>

sockopt test that verifies chaining behavior when 0/2 is returned.

Cc: Martin Lau <kafai@fb.com>
Signed-off-by: Stanislav Fomichev <sdf@google.com>
---
 tools/testing/selftests/bpf/.gitignore        |   1 +
 tools/testing/selftests/bpf/Makefile          |   4 +-
 .../selftests/bpf/test_sockopt_multi.c        | 264 ++++++++++++++++++
 3 files changed, 268 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/bpf/test_sockopt_multi.c

diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore
index 8ac076c311d4..a2f7f79c7908 100644
--- a/tools/testing/selftests/bpf/.gitignore
+++ b/tools/testing/selftests/bpf/.gitignore
@@ -41,3 +41,4 @@ test_btf_dump
 xdping
 test_sockopt
 test_sockopt_sk
+test_sockopt_multi
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 33aa4f97af28..d3a5b6f9080d 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -26,7 +26,8 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test
 	test_sock test_btf test_sockmap test_lirc_mode2_user get_cgroup_id_user \
 	test_socket_cookie test_cgroup_storage test_select_reuseport test_section_names \
 	test_netcnt test_tcpnotify_user test_sock_fields test_sysctl test_hashmap \
-	test_btf_dump test_cgroup_attach xdping test_sockopt test_sockopt_sk
+	test_btf_dump test_cgroup_attach xdping test_sockopt test_sockopt_sk \
+	test_sockopt_multi
 
 BPF_OBJ_FILES = $(patsubst %.c,%.o, $(notdir $(wildcard progs/*.c)))
 TEST_GEN_FILES = $(BPF_OBJ_FILES)
@@ -103,6 +104,7 @@ $(OUTPUT)/test_sysctl: cgroup_helpers.c
 $(OUTPUT)/test_cgroup_attach: cgroup_helpers.c
 $(OUTPUT)/test_sockopt: cgroup_helpers.c
 $(OUTPUT)/test_sockopt_sk: cgroup_helpers.c
+$(OUTPUT)/test_sockopt_multi: cgroup_helpers.c
 
 .PHONY: force
 
diff --git a/tools/testing/selftests/bpf/test_sockopt_multi.c b/tools/testing/selftests/bpf/test_sockopt_multi.c
new file mode 100644
index 000000000000..e667d762e8d0
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_sockopt_multi.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <error.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <linux/filter.h>
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+
+#include "bpf_rlimit.h"
+#include "bpf_util.h"
+#include "cgroup_helpers.h"
+
+static char bpf_log_buf[BPF_LOG_BUF_SIZE];
+
+static struct bpf_insn prog_deny[] = {
+	BPF_MOV64_IMM(BPF_REG_0, 0),
+	BPF_EXIT_INSN(),
+};
+
+static struct bpf_insn prog_bypass[] = {
+	BPF_MOV64_IMM(BPF_REG_0, 2),
+	BPF_EXIT_INSN(),
+};
+
+static struct bpf_insn prog_inc[] = {
+	/* void *map_fd = NULL (to be filled by main()) */
+	BPF_LD_MAP_FD(BPF_REG_1, 0),
+
+	/* __u32 key = 0 */
+	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
+	BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0),
+
+	/* r0 = bpf_map_lookup(map_fd, 0) */
+	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+		     BPF_FUNC_map_lookup_elem),
+	/* if (r0 != NULL) { */
+	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
+	/* *r0 += 1 */
+	BPF_MOV64_IMM(BPF_REG_1, 1),
+	BPF_STX_XADD(BPF_W, BPF_REG_0, BPF_REG_1, 0),
+	/* } */
+
+	/* return 1 */
+	BPF_MOV64_IMM(BPF_REG_0, 1),
+	BPF_EXIT_INSN(),
+};
+
+static int read_cnt(int map_fd)
+{
+	int key = 0;
+	int val;
+
+	if (bpf_map_lookup_elem(map_fd, &key, &val) < 0)
+		error(-1, errno, "Failed to lookup the map");
+
+	return val;
+}
+
+int main(int argc, char **argv)
+{
+	int prog_deny_fd = -1, prog_bypass_fd = -1, prog_inc_fd = -1;
+	struct bpf_load_program_attr load_attr = {};
+	int cg_a = -1, cg_a_b = -1;
+	int err = EXIT_FAILURE;
+	char buf[1] = { 0x08 };
+	int sock_fd = -1;
+	int map_fd = -1;
+	int ret;
+
+	load_attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCKOPT,
+	load_attr.license = "GPL",
+	load_attr.expected_attach_type = BPF_CGROUP_SETSOCKOPT;
+
+	map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY,
+				sizeof(int), sizeof(int), 1, 0);
+	if (map_fd < 0) {
+		log_err("Failed to create map");
+		goto out;
+	}
+
+	prog_inc[0].imm = map_fd;
+
+	if (setup_cgroup_environment()) {
+		log_err("Failed to setup cgroup environment\n");
+		goto out;
+	}
+
+	cg_a = create_and_get_cgroup("/a");
+	if (cg_a < 0) {
+		log_err("Failed to create cgroup /a\n");
+		goto out;
+	}
+
+	cg_a_b = create_and_get_cgroup("/a/b");
+	if (cg_a_b < 0) {
+		log_err("Failed to create cgroup /a/b\n");
+		goto out;
+	}
+
+	if (join_cgroup("/a/b")) {
+		log_err("Failed to join cgroup /a/b\n");
+		goto out;
+	}
+
+	sock_fd = socket(AF_INET, SOCK_STREAM, 0);
+	if (sock_fd < 0) {
+		log_err("Failed to create socket");
+		goto out;
+	}
+
+	load_attr.insns = prog_deny;
+	load_attr.insns_cnt = ARRAY_SIZE(prog_deny);
+	prog_deny_fd = bpf_load_program_xattr(&load_attr, bpf_log_buf,
+					      sizeof(bpf_log_buf));
+	if (prog_deny_fd < 0) {
+		log_err("Failed to load prog_deny:\n%s\n", bpf_log_buf);
+		goto out;
+	}
+
+	load_attr.insns = prog_bypass;
+	load_attr.insns_cnt = ARRAY_SIZE(prog_bypass);
+	prog_bypass_fd = bpf_load_program_xattr(&load_attr, bpf_log_buf,
+						sizeof(bpf_log_buf));
+	if (prog_bypass_fd < 0) {
+		log_err("Failed to load prog_bypass:\n%s\n", bpf_log_buf);
+		goto out;
+	}
+
+	load_attr.insns = prog_inc;
+	load_attr.insns_cnt = ARRAY_SIZE(prog_inc);
+	prog_inc_fd = bpf_load_program_xattr(&load_attr, bpf_log_buf,
+					     sizeof(bpf_log_buf));
+	if (prog_inc_fd < 0) {
+		log_err("Failed to load prog_inc:\n%s\n", bpf_log_buf);
+		goto out;
+	}
+
+	if (bpf_prog_attach(prog_inc_fd, cg_a,
+			    BPF_CGROUP_SETSOCKOPT, BPF_F_ALLOW_MULTI)) {
+		log_err("Failed to attach prog_inc\n");
+		goto out;
+	}
+
+	/* No program was triggered so far, expected value is 0.
+	 */
+
+	ret = read_cnt(map_fd);
+	if (ret != 0) {
+		log_err("Unexpected initial map value %d != 0\n", ret);
+		goto out;
+	}
+
+	/* Call setsockopt that should trigger bpf program in the parent
+	 * cgroup and increase the counter to 1.
+	 */
+
+	if (setsockopt(sock_fd, SOL_IP, IP_TOS, buf, 1) < 0) {
+		log_err("Failed to call setsockopt(IP_TOS)");
+		goto out;
+	}
+
+	ret = read_cnt(map_fd);
+	if (ret != 1) {
+		log_err("Unexpected prog_inc sockopt map value %d != 1\n", ret);
+		goto out;
+	}
+
+	/* Attach program that returns 0 to current cgroup, parent program
+	 * should not trigger.
+	 */
+
+	if (bpf_prog_attach(prog_deny_fd, cg_a_b,
+			    BPF_CGROUP_SETSOCKOPT, BPF_F_ALLOW_MULTI)) {
+		log_err("Failed to attach prog_deny\n");
+		goto out;
+	}
+
+	if (setsockopt(sock_fd, SOL_IP, IP_TOS, buf, 1) >= 0) {
+		log_err("Unexpected success when calling setsockopt(IP_TOS)");
+		goto out;
+	}
+
+	ret = read_cnt(map_fd);
+	if (ret != 1) {
+		log_err("Unexpected prog_deny map value %d != 1\n", ret);
+		goto out;
+	}
+
+	/* Attach program that returns 2 to current cgroup, parent program
+	 * should not trigger.
+	 */
+
+	if (bpf_prog_detach2(prog_deny_fd, cg_a_b, BPF_CGROUP_SETSOCKOPT)) {
+		log_err("Failed to detach prog_deny\n");
+		goto out;
+	}
+
+	if (bpf_prog_attach(prog_bypass_fd, cg_a_b,
+			    BPF_CGROUP_SETSOCKOPT, BPF_F_ALLOW_MULTI)) {
+		log_err("Failed to attach prog_bypass\n");
+		goto out;
+	}
+
+	if (setsockopt(sock_fd, SOL_IP, IP_TOS, buf, 1) < 0) {
+		log_err("Failed to call setsockopt(IP_TOS)");
+		goto out;
+	}
+
+	ret = read_cnt(map_fd);
+	if (ret != 1) {
+		log_err("Unexpected prog_bypass map value %d != 1\n", ret);
+		goto out;
+	}
+
+	/* Attach the same program that increases the counters to current
+	 * cgroup, bpf program should trigger twice.
+	 */
+
+	if (bpf_prog_detach2(prog_bypass_fd, cg_a_b, BPF_CGROUP_SETSOCKOPT)) {
+		log_err("Failed to detach prog_deny\n");
+		goto out;
+	}
+
+	if (bpf_prog_attach(prog_inc_fd, cg_a_b,
+			    BPF_CGROUP_SETSOCKOPT, BPF_F_ALLOW_MULTI)) {
+		log_err("Failed to attach prog_inc\n");
+		goto out;
+	}
+
+	if (setsockopt(sock_fd, SOL_IP, IP_TOS, buf, 1) < 0) {
+		log_err("Failed to call setsockopt(IP_TOS)");
+		goto out;
+	}
+
+	ret = read_cnt(map_fd);
+	if (ret != 3) {
+		log_err("Unexpected 2x prog_inc map value %d != 3\n", ret);
+		goto out;
+	}
+
+	err = EXIT_SUCCESS;
+
+out:
+	bpf_prog_detach2(prog_inc_fd, cg_a, BPF_CGROUP_SETSOCKOPT);
+	bpf_prog_detach2(prog_inc_fd, cg_a_b, BPF_CGROUP_SETSOCKOPT);
+	close(prog_inc_fd);
+	close(prog_bypass_fd);
+	close(prog_deny_fd);
+	close(sock_fd);
+	close(cg_a_b);
+	close(cg_a);
+	close(map_fd);
+
+	printf("test_sockopt_multi: %s\n",
+	       err == EXIT_SUCCESS ? "PASSED" : "FAILED");
+	return err;
+}
-- 
2.22.0.410.gd8fdbe21b5-goog


  parent reply	other threads:[~2019-06-17 18:02 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-17 18:01 [PATCH bpf-next v6 0/9] bpf: getsockopt and setsockopt hooks Stanislav Fomichev
2019-06-17 18:01 ` [PATCH bpf-next v6 1/9] bpf: implement " Stanislav Fomichev
2019-06-18 16:31   ` Alexei Starovoitov
2019-06-18 16:49     ` Stanislav Fomichev
2019-06-18 18:09       ` Stanislav Fomichev
2019-06-18 18:41         ` Alexei Starovoitov
2019-06-18 18:53           ` Stanislav Fomichev
2019-06-17 18:01 ` [PATCH bpf-next v6 2/9] bpf: sync bpf.h to tools/ Stanislav Fomichev
2019-06-17 18:01 ` [PATCH bpf-next v6 3/9] libbpf: support sockopt hooks Stanislav Fomichev
2019-06-17 18:01 ` [PATCH bpf-next v6 4/9] selftests/bpf: test sockopt section name Stanislav Fomichev
2019-06-17 18:01 ` [PATCH bpf-next v6 5/9] selftests/bpf: add sockopt test Stanislav Fomichev
2019-06-17 18:01 ` [PATCH bpf-next v6 6/9] selftests/bpf: add sockopt test that exercises sk helpers Stanislav Fomichev
2019-06-17 18:01 ` Stanislav Fomichev [this message]
2019-06-17 18:01 ` [PATCH bpf-next v6 8/9] bpf: add sockopt documentation Stanislav Fomichev
2019-06-17 18:01 ` [PATCH bpf-next v6 9/9] bpftool: support cgroup sockopt Stanislav Fomichev

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190617180109.34950-8-sdf@google.com \
    --to=sdf@google.com \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=kafai@fb.com \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.