ACL: Support for non-conntrack supported traffic.
[netvirt.git] / vpnservice / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / utils / AclServiceUtils.java
index 6cd6e08f4f0d03c414fe1ec334a17d2e451f8be8..06159bf5bb0547c9850eb3ec3c0e4c2ead237248 100644 (file)
@@ -9,12 +9,21 @@
 package org.opendaylight.netvirt.aclservice.utils;
 
 import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+import com.google.common.net.InetAddresses;
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import javax.inject.Inject;
@@ -23,11 +32,15 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.genius.interfacemanager.globals.InterfaceServiceUtil;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.NxMatchInfo;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
+import org.opendaylight.genius.mdsalutil.matches.MatchArpSpa;
+import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
 import org.opendaylight.genius.mdsalutil.matches.MatchIcmpv6;
 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
@@ -39,12 +52,14 @@ import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
 import org.opendaylight.genius.mdsalutil.matches.MatchUdpDestinationPort;
 import org.opendaylight.genius.mdsalutil.matches.MatchUdpSourcePort;
 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
+import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.MatchCriteria;
 import org.opendaylight.netvirt.aclservice.api.utils.AclInterface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AccessLists;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.Ipv4Acl;
 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.AclKey;
+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.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
@@ -54,6 +69,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
@@ -72,7 +88,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpc
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
@@ -83,10 +99,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.ser
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.config.rev160806.AclserviceConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.PortsSubnetIpPrefixes;
 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.ports.subnet.ip.prefixes.PortSubnetIpPrefixes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.ports.subnet.ip.prefixes.PortSubnetIpPrefixesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
@@ -102,10 +122,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Singleton
-@SuppressWarnings("deprecation")
 public final class AclServiceUtils {
 
     private static final Logger LOG = LoggerFactory.getLogger(AclServiceUtils.class);
+    public static final AclserviceConfig.DefaultBehavior DEFAULT_DENY = AclserviceConfig.DefaultBehavior.Deny;
+    public static final AclserviceConfig.DefaultBehavior DEFAULT_ALLOW = AclserviceConfig.DefaultBehavior.Allow;
 
     private final AclDataUtil aclDataUtil;
     private final AclserviceConfig config;
@@ -113,7 +134,6 @@ public final class AclServiceUtils {
 
     @Inject
     public AclServiceUtils(AclDataUtil aclDataUtil, AclserviceConfig config, IdManagerService idManager) {
-        super();
         this.aclDataUtil = aclDataUtil;
         this.config = config;
         this.idManager = idManager;
@@ -156,7 +176,7 @@ public final class AclServiceUtils {
         try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
             return tx.read(datastoreType, path).checkedGet();
         } catch (ReadFailedException e) {
-            LOG.warn("Failed to read InstanceIdentifier {} from {}", path, datastoreType, e);
+            LOG.error("Failed to read InstanceIdentifier {} from {}", path, datastoreType, e);
             return Optional.absent();
         }
     }
@@ -295,7 +315,7 @@ public final class AclServiceUtils {
      */
     public static List<MatchInfoBase> buildDhcpMatches(int srcPort, int dstPort, int lportTag,
             Class<? extends ServiceModeBase> serviceMode) {
-        List<MatchInfoBase> matches = new ArrayList<>(6);
+        List<MatchInfoBase> matches = new ArrayList<>(5);
         matches.add(MatchEthernetType.IPV4);
         matches.add(MatchIpProtocol.UDP);
         matches.add(new MatchUdpDestinationPort(dstPort));
@@ -345,6 +365,20 @@ public final class AclServiceUtils {
         return matches;
     }
 
+    public static List<MatchInfoBase> buildBroadcastIpV4Matches(String ipAddr) {
+        List<MatchInfoBase> matches = new ArrayList<>(2);
+        matches.add(new MatchEthernetDestination(new MacAddress(AclConstants.BROADCAST_MAC)));
+        matches.addAll(AclServiceUtils.buildIpMatches(new IpPrefixOrAddress(ipAddr.toCharArray()),
+                MatchCriteria.MATCH_DESTINATION));
+        return matches;
+    }
+
+    public static List<MatchInfoBase> buildL2BroadcastMatches() {
+        List<MatchInfoBase> matches = new ArrayList<>();
+        matches.add(new MatchEthernetDestination(new MacAddress(AclConstants.BROADCAST_MAC)));
+        return matches;
+    }
+
     /**
      * Builds the service id.
      *
@@ -381,7 +415,7 @@ public final class AclServiceUtils {
 
     public static List<Uuid> getUpdatedAclList(List<Uuid> updatedAclList, List<Uuid> currentAclList) {
         if (updatedAclList == null) {
-            return null;
+            return Collections.emptyList();
         }
         List<Uuid> newAclList = new ArrayList<>(updatedAclList);
         if (currentAclList == null) {
@@ -446,6 +480,33 @@ public final class AclServiceUtils {
         return dpId;
     }
 
+    public static List<String> getIpBroadcastAddresses(List<IpPrefixOrAddress> cidrs) {
+        List<String> ipBroadcastAddresses = new ArrayList<>();
+        for (IpPrefixOrAddress cidr : cidrs) {
+            IpPrefix cidrIpPrefix = cidr.getIpPrefix();
+            if (cidrIpPrefix != null) {
+                Ipv4Prefix cidrIpv4Prefix = cidrIpPrefix.getIpv4Prefix();
+                if (cidrIpv4Prefix != null) {
+                    ipBroadcastAddresses.add(getBroadcastAddressFromCidr(cidrIpv4Prefix.getValue()));
+                }
+            }
+        }
+        return ipBroadcastAddresses;
+    }
+
+    public static String getBroadcastAddressFromCidr(String cidr) {
+        String[] ipaddressValues = cidr.split("/");
+        int address = InetAddresses.coerceToInteger(InetAddresses.forString(ipaddressValues[0]));
+        int cidrPart = Integer.parseInt(ipaddressValues[1]);
+        int netmask = 0;
+        for (int j = 0; j < cidrPart; ++j) {
+            netmask |= 1 << 31 - j;
+        }
+        int network = address & netmask;
+        int broadcast = network | ~netmask;
+        return InetAddresses.toAddrString(InetAddresses.fromInteger(broadcast));
+    }
+
     /**
      * Builds the ip matches.
      *
@@ -487,24 +548,109 @@ public final class AclServiceUtils {
         return flowMatches;
     }
 
-    private List<MatchInfoBase> buildAclIdMetadataMatch(Uuid remoteAclId) {
+    /**
+     * Builds the arp ip matches.
+     * @param ipPrefixOrAddress the ip prefix or address
+     * @return the MatchInfoBase list
+     */
+    public static List<MatchInfoBase> buildArpIpMatches(IpPrefixOrAddress ipPrefixOrAddress) {
+        List<MatchInfoBase> flowMatches = new ArrayList<>();
+        IpPrefix ipPrefix = ipPrefixOrAddress.getIpPrefix();
+        if (ipPrefix != null) {
+            Ipv4Prefix ipv4Prefix = ipPrefix.getIpv4Prefix();
+            if (ipv4Prefix != null && !ipv4Prefix.getValue().equals(AclConstants.IPV4_ALL_NETWORK)) {
+                flowMatches.add(new MatchArpSpa(ipv4Prefix));
+            }
+        } else {
+            IpAddress ipAddress = ipPrefixOrAddress.getIpAddress();
+            if (ipAddress != null && ipAddress.getIpv4Address() != null) {
+                flowMatches.add(new MatchArpSpa(ipAddress.getIpv4Address().getValue(), "32"));
+            }
+        }
+        return flowMatches;
+    }
+
+    private List<MatchInfoBase> buildAclIdMetadataMatches(Uuid remoteAclId) {
         List<MatchInfoBase> flowMatches = new ArrayList<>();
         BigInteger aclId = buildAclId(remoteAclId);
-        if (aclId.intValue() != AclConstants.INVALID_ACL_ID) {
-            MatchMetadata metadataMatch = new MatchMetadata(aclId.shiftLeft(1),
-                    MetaDataUtil.METADATA_MASK_REMOTE_ACL_ID);
+        if (aclId.intValue() != AclConstants.INVALID_ACL_TAG) {
+            MatchMetadata metadataMatch = new MatchMetadata(getAclTagMetadata(aclId),
+                    MetaDataUtil.METADATA_MASK_REMOTE_ACL_TAG);
             flowMatches.add(metadataMatch);
         } else {
-            LOG.warn("Failed building metadata match for Acl id match. Failed to allocate id");
+            LOG.error("Failed building metadata match for Acl id match. Failed to allocate id");
         }
         return flowMatches;
     }
 
+    public static MatchInfoBase buildAclTagMetadataMatch(Integer aclTag) {
+        return new MatchMetadata(getAclTagMetadata(BigInteger.valueOf(aclTag)),
+                MetaDataUtil.METADATA_MASK_REMOTE_ACL_TAG);
+    }
+
     public BigInteger buildAclId(Uuid remoteAclId) {
-        Integer aclId = allocateAclId(remoteAclId.getValue());
+        Integer aclId = allocateAclTag(remoteAclId.getValue());
         return BigInteger.valueOf(aclId);
     }
 
+    public static BigInteger getAclTagMetadata(BigInteger aclTag) {
+        return aclTag.shiftLeft(4);
+    }
+
+    /**
+     * Does IPv4 address exists in the list of allowed address pair.
+     *
+     * @param aaps the allowed address pairs
+     * @return true, if successful
+     */
+    public static boolean doesIpv4AddressExists(List<AllowedAddressPairs> aaps) {
+        if (aaps == null) {
+            return false;
+        }
+        for (AllowedAddressPairs aap : aaps) {
+            IpPrefixOrAddress ipPrefixOrAddress = aap.getIpAddress();
+            IpPrefix ipPrefix = ipPrefixOrAddress.getIpPrefix();
+            if (ipPrefix != null) {
+                if (ipPrefix.getIpv4Prefix() != null) {
+                    return true;
+                }
+            } else {
+                IpAddress ipAddress = ipPrefixOrAddress.getIpAddress();
+                if (ipAddress != null && ipAddress.getIpv4Address() != null) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Does IPv6 address exists in the list of allowed address pair.
+     *
+     * @param aaps the allowed address pairs
+     * @return true, if successful
+     */
+    public static boolean doesIpv6AddressExists(List<AllowedAddressPairs> aaps) {
+        if (aaps == null) {
+            return false;
+        }
+        for (AllowedAddressPairs aap : aaps) {
+            IpPrefixOrAddress ipPrefixOrAddress = aap.getIpAddress();
+            IpPrefix ipPrefix = ipPrefixOrAddress.getIpPrefix();
+            if (ipPrefix != null) {
+                if (ipPrefix.getIpv6Prefix() != null) {
+                    return true;
+                }
+            } else {
+                IpAddress ipAddress = ipPrefixOrAddress.getIpAddress();
+                if (ipAddress != null && ipAddress.getIpv6Address() != null) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     /**
      * Gets the lport tag match.
      * Ingress match is based on metadata and egress match is based on masked reg6
@@ -514,7 +660,7 @@ public final class AclServiceUtils {
      * @return the lport tag match
      */
     public static MatchInfoBase buildLPortTagMatch(int lportTag, Class<? extends ServiceModeBase> serviceMode) {
-        if (serviceMode != null && serviceMode.isAssignableFrom(ServiceModeIngress.class)) {
+        if (serviceMode != null && serviceMode.isAssignableFrom(ServiceModeEgress.class)) {
             return new NxMatchRegister(NxmNxReg6.class, MetaDataUtil.getLportTagForReg6(lportTag).longValue(),
                     MetaDataUtil.getLportTagMaskForReg6());
         } else {
@@ -522,6 +668,44 @@ public final class AclServiceUtils {
         }
     }
 
+    public static List<MatchInfoBase> buildMatchesForLPortTagAndRemoteAclTag(Integer lportTag, Integer aclTag,
+            Class<? extends ServiceModeBase> serviceMode) {
+        List<MatchInfoBase> matches = new ArrayList<>();
+        if (serviceMode != null && serviceMode.isAssignableFrom(ServiceModeEgress.class)) {
+            matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
+            matches.add(AclServiceUtils.buildAclTagMetadataMatch(aclTag));
+        } else {
+            // In case of ingress service mode, only metadata is used for
+            // matching both lportTag and aclTag. Hence performing "or"
+            // operation on both lportTag and aclTag metadata.
+            BigInteger metaData =
+                    MetaDataUtil.getLportTagMetaData(lportTag).or(getAclTagMetadata(BigInteger.valueOf(aclTag)));
+            BigInteger metaDataMask = MetaDataUtil.METADATA_MASK_LPORT_TAG
+                    .or(MetaDataUtil.METADATA_MASK_REMOTE_ACL_TAG);
+            matches.add(new MatchMetadata(metaData, metaDataMask));
+        }
+        return matches;
+    }
+
+    public static InstructionWriteMetadata getWriteMetadataForAclClassifierType(
+            AclConntrackClassifierType conntrackClassifierType) {
+        return new InstructionWriteMetadata(
+                MetaDataUtil.getAclConntrackClassifierTypeFromMetaData(conntrackClassifierType.getValue()),
+                MetaDataUtil.METADATA_MASK_ACL_CONNTRACK_CLASSIFIER_TYPE);
+    }
+
+    public static InstructionWriteMetadata getWriteMetadataForRemoteAclTag(Integer remoteAclTag) {
+        return new InstructionWriteMetadata(getAclTagMetadata(BigInteger.valueOf(remoteAclTag)),
+                MetaDataUtil.METADATA_MASK_REMOTE_ACL_TAG);
+    }
+
+    public static MatchInfoBase buildAclConntrackClassifierTypeMatch(
+            AclConntrackClassifierType conntrackSupportedType) {
+        return new MatchMetadata(
+                MetaDataUtil.getAclConntrackClassifierTypeFromMetaData(conntrackSupportedType.getValue()),
+                MetaDataUtil.METADATA_MASK_ACL_CONNTRACK_CLASSIFIER_TYPE);
+    }
+
     public static List<Ace> getAceWithRemoteAclId(DataBroker dataBroker, AclInterface port, Uuid remoteAcl) {
         List<Ace> remoteAclRuleList = new ArrayList<>();
         List<Uuid> aclList = port.getSecurityGroups();
@@ -538,37 +722,44 @@ public final class AclServiceUtils {
         return remoteAclRuleList;
     }
 
-    public Map<String, List<MatchInfoBase>> getFlowForRemoteAcl(Uuid remoteAclId, String ignoreInterfaceId,
-            Map<String, List<MatchInfoBase>> flowMatchesMap, boolean isSourceIpMacMatch) {
-        List<AclInterface> interfaceList = aclDataUtil.getInterfaceList(remoteAclId);
-        if (flowMatchesMap == null || interfaceList == null || interfaceList.isEmpty()) {
-            return null;
+    public Map<String, List<MatchInfoBase>> getFlowForRemoteAcl(AclInterface aclInterface, Uuid remoteAclId,
+            String ignoreInterfaceId, Map<String, List<MatchInfoBase>> flowMatchesMap, boolean isSourceIpMacMatch) {
+        boolean singleAcl = false;
+        Collection<AclInterface> interfaceList = null;
+        if (aclInterface.getSecurityGroups() != null && aclInterface.getSecurityGroups().size() == 1) {
+            singleAcl = true;
+        } else {
+            interfaceList = aclDataUtil.getInterfaceList(remoteAclId);
+            if (flowMatchesMap == null || interfaceList == null || interfaceList.isEmpty()) {
+                return null;
+            }
         }
         Map<String, List<MatchInfoBase>> updatedFlowMatchesMap = new HashMap<>();
         MatchInfoBase ipv4Match = MatchEthernetType.IPV4;
         MatchInfoBase ipv6Match = MatchEthernetType.IPV6;
-        for (String flowName : flowMatchesMap.keySet()) {
-            List<MatchInfoBase> flows = flowMatchesMap.get(flowName);
-
-            List<MatchInfoBase> matchInfoBaseList = addFlowMatchForAclId(remoteAclId, flows);
-            String flowId = flowName + "_remoteACL_id_" + remoteAclId.getValue();
-            updatedFlowMatchesMap.put(flowId, matchInfoBaseList);
+        for (Entry<String, List<MatchInfoBase>> entry : flowMatchesMap.entrySet()) {
+            String flowName = entry.getKey();
+            List<MatchInfoBase> flows = entry.getValue();
+            if (singleAcl) {
+                LOG.debug("port {} is in only one SG. "
+                        + "Doesn't adding it's IPs {} to matches (handled in acl id match)",
+                        aclInterface.getLPortTag(), aclInterface.getAllowedAddressPairs());
+                List<MatchInfoBase> matchInfoBaseList = addFlowMatchForAclId(remoteAclId, flows);
+                String flowId = flowName + "_remoteACL_id_" + remoteAclId.getValue();
+                updatedFlowMatchesMap.put(flowId, matchInfoBaseList);
+                continue;
+            }
             for (AclInterface port : interfaceList) {
                 if (port.getInterfaceId().equals(ignoreInterfaceId)) {
                     continue;
                 }
 
-                if (port.getSecurityGroups() != null && port.getSecurityGroups().size() == 1) {
-                    LOG.debug(
-                            "port {} is in only one SG. "
-                                    + "Doesn't adding it's IPs {} to matches (handled in acl id match)",
-                            port.getLPortTag(), port.getAllowedAddressPairs());
-                    continue;
-                }
                 // get allow address pair
                 List<AllowedAddressPairs> allowedAddressPair = port.getAllowedAddressPairs();
                 // iterate over allow address pair and update match type
                 for (AllowedAddressPairs aap : allowedAddressPair) {
+                    List<MatchInfoBase> matchInfoBaseList;
+                    String flowId;
                     if (flows.contains(ipv4Match) && isIPv4Address(aap) && isNotIpv4AllNetwork(aap)) {
                         matchInfoBaseList = updateAAPMatches(isSourceIpMacMatch, flows, aap);
                         flowId = flowName + "_ipv4_remoteACL_interface_aap_" + getAapFlowId(aap);
@@ -588,7 +779,7 @@ public final class AclServiceUtils {
         return config;
     }
 
-    private static boolean isIPv4Address(AllowedAddressPairs aap) {
+    public static boolean isIPv4Address(AllowedAddressPairs aap) {
         IpPrefixOrAddress ipPrefixOrAddress = aap.getIpAddress();
         IpPrefix ipPrefix = ipPrefixOrAddress.getIpPrefix();
         if (ipPrefix != null) {
@@ -597,7 +788,7 @@ public final class AclServiceUtils {
             }
         } else {
             IpAddress ipAddress = ipPrefixOrAddress.getIpAddress();
-            if (ipAddress.getIpv4Address() != null) {
+            if (ipAddress != null && ipAddress.getIpv4Address() != null) {
                 return true;
             }
         }
@@ -613,8 +804,9 @@ public final class AclServiceUtils {
         Map<String, List<MatchInfoBase>> updatedFlowMatchesMap = new HashMap<>();
         MatchInfoBase ipv4Match = MatchEthernetType.IPV4;
         MatchInfoBase ipv6Match = MatchEthernetType.IPV6;
-        for (String flowName : flowMatchesMap.keySet()) {
-            List<MatchInfoBase> flows = flowMatchesMap.get(flowName);
+        for (Entry<String, List<MatchInfoBase>> entry : flowMatchesMap.entrySet()) {
+            String flowName = entry.getKey();
+            List<MatchInfoBase> flows = entry.getValue();
             // iterate over allow address pair and update match type
             for (AllowedAddressPairs aap : syncAllowedAddresses) {
                 List<MatchInfoBase> matchInfoBaseList;
@@ -685,6 +877,22 @@ public final class AclServiceUtils {
                 .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
     }
 
+    public static List<IpPrefixOrAddress> getSubnetIpPrefixes(DataBroker broker, String portId) {
+        InstanceIdentifier<PortSubnetIpPrefixes> id = InstanceIdentifier.builder(PortsSubnetIpPrefixes.class)
+                .child(PortSubnetIpPrefixes.class, new PortSubnetIpPrefixesKey(portId)).build();
+        Optional<PortSubnetIpPrefixes> portSubnetIpPrefixes = read(broker, LogicalDatastoreType.OPERATIONAL, id);
+        if (portSubnetIpPrefixes.isPresent()) {
+            return portSubnetIpPrefixes.get().getSubnetIpPrefixes();
+        }
+        return null;
+    }
+
+    public static void deleteSubnetIpPrefixes(DataBroker broker, String portId) {
+        InstanceIdentifier<PortSubnetIpPrefixes> id = InstanceIdentifier.builder(PortsSubnetIpPrefixes.class)
+                    .child(PortSubnetIpPrefixes.class, new PortSubnetIpPrefixesKey(portId)).build();
+        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+    }
+
     private static List<MatchInfoBase> updateAAPMatches(boolean isSourceIpMacMatch, List<MatchInfoBase> flows,
                                                         AllowedAddressPairs aap) {
         List<MatchInfoBase> matchInfoBaseList;
@@ -697,9 +905,9 @@ public final class AclServiceUtils {
         return matchInfoBaseList;
     }
 
-    private List<MatchInfoBase> addFlowMatchForAclId(Uuid remoteAclId, List<MatchInfoBase> flows) {
+    public List<MatchInfoBase> addFlowMatchForAclId(Uuid remoteAclId, List<MatchInfoBase> flows) {
         List<MatchInfoBase> matchInfoBaseList;
-        matchInfoBaseList = buildAclIdMetadataMatch(remoteAclId);
+        matchInfoBaseList = buildAclIdMetadataMatches(remoteAclId);
         matchInfoBaseList.addAll(flows);
         return matchInfoBaseList;
     }
@@ -731,12 +939,15 @@ public final class AclServiceUtils {
             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
             RpcResult<AllocateIdOutput> rpcResult = result.get();
             if (rpcResult.isSuccessful()) {
-                return rpcResult.getResult().getIdValue().intValue();
+                Integer allocatedId = rpcResult.getResult().getIdValue().intValue();
+                LOG.debug("Allocated ACL ID: {} with key: {} into pool: {}", allocatedId, idKey, poolName);
+                return allocatedId;
             } else {
-                LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
+                LOG.error("RPC Call to Get Unique Id for key {} from pool {} returned with Errors {}",
+                        idKey, poolName, rpcResult.getErrors());
             }
         } catch (InterruptedException | ExecutionException e) {
-            LOG.warn("Exception when getting Unique Id", e);
+            LOG.error("Exception when getting Unique Id for key {} from pool {} ", idKey, poolName, e);
         }
         return defaultId;
     }
@@ -747,105 +958,79 @@ public final class AclServiceUtils {
             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
             RpcResult<Void> rpcResult = result.get();
             if (!rpcResult.isSuccessful()) {
-                LOG.warn("RPC Call to release Id {} with Key {} returned with Errors {}", idKey, rpcResult.getErrors());
+                LOG.error("RPC Call to release Id with Key {} from pool {} returned with Errors {}",
+                        idKey, poolName, rpcResult.getErrors());
+            } else {
+                LOG.debug("Released ACL ID with key: {} from pool: {}", idKey, poolName);
             }
         } catch (InterruptedException | ExecutionException e) {
-            LOG.warn("Exception when releasing Id for key {}", idKey, e);
+            LOG.error("Exception when releasing Id for key {} from pool {} ", idKey, poolName, e);
         }
     }
 
     /**
-     * Allocate and save flow priority in cache.
+     * Gets the ACL tag from cache. If not found in cache, tries to allocate and
+     * return the value.
      *
-     * @param key the key
-     * @return the integer
+     * @param aclId the acl id
+     * @return the acl tag
      */
-    public Integer allocateAndSaveFlowPriorityInCache(BigInteger dpId, short tableId, String key) {
-        String poolName = getAclPoolName(dpId, tableId);
-        Integer flowPriority = AclServiceUtils.allocateId(this.idManager, poolName, key,
-                AclConstants.PROTO_MATCH_PRIORITY);
-        this.aclDataUtil.addAclFlowPriority(key, flowPriority);
-        return flowPriority;
+    public Integer getAclTag(final Uuid aclId) {
+        String aclName = aclId.getValue();
+        Integer aclTag = this.aclDataUtil.getAclTag(aclName);
+        if (aclTag == null) {
+            LOG.debug("ACL tag not found in cache for ACL={}, trying to allocate again.", aclName);
+            aclTag = allocateAclTag(aclName);
+            if (aclTag != null && aclTag != AclConstants.INVALID_ACL_TAG) {
+                this.aclDataUtil.addAclTag(aclName, aclTag);
+            }
+        }
+        return aclTag;
     }
 
     /**
-     * Allocate acl id.
+     * Allocate ACL tag.
      *
-     * @param key the key
+     * @param aclName the ACL name
+     * @return the integer
      */
-    public Integer allocateAclId(String key) {
-        Integer aclId = AclServiceUtils.allocateId(this.idManager, AclConstants.ACL_ID_POOL_NAME, key,
-                AclConstants.INVALID_ACL_ID);
-        return aclId;
-    }
-
-    /**
-    * Allocate and save flow priority in cache.
-    *
-    * @param key the key
-    */
-    public void releaseAclId(String key) {
-        AclServiceUtils.releaseId(idManager, AclConstants.ACL_ID_POOL_NAME, key);
+    public Integer allocateAclTag(String aclName) {
+        Integer aclTag = AclServiceUtils.allocateId(this.idManager, AclConstants.ACL_TAG_POOL_NAME, aclName,
+                AclConstants.INVALID_ACL_TAG);
+        return aclTag;
     }
 
     /**
-     * Release and remove flow priority from cache.
+     * Release ACL tag.
      *
-     * @param key the key
-     * @return the integer
+     * @param aclName the ACL name
      */
-    public Integer releaseAndRemoveFlowPriorityFromCache(BigInteger dpId, short tableId, String key) {
-        String poolName = getAclPoolName(dpId, tableId);
-        AclServiceUtils.releaseId(this.idManager, poolName, key);
-        Integer flowPriority = this.aclDataUtil.removeAclFlowPriority(key);
-        if (flowPriority == null) {
-            flowPriority = AclConstants.PROTO_MATCH_PRIORITY;
-        }
-        return flowPriority;
+    public void releaseAclTag(String aclName) {
+        AclServiceUtils.releaseId(this.idManager, AclConstants.ACL_TAG_POOL_NAME, aclName);
     }
 
     /**
      * Indicates whether the interface has port security enabled.
+     *
      * @param aclInterface the interface.
      * @return true if port is security enabled.
      */
     public static boolean isOfInterest(AclInterface aclInterface) {
-        return aclInterface != null && aclInterface.getPortSecurityEnabled() != null
-                && aclInterface.isPortSecurityEnabled();
-    }
-
-    /**
-     * Creates the id pool.
-     *
-     * @param poolName the pool name
-     */
-    public void createIdPool(String poolName) {
-        CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
-                .setPoolName(poolName).setLow(AclConstants.ACL_FLOW_PRIORITY_POOL_START)
-                .setHigh(AclConstants.ACL_FLOW_PRIORITY_POOL_END).build();
-        try {
-            Future<RpcResult<Void>> result = this.idManager.createIdPool(createPool);
-            if ((result != null) && (result.get().isSuccessful())) {
-                LOG.debug("Created IdPool for {}", poolName);
-            }
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.error("Failed to create ID pool [{}] for ACL flow priority", poolName, e);
-            throw new RuntimeException("Failed to create ID pool for ACL flow priority", e);
-        }
+        return aclInterface != null && aclInterface.isPortSecurityEnabled();
     }
 
     /**
-     * Creates the id pool.
+     * Creates the id pool for ACL tag.
      *
      * @param poolName the pool name
      */
-    private void createIdPoolForAclId(String poolName) {
+    private void createIdPoolForAclTag(String poolName) {
         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
-                .setPoolName(poolName).setLow(AclConstants.ACL_ID_METADATA_POOL_START)
-                .setHigh(AclConstants.ACL_ID_METADATA_POOL_END).build();
+                .setPoolName(poolName).setLow(AclConstants.ACL_TAG_POOL_START)
+                .setHigh(AclConstants.ACL_TAG_POOL_END).build();
         try {
             Future<RpcResult<Void>> result = this.idManager.createIdPool(createPool);
-            if ((result != null) && (result.get().isSuccessful())) {
+            if (result != null && result.get().isSuccessful()) {
                 LOG.debug("Created IdPool for {}", poolName);
             }
         } catch (InterruptedException | ExecutionException e) {
@@ -863,7 +1048,7 @@ public final class AclServiceUtils {
         DeleteIdPoolInput deletePool = new DeleteIdPoolInputBuilder().setPoolName(poolName).build();
         try {
             Future<RpcResult<Void>> result = this.idManager.deleteIdPool(deletePool);
-            if ((result != null) && (result.get().isSuccessful())) {
+            if (result != null && result.get().isSuccessful()) {
                 LOG.debug("Deleted IdPool for {}", poolName);
             }
         } catch (InterruptedException | ExecutionException e) {
@@ -872,57 +1057,24 @@ public final class AclServiceUtils {
         }
     }
 
-    /**
-     * Gets the acl pool name.
-     *
-     * @param dpId the dp id
-     * @param tableId the table id
-     * @return the acl pool name
-     */
-    public static String getAclPoolName(BigInteger dpId, short tableId) {
-        return AclConstants.ACL_FLOW_PRIORITY_POOL_NAME + "." + dpId + "." + tableId;
-    }
-
-    /**
-     * Creates the acl id pools.
-     *
-     * @param dpId the dp id
-     */
-    public void createAclIdPools(BigInteger dpId) {
-        createIdPool(getAclPoolName(dpId, NwConstants.INGRESS_ACL_FILTER_TABLE));
-        createIdPool(getAclPoolName(dpId, NwConstants.EGRESS_ACL_FILTER_TABLE));
-    }
-
     /**
      * Creates remote the acl id pools.
      */
     public void createRemoteAclIdPool() {
-        createIdPoolForAclId(AclConstants.ACL_ID_POOL_NAME);
+        createIdPoolForAclTag(AclConstants.ACL_TAG_POOL_NAME);
     }
 
     /**
      * Delete remote the acl id pools.
      */
     public void deleteRemoteAclIdPool() {
-        deleteIdPool(AclConstants.ACL_ID_POOL_NAME);
-    }
-
-    /**
-     * Delete acl id pools.
-     *
-     * @param dpId the dp id
-     */
-    public void deleteAclIdPools(BigInteger dpId) {
-        deleteIdPool(getAclPoolName(dpId, NwConstants.INGRESS_ACL_FILTER_TABLE));
-        deleteIdPool(getAclPoolName(dpId, NwConstants.EGRESS_ACL_FILTER_TABLE));
+        deleteIdPool(AclConstants.ACL_TAG_POOL_NAME);
     }
 
-    public static List<? extends MatchInfoBase> buildIpAndElanSrcMatch(long elanTag, AllowedAddressPairs ip,
+    public static List<? extends MatchInfoBase> buildIpAndSrcServiceMatch(Integer aclTag, AllowedAddressPairs ip,
             DataBroker dataBroker) {
         List<MatchInfoBase> flowMatches = new ArrayList<>();
-        MatchMetadata metadatMatch =
-                new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE);
-        flowMatches.add(metadatMatch);
+        flowMatches.add(buildAclTagMetadataMatch(aclTag));
         if (ip.getIpAddress().getIpAddress() != null) {
             if (ip.getIpAddress().getIpAddress().getIpv4Address() != null) {
                 MatchEthernetType ipv4EthMatch = new MatchEthernetType(NwConstants.ETHTYPE_IPV4);
@@ -953,12 +1105,10 @@ public final class AclServiceUtils {
         return flowMatches;
     }
 
-    public static List<? extends MatchInfoBase> buildIpAndElanDstMatch(Long elanTag, AllowedAddressPairs ip,
+    public static List<? extends MatchInfoBase> buildIpAndDstServiceMatch(Integer aclTag, AllowedAddressPairs ip,
             DataBroker dataBroker) {
         List<MatchInfoBase> flowMatches = new ArrayList<>();
-        MatchMetadata metadatMatch =
-                new MatchMetadata(MetaDataUtil.getElanTagMetadata(elanTag), MetaDataUtil.METADATA_MASK_SERVICE);
-        flowMatches.add(metadatMatch);
+        flowMatches.add(buildAclTagMetadataMatch(aclTag));
 
         if (ip.getIpAddress().getIpAddress() != null) {
             if (ip.getIpAddress().getIpAddress().getIpv4Address() != null) {
@@ -992,7 +1142,86 @@ public final class AclServiceUtils {
         return flowMatches;
     }
 
-    public static boolean isMoreThanOneAcl(AclInterface port) {
-        return port.getSecurityGroups().size() > 1;
+    public static boolean isOfAclInterest(Acl acl) {
+        List<Ace> aceList = acl.getAccessListEntries().getAce();
+        if (aceList != null && !aceList.isEmpty()) {
+            return aceList.get(0).getAugmentation(SecurityRuleAttr.class) != null;
+        }
+        return false;
+    }
+
+    public static void addLportTagMetadataMatch(int lportTag, List<MatchInfoBase> flowMatches,
+            Class<? extends ServiceModeBase> serviceMode) {
+        MatchInfoBase lportMatch = buildLPortTagMatch(lportTag, serviceMode);
+        InterfaceServiceUtil.mergeMetadataMatchsOrAdd(flowMatches, lportMatch);
+    }
+
+    /**
+     * Returns ACL specific key for synchronization.
+     *
+     * @param key the generic key
+     * @return ACL key that can be used with synchronization
+     */
+    public static String getAclKeyForSynchronization(String key) {
+        return key + AclConstants.ACL_SYNC_KEY_EXT;
+    }
+
+    /**
+     * Builds the ip protocol matches.
+     *
+     * @param etherType the ether type
+     * @param protocol the protocol
+     * @return the list of matches.
+     */
+    public static List<MatchInfoBase> buildIpProtocolMatches(MatchEthernetType etherType, IPProtocols protocol) {
+        return Lists.newArrayList(etherType, new MatchIpProtocol(protocol.shortValue()));
+    }
+
+    /**
+     * Does ACE have remote group id.
+     *
+     * @param aceAttr the ace attr
+     * @return true, if successful
+     */
+    public static boolean doesAceHaveRemoteGroupId(final SecurityRuleAttr aceAttr) {
+        return aceAttr.getRemoteGroupId() != null;
+    }
+
+    public SortedSet<Integer> getRemoteAclTags(List<Uuid> aclIds, Class<? extends DirectionBase> direction,
+            DataBroker dataBroker) {
+        SortedSet<Integer> remoteAclTags = new TreeSet<>();
+        Set<Uuid> remoteAclIds = AclServiceUtils.getRemoteAclIdsByDirection(aclIds, direction, dataBroker);
+        for (Uuid remoteAclId : remoteAclIds) {
+            Integer remoteAclTag = getAclTag(remoteAclId);
+            if (remoteAclTag != null && remoteAclTag != AclConstants.INVALID_ACL_TAG) {
+                remoteAclTags.add(remoteAclTag);
+            }
+        }
+        return remoteAclTags;
+    }
+
+    public static Set<Uuid> getRemoteAclIdsByDirection(List<Uuid> aclIds, Class<? extends DirectionBase> direction,
+            DataBroker broker) {
+        Set<Uuid> remoteAclIds = new HashSet<>();
+        if (aclIds == null || aclIds.isEmpty()) {
+            return remoteAclIds;
+        }
+
+        for (Uuid aclId : aclIds) {
+            Acl acl = AclServiceUtils.getAcl(broker, aclId.getValue());
+            if (null == acl) {
+                LOG.warn("ACL {} not found in config DS.", aclId.getValue());
+                continue;
+            }
+            AccessListEntries accessListEntries = acl.getAccessListEntries();
+            List<Ace> aceList = accessListEntries.getAce();
+            for (Ace ace : aceList) {
+                SecurityRuleAttr aceAttr = AclServiceUtils.getAccesssListAttributes(ace);
+                if (aceAttr.getDirection().equals(direction) && doesAceHaveRemoteGroupId(aceAttr)) {
+                    remoteAclIds.add(aceAttr.getRemoteGroupId());
+                }
+            }
+        }
+        return remoteAclIds;
     }
 }