All of lore.kernel.org
 help / color / mirror / Atom feed
* [MPTCP][PATCH v2 mptcp-next 0/5] MP_FAIL support
@ 2021-06-24 12:02 Geliang Tang
  2021-06-24 12:02 ` [MPTCP][PATCH v2 mptcp-next 1/5] mptcp: MP_FAIL suboption sending Geliang Tang
  0 siblings, 1 reply; 9+ messages in thread
From: Geliang Tang @ 2021-06-24 12:02 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

v2:
 - MP_FAIL logic:
   * Peer B send a DSS to peer A, and the data has been modify by the
  middleboxes, then peer A detects the bad checksum.
   * In the multiple subflows case, peer A sends MP_FAIL+RST back to peer B,
  and peer A discards the data following the bad data sequence number. Peer
  B receives this MP_FAIL+RST, and close this subflow.
   * In the single subflow case, using the simple implementation, peer A
  sends MP_FAIL back to peer B, and peer A fallback to a regular TCP. Peer
  B receives this MP_FAIL, and fallback to a regular TCP.
 - apply: export/20210624T054331

Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/52

Geliang Tang (5):
  mptcp: MP_FAIL suboption sending
  mptcp: MP_FAIL suboption receiving
  mptcp: send out MP_FAIL when data checksum fail
  mptcp: add the mibs for MP_FAIL
  selftests: mptcp: add MP_FAIL mibs check

 include/net/mptcp.h                           |  1 +
 net/mptcp/mib.c                               |  2 +
 net/mptcp/mib.h                               |  2 +
 net/mptcp/options.c                           | 63 ++++++++++++++++++-
 net/mptcp/pm.c                                | 14 +++++
 net/mptcp/protocol.h                          | 19 ++++++
 net/mptcp/subflow.c                           | 16 +++++
 .../testing/selftests/net/mptcp/mptcp_join.sh | 38 +++++++++++
 8 files changed, 154 insertions(+), 1 deletion(-)

-- 
2.31.1


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

* [MPTCP][PATCH v2 mptcp-next 1/5] mptcp: MP_FAIL suboption sending
  2021-06-24 12:02 [MPTCP][PATCH v2 mptcp-next 0/5] MP_FAIL support Geliang Tang
@ 2021-06-24 12:02 ` Geliang Tang
  2021-06-24 12:02   ` [MPTCP][PATCH v2 mptcp-next 2/5] mptcp: MP_FAIL suboption receiving Geliang Tang
  0 siblings, 1 reply; 9+ messages in thread
From: Geliang Tang @ 2021-06-24 12:02 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

This patch added the MP_FAIL suboption sending support.

Add a new flag named send_mp_fail in struct mptcp_subflow_context. If
this flag is set, send out MP_FAIL suboption.

Add a new member fail_seq in struct mptcp_out_options to save the data
sequence number to put into the MP_FAIL suboption.

Signed-off-by: Geliang Tang <geliangtang@gmail.com>
---
 include/net/mptcp.h  |  1 +
 net/mptcp/options.c  | 46 +++++++++++++++++++++++++++++++++++++++++++-
 net/mptcp/protocol.h |  3 +++
 3 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index cb580b06152f..f48d3b5a3fd4 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -72,6 +72,7 @@ struct mptcp_out_options {
 	u32 nonce;
 	u64 thmac;
 	u32 token;
+	u64 fail_seq;
 	u8 hmac[20];
 	struct mptcp_ext ext_copy;
 #endif
diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index b5850afea343..eac23ceb9843 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -771,6 +771,28 @@ static noinline void mptcp_established_options_rst(struct sock *sk, struct sk_bu
 	opts->reset_reason = subflow->reset_reason;
 }
 
+static bool mptcp_established_options_mp_fail(struct sock *sk,
+					      unsigned int *size,
+					      unsigned int remaining,
+					      struct mptcp_out_options *opts)
+{
+	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
+
+	if (!subflow->send_mp_fail)
+		return false;
+
+	if (remaining < TCPOLEN_MPTCP_FAIL)
+		return false;
+
+	*size = TCPOLEN_MPTCP_FAIL;
+	opts->suboptions |= OPTION_MPTCP_FAIL;
+	opts->fail_seq = subflow->map_seq;
+
+	pr_debug("MP_FAIL fail_seq=%llu", opts->fail_seq);
+
+	return true;
+}
+
 bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
 			       unsigned int *size, unsigned int remaining,
 			       struct mptcp_out_options *opts)
@@ -786,8 +808,16 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
 	if (unlikely(__mptcp_check_fallback(msk)))
 		return false;
 
+	if (mptcp_established_options_mp_fail(sk, &opt_size, remaining, opts)) {
+		*size += opt_size;
+		remaining -= opt_size;
+		ret = true;
+	}
+
 	if (unlikely(skb && TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) {
-		mptcp_established_options_rst(sk, skb, size, remaining, opts);
+		mptcp_established_options_rst(sk, skb, &opt_size, remaining, opts);
+		*size += opt_size;
+		remaining -= opt_size;
 		return true;
 	}
 
@@ -1334,6 +1364,20 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
 				      opts->backup, TCPOPT_NOP);
 	}
 
+	if (OPTION_MPTCP_FAIL & opts->suboptions) {
+		const struct sock *ssk = (const struct sock *)tp;
+		struct mptcp_subflow_context *subflow;
+
+		subflow = mptcp_subflow_ctx(ssk);
+		subflow->send_mp_fail = 0;
+
+		*ptr++ = mptcp_option(MPTCPOPT_MP_FAIL,
+				      TCPOLEN_MPTCP_FAIL,
+				      0, 0);
+		put_unaligned_be64(opts->fail_seq, ptr);
+		ptr += 2;
+	}
+
 	if (OPTION_MPTCP_MPJ_SYN & opts->suboptions) {
 		*ptr++ = mptcp_option(MPTCPOPT_MP_JOIN,
 				      TCPOLEN_MPTCP_MPJ_SYN,
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 426ed80fe72f..fd36c743c638 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -26,6 +26,7 @@
 #define OPTION_MPTCP_FASTCLOSE	BIT(8)
 #define OPTION_MPTCP_PRIO	BIT(9)
 #define OPTION_MPTCP_RST	BIT(10)
+#define OPTION_MPTCP_FAIL	BIT(11)
 
 /* MPTCP option subtypes */
 #define MPTCPOPT_MP_CAPABLE	0
@@ -67,6 +68,7 @@
 #define TCPOLEN_MPTCP_PRIO_ALIGN	4
 #define TCPOLEN_MPTCP_FASTCLOSE		12
 #define TCPOLEN_MPTCP_RST		4
+#define TCPOLEN_MPTCP_FAIL		12
 
 #define TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM	(TCPOLEN_MPTCP_DSS_CHECKSUM + TCPOLEN_MPTCP_MPC_ACK_DATA)
 
@@ -417,6 +419,7 @@ struct mptcp_subflow_context {
 		mpc_map : 1,
 		backup : 1,
 		send_mp_prio : 1,
+		send_mp_fail : 1,
 		rx_eof : 1,
 		can_ack : 1,        /* only after processing the remote a key */
 		disposable : 1;	    /* ctx can be free at ulp release time */
-- 
2.31.1


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

* [MPTCP][PATCH v2 mptcp-next 2/5] mptcp: MP_FAIL suboption receiving
  2021-06-24 12:02 ` [MPTCP][PATCH v2 mptcp-next 1/5] mptcp: MP_FAIL suboption sending Geliang Tang
@ 2021-06-24 12:02   ` Geliang Tang
  2021-06-24 12:02     ` [MPTCP][PATCH v2 mptcp-next 3/5] mptcp: send out MP_FAIL when data checksum fail Geliang Tang
  2021-06-25 23:47     ` [MPTCP][PATCH v2 mptcp-next 2/5] mptcp: MP_FAIL suboption receiving Mat Martineau
  0 siblings, 2 replies; 9+ messages in thread
From: Geliang Tang @ 2021-06-24 12:02 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

This patch added handling for receiving MP_FAIL suboption.

Add a new members mp_fail and fail_seq in struct mptcp_options_received.
When MP_FAIL suboption is received, set mp_fail to 1 and save the sequence
number to fail_seq.

Then invoke mptcp_pm_mp_fail_received to deal with the MP_FAIL suboption.
In it, if there is no other established subflow, fallback to TCP.

Signed-off-by: Geliang Tang <geliangtang@gmail.com>
---
 net/mptcp/options.c  | 16 ++++++++++++++++
 net/mptcp/pm.c       | 13 +++++++++++++
 net/mptcp/protocol.h | 16 ++++++++++++++++
 3 files changed, 45 insertions(+)

diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index eac23ceb9843..cd4d0521556d 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -336,6 +336,16 @@ static void mptcp_parse_option(const struct sk_buff *skb,
 		mp_opt->reset_reason = *ptr;
 		break;
 
+	case MPTCPOPT_MP_FAIL:
+		if (opsize != TCPOLEN_MPTCP_FAIL)
+			break;
+
+		ptr += 2;
+		mp_opt->mp_fail = 1;
+		mp_opt->fail_seq = get_unaligned_be64(ptr);
+		pr_debug("MP_FAIL: data_seq=%llu", mp_opt->fail_seq);
+		break;
+
 	default:
 		break;
 	}
@@ -364,6 +374,7 @@ void mptcp_get_options(const struct sock *sk,
 	mp_opt->reset = 0;
 	mp_opt->csum_reqd = READ_ONCE(msk->csum_enabled);
 	mp_opt->deny_join_id0 = 0;
+	mp_opt->mp_fail = 0;
 
 	length = (th->doff * 4) - sizeof(struct tcphdr);
 	ptr = (const unsigned char *)(th + 1);
@@ -1123,6 +1134,11 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
 		mp_opt.mp_prio = 0;
 	}
 
+	if (mp_opt.mp_fail) {
+		mptcp_pm_mp_fail_received(sk, mp_opt.fail_seq);
+		mp_opt.mp_fail = 0;
+	}
+
 	if (mp_opt.reset) {
 		subflow->reset_seen = 1;
 		subflow->reset_reason = mp_opt.reset_reason;
diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index 639271e09604..d7792f6e38ba 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -247,6 +247,19 @@ void mptcp_pm_mp_prio_received(struct sock *sk, u8 bkup)
 	mptcp_event(MPTCP_EVENT_SUB_PRIORITY, mptcp_sk(subflow->conn), sk, GFP_ATOMIC);
 }
 
+void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
+{
+	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
+	struct mptcp_sock *msk = mptcp_sk(subflow->conn);
+
+	pr_debug("map_seq=%llu fail_seq=%llu", subflow->map_seq, fail_seq);
+
+	if (!mptcp_has_another_subflow_established(sk)) {
+		pr_fallback(msk);
+		__mptcp_do_fallback(msk);
+	}
+}
+
 /* path manager helpers */
 
 bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index fd36c743c638..62fe09394624 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -139,6 +139,7 @@ struct mptcp_options_received {
 		add_addr : 1,
 		rm_addr : 1,
 		mp_prio : 1,
+		mp_fail : 1,
 		echo : 1,
 		csum_reqd : 1,
 		backup : 1,
@@ -160,6 +161,7 @@ struct mptcp_options_received {
 	u64	ahmac;
 	u8	reset_reason:4;
 	u8	reset_transient:1;
+	u64	fail_seq;
 };
 
 static inline __be32 mptcp_option(u8 subopt, u8 len, u8 nib, u8 field)
@@ -591,6 +593,19 @@ static inline void mptcp_subflow_tcp_fallback(struct sock *sk,
 	inet_csk(sk)->icsk_af_ops = ctx->icsk_af_ops;
 }
 
+static inline bool mptcp_has_another_subflow_established(struct sock *ssk)
+{
+	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk), *tmp;
+	struct mptcp_sock *msk = mptcp_sk(subflow->conn);
+
+	mptcp_for_each_subflow(msk, tmp) {
+		if (tmp->fully_established && tmp != subflow)
+			return true;
+	}
+
+	return false;
+}
+
 void __init mptcp_proto_init(void);
 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
 int __init mptcp_proto_v6_init(void);
@@ -703,6 +718,7 @@ void mptcp_pm_mp_prio_received(struct sock *sk, u8 bkup);
 int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
 				 struct mptcp_addr_info *addr,
 				 u8 bkup);
+void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq);
 void mptcp_pm_free_anno_list(struct mptcp_sock *msk);
 bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk);
 struct mptcp_pm_add_entry *
-- 
2.31.1


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

* [MPTCP][PATCH v2 mptcp-next 3/5] mptcp: send out MP_FAIL when data checksum fail
  2021-06-24 12:02   ` [MPTCP][PATCH v2 mptcp-next 2/5] mptcp: MP_FAIL suboption receiving Geliang Tang
@ 2021-06-24 12:02     ` Geliang Tang
  2021-06-24 12:02       ` [MPTCP][PATCH v2 mptcp-next 4/5] mptcp: add the mibs for MP_FAIL Geliang Tang
  2021-06-26  0:18       ` [MPTCP][PATCH v2 mptcp-next 3/5] mptcp: send out MP_FAIL when data checksum fail Mat Martineau
  2021-06-25 23:47     ` [MPTCP][PATCH v2 mptcp-next 2/5] mptcp: MP_FAIL suboption receiving Mat Martineau
  1 sibling, 2 replies; 9+ messages in thread
From: Geliang Tang @ 2021-06-24 12:02 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

When a bad checksum is detected, send out the MP_FAIL suboption.

Signed-off-by: Geliang Tang <geliangtang@gmail.com>
---
 net/mptcp/subflow.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 0b5d4a3eadcd..13e53a6bd3a1 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -913,6 +913,7 @@ static enum mapping_status validate_data_csum(struct sock *ssk, struct sk_buff *
 	csum = csum_partial(&header, sizeof(header), subflow->map_data_csum);
 	if (unlikely(csum_fold(csum))) {
 		MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_DATACSUMERR);
+		subflow->send_mp_fail = 1;
 		return subflow->mp_join ? MAPPING_INVALID : MAPPING_DUMMY;
 	}
 
@@ -1159,6 +1160,20 @@ static bool subflow_check_data_avail(struct sock *ssk)
 	return false;
 
 fallback:
+	if (subflow->send_mp_fail) {
+		if (mptcp_has_another_subflow_established(ssk)) {
+			mptcp_subflow_reset(ssk);
+			while ((skb = skb_peek(&ssk->sk_receive_queue)))
+				sk_eat_skb(ssk, skb);
+		} else {
+			pr_fallback(msk);
+			__mptcp_do_fallback(msk);
+		}
+
+		WRITE_ONCE(subflow->data_avail, 0);
+		return true;
+	}
+
 	/* RFC 8684 section 3.7. */
 	if (subflow->mp_join || subflow->fully_established) {
 		/* fatal protocol error, close the socket.
-- 
2.31.1


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

* [MPTCP][PATCH v2 mptcp-next 4/5] mptcp: add the mibs for MP_FAIL
  2021-06-24 12:02     ` [MPTCP][PATCH v2 mptcp-next 3/5] mptcp: send out MP_FAIL when data checksum fail Geliang Tang
@ 2021-06-24 12:02       ` Geliang Tang
  2021-06-24 12:02         ` [MPTCP][PATCH v2 mptcp-next 5/5] selftests: mptcp: add MP_FAIL mibs check Geliang Tang
  2021-06-26  0:19         ` [MPTCP][PATCH v2 mptcp-next 4/5] mptcp: add the mibs for MP_FAIL Mat Martineau
  2021-06-26  0:18       ` [MPTCP][PATCH v2 mptcp-next 3/5] mptcp: send out MP_FAIL when data checksum fail Mat Martineau
  1 sibling, 2 replies; 9+ messages in thread
From: Geliang Tang @ 2021-06-24 12:02 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

This patch added the mibs for MP_FAIL: MPTCP_MIB_MPFAILTX and
MPTCP_MIB_MPFAILRX.

Signed-off-by: Geliang Tang <geliangtang@gmail.com>
---
 net/mptcp/mib.c     | 2 ++
 net/mptcp/mib.h     | 2 ++
 net/mptcp/options.c | 1 +
 net/mptcp/pm.c      | 1 +
 net/mptcp/subflow.c | 1 +
 5 files changed, 7 insertions(+)

diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c
index 52ea2517e856..3f0df09138b2 100644
--- a/net/mptcp/mib.c
+++ b/net/mptcp/mib.c
@@ -44,6 +44,8 @@ static const struct snmp_mib mptcp_snmp_list[] = {
 	SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW),
 	SNMP_MIB_ITEM("MPPrioTx", MPTCP_MIB_MPPRIOTX),
 	SNMP_MIB_ITEM("MPPrioRx", MPTCP_MIB_MPPRIORX),
+	SNMP_MIB_ITEM("MPFailTx", MPTCP_MIB_MPFAILTX),
+	SNMP_MIB_ITEM("MPFailRx", MPTCP_MIB_MPFAILRX),
 	SNMP_MIB_SENTINEL
 };
 
diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h
index 193466c9b549..2a6cb1d8704c 100644
--- a/net/mptcp/mib.h
+++ b/net/mptcp/mib.h
@@ -37,6 +37,8 @@ enum linux_mptcp_mib_field {
 	MPTCP_MIB_RMSUBFLOW,		/* Remove a subflow */
 	MPTCP_MIB_MPPRIOTX,		/* Transmit a MP_PRIO */
 	MPTCP_MIB_MPPRIORX,		/* Received a MP_PRIO */
+	MPTCP_MIB_MPFAILTX,		/* Transmit a MP_FAIL */
+	MPTCP_MIB_MPFAILRX,		/* Received a MP_FAIL */
 	__MPTCP_MIB_MAX
 };
 
diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index cd4d0521556d..5442ca39b3eb 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -1136,6 +1136,7 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
 
 	if (mp_opt.mp_fail) {
 		mptcp_pm_mp_fail_received(sk, mp_opt.fail_seq);
+		MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILRX);
 		mp_opt.mp_fail = 0;
 	}
 
diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index d7792f6e38ba..d74eb56043c3 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -9,6 +9,7 @@
 #include <net/tcp.h>
 #include <net/mptcp.h>
 #include "protocol.h"
+#include "mib.h"
 
 /* path manager command handlers */
 
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 13e53a6bd3a1..1228ed275a9f 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -914,6 +914,7 @@ static enum mapping_status validate_data_csum(struct sock *ssk, struct sk_buff *
 	if (unlikely(csum_fold(csum))) {
 		MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_DATACSUMERR);
 		subflow->send_mp_fail = 1;
+		MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPFAILTX);
 		return subflow->mp_join ? MAPPING_INVALID : MAPPING_DUMMY;
 	}
 
-- 
2.31.1


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

* [MPTCP][PATCH v2 mptcp-next 5/5] selftests: mptcp: add MP_FAIL mibs check
  2021-06-24 12:02       ` [MPTCP][PATCH v2 mptcp-next 4/5] mptcp: add the mibs for MP_FAIL Geliang Tang
@ 2021-06-24 12:02         ` Geliang Tang
  2021-06-26  0:19         ` [MPTCP][PATCH v2 mptcp-next 4/5] mptcp: add the mibs for MP_FAIL Mat Martineau
  1 sibling, 0 replies; 9+ messages in thread
From: Geliang Tang @ 2021-06-24 12:02 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

This patch added a function chk_fail_nr to check the mibs for MP_FAIL.

Signed-off-by: Geliang Tang <geliangtang@gmail.com>
---
 .../testing/selftests/net/mptcp/mptcp_join.sh | 38 +++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh
index 9a191c1a5de8..535a2757ec30 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_join.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh
@@ -541,6 +541,43 @@ chk_csum_nr()
 	fi
 }
 
+chk_fail_nr()
+{
+	local mp_fail_nr_tx=$1
+	local mp_fail_nr_rx=$2
+	local count
+	local dump_stats
+
+	printf "%-39s %s" " " "ftx"
+	count=`ip netns exec $ns1 nstat -as | grep MPTcpExtMPFailTx | awk '{print $2}'`
+	[ -z "$count" ] && count=0
+	if [ "$count" != "$mp_fail_nr_tx" ]; then
+		echo "[fail] got $count MP_FAIL[s] TX expected $mp_fail_nr_tx"
+		ret=1
+		dump_stats=1
+	else
+		echo -n "[ ok ]"
+	fi
+
+	echo -n " - frx   "
+	count=`ip netns exec $ns1 nstat -as | grep MPTcpExtMPFailRx | awk '{print $2}'`
+	[ -z "$count" ] && count=0
+	if [ "$count" != "$mp_fail_nr_rx" ]; then
+		echo "[fail] got $count MP_FAIL[s] RX expected $mp_fail_nr_rx"
+		ret=1
+		dump_stats=1
+	else
+		echo "[ ok ]"
+	fi
+
+	if [ "${dump_stats}" = 1 ]; then
+		echo Server ns stats
+		ip netns exec $ns1 nstat -as | grep MPTcp
+		echo Client ns stats
+		ip netns exec $ns2 nstat -as | grep MPTcp
+	fi
+}
+
 chk_join_nr()
 {
 	local msg="$1"
@@ -590,6 +627,7 @@ chk_join_nr()
 	fi
 	if [ $checksum -eq 1 ]; then
 		chk_csum_nr
+		chk_fail_nr 0 0
 	fi
 }
 
-- 
2.31.1


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

* Re: [MPTCP][PATCH v2 mptcp-next 2/5] mptcp: MP_FAIL suboption receiving
  2021-06-24 12:02   ` [MPTCP][PATCH v2 mptcp-next 2/5] mptcp: MP_FAIL suboption receiving Geliang Tang
  2021-06-24 12:02     ` [MPTCP][PATCH v2 mptcp-next 3/5] mptcp: send out MP_FAIL when data checksum fail Geliang Tang
@ 2021-06-25 23:47     ` Mat Martineau
  1 sibling, 0 replies; 9+ messages in thread
From: Mat Martineau @ 2021-06-25 23:47 UTC (permalink / raw)
  To: Geliang Tang; +Cc: mptcp

On Thu, 24 Jun 2021, Geliang Tang wrote:

> This patch added handling for receiving MP_FAIL suboption.
>
> Add a new members mp_fail and fail_seq in struct mptcp_options_received.
> When MP_FAIL suboption is received, set mp_fail to 1 and save the sequence
> number to fail_seq.
>
> Then invoke mptcp_pm_mp_fail_received to deal with the MP_FAIL suboption.
> In it, if there is no other established subflow, fallback to TCP.
>
> Signed-off-by: Geliang Tang <geliangtang@gmail.com>
> ---
> net/mptcp/options.c  | 16 ++++++++++++++++
> net/mptcp/pm.c       | 13 +++++++++++++
> net/mptcp/protocol.h | 16 ++++++++++++++++
> 3 files changed, 45 insertions(+)
>
> diff --git a/net/mptcp/options.c b/net/mptcp/options.c
> index eac23ceb9843..cd4d0521556d 100644
> --- a/net/mptcp/options.c
> +++ b/net/mptcp/options.c
> @@ -336,6 +336,16 @@ static void mptcp_parse_option(const struct sk_buff *skb,
> 		mp_opt->reset_reason = *ptr;
> 		break;
>
> +	case MPTCPOPT_MP_FAIL:
> +		if (opsize != TCPOLEN_MPTCP_FAIL)
> +			break;
> +
> +		ptr += 2;
> +		mp_opt->mp_fail = 1;
> +		mp_opt->fail_seq = get_unaligned_be64(ptr);
> +		pr_debug("MP_FAIL: data_seq=%llu", mp_opt->fail_seq);
> +		break;
> +
> 	default:
> 		break;
> 	}
> @@ -364,6 +374,7 @@ void mptcp_get_options(const struct sock *sk,
> 	mp_opt->reset = 0;
> 	mp_opt->csum_reqd = READ_ONCE(msk->csum_enabled);
> 	mp_opt->deny_join_id0 = 0;
> +	mp_opt->mp_fail = 0;
>
> 	length = (th->doff * 4) - sizeof(struct tcphdr);
> 	ptr = (const unsigned char *)(th + 1);
> @@ -1123,6 +1134,11 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
> 		mp_opt.mp_prio = 0;
> 	}
>
> +	if (mp_opt.mp_fail) {
> +		mptcp_pm_mp_fail_received(sk, mp_opt.fail_seq);
> +		mp_opt.mp_fail = 0;
> +	}
> +
> 	if (mp_opt.reset) {
> 		subflow->reset_seen = 1;
> 		subflow->reset_reason = mp_opt.reset_reason;
> diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
> index 639271e09604..d7792f6e38ba 100644
> --- a/net/mptcp/pm.c
> +++ b/net/mptcp/pm.c
> @@ -247,6 +247,19 @@ void mptcp_pm_mp_prio_received(struct sock *sk, u8 bkup)
> 	mptcp_event(MPTCP_EVENT_SUB_PRIORITY, mptcp_sk(subflow->conn), sk, GFP_ATOMIC);
> }
>
> +void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq)
> +{
> +	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
> +	struct mptcp_sock *msk = mptcp_sk(subflow->conn);
> +
> +	pr_debug("map_seq=%llu fail_seq=%llu", subflow->map_seq, fail_seq);
> +
> +	if (!mptcp_has_another_subflow_established(sk)) {
> +		pr_fallback(msk);
> +		__mptcp_do_fallback(msk);
> +	}
> +}
> +

RFC 8684 also says the receiver of MP_FAIL should respond with MP_FAIL. 
That would also require some logic so only one MP_FAIL is sent in each 
direction.

I think there's some more fallback complexity too, see patch 3 reply.

-Mat


> /* path manager helpers */
>
> bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
> diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
> index fd36c743c638..62fe09394624 100644
> --- a/net/mptcp/protocol.h
> +++ b/net/mptcp/protocol.h
> @@ -139,6 +139,7 @@ struct mptcp_options_received {
> 		add_addr : 1,
> 		rm_addr : 1,
> 		mp_prio : 1,
> +		mp_fail : 1,
> 		echo : 1,
> 		csum_reqd : 1,
> 		backup : 1,
> @@ -160,6 +161,7 @@ struct mptcp_options_received {
> 	u64	ahmac;
> 	u8	reset_reason:4;
> 	u8	reset_transient:1;
> +	u64	fail_seq;
> };
>
> static inline __be32 mptcp_option(u8 subopt, u8 len, u8 nib, u8 field)
> @@ -591,6 +593,19 @@ static inline void mptcp_subflow_tcp_fallback(struct sock *sk,
> 	inet_csk(sk)->icsk_af_ops = ctx->icsk_af_ops;
> }
>
> +static inline bool mptcp_has_another_subflow_established(struct sock *ssk)
> +{
> +	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk), *tmp;
> +	struct mptcp_sock *msk = mptcp_sk(subflow->conn);
> +
> +	mptcp_for_each_subflow(msk, tmp) {
> +		if (tmp->fully_established && tmp != subflow)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> void __init mptcp_proto_init(void);
> #if IS_ENABLED(CONFIG_MPTCP_IPV6)
> int __init mptcp_proto_v6_init(void);
> @@ -703,6 +718,7 @@ void mptcp_pm_mp_prio_received(struct sock *sk, u8 bkup);
> int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
> 				 struct mptcp_addr_info *addr,
> 				 u8 bkup);
> +void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq);
> void mptcp_pm_free_anno_list(struct mptcp_sock *msk);
> bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk);
> struct mptcp_pm_add_entry *
> -- 
> 2.31.1
>
>
>

--
Mat Martineau
Intel

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

* Re: [MPTCP][PATCH v2 mptcp-next 3/5] mptcp: send out MP_FAIL when data checksum fail
  2021-06-24 12:02     ` [MPTCP][PATCH v2 mptcp-next 3/5] mptcp: send out MP_FAIL when data checksum fail Geliang Tang
  2021-06-24 12:02       ` [MPTCP][PATCH v2 mptcp-next 4/5] mptcp: add the mibs for MP_FAIL Geliang Tang
@ 2021-06-26  0:18       ` Mat Martineau
  1 sibling, 0 replies; 9+ messages in thread
From: Mat Martineau @ 2021-06-26  0:18 UTC (permalink / raw)
  To: Geliang Tang; +Cc: mptcp

On Thu, 24 Jun 2021, Geliang Tang wrote:

> When a bad checksum is detected, send out the MP_FAIL suboption.
>
> Signed-off-by: Geliang Tang <geliangtang@gmail.com>
> ---
> net/mptcp/subflow.c | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
>
> diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
> index 0b5d4a3eadcd..13e53a6bd3a1 100644
> --- a/net/mptcp/subflow.c
> +++ b/net/mptcp/subflow.c
> @@ -913,6 +913,7 @@ static enum mapping_status validate_data_csum(struct sock *ssk, struct sk_buff *
> 	csum = csum_partial(&header, sizeof(header), subflow->map_data_csum);
> 	if (unlikely(csum_fold(csum))) {
> 		MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_DATACSUMERR);
> +		subflow->send_mp_fail = 1;
> 		return subflow->mp_join ? MAPPING_INVALID : MAPPING_DUMMY;
> 	}
>
> @@ -1159,6 +1160,20 @@ static bool subflow_check_data_avail(struct sock *ssk)
> 	return false;
>
> fallback:
> +	if (subflow->send_mp_fail) {
> +		if (mptcp_has_another_subflow_established(ssk)) {

mptcp_has_another_subflow_established() can return false if there's 
another subflow that's not fully established yet. It's not clear what 
happens to such a join-in-progress subflow in the 'else' case below.

Probably safest to only do the "single subflow fallback" case when there 
are no other subflows at all.

> +			mptcp_subflow_reset(ssk);
> +			while ((skb = skb_peek(&ssk->sk_receive_queue)))
> +				sk_eat_skb(ssk, skb);
> +		} else {
> +			pr_fallback(msk);
> +			__mptcp_do_fallback(msk);
> +		}
> +
> +		WRITE_ONCE(subflow->data_avail, 0);
> +		return true;
> +	}
> +

Existing fallback code has only been implemented for not-fully-established 
connections, when the process is much simpler. This checksum-triggered 
MP_FAIL case could happen when more data is in-flight or queued in the 
MPTCP socket (ooo queue).

The RFC uses an "infinite mapping" to fallback after a checksum failure, 
which isn't implemented yet. The MP_FAIL section of the RFC has several 
requirements around this different type of fallback, including a sender 
knowing that all in-flight data is contiguous, and other requirements for 
clearing send buffers with subflow ACKs. This is probably the biggest 
task for MP_FAIL.

> 	/* RFC 8684 section 3.7. */
> 	if (subflow->mp_join || subflow->fully_established) {
> 		/* fatal protocol error, close the socket.
> -- 
> 2.31.1

Thanks,

--
Mat Martineau
Intel

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

* Re: [MPTCP][PATCH v2 mptcp-next 4/5] mptcp: add the mibs for MP_FAIL
  2021-06-24 12:02       ` [MPTCP][PATCH v2 mptcp-next 4/5] mptcp: add the mibs for MP_FAIL Geliang Tang
  2021-06-24 12:02         ` [MPTCP][PATCH v2 mptcp-next 5/5] selftests: mptcp: add MP_FAIL mibs check Geliang Tang
@ 2021-06-26  0:19         ` Mat Martineau
  1 sibling, 0 replies; 9+ messages in thread
From: Mat Martineau @ 2021-06-26  0:19 UTC (permalink / raw)
  To: Geliang Tang; +Cc: mptcp

On Thu, 24 Jun 2021, Geliang Tang wrote:

> This patch added the mibs for MP_FAIL: MPTCP_MIB_MPFAILTX and
> MPTCP_MIB_MPFAILRX.
>
> Signed-off-by: Geliang Tang <geliangtang@gmail.com>
> ---
> net/mptcp/mib.c     | 2 ++
> net/mptcp/mib.h     | 2 ++
> net/mptcp/options.c | 1 +
> net/mptcp/pm.c      | 1 +
> net/mptcp/subflow.c | 1 +
> 5 files changed, 7 insertions(+)
>
> diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c
> index 52ea2517e856..3f0df09138b2 100644
> --- a/net/mptcp/mib.c
> +++ b/net/mptcp/mib.c
> @@ -44,6 +44,8 @@ static const struct snmp_mib mptcp_snmp_list[] = {
> 	SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW),
> 	SNMP_MIB_ITEM("MPPrioTx", MPTCP_MIB_MPPRIOTX),
> 	SNMP_MIB_ITEM("MPPrioRx", MPTCP_MIB_MPPRIORX),
> +	SNMP_MIB_ITEM("MPFailTx", MPTCP_MIB_MPFAILTX),
> +	SNMP_MIB_ITEM("MPFailRx", MPTCP_MIB_MPFAILRX),
> 	SNMP_MIB_SENTINEL
> };
>
> diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h
> index 193466c9b549..2a6cb1d8704c 100644
> --- a/net/mptcp/mib.h
> +++ b/net/mptcp/mib.h
> @@ -37,6 +37,8 @@ enum linux_mptcp_mib_field {
> 	MPTCP_MIB_RMSUBFLOW,		/* Remove a subflow */
> 	MPTCP_MIB_MPPRIOTX,		/* Transmit a MP_PRIO */
> 	MPTCP_MIB_MPPRIORX,		/* Received a MP_PRIO */
> +	MPTCP_MIB_MPFAILTX,		/* Transmit a MP_FAIL */
> +	MPTCP_MIB_MPFAILRX,		/* Received a MP_FAIL */
> 	__MPTCP_MIB_MAX
> };
>
> diff --git a/net/mptcp/options.c b/net/mptcp/options.c
> index cd4d0521556d..5442ca39b3eb 100644
> --- a/net/mptcp/options.c
> +++ b/net/mptcp/options.c
> @@ -1136,6 +1136,7 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
>
> 	if (mp_opt.mp_fail) {
> 		mptcp_pm_mp_fail_received(sk, mp_opt.fail_seq);
> +		MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILRX);
> 		mp_opt.mp_fail = 0;
> 	}
>
> diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
> index d7792f6e38ba..d74eb56043c3 100644
> --- a/net/mptcp/pm.c
> +++ b/net/mptcp/pm.c
> @@ -9,6 +9,7 @@
> #include <net/tcp.h>
> #include <net/mptcp.h>
> #include "protocol.h"
> +#include "mib.h"
>
> /* path manager command handlers */
>
> diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
> index 13e53a6bd3a1..1228ed275a9f 100644
> --- a/net/mptcp/subflow.c
> +++ b/net/mptcp/subflow.c
> @@ -914,6 +914,7 @@ static enum mapping_status validate_data_csum(struct sock *ssk, struct sk_buff *
> 	if (unlikely(csum_fold(csum))) {
> 		MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_DATACSUMERR);
> 		subflow->send_mp_fail = 1;
> +		MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPFAILTX);

Looks like MPTCP_MIB_DATACSUMERR and MPTCP_MIB_MPFAILTX will always be 
exactly the same, do we need the new one?

> 		return subflow->mp_join ? MAPPING_INVALID : MAPPING_DUMMY;
> 	}
>
> -- 
> 2.31.1
>
>
>

--
Mat Martineau
Intel

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

end of thread, other threads:[~2021-06-26  0:19 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-24 12:02 [MPTCP][PATCH v2 mptcp-next 0/5] MP_FAIL support Geliang Tang
2021-06-24 12:02 ` [MPTCP][PATCH v2 mptcp-next 1/5] mptcp: MP_FAIL suboption sending Geliang Tang
2021-06-24 12:02   ` [MPTCP][PATCH v2 mptcp-next 2/5] mptcp: MP_FAIL suboption receiving Geliang Tang
2021-06-24 12:02     ` [MPTCP][PATCH v2 mptcp-next 3/5] mptcp: send out MP_FAIL when data checksum fail Geliang Tang
2021-06-24 12:02       ` [MPTCP][PATCH v2 mptcp-next 4/5] mptcp: add the mibs for MP_FAIL Geliang Tang
2021-06-24 12:02         ` [MPTCP][PATCH v2 mptcp-next 5/5] selftests: mptcp: add MP_FAIL mibs check Geliang Tang
2021-06-26  0:19         ` [MPTCP][PATCH v2 mptcp-next 4/5] mptcp: add the mibs for MP_FAIL Mat Martineau
2021-06-26  0:18       ` [MPTCP][PATCH v2 mptcp-next 3/5] mptcp: send out MP_FAIL when data checksum fail Mat Martineau
2021-06-25 23:47     ` [MPTCP][PATCH v2 mptcp-next 2/5] mptcp: MP_FAIL suboption receiving Mat Martineau

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.