static void tcp_cubic_ack_rcvd(struct tcpcb *tp, struct tcphdr *th) { /* Do not increase the congestion window in non-validated phase */ if (tcp_cc_is_cwnd_nonvalidated(tp) != 0) return; if (tp->snd_cwnd >= tp->snd_ssthresh) { /* Congestion avoidance phase */ tcp_cubic_congestion_avd(tp, th); } else { /* * Use 2*SMSS as limit on increment as suggested * by RFC 3465 section 2.3 */ uint32_t acked, abc_lim, incr; acked = BYTES_ACKED(th, tp); abc_lim = (tcp_do_rfc3465_lim2 && tp->snd_nxt == tp->snd_max) ? 2 * tp->t_maxseg : tp->t_maxseg; incr = min(acked, abc_lim); tp->snd_cwnd += incr; tp->snd_cwnd = min(tp->snd_cwnd, TCP_MAXWIN << tp->snd_scale); } }
/* Function to process an ack. */ void tcp_newreno_ack_rcvd(struct tcpcb *tp, struct tcphdr *th) { /* * RFC 3465 - Appropriate Byte Counting. * * If the window is currently less than ssthresh, * open the window by the number of bytes ACKed by * the last ACK, however clamp the window increase * to an upper limit "L". * * In congestion avoidance phase, open the window by * one segment each time "bytes_acked" grows to be * greater than or equal to the congestion window. */ u_int cw = tp->snd_cwnd; u_int incr = tp->t_maxseg; int acked = 0; acked = BYTES_ACKED(th, tp); if (tcp_do_rfc3465) { if (cw >= tp->snd_ssthresh) { tp->t_bytes_acked += acked; if (tp->t_bytes_acked >= cw) { /* Time to increase the window. */ tp->t_bytes_acked -= cw; } else { /* No need to increase yet. */ incr = 0; } } else { /* * If the user explicitly enables RFC3465 * use 2*SMSS for the "L" param. Otherwise * use the more conservative 1*SMSS. * * (See RFC 3465 2.3 Choosing the Limit) */ uint32_t abc_lim; abc_lim = (tcp_do_rfc3465_lim2 && tp->snd_nxt == tp->snd_max) ? incr * 2 : incr; incr = lmin(acked, abc_lim); } } else { /* * If the window gives us less than ssthresh packets * in flight, open exponentially (segsz per packet). * Otherwise open linearly: segsz per window * (segsz^2 / cwnd per packet). */ if (cw >= tp->snd_ssthresh) incr = max((incr * incr / cw), 1); } tp->snd_cwnd = min(cw+incr, TCP_MAXWIN<<tp->snd_scale); }
/* * Handle an in-sequence ack during congestion avoidance phase. */ static void tcp_cubic_congestion_avd(struct tcpcb *tp, struct tcphdr *th) { u_int32_t cubic_target_win, tcp_win, rtt; /* Do not increase congestion window in non-validated phase */ if (tcp_cc_is_cwnd_nonvalidated(tp) != 0) return; tp->t_bytes_acked += BYTES_ACKED(th, tp); rtt = get_base_rtt(tp); /* * First compute cubic window. If cubic variables are not * initialized (after coming out of recovery), this call will * initialize them. */ cubic_target_win = tcp_cubic_update(tp, rtt); /* Compute TCP window if a multiplicative decrease of 0.2 is used */ tcp_win = tcp_cubic_tcpwin(tp, th); if (tp->snd_cwnd < tcp_win && (tcp_cubic_tcp_friendliness == 1 || TCP_CUBIC_ENABLE_TCPMODE(tp))) { /* this connection is in TCP-friendly region */ if (tp->t_bytes_acked >= tp->snd_cwnd) { tp->t_bytes_acked -= tp->snd_cwnd; tp->snd_cwnd = min(tcp_win, TCP_MAXWIN << tp->snd_scale); } } else { if (cubic_target_win > tp->snd_cwnd) { /* * The target win is computed for the next RTT. * To reach this value, cwnd will have to be updated * one segment at a time. Compute how many bytes * need to be acknowledged before we can increase * the cwnd by one segment. */ u_int64_t incr_win; incr_win = tp->snd_cwnd * tp->t_maxseg; incr_win /= (cubic_target_win - tp->snd_cwnd); if (incr_win > 0 && tp->t_bytes_acked >= incr_win) { tp->t_bytes_acked -= incr_win; tp->snd_cwnd = min((tp->snd_cwnd + tp->t_maxseg), TCP_MAXWIN << tp->snd_scale); } } } }
/* Function to handle an in-sequence ack during congestion avoidance phase. * This will get called from header prediction code. */ void tcp_newreno_congestion_avd(struct tcpcb *tp, struct tcphdr *th) { uint32_t acked = 0; acked = BYTES_ACKED(th, tp); /* * Grow the congestion window, if the * connection is cwnd bound. */ if (tp->snd_cwnd < tp->snd_wnd) { tp->t_bytes_acked += acked; if (tp->t_bytes_acked > tp->snd_cwnd) { tp->t_bytes_acked -= tp->snd_cwnd; tp->snd_cwnd += tp->t_maxseg; } } }
/* Function to handle an in-sequence ack which is fast-path processing * of an in sequence ack in tcp_input function (called as header prediction). * This gets called only during congestion avoidance phase. */ void tcp_ledbat_congestion_avd(struct tcpcb *tp, struct tcphdr *th) { int acked = 0; u_int32_t incr = 0; acked = BYTES_ACKED(th, tp); tp->t_bytes_acked += acked; if (tp->t_bytes_acked > tp->snd_cwnd) { tp->t_bytes_acked -= tp->snd_cwnd; incr = tp->t_maxseg; } if (tp->snd_cwnd < tp->snd_wnd && incr > 0) { update_cwnd(tp, incr); } }
/* Function to process an ack. */ void tcp_ledbat_ack_rcvd(struct tcpcb *tp, struct tcphdr *th) { /* * RFC 3465 - Appropriate Byte Counting. * * If the window is currently less than ssthresh, * open the window by the number of bytes ACKed by * the last ACK, however clamp the window increase * to an upper limit "L". * * In congestion avoidance phase, open the window by * one segment each time "bytes_acked" grows to be * greater than or equal to the congestion window. */ register u_int cw = tp->snd_cwnd; register u_int incr = tp->t_maxseg; int acked = 0; acked = BYTES_ACKED(th, tp); tp->t_bytes_acked += acked; if (cw >= tp->bg_ssthresh) { /* congestion-avoidance */ if (tp->t_bytes_acked < cw) { /* No need to increase yet. */ incr = 0; } } else { /* * If the user explicitly enables RFC3465 * use 2*SMSS for the "L" param. Otherwise * use the more conservative 1*SMSS. * * (See RFC 3465 2.3 Choosing the Limit) */ u_int abc_lim; abc_lim = (tcp_do_rfc3465_lim2 && tp->snd_nxt == tp->snd_max) ? incr * 2 : incr; incr = lmin(acked, abc_lim); } if (tp->t_bytes_acked >= cw) tp->t_bytes_acked -= cw; if (incr > 0) update_cwnd(tp, incr); }
/* * Compute the window growth if standard TCP (AIMD) was used with * a backoff of 0.5 and additive increase of 1 packet per RTT. * * TCP window at time t can be calculated using the following equation * with beta as 0.8 * * W(t) <- Wmax * beta + 3 * ((1 - beta)/(1 + beta)) * t/RTT * */ static uint32_t tcp_cubic_tcpwin(struct tcpcb *tp, struct tcphdr *th) { if (tp->t_ccstate->cub_tcp_win == 0) { tp->t_ccstate->cub_tcp_win = min(tp->snd_cwnd, tp->snd_wnd); tp->t_ccstate->cub_tcp_bytes_acked = 0; } else { tp->t_ccstate->cub_tcp_bytes_acked += BYTES_ACKED(th, tp); if (tp->t_ccstate->cub_tcp_bytes_acked >= tp->t_ccstate->cub_tcp_win) { tp->t_ccstate->cub_tcp_bytes_acked -= tp->t_ccstate->cub_tcp_win; tp->t_ccstate->cub_tcp_win += tp->t_maxseg; } } return (tp->t_ccstate->cub_tcp_win); }