| /* |
| * Copyright 2022-present Open Networking Foundation |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package application |
| |
| import ( |
| "context" |
| |
| infraerrorcode "voltha-go-controller/internal/pkg/errorcodes/service" |
| "voltha-go-controller/internal/pkg/util" |
| |
| "voltha-go-controller/internal/pkg/intf" |
| "voltha-go-controller/log" |
| ) |
| |
| // Generic Framework to enabling all flow based event trigger and handling. |
| // The eventMapper can be updated for dynamic func caller for future events |
| |
| // FlowEventType - Type of event enumeration |
| type FlowEventType string |
| |
| // FlowEventHandler - Func prototype for flow event handling funcs |
| type FlowEventHandler func(context.Context, *FlowEvent, intf.FlowStatus, *util.ConcurrentMap) |
| |
| var eventMapper map[FlowEventType]FlowEventHandler |
| |
| const ( |
| // EventTypeUsIgmpFlowAdded - Event type for IGMP US flow add |
| EventTypeUsIgmpFlowAdded FlowEventType = "USIgmpFlowAdded" |
| // EventTypeServiceFlowAdded - Event type for Service flow add |
| EventTypeServiceFlowAdded FlowEventType = "ServiceFlowAdded" |
| // EventTypeControlFlowAdded - Event type for Control flow add |
| EventTypeControlFlowAdded FlowEventType = "ControlFlowAdded" |
| |
| // EventTypeDeviceFlowRemoved - Event type for Device flow del |
| EventTypeDeviceFlowRemoved FlowEventType = "DeviceFlowRemoved" |
| // EventTypeMcastFlowRemoved - Event type for Mcast flow del |
| EventTypeMcastFlowRemoved FlowEventType = "McastFlowRemoved" |
| |
| // EventTypeServiceFlowRemoved - Event type for Service flow del |
| EventTypeServiceFlowRemoved FlowEventType = "ServiceFlowRemoved" |
| // EventTypeControlFlowRemoved - Event type for Control flow del |
| EventTypeControlFlowRemoved FlowEventType = "ControlFlowRemoved" |
| ) |
| |
| // FlowEvent - Event info for Flow event processing |
| type FlowEvent struct { |
| eventData interface{} |
| device string |
| cookie string |
| eType FlowEventType |
| } |
| |
| // InitEventFuncMapper - Initialization of flow event mapper |
| func InitEventFuncMapper() { |
| eventMapper = map[FlowEventType]FlowEventHandler{ |
| EventTypeUsIgmpFlowAdded: ProcessUsIgmpFlowAddEvent, |
| EventTypeControlFlowAdded: ProcessControlFlowAddEvent, |
| EventTypeServiceFlowAdded: ProcessServiceFlowAddEvent, |
| EventTypeControlFlowRemoved: ProcessControlFlowDelEvent, |
| EventTypeServiceFlowRemoved: ProcessServiceFlowDelEvent, |
| EventTypeDeviceFlowRemoved: ProcessDeviceFlowDelEvent, |
| EventTypeMcastFlowRemoved: ProcessMcastFlowDelEvent, |
| } |
| } |
| |
| // ExecuteFlowEvent - Process flow based event triggers |
| func ExecuteFlowEvent(cntx context.Context, vd *VoltDevice, cookie string, flowStatus intf.FlowStatus) bool { |
| logger.Debugw(ctx, "Execute Flow event", log.Fields{"Cookie": cookie, "flowMod": flowStatus.FlowModType}) |
| var event interface{} |
| |
| flowEventMap, err := vd.GetFlowEventRegister(flowStatus.FlowModType) |
| if err != nil { |
| logger.Warnw(ctx, "Flow event map does not exists", log.Fields{"flowMod": flowStatus.FlowModType, "Error": err}) |
| return false |
| } |
| flowEventMap.MapLock.Lock() |
| |
| if event, _ = flowEventMap.Get(cookie); event == nil { |
| logger.Debugw(ctx, "Event already processed or event not registered for the cookie", log.Fields{"Cookie": cookie}) |
| flowEventMap.MapLock.Unlock() |
| return false |
| } |
| flowEventMap.MapLock.Unlock() |
| flowEvent := event.(*FlowEvent) |
| if flowEvent.eType != EventTypeServiceFlowAdded && flowEvent.eType != EventTypeServiceFlowRemoved { |
| flowEventMap.MapLock.Lock() |
| flowEventMap.Remove(cookie) |
| flowEventMap.MapLock.Unlock() |
| } |
| eventMapper[flowEvent.eType](cntx, flowEvent, flowStatus, flowEventMap) |
| return true |
| } |
| |
| // ProcessUsIgmpFlowAddEvent - Process Us Igmp Flow event trigger |
| func ProcessUsIgmpFlowAddEvent(cntx context.Context, event *FlowEvent, flowStatus intf.FlowStatus, flowEventMap *util.ConcurrentMap) { |
| logger.Infow(ctx, "Processing Post Flow Add Event for US Igmp", log.Fields{"Cookie": event.cookie, "event": event}) |
| vpv := event.eventData.(*VoltPortVnet) |
| if isFlowStatusSuccess(flowStatus.Status, true) { |
| vpv.services.Range(ReceiverUpInd) |
| } else { |
| vpv.IgmpFlowInstallFailure(event.cookie, flowStatus.Status, flowStatus.Reason) |
| } |
| } |
| |
| // ProcessServiceFlowAddEvent - Process Service Flow event trigger |
| func ProcessServiceFlowAddEvent(cntx context.Context, event *FlowEvent, flowStatus intf.FlowStatus, flowEventMap *util.ConcurrentMap) { |
| logger.Infow(ctx, "Processing Post Flow Add Event for Service", log.Fields{"Cookie": event.cookie, "event": event}) |
| vs := event.eventData.(*VoltService) |
| if isFlowStatusSuccess(flowStatus.Status, true) { |
| vs.FlowInstallSuccess(cntx, event.cookie, flowStatus.AdditionalData, flowEventMap) |
| } else { |
| vs.FlowInstallFailure(cntx, event.cookie, flowStatus.Status, flowStatus.Reason, flowEventMap) |
| } |
| } |
| |
| // ProcessControlFlowAddEvent - Process Control Flow event trigger |
| func ProcessControlFlowAddEvent(cntx context.Context, event *FlowEvent, flowStatus intf.FlowStatus, flowEventMap *util.ConcurrentMap) { |
| logger.Infow(ctx, "Processing Post Flow Add Event for VPV", log.Fields{"Cookie": event.cookie, "event": event}) |
| vpv := event.eventData.(*VoltPortVnet) |
| if !isFlowStatusSuccess(flowStatus.Status, true) { |
| vpv.FlowInstallFailure(event.cookie, flowStatus.Status, flowStatus.Reason) |
| } |
| } |
| |
| // ProcessServiceFlowDelEvent - Process Service Flow event trigger |
| func ProcessServiceFlowDelEvent(cntx context.Context, event *FlowEvent, flowStatus intf.FlowStatus, flowEventMap *util.ConcurrentMap) { |
| logger.Infow(ctx, "Processing Post Flow Remove Event for Service", log.Fields{"Cookie": event.cookie, "event": event}) |
| vs := event.eventData.(*VoltService) |
| if isFlowStatusSuccess(flowStatus.Status, false) { |
| vs.FlowRemoveSuccess(cntx, event.cookie, flowEventMap) |
| } else { |
| vs.FlowRemoveFailure(cntx, event.cookie, flowStatus.Status, flowStatus.Reason, flowEventMap) |
| } |
| } |
| |
| // ProcessControlFlowDelEvent - Process Control Flow event trigger |
| func ProcessControlFlowDelEvent(cntx context.Context, event *FlowEvent, flowStatus intf.FlowStatus, flowEventMap *util.ConcurrentMap) { |
| logger.Infow(ctx, "Processing Post Flow Remove Event for VPV", log.Fields{"Cookie": event.cookie, "event": event}) |
| vpv := event.eventData.(*VoltPortVnet) |
| if isFlowStatusSuccess(flowStatus.Status, false) { |
| vpv.FlowRemoveSuccess(cntx, event.cookie, event.device) |
| } else { |
| vpv.FlowRemoveFailure(cntx, event.cookie, event.device, flowStatus.Status, flowStatus.Reason) |
| } |
| } |
| |
| // ProcessMcastFlowDelEvent - Process Control Flow event trigger |
| func ProcessMcastFlowDelEvent(cntx context.Context, event *FlowEvent, flowStatus intf.FlowStatus, flowEventMap *util.ConcurrentMap) { |
| logger.Infow(ctx, "Processing Post Flow Remove Event for Mcast/Igmp", log.Fields{"Cookie": event.cookie, "event": event}) |
| mvp := event.eventData.(*MvlanProfile) |
| if isFlowStatusSuccess(flowStatus.Status, false) { |
| mvp.FlowRemoveSuccess(cntx, event.cookie, event.device) |
| } else { |
| mvp.FlowRemoveFailure(event.cookie, event.device, flowStatus.Status, flowStatus.Reason) |
| } |
| } |
| |
| // ProcessDeviceFlowDelEvent - Process Control Flow event trigger |
| func ProcessDeviceFlowDelEvent(cntx context.Context, event *FlowEvent, flowStatus intf.FlowStatus, flowEventMap *util.ConcurrentMap) { |
| logger.Debugw(ctx, "Processing Post Flow Remove Event for VNET", log.Fields{"Cookie": event.cookie, "event": event}) |
| vnet := event.eventData.(*VoltVnet) |
| if isFlowStatusSuccess(flowStatus.Status, false) { |
| vnet.FlowRemoveSuccess(cntx, event.cookie, event.device) |
| } else { |
| vnet.FlowRemoveFailure(cntx, event.cookie, event.device, flowStatus.Status, flowStatus.Reason) |
| } |
| } |
| |
| // TODO: Update the func or flowStatus struct once all flow status are based on NB error code |
| func isFlowStatusSuccess(status uint32, flowAdd bool) bool { |
| logger.Infow(ctx, "Processing isFlowStatusSuccess", log.Fields{"Status": status, "FlowAdd": flowAdd}) |
| result := false |
| errorCode := infraerrorcode.ErrorCode(status) |
| |
| if errorCode == infraerrorcode.ErrOk { |
| result = true |
| } else if !flowAdd && errorCode == infraerrorcode.ErrNotExists { |
| result = true |
| } |
| return result |
| } |