forked from mirrors/linux
		
	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: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Geliang Tang <geliangtang@xiaomi.com> Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									d7b2690837
								
							
						
					
					
						commit
						c25aeb4e09
					
				
					 3 changed files with 62 additions and 5 deletions
				
			
		|  | @ -74,7 +74,10 @@ struct mptcp_out_options { | ||||||
| 			struct mptcp_addr_info addr; | 			struct mptcp_addr_info addr; | ||||||
| 			u64 ahmac; | 			u64 ahmac; | ||||||
| 		}; | 		}; | ||||||
|  | 		struct { | ||||||
| 			struct mptcp_ext ext_copy; | 			struct mptcp_ext ext_copy; | ||||||
|  | 			u64 fail_seq; | ||||||
|  | 		}; | ||||||
| 		struct { | 		struct { | ||||||
| 			u32 nonce; | 			u32 nonce; | ||||||
| 			u32 token; | 			u32 token; | ||||||
|  |  | ||||||
|  | @ -767,7 +767,7 @@ static bool mptcp_established_options_mp_prio(struct sock *sk, | ||||||
| 	return true; | 	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 *size, | ||||||
| 						   unsigned int remaining, | 						   unsigned int remaining, | ||||||
| 						   struct mptcp_out_options *opts) | 						   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); | 	const struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); | ||||||
| 
 | 
 | ||||||
| 	if (remaining < TCPOLEN_MPTCP_RST) | 	if (remaining < TCPOLEN_MPTCP_RST) | ||||||
| 		return; | 		return false; | ||||||
| 
 | 
 | ||||||
| 	*size = TCPOLEN_MPTCP_RST; | 	*size = TCPOLEN_MPTCP_RST; | ||||||
| 	opts->suboptions |= OPTION_MPTCP_RST; | 	opts->suboptions |= OPTION_MPTCP_RST; | ||||||
| 	opts->reset_transient = subflow->reset_transient; | 	opts->reset_transient = subflow->reset_transient; | ||||||
| 	opts->reset_reason = subflow->reset_reason; | 	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, | 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; | 		return false; | ||||||
| 
 | 
 | ||||||
| 	if (unlikely(skb && TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) { | 	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; | 		return true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	snd_data_fin = mptcp_data_fin_enabled(msk); | 	snd_data_fin = mptcp_data_fin_enabled(msk); | ||||||
| 	if (mptcp_established_options_mp(sk, skb, snd_data_fin, &opt_size, remaining, opts)) | 	if (mptcp_established_options_mp(sk, skb, snd_data_fin, &opt_size, remaining, opts)) | ||||||
| 		ret = true; | 		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; | 		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
 | 	/* we reserved enough space for the above options, and exceeding the
 | ||||||
| 	 * TCP option space would be fatal | 	 * 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, | void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp, | ||||||
| 			 struct mptcp_out_options *opts) | 			 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 */ | 	/* RST is mutually exclusive with everything else */ | ||||||
| 	if (unlikely(OPTION_MPTCP_RST & opts->suboptions)) { | 	if (unlikely(OPTION_MPTCP_RST & opts->suboptions)) { | ||||||
| 		*ptr++ = mptcp_option(MPTCPOPT_RST, | 		*ptr++ = mptcp_option(MPTCPOPT_RST, | ||||||
|  |  | ||||||
|  | @ -27,6 +27,7 @@ | ||||||
| #define OPTION_MPTCP_PRIO	BIT(9) | #define OPTION_MPTCP_PRIO	BIT(9) | ||||||
| #define OPTION_MPTCP_RST	BIT(10) | #define OPTION_MPTCP_RST	BIT(10) | ||||||
| #define OPTION_MPTCP_DSS	BIT(11) | #define OPTION_MPTCP_DSS	BIT(11) | ||||||
|  | #define OPTION_MPTCP_FAIL	BIT(12) | ||||||
| 
 | 
 | ||||||
| /* MPTCP option subtypes */ | /* MPTCP option subtypes */ | ||||||
| #define MPTCPOPT_MP_CAPABLE	0 | #define MPTCPOPT_MP_CAPABLE	0 | ||||||
|  | @ -68,6 +69,7 @@ | ||||||
| #define TCPOLEN_MPTCP_PRIO_ALIGN	4 | #define TCPOLEN_MPTCP_PRIO_ALIGN	4 | ||||||
| #define TCPOLEN_MPTCP_FASTCLOSE		12 | #define TCPOLEN_MPTCP_FASTCLOSE		12 | ||||||
| #define TCPOLEN_MPTCP_RST		4 | #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) | #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, | 		mpc_map : 1, | ||||||
| 		backup : 1, | 		backup : 1, | ||||||
| 		send_mp_prio : 1, | 		send_mp_prio : 1, | ||||||
|  | 		send_mp_fail : 1, | ||||||
| 		rx_eof : 1, | 		rx_eof : 1, | ||||||
| 		can_ack : 1,        /* only after processing the remote a key */ | 		can_ack : 1,        /* only after processing the remote a key */ | ||||||
| 		disposable : 1,	    /* ctx can be free at ulp release time */ | 		disposable : 1,	    /* ctx can be free at ulp release time */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Geliang Tang
						Geliang Tang