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