Fix FindBugs violations and enable enforcement in elanmanager-impl
[netvirt.git] / vpnservice / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / netvirt / elan / utils / ElanUtils.java
1 /*
2  * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.netvirt.elan.utils;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.base.Strings;
13 import com.google.common.collect.Lists;
14 import com.google.common.primitives.Ints;
15 import com.google.common.util.concurrent.CheckedFuture;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import com.google.common.util.concurrent.MoreExecutors;
20 import java.math.BigInteger;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ExecutionException;
30 import java.util.concurrent.Future;
31 import javax.annotation.Nonnull;
32 import javax.annotation.Nullable;
33 import javax.inject.Inject;
34 import javax.inject.Singleton;
35 import org.apache.commons.lang3.StringUtils;
36 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
37 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
38 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
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.controller.md.sal.common.api.data.TransactionCommitFailedException;
42 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
43 import org.opendaylight.genius.interfacemanager.globals.InterfaceServiceUtil;
44 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
45 import org.opendaylight.genius.itm.globals.ITMConstants;
46 import org.opendaylight.genius.mdsalutil.ActionInfo;
47 import org.opendaylight.genius.mdsalutil.FlowEntity;
48 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
49 import org.opendaylight.genius.mdsalutil.InstructionInfo;
50 import org.opendaylight.genius.mdsalutil.MDSALUtil;
51 import org.opendaylight.genius.mdsalutil.MatchInfo;
52 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
53 import org.opendaylight.genius.mdsalutil.NWUtil;
54 import org.opendaylight.genius.mdsalutil.NwConstants;
55 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
56 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
57 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
58 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
59 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
60 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetSource;
61 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
62 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
63 import org.opendaylight.genius.mdsalutil.packet.ARP;
64 import org.opendaylight.genius.mdsalutil.packet.Ethernet;
65 import org.opendaylight.genius.mdsalutil.packet.IPv4;
66 import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
67 import org.opendaylight.netvirt.elan.ElanException;
68 import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
69 import org.opendaylight.netvirt.elan.internal.ElanInstanceManager;
70 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
71 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
72 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
73 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
74 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
75 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
76 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
77 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
78 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
79 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.IfIndexesInterfaceMap;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._if.indexes._interface.map.IfIndexInterface;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._if.indexes._interface.map.IfIndexInterfaceKey;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInput;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
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.genius.itm.op.rev160406.ExternalTunnelList;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnelKey;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInput;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInputBuilder;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.config.rev150710.ElanConfig;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstanceBuilder;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTag;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagNameBuilder;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaceForwardingEntries;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanState;
140 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanTagNameMap;
141 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeFlat;
142 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVlan;
143 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVxlan;
144 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
145 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
146 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
147 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
148 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
149 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
150 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
151 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableBuilder;
152 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
153 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
154 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
155 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ElanSegments;
156 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
157 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
158 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
159 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntriesBuilder;
160 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntriesKey;
161 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
162 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
163 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
164 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagName;
165 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagNameBuilder;
166 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagNameKey;
167 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
168 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
169 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
170 import org.opendaylight.yangtools.yang.binding.DataObject;
171 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
172 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
173 import org.opendaylight.yangtools.yang.common.RpcResult;
174 import org.slf4j.Logger;
175 import org.slf4j.LoggerFactory;
176
177 @Singleton
178 public class ElanUtils {
179
180     private static final Logger LOG = LoggerFactory.getLogger(ElanUtils.class);
181
182     private static Map<String, ElanInstance> elanInstanceLocalCache = new ConcurrentHashMap<>();
183     private static Map<String, ElanInterface> elanInterfaceLocalCache = new ConcurrentHashMap<>();
184     private static Map<String, Set<DpnInterfaces>> elanInstancToDpnsCache = new ConcurrentHashMap<>();
185     private static Map<String, Set<String>> elanInstanceToInterfacesCache = new ConcurrentHashMap<>();
186
187     private final DataBroker broker;
188     private final IMdsalApiManager mdsalManager;
189     private final ElanInstanceManager elanInstanceManager;
190     private final OdlInterfaceRpcService interfaceManagerRpcService;
191     private final ItmRpcService itmRpcService;
192     private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
193     private final IInterfaceManager interfaceManager;
194     private final ElanConfig elanConfig;
195     private final ElanItmUtils elanItmUtils;
196     private final ElanEtreeUtils elanEtreeUtils;
197
198     public static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
199         @Override
200         public void onSuccess(Void result) {
201             LOG.debug("Success in Datastore operation");
202         }
203
204         @Override
205         public void onFailure(Throwable error) {
206             LOG.error("Error in Datastore operation", error);
207         }
208     };
209
210     @Inject
211     public ElanUtils(DataBroker dataBroker, IMdsalApiManager mdsalManager, ElanInstanceManager elanInstanceManager,
212                      OdlInterfaceRpcService interfaceManagerRpcService, ItmRpcService itmRpcService,
213                      ElanConfig elanConfig,
214                      IInterfaceManager interfaceManager,
215                      ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils, ElanEtreeUtils elanEtreeUtils,
216                      ElanItmUtils elanItmUtils) {
217         this.broker = dataBroker;
218         this.mdsalManager = mdsalManager;
219         this.elanInstanceManager = elanInstanceManager;
220         this.interfaceManagerRpcService = interfaceManagerRpcService;
221         this.itmRpcService = itmRpcService;
222         this.interfaceManager = interfaceManager;
223         this.elanConfig = elanConfig;
224
225         this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
226         this.elanEtreeUtils = elanEtreeUtils;
227         this.elanItmUtils = elanItmUtils;
228     }
229
230     public ElanL2GatewayMulticastUtils getElanL2GatewayMulticastUtils() {
231         return elanL2GatewayMulticastUtils;
232     }
233
234     public final Boolean isOpenstackVniSemanticsEnforced() {
235         return elanConfig.isOpenstackVniSemanticsEnforced() != null
236                 ? elanConfig.isOpenstackVniSemanticsEnforced() : false;
237     }
238
239     public static void addElanInstanceIntoCache(String elanInstanceName, ElanInstance elanInstance) {
240         elanInstanceLocalCache.put(elanInstanceName, elanInstance);
241     }
242
243     public static void removeElanInstanceFromCache(String elanInstanceName) {
244         elanInstanceLocalCache.remove(elanInstanceName);
245     }
246
247     public static ElanInstance getElanInstanceFromCache(String elanInstanceName) {
248         return elanInstanceLocalCache.get(elanInstanceName);
249     }
250
251     public static Set<String> getAllElanNames() {
252         return elanInstanceLocalCache.keySet();
253     }
254
255     public static void addElanInterfaceIntoCache(String interfaceName, ElanInterface elanInterface) {
256         elanInterfaceLocalCache.put(interfaceName, elanInterface);
257     }
258
259     public static void removeElanInterfaceFromCache(String interfaceName) {
260         elanInterfaceLocalCache.remove(interfaceName);
261     }
262
263     public static ElanInterface getElanInterfaceFromCache(String interfaceName) {
264         return elanInterfaceLocalCache.get(interfaceName);
265     }
266
267     /**
268      * Uses the IdManager to retrieve a brand new ElanTag.
269      *
270      * @param idManager
271      *            the id manager
272      * @param idKey
273      *            the id key
274      * @return the integer
275      */
276     public static Long retrieveNewElanTag(IdManagerService idManager, String idKey) {
277
278         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME)
279                 .setIdKey(idKey).build();
280
281         try {
282             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
283             RpcResult<AllocateIdOutput> rpcResult = result.get();
284             if (rpcResult.isSuccessful()) {
285                 return rpcResult.getResult().getIdValue();
286             } else {
287                 LOG.warn("RPC Call to Allocate Id returned with Errors {}", rpcResult.getErrors());
288             }
289         } catch (InterruptedException | ExecutionException e) {
290             LOG.warn("Exception when Allocating Id", e);
291         }
292         return 0L;
293     }
294
295     public static void releaseId(IdManagerService idManager, String poolName, String idKey) {
296         ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
297         JdkFutures.addErrorLogging(idManager.releaseId(releaseIdInput), LOG, "Release Id");
298     }
299
300     /**
301      * Read utility.
302      *
303      * @deprecated Consider using {@link #read2(LogicalDatastoreType, InstanceIdentifier)} with proper exception
304      *             handling instead
305      */
306     @Deprecated
307     @SuppressWarnings("checkstyle:IllegalCatch")
308     public static <T extends DataObject> Optional<T> read(@Nonnull DataBroker broker,
309             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
310         try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
311             return tx.read(datastoreType, path).get();
312         } catch (Exception e) {
313             throw new RuntimeException(e);
314         }
315     }
316
317     public <T extends DataObject> Optional<T> read2(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
318             throws ReadFailedException {
319         try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
320             CheckedFuture<Optional<T>, ReadFailedException> checkedFuture = tx.read(datastoreType, path);
321             return checkedFuture.checkedGet();
322         }
323     }
324
325     public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
326             InstanceIdentifier<T> path) {
327         WriteTransaction tx = broker.newWriteOnlyTransaction();
328         tx.delete(datastoreType, path);
329         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK, MoreExecutors.directExecutor());
330     }
331
332     public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
333             InstanceIdentifier<T> path, FutureCallback<Void> callback) {
334         WriteTransaction tx = broker.newWriteOnlyTransaction();
335         tx.delete(datastoreType, path);
336         Futures.addCallback(tx.submit(), callback, MoreExecutors.directExecutor());
337     }
338
339     public static InstanceIdentifier<ElanInstance> getElanInstanceIdentifier() {
340         return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class).build();
341     }
342
343     // elan-instances config container
344     @Nullable
345     public static ElanInstance getElanInstanceByName(DataBroker broker, String elanInstanceName) {
346         ElanInstance elanObj = getElanInstanceFromCache(elanInstanceName);
347         if (elanObj != null) {
348             return elanObj;
349         }
350         InstanceIdentifier<ElanInstance> elanIdentifierId =
351                 ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName);
352         return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId).orNull();
353     }
354
355     // elan-interfaces Config Container
356     public static ElanInterface getElanInterfaceByElanInterfaceName(DataBroker broker, String elanInterfaceName) {
357         ElanInterface elanInterfaceObj = getElanInterfaceFromCache(elanInterfaceName);
358         if (elanInterfaceObj != null) {
359             return elanInterfaceObj;
360         }
361         InstanceIdentifier<ElanInterface> elanInterfaceId = getElanInterfaceConfigurationDataPathId(elanInterfaceName);
362         return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId).orNull();
363     }
364
365     public static EtreeInterface getEtreeInterfaceByElanInterfaceName(DataBroker broker, String elanInterfaceName) {
366         ElanInterface elanInterface = getElanInterfaceByElanInterfaceName(broker, elanInterfaceName);
367         if (elanInterface == null) {
368             return null;
369         } else {
370             return elanInterface.getAugmentation(EtreeInterface.class);
371         }
372     }
373
374     public static InstanceIdentifier<ElanInterface> getElanInterfaceConfigurationDataPathId(String interfaceName) {
375         return InstanceIdentifier.builder(ElanInterfaces.class)
376                 .child(ElanInterface.class, new ElanInterfaceKey(interfaceName)).build();
377     }
378
379     // elan-state Operational container
380     public static Elan getElanByName(DataBroker broker, String elanInstanceName) {
381         InstanceIdentifier<Elan> elanIdentifier = getElanInstanceOperationalDataPath(elanInstanceName);
382         return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).orNull();
383     }
384
385     public static InstanceIdentifier<Elan> getElanInstanceOperationalDataPath(String elanInstanceName) {
386         return InstanceIdentifier.builder(ElanState.class).child(Elan.class, new ElanKey(elanInstanceName)).build();
387     }
388
389     // grouping of forwarding-entries
390     public MacEntry getInterfaceMacEntriesOperationalDataPath(String interfaceName, PhysAddress physAddress) {
391         InstanceIdentifier<MacEntry> existingMacEntryId = getInterfaceMacEntriesIdentifierOperationalDataPath(
392                 interfaceName, physAddress);
393         return read(broker, LogicalDatastoreType.OPERATIONAL, existingMacEntryId).orNull();
394     }
395
396     public MacEntry getInterfaceMacEntriesOperationalDataPathFromId(InstanceIdentifier identifier) {
397         Optional<MacEntry> existingInterfaceMacEntry = read(broker,
398                 LogicalDatastoreType.OPERATIONAL, identifier);
399         return existingInterfaceMacEntry.orNull();
400     }
401
402     public static InstanceIdentifier<MacEntry> getInterfaceMacEntriesIdentifierOperationalDataPath(String interfaceName,
403             PhysAddress physAddress) {
404         return InstanceIdentifier.builder(ElanInterfaceForwardingEntries.class)
405                 .child(ElanInterfaceMac.class, new ElanInterfaceMacKey(interfaceName))
406                 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
407
408     }
409
410     // elan-forwarding-tables Operational container
411     public Optional<MacEntry> getMacEntryForElanInstance(String elanName, PhysAddress physAddress) {
412         InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanName, physAddress);
413         return read(broker, LogicalDatastoreType.OPERATIONAL, macId);
414     }
415
416     public MacEntry getMacEntryFromElanMacId(InstanceIdentifier identifier) {
417         Optional<MacEntry> existingInterfaceMacEntry = read(broker,
418                 LogicalDatastoreType.OPERATIONAL, identifier);
419         return existingInterfaceMacEntry.orNull();
420     }
421
422     public static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
423             PhysAddress physAddress) {
424         return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
425                 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
426     }
427
428     public static InstanceIdentifier<MacTable> getElanMacTableOperationalDataPath(String elanName) {
429         return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
430                 .build();
431     }
432
433     // elan-interface-forwarding-entries Operational container
434     public ElanInterfaceMac getElanInterfaceMacByInterfaceName(String interfaceName) {
435         return getElanInterfaceMacByInterfaceName(broker, interfaceName);
436     }
437
438     @Nullable
439     public static ElanInterfaceMac getElanInterfaceMacByInterfaceName(DataBroker dataBroker, String interfaceName) {
440         InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = getElanInterfaceMacEntriesOperationalDataPath(
441                 interfaceName);
442         return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId).orNull();
443     }
444
445     /**
446      * Gets the elan interface mac addresses.
447      *
448      * @param interfaceName
449      *            the interface name
450      * @return the elan interface mac addresses
451      */
452     public List<PhysAddress> getElanInterfaceMacAddresses(String interfaceName) {
453         List<PhysAddress> macAddresses = new ArrayList<>();
454         ElanInterfaceMac elanInterfaceMac = getElanInterfaceMacByInterfaceName(interfaceName);
455         if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
456             List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
457             for (MacEntry macEntry : macEntries) {
458                 macAddresses.add(macEntry.getMacAddress());
459             }
460         }
461         return macAddresses;
462     }
463
464     public static InstanceIdentifier<ElanInterfaceMac> getElanInterfaceMacEntriesOperationalDataPath(
465             String interfaceName) {
466         return InstanceIdentifier.builder(ElanInterfaceForwardingEntries.class)
467                 .child(ElanInterfaceMac.class, new ElanInterfaceMacKey(interfaceName)).build();
468     }
469
470     /**
471      * Returns the list of Interfaces that belong to an Elan on an specific DPN.
472      * Data retrieved from Elan's operational DS: elan-dpn-interfaces container
473      *
474      * @param elanInstanceName
475      *            name of the Elan to which the interfaces must belong to
476      * @param dpId
477      *            Id of the DPN where the interfaces are located
478      * @return the elan interface Info
479      */
480     public DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId) {
481         InstanceIdentifier<DpnInterfaces> elanDpnInterfacesId = getElanDpnInterfaceOperationalDataPath(elanInstanceName,
482                 dpId);
483         return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfacesId).orNull();
484     }
485
486     /**
487      * Returns the InstanceIdentifier that points to the Interfaces of an Elan
488      * in a given DPN in the Operational DS. Data retrieved from Elans's
489      * operational DS: dpn-interfaces list
490      *
491      * @param elanInstanceName
492      *            name of the Elan to which the interfaces must belong to
493      * @param dpId
494      *            Id of the DPN where the interfaces are located
495      * @return the elan dpn interface
496      */
497     public static InstanceIdentifier<DpnInterfaces> getElanDpnInterfaceOperationalDataPath(String elanInstanceName,
498             BigInteger dpId) {
499         return InstanceIdentifier.builder(ElanDpnInterfaces.class)
500                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName))
501                 .child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build();
502     }
503
504     // elan-tag-name-map Operational Container
505     public ElanTagName getElanInfoByElanTag(long elanTag) {
506         InstanceIdentifier<ElanTagName> elanId = getElanInfoEntriesOperationalDataPath(elanTag);
507         Optional<ElanTagName> existingElanInfo = read(broker,
508                 LogicalDatastoreType.OPERATIONAL, elanId);
509         return existingElanInfo.orNull();
510     }
511
512     public static InstanceIdentifier<ElanTagName> getElanInfoEntriesOperationalDataPath(long elanTag) {
513         return InstanceIdentifier.builder(ElanTagNameMap.class).child(ElanTagName.class, new ElanTagNameKey(elanTag))
514                 .build();
515     }
516
517     // interface-index-tag operational container
518     public Optional<IfIndexInterface> getInterfaceInfoByInterfaceTag(long interfaceTag) {
519         InstanceIdentifier<IfIndexInterface> interfaceId = getInterfaceInfoEntriesOperationalDataPath(interfaceTag);
520         return read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
521     }
522
523     public static InstanceIdentifier<IfIndexInterface> getInterfaceInfoEntriesOperationalDataPath(long interfaceTag) {
524         return InstanceIdentifier.builder(IfIndexesInterfaceMap.class)
525                 .child(IfIndexInterface.class, new IfIndexInterfaceKey((int) interfaceTag)).build();
526     }
527
528     public static InstanceIdentifier<ElanDpnInterfacesList> getElanDpnOperationDataPath(String elanInstanceName) {
529         return InstanceIdentifier.builder(ElanDpnInterfaces.class)
530                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
531     }
532
533     public ElanDpnInterfacesList getElanDpnInterfacesList(String elanName) {
534         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanName);
535         return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orNull();
536     }
537
538     public ElanDpnInterfaces getElanDpnInterfacesList() {
539         InstanceIdentifier<ElanDpnInterfaces> elanDpnInterfaceId = InstanceIdentifier.builder(ElanDpnInterfaces.class)
540                 .build();
541         return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orNull();
542     }
543
544     /**
545      * This method is useful get all ELAN participating CSS dpIds to install
546      * program remote dmac entries and updating remote bc groups for tor
547      * integration.
548      *
549      * @param elanInstanceName
550      *            the elan instance name
551      * @return list of dpIds
552      */
553     @Nonnull
554     public List<BigInteger> getParticipatingDpnsInElanInstance(String elanInstanceName) {
555         List<BigInteger> dpIds = new ArrayList<>();
556         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
557         Optional<ElanDpnInterfacesList> existingElanDpnInterfaces = read(broker,
558                 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
559         if (!existingElanDpnInterfaces.isPresent()) {
560             return dpIds;
561         }
562         List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces();
563         for (DpnInterfaces dpnInterface : dpnInterfaces) {
564             dpIds.add(dpnInterface.getDpId());
565         }
566         return dpIds;
567     }
568
569     /**
570      * To check given dpId is already present in Elan instance. This can be used
571      * to program flow entry in external tunnel table when a new access port
572      * added for first time into the ELAN instance
573      *
574      * @param dpId
575      *            the dp id
576      * @param elanInstanceName
577      *            the elan instance name
578      * @return true if dpId is already present, otherwise return false
579      */
580     public boolean isDpnAlreadyPresentInElanInstance(BigInteger dpId, String elanInstanceName) {
581         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
582         Optional<ElanDpnInterfacesList> existingElanDpnInterfaces = read(broker,
583                 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
584         if (!existingElanDpnInterfaces.isPresent()) {
585             return false;
586         }
587         List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces();
588         for (DpnInterfaces dpnInterface : dpnInterfaces) {
589             if (dpnInterface.getDpId().equals(dpId)) {
590                 return true;
591             }
592         }
593         return false;
594     }
595
596     public ElanForwardingTables getElanForwardingList() {
597         InstanceIdentifier<ElanForwardingTables> elanForwardingTableId = InstanceIdentifier
598                 .builder(ElanForwardingTables.class).build();
599         return read(broker, LogicalDatastoreType.OPERATIONAL, elanForwardingTableId).orNull();
600     }
601
602     public static long getElanRemoteBroadCastGroupID(long elanTag) {
603         return ElanConstants.ELAN_GID_MIN + elanTag % ElanConstants.ELAN_GID_MIN * 2;
604     }
605
606     /**
607      * Gets the elan mac table.
608      *
609      * @param elanName
610      *            the elan name
611      * @return the elan mac table
612      */
613     public MacTable getElanMacTable(String elanName) {
614         return getElanMacTable(broker, elanName);
615     }
616
617     @Nullable
618     public static MacTable getElanMacTable(DataBroker dataBroker, String elanName) {
619         InstanceIdentifier<MacTable> elanMacTableId = getElanMacTableOperationalDataPath(elanName);
620         return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanMacTableId).orNull();
621     }
622
623     public static long getElanLocalBCGId(long elanTag) {
624         return ElanConstants.ELAN_GID_MIN + (elanTag % ElanConstants.ELAN_GID_MIN * 2 - 1);
625     }
626
627     public static long getElanRemoteBCGId(long elanTag) {
628         return ElanConstants.ELAN_GID_MIN + elanTag % ElanConstants.ELAN_GID_MIN * 2;
629     }
630
631     public static long getEtreeLeafLocalBCGId(long etreeLeafTag) {
632         return ElanConstants.ELAN_GID_MIN + (etreeLeafTag % ElanConstants.ELAN_GID_MIN * 2 - 1);
633     }
634
635     public static long getEtreeLeafRemoteBCGId(long etreeLeafTag) {
636         return ElanConstants.ELAN_GID_MIN + etreeLeafTag % ElanConstants.ELAN_GID_MIN * 2;
637     }
638
639     public static BigInteger getElanMetadataLabel(long elanTag, boolean isSHFlagSet) {
640         int shBit = isSHFlagSet ? 1 : 0;
641         return BigInteger.valueOf(elanTag).shiftLeft(24).or(BigInteger.valueOf(shBit));
642     }
643
644     /**
645      * Setting SMAC, DMAC, UDMAC in this DPN and optionally in other DPNs.
646      *
647      * @param elanInfo
648      *            the elan info
649      * @param interfaceInfo
650      *            the interface info
651      * @param macTimeout
652      *            the mac timeout
653      * @param macAddress
654      *            the mac address
655      * @param configureRemoteFlows
656      *            true if remote dmac flows should be configured as well
657      * @param writeFlowGroupTx
658      *            the flow group tx
659      * @throws ElanException in case of issues creating the flow objects
660      */
661     public void setupMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
662                               long macTimeout, String macAddress, boolean configureRemoteFlows,
663                               WriteTransaction writeFlowGroupTx) throws ElanException {
664         synchronized (getElanMacDPNKey(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) {
665             setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, mdsalManager,
666                 writeFlowGroupTx);
667             setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, configureRemoteFlows, mdsalManager,
668                 broker, writeFlowGroupTx);
669         }
670     }
671
672     public void setupDMacFlowOnRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId,
673                                          String macAddress, WriteTransaction writeFlowTx) throws ElanException {
674         String elanInstanceName = elanInfo.getElanInstanceName();
675         setupRemoteDmacFlow(dstDpId, interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag(), elanInfo.getElanTag(),
676                 macAddress, elanInstanceName, writeFlowTx, interfaceInfo.getInterfaceName(), elanInfo);
677         LOG.info("Remote Dmac flow entry created for elan Name:{}, logical port Name:{} and"
678                 + " mac address {} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(),
679                 macAddress, dstDpId);
680     }
681
682     /**
683      * Inserts a Flow in SMAC table to state that the MAC has already been
684      * learnt.
685      */
686     private void setupKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout,
687             String macAddress, IMdsalApiManager mdsalApiManager, WriteTransaction writeFlowGroupTx) {
688         FlowEntity flowEntity = buildKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress);
689         mdsalApiManager.addFlowToTx(flowEntity, writeFlowGroupTx);
690         LOG.debug("Known Smac flow entry created for elan Name:{}, logical Interface port:{} and mac address:{}",
691                 elanInfo.getElanInstanceName(), elanInfo.getDescription(), macAddress);
692     }
693
694     public FlowEntity buildKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout,
695             String macAddress) {
696         int lportTag = interfaceInfo.getInterfaceTag();
697         // Matching metadata and eth_src fields
698         List<MatchInfo> mkMatches = new ArrayList<>();
699         mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanInfo.getElanTag(), lportTag),
700                 ElanHelper.getElanMetadataMask()));
701         mkMatches.add(new MatchEthernetSource(new MacAddress(macAddress)));
702         List<InstructionInfo> mkInstructions = new ArrayList<>();
703         mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
704         BigInteger dpId = interfaceInfo.getDpId();
705         long elanTag = getElanTag(broker, elanInfo, interfaceInfo);
706         return new FlowEntityBuilder()
707             .setDpnId(dpId)
708             .setTableId(NwConstants.ELAN_SMAC_TABLE)
709             .setFlowId(getKnownDynamicmacFlowRef(NwConstants.ELAN_SMAC_TABLE, dpId, lportTag, macAddress, elanTag))
710             .setPriority(20)
711             .setFlowName(elanInfo.getDescription())
712             .setIdleTimeOut((int) macTimeout)
713             .setHardTimeOut(0)
714             .setCookie(ElanConstants.COOKIE_ELAN_KNOWN_SMAC.add(BigInteger.valueOf(elanTag)))
715             .setMatchInfoList(mkMatches)
716             .setInstructionInfoList(mkInstructions)
717             .setStrictFlag(true)
718             // If Mac timeout is 0, the flow won't be deleted automatically, so no need to get notified
719             .setSendFlowRemFlag(macTimeout != 0)
720             .build();
721     }
722
723     private static Long getElanTag(DataBroker broker, ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
724         EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, interfaceInfo.getInterfaceName());
725         if (etreeInterface == null || etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
726             return elanInfo.getElanTag();
727         } else { // Leaf
728             EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
729             if (etreeInstance == null) {
730                 LOG.warn("EtreeInterface {} is connected to a non-Etree network: {}",
731                          interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName());
732                 return elanInfo.getElanTag();
733             } else {
734                 return etreeInstance.getEtreeLeafTagVal().getValue();
735             }
736         }
737     }
738
739     /**
740      * Installs a Flow in INTERNAL_TUNNEL_TABLE of the affected DPN that sends
741      * the packet through the specified interface if the tunnel_id matches the
742      * interface's lportTag.
743      *
744      * @param interfaceInfo
745      *            the interface info
746      * @param mdsalApiManager
747      *            the mdsal API manager
748      * @param writeFlowGroupTx
749      *            the writeFLowGroup tx
750      */
751     public void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager,
752                                    WriteTransaction writeFlowGroupTx) {
753         BigInteger dpId = interfaceInfo.getDpId();
754         int lportTag = interfaceInfo.getInterfaceTag();
755         Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
756                 getIntTunnelTableFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, lportTag), 5,
757                 String.format("%s:%d", "ITM Flow Entry ", lportTag), 0, 0,
758                 ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(lportTag)),
759                 getTunnelIdMatchForFilterEqualsLPortTag(lportTag),
760                 getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
761         mdsalApiManager.addFlowToTx(dpId, flow, writeFlowGroupTx);
762         LOG.debug("Terminating service table flow entry created on dpn:{} for logical Interface port:{}", dpId,
763                 interfaceInfo.getPortName());
764     }
765
766     /**
767      * Constructs the FlowName for flows installed in the Internal Tunnel Table,
768      * consisting in tableId + elanTag.
769      *
770      * @param tableId
771      *            table Id
772      * @param elanTag
773      *            elan Tag
774      * @return the Internal tunnel
775      */
776     public static String getIntTunnelTableFlowRef(short tableId, int elanTag) {
777         return new StringBuffer().append(tableId).append(elanTag).toString();
778     }
779
780     /**
781      * Constructs the Matches that checks that the tunnel_id field contains a
782      * specific lportTag.
783      *
784      * @param lportTag
785      *            lportTag that must be checked against the tunnel_id field
786      * @return the list of match Info
787      */
788     public static List<MatchInfo> getTunnelIdMatchForFilterEqualsLPortTag(int lportTag) {
789         List<MatchInfo> mkMatches = new ArrayList<>();
790         // Matching metadata
791         mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
792         return mkMatches;
793     }
794
795     /**
796      * Constructs the Instructions that take the packet over a given interface.
797      *
798      * @param ifName
799      *            Name of the interface where the packet must be sent over. It
800      *            can be a local interface or a tunnel interface (internal or
801      *            external)
802      * @return the Instruction
803      */
804     public List<Instruction> getInstructionsInPortForOutGroup(String ifName) {
805         List<Instruction> mkInstructions = new ArrayList<>();
806         List<Action> actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null);
807
808         mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
809         return mkInstructions;
810     }
811
812     /**
813      * Returns the list of Actions to be taken when sending the packet through
814      * an Elan interface. Note that this interface can refer to an ElanInterface
815      * where the Elan VM is attached to a DPN or an ITM tunnel interface where
816      * Elan traffic can be sent through. In this latter case, the tunnelKey is
817      * mandatory and it can hold serviceId for internal tunnels or the VNI for
818      * external tunnels.
819      *
820      * @param ifName
821      *            the if name
822      * @param tunnelKey
823      *            the tunnel key
824      * @return the egress actions for interface
825      */
826     @SuppressWarnings("checkstyle:IllegalCatch")
827     public List<Action> getEgressActionsForInterface(String ifName, Long tunnelKey) {
828         List<Action> listAction = new ArrayList<>();
829         try {
830             GetEgressActionsForInterfaceInput getEgressActionInput = new GetEgressActionsForInterfaceInputBuilder()
831                     .setIntfName(ifName).setTunnelKey(tunnelKey).build();
832             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result = interfaceManagerRpcService
833                     .getEgressActionsForInterface(getEgressActionInput);
834             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
835             if (!rpcResult.isSuccessful()) {
836                 LOG.debug("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName,
837                         rpcResult.getErrors());
838             } else {
839                 List<Action> actions = rpcResult.getResult().getAction();
840                 listAction = actions;
841             }
842         } catch (Exception e) {
843             LOG.warn("Exception when egress actions for interface {}", ifName, e);
844         }
845         return listAction;
846     }
847
848     private void setupOrigDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
849                                     boolean configureRemoteFlows, IMdsalApiManager mdsalApiManager,
850                                     DataBroker broker, WriteTransaction writeFlowGroupTx)
851                                     throws ElanException {
852         BigInteger dpId = interfaceInfo.getDpId();
853         String ifName = interfaceInfo.getInterfaceName();
854         long ifTag = interfaceInfo.getInterfaceTag();
855         String elanInstanceName = elanInfo.getElanInstanceName();
856
857         Long elanTag = elanInfo.getElanTag();
858
859         setupLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo, mdsalApiManager, ifTag,
860                 writeFlowGroupTx);
861         LOG.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} mand mac address:{} "
862                                     + "on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, dpId);
863
864         if (!configureRemoteFlows) {
865             return;
866         }
867
868         List<DpnInterfaces> elanDpns = getInvolvedDpnsInElan(elanInstanceName);
869         for (DpnInterfaces elanDpn : elanDpns) {
870
871             if (elanDpn.getDpId().equals(dpId)) {
872                 continue;
873             }
874
875             // Check for the Remote DPN present in Inventory Manager
876             if (!isDpnPresent(elanDpn.getDpId())) {
877                 continue;
878             }
879
880             // For remote DPNs a flow is needed to indicate that packets of this ELAN going to this MAC need to be
881             // forwarded through the appropriate ITM tunnel
882             setupRemoteDmacFlow(elanDpn.getDpId(), // srcDpn (the remote DPN in this case)
883                     dpId, // dstDpn (the local DPN)
884                     interfaceInfo.getInterfaceTag(), // lportTag of the local interface
885                     elanTag,  // identifier of the Elan
886                     macAddress, // MAC to be programmed in remote DPN
887                     elanInstanceName, writeFlowGroupTx, ifName, elanInfo
888             );
889             LOG.debug("Remote Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on"
890                         + " dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, elanDpn.getDpId());
891         }
892
893         // TODO: Make sure that the same is performed against the ElanDevices.
894     }
895
896     @Nonnull
897     public List<DpnInterfaces> getInvolvedDpnsInElan(String elanName) {
898         return elanInstanceManager.getElanDPNByName(elanName);
899     }
900
901     private void setupLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress,
902             ElanInstance elanInfo, IMdsalApiManager mdsalApiManager, long ifTag, WriteTransaction writeFlowGroupTx) {
903         Flow flowEntity = buildLocalDmacFlowEntry(elanTag, dpId, ifName, macAddress, elanInfo, ifTag);
904         mdsalApiManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
905         installEtreeLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo,
906                 mdsalApiManager, ifTag, writeFlowGroupTx);
907     }
908
909     private void installEtreeLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress,
910             ElanInstance elanInfo, IMdsalApiManager mdsalApiManager, long ifTag, WriteTransaction writeFlowGroupTx) {
911         EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, ifName);
912         if (etreeInterface != null) {
913             if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
914                 EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
915                 if (etreeTagName == null) {
916                     LOG.warn("Interface {} seems like it belongs to Etree but etreeTagName from elanTag {} is null",
917                              ifName, elanTag);
918                 } else {
919                     Flow flowEntity = buildLocalDmacFlowEntry(etreeTagName.getEtreeLeafTag().getValue(), dpId, ifName,
920                             macAddress, elanInfo, ifTag);
921                     mdsalApiManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
922                 }
923             }
924         }
925     }
926
927     public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, long lporTag, String macAddress,
928             long elanTag) {
929         return new StringBuffer().append(tableId).append(elanTag).append(dpId).append(lporTag).append(macAddress)
930                 .toString();
931     }
932
933     public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, BigInteger remoteDpId,
934             String macAddress, long elanTag) {
935         return new StringBuffer().append(tableId).append(elanTag).append(dpId).append(remoteDpId).append(macAddress)
936                 .toString();
937     }
938
939     public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, String macAddress, long elanTag) {
940         return new StringBuffer().append(tableId).append(elanTag).append(dpId).append(macAddress).toString();
941     }
942
943     public static String getKnownDynamicmacFlowRef(short elanDmacTable, BigInteger dpId, String extDeviceNodeId,
944             String dstMacAddress, long elanTag, boolean shFlag) {
945         return new StringBuffer().append(elanDmacTable).append(elanTag).append(dpId).append(extDeviceNodeId)
946                 .append(dstMacAddress).append(shFlag).toString();
947     }
948
949     /**
950      * Builds the flow to be programmed in the DMAC table of the local DPN (that
951      * is, where the MAC is attached to). This flow consists in:
952      *
953      * <p>Match: + elanTag in metadata + packet goes to a MAC locally attached
954      * Actions: + optionally, pop-vlan + set-vlan-id + output to ifName's
955      * portNumber
956      *
957      * @param elanTag
958      *            the elan tag
959      * @param dpId
960      *            the dp id
961      * @param ifName
962      *            the if name
963      * @param macAddress
964      *            the mac address
965      * @param elanInfo
966      *            the elan info
967      * @param ifTag
968      *            the if tag
969      * @return the flow
970      */
971     public Flow buildLocalDmacFlowEntry(long elanTag, BigInteger dpId, String ifName, String macAddress,
972             ElanInstance elanInfo, long ifTag) {
973
974         List<MatchInfo> mkMatches = new ArrayList<>();
975         mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
976         mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress)));
977
978         List<Instruction> mkInstructions = new ArrayList<>();
979         List<Action> actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null);
980         mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
981         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
982                 getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, ifTag, macAddress, elanTag), 20,
983                 elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(
984                         BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
985
986         return flow;
987     }
988
989     public void setupRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, String
990             macAddress, String displayName, WriteTransaction writeFlowGroupTx, String interfaceName, ElanInstance
991             elanInstance) throws ElanException {
992         if (interfaceManager.isExternalInterface(interfaceName)) {
993             LOG.debug("Ignoring install remote DMAC {} flow on provider interface {} elan {}",
994                     macAddress, interfaceName, elanInstance.getElanInstanceName());
995             return;
996         }
997         Flow flowEntity;
998         // if openstack-vni-semantics are enforced, segmentation ID is passed as network VNI for VxLAN based provider
999         // networks, 0 otherwise
1000         long lportTagOrVni = !isOpenstackVniSemanticsEnforced() ? lportTag : isVxlan(elanInstance)
1001                 ? elanInstance.getSegmentationId() : 0;
1002         flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName,
1003                 elanInstance);
1004         mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx);
1005         setupEtreeRemoteDmacFlow(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName, interfaceName,
1006                 writeFlowGroupTx, elanInstance);
1007     }
1008
1009     private void setupEtreeRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag,
1010                                           String macAddress, String displayName, String interfaceName,
1011                                           WriteTransaction writeFlowGroupTx, ElanInstance elanInstance)
1012                                           throws ElanException {
1013         Flow flowEntity;
1014         EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(broker, interfaceName);
1015         if (etreeInterface != null) {
1016             if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1017                 EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1018                 if (etreeTagName == null) {
1019                     LOG.warn("Interface " + interfaceName
1020                             + " seems like it belongs to Etree but etreeTagName from elanTag " + elanTag + " is null.");
1021                 } else {
1022                     flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni,
1023                             etreeTagName.getEtreeLeafTag().getValue(), macAddress, displayName, elanInstance);
1024                     mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx);
1025                 }
1026             }
1027         }
1028     }
1029
1030     /**
1031      * Builds a Flow to be programmed in a remote DPN's DMAC table. This flow
1032      * consists in: Match: + elanTag in packet's metadata + packet going to a
1033      * MAC known to be located in another DPN Actions: + set_tunnel_id
1034      * + output ITM internal tunnel interface with the other DPN
1035      *
1036      * @param srcDpId
1037      *            the src Dpn Id
1038      * @param destDpId
1039      *            dest Dp Id
1040      * @param lportTagOrVni
1041      *            lportTag or network VNI
1042      * @param elanTag
1043      *            elan Tag
1044      * @param macAddress
1045      *            macAddress
1046      * @param displayName
1047      *            display Name
1048      * @return the flow remote Dmac
1049      * @throws ElanException in case of issues creating the flow objects
1050      */
1051     @SuppressWarnings("checkstyle:IllegalCatch")
1052     public Flow buildRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag,
1053             String macAddress, String displayName, ElanInstance elanInstance) throws ElanException {
1054         List<MatchInfo> mkMatches = new ArrayList<>();
1055         mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
1056         mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress)));
1057
1058         List<Instruction> mkInstructions = new ArrayList<>();
1059
1060         // List of Action for the provided Source and Destination DPIDs
1061         try {
1062             List<Action> actions = null;
1063             if (isVlan(elanInstance) || isFlat(elanInstance)) {
1064                 String interfaceName = getExternalElanInterface(elanInstance.getElanInstanceName(), srcDpId);
1065                 if (null == interfaceName) {
1066                     LOG.info("buildRemoteDmacFlowEntry: Could not find interfaceName for {} {}", srcDpId,
1067                         elanInstance);
1068                 }
1069                 actions = getEgressActionsForInterface(interfaceName, null);
1070             } else if (isVxlan(elanInstance)) {
1071                 actions = elanItmUtils.getInternalTunnelItmEgressAction(srcDpId, destDpId, lportTagOrVni);
1072             }
1073             mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
1074         } catch (Exception e) {
1075             LOG.error("Could not get egress actions to add to flow for srcDpId=" + srcDpId + ", destDpId=" + destDpId
1076                     + ", lportTag/VNI=" + lportTagOrVni, e);
1077         }
1078
1079         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
1080                 getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, srcDpId, destDpId, macAddress, elanTag),
1081                 20, /* prio */
1082                 displayName, 0, /* idleTimeout */
1083                 0, /* hardTimeout */
1084                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
1085
1086         return flow;
1087
1088     }
1089
1090     public void deleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, MacEntry macEntry,
1091             WriteTransaction deleteFlowGroupTx) {
1092         if (elanInfo == null || interfaceInfo == null) {
1093             return;
1094         }
1095         String macAddress = macEntry.getMacAddress().getValue();
1096         synchronized (getElanMacDPNKey(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) {
1097             deleteMacFlows(elanInfo, interfaceInfo, macAddress, /* alsoDeleteSMAC */ true, deleteFlowGroupTx);
1098         }
1099     }
1100
1101     public void deleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
1102             boolean deleteSmac, WriteTransaction deleteFlowGroupTx) {
1103         String elanInstanceName = elanInfo.getElanInstanceName();
1104         List<DpnInterfaces> remoteFEs = getInvolvedDpnsInElan(elanInstanceName);
1105         BigInteger srcdpId = interfaceInfo.getDpId();
1106         boolean isFlowsRemovedInSrcDpn = false;
1107         for (DpnInterfaces dpnInterface : remoteFEs) {
1108             Long elanTag = elanInfo.getElanTag();
1109             BigInteger dstDpId = dpnInterface.getDpId();
1110             if (executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
1111                     elanTag, dstDpId, deleteFlowGroupTx)) {
1112                 isFlowsRemovedInSrcDpn = true;
1113             }
1114             executeEtreeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
1115                     elanTag, dstDpId, deleteFlowGroupTx);
1116         }
1117         if (!isFlowsRemovedInSrcDpn) {
1118             deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, deleteFlowGroupTx);
1119         }
1120     }
1121
1122     private void executeEtreeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
1123             boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId,
1124             WriteTransaction deleteFlowGroupTx) {
1125         EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
1126         if (etreeLeafTag != null) {
1127             executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
1128                     etreeLeafTag.getEtreeLeafTag().getValue(), dstDpId, deleteFlowGroupTx);
1129         }
1130     }
1131
1132     private boolean executeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
1133             boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId,
1134             WriteTransaction deleteFlowGroupTx) {
1135         boolean isFlowsRemovedInSrcDpn = false;
1136         if (dstDpId.equals(srcdpId)) {
1137             isFlowsRemovedInSrcDpn = true;
1138             deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, deleteFlowGroupTx);
1139         } else if (isDpnPresent(dstDpId)) {
1140             mdsalManager
1141                     .removeFlowToTx(dstDpId,
1142                             MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, getKnownDynamicmacFlowRef(
1143                                     NwConstants.ELAN_DMAC_TABLE, dstDpId, srcdpId, macAddress, elanTag)),
1144                             deleteFlowGroupTx);
1145             LOG.debug("Dmac flow entry deleted for elan:{}, logical interface port:{} and mac address:{} on dpn:{}",
1146                     elanInstanceName, interfaceInfo.getPortName(), macAddress, dstDpId);
1147         }
1148         return isFlowsRemovedInSrcDpn;
1149     }
1150
1151     private void deleteSmacAndDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
1152             boolean deleteSmac, WriteTransaction deleteFlowGroupTx) {
1153         String elanInstanceName = elanInfo.getElanInstanceName();
1154         long ifTag = interfaceInfo.getInterfaceTag();
1155         BigInteger srcdpId = interfaceInfo.getDpId();
1156         Long elanTag = elanInfo.getElanTag();
1157         if (deleteSmac) {
1158             mdsalManager
1159                     .removeFlowToTx(srcdpId,
1160                             MDSALUtil.buildFlow(NwConstants.ELAN_SMAC_TABLE, getKnownDynamicmacFlowRef(
1161                                     NwConstants.ELAN_SMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)),
1162                             deleteFlowGroupTx);
1163         }
1164         mdsalManager.removeFlowToTx(srcdpId,
1165                 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
1166                         getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)),
1167                 deleteFlowGroupTx);
1168         LOG.debug("All the required flows deleted for elan:{}, logical Interface port:{} and MAC address:{} on dpn:{}",
1169                 elanInstanceName, interfaceInfo.getPortName(), macAddress, srcdpId);
1170     }
1171
1172     /**
1173      * Updates the Elan information in the Operational DS. It also updates the
1174      * ElanInstance in the Config DS by setting the adquired elanTag.
1175      *
1176      * @param broker
1177      *            the broker
1178      * @param idManager
1179      *            the id manager
1180      * @param elanInstanceAdded
1181      *            the elan instance added
1182      * @param elanInterfaces
1183      *            the elan interfaces
1184      * @param tx
1185      *            transaction
1186      */
1187     public static void updateOperationalDataStore(DataBroker broker, IdManagerService idManager,
1188             ElanInstance elanInstanceAdded, List<String> elanInterfaces, WriteTransaction tx) {
1189         String elanInstanceName = elanInstanceAdded.getElanInstanceName();
1190         Long elanTag = elanInstanceAdded.getElanTag();
1191         if (elanTag == null || elanTag == 0L) {
1192             elanTag = retrieveNewElanTag(idManager, elanInstanceName);
1193         }
1194         Elan elanInfo = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(elanInterfaces)
1195                 .setKey(new ElanKey(elanInstanceName)).build();
1196
1197         // Add the ElanState in the elan-state operational data-store
1198         tx.put(LogicalDatastoreType.OPERATIONAL, getElanInstanceOperationalDataPath(elanInstanceName),
1199                 elanInfo, WriteTransaction.CREATE_MISSING_PARENTS);
1200
1201         // Add the ElanMacTable in the elan-mac-table operational data-store
1202         MacTable elanMacTable = new MacTableBuilder().setKey(new MacTableKey(elanInstanceName)).build();
1203         tx.put(LogicalDatastoreType.OPERATIONAL, getElanMacTableOperationalDataPath(elanInstanceName),
1204                 elanMacTable, WriteTransaction.CREATE_MISSING_PARENTS);
1205
1206         ElanTagNameBuilder elanTagNameBuilder = new ElanTagNameBuilder().setElanTag(elanTag)
1207                 .setKey(new ElanTagNameKey(elanTag)).setName(elanInstanceName);
1208         long etreeLeafTag = -1;
1209         if (isEtreeInstance(elanInstanceAdded)) {
1210             etreeLeafTag = retrieveNewElanTag(idManager,elanInstanceName + ElanConstants
1211                     .LEAVES_POSTFIX);
1212             EtreeLeafTagName etreeLeafTagName = new EtreeLeafTagNameBuilder()
1213                     .setEtreeLeafTag(new EtreeLeafTag(etreeLeafTag)).build();
1214             elanTagNameBuilder.addAugmentation(EtreeLeafTagName.class, etreeLeafTagName);
1215             addTheLeafTagAsElanTag(broker, elanInstanceName, etreeLeafTag, tx);
1216         }
1217         ElanTagName elanTagName = elanTagNameBuilder.build();
1218
1219         // Add the ElanTag to ElanName in the elan-tag-name Operational
1220         // data-store
1221         tx.put(LogicalDatastoreType.OPERATIONAL,
1222                 getElanInfoEntriesOperationalDataPath(elanTag), elanTagName);
1223
1224         // Updates the ElanInstance Config DS by setting the just acquired
1225         // elanTag
1226         ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
1227                 .setDescription(elanInstanceAdded.getDescription())
1228                 .setMacTimeout(elanInstanceAdded.getMacTimeout() == null
1229                         ? Long.valueOf(ElanConstants.DEFAULT_MAC_TIME_OUT) : elanInstanceAdded.getMacTimeout())
1230                 .setKey(elanInstanceAdded.getKey()).setElanTag(elanTag);
1231         if (isEtreeInstance(elanInstanceAdded)) {
1232             EtreeInstance etreeInstance = new EtreeInstanceBuilder().setEtreeLeafTagVal(new EtreeLeafTag(etreeLeafTag))
1233                     .build();
1234             elanInstanceBuilder.addAugmentation(EtreeInstance.class, etreeInstance);
1235         }
1236         ElanInstance elanInstanceWithTag = elanInstanceBuilder.build();
1237         tx.merge(LogicalDatastoreType.CONFIGURATION, ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName),
1238                 elanInstanceWithTag, true);
1239     }
1240
1241     private static void addTheLeafTagAsElanTag(DataBroker broker, String elanInstanceName, long etreeLeafTag,
1242             WriteTransaction tx) {
1243         ElanTagName etreeTagAsElanTag = new ElanTagNameBuilder().setElanTag(etreeLeafTag)
1244                 .setKey(new ElanTagNameKey(etreeLeafTag)).setName(elanInstanceName).build();
1245         tx.put(LogicalDatastoreType.OPERATIONAL,
1246                 getElanInfoEntriesOperationalDataPath(etreeLeafTag), etreeTagAsElanTag);
1247     }
1248
1249     private static boolean isEtreeInstance(ElanInstance elanInstanceAdded) {
1250         return elanInstanceAdded.getAugmentation(EtreeInstance.class) != null;
1251     }
1252
1253     public boolean isDpnPresent(BigInteger dpnId) {
1254         String dpn = String.format("%s:%s", "openflow", dpnId);
1255         NodeId nodeId = new NodeId(dpn);
1256
1257         InstanceIdentifier<Node> node = InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(nodeId))
1258                 .build();
1259         return read(broker, LogicalDatastoreType.CONFIGURATION, node).isPresent();
1260     }
1261
1262     public static ServicesInfo getServiceInfo(String elanInstanceName, String interfaceName) {
1263         return InterfaceServiceUtil.buildServiceInfo(elanInstanceName + "." + interfaceName,
1264                 ElanConstants.ELAN_SERVICE_PRIORITY);
1265     }
1266
1267     public static String getElanServiceName(String elanName, String interfaceName) {
1268         return "elan." + elanName + interfaceName;
1269     }
1270
1271     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
1272             BigInteger cookie, List<Instruction> instructions) {
1273         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
1274                 .setInstruction(instructions);
1275         return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
1276                 .setServicePriority(servicePriority).setServiceType(ServiceTypeFlowBased.class)
1277                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
1278     }
1279
1280     public static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short serviceIndex) {
1281         return InstanceIdentifier.builder(ServiceBindings.class)
1282                 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
1283                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
1284     }
1285
1286     public static List<MatchInfo> getTunnelMatchesForServiceId(int elanTag) {
1287         List<MatchInfo> mkMatches = new ArrayList<>();
1288         // Matching metadata
1289         mkMatches.add(new MatchTunnelId(BigInteger.valueOf(elanTag)));
1290
1291         return mkMatches;
1292     }
1293
1294     public void removeTerminatingServiceAction(BigInteger destDpId, int serviceId) {
1295         RemoveTerminatingServiceActionsInput input = new RemoveTerminatingServiceActionsInputBuilder()
1296                 .setDpnId(destDpId).setServiceId(serviceId).build();
1297         Future<RpcResult<Void>> futureObject = itmRpcService.removeTerminatingServiceActions(input);
1298         try {
1299             RpcResult<Void> result = futureObject.get();
1300             if (result.isSuccessful()) {
1301                 LOG.debug("Successfully completed removeTerminatingServiceActions for ELAN with serviceId {} on "
1302                                 + "dpn {}", serviceId, destDpId);
1303             } else {
1304                 LOG.debug("Failure in removeTerminatingServiceAction RPC call for ELAN with serviceId {} on "
1305                         + "dpn {}", serviceId, destDpId);
1306             }
1307         } catch (InterruptedException | ExecutionException e) {
1308             LOG.error("Error in RPC call removeTerminatingServiceActions for ELAN with serviceId {} on "
1309                     + "dpn {}: {}", serviceId, destDpId, e);
1310         }
1311     }
1312
1313     /**
1314      * Gets the external tunnel.
1315      *
1316      * @param sourceDevice
1317      *            the source device
1318      * @param destinationDevice
1319      *            the destination device
1320      * @param datastoreType
1321      *            the datastore type
1322      * @return the external tunnel
1323      */
1324     public ExternalTunnel getExternalTunnel(String sourceDevice, String destinationDevice,
1325             LogicalDatastoreType datastoreType) {
1326         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
1327         InstanceIdentifier<ExternalTunnel> iid = InstanceIdentifier.builder(ExternalTunnelList.class)
1328                 .child(ExternalTunnel.class, new ExternalTunnelKey(destinationDevice, sourceDevice, tunType)).build();
1329         return read(broker, datastoreType, iid).orNull();
1330     }
1331
1332     /**
1333      * Gets the external tunnel.
1334      *
1335      * @param interfaceName
1336      *            the interface name
1337      * @param datastoreType
1338      *            the datastore type
1339      * @return the external tunnel
1340      */
1341     public ExternalTunnel getExternalTunnel(String interfaceName, LogicalDatastoreType datastoreType) {
1342         ExternalTunnel externalTunnel = null;
1343         List<ExternalTunnel> externalTunnels = getAllExternalTunnels(datastoreType);
1344         for (ExternalTunnel tunnel : externalTunnels) {
1345             if (StringUtils.equalsIgnoreCase(interfaceName, tunnel.getTunnelInterfaceName())) {
1346                 externalTunnel = tunnel;
1347                 break;
1348             }
1349         }
1350         return externalTunnel;
1351     }
1352
1353     /**
1354      * Gets the all external tunnels.
1355      *
1356      * @param datastoreType
1357      *            the data store type
1358      * @return the all external tunnels
1359      */
1360     public List<ExternalTunnel> getAllExternalTunnels(LogicalDatastoreType datastoreType) {
1361         InstanceIdentifier<ExternalTunnelList> iid = InstanceIdentifier.builder(ExternalTunnelList.class).build();
1362         return read(broker, datastoreType, iid).toJavaUtil().map(ExternalTunnelList::getExternalTunnel).orElse(
1363                 Collections.emptyList());
1364     }
1365
1366     public static List<MatchInfo> buildMatchesForElanTagShFlagAndDstMac(long elanTag, boolean shFlag, String macAddr) {
1367         List<MatchInfo> mkMatches = new ArrayList<>();
1368         mkMatches.add(
1369                 new MatchMetadata(getElanMetadataLabel(elanTag, shFlag), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG));
1370         mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddr)));
1371         return mkMatches;
1372     }
1373
1374     /**
1375      * Checks if is interface operational.
1376      *
1377      * @param interfaceName
1378      *            the interface name
1379      * @param dataBroker
1380      *            the data broker
1381      * @return true, if is interface operational
1382      */
1383     public static boolean isInterfaceOperational(String interfaceName, DataBroker dataBroker) {
1384         if (StringUtils.isBlank(interfaceName)) {
1385             return false;
1386         }
1387         Interface ifState = getInterfaceStateFromOperDS(interfaceName, dataBroker);
1388         if (ifState == null) {
1389             return false;
1390         }
1391         return ifState.getOperStatus() == OperStatus.Up && ifState.getAdminStatus() == AdminStatus.Up;
1392     }
1393
1394     /**
1395      * Gets the interface state from operational ds.
1396      *
1397      * @param interfaceName
1398      *            the interface name
1399      * @param dataBroker
1400      *            the data broker
1401      * @return the interface state from oper ds
1402      */
1403     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
1404         .ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
1405             String interfaceName, DataBroker dataBroker) {
1406         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
1407             .ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId = createInterfaceStateInstanceIdentifier(
1408                 interfaceName);
1409         return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId).orNull();
1410     }
1411
1412     /**
1413      * Creates the interface state instance identifier.
1414      *
1415      * @param interfaceName
1416      *            the interface name
1417      * @return the instance identifier
1418      */
1419     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
1420         .ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
1421             String interfaceName) {
1422         InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
1423             .ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder = InstanceIdentifier
1424                 .builder(InterfacesState.class)
1425                 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
1426                         .ietf.interfaces.rev140508.interfaces.state.Interface.class,
1427                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
1428                             .ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
1429                                 interfaceName));
1430         return idBuilder.build();
1431     }
1432
1433     public static CheckedFuture<Void, TransactionCommitFailedException> waitForTransactionToComplete(
1434             WriteTransaction tx) {
1435         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
1436         try {
1437             futures.get();
1438         } catch (InterruptedException | ExecutionException e) {
1439             LOG.error("Error writing to datastore {}", e);
1440         }
1441         return futures;
1442     }
1443
1444     public static boolean isVxlanNetwork(DataBroker broker, String elanInstanceName) {
1445         ElanInstance elanInstance = getElanInstanceByName(broker, elanInstanceName);
1446         return elanInstance != null && isVxlan(elanInstance);
1447     }
1448
1449     public static boolean isVxlan(ElanInstance elanInstance) {
1450         return elanInstance != null && elanInstance.getSegmentType() != null
1451                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
1452                 && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0;
1453     }
1454
1455     private static boolean isVxlanSegment(ElanInstance elanInstance) {
1456         if (elanInstance != null) {
1457             List<ElanSegments> elanSegments = elanInstance.getElanSegments();
1458             if (elanSegments != null) {
1459                 for (ElanSegments segment : elanSegments) {
1460                     if (segment != null && segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
1461                             && segment.getSegmentationId() != null
1462                             && segment.getSegmentationId().longValue() != 0) {
1463                         return true;
1464                     }
1465                 }
1466             }
1467         }
1468         return false;
1469     }
1470
1471     public static boolean isVxlanNetworkOrVxlanSegment(ElanInstance elanInstance) {
1472         return isVxlan(elanInstance) || isVxlanSegment(elanInstance);
1473     }
1474
1475     public static Long getVxlanSegmentationId(ElanInstance elanInstance) {
1476         Long segmentationId = 0L;
1477         if (elanInstance == null) {
1478             return segmentationId;
1479         }
1480
1481         if (elanInstance.getSegmentType() != null
1482                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
1483                 && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().longValue() != 0) {
1484             segmentationId = elanInstance.getSegmentationId();
1485         } else {
1486             for (ElanSegments segment: elanInstance.getElanSegments()) {
1487                 if (segment != null && segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
1488                     && segment.getSegmentationId() != null
1489                     && segment.getSegmentationId().longValue() != 0) {
1490                     segmentationId = segment.getSegmentationId();
1491                 }
1492             }
1493         }
1494         return segmentationId;
1495     }
1496
1497     public static boolean isVlan(ElanInstance elanInstance) {
1498         return elanInstance != null && elanInstance.getSegmentType() != null
1499                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVlan.class)
1500                 && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0;
1501     }
1502
1503     public static boolean isFlat(ElanInstance elanInstance) {
1504         return elanInstance != null && elanInstance.getSegmentType() != null
1505                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeFlat.class);
1506     }
1507
1508     public void addDmacRedirectToDispatcherFlows(Long elanTag, String displayName,
1509             String macAddress, List<BigInteger> dpnIds) {
1510         for (BigInteger dpId : dpnIds) {
1511             WriteTransaction writeTx = broker.newWriteOnlyTransaction();
1512             mdsalManager.addFlowToTx(buildDmacRedirectToDispatcherFlow(dpId, macAddress, displayName, elanTag),
1513                     writeTx);
1514             writeTx.submit();
1515         }
1516     }
1517
1518     public void removeDmacRedirectToDispatcherFlows(Long elanTag, String macAddress, List<BigInteger> dpnIds) {
1519         for (BigInteger dpId : dpnIds) {
1520             String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, macAddress, elanTag);
1521             mdsalManager.removeFlow(dpId, MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, flowId));
1522         }
1523     }
1524
1525     public static FlowEntity buildDmacRedirectToDispatcherFlow(BigInteger dpId, String dstMacAddress,
1526             String displayName, long elanTag) {
1527         List<MatchInfo> matches = new ArrayList<>();
1528         matches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
1529         matches.add(new MatchEthernetDestination(new MacAddress(dstMacAddress)));
1530         List<InstructionInfo> instructions = new ArrayList<>();
1531         List<ActionInfo> actions = new ArrayList<>();
1532         actions.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
1533
1534         instructions.add(new InstructionApplyActions(actions));
1535         String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, dstMacAddress, elanTag);
1536         FlowEntity flow  = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_DMAC_TABLE, flowId, 20, displayName, 0, 0,
1537                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
1538                 matches, instructions);
1539         return flow;
1540     }
1541
1542     /**
1543      * Add Mac Address to ElanInterfaceForwardingEntries and ElanForwardingTables
1544      * Install SMAC and DMAC flows.
1545      */
1546     public void addMacEntryToDsAndSetupFlows(IInterfaceManager interfaceManager, String interfaceName,
1547             String macAddress, String elanName, WriteTransaction interfaceTx, WriteTransaction flowTx, int macTimeOut)
1548             throws ElanException {
1549         LOG.trace("Adding mac address {} and interface name {} to ElanInterfaceForwardingEntries and "
1550             + "ElanForwardingTables DS", macAddress, interfaceName);
1551         BigInteger timeStamp = new BigInteger(String.valueOf(System.currentTimeMillis()));
1552         PhysAddress physAddress = new PhysAddress(macAddress);
1553         MacEntry macEntry = new MacEntryBuilder().setInterface(interfaceName).setMacAddress(physAddress)
1554                 .setKey(new MacEntryKey(physAddress)).setControllerLearnedForwardingEntryTimestamp(timeStamp)
1555                 .setIsStaticAddress(false).build();
1556         InstanceIdentifier<MacEntry> macEntryId = ElanUtils
1557                 .getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
1558         interfaceTx.put(LogicalDatastoreType.OPERATIONAL, macEntryId, macEntry);
1559         InstanceIdentifier<MacEntry> elanMacEntryId = ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress);
1560         interfaceTx.put(LogicalDatastoreType.OPERATIONAL, elanMacEntryId, macEntry);
1561         ElanInstance elanInstance = ElanUtils.getElanInstanceByName(broker, elanName);
1562         setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), macTimeOut, macAddress, true,
1563                 flowTx);
1564     }
1565
1566     /**
1567      * Remove Mac Address from ElanInterfaceForwardingEntries and ElanForwardingTables
1568      * Remove SMAC and DMAC flows.
1569      */
1570     public void deleteMacEntryFromDsAndRemoveFlows(IInterfaceManager interfaceManager, String interfaceName,
1571             String macAddress, String elanName, WriteTransaction interfaceTx, WriteTransaction flowTx) {
1572         LOG.trace("Deleting mac address {} and interface name {} from ElanInterfaceForwardingEntries "
1573                 + "and ElanForwardingTables DS", macAddress, interfaceName);
1574         PhysAddress physAddress = new PhysAddress(macAddress);
1575         MacEntry macEntry = getInterfaceMacEntriesOperationalDataPath(interfaceName, physAddress);
1576         InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
1577         if (macEntry != null && interfaceInfo != null) {
1578             deleteMacFlows(ElanUtils.getElanInstanceByName(broker, elanName), interfaceInfo, macEntry, flowTx);
1579         }
1580         interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
1581                 ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress));
1582         interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
1583                 ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress));
1584     }
1585
1586     public String getExternalElanInterface(String elanInstanceName, BigInteger dpnId) {
1587         DpnInterfaces dpnInterfaces = getElanInterfaceInfoByElanDpn(elanInstanceName, dpnId);
1588         if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null) {
1589             LOG.trace("Elan {} does not have interfaces in DPN {}", elanInstanceName, dpnId);
1590             return null;
1591         }
1592
1593         for (String dpnInterface : dpnInterfaces.getInterfaces()) {
1594             if (interfaceManager.isExternalInterface(dpnInterface)) {
1595                 return dpnInterface;
1596             }
1597         }
1598
1599         LOG.trace("Elan {} does not have any external interace attached to DPN {}", elanInstanceName, dpnId);
1600         return null;
1601     }
1602
1603     public static String getElanMacDPNKey(long elanTag, String macAddress, BigInteger dpnId) {
1604         String elanMacDmacDpnKey = "MAC-" + macAddress + " ELAN_TAG-" + elanTag + "DPN_ID-" + dpnId;
1605         return elanMacDmacDpnKey.intern();
1606     }
1607
1608     public static String getElanMacKey(long elanTag, String macAddress) {
1609         String elanMacKey = "MAC-" + macAddress + " ELAN_TAG-" + elanTag;
1610         return elanMacKey.intern();
1611     }
1612
1613     // TODO This should return a collection of futures
1614     public static void addToListenableFutureIfTxException(RuntimeException exception,
1615             List<ListenableFuture<Void>> futures) {
1616         Throwable cause = exception.getCause();
1617         if (cause != null && cause instanceof TransactionCommitFailedException) {
1618             futures.add(Futures.immediateFailedCheckedFuture((TransactionCommitFailedException) cause));
1619         }
1620     }
1621
1622     public static List<PhysAddress> getPhysAddress(List<String> macAddress) {
1623         Preconditions.checkNotNull(macAddress, "macAddress cannot be null");
1624         List<PhysAddress> physAddresses = new ArrayList<>();
1625         for (String mac : macAddress) {
1626             physAddresses.add(new PhysAddress(mac));
1627         }
1628         return physAddresses;
1629     }
1630
1631     public static List<StaticMacEntries> getStaticMacEntries(List<String> staticMacAddresses) {
1632         if (isEmpty(staticMacAddresses)) {
1633             return Collections.EMPTY_LIST;
1634         }
1635         StaticMacEntriesBuilder staticMacEntriesBuilder = new StaticMacEntriesBuilder();
1636         List<StaticMacEntries> staticMacEntries = new ArrayList<>();
1637         List<PhysAddress> physAddressList = getPhysAddress(staticMacAddresses);
1638         for (PhysAddress physAddress : physAddressList) {
1639             staticMacEntries.add(staticMacEntriesBuilder.setMacAddress(physAddress).build());
1640         }
1641         return staticMacEntries;
1642     }
1643
1644     public static InstanceIdentifier<StaticMacEntries> getStaticMacEntriesCfgDataPathIdentifier(String interfaceName,
1645                                                                                                 String macAddress) {
1646         return InstanceIdentifier.builder(ElanInterfaces.class)
1647                 .child(ElanInterface.class, new ElanInterfaceKey(interfaceName)).child(StaticMacEntries.class,
1648                         new StaticMacEntriesKey(new PhysAddress(macAddress))).build();
1649     }
1650
1651     public static List<StaticMacEntries> getDeletedEntries(List<StaticMacEntries> originalStaticMacEntries,
1652                                                            List<StaticMacEntries> updatedStaticMacEntries) {
1653         if (isEmpty(originalStaticMacEntries)) {
1654             return Collections.EMPTY_LIST;
1655         }
1656         List<StaticMacEntries> deleted = Lists.newArrayList(originalStaticMacEntries);
1657         if (isNotEmpty(updatedStaticMacEntries)) {
1658             deleted.removeAll(updatedStaticMacEntries);
1659         }
1660         return deleted;
1661     }
1662
1663     public static <T> List<T> diffOf(List<T> orig, List<T> updated) {
1664         if (isEmpty(orig)) {
1665             return Collections.EMPTY_LIST;
1666         }
1667         List<T> diff = Lists.newArrayList(orig);
1668         if (isNotEmpty(updated)) {
1669             diff.removeAll(updated);
1670         }
1671         return diff;
1672     }
1673
1674     public static void segregateToBeDeletedAndAddEntries(List<StaticMacEntries> originalStaticMacEntries,
1675                                                              List<StaticMacEntries> updatedStaticMacEntries) {
1676         if (isNotEmpty(updatedStaticMacEntries)) {
1677             List<StaticMacEntries> existingClonedStaticMacEntries = new ArrayList<>();
1678             if (isNotEmpty(originalStaticMacEntries)) {
1679                 existingClonedStaticMacEntries.addAll(0, originalStaticMacEntries);
1680                 originalStaticMacEntries.removeAll(updatedStaticMacEntries);
1681                 updatedStaticMacEntries.removeAll(existingClonedStaticMacEntries);
1682             }
1683         }
1684     }
1685
1686     public static boolean isEmpty(Collection collection) {
1687         return collection == null || collection.isEmpty();
1688     }
1689
1690     public static boolean isNotEmpty(Collection collection) {
1691         return !isEmpty(collection);
1692     }
1693
1694     public static void setElanInstancToDpnsCache(Map<String, Set<DpnInterfaces>> elanInstancToDpnsCache) {
1695         ElanUtils.elanInstancToDpnsCache = elanInstancToDpnsCache;
1696     }
1697
1698     public static Set<DpnInterfaces> getElanInvolvedDPNsFromCache(String elanName) {
1699         return elanInstancToDpnsCache.get(elanName);
1700     }
1701
1702     public static void addDPNInterfaceToElanInCache(String elanName, DpnInterfaces dpnInterfaces) {
1703         elanInstancToDpnsCache.computeIfAbsent(elanName, key -> new HashSet<>()).add(dpnInterfaces);
1704     }
1705
1706     public static void removeDPNInterfaceFromElanInCache(String elanName, DpnInterfaces dpnInterfaces) {
1707         elanInstancToDpnsCache.computeIfAbsent(elanName, key -> new HashSet<>()).remove(dpnInterfaces);
1708     }
1709
1710     public Optional<IpAddress> getSourceIpAddress(Ethernet ethernet) {
1711         Optional<IpAddress> srcIpAddress = Optional.absent();
1712         if (ethernet.getPayload() == null) {
1713             return srcIpAddress;
1714         }
1715         byte[] ipAddrBytes = null;
1716         if (ethernet.getPayload() instanceof IPv4) {
1717             IPv4 ipv4 = (IPv4) ethernet.getPayload();
1718             ipAddrBytes = Ints.toByteArray(ipv4.getSourceAddress());
1719         } else if (ethernet.getPayload() instanceof ARP) {
1720             ipAddrBytes = ((ARP) ethernet.getPayload()).getSenderProtocolAddress();
1721         }
1722         if (ipAddrBytes != null) {
1723             String ipAddr = NWUtil.toStringIpAddress(ipAddrBytes);
1724             return Optional.of(IpAddressBuilder.getDefaultInstance(ipAddr));
1725         }
1726         return srcIpAddress;
1727     }
1728
1729     public List<MacEntry> getElanMacEntries(String elanName) {
1730         MacTable macTable = getElanMacTable(elanName);
1731         if (macTable == null) {
1732             return Collections.emptyList();
1733         }
1734         return macTable.getMacEntry();
1735     }
1736
1737     public boolean isTunnelInLogicalGroup(String interfaceName, DataBroker broker) {
1738         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
1739             .ietf.interfaces.rev140508.interfaces.Interface configIface =
1740             interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName);
1741         IfTunnel ifTunnel = configIface.getAugmentation(IfTunnel.class);
1742         if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
1743             ParentRefs refs = configIface.getAugmentation(ParentRefs.class);
1744             if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
1745                 return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
1746             }
1747         }
1748         return false;
1749     }
1750
1751     public static void addElanInterfaceToElanInstanceCache(String elanInstanceName, String elanInterfaceName) {
1752         elanInstanceToInterfacesCache.computeIfAbsent(elanInstanceName, key -> new HashSet<>()).add(elanInterfaceName);
1753     }
1754
1755     public static void removeElanInterfaceToElanInstanceCache(String elanInstanceName, String interfaceName) {
1756         Set<String> elanInterfaces = elanInstanceToInterfacesCache.get(elanInstanceName);
1757         if (elanInterfaces == null || elanInterfaces.isEmpty()) {
1758             return;
1759         }
1760         elanInterfaces.remove(interfaceName);
1761     }
1762
1763     @Nonnull public static Set<String> removeAndGetElanInterfaces(String elanInstanceName) {
1764         Set<String> removed = elanInstanceToInterfacesCache.remove(elanInstanceName);
1765         return removed != null ? removed : Collections.emptySet();
1766     }
1767
1768     public static InstanceIdentifier<Flow> getFlowIid(Flow flow, BigInteger dpnId) {
1769         FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
1770         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId =
1771                 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId("openflow:" + dpnId);
1772         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node nodeDpn =
1773                 new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
1774         return InstanceIdentifier.builder(Nodes.class)
1775                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
1776                         nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1777                 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1778     }
1779
1780     public static String getElanInterfaceJobKey(String interfaceName) {
1781         return "elaninterface-" + interfaceName;
1782     }
1783
1784     public void addArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress, String macAddress,
1785             int lportTag, List<Instruction> instructions) {
1786         LOG.info("Installing the ARP responder flow on DPN {} for Interface {} with MAC {} & IP {}", dpnId,
1787                 ingressInterfaceName, macAddress, ipAddress);
1788         ElanInterface elanIface = getElanInterfaceByElanInterfaceName(broker, ingressInterfaceName);
1789         ElanInstance elanInstance = getElanInstanceByName(broker, elanIface.getElanInstanceName());
1790         if (elanInstance == null) {
1791             LOG.debug("addArpResponderFlow: elanInstance is null, Failed to install arp responder flow for Interface {}"
1792                       + " with MAC {} & IP {}", dpnId,
1793                 ingressInterfaceName, macAddress, ipAddress);
1794             return;
1795         }
1796         String flowId = ArpResponderUtil.getFlowId(lportTag, ipAddress);
1797         ArpResponderUtil.installFlow(mdsalManager, dpnId, flowId, flowId, NwConstants.DEFAULT_ARP_FLOW_PRIORITY,
1798                 ArpResponderUtil.generateCookie(lportTag, ipAddress),
1799                 ArpResponderUtil.getMatchCriteria(lportTag, elanInstance, ipAddress), instructions);
1800         LOG.info("Installed the ARP Responder flow for Interface {}", ingressInterfaceName);
1801     }
1802
1803     public void removeArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress,
1804             int lportTag) {
1805         LOG.info("Removing the ARP responder flow on DPN {} of Interface {} with IP {}", dpnId, ingressInterfaceName,
1806                 ipAddress);
1807         ArpResponderUtil.removeFlow(mdsalManager, dpnId, ArpResponderUtil.getFlowId(lportTag, ipAddress));
1808     }
1809 }
1810
1811