使用Golang简化现有库以获取LLDP信息
使用Golang简化现有库以获取LLDP信息 我刚开始学习Go语言和编程。我能写一些简单的脚本,但我的知识也就仅限于此了。
我想编写的代码: 我希望有一个“简单”的函数,可以调用它来获取指定接口的LLDP邻居信息。
我已经找到了这个项目,它似乎已经实现了我的需求
我的问题: 它是一个大型软件的插件,并且似乎通过gRPC与其他进程通信。 所以它对我来说功能太多了。我真的只想要一个阻塞函数,调用后返回指定接口的LLDP信息。 于是我尝试了这样做:lldp.go - Pastebin.com(如果你要测试,需要修改第183行的接口名称)。
遗憾的是它似乎没有正常工作:
go build lldptest.go && ./lldptest 2.6.3
2022/10/24 21:06:14 LLDP Plugin Started.
2022/10/24 21:06:14 Started Capture
2022/10/24 21:06:24 Opened interface: en0
SysName: %s lol
2022/10/24 21:06:26 Waited for all processes to stop
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
{{0 0 0} <nil>}
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x38 pc=0x10044daac]
goroutine 35 [running]:
github.com/RackHD/inservice/plugins/lldp/neighbors.(*Neighbors).translatePacket(0x1e?, 0xc000100a00)
/Users/user/code/go/pkg/mod/github.com/!rack!h!d/inservice@v0.0.0-20170929210032-8049898f824e/plugins/lldp/neighbors/decode.go:12 +0x2c
github.com/RackHD/inservice/plugins/lldp/neighbors.(*Neighbors).ProcessPacket(0xc00022e150, 0xc00022e0f0?, {{0x0, 0x0, {0x0, 0x0}, {0x0, 0x0, 0x0}, 0x0}, ...})
/Users/user/code/go/pkg/mod/github.com/!rack!h!d/inservice@v0.0.0-20170929210032-8049898f824e/plugins/lldp/neighbors/neighbors.go:148 +0xc5
created by main.(*LLDPPlugin).Capture.func1
/tmp/lldptest/lldptest.go:139 +0x38
更多关于使用Golang简化现有库以获取LLDP信息的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于使用Golang简化现有库以获取LLDP信息的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我看了你的代码和错误信息。问题在于你直接使用了RackHD库的neighbors.Neighbors结构,但该库的设计需要完整的插件初始化流程。这里提供一个简化版的LLDP抓取实现:
package main
import (
"fmt"
"log"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
type LLDPNeighbor struct {
ChassisID string
PortID string
SystemName string
PortDesc string
SystemDesc string
Capabilities []string
}
func GetLLDPNeighbors(interfaceName string, timeout time.Duration) ([]LLDPNeighbor, error) {
handle, err := pcap.OpenLive(interfaceName, 65536, true, pcap.BlockForever)
if err != nil {
return nil, fmt.Errorf("打开接口失败: %v", err)
}
defer handle.Close()
// 设置BPF过滤器只捕获LLDP包
err = handle.SetBPFFilter("ether proto 0x88cc")
if err != nil {
return nil, fmt.Errorf("设置过滤器失败: %v", err)
}
var neighbors []LLDPNeighbor
endTime := time.Now().Add(timeout)
for time.Now().Before(endTime) {
data, _, err := handle.ReadPacketData()
if err != nil {
if err == pcap.NextErrorTimeoutExpired {
continue
}
break
}
packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.Default)
if lldpLayer := packet.Layer(layers.LayerTypeLinkLayerDiscovery); lldpLayer != nil {
lldp := lldpLayer.(*layers.LinkLayerDiscovery)
neighbor := LLDPNeighbor{}
// 解析Chassis ID
if lldp.ChassisID != nil {
neighbor.ChassisID = string(lldp.ChassisID.ID)
}
// 解析Port ID
if lldp.PortID != nil {
neighbor.PortID = string(lldp.PortID.ID)
}
// 解析TLVs
for _, tlv := range lldp.OrganizationSpecificTLVs {
switch tlv.SubType {
case 5: // System Name
neighbor.SystemName = string(tlv.Info)
case 6: // System Description
neighbor.SystemDesc = string(tlv.Info)
case 7: // System Capabilities
neighbor.Capabilities = parseCapabilities(tlv.Info)
}
}
neighbors = append(neighbors, neighbor)
}
}
return neighbors, nil
}
func parseCapabilities(data []byte) []string {
if len(data) < 4 {
return nil
}
capabilities := []string{}
enabled := data[2]<<8 | data[3]
capMap := map[uint16]string{
0x0001: "Other",
0x0002: "Repeater",
0x0004: "Bridge",
0x0008: "WLAN AP",
0x0010: "Router",
0x0020: "Telephone",
0x0040: "DOCSIS",
0x0080: "Station",
}
for mask, name := range capMap {
if enabled&mask != 0 {
capabilities = append(capabilities, name)
}
}
return capabilities
}
func main() {
// 使用示例
neighbors, err := GetLLDPNeighbors("en0", 10*time.Second)
if err != nil {
log.Fatal(err)
}
for i, neighbor := range neighbors {
fmt.Printf("Neighbor %d:\n", i+1)
fmt.Printf(" ChassisID: %s\n", neighbor.ChassisID)
fmt.Printf(" PortID: %s\n", neighbor.PortID)
fmt.Printf(" SystemName: %s\n", neighbor.SystemName)
fmt.Printf(" SystemDesc: %s\n", neighbor.SystemDesc)
fmt.Printf(" Capabilities: %v\n", neighbor.Capabilities)
fmt.Println()
}
}
需要安装依赖:
go get github.com/google/gopacket
go get github.com/google/gopacket/layers
go get github.com/google/gopacket/pcap
这个实现直接使用gopacket库捕获和解析LLDP包,避免了复杂的插件系统。GetLLDPNeighbors函数是阻塞的,会在指定超时时间内等待LLDP包。

