tcp/sack: If other side reneged, discard the current SACK scoreboard
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 30 May 2012 01:43:50 +0000 (09:43 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 30 May 2012 01:43:50 +0000 (09:43 +0800)
Other side reneging is detected using the first SACK record:
If its left edge is less than or equal to the cumulative ACK of the
incoming segment, other side probably reneged.

This fixes the later assertion that the first SACK record's left edge
must be above snd_una in tcp_sack_first_unsacked_len()

Add statistics about other side reneging

sys/netinet/tcp_sack.c
sys/netinet/tcp_var.h
usr.bin/netstat/inet.c

index 10ac3f6..356bbca 100644 (file)
@@ -217,8 +217,11 @@ tcp_sack_ack_blocks(struct scoreboard *scb, tcp_seq th_ack)
                    ("SACK block count underflow: %d < 0", scb->nblocks));
                sb = nb;
        }
-       if (sb && SEQ_GT(th_ack, sb->sblk_start))
-               sb->sblk_start = th_ack;        /* other side reneged? XXX */
+       if (sb && SEQ_GEQ(th_ack, sb->sblk_start)) {
+               /* Other side reneged? XXX */
+               tcpstat.tcps_sackrenege++;
+               tcp_sack_cleanup(scb);
+       }
 }
 
 /*
index 20f5a3f..3b3d8e5 100644 (file)
@@ -415,12 +415,13 @@ struct tcp_stats {
        u_long  tcps_mturesent;         /* resends due to MTU discovery */
        u_long  tcps_listendrop;        /* listen queue overflows */
        u_long  tcps_rcvbadsackopt;     /* rcvd illegal SACK options */
+       u_long  tcps_sackrenege;        /* times other side reneged */
 
        u_long  tcps_sacksbupdate;      /* times SACK scoreboard updated */
        u_long  tcps_sacksboverflow;    /* times SACK scoreboard overflowed */
        u_long  tcps_sacksbreused;      /* times SACK sb-block reused */
        u_long  tcps_sacksbfailed;      /* times SACK sb update failed */
-       u_long  tcps_sacksbfast;        /* timee SACK sb-block uses cache */
+       u_long  tcps_sacksbfast;        /* times SACK sb-block uses cache */
 
        u_long  tcps_sc_added;          /* entry added to syncache */
        u_long  tcps_sc_retransmitted;  /* syncache entry was retransmitted */
index 64f65f7..9485866 100644 (file)
@@ -494,6 +494,7 @@ tcp_stats(u_long off __unused, const char *name, int af1 __unused)
        p(tcps_rcvbadoff, "\t\t%lu discarded for bad header offset field%s\n");
        p1a(tcps_rcvshort, "\t\t%lu discarded because packet too short\n");
        p(tcps_rcvbadsackopt, "\t\t%lu bad SACK option%s\n");
+       p1a(tcps_sackrenege, "\t\t%lu other side reneged\n");
        p(tcps_connattempt, "\t%lu connection request%s\n");
        p(tcps_accepts, "\t%lu connection accept%s\n");
        p(tcps_badsyn, "\t%lu bad connection attempt%s\n");