diff options
author | Sean Bruno <sbruno@FreeBSD.org> | 2018-03-09 00:08:43 +0000 |
---|---|---|
committer | Sean Bruno <sbruno@FreeBSD.org> | 2018-03-09 00:08:43 +0000 |
commit | d7fb35d13a488381724c5b1df06db78b9e4c9aaf (patch) | |
tree | 9d245eb923726b04d2810cef4691bb945485e979 /sys/netinet/tcp_lro.c | |
parent | 1857bc794f0b48269fbc3162f487468ee9ccdf8a (diff) | |
download | src-d7fb35d13a488381724c5b1df06db78b9e4c9aaf.tar.gz src-d7fb35d13a488381724c5b1df06db78b9e4c9aaf.zip |
Update tcp_lro with tested bugfixes from Netflix and LLNW:
rrs - Lets make the LRO code look for true dup-acks and window update acks
fly on through and combine.
rrs - Make the LRO engine a bit more aware of ack-only seq space. Lets not
have it incorrectly wipe out newer acks for older acks when we have
out-of-order acks (common in wifi environments).
jeggleston - LRO eating window updates
Based on all of the above I think we are RFC compliant doing it this way:
https://tools.ietf.org/html/rfc1122
section 4.2.2.16
"Note that TCP has a heuristic to select the latest window update despite
possible datagram reordering; as a result, it may ignore a window update with
a smaller window than previously offered if neither the sequence number nor the
acknowledgment number is increased."
Submitted by: Kevin Bowling <kevin.bowling@kev009.com>
Reviewed by: rstone gallatin
Sponsored by: NetFlix and Limelight Networks
Differential Revision: https://reviews.freebsd.org/D14540
Notes
Notes:
svn path=/head/; revision=330675
Diffstat (limited to 'sys/netinet/tcp_lro.c')
-rw-r--r-- | sys/netinet/tcp_lro.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/sys/netinet/tcp_lro.c b/sys/netinet/tcp_lro.c index c859344135f0..0061df3ecaa8 100644 --- a/sys/netinet/tcp_lro.c +++ b/sys/netinet/tcp_lro.c @@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/ip.h> #include <netinet/ip_var.h> #include <netinet/tcp.h> +#include <netinet/tcp_seq.h> #include <netinet/tcp_lro.h> #include <netinet/tcp_var.h> @@ -794,7 +795,9 @@ tcp_lro_rx2(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum, int use_hash) /* Try to append the new segment. */ if (__predict_false(seq != le->next_seq || - (tcp_data_len == 0 && le->ack_seq == th->th_ack))) { + (tcp_data_len == 0 && + le->ack_seq == th->th_ack && + le->window == th->th_win))) { /* Out of order packet or duplicate ACK. */ tcp_lro_active_remove(le); tcp_lro_flush(lc, le); @@ -811,12 +814,20 @@ tcp_lro_rx2(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum, int use_hash) le->tsval = tsval; le->tsecr = *(ts_ptr + 2); } - - le->next_seq += tcp_data_len; - le->ack_seq = th->th_ack; - le->window = th->th_win; - le->append_cnt++; - + if (tcp_data_len || SEQ_GT(ntohl(th->th_ack), ntohl(le->ack_seq))) { + le->next_seq += tcp_data_len; + le->ack_seq = th->th_ack; + le->window = th->th_win; + le->append_cnt++; + } else if (th->th_ack == le->ack_seq) { + le->window = WIN_MAX(le->window, th->th_win); + le->append_cnt++; + } else { + /* no data and old ack */ + le->append_cnt++; + m_freem(m); + return (0); + } #ifdef TCP_LRO_UPDATE_CSUM le->ulp_csum += tcp_lro_rx_csum_fixup(le, l3hdr, th, tcp_data_len, ~csum); |