diff --git a/poller/internal/device/interfaces.go b/poller/internal/device/interfaces.go index 53ce1d4..5b1d13f 100644 --- a/poller/internal/device/interfaces.go +++ b/poller/internal/device/interfaces.go @@ -1,10 +1,10 @@ -// Package device provides RouterOS metric collectors for the poller. package device import ( "fmt" "log/slog" "strconv" + "strings" routeros "github.com/go-routeros/routeros/v3" ) @@ -59,3 +59,65 @@ func CollectInterfaces(client *routeros.Client) ([]InterfaceStats, error) { return stats, nil } + +// InterfaceInfo holds basic interface identity data from a RouterOS device. +// This is used for link discovery — MAC addresses identify which device owns +// each end of a network link. +type InterfaceInfo struct { + Name string `json:"name"` + MacAddress string `json:"mac_address"` + Type string `json:"type"` + Running bool `json:"running"` +} + +// normalizeMACAddress lowercases a MAC address for consistent matching. +func normalizeMACAddress(mac string) string { + return strings.ToLower(mac) +} + +// parseRunning converts a RouterOS "true"/"false" string to a Go bool. +func parseRunning(s string) bool { + return s == "true" +} + +// CollectInterfaceInfo queries the RouterOS device for all interfaces and +// returns their name, MAC address, type, and running status. +// +// The /interface/print command is version-agnostic (works on both v6 and v7). +// Entries with an empty mac-address (loopback, bridge without MAC) are skipped. +// +// Returns nil, nil when the device has no interfaces (matching the +// CollectWireless pattern — empty result is not an error). +func CollectInterfaceInfo(client *routeros.Client) ([]InterfaceInfo, error) { + reply, err := client.Run("/interface/print") + if err != nil { + slog.Debug("failed to collect interface info", "error", err) + return nil, nil + } + + if len(reply.Re) == 0 { + return nil, nil + } + + result := make([]InterfaceInfo, 0, len(reply.Re)) + for _, s := range reply.Re { + m := s.Map + mac := m["mac-address"] + if mac == "" { + continue + } + + result = append(result, InterfaceInfo{ + Name: m["name"], + MacAddress: normalizeMACAddress(mac), + Type: m["type"], + Running: parseRunning(m["running"]), + }) + } + + if len(result) == 0 { + return nil, nil + } + + return result, nil +}