1 Commits

3 changed files with 107 additions and 86 deletions
+4 -3
View File
@@ -11,10 +11,11 @@ The congestion avoidance phase, called ORBITER, uses
CUBIC's window growth function and adds, based on RTT CUBIC's window growth function and adds, based on RTT
and ACK rate, congestion events. and ACK rate, congestion events.
A peer-reviewed paper on TCP ROCCET will be presented at the WONS 2026 conference. NOTE: A paper for TCP ROCCET is currently under review.
A draft of the paper is available here: Paper draft:
https://arxiv.org/abs/2510.25281 https://arxiv.org/abs/2510.25281
The oldest Linux kernel version we tested with ROCCET is 6.1.
## Setup ## Setup
+65 -43
View File
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0-only
/* /*
* TCP ROCCET: An RTT-Oriented CUBIC Congestion Control * TCP ROCCET: An RTT-Oriented CUBIC Congestion Control
* Extension for 5G and Beyond Networks * Extension for 5G and Beyond Networks
@@ -16,13 +16,13 @@
* *
* A peer-reviewed paper on TCP ROCCET will be presented at the WONS 2026 conference. * A peer-reviewed paper on TCP ROCCET will be presented at the WONS 2026 conference.
* A draft of the paper is available here: * A draft of the paper is available here:
* https://arxiv.org/abs/2510.25281 * https://arxiv.org/abs/2510.25281
* *
* *
* Further information about CUBIC: * Further information about CUBIC:
* TCP CUBIC: Binary Increase Congestion control for TCP v2.3 * TCP CUBIC: Binary Increase Congestion control for TCP v2.3
* Home page: * Home page:
* http://netsrv.csc.ncsu.edu/twiki/bin/view/Main/BIC * http://netsrv.csc.ncsu.edu/twiki/bin/view/Main/BIC
* This is from the implementation of CUBIC TCP in * This is from the implementation of CUBIC TCP in
* Sangtae Ha, Injong Rhee and Lisong Xu, * Sangtae Ha, Injong Rhee and Lisong Xu,
* "CUBIC: A New TCP-Friendly High-Speed TCP Variant" * "CUBIC: A New TCP-Friendly High-Speed TCP Variant"
@@ -72,26 +72,30 @@
static int sr_rtt_upper_bound __read_mostly = 100; static int sr_rtt_upper_bound __read_mostly = 100;
static int ack_rate_diff_ss __read_mostly = 10; static int ack_rate_diff_ss __read_mostly = 10;
static int ack_rate_diff_ca __read_mostly = 200; static int ack_rate_diff_ca __read_mostly = 200;
static bool calculate_min_rtt __read_mostly; static int calculate_min_rtt __read_mostly = 0;
static bool ignore_loss __read_mostly; static int ignore_loss __read_mostly = 0;
static int roccet_min_rtt_interpolation_factor __read_mostly = 70; static int roccet_minRTT_interpolation_factor __read_mostly = 70;
module_param(sr_rtt_upper_bound, int, 0644); module_param(sr_rtt_upper_bound, int, 0644);
MODULE_PARM_DESC(sr_rtt_upper_bound, "ROCCET's upper bound for srRTT."); MODULE_PARM_DESC(sr_rtt_upper_bound, "ROCCET's upper bound for srRTT.");
module_param(ack_rate_diff_ss, int, 0644); module_param(ack_rate_diff_ss, int, 0644);
MODULE_PARM_DESC(ack_rate_diff_ss, MODULE_PARM_DESC(ack_rate_diff_ss,
"ROCCET's threshold to exit slow start if ACK-rate defer by given amount of segments."); "ROCCET's threshold to exit slow start if ACK-rate defer by "
"given amount of segments.");
module_param(ack_rate_diff_ca, int, 0644); module_param(ack_rate_diff_ca, int, 0644);
MODULE_PARM_DESC(ack_rate_diff_ca, MODULE_PARM_DESC(ack_rate_diff_ca,
"ROCCET's threshold for ack-rate and cum_cwnd, in percantage of the current cwnd."); "ROCCET's threshold for ack-rate and cum_cwnd, in percantage "
module_param(calculate_min_rtt, bool, 0644); "of the current cwnd.");
module_param(calculate_min_rtt, int, 0644);
MODULE_PARM_DESC(calculate_min_rtt, MODULE_PARM_DESC(calculate_min_rtt,
"Calculate min RTT if no lower RTT occurs after 10 sec."); "Calculate min RTT if no lower RTT occurs after 10 sec.");
module_param(ignore_loss, bool, 0644); module_param(ignore_loss, int, 0644);
MODULE_PARM_DESC(ignore_loss, "Ignore loss as a congestion event."); MODULE_PARM_DESC(ignore_loss, "Ignore loss as a congestion event.");
module_param(roccet_min_rtt_interpolation_factor, int, 0644); module_param(roccet_minRTT_interpolation_factor, int, 0644);
MODULE_PARM_DESC(roccet_min_rtt_interpolation_factor, MODULE_PARM_DESC(
"ROCCET factor for interpolating the current RTT with the last minRTT (minRTT = (factor * currRTT + (100-factor) * minRTT) / 100)"); roccet_minRTT_interpolation_factor,
"ROCCET factor for interpolating the current RTT with the last minRTT "
"(minRTT = (factor * currRTT + (100-factor) * minRTT) / 100)");
static int fast_convergence __read_mostly = 1; static int fast_convergence __read_mostly = 1;
static int beta __read_mostly = 717; /* = 717/1024 (BICTCP_BETA_SCALE) */ static int beta __read_mostly = 717; /* = 717/1024 (BICTCP_BETA_SCALE) */
@@ -111,8 +115,9 @@ MODULE_PARM_DESC(beta, "beta for multiplicative increase");
module_param(initial_ssthresh, int, 0644); module_param(initial_ssthresh, int, 0644);
MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold"); MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold");
module_param(bic_scale, int, 0444); module_param(bic_scale, int, 0444);
MODULE_PARM_DESC(bic_scale, MODULE_PARM_DESC(
"scale (scaled by 1024) value for bic function (bic_scale/1024)"); bic_scale,
"scale (scaled by 1024) value for bic function (bic_scale/1024)");
module_param(tcp_friendliness, int, 0644); module_param(tcp_friendliness, int, 0644);
MODULE_PARM_DESC(tcp_friendliness, "turn on/off tcp friendliness"); MODULE_PARM_DESC(tcp_friendliness, "turn on/off tcp friendliness");
@@ -124,8 +129,8 @@ static inline void roccettcp_reset(struct roccettcp *ca)
ca->bw_limit.next_check = 0; ca->bw_limit.next_check = 0;
ca->curr_min_rtt_timed.rtt = ~0U; ca->curr_min_rtt_timed.rtt = ~0U;
ca->curr_min_rtt_timed.time = ~0U; ca->curr_min_rtt_timed.time = ~0U;
ca->last_rtt = 0; ca->ece_srrtt = 0;
ca->ece_received = false; ca->ece_cwnd = 2;
} }
static inline void update_min_rtt(struct sock *sk) static inline void update_min_rtt(struct sock *sk)
@@ -140,9 +145,9 @@ static inline void update_min_rtt(struct sock *sk)
u32 old_min_rtt = ca->curr_min_rtt_timed.rtt; u32 old_min_rtt = ca->curr_min_rtt_timed.rtt;
u32 interpolated_min_rtt = u32 interpolated_min_rtt =
(new_min_rtt * roccet_min_rtt_interpolation_factor + (new_min_rtt * roccet_minRTT_interpolation_factor +
old_min_rtt * old_min_rtt *
(100 - roccet_min_rtt_interpolation_factor)) / (100 - roccet_minRTT_interpolation_factor)) /
100; 100;
ca->curr_min_rtt_timed.rtt = interpolated_min_rtt; ca->curr_min_rtt_timed.rtt = interpolated_min_rtt;
@@ -193,12 +198,13 @@ static inline void update_srrtt(struct sock *sk)
/* Calculate the new rRTT (Scaled by 100). /* Calculate the new rRTT (Scaled by 100).
* 100 * ((sRTT - sRTT_min) / sRTT_min) * 100 * ((sRTT - sRTT_min) / sRTT_min)
*/ */
u32 rrtt = (100 * (ca->curr_rtt - ca->curr_min_rtt_timed.rtt)) / u32 rRTT = (100 * (ca->curr_rtt - ca->curr_min_rtt_timed.rtt)) /
ca->curr_min_rtt_timed.rtt; ca->curr_min_rtt_timed.rtt;
// (1 - alpha) * srRTT + alpha * rRTT // (1 - alpha) * srRTT + alpha * rRTT
ca->curr_srrtt = ((100 - ROCCET_ALPHA_TIMES_100) * ca->curr_srrtt + ca->curr_srRTT = ((100 - ROCCET_ALPHA_TIMES_100) * ca->curr_srRTT +
ROCCET_ALPHA_TIMES_100 * rrtt) / 100; ROCCET_ALPHA_TIMES_100 * rRTT) /
100;
} }
__bpf_kfunc static void roccettcp_init(struct sock *sk) __bpf_kfunc static void roccettcp_init(struct sock *sk)
@@ -210,7 +216,7 @@ __bpf_kfunc static void roccettcp_init(struct sock *sk)
if (initial_ssthresh) if (initial_ssthresh)
tcp_sk(sk)->snd_ssthresh = initial_ssthresh; tcp_sk(sk)->snd_ssthresh = initial_ssthresh;
/* Initial roccet parameters */ /* Initial roccet paramters */
ca->roccet_last_event_time_us = 0; ca->roccet_last_event_time_us = 0;
ca->curr_min_rtt = ~0U; ca->curr_min_rtt = ~0U;
ca->ack_rate.last_rate = 0; ca->ack_rate.last_rate = 0;
@@ -334,7 +340,7 @@ static inline void bictcp_update(struct roccettcp *ca, u32 cwnd, u32 acked)
* (so time^3 is done by using 64 bit) * (so time^3 is done by using 64 bit)
* and without the support of division of 64bit numbers * and without the support of division of 64bit numbers
* (so all divisions are done by using 32 bit) * (so all divisions are done by using 32 bit)
* also NOTE the unit of those variables * also NOTE the unit of those veriables
* time = (t - K) / 2^bictcp_HZ * time = (t - K) / 2^bictcp_HZ
* c = bic_scale >> 10 * c = bic_scale >> 10
* rtt = (srtt >> 3) / HZ * rtt = (srtt >> 3) / HZ
@@ -362,10 +368,11 @@ static inline void bictcp_update(struct roccettcp *ca, u32 cwnd, u32 acked)
bic_target = ca->bic_origin_point + delta; bic_target = ca->bic_origin_point + delta;
/* cubic function - calc bictcp_cnt*/ /* cubic function - calc bictcp_cnt*/
if (bic_target > cwnd) if (bic_target > cwnd) {
ca->cnt = cwnd / (bic_target - cwnd); ca->cnt = cwnd / (bic_target - cwnd);
else } else {
ca->cnt = 100 * cwnd; /* very small increment*/ ca->cnt = 100 * cwnd; /* very small increment*/
}
/* The initial growth of cubic function may be too conservative /* The initial growth of cubic function may be too conservative
* when the available bandwidth is still unknown. * when the available bandwidth is still unknown.
@@ -408,17 +415,26 @@ __bpf_kfunc static void roccettcp_cong_avoid(struct sock *sk, u32 ack,
u32 bw_limit_detect = 0; u32 bw_limit_detect = 0;
u32 roccet_xj; u32 roccet_xj;
u32 jitter; u32 jitter;
if (ca->last_rtt > ca->curr_rtt) {
if (ca->last_rtt > ca->curr_rtt)
jitter = ca->last_rtt - ca->curr_rtt; jitter = ca->last_rtt - ca->curr_rtt;
else } else {
jitter = ca->curr_rtt - ca->last_rtt; jitter = ca->curr_rtt - ca->last_rtt;
}
/* Update roccet parameters */ /* Update roccet paramters */
update_ack_rate(sk); update_ack_rate(sk);
update_min_rtt(sk); update_min_rtt(sk);
update_srrtt(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. /* ROCCET drain.
* Do not increase the cwnd for 100ms after a roccet congestion event * Do not increase the cwnd for 100ms after a roccet congestion event
*/ */
@@ -432,12 +448,13 @@ __bpf_kfunc static void roccettcp_cong_avoid(struct sock *sk, u32 ack,
* data rate. * data rate.
*/ */
if ((tcp_in_slow_start(tp) && ca->curr_srrtt > sr_rtt_upper_bound && if ((tcp_in_slow_start(tp) && ca->curr_srRTT > sr_rtt_upper_bound &&
get_ack_rate_diff(ca) >= ack_rate_diff_ss) || get_ack_rate_diff(ca) >= ack_rate_diff_ss) ||
(!tcp_is_cwnd_limited(sk) && tcp_in_slow_start(tp))) { (!tcp_is_cwnd_limited(sk) && tcp_in_slow_start(tp))
) {
ca->epoch_start = 0; ca->epoch_start = 0;
/* Handle initial slow start. Here we observe the most problems */ /* Handle inital slow start. Here we observe the most problems */
if (tp->snd_ssthresh == TCP_INFINITE_SSTHRESH) { if (tp->snd_ssthresh == TCP_INFINITE_SSTHRESH) {
tcp_sk(sk)->snd_ssthresh = tcp_snd_cwnd(tp) / 2; tcp_sk(sk)->snd_ssthresh = tcp_snd_cwnd(tp) / 2;
tcp_snd_cwnd_set(tp, tcp_snd_cwnd(tp) / 2); tcp_snd_cwnd_set(tp, tcp_snd_cwnd(tp) / 2);
@@ -485,9 +502,13 @@ __bpf_kfunc static void roccettcp_cong_avoid(struct sock *sk, u32 ack,
if (roccet_xj < sr_rtt_upper_bound) if (roccet_xj < sr_rtt_upper_bound)
roccet_xj = sr_rtt_upper_bound; roccet_xj = sr_rtt_upper_bound;
if (ca->curr_srrtt > roccet_xj && (bw_limit_detect || ca->ece_received)) { /* This is true if we recently received an ECE bit.
if (ca->ece_received) * Therefore we should respect the srRTT at this piont.
ca->ece_received = false; */
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->epoch_start = 0;
ca->roccet_last_event_time_us = now; ca->roccet_last_event_time_us = now;
ca->cnt = 100 * tcp_snd_cwnd(tp); ca->cnt = 100 * tcp_snd_cwnd(tp);
@@ -497,7 +518,7 @@ __bpf_kfunc static void roccettcp_cong_avoid(struct sock *sk, u32 ack,
ca->last_max_cwnd = tcp_snd_cwnd(tp); ca->last_max_cwnd = tcp_snd_cwnd(tp);
tcp_snd_cwnd_set(tp, min(tp->snd_cwnd_clamp, tcp_snd_cwnd_set(tp, min(tp->snd_cwnd_clamp,
max((tcp_snd_cwnd(tp) * beta) / BICTCP_BETA_SCALE, 2U))); max((tcp_snd_cwnd(tp) * beta) / BICTCP_BETA_SCALE, 2U)));
tp->snd_ssthresh = tcp_snd_cwnd(tp); tp->snd_ssthresh = tcp_snd_cwnd(tp);
return; return;
} }
@@ -544,7 +565,6 @@ __bpf_kfunc static u32 roccettcp_recalc_ssthresh(struct sock *sk)
__bpf_kfunc static void roccettcp_state(struct sock *sk, u8 new_state) __bpf_kfunc static void roccettcp_state(struct sock *sk, u8 new_state)
{ {
struct roccettcp *ca = inet_csk_ca(sk); struct roccettcp *ca = inet_csk_ca(sk);
if (new_state == TCP_CA_Loss) if (new_state == TCP_CA_Loss)
roccettcp_reset(ca); roccettcp_reset(ca);
} }
@@ -563,7 +583,6 @@ __bpf_kfunc static void roccettcp_acked(struct sock *sk,
return; return;
u32 delay = sample->rtt_us; u32 delay = sample->rtt_us;
if (delay == 0) if (delay == 0)
delay = 1; delay = 1;
@@ -580,13 +599,16 @@ __bpf_kfunc static void roccettcp_acked(struct sock *sk,
__bpf_kfunc static void roccet_in_ack_event(struct sock *sk, u32 flags) __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); struct roccettcp *ca = inet_csk_ca(sk);
/* Handle ECE bit. /* Handle ECE bit.
* Processing of ECE events is done in roccettcp_cong_avoid() * Pocessing of ECE events is done in roccettcp_cong_avoid()
*/ */
if (flags & CA_ACK_ECE) if (flags & CA_ACK_ECE) {
ca->ece_received = true; ca->ece_srrtt = ca->curr_srRTT;
ca->ece_cwnd = tcp_snd_cwnd(tp);
}
} }
static struct tcp_congestion_ops roccet_tcp __read_mostly = { static struct tcp_congestion_ops roccet_tcp __read_mostly = {
+33 -35
View File
@@ -1,4 +1,3 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* TCP ROCCET congestion control interface * TCP ROCCET congestion control interface
*/ */
@@ -7,50 +6,49 @@
#include <linux/math64.h> #include <linux/math64.h>
struct ack_rate { struct AckRate {
u16 last_rate; /* Last ACK-rate */ u16 last_rate; /* Last ACK-rate */
u32 last_rate_time; /* Timestamp of the last ACK-rate */ u32 last_rate_time; /* Timestamp of the last ACK-rate */
u16 curr_rate; /* Current ACK-rate */ u16 curr_rate; /* Current ACK-rate */
u16 cnt; /* Used for counting acks */ u16 cnt; /* Used for counting acks */
}; };
struct bandwidth_limit_detect { struct BandwidthLimitDetect {
u32 sum_cwnd; /* sum of cwnd during time interval */ u32 sum_cwnd; /* sum of cwnd during time interval */
u32 sum_acked; /* sum of received acks during time interval */ u32 sum_acked; /* sum of received acks during time interval */
u32 next_check; /* end/upper bound of time interval */ u32 next_check; /* end/upper bound of time interval */
}; };
struct timed_rtt { struct TimedRTT {
u32 time; /* Time of recording */ u32 time; /* Time of recoding */
u32 rtt; /* Measured RTT */ u32 rtt; /* Measured RTT */
}; };
/* Based on the BICTCP struct with additions specific for the ROCCET-Algorithm */ /* Based on the BICTCP struct with additions specific for the ROCCET-Algorithm */
struct roccettcp { struct roccettcp {
u32 cnt; /* increase cwnd by 1 after ACKs */ u32 cnt; /* increase cwnd by 1 after ACKs */
u32 last_max_cwnd; /* last maximum snd_cwnd */ u32 last_max_cwnd; /* last maximum snd_cwnd */
u32 last_cwnd; /* the last snd_cwnd */ u32 last_cwnd; /* the last snd_cwnd */
u32 last_time; /* time when updated last_cwnd */ u32 last_time; /* time when updated last_cwnd */
u32 bic_origin_point; /* origin point of bic function */ u32 bic_origin_point; /* origin point of bic function */
u32 bic_K; /* time to origin point from the u32 bic_K; /* time to origin point from the
* beginning of the current epoch beginning of the current epoch */
*/ u32 delay_min; /* min delay (usec) */
u32 delay_min; /* min delay (usec) */ u32 epoch_start; /* beginning of an epoch */
u32 epoch_start; /* beginning of an epoch */ u32 ack_cnt; /* number of acks */
u32 ack_cnt; /* number of acks */ u32 tcp_cwnd; /* estimated tcp cwnd */
u32 tcp_cwnd; /* estimated tcp cwnd */ u32 curr_rtt; /* the minimum rtt of current round */
u32 curr_rtt; /* the minimum rtt of current round */
u32 roccet_last_event_time_us; /* The last time ROCCET was triggered */ u32 roccet_last_event_time_us; /* The last time ROCCET was triggered */
bool ece_received; /* Set to true if an ECE bit was received */ u32 ece_cwnd; /* The cwnd when a ECE bit was received */
u32 curr_min_rtt; /* The current observed minRTT */ u32 ece_srrtt; /* The srRTT whent the ECE was received */
struct timed_rtt curr_min_rtt_timed; /* The current observed minRTT with u32 curr_min_rtt; /* The current observed minRTT */
* the timestamp when it was observed struct TimedRTT curr_min_rtt_timed; /* The current observed minRTT with
*/ the timestamp when it was observed */
u32 curr_srrtt; /* The srRTT calculated based on the latest ACK */ u32 curr_srRTT; /* The srRTT calculated based on the latest ACK */
struct ack_rate ack_rate; /* The last and the current ACK rate */ struct AckRate ack_rate; /* The last and the current ACK rate */
struct bandwidth_limit_detect bw_limit; struct BandwidthLimitDetect bw_limit;
u32 last_rtt; /* Used for jitter calculation */ u32 last_rtt; /* Used for jitter calculation */
}; };
#endif /* __TCP_ROCCET_H */ #endif /* __TCP_ROCCET_H */