summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Paasch <cpaasch@apple.com>2020-05-14 08:53:03 -0700
committerDavid S. Miller <davem@davemloft.net>2020-05-16 13:51:10 -0700
commita0c1d0eafd1ef1ada3b588ea205e5bc37ae0d8d9 (patch)
tree9e6c4e1406a00559b1dd4ef04cf502d65e5cb3e7
parent9efd6a3cecdde984d67e63d17fe6af53c7c50968 (diff)
downloadlinux-a0c1d0eafd1ef1ada3b588ea205e5bc37ae0d8d9.tar.bz2
mptcp: Use 32-bit DATA_ACK when possible
RFC8684 allows to send 32-bit DATA_ACKs as long as the peer is not sending 64-bit data-sequence numbers. The 64-bit DSN is only there for extreme scenarios when a very high throughput subflow is combined with a long-RTT subflow such that the high-throughput subflow wraps around the 32-bit sequence number space within an RTT of the high-RTT subflow. It is thus a rare scenario and we should try to use the 32-bit DATA_ACK instead as long as possible. It allows to reduce the TCP-option overhead by 4 bytes, thus makes space for an additional SACK-block. It also makes tcpdumps much easier to read when the DSN and DATA_ACK are both either 32 or 64-bit. Signed-off-by: Christoph Paasch <cpaasch@apple.com> Reviewed-by: Matthieu Baerts <matthieu.baerts@tessares.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/mptcp.h5
-rw-r--r--net/mptcp/options.c33
-rw-r--r--net/mptcp/protocol.h1
-rw-r--r--net/mptcp/subflow.c2
4 files changed, 31 insertions, 10 deletions
diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index c4a6ef4ba35b..46d0487d2b22 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -16,7 +16,10 @@ struct seq_file;
/* MPTCP sk_buff extension data */
struct mptcp_ext {
- u64 data_ack;
+ union {
+ u64 data_ack;
+ u32 data_ack32;
+ };
u64 data_seq;
u32 subflow_seq;
u16 data_len;
diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index 45497af23906..ece6f92cf7d1 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -516,7 +516,16 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
return ret;
}
- ack_size = TCPOLEN_MPTCP_DSS_ACK64;
+ if (subflow->use_64bit_ack) {
+ ack_size = TCPOLEN_MPTCP_DSS_ACK64;
+ opts->ext_copy.data_ack = msk->ack_seq;
+ opts->ext_copy.ack64 = 1;
+ } else {
+ ack_size = TCPOLEN_MPTCP_DSS_ACK32;
+ opts->ext_copy.data_ack32 = (uint32_t)(msk->ack_seq);
+ opts->ext_copy.ack64 = 0;
+ }
+ opts->ext_copy.use_ack = 1;
/* Add kind/length/subtype/flag overhead if mapping is not populated */
if (dss_size == 0)
@@ -524,10 +533,6 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
dss_size += ack_size;
- opts->ext_copy.data_ack = msk->ack_seq;
- opts->ext_copy.ack64 = 1;
- opts->ext_copy.use_ack = 1;
-
*size = ALIGN(dss_size, 4);
return true;
}
@@ -986,8 +991,13 @@ mp_capable_done:
u8 flags = 0;
if (mpext->use_ack) {
- len += TCPOLEN_MPTCP_DSS_ACK64;
- flags = MPTCP_DSS_HAS_ACK | MPTCP_DSS_ACK64;
+ flags = MPTCP_DSS_HAS_ACK;
+ if (mpext->ack64) {
+ len += TCPOLEN_MPTCP_DSS_ACK64;
+ flags |= MPTCP_DSS_ACK64;
+ } else {
+ len += TCPOLEN_MPTCP_DSS_ACK32;
+ }
}
if (mpext->use_map) {
@@ -1004,8 +1014,13 @@ mp_capable_done:
*ptr++ = mptcp_option(MPTCPOPT_DSS, len, 0, flags);
if (mpext->use_ack) {
- put_unaligned_be64(mpext->data_ack, ptr);
- ptr += 2;
+ if (mpext->ack64) {
+ put_unaligned_be64(mpext->data_ack, ptr);
+ ptr += 2;
+ } else {
+ put_unaligned_be32(mpext->data_ack32, ptr);
+ ptr += 1;
+ }
}
if (mpext->use_map) {
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index e4ca6320ce76..f5adca93e8fb 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -290,6 +290,7 @@ struct mptcp_subflow_context {
data_avail : 1,
rx_eof : 1,
data_fin_tx_enable : 1,
+ use_64bit_ack : 1, /* Set when we received a 64-bit DSN */
can_ack : 1; /* only after processing the remote a key */
u64 data_fin_tx_seq;
u32 remote_nonce;
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index 53c75b0e5dce..0020d356233d 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -667,9 +667,11 @@ static enum mapping_status get_mapping_status(struct sock *ssk)
if (!mpext->dsn64) {
map_seq = expand_seq(subflow->map_seq, subflow->map_data_len,
mpext->data_seq);
+ subflow->use_64bit_ack = 0;
pr_debug("expanded seq=%llu", subflow->map_seq);
} else {
map_seq = mpext->data_seq;
+ subflow->use_64bit_ack = 1;
}
if (subflow->map_valid) {