Re: Refactor TCP partial ACK handling
On Tue, Oct 24, 2017 at 03:21:08PM +0200, Mike Belopuhov wrote: > I didn't do it because tcp_var.h is where tcp keeps all of it's prototypes > but I don't mind moving them into tcp_input.c. Any objections? Otherwise > I'll check in the diff below. ok job@
Re: Refactor TCP partial ACK handling
On Tue, Oct 24, 2017 at 03:21:08PM +0200, Mike Belopuhov wrote: > I didn't do it because tcp_var.h is where tcp keeps all of it's prototypes > but I don't mind moving them into tcp_input.c. Any objections? Otherwise > I'll check in the diff below. Regression tests pass. OK bluhm@ > diff --git sys/netinet/tcp_input.c sys/netinet/tcp_input.c > index 790e163975e..8d172e2905c 100644 > --- sys/netinet/tcp_input.c > +++ sys/netinet/tcp_input.c > @@ -183,10 +183,13 @@ do { \ > else \ > TCP_SET_DELACK(tp); \ > if_put(ifp); \ > } while (0) > > +void tcp_sack_partialack(struct tcpcb *, struct tcphdr *); > +void tcp_newreno_partialack(struct tcpcb *, struct tcphdr *); > + > void syn_cache_put(struct syn_cache *); > void syn_cache_rm(struct syn_cache *); > int syn_cache_respond(struct syn_cache *, struct mbuf *); > void syn_cache_timer(void *); > void syn_cache_reaper(void *); > @@ -1664,52 +1667,39 @@ trimthenstep6: > } > /* >* If the congestion window was inflated to account >* for the other side's cached packets, retract it. >*/ > - if (tp->sack_enable) { > - if (tp->t_dupacks >= tcprexmtthresh) { > - /* Check for a partial ACK */ > - if (tcp_sack_partialack(tp, th)) { > -#ifdef TCP_FACK > - /* Force call to tcp_output */ > - if (tp->snd_awnd < tp->snd_cwnd) > - tp->t_flags |= TF_NEEDOUTPUT; > -#else > - tp->snd_cwnd += tp->t_maxseg; > - tp->t_flags |= TF_NEEDOUTPUT; > -#endif /* TCP_FACK */ > - } else { > - /* Out of fast recovery */ > - tp->snd_cwnd = tp->snd_ssthresh; > - if (tcp_seq_subtract(tp->snd_max, > - th->th_ack) < tp->snd_ssthresh) > - tp->snd_cwnd = > -tcp_seq_subtract(tp->snd_max, > -th->th_ack); > - tp->t_dupacks = 0; > -#ifdef TCP_FACK > - if (SEQ_GT(th->th_ack, tp->snd_fack)) > - tp->snd_fack = th->th_ack; > -#endif > - } > - } > - } else { > - if (tp->t_dupacks >= tcprexmtthresh && > - !tcp_newreno(tp, th)) { > + if (tp->t_dupacks >= tcprexmtthresh) { > + /* Check for a partial ACK */ > + if (SEQ_LT(th->th_ack, tp->snd_last)) { > + if (tp->sack_enable) > + tcp_sack_partialack(tp, th); > + else > + tcp_newreno_partialack(tp, th); > + } else { > /* Out of fast recovery */ > tp->snd_cwnd = tp->snd_ssthresh; > if (tcp_seq_subtract(tp->snd_max, th->th_ack) < > tp->snd_ssthresh) > tp->snd_cwnd = > tcp_seq_subtract(tp->snd_max, > th->th_ack); > tp->t_dupacks = 0; > +#ifdef TCP_FACK > + if (tp->sack_enable && > + SEQ_GT(th->th_ack, tp->snd_fack)) > + tp->snd_fack = th->th_ack; > +#endif > } > - } > - if (tp->t_dupacks < tcprexmtthresh) > + } else { > + /* > + * Reset the duplicate ACK counter if we > + * were not in fast recovery. > + */ > tp->t_dupacks = 0; > + } > if (SEQ_GT(th->th_ack, tp->snd_max)) { > tcpstat_inc(tcps_rcvacktoomuch); > goto dropafterack_ratelim; > } > acked = th->th_ack - tp->snd_una; > @@ -2703,36 +2693,38 @@ tcp_clean_sackreport(struct tcpcb *tp) > tp->sackblks[i].start = tp->sackblks[i].end=0; > > } > > /* > - * Checks for partial ack. If partial ack arrives, turn off retransmission > - * timer, deflate the window, do not clear tp->t_dupacks, and return 1. > - * If the ack advances at least to tp->snd_last, return 0. > + * Partial ack handling within a sack recovery episode. When a partial ack > + * arrives, turn off
Re: Refactor TCP partial ACK handling
On Tue, Oct 24, 2017 at 13:37 +0200, Martin Pieuchot wrote: > On 24/10/17(Tue) 12:27, Mike Belopuhov wrote: > > On Tue, Oct 24, 2017 at 12:05 +0200, Martin Pieuchot wrote: > > > On 21/10/17(Sat) 15:17, Mike Belopuhov wrote: > > > > On Fri, Oct 20, 2017 at 22:59 +0200, Klemens Nanni wrote: > > > > > The comments for both void tcp_{sack,newreno}_partialack() still > > > > > mention > > > > > tp->snd_last and return value bits. > > > > > > > > > > > > > Good eyes! It made me spot a mistake I made by folding two lines > > > > into an incorrect ifdef in tcp_sack_partialack. I expected it to > > > > say "ifdef TCP_FACK" while it says "ifNdef". The adjusted comment > > > > didn't make sense and I found the bug. > > > > > > Could you send the full/fixed diff? > > > > > > > Sure. > > Diff is correct. I have two suggestions, but it's ok mpi@ either way. > > > > And what about TCP_FACK? It is disabled by default, is there a > > > point in keeping it? > > > > Job has pointed out that RFC 6675 might be a better alternative > > so it might be a good idea to ditch it while we're at it. I'm > > not certain which parts need to be preserved (if any) however. > > I'd say remove it. One can always look in the Attic if necessary. > > > diff --git sys/netinet/tcp_input.c sys/netinet/tcp_input.c > > index 790e163975e..3809a2371f2 100644 > > --- sys/netinet/tcp_input.c > > +++ sys/netinet/tcp_input.c > > @@ -1664,52 +1664,38 @@ trimthenstep6: > > } > > /* > > * If the congestion window was inflated to account > > * for the other side's cached packets, retract it. > > */ > > - if (tp->sack_enable) { > > - if (tp->t_dupacks >= tcprexmtthresh) { > > - /* Check for a partial ACK */ > > - if (tcp_sack_partialack(tp, th)) { > > -#ifdef TCP_FACK > > - /* Force call to tcp_output */ > > - if (tp->snd_awnd < tp->snd_cwnd) > > - tp->t_flags |= TF_NEEDOUTPUT; > > -#else > > - tp->snd_cwnd += tp->t_maxseg; > > - tp->t_flags |= TF_NEEDOUTPUT; > > -#endif /* TCP_FACK */ > > - } else { > > - /* Out of fast recovery */ > > - tp->snd_cwnd = tp->snd_ssthresh; > > - if (tcp_seq_subtract(tp->snd_max, > > - th->th_ack) < tp->snd_ssthresh) > > - tp->snd_cwnd = > > - tcp_seq_subtract(tp->snd_max, > > - th->th_ack); > > - tp->t_dupacks = 0; > > -#ifdef TCP_FACK > > - if (SEQ_GT(th->th_ack, tp->snd_fack)) > > - tp->snd_fack = th->th_ack; > > -#endif > > - } > > - } > > - } else { > > - if (tp->t_dupacks >= tcprexmtthresh && > > - !tcp_newreno(tp, th)) { > > + if (tp->t_dupacks >= tcprexmtthresh) { > > I'd keep the comment: > > /* Check for a partial ACK */ Sure. > > diff --git sys/netinet/tcp_var.h sys/netinet/tcp_var.h > > index 6b797fd48e7..97b04884879 100644 > > --- sys/netinet/tcp_var.h > > +++ sys/netinet/tcp_var.h > > @@ -764,15 +764,15 @@ void tcp_update_sack_list(struct tcpcb *tp, > > tcp_seq, tcp_seq); > > voidtcp_del_sackholes(struct tcpcb *, struct tcphdr *); > > voidtcp_clean_sackreport(struct tcpcb *tp); > > voidtcp_sack_adjust(struct tcpcb *tp); > > struct sackhole * > > tcp_sack_output(struct tcpcb *tp); > > -int tcp_sack_partialack(struct tcpcb *, struct tcphdr *); > > +voidtcp_sack_partialack(struct tcpcb *, struct tcphdr *); > > +voidtcp_newreno_partialack(struct tcpcb *, struct tcphdr *); > > #ifdef DEBUG > > voidtcp_print_holes(struct tcpcb *tp); > > #endif > > -int tcp_newreno(struct tcpcb *, struct tcphdr *); > > I'd love to see these definitions moved to netinet/tcp_input.c. It > makes code audit much more simpler as you know that their are local. > I didn't do it because tcp_var.h is where tcp keeps all of it's prototypes but I don't mind moving them into tcp_input.c. Any objections? Otherwise I'll check in the diff below. diff --git sys/netinet/tcp_input.c sys/netinet/tcp_input.c index 790e163975e..8d172e2905c 100644 --- sys/netinet/tcp_input.c +++ sys/netinet/tcp_input.c @@ -183,10 +183,13 @@ do { \ else \ TCP_SET_DELACK(tp); \ if_put(ifp); \ } while (0) +voidtcp_sack_partialack(struct tcpcb *, struct tcphdr *); +void
Re: Refactor TCP partial ACK handling
On 24/10/17(Tue) 12:27, Mike Belopuhov wrote: > On Tue, Oct 24, 2017 at 12:05 +0200, Martin Pieuchot wrote: > > On 21/10/17(Sat) 15:17, Mike Belopuhov wrote: > > > On Fri, Oct 20, 2017 at 22:59 +0200, Klemens Nanni wrote: > > > > The comments for both void tcp_{sack,newreno}_partialack() still mention > > > > tp->snd_last and return value bits. > > > > > > > > > > Good eyes! It made me spot a mistake I made by folding two lines > > > into an incorrect ifdef in tcp_sack_partialack. I expected it to > > > say "ifdef TCP_FACK" while it says "ifNdef". The adjusted comment > > > didn't make sense and I found the bug. > > > > Could you send the full/fixed diff? > > > > Sure. Diff is correct. I have two suggestions, but it's ok mpi@ either way. > > And what about TCP_FACK? It is disabled by default, is there a > > point in keeping it? > > Job has pointed out that RFC 6675 might be a better alternative > so it might be a good idea to ditch it while we're at it. I'm > not certain which parts need to be preserved (if any) however. I'd say remove it. One can always look in the Attic if necessary. > diff --git sys/netinet/tcp_input.c sys/netinet/tcp_input.c > index 790e163975e..3809a2371f2 100644 > --- sys/netinet/tcp_input.c > +++ sys/netinet/tcp_input.c > @@ -1664,52 +1664,38 @@ trimthenstep6: > } > /* >* If the congestion window was inflated to account >* for the other side's cached packets, retract it. >*/ > - if (tp->sack_enable) { > - if (tp->t_dupacks >= tcprexmtthresh) { > - /* Check for a partial ACK */ > - if (tcp_sack_partialack(tp, th)) { > -#ifdef TCP_FACK > - /* Force call to tcp_output */ > - if (tp->snd_awnd < tp->snd_cwnd) > - tp->t_flags |= TF_NEEDOUTPUT; > -#else > - tp->snd_cwnd += tp->t_maxseg; > - tp->t_flags |= TF_NEEDOUTPUT; > -#endif /* TCP_FACK */ > - } else { > - /* Out of fast recovery */ > - tp->snd_cwnd = tp->snd_ssthresh; > - if (tcp_seq_subtract(tp->snd_max, > - th->th_ack) < tp->snd_ssthresh) > - tp->snd_cwnd = > -tcp_seq_subtract(tp->snd_max, > -th->th_ack); > - tp->t_dupacks = 0; > -#ifdef TCP_FACK > - if (SEQ_GT(th->th_ack, tp->snd_fack)) > - tp->snd_fack = th->th_ack; > -#endif > - } > - } > - } else { > - if (tp->t_dupacks >= tcprexmtthresh && > - !tcp_newreno(tp, th)) { > + if (tp->t_dupacks >= tcprexmtthresh) { I'd keep the comment: /* Check for a partial ACK */ > + if (SEQ_LT(th->th_ack, tp->snd_last)) { > + if (tp->sack_enable) > + tcp_sack_partialack(tp, th); > + else > + tcp_newreno_partialack(tp, th); > + } else { > /* Out of fast recovery */ > tp->snd_cwnd = tp->snd_ssthresh; > if (tcp_seq_subtract(tp->snd_max, th->th_ack) < > tp->snd_ssthresh) > tp->snd_cwnd = > tcp_seq_subtract(tp->snd_max, > th->th_ack); > tp->t_dupacks = 0; > +#ifdef TCP_FACK > + if (tp->sack_enable && > + SEQ_GT(th->th_ack, tp->snd_fack)) > + tp->snd_fack = th->th_ack; > +#endif > } > - } > - if (tp->t_dupacks < tcprexmtthresh) > + } else { > + /* > + * Reset the duplicate ACK counter if we > + * were not in fast recovery. > + */ > tp->t_dupacks = 0; > + } > if (SEQ_GT(th->th_ack, tp->snd_max)) { > tcpstat_inc(tcps_rcvacktoomuch); > goto dropafterack_ratelim; > } > acked = th->th_ack - tp->snd_una; > @@ -2703,36 +2689,38 @@ tcp_clean_sackreport(struct tcpcb *tp) >
Re: Refactor TCP partial ACK handling
On Tue, Oct 24, 2017 at 12:05 +0200, Martin Pieuchot wrote: > On 21/10/17(Sat) 15:17, Mike Belopuhov wrote: > > On Fri, Oct 20, 2017 at 22:59 +0200, Klemens Nanni wrote: > > > The comments for both void tcp_{sack,newreno}_partialack() still mention > > > tp->snd_last and return value bits. > > > > > > > Good eyes! It made me spot a mistake I made by folding two lines > > into an incorrect ifdef in tcp_sack_partialack. I expected it to > > say "ifdef TCP_FACK" while it says "ifNdef". The adjusted comment > > didn't make sense and I found the bug. > > Could you send the full/fixed diff? > Sure. > And what about TCP_FACK? It is disabled by default, is there a > point in keeping it? Job has pointed out that RFC 6675 might be a better alternative so it might be a good idea to ditch it while we're at it. I'm not certain which parts need to be preserved (if any) however. diff --git sys/netinet/tcp_input.c sys/netinet/tcp_input.c index 790e163975e..3809a2371f2 100644 --- sys/netinet/tcp_input.c +++ sys/netinet/tcp_input.c @@ -1664,52 +1664,38 @@ trimthenstep6: } /* * If the congestion window was inflated to account * for the other side's cached packets, retract it. */ - if (tp->sack_enable) { - if (tp->t_dupacks >= tcprexmtthresh) { - /* Check for a partial ACK */ - if (tcp_sack_partialack(tp, th)) { -#ifdef TCP_FACK - /* Force call to tcp_output */ - if (tp->snd_awnd < tp->snd_cwnd) - tp->t_flags |= TF_NEEDOUTPUT; -#else - tp->snd_cwnd += tp->t_maxseg; - tp->t_flags |= TF_NEEDOUTPUT; -#endif /* TCP_FACK */ - } else { - /* Out of fast recovery */ - tp->snd_cwnd = tp->snd_ssthresh; - if (tcp_seq_subtract(tp->snd_max, - th->th_ack) < tp->snd_ssthresh) - tp->snd_cwnd = - tcp_seq_subtract(tp->snd_max, - th->th_ack); - tp->t_dupacks = 0; -#ifdef TCP_FACK - if (SEQ_GT(th->th_ack, tp->snd_fack)) - tp->snd_fack = th->th_ack; -#endif - } - } - } else { - if (tp->t_dupacks >= tcprexmtthresh && - !tcp_newreno(tp, th)) { + if (tp->t_dupacks >= tcprexmtthresh) { + if (SEQ_LT(th->th_ack, tp->snd_last)) { + if (tp->sack_enable) + tcp_sack_partialack(tp, th); + else + tcp_newreno_partialack(tp, th); + } else { /* Out of fast recovery */ tp->snd_cwnd = tp->snd_ssthresh; if (tcp_seq_subtract(tp->snd_max, th->th_ack) < tp->snd_ssthresh) tp->snd_cwnd = tcp_seq_subtract(tp->snd_max, th->th_ack); tp->t_dupacks = 0; +#ifdef TCP_FACK + if (tp->sack_enable && + SEQ_GT(th->th_ack, tp->snd_fack)) + tp->snd_fack = th->th_ack; +#endif } - } - if (tp->t_dupacks < tcprexmtthresh) + } else { + /* +* Reset the duplicate ACK counter if we +* were not in fast recovery. +*/ tp->t_dupacks = 0; + } if (SEQ_GT(th->th_ack, tp->snd_max)) { tcpstat_inc(tcps_rcvacktoomuch); goto dropafterack_ratelim; } acked = th->th_ack - tp->snd_una; @@ -2703,36 +2689,38 @@ tcp_clean_sackreport(struct tcpcb *tp) tp->sackblks[i].start = tp->sackblks[i].end=0; } /* - * Checks for partial ack. If partial ack arrives, turn off retransmission - * timer, deflate the window, do not clear tp->t_dupacks, and return 1. - * If the ack advances at least to tp->snd_last, return 0. + * Partial ack handling within a sack recovery episode. When a partial ack +
Re: Refactor TCP partial ACK handling
On 21/10/17(Sat) 15:17, Mike Belopuhov wrote: > On Fri, Oct 20, 2017 at 22:59 +0200, Klemens Nanni wrote: > > The comments for both void tcp_{sack,newreno}_partialack() still mention > > tp->snd_last and return value bits. > > > > Good eyes! It made me spot a mistake I made by folding two lines > into an incorrect ifdef in tcp_sack_partialack. I expected it to > say "ifdef TCP_FACK" while it says "ifNdef". The adjusted comment > didn't make sense and I found the bug. Could you send the full/fixed diff? And what about TCP_FACK? It is disabled by default, is there a point in keeping it? > diff --git sys/netinet/tcp_input.c sys/netinet/tcp_input.c > index 45aafee0d05..d5de9cb2407 100644 > --- sys/netinet/tcp_input.c > +++ sys/netinet/tcp_input.c > @@ -2690,13 +2690,13 @@ tcp_clean_sackreport(struct tcpcb *tp) > tp->sackblks[i].start = tp->sackblks[i].end=0; > > } > > /* > - * Checks for partial ack. If partial ack arrives, turn off retransmission > - * timer, deflate the window, do not clear tp->t_dupacks, and return 1. > - * If the ack advances at least to tp->snd_last, return 0. > + * Partial ack handling within a sack recovery episode. When a partial ack > + * arrives, turn off retransmission timer, deflate the window, do not clear > + * tp->t_dupacks. > */ > void > tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th) > { > /* Turn off retx. timer (will start again next segment) */ > @@ -2711,16 +2711,16 @@ tcp_sack_partialack(struct tcpcb *tp, struct tcphdr > *th) > if (tp->snd_cwnd > (th->th_ack - tp->snd_una)) { > tp->snd_cwnd -= th->th_ack - tp->snd_una; > tp->snd_cwnd += tp->t_maxseg; > } else > tp->snd_cwnd = tp->t_maxseg; > + tp->snd_cwnd += tp->t_maxseg; > + tp->t_flags |= TF_NEEDOUTPUT; > +#else > /* Force call to tcp_output */ > if (tp->snd_awnd < tp->snd_cwnd) > tp->t_flags |= TF_NEEDOUTPUT; > -#else > - tp->snd_cwnd += tp->t_maxseg; > - tp->t_flags |= TF_NEEDOUTPUT; > #endif > } > > /* > * Pull out of band byte out of a segment so > @@ -3078,14 +3078,14 @@ tcp_mss_update(struct tcpcb *tp) > } > > } > > /* > - * Checks for partial ack. If partial ack arrives, force the retransmission > - * of the next unacknowledged segment, do not clear tp->t_dupacks, and return > - * 1. By setting snd_nxt to ti_ack, this forces retransmission timer to > - * be started again. If the ack advances at least to tp->snd_last, return 0. > + * When a partial ack arrives, force the retransmission of the > + * next unacknowledged segment. Do not clear tp->t_dupacks. > + * By setting snd_nxt to ti_ack, this forces retransmission timer > + * to be started again. > */ > void > tcp_newreno_partialack(struct tcpcb *tp, struct tcphdr *th) > { > /* >
Re: Refactor TCP partial ACK handling
On Fri, Oct 20, 2017 at 22:59 +0200, Klemens Nanni wrote: > The comments for both void tcp_{sack,newreno}_partialack() still mention > tp->snd_last and return value bits. > Good eyes! It made me spot a mistake I made by folding two lines into an incorrect ifdef in tcp_sack_partialack. I expected it to say "ifdef TCP_FACK" while it says "ifNdef". The adjusted comment didn't make sense and I found the bug. diff --git sys/netinet/tcp_input.c sys/netinet/tcp_input.c index 45aafee0d05..d5de9cb2407 100644 --- sys/netinet/tcp_input.c +++ sys/netinet/tcp_input.c @@ -2690,13 +2690,13 @@ tcp_clean_sackreport(struct tcpcb *tp) tp->sackblks[i].start = tp->sackblks[i].end=0; } /* - * Checks for partial ack. If partial ack arrives, turn off retransmission - * timer, deflate the window, do not clear tp->t_dupacks, and return 1. - * If the ack advances at least to tp->snd_last, return 0. + * Partial ack handling within a sack recovery episode. When a partial ack + * arrives, turn off retransmission timer, deflate the window, do not clear + * tp->t_dupacks. */ void tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th) { /* Turn off retx. timer (will start again next segment) */ @@ -2711,16 +2711,16 @@ tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th) if (tp->snd_cwnd > (th->th_ack - tp->snd_una)) { tp->snd_cwnd -= th->th_ack - tp->snd_una; tp->snd_cwnd += tp->t_maxseg; } else tp->snd_cwnd = tp->t_maxseg; + tp->snd_cwnd += tp->t_maxseg; + tp->t_flags |= TF_NEEDOUTPUT; +#else /* Force call to tcp_output */ if (tp->snd_awnd < tp->snd_cwnd) tp->t_flags |= TF_NEEDOUTPUT; -#else - tp->snd_cwnd += tp->t_maxseg; - tp->t_flags |= TF_NEEDOUTPUT; #endif } /* * Pull out of band byte out of a segment so @@ -3078,14 +3078,14 @@ tcp_mss_update(struct tcpcb *tp) } } /* - * Checks for partial ack. If partial ack arrives, force the retransmission - * of the next unacknowledged segment, do not clear tp->t_dupacks, and return - * 1. By setting snd_nxt to ti_ack, this forces retransmission timer to - * be started again. If the ack advances at least to tp->snd_last, return 0. + * When a partial ack arrives, force the retransmission of the + * next unacknowledged segment. Do not clear tp->t_dupacks. + * By setting snd_nxt to ti_ack, this forces retransmission timer + * to be started again. */ void tcp_newreno_partialack(struct tcpcb *tp, struct tcphdr *th) { /*
Re: Refactor TCP partial ACK handling
On Fri, Oct 20, 2017 at 09:07:20PM +0200, Mike Belopuhov wrote: > This is a small and not intrusive refactoring of partial ACK handling > but it certainly doesn't look like one. It's intended to be applied > after the TCP SACK diff that I've sent earlier and basically moves the > conditional (SEQ_LT(th->th_ack, tp->snd_last)) out of tcp_sack_partialack > and tcp_newreno into the tcp_input itself making these two functions just > do the work and let tcp_input make decisions. Here's how it looks after > refactoring: > > if (tp->t_dupacks >= tcprexmtthresh) { > if (SEQ_LT(th->th_ack, tp->snd_last)) { > if (tp->sack_enable) > tcp_sack_partialack(tp, th); > else > tcp_newreno_partialack(tp, th); > } else { > /* Out of fast recovery */ > tp->snd_cwnd = tp->snd_ssthresh; > if (tcp_seq_subtract(tp->snd_max, th->th_ack) < > tp->snd_ssthresh) > tp->snd_cwnd = > tcp_seq_subtract(tp->snd_max, > th->th_ack); > tp->t_dupacks = 0; > #ifdef TCP_FACK > if (tp->sack_enable && > SEQ_GT(th->th_ack, tp->snd_fack)) > tp->snd_fack = th->th_ack; > #endif > } > } else { > /* >* Reset the duplicate ACK counter if we >* were not in fast recovery. >*/ > tp->t_dupacks = 0; > } > > This allows to consolidate the "out of fast recovery" branch currently > repeated twice as well as show how tcp_sack_partialack and tcp_newreno > interact without extra clutter. The true branch of the old condition > "if (tcp_sack_partialack(tp, th))" gets integrated into the function > tcp_sack_partialack itself and tcp_newreno is renamed for consistency. > > The diff also hooks up the "if (tp->t_dupacks < tcprexmtthresh)" branch > to this "main if" since t_dupacks is ether greater then tcprexmtthresh > or not. > > In the end there's no (intentional) logic change at all, but gained > clarity is quite substantial as noticed by FreeBSD folks as well. > Consolidating the 'out of fast recovery' branch is also beneficial for > later work. > > OK? > > diff --git sys/netinet/tcp_input.c sys/netinet/tcp_input.c > index 9951923bbdb..84cdb35f048 100644 > --- sys/netinet/tcp_input.c > +++ sys/netinet/tcp_input.c > @@ -1664,52 +1664,38 @@ trimthenstep6: > } > /* >* If the congestion window was inflated to account >* for the other side's cached packets, retract it. >*/ > - if (tp->sack_enable) { > - if (tp->t_dupacks >= tcprexmtthresh) { > - /* Check for a partial ACK */ > - if (tcp_sack_partialack(tp, th)) { > -#ifdef TCP_FACK > - /* Force call to tcp_output */ > - if (tp->snd_awnd < tp->snd_cwnd) > - tp->t_flags |= TF_NEEDOUTPUT; > -#else > - tp->snd_cwnd += tp->t_maxseg; > - tp->t_flags |= TF_NEEDOUTPUT; > -#endif /* TCP_FACK */ > - } else { > - /* Out of fast recovery */ > - tp->snd_cwnd = tp->snd_ssthresh; > - if (tcp_seq_subtract(tp->snd_max, > - th->th_ack) < tp->snd_ssthresh) > - tp->snd_cwnd = > -tcp_seq_subtract(tp->snd_max, > -th->th_ack); > - tp->t_dupacks = 0; > -#ifdef TCP_FACK > - if (SEQ_GT(th->th_ack, tp->snd_fack)) > - tp->snd_fack = th->th_ack; > -#endif > - } > - } > - } else { > - if (tp->t_dupacks >= tcprexmtthresh && > - !tcp_newreno(tp, th)) { > + if (tp->t_dupacks >= tcprexmtthresh) { > + if (SEQ_LT(th->th_ack, tp->snd_last)) { > + if (tp->sack_enable) > + tcp_sack_partialack(tp, th); > + else > + tcp_newreno_partialack(tp, th); > + } else { > /* Out of fast recovery */ > tp->snd_cwnd = tp->snd_ssthresh; >