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"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net"
|
"net"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
@ -71,51 +72,107 @@ func getIfaceData(index int) (*ifMsghdr2, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = binary.Read(bytes.NewReader(rawData), binary.LittleEndian, &data)
|
err = binary.Read(bytes.NewReader(rawData), binary.LittleEndian, &data)
|
||||||
|
if err != nil {
|
||||||
|
return &data, err
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
return &data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/if.h#L220-L232
|
||||||
type ifMsghdr2 struct {
|
type ifMsghdr2 struct {
|
||||||
Msglen uint16
|
Msglen uint16 // to skip over non-understood messages
|
||||||
Version uint8
|
Version uint8 // future binary compatabilit
|
||||||
Type uint8
|
Type uint8 // message type
|
||||||
Addrs int32
|
Addrs int32 // like rtm_addrs
|
||||||
Flags int32
|
Flags int32 // value of if_flags
|
||||||
Index uint16
|
Index uint16 // index for associated ifp
|
||||||
_ [2]byte
|
_ [2]byte // padding for alignment
|
||||||
SndLen int32
|
SndLen int32 // instantaneous length of send queue
|
||||||
SndMaxlen int32
|
SndMaxlen int32 // maximum length of send queue
|
||||||
SndDrops int32
|
SndDrops int32 // number of drops in send queue
|
||||||
Timer int32
|
Timer int32 // time until if_watchdog called
|
||||||
Data ifData64
|
Data ifData64 // statistics and other data
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/apple/darwin-xnu/blob/main/bsd/net/if_var.h#L199-L231
|
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/if_var.h#L207-L235
|
||||||
type ifData64 struct {
|
type ifData64 struct {
|
||||||
Type uint8
|
Type uint8 // ethernet, tokenring, etc
|
||||||
Typelen uint8
|
Typelen uint8 // Length of frame type id
|
||||||
Physical uint8
|
Physical uint8 // e.g., AUI, Thinnet, 10base-T, etc
|
||||||
Addrlen uint8
|
Addrlen uint8 // media address length
|
||||||
Hdrlen uint8
|
Hdrlen uint8 // media header length
|
||||||
Recvquota uint8
|
Recvquota uint8 // polling quota for receive intrs
|
||||||
Xmitquota uint8
|
Xmitquota uint8 // polling quota for xmit intrs
|
||||||
Unused1 uint8
|
Unused1 uint8 // for future use
|
||||||
Mtu uint32
|
Mtu uint32 // maximum transmission unit
|
||||||
Metric uint32
|
Metric uint32 // routing metric (external only)
|
||||||
Baudrate uint64
|
Baudrate uint64 // linespeed
|
||||||
Ipackets uint64
|
|
||||||
Ierrors uint64
|
// volatile statistics
|
||||||
Opackets uint64
|
Ipackets uint64 // packets received on interface
|
||||||
Oerrors uint64
|
Ierrors uint64 // input errors on interface
|
||||||
Collisions uint64
|
Opackets uint64 // packets sent on interface
|
||||||
Ibytes uint64
|
Oerrors uint64 // output errors on interface
|
||||||
Obytes uint64
|
Collisions uint64 // collisions on csma interfaces
|
||||||
Imcasts uint64
|
Ibytes uint64 // total number of octets received
|
||||||
Omcasts uint64
|
Obytes uint64 // total number of octets sent
|
||||||
Iqdrops uint64
|
Imcasts uint64 // packets received via multicast
|
||||||
Noproto uint64
|
Omcasts uint64 // packets sent via multicast
|
||||||
Recvtiming uint32
|
Iqdrops uint64 // dropped on input, this interface
|
||||||
Xmittiming uint32
|
Noproto uint64 // destined for unsupported protocol
|
||||||
Lastchange unix.Timeval32
|
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) {
|
func getNetDevLabels() (map[string]map[string]string, error) {
|
||||||
|
|
Loading…
Reference in a new issue