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