diff options
author | Stefano Brivio <sbrivio@redhat.com> | 2021-08-04 01:29:59 +0200 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2021-08-04 01:29:59 +0200 |
commit | 0017bc3c3e3f666bb190f2c1f808e447e96a10aa (patch) | |
tree | 83c6aa5da53af9d9e9fb80041e545e23321101dd /tcp.c | |
parent | c62490ffa8b9c41a109bce4cced45d8b0f555c5a (diff) | |
download | passt-0017bc3c3e3f666bb190f2c1f808e447e96a10aa.tar passt-0017bc3c3e3f666bb190f2c1f808e447e96a10aa.tar.gz passt-0017bc3c3e3f666bb190f2c1f808e447e96a10aa.tar.bz2 passt-0017bc3c3e3f666bb190f2c1f808e447e96a10aa.tar.lz passt-0017bc3c3e3f666bb190f2c1f808e447e96a10aa.tar.xz passt-0017bc3c3e3f666bb190f2c1f808e447e96a10aa.tar.zst passt-0017bc3c3e3f666bb190f2c1f808e447e96a10aa.zip |
tcp: Always allow ACKs when pending, fixes for no_snd_wnd and closing states
We won't necessarily have another choice to ACK in a timely fashion
if we skip ACKs from a number of states (including ESTABLISHED) when
there's enough window left. Check for ACKed bytes as soon as it makes
sense.
If the sending window is not reported by the kernel, ACK as soon as
we queue onto the socket, given that we're forced to use a rather
small window.
In FIN_WAIT_1_SOCK_FIN, we also have to account for the FIN flag sent
by the peer in the sequence.
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Diffstat (limited to 'tcp.c')
-rw-r--r-- | tcp.c | 33 |
1 files changed, 23 insertions, 10 deletions
@@ -1081,15 +1081,17 @@ static int tcp_send_to_tap(struct ctx *c, struct tcp_tap_conn *conn, uint32_t ack_offset = conn->seq_from_tap - conn->seq_ack_to_tap; char buf[USHRT_MAX] = { 0 }, *data; struct tcp_info info = { 0 }; + int ws = 0, err, ack_pending; socklen_t sl = sizeof(info); struct tcphdr *th; - int ws = 0, err; - if (ack_offset < conn->tcpi_snd_wnd / 10 && !flags) { + if (!ack_offset && !flags) { err = 0; info.tcpi_bytes_acked = conn->tcpi_acked_last; info.tcpi_snd_wnd = conn->tcpi_snd_wnd; info.tcpi_snd_wscale = conn->ws; + } else if (conn->no_snd_wnd && !(flags & SYN)) { + err = 0; } else { err = getsockopt(conn->sock, SOL_TCP, TCP_INFO, &info, &sl); if (err && !(flags & RST)) { @@ -1135,21 +1137,32 @@ static int tcp_send_to_tap(struct ctx *c, struct tcp_tap_conn *conn, conn->seq_to_tap += len; } - if (!err && ((info.tcpi_bytes_acked > conn->tcpi_acked_last) || - (flags & ACK) || len)) { + if (conn->no_snd_wnd) { + ack_pending = (conn->seq_from_tap - conn->seq_ack_to_tap) < + MAX_WINDOW; + } else { + ack_pending = info.tcpi_bytes_acked > conn->tcpi_acked_last; + } + + if (!err && (ack_pending || (flags & ACK) || len)) { th->ack = 1; - conn->seq_ack_to_tap = info.tcpi_bytes_acked + - conn->seq_init_from_tap; + if (conn->no_snd_wnd) { + conn->seq_ack_to_tap = conn->seq_from_tap; + } else { + conn->seq_ack_to_tap = info.tcpi_bytes_acked + + conn->seq_init_from_tap; + conn->tcpi_acked_last = info.tcpi_bytes_acked; + } - if (conn->state == LAST_ACK) { + if (conn->state == LAST_ACK || + conn->state == FIN_WAIT_1_SOCK_FIN) conn->seq_ack_to_tap = conn->seq_from_tap + 1; + + if (conn->state == LAST_ACK) th->seq = htonl(ntohl(th->seq) + 1); - } th->ack_seq = htonl(conn->seq_ack_to_tap); - - conn->tcpi_acked_last = info.tcpi_bytes_acked; } else { if (!len && !flags) return 0; |