Skip to content

Commit

Permalink
mptcp: fallback to TCP after SYN+MPC drops
Browse files Browse the repository at this point in the history
Some middleboxes might be nasty with MPTCP, and decide to drop packets
with MPTCP options, instead of just dropping the MPTCP options (or
letting them pass...).

In this case, it sounds better to fallback to "plain" TCP, and try
again.

Closes: #477
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
  • Loading branch information
matttbe committed Sep 11, 2024
1 parent 829bf60 commit 9bac5af
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 0 deletions.
4 changes: 4 additions & 0 deletions include/net/mptcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ static inline __be32 mptcp_reset_option(const struct sk_buff *skb)

return htonl(0u);
}

void mptcp_active_detect_blackhole(struct sock *sk, bool expired);
#else

static inline void mptcp_init(void)
Expand Down Expand Up @@ -307,6 +309,8 @@ static inline struct request_sock *mptcp_subflow_reqsk_alloc(const struct reques
}

static inline __be32 mptcp_reset_option(const struct sk_buff *skb) { return htonl(0u); }

static inline void mptcp_active_detect_blackhole(struct sock *sk, bool expired) { }
#endif /* CONFIG_MPTCP */

#if IS_ENABLED(CONFIG_MPTCP_IPV6)
Expand Down
1 change: 1 addition & 0 deletions net/ipv4/tcp_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ static int tcp_write_timeout(struct sock *sk)
expired = retransmits_timed_out(sk, retry_until,
READ_ONCE(icsk->icsk_user_timeout));
tcp_fastopen_active_detect_blackhole(sk, expired);
mptcp_active_detect_blackhole(sk, expired);

if (BPF_SOCK_OPS_TEST_FLAG(tp, BPF_SOCK_OPS_RTO_CB_FLAG))
tcp_call_bpf_3arg(sk, BPF_SOCK_OPS_RTO_CB,
Expand Down
20 changes: 20 additions & 0 deletions net/mptcp/ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <net/netns/generic.h>

#include "protocol.h"
#include "mib.h"

#define MPTCP_SYSCTL_PATH "net/mptcp"

Expand Down Expand Up @@ -277,6 +278,25 @@ static void mptcp_pernet_del_table(struct mptcp_pernet *pernet) {}

#endif /* CONFIG_SYSCTL */

/* Check the number of retransmissions, and fallback to TCP if needed */
void mptcp_active_detect_blackhole(struct sock *ssk, bool expired)
{
struct mptcp_subflow_context *subflow;
u32 timeouts;

if (!sk_is_mptcp(ssk))
return;

timeouts = inet_csk(ssk)->icsk_retransmits;
subflow = mptcp_subflow_ctx(ssk);

if (subflow->request_mptcp && ssk->sk_state == TCP_SYN_SENT &&
(timeouts == 2 || (timeouts < 2 && expired))) {
MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPCAPABLEACTIVEDROP);
mptcp_subflow_early_fallback(mptcp_sk(subflow->conn), subflow);
}
}

static int __net_init mptcp_net_init(struct net *net)
{
struct mptcp_pernet *pernet = mptcp_get_pernet(net);
Expand Down
1 change: 1 addition & 0 deletions net/mptcp/mib.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ static const struct snmp_mib mptcp_snmp_list[] = {
SNMP_MIB_ITEM("MPCapableACKRX", MPTCP_MIB_MPCAPABLEPASSIVEACK),
SNMP_MIB_ITEM("MPCapableFallbackACK", MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK),
SNMP_MIB_ITEM("MPCapableFallbackSYNACK", MPTCP_MIB_MPCAPABLEACTIVEFALLBACK),
SNMP_MIB_ITEM("MPCapableSYNTXDrop", MPTCP_MIB_MPCAPABLEACTIVEDROP),
SNMP_MIB_ITEM("MPFallbackTokenInit", MPTCP_MIB_TOKENFALLBACKINIT),
SNMP_MIB_ITEM("MPTCPRetrans", MPTCP_MIB_RETRANSSEGS),
SNMP_MIB_ITEM("MPJoinNoTokenFound", MPTCP_MIB_JOINNOTOKEN),
Expand Down
1 change: 1 addition & 0 deletions net/mptcp/mib.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ enum linux_mptcp_mib_field {
MPTCP_MIB_MPCAPABLEPASSIVEACK, /* Received third ACK with MP_CAPABLE */
MPTCP_MIB_MPCAPABLEPASSIVEFALLBACK,/* Server-side fallback during 3-way handshake */
MPTCP_MIB_MPCAPABLEACTIVEFALLBACK, /* Client-side fallback during 3-way handshake */
MPTCP_MIB_MPCAPABLEACTIVEDROP, /* Client-side fallback due to a MPC drop */
MPTCP_MIB_TOKENFALLBACKINIT, /* Could not init/allocate token */
MPTCP_MIB_RETRANSSEGS, /* Segments retransmitted at the MPTCP-level */
MPTCP_MIB_JOINNOTOKEN, /* Received MP_JOIN but the token was not found */
Expand Down

0 comments on commit 9bac5af

Please sign in to comment.