Track packets dropped by full device TX queue

QDisc/LinkEndpoint may drop packets if the device's send/transmit queue
is full.

BUG: https://fxbug.dev/98974
PiperOrigin-RevId: 448570489
This commit is contained in:
Ghanan Gowripalan
2022-05-13 13:54:14 -07:00
committed by gVisor bot
parent e189fb6886
commit ae508f4064
5 changed files with 40 additions and 1 deletions
+1
View File
@@ -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."),
+3
View File
@@ -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
}
+2
View File
@@ -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)
+7
View File
@@ -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
+27 -1
View File
@@ -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)