Use interface details to populate the ifmib, on startup and after each event
This commit is contained in:
@ -83,6 +83,7 @@ type InterfaceMIB struct {
|
|||||||
ifXTableSession *agentx.Session
|
ifXTableSession *agentx.Session
|
||||||
stats map[uint32]*api.InterfaceCounters // indexed by interface index
|
stats map[uint32]*api.InterfaceCounters // indexed by interface index
|
||||||
descriptions map[string]string // interface name -> description mapping
|
descriptions map[string]string // interface name -> description mapping
|
||||||
|
interfaceDetails map[uint32]*vpp.InterfaceDetails // indexed by interface index
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInterfaceMIB() *InterfaceMIB {
|
func NewInterfaceMIB() *InterfaceMIB {
|
||||||
@ -90,6 +91,7 @@ func NewInterfaceMIB() *InterfaceMIB {
|
|||||||
handler: &agentx.ListHandler{},
|
handler: &agentx.ListHandler{},
|
||||||
stats: make(map[uint32]*api.InterfaceCounters),
|
stats: make(map[uint32]*api.InterfaceCounters),
|
||||||
descriptions: make(map[string]string),
|
descriptions: make(map[string]string),
|
||||||
|
interfaceDetails: make(map[uint32]*vpp.InterfaceDetails),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,6 +144,22 @@ func (m *InterfaceMIB) LoadVPPConfig(configPath string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
func (m *InterfaceMIB) UpdateStats(interfaceStats *api.InterfaceStats) {
|
func (m *InterfaceMIB) UpdateStats(interfaceStats *api.InterfaceStats) {
|
||||||
m.mutex.Lock()
|
m.mutex.Lock()
|
||||||
defer m.mutex.Unlock()
|
defer m.mutex.Unlock()
|
||||||
@ -186,6 +204,9 @@ func (m *InterfaceMIB) addInterfaceToMIB(iface *api.InterfaceCounters) {
|
|||||||
func (m *InterfaceMIB) addIfEntry(iface *api.InterfaceCounters, idx int) {
|
func (m *InterfaceMIB) addIfEntry(iface *api.InterfaceCounters, idx int) {
|
||||||
var item *agentx.ListItem
|
var item *agentx.ListItem
|
||||||
|
|
||||||
|
// Get interface details if available
|
||||||
|
details := m.interfaceDetails[iface.InterfaceIndex]
|
||||||
|
|
||||||
// ifIndex (.1)
|
// ifIndex (.1)
|
||||||
item = m.handler.Add(fmt.Sprintf("%s.1.%d", ifEntryOID, idx))
|
item = m.handler.Add(fmt.Sprintf("%s.1.%d", ifEntryOID, idx))
|
||||||
item.Type = pdu.VariableTypeInteger
|
item.Type = pdu.VariableTypeInteger
|
||||||
@ -201,30 +222,58 @@ func (m *InterfaceMIB) addIfEntry(iface *api.InterfaceCounters, idx int) {
|
|||||||
item.Type = pdu.VariableTypeInteger
|
item.Type = pdu.VariableTypeInteger
|
||||||
item.Value = int32(6)
|
item.Value = int32(6)
|
||||||
|
|
||||||
// ifMtu (.4) - Default MTU 1500
|
// ifMtu (.4) - Use real MTU if available, otherwise default to 1500
|
||||||
|
mtu := int32(1500)
|
||||||
|
if details != nil {
|
||||||
|
mtu = int32(details.MTU)
|
||||||
|
}
|
||||||
item = m.handler.Add(fmt.Sprintf("%s.4.%d", ifEntryOID, idx))
|
item = m.handler.Add(fmt.Sprintf("%s.4.%d", ifEntryOID, idx))
|
||||||
item.Type = pdu.VariableTypeInteger
|
item.Type = pdu.VariableTypeInteger
|
||||||
item.Value = int32(1500)
|
item.Value = mtu
|
||||||
|
|
||||||
// ifSpeed (.5) - Default to 1Gbps (1000000000 bits/sec)
|
// ifSpeed (.5) - Use real speed if available, otherwise default to 1Gbps
|
||||||
|
speed := uint32(1000000000)
|
||||||
|
if details != nil && details.Speed > 0 {
|
||||||
|
speed = uint32(details.Speed)
|
||||||
|
}
|
||||||
item = m.handler.Add(fmt.Sprintf("%s.5.%d", ifEntryOID, idx))
|
item = m.handler.Add(fmt.Sprintf("%s.5.%d", ifEntryOID, idx))
|
||||||
item.Type = pdu.VariableTypeGauge32
|
item.Type = pdu.VariableTypeGauge32
|
||||||
item.Value = uint32(1000000000)
|
item.Value = speed
|
||||||
|
|
||||||
// ifPhysAddress (.6) - Empty for now
|
// ifPhysAddress (.6) - Use real MAC address if available
|
||||||
|
macAddr := ""
|
||||||
|
if details != nil && len(details.MacAddress) > 0 {
|
||||||
|
macAddr = string(details.MacAddress)
|
||||||
|
}
|
||||||
item = m.handler.Add(fmt.Sprintf("%s.6.%d", ifEntryOID, idx))
|
item = m.handler.Add(fmt.Sprintf("%s.6.%d", ifEntryOID, idx))
|
||||||
item.Type = pdu.VariableTypeOctetString
|
item.Type = pdu.VariableTypeOctetString
|
||||||
item.Value = ""
|
item.Value = macAddr
|
||||||
|
|
||||||
// ifAdminStatus (.7) - up(1)
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
item = m.handler.Add(fmt.Sprintf("%s.7.%d", ifEntryOID, idx))
|
item = m.handler.Add(fmt.Sprintf("%s.7.%d", ifEntryOID, idx))
|
||||||
item.Type = pdu.VariableTypeInteger
|
item.Type = pdu.VariableTypeInteger
|
||||||
item.Value = int32(1)
|
item.Value = adminStatus
|
||||||
|
|
||||||
// ifOperStatus (.8) - up(1)
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
item = m.handler.Add(fmt.Sprintf("%s.8.%d", ifEntryOID, idx))
|
item = m.handler.Add(fmt.Sprintf("%s.8.%d", ifEntryOID, idx))
|
||||||
item.Type = pdu.VariableTypeInteger
|
item.Type = pdu.VariableTypeInteger
|
||||||
item.Value = int32(1)
|
item.Value = operStatus
|
||||||
|
|
||||||
// ifLastChange (.9) - 0 (unknown)
|
// ifLastChange (.9) - 0 (unknown)
|
||||||
item = m.handler.Add(fmt.Sprintf("%s.9.%d", ifEntryOID, idx))
|
item = m.handler.Add(fmt.Sprintf("%s.9.%d", ifEntryOID, idx))
|
||||||
|
@ -40,6 +40,9 @@ func main() {
|
|||||||
log.Fatalf("Failed to start AgentX: %v", err)
|
log.Fatalf("Failed to start AgentX: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up interface event callback to update interface details
|
||||||
|
vpp.SetInterfaceEventCallback(interfaceMIB.UpdateInterfaceDetails)
|
||||||
|
|
||||||
// Start VPP stats routine with callback to update MIB
|
// Start VPP stats routine with callback to update MIB
|
||||||
vpp.StartStatsRoutine(interfaceMIB.UpdateStats)
|
vpp.StartStatsRoutine(interfaceMIB.UpdateStats)
|
||||||
|
|
||||||
|
@ -7,11 +7,73 @@ import (
|
|||||||
|
|
||||||
"go.fd.io/govpp/api"
|
"go.fd.io/govpp/api"
|
||||||
interfaces "go.fd.io/govpp/binapi/interface"
|
interfaces "go.fd.io/govpp/binapi/interface"
|
||||||
|
"go.fd.io/govpp/binapi/interface_types"
|
||||||
|
|
||||||
"govpp-snmp-agentx/logger"
|
"govpp-snmp-agentx/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
func WatchInterfaceEvents(ch api.Channel) error {
|
// InterfaceDetails holds detailed information about a VPP interface
|
||||||
|
type InterfaceDetails struct {
|
||||||
|
SwIfIndex interface_types.InterfaceIndex
|
||||||
|
InterfaceName string
|
||||||
|
MacAddress []byte
|
||||||
|
Speed uint64
|
||||||
|
AdminStatus bool
|
||||||
|
OperStatus bool
|
||||||
|
MTU uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterfaceEventCallback is called when interface events occur
|
||||||
|
type InterfaceEventCallback func(details []InterfaceDetails)
|
||||||
|
|
||||||
|
// GetAllInterfaceDetails retrieves detailed information for all interfaces
|
||||||
|
func GetAllInterfaceDetails(ch api.Channel) ([]InterfaceDetails, error) {
|
||||||
|
logger.Debugf("Retrieving all interface details from VPP")
|
||||||
|
|
||||||
|
// Get all interfaces
|
||||||
|
reqCtx := ch.SendMultiRequest(&interfaces.SwInterfaceDump{
|
||||||
|
SwIfIndex: ^interface_types.InterfaceIndex(0), // All interfaces
|
||||||
|
})
|
||||||
|
|
||||||
|
var details []InterfaceDetails
|
||||||
|
|
||||||
|
for {
|
||||||
|
iface := &interfaces.SwInterfaceDetails{}
|
||||||
|
stop, err := reqCtx.ReceiveReply(iface)
|
||||||
|
if stop {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
logger.Debugf("Error retrieving interface details: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert VPP interface flags to admin/oper status
|
||||||
|
adminUp := (iface.Flags & interface_types.IF_STATUS_API_FLAG_ADMIN_UP) != 0
|
||||||
|
operUp := (iface.Flags & interface_types.IF_STATUS_API_FLAG_LINK_UP) != 0
|
||||||
|
|
||||||
|
detail := InterfaceDetails{
|
||||||
|
SwIfIndex: iface.SwIfIndex,
|
||||||
|
InterfaceName: string(iface.InterfaceName),
|
||||||
|
MacAddress: iface.L2Address[:],
|
||||||
|
Speed: uint64(iface.LinkSpeed) * 1000, // Convert Kbps to bps
|
||||||
|
AdminStatus: adminUp,
|
||||||
|
OperStatus: operUp,
|
||||||
|
MTU: uint32(iface.LinkMtu),
|
||||||
|
}
|
||||||
|
|
||||||
|
details = append(details, detail)
|
||||||
|
|
||||||
|
logger.Debugf("Interface %d (%s): MAC=%x, Speed=%d, Admin=%t, Oper=%t, MTU=%d",
|
||||||
|
detail.SwIfIndex, detail.InterfaceName, detail.MacAddress,
|
||||||
|
detail.Speed, detail.AdminStatus, detail.OperStatus, detail.MTU)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debugf("Retrieved details for %d interfaces", len(details))
|
||||||
|
return details, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WatchInterfaceEvents(ch api.Channel, callback InterfaceEventCallback) error {
|
||||||
logger.Debugf("WatchInterfaceEvents() called - starting interface event monitoring")
|
logger.Debugf("WatchInterfaceEvents() called - starting interface event monitoring")
|
||||||
|
|
||||||
notifChan := make(chan api.Message, 100)
|
notifChan := make(chan api.Message, 100)
|
||||||
@ -64,6 +126,17 @@ func WatchInterfaceEvents(ch api.Channel) error {
|
|||||||
e := notif.(*interfaces.SwInterfaceEvent)
|
e := notif.(*interfaces.SwInterfaceEvent)
|
||||||
logger.Debugf("interface event: SwIfIndex=%d, Flags=%d, Deleted=%t",
|
logger.Debugf("interface event: SwIfIndex=%d, Flags=%d, Deleted=%t",
|
||||||
e.SwIfIndex, e.Flags, e.Deleted)
|
e.SwIfIndex, e.Flags, e.Deleted)
|
||||||
|
|
||||||
|
// When an interface event occurs, retrieve all interface details and call callback
|
||||||
|
if callback != nil {
|
||||||
|
details, err := GetAllInterfaceDetails(ch)
|
||||||
|
if err != nil {
|
||||||
|
logger.Debugf("Failed to retrieve interface details after event: %v", err)
|
||||||
|
} else {
|
||||||
|
logger.Debugf("Calling interface event callback with %d interfaces", len(details))
|
||||||
|
callback(details)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
logger.Debugf("Interface event listener goroutine ended")
|
logger.Debugf("Interface event listener goroutine ended")
|
||||||
}()
|
}()
|
||||||
|
@ -17,6 +17,9 @@ import (
|
|||||||
|
|
||||||
type StatsCallback func(*api.InterfaceStats)
|
type StatsCallback func(*api.InterfaceStats)
|
||||||
|
|
||||||
|
// Global callback for interface events
|
||||||
|
var interfaceEventCallback InterfaceEventCallback
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Flags for VPP stats configuration
|
// Flags for VPP stats configuration
|
||||||
ApiAddr = flag.String("vppstats.api.addr", "/var/run/vpp/api.sock", "VPP API socket path")
|
ApiAddr = flag.String("vppstats.api.addr", "/var/run/vpp/api.sock", "VPP API socket path")
|
||||||
@ -25,6 +28,11 @@ var (
|
|||||||
Period = flag.Int("vppstats.period", 10, "Interval in seconds for querying VPP interface stats")
|
Period = flag.Int("vppstats.period", 10, "Interval in seconds for querying VPP interface stats")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SetInterfaceEventCallback sets the callback for interface events
|
||||||
|
func SetInterfaceEventCallback(callback InterfaceEventCallback) {
|
||||||
|
interfaceEventCallback = callback
|
||||||
|
}
|
||||||
|
|
||||||
// StartStatsRoutine starts a goroutine that queries VPP interface stats at the configured interval
|
// StartStatsRoutine starts a goroutine that queries VPP interface stats at the configured interval
|
||||||
func StartStatsRoutine(callback StatsCallback) {
|
func StartStatsRoutine(callback StatsCallback) {
|
||||||
period := time.Duration(*Period) * time.Second
|
period := time.Duration(*Period) * time.Second
|
||||||
@ -139,11 +147,22 @@ func statsRoutine(period time.Duration, callback StatsCallback) {
|
|||||||
logger.Debugf("Failed to create API channel for interface events: %v", err)
|
logger.Debugf("Failed to create API channel for interface events: %v", err)
|
||||||
} else {
|
} else {
|
||||||
logger.Debugf("API channel created successfully, calling WatchInterfaceEvents...")
|
logger.Debugf("API channel created successfully, calling WatchInterfaceEvents...")
|
||||||
if err := WatchInterfaceEvents(ch); err != nil {
|
if err := WatchInterfaceEvents(ch, interfaceEventCallback); err != nil {
|
||||||
logger.Debugf("Failed to start interface event watching: %v", err)
|
logger.Debugf("Failed to start interface event watching: %v", err)
|
||||||
ch.Close()
|
ch.Close()
|
||||||
} else {
|
} else {
|
||||||
logger.Printf("Interface event watching started successfully")
|
logger.Printf("Interface event watching started successfully")
|
||||||
|
|
||||||
|
// Do initial retrieval of interface details
|
||||||
|
if interfaceEventCallback != nil {
|
||||||
|
details, err := GetAllInterfaceDetails(ch)
|
||||||
|
if err != nil {
|
||||||
|
logger.Debugf("Failed to get initial interface details: %v", err)
|
||||||
|
} else {
|
||||||
|
logger.Debugf("Retrieved initial interface details for %d interfaces", len(details))
|
||||||
|
interfaceEventCallback(details)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user