All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH mptcp-next v5 0/3] fixes for "new MPTCP subflow subtest v4"
@ 2024-08-29  2:53 Geliang Tang
  2024-08-29  2:53 ` [PATCH mptcp-next v5 1/3] selftests/bpf: Add getsockopt to inspect mptcp subflow Geliang Tang
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Geliang Tang @ 2024-08-29  2:53 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

From: Geliang Tang <tanggeliang@kylinos.cn>

v5:
 - rename _check_getsockopt_subflows_mark in patch 1.
 - address Matt's comments in v4.

v4:
 - address Matt's comments in v3.

v3:
 - drop "ss_search" from subflow subtest
 - fix mptcp_for_each_subflow_safe
 - add cond_break in list_for_each_entry/_safe

Two fixes address Martin's comments in "new MPTCP subflow subtest" v4.
Patch 2 will conflict with "selftests/bpf: Add bpf_first scheduler & test".

Geliang Tang (3):
  selftests/bpf: Add getsockopt to inspect mptcp subflow
  Squash to "selftests/bpf: Add mptcp subflow subtest"
  Squash to "selftests/bpf: Add bpf scheduler test"

 .../testing/selftests/bpf/prog_tests/mptcp.c  | 60 +++++++++++-------
 tools/testing/selftests/bpf/progs/mptcp_bpf.h | 35 +++++++++++
 .../selftests/bpf/progs/mptcp_subflow.c       | 62 +++++++++++++++++++
 3 files changed, 135 insertions(+), 22 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH mptcp-next v5 1/3] selftests/bpf: Add getsockopt to inspect mptcp subflow
  2024-08-29  2:53 [PATCH mptcp-next v5 0/3] fixes for "new MPTCP subflow subtest v4" Geliang Tang
@ 2024-08-29  2:53 ` Geliang Tang
  2024-08-29 14:25   ` Matthieu Baerts
  2024-08-29  2:53 ` [PATCH mptcp-next v5 2/3] Squash to "selftests/bpf: Add mptcp subflow subtest" Geliang Tang
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: Geliang Tang @ 2024-08-29  2:53 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang, Martin KaFai Lau

From: Geliang Tang <tanggeliang@kylinos.cn>

This patch adds a "cgroup/getsockopt" way to inspect the subflows of a
mptcp socket.

mptcp_for_each_stubflow() and other helpers related to list_dentry are
added into progs/mptcp_bpf.h.

Add an extra "cgroup/getsockopt" prog to walk the msk->conn_list and use
bpf_core_cast to cast a pointer to tcp_sock for readonly. It will allow
to inspect all the fields in a tcp_sock.

Suggested-by: Martin KaFai Lau <martin.lau@kernel.org>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
 tools/testing/selftests/bpf/progs/mptcp_bpf.h | 35 +++++++++++
 .../selftests/bpf/progs/mptcp_subflow.c       | 62 +++++++++++++++++++
 2 files changed, 97 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/mptcp_bpf.h b/tools/testing/selftests/bpf/progs/mptcp_bpf.h
index 782f36ed027e..d60e3c8f85a1 100644
--- a/tools/testing/selftests/bpf/progs/mptcp_bpf.h
+++ b/tools/testing/selftests/bpf/progs/mptcp_bpf.h
@@ -4,9 +4,44 @@
 
 #include <vmlinux.h>
 #include <bpf/bpf_core_read.h>
+#include "bpf_experimental.h"
 
 #define MPTCP_SUBFLOWS_MAX 8
 
+static inline int list_is_head(const struct list_head *list,
+			       const struct list_head *head)
+{
+	return list == head;
+}
+
+#define list_entry(ptr, type, member)					\
+	container_of(ptr, type, member)
+
+#define list_first_entry(ptr, type, member)				\
+	list_entry((ptr)->next, type, member)
+
+#define list_next_entry(pos, member)					\
+	list_entry((pos)->member.next, typeof(*(pos)), member)
+
+#define list_entry_is_head(pos, head, member)				\
+	list_is_head(&pos->member, (head))
+
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_first_entry(head, typeof(*pos), member);	\
+	     cond_break, !list_entry_is_head(pos, head, member);	\
+	     pos = list_next_entry(pos, member))
+
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_first_entry(head, typeof(*pos), member),	\
+		n = list_next_entry(pos, member);			\
+	     cond_break, !list_entry_is_head(pos, head, member);	\
+	     pos = n, n = list_next_entry(n, member))
+
+#define mptcp_for_each_subflow(__msk, __subflow)			\
+	list_for_each_entry(__subflow, &((__msk)->conn_list), node)
+#define mptcp_for_each_subflow_safe(__msk, __subflow, __tmp)		\
+	list_for_each_entry_safe(__subflow, __tmp, &((__msk)->conn_list), node)
+
 extern void mptcp_subflow_set_scheduled(struct mptcp_subflow_context *subflow,
 					bool scheduled) __ksym;
 
diff --git a/tools/testing/selftests/bpf/progs/mptcp_subflow.c b/tools/testing/selftests/bpf/progs/mptcp_subflow.c
index bc572e1d6df8..6a7cf71c2795 100644
--- a/tools/testing/selftests/bpf/progs/mptcp_subflow.c
+++ b/tools/testing/selftests/bpf/progs/mptcp_subflow.c
@@ -4,6 +4,7 @@
 
 /* vmlinux.h, bpf_helpers.h and other 'define' */
 #include "bpf_tracing_net.h"
+#include "mptcp_bpf.h"
 
 char _license[] SEC("license") = "GPL";
 
@@ -57,3 +58,64 @@ int mptcp_subflow(struct bpf_sock_ops *skops)
 
 	return 1;
 }
+
+static int _check_getsockopt_subflow_mark(struct mptcp_sock *msk, struct bpf_sockopt *ctx)
+{
+	struct mptcp_subflow_context *subflow;
+	int i = 0;
+
+	mptcp_for_each_subflow(msk, subflow) {
+		struct sock *ssk;
+
+		ssk = mptcp_subflow_tcp_sock(bpf_core_cast(subflow,
+							   struct mptcp_subflow_context));
+
+		if (ssk->sk_mark != ++i)
+			ctx->retval = -1;
+	}
+
+	return 1;
+}
+
+static int _check_getsockopt_subflow_cc(struct mptcp_sock *msk, struct bpf_sockopt *ctx)
+{
+	struct mptcp_subflow_context *subflow, *tmp;
+
+	mptcp_for_each_subflow_safe(msk, subflow, tmp) {
+		struct inet_connection_sock *icsk;
+		struct sock *ssk;
+
+		ssk = mptcp_subflow_tcp_sock(bpf_core_cast(subflow,
+							   struct mptcp_subflow_context));
+		icsk = bpf_core_cast(ssk, struct inet_connection_sock);
+
+		if ((ssk->sk_mark == 1 &&
+		     __builtin_memcmp(icsk->icsk_ca_ops->name, cc, TCP_CA_NAME_MAX)) ||
+		    (ssk->sk_mark == 2 &&
+		     __builtin_memcmp(icsk->icsk_ca_ops->name, "cubic", TCP_CA_NAME_MAX)))
+			ctx->retval = -1;
+	}
+
+	return 1;
+}
+
+SEC("cgroup/getsockopt")
+int _getsockopt_subflow(struct bpf_sockopt *ctx)
+{
+	struct bpf_sock *sk = ctx->sk;
+	struct mptcp_sock *msk;
+
+	if (!sk || sk->protocol != IPPROTO_MPTCP)
+		return 1;
+
+	msk = bpf_core_cast(sk, struct mptcp_sock);
+	if (msk->pm.subflows != 1)
+		return 1;
+
+	if (ctx->level == SOL_SOCKET && ctx->optname == SO_MARK)
+		return _check_getsockopt_subflow_mark(msk, ctx);
+	if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION)
+		return _check_getsockopt_subflow_cc(msk, ctx);
+
+	return 1;
+}
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH mptcp-next v5 2/3] Squash to "selftests/bpf: Add mptcp subflow subtest"
  2024-08-29  2:53 [PATCH mptcp-next v5 0/3] fixes for "new MPTCP subflow subtest v4" Geliang Tang
  2024-08-29  2:53 ` [PATCH mptcp-next v5 1/3] selftests/bpf: Add getsockopt to inspect mptcp subflow Geliang Tang
@ 2024-08-29  2:53 ` Geliang Tang
  2024-08-29 14:38   ` Matthieu Baerts
  2024-08-29  2:53 ` [PATCH mptcp-next v5 3/3] Squash to "selftests/bpf: Add bpf scheduler test" Geliang Tang
  2024-09-02 17:48 ` [PATCH mptcp-next v5 0/3] fixes for "new MPTCP subflow subtest v4" MPTCP CI
  3 siblings, 1 reply; 8+ messages in thread
From: Geliang Tang @ 2024-08-29  2:53 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

From: Geliang Tang <tanggeliang@kylinos.cn>

Drop ss_search() from run_subflow().

Use the "cgroup/getsockopt" way to inspect the subflows.

Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
 .../testing/selftests/bpf/prog_tests/mptcp.c  | 52 +++++++++++--------
 1 file changed, 31 insertions(+), 21 deletions(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c
index 73adc58cd776..85883515c67b 100644
--- a/tools/testing/selftests/bpf/prog_tests/mptcp.c
+++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c
@@ -368,22 +368,13 @@ static int endpoint_init(char *flags)
 	return -1;
 }
 
-static int _ss_search(char *src, char *dst, char *port, char *keyword)
-{
-	return SYS_NOFAIL("ip netns exec %s ss -enita src %s dst %s %s %d | grep -q '%s'",
-			  NS_TEST, src, dst, port, PORT_1, keyword);
-}
-
-static int ss_search(char *src, char *keyword)
-{
-	return _ss_search(src, ADDR_1, "dport", keyword);
-}
-
 static void run_subflow(char *new)
 {
-	int server_fd, client_fd, err;
+	int server_fd, client_fd, err, i;
 	char cc[TCP_CA_NAME_MAX];
+	unsigned int mark;
 	socklen_t len;
+	u8 subflows;
 
 	server_fd = start_mptcp_server(AF_INET, ADDR_1, PORT_1, 0);
 	if (!ASSERT_GE(server_fd, 0, "start_mptcp_server"))
@@ -393,17 +384,29 @@ static void run_subflow(char *new)
 	if (!ASSERT_GE(client_fd, 0, "connect to fd"))
 		goto close_server;
 
-	len = sizeof(cc);
-	err = getsockopt(server_fd, SOL_TCP, TCP_CONGESTION, cc, &len);
-	if (!ASSERT_OK(err, "getsockopt(server_fd, TCP_CONGESTION)"))
-		goto close_client;
-
 	send_byte(client_fd);
 
-	ASSERT_OK(ss_search(ADDR_1, "fwmark:0x1"), "ss_search fwmark:0x1");
-	ASSERT_OK(ss_search(ADDR_2, "fwmark:0x2"), "ss_search fwmark:0x2");
-	ASSERT_OK(ss_search(ADDR_1, new), "ss_search new cc");
-	ASSERT_OK(ss_search(ADDR_2, cc), "ss_search default cc");
+	len = sizeof(subflows);
+	/* Wait max 1 sec for new subflows to be created */
+	for (i = 0; i < 10; i++) {
+		err = getsockopt(client_fd, SOL_MPTCP, MPTCP_INFO, &subflows, &len);
+		if (!err && subflows > 0)
+			break;
+
+		sleep(0.1);
+	}
+
+	len = sizeof(mark);
+	err = getsockopt(client_fd, SOL_SOCKET, SO_MARK, &mark, &len);
+	if (!ASSERT_OK(err, "getsockopt(client_fd, SO_MARK)"))
+		goto close_client;
+	ASSERT_EQ(mark, 0, "mark");
+
+	len = sizeof(cc);
+	err = getsockopt(client_fd, SOL_TCP, TCP_CONGESTION, cc, &len);
+	if (!ASSERT_OK(err, "getsockopt(client_fd, TCP_CONGESTION)"))
+		goto close_client;
+	ASSERT_STREQ(cc, new, "cc");
 
 close_client:
 	close(client_fd);
@@ -416,6 +419,7 @@ static void test_subflow(void)
 	int cgroup_fd, prog_fd, err;
 	struct mptcp_subflow *skel;
 	struct nstoken *nstoken;
+	struct bpf_link *link;
 
 	cgroup_fd = test__join_cgroup("/mptcp_subflow");
 	if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup: mptcp_subflow"))
@@ -441,6 +445,11 @@ static void test_subflow(void)
 	if (endpoint_init("subflow") < 0)
 		goto close_netns;
 
+	link = bpf_program__attach_cgroup(skel->progs._getsockopt_subflow,
+					  cgroup_fd);
+	if (!ASSERT_OK_PTR(link, "getsockopt prog"))
+		goto close_netns;
+
 	run_subflow(skel->data->cc);
 
 close_netns:
@@ -448,6 +457,7 @@ static void test_subflow(void)
 skel_destroy:
 	mptcp_subflow__destroy(skel);
 close_cgroup:
+	bpf_link__destroy(link);
 	close(cgroup_fd);
 }
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH mptcp-next v5 3/3] Squash to "selftests/bpf: Add bpf scheduler test"
  2024-08-29  2:53 [PATCH mptcp-next v5 0/3] fixes for "new MPTCP subflow subtest v4" Geliang Tang
  2024-08-29  2:53 ` [PATCH mptcp-next v5 1/3] selftests/bpf: Add getsockopt to inspect mptcp subflow Geliang Tang
  2024-08-29  2:53 ` [PATCH mptcp-next v5 2/3] Squash to "selftests/bpf: Add mptcp subflow subtest" Geliang Tang
@ 2024-08-29  2:53 ` Geliang Tang
  2024-09-02 17:48 ` [PATCH mptcp-next v5 0/3] fixes for "new MPTCP subflow subtest v4" MPTCP CI
  3 siblings, 0 replies; 8+ messages in thread
From: Geliang Tang @ 2024-08-29  2:53 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

From: Geliang Tang <tanggeliang@kylinos.cn>

Now ss_search() are only used by bpf_sched tests. It will be dropped
in next step.

Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
 tools/testing/selftests/bpf/prog_tests/mptcp.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c
index 85883515c67b..9b4d054462ad 100644
--- a/tools/testing/selftests/bpf/prog_tests/mptcp.c
+++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c
@@ -480,9 +480,15 @@ static struct nstoken *sched_init(char *flags, char *sched)
 	return NULL;
 }
 
+static int ss_search(char *src, char *dst, char *port, char *keyword)
+{
+	return SYS_NOFAIL("ip netns exec %s ss -enita src %s dst %s %s %d | grep -q '%s'",
+			  NS_TEST, src, dst, port, PORT_1, keyword);
+}
+
 static int has_bytes_sent(char *dst)
 {
-	return _ss_search(ADDR_1, dst, "sport", "bytes_sent:");
+	return ss_search(ADDR_1, dst, "sport", "bytes_sent:");
 }
 
 static void send_data_and_verify(char *sched, bool addr1, bool addr2)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH mptcp-next v5 1/3] selftests/bpf: Add getsockopt to inspect mptcp subflow
  2024-08-29  2:53 ` [PATCH mptcp-next v5 1/3] selftests/bpf: Add getsockopt to inspect mptcp subflow Geliang Tang
@ 2024-08-29 14:25   ` Matthieu Baerts
  2024-08-30  7:12     ` Geliang Tang
  0 siblings, 1 reply; 8+ messages in thread
From: Matthieu Baerts @ 2024-08-29 14:25 UTC (permalink / raw)
  To: Geliang Tang, mptcp; +Cc: Geliang Tang

Hi Geliang,

cc: -Martin (not to annoy him with MPTCP specific stuff)

On 29/08/2024 04:53, Geliang Tang wrote:
> From: Geliang Tang <tanggeliang@kylinos.cn>
> 
> This patch adds a "cgroup/getsockopt" way to inspect the subflows of a
> mptcp socket.
> 
> mptcp_for_each_stubflow() and other helpers related to list_dentry are
> added into progs/mptcp_bpf.h.
> 
> Add an extra "cgroup/getsockopt" prog to walk the msk->conn_list and use
> bpf_core_cast to cast a pointer to tcp_sock for readonly. It will allow
> to inspect all the fields in a tcp_sock.

(...)

> diff --git a/tools/testing/selftests/bpf/progs/mptcp_subflow.c b/tools/testing/selftests/bpf/progs/mptcp_subflow.c
> index bc572e1d6df8..6a7cf71c2795 100644
> --- a/tools/testing/selftests/bpf/progs/mptcp_subflow.c
> +++ b/tools/testing/selftests/bpf/progs/mptcp_subflow.c
> @@ -4,6 +4,7 @@
>  
>  /* vmlinux.h, bpf_helpers.h and other 'define' */
>  #include "bpf_tracing_net.h"
> +#include "mptcp_bpf.h"
>  
>  char _license[] SEC("license") = "GPL";
>  
> @@ -57,3 +58,64 @@ int mptcp_subflow(struct bpf_sock_ops *skops)
>  
>  	return 1;
>  }
> +
> +static int _check_getsockopt_subflow_mark(struct mptcp_sock *msk, struct bpf_sockopt *ctx)
> +{
> +	struct mptcp_subflow_context *subflow;
> +	int i = 0;
> +
> +	mptcp_for_each_subflow(msk, subflow) {
> +		struct sock *ssk;
> +
> +		ssk = mptcp_subflow_tcp_sock(bpf_core_cast(subflow,
> +							   struct mptcp_subflow_context));
> +
> +		if (ssk->sk_mark != ++i)
> +			ctx->retval = -1;
> +	}
> +
> +	return 1;
> +}
> +
> +static int _check_getsockopt_subflow_cc(struct mptcp_sock *msk, struct bpf_sockopt *ctx)
> +{
> +	struct mptcp_subflow_context *subflow, *tmp;
> +
> +	mptcp_for_each_subflow_safe(msk, subflow, tmp) {

Out of curiosity, why do you need the '_safe()' helper here? Just to
check it works?

> +		struct inet_connection_sock *icsk;
> +		struct sock *ssk;
> +
> +		ssk = mptcp_subflow_tcp_sock(bpf_core_cast(subflow,
> +							   struct mptcp_subflow_context));
> +		icsk = bpf_core_cast(ssk, struct inet_connection_sock);
> +
> +		if ((ssk->sk_mark == 1 &&
> +		     __builtin_memcmp(icsk->icsk_ca_ops->name, cc, TCP_CA_NAME_MAX)) ||

In your previous version, you had a patch to set the cc on the other
subflow, not to change the value of 'getsockopt(TCP_CONGESTION)' seen by
the userspace. Why did you drop it?

> +		    (ssk->sk_mark == 2 &&
> +		     __builtin_memcmp(icsk->icsk_ca_ops->name, "cubic", TCP_CA_NAME_MAX)))

You cannot check this one (or at least not like that): the default TCP
CC can be changed with a kernel config, it is not necessarily cubic.

I think it is fine to only check the other subflow.

> +			ctx->retval = -1;

Should you not mark it as an error if the mark is different from 1 or 2?
(Or maybe not, because that's covered by _check_getsockopt_subflow_mark)

> +	}
> +
> +	return 1;
> +}
> +
> +SEC("cgroup/getsockopt")
> +int _getsockopt_subflow(struct bpf_sockopt *ctx)
> +{
> +	struct bpf_sock *sk = ctx->sk;
> +	struct mptcp_sock *msk;
> +
> +	if (!sk || sk->protocol != IPPROTO_MPTCP)
> +		return 1;

If this test fails, the check will not be done.

> +
> +	msk = bpf_core_cast(sk, struct mptcp_sock);
> +	if (msk->pm.subflows != 1)
> +		return 1;

Same here: if there is no extra subflow, the test is silently not done.
You change 'ctx->retval'.

Also, it might be good to print something somewhere everywhere you set
this 'ctx->retval' to -1, to be able to easily understand what went
wrong, no? Can we use bpf_printk() or something similar?

> +
> +	if (ctx->level == SOL_SOCKET && ctx->optname == SO_MARK)
> +		return _check_getsockopt_subflow_mark(msk, ctx);
> +	if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION)
> +		return _check_getsockopt_subflow_cc(msk, ctx);
> +
> +	return 1;
> +}

Cheers,
Matt
-- 
Sponsored by the NGI0 Core fund.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH mptcp-next v5 2/3] Squash to "selftests/bpf: Add mptcp subflow subtest"
  2024-08-29  2:53 ` [PATCH mptcp-next v5 2/3] Squash to "selftests/bpf: Add mptcp subflow subtest" Geliang Tang
@ 2024-08-29 14:38   ` Matthieu Baerts
  0 siblings, 0 replies; 8+ messages in thread
From: Matthieu Baerts @ 2024-08-29 14:38 UTC (permalink / raw)
  To: Geliang Tang, mptcp; +Cc: Geliang Tang

Hi Geliang,

Thank you for the update.

On 29/08/2024 04:53, Geliang Tang wrote:
> From: Geliang Tang <tanggeliang@kylinos.cn>
> 
> Drop ss_search() from run_subflow().
> 
> Use the "cgroup/getsockopt" way to inspect the subflows.
> 
> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
> ---
>  .../testing/selftests/bpf/prog_tests/mptcp.c  | 52 +++++++++++--------
>  1 file changed, 31 insertions(+), 21 deletions(-)
> 
> diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c
> index 73adc58cd776..85883515c67b 100644
> --- a/tools/testing/selftests/bpf/prog_tests/mptcp.c
> +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c

(...)

> @@ -393,17 +384,29 @@ static void run_subflow(char *new)
>  	if (!ASSERT_GE(client_fd, 0, "connect to fd"))
>  		goto close_server;
>  
> -	len = sizeof(cc);
> -	err = getsockopt(server_fd, SOL_TCP, TCP_CONGESTION, cc, &len);
> -	if (!ASSERT_OK(err, "getsockopt(server_fd, TCP_CONGESTION)"))
> -		goto close_client;
> -
>  	send_byte(client_fd);
>  
> -	ASSERT_OK(ss_search(ADDR_1, "fwmark:0x1"), "ss_search fwmark:0x1");
> -	ASSERT_OK(ss_search(ADDR_2, "fwmark:0x2"), "ss_search fwmark:0x2");
> -	ASSERT_OK(ss_search(ADDR_1, new), "ss_search new cc");
> -	ASSERT_OK(ss_search(ADDR_2, cc), "ss_search default cc");
> +	len = sizeof(subflows);
> +	/* Wait max 1 sec for new subflows to be created */
> +	for (i = 0; i < 10; i++) {
> +		err = getsockopt(client_fd, SOL_MPTCP, MPTCP_INFO, &subflows, &len);
> +		if (!err && subflows > 0)
> +			break;
> +
> +		sleep(0.1);
> +	}

(detail: it might be better to have that in a new helper, but up to you,
maybe easier to keep it here for the moment).

> +
> +	len = sizeof(mark);
> +	err = getsockopt(client_fd, SOL_SOCKET, SO_MARK, &mark, &len);
> +	if (!ASSERT_OK(err, "getsockopt(client_fd, SO_MARK)"))
> +		goto close_client;

You still don't need this 'goto close_client': it is better to do as
many checks as possible. If needed, you can do something like:

  if (ASSERT_OK(err, "getsockopt(client_fd, SO_MARK)"))
          ASSERT_EQ(mark, 0, "mark");

But it is better to also check the TCP_CC, to better understand what
went wrong.

> +	ASSERT_EQ(mark, 0, "mark");
> +
> +	len = sizeof(cc);
> +	err = getsockopt(client_fd, SOL_TCP, TCP_CONGESTION, cc, &len);
> +	if (!ASSERT_OK(err, "getsockopt(client_fd, TCP_CONGESTION)"))
> +		goto close_client;

Same here.

> +	ASSERT_STREQ(cc, new, "cc");

Did you drop the first patch of the v4 to ease the check here, and not
to have to look at the default value? I suppose that's OK.

>  close_client:
>  	close(client_fd);
> @@ -416,6 +419,7 @@ static void test_subflow(void)
>  	int cgroup_fd, prog_fd, err;
>  	struct mptcp_subflow *skel;
>  	struct nstoken *nstoken;
> +	struct bpf_link *link;
>  
>  	cgroup_fd = test__join_cgroup("/mptcp_subflow");
>  	if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup: mptcp_subflow"))
> @@ -441,6 +445,11 @@ static void test_subflow(void)
>  	if (endpoint_init("subflow") < 0)
>  		goto close_netns;
>  
> +	link = bpf_program__attach_cgroup(skel->progs._getsockopt_subflow,
> +					  cgroup_fd);
> +	if (!ASSERT_OK_PTR(link, "getsockopt prog"))
> +		goto close_netns;
> +
>  	run_subflow(skel->data->cc);
>  
>  close_netns:
> @@ -448,6 +457,7 @@ static void test_subflow(void)
>  skel_destroy:
>  	mptcp_subflow__destroy(skel);
>  close_cgroup:
> +	bpf_link__destroy(link);

Mmh, I see you moved it, but I don't think it is OK to have here, right?

I should be placed just before the 'close_netns' label, not to call it
with an undefined 'link' variable, no?

>  	close(cgroup_fd);
>  }
>  

Cheers,
Matt
-- 
Sponsored by the NGI0 Core fund.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH mptcp-next v5 1/3] selftests/bpf: Add getsockopt to inspect mptcp subflow
  2024-08-29 14:25   ` Matthieu Baerts
@ 2024-08-30  7:12     ` Geliang Tang
  0 siblings, 0 replies; 8+ messages in thread
From: Geliang Tang @ 2024-08-30  7:12 UTC (permalink / raw)
  To: Matthieu Baerts, mptcp; +Cc: Geliang Tang

Hi Matt,

On Thu, 2024-08-29 at 16:25 +0200, Matthieu Baerts wrote:
> Hi Geliang,
> 
> cc: -Martin (not to annoy him with MPTCP specific stuff)
> 
> On 29/08/2024 04:53, Geliang Tang wrote:
> > From: Geliang Tang <tanggeliang@kylinos.cn>
> > 
> > This patch adds a "cgroup/getsockopt" way to inspect the subflows
> > of a
> > mptcp socket.
> > 
> > mptcp_for_each_stubflow() and other helpers related to list_dentry
> > are
> > added into progs/mptcp_bpf.h.
> > 
> > Add an extra "cgroup/getsockopt" prog to walk the msk->conn_list
> > and use
> > bpf_core_cast to cast a pointer to tcp_sock for readonly. It will
> > allow
> > to inspect all the fields in a tcp_sock.
> 
> (...)
> 
> > diff --git a/tools/testing/selftests/bpf/progs/mptcp_subflow.c
> > b/tools/testing/selftests/bpf/progs/mptcp_subflow.c
> > index bc572e1d6df8..6a7cf71c2795 100644
> > --- a/tools/testing/selftests/bpf/progs/mptcp_subflow.c
> > +++ b/tools/testing/selftests/bpf/progs/mptcp_subflow.c
> > @@ -4,6 +4,7 @@
> >  
> >  /* vmlinux.h, bpf_helpers.h and other 'define' */
> >  #include "bpf_tracing_net.h"
> > +#include "mptcp_bpf.h"
> >  
> >  char _license[] SEC("license") = "GPL";
> >  
> > @@ -57,3 +58,64 @@ int mptcp_subflow(struct bpf_sock_ops *skops)
> >  
> >   return 1;
> >  }
> > +
> > +static int _check_getsockopt_subflow_mark(struct mptcp_sock *msk,
> > struct bpf_sockopt *ctx)
> > +{
> > + struct mptcp_subflow_context *subflow;
> > + int i = 0;
> > +
> > + mptcp_for_each_subflow(msk, subflow) {
> > + struct sock *ssk;
> > +
> > + ssk = mptcp_subflow_tcp_sock(bpf_core_cast(subflow,
> > +    struct mptcp_subflow_context));
> > +
> > + if (ssk->sk_mark != ++i)
> > + ctx->retval = -1;
> > + }
> > +
> > + return 1;
> > +}
> > +
> > +static int _check_getsockopt_subflow_cc(struct mptcp_sock *msk,
> > struct bpf_sockopt *ctx)
> > +{
> > + struct mptcp_subflow_context *subflow, *tmp;
> > +
> > + mptcp_for_each_subflow_safe(msk, subflow, tmp) {
> 
> Out of curiosity, why do you need the '_safe()' helper here? Just to
> check it works?
> 
> > + struct inet_connection_sock *icsk;
> > + struct sock *ssk;
> > +
> > + ssk = mptcp_subflow_tcp_sock(bpf_core_cast(subflow,
> > +    struct mptcp_subflow_context));
> > + icsk = bpf_core_cast(ssk, struct inet_connection_sock);
> > +
> > + if ((ssk->sk_mark == 1 &&
> > +      __builtin_memcmp(icsk->icsk_ca_ops->name, cc,
> > TCP_CA_NAME_MAX)) ||
> 
> In your previous version, you had a patch to set the cc on the other
> subflow, not to change the value of 'getsockopt(TCP_CONGESTION)' seen
> by
> the userspace. Why did you drop it?
> 
> > +     (ssk->sk_mark == 2 &&
> > +      __builtin_memcmp(icsk->icsk_ca_ops->name, "cubic",
> > TCP_CA_NAME_MAX)))
> 
> You cannot check this one (or at least not like that): the default
> TCP
> CC can be changed with a kernel config, it is not necessarily cubic.
> 
> I think it is fine to only check the other subflow.
> 
> > + ctx->retval = -1;
> 
> Should you not mark it as an error if the mark is different from 1 or
> 2?
> (Or maybe not, because that's covered by
> _check_getsockopt_subflow_mark)
> 
> > + }
> > +
> > + return 1;
> > +}
> > +
> > +SEC("cgroup/getsockopt")
> > +int _getsockopt_subflow(struct bpf_sockopt *ctx)
> > +{
> > + struct bpf_sock *sk = ctx->sk;
> > + struct mptcp_sock *msk;
> > +
> > + if (!sk || sk->protocol != IPPROTO_MPTCP)
> > + return 1;
> 
> If this test fails, the check will not be done.
> 
> > +
> > + msk = bpf_core_cast(sk, struct mptcp_sock);
> > + if (msk->pm.subflows != 1)
> > + return 1;
> 
> Same here: if there is no extra subflow, the test is silently not
> done.
> You change 'ctx->retval'.
> 
> Also, it might be good to print something somewhere everywhere you
> set
> this 'ctx->retval' to -1, to be able to easily understand what went
> wrong, no? Can we use bpf_printk() or something similar?

getsockopt() is invoked by connect_to_fd() too, and msk->pm.subflows is
0 in this case. So in v6, I moved this "msk->pm.subflows" check into
_check_getsockopt_subflow_mark/cc.

Thanks,
-Geliang

> 
> > +
> > + if (ctx->level == SOL_SOCKET && ctx->optname == SO_MARK)
> > + return _check_getsockopt_subflow_mark(msk, ctx);
> > + if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION)
> > + return _check_getsockopt_subflow_cc(msk, ctx);
> > +
> > + return 1;
> > +}
> 
> Cheers,
> Matt


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH mptcp-next v5 0/3] fixes for "new MPTCP subflow subtest v4"
  2024-08-29  2:53 [PATCH mptcp-next v5 0/3] fixes for "new MPTCP subflow subtest v4" Geliang Tang
                   ` (2 preceding siblings ...)
  2024-08-29  2:53 ` [PATCH mptcp-next v5 3/3] Squash to "selftests/bpf: Add bpf scheduler test" Geliang Tang
@ 2024-09-02 17:48 ` MPTCP CI
  3 siblings, 0 replies; 8+ messages in thread
From: MPTCP CI @ 2024-09-02 17:48 UTC (permalink / raw)
  To: Geliang Tang; +Cc: mptcp

Hi Geliang,

Thank you for your modifications, that's great!

Our CI did some validations and here is its report:

- KVM Validation: normal: Success! ✅
- KVM Validation: debug: Success! ✅
- KVM Validation: btf (only bpftest_all): Success! ✅
- Task: https://github.com/multipath-tcp/mptcp_net-next/actions/runs/10670887546

Initiator: Patchew Applier
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/6898e3d0eaaf
Patchwork: https://patchwork.kernel.org/project/mptcp/list/?series=884526


If there are some issues, you can reproduce them using the same environment as
the one used by the CI thanks to a docker image, e.g.:

    $ cd [kernel source code]
    $ docker run -v "${PWD}:${PWD}:rw" -w "${PWD}" --privileged --rm -it \
        --pull always mptcp/mptcp-upstream-virtme-docker:latest \
        auto-normal

For more details:

    https://github.com/multipath-tcp/mptcp-upstream-virtme-docker


Please note that despite all the efforts that have been already done to have a
stable tests suite when executed on a public CI like here, it is possible some
reported issues are not due to your modifications. Still, do not hesitate to
help us improve that ;-)

Cheers,
MPTCP GH Action bot
Bot operated by Matthieu Baerts (NGI0 Core)

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2024-09-02 17:48 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-29  2:53 [PATCH mptcp-next v5 0/3] fixes for "new MPTCP subflow subtest v4" Geliang Tang
2024-08-29  2:53 ` [PATCH mptcp-next v5 1/3] selftests/bpf: Add getsockopt to inspect mptcp subflow Geliang Tang
2024-08-29 14:25   ` Matthieu Baerts
2024-08-30  7:12     ` Geliang Tang
2024-08-29  2:53 ` [PATCH mptcp-next v5 2/3] Squash to "selftests/bpf: Add mptcp subflow subtest" Geliang Tang
2024-08-29 14:38   ` Matthieu Baerts
2024-08-29  2:53 ` [PATCH mptcp-next v5 3/3] Squash to "selftests/bpf: Add bpf scheduler test" Geliang Tang
2024-09-02 17:48 ` [PATCH mptcp-next v5 0/3] fixes for "new MPTCP subflow subtest v4" MPTCP CI

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.