From 2bc1470feca90694eb392ad0f22a9b2955c6265d Mon Sep 17 00:00:00 2001 From: rrs Date: Sun, 14 Jul 2019 16:05:47 +0000 Subject: [PATCH] This is the second in a number of patches needed to get BBRv1 into the tree. This fixes the DSACK bug but is also needed by BBR. We have yet to go two more one will be for the pacing code (tcp_ratelimit.c) and the second will be for the new updated LRO code that allows a transport to know the arrival times of packets and (tcp_lro.c). After that we should finally be able to get BBRv1 into head. Sponsored by: Netflix Inc Differential Revision: https://reviews.freebsd.org/D20908 --- sys/netinet/tcp_output.c | 8 ++++++- sys/netinet/tcp_sack.c | 39 +++++++++++++++++++++++++++++++++++ sys/netinet/tcp_stacks/rack.c | 7 +++---- sys/netinet/tcp_var.h | 1 + 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index d67e1b9bee33..f329703c3ffb 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -1508,7 +1508,13 @@ timer: if (SEQ_GT(tp->snd_nxt + xlen, tp->snd_max)) tp->snd_max = tp->snd_nxt + xlen; } - + if ((error == 0) && + (TCPS_HAVEESTABLISHED(tp->t_state) && + (tp->t_flags & TF_SACK_PERMIT) && + tp->rcv_numsacks > 0)) { + /* Clean up any DSACK's sent */ + tcp_clean_dsack_blocks(tp); + } if (error) { /* Record the error. */ TCP_LOG_EVENT(tp, NULL, &so->so_rcv, &so->so_snd, TCP_LOG_OUT, diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c index eb4064d29cf7..978e692c498b 100644 --- a/sys/netinet/tcp_sack.c +++ b/sys/netinet/tcp_sack.c @@ -279,6 +279,45 @@ tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_start, tcp_seq rcv_end) tp->rcv_numsacks = num_head + num_saved; } +void +tcp_clean_dsack_blocks(struct tcpcb *tp) +{ + struct sackblk saved_blks[MAX_SACK_BLKS]; + int num_saved, i; + + INP_WLOCK_ASSERT(tp->t_inpcb); + /* + * Clean up any DSACK blocks that + * are in our queue of sack blocks. + * + */ + num_saved = 0; + for (i = 0; i < tp->rcv_numsacks; i++) { + tcp_seq start = tp->sackblks[i].start; + tcp_seq end = tp->sackblks[i].end; + if (SEQ_GEQ(start, end) || SEQ_LEQ(start, tp->rcv_nxt)) { + /* + * Discard this D-SACK block. + */ + continue; + } + /* + * Save this SACK block. + */ + saved_blks[num_saved].start = start; + saved_blks[num_saved].end = end; + num_saved++; + } + if (num_saved > 0) { + /* + * Copy the saved SACK blocks back. + */ + bcopy(saved_blks, &tp->sackblks[0], + sizeof(struct sackblk) * num_saved); + } + tp->rcv_numsacks = num_saved; +} + /* * Delete all receiver-side SACK information. */ diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c index b828a815ad18..ef205869a624 100644 --- a/sys/netinet/tcp_stacks/rack.c +++ b/sys/netinet/tcp_stacks/rack.c @@ -5087,9 +5087,8 @@ rack_do_fastnewdata(struct mbuf *m, struct tcphdr *th, struct socket *so, /* Clean receiver SACK report if present */ -/* if (tp->rcv_numsacks) + if (tp->rcv_numsacks) tcp_clean_sackreport(tp); -*/ TCPSTAT_INC(tcps_preddat); tp->rcv_nxt += tlen; /* @@ -8537,10 +8536,10 @@ out: * retransmit. In persist state, just set snd_max. */ if (error == 0) { -/* if (TCPS_HAVEESTABLISHED(tp->t_state) && + if (TCPS_HAVEESTABLISHED(tp->t_state) && (tp->t_flags & TF_SACK_PERMIT) && tp->rcv_numsacks > 0) - tcp_clean_dsack_blocks(tp);*/ + tcp_clean_dsack_blocks(tp); if (len == 0) counter_u64_add(rack_out_size[TCP_MSS_ACCT_SNDACK], 1); else if (len == 1) { diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index 8d3ffa8b5880..dad91be83d5b 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -939,6 +939,7 @@ tcp_seq tcp_new_isn(struct in_conninfo *); int tcp_sack_doack(struct tcpcb *, struct tcpopt *, tcp_seq); void tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_laststart, tcp_seq rcv_lastend); +void tcp_clean_dsack_blocks(struct tcpcb *tp); 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);