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