All of lore.kernel.org
 help / color / mirror / Atom feed
From: John Fastabend <john.fastabend@gmail.com>
To: jakub@cloudflare.com, bpf@vger.kernel.org
Cc: netdev@vger.kernel.org, john.fastabend@gmail.com, andrii@kernel.org
Subject: [PATCH bpf-next v2 1/4] bpf: sockmap, add test for sk_msg prog pop msg helper
Date: Wed, 24 Jan 2024 10:54:00 -0800	[thread overview]
Message-ID: <20240124185403.1104141-2-john.fastabend@gmail.com> (raw)
In-Reply-To: <20240124185403.1104141-1-john.fastabend@gmail.com>

For msg_pop sk_msg helpers we only have older tests in test_sockmap, but
these are showing their age. They don't use any of the newer style BPF
and also require running test_sockmap. Lets use the prog_test framework
and add a test for msg_pop.

This is a much nicer test env using newer style BPF. We can
extend this to support all the other helpers shortly.

The bpf program is a template that lets us run through all the helpers
so we can cover not just pop, but all the other helpers as well.

Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
 .../bpf/prog_tests/sockmap_helpers.h          |  10 +
 .../bpf/prog_tests/sockmap_msg_helpers.c      | 210 ++++++++++++++++++
 .../bpf/progs/test_sockmap_msg_helpers.c      |  52 +++++
 3 files changed, 272 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/sockmap_msg_helpers.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_sockmap_msg_helpers.c

diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_helpers.h b/tools/testing/selftests/bpf/prog_tests/sockmap_helpers.h
index e880f97bc44d..781cbdf01d7b 100644
--- a/tools/testing/selftests/bpf/prog_tests/sockmap_helpers.h
+++ b/tools/testing/selftests/bpf/prog_tests/sockmap_helpers.h
@@ -112,6 +112,16 @@
 		__ret;                                                         \
 	})
 
+#define xrecv_nonblock(fd, buf, len, flags)                                    \
+	({                                                                     \
+		ssize_t __ret = recv_timeout((fd), (buf), (len), (flags),      \
+					     IO_TIMEOUT_SEC);                  \
+		if (__ret == -1)                                               \
+			FAIL_ERRNO("recv");                                    \
+		__ret;                                                         \
+	})
+
+
 #define xsocket(family, sotype, flags)                                         \
 	({                                                                     \
 		int __ret = socket(family, sotype, flags);                     \
diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_msg_helpers.c b/tools/testing/selftests/bpf/prog_tests/sockmap_msg_helpers.c
new file mode 100644
index 000000000000..9ffe02f45808
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/sockmap_msg_helpers.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2020 Cloudflare
+#include <error.h>
+#include <netinet/tcp.h>
+#include <sys/epoll.h>
+
+#include "test_progs.h"
+#include "test_sockmap_msg_helpers.skel.h"
+#include "sockmap_helpers.h"
+
+#define TCP_REPAIR		19	/* TCP sock is under repair right now */
+
+#define TCP_REPAIR_ON		1
+#define TCP_REPAIR_OFF_NO_WP	-1	/* Turn off without window probes */
+
+struct msg_test_opts {
+	struct test_sockmap_msg_helpers *skel;
+	int server;
+	int client;
+};
+
+#define POP_END -1
+
+static void pop_simple_send(struct msg_test_opts *opts, int start, int len)
+{
+	struct test_sockmap_msg_helpers *skel = opts->skel;
+	char buf[] = "abcdefghijklmnopqrstuvwxyz";
+	char recvbuf[sizeof(buf)];
+	size_t sent, recv, cmp;
+
+	skel->bss->pop = true;
+
+	if (start == -1)
+		start = sizeof(buf) - len - 1;
+
+	skel->bss->pop_start = start;
+	skel->bss->pop_len = len;
+
+	sent = xsend(opts->client, buf, sizeof(buf), 0);
+	if (sent < sizeof(buf))
+		FAIL("xsend failed");
+
+	ASSERT_OK(skel->bss->err, "pop error");
+
+	recv = xrecv_nonblock(opts->server, recvbuf, sizeof(buf), 0);
+	if (recv != sent - skel->bss->pop_len)
+		FAIL("Received incorrect number number of bytes after pop");
+
+	cmp = memcmp(&buf[0], &recvbuf[0], start);
+	ASSERT_OK(cmp, "pop cmp start bytes failed");
+	cmp = memcmp(&buf[start+len], &recvbuf[start], sizeof(buf) - start - len);
+	ASSERT_OK(cmp, "pop cmp end bytes failed");
+}
+
+static void test_sockmap_pop(void)
+{
+	struct msg_test_opts opts;
+	struct test_sockmap_msg_helpers *skel;
+	int s, client, server;
+	int err, map, prog;
+
+	skel = test_sockmap_msg_helpers__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "open_and_load"))
+		return;
+
+	map = bpf_map__fd(skel->maps.sock_map);
+	prog = bpf_program__fd(skel->progs.msg_helpers);
+	err = bpf_prog_attach(prog, map, BPF_SK_MSG_VERDICT, 0);
+	if (!ASSERT_OK(err, "bpf_prog_attach"))
+		goto out;
+
+	s = socket_loopback(AF_INET, SOCK_STREAM);
+	if (s < 0)
+		goto out;
+
+	err = create_pair(s, AF_INET, SOCK_STREAM, &client, &server);
+	if (err < 0)
+		goto close_loopback;
+
+	err = add_to_sockmap(map, client, server);
+	if (err < 0)
+		goto close_sockets;
+
+	opts.client = client;
+	opts.server = server;
+	opts.skel = skel;
+
+	/* Pop from start */
+	pop_simple_send(&opts, 0, 5);
+	/* Pop from the middle */
+	pop_simple_send(&opts, 10, 5);
+	/* Pop from end */
+	pop_simple_send(&opts, POP_END, 5);
+
+close_sockets:
+	close(client);
+	close(server);
+close_loopback:
+	close(s);
+out:
+	test_sockmap_msg_helpers__destroy(skel);
+}
+
+static void test_sockmap_pop_errors(void)
+{
+	char buf[] = "abcdefghijklmnopqrstuvwxyz";
+	struct test_sockmap_msg_helpers *skel;
+	int i, recv, err, map, prog;
+	char recvbuf[sizeof(buf)];
+	int s, client, server;
+
+	skel = test_sockmap_msg_helpers__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "open_and_load"))
+		return;
+
+	map = bpf_map__fd(skel->maps.sock_map);
+	prog = bpf_program__fd(skel->progs.msg_helpers);
+	err = bpf_prog_attach(prog, map, BPF_SK_MSG_VERDICT, 0);
+	if (!ASSERT_OK(err, "bpf_prog_attach"))
+		goto out;
+
+	s = socket_loopback(AF_INET, SOCK_STREAM);
+	if (s < 0)
+		goto out;
+
+	err = create_pair(s, AF_INET, SOCK_STREAM, &client, &server);
+	if (err < 0)
+		goto close_loopback;
+
+	err = add_to_sockmap(map, client, server);
+	if (err < 0)
+		goto close_sockets;
+
+	skel->bss->pop = true;
+
+	/* Pop larger than buffer */
+	skel->bss->pop_start = 0;
+	skel->bss->pop_len = sizeof(buf) + 1;
+	xsend(client, buf, sizeof(buf), 0);
+	ASSERT_ERR(skel->bss->err, "popping more bytes than msg did not throw an error");
+	xrecv_nonblock(server, recvbuf, sizeof(recvbuf), 0);
+
+	/* Pop past end of buffer */
+	skel->bss->pop_start = sizeof(buf) - 5;
+	skel->bss->pop_len = 10;
+	xsend(client, buf, sizeof(buf), 0);
+	ASSERT_ERR(skel->bss->err, "popping past end of msg did not throw an error");
+	xrecv_nonblock(server, recvbuf, sizeof(recvbuf), 0);
+
+	/* Pop larger than buffer on complex send */
+	skel->bss->pop_start = 0;
+	skel->bss->pop_len = 0;
+	for (i = 0; i < 14; i++)
+		xsend(client, buf, sizeof(buf), MSG_MORE);
+	skel->bss->pop_start = 0;
+	skel->bss->pop_len = sizeof(buf) * 32;
+	xsend(client, buf, sizeof(buf), MSG_MORE);
+	ASSERT_ERR(skel->bss->err, "popping more bytes than sg msg did not throw an error");
+	i = 0;
+	do {
+		i++;
+		recv = xrecv_nonblock(server, recvbuf, sizeof(recvbuf), 0);
+	} while (recv > 0 && i < 15);
+
+	/* Pop past end of complex send */
+	skel->bss->pop_start = 0;
+	skel->bss->pop_len = 0;
+	for (i = 0; i < 14; i++)
+		xsend(client, buf, sizeof(buf), MSG_MORE);
+	skel->bss->pop_start = sizeof(buf) * 14;
+	skel->bss->pop_len = sizeof(buf) + 1;
+	xsend(client, buf, sizeof(buf), MSG_MORE);
+	ASSERT_ERR(skel->bss->err, "popping past end of sg msg did not throw an error");
+	i = 0;
+	do {
+		i++;
+		recv = xrecv_nonblock(server, recvbuf, sizeof(recvbuf), 0);
+	} while (recv > 0 && i < 15);
+
+	/* Pop past end of complex send starting in middle of last sg */
+	skel->bss->pop_start = 0;
+	skel->bss->pop_len = 0;
+	for (i = 0; i < 14; i++)
+		xsend(client, buf, sizeof(buf), MSG_MORE);
+	skel->bss->pop_start = (sizeof(buf) * 14) + sizeof(buf) - 5;
+	skel->bss->pop_len = 10;
+	xsend(client, buf, sizeof(buf), MSG_MORE);
+	ASSERT_ERR(skel->bss->err, "popping past end from offset of sg msg did not throw an error");
+	i = 0;
+	do {
+		i++;
+		recv = xrecv_nonblock(server, recvbuf, sizeof(recvbuf), 0);
+	} while (recv > 0 && i < 15);
+
+close_sockets:
+	close(client);
+	close(server);
+close_loopback:
+	close(s);
+out:
+	test_sockmap_msg_helpers__destroy(skel);
+}
+
+void test_sockmap_msg_helpers(void)
+{
+	if (test__start_subtest("sockmap pop"))
+		test_sockmap_pop();
+	if (test__start_subtest("sockmap pop errors"))
+		test_sockmap_pop_errors();
+}
diff --git a/tools/testing/selftests/bpf/progs/test_sockmap_msg_helpers.c b/tools/testing/selftests/bpf/progs/test_sockmap_msg_helpers.c
new file mode 100644
index 000000000000..c721a00b6001
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_sockmap_msg_helpers.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2020 Cloudflare
+
+#include <errno.h>
+#include <stdbool.h>
+#include <linux/bpf.h>
+
+#include <bpf/bpf_helpers.h>
+
+struct {
+	__uint(type, BPF_MAP_TYPE_SOCKMAP);
+	__uint(max_entries, 2);
+	__type(key, __u32);
+	__type(value, __u64);
+} sock_map SEC(".maps");
+
+int cork = 0;
+
+bool pull = false;
+bool push = false;
+bool pop = false;
+
+int pull_start = 0;
+int pull_end = 0;
+
+int push_start = 0;
+int push_end = 0;
+
+int pop_start = 0;
+int pop_len = 0;
+
+int err;
+
+SEC("sk_msg")
+int msg_helpers(struct sk_msg_md *msg)
+{
+	if (cork)
+		err = bpf_msg_cork_bytes(msg, cork);
+
+	if (pull)
+		err = bpf_msg_pull_data(msg, pull_start, pull_end, 0);
+
+	if (push)
+		err = bpf_msg_push_data(msg, push_start, push_end, 0);
+
+	if (pop)
+		err = bpf_msg_pop_data(msg, pop_start, pop_len, 0);
+
+	return SK_PASS;
+}
+
+char _license[] SEC("license") = "GPL";
-- 
2.33.0


  reply	other threads:[~2024-01-24 18:54 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-24 18:53 [PATCH bpf-next v2 0/4] transition sockmap testing to test_progs John Fastabend
2024-01-24 18:54 ` John Fastabend [this message]
2024-01-26 11:48   ` [PATCH bpf-next v2 1/4] bpf: sockmap, add test for sk_msg prog pop msg helper Jakub Sitnicki
2024-01-26 15:37     ` John Fastabend
2024-01-24 18:54 ` [PATCH bpf-next v2 2/4] bpf: sockmap, add a sendmsg test so we can check that path John Fastabend
2024-01-26 12:17   ` Jakub Sitnicki
2024-01-26 14:24     ` Jakub Sitnicki
2024-01-26 15:38     ` John Fastabend
2024-01-24 18:54 ` [PATCH bpf-next v2 3/4] bpf: sockmap, add a cork to force buffering of the scatterlist John Fastabend
2024-01-26 14:19   ` Jakub Sitnicki
2024-01-26 15:38     ` John Fastabend
2024-01-24 18:54 ` [PATCH bpf-next v2 4/4] bpf: sockmap test cork and pop combined John Fastabend
2024-01-24 22:58 ` [PATCH bpf-next v2 0/4] transition sockmap testing to test_progs John Fastabend
2024-01-26 14:39 ` Jakub Sitnicki
2024-01-26 15:40   ` John Fastabend

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=20240124185403.1104141-2-john.fastabend@gmail.com \
    --to=john.fastabend@gmail.com \
    --cc=andrii@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=jakub@cloudflare.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.