aboutgitcodebugslistschat
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2021-08-04 01:29:59 +0200
committerStefano Brivio <sbrivio@redhat.com>2021-08-04 01:29:59 +0200
commit0017bc3c3e3f666bb190f2c1f808e447e96a10aa (patch)
tree83c6aa5da53af9d9e9fb80041e545e23321101dd
parentc62490ffa8b9c41a109bce4cced45d8b0f555c5a (diff)
downloadpasst-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>
-rw-r--r--tcp.c33
1 files changed, 23 insertions, 10 deletions
diff --git a/tcp.c b/tcp.c
index 65a9aff..5f9d5f6 100644
--- a/tcp.c
+++ b/tcp.c
@@ -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;