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>
This commit is contained in:
Christoph Paasch 2020-05-14 08:53:03 -07:00 committed by David S. Miller
parent 9efd6a3cec
commit a0c1d0eafd
4 changed files with 31 additions and 10 deletions

View File

@ -16,7 +16,10 @@ struct seq_file;
/* MPTCP sk_buff extension data */ /* MPTCP sk_buff extension data */
struct mptcp_ext { struct mptcp_ext {
union {
u64 data_ack; u64 data_ack;
u32 data_ack32;
};
u64 data_seq; u64 data_seq;
u32 subflow_seq; u32 subflow_seq;
u16 data_len; u16 data_len;

View File

@ -516,7 +516,16 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
return ret; return ret;
} }
if (subflow->use_64bit_ack) {
ack_size = TCPOLEN_MPTCP_DSS_ACK64; 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 */ /* Add kind/length/subtype/flag overhead if mapping is not populated */
if (dss_size == 0) 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; 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); *size = ALIGN(dss_size, 4);
return true; return true;
} }
@ -986,8 +991,13 @@ void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
u8 flags = 0; u8 flags = 0;
if (mpext->use_ack) { if (mpext->use_ack) {
flags = MPTCP_DSS_HAS_ACK;
if (mpext->ack64) {
len += TCPOLEN_MPTCP_DSS_ACK64; len += TCPOLEN_MPTCP_DSS_ACK64;
flags = MPTCP_DSS_HAS_ACK | MPTCP_DSS_ACK64; flags |= MPTCP_DSS_ACK64;
} else {
len += TCPOLEN_MPTCP_DSS_ACK32;
}
} }
if (mpext->use_map) { if (mpext->use_map) {
@ -1004,8 +1014,13 @@ void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
*ptr++ = mptcp_option(MPTCPOPT_DSS, len, 0, flags); *ptr++ = mptcp_option(MPTCPOPT_DSS, len, 0, flags);
if (mpext->use_ack) { if (mpext->use_ack) {
if (mpext->ack64) {
put_unaligned_be64(mpext->data_ack, ptr); put_unaligned_be64(mpext->data_ack, ptr);
ptr += 2; ptr += 2;
} else {
put_unaligned_be32(mpext->data_ack32, ptr);
ptr += 1;
}
} }
if (mpext->use_map) { if (mpext->use_map) {

View File

@ -290,6 +290,7 @@ struct mptcp_subflow_context {
data_avail : 1, data_avail : 1,
rx_eof : 1, rx_eof : 1,
data_fin_tx_enable : 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 */ can_ack : 1; /* only after processing the remote a key */
u64 data_fin_tx_seq; u64 data_fin_tx_seq;
u32 remote_nonce; u32 remote_nonce;

View File

@ -667,9 +667,11 @@ static enum mapping_status get_mapping_status(struct sock *ssk)
if (!mpext->dsn64) { if (!mpext->dsn64) {
map_seq = expand_seq(subflow->map_seq, subflow->map_data_len, map_seq = expand_seq(subflow->map_seq, subflow->map_data_len,
mpext->data_seq); mpext->data_seq);
subflow->use_64bit_ack = 0;
pr_debug("expanded seq=%llu", subflow->map_seq); pr_debug("expanded seq=%llu", subflow->map_seq);
} else { } else {
map_seq = mpext->data_seq; map_seq = mpext->data_seq;
subflow->use_64bit_ack = 1;
} }
if (subflow->map_valid) { if (subflow->map_valid) {