[PATCH mptcp-next v3 4/4] mptcp: sched: add penalise counters and tracepoint
Shardul Bankar <[email protected]>
| Newsgroups | dev.linux.lists.mptcp |
|---|---|
| Message-ID | <20260817-mptcp_penalise_send_v2-v3-4-e6a2ad2f1b82@mpiricsoftware.com> |
Add observability for the cwnd-halving penalty introduced in the previous patches. Two MPTcpExt SNMP counters: - CwndPenalised: times a subflow cwnd was actually halved; - PenalCandidate: times the rate trigger picked a slow subflow. The two show whether the rate trigger fired at all and how many of those candidates were actually halved; the gap reflects the gates and the once-per-RTT limiter collectively, not any single condition. Add a mptcp_subflow_penalise tracepoint. The penalise verdict is decided after the subflow-selection loop, once the fastest path is known, so it is exposed through a dedicated tracepoint rather than the per-candidate mptcp_subflow_get_send emit. It reports the selected subflow's pace, the fastest path's pace and its cwnd alongside the verdict, so a slow-but-gated subflow and its window can be watched from a single line. Co-developed-by: Matthieu Baerts (NGI0) <[email protected]> Signed-off-by: Shardul Bankar <[email protected]> --- include/trace/events/mptcp.h | 30 ++++++++++++++++++++++++++++++ net/mptcp/mib.c | 2 ++ net/mptcp/mib.h | 2 ++ net/mptcp/protocol.c | 6 ++++++ 4 files changed, 40 insertions(+) diff --git a/include/trace/events/mptcp.h b/include/trace/events/mptcp.h index 22882bd03459..fe13f0c8a34d 100644 --- a/include/trace/events/mptcp.h +++ b/include/trace/events/mptcp.h @@ -68,6 +68,36 @@ TRACE_EVENT(mptcp_subflow_get_send, __entry->backup, __entry->ratio) ); +TRACE_EVENT(mptcp_subflow_penalise, + + TP_PROTO(struct mptcp_subflow_context *subflow, unsigned long max_pace), + + TP_ARGS(subflow, max_pace), + + TP_STRUCT__entry( + __field(u64, pace) + __field(u64, max_pace) + __field(u32, cwnd) + __field(bool, penalise) + ), + + TP_fast_assign( + struct sock *ssk = mptcp_subflow_tcp_sock(subflow); + + __entry->pace = subflow->avg_pacing_rate; + __entry->max_pace = max_pace; + if (ssk && sk_fullsock(ssk)) + __entry->cwnd = tcp_snd_cwnd(tcp_sk(ssk)); + else + __entry->cwnd = 0; + __entry->penalise = subflow->penalise; + ), + + TP_printk("pace=%llu max_pace=%llu cwnd=%u penalise=%d", + __entry->pace, __entry->max_pace, + __entry->cwnd, __entry->penalise) +); + DECLARE_EVENT_CLASS(mptcp_dump_mpext, TP_PROTO(struct mptcp_ext *mpext), diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c index 608cb568897c..b39b5511345d 100644 --- a/net/mptcp/mib.c +++ b/net/mptcp/mib.c @@ -95,6 +95,8 @@ static const struct snmp_mib mptcp_snmp_list[] = { SNMP_MIB_ITEM("BacklogDrop", MPTCP_MIB_BACKLOGDROP), SNMP_MIB_ITEM("RcvPruned", MPTCP_MIB_RCVPRUNED), SNMP_MIB_ITEM("OFOPruned", MPTCP_MIB_OFOPRUNED), + SNMP_MIB_ITEM("CwndPenalised", MPTCP_MIB_CWNDPENALISED), + SNMP_MIB_ITEM("PenalCandidate", MPTCP_MIB_PENALCAND), }; /* mptcp_mib_alloc - allocate percpu mib counters diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h index 1ebdb55e9534..a7b5bf684af7 100644 --- a/net/mptcp/mib.h +++ b/net/mptcp/mib.h @@ -98,6 +98,8 @@ enum linux_mptcp_mib_field { MPTCP_MIB_BACKLOGDROP, /* Backlog over memory limit */ MPTCP_MIB_RCVPRUNED, /* Dropped due to memory constraints */ MPTCP_MIB_OFOPRUNED, /* MPTCP-level OoO queue pruned */ + MPTCP_MIB_CWNDPENALISED, /* subflow cwnd halved by the scheduler */ + MPTCP_MIB_PENALCAND, /* scheduler picked a slow (low-rate) subflow */ __MPTCP_MIB_MAX }; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index e4d26c2dce1e..0cd18705ab40 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -1656,6 +1656,7 @@ static void mptcp_penalise_cwnd(struct sock *ssk) return; subflow->last_penalise = tcp_jiffies32; tcp_snd_cwnd_set(tp, max_t(u32, cwnd >> 1, MPTCP_PENALISE_MIN_CWND)); + MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_CWNDPENALISED); if (cwnd >= tp->snd_ssthresh) tp->snd_ssthresh = max_t(u32, tp->snd_ssthresh >> 1, 2); } @@ -1739,6 +1740,8 @@ struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk) subflow = mptcp_subflow_ctx(ssk); penal_cand = fastest && ssk != fastest && subflow->avg_pacing_rate < max_pace / MPTCP_PENALISE_RATE_RATIO; + if (penal_cand) + MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_PENALCAND); subflow->penalise = penal_cand && tcp_snd_cwnd(tcp_sk(ssk)) > MPTCP_PENALISE_MIN_CWND && inet_csk(ssk)->icsk_ca_state == TCP_CA_Open && @@ -1746,6 +1749,9 @@ struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk) mptcp_snd_wnd_test(msk) && mptcp_penalise_throttle_ok(subflow); + /* trace the penalise verdict, decided here after the selection loop */ + trace_mptcp_subflow_penalise(subflow, max_pace); + burst = min(MPTCP_SEND_BURST_SIZE, mptcp_wnd_end(msk) - msk->snd_nxt); wmem = READ_ONCE(ssk->sk_wmem_queued); if (!burst) { -- 2.34.1