First Commit of Voltha-Go-Controller from Radisys

Change-Id: I8e2e908e7ab09a4fe3d86849da18b6d69dcf4ab0
diff --git a/internal/pkg/application/flowevent.go b/internal/pkg/application/flowevent.go
new file mode 100644
index 0000000..4fe1a0a
--- /dev/null
+++ b/internal/pkg/application/flowevent.go
@@ -0,0 +1,192 @@
+/*
+* 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 (
+	infraerrorcode "voltha-go-controller/internal/pkg/errorcodes/service"
+
+	"voltha-go-controller/internal/pkg/intf"
+	"github.com/opencord/voltha-lib-go/v7/pkg/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(*FlowEvent, intf.FlowStatus)
+
+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 {
+	eType     FlowEventType
+	device    string
+	cookie    string
+	eventData interface{}
+}
+
+//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(vd *VoltDevice, cookie string, flowStatus intf.FlowStatus) bool {
+	var event interface{}
+
+	flowEventMap, err := vd.GetFlowEventRegister(flowStatus.FlowModType)
+	if err != nil {
+		logger.Debugw(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.Remove(cookie)
+	flowEventMap.MapLock.Unlock()
+	flowEvent := event.(*FlowEvent)
+	eventMapper[flowEvent.eType](flowEvent, flowStatus)
+	return true
+}
+
+//ProcessUsIgmpFlowAddEvent - Process Us Igmp Flow event trigger
+func ProcessUsIgmpFlowAddEvent(event *FlowEvent, flowStatus intf.FlowStatus) {
+
+	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(event *FlowEvent, flowStatus intf.FlowStatus) {
+
+	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(event.cookie, flowStatus.AdditionalData)
+	} else {
+		vs.FlowInstallFailure(event.cookie, flowStatus.Status, flowStatus.Reason)
+	}
+}
+
+//ProcessControlFlowAddEvent - Process Control Flow event trigger
+func ProcessControlFlowAddEvent(event *FlowEvent, flowStatus intf.FlowStatus) {
+
+	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(event *FlowEvent, flowStatus intf.FlowStatus) {
+
+	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(event.cookie)
+	} else {
+		vs.FlowRemoveFailure(event.cookie, flowStatus.Status, flowStatus.Reason)
+	}
+}
+
+//ProcessControlFlowDelEvent - Process Control Flow event trigger
+func ProcessControlFlowDelEvent(event *FlowEvent, flowStatus intf.FlowStatus) {
+
+	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(event.cookie, event.device)
+	} else {
+		vpv.FlowRemoveFailure(event.cookie, event.device, flowStatus.Status, flowStatus.Reason)
+	}
+}
+
+//ProcessMcastFlowDelEvent - Process Control Flow event trigger
+func ProcessMcastFlowDelEvent(event *FlowEvent, flowStatus intf.FlowStatus) {
+
+	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(event.cookie, event.device)
+	} else {
+		mvp.FlowRemoveFailure(event.cookie, event.device, flowStatus.Status, flowStatus.Reason)
+	}
+}
+
+//ProcessDeviceFlowDelEvent - Process Control Flow event trigger
+func ProcessDeviceFlowDelEvent(event *FlowEvent, flowStatus intf.FlowStatus) {
+
+	logger.Infow(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(event.cookie, event.device)
+	} else {
+		vnet.FlowRemoveFailure(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 {
+	result := false
+	errorCode := infraerrorcode.ErrorCode(status)
+
+	if errorCode == infraerrorcode.ErrOk {
+		result = true
+	} else if !flowAdd && errorCode == infraerrorcode.ErrNotExists {
+		result = true
+	}
+	return result
+}