Add -vpp-ifindex-offset flag
This commit is contained in:
163
ifmib/ifmib.go
Normal file
163
ifmib/ifmib.go
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
package ifmib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/posteo/go-agentx"
|
||||||
|
"github.com/posteo/go-agentx/pdu"
|
||||||
|
"github.com/posteo/go-agentx/value"
|
||||||
|
"go.fd.io/govpp/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IF-MIB OID base: 1.3.6.1.2.1.31.1.1.1
|
||||||
|
// ifXTable entries:
|
||||||
|
// ifName .1 - DisplayString
|
||||||
|
// ifInMulticastPkts .2 - Counter32
|
||||||
|
// ifInBroadcastPkts .3 - Counter32
|
||||||
|
// ifOutMulticastPkts .4 - Counter32
|
||||||
|
// ifOutBroadcastPkts .5 - Counter32
|
||||||
|
// ifHCInOctets .6 - Counter64
|
||||||
|
// ifHCInUcastPkts .7 - Counter64
|
||||||
|
// ifHCInMulticastPkts .8 - Counter64
|
||||||
|
// ifHCInBroadcastPkts .9 - Counter64
|
||||||
|
// ifHCOutOctets .10 - Counter64
|
||||||
|
// ifHCOutUcastPkts .11 - Counter64
|
||||||
|
// ifHCOutMulticastPkts .12 - Counter64
|
||||||
|
// ifHCOutBroadcastPkts .13 - Counter64
|
||||||
|
|
||||||
|
const ifXTableOID = "1.3.6.1.2.1.31.1.1.1"
|
||||||
|
|
||||||
|
type InterfaceMIB struct {
|
||||||
|
mutex sync.RWMutex
|
||||||
|
handler *agentx.ListHandler
|
||||||
|
session *agentx.Session
|
||||||
|
stats map[uint32]*api.InterfaceCounters // indexed by interface index
|
||||||
|
indexOffset int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInterfaceMIB(indexOffset int) *InterfaceMIB {
|
||||||
|
return &InterfaceMIB{
|
||||||
|
handler: &agentx.ListHandler{},
|
||||||
|
stats: make(map[uint32]*api.InterfaceCounters),
|
||||||
|
indexOffset: indexOffset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *InterfaceMIB) GetHandler() *agentx.ListHandler {
|
||||||
|
return m.handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *InterfaceMIB) UpdateStats(interfaceStats *api.InterfaceStats) {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
|
log.Printf("Updating IF-MIB with %d interfaces", len(interfaceStats.Interfaces))
|
||||||
|
|
||||||
|
// Clear existing entries
|
||||||
|
m.handler = &agentx.ListHandler{}
|
||||||
|
m.stats = make(map[uint32]*api.InterfaceCounters)
|
||||||
|
|
||||||
|
// Add new entries
|
||||||
|
for _, iface := range interfaceStats.Interfaces {
|
||||||
|
log.Printf("Processing interface %d (%s)", iface.InterfaceIndex, iface.InterfaceName)
|
||||||
|
m.stats[iface.InterfaceIndex] = &iface
|
||||||
|
m.addInterfaceToMIB(&iface)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the session with the new handler
|
||||||
|
if m.session != nil {
|
||||||
|
m.session.Handler = m.handler
|
||||||
|
log.Printf("Updated session handler with new IF-MIB data")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("IF-MIB now contains %d interfaces", len(m.stats))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *InterfaceMIB) addInterfaceToMIB(iface *api.InterfaceCounters) {
|
||||||
|
idx := int(iface.InterfaceIndex) + m.indexOffset
|
||||||
|
|
||||||
|
// ifName (.1)
|
||||||
|
item := m.handler.Add(fmt.Sprintf("%s.1.%d", ifXTableOID, idx))
|
||||||
|
item.Type = pdu.VariableTypeOctetString
|
||||||
|
item.Value = iface.InterfaceName
|
||||||
|
|
||||||
|
// ifInMulticastPkts (.2)
|
||||||
|
item = m.handler.Add(fmt.Sprintf("%s.2.%d", ifXTableOID, idx))
|
||||||
|
item.Type = pdu.VariableTypeCounter32
|
||||||
|
item.Value = uint32(iface.RxMulticast.Packets)
|
||||||
|
|
||||||
|
// ifInBroadcastPkts (.3)
|
||||||
|
item = m.handler.Add(fmt.Sprintf("%s.3.%d", ifXTableOID, idx))
|
||||||
|
item.Type = pdu.VariableTypeCounter32
|
||||||
|
item.Value = uint32(iface.RxBroadcast.Packets)
|
||||||
|
|
||||||
|
// ifOutMulticastPkts (.4)
|
||||||
|
item = m.handler.Add(fmt.Sprintf("%s.4.%d", ifXTableOID, idx))
|
||||||
|
item.Type = pdu.VariableTypeCounter32
|
||||||
|
item.Value = uint32(iface.TxMulticast.Packets)
|
||||||
|
|
||||||
|
// ifOutBroadcastPkts (.5)
|
||||||
|
item = m.handler.Add(fmt.Sprintf("%s.5.%d", ifXTableOID, idx))
|
||||||
|
item.Type = pdu.VariableTypeCounter32
|
||||||
|
item.Value = uint32(iface.TxBroadcast.Packets)
|
||||||
|
|
||||||
|
// ifHCInOctets (.6)
|
||||||
|
item = m.handler.Add(fmt.Sprintf("%s.6.%d", ifXTableOID, idx))
|
||||||
|
item.Type = pdu.VariableTypeCounter64
|
||||||
|
item.Value = iface.Rx.Bytes
|
||||||
|
|
||||||
|
// ifHCInUcastPkts (.7)
|
||||||
|
item = m.handler.Add(fmt.Sprintf("%s.7.%d", ifXTableOID, idx))
|
||||||
|
item.Type = pdu.VariableTypeCounter64
|
||||||
|
item.Value = iface.RxUnicast.Packets
|
||||||
|
|
||||||
|
// ifHCInMulticastPkts (.8)
|
||||||
|
item = m.handler.Add(fmt.Sprintf("%s.8.%d", ifXTableOID, idx))
|
||||||
|
item.Type = pdu.VariableTypeCounter64
|
||||||
|
item.Value = iface.RxMulticast.Packets
|
||||||
|
|
||||||
|
// ifHCInBroadcastPkts (.9)
|
||||||
|
item = m.handler.Add(fmt.Sprintf("%s.9.%d", ifXTableOID, idx))
|
||||||
|
item.Type = pdu.VariableTypeCounter64
|
||||||
|
item.Value = iface.RxBroadcast.Packets
|
||||||
|
|
||||||
|
// ifHCOutOctets (.10)
|
||||||
|
item = m.handler.Add(fmt.Sprintf("%s.10.%d", ifXTableOID, idx))
|
||||||
|
item.Type = pdu.VariableTypeCounter64
|
||||||
|
item.Value = iface.Tx.Bytes
|
||||||
|
|
||||||
|
// ifHCOutUcastPkts (.11)
|
||||||
|
item = m.handler.Add(fmt.Sprintf("%s.11.%d", ifXTableOID, idx))
|
||||||
|
item.Type = pdu.VariableTypeCounter64
|
||||||
|
item.Value = iface.TxUnicast.Packets
|
||||||
|
|
||||||
|
// ifHCOutMulticastPkts (.12)
|
||||||
|
item = m.handler.Add(fmt.Sprintf("%s.12.%d", ifXTableOID, idx))
|
||||||
|
item.Type = pdu.VariableTypeCounter64
|
||||||
|
item.Value = iface.TxMulticast.Packets
|
||||||
|
|
||||||
|
// ifHCOutBroadcastPkts (.13)
|
||||||
|
item = m.handler.Add(fmt.Sprintf("%s.13.%d", ifXTableOID, idx))
|
||||||
|
item.Type = pdu.VariableTypeCounter64
|
||||||
|
item.Value = iface.TxBroadcast.Packets
|
||||||
|
|
||||||
|
log.Printf("Added interface %d (%s) to IF-MIB with SNMP index %d", iface.InterfaceIndex, iface.InterfaceName, idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *InterfaceMIB) RegisterWithSession(session *agentx.Session) error {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
|
m.session = session
|
||||||
|
session.Handler = m.handler
|
||||||
|
// Register at the ifXTable level
|
||||||
|
err := session.Register(127, value.MustParseOID(ifXTableOID))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to register IF-MIB: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Registered IF-MIB at OID %s", ifXTableOID)
|
||||||
|
return nil
|
||||||
|
}
|
19
main.go
19
main.go
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/posteo/go-agentx"
|
"github.com/posteo/go-agentx"
|
||||||
|
|
||||||
|
"govpp-snmp-example/ifmib"
|
||||||
"govpp-snmp-example/vppstats"
|
"govpp-snmp-example/vppstats"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ func main() {
|
|||||||
addr := flag.String("agentx-addr", "localhost:705", "Address to connect to (hostname:port or Unix socket path)")
|
addr := flag.String("agentx-addr", "localhost:705", "Address to connect to (hostname:port or Unix socket path)")
|
||||||
vppStatsAddr := flag.String("vpp-stats-addr", "/var/run/vpp/stats.sock", "VPP stats socket path")
|
vppStatsAddr := flag.String("vpp-stats-addr", "/var/run/vpp/stats.sock", "VPP stats socket path")
|
||||||
period := flag.Float64("period", 10.0, "Interval in seconds for querying VPP interface stats")
|
period := flag.Float64("period", 10.0, "Interval in seconds for querying VPP interface stats")
|
||||||
|
ifIndexOffset := flag.Int("vpp-ifindex-offset", 1000, "Offset to add to VPP interface indices for SNMP")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
var network, address string
|
var network, address string
|
||||||
@ -33,8 +35,21 @@ func main() {
|
|||||||
client.Timeout = 1 * time.Minute
|
client.Timeout = 1 * time.Minute
|
||||||
client.ReconnectInterval = 1 * time.Second
|
client.ReconnectInterval = 1 * time.Second
|
||||||
|
|
||||||
// Start VPP stats routine
|
session, err := client.Session()
|
||||||
vppstats.StartStatsRoutine(*vppStatsAddr, time.Duration(*period*1000)*time.Millisecond)
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to create session: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the interface MIB
|
||||||
|
interfaceMIB := ifmib.NewInterfaceMIB(*ifIndexOffset)
|
||||||
|
|
||||||
|
// Register the interface MIB with the AgentX session
|
||||||
|
if err := interfaceMIB.RegisterWithSession(session); err != nil {
|
||||||
|
log.Fatalf("Failed to register interface MIB: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start VPP stats routine with callback to update MIB
|
||||||
|
vppstats.StartStatsRoutine(*vppStatsAddr, time.Duration(*period*1000)*time.Millisecond, interfaceMIB.UpdateStats)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
@ -9,12 +9,14 @@ import (
|
|||||||
"go.fd.io/govpp/core"
|
"go.fd.io/govpp/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type StatsCallback func(*api.InterfaceStats)
|
||||||
|
|
||||||
// StartStatsRoutine starts a goroutine that queries VPP interface stats at the specified interval
|
// StartStatsRoutine starts a goroutine that queries VPP interface stats at the specified interval
|
||||||
func StartStatsRoutine(statsSocketPath string, period time.Duration) {
|
func StartStatsRoutine(statsSocketPath string, period time.Duration, callback StatsCallback) {
|
||||||
go statsRoutine(statsSocketPath, period)
|
go statsRoutine(statsSocketPath, period, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
func statsRoutine(statsSocketPath string, period time.Duration) {
|
func statsRoutine(statsSocketPath string, period time.Duration, callback StatsCallback) {
|
||||||
log.Printf("Starting VPP stats routine with socket: %s, period: %v", statsSocketPath, period)
|
log.Printf("Starting VPP stats routine with socket: %s, period: %v", statsSocketPath, period)
|
||||||
|
|
||||||
// Create stats client
|
// Create stats client
|
||||||
@ -29,7 +31,7 @@ func statsRoutine(statsSocketPath string, period time.Duration) {
|
|||||||
defer c.Disconnect()
|
defer c.Disconnect()
|
||||||
|
|
||||||
// Query stats immediately on startup
|
// Query stats immediately on startup
|
||||||
queryInterfaceStats(c)
|
queryInterfaceStats(c, callback)
|
||||||
|
|
||||||
ticker := time.NewTicker(period)
|
ticker := time.NewTicker(period)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
@ -37,12 +39,12 @@ func statsRoutine(statsSocketPath string, period time.Duration) {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
queryInterfaceStats(c)
|
queryInterfaceStats(c, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryInterfaceStats(c *core.StatsConnection) {
|
func queryInterfaceStats(c *core.StatsConnection, callback StatsCallback) {
|
||||||
log.Printf("Querying VPP interface stats at %s", time.Now().Format(time.RFC3339))
|
log.Printf("Querying VPP interface stats at %s", time.Now().Format(time.RFC3339))
|
||||||
|
|
||||||
// Create the proper struct for interface stats
|
// Create the proper struct for interface stats
|
||||||
@ -54,14 +56,17 @@ func queryInterfaceStats(c *core.StatsConnection) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now you have properly structured data
|
// Log basic info
|
||||||
|
log.Printf("Retrieved stats for %d interfaces", len(stats.Interfaces))
|
||||||
for _, iface := range stats.Interfaces {
|
for _, iface := range stats.Interfaces {
|
||||||
log.Printf("Interface %d (%s):", iface.InterfaceIndex, iface.InterfaceName)
|
log.Printf("Interface %d (%s): RX %d pkts/%d bytes, TX %d pkts/%d bytes",
|
||||||
log.Printf(" RX: %d packets, %d bytes", iface.Rx.Packets, iface.Rx.Bytes)
|
iface.InterfaceIndex, iface.InterfaceName,
|
||||||
log.Printf(" TX: %d packets, %d bytes", iface.Tx.Packets, iface.Tx.Bytes)
|
iface.Rx.Packets, iface.Rx.Bytes,
|
||||||
log.Printf(" RX Errors: %d, TX Errors: %d", iface.RxErrors, iface.TxErrors)
|
iface.Tx.Packets, iface.Tx.Bytes)
|
||||||
log.Printf(" Drops: %d, Punts: %d", iface.Drops, iface.Punts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Retrieved stats for %d interfaces", len(stats.Interfaces))
|
// Call the callback to update the MIB
|
||||||
|
if callback != nil {
|
||||||
|
callback(stats)
|
||||||
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user