Commit c25aeb4e authored by Geliang Tang's avatar Geliang Tang Committed by David S. Miller
Browse files

mptcp: MP_FAIL suboption sending



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.

An MP_FAIL option could be included in a RST or on the subflow-level
ACK.

Suggested-by: default avatarPaolo Abeni <pabeni@redhat.com>
Signed-off-by: default avatarGeliang Tang <geliangtang@xiaomi.com>
Signed-off-by: default avatarMat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d7b26908
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -74,7 +74,10 @@ struct mptcp_out_options {
			struct mptcp_addr_info addr;
			u64 ahmac;
		};
		struct {
			struct mptcp_ext ext_copy;
			u64 fail_seq;
		};
		struct {
			u32 nonce;
			u32 token;
+55 −4
Original line number Diff line number Diff line
@@ -767,7 +767,7 @@ static bool mptcp_established_options_mp_prio(struct sock *sk,
	return true;
}

static noinline void mptcp_established_options_rst(struct sock *sk, struct sk_buff *skb,
static noinline bool mptcp_established_options_rst(struct sock *sk, struct sk_buff *skb,
						   unsigned int *size,
						   unsigned int remaining,
						   struct mptcp_out_options *opts)
@@ -775,12 +775,36 @@ static noinline void mptcp_established_options_rst(struct sock *sk, struct sk_bu
	const struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);

	if (remaining < TCPOLEN_MPTCP_RST)
		return;
		return false;

	*size = TCPOLEN_MPTCP_RST;
	opts->suboptions |= OPTION_MPTCP_RST;
	opts->reset_transient = subflow->reset_transient;
	opts->reset_reason = subflow->reset_reason;

	return true;
}

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 (likely(!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,
@@ -799,15 +823,28 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
		return false;

	if (unlikely(skb && TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) {
		mptcp_established_options_rst(sk, skb, size, remaining, opts);
		if (mptcp_established_options_mp_fail(sk, &opt_size, remaining, opts)) {
			*size += opt_size;
			remaining -= opt_size;
		}
		if (mptcp_established_options_rst(sk, skb, &opt_size, remaining, opts)) {
			*size += opt_size;
			remaining -= opt_size;
		}
		return true;
	}

	snd_data_fin = mptcp_data_fin_enabled(msk);
	if (mptcp_established_options_mp(sk, skb, snd_data_fin, &opt_size, remaining, opts))
		ret = true;
	else if (mptcp_established_options_dss(sk, skb, snd_data_fin, &opt_size, remaining, opts))
	else if (mptcp_established_options_dss(sk, skb, snd_data_fin, &opt_size, remaining, opts)) {
		ret = true;
		if (mptcp_established_options_mp_fail(sk, &opt_size, remaining, opts)) {
			*size += opt_size;
			remaining -= opt_size;
			return true;
		}
	}

	/* we reserved enough space for the above options, and exceeding the
	 * TCP option space would be fatal
@@ -1210,6 +1247,20 @@ static u16 mptcp_make_csum(const struct mptcp_ext *mpext)
void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
			 struct mptcp_out_options *opts)
{
	if (unlikely(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;
	}

	/* RST is mutually exclusive with everything else */
	if (unlikely(OPTION_MPTCP_RST & opts->suboptions)) {
		*ptr++ = mptcp_option(MPTCPOPT_RST,
+3 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#define OPTION_MPTCP_PRIO	BIT(9)
#define OPTION_MPTCP_RST	BIT(10)
#define OPTION_MPTCP_DSS	BIT(11)
#define OPTION_MPTCP_FAIL	BIT(12)

/* MPTCP option subtypes */
#define MPTCPOPT_MP_CAPABLE	0
@@ -68,6 +69,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)

@@ -429,6 +431,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 */