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