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