Merge "Add service names for priority configuration"
[netvirt.git] / vpnservice / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / netvirt / elan / utils / ElanUtils.java
1 /*
2  * Copyright (c) 2016 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.util.concurrent.CheckedFuture;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import java.math.BigInteger;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.concurrent.ConcurrentHashMap;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.Future;
23 import org.apache.commons.lang3.StringUtils;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
26 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
29 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
30 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
31 import org.opendaylight.genius.interfacemanager.globals.InterfaceServiceUtil;
32 import org.opendaylight.genius.itm.globals.ITMConstants;
33 import org.opendaylight.genius.mdsalutil.FlowEntity;
34 import org.opendaylight.genius.mdsalutil.InstructionInfo;
35 import org.opendaylight.genius.mdsalutil.InstructionType;
36 import org.opendaylight.genius.mdsalutil.MDSALUtil;
37 import org.opendaylight.genius.mdsalutil.MDSALUtil.MdsalOp;
38 import org.opendaylight.genius.mdsalutil.MatchFieldType;
39 import org.opendaylight.genius.mdsalutil.MatchInfo;
40 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
41 import org.opendaylight.genius.mdsalutil.NwConstants;
42 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
43 import org.opendaylight.genius.utils.ServiceIndex;
44 import org.opendaylight.netvirt.elan.internal.ElanInstanceManager;
45 import org.opendaylight.netvirt.elan.internal.ElanServiceProvider;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.IfIndexesInterfaceMap;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._if.indexes._interface.map.IfIndexInterface;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._if.indexes._interface.map.IfIndexInterfaceKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfExternal;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInput;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.ExternalTunnelList;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelList;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnelKey;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.CreateTerminatingServiceActionsInput;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.CreateTerminatingServiceActionsInputBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInput;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInputBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameOutput;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInput;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInput;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInputBuilder;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstanceBuilder;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTag;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagNameBuilder;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaceForwardingEntries;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanState;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanTagNameMap;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeFlat;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVlan;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVxlan;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableBuilder;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagName;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagNameBuilder;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagNameKey;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
140 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
141 import org.opendaylight.yangtools.yang.binding.DataObject;
142 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
143 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
144 import org.opendaylight.yangtools.yang.common.RpcResult;
145 import org.slf4j.Logger;
146 import org.slf4j.LoggerFactory;
147
148 public class ElanUtils {
149
150     private static ElanServiceProvider elanServiceProvider;
151     private static final Logger LOG = LoggerFactory.getLogger(ElanUtils.class);
152     private static Map<String, ElanInstance> elanInstanceLocalCache = new ConcurrentHashMap<>();
153     private static Map<String, ElanInterface> elanInterfaceLocalCache = new ConcurrentHashMap<>();
154
155     public static void setElanServiceProvider(ElanServiceProvider serviceProvider) {
156         elanServiceProvider = serviceProvider;
157     }
158
159     public static ElanServiceProvider getElanServiceProvider() {
160         return elanServiceProvider;
161     }
162
163     public static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
164         @Override
165         public void onSuccess(Void result) {
166             LOG.debug("Success in Datastore operation");
167         }
168
169         @Override
170         public void onFailure(Throwable error) {
171             LOG.error("Error in Datastore operation", error);
172         }
173     };
174     
175
176     public static void addElanInstanceIntoCache(String elanInstanceName, ElanInstance elanInstance) {
177         elanInstanceLocalCache.put(elanInstanceName, elanInstance);
178     }
179
180     public static void removeElanInstanceFromCache(String elanInstanceName) {
181         elanInstanceLocalCache.remove(elanInstanceName);
182     }
183
184     public static ElanInstance getElanInstanceFromCache(String elanInstanceName) {
185         return elanInstanceLocalCache.get(elanInstanceName);
186     }
187
188     public static void addElanInterfaceIntoCache(String interfaceName, ElanInterface elanInterface) {
189         elanInterfaceLocalCache.put(interfaceName, elanInterface);
190     }
191
192     public static void removeElanInterfaceFromCache(String interfaceName) {
193         elanInterfaceLocalCache.remove(interfaceName);
194     }
195
196     public static ElanInterface getElanInterfaceFromCache(String interfaceName) {
197         return elanInterfaceLocalCache.get(interfaceName);
198     }
199
200     /**
201      * Uses the IdManager to retrieve a brand new ElanTag.
202      *
203      * @param idManager
204      *            the id manager
205      * @param idKey
206      *            the id key
207      * @return the integer
208      */
209     public static Long retrieveNewElanTag(IdManagerService idManager, String idKey) {
210
211         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME)
212                 .setIdKey(idKey).build();
213
214         try {
215             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
216             RpcResult<AllocateIdOutput> rpcResult = result.get();
217             if (rpcResult.isSuccessful()) {
218                 return rpcResult.getResult().getIdValue().longValue();
219             } else {
220                 LOG.warn("RPC Call to Allocate Id returned with Errors {}", rpcResult.getErrors());
221             }
222         } catch (InterruptedException | ExecutionException e) {
223             LOG.warn("Exception when Allocating Id", e);
224         }
225         return 0L;
226     }
227
228     public static void releaseId(IdManagerService idManager, String poolName, String idKey) {
229         ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
230         Future<RpcResult<Void>> result = idManager.releaseId(releaseIdInput);
231     }
232
233     public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
234             InstanceIdentifier<T> path) {
235         ReadOnlyTransaction tx = (broker != null) ? broker.newReadOnlyTransaction()
236                 : elanServiceProvider.getBroker().newReadOnlyTransaction();
237         Optional<T> result = Optional.absent();
238         try {
239             CheckedFuture<Optional<T>, ReadFailedException> checkedFuture = tx.read(datastoreType, path);
240             result = checkedFuture.get();
241         } catch (Exception e) {
242             throw new RuntimeException(e);
243         }
244
245         return result;
246     }
247
248     public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
249             InstanceIdentifier<T> path) {
250         WriteTransaction tx = broker.newWriteOnlyTransaction();
251         tx.delete(datastoreType, path);
252         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
253     }
254
255     public static InstanceIdentifier<ElanInstance> getElanInstanceIdentifier() {
256         return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class).build();
257     }
258
259     // elan-instances config container
260     public static ElanInstance getElanInstanceByName(String elanInstanceName) {
261          ElanInstance elanObj = getElanInstanceFromCache(elanInstanceName);
262          if (elanObj != null) {
263              return elanObj;
264          }
265         InstanceIdentifier<ElanInstance> elanIdentifierId = getElanInstanceConfigurationDataPath(elanInstanceName);
266         Optional<ElanInstance> elanInstance = read(elanServiceProvider.getBroker(), LogicalDatastoreType.CONFIGURATION,
267                 elanIdentifierId);
268         if (elanInstance.isPresent()) {
269             return elanInstance.get();
270         }
271         return null;
272     }
273
274     public static InstanceIdentifier<ElanInstance> getElanInstanceConfigurationDataPath(String elanInstanceName) {
275         return InstanceIdentifier.builder(ElanInstances.class)
276                 .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
277     }
278
279     // elan-interfaces Config Container
280     public static ElanInterface getElanInterfaceByElanInterfaceName(String elanInterfaceName) {
281           ElanInterface elanInterfaceObj = getElanInterfaceFromCache(elanInterfaceName);
282           if (elanInterfaceObj != null) {
283               return elanInterfaceObj;
284           }
285         InstanceIdentifier<ElanInterface> elanInterfaceId = getElanInterfaceConfigurationDataPathId(elanInterfaceName);
286         Optional<ElanInterface> existingElanInterface = read(elanServiceProvider.getBroker(),
287                 LogicalDatastoreType.CONFIGURATION, elanInterfaceId);
288         if (existingElanInterface.isPresent()) {
289             return existingElanInterface.get();
290         }
291         return null;
292     }
293
294     public static EtreeInterface getEtreeInterfaceByElanInterfaceName(String elanInterfaceName) {
295         ElanInterface elanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(elanInterfaceName);
296         return elanInterface.getAugmentation(EtreeInterface.class);
297     }
298
299     public static InstanceIdentifier<ElanInterface> getElanInterfaceConfigurationDataPathId(String interfaceName) {
300         return InstanceIdentifier.builder(ElanInterfaces.class)
301                 .child(ElanInterface.class, new ElanInterfaceKey(interfaceName)).build();
302     }
303
304     // elan-state Operational container
305     public static Elan getElanByName(String elanInstanceName) {
306         InstanceIdentifier<Elan> elanIdentifier = getElanInstanceOperationalDataPath(elanInstanceName);
307         Optional<Elan> elanInstance = read(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL,
308                 elanIdentifier);
309         if (elanInstance.isPresent()) {
310             return elanInstance.get();
311         }
312         return null;
313     }
314
315     public static InstanceIdentifier<Elan> getElanInstanceOperationalDataPath(String elanInstanceName) {
316         return InstanceIdentifier.builder(ElanState.class).child(Elan.class, new ElanKey(elanInstanceName)).build();
317     }
318
319     // grouping of forwarding-entries
320     public static MacEntry getInterfaceMacEntriesOperationalDataPath(String interfaceName, PhysAddress physAddress) {
321         InstanceIdentifier<MacEntry> existingMacEntryId = getInterfaceMacEntriesIdentifierOperationalDataPath(
322                 interfaceName, physAddress);
323         Optional<MacEntry> existingInterfaceMacEntry = read(elanServiceProvider.getBroker(),
324                 LogicalDatastoreType.OPERATIONAL, existingMacEntryId);
325         if (existingInterfaceMacEntry.isPresent()) {
326             return existingInterfaceMacEntry.get();
327         }
328         return null;
329     }
330
331     public static MacEntry getInterfaceMacEntriesOperationalDataPathFromId(InstanceIdentifier identifier) {
332         Optional<MacEntry> existingInterfaceMacEntry = read(elanServiceProvider.getBroker(),
333                 LogicalDatastoreType.OPERATIONAL, identifier);
334         if (existingInterfaceMacEntry.isPresent()) {
335             return existingInterfaceMacEntry.get();
336         }
337         return null;
338     }
339
340     public static InstanceIdentifier<MacEntry> getInterfaceMacEntriesIdentifierOperationalDataPath(String interfaceName,
341             PhysAddress physAddress) {
342         return InstanceIdentifier.builder(ElanInterfaceForwardingEntries.class)
343                 .child(ElanInterfaceMac.class, new ElanInterfaceMacKey(interfaceName))
344                 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
345
346     }
347
348     // elan-forwarding-tables Operational container
349     public static MacEntry getMacTableByElanName(String elanName, PhysAddress physAddress) {
350         InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanName, physAddress);
351         Optional<MacEntry> existingElanMacEntry = read(elanServiceProvider.getBroker(),
352                 LogicalDatastoreType.OPERATIONAL, macId);
353         if (existingElanMacEntry.isPresent()) {
354             return existingElanMacEntry.get();
355         }
356         return null;
357     }
358
359     public static MacEntry getMacEntryFromElanMacId(InstanceIdentifier identifier) {
360         Optional<MacEntry> existingInterfaceMacEntry = read(elanServiceProvider.getBroker(),
361                 LogicalDatastoreType.OPERATIONAL, identifier);
362         if (existingInterfaceMacEntry.isPresent()) {
363             return existingInterfaceMacEntry.get();
364         }
365         return null;
366     }
367
368     public static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
369             PhysAddress physAddress) {
370         return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
371                 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
372     }
373
374     public static InstanceIdentifier<MacTable> getElanMacTableOperationalDataPath(String elanName) {
375         return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
376                 .build();
377     }
378
379     // elan-interface-forwarding-entries Operational container
380     public static ElanInterfaceMac getElanInterfaceMacByInterfaceName(String interfaceName) {
381         InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = getElanInterfaceMacEntriesOperationalDataPath(
382                 interfaceName);
383         Optional<ElanInterfaceMac> existingElanInterface = read(elanServiceProvider.getBroker(),
384                 LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
385         if (existingElanInterface.isPresent()) {
386             return existingElanInterface.get();
387         }
388         return null;
389     }
390
391     /**
392      * Gets the elan interface mac addresses.
393      *
394      * @param interfaceName
395      *            the interface name
396      * @return the elan interface mac addresses
397      */
398     public static List<PhysAddress> getElanInterfaceMacAddresses(String interfaceName) {
399         List<PhysAddress> macAddresses = new ArrayList<PhysAddress>();
400         ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
401         if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
402             List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
403             for (MacEntry macEntry : macEntries) {
404                 macAddresses.add(macEntry.getMacAddress());
405             }
406         }
407         return macAddresses;
408     }
409
410     public static InstanceIdentifier<ElanInterfaceMac> getElanInterfaceMacEntriesOperationalDataPath(
411             String interfaceName) {
412         return InstanceIdentifier.builder(ElanInterfaceForwardingEntries.class)
413                 .child(ElanInterfaceMac.class, new ElanInterfaceMacKey(interfaceName)).build();
414     }
415
416     /**
417      * Returns the list of Interfaces that belong to an Elan on an specific DPN.
418      * Data retrieved from Elan's operational DS: elan-dpn-interfaces container
419      *
420      * @param elanInstanceName
421      *            name of the Elan to which the interfaces must belong to
422      * @param dpId
423      *            Id of the DPN where the interfaces are located
424      * @return the elan interface Info
425      */
426     public static DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId) {
427         InstanceIdentifier<DpnInterfaces> elanDpnInterfacesId = getElanDpnInterfaceOperationalDataPath(elanInstanceName,
428                 dpId);
429         Optional<DpnInterfaces> elanDpnInterfaces = read(elanServiceProvider.getBroker(),
430                 LogicalDatastoreType.OPERATIONAL, elanDpnInterfacesId);
431         if (elanDpnInterfaces.isPresent()) {
432             return elanDpnInterfaces.get();
433         }
434         return null;
435     }
436
437     /**
438      * Returns the InstanceIdentifier that points to the Interfaces of an Elan
439      * in a given DPN in the Operational DS. Data retrieved from Elans's
440      * operational DS: dpn-interfaces list
441      *
442      * @param elanInstanceName
443      *            name of the Elan to which the interfaces must belong to
444      * @param dpId
445      *            Id of the DPN where the interfaces are located
446      * @return the elan dpn interface
447      */
448     public static InstanceIdentifier<DpnInterfaces> getElanDpnInterfaceOperationalDataPath(String elanInstanceName,
449             BigInteger dpId) {
450         return InstanceIdentifier.builder(ElanDpnInterfaces.class)
451                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName))
452                 .child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build();
453     }
454
455     // elan-tag-name-map Operational Container
456     public static ElanTagName getElanInfoByElanTag(long elanTag) {
457         InstanceIdentifier<ElanTagName> elanId = getElanInfoEntriesOperationalDataPath(elanTag);
458         Optional<ElanTagName> existingElanInfo = ElanUtils.read(elanServiceProvider.getBroker(),
459                 LogicalDatastoreType.OPERATIONAL, elanId);
460         if (existingElanInfo.isPresent()) {
461             return existingElanInfo.get();
462         }
463         return null;
464     }
465
466     public static EtreeLeafTagName getEtreeLeafTagByElanTag(long elanTag) {
467         InstanceIdentifier<ElanTagName> elanId = getElanInfoEntriesOperationalDataPath(elanTag);
468         Optional<ElanTagName> existingElanInfo = ElanUtils.read(elanServiceProvider.getBroker(),
469                 LogicalDatastoreType.OPERATIONAL, elanId);
470         if (existingElanInfo.isPresent()) {
471             ElanTagName elanTagName = existingElanInfo.get();
472             EtreeLeafTagName etreeAugmentation = elanTagName.getAugmentation(EtreeLeafTagName.class);
473             return etreeAugmentation;
474         }
475         return null;
476     }
477
478     public static InstanceIdentifier<ElanTagName> getElanInfoEntriesOperationalDataPath(long elanTag) {
479         return InstanceIdentifier.builder(ElanTagNameMap.class).child(ElanTagName.class, new ElanTagNameKey(elanTag))
480                 .build();
481     }
482
483     // interface-index-tag operational container
484     public static Optional<IfIndexInterface> getInterfaceInfoByInterfaceTag(long interfaceTag) {
485         InstanceIdentifier<IfIndexInterface> interfaceId = getInterfaceInfoEntriesOperationalDataPath(interfaceTag);
486         return ElanUtils.read(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, interfaceId);
487     }
488
489     public static InstanceIdentifier<IfIndexInterface> getInterfaceInfoEntriesOperationalDataPath(long interfaceTag) {
490         return InstanceIdentifier.builder(IfIndexesInterfaceMap.class)
491                 .child(IfIndexInterface.class, new IfIndexInterfaceKey((int) interfaceTag)).build();
492     }
493
494     public static InstanceIdentifier<ElanDpnInterfacesList> getElanDpnOperationDataPath(String elanInstanceName) {
495         return InstanceIdentifier.builder(ElanDpnInterfaces.class)
496                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
497     }
498
499     public static ElanDpnInterfacesList getElanDpnInterfacesList(String elanName) {
500         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanName);
501         Optional<ElanDpnInterfacesList> existingElanDpnInterfaces = ElanUtils.read(elanServiceProvider.getBroker(),
502                 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
503         if (existingElanDpnInterfaces.isPresent()) {
504             return existingElanDpnInterfaces.get();
505         }
506         return null;
507     }
508
509     /**
510      * This method is useful get all ELAN participating CSS dpIds to install
511      * program remote dmac entries and updating remote bc groups for tor
512      * integration.
513      *
514      * @param elanInstanceName
515      *            the elan instance name
516      * @return list of dpIds
517      */
518     public static List<BigInteger> getParticipatingDPNsInElanInstance(String elanInstanceName) {
519         List<BigInteger> dpIds = new ArrayList<BigInteger>();
520         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
521         Optional<ElanDpnInterfacesList> existingElanDpnInterfaces = ElanUtils.read(elanServiceProvider.getBroker(),
522                 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
523         if (!existingElanDpnInterfaces.isPresent()) {
524             return dpIds;
525         }
526         List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces();
527         for (DpnInterfaces dpnInterface : dpnInterfaces) {
528             dpIds.add(dpnInterface.getDpId());
529         }
530         return dpIds;
531     }
532
533     /**
534      * To check given dpId is already present in Elan instance. This can be used
535      * to program flow entry in external tunnel table when a new access port
536      * added for first time into the ELAN instance
537      *
538      * @param dpId
539      *            the dp id
540      * @param elanInstanceName
541      *            the elan instance name
542      * @return true if dpId is already present, otherwise return false
543      */
544     public static boolean isDpnAlreadyPresentInElanInstance(BigInteger dpId, String elanInstanceName) {
545         boolean isDpIdPresent = false;
546         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
547         Optional<ElanDpnInterfacesList> existingElanDpnInterfaces = ElanUtils.read(elanServiceProvider.getBroker(),
548                 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
549         if (!existingElanDpnInterfaces.isPresent()) {
550             return isDpIdPresent;
551         }
552         List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces();
553         for (DpnInterfaces dpnInterface : dpnInterfaces) {
554             if (dpnInterface.getDpId().equals(dpId)) {
555                 isDpIdPresent = true;
556                 break;
557             }
558         }
559         return isDpIdPresent;
560     }
561
562     public static ElanDpnInterfaces getElanDpnInterfacesList() {
563         InstanceIdentifier<ElanDpnInterfaces> elanDpnInterfaceId = InstanceIdentifier.builder(ElanDpnInterfaces.class)
564                 .build();
565         Optional<ElanDpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(elanServiceProvider.getBroker(),
566                 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
567         if (existingElanDpnInterfaces.isPresent()) {
568             return existingElanDpnInterfaces.get();
569         }
570         return null;
571     }
572
573     public static ElanForwardingTables getElanForwardingList() {
574         InstanceIdentifier<ElanForwardingTables> elanForwardingTableId = InstanceIdentifier
575                 .builder(ElanForwardingTables.class).build();
576         Optional<ElanForwardingTables> existingElanForwardingList = ElanUtils.read(elanServiceProvider.getBroker(),
577                 LogicalDatastoreType.OPERATIONAL, elanForwardingTableId);
578         if (existingElanForwardingList.isPresent()) {
579             return existingElanForwardingList.get();
580         }
581         return null;
582     }
583
584     /**
585      * Gets the elan mac table.
586      *
587      * @param elanName
588      *            the elan name
589      * @return the elan mac table
590      */
591     public static MacTable getElanMacTable(String elanName) {
592         InstanceIdentifier<MacTable> elanMacTableId = getElanMacTableOperationalDataPath(elanName);
593         Optional<MacTable> existingElanMacTable = ElanUtils.read(elanServiceProvider.getBroker(),
594                 LogicalDatastoreType.OPERATIONAL, elanMacTableId);
595         if (existingElanMacTable.isPresent()) {
596             return existingElanMacTable.get();
597         }
598         return null;
599     }
600
601     public static long getElanLocalBCGID(long elanTag) {
602         return ElanConstants.ELAN_GID_MIN + (((elanTag % ElanConstants.ELAN_GID_MIN) * 2) - 1);
603     }
604
605     public static long getElanRemoteBCGID(long elanTag) {
606         return ElanConstants.ELAN_GID_MIN + (((elanTag % ElanConstants.ELAN_GID_MIN) * 2));
607     }
608
609     public static long getEtreeLeafLocalBCGID(long etreeLeafTag) {
610         return ElanConstants.ELAN_GID_MIN + (((etreeLeafTag % ElanConstants.ELAN_GID_MIN) * 2) - 1);
611     }
612
613     public static long getEtreeLeafRemoteBCGID(long etreeLeafTag) {
614         return ElanConstants.ELAN_GID_MIN + (((etreeLeafTag % ElanConstants.ELAN_GID_MIN) * 2));
615     }
616
617     public static BigInteger getElanMetadataLabel(long elanTag) {
618         return (BigInteger.valueOf(elanTag)).shiftLeft(24);
619     }
620
621     public static BigInteger getElanMetadataLabel(long elanTag, boolean isSHFlagSet) {
622         int shBit = (isSHFlagSet) ? 1 : 0;
623         return (BigInteger.valueOf(elanTag)).shiftLeft(24).or(BigInteger.valueOf(shBit));
624     }
625
626     public static BigInteger getElanMetadataLabel(long elanTag, int lportTag) {
627         return getElanMetadataLabel(elanTag).or(MetaDataUtil.getLportTagMetaData(lportTag));
628     }
629
630     public static BigInteger getElanMetadataMask() {
631         return MetaDataUtil.METADATA_MASK_SERVICE.or(MetaDataUtil.METADATA_MASK_LPORT_TAG);
632     }
633
634     /**
635      * Setting INTERNAL_TUNNEL_TABLE, SMAC, DMAC, UDMAC in this DPN and also in
636      * other DPNs.
637      *
638      * @param elanInfo
639      *            the elan info
640      * @param interfaceInfo
641      *            the interface info
642      * @param macTimeout
643      *            the mac timeout
644      * @param macAddress
645      *            the mac address
646      * @param writeFlowGroupTx
647      *            the flow group tx
648      */
649     public static void setupMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout,
650             String macAddress, WriteTransaction writeFlowGroupTx) {
651         synchronized (macAddress) {
652             LOG.info("Acquired lock for mac : " + macAddress + ". Proceeding with install operation.");
653             setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, elanServiceProvider.getMdsalManager(),
654                     writeFlowGroupTx);
655             setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, elanServiceProvider.getMdsalManager(),
656                     elanServiceProvider.getBroker(), writeFlowGroupTx);
657         }
658     }
659
660     public static void setupDMacFlowonRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId,
661             String macAddress, WriteTransaction writeFlowTx) {
662         synchronized (macAddress) {
663             LOG.info("Acquired lock for mac : " + macAddress + "Proceeding with install operation.");
664             setupOrigDmacFlowsonRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, writeFlowTx);
665         }
666     }
667
668     /**
669      * Inserts a Flow in SMAC table to state that the MAC has already been
670      * learnt.
671      *
672      * @param elanInfo
673      * @param interfaceInfo
674      * @param macTimeout
675      * @param macAddress
676      * @param mdsalApiManager
677      */
678     private static void setupKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout,
679             String macAddress, IMdsalApiManager mdsalApiManager, WriteTransaction writeFlowGroupTx) {
680         FlowEntity flowEntity = buildKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress);
681         mdsalApiManager.addFlowToTx(flowEntity, writeFlowGroupTx);
682         if (LOG.isDebugEnabled()) {
683             LOG.debug("Known Smac flow entry created for elan Name:{}, logical Interface port:{} and mac address:{}",
684                     elanInfo.getElanInstanceName(), elanInfo.getDescription(), macAddress);
685         }
686     }
687
688     public static FlowEntity buildKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout,
689             String macAddress) {
690         BigInteger dpId = interfaceInfo.getDpId();
691         int lportTag = interfaceInfo.getInterfaceTag();
692         long elanTag = getElanTag(elanInfo, interfaceInfo);
693         // Matching metadata and eth_src fields
694         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
695         mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
696                 ElanUtils.getElanMetadataLabel(elanInfo.getElanTag(), lportTag), ElanUtils.getElanMetadataMask() }));
697         mkMatches.add(new MatchInfo(MatchFieldType.eth_src, new String[] { macAddress }));
698         List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
699         mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.ELAN_DMAC_TABLE }));
700
701         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_SMAC_TABLE,
702                 getKnownDynamicmacFlowRef(NwConstants.ELAN_SMAC_TABLE, dpId, lportTag, macAddress, elanTag), 20,
703                 elanInfo.getDescription(), (int) macTimeout, 0,
704                 ElanConstants.COOKIE_ELAN_KNOWN_SMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
705         flowEntity.setStrictFlag(true);
706         flowEntity.setSendFlowRemFlag(macTimeout != 0); // If Mac timeout is 0,
707                                                         // the flow wont be
708                                                         // deleted
709                                                         // automatically, so no
710                                                         // need to get notified
711         return flowEntity;
712     }
713
714     private static Long getElanTag(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
715         EtreeInterface etreeInterface = ElanUtils
716                 .getEtreeInterfaceByElanInterfaceName(interfaceInfo.getInterfaceName());
717         if (etreeInterface == null || etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
718             return elanInfo.getElanTag();
719         } else { // Leaf
720             EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
721             if (etreeInstance == null) {
722                 LOG.warn("EtreeInterface " + interfaceInfo.getInterfaceName() + " is connected to a non-Etree network: "
723                         + elanInfo.getElanInstanceName());
724                 return elanInfo.getElanTag();
725             } else {
726                 return etreeInstance.getEtreeLeafTagVal().getValue();
727             }
728         }
729     }
730
731     /**
732      * Installs a Flow in INTERNAL_TUNNEL_TABLE of the affected DPN that sends
733      * the packet through the specified interface if the tunnel_id matches the
734      * interface's lportTag
735      *
736      * @param interfaceInfo
737      *            the interface info
738      * @param mdsalApiManager
739      *            the mdsal API manager
740      * @param writeFlowGroupTx
741      *            the writeFLowGroup tx
742      */
743     public static void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager,
744             WriteTransaction writeFlowGroupTx) {
745         BigInteger dpId = interfaceInfo.getDpId();
746         int lportTag = interfaceInfo.getInterfaceTag();
747         Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
748                 getIntTunnelTableFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, lportTag), 5,
749                 String.format("%s:%d", "ITM Flow Entry ", lportTag), 0, 0,
750                 ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(lportTag)),
751                 getTunnelIdMatchForFilterEqualsLPortTag(lportTag),
752                 getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
753         mdsalApiManager.addFlowToTx(dpId, flow, writeFlowGroupTx);
754         if (LOG.isDebugEnabled()) {
755             LOG.debug("Terminating service table flow entry created on dpn:{} for logical Interface port:{}", dpId,
756                     interfaceInfo.getPortName());
757         }
758     }
759
760     /**
761      * Constructs the FlowName for flows installed in the Internal Tunnel Table,
762      * consisting in tableId + elanTag.
763      *
764      * @param tableId
765      *            table Id
766      * @param elanTag
767      *            elan Tag
768      * @return the Internal tunnel
769      */
770     public static String getIntTunnelTableFlowRef(short tableId, int elanTag) {
771         return new StringBuffer().append(tableId).append(elanTag).toString();
772     }
773
774     /**
775      * Constructs the Matches that checks that the tunnel_id field contains a
776      * specific lportTag
777      *
778      * @param lportTag
779      *            lportTag that must be checked against the tunnel_id field
780      * @return the list of match Info
781      */
782     public static List<MatchInfo> getTunnelIdMatchForFilterEqualsLPortTag(int lportTag) {
783         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
784         // Matching metadata
785         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] { BigInteger.valueOf(lportTag) }));
786         return mkMatches;
787     }
788
789     /**
790      * Constructs the Instructions that take the packet over a given interface
791      *
792      * @param ifName
793      *            Name of the interface where the packet must be sent over. It
794      *            can be a local interface or a tunnel interface (internal or
795      *            external)
796      * @return the Instruction
797      */
798     public static List<Instruction> getInstructionsInPortForOutGroup(String ifName) {
799         List<Instruction> mkInstructions = new ArrayList<Instruction>();
800         List<Action> actions = ElanUtils.getEgressActionsForInterface(ifName, /* tunnelKey */ null);
801
802         mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
803         return mkInstructions;
804     }
805
806     /**
807      * Returns the list of Actions to be taken when sending the packet through
808      * an Elan interface. Note that this interface can refer to an ElanInterface
809      * where the Elan VM is attached to a DPN or an ITM tunnel interface where
810      * Elan traffic can be sent through. In this latter case, the tunnelKey is
811      * mandatory and it can hold serviceId for internal tunnels or the VNI for
812      * external tunnels.
813      *
814      * @param ifName
815      *            the if name
816      * @param tunnelKey
817      *            the tunnel key
818      * @return the egress actions for interface
819      */
820     public static List<Action> getEgressActionsForInterface(String ifName, Long tunnelKey) {
821         List<Action> listAction = new ArrayList<Action>();
822         try {
823             GetEgressActionsForInterfaceInput getEgressActionInput = new GetEgressActionsForInterfaceInputBuilder()
824                     .setIntfName(ifName).setTunnelKey(tunnelKey).build();
825             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result = elanServiceProvider
826                     .getInterfaceManagerRpcService().getEgressActionsForInterface(getEgressActionInput);
827             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
828             if (!rpcResult.isSuccessful()) {
829                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName,
830                         rpcResult.getErrors());
831             } else {
832                 List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actions = rpcResult
833                         .getResult().getAction();
834                 listAction = actions;
835             }
836         } catch (InterruptedException | ExecutionException e) {
837             LOG.warn("Exception when egress actions for interface {}", ifName, e);
838         }
839         return listAction;
840     }
841
842     private static void setupOrigDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
843             IMdsalApiManager mdsalApiManager, DataBroker broker, WriteTransaction writeFlowGroupTx) {
844         BigInteger dpId = interfaceInfo.getDpId();
845         String ifName = interfaceInfo.getInterfaceName();
846         long ifTag = interfaceInfo.getInterfaceTag();
847         String elanInstanceName = elanInfo.getElanInstanceName();
848         List<DpnInterfaces> elanDpns = getInvolvedDpnsInElan(elanInstanceName);
849         if (elanDpns != null) {
850             Long elanTag = getElanTag(elanInfo, interfaceInfo); // TODO might be
851                                                                 // bug and
852                                                                 // should call
853                                                                 // here just
854                                                                 // elanInfo.getElanTag()
855             for (DpnInterfaces elanDpn : elanDpns) {
856                 if (elanDpn.getDpId().equals(dpId)) {
857                     // On the local DPN set up a direct output flow
858                     setupLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInstanceName, mdsalApiManager, ifTag,
859                             writeFlowGroupTx);
860                     LOG.debug(
861                             "Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on dpn:{}",
862                             elanInstanceName, interfaceInfo.getPortName(), macAddress, dpId);
863                 } else {
864                     // Check for the Remote DPN present in Inventory Manager
865                     if (isDpnPresent(elanDpn.getDpId())) {
866                         // For remote DPNs a flow is needed to indicate that
867                         // packets of this ELAN going to this MAC
868                         // need to be forwarded through the appropiated ITM
869                         // tunnel
870                         setupRemoteDmacFlow(elanDpn.getDpId(), // srcDpn (the
871                                                                // remote DPN in
872                                                                // this case)
873                                 dpId, // dstDpn (the local DPN)
874                                 interfaceInfo.getInterfaceTag(), // lportTag of
875                                                                  // the local
876                                                                  // interface
877                                 elanTag, // identifier of the Elan
878                                 macAddress, // MAC to be programmed in remote
879                                             // DPN
880                                 elanInstanceName, writeFlowGroupTx, ifName);
881                         LOG.debug(
882                                 "Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on dpn:{}",
883                                 elanInstanceName, interfaceInfo.getPortName(), macAddress, elanDpn.getDpId());
884                     }
885                 }
886             }
887
888             // TODO: Make sure that the same is performed against the
889             // ElanDevices.
890         }
891     }
892
893     private static void setupOrigDmacFlowsonRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
894             BigInteger dstDpId, String macAddress, WriteTransaction writeFlowTx) {
895         BigInteger dpId = interfaceInfo.getDpId();
896         String elanInstanceName = elanInfo.getElanInstanceName();
897         List<DpnInterfaces> remoteFEs = getInvolvedDpnsInElan(elanInstanceName);
898         for (DpnInterfaces remoteFE : remoteFEs) {
899             Long elanTag = elanInfo.getElanTag();
900             if (remoteFE.getDpId().equals(dstDpId)) {
901                 // Check for the Remote DPN present in Inventory Manager
902                 setupRemoteDmacFlow(dstDpId, dpId, interfaceInfo.getInterfaceTag(), elanTag, macAddress,
903                         elanInstanceName, writeFlowTx, interfaceInfo.getInterfaceName());
904                 if (LOG.isDebugEnabled()) {
905                     LOG.debug(
906                             "Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address {} on dpn:{}",
907                             elanInstanceName, interfaceInfo.getPortName(), macAddress, remoteFE.getDpId());
908                 }
909                 break;
910             }
911         }
912     }
913
914     @SuppressWarnings("unchecked")
915     public static List<DpnInterfaces> getInvolvedDpnsInElan(String elanName) {
916         List<DpnInterfaces> dpns = ElanInstanceManager.getElanInstanceManager(elanServiceProvider)
917                 .getElanDPNByName(elanName);
918         if (dpns == null) {
919             return Collections.emptyList();
920         }
921         return dpns;
922     }
923
924     private static void setupLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress,
925             String displayName, IMdsalApiManager mdsalApiManager, long ifTag, WriteTransaction writeFlowGroupTx) {
926         Flow flowEntity = buildLocalDmacFlowEntry(elanTag, dpId, ifName, macAddress, displayName, ifTag);
927         mdsalApiManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
928         installEtreeLocalDmacFlow(elanTag, dpId, ifName, macAddress, displayName, mdsalApiManager, ifTag,
929                 writeFlowGroupTx);
930     }
931
932     private static void installEtreeLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress,
933             String displayName, IMdsalApiManager mdsalApiManager, long ifTag, WriteTransaction writeFlowGroupTx) {
934         EtreeInterface etreeInterface = ElanUtils.getEtreeInterfaceByElanInterfaceName(ifName);
935         if (etreeInterface != null) {
936             if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
937                 EtreeLeafTagName etreeTagName = ElanUtils.getEtreeLeafTagByElanTag(elanTag);
938                 if (etreeTagName == null) {
939                     LOG.warn("Interface " + ifName + " seems like it belongs to Etree but etreeTagName from elanTag "
940                             + elanTag + " is null.");
941                 } else {
942                     Flow flowEntity = buildLocalDmacFlowEntry(etreeTagName.getEtreeLeafTag().getValue(), dpId, ifName,
943                             macAddress, displayName, ifTag);
944                     mdsalApiManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
945                 }
946             }
947         }
948     }
949
950     public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, long lporTag, String macAddress,
951             long elanTag) {
952         return new StringBuffer().append(tableId).append(elanTag).append(dpId).append(lporTag).append(macAddress)
953                 .toString();
954     }
955
956     public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, BigInteger remoteDpId,
957             String macAddress, long elanTag) {
958         return new StringBuffer().append(tableId).append(elanTag).append(dpId).append(remoteDpId).append(macAddress)
959                 .toString();
960     }
961
962     private static String getKnownDynamicmacFlowRef(short elanDmacTable, BigInteger dpId, String extDeviceNodeId,
963             String dstMacAddress, long elanTag, boolean shFlag) {
964         return new StringBuffer().append(elanDmacTable).append(elanTag).append(dpId).append(extDeviceNodeId)
965                 .append(dstMacAddress).append(shFlag).toString();
966     }
967
968     /**
969      * Builds the flow to be programmed in the DMAC table of the local DPN (that
970      * is, where the MAC is attached to). This flow consists in:
971      *
972      * Match: + elanTag in metadata + packet goes to a MAC locally attached
973      * Actions: + optionally, pop-vlan + set-vlan-id + output to ifName's
974      * portNumber
975      *
976      * @param elanTag
977      *            the elan tag
978      * @param dpId
979      *            the dp id
980      * @param ifName
981      *            the if name
982      * @param macAddress
983      *            the mac address
984      * @param displayName
985      *            the display name
986      * @param ifTag
987      *            the if tag
988      * @return the flow
989      */
990     public static Flow buildLocalDmacFlowEntry(long elanTag, BigInteger dpId, String ifName, String macAddress,
991             String displayName, long ifTag) {
992         List<MatchInfo> mkMatches = new ArrayList<>();
993         mkMatches.add(new MatchInfo(MatchFieldType.metadata,
994                 new BigInteger[] { ElanUtils.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE }));
995         mkMatches.add(new MatchInfo(MatchFieldType.eth_dst, new String[] { macAddress }));
996
997         List<Instruction> mkInstructions = new ArrayList<Instruction>();
998         List<Action> actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null);
999         mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
1000         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
1001                 getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, ifTag, macAddress, elanTag), 20,
1002                 displayName, 0, 0, ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches,
1003                 mkInstructions);
1004
1005         return flow;
1006     }
1007
1008     public static void setupRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag,
1009             String macAddress, String displayName, WriteTransaction writeFlowGroupTx, String interfaceName) {
1010         Flow flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTag, elanTag, macAddress, displayName);
1011         elanServiceProvider.getMdsalManager().addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx);
1012         setupEtreeRemoteDmacFlow(srcDpId, destDpId, lportTag, elanTag, macAddress, displayName, interfaceName,
1013                 writeFlowGroupTx);
1014     }
1015
1016     private static void setupEtreeRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag,
1017             String macAddress, String displayName, String interfaceName, WriteTransaction writeFlowGroupTx) {
1018         Flow flowEntity;
1019         EtreeInterface etreeInterface = ElanUtils.getEtreeInterfaceByElanInterfaceName(interfaceName);
1020         if (etreeInterface != null) {
1021             if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1022                 EtreeLeafTagName etreeTagName = ElanUtils.getEtreeLeafTagByElanTag(elanTag);
1023                 if (etreeTagName == null) {
1024                     LOG.warn("Interface " + interfaceName
1025                             + " seems like it belongs to Etree but etreeTagName from elanTag " + elanTag + " is null.");
1026                 } else {
1027                     flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTag,
1028                             etreeTagName.getEtreeLeafTag().getValue(), macAddress, displayName);
1029                     elanServiceProvider.getMdsalManager().addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx);
1030                 }
1031             }
1032         }
1033     }
1034
1035     /**
1036      * Builds a Flow to be programmed in a remote DPN's DMAC table. This flow
1037      * consists in: Match: + elanTag in packet's metadata + packet going to a
1038      * MAC known to be located in another DPN Actions: + set_tunnel_id(lportTag)
1039      * + output ITM internal tunnel interface with the other DPN
1040      *
1041      * @param srcDpId
1042      *            the src Dpn Id
1043      * @param destDpId
1044      *            dest Dp Id
1045      * @param lportTag
1046      *            lport Tag
1047      * @param elanTag
1048      *            elan Tag
1049      * @param macAddress
1050      *            macAddress
1051      * @param displayName
1052      *            display Name
1053      * @return the flow remote Dmac
1054      */
1055     public static Flow buildRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag,
1056             String macAddress, String displayName) {
1057         List<MatchInfo> mkMatches = new ArrayList<>();
1058         mkMatches.add(new MatchInfo(MatchFieldType.metadata,
1059                 new BigInteger[] { ElanUtils.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE }));
1060         mkMatches.add(new MatchInfo(MatchFieldType.eth_dst, new String[] { macAddress }));
1061
1062         List<Instruction> mkInstructions = new ArrayList<Instruction>();
1063
1064         // List of Action for the provided Source and Destination DPIDs
1065         try {
1066             List<Action> actions = getInternalTunnelItmEgressAction(srcDpId, destDpId, lportTag);
1067             mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
1068         } catch (Exception e) {
1069             LOG.error("Interface Not Found exception");
1070         }
1071
1072         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
1073                 getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, srcDpId, destDpId, macAddress, elanTag),
1074                 20, /* prio */
1075                 displayName, 0, /* idleTimeout */
1076                 0, /* hardTimeout */
1077                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
1078
1079         return flow;
1080
1081     }
1082
1083     public static void deleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, MacEntry macEntry,
1084             WriteTransaction deleteFlowGroupTx) {
1085         if (elanInfo == null || interfaceInfo == null) {
1086             return;
1087         }
1088         String macAddress = macEntry.getMacAddress().getValue();
1089         synchronized (macAddress) {
1090             LOG.info("Acquired lock for mac : " + macAddress + "Proceeding with remove operation.");
1091             deleteMacFlows(elanInfo, interfaceInfo, macAddress, /* alsoDeleteSMAC */ true, deleteFlowGroupTx);
1092         }
1093     }
1094
1095     public static void deleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
1096             boolean deleteSmac, WriteTransaction deleteFlowGroupTx) {
1097         String elanInstanceName = elanInfo.getElanInstanceName();
1098         List<DpnInterfaces> remoteFEs = getInvolvedDpnsInElan(elanInstanceName);
1099         BigInteger srcdpId = interfaceInfo.getDpId();
1100         boolean isFlowsRemovedInSrcDpn = false;
1101         for (DpnInterfaces dpnInterface : remoteFEs) {
1102             Long elanTag = elanInfo.getElanTag();
1103             BigInteger dstDpId = dpnInterface.getDpId();
1104             if (executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId, elanTag,
1105                     dstDpId, deleteFlowGroupTx)) {
1106                 isFlowsRemovedInSrcDpn = true;
1107             }
1108             executeEtreeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId, elanTag,
1109                     dstDpId, deleteFlowGroupTx);
1110         }
1111         if (!isFlowsRemovedInSrcDpn) {
1112             deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, deleteFlowGroupTx);
1113         }
1114     }
1115
1116     private static void executeEtreeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, boolean deleteSmac,
1117             String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId,
1118             WriteTransaction deleteFlowGroupTx) {
1119         EtreeLeafTagName etreeLeafTag = ElanUtils.getEtreeLeafTagByElanTag(elanTag);
1120         if (etreeLeafTag != null) {
1121             executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
1122                     etreeLeafTag.getEtreeLeafTag().getValue(), dstDpId, deleteFlowGroupTx);
1123         }
1124     }
1125
1126     private static boolean executeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, boolean deleteSmac,
1127             String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId,
1128             WriteTransaction deleteFlowGroupTx) {
1129         boolean isFlowsRemovedInSrcDpn = false;
1130         if (dstDpId.equals(srcdpId)) {
1131             isFlowsRemovedInSrcDpn = true;
1132             deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, deleteFlowGroupTx);
1133         } else if (isDpnPresent(dstDpId)) {
1134             elanServiceProvider.getMdsalManager()
1135                     .removeFlowToTx(dstDpId,
1136                             MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, getKnownDynamicmacFlowRef(
1137                                     NwConstants.ELAN_DMAC_TABLE, dstDpId, srcdpId, macAddress, elanTag)),
1138                             deleteFlowGroupTx);
1139             if (LOG.isDebugEnabled()) {
1140                 LOG.debug("Dmac flow entry deleted for elan:{}, logical interface port:{} and mac address:{} on dpn:{}",
1141                         elanInstanceName, interfaceInfo.getPortName(), macAddress, dstDpId);
1142             }
1143         }
1144         return isFlowsRemovedInSrcDpn;
1145     }
1146
1147     private static void deleteSmacAndDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
1148             boolean deleteSmac, WriteTransaction deleteFlowGroupTx) {
1149         String elanInstanceName = elanInfo.getElanInstanceName();
1150         long ifTag = interfaceInfo.getInterfaceTag();
1151         BigInteger srcdpId = interfaceInfo.getDpId();
1152         Long elanTag = elanInfo.getElanTag();
1153         if (deleteSmac) {
1154             elanServiceProvider.getMdsalManager()
1155                     .removeFlowToTx(srcdpId,
1156                             MDSALUtil.buildFlow(NwConstants.ELAN_SMAC_TABLE, getKnownDynamicmacFlowRef(
1157                                     NwConstants.ELAN_SMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)),
1158                             deleteFlowGroupTx);
1159         }
1160         elanServiceProvider.getMdsalManager().removeFlowToTx(srcdpId,
1161                 MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
1162                         getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)),
1163                 deleteFlowGroupTx);
1164         if (LOG.isDebugEnabled()) {
1165             LOG.debug(
1166                     "All the required flows deleted for elan:{}, logical Interface port:{} and mac address:{} on dpn:{}",
1167                     elanInstanceName, interfaceInfo.getPortName(), macAddress, srcdpId);
1168         }
1169     }
1170
1171     /**
1172      * Updates the Elan information in the Operational DS. It also updates the
1173      * ElanInstance in the Config DS by setting the adquired elanTag.
1174      *
1175      * @param broker
1176      *            the broker
1177      * @param idManager
1178      *            the id manager
1179      * @param elanInstanceAdded
1180      *            the elan instance added
1181      * @param tx
1182      *            transaction
1183      */
1184     public static void updateOperationalDataStore(DataBroker broker, IdManagerService idManager,
1185             ElanInstance elanInstanceAdded, List<String> elanInterfaces, WriteTransaction tx) {
1186         String elanInstanceName = elanInstanceAdded.getElanInstanceName();
1187         Long elanTag = elanInstanceAdded.getElanTag();
1188         if (elanTag == null || elanTag == 0L) {
1189             elanTag = ElanUtils.retrieveNewElanTag(idManager, elanInstanceName);
1190         }
1191         Elan elanInfo = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(elanInterfaces)
1192                 .setKey(new ElanKey(elanInstanceName)).build();
1193
1194         // Add the ElanState in the elan-state operational data-store
1195         tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName),
1196                 elanInfo, true);
1197
1198         // Add the ElanMacTable in the elan-mac-table operational data-store
1199         MacTable elanMacTable = new MacTableBuilder().setKey(new MacTableKey(elanInstanceName)).build();
1200         tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanInstanceName),
1201                 elanMacTable, true);
1202
1203         ElanTagNameBuilder elanTagNameBuilder = new ElanTagNameBuilder().setElanTag(elanTag)
1204                 .setKey(new ElanTagNameKey(elanTag)).setName(elanInstanceName);
1205         long etreeLeafTag = -1;
1206         if (isEtreeInstance(elanInstanceAdded)) {
1207             etreeLeafTag = ElanUtils.retrieveNewElanTag(idManager, elanInstanceName + ElanConstants.LEAVES_POSTFIX);
1208             EtreeLeafTagName etreeLeafTagName = new EtreeLeafTagNameBuilder()
1209                     .setEtreeLeafTag(new EtreeLeafTag(etreeLeafTag)).build();
1210             elanTagNameBuilder.addAugmentation(EtreeLeafTagName.class, etreeLeafTagName);
1211             addTheLeafTagAsElanTag(broker, elanInstanceName, etreeLeafTag, tx);
1212         }
1213         ElanTagName elanTagName = elanTagNameBuilder.build();
1214
1215         // Add the ElanTag to ElanName in the elan-tag-name Operational
1216         // data-store
1217         tx.put(LogicalDatastoreType.OPERATIONAL,
1218                 ElanUtils.getElanInfoEntriesOperationalDataPath(elanTag), elanTagName);
1219
1220         // Updates the ElanInstance Config DS by setting the just acquired
1221         // elanTag
1222         ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
1223                 .setDescription(elanInstanceAdded.getDescription())
1224                 .setMacTimeout(elanInstanceAdded.getMacTimeout() == null ? ElanConstants.DEFAULT_MAC_TIME_OUT
1225                         : elanInstanceAdded.getMacTimeout())
1226                 .setKey(elanInstanceAdded.getKey()).setElanTag(elanTag);
1227         if (isEtreeInstance(elanInstanceAdded)) {
1228             EtreeInstance etreeInstance = new EtreeInstanceBuilder().setEtreeLeafTagVal(new EtreeLeafTag(etreeLeafTag))
1229                     .build();
1230             elanInstanceBuilder.addAugmentation(EtreeInstance.class, etreeInstance);
1231         }
1232         ElanInstance elanInstanceWithTag = elanInstanceBuilder.build();
1233         tx.merge(LogicalDatastoreType.CONFIGURATION, getElanInstanceConfigurationDataPath(elanInstanceName),
1234                 elanInstanceWithTag, true);
1235     }
1236
1237     private static void addTheLeafTagAsElanTag(DataBroker broker, String elanInstanceName, long etreeLeafTag,
1238             WriteTransaction tx) {
1239         ElanTagName etreeTagAsElanTag = new ElanTagNameBuilder().setElanTag(etreeLeafTag)
1240                 .setKey(new ElanTagNameKey(etreeLeafTag)).setName(elanInstanceName).build();
1241         tx.put(LogicalDatastoreType.OPERATIONAL,
1242                 ElanUtils.getElanInfoEntriesOperationalDataPath(etreeLeafTag), etreeTagAsElanTag);
1243     }
1244
1245     private static boolean isEtreeInstance(ElanInstance elanInstanceAdded) {
1246         return elanInstanceAdded.getAugmentation(EtreeInstance.class) != null;
1247     }
1248
1249     public static boolean isDpnPresent(BigInteger dpnId) {
1250         String dpn = String.format("%s:%s", "openflow", dpnId);
1251         NodeId nodeId = new NodeId(dpn);
1252
1253         InstanceIdentifier<Node> node = InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(nodeId))
1254                 .build();
1255         Optional<Node> nodePresent = read(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, node);
1256         return (nodePresent.isPresent());
1257     }
1258
1259     public static ServicesInfo getServiceInfo(String elanInstanceName, long elanTag, String interfaceName) {
1260         int priority = ElanConstants.ELAN_SERVICE_PRIORITY;
1261         int instructionKey = 0;
1262         List<Instruction> instructions = new ArrayList<>();
1263         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanUtils.getElanMetadataLabel(elanTag),
1264                 MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1265         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ELAN_SMAC_TABLE, ++instructionKey));
1266
1267         short serviceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
1268         ServicesInfo serviceInfo = InterfaceServiceUtil.buildServiceInfo(
1269                 String.format("%s.%s", elanInstanceName, interfaceName), serviceIndex, priority,
1270                 NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1271         return serviceInfo;
1272     }
1273
1274     public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
1275             InstanceIdentifier<T> path, FutureCallback<Void> callback) {
1276         WriteTransaction tx = broker.newWriteOnlyTransaction();
1277         tx.delete(datastoreType, path);
1278         Futures.addCallback(tx.submit(), callback);
1279     }
1280
1281     public static <T extends DataObject> void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
1282             InstanceIdentifier<T> path, T data) {
1283         WriteTransaction tx = broker.newWriteOnlyTransaction();
1284         tx.put(datastoreType, path, data, true);
1285         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
1286         try {
1287             futures.get();
1288         } catch (InterruptedException | ExecutionException e) {
1289             LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data);
1290             throw new RuntimeException(e.getMessage());
1291         }
1292     }
1293
1294     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
1295             BigInteger cookie, List<Instruction> instructions) {
1296         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
1297                 .setInstruction(instructions);
1298         return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
1299                 .setServicePriority(servicePriority).setServiceType(ServiceTypeFlowBased.class)
1300                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
1301     }
1302
1303     public static InstanceIdentifier<BoundServices> buildServiceId(String vpnInterfaceName, short serviceIndex) {
1304         return InstanceIdentifier.builder(ServiceBindings.class)
1305                 .child(ServicesInfo.class, new ServicesInfoKey(vpnInterfaceName, ServiceModeIngress.class))
1306                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
1307     }
1308
1309     /**
1310      * Builds the list of actions to be taken when sending the packet over a
1311      * VxLan Tunnel Interface, such as setting the tunnel_id field, the vlanId
1312      * if proceeds and output the packet over the right port.
1313      *
1314      * @param tunnelIfaceName
1315      *            the tunnel iface name
1316      * @param tunnelKey
1317      *            the tunnel key
1318      * @return the list
1319      */
1320     public static List<Action> buildTunnelItmEgressActions(String tunnelIfaceName, Long tunnelKey) {
1321         if (tunnelIfaceName != null && !tunnelIfaceName.isEmpty()) {
1322             return buildItmEgressActions(tunnelIfaceName, tunnelKey);
1323         }
1324
1325         return Collections.emptyList();
1326     }
1327
1328     /**
1329      * Builds the list of actions to be taken when sending the packet over
1330      * external port such as tunnel, physical port etc.
1331      *
1332      * @param interfaceName
1333      *            the interface name
1334      * @param tunnelKey
1335      *            can be VNI for VxLAN tunnel interfaces, Gre Key for GRE
1336      *            tunnels, etc.
1337      * @return the list
1338      */
1339     public static List<Action> buildItmEgressActions(String interfaceName, Long tunnelKey) {
1340         List<Action> result = Collections.emptyList();
1341         GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
1342                 .setIntfName(interfaceName).setTunnelKey(tunnelKey).build();
1343
1344         Future<RpcResult<GetEgressActionsForInterfaceOutput>> egressActionsOutputFuture = elanServiceProvider
1345                 .getInterfaceManagerRpcService().getEgressActionsForInterface(getEgressActInput);
1346         try {
1347             if (egressActionsOutputFuture.get().isSuccessful()) {
1348                 GetEgressActionsForInterfaceOutput egressActionsOutput = egressActionsOutputFuture.get().getResult();
1349                 result = egressActionsOutput.getAction();
1350             }
1351         } catch (InterruptedException | ExecutionException e) {
1352             LOG.error("Error in RPC call getEgressActionsForInterface {}", e);
1353         }
1354
1355         if (result == null || result.size() == 0) {
1356             LOG.warn("Could not build Egress actions for interface {} and tunnelId {}", interfaceName, tunnelKey);
1357         }
1358         return result;
1359     }
1360
1361     /**
1362      * Builds the list of actions to be taken when sending the packet over an
1363      * external VxLan tunnel interface, such as stamping the VNI on the VxLAN
1364      * header, setting the vlanId if it proceeds and output the packet over the
1365      * right port.
1366      *
1367      * @param srcDpnId
1368      *            Dpn where the tunnelInterface is located
1369      * @param torNode
1370      *            NodeId of the ExternalDevice where the packet must be sent to.
1371      * @param vni
1372      *            Vni to be stamped on the VxLAN Header.
1373      * @return the external itm egress action
1374      */
1375     public static List<Action> getExternalTunnelItmEgressAction(BigInteger srcDpnId, NodeId torNode, long vni) {
1376         List<Action> result = Collections.emptyList();
1377
1378         GetExternalTunnelInterfaceNameInput input = new GetExternalTunnelInterfaceNameInputBuilder()
1379                 .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString())
1380                 .setTunnelType(TunnelTypeVxlan.class).build();
1381         Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = elanServiceProvider.getItmRpcService()
1382                 .getExternalTunnelInterfaceName(input);
1383         try {
1384             if (output.get().isSuccessful()) {
1385                 GetExternalTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult();
1386                 String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName();
1387                 if (LOG.isDebugEnabled())
1388                     LOG.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName);
1389
1390                 result = buildTunnelItmEgressActions(tunnelIfaceName, vni);
1391             }
1392
1393         } catch (InterruptedException | ExecutionException e) {
1394             LOG.error("Error in RPC call getTunnelInterfaceName {}", e);
1395         }
1396
1397         return result;
1398     }
1399
1400     /**
1401      * Builds the list of actions to be taken when sending the packet over an
1402      * internal VxLan tunnel interface, such as setting the serviceTag on the
1403      * VNI field of the VxLAN header, setting the vlanId if it proceeds and
1404      * output the packet over the right port.
1405      *
1406      * @param sourceDpnId
1407      *            Dpn where the tunnelInterface is located
1408      * @param destinationDpnId
1409      *            Dpn where the packet must be sent to. It is used here in order
1410      *            to select the right tunnel interface.
1411      * @param serviceTag
1412      *            serviceId to be sent on the VxLAN header.
1413      * @return the internal itm egress action
1414      */
1415     public static List<Action> getInternalTunnelItmEgressAction(BigInteger sourceDpnId, BigInteger destinationDpnId,
1416             long serviceTag) {
1417         List<Action> result = Collections.emptyList();
1418
1419         LOG.debug("In getInternalItmEgressAction Action source {}, destination {}, elanTag {}", sourceDpnId,
1420                 destinationDpnId, serviceTag);
1421         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
1422         GetTunnelInterfaceNameInput input = new GetTunnelInterfaceNameInputBuilder()
1423                 .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).setTunnelType(tunType).build();
1424         Future<RpcResult<GetTunnelInterfaceNameOutput>> output = elanServiceProvider.getItmRpcService()
1425                 .getTunnelInterfaceName(input);
1426         try {
1427             if (output.get().isSuccessful()) {
1428                 GetTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult();
1429                 String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName();
1430                 LOG.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName);
1431
1432                 result = buildTunnelItmEgressActions(tunnelIfaceName, serviceTag);
1433             }
1434         } catch (InterruptedException | ExecutionException e) {
1435             LOG.error("Error in RPC call getTunnelInterfaceName {}", e);
1436         }
1437
1438         return result;
1439     }
1440
1441     /**
1442      * Build the list of actions to be taken when sending the packet to external
1443      * (physical) port
1444      *
1445      * @param interfaceName
1446      *            Interface name
1447      * @return the external port itm egress actions
1448      */
1449     public static List<Action> getExternalPortItmEgressAction(String interfaceName) {
1450         return buildItmEgressActions(interfaceName, null);
1451     }
1452
1453     public static List<MatchInfo> getTunnelMatchesForServiceId(int elanTag) {
1454         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
1455         // Matching metadata
1456         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] { BigInteger.valueOf(elanTag) }));
1457
1458         return mkMatches;
1459     }
1460
1461     public static void removeTerminatingServiceAction(BigInteger destDpId, int serviceId) {
1462         RemoveTerminatingServiceActionsInput input = new RemoveTerminatingServiceActionsInputBuilder()
1463                 .setDpnId(destDpId).setServiceId(serviceId).build();
1464         Future<RpcResult<Void>> futureObject = elanServiceProvider.getItmRpcService()
1465                 .removeTerminatingServiceActions(input);
1466         try {
1467             RpcResult<Void> result = futureObject.get();
1468             if (result.isSuccessful()) {
1469                 LOG.debug("Successfully completed removeTerminatingServiceActions");
1470             } else {
1471                 LOG.debug("Failure in removeTerminatingServiceAction RPC call");
1472             }
1473         } catch (InterruptedException | ExecutionException e) {
1474             LOG.error("Error in RPC call removeTerminatingServiceActions {}", e);
1475         }
1476     }
1477
1478     public static void createTerminatingServiceActions(BigInteger destDpId, int serviceId, List<Action> actions) {
1479         List<Instruction> mkInstructions = new ArrayList<Instruction>();
1480         mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
1481         CreateTerminatingServiceActionsInput input = new CreateTerminatingServiceActionsInputBuilder()
1482                 .setDpnId(destDpId).setServiceId(serviceId).setInstruction(mkInstructions).build();
1483
1484         elanServiceProvider.getItmRpcService().createTerminatingServiceActions(input);
1485     }
1486
1487     public static TunnelList buildInternalTunnel(DataBroker broker) {
1488         InstanceIdentifier<TunnelList> tunnelListInstanceIdentifier = InstanceIdentifier.builder(TunnelList.class)
1489                 .build();
1490         Optional<TunnelList> tunnelList = read(broker, LogicalDatastoreType.CONFIGURATION,
1491                 tunnelListInstanceIdentifier);
1492         if (tunnelList.isPresent()) {
1493             return tunnelList.get();
1494         }
1495         return null;
1496     }
1497
1498     /**
1499      * Gets the external tunnel.
1500      *
1501      * @param sourceDevice
1502      *            the source device
1503      * @param destinationDevice
1504      *            the destination device
1505      * @param datastoreType
1506      *            the datastore type
1507      * @return the external tunnel
1508      */
1509     public static ExternalTunnel getExternalTunnel(String sourceDevice, String destinationDevice,
1510             LogicalDatastoreType datastoreType) {
1511         ExternalTunnel externalTunnel = null;
1512         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
1513         InstanceIdentifier<ExternalTunnel> iid = InstanceIdentifier.builder(ExternalTunnelList.class)
1514                 .child(ExternalTunnel.class, new ExternalTunnelKey(destinationDevice, sourceDevice, tunType)).build();
1515         Optional<ExternalTunnel> tunnelList = read(elanServiceProvider.getBroker(), datastoreType, iid);
1516         if (tunnelList.isPresent()) {
1517             externalTunnel = tunnelList.get();
1518         }
1519         return externalTunnel;
1520     }
1521
1522     /**
1523      * Gets the external tunnel.
1524      *
1525      * @param interfaceName
1526      *            the interface name
1527      * @param datastoreType
1528      *            the datastore type
1529      * @return the external tunnel
1530      */
1531     public static ExternalTunnel getExternalTunnel(String interfaceName, LogicalDatastoreType datastoreType) {
1532         ExternalTunnel externalTunnel = null;
1533         List<ExternalTunnel> externalTunnels = getAllExternalTunnels(datastoreType);
1534         for (ExternalTunnel tunnel : externalTunnels) {
1535             if (StringUtils.equalsIgnoreCase(interfaceName, tunnel.getTunnelInterfaceName())) {
1536                 externalTunnel = tunnel;
1537                 break;
1538             }
1539         }
1540         return externalTunnel;
1541     }
1542
1543     /**
1544      * Gets the all external tunnels.
1545      *
1546      * @param datastoreType
1547      *            the data store type
1548      * @return the all external tunnels
1549      */
1550     public static List<ExternalTunnel> getAllExternalTunnels(LogicalDatastoreType datastoreType) {
1551         List<ExternalTunnel> result = null;
1552         InstanceIdentifier<ExternalTunnelList> iid = InstanceIdentifier.builder(ExternalTunnelList.class).build();
1553         Optional<ExternalTunnelList> tunnelList = read(elanServiceProvider.getBroker(), datastoreType, iid);
1554         if (tunnelList.isPresent()) {
1555             result = tunnelList.get().getExternalTunnel();
1556         }
1557         if (result == null) {
1558             result = Collections.emptyList();
1559         }
1560         return result;
1561     }
1562
1563     /**
1564      * Installs a Flow in a DPN's DMAC table. The Flow is for a MAC that is
1565      * connected remotely in another CSS and accessible through an internal
1566      * tunnel. It also installs the flow for dropping the packet if it came over
1567      * an ITM tunnel (that is, if the Split-Horizon flag is set)
1568      *
1569      * @param localDpId
1570      *            Id of the DPN where the MAC Addr is accessible locally
1571      * @param remoteDpId
1572      *            Id of the DPN where the flow must be installed
1573      * @param lportTag
1574      *            lportTag of the interface where the mac is connected to.
1575      * @param elanTag
1576      *            Identifier of the ELAN
1577      * @param macAddress
1578      *            MAC to be installed in remoteDpId's DMAC table
1579      * @param displayName
1580      *            the display name
1581      */
1582     public static void installDmacFlowsToInternalRemoteMac(BigInteger localDpId, BigInteger remoteDpId, long lportTag,
1583             long elanTag, String macAddress, String displayName) {
1584         Flow flow = buildDmacFlowForInternalRemoteMac(localDpId, remoteDpId, lportTag, elanTag, macAddress,
1585                 displayName);
1586         elanServiceProvider.getMdsalManager().installFlow(remoteDpId, flow);
1587     }
1588
1589     /**
1590      * Installs a Flow in the specified DPN's DMAC table. The flow is for a MAC
1591      * that is connected remotely in an External Device (TOR) and that is
1592      * accessible through an external tunnel. It also installs the flow for
1593      * dropping the packet if it came over an ITM tunnel (that is, if the
1594      * Split-Horizon flag is set)
1595      *
1596      * @param dpnId
1597      *            Id of the DPN where the flow must be installed
1598      * @param extDeviceNodeId
1599      *            the ext device node id
1600      * @param elanTag
1601      *            the elan tag
1602      * @param vni
1603      *            the vni
1604      * @param macAddress
1605      *            the mac address
1606      * @param displayName
1607      *            the display name
1608      *
1609      * @return the dmac flows
1610      */
1611     public static List<ListenableFuture<Void>> installDmacFlowsToExternalRemoteMac(BigInteger dpnId,
1612             String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName,
1613             String interfaceName) {
1614         List<ListenableFuture<Void>> futures = new ArrayList<>();
1615         synchronized (macAddress) {
1616             Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress,
1617                     displayName);
1618             futures.add(elanServiceProvider.getMdsalManager().installFlow(dpnId, flow));
1619
1620             Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress);
1621             futures.add(elanServiceProvider.getMdsalManager().installFlow(dpnId, dropFlow));
1622             installEtreeDmacFlowsToExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress, displayName,
1623                     interfaceName, futures);
1624         }
1625         return futures;
1626     }
1627
1628     private static void installEtreeDmacFlowsToExternalRemoteMac(BigInteger dpnId, String extDeviceNodeId, Long elanTag,
1629             Long vni, String macAddress, String displayName, String interfaceName,
1630             List<ListenableFuture<Void>> futures) {
1631         EtreeLeafTagName etreeLeafTag = ElanUtils.getEtreeLeafTagByElanTag(elanTag);
1632         if (etreeLeafTag != null) {
1633             buildEtreeDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress, futures,
1634                     etreeLeafTag);
1635             buildEtreeDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, vni, macAddress, displayName, interfaceName,
1636                     futures, etreeLeafTag);
1637         }
1638     }
1639
1640     private static void buildEtreeDmacFlowForExternalRemoteMac(BigInteger dpnId, String extDeviceNodeId, Long vni,
1641             String macAddress, String displayName, String interfaceName, List<ListenableFuture<Void>> futures,
1642             EtreeLeafTagName etreeLeafTag) {
1643         boolean isRoot = false;
1644         if (interfaceName == null) {
1645             isRoot = true;
1646         } else {
1647             EtreeInterface etreeInterface = ElanUtils.getEtreeInterfaceByElanInterfaceName(interfaceName);
1648             if (etreeInterface != null) {
1649                 if (etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
1650                     isRoot = true;
1651                 }
1652             }
1653         }
1654         if (isRoot) {
1655             Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId,
1656                     etreeLeafTag.getEtreeLeafTag().getValue(), vni, macAddress, displayName);
1657             futures.add(elanServiceProvider.getMdsalManager().installFlow(dpnId, flow));
1658         }
1659     }
1660
1661     private static void buildEtreeDmacFlowDropIfPacketComingFromTunnel(BigInteger dpnId, String extDeviceNodeId,
1662             Long elanTag, String macAddress, List<ListenableFuture<Void>> futures, EtreeLeafTagName etreeLeafTag) {
1663         if (etreeLeafTag != null) {
1664             Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId,
1665                     etreeLeafTag.getEtreeLeafTag().getValue(), macAddress);
1666             futures.add(elanServiceProvider.getMdsalManager().installFlow(dpnId, dropFlow));
1667         }
1668     }
1669
1670     public static List<MatchInfo> buildMatchesForElanTagShFlagAndDstMac(long elanTag, boolean shFlag, String macAddr) {
1671         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
1672         mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
1673                 ElanUtils.getElanMetadataLabel(elanTag, shFlag), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG }));
1674         mkMatches.add(new MatchInfo(MatchFieldType.eth_dst, new String[] { macAddr }));
1675
1676         return mkMatches;
1677     }
1678
1679     /**
1680      * Builds a Flow to be programmed in a DPN's DMAC table. This method must be
1681      * used when the MAC is located in an External Device (TOR). The flow
1682      * matches on the specified MAC and 1) sends the packet over the CSS-TOR
1683      * tunnel if SHFlag is not set, or 2) drops it if SHFlag is set (what means
1684      * the packet came from an external tunnel)
1685      *
1686      * @param dpId
1687      *            DPN whose DMAC table is going to be modified
1688      * @param extDeviceNodeId
1689      *            Hwvtep node where the mac is attached to
1690      * @param elanTag
1691      *            ElanId to which the MAC is being added to
1692      * @param vni
1693      *            the vni
1694      * @param dstMacAddress
1695      *            The mac address to be programmed
1696      * @param displayName
1697      *            the display name
1698      * @return the flow
1699      */
1700     public static Flow buildDmacFlowForExternalRemoteMac(BigInteger dpId, String extDeviceNodeId, long elanTag,
1701             Long vni, String dstMacAddress, String displayName) {
1702         List<MatchInfo> mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ false, dstMacAddress);
1703         List<Instruction> mkInstructions = new ArrayList<>();
1704         try {
1705             List<Action> actions = getExternalTunnelItmEgressAction(dpId, new NodeId(extDeviceNodeId), vni);
1706             mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
1707         } catch (Exception e) {
1708             LOG.error("Could not get Egress Actions for DpId={}  externalNode={}", dpId, extDeviceNodeId);
1709         }
1710
1711         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
1712                 getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, dstMacAddress, elanTag,
1713                         false),
1714                 20, /* prio */
1715                 displayName, 0, /* idleTimeout */
1716                 0, /* hardTimeout */
1717                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
1718
1719         return flow;
1720     }
1721
1722     /**
1723      * Builds the flow that drops the packet if it came through an external
1724      * tunnel, that is, if the Split-Horizon flag is set.
1725      *
1726      * @param dpnId
1727      *            DPN whose DMAC table is going to be modified
1728      * @param extDeviceNodeId
1729      *            Hwvtep node where the mac is attached to
1730      * @param elanTag
1731      *            ElanId to which the MAC is being added to
1732      * @param dstMacAddress
1733      *            The mac address to be programmed
1734      * @param displayName
1735      * @return
1736      */
1737     private static Flow buildDmacFlowDropIfPacketComingFromTunnel(BigInteger dpnId, String extDeviceNodeId,
1738             Long elanTag, String dstMacAddress) {
1739         List<MatchInfo> mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ true, dstMacAddress);
1740         List<Instruction> mkInstructions = MDSALUtil.buildInstructionsDrop();
1741         String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpnId, extDeviceNodeId, dstMacAddress,
1742                 elanTag, true);
1743         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE, flowId, 20, /* prio */
1744                 "Drop", 0, /* idleTimeout */
1745                 0, /* hardTimeout */
1746                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
1747
1748         return flow;
1749     }
1750
1751     private static String getDmacDropFlowId(Long elanTag, String dstMacAddress) {
1752         return new StringBuilder(NwConstants.ELAN_DMAC_TABLE).append(elanTag).append(dstMacAddress).append("Drop")
1753                 .toString();
1754     }
1755
1756     /**
1757      * Builds a Flow to be programmed in a remote DPN's DMAC table. This method
1758      * must be used when the MAC is located in another CSS.
1759      *
1760      * This flow consists in: Match: + elanTag in packet's metadata + packet
1761      * going to a MAC known to be located in another DPN Actions: +
1762      * set_tunnel_id(lportTag) + output on ITM internal tunnel interface with
1763      * the other DPN
1764      *
1765      * @param localDpId
1766      *            the local dp id
1767      * @param remoteDpId
1768      *            the remote dp id
1769      * @param lportTag
1770      *            the lport tag
1771      * @param elanTag
1772      *            the elan tag
1773      * @param macAddress
1774      *            the mac address
1775      * @param displayName
1776      *            the display name
1777      * @return the flow
1778      */
1779     public static Flow buildDmacFlowForInternalRemoteMac(BigInteger localDpId, BigInteger remoteDpId, long lportTag,
1780             long elanTag, String macAddress, String displayName) {
1781         List<MatchInfo> mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /* shFlag */ false, macAddress);
1782
1783         List<Instruction> mkInstructions = new ArrayList<Instruction>();
1784
1785         try {
1786             // List of Action for the provided Source and Destination DPIDs
1787             List<Action> actions = getInternalTunnelItmEgressAction(localDpId, remoteDpId, lportTag);
1788             mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
1789         } catch (Exception e) {
1790             LOG.error("Could not get Egress Actions for localDpId={}  remoteDpId={}   lportTag={}", localDpId,
1791                     remoteDpId, lportTag);
1792         }
1793
1794         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
1795                 getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, localDpId, remoteDpId, macAddress, elanTag),
1796                 20, /* prio */
1797                 displayName, 0, /* idleTimeout */
1798                 0, /* hardTimeout */
1799                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
1800
1801         return flow;
1802
1803     }
1804
1805     /**
1806      * Installs or removes flows in DMAC table for MACs that are/were located in
1807      * an external Elan Device.
1808      *
1809      * @param dpId
1810      *            Id of the DPN where the DMAC table is going to be modified
1811      * @param extNodeId
1812      *            Id of the External Device where the MAC is located
1813      * @param elanTag
1814      *            Id of the ELAN
1815      * @param vni
1816      *            VNI of the LogicalSwitch to which the MAC belongs to, and that
1817      *            is associated with the ELAN
1818      * @param macAddress
1819      *            the mac address
1820      * @param elanInstanceName
1821      *            the elan instance name
1822      * @param addOrRemove
1823      *            Indicates if flows must be installed or removed.
1824      * @see org.opendaylight.genius.mdsalutil.MDSALUtil.MdsalOp
1825      */
1826     public static void setupDmacFlowsToExternalRemoteMac(BigInteger dpId, String extNodeId, Long elanTag, Long vni,
1827             String macAddress, String elanInstanceName, MdsalOp addOrRemove, String interfaceName) {
1828         if (addOrRemove == MdsalOp.CREATION_OP) {
1829             ElanUtils.installDmacFlowsToExternalRemoteMac(dpId, extNodeId, elanTag, vni, macAddress, elanInstanceName,
1830                     interfaceName);
1831         } else if (addOrRemove == MdsalOp.REMOVAL_OP) {
1832             ElanUtils.deleteDmacFlowsToExternalMac(elanTag, dpId, extNodeId, macAddress);
1833         }
1834     }
1835
1836     /**
1837      * Delete dmac flows to external mac.
1838      *
1839      * @param elanTag
1840      *            the elan tag
1841      * @param dpId
1842      *            the dp id
1843      * @param extDeviceNodeId
1844      *            the ext device node id
1845      * @param macToRemove
1846      *            the mac to remove
1847      * @return dmac flow
1848      */
1849     public static List<ListenableFuture<Void>> deleteDmacFlowsToExternalMac(long elanTag, BigInteger dpId,
1850             String extDeviceNodeId, String macToRemove) {
1851         List<ListenableFuture<Void>> futures = new ArrayList<>();
1852         synchronized (macToRemove) {
1853             // Removing the flows that sends the packet on an external tunnel
1854             removeFlowThatSendsThePacketOnAnExternalTunnel(elanTag, dpId, extDeviceNodeId, macToRemove, futures);
1855
1856             // And now removing the drop flow
1857             removeTheDropFlow(elanTag, dpId, extDeviceNodeId, macToRemove, futures);
1858
1859             deleteEtreeDmacFlowsToExternalMac(elanTag, dpId, extDeviceNodeId, macToRemove, futures);
1860         }
1861         return futures;
1862     }
1863
1864     private static void deleteEtreeDmacFlowsToExternalMac(long elanTag, BigInteger dpId, String extDeviceNodeId,
1865             String macToRemove, List<ListenableFuture<Void>> futures) {
1866         EtreeLeafTagName etreeLeafTag = ElanUtils.getEtreeLeafTagByElanTag(elanTag);
1867         if (etreeLeafTag != null) {
1868             removeFlowThatSendsThePacketOnAnExternalTunnel(etreeLeafTag.getEtreeLeafTag().getValue(), dpId,
1869                     extDeviceNodeId, macToRemove, futures);
1870             removeTheDropFlow(etreeLeafTag.getEtreeLeafTag().getValue(), dpId, extDeviceNodeId, macToRemove, futures);
1871         }
1872     }
1873
1874     private static void removeTheDropFlow(long elanTag, BigInteger dpId, String extDeviceNodeId, String macToRemove,
1875             List<ListenableFuture<Void>> futures) {
1876         String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
1877                 elanTag, true);
1878         Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build();
1879         futures.add(elanServiceProvider.getMdsalManager().removeFlow(dpId, flowToRemove));
1880     }
1881
1882     private static void removeFlowThatSendsThePacketOnAnExternalTunnel(long elanTag, BigInteger dpId,
1883             String extDeviceNodeId, String macToRemove, List<ListenableFuture<Void>> futures) {
1884         String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
1885                 elanTag, false);
1886         Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(NwConstants.ELAN_DMAC_TABLE).build();
1887         futures.add(elanServiceProvider.getMdsalManager().removeFlow(dpId, flowToRemove));
1888     }
1889
1890     /**
1891      * Gets the dpid from interface.
1892      *
1893      * @param interfaceName
1894      *            the interface name
1895      * @return the dpid from interface
1896      */
1897     public static BigInteger getDpidFromInterface(String interfaceName) {
1898         BigInteger dpId = null;
1899         Future<RpcResult<GetDpidFromInterfaceOutput>> output = elanServiceProvider.getInterfaceManagerRpcService()
1900                 .getDpidFromInterface(new GetDpidFromInterfaceInputBuilder().setIntfName(interfaceName).build());
1901         try {
1902             RpcResult<GetDpidFromInterfaceOutput> rpcResult = output.get();
1903             if (rpcResult.isSuccessful()) {
1904                 dpId = rpcResult.getResult().getDpid();
1905             }
1906         } catch (NullPointerException | InterruptedException | ExecutionException e) {
1907             LOG.error("Failed to get the DPN ID: {} for interface {}: {} ", dpId, interfaceName, e);
1908         }
1909         return dpId;
1910     }
1911
1912     /**
1913      * Checks if is interface operational.
1914      *
1915      * @param interfaceName
1916      *            the interface name
1917      * @param dataBroker
1918      *            the data broker
1919      * @return true, if is interface operational
1920      */
1921     public static boolean isInterfaceOperational(String interfaceName, DataBroker dataBroker) {
1922         if (StringUtils.isBlank(interfaceName)) {
1923             return false;
1924         }
1925         Interface ifState = getInterfaceStateFromOperDS(interfaceName, dataBroker);
1926         if (ifState == null) {
1927             return false;
1928         }
1929         return ((ifState.getOperStatus() == OperStatus.Up) && (ifState.getAdminStatus() == AdminStatus.Up));
1930     }
1931
1932     /**
1933      * Gets the interface state from operational ds.
1934      *
1935      * @param interfaceName
1936      *            the interface name
1937      * @param dataBroker
1938      *            the data broker
1939      * @return the interface state from oper ds
1940      */
1941     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
1942             String interfaceName, DataBroker dataBroker) {
1943         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId = createInterfaceStateInstanceIdentifier(
1944                 interfaceName);
1945         Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateOptional = MDSALUtil
1946                 .read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId);
1947         if (ifStateOptional.isPresent()) {
1948             return ifStateOptional.get();
1949         }
1950         return null;
1951     }
1952
1953     /**
1954      * Gets the interface from config ds.
1955      *
1956      * @param interfaceName
1957      *            the interface name
1958      * @param dataBroker
1959      *            the data broker
1960      * @return the interface from config ds
1961      */
1962     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface getInterfaceFromConfigDS(
1963             String interfaceName, DataBroker dataBroker) {
1964         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface> ifaceId = createInterfaceInstanceIdentifier(
1965                 interfaceName);
1966         Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface> iface = MDSALUtil
1967                 .read(dataBroker, LogicalDatastoreType.CONFIGURATION, ifaceId);
1968         if (iface.isPresent()) {
1969             return iface.get();
1970         }
1971         return null;
1972     }
1973
1974     /**
1975      * Creates the interface state instance identifier.
1976      *
1977      * @param interfaceName
1978      *            the interface name
1979      * @return the instance identifier
1980      */
1981     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
1982             String interfaceName) {
1983         InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder = InstanceIdentifier
1984                 .builder(InterfacesState.class)
1985                 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
1986                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
1987                                 interfaceName));
1988         return idBuilder.build();
1989     }
1990
1991     /**
1992      * Creates the interface instance identifier.
1993      *
1994      * @param interfaceName
1995      *            the interface name
1996      * @return the instance identifier
1997      */
1998     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface> createInterfaceInstanceIdentifier(
1999             String interfaceName) {
2000         InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface> idBuilder = InstanceIdentifier
2001                 .builder(Interfaces.class)
2002                 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface.class,
2003                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey(
2004                                 interfaceName));
2005         return idBuilder.build();
2006     }
2007
2008     public static void waitForTransactionToComplete(WriteTransaction tx) {
2009         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
2010         try {
2011             futures.get();
2012         } catch (InterruptedException | ExecutionException e) {
2013             LOG.error("Error writing to datastore {}", e);
2014         }
2015     }
2016
2017     public static boolean isVxlan(ElanInstance elanInstance) {
2018         return elanInstance != null && elanInstance.getSegmentType() != null
2019                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
2020                 && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().longValue() != 0;
2021     }
2022
2023     public static boolean isVlan(ElanInstance elanInstance) {
2024         return elanInstance != null && elanInstance.getSegmentType() != null
2025                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVlan.class)
2026                 && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().longValue() != 0;
2027     }
2028
2029     public static boolean isFlat(ElanInstance elanInstance) {
2030         return elanInstance != null && elanInstance.getSegmentType() != null
2031                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeFlat.class);
2032     }
2033
2034     public static boolean isExternal(String interfaceName) {
2035         return isExternal(getInterfaceFromConfigDS(interfaceName, elanServiceProvider.getBroker()));
2036     }
2037
2038     public static boolean isExternal(
2039             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface) {
2040         if (iface == null) {
2041             return false;
2042         }
2043
2044         IfExternal ifExternal = iface.getAugmentation(IfExternal.class);
2045         return ifExternal != null && Boolean.TRUE.equals(ifExternal.isExternal());
2046     }
2047
2048     public static boolean isEtreeRootInterfaceByInterfaceName(String interfaceName) {
2049         EtreeInterface etreeInterface = getEtreeInterfaceByElanInterfaceName(interfaceName);
2050         if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
2051             return true;
2052         }
2053         return false;
2054     }
2055 }