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