Files
tendrils/lldp.go
Ian Gulliver 0d36c21db2 add node names from hostname, lldp, and snmp
populate local node name from hostname. extract system name from lldp packets and snmp sysname oid. call logtree after node merges.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 22:27:31 -08:00

107 lines
2.0 KiB
Go

package tendrils
import (
"context"
"log"
"net"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
func (t *Tendrils) listenLLDP(ctx context.Context, iface net.Interface) {
handle, err := pcap.OpenLive(iface.Name, 65536, true, 5*time.Second)
if err != nil {
log.Printf("[ERROR] failed to open interface %s: %v", iface.Name, err)
return
}
defer handle.Close()
if err := handle.SetBPFFilter("ether proto 0x88cc"); err != nil {
log.Printf("[ERROR] failed to set BPF filter on %s: %v", iface.Name, err)
return
}
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
packets := packetSource.Packets()
for {
select {
case <-ctx.Done():
return
case packet, ok := <-packets:
if !ok {
return
}
t.handleLLDPPacket(iface.Name, packet)
}
}
}
func (t *Tendrils) handleLLDPPacket(ifaceName string, packet gopacket.Packet) {
lldpLayer := packet.Layer(layers.LayerTypeLinkLayerDiscovery)
if lldpLayer == nil {
return
}
lldp, ok := lldpLayer.(*layers.LinkLayerDiscovery)
if !ok {
return
}
if len(lldp.ChassisID.ID) == 6 {
mac := net.HardwareAddr(lldp.ChassisID.ID)
if !isBroadcastOrZero(mac) {
childPort := string(lldp.PortID.ID)
var systemName string
for _, opt := range lldp.Values {
if opt.Type == layers.LLDPTLVSysName {
systemName = string(opt.Value)
break
}
}
t.nodes.Update(nil, []net.HardwareAddr{mac}, ifaceName, childPort, "lldp")
if systemName != "" {
t.nodes.SetName(mac, systemName)
}
}
}
}
func isBroadcastOrZero(mac net.HardwareAddr) bool {
if len(mac) != 6 {
return true
}
allZero := true
allFF := true
for _, b := range mac {
if b != 0x00 {
allZero = false
}
if b != 0xff {
allFF = false
}
}
if allZero || allFF {
return true
}
if mac[0] == 0x01 && mac[1] == 0x00 && mac[2] == 0x5e {
return true
}
if mac[0] == 0x33 && mac[1] == 0x33 {
return true
}
return false
}