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