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