1// Copyright 2018 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// +build !windows 15 16package sysfs 17 18import ( 19 "fmt" 20 "io/ioutil" 21 "os" 22 "path/filepath" 23 24 "github.com/prometheus/procfs/internal/util" 25) 26 27const netclassPath = "class/net" 28 29// NetClassIface contains info from files in /sys/class/net/<iface> 30// for single interface (iface). 31type NetClassIface struct { 32 Name string // Interface name 33 AddrAssignType *int64 // /sys/class/net/<iface>/addr_assign_type 34 AddrLen *int64 // /sys/class/net/<iface>/addr_len 35 Address string // /sys/class/net/<iface>/address 36 Broadcast string // /sys/class/net/<iface>/broadcast 37 Carrier *int64 // /sys/class/net/<iface>/carrier 38 CarrierChanges *int64 // /sys/class/net/<iface>/carrier_changes 39 CarrierUpCount *int64 // /sys/class/net/<iface>/carrier_up_count 40 CarrierDownCount *int64 // /sys/class/net/<iface>/carrier_down_count 41 DevID *int64 // /sys/class/net/<iface>/dev_id 42 Dormant *int64 // /sys/class/net/<iface>/dormant 43 Duplex string // /sys/class/net/<iface>/duplex 44 Flags *int64 // /sys/class/net/<iface>/flags 45 IfAlias string // /sys/class/net/<iface>/ifalias 46 IfIndex *int64 // /sys/class/net/<iface>/ifindex 47 IfLink *int64 // /sys/class/net/<iface>/iflink 48 LinkMode *int64 // /sys/class/net/<iface>/link_mode 49 MTU *int64 // /sys/class/net/<iface>/mtu 50 NameAssignType *int64 // /sys/class/net/<iface>/name_assign_type 51 NetDevGroup *int64 // /sys/class/net/<iface>/netdev_group 52 OperState string // /sys/class/net/<iface>/operstate 53 PhysPortID string // /sys/class/net/<iface>/phys_port_id 54 PhysPortName string // /sys/class/net/<iface>/phys_port_name 55 PhysSwitchID string // /sys/class/net/<iface>/phys_switch_id 56 Speed *int64 // /sys/class/net/<iface>/speed 57 TxQueueLen *int64 // /sys/class/net/<iface>/tx_queue_len 58 Type *int64 // /sys/class/net/<iface>/type 59} 60 61// NetClass is collection of info for every interface (iface) in /sys/class/net. The map keys 62// are interface (iface) names. 63type NetClass map[string]NetClassIface 64 65// NetClassDevices scans /sys/class/net for devices and returns them as a list of names. 66func (fs FS) NetClassDevices() ([]string, error) { 67 var res []string 68 path := fs.sys.Path(netclassPath) 69 70 devices, err := ioutil.ReadDir(path) 71 if err != nil { 72 return res, fmt.Errorf("cannot access dir %q: %w", path, err) 73 } 74 75 for _, deviceDir := range devices { 76 if deviceDir.Mode().IsRegular() { 77 continue 78 } 79 res = append(res, deviceDir.Name()) 80 } 81 82 return res, nil 83} 84 85// NetClass returns info for all net interfaces (iface) read from /sys/class/net/<iface>. 86func (fs FS) NetClass() (NetClass, error) { 87 devices, err := fs.NetClassDevices() 88 if err != nil { 89 return nil, err 90 } 91 92 path := fs.sys.Path(netclassPath) 93 netClass := NetClass{} 94 for _, deviceDir := range devices { 95 interfaceClass, err := netClass.parseNetClassIface(filepath.Join(path, deviceDir)) 96 if err != nil { 97 return nil, err 98 } 99 interfaceClass.Name = deviceDir 100 netClass[deviceDir] = *interfaceClass 101 } 102 return netClass, nil 103} 104 105// parseNetClassIface scans predefined files in /sys/class/net/<iface> 106// directory and gets their contents. 107func (nc NetClass) parseNetClassIface(devicePath string) (*NetClassIface, error) { 108 interfaceClass := NetClassIface{} 109 110 files, err := ioutil.ReadDir(devicePath) 111 if err != nil { 112 return nil, err 113 } 114 115 for _, f := range files { 116 if !f.Mode().IsRegular() { 117 continue 118 } 119 name := filepath.Join(devicePath, f.Name()) 120 value, err := util.SysReadFile(name) 121 if err != nil { 122 if os.IsNotExist(err) || os.IsPermission(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" { 123 continue 124 } 125 return nil, fmt.Errorf("failed to read file %q: %w", name, err) 126 } 127 vp := util.NewValueParser(value) 128 switch f.Name() { 129 case "addr_assign_type": 130 interfaceClass.AddrAssignType = vp.PInt64() 131 case "addr_len": 132 interfaceClass.AddrLen = vp.PInt64() 133 case "address": 134 interfaceClass.Address = value 135 case "broadcast": 136 interfaceClass.Broadcast = value 137 case "carrier": 138 interfaceClass.Carrier = vp.PInt64() 139 case "carrier_changes": 140 interfaceClass.CarrierChanges = vp.PInt64() 141 case "carrier_up_count": 142 interfaceClass.CarrierUpCount = vp.PInt64() 143 case "carrier_down_count": 144 interfaceClass.CarrierDownCount = vp.PInt64() 145 case "dev_id": 146 interfaceClass.DevID = vp.PInt64() 147 case "dormant": 148 interfaceClass.Dormant = vp.PInt64() 149 case "duplex": 150 interfaceClass.Duplex = value 151 case "flags": 152 interfaceClass.Flags = vp.PInt64() 153 case "ifalias": 154 interfaceClass.IfAlias = value 155 case "ifindex": 156 interfaceClass.IfIndex = vp.PInt64() 157 case "iflink": 158 interfaceClass.IfLink = vp.PInt64() 159 case "link_mode": 160 interfaceClass.LinkMode = vp.PInt64() 161 case "mtu": 162 interfaceClass.MTU = vp.PInt64() 163 case "name_assign_type": 164 interfaceClass.NameAssignType = vp.PInt64() 165 case "netdev_group": 166 interfaceClass.NetDevGroup = vp.PInt64() 167 case "operstate": 168 interfaceClass.OperState = value 169 case "phys_port_id": 170 interfaceClass.PhysPortID = value 171 case "phys_port_name": 172 interfaceClass.PhysPortName = value 173 case "phys_switch_id": 174 interfaceClass.PhysSwitchID = value 175 case "speed": 176 interfaceClass.Speed = vp.PInt64() 177 case "tx_queue_len": 178 interfaceClass.TxQueueLen = vp.PInt64() 179 case "type": 180 interfaceClass.Type = vp.PInt64() 181 } 182 } 183 return &interfaceClass, nil 184 185} 186