MRI version bumpup for Aluminium
[netvirt.git] / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / utils / AclServiceUtils.java
1 /*
2  * Copyright (c) 2016, 2018 Red Hat, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.netvirt.aclservice.utils;
10
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
13
14 import com.google.common.collect.Lists;
15 import com.google.common.net.InetAddresses;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.math.BigInteger;
18 import java.net.InetAddress;
19 import java.net.UnknownHostException;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Objects;
28 import java.util.Optional;
29 import java.util.Set;
30 import java.util.SortedSet;
31 import java.util.TreeSet;
32 import java.util.concurrent.ExecutionException;
33 import javax.inject.Inject;
34 import javax.inject.Singleton;
35 import org.eclipse.jdt.annotation.NonNull;
36 import org.eclipse.jdt.annotation.Nullable;
37 import org.opendaylight.genius.infra.Datastore.Operational;
38 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
39 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
40 import org.opendaylight.genius.infra.TypedWriteTransaction;
41 import org.opendaylight.genius.mdsalutil.ActionInfo;
42 import org.opendaylight.genius.mdsalutil.InstructionInfo;
43 import org.opendaylight.genius.mdsalutil.MDSALUtil;
44 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
45 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
46 import org.opendaylight.genius.mdsalutil.NwConstants;
47 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack;
48 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack.NxCtAction;
49 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
50 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
51 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
52 import org.opendaylight.genius.mdsalutil.matches.MatchArpSpa;
53 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
54 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
55 import org.opendaylight.genius.mdsalutil.matches.MatchIcmpv6;
56 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
57 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
58 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Source;
59 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6Destination;
60 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6Source;
61 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
62 import org.opendaylight.genius.mdsalutil.matches.MatchUdpDestinationPort;
63 import org.opendaylight.genius.mdsalutil.matches.MatchUdpSourcePort;
64 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
65 import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
66 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
67 import org.opendaylight.mdsal.binding.api.DataBroker;
68 import org.opendaylight.mdsal.binding.api.ReadTransaction;
69 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
70 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.MatchCriteria;
71 import org.opendaylight.netvirt.aclservice.api.utils.AclInterface;
72 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AccessLists;
73 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.Ipv4Acl;
74 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
75 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.AclKey;
76 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.AccessListEntries;
77 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
78 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;
79 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;
80 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
81 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
82 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
83 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
84 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
85 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
86 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
87 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
88 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.config.rev160806.AclserviceConfig;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.AclPortsLookup;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.AclserviceAugmentation;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddressBuilder;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpVersionV6;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.SecurityRuleAttr;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.acl.ports.lookup.AclPortsByIp;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.acl.ports.lookup.AclPortsByIpKey;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.acl.ports.lookup.acl.ports.by.ip.AclIpPrefixes;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.acl.ports.lookup.acl.ports.by.ip.AclIpPrefixesKey;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.acl.ports.lookup.acl.ports.by.ip.acl.ip.prefixes.PortIds;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.acl.ports.lookup.acl.ports.by.ip.acl.ip.prefixes.PortIdsBuilder;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.acl.ports.lookup.acl.ports.by.ip.acl.ip.prefixes.PortIdsKey;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.SubnetInfo;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.serviceutils.srm.types.rev180626.NetvirtAcl;
128 import org.opendaylight.yangtools.yang.binding.DataObject;
129 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
130 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
131 import org.opendaylight.yangtools.yang.common.Uint64;
132 import org.slf4j.Logger;
133 import org.slf4j.LoggerFactory;
134
135 @Singleton
136 public final class AclServiceUtils {
137
138     private static final Logger LOG = LoggerFactory.getLogger(AclServiceUtils.class);
139
140     private final DataBroker dataBroker;
141     private final ManagedNewTransactionRunner txRunner;
142     private final AclDataUtil aclDataUtil;
143     private final AclserviceConfig config;
144     private final JobCoordinator jobCoordinator;
145
146     @Inject
147     public AclServiceUtils(DataBroker dataBroker, AclDataUtil aclDataUtil, AclserviceConfig config,
148             JobCoordinator jobCoordinator) {
149         this.dataBroker = dataBroker;
150         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
151         this.aclDataUtil = aclDataUtil;
152         this.config = config;
153         this.jobCoordinator = jobCoordinator;
154     }
155
156     /**
157      * Retrieves the Interface from the datastore.
158      * @param broker the data broker
159      * @param interfaceName the interface name
160      * @return the interface.
161      */
162     public static Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
163         .Interface> getInterface(DataBroker broker, String interfaceName) {
164         return read(broker, LogicalDatastoreType.CONFIGURATION, getInterfaceIdentifier(interfaceName));
165     }
166
167     /**
168      * Builds the interface identifier.
169      * @param interfaceName the interface name.
170      * @return the interface identifier.
171      */
172     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
173         .interfaces.Interface> getInterfaceIdentifier(String interfaceName) {
174         return InstanceIdentifier.builder(Interfaces.class)
175                 .child(
176                     org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
177                     .Interface.class, new InterfaceKey(interfaceName)).build();
178     }
179
180     /**
181      * Retrieves the object from the datastore.
182      * @param broker the data broker.
183      * @param datastoreType the data store type.
184      * @param path the wild card path.
185      * @param <T> type of DataObject
186      * @return the required object.
187      */
188     public static <T extends DataObject> Optional<T> read(
189             DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
190         try (ReadTransaction tx = broker.newReadOnlyTransaction()) {
191             return tx.read(datastoreType, path).get();
192         } catch (InterruptedException | ExecutionException e) {
193             LOG.error("Failed to read InstanceIdentifier {} from {}", path, datastoreType, e);
194             return Optional.empty();
195         }
196     }
197
198     /**
199      * Retrieves the interface state.
200      * @param dataBroker the data broker.
201      * @param interfaceName the interface name.
202      * @return the interface state.
203      */
204     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
205         .@Nullable Interface getInterfaceStateFromOperDS(DataBroker dataBroker, String interfaceName) {
206         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
207             .interfaces.state.Interface> ifStateId = buildStateInterfaceId(interfaceName);
208         return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, ifStateId, dataBroker).orElse(null);
209     }
210
211     /**
212      * Build the interface state.
213      * @param interfaceName the interface name.
214      * @return the interface state.
215      */
216     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
217         .interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
218         InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
219             .interfaces.state.Interface> idBuilder = InstanceIdentifier.builder(InterfacesState.class)
220             .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
221             .state.Interface.class, new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces
222             .rev140508.interfaces.state.InterfaceKey(interfaceName));
223         return idBuilder.build();
224     }
225
226     /**
227      * Retrieves the security rule attribute augmentation from the access list.
228      * @param ace the access list entry
229      * @return the security rule attributes
230      */
231     @Nullable
232     public static SecurityRuleAttr getAccessListAttributes(Ace ace) {
233         if (ace == null) {
234             return null;
235         }
236         SecurityRuleAttr aceAttributes = ace.augmentation(SecurityRuleAttr.class);
237         if (aceAttributes == null) {
238             return null;
239         }
240         return aceAttributes;
241     }
242
243     /**
244      * Returns the DHCP match.
245      *
246      * @param srcPort the source port.
247      * @param dstPort the destination port.
248      * @param lportTag the lport tag
249      * @param serviceMode ingress or egress service
250      * @return list of matches.
251      */
252     public static List<MatchInfoBase> buildDhcpMatches(int srcPort, int dstPort, int lportTag,
253             Class<? extends ServiceModeBase> serviceMode) {
254         List<MatchInfoBase> matches = new ArrayList<>(5);
255         matches.add(MatchEthernetType.IPV4);
256         matches.add(MatchIpProtocol.UDP);
257         matches.add(new MatchUdpDestinationPort(dstPort));
258         matches.add(new MatchUdpSourcePort(srcPort));
259         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
260         return matches;
261     }
262
263     /**
264      * Returns the DHCPv6 match.
265      *
266      * @param srcPort the source port.
267      * @param dstPort the destination port.
268      * @param lportTag the lport tag
269      * @param serviceMode ingress or egress
270      * @return list of matches.
271      */
272     public static List<MatchInfoBase> buildDhcpV6Matches(int srcPort, int dstPort, int lportTag,
273             Class<? extends ServiceModeBase> serviceMode) {
274         List<MatchInfoBase> matches = new ArrayList<>(6);
275         matches.add(MatchEthernetType.IPV6);
276         matches.add(MatchIpProtocol.UDP);
277         matches.add(new MatchUdpDestinationPort(dstPort));
278         matches.add(new MatchUdpSourcePort(srcPort));
279         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
280         return matches;
281     }
282
283     /**
284      * Returns the ICMPv6 match.
285      *
286      * @param icmpType the icmpv6-type.
287      * @param icmpCode the icmpv6-code.
288      * @param lportTag the lport tag
289      * @param serviceMode ingress or egress
290      * @return list of matches.
291      */
292     public static List<MatchInfoBase> buildIcmpV6Matches(int icmpType, int icmpCode, int lportTag,
293             Class<? extends ServiceModeBase> serviceMode) {
294         List<MatchInfoBase> matches = new ArrayList<>();
295         matches.add(MatchEthernetType.IPV6);
296         matches.add(MatchIpProtocol.ICMPV6);
297         if (icmpType != 0) {
298             matches.add(new MatchIcmpv6((short) icmpType, (short) icmpCode));
299         }
300         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
301         return matches;
302     }
303
304     public static List<MatchInfoBase> buildBroadcastIpV4Matches(String ipAddr) {
305         List<MatchInfoBase> matches = new ArrayList<>(2);
306         matches.add(new MatchEthernetDestination(new MacAddress(AclConstants.BROADCAST_MAC)));
307         matches.addAll(AclServiceUtils.buildIpMatches(IpPrefixOrAddressBuilder.getDefaultInstance(ipAddr),
308                 MatchCriteria.MATCH_DESTINATION));
309         return matches;
310     }
311
312     public static List<MatchInfoBase> buildL2BroadcastMatches() {
313         List<MatchInfoBase> matches = new ArrayList<>();
314         matches.add(new MatchEthernetDestination(new MacAddress(AclConstants.BROADCAST_MAC)));
315         return matches;
316     }
317
318     /**
319      * Builds the service id.
320      *
321      * @param interfaceName the interface name
322      * @param serviceIndex the service index
323      * @param serviceMode the service mode
324      * @return the instance identifier
325      */
326     public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex,
327             Class<? extends ServiceModeBase> serviceMode) {
328         return InstanceIdentifier.builder(ServiceBindings.class)
329                 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, serviceMode))
330                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
331     }
332
333     /**
334      * Gets the bound services.
335      *
336      * @param serviceName the service name
337      * @param servicePriority the service priority
338      * @param flowPriority the flow priority
339      * @param cookie the cookie
340      * @param instructions the instructions
341      * @return the bound services
342      */
343     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
344             Uint64 cookie, List<Instruction> instructions) {
345         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
346                 .setInstruction(instructions);
347         return new BoundServicesBuilder().withKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
348                 .setServicePriority(servicePriority).setServiceType(ServiceTypeFlowBased.class)
349                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
350     }
351
352     public static List<Uuid> getUpdatedAclList(List<Uuid> updatedAclList, List<Uuid> currentAclList) {
353         if (updatedAclList == null) {
354             return Collections.emptyList();
355         }
356         List<Uuid> newAclList = new ArrayList<>(updatedAclList);
357         if (currentAclList == null) {
358             return newAclList;
359         }
360         List<Uuid> origAclList = new ArrayList<>(currentAclList);
361         newAclList.removeAll(origAclList);
362         return newAclList;
363     }
364
365     public static List<AllowedAddressPairs> getUpdatedAllowedAddressPairs(
366             @Nullable List<AllowedAddressPairs> updatedAllowedAddressPairs,
367             @Nullable List<AllowedAddressPairs> currentAllowedAddressPairs) {
368         if (updatedAllowedAddressPairs == null) {
369             return Collections.emptyList();
370         }
371         List<AllowedAddressPairs> newAllowedAddressPairs = new ArrayList<>(updatedAllowedAddressPairs);
372         if (currentAllowedAddressPairs == null) {
373             return newAllowedAddressPairs;
374         }
375         List<AllowedAddressPairs> origAllowedAddressPairs = new ArrayList<>(currentAllowedAddressPairs);
376         for (Iterator<AllowedAddressPairs> iterator = newAllowedAddressPairs.iterator(); iterator.hasNext();) {
377             AllowedAddressPairs updatedAllowedAddressPair = iterator.next();
378             for (AllowedAddressPairs currentAllowedAddressPair : origAllowedAddressPairs) {
379                 if (updatedAllowedAddressPair.key().equals(currentAllowedAddressPair.key())) {
380                     iterator.remove();
381                     break;
382                 }
383             }
384         }
385         return newAllowedAddressPairs;
386     }
387
388     @Nullable
389     public static BigInteger getDpIdFromIterfaceState(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
390             .interfaces.rev140508.interfaces.state.Interface interfaceState) {
391         BigInteger dpId = null;
392         List<String> ofportIds = interfaceState.getLowerLayerIf();
393         if (ofportIds != null && !ofportIds.isEmpty()) {
394             NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
395             dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
396         }
397         return dpId;
398     }
399
400     public static List<String> getIpBroadcastAddresses(List<SubnetInfo> subnetInfoList) {
401         List<String> ipBroadcastAddresses = new ArrayList<>();
402         for (SubnetInfo subnetInfo : subnetInfoList) {
403             IpPrefix cidrIpPrefix = subnetInfo.getIpPrefix().getIpPrefix();
404             if (cidrIpPrefix != null) {
405                 Ipv4Prefix cidrIpv4Prefix = cidrIpPrefix.getIpv4Prefix();
406                 if (cidrIpv4Prefix != null) {
407                     ipBroadcastAddresses.add(getBroadcastAddressFromCidr(cidrIpv4Prefix.getValue()));
408                 }
409             }
410         }
411         return ipBroadcastAddresses;
412     }
413
414     public static String getBroadcastAddressFromCidr(String cidr) {
415         String[] ipaddressValues = cidr.split("/");
416         int address = InetAddresses.coerceToInteger(InetAddresses.forString(ipaddressValues[0]));
417         int cidrPart = Integer.parseInt(ipaddressValues[1]);
418         int netmask = 0;
419         for (int j = 0; j < cidrPart; ++j) {
420             netmask |= 1 << 31 - j;
421         }
422         int network = address & netmask;
423         int broadcast = network | ~netmask;
424         return InetAddresses.toAddrString(InetAddresses.fromInteger(broadcast));
425     }
426
427     /**
428      * Builds the ip matches.
429      *
430      * @param ipPrefixOrAddress the ip prefix or address
431      * @param matchCriteria the source_ip or destination_ip used for the match
432      * @return the list
433      */
434     public static List<MatchInfoBase> buildIpMatches(IpPrefixOrAddress ipPrefixOrAddress,
435                                                      MatchCriteria matchCriteria) {
436         List<MatchInfoBase> flowMatches = new ArrayList<>();
437         IpPrefix ipPrefix = ipPrefixOrAddress.getIpPrefix();
438         if (ipPrefix != null) {
439             Ipv4Prefix ipv4Prefix = ipPrefix.getIpv4Prefix();
440             if (ipv4Prefix != null) {
441                 flowMatches.add(MatchEthernetType.IPV4);
442                 if (!ipv4Prefix.getValue().equals(AclConstants.IPV4_ALL_NETWORK)) {
443                     flowMatches.add(matchCriteria == MatchCriteria.MATCH_SOURCE ? new MatchIpv4Source(ipv4Prefix)
444                             : new MatchIpv4Destination(ipv4Prefix));
445                 }
446             } else {
447                 flowMatches.add(MatchEthernetType.IPV6);
448                 flowMatches.add(matchCriteria == MatchCriteria.MATCH_SOURCE ? new MatchIpv6Source(
449                         ipPrefix.getIpv6Prefix()) : new MatchIpv6Destination(ipPrefix.getIpv6Prefix()));
450             }
451         } else {
452             IpAddress ipAddress = ipPrefixOrAddress.getIpAddress();
453             if (ipAddress.getIpv4Address() != null) {
454                 flowMatches.add(MatchEthernetType.IPV4);
455                 flowMatches.add(matchCriteria == MatchCriteria.MATCH_SOURCE ? new MatchIpv4Source(
456                         ipAddress.getIpv4Address().getValue(), "32") : new MatchIpv4Destination(
457                         ipAddress.getIpv4Address().getValue(), "32"));
458             } else {
459                 flowMatches.add(MatchEthernetType.IPV6);
460                 flowMatches.add(matchCriteria == MatchCriteria.MATCH_SOURCE ? new MatchIpv6Source(
461                         ipAddress.getIpv6Address().getValue() + "/128") : new MatchIpv6Destination(
462                         ipAddress.getIpv6Address().getValue() + "/128"));
463             }
464         }
465         return flowMatches;
466     }
467
468     /**
469      * Builds the arp ip matches.
470      * @param ipPrefixOrAddress the ip prefix or address
471      * @return the MatchInfoBase list
472      */
473     public static List<MatchInfoBase> buildArpIpMatches(IpPrefixOrAddress ipPrefixOrAddress) {
474         List<MatchInfoBase> flowMatches = new ArrayList<>();
475         IpPrefix ipPrefix = ipPrefixOrAddress.getIpPrefix();
476         if (ipPrefix != null) {
477             Ipv4Prefix ipv4Prefix = ipPrefix.getIpv4Prefix();
478             if (ipv4Prefix != null && !ipv4Prefix.getValue().equals(AclConstants.IPV4_ALL_NETWORK)) {
479                 flowMatches.add(new MatchArpSpa(ipv4Prefix));
480             }
481         } else {
482             IpAddress ipAddress = ipPrefixOrAddress.getIpAddress();
483             if (ipAddress != null && ipAddress.getIpv4Address() != null) {
484                 flowMatches.add(new MatchArpSpa(ipAddress.getIpv4Address().getValue(), "32"));
485             }
486         }
487         return flowMatches;
488     }
489
490     public static MatchInfoBase buildRemoteAclTagMetadataMatch(Integer remoteAclTag) {
491         return new MatchMetadata(getRemoteAclTagMetadata(BigInteger.valueOf(remoteAclTag)),
492                 MetaDataUtil.METADATA_MASK_REMOTE_ACL_TAG);
493     }
494
495     public static Uint64 getRemoteAclTagMetadata(BigInteger remoteAclTag) {
496         return Uint64.valueOf(remoteAclTag.shiftLeft(4));
497     }
498
499     public static Uint64 getDropFlowCookie(int lport) {
500         return Uint64.fromLongBits(MetaDataUtil.getLportTagMetaData(lport).longValue()
501                    | AclConstants.COOKIE_ACL_DROP_FLOW.longValue());
502     }
503
504     /**
505      * Does IPv4 address exists in the list of allowed address pair.
506      *
507      * @param aaps the allowed address pairs
508      * @return true, if successful
509      */
510     public static boolean doesIpv4AddressExists(List<AllowedAddressPairs> aaps) {
511         if (aaps == null) {
512             return false;
513         }
514         for (AllowedAddressPairs aap : aaps) {
515             IpPrefixOrAddress ipPrefixOrAddress = aap.getIpAddress();
516             IpPrefix ipPrefix = ipPrefixOrAddress.getIpPrefix();
517             if (ipPrefix != null) {
518                 if (ipPrefix.getIpv4Prefix() != null) {
519                     return true;
520                 }
521             } else {
522                 IpAddress ipAddress = ipPrefixOrAddress.getIpAddress();
523                 if (ipAddress != null && ipAddress.getIpv4Address() != null) {
524                     return true;
525                 }
526             }
527         }
528         return false;
529     }
530
531     /**
532      * Does IPv6 address exists in the list of allowed address pair.
533      *
534      * @param aaps the allowed address pairs
535      * @return true, if successful
536      */
537     public static boolean doesIpv6AddressExists(List<AllowedAddressPairs> aaps) {
538         if (aaps == null) {
539             return false;
540         }
541         for (AllowedAddressPairs aap : aaps) {
542             IpPrefixOrAddress ipPrefixOrAddress = aap.getIpAddress();
543             IpPrefix ipPrefix = ipPrefixOrAddress.getIpPrefix();
544             if (ipPrefix != null) {
545                 if (ipPrefix.getIpv6Prefix() != null) {
546                     return true;
547                 }
548             } else {
549                 IpAddress ipAddress = ipPrefixOrAddress.getIpAddress();
550                 if (ipAddress != null && ipAddress.getIpv6Address() != null) {
551                     return true;
552                 }
553             }
554         }
555         return false;
556     }
557
558     /**
559      * Gets the lport tag match.
560      * Ingress match is based on metadata and egress match is based on masked reg6
561      *
562      * @param lportTag the lport tag
563      * @param serviceMode ingress or egress service mode
564      * @return the lport tag match
565      */
566     public static MatchInfoBase buildLPortTagMatch(int lportTag, Class<? extends ServiceModeBase> serviceMode) {
567         if (serviceMode != null && serviceMode.isAssignableFrom(ServiceModeEgress.class)) {
568             return new NxMatchRegister(NxmNxReg6.class, MetaDataUtil.getLportTagForReg6(lportTag).longValue(),
569                     MetaDataUtil.getLportTagMaskForReg6());
570         } else {
571             return new MatchMetadata(MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG);
572         }
573     }
574
575     public static List<MatchInfoBase> buildMatchesForLPortTagAndRemoteAclTag(Integer lportTag, Integer remoteAclTag,
576             Class<? extends ServiceModeBase> serviceMode) {
577         List<MatchInfoBase> matches = new ArrayList<>();
578         if (serviceMode != null && serviceMode.isAssignableFrom(ServiceModeEgress.class)) {
579             matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
580             matches.add(AclServiceUtils.buildRemoteAclTagMetadataMatch(remoteAclTag));
581         } else {
582             // In case of ingress service mode, only metadata is used for
583             // matching both lportTag and aclTag. Hence performing "or"
584             // operation on both lportTag and aclTag metadata.
585             Uint64 metaData = Uint64.fromLongBits(MetaDataUtil.getLportTagMetaData(lportTag).longValue()
586                     | (getRemoteAclTagMetadata(BigInteger.valueOf(remoteAclTag)).longValue()));
587             Uint64 metaDataMask = Uint64.fromLongBits(MetaDataUtil.METADATA_MASK_LPORT_TAG.longValue()
588                     | MetaDataUtil.METADATA_MASK_REMOTE_ACL_TAG.longValue());
589             matches.add(new MatchMetadata(metaData, metaDataMask));
590         }
591         return matches;
592     }
593
594     public static Collection<? extends MatchInfoBase> buildMatchesForLPortTagAndConntrackClassifierType(int lportTag,
595             AclConntrackClassifierType conntrackClassifierType, Class<? extends ServiceModeBase> serviceMode) {
596         List<MatchInfoBase> matches = new ArrayList<>();
597         if (serviceMode != null && serviceMode.isAssignableFrom(ServiceModeEgress.class)) {
598             matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
599             matches.add(AclServiceUtils.buildAclConntrackClassifierTypeMatch(conntrackClassifierType));
600         } else {
601             // In case of ingress service mode, only metadata is used for
602             // matching both lportTag and conntrackClassifierType. Hence performing "or"
603             // operation on both lportTag and conntrackClassifierType metadata.
604             Uint64 metaData = Uint64.fromLongBits(MetaDataUtil.getLportTagMetaData(lportTag).longValue()
605                     | (MetaDataUtil.getAclConntrackClassifierTypeFromMetaData(
606                        Uint64.valueOf(conntrackClassifierType.getValue()))).longValue());
607             Uint64 metaDataMask = Uint64.fromLongBits(MetaDataUtil.METADATA_MASK_LPORT_TAG.longValue()
608                    | MetaDataUtil.METADATA_MASK_ACL_CONNTRACK_CLASSIFIER_TYPE.longValue());
609             matches.add(new MatchMetadata(metaData, metaDataMask));
610         }
611         return matches;
612     }
613
614     public static InstructionWriteMetadata getWriteMetadataForAclClassifierType(
615             AclConntrackClassifierType conntrackClassifierType) {
616         return new InstructionWriteMetadata(MetaDataUtil.getAclConntrackClassifierTypeFromMetaData(
617                 Uint64.valueOf(conntrackClassifierType.getValue())),
618                 MetaDataUtil.METADATA_MASK_ACL_CONNTRACK_CLASSIFIER_TYPE);
619     }
620
621     public static InstructionWriteMetadata getWriteMetadataForDropFlag() {
622         return new InstructionWriteMetadata(MetaDataUtil.getAclDropMetaData(AclConstants.METADATA_DROP_FLAG),
623                 MetaDataUtil.METADATA_MASK_ACL_DROP);
624     }
625
626     public static InstructionWriteMetadata getWriteMetadataForRemoteAclTag(Integer remoteAclTag) {
627         return new InstructionWriteMetadata(getRemoteAclTagMetadata(BigInteger.valueOf(remoteAclTag)),
628                 MetaDataUtil.METADATA_MASK_REMOTE_ACL_TAG);
629     }
630
631     public static MatchInfoBase buildAclConntrackClassifierTypeMatch(
632             AclConntrackClassifierType conntrackSupportedType) {
633         return new MatchMetadata(
634                 MetaDataUtil.getAclConntrackClassifierTypeFromMetaData(
635                     Uint64.valueOf(conntrackSupportedType.getValue())),
636                     MetaDataUtil.METADATA_MASK_ACL_CONNTRACK_CLASSIFIER_TYPE);
637     }
638
639     public AclserviceConfig getConfig() {
640         return config;
641     }
642
643     public static boolean isIPv4Address(AllowedAddressPairs aap) {
644         IpPrefixOrAddress ipPrefixOrAddress = aap.getIpAddress();
645         IpPrefix ipPrefix = ipPrefixOrAddress.getIpPrefix();
646         if (ipPrefix != null) {
647             if (ipPrefix.getIpv4Prefix() != null) {
648                 return true;
649             }
650         } else {
651             IpAddress ipAddress = ipPrefixOrAddress.getIpAddress();
652             if (ipAddress != null && ipAddress.getIpv4Address() != null) {
653                 return true;
654             }
655         }
656         return false;
657     }
658
659     public static boolean isNotIpv4AllNetwork(AllowedAddressPairs aap) {
660         IpPrefix ipPrefix = aap.getIpAddress().getIpPrefix();
661         if (ipPrefix != null && ipPrefix.getIpv4Prefix() != null
662                 && ipPrefix.getIpv4Prefix().getValue().equals(AclConstants.IPV4_ALL_NETWORK)) {
663             return false;
664         }
665         return true;
666     }
667
668     protected static boolean isNotIpv6AllNetwork(AllowedAddressPairs aap) {
669         IpPrefix ipPrefix = aap.getIpAddress().getIpPrefix();
670         if (ipPrefix != null && ipPrefix.getIpv6Prefix() != null
671                 && ipPrefix.getIpv6Prefix().getValue().equals(AclConstants.IPV6_ALL_NETWORK)) {
672             return false;
673         }
674         return true;
675     }
676
677     public static boolean isNotIpAllNetwork(AllowedAddressPairs aap) {
678         return isNotIpv4AllNetwork(aap) && isNotIpv6AllNetwork(aap);
679     }
680
681     @Nullable
682     public static Long getElanIdFromInterface(String elanInterfaceName, DataBroker broker) {
683         ElanInterface elanInterface = getElanInterfaceByElanInterfaceName(elanInterfaceName, broker);
684         if (null != elanInterface) {
685             ElanInstance elanInfo = getElanInstanceByName(elanInterface.getElanInstanceName(), broker);
686             return elanInfo != null ? elanInfo.getElanTag().toJava() : null;
687         }
688         return null;
689     }
690
691     @Nullable
692     public static ElanInterface getElanInterfaceByElanInterfaceName(String elanInterfaceName,DataBroker broker) {
693         InstanceIdentifier<ElanInterface> elanInterfaceId = getElanInterfaceConfigurationDataPathId(elanInterfaceName);
694         return read(broker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId).orElse(null);
695     }
696
697     public static InstanceIdentifier<ElanInterface> getElanInterfaceConfigurationDataPathId(String interfaceName) {
698         return InstanceIdentifier.builder(ElanInterfaces.class)
699                 .child(ElanInterface.class, new ElanInterfaceKey(interfaceName)).build();
700     }
701
702     // elan-instances config container
703     @Nullable
704     public static ElanInstance getElanInstanceByName(String elanInstanceName, DataBroker broker) {
705         InstanceIdentifier<ElanInstance> elanIdentifierId = getElanInstanceConfigurationDataPath(elanInstanceName);
706         return read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId).orElse(null);
707     }
708
709     public static InstanceIdentifier<ElanInstance> getElanInstanceConfigurationDataPath(String elanInstanceName) {
710         return InstanceIdentifier.builder(ElanInstances.class)
711                 .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
712     }
713
714     public void deleteAcesFromConfigDS(String aclName, List<Ace> deletedAceRules) {
715         List<List<Ace>> acesParts = Lists.partition(deletedAceRules, AclConstants.ACES_PER_TRANSACTION);
716         for (List<Ace> acePart : acesParts) {
717             jobCoordinator.enqueueJob(aclName,
718                 () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
719                     tx -> {
720                         for (Ace ace: acePart) {
721                             InstanceIdentifier<Ace> id = InstanceIdentifier.builder(AccessLists.class)
722                                     .child(Acl.class, new AclKey(aclName, Ipv4Acl.class)).child(AccessListEntries.class)
723                                     .child(Ace.class, ace.key()).build();
724                             tx.delete(id);
725                         }
726                     })), AclConstants.ACEDELETE_MAX_RETRIES);
727         }
728     }
729
730     /**
731      * Gets ACL tag from Acl.
732      * @param acl Acl object
733      * @return the acl tag
734      */
735     public static Integer getAclTag(Acl acl) {
736         Integer aclTag = null;
737         AclserviceAugmentation aclserviceAugmentation = acl.augmentation(AclserviceAugmentation.class);
738         if (aclserviceAugmentation != null) {
739             aclTag = aclserviceAugmentation.getAclTag().intValue();
740         }
741         return aclTag;
742     }
743
744     /**
745      * Gets the ACL tag from cache.
746      *
747      * @param aclId the acl id
748      * @return the acl tag
749      */
750     public Integer getAclTag(final Uuid aclId) {
751         String aclName = aclId.getValue();
752         return this.aclDataUtil.getAclTag(aclName);
753     }
754
755     /**
756      * Indicates whether the interface has port security enabled or interface is DHCP service port.
757      *
758      * @param aclInterface the interface.
759      * @return true if port is security enabled or is a DHCP service port.
760      */
761     public static boolean isOfInterest(AclInterface aclInterface) {
762         return aclInterface != null && (aclInterface.isPortSecurityEnabled()
763                 || aclInterface.getInterfaceType() == InterfaceAcl.InterfaceType.DhcpService);
764     }
765
766     /**
767      * Indicates whether the interface has port security enabled or interface is DHCP service port.
768      *
769      * @param aclInterface the interface.
770      * @return true if port is security enabled or is a DHCP service port.
771      */
772     public static boolean isOfInterest(InterfaceAcl aclInterface) {
773         return aclInterface != null && (aclInterface.isPortSecurityEnabled()
774                 || aclInterface.getInterfaceType() == InterfaceAcl.InterfaceType.DhcpService);
775     }
776
777     public static List<? extends MatchInfoBase> buildIpAndSrcServiceMatch(Integer aclTag, AllowedAddressPairs aap) {
778         List<MatchInfoBase> flowMatches = new ArrayList<>();
779         flowMatches.add(buildRemoteAclTagMetadataMatch(aclTag));
780         if (aap.getIpAddress().getIpAddress() != null) {
781             if (aap.getIpAddress().getIpAddress().getIpv4Address() != null) {
782                 MatchEthernetType ipv4EthMatch = new MatchEthernetType(NwConstants.ETHTYPE_IPV4);
783                 flowMatches.add(ipv4EthMatch);
784                 MatchIpv4Source srcMatch = new MatchIpv4Source(
785                         new Ipv4Prefix(aap.getIpAddress().getIpAddress().getIpv4Address().getValue() + "/32"));
786                 flowMatches.add(srcMatch);
787             } else if (aap.getIpAddress().getIpAddress().getIpv6Address() != null) {
788                 MatchEthernetType ipv6EthMatch = new MatchEthernetType(NwConstants.ETHTYPE_IPV6);
789                 flowMatches.add(ipv6EthMatch);
790                 MatchIpv6Source srcMatch = new MatchIpv6Source(
791                         new Ipv6Prefix(aap.getIpAddress().getIpAddress().getIpv6Address().getValue() + "/128"));
792                 flowMatches.add(srcMatch);
793             }
794         } else if (aap.getIpAddress().getIpPrefix() != null) {
795             if (aap.getIpAddress().getIpPrefix().getIpv4Prefix() != null) {
796                 MatchEthernetType ipv4EthMatch = new MatchEthernetType(NwConstants.ETHTYPE_IPV4);
797                 flowMatches.add(ipv4EthMatch);
798                 MatchIpv4Source srcMatch = new MatchIpv4Source(aap.getIpAddress().getIpPrefix().getIpv4Prefix());
799                 flowMatches.add(srcMatch);
800             } else if (aap.getIpAddress().getIpPrefix().getIpv6Prefix() != null) {
801                 MatchEthernetType ipv6EthMatch = new MatchEthernetType(NwConstants.ETHTYPE_IPV6);
802                 flowMatches.add(ipv6EthMatch);
803                 MatchIpv6Source srcMatch = new MatchIpv6Source(aap.getIpAddress().getIpPrefix().getIpv6Prefix());
804                 flowMatches.add(srcMatch);
805             }
806         }
807         return flowMatches;
808     }
809
810     public static List<? extends MatchInfoBase> buildIpAndDstServiceMatch(Integer aclTag, AllowedAddressPairs aap) {
811         List<MatchInfoBase> flowMatches = new ArrayList<>();
812         flowMatches.add(buildRemoteAclTagMetadataMatch(aclTag));
813
814         if (aap.getIpAddress().getIpAddress() != null) {
815             if (aap.getIpAddress().getIpAddress().getIpv4Address() != null) {
816                 MatchEthernetType ipv4EthMatch = new MatchEthernetType(NwConstants.ETHTYPE_IPV4);
817                 flowMatches.add(ipv4EthMatch);
818                 MatchIpv4Destination dstMatch = new MatchIpv4Destination(
819                         new Ipv4Prefix(aap.getIpAddress().getIpAddress().getIpv4Address().getValue() + "/32"));
820                 flowMatches.add(dstMatch);
821             } else if (aap.getIpAddress().getIpAddress().getIpv6Address() != null) {
822                 MatchEthernetType ipv6EthMatch = new MatchEthernetType(NwConstants.ETHTYPE_IPV6);
823                 flowMatches.add(ipv6EthMatch);
824                 MatchIpv6Destination dstMatch = new MatchIpv6Destination(
825                         new Ipv6Prefix(aap.getIpAddress().getIpAddress().getIpv6Address().getValue() + "/128"));
826                 flowMatches.add(dstMatch);
827             }
828         } else if (aap.getIpAddress().getIpPrefix() != null) {
829             if (aap.getIpAddress().getIpPrefix().getIpv4Prefix() != null) {
830                 MatchEthernetType ipv4EthMatch = new MatchEthernetType(NwConstants.ETHTYPE_IPV4);
831                 flowMatches.add(ipv4EthMatch);
832                 MatchIpv4Destination dstMatch =
833                         new MatchIpv4Destination(aap.getIpAddress().getIpPrefix().getIpv4Prefix());
834                 flowMatches.add(dstMatch);
835             } else if (aap.getIpAddress().getIpPrefix().getIpv6Prefix() != null) {
836                 MatchEthernetType ipv6EthMatch = new MatchEthernetType(NwConstants.ETHTYPE_IPV6);
837                 flowMatches.add(ipv6EthMatch);
838                 MatchIpv6Destination dstMatch =
839                         new MatchIpv6Destination(aap.getIpAddress().getIpPrefix().getIpv6Prefix());
840                 flowMatches.add(dstMatch);
841             }
842         }
843         return flowMatches;
844     }
845
846     public static @NonNull List<Ace> aceList(@NonNull Acl acl) {
847         final AccessListEntries ale = acl.getAccessListEntries();
848         return ale == null ? Collections.emptyList() : ale.nonnullAce();
849     }
850
851     public static @NonNull List<Ace> getAceListFromAcl(Acl acl) {
852         List<Ace> aceList = aceList(acl);
853         if (!aceList.isEmpty() && aceList.get(0).augmentation(SecurityRuleAttr.class) != null) {
854             return aceList;
855         }
856         return Collections.emptyList();
857     }
858
859     /**
860      * Builds the ip protocol matches.
861      *
862      * @param etherType the ether type
863      * @param protocol the protocol
864      * @return the list of matches.
865      */
866     public static List<MatchInfoBase> buildIpProtocolMatches(MatchEthernetType etherType, IPProtocols protocol) {
867         return Lists.newArrayList(etherType, new MatchIpProtocol(protocol.shortValue()));
868     }
869
870     /**
871      * Does ACE have remote group id.
872      *
873      * @param aceAttr the ace attr
874      * @return true, if successful
875      */
876     public static boolean doesAceHaveRemoteGroupId(final SecurityRuleAttr aceAttr) {
877         return aceAttr != null && aceAttr.getRemoteGroupId() != null;
878     }
879
880     public SortedSet<Integer> getRemoteAclTags(@Nullable List<Uuid> aclIds, Class<? extends DirectionBase> direction) {
881         SortedSet<Integer> remoteAclTags = new TreeSet<>();
882         Set<Uuid> remoteAclIds = getRemoteAclIdsByDirection(aclIds, direction);
883         for (Uuid remoteAclId : remoteAclIds) {
884             Integer remoteAclTag = getAclTag(remoteAclId);
885             if (remoteAclTag != null && remoteAclTag != AclConstants.INVALID_ACL_TAG) {
886                 remoteAclTags.add(remoteAclTag);
887             }
888         }
889         return remoteAclTags;
890     }
891
892     public Set<Uuid> getRemoteAclIdsByDirection(@Nullable List<Uuid> aclIds, Class<? extends DirectionBase> direction) {
893         Set<Uuid> remoteAclIds = new HashSet<>();
894         if (aclIds == null || aclIds.isEmpty()) {
895             return remoteAclIds;
896         }
897
898         for (Uuid aclId : aclIds) {
899             Acl acl = this.aclDataUtil.getAcl(aclId.getValue());
900             if (null == acl) {
901                 LOG.warn("ACL {} not found in cache.", aclId.getValue());
902                 continue;
903             }
904             remoteAclIds.addAll(getRemoteAclIdsByDirection(acl, direction));
905         }
906         return remoteAclIds;
907     }
908
909     public static Set<Uuid> getRemoteAclIdsByDirection(Acl acl, Class<? extends DirectionBase> direction) {
910         Set<Uuid> remoteAclIds = new HashSet<>();
911         for (Ace ace : aceList(acl)) {
912             SecurityRuleAttr aceAttr = AclServiceUtils.getAccessListAttributes(ace);
913             if (aceAttr != null && Objects.equals(aceAttr.getDirection(), direction)
914                     && doesAceHaveRemoteGroupId(aceAttr)) {
915                 remoteAclIds.add(aceAttr.getRemoteGroupId());
916             }
917         }
918         return remoteAclIds;
919     }
920
921     /**
922      * Skip delete in case of overlapping IP.
923      *
924      * <p>
925      * When there are multiple ports (e.g., p1, p2, p3) having same AAP (e.g.,
926      * 224.0.0.5) configured which are part of single SG, there would be single
927      * flow in remote ACL table. When one of these ports (say p1) is deleted,
928      * the single flow which is configured in remote ACL table shouldn't be
929      * deleted. It should be deleted only when there are no more references to
930      * it.
931      *
932      * @param portId the port id
933      * @param remoteAclId the remote Acl Id
934      * @param ipPrefix the ip prefix
935      * @param addOrRemove the add or remove
936      * @return true, if successful
937      */
938     public boolean skipDeleteInCaseOfOverlappingIP(String portId, Uuid remoteAclId, IpPrefixOrAddress ipPrefix,
939             int addOrRemove) {
940         boolean skipDelete = false;
941         if (addOrRemove != NwConstants.DEL_FLOW) {
942             return skipDelete;
943         }
944         AclIpPrefixes aclIpPrefixes = getAclIpPrefixesFromOperDs(remoteAclId.getValue(), ipPrefix);
945         if (aclIpPrefixes != null && aclIpPrefixes.getPortIds() != null) {
946             List<String> ignorePorts = Lists.newArrayList(portId);
947             List<PortIds> portIds = new ArrayList<>(aclIpPrefixes.getPortIds().values());
948             // Checking if there are any other ports excluding ignorePorts
949             long noOfRemotePorts =
950                     portIds.stream().map(PortIds::getPortId).filter(y -> !ignorePorts.contains(y)).count();
951             if (noOfRemotePorts > 0) {
952                 skipDelete = true;
953             }
954         }
955         return skipDelete;
956     }
957
958     public boolean doesRemoteAclIdExistsInAcls(List<Uuid> aclIds, Uuid remoteAclId,
959             Class<? extends DirectionBase> direction) {
960         if (aclIds == null) {
961             return false;
962         }
963         for (Uuid aclId : aclIds) {
964             Acl acl = this.aclDataUtil.getAcl(aclId.getValue());
965             if (null == acl) {
966                 LOG.warn("ACL {} not found in cache.", aclId.getValue());
967                 continue;
968             }
969             AccessListEntries accessListEntries = acl.getAccessListEntries();
970             if (accessListEntries != null && accessListEntries.getAce() != null) {
971                 for (Ace ace : accessListEntries.getAce()) {
972                     SecurityRuleAttr aceAttr = AclServiceUtils.getAccessListAttributes(ace);
973                     if (aceAttr != null && aceAttr.getDirection().equals(direction)
974                             && doesAceHaveRemoteGroupId(aceAttr)) {
975                         if (aceAttr.getRemoteGroupId().equals(remoteAclId)) {
976                             return true;
977                         }
978                     }
979                 }
980             }
981         }
982         return false;
983     }
984
985     public static InstanceIdentifier<AclPortsByIp> aclPortsByIpPath(String aclName) {
986         return InstanceIdentifier.builder(AclPortsLookup.class)
987                 .child(AclPortsByIp.class, new AclPortsByIpKey(aclName)).build();
988     }
989
990     public static InstanceIdentifier<AclIpPrefixes> getAclIpPrefixesPath(String aclName, IpPrefixOrAddress ipPrefix) {
991         return InstanceIdentifier.builder(AclPortsLookup.class).child(AclPortsByIp.class, new AclPortsByIpKey(aclName))
992                 .child(AclIpPrefixes.class, new AclIpPrefixesKey(ipPrefix)).build();
993     }
994
995     public static InstanceIdentifier<PortIds> getPortIdsPathInAclPortsLookup(String ruleName,
996             IpPrefixOrAddress ipPrefix, String portId) {
997         return InstanceIdentifier.builder(AclPortsLookup.class).child(AclPortsByIp.class, new AclPortsByIpKey(ruleName))
998                 .child(AclIpPrefixes.class, new AclIpPrefixesKey(ipPrefix)).child(PortIds.class, new PortIdsKey(portId))
999                 .build();
1000     }
1001
1002     public void addAclPortsLookupForInterfaceUpdate(AclInterface portBefore, AclInterface portAfter) {
1003         LOG.debug("Processing interface additions for port {}", portAfter.getInterfaceId());
1004         List<AllowedAddressPairs> addedAllowedAddressPairs = getUpdatedAllowedAddressPairs(
1005                 portAfter.getAllowedAddressPairs(), portBefore.getAllowedAddressPairs());
1006         if (!addedAllowedAddressPairs.isEmpty()) {
1007             addAclPortsLookup(portAfter, portAfter.getSecurityGroups(), addedAllowedAddressPairs);
1008         }
1009
1010         List<Uuid> addedAcls = getUpdatedAclList(portAfter.getSecurityGroups(), portBefore.getSecurityGroups());
1011         if (!addedAcls.isEmpty()) {
1012             addAclPortsLookup(portAfter, addedAcls, portAfter.getAllowedAddressPairs());
1013         }
1014     }
1015
1016     public void deleteAclPortsLookupForInterfaceUpdate(AclInterface portBefore, AclInterface portAfter) {
1017         LOG.debug("Processing interface removals for port {}", portAfter.getInterfaceId());
1018         List<AllowedAddressPairs> deletedAllowedAddressPairs = getUpdatedAllowedAddressPairs(
1019                 portBefore.getAllowedAddressPairs(), portAfter.getAllowedAddressPairs());
1020         if (!deletedAllowedAddressPairs.isEmpty()) {
1021             deleteAclPortsLookup(portAfter, portAfter.getSecurityGroups(), deletedAllowedAddressPairs);
1022         }
1023
1024         List<Uuid> deletedAcls = getUpdatedAclList(portBefore.getSecurityGroups(), portAfter.getSecurityGroups());
1025         if (!deletedAcls.isEmpty()) {
1026             deleteAclPortsLookup(portAfter, deletedAcls, portAfter.getAllowedAddressPairs());
1027         }
1028     }
1029
1030     public void addAclPortsLookup(AclInterface port, List<Uuid> aclList,
1031             List<AllowedAddressPairs> allowedAddresses) {
1032         String portId = port.getInterfaceId();
1033         LOG.trace("Adding AclPortsLookup for port={}, acls={}, AAPs={}", portId, aclList, allowedAddresses);
1034
1035         if (aclList == null || allowedAddresses == null || allowedAddresses.isEmpty()) {
1036             LOG.warn("aclList or allowedAddresses is null. port={}, acls={}, AAPs={}", portId, aclList,
1037                     allowedAddresses);
1038             return;
1039         }
1040
1041         for (Uuid aclId : aclList) {
1042             String aclName = aclId.getValue();
1043             jobCoordinator.enqueueJob(aclName, () -> {
1044                 List<ListenableFuture<Void>> futures = new ArrayList<>();
1045                 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
1046                     for (AllowedAddressPairs aap : allowedAddresses) {
1047                         PortIds portIdObj =
1048                                 new PortIdsBuilder().withKey(new PortIdsKey(portId)).setPortId(portId).build();
1049                         InstanceIdentifier<PortIds> path =
1050                                 AclServiceUtils.getPortIdsPathInAclPortsLookup(aclName, aap.getIpAddress(), portId);
1051                         tx.mergeParentStructurePut(path, portIdObj);
1052                     }
1053                 }));
1054                 return futures;
1055             });
1056         }
1057     }
1058
1059     public void deleteAclPortsLookup(AclInterface port, List<Uuid> aclList,
1060             List<AllowedAddressPairs> allowedAddresses) {
1061         String portId = port.getInterfaceId();
1062         LOG.trace("Deleting AclPortsLookup for port={}, acls={}, AAPs={}", portId, aclList, allowedAddresses);
1063
1064         if (aclList == null || allowedAddresses == null || allowedAddresses.isEmpty()) {
1065             LOG.warn("aclList or allowedAddresses is null. port={}, acls={}, AAPs={}", portId, aclList,
1066                     allowedAddresses);
1067             return;
1068         }
1069
1070         for (Uuid aclId : aclList) {
1071             String aclName = aclId.getValue();
1072             jobCoordinator.enqueueJob(aclName, () -> {
1073                 List<ListenableFuture<Void>> futures = new ArrayList<>();
1074                 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
1075                     for (AllowedAddressPairs aap : allowedAddresses) {
1076                         InstanceIdentifier<PortIds> path =
1077                                 AclServiceUtils.getPortIdsPathInAclPortsLookup(aclName, aap.getIpAddress(), portId);
1078                         tx.delete(path);
1079                     }
1080
1081                     cleanUpStaleEntriesInAclPortsLookup(aclName, tx);
1082                 }));
1083                 return futures;
1084             });
1085         }
1086     }
1087
1088     private void cleanUpStaleEntriesInAclPortsLookup(String aclName, TypedWriteTransaction<Operational> tx) {
1089         AclPortsByIp aclPortsByIp = getAclPortsByIpFromOperDs(aclName);
1090         if (aclPortsByIp == null) {
1091             return;
1092         }
1093         boolean deleteEntireAcl;
1094         @NonNull Map<AclIpPrefixesKey, AclIpPrefixes> aclIpPrefixesKeyAclIpPrefixesMap
1095                 = aclPortsByIp.getAclIpPrefixes();
1096         if (aclIpPrefixesKeyAclIpPrefixesMap == null || aclIpPrefixesKeyAclIpPrefixesMap.isEmpty()) {
1097             deleteEntireAcl = true;
1098         } else {
1099             boolean deleteMap = true;
1100             for (AclIpPrefixes ipPrefix : aclIpPrefixesKeyAclIpPrefixesMap.values()) {
1101                 if (ipPrefix.getPortIds() != null && !ipPrefix.getPortIds().isEmpty()) {
1102                     deleteMap = false;
1103                     break;
1104                 }
1105             }
1106             deleteEntireAcl = deleteMap;
1107         }
1108         if (deleteEntireAcl) {
1109             tx.delete(AclServiceUtils.aclPortsByIpPath(aclName));
1110         } else {
1111             for (AclIpPrefixes ipPrefix : aclIpPrefixesKeyAclIpPrefixesMap.values()) {
1112                 if (ipPrefix.getPortIds() == null || ipPrefix.getPortIds().isEmpty()) {
1113                     InstanceIdentifier<AclIpPrefixes> delPath =
1114                             AclServiceUtils.getAclIpPrefixesPath(aclName, ipPrefix.getIpPrefix());
1115                     tx.delete(delPath);
1116                 }
1117             }
1118         }
1119     }
1120
1121     @Nullable
1122     private AclPortsByIp getAclPortsByIpFromOperDs(String aclName) {
1123         InstanceIdentifier<AclPortsByIp> path = aclPortsByIpPath(aclName);
1124         try (ReadTransaction tx = dataBroker.newReadOnlyTransaction()) {
1125             return tx.read(LogicalDatastoreType.OPERATIONAL, path).get().orElse(null);
1126         } catch (InterruptedException | ExecutionException e) {
1127             LOG.error("Failed to read ACL ports {}", path, e);
1128             return null;
1129         }
1130     }
1131
1132     @Nullable
1133     private AclIpPrefixes getAclIpPrefixesFromOperDs(String aclName, IpPrefixOrAddress ipPrefix) {
1134         InstanceIdentifier<AclIpPrefixes> path = getAclIpPrefixesPath(aclName, ipPrefix);
1135         try (ReadTransaction tx = dataBroker.newReadOnlyTransaction()) {
1136             return tx.read(LogicalDatastoreType.OPERATIONAL, path).get().orElse(null);
1137         } catch (InterruptedException | ExecutionException e) {
1138             LOG.error("Failed to read ACL IP prefixes {}", path, e);
1139             return null;
1140         }
1141     }
1142
1143     /**
1144      * Gets the ace flow priority.
1145      *
1146      * @param aclName the acl name
1147      * @return the ace flow priority
1148      */
1149     public Integer getAceFlowPriority(String aclName) {
1150         Integer priority = AclConstants.ACE_DEFAULT_PRIORITY;
1151         Integer aclTag = getAclTag(new Uuid(aclName));
1152         if (aclTag != null && aclTag != AclConstants.INVALID_ACL_TAG) {
1153             // To handle overlapping rules, aclTag is added to priority
1154             priority += aclTag;
1155         } else {
1156             LOG.warn("aclTag={} is null or invalid for aclName={}", aclTag, aclName);
1157         }
1158         return priority;
1159     }
1160
1161     /**
1162      * Returns the hard timeout based on the protocol when a ACL rule removed from the instance.
1163      * It will returns the timeout configured in the {@link AclserviceConfig} class.
1164      *
1165      * @param ace the ace
1166      * @param aclServiceUtils acl service utils
1167      * @return the hard time out
1168      */
1169     public static Integer getHardTimoutForApplyStatefulChangeOnExistingTraffic(Ace ace,
1170             AclServiceUtils aclServiceUtils) {
1171         int hardTimeout = AclConstants.SECURITY_GROUP_ICMP_IDLE_TIME_OUT;
1172         Matches matches = ace.getMatches();
1173         AceIp acl = (AceIp) matches.getAceType();
1174         Short protocol = acl.getProtocol() != null ? acl.getProtocol().toJava() : null;
1175         if (protocol == null) {
1176             return hardTimeout;
1177         } else if (protocol == NwConstants.IP_PROT_TCP
1178                 && aclServiceUtils.getConfig().getSecurityGroupTcpIdleTimeout() != null) {
1179             hardTimeout = aclServiceUtils.getConfig().getSecurityGroupTcpIdleTimeout().toJava();
1180         } else if (protocol == NwConstants.IP_PROT_UDP
1181                 && aclServiceUtils.getConfig().getSecurityGroupTcpIdleTimeout() != null) {
1182             hardTimeout = aclServiceUtils.getConfig().getSecurityGroupUdpIdleTimeout().toJava();
1183         }
1184         return hardTimeout;
1185     }
1186
1187     /**
1188      * This method creates and returns the ct_mark instruction when a ACL rule removed from the
1189      * instance. This instruction will reset the ct_mark value and stops the existing traffics.
1190      *
1191      * @param filterTable the filterTable
1192      * @param elanId the Elan id
1193      * @return list of instruction
1194      */
1195     public static List<InstructionInfo> createCtMarkInstructionForNewState(Short filterTable, Long elanId) {
1196
1197         List<InstructionInfo> instructions = new ArrayList<>();
1198         List<ActionInfo> actionsInfos = new ArrayList<>();
1199         List<NxCtAction> ctActionsList = new ArrayList<>();
1200         NxCtAction nxCtMarkClearAction = new ActionNxConntrack.NxCtMark(AclConstants.CT_MARK_NEW_STATE);
1201         ctActionsList.add(nxCtMarkClearAction);
1202
1203         ActionNxConntrack actionNxConntrack = new ActionNxConntrack(2, 1, 0, elanId.intValue(),
1204             (short) 255, ctActionsList);
1205         actionsInfos.add(actionNxConntrack);
1206         instructions.add(new InstructionApplyActions(actionsInfos));
1207         instructions.add(new InstructionGotoTable(filterTable));
1208
1209         return instructions;
1210     }
1211
1212     public static List<AllowedAddressPairs> excludeMulticastAAPs(@Nullable List<AllowedAddressPairs> allowedAddresses) {
1213         List<AllowedAddressPairs> filteredAAPs = new ArrayList<>();
1214         if (allowedAddresses != null) {
1215             for (AllowedAddressPairs allowedAddress : allowedAddresses) {
1216                 InetAddress inetAddr = getInetAddress(allowedAddress.getIpAddress());
1217                 if (inetAddr != null && !inetAddr.isMulticastAddress()) {
1218                     filteredAAPs.add(allowedAddress);
1219                 }
1220             }
1221         }
1222         return filteredAAPs;
1223     }
1224
1225     public static String getRecoverServiceRegistryKey() {
1226         return NetvirtAcl.class.toString();
1227     }
1228
1229     @Nullable
1230     private static InetAddress getInetAddress(IpPrefixOrAddress ipPrefixOrAddress) {
1231         String addr;
1232
1233         IpPrefix ipPrefix = ipPrefixOrAddress.getIpPrefix();
1234         if (ipPrefix != null) {
1235             addr = ipPrefix.stringValue().split("/")[0];
1236         } else {
1237             IpAddress ipAddress = ipPrefixOrAddress.getIpAddress();
1238             if (ipAddress == null) {
1239                 LOG.error("Invalid address : {}", ipPrefixOrAddress);
1240                 return null;
1241             } else {
1242                 addr = ipAddress.stringValue();
1243             }
1244         }
1245         try {
1246             return InetAddress.getByName(addr);
1247         } catch (UnknownHostException e) {
1248             LOG.error("Invalid address : {}", addr, e);
1249             return null;
1250         }
1251     }
1252
1253     public static Boolean isIpv6Subnet(List<SubnetInfo> subnetInfoList) {
1254         if (subnetInfoList != null && !subnetInfoList.isEmpty()) {
1255             for (SubnetInfo subnetInfo : subnetInfoList) {
1256                 if (subnetInfo != null && IpVersionV6.class.equals(subnetInfo.getIpVersion())) {
1257                     return true;
1258                 }
1259             }
1260         }
1261         return false;
1262     }
1263
1264     /**
1265      * Gets the subnet difference by performing (subnetInfo1 - subnetInfo2).
1266      *
1267      * @param subnetInfo1 the subnet info 1
1268      * @param subnetInfo2 the subnet info 2
1269      * @return the subnet diff
1270      */
1271     public static List<SubnetInfo> getSubnetDiff(List<SubnetInfo> subnetInfo1, List<SubnetInfo> subnetInfo2) {
1272         if (subnetInfo1 == null) {
1273             return Collections.emptyList();
1274         }
1275         List<SubnetInfo> newSubnetList = new ArrayList<>(subnetInfo1);
1276         if (subnetInfo2 == null) {
1277             return newSubnetList;
1278         }
1279         newSubnetList.removeAll(subnetInfo2);
1280         return newSubnetList;
1281     }
1282 }