[VOL-5402]-VGC all fixes till date from jan 2024
Change-Id: I2857e0ef9b1829a28c6e3ad04da96b826cb900b6
Signed-off-by: Akash Soni <akash.soni@radisys.com>
diff --git a/internal/pkg/application/application.go b/internal/pkg/application/application.go
index c87e419..7c61725 100644
--- a/internal/pkg/application/application.go
+++ b/internal/pkg/application/application.go
@@ -203,6 +203,7 @@
// NniPort: The identity of the NNI port
// Ports: List of all ports added to the device
type VoltDevice struct {
+ VoltDeviceIntr VoltDevInterface
FlowAddEventMap *util.ConcurrentMap //map[string]*FlowEvent
FlowDelEventMap *util.ConcurrentMap //map[string]*FlowEvent
MigratingServices *util.ConcurrentMap //<vnetID,<RequestID, MigrateServicesRequest>>
@@ -222,7 +223,6 @@
NniDhcpTrapVid of.VlanType
GlobalDhcpFlowAdded bool
icmpv6GroupAdded bool
- VoltDeviceIntr VoltDevInterface
}
type VoltDevInterface interface {
@@ -459,8 +459,8 @@
IgmpPendingPool map[string]map[*IgmpGroup]bool //[grpkey, map[groupObj]bool] //mvlan_grpName/IP
macPortMap map[string]string
VnetsToDelete map[string]bool
- ServicesToDelete map[string]bool
- ServicesToDeactivate map[string]bool
+ ServicesToDelete sync.Map
+ ServicesToDeactivate sync.Map
PortAlarmProfileCache map[string]map[string]int // [portAlarmID][ThresholdLevelString]ThresholdLevel
vendorID string
ServiceByName sync.Map // [serName]*VoltService
@@ -700,8 +700,6 @@
va.IgmpPendingPool = make(map[string]map[*IgmpGroup]bool)
va.VnetsBySvlan = util.NewConcurrentMap()
va.VnetsToDelete = make(map[string]bool)
- va.ServicesToDelete = make(map[string]bool)
- va.ServicesToDeactivate = make(map[string]bool)
va.VoltPortVnetsToDelete = make(map[*VoltPortVnet]bool)
go va.Start(context.Background(), TimerCfg{tick: 100 * time.Millisecond}, tickTimer)
go va.Start(context.Background(), TimerCfg{tick: time.Duration(GroupExpiryTime) * time.Minute}, pendingPoolTimer)
@@ -926,6 +924,21 @@
}
}
+// CheckServiceExists to check if service exists for the given uniport and tech profile ID.
+func (va *VoltApplication) CheckServiceExists(port string, techProfID uint16) bool {
+ var serviceExists bool
+ va.ServiceByName.Range(func(key, existingServiceIntf interface{}) bool {
+ existingService := existingServiceIntf.(*VoltService)
+ if existingService.Port == port && existingService.TechProfileID == techProfID {
+ logger.Warnw(ctx, "Service already exists for same Port and TP. Ignoring add service request", log.Fields{"ExistingService": existingService.Name})
+ serviceExists = true
+ return false
+ }
+ return true
+ })
+ return serviceExists
+}
+
// GetDeviceBySerialNo to get a device by serial number.
// TODO - Transform this into a MAP instead
func (va *VoltApplication) GetDeviceBySerialNo(slno string) (*VoltDevice, string) {
@@ -1772,35 +1785,60 @@
}
}
-// IsFlowDelThresholdReached - check if the attempts for flow delete has reached threshold or not
-func (va *VoltApplication) IsFlowDelThresholdReached(cntx context.Context, cookie string, device string) bool {
- logger.Debugw(ctx, "Check flow delete threshold", log.Fields{"Cookie": cookie, "Device": device})
- d := va.GetDevice(device)
- if d == nil {
- logger.Warnw(ctx, "Failed to get device during flow delete threshold check", log.Fields{"Cookie": cookie, "Device": device})
- return false
+// CheckAndDeactivateService - check if the attempts for flow delete has reached threshold or not
+func (va *VoltApplication) CheckAndDeactivateService(ctx context.Context, flow *of.VoltSubFlow, devSerialNum string, devID string) {
+ logger.Debugw(ctx, "Check and Deactivate service", log.Fields{"Cookie": flow.Cookie, "FlowCount": flow.FlowCount, "DeviceSerial": devSerialNum})
+ if flow.FlowCount >= controller.GetController().GetMaxFlowRetryAttempt() {
+ devConfig := va.GetDeviceConfig(devSerialNum)
+ if devConfig != nil {
+ portNo := util.GetUniPortFromFlow(devConfig.UplinkPort, flow)
+ portName, err := va.GetPortName(portNo)
+ if err != nil {
+ logger.Warnw(ctx, "Error getting port name", log.Fields{"Reason": err.Error(), "PortID": portNo})
+ return
+ } else if portName == "" {
+ logger.Warnw(ctx, "Port does not exist", log.Fields{"PortID": portNo})
+ return
+ }
+ svc := va.GetServiceNameFromCookie(flow.Cookie, portName, uint8(of.PbitMatchNone), devID, flow.Match.TableMetadata)
+ if svc != nil {
+ va.DeactivateServiceForPort(ctx, svc, devID, portName)
+ }
+ }
}
+}
- flowEventMap, err := d.GetFlowEventRegister(of.CommandDel)
- if err != nil {
- logger.Warnw(ctx, "Flow event map does not exists", log.Fields{"flowMod": of.CommandDel, "Error": err})
- return false
+// DeactivateServiceForPort - deactivate service for given UNI and remove flows from DB, after max flow install threshold has reached
+func (va *VoltApplication) DeactivateServiceForPort(cntx context.Context, vs *VoltService, devID string, portName string) {
+ logger.Debugw(ctx, "Flow install threshold reached. Deactivating service", log.Fields{"Service": vs.Name, "Port": portName})
+
+ if devID == vs.Device && portName == vs.Port && vs.IsActivated {
+ vs.SetSvcDeactivationFlags(SvcDeacRsn_Controller)
+ va.ServiceByName.Store(vs.Name, vs)
+ vs.WriteToDb(cntx)
+ device, err := va.GetDeviceFromPort(portName)
+ if err != nil {
+ // Even if the port/device does not exists at this point in time, the deactivate request is succss.
+ // So no error is returned
+ logger.Warnw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portName})
+ }
+ p := device.GetPort(vs.Port)
+ if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable) {
+ if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
+ // Port down call internally deletes all the flows
+ vpv.PortDownInd(cntx, device.Name, portName, true, true)
+ if vpv.IgmpEnabled {
+ va.ReceiverDownInd(cntx, device.Name, portName)
+ }
+ } else {
+ logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": device.Name, "port": portName, "SvcName": vs.Name})
+ }
+ logger.Infow(ctx, "Service deactivated after flow install threshold", log.Fields{"Device": device.Name, "Service": vs.Name, "Port": portName})
+ }
+ vs.DeactivateInProgress = false
+ va.ServiceByName.Store(vs.Name, vs)
+ vs.WriteToDb(cntx)
}
- flowEventMap.MapLock.Lock()
- var event interface{}
- if event, _ = flowEventMap.Get(cookie); event == nil {
- logger.Warnw(ctx, "Event does not exist during flow delete threshold check", log.Fields{"Cookie": cookie})
- flowEventMap.MapLock.Unlock()
- return false
- }
- flowEventMap.MapLock.Unlock()
- flowEvent := event.(*FlowEvent)
- if vs, ok := flowEvent.eventData.(*VoltService); ok {
- vs.ServiceLock.RLock()
- defer vs.ServiceLock.RUnlock()
- return vs.FlowPushCount[cookie] == controller.GetController().GetMaxFlowRetryAttempt()
- }
- return false
}
func pushFlowFailureNotif(flowStatus intf.FlowStatus) {
@@ -2131,46 +2169,51 @@
// TriggerPendingServiceDeactivateReq - trigger pending service deactivate request
func (va *VoltApplication) TriggerPendingServiceDeactivateReq(cntx context.Context, device string) {
- logger.Infow(ctx, "Pending Services to be deactivated", log.Fields{"Count": len(va.ServicesToDeactivate)})
- for serviceName := range va.ServicesToDeactivate {
- logger.Debugw(ctx, "Trigger Service Deactivate", log.Fields{"Service": serviceName})
+ va.ServicesToDeactivate.Range(func(key, value interface{}) bool {
+ serviceName := key.(string)
if vs := va.GetService(serviceName); vs != nil {
if vs.Device == device {
logger.Infow(ctx, "Triggering Pending Service Deactivate", log.Fields{"Service": vs.Name})
vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
if vpv == nil {
logger.Warnw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name, "port": vs.Port, "Vnet": vs.VnetID})
- continue
+ return true
}
-
vpv.DelTrapFlows(cntx)
vs.DelHsiaFlows(cntx)
+ // Set the flag to false and clear the SevicesToDeactivate map entry so that when core restarts, VGC will not
+ // try to deactivate the service again
+ vs.DeactivateInProgress = false
+ va.ServicesToDeactivate.Delete(serviceName)
vs.WriteToDb(cntx)
vpv.ClearServiceCounters(cntx)
}
} else {
- logger.Warnw(ctx, "Pending Service Not found", log.Fields{"Service": serviceName})
+ logger.Warnw(ctx, "Pending Service Not found during Deactivate", log.Fields{"Service": serviceName})
}
- }
+ return true
+ })
}
// TriggerPendingServiceDeleteReq - trigger pending service delete request
func (va *VoltApplication) TriggerPendingServiceDeleteReq(cntx context.Context, device string) {
- logger.Infow(ctx, "Pending Services to be deleted", log.Fields{"Count": len(va.ServicesToDelete)})
- for serviceName := range va.ServicesToDelete {
- logger.Debugw(ctx, "Trigger Service Delete", log.Fields{"Service": serviceName})
+ va.ServicesToDelete.Range(func(key, value interface{}) bool {
+ serviceName := key.(string)
if vs := va.GetService(serviceName); vs != nil {
if vs.Device == device {
logger.Infow(ctx, "Triggering Pending Service delete", log.Fields{"Service": vs.Name})
vs.DelHsiaFlows(cntx)
+ // Clear the SevicesToDelete map so that when core restarts, VGC will not try to deactivate the service again
+ va.ServicesToDelete.Delete(serviceName)
if vs.ForceDelete {
vs.DelFromDb(cntx)
}
}
} else {
- logger.Warnw(ctx, "Pending Service Not found", log.Fields{"Service": serviceName})
+ logger.Warnw(ctx, "Pending Service Not found during Delete", log.Fields{"Service": serviceName})
}
- }
+ return true
+ })
}
// TriggerPendingVpvDeleteReq - trigger pending VPV delete request