All of lore.kernel.org
 help / color / mirror / Atom feed
* [MPTCP] [RFC v2 mptcp-next 01/12] mptcp: add syncookie support
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: mptcp

[-- Attachment #1: Type: text/plain, Size: 4186 bytes --]

TL;DR: please review the changes in TCP for sanity, thanks.

This RFC series adds syn cookie support to MPTCP.

At this time, when syn-cookies are used and the SYN had an MPTCP-option,
the cookie SYNACK is sent with MPTCP option cleared, as the code path
that creates a request socket based off a valid ACK token lacks the
needed changes to construct MPTCP request sockets.

After this series, if SYN carries an MPTCP option, the MPTCP option is
not cleared anymore and reconstruction will be done using the MPTCP option
that is re-sent with the ACK.

No additional state gets encoded into the syn cookie or the timestamp.

There are differences from the normal (syn queue) case with MPTCP:

I. When syn-cookies are used, the server-generated key is not stored,
   it is best-effort only: Storing state would defeat the purpose of
   cookies.

The drawback is that the next connection request that comes in before
the cookie-ACK has a small chance that it will generate the same
local_key.

If this happens, the cookie ACK that comes in "second" (and contains
the local and remote key in mptcp options) will recompute the token hash
and then detects that this is already in use.
This results in late TCP fallback, i.e. the connection sock is not marked
as mptcp capable.

II). SYN packets containing a MP_JOIN requests cannot be handled without
     storing state.  This is because the SYN contains a nonce value that
     we need to validate the HMAC of the MP_JOIN ACK that completes 3whs.

There are only 2 ways to solve this:
 a). Do not support JOINs when cookies are used.
 b). Store the nonce somewhere.

The approach chosen here is b), by allowing the MPTCP init_req function to
override the listener sockets queue limits and store the request socket
anyway.

This is subject to following constraints:
1. The token in the JOIN request is valid (i.e. it refers an
   established MPTCP connection).
2. The MPTCP connection can still accept a new subflow.

Extra accounting is added to the MPTCP parent socket.  In case the
parent already has too many subflow connections (including half-open ones),
cookie mode is used instead (which won't work for a join request).
This will trigger TCP fallback + RST when ack comes back to notify
peer about failed JOIN.

I've added comments to a few of the TCP patches to suggest alternative
approaches for a few details.

Comments welcome.

Florian Westphal (12):
      tcp: remove cookie_ts bit from request_sock
      tcp: syncookies: use single reqsk_free location
      mptcp: token: move retry to caller
      mptcp: subflow: split subflow_init_req into helpers
      mptcp: rename and export mptcp_subflow_request_sock_ops
      tcp: remove sk_listener const qualifier from req_init function
      tcp: pass want_cookie down to req_init function
      mptcp: subflow: add mptcp_subflow_init_cookie_req helper
      tcp: syncookies: keep mptcp option enabled
      tcp: handle want_cookie clause via reqsk_put
      mptcp: enable JOIN requests even if cookies are in use
      selftests: mptcp: make 2nd net namespace use tcp syn cookies unconditionally

 drivers/crypto/chelsio/chtls/chtls_cm.c            |   1 -
 include/net/mptcp.h                                |  11 ++
 include/net/request_sock.h                         |   3 +-
 include/net/tcp.h                                  |   5 +-
 net/ipv4/syncookies.c                              |  40 ++--
 net/ipv4/tcp_input.c                               |  14 +-
 net/ipv4/tcp_ipv4.c                                |   5 +-
 net/ipv4/tcp_output.c                              |   2 +-
 net/ipv6/syncookies.c                              |  17 +-
 net/ipv6/tcp_ipv6.c                                |   5 +-
 net/mptcp/pm_netlink.c                             |   2 +-
 net/mptcp/protocol.h                               |   3 +
 net/mptcp/subflow.c                                | 203 +++++++++++++++++----
 net/mptcp/token.c                                  |  38 +++-
 tools/testing/selftests/net/mptcp/mptcp_connect.sh |  50 +++++
 15 files changed, 321 insertions(+), 78 deletions(-)

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

* [RFC v2 mptcp-next 01/12] mptcp: add syncookie support
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: netdev; +Cc: mathew.j.martineau, edumazet, mptcp, matthieu.baerts

TL;DR: please review the changes in TCP for sanity, thanks.

This RFC series adds syn cookie support to MPTCP.

At this time, when syn-cookies are used and the SYN had an MPTCP-option,
the cookie SYNACK is sent with MPTCP option cleared, as the code path
that creates a request socket based off a valid ACK token lacks the
needed changes to construct MPTCP request sockets.

After this series, if SYN carries an MPTCP option, the MPTCP option is
not cleared anymore and reconstruction will be done using the MPTCP option
that is re-sent with the ACK.

No additional state gets encoded into the syn cookie or the timestamp.

There are differences from the normal (syn queue) case with MPTCP:

I. When syn-cookies are used, the server-generated key is not stored,
   it is best-effort only: Storing state would defeat the purpose of
   cookies.

The drawback is that the next connection request that comes in before
the cookie-ACK has a small chance that it will generate the same
local_key.

If this happens, the cookie ACK that comes in "second" (and contains
the local and remote key in mptcp options) will recompute the token hash
and then detects that this is already in use.
This results in late TCP fallback, i.e. the connection sock is not marked
as mptcp capable.

II). SYN packets containing a MP_JOIN requests cannot be handled without
     storing state.  This is because the SYN contains a nonce value that
     we need to validate the HMAC of the MP_JOIN ACK that completes 3whs.

There are only 2 ways to solve this:
 a). Do not support JOINs when cookies are used.
 b). Store the nonce somewhere.

The approach chosen here is b), by allowing the MPTCP init_req function to
override the listener sockets queue limits and store the request socket
anyway.

This is subject to following constraints:
1. The token in the JOIN request is valid (i.e. it refers an
   established MPTCP connection).
2. The MPTCP connection can still accept a new subflow.

Extra accounting is added to the MPTCP parent socket.  In case the
parent already has too many subflow connections (including half-open ones),
cookie mode is used instead (which won't work for a join request).
This will trigger TCP fallback + RST when ack comes back to notify
peer about failed JOIN.

I've added comments to a few of the TCP patches to suggest alternative
approaches for a few details.

Comments welcome.

Florian Westphal (12):
      tcp: remove cookie_ts bit from request_sock
      tcp: syncookies: use single reqsk_free location
      mptcp: token: move retry to caller
      mptcp: subflow: split subflow_init_req into helpers
      mptcp: rename and export mptcp_subflow_request_sock_ops
      tcp: remove sk_listener const qualifier from req_init function
      tcp: pass want_cookie down to req_init function
      mptcp: subflow: add mptcp_subflow_init_cookie_req helper
      tcp: syncookies: keep mptcp option enabled
      tcp: handle want_cookie clause via reqsk_put
      mptcp: enable JOIN requests even if cookies are in use
      selftests: mptcp: make 2nd net namespace use tcp syn cookies unconditionally

 drivers/crypto/chelsio/chtls/chtls_cm.c            |   1 -
 include/net/mptcp.h                                |  11 ++
 include/net/request_sock.h                         |   3 +-
 include/net/tcp.h                                  |   5 +-
 net/ipv4/syncookies.c                              |  40 ++--
 net/ipv4/tcp_input.c                               |  14 +-
 net/ipv4/tcp_ipv4.c                                |   5 +-
 net/ipv4/tcp_output.c                              |   2 +-
 net/ipv6/syncookies.c                              |  17 +-
 net/ipv6/tcp_ipv6.c                                |   5 +-
 net/mptcp/pm_netlink.c                             |   2 +-
 net/mptcp/protocol.h                               |   3 +
 net/mptcp/subflow.c                                | 203 +++++++++++++++++----
 net/mptcp/token.c                                  |  38 +++-
 tools/testing/selftests/net/mptcp/mptcp_connect.sh |  50 +++++
 15 files changed, 321 insertions(+), 78 deletions(-)


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

* [MPTCP] [RFC v2 mptcp-next 01/12] tcp: remove cookie_ts bit from request_sock
  2020-07-21 20:36 ` Florian Westphal
@ 2020-07-21 20:36 ` Florian Westphal
  -1 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: mptcp

[-- Attachment #1: Type: text/plain, Size: 2930 bytes --]

No need for this anymore; nowadays output function has a 'synack_type'
argument that tells us when the syn/ack is emitted via syncookies.

The request already tells us when timestamps are supported, so check
both to detect special timestamp for tcp option encoding is needed.

Signed-off-by: Florian Westphal <fw(a)strlen.de>
---
 drivers/crypto/chelsio/chtls/chtls_cm.c | 1 -
 include/net/request_sock.h              | 3 +--
 net/ipv4/tcp_input.c                    | 2 --
 net/ipv4/tcp_output.c                   | 2 +-
 4 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/crypto/chelsio/chtls/chtls_cm.c b/drivers/crypto/chelsio/chtls/chtls_cm.c
index f200fae6f7cb..fcd41f586da8 100644
--- a/drivers/crypto/chelsio/chtls/chtls_cm.c
+++ b/drivers/crypto/chelsio/chtls/chtls_cm.c
@@ -1347,7 +1347,6 @@ static void chtls_pass_accept_request(struct sock *sk,
 
 	oreq->rsk_rcv_wnd = 0;
 	oreq->rsk_window_clamp = 0;
-	oreq->cookie_ts = 0;
 	oreq->mss = 0;
 	oreq->ts_recent = 0;
 
diff --git a/include/net/request_sock.h b/include/net/request_sock.h
index cf8b33213bbc..2f717d4dafc5 100644
--- a/include/net/request_sock.h
+++ b/include/net/request_sock.h
@@ -54,8 +54,7 @@ struct request_sock {
 	struct request_sock		*dl_next;
 	u16				mss;
 	u8				num_retrans; /* number of retransmits */
-	u8				cookie_ts:1; /* syncookie: encode tcpopts in timestamp */
-	u8				num_timeout:7; /* number of timeouts */
+	u8				num_timeout; /* number of timeouts */
 	u32				ts_recent;
 	struct timer_list		rsk_timer;
 	const struct request_sock_ops	*rsk_ops;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 82906deb7874..727ca87a2929 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6518,7 +6518,6 @@ static void tcp_openreq_init(struct request_sock *req,
 	struct inet_request_sock *ireq = inet_rsk(req);
 
 	req->rsk_rcv_wnd = 0;		/* So that tcp_send_synack() knows! */
-	req->cookie_ts = 0;
 	tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq;
 	tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
 	tcp_rsk(req)->snt_synack = 0;
@@ -6738,7 +6737,6 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 
 	if (want_cookie) {
 		isn = cookie_init_sequence(af_ops, sk, skb, &req->mss);
-		req->cookie_ts = tmp_opt.tstamp_ok;
 		if (!tmp_opt.tstamp_ok)
 			inet_rsk(req)->ecn_ok = 0;
 	}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index dc0117013ba5..0ca3d75dcc52 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -3390,7 +3390,7 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
 	memset(&opts, 0, sizeof(opts));
 	now = tcp_clock_ns();
 #ifdef CONFIG_SYN_COOKIES
-	if (unlikely(req->cookie_ts))
+	if (unlikely(synack_type == TCP_SYNACK_COOKIE && inet_rsk(req)->tstamp_ok))
 		skb->skb_mstamp_ns = cookie_init_timestamp(req, now);
 	else
 #endif
-- 
2.26.2

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

* [RFC v2 mptcp-next 01/12] tcp: remove cookie_ts bit from request_sock
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: netdev
  Cc: mathew.j.martineau, edumazet, mptcp, matthieu.baerts, Florian Westphal

No need for this anymore; nowadays output function has a 'synack_type'
argument that tells us when the syn/ack is emitted via syncookies.

The request already tells us when timestamps are supported, so check
both to detect special timestamp for tcp option encoding is needed.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 drivers/crypto/chelsio/chtls/chtls_cm.c | 1 -
 include/net/request_sock.h              | 3 +--
 net/ipv4/tcp_input.c                    | 2 --
 net/ipv4/tcp_output.c                   | 2 +-
 4 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/crypto/chelsio/chtls/chtls_cm.c b/drivers/crypto/chelsio/chtls/chtls_cm.c
index f200fae6f7cb..fcd41f586da8 100644
--- a/drivers/crypto/chelsio/chtls/chtls_cm.c
+++ b/drivers/crypto/chelsio/chtls/chtls_cm.c
@@ -1347,7 +1347,6 @@ static void chtls_pass_accept_request(struct sock *sk,
 
 	oreq->rsk_rcv_wnd = 0;
 	oreq->rsk_window_clamp = 0;
-	oreq->cookie_ts = 0;
 	oreq->mss = 0;
 	oreq->ts_recent = 0;
 
diff --git a/include/net/request_sock.h b/include/net/request_sock.h
index cf8b33213bbc..2f717d4dafc5 100644
--- a/include/net/request_sock.h
+++ b/include/net/request_sock.h
@@ -54,8 +54,7 @@ struct request_sock {
 	struct request_sock		*dl_next;
 	u16				mss;
 	u8				num_retrans; /* number of retransmits */
-	u8				cookie_ts:1; /* syncookie: encode tcpopts in timestamp */
-	u8				num_timeout:7; /* number of timeouts */
+	u8				num_timeout; /* number of timeouts */
 	u32				ts_recent;
 	struct timer_list		rsk_timer;
 	const struct request_sock_ops	*rsk_ops;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 82906deb7874..727ca87a2929 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6518,7 +6518,6 @@ static void tcp_openreq_init(struct request_sock *req,
 	struct inet_request_sock *ireq = inet_rsk(req);
 
 	req->rsk_rcv_wnd = 0;		/* So that tcp_send_synack() knows! */
-	req->cookie_ts = 0;
 	tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq;
 	tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
 	tcp_rsk(req)->snt_synack = 0;
@@ -6738,7 +6737,6 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 
 	if (want_cookie) {
 		isn = cookie_init_sequence(af_ops, sk, skb, &req->mss);
-		req->cookie_ts = tmp_opt.tstamp_ok;
 		if (!tmp_opt.tstamp_ok)
 			inet_rsk(req)->ecn_ok = 0;
 	}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index dc0117013ba5..0ca3d75dcc52 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -3390,7 +3390,7 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
 	memset(&opts, 0, sizeof(opts));
 	now = tcp_clock_ns();
 #ifdef CONFIG_SYN_COOKIES
-	if (unlikely(req->cookie_ts))
+	if (unlikely(synack_type == TCP_SYNACK_COOKIE && inet_rsk(req)->tstamp_ok))
 		skb->skb_mstamp_ns = cookie_init_timestamp(req, now);
 	else
 #endif
-- 
2.26.2


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

* [MPTCP] [RFC v2 mptcp-next 02/12] tcp: syncookies: use single reqsk_free location
  2020-07-21 20:36 ` Florian Westphal
@ 2020-07-21 20:36 ` Florian Westphal
  -1 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: mptcp

[-- Attachment #1: Type: text/plain, Size: 1609 bytes --]

Add a common error label and use it.

Followup patch would need to add a 3rd 'if (err) { free(x); goto out;}.

This will allow use of simpler 'if (err) goto free' instead.

Signed-off-by: Florian Westphal <fw(a)strlen.de>
---
 net/ipv4/syncookies.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 9a4f6b16c9bc..ee17f55401ef 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -363,10 +363,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
 	 */
 	RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(sock_net(sk), skb));
 
-	if (security_inet_conn_request(sk, skb, req)) {
-		reqsk_free(req);
-		goto out;
-	}
+	if (security_inet_conn_request(sk, skb, req))
+		goto out_free;
 
 	req->num_retrans = 0;
 
@@ -383,10 +381,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
 			   ireq->ir_loc_addr, th->source, th->dest, sk->sk_uid);
 	security_req_classify_flow(req, flowi4_to_flowi(&fl4));
 	rt = ip_route_output_key(sock_net(sk), &fl4);
-	if (IS_ERR(rt)) {
-		reqsk_free(req);
-		goto out;
-	}
+	if (IS_ERR(rt))
+		goto out_free;
 
 	/* Try to redo what tcp_v4_send_synack did. */
 	req->rsk_window_clamp = tp->window_clamp ? :dst_metric(&rt->dst, RTAX_WINDOW);
@@ -405,5 +401,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
 	 */
 	if (ret)
 		inet_sk(ret)->cork.fl.u.ip4 = fl4;
-out:	return ret;
+	return ret;
+
+out_free:
+	reqsk_free(req);
+out:
+	return ret;
 }
-- 
2.26.2

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

* [RFC v2 mptcp-next 02/12] tcp: syncookies: use single reqsk_free location
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: netdev
  Cc: mathew.j.martineau, edumazet, mptcp, matthieu.baerts, Florian Westphal

Add a common error label and use it.

Followup patch would need to add a 3rd 'if (err) { free(x); goto out;}.

This will allow use of simpler 'if (err) goto free' instead.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 net/ipv4/syncookies.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 9a4f6b16c9bc..ee17f55401ef 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -363,10 +363,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
 	 */
 	RCU_INIT_POINTER(ireq->ireq_opt, tcp_v4_save_options(sock_net(sk), skb));
 
-	if (security_inet_conn_request(sk, skb, req)) {
-		reqsk_free(req);
-		goto out;
-	}
+	if (security_inet_conn_request(sk, skb, req))
+		goto out_free;
 
 	req->num_retrans = 0;
 
@@ -383,10 +381,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
 			   ireq->ir_loc_addr, th->source, th->dest, sk->sk_uid);
 	security_req_classify_flow(req, flowi4_to_flowi(&fl4));
 	rt = ip_route_output_key(sock_net(sk), &fl4);
-	if (IS_ERR(rt)) {
-		reqsk_free(req);
-		goto out;
-	}
+	if (IS_ERR(rt))
+		goto out_free;
 
 	/* Try to redo what tcp_v4_send_synack did. */
 	req->rsk_window_clamp = tp->window_clamp ? :dst_metric(&rt->dst, RTAX_WINDOW);
@@ -405,5 +401,10 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
 	 */
 	if (ret)
 		inet_sk(ret)->cork.fl.u.ip4 = fl4;
-out:	return ret;
+	return ret;
+
+out_free:
+	reqsk_free(req);
+out:
+	return ret;
 }
-- 
2.26.2


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

* [MPTCP] [RFC v2 mptcp-next 03/12] mptcp: token: move retry to caller
  2020-07-21 20:36 ` Florian Westphal
@ 2020-07-21 20:36 ` Florian Westphal
  -1 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: mptcp

[-- Attachment #1: Type: text/plain, Size: 2547 bytes --]

Once syncookie support is added, no state will be stored anymore when the
syn/ack is generated in syncookie mode.

When the ACK comes back, the generated key will be taken from the TCP ACK,
the token is re-generated and inserted into the token tree.

This means we can't retry with a new key when the token is already taken
in the syncookie case.

Therefore, move the retry logic to the caller to prepare for syncookie
support in mptcp.

Signed-off-by: Florian Westphal <fw(a)strlen.de>
---
 net/mptcp/subflow.c |  9 ++++++++-
 net/mptcp/token.c   | 12 ++++--------
 2 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 27dccf85b928..9526566ec153 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -126,11 +126,18 @@ static void subflow_init_req(struct request_sock *req,
 	}
 
 	if (mp_opt.mp_capable && listener->request_mptcp) {
-		int err;
+		int err, retries = 4;
+
+again:
+		do {
+			get_random_bytes(&subflow_req->local_key, sizeof(subflow_req->local_key));
+		} while (subflow_req->local_key == 0);
 
 		err = mptcp_token_new_request(req);
 		if (err == 0)
 			subflow_req->mp_capable = 1;
+		else if (retries-- > 0)
+			goto again;
 
 		subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq;
 	} else if (mp_opt.mp_join && listener->request_mptcp) {
diff --git a/net/mptcp/token.c b/net/mptcp/token.c
index 97cfc45bcc4f..f82410c54653 100644
--- a/net/mptcp/token.c
+++ b/net/mptcp/token.c
@@ -109,14 +109,12 @@ static void mptcp_crypto_key_gen_sha(u64 *key, u32 *token, u64 *idsn)
 int mptcp_token_new_request(struct request_sock *req)
 {
 	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
-	int retries = TOKEN_MAX_RETRIES;
 	struct token_bucket *bucket;
 	u32 token;
 
-again:
-	mptcp_crypto_key_gen_sha(&subflow_req->local_key,
-				 &subflow_req->token,
-				 &subflow_req->idsn);
+	mptcp_crypto_key_sha(subflow_req->local_key,
+			     &subflow_req->token,
+			     &subflow_req->idsn);
 	pr_debug("req=%p local_key=%llu, token=%u, idsn=%llu\n",
 		 req, subflow_req->local_key, subflow_req->token,
 		 subflow_req->idsn);
@@ -126,9 +124,7 @@ int mptcp_token_new_request(struct request_sock *req)
 	spin_lock_bh(&bucket->lock);
 	if (__token_bucket_busy(bucket, token)) {
 		spin_unlock_bh(&bucket->lock);
-		if (!--retries)
-			return -EBUSY;
-		goto again;
+		return -EBUSY;
 	}
 
 	hlist_nulls_add_head_rcu(&subflow_req->token_node, &bucket->req_chain);
-- 
2.26.2

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

* [RFC v2 mptcp-next 03/12] mptcp: token: move retry to caller
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: netdev
  Cc: mathew.j.martineau, edumazet, mptcp, matthieu.baerts, Florian Westphal

Once syncookie support is added, no state will be stored anymore when the
syn/ack is generated in syncookie mode.

When the ACK comes back, the generated key will be taken from the TCP ACK,
the token is re-generated and inserted into the token tree.

This means we can't retry with a new key when the token is already taken
in the syncookie case.

Therefore, move the retry logic to the caller to prepare for syncookie
support in mptcp.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 net/mptcp/subflow.c |  9 ++++++++-
 net/mptcp/token.c   | 12 ++++--------
 2 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 27dccf85b928..9526566ec153 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -126,11 +126,18 @@ static void subflow_init_req(struct request_sock *req,
 	}
 
 	if (mp_opt.mp_capable && listener->request_mptcp) {
-		int err;
+		int err, retries = 4;
+
+again:
+		do {
+			get_random_bytes(&subflow_req->local_key, sizeof(subflow_req->local_key));
+		} while (subflow_req->local_key == 0);
 
 		err = mptcp_token_new_request(req);
 		if (err == 0)
 			subflow_req->mp_capable = 1;
+		else if (retries-- > 0)
+			goto again;
 
 		subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq;
 	} else if (mp_opt.mp_join && listener->request_mptcp) {
diff --git a/net/mptcp/token.c b/net/mptcp/token.c
index 97cfc45bcc4f..f82410c54653 100644
--- a/net/mptcp/token.c
+++ b/net/mptcp/token.c
@@ -109,14 +109,12 @@ static void mptcp_crypto_key_gen_sha(u64 *key, u32 *token, u64 *idsn)
 int mptcp_token_new_request(struct request_sock *req)
 {
 	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
-	int retries = TOKEN_MAX_RETRIES;
 	struct token_bucket *bucket;
 	u32 token;
 
-again:
-	mptcp_crypto_key_gen_sha(&subflow_req->local_key,
-				 &subflow_req->token,
-				 &subflow_req->idsn);
+	mptcp_crypto_key_sha(subflow_req->local_key,
+			     &subflow_req->token,
+			     &subflow_req->idsn);
 	pr_debug("req=%p local_key=%llu, token=%u, idsn=%llu\n",
 		 req, subflow_req->local_key, subflow_req->token,
 		 subflow_req->idsn);
@@ -126,9 +124,7 @@ int mptcp_token_new_request(struct request_sock *req)
 	spin_lock_bh(&bucket->lock);
 	if (__token_bucket_busy(bucket, token)) {
 		spin_unlock_bh(&bucket->lock);
-		if (!--retries)
-			return -EBUSY;
-		goto again;
+		return -EBUSY;
 	}
 
 	hlist_nulls_add_head_rcu(&subflow_req->token_node, &bucket->req_chain);
-- 
2.26.2


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

* [MPTCP] [RFC v2 mptcp-next 04/12] mptcp: subflow: split subflow_init_req into helpers
  2020-07-21 20:36 ` Florian Westphal
@ 2020-07-21 20:36 ` Florian Westphal
  -1 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: mptcp

[-- Attachment #1: Type: text/plain, Size: 2809 bytes --]

When syncookie support is added, we will need to add a variant of
subflow_init_req() helper.  It will do almost same thing except
that it will not compute/add a token to the mptcp token tree.

To avoid excess copy&paste, this commit splits away part of the
code into helpers that can then be re-used from the 'no insert'
function added in a followup change.

Signed-off-by: Florian Westphal <fw(a)strlen.de>
---
 net/mptcp/subflow.c | 49 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 35 insertions(+), 14 deletions(-)

diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 9526566ec153..800e7d472dcd 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -91,17 +91,9 @@ static struct mptcp_sock *subflow_token_join_request(struct request_sock *req,
 	return msk;
 }
 
-static void subflow_init_req(struct request_sock *req,
-			     const struct sock *sk_listener,
-			     struct sk_buff *skb)
+static int __subflow_init_req(struct request_sock *req, const struct sock *sk_listener)
 {
-	struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk_listener);
 	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
-	struct mptcp_options_received mp_opt;
-
-	pr_debug("subflow_req=%p, listener=%p", subflow_req, listener);
-
-	mptcp_get_options(skb, &mp_opt);
 
 	subflow_req->mp_capable = 0;
 	subflow_req->mp_join = 0;
@@ -113,18 +105,47 @@ static void subflow_init_req(struct request_sock *req,
 	 * TCP option space.
 	 */
 	if (rcu_access_pointer(tcp_sk(sk_listener)->md5sig_info))
-		return;
+		return -EINVAL;
 #endif
 
-	if (mp_opt.mp_capable) {
+	return 0;
+}
+
+static int __subflow_check_options(const struct mptcp_options_received *mp_opt,
+				   struct request_sock *req)
+{
+	if (mp_opt->mp_capable) {
 		SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MPCAPABLEPASSIVE);
 
-		if (mp_opt.mp_join)
-			return;
-	} else if (mp_opt.mp_join) {
+		if (mp_opt->mp_join)
+			return -EINVAL;
+	} else if (mp_opt->mp_join) {
 		SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINSYNRX);
 	}
 
+	return 0;
+}
+
+static void subflow_init_req(struct request_sock *req,
+			     const struct sock *sk_listener,
+			     struct sk_buff *skb)
+{
+	struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk_listener);
+	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
+	struct mptcp_options_received mp_opt;
+	int ret;
+
+	pr_debug("subflow_req=%p, listener=%p", subflow_req, listener);
+
+	ret = __subflow_init_req(req, sk_listener);
+	if (ret)
+		return;
+
+	mptcp_get_options(skb, &mp_opt);
+	ret = __subflow_check_options(&mp_opt, req);
+	if (ret)
+		return;
+
 	if (mp_opt.mp_capable && listener->request_mptcp) {
 		int err, retries = 4;
 
-- 
2.26.2

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

* [RFC v2 mptcp-next 04/12] mptcp: subflow: split subflow_init_req into helpers
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: netdev
  Cc: mathew.j.martineau, edumazet, mptcp, matthieu.baerts, Florian Westphal

When syncookie support is added, we will need to add a variant of
subflow_init_req() helper.  It will do almost same thing except
that it will not compute/add a token to the mptcp token tree.

To avoid excess copy&paste, this commit splits away part of the
code into helpers that can then be re-used from the 'no insert'
function added in a followup change.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 net/mptcp/subflow.c | 49 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 35 insertions(+), 14 deletions(-)

diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 9526566ec153..800e7d472dcd 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -91,17 +91,9 @@ static struct mptcp_sock *subflow_token_join_request(struct request_sock *req,
 	return msk;
 }
 
-static void subflow_init_req(struct request_sock *req,
-			     const struct sock *sk_listener,
-			     struct sk_buff *skb)
+static int __subflow_init_req(struct request_sock *req, const struct sock *sk_listener)
 {
-	struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk_listener);
 	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
-	struct mptcp_options_received mp_opt;
-
-	pr_debug("subflow_req=%p, listener=%p", subflow_req, listener);
-
-	mptcp_get_options(skb, &mp_opt);
 
 	subflow_req->mp_capable = 0;
 	subflow_req->mp_join = 0;
@@ -113,18 +105,47 @@ static void subflow_init_req(struct request_sock *req,
 	 * TCP option space.
 	 */
 	if (rcu_access_pointer(tcp_sk(sk_listener)->md5sig_info))
-		return;
+		return -EINVAL;
 #endif
 
-	if (mp_opt.mp_capable) {
+	return 0;
+}
+
+static int __subflow_check_options(const struct mptcp_options_received *mp_opt,
+				   struct request_sock *req)
+{
+	if (mp_opt->mp_capable) {
 		SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MPCAPABLEPASSIVE);
 
-		if (mp_opt.mp_join)
-			return;
-	} else if (mp_opt.mp_join) {
+		if (mp_opt->mp_join)
+			return -EINVAL;
+	} else if (mp_opt->mp_join) {
 		SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINSYNRX);
 	}
 
+	return 0;
+}
+
+static void subflow_init_req(struct request_sock *req,
+			     const struct sock *sk_listener,
+			     struct sk_buff *skb)
+{
+	struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk_listener);
+	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
+	struct mptcp_options_received mp_opt;
+	int ret;
+
+	pr_debug("subflow_req=%p, listener=%p", subflow_req, listener);
+
+	ret = __subflow_init_req(req, sk_listener);
+	if (ret)
+		return;
+
+	mptcp_get_options(skb, &mp_opt);
+	ret = __subflow_check_options(&mp_opt, req);
+	if (ret)
+		return;
+
 	if (mp_opt.mp_capable && listener->request_mptcp) {
 		int err, retries = 4;
 
-- 
2.26.2


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

* [MPTCP] [RFC v2 mptcp-next 05/12] mptcp: rename and export mptcp_subflow_request_sock_ops
  2020-07-21 20:36 ` Florian Westphal
@ 2020-07-21 20:36 ` Florian Westphal
  -1 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: mptcp

[-- Attachment #1: Type: text/plain, Size: 2415 bytes --]

syncookie code path needs to create an mptcp request sock.

Prepare for this and add mptcp prefix plus needed export of ops struct.

Signed-off-by: Florian Westphal <fw(a)strlen.de>
---
 include/net/mptcp.h |  1 +
 net/mptcp/subflow.c | 11 ++++++-----
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index 02158c257bd4..76eb915bf91c 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -58,6 +58,7 @@ struct mptcp_out_options {
 };
 
 #ifdef CONFIG_MPTCP
+extern struct request_sock_ops mptcp_subflow_request_sock_ops;
 
 void mptcp_init(void);
 
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 800e7d472dcd..6b1d88332a2d 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -293,7 +293,8 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
 	tcp_done(sk);
 }
 
-static struct request_sock_ops subflow_request_sock_ops;
+struct request_sock_ops mptcp_subflow_request_sock_ops;
+EXPORT_SYMBOL_GPL(mptcp_subflow_request_sock_ops);
 static struct tcp_request_sock_ops subflow_request_sock_ipv4_ops;
 
 static int subflow_v4_conn_request(struct sock *sk, struct sk_buff *skb)
@@ -306,7 +307,7 @@ static int subflow_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
 		goto drop;
 
-	return tcp_conn_request(&subflow_request_sock_ops,
+	return tcp_conn_request(&mptcp_subflow_request_sock_ops,
 				&subflow_request_sock_ipv4_ops,
 				sk, skb);
 drop:
@@ -331,7 +332,7 @@ static int subflow_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (!ipv6_unicast_destination(skb))
 		goto drop;
 
-	return tcp_conn_request(&subflow_request_sock_ops,
+	return tcp_conn_request(&mptcp_subflow_request_sock_ops,
 				&subflow_request_sock_ipv6_ops, sk, skb);
 
 drop:
@@ -1310,8 +1311,8 @@ static int subflow_ops_init(struct request_sock_ops *subflow_ops)
 
 void __init mptcp_subflow_init(void)
 {
-	subflow_request_sock_ops = tcp_request_sock_ops;
-	if (subflow_ops_init(&subflow_request_sock_ops) != 0)
+	mptcp_subflow_request_sock_ops = tcp_request_sock_ops;
+	if (subflow_ops_init(&mptcp_subflow_request_sock_ops) != 0)
 		panic("MPTCP: failed to init subflow request sock ops\n");
 
 	subflow_request_sock_ipv4_ops = tcp_request_sock_ipv4_ops;
-- 
2.26.2

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

* [RFC v2 mptcp-next 05/12] mptcp: rename and export mptcp_subflow_request_sock_ops
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: netdev
  Cc: mathew.j.martineau, edumazet, mptcp, matthieu.baerts, Florian Westphal

syncookie code path needs to create an mptcp request sock.

Prepare for this and add mptcp prefix plus needed export of ops struct.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/net/mptcp.h |  1 +
 net/mptcp/subflow.c | 11 ++++++-----
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index 02158c257bd4..76eb915bf91c 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -58,6 +58,7 @@ struct mptcp_out_options {
 };
 
 #ifdef CONFIG_MPTCP
+extern struct request_sock_ops mptcp_subflow_request_sock_ops;
 
 void mptcp_init(void);
 
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 800e7d472dcd..6b1d88332a2d 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -293,7 +293,8 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
 	tcp_done(sk);
 }
 
-static struct request_sock_ops subflow_request_sock_ops;
+struct request_sock_ops mptcp_subflow_request_sock_ops;
+EXPORT_SYMBOL_GPL(mptcp_subflow_request_sock_ops);
 static struct tcp_request_sock_ops subflow_request_sock_ipv4_ops;
 
 static int subflow_v4_conn_request(struct sock *sk, struct sk_buff *skb)
@@ -306,7 +307,7 @@ static int subflow_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
 		goto drop;
 
-	return tcp_conn_request(&subflow_request_sock_ops,
+	return tcp_conn_request(&mptcp_subflow_request_sock_ops,
 				&subflow_request_sock_ipv4_ops,
 				sk, skb);
 drop:
@@ -331,7 +332,7 @@ static int subflow_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (!ipv6_unicast_destination(skb))
 		goto drop;
 
-	return tcp_conn_request(&subflow_request_sock_ops,
+	return tcp_conn_request(&mptcp_subflow_request_sock_ops,
 				&subflow_request_sock_ipv6_ops, sk, skb);
 
 drop:
@@ -1310,8 +1311,8 @@ static int subflow_ops_init(struct request_sock_ops *subflow_ops)
 
 void __init mptcp_subflow_init(void)
 {
-	subflow_request_sock_ops = tcp_request_sock_ops;
-	if (subflow_ops_init(&subflow_request_sock_ops) != 0)
+	mptcp_subflow_request_sock_ops = tcp_request_sock_ops;
+	if (subflow_ops_init(&mptcp_subflow_request_sock_ops) != 0)
 		panic("MPTCP: failed to init subflow request sock ops\n");
 
 	subflow_request_sock_ipv4_ops = tcp_request_sock_ipv4_ops;
-- 
2.26.2


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

* [MPTCP] [RFC v2 mptcp-next 06/12] tcp: remove sk_listener const qualifier from req_init function
  2020-07-21 20:36 ` Florian Westphal
@ 2020-07-21 20:36 ` Florian Westphal
  -1 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: mptcp

[-- Attachment #1: Type: text/plain, Size: 3469 bytes --]

In MPTCP case, we may want to add the request sock to the listner
backlog even when syncookies are in use in order to handle MPTCP
JOIN requests.

This will push the request queue past its limit, but is subject to other
checks:

1. The (32bit) token resolves to a established MPTCP connection.
2. The MPTCP connection can still accept another subflow.

Without this, the mptcp req_init function needs to use a cast such as
 foo((void *)sk_listener);

to suppress a compiler warning.

Signed-off-by: Florian Westphal <fw(a)strlen.de>
---
 This isn't nice given this is only for MPTCP syncookies.

 Possible alternatives are:

  1. Give up on JOIN support in cookie mode and toss this patch.
  2. live with a cast and toss this patch.
  3. Allow ->init_req() to cancel syncookie mode and do the
     add of rsk to sk_listener in the caller/tcp stack.
  4. Do not store the request socket but some more minimal state
     (peers nonce, connid, our nonce, ...)
  I'd rather avoid that since it won't resolve the fundamental issue
  of storing information, also needs to reinvent several things e.g.
  timeouts and so on.

 include/net/tcp.h   | 2 +-
 net/ipv4/tcp_ipv4.c | 2 +-
 net/ipv6/tcp_ipv6.c | 2 +-
 net/mptcp/subflow.c | 4 ++--
 4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 9f7f7c0c1104..74c0b37584ef 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -2018,7 +2018,7 @@ struct tcp_request_sock_ops {
 					  const struct sk_buff *skb);
 #endif
 	void (*init_req)(struct request_sock *req,
-			 const struct sock *sk_listener,
+			 struct sock *sk_listener,
 			 struct sk_buff *skb);
 #ifdef CONFIG_SYN_COOKIES
 	__u32 (*cookie_init_seq)(const struct sk_buff *skb,
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index cd81b6e04efb..f0b01d09d5ad 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1420,7 +1420,7 @@ static bool tcp_v4_inbound_md5_hash(const struct sock *sk,
 }
 
 static void tcp_v4_init_req(struct request_sock *req,
-			    const struct sock *sk_listener,
+			    struct sock *sk_listener,
 			    struct sk_buff *skb)
 {
 	struct inet_request_sock *ireq = inet_rsk(req);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index c34b7834fd84..1c7bf70660e8 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -792,7 +792,7 @@ static bool tcp_v6_inbound_md5_hash(const struct sock *sk,
 }
 
 static void tcp_v6_init_req(struct request_sock *req,
-			    const struct sock *sk_listener,
+			    struct sock *sk_listener,
 			    struct sk_buff *skb)
 {
 	bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags);
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 6b1d88332a2d..55a19f8ed8ec 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -175,7 +175,7 @@ static void subflow_init_req(struct request_sock *req,
 }
 
 static void subflow_v4_init_req(struct request_sock *req,
-				const struct sock *sk_listener,
+				struct sock *sk_listener,
 				struct sk_buff *skb)
 {
 	tcp_rsk(req)->is_mptcp = 1;
@@ -187,7 +187,7 @@ static void subflow_v4_init_req(struct request_sock *req,
 
 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
 static void subflow_v6_init_req(struct request_sock *req,
-				const struct sock *sk_listener,
+				struct sock *sk_listener,
 				struct sk_buff *skb)
 {
 	tcp_rsk(req)->is_mptcp = 1;
-- 
2.26.2

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

* [RFC v2 mptcp-next 06/12] tcp: remove sk_listener const qualifier from req_init function
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: netdev
  Cc: mathew.j.martineau, edumazet, mptcp, matthieu.baerts, Florian Westphal

In MPTCP case, we may want to add the request sock to the listner
backlog even when syncookies are in use in order to handle MPTCP
JOIN requests.

This will push the request queue past its limit, but is subject to other
checks:

1. The (32bit) token resolves to a established MPTCP connection.
2. The MPTCP connection can still accept another subflow.

Without this, the mptcp req_init function needs to use a cast such as
 foo((void *)sk_listener);

to suppress a compiler warning.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 This isn't nice given this is only for MPTCP syncookies.

 Possible alternatives are:

  1. Give up on JOIN support in cookie mode and toss this patch.
  2. live with a cast and toss this patch.
  3. Allow ->init_req() to cancel syncookie mode and do the
     add of rsk to sk_listener in the caller/tcp stack.
  4. Do not store the request socket but some more minimal state
     (peers nonce, connid, our nonce, ...)
  I'd rather avoid that since it won't resolve the fundamental issue
  of storing information, also needs to reinvent several things e.g.
  timeouts and so on.

 include/net/tcp.h   | 2 +-
 net/ipv4/tcp_ipv4.c | 2 +-
 net/ipv6/tcp_ipv6.c | 2 +-
 net/mptcp/subflow.c | 4 ++--
 4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 9f7f7c0c1104..74c0b37584ef 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -2018,7 +2018,7 @@ struct tcp_request_sock_ops {
 					  const struct sk_buff *skb);
 #endif
 	void (*init_req)(struct request_sock *req,
-			 const struct sock *sk_listener,
+			 struct sock *sk_listener,
 			 struct sk_buff *skb);
 #ifdef CONFIG_SYN_COOKIES
 	__u32 (*cookie_init_seq)(const struct sk_buff *skb,
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index cd81b6e04efb..f0b01d09d5ad 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1420,7 +1420,7 @@ static bool tcp_v4_inbound_md5_hash(const struct sock *sk,
 }
 
 static void tcp_v4_init_req(struct request_sock *req,
-			    const struct sock *sk_listener,
+			    struct sock *sk_listener,
 			    struct sk_buff *skb)
 {
 	struct inet_request_sock *ireq = inet_rsk(req);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index c34b7834fd84..1c7bf70660e8 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -792,7 +792,7 @@ static bool tcp_v6_inbound_md5_hash(const struct sock *sk,
 }
 
 static void tcp_v6_init_req(struct request_sock *req,
-			    const struct sock *sk_listener,
+			    struct sock *sk_listener,
 			    struct sk_buff *skb)
 {
 	bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags);
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 6b1d88332a2d..55a19f8ed8ec 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -175,7 +175,7 @@ static void subflow_init_req(struct request_sock *req,
 }
 
 static void subflow_v4_init_req(struct request_sock *req,
-				const struct sock *sk_listener,
+				struct sock *sk_listener,
 				struct sk_buff *skb)
 {
 	tcp_rsk(req)->is_mptcp = 1;
@@ -187,7 +187,7 @@ static void subflow_v4_init_req(struct request_sock *req,
 
 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
 static void subflow_v6_init_req(struct request_sock *req,
-				const struct sock *sk_listener,
+				struct sock *sk_listener,
 				struct sk_buff *skb)
 {
 	tcp_rsk(req)->is_mptcp = 1;
-- 
2.26.2


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

* [MPTCP] [RFC v2 mptcp-next 07/12] tcp: pass want_cookie down to req_init function
  2020-07-21 20:36 ` Florian Westphal
@ 2020-07-21 20:36 ` Florian Westphal
  -1 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: mptcp

[-- Attachment #1: Type: text/plain, Size: 4546 bytes --]

In MPTCP case, we want to know if we should store a new token id or if we
should try best-effort only (cookie case).

This allows the MPTCP core to detect when it should elide the storage
of the generated MPTCP token.

Signed-off-by: Florian Westphal <fw(a)strlen.de>
---
 This isn't nice either, its useless from TCP pov.

 One alternative would be to add a bit in the mptcp request
 socket and use that instead.
 Another alternative would be to store the token normally but
 then toss it again as soon as request sk is discarded again.

 Let me know if I should evaluate a different approach.

 include/net/tcp.h    |  3 ++-
 net/ipv4/tcp_input.c |  2 +-
 net/ipv4/tcp_ipv4.c  |  3 ++-
 net/ipv6/tcp_ipv6.c  |  3 ++-
 net/mptcp/subflow.c  | 17 ++++++++++-------
 5 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 74c0b37584ef..401b9820628e 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -2019,7 +2019,8 @@ struct tcp_request_sock_ops {
 #endif
 	void (*init_req)(struct request_sock *req,
 			 struct sock *sk_listener,
-			 struct sk_buff *skb);
+			 struct sk_buff *skb,
+			 bool syncookie_req);
 #ifdef CONFIG_SYN_COOKIES
 	__u32 (*cookie_init_seq)(const struct sk_buff *skb,
 				 __u16 *mss);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 727ca87a2929..17aa1c29d11c 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6697,7 +6697,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 	/* Note: tcp_v6_init_req() might override ir_iif for link locals */
 	inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb);
 
-	af_ops->init_req(req, sk, skb);
+	af_ops->init_req(req, sk, skb, want_cookie);
 
 	if (IS_ENABLED(CONFIG_MPTCP) && want_cookie)
 		tcp_rsk(req)->is_mptcp = 0;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index f0b01d09d5ad..0a8c61c4d590 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1421,7 +1421,8 @@ static bool tcp_v4_inbound_md5_hash(const struct sock *sk,
 
 static void tcp_v4_init_req(struct request_sock *req,
 			    struct sock *sk_listener,
-			    struct sk_buff *skb)
+			    struct sk_buff *skb,
+			    bool want_cookie)
 {
 	struct inet_request_sock *ireq = inet_rsk(req);
 	struct net *net = sock_net(sk_listener);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 1c7bf70660e8..ccf03d5c143a 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -793,7 +793,8 @@ static bool tcp_v6_inbound_md5_hash(const struct sock *sk,
 
 static void tcp_v6_init_req(struct request_sock *req,
 			    struct sock *sk_listener,
-			    struct sk_buff *skb)
+			    struct sk_buff *skb,
+			    bool want_cookie)
 {
 	bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags);
 	struct inet_request_sock *ireq = inet_rsk(req);
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 55a19f8ed8ec..023e9f435d1b 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -128,7 +128,8 @@ static int __subflow_check_options(const struct mptcp_options_received *mp_opt,
 
 static void subflow_init_req(struct request_sock *req,
 			     const struct sock *sk_listener,
-			     struct sk_buff *skb)
+			     struct sk_buff *skb,
+			     bool want_cookie)
 {
 	struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk_listener);
 	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
@@ -176,25 +177,27 @@ static void subflow_init_req(struct request_sock *req,
 
 static void subflow_v4_init_req(struct request_sock *req,
 				struct sock *sk_listener,
-				struct sk_buff *skb)
+				struct sk_buff *skb,
+				bool want_cookie)
 {
 	tcp_rsk(req)->is_mptcp = 1;
 
-	tcp_request_sock_ipv4_ops.init_req(req, sk_listener, skb);
+	tcp_request_sock_ipv4_ops.init_req(req, sk_listener, skb, want_cookie);
 
-	subflow_init_req(req, sk_listener, skb);
+	subflow_init_req(req, sk_listener, skb, want_cookie);
 }
 
 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
 static void subflow_v6_init_req(struct request_sock *req,
 				struct sock *sk_listener,
-				struct sk_buff *skb)
+				struct sk_buff *skb,
+				bool want_cookie)
 {
 	tcp_rsk(req)->is_mptcp = 1;
 
-	tcp_request_sock_ipv6_ops.init_req(req, sk_listener, skb);
+	tcp_request_sock_ipv6_ops.init_req(req, sk_listener, skb, want_cookie);
 
-	subflow_init_req(req, sk_listener, skb);
+	subflow_init_req(req, sk_listener, skb, want_cookie);
 }
 #endif
 
-- 
2.26.2

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

* [RFC v2 mptcp-next 07/12] tcp: pass want_cookie down to req_init function
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: netdev
  Cc: mathew.j.martineau, edumazet, mptcp, matthieu.baerts, Florian Westphal

In MPTCP case, we want to know if we should store a new token id or if we
should try best-effort only (cookie case).

This allows the MPTCP core to detect when it should elide the storage
of the generated MPTCP token.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 This isn't nice either, its useless from TCP pov.

 One alternative would be to add a bit in the mptcp request
 socket and use that instead.
 Another alternative would be to store the token normally but
 then toss it again as soon as request sk is discarded again.

 Let me know if I should evaluate a different approach.

 include/net/tcp.h    |  3 ++-
 net/ipv4/tcp_input.c |  2 +-
 net/ipv4/tcp_ipv4.c  |  3 ++-
 net/ipv6/tcp_ipv6.c  |  3 ++-
 net/mptcp/subflow.c  | 17 ++++++++++-------
 5 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/include/net/tcp.h b/include/net/tcp.h
index 74c0b37584ef..401b9820628e 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -2019,7 +2019,8 @@ struct tcp_request_sock_ops {
 #endif
 	void (*init_req)(struct request_sock *req,
 			 struct sock *sk_listener,
-			 struct sk_buff *skb);
+			 struct sk_buff *skb,
+			 bool syncookie_req);
 #ifdef CONFIG_SYN_COOKIES
 	__u32 (*cookie_init_seq)(const struct sk_buff *skb,
 				 __u16 *mss);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 727ca87a2929..17aa1c29d11c 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6697,7 +6697,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 	/* Note: tcp_v6_init_req() might override ir_iif for link locals */
 	inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb);
 
-	af_ops->init_req(req, sk, skb);
+	af_ops->init_req(req, sk, skb, want_cookie);
 
 	if (IS_ENABLED(CONFIG_MPTCP) && want_cookie)
 		tcp_rsk(req)->is_mptcp = 0;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index f0b01d09d5ad..0a8c61c4d590 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1421,7 +1421,8 @@ static bool tcp_v4_inbound_md5_hash(const struct sock *sk,
 
 static void tcp_v4_init_req(struct request_sock *req,
 			    struct sock *sk_listener,
-			    struct sk_buff *skb)
+			    struct sk_buff *skb,
+			    bool want_cookie)
 {
 	struct inet_request_sock *ireq = inet_rsk(req);
 	struct net *net = sock_net(sk_listener);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 1c7bf70660e8..ccf03d5c143a 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -793,7 +793,8 @@ static bool tcp_v6_inbound_md5_hash(const struct sock *sk,
 
 static void tcp_v6_init_req(struct request_sock *req,
 			    struct sock *sk_listener,
-			    struct sk_buff *skb)
+			    struct sk_buff *skb,
+			    bool want_cookie)
 {
 	bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags);
 	struct inet_request_sock *ireq = inet_rsk(req);
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 55a19f8ed8ec..023e9f435d1b 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -128,7 +128,8 @@ static int __subflow_check_options(const struct mptcp_options_received *mp_opt,
 
 static void subflow_init_req(struct request_sock *req,
 			     const struct sock *sk_listener,
-			     struct sk_buff *skb)
+			     struct sk_buff *skb,
+			     bool want_cookie)
 {
 	struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk_listener);
 	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
@@ -176,25 +177,27 @@ static void subflow_init_req(struct request_sock *req,
 
 static void subflow_v4_init_req(struct request_sock *req,
 				struct sock *sk_listener,
-				struct sk_buff *skb)
+				struct sk_buff *skb,
+				bool want_cookie)
 {
 	tcp_rsk(req)->is_mptcp = 1;
 
-	tcp_request_sock_ipv4_ops.init_req(req, sk_listener, skb);
+	tcp_request_sock_ipv4_ops.init_req(req, sk_listener, skb, want_cookie);
 
-	subflow_init_req(req, sk_listener, skb);
+	subflow_init_req(req, sk_listener, skb, want_cookie);
 }
 
 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
 static void subflow_v6_init_req(struct request_sock *req,
 				struct sock *sk_listener,
-				struct sk_buff *skb)
+				struct sk_buff *skb,
+				bool want_cookie)
 {
 	tcp_rsk(req)->is_mptcp = 1;
 
-	tcp_request_sock_ipv6_ops.init_req(req, sk_listener, skb);
+	tcp_request_sock_ipv6_ops.init_req(req, sk_listener, skb, want_cookie);
 
-	subflow_init_req(req, sk_listener, skb);
+	subflow_init_req(req, sk_listener, skb, want_cookie);
 }
 #endif
 
-- 
2.26.2


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

* [MPTCP] [RFC v2 mptcp-next 08/12] mptcp: subflow: add mptcp_subflow_init_cookie_req helper
  2020-07-21 20:36 ` Florian Westphal
@ 2020-07-21 20:36 ` Florian Westphal
  -1 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: mptcp

[-- Attachment #1: Type: text/plain, Size: 5933 bytes --]

Will be used to initialize the mptcp request socket when a MP_CAPABLE
request was handled in syncookie mode, i.e. when a TCP ACK containing a
MP_CAPABLE option is a valid syncookie value.

Normally (non-cookie case), MPTCP will generate a 32 bit connection
ID and stores it in the MPTCP token storage to be able to retrieve the
mptcp socket for JOIN requests.

In syncookie case, we do not want to store any state, so just generate the
unique ID and use it in the reply.

This means there is a small window where another connection could generate
the same token.

When Cookie ACK comes back, we check that the token has not been registered
in the mean time.  If it was, the connection needs to fall back to TCP.

Signed-off-by: Florian Westphal <fw(a)strlen.de>
---
 include/net/mptcp.h  | 10 ++++++++
 net/mptcp/protocol.h |  1 +
 net/mptcp/subflow.c  | 55 +++++++++++++++++++++++++++++++++++++++++++-
 net/mptcp/token.c    | 26 +++++++++++++++++++++
 4 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index 76eb915bf91c..3525d2822abe 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -131,6 +131,9 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
 }
 
 void mptcp_seq_show(struct seq_file *seq);
+int mptcp_subflow_init_cookie_req(struct request_sock *req,
+				  const struct sock *sk_listener,
+				  struct sk_buff *skb);
 #else
 
 static inline void mptcp_init(void)
@@ -200,6 +203,13 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
 
 static inline void mptcp_space(const struct sock *ssk, int *s, int *fs) { }
 static inline void mptcp_seq_show(struct seq_file *seq) { }
+
+static inline int mptcp_subflow_init_cookie_req(struct request_sock *req,
+						const struct sock *sk_listener,
+						struct sk_buff *skb)
+{
+	return 0; /* TCP fallback */
+}
 #endif /* CONFIG_MPTCP */
 
 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index cf74305c1d42..0ed402cdb9fd 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -392,6 +392,7 @@ void mptcp_token_destroy_request(struct request_sock *req);
 int mptcp_token_new_connect(struct sock *sk);
 void mptcp_token_accept(struct mptcp_subflow_request_sock *r,
 			struct mptcp_sock *msk);
+bool mptcp_token_exists(u32 token);
 struct mptcp_sock *mptcp_token_get_sock(u32 token);
 struct mptcp_sock *mptcp_token_iter_next(const struct net *net, long *s_slot,
 					 long *s_num);
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 023e9f435d1b..0761c35268ce 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -150,18 +150,31 @@ static void subflow_init_req(struct request_sock *req,
 	if (mp_opt.mp_capable && listener->request_mptcp) {
 		int err, retries = 4;
 
+		subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq;
 again:
 		do {
 			get_random_bytes(&subflow_req->local_key, sizeof(subflow_req->local_key));
 		} while (subflow_req->local_key == 0);
 
+		if (unlikely(want_cookie)) {
+			mptcp_crypto_key_sha(subflow_req->local_key,
+					     &subflow_req->token,
+					     &subflow_req->idsn);
+			if (mptcp_token_exists(subflow_req->token)) {
+				if (retries-- > 0)
+					goto again;
+			} else {
+				subflow_req->mp_capable = 1;
+			}
+			return;
+		}
+
 		err = mptcp_token_new_request(req);
 		if (err == 0)
 			subflow_req->mp_capable = 1;
 		else if (retries-- > 0)
 			goto again;
 
-		subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq;
 	} else if (mp_opt.mp_join && listener->request_mptcp) {
 		subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq;
 		subflow_req->mp_join = 1;
@@ -175,6 +188,46 @@ static void subflow_init_req(struct request_sock *req,
 	}
 }
 
+int mptcp_subflow_init_cookie_req(struct request_sock *req,
+				  const struct sock *sk_listener,
+				  struct sk_buff *skb)
+{
+	struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk_listener);
+	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
+	struct mptcp_options_received mp_opt;
+	int ret;
+
+	ret = __subflow_init_req(req, sk_listener);
+	if (ret)
+		return ret;
+
+	mptcp_get_options(skb, &mp_opt);
+	ret = __subflow_check_options(&mp_opt, req);
+	if (ret)
+		return ret;
+
+	if (mp_opt.mp_capable && listener->request_mptcp) {
+		int err;
+
+		if (mp_opt.sndr_key == 0)
+			return -EINVAL;
+
+		subflow_req->local_key = mp_opt.rcvr_key;
+		err = mptcp_token_new_request(req);
+		if (err)
+			return err;
+
+		subflow_req->mp_capable = 1;
+		subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq - 1;
+	}
+	/* JOIN cannot be handled via cookies due to need
+	 * to store the remote peer nonce value.
+	 */
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mptcp_subflow_init_cookie_req);
+
 static void subflow_v4_init_req(struct request_sock *req,
 				struct sock *sk_listener,
 				struct sk_buff *skb,
diff --git a/net/mptcp/token.c b/net/mptcp/token.c
index f82410c54653..8b47c4bb1c6b 100644
--- a/net/mptcp/token.c
+++ b/net/mptcp/token.c
@@ -204,6 +204,32 @@ void mptcp_token_accept(struct mptcp_subflow_request_sock *req,
 	spin_unlock_bh(&bucket->lock);
 }
 
+bool mptcp_token_exists(u32 token)
+{
+	struct hlist_nulls_node *pos;
+	struct token_bucket *bucket;
+	struct mptcp_sock *msk;
+	struct sock *sk;
+
+	rcu_read_lock();
+	bucket = token_bucket(token);
+
+again:
+	sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
+		msk = mptcp_sk(sk);
+		if (READ_ONCE(msk->token) == token)
+			goto found;
+	}
+	if (get_nulls_value(pos) != (token & token_mask))
+		goto again;
+
+	rcu_read_unlock();
+	return false;
+found:
+	rcu_read_unlock();
+	return true;
+}
+
 /**
  * mptcp_token_get_sock - retrieve mptcp connection sock using its token
  * @token: token of the mptcp connection to retrieve
-- 
2.26.2

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

* [RFC v2 mptcp-next 08/12] mptcp: subflow: add mptcp_subflow_init_cookie_req helper
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: netdev
  Cc: mathew.j.martineau, edumazet, mptcp, matthieu.baerts, Florian Westphal

Will be used to initialize the mptcp request socket when a MP_CAPABLE
request was handled in syncookie mode, i.e. when a TCP ACK containing a
MP_CAPABLE option is a valid syncookie value.

Normally (non-cookie case), MPTCP will generate a 32 bit connection
ID and stores it in the MPTCP token storage to be able to retrieve the
mptcp socket for JOIN requests.

In syncookie case, we do not want to store any state, so just generate the
unique ID and use it in the reply.

This means there is a small window where another connection could generate
the same token.

When Cookie ACK comes back, we check that the token has not been registered
in the mean time.  If it was, the connection needs to fall back to TCP.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/net/mptcp.h  | 10 ++++++++
 net/mptcp/protocol.h |  1 +
 net/mptcp/subflow.c  | 55 +++++++++++++++++++++++++++++++++++++++++++-
 net/mptcp/token.c    | 26 +++++++++++++++++++++
 4 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index 76eb915bf91c..3525d2822abe 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -131,6 +131,9 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
 }
 
 void mptcp_seq_show(struct seq_file *seq);
+int mptcp_subflow_init_cookie_req(struct request_sock *req,
+				  const struct sock *sk_listener,
+				  struct sk_buff *skb);
 #else
 
 static inline void mptcp_init(void)
@@ -200,6 +203,13 @@ static inline bool mptcp_skb_can_collapse(const struct sk_buff *to,
 
 static inline void mptcp_space(const struct sock *ssk, int *s, int *fs) { }
 static inline void mptcp_seq_show(struct seq_file *seq) { }
+
+static inline int mptcp_subflow_init_cookie_req(struct request_sock *req,
+						const struct sock *sk_listener,
+						struct sk_buff *skb)
+{
+	return 0; /* TCP fallback */
+}
 #endif /* CONFIG_MPTCP */
 
 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index cf74305c1d42..0ed402cdb9fd 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -392,6 +392,7 @@ void mptcp_token_destroy_request(struct request_sock *req);
 int mptcp_token_new_connect(struct sock *sk);
 void mptcp_token_accept(struct mptcp_subflow_request_sock *r,
 			struct mptcp_sock *msk);
+bool mptcp_token_exists(u32 token);
 struct mptcp_sock *mptcp_token_get_sock(u32 token);
 struct mptcp_sock *mptcp_token_iter_next(const struct net *net, long *s_slot,
 					 long *s_num);
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 023e9f435d1b..0761c35268ce 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -150,18 +150,31 @@ static void subflow_init_req(struct request_sock *req,
 	if (mp_opt.mp_capable && listener->request_mptcp) {
 		int err, retries = 4;
 
+		subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq;
 again:
 		do {
 			get_random_bytes(&subflow_req->local_key, sizeof(subflow_req->local_key));
 		} while (subflow_req->local_key == 0);
 
+		if (unlikely(want_cookie)) {
+			mptcp_crypto_key_sha(subflow_req->local_key,
+					     &subflow_req->token,
+					     &subflow_req->idsn);
+			if (mptcp_token_exists(subflow_req->token)) {
+				if (retries-- > 0)
+					goto again;
+			} else {
+				subflow_req->mp_capable = 1;
+			}
+			return;
+		}
+
 		err = mptcp_token_new_request(req);
 		if (err == 0)
 			subflow_req->mp_capable = 1;
 		else if (retries-- > 0)
 			goto again;
 
-		subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq;
 	} else if (mp_opt.mp_join && listener->request_mptcp) {
 		subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq;
 		subflow_req->mp_join = 1;
@@ -175,6 +188,46 @@ static void subflow_init_req(struct request_sock *req,
 	}
 }
 
+int mptcp_subflow_init_cookie_req(struct request_sock *req,
+				  const struct sock *sk_listener,
+				  struct sk_buff *skb)
+{
+	struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk_listener);
+	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
+	struct mptcp_options_received mp_opt;
+	int ret;
+
+	ret = __subflow_init_req(req, sk_listener);
+	if (ret)
+		return ret;
+
+	mptcp_get_options(skb, &mp_opt);
+	ret = __subflow_check_options(&mp_opt, req);
+	if (ret)
+		return ret;
+
+	if (mp_opt.mp_capable && listener->request_mptcp) {
+		int err;
+
+		if (mp_opt.sndr_key == 0)
+			return -EINVAL;
+
+		subflow_req->local_key = mp_opt.rcvr_key;
+		err = mptcp_token_new_request(req);
+		if (err)
+			return err;
+
+		subflow_req->mp_capable = 1;
+		subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq - 1;
+	}
+	/* JOIN cannot be handled via cookies due to need
+	 * to store the remote peer nonce value.
+	 */
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mptcp_subflow_init_cookie_req);
+
 static void subflow_v4_init_req(struct request_sock *req,
 				struct sock *sk_listener,
 				struct sk_buff *skb,
diff --git a/net/mptcp/token.c b/net/mptcp/token.c
index f82410c54653..8b47c4bb1c6b 100644
--- a/net/mptcp/token.c
+++ b/net/mptcp/token.c
@@ -204,6 +204,32 @@ void mptcp_token_accept(struct mptcp_subflow_request_sock *req,
 	spin_unlock_bh(&bucket->lock);
 }
 
+bool mptcp_token_exists(u32 token)
+{
+	struct hlist_nulls_node *pos;
+	struct token_bucket *bucket;
+	struct mptcp_sock *msk;
+	struct sock *sk;
+
+	rcu_read_lock();
+	bucket = token_bucket(token);
+
+again:
+	sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
+		msk = mptcp_sk(sk);
+		if (READ_ONCE(msk->token) == token)
+			goto found;
+	}
+	if (get_nulls_value(pos) != (token & token_mask))
+		goto again;
+
+	rcu_read_unlock();
+	return false;
+found:
+	rcu_read_unlock();
+	return true;
+}
+
 /**
  * mptcp_token_get_sock - retrieve mptcp connection sock using its token
  * @token: token of the mptcp connection to retrieve
-- 
2.26.2


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

* [MPTCP] [RFC v2 mptcp-next 09/12] tcp: syncookies: create mptcp request socket for ACK cookies with MPTCP option
  2020-07-21 20:36 ` Florian Westphal
@ 2020-07-21 20:36 ` Florian Westphal
  -1 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: mptcp

[-- Attachment #1: Type: text/plain, Size: 3651 bytes --]

If SYN packet contains MP_CAPABLE option, keep it enabled.
Syncokie validation and cookie-based socket creation is changed to
instantiate an mptcp request sockets if the ACK contains an MPTCP
connection request.

Signed-off-by: Florian Westphal <fw(a)strlen.de>
---
 net/ipv4/syncookies.c | 21 +++++++++++++++++----
 net/ipv4/tcp_input.c  |  3 ---
 net/ipv6/syncookies.c | 17 ++++++++++++++---
 3 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index ee17f55401ef..5da49dc126f9 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -289,6 +289,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
 	struct tcp_sock *tp = tcp_sk(sk);
 	const struct tcphdr *th = tcp_hdr(skb);
 	__u32 cookie = ntohl(th->ack_seq) - 1;
+	const struct request_sock_ops *ops;
 	struct sock *ret = sk;
 	struct request_sock *req;
 	int mss;
@@ -326,12 +327,27 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
 		goto out;
 
 	ret = NULL;
-	req = inet_reqsk_alloc(&tcp_request_sock_ops, sk, false); /* for safety */
+	ops = &tcp_request_sock_ops;
+#ifdef CONFIG_MPTCP
+	if (sk_is_mptcp(sk))
+		ops = &mptcp_subflow_request_sock_ops;
+#endif
+
+	req = inet_reqsk_alloc(ops, sk, false); /* for safety */
 	if (!req)
 		goto out;
 
 	ireq = inet_rsk(req);
 	treq = tcp_rsk(req);
+	treq->is_mptcp = sk_is_mptcp(sk);
+
+	if (treq->is_mptcp) {
+		int err = mptcp_subflow_init_cookie_req(req, sk, skb);
+
+		if (err)
+			goto out_free;
+	}
+
 	treq->rcv_isn		= ntohl(th->seq) - 1;
 	treq->snt_isn		= cookie;
 	treq->ts_off		= 0;
@@ -350,9 +366,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
 	treq->snt_synack	= 0;
 	treq->tfo_listener	= false;
 
-	if (IS_ENABLED(CONFIG_MPTCP))
-		treq->is_mptcp = 0;
-
 	if (IS_ENABLED(CONFIG_SMC))
 		ireq->smc_ok = 0;
 
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 17aa1c29d11c..7f4c21bca3b5 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6699,9 +6699,6 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 
 	af_ops->init_req(req, sk, skb, want_cookie);
 
-	if (IS_ENABLED(CONFIG_MPTCP) && want_cookie)
-		tcp_rsk(req)->is_mptcp = 0;
-
 	if (security_inet_conn_request(sk, skb, req))
 		goto drop_and_free;
 
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 13235a012388..0a05c3c1e776 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -134,6 +134,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 	struct tcp_sock *tp = tcp_sk(sk);
 	const struct tcphdr *th = tcp_hdr(skb);
 	__u32 cookie = ntohl(th->ack_seq) - 1;
+	const struct request_sock_ops *ops;
 	struct sock *ret = sk;
 	struct request_sock *req;
 	int mss;
@@ -170,7 +171,13 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 		goto out;
 
 	ret = NULL;
-	req = inet_reqsk_alloc(&tcp6_request_sock_ops, sk, false);
+	ops = &tcp6_request_sock_ops;
+#ifdef CONFIG_MPTCP
+	if (sk_is_mptcp(sk))
+		ops = &mptcp_subflow_request_sock_ops;
+#endif
+
+	req = inet_reqsk_alloc(ops, sk, false);
 	if (!req)
 		goto out;
 
@@ -178,8 +185,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 	treq = tcp_rsk(req);
 	treq->tfo_listener = false;
 
-	if (IS_ENABLED(CONFIG_MPTCP))
-		treq->is_mptcp = 0;
+	if (treq->is_mptcp) {
+		int err = mptcp_subflow_init_cookie_req(req, sk, skb);
+
+		if (err)
+			goto out_free;
+	}
 
 	if (security_inet_conn_request(sk, skb, req))
 		goto out_free;
-- 
2.26.2

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

* [RFC v2 mptcp-next 09/12] tcp: syncookies: create mptcp request socket for ACK cookies with MPTCP option
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: netdev
  Cc: mathew.j.martineau, edumazet, mptcp, matthieu.baerts, Florian Westphal

If SYN packet contains MP_CAPABLE option, keep it enabled.
Syncokie validation and cookie-based socket creation is changed to
instantiate an mptcp request sockets if the ACK contains an MPTCP
connection request.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 net/ipv4/syncookies.c | 21 +++++++++++++++++----
 net/ipv4/tcp_input.c  |  3 ---
 net/ipv6/syncookies.c | 17 ++++++++++++++---
 3 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index ee17f55401ef..5da49dc126f9 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -289,6 +289,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
 	struct tcp_sock *tp = tcp_sk(sk);
 	const struct tcphdr *th = tcp_hdr(skb);
 	__u32 cookie = ntohl(th->ack_seq) - 1;
+	const struct request_sock_ops *ops;
 	struct sock *ret = sk;
 	struct request_sock *req;
 	int mss;
@@ -326,12 +327,27 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
 		goto out;
 
 	ret = NULL;
-	req = inet_reqsk_alloc(&tcp_request_sock_ops, sk, false); /* for safety */
+	ops = &tcp_request_sock_ops;
+#ifdef CONFIG_MPTCP
+	if (sk_is_mptcp(sk))
+		ops = &mptcp_subflow_request_sock_ops;
+#endif
+
+	req = inet_reqsk_alloc(ops, sk, false); /* for safety */
 	if (!req)
 		goto out;
 
 	ireq = inet_rsk(req);
 	treq = tcp_rsk(req);
+	treq->is_mptcp = sk_is_mptcp(sk);
+
+	if (treq->is_mptcp) {
+		int err = mptcp_subflow_init_cookie_req(req, sk, skb);
+
+		if (err)
+			goto out_free;
+	}
+
 	treq->rcv_isn		= ntohl(th->seq) - 1;
 	treq->snt_isn		= cookie;
 	treq->ts_off		= 0;
@@ -350,9 +366,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
 	treq->snt_synack	= 0;
 	treq->tfo_listener	= false;
 
-	if (IS_ENABLED(CONFIG_MPTCP))
-		treq->is_mptcp = 0;
-
 	if (IS_ENABLED(CONFIG_SMC))
 		ireq->smc_ok = 0;
 
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 17aa1c29d11c..7f4c21bca3b5 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6699,9 +6699,6 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 
 	af_ops->init_req(req, sk, skb, want_cookie);
 
-	if (IS_ENABLED(CONFIG_MPTCP) && want_cookie)
-		tcp_rsk(req)->is_mptcp = 0;
-
 	if (security_inet_conn_request(sk, skb, req))
 		goto drop_and_free;
 
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 13235a012388..0a05c3c1e776 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -134,6 +134,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 	struct tcp_sock *tp = tcp_sk(sk);
 	const struct tcphdr *th = tcp_hdr(skb);
 	__u32 cookie = ntohl(th->ack_seq) - 1;
+	const struct request_sock_ops *ops;
 	struct sock *ret = sk;
 	struct request_sock *req;
 	int mss;
@@ -170,7 +171,13 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 		goto out;
 
 	ret = NULL;
-	req = inet_reqsk_alloc(&tcp6_request_sock_ops, sk, false);
+	ops = &tcp6_request_sock_ops;
+#ifdef CONFIG_MPTCP
+	if (sk_is_mptcp(sk))
+		ops = &mptcp_subflow_request_sock_ops;
+#endif
+
+	req = inet_reqsk_alloc(ops, sk, false);
 	if (!req)
 		goto out;
 
@@ -178,8 +185,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 	treq = tcp_rsk(req);
 	treq->tfo_listener = false;
 
-	if (IS_ENABLED(CONFIG_MPTCP))
-		treq->is_mptcp = 0;
+	if (treq->is_mptcp) {
+		int err = mptcp_subflow_init_cookie_req(req, sk, skb);
+
+		if (err)
+			goto out_free;
+	}
 
 	if (security_inet_conn_request(sk, skb, req))
 		goto out_free;
-- 
2.26.2


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

* [MPTCP] [RFC v2 mptcp-next 10/12] tcp: handle want_cookie clause via reqsk_put
  2020-07-21 20:36 ` Florian Westphal
@ 2020-07-21 20:36 ` Florian Westphal
  -1 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: mptcp

[-- Attachment #1: Type: text/plain, Size: 1888 bytes --]

This will allow the syn_recv_sock callback to keep the request socket
around even when syncookies are used.

This will be needed to make MPTCP JOIN requests work in cookie mode.

When a JOIN request is received, we cannot use cookies because we need
to remember the peers nonce value for HMAC validation.

Next patch will handle the cookie+join case by allowing the
rsk to stay around provided:
 1. We can find a valid mptcp socket for the 32bit token provided
    by the join and
 2. the found mptcp socket doesn't exceed the maximum number of
    subflows.

To handle 2) the request socket will not only be accounted with the
listener but also with the mptcp (parent) socket.

Signed-off-by: Florian Westphal <fw(a)strlen.de>
---
 net/ipv4/tcp_input.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 7f4c21bca3b5..184c6d111ca0 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6697,6 +6697,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 	/* Note: tcp_v6_init_req() might override ir_iif for link locals */
 	inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb);
 
+	refcount_set(&req->rsk_refcnt, 1);
 	af_ops->init_req(req, sk, skb, want_cookie);
 
 	if (security_inet_conn_request(sk, skb, req))
@@ -6767,10 +6768,6 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 		af_ops->send_synack(sk, dst, &fl, req, &foc,
 				    !want_cookie ? TCP_SYNACK_NORMAL :
 						   TCP_SYNACK_COOKIE);
-		if (want_cookie) {
-			reqsk_free(req);
-			return 0;
-		}
 	}
 	reqsk_put(req);
 	return 0;
@@ -6778,7 +6775,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 drop_and_release:
 	dst_release(dst);
 drop_and_free:
-	__reqsk_free(req);
+	reqsk_put(req);
 drop:
 	tcp_listendrop(sk);
 	return 0;
-- 
2.26.2

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

* [RFC v2 mptcp-next 10/12] tcp: handle want_cookie clause via reqsk_put
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: netdev
  Cc: mathew.j.martineau, edumazet, mptcp, matthieu.baerts, Florian Westphal

This will allow the syn_recv_sock callback to keep the request socket
around even when syncookies are used.

This will be needed to make MPTCP JOIN requests work in cookie mode.

When a JOIN request is received, we cannot use cookies because we need
to remember the peers nonce value for HMAC validation.

Next patch will handle the cookie+join case by allowing the
rsk to stay around provided:
 1. We can find a valid mptcp socket for the 32bit token provided
    by the join and
 2. the found mptcp socket doesn't exceed the maximum number of
    subflows.

To handle 2) the request socket will not only be accounted with the
listener but also with the mptcp (parent) socket.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 net/ipv4/tcp_input.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 7f4c21bca3b5..184c6d111ca0 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6697,6 +6697,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 	/* Note: tcp_v6_init_req() might override ir_iif for link locals */
 	inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb);
 
+	refcount_set(&req->rsk_refcnt, 1);
 	af_ops->init_req(req, sk, skb, want_cookie);
 
 	if (security_inet_conn_request(sk, skb, req))
@@ -6767,10 +6768,6 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 		af_ops->send_synack(sk, dst, &fl, req, &foc,
 				    !want_cookie ? TCP_SYNACK_NORMAL :
 						   TCP_SYNACK_COOKIE);
-		if (want_cookie) {
-			reqsk_free(req);
-			return 0;
-		}
 	}
 	reqsk_put(req);
 	return 0;
@@ -6778,7 +6775,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 drop_and_release:
 	dst_release(dst);
 drop_and_free:
-	__reqsk_free(req);
+	reqsk_put(req);
 drop:
 	tcp_listendrop(sk);
 	return 0;
-- 
2.26.2


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

* [MPTCP] [RFC v2 mptcp-next 11/12] mptcp: enable JOIN requests even if cookies are in use
  2020-07-21 20:36 ` Florian Westphal
@ 2020-07-21 20:36 ` Florian Westphal
  -1 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: mptcp

[-- Attachment #1: Type: text/plain, Size: 5217 bytes --]

JOIN requests do not work in syncookie mode -- for HMAC validation, the
peers nonce is required, but this nonce is only present in the SYN.

So either we need to drop or reject all JOIN requests once a listening
socket enters syncookie mode, or we need to store enough state to
validate the ACKs HMAC later on.

This allows the subflow request initialisation function to store the
request socket even when syncookies are used, i.e. the listener
socket queue will grow past its upper limit.

Following restrictions apply:
1. The (32bit) token contained in the MP_JOIN SYN packet returns
   a valid parent connection.
2. The parent connection can accept one more subflow.

To ensure 2), all MP_JOIN requests (new incoming and existing)
are accounted in the mptcp parent socket.

If the token is invalid or the parent cannot accept a new subflow,
no information is stored and TCP fallback path is used.

The parent socket can't be used without further changes in TCP stack,
because socket creation after 3whs completion checks that the associated
socket is in LISTEN state.

Signed-off-by: Florian Westphal <fw(a)strlen.de>
---
 To ease review I think it would also be possible to
 defer the JOIN stuff for later and just focus on initial
 MP_CAPABLE request.  OTOH, doing so yields MPTCP-on-wire but with no
 Multipath capability so I'm not sure having MP_CAPABLE without
 MP_JOIN is useful.

 net/mptcp/pm_netlink.c |  2 +-
 net/mptcp/protocol.h   |  2 ++
 net/mptcp/subflow.c    | 60 +++++++++++++++++++++++++++++++++++++++---
 3 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
index c8820c4156e6..117f794ecc54 100644
--- a/net/mptcp/pm_netlink.c
+++ b/net/mptcp/pm_netlink.c
@@ -41,7 +41,7 @@ struct pm_nl_pernet {
 	unsigned int		next_id;
 };
 
-#define MPTCP_PM_ADDR_MAX	8
+#define MPTCP_PM_ADDR_MAX	MPTCP_SUBFLOWS_MAX
 
 static bool addresses_equal(const struct mptcp_addr_info *a,
 			    struct mptcp_addr_info *b, bool use_port)
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 0ed402cdb9fd..586601e889fc 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -154,6 +154,8 @@ enum mptcp_pm_status {
 	MPTCP_PM_SUBFLOW_ESTABLISHED,
 };
 
+#define MPTCP_SUBFLOWS_MAX	8
+
 struct mptcp_pm_data {
 	struct mptcp_addr_info local;
 	struct mptcp_addr_info remote;
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 0761c35268ce..ab86010483fe 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -126,6 +126,49 @@ static int __subflow_check_options(const struct mptcp_options_received *mp_opt,
 	return 0;
 }
 
+static bool mptcp_join_store(struct mptcp_subflow_request_sock *req,
+			     struct sock *sk_listener,
+			     bool want_cookie)
+{
+	struct mptcp_sock *msk = req->msk;
+	struct inet_connection_sock *icsk;
+	struct sock *sk;
+
+	icsk = &msk->sk;
+	sk = &icsk->icsk_inet.sk;
+
+	if (inet_csk_reqsk_queue_len(sk) >= MPTCP_SUBFLOWS_MAX ||
+	    !mptcp_can_accept_new_subflow(msk))
+		return false;
+
+	atomic_inc(&inet_csk(sk)->icsk_accept_queue.qlen);
+
+	if (likely(!want_cookie))
+		return true;
+
+	/* Syncookies are used.
+	 * We can't do this for JOIN requests because we need to store
+	 * the initiators nonce for HMAC validation.
+	 *
+	 * At this point we know:
+	 * 1. a valid parent connection that should be joined
+	 * 2. the parent socket has less than MPTCP_SUBFLOWS_MAX joined
+	 * connections (includes those in progress).
+	 *
+	 * We add the request to the accept queue backlog ourselves
+	 * in this case.
+	 */
+	if (unlikely(!refcount_inc_not_zero(&sk_listener->sk_refcnt))) {
+		atomic_dec(&inet_csk(sk)->icsk_accept_queue.qlen);
+		return false;
+	}
+
+	req->sk.req.req.rsk_listener = sk_listener;
+	inet_csk_reqsk_queue_hash_add(sk, &req->sk.req.req,
+				      tcp_timeout_init((struct sock *)req));
+	return true;
+}
+
 static void subflow_init_req(struct request_sock *req,
 			     const struct sock *sk_listener,
 			     struct sk_buff *skb,
@@ -177,12 +220,18 @@ static void subflow_init_req(struct request_sock *req,
 
 	} else if (mp_opt.mp_join && listener->request_mptcp) {
 		subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq;
-		subflow_req->mp_join = 1;
 		subflow_req->backup = mp_opt.backup;
 		subflow_req->remote_id = mp_opt.join_id;
 		subflow_req->token = mp_opt.token;
 		subflow_req->remote_nonce = mp_opt.nonce;
 		subflow_req->msk = subflow_token_join_request(req, skb);
+		if (!subflow_req->msk)
+			return;
+
+		if (!mptcp_join_store(subflow_req, (void *)sk_listener, want_cookie))
+			return;
+
+		subflow_req->mp_join = 1;
 		pr_debug("token=%u, remote_nonce=%u msk=%p", subflow_req->token,
 			 subflow_req->remote_nonce, subflow_req->msk);
 	}
@@ -1285,9 +1334,14 @@ static void subflow_ulp_release(struct sock *sk)
 	if (!ctx)
 		return;
 
-	if (ctx->conn)
-		sock_put(ctx->conn);
+	if (ctx->conn) {
+		struct sock *msk = ctx->conn;
+
+		if (ctx->mp_join)
+			atomic_add_unless(&inet_csk(msk)->icsk_accept_queue.qlen, -1, 0);
 
+		sock_put(msk);
+	}
 	kfree_rcu(ctx, rcu);
 }
 
-- 
2.26.2

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

* [RFC v2 mptcp-next 11/12] mptcp: enable JOIN requests even if cookies are in use
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: netdev
  Cc: mathew.j.martineau, edumazet, mptcp, matthieu.baerts, Florian Westphal

JOIN requests do not work in syncookie mode -- for HMAC validation, the
peers nonce is required, but this nonce is only present in the SYN.

So either we need to drop or reject all JOIN requests once a listening
socket enters syncookie mode, or we need to store enough state to
validate the ACKs HMAC later on.

This allows the subflow request initialisation function to store the
request socket even when syncookies are used, i.e. the listener
socket queue will grow past its upper limit.

Following restrictions apply:
1. The (32bit) token contained in the MP_JOIN SYN packet returns
   a valid parent connection.
2. The parent connection can accept one more subflow.

To ensure 2), all MP_JOIN requests (new incoming and existing)
are accounted in the mptcp parent socket.

If the token is invalid or the parent cannot accept a new subflow,
no information is stored and TCP fallback path is used.

The parent socket can't be used without further changes in TCP stack,
because socket creation after 3whs completion checks that the associated
socket is in LISTEN state.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 To ease review I think it would also be possible to
 defer the JOIN stuff for later and just focus on initial
 MP_CAPABLE request.  OTOH, doing so yields MPTCP-on-wire but with no
 Multipath capability so I'm not sure having MP_CAPABLE without
 MP_JOIN is useful.

 net/mptcp/pm_netlink.c |  2 +-
 net/mptcp/protocol.h   |  2 ++
 net/mptcp/subflow.c    | 60 +++++++++++++++++++++++++++++++++++++++---
 3 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
index c8820c4156e6..117f794ecc54 100644
--- a/net/mptcp/pm_netlink.c
+++ b/net/mptcp/pm_netlink.c
@@ -41,7 +41,7 @@ struct pm_nl_pernet {
 	unsigned int		next_id;
 };
 
-#define MPTCP_PM_ADDR_MAX	8
+#define MPTCP_PM_ADDR_MAX	MPTCP_SUBFLOWS_MAX
 
 static bool addresses_equal(const struct mptcp_addr_info *a,
 			    struct mptcp_addr_info *b, bool use_port)
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 0ed402cdb9fd..586601e889fc 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -154,6 +154,8 @@ enum mptcp_pm_status {
 	MPTCP_PM_SUBFLOW_ESTABLISHED,
 };
 
+#define MPTCP_SUBFLOWS_MAX	8
+
 struct mptcp_pm_data {
 	struct mptcp_addr_info local;
 	struct mptcp_addr_info remote;
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 0761c35268ce..ab86010483fe 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -126,6 +126,49 @@ static int __subflow_check_options(const struct mptcp_options_received *mp_opt,
 	return 0;
 }
 
+static bool mptcp_join_store(struct mptcp_subflow_request_sock *req,
+			     struct sock *sk_listener,
+			     bool want_cookie)
+{
+	struct mptcp_sock *msk = req->msk;
+	struct inet_connection_sock *icsk;
+	struct sock *sk;
+
+	icsk = &msk->sk;
+	sk = &icsk->icsk_inet.sk;
+
+	if (inet_csk_reqsk_queue_len(sk) >= MPTCP_SUBFLOWS_MAX ||
+	    !mptcp_can_accept_new_subflow(msk))
+		return false;
+
+	atomic_inc(&inet_csk(sk)->icsk_accept_queue.qlen);
+
+	if (likely(!want_cookie))
+		return true;
+
+	/* Syncookies are used.
+	 * We can't do this for JOIN requests because we need to store
+	 * the initiators nonce for HMAC validation.
+	 *
+	 * At this point we know:
+	 * 1. a valid parent connection that should be joined
+	 * 2. the parent socket has less than MPTCP_SUBFLOWS_MAX joined
+	 * connections (includes those in progress).
+	 *
+	 * We add the request to the accept queue backlog ourselves
+	 * in this case.
+	 */
+	if (unlikely(!refcount_inc_not_zero(&sk_listener->sk_refcnt))) {
+		atomic_dec(&inet_csk(sk)->icsk_accept_queue.qlen);
+		return false;
+	}
+
+	req->sk.req.req.rsk_listener = sk_listener;
+	inet_csk_reqsk_queue_hash_add(sk, &req->sk.req.req,
+				      tcp_timeout_init((struct sock *)req));
+	return true;
+}
+
 static void subflow_init_req(struct request_sock *req,
 			     const struct sock *sk_listener,
 			     struct sk_buff *skb,
@@ -177,12 +220,18 @@ static void subflow_init_req(struct request_sock *req,
 
 	} else if (mp_opt.mp_join && listener->request_mptcp) {
 		subflow_req->ssn_offset = TCP_SKB_CB(skb)->seq;
-		subflow_req->mp_join = 1;
 		subflow_req->backup = mp_opt.backup;
 		subflow_req->remote_id = mp_opt.join_id;
 		subflow_req->token = mp_opt.token;
 		subflow_req->remote_nonce = mp_opt.nonce;
 		subflow_req->msk = subflow_token_join_request(req, skb);
+		if (!subflow_req->msk)
+			return;
+
+		if (!mptcp_join_store(subflow_req, (void *)sk_listener, want_cookie))
+			return;
+
+		subflow_req->mp_join = 1;
 		pr_debug("token=%u, remote_nonce=%u msk=%p", subflow_req->token,
 			 subflow_req->remote_nonce, subflow_req->msk);
 	}
@@ -1285,9 +1334,14 @@ static void subflow_ulp_release(struct sock *sk)
 	if (!ctx)
 		return;
 
-	if (ctx->conn)
-		sock_put(ctx->conn);
+	if (ctx->conn) {
+		struct sock *msk = ctx->conn;
+
+		if (ctx->mp_join)
+			atomic_add_unless(&inet_csk(msk)->icsk_accept_queue.qlen, -1, 0);
 
+		sock_put(msk);
+	}
 	kfree_rcu(ctx, rcu);
 }
 
-- 
2.26.2


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

* [MPTCP] [RFC v2 mptcp-next 12/12] selftests: mptcp: make 2nd net namespace use tcp syn cookies unconditionally
  2020-07-21 20:36 ` Florian Westphal
@ 2020-07-21 20:36 ` Florian Westphal
  -1 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: mptcp

[-- Attachment #1: Type: text/plain, Size: 4064 bytes --]

check we can establish connections even in syncookie mode.
Also check following MIB counters:
MPTcpExtMPCapableSYNRX (should increase for each MPTCP test)
MPTcpExtMPCapableACKRX (should increase for each MPTCP test)
TcpExtSyncookiesSent (should increase for listener in ns2)
TcpExtSyncookiesRecv (same)

Signed-off-by: Florian Westphal <fw(a)strlen.de>
---
 .../selftests/net/mptcp/mptcp_connect.sh      | 50 +++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/testing/selftests/net/mptcp/mptcp_connect.sh
index c0589e071f20..6260520674d0 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh
@@ -196,6 +196,9 @@ ip -net "$ns4" link set ns4eth3 up
 ip -net "$ns4" route add default via 10.0.3.2
 ip -net "$ns4" route add default via dead:beef:3::2
 
+# use TCP syn cookies, even if no flooding was detected.
+ip netns exec "$ns2" sysctl -q net.ipv4.tcp_syncookies=2
+
 set_ethtool_flags() {
 	local ns="$1"
 	local dev="$2"
@@ -407,6 +410,11 @@ do_transfer()
 		sleep 1
 	fi
 
+	local stat_synrx_last_l=$(ip netns exec ${listener_ns} nstat -z -a MPTcpExtMPCapableSYNRX | while read a count c rest ;do  echo $count;done)
+	local stat_ackrx_last_l=$(ip netns exec ${listener_ns} nstat -z -a MPTcpExtMPCapableACKRX | while read a count c rest ;do  echo $count;done)
+	local stat_cookietx_last=$(ip netns exec ${listener_ns} nstat -z -a TcpExtSyncookiesSent | while read a count c rest ;do  echo $count;done)
+	local stat_cookierx_last=$(ip netns exec ${listener_ns} nstat -z -a TcpExtSyncookiesRecv | while read a count c rest ;do  echo $count;done)
+
 	ip netns exec ${listener_ns} ./mptcp_connect -t $timeout -l -p $port -s ${srv_proto} $extra_args $local_addr < "$sin" > "$sout" &
 	local spid=$!
 
@@ -450,6 +458,48 @@ do_transfer()
 	check_transfer $cin $sout "file received by server"
 	rets=$?
 
+	local stat_synrx_now_l=$(ip netns exec ${listener_ns} nstat -z -a MPTcpExtMPCapableSYNRX  | while read a count c rest ;do  echo $count;done)
+	local stat_ackrx_now_l=$(ip netns exec ${listener_ns} nstat -z -a MPTcpExtMPCapableACKRX  | while read a count c rest ;do  echo $count;done)
+
+	local stat_cookietx_now=$(ip netns exec ${listener_ns} nstat -z -a TcpExtSyncookiesSent | while read a count c rest ;do  echo $count;done)
+	local stat_cookierx_now=$(ip netns exec ${listener_ns} nstat -z -a TcpExtSyncookiesRecv | while read a count c rest ;do  echo $count;done)
+
+	expect_synrx=$((stat_synrx_last_l))
+	expect_ackrx=$((stat_ackrx_last_l))
+
+	cookies=$(ip netns exec ${listener_ns} sysctl net.ipv4.tcp_syncookies)
+	cookies=${cookies##*=}
+
+	if [ ${cl_proto} = "MPTCP" ] && [ ${srv_proto} = "MPTCP" ]; then
+		expect_synrx=$((stat_synrx_last_l+1))
+		expect_ackrx=$((stat_ackrx_last_l+1))
+		if [ $cookies -eq 2 ];then
+			expect_synrx=$((stat_synrx_last_l+2))
+		fi
+	fi
+	if [ $cookies -eq 2 ];then
+		if [ $stat_cookietx_last -ge $stat_cookietx_now ] ;then
+			echo "${listener_ns} CookieSent: ${cl_proto} -> ${srv_proto}: did not advance"
+		fi
+		if [ $stat_cookierx_last -ge $stat_cookierx_now ] ;then
+			echo "${listener_ns} CookieRecv: ${cl_proto} -> ${srv_proto}: did not advance"
+		fi
+	else
+		if [ $stat_cookietx_last -ne $stat_cookietx_now ] ;then
+			echo "${listener_ns} CookieSent: ${cl_proto} -> ${srv_proto}: changed"
+		fi
+		if [ $stat_cookierx_last -ne $stat_cookierx_now ] ;then
+			echo "${listener_ns} CookieRecv: ${cl_proto} -> ${srv_proto}: changed"
+		fi
+	fi
+
+	if [ $expect_synrx -ne $stat_synrx_now_l ] ;then
+		echo "${listener_ns} SYNRX: ${cl_proto} -> ${srv_proto}: expect ${expect_synrx}, got ${stat_synrx_now_l}"
+	fi
+	if [ $expect_ackrx -ne $stat_ackrx_now_l ] ;then
+		echo "${listener_ns} ACKRX: ${cl_proto} -> ${srv_proto}: expect ${expect_synrx}, got ${stat_synrx_now_l}"
+	fi
+
 	if [ $retc -eq 0 ] && [ $rets -eq 0 ];then
 		echo "$duration [ OK ]"
 		cat "$capout"
-- 
2.26.2

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

* [RFC v2 mptcp-next 12/12] selftests: mptcp: make 2nd net namespace use tcp syn cookies unconditionally
@ 2020-07-21 20:36 ` Florian Westphal
  0 siblings, 0 replies; 26+ messages in thread
From: Florian Westphal @ 2020-07-21 20:36 UTC (permalink / raw)
  To: netdev
  Cc: mathew.j.martineau, edumazet, mptcp, matthieu.baerts, Florian Westphal

check we can establish connections even in syncookie mode.
Also check following MIB counters:
MPTcpExtMPCapableSYNRX (should increase for each MPTCP test)
MPTcpExtMPCapableACKRX (should increase for each MPTCP test)
TcpExtSyncookiesSent (should increase for listener in ns2)
TcpExtSyncookiesRecv (same)

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 .../selftests/net/mptcp/mptcp_connect.sh      | 50 +++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/testing/selftests/net/mptcp/mptcp_connect.sh
index c0589e071f20..6260520674d0 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh
@@ -196,6 +196,9 @@ ip -net "$ns4" link set ns4eth3 up
 ip -net "$ns4" route add default via 10.0.3.2
 ip -net "$ns4" route add default via dead:beef:3::2
 
+# use TCP syn cookies, even if no flooding was detected.
+ip netns exec "$ns2" sysctl -q net.ipv4.tcp_syncookies=2
+
 set_ethtool_flags() {
 	local ns="$1"
 	local dev="$2"
@@ -407,6 +410,11 @@ do_transfer()
 		sleep 1
 	fi
 
+	local stat_synrx_last_l=$(ip netns exec ${listener_ns} nstat -z -a MPTcpExtMPCapableSYNRX | while read a count c rest ;do  echo $count;done)
+	local stat_ackrx_last_l=$(ip netns exec ${listener_ns} nstat -z -a MPTcpExtMPCapableACKRX | while read a count c rest ;do  echo $count;done)
+	local stat_cookietx_last=$(ip netns exec ${listener_ns} nstat -z -a TcpExtSyncookiesSent | while read a count c rest ;do  echo $count;done)
+	local stat_cookierx_last=$(ip netns exec ${listener_ns} nstat -z -a TcpExtSyncookiesRecv | while read a count c rest ;do  echo $count;done)
+
 	ip netns exec ${listener_ns} ./mptcp_connect -t $timeout -l -p $port -s ${srv_proto} $extra_args $local_addr < "$sin" > "$sout" &
 	local spid=$!
 
@@ -450,6 +458,48 @@ do_transfer()
 	check_transfer $cin $sout "file received by server"
 	rets=$?
 
+	local stat_synrx_now_l=$(ip netns exec ${listener_ns} nstat -z -a MPTcpExtMPCapableSYNRX  | while read a count c rest ;do  echo $count;done)
+	local stat_ackrx_now_l=$(ip netns exec ${listener_ns} nstat -z -a MPTcpExtMPCapableACKRX  | while read a count c rest ;do  echo $count;done)
+
+	local stat_cookietx_now=$(ip netns exec ${listener_ns} nstat -z -a TcpExtSyncookiesSent | while read a count c rest ;do  echo $count;done)
+	local stat_cookierx_now=$(ip netns exec ${listener_ns} nstat -z -a TcpExtSyncookiesRecv | while read a count c rest ;do  echo $count;done)
+
+	expect_synrx=$((stat_synrx_last_l))
+	expect_ackrx=$((stat_ackrx_last_l))
+
+	cookies=$(ip netns exec ${listener_ns} sysctl net.ipv4.tcp_syncookies)
+	cookies=${cookies##*=}
+
+	if [ ${cl_proto} = "MPTCP" ] && [ ${srv_proto} = "MPTCP" ]; then
+		expect_synrx=$((stat_synrx_last_l+1))
+		expect_ackrx=$((stat_ackrx_last_l+1))
+		if [ $cookies -eq 2 ];then
+			expect_synrx=$((stat_synrx_last_l+2))
+		fi
+	fi
+	if [ $cookies -eq 2 ];then
+		if [ $stat_cookietx_last -ge $stat_cookietx_now ] ;then
+			echo "${listener_ns} CookieSent: ${cl_proto} -> ${srv_proto}: did not advance"
+		fi
+		if [ $stat_cookierx_last -ge $stat_cookierx_now ] ;then
+			echo "${listener_ns} CookieRecv: ${cl_proto} -> ${srv_proto}: did not advance"
+		fi
+	else
+		if [ $stat_cookietx_last -ne $stat_cookietx_now ] ;then
+			echo "${listener_ns} CookieSent: ${cl_proto} -> ${srv_proto}: changed"
+		fi
+		if [ $stat_cookierx_last -ne $stat_cookierx_now ] ;then
+			echo "${listener_ns} CookieRecv: ${cl_proto} -> ${srv_proto}: changed"
+		fi
+	fi
+
+	if [ $expect_synrx -ne $stat_synrx_now_l ] ;then
+		echo "${listener_ns} SYNRX: ${cl_proto} -> ${srv_proto}: expect ${expect_synrx}, got ${stat_synrx_now_l}"
+	fi
+	if [ $expect_ackrx -ne $stat_ackrx_now_l ] ;then
+		echo "${listener_ns} ACKRX: ${cl_proto} -> ${srv_proto}: expect ${expect_synrx}, got ${stat_synrx_now_l}"
+	fi
+
 	if [ $retc -eq 0 ] && [ $rets -eq 0 ];then
 		echo "$duration [ OK ]"
 		cat "$capout"
-- 
2.26.2


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

end of thread, other threads:[~2020-07-21 20:37 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-21 20:36 [MPTCP] [RFC v2 mptcp-next 10/12] tcp: handle want_cookie clause via reqsk_put Florian Westphal
2020-07-21 20:36 ` Florian Westphal
  -- strict thread matches above, loose matches on Subject: below --
2020-07-21 20:36 [MPTCP] [RFC v2 mptcp-next 12/12] selftests: mptcp: make 2nd net namespace use tcp syn cookies unconditionally Florian Westphal
2020-07-21 20:36 ` Florian Westphal
2020-07-21 20:36 [MPTCP] [RFC v2 mptcp-next 11/12] mptcp: enable JOIN requests even if cookies are in use Florian Westphal
2020-07-21 20:36 ` Florian Westphal
2020-07-21 20:36 [MPTCP] [RFC v2 mptcp-next 09/12] tcp: syncookies: create mptcp request socket for ACK cookies with MPTCP option Florian Westphal
2020-07-21 20:36 ` Florian Westphal
2020-07-21 20:36 [MPTCP] [RFC v2 mptcp-next 08/12] mptcp: subflow: add mptcp_subflow_init_cookie_req helper Florian Westphal
2020-07-21 20:36 ` Florian Westphal
2020-07-21 20:36 [MPTCP] [RFC v2 mptcp-next 07/12] tcp: pass want_cookie down to req_init function Florian Westphal
2020-07-21 20:36 ` Florian Westphal
2020-07-21 20:36 [MPTCP] [RFC v2 mptcp-next 06/12] tcp: remove sk_listener const qualifier from " Florian Westphal
2020-07-21 20:36 ` Florian Westphal
2020-07-21 20:36 [MPTCP] [RFC v2 mptcp-next 05/12] mptcp: rename and export mptcp_subflow_request_sock_ops Florian Westphal
2020-07-21 20:36 ` Florian Westphal
2020-07-21 20:36 [MPTCP] [RFC v2 mptcp-next 04/12] mptcp: subflow: split subflow_init_req into helpers Florian Westphal
2020-07-21 20:36 ` Florian Westphal
2020-07-21 20:36 [MPTCP] [RFC v2 mptcp-next 03/12] mptcp: token: move retry to caller Florian Westphal
2020-07-21 20:36 ` Florian Westphal
2020-07-21 20:36 [MPTCP] [RFC v2 mptcp-next 02/12] tcp: syncookies: use single reqsk_free location Florian Westphal
2020-07-21 20:36 ` Florian Westphal
2020-07-21 20:36 [MPTCP] [RFC v2 mptcp-next 01/12] tcp: remove cookie_ts bit from request_sock Florian Westphal
2020-07-21 20:36 ` Florian Westphal
2020-07-21 20:36 [MPTCP] [RFC v2 mptcp-next 01/12] mptcp: add syncookie support Florian Westphal
2020-07-21 20:36 ` Florian Westphal

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.