add switch-wide poe budget tracking via snmp
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
21
nodes.go
21
nodes.go
@@ -94,10 +94,16 @@ func joinParts(parts []string) string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PoEBudget struct {
|
||||||
|
Power float64 // watts in use
|
||||||
|
MaxPower float64 // watts total budget
|
||||||
|
}
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
Name string
|
Name string
|
||||||
Interfaces map[string]*Interface
|
Interfaces map[string]*Interface
|
||||||
MACTable map[string]string // peer MAC -> local interface name
|
MACTable map[string]string // peer MAC -> local interface name
|
||||||
|
PoEBudget *PoEBudget
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) String() string {
|
func (n *Node) String() string {
|
||||||
@@ -106,13 +112,22 @@ func (n *Node) String() string {
|
|||||||
name = "??"
|
name = "??"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var parts []string
|
||||||
|
parts = append(parts, name)
|
||||||
|
|
||||||
|
if n.PoEBudget != nil {
|
||||||
|
parts = append(parts, fmt.Sprintf("[poe:%.0f/%.0fW]", n.PoEBudget.Power, n.PoEBudget.MaxPower))
|
||||||
|
}
|
||||||
|
|
||||||
var ifaces []string
|
var ifaces []string
|
||||||
for _, iface := range n.Interfaces {
|
for _, iface := range n.Interfaces {
|
||||||
ifaces = append(ifaces, iface.String())
|
ifaces = append(ifaces, iface.String())
|
||||||
}
|
}
|
||||||
sort.Slice(ifaces, func(i, j int) bool { return sortorder.NaturalLess(ifaces[i], ifaces[j]) })
|
sort.Slice(ifaces, func(i, j int) bool { return sortorder.NaturalLess(ifaces[i], ifaces[j]) })
|
||||||
|
|
||||||
return fmt.Sprintf("%s {%v}", name, ifaces)
|
parts = append(parts, fmt.Sprintf("{%v}", ifaces))
|
||||||
|
|
||||||
|
return joinParts(parts)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Nodes struct {
|
type Nodes struct {
|
||||||
@@ -365,7 +380,11 @@ func (n *Nodes) logNode(node *Node) {
|
|||||||
if name == "" {
|
if name == "" {
|
||||||
name = "??"
|
name = "??"
|
||||||
}
|
}
|
||||||
|
if node.PoEBudget != nil {
|
||||||
|
log.Printf("[node] %s [poe:%.0f/%.0fW]", name, node.PoEBudget.Power, node.PoEBudget.MaxPower)
|
||||||
|
} else {
|
||||||
log.Printf("[node] %s", name)
|
log.Printf("[node] %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
var ifaceKeys []string
|
var ifaceKeys []string
|
||||||
for ifaceKey := range node.Interfaces {
|
for ifaceKey := range node.Interfaces {
|
||||||
|
|||||||
40
snmp.go
40
snmp.go
@@ -125,6 +125,7 @@ func (t *Tendrils) querySNMPDevice(node *Node, ip net.IP) {
|
|||||||
t.querySysName(snmp, node)
|
t.querySysName(snmp, node)
|
||||||
t.queryInterfaceMACs(snmp, node)
|
t.queryInterfaceMACs(snmp, node)
|
||||||
t.queryInterfaceStats(snmp, node)
|
t.queryInterfaceStats(snmp, node)
|
||||||
|
t.queryPoEBudget(snmp, node)
|
||||||
t.queryBridgeMIB(snmp, node)
|
t.queryBridgeMIB(snmp, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,6 +243,45 @@ func (t *Tendrils) queryInterfaceStats(snmp *gosnmp.GoSNMP, node *Node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Tendrils) queryPoEBudget(snmp *gosnmp.GoSNMP, node *Node) {
|
||||||
|
maxPowerOID := "1.3.6.1.2.1.105.1.3.1.1.2.1"
|
||||||
|
powerOID := "1.3.6.1.2.1.105.1.3.1.1.4.1"
|
||||||
|
|
||||||
|
result, err := snmp.Get([]string{maxPowerOID, powerOID})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var power, maxPower float64
|
||||||
|
for _, v := range result.Variables {
|
||||||
|
var val int
|
||||||
|
switch x := v.Value.(type) {
|
||||||
|
case int:
|
||||||
|
val = x
|
||||||
|
case uint:
|
||||||
|
val = int(x)
|
||||||
|
case int64:
|
||||||
|
val = int(x)
|
||||||
|
case uint64:
|
||||||
|
val = int(x)
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Name == "."+powerOID {
|
||||||
|
power = float64(val)
|
||||||
|
} else if v.Name == "."+maxPowerOID {
|
||||||
|
maxPower = float64(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxPower > 0 {
|
||||||
|
t.nodes.mu.Lock()
|
||||||
|
node.PoEBudget = &PoEBudget{Power: power, MaxPower: maxPower}
|
||||||
|
t.nodes.mu.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Tendrils) getInterfaceTable(snmp *gosnmp.GoSNMP, oid string) map[int]int {
|
func (t *Tendrils) getInterfaceTable(snmp *gosnmp.GoSNMP, oid string) map[int]int {
|
||||||
results, err := snmp.BulkWalkAll(oid)
|
results, err := snmp.BulkWalkAll(oid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user