From 0d299edd5f315e46038810f8a44e9bbb426311fc Mon Sep 17 00:00:00 2001 From: Lukas Prause Date: Fri, 30 Jan 2026 13:48:31 +0100 Subject: [PATCH] Adds ECN handling managed by ROCCET. Use of srRTT as a hard condition after receiving an ECN. --- tcp_roccet.c | 53 ++++++++++++++++++++++++++++++++++++++++++++-------- tcp_roccet.h | 4 +++- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/tcp_roccet.c b/tcp_roccet.c index e3d7966..3377114 100644 --- a/tcp_roccet.c +++ b/tcp_roccet.c @@ -14,8 +14,9 @@ * CUBIC's window growth function and adds, based on RTT * and ACK rate, congestion events. * - * NOTE: A paper for TCP ROCCET is currently under review. - * A draft of this paper can be found here: + * A peer-reviewed paper on TCP ROCCET will be presented at the WONS 2026 conference. + * A draft of the paper is available here: + * https://arxiv.org/abs/2510.25281 * * * Further information about CUBIC: @@ -128,7 +129,8 @@ static inline void roccettcp_reset(struct roccettcp *ca) ca->bw_limit.next_check = 0; ca->curr_min_rtt_timed.rtt = ~0U; ca->curr_min_rtt_timed.time = ~0U; - ca->last_rtt = 0; + ca->ece_srrtt = 0; + ca->ece_cwnd = 2; } static inline void update_min_rtt(struct sock *sk) @@ -424,18 +426,32 @@ __bpf_kfunc static void roccettcp_cong_avoid(struct sock *sk, u32 ack, update_min_rtt(sk); update_srrtt(sk); + /* Reset ECE handling if we already have more bandwidth + * than we received the last ECE. + */ + if(ca->ece_srrtt > 0){ + if(tcp_snd_cwnd(tp) >= ca->ece_cwnd){ + ca->ece_srrtt = 0; + } + } + /* ROCCET drain. * Do not increase the cwnd for 100ms after a roccet congestion event */ if (now - ca->roccet_last_event_time_us <= 100 * USEC_PER_MSEC) return; - /* Lift off: Detect an exit point for tcp slow start + /* LAUNCH: Detect an exit point for tcp slow start * in networks with large buffers of multiple BDP * Like in cellular networks (5G, ...). + * Or exit LAUNCH if cwnd is too large for application layer + * data rate. */ - if (tcp_in_slow_start(tp) && ca->curr_srRTT > sr_rtt_upper_bound && - get_ack_rate_diff(ca) >= ack_rate_diff_ss) { + + if ((tcp_in_slow_start(tp) && ca->curr_srRTT > sr_rtt_upper_bound && + get_ack_rate_diff(ca) >= ack_rate_diff_ss) || + (!tcp_is_cwnd_limited(sk) && tcp_in_slow_start(tp)) + ) { ca->epoch_start = 0; /* Handle inital slow start. Here we observe the most problems */ @@ -486,7 +502,13 @@ __bpf_kfunc static void roccettcp_cong_avoid(struct sock *sk, u32 ack, if (roccet_xj < sr_rtt_upper_bound) roccet_xj = sr_rtt_upper_bound; - if (ca->curr_srRTT > roccet_xj && bw_limit_detect) { + /* This is true if we recently received an ECE bit. + * Therefore we should respect the srRTT at this piont. + */ + if(ca->ece_srrtt < roccet_xj && ca->ece_srrtt > 0) + roccet_xj = ca->ece_srrtt; + + if (ca->curr_srRTT > roccet_xj && (bw_limit_detect || ca->ece_srrtt > 0)) { ca->epoch_start = 0; ca->roccet_last_event_time_us = now; ca->cnt = 100 * tcp_snd_cwnd(tp); @@ -526,7 +548,7 @@ __bpf_kfunc static u32 roccettcp_recalc_ssthresh(struct sock *sk) /* Don't exit slow start if loss occurs. */ if (tcp_in_slow_start(tp)) return tcp_snd_cwnd(tp); - + ca->epoch_start = 0; /* end of epoch */ /* Wmax and fast convergence */ @@ -575,6 +597,20 @@ __bpf_kfunc static void roccettcp_acked(struct sock *sk, } } +__bpf_kfunc static void roccet_in_ack_event(struct sock *sk, u32 flags) +{ + struct tcp_sock *tp = tcp_sk(sk); + struct roccettcp *ca = inet_csk_ca(sk); + + /* Handle ECE bit. + * Pocessing of ECE events is done in roccettcp_cong_avoid() + */ + if (flags & CA_ACK_ECE) { + ca->ece_srrtt = ca->curr_srRTT; + ca->ece_cwnd = tcp_snd_cwnd(tp); + } +} + static struct tcp_congestion_ops roccet_tcp __read_mostly = { .init = roccettcp_init, .ssthresh = roccettcp_recalc_ssthresh, @@ -583,6 +619,7 @@ static struct tcp_congestion_ops roccet_tcp __read_mostly = { .undo_cwnd = tcp_reno_undo_cwnd, .cwnd_event = roccettcp_cwnd_event, .pkts_acked = roccettcp_acked, + .in_ack_event = roccet_in_ack_event, .owner = THIS_MODULE, .name = "roccet", }; diff --git a/tcp_roccet.h b/tcp_roccet.h index dc1e03b..0112a0d 100644 --- a/tcp_roccet.h +++ b/tcp_roccet.h @@ -39,7 +39,9 @@ struct roccettcp { u32 tcp_cwnd; /* estimated tcp cwnd */ u32 curr_rtt; /* the minimum rtt of current round */ - u32 roccet_last_event_time_us; /* The last time ROCCETv2 was triggered */ + u32 roccet_last_event_time_us; /* The last time ROCCET was triggered */ + u32 ece_cwnd; /* The cwnd when a ECE bit was received */ + u32 ece_srrtt; /* The srRTT whent the ECE was received */ u32 curr_min_rtt; /* The current observed minRTT */ struct TimedRTT curr_min_rtt_timed; /* The current observed minRTT with the timestamp when it was observed */