Filter interface data from stats segment by known vpp_iface; this avoids an issue in VPP where deleted interfaces remain in the stats segment
This commit is contained in:
@@ -48,7 +48,7 @@ func main() {
|
||||
// Create VPP client and managers
|
||||
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)
|
||||
|
||||
@@ -16,15 +16,17 @@ type StatsCallback func(*api.InterfaceStats)
|
||||
// StatsManager handles VPP statistics operations
|
||||
type StatsManager struct {
|
||||
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,
|
||||
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
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ import (
|
||||
|
||||
func TestNewStatsManager(t *testing.T) {
|
||||
client := &VPPClient{}
|
||||
manager := NewStatsManager(client)
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
if manager == nil {
|
||||
t.Fatal("NewStatsManager() returned nil")
|
||||
@@ -37,7 +38,8 @@ func TestNewStatsManager(t *testing.T) {
|
||||
|
||||
func TestStatsManagerSetStatsCallback(t *testing.T) {
|
||||
client := &VPPClient{}
|
||||
manager := NewStatsManager(client)
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
var callbackCalled bool
|
||||
var receivedStats *api.InterfaceStats
|
||||
@@ -86,7 +88,8 @@ func TestStatsManagerSetStatsCallback(t *testing.T) {
|
||||
|
||||
func TestStatsManagerSetPeriod(t *testing.T) {
|
||||
client := &VPPClient{}
|
||||
manager := NewStatsManager(client)
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
newPeriod := 5 * time.Second
|
||||
manager.SetPeriod(newPeriod)
|
||||
@@ -98,7 +101,8 @@ func TestStatsManagerSetPeriod(t *testing.T) {
|
||||
|
||||
func TestStatsManagerStartStopStatsRoutine(t *testing.T) {
|
||||
client := &VPPClient{}
|
||||
manager := NewStatsManager(client)
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
if manager.running {
|
||||
t.Error("StatsManager should not be running initially")
|
||||
@@ -126,7 +130,8 @@ func TestStatsManagerStartStopStatsRoutine(t *testing.T) {
|
||||
|
||||
func TestStatsManagerGetInterfaceStatsWithoutConnection(t *testing.T) {
|
||||
client := &VPPClient{}
|
||||
manager := NewStatsManager(client)
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
_, err := manager.GetInterfaceStats()
|
||||
if err == nil {
|
||||
@@ -207,7 +212,8 @@ func TestStatsCallback(t *testing.T) {
|
||||
|
||||
func TestStatsManagerQueryAndReportStatsWithoutConnection(t *testing.T) {
|
||||
client := &VPPClient{}
|
||||
manager := NewStatsManager(client)
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
// Should return false when not connected
|
||||
if manager.queryAndReportStats() {
|
||||
@@ -217,7 +223,8 @@ func TestStatsManagerQueryAndReportStatsWithoutConnection(t *testing.T) {
|
||||
|
||||
func TestStatsManagerWithShortPeriod(t *testing.T) {
|
||||
client := &VPPClient{}
|
||||
manager := NewStatsManager(client)
|
||||
interfaceManager := NewInterfaceManager(client)
|
||||
manager := NewStatsManager(client, interfaceManager)
|
||||
|
||||
// Set a very short period for testing
|
||||
manager.SetPeriod(10 * time.Millisecond)
|
||||
|
||||
Reference in New Issue
Block a user