Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions proc_netstat.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,20 @@ type TcpExt struct { // nolint:revive
TCPMTUPFail *float64
TCPMTUPSuccess *float64
TCPWqueueTooBig *float64

// Legacy TcpExt counters dropped from recent kernels' TcpExt table;
// modeled so consumers retain metric parity with older kernels that
// still print them in /proc/net/netstat.
TCPLoss *float64
PAWSPassive *float64
TCPForwardRetrans *float64
TCPSchedulerFailed *float64
TCPPrequeued *float64
TCPDirectCopyFromBacklog *float64
TCPDirectCopyFromPrequeue *float64
TCPPrequeueDropped *float64
TCPFACKReorder *float64
TCPHPHitsToUser *float64
}

type IpExt struct { // nolint:revive
Expand Down Expand Up @@ -396,6 +410,26 @@ func parseProcNetstat(r io.Reader, fileName string) (ProcNetstat, error) {
procNetstat.TCPMTUPSuccess = &value
case "TCPWqueueTooBig":
procNetstat.TCPWqueueTooBig = &value
case "TCPLoss":
procNetstat.TCPLoss = &value
case "PAWSPassive":
procNetstat.PAWSPassive = &value
case "TCPForwardRetrans":
procNetstat.TCPForwardRetrans = &value
case "TCPSchedulerFailed":
procNetstat.TCPSchedulerFailed = &value
case "TCPPrequeued":
procNetstat.TCPPrequeued = &value
case "TCPDirectCopyFromBacklog":
procNetstat.TCPDirectCopyFromBacklog = &value
case "TCPDirectCopyFromPrequeue":
procNetstat.TCPDirectCopyFromPrequeue = &value
case "TCPPrequeueDropped":
procNetstat.TCPPrequeueDropped = &value
case "TCPFACKReorder":
procNetstat.TCPFACKReorder = &value
case "TCPHPHitsToUser":
procNetstat.TCPHPHitsToUser = &value
}
case "IpExt":
switch key {
Expand Down
56 changes: 56 additions & 0 deletions proc_netstat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package procfs

import (
"strings"
"testing"
)

Expand Down Expand Up @@ -48,3 +49,58 @@ func TestProcNetstat(t *testing.T) {
}
}
}

// TestParseProcNetstatLegacyFields covers TcpExt counters that are no longer
// part of the kernel's TcpExt table but were still printed by older kernels.
func TestParseProcNetstatLegacyFields(t *testing.T) {
payload := `TcpExt: SyncookiesSent PAWSPassive TCPPrequeued TCPDirectCopyFromBacklog TCPDirectCopyFromPrequeue TCPPrequeueDropped TCPLoss TCPFACKReorder TCPForwardRetrans TCPHPHitsToUser TCPSchedulerFailed
TcpExt: 1 2 3 4 5 6 7 8 9 10 11
IpExt: InNoRoutes OutOctets
IpExt: 12 13`

procNetstat, err := parseProcNetstat(strings.NewReader(payload), "net/netstat")
if err != nil {
t.Fatal(err)
}

for _, test := range []struct {
name string
want float64
have float64
}{
{name: "TcpExt:SyncookiesSent", want: 1, have: *procNetstat.SyncookiesSent},
{name: "TcpExt:PAWSPassive", want: 2, have: *procNetstat.PAWSPassive},
{name: "TcpExt:TCPPrequeued", want: 3, have: *procNetstat.TCPPrequeued},
{name: "TcpExt:TCPDirectCopyFromBacklog", want: 4, have: *procNetstat.TCPDirectCopyFromBacklog},
{name: "TcpExt:TCPDirectCopyFromPrequeue", want: 5, have: *procNetstat.TCPDirectCopyFromPrequeue},
{name: "TcpExt:TCPPrequeueDropped", want: 6, have: *procNetstat.TCPPrequeueDropped},
{name: "TcpExt:TCPLoss", want: 7, have: *procNetstat.TCPLoss},
{name: "TcpExt:TCPFACKReorder", want: 8, have: *procNetstat.TCPFACKReorder},
{name: "TcpExt:TCPForwardRetrans", want: 9, have: *procNetstat.TCPForwardRetrans},
{name: "TcpExt:TCPHPHitsToUser", want: 10, have: *procNetstat.TCPHPHitsToUser},
{name: "TcpExt:TCPSchedulerFailed", want: 11, have: *procNetstat.TCPSchedulerFailed},
{name: "IpExt:InNoRoutes", want: 12, have: *procNetstat.InNoRoutes},
{name: "IpExt:OutOctets", want: 13, have: *procNetstat.OutOctets},
} {
if test.want != test.have {
t.Errorf("want %s %f, have %f", test.name, test.want, test.have)
}
}

modern := `TcpExt: SyncookiesSent
TcpExt: 1
IpExt: InNoRoutes
IpExt: 12`

pn, err := parseProcNetstat(strings.NewReader(modern), "net/netstat")
if err != nil {
t.Fatal(err)
}

if pn.SyncookiesSent == nil || *pn.SyncookiesSent != 1 {
t.Error("want TcpExt:SyncookiesSent 1")
}
if pn.TCPPrequeued != nil {
t.Error("TCPPrequeued should be nil when the kernel does not report it")
}
}