mirror of
https://github.com/prometheus/node_exporter.git
synced 2025-08-20 18:33:52 -07:00
fix: darwin netdev i/o bytes metric (#3336)
There is a bug in darwin kernel since macOS Ventura 13.2.1, which results in interface i/o bytes values to be truncated at 4GiB. This change uses a workaround to collect the same metrics, taking advantage of another bug. fixes #3333 Signed-off-by: Siavash Safi <git@hosted.run>
This commit is contained in:
parent
43fb05c81d
commit
979a349637
|
@ -22,6 +22,7 @@ import (
|
|||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
@ -71,51 +72,107 @@ func getIfaceData(index int) (*ifMsghdr2, error) {
|
|||
return nil, err
|
||||
}
|
||||
err = binary.Read(bytes.NewReader(rawData), binary.LittleEndian, &data)
|
||||
if err != nil {
|
||||
return &data, err
|
||||
}
|
||||
|
||||
type ifMsghdr2 struct {
|
||||
Msglen uint16
|
||||
Version uint8
|
||||
Type uint8
|
||||
Addrs int32
|
||||
Flags int32
|
||||
Index uint16
|
||||
_ [2]byte
|
||||
SndLen int32
|
||||
SndMaxlen int32
|
||||
SndDrops int32
|
||||
Timer int32
|
||||
Data ifData64
|
||||
/*
|
||||
As of macOS Ventura 13.2.1, there’s a kernel bug which truncates traffic values at the 4GiB mark.
|
||||
This is a workaround to fetch the interface traffic metrics using a sysctl call.
|
||||
Apple wants to prevent fingerprinting by 3rdparty apps and might fix this bug in future which would break this implementation.
|
||||
*/
|
||||
mib := []int32{
|
||||
unix.CTL_NET,
|
||||
unix.AF_LINK,
|
||||
0, // NETLINK_GENERIC: functions not specific to a type of iface
|
||||
2, //IFMIB_IFDATA: per-interface data table
|
||||
int32(index),
|
||||
1, // IFDATA_GENERAL: generic stats for all kinds of ifaces
|
||||
}
|
||||
|
||||
// https://github.com/apple/darwin-xnu/blob/main/bsd/net/if_var.h#L199-L231
|
||||
var mibData ifMibData
|
||||
size := unsafe.Sizeof(mibData)
|
||||
|
||||
if _, _, errno := unix.Syscall6(
|
||||
unix.SYS___SYSCTL,
|
||||
uintptr(unsafe.Pointer(&mib[0])),
|
||||
uintptr(len(mib)),
|
||||
uintptr(unsafe.Pointer(&mibData)),
|
||||
uintptr(unsafe.Pointer(&size)),
|
||||
uintptr(unsafe.Pointer(nil)),
|
||||
0,
|
||||
); errno != 0 {
|
||||
return &data, err
|
||||
}
|
||||
|
||||
var ifdata ifData64
|
||||
err = binary.Read(bytes.NewReader(mibData.Data[:]), binary.LittleEndian, &ifdata)
|
||||
if err != nil {
|
||||
return &data, err
|
||||
}
|
||||
|
||||
data.Data.Ibytes = ifdata.Ibytes
|
||||
data.Data.Obytes = ifdata.Obytes
|
||||
return &data, err
|
||||
}
|
||||
|
||||
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/if.h#L220-L232
|
||||
type ifMsghdr2 struct {
|
||||
Msglen uint16 // to skip over non-understood messages
|
||||
Version uint8 // future binary compatabilit
|
||||
Type uint8 // message type
|
||||
Addrs int32 // like rtm_addrs
|
||||
Flags int32 // value of if_flags
|
||||
Index uint16 // index for associated ifp
|
||||
_ [2]byte // padding for alignment
|
||||
SndLen int32 // instantaneous length of send queue
|
||||
SndMaxlen int32 // maximum length of send queue
|
||||
SndDrops int32 // number of drops in send queue
|
||||
Timer int32 // time until if_watchdog called
|
||||
Data ifData64 // statistics and other data
|
||||
}
|
||||
|
||||
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/if_var.h#L207-L235
|
||||
type ifData64 struct {
|
||||
Type uint8
|
||||
Typelen uint8
|
||||
Physical uint8
|
||||
Addrlen uint8
|
||||
Hdrlen uint8
|
||||
Recvquota uint8
|
||||
Xmitquota uint8
|
||||
Unused1 uint8
|
||||
Mtu uint32
|
||||
Metric uint32
|
||||
Baudrate uint64
|
||||
Ipackets uint64
|
||||
Ierrors uint64
|
||||
Opackets uint64
|
||||
Oerrors uint64
|
||||
Collisions uint64
|
||||
Ibytes uint64
|
||||
Obytes uint64
|
||||
Imcasts uint64
|
||||
Omcasts uint64
|
||||
Iqdrops uint64
|
||||
Noproto uint64
|
||||
Recvtiming uint32
|
||||
Xmittiming uint32
|
||||
Lastchange unix.Timeval32
|
||||
Type uint8 // ethernet, tokenring, etc
|
||||
Typelen uint8 // Length of frame type id
|
||||
Physical uint8 // e.g., AUI, Thinnet, 10base-T, etc
|
||||
Addrlen uint8 // media address length
|
||||
Hdrlen uint8 // media header length
|
||||
Recvquota uint8 // polling quota for receive intrs
|
||||
Xmitquota uint8 // polling quota for xmit intrs
|
||||
Unused1 uint8 // for future use
|
||||
Mtu uint32 // maximum transmission unit
|
||||
Metric uint32 // routing metric (external only)
|
||||
Baudrate uint64 // linespeed
|
||||
|
||||
// volatile statistics
|
||||
Ipackets uint64 // packets received on interface
|
||||
Ierrors uint64 // input errors on interface
|
||||
Opackets uint64 // packets sent on interface
|
||||
Oerrors uint64 // output errors on interface
|
||||
Collisions uint64 // collisions on csma interfaces
|
||||
Ibytes uint64 // total number of octets received
|
||||
Obytes uint64 // total number of octets sent
|
||||
Imcasts uint64 // packets received via multicast
|
||||
Omcasts uint64 // packets sent via multicast
|
||||
Iqdrops uint64 // dropped on input, this interface
|
||||
Noproto uint64 // destined for unsupported protocol
|
||||
Recvtiming uint32 // usec spent receiving when timing
|
||||
Xmittiming uint32 // usec spent xmitting when timing
|
||||
Lastchange unix.Timeval32 // time of last administrative change
|
||||
}
|
||||
|
||||
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/if_mib.h#L65-L74
|
||||
type ifMibData struct {
|
||||
Name [16]byte // name of interface
|
||||
PCount uint32 // number of promiscuous listeners
|
||||
Flags uint32 // interface flags
|
||||
SendLength uint32 // instantaneous length of send queue
|
||||
MaxSendLength uint32 // maximum length of send queue
|
||||
SendDrops uint32 // number of drops in send queue
|
||||
_ [4]uint32 // for future expansion
|
||||
Data [128]byte // generic information and statistics
|
||||
}
|
||||
|
||||
func getNetDevLabels() (map[string]map[string]string, error) {
|
||||
|
|
Loading…
Reference in a new issue