Move Go code to src/
This commit is contained in:
413
src/ifmib/ifmib.go
Normal file
413
src/ifmib/ifmib.go
Normal file
@ -0,0 +1,413 @@
|
||||
// Copyright 2025, IPng Networks GmbH, Pim van Pelt <pim@ipng.ch>
|
||||
|
||||
package ifmib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/posteo/go-agentx"
|
||||
"github.com/posteo/go-agentx/pdu"
|
||||
"github.com/posteo/go-agentx/value"
|
||||
"go.fd.io/govpp/api"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"govpp-snmp-agentx/logger"
|
||||
"govpp-snmp-agentx/vppstats"
|
||||
)
|
||||
|
||||
// IF-MIB OID bases:
|
||||
// ifEntry (classic): 1.3.6.1.2.1.2.2.1
|
||||
// ifXTable (extended): 1.3.6.1.2.1.31.1.1.1
|
||||
|
||||
// ifEntry (1.3.6.1.2.1.2.2.1) - Classic Interface Table:
|
||||
// ifIndex .1 - Integer32
|
||||
// ifDescr .2 - DisplayString
|
||||
// ifType .3 - IANAifType
|
||||
// ifMtu .4 - Integer32
|
||||
// ifSpeed .5 - Gauge32
|
||||
// ifPhysAddress .6 - PhysAddress
|
||||
// ifAdminStatus .7 - INTEGER
|
||||
// ifOperStatus .8 - INTEGER
|
||||
// ifLastChange .9 - TimeTicks
|
||||
// ifInOctets .10 - Counter32
|
||||
// ifInUcastPkts .11 - Counter32
|
||||
// ifInNUcastPkts .12 - Counter32
|
||||
// ifInDiscards .13 - Counter32
|
||||
// ifInErrors .14 - Counter32
|
||||
// ifInUnknownProtos .15 - Counter32
|
||||
// ifOutOctets .16 - Counter32
|
||||
// ifOutUcastPkts .17 - Counter32
|
||||
// ifOutNUcastPkts .18 - Counter32
|
||||
// ifOutDiscards .19 - Counter32
|
||||
// ifOutErrors .20 - Counter32
|
||||
// ifOutQLen .21 - Gauge32
|
||||
// ifSpecific .22 - OBJECT IDENTIFIER
|
||||
|
||||
// ifXTable (1.3.6.1.2.1.31.1.1.1) - Extended Interface Table:
|
||||
// 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
|
||||
// ifAlias .18 - DisplayString
|
||||
|
||||
const ifEntryOID = "1.3.6.1.2.1.2.2.1"
|
||||
const ifXTableOID = "1.3.6.1.2.1.31.1.1.1"
|
||||
|
||||
// VPP Config YAML structures
|
||||
type VPPConfig struct {
|
||||
Interfaces map[string]VPPInterface `yaml:"interfaces"`
|
||||
Loopbacks map[string]VPPInterface `yaml:"loopbacks"`
|
||||
}
|
||||
|
||||
type VPPInterface struct {
|
||||
Description string `yaml:"description"`
|
||||
SubInterfaces map[string]VPPInterface `yaml:"sub-interfaces"`
|
||||
}
|
||||
|
||||
type InterfaceMIB struct {
|
||||
mutex sync.RWMutex
|
||||
handler *agentx.ListHandler
|
||||
ifEntrySession *agentx.Session
|
||||
ifXTableSession *agentx.Session
|
||||
stats map[uint32]*api.InterfaceCounters // indexed by interface index
|
||||
descriptions map[string]string // interface name -> description mapping
|
||||
}
|
||||
|
||||
func NewInterfaceMIB() *InterfaceMIB {
|
||||
return &InterfaceMIB{
|
||||
handler: &agentx.ListHandler{},
|
||||
stats: make(map[uint32]*api.InterfaceCounters),
|
||||
descriptions: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *InterfaceMIB) GetHandler() *agentx.ListHandler {
|
||||
return m.handler
|
||||
}
|
||||
|
||||
func (m *InterfaceMIB) LoadVPPConfig(configPath string) error {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
// Read YAML file
|
||||
data, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read VPP config file: %v", err)
|
||||
}
|
||||
|
||||
// Parse YAML
|
||||
var config VPPConfig
|
||||
if err := yaml.Unmarshal(data, &config); err != nil {
|
||||
return fmt.Errorf("failed to parse VPP config YAML: %v", err)
|
||||
}
|
||||
|
||||
// Extract interface descriptions
|
||||
for ifName, ifConfig := range config.Interfaces {
|
||||
if ifConfig.Description != "" {
|
||||
m.descriptions[ifName] = ifConfig.Description
|
||||
logger.Debugf("Loaded description for interface %s: %s", ifName, ifConfig.Description)
|
||||
}
|
||||
|
||||
// Process sub-interfaces
|
||||
for subID, subConfig := range ifConfig.SubInterfaces {
|
||||
if subConfig.Description != "" {
|
||||
subIfName := fmt.Sprintf("%s.%s", ifName, subID)
|
||||
m.descriptions[subIfName] = subConfig.Description
|
||||
logger.Debugf("Loaded description for sub-interface %s: %s", subIfName, subConfig.Description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract loopback descriptions
|
||||
for ifName, ifConfig := range config.Loopbacks {
|
||||
if ifConfig.Description != "" {
|
||||
m.descriptions[ifName] = ifConfig.Description
|
||||
logger.Debugf("Loaded description for loopback %s: %s", ifName, ifConfig.Description)
|
||||
}
|
||||
}
|
||||
|
||||
logger.Printf("Loaded %d interface descriptions from VPP config", len(m.descriptions))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *InterfaceMIB) UpdateStats(interfaceStats *api.InterfaceStats) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
logger.Debugf("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 {
|
||||
logger.Debugf("Processing interface %d (%s)", iface.InterfaceIndex, iface.InterfaceName)
|
||||
m.stats[iface.InterfaceIndex] = &iface
|
||||
m.addInterfaceToMIB(&iface)
|
||||
}
|
||||
|
||||
// Update both sessions with the new handler
|
||||
if m.ifEntrySession != nil {
|
||||
m.ifEntrySession.Handler = m.handler
|
||||
}
|
||||
if m.ifXTableSession != nil {
|
||||
m.ifXTableSession.Handler = m.handler
|
||||
logger.Printf("Updated session handlers with new IF-MIB data")
|
||||
}
|
||||
|
||||
logger.Debugf("IF-MIB now contains %d interfaces", len(m.stats))
|
||||
}
|
||||
|
||||
func (m *InterfaceMIB) addInterfaceToMIB(iface *api.InterfaceCounters) {
|
||||
idx := int(iface.InterfaceIndex) + *vppstats.IfIndexOffset
|
||||
|
||||
// Add ifEntry (classic interface table) entries
|
||||
m.addIfEntry(iface, idx)
|
||||
|
||||
// Add ifXTable (extended interface table) entries
|
||||
m.addIfXTable(iface, idx)
|
||||
|
||||
logger.Debugf("Added interface %d (%s) to IF-MIB with SNMP index %d", iface.InterfaceIndex, iface.InterfaceName, idx)
|
||||
}
|
||||
|
||||
func (m *InterfaceMIB) addIfEntry(iface *api.InterfaceCounters, idx int) {
|
||||
var item *agentx.ListItem
|
||||
|
||||
// ifIndex (.1)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.1.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeInteger
|
||||
item.Value = int32(idx)
|
||||
|
||||
// ifDescr (.2)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.2.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeOctetString
|
||||
item.Value = iface.InterfaceName
|
||||
|
||||
// ifType (.3) - Using ethernetCsmacd(6) as default
|
||||
item = m.handler.Add(fmt.Sprintf("%s.3.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeInteger
|
||||
item.Value = int32(6)
|
||||
|
||||
// ifMtu (.4) - Default MTU 1500
|
||||
item = m.handler.Add(fmt.Sprintf("%s.4.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeInteger
|
||||
item.Value = int32(1500)
|
||||
|
||||
// ifSpeed (.5) - Default to 1Gbps (1000000000 bits/sec)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.5.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeGauge32
|
||||
item.Value = uint32(1000000000)
|
||||
|
||||
// ifPhysAddress (.6) - Empty for now
|
||||
item = m.handler.Add(fmt.Sprintf("%s.6.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeOctetString
|
||||
item.Value = ""
|
||||
|
||||
// ifAdminStatus (.7) - up(1)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.7.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeInteger
|
||||
item.Value = int32(1)
|
||||
|
||||
// ifOperStatus (.8) - up(1)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.8.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeInteger
|
||||
item.Value = int32(1)
|
||||
|
||||
// ifLastChange (.9) - 0 (unknown)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.9.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeTimeTicks
|
||||
item.Value = 0 * time.Second
|
||||
|
||||
// ifInOctets (.10)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.10.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeCounter32
|
||||
item.Value = uint32(iface.Rx.Bytes)
|
||||
|
||||
// ifInUcastPkts (.11)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.11.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeCounter32
|
||||
item.Value = uint32(iface.RxUnicast.Packets)
|
||||
|
||||
// ifInNUcastPkts (.12) - multicast + broadcast
|
||||
item = m.handler.Add(fmt.Sprintf("%s.12.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeCounter32
|
||||
item.Value = uint32(iface.RxMulticast.Packets + iface.RxBroadcast.Packets)
|
||||
|
||||
// ifInDiscards (.13) - using drops
|
||||
item = m.handler.Add(fmt.Sprintf("%s.13.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeCounter32
|
||||
item.Value = uint32(iface.Drops)
|
||||
|
||||
// ifInErrors (.14)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.14.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeCounter32
|
||||
item.Value = uint32(iface.RxErrors)
|
||||
|
||||
// ifInUnknownProtos (.15) - 0 (not available)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.15.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeCounter32
|
||||
item.Value = uint32(0)
|
||||
|
||||
// ifOutOctets (.16)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.16.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeCounter32
|
||||
item.Value = uint32(iface.Tx.Bytes)
|
||||
|
||||
// ifOutUcastPkts (.17)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.17.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeCounter32
|
||||
item.Value = uint32(iface.TxUnicast.Packets)
|
||||
|
||||
// ifOutNUcastPkts (.18) - multicast + broadcast
|
||||
item = m.handler.Add(fmt.Sprintf("%s.18.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeCounter32
|
||||
item.Value = uint32(iface.TxMulticast.Packets + iface.TxBroadcast.Packets)
|
||||
|
||||
// ifOutDiscards (.19) - 0 (not available)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.19.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeCounter32
|
||||
item.Value = uint32(0)
|
||||
|
||||
// ifOutErrors (.20)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.20.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeCounter32
|
||||
item.Value = uint32(iface.TxErrors)
|
||||
|
||||
// ifOutQLen (.21) - 0 (not available)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.21.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeGauge32
|
||||
item.Value = uint32(0)
|
||||
|
||||
// ifSpecific (.22) - Skip this field as it's optional and causing issues
|
||||
}
|
||||
|
||||
func (m *InterfaceMIB) addIfXTable(iface *api.InterfaceCounters, idx int) {
|
||||
var item *agentx.ListItem
|
||||
|
||||
// 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
|
||||
|
||||
// ifAlias (.18) - Interface description/alias
|
||||
item = m.handler.Add(fmt.Sprintf("%s.18.%d", ifXTableOID, idx))
|
||||
item.Type = pdu.VariableTypeOctetString
|
||||
// Use description from VPP config if available, otherwise use interface name
|
||||
if desc, exists := m.descriptions[iface.InterfaceName]; exists {
|
||||
item.Value = desc
|
||||
} else {
|
||||
item.Value = iface.InterfaceName
|
||||
}
|
||||
}
|
||||
|
||||
func (m *InterfaceMIB) RegisterWithClient(client *agentx.Client) error {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
// Create separate sessions for each MIB
|
||||
ifEntrySession, err := client.Session()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create ifEntry session: %v", err)
|
||||
}
|
||||
|
||||
ifXTableSession, err := client.Session()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create ifXTable session: %v", err)
|
||||
}
|
||||
|
||||
m.ifEntrySession = ifEntrySession
|
||||
m.ifXTableSession = ifXTableSession
|
||||
|
||||
// Set handlers for both sessions
|
||||
ifEntrySession.Handler = m.handler
|
||||
ifXTableSession.Handler = m.handler
|
||||
|
||||
// Register the classic ifEntry
|
||||
err = ifEntrySession.Register(127, value.MustParseOID(ifEntryOID))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to register ifEntry: %v", err)
|
||||
}
|
||||
|
||||
// Register the extended ifXTable
|
||||
err = ifXTableSession.Register(127, value.MustParseOID(ifXTableOID))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to register ifXTable: %v", err)
|
||||
}
|
||||
|
||||
logger.Debugf("Registered IF-MIB ifEntry at OID %s", ifEntryOID)
|
||||
logger.Debugf("Registered IF-MIB ifXTable at OID %s", ifXTableOID)
|
||||
return nil
|
||||
}
|
180
src/ifmib/ifmib_test.go
Normal file
180
src/ifmib/ifmib_test.go
Normal file
@ -0,0 +1,180 @@
|
||||
// Copyright 2025, IPng Networks GmbH, Pim van Pelt <pim@ipng.ch>
|
||||
|
||||
package ifmib
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"go.fd.io/govpp/api"
|
||||
)
|
||||
|
||||
func TestNewInterfaceMIB(t *testing.T) {
|
||||
mib := NewInterfaceMIB()
|
||||
|
||||
if mib == nil {
|
||||
t.Fatal("NewInterfaceMIB returned nil")
|
||||
}
|
||||
|
||||
if mib.handler == nil {
|
||||
t.Error("Expected handler to be initialized")
|
||||
}
|
||||
|
||||
if mib.stats == nil {
|
||||
t.Error("Expected stats map to be initialized")
|
||||
}
|
||||
|
||||
if mib.descriptions == nil {
|
||||
t.Error("Expected descriptions map to be initialized")
|
||||
}
|
||||
|
||||
if len(mib.stats) != 0 {
|
||||
t.Errorf("Expected stats map to be empty, got %d entries", len(mib.stats))
|
||||
}
|
||||
|
||||
if len(mib.descriptions) != 0 {
|
||||
t.Errorf("Expected descriptions map to be empty, got %d entries", len(mib.descriptions))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHandler(t *testing.T) {
|
||||
mib := NewInterfaceMIB()
|
||||
handler := mib.GetHandler()
|
||||
|
||||
if handler == nil {
|
||||
t.Error("GetHandler returned nil")
|
||||
}
|
||||
|
||||
if handler != mib.handler {
|
||||
t.Error("GetHandler returned different handler than expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadVPPConfigValidYAML(t *testing.T) {
|
||||
mib := NewInterfaceMIB()
|
||||
|
||||
// Create a temporary YAML file
|
||||
yamlContent := `interfaces:
|
||||
GigabitEthernet0/0/0:
|
||||
description: 'Test: Interface'
|
||||
sub-interfaces:
|
||||
100:
|
||||
description: 'Test: Sub-interface'
|
||||
loopbacks:
|
||||
loop0:
|
||||
description: 'Test: Loopback'
|
||||
`
|
||||
|
||||
tmpfile, err := os.CreateTemp("", "test_*.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(tmpfile.Name())
|
||||
|
||||
if _, err := tmpfile.Write([]byte(yamlContent)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := tmpfile.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test loading the config
|
||||
err = mib.LoadVPPConfig(tmpfile.Name())
|
||||
if err != nil {
|
||||
t.Fatalf("LoadVPPConfig failed: %v", err)
|
||||
}
|
||||
|
||||
// Check that descriptions were loaded
|
||||
if len(mib.descriptions) != 3 {
|
||||
t.Errorf("Expected 3 descriptions, got %d", len(mib.descriptions))
|
||||
}
|
||||
|
||||
if mib.descriptions["GigabitEthernet0/0/0"] != "Test: Interface" {
|
||||
t.Errorf("Unexpected interface description: %s", mib.descriptions["GigabitEthernet0/0/0"])
|
||||
}
|
||||
|
||||
if mib.descriptions["GigabitEthernet0/0/0.100"] != "Test: Sub-interface" {
|
||||
t.Errorf("Unexpected sub-interface description: %s", mib.descriptions["GigabitEthernet0/0/0.100"])
|
||||
}
|
||||
|
||||
if mib.descriptions["loop0"] != "Test: Loopback" {
|
||||
t.Errorf("Unexpected loopback description: %s", mib.descriptions["loop0"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadVPPConfigNonExistentFile(t *testing.T) {
|
||||
mib := NewInterfaceMIB()
|
||||
|
||||
err := mib.LoadVPPConfig("/nonexistent/file.yaml")
|
||||
if err == nil {
|
||||
t.Error("Expected error for non-existent file")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadVPPConfigInvalidYAML(t *testing.T) {
|
||||
mib := NewInterfaceMIB()
|
||||
|
||||
// Create a temporary file with invalid YAML
|
||||
invalidYAML := `interfaces:
|
||||
test: [
|
||||
`
|
||||
|
||||
tmpfile, err := os.CreateTemp("", "invalid_*.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(tmpfile.Name())
|
||||
|
||||
if _, err := tmpfile.Write([]byte(invalidYAML)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := tmpfile.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = mib.LoadVPPConfig(tmpfile.Name())
|
||||
if err == nil {
|
||||
t.Error("Expected error for invalid YAML")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateStatsBasic(t *testing.T) {
|
||||
mib := NewInterfaceMIB()
|
||||
|
||||
// Create mock interface stats
|
||||
stats := &api.InterfaceStats{
|
||||
Interfaces: []api.InterfaceCounters{
|
||||
{
|
||||
InterfaceIndex: 0,
|
||||
InterfaceName: "test0",
|
||||
Rx: api.InterfaceCounterCombined{
|
||||
Packets: 100,
|
||||
Bytes: 1000,
|
||||
},
|
||||
Tx: api.InterfaceCounterCombined{
|
||||
Packets: 200,
|
||||
Bytes: 2000,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Call UpdateStats (this will test the basic flow without AgentX sessions)
|
||||
mib.UpdateStats(stats)
|
||||
|
||||
// Check that stats were stored
|
||||
if len(mib.stats) != 1 {
|
||||
t.Errorf("Expected 1 interface in stats, got %d", len(mib.stats))
|
||||
}
|
||||
|
||||
if storedStats, exists := mib.stats[0]; !exists {
|
||||
t.Error("Expected interface 0 to be stored in stats")
|
||||
} else {
|
||||
if storedStats.InterfaceName != "test0" {
|
||||
t.Errorf("Expected interface name 'test0', got '%s'", storedStats.InterfaceName)
|
||||
}
|
||||
if storedStats.Rx.Packets != 100 {
|
||||
t.Errorf("Expected RX packets 100, got %d", storedStats.Rx.Packets)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user