* [MPTCP] [RFC PATCH v2 04/19] mptcp: Handle MPTCP TCP options
@ 2018-06-05 23:40 Mat Martineau
0 siblings, 0 replies; 3+ messages in thread
From: Mat Martineau @ 2018-06-05 23:40 UTC (permalink / raw)
To: mptcp
[-- Attachment #1: Type: text/plain, Size: 14457 bytes --]
From: Peter Krystad <peter.krystad(a)intel.com>
Signed-off-by: Peter Krystad <peter.krystad(a)intel.com>
---
include/linux/tcp.h | 14 ++++
include/net/mptcp.h | 49 ++++++++++++
include/net/tcp.h | 2 +
net/ipv4/tcp_input.c | 15 ++++
net/ipv4/tcp_output.c | 72 +++++++++++++++++
net/mptcp/Makefile | 2 +-
net/mptcp/options.c | 176 ++++++++++++++++++++++++++++++++++++++++++
7 files changed, 329 insertions(+), 1 deletion(-)
create mode 100644 net/mptcp/options.c
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 72705eaf4b84..17ecbebf129d 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -104,6 +104,16 @@ struct tcp_options_received {
u8 num_sacks; /* Number of SACK blocks */
u16 user_mss; /* mss requested by user in ioctl */
u16 mss_clamp; /* Maximal mss, negotiated at connection setup */
+ struct {
+ u8 mp_capable : 1,
+ mp_join : 1,
+ dss : 1,
+ version : 4;
+ u8 flags;
+ u64 sndr_key;
+ u64 rcvr_key;
+ } mptcp;
+
};
static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
@@ -113,6 +123,7 @@ static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
#if IS_ENABLED(CONFIG_SMC)
rx_opt->smc_ok = 0;
#endif
+ rx_opt->mptcp.mp_capable = rx_opt->mptcp.mp_join = rx_opt->mptcp.dss = 0;
}
/* This is the max number of SACKS that we'll generate and process. It's safe
@@ -137,6 +148,7 @@ struct tcp_request_sock {
* FastOpen it's the seq#
* after data-in-SYN.
*/
+ bool is_mptcp;
};
static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
@@ -387,6 +399,8 @@ struct tcp_sock {
*/
struct request_sock *fastopen_rsk;
u32 *saved_syn;
+
+ bool is_mptcp;
};
enum tsq_enum {
diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index 7f7b18b000fe..736febd2a9d4 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -18,6 +18,23 @@
#include <linux/tcp.h>
+/* MPTCP option subtypes */
+
+#define MPTCPOPT_MP_CAPABLE 0
+#define MPTCPOPT_MP_JOIN 1
+#define MPTCPOPT_DSS 2
+#define MPTCPOPT_ADD_ADDR 3
+#define MPTCPOPT_REMOVE_ADDR 4
+#define MPTCPOPT_MP_PRIO 5
+#define MPTCPOPT_MP_FAIL 6
+#define MPTCPOPT_MP_FASTCLOSE 7
+
+/* MPTCP handshake flags */
+
+#define MPTCP_CAP_CHECKSUM_REQD (1 << 7)
+#define MPTCP_CAP_EXTENSIBILITY (1 << 6)
+#define MPTCP_CAP_HMAC_SHA1 (1 << 0)
+
/* MPTCP connection sock */
struct mptcp_sock {
/* inet_connection_sock must be the first member */
@@ -30,4 +47,36 @@ static inline struct mptcp_sock *mptcp_sk(const struct sock *sk)
return (struct mptcp_sock *)sk;
}
+#ifdef CONFIG_MPTCP
+
+void mptcp_parse_option(const unsigned char *ptr, int opsize,
+ struct tcp_options_received *opt_rx);
+unsigned int mptcp_syn_options(struct sock *sk, u64 *local_key);
+unsigned int mptcp_synack_options(struct request_sock *req,
+ u64 *local_key, u64 *remote_key);
+
+void mptcp_get_options(const struct sk_buff *skb,
+ struct tcp_options_received *options);
+
+#else
+
+static inline void mptcp_parse_option(const unsigned char *ptr, int opsize,
+ struct tcp_options_received *opt_rx)
+{
+}
+
+static inline unsigned int mptcp_syn_options(struct sock *sk, u64 *local_key)
+{
+ return 0;
+}
+static inline unsigned int mptcp_synack_options(struct request_sock *sk,
+ u64 *local_key,
+ u64 *remote_key)
+{
+ return 0;
+}
+
+
+
+#endif /* CONFIG_MPTCP */
#endif /* __NET_MPTCP_H */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index c8716de4547c..a1d4e744b258 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -214,6 +214,8 @@ void tcp_time_wait(struct sock *sk, int state, int timeo);
#define TCPOLEN_MD5SIG_ALIGNED 20
#define TCPOLEN_MSS_ALIGNED 4
#define TCPOLEN_EXP_SMC_BASE_ALIGNED 8
+#define TCPOLEN_MPTCP_MPC_SYN 12
+#define TCPOLEN_MPTCP_MPC_SYNACK 20
/* Flags in tp->nonagle */
#define TCP_NAGLE_OFF 1 /* Nagle's algo is disabled */
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 355d3dffd021..bdc36001ce90 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -78,6 +78,7 @@
#include <linux/errqueue.h>
#include <trace/events/tcp.h>
#include <linux/static_key.h>
+#include <net/mptcp.h>
int sysctl_tcp_max_orphans __read_mostly = NR_FILE;
@@ -3842,6 +3843,10 @@ void tcp_parse_options(const struct net *net,
*/
break;
#endif
+ case TCPOPT_MPTCP:
+ mptcp_parse_option(ptr, opsize, opt_rx);
+ break;
+
case TCPOPT_FASTOPEN:
tcp_parse_fastopen_option(
opsize - TCPOLEN_FASTOPEN_BASE,
@@ -5763,6 +5768,15 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
tcp_initialize_rcv_mss(sk);
+ // @@ could use a callout here
+ if (tp->is_mptcp) {
+ struct subflow_sock *subflow = subflow_sk(sk);
+ if (subflow->request_mptcp && tp->rx_opt.mptcp.mp_capable) {
+ subflow->mp_capable = 1;
+ subflow->remote_key = tp->rx_opt.mptcp.sndr_key;
+ }
+ }
+
/* Remember, tcp_poll() does not lock socket!
* Change state from SYN-SENT only after copied_seq
* is initialized. */
@@ -6339,6 +6353,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
tcp_rsk(req)->af_specific = af_ops;
tcp_rsk(req)->ts_off = 0;
+ tcp_rsk(req)->is_mptcp = 0;
tcp_clear_options(&tmp_opt);
tmp_opt.mss_clamp = af_ops->mss_clamp;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 8e08b409c71e..fc49d80d3ba7 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -37,6 +37,7 @@
#define pr_fmt(fmt) "TCP: " fmt
#include <net/tcp.h>
+#include <net/mptcp.h>
#include <linux/compiler.h>
#include <linux/gfp.h>
@@ -411,6 +412,8 @@ static inline bool tcp_urg_mode(const struct tcp_sock *tp)
#define OPTION_WSCALE (1 << 3)
#define OPTION_FAST_OPEN_COOKIE (1 << 8)
#define OPTION_SMC (1 << 9)
+#define OPTION_MPTCP (1 << 10)
+#define OPTION_MPTCP_ACK (1 << 11)
static void smc_options_write(__be32 *ptr, u16 *options)
{
@@ -436,6 +439,8 @@ struct tcp_out_options {
__u8 *hash_location; /* temporary pointer, overloaded */
__u32 tsval, tsecr; /* need to include OPTION_TS */
struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */
+ u64 sndr_key;
+ u64 rcvr_key;
};
/* Write previously computed TCP options to the packet.
@@ -546,6 +551,29 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
}
smc_options_write(ptr, &options);
+
+ if (OPTION_MPTCP & options) {
+ u8 *p = (u8 *)ptr;
+ *p++ = 0x1e; // TCP option: Multipath TCP
+ *p++ = 12; // length
+ *p++ = 0; // subtype=MP_CAPABLE | version=0
+ *p++ = 0x1; // flags=HMAC-SHA1
+ memcpy(p, &opts->sndr_key, 8);
+ pr_debug("tcp_options_write: opts->sndr_key=%llu", opts->sndr_key);
+ }
+
+ if (OPTION_MPTCP_ACK & options) {
+ u8 *p = (u8 *)ptr;
+ *p++ = 0x1e; // TCP option: Multipath TCP
+ *p++ = 20; // length
+ *p++ = 0; // subtype=MP_CAPABLE | version=0
+ *p++ = 0x1; // flags=HMAC-SHA1
+ memcpy(p, &opts->sndr_key, 8);
+ pr_debug("tcp_options_write: opts->sndr_key=%llu", opts->sndr_key);
+ p += 8;
+ memcpy(p, &opts->rcvr_key, 8);
+ pr_debug("tcp_options_write: opts->rcvr_key=%llu", opts->rcvr_key);
+ }
}
static void smc_set_option(const struct tcp_sock *tp,
@@ -649,6 +677,15 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
smc_set_option(tp, opts, &remaining);
+ if (tp->is_mptcp) {
+ u64 local_key;
+ if (mptcp_syn_options(sk, &local_key)) {
+ opts->options |= OPTION_MPTCP;
+ opts->sndr_key = local_key;
+ remaining -= TCPOLEN_MPTCP_MPC_SYN;
+ }
+ }
+
return MAX_TCP_OPTION_SPACE - remaining;
}
@@ -709,6 +746,18 @@ static unsigned int tcp_synack_options(const struct sock *sk,
remaining -= need;
}
}
+ if (tcp_rsk(req)->is_mptcp) {
+ u64 local_key;
+ u64 remote_key;
+ if (mptcp_synack_options(req, &local_key, &remote_key)) {
+ if (remaining >= TCPOLEN_MPTCP_MPC_SYNACK) {
+ opts->options |= OPTION_MPTCP_ACK;
+ opts->sndr_key = local_key;
+ opts->rcvr_key = remote_key;
+ remaining -= TCPOLEN_MPTCP_MPC_SYNACK;
+ }
+ }
+ }
smc_set_option_cond(tcp_sk(sk), ireq, opts, &remaining);
@@ -757,6 +806,29 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb
opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK;
}
+ if (tp->is_mptcp) {
+ struct subflow_sock *subflow = subflow_sk(sk);
+ pr_debug("tcp_established_options: subflow=%p", subflow);
+ if (subflow->mp_capable) {
+ const unsigned int remaining = MAX_TCP_OPTION_SPACE - size;
+ pr_debug("tcp_established_options: remaining=%d", remaining);
+ if (!subflow->fourth_ack) {
+ pr_debug("tcp_established_options: OPTION_MPTCP_ACK");
+ if (remaining >= 20) {
+ opts->options |= OPTION_MPTCP_ACK;
+ opts->sndr_key = subflow->local_key;
+ opts->rcvr_key = subflow->remote_key;
+ size += 20;
+ }
+ subflow->fourth_ack = 1;
+ // @@ also this is where first DSS goes in?
+ }
+ else {
+ pr_debug("tcp_established_options: OPTION_MPTCP_DSS");
+ // @@ send DSS based on remaining
+ }
+ }
+ }
return size;
}
diff --git a/net/mptcp/Makefile b/net/mptcp/Makefile
index 5624e7d51d48..2bd18e3b9fda 100644
--- a/net/mptcp/Makefile
+++ b/net/mptcp/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_MPTCP) += mptcp.o
-mptcp-y := protocol.o
+mptcp-y := protocol.o options.o
diff --git a/net/mptcp/options.c b/net/mptcp/options.c
new file mode 100644
index 000000000000..2ef7ba20b33b
--- /dev/null
+++ b/net/mptcp/options.c
@@ -0,0 +1,176 @@
+/*
+ * Multipath TCP
+ *
+ * Copyright (c) 2017, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <net/tcp.h>
+#include <net/mptcp.h>
+
+void mptcp_parse_option(const unsigned char *ptr, int opsize,
+ struct tcp_options_received *opt_rx)
+{
+ u8 subtype;
+ u64 *p;
+
+ opsize -= 2;
+ subtype = *ptr++;
+
+ /* MPTCPOPT_MP_CAPABLE
+ * 0: 4MSB=subtype, 4LSB=version
+ * 1: Handshake flags
+ * 2-9: Sender key
+ * 10-17: Receiver key (optional)
+ */
+ switch (subtype & 0xF0) {
+ case 0x00:
+ pr_debug("MP_CAPABLE");
+ pr_debug("flags=%02x", *ptr);
+ opt_rx->mptcp.mp_capable = 1;
+ opt_rx->mptcp.version = subtype & 0x0F;
+ opt_rx->mptcp.flags = *ptr++;
+ p = (u64 *)ptr;
+ pr_debug("sndr_key=%llu", *p);
+ opt_rx->mptcp.sndr_key = *p++;
+ if (opsize > 10) {
+ pr_debug("rcvr_key=%llu", *p);
+ opt_rx->mptcp.rcvr_key = *p++;
+ }
+ break;
+
+ /* MPTCPOPT_MP_JOIN
+ *
+ * Initial SYN
+ * 0: 4MSB=subtype, 000, 1LSB=Backup
+ * 1: Address ID
+ * 2-5: Receiver token
+ * 6-9: Sender random number
+ *
+ * SYN/ACK response
+ * 0: 4MSB=subtype, 000, 1LSB=Backup
+ * 1: Address ID
+ * 2-9: Sender truncated HMAC
+ * 10-13: Sender random number
+ *
+ * Third ACK
+ * 0: 4MSB=subtype, 0000
+ * 1: 0 (Reserved)
+ * 2-21: Sender HMAC
+ */
+
+ /* MPTCPOPT_DSS
+ * 0: 4MSB=subtype, 0000
+ * 1: 3MSB=0, F=Data FIN, m=DSN length, M=has DSN/SSN/DLL/checksum,
+ * a=DACK length, A=has DACK
+ * 0, 4, or 8 bytes of DACK (depending on A/a)
+ * 0, 4, or 8 bytes of DSN (depending on M/m)
+ * 0 or 4 bytes of SSN (depending on M)
+ * 0 or 2 bytes of DLL (depending on M)
+ * 0 or 2 bytes of checksum (depending on M)
+ */
+ case 0x20:
+ pr_debug("DSS");
+ opt_rx->mptcp.dss = 1;
+ break;
+
+ /* MPTCPOPT_ADD_ADDR
+ * 0: 4MSB=subtype, 4LSB=IP version (4 or 6)
+ * 1: Address ID
+ * 4 or 16 bytes of address (depending on ip version)
+ * 0 or 2 bytes of port (depending on length)
+ */
+
+ /* MPTCPOPT_REMOVE_ADDR
+ * 0: 4MSB=subtype, 0000
+ * 1: Address ID
+ * Additional bytes: More address IDs (depending on length)
+ */
+
+ /* MPTCPOPT_MP_PRIO
+ * 0: 4MSB=subtype, 000, 1LSB=Backup
+ * 1: Address ID (optional, current addr implied if not present)
+ */
+
+ /* MPTCPOPT_MP_FAIL
+ * 0: 4MSB=subtype, 0000
+ * 1: 0 (Reserved)
+ * 2-9: DSN
+ */
+
+ /* MPTCPOPT_MP_FASTCLOSE
+ * 0: 4MSB=subtype, 0000
+ * 1: 0 (Reserved)
+ * 2-9: Receiver key
+ */
+ default:
+ break;
+ }
+}
+
+void mptcp_get_options(const struct sk_buff *skb,
+ struct tcp_options_received *opt_rx)
+{
+ const unsigned char *ptr;
+ const struct tcphdr *th = tcp_hdr(skb);
+ int length = (th->doff * 4) - sizeof(struct tcphdr);
+
+ ptr = (const unsigned char *)(th + 1);
+
+ while (length > 0) {
+ int opcode = *ptr++;
+ int opsize;
+
+ switch (opcode) {
+ case TCPOPT_EOL:
+ return;
+ case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
+ length--;
+ continue;
+ default:
+ opsize = *ptr++;
+ if (opsize < 2) /* "silly options" */
+ return;
+ if (opsize > length)
+ return; /* don't parse partial options */
+ if (opcode == TCPOPT_MPTCP)
+ mptcp_parse_option(ptr, opsize, opt_rx);
+ ptr += opsize - 2;
+ length -= opsize;
+ }
+ }
+}
+
+unsigned int mptcp_syn_options(struct sock *sk, u64 *local_key)
+{
+ struct subflow_sock *subflow = subflow_sk(sk);
+
+ if (subflow->request_mptcp) {
+ pr_debug("local_key=%llu", subflow->local_key);
+ *local_key = subflow->local_key;
+ }
+ return subflow->request_mptcp;
+}
+
+unsigned int mptcp_synack_options(struct request_sock *req, u64 *local_key,
+ u64 *remote_key)
+{
+ struct subflow_request_sock *subflow_req = subflow_rsk(req);
+
+ if (subflow_req->mp_capable) {
+ *local_key = subflow_req->local_key;
+ *remote_key = subflow_req->remote_key;
+ pr_debug("local_key=%llu", *local_key);
+ pr_debug("remote_key=%llu", *remote_key);
+ }
+ return subflow_req->mp_capable;
+}
--
2.17.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [MPTCP] [RFC PATCH v2 04/19] mptcp: Handle MPTCP TCP options
@ 2018-06-07 18:53 Christoph Paasch
0 siblings, 0 replies; 3+ messages in thread
From: Christoph Paasch @ 2018-06-07 18:53 UTC (permalink / raw)
To: mptcp
[-- Attachment #1: Type: text/plain, Size: 16037 bytes --]
On 05/06/18 - 16:40:23, Mat Martineau wrote:
> From: Peter Krystad <peter.krystad(a)intel.com>
>
> Signed-off-by: Peter Krystad <peter.krystad(a)intel.com>
> ---
> include/linux/tcp.h | 14 ++++
> include/net/mptcp.h | 49 ++++++++++++
> include/net/tcp.h | 2 +
> net/ipv4/tcp_input.c | 15 ++++
> net/ipv4/tcp_output.c | 72 +++++++++++++++++
> net/mptcp/Makefile | 2 +-
> net/mptcp/options.c | 176 ++++++++++++++++++++++++++++++++++++++++++
> 7 files changed, 329 insertions(+), 1 deletion(-)
> create mode 100644 net/mptcp/options.c
>
> diff --git a/include/linux/tcp.h b/include/linux/tcp.h
> index 72705eaf4b84..17ecbebf129d 100644
> --- a/include/linux/tcp.h
> +++ b/include/linux/tcp.h
> @@ -104,6 +104,16 @@ struct tcp_options_received {
> u8 num_sacks; /* Number of SACK blocks */
> u16 user_mss; /* mss requested by user in ioctl */
> u16 mss_clamp; /* Maximal mss, negotiated at connection setup */
> + struct {
> + u8 mp_capable : 1,
> + mp_join : 1,
> + dss : 1,
> + version : 4;
> + u8 flags;
> + u64 sndr_key;
> + u64 rcvr_key;
> + } mptcp;
Indentation looks wrong here.
Nit-picking ;-) (because I have a bigger comment further down below)
> +
> };
>
> static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
> @@ -113,6 +123,7 @@ static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
> #if IS_ENABLED(CONFIG_SMC)
> rx_opt->smc_ok = 0;
> #endif
> + rx_opt->mptcp.mp_capable = rx_opt->mptcp.mp_join = rx_opt->mptcp.dss = 0;
> }
>
> /* This is the max number of SACKS that we'll generate and process. It's safe
> @@ -137,6 +148,7 @@ struct tcp_request_sock {
> * FastOpen it's the seq#
> * after data-in-SYN.
> */
> + bool is_mptcp;
> };
>
> static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
> @@ -387,6 +399,8 @@ struct tcp_sock {
> */
> struct request_sock *fastopen_rsk;
> u32 *saved_syn;
> +
> + bool is_mptcp;
> };
>
> enum tsq_enum {
> diff --git a/include/net/mptcp.h b/include/net/mptcp.h
> index 7f7b18b000fe..736febd2a9d4 100644
> --- a/include/net/mptcp.h
> +++ b/include/net/mptcp.h
> @@ -18,6 +18,23 @@
>
> #include <linux/tcp.h>
>
> +/* MPTCP option subtypes */
> +
> +#define MPTCPOPT_MP_CAPABLE 0
> +#define MPTCPOPT_MP_JOIN 1
> +#define MPTCPOPT_DSS 2
> +#define MPTCPOPT_ADD_ADDR 3
> +#define MPTCPOPT_REMOVE_ADDR 4
> +#define MPTCPOPT_MP_PRIO 5
> +#define MPTCPOPT_MP_FAIL 6
> +#define MPTCPOPT_MP_FASTCLOSE 7
> +
> +/* MPTCP handshake flags */
> +
> +#define MPTCP_CAP_CHECKSUM_REQD (1 << 7)
> +#define MPTCP_CAP_EXTENSIBILITY (1 << 6)
> +#define MPTCP_CAP_HMAC_SHA1 (1 << 0)
> +
> /* MPTCP connection sock */
> struct mptcp_sock {
> /* inet_connection_sock must be the first member */
> @@ -30,4 +47,36 @@ static inline struct mptcp_sock *mptcp_sk(const struct sock *sk)
> return (struct mptcp_sock *)sk;
> }
>
> +#ifdef CONFIG_MPTCP
> +
> +void mptcp_parse_option(const unsigned char *ptr, int opsize,
> + struct tcp_options_received *opt_rx);
> +unsigned int mptcp_syn_options(struct sock *sk, u64 *local_key);
> +unsigned int mptcp_synack_options(struct request_sock *req,
> + u64 *local_key, u64 *remote_key);
> +
> +void mptcp_get_options(const struct sk_buff *skb,
> + struct tcp_options_received *options);
> +
> +#else
> +
> +static inline void mptcp_parse_option(const unsigned char *ptr, int opsize,
> + struct tcp_options_received *opt_rx)
> +{
> +}
> +
> +static inline unsigned int mptcp_syn_options(struct sock *sk, u64 *local_key)
> +{
> + return 0;
> +}
> +static inline unsigned int mptcp_synack_options(struct request_sock *sk,
> + u64 *local_key,
> + u64 *remote_key)
> +{
> + return 0;
> +}
> +
> +
> +
> +#endif /* CONFIG_MPTCP */
> #endif /* __NET_MPTCP_H */
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index c8716de4547c..a1d4e744b258 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -214,6 +214,8 @@ void tcp_time_wait(struct sock *sk, int state, int timeo);
> #define TCPOLEN_MD5SIG_ALIGNED 20
> #define TCPOLEN_MSS_ALIGNED 4
> #define TCPOLEN_EXP_SMC_BASE_ALIGNED 8
> +#define TCPOLEN_MPTCP_MPC_SYN 12
> +#define TCPOLEN_MPTCP_MPC_SYNACK 20
>
> /* Flags in tp->nonagle */
> #define TCP_NAGLE_OFF 1 /* Nagle's algo is disabled */
> diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> index 355d3dffd021..bdc36001ce90 100644
> --- a/net/ipv4/tcp_input.c
> +++ b/net/ipv4/tcp_input.c
> @@ -78,6 +78,7 @@
> #include <linux/errqueue.h>
> #include <trace/events/tcp.h>
> #include <linux/static_key.h>
> +#include <net/mptcp.h>
>
> int sysctl_tcp_max_orphans __read_mostly = NR_FILE;
>
> @@ -3842,6 +3843,10 @@ void tcp_parse_options(const struct net *net,
> */
> break;
> #endif
> + case TCPOPT_MPTCP:
> + mptcp_parse_option(ptr, opsize, opt_rx);
> + break;
> +
> case TCPOPT_FASTOPEN:
> tcp_parse_fastopen_option(
> opsize - TCPOLEN_FASTOPEN_BASE,
> @@ -5763,6 +5768,15 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
> tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
> tcp_initialize_rcv_mss(sk);
>
> + // @@ could use a callout here
> + if (tp->is_mptcp) {
> + struct subflow_sock *subflow = subflow_sk(sk);
> + if (subflow->request_mptcp && tp->rx_opt.mptcp.mp_capable) {
> + subflow->mp_capable = 1;
> + subflow->remote_key = tp->rx_opt.mptcp.sndr_key;
> + }
> + }
> +
> /* Remember, tcp_poll() does not lock socket!
> * Change state from SYN-SENT only after copied_seq
> * is initialized. */
> @@ -6339,6 +6353,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
>
> tcp_rsk(req)->af_specific = af_ops;
> tcp_rsk(req)->ts_off = 0;
> + tcp_rsk(req)->is_mptcp = 0;
>
> tcp_clear_options(&tmp_opt);
> tmp_opt.mss_clamp = af_ops->mss_clamp;
> diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
> index 8e08b409c71e..fc49d80d3ba7 100644
> --- a/net/ipv4/tcp_output.c
> +++ b/net/ipv4/tcp_output.c
> @@ -37,6 +37,7 @@
> #define pr_fmt(fmt) "TCP: " fmt
>
> #include <net/tcp.h>
> +#include <net/mptcp.h>
>
> #include <linux/compiler.h>
> #include <linux/gfp.h>
> @@ -411,6 +412,8 @@ static inline bool tcp_urg_mode(const struct tcp_sock *tp)
> #define OPTION_WSCALE (1 << 3)
> #define OPTION_FAST_OPEN_COOKIE (1 << 8)
> #define OPTION_SMC (1 << 9)
> +#define OPTION_MPTCP (1 << 10)
> +#define OPTION_MPTCP_ACK (1 << 11)
>
> static void smc_options_write(__be32 *ptr, u16 *options)
> {
> @@ -436,6 +439,8 @@ struct tcp_out_options {
> __u8 *hash_location; /* temporary pointer, overloaded */
> __u32 tsval, tsecr; /* need to include OPTION_TS */
> struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */
> + u64 sndr_key;
> + u64 rcvr_key;
> };
>
> /* Write previously computed TCP options to the packet.
> @@ -546,6 +551,29 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
> }
>
> smc_options_write(ptr, &options);
> +
> + if (OPTION_MPTCP & options) {
> + u8 *p = (u8 *)ptr;
> + *p++ = 0x1e; // TCP option: Multipath TCP
> + *p++ = 12; // length
> + *p++ = 0; // subtype=MP_CAPABLE | version=0
> + *p++ = 0x1; // flags=HMAC-SHA1
> + memcpy(p, &opts->sndr_key, 8);
> + pr_debug("tcp_options_write: opts->sndr_key=%llu", opts->sndr_key);
> + }
> +
> + if (OPTION_MPTCP_ACK & options) {
> + u8 *p = (u8 *)ptr;
> + *p++ = 0x1e; // TCP option: Multipath TCP
> + *p++ = 20; // length
> + *p++ = 0; // subtype=MP_CAPABLE | version=0
> + *p++ = 0x1; // flags=HMAC-SHA1
> + memcpy(p, &opts->sndr_key, 8);
> + pr_debug("tcp_options_write: opts->sndr_key=%llu", opts->sndr_key);
> + p += 8;
> + memcpy(p, &opts->rcvr_key, 8);
> + pr_debug("tcp_options_write: opts->rcvr_key=%llu", opts->rcvr_key);
> + }
> }
>
> static void smc_set_option(const struct tcp_sock *tp,
> @@ -649,6 +677,15 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
>
> smc_set_option(tp, opts, &remaining);
>
> + if (tp->is_mptcp) {
> + u64 local_key;
> + if (mptcp_syn_options(sk, &local_key)) {
> + opts->options |= OPTION_MPTCP;
> + opts->sndr_key = local_key;
> + remaining -= TCPOLEN_MPTCP_MPC_SYN;
> + }
> + }
> +
> return MAX_TCP_OPTION_SPACE - remaining;
> }
>
> @@ -709,6 +746,18 @@ static unsigned int tcp_synack_options(const struct sock *sk,
> remaining -= need;
> }
> }
> + if (tcp_rsk(req)->is_mptcp) {
> + u64 local_key;
> + u64 remote_key;
> + if (mptcp_synack_options(req, &local_key, &remote_key)) {
> + if (remaining >= TCPOLEN_MPTCP_MPC_SYNACK) {
> + opts->options |= OPTION_MPTCP_ACK;
> + opts->sndr_key = local_key;
> + opts->rcvr_key = remote_key;
> + remaining -= TCPOLEN_MPTCP_MPC_SYNACK;
> + }
> + }
> + }
>
> smc_set_option_cond(tcp_sk(sk), ireq, opts, &remaining);
>
> @@ -757,6 +806,29 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb
> opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK;
> }
>
> + if (tp->is_mptcp) {
> + struct subflow_sock *subflow = subflow_sk(sk);
> + pr_debug("tcp_established_options: subflow=%p", subflow);
> + if (subflow->mp_capable) {
> + const unsigned int remaining = MAX_TCP_OPTION_SPACE - size;
> + pr_debug("tcp_established_options: remaining=%d", remaining);
> + if (!subflow->fourth_ack) {
> + pr_debug("tcp_established_options: OPTION_MPTCP_ACK");
> + if (remaining >= 20) {
> + opts->options |= OPTION_MPTCP_ACK;
> + opts->sndr_key = subflow->local_key;
> + opts->rcvr_key = subflow->remote_key;
> + size += 20;
> + }
> + subflow->fourth_ack = 1;
> + // @@ also this is where first DSS goes in?
> + }
> + else {
> + pr_debug("tcp_established_options: OPTION_MPTCP_DSS");
> + // @@ send DSS based on remaining
> + }
> + }
> + }
You would need to have this code before the SACK-code. Because otherwise
SACK might fill up the available space and you will end up not writing the
DSS-option.
This also implies that you need to check whether at all there is space for a
SACK-block.
Christoph
> return size;
> }
>
> diff --git a/net/mptcp/Makefile b/net/mptcp/Makefile
> index 5624e7d51d48..2bd18e3b9fda 100644
> --- a/net/mptcp/Makefile
> +++ b/net/mptcp/Makefile
> @@ -1,3 +1,3 @@
> obj-$(CONFIG_MPTCP) += mptcp.o
>
> -mptcp-y := protocol.o
> +mptcp-y := protocol.o options.o
> diff --git a/net/mptcp/options.c b/net/mptcp/options.c
> new file mode 100644
> index 000000000000..2ef7ba20b33b
> --- /dev/null
> +++ b/net/mptcp/options.c
> @@ -0,0 +1,176 @@
> +/*
> + * Multipath TCP
> + *
> + * Copyright (c) 2017, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + */
> +
> +#include <linux/kernel.h>
> +#include <net/tcp.h>
> +#include <net/mptcp.h>
> +
> +void mptcp_parse_option(const unsigned char *ptr, int opsize,
> + struct tcp_options_received *opt_rx)
> +{
> + u8 subtype;
> + u64 *p;
> +
> + opsize -= 2;
> + subtype = *ptr++;
> +
> + /* MPTCPOPT_MP_CAPABLE
> + * 0: 4MSB=subtype, 4LSB=version
> + * 1: Handshake flags
> + * 2-9: Sender key
> + * 10-17: Receiver key (optional)
> + */
> + switch (subtype & 0xF0) {
> + case 0x00:
> + pr_debug("MP_CAPABLE");
> + pr_debug("flags=%02x", *ptr);
> + opt_rx->mptcp.mp_capable = 1;
> + opt_rx->mptcp.version = subtype & 0x0F;
> + opt_rx->mptcp.flags = *ptr++;
> + p = (u64 *)ptr;
> + pr_debug("sndr_key=%llu", *p);
> + opt_rx->mptcp.sndr_key = *p++;
> + if (opsize > 10) {
> + pr_debug("rcvr_key=%llu", *p);
> + opt_rx->mptcp.rcvr_key = *p++;
> + }
> + break;
> +
> + /* MPTCPOPT_MP_JOIN
> + *
> + * Initial SYN
> + * 0: 4MSB=subtype, 000, 1LSB=Backup
> + * 1: Address ID
> + * 2-5: Receiver token
> + * 6-9: Sender random number
> + *
> + * SYN/ACK response
> + * 0: 4MSB=subtype, 000, 1LSB=Backup
> + * 1: Address ID
> + * 2-9: Sender truncated HMAC
> + * 10-13: Sender random number
> + *
> + * Third ACK
> + * 0: 4MSB=subtype, 0000
> + * 1: 0 (Reserved)
> + * 2-21: Sender HMAC
> + */
> +
> + /* MPTCPOPT_DSS
> + * 0: 4MSB=subtype, 0000
> + * 1: 3MSB=0, F=Data FIN, m=DSN length, M=has DSN/SSN/DLL/checksum,
> + * a=DACK length, A=has DACK
> + * 0, 4, or 8 bytes of DACK (depending on A/a)
> + * 0, 4, or 8 bytes of DSN (depending on M/m)
> + * 0 or 4 bytes of SSN (depending on M)
> + * 0 or 2 bytes of DLL (depending on M)
> + * 0 or 2 bytes of checksum (depending on M)
> + */
> + case 0x20:
> + pr_debug("DSS");
> + opt_rx->mptcp.dss = 1;
> + break;
> +
> + /* MPTCPOPT_ADD_ADDR
> + * 0: 4MSB=subtype, 4LSB=IP version (4 or 6)
> + * 1: Address ID
> + * 4 or 16 bytes of address (depending on ip version)
> + * 0 or 2 bytes of port (depending on length)
> + */
> +
> + /* MPTCPOPT_REMOVE_ADDR
> + * 0: 4MSB=subtype, 0000
> + * 1: Address ID
> + * Additional bytes: More address IDs (depending on length)
> + */
> +
> + /* MPTCPOPT_MP_PRIO
> + * 0: 4MSB=subtype, 000, 1LSB=Backup
> + * 1: Address ID (optional, current addr implied if not present)
> + */
> +
> + /* MPTCPOPT_MP_FAIL
> + * 0: 4MSB=subtype, 0000
> + * 1: 0 (Reserved)
> + * 2-9: DSN
> + */
> +
> + /* MPTCPOPT_MP_FASTCLOSE
> + * 0: 4MSB=subtype, 0000
> + * 1: 0 (Reserved)
> + * 2-9: Receiver key
> + */
> + default:
> + break;
> + }
> +}
> +
> +void mptcp_get_options(const struct sk_buff *skb,
> + struct tcp_options_received *opt_rx)
> +{
> + const unsigned char *ptr;
> + const struct tcphdr *th = tcp_hdr(skb);
> + int length = (th->doff * 4) - sizeof(struct tcphdr);
> +
> + ptr = (const unsigned char *)(th + 1);
> +
> + while (length > 0) {
> + int opcode = *ptr++;
> + int opsize;
> +
> + switch (opcode) {
> + case TCPOPT_EOL:
> + return;
> + case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
> + length--;
> + continue;
> + default:
> + opsize = *ptr++;
> + if (opsize < 2) /* "silly options" */
> + return;
> + if (opsize > length)
> + return; /* don't parse partial options */
> + if (opcode == TCPOPT_MPTCP)
> + mptcp_parse_option(ptr, opsize, opt_rx);
> + ptr += opsize - 2;
> + length -= opsize;
> + }
> + }
> +}
> +
> +unsigned int mptcp_syn_options(struct sock *sk, u64 *local_key)
> +{
> + struct subflow_sock *subflow = subflow_sk(sk);
> +
> + if (subflow->request_mptcp) {
> + pr_debug("local_key=%llu", subflow->local_key);
> + *local_key = subflow->local_key;
> + }
> + return subflow->request_mptcp;
> +}
> +
> +unsigned int mptcp_synack_options(struct request_sock *req, u64 *local_key,
> + u64 *remote_key)
> +{
> + struct subflow_request_sock *subflow_req = subflow_rsk(req);
> +
> + if (subflow_req->mp_capable) {
> + *local_key = subflow_req->local_key;
> + *remote_key = subflow_req->remote_key;
> + pr_debug("local_key=%llu", *local_key);
> + pr_debug("remote_key=%llu", *remote_key);
> + }
> + return subflow_req->mp_capable;
> +}
> --
> 2.17.1
>
> _______________________________________________
> mptcp mailing list
> mptcp(a)lists.01.org
> https://lists.01.org/mailman/listinfo/mptcp
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [MPTCP] [RFC PATCH v2 04/19] mptcp: Handle MPTCP TCP options
@ 2018-06-13 0:29 Krystad, Peter
0 siblings, 0 replies; 3+ messages in thread
From: Krystad, Peter @ 2018-06-13 0:29 UTC (permalink / raw)
To: mptcp
[-- Attachment #1: Type: text/plain, Size: 17394 bytes --]
Hi Christoph -
On Thu, 2018-06-07 at 11:53 -0700, Christoph Paasch wrote:
> On 05/06/18 - 16:40:23, Mat Martineau wrote:
> > From: Peter Krystad <peter.krystad(a)intel.com>
> >
> > Signed-off-by: Peter Krystad <peter.krystad(a)intel.com>
> > ---
> > include/linux/tcp.h | 14 ++++
> > include/net/mptcp.h | 49 ++++++++++++
> > include/net/tcp.h | 2 +
> > net/ipv4/tcp_input.c | 15 ++++
> > net/ipv4/tcp_output.c | 72 +++++++++++++++++
> > net/mptcp/Makefile | 2 +-
> > net/mptcp/options.c | 176 ++++++++++++++++++++++++++++++++++++++++++
> > 7 files changed, 329 insertions(+), 1 deletion(-)
> > create mode 100644 net/mptcp/options.c
> >
> > diff --git a/include/linux/tcp.h b/include/linux/tcp.h
> > index 72705eaf4b84..17ecbebf129d 100644
> > --- a/include/linux/tcp.h
> > +++ b/include/linux/tcp.h
> > @@ -104,6 +104,16 @@ struct tcp_options_received {
> > u8 num_sacks; /* Number of SACK blocks */
> > u16 user_mss; /* mss requested by user in ioctl */
> > u16 mss_clamp; /* Maximal mss, negotiated at connection setup */
> > + struct {
> > + u8 mp_capable : 1,
> > + mp_join : 1,
> > + dss : 1,
> > + version : 4;
> > + u8 flags;
> > + u64 sndr_key;
> > + u64 rcvr_key;
> > + } mptcp;
>
> Indentation looks wrong here.
>
> Nit-picking ;-) (because I have a bigger comment further down below)
>
> > +
> > };
> >
> > static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
> > @@ -113,6 +123,7 @@ static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
> > #if IS_ENABLED(CONFIG_SMC)
> > rx_opt->smc_ok = 0;
> > #endif
> > + rx_opt->mptcp.mp_capable = rx_opt->mptcp.mp_join = rx_opt->mptcp.dss = 0;
> > }
> >
> > /* This is the max number of SACKS that we'll generate and process. It's safe
> > @@ -137,6 +148,7 @@ struct tcp_request_sock {
> > * FastOpen it's the seq#
> > * after data-in-SYN.
> > */
> > + bool is_mptcp;
> > };
> >
> > static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
> > @@ -387,6 +399,8 @@ struct tcp_sock {
> > */
> > struct request_sock *fastopen_rsk;
> > u32 *saved_syn;
> > +
> > + bool is_mptcp;
> > };
> >
> > enum tsq_enum {
> > diff --git a/include/net/mptcp.h b/include/net/mptcp.h
> > index 7f7b18b000fe..736febd2a9d4 100644
> > --- a/include/net/mptcp.h
> > +++ b/include/net/mptcp.h
> > @@ -18,6 +18,23 @@
> >
> > #include <linux/tcp.h>
> >
> > +/* MPTCP option subtypes */
> > +
> > +#define MPTCPOPT_MP_CAPABLE 0
> > +#define MPTCPOPT_MP_JOIN 1
> > +#define MPTCPOPT_DSS 2
> > +#define MPTCPOPT_ADD_ADDR 3
> > +#define MPTCPOPT_REMOVE_ADDR 4
> > +#define MPTCPOPT_MP_PRIO 5
> > +#define MPTCPOPT_MP_FAIL 6
> > +#define MPTCPOPT_MP_FASTCLOSE 7
> > +
> > +/* MPTCP handshake flags */
> > +
> > +#define MPTCP_CAP_CHECKSUM_REQD (1 << 7)
> > +#define MPTCP_CAP_EXTENSIBILITY (1 << 6)
> > +#define MPTCP_CAP_HMAC_SHA1 (1 << 0)
> > +
> > /* MPTCP connection sock */
> > struct mptcp_sock {
> > /* inet_connection_sock must be the first member */
> > @@ -30,4 +47,36 @@ static inline struct mptcp_sock *mptcp_sk(const struct sock *sk)
> > return (struct mptcp_sock *)sk;
> > }
> >
> > +#ifdef CONFIG_MPTCP
> > +
> > +void mptcp_parse_option(const unsigned char *ptr, int opsize,
> > + struct tcp_options_received *opt_rx);
> > +unsigned int mptcp_syn_options(struct sock *sk, u64 *local_key);
> > +unsigned int mptcp_synack_options(struct request_sock *req,
> > + u64 *local_key, u64 *remote_key);
> > +
> > +void mptcp_get_options(const struct sk_buff *skb,
> > + struct tcp_options_received *options);
> > +
> > +#else
> > +
> > +static inline void mptcp_parse_option(const unsigned char *ptr, int opsize,
> > + struct tcp_options_received *opt_rx)
> > +{
> > +}
> > +
> > +static inline unsigned int mptcp_syn_options(struct sock *sk, u64 *local_key)
> > +{
> > + return 0;
> > +}
> > +static inline unsigned int mptcp_synack_options(struct request_sock *sk,
> > + u64 *local_key,
> > + u64 *remote_key)
> > +{
> > + return 0;
> > +}
> > +
> > +
> > +
> > +#endif /* CONFIG_MPTCP */
> > #endif /* __NET_MPTCP_H */
> > diff --git a/include/net/tcp.h b/include/net/tcp.h
> > index c8716de4547c..a1d4e744b258 100644
> > --- a/include/net/tcp.h
> > +++ b/include/net/tcp.h
> > @@ -214,6 +214,8 @@ void tcp_time_wait(struct sock *sk, int state, int timeo);
> > #define TCPOLEN_MD5SIG_ALIGNED 20
> > #define TCPOLEN_MSS_ALIGNED 4
> > #define TCPOLEN_EXP_SMC_BASE_ALIGNED 8
> > +#define TCPOLEN_MPTCP_MPC_SYN 12
> > +#define TCPOLEN_MPTCP_MPC_SYNACK 20
> >
> > /* Flags in tp->nonagle */
> > #define TCP_NAGLE_OFF 1 /* Nagle's algo is disabled */
> > diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> > index 355d3dffd021..bdc36001ce90 100644
> > --- a/net/ipv4/tcp_input.c
> > +++ b/net/ipv4/tcp_input.c
> > @@ -78,6 +78,7 @@
> > #include <linux/errqueue.h>
> > #include <trace/events/tcp.h>
> > #include <linux/static_key.h>
> > +#include <net/mptcp.h>
> >
> > int sysctl_tcp_max_orphans __read_mostly = NR_FILE;
> >
> > @@ -3842,6 +3843,10 @@ void tcp_parse_options(const struct net *net,
> > */
> > break;
> > #endif
> > + case TCPOPT_MPTCP:
> > + mptcp_parse_option(ptr, opsize, opt_rx);
> > + break;
> > +
> > case TCPOPT_FASTOPEN:
> > tcp_parse_fastopen_option(
> > opsize - TCPOLEN_FASTOPEN_BASE,
> > @@ -5763,6 +5768,15 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
> > tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
> > tcp_initialize_rcv_mss(sk);
> >
> > + // @@ could use a callout here
> > + if (tp->is_mptcp) {
> > + struct subflow_sock *subflow = subflow_sk(sk);
> > + if (subflow->request_mptcp && tp->rx_opt.mptcp.mp_capable) {
> > + subflow->mp_capable = 1;
> > + subflow->remote_key = tp->rx_opt.mptcp.sndr_key;
> > + }
> > + }
> > +
> > /* Remember, tcp_poll() does not lock socket!
> > * Change state from SYN-SENT only after copied_seq
> > * is initialized. */
> > @@ -6339,6 +6353,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
> >
> > tcp_rsk(req)->af_specific = af_ops;
> > tcp_rsk(req)->ts_off = 0;
> > + tcp_rsk(req)->is_mptcp = 0;
> >
> > tcp_clear_options(&tmp_opt);
> > tmp_opt.mss_clamp = af_ops->mss_clamp;
> > diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
> > index 8e08b409c71e..fc49d80d3ba7 100644
> > --- a/net/ipv4/tcp_output.c
> > +++ b/net/ipv4/tcp_output.c
> > @@ -37,6 +37,7 @@
> > #define pr_fmt(fmt) "TCP: " fmt
> >
> > #include <net/tcp.h>
> > +#include <net/mptcp.h>
> >
> > #include <linux/compiler.h>
> > #include <linux/gfp.h>
> > @@ -411,6 +412,8 @@ static inline bool tcp_urg_mode(const struct tcp_sock *tp)
> > #define OPTION_WSCALE (1 << 3)
> > #define OPTION_FAST_OPEN_COOKIE (1 << 8)
> > #define OPTION_SMC (1 << 9)
> > +#define OPTION_MPTCP (1 << 10)
> > +#define OPTION_MPTCP_ACK (1 << 11)
> >
> > static void smc_options_write(__be32 *ptr, u16 *options)
> > {
> > @@ -436,6 +439,8 @@ struct tcp_out_options {
> > __u8 *hash_location; /* temporary pointer, overloaded */
> > __u32 tsval, tsecr; /* need to include OPTION_TS */
> > struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */
> > + u64 sndr_key;
> > + u64 rcvr_key;
> > };
> >
> > /* Write previously computed TCP options to the packet.
> > @@ -546,6 +551,29 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
> > }
> >
> > smc_options_write(ptr, &options);
> > +
> > + if (OPTION_MPTCP & options) {
> > + u8 *p = (u8 *)ptr;
> > + *p++ = 0x1e; // TCP option: Multipath TCP
> > + *p++ = 12; // length
> > + *p++ = 0; // subtype=MP_CAPABLE | version=0
> > + *p++ = 0x1; // flags=HMAC-SHA1
> > + memcpy(p, &opts->sndr_key, 8);
> > + pr_debug("tcp_options_write: opts->sndr_key=%llu", opts->sndr_key);
> > + }
> > +
> > + if (OPTION_MPTCP_ACK & options) {
> > + u8 *p = (u8 *)ptr;
> > + *p++ = 0x1e; // TCP option: Multipath TCP
> > + *p++ = 20; // length
> > + *p++ = 0; // subtype=MP_CAPABLE | version=0
> > + *p++ = 0x1; // flags=HMAC-SHA1
> > + memcpy(p, &opts->sndr_key, 8);
> > + pr_debug("tcp_options_write: opts->sndr_key=%llu", opts->sndr_key);
> > + p += 8;
> > + memcpy(p, &opts->rcvr_key, 8);
> > + pr_debug("tcp_options_write: opts->rcvr_key=%llu", opts->rcvr_key);
> > + }
> > }
> >
> > static void smc_set_option(const struct tcp_sock *tp,
> > @@ -649,6 +677,15 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
> >
> > smc_set_option(tp, opts, &remaining);
> >
> > + if (tp->is_mptcp) {
> > + u64 local_key;
> > + if (mptcp_syn_options(sk, &local_key)) {
> > + opts->options |= OPTION_MPTCP;
> > + opts->sndr_key = local_key;
> > + remaining -= TCPOLEN_MPTCP_MPC_SYN;
> > + }
> > + }
> > +
> > return MAX_TCP_OPTION_SPACE - remaining;
> > }
> >
> > @@ -709,6 +746,18 @@ static unsigned int tcp_synack_options(const struct sock *sk,
> > remaining -= need;
> > }
> > }
> > + if (tcp_rsk(req)->is_mptcp) {
> > + u64 local_key;
> > + u64 remote_key;
> > + if (mptcp_synack_options(req, &local_key, &remote_key)) {
> > + if (remaining >= TCPOLEN_MPTCP_MPC_SYNACK) {
> > + opts->options |= OPTION_MPTCP_ACK;
> > + opts->sndr_key = local_key;
> > + opts->rcvr_key = remote_key;
> > + remaining -= TCPOLEN_MPTCP_MPC_SYNACK;
> > + }
> > + }
> > + }
> >
> > smc_set_option_cond(tcp_sk(sk), ireq, opts, &remaining);
> >
> > @@ -757,6 +806,29 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb
> > opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK;
> > }
> >
> > + if (tp->is_mptcp) {
> > + struct subflow_sock *subflow = subflow_sk(sk);
> > + pr_debug("tcp_established_options: subflow=%p", subflow);
> > + if (subflow->mp_capable) {
> > + const unsigned int remaining = MAX_TCP_OPTION_SPACE - size;
> > + pr_debug("tcp_established_options: remaining=%d", remaining);
> > + if (!subflow->fourth_ack) {
> > + pr_debug("tcp_established_options: OPTION_MPTCP_ACK");
> > + if (remaining >= 20) {
> > + opts->options |= OPTION_MPTCP_ACK;
> > + opts->sndr_key = subflow->local_key;
> > + opts->rcvr_key = subflow->remote_key;
> > + size += 20;
> > + }
> > + subflow->fourth_ack = 1;
> > + // @@ also this is where first DSS goes in?
> > + }
> > + else {
> > + pr_debug("tcp_established_options: OPTION_MPTCP_DSS");
> > + // @@ send DSS based on remaining
> > + }
> > + }
> > + }
>
> You would need to have this code before the SACK-code. Because otherwise
> SACK might fill up the available space and you will end up not writing the
> DSS-option.
>
> This also implies that you need to check whether at all there is space for a
> SACK-block.
>
This is addressed in patch 16 of this set. I'll clean up the indenting.
Peter.
> Christoph
>
> > return size;
> > }
> >
> > diff --git a/net/mptcp/Makefile b/net/mptcp/Makefile
> > index 5624e7d51d48..2bd18e3b9fda 100644
> > --- a/net/mptcp/Makefile
> > +++ b/net/mptcp/Makefile
> > @@ -1,3 +1,3 @@
> > obj-$(CONFIG_MPTCP) += mptcp.o
> >
> > -mptcp-y := protocol.o
> > +mptcp-y := protocol.o options.o
> > diff --git a/net/mptcp/options.c b/net/mptcp/options.c
> > new file mode 100644
> > index 000000000000..2ef7ba20b33b
> > --- /dev/null
> > +++ b/net/mptcp/options.c
> > @@ -0,0 +1,176 @@
> > +/*
> > + * Multipath TCP
> > + *
> > + * Copyright (c) 2017, Intel Corporation.
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> > + * more details.
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <net/tcp.h>
> > +#include <net/mptcp.h>
> > +
> > +void mptcp_parse_option(const unsigned char *ptr, int opsize,
> > + struct tcp_options_received *opt_rx)
> > +{
> > + u8 subtype;
> > + u64 *p;
> > +
> > + opsize -= 2;
> > + subtype = *ptr++;
> > +
> > + /* MPTCPOPT_MP_CAPABLE
> > + * 0: 4MSB=subtype, 4LSB=version
> > + * 1: Handshake flags
> > + * 2-9: Sender key
> > + * 10-17: Receiver key (optional)
> > + */
> > + switch (subtype & 0xF0) {
> > + case 0x00:
> > + pr_debug("MP_CAPABLE");
> > + pr_debug("flags=%02x", *ptr);
> > + opt_rx->mptcp.mp_capable = 1;
> > + opt_rx->mptcp.version = subtype & 0x0F;
> > + opt_rx->mptcp.flags = *ptr++;
> > + p = (u64 *)ptr;
> > + pr_debug("sndr_key=%llu", *p);
> > + opt_rx->mptcp.sndr_key = *p++;
> > + if (opsize > 10) {
> > + pr_debug("rcvr_key=%llu", *p);
> > + opt_rx->mptcp.rcvr_key = *p++;
> > + }
> > + break;
> > +
> > + /* MPTCPOPT_MP_JOIN
> > + *
> > + * Initial SYN
> > + * 0: 4MSB=subtype, 000, 1LSB=Backup
> > + * 1: Address ID
> > + * 2-5: Receiver token
> > + * 6-9: Sender random number
> > + *
> > + * SYN/ACK response
> > + * 0: 4MSB=subtype, 000, 1LSB=Backup
> > + * 1: Address ID
> > + * 2-9: Sender truncated HMAC
> > + * 10-13: Sender random number
> > + *
> > + * Third ACK
> > + * 0: 4MSB=subtype, 0000
> > + * 1: 0 (Reserved)
> > + * 2-21: Sender HMAC
> > + */
> > +
> > + /* MPTCPOPT_DSS
> > + * 0: 4MSB=subtype, 0000
> > + * 1: 3MSB=0, F=Data FIN, m=DSN length, M=has DSN/SSN/DLL/checksum,
> > + * a=DACK length, A=has DACK
> > + * 0, 4, or 8 bytes of DACK (depending on A/a)
> > + * 0, 4, or 8 bytes of DSN (depending on M/m)
> > + * 0 or 4 bytes of SSN (depending on M)
> > + * 0 or 2 bytes of DLL (depending on M)
> > + * 0 or 2 bytes of checksum (depending on M)
> > + */
> > + case 0x20:
> > + pr_debug("DSS");
> > + opt_rx->mptcp.dss = 1;
> > + break;
> > +
> > + /* MPTCPOPT_ADD_ADDR
> > + * 0: 4MSB=subtype, 4LSB=IP version (4 or 6)
> > + * 1: Address ID
> > + * 4 or 16 bytes of address (depending on ip version)
> > + * 0 or 2 bytes of port (depending on length)
> > + */
> > +
> > + /* MPTCPOPT_REMOVE_ADDR
> > + * 0: 4MSB=subtype, 0000
> > + * 1: Address ID
> > + * Additional bytes: More address IDs (depending on length)
> > + */
> > +
> > + /* MPTCPOPT_MP_PRIO
> > + * 0: 4MSB=subtype, 000, 1LSB=Backup
> > + * 1: Address ID (optional, current addr implied if not present)
> > + */
> > +
> > + /* MPTCPOPT_MP_FAIL
> > + * 0: 4MSB=subtype, 0000
> > + * 1: 0 (Reserved)
> > + * 2-9: DSN
> > + */
> > +
> > + /* MPTCPOPT_MP_FASTCLOSE
> > + * 0: 4MSB=subtype, 0000
> > + * 1: 0 (Reserved)
> > + * 2-9: Receiver key
> > + */
> > + default:
> > + break;
> > + }
> > +}
> > +
> > +void mptcp_get_options(const struct sk_buff *skb,
> > + struct tcp_options_received *opt_rx)
> > +{
> > + const unsigned char *ptr;
> > + const struct tcphdr *th = tcp_hdr(skb);
> > + int length = (th->doff * 4) - sizeof(struct tcphdr);
> > +
> > + ptr = (const unsigned char *)(th + 1);
> > +
> > + while (length > 0) {
> > + int opcode = *ptr++;
> > + int opsize;
> > +
> > + switch (opcode) {
> > + case TCPOPT_EOL:
> > + return;
> > + case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
> > + length--;
> > + continue;
> > + default:
> > + opsize = *ptr++;
> > + if (opsize < 2) /* "silly options" */
> > + return;
> > + if (opsize > length)
> > + return; /* don't parse partial options */
> > + if (opcode == TCPOPT_MPTCP)
> > + mptcp_parse_option(ptr, opsize, opt_rx);
> > + ptr += opsize - 2;
> > + length -= opsize;
> > + }
> > + }
> > +}
> > +
> > +unsigned int mptcp_syn_options(struct sock *sk, u64 *local_key)
> > +{
> > + struct subflow_sock *subflow = subflow_sk(sk);
> > +
> > + if (subflow->request_mptcp) {
> > + pr_debug("local_key=%llu", subflow->local_key);
> > + *local_key = subflow->local_key;
> > + }
> > + return subflow->request_mptcp;
> > +}
> > +
> > +unsigned int mptcp_synack_options(struct request_sock *req, u64 *local_key,
> > + u64 *remote_key)
> > +{
> > + struct subflow_request_sock *subflow_req = subflow_rsk(req);
> > +
> > + if (subflow_req->mp_capable) {
> > + *local_key = subflow_req->local_key;
> > + *remote_key = subflow_req->remote_key;
> > + pr_debug("local_key=%llu", *local_key);
> > + pr_debug("remote_key=%llu", *remote_key);
> > + }
> > + return subflow_req->mp_capable;
> > +}
> > --
> > 2.17.1
> >
> > _______________________________________________
> > mptcp mailing list
> > mptcp(a)lists.01.org
> > https://lists.01.org/mailman/listinfo/mptcp
>
> _______________________________________________
> mptcp mailing list
> mptcp(a)lists.01.org
> https://lists.01.org/mailman/listinfo/mptcp
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2018-06-13 0:29 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-06-13 0:29 [MPTCP] [RFC PATCH v2 04/19] mptcp: Handle MPTCP TCP options Krystad, Peter
-- strict thread matches above, loose matches on Subject: below --
2018-06-07 18:53 Christoph Paasch
2018-06-05 23:40 Mat Martineau
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.