diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1529,7 +1529,7 @@ struct mbuf *mfree; struct tcpopt to; int tfo_syn; - u_int maxseg; + u_int maxseg = 0; thflags = tcp_get_flags(th); tp->sackhint.last_sack_ack = 0; @@ -2596,7 +2596,7 @@ if (V_tcp_do_prr && IN_FASTRECOVERY(tp->t_flags) && (tp->t_flags & TF_SACK_PERMIT)) { - tcp_do_prr_ack(tp, th, &to, sack_changed); + tcp_do_prr_ack(tp, th, &to, sack_changed, &maxseg); } else if (tcp_is_sack_recovery(tp, &to) && IN_FASTRECOVERY(tp->t_flags)) { int awnd; @@ -2805,11 +2805,12 @@ if (V_tcp_do_prr && to.to_flags & TOF_SACK) { tcp_timer_activate(tp, TT_REXMT, 0); tp->t_rtttime = 0; - tcp_do_prr_ack(tp, th, &to, sack_changed); + tcp_do_prr_ack(tp, th, &to, sack_changed, + &maxseg); tp->t_flags |= TF_ACKNOW; (void) tcp_output(tp); } else - tcp_sack_partialack(tp, th); + tcp_sack_partialack(tp, th, &maxseg); else tcp_newreno_partial_ack(tp, th); } else @@ -2823,7 +2824,7 @@ * During ECN cwnd reduction * always use PRR-SSRB */ - tcp_do_prr_ack(tp, th, &to, SACK_CHANGE); + tcp_do_prr_ack(tp, th, &to, SACK_CHANGE, &maxseg); (void) tcp_output(tp); } } else @@ -3946,13 +3947,15 @@ } void -tcp_do_prr_ack(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to, sackstatus_t sack_changed) +tcp_do_prr_ack(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to, sackstatus_t sack_changed, u_int *maxseg) { int snd_cnt = 0, limit = 0, del_data = 0, pipe = 0; - int maxseg = tcp_maxseg(tp); INP_WLOCK_ASSERT(tptoinpcb(tp)); + if (*maxseg == 0) { + *maxseg = tcp_maxseg(tp); + } /* * Compute the amount of data that this ACK is indicating * (del_data) and an estimate of how many bytes are in the @@ -3968,11 +3971,11 @@ pipe = (tp->snd_nxt - tp->snd_fack) + tp->sackhint.sack_bytes_rexmit; } else { - if (tp->sackhint.prr_delivered < (tcprexmtthresh * maxseg + + if (tp->sackhint.prr_delivered < (tcprexmtthresh * *maxseg + tp->snd_recover - tp->snd_una)) - del_data = maxseg; + del_data = *maxseg; pipe = imax(0, tp->snd_max - tp->snd_una - - imin(INT_MAX / 65536, tp->t_dupacks) * maxseg); + imin(INT_MAX / 65536, tp->t_dupacks) * *maxseg); } tp->sackhint.prr_delivered += del_data; /* @@ -3984,7 +3987,7 @@ imax(1, tp->snd_nxt - tp->snd_una); snd_cnt = howmany((long)tp->sackhint.prr_delivered * tp->snd_ssthresh, tp->sackhint.recover_fs) - - tp->sackhint.prr_out + maxseg - 1; + tp->sackhint.prr_out + *maxseg - 1; } else { /* * PRR 6937bis heuristic: @@ -4002,10 +4005,10 @@ else limit = imax(tp->sackhint.prr_delivered - tp->sackhint.prr_out, del_data) + - maxseg; + *maxseg; snd_cnt = imin((tp->snd_ssthresh - pipe), limit); } - snd_cnt = imax(snd_cnt, 0) / maxseg; + snd_cnt = imax(snd_cnt, 0) / *maxseg; /* * Send snd_cnt new data into the network in response to this ack. * If there is going to be a SACK retransmission, adjust snd_cwnd @@ -4015,14 +4018,14 @@ if (tcp_is_sack_recovery(tp, to)) { tp->snd_cwnd = tp->snd_nxt - tp->snd_recover + tp->sackhint.sack_bytes_rexmit + - (snd_cnt * maxseg); + (snd_cnt * *maxseg); } else { tp->snd_cwnd = (tp->snd_max - tp->snd_una) + - (snd_cnt * maxseg); + (snd_cnt * *maxseg); } } else if (IN_CONGRECOVERY(tp->t_flags)) - tp->snd_cwnd = pipe - del_data + (snd_cnt * maxseg); - tp->snd_cwnd = imax(maxseg, tp->snd_cwnd); + tp->snd_cwnd = pipe - del_data + (snd_cnt * *maxseg); + tp->snd_cwnd = imax(*maxseg, tp->snd_cwnd); } /* diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c --- a/sys/netinet/tcp_sack.c +++ b/sys/netinet/tcp_sack.c @@ -936,20 +936,23 @@ * the midst of sack recovery. */ void -tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th) +tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th, u_int *maxseg) { struct sackhole *temp; int num_segs = 1; - u_int maxseg = tcp_maxseg(tp); INP_WLOCK_ASSERT(tptoinpcb(tp)); + + if (*maxseg == 0) { + *maxseg = tcp_maxseg(tp); + } tcp_timer_activate(tp, TT_REXMT, 0); tp->t_rtttime = 0; /* Send one or 2 segments based on how much new data was acked. */ - if ((BYTES_THIS_ACK(tp, th) / maxseg) >= 2) + if ((BYTES_THIS_ACK(tp, th) / *maxseg) >= 2) num_segs = 2; tp->snd_cwnd = (tp->sackhint.sack_bytes_rexmit + - (tp->snd_nxt - tp->snd_recover) + num_segs * maxseg); + (tp->snd_nxt - tp->snd_recover) + num_segs * *maxseg); if (tp->snd_cwnd > tp->snd_ssthresh) tp->snd_cwnd = tp->snd_ssthresh; tp->t_flags |= TF_ACKNOW; @@ -986,7 +989,7 @@ if (th->th_ack != highdata) { tp->snd_fack = th->th_ack; if ((temp = tcp_sackhole_insert(tp, SEQ_MAX(th->th_ack, - highdata - maxseg), highdata, NULL)) != NULL) + highdata - *maxseg), highdata, NULL)) != NULL) tp->sackhint.hole_bytes += temp->end - temp->start; } diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1486,9 +1486,9 @@ void tcp_clean_sackreport(struct tcpcb *tp); void tcp_sack_adjust(struct tcpcb *tp); struct sackhole *tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt); -void tcp_do_prr_ack(struct tcpcb *, struct tcphdr *, struct tcpopt *, sackstatus_t); +void tcp_do_prr_ack(struct tcpcb *, struct tcphdr *, struct tcpopt *, sackstatus_t, u_int *); void tcp_lost_retransmission(struct tcpcb *, struct tcphdr *); -void tcp_sack_partialack(struct tcpcb *, struct tcphdr *); +void tcp_sack_partialack(struct tcpcb *, struct tcphdr *, u_int *); void tcp_resend_sackholes(struct tcpcb *tp); void tcp_free_sackholes(struct tcpcb *tp); void tcp_sack_lost_retransmission(struct tcpcb *, struct tcphdr *);