add per-node mac table populated from snmp and arp
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
5
arp.go
5
arp.go
@@ -36,6 +36,8 @@ type arpEntry struct {
|
|||||||
func (t *Tendrils) readARPTable() {
|
func (t *Tendrils) readARPTable() {
|
||||||
entries := t.parseARPTable()
|
entries := t.parseARPTable()
|
||||||
|
|
||||||
|
localNode := t.getLocalNode()
|
||||||
|
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if t.Interface != "" && entry.iface != t.Interface {
|
if t.Interface != "" && entry.iface != t.Interface {
|
||||||
continue
|
continue
|
||||||
@@ -49,6 +51,9 @@ func (t *Tendrils) readARPTable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.nodes.Update(nil, entry.mac, []net.IP{entry.ip}, "", "", "arp")
|
t.nodes.Update(nil, entry.mac, []net.IP{entry.ip}, "", "", "arp")
|
||||||
|
if localNode != nil {
|
||||||
|
t.nodes.UpdateMACTable(localNode, entry.mac, entry.iface)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
23
nodes.go
23
nodes.go
@@ -42,6 +42,7 @@ func (i *Interface) String() string {
|
|||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) String() string {
|
func (n *Node) String() string {
|
||||||
@@ -118,6 +119,7 @@ func (n *Nodes) Update(target *Node, mac net.HardwareAddr, ips []net.IP, ifaceNa
|
|||||||
n.nextID++
|
n.nextID++
|
||||||
n.nodes[targetID] = &Node{
|
n.nodes[targetID] = &Node{
|
||||||
Interfaces: map[string]*Interface{},
|
Interfaces: map[string]*Interface{},
|
||||||
|
MACTable: map[string]string{},
|
||||||
}
|
}
|
||||||
isNew = true
|
isNew = true
|
||||||
}
|
}
|
||||||
@@ -263,6 +265,13 @@ func (n *Nodes) mergeNodes(keepID, mergeID int) {
|
|||||||
n.macIndex[iface.MAC.String()] = keepID
|
n.macIndex[iface.MAC.String()] = keepID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for peerMAC, ifaceName := range merge.MACTable {
|
||||||
|
if keep.MACTable == nil {
|
||||||
|
keep.MACTable = map[string]string{}
|
||||||
|
}
|
||||||
|
keep.MACTable[peerMAC] = ifaceName
|
||||||
|
}
|
||||||
|
|
||||||
delete(n.nodes, mergeID)
|
delete(n.nodes, mergeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,6 +295,16 @@ func (n *Nodes) GetByMAC(mac net.HardwareAddr) *Node {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *Nodes) UpdateMACTable(node *Node, peerMAC net.HardwareAddr, ifaceName string) {
|
||||||
|
n.mu.Lock()
|
||||||
|
defer n.mu.Unlock()
|
||||||
|
|
||||||
|
if node.MACTable == nil {
|
||||||
|
node.MACTable = map[string]string{}
|
||||||
|
}
|
||||||
|
node.MACTable[peerMAC.String()] = ifaceName
|
||||||
|
}
|
||||||
|
|
||||||
func (n *Nodes) logNode(node *Node) {
|
func (n *Nodes) logNode(node *Node) {
|
||||||
name := node.Name
|
name := node.Name
|
||||||
if name == "" {
|
if name == "" {
|
||||||
@@ -303,6 +322,10 @@ func (n *Nodes) logNode(node *Node) {
|
|||||||
iface := node.Interfaces[ifaceKey]
|
iface := node.Interfaces[ifaceKey]
|
||||||
log.Printf("[node] %s", iface)
|
log.Printf("[node] %s", iface)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(node.MACTable) > 0 {
|
||||||
|
log.Printf("[node] mac table: %d entries", len(node.MACTable))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Nodes) All() []*Node {
|
func (n *Nodes) All() []*Node {
|
||||||
|
|||||||
21
snmp.go
21
snmp.go
@@ -124,7 +124,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.queryBridgeMIB(snmp, ip)
|
t.queryBridgeMIB(snmp, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tendrils) querySysName(snmp *gosnmp.GoSNMP, node *Node) {
|
func (t *Tendrils) querySysName(snmp *gosnmp.GoSNMP, node *Node) {
|
||||||
@@ -192,7 +192,7 @@ func (t *Tendrils) queryInterfaceMACs(snmp *gosnmp.GoSNMP, node *Node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tendrils) queryBridgeMIB(snmp *gosnmp.GoSNMP, deviceIP net.IP) {
|
func (t *Tendrils) queryBridgeMIB(snmp *gosnmp.GoSNMP, node *Node) {
|
||||||
portOID := "1.3.6.1.2.1.17.7.1.2.2.1.2"
|
portOID := "1.3.6.1.2.1.17.7.1.2.2.1.2"
|
||||||
|
|
||||||
portResults, err := snmp.BulkWalkAll(portOID)
|
portResults, err := snmp.BulkWalkAll(portOID)
|
||||||
@@ -238,19 +238,18 @@ func (t *Tendrils) queryBridgeMIB(snmp *gosnmp.GoSNMP, deviceIP net.IP) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ifIndex, exists := bridgePortToIfIndex[entry.bridgePort]
|
||||||
|
if !exists {
|
||||||
|
ifIndex = entry.bridgePort
|
||||||
|
}
|
||||||
|
ifName := rewritePortName(ifNames[ifIndex])
|
||||||
|
|
||||||
if t.DebugSNMP {
|
if t.DebugSNMP {
|
||||||
ifIndex, exists := bridgePortToIfIndex[entry.bridgePort]
|
log.Printf("[snmp] %s: mac=%s port=%s", snmp.Target, mac, ifName)
|
||||||
if !exists {
|
|
||||||
ifIndex = entry.bridgePort
|
|
||||||
}
|
|
||||||
ifName := ifNames[ifIndex]
|
|
||||||
if ifName == "" {
|
|
||||||
ifName = "??"
|
|
||||||
}
|
|
||||||
log.Printf("[snmp] %s: mac=%s port=%s", deviceIP, mac, ifName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.nodes.Update(nil, mac, nil, "", "", "snmp")
|
t.nodes.Update(nil, mac, nil, "", "", "snmp")
|
||||||
|
t.nodes.UpdateMACTable(node, mac, ifName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
tendrils.go
16
tendrils.go
@@ -97,6 +97,22 @@ func (t *Tendrils) populateLocalAddresses() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Tendrils) getLocalNode() *Node {
|
||||||
|
interfaces, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, iface := range interfaces {
|
||||||
|
if len(iface.HardwareAddr) > 0 {
|
||||||
|
if node := t.nodes.GetByMAC(iface.HardwareAddr); node != nil {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Tendrils) listInterfaces() []net.Interface {
|
func (t *Tendrils) listInterfaces() []net.Interface {
|
||||||
interfaces, err := net.Interfaces()
|
interfaces, err := net.Interfaces()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user