Merge "Bug 8859 : Table 220 programmed with wrong service-index"
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / servicebindings / flowbased / utilities / FlowBasedServicesUtils.java
index a686e8ccc4a6aa5a96018d0f1ceb549dbf5380b1..4beb1586b88124bb97992037397fb19887e9f6bf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -13,6 +13,7 @@ import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import org.apache.commons.lang3.StringUtils;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -21,16 +22,17 @@ import org.opendaylight.genius.interfacemanager.IfmUtil;
 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
-import org.opendaylight.genius.mdsalutil.InstructionType;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
-import org.opendaylight.genius.mdsalutil.MatchFieldType;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
-import org.opendaylight.genius.mdsalutil.NxMatchFieldType;
-import org.opendaylight.genius.mdsalutil.NxMatchInfo;
 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
+import org.opendaylight.genius.mdsalutil.matches.MatchInPort;
+import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
+import org.opendaylight.genius.mdsalutil.matches.MatchVlanVid;
+import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
 import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
@@ -47,6 +49,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternal;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.SplitHorizon;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.BoundServicesStateList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
@@ -54,6 +57,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.ser
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.bound.services.state.list.BoundServicesState;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.bound.services.state.list.BoundServicesStateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.bound.services.state.list.BoundServicesStateKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
@@ -65,54 +71,59 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class FlowBasedServicesUtils {
     private static final Logger LOG = LoggerFactory.getLogger(FlowBasedServicesUtils.class);
+    private static final int DEFAULT_DISPATCHER_PRIORITY = 10;
 
-    public enum ServiceMode  {
-        INGRESS,
-        EGRESS
+    public enum ServiceMode {
+        INGRESS, EGRESS
     }
 
-    public static final ImmutableBiMap SERVICE_MODE_MAP =
-            new ImmutableBiMap.Builder<ServiceMode, Class<? extends ServiceModeBase>>()
-                    .put(ServiceMode.EGRESS, ServiceModeEgress.class)
-                    .put(ServiceMode.INGRESS, ServiceModeIngress.class)
-                    .build();
+    public static final ImmutableBiMap<ServiceMode, Class<? extends ServiceModeBase>>
+        SERVICE_MODE_MAP = new ImmutableBiMap.Builder<ServiceMode, Class<? extends ServiceModeBase>>()
+            .put(ServiceMode.EGRESS, ServiceModeEgress.class).put(ServiceMode.INGRESS, ServiceModeIngress.class)
+            .build();
 
-    public static ServicesInfo getServicesInfoForInterface(String interfaceName, Class<? extends ServiceModeBase> serviceMode,
-                                                           DataBroker dataBroker) {
-        ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName,serviceMode);
-        InstanceIdentifier.InstanceIdentifierBuilder<ServicesInfo> servicesInfoIdentifierBuilder =
-                InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey);
-        return IfmUtil.read(LogicalDatastoreType.CONFIGURATION, servicesInfoIdentifierBuilder.build(),
-                dataBroker).orNull();
+    public static ServicesInfo getServicesInfoForInterface(String interfaceName,
+            Class<? extends ServiceModeBase> serviceMode, DataBroker dataBroker) {
+        ServicesInfoKey servicesInfoKey = new ServicesInfoKey(interfaceName, serviceMode);
+        InstanceIdentifier.InstanceIdentifierBuilder<ServicesInfo> servicesInfoIdentifierBuilder = InstanceIdentifier
+                .builder(ServiceBindings.class).child(ServicesInfo.class, servicesInfoKey);
+        return IfmUtil.read(LogicalDatastoreType.CONFIGURATION, servicesInfoIdentifierBuilder.build(), dataBroker)
+                .orNull();
     }
 
     public static NodeConnectorId getNodeConnectorIdFromInterface(String interfaceName, DataBroker dataBroker) {
-        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState =
-                InterfaceManagerCommonUtils.getInterfaceStateFromOperDS(interfaceName, dataBroker);
-        if(ifState != null) {
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
+            .ietf.interfaces.rev140508.interfaces.state.Interface ifState = InterfaceManagerCommonUtils
+                .getInterfaceState(interfaceName, dataBroker);
+        if (ifState != null) {
             List<String> ofportIds = ifState.getLowerLayerIf();
             return new NodeConnectorId(ofportIds.get(0));
         }
         return null;
     }
 
-    public static NodeConnectorId getNodeConnectorIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
-        if(ifState != null) {
+    public static NodeConnectorId getNodeConnectorIdFromInterface(
+            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
+                .ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
+        if (ifState != null) {
             List<String> ofportIds = ifState.getLowerLayerIf();
             return new NodeConnectorId(ofportIds.get(0));
         }
         return null;
     }
 
-    public static BigInteger getDpnIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
+    public static BigInteger getDpnIdFromInterface(
+            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
+                .ietf.interfaces.rev140508.interfaces.state.Interface ifState) {
         NodeConnectorId nodeConnectorId = null;
-        if(ifState != null) {
+        if (ifState != null) {
             List<String> ofportIds = ifState.getLowerLayerIf();
             nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
         }
@@ -121,69 +132,67 @@ public class FlowBasedServicesUtils {
 
     public static List<MatchInfo> getMatchInfoForVlanPortAtIngressTable(BigInteger dpId, long portNo, Interface iface) {
         List<MatchInfo> matches = new ArrayList<>();
-        matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[] {dpId, BigInteger.valueOf(portNo)}));
+        matches.add(new MatchInPort(dpId, portNo));
         int vlanId = 0;
         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
-        if(l2vlan != null && l2vlan.getL2vlanMode() != IfL2vlan.L2vlanMode.Transparent){
+        if (l2vlan != null) {
             vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
         }
-        if (vlanId > 0) {
-            matches.add(new MatchInfo(MatchFieldType.vlan_vid, new long[]{vlanId}));
+        if (vlanId >= 0  && l2vlan.getL2vlanMode() != IfL2vlan.L2vlanMode.Transparent) {
+            matches.add(new MatchVlanVid(vlanId));
         }
         return matches;
     }
 
     public static List<MatchInfo> getMatchInfoForTunnelPortAtIngressTable(BigInteger dpId, long portNo) {
         List<MatchInfo> matches = new ArrayList<>();
-        matches.add(new MatchInfo(MatchFieldType.in_port, new BigInteger[]{dpId, BigInteger.valueOf(portNo)}));
+        matches.add(new MatchInPort(dpId, portNo));
         return matches;
     }
 
-    public static List<MatchInfo> getMatchInfoForDispatcherTable(BigInteger dpId,
-                                                                 int interfaceTag, short servicePriority) {
+    public static List<MatchInfo> getMatchInfoForDispatcherTable(BigInteger dpId, int interfaceTag,
+            short servicePriority) {
         List<MatchInfo> matches = new ArrayList<>();
-        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
-                MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority),
-                MetaDataUtil.getMetaDataMaskForLPortDispatcher() }));
+        matches.add(new MatchMetadata(MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, servicePriority),
+                MetaDataUtil.getMetaDataMaskForLPortDispatcher()));
         return matches;
     }
 
     public static List<MatchInfoBase> getMatchInfoForEgressDispatcherTable(int interfaceTag, short serviceIndex) {
         List<MatchInfoBase> matches = new ArrayList<>();
-        matches.add(new NxMatchInfo(NxMatchFieldType.nxm_reg_6, new long[] {
-                MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, serviceIndex)}));
+        matches.add(new NxMatchRegister(NxmNxReg6.class,
+                MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, serviceIndex)));
         return matches;
     }
 
-    public static void installInterfaceIngressFlow(BigInteger dpId, Interface iface,
-                                                   BoundServices boundServiceNew,
-                                                   WriteTransaction t,
-                                                   List<MatchInfo> matches, int lportTag, short tableId) {
+    public static void installInterfaceIngressFlow(BigInteger dpId, Interface iface, BoundServices boundServiceNew,
+            WriteTransaction writeTransaction, List<MatchInfo> matches, int lportTag, short tableId) {
         List<Instruction> instructions = boundServiceNew.getAugmentation(StypeOpenflow.class).getInstruction();
 
         int serviceInstructionsSize = instructions.size();
         List<Instruction> instructionSet = new ArrayList<>();
         int vlanId = 0;
         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
-        if(l2vlan != null && l2vlan.getVlanId() != null){
+        if (l2vlan != null && l2vlan.getVlanId() != null) {
             vlanId = l2vlan.getVlanId().getValue();
         }
         if (vlanId != 0) {
-            // incrementing instructionSize and using it as actionKey. Because it won't clash with any other instructions
+            // incrementing instructionSize and using it as actionKey. Because
+            // it won't clash with any other instructions
             int actionKey = ++serviceInstructionsSize;
             instructionSet.add(MDSALUtil.buildAndGetPopVlanActionInstruction(actionKey, ++serviceInstructionsSize));
         }
 
         if (lportTag != 0L) {
             BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(instructions);
-            short sIndex = boundServiceNew.getServicePriority();
-            BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag,
-                    ++sIndex, metadataValues[0], isExternal(iface));
+            short index = boundServiceNew.getServicePriority();
+            BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, ++index, metadataValues[0],
+                    isExternal(iface));
             BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(
-                    MetaDataUtil.METADATA_MASK_SERVICE_INDEX,
-                    MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG, metadataValues[1]);
-            instructionSet.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask,
-                    ++serviceInstructionsSize));
+                    MetaDataUtil.METADATA_MASK_SERVICE_INDEX, MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG,
+                    metadataValues[1]);
+            instructionSet.add(
+                    MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++serviceInstructionsSize));
         }
 
         if (instructions != null && !instructions.isEmpty()) {
@@ -193,10 +202,10 @@ public class FlowBasedServicesUtils {
                     continue;
                 } else if (info.getInstruction() instanceof WriteActionsCase) {
                     info = MDSALUtil.buildWriteActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
-                        ((WriteActionsCase)info.getInstruction()).getWriteActions().getAction()));
+                            ((WriteActionsCase) info.getInstruction()).getWriteActions().getAction()));
                 } else if (info.getInstruction() instanceof ApplyActionsCase) {
                     info = MDSALUtil.buildApplyActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
-                        ((ApplyActionsCase)info.getInstruction()).getApplyActions().getAction()));
+                            ((ApplyActionsCase) info.getInstruction()).getApplyActions().getAction()));
                 }
                 instructionSet.add(info);
             }
@@ -206,31 +215,19 @@ public class FlowBasedServicesUtils {
         String flowRef = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, iface.getName(),
                 boundServiceNew, boundServiceNew.getServicePriority());
         StypeOpenflow stypeOpenflow = boundServiceNew.getAugmentation(StypeOpenflow.class);
-        Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, flowRef,
-                stypeOpenflow.getFlowPriority(), serviceRef, 0, 0,
+        Flow ingressFlow = MDSALUtil.buildFlowNew(tableId, flowRef, stypeOpenflow.getFlowPriority(), serviceRef, 0, 0,
                 stypeOpenflow.getFlowCookie(), matches, instructionSet);
-        installFlow(dpId, ingressFlow, t);
+        installFlow(dpId, ingressFlow, writeTransaction);
     }
 
-    public static void installFlow(BigInteger dpId, Flow flow, WriteTransaction t) {
+    public static void installFlow(BigInteger dpId, Flow flow, WriteTransaction writeTransaction) {
         FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
         Node nodeDpn = buildInventoryDpnNode(dpId);
         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
-                .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class,flowKey).build();
+                .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
 
-        t.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
-    }
-
-    public static void removeFlow(String flowRef, BigInteger dpId, WriteTransaction t) {
-        LOG.debug("Removing Ingress Flows");
-        FlowKey flowKey = new FlowKey(new FlowId(flowRef));
-        Node nodeDpn = buildInventoryDpnNode(dpId);
-        InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
-                .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
-                .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
-
-        t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
+        writeTransaction.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
     }
 
     private static Node buildInventoryDpnNode(BigInteger dpnId) {
@@ -241,17 +238,19 @@ public class FlowBasedServicesUtils {
     }
 
     public static void installLPortDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
-                                                  WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
-        LOG.debug("Installing LPort Dispatcher Flow {}, {}", dpId, interfaceName);
+            WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
         String serviceRef = boundService.getServiceName();
-        List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, interfaceTag, currentServiceIndex);
+        List<MatchInfo> matches = FlowBasedServicesUtils.getMatchInfoForDispatcherTable(dpId, interfaceTag,
+                currentServiceIndex);
 
-        // Get the metadata and mask from the service's write metadata instruction
+        // Get the metadata and mask from the service's write metadata
+        // instruction
         StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
         List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
         int instructionSize = serviceInstructions.size();
         BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
-        BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex, metadataValues[0]);
+        BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex,
+                metadataValues[0]);
         BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable();
 
         // build the final instruction for LPort Dispatcher table flow entry
@@ -264,80 +263,106 @@ public class FlowBasedServicesUtils {
                     continue;
                 } else if (info.getInstruction() instanceof WriteActionsCase) {
                     info = MDSALUtil.buildWriteActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
-                        ((WriteActionsCase)info.getInstruction()).getWriteActions().getAction()));
+                            ((WriteActionsCase) info.getInstruction()).getWriteActions().getAction()));
                 } else if (info.getInstruction() instanceof ApplyActionsCase) {
                     info = MDSALUtil.buildApplyActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
-                        ((ApplyActionsCase)info.getInstruction()).getApplyActions().getAction()));
+                            ((ApplyActionsCase) info.getInstruction()).getApplyActions().getAction()));
                 }
                 instructions.add(info);
             }
         }
 
         // build the flow and install it
-        String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, interfaceName, boundService, currentServiceIndex);
+        String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, interfaceName,
+            boundService, currentServiceIndex);
         Flow ingressFlow = MDSALUtil.buildFlowNew(NwConstants.LPORT_DISPATCHER_TABLE, flowRef,
-                boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
-        installFlow(dpId, ingressFlow, t);
+                DEFAULT_DISPATCHER_PRIORITY, serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches,
+                instructions);
+        LOG.debug("Installing LPort Dispatcher Flow on DPN {}, for interface {}, with flowRef {}", dpId,
+            interfaceName, flowRef);
+        installFlow(dpId, ingressFlow, writeTransaction);
     }
 
     public static void installEgressDispatcherFlows(BigInteger dpId, BoundServices boundService, String interfaceName,
-                                                  WriteTransaction t, int interfaceTag, short currentServiceIndex,
-                                                  short nextServiceIndex, Interface iface) {
-        LOG.debug("Installing Egress Dispatcher Flows {}, {}", dpId, interfaceName);
-        installEgressDispatcherFlow(dpId, boundService, interfaceName, t, interfaceTag, currentServiceIndex, nextServiceIndex);
-
-        // Install Split Horizon drop flow only for the default egress service - this flow drops traffic targeted to external interfaces if they arrived
+            WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex, short nextServiceIndex,
+            Interface iface) {
+        LOG.debug("Installing Egress Dispatcher Flows on dpn : {}, for interface : {}", dpId, interfaceName);
+        installEgressDispatcherFlow(dpId, boundService, interfaceName, writeTransaction, interfaceTag,
+                currentServiceIndex, nextServiceIndex);
+
+        // Install Split Horizon drop flow only for the default egress service -
+        // this flow drops traffic targeted to external interfaces if they
+        // arrived
         // from an external interface (marked with the SH bit)
-        if (boundService.getServicePriority() == ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
-            installEgressDispatcherSplitHorizonFlow(dpId, boundService, interfaceName, t, interfaceTag, currentServiceIndex, iface);
+        if (boundService.getServicePriority() == ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
+                NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
+            installEgressDispatcherSplitHorizonFlow(dpId, boundService, interfaceName, writeTransaction, interfaceTag,
+                    currentServiceIndex, iface);
         }
     }
 
     private static void installEgressDispatcherFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
-        WriteTransaction t, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
-        String serviceRef = boundService.getServiceName();
-        List<? extends MatchInfoBase> matches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
+            WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex, short nextServiceIndex) {
 
         // Get the metadata and mask from the service's write metadata instruction
-        StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
-        List<Instruction> serviceInstructions = stypeOpenFlow.getInstruction();
-        int instructionSize = serviceInstructions.size();
+        StypeOpenflow stypeOpenflow = boundService.getAugmentation(StypeOpenflow.class);
+        if (stypeOpenflow == null) {
+            LOG.warn("Could not install egress dispatcher flow, missing service openflow configuration");
+            return;
+        }
+        List<Instruction> serviceInstructions = stypeOpenflow.getInstruction() != null
+                ? stypeOpenflow.getInstruction()
+                : Collections.emptyList();
 
         // build the final instruction for LPort Dispatcher table flow entry
+        List<Action> finalApplyActions = new ArrayList<>();
         List<Instruction> instructions = new ArrayList<>();
-        if(boundService.getServicePriority() != ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
+        if (boundService.getServicePriority() != ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
+                NwConstants.DEFAULT_EGRESS_SERVICE_INDEX)) {
             BigInteger[] metadataValues = IfmUtil.mergeOpenflowMetadataWriteInstructions(serviceInstructions);
-            BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(interfaceTag, nextServiceIndex, metadataValues[0]);
-            BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForDispatcherTable();
-            instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, ++instructionSize));
-            instructions.add(MDSALUtil.buildAndGetSetReg6ActionInstruction(0, ++instructionSize, 0, 31,
+            BigInteger metadataMask = MetaDataUtil.getWriteMetaDataMaskForEgressDispatcherTable();
+            instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadataValues[0], metadataMask,
+                    instructions.size()));
+            finalApplyActions.add(MDSALUtil.createSetReg6Action(finalApplyActions.size(), 0, 31,
                     MetaDataUtil.getReg6ValueForLPortDispatcher(interfaceTag, nextServiceIndex)));
         }
-        if (serviceInstructions != null && !serviceInstructions.isEmpty()) {
-            for (Instruction info : serviceInstructions) {
+
+        final int applyActionsOffset = finalApplyActions.size();
+        for (Instruction info : serviceInstructions) {
+            if (info.getInstruction() instanceof WriteActionsCase) {
+                List<Action> writeActions = ActionConverterUtil.convertServiceActionToFlowAction(
+                        ((WriteActionsCase) info.getInstruction()).getWriteActions().getAction());
+                instructions.add(MDSALUtil.buildWriteActionsInstruction(writeActions, instructions.size()));
+            } else if (info.getInstruction() instanceof ApplyActionsCase) {
+                List<Action> applyActions = ActionConverterUtil.convertServiceActionToFlowAction(
+                        ((ApplyActionsCase) info.getInstruction()).getApplyActions().getAction(),
+                        applyActionsOffset);
+                finalApplyActions.addAll(applyActions);
+            } else if (!(info.getInstruction() instanceof WriteMetadataCase)) {
                 // Skip meta data write as that is handled already
-                if (info.getInstruction() instanceof WriteMetadataCase) {
-                    continue;
-                } else if (info.getInstruction() instanceof WriteActionsCase) {
-                    info = MDSALUtil.buildWriteActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
-                        ((WriteActionsCase)info.getInstruction()).getWriteActions().getAction()));
-                } else if (info.getInstruction() instanceof ApplyActionsCase) {
-                    info = MDSALUtil.buildApplyActionsInstruction(ActionConverterUtil.convertServiceActionToFlowAction(
-                        ((ApplyActionsCase)info.getInstruction()).getApplyActions().getAction()));
-                }
-                instructions.add(info);
+                instructions.add(MDSALUtil.buildInstruction(info, instructions.size()));
             }
         }
+        if (!finalApplyActions.isEmpty()) {
+            instructions.add(MDSALUtil.buildApplyActionsInstruction(finalApplyActions, instructions.size()));
+        }
 
         // build the flow and install it
-        String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, boundService, currentServiceIndex);
+        String serviceRef = boundService.getServiceName();
+        List<? extends MatchInfoBase> matches = FlowBasedServicesUtils
+                .getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
+        String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, boundService,
+            currentServiceIndex);
         Flow egressFlow = MDSALUtil.buildFlowNew(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
-                boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), matches, instructions);
-        installFlow(dpId, egressFlow, t);
+                boundService.getServicePriority(), serviceRef, 0, 0, stypeOpenflow.getFlowCookie(), matches,
+                instructions);
+        LOG.debug("Installing Egress Dispatcher Flow for interface : {}, with flow-ref : {}", interfaceName, flowRef);
+        installFlow(dpId, egressFlow, writeTransaction);
     }
 
-    public static void installEgressDispatcherSplitHorizonFlow(BigInteger dpId, BoundServices boundService, String interfaceName,
-            WriteTransaction t, int interfaceTag, short currentServiceIndex, Interface iface) {
+    public static void installEgressDispatcherSplitHorizonFlow(BigInteger dpId, BoundServices boundService,
+            String interfaceName, WriteTransaction writeTransaction, int interfaceTag, short currentServiceIndex,
+            Interface iface) {
         // only install split horizon drop flows for external interfaces
         if (!isExternal(iface)) {
             return;
@@ -347,152 +372,219 @@ public class FlowBasedServicesUtils {
             LOG.debug("Installing split horizon drop flow for external interface {} on dpId {}", interfaceName, dpId);
         }
 
-        BigInteger shFlagSet = BigInteger.ONE; // BigInteger.ONE is used for checking the Split-Horizon flag
-        StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
-        List<MatchInfoBase> shMatches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag, currentServiceIndex);
-        shMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { shFlagSet, MetaDataUtil.METADATA_MASK_SH_FLAG }));
+        BigInteger shFlagSet = BigInteger.ONE; // BigInteger.ONE is used for
+                                                // checking the Split-Horizon
+                                                // flag
+        List<MatchInfoBase> shMatches = FlowBasedServicesUtils.getMatchInfoForEgressDispatcherTable(interfaceTag,
+                currentServiceIndex);
+        shMatches.add(new MatchMetadata(shFlagSet, MetaDataUtil.METADATA_MASK_SH_FLAG));
         List<InstructionInfo> shInstructions = new ArrayList<>();
         List<ActionInfo> actionsInfos = new ArrayList<>();
         actionsInfos.add(new ActionDrop());
-        shInstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
+        shInstructions.add(new InstructionApplyActions(actionsInfos));
 
-        String flowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName, currentServiceIndex, shFlagSet);
+        String flowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, interfaceName,
+                currentServiceIndex, shFlagSet);
         String serviceRef = boundService.getServiceName();
-        int splitHorizonFlowPriority = boundService.getServicePriority() + 1; // this must be higher priority than the egress flow
+        // This must be higher priority than the egress flow
+        int splitHorizonFlowPriority = boundService.getServicePriority() + 1;
+        StypeOpenflow stypeOpenFlow = boundService.getAugmentation(StypeOpenflow.class);
         Flow egressSplitHorizonFlow = MDSALUtil.buildFlow(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, flowRef,
                 splitHorizonFlowPriority, serviceRef, 0, 0, stypeOpenFlow.getFlowCookie(), shMatches, shInstructions);
 
-        installFlow(dpId, egressSplitHorizonFlow, t);
+        installFlow(dpId, egressSplitHorizonFlow, writeTransaction);
     }
 
     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
-                                                 BigInteger cookie, List<Instruction> instructions) {
-        StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority).setInstruction(instructions);
-        return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority))
-                .setServiceName(serviceName).setServicePriority(servicePriority)
-                .setServiceType(ServiceTypeFlowBased.class).addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
+            BigInteger cookie, List<Instruction> instructions) {
+        StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
+                .setInstruction(instructions);
+        return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
+                .setServicePriority(servicePriority).setServiceType(ServiceTypeFlowBased.class)
+                .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
     }
 
     public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex) {
-        return InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class,
-                new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
+        return InstanceIdentifier.builder(ServiceBindings.class)
+                .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
     }
 
-    public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex, Class<? extends ServiceModeBase> serviceMode) {
-        return InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class,
-                new ServicesInfoKey(interfaceName, serviceMode))
+    public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex,
+            Class<? extends ServiceModeBase> serviceMode) {
+        return InstanceIdentifier.builder(ServiceBindings.class)
+                .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, serviceMode))
                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
     }
 
     public static void unbindDefaultEgressDispatcherService(DataBroker dataBroker, String interfaceName) {
-        IfmUtil.unbindService(dataBroker, interfaceName, buildServiceId(interfaceName,
-                ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX),
-                ServiceModeEgress.class));
+        IfmUtil.unbindService(dataBroker, interfaceName,
+                buildServiceId(interfaceName, ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
+                        NwConstants.DEFAULT_EGRESS_SERVICE_INDEX), ServiceModeEgress.class));
     }
 
     public static void bindDefaultEgressDispatcherService(DataBroker dataBroker, List<ListenableFuture<Void>> futures,
                                                           Interface interfaceInfo, String portNo,
                                                           String interfaceName, int ifIndex) {
+        List<Instruction> instructions =
+                IfmUtil.getEgressInstructionsForInterface(interfaceInfo, portNo, null, true, ifIndex, 0);
+        bindDefaultEgressDispatcherService(dataBroker, futures, interfaceName, instructions);
+    }
+
+    public static void bindDefaultEgressDispatcherService(DataBroker dataBroker, List<ListenableFuture<Void>> futures,
+            Interface interfaceInfo, String interfaceName, int ifIndex, long groupId) {
+        List<Instruction> instructions =
+             IfmUtil.getEgressInstructionsForInterface(interfaceInfo, StringUtils.EMPTY, null, true, ifIndex, groupId);
+        bindDefaultEgressDispatcherService(dataBroker, futures, interfaceName, instructions);
+    }
+
+    public static void bindDefaultEgressDispatcherService(DataBroker dataBroker, List<ListenableFuture<Void>> futures,
+            String interfaceName, List<Instruction> instructions) {
         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
-        int priority = ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX);
-        List<Instruction> instructions = IfmUtil.getEgressInstructionsForInterface(interfaceInfo, portNo, null, true, ifIndex);
+        int priority = ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
+                                             NwConstants.DEFAULT_EGRESS_SERVICE_INDEX);
         BoundServices
                 serviceInfo =
                 getBoundServices(String.format("%s.%s", "default", interfaceName),
-                        ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME, NwConstants.DEFAULT_EGRESS_SERVICE_INDEX), priority,
-                        NwConstants.EGRESS_DISPATCHER_TABLE_COOKIE, instructions);
+                        ServiceIndex.getIndex(NwConstants.DEFAULT_EGRESS_SERVICE_NAME,
+                                              NwConstants.DEFAULT_EGRESS_SERVICE_INDEX),
+                        priority, NwConstants.EGRESS_DISPATCHER_TABLE_COOKIE, instructions);
         IfmUtil.bindService(tx, interfaceName, serviceInfo, ServiceModeEgress.class);
         futures.add(tx.submit());
     }
 
-    public static void removeIngressFlow(String name, BoundServices serviceOld, BigInteger dpId, WriteTransaction t) {
-        LOG.debug("Removing Ingress Flows");
-        String flowKeyStr = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, name, serviceOld, serviceOld.getServicePriority());
+    public static void removeIngressFlow(String interfaceName, BigInteger dpId, DataBroker dataBroker,
+            List<ListenableFuture<Void>> futures) {
+        if (dpId == null) {
+            return;
+        }
+        LOG.debug("Removing Ingress Flows for {}", interfaceName);
+        WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+        String flowKeyStr = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, interfaceName);
+        FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
+        Node nodeDpn = buildInventoryDpnNode(dpId);
+        InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey)
+                .build();
+
+        writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
+        futures.add(writeTransaction.submit());
+    }
+
+    public static void removeIngressFlow(String name, BoundServices serviceOld, BigInteger dpId,
+            WriteTransaction writeTransaction) {
+        String flowKeyStr = getFlowRef(dpId, NwConstants.VLAN_INTERFACE_INGRESS_TABLE, name, serviceOld,
+                serviceOld.getServicePriority());
+        LOG.debug("Removing Ingress Flow {}", flowKeyStr);
         FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
         Node nodeDpn = buildInventoryDpnNode(dpId);
         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
-                .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
+                .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey)
+                .build();
 
-        t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
+        writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
     }
 
-    public static void removeLPortDispatcherFlow(BigInteger dpId, String iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) {
+    public static void removeLPortDispatcherFlow(BigInteger dpId, String iface, BoundServices boundServicesOld,
+            WriteTransaction writeTransaction, short currentServiceIndex) {
         LOG.debug("Removing LPort Dispatcher Flows {}, {}", dpId, iface);
 
         boundServicesOld.getAugmentation(StypeOpenflow.class);
         // build the flow and install it
-        String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, iface, boundServicesOld, currentServiceIndex);
+        String flowRef = getFlowRef(dpId, NwConstants.LPORT_DISPATCHER_TABLE, iface, boundServicesOld,
+            currentServiceIndex);
         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
         Node nodeDpn = buildInventoryDpnNode(dpId);
         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
-                .child(Table.class, new TableKey(NwConstants.LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey).build();
+                .child(Table.class, new TableKey(NwConstants.LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey)
+                .build();
 
-        t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
+        writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
     }
 
-    public static void removeEgressDispatcherFlows(BigInteger dpId, String iface, BoundServices boundServicesOld, WriteTransaction t, short currentServiceIndex) {
+    public static void removeEgressDispatcherFlows(BigInteger dpId, String iface, BoundServices boundServicesOld,
+            WriteTransaction writeTransaction, short currentServiceIndex) {
         LOG.debug("Removing Egress Dispatcher Flows {}, {}", dpId, iface);
-        removeEgressDispatcherFlow(dpId, iface, t, currentServiceIndex, boundServicesOld);
-        removeEgressSplitHorizonDispatcherFlow(dpId, iface, t, currentServiceIndex);
+        removeEgressDispatcherFlow(dpId, iface, writeTransaction, currentServiceIndex, boundServicesOld);
+        removeEgressSplitHorizonDispatcherFlow(dpId, iface, writeTransaction, currentServiceIndex);
     }
 
-    private static void removeEgressDispatcherFlow(BigInteger dpId, String iface, WriteTransaction t,
+    private static void removeEgressDispatcherFlow(BigInteger dpId, String iface, WriteTransaction writeTransaction,
             short currentServiceIndex, BoundServices boundServicesOld) {
         // build the flow and install it
-        String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface, boundServicesOld, currentServiceIndex);
+        String flowRef = getFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface, boundServicesOld,
+            currentServiceIndex);
         FlowKey flowKey = new FlowKey(new FlowId(flowRef));
         Node nodeDpn = buildInventoryDpnNode(dpId);
         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
-                .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey).build();
+                .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE)).child(Flow.class, flowKey)
+                .build();
 
-        t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
+        writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
     }
 
-    public static void removeEgressSplitHorizonDispatcherFlow(BigInteger dpId, String iface, WriteTransaction t, short currentServiceIndex) {
-        BigInteger shFlagSet = BigInteger.ONE; // BigInteger.ONE is used for checking the Split-Horizon flag
-        String shFlowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface, currentServiceIndex, shFlagSet);
+    public static void removeEgressSplitHorizonDispatcherFlow(BigInteger dpId, String iface,
+            WriteTransaction writeTransaction, short currentServiceIndex) {
+        // BigInteger.ONE is used for checking the Split-Horizon flag
+        BigInteger shFlagSet = BigInteger.ONE;
+        String shFlowRef = getSplitHorizonFlowRef(dpId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, iface,
+                currentServiceIndex, shFlagSet);
         FlowKey shFlowKey = new FlowKey(new FlowId(shFlowRef));
         Node nodeDpn = buildInventoryDpnNode(dpId);
         InstanceIdentifier<Flow> shFlowInstanceId = InstanceIdentifier.builder(Nodes.class)
                 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
-                .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE)).child(Flow.class, shFlowKey).build();
+                .child(Table.class, new TableKey(NwConstants.EGRESS_LPORT_DISPATCHER_TABLE))
+                .child(Flow.class, shFlowKey).build();
 
-        t.delete(LogicalDatastoreType.CONFIGURATION, shFlowInstanceId);
+        writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, shFlowInstanceId);
     }
 
-    private static String getFlowRef(BigInteger dpnId, short tableId, String iface, BoundServices service, short currentServiceIndex) {
-        return String.valueOf(dpnId) + tableId + NwConstants.FLOWID_SEPARATOR +
-                iface + NwConstants.FLOWID_SEPARATOR + currentServiceIndex;
+    public static String getFlowRef(short tableId, BigInteger dpnId, String infName) {
+        return String.format("%d:%s:%s", tableId, dpnId, infName);
     }
 
-    private static String getSplitHorizonFlowRef(BigInteger dpnId, short tableId, String iface, short currentServiceIndex, BigInteger shFlag) {
-        return new StringBuffer().append(dpnId).append(tableId).append(NwConstants.FLOWID_SEPARATOR)
-                .append(iface).append(NwConstants.FLOWID_SEPARATOR).append(shFlag.toString()).toString();
+    private static String getFlowRef(BigInteger dpnId, short tableId, String iface,BoundServices service,
+                                     short currentServiceIndex) {
+        return String.valueOf(dpnId) + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + iface
+                + NwConstants.FLOWID_SEPARATOR + currentServiceIndex;
     }
+
+    private static String getSplitHorizonFlowRef(BigInteger dpnId, short tableId, String iface,
+            short currentServiceIndex, BigInteger shFlag) {
+        return new StringBuffer().append(dpnId).append(NwConstants.FLOWID_SEPARATOR).append(tableId).append(NwConstants
+                .FLOWID_SEPARATOR).append(iface).append(NwConstants.FLOWID_SEPARATOR)
+                .append(shFlag.toString()).toString();
+    }
+
     /**
-     * This util method returns an array of ServiceInfo in which index 0 will
+     * This utility method returns an array of ServiceInfo in which index 0 will
      * have the immediate lower priority service and index 1 will have the
-     * immediate higher priority service among the list of existing serviceInfos
+     * immediate higher priority service among the list of existing
+     * serviceInfos.
      *
      * @param serviceInfos
+     *            list of services bound
      * @param currentServiceInfo
-     * @return
+     *            current service bound
+     * @return array bound services
      */
-    public static BoundServices[] getHighAndLowPriorityService(
-            List<BoundServices> serviceInfos, BoundServices currentServiceInfo) {
-        BoundServices higher = null; // this will be used to hold the immediate higher service priority with respect to the currentServiceInfo
-        BoundServices lower = null; // this will be used to hold the immediate lower service priority with respect to the currentServiceInfo
+    public static BoundServices[] getHighAndLowPriorityService(List<BoundServices> serviceInfos,
+            BoundServices currentServiceInfo) {
+        // This will be used to hold the immediate higher service priority with respect to the currentServiceInfo
+        BoundServices higher = null;
+        // This will be used to hold the immediate lower service priority with respect to the currentServiceInfo
+        BoundServices lower = null;
         if (serviceInfos == null || serviceInfos.isEmpty()) {
-            return new BoundServices[]{lower, higher};
+            return new BoundServices[] { lower, higher };
         }
-        List <BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
-        Collections.sort(availableServiceInfos,
-                (serviceInfo1, serviceInfo2) -> serviceInfo1.getServicePriority().compareTo(serviceInfo2.getServicePriority()));
-        for (BoundServices availableServiceInfo: availableServiceInfos) {
+        List<BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
+        Collections.sort(availableServiceInfos, (serviceInfo1, serviceInfo2) -> serviceInfo1.getServicePriority()
+                .compareTo(serviceInfo2.getServicePriority()));
+        for (BoundServices availableServiceInfo : availableServiceInfos) {
             if (currentServiceInfo.getServicePriority() < availableServiceInfo.getServicePriority()) {
                 lower = availableServiceInfo;
                 break;
@@ -500,17 +592,17 @@ public class FlowBasedServicesUtils {
                 higher = availableServiceInfo;
             }
         }
-        return new BoundServices[]{lower,higher};
+        return new BoundServices[] { lower, higher };
     }
 
     public static BoundServices getHighestPriorityService(List<BoundServices> serviceInfos) {
-        List <BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
+        List<BoundServices> availableServiceInfos = new ArrayList<>(serviceInfos);
         if (availableServiceInfos.isEmpty()) {
             return null;
         }
         BoundServices highPriorityService = availableServiceInfos.get(0);
         availableServiceInfos.remove(0);
-        for (BoundServices availableServiceInfo: availableServiceInfos) {
+        for (BoundServices availableServiceInfo : availableServiceInfos) {
             if (availableServiceInfo.getServicePriority() < highPriorityService.getServicePriority()) {
                 highPriorityService = availableServiceInfo;
             }
@@ -519,66 +611,96 @@ public class FlowBasedServicesUtils {
     }
 
     public static void installLportIngressFlow(BigInteger dpId, long portNo, Interface iface,
-                                               List<ListenableFuture<Void>> futures, DataBroker dataBroker,
-                                               int lportTag) {
+            List<ListenableFuture<Void>> futures, DataBroker dataBroker, int lportTag) {
         int vlanId = 0;
         boolean isVlanTransparent = false;
-        WriteTransaction  inventoryConfigShardTransaction = dataBroker.newWriteOnlyTransaction();
-        List<MatchInfo> matches = getMatchInfoForVlanPortAtIngressTable(dpId, portNo, iface);
+
         IfL2vlan l2vlan = iface.getAugmentation(IfL2vlan.class);
-        if(l2vlan != null){
+        if (l2vlan != null) {
             vlanId = l2vlan.getVlanId() == null ? 0 : l2vlan.getVlanId().getValue();
             isVlanTransparent = l2vlan.getL2vlanMode() == IfL2vlan.L2vlanMode.Transparent;
         }
         int instructionKey = 0;
-        BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, (short) 0, BigInteger.ZERO, isExternal(iface));
-        BigInteger metadataMask = MetaDataUtil.getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG);
+
         List<Instruction> instructions = new ArrayList<>();
 
         final SplitHorizon splitHorizon = iface.getAugmentation(SplitHorizon.class);
-        boolean overrideSplitHorizonProtection = splitHorizon != null && splitHorizon.isOverrideSplitHorizonProtection();
+        boolean overrideSplitHorizonProtection = splitHorizon != null
+                && splitHorizon.isOverrideSplitHorizonProtection();
         int actionKey = 0;
         List<Action> actions = new ArrayList<>();
         if (vlanId != 0 && !isVlanTransparent) {
             actions.add(MDSALUtil.createPopVlanAction(actionKey++));
         }
         if (overrideSplitHorizonProtection) {
-            actions.add(MDSALUtil.createNxOfInPortAction(actionKey++,0));
+            actions.add(MDSALUtil.createNxOfInPortAction(actionKey++, 0));
         }
-        if (actions.size() != 0) {
-            instructions.add(MDSALUtil.buildApplyActionsInstruction(actions,instructionKey++));
+        if (!actions.isEmpty()) {
+            instructions.add(MDSALUtil.buildApplyActionsInstruction(actions, instructionKey++));
         }
-
+        BigInteger metadata = MetaDataUtil.getMetaDataForLPortDispatcher(lportTag, (short) 0, BigInteger.ZERO,
+                isExternal(iface));
+        BigInteger metadataMask = MetaDataUtil
+                .getMetaDataMaskForLPortDispatcher(MetaDataUtil.METADATA_MASK_LPORT_TAG_SH_FLAG);
         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(metadata, metadataMask, instructionKey++));
-        instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.LPORT_DISPATCHER_TABLE, instructionKey++));
-        int priority =  isVlanTransparent ? 1 : vlanId == 0 ? IfmConstants.FLOW_PRIORITY_FOR_UNTAGGED_VLAN : IfmConstants.FLOW_HIGH_PRIORITY;
+        instructions
+                .add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.LPORT_DISPATCHER_TABLE, instructionKey++));
+        int priority = isVlanTransparent ? 1
+                : vlanId == 0 ? IfmConstants.FLOW_PRIORITY_FOR_UNTAGGED_VLAN : IfmConstants.FLOW_HIGH_PRIORITY;
         String flowRef = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, iface.getName());
-        Flow ingressFlow = MDSALUtil.buildFlowNew(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, flowRef, priority, flowRef, 0, 0,
-                NwConstants.VLAN_TABLE_COOKIE, matches, instructions);
+        List<MatchInfo> matches = getMatchInfoForVlanPortAtIngressTable(dpId, portNo, iface);
+        Flow ingressFlow = MDSALUtil.buildFlowNew(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, flowRef, priority, flowRef,
+                0, 0, NwConstants.VLAN_TABLE_COOKIE, matches, instructions);
+        LOG.debug("Installing ingress flow {} for {}", flowRef, iface.getName());
+        WriteTransaction inventoryConfigShardTransaction = dataBroker.newWriteOnlyTransaction();
         installFlow(dpId, ingressFlow, inventoryConfigShardTransaction);
         futures.add(inventoryConfigShardTransaction.submit());
     }
 
-    public static String getFlowRef(short tableId, BigInteger dpnId, String infName) {
-        return String.format("%d:%s:%s", tableId, dpnId, infName);
-    }
-
-    public static void removeIngressFlow(String interfaceName, BigInteger dpId, DataBroker dataBroker,
-                                         List<ListenableFuture<Void>> futures) {
-        if(dpId == null){
-            return;
-        }
-        LOG.debug("Removing Ingress Flows for {}", interfaceName);
-        WriteTransaction t = dataBroker.newWriteOnlyTransaction();
-        String flowKeyStr = getFlowRef(IfmConstants.VLAN_INTERFACE_INGRESS_TABLE, dpId, interfaceName);
-        FlowKey flowKey = new FlowKey(new FlowId(flowKeyStr));
-        Node nodeDpn = buildInventoryDpnNode(dpId);
-        InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
-                .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
-                .child(Table.class, new TableKey(NwConstants.VLAN_INTERFACE_INGRESS_TABLE)).child(Flow.class, flowKey).build();
-
-        t.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
-        futures.add(t.submit());
+    public static BoundServicesState buildBoundServicesState(
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
+            interfaceState, Class<? extends ServiceModeBase> serviceMode) {
+        NodeConnectorId nodeConnectorId = IfmUtil.getNodeConnectorIdFromInterface(interfaceState);
+        BigInteger dpId = IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
+        long portNo = IfmUtil.getPortNumberFromNodeConnectorId(nodeConnectorId);
+        BoundServicesStateKey boundServicesStateKey = new BoundServicesStateKey(interfaceState.getName(), serviceMode);
+        return new BoundServicesStateBuilder().setDpid(dpId).setIfIndex(interfaceState.getIfIndex())
+            .setInterfaceName(interfaceState.getName()).setInterfaceType(interfaceState.getType()).setPortNo(portNo)
+            .setServiceMode(serviceMode).setKey(boundServicesStateKey).build();
+    }
+
+    public static BoundServicesState getBoundServicesState(DataBroker dataBroker,
+                                                           String interfaceName,
+                                                           Class<? extends ServiceModeBase>
+                                                                                 serviceMode) {
+        InstanceIdentifier<BoundServicesState> id = InstanceIdentifier.builder(BoundServicesStateList.class)
+            .child(BoundServicesState.class, new BoundServicesStateKey(interfaceName, serviceMode)).build();
+        return IfmUtil.read(LogicalDatastoreType.OPERATIONAL, id, dataBroker).orNull();
+    }
+
+    public static void addBoundServicesState(List<ListenableFuture<Void>> futures,
+                                             DataBroker dataBroker, String interfaceName,
+                                             BoundServicesState interfaceBoundServicesState) {
+        LOG.info("adding bound-service state information for interface : {}, service-mode : {}",
+            interfaceBoundServicesState.getInterfaceName(), interfaceBoundServicesState.getServiceMode().getName());
+        InstanceIdentifier<BoundServicesState> id = InstanceIdentifier.builder(BoundServicesStateList.class)
+            .child(BoundServicesState.class, new BoundServicesStateKey(interfaceName,
+                interfaceBoundServicesState.getServiceMode())).build();
+        WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+        writeTransaction.put(LogicalDatastoreType.OPERATIONAL, id, interfaceBoundServicesState, true);
+        futures.add(writeTransaction.submit());
+    }
+
+    public static  void removeBoundServicesState(List<ListenableFuture<Void>> futures,
+                                                 DataBroker dataBroker,
+                                                 String interfaceName, Class<? extends ServiceModeBase> serviceMode) {
+        LOG.info("remove bound-service state information for interface : {}, service-mode : {}", interfaceName,
+            serviceMode.getName());
+        InstanceIdentifier<BoundServicesState> id = InstanceIdentifier.builder(BoundServicesStateList.class)
+            .child(BoundServicesState.class, new BoundServicesStateKey(interfaceName, serviceMode)).build();
+        WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+        writeTransaction.delete(LogicalDatastoreType.OPERATIONAL, id);
+        futures.add(writeTransaction.submit());
     }
 
     private static boolean isExternal(Interface iface) {