Optimize the method in AclServiceUtils.java
[netvirt.git] / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / AbstractAclServiceImpl.java
index da7768153d973607ae6ca91c385a470c8a6f4c21..afeff3f09c9d8bfa8f44002e1d7c54d178edfccf 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.netvirt.aclservice;
 
+import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
+
 import com.google.common.collect.Lists;
 import java.math.BigInteger;
 import java.util.ArrayList;
@@ -20,6 +22,7 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.stream.Collectors;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
@@ -31,6 +34,7 @@ import org.opendaylight.genius.mdsalutil.MatchInfoBase;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack;
 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack.NxCtAction;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxCtClear;
 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
@@ -59,8 +63,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.ser
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionEgress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionIngress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl.InterfaceType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.SecurityRuleAttr;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.SubnetInfo;
+import org.opendaylight.yangtools.yang.common.Uint64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -69,7 +76,6 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractAclServiceImpl.class);
 
     protected final IMdsalApiManager mdsalManager;
-    protected final DataBroker dataBroker;
     protected final ManagedNewTransactionRunner txRunner;
     protected final Class<? extends ServiceModeBase> serviceMode;
     protected final AclDataUtil aclDataUtil;
@@ -94,7 +100,6 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
     public AbstractAclServiceImpl(Class<? extends ServiceModeBase> serviceMode, DataBroker dataBroker,
             IMdsalApiManager mdsalManager, AclDataUtil aclDataUtil, AclServiceUtils aclServiceUtils,
             JobCoordinator jobCoordinator, AclInterfaceCache aclInterfaceCache) {
-        this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.mdsalManager = mdsalManager;
         this.serviceMode = serviceMode;
@@ -114,31 +119,35 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
             LOG.error("port cannot be null");
             return false;
         }
-        if (port.getSecurityGroups() == null) {
-            LOG.info("Port {} without SGs", port.getInterfaceId());
-            return false;
-        }
         BigInteger dpId = port.getDpId();
         if (dpId == null || port.getLPortTag() == null) {
             LOG.error("Unable to find DpId from ACL interface with id {}", port.getInterfaceId());
             return false;
         }
+
         LOG.debug("Applying ACL on port {} with DpId {}", port, dpId);
-        programAcl(port, Action.ADD, NwConstants.ADD_FLOW);
-        updateRemoteAclFilterTable(port, NwConstants.ADD_FLOW);
+        List<FlowEntity> flowEntries = new ArrayList<>();
+        if (port.getInterfaceType() == InterfaceType.DhcpService) {
+            programDhcpService(flowEntries, port, Action.ADD, NwConstants.ADD_FLOW);
+        } else {
+            if (port.getSecurityGroups() == null) {
+                LOG.info("Port {} without SGs", port.getInterfaceId());
+                return false;
+            }
+            programAcl(flowEntries, port, Action.ADD, NwConstants.ADD_FLOW);
+            updateRemoteAclFilterTable(flowEntries, port, NwConstants.ADD_FLOW);
+        }
+        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, NwConstants.ADD_FLOW);
         return true;
     }
 
     @Override
     public boolean bindAcl(AclInterface port) {
-        if (port == null || port.getSecurityGroups() == null) {
-            LOG.error("Port and port security groups cannot be null for binding ACL service, port={}", port);
+        if (port == null) {
+            LOG.error("Port cannot be null for binding ACL service");
             return false;
         }
         bindService(port);
-        if (port.getDpId() != null) {
-            updateRemoteAclFilterTable(port, NwConstants.ADD_FLOW);
-        }
         return true;
     }
 
@@ -150,7 +159,6 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         }
         if (port.getDpId() != null) {
             unbindService(port);
-            updateRemoteAclFilterTable(port, NwConstants.DEL_FLOW);
         }
         return true;
     }
@@ -179,46 +187,93 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
             // Acls has been updated, find added/removed Acls and act accordingly.
             processInterfaceUpdate(portBefore, portAfter);
             LOG.debug("On ACL update, ACL has been updated for {}", portAfter.getInterfaceId());
+        } else if (portAfter.getInterfaceType() == InterfaceType.DhcpService) {
+            processDhcpServiceInterfaceUpdate(portBefore, portAfter);
         }
 
         return result;
     }
 
+    private void processDhcpServiceInterfaceUpdate(AclInterface portBefore, AclInterface portAfter) {
+        List<FlowEntity> addFlowEntries = new ArrayList<>();
+        List<FlowEntity> deleteFlowEntries = new ArrayList<>();
+        List<AllowedAddressPairs> addedAaps = AclServiceUtils
+                .getUpdatedAllowedAddressPairs(portAfter.getAllowedAddressPairs(), portBefore.getAllowedAddressPairs());
+        List<AllowedAddressPairs> deletedAaps = AclServiceUtils
+                .getUpdatedAllowedAddressPairs(portBefore.getAllowedAddressPairs(), portAfter.getAllowedAddressPairs());
+        if (!deletedAaps.isEmpty()) {
+            processDhcpServiceUpdate(deleteFlowEntries, portBefore, deletedAaps, NwConstants.DEL_FLOW);
+        }
+        if (!addedAaps.isEmpty()) {
+            processDhcpServiceUpdate(addFlowEntries, portAfter, addedAaps, NwConstants.ADD_FLOW);
+        }
+        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + portAfter.getInterfaceId(), deleteFlowEntries,
+                NwConstants.DEL_FLOW);
+        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + portAfter.getInterfaceId(), addFlowEntries,
+                NwConstants.ADD_FLOW);
+    }
+
     private void processInterfaceUpdate(AclInterface portBefore, AclInterface portAfter) {
+        List<FlowEntity> addFlowEntries = new ArrayList<>();
+        List<FlowEntity> deleteFlowEntries = new ArrayList<>();
         List<AllowedAddressPairs> addedAaps = AclServiceUtils
                 .getUpdatedAllowedAddressPairs(portAfter.getAllowedAddressPairs(), portBefore.getAllowedAddressPairs());
         List<AllowedAddressPairs> deletedAaps = AclServiceUtils
                 .getUpdatedAllowedAddressPairs(portBefore.getAllowedAddressPairs(), portAfter.getAllowedAddressPairs());
-        if (deletedAaps != null && !deletedAaps.isEmpty()) {
-            programAclWithAllowedAddress(portBefore, deletedAaps, Action.UPDATE, NwConstants.DEL_FLOW);
-            updateRemoteAclFilterTable(portBefore, portBefore.getSecurityGroups(), deletedAaps, NwConstants.DEL_FLOW);
+        if (!deletedAaps.isEmpty()) {
+            programAclWithAllowedAddress(deleteFlowEntries, portBefore, deletedAaps, Action.UPDATE,
+                    NwConstants.DEL_FLOW);
+            updateRemoteAclFilterTable(deleteFlowEntries, portBefore, portBefore.getSecurityGroups(), deletedAaps,
+                    NwConstants.DEL_FLOW);
         }
-        if (addedAaps != null && !addedAaps.isEmpty()) {
-            programAclWithAllowedAddress(portAfter, addedAaps, Action.UPDATE, NwConstants.ADD_FLOW);
-            updateRemoteAclFilterTable(portAfter, portAfter.getSecurityGroups(), addedAaps, NwConstants.ADD_FLOW);
+        if (!addedAaps.isEmpty()) {
+            programAclWithAllowedAddress(addFlowEntries, portAfter, addedAaps, Action.UPDATE, NwConstants.ADD_FLOW);
+            updateRemoteAclFilterTable(addFlowEntries, portAfter, portAfter.getSecurityGroups(), addedAaps,
+                    NwConstants.ADD_FLOW);
         }
-        if (portAfter.getSubnetIpPrefixes() != null && portBefore.getSubnetIpPrefixes() == null) {
-            programBroadcastRules(portAfter, NwConstants.ADD_FLOW);
+        if (portAfter.getSubnetInfo() != null && portBefore.getSubnetInfo() == null) {
+            programBroadcastRules(addFlowEntries, portAfter, Action.UPDATE, NwConstants.ADD_FLOW);
         }
+        handleSubnetChange(portBefore, portAfter, addFlowEntries, deleteFlowEntries);
 
         List<Uuid> addedAcls = AclServiceUtils.getUpdatedAclList(portAfter.getSecurityGroups(),
                 portBefore.getSecurityGroups());
         List<Uuid> deletedAcls = AclServiceUtils.getUpdatedAclList(portBefore.getSecurityGroups(),
                 portAfter.getSecurityGroups());
-        if (deletedAcls.isEmpty() && addedAcls.isEmpty()) {
-            LOG.trace("No change w.r.t ACL list for port={}", portAfter.getInterfaceId());
-            return;
+        if (!deletedAcls.isEmpty() || !addedAcls.isEmpty()) {
+            handleAclChange(deleteFlowEntries, portBefore, deletedAcls, NwConstants.DEL_FLOW);
+            handleAclChange(addFlowEntries, portAfter, addedAcls, NwConstants.ADD_FLOW);
         }
 
-        handleAclChange(portBefore, deletedAcls, NwConstants.DEL_FLOW);
-        handleAclChange(portAfter, addedAcls, NwConstants.ADD_FLOW);
+        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + portAfter.getInterfaceId(), deleteFlowEntries,
+                NwConstants.DEL_FLOW);
+        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + portAfter.getInterfaceId(), addFlowEntries,
+                NwConstants.ADD_FLOW);
     }
 
-    private void handleAclChange(AclInterface port, List<Uuid> aclList, int addOrRemove) {
-        int operationForAclRules = (addOrRemove == NwConstants.DEL_FLOW) ? NwConstants.MOD_FLOW : addOrRemove;
-        programAclRules(port, aclList, operationForAclRules);
-        updateRemoteAclFilterTable(port, aclList, port.getAllowedAddressPairs(), addOrRemove);
-        programAclDispatcherTable(port, addOrRemove);
+    private void handleSubnetChange(AclInterface portBefore, AclInterface portAfter,
+            List<FlowEntity> addFlowEntries, List<FlowEntity> deleteFlowEntries) {
+        List<SubnetInfo> deletedSubnets =
+                AclServiceUtils.getSubnetDiff(portBefore.getSubnetInfo(), portAfter.getSubnetInfo());
+        List<SubnetInfo> addedSubnets =
+                AclServiceUtils.getSubnetDiff(portAfter.getSubnetInfo(), portBefore.getSubnetInfo());
+
+        if (deletedSubnets != null && !deletedSubnets.isEmpty()) {
+            programIcmpv6RARule(deleteFlowEntries, portAfter, deletedSubnets, NwConstants.DEL_FLOW);
+            programSubnetBroadcastRules(deleteFlowEntries, portAfter, deletedSubnets, NwConstants.DEL_FLOW);
+        }
+        if (addedSubnets != null && !addedSubnets.isEmpty()) {
+            programIcmpv6RARule(addFlowEntries, portAfter, addedSubnets, NwConstants.ADD_FLOW);
+            programSubnetBroadcastRules(addFlowEntries, portAfter, addedSubnets, NwConstants.ADD_FLOW);
+        }
+    }
+
+    private void handleAclChange(List<FlowEntity> flowEntries, AclInterface port, List<Uuid> aclList,
+            int addOrRemove) {
+        int operationForAclRules = addOrRemove == NwConstants.DEL_FLOW ? NwConstants.MOD_FLOW : addOrRemove;
+        programAclRules(flowEntries, port, aclList, operationForAclRules);
+        updateRemoteAclFilterTable(flowEntries, port, aclList, port.getAllowedAddressPairs(), addOrRemove);
+        programAclDispatcherTable(flowEntries, port, addOrRemove);
     }
 
     protected SortedSet<Integer> getRemoteAclTags(AclInterface port) {
@@ -226,7 +281,7 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
                 : port.getEgressRemoteAclTags();
     }
 
-    protected void programAclDispatcherTable(AclInterface port, int addOrRemove) {
+    protected void programAclDispatcherTable(List<FlowEntity> flowEntries, AclInterface port, int addOrRemove) {
         SortedSet<Integer> remoteAclTags = getRemoteAclTags(port);
         if (remoteAclTags.isEmpty()) {
             LOG.debug("No {} rules with remote group id for port={}", this.directionString, port.getInterfaceId());
@@ -235,8 +290,8 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         Integer firstRemoteAclTag = remoteAclTags.first();
         Integer lastRemoteAclTag = remoteAclTags.last();
 
-        programFirstRemoteAclEntryInDispatcherTable(port, firstRemoteAclTag, addOrRemove);
-        programLastRemoteAclEntryInDispatcherTable(port, lastRemoteAclTag, addOrRemove);
+        programFirstRemoteAclEntryInDispatcherTable(flowEntries, port, firstRemoteAclTag, addOrRemove);
+        programLastRemoteAclEntryInDispatcherTable(flowEntries, port, lastRemoteAclTag, addOrRemove);
 
         Integer previousRemoteAclTag = firstRemoteAclTag;
         for (Integer remoteAclTag : remoteAclTags) {
@@ -252,16 +307,16 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
             List<InstructionInfo> instructions =
                     AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclRuleBasedFilterTable());
             instructions.add(AclServiceUtils.getWriteMetadataForRemoteAclTag(remoteAclTag));
-            syncFlow(port.getDpId(), getAclFilterCumDispatcherTable(), flowId,
-                    AclConstants.ACE_GOTO_NEXT_REMOTE_ACL_PRIORITY, "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
+            addFlowEntryToList(flowEntries, Uint64.valueOf(port.getDpId()), getAclFilterCumDispatcherTable(), flowId,
+                    AclConstants.ACE_GOTO_NEXT_REMOTE_ACL_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches,
                     instructions, addOrRemove);
 
             previousRemoteAclTag = remoteAclTag;
         }
     }
 
-    protected void programFirstRemoteAclEntryInDispatcherTable(AclInterface port, Integer firstRemoteAclTag,
-            int addOrRemove) {
+    protected void programFirstRemoteAclEntryInDispatcherTable(List<FlowEntity> flowEntries, AclInterface port,
+            Integer firstRemoteAclTag, int addOrRemove) {
         List<MatchInfoBase> matches = new ArrayList<>();
         matches.add(AclServiceUtils.buildLPortTagMatch(port.getLPortTag(), serviceMode));
         String flowId = this.directionString + "_ACL_Dispatcher_First_" + port.getDpId() + "_" + port.getLPortTag()
@@ -270,12 +325,13 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         List<InstructionInfo> instructions =
                 AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclRuleBasedFilterTable());
         instructions.add(AclServiceUtils.getWriteMetadataForRemoteAclTag(firstRemoteAclTag));
-        syncFlow(port.getDpId(), getAclFilterCumDispatcherTable(), flowId, AclConstants.ACE_FIRST_REMOTE_ACL_PRIORITY,
-                "ACL", 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
+        addFlowEntryToList(flowEntries, Uint64.valueOf(port.getDpId()), getAclFilterCumDispatcherTable(), flowId,
+                AclConstants.ACE_FIRST_REMOTE_ACL_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions,
+                addOrRemove);
     }
 
-    protected void programLastRemoteAclEntryInDispatcherTable(AclInterface port, Integer lastRemoteAclTag,
-            int addOrRemove) {
+    protected void programLastRemoteAclEntryInDispatcherTable(List<FlowEntity> flowEntries, AclInterface port,
+            Integer lastRemoteAclTag, int addOrRemove) {
         List<MatchInfoBase> matches = new ArrayList<>();
         matches.addAll(AclServiceUtils.buildMatchesForLPortTagAndRemoteAclTag(port.getLPortTag(), lastRemoteAclTag,
                 serviceMode));
@@ -283,37 +339,40 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
                 + lastRemoteAclTag;
 
         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
-        syncFlow(port.getDpId(), getAclFilterCumDispatcherTable(), flowId, AclConstants.ACE_LAST_REMOTE_ACL_PRIORITY,
-                "ACL", 0, 0, AclConstants.COOKIE_ACL_DROP_FLOW, matches, instructions, addOrRemove);
+        addFlowEntryToList(flowEntries, Uint64.valueOf(port.getDpId()), getAclFilterCumDispatcherTable(), flowId,
+                AclConstants.ACE_LAST_REMOTE_ACL_PRIORITY, 0, 0, AclServiceUtils.getDropFlowCookie(port.getLPortTag()),
+                matches, instructions, addOrRemove);
     }
 
-    private void programAcl(AclInterface port, Action action, int addOrRemove) {
-        programAclWithAllowedAddress(port, port.getAllowedAddressPairs(), action, addOrRemove);
+    private void programAcl(List<FlowEntity> flowEntries, AclInterface port, Action action, int addOrRemove) {
+        programAclWithAllowedAddress(flowEntries, port, port.getAllowedAddressPairs(), action, addOrRemove);
     }
 
-    private void programAclWithAllowedAddress(AclInterface port, List<AllowedAddressPairs> allowedAddresses,
-            Action action, int addOrRemove) {
-        BigInteger dpId = port.getDpId();
+    private void programAclWithAllowedAddress(List<FlowEntity> flowEntries, AclInterface port,
+            List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove) {
+        Uint64 dpId = Uint64.valueOf(port.getDpId());
         int lportTag = port.getLPortTag();
         LOG.debug("Applying ACL Allowed Address on DpId {}, lportTag {}, Action {}", dpId, lportTag, action);
         String portId = port.getInterfaceId();
-        programAntiSpoofingRules(port, allowedAddresses, action, addOrRemove);
-        programAclPortSpecificFixedRules(dpId, allowedAddresses, lportTag, portId, action, addOrRemove);
+        programAntiSpoofingRules(flowEntries, port, allowedAddresses, action, addOrRemove);
+        programAclPortSpecificFixedRules(flowEntries, dpId, allowedAddresses, lportTag, portId, action, addOrRemove);
         if (action == Action.ADD || action == Action.REMOVE) {
-            programAclRules(port, port.getSecurityGroups(), addOrRemove);
-            programAclDispatcherTable(port, addOrRemove);
+            programAclRules(flowEntries, port, port.getSecurityGroups(), addOrRemove);
+            programAclDispatcherTable(flowEntries, port, addOrRemove);
         }
     }
 
     /**
      * Programs the acl custom rules.
      *
+     * @param flowEntries the flow entries
      * @param port acl interface
      * @param aclUuidList the list of acl uuid to be applied
      * @param addOrRemove whether to delete or add flow
      * @return program succeeded
      */
-    protected boolean programAclRules(AclInterface port, List<Uuid> aclUuidList, int addOrRemove) {
+    protected boolean programAclRules(List<FlowEntity> flowEntries, AclInterface port, List<Uuid> aclUuidList,
+            int addOrRemove) {
         BigInteger dpId = port.getDpId();
         LOG.debug("Applying custom rules on DpId {}, lportTag {}", dpId, port.getLPortTag());
         if (aclUuidList == null || dpId == null) {
@@ -328,9 +387,10 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
                 continue;
             }
             AccessListEntries accessListEntries = acl.getAccessListEntries();
-            List<Ace> aceList = accessListEntries.getAce();
-            for (Ace ace: aceList) {
-                programAceRule(port, aclUuid.getValue(), ace, addOrRemove);
+            if (accessListEntries != null && accessListEntries.getAce() != null) {
+                for (Ace ace: accessListEntries.getAce()) {
+                    programAceRule(flowEntries, port, aclUuid.getValue(), ace, addOrRemove);
+                }
             }
         }
         return true;
@@ -339,13 +399,24 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
     /**
      * Programs the ace specific rule.
      *
+     * @param flowEntries flow entries
      * @param port acl interface
      * @param aclName the acl name
      * @param ace rule to be program
      * @param addOrRemove whether to delete or add flow
      */
-    protected void programAceRule(AclInterface port, String aclName, Ace ace, int addOrRemove) {
-        SecurityRuleAttr aceAttr = AclServiceUtils.getAccesssListAttributes(ace);
+    protected void programAceRule(List<FlowEntity> flowEntries, AclInterface port, String aclName, Ace ace,
+            int addOrRemove) {
+        SecurityRuleAttr aceAttr = AclServiceUtils.getAccessListAttributes(ace);
+        if (aceAttr == null) {
+            LOG.error("Ace {} of Acl {} is either null or not having SecurityRuleAttr",
+                    ((ace == null) ? null : ace.getRuleName()), aclName);
+            return;
+        }
+        if (addOrRemove == NwConstants.ADD_FLOW && aceAttr.isDeleted()) {
+            LOG.trace("Ignoring {} rule which is already deleted", ace.getRuleName());
+            return;
+        }
         if (!isValidDirection(aceAttr.getDirection())) {
             LOG.trace("Ignoring {} direction while processing for {} ACE Rule {}", aceAttr.getDirection(),
                     this.directionString, ace.getRuleName());
@@ -356,22 +427,21 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
                 port.getInterfaceId());
 
         Matches matches = ace.getMatches();
-        Map<String, List<MatchInfoBase>> flowMap = null;
-        if (matches.getAceType() instanceof AceIp) {
-            flowMap = AclServiceOFFlowBuilder.programIpFlow(matches);
+        if (matches != null && matches.getAceType() instanceof AceIp) {
+            Map<String, List<MatchInfoBase>> flowMap = AclServiceOFFlowBuilder.programIpFlow(matches);
             if (!AclServiceUtils.doesAceHaveRemoteGroupId(aceAttr)) {
                 // programming for ACE which doesn't have any remote group Id
-                programForAceNotHavingRemoteAclId(port, aclName, ace, flowMap, addOrRemove);
+                programForAceNotHavingRemoteAclId(flowEntries, port, aclName, ace, flowMap, addOrRemove);
             } else {
                 Uuid remoteAclId = aceAttr.getRemoteGroupId();
                 // programming for ACE which have remote group Id
-                programAceSpecificFlows(port, aclName, ace, flowMap, remoteAclId, addOrRemove);
+                programAceSpecificFlows(flowEntries, port, aclName, ace, flowMap, remoteAclId, addOrRemove);
             }
         }
     }
 
-    protected void programForAceNotHavingRemoteAclId(AclInterface port, String aclName, Ace ace,
-            Map<String, List<MatchInfoBase>> flowMap, int addOrRemove) {
+    protected void programForAceNotHavingRemoteAclId(List<FlowEntity> flowEntries, AclInterface port, String aclName,
+            Ace ace, @Nullable Map<String, List<MatchInfoBase>> flowMap, int addOrRemove) {
         if (null == flowMap) {
             return;
         }
@@ -384,11 +454,11 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
             List<MatchInfoBase> matches = entry.getValue();
             matches.add(lportTagMatch);
             String flowId = flowName + this.directionString + "_" + port.getDpId() + "_" + port.getLPortTag() + "_"
-                    + ace.getKey().getRuleName();
+                    + ace.key().getRuleName();
 
             int operation = addOrRemove == NwConstants.MOD_FLOW ? NwConstants.DEL_FLOW : addOrRemove;
-            syncFlow(port.getDpId(), getAclFilterCumDispatcherTable(), flowId, flowPriority, "ACL", 0, 0,
-                    AclConstants.COOKIE_ACL_BASE, matches, instructions, operation);
+            addFlowEntryToList(flowEntries, Uint64.valueOf(port.getDpId()), getAclFilterCumDispatcherTable(),
+                    flowId, flowPriority, 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, operation);
 
             if (addOrRemove != NwConstants.DEL_FLOW) {
                 programAclForExistingTrafficTable(port, ace, addOrRemove, flowName, matches, flowPriority);
@@ -396,8 +466,8 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         }
     }
 
-    protected void programAceSpecificFlows(AclInterface port, String aclName, Ace ace,
-            Map<String, List<MatchInfoBase>> flowMap, Uuid remoteAclId, int addOrRemove) {
+    protected void programAceSpecificFlows(List<FlowEntity> flowEntries, AclInterface port, String aclName, Ace ace,
+            @Nullable Map<String, List<MatchInfoBase>> flowMap, Uuid remoteAclId, int addOrRemove) {
         if (null == flowMap) {
             return;
         }
@@ -416,15 +486,14 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
             List<MatchInfoBase> matches = entry.getValue();
             matches.addAll(lportAndAclMatches);
             String flowId = flowName + this.directionString + "_" + port.getDpId() + "_" + port.getLPortTag() + "_"
-                    + ace.getKey().getRuleName();
+                    + ace.key().getRuleName();
 
             int operation = addOrRemove == NwConstants.MOD_FLOW ? NwConstants.DEL_FLOW : addOrRemove;
-            syncFlow(port.getDpId(), getAclRuleBasedFilterTable(), flowId, flowPriority, "ACL", 0, 0,
-                    AclConstants.COOKIE_ACL_BASE, matches, instructions, operation);
+            addFlowEntryToList(flowEntries, Uint64.valueOf(port.getDpId()), getAclRuleBasedFilterTable(), flowId,
+                    flowPriority, 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, operation);
 
             if (addOrRemove != NwConstants.DEL_FLOW) {
-                programAclForExistingTrafficTable(port, ace, addOrRemove, flowName, matches,
-                        flowPriority);
+                programAclForExistingTrafficTable(port, ace, addOrRemove, flowName, matches, flowPriority);
             }
         }
     }
@@ -433,7 +502,7 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
             List<MatchInfoBase> matches, Integer priority) {
         AceIp acl = (AceIp) ace.getMatches().getAceType();
         final String newFlowName = flowName + this.directionString + "_" + port.getDpId() + "_" + port.getLPortTag()
-                + "_" + ((acl.getAceIpVersion() instanceof AceIpv4) ? "_IPv4" : "_IPv6") + "_FlowAfterRuleDeleted";
+                + "_" + (acl.getAceIpVersion() instanceof AceIpv4 ? "_IPv4" : "_IPv6") + "_FlowAfterRuleDeleted";
 
         final List<MatchInfoBase> newMatches =
                 matches.stream().filter(obj -> !(obj instanceof NxMatchCtState || obj instanceof MatchMetadata))
@@ -444,10 +513,12 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         List<InstructionInfo> instructions =
                 AclServiceUtils.createCtMarkInstructionForNewState(getAclFilterCumDispatcherTable(), port.getElanId());
         // Reversing the flow add/delete operation for this table.
-        int operation = (addOrRemove == NwConstants.ADD_FLOW) ? NwConstants.DEL_FLOW : NwConstants.ADD_FLOW;
-        syncFlow(port.getDpId(), getAclForExistingTrafficTable(), newFlowName, priority, "ACL", 0,
-                AclServiceUtils.getHardTimoutForApplyStatefulChangeOnExistingTraffic(ace, aclServiceUtils),
+        List<FlowEntity> flowEntries = new ArrayList<>();
+        int operation = addOrRemove == NwConstants.ADD_FLOW ? NwConstants.DEL_FLOW : NwConstants.ADD_FLOW;
+        addFlowEntryToList(flowEntries, Uint64.valueOf(port.getDpId()), getAclForExistingTrafficTable(), newFlowName,
+                priority, 0, AclServiceUtils.getHardTimoutForApplyStatefulChangeOnExistingTraffic(ace, aclServiceUtils),
                 AclConstants.COOKIE_ACL_BASE, newMatches, instructions, operation);
+        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, operation);
     }
 
     @Override
@@ -456,8 +527,14 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
             LOG.warn("Unable to find DP Id from ACL interface with id {}", port.getInterfaceId());
             return false;
         }
-        programAcl(port, Action.REMOVE, NwConstants.DEL_FLOW);
-        updateRemoteAclFilterTable(port, NwConstants.DEL_FLOW);
+        List<FlowEntity> flowEntries = new ArrayList<>();
+        if (port.getInterfaceType() == InterfaceType.DhcpService) {
+            programDhcpService(flowEntries, port, Action.REMOVE, NwConstants.DEL_FLOW);
+        } else {
+            programAcl(flowEntries, port, Action.REMOVE, NwConstants.DEL_FLOW);
+            updateRemoteAclFilterTable(flowEntries, port, NwConstants.DEL_FLOW);
+        }
+        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, NwConstants.DEL_FLOW);
         return true;
     }
 
@@ -466,7 +543,9 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         if (!port.isPortSecurityEnabled() || port.getDpId() == null) {
             return false;
         }
-        programAceRule(port, aclName, ace, NwConstants.ADD_FLOW);
+        List<FlowEntity> flowEntries = new ArrayList<>();
+        programAceRule(flowEntries, port, aclName, ace, NwConstants.ADD_FLOW);
+        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, NwConstants.ADD_FLOW);
         return true;
     }
 
@@ -475,7 +554,9 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         if (!port.isPortSecurityEnabled() || port.getDpId() == null) {
             return false;
         }
-        programAceRule(port, aclName, ace, NwConstants.MOD_FLOW);
+        List<FlowEntity> flowEntries = new ArrayList<>();
+        programAceRule(flowEntries, port, aclName, ace, NwConstants.MOD_FLOW);
+        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, NwConstants.DEL_FLOW);
         return true;
     }
 
@@ -498,27 +579,66 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
      */
     protected abstract void unbindService(AclInterface aclInterface);
 
+    /**
+     * Programs DHCP Service flows.
+     *
+     * @param flowEntries the flow entries
+     * @param port the acl interface
+     * @param action add/modify/remove action
+     * @param addOrRemove addorRemove
+     */
+    protected abstract void programDhcpService(List<FlowEntity> flowEntries, AclInterface port,
+            Action action, int addOrRemove);
+
+    /**
+     * Programs DHCP service flows.
+     *
+     * @param flowEntries the flow entries
+     * @param port the acl interface
+     * @param allowedAddresses the allowed addresses
+     * @param addOrRemove addorRemove
+     */
+    protected abstract void processDhcpServiceUpdate(List<FlowEntity> flowEntries, AclInterface port,
+            List<AllowedAddressPairs> allowedAddresses, int addOrRemove);
+
     /**
      * Programs the anti-spoofing rules.
      *
+     * @param flowEntries the flow entries
      * @param port the acl interface
      * @param allowedAddresses the allowed addresses
      * @param action add/modify/remove action
      * @param addOrRemove addorRemove
      */
-    protected abstract void programAntiSpoofingRules(AclInterface port, List<AllowedAddressPairs> allowedAddresses,
-            Action action, int addOrRemove);
+    protected abstract void programAntiSpoofingRules(List<FlowEntity> flowEntries, AclInterface port,
+            List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove);
 
     /**
      * Programs broadcast rules.
      *
+     * @param flowEntries the flow entries
      * @param port the Acl Interface port
      * @param addOrRemove whether to delete or add flow
      */
-    protected abstract void programBroadcastRules(AclInterface port, int addOrRemove);
+    protected abstract void programBroadcastRules(List<FlowEntity> flowEntries, AclInterface port, Action action,
+            int addOrRemove);
+
+    /**
+     * Programs broadcast rules.
+     *
+     * @param flowEntries the flow entries
+     * @param port the Acl Interface port
+     * @param subnetInfoList the port subnet info list
+     * @param addOrRemove whether to delete or add flow
+     */
+    protected abstract void programSubnetBroadcastRules(List<FlowEntity> flowEntries, AclInterface port,
+            List<SubnetInfo> subnetInfoList, int addOrRemove);
+
+    protected abstract void programIcmpv6RARule(List<FlowEntity> flowEntries, AclInterface port,
+            List<SubnetInfo> subnets, int addOrRemove);
 
     /**
-     * Writes/remove the flow to/from the datastore.
+     * Add Flow to list.
      *
      * @param dpId
      *            the dpId
@@ -528,8 +648,6 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
      *            the flowId
      * @param priority
      *            the priority
-     * @param flowName
-     *            the flow name
      * @param idleTimeOut
      *            the idle timeout
      * @param hardTimeOut
@@ -543,24 +661,36 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
      * @param addOrRemove
      *            add or remove the entries.
      */
-    protected void syncFlow(BigInteger dpId, short tableId, String flowId, int priority, String flowName,
-            int idleTimeOut, int hardTimeOut, BigInteger cookie, List<? extends MatchInfoBase> matches,
+    protected void addFlowEntryToList(List<FlowEntity> flowEntries, Uint64 dpId, short tableId, String flowId,
+            int priority, int idleTimeOut, int hardTimeOut, Uint64 cookie, List<? extends MatchInfoBase> matches,
             List<InstructionInfo> instructions, int addOrRemove) {
-        jobCoordinator.enqueueJob(flowName, () -> {
-            if (addOrRemove == NwConstants.DEL_FLOW) {
-                FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority, flowName,
-                        idleTimeOut, hardTimeOut, cookie, matches, null);
-                LOG.trace("Removing Acl Flow DpnId {}, flowId {}", dpId, flowId);
-
-                return Collections.singletonList(mdsalManager.removeFlow(dpId, flowEntity));
+        List<InstructionInfo> instructionInfos = null;
+        if (addOrRemove == NwConstants.ADD_FLOW) {
+            instructionInfos = instructions;
+        }
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority,
+                flowId, idleTimeOut, hardTimeOut, cookie, matches, instructionInfos);
+        LOG.trace("Adding flow to list: DpnId {}, flowId {}", dpId, flowId);
+        flowEntries.add(flowEntity);
+    }
 
-            } else {
-                FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId, priority, flowName,
-                        idleTimeOut, hardTimeOut, cookie, matches, instructions);
-                LOG.trace("Installing DpnId {}, flowId {}", dpId, flowId);
-                return Collections.singletonList(mdsalManager.installFlow(dpId, flowEntity));
-            }
-        });
+    protected void programFlows(String jobName, List<FlowEntity> flowEntries, int addOrRemove) {
+        List<List<FlowEntity>> flowEntityParts = Lists.partition(flowEntries, AclConstants.FLOWS_PER_TRANSACTION);
+        for (List<FlowEntity> part : flowEntityParts) {
+            jobCoordinator.enqueueJob(jobName,
+                () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
+                    tx -> {
+                        if (addOrRemove == NwConstants.ADD_FLOW) {
+                            for (FlowEntity flowEntity: part) {
+                                mdsalManager.addFlow(tx, flowEntity);
+                            }
+                        } else {
+                            for (FlowEntity flowEntity: part) {
+                                mdsalManager.removeFlow(tx, flowEntity);
+                            }
+                        }
+                    })), AclConstants.JOB_MAX_RETRIES);
+        }
     }
 
     protected List<InstructionInfo> getDispatcherTableResubmitInstructions() {
@@ -589,7 +719,7 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
     protected void handleRemoteAclUpdate(Acl aclBefore, Acl aclAfter, Collection<AclInterface> portsBefore) {
         String aclName = aclAfter.getAclName();
         Collection<AclInterface> interfaceList = aclDataUtil.getInterfaceList(new Uuid(aclName));
-        if (interfaceList == null || interfaceList.isEmpty()) {
+        if (interfaceList.isEmpty()) {
             LOG.trace("handleRemoteAclUpdate: No interfaces found with ACL={}", aclName);
             return;
         }
@@ -602,26 +732,32 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         Set<Uuid> remoteAclsDeleted = new HashSet<>(remoteAclsBefore);
         remoteAclsDeleted.removeAll(remoteAclsAfter);
 
+        List<FlowEntity> addFlowEntries = new ArrayList<>();
+        List<FlowEntity> deleteFlowEntries = new ArrayList<>();
         if (!remoteAclsAdded.isEmpty() || !remoteAclsDeleted.isEmpty()) {
             // delete and add flows in ACL dispatcher table for all applicable
             // ports
             for (AclInterface portBefore : portsBefore) {
-                programAclDispatcherTable(portBefore, NwConstants.DEL_FLOW);
+                programAclDispatcherTable(deleteFlowEntries, portBefore, NwConstants.DEL_FLOW);
             }
             for (AclInterface port : interfaceList) {
-                programAclDispatcherTable(port, NwConstants.ADD_FLOW);
+                programAclDispatcherTable(addFlowEntries, port, NwConstants.ADD_FLOW);
             }
         }
         Set<BigInteger> dpns = interfaceList.stream().map(AclInterface::getDpId).collect(Collectors.toSet());
 
-        programRemoteAclTable(aclName, remoteAclsDeleted, dpns, NwConstants.DEL_FLOW);
-        programRemoteAclTable(aclName, remoteAclsAdded, dpns, NwConstants.ADD_FLOW);
+        programRemoteAclTable(deleteFlowEntries, aclName, remoteAclsDeleted, dpns, NwConstants.DEL_FLOW);
+        programRemoteAclTable(addFlowEntries, aclName, remoteAclsAdded, dpns, NwConstants.ADD_FLOW);
+
+        programFlows(aclName, deleteFlowEntries, NwConstants.DEL_FLOW);
+        programFlows(aclName, addFlowEntries, NwConstants.ADD_FLOW);
     }
 
-    private void programRemoteAclTable(String aclName, Set<Uuid> remoteAclIds, Set<BigInteger> dpns, int addOrRemove) {
+    private void programRemoteAclTable(List<FlowEntity> flowEntries, String aclName, Set<Uuid> remoteAclIds,
+            Set<BigInteger> dpns, int addOrRemove) {
         for (Uuid remoteAclId : remoteAclIds) {
             Collection<AclInterface> remoteAclInterfaces = aclDataUtil.getInterfaceList(remoteAclId);
-            if (remoteAclInterfaces == null || remoteAclInterfaces.isEmpty()) {
+            if (remoteAclInterfaces.isEmpty()) {
                 continue;
             }
             Set<AllowedAddressPairs> aaps =
@@ -632,7 +768,7 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
             if (addOrRemove == NwConstants.ADD_FLOW) {
                 for (BigInteger dpn : dpns) {
                     for (AllowedAddressPairs aap : aaps) {
-                        programRemoteAclTableFlow(dpn, aclTag, aap, addOrRemove);
+                        programRemoteAclTableFlow(flowEntries, Uint64.valueOf(dpn), aclTag, aap, addOrRemove);
                     }
                 }
             } else if (addOrRemove == NwConstants.DEL_FLOW) {
@@ -653,19 +789,20 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
 
                 for (BigInteger dpn : dpnsToOperate) {
                     for (AllowedAddressPairs aap : aaps) {
-                        programRemoteAclTableFlow(dpn, aclTag, aap, addOrRemove);
+                        programRemoteAclTableFlow(flowEntries, Uint64.valueOf(dpn), aclTag, aap, addOrRemove);
                     }
                 }
             }
         }
     }
 
-    private void updateRemoteAclFilterTable(AclInterface port, int addOrRemove) {
-        updateRemoteAclFilterTable(port, port.getSecurityGroups(), port.getAllowedAddressPairs(), addOrRemove);
+    private void updateRemoteAclFilterTable(List<FlowEntity> flowEntries, AclInterface port, int addOrRemove) {
+        updateRemoteAclFilterTable(flowEntries, port, port.getSecurityGroups(), port.getAllowedAddressPairs(),
+                addOrRemove);
     }
 
-    private void updateRemoteAclFilterTable(AclInterface port, List<Uuid> aclList, List<AllowedAddressPairs> aaps,
-            int addOrRemove) {
+    private void updateRemoteAclFilterTable(List<FlowEntity> flowEntries, AclInterface port, List<Uuid> aclList,
+            List<AllowedAddressPairs> aaps, int addOrRemove) {
         if (aclList == null) {
             LOG.debug("Port {} without SGs", port.getInterfaceId());
             return;
@@ -677,24 +814,27 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
             if (aclDataUtil.getRemoteAcl(aclId, this.direction) != null) {
                 Integer aclTag = aclServiceUtils.getAclTag(aclId);
                 if (addOrRemove == NwConstants.ADD_FLOW) {
-                    syncRemoteAclTable(portId, aclId, aclTag, aaps, addOrRemove);
-                } else if (addOrRemove == NwConstants.DEL_FLOW) {
-                    // Synchronizing during delete operation as there are
-                    // look-ups for AclPortsLookup data.
-                    synchronized (aclId.getValue().intern()) {
-                        syncRemoteAclTable(portId, aclId, aclTag, aaps, addOrRemove);
-                    }
+                    syncRemoteAclTable(flowEntries, portId, aclId, aclTag, aaps, addOrRemove);
+                }
+                else if (addOrRemove == NwConstants.DEL_FLOW) {
+                    jobCoordinator.enqueueJob(aclId.getValue(), () -> {
+                        List<FlowEntity> remoteTableFlowEntries = new ArrayList<>();
+                        syncRemoteAclTable(remoteTableFlowEntries, portId, aclId, aclTag, aaps, addOrRemove);
+                        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + aclId.getValue(),
+                                remoteTableFlowEntries, NwConstants.DEL_FLOW);
+                        return Collections.emptyList();
+                    });
                 }
             }
         }
         Set<Uuid> remoteAclIds = aclServiceUtils.getRemoteAclIdsByDirection(aclList, direction);
         for (Uuid remoteAclId : remoteAclIds) {
-            syncRemoteAclTableFromOtherDpns(port, remoteAclId, addOrRemove);
+            syncRemoteAclTableFromOtherDpns(flowEntries, port, remoteAclId, addOrRemove);
         }
     }
 
-    private void syncRemoteAclTable(String portId, Uuid acl, Integer aclTag, List<AllowedAddressPairs> aaps,
-            int addOrRemove) {
+    private void syncRemoteAclTable(List<FlowEntity> flowEntries, String portId, Uuid acl, Integer aclTag,
+            List<AllowedAddressPairs> aaps, int addOrRemove) {
         Map<String, Set<AclInterface>> mapAclWithPortSet = aclDataUtil.getRemoteAclInterfaces(acl, this.direction);
         Set<BigInteger> dpns = collectDpns(mapAclWithPortSet);
         for (AllowedAddressPairs aap : aaps) {
@@ -708,15 +848,16 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
                 continue;
             }
             for (BigInteger dpId : dpns) {
-                programRemoteAclTableFlow(dpId, aclTag, aap, addOrRemove);
+                programRemoteAclTableFlow(flowEntries, Uint64.valueOf(dpId), aclTag, aap, addOrRemove);
             }
         }
     }
 
-    private void syncRemoteAclTableFromOtherDpns(AclInterface port, Uuid remoteAclId, int addOrRemove) {
+    private void syncRemoteAclTableFromOtherDpns(List<FlowEntity> flowEntries, AclInterface port, Uuid remoteAclId,
+            int addOrRemove) {
         Collection<AclInterface> aclInterfaces = aclDataUtil.getInterfaceList(remoteAclId);
 
-        if (aclInterfaces != null && !aclInterfaces.isEmpty() && isFirstPortInDpnWithRemoteAclId(port, remoteAclId)) {
+        if (!aclInterfaces.isEmpty() && isFirstPortInDpnWithRemoteAclId(port, remoteAclId)) {
             Integer aclTag = aclServiceUtils.getAclTag(remoteAclId);
             for (AclInterface aclInterface : aclInterfaces) {
                 if (port.getInterfaceId().equals(aclInterface.getInterfaceId())) {
@@ -724,7 +865,8 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
                 }
                 for (AllowedAddressPairs aap : aclInterface.getAllowedAddressPairs()) {
                     if (AclServiceUtils.isNotIpAllNetwork(aap)) {
-                        programRemoteAclTableFlow(port.getDpId(), aclTag, aap, addOrRemove);
+                        programRemoteAclTableFlow(flowEntries, Uint64.valueOf(port.getDpId()),
+                            aclTag, aap, addOrRemove);
                     }
                 }
             }
@@ -751,28 +893,10 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         return true;
     }
 
-    protected abstract void programRemoteAclTableFlow(BigInteger dpId, Integer aclTag, AllowedAddressPairs aap,
-            int addOrRemove);
+    protected abstract void programRemoteAclTableFlow(List<FlowEntity> flowEntries, Uint64 dpId, Integer aclTag,
+            AllowedAddressPairs aap, int addOrRemove);
 
-    protected String getOperAsString(int flowOper) {
-        String oper;
-        switch (flowOper) {
-            case NwConstants.ADD_FLOW:
-                oper = "Add";
-                break;
-            case NwConstants.DEL_FLOW:
-                oper = "Del";
-                break;
-            case NwConstants.MOD_FLOW:
-                oper = "Mod";
-                break;
-            default:
-                oper = "UNKNOWN";
-        }
-        return oper;
-    }
-
-    protected Set<BigInteger> collectDpns(Map<String, Set<AclInterface>> mapAclWithPortSet) {
+    protected Set<BigInteger> collectDpns(@Nullable Map<String, Set<AclInterface>> mapAclWithPortSet) {
         Set<BigInteger> dpns = new HashSet<>();
         if (mapAclWithPortSet == null) {
             return dpns;
@@ -791,6 +915,7 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
     /**
      * Programs the port specific fixed rules.
      *
+     * @param flowEntries the flow entries
      * @param dpId the dp id
      * @param allowedAddresses the allowed addresses
      * @param lportTag the lport tag
@@ -798,42 +923,43 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
      * @param action the action
      * @param write whether to add or remove the flow.
      */
-    protected void programAclPortSpecificFixedRules(BigInteger dpId, List<AllowedAddressPairs> allowedAddresses,
-            int lportTag, String portId, Action action, int write) {
-        programGotoClassifierTableRules(dpId, allowedAddresses, lportTag, write);
+    protected void programAclPortSpecificFixedRules(List<FlowEntity> flowEntries, Uint64 dpId,
+            List<AllowedAddressPairs> allowedAddresses, int lportTag, String portId, Action action, int write) {
+        programGotoClassifierTableRules(flowEntries, dpId, allowedAddresses, lportTag, write);
         if (action == Action.ADD || action == Action.REMOVE) {
-            programConntrackRecircRules(dpId, allowedAddresses, lportTag, portId, write);
-            programPortSpecificDropRules(dpId, lportTag, write);
-            programAclCommitRules(dpId, lportTag, portId, write);
+            programConntrackRecircRules(flowEntries, dpId, allowedAddresses, lportTag, portId, write);
+            programPortSpecificDropRules(flowEntries, dpId, lportTag, write);
+            programAclCommitRules(flowEntries, dpId, lportTag, portId, write);
         }
         LOG.info("programAclPortSpecificFixedRules: flows for dpId={}, lportId={}, action={}, write={}", dpId, lportTag,
                 action, write);
     }
 
-    protected abstract void programGotoClassifierTableRules(BigInteger dpId, List<AllowedAddressPairs> aaps,
-            int lportTag, int addOrRemove);
+    protected abstract void programGotoClassifierTableRules(List<FlowEntity> flowEntries, Uint64 dpId,
+            List<AllowedAddressPairs> aaps, int lportTag, int addOrRemove);
 
     /**
      * Adds the rule to send the packet to the netfilter to check whether it is a known packet.
      *
+     * @param flowEntries the flow entries
      * @param dpId the dpId
      * @param aaps the allowed address pairs
      * @param lportTag the lport tag
      * @param portId the portId
      * @param addOrRemove whether to add or remove the flow
      */
-    protected void programConntrackRecircRules(BigInteger dpId, List<AllowedAddressPairs> aaps, int lportTag,
-            String portId, int addOrRemove) {
+    protected void programConntrackRecircRules(List<FlowEntity> flowEntries, Uint64 dpId,
+            List<AllowedAddressPairs> aaps, int lportTag, String portId, int addOrRemove) {
         if (AclServiceUtils.doesIpv4AddressExists(aaps)) {
-            programConntrackRecircRule(dpId, lportTag, portId, MatchEthernetType.IPV4, addOrRemove);
+            programConntrackRecircRule(flowEntries, dpId, lportTag, portId, MatchEthernetType.IPV4, addOrRemove);
         }
         if (AclServiceUtils.doesIpv6AddressExists(aaps)) {
-            programConntrackRecircRule(dpId, lportTag, portId, MatchEthernetType.IPV6, addOrRemove);
+            programConntrackRecircRule(flowEntries, dpId, lportTag, portId, MatchEthernetType.IPV6, addOrRemove);
         }
     }
 
-    protected void programConntrackRecircRule(BigInteger dpId, int lportTag, String portId,
-            MatchEthernetType matchEtherType, int addOrRemove) {
+    protected void programConntrackRecircRule(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
+            String portId, MatchEthernetType matchEtherType, int addOrRemove) {
         List<MatchInfoBase> matches = new ArrayList<>();
         matches.add(matchEtherType);
         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
@@ -852,83 +978,97 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         }
 
         String flowName =
-                this.directionString + "_Fixed_Conntrk_" + dpId + "_" + lportTag + "_" + matchEtherType + "_Recirc";
-        syncFlow(dpId, getAclConntrackSenderTable(), flowName, AclConstants.ACL_DEFAULT_PRIORITY, "ACL", 0, 0,
-                AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
+                this.directionString + "_Fixed_Conntrk_" + dpId.toString() + "_"
+                    + lportTag + "_" + matchEtherType + "_Recirc";
+        addFlowEntryToList(flowEntries, dpId, getAclConntrackSenderTable(), flowName,
+                AclConstants.ACL_DEFAULT_PRIORITY, 0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions,
+                addOrRemove);
     }
 
     /**
      * Adds the rules to drop the unknown/invalid packets .
      *
+     * @param flowEntries the flow entries
      * @param dpId the dpId
      * @param lportTag the lport tag
      * @param addOrRemove whether to add or remove the flow
      */
-    protected void programPortSpecificDropRules(BigInteger dpId, int lportTag, int addOrRemove) {
+    protected void programPortSpecificDropRules(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
+            int addOrRemove) {
         LOG.debug("Programming Drop Rules: DpId={}, lportTag={}, addOrRemove={}", dpId, lportTag, addOrRemove);
-        programConntrackInvalidDropRule(dpId, lportTag, addOrRemove);
-        programAclRuleMissDropRule(dpId, lportTag, addOrRemove);
+        programConntrackInvalidDropRule(flowEntries, dpId, lportTag, addOrRemove);
+        programAclRuleMissDropRule(flowEntries, dpId, lportTag, addOrRemove);
     }
 
     /**
      * Adds the rule to drop the conntrack invalid packets .
      *
+     * @param flowEntries the flow entries
      * @param dpId the dpId
      * @param lportTag the lport tag
      * @param addOrRemove whether to add or remove the flow
      */
-    protected void programConntrackInvalidDropRule(BigInteger dpId, int lportTag, int addOrRemove) {
+    protected void programConntrackInvalidDropRule(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
+            int addOrRemove) {
         List<MatchInfoBase> matches = AclServiceOFFlowBuilder.addLPortTagMatches(lportTag,
                 AclConstants.TRACKED_INV_CT_STATE, AclConstants.TRACKED_INV_CT_STATE_MASK, serviceMode);
         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
 
-        String flowId = this.directionString + "_Fixed_Conntrk_Drop" + dpId + "_" + lportTag + "_Tracked_Invalid";
-        syncFlow(dpId, getAclFilterCumDispatcherTable(), flowId, AclConstants.CT_STATE_TRACKED_INVALID_PRIORITY, "ACL",
-                0, 0, AclConstants.COOKIE_ACL_DROP_FLOW, matches, instructions, addOrRemove);
+        String flowId = this.directionString + "_Fixed_Conntrk_Drop" + dpId.toString()
+                            + "_" + lportTag + "_Tracked_Invalid";
+        addFlowEntryToList(flowEntries, dpId, getAclFilterCumDispatcherTable(), flowId,
+                AclConstants.CT_STATE_TRACKED_INVALID_PRIORITY, 0, 0, AclServiceUtils.getDropFlowCookie(lportTag),
+                matches, instructions, addOrRemove);
     }
 
     /**
      * Program ACL rule miss drop rule for a port.
      *
+     * @param flowEntries the flow entries
      * @param dpId the dp id
      * @param lportTag the lport tag
      * @param addOrRemove the add or remove
      */
-    protected void programAclRuleMissDropRule(BigInteger dpId, int lportTag, int addOrRemove) {
+    protected void programAclRuleMissDropRule(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
+            int addOrRemove) {
         List<MatchInfoBase> matches = new ArrayList<>();
         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
 
-        String flowId = this.directionString + "_Fixed_Acl_Rule_Miss_Drop_" + dpId + "_" + lportTag;
-        syncFlow(dpId, getAclFilterCumDispatcherTable(), flowId, AclConstants.ACL_PORT_SPECIFIC_DROP_PRIORITY, "ACL", 0,
-                0, AclConstants.COOKIE_ACL_DROP_FLOW, matches, instructions, addOrRemove);
+        String flowId = this.directionString + "_Fixed_Acl_Rule_Miss_Drop_" + dpId.toString() + "_" + lportTag;
+        addFlowEntryToList(flowEntries, dpId, getAclFilterCumDispatcherTable(), flowId,
+                AclConstants.ACL_PORT_SPECIFIC_DROP_PRIORITY, 0, 0, AclServiceUtils.getDropFlowCookie(lportTag),
+                matches, instructions, addOrRemove);
     }
 
     /**
      * Program acl commit rules.
      *
+     * @param flowEntries the flow entries
      * @param dpId the dp id
      * @param lportTag the lport tag
      * @param portId the port id
      * @param addOrRemove the add or remove
      */
-    protected void programAclCommitRules(BigInteger dpId, int lportTag, String portId, int addOrRemove) {
-        programAclCommitRuleForConntrack(dpId, lportTag, portId, MatchEthernetType.IPV4, addOrRemove);
-        programAclCommitRuleForConntrack(dpId, lportTag, portId, MatchEthernetType.IPV6, addOrRemove);
-        programAclCommitRuleForNonConntrack(dpId, lportTag, addOrRemove);
+    protected void programAclCommitRules(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag, String portId,
+            int addOrRemove) {
+        programAclCommitRuleForConntrack(flowEntries, dpId, lportTag, portId, MatchEthernetType.IPV4, addOrRemove);
+        programAclCommitRuleForConntrack(flowEntries, dpId, lportTag, portId, MatchEthernetType.IPV6, addOrRemove);
+        programAclCommitRuleForNonConntrack(flowEntries, dpId, lportTag, addOrRemove);
     }
 
     /**
      * Program acl commit rule for conntrack.
      *
+     * @param flowEntries the flow entries
      * @param dpId the dp id
      * @param lportTag the lport tag
      * @param portId the port id
      * @param matchEtherType the match ether type
      * @param addOrRemove the add or remove
      */
-    protected void programAclCommitRuleForConntrack(BigInteger dpId, int lportTag, String portId,
-            MatchEthernetType matchEtherType, int addOrRemove) {
+    protected void programAclCommitRuleForConntrack(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
+            String portId, MatchEthernetType matchEtherType, int addOrRemove) {
         List<MatchInfoBase> matches = new ArrayList<>();
         matches.add(matchEtherType);
         matches.addAll(AclServiceUtils.buildMatchesForLPortTagAndConntrackClassifierType(lportTag,
@@ -945,23 +1085,27 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
             List<NxCtAction> ctActionsList =
                     Lists.newArrayList(new ActionNxConntrack.NxCtMark(AclConstants.CT_MARK_EST_STATE));
             actionsInfos.add(new ActionNxConntrack(2, 1, 0, elanId.intValue(), (short) 255, ctActionsList));
+            actionsInfos.add(new ActionNxCtClear());
         }
         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions(actionsInfos);
 
-        String flowName = directionString + "_Acl_Commit_Conntrack_" + dpId + "_" + lportTag + "_" + matchEtherType;
+        String flowName = directionString + "_Acl_Commit_Conntrack_" + dpId.toString()
+                            + "_" + lportTag + "_" + matchEtherType;
         // Flow for conntrack traffic to commit and resubmit to dispatcher
-        syncFlow(dpId, getAclCommitterTable(), flowName, AclConstants.ACL_DEFAULT_PRIORITY, "ACL", 0, 0,
-                AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
+        addFlowEntryToList(flowEntries, dpId, getAclCommitterTable(), flowName, AclConstants.ACL_DEFAULT_PRIORITY,
+                0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
     }
 
     /**
      * Program acl commit rule for non conntrack.
      *
+     * @param flowEntries the flow entries
      * @param dpId the dp id
      * @param lportTag the lport tag
      * @param addOrRemove the add or remove
      */
-    protected void programAclCommitRuleForNonConntrack(BigInteger dpId, int lportTag, int addOrRemove) {
+    protected void programAclCommitRuleForNonConntrack(List<FlowEntity> flowEntries, Uint64 dpId, int lportTag,
+            int addOrRemove) {
         List<MatchInfoBase> matches = new ArrayList<>();
         matches.addAll(AclServiceUtils.buildMatchesForLPortTagAndConntrackClassifierType(lportTag,
                 AclConntrackClassifierType.NON_CONNTRACK_SUPPORTED, serviceMode));
@@ -969,10 +1113,11 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
         String flowName = this.directionString + "_Acl_Commit_Non_Conntrack_" + dpId + "_" + lportTag;
         // Flow for non-conntrack traffic to resubmit to dispatcher
-        syncFlow(dpId, getAclCommitterTable(), flowName, AclConstants.ACL_DEFAULT_PRIORITY, "ACL", 0, 0,
-                AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
+        addFlowEntryToList(flowEntries, dpId, getAclCommitterTable(), flowName, AclConstants.ACL_DEFAULT_PRIORITY,
+                0, 0, AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
     }
 
+    @Nullable
     protected Long getElanIdFromAclInterface(String elanInterfaceName) {
         AclInterface aclInterface = aclInterfaceCache.get(elanInterfaceName);
         if (null != aclInterface) {
@@ -983,10 +1128,6 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
 
     protected abstract boolean isValidDirection(Class<? extends DirectionBase> direction);
 
-    protected abstract short getAclAntiSpoofingTable();
-
-    protected abstract short getAclConntrackClassifierTable();
-
     protected abstract short getAclConntrackSenderTable();
 
     protected abstract short getAclForExistingTrafficTable();