From 0dd8c3ab97f94c8cdddd1c46a8a04f6f30820a03 Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Wed, 16 Mar 2022 17:28:59 -0500 Subject: [PATCH] Add structures for interface bonding information Update net_class.go with new structures to handle bonding driver information Add new true/false values to internal.util.parse.ParseBool References: torvalds/linux/drivers/net/bonding/bond_sysfs.c torvalds/linux/drivers/net/bonding/bond_sysfs_slave.c torvalds/linux/include/net/bonding.h torvalds/linux/include/net/bond_options.h torvalds/linux/include/net/bond_3ad.h Signed-off-by: Brandon Ewing --- fixtures.ttar | 359 ++++++++++++++++++++++++++++++++++++++ internal/util/parse.go | 4 +- sysfs/net_class.go | 371 ++++++++++++++++++++++++++++++++++++---- sysfs/net_class_test.go | 154 ++++++++++++----- 4 files changed, 810 insertions(+), 78 deletions(-) diff --git a/fixtures.ttar b/fixtures.ttar index 0c4f6a33d..16b57deb7 100644 --- a/fixtures.ttar +++ b/fixtures.ttar @@ -4599,6 +4599,319 @@ Mode: 644 Directory: fixtures/sys/class/net Mode: 775 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/net/bond0 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/addr_assign_type +Lines: 1 +3 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/addr_len +Lines: 1 +6 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/address +Lines: 1 +02:02:02:02:02:02 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/net/bond0/bonding +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/active_slave +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/ad_actor_key +Lines: 1 +15 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/ad_actor_sys_prio +Lines: 1 +65535 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/ad_actor_system +Lines: 1 +00:00:00:00:00:00 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/ad_aggregator +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/ad_num_ports +Lines: 1 +2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/ad_partner_key +Lines: 1 +1034 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/ad_partner_mac +Lines: 1 +01:23:45:67:89:AB +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/ad_select +Lines: 1 +stable 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/ad_user_port_key +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/all_slaves_active +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/arp_all_targets +Lines: 1 +any 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/arp_interval +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/arp_ip_target +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/arp_validate +Lines: 1 +none 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/downdelay +Lines: 1 +200 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/fail_over_mac +Lines: 1 +none 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/lacp_rate +Lines: 1 +slow 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/lp_interval +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/mii_status +Lines: 1 +up +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/miimon +Lines: 1 +100 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/min_links +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/mode +Lines: 1 +802.3ad 4 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/num_grat_arp +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/num_unsol_na +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/packets_per_slave +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/primary +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/primary_reselect +Lines: 1 +always 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/queue_id +Lines: 1 +eth0:0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/resend_igmp +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/slaves +Lines: 1 +eth0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/tlb_dynamic_lb +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/updelay +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/use_carrier +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/bonding/xmit_hash_policy +Lines: 1 +layer3+4 1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/broadcast +Lines: 1 +ff:ff:ff:ff:ff:ff +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/carrier +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/carrier_changes +Lines: 1 +2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/carrier_down_count +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/carrier_up_count +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/dev_id +Lines: 1 +0x20 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/device +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/dormant +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/duplex +Lines: 1 +full +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/flags +Lines: 1 +0x1303 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/ifalias +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/ifindex +Lines: 1 +2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/iflink +Lines: 1 +2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/link_mode +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/mtu +Lines: 1 +1500 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/name_assign_type +Lines: 1 +2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/netdev_group +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/operstate +Lines: 1 +up +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/phys_port_id +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/phys_port_name +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/phys_switch_id +Lines: 0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/proto_down +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/speed +Lines: 1 +1000 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/tx_queue_len +Lines: 1 +1000 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/bond0/type +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Directory: fixtures/sys/class/net/eth0 Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -4617,6 +4930,49 @@ Lines: 1 01:01:01:01:01:01 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/net/eth0/bonding_slave +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/bonding_slave/ad_actor_oper_port_state +Lines: 1 +61 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/bonding_slave/ad_aggregator_id +Lines: 1 +1 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/bonding_slave/ad_partner_oper_port_state +Lines: 1 +61 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/bonding_slave/link_failure_count +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/bonding_slave/mii_status +Lines: 1 +up +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/bonding_slave/perm_hwaddr +Lines: 1 +01:01:01:01:01:01 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/bonding_slave/queue_id +Lines: 1 +0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/bonding_slave/state +Lines: 1 +active +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Path: fixtures/sys/class/net/eth0/broadcast Lines: 1 ff:ff:ff:ff:ff:ff @@ -4684,6 +5040,9 @@ Lines: 1 1 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/net/eth0/master +SymlinkTo: ../bond0 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Path: fixtures/sys/class/net/eth0/mtu Lines: 1 1500 diff --git a/internal/util/parse.go b/internal/util/parse.go index 22cb07a6b..d7e8c9bf8 100644 --- a/internal/util/parse.go +++ b/internal/util/parse.go @@ -86,9 +86,9 @@ func ReadIntFromFile(path string) (int64, error) { func ParseBool(b string) *bool { var truth bool switch b { - case "enabled": + case "enabled", "up", "1": truth = true - case "disabled": + case "disabled", "down", "0": truth = false default: return nil diff --git a/sysfs/net_class.go b/sysfs/net_class.go index 6dff98e69..b6722edff 100644 --- a/sysfs/net_class.go +++ b/sysfs/net_class.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build linux // +build linux package sysfs @@ -18,44 +19,103 @@ package sysfs import ( "fmt" "io/ioutil" + "net" "os" "path/filepath" + "strconv" + "strings" "github.com/prometheus/procfs/internal/util" ) const netclassPath = "class/net" +// NetClassBondAttrs contains info from files in /sys/class/net//bonding +// for a bonding controller interface (iface) +type NetClassBondAttrs struct { + ActiveDevice *NetClassIface // /sys/class/net//bonding/active_slave + AdActorKey *uint64 // /sys/class/net//bonding/ad_actor_key (Requires CAP_NET_ADMIN) + AdActorSysPriority *uint64 // /sys/class/net//bonding/ad_actor_sys_prio (Requires CAP_NET_ADMIN) + AdActorSystem *net.HardwareAddr // /sys/class/net//bonding/ad_actor_system (Requires CAP_NET_ADMIN) + AdAggregator *uint64 // /sys/class/net//bonding/ad_aggregator + AdNumPorts *uint64 // /sys/class/net//bonding/ad_num_ports + AdPartnerKey *uint64 // /sys/class/net//bonding/ad_partner_key (Requires CAP_NET_ADMIN) + AdPartnerMac *net.HardwareAddr // /sys/class/net//bonding/ad_partner_mac (Requires CAP_NET_ADMIN) + AdSelect *string // /sys/class/net//bonding/ad_select + AdUserPortKey *uint64 // /sys/class/net//bonding/ad_user_port_key (Requires CAP_NET_ADMIN) + AllDevicesActive *bool // /sys/class/net//bonding/all_slaves_active + ARPAllTargets *string // /sys/class/net//bonding/arp_all_targets + ARPInterval *int64 // /sys/class/net//bonding/arp_interval + ARPIPTarget []net.IP // /sys/class/net//bonding/arp_ip_target + ARPValidate *string // /sys/class/net//bonding/arp_validate + DownDelay *int64 // /sys/class/net//bonding/downdelay + FailoverMac *string // /sys/class/net//bonding/failover_mac + LACPRate *string // /sys/class/net//bonding/lacp_rate + LPInterval *int64 // /sys/class/net//bonding/lp_interval + MIIMon *int64 // /sys/class/net//bonding/miimon + MIIStatus *bool // /sys/class/net//bonding/mii_status + MinLinks *uint64 // /sys/class/net//bonding/min_links + Mode *string // /sys/class/net//bonding/mode + NumberGratuitousArp *uint64 // /sys/class/net//bonding/num_grat_arp + NumberUnsolicitedNeighborAdvertisement *uint64 // /sys/class/net//bonding/num_unsol_na + PacketsPerDevice *int64 // /sys/class/net//bonding/packets_per_slave + PrimaryDevice *string // /sys/class/net//bonding/primary + PrimaryReselect *string // /sys/class/net//bonding/primary_reselect + DeviceQueueIDs map[string]uint64 // /sys/class/net//bonding/queue_id + ResendIgmp *int64 // /sys/class/net//bonding/resend_igmp + Devices []*NetClassIface // /sys/class/net//bonding/slaves + TLBDynamicLB *int64 // /sys/class/net//bonding/tlb_dynamic_lb + UpDelay *int64 // /sys/class/net//bonding/updelay + UseCarrier *bool // /sys/class/net//bonding/use_carrier + TransmitHashPolicy *string // /sys/class/net//bonding/xmit_hash_policy +} + +// NetClassBondDeviceAttrs contains info from files in /sys/class/net//bonding_slave +// for a bonding device interface (iface) +type NetClassBondDeviceAttrs struct { + Controller *NetClassIface // /sys/class/net//master + AdActorOperationalPortState *uint64 // /sys/class/net//bonding_slave/ad_actor_oper_port_state + AdAggregatorId *uint64 // /sys/class/net//bonding_slave/ad_aggregator_id + AdPartnerOperationalPortState *uint64 // /sys/class/net//bonding_slave/ad_partner_oper_port_state + LinkFailureCount *uint64 // /sys/class/net//bonding_slave/link_failure_count + MiiStatus *bool // /sys/class/net//bonding_slave/mii_status + PermamentHWAddress *net.HardwareAddr // /sys/class/net//bonding_slave/perm_hwaddr + QueueID *uint64 // /sys/class/net//bonding_slave/queue_id + State *uint64 // /sys/class/net//bonding_slave/state +} + // NetClassIface contains info from files in /sys/class/net/ // for single interface (iface). type NetClassIface struct { - Name string // Interface name - AddrAssignType *int64 // /sys/class/net//addr_assign_type - AddrLen *int64 // /sys/class/net//addr_len - Address string // /sys/class/net//address - Broadcast string // /sys/class/net//broadcast - Carrier *int64 // /sys/class/net//carrier - CarrierChanges *int64 // /sys/class/net//carrier_changes - CarrierUpCount *int64 // /sys/class/net//carrier_up_count - CarrierDownCount *int64 // /sys/class/net//carrier_down_count - DevID *int64 // /sys/class/net//dev_id - Dormant *int64 // /sys/class/net//dormant - Duplex string // /sys/class/net//duplex - Flags *int64 // /sys/class/net//flags - IfAlias string // /sys/class/net//ifalias - IfIndex *int64 // /sys/class/net//ifindex - IfLink *int64 // /sys/class/net//iflink - LinkMode *int64 // /sys/class/net//link_mode - MTU *int64 // /sys/class/net//mtu - NameAssignType *int64 // /sys/class/net//name_assign_type - NetDevGroup *int64 // /sys/class/net//netdev_group - OperState string // /sys/class/net//operstate - PhysPortID string // /sys/class/net//phys_port_id - PhysPortName string // /sys/class/net//phys_port_name - PhysSwitchID string // /sys/class/net//phys_switch_id - Speed *int64 // /sys/class/net//speed - TxQueueLen *int64 // /sys/class/net//tx_queue_len - Type *int64 // /sys/class/net//type + Name string // Interface name + AddrAssignType *int64 // /sys/class/net//addr_assign_type + AddrLen *int64 // /sys/class/net//addr_len + Address string // /sys/class/net//address + Broadcast string // /sys/class/net//broadcast + BondAttrs *NetClassBondAttrs // /sys/class/net//bonding + BondDeviceAttrs *NetClassBondDeviceAttrs // /sys/class/net//bonding_slave + Carrier *int64 // /sys/class/net//carrier + CarrierChanges *int64 // /sys/class/net//carrier_changes + CarrierUpCount *int64 // /sys/class/net//carrier_up_count + CarrierDownCount *int64 // /sys/class/net//carrier_down_count + DevID *int64 // /sys/class/net//dev_id + Dormant *int64 // /sys/class/net//dormant + Duplex string // /sys/class/net//duplex + Flags *int64 // /sys/class/net//flags + IfAlias string // /sys/class/net//ifalias + IfIndex *int64 // /sys/class/net//ifindex + IfLink *int64 // /sys/class/net//iflink + LinkMode *int64 // /sys/class/net//link_mode + MTU *int64 // /sys/class/net//mtu + NameAssignType *int64 // /sys/class/net//name_assign_type + NetDevGroup *int64 // /sys/class/net//netdev_group + OperState string // /sys/class/net//operstate + PhysPortID string // /sys/class/net//phys_port_id + PhysPortName string // /sys/class/net//phys_port_name + PhysSwitchID string // /sys/class/net//phys_switch_id + Speed *int64 // /sys/class/net//speed + TxQueueLen *int64 // /sys/class/net//tx_queue_len + Type *int64 // /sys/class/net//type } // NetClass is collection of info for every interface (iface) in /sys/class/net. The map keys @@ -84,15 +144,14 @@ func (fs FS) NetClassDevices() ([]string, error) { // NetClassByIface returns info for a single net interfaces (iface). func (fs FS) NetClassByIface(devicePath string) (*NetClassIface, error) { - path := fs.sys.Path(netclassPath) - - interfaceClass, err := parseNetClassIface(filepath.Join(path, devicePath)) + devices, err := fs.NetClass() if err != nil { return nil, err } - interfaceClass.Name = devicePath - - return interfaceClass, nil + if device, found := devices[devicePath]; found { + return &device, nil + } + return nil, fmt.Errorf("device %s not found", devicePath) } // NetClass returns info for all net interfaces (iface) read from /sys/class/net/. @@ -112,6 +171,9 @@ func (fs FS) NetClass() (NetClass, error) { interfaceClass.Name = devicePath netClass[devicePath] = *interfaceClass } + if err := fs.resolveBondingRelationships(&netClass); err != nil { + return nil, err + } return netClass, nil } @@ -194,6 +256,249 @@ func parseNetClassIface(devicePath string) (*NetClassIface, error) { interfaceClass.Type = vp.PInt64() } } + bondingPath := filepath.Join(devicePath, "bonding") + if _, err := os.Stat(bondingPath); !os.IsNotExist(err) { + interfaceClass.BondAttrs, err = parseNetClassBondAttrs(bondingPath) + if err != nil { + return nil, err + } + } + bondingDevicesPath := filepath.Join(devicePath, "bonding_slave") + if _, err := os.Stat(bondingDevicesPath); !os.IsNotExist(err) { + interfaceClass.BondDeviceAttrs, err = parseNetClassBondDeviceAttrs(bondingDevicesPath) + if err != nil { + return nil, err + } + } return &interfaceClass, nil } + +func parseNetClassBondAttrs(devicePath string) (*NetClassBondAttrs, error) { + attrs := NetClassBondAttrs{} + + files, err := ioutil.ReadDir(devicePath) + if err != nil { + return nil, err + } + + for _, f := range files { + if !f.Mode().IsRegular() { + continue + } + name := filepath.Join(devicePath, f.Name()) + value, err := util.SysReadFile(name) + if err != nil { + if os.IsNotExist(err) || os.IsPermission(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" { + continue + } + return nil, fmt.Errorf("failed to read file %q: %w", name, err) + } + vp := util.NewValueParser(value) + switch f.Name() { + case "ad_actor_key": + attrs.AdActorKey = vp.PUInt64() + case "ad_actor_sys_prio": + attrs.AdActorSysPriority = vp.PUInt64() + case "ad_actor_system": + mac, err := net.ParseMAC(value) + if err != nil { + return nil, err + } + attrs.AdActorSystem = &mac + case "ad_aggregator": + attrs.AdAggregator = vp.PUInt64() + case "ad_num_ports": + attrs.AdNumPorts = vp.PUInt64() + case "ad_partner_key": + attrs.AdPartnerKey = vp.PUInt64() + case "ad_partner_mac": + mac, err := net.ParseMAC(value) + if err != nil { + return nil, err + } + attrs.AdPartnerMac = &mac + case "ad_select": + attrs.AdSelect = &value + case "ad_user_port_key": + attrs.AdUserPortKey = vp.PUInt64() + case "all_slaves_active": + attrs.AllDevicesActive = util.ParseBool(value) + case "arp_all_targets": + attrs.ARPAllTargets = &value + case "arp_interval": + attrs.ARPInterval = vp.PInt64() + case "arp_ip_target": + ips, err := parseArpTargets(value) + if err != nil { + return nil, err + } + attrs.ARPIPTarget = ips + case "arp_valiate": + attrs.ARPValidate = &value + case "downdelay": + attrs.DownDelay = vp.PInt64() + case "fail_over_mac": + attrs.FailoverMac = &value + case "lacp_rate": + attrs.LACPRate = &value + case "lp_interval": + attrs.LPInterval = vp.PInt64() + case "miimon": + attrs.MIIMon = vp.PInt64() + case "mii_status": + attrs.MIIStatus = util.ParseBool(value) + case "min_links": + attrs.MinLinks = vp.PUInt64() + case "mode": + attrs.Mode = &value + case "num_grat_arp": + attrs.NumberGratuitousArp = vp.PUInt64() + case "num_unsol_na": + attrs.NumberUnsolicitedNeighborAdvertisement = vp.PUInt64() + case "queue_id": + ids, err := parseDeviceQueueIDs(value) + if err != nil { + return nil, err + } + attrs.DeviceQueueIDs = ids + case "packets_per_slave": + attrs.PacketsPerDevice = vp.PInt64() + case "primary_reselect": + attrs.PrimaryReselect = &value + case "resend_igmp": + attrs.ResendIgmp = vp.PInt64() + case "tlb_dynamic_lb": + attrs.TLBDynamicLB = vp.PInt64() + case "updelay": + attrs.UpDelay = vp.PInt64() + case "use_carrier": + attrs.UseCarrier = util.ParseBool(value) + case "xmit_hash_policy": + attrs.TransmitHashPolicy = &value + } + + } + return &attrs, nil +} + +func parseNetClassBondDeviceAttrs(devicePath string) (*NetClassBondDeviceAttrs, error) { + attrs := NetClassBondDeviceAttrs{} + files, err := ioutil.ReadDir(devicePath) + if err != nil { + return nil, err + } + + for _, f := range files { + if !f.Mode().IsRegular() { + continue + } + name := filepath.Join(devicePath, f.Name()) + value, err := util.SysReadFile(name) + if err != nil { + if os.IsNotExist(err) || os.IsPermission(err) || err.Error() == "operation not supported" || err.Error() == "invalid argument" { + continue + } + return nil, fmt.Errorf("failed to read file %q: %w", name, err) + } + vp := util.NewValueParser(value) + switch f.Name() { + case "ad_actor_oper_port_state": + attrs.AdActorOperationalPortState = vp.PUInt64() + case "ad_aggregator_id": + attrs.AdAggregatorId = vp.PUInt64() + case "ad_partner_oper_port_state": + attrs.AdPartnerOperationalPortState = vp.PUInt64() + case "link_failure_count": + attrs.LinkFailureCount = vp.PUInt64() + case "mii_status": + attrs.MiiStatus = util.ParseBool(value) + case "perm_hwaddr": + mac, err := net.ParseMAC(value) + if err != nil { + return nil, err + } + attrs.PermamentHWAddress = &mac + case "queue_id": + attrs.QueueID = vp.PUInt64() + case "state": + attrs.State = vp.PUInt64() + } + } + return &attrs, nil +} + +func (fs FS) resolveBondingRelationships(netClass *NetClass) error { + for _, netClassIface := range *netClass { + if netClassIface.BondAttrs != nil { + path := filepath.Join(fs.sys.Path(netclassPath), netClassIface.Name, "bonding") + if _, err := os.Stat(filepath.Join(path, "active_slave")); !os.IsNotExist(err) { + active_slave, err := util.SysReadFile(filepath.Join(path, "active_slave")) + if err != nil { + return fmt.Errorf("unable to read %s", filepath.Join(path, "active_slave")) + } + if len(active_slave) > 0 { + if intf, exists := (*netClass)[active_slave]; exists { + netClassIface.BondAttrs.ActiveDevice = &intf + } else { + return fmt.Errorf("unable to find device %s", active_slave) + } + } + } + if _, err := os.Stat(filepath.Join(path, "slaves")); !os.IsNotExist(err) { + devices, err := util.SysReadFile(filepath.Join(path, "slaves")) + if err != nil { + return fmt.Errorf("unable to read %s", filepath.Join(path, "slaves")) + } + if devices != "" { + for _, device := range strings.Split(devices, " ") { + if intf, exists := (*netClass)[device]; exists { + netClassIface.BondAttrs.Devices = append(netClassIface.BondAttrs.Devices, &intf) + } else { + return fmt.Errorf("unable to find device %s", device) + } + } + } + } + } + if netClassIface.BondDeviceAttrs != nil { + path := filepath.Join(fs.sys.Path(netclassPath), netClassIface.Name, "master") + controller, err := filepath.EvalSymlinks(path) + if err != nil { + return fmt.Errorf("unable to read %s", path) + } + name := filepath.Base(controller) + if intf, exists := (*netClass)[name]; exists { + netClassIface.BondDeviceAttrs.Controller = &intf + } else { + return fmt.Errorf("unable to find device %s", controller) + } + } + } + return nil +} + +func parseDeviceQueueIDs(data string) (queueIDs map[string]uint64, err error) { + queueIDs = make(map[string]uint64) + for _, line := range strings.Split(data, " ") { + sep := strings.LastIndex(line, ":") + if queueIDs[line[:sep]], err = strconv.ParseUint(line[sep+1:], 10, 64); err != nil { + return nil, err + } + } + return +} + +func parseArpTargets(data string) (arpTargets []net.IP, err error) { + if data == "" { + return + } + for _, ipString := range strings.Split(data, " ") { + ip := net.ParseIP(ipString) + if ip == nil { + return nil, fmt.Errorf("could not parse ip %s", ip) + } + arpTargets = append(arpTargets, ip) + } + return +} diff --git a/sysfs/net_class_test.go b/sysfs/net_class_test.go index f85660756..e1302ae84 100644 --- a/sysfs/net_class_test.go +++ b/sysfs/net_class_test.go @@ -11,13 +11,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +//go:build linux // +build linux package sysfs import ( + "net" "reflect" "testing" + + "github.com/prometheus/procfs/internal/util" ) func TestNewNetClassDevices(t *testing.T) { @@ -31,10 +35,10 @@ func TestNewNetClassDevices(t *testing.T) { t.Fatal(err) } - if len(devices) != 1 { - t.Errorf("Unexpected number of devices, want %d, have %d", 1, len(devices)) + if len(devices) != 2 { + t.Errorf("Unexpected number of devices, want %d, have %d", 2, len(devices)) } - if devices[0] != "eth0" { + if !reflect.DeepEqual(devices, []string{"bond0", "eth0"}) { t.Errorf("Found unexpected device, want %s, have %s", "eth0", devices[0]) } } @@ -70,61 +74,125 @@ func TestNetClass(t *testing.T) { if err != nil { t.Fatal(err) } - - var ( - addrAssignType int64 = 3 - addrLen int64 = 6 - carrier int64 = 1 - carrierChanges int64 = 2 - carrierDownCount int64 = 1 - carrierUpCount int64 = 1 - devID int64 = 32 - dormant int64 = 1 - flags int64 = 4867 - ifIndex int64 = 2 - ifLink int64 = 2 - linkMode int64 = 1 - mtu int64 = 1500 - nameAssignType int64 = 2 - netDevGroup int64 - speed int64 = 1000 - txQueueLen int64 = 1000 - netType int64 = 1 - ) - netClass := NetClass{ + "bond0": { + Address: "02:02:02:02:02:02", + AddrAssignType: util.NewValueParser("3").PInt64(), + AddrLen: util.NewValueParser("6").PInt64(), + Broadcast: "ff:ff:ff:ff:ff:ff", + Carrier: util.NewValueParser("1").PInt64(), + CarrierChanges: util.NewValueParser("2").PInt64(), + CarrierDownCount: util.NewValueParser("1").PInt64(), + CarrierUpCount: util.NewValueParser("1").PInt64(), + DevID: util.NewValueParser("32").PInt64(), + Dormant: util.NewValueParser("1").PInt64(), + Duplex: "full", + Flags: util.NewValueParser("4867").PInt64(), + IfAlias: "", + IfIndex: util.NewValueParser("2").PInt64(), + IfLink: util.NewValueParser("2").PInt64(), + LinkMode: util.NewValueParser("1").PInt64(), + MTU: util.NewValueParser("1500").PInt64(), + Name: "bond0", + NameAssignType: util.NewValueParser("2").PInt64(), + NetDevGroup: util.NewValueParser("0").PInt64(), + OperState: "up", + PhysPortID: "", + PhysPortName: "", + PhysSwitchID: "", + Speed: util.NewValueParser("1000").PInt64(), + TxQueueLen: util.NewValueParser("1000").PInt64(), + Type: util.NewValueParser("1").PInt64(), + BondAttrs: &NetClassBondAttrs{ + AdActorKey: util.NewValueParser("15").PUInt64(), + AdActorSysPriority: util.NewValueParser("65535").PUInt64(), + AdActorSystem: makeMAC("00:00:00:00:00:00"), + AdAggregator: util.NewValueParser("1").PUInt64(), + AdNumPorts: util.NewValueParser("2").PUInt64(), + AdPartnerKey: util.NewValueParser("1034").PUInt64(), + AdPartnerMac: makeMAC("01:23:45:67:89:AB"), + AdSelect: strPTR("stable 0"), + AdUserPortKey: util.NewValueParser("0").PUInt64(), + AllDevicesActive: util.ParseBool("0"), + ARPAllTargets: strPTR("any 0"), + ARPInterval: util.NewValueParser("0").PInt64(), + DownDelay: util.NewValueParser("200").PInt64(), + FailoverMac: strPTR("none 0"), + LACPRate: strPTR("slow 0"), + LPInterval: util.NewValueParser("1").PInt64(), + MIIMon: util.NewValueParser("100").PInt64(), + MIIStatus: util.ParseBool("1"), + MinLinks: util.NewValueParser("0").PUInt64(), + Mode: strPTR("802.3ad 4"), + NumberGratuitousArp: util.NewValueParser("1").PUInt64(), + NumberUnsolicitedNeighborAdvertisement: util.NewValueParser("1").PUInt64(), + PacketsPerDevice: util.NewValueParser("1").PInt64(), + PrimaryReselect: strPTR("always 0"), + ResendIgmp: util.NewValueParser("1").PInt64(), + TLBDynamicLB: util.NewValueParser("1").PInt64(), + UpDelay: util.NewValueParser("0").PInt64(), + UseCarrier: util.ParseBool("1"), + TransmitHashPolicy: strPTR("layer3+4 1"), + }, + }, "eth0": { Address: "01:01:01:01:01:01", - AddrAssignType: &addrAssignType, - AddrLen: &addrLen, + AddrAssignType: util.NewValueParser("3").PInt64(), + AddrLen: util.NewValueParser("6").PInt64(), Broadcast: "ff:ff:ff:ff:ff:ff", - Carrier: &carrier, - CarrierChanges: &carrierChanges, - CarrierDownCount: &carrierDownCount, - CarrierUpCount: &carrierUpCount, - DevID: &devID, - Dormant: &dormant, + Carrier: util.NewValueParser("1").PInt64(), + CarrierChanges: util.NewValueParser("2").PInt64(), + CarrierDownCount: util.NewValueParser("1").PInt64(), + CarrierUpCount: util.NewValueParser("1").PInt64(), + DevID: util.NewValueParser("32").PInt64(), + Dormant: util.NewValueParser("1").PInt64(), Duplex: "full", - Flags: &flags, + Flags: util.NewValueParser("4867").PInt64(), IfAlias: "", - IfIndex: &ifIndex, - IfLink: &ifLink, - LinkMode: &linkMode, - MTU: &mtu, + IfIndex: util.NewValueParser("2").PInt64(), + IfLink: util.NewValueParser("2").PInt64(), + LinkMode: util.NewValueParser("1").PInt64(), + MTU: util.NewValueParser("1500").PInt64(), Name: "eth0", - NameAssignType: &nameAssignType, - NetDevGroup: &netDevGroup, + NameAssignType: util.NewValueParser("2").PInt64(), + NetDevGroup: util.NewValueParser("0").PInt64(), OperState: "up", PhysPortID: "", PhysPortName: "", PhysSwitchID: "", - Speed: &speed, - TxQueueLen: &txQueueLen, - Type: &netType, + Speed: util.NewValueParser("1000").PInt64(), + TxQueueLen: util.NewValueParser("1000").PInt64(), + Type: util.NewValueParser("1").PInt64(), + BondDeviceAttrs: &NetClassBondDeviceAttrs{ + AdActorOperationalPortState: util.NewValueParser("61").PUInt64(), + AdAggregatorId: util.NewValueParser("1").PUInt64(), + AdPartnerOperationalPortState: util.NewValueParser("61").PUInt64(), + LinkFailureCount: util.NewValueParser("0").PUInt64(), + MiiStatus: util.ParseBool("1"), + PermamentHWAddress: makeMAC("01:01:01:01:01:01"), + QueueID: util.NewValueParser("0").PUInt64(), + }, }, } + bond0 := netClass["bond0"] + eth0 := netClass["eth0"] + netClass["bond0"].BondAttrs.Devices = append(netClass["bond0"].BondAttrs.Devices, ð0) + queueIDs := make(map[string]uint64) + queueIDs["eth0"] = 0 + + netClass["bond0"].BondAttrs.DeviceQueueIDs = queueIDs + netClass["eth0"].BondDeviceAttrs.Controller = &bond0 if !reflect.DeepEqual(netClass, nc) { t.Errorf("Result not correct: want %v, have %v", netClass, nc) } } + +func makeMAC(s string) *net.HardwareAddr { + mac, _ := net.ParseMAC(s) + return &mac +} + +func strPTR(s string) *string { + return &s +}