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