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