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