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