Bump versions by 0.1.0 for next dev cycle
[vpnservice.git] / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / vpnservice / 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.vpnservice.elan.utils;
9
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.List;
14 import java.util.concurrent.ExecutionException;
15 import java.util.concurrent.Future;
16
17 import org.apache.commons.lang3.StringUtils;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
23 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
24 import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
25 import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
26 import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceServiceUtil;
27 import org.opendaylight.vpnservice.itm.globals.ITMConstants;
28 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
29 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
30 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
31 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
32 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil.MdsalOp;
33 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
34 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
35 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
36 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
37 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.ServiceBindings;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.ServiceTypeFlowBased;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.StypeOpenflow;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.StypeOpenflowBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfo;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.ServicesInfoKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServicesBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServicesKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanForwardingTables;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInstances;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInterfaceForwardingEntries;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInterfaces;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanState;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanTagNameMap;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.forwarding.tables.MacTable;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.forwarding.tables.MacTableBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.forwarding.tables.MacTableKey;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstanceBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstanceKey;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.interfaces.ElanInterface;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.interfaces.ElanInterfaceKey;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.state.Elan;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.state.ElanBuilder;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.state.ElanKey;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagName;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagNameBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagNameKey;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntry;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntryKey;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInputBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInput;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInputBuilder;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.IfIndexesInterfaceMap;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterface;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterfaceKey;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInput;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnelKey;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.CreateTerminatingServiceActionsInput;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.CreateTerminatingServiceActionsInputBuilder;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInput;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInputBuilder;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameOutput;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameInput;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameInputBuilder;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameOutput;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.RemoveTerminatingServiceActionsInput;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.RemoveTerminatingServiceActionsInputBuilder;
123 import org.opendaylight.yangtools.yang.binding.DataObject;
124 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
125 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
126 import org.opendaylight.yangtools.yang.common.RpcResult;
127 import org.slf4j.Logger;
128 import org.slf4j.LoggerFactory;
129
130 import com.google.common.base.Optional;
131 import com.google.common.util.concurrent.CheckedFuture;
132 import com.google.common.util.concurrent.FutureCallback;
133 import com.google.common.util.concurrent.Futures;
134 import com.google.common.util.concurrent.ListenableFuture;
135
136 public class ElanUtils {
137
138     private static OdlInterfaceRpcService interfaceMgrRpcService;
139
140     private static ItmRpcService itmRpcService;
141
142     private static IMdsalApiManager mdsalMgr;
143
144     private static DataBroker dataBroker;
145
146     private static final Logger logger = LoggerFactory.getLogger(ElanUtils.class);
147
148     public static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
149         @Override
150         public void onSuccess(Void result) {
151             logger.debug("Success in Datastore operation");
152         }
153
154         @Override
155         public void onFailure(Throwable error) {
156             logger.error("Error in Datastore operation", error);
157         }
158     };
159
160     /**
161      * Uses the IdManager to retrieve a brand new ElanTag.
162      *
163      * @param idManager
164      *            the id manager
165      * @param idKey
166      *            the id key
167      * @return the integer
168      */
169     public static Integer retrieveNewElanTag(IdManagerService idManager, String idKey) {
170
171         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME)
172                 .setIdKey(idKey).build();
173
174         try {
175             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
176             RpcResult<AllocateIdOutput> rpcResult = result.get();
177             if (rpcResult.isSuccessful()) {
178                 return rpcResult.getResult().getIdValue().intValue();
179             } else {
180                 logger.warn("RPC Call to Allocate Id returned with Errors {}", rpcResult.getErrors());
181             }
182         } catch (InterruptedException | ExecutionException e) {
183             logger.warn("Exception when Allocating Id",e);
184         }
185         return 0;
186     }
187
188     public static DataBroker getDataBroker() {
189         return dataBroker;
190     }
191
192     public final static void setIfaceMgrRpcService(OdlInterfaceRpcService rpcService) {
193         interfaceMgrRpcService = rpcService;
194     }
195
196     public final static void setItmRpcService(ItmRpcService itmService) {
197         itmRpcService = itmService;
198     }
199
200     public final static void setDataBroker(DataBroker broker) {
201         dataBroker = broker;
202     }
203
204     public final static void setMdsalManager(IMdsalApiManager mdsalApiManager) {
205         mdsalMgr = mdsalApiManager;
206     }
207
208     public static void releaseId(IdManagerService idManager, String poolName, String idKey) {
209         ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
210         Future<RpcResult<Void>> result = idManager.releaseId(releaseIdInput);
211     }
212
213     public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
214             InstanceIdentifier<T> path) {
215         ReadOnlyTransaction tx = (broker != null ) ? broker.newReadOnlyTransaction() : dataBroker.newReadOnlyTransaction();
216         Optional<T> result = Optional.absent();
217         try {
218             CheckedFuture<Optional<T>, ReadFailedException> checkedFuture = tx.read(datastoreType, path);
219             result = checkedFuture.get();
220         } catch (Exception e) {
221             throw new RuntimeException(e);
222         }
223
224         return result;
225     }
226
227
228     public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
229         WriteTransaction tx = broker.newWriteOnlyTransaction();
230         tx.delete(datastoreType, path);
231         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
232     }
233
234
235     public static InstanceIdentifier<ElanInstance> getElanInstanceIdentifier() {
236         return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class).build();
237     }
238
239     //elan-instances config container
240     public static ElanInstance getElanInstanceByName(String elanInstanceName) {
241         InstanceIdentifier<ElanInstance> elanIdentifierId = getElanInstanceConfigurationDataPath(elanInstanceName);
242         Optional<ElanInstance> elanInstance = read(dataBroker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId);
243         if(elanInstance.isPresent()) {
244             return elanInstance.get();
245         }
246         return null;
247     }
248
249     public static InstanceIdentifier<ElanInstance> getElanInstanceConfigurationDataPath(String elanInstanceName) {
250         return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
251     }
252
253     //elan-interfaces Config Container
254     public static ElanInterface getElanInterfaceByElanInterfaceName(String elanInterfaceName) {
255         InstanceIdentifier<ElanInterface> elanInterfaceId = getElanInterfaceConfigurationDataPathId(elanInterfaceName);
256         Optional<ElanInterface> existingElanInterface = read(dataBroker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId);
257         if(existingElanInterface.isPresent()) {
258             return existingElanInterface.get();
259         }
260         return null;
261     }
262
263     public static InstanceIdentifier<ElanInterface> getElanInterfaceConfigurationDataPathId(String interfaceName) {
264         return InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface.class,
265                 new ElanInterfaceKey(interfaceName)).build();
266     }
267
268     //elan-state Operational container
269     public static Elan getElanByName(String elanInstanceName) {
270         InstanceIdentifier<Elan> elanIdentifier = getElanInstanceOperationalDataPath(elanInstanceName);
271         Optional<Elan> elanInstance = read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanIdentifier);
272         if(elanInstance.isPresent()) {
273             return elanInstance.get();
274         }
275         return null;
276     }
277
278     public static InstanceIdentifier<Elan> getElanInstanceOperationalDataPath(String elanInstanceName) {
279         return InstanceIdentifier.builder(ElanState.class).child(Elan.class, new ElanKey(elanInstanceName)).build();
280     }
281
282     // grouping of forwarding-entries
283     public static MacEntry getInterfaceMacEntriesOperationalDataPath(String interfaceName, PhysAddress physAddress) {
284         InstanceIdentifier<MacEntry> existingMacEntryId = getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
285         Optional<MacEntry> existingInterfaceMacEntry = read(dataBroker, LogicalDatastoreType.OPERATIONAL, existingMacEntryId);
286         if(existingInterfaceMacEntry.isPresent()) {
287             return existingInterfaceMacEntry.get();
288         }
289         return null;
290     }
291
292     public static MacEntry getInterfaceMacEntriesOperationalDataPathFromId(InstanceIdentifier identifier) {
293         Optional<MacEntry> existingInterfaceMacEntry = read(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
294         if(existingInterfaceMacEntry.isPresent()) {
295             return existingInterfaceMacEntry.get();
296         }
297         return null;
298     }
299
300     public static InstanceIdentifier<MacEntry> getInterfaceMacEntriesIdentifierOperationalDataPath(String interfaceName, PhysAddress physAddress) {
301         return InstanceIdentifier.builder(ElanInterfaceForwardingEntries.class).child(ElanInterfaceMac.class,
302                 new ElanInterfaceMacKey(interfaceName)).child(MacEntry.class, new MacEntryKey(physAddress)).build();
303
304     }
305
306     //elan-forwarding-tables Operational container
307     public static MacEntry getMacTableByElanName(String elanName, PhysAddress physAddress) {
308         InstanceIdentifier<MacEntry> macId =  getMacEntryOperationalDataPath(elanName, physAddress);
309         Optional<MacEntry> existingElanMacEntry = read(dataBroker, LogicalDatastoreType.OPERATIONAL, macId);
310         if(existingElanMacEntry.isPresent()) {
311             return existingElanMacEntry.get();
312         }
313         return null;
314     }
315
316
317     public static MacEntry getMacEntryFromElanMacId(InstanceIdentifier identifier) {
318         Optional<MacEntry> existingInterfaceMacEntry = read(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
319         if(existingInterfaceMacEntry.isPresent()) {
320             return existingInterfaceMacEntry.get();
321         }
322         return null;
323     }
324
325     public static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
326         return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class,
327                 new MacTableKey(elanName)).child(MacEntry.class, new MacEntryKey(physAddress)).build();
328     }
329
330     public static InstanceIdentifier<MacTable> getElanMacTableOperationalDataPath(String elanName) {
331         return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class,
332                 new MacTableKey(elanName)).build();
333     }
334
335     //elan-interface-forwarding-entries Operational container
336     public static ElanInterfaceMac getElanInterfaceMacByInterfaceName(String interfaceName) {
337         InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
338         Optional<ElanInterfaceMac> existingElanInterface = read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
339         if(existingElanInterface.isPresent()) {
340             return existingElanInterface.get();
341         }
342         return null;
343     }
344
345     /**
346      * Gets the elan interface mac addresses.
347      *
348      * @param interfaceName
349      *            the interface name
350      * @return the elan interface mac addresses
351      */
352     public static List<PhysAddress> getElanInterfaceMacAddresses(String interfaceName) {
353         List<PhysAddress> macAddresses = new ArrayList<PhysAddress>();
354         ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
355         if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
356             List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
357             for (MacEntry macEntry : macEntries) {
358                 macAddresses.add(macEntry.getMacAddress());
359             }
360         }
361         return macAddresses;
362     }
363
364     public static InstanceIdentifier<ElanInterfaceMac> getElanInterfaceMacEntriesOperationalDataPath(String interfaceName) {
365         return InstanceIdentifier.builder(ElanInterfaceForwardingEntries.class).child(ElanInterfaceMac.class,
366                 new ElanInterfaceMacKey(interfaceName)).build();
367     }
368
369     /**
370      * Returns the list of Interfaces that belong to an Elan on an specific DPN.
371      * Data retrieved from Elan's operational DS: elan-dpn-interfaces container
372      *
373      * @param elanInstanceName
374      *          name of the Elan to which the interfaces must belong to
375      * @param dpId
376      *          Id of the DPN where the interfaces are located
377      * @return
378      */
379     public static DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId) {
380         InstanceIdentifier<DpnInterfaces> elanDpnInterfacesId =
381                 getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
382         Optional<DpnInterfaces> elanDpnInterfaces = read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfacesId);
383         if ( elanDpnInterfaces.isPresent() ) {
384             return elanDpnInterfaces.get();
385         }
386         return null;
387     }
388
389     /**
390      * Returns the InstanceIdentifier that points to the Interfaces of an Elan in a
391      * given DPN in the Operational DS.
392      * Data retrieved from Elans's operational DS: dpn-interfaces list
393      *
394      * @param elanInstanceName
395      *          name of the Elan to which the interfaces must belong to
396      * @param dpId
397      *          Id of the DPN where the interfaces are located
398      * @return
399      */
400     public static InstanceIdentifier<DpnInterfaces> getElanDpnInterfaceOperationalDataPath(String elanInstanceName,
401             BigInteger dpId) {
402         return InstanceIdentifier.builder(ElanDpnInterfaces.class)
403                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName))
404                 .child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build();
405     }
406
407     //elan-tag-name-map Operational Container
408     public static ElanTagName getElanInfoByElanTag(long elanTag) {
409         InstanceIdentifier<ElanTagName> elanId = getElanInfoEntriesOperationalDataPath(elanTag);
410         Optional<ElanTagName> existingElanInfo = ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanId);
411         if(existingElanInfo.isPresent()) {
412             return existingElanInfo.get();
413         }
414         return null;
415     }
416
417     public static InstanceIdentifier<ElanTagName> getElanInfoEntriesOperationalDataPath(long elanTag) {
418         return InstanceIdentifier.builder(ElanTagNameMap.class).child(ElanTagName.class,
419                 new ElanTagNameKey(elanTag)).build();
420     }
421
422     // interface-index-tag operational container
423     public static Optional<IfIndexInterface> getInterfaceInfoByInterfaceTag(long interfaceTag) {
424         InstanceIdentifier<IfIndexInterface> interfaceId = getInterfaceInfoEntriesOperationalDataPath(interfaceTag);
425         return ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, interfaceId);
426     }
427
428     public static InstanceIdentifier<IfIndexInterface> getInterfaceInfoEntriesOperationalDataPath(long interfaceTag) {
429         return InstanceIdentifier.builder(IfIndexesInterfaceMap.class).child(IfIndexInterface.class,
430                 new IfIndexInterfaceKey((int) interfaceTag)).build();
431     }
432
433
434
435     public static InstanceIdentifier<ElanDpnInterfacesList> getElanDpnOperationDataPath(String elanInstanceName) {
436         return InstanceIdentifier.builder(ElanDpnInterfaces.class).child(ElanDpnInterfacesList.class,
437                 new ElanDpnInterfacesListKey(elanInstanceName)).build();
438     }
439
440     public static  ElanDpnInterfacesList getElanDpnInterfacesList(String elanName) {
441         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanName);
442         Optional<ElanDpnInterfacesList> existingElanDpnInterfaces =
443                 ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
444         if(existingElanDpnInterfaces.isPresent()) {
445             return existingElanDpnInterfaces.get();
446         }
447         return null;
448     }
449
450     /**
451      * This method is useful get all ELAN participating CSS dpIds to install
452      * program remote dmac entries and updating remote bc groups for tor
453      * integration.
454      *
455      * @param elanInstanceName
456      *            the elan instance name
457      * @return list of dpIds
458      */
459     public static List<BigInteger> getParticipatingDPNsInElanInstance(String elanInstanceName) {
460         List<BigInteger> dpIds = new ArrayList<BigInteger>();
461         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
462         Optional<ElanDpnInterfacesList> existingElanDpnInterfaces =
463                 ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
464         if (!existingElanDpnInterfaces.isPresent()) {
465             return dpIds;
466         }
467         List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces();
468         for (DpnInterfaces dpnInterface: dpnInterfaces) {
469             dpIds.add(dpnInterface.getDpId());
470         }
471         return dpIds;
472     }
473
474     /**
475      * To check given dpId is already present in Elan instance. This can be used
476      * to program flow entry in external tunnel table when a new access port
477      * added for first time into the ELAN instance
478      *
479      * @param dpId
480      *            the dp id
481      * @param elanInstanceName
482      *            the elan instance name
483      * @return true if dpId is already present, otherwise return false
484      */
485     public static boolean isDpnAlreadyPresentInElanInstance(BigInteger dpId, String elanInstanceName) {
486         boolean isDpIdPresent = false;
487         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
488         Optional<ElanDpnInterfacesList> existingElanDpnInterfaces =
489                 ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
490         if (!existingElanDpnInterfaces.isPresent()) {
491             return isDpIdPresent;
492         }
493         List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces();
494         for (DpnInterfaces dpnInterface: dpnInterfaces) {
495             if (dpnInterface.getDpId().equals(dpId)) {
496                 isDpIdPresent = true;
497                 break;
498             }
499         }
500         return isDpIdPresent;
501     }
502
503     public static ElanDpnInterfaces getElanDpnInterfacesList() {
504         InstanceIdentifier<ElanDpnInterfaces> elanDpnInterfaceId =
505                 InstanceIdentifier.builder(ElanDpnInterfaces.class).build();
506         Optional<ElanDpnInterfaces> existingElanDpnInterfaces =
507                 ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
508         if(existingElanDpnInterfaces.isPresent()) {
509             return existingElanDpnInterfaces.get();
510         }
511         return null;
512     }
513
514     public static ElanForwardingTables getElanForwardingList() {
515         InstanceIdentifier<ElanForwardingTables> elanForwardingTableId =
516                 InstanceIdentifier.builder(ElanForwardingTables.class).build();
517         Optional<ElanForwardingTables> existingElanForwardingList =
518                 ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanForwardingTableId);
519         if(existingElanForwardingList.isPresent()) {
520             return existingElanForwardingList.get();
521         }
522         return null;
523     }
524
525     /**
526      * Gets the elan mac table.
527      *
528      * @param elanName
529      *            the elan name
530      * @return the elan mac table
531      */
532     public static MacTable getElanMacTable(String elanName) {
533         InstanceIdentifier<MacTable> elanMacTableId = getElanMacTableOperationalDataPath(elanName);
534         Optional<MacTable> existingElanMacTable =
535                 ElanUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanMacTableId);
536         if (existingElanMacTable.isPresent()) {
537             return existingElanMacTable.get();
538         }
539         return null;
540     }
541
542     public static long getElanLocalBCGID(long elanTag) {
543         return ElanConstants.ELAN_GID_MIN + (((elanTag % ElanConstants.ELAN_GID_MIN) *2) - 1);
544     }
545
546     public static long getElanRemoteBCGID(long elanTag) {
547         return ElanConstants.ELAN_GID_MIN + (((elanTag % ElanConstants.ELAN_GID_MIN) *2));
548     }
549
550     public static BigInteger getElanMetadataLabel(long elanTag) {
551         return (BigInteger.valueOf(elanTag)).shiftLeft(24);
552     }
553
554     public static BigInteger getElanMetadataLabel(long elanTag, boolean isSHFlagSet ) {
555         int shBit = (isSHFlagSet) ? 1 : 0;
556         return (BigInteger.valueOf(elanTag)).shiftLeft(24).or(BigInteger.valueOf(shBit));
557     }
558
559     public static BigInteger getElanMetadataLabel(long elanTag, int lportTag) {
560         return getElanMetadataLabel(elanTag).or(MetaDataUtil.getLportTagMetaData(lportTag));
561     }
562
563     public static BigInteger getElanMetadataMask() {
564         return MetaDataUtil.METADATA_MASK_SERVICE.or(MetaDataUtil.METADATA_MASK_LPORT_TAG);
565     }
566
567     /**
568      * Setting INTERNAL_TUNNEL_TABLE, SMAC, DMAC, UDMAC in this DPN and also in
569      * other DPNs.
570      *
571      * @param elanInfo
572      *            the elan info
573      * @param interfaceInfo
574      *            the interface info
575      * @param macTimeout
576      *            the mac timeout
577      * @param macAddress
578      *            the mac address
579      */
580     public static void setupMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout,
581             String macAddress) {
582         synchronized (macAddress) {
583             logger.info("Acquired lock for mac : " + macAddress + ". Proceeding with install operation.");
584             setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, mdsalMgr);
585             setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, mdsalMgr, dataBroker);
586         }
587     }
588
589     public static void setupDMacFlowonRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId,
590             String macAddress) {
591         synchronized (macAddress) {
592             logger.info("Acquired lock for mac : " + macAddress + "Proceeding with install operation.");
593             setupOrigDmacFlowsonRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress);
594         }
595     }
596
597
598     /**
599      * Inserts a Flow in SMAC table to state that the MAC has already been learnt.
600      *
601      * @param elanInfo
602      * @param interfaceInfo
603      * @param macTimeout
604      * @param macAddress
605      * @param mdsalApiManager
606      */
607     private static void setupKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout,
608             String macAddress, IMdsalApiManager mdsalApiManager) {
609         FlowEntity flowEntity = buildKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress);
610         mdsalApiManager.installFlow(flowEntity);
611         if (logger.isDebugEnabled()) {
612             logger.debug("Known Smac flow entry created for elan Name:{}, logical Interface port:{} and mac address:{}",
613                          elanInfo.getElanInstanceName(), elanInfo.getDescription(), macAddress);
614         }
615     }
616
617     public static FlowEntity buildKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout, String macAddress) {
618         BigInteger dpId = interfaceInfo.getDpId();
619         int lportTag = interfaceInfo.getInterfaceTag();
620         long elanTag = elanInfo.getElanTag();
621         // Matching metadata and eth_src fields
622         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
623         mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
624                 ElanUtils.getElanMetadataLabel(elanInfo.getElanTag(), lportTag),
625                 ElanUtils.getElanMetadataMask() }));
626         mkMatches.add(new MatchInfo(MatchFieldType.eth_src, new String[] { macAddress }));
627         List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
628         mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { ElanConstants.ELAN_DMAC_TABLE }));
629
630         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, ElanConstants.ELAN_SMAC_TABLE,
631                 getKnownDynamicmacFlowRef(ElanConstants.ELAN_SMAC_TABLE, dpId, lportTag, macAddress, elanTag),
632                 20, elanInfo.getDescription(), (int)macTimeout, 0, ElanConstants.COOKIE_ELAN_KNOWN_SMAC.add(BigInteger.valueOf(elanTag)),
633                 mkMatches, mkInstructions);
634         flowEntity.setStrictFlag(true);
635         flowEntity.setSendFlowRemFlag(macTimeout != 0); //If Mac timeout is 0, the flow wont be deleted automatically, so no need to get notified
636         return flowEntity;
637     }
638
639     /**
640      * Installs a Flow in INTERNAL_TUNNEL_TABLE of the affected DPN that sends the packet through the specified
641      * interface if the tunnel_id matches the interface's lportTag
642      *
643      * @param interfaceInfo
644      * @param mdsalApiManager
645      */
646     public static void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager) {
647         BigInteger dpId = interfaceInfo.getDpId();
648         int lportTag = interfaceInfo.getInterfaceTag();
649         Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
650                 getIntTunnelTableFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, lportTag), 5,
651                 String.format("%s:%d","ITM Flow Entry ",lportTag), 0, 0,
652                 ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(lportTag)),
653                 getTunnelIdMatchForFilterEqualsLPortTag(lportTag),
654                 getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
655         mdsalApiManager.installFlow(dpId, flow);
656         if (logger.isDebugEnabled()) {
657             logger.debug("Terminating service table flow entry created on dpn:{} for logical Interface port:{}",
658                          dpId, interfaceInfo.getPortName());
659         }
660     }
661
662     /**
663      * Constructs the FlowName for flows installed in the Internal Tunnel Table,
664      * consisting in tableId + elanTag.
665      *
666      * @param tableId
667      * @param elanTag
668      * @return
669      */
670     public static String getIntTunnelTableFlowRef(short tableId, int elanTag) {
671         return new StringBuffer().append(tableId).append(elanTag).toString();
672     }
673
674     /**
675      * Constructs the Matches that checks that the tunnel_id field contains a
676      * specific lportTag
677      *
678      * @param lportTag
679      *            lportTag that must be checked against the tunnel_id field
680      * @return
681      */
682     public static List<MatchInfo> getTunnelIdMatchForFilterEqualsLPortTag(int lportTag) {
683         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
684         // Matching metadata
685         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {
686                 BigInteger.valueOf(lportTag)}));
687         return mkMatches;
688     }
689
690     /**
691      * Constructs the Instructions that take the packet over a given interface
692      *
693      * @param ifName
694      *          Name of the interface where the packet must be sent over. It can
695      *          be a local interface or a tunnel interface (internal or external)
696      * @return
697      */
698     public static List<Instruction> getInstructionsInPortForOutGroup(String ifName) {
699         List<Instruction> mkInstructions = new ArrayList<Instruction>();
700         List<Action> actions = ElanUtils.getEgressActionsForInterface(ifName, /*tunnelKey*/ null );
701
702         mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
703         return mkInstructions;
704     }
705
706
707     /**
708      * Returns the list of Actions to be taken when sending the packet through
709      * an Elan interface. Note that this interface can refer to an ElanInterface
710      * where the Elan VM is attached to a DPN or an ITM tunnel interface where
711      * Elan traffic can be sent through. In this latter case, the tunnelKey is
712      * mandatory and it can hold serviceId for internal tunnels or the VNI for
713      * external tunnels.
714      *
715      * @param ifName
716      *            the if name
717      * @param tunnelKey
718      *            the tunnel key
719      * @return the egress actions for interface
720      */
721     public static List<Action> getEgressActionsForInterface(String ifName, Long tunnelKey) {
722         List<Action> listAction = new ArrayList<Action>();
723         try {
724             GetEgressActionsForInterfaceInput getEgressActionInput =
725                     new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).setTunnelKey(tunnelKey).build();
726             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
727                     interfaceMgrRpcService.getEgressActionsForInterface(getEgressActionInput);
728             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
729             if (!rpcResult.isSuccessful()) {
730                 logger.warn("RPC Call to Get egress actions for interface {} returned with Errors {}",
731                             ifName, rpcResult.getErrors());
732             } else {
733                 List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actions =
734                         rpcResult.getResult().getAction();
735                 listAction = actions;
736             }
737         } catch (InterruptedException | ExecutionException e) {
738             logger.warn("Exception when egress actions for interface {}", ifName, e);
739         }
740         return listAction;
741     }
742
743     private static void setupOrigDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
744             IMdsalApiManager mdsalApiManager, DataBroker broker) {
745         BigInteger dpId = interfaceInfo.getDpId();
746         String ifName = interfaceInfo.getInterfaceName();
747         long ifTag = interfaceInfo.getInterfaceTag();
748         String elanInstanceName = elanInfo.getElanInstanceName();
749         List<DpnInterfaces> elanDpns = getInvolvedDpnsInElan(elanInstanceName);
750         if (elanDpns != null) {
751             Long elanTag = elanInfo.getElanTag();
752             for (DpnInterfaces elanDpn : elanDpns) {
753                 if (elanDpn.getDpId().equals(dpId)) {
754                     // On the local DPN set up a direct output flow
755                     setupLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInstanceName, mdsalApiManager, ifTag);
756                     logger.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on dpn:{}",
757                                  elanInstanceName, interfaceInfo.getPortName(), macAddress, dpId);
758                 } else {
759                     // Check for the Remote DPN present in Inventory Manager
760                     if (isDpnPresent(elanDpn.getDpId())) {
761                         // For remote DPNs a flow is needed to indicate that packets of this ELAN going to this MAC
762                         // need to be forwarded through the appropiated ITM tunnel
763                         setupRemoteDmacFlow(elanDpn.getDpId(),   // srcDpn (the remote DPN in this case)
764                                             dpId,                // dstDpn (the local DPN)
765                                             interfaceInfo.getInterfaceTag(), // lportTag of the local interface
766                                             elanTag,             // identifier of the Elan
767                                             macAddress,          // MAC to be programmed in remote DPN
768                                             elanInstanceName);
769                         logger.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address:{} on dpn:{}",
770                                      elanInstanceName, interfaceInfo.getPortName(), macAddress, elanDpn.getDpId());
771                     }
772                 }
773             }
774
775             // TODO (eperefr): Make sure that the same is performed against the ElanDevices.
776         }
777     }
778
779     private static void setupOrigDmacFlowsonRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId, String macAddress) {
780         BigInteger dpId = interfaceInfo.getDpId();
781         String elanInstanceName = elanInfo.getElanInstanceName();
782         List<DpnInterfaces> remoteFEs = getInvolvedDpnsInElan(elanInstanceName);
783         for(DpnInterfaces remoteFE: remoteFEs) {
784             Long elanTag = elanInfo.getElanTag();
785             if (remoteFE.getDpId().equals(dstDpId)) {
786                 // Check for the Remote DPN present in Inventory Manager
787                 setupRemoteDmacFlow(dstDpId, dpId, interfaceInfo.getInterfaceTag(), elanTag, macAddress, elanInstanceName);
788                 if (logger.isDebugEnabled()) {
789                     logger.debug("Dmac flow entry created for elan Name:{}, logical port Name:{} and mac address {} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, remoteFE.getDpId());
790                 }
791                 break;
792             }
793         }
794     }
795
796
797     @SuppressWarnings("unchecked")
798     public static List<DpnInterfaces> getInvolvedDpnsInElan(String elanName) {
799         List<DpnInterfaces> dpns = ElanInstanceManager.getElanInstanceManager().getElanDPNByName(elanName);
800         if (dpns == null) {
801             return Collections.emptyList();
802         }
803         return dpns;
804     }
805
806     private static void setupLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress,
807                                            String displayName, IMdsalApiManager mdsalApiManager, long ifTag) {
808         Flow flowEntity = buildLocalDmacFlowEntry(elanTag, dpId, ifName, macAddress, displayName, ifTag);
809         mdsalApiManager.installFlow(dpId, flowEntity);
810
811     }
812
813     public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, long lporTag, String macAddress, long elanTag) {
814         return new StringBuffer().append(tableId).append(elanTag).append(dpId).append(lporTag).append(macAddress).toString();
815     }
816
817     public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, BigInteger remoteDpId, String macAddress, long elanTag) {
818         return new StringBuffer().append(tableId).append(elanTag).append(dpId).append(remoteDpId).append(macAddress).toString();
819     }
820
821     private static String getKnownDynamicmacFlowRef(short elanDmacTable, BigInteger dpId, String extDeviceNodeId,
822             String dstMacAddress, long elanTag, boolean shFlag) {
823         return new StringBuffer().append(elanDmacTable).append(elanTag).append(dpId)
824                                  .append(extDeviceNodeId).append(dstMacAddress).append(shFlag)
825                                  .toString();
826     }
827
828     /**
829      * Builds the flow to be programmed in the DMAC table of the local DPN (that is, where the MAC is attached to).
830      * This flow consists in:
831      *
832      *  Match:
833      *     + elanTag in metadata
834      *     + packet goes to a MAC locally attached
835      *  Actions:
836      *     + optionally, pop-vlan + set-vlan-id
837      *     + output to ifName's portNumber
838      *
839      * @param elanTag the elan tag
840      * @param dpId the dp id
841      * @param ifName the if name
842      * @param macAddress the mac address
843      * @param displayName the display name
844      * @param ifTag the if tag
845      * @return the flow
846      */
847     public static Flow buildLocalDmacFlowEntry(long elanTag, BigInteger dpId, String ifName, String macAddress,
848                                                String displayName, long ifTag) {
849         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
850         mkMatches.add(new MatchInfo(MatchFieldType.metadata,
851                 new BigInteger[] { ElanUtils.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE }));
852         mkMatches.add(new MatchInfo(MatchFieldType.eth_dst, new String[] { macAddress }));
853
854         List<Instruction> mkInstructions = new ArrayList<Instruction>();
855         List<Action> actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null);
856         mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
857         Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_DMAC_TABLE,
858                 getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, ifTag, macAddress, elanTag), 20,
859                 displayName, 0, 0, ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches,
860                 mkInstructions);
861
862         return flow;
863     }
864
865     public static void setupRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, String macAddress,
866                                            String displayName) {
867         Flow flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTag, elanTag, macAddress, displayName);
868         mdsalMgr.installFlow(srcDpId, flowEntity);
869     }
870
871     /**
872      * Builds a Flow to be programmed in a remote DPN's DMAC table.
873      * This flow consists in:
874      *  Match:
875      *    + elanTag in packet's metadata
876      *    + packet going to a MAC known to be located in another DPN
877      *  Actions:
878      *    + set_tunnel_id(lportTag)
879      *    + output ITM internal tunnel interface with the other DPN
880      *
881      * @param srcDpId
882      * @param destDpId
883      * @param lportTag
884      * @param elanTag
885      * @param macAddress
886      * @param displayName
887      * @return
888      */
889     public static Flow buildRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag,
890                                                  String macAddress, String displayName) {
891         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
892         mkMatches.add(new MatchInfo(MatchFieldType.metadata,
893                                     new BigInteger[]{ ElanUtils.getElanMetadataLabel(elanTag),
894                                                       MetaDataUtil.METADATA_MASK_SERVICE }));
895         mkMatches.add(new MatchInfo(MatchFieldType.eth_dst, new String[] { macAddress }));
896
897         List<Instruction> mkInstructions = new ArrayList<Instruction>();
898
899         //List of Action for the provided Source and Destination DPIDs
900         try {
901             List<Action> actions = getInternalItmEgressAction(srcDpId, destDpId, lportTag);
902             mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
903         } catch (Exception e) {
904             logger.error("Interface Not Found exception");
905         }
906
907
908         Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_DMAC_TABLE,
909                 getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, srcDpId, destDpId, macAddress, elanTag),
910                 20,  /* prio */
911                 displayName, 0,   /* idleTimeout */
912                 0,   /* hardTimeout */
913                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
914
915         return flow;
916
917     }
918
919     public static void deleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, MacEntry macEntry) {
920         if (elanInfo == null || interfaceInfo == null) {
921             return;
922         }
923         String macAddress = macEntry.getMacAddress().getValue();
924         synchronized (macAddress) {
925             logger.info("Acquired lock for mac : " + macAddress + "Proceeding with remove operation.");
926             deleteMacFlows(elanInfo, interfaceInfo,  macAddress, /* alsoDeleteSMAC */ true);
927         }
928     }
929
930     public static void deleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress, boolean deleteSmac) {
931         String elanInstanceName = elanInfo.getElanInstanceName();
932         long ifTag = interfaceInfo.getInterfaceTag();
933         List<DpnInterfaces> remoteFEs = getInvolvedDpnsInElan(elanInstanceName);
934         BigInteger srcdpId = interfaceInfo.getDpId();
935         for (DpnInterfaces dpnInterface: remoteFEs) {
936             Long elanTag = elanInfo.getElanTag();
937             BigInteger dstDpId = dpnInterface.getDpId();
938             if (dstDpId.equals(srcdpId)) {
939                 if(deleteSmac) {
940                     mdsalMgr.removeFlow(srcdpId, MDSALUtil.buildFlow(ElanConstants.ELAN_SMAC_TABLE,
941                             getKnownDynamicmacFlowRef(ElanConstants.ELAN_SMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)));
942                 }
943                 mdsalMgr.removeFlow(srcdpId, MDSALUtil.buildFlow(ElanConstants.ELAN_DMAC_TABLE,
944                         getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)));
945                 if (logger.isDebugEnabled()) {
946                     logger.debug("All the required flows deleted for elan:{}, logical Interface port:{} and mac address:{} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, srcdpId);
947                 }
948             } else if (isDpnPresent(dstDpId)) {
949                 mdsalMgr.removeFlow(dstDpId, MDSALUtil.buildFlow(ElanConstants.ELAN_DMAC_TABLE,
950                         getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dstDpId, srcdpId, macAddress, elanTag)));
951                 if (logger.isDebugEnabled()) {
952                     logger.debug("Dmac flow entry deleted for elan:{}, logical interface port:{} and mac address:{} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, dstDpId);
953                 }
954             }
955         }
956     }
957
958     /**
959      * Updates the Elan information in the Operational DS. It also updates the
960      * ElanInstance in the Config DS by setting the adquired elanTag.
961      *
962      * @param broker
963      *            the broker
964      * @param idManager
965      *            the id manager
966      * @param elanInstanceAdded
967      *            the elan instance added
968      */
969     public static void updateOperationalDataStore(DataBroker broker, IdManagerService idManager,
970             ElanInstance elanInstanceAdded) {
971         String elanInstanceName = elanInstanceAdded.getElanInstanceName();
972         long elanTag = ElanUtils.retrieveNewElanTag(idManager, elanInstanceName);
973         Elan elanInfo = new ElanBuilder().setName(elanInstanceName).setKey(new ElanKey(elanInstanceName)).build();
974
975         //Add the ElanState in the elan-state operational data-store
976         MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL,
977                 ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanInfo);
978
979         //Add the ElanMacTable in the elan-mac-table operational data-store
980         MacTable elanMacTable = new MacTableBuilder().setKey(new MacTableKey(elanInstanceName)).build();
981         MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL,
982                 ElanUtils.getElanMacTableOperationalDataPath(elanInstanceName), elanMacTable);
983
984         ElanTagName elanTagName = new ElanTagNameBuilder().setElanTag(elanTag).setKey(new ElanTagNameKey(elanTag))
985                 .setName(elanInstanceName).build();
986
987         //Add the ElanTag to ElanName in the elan-tag-name Operational data-store
988         MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL,
989                 ElanUtils.getElanInfoEntriesOperationalDataPath(elanTag), elanTagName);
990
991         // Updates the ElanInstance Config DS by setting the just adquired elanTag
992         ElanInstance elanInstanceWithTag = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
993                 .setDescription(elanInstanceAdded.getDescription())
994                 .setMacTimeout(elanInstanceAdded.getMacTimeout() == null ?  ElanConstants.DEFAULT_MAC_TIME_OUT
995                         : elanInstanceAdded.getMacTimeout())
996                 .setKey(elanInstanceAdded.getKey()).setElanTag(elanTag).build();
997         MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION,
998                 getElanInstanceConfigurationDataPath(elanInstanceName), elanInstanceWithTag);
999     }
1000
1001     public static boolean isDpnPresent(BigInteger dpnId) {
1002         String dpn = String.format("%s:%s", "openflow",dpnId);
1003         NodeId nodeId = new NodeId(dpn);
1004
1005         InstanceIdentifier<Node> node = InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(nodeId))
1006                 .build();
1007         Optional<Node> nodePresent = read(dataBroker, LogicalDatastoreType.OPERATIONAL, node);
1008         return (nodePresent.isPresent());
1009     }
1010
1011     public static ServicesInfo getServiceInfo(String elanInstanceName, long elanTag, String interfaceName) {
1012         int priority = ElanConstants.ELAN_SERVICE_PRIORITY;
1013         int instructionKey = 0;
1014         List<Instruction> instructions = new ArrayList<Instruction>();
1015         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanUtils.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1016         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(ElanConstants.ELAN_SMAC_TABLE, ++instructionKey));
1017
1018         ServicesInfo serviceInfo = InterfaceServiceUtil.buildServiceInfo(String.format("%s.%s", elanInstanceName, interfaceName), ElanConstants.ELAN_SERVICE_INDEX,
1019                 priority, ElanConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1020         return serviceInfo;
1021     }
1022
1023     public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
1024             InstanceIdentifier<T> path, FutureCallback<Void> callback) {
1025         WriteTransaction tx = broker.newWriteOnlyTransaction();
1026         tx.delete(datastoreType, path);
1027         Futures.addCallback(tx.submit(), callback);
1028     }
1029
1030     public static <T extends DataObject> void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
1031             InstanceIdentifier<T> path, T data) {
1032         WriteTransaction tx = broker.newWriteOnlyTransaction();
1033         tx.put(datastoreType, path, data, true);
1034         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
1035         try {
1036             futures.get();
1037         } catch (InterruptedException | ExecutionException e) {
1038             logger.error("Error writing to datastore (path, data) : ({}, {})", path, data);
1039             throw new RuntimeException(e.getMessage());
1040         }
1041     }
1042
1043
1044     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
1045             BigInteger cookie, List<Instruction> instructions) {
1046         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority).setInstruction(instructions);
1047         return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority))
1048                 .setServiceName(serviceName).setServicePriority(servicePriority)
1049                 .setServiceType(ServiceTypeFlowBased.class).addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
1050     }
1051
1052     public static InstanceIdentifier<BoundServices> buildServiceId(String vpnInterfaceName, short serviceIndex) {
1053         return InstanceIdentifier.builder(ServiceBindings.class).child(ServicesInfo.class, new ServicesInfoKey(vpnInterfaceName))
1054                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
1055     }
1056
1057     /**
1058      * Builds the list of actions to be taken when sending the packet over a
1059      * VxLan Tunnel Interface, such as setting the tunnel_id field, the vlanId
1060      * if proceeds and output the packet over the right port.
1061      *
1062      * @param tunnelIfaceName
1063      *            the tunnel iface name
1064      * @param tunnelKey
1065      *            the tunnel key
1066      * @return the list
1067      */
1068     public static List<Action> buildItmEgressActions(String tunnelIfaceName, Long tunnelKey) {
1069         List<Action> result = Collections.emptyList();
1070         if (tunnelIfaceName != null && !tunnelIfaceName.isEmpty()) {
1071             GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
1072                     .setIntfName(tunnelIfaceName).setTunnelKey(tunnelKey).build();
1073
1074             Future<RpcResult<GetEgressActionsForInterfaceOutput>> egressActionsOutputFuture =
1075                     interfaceMgrRpcService.getEgressActionsForInterface(getEgressActInput);
1076             try {
1077                 if (egressActionsOutputFuture.get().isSuccessful()) {
1078                     GetEgressActionsForInterfaceOutput egressActionsOutput = egressActionsOutputFuture.get().getResult();
1079                     result = egressActionsOutput.getAction();
1080                 }
1081             } catch (InterruptedException | ExecutionException e) {
1082                 logger.error("Error in RPC call getEgressActionsForInterface {}", e);
1083             }
1084         }
1085
1086         if ( result == null || result.size() == 0 ) {
1087             logger.warn("Could not build Egress actions for interface {} and tunnelId {}", tunnelIfaceName, tunnelKey);
1088         }
1089         return result;
1090     }
1091
1092     /**
1093      * Builds the list of actions to be taken when sending the packet over an
1094      * external VxLan tunnel interface, such as stamping the VNI on the VxLAN
1095      * header, setting the vlanId if it proceeds and output the packet over the
1096      * right port.
1097      *
1098      * @param srcDpnId
1099      *            Dpn where the tunnelInterface is located
1100      * @param torNode
1101      *            NodeId of the ExternalDevice where the packet must be sent to.
1102      * @param vni
1103      *            Vni to be stamped on the VxLAN Header.
1104      * @return the external itm egress action
1105      */
1106     public static List<Action> getExternalItmEgressAction(BigInteger srcDpnId, NodeId torNode, long vni ) {
1107         List<Action> result = Collections.emptyList();
1108
1109         GetExternalTunnelInterfaceNameInput input = new GetExternalTunnelInterfaceNameInputBuilder()
1110                 .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString()).setTunnelType(TunnelTypeVxlan.class).build();
1111         Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output =
1112                 itmRpcService.getExternalTunnelInterfaceName(input);
1113         try {
1114             if (output.get().isSuccessful()) {
1115                 GetExternalTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult();
1116                 String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName();
1117                 if ( logger.isDebugEnabled() )
1118                     logger.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName);
1119
1120                 result = buildItmEgressActions(tunnelIfaceName, vni);
1121             }
1122
1123         } catch (InterruptedException | ExecutionException e) {
1124             logger.error("Error in RPC call getTunnelInterfaceName {}", e);
1125         }
1126
1127         return result;
1128     }
1129
1130     /**
1131      * Builds the list of actions to be taken when sending the packet over an
1132      * internal VxLan tunnel interface, such as setting the serviceTag on the
1133      * VNI field of the VxLAN header, setting the vlanId if it proceeds and
1134      * output the packet over the right port.
1135      *
1136      * @param sourceDpnId
1137      *            Dpn where the tunnelInterface is located
1138      * @param destinationDpnId
1139      *            Dpn where the packet must be sent to. It is used here in order
1140      *            to select the right tunnel interface.
1141      * @param serviceTag
1142      *            serviceId to be sent on the VxLAN header.
1143      * @return the internal itm egress action
1144      */
1145     public static List<Action> getInternalItmEgressAction(BigInteger sourceDpnId, BigInteger destinationDpnId,
1146             long serviceTag) {
1147         List<Action> result = Collections.emptyList();
1148
1149         logger.debug("In getInternalItmEgressAction Action source {}, destination {}, elanTag {}",
1150                      sourceDpnId, destinationDpnId, serviceTag);
1151         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
1152         GetTunnelInterfaceNameInput input = new GetTunnelInterfaceNameInputBuilder()
1153                 .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).setTunnelType(tunType).build();
1154         Future<RpcResult<GetTunnelInterfaceNameOutput>> output = itmRpcService.getTunnelInterfaceName(input);
1155         try {
1156             if (output.get().isSuccessful()) {
1157                 GetTunnelInterfaceNameOutput tunnelInterfaceNameOutput = output.get().getResult();
1158                 String tunnelIfaceName = tunnelInterfaceNameOutput.getInterfaceName();
1159                 logger.debug("Received tunnelInterfaceName from getTunnelInterfaceName RPC {}", tunnelIfaceName);
1160
1161                 result = buildItmEgressActions(tunnelIfaceName, serviceTag);
1162             }
1163         } catch (InterruptedException | ExecutionException e) {
1164             logger.error("Error in RPC call getTunnelInterfaceName {}", e);
1165         }
1166
1167         return result;
1168     }
1169
1170     public static List<MatchInfo> getTunnelMatchesForServiceId(int elanTag) {
1171         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
1172         // Matching metadata
1173         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[]{BigInteger.valueOf(elanTag)}));
1174
1175         return mkMatches;
1176     }
1177
1178     public static void removeTerminatingServiceAction(BigInteger destDpId, int serviceId) {
1179         RemoveTerminatingServiceActionsInput input = new RemoveTerminatingServiceActionsInputBuilder().setDpnId(destDpId).setServiceId(serviceId).build();
1180         Future<RpcResult<Void>> futureObject = itmRpcService.removeTerminatingServiceActions(input);
1181         try {
1182             RpcResult<Void> result = futureObject.get();
1183             if (result.isSuccessful()) {
1184                 logger.debug("Successfully completed removeTerminatingServiceActions");
1185             } else {
1186                 logger.debug("Failure in removeTerminatingServiceAction RPC call");
1187             }
1188         } catch (InterruptedException | ExecutionException e) {
1189             logger.error("Error in RPC call removeTerminatingServiceActions {}", e);
1190         }
1191     }
1192
1193     public static void createTerminatingServiceActions(BigInteger destDpId, int serviceId, List<Action> actions) {
1194         List<Instruction> mkInstructions = new ArrayList<Instruction>();
1195         mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
1196         CreateTerminatingServiceActionsInput input = new CreateTerminatingServiceActionsInputBuilder().setDpnId(destDpId).setServiceId(serviceId).setInstruction(mkInstructions).build();
1197
1198         itmRpcService.createTerminatingServiceActions(input);
1199     }
1200
1201     public static TunnelList buildInternalTunnel(DataBroker broker) {
1202         InstanceIdentifier<TunnelList> tunnelListInstanceIdentifier = InstanceIdentifier.builder(TunnelList.class).build();
1203         Optional<TunnelList> tunnelList = read(broker, LogicalDatastoreType.CONFIGURATION, tunnelListInstanceIdentifier);
1204         if (tunnelList.isPresent()) {
1205             return tunnelList.get();
1206         }
1207         return null;
1208     }
1209
1210     /**
1211      * Gets the external tunnel.
1212      *
1213      * @param sourceDevice
1214      *            the source device
1215      * @param destinationDevice
1216      *            the destination device
1217      * @param datastoreType
1218      *            the datastore type
1219      * @return the external tunnel
1220      */
1221     public static ExternalTunnel getExternalTunnel(String sourceDevice, String destinationDevice,
1222             LogicalDatastoreType datastoreType) {
1223         ExternalTunnel externalTunnel = null;
1224         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class ;
1225         InstanceIdentifier<ExternalTunnel> iid = InstanceIdentifier.builder(ExternalTunnelList.class)
1226                 .child(ExternalTunnel.class, new ExternalTunnelKey(destinationDevice, sourceDevice, tunType)).build();
1227         Optional<ExternalTunnel> tunnelList = read(dataBroker, datastoreType, iid);
1228         if (tunnelList.isPresent()) {
1229             externalTunnel = tunnelList.get();
1230         }
1231         return externalTunnel;
1232     }
1233
1234     /**
1235      * Gets the external tunnel.
1236      *
1237      * @param interfaceName
1238      *            the interface name
1239      * @param datastoreType
1240      *            the datastore type
1241      * @return the external tunnel
1242      */
1243     public static ExternalTunnel getExternalTunnel(String interfaceName, LogicalDatastoreType datastoreType) {
1244         ExternalTunnel externalTunnel = null;
1245         List<ExternalTunnel> externalTunnels = getAllExternalTunnels(datastoreType);
1246         for (ExternalTunnel tunnel : externalTunnels) {
1247             if (StringUtils.equalsIgnoreCase(interfaceName, tunnel.getTunnelInterfaceName())) {
1248                 externalTunnel = tunnel;
1249                 break;
1250             }
1251         }
1252         return externalTunnel;
1253     }
1254
1255     /**
1256      * Gets the all external tunnels.
1257      *
1258      * @return the all external tunnels
1259      */
1260     public static List<ExternalTunnel> getAllExternalTunnels(LogicalDatastoreType datastoreType) {
1261         List<ExternalTunnel> result = null;
1262         InstanceIdentifier<ExternalTunnelList> iid = InstanceIdentifier.builder(ExternalTunnelList.class).build();
1263         Optional<ExternalTunnelList> tunnelList = read(dataBroker, datastoreType, iid);
1264         if (tunnelList.isPresent()) {
1265             result = tunnelList.get().getExternalTunnel();
1266         }
1267         if (result == null) {
1268             result = Collections.emptyList();
1269         }
1270         return result;
1271     }
1272
1273     /**
1274      * Installs a Flow in a DPN's DMAC table. The Flow is for a MAC that is
1275      * connected remotely in another CSS and accessible through an internal
1276      * tunnel. It also installs the flow for dropping the packet if it came over
1277      * an ITM tunnel (that is, if the Split-Horizon flag is set)
1278      *
1279      * @param localDpId
1280      *            Id of the DPN where the MAC Addr is accessible locally
1281      * @param remoteDpId
1282      *            Id of the DPN where the flow must be installed
1283      * @param lportTag
1284      *            lportTag of the interface where the mac is connected to.
1285      * @param elanTag
1286      *            Identifier of the ELAN
1287      * @param macAddress
1288      *            MAC to be installed in remoteDpId's DMAC table
1289      * @param displayName
1290      *            the display name
1291      */
1292     public static void installDmacFlowsToInternalRemoteMac(BigInteger localDpId, BigInteger remoteDpId, long lportTag,
1293             long elanTag, String macAddress, String displayName) {
1294         Flow flow = buildDmacFlowForInternalRemoteMac(localDpId, remoteDpId, lportTag, elanTag, macAddress, displayName);
1295         mdsalMgr.installFlow(remoteDpId, flow);
1296     }
1297
1298     /**
1299      * Installs a Flow in the specified DPN's DMAC table. The flow is for a MAC
1300      * that is connected remotely in an External Device (TOR) and that is
1301      * accessible through an external tunnel. It also installs the flow for
1302      * dropping the packet if it came over an ITM tunnel (that is, if the
1303      * Split-Horizon flag is set)
1304      *
1305      * @param dpnId
1306      *            Id of the DPN where the flow must be installed
1307      * @param extDeviceNodeId
1308      *            the ext device node id
1309      * @param elanTag
1310      *            the elan tag
1311      * @param vni
1312      *            the vni
1313      * @param macAddress
1314      *            the mac address
1315      * @param displayName
1316      *            the display name
1317      */
1318     public static List<ListenableFuture<Void>> installDmacFlowsToExternalRemoteMac(BigInteger dpnId,
1319             String extDeviceNodeId, Long elanTag, Long vni, String macAddress, String displayName) {
1320         List<ListenableFuture<Void>> futures = new ArrayList<>();
1321         synchronized (macAddress) {
1322             Flow flow = buildDmacFlowForExternalRemoteMac(dpnId, extDeviceNodeId, elanTag, vni, macAddress, displayName);
1323             futures.add(mdsalMgr.installFlow(dpnId, flow));
1324
1325             Flow dropFlow = buildDmacFlowDropIfPacketComingFromTunnel(dpnId, extDeviceNodeId, elanTag, macAddress);
1326             futures.add(mdsalMgr.installFlow(dpnId, dropFlow));
1327         }
1328         return futures;
1329     }
1330
1331     public static List<MatchInfo> buildMatchesForElanTagShFlagAndDstMac(long elanTag, boolean shFlag, String macAddr) {
1332         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
1333         mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
1334                 ElanUtils.getElanMetadataLabel(elanTag, shFlag), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG }));
1335         mkMatches.add(new MatchInfo(MatchFieldType.eth_dst, new String[] { macAddr }));
1336
1337         return mkMatches;
1338     }
1339
1340     /**
1341      * Builds a Flow to be programmed in a DPN's DMAC table. This method must be used when the MAC is located in an
1342      * External Device (TOR).
1343      * The flow matches on the specified MAC and
1344      *   1) sends the packet over the CSS-TOR tunnel if SHFlag is not set, or
1345      *   2) drops it if SHFlag is set (what means the packet came from an external tunnel)
1346      *
1347      * @param dpId DPN whose DMAC table is going to be modified
1348      * @param extDeviceNodeId Hwvtep node where the mac is attached to
1349      * @param elanTag ElanId to which the MAC is being added to
1350      * @param vni the vni
1351      * @param dstMacAddress The mac address to be programmed
1352      * @param displayName the display name
1353      * @return the flow
1354      */
1355     public static Flow buildDmacFlowForExternalRemoteMac(BigInteger dpId, String extDeviceNodeId, long elanTag,
1356             Long vni, String dstMacAddress, String displayName ) {
1357         List<MatchInfo> mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /*shFlag*/ false, dstMacAddress);
1358         List<Instruction> mkInstructions = new ArrayList<Instruction>();
1359         try {
1360             List<Action> actions = getExternalItmEgressAction(dpId, new NodeId(extDeviceNodeId), vni);
1361             mkInstructions.add( MDSALUtil.buildApplyActionsInstruction(actions) );
1362         } catch (Exception e) {
1363             logger.error("Could not get Egress Actions for DpId={}  externalNode={}", dpId, extDeviceNodeId );
1364         }
1365
1366         Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_DMAC_TABLE,
1367                 getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, dstMacAddress, elanTag,
1368                         false),
1369                 20,  /* prio */
1370                 displayName, 0,   /* idleTimeout */
1371                 0,   /* hardTimeout */
1372                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
1373
1374         return flow;
1375     }
1376
1377     /**
1378      * Builds the flow that drops the packet if it came through an external tunnel, that is, if the Split-Horizon
1379      * flag is set.
1380      *
1381      * @param dpnId DPN whose DMAC table is going to be modified
1382      * @param extDeviceNodeId  Hwvtep node where the mac is attached to
1383      * @param elanTag ElanId to which the MAC is being added to
1384      * @param dstMacAddress The mac address to be programmed
1385      * @param displayName
1386      * @return
1387      */
1388     private static Flow buildDmacFlowDropIfPacketComingFromTunnel(BigInteger dpnId, String extDeviceNodeId,
1389             Long elanTag, String dstMacAddress) {
1390         List<MatchInfo> mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /*shFlag*/ true, dstMacAddress);
1391         List<Instruction> mkInstructions = MDSALUtil.buildInstructionsDrop();
1392         String flowId = getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpnId, extDeviceNodeId, dstMacAddress,
1393                 elanTag, true);
1394         Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_DMAC_TABLE, flowId, 20,  /* prio */
1395                 "Drop", 0,   /* idleTimeout */
1396                 0,   /* hardTimeout */
1397                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
1398
1399         return flow;
1400     }
1401
1402     private static String getDmacDropFlowId(Long elanTag, String dstMacAddress) {
1403         return new StringBuilder(ElanConstants.ELAN_DMAC_TABLE).append(elanTag).append(dstMacAddress).append("Drop")
1404                 .toString();
1405     }
1406
1407     /**
1408      * Builds a Flow to be programmed in a remote DPN's DMAC table. This method must be used when the MAC is located
1409      * in another CSS.
1410      *
1411      * This flow consists in:
1412      *  Match:
1413      *    + elanTag in packet's metadata
1414      *    + packet going to a MAC known to be located in another DPN
1415      *  Actions:
1416      *    + set_tunnel_id(lportTag)
1417      *    + output on ITM internal tunnel interface with the other DPN
1418      *
1419      * @param localDpId the local dp id
1420      * @param remoteDpId the remote dp id
1421      * @param lportTag the lport tag
1422      * @param elanTag the elan tag
1423      * @param macAddress the mac address
1424      * @param displayName the display name
1425      * @return the flow
1426      */
1427     public static Flow buildDmacFlowForInternalRemoteMac(BigInteger localDpId, BigInteger remoteDpId, long lportTag,
1428             long elanTag, String macAddress, String displayName) {
1429         List<MatchInfo> mkMatches = buildMatchesForElanTagShFlagAndDstMac(elanTag, /*shFlag*/ false, macAddress);
1430
1431         List<Instruction> mkInstructions = new ArrayList<Instruction>();
1432
1433         try {
1434             //List of Action for the provided Source and Destination DPIDs
1435             List<Action> actions = getInternalItmEgressAction(localDpId, remoteDpId, lportTag);
1436             mkInstructions.add( MDSALUtil.buildApplyActionsInstruction(actions) );
1437         } catch (Exception e) {
1438             logger.error("Could not get Egress Actions for localDpId={}  remoteDpId={}   lportTag={}",
1439                          localDpId, remoteDpId, lportTag);
1440         }
1441
1442         Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_DMAC_TABLE,
1443                 getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, localDpId, remoteDpId, macAddress, elanTag),
1444                 20,  /* prio */
1445                 displayName, 0,   /* idleTimeout */
1446                 0,   /* hardTimeout */
1447                 ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
1448
1449         return flow;
1450
1451     }
1452
1453     /**
1454      * Installs or removes flows in DMAC table for MACs that are/were located in
1455      * an external Elan Device.
1456      *
1457      * @param dpId
1458      *            Id of the DPN where the DMAC table is going to be modified
1459      * @param extNodeId
1460      *            Id of the External Device where the MAC is located
1461      * @param elanTag
1462      *            Id of the ELAN
1463      * @param vni
1464      *            VNI of the LogicalSwitch to which the MAC belongs to, and that
1465      *            is associated with the ELAN
1466      * @param macAddress
1467      *            the mac address
1468      * @param elanInstanceName
1469      *            the elan instance name
1470      * @param addOrRemove
1471      *            Indicates if flows must be installed or removed.
1472      * @see org.opendaylight.vpnservice.mdsalutil.MDSALUtil.MdsalOp
1473      */
1474     public static void setupDmacFlowsToExternalRemoteMac(BigInteger dpId, String extNodeId, Long elanTag, Long vni,
1475             String macAddress, String elanInstanceName, MdsalOp addOrRemove) {
1476         if ( addOrRemove == MdsalOp.CREATION_OP ) {
1477             ElanUtils.installDmacFlowsToExternalRemoteMac(dpId, extNodeId, elanTag, vni, macAddress, elanInstanceName);
1478         } else if ( addOrRemove == MdsalOp.REMOVAL_OP ) {
1479             ElanUtils.deleteDmacFlowsToExternalMac(elanTag, dpId, extNodeId, macAddress );
1480         }
1481     }
1482
1483     /**
1484      * Delete dmac flows to external mac.
1485      *
1486      * @param elanTag
1487      *            the elan tag
1488      * @param dpId
1489      *            the dp id
1490      * @param extDeviceNodeId
1491      *            the ext device node id
1492      * @param macToRemove
1493      *            the mac to remove
1494      */
1495     public static List<ListenableFuture<Void>> deleteDmacFlowsToExternalMac(long elanTag, BigInteger dpId,
1496             String extDeviceNodeId, String macToRemove ) {
1497         List<ListenableFuture<Void>> futures = new ArrayList<>();
1498         synchronized (macToRemove) {
1499             // Removing the flows that sends the packet on an external tunnel
1500             String flowId = getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId,
1501                     macToRemove, elanTag, false);
1502             Flow flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(ElanConstants.ELAN_DMAC_TABLE)
1503                     .build();
1504             futures.add(mdsalMgr.removeFlow(dpId, flowToRemove));
1505
1506             // And now removing the drop flow
1507             flowId = getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, extDeviceNodeId, macToRemove,
1508                     elanTag, true);
1509             flowToRemove = new FlowBuilder().setId(new FlowId(flowId)).setTableId(ElanConstants.ELAN_DMAC_TABLE)
1510                     .build();
1511             futures.add(mdsalMgr.removeFlow(dpId, flowToRemove));
1512         }
1513         return futures;
1514     }
1515
1516     /**
1517      * Gets the dpid from interface.
1518      *
1519      * @param interfaceName
1520      *            the interface name
1521      * @return the dpid from interface
1522      */
1523     public static BigInteger getDpidFromInterface(String interfaceName) {
1524         BigInteger dpId = null;
1525         Future<RpcResult<GetDpidFromInterfaceOutput>> output = interfaceMgrRpcService
1526                 .getDpidFromInterface(new GetDpidFromInterfaceInputBuilder().setIntfName(interfaceName).build());
1527         try {
1528             RpcResult<GetDpidFromInterfaceOutput> rpcResult = output.get();
1529             if (rpcResult.isSuccessful()) {
1530                 dpId = rpcResult.getResult().getDpid();
1531             }
1532         } catch (NullPointerException | InterruptedException | ExecutionException e) {
1533             logger.error("Failed to get the DPN ID: {} for interface {}: {} ", dpId, interfaceName, e);
1534         }
1535         return dpId;
1536     }
1537
1538     /**
1539      * Checks if is interface operational.
1540      *
1541      * @param interfaceName
1542      *            the interface name
1543      * @param dataBroker
1544      *            the data broker
1545      * @return true, if is interface operational
1546      */
1547     public static boolean isInterfaceOperational(String interfaceName, DataBroker dataBroker) {
1548         if (StringUtils.isBlank(interfaceName)) {
1549             return false;
1550         }
1551         Interface ifState = getInterfaceStateFromOperDS(interfaceName, dataBroker);
1552         if (ifState == null) {
1553             return false;
1554         }
1555         return ((ifState.getOperStatus() == OperStatus.Up) && (ifState.getAdminStatus() == AdminStatus.Up));
1556     }
1557
1558     /**
1559      * Gets the interface state from operational ds.
1560      *
1561      * @param interfaceName
1562      *            the interface name
1563      * @param dataBroker
1564      *            the data broker
1565      * @return the interface state from oper ds
1566      */
1567     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
1568             String interfaceName, DataBroker dataBroker) {
1569         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId = createInterfaceStateInstanceIdentifier(
1570                 interfaceName);
1571         Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateOptional = MDSALUtil
1572                 .read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId);
1573         if (ifStateOptional.isPresent()) {
1574             return ifStateOptional.get();
1575         }
1576         return null;
1577     }
1578
1579     /**
1580      * Creates the interface state instance identifier.
1581      *
1582      * @param interfaceName
1583      *            the interface name
1584      * @return the instance identifier
1585      */
1586     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
1587             String interfaceName) {
1588         InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder = InstanceIdentifier
1589                 .builder(InterfacesState.class)
1590                 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
1591                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
1592                                 interfaceName));
1593         return idBuilder.build();
1594     }
1595
1596 }
1597