Bug 7020: Deletion issue when VM has multiple SGs with same rules
[netvirt.git] / vpnservice / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / utils / AclServiceUtils.java
1 /*
2  * Copyright (c) 2016 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 com.google.common.base.Optional;
12 import com.googlecode.ipv6.IPv6Address;
13 import com.googlecode.ipv6.IPv6NetworkMask;
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.HashMap;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Future;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
28 import org.opendaylight.genius.mdsalutil.MDSALUtil;
29 import org.opendaylight.genius.mdsalutil.MatchFieldType;
30 import org.opendaylight.genius.mdsalutil.MatchInfo;
31 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
32 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
33 import org.opendaylight.genius.mdsalutil.NwConstants;
34 import org.opendaylight.genius.mdsalutil.NxMatchFieldType;
35 import org.opendaylight.genius.mdsalutil.NxMatchInfo;
36 import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
37 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.MatchCriteria;
38 import org.opendaylight.netvirt.aclservice.api.utils.AclInterface;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AccessLists;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.Ipv4Acl;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.AclKey;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.config.rev160806.AclserviceConfig;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.SecurityRuleAttr;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
84 import org.opendaylight.yangtools.yang.binding.DataObject;
85 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
86 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
87 import org.opendaylight.yangtools.yang.common.RpcResult;
88 import org.slf4j.Logger;
89 import org.slf4j.LoggerFactory;
90
91 @Singleton
92 @SuppressWarnings("deprecation")
93 public final class AclServiceUtils {
94
95     private static final Logger LOG = LoggerFactory.getLogger(AclServiceUtils.class);
96
97     private final AclDataUtil aclDataUtil;
98     private final AclserviceConfig config;
99
100     @Inject
101     public AclServiceUtils(AclDataUtil aclDataUtil, AclserviceConfig config) {
102         super();
103         this.aclDataUtil = aclDataUtil;
104         this.config = config;
105     }
106
107     /**
108      * Retrieves the Interface from the datastore.
109      * @param broker the data broker
110      * @param interfaceName the interface name
111      * @return the interface.
112      */
113     public static Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
114         .Interface> getInterface(DataBroker broker, String interfaceName) {
115         return read(broker, LogicalDatastoreType.CONFIGURATION, getInterfaceIdentifier(interfaceName));
116     }
117
118     /**
119      * Builds the interface identifier.
120      * @param interfaceName the interface name.
121      * @return the interface identifier.
122      */
123     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
124         .interfaces.Interface> getInterfaceIdentifier(String interfaceName) {
125         return InstanceIdentifier.builder(Interfaces.class)
126                 .child(
127                     org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
128                     .Interface.class, new InterfaceKey(interfaceName)).build();
129     }
130
131     /**
132      * Retrieves the object from the datastore.
133      * @param broker the data broker.
134      * @param datastoreType the data store type.
135      * @param path the wild card path.
136      * @param <T> type of DataObject
137      * @return the required object.
138      */
139     public static <T extends DataObject> Optional<T> read(
140             DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
141
142         Optional<T> result = Optional.absent();
143         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
144         try {
145             result = tx.read(datastoreType, path).checkedGet();
146         } catch (ReadFailedException e) {
147             LOG.warn("Failed to read InstanceIdentifier {} from {}", path, datastoreType, e);
148         } finally {
149             tx.close();
150         }
151         return result;
152     }
153
154     /**
155      * Retrieves the acl matching the key from the data store.
156      *
157      * @param broker the data broker
158      * @param aclKey the acl key
159      * @return the acl
160      */
161     public static Acl getAcl(DataBroker broker, String aclKey) {
162         Optional<Acl> optAcl = read(broker,
163             LogicalDatastoreType.CONFIGURATION, getAclInstanceIdentifier(aclKey));
164         if (optAcl.isPresent()) {
165             return optAcl.get();
166         }
167         return null;
168     }
169
170     /** Creates the Acl instance identifier.
171      *
172      * @param aclKey the acl key
173      * @return the instance identifier
174      */
175     public static InstanceIdentifier<Acl> getAclInstanceIdentifier(String aclKey) {
176         return InstanceIdentifier
177                 .builder(AccessLists.class)
178                 .child(Acl.class,
179                         new AclKey(aclKey,Ipv4Acl.class))
180                 .build();
181     }
182
183     /**
184      * Get the data path number for the interface.
185      * @param interfaceManagerRpcService interfaceManagerRpcService instance.
186      * @param ifName the interface name.
187      * @return the dpn.
188      */
189     public static BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {
190         BigInteger nodeId = BigInteger.ZERO;
191         try {
192             GetDpidFromInterfaceInput dpIdInput =
193                     new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
194             Future<RpcResult<GetDpidFromInterfaceOutput>> dpIdOutput =
195                     interfaceManagerRpcService.getDpidFromInterface(dpIdInput);
196             RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
197             if (dpIdResult.isSuccessful()) {
198                 nodeId = dpIdResult.getResult().getDpid();
199             } else {
200                 LOG.error("Could not retrieve DPN Id for interface {}", ifName);
201             }
202         } catch (NullPointerException | InterruptedException | ExecutionException e) {
203             LOG.error("Exception when getting dpn for interface {}", ifName,  e);
204         }
205         return nodeId;
206     }
207
208     /**
209      * Retrieves the interface state.
210      * @param dataBroker the data broker.
211      * @param interfaceName the interface name.
212      * @return the interface state.
213      */
214     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
215         .Interface getInterfaceStateFromOperDS(DataBroker dataBroker, String interfaceName) {
216         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
217             .interfaces.state.Interface> ifStateId = buildStateInterfaceId(interfaceName);
218         Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
219             .interfaces.state.Interface> ifStateOptional = MDSALUtil.read(LogicalDatastoreType
220                 .OPERATIONAL, ifStateId, dataBroker);
221         if (!ifStateOptional.isPresent()) {
222             return null;
223         }
224
225         return ifStateOptional.get();
226     }
227
228     /**
229      * Build the interface state.
230      * @param interfaceName the interface name.
231      * @return the interface state.
232      */
233     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
234         .interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
235         InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
236             .interfaces.state.Interface> idBuilder = InstanceIdentifier.builder(InterfacesState.class)
237             .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
238             .state.Interface.class, new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces
239             .rev140508.interfaces.state.InterfaceKey(interfaceName));
240         return idBuilder.build();
241     }
242
243     /**
244      * Checks whether port security is enabled for the port.
245      * @param port the port.
246      * @return the port security is enabled/not.
247      */
248     public static boolean isPortSecurityEnabled(AclInterface port) {
249         return port.isPortSecurityEnabled();
250     }
251
252     /**
253      * Checks whether port security is enabled for the port.
254      * @param port the port.
255      * @return the list of security groups.
256      */
257     public static List<Uuid> getInterfaceAcls(Interface port) {
258         if (port == null) {
259             LOG.error("Port is Null");
260             return null;
261         }
262         InterfaceAcl aclInPort = port.getAugmentation(InterfaceAcl.class);
263         if (aclInPort == null) {
264             LOG.error("getSecurityGroupInPortList: no security group associated}",
265                 port.getName());
266             return null;
267         }
268         return aclInPort.getSecurityGroups();
269     }
270
271     /**
272      * Retrieves the security rule attribute augmentation from the access list.
273      * @param ace the access list entry
274      * @return the security rule attributes
275      */
276     public static SecurityRuleAttr  getAccesssListAttributes(Ace ace) {
277         if (ace == null) {
278             LOG.error("Ace is Null");
279             return null;
280         }
281         SecurityRuleAttr aceAttributes = ace.getAugmentation(SecurityRuleAttr.class);
282         if (aceAttributes == null) {
283             LOG.error("Ace is null");
284             return null;
285         }
286         return aceAttributes;
287     }
288
289     /**
290      * Returns the DHCP match.
291      *
292      * @param srcPort the source port.
293      * @param dstPort the destination port.
294      * @param lportTag the lport tag
295      * @return list of matches.
296      */
297     public static List<MatchInfoBase> buildDhcpMatches(int srcPort, int dstPort, int lportTag) {
298         List<MatchInfoBase> matches = new ArrayList<>(6);
299         matches.add(new MatchInfo(MatchFieldType.eth_type,
300                 new long[] { NwConstants.ETHTYPE_IPV4 }));
301         matches.add(new MatchInfo(MatchFieldType.ip_proto,
302                 new long[] { IPProtocols.UDP.intValue() }));
303         matches.add(new MatchInfo(MatchFieldType.udp_dst,
304                 new long[] { dstPort }));
305         matches.add(new MatchInfo(MatchFieldType.udp_src,
306                 new long[] { srcPort}));
307         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag));
308         return matches;
309     }
310
311     /**
312      * Returns the DHCPv6 match.
313      *
314      * @param srcPort the source port.
315      * @param dstPort the destination port.
316      * @param lportTag the lport tag
317      * @return list of matches.
318      */
319     public static List<MatchInfoBase> buildDhcpV6Matches(int srcPort, int dstPort, int lportTag) {
320         List<MatchInfoBase> matches = new ArrayList<>(6);
321         matches.add(new MatchInfo(MatchFieldType.eth_type,
322                 new long[] { NwConstants.ETHTYPE_IPV6 }));
323         matches.add(new MatchInfo(MatchFieldType.ip_proto,
324                 new long[] { IPProtocols.UDP.intValue() }));
325         matches.add(new MatchInfo(MatchFieldType.udp_dst,
326                 new long[] { dstPort }));
327         matches.add(new MatchInfo(MatchFieldType.udp_src,
328                 new long[] { srcPort}));
329         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag));
330         return matches;
331     }
332
333     /**
334      * Returns the ICMPv6 match.
335      *
336      * @param icmpType the icmpv6-type.
337      * @param icmpCode the icmpv6-code.
338      * @param lportTag the lport tag
339      * @return list of matches.
340      */
341     public static List<MatchInfoBase> buildIcmpV6Matches(int icmpType, int icmpCode, int lportTag) {
342         List<MatchInfoBase> matches = new ArrayList<>(6);
343         matches.add(new MatchInfo(MatchFieldType.eth_type,
344                 new long[] { NwConstants.ETHTYPE_IPV6 }));
345         matches.add(new MatchInfo(MatchFieldType.ip_proto,
346                 new long[] { IPProtocols.IPV6ICMP.intValue() }));
347         if (icmpType != 0) {
348             matches.add(new MatchInfo(MatchFieldType.icmp_v6,
349                     new long[] { icmpType, icmpCode}));
350         }
351         matches.add(AclServiceUtils.buildLPortTagMatch(lportTag));
352         return matches;
353     }
354
355     /**
356      * Builds the service id.
357      *
358      * @param interfaceName the interface name
359      * @param serviceIndex the service index
360      * @param serviceMode the service mode
361      * @return the instance identifier
362      */
363     public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex,
364             Class<? extends ServiceModeBase> serviceMode) {
365         return InstanceIdentifier.builder(ServiceBindings.class)
366                 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, serviceMode))
367                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
368     }
369
370     /**
371      * Gets the bound services.
372      *
373      * @param serviceName the service name
374      * @param servicePriority the service priority
375      * @param flowPriority the flow priority
376      * @param cookie the cookie
377      * @param instructions the instructions
378      * @return the bound services
379      */
380     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
381             BigInteger cookie, List<Instruction> instructions) {
382         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
383                 .setInstruction(instructions);
384         return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
385                 .setServicePriority(servicePriority).setServiceType(ServiceTypeFlowBased.class)
386                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
387     }
388
389     public static List<Uuid> getUpdatedAclList(List<Uuid> updatedAclList, List<Uuid> currentAclList) {
390         if (updatedAclList == null) {
391             return null;
392         }
393         List<Uuid> newAclList = new ArrayList<>(updatedAclList);
394         if (currentAclList == null) {
395             return newAclList;
396         }
397         List<Uuid> origAclList = new ArrayList<>(currentAclList);
398         for (Iterator<Uuid> iterator = newAclList.iterator(); iterator.hasNext();) {
399             Uuid updatedAclUuid = iterator.next();
400             for (Uuid currentAclUuid :origAclList) {
401                 if (updatedAclUuid.getValue().equals(currentAclUuid.getValue())) {
402                     iterator.remove();
403                 }
404             }
405         }
406         return newAclList;
407     }
408
409     public static List<AllowedAddressPairs> getUpdatedAllowedAddressPairs(
410             List<AllowedAddressPairs> updatedAllowedAddressPairs,
411             List<AllowedAddressPairs> currentAllowedAddressPairs) {
412         if (updatedAllowedAddressPairs == null) {
413             return null;
414         }
415         List<AllowedAddressPairs> newAllowedAddressPairs = new ArrayList<>(updatedAllowedAddressPairs);
416         if (currentAllowedAddressPairs == null) {
417             return newAllowedAddressPairs;
418         }
419         List<AllowedAddressPairs> origAllowedAddressPairs = new ArrayList<>(currentAllowedAddressPairs);
420         for (Iterator<AllowedAddressPairs> iterator = newAllowedAddressPairs.iterator(); iterator.hasNext();) {
421             AllowedAddressPairs updatedAllowedAddressPair = iterator.next();
422             for (AllowedAddressPairs currentAllowedAddressPair : origAllowedAddressPairs) {
423                 if (updatedAllowedAddressPair.getKey().equals(currentAllowedAddressPair.getKey())) {
424                     iterator.remove();
425                     break;
426                 }
427             }
428         }
429         return newAllowedAddressPairs;
430     }
431
432     public static List<AllowedAddressPairs> getPortAllowedAddresses(Interface port) {
433         if (port == null) {
434             LOG.error("Port is Null");
435             return null;
436         }
437         InterfaceAcl aclInPort = port.getAugmentation(InterfaceAcl.class);
438         if (aclInPort == null) {
439             LOG.error("getSecurityGroupInPortList: no security group associated to Interface port: {}", port.getName());
440             return null;
441         }
442         return aclInPort.getAllowedAddressPairs();
443     }
444
445     public static BigInteger getDpIdFromIterfaceState(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
446             .interfaces.rev140508.interfaces.state.Interface interfaceState) {
447         BigInteger dpId = null;
448         List<String> ofportIds = interfaceState.getLowerLayerIf();
449         if (ofportIds != null && !ofportIds.isEmpty()) {
450             NodeConnectorId nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
451             dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
452         }
453         return dpId;
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         MatchFieldType matchFieldType;
468         if (ipPrefix != null) {
469             if (ipPrefix.getIpv4Prefix() != null) {
470                 flowMatches.add(new MatchInfo(MatchFieldType.eth_type, new long[] {NwConstants.ETHTYPE_IPV4}));
471                 String[] ipaddressValues = ipPrefix.getIpv4Prefix().getValue().split("/");
472                 matchFieldType = matchCriteria == MatchCriteria.MATCH_SOURCE
473                         ? MatchFieldType.ipv4_source : MatchFieldType.ipv4_destination;
474                 flowMatches.add(new MatchInfo(matchFieldType, new String[] {ipaddressValues[0], ipaddressValues[1]}));
475             } else {
476                 matchFieldType = matchCriteria == MatchCriteria.MATCH_SOURCE
477                         ? MatchFieldType.ipv6_source : MatchFieldType.ipv6_destination;
478                 String[] ipv6addressValues = ipPrefix.getIpv6Prefix().getValue().split("/");
479                 IPv6Address ipv6Address = IPv6Address.fromString(ipv6addressValues[0]);
480                 IPv6Address maskedV6Address = ipv6Address.maskWithNetworkMask(
481                         IPv6NetworkMask.fromPrefixLength(Integer.parseInt(ipv6addressValues[1])));
482                 flowMatches.add(new MatchInfo(MatchFieldType.eth_type, new long[] {NwConstants.ETHTYPE_IPV6}));
483                 flowMatches.add(new MatchInfo(matchFieldType,
484                         new String[] {maskedV6Address.toString() + "/" + ipv6addressValues[1]}));
485             }
486         } else {
487             IpAddress ipAddress = ipPrefixOrAddress.getIpAddress();
488             if (ipAddress.getIpv4Address() != null) {
489                 matchFieldType = matchCriteria == MatchCriteria.MATCH_SOURCE
490                         ? MatchFieldType.ipv4_source : MatchFieldType.ipv4_destination;
491                 flowMatches.add(new MatchInfo(MatchFieldType.eth_type, new long[] {NwConstants.ETHTYPE_IPV4}));
492                 flowMatches.add(new MatchInfo(matchFieldType,
493                         new String[] {ipAddress.getIpv4Address().getValue(), "32"}));
494             } else {
495                 matchFieldType = matchCriteria == MatchCriteria.MATCH_SOURCE
496                         ? MatchFieldType.ipv6_source : MatchFieldType.ipv6_destination;
497                 flowMatches.add(new MatchInfo(MatchFieldType.eth_type, new long[] {NwConstants.ETHTYPE_IPV6}));
498                 flowMatches.add(new MatchInfo(matchFieldType,
499                         new String[] {ipAddress.getIpv6Address().getValue() + "/128" }));
500             }
501         }
502         return flowMatches;
503     }
504
505     /**
506      * Gets the lport tag match.
507      *
508      * @param lportTag the lport tag
509      * @return the lport tag match
510      */
511     public static MatchInfo buildLPortTagMatch(int lportTag) {
512         return new MatchInfo(MatchFieldType.metadata,
513                 new BigInteger[] {MetaDataUtil.getLportTagMetaData(lportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG});
514     }
515
516     public static List<Ace> getAceWithRemoteAclId(DataBroker dataBroker, AclInterface port, Uuid remoteAcl) {
517         List<Ace> remoteAclRuleList = new ArrayList<>();
518         List<Uuid> aclList = port.getSecurityGroups();
519         for (Uuid aclId : aclList) {
520             Acl acl = getAcl(dataBroker, aclId.getValue());
521             List<Ace> aceList = acl.getAccessListEntries().getAce();
522             for (Ace ace : aceList) {
523                 Uuid tempRemoteAcl = getAccesssListAttributes(ace).getRemoteGroupId();
524                 if (tempRemoteAcl != null && tempRemoteAcl.equals(remoteAcl)) {
525                     remoteAclRuleList.add(ace);
526                 }
527             }
528         }
529         return remoteAclRuleList;
530     }
531
532     public Map<String, List<MatchInfoBase>> getFlowForRemoteAcl(Uuid remoteAclId, String ignoreInterfaceId,
533                                                                        Map<String, List<MatchInfoBase>>
534                                                                                flowMatchesMap, boolean
535                                                                                isSourceIpMacMatch) {
536         List<AclInterface> interfaceList = aclDataUtil.getInterfaceList(remoteAclId);
537         if (flowMatchesMap == null || interfaceList == null || interfaceList.isEmpty()) {
538             return null;
539         }
540         Map<String, List<MatchInfoBase>> updatedFlowMatchesMap = new HashMap<>();
541         MatchInfoBase ipv4Match = new MatchInfo(MatchFieldType.eth_type, new long[] {NwConstants.ETHTYPE_IPV4});
542         MatchInfoBase ipv6Match = new MatchInfo(MatchFieldType.eth_type, new long[] {NwConstants.ETHTYPE_IPV6});
543         for (String flowName : flowMatchesMap.keySet()) {
544             List<MatchInfoBase> flows = flowMatchesMap.get(flowName);
545             for (AclInterface port : interfaceList) {
546                 if (port.getInterfaceId().equals(ignoreInterfaceId)) {
547                     continue;
548                 }
549                 //get allow address pair
550                 List<AllowedAddressPairs> allowedAddressPair = port.getAllowedAddressPairs();
551                 // iterate over allow address pair and update match type
552                 for (AllowedAddressPairs aap : allowedAddressPair) {
553                     List<MatchInfoBase> matchInfoBaseList;
554                     String flowId;
555                     if (flows.contains(ipv4Match) && isIPv4Address(aap)) {
556                         matchInfoBaseList = updateAAPMatches(isSourceIpMacMatch, flows, aap);
557                         flowId = flowName + "_ipv4_remoteACL_interface_aap_" + aap.getKey();
558                         updatedFlowMatchesMap.put(flowId, matchInfoBaseList);
559                     } else if (flows.contains(ipv6Match) && !isIPv4Address(aap)) {
560                         matchInfoBaseList = updateAAPMatches(isSourceIpMacMatch, flows, aap);
561                         flowId = flowName + "_ipv6_remoteACL_interface_aap_" +  aap.getKey();
562                         updatedFlowMatchesMap.put(flowId, matchInfoBaseList);
563                     }
564                 }
565
566             }
567
568         }
569         return updatedFlowMatchesMap;
570     }
571
572     public AclserviceConfig getConfig() {
573         return config;
574     }
575
576     private static boolean isIPv4Address(AllowedAddressPairs aap) {
577         IpPrefixOrAddress ipPrefixOrAddress = aap.getIpAddress();
578         IpPrefix ipPrefix = ipPrefixOrAddress.getIpPrefix();
579         if (ipPrefix != null) {
580             if (ipPrefix.getIpv4Prefix() != null) {
581                 return true;
582             }
583         } else {
584             IpAddress ipAddress = ipPrefixOrAddress.getIpAddress();
585             if (ipAddress.getIpv4Address() != null) {
586                 return true;
587             }
588         }
589         return false;
590     }
591
592     public static Map<String, List<MatchInfoBase>> getFlowForAllowedAddresses(List<AllowedAddressPairs>
593                                                                                       syncAllowedAddresses,
594                                                                               Map<String, List<MatchInfoBase>>
595                                                                                       flowMatchesMap, boolean
596                                                                                       isSourceIpMacMatch) {
597         if (flowMatchesMap == null) {
598             return null;
599         }
600         Map<String, List<MatchInfoBase>> updatedFlowMatchesMap = new HashMap<>();
601         MatchInfoBase ipv4Match = new MatchInfo(MatchFieldType.eth_type, new long[] {NwConstants.ETHTYPE_IPV4});
602         MatchInfoBase ipv6Match = new MatchInfo(MatchFieldType.eth_type, new long[] {NwConstants.ETHTYPE_IPV6});
603         for (String flowName : flowMatchesMap.keySet()) {
604             List<MatchInfoBase> flows = flowMatchesMap.get(flowName);
605             // iterate over allow address pair and update match type
606             for (AllowedAddressPairs aap : syncAllowedAddresses) {
607                 List<MatchInfoBase> matchInfoBaseList;
608                 String flowId;
609                 if (flows.contains(ipv4Match) && isIPv4Address(aap)) {
610                     matchInfoBaseList = updateAAPMatches(isSourceIpMacMatch, flows, aap);
611                     flowId = flowName + "_ipv4_remoteACL_interface_aap_" + aap.getKey();
612                     updatedFlowMatchesMap.put(flowId, matchInfoBaseList);
613                 } else if (flows.contains(ipv6Match) && !isIPv4Address(aap)) {
614                     matchInfoBaseList = updateAAPMatches(isSourceIpMacMatch, flows, aap);
615                     flowId = flowName + "_ipv6_remoteACL_interface_aap_" + aap.getKey();
616                     updatedFlowMatchesMap.put(flowId, matchInfoBaseList);
617                 }
618             }
619
620         }
621         return updatedFlowMatchesMap;
622     }
623
624     public static Long getElanIdFromInterface(String elanInterfaceName,DataBroker broker) {
625         ElanInterface elanInterface = getElanInterfaceByElanInterfaceName(elanInterfaceName, broker);
626         if (null != elanInterface) {
627             ElanInstance elanInfo = getElanInstanceByName(elanInterface.getElanInstanceName(), broker);
628             return elanInfo.getElanTag();
629         }
630         return null;
631     }
632
633     public static ElanInterface getElanInterfaceByElanInterfaceName(String elanInterfaceName,DataBroker broker) {
634         InstanceIdentifier<ElanInterface> elanInterfaceId = getElanInterfaceConfigurationDataPathId(elanInterfaceName);
635         Optional<ElanInterface> existingElanInterface = read(broker,
636                 LogicalDatastoreType.CONFIGURATION, elanInterfaceId);
637         if (existingElanInterface.isPresent()) {
638             return existingElanInterface.get();
639         }
640         return null;
641     }
642
643     public static InstanceIdentifier<ElanInterface> getElanInterfaceConfigurationDataPathId(String interfaceName) {
644         return InstanceIdentifier.builder(ElanInterfaces.class)
645                 .child(ElanInterface.class, new ElanInterfaceKey(interfaceName)).build();
646     }
647
648     // elan-instances config container
649     public static ElanInstance getElanInstanceByName(String elanInstanceName, DataBroker broker) {
650         InstanceIdentifier<ElanInstance> elanIdentifierId = getElanInstanceConfigurationDataPath(elanInstanceName);
651         Optional<ElanInstance> elanInstance = read(broker, LogicalDatastoreType.CONFIGURATION,
652                 elanIdentifierId);
653         if (elanInstance.isPresent()) {
654             return elanInstance.get();
655         }
656         return null;
657     }
658
659     public static InstanceIdentifier<ElanInstance> getElanInstanceConfigurationDataPath(String elanInstanceName) {
660         return InstanceIdentifier.builder(ElanInstances.class)
661                 .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
662     }
663
664     private static List<MatchInfoBase> updateAAPMatches(boolean isSourceIpMacMatch, List<MatchInfoBase> flows,
665                                                         AllowedAddressPairs aap) {
666         List<MatchInfoBase> matchInfoBaseList;
667         if (isSourceIpMacMatch) {
668             matchInfoBaseList = AclServiceUtils.buildIpMatches(aap.getIpAddress(), MatchCriteria.MATCH_SOURCE);
669         } else {
670             matchInfoBaseList = AclServiceUtils.buildIpMatches(aap.getIpAddress(), MatchCriteria.MATCH_DESTINATION);
671         }
672         matchInfoBaseList.addAll(flows);
673         return matchInfoBaseList;
674     }
675
676     public static MatchInfoBase popMatchInfoByType(List<MatchInfoBase> flows, MatchFieldType type) {
677         MatchInfoBase mib = getMatchInfoByType(flows, type);
678         if (mib != null) {
679             flows.remove(mib);
680         }
681         return mib;
682     }
683
684     public static MatchInfoBase getMatchInfoByType(List<MatchInfoBase> flows, MatchFieldType type) {
685         for (MatchInfoBase mib : flows) {
686             if (mib instanceof MatchInfo) {
687                 if (((MatchInfo)mib).getMatchField() == type) {
688                     return mib;
689                 }
690             }
691         }
692         return null;
693     }
694
695     public static MatchInfoBase getMatchInfoByType(List<MatchInfoBase> flows, NxMatchFieldType type) {
696         for (MatchInfoBase mib : flows) {
697             if (mib instanceof NxMatchInfo) {
698                 if (((NxMatchInfo)mib).getMatchField() == type) {
699                     return mib;
700                 }
701             }
702         }
703         return null;
704     }
705
706     public static boolean containsMatchFieldType(List<MatchInfoBase> flows, MatchFieldType type) {
707         MatchInfoBase mib = getMatchInfoByType(flows, type);
708         if (mib != null) {
709             return true;
710         }
711         return false;
712     }
713
714     public static boolean containsMatchFieldType(List<MatchInfoBase> flows, NxMatchFieldType type) {
715         MatchInfoBase mib = getMatchInfoByType(flows, type);
716         if (mib != null) {
717             return true;
718         }
719         return false;
720     }
721
722     public static Integer allocateId(IdManagerService idManager, String poolName, String idKey) {
723         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
724         try {
725             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
726             RpcResult<AllocateIdOutput> rpcResult = result.get();
727             if (rpcResult.isSuccessful()) {
728                 return rpcResult.getResult().getIdValue().intValue();
729             } else {
730                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
731             }
732         } catch (InterruptedException | ExecutionException e) {
733             LOG.warn("Exception when getting Unique Id", e);
734         }
735         return AclConstants.PROTO_MATCH_PRIORITY;
736     }
737
738     public static void releaseId(IdManagerService idManager, String poolName, String idKey) {
739         ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
740         try {
741             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
742             RpcResult<Void> rpcResult = result.get();
743             if (!rpcResult.isSuccessful()) {
744                 LOG.warn("RPC Call to release Id {} with Key {} returned with Errors {}", idKey, rpcResult.getErrors());
745             }
746         } catch (InterruptedException | ExecutionException e) {
747             LOG.warn("Exception when releasing Id for key {}", idKey, e);
748         }
749     }
750 }