aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/tcp_lro.c
diff options
context:
space:
mode:
authorSean Bruno <sbruno@FreeBSD.org>2018-03-09 00:08:43 +0000
committerSean Bruno <sbruno@FreeBSD.org>2018-03-09 00:08:43 +0000
commitd7fb35d13a488381724c5b1df06db78b9e4c9aaf (patch)
tree9d245eb923726b04d2810cef4691bb945485e979 /sys/netinet/tcp_lro.c
parent1857bc794f0b48269fbc3162f487468ee9ccdf8a (diff)
downloadsrc-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.c25
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);