1 1.1 christos #include "internal/quic_cc.h" 2 1.1 christos #include "internal/quic_types.h" 3 1.1 christos #include "internal/safe_math.h" 4 1.1 christos 5 1.1 christos OSSL_SAFE_MATH_UNSIGNED(u64, uint64_t) 6 1.1 christos 7 1.1 christos typedef struct ossl_cc_newreno_st { 8 1.1 christos /* Dependencies. */ 9 1.1.1.2 christos OSSL_TIME (*now_cb)(void *arg); 10 1.1.1.2 christos void *now_cb_arg; 11 1.1 christos 12 1.1 christos /* 'Constants' (which we allow to be configurable). */ 13 1.1.1.2 christos uint64_t k_init_wnd, k_min_wnd; 14 1.1.1.2 christos uint32_t k_loss_reduction_factor_num, k_loss_reduction_factor_den; 15 1.1.1.2 christos uint32_t persistent_cong_thresh; 16 1.1 christos 17 1.1 christos /* State. */ 18 1.1.1.2 christos size_t max_dgram_size; 19 1.1.1.2 christos uint64_t bytes_in_flight, cong_wnd, slow_start_thresh, bytes_acked; 20 1.1.1.2 christos OSSL_TIME cong_recovery_start_time; 21 1.1 christos 22 1.1 christos /* Unflushed state during multiple on-loss calls. */ 23 1.1.1.2 christos int processing_loss; /* 1 if not flushed */ 24 1.1.1.2 christos OSSL_TIME tx_time_of_last_loss; 25 1.1 christos 26 1.1 christos /* Diagnostic state. */ 27 1.1.1.2 christos int in_congestion_recovery; 28 1.1 christos 29 1.1 christos /* Diagnostic output locations. */ 30 1.1.1.2 christos size_t *p_diag_max_dgram_payload_len; 31 1.1.1.2 christos uint64_t *p_diag_cur_cwnd_size; 32 1.1.1.2 christos uint64_t *p_diag_min_cwnd_size; 33 1.1.1.2 christos uint64_t *p_diag_cur_bytes_in_flight; 34 1.1.1.2 christos uint32_t *p_diag_cur_state; 35 1.1 christos } OSSL_CC_NEWRENO; 36 1.1 christos 37 1.1.1.2 christos #define MIN_MAX_INIT_WND_SIZE 14720 /* RFC 9002 s. 7.2 */ 38 1.1 christos 39 1.1 christos /* TODO(QUIC FUTURE): Pacing support. */ 40 1.1 christos 41 1.1 christos static void newreno_set_max_dgram_size(OSSL_CC_NEWRENO *nr, 42 1.1.1.2 christos size_t max_dgram_size); 43 1.1 christos static void newreno_update_diag(OSSL_CC_NEWRENO *nr); 44 1.1 christos 45 1.1 christos static void newreno_reset(OSSL_CC_DATA *cc); 46 1.1 christos 47 1.1 christos static OSSL_CC_DATA *newreno_new(OSSL_TIME (*now_cb)(void *arg), 48 1.1.1.2 christos void *now_cb_arg) 49 1.1 christos { 50 1.1 christos OSSL_CC_NEWRENO *nr; 51 1.1 christos 52 1.1 christos if ((nr = OPENSSL_zalloc(sizeof(*nr))) == NULL) 53 1.1 christos return NULL; 54 1.1 christos 55 1.1.1.2 christos nr->now_cb = now_cb; 56 1.1.1.2 christos nr->now_cb_arg = now_cb_arg; 57 1.1 christos 58 1.1 christos newreno_set_max_dgram_size(nr, QUIC_MIN_INITIAL_DGRAM_LEN); 59 1.1 christos newreno_reset((OSSL_CC_DATA *)nr); 60 1.1 christos 61 1.1 christos return (OSSL_CC_DATA *)nr; 62 1.1 christos } 63 1.1 christos 64 1.1 christos static void newreno_free(OSSL_CC_DATA *cc) 65 1.1 christos { 66 1.1 christos OPENSSL_free(cc); 67 1.1 christos } 68 1.1 christos 69 1.1 christos static void newreno_set_max_dgram_size(OSSL_CC_NEWRENO *nr, 70 1.1.1.2 christos size_t max_dgram_size) 71 1.1 christos { 72 1.1 christos size_t max_init_wnd; 73 1.1 christos int is_reduced = (max_dgram_size < nr->max_dgram_size); 74 1.1 christos 75 1.1 christos nr->max_dgram_size = max_dgram_size; 76 1.1 christos 77 1.1 christos max_init_wnd = 2 * max_dgram_size; 78 1.1 christos if (max_init_wnd < MIN_MAX_INIT_WND_SIZE) 79 1.1 christos max_init_wnd = MIN_MAX_INIT_WND_SIZE; 80 1.1 christos 81 1.1 christos nr->k_init_wnd = 10 * max_dgram_size; 82 1.1 christos if (nr->k_init_wnd > max_init_wnd) 83 1.1 christos nr->k_init_wnd = max_init_wnd; 84 1.1 christos 85 1.1 christos nr->k_min_wnd = 2 * max_dgram_size; 86 1.1 christos 87 1.1 christos if (is_reduced) 88 1.1 christos nr->cong_wnd = nr->k_init_wnd; 89 1.1 christos 90 1.1 christos newreno_update_diag(nr); 91 1.1 christos } 92 1.1 christos 93 1.1 christos static void newreno_reset(OSSL_CC_DATA *cc) 94 1.1 christos { 95 1.1 christos OSSL_CC_NEWRENO *nr = (OSSL_CC_NEWRENO *)cc; 96 1.1 christos 97 1.1.1.2 christos nr->k_loss_reduction_factor_num = 1; 98 1.1.1.2 christos nr->k_loss_reduction_factor_den = 2; 99 1.1.1.2 christos nr->persistent_cong_thresh = 3; 100 1.1.1.2 christos 101 1.1.1.2 christos nr->cong_wnd = nr->k_init_wnd; 102 1.1.1.2 christos nr->bytes_in_flight = 0; 103 1.1.1.2 christos nr->bytes_acked = 0; 104 1.1.1.2 christos nr->slow_start_thresh = UINT64_MAX; 105 1.1.1.2 christos nr->cong_recovery_start_time = ossl_time_zero(); 106 1.1.1.2 christos 107 1.1.1.2 christos nr->processing_loss = 0; 108 1.1.1.2 christos nr->tx_time_of_last_loss = ossl_time_zero(); 109 1.1.1.2 christos nr->in_congestion_recovery = 0; 110 1.1 christos } 111 1.1 christos 112 1.1 christos static int newreno_set_input_params(OSSL_CC_DATA *cc, const OSSL_PARAM *params) 113 1.1 christos { 114 1.1 christos OSSL_CC_NEWRENO *nr = (OSSL_CC_NEWRENO *)cc; 115 1.1 christos const OSSL_PARAM *p; 116 1.1 christos size_t value; 117 1.1 christos 118 1.1 christos p = OSSL_PARAM_locate_const(params, OSSL_CC_OPTION_MAX_DGRAM_PAYLOAD_LEN); 119 1.1 christos if (p != NULL) { 120 1.1 christos if (!OSSL_PARAM_get_size_t(p, &value)) 121 1.1 christos return 0; 122 1.1 christos if (value < QUIC_MIN_INITIAL_DGRAM_LEN) 123 1.1 christos return 0; 124 1.1 christos 125 1.1 christos newreno_set_max_dgram_size(nr, value); 126 1.1 christos } 127 1.1 christos 128 1.1 christos return 1; 129 1.1 christos } 130 1.1 christos 131 1.1 christos static int bind_diag(OSSL_PARAM *params, const char *param_name, size_t len, 132 1.1.1.2 christos void **pp) 133 1.1 christos { 134 1.1 christos const OSSL_PARAM *p = OSSL_PARAM_locate_const(params, param_name); 135 1.1 christos 136 1.1 christos *pp = NULL; 137 1.1 christos 138 1.1 christos if (p == NULL) 139 1.1 christos return 1; 140 1.1 christos 141 1.1 christos if (p->data_type != OSSL_PARAM_UNSIGNED_INTEGER 142 1.1 christos || p->data_size != len) 143 1.1 christos return 0; 144 1.1 christos 145 1.1 christos *pp = p->data; 146 1.1 christos return 1; 147 1.1 christos } 148 1.1 christos 149 1.1 christos static int newreno_bind_diagnostic(OSSL_CC_DATA *cc, OSSL_PARAM *params) 150 1.1 christos { 151 1.1 christos OSSL_CC_NEWRENO *nr = (OSSL_CC_NEWRENO *)cc; 152 1.1 christos size_t *new_p_max_dgram_payload_len; 153 1.1 christos uint64_t *new_p_cur_cwnd_size; 154 1.1 christos uint64_t *new_p_min_cwnd_size; 155 1.1 christos uint64_t *new_p_cur_bytes_in_flight; 156 1.1 christos uint32_t *new_p_cur_state; 157 1.1 christos 158 1.1 christos if (!bind_diag(params, OSSL_CC_OPTION_MAX_DGRAM_PAYLOAD_LEN, 159 1.1.1.2 christos sizeof(size_t), (void **)&new_p_max_dgram_payload_len) 160 1.1 christos || !bind_diag(params, OSSL_CC_OPTION_CUR_CWND_SIZE, 161 1.1.1.2 christos sizeof(uint64_t), (void **)&new_p_cur_cwnd_size) 162 1.1 christos || !bind_diag(params, OSSL_CC_OPTION_MIN_CWND_SIZE, 163 1.1.1.2 christos sizeof(uint64_t), (void **)&new_p_min_cwnd_size) 164 1.1 christos || !bind_diag(params, OSSL_CC_OPTION_CUR_BYTES_IN_FLIGHT, 165 1.1.1.2 christos sizeof(uint64_t), (void **)&new_p_cur_bytes_in_flight) 166 1.1 christos || !bind_diag(params, OSSL_CC_OPTION_CUR_STATE, 167 1.1.1.2 christos sizeof(uint32_t), (void **)&new_p_cur_state)) 168 1.1 christos return 0; 169 1.1 christos 170 1.1 christos if (new_p_max_dgram_payload_len != NULL) 171 1.1 christos nr->p_diag_max_dgram_payload_len = new_p_max_dgram_payload_len; 172 1.1 christos 173 1.1 christos if (new_p_cur_cwnd_size != NULL) 174 1.1 christos nr->p_diag_cur_cwnd_size = new_p_cur_cwnd_size; 175 1.1 christos 176 1.1 christos if (new_p_min_cwnd_size != NULL) 177 1.1 christos nr->p_diag_min_cwnd_size = new_p_min_cwnd_size; 178 1.1 christos 179 1.1 christos if (new_p_cur_bytes_in_flight != NULL) 180 1.1 christos nr->p_diag_cur_bytes_in_flight = new_p_cur_bytes_in_flight; 181 1.1 christos 182 1.1 christos if (new_p_cur_state != NULL) 183 1.1 christos nr->p_diag_cur_state = new_p_cur_state; 184 1.1 christos 185 1.1 christos newreno_update_diag(nr); 186 1.1 christos return 1; 187 1.1 christos } 188 1.1 christos 189 1.1 christos static void unbind_diag(OSSL_PARAM *params, const char *param_name, 190 1.1.1.2 christos void **pp) 191 1.1 christos { 192 1.1 christos const OSSL_PARAM *p = OSSL_PARAM_locate_const(params, param_name); 193 1.1 christos 194 1.1 christos if (p != NULL) 195 1.1 christos *pp = NULL; 196 1.1 christos } 197 1.1 christos 198 1.1 christos static int newreno_unbind_diagnostic(OSSL_CC_DATA *cc, OSSL_PARAM *params) 199 1.1 christos { 200 1.1 christos OSSL_CC_NEWRENO *nr = (OSSL_CC_NEWRENO *)cc; 201 1.1 christos 202 1.1 christos unbind_diag(params, OSSL_CC_OPTION_MAX_DGRAM_PAYLOAD_LEN, 203 1.1.1.2 christos (void **)&nr->p_diag_max_dgram_payload_len); 204 1.1 christos unbind_diag(params, OSSL_CC_OPTION_CUR_CWND_SIZE, 205 1.1.1.2 christos (void **)&nr->p_diag_cur_cwnd_size); 206 1.1 christos unbind_diag(params, OSSL_CC_OPTION_MIN_CWND_SIZE, 207 1.1.1.2 christos (void **)&nr->p_diag_min_cwnd_size); 208 1.1 christos unbind_diag(params, OSSL_CC_OPTION_CUR_BYTES_IN_FLIGHT, 209 1.1.1.2 christos (void **)&nr->p_diag_cur_bytes_in_flight); 210 1.1 christos unbind_diag(params, OSSL_CC_OPTION_CUR_STATE, 211 1.1.1.2 christos (void **)&nr->p_diag_cur_state); 212 1.1 christos return 1; 213 1.1 christos } 214 1.1 christos 215 1.1 christos static void newreno_update_diag(OSSL_CC_NEWRENO *nr) 216 1.1 christos { 217 1.1 christos if (nr->p_diag_max_dgram_payload_len != NULL) 218 1.1 christos *nr->p_diag_max_dgram_payload_len = nr->max_dgram_size; 219 1.1 christos 220 1.1 christos if (nr->p_diag_cur_cwnd_size != NULL) 221 1.1 christos *nr->p_diag_cur_cwnd_size = nr->cong_wnd; 222 1.1 christos 223 1.1 christos if (nr->p_diag_min_cwnd_size != NULL) 224 1.1 christos *nr->p_diag_min_cwnd_size = nr->k_min_wnd; 225 1.1 christos 226 1.1 christos if (nr->p_diag_cur_bytes_in_flight != NULL) 227 1.1 christos *nr->p_diag_cur_bytes_in_flight = nr->bytes_in_flight; 228 1.1 christos 229 1.1 christos if (nr->p_diag_cur_state != NULL) { 230 1.1 christos if (nr->in_congestion_recovery) 231 1.1 christos *nr->p_diag_cur_state = 'R'; 232 1.1 christos else if (nr->cong_wnd < nr->slow_start_thresh) 233 1.1 christos *nr->p_diag_cur_state = 'S'; 234 1.1 christos else 235 1.1 christos *nr->p_diag_cur_state = 'A'; 236 1.1 christos } 237 1.1 christos } 238 1.1 christos 239 1.1 christos static int newreno_in_cong_recovery(OSSL_CC_NEWRENO *nr, OSSL_TIME tx_time) 240 1.1 christos { 241 1.1 christos return ossl_time_compare(tx_time, nr->cong_recovery_start_time) <= 0; 242 1.1 christos } 243 1.1 christos 244 1.1 christos static void newreno_cong(OSSL_CC_NEWRENO *nr, OSSL_TIME tx_time) 245 1.1 christos { 246 1.1 christos int err = 0; 247 1.1 christos 248 1.1 christos /* No reaction if already in a recovery period. */ 249 1.1 christos if (newreno_in_cong_recovery(nr, tx_time)) 250 1.1 christos return; 251 1.1 christos 252 1.1 christos /* Start a new recovery period. */ 253 1.1 christos nr->in_congestion_recovery = 1; 254 1.1 christos nr->cong_recovery_start_time = nr->now_cb(nr->now_cb_arg); 255 1.1 christos 256 1.1 christos /* slow_start_thresh = cong_wnd * loss_reduction_factor */ 257 1.1 christos nr->slow_start_thresh 258 1.1 christos = safe_muldiv_u64(nr->cong_wnd, 259 1.1.1.2 christos nr->k_loss_reduction_factor_num, 260 1.1.1.2 christos nr->k_loss_reduction_factor_den, 261 1.1.1.2 christos &err); 262 1.1 christos 263 1.1 christos if (err) 264 1.1 christos nr->slow_start_thresh = UINT64_MAX; 265 1.1 christos 266 1.1 christos nr->cong_wnd = nr->slow_start_thresh; 267 1.1 christos if (nr->cong_wnd < nr->k_min_wnd) 268 1.1 christos nr->cong_wnd = nr->k_min_wnd; 269 1.1 christos } 270 1.1 christos 271 1.1 christos static void newreno_flush(OSSL_CC_NEWRENO *nr, uint32_t flags) 272 1.1 christos { 273 1.1 christos if (!nr->processing_loss) 274 1.1 christos return; 275 1.1 christos 276 1.1 christos newreno_cong(nr, nr->tx_time_of_last_loss); 277 1.1 christos 278 1.1 christos if ((flags & OSSL_CC_LOST_FLAG_PERSISTENT_CONGESTION) != 0) { 279 1.1.1.2 christos nr->cong_wnd = nr->k_min_wnd; 280 1.1.1.2 christos nr->cong_recovery_start_time = ossl_time_zero(); 281 1.1 christos } 282 1.1 christos 283 1.1 christos nr->processing_loss = 0; 284 1.1 christos newreno_update_diag(nr); 285 1.1 christos } 286 1.1 christos 287 1.1 christos static uint64_t newreno_get_tx_allowance(OSSL_CC_DATA *cc) 288 1.1 christos { 289 1.1 christos OSSL_CC_NEWRENO *nr = (OSSL_CC_NEWRENO *)cc; 290 1.1 christos 291 1.1 christos if (nr->bytes_in_flight >= nr->cong_wnd) 292 1.1 christos return 0; 293 1.1 christos 294 1.1 christos return nr->cong_wnd - nr->bytes_in_flight; 295 1.1 christos } 296 1.1 christos 297 1.1 christos static OSSL_TIME newreno_get_wakeup_deadline(OSSL_CC_DATA *cc) 298 1.1 christos { 299 1.1 christos if (newreno_get_tx_allowance(cc) > 0) { 300 1.1 christos /* We have TX allowance now so wakeup immediately */ 301 1.1 christos return ossl_time_zero(); 302 1.1 christos } else { 303 1.1 christos /* 304 1.1 christos * The NewReno congestion controller does not vary its state in time, 305 1.1 christos * only in response to stimulus. 306 1.1 christos */ 307 1.1 christos return ossl_time_infinite(); 308 1.1 christos } 309 1.1 christos } 310 1.1 christos 311 1.1 christos static int newreno_on_data_sent(OSSL_CC_DATA *cc, uint64_t num_bytes) 312 1.1 christos { 313 1.1 christos OSSL_CC_NEWRENO *nr = (OSSL_CC_NEWRENO *)cc; 314 1.1 christos 315 1.1 christos nr->bytes_in_flight += num_bytes; 316 1.1 christos newreno_update_diag(nr); 317 1.1 christos return 1; 318 1.1 christos } 319 1.1 christos 320 1.1 christos static int newreno_is_cong_limited(OSSL_CC_NEWRENO *nr) 321 1.1 christos { 322 1.1 christos uint64_t wnd_rem; 323 1.1 christos 324 1.1 christos /* We are congestion-limited if we are already at the congestion window. */ 325 1.1 christos if (nr->bytes_in_flight >= nr->cong_wnd) 326 1.1 christos return 1; 327 1.1 christos 328 1.1 christos wnd_rem = nr->cong_wnd - nr->bytes_in_flight; 329 1.1 christos 330 1.1 christos /* 331 1.1 christos * Consider ourselves congestion-limited if less than three datagrams' worth 332 1.1 christos * of congestion window remains to be spent, or if we are in slow start and 333 1.1 christos * have consumed half of our window. 334 1.1 christos */ 335 1.1 christos return (nr->cong_wnd < nr->slow_start_thresh && wnd_rem <= nr->cong_wnd / 2) 336 1.1.1.2 christos || wnd_rem <= 3 * nr->max_dgram_size; 337 1.1 christos } 338 1.1 christos 339 1.1 christos static int newreno_on_data_acked(OSSL_CC_DATA *cc, 340 1.1.1.2 christos const OSSL_CC_ACK_INFO *info) 341 1.1 christos { 342 1.1 christos OSSL_CC_NEWRENO *nr = (OSSL_CC_NEWRENO *)cc; 343 1.1 christos 344 1.1 christos /* 345 1.1 christos * Packet has been acked. Firstly, remove it from the aggregate count of 346 1.1 christos * bytes in flight. 347 1.1 christos */ 348 1.1 christos nr->bytes_in_flight -= info->tx_size; 349 1.1 christos 350 1.1 christos /* 351 1.1 christos * We use acknowledgement of data as a signal that we are not at channel 352 1.1 christos * capacity and that it may be reasonable to increase the congestion window. 353 1.1 christos * However, acknowledgement is not a useful signal that there is further 354 1.1 christos * capacity if we are not actually saturating the congestion window that we 355 1.1 christos * already have (for example, if the application is not generating much data 356 1.1 christos * or we are limited by flow control). Therefore, we only expand the 357 1.1 christos * congestion window if we are consuming a significant fraction of the 358 1.1 christos * congestion window. 359 1.1 christos */ 360 1.1 christos if (!newreno_is_cong_limited(nr)) 361 1.1 christos goto out; 362 1.1 christos 363 1.1 christos /* 364 1.1 christos * We can handle acknowledgement of a packet in one of three ways 365 1.1 christos * depending on our current state: 366 1.1 christos * 367 1.1 christos * - Congestion Recovery: Do nothing. We don't start increasing 368 1.1 christos * the congestion window in response to acknowledgements until 369 1.1 christos * we are no longer in the Congestion Recovery state. 370 1.1 christos * 371 1.1 christos * - Slow Start: Increase the congestion window using the slow 372 1.1 christos * start scale. 373 1.1 christos * 374 1.1 christos * - Congestion Avoidance: Increase the congestion window using 375 1.1 christos * the congestion avoidance scale. 376 1.1 christos */ 377 1.1 christos if (newreno_in_cong_recovery(nr, info->tx_time)) { 378 1.1 christos /* Congestion recovery, do nothing. */ 379 1.1 christos } else if (nr->cong_wnd < nr->slow_start_thresh) { 380 1.1 christos /* When this condition is true we are in the Slow Start state. */ 381 1.1 christos nr->cong_wnd += info->tx_size; 382 1.1 christos nr->in_congestion_recovery = 0; 383 1.1 christos } else { 384 1.1 christos /* Otherwise, we are in the Congestion Avoidance state. */ 385 1.1 christos nr->bytes_acked += info->tx_size; 386 1.1 christos 387 1.1 christos /* 388 1.1 christos * Avoid integer division as per RFC 9002 s. B.5. / RFC3465 s. 2.1. 389 1.1 christos */ 390 1.1 christos if (nr->bytes_acked >= nr->cong_wnd) { 391 1.1 christos nr->bytes_acked -= nr->cong_wnd; 392 1.1.1.2 christos nr->cong_wnd += nr->max_dgram_size; 393 1.1 christos } 394 1.1 christos 395 1.1 christos nr->in_congestion_recovery = 0; 396 1.1 christos } 397 1.1 christos 398 1.1 christos out: 399 1.1 christos newreno_update_diag(nr); 400 1.1 christos return 1; 401 1.1 christos } 402 1.1 christos 403 1.1 christos static int newreno_on_data_lost(OSSL_CC_DATA *cc, 404 1.1.1.2 christos const OSSL_CC_LOSS_INFO *info) 405 1.1 christos { 406 1.1 christos OSSL_CC_NEWRENO *nr = (OSSL_CC_NEWRENO *)cc; 407 1.1 christos 408 1.1 christos if (info->tx_size > nr->bytes_in_flight) 409 1.1 christos return 0; 410 1.1 christos 411 1.1 christos nr->bytes_in_flight -= info->tx_size; 412 1.1 christos 413 1.1 christos if (!nr->processing_loss) { 414 1.1 christos 415 1.1 christos if (ossl_time_compare(info->tx_time, nr->tx_time_of_last_loss) <= 0) 416 1.1 christos /* 417 1.1 christos * After triggering congestion due to a lost packet at time t, don't 418 1.1 christos * trigger congestion again due to any subsequently detected lost 419 1.1 christos * packet at a time s < t, as we've effectively already signalled 420 1.1 christos * congestion on loss of that and subsequent packets. 421 1.1 christos */ 422 1.1 christos goto out; 423 1.1 christos 424 1.1 christos nr->processing_loss = 1; 425 1.1 christos 426 1.1 christos /* 427 1.1 christos * Cancel any pending window increase in the Congestion Avoidance state. 428 1.1 christos */ 429 1.1 christos nr->bytes_acked = 0; 430 1.1 christos } 431 1.1 christos 432 1.1 christos nr->tx_time_of_last_loss 433 1.1 christos = ossl_time_max(nr->tx_time_of_last_loss, info->tx_time); 434 1.1 christos 435 1.1 christos out: 436 1.1 christos newreno_update_diag(nr); 437 1.1 christos return 1; 438 1.1 christos } 439 1.1 christos 440 1.1 christos static int newreno_on_data_lost_finished(OSSL_CC_DATA *cc, uint32_t flags) 441 1.1 christos { 442 1.1 christos OSSL_CC_NEWRENO *nr = (OSSL_CC_NEWRENO *)cc; 443 1.1 christos 444 1.1 christos newreno_flush(nr, flags); 445 1.1 christos return 1; 446 1.1 christos } 447 1.1 christos 448 1.1 christos static int newreno_on_data_invalidated(OSSL_CC_DATA *cc, 449 1.1.1.2 christos uint64_t num_bytes) 450 1.1 christos { 451 1.1 christos OSSL_CC_NEWRENO *nr = (OSSL_CC_NEWRENO *)cc; 452 1.1 christos 453 1.1 christos nr->bytes_in_flight -= num_bytes; 454 1.1 christos newreno_update_diag(nr); 455 1.1 christos return 1; 456 1.1 christos } 457 1.1 christos 458 1.1 christos static int newreno_on_ecn(OSSL_CC_DATA *cc, 459 1.1.1.2 christos const OSSL_CC_ECN_INFO *info) 460 1.1 christos { 461 1.1 christos OSSL_CC_NEWRENO *nr = (OSSL_CC_NEWRENO *)cc; 462 1.1 christos 463 1.1.1.2 christos nr->processing_loss = 1; 464 1.1.1.2 christos nr->bytes_acked = 0; 465 1.1.1.2 christos nr->tx_time_of_last_loss = info->largest_acked_time; 466 1.1 christos newreno_flush(nr, 0); 467 1.1 christos return 1; 468 1.1 christos } 469 1.1 christos 470 1.1 christos const OSSL_CC_METHOD ossl_cc_newreno_method = { 471 1.1 christos newreno_new, 472 1.1 christos newreno_free, 473 1.1 christos newreno_reset, 474 1.1 christos newreno_set_input_params, 475 1.1 christos newreno_bind_diagnostic, 476 1.1 christos newreno_unbind_diagnostic, 477 1.1 christos newreno_get_tx_allowance, 478 1.1 christos newreno_get_wakeup_deadline, 479 1.1 christos newreno_on_data_sent, 480 1.1 christos newreno_on_data_acked, 481 1.1 christos newreno_on_data_lost, 482 1.1 christos newreno_on_data_lost_finished, 483 1.1 christos newreno_on_data_invalidated, 484 1.1 christos newreno_on_ecn, 485 1.1 christos }; 486