diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go index daac7bc9c..06587cc27 100644 --- a/pkg/sentry/socket/netstack/netstack.go +++ b/pkg/sentry/socket/netstack/netstack.go @@ -88,6 +88,7 @@ var Metrics = tcpip.Stats{ Packets: mustCreateMetric("/netstack/nic/tx/packets", "Number of packets transmitted."), Bytes: mustCreateMetric("/netstack/nic/tx/bytes", "Number of bytes transmitted."), }, + TxPacketsDroppedNoBufferSpace: mustCreateMetric("/netstack/nic/tx_packets_dropped_no_buffer_space", "Number of TX packets dropped as a result of no buffer space errors."), Rx: tcpip.NICPacketStats{ Packets: mustCreateMetric("/netstack/nic/rx/packets", "Number of packets received."), Bytes: mustCreateMetric("/netstack/nic/rx/bytes", "Number of bytes received."), diff --git a/pkg/tcpip/stack/nic.go b/pkg/tcpip/stack/nic.go index 7f7029442..c805f74f5 100644 --- a/pkg/tcpip/stack/nic.go +++ b/pkg/tcpip/stack/nic.go @@ -394,6 +394,9 @@ func (n *nic) writePacket(pkt *PacketBuffer) tcpip.Error { func (n *nic) writeRawPacket(pkt *PacketBuffer) tcpip.Error { if err := n.qDisc.WritePacket(pkt); err != nil { + if _, ok := err.(*tcpip.ErrNoBufferSpace); ok { + n.stats.txPacketsDroppedNoBufferSpace.Increment() + } return err } diff --git a/pkg/tcpip/stack/nic_stats.go b/pkg/tcpip/stack/nic_stats.go index 89aa95131..e94ea572f 100644 --- a/pkg/tcpip/stack/nic_stats.go +++ b/pkg/tcpip/stack/nic_stats.go @@ -56,6 +56,7 @@ type multiCounterNICStats struct { unknownL4ProtocolRcvdPacketCounts tcpip.MultiIntegralStatCounterMap malformedL4RcvdPackets tcpip.MultiCounterStat tx multiCounterNICPacketStats + txPacketsDroppedNoBufferSpace tcpip.MultiCounterStat rx multiCounterNICPacketStats disabledRx multiCounterNICPacketStats neighbor multiCounterNICNeighborStats @@ -66,6 +67,7 @@ func (m *multiCounterNICStats) init(a, b *tcpip.NICStats) { m.unknownL4ProtocolRcvdPacketCounts.Init(a.UnknownL4ProtocolRcvdPacketCounts, b.UnknownL4ProtocolRcvdPacketCounts) m.malformedL4RcvdPackets.Init(a.MalformedL4RcvdPackets, b.MalformedL4RcvdPackets) m.tx.init(&a.Tx, &b.Tx) + m.txPacketsDroppedNoBufferSpace.Init(a.TxPacketsDroppedNoBufferSpace, b.TxPacketsDroppedNoBufferSpace) m.rx.init(&a.Rx, &b.Rx) m.disabledRx.init(&a.DisabledRx, &b.DisabledRx) m.neighbor.init(&a.Neighbor, &b.Neighbor) diff --git a/pkg/tcpip/tcpip.go b/pkg/tcpip/tcpip.go index b54930f69..f125c7fd3 100644 --- a/pkg/tcpip/tcpip.go +++ b/pkg/tcpip/tcpip.go @@ -2103,6 +2103,13 @@ type NICStats struct { // Tx contains statistics about transmitted packets. Tx NICPacketStats + // TxPacketsDroppedNoBufferSpace is the number of packets dropepd due to the + // NIC not having enough buffer space to send the packet. + // + // Packets may be dropped with a no buffer space error when the device TX + // queue is full. + TxPacketsDroppedNoBufferSpace *StatCounter + // Rx contains statistics about received packets. Rx NICPacketStats diff --git a/pkg/tcpip/transport/datagram_test.go b/pkg/tcpip/transport/datagram_test.go index 8538cbe89..bf3a7c442 100644 --- a/pkg/tcpip/transport/datagram_test.go +++ b/pkg/tcpip/transport/datagram_test.go @@ -468,7 +468,29 @@ func TestDeviceReturnErrNoBufferSpace(t *testing.T) { t.Fatalf("ep.Connect(%#v): %s", to, err) } - ops := ep.SocketOptions() + stackTxPacketsDroppedNoBufferSpace := s.Stats().NICs.TxPacketsDroppedNoBufferSpace + + nicsInfo := s.NICInfo() + nicInfo, ok := nicsInfo[nicID] + if !ok { + t.Fatalf("expected NICInfo for nicID=%d; got s.NICInfo() = %#v", nicID, nicsInfo) + } + nicTxPacketsDroppedNoBufferSpace := nicInfo.Stats.TxPacketsDroppedNoBufferSpace + + checkStats := func(want uint64) { + t.Helper() + + if got := stackTxPacketsDroppedNoBufferSpace.Value(); got != want { + t.Errorf("got stackTxPacketsDroppedNoBufferSpace.Value() = %d, want = %d", got, want) + } + if got := nicTxPacketsDroppedNoBufferSpace.Value(); got != want { + t.Errorf("got nicTxPacketsDroppedNoBufferSpace.Value() = %d, want = %d", got, want) + } + } + + droppedPkts := uint64(0) + checkStats(droppedPkts) + checkWrite := func(netProto tcpip.NetworkProtocolNumber) { t.Helper() @@ -481,8 +503,12 @@ func TestDeviceReturnErrNoBufferSpace(t *testing.T) { if n, err := ep.Write(&r, tcpip.WriteOptions{}); err != wantErr { t.Fatalf("got Write(...) = (%d, %s), want = (_, %s)", n, err, wantErr) } + + droppedPkts++ + checkStats(droppedPkts) } + ops := ep.SocketOptions() ops.SetIPv4RecvError(true) checkWrite(ipv4.ProtocolNumber)