Skip to content

Commit 436b8d6

Browse files
mdlayherdiscordianfish
authored andcommitted
procfs: clean up softnet parsing APIs and code
Signed-off-by: Matt Layher <[email protected]>
1 parent 314d69e commit 436b8d6

File tree

2 files changed

+66
-59
lines changed

2 files changed

+66
-59
lines changed

net_softnet.go

Lines changed: 54 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,78 +14,85 @@
1414
package procfs
1515

1616
import (
17+
"bufio"
18+
"bytes"
1719
"fmt"
18-
"io/ioutil"
20+
"io"
1921
"strconv"
2022
"strings"
23+
24+
"github.com/prometheus/procfs/internal/util"
2125
)
2226

2327
// For the proc file format details,
2428
// see https://elixir.bootlin.com/linux/v4.17/source/net/core/net-procfs.c#L162
2529
// and https://elixir.bootlin.com/linux/v4.17/source/include/linux/netdevice.h#L2810.
2630

27-
// SoftnetEntry contains a single row of data from /proc/net/softnet_stat
28-
type SoftnetEntry struct {
31+
// SoftnetStat contains a single row of data from /proc/net/softnet_stat
32+
type SoftnetStat struct {
2933
// Number of processed packets
30-
Processed uint
34+
Processed uint32
3135
// Number of dropped packets
32-
Dropped uint
36+
Dropped uint32
3337
// Number of times processing packets ran out of quota
34-
TimeSqueezed uint
38+
TimeSqueezed uint32
3539
}
3640

37-
// GatherSoftnetStats reads /proc/net/softnet_stat, parse the relevant columns,
38-
// and then return a slice of SoftnetEntry's.
39-
func (fs FS) GatherSoftnetStats() ([]SoftnetEntry, error) {
40-
data, err := ioutil.ReadFile(fs.proc.Path("net/softnet_stat"))
41+
// NetSoftnetStat reads data from /proc/net/softnet_stat.
42+
func (fs FS) NetSoftnetStat() ([]SoftnetStat, error) {
43+
b, err := util.ReadFileNoStat(fs.proc.Path("net/softnet_stat"))
4144
if err != nil {
42-
return nil, fmt.Errorf("error reading softnet %s: %s", fs.proc.Path("net/softnet_stat"), err)
45+
return nil, err
4346
}
4447

45-
return parseSoftnetEntries(data)
48+
entries, err := parseSoftnet(bytes.NewReader(b))
49+
if err != nil {
50+
return nil, fmt.Errorf("failed to parse /proc/net/softnet_stat: %v", err)
51+
}
52+
53+
return entries, nil
4654
}
4755

48-
func parseSoftnetEntries(data []byte) ([]SoftnetEntry, error) {
49-
lines := strings.Split(string(data), "\n")
50-
entries := make([]SoftnetEntry, 0)
51-
var err error
52-
const (
53-
expectedColumns = 11
54-
)
55-
for _, line := range lines {
56-
columns := strings.Fields(line)
56+
func parseSoftnet(r io.Reader) ([]SoftnetStat, error) {
57+
const expectedColumns = 11
58+
59+
s := bufio.NewScanner(r)
60+
61+
var stats []SoftnetStat
62+
for s.Scan() {
63+
columns := strings.Fields(s.Text())
5764
width := len(columns)
58-
if width == 0 {
59-
continue
60-
}
61-
if width != expectedColumns {
62-
return []SoftnetEntry{}, fmt.Errorf("%d columns were detected, but %d were expected", width, expectedColumns)
65+
66+
if width != 11 {
67+
return nil, fmt.Errorf("%d columns were detected, but %d were expected", width, expectedColumns)
6368
}
64-
var entry SoftnetEntry
65-
if entry, err = parseSoftnetEntry(columns); err != nil {
66-
return []SoftnetEntry{}, err
69+
70+
// We only parse the first three columns at the moment.
71+
us, err := parseHexUint32s(columns[0:3])
72+
if err != nil {
73+
return nil, err
6774
}
68-
entries = append(entries, entry)
75+
76+
stats = append(stats, SoftnetStat{
77+
Processed: us[0],
78+
Dropped: us[1],
79+
TimeSqueezed: us[2],
80+
})
6981
}
7082

71-
return entries, nil
83+
return stats, nil
7284
}
7385

74-
func parseSoftnetEntry(columns []string) (SoftnetEntry, error) {
75-
var err error
76-
var processed, dropped, timeSqueezed uint64
77-
if processed, err = strconv.ParseUint(columns[0], 16, 32); err != nil {
78-
return SoftnetEntry{}, fmt.Errorf("Unable to parse column 0: %s", err)
79-
}
80-
if dropped, err = strconv.ParseUint(columns[1], 16, 32); err != nil {
81-
return SoftnetEntry{}, fmt.Errorf("Unable to parse column 1: %s", err)
82-
}
83-
if timeSqueezed, err = strconv.ParseUint(columns[2], 16, 32); err != nil {
84-
return SoftnetEntry{}, fmt.Errorf("Unable to parse column 2: %s", err)
86+
func parseHexUint32s(ss []string) ([]uint32, error) {
87+
us := make([]uint32, 0, len(ss))
88+
for _, s := range ss {
89+
u, err := strconv.ParseUint(s, 16, 32)
90+
if err != nil {
91+
return nil, err
92+
}
93+
94+
us = append(us, uint32(u))
8595
}
86-
return SoftnetEntry{
87-
Processed: uint(processed),
88-
Dropped: uint(dropped),
89-
TimeSqueezed: uint(timeSqueezed),
90-
}, nil
96+
97+
return us, nil
9198
}

net_softnet_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,28 @@ package procfs
1515

1616
import (
1717
"testing"
18+
19+
"github.com/google/go-cmp/cmp"
1820
)
1921

20-
func TestSoftnet(t *testing.T) {
22+
func TestNetSoftnet(t *testing.T) {
2123
fs, err := NewFS(procTestFixtures)
2224
if err != nil {
2325
t.Fatal(err)
2426
}
2527

26-
entries, err := fs.GatherSoftnetStats()
28+
want := []SoftnetStat{{
29+
Processed: 0x00015c73,
30+
Dropped: 0x00020e76,
31+
TimeSqueezed: 0xf0000769,
32+
}}
33+
34+
got, err := fs.NetSoftnetStat()
2735
if err != nil {
2836
t.Fatal(err)
2937
}
3038

31-
if want, got := uint(0x00015c73), entries[0].Processed; want != got {
32-
t.Errorf("want %08x, got %08x", want, got)
33-
}
34-
35-
if want, got := uint(0x00020e76), entries[0].Dropped; want != got {
36-
t.Errorf("want %08x, got %08x", want, got)
37-
}
38-
39-
if want, got := uint(0xF0000769), entries[0].TimeSqueezed; want != got {
40-
t.Errorf("want %08x, got %08x", want, got)
39+
if diff := cmp.Diff(want, got); diff != "" {
40+
t.Fatalf("unexpected softnet stats(-want +got):\n%s", diff)
4141
}
4242
}

0 commit comments

Comments
 (0)