Skip to content

Commit dd6bb71

Browse files
SuperQdiscordianfish
authored andcommitted
Support old conntrack stats
Linux < 2.6.35 was missing the `search_restart` field in nf_conntrack. * Refactor stat parsing to simplify code. * Support 16-field nf_conntrack entries. * Support additional fields. Fixes: #499 Signed-off-by: SuperQ <[email protected]>
1 parent f930a52 commit dd6bb71

File tree

3 files changed

+74
-62
lines changed

3 files changed

+74
-62
lines changed

internal/util/parse.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,21 @@ func ParsePInt64s(ss []string) ([]*int64, error) {
6464
return us, nil
6565
}
6666

67+
// Parses a uint64 from given hex in string.
68+
func ParseHexUint64s(ss []string) ([]*uint64, error) {
69+
us := make([]*uint64, 0, len(ss))
70+
for _, s := range ss {
71+
u, err := strconv.ParseUint(s, 16, 64)
72+
if err != nil {
73+
return nil, err
74+
}
75+
76+
us = append(us, &u)
77+
}
78+
79+
return us, nil
80+
}
81+
6782
// ReadUintFromFile reads a file and attempts to parse a uint64 from it.
6883
func ReadUintFromFile(path string) (uint64, error) {
6984
data, err := os.ReadFile(path)

net_conntrackstat.go

Lines changed: 26 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"bytes"
1919
"fmt"
2020
"io"
21-
"strconv"
2221
"strings"
2322

2423
"github.com/prometheus/procfs/internal/util"
@@ -28,9 +27,13 @@ import (
2827
// and contains netfilter conntrack statistics at one CPU core.
2928
type ConntrackStatEntry struct {
3029
Entries uint64
30+
Searched uint64
3131
Found uint64
32+
New uint64
3233
Invalid uint64
3334
Ignore uint64
35+
Delete uint64
36+
DeleteList uint64
3437
Insert uint64
3538
InsertFailed uint64
3639
Drop uint64
@@ -81,73 +84,34 @@ func parseConntrackStat(r io.Reader) ([]ConntrackStatEntry, error) {
8184

8285
// Parses a ConntrackStatEntry from given array of fields.
8386
func parseConntrackStatEntry(fields []string) (*ConntrackStatEntry, error) {
84-
if len(fields) != 17 {
85-
return nil, fmt.Errorf("invalid conntrackstat entry, missing fields")
86-
}
87-
entry := &ConntrackStatEntry{}
88-
89-
entries, err := parseConntrackStatField(fields[0])
90-
if err != nil {
91-
return nil, err
92-
}
93-
entry.Entries = entries
94-
95-
found, err := parseConntrackStatField(fields[2])
96-
if err != nil {
97-
return nil, err
98-
}
99-
entry.Found = found
100-
101-
invalid, err := parseConntrackStatField(fields[4])
102-
if err != nil {
103-
return nil, err
104-
}
105-
entry.Invalid = invalid
106-
107-
ignore, err := parseConntrackStatField(fields[5])
108-
if err != nil {
109-
return nil, err
110-
}
111-
entry.Ignore = ignore
112-
113-
insert, err := parseConntrackStatField(fields[8])
87+
entries, err := util.ParseHexUint64s(fields)
11488
if err != nil {
115-
return nil, err
89+
return nil, fmt.Errorf("invalid conntrackstat entry, couldn't parse fields: %s", err)
11690
}
117-
entry.Insert = insert
118-
119-
insertFailed, err := parseConntrackStatField(fields[9])
120-
if err != nil {
121-
return nil, err
91+
numEntries := len(entries)
92+
if numEntries < 16 || numEntries > 17 {
93+
return nil, fmt.Errorf("invalid conntrackstat entry, invalid number of fields: %d", numEntries)
12294
}
123-
entry.InsertFailed = insertFailed
12495

125-
drop, err := parseConntrackStatField(fields[10])
126-
if err != nil {
127-
return nil, err
96+
stats := &ConntrackStatEntry{
97+
Entries: *entries[0],
98+
Searched: *entries[1],
99+
Found: *entries[2],
100+
New: *entries[3],
101+
Invalid: *entries[4],
102+
Ignore: *entries[5],
103+
Delete: *entries[6],
104+
DeleteList: *entries[7],
105+
Insert: *entries[8],
106+
InsertFailed: *entries[9],
107+
Drop: *entries[10],
108+
EarlyDrop: *entries[11],
128109
}
129-
entry.Drop = drop
130110

131-
earlyDrop, err := parseConntrackStatField(fields[11])
132-
if err != nil {
133-
return nil, err
111+
// Ignore missing search_restart on Linux < 2.6.35.
112+
if numEntries == 17 {
113+
stats.SearchRestart = *entries[16]
134114
}
135-
entry.EarlyDrop = earlyDrop
136115

137-
searchRestart, err := parseConntrackStatField(fields[16])
138-
if err != nil {
139-
return nil, err
140-
}
141-
entry.SearchRestart = searchRestart
142-
143-
return entry, nil
144-
}
145-
146-
// Parses a uint64 from given hex in string.
147-
func parseConntrackStatField(field string) (uint64, error) {
148-
val, err := strconv.ParseUint(field, 16, 64)
149-
if err != nil {
150-
return 0, fmt.Errorf("couldn't parse %q field: %w", field, err)
151-
}
152-
return val, err
116+
return stats, nil
153117
}

net_conntrackstat_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,36 @@ func TestParseConntrackStat(t *testing.T) {
8383
t.Errorf("want %v, have %v", want, have)
8484
}
8585
}
86+
87+
func TestParseOldConntrackStat(t *testing.T) {
88+
var nfConntrackStat = []byte(`entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete
89+
0000002b 0003159f 02e6786a 00142562 0001bf93 00e1a051 00142537 000b8fe0 000b900b 00000000 00000000 00000000 0001b46a 00000000 00000000 00000000
90+
`)
91+
r := bytes.NewReader(nfConntrackStat)
92+
93+
have, err := parseConntrackStat(r)
94+
if err != nil {
95+
t.Fatal(err)
96+
}
97+
98+
want := []ConntrackStatEntry{
99+
ConntrackStatEntry{
100+
Entries: 43,
101+
Searched: 202143,
102+
Found: 48658538,
103+
New: 1320290,
104+
Invalid: 114579,
105+
Ignore: 14786641,
106+
Delete: 1320247,
107+
DeleteList: 757728,
108+
Insert: 757771,
109+
InsertFailed: 0,
110+
Drop: 0,
111+
EarlyDrop: 0,
112+
SearchRestart: 0,
113+
},
114+
}
115+
if !reflect.DeepEqual(want, have) {
116+
t.Errorf("want %v, have %v", want, have)
117+
}
118+
}

0 commit comments

Comments
 (0)