Compare commits
9 Commits
27c7a5bcae
...
v1.2.3-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06a1f4401d | ||
|
|
b450e02b8d | ||
|
|
5e36d5c926 | ||
|
|
16bebb0ece | ||
|
|
cdc8765a9e | ||
|
|
9596e16887 | ||
|
|
4935f5a8ef | ||
|
|
b6d2e3b629 | ||
|
|
a0d5c61643 |
53
debian/changelog
vendored
53
debian/changelog
vendored
@@ -1,9 +1,60 @@
|
||||
govpp-snmp-agentx (1.1.6-1) bookworm; urgency=medium
|
||||
govpp-snmp-agentx (1.2.3-1) bookworm; urgency=medium
|
||||
|
||||
* Fix VPP stats filtering to exclude deleted interfaces
|
||||
* Add interface manager integration to stats manager
|
||||
* Filter out stale interface statistics from deleted interfaces
|
||||
* Improve stats reliability by cross-referencing with current interface list
|
||||
|
||||
-- Pim van Pelt <pim@ipng.ch> Sat, 23 Nov 2024 00:00:00 +0000
|
||||
|
||||
govpp-snmp-agentx (1.2.2-1) bookworm; urgency=medium
|
||||
|
||||
* Simplify ifmib integration by removing reflection usage
|
||||
* Move to direct counter updates for improved performance
|
||||
* Refactor interface tracking with simplified state management
|
||||
* Remove dependency on reflection for handler manipulation
|
||||
* Fix test suite to match refactored ifmib implementation
|
||||
|
||||
-- Pim van Pelt <pim@ipng.ch> Sat, 23 Nov 2024 00:00:00 +0000
|
||||
|
||||
govpp-snmp-agentx (1.2.1-1) bookworm; urgency=medium
|
||||
|
||||
* Fix OID visibility bug after go-agentx 0.3.0 upgrade
|
||||
* Use reflection to clear handler contents instead of creating new handlers
|
||||
* Simplify AgentX session creation and registration logic
|
||||
* Add proper session cleanup method (Close())
|
||||
* Improve error handling in AgentX interactions
|
||||
* Code cleanup and maintainability improvements
|
||||
|
||||
-- Pim van Pelt <pim@ipng.ch> Fri, 22 Nov 2024 00:00:00 +0000
|
||||
|
||||
govpp-snmp-agentx (1.2.0-1) bookworm; urgency=medium
|
||||
|
||||
* Update go-agentx dependency from 0.2.1 to 0.3.0 to fix compilation issues
|
||||
* Adapt to breaking changes in go-agentx Session API (now requires nameOID, name, handler)
|
||||
* Update Client configuration to use dial options (WithTimeout, WithReconnectInterval)
|
||||
* Remove access to unexported Session.Handler field (API change)
|
||||
* NOTE: This version fixes compilation broken in 1.1.6-1 and 1.1.7-1
|
||||
|
||||
-- Pim van Pelt <pim@ipng.ch> Wed, 20 Nov 2024 00:00:00 +0000
|
||||
|
||||
govpp-snmp-agentx (1.1.7-1) bookworm; urgency=critical
|
||||
|
||||
* Refactor VPPClient constructor to use idiomatic Go patterns
|
||||
* Remove redundant NewVPPClient() constructor function
|
||||
* Update all code to use direct struct initialization (&VPPClient{})
|
||||
* Improve code maintainability and follow Go best practices
|
||||
* WARNING: This version is BROKEN due to go-agentx 0.2.1 incompatibility
|
||||
|
||||
-- Pim van Pelt <pim@ipng.ch> Fri, 15 Nov 2024 00:00:00 +0000
|
||||
|
||||
govpp-snmp-agentx (1.1.6-1) bookworm; urgency=critical
|
||||
|
||||
* Replace forked go-agentx dependency with upstream github.com/posteo/go-agentx
|
||||
* Remove local src/go-agentx/ directory and use official upstream package
|
||||
* Upgrade to go-agentx v0.2.1 from official GitHub repository
|
||||
* Improve dependency management and reduce maintenance overhead
|
||||
* WARNING: This version is BROKEN due to go-agentx 0.2.1 incompatibility
|
||||
|
||||
-- Pim van Pelt <pim@ipng.ch> Fri, 08 Nov 2024 00:00:00 +0000
|
||||
|
||||
|
||||
@@ -20,29 +20,27 @@ var (
|
||||
|
||||
// StartAgentXRoutine initializes the AgentX client and registers the interface MIB
|
||||
func StartAgentXRoutine(interfaceMIB *ifmib.InterfaceMIB) error {
|
||||
var network, address string
|
||||
// Determine network type based on address format
|
||||
network := "tcp"
|
||||
if strings.HasPrefix(*AgentXAddr, "/") {
|
||||
network = "unix"
|
||||
address = *AgentXAddr
|
||||
} else {
|
||||
network = "tcp"
|
||||
address = *AgentXAddr
|
||||
}
|
||||
|
||||
logger.Debugf("Connecting to AgentX at %s://%s", network, address)
|
||||
logger.Debugf("Connecting to AgentX at %s://%s", network, *AgentXAddr)
|
||||
|
||||
client, err := agentx.Dial(network, address)
|
||||
client, err := agentx.Dial(network, *AgentXAddr,
|
||||
agentx.WithTimeout(1*time.Minute),
|
||||
agentx.WithReconnectInterval(1*time.Second),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client.Timeout = 1 * time.Minute
|
||||
client.ReconnectInterval = 1 * time.Second
|
||||
|
||||
// Register the interface MIB with the AgentX client
|
||||
if err := interfaceMIB.RegisterWithClient(client); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Printf("Successfully registered with AgentX at %s://%s", network, address)
|
||||
logger.Printf("Successfully registered with AgentX at %s://%s", network, *AgentXAddr)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ func TestAgentXAddrFlagParsing(t *testing.T) {
|
||||
// Test Unix socket path
|
||||
testAddr := "/var/run/test.sock"
|
||||
*AgentXAddr = testAddr
|
||||
|
||||
|
||||
if *AgentXAddr != testAddr {
|
||||
t.Errorf("Expected AgentX address to be '%s', got '%s'", testAddr, *AgentXAddr)
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func TestAgentXAddrFlagParsing(t *testing.T) {
|
||||
// Test TCP address
|
||||
testAddr = "192.168.1.1:705"
|
||||
*AgentXAddr = testAddr
|
||||
|
||||
|
||||
if *AgentXAddr != testAddr {
|
||||
t.Errorf("Expected AgentX address to be '%s', got '%s'", testAddr, *AgentXAddr)
|
||||
}
|
||||
@@ -43,12 +43,12 @@ func TestFlagRegistration(t *testing.T) {
|
||||
t.Error("Expected agentx.addr flag to be registered")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if f.DefValue != "localhost:705" {
|
||||
t.Errorf("Expected flag default value to be 'localhost:705', got '%s'", f.DefValue)
|
||||
}
|
||||
|
||||
|
||||
if f.Usage != "Address to connect to (hostname:port or Unix socket path)" {
|
||||
t.Errorf("Unexpected flag usage string: %s", f.Usage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@ package config
|
||||
// Global configuration variables
|
||||
var (
|
||||
Debug bool
|
||||
)
|
||||
)
|
||||
|
||||
@@ -27,4 +27,4 @@ func TestDebugFlagSet(t *testing.T) {
|
||||
if Debug != false {
|
||||
t.Errorf("Expected Debug to be false after setting, got %v", Debug)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ module govpp-snmp-agentx
|
||||
go 1.23.8
|
||||
|
||||
require (
|
||||
github.com/posteo/go-agentx v0.2.1
|
||||
github.com/posteo/go-agentx v0.3.0
|
||||
go.fd.io/govpp v0.12.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -18,12 +18,11 @@ github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posteo/go-agentx v0.2.1 h1:HO0zO/+GosL0RYEodu7KNH9OF/rL5bJbhXNP1z3hkT8=
|
||||
github.com/posteo/go-agentx v0.2.1/go.mod h1:EUR75CfAEDstQn3WqCs26Ti64EsggaSXDk2dgxPQ5TI=
|
||||
github.com/posteo/go-agentx v0.3.0 h1:Mqu0qzPHxbyZF3+fKwN2vjW49t6TPPgivjjplcuouNw=
|
||||
github.com/posteo/go-agentx v0.3.0/go.mod h1:YCWL7bzLlpSNeU9vnfEg1pdlllDs1v2mz+pRcg21CUg=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
go.fd.io/govpp v0.12.0 h1:5HnMzsKHSFdxglsFyEhR0g+CzncWiLYXG2NDYgNUrnE=
|
||||
|
||||
@@ -18,55 +18,11 @@ import (
|
||||
"govpp-snmp-agentx/vpp"
|
||||
)
|
||||
|
||||
// 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
|
||||
// ifHighSpeed .15 - Gauge32 (interface speed in Mbps)
|
||||
// ifAlias .18 - DisplayString
|
||||
|
||||
// IF-MIB OID bases
|
||||
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
|
||||
// VPP Config structures
|
||||
type VPPConfig struct {
|
||||
Interfaces map[string]VPPInterface `yaml:"interfaces"`
|
||||
Loopbacks map[string]VPPInterface `yaml:"loopbacks"`
|
||||
@@ -78,39 +34,43 @@ type VPPInterface struct {
|
||||
}
|
||||
|
||||
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
|
||||
interfaceDetails map[uint32]*vpp.InterfaceDetails // indexed by interface index
|
||||
mutex sync.RWMutex
|
||||
client *agentx.Client
|
||||
ifEntrySession *agentx.Session
|
||||
ifXTableSession *agentx.Session
|
||||
|
||||
// Simple approach: track interface set and rebuild when it changes
|
||||
currentInterfaces map[uint32]bool
|
||||
descriptions map[string]string
|
||||
interfaceDetails map[uint32]*vpp.InterfaceDetails
|
||||
|
||||
// Counter items - direct references for fast updates
|
||||
counterItems map[string]*agentx.ListItem
|
||||
}
|
||||
|
||||
func NewInterfaceMIB() *InterfaceMIB {
|
||||
return &InterfaceMIB{
|
||||
handler: &agentx.ListHandler{},
|
||||
stats: make(map[uint32]*api.InterfaceCounters),
|
||||
descriptions: make(map[string]string),
|
||||
interfaceDetails: make(map[uint32]*vpp.InterfaceDetails),
|
||||
currentInterfaces: make(map[uint32]bool),
|
||||
descriptions: make(map[string]string),
|
||||
interfaceDetails: make(map[uint32]*vpp.InterfaceDetails),
|
||||
counterItems: make(map[string]*agentx.ListItem),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *InterfaceMIB) GetHandler() *agentx.ListHandler {
|
||||
return m.handler
|
||||
// Always create a new handler - this is the key simplification
|
||||
return &agentx.ListHandler{}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -120,24 +80,18 @@ func (m *InterfaceMIB) LoadVPPConfig(configPath string) error {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,306 +103,225 @@ func (m *InterfaceMIB) UpdateInterfaceDetails(details []vpp.InterfaceDetails) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
logger.Debugf("Updating interface details for %d interfaces", len(details))
|
||||
|
||||
// Update interface details map
|
||||
for _, detail := range details {
|
||||
m.interfaceDetails[uint32(detail.SwIfIndex)] = &detail
|
||||
logger.Debugf("Updated details for interface %d (%s): MAC=%x, Speed=%d",
|
||||
detail.SwIfIndex, detail.InterfaceName, detail.MacAddress, detail.Speed)
|
||||
}
|
||||
|
||||
logger.Debugf("Interface details updated for %d interfaces", len(details))
|
||||
logger.Debugf("Updated interface details for %d interfaces", len(details))
|
||||
}
|
||||
|
||||
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
|
||||
// Check if interface set changed
|
||||
newInterfaces := make(map[uint32]bool)
|
||||
for _, iface := range interfaceStats.Interfaces {
|
||||
logger.Debugf("Processing interface %d (%s)", iface.InterfaceIndex, iface.InterfaceName)
|
||||
m.stats[iface.InterfaceIndex] = &iface
|
||||
m.addInterfaceToMIB(&iface)
|
||||
newInterfaces[iface.InterfaceIndex] = true
|
||||
}
|
||||
|
||||
// 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 for %d interfaces", len(m.stats))
|
||||
// Simple comparison - rebuild if different
|
||||
needsRebuild := len(newInterfaces) != len(m.currentInterfaces)
|
||||
if !needsRebuild {
|
||||
for idx := range newInterfaces {
|
||||
if !m.currentInterfaces[idx] {
|
||||
needsRebuild = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.Debugf("IF-MIB now contains %d interfaces", len(m.stats))
|
||||
if needsRebuild {
|
||||
logger.Debugf("Interface set changed, rebuilding MIB")
|
||||
if err := m.rebuildMIB(interfaceStats.Interfaces); err != nil {
|
||||
logger.Printf("Failed to rebuild MIB: %v", err)
|
||||
return
|
||||
}
|
||||
m.currentInterfaces = newInterfaces
|
||||
} else {
|
||||
// Fast path: just update counters
|
||||
logger.Debugf("Updating counters for %d interfaces", len(interfaceStats.Interfaces))
|
||||
for _, iface := range interfaceStats.Interfaces {
|
||||
m.updateCounterValues(&iface)
|
||||
}
|
||||
}
|
||||
|
||||
logger.Printf("Updated IF-MIB data for %d interfaces", len(interfaceStats.Interfaces))
|
||||
}
|
||||
|
||||
func (m *InterfaceMIB) addInterfaceToMIB(iface *api.InterfaceCounters) {
|
||||
func (m *InterfaceMIB) rebuildMIB(interfaces []api.InterfaceCounters) error {
|
||||
// If no client is available (e.g., during testing), just track interfaces
|
||||
if m.client == nil {
|
||||
logger.Debugf("No AgentX client available, only tracking interface set")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close old sessions
|
||||
if m.ifEntrySession != nil {
|
||||
m.ifEntrySession.Close()
|
||||
m.ifEntrySession = nil
|
||||
}
|
||||
if m.ifXTableSession != nil {
|
||||
m.ifXTableSession.Close()
|
||||
m.ifXTableSession = nil
|
||||
}
|
||||
|
||||
// Create fresh handler
|
||||
handler := &agentx.ListHandler{}
|
||||
m.counterItems = make(map[string]*agentx.ListItem)
|
||||
|
||||
// Build all MIB entries
|
||||
for _, iface := range interfaces {
|
||||
m.addInterfaceToHandler(handler, &iface)
|
||||
}
|
||||
|
||||
// Register new sessions
|
||||
ifEntrySession, err := m.client.Session(value.MustParseOID(ifEntryOID), "ifEntry", handler)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create ifEntry session: %v", err)
|
||||
}
|
||||
|
||||
err = ifEntrySession.Register(127, value.MustParseOID(ifEntryOID))
|
||||
if err != nil {
|
||||
ifEntrySession.Close()
|
||||
return fmt.Errorf("failed to register ifEntry: %v", err)
|
||||
}
|
||||
|
||||
ifXTableSession, err := m.client.Session(value.MustParseOID(ifXTableOID), "ifXTable", handler)
|
||||
if err != nil {
|
||||
ifEntrySession.Close()
|
||||
return fmt.Errorf("failed to create ifXTable session: %v", err)
|
||||
}
|
||||
|
||||
err = ifXTableSession.Register(127, value.MustParseOID(ifXTableOID))
|
||||
if err != nil {
|
||||
ifEntrySession.Close()
|
||||
ifXTableSession.Close()
|
||||
return fmt.Errorf("failed to register ifXTable: %v", err)
|
||||
}
|
||||
|
||||
m.ifEntrySession = ifEntrySession
|
||||
m.ifXTableSession = ifXTableSession
|
||||
|
||||
logger.Debugf("Successfully rebuilt MIB with %d interfaces", len(interfaces))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *InterfaceMIB) addInterfaceToHandler(handler *agentx.ListHandler, iface *api.InterfaceCounters) {
|
||||
idx := int(iface.InterfaceIndex) + *vpp.IfIndexOffset
|
||||
details := m.interfaceDetails[iface.InterfaceIndex]
|
||||
|
||||
// Add ifEntry (classic interface table) entries
|
||||
m.addIfEntry(iface, idx)
|
||||
// Add static fields (these don't change frequently)
|
||||
m.addStaticFields(handler, iface, idx, details)
|
||||
|
||||
// Add ifXTable (extended interface table) entries
|
||||
m.addIfXTable(iface, idx)
|
||||
// Add counter fields and store references for fast updates
|
||||
m.addCounterFields(handler, 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) {
|
||||
func (m *InterfaceMIB) addStaticFields(handler *agentx.ListHandler, iface *api.InterfaceCounters, idx int, details *vpp.InterfaceDetails) {
|
||||
var item *agentx.ListItem
|
||||
|
||||
// Get interface details if available
|
||||
details := m.interfaceDetails[iface.InterfaceIndex]
|
||||
|
||||
// ifIndex (.1)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.1.%d", ifEntryOID, idx))
|
||||
item = 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 = 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 = handler.Add(fmt.Sprintf("%s.3.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeInteger
|
||||
item.Value = int32(6)
|
||||
|
||||
// ifMtu (.4) - Use real MTU if available, otherwise default to 1500
|
||||
// ifMtu (.4)
|
||||
mtu := int32(1500)
|
||||
if details != nil {
|
||||
mtu = int32(details.MTU)
|
||||
}
|
||||
item = m.handler.Add(fmt.Sprintf("%s.4.%d", ifEntryOID, idx))
|
||||
item = handler.Add(fmt.Sprintf("%s.4.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeInteger
|
||||
item.Value = mtu
|
||||
|
||||
// ifSpeed (.5) - Only populate for speeds <= 2.5Gbps (legacy field limitation)
|
||||
// ifSpeed (.5) - Only for speeds <= 2.5Gbps
|
||||
if details != nil && details.Speed > 0 && details.Speed <= 2500000000 {
|
||||
// Use real speed for interfaces <= 2.5Gbps
|
||||
item = m.handler.Add(fmt.Sprintf("%s.5.%d", ifEntryOID, idx))
|
||||
item = handler.Add(fmt.Sprintf("%s.5.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeGauge32
|
||||
item.Value = uint32(details.Speed)
|
||||
} else if details == nil || details.Speed == 0 {
|
||||
// Default to 1Gbps when speed is unknown
|
||||
item = m.handler.Add(fmt.Sprintf("%s.5.%d", ifEntryOID, idx))
|
||||
item = handler.Add(fmt.Sprintf("%s.5.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeGauge32
|
||||
item.Value = uint32(1000000000)
|
||||
}
|
||||
// For speeds > 2.5Gbps, don't populate ifSpeed field at all
|
||||
|
||||
// ifPhysAddress (.6) - Use real MAC address if available
|
||||
// ifPhysAddress (.6)
|
||||
macAddr := ""
|
||||
if details != nil && len(details.MacAddress) > 0 {
|
||||
macAddr = string(details.MacAddress)
|
||||
}
|
||||
item = m.handler.Add(fmt.Sprintf("%s.6.%d", ifEntryOID, idx))
|
||||
item = handler.Add(fmt.Sprintf("%s.6.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeOctetString
|
||||
item.Value = macAddr
|
||||
|
||||
// ifAdminStatus (.7) - Use real admin status if available
|
||||
adminStatus := int32(1) // default up
|
||||
if details != nil {
|
||||
if details.AdminStatus {
|
||||
adminStatus = 1 // up
|
||||
} else {
|
||||
adminStatus = 2 // down
|
||||
}
|
||||
// ifAdminStatus (.7)
|
||||
adminStatus := int32(1)
|
||||
if details != nil && !details.AdminStatus {
|
||||
adminStatus = 2
|
||||
}
|
||||
item = m.handler.Add(fmt.Sprintf("%s.7.%d", ifEntryOID, idx))
|
||||
item = handler.Add(fmt.Sprintf("%s.7.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeInteger
|
||||
item.Value = adminStatus
|
||||
|
||||
// ifOperStatus (.8) - Use real operational status if available
|
||||
operStatus := int32(1) // default up
|
||||
if details != nil {
|
||||
if details.OperStatus {
|
||||
operStatus = 1 // up
|
||||
} else {
|
||||
operStatus = 2 // down
|
||||
}
|
||||
// ifOperStatus (.8)
|
||||
operStatus := int32(1)
|
||||
if details != nil && !details.OperStatus {
|
||||
operStatus = 2
|
||||
}
|
||||
item = m.handler.Add(fmt.Sprintf("%s.8.%d", ifEntryOID, idx))
|
||||
item = handler.Add(fmt.Sprintf("%s.8.%d", ifEntryOID, idx))
|
||||
item.Type = pdu.VariableTypeInteger
|
||||
item.Value = operStatus
|
||||
|
||||
// ifLastChange (.9) - 0 (unknown)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.9.%d", ifEntryOID, idx))
|
||||
// ifLastChange (.9)
|
||||
item = 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
|
||||
// iface.Rx*cast.Packets is only set if "set interface feature X stats-collect-rx arc device-input" is configured
|
||||
if iface.RxUnicast.Packets == 0 {
|
||||
item.Value = uint32(iface.Rx.Packets)
|
||||
} else {
|
||||
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))
|
||||
// ifInUnknownProtos (.15)
|
||||
item = 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
|
||||
// iface.Tx*cast.Packets is only set if "set interface feature X stats-collect-tx arc interface-output" is configured
|
||||
if iface.TxUnicast.Packets == 0 {
|
||||
item.Value = uint32(iface.Tx.Packets)
|
||||
} else {
|
||||
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))
|
||||
// ifOutDiscards (.19)
|
||||
item = 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))
|
||||
// ifOutQLen (.21)
|
||||
item = 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
|
||||
|
||||
// ifXTable static fields
|
||||
// ifName (.1)
|
||||
item = m.handler.Add(fmt.Sprintf("%s.1.%d", ifXTableOID, idx))
|
||||
item = 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
|
||||
if iface.RxUnicast.Packets == 0 {
|
||||
item.Value = iface.Rx.Packets
|
||||
} else {
|
||||
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
|
||||
if iface.TxUnicast.Packets == 0 {
|
||||
item.Value = iface.Tx.Packets
|
||||
} else {
|
||||
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
|
||||
|
||||
// ifHighSpeed (.15) - Interface speed in Megabits per second
|
||||
details := m.interfaceDetails[iface.InterfaceIndex]
|
||||
speedMbps := uint32(1000) // default 1 Gbps = 1000 Mbps
|
||||
// ifHighSpeed (.15)
|
||||
speedMbps := uint32(1000)
|
||||
if details != nil && details.Speed > 0 {
|
||||
speedMbps = uint32(details.Speed / 1000000) // Convert bps to Mbps
|
||||
speedMbps = uint32(details.Speed / 1000000)
|
||||
}
|
||||
item = m.handler.Add(fmt.Sprintf("%s.15.%d", ifXTableOID, idx))
|
||||
item = handler.Add(fmt.Sprintf("%s.15.%d", ifXTableOID, idx))
|
||||
item.Type = pdu.VariableTypeGauge32
|
||||
item.Value = speedMbps
|
||||
|
||||
// ifAlias (.18) - Interface description/alias
|
||||
item = m.handler.Add(fmt.Sprintf("%s.18.%d", ifXTableOID, idx))
|
||||
// ifAlias (.18)
|
||||
item = 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 {
|
||||
@@ -456,41 +329,157 @@ func (m *InterfaceMIB) addIfXTable(iface *api.InterfaceCounters, idx int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *InterfaceMIB) addCounterFields(handler *agentx.ListHandler, iface *api.InterfaceCounters, idx int) {
|
||||
ifIdx := iface.InterfaceIndex
|
||||
|
||||
// ifEntry counters
|
||||
counters := []struct {
|
||||
oid string
|
||||
key string
|
||||
typ pdu.VariableType
|
||||
}{
|
||||
{fmt.Sprintf("%s.10.%d", ifEntryOID, idx), "ifInOctets", pdu.VariableTypeCounter32},
|
||||
{fmt.Sprintf("%s.11.%d", ifEntryOID, idx), "ifInUcastPkts", pdu.VariableTypeCounter32},
|
||||
{fmt.Sprintf("%s.12.%d", ifEntryOID, idx), "ifInNUcastPkts", pdu.VariableTypeCounter32},
|
||||
{fmt.Sprintf("%s.13.%d", ifEntryOID, idx), "ifInDiscards", pdu.VariableTypeCounter32},
|
||||
{fmt.Sprintf("%s.14.%d", ifEntryOID, idx), "ifInErrors", pdu.VariableTypeCounter32},
|
||||
{fmt.Sprintf("%s.16.%d", ifEntryOID, idx), "ifOutOctets", pdu.VariableTypeCounter32},
|
||||
{fmt.Sprintf("%s.17.%d", ifEntryOID, idx), "ifOutUcastPkts", pdu.VariableTypeCounter32},
|
||||
{fmt.Sprintf("%s.18.%d", ifEntryOID, idx), "ifOutNUcastPkts", pdu.VariableTypeCounter32},
|
||||
{fmt.Sprintf("%s.20.%d", ifEntryOID, idx), "ifOutErrors", pdu.VariableTypeCounter32},
|
||||
|
||||
// ifXTable counters
|
||||
{fmt.Sprintf("%s.2.%d", ifXTableOID, idx), "ifInMulticastPkts", pdu.VariableTypeCounter32},
|
||||
{fmt.Sprintf("%s.3.%d", ifXTableOID, idx), "ifInBroadcastPkts", pdu.VariableTypeCounter32},
|
||||
{fmt.Sprintf("%s.4.%d", ifXTableOID, idx), "ifOutMulticastPkts", pdu.VariableTypeCounter32},
|
||||
{fmt.Sprintf("%s.5.%d", ifXTableOID, idx), "ifOutBroadcastPkts", pdu.VariableTypeCounter32},
|
||||
{fmt.Sprintf("%s.6.%d", ifXTableOID, idx), "ifHCInOctets", pdu.VariableTypeCounter64},
|
||||
{fmt.Sprintf("%s.7.%d", ifXTableOID, idx), "ifHCInUcastPkts", pdu.VariableTypeCounter64},
|
||||
{fmt.Sprintf("%s.8.%d", ifXTableOID, idx), "ifHCInMulticastPkts", pdu.VariableTypeCounter64},
|
||||
{fmt.Sprintf("%s.9.%d", ifXTableOID, idx), "ifHCInBroadcastPkts", pdu.VariableTypeCounter64},
|
||||
{fmt.Sprintf("%s.10.%d", ifXTableOID, idx), "ifHCOutOctets", pdu.VariableTypeCounter64},
|
||||
{fmt.Sprintf("%s.11.%d", ifXTableOID, idx), "ifHCOutUcastPkts", pdu.VariableTypeCounter64},
|
||||
{fmt.Sprintf("%s.12.%d", ifXTableOID, idx), "ifHCOutMulticastPkts", pdu.VariableTypeCounter64},
|
||||
{fmt.Sprintf("%s.13.%d", ifXTableOID, idx), "ifHCOutBroadcastPkts", pdu.VariableTypeCounter64},
|
||||
}
|
||||
|
||||
for _, counter := range counters {
|
||||
item := handler.Add(counter.oid)
|
||||
item.Type = counter.typ
|
||||
m.counterItems[fmt.Sprintf("%d_%s", ifIdx, counter.key)] = item
|
||||
}
|
||||
|
||||
// Set initial values
|
||||
m.updateCounterValues(iface)
|
||||
}
|
||||
|
||||
func (m *InterfaceMIB) updateCounterValues(iface *api.InterfaceCounters) {
|
||||
ifIdx := iface.InterfaceIndex
|
||||
|
||||
// ifEntry counters
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifInOctets", ifIdx)]; item != nil {
|
||||
item.Value = uint32(iface.Rx.Bytes)
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifInUcastPkts", ifIdx)]; item != nil {
|
||||
if iface.RxUnicast.Packets == 0 {
|
||||
item.Value = uint32(iface.Rx.Packets)
|
||||
} else {
|
||||
item.Value = uint32(iface.RxUnicast.Packets)
|
||||
}
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifInNUcastPkts", ifIdx)]; item != nil {
|
||||
item.Value = uint32(iface.RxMulticast.Packets + iface.RxBroadcast.Packets)
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifInDiscards", ifIdx)]; item != nil {
|
||||
item.Value = uint32(iface.Drops)
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifInErrors", ifIdx)]; item != nil {
|
||||
item.Value = uint32(iface.RxErrors)
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifOutOctets", ifIdx)]; item != nil {
|
||||
item.Value = uint32(iface.Tx.Bytes)
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifOutUcastPkts", ifIdx)]; item != nil {
|
||||
if iface.TxUnicast.Packets == 0 {
|
||||
item.Value = uint32(iface.Tx.Packets)
|
||||
} else {
|
||||
item.Value = uint32(iface.TxUnicast.Packets)
|
||||
}
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifOutNUcastPkts", ifIdx)]; item != nil {
|
||||
item.Value = uint32(iface.TxMulticast.Packets + iface.TxBroadcast.Packets)
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifOutErrors", ifIdx)]; item != nil {
|
||||
item.Value = uint32(iface.TxErrors)
|
||||
}
|
||||
|
||||
// ifXTable counters
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifInMulticastPkts", ifIdx)]; item != nil {
|
||||
item.Value = uint32(iface.RxMulticast.Packets)
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifInBroadcastPkts", ifIdx)]; item != nil {
|
||||
item.Value = uint32(iface.RxBroadcast.Packets)
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifOutMulticastPkts", ifIdx)]; item != nil {
|
||||
item.Value = uint32(iface.TxMulticast.Packets)
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifOutBroadcastPkts", ifIdx)]; item != nil {
|
||||
item.Value = uint32(iface.TxBroadcast.Packets)
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifHCInOctets", ifIdx)]; item != nil {
|
||||
item.Value = iface.Rx.Bytes
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifHCInUcastPkts", ifIdx)]; item != nil {
|
||||
if iface.RxUnicast.Packets == 0 {
|
||||
item.Value = iface.Rx.Packets
|
||||
} else {
|
||||
item.Value = iface.RxUnicast.Packets
|
||||
}
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifHCInMulticastPkts", ifIdx)]; item != nil {
|
||||
item.Value = iface.RxMulticast.Packets
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifHCInBroadcastPkts", ifIdx)]; item != nil {
|
||||
item.Value = iface.RxBroadcast.Packets
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifHCOutOctets", ifIdx)]; item != nil {
|
||||
item.Value = iface.Tx.Bytes
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifHCOutUcastPkts", ifIdx)]; item != nil {
|
||||
if iface.TxUnicast.Packets == 0 {
|
||||
item.Value = iface.Tx.Packets
|
||||
} else {
|
||||
item.Value = iface.TxUnicast.Packets
|
||||
}
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifHCOutMulticastPkts", ifIdx)]; item != nil {
|
||||
item.Value = iface.TxMulticast.Packets
|
||||
}
|
||||
if item := m.counterItems[fmt.Sprintf("%d_ifHCOutBroadcastPkts", ifIdx)]; item != nil {
|
||||
item.Value = iface.TxBroadcast.Packets
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
m.client = client
|
||||
// Don't register anything yet - wait for first UpdateStats call
|
||||
logger.Debugf("Stored AgentX client reference")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *InterfaceMIB) Close() {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
if m.ifEntrySession != nil {
|
||||
m.ifEntrySession.Close()
|
||||
m.ifEntrySession = nil
|
||||
}
|
||||
if m.ifXTableSession != nil {
|
||||
m.ifXTableSession.Close()
|
||||
m.ifXTableSession = nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,20 +17,24 @@ func TestNewInterfaceMIB(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
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 mib.interfaceDetails == nil {
|
||||
t.Error("Expected interfaceDetails map to be initialized")
|
||||
}
|
||||
|
||||
if mib.currentInterfaces == nil {
|
||||
t.Error("Expected currentInterfaces map to be initialized")
|
||||
}
|
||||
|
||||
if mib.counterItems == nil {
|
||||
t.Error("Expected counterItems map to be initialized")
|
||||
}
|
||||
|
||||
if len(mib.currentInterfaces) != 0 {
|
||||
t.Errorf("Expected currentInterfaces map to be empty, got %d entries", len(mib.currentInterfaces))
|
||||
}
|
||||
|
||||
if len(mib.descriptions) != 0 {
|
||||
@@ -40,14 +44,20 @@ func TestNewInterfaceMIB(t *testing.T) {
|
||||
|
||||
func TestGetHandler(t *testing.T) {
|
||||
mib := NewInterfaceMIB()
|
||||
handler := mib.GetHandler()
|
||||
handler1 := mib.GetHandler()
|
||||
handler2 := mib.GetHandler()
|
||||
|
||||
if handler == nil {
|
||||
if handler1 == nil {
|
||||
t.Error("GetHandler returned nil")
|
||||
}
|
||||
|
||||
if handler != mib.handler {
|
||||
t.Error("GetHandler returned different handler than expected")
|
||||
if handler2 == nil {
|
||||
t.Error("GetHandler returned nil")
|
||||
}
|
||||
|
||||
// In the new implementation, GetHandler always returns a fresh handler
|
||||
if handler1 == handler2 {
|
||||
t.Error("Expected GetHandler to return fresh handlers, but got the same reference")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,19 +173,12 @@ func TestUpdateStatsBasic(t *testing.T) {
|
||||
// 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))
|
||||
// Check that interface was registered
|
||||
if len(mib.currentInterfaces) != 1 {
|
||||
t.Errorf("Expected 1 interface in currentInterfaces, got %d", len(mib.currentInterfaces))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
if !mib.currentInterfaces[0] {
|
||||
t.Error("Expected interface 0 to be registered in currentInterfaces")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
|
||||
"govpp-snmp-agentx/config"
|
||||
)
|
||||
|
||||
@@ -16,15 +16,15 @@ func getCallerInfo() string {
|
||||
if !ok {
|
||||
return "unknown:unknown"
|
||||
}
|
||||
|
||||
|
||||
fn := runtime.FuncForPC(pc)
|
||||
if fn == nil {
|
||||
return "unknown:unknown"
|
||||
}
|
||||
|
||||
|
||||
funcName := filepath.Base(fn.Name())
|
||||
fileName := filepath.Base(file)
|
||||
|
||||
|
||||
return fmt.Sprintf("%s:%s", fileName, funcName)
|
||||
}
|
||||
|
||||
@@ -49,4 +49,4 @@ func Debugf(format string, args ...interface{}) {
|
||||
// Sync flushes any buffered log entries (no-op for fmt.Println)
|
||||
func Sync() {
|
||||
// No buffering with fmt.Println, so this is a no-op
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +33,11 @@ func TestPrintf(t *testing.T) {
|
||||
if !strings.HasPrefix(output, "INFO ") {
|
||||
t.Errorf("Expected output to start with 'INFO ', got: %s", output)
|
||||
}
|
||||
|
||||
|
||||
if !strings.Contains(output, "logger_test.go:logger.TestPrintf") {
|
||||
t.Errorf("Expected output to contain caller info, got: %s", output)
|
||||
}
|
||||
|
||||
|
||||
if !strings.Contains(output, "test message: hello") {
|
||||
t.Errorf("Expected output to contain message, got: %s", output)
|
||||
}
|
||||
@@ -71,7 +71,7 @@ func TestDebugfWithDebugEnabled(t *testing.T) {
|
||||
if !strings.HasPrefix(output, "DEBUG ") {
|
||||
t.Errorf("Expected output to start with 'DEBUG ', got: %s", output)
|
||||
}
|
||||
|
||||
|
||||
if !strings.Contains(output, "debug message: test") {
|
||||
t.Errorf("Expected output to contain message, got: %s", output)
|
||||
}
|
||||
@@ -110,4 +110,4 @@ func TestDebugfWithDebugDisabled(t *testing.T) {
|
||||
func TestSync(t *testing.T) {
|
||||
// Test that Sync doesn't panic (it's a no-op now)
|
||||
Sync()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"govpp-snmp-agentx/vpp"
|
||||
)
|
||||
|
||||
const Version = "1.1.6-1"
|
||||
const Version = "1.2.3-1"
|
||||
|
||||
func main() {
|
||||
debug := flag.Bool("debug", false, "Enable debug logging")
|
||||
@@ -46,9 +46,9 @@ func main() {
|
||||
}
|
||||
|
||||
// Create VPP client and managers
|
||||
vppClient := vpp.NewVPPClient()
|
||||
vppClient := &vpp.VPPClient{}
|
||||
interfaceManager := vpp.NewInterfaceManager(vppClient)
|
||||
statsManager := vpp.NewStatsManager(vppClient)
|
||||
statsManager := vpp.NewStatsManager(vppClient, interfaceManager)
|
||||
|
||||
// Set up interface event callback to update interface details
|
||||
interfaceManager.SetEventCallback(interfaceMIB.UpdateInterfaceDetails)
|
||||
|
||||
@@ -29,11 +29,6 @@ type VPPClient struct {
|
||||
connected bool
|
||||
}
|
||||
|
||||
// NewVPPClient creates a new VPP client instance
|
||||
func NewVPPClient() *VPPClient {
|
||||
return &VPPClient{}
|
||||
}
|
||||
|
||||
// Connect establishes connections to both VPP API and Stats sockets
|
||||
func (c *VPPClient) Connect() error {
|
||||
logger.Debugf("Connecting to VPP (API: %s, Stats: %s)", *ApiAddr, *StatsAddr)
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func TestNewInterfaceManager(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
client := &VPPClient{}
|
||||
manager := NewInterfaceManager(client)
|
||||
|
||||
if manager == nil {
|
||||
@@ -36,7 +36,7 @@ func TestNewInterfaceManager(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInterfaceManagerSetEventCallback(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
client := &VPPClient{}
|
||||
manager := NewInterfaceManager(client)
|
||||
|
||||
var callbackCalled bool
|
||||
@@ -82,7 +82,7 @@ func TestInterfaceManagerSetEventCallback(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInterfaceManagerGetAllInterfaceDetailsWithoutConnection(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
client := &VPPClient{}
|
||||
manager := NewInterfaceManager(client)
|
||||
|
||||
_, err := manager.GetAllInterfaceDetails()
|
||||
@@ -101,7 +101,7 @@ func TestInterfaceManagerGetAllInterfaceDetailsWithoutConnection(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInterfaceManagerStartEventWatcherWithoutConnection(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
client := &VPPClient{}
|
||||
manager := NewInterfaceManager(client)
|
||||
|
||||
err := manager.StartEventWatcher()
|
||||
@@ -120,7 +120,7 @@ func TestInterfaceManagerStartEventWatcherWithoutConnection(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInterfaceManagerHandleInterfaceEventWithoutCallback(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
client := &VPPClient{}
|
||||
manager := NewInterfaceManager(client)
|
||||
|
||||
// Should not panic when callback is nil
|
||||
@@ -128,7 +128,7 @@ func TestInterfaceManagerHandleInterfaceEventWithoutCallback(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInterfaceManagerInitializeEventWatchingWithoutConnection(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
client := &VPPClient{}
|
||||
manager := NewInterfaceManager(client)
|
||||
|
||||
err := manager.InitializeEventWatching()
|
||||
@@ -220,7 +220,7 @@ func TestInterfaceEventCallback(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInterfaceManagerStartStopEventMonitoring(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
client := &VPPClient{}
|
||||
manager := NewInterfaceManager(client)
|
||||
|
||||
if manager.running {
|
||||
@@ -248,7 +248,7 @@ func TestInterfaceManagerStartStopEventMonitoring(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInterfaceManagerEventMonitoringWithConnectionChanges(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
client := &VPPClient{}
|
||||
manager := NewInterfaceManager(client)
|
||||
|
||||
// Set a callback to track calls
|
||||
|
||||
@@ -15,17 +15,19 @@ type StatsCallback func(*api.InterfaceStats)
|
||||
|
||||
// StatsManager handles VPP statistics operations
|
||||
type StatsManager struct {
|
||||
client *VPPClient
|
||||
statsCallback StatsCallback
|
||||
period time.Duration
|
||||
running bool
|
||||
client *VPPClient
|
||||
interfaceManager *InterfaceManager
|
||||
statsCallback StatsCallback
|
||||
period time.Duration
|
||||
running bool
|
||||
}
|
||||
|
||||
// NewStatsManager creates a new stats manager
|
||||
func NewStatsManager(client *VPPClient) *StatsManager {
|
||||
func NewStatsManager(client *VPPClient, interfaceManager *InterfaceManager) *StatsManager {
|
||||
return &StatsManager{
|
||||
client: client,
|
||||
period: time.Duration(*Period) * time.Second,
|
||||
client: client,
|
||||
interfaceManager: interfaceManager,
|
||||
period: time.Duration(*Period) * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,11 +141,24 @@ func (sm *StatsManager) queryAndReportStats() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Filter out deleted interfaces by comparing with current interface list
|
||||
filteredStats, err := sm.filterValidInterfaces(stats)
|
||||
if err != nil {
|
||||
logger.Printf("Failed to filter interface stats: %v", err)
|
||||
return false
|
||||
}
|
||||
|
||||
// Debug log basic info
|
||||
logger.Debugf("Retrieved stats for %d interfaces", len(stats.Interfaces))
|
||||
originalCount := len(stats.Interfaces)
|
||||
filteredCount := len(filteredStats.Interfaces)
|
||||
logger.Debugf("Retrieved stats for %d interfaces, filtered to %d valid interfaces", originalCount, filteredCount)
|
||||
|
||||
if originalCount > filteredCount {
|
||||
logger.Debugf("Filtered out %d deleted interfaces", originalCount-filteredCount)
|
||||
}
|
||||
|
||||
// Debug logging for individual interfaces
|
||||
for _, iface := range stats.Interfaces {
|
||||
for _, iface := range filteredStats.Interfaces {
|
||||
logger.Debugf("Interface %d (%s): RX %d pkts/%d bytes, TX %d pkts/%d bytes",
|
||||
iface.InterfaceIndex, iface.InterfaceName,
|
||||
iface.Rx.Packets, iface.Rx.Bytes,
|
||||
@@ -152,8 +167,45 @@ func (sm *StatsManager) queryAndReportStats() bool {
|
||||
|
||||
// Call the callback to update the MIB
|
||||
if sm.statsCallback != nil {
|
||||
sm.statsCallback(stats)
|
||||
sm.statsCallback(filteredStats)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// filterValidInterfaces removes stats for deleted interfaces by comparing with current interface list
|
||||
func (sm *StatsManager) filterValidInterfaces(stats *api.InterfaceStats) (*api.InterfaceStats, error) {
|
||||
if sm.interfaceManager == nil {
|
||||
logger.Debugf("No interface manager available, returning unfiltered stats")
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// Get current interface details
|
||||
currentInterfaces, err := sm.interfaceManager.GetAllInterfaceDetails()
|
||||
if err != nil {
|
||||
logger.Debugf("Failed to get current interface list: %v", err)
|
||||
return stats, err
|
||||
}
|
||||
|
||||
// Create a map of valid sw_if_index values
|
||||
validInterfaces := make(map[uint32]bool)
|
||||
for _, iface := range currentInterfaces {
|
||||
validInterfaces[uint32(iface.SwIfIndex)] = true
|
||||
}
|
||||
|
||||
// Filter the stats to only include valid interfaces
|
||||
filteredStats := &api.InterfaceStats{
|
||||
Interfaces: make([]api.InterfaceCounters, 0, len(stats.Interfaces)),
|
||||
}
|
||||
|
||||
for _, ifaceStat := range stats.Interfaces {
|
||||
if validInterfaces[ifaceStat.InterfaceIndex] {
|
||||
filteredStats.Interfaces = append(filteredStats.Interfaces, ifaceStat)
|
||||
} else {
|
||||
logger.Debugf("Filtering out stats for deleted interface %d (%s)",
|
||||
ifaceStat.InterfaceIndex, ifaceStat.InterfaceName)
|
||||
}
|
||||
}
|
||||
|
||||
return filteredStats, nil
|
||||
}
|
||||
|
||||
@@ -10,8 +10,9 @@ import (
|
||||
)
|
||||
|
||||
func TestNewStatsManager(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
manager := NewStatsManager(client)
|
||||
client := &VPPClient{}
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
if manager == nil {
|
||||
t.Fatal("NewStatsManager() returned nil")
|
||||
@@ -36,8 +37,9 @@ func TestNewStatsManager(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStatsManagerSetStatsCallback(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
manager := NewStatsManager(client)
|
||||
client := &VPPClient{}
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
var callbackCalled bool
|
||||
var receivedStats *api.InterfaceStats
|
||||
@@ -85,8 +87,9 @@ func TestStatsManagerSetStatsCallback(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStatsManagerSetPeriod(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
manager := NewStatsManager(client)
|
||||
client := &VPPClient{}
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
newPeriod := 5 * time.Second
|
||||
manager.SetPeriod(newPeriod)
|
||||
@@ -97,8 +100,9 @@ func TestStatsManagerSetPeriod(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStatsManagerStartStopStatsRoutine(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
manager := NewStatsManager(client)
|
||||
client := &VPPClient{}
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
if manager.running {
|
||||
t.Error("StatsManager should not be running initially")
|
||||
@@ -125,8 +129,9 @@ func TestStatsManagerStartStopStatsRoutine(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStatsManagerGetInterfaceStatsWithoutConnection(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
manager := NewStatsManager(client)
|
||||
client := &VPPClient{}
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
_, err := manager.GetInterfaceStats()
|
||||
if err == nil {
|
||||
@@ -206,8 +211,9 @@ func TestStatsCallback(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStatsManagerQueryAndReportStatsWithoutConnection(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
manager := NewStatsManager(client)
|
||||
client := &VPPClient{}
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
// Should return false when not connected
|
||||
if manager.queryAndReportStats() {
|
||||
@@ -216,8 +222,9 @@ func TestStatsManagerQueryAndReportStatsWithoutConnection(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStatsManagerWithShortPeriod(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
manager := NewStatsManager(client)
|
||||
client := &VPPClient{}
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
// Set a very short period for testing
|
||||
manager.SetPeriod(10 * time.Millisecond)
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func TestNewVPPClient(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
client := &VPPClient{}
|
||||
|
||||
if client == nil {
|
||||
t.Fatal("NewVPPClient() returned nil")
|
||||
@@ -27,7 +27,7 @@ func TestNewVPPClient(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestVPPClientDisconnect(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
client := &VPPClient{}
|
||||
|
||||
// Should be safe to call disconnect on unconnected client
|
||||
client.Disconnect()
|
||||
@@ -38,7 +38,7 @@ func TestVPPClientDisconnect(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestVPPClientNewAPIChannelWithoutConnection(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
client := &VPPClient{}
|
||||
|
||||
_, err := client.NewAPIChannel()
|
||||
if err == nil {
|
||||
@@ -56,7 +56,7 @@ func TestVPPClientNewAPIChannelWithoutConnection(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestVPPClientCheckLivenessWithoutConnection(t *testing.T) {
|
||||
client := NewVPPClient()
|
||||
client := &VPPClient{}
|
||||
|
||||
if client.CheckLiveness() {
|
||||
t.Error("CheckLiveness() should return false when not connected")
|
||||
@@ -86,7 +86,7 @@ func TestVPPClientConnectWithInvalidPaths(t *testing.T) {
|
||||
*StatsAddr = origStatsAddr
|
||||
}()
|
||||
|
||||
client := NewVPPClient()
|
||||
client := &VPPClient{}
|
||||
err := client.Connect()
|
||||
|
||||
if err == nil {
|
||||
|
||||
Reference in New Issue
Block a user