BUG:5021 ELan datapath code-changes and cleanUp some code.
[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 com.google.common.base.Optional;
11 import com.google.common.collect.Lists;
12 import com.google.common.collect.Maps;
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
15 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.vpnservice.elan.utils.ElanConstants;
18 import org.opendaylight.vpnservice.elan.utils.ElanUtils;
19 import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
20 import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo.InterfaceType;
21 import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
22 import org.opendaylight.vpnservice.itm.api.IITMProvider;
23
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
26 import org.opendaylight.vpnservice.mdsalutil.*;
27 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanForwardingTables;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanInterfaces;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMacKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.forwarding.tables.MacTable;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.forwarding.tables.MacTableKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstanceBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.interfaces.ElanInterface;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.state.Elan;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.state.ElanBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.state.ElanKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntry;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntryBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntryKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
55 import org.opendaylight.yangtools.concepts.ListenerRegistration;
56 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 import java.math.BigInteger;
61 import java.util.*;
62 import java.util.concurrent.ConcurrentHashMap;
63 import java.util.concurrent.ConcurrentLinkedQueue;
64
65
66 public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterface> implements AutoCloseable {
67
68     private static ElanInterfaceManager elanInterfaceManager = new ElanInterfaceManager();
69     private ListenerRegistration<DataChangeListener> elanInterfaceListenerRegistration;
70     private ListenerRegistration<DataChangeListener> itmInterfaceListenerRegistration;
71     private OdlInterfaceRpcService interfaceManagerRpcService;
72     private DataBroker broker;
73     private IMdsalApiManager mdsalManager;
74     private IInterfaceManager interfaceManager;
75     private IdManagerService idManager;
76     private IITMProvider itmManager;
77     private ElanForwardingEntriesHandler elanForwardingEntriesHandler;
78     private Map<String, ConcurrentLinkedQueue<ElanInterface>> unProcessedElanInterfaces =
79             new ConcurrentHashMap<String, ConcurrentLinkedQueue<ElanInterface>> ();
80
81     private static final Logger logger = LoggerFactory.getLogger(ElanInterfaceManager.class);
82
83     public ElanInterfaceManager() {
84         super(ElanInterface.class);
85     }
86
87     public static ElanInterfaceManager getElanInterfaceManager() {
88         return elanInterfaceManager;
89     }
90
91     public void setMdSalApiManager(IMdsalApiManager mdsalManager) {
92         this.mdsalManager = mdsalManager;
93     }
94
95     public void setInterfaceManagerRpcService(OdlInterfaceRpcService ifManager) {
96         this.interfaceManagerRpcService = ifManager;
97     }
98
99     public void setElanForwardingEntriesHandler(ElanForwardingEntriesHandler elanForwardingEntriesHandler) {
100         this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
101     }
102
103     public void setInterfaceManager(IInterfaceManager interfaceManager) {
104         this.interfaceManager = interfaceManager;
105     }
106
107     public void setDataBroker(DataBroker broker) {
108         this.broker = broker;
109     }
110
111     public void setIITMManager(IITMProvider itmManager) {
112         this.itmManager = itmManager;
113     }
114
115     @Override
116     public void close() throws Exception {
117         if (elanInterfaceListenerRegistration != null) {
118             try {
119                 elanInterfaceListenerRegistration.close();
120             } catch (final Exception e) {
121                 logger.error("Error when cleaning up DataChangeListener.", e);
122             }
123             elanInterfaceListenerRegistration = null;
124         }
125     }
126
127     public void registerListener() {
128         try {
129             elanInterfaceListenerRegistration = broker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
130                     getElanInterfaceWildcardPath(), ElanInterfaceManager.this, DataChangeScope.SUBTREE);
131         } catch (final Exception e) {
132             logger.error("ELAN Interface DataChange listener registration failed !", e);
133             throw new IllegalStateException("ELAN Interface registration Listener failed.", e);
134         }
135     }
136
137     private InstanceIdentifier<?> getElanInterfaceWildcardPath() {
138         return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
139     }
140
141     public void setIdManager(IdManagerService idManager) {
142         this.idManager = idManager;
143     }
144
145     @Override
146     protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
147         String interfaceName =  del.getName();
148         ElanInstance elanInfo = ElanUtils.getElanInstanceByName(del.getElanInstanceName());
149         removeElanInterface(elanInfo, interfaceName);
150     }
151
152     public void removeElanService(ElanInterface del, int vlanId) {
153         ElanInstance elanInstance = ElanUtils.getElanInstanceByName(del.getElanInstanceName());
154         String interfaceName = del.getName();
155         InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName, InterfaceType.VLAN_INTERFACE);
156         removeElanInterface(elanInstance, interfaceInfo);
157         unbindService(elanInstance, interfaceName, vlanId);
158     }
159
160     public void removeElanInterface(ElanInstance elanInfo, String interfaceName) {
161         String elanName = elanInfo.getElanInstanceName();
162         InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
163         if (interfaceInfo == null) {
164             ElanInterfaceMac elanInterfaceMac =  ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
165             if(elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
166                List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
167                 for(MacEntry macEntry : macEntries) {
168                     ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getMacEntryOperationalDataPath(elanName, macEntry.getMacAddress()));
169                 }
170             }
171             ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName));
172             Elan elanState = ElanUtils.getElanByName(elanName);
173             List<String> elanInterfaces = elanState.getElanInterfaces();
174             elanInterfaces.remove(interfaceName);
175             if(elanInterfaces.isEmpty()) {
176                 ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
177                 ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
178                 ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
179                 ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION, ElanUtils.getElanInstanceConfigurationDataPath(elanName));
180             } else {
181                 Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName).setKey(new ElanKey(elanName)).build();
182                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
183             }
184             return;
185         }
186         removeElanInterface(elanInfo, interfaceInfo);
187         unbindService(elanInfo, interfaceName);
188     }
189
190     private void removeElanInterface(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
191
192         BigInteger dpId = interfaceInfo.getDpId();
193         String elanName = elanInfo.getElanInstanceName();
194         String interfaceName = interfaceInfo.getInterfaceName();
195         Elan elanState = ElanUtils.getElanByName(elanName);
196         logger.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
197         InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
198         Optional<ElanInterfaceMac> existingElanInterface = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
199         if(existingElanInterface.isPresent()) {
200             List<MacEntry> macEntries = existingElanInterface.get().getMacEntry();
201             if(macEntries != null && !macEntries.isEmpty()) {
202                 for (MacEntry macEntry : macEntries) {
203                     logger.debug("removing the  mac-entry:{} present on elanInterface:{}", macEntry.getMacAddress().getValue(), interfaceName);
204                     elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(elanInfo, interfaceInfo, macEntry);
205                 }
206             }
207         }
208
209         /*
210          *This condition check is mainly to get DPN-ID in pre-provision deletion scenario after stopping CSS
211          */
212         if(dpId.equals(ElanConstants.INVALID_DPN)) {
213             ElanDpnInterfacesList elanDpnInterfacesList = ElanUtils.getElanDpnInterfacesList(elanName);
214             if(elanDpnInterfacesList != null && !elanDpnInterfacesList.getDpnInterfaces().isEmpty()) {
215                 List<DpnInterfaces> dpnIfList = elanDpnInterfacesList.getDpnInterfaces();
216                 for (DpnInterfaces dpnInterface : dpnIfList) {
217                     DpnInterfaces dpnIfLists = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpnInterface.getDpId());
218                     if (dpnIfLists.getInterfaces().contains(interfaceName)) {
219                         logger.debug("deleting the elanInterface from the ElanDpnInterface cache in pre-provision scenario of elan:{} dpn:{} interfaceName:{}", elanName, dpId, interfaceName);
220                         removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName);
221                         break;
222                     }
223                 }
224             }
225         } else {
226             removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName);
227         }
228
229         ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
230         List<String> elanInterfaces = elanState.getElanInterfaces();
231         elanInterfaces.remove(interfaceName);
232         removeStaticELanFlows(elanInfo, interfaceInfo);
233         if(elanInterfaces.isEmpty()) {
234             ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
235             ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnOperationDataPath(elanName));
236             ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
237             ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
238             //ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION, ElanUtils.getElanInstanceConfigurationDataPath(elanName));
239         } else {
240             Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName).setKey(new ElanKey(elanName)).build();
241             MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
242         }
243     }
244
245     private void removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId, String interfaceName) {
246         DpnInterfaces dpnInterfaces =  ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
247         if(dpnInterfaces != null) {
248             List<String> interfaceLists = dpnInterfaces.getInterfaces();
249             interfaceLists.remove(interfaceName);
250             updateElanDpnInterfacesList(elanName, dpId, interfaceLists);
251         }
252     }
253
254     @Override
255     protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
256         // updating the static-Mac Entries for the existing elanInterface
257         String elanName = update.getElanInstanceName();
258         String interfaceName = update.getName();
259         InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
260         List<PhysAddress> existingPhysAddress = original.getStaticMacEntries();
261         List<PhysAddress> updatedPhysAddress = update.getStaticMacEntries();
262         if(updatedPhysAddress != null && !updatedPhysAddress.isEmpty()) {
263             List<PhysAddress> existingClonedPhyAddress = new ArrayList<>();
264             if(existingPhysAddress != null && !existingPhysAddress.isEmpty()) {
265                 existingClonedPhyAddress.addAll(0, existingPhysAddress);
266                 existingPhysAddress.removeAll(updatedPhysAddress);
267                 updatedPhysAddress.removeAll(existingClonedPhyAddress);
268                 // removing the PhyAddress which are not presented in the updated List
269                 for(PhysAddress physAddress: existingPhysAddress) {
270                     removeInterfaceStaticMacEntires(elanName, interfaceName, physAddress);
271                 }
272             }
273             // Adding the new PhysAddress which are presented in the updated List
274             if(updatedPhysAddress.size() > 0) {
275                 for(PhysAddress physAddress: updatedPhysAddress) {
276                     InstanceIdentifier<MacEntry> macId =  getMacEntryOperationalDataPath(elanName, physAddress);
277                     Optional<MacEntry> existingMacEntry = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, macId);
278                     if(existingMacEntry.isPresent()) {
279                         elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get());
280                     } else {
281                         elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(ElanUtils.getElanInstanceByName(elanName), interfaceName, physAddress);
282                     }
283                 }
284             }
285         } else if(existingPhysAddress != null && !existingPhysAddress.isEmpty()) {
286             for( PhysAddress physAddress : existingPhysAddress) {
287                 removeInterfaceStaticMacEntires(elanName, interfaceName, physAddress);
288             }
289         }
290     }
291
292     @Override
293     protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
294         String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
295         String interfaceName = elanInterfaceAdded.getName();
296         InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
297         ElanInstance elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
298
299         if (elanInstance == null) {
300             elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(elanInterfaceAdded.getDescription()).build();
301             //Add the ElanInstance in the Configuration data-store
302             ElanUtils.UpdateOperationalDataStore(broker, idManager, elanInstance);
303             elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
304         }
305
306
307         Long elanTag = elanInstance.getElanTag();
308         // If elan tag is not updated, then put the elan interface into unprocessed entry map and entry. Let entries
309         // in this map get processed during ELAN update DCN.
310         if (elanTag == null) {
311             ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
312             if (elanInterfaces == null) {
313                 elanInterfaces = new ConcurrentLinkedQueue<ElanInterface>();
314             }
315             elanInterfaces.add(elanInterfaceAdded);
316             unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
317             return;
318         }
319         addElanInterface(elanInterfaceAdded, interfaceInfo, elanInstance);
320     }
321
322     void handleunprocessedElanInterfaces(ElanInstance elanInstance) {
323         Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
324         if (elanInterfaces == null || elanInterfaces.isEmpty()) {
325             return;
326         }
327         for (ElanInterface elanInterface: elanInterfaces) {
328             String interfaceName = elanInterface.getName();
329             InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
330             addElanInterface(elanInterface, interfaceInfo, elanInstance);
331         }
332     }
333
334     void addElanInterface(ElanInterface elanInterface, InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
335         String interfaceName = elanInterface.getName();
336         String elanInstanceName = elanInterface.getElanInstanceName();
337         List<PhysAddress> staticMacAddresses = elanInterface.getStaticMacEntries();
338         Elan elanInfo = ElanUtils.getElanByName(elanInstanceName);
339         BigInteger dpId = null;
340         if(elanInfo == null) {
341             ElanUtils.UpdateOperationalDataStore(broker, idManager, elanInstance);
342         }
343         if(interfaceInfo != null) {
344             dpId = interfaceInfo.getDpId();
345         }
346         if(dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
347             InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
348             Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
349             if (!existingElanDpnInterfaces.isPresent()) {
350                 createElanInterfacesList(elanInstanceName, interfaceName, dpId);
351             } else {
352                 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
353                 elanInterfaces.add(interfaceName);
354                 updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces);
355             }
356         }
357
358         // add code to install Local/Remote BC group, unknow DMAC entry, terminating service table flow entry
359         // call bindservice of interfacemanager to create ingress table flow enty.
360         //Add interface to the ElanInterfaceForwardingEntires Container
361         createElanInterfaceTablesList(interfaceName);
362         createElanStateList(elanInstanceName, interfaceName);
363         if(interfaceInfo != null) {
364             installFlowsAndGroups(elanInstance, interfaceInfo);
365         }
366         // add the static mac addresses
367         if(staticMacAddresses != null) {
368             for (PhysAddress physAddress : staticMacAddresses) {
369                 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
370                 Optional<MacEntry> existingMacEntry = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, macId);
371                 if (existingMacEntry.isPresent()) {
372                     elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(elanInstanceName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get());
373                 } else {
374                     elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(elanInstance, interfaceName, physAddress);
375                 }
376                 if(interfaceInfo != null && isOperational(interfaceInfo)) {
377                     logger.debug("Installing Static Mac-Entry on the Elan Interface:{} with MacAddress:{}", interfaceInfo, physAddress.getValue());
378                     ElanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT, physAddress.getValue());
379                 }
380             }
381         }
382     }
383
384     private Map<BigInteger, List<String>> readFePortsDbForElan(String elanName) {
385         ElanDpnInterfacesList elanDpnInterfacesList = ElanUtils.getElanDpnInterfacesList(elanName);
386         HashMap<BigInteger, List<String>> fePortsDb = Maps.newHashMap();
387         if (elanDpnInterfacesList == null) {
388             return fePortsDb;
389         }
390         List<DpnInterfaces> dpnInterfaces = elanDpnInterfacesList.getDpnInterfaces();
391         if (dpnInterfaces == null) {
392             return fePortsDb;
393         }
394         for (DpnInterfaces dpnInterface : dpnInterfaces) {
395             fePortsDb.put(dpnInterface.getDpId(), dpnInterface.getInterfaces());
396         }
397         return fePortsDb;
398     }
399
400     protected void removeInterfaceStaticMacEntires(String elanInstanceName, String interfaceName, PhysAddress physAddress) {
401         InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
402         InstanceIdentifier<MacEntry> macId =  getMacEntryOperationalDataPath(elanInstanceName, physAddress);
403         Optional<MacEntry> existingMacEntry = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, macId);
404
405         if(!existingMacEntry.isPresent()) {
406             return;
407         }
408
409         MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName).setKey(new MacEntryKey(physAddress)).build();
410         elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(ElanUtils.getElanInstanceByName(elanInstanceName), interfaceInfo, macEntry);
411         elanForwardingEntriesHandler.deleteElanInterfaceMacForwardingEntries(interfaceName, physAddress);
412     }
413
414
415     private InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
416         return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class,
417                 new MacTableKey(elanName)).child(MacEntry.class, new MacEntryKey(physAddress)).build();
418     }
419
420     public void installFlowsAndGroups(final ElanInstance elanInfo, final InterfaceInfo interfaceInfo) {
421         if (isOperational(interfaceInfo)) {
422
423             // LocalBroadcast Group creation with elan-Interfaces
424             setupLocalBroadcastGroups(elanInfo, interfaceInfo);
425
426             //Terminating Service , UnknownDMAC Table.
427             setupTerminateServiceTable(elanInfo, interfaceInfo);
428             setupUnknownDMacTable(elanInfo, interfaceInfo);
429             setupFilterEqualsTable(elanInfo, interfaceInfo);
430             // bind the Elan service to the Interface
431             bindService(elanInfo, interfaceInfo.getInterfaceName());
432
433             //update the remote-DPNs remoteBC group entry with Tunnels
434             setRemoteBCGrouponOtherDpns(elanInfo, interfaceInfo);
435         }
436     }
437
438     public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
439         int ifTag = interfaceInfo.getInterfaceTag();
440         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(interfaceInfo.getDpId(), ElanConstants.ELAN_FILTER_EQUALS_TABLE, getFlowRef(ElanConstants.ELAN_FILTER_EQUALS_TABLE, ifTag),
441                 9, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
442                 getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
443
444         mdsalManager.installFlow(flowEntity);
445
446         FlowEntity flowEntity1 = MDSALUtil.buildFlowEntity(interfaceInfo.getDpId(), ElanConstants.ELAN_FILTER_EQUALS_TABLE, getFlowRef(ElanConstants.ELAN_FILTER_EQUALS_TABLE, 1000+ifTag),
447                 10, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), getMatchesForFilterEqualsLPortTag(ifTag),
448                 getInstructionsDrop());
449
450         mdsalManager.installFlow(flowEntity1);
451     }
452
453     private List<BucketInfo> getRemoteBCGroupBucketInfos(ElanInstance elanInfo,
454             InterfaceInfo interfaceInfo) {
455         BigInteger dpnId = interfaceInfo.getDpId();
456         int elanTag = elanInfo.getElanTag().intValue();
457         List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
458         ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
459         if(elanDpns != null) {
460             List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
461             for(DpnInterfaces dpnInterface : dpnInterfaceses) {
462                if(ElanUtils.isDpnPresent(dpnInterface.getDpId()) && dpnInterface.getDpId() != dpnId && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
463                    try {
464                        //FIXME [ELANBE] Removing ITM API for now, will need this for multi dpn.
465                        //List<ActionInfo> listActionInfo = itmManager.ITMIngressGetActions(dpnId, dpnInterface.getDpId(), (int) elanTag);
466                        //listBucketInfo.add(new BucketInfo(listActionInfo));
467                    } catch (Exception ex) {
468                        logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnId, dpnInterface.getDpId() );
469                    }
470                }
471             }
472         }
473         List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
474         listActionInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(ElanUtils.getElanLocalBCGID(elanInfo.getElanTag()))}));
475         listBucketInfo.add(new BucketInfo(listActionInfo));
476         return listBucketInfo;
477     }
478
479     public ActionInfo getTunnelIdActionInfo(int interfaceTag) {
480          return new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{BigInteger.valueOf(interfaceTag)});
481     }
482
483     private void setRemoteBCGrouponOtherDpns(ElanInstance elanInfo,
484                                                          InterfaceInfo interfaceInfo) {
485         BigInteger dpnId = interfaceInfo.getDpId();
486         int elanTag = elanInfo.getElanTag().intValue();
487         long groupId = ElanUtils.getElanRemoteBCGID(elanTag);
488         ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
489         if(elanDpns != null) {
490             List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
491             for(DpnInterfaces dpnInterface : dpnInterfaceses) {
492               List<BucketInfo> remoteListBucketInfo = new ArrayList<BucketInfo>();
493                 if(ElanUtils.isDpnPresent(dpnInterface.getDpId()) && !dpnInterface.getDpId().equals(dpnId) && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
494                     for(DpnInterfaces otherFes : dpnInterfaceses) {
495                         if (ElanUtils.isDpnPresent(otherFes.getDpId()) && otherFes.getDpId() != dpnInterface.getDpId()
496                                 && otherFes.getInterfaces() != null && ! otherFes.getInterfaces().isEmpty()) {
497                             try {
498                                 //FIXME [ELANBE] Removing ITM API for now, will need this for multi dpn.
499                                 //List<ActionInfo> remoteListActionInfo = itmManager.ITMIngressGetActions(dpnInterface.getDpId(), otherFes.getDpId(), (int) elanTag);
500                                 //remoteListBucketInfo.add(new BucketInfo(remoteListActionInfo));
501                             } catch (Exception ex) {
502                                 logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnInterface.getDpId(), otherFes.getDpId() );
503                                 return;
504                             }
505                         }
506                     }
507                     List<ActionInfo> remoteListActionInfo = new ArrayList<ActionInfo>();
508                     remoteListActionInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(ElanUtils.getElanLocalBCGID(elanTag))}));
509                     remoteListBucketInfo.add(new BucketInfo(remoteListActionInfo));
510                     GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnInterface.getDpId(), groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, remoteListBucketInfo);
511                     mdsalManager.installGroup(groupEntity);
512                 }
513             }
514         }
515     }
516
517     private void updateRemoteBCGrouponDpnTunnelEvent(ElanInstance elanInfo,
518                                                InterfaceInfo interfaceInfo, BigInteger dstDpId) {
519         int elanTag = elanInfo.getElanTag().intValue();
520         long groupId = ElanUtils.getElanRemoteBCGID(elanTag);
521         List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
522         if(elanDpns != null) {
523             for(DpnInterfaces dpnInterface : elanDpns) {
524                 List<BucketInfo> remoteListBucketInfo = new ArrayList<BucketInfo>();
525                 if(ElanUtils.isDpnPresent(dstDpId) && dpnInterface.getDpId().equals(dstDpId) && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
526                     try {
527                         //FIXME [ELANBE] Removing ITM API for now, will need this for multi dpn.
528                         //List<ActionInfo> remoteListActionInfo = itmManager.ITMIngressGetActions(interfaceInfo.getDpId(), dstDpId, (int) elanTag);
529                         //remoteListBucketInfo.add(new BucketInfo(remoteListActionInfo));
530                     } catch (Exception ex) {
531                         logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnInterface.getDpId(), dstDpId);
532                         return;
533                     }
534                     List<ActionInfo> remoteListActionInfo = new ArrayList<ActionInfo>();
535                     remoteListActionInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(ElanUtils.getElanLocalBCGID(elanTag))}));
536                     remoteListBucketInfo.add(new BucketInfo(remoteListActionInfo));
537                     GroupEntity groupEntity = MDSALUtil.buildGroupEntity(interfaceInfo.getDpId(), groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, remoteListBucketInfo);
538                     mdsalManager.installGroup(groupEntity);
539                     break;
540                 }
541             }
542         }
543     }
544
545
546     /**
547      * Returns the bucket info with the given interface as the only bucket.
548      */
549     private List<BucketInfo> getLocalBCGroupBucketInfo(InterfaceInfo interfaceInfo) {
550         return Lists.newArrayList(new BucketInfo(getInterfacePortActionInfos(interfaceInfo)));
551     }
552
553     private List<MatchInfo> getMatchesForElanTag(Long elanTag) {
554         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
555         // Matching metadata
556         mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
557                 ElanUtils.getElanMetadataLabel(elanTag),
558                 MetaDataUtil.METADATA_MASK_SERVICE }));
559         return mkMatches;
560     }
561
562     private List<InstructionInfo> getInstructionsForOutGroup(
563             long groupId) {
564         List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
565         List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
566         actionsInfos.add(new ActionInfo(ActionType.group, new String[]{Long.toString(groupId)}));
567         mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
568         return mkInstructions;
569     }
570
571     public void removeFlowsAndGroups(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
572         removeStaticELanFlows(elanInfo, interfaceInfo);
573         unbindService(elanInfo, interfaceInfo.getInterfaceName());
574     }
575
576     public void installMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
577         String interfaceName = interfaceInfo.getInterfaceName();
578         BigInteger currentDpn = interfaceInfo.getDpId();
579         ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
580         if(elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
581             List<MacEntry> macEntries =  elanInterfaceMac.getMacEntry();
582             for(MacEntry macEntry : macEntries) {
583                 PhysAddress physAddress = macEntry.getMacAddress();
584                 ElanUtils.setupMacFlows(elanInfo, interfaceInfo, macEntry.isIsStaticAddress() ? ElanConstants.STATIC_MAC_TIMEOUT : elanInfo.getMacTimeout(), physAddress.getValue());
585             }
586             //Programming the remoteDMACFlows
587             ElanDpnInterfacesList elanDpnInterfacesList =  ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
588             List<DpnInterfaces> dpnInterfaceLists =  elanDpnInterfacesList.getDpnInterfaces();
589             for(DpnInterfaces dpnInterfaces : dpnInterfaceLists){
590                 if(dpnInterfaces.getDpId().equals(interfaceInfo.getDpId())) {
591                     continue;
592                 }
593                 List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
594                 for(String remoteIf : remoteElanInterfaces) {
595                     ElanInterfaceMac elanIfMac = ElanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
596                     InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
597                     if(elanIfMac == null) {
598                         continue;
599                     }
600                     List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
601                     if(remoteMacEntries != null) {
602                         for (MacEntry macEntry : remoteMacEntries) {
603                             PhysAddress physAddress = macEntry.getMacAddress();
604                             ElanUtils.setupRemoteDmacFlow(currentDpn, remoteInterface.getDpId(), remoteInterface.getInterfaceTag(), elanInfo.getElanTag(), physAddress.getValue(), elanInfo.getElanInstanceName());
605                         }
606                     }
607                 }
608             }
609         }
610     }
611
612     // Install DMAC entry on dst DPN
613     public void installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId) {
614         String interfaceName = interfaceInfo.getInterfaceName();
615         ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
616         if(elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
617             List<MacEntry> macEntries =  elanInterfaceMac.getMacEntry();
618             for(MacEntry macEntry : macEntries) {
619                 PhysAddress physAddress = macEntry.getMacAddress();
620                 ElanUtils.setupDMacFlowonRemoteDpn(elanInfo, interfaceInfo, dstDpId, physAddress.getValue());
621             }
622         }
623     }
624
625     public void removeMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
626         ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceInfo.getInterfaceName());
627         if(elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
628             List<MacEntry> macEntries =  elanInterfaceMac.getMacEntry();
629             for(MacEntry macEntry : macEntries) {
630                 ElanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry);
631             }
632         }
633     }
634
635     public void setupLocalBroadcastGroups(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
636         List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
637         BigInteger dpnId = interfaceInfo.getDpId();
638         long groupId = ElanUtils.getElanLocalBCGID(elanInfo.getElanTag());
639
640         DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanInfo.getElanInstanceName(), dpnId);
641         for(String ifName : dpnInterfaces.getInterfaces()) {
642             // In case if there is a InterfacePort in the cache which is not in
643             // operational state, skip processing it
644             InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
645             if (!isOperational(ifInfo)) {
646                 continue;
647             }
648
649             listBucketInfo.add(new BucketInfo(getInterfacePortActionInfos(ifInfo)));
650         }
651         GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, listBucketInfo);
652         logger.trace("installing the localBroadCast GroupEntity:{}", groupEntity);
653         mdsalManager.syncInstallGroup(groupEntity, ElanConstants.DELAY_TIME_IN_MILLISECOND);
654     }
655
656     public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
657         BigInteger dpnId = interfaceInfo.getDpId();
658         long groupId = ElanUtils.getElanLocalBCGID(elanInfo.getElanTag());
659
660         GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, getLocalBCGroupBucketInfo(interfaceInfo));
661         logger.trace("deleted the localBroadCast GroupEntity:{}", groupEntity);
662         mdsalManager.syncRemoveGroup(groupEntity);
663     }
664
665     public void removeRemoteBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
666         List<BucketInfo> listBucketInfo = getRemoteBCGroupBucketInfos(elanInfo, interfaceInfo);
667         BigInteger dpnId = interfaceInfo.getDpId();
668         long groupId = ElanUtils.getElanRemoteBCGID(elanInfo.getElanTag());
669         GroupEntity groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, listBucketInfo);
670         logger.trace("deleting the remoteBroadCast GroupEntity:{}", groupEntity);
671         mdsalManager.syncRemoveGroup(groupEntity);
672     }
673
674     public void setupTerminateServiceTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
675         long elanTag = elanInfo.getElanTag();
676         //FIXME [ELANBE] Removing ITM API for now, will need this for multi dpn.
677 //        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(interfaceInfo.getDpId(), ITMConstants.TERMINATING_SERVICE_TABLE, getFlowRef(ITMConstants.TERMINATING_SERVICE_TABLE, elanTag),
678 //                5, elanInfo.getElanInstanceName(), 0,  0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), itmManager.getTunnelMatchesForServiceId(elanTag),
679 //                getInstructionsForOutGroup(ElanUtils.getElanLocalBCGID(elanTag)));
680 //
681 //        mdsalManager.installFlow(flowEntity);
682     }
683
684     public void setupUnknownDMacTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
685         long elanTag = elanInfo.getElanTag();
686         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(interfaceInfo.getDpId(), ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, getFlowRef(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag),
687                 5, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)), getMatchesForElanTag(elanTag),
688                 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGID(elanTag)));
689
690         mdsalManager.installFlow(flowEntity);
691     }
692
693     private void removeStaticELanFlows(final ElanInstance elanInfo, final InterfaceInfo interfaceInfo) {
694         BigInteger dpId = interfaceInfo.getDpId();
695         long elanTag = elanInfo.getElanTag();
696         /*
697          * If there are not elan ports, remove the unknown smac and default dmac
698          * flows
699          */
700         DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanInfo.getElanInstanceName(), dpId);
701         if(dpnInterfaces == null) {
702             return;
703         }
704         List <String> elanInterfaces = dpnInterfaces.getInterfaces();
705         if (elanInterfaces == null || elanInterfaces.isEmpty()) {
706
707             logger.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
708             removeDefaultTermFlow(dpId, elanInfo.getElanTag());
709             removeUnknownDmacFlow(dpId, elanInfo);
710             removeRemoteBroadcastGroup(elanInfo, interfaceInfo);
711             removeLocalBroadcastGroup(elanInfo, interfaceInfo);
712         } else {
713             setupLocalBroadcastGroups(elanInfo, interfaceInfo);
714         }
715     }
716
717     private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo) {
718         FlowEntity flowEntity = getUnknownDmacFlowEntity(dpId, elanInfo);
719         mdsalManager.syncRemoveFlow(flowEntity, ElanConstants.DELAY_TIME_IN_MILLISECOND);
720     }
721
722     private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
723         //FIXME [ELANBE] Removing ITM API for now, will need this for multi dpn.
724         //itmManager.removeTerminatingServiceAction(dpId, (int) elanTag);
725     }
726
727     private void bindService(ElanInstance elanInfo, String interfaceName) {
728        // interfaceManager.bindService(interfaceName, ElanUtils.getServiceInfo(elanInfo.getElanInstanceName(), elanInfo.getElanTag(), interfaceName));
729
730         int priority = ElanConstants.ELAN_SERVICE_PRIORITY;
731         int instructionKey = 0;
732         List<Instruction> instructions = new ArrayList<Instruction>();
733         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanUtils.getElanMetadataLabel(elanInfo.getElanTag()), MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
734         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(ElanConstants.ELAN_SMAC_TABLE, ++instructionKey));
735         BoundServices
736                 serviceInfo =
737                 ElanUtils.getBoundServices(String.format("%s.%s.%s", "vpn",elanInfo.getElanInstanceName(), interfaceName),
738                         ElanConstants.ELAN_SERVICE_INDEX, priority,
739                         ElanConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
740         ElanUtils.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
741                 ElanUtils.buildServiceId(interfaceName, ElanConstants.ELAN_SERVICE_INDEX), serviceInfo);
742     }
743
744     private void unbindService(ElanInstance elanInfo, String interfaceName) {
745         ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
746                 ElanUtils.buildServiceId(interfaceName,ElanConstants.ELAN_SERVICE_INDEX),
747                 ElanUtils.DEFAULT_CALLBACK);
748     }
749
750     private void unbindService(ElanInstance elanInfo, String interfaceName, int vlanId) {
751         ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
752                 ElanUtils.buildServiceId(interfaceName,ElanConstants.ELAN_SERVICE_INDEX),
753                 ElanUtils.DEFAULT_CALLBACK);
754     }
755
756     private FlowEntity getUnknownDmacFlowEntity(BigInteger dpId, ElanInstance elanInfo) {
757         long elanTag = elanInfo.getElanTag();
758         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
759         // Matching metadata
760         mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
761                 ElanUtils.getElanMetadataLabel(elanTag),
762                 MetaDataUtil.METADATA_MASK_SERVICE }));
763
764         List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
765         List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
766         actionsInfos.add(new ActionInfo(ActionType.group, new String[]{Long.toString(ElanUtils.getElanRemoteBCGID(elanTag))}));
767         mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
768
769         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, getFlowRef(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag),
770                 5, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
771                 mkMatches, mkInstructions);
772         return flowEntity;
773     }
774
775     private String getFlowRef(long tableId, long elanTag) {
776         return new StringBuffer().append(tableId).append(elanTag).toString();
777     }
778
779     private List<ActionInfo> getInterfacePortActionInfos(InterfaceInfo interfaceInfo) {
780         List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
781         listActionInfo.add(getTunnelIdActionInfo(interfaceInfo.getInterfaceTag()));
782         listActionInfo.add(new ActionInfo(ActionType.nx_resubmit, new String[]{}));
783         return listActionInfo;
784     }
785
786     private void updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId, List<String> interfaceNames) {
787         if(!interfaceNames.isEmpty()) {
788             DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId)
789                     .setInterfaces(interfaceNames).setKey(new DpnInterfacesKey(dpId)).build();
790             MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId),
791                     dpnInterface);
792         } else {
793             MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId));
794         }
795         
796     }
797
798     private List<String> createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId) {
799         List<String> interfaceNames = new ArrayList<String>();
800         interfaceNames.add(interfaceName);
801         DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId)
802                 .setInterfaces(interfaceNames).setKey(new DpnInterfacesKey(dpId)).build();
803         MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId),
804                 dpnInterface);
805         return interfaceNames;
806     }
807
808     private void createElanInterfaceTablesList(String interfaceName) {
809         InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
810         Optional<ElanInterfaceMac> interfaceMacTables = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
811         // Adding new Elan Interface Port to the operational DataStore without Static-Mac Entries..
812         if(!interfaceMacTables.isPresent()) {
813             ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName).setKey(new ElanInterfaceMacKey(interfaceName)).build();
814             MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName),
815                     elanInterfaceMacTable);
816         }
817     }
818
819     private void createElanStateList(String elanInstanceName, String interfaceName) {
820         InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
821         Optional<Elan> elanInterfaceLists = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanInstance);
822         // Adding new Elan Interface Port to the operational DataStore without Static-Mac Entries..
823         if(elanInterfaceLists.isPresent()) {
824             List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
825             if(interfaceLists == null) {
826                 interfaceLists = new ArrayList<>();
827             }
828             interfaceLists.add(interfaceName);
829             Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists).setKey(new ElanKey(elanInstanceName)).build();
830             MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState);
831         }
832     }
833
834     private boolean isOperational(InterfaceInfo interfaceInfo) {
835         return ((interfaceInfo.getOpState() == InterfaceInfo.InterfaceOpState.UP) && (interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED));
836     }
837
838     protected void updatedIfPrimaryAttributeChanged(ElanInterface elanInterface, boolean isUpdated) {
839         String interfaceName = elanInterface.getName();
840         InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
841         BigInteger dpId = interfaceInfo.getDpId();
842         InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
843         Optional<ElanInterfaceMac> existingElanInterface = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
844         ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanInterface.getElanInstanceName());
845
846         if(!existingElanInterface.isPresent()) {
847             return;
848         }
849
850         List<MacEntry> macEntries = existingElanInterface.get().getMacEntry();
851         if(macEntries != null && !macEntries.isEmpty()) {
852             for (MacEntry macEntry : macEntries) {
853                 if(isUpdated) {
854                     ElanUtils.setupMacFlows(elanInfo, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT, macEntry.getMacAddress().getValue());
855                 } else {
856                     ElanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry);
857                 }
858             }
859         }
860
861         InstanceIdentifier<DpnInterfaces> dpnInterfaceId = ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInterface.getElanInstanceName(), interfaceInfo.getDpId());
862         Optional<DpnInterfaces> dpnInterfaces =  ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, dpnInterfaceId);
863         List<String> interfaceLists = dpnInterfaces.get().getInterfaces();
864
865         if(isUpdated) {
866             interfaceLists.add(elanInterface.getName());
867         } else {
868             interfaceLists.remove(elanInterface.getName());
869         }
870
871         DpnInterfaces  updateDpnInterfaces = new DpnInterfacesBuilder().setInterfaces(interfaceLists).setDpId(dpId).setKey(new DpnInterfacesKey(dpId)).build();
872         MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, dpnInterfaceId, updateDpnInterfaces);
873
874         if(isUpdated) {
875             installFlowsAndGroups(elanInfo, interfaceInfo);
876         } else {
877             removeStaticELanFlows(elanInfo, interfaceInfo);
878             unbindService(elanInfo, interfaceName);
879         }
880     }
881
882     public void handleTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
883         ElanDpnInterfaces dpnInterfaceLists =  ElanUtils.getElanDpnInterfacesList();
884         Set<String> elanInstancesMap = new HashSet<>();
885         if(dpnInterfaceLists == null) {
886             return;
887         }
888         List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
889         for(ElanDpnInterfacesList elanDpns: elanDpnIf) {
890             int cnt = 0;
891             String elanName = elanDpns.getElanInstanceName();
892             List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
893             if(dpnInterfaces == null) {
894                continue;
895             }
896             for (DpnInterfaces dpnIf : dpnInterfaces) {
897                if(dpnIf.getDpId().equals(srcDpId) || dpnIf.getDpId().equals(dstDpId)) {
898                    cnt++;
899                 }
900             }
901             if(cnt == 2) {
902                 logger.debug("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
903                 DpnInterfaces dpnInterface = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, srcDpId);
904                 Set<String> interfaceLists = new HashSet<>();
905                 ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
906                 interfaceLists.addAll(dpnInterface.getInterfaces());
907                 for(String ifName : interfaceLists) {
908                     InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
909                     if (isOperational(interfaceInfo)) {
910                         if (interfaceInfo.getDpId().equals(srcDpId) && !elanInstancesMap.contains(elanDpns.getElanInstanceName())) {
911                             elanInstancesMap.add(elanDpns.getElanInstanceName());
912                             elanInterfaceManager.updateRemoteBCGrouponDpnTunnelEvent(elanInfo, interfaceInfo, dstDpId);
913                         }
914                         elanInterfaceManager.installDMacAddressTables(elanInfo, interfaceInfo, dstDpId);
915                     }
916                 }
917             }
918
919         }
920     }
921
922     public void handleInterfaceUpated(InterfaceInfo interfaceInfo, ElanInstance elanInstance, boolean isStateUp) {
923         BigInteger dpId = interfaceInfo.getDpId();
924         String elanName = elanInstance.getElanInstanceName();
925         String ifName = interfaceInfo.getInterfaceName();
926         logger.trace("Handling interface update event for interface with info {} , state {}", interfaceInfo, isStateUp);
927         if(isStateUp) {
928
929             DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
930             if(dpnInterfaces == null) {
931                 createElanInterfacesList(elanName, interfaceInfo.getInterfaceName(), dpId);
932             } else {
933               List<String> dpnElanInterfaces = dpnInterfaces.getInterfaces();
934                 dpnElanInterfaces.add(interfaceInfo.getInterfaceName());
935                 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId)
936                         .setInterfaces(dpnElanInterfaces).setKey(new DpnInterfacesKey(dpId)).build();
937                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnInterfaceOperationalDataPath(elanName, interfaceInfo.getDpId()), dpnInterface);
938             }
939
940             logger.trace("ElanInterface Service is installed for interface:{}", ifName);
941             elanInterfaceManager.installFlowsAndGroups(elanInstance, interfaceInfo);
942             elanInterfaceManager.installMacAddressTables(elanInstance, interfaceInfo);
943         } else {
944
945             DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
946             if(dpnInterfaces != null) {
947                 List<String> dpnElanInterfaces = dpnInterfaces.getInterfaces();
948                 dpnElanInterfaces.remove(interfaceInfo.getInterfaceName());
949                 DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId)
950                         .setInterfaces(dpnElanInterfaces).setKey(new DpnInterfacesKey(dpId)).build();
951                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnInterfaceOperationalDataPath(elanName, interfaceInfo.getDpId()), dpnInterface);
952             }
953             logger.trace("ElanInterface Service is removed for the interface:{}", ifName);
954             elanInterfaceManager.removeMacAddressTables(elanInstance, interfaceInfo);
955             elanInterfaceManager.removeFlowsAndGroups(elanInstance, interfaceInfo);
956         }
957     }
958
959     private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int LportTag) {
960         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
961         // Matching metadata
962         mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
963                 MetaDataUtil.getLportTagMetaData(LportTag),
964                 MetaDataUtil.METADATA_MASK_LPORT_TAG }));
965         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(LportTag)}));
966         return mkMatches;
967     }
968
969
970     private List<MatchInfo> getTunnelIdMatchForFilterEqualsLPortTag(int LportTag) {
971         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
972         // Matching metadata
973         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {
974                 BigInteger.valueOf(LportTag)}));
975         return mkMatches;
976
977
978     }
979
980     private List<InstructionInfo> getInstructionsInPortForOutGroup(
981             String ifName) {
982         List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
983         List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
984         actionsInfos.addAll(ElanUtils.getEgressActionsForInterface(ifName));
985         mkInstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
986         return mkInstructions;
987     }
988
989
990
991     private List<InstructionInfo> getInstructionsDrop() {
992         List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
993         List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
994         actionsInfos.add(new ActionInfo(ActionType.drop_action, new String[]{}));
995         mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
996         return mkInstructions;
997     }
998
999 }