From mboxrd@z Thu Jan 1 00:00:00 1970 Received: by passt.top (Postfix, from userid 1000) id E66C45A063D; Thu, 13 Feb 2025 23:16:44 +0100 (CET) From: Stefano Brivio To: passt-dev@passt.top Subject: [PATCH] tcp: Keep updating window and checking for socket data after FIN from guest Date: Thu, 13 Feb 2025 23:16:44 +0100 Message-ID: <20250213221644.4086036-1-sbrivio@redhat.com> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: 4BC7VBXHJRZIJZCDMPE7YDGAEO436KUI X-Message-ID-Hash: 4BC7VBXHJRZIJZCDMPE7YDGAEO436KUI X-MailFrom: sbrivio@passt.top X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: David Gibson X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Once we get a FIN segment from the container/guest, we enter something resembling CLOSE_WAIT (from the perspective of the peer), but that doesn't mean that we should stop processing window updates from the guest and checking for socket data if the guest acknowledges something. If we don't do that, we can very easily run into a situation where we send a burst of data to the tap, get a zero window update, along with a FIN segment, because the flow is meant to be unidirectional, and now the connection will be stuck forever, because we'll ignore updates. Reproducer, server: $ pasta --config-net -t 9999 -- sh -c 'echo DONE | socat TCP-LISTEN:9997,shut-down STDIO' and client: $ ./test/rampstream send 50000 | socat -u STDIN TCP:$LOCAL_ADDR:9997 2025/02/13 09:14:45 socat[2997126] E write(5, 0x55f5dbf47000, 8192): Broken pipe while at it, update the message string for the third passive close state (which we see in this case): it's CLOSE_WAIT, not LAST_ACK. Signed-off-by: Stefano Brivio --- tcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tcp.c b/tcp.c index a1d6c53..16d01f6 100644 --- a/tcp.c +++ b/tcp.c @@ -338,7 +338,7 @@ static const char *tcp_state_str[] __attribute((__unused__)) = { "SYN_RCVD", /* approximately maps to TAP_SYN_ACK_SENT */ /* Passive close: */ - "CLOSE_WAIT", "CLOSE_WAIT", "LAST_ACK", "LAST_ACK", "LAST_ACK", + "CLOSE_WAIT", "CLOSE_WAIT", "CLOSE_WAIT", "LAST_ACK", "LAST_ACK", /* Active close (+5): */ "CLOSING", "FIN_WAIT_1", "FIN_WAIT_1", "FIN_WAIT_2", "TIME_WAIT", }; @@ -1968,6 +1968,8 @@ int tcp_tap_handler(const struct ctx *c, uint8_t pif, sa_family_t af, /* Established connections not accepting data from tap */ if (conn->events & TAP_FIN_RCVD) { tcp_update_seqack_from_tap(c, conn, ntohl(th->ack_seq)); + tcp_tap_window_update(conn, ntohs(th->window)); + tcp_data_from_sock(c, conn); if (conn->events & SOCK_FIN_RCVD && conn->seq_ack_from_tap == conn->seq_to_tap) -- 2.43.0