Skip to content

Commit 8b6d466

Browse files
authored
Merge pull request #488 from Dentrax/wireless
Add /proc/net/wireless parsing
2 parents 7be8e40 + 150eff5 commit 8b6d466

File tree

3 files changed

+260
-0
lines changed

3 files changed

+260
-0
lines changed

net_wireless.go

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// Copyright 2023 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package procfs
15+
16+
import (
17+
"bufio"
18+
"bytes"
19+
"fmt"
20+
"io"
21+
"strconv"
22+
"strings"
23+
24+
"github.com/prometheus/procfs/internal/util"
25+
)
26+
27+
// Wireless models the content of /proc/net/wireless.
28+
type Wireless struct {
29+
Name string
30+
31+
// Status is the current 4-digit hex value status of the interface.
32+
Status uint64
33+
34+
// QualityLink is the link quality.
35+
QualityLink int
36+
37+
// QualityLevel is the signal gain (dBm).
38+
QualityLevel int
39+
40+
// QualityNoise is the signal noise baseline (dBm).
41+
QualityNoise int
42+
43+
// DiscardedNwid is the number of discarded packets with wrong nwid/essid.
44+
DiscardedNwid int
45+
46+
// DiscardedCrypt is the number of discarded packets with wrong code/decode (WEP).
47+
DiscardedCrypt int
48+
49+
// DiscardedFrag is the number of discarded packets that can't perform MAC reassembly.
50+
DiscardedFrag int
51+
52+
// DiscardedRetry is the number of discarded packets that reached max MAC retries.
53+
DiscardedRetry int
54+
55+
// DiscardedMisc is the number of discarded packets for other reasons.
56+
DiscardedMisc int
57+
58+
// MissedBeacon is the number of missed beacons/superframe.
59+
MissedBeacon int
60+
}
61+
62+
// Wireless returns kernel wireless statistics.
63+
func (fs FS) Wireless() ([]*Wireless, error) {
64+
b, err := util.ReadFileNoStat(fs.proc.Path("net/wireless"))
65+
if err != nil {
66+
return nil, err
67+
}
68+
69+
m, err := parseWireless(bytes.NewReader(b))
70+
if err != nil {
71+
return nil, fmt.Errorf("failed to parse wireless: %w", err)
72+
}
73+
74+
return m, nil
75+
}
76+
77+
// parseWireless parses the contents of /proc/net/wireless.
78+
/*
79+
Inter-| sta-| Quality | Discarded packets | Missed | WE
80+
face | tus | link level noise | nwid crypt frag retry misc | beacon | 22
81+
eth1: 0000 5. -256. -10. 0 1 0 3 0 0
82+
eth2: 0000 5. -256. -20. 0 2 0 4 0 0
83+
*/
84+
func parseWireless(r io.Reader) ([]*Wireless, error) {
85+
var (
86+
interfaces []*Wireless
87+
scanner = bufio.NewScanner(r)
88+
)
89+
90+
for n := 0; scanner.Scan(); n++ {
91+
// Skip the 2 header lines.
92+
if n < 2 {
93+
continue
94+
}
95+
96+
line := scanner.Text()
97+
98+
parts := strings.Split(line, ":")
99+
if len(parts) != 2 {
100+
return nil, fmt.Errorf("expected 2 parts after splitting line by ':', got %d for line %q", len(parts), line)
101+
}
102+
103+
name := strings.TrimSpace(parts[0])
104+
stats := strings.Fields(parts[1])
105+
106+
if len(stats) < 10 {
107+
return nil, fmt.Errorf("invalid number of fields in line %d, expected at least 10, got %d: %q", n, len(stats), line)
108+
}
109+
110+
status, err := strconv.ParseUint(stats[0], 16, 16)
111+
if err != nil {
112+
return nil, fmt.Errorf("invalid status in line %d: %q", n, line)
113+
}
114+
115+
qlink, err := strconv.Atoi(strings.TrimSuffix(stats[1], "."))
116+
if err != nil {
117+
return nil, fmt.Errorf("failed to parse Quality:link as integer %q: %w", qlink, err)
118+
}
119+
120+
qlevel, err := strconv.Atoi(strings.TrimSuffix(stats[2], "."))
121+
if err != nil {
122+
return nil, fmt.Errorf("failed to parse Quality:level as integer %q: %w", qlevel, err)
123+
}
124+
125+
qnoise, err := strconv.Atoi(strings.TrimSuffix(stats[3], "."))
126+
if err != nil {
127+
return nil, fmt.Errorf("failed to parse Quality:noise as integer %q: %w", qnoise, err)
128+
}
129+
130+
dnwid, err := strconv.Atoi(stats[4])
131+
if err != nil {
132+
return nil, fmt.Errorf("failed to parse Discarded:nwid as integer %q: %w", dnwid, err)
133+
}
134+
135+
dcrypt, err := strconv.Atoi(stats[5])
136+
if err != nil {
137+
return nil, fmt.Errorf("failed to parse Discarded:crypt as integer %q: %w", dcrypt, err)
138+
}
139+
140+
dfrag, err := strconv.Atoi(stats[6])
141+
if err != nil {
142+
return nil, fmt.Errorf("failed to parse Discarded:frag as integer %q: %w", dfrag, err)
143+
}
144+
145+
dretry, err := strconv.Atoi(stats[7])
146+
if err != nil {
147+
return nil, fmt.Errorf("failed to parse Discarded:retry as integer %q: %w", dretry, err)
148+
}
149+
150+
dmisc, err := strconv.Atoi(stats[8])
151+
if err != nil {
152+
return nil, fmt.Errorf("failed to parse Discarded:misc as integer %q: %w", dmisc, err)
153+
}
154+
155+
mbeacon, err := strconv.Atoi(stats[9])
156+
if err != nil {
157+
return nil, fmt.Errorf("failed to parse Missed:beacon as integer %q: %w", mbeacon, err)
158+
}
159+
160+
w := &Wireless{
161+
Name: name,
162+
Status: status,
163+
QualityLink: qlink,
164+
QualityLevel: qlevel,
165+
QualityNoise: qnoise,
166+
DiscardedNwid: dnwid,
167+
DiscardedCrypt: dcrypt,
168+
DiscardedFrag: dfrag,
169+
DiscardedRetry: dretry,
170+
DiscardedMisc: dmisc,
171+
MissedBeacon: mbeacon,
172+
}
173+
174+
interfaces = append(interfaces, w)
175+
}
176+
177+
if err := scanner.Err(); err != nil {
178+
return nil, fmt.Errorf("failed to scan /proc/net/wireless: %w", err)
179+
}
180+
181+
return interfaces, nil
182+
}

net_wireless_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2023 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package procfs
15+
16+
import (
17+
"reflect"
18+
"testing"
19+
)
20+
21+
func TestWireless(t *testing.T) {
22+
fs, err := NewFS(procTestFixtures)
23+
if err != nil {
24+
t.Fatalf("failed to open procfs: %v", err)
25+
}
26+
27+
got, err := fs.Wireless()
28+
if err != nil {
29+
t.Fatal(err)
30+
}
31+
32+
expected := []*Wireless{
33+
{
34+
Name: "wlan0",
35+
Status: 1,
36+
QualityLink: 2,
37+
QualityLevel: 3,
38+
QualityNoise: 4,
39+
DiscardedNwid: 5,
40+
DiscardedCrypt: 6,
41+
DiscardedFrag: 7,
42+
DiscardedRetry: 8,
43+
DiscardedMisc: 9,
44+
MissedBeacon: 10,
45+
},
46+
{
47+
Name: "wlan1",
48+
Status: 16,
49+
QualityLink: 9,
50+
QualityLevel: 8,
51+
QualityNoise: 7,
52+
DiscardedNwid: 6,
53+
DiscardedCrypt: 5,
54+
DiscardedFrag: 4,
55+
DiscardedRetry: 3,
56+
DiscardedMisc: 2,
57+
MissedBeacon: 1,
58+
},
59+
}
60+
61+
if len(got) != len(expected) {
62+
t.Fatalf("unexpected number of interfaces parsed %d, expected %d", len(got), len(expected))
63+
}
64+
65+
for i, iface := range got {
66+
if !reflect.DeepEqual(iface, expected[i]) {
67+
t.Errorf("unexpected interface got %+v, expected %+v", iface, expected[i])
68+
}
69+
}
70+
}

testdata/fixtures.ttar

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2568,6 +2568,14 @@ Num RefCount Protocol Flags Type St Path
25682568
0000000000000000: 00000003 00000000 00000000 0001 03
25692569
Mode: 644
25702570
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2571+
Path: fixtures/proc/net/wireless
2572+
Lines: 4
2573+
Inter-| sta-| Quality | Discarded packets | Missed
2574+
face | tus | link level noise | nwid crypt frag retry misc | beacon
2575+
wlan0: 0001 2. 3. 4. 5 6 7 8 9 10
2576+
wlan1: 0010 9 8. 7. 6 5 4 3 2 1
2577+
Mode: 644
2578+
# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
25712579
Path: fixtures/proc/net/xfrm_stat
25722580
Lines: 28
25732581
XfrmInError 1

0 commit comments

Comments
 (0)