Merge "Using Table Ids from NwConstants.java"
[netvirt.git] / vpnservice / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / netvirt / elan / internal / ElanInterfaceManager.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.internal;
9
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Queue;
17 import java.util.Set;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.ConcurrentLinkedQueue;
20 import java.util.concurrent.ConcurrentMap;
21
22 import org.apache.commons.lang3.StringUtils;
23 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
26 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
27 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
28 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
29 import org.opendaylight.netvirt.elan.utils.ElanConstants;
30 import org.opendaylight.netvirt.elan.utils.ElanUtils;
31 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
32 import org.opendaylight.genius.itm.globals.ITMConstants;
33 import org.opendaylight.genius.mdsalutil.ActionInfo;
34 import org.opendaylight.genius.mdsalutil.ActionType;
35 import org.opendaylight.genius.mdsalutil.FlowEntity;
36 import org.opendaylight.genius.mdsalutil.InstructionInfo;
37 import org.opendaylight.genius.mdsalutil.InstructionType;
38 import org.opendaylight.genius.mdsalutil.MDSALUtil;
39 import org.opendaylight.genius.mdsalutil.MatchFieldType;
40 import org.opendaylight.genius.mdsalutil.MatchInfo;
41 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
42 import org.opendaylight.genius.mdsalutil.NwConstants;
43 //import org.opendaylight.genius.neutronvpn.api.l2gw.L2GatewayDevice;
44 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTableKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.ElanKey;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
79 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
80 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
83
84 import com.google.common.base.Optional;
85 import com.google.common.base.Preconditions;
86
87 /**
88  * Class in charge of handling creations, modifications and removals of ElanInterfaces.
89  *
90  * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
91  *
92  */
93 @SuppressWarnings( "deprecation" )
94 public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface,ElanInterfaceManager> implements AutoCloseable {
95
96     private ElanServiceProvider elanServiceProvider = null;
97     private static volatile ElanInterfaceManager elanInterfaceManager = null;
98     private static long waitTimeForSyncInstall;
99
100     private Map<String, ConcurrentLinkedQueue<ElanInterface>> unProcessedElanInterfaces =
101         new ConcurrentHashMap<String, ConcurrentLinkedQueue<ElanInterface>> ();
102
103     private static final Logger logger = LoggerFactory.getLogger(ElanInterfaceManager.class);
104
105     public ElanInterfaceManager(ElanServiceProvider elanServiceProvider) {
106         super(ElanInterface.class,ElanInterfaceManager.class);
107         this.elanServiceProvider = elanServiceProvider;
108     }
109
110     public static ElanInterfaceManager getElanInterfaceManager(ElanServiceProvider elanServiceProvider) {
111         if (elanInterfaceManager == null) {
112             synchronized (ElanInterfaceManager.class) {
113                 if (elanInterfaceManager == null) {
114                     elanInterfaceManager = new ElanInterfaceManager(elanServiceProvider);
115                     Long waitTime = Long.getLong("wait.time.sync.install");
116                     if (waitTime == null) {
117                         waitTime = 300L;
118                     }
119                     waitTimeForSyncInstall = waitTime;
120                 }
121             }
122         }
123         return elanInterfaceManager;
124     }
125
126     @Override
127     protected InstanceIdentifier<ElanInterface> getWildCardPath() {
128         return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
129     }
130
131     @Override
132     protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
133         String interfaceName =  del.getName();
134         ElanInstance elanInfo = ElanUtils.getElanInstanceByName(del.getElanInstanceName());
135         /*
136          * Handling in case the elan instance is deleted.If the Elan instance is deleted, there is no need to explicitly delete the elan interfaces
137          */
138         if (elanInfo == null) {
139             return;
140         }
141         InterfaceInfo interfaceInfo = elanServiceProvider.getInterfaceManager().getInterfaceInfo(interfaceName);
142         String elanInstanceName = elanInfo.getElanInstanceName();
143         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
144         InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo, interfaceName, interfaceInfo, false, this);
145         coordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
146     }
147
148     public void removeElanInterface(ElanInstance elanInfo, String interfaceName, InterfaceInfo interfaceInfo, boolean isInterfaceStateRemoved) {
149         String elanName = elanInfo.getElanInstanceName();
150         boolean isLastElanInterface = false;
151         long elanTag = elanInfo.getElanTag();
152         WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
153         WriteTransaction deleteFlowGroupTx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
154         Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, tx);
155         if (elanState == null) {
156             return;
157         }
158         List<String> elanInterfaces = elanState.getElanInterfaces();
159         if (elanInterfaces.size() == 0) {
160             isLastElanInterface = true;
161         }
162         if (interfaceInfo != null) {
163             BigInteger dpId = interfaceInfo.getDpId();
164             DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName, elanTag, tx);
165             /*
166              * If there are not elan ports, remove the unknown dmac, terminating service table
167              * flows, remote/local bc group
168              */
169             if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null || dpnInterfaces.getInterfaces().isEmpty()) {
170                 // No more Elan Interfaces in this DPN
171                 logger.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
172                 removeDefaultTermFlow(dpId, elanInfo.getElanTag());
173                 removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx);
174                 removeElanBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
175                 removeLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
176                 if (ElanUtils.isVxlan(elanInfo)) {
177                     unsetExternalTunnelTable(dpId, elanInfo);
178                 }
179             } else {
180                 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
181             }
182         }
183         ElanUtils.waitForTransactionToComplete(tx);
184         ElanUtils.waitForTransactionToComplete(deleteFlowGroupTx);
185         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
186         InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(interfaceName, elanInfo,
187             interfaceInfo, isInterfaceStateRemoved, this, isLastElanInterface);
188         coordinator.enqueueJob(interfaceName, removeInterfaceWorker, ElanConstants.JOB_MAX_RETRIES);
189     }
190
191     private Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
192         String elanName = elanInfo.getElanInstanceName();
193         Elan elanState = ElanUtils.getElanByName(elanName);
194         if(elanState == null) {
195             return elanState;
196         }
197         List<String> elanInterfaces = elanState.getElanInterfaces();
198         elanInterfaces.remove(interfaceName);
199         if(elanInterfaces.isEmpty()) {
200             tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
201             tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
202             tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
203         } else {
204             Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName).setKey(new ElanKey(elanName)).build();
205             tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
206         }
207         return elanState;
208     }
209
210     private void deleteElanInterfaceFromConfigDS(String interfaceName, WriteTransaction tx) {
211         //removing the ElanInterface from the config data_store if interface is not present in Interface config DS
212         if (elanServiceProvider.getInterfaceManager().getInterfaceInfoFromConfigDataStore(interfaceName) == null) {
213             tx.delete(LogicalDatastoreType.CONFIGURATION, ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
214         }
215     }
216
217     void removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String interfaceName, boolean isInterfaceStateRemoved, boolean isLastElanInterface) {
218         String elanName = elanInfo.getElanInstanceName();
219         WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
220         WriteTransaction deleteFlowGroupTx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
221         InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
222         logger.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
223         if (interfaceInfo != null) {
224             Optional<ElanInterfaceMac> existingElanInterfaceMac = ElanUtils.read(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
225             if(existingElanInterfaceMac.isPresent()) {
226                 List<PhysAddress> macAddresses = new ArrayList<PhysAddress>();
227                 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
228                 List<MacEntry> macEntries = new ArrayList<>();
229                 if (existingMacEntries != null && !existingMacEntries.isEmpty()) {
230                     macEntries.addAll(existingMacEntries);
231                 }
232                 if(!macEntries.isEmpty()) {
233                     for (MacEntry macEntry : macEntries) {
234                         logger.debug("removing the  mac-entry:{} present on elanInterface:{}", macEntry.getMacAddress().getValue(), interfaceName);
235                         if (!isLastElanInterface) {
236                             tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getMacEntryOperationalDataPath(elanName, macEntry.getMacAddress()));
237                         }
238                         ElanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, deleteFlowGroupTx);
239                         macAddresses.add(macEntry.getMacAddress());
240                     }
241
242                     // Removing all those MACs from External Devices belonging to this ELAN
243                     if (ElanUtils.isVxlan(elanInfo)) {
244                         ElanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
245                     }
246                 }
247             }
248             removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
249             removeFilterEqualsTable(elanInfo, interfaceInfo, deleteFlowGroupTx);
250         } else {
251             // Interface does not exist in ConfigDS, so lets remove everything about that interface related to Elan
252             ElanInterfaceMac elanInterfaceMac =  ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
253             if(elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
254                 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
255                 for(MacEntry macEntry : macEntries) {
256                     tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getMacEntryOperationalDataPath(elanName, macEntry.getMacAddress()));
257                 }
258             }
259         }
260         tx.delete(LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
261         if(!isInterfaceStateRemoved) {
262             unbindService(elanInfo, interfaceName, tx);
263         }
264         deleteElanInterfaceFromConfigDS(interfaceName, tx);
265         ElanUtils.waitForTransactionToComplete(tx);
266         ElanUtils.waitForTransactionToComplete(deleteFlowGroupTx);
267     }
268
269     private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId, String interfaceName,
270                                                                          long elanTag, WriteTransaction tx) {
271         DpnInterfaces dpnInterfaces =  ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
272         if(dpnInterfaces != null) {
273             List<String> interfaceLists = dpnInterfaces.getInterfaces();
274             interfaceLists.remove(interfaceName);
275
276             if (interfaceLists == null || interfaceLists.isEmpty()) {
277                 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
278                 deleteElanDpnInterface(elanName, dpId, tx);
279             } else {
280                 dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
281             }
282         }
283         return dpnInterfaces;
284     }
285
286     private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
287         List<DpnInterfaces> dpnInterfaces = ElanUtils.getInvolvedDpnsInElan(elanName);
288         for (DpnInterfaces dpnInterface : dpnInterfaces) {
289             BigInteger currentDpId = dpnInterface.getDpId();
290             if (!currentDpId.equals(dpId)) {
291                 for (String elanInterface : dpnInterface.getInterfaces()) {
292                     ElanInterfaceMac macs = ElanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
293                     if (macs == null) {
294                         continue;
295                     }
296                     for (MacEntry mac : macs.getMacEntry())
297                         elanServiceProvider.getMdsalManager().removeFlow(dpId, MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
298                             ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId, mac.getMacAddress().getValue(), elanTag)));
299                 }
300             }
301         }
302     }
303
304     @Override
305     protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
306         // updating the static-Mac Entries for the existing elanInterface
307         String elanName = update.getElanInstanceName();
308         String interfaceName = update.getName();
309         InterfaceInfo interfaceInfo = elanServiceProvider.getInterfaceManager().getInterfaceInfo(interfaceName);
310         List<PhysAddress> existingPhysAddress = original.getStaticMacEntries();
311         List<PhysAddress> updatedPhysAddress = update.getStaticMacEntries();
312         if(updatedPhysAddress != null && !updatedPhysAddress.isEmpty()) {
313             List<PhysAddress> existingClonedPhyAddress = new ArrayList<>();
314             if(existingPhysAddress != null && !existingPhysAddress.isEmpty()) {
315                 existingClonedPhyAddress.addAll(0, existingPhysAddress);
316                 existingPhysAddress.removeAll(updatedPhysAddress);
317                 updatedPhysAddress.removeAll(existingClonedPhyAddress);
318                 // removing the PhyAddress which are not presented in the updated List
319                 for(PhysAddress physAddress: existingPhysAddress) {
320                     removeInterfaceStaticMacEntires(elanName, interfaceName, physAddress);
321                 }
322             }
323             // Adding the new PhysAddress which are presented in the updated List
324             if(updatedPhysAddress.size() > 0) {
325                 for(PhysAddress physAddress: updatedPhysAddress) {
326                     InstanceIdentifier<MacEntry> macId =  getMacEntryOperationalDataPath(elanName, physAddress);
327                     Optional<MacEntry> existingMacEntry = ElanUtils.read(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, macId);
328                     WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
329                     if(existingMacEntry.isPresent()) {
330                         elanServiceProvider.getElanForwardingEntriesHandler().updateElanInterfaceForwardingTablesList(elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(), tx);
331                     } else {
332                         elanServiceProvider.getElanForwardingEntriesHandler().addElanInterfaceForwardingTableList(ElanUtils.getElanInstanceByName(elanName), interfaceName, physAddress, tx);
333                     }
334                     ElanUtils.waitForTransactionToComplete(tx);
335                 }
336             }
337         } else if(existingPhysAddress != null && !existingPhysAddress.isEmpty()) {
338             for( PhysAddress physAddress : existingPhysAddress) {
339                 removeInterfaceStaticMacEntires(elanName, interfaceName, physAddress);
340             }
341         }
342     }
343
344     @Override
345     protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
346         String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
347         String interfaceName = elanInterfaceAdded.getName();
348         InterfaceInfo interfaceInfo = elanServiceProvider.getInterfaceManager().getInterfaceInfo(interfaceName);
349         if (interfaceInfo == null) {
350             logger.warn("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
351             return;
352         }
353         ElanInstance elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
354
355         if (elanInstance == null) {
356             elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(elanInterfaceAdded.getDescription()).build();
357             //Add the ElanInstance in the Configuration data-store
358             WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
359             List<String> elanInterfaces = new ArrayList<String>();
360             elanInterfaces.add(interfaceName);
361             ElanUtils.updateOperationalDataStore(elanServiceProvider.getBroker(), elanServiceProvider.getIdManager(), elanInstance, elanInterfaces, tx);
362             ElanUtils.waitForTransactionToComplete(tx);
363             elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
364         }
365
366
367         Long elanTag = elanInstance.getElanTag();
368         // If elan tag is not updated, then put the elan interface into unprocessed entry map and entry. Let entries
369         // in this map get processed during ELAN update DCN.
370         if (elanTag == null) {
371             ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
372             if (elanInterfaces == null) {
373                 elanInterfaces = new ConcurrentLinkedQueue<ElanInterface>();
374             }
375             elanInterfaces.add(elanInterfaceAdded);
376             unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
377             return;
378         }
379         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
380         InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
381             interfaceInfo, elanInstance, this);
382         coordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
383     }
384
385     void handleunprocessedElanInterfaces(ElanInstance elanInstance) {
386         Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
387         if (elanInterfaces == null || elanInterfaces.isEmpty()) {
388             return;
389         }
390         for (ElanInterface elanInterface: elanInterfaces) {
391             String interfaceName = elanInterface.getName();
392             InterfaceInfo interfaceInfo = elanServiceProvider.getInterfaceManager().getInterfaceInfo(interfaceName);
393             addElanInterface(elanInterface, interfaceInfo, elanInstance);
394         }
395     }
396
397     void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo, WriteTransaction writeFlowGroupTx){
398         ElanDpnInterfacesList elanDpnInterfacesList =  ElanUtils.getElanDpnInterfacesList(elanInstance.getElanInstanceName());
399         List<DpnInterfaces> dpnInterfaceLists =  null;
400         if (elanDpnInterfacesList != null) {
401             dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
402         }
403         if (dpnInterfaceLists == null) {
404             dpnInterfaceLists = new ArrayList<DpnInterfaces>();
405         }
406         for(DpnInterfaces dpnInterfaces : dpnInterfaceLists){
407             if(dpnInterfaces.getDpId().equals(interfaceInfo.getDpId())) {
408                 continue;
409             }
410             List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
411             for(String remoteIf : remoteElanInterfaces) {
412                 ElanInterfaceMac elanIfMac = ElanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
413                 InterfaceInfo remoteInterface = elanServiceProvider.getInterfaceManager().getInterfaceInfo(remoteIf);
414                 if(elanIfMac == null) {
415                     continue;
416                 }
417                 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
418                 if(remoteMacEntries != null) {
419                     for (MacEntry macEntry : remoteMacEntries) {
420                         PhysAddress physAddress = macEntry.getMacAddress();
421                         ElanUtils.setupRemoteDmacFlow(interfaceInfo.getDpId(), remoteInterface.getDpId(),
422                             remoteInterface.getInterfaceTag(),
423                             elanInstance.getElanTag(),
424                             physAddress.getValue(),
425                             elanInstance.getElanInstanceName(), writeFlowGroupTx);
426                     }
427                 }
428             }
429         }
430     }
431
432     void addElanInterface(ElanInterface elanInterface, InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
433         Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
434         Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
435         Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
436
437         String interfaceName = elanInterface.getName();
438         String elanInstanceName = elanInterface.getElanInstanceName();
439
440         Elan elanInfo = ElanUtils.getElanByName(elanInstanceName);
441         WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
442         if (elanInfo == null) {
443             List<String> elanInterfaces = new ArrayList<String>();
444             elanInterfaces.add(interfaceName);
445             ElanUtils.updateOperationalDataStore(elanServiceProvider.getBroker(), elanServiceProvider.getIdManager(), elanInstance, elanInterfaces, tx);
446         } else {
447             createElanStateList(elanInstanceName, interfaceName, tx);
448         }
449         boolean isFirstInterfaceInDpn = false;
450         // Specific actions to the DPN where the ElanInterface has been added, for example, programming the
451         // External tunnel table if needed or adding the ElanInterface to the DpnInterfaces in the operational DS.
452         BigInteger dpId = ( interfaceInfo != null ) ? dpId = interfaceInfo.getDpId() : null;
453         DpnInterfaces dpnInterfaces = null;
454         if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
455             InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
456             Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
457             if (!existingElanDpnInterfaces.isPresent()) {
458                 isFirstInterfaceInDpn = true;
459                 // ELAN's 1st ElanInterface added to this DPN
460                 dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
461                 // The 1st ElanInterface in a DPN must program the Ext Tunnel table, but only if Elan has VNI
462                 if (ElanUtils.isVxlan(elanInstance)) {
463                     setExternalTunnelTable(dpId, elanInstance);
464                 }
465                 ElanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance);
466             } else {
467                 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
468                 elanInterfaces.add(interfaceName);
469                 if (elanInterfaces.size() == 1) {//1st dpn interface
470                     ElanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance);
471                 }
472                 dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
473             }
474         }
475
476         // add code to install Local/Remote BC group, unknow DMAC entry, terminating service table flow entry
477         // call bindservice of interfacemanager to create ingress table flow enty.
478         //Add interface to the ElanInterfaceForwardingEntires Container
479         createElanInterfaceTablesList(interfaceName, tx);
480         if (interfaceInfo != null) {
481             installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces, isFirstInterfaceInDpn, tx);
482         }
483         ElanUtils.waitForTransactionToComplete(tx);
484
485         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
486         InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(interfaceName, elanInterface,
487             interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
488         coordinator.enqueueJob(interfaceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
489     }
490
491     void setupEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
492                                       InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) {
493         String elanInstanceName = elanInstance.getElanInstanceName();
494         String interfaceName = elanInterface.getName();
495         WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
496         BigInteger dpId = interfaceInfo.getDpId();
497         WriteTransaction writeFlowGroupTx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
498         installEntriesForElanInterface(elanInstance, interfaceInfo, isFirstInterfaceInDpn, tx, writeFlowGroupTx);
499         List<PhysAddress> staticMacAddresses = elanInterface.getStaticMacEntries();
500         if (staticMacAddresses != null) {
501             boolean isInterfaceOperational = isOperational(interfaceInfo);
502             for (PhysAddress physAddress : staticMacAddresses) {
503                 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
504                 Optional<MacEntry> existingMacEntry = ElanUtils.read(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, macId);
505                 if (existingMacEntry.isPresent()) {
506                     elanServiceProvider.getElanForwardingEntriesHandler().updateElanInterfaceForwardingTablesList(elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
507                         existingMacEntry.get(), tx);
508                 } else {
509                     elanServiceProvider.getElanForwardingEntriesHandler().addElanInterfaceForwardingTableList(elanInstance, interfaceName, physAddress, tx);
510                 }
511
512                 if ( isInterfaceOperational ) {
513                     // Setting SMAC, DMAC, UDMAC in this DPN and also in other DPNs
514                     ElanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT, physAddress.getValue(), writeFlowGroupTx);
515                 }
516             }
517
518             if ( isInterfaceOperational ) {
519                 // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop on purpose.
520                 ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId, staticMacAddresses);
521             }
522         }
523         ElanUtils.waitForTransactionToComplete(tx);
524         ElanUtils.waitForTransactionToComplete(writeFlowGroupTx);
525     }
526
527     protected void removeInterfaceStaticMacEntires(String elanInstanceName, String interfaceName, PhysAddress physAddress) {
528         InterfaceInfo interfaceInfo = elanServiceProvider.getInterfaceManager().getInterfaceInfo(interfaceName);
529         InstanceIdentifier<MacEntry> macId =  getMacEntryOperationalDataPath(elanInstanceName, physAddress);
530         Optional<MacEntry> existingMacEntry = ElanUtils.read(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, macId);
531
532         if (!existingMacEntry.isPresent()) {
533             return;
534         }
535
536         MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName).setKey(new MacEntryKey(physAddress)).build();
537         WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
538         elanServiceProvider.getElanForwardingEntriesHandler().deleteElanInterfaceForwardingEntries(ElanUtils.getElanInstanceByName(elanInstanceName), interfaceInfo, macEntry, tx);
539         elanServiceProvider.getElanForwardingEntriesHandler().deleteElanInterfaceMacForwardingEntries(interfaceName, physAddress, tx);
540         ElanUtils.waitForTransactionToComplete(tx);
541     }
542
543
544     private InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
545         return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class,
546             new MacTableKey(elanName)).child(MacEntry.class, new MacEntryKey(physAddress)).build();
547     }
548
549     private void installEntriesForElanInterface(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
550                                                 boolean isFirstInterfaceInDpn, WriteTransaction tx, WriteTransaction writeFlowGroupTx) {
551         if (!isOperational(interfaceInfo)) {
552             return;
553         }
554         BigInteger dpId = interfaceInfo.getDpId();
555         ElanUtils.setupTermDmacFlows(interfaceInfo, elanServiceProvider.getMdsalManager(), writeFlowGroupTx);
556         setupFilterEqualsTable(elanInstance, interfaceInfo, writeFlowGroupTx);
557         if (isFirstInterfaceInDpn) {
558             //Terminating Service , UnknownDMAC Table.
559             setupTerminateServiceTable(elanInstance, dpId, writeFlowGroupTx);
560             setupUnknownDMacTable(elanInstance, dpId, writeFlowGroupTx);
561             //update the remote-DPNs remoteBC group entry with Tunnels
562             setElanBCGrouponOtherDpns(elanInstance, dpId, writeFlowGroupTx);
563             /*
564              * Install remote DMAC flow.
565              * This is required since this DPN is added later to the elan instance
566              * and remote DMACs of other interfaces in this elan instance are not present in the current dpn.
567              */
568             programRemoteDmacFlow(elanInstance, interfaceInfo, writeFlowGroupTx);
569         }
570         // bind the Elan service to the Interface
571         bindService(elanInstance, interfaceInfo.getInterfaceName(), tx);
572     }
573
574     public void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, DpnInterfaces dpnInterfaces,
575                                                      boolean isFirstInterfaceInDpn, WriteTransaction tx) {
576         if (!isOperational(interfaceInfo)) {
577             return;
578         }
579         // LocalBroadcast Group creation with elan-Interfaces
580         setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
581         if (isFirstInterfaceInDpn) {
582             logger.trace("waitTimeForSyncInstall is {}", waitTimeForSyncInstall);
583             BigInteger dpId = interfaceInfo.getDpId();
584             // RemoteBroadcast Group creation
585             try {
586                 Thread.sleep(waitTimeForSyncInstall);
587             } catch (InterruptedException e1) {
588                 logger.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
589             }
590             setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId);
591             try {
592                 Thread.sleep(waitTimeForSyncInstall);
593             } catch (InterruptedException e1) {
594                 logger.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
595             }
596         }
597     }
598
599     public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo, WriteTransaction writeFlowGroupTx) {
600         int ifTag = interfaceInfo.getInterfaceTag();
601         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE, getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag),
602             9, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), getTunnelIdMatchForFilterEqualsLPortTag(ifTag), ElanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
603
604         elanServiceProvider.getMdsalManager().addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx);
605
606         Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE, getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, 1000+ifTag),
607             10, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), getMatchesForFilterEqualsLPortTag(ifTag),
608             MDSALUtil.buildInstructionsDrop());
609
610         elanServiceProvider.getMdsalManager().addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx);
611     }
612
613     public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo, WriteTransaction deleteFlowGroupTx) {
614         int ifTag = interfaceInfo.getInterfaceTag();
615         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE, getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag),
616             9, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), getTunnelIdMatchForFilterEqualsLPortTag(ifTag), ElanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
617
618         elanServiceProvider.getMdsalManager().removeFlowToTx(interfaceInfo.getDpId(), flow, deleteFlowGroupTx);
619
620         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE, getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, 1000+ifTag),
621             10, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), getMatchesForFilterEqualsLPortTag(ifTag),
622             MDSALUtil.buildInstructionsDrop());
623
624         elanServiceProvider.getMdsalManager().removeFlowToTx(interfaceInfo.getDpId(), flowEntity, deleteFlowGroupTx);
625     }
626
627     private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo,
628                                                      int bucketKeyStart, InterfaceInfo interfaceInfo) {
629         return getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(), bucketKeyStart);
630     }
631
632     private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId, int bucketId) {
633         int elanTag = elanInfo.getElanTag().intValue();
634         List<Bucket> listBucketInfo = new ArrayList<Bucket>();
635         ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
636         listBucketInfo.addAll(getRemoteBCGroupTunnelBuckets(elanDpns, dpnId, bucketId, elanTag));
637         listBucketInfo.addAll(getRemoteBCGroupExternalPortBuckets(elanDpns, dpnInterfaces, dpnId, bucketId));
638         listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId));
639         return listBucketInfo;
640     }
641
642     private List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, BigInteger dpnId, int bucketId,
643             int elanTag) {
644         List<Bucket> listBucketInfo = new ArrayList<Bucket>();
645         if (elanDpns != null) {
646             for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
647                 if (ElanUtils.isDpnPresent(dpnInterface.getDpId()) && dpnInterface.getDpId() != dpnId
648                         && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
649                     try {
650                         List<Action> listActionInfo = ElanUtils.getInternalTunnelItmEgressAction(dpnId,
651                                 dpnInterface.getDpId(), elanTag);
652                         if (listActionInfo.isEmpty()) {
653                             continue;
654                         }
655                         listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
656                                 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
657                         bucketId++;
658                     } catch (Exception ex) {
659                         logger.error("Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
660                                 dpnId, dpnInterface.getDpId());
661                     }
662                 }
663             }
664         }
665         return listBucketInfo;
666     }
667
668     private List<Bucket> getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns, DpnInterfaces dpnInterfaces, BigInteger dpnId,
669             int bucketId) {
670         DpnInterfaces currDpnInterfaces = dpnInterfaces != null ? dpnInterfaces : getDpnInterfaces(elanDpns, dpnId);
671         if (currDpnInterfaces == null || !ElanUtils.isDpnPresent(currDpnInterfaces.getDpId())
672                 || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) {
673             return Collections.emptyList();
674         }
675
676         List<Bucket> listBucketInfo = new ArrayList<Bucket>();
677         for (String interfaceName : currDpnInterfaces.getInterfaces()) {
678             if (ElanUtils.isExternal(interfaceName)) {
679                 List<Action> listActionInfo = ElanUtils.getExternalPortItmEgressAction(interfaceName);
680                 if (!listActionInfo.isEmpty()) {
681                     listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
682                             MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
683                     bucketId++;
684                 }
685             }
686         }
687         return listBucketInfo;
688     }
689
690     private DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, BigInteger dpnId) {
691         if (elanDpns != null) {
692             for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
693                 if (dpnInterface.getDpId() == dpnId) {
694                     return dpnInterface;
695                 }
696             }
697         }
698         return null;
699     }
700
701     private void setElanBCGrouponOtherDpns(ElanInstance elanInfo,
702                                            BigInteger dpId, WriteTransaction tx) {
703         int elanTag = elanInfo.getElanTag().intValue();
704         long groupId = ElanUtils.getElanRemoteBCGID(elanTag);
705         List<Bucket> listBucket = new ArrayList<Bucket>();
706         int bucketId = 0;
707         ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
708         if (elanDpns != null) {
709             List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
710             for(DpnInterfaces dpnInterface : dpnInterfaceses) {
711                 List<Bucket> remoteListBucketInfo = new ArrayList<Bucket>();
712                 if (ElanUtils.isDpnPresent(dpnInterface.getDpId()) && !dpnInterface.getDpId().equals(dpId) && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
713                     List<Action> listAction = new ArrayList<Action>();
714                     int actionKey = 0;
715                     listAction.add((new ActionInfo(ActionType.group, new String[] {String.valueOf(ElanUtils.getElanLocalBCGID(elanTag))}, ++actionKey)).buildAction());
716                     listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
717                     bucketId++;
718                     remoteListBucketInfo.addAll(listBucket);
719                     for(DpnInterfaces otherFes : dpnInterfaceses) {
720                         if (ElanUtils.isDpnPresent(otherFes.getDpId()) && otherFes.getDpId() != dpnInterface.getDpId()
721                             && otherFes.getInterfaces() != null && ! otherFes.getInterfaces().isEmpty()) {
722                             try {
723                                 List<Action> remoteListActionInfo = ElanUtils.getInternalTunnelItmEgressAction(dpnInterface.getDpId(), otherFes.getDpId(), elanTag);
724                                 if (!remoteListActionInfo.isEmpty()) {
725                                     remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,MDSALUtil.WATCH_GROUP));
726                                     bucketId++;
727                                 }
728                             } catch (Exception ex) {
729                                 logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnInterface.getDpId(), otherFes.getDpId() );
730                                 return;
731                             }
732                         }
733                     }
734                     List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpId,
735                         bucketId);
736                     remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
737
738                     if (remoteListBucketInfo.size() == 0) {
739                         logger.debug( "No ITM is present on Dpn - {} " ,dpnInterface.getDpId());
740                         continue;
741                     }
742                     Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(remoteListBucketInfo));
743                     elanServiceProvider.getMdsalManager().addGroupToTx(dpnInterface.getDpId(), group, tx);
744                 }
745             }
746         }
747     }
748
749     /**
750      * Returns the bucket info with the given interface as the only bucket.
751      */
752     private Bucket getLocalBCGroupBucketInfo(InterfaceInfo interfaceInfo, int bucketIdStart) {
753         return MDSALUtil.buildBucket(getInterfacePortActions(interfaceInfo), MDSALUtil.GROUP_WEIGHT, bucketIdStart, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP);
754     }
755
756     private List<MatchInfo> getMatchesForElanTag(Long elanTag) {
757         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
758         // Matching metadata
759         mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
760             ElanUtils.getElanMetadataLabel(elanTag),
761             MetaDataUtil.METADATA_MASK_SERVICE }));
762         return mkMatches;
763     }
764
765
766     private List<MatchInfo> buildMatchesForVni(Long vni) {
767         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
768         MatchInfo match = new MatchInfo(MatchFieldType.tunnel_id,
769             new BigInteger[]{BigInteger.valueOf(vni)} );
770         mkMatches.add(match);
771         return mkMatches;
772     }
773
774     private List<Instruction> getInstructionsForOutGroup(
775         long groupId) {
776         List<Instruction> mkInstructions = new ArrayList<Instruction>();
777         List <Action> actions = new ArrayList <Action> ();
778         actions.add(new ActionInfo(ActionType.group, new String[]{Long.toString(groupId)}).buildAction());
779         mkInstructions.add(MDSALUtil.getWriteActionsInstruction(actions, 0));
780         return mkInstructions;
781     }
782
783     private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
784         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
785         // Matching metadata
786         mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
787             ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet),
788             MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG}));
789         return mkMatches;
790     }
791
792     /**
793      * Builds the list of instructions to be installed in the External Tunnel table (38), which so far
794      * consists in writing the elanTag in metadata and send packet to the new DHCP table
795      *
796      * @param elanTag elanTag to be written in metadata when flow is selected
797      * @return the instructions ready to be installed in a flow
798      */
799     private List<InstructionInfo> getInstructionsExtTunnelTable(Long elanTag) {
800         List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
801         mkInstructions.add(new InstructionInfo(InstructionType.write_metadata,
802             new BigInteger[] {
803                 ElanUtils.getElanMetadataLabel(elanTag),
804                 ElanUtils.getElanMetadataMask()
805             } ) );
806         // TODO: We should point to SMAC or DMAC depending on a configuration property to enable
807         // mac learning
808         mkInstructions.add(new InstructionInfo(InstructionType.goto_table,
809             new long[] { NwConstants.ELAN_DMAC_TABLE }));
810
811         return mkInstructions;
812     }
813
814     // Install DMAC entry on dst DPN
815     public void installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId) {
816         String interfaceName = interfaceInfo.getInterfaceName();
817         ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
818         if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
819             WriteTransaction writeFlowTx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
820             List<MacEntry> macEntries =  elanInterfaceMac.getMacEntry();
821             for(MacEntry macEntry : macEntries) {
822                 PhysAddress physAddress = macEntry.getMacAddress();
823                 ElanUtils.setupDMacFlowonRemoteDpn(elanInfo, interfaceInfo, dstDpId, physAddress.getValue(), writeFlowTx);
824             }
825             writeFlowTx.submit();
826         }
827     }
828
829     public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId) {
830         setupElanBroadcastGroups(elanInfo, null, dpnId);
831     }
832
833     public void setupElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
834         List<Bucket> listBucket = new ArrayList<Bucket>();
835         int bucketId = 0;
836         int actionKey = 0;
837         Long elanTag = elanInfo.getElanTag();
838         long groupId = ElanUtils.getElanRemoteBCGID(elanTag);
839         List<Action> listAction = new ArrayList<Action>();
840         listAction.add((new ActionInfo(ActionType.group, new String[] {String.valueOf(ElanUtils.getElanLocalBCGID(elanTag))}, ++actionKey)).buildAction());
841         listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
842         bucketId++;
843         List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId);
844         listBucket.addAll(listBucketInfoRemote);
845         Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket));
846         logger.trace("Installing the remote BroadCast Group:{}", group);
847         elanServiceProvider.getMdsalManager().syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
848     }
849
850     public void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface, InterfaceInfo interfaceInfo) {
851         List<Bucket> listBucket = new ArrayList<Bucket>();
852         int bucketId = 0;
853         BigInteger dpnId = interfaceInfo.getDpId();
854         long groupId = ElanUtils.getElanLocalBCGID(elanInfo.getElanTag());
855
856         List<String> interfaces = new ArrayList<String>();
857         if (newDpnInterface != null) {
858             interfaces = newDpnInterface.getInterfaces();
859         }
860         for(String ifName : interfaces) {
861             // In case if there is a InterfacePort in the cache which is not in
862             // operational state, skip processing it
863             InterfaceInfo ifInfo = elanServiceProvider.getInterfaceManager().getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
864             if (!isOperational(ifInfo)) {
865                 continue;
866             }
867
868             if (!ElanUtils.isExternal(ifName)) {
869                 listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
870                         MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
871                 bucketId++;
872             }
873         }
874
875         Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket));
876         logger.trace("installing the localBroadCast Group:{}", group);
877         elanServiceProvider.getMdsalManager().syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
878     }
879
880     public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo, WriteTransaction deleteFlowGroupTx) {
881         BigInteger dpnId = interfaceInfo.getDpId();
882         long groupId = ElanUtils.getElanLocalBCGID(elanInfo.getElanTag());
883         List<Bucket> listBuckets = new ArrayList<>();
884         int bucketId = 0;
885         listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
886         //listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1, interfaceInfo));
887         Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBuckets));
888         logger.trace("deleted the localBroadCast Group:{}", group);
889         elanServiceProvider.getMdsalManager().removeGroupToTx(dpnId, group, deleteFlowGroupTx);
890     }
891
892     public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo, WriteTransaction deleteFlowGroupTx) {
893         int bucketId = 0;
894         int actionKey = 0;
895         Long elanTag = elanInfo.getElanTag();
896         List<Bucket> listBuckets = new ArrayList<>();
897         List<Action> listAction = new ArrayList<Action>();
898         listAction.add((new ActionInfo(ActionType.group, new String[] {String.valueOf(ElanUtils.getElanLocalBCGID(elanTag))}, ++actionKey)).buildAction());
899         listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
900         bucketId++;
901         listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo));
902         BigInteger dpnId = interfaceInfo.getDpId();
903         long groupId = ElanUtils.getElanRemoteBCGID(elanInfo.getElanTag());
904         Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBuckets));
905         logger.trace("deleting the remoteBroadCast group:{}", group);
906         elanServiceProvider.getMdsalManager().removeGroupToTx(dpnId, group, deleteFlowGroupTx);
907     }
908
909     /**
910      * Installs a flow in the External Tunnel table consisting in translating
911      * the VNI retrieved from the packet that came over a tunnel with a TOR into
912      * elanTag that will be used later in the ELANs pipeline.
913      *
914      * @param dpnId
915      *            the dpn id
916      * @param elanInfo
917      *            the elan info
918      */
919     public void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
920         long elanTag = elanInfo.getElanTag();
921         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId,
922             NwConstants.EXTERNAL_TUNNEL_TABLE,
923             getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag),
924             5,  // prio
925             elanInfo.getElanInstanceName(),  // flowName
926             0,  // idleTimeout
927             0,  // hardTimeout
928             ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
929             buildMatchesForVni(elanInfo.getSegmentationId()),
930             getInstructionsExtTunnelTable(elanTag) );
931
932         elanServiceProvider.getMdsalManager().installFlow(flowEntity);
933     }
934
935     /**
936      * Removes, from External Tunnel table, the flow that translates from VNI to elanTag.
937      * Important: ensure this method is only called whenever there is no other ElanInterface in the specified DPN
938      *
939      * @param dpnId DPN whose Ext Tunnel table is going to be modified
940      * @param elanInfo holds the elanTag needed for selecting the flow to be removed
941      */
942     public void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
943         // TODO: Use DataStoreJobCoordinator in order to avoid that removing the last ElanInstance plus
944         // adding a new one does (almost at the same time) are executed in that exact order
945
946         String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
947         FlowEntity flowEntity = new FlowEntity(dpnId);
948         flowEntity.setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE);
949         flowEntity.setFlowId(flowId);
950         elanServiceProvider.getMdsalManager().removeFlow(flowEntity);
951     }
952
953     public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
954         long elanTag = elanInfo.getElanTag();
955         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE, getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, elanTag),
956             5, String.format("%s:%d","ITM Flow Entry ",elanTag), 0,  0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), ElanUtils.getTunnelMatchesForServiceId((int)elanTag),
957             getInstructionsForOutGroup(ElanUtils.getElanLocalBCGID(elanTag)));
958
959         elanServiceProvider.getMdsalManager().addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
960     }
961
962     public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
963         long elanTag = elanInfo.getElanTag();
964         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag, /*SH flag*/false),
965             5, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)), getMatchesForElanTag(elanTag, /*SH flag*/false),
966             getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGID(elanTag)));
967
968         elanServiceProvider.getMdsalManager().addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
969
970         // only if ELAN can connect to external network, perform the following
971         if (ElanUtils.isVxlan(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
972             Flow flowEntity2 = MDSALUtil.buildFlowNew(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag, /*SH flag*/true),
973                 5, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)), getMatchesForElanTag(elanTag, /*SH flag*/true),
974                 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGID(elanTag)));
975             elanServiceProvider.getMdsalManager().addFlowToTx(dpId, flowEntity2, writeFlowGroupTx);
976         }
977
978     }
979
980     private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, WriteTransaction deleteFlowGroupTx) {
981         //        Flow flow = getUnknownDmacFlowEntity(dpId, elanInfo);
982         //        mdsalManager.removeFlow(dpId, flow);
983         Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
984             elanInfo.getElanTag(), /*SH flag*/ false)))
985             .setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
986             .build();
987         elanServiceProvider.getMdsalManager().removeFlowToTx(dpId, flow, deleteFlowGroupTx);
988
989         if (ElanUtils.isVxlan(elanInfo)) {
990             Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
991                 elanInfo.getElanTag(), /*SH flag*/ true)))
992                 .setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
993                 .build();
994             elanServiceProvider.getMdsalManager().removeFlowToTx(dpId, flow2, deleteFlowGroupTx);
995         }
996
997
998     }
999
1000     private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
1001         ElanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
1002     }
1003
1004     private void bindService(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
1005         // interfaceManager.bindService(interfaceName, ElanUtils.getServiceInfo(elanInfo.getElanInstanceName(), elanInfo.getElanTag(), interfaceName));
1006
1007         int priority = ElanConstants.ELAN_SERVICE_PRIORITY;
1008         int instructionKey = 0;
1009         List<Instruction> instructions = new ArrayList<Instruction>();
1010         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanUtils.getElanMetadataLabel(elanInfo.getElanTag()), MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
1011         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ELAN_SMAC_TABLE, ++instructionKey));
1012         BoundServices
1013             serviceInfo =
1014             ElanUtils.getBoundServices(String.format("%s.%s.%s", "vpn",elanInfo.getElanInstanceName(), interfaceName),
1015                 NwConstants.ELAN_SERVICE_INDEX, priority,
1016                 NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
1017         tx.put(LogicalDatastoreType.CONFIGURATION,
1018             ElanUtils.buildServiceId(interfaceName, NwConstants.ELAN_SERVICE_INDEX), serviceInfo, true);
1019     }
1020
1021     private void unbindService(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
1022         tx.delete(LogicalDatastoreType.CONFIGURATION, ElanUtils.buildServiceId(interfaceName,NwConstants.ELAN_SERVICE_INDEX));
1023     }
1024
1025     private String getFlowRef(long tableId, long elanTag) {
1026         return new StringBuffer().append(tableId).append(elanTag).toString();
1027     }
1028
1029     private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
1030         return new StringBuffer().append(tableId).append(elanTag).append(shFlag).toString();
1031     }
1032
1033     private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
1034         List<Action> listAction = new ArrayList<Action>();
1035         int actionKey = 0;
1036         listAction.add((new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {BigInteger.valueOf(interfaceInfo.getInterfaceTag())}, actionKey)).buildAction());
1037         actionKey++;
1038         listAction.add((new ActionInfo(ActionType.nx_resubmit,
1039             new String[] {String.valueOf(NwConstants.ELAN_FILTER_EQUALS_TABLE)}, actionKey)).buildAction());
1040         return listAction;
1041     }
1042
1043     private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId, List<String> interfaceNames, WriteTransaction tx) {
1044         DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId)
1045             .setInterfaces(interfaceNames).setKey(new DpnInterfacesKey(dpId)).build();
1046         tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId),
1047             dpnInterface, true);
1048         return dpnInterface;
1049     }
1050
1051     /**
1052      * Delete elan dpn interface from operational DS.
1053      *
1054      * @param elanInstanceName
1055      *            the elan instance name
1056      * @param dpId
1057      *            the dp id
1058      */
1059     private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId, WriteTransaction tx) {
1060         tx.delete(LogicalDatastoreType.OPERATIONAL,
1061             ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId));
1062     }
1063
1064     private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId, WriteTransaction tx) {
1065         List<String> interfaceNames = new ArrayList<String>();
1066         interfaceNames.add(interfaceName);
1067         DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId)
1068             .setInterfaces(interfaceNames).setKey(new DpnInterfacesKey(dpId)).build();
1069         tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId),
1070             dpnInterface, true);
1071         return dpnInterface;
1072     }
1073
1074     private void createElanInterfaceTablesList(String interfaceName, WriteTransaction tx) {
1075         InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
1076         Optional<ElanInterfaceMac> interfaceMacTables = ElanUtils.read(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
1077         // Adding new Elan Interface Port to the operational DataStore without Static-Mac Entries..
1078         if (!interfaceMacTables.isPresent()) {
1079             ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName).setKey(new ElanInterfaceMacKey(interfaceName)).build();
1080             tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName),
1081                 elanInterfaceMacTable, true);
1082         }
1083     }
1084
1085     private void createElanStateList(String elanInstanceName, String interfaceName, WriteTransaction tx) {
1086         InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
1087         Optional<Elan> elanInterfaceLists = ElanUtils.read(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, elanInstance);
1088         // Adding new Elan Interface Port to the operational DataStore without Static-Mac Entries..
1089         if (elanInterfaceLists.isPresent()) {
1090             List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
1091             if (interfaceLists == null) {
1092                 interfaceLists = new ArrayList<>();
1093             }
1094             interfaceLists.add(interfaceName);
1095             Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists).setKey(new ElanKey(elanInstanceName)).build();
1096             tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState, true);
1097         }
1098     }
1099
1100     private boolean isOperational(InterfaceInfo interfaceInfo) {
1101         if (interfaceInfo == null) {
1102             return false;
1103         }
1104         return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
1105     }
1106
1107     public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
1108         ElanDpnInterfaces dpnInterfaceLists =  ElanUtils.getElanDpnInterfacesList();
1109         if (dpnInterfaceLists == null) {
1110             return;
1111         }
1112         List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1113         for(ElanDpnInterfacesList elanDpns: elanDpnIf) {
1114             int cnt = 0;
1115             String elanName = elanDpns.getElanInstanceName();
1116             List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
1117             if (dpnInterfaces == null) {
1118                 continue;
1119             }
1120             for (DpnInterfaces dpnIf : dpnInterfaces) {
1121                 if (dpnIf.getDpId().equals(srcDpId) || dpnIf.getDpId().equals(dstDpId)) {
1122                     cnt++;
1123                 }
1124             }
1125             if (cnt == 2) {
1126                 logger.debug("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
1127                 ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
1128                 // update Remote BC Group
1129                 setupElanBroadcastGroups(elanInfo, srcDpId);
1130
1131                 DpnInterfaces dpnInterface = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dstDpId);
1132                 Set<String> interfaceLists = new HashSet<>();
1133                 interfaceLists.addAll(dpnInterface.getInterfaces());
1134                 for(String ifName : interfaceLists) {
1135                     InterfaceInfo interfaceInfo = elanServiceProvider.getInterfaceManager().getInterfaceInfo(ifName);
1136                     if (isOperational(interfaceInfo)) {
1137                         installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
1138                     }
1139                 }
1140             }
1141
1142         }
1143     }
1144
1145     /**
1146      * Handle external tunnel state event.
1147      *
1148      * @param externalTunnel
1149      *            the external tunnel
1150      * @param intrf
1151      *            the interface
1152      */
1153     public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1154         if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
1155             return;
1156         }
1157         // dpId/externalNodeId will be available either in source or destination
1158         // based on the tunnel end point
1159         BigInteger dpId = null;
1160         NodeId externalNodeId = null;
1161         if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
1162             dpId = new BigInteger(externalTunnel.getSourceDevice());
1163             externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
1164         } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
1165             dpId = new BigInteger(externalTunnel.getDestinationDevice());
1166             externalNodeId = new NodeId(externalTunnel.getSourceDevice());
1167         }
1168         if (dpId == null || externalNodeId == null) {
1169             logger.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
1170             return;
1171         }
1172
1173         ElanDpnInterfaces dpnInterfaceLists = ElanUtils.getElanDpnInterfacesList();
1174         if (dpnInterfaceLists == null) {
1175             return;
1176         }
1177         List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
1178         for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
1179             String elanName = elanDpns.getElanInstanceName();
1180             ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
1181
1182             DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
1183             if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
1184                 || dpnInterfaces.getInterfaces().isEmpty()) {
1185                 continue;
1186             }
1187             logger.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
1188
1189             setupElanBroadcastGroups(elanInfo, dpId);
1190             // install L2gwDevices local macs in dpn.
1191             ElanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo);
1192             // Install dpn macs on external device
1193             ElanL2GatewayUtils.installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
1194                 externalNodeId);
1195         }
1196         logger.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
1197     }
1198
1199     /**
1200      * Validate external tunnel state event.
1201      *
1202      * @param externalTunnel
1203      *            the external tunnel
1204      * @param intrf
1205      *            the intrf
1206      * @return true, if successful
1207      */
1208     private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
1209         if (intrf.getOperStatus() == Interface.OperStatus.Up) {
1210             String srcDevice = externalTunnel.getDestinationDevice();
1211             String destDevice = externalTunnel.getSourceDevice();
1212             ExternalTunnel otherEndPointExtTunnel = ElanUtils.getExternalTunnel(srcDevice, destDevice,
1213                 LogicalDatastoreType.CONFIGURATION);
1214             if (logger.isTraceEnabled()) {
1215                 logger.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
1216                     otherEndPointExtTunnel);
1217             }
1218             if (otherEndPointExtTunnel != null) {
1219                 boolean otherEndPointInterfaceOperational = ElanUtils
1220                     .isInterfaceOperational(otherEndPointExtTunnel.getTunnelInterfaceName(), elanServiceProvider.getBroker());
1221                 if (otherEndPointInterfaceOperational) {
1222                     return true;
1223                 } else {
1224                     logger.debug("Other end [{}] of the external tunnel is not yet UP for {}",
1225                         otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
1226                 }
1227             }
1228         }
1229         return false;
1230     }
1231
1232     private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int LportTag) {
1233         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
1234         // Matching metadata
1235         mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
1236             MetaDataUtil.getLportTagMetaData(LportTag),
1237             MetaDataUtil.METADATA_MASK_LPORT_TAG }));
1238         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(LportTag)}));
1239         return mkMatches;
1240     }
1241
1242
1243     private List<MatchInfo> getTunnelIdMatchForFilterEqualsLPortTag(int LportTag) {
1244         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
1245         // Matching metadata
1246         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {
1247             BigInteger.valueOf(LportTag)}));
1248         return mkMatches;
1249     }
1250
1251     public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo) {
1252         List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
1253         if (dpns == null) {
1254             return;
1255         }
1256         for (DpnInterfaces dpn : dpns) {
1257             setupElanBroadcastGroups(elanInfo, dpn.getDpId());
1258         }
1259     }
1260
1261     public static List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
1262                                                                         int bucketId) {
1263         List<Bucket> listBucketInfo = new ArrayList<Bucket>();
1264         ConcurrentMap<String, L2GatewayDevice> map = ElanL2GwCacheUtils
1265             .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
1266         for (L2GatewayDevice device : map.values()) {
1267             String interfaceName = ElanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
1268                 device.getHwvtepNodeId());
1269             if (interfaceName == null) {
1270                 continue;
1271             }
1272             List<Action> listActionInfo = ElanUtils.buildTunnelItmEgressActions(interfaceName, elanInfo.getSegmentationId());
1273             listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
1274                 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
1275             bucketId++;
1276         }
1277         return listBucketInfo;
1278     }
1279
1280     public ElanServiceProvider getElanServiceProvider() {
1281         return elanServiceProvider;
1282     }
1283
1284     public void setElanServiceProvider(ElanServiceProvider elanServiceProvider) {
1285         this.elanServiceProvider = elanServiceProvider;
1286     }
1287
1288
1289     @Override
1290     protected ElanInterfaceManager getDataTreeChangeListener() {
1291         return this;
1292     }
1293
1294 }
1295
1296