Add metric to count number of segments acknowledged by DSACK.

- Creates new metric "/tcp/segments_acked_with_dsack" to count the number of
segments acked with DSACK.
- Added check to verify the metric is getting incremented when a DSACK is sent
in the unit tests.

PiperOrigin-RevId: 386135949
This commit is contained in:
Nayana Bidari
2021-07-21 18:06:31 -07:00
committed by gVisor bot
parent bc0ab8ea0f
commit f1f746dddc
4 changed files with 56 additions and 0 deletions
+1
View File
@@ -274,6 +274,7 @@ var Metrics = tcpip.Stats{
Timeouts: mustCreateMetric("/netstack/tcp/timeouts", "Number of times RTO expired."),
ChecksumErrors: mustCreateMetric("/netstack/tcp/checksum_errors", "Number of segments dropped due to bad checksums."),
FailedPortReservations: mustCreateMetric("/netstack/tcp/failed_port_reservations", "Number of time TCP failed to reserve a port."),
SegmentsAckedWithDSACK: mustCreateMetric("/netstack/tcp/segments_acked_with_dsack", "Number of segments for which DSACK was received."),
},
UDP: tcpip.UDPStats{
PacketsReceived: mustCreateMetric("/netstack/udp/packets_received", "Number of UDP datagrams received via HandlePacket."),
+4
View File
@@ -1845,6 +1845,10 @@ type TCPStats struct {
// FailedPortReservations is the number of times TCP failed to reserve
// a port.
FailedPortReservations *StatCounter
// SegmentsAckedWithDSACK is the number of segments acknowledged with
// DSACK.
SegmentsAckedWithDSACK *StatCounter
}
// UDPStats collects UDP-specific stats.
+7
View File
@@ -1154,6 +1154,13 @@ func (s *sender) walkSACK(rcvdSeg *segment) {
idx := 0
n := len(rcvdSeg.parsedOptions.SACKBlocks)
if checkDSACK(rcvdSeg) {
dsackBlock := rcvdSeg.parsedOptions.SACKBlocks[0]
numDSACK := uint64(dsackBlock.End-dsackBlock.Start) / uint64(s.MaxPayloadSize)
// numDSACK can be zero when DSACK is sent for subsegments.
if numDSACK < 1 {
numDSACK = 1
}
s.ep.stack.Stats().TCP.SegmentsAckedWithDSACK.IncrementBy(numDSACK)
s.rc.setDSACKSeen(true)
idx = 1
n--
+44
View File
@@ -540,6 +540,28 @@ func TestRACKDetectDSACK(t *testing.T) {
case invalidDSACKDetected:
t.Fatalf("RACK DSACK detected when there is no duplicate SACK")
}
metricPollFn := func() error {
tcpStats := c.Stack().Stats().TCP
stats := []struct {
stat *tcpip.StatCounter
name string
want uint64
}{
// Check DSACK was received for one segment.
{tcpStats.SegmentsAckedWithDSACK, "stats.TCP.SegmentsAckedWithDSACK", 1},
}
for _, s := range stats {
if got, want := s.stat.Value(), s.want; got != want {
return fmt.Errorf("got %s.Value() = %d, want = %d", s.name, got, want)
}
}
return nil
}
if err := testutil.Poll(metricPollFn, 1*time.Second); err != nil {
t.Error(err)
}
}
// TestRACKDetectDSACKWithOutOfOrder tests that RACK detects DSACK with out of
@@ -680,6 +702,28 @@ func TestRACKDetectDSACKSingleDup(t *testing.T) {
case invalidDSACKDetected:
t.Fatalf("RACK DSACK detected when there is no duplicate SACK")
}
metricPollFn := func() error {
tcpStats := c.Stack().Stats().TCP
stats := []struct {
stat *tcpip.StatCounter
name string
want uint64
}{
// Check DSACK was received for a subsegment.
{tcpStats.SegmentsAckedWithDSACK, "stats.TCP.SegmentsAckedWithDSACK", 1},
}
for _, s := range stats {
if got, want := s.stat.Value(), s.want; got != want {
return fmt.Errorf("got %s.Value() = %d, want = %d", s.name, got, want)
}
}
return nil
}
if err := testutil.Poll(metricPollFn, 1*time.Second); err != nil {
t.Error(err)
}
}
// TestRACKDetectDSACKDupWithCumulativeACK tests DSACK for two non-contiguous