diff options
-rw-r--r-- | src/vnet/tcp/tcp.c | 25 | ||||
-rw-r--r-- | src/vnet/tcp/tcp.h | 10 | ||||
-rw-r--r-- | src/vnet/tcp/tcp_cubic.c | 44 | ||||
-rw-r--r-- | src/vnet/tcp/tcp_newreno.c | 1 |
4 files changed, 73 insertions, 7 deletions
diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c index 2511a176e00..25c2615b101 100644 --- a/src/vnet/tcp/tcp.c +++ b/src/vnet/tcp/tcp.c @@ -1448,6 +1448,29 @@ unformat_tcp_cc_algo (unformat_input_t * input, va_list * va) return 1; } +uword +unformat_tcp_cc_algo_cfg (unformat_input_t * input, va_list * va) +{ + tcp_main_t *tm = vnet_get_tcp_main (); + tcp_cc_algorithm_t *cc_alg; + unformat_input_t sub_input; + int found = 0; + + vec_foreach (cc_alg, tm->cc_algos) + { + if (!unformat (input, cc_alg->name)) + continue; + + if (cc_alg->unformat_cfg + && unformat (input, "%U", unformat_vlib_cli_sub_input, &sub_input)) + { + if (cc_alg->unformat_cfg (&sub_input)) + found = 1; + } + } + return found; +} + static clib_error_t * tcp_config_fn (vlib_main_t * vm, unformat_input_t * input) { @@ -1472,6 +1495,8 @@ tcp_config_fn (vlib_main_t * vm, unformat_input_t * input) else if (unformat (input, "cc-algo %U", unformat_tcp_cc_algo, &tm->cc_algo)) ; + else if (unformat (input, "%U", unformat_tcp_cc_algo_cfg)) + ; else return clib_error_return (0, "unknown input `%U'", format_unformat_error, input); diff --git a/src/vnet/tcp/tcp.h b/src/vnet/tcp/tcp.h index d4bebeb47b8..5b235b65d74 100644 --- a/src/vnet/tcp/tcp.h +++ b/src/vnet/tcp/tcp.h @@ -30,7 +30,7 @@ #define TCP_PAWS_IDLE 24 * 24 * 60 * 60 * THZ /**< 24 days */ #define TCP_FIB_RECHECK_PERIOD 1 * THZ /**< Recheck every 1s */ #define TCP_MAX_OPTION_SPACE 40 -#define TCP_CC_DATA_SZ 20 +#define TCP_CC_DATA_SZ 24 #define TCP_DUPACK_THRESHOLD 3 #define TCP_MAX_RX_FIFO_SIZE 32 << 20 @@ -336,14 +336,18 @@ typedef struct _tcp_connection u32 tx_fifo_size; /**< Tx fifo size. Used to constrain cwnd */ } tcp_connection_t; +/* *INDENT-OFF* */ struct _tcp_cc_algorithm { + const char *name; + uword (*unformat_cfg) (unformat_input_t * input); void (*rcv_ack) (tcp_connection_t * tc); void (*rcv_cong_ack) (tcp_connection_t * tc, tcp_cc_ack_t ack); void (*congestion) (tcp_connection_t * tc); void (*recovered) (tcp_connection_t * tc); void (*init) (tcp_connection_t * tc); }; +/* *INDENT-ON* */ #define tcp_fastrecovery_on(tc) (tc)->flags |= TCP_CONN_FAST_RECOVERY #define tcp_fastrecovery_off(tc) (tc)->flags &= ~TCP_CONN_FAST_RECOVERY @@ -485,7 +489,9 @@ typedef struct _tcp_main /** fault-injection */ f64 buffer_fail_fraction; - u8 cc_algo; + /** Default congestion control algorithm type */ + tcp_cc_algorithm_type_e cc_algo; + } tcp_main_t; extern tcp_main_t tcp_main; diff --git a/src/vnet/tcp/tcp_cubic.c b/src/vnet/tcp/tcp_cubic.c index b9a1c3da06a..55bbcca3497 100644 --- a/src/vnet/tcp/tcp_cubic.c +++ b/src/vnet/tcp/tcp_cubic.c @@ -20,6 +20,15 @@ #define cubic_c 0.4 #define west_const (3 * (1 - beta_cubic) / (1 + beta_cubic)) +typedef struct cubic_cfg_ +{ + u8 fast_convergence; +} cubic_cfg_t; + +static cubic_cfg_t cubic_cfg = { + .fast_convergence = 1, +}; + typedef struct cubic_data_ { /** time period (in seconds) needed to increase the current window @@ -29,7 +38,7 @@ typedef struct cubic_data_ /** time (in sec) since the start of current congestion avoidance */ f64 t_start; - /** Inflection point of the cubic function */ + /** Inflection point of the cubic function (in snd_mss segments) */ u32 w_max; } __clib_packed cubic_data_t; @@ -84,8 +93,13 @@ static void cubic_congestion (tcp_connection_t * tc) { cubic_data_t *cd = (cubic_data_t *) tcp_cc_data (tc); + u32 w_max; + + w_max = tc->cwnd / tc->snd_mss; + if (cubic_cfg.fast_convergence && w_max < cd->w_max) + w_max = w_max * ((1.0 + beta_cubic) / 2.0); - cd->w_max = tc->cwnd / tc->snd_mss; + cd->w_max = w_max; tc->ssthresh = clib_max (tc->cwnd * beta_cubic, 2 * tc->snd_mss); } @@ -120,7 +134,7 @@ cubic_rcv_ack (tcp_connection_t * tc) rtt_sec = clib_min (tc->mrtt_us, (f64) tc->srtt * TCP_TICK); w_cubic = W_cubic (cd, t + rtt_sec) * tc->snd_mss; - w_aimd = W_est (cd, t, rtt_sec) * tc->snd_mss; + w_aimd = (u64) W_est (cd, t, rtt_sec) * tc->snd_mss; if (w_cubic < w_aimd) { tcp_cwnd_accumulate (tc, tc->cwnd, tc->bytes_acked); @@ -148,7 +162,7 @@ cubic_rcv_ack (tcp_connection_t * tc) else { /* Practically we can't increment so just inflate threshold */ - thresh = 1000 * tc->cwnd; + thresh = 50 * tc->cwnd; } tcp_cwnd_accumulate (tc, thresh, tc->bytes_acked); } @@ -165,12 +179,32 @@ cubic_conn_init (tcp_connection_t * tc) cd->t_start = cubic_time (tc->c_thread_index); } +static uword +cubic_unformat_config (unformat_input_t * input) +{ + if (!input) + return 0; + + unformat_skip_white_space (input); + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "no-fast-convergence")) + cubic_cfg.fast_convergence = 0; + else + return 0; + } + return 1; +} + const static tcp_cc_algorithm_t tcp_cubic = { + .name = "cubic", + .unformat_cfg = cubic_unformat_config, .congestion = cubic_congestion, .recovered = cubic_recovered, .rcv_ack = cubic_rcv_ack, .rcv_cong_ack = newreno_rcv_cong_ack, - .init = cubic_conn_init + .init = cubic_conn_init, }; clib_error_t * diff --git a/src/vnet/tcp/tcp_newreno.c b/src/vnet/tcp/tcp_newreno.c index 420e47a8ca4..e36416cdfe1 100644 --- a/src/vnet/tcp/tcp_newreno.c +++ b/src/vnet/tcp/tcp_newreno.c @@ -79,6 +79,7 @@ newreno_conn_init (tcp_connection_t * tc) } const static tcp_cc_algorithm_t tcp_newreno = { + .name = "newreno", .congestion = newreno_congestion, .recovered = newreno_recovered, .rcv_ack = newreno_rcv_ack, |