Hi there,

We are using the network stack of FreeBSD 13 on top of DPDK in our application.
During the last tests in the lab I stumbled upon the following situation:
1. It's a test where 5000 parallel connections are opened by Apache
Bench and each one downloads 1MB data. It causes the client NIC to
start dropping packets due to overflows which is intentional behavior.
2. The server side is our application with the FreeBSD stack. The
client side Ubuntu 24.04 with Linux 6.8.0.
3. So, a connection is opened and the download starts on it. At some
point the first drops occur and according to the TCP dump, from the
client side, they take a few seconds before the connection heals up.
However, these drops lead to increased values of t_srtt, t_rttvar and
thus to increased value of t_rxtcur.
4. The window opens again up to 100-200 KB with lots of packets
in-flight and the drops start again. They cause the re-transmit timer
from the FreeBSD side to be started but with an interval of something
like 18-20 seconds (according to my printf debugging on this side).
5. At the same time the TCP keep-alive timer is also started for the
same connection (it's enabled for all connections) with a timeout of
15 seconds.
6. Nothing happens on this connection for the next 15 seconds. I'm not
sure why the Linux stack didn't send any "wake-up" ACK packets or
something but the tcpdump from the client side shows full silence
between 14-th and 29-th second.
7. Next the FreeBSD keep-alive logic kicks-in and sends an ACK packet
which is ACK-ed by the Linux stack immediately. However, this ACK
packet received by the FreeBSD stack leads to restart of the
retransmit timer and with the interval which is bigger than the
keep-alive interval.
8. Point 6 and 7 repeat one more time before the apache bench client
gives up on this connection and declares that it's timed-out. My
understanding is that the connection can "loop" in 6-7 for a very long
time and a packet with data will never be retransmitted.
9. As far as I debugged the situation from the FreeBSD side the
restart of the retransmit timer happens in the code after the
`process_ACK` label, in the else branch here:
```
        if (th->th_ack == tp->snd_max) {
            tcp_timer_activate(tp, TT_REXMT, 0);
            needoutput = 1;
        } else if (!tcp_timer_active(tp, TT_PERSIST))
            tcp_timer_activate(tp, TT_REXMT, tp->t_rxtcur);
```

So, based on the above situation I've the following questions:
1. Would it be correct if the re-transmit timer is not restarted by
keep-alive ACK packets?
2. Assuming that the above change won't break anything else, is there
a way for detecting that an ACK packet acknowledges previously sent
keep-alive packet?

Regards,
Pavel.

Reply via email to