Separate network faults from software drops and fix CPU temperature history
This commit is contained in:
103
network_faults.go
Normal file
103
network_faults.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func counterDelta(current, previous uint64) uint64 {
|
||||
if current < previous {
|
||||
return 0
|
||||
}
|
||||
return current - previous
|
||||
}
|
||||
|
||||
func updateInterfaceDeltas(v *NetworkInterface, old NetworkInterface, elapsed float64) {
|
||||
if elapsed <= 0 {
|
||||
return
|
||||
}
|
||||
v.ReceivePerSec = float64(counterDelta(v.ReceiveBytes, old.ReceiveBytes)) / elapsed
|
||||
v.TransmitPerSec = float64(counterDelta(v.TransmitBytes, old.TransmitBytes)) / elapsed
|
||||
v.NewErrors = counterDelta(v.ReceiveErrors, old.ReceiveErrors) + counterDelta(v.TransmitErrors, old.TransmitErrors)
|
||||
v.NewReceiveDrops = counterDelta(v.ReceiveDrops, old.ReceiveDrops)
|
||||
v.NewTransmitDrops = counterDelta(v.TransmitDrops, old.TransmitDrops)
|
||||
v.NewDrops = v.NewReceiveDrops + v.NewTransmitDrops
|
||||
for name, value := range v.FaultCounters {
|
||||
if previous, ok := old.FaultCounters[name]; ok {
|
||||
v.NewFaults += counterDelta(value, previous)
|
||||
}
|
||||
}
|
||||
// A transition matters even if the interface has not carried traffic yet.
|
||||
v.LinkDown = old.Carrier && !v.Carrier
|
||||
}
|
||||
|
||||
func interfaceLinkDown(v NetworkInterface) bool {
|
||||
if v.Kind == "Firewall bridge" || v.Kind == "Firewall link" {
|
||||
return false
|
||||
}
|
||||
if v.LinkDown {
|
||||
return true
|
||||
}
|
||||
used := v.Master != "" || v.ReceiveBytes+v.TransmitBytes > 0
|
||||
if v.Kind == "Physical" {
|
||||
return used && (!v.Carrier || v.State == "down")
|
||||
}
|
||||
return used && v.State == "down"
|
||||
}
|
||||
|
||||
func collectInterfaceFaults(v *NetworkInterface) {
|
||||
base := filepath.Join("/sys/class/net", v.Name)
|
||||
// /proc/net/dev folds missed packets into RX drop. Sysfs keeps software
|
||||
// drops separate from rx_missed_errors, which must still trigger an alert.
|
||||
if n, err := strconv.ParseUint(readTrimmed(filepath.Join(base, "statistics/rx_dropped")), 10, 64); err == nil {
|
||||
v.ReceiveDrops = n
|
||||
}
|
||||
v.FaultCounters = map[string]uint64{}
|
||||
for _, name := range []string{"rx_crc_errors", "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", "tx_fifo_errors", "tx_carrier_errors", "carrier_down_count"} {
|
||||
path := filepath.Join(base, "statistics", name)
|
||||
if name == "carrier_down_count" {
|
||||
path = filepath.Join(base, name)
|
||||
}
|
||||
if n, err := strconv.ParseUint(readTrimmed(path), 10, 64); err == nil {
|
||||
v.FaultCounters[name] = n
|
||||
}
|
||||
}
|
||||
// Only Atlantic exposes the driver-specific names below. No configuration
|
||||
// changes, and a missing ethtool is not itself a network failure.
|
||||
driver, err := filepath.EvalSymlinks(filepath.Join(base, "device/driver"))
|
||||
if err != nil || filepath.Base(driver) != "atlantic" {
|
||||
return
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
if out, err := exec.CommandContext(ctx, "ethtool", "-S", v.Name).Output(); err == nil {
|
||||
for k, n := range parseAtlanticFaults(string(out)) {
|
||||
v.FaultCounters["atlantic:"+k] = n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseAtlanticFaults(output string) map[string]uint64 {
|
||||
result := map[string]uint64{}
|
||||
for _, line := range strings.Split(output, "\n") {
|
||||
key, value, ok := strings.Cut(strings.TrimSpace(line), ":")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(key)
|
||||
if len(fields) == 0 {
|
||||
continue
|
||||
}
|
||||
switch fields[len(fields)-1] {
|
||||
case "InErrors", "InDroppedDma", "AllocFails", "SkbAllocFails", "Restarts":
|
||||
if n, err := strconv.ParseUint(strings.TrimSpace(value), 10, 64); err == nil {
|
||||
result[key] = n
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user