Skip to content

Commit c8c8f52

Browse files
authored
netstat: model legacy TcpExt counters removed from recent kernels (#863)
PAWSPassive, TCPPrequeued, TCPDirectCopyFromBacklog, TCPDirectCopyFromPrequeue, TCPPrequeueDropped, TCPLoss, TCPFACKReorder, TCPForwardRetrans, TCPHPHitsToUser and TCPSchedulerFailed are absent from the current kernel TcpExt table but are still printed by older kernels. Model them so consumers keep metric parity with older kernels; the parser stays additive (absent keys remain nil). See prometheus/node_exporter#3796. Signed-off-by: 霏承 <huangleshu.hls@alibaba-inc.com>
1 parent 95cb71f commit c8c8f52

2 files changed

Lines changed: 90 additions & 0 deletions

File tree

proc_netstat.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,20 @@ type TcpExt struct { // nolint:revive
146146
TCPMTUPFail *float64
147147
TCPMTUPSuccess *float64
148148
TCPWqueueTooBig *float64
149+
150+
// Legacy TcpExt counters dropped from recent kernels' TcpExt table;
151+
// modeled so consumers retain metric parity with older kernels that
152+
// still print them in /proc/net/netstat.
153+
TCPLoss *float64
154+
PAWSPassive *float64
155+
TCPForwardRetrans *float64
156+
TCPSchedulerFailed *float64
157+
TCPPrequeued *float64
158+
TCPDirectCopyFromBacklog *float64
159+
TCPDirectCopyFromPrequeue *float64
160+
TCPPrequeueDropped *float64
161+
TCPFACKReorder *float64
162+
TCPHPHitsToUser *float64
149163
}
150164

151165
type IpExt struct { // nolint:revive
@@ -396,6 +410,26 @@ func parseProcNetstat(r io.Reader, fileName string) (ProcNetstat, error) {
396410
procNetstat.TCPMTUPSuccess = &value
397411
case "TCPWqueueTooBig":
398412
procNetstat.TCPWqueueTooBig = &value
413+
case "TCPLoss":
414+
procNetstat.TCPLoss = &value
415+
case "PAWSPassive":
416+
procNetstat.PAWSPassive = &value
417+
case "TCPForwardRetrans":
418+
procNetstat.TCPForwardRetrans = &value
419+
case "TCPSchedulerFailed":
420+
procNetstat.TCPSchedulerFailed = &value
421+
case "TCPPrequeued":
422+
procNetstat.TCPPrequeued = &value
423+
case "TCPDirectCopyFromBacklog":
424+
procNetstat.TCPDirectCopyFromBacklog = &value
425+
case "TCPDirectCopyFromPrequeue":
426+
procNetstat.TCPDirectCopyFromPrequeue = &value
427+
case "TCPPrequeueDropped":
428+
procNetstat.TCPPrequeueDropped = &value
429+
case "TCPFACKReorder":
430+
procNetstat.TCPFACKReorder = &value
431+
case "TCPHPHitsToUser":
432+
procNetstat.TCPHPHitsToUser = &value
399433
}
400434
case "IpExt":
401435
switch key {

proc_netstat_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package procfs
1515

1616
import (
17+
"strings"
1718
"testing"
1819
)
1920

@@ -48,3 +49,58 @@ func TestProcNetstat(t *testing.T) {
4849
}
4950
}
5051
}
52+
53+
// TestParseProcNetstatLegacyFields covers TcpExt counters that are no longer
54+
// part of the kernel's TcpExt table but were still printed by older kernels.
55+
func TestParseProcNetstatLegacyFields(t *testing.T) {
56+
payload := `TcpExt: SyncookiesSent PAWSPassive TCPPrequeued TCPDirectCopyFromBacklog TCPDirectCopyFromPrequeue TCPPrequeueDropped TCPLoss TCPFACKReorder TCPForwardRetrans TCPHPHitsToUser TCPSchedulerFailed
57+
TcpExt: 1 2 3 4 5 6 7 8 9 10 11
58+
IpExt: InNoRoutes OutOctets
59+
IpExt: 12 13`
60+
61+
procNetstat, err := parseProcNetstat(strings.NewReader(payload), "net/netstat")
62+
if err != nil {
63+
t.Fatal(err)
64+
}
65+
66+
for _, test := range []struct {
67+
name string
68+
want float64
69+
have float64
70+
}{
71+
{name: "TcpExt:SyncookiesSent", want: 1, have: *procNetstat.SyncookiesSent},
72+
{name: "TcpExt:PAWSPassive", want: 2, have: *procNetstat.PAWSPassive},
73+
{name: "TcpExt:TCPPrequeued", want: 3, have: *procNetstat.TCPPrequeued},
74+
{name: "TcpExt:TCPDirectCopyFromBacklog", want: 4, have: *procNetstat.TCPDirectCopyFromBacklog},
75+
{name: "TcpExt:TCPDirectCopyFromPrequeue", want: 5, have: *procNetstat.TCPDirectCopyFromPrequeue},
76+
{name: "TcpExt:TCPPrequeueDropped", want: 6, have: *procNetstat.TCPPrequeueDropped},
77+
{name: "TcpExt:TCPLoss", want: 7, have: *procNetstat.TCPLoss},
78+
{name: "TcpExt:TCPFACKReorder", want: 8, have: *procNetstat.TCPFACKReorder},
79+
{name: "TcpExt:TCPForwardRetrans", want: 9, have: *procNetstat.TCPForwardRetrans},
80+
{name: "TcpExt:TCPHPHitsToUser", want: 10, have: *procNetstat.TCPHPHitsToUser},
81+
{name: "TcpExt:TCPSchedulerFailed", want: 11, have: *procNetstat.TCPSchedulerFailed},
82+
{name: "IpExt:InNoRoutes", want: 12, have: *procNetstat.InNoRoutes},
83+
{name: "IpExt:OutOctets", want: 13, have: *procNetstat.OutOctets},
84+
} {
85+
if test.want != test.have {
86+
t.Errorf("want %s %f, have %f", test.name, test.want, test.have)
87+
}
88+
}
89+
90+
modern := `TcpExt: SyncookiesSent
91+
TcpExt: 1
92+
IpExt: InNoRoutes
93+
IpExt: 12`
94+
95+
pn, err := parseProcNetstat(strings.NewReader(modern), "net/netstat")
96+
if err != nil {
97+
t.Fatal(err)
98+
}
99+
100+
if pn.SyncookiesSent == nil || *pn.SyncookiesSent != 1 {
101+
t.Error("want TcpExt:SyncookiesSent 1")
102+
}
103+
if pn.TCPPrequeued != nil {
104+
t.Error("TCPPrequeued should be nil when the kernel does not report it")
105+
}
106+
}

0 commit comments

Comments
 (0)