Remove GENIUS UTIL references in AclService Module
[netvirt.git] / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / AbstractAclServiceImpl.java
index 3f83ccceeb3025e6345bfb5509dafc51843e8513..738e78a8a651b720624ba20284efb839433792b9 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.netvirt.aclservice;
 
+import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
+
 import com.google.common.collect.Lists;
 import java.math.BigInteger;
 import java.util.ArrayList;
@@ -19,10 +21,9 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.SortedSet;
+import java.util.concurrent.ConcurrentMap;
 import java.util.stream.Collectors;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
-import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
@@ -39,6 +40,9 @@ import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchCtState;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
+import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
 import org.opendaylight.netvirt.aclservice.api.AclInterfaceCache;
 import org.opendaylight.netvirt.aclservice.api.AclServiceListener;
 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.Action;
@@ -49,7 +53,6 @@ import org.opendaylight.netvirt.aclservice.utils.AclDataUtil;
 import org.opendaylight.netvirt.aclservice.utils.AclServiceOFFlowBuilder;
 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.AccessListEntries;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
@@ -60,9 +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.port.subnets.port.subnet.SubnetInfo;
+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;
 
@@ -71,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;
@@ -96,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;
@@ -116,25 +119,34 @@ 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();
+        String portId = port.getInterfaceId();
         if (dpId == null || port.getLPortTag() == null) {
-            LOG.error("Unable to find DpId from ACL interface with id {}", port.getInterfaceId());
+            LOG.error("Unable to find DpId from ACL interface with id {}", portId);
             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", portId);
+                return false;
+            }
+            programAclWithAllowedAddress(flowEntries, port, port.getAllowedAddressPairs(),
+                    Action.ADD, NwConstants.ADD_FLOW);
+            updateRemoteAclFilterTable(port, NwConstants.ADD_FLOW);
+        }
+        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + portId, 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);
@@ -177,61 +189,91 @@ 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);
+        if (!deletedAaps.isEmpty()) {
+            programAclWithAllowedAddress(deleteFlowEntries, portBefore, deletedAaps, Action.UPDATE,
+                    NwConstants.DEL_FLOW);
             updateRemoteAclFilterTable(portBefore, portBefore.getSecurityGroups(), deletedAaps, NwConstants.DEL_FLOW);
         }
-        if (addedAaps != null && !addedAaps.isEmpty()) {
-            programAclWithAllowedAddress(portAfter, addedAaps, Action.UPDATE, NwConstants.ADD_FLOW);
+        if (!addedAaps.isEmpty()) {
+            programAclWithAllowedAddress(addFlowEntries, portAfter, addedAaps, Action.UPDATE, NwConstants.ADD_FLOW);
             updateRemoteAclFilterTable(portAfter, portAfter.getSecurityGroups(), addedAaps, NwConstants.ADD_FLOW);
         }
         if (portAfter.getSubnetInfo() != null && portBefore.getSubnetInfo() == null) {
-            programBroadcastRules(portAfter, NwConstants.ADD_FLOW);
+            programBroadcastRules(addFlowEntries, portAfter, Action.UPDATE, NwConstants.ADD_FLOW);
         }
-        handleSubnetChange(portBefore, portAfter);
+        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 handleSubnetChange(AclInterface portBefore, AclInterface portAfter) {
+    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(portAfter, deletedSubnets, NwConstants.DEL_FLOW);
+            programIcmpv6RARule(deleteFlowEntries, portAfter, deletedSubnets, NwConstants.DEL_FLOW);
+            programSubnetBroadcastRules(deleteFlowEntries, portAfter, deletedSubnets, NwConstants.DEL_FLOW);
         }
         if (addedSubnets != null && !addedSubnets.isEmpty()) {
-            programIcmpv6RARule(portAfter, addedSubnets, NwConstants.ADD_FLOW);
+            programIcmpv6RARule(addFlowEntries, portAfter, addedSubnets, NwConstants.ADD_FLOW);
+            programSubnetBroadcastRules(addFlowEntries, portAfter, addedSubnets, 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);
+    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(port, aclList, port.getAllowedAddressPairs(), addOrRemove);
-        programAclDispatcherTable(port, addOrRemove);
+        programAclDispatcherTable(flowEntries, port, addOrRemove);
     }
 
     protected SortedSet<Integer> getRemoteAclTags(AclInterface port) {
@@ -239,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());
@@ -248,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) {
@@ -265,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()
@@ -283,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));
@@ -296,37 +339,36 @@ 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, AclServiceUtils.getDropFlowCookie(port.getLPortTag()), matches, instructions, addOrRemove);
-    }
-
-    private void programAcl(AclInterface port, Action action, int addOrRemove) {
-        programAclWithAllowedAddress(port, port.getAllowedAddressPairs(), action, 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 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) {
@@ -340,10 +382,8 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
                 LOG.warn("The ACL {} not found in cache", aclUuid.getValue());
                 continue;
             }
-            AccessListEntries accessListEntries = acl.getAccessListEntries();
-            List<Ace> aceList = accessListEntries.getAce();
-            for (Ace ace: aceList) {
-                programAceRule(port, aclUuid.getValue(), ace, addOrRemove);
+            for (Ace ace : AclServiceUtils.aceList(acl)) {
+                programAceRule(flowEntries, port, aclUuid.getValue(), ace, addOrRemove);
             }
         }
         return true;
@@ -352,13 +392,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());
@@ -369,22 +420,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;
         }
@@ -400,8 +450,8 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
                     + 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);
@@ -409,8 +459,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;
         }
@@ -432,21 +482,25 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
                     + 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);
             }
         }
     }
 
     private void programAclForExistingTrafficTable(AclInterface port, Ace ace, int addOrRemove, String flowName,
             List<MatchInfoBase> matches, Integer priority) {
+        if (port == null || port.getElanId() == null) {
+            LOG.debug("Acl interface or elan id is null, No need to update traffic flow table.");
+            return;
+        }
+
         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))
@@ -457,10 +511,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
@@ -469,8 +525,15 @@ 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 {
+            programAclWithAllowedAddress(flowEntries, port, port.getAllowedAddressPairs(),
+                    Action.REMOVE, NwConstants.DEL_FLOW);
+            updateRemoteAclFilterTable(port, NwConstants.DEL_FLOW);
+        }
+        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + port.getInterfaceId(), flowEntries, NwConstants.DEL_FLOW);
         return true;
     }
 
@@ -479,7 +542,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;
     }
 
@@ -488,7 +553,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;
     }
 
@@ -511,29 +578,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(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 programBroadcastRules(AclInterface port, int addOrRemove);
+    protected abstract void programSubnetBroadcastRules(List<FlowEntity> flowEntries, AclInterface port,
+            List<SubnetInfo> subnetInfoList, int addOrRemove);
 
-    protected abstract void programIcmpv6RARule(AclInterface port, List<SubnetInfo> subnets, 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
@@ -543,8 +647,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
@@ -558,24 +660,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() {
@@ -604,7 +718,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;
         }
@@ -617,26 +731,43 @@ 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
+            // delete and add flows in ACL dispatcher table for all applicable ports
             for (AclInterface portBefore : portsBefore) {
-                programAclDispatcherTable(portBefore, NwConstants.DEL_FLOW);
+                if (portBefore.getDpId() != null) {
+                    programAclDispatcherTable(deleteFlowEntries, portBefore, NwConstants.DEL_FLOW);
+                } else {
+                    LOG.debug("Skip ACL dispatcher table update as DP ID for interface {} is not present.",
+                            portBefore.getInterfaceId());
+                }
             }
             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());
+        Set<BigInteger> dpns = interfaceList.stream().filter(port -> {
+            if (port.getDpId() == null) {
+                LOG.debug("Skip remote ACL table update as DP ID for interface {} is not present.",
+                        port.getInterfaceId());
+                return false;
+            }
+            return true;
+        }).map(AclInterface::getDpId).collect(Collectors.toSet());
+
+        programRemoteAclTable(deleteFlowEntries, aclName, remoteAclsDeleted, dpns, NwConstants.DEL_FLOW);
+        programRemoteAclTable(addFlowEntries, aclName, remoteAclsAdded, dpns, NwConstants.ADD_FLOW);
 
-        programRemoteAclTable(aclName, remoteAclsDeleted, dpns, NwConstants.DEL_FLOW);
-        programRemoteAclTable(aclName, remoteAclsAdded, dpns, NwConstants.ADD_FLOW);
+        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + aclName, deleteFlowEntries, NwConstants.DEL_FLOW);
+        programFlows(AclConstants.ACL_JOB_KEY_PREFIX + 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 =
@@ -644,10 +775,14 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
                             .filter(AclServiceUtils::isNotIpAllNetwork).collect(Collectors.toSet());
 
             Integer aclTag = aclServiceUtils.getAclTag(remoteAclId);
+            if (aclTag == null || aclTag == AclConstants.INVALID_ACL_TAG) {
+                LOG.error("aclTag={} is null or invalid for remoteAclId={}", aclTag, remoteAclId);
+                continue;
+            }
             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) {
@@ -668,7 +803,7 @@ 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);
                     }
                 }
             }
@@ -688,29 +823,43 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         String portId = port.getInterfaceId();
         LOG.trace("updateRemoteAclFilterTable for portId={}, aclList={}, aaps={}, addOrRemove={}", portId, aclList,
                 aaps, addOrRemove);
+
+        ConcurrentMap<Uuid, Map<String, Set<AclInterface>>> mapOfAclWithInterfacesList =
+                aclDataUtil.getRemoteAclInterfaces(aclList, this.direction);
         for (Uuid aclId : aclList) {
+            Map<String, Set<AclInterface>> mapAclWithPortSet = mapOfAclWithInterfacesList.get(aclId);
             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);
-                    }
+                if (aclTag == null || aclTag == AclConstants.INVALID_ACL_TAG) {
+                    LOG.error("aclTag={} is null or invalid for aclId={}", aclTag, aclId);
+                    continue;
                 }
+                jobCoordinator.enqueueJob(aclId.getValue().intern(), () -> {
+                    List<FlowEntity> flowEntries = new ArrayList<>();
+                    syncRemoteAclTable(flowEntries, portId, aclId, aclTag, aaps, mapAclWithPortSet, addOrRemove);
+                    programFlows(AclConstants.ACL_JOB_KEY_PREFIX + aclId.getValue(), flowEntries, addOrRemove);
+                    return Collections.emptyList();
+                });
             }
         }
         Set<Uuid> remoteAclIds = aclServiceUtils.getRemoteAclIdsByDirection(aclList, direction);
         for (Uuid remoteAclId : remoteAclIds) {
-            syncRemoteAclTableFromOtherDpns(port, remoteAclId, addOrRemove);
+            List<Uuid> aclIds = new ArrayList<Uuid>(port.getSecurityGroups());
+            aclIds.removeAll(aclList);
+            if (addOrRemove == NwConstants.DEL_FLOW && aclServiceUtils.doesRemoteAclIdExistsInAcls(aclIds, remoteAclId,
+                    this.direction)) {
+                LOG.debug("Skipping delete as remoteAclId {} is used with other ACE configured with port {}",
+                        remoteAclId, portId);
+                return;
+            }
+            List<FlowEntity> flowEntries = new ArrayList<>();
+            syncRemoteAclTableFromOtherDpns(flowEntries, port, remoteAclId, addOrRemove);
+            programFlows(AclConstants.ACL_JOB_KEY_PREFIX + remoteAclId.getValue(), flowEntries, addOrRemove);
         }
     }
 
-    private void syncRemoteAclTable(String portId, Uuid acl, Integer aclTag, List<AllowedAddressPairs> aaps,
-            int addOrRemove) {
-        Map<String, Set<AclInterface>> mapAclWithPortSet = aclDataUtil.getRemoteAclInterfaces(acl, this.direction);
+    private void syncRemoteAclTable(List<FlowEntity> flowEntries, String portId, Uuid acl, Integer aclTag,
+            List<AllowedAddressPairs> aaps, Map<String, Set<AclInterface>> mapAclWithPortSet, int addOrRemove) {
         Set<BigInteger> dpns = collectDpns(mapAclWithPortSet);
         for (AllowedAddressPairs aap : aaps) {
             if (!AclServiceUtils.isNotIpAllNetwork(aap)) {
@@ -723,23 +872,29 @@ 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);
+            if (aclTag == null || aclTag == AclConstants.INVALID_ACL_TAG) {
+                LOG.error("aclTag={} is null or invalid for remoteAclId={}", aclTag, remoteAclId);
+                return;
+            }
             for (AclInterface aclInterface : aclInterfaces) {
                 if (port.getInterfaceId().equals(aclInterface.getInterfaceId())) {
                     continue;
                 }
                 for (AllowedAddressPairs aap : aclInterface.getAllowedAddressPairs()) {
                     if (AclServiceUtils.isNotIpAllNetwork(aap)) {
-                        programRemoteAclTableFlow(port.getDpId(), aclTag, aap, addOrRemove);
+                        programRemoteAclTableFlow(flowEntries, Uint64.valueOf(port.getDpId()),
+                            aclTag, aap, addOrRemove);
                     }
                 }
             }
@@ -766,28 +921,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;
@@ -806,6 +943,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
@@ -813,42 +951,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));
@@ -867,83 +1006,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 + "_"
+                    + 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, AclServiceUtils.getDropFlowCookie(lportTag), 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, AclServiceUtils.getDropFlowCookie(lportTag), 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,
@@ -964,20 +1117,23 @@ public abstract class AbstractAclServiceImpl implements AclServiceListener {
         }
         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));
@@ -985,10 +1141,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) {
@@ -999,10 +1156,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();