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
|
// Create VPP client and managers
|
||||||
vppClient := &vpp.VPPClient{}
|
vppClient := &vpp.VPPClient{}
|
||||||
interfaceManager := vpp.NewInterfaceManager(vppClient)
|
interfaceManager := vpp.NewInterfaceManager(vppClient)
|
||||||
statsManager := vpp.NewStatsManager(vppClient)
|
statsManager := vpp.NewStatsManager(vppClient, interfaceManager)
|
||||||
|
|
||||||
// Set up interface event callback to update interface details
|
// Set up interface event callback to update interface details
|
||||||
interfaceManager.SetEventCallback(interfaceMIB.UpdateInterfaceDetails)
|
interfaceManager.SetEventCallback(interfaceMIB.UpdateInterfaceDetails)
|
||||||
|
|||||||
@@ -16,15 +16,17 @@ type StatsCallback func(*api.InterfaceStats)
|
|||||||
// StatsManager handles VPP statistics operations
|
// StatsManager handles VPP statistics operations
|
||||||
type StatsManager struct {
|
type StatsManager struct {
|
||||||
client *VPPClient
|
client *VPPClient
|
||||||
|
interfaceManager *InterfaceManager
|
||||||
statsCallback StatsCallback
|
statsCallback StatsCallback
|
||||||
period time.Duration
|
period time.Duration
|
||||||
running bool
|
running bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStatsManager creates a new stats manager
|
// NewStatsManager creates a new stats manager
|
||||||
func NewStatsManager(client *VPPClient) *StatsManager {
|
func NewStatsManager(client *VPPClient, interfaceManager *InterfaceManager) *StatsManager {
|
||||||
return &StatsManager{
|
return &StatsManager{
|
||||||
client: client,
|
client: client,
|
||||||
|
interfaceManager: interfaceManager,
|
||||||
period: time.Duration(*Period) * time.Second,
|
period: time.Duration(*Period) * time.Second,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,11 +141,24 @@ func (sm *StatsManager) queryAndReportStats() bool {
|
|||||||
return false
|
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
|
// 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
|
// 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",
|
logger.Debugf("Interface %d (%s): RX %d pkts/%d bytes, TX %d pkts/%d bytes",
|
||||||
iface.InterfaceIndex, iface.InterfaceName,
|
iface.InterfaceIndex, iface.InterfaceName,
|
||||||
iface.Rx.Packets, iface.Rx.Bytes,
|
iface.Rx.Packets, iface.Rx.Bytes,
|
||||||
@@ -152,8 +167,45 @@ func (sm *StatsManager) queryAndReportStats() bool {
|
|||||||
|
|
||||||
// Call the callback to update the MIB
|
// Call the callback to update the MIB
|
||||||
if sm.statsCallback != nil {
|
if sm.statsCallback != nil {
|
||||||
sm.statsCallback(stats)
|
sm.statsCallback(filteredStats)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
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) {
|
func TestNewStatsManager(t *testing.T) {
|
||||||
client := &VPPClient{}
|
client := &VPPClient{}
|
||||||
manager := NewStatsManager(client)
|
interfaceManager := NewInterfaceManager(client)
|
||||||
|
manager := NewStatsManager(client, interfaceManager)
|
||||||
|
|
||||||
if manager == nil {
|
if manager == nil {
|
||||||
t.Fatal("NewStatsManager() returned nil")
|
t.Fatal("NewStatsManager() returned nil")
|
||||||
@@ -37,7 +38,8 @@ func TestNewStatsManager(t *testing.T) {
|
|||||||
|
|
||||||
func TestStatsManagerSetStatsCallback(t *testing.T) {
|
func TestStatsManagerSetStatsCallback(t *testing.T) {
|
||||||
client := &VPPClient{}
|
client := &VPPClient{}
|
||||||
manager := NewStatsManager(client)
|
interfaceManager := NewInterfaceManager(client)
|
||||||
|
manager := NewStatsManager(client, interfaceManager)
|
||||||
|
|
||||||
var callbackCalled bool
|
var callbackCalled bool
|
||||||
var receivedStats *api.InterfaceStats
|
var receivedStats *api.InterfaceStats
|
||||||
@@ -86,7 +88,8 @@ func TestStatsManagerSetStatsCallback(t *testing.T) {
|
|||||||
|
|
||||||
func TestStatsManagerSetPeriod(t *testing.T) {
|
func TestStatsManagerSetPeriod(t *testing.T) {
|
||||||
client := &VPPClient{}
|
client := &VPPClient{}
|
||||||
manager := NewStatsManager(client)
|
interfaceManager := NewInterfaceManager(client)
|
||||||
|
manager := NewStatsManager(client, interfaceManager)
|
||||||
|
|
||||||
newPeriod := 5 * time.Second
|
newPeriod := 5 * time.Second
|
||||||
manager.SetPeriod(newPeriod)
|
manager.SetPeriod(newPeriod)
|
||||||
@@ -98,7 +101,8 @@ func TestStatsManagerSetPeriod(t *testing.T) {
|
|||||||
|
|
||||||
func TestStatsManagerStartStopStatsRoutine(t *testing.T) {
|
func TestStatsManagerStartStopStatsRoutine(t *testing.T) {
|
||||||
client := &VPPClient{}
|
client := &VPPClient{}
|
||||||
manager := NewStatsManager(client)
|
interfaceManager := NewInterfaceManager(client)
|
||||||
|
manager := NewStatsManager(client, interfaceManager)
|
||||||
|
|
||||||
if manager.running {
|
if manager.running {
|
||||||
t.Error("StatsManager should not be running initially")
|
t.Error("StatsManager should not be running initially")
|
||||||
@@ -126,7 +130,8 @@ func TestStatsManagerStartStopStatsRoutine(t *testing.T) {
|
|||||||
|
|
||||||
func TestStatsManagerGetInterfaceStatsWithoutConnection(t *testing.T) {
|
func TestStatsManagerGetInterfaceStatsWithoutConnection(t *testing.T) {
|
||||||
client := &VPPClient{}
|
client := &VPPClient{}
|
||||||
manager := NewStatsManager(client)
|
interfaceManager := NewInterfaceManager(client)
|
||||||
|
manager := NewStatsManager(client, interfaceManager)
|
||||||
|
|
||||||
_, err := manager.GetInterfaceStats()
|
_, err := manager.GetInterfaceStats()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -207,7 +212,8 @@ func TestStatsCallback(t *testing.T) {
|
|||||||
|
|
||||||
func TestStatsManagerQueryAndReportStatsWithoutConnection(t *testing.T) {
|
func TestStatsManagerQueryAndReportStatsWithoutConnection(t *testing.T) {
|
||||||
client := &VPPClient{}
|
client := &VPPClient{}
|
||||||
manager := NewStatsManager(client)
|
interfaceManager := NewInterfaceManager(client)
|
||||||
|
manager := NewStatsManager(client, interfaceManager)
|
||||||
|
|
||||||
// Should return false when not connected
|
// Should return false when not connected
|
||||||
if manager.queryAndReportStats() {
|
if manager.queryAndReportStats() {
|
||||||
@@ -217,7 +223,8 @@ func TestStatsManagerQueryAndReportStatsWithoutConnection(t *testing.T) {
|
|||||||
|
|
||||||
func TestStatsManagerWithShortPeriod(t *testing.T) {
|
func TestStatsManagerWithShortPeriod(t *testing.T) {
|
||||||
client := &VPPClient{}
|
client := &VPPClient{}
|
||||||
manager := NewStatsManager(client)
|
interfaceManager := NewInterfaceManager(client)
|
||||||
|
manager := NewStatsManager(client, interfaceManager)
|
||||||
|
|
||||||
// Set a very short period for testing
|
// Set a very short period for testing
|
||||||
manager.SetPeriod(10 * time.Millisecond)
|
manager.SetPeriod(10 * time.Millisecond)
|
||||||
|
|||||||
Reference in New Issue
Block a user