netlink: read missing attributes from sysfs (#2669)

Read missing dev_id, name_assign_type, and addr_assign_type
from sysfs, since they only take a device-specific lock and
not the whole RTNL lock. This means reading them is much less
impactful on other system processes than many of the other
attributes in sysfs that do take the RTNL lock.

Signed-off-by: Dan Williams <dcbw@redhat.com>
pull/2702/head
Dan Williams 2 years ago committed by GitHub
parent eaacb2e3c7
commit 8c5847bd94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -20,12 +20,14 @@ import (
"errors" "errors"
"fmt" "fmt"
"io/fs" "io/fs"
"path/filepath"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/go-kit/log/level" "github.com/go-kit/log/level"
"github.com/jsimonetti/rtnetlink" "github.com/jsimonetti/rtnetlink"
"github.com/mdlayher/ethtool" "github.com/mdlayher/ethtool"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/procfs/sysfs"
) )
var ( var (
@ -57,14 +59,27 @@ func (c *netClassCollector) netClassRTNLUpdate(ch chan<- prometheus.Metric) erro
} }
} }
// Get most attributes from Netlink
lMsgs, err := c.getNetClassInfoRTNL() lMsgs, err := c.getNetClassInfoRTNL()
if err != nil { if err != nil {
return fmt.Errorf("could not get net class info: %w", err) return fmt.Errorf("could not get net class info: %w", err)
} }
relevantLinks := make([]rtnetlink.LinkMessage, 0, len(lMsgs))
for _, msg := range lMsgs { for _, msg := range lMsgs {
if c.ignoredDevicesPattern.MatchString(msg.Attributes.Name) { if !c.ignoredDevicesPattern.MatchString(msg.Attributes.Name) {
continue relevantLinks = append(relevantLinks, msg)
} }
}
// Read sysfs for attributes that Netlink doesn't expose
sysfsAttrs, err := getSysfsAttributes(relevantLinks)
if err != nil {
return fmt.Errorf("could not get sysfs device info: %w", err)
}
// Parse all the info and update metrics
for _, msg := range relevantLinks {
upDesc := prometheus.NewDesc( upDesc := prometheus.NewDesc(
prometheus.BuildFQName(namespace, c.subsystem, "up"), prometheus.BuildFQName(namespace, c.subsystem, "up"),
"Value is 1 if operstate is 'up', 0 otherwise.", "Value is 1 if operstate is 'up', 0 otherwise.",
@ -96,12 +111,16 @@ func (c *netClassCollector) netClassRTNLUpdate(ch chan<- prometheus.Metric) erro
duplex = lm.Duplex.String() duplex = lm.Duplex.String()
} }
ifaceInfo := sysfsAttrs[msg.Attributes.Name]
ch <- prometheus.MustNewConstMetric(infoDesc, prometheus.GaugeValue, infoValue, msg.Attributes.Name, msg.Attributes.Address.String(), msg.Attributes.Broadcast.String(), duplex, operstateStr[int(msg.Attributes.OperationalState)], ifalias) ch <- prometheus.MustNewConstMetric(infoDesc, prometheus.GaugeValue, infoValue, msg.Attributes.Name, msg.Attributes.Address.String(), msg.Attributes.Broadcast.String(), duplex, operstateStr[int(msg.Attributes.OperationalState)], ifalias)
pushMetric(ch, c.getFieldDesc("address_assign_type"), "address_assign_type", ifaceInfo.AddrAssignType, prometheus.GaugeValue, msg.Attributes.Name)
pushMetric(ch, c.getFieldDesc("carrier"), "carrier", msg.Attributes.Carrier, prometheus.GaugeValue, msg.Attributes.Name) pushMetric(ch, c.getFieldDesc("carrier"), "carrier", msg.Attributes.Carrier, prometheus.GaugeValue, msg.Attributes.Name)
pushMetric(ch, c.getFieldDesc("carrier_changes_total"), "carrier_changes_total", msg.Attributes.CarrierChanges, prometheus.CounterValue, msg.Attributes.Name) pushMetric(ch, c.getFieldDesc("carrier_changes_total"), "carrier_changes_total", msg.Attributes.CarrierChanges, prometheus.CounterValue, msg.Attributes.Name)
pushMetric(ch, c.getFieldDesc("carrier_up_changes_total"), "carrier_up_changes_total", msg.Attributes.CarrierUpCount, prometheus.CounterValue, msg.Attributes.Name) pushMetric(ch, c.getFieldDesc("carrier_up_changes_total"), "carrier_up_changes_total", msg.Attributes.CarrierUpCount, prometheus.CounterValue, msg.Attributes.Name)
pushMetric(ch, c.getFieldDesc("carrier_down_changes_total"), "carrier_down_changes_total", msg.Attributes.CarrierDownCount, prometheus.CounterValue, msg.Attributes.Name) pushMetric(ch, c.getFieldDesc("carrier_down_changes_total"), "carrier_down_changes_total", msg.Attributes.CarrierDownCount, prometheus.CounterValue, msg.Attributes.Name)
pushMetric(ch, c.getFieldDesc("device_id"), "device_id", ifaceInfo.DevID, prometheus.GaugeValue, msg.Attributes.Name)
pushMetric(ch, c.getFieldDesc("flags"), "flags", msg.Flags, prometheus.GaugeValue, msg.Attributes.Name) pushMetric(ch, c.getFieldDesc("flags"), "flags", msg.Flags, prometheus.GaugeValue, msg.Attributes.Name)
pushMetric(ch, c.getFieldDesc("iface_id"), "iface_id", msg.Index, prometheus.GaugeValue, msg.Attributes.Name) pushMetric(ch, c.getFieldDesc("iface_id"), "iface_id", msg.Index, prometheus.GaugeValue, msg.Attributes.Name)
pushMetric(ch, c.getFieldDesc("iface_link_mode"), "iface_link_mode", msg.Attributes.LinkMode, prometheus.GaugeValue, msg.Attributes.Name) pushMetric(ch, c.getFieldDesc("iface_link_mode"), "iface_link_mode", msg.Attributes.LinkMode, prometheus.GaugeValue, msg.Attributes.Name)
@ -117,6 +136,7 @@ func (c *netClassCollector) netClassRTNLUpdate(ch chan<- prometheus.Metric) erro
} }
pushMetric(ch, c.getFieldDesc("mtu_bytes"), "mtu_bytes", msg.Attributes.MTU, prometheus.GaugeValue, msg.Attributes.Name) pushMetric(ch, c.getFieldDesc("mtu_bytes"), "mtu_bytes", msg.Attributes.MTU, prometheus.GaugeValue, msg.Attributes.Name)
pushMetric(ch, c.getFieldDesc("name_assign_type"), "name_assign_type", ifaceInfo.NameAssignType, prometheus.GaugeValue, msg.Attributes.Name)
pushMetric(ch, c.getFieldDesc("net_dev_group"), "net_dev_group", msg.Attributes.NetDevGroup, prometheus.GaugeValue, msg.Attributes.Name) pushMetric(ch, c.getFieldDesc("net_dev_group"), "net_dev_group", msg.Attributes.NetDevGroup, prometheus.GaugeValue, msg.Attributes.Name)
pushMetric(ch, c.getFieldDesc("transmit_queue_length"), "transmit_queue_length", msg.Attributes.TxQueueLen, prometheus.GaugeValue, msg.Attributes.Name) pushMetric(ch, c.getFieldDesc("transmit_queue_length"), "transmit_queue_length", msg.Attributes.TxQueueLen, prometheus.GaugeValue, msg.Attributes.Name)
pushMetric(ch, c.getFieldDesc("protocol_type"), "protocol_type", msg.Type, prometheus.GaugeValue, msg.Attributes.Name) pushMetric(ch, c.getFieldDesc("protocol_type"), "protocol_type", msg.Type, prometheus.GaugeValue, msg.Attributes.Name)
@ -186,3 +206,25 @@ func (c *netClassCollector) getLinkModes() ([]*ethtool.LinkMode, error) {
return lms, err return lms, err
} }
// getSysfsAttributes reads attributes that are absent from netlink but provided
// by sysfs.
func getSysfsAttributes(links []rtnetlink.LinkMessage) (sysfs.NetClass, error) {
netClass := sysfs.NetClass{}
for _, msg := range links {
interfaceClass := sysfs.NetClassIface{}
ifName := msg.Attributes.Name
devPath := filepath.Join("/sys", "class", "net", ifName)
// These three attributes hold a device-specific lock when
// accessed, not the RTNL lock, so they are much less impactful
// than reading most of the other attributes from sysfs.
for _, attr := range []string{"addr_assign_type", "dev_id", "name_assign_type"} {
if err := sysfs.ParseNetClassAttribute(devPath, attr, &interfaceClass); err != nil {
return nil, err
}
}
netClass[ifName] = interfaceClass
}
return netClass, nil
}

Loading…
Cancel
Save