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