...

Source file src/github.com/prometheus/procfs/sysfs/net_class.go

Documentation: github.com/prometheus/procfs/sysfs

     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  //go:build linux
    15  // +build linux
    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  // NetClassIface contains info from files in /sys/class/net/<iface>
    32  // for single interface (iface).
    33  type NetClassIface struct {
    34  	Name             string // Interface name
    35  	AddrAssignType   *int64 // /sys/class/net/<iface>/addr_assign_type
    36  	AddrLen          *int64 // /sys/class/net/<iface>/addr_len
    37  	Address          string // /sys/class/net/<iface>/address
    38  	Broadcast        string // /sys/class/net/<iface>/broadcast
    39  	Carrier          *int64 // /sys/class/net/<iface>/carrier
    40  	CarrierChanges   *int64 // /sys/class/net/<iface>/carrier_changes
    41  	CarrierUpCount   *int64 // /sys/class/net/<iface>/carrier_up_count
    42  	CarrierDownCount *int64 // /sys/class/net/<iface>/carrier_down_count
    43  	DevID            *int64 // /sys/class/net/<iface>/dev_id
    44  	Dormant          *int64 // /sys/class/net/<iface>/dormant
    45  	Duplex           string // /sys/class/net/<iface>/duplex
    46  	Flags            *int64 // /sys/class/net/<iface>/flags
    47  	IfAlias          string // /sys/class/net/<iface>/ifalias
    48  	IfIndex          *int64 // /sys/class/net/<iface>/ifindex
    49  	IfLink           *int64 // /sys/class/net/<iface>/iflink
    50  	LinkMode         *int64 // /sys/class/net/<iface>/link_mode
    51  	MTU              *int64 // /sys/class/net/<iface>/mtu
    52  	NameAssignType   *int64 // /sys/class/net/<iface>/name_assign_type
    53  	NetDevGroup      *int64 // /sys/class/net/<iface>/netdev_group
    54  	OperState        string // /sys/class/net/<iface>/operstate
    55  	PhysPortID       string // /sys/class/net/<iface>/phys_port_id
    56  	PhysPortName     string // /sys/class/net/<iface>/phys_port_name
    57  	PhysSwitchID     string // /sys/class/net/<iface>/phys_switch_id
    58  	Speed            *int64 // /sys/class/net/<iface>/speed
    59  	TxQueueLen       *int64 // /sys/class/net/<iface>/tx_queue_len
    60  	Type             *int64 // /sys/class/net/<iface>/type
    61  }
    62  
    63  // NetClass is collection of info for every interface (iface) in /sys/class/net. The map keys
    64  // are interface (iface) names.
    65  type NetClass map[string]NetClassIface
    66  
    67  // NetClassDevices scans /sys/class/net for devices and returns them as a list of names.
    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  // NetClassByIface returns info for a single net interfaces (iface).
    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  // NetClass returns info for all net interfaces (iface) read from /sys/class/net/<iface>.
   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  // canIgnoreError returns true if the error is non-fatal and can be ignored.
   122  // Some kernels and some devices don't expose specific attributes or return
   123  // errors when reading those attributes; we can ignore these errors and the
   124  // attribute that caused them.
   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  	// all other errors are fatal
   140  	return false
   141  }
   142  
   143  // ParseNetClassAttribute parses a given file in /sys/class/net/<iface>
   144  // and sets the value in a given NetClassIface object if the value was readable.
   145  // It returns an error if the file cannot be read and the error is fatal.
   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  // parseNetClassIface scans predefined files in /sys/class/net/<iface>
   218  // directory and gets their contents.
   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