RFC 3042 Implementation

Matt Miller matt at matthewjmiller.net
Thu Apr 11 19:00:39 UTC 2013


In some of our tests, we noticed some duplicate pure ACKs (not window
updates), most of which the duplicates were coming from this tcp_output()
call in tcp_do_segment() (line 2534):

2508                                 } else if (V_tcp_do_rfc3042) {
2509                                         cc_ack_received(tp, th,
CC_DUPACK);
2510                                         u_long oldcwnd = tp->snd_cwnd;
2511                                         tcp_seq oldsndmax =
tp->snd_max;
2512                                         u_int sent;
2513
2514                                         KASSERT(tp->t_dupacks == 1 ||
2515                                             tp->t_dupacks == 2,
2516                                             ("%s: dupacks not 1 or 2",
2517                                             __func__));
2518                                         if (tp->t_dupacks == 1)
2519                                                 tp->snd_limited = 0;
2520                                         tp->snd_cwnd =
2521                                             (tp->snd_nxt -
tp->snd_una) +
2522                                             (tp->t_dupacks -
tp->snd_limited) *
2523                                             tp->t_maxseg;
2524                                         if ((thflags & TH_FIN) &&
2525
(TCPS_HAVERCVDFIN(tp->t_state) == 0)) {
2526                                                 /*
2527                                                  * If its a fin we
need to process
2528                                                  * it to avoid a race
where both
2529                                                  * sides enter
FIN-WAIT and send FIN|ACK
2530                                                  * at the same time.
2531                                                  */
2532                                                 break;
2533                                         }
2534                                         (void) tcp_output(tp);

I added some instrumentation here to count how many time the following is
zero prior to calling tcp_output():

so->so_snd.sb_cc - ((tp->snd_nxt - tp->snd_una)

And, in our tests, it was like 97% of the time.

It looks like the intent of the RFC is to only send one or two unsent data
segments here, not pure ACKs.  And this subsequent standard seems to
clarify that new data should be available for transmission:

http://tools.ietf.org/html/rfc5681

<quote>
       On the first and second duplicate ACKs received at a sender, a
       TCP SHOULD send a segment of previously unsent data per [RFC3042]
       provided that the receiver's advertised window allows, the total
       FlightSize would remain less than or equal to cwnd plus 2*SMSS,
       and that new data is available for transmission.
</quote>

So, this is a detailed way of asking: do we need a check here to make sure
there is new data to send prior to calling tcp_output()?

Thanks,

Matt


More information about the freebsd-net mailing list