...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package sysfs
18
19 import (
20 "errors"
21 "fmt"
22 "os"
23 "path/filepath"
24 "syscall"
25
26 "github.com/prometheus/procfs/internal/util"
27 )
28
29 const netclassPath = "class/net"
30
31
32
33 type NetClassIface struct {
34 Name string
35 AddrAssignType *int64
36 AddrLen *int64
37 Address string
38 Broadcast string
39 Carrier *int64
40 CarrierChanges *int64
41 CarrierUpCount *int64
42 CarrierDownCount *int64
43 DevID *int64
44 Dormant *int64
45 Duplex string
46 Flags *int64
47 IfAlias string
48 IfIndex *int64
49 IfLink *int64
50 LinkMode *int64
51 MTU *int64
52 NameAssignType *int64
53 NetDevGroup *int64
54 OperState string
55 PhysPortID string
56 PhysPortName string
57 PhysSwitchID string
58 Speed *int64
59 TxQueueLen *int64
60 Type *int64
61 }
62
63
64
65 type NetClass map[string]NetClassIface
66
67
68 func (fs FS) NetClassDevices() ([]string, error) {
69 var res []string
70 path := fs.sys.Path(netclassPath)
71
72 devices, err := os.ReadDir(path)
73 if err != nil {
74 return res, fmt.Errorf("cannot access dir %q: %w", path, err)
75 }
76
77 for _, deviceDir := range devices {
78 if deviceDir.Type().IsRegular() {
79 continue
80 }
81 res = append(res, deviceDir.Name())
82 }
83
84 return res, nil
85 }
86
87
88 func (fs FS) NetClassByIface(devicePath string) (*NetClassIface, error) {
89 path := fs.sys.Path(netclassPath)
90
91 interfaceClass, err := parseNetClassIface(filepath.Join(path, devicePath))
92 if err != nil {
93 return nil, err
94 }
95 interfaceClass.Name = devicePath
96
97 return interfaceClass, nil
98 }
99
100
101 func (fs FS) NetClass() (NetClass, error) {
102 devices, err := fs.NetClassDevices()
103 if err != nil {
104 return nil, err
105 }
106
107 path := fs.sys.Path(netclassPath)
108 netClass := NetClass{}
109 for _, devicePath := range devices {
110 interfaceClass, err := parseNetClassIface(filepath.Join(path, devicePath))
111 if err != nil {
112 return nil, err
113 }
114 interfaceClass.Name = devicePath
115 netClass[devicePath] = *interfaceClass
116 }
117
118 return netClass, nil
119 }
120
121
122
123
124
125 func canIgnoreError(err error) bool {
126 var errno syscall.Errno
127
128 if os.IsNotExist(err) {
129 return true
130 } else if os.IsPermission(err) {
131 return true
132 } else if err.Error() == "operation not supported" {
133 return true
134 } else if errors.Is(err, os.ErrInvalid) {
135 return true
136 } else if errors.As(err, &errno) && (errno == syscall.EINVAL) {
137 return true
138 }
139
140 return false
141 }
142
143
144
145
146 func ParseNetClassAttribute(devicePath, attrName string, interfaceClass *NetClassIface) error {
147 attrPath := filepath.Join(devicePath, attrName)
148 value, err := util.SysReadFile(attrPath)
149 if err != nil {
150 if canIgnoreError(err) {
151 return nil
152 }
153 return fmt.Errorf("failed to read file %q: %w", attrPath, err)
154 }
155
156 vp := util.NewValueParser(value)
157 switch attrName {
158 case "addr_assign_type":
159 interfaceClass.AddrAssignType = vp.PInt64()
160 case "addr_len":
161 interfaceClass.AddrLen = vp.PInt64()
162 case "address":
163 interfaceClass.Address = value
164 case "broadcast":
165 interfaceClass.Broadcast = value
166 case "carrier":
167 interfaceClass.Carrier = vp.PInt64()
168 case "carrier_changes":
169 interfaceClass.CarrierChanges = vp.PInt64()
170 case "carrier_up_count":
171 interfaceClass.CarrierUpCount = vp.PInt64()
172 case "carrier_down_count":
173 interfaceClass.CarrierDownCount = vp.PInt64()
174 case "dev_id":
175 interfaceClass.DevID = vp.PInt64()
176 case "dormant":
177 interfaceClass.Dormant = vp.PInt64()
178 case "duplex":
179 interfaceClass.Duplex = value
180 case "flags":
181 interfaceClass.Flags = vp.PInt64()
182 case "ifalias":
183 interfaceClass.IfAlias = value
184 case "ifindex":
185 interfaceClass.IfIndex = vp.PInt64()
186 case "iflink":
187 interfaceClass.IfLink = vp.PInt64()
188 case "link_mode":
189 interfaceClass.LinkMode = vp.PInt64()
190 case "mtu":
191 interfaceClass.MTU = vp.PInt64()
192 case "name_assign_type":
193 interfaceClass.NameAssignType = vp.PInt64()
194 case "netdev_group":
195 interfaceClass.NetDevGroup = vp.PInt64()
196 case "operstate":
197 interfaceClass.OperState = value
198 case "phys_port_id":
199 interfaceClass.PhysPortID = value
200 case "phys_port_name":
201 interfaceClass.PhysPortName = value
202 case "phys_switch_id":
203 interfaceClass.PhysSwitchID = value
204 case "speed":
205 interfaceClass.Speed = vp.PInt64()
206 case "tx_queue_len":
207 interfaceClass.TxQueueLen = vp.PInt64()
208 case "type":
209 interfaceClass.Type = vp.PInt64()
210 default:
211 return nil
212 }
213
214 return nil
215 }
216
217
218
219 func parseNetClassIface(devicePath string) (*NetClassIface, error) {
220 interfaceClass := NetClassIface{}
221
222 files, err := os.ReadDir(devicePath)
223 if err != nil {
224 return nil, err
225 }
226
227 for _, f := range files {
228 if !f.Type().IsRegular() {
229 continue
230 }
231 if err := ParseNetClassAttribute(devicePath, f.Name(), &interfaceClass); err != nil {
232 return nil, err
233 }
234 }
235
236 return &interfaceClass, nil
237 }
238
View as plain text