Closed pronebird closed 5 months ago
I have also noticed this piece of code:
https://github.com/narrowlink/ipstack/blob/main/src/stream/tcp.rs#L459-L462
Note that early return there on UnexpectedEof
. self.tcb.retransmission
remains set. Maybe we should reset retransmission
before packet_sender.send()
?
I'm using self.tcb.retransmission.take()
to preliminarily set it to None
.
The problem is looks related to the logic of tcp stack, and I don't believe that it can be fixed by taking. If the function returns UnexpectedEof, it means the stream is terminated, and poll_flush won't be called anymore! Based on what you provided, ipstack received a retransmission of data that is not available in the inflight_packets anymore, as you mentioned. There are two reasons that this can happen:
1) We removed that buffer from inflight_packets improperly. 2) We are miscalculating the RetransmissionRequest in the check_pkt_type function.
I intentionally left the panic there because I suspected the accuracy of the check_pkt_type for this part and aimed to identify the potential miscalculation.
The problem is that inflight_packets
is empty.
inflight_packets should not be empty at this stage.
tcp_sequence: 1615887506
last_ack: 1615879314
8192 bytes should be available in the inflight_packets
I suspect that a regression occurred here: https://github.com/narrowlink/ipstack/commit/2d54e7ed0e7cbd20cda99256b2eff1a278f86759
self.inflight_packets.retain(|p| {
let last_byte = p.seq.wrapping_add(p.payload.len() as u32);
last_byte.saturating_sub(self.last_ack) > 0
&& self.seq.saturating_sub(last_byte) > 0
});
I am suspected to this part, 'seq' in 'inflight_packets' refers to the packet's sequence at the time it was pushed into the buffer. 'p.seq + 1' indicates the first byte, while 'p.seq' itself isn't available in the buffer.
self.inflight_packets.retain(|p| { let last_byte = p.seq.wrapping_add(p.payload.len() as u32); last_byte.saturating_sub(self.last_ack) > 0 && self.seq.saturating_sub(last_byte) > 0 });
I am suspected to this part, 'seq' in 'inflight_packets' refers to the packet's sequence at the time it was pushed into the buffer. 'p.seq + 1' indicates the first byte, while 'p.seq' itself isn't available in the buffer.
self.seq.saturating_sub(last_byte) > 0
Based on the explanation provided above this condition is incorrect and removing it should solve the issue.
@RoDmitry Could you please verify my conclusion?
If I would understand the meaning of the self.last_ack
and self.seq
, then maybe I could verify š. Maybe we need tests for this?
@SajjadPourali patched it as per your suggestion. Will run the ipstack the entire day and monitor logs. https://github.com/narrowlink/ipstack/commit/f64ca2c8d85b55e50c17884797f1945c72aa71f5
If I would understand the meaning of the
self.last_ack
andself.seq
, then maybe I could verify š. Maybe we need tests for this?
In the TCB of ipstack, "last_ack" means the last byte acknowledged by the peer (i.e., SND.UNA), and "seq" is the last byte sent and still not acknowledged (i.e., SND.NEXT).
1 2 3 4
----------|----------|----------|----------
SND.UNA SND.NXT SND.UNA
+SND.WND
Then yes, checking for self.seq.saturating_sub(last_byte) > 0
is invalid, because self.seq
can be equal to the last_byte of the packet, and so it will be dropped.
Using 0.0.9. Caught a panic today:
By looking at the code issuing the panic I can conclude that
inflights_packets
is empty, because only four lines are logged and the loop is entirely skipped. What's really going on in this piece of code? Maybe it shouldn't panic if there are no more inflight packets to flush?