Merge branch 'mptcp-track-more-fallback-cases'

Matthieu Baerts says:

====================
mptcp: track more fallback cases

This series has two patches linked to fallback to TCP:

- Patch 1: additional MIB counters for remaining error code paths around
  fallback

- Patch 2: remove dedicated pr_debug() linked to fallback now that
  everything should be covered by dedicated MIB counters.
====================

Link: https://patch.msgid.link/20250723-net-next-mptcp-track-fallbacks-v1-0-a83cce08f2d5@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2025-07-25 11:29:07 -07:00
7 changed files with 62 additions and 54 deletions
+2 -2
View File
@@ -533,9 +533,9 @@ void mptcp_active_detect_blackhole(struct sock *ssk, bool expired)
to_max = mptcp_get_pernet(net)->syn_retrans_before_tcp_fallback;
if (timeouts == to_max || (timeouts < to_max && expired)) {
MPTCP_INC_STATS(net, MPTCP_MIB_MPCAPABLEACTIVEDROP);
subflow->mpc_drop = 1;
mptcp_subflow_early_fallback(mptcp_sk(subflow->conn), subflow);
mptcp_early_fallback(mptcp_sk(subflow->conn), subflow,
MPTCP_MIB_MPCAPABLEACTIVEDROP);
}
}
+5
View File
@@ -80,6 +80,11 @@ static const struct snmp_mib mptcp_snmp_list[] = {
SNMP_MIB_ITEM("RcvWndConflict", MPTCP_MIB_RCVWNDCONFLICT),
SNMP_MIB_ITEM("MPCurrEstab", MPTCP_MIB_CURRESTAB),
SNMP_MIB_ITEM("Blackhole", MPTCP_MIB_BLACKHOLE),
SNMP_MIB_ITEM("MPCapableDataFallback", MPTCP_MIB_MPCAPABLEDATAFALLBACK),
SNMP_MIB_ITEM("MD5SigFallback", MPTCP_MIB_MD5SIGFALLBACK),
SNMP_MIB_ITEM("DssFallback", MPTCP_MIB_DSSFALLBACK),
SNMP_MIB_ITEM("SimultConnectFallback", MPTCP_MIB_SIMULTCONNFALLBACK),
SNMP_MIB_ITEM("FallbackFailed", MPTCP_MIB_FALLBACKFAILED),
SNMP_MIB_SENTINEL
};
+7
View File
@@ -81,6 +81,13 @@ enum linux_mptcp_mib_field {
MPTCP_MIB_RCVWNDCONFLICT, /* Conflict with while updating msk rcv wnd */
MPTCP_MIB_CURRESTAB, /* Current established MPTCP connections */
MPTCP_MIB_BLACKHOLE, /* A blackhole has been detected */
MPTCP_MIB_MPCAPABLEDATAFALLBACK, /* Missing DSS/MPC+data on first
* established packet
*/
MPTCP_MIB_MD5SIGFALLBACK, /* Conflicting TCP option enabled */
MPTCP_MIB_DSSFALLBACK, /* Bad or missing DSS */
MPTCP_MIB_SIMULTCONNFALLBACK, /* Simultaneous connect */
MPTCP_MIB_FALLBACKFAILED, /* Can't fallback due to msk status */
__MPTCP_MIB_MAX
};
+3 -2
View File
@@ -978,9 +978,10 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,
if (subflow->mp_join)
goto reset;
subflow->mp_capable = 0;
if (!mptcp_try_fallback(ssk))
if (!mptcp_try_fallback(ssk, MPTCP_MIB_MPCAPABLEDATAFALLBACK)) {
MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_FALLBACKFAILED);
goto reset;
pr_fallback(msk);
}
return false;
}
+30 -15
View File
@@ -68,6 +68,26 @@ static const struct proto_ops *mptcp_fallback_tcp_ops(const struct sock *sk)
return &inet_stream_ops;
}
bool __mptcp_try_fallback(struct mptcp_sock *msk, int fb_mib)
{
struct net *net = sock_net((struct sock *)msk);
if (__mptcp_check_fallback(msk))
return true;
spin_lock_bh(&msk->fallback_lock);
if (!msk->allow_infinite_fallback) {
spin_unlock_bh(&msk->fallback_lock);
return false;
}
msk->allow_subflows = false;
set_bit(MPTCP_FALLBACK_DONE, &msk->flags);
__MPTCP_INC_STATS(net, fb_mib);
spin_unlock_bh(&msk->fallback_lock);
return true;
}
static int __mptcp_socket_create(struct mptcp_sock *msk)
{
struct mptcp_subflow_context *subflow;
@@ -561,10 +581,7 @@ static bool mptcp_check_data_fin(struct sock *sk)
static void mptcp_dss_corruption(struct mptcp_sock *msk, struct sock *ssk)
{
if (mptcp_try_fallback(ssk)) {
MPTCP_INC_STATS(sock_net(ssk),
MPTCP_MIB_DSSCORRUPTIONFALLBACK);
} else {
if (!mptcp_try_fallback(ssk, MPTCP_MIB_DSSCORRUPTIONFALLBACK)) {
MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_DSSCORRUPTIONRESET);
mptcp_subflow_reset(ssk);
}
@@ -1143,14 +1160,13 @@ static void mptcp_update_infinite_map(struct mptcp_sock *msk,
mpext->infinite_map = 1;
mpext->data_len = 0;
if (!mptcp_try_fallback(ssk)) {
if (!mptcp_try_fallback(ssk, MPTCP_MIB_INFINITEMAPTX)) {
MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_FALLBACKFAILED);
mptcp_subflow_reset(ssk);
return;
}
MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_INFINITEMAPTX);
mptcp_subflow_ctx(ssk)->send_infinite_map = 0;
pr_fallback(msk);
}
#define MPTCP_MAX_GSO_SIZE (GSO_LEGACY_MAX_SIZE - (MAX_TCP_HEADER + 1))
@@ -3689,16 +3705,15 @@ static int mptcp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
* TCP option space.
*/
if (rcu_access_pointer(tcp_sk(ssk)->md5sig_info))
mptcp_subflow_early_fallback(msk, subflow);
mptcp_early_fallback(msk, subflow, MPTCP_MIB_MD5SIGFALLBACK);
#endif
if (subflow->request_mptcp) {
if (mptcp_active_should_disable(sk)) {
MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPCAPABLEACTIVEDISABLED);
mptcp_subflow_early_fallback(msk, subflow);
} else if (mptcp_token_new_connect(ssk) < 0) {
MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_TOKENFALLBACKINIT);
mptcp_subflow_early_fallback(msk, subflow);
}
if (mptcp_active_should_disable(sk))
mptcp_early_fallback(msk, subflow,
MPTCP_MIB_MPCAPABLEACTIVEDISABLED);
else if (mptcp_token_new_connect(ssk) < 0)
mptcp_early_fallback(msk, subflow,
MPTCP_MIB_TOKENFALLBACKINIT);
}
WRITE_ONCE(msk->write_seq, subflow->idsn);
+8 -26
View File
@@ -1223,24 +1223,6 @@ static inline bool mptcp_check_fallback(const struct sock *sk)
return __mptcp_check_fallback(msk);
}
static inline bool __mptcp_try_fallback(struct mptcp_sock *msk)
{
if (__mptcp_check_fallback(msk)) {
pr_debug("TCP fallback already done (msk=%p)\n", msk);
return true;
}
spin_lock_bh(&msk->fallback_lock);
if (!msk->allow_infinite_fallback) {
spin_unlock_bh(&msk->fallback_lock);
return false;
}
msk->allow_subflows = false;
set_bit(MPTCP_FALLBACK_DONE, &msk->flags);
spin_unlock_bh(&msk->fallback_lock);
return true;
}
static inline bool __mptcp_has_initial_subflow(const struct mptcp_sock *msk)
{
struct sock *ssk = READ_ONCE(msk->first);
@@ -1250,14 +1232,16 @@ static inline bool __mptcp_has_initial_subflow(const struct mptcp_sock *msk)
TCPF_SYN_RECV | TCPF_LISTEN));
}
static inline bool mptcp_try_fallback(struct sock *ssk)
bool __mptcp_try_fallback(struct mptcp_sock *msk, int fb_mib);
static inline bool mptcp_try_fallback(struct sock *ssk, int fb_mib)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
struct sock *sk = subflow->conn;
struct mptcp_sock *msk;
msk = mptcp_sk(sk);
if (!__mptcp_try_fallback(msk))
if (!__mptcp_try_fallback(msk, fb_mib))
return false;
if (READ_ONCE(msk->snd_data_fin_enable) && !(ssk->sk_shutdown & SEND_SHUTDOWN)) {
gfp_t saved_allocation = ssk->sk_allocation;
@@ -1273,14 +1257,12 @@ static inline bool mptcp_try_fallback(struct sock *ssk)
return true;
}
#define pr_fallback(a) pr_debug("%s:fallback to TCP (msk=%p)\n", __func__, a)
static inline void mptcp_subflow_early_fallback(struct mptcp_sock *msk,
struct mptcp_subflow_context *subflow)
static inline void mptcp_early_fallback(struct mptcp_sock *msk,
struct mptcp_subflow_context *subflow,
int fb_mib)
{
pr_fallback(msk);
subflow->request_mptcp = 0;
WARN_ON_ONCE(!__mptcp_try_fallback(msk));
WARN_ON_ONCE(!__mptcp_try_fallback(msk, fb_mib));
}
static inline bool mptcp_check_infinite_map(struct sk_buff *skb)
+7 -9
View File
@@ -544,12 +544,13 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
mptcp_get_options(skb, &mp_opt);
if (subflow->request_mptcp) {
if (!(mp_opt.suboptions & OPTION_MPTCP_MPC_SYNACK)) {
if (!mptcp_try_fallback(sk))
if (!mptcp_try_fallback(sk,
MPTCP_MIB_MPCAPABLEACTIVEFALLBACK)) {
MPTCP_INC_STATS(sock_net(sk),
MPTCP_MIB_FALLBACKFAILED);
goto do_reset;
}
MPTCP_INC_STATS(sock_net(sk),
MPTCP_MIB_MPCAPABLEACTIVEFALLBACK);
pr_fallback(msk);
goto fallback;
}
@@ -1406,7 +1407,7 @@ fallback:
return true;
}
if (!mptcp_try_fallback(ssk)) {
if (!mptcp_try_fallback(ssk, MPTCP_MIB_DSSFALLBACK)) {
/* fatal protocol error, close the socket.
* subflow_error_report() will introduce the appropriate barriers
*/
@@ -1853,14 +1854,11 @@ static void subflow_state_change(struct sock *sk)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
struct sock *parent = subflow->conn;
struct mptcp_sock *msk;
__subflow_state_change(sk);
msk = mptcp_sk(parent);
if (subflow_simultaneous_connect(sk)) {
WARN_ON_ONCE(!mptcp_try_fallback(sk));
pr_fallback(msk);
WARN_ON_ONCE(!mptcp_try_fallback(sk, MPTCP_MIB_SIMULTCONNFALLBACK));
subflow->conn_finished = 1;
mptcp_propagate_state(parent, sk, subflow, NULL);
}