d696419ea59eb81c9936e21674e0621d585bbe44
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / internal / ElanServiceProvider.java
1 /*
2  * Copyright (c) 2016, 2017 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
9 package org.opendaylight.netvirt.elan.internal;
10
11 import com.google.common.base.Optional;
12 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.concurrent.Future;
22 import java.util.function.BiFunction;
23 import javax.annotation.Nonnull;
24 import javax.inject.Inject;
25 import javax.inject.Singleton;
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.genius.interfacemanager.exceptions.InterfaceAlreadyExistsException;
29 import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
30 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
31 import org.opendaylight.genius.mdsalutil.MDSALUtil;
32 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
33 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
34 import org.opendaylight.genius.mdsalutil.NwConstants;
35 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
36 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
37 import org.opendaylight.genius.utils.ServiceIndex;
38 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
39 import org.opendaylight.infrautils.inject.AbstractLifecycle;
40 import org.opendaylight.mdsal.eos.binding.api.Entity;
41 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipCandidateRegistration;
42 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
43 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
44 import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
45 import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
46 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
47 import org.opendaylight.netvirt.elan.utils.ElanConstants;
48 import org.opendaylight.netvirt.elan.utils.ElanUtils;
49 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
50 import org.opendaylight.netvirt.elanmanager.api.IElanService;
51 import org.opendaylight.netvirt.elanmanager.exceptions.MacNotFoundException;
52 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstanceBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterfaceBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntriesBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
80 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
81 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
82 import org.opendaylight.yangtools.yang.common.RpcResult;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
85
86 @Singleton
87 public class ElanServiceProvider extends AbstractLifecycle implements IElanService {
88
89     private static final Logger LOG = LoggerFactory.getLogger(ElanServiceProvider.class);
90
91     private final IdManagerService idManager;
92     private final IInterfaceManager interfaceManager;
93     private final ElanInstanceManager elanInstanceManager;
94     private final ElanBridgeManager bridgeMgr;
95     private final DataBroker broker;
96     private final ElanUtils elanUtils;
97     private final SouthboundUtils southboundUtils;
98     private final IMdsalApiManager mdsalManager;
99     private final ElanInstanceCache elanInstanceCache;
100     private boolean isL2BeforeL3;
101
102     private final EntityOwnershipCandidateRegistration candidateRegistration;
103
104     @Inject
105     public ElanServiceProvider(IdManagerService idManager, IInterfaceManager interfaceManager,
106                                ElanInstanceManager elanInstanceManager, ElanBridgeManager bridgeMgr,
107                                DataBroker dataBroker,
108                                ElanInterfaceManager elanInterfaceManager,
109                                ElanUtils elanUtils,
110                                EntityOwnershipService entityOwnershipService,
111                                SouthboundUtils southboundUtils, ElanInstanceCache elanInstanceCache,
112                                IMdsalApiManager mdsalManager) {
113         this.idManager = idManager;
114         this.interfaceManager = interfaceManager;
115         this.elanInstanceManager = elanInstanceManager;
116         this.bridgeMgr = bridgeMgr;
117         this.broker = dataBroker;
118         this.elanUtils = elanUtils;
119         this.southboundUtils = southboundUtils;
120         this.elanInstanceCache = elanInstanceCache;
121         this.mdsalManager = mdsalManager;
122
123         candidateRegistration = registerCandidate(entityOwnershipService);
124     }
125
126     private static EntityOwnershipCandidateRegistration registerCandidate(
127             EntityOwnershipService entityOwnershipService) {
128         try {
129             return entityOwnershipService.registerCandidate(
130                     new Entity(HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE));
131         } catch (CandidateAlreadyRegisteredException e) {
132             LOG.error("failed to register the entity");
133             return null;
134         }
135     }
136
137     @Override
138     @SuppressWarnings("checkstyle:IllegalCatch")
139     protected void start() throws Exception {
140         LOG.info("Starting ElanServiceProvider");
141         setIsL2BeforeL3();
142         createIdPool();
143     }
144
145     @Override
146     protected void stop() {
147         if (candidateRegistration != null) {
148             candidateRegistration.close();
149         }
150
151         LOG.info("ElanServiceProvider stopped");
152     }
153
154     @Override
155     // Confusing with isOpenstackVniSemanticsEnforced but this is an interface method so can't change it.
156     @SuppressFBWarnings("NM_CONFUSING")
157     public Boolean isOpenStackVniSemanticsEnforced() {
158         return elanUtils.isOpenstackVniSemanticsEnforced();
159     }
160
161     private void createIdPool() throws Exception {
162         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME)
163                 .setLow(ElanConstants.ELAN_ID_LOW_VALUE).setHigh(ElanConstants.ELAN_ID_HIGH_VALUE).build();
164         Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
165         if (result != null && result.get().isSuccessful()) {
166             LOG.debug("ELAN Id Pool is created successfully");
167         }
168     }
169
170     @Override
171     public boolean createElanInstance(String elanInstanceName, long macTimeout, String description) {
172         ElanInstance existingElanInstance = elanInstanceManager.getElanInstanceByName(elanInstanceName);
173         boolean isSuccess = true;
174         if (existingElanInstance != null) {
175             if (compareWithExistingElanInstance(existingElanInstance, macTimeout, description)) {
176                 LOG.debug("Elan Instance is already present in the Operational DS {}", existingElanInstance);
177                 return true;
178             } else {
179                 ElanInstance updateElanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
180                         .setDescription(description).setMacTimeout(macTimeout)
181                         .setKey(new ElanInstanceKey(elanInstanceName)).build();
182                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
183                         ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), updateElanInstance);
184                 LOG.debug("Updating the Elan Instance {} with MAC TIME-OUT %l and Description %s ",
185                         updateElanInstance, macTimeout, description);
186             }
187         } else {
188             ElanInstance elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
189                     .setMacTimeout(macTimeout).setDescription(description).setKey(new ElanInstanceKey(elanInstanceName))
190                     .build();
191             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
192                     ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstance);
193             LOG.debug("Creating the new Elan Instance {}", elanInstance);
194         }
195         return isSuccess;
196     }
197
198     @Override
199     public boolean createEtreeInstance(String elanInstanceName, long macTimeout, String description) {
200         ElanInstance existingElanInstance = elanInstanceManager.getElanInstanceByName(elanInstanceName);
201         boolean isSuccess = true;
202         if (existingElanInstance != null) {
203             if (compareWithExistingElanInstance(existingElanInstance, macTimeout, description)) {
204                 LOG.warn("Etree Instance is already present in the Operational DS {}", existingElanInstance);
205                 return true;
206             } else {
207                 EtreeInstance etreeInstance = new EtreeInstanceBuilder().build();
208                 ElanInstance updateElanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
209                         .setDescription(description).setMacTimeout(macTimeout)
210                         .setKey(new ElanInstanceKey(elanInstanceName))
211                         .addAugmentation(EtreeInstance.class, etreeInstance).build();
212                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
213                         ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), updateElanInstance);
214                 LOG.debug("Updating the Etree Instance {} with MAC TIME-OUT %l and Description %s ",
215                         updateElanInstance, macTimeout, description);
216             }
217         } else {
218             EtreeInstance etreeInstance = new EtreeInstanceBuilder().build();
219             ElanInstance elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
220                     .setMacTimeout(macTimeout).setDescription(description).setKey(new ElanInstanceKey(elanInstanceName))
221                     .addAugmentation(EtreeInstance.class, etreeInstance).build();
222             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
223                     ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstance);
224             LOG.debug("Creating the new Etree Instance {}", elanInstance);
225         }
226         return isSuccess;
227     }
228
229     @Override
230     public EtreeInterface getEtreeInterfaceByElanInterfaceName(String elanInterface) {
231         return ElanUtils.getEtreeInterfaceByElanInterfaceName(broker, elanInterface);
232     }
233
234     public static boolean compareWithExistingElanInstance(ElanInstance existingElanInstance, long macTimeOut,
235             String description) {
236         boolean isEqual = false;
237         if (existingElanInstance.getMacTimeout() == macTimeOut
238                 && existingElanInstance.getDescription().equals(description)) {
239             isEqual = true;
240         }
241         return isEqual;
242     }
243
244     @Override
245     public void updateElanInstance(String elanInstanceName, long newMacTimout, String newDescription) {
246         createElanInstance(elanInstanceName, newMacTimout, newDescription);
247     }
248
249     @Override
250     public boolean deleteEtreeInstance(String etreeInstanceName) {
251         return deleteElanInstance(etreeInstanceName);
252     }
253
254     @Override
255     public boolean deleteElanInstance(String elanInstanceName) {
256         boolean isSuccess = false;
257         ElanInstance existingElanInstance = elanInstanceManager.getElanInstanceByName(elanInstanceName);
258         if (existingElanInstance == null) {
259             LOG.debug("Elan Instance is not present for {}", elanInstanceName);
260             return isSuccess;
261         }
262         LOG.debug("Deletion of the existing Elan Instance {}", existingElanInstance);
263         ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
264                 ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName));
265         isSuccess = true;
266         return isSuccess;
267     }
268
269     @Override
270     public void addEtreeInterface(String etreeInstanceName, String interfaceName, EtreeInterfaceType interfaceType,
271             List<String> staticMacAddresses, String description) {
272         ElanInstance existingElanInstance = elanInstanceManager.getElanInstanceByName(etreeInstanceName);
273         if (existingElanInstance != null && existingElanInstance.getAugmentation(EtreeInstance.class) != null) {
274             EtreeInterface etreeInterface = new EtreeInterfaceBuilder().setEtreeInterfaceType(interfaceType).build();
275             ElanInterface elanInterface;
276             if (staticMacAddresses == null) {
277                 elanInterface = new ElanInterfaceBuilder().setElanInstanceName(etreeInstanceName)
278                         .setDescription(description).setName(interfaceName).setKey(new ElanInterfaceKey(interfaceName))
279                         .addAugmentation(EtreeInterface.class, etreeInterface).build();
280             } else {
281                 List<StaticMacEntries> staticMacEntries = ElanUtils.getStaticMacEntries(staticMacAddresses);
282                 elanInterface = new ElanInterfaceBuilder().setElanInstanceName(etreeInstanceName)
283                         .setDescription(description).setName(interfaceName)
284                         .setStaticMacEntries(staticMacEntries)
285                         .setKey(new ElanInterfaceKey(interfaceName))
286                         .addAugmentation(EtreeInterface.class, etreeInterface).build();
287             }
288             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
289                     ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
290             LOG.debug("Creating the new Etree Interface {}", elanInterface);
291         }
292     }
293
294     @Override
295     public void addElanInterface(String elanInstanceName, String interfaceName, List<String> staticMacAddresses,
296             String description) {
297         ElanInstance existingElanInstance = elanInstanceManager.getElanInstanceByName(elanInstanceName);
298         if (existingElanInstance != null) {
299             ElanInterfaceBuilder elanInterfaceBuilder = new ElanInterfaceBuilder()
300                     .setElanInstanceName(elanInstanceName)
301                     .setDescription(description).setName(interfaceName)
302                     .setKey(new ElanInterfaceKey(interfaceName));
303             if (staticMacAddresses != null) {
304                 List<StaticMacEntries> staticMacEntries = ElanUtils.getStaticMacEntries(staticMacAddresses);
305                 elanInterfaceBuilder.setStaticMacEntries(staticMacEntries);
306             }
307             ElanInterface elanInterface = elanInterfaceBuilder.build();
308             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
309                     ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
310             LOG.debug("Created the new ELan Interface {}", elanInterface);
311         }
312     }
313
314     @Override
315     public void updateElanInterface(String elanInstanceName, String interfaceName,
316             List<String> updatedStaticMacAddresses, String newDescription) {
317         ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName);
318         if (existingElanInterface == null) {
319             return;
320         }
321
322         List<StaticMacEntries> updatedStaticMacEntries = ElanUtils.getStaticMacEntries(updatedStaticMacAddresses);
323         LOG.debug("updating the ElanInterface with new Mac Entries {}", updatedStaticMacAddresses);
324         ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
325                 .setName(interfaceName).setDescription(newDescription).setStaticMacEntries(updatedStaticMacEntries)
326                 .setKey(new ElanInterfaceKey(interfaceName)).build();
327         MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
328                 ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
329     }
330
331     @Override
332     public void deleteEtreeInterface(String elanInstanceName, String interfaceName) {
333         deleteElanInterface(elanInstanceName, interfaceName);
334         LOG.debug("deleting the Etree Interface {}", interfaceName);
335     }
336
337     @Override
338     public void deleteElanInterface(String elanInstanceName, String interfaceName) {
339         ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName);
340         if (existingElanInterface != null) {
341             ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
342                     ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
343             LOG.debug("deleting the Elan Interface {}", existingElanInterface);
344         }
345     }
346
347     @Override
348     public void addStaticMacAddress(String elanInstanceName, String interfaceName, String macAddress) {
349         ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName);
350         PhysAddress updateStaticMacAddress = new PhysAddress(macAddress);
351         if (existingElanInterface != null) {
352             StaticMacEntriesBuilder staticMacEntriesBuilder = new StaticMacEntriesBuilder();
353             StaticMacEntries staticMacEntry = staticMacEntriesBuilder.setMacAddress(updateStaticMacAddress).build();
354             InstanceIdentifier<StaticMacEntries> staticMacEntriesIdentifier =
355                     ElanUtils.getStaticMacEntriesCfgDataPathIdentifier(interfaceName,
356                     macAddress);
357             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, staticMacEntriesIdentifier, staticMacEntry);
358             return;
359         }
360
361         return;
362     }
363
364     @Override
365     public void deleteStaticMacAddress(String elanInstanceName, String interfaceName, String macAddress)
366             throws MacNotFoundException {
367         ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName);
368         if (existingElanInterface != null) {
369             InstanceIdentifier<StaticMacEntries> staticMacEntriesIdentifier =
370                     ElanUtils.getStaticMacEntriesCfgDataPathIdentifier(interfaceName,
371                     macAddress);
372             MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, staticMacEntriesIdentifier);
373         }
374     }
375
376     @Override
377     public Collection<MacEntry> getElanMacTable(String elanInstanceName) {
378         Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
379         List<MacEntry> macAddress = new ArrayList<>();
380         if (elanInfo == null) {
381             return macAddress;
382         }
383         List<String> elanInterfaces = elanInfo.getElanInterfaces();
384         if (elanInterfaces != null && elanInterfaces.size() > 0) {
385             for (String elanInterface : elanInterfaces) {
386                 ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
387                 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null
388                         && elanInterfaceMac.getMacEntry().size() > 0) {
389                     macAddress.addAll(elanInterfaceMac.getMacEntry());
390                 }
391             }
392         }
393         return macAddress;
394     }
395
396     @Override
397     public void flushMACTable(String elanInstanceName) {
398         Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
399         if (elanInfo == null) {
400             return;
401         }
402         List<String> elanInterfaces = elanInfo.getElanInterfaces();
403         if (elanInterfaces == null || elanInterfaces.isEmpty()) {
404             return;
405         }
406         for (String elanInterface : elanInterfaces) {
407             ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
408             if (elanInterfaceMac.getMacEntry() != null && elanInterfaceMac.getMacEntry().size() > 0) {
409                 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
410                 for (MacEntry macEntry : macEntries) {
411                     try {
412                         deleteStaticMacAddress(elanInstanceName, elanInterface, macEntry.getMacAddress().getValue());
413                     } catch (MacNotFoundException e) {
414                         LOG.error("Mac Not Found Exception {}", e);
415                     }
416                 }
417             }
418         }
419
420     }
421
422     @Override
423     public ElanInstance getElanInstance(String elanName) {
424         return elanInstanceCache.get(elanName).orNull();
425     }
426
427     @Override
428     public List<ElanInstance> getElanInstances() {
429         InstanceIdentifier<ElanInstances> elanInstancesIdentifier = InstanceIdentifier.builder(ElanInstances.class)
430                 .build();
431         return ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanInstancesIdentifier).toJavaUtil().map(
432                 ElanInstances::getElanInstance).orElse(Collections.emptyList());
433     }
434
435     @Override
436     @Nonnull
437     public List<String> getElanInterfaces(String elanInstanceName) {
438         List<String> elanInterfaces = new ArrayList<>();
439         InstanceIdentifier<ElanInterfaces> elanInterfacesIdentifier = InstanceIdentifier.builder(ElanInterfaces.class)
440                 .build();
441         Optional<ElanInterfaces> elanInterfacesOptional = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
442                 elanInterfacesIdentifier);
443         if (!elanInterfacesOptional.isPresent()) {
444             return elanInterfaces;
445         }
446         List<ElanInterface> elanInterfaceList = elanInterfacesOptional.get().getElanInterface();
447         for (ElanInterface elanInterface : elanInterfaceList) {
448             if (elanInterface.getElanInstanceName().equals(elanInstanceName)) {
449                 elanInterfaces.add(elanInterface.getName());
450             }
451         }
452         return elanInterfaces;
453     }
454
455     @Override
456     public void createExternalElanNetworks(Node node) {
457         handleExternalElanNetworks(node, true, (elanInstance, interfaceName) -> {
458             createExternalElanNetwork(elanInstance, interfaceName);
459             return null;
460         });
461     }
462
463     @Override
464     public void createExternalElanNetwork(ElanInstance elanInstance) {
465         handleExternalElanNetwork(elanInstance, false, (elanInstance1, interfaceName) -> {
466             createExternalElanNetwork(elanInstance1, interfaceName);
467             return null;
468         });
469     }
470
471     protected void createExternalElanNetwork(ElanInstance elanInstance, BigInteger dpId) {
472         String providerIntfName = bridgeMgr.getProviderInterfaceName(dpId, elanInstance.getPhysicalNetworkName());
473         String intfName = providerIntfName + IfmConstants.OF_URI_SEPARATOR + elanInstance.getSegmentationId();
474         Interface memberIntf = interfaceManager.getInterfaceInfoFromConfigDataStore(intfName);
475         if (memberIntf == null) {
476             LOG.debug("creating vlan prv intf in elan {}, dpn {}", elanInstance.getElanInstanceName(),
477                     dpId);
478             createExternalElanNetwork(elanInstance, providerIntfName);
479         }
480     }
481
482     private void createExternalElanNetwork(ElanInstance elanInstance, String interfaceName) {
483         if (interfaceName == null) {
484             LOG.trace("No physical interface is attached to {}", elanInstance.getPhysicalNetworkName());
485             return;
486         }
487
488         String elanInterfaceName = createIetfInterfaces(elanInstance, interfaceName);
489         addElanInterface(elanInstance.getElanInstanceName(), elanInterfaceName, null, null);
490     }
491
492     @Override
493     public void updateExternalElanNetwork(ElanInstance elanInstance) {
494         handleExternalElanNetwork(elanInstance, true, (elanInstance1, interfaceName) -> {
495             createExternalElanNetwork(elanInstance1, interfaceName);
496             return null;
497         });
498     }
499
500     @Override
501     public void deleteExternalElanNetworks(Node node) {
502         handleExternalElanNetworks(node, false, (elanInstance, interfaceName) -> {
503             deleteExternalElanNetwork(elanInstance, interfaceName);
504             return null;
505         });
506     }
507
508     @Override
509     public void deleteExternalElanNetwork(ElanInstance elanInstance) {
510         handleExternalElanNetwork(elanInstance, false, (elanInstance1, interfaceName) -> {
511             deleteExternalElanNetwork(elanInstance1, interfaceName);
512             return null;
513         });
514     }
515
516     protected void deleteExternalElanNetwork(ElanInstance elanInstance, BigInteger dpnId) {
517         String providerIntfName = bridgeMgr.getProviderInterfaceName(dpnId, elanInstance.getPhysicalNetworkName());
518         String intfName = providerIntfName + IfmConstants.OF_URI_SEPARATOR + elanInstance.getSegmentationId();
519         Interface memberIntf = interfaceManager.getInterfaceInfoFromConfigDataStore(intfName);
520         if (memberIntf != null) {
521             deleteElanInterface(elanInstance.getElanInstanceName(), intfName);
522             deleteIetfInterface(intfName);
523             LOG.debug("delete vlan prv intf {} in elan {}, dpID {}", intfName,
524                     elanInstance.getElanInstanceName(), dpnId);
525         } else {
526             LOG.debug("vlan prv intf {} not found in interfacemgr config DS", intfName);
527         }
528     }
529
530     private void deleteExternalElanNetwork(ElanInstance elanInstance, String interfaceName) {
531         if (interfaceName == null) {
532             LOG.trace("No physial interface is attached to {}", elanInstance.getPhysicalNetworkName());
533             return;
534         }
535
536         String elanInstanceName = elanInstance.getElanInstanceName();
537         for (String elanInterface : getExternalElanInterfaces(elanInstanceName)) {
538             if (elanInterface.startsWith(interfaceName)) {
539                 if (ElanUtils.isVlan(elanInstance)) {
540                     deleteIetfInterface(elanInterface);
541                 }
542                 String trunkInterfaceName = getTrunkInterfaceName(interfaceName);
543                 if (shouldDeleteTrunk(trunkInterfaceName, elanInterface)) {
544                     deleteIetfInterface(trunkInterfaceName);
545                 }
546                 deleteElanInterface(elanInstanceName, elanInterface);
547             }
548         }
549     }
550
551     private boolean shouldDeleteTrunk(String trunkInterfaceName, String elanInterfaceName) {
552         List<Interface> childInterfaces = interfaceManager.getChildInterfaces(trunkInterfaceName);
553         if (childInterfaces == null || childInterfaces.isEmpty()
554                 || childInterfaces.size() == 1 && elanInterfaceName.equals(childInterfaces.get(0).getName())) {
555             LOG.debug("No more VLAN member interfaces left for trunk {}", trunkInterfaceName);
556             return true;
557         }
558
559         LOG.debug("Trunk interface {} has {} VLAN member interfaces left", trunkInterfaceName, childInterfaces.size());
560         return false;
561     }
562
563     @Override
564     public void updateExternalElanNetworks(Node origNode, Node updatedNode) {
565         if (!bridgeMgr.isIntegrationBridge(updatedNode)) {
566             return;
567         }
568
569         List<ElanInstance> elanInstances = getElanInstances();
570         if (elanInstances == null || elanInstances.isEmpty()) {
571             LOG.trace("No ELAN instances found");
572             return;
573         }
574
575         LOG.debug("updateExternalElanNetworks, orig bridge {} . updated bridge {}", origNode, updatedNode);
576
577         Map<String, String> origProviderMappping = getMapFromOtherConfig(origNode,
578                 ElanBridgeManager.PROVIDER_MAPPINGS_KEY);
579         Map<String, String> updatedProviderMappping = getMapFromOtherConfig(updatedNode,
580                 ElanBridgeManager.PROVIDER_MAPPINGS_KEY);
581
582         boolean hasDatapathIdOnOrigNode = bridgeMgr.hasDatapathID(origNode);
583         boolean hasDatapathIdOnUpdatedNode = bridgeMgr.hasDatapathID(updatedNode);
584         BigInteger origDpnID = bridgeMgr.getDatapathId(origNode);
585
586         for (ElanInstance elanInstance : elanInstances) {
587             String physicalNetworkName = elanInstance.getPhysicalNetworkName();
588             boolean createExternalElanNw = true;
589             if (physicalNetworkName != null) {
590                 String origPortName = origProviderMappping.get(physicalNetworkName);
591                 String updatedPortName = updatedProviderMappping.get(physicalNetworkName);
592                 /**
593                  * for internal vlan network, vlan provider interface creation should be
594                  * triggered only if there is existing vlan provider intf indicating presence
595                  * of VM ports on the DPN
596                  */
597                 if (hasDatapathIdOnOrigNode && !elanInstance.isExternal()
598                         && ElanUtils.isVlan(elanInstance)) {
599                     String externalIntf = getExternalElanInterface(elanInstance.getElanInstanceName(),
600                             origDpnID);
601                     if (externalIntf == null) {
602                         createExternalElanNw = false;
603                     }
604                 }
605                 if (hasPortNameRemoved(origPortName, updatedPortName)) {
606                     deleteExternalElanNetwork(elanInstance,
607                             bridgeMgr.getProviderInterfaceName(origNode, physicalNetworkName));
608                 }
609
610                 if (createExternalElanNw && (hasPortNameUpdated(origPortName, updatedPortName)
611                         || hasDatapathIdAdded(hasDatapathIdOnOrigNode, hasDatapathIdOnUpdatedNode))) {
612                     createExternalElanNetwork(elanInstance,
613                             bridgeMgr.getProviderInterfaceName(updatedNode, physicalNetworkName));
614                 }
615             }
616         }
617     }
618
619     private boolean hasDatapathIdAdded(boolean hasDatapathIdOnOrigNode, boolean hasDatapathIdOnUpdatedNode) {
620         return !hasDatapathIdOnOrigNode && hasDatapathIdOnUpdatedNode;
621     }
622
623     private boolean hasPortNameUpdated(String origPortName, String updatedPortName) {
624         return updatedPortName != null && !updatedPortName.equals(origPortName);
625     }
626
627     private boolean hasPortNameRemoved(String origPortName, String updatedPortName) {
628         return origPortName != null && !origPortName.equals(updatedPortName);
629     }
630
631     private Map<String, String> getMapFromOtherConfig(Node node, String otherConfigColumn) {
632         return bridgeMgr.getOpenvswitchOtherConfigMap(node, otherConfigColumn);
633     }
634
635     @Override
636     public Collection<String> getExternalElanInterfaces(String elanInstanceName) {
637         List<String> elanInterfaces = getElanInterfaces(elanInstanceName);
638         if (elanInterfaces.isEmpty()) {
639             LOG.trace("No ELAN interfaces defined for {}", elanInstanceName);
640             return Collections.emptySet();
641         }
642
643         Set<String> externalElanInterfaces = new HashSet<>();
644         for (String elanInterface : elanInterfaces) {
645             if (interfaceManager.isExternalInterface(elanInterface)) {
646                 externalElanInterfaces.add(elanInterface);
647             }
648         }
649
650         return externalElanInterfaces;
651     }
652
653     @Override
654     public String getExternalElanInterface(String elanInstanceName, BigInteger dpnId) {
655         return elanUtils.getExternalElanInterface(elanInstanceName, dpnId);
656     }
657
658     @Override
659     public boolean isExternalInterface(String interfaceName) {
660         return interfaceManager.isExternalInterface(interfaceName);
661     }
662
663     @Override
664     public ElanInterface getElanInterfaceByElanInterfaceName(String interfaceName) {
665         return ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName);
666     }
667
668     @Override
669     public void handleKnownL3DmacAddress(String macAddress, String elanInstanceName, int addOrRemove) {
670         if (addOrRemove == NwConstants.ADD_FLOW) {
671             addKnownL3DmacAddress(macAddress, elanInstanceName);
672         } else {
673             removeKnownL3DmacAddress(macAddress, elanInstanceName);
674         }
675     }
676
677     @Override
678     public void addKnownL3DmacAddress(String macAddress, String elanInstanceName) {
679         if (!isL2BeforeL3) {
680             LOG.trace("ELAN service is after L3VPN in the Netvirt pipeline skip known L3DMAC flows installation");
681             return;
682         }
683         ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
684         if (elanInstance == null) {
685             LOG.warn("Null elan instance {}", elanInstanceName);
686             return;
687         }
688
689         List<BigInteger> dpnsIdsForElanInstance = elanUtils.getParticipatingDpnsInElanInstance(elanInstanceName);
690         if (dpnsIdsForElanInstance.isEmpty()) {
691             LOG.warn("No DPNs for elan instance {}", elanInstance);
692             return;
693         }
694
695         elanUtils.addDmacRedirectToDispatcherFlows(elanInstance.getElanTag(), elanInstanceName, macAddress,
696                 dpnsIdsForElanInstance);
697     }
698
699     @Override
700     public void removeKnownL3DmacAddress(String macAddress, String elanInstanceName) {
701         if (!isL2BeforeL3) {
702             LOG.trace("ELAN service is after L3VPN in the Netvirt pipeline skip known L3DMAC flows installation");
703             return;
704         }
705         ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
706         if (elanInstance == null) {
707             LOG.warn("Null elan instance {}", elanInstanceName);
708             return;
709         }
710
711         List<BigInteger> dpnsIdsForElanInstance = elanUtils.getParticipatingDpnsInElanInstance(elanInstanceName);
712         if (dpnsIdsForElanInstance.isEmpty()) {
713             LOG.warn("No DPNs for elan instance {}", elanInstance);
714             return;
715         }
716
717         elanUtils.removeDmacRedirectToDispatcherFlows(elanInstance.getElanTag(), macAddress, dpnsIdsForElanInstance);
718     }
719
720     @Override
721     public List<MatchInfoBase> getEgressMatchesForElanInstance(String elanInstanceName) {
722         ElanInstance elanInstance = getElanInstance(elanInstanceName);
723         if (elanInstance == null) {
724             LOG.debug("No ELAN instance found for {}", elanInstanceName);
725             return Collections.emptyList();
726         }
727
728         Long elanTag = elanInstance.getElanTag();
729         if (elanTag == null) {
730             LOG.debug("No ELAN tag found for {}", elanInstanceName);
731             return Collections.emptyList();
732         }
733         return Collections.singletonList(
734                 new NxMatchRegister(ElanConstants.ELAN_REG_ID, elanTag, MetaDataUtil.getElanMaskForReg()));
735     }
736
737     /**
738      * Create ietf-interfaces based on the ELAN segment type.<br>
739      * For segment type flat - create transparent interface pointing to the
740      * patch-port attached to the physnet port.<br>
741      * For segment type vlan - create trunk interface pointing to the patch-port
742      * attached to the physnet port + trunk-member interface pointing to the
743      * trunk interface.
744      *
745      * @param elanInstance
746      *            ELAN instance
747      * @param parentRef
748      *            parent interface name
749      * @return the name of the interface to be added to the ELAN instance i.e.
750      *         trunk-member name for vlan network and transparent for flat
751      *         network or null otherwise
752      */
753     private String createIetfInterfaces(ElanInstance elanInstance, String parentRef) {
754         String interfaceName = null;
755
756         try {
757             String trunkName = getTrunkInterfaceName(parentRef);
758             // trunk interface may have been created by other vlan network
759             Interface trunkInterface = interfaceManager.getInterfaceInfoFromConfigDataStore(trunkName);
760             if (trunkInterface == null) {
761                 interfaceManager.createVLANInterface(trunkName, parentRef, null, null,
762                         IfL2vlan.L2vlanMode.Trunk, true);
763             }
764             if (ElanUtils.isFlat(elanInstance)) {
765                 interfaceName = trunkName;
766             } else if (ElanUtils.isVlan(elanInstance)) {
767                 Long segmentationId = elanInstance.getSegmentationId();
768                 interfaceName = parentRef + IfmConstants.OF_URI_SEPARATOR + segmentationId;
769                 interfaceManager.createVLANInterface(interfaceName, trunkName, segmentationId.intValue(), null,
770                         IfL2vlan.L2vlanMode.TrunkMember, true);
771             }
772         } catch (InterfaceAlreadyExistsException e) {
773             LOG.trace("Interface {} was already created", interfaceName);
774         }
775
776         return interfaceName;
777     }
778
779     private void deleteIetfInterface(String interfaceName) {
780         InterfaceKey interfaceKey = new InterfaceKey(interfaceName);
781         InstanceIdentifier<Interface> interfaceInstanceIdentifier = InstanceIdentifier.builder(Interfaces.class)
782                 .child(Interface.class, interfaceKey).build();
783         MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, interfaceInstanceIdentifier);
784         LOG.debug("Deleting IETF interface {}", interfaceName);
785     }
786
787     private void handleExternalElanNetworks(Node node, boolean skipIntVlanNw,
788                                             BiFunction<ElanInstance, String, Void> function) {
789         if (!bridgeMgr.isIntegrationBridge(node)) {
790             return;
791         }
792
793         List<ElanInstance> elanInstances = getElanInstances();
794         if (elanInstances == null || elanInstances.isEmpty()) {
795             LOG.trace("No ELAN instances found");
796             return;
797         }
798
799         for (ElanInstance elanInstance : elanInstances) {
800             if (skipIntVlanNw && !elanInstance.isExternal() && ElanUtils.isVlan(elanInstance)) {
801                 continue;
802             }
803             String interfaceName = bridgeMgr.getProviderInterfaceName(node, elanInstance.getPhysicalNetworkName());
804             if (interfaceName != null) {
805                 function.apply(elanInstance, interfaceName);
806             }
807         }
808     }
809
810     private void handleExternalElanNetwork(ElanInstance elanInstance, boolean update,
811                                            BiFunction<ElanInstance, String, Void> function) {
812         String elanInstanceName = elanInstance.getElanInstanceName();
813         if (elanInstance.getPhysicalNetworkName() == null) {
814             LOG.trace("No physical network attached to {}", elanInstanceName);
815             return;
816         }
817
818         List<Node> nodes = southboundUtils.getOvsdbNodes();
819         if (nodes == null || nodes.isEmpty()) {
820             LOG.trace("No OVS nodes found while creating external network for ELAN {}",
821                     elanInstance.getElanInstanceName());
822             return;
823         }
824
825         for (Node node : nodes) {
826             if (bridgeMgr.isIntegrationBridge(node)) {
827                 if (update && !elanInstance.isExternal()) {
828                     DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanInstanceName,
829                             bridgeMgr.getDatapathId(node));
830                     if (dpnInterfaces == null || dpnInterfaces.getInterfaces().isEmpty()) {
831                         continue;
832                     }
833                 }
834                 String interfaceName = bridgeMgr.getProviderInterfaceName(node, elanInstance.getPhysicalNetworkName());
835                 function.apply(elanInstance, interfaceName);
836             }
837         }
838     }
839
840     private String getTrunkInterfaceName(String parentRef) {
841         return parentRef + IfmConstants.OF_URI_SEPARATOR + "trunk";
842     }
843
844     private void setIsL2BeforeL3() {
845         short elanServiceRealIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME,
846                 NwConstants.ELAN_SERVICE_INDEX);
847         short l3vpnServiceRealIndex = ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
848                 NwConstants.L3VPN_SERVICE_INDEX);
849         if (elanServiceRealIndex < l3vpnServiceRealIndex) {
850             LOG.info("ELAN service is set before L3VPN service in the Netvirt pipeline");
851             isL2BeforeL3 = true;
852         } else {
853             LOG.info("ELAN service is set after L3VPN service in the Netvirt pipeline");
854             isL2BeforeL3 = false;
855         }
856     }
857
858     @Override
859     public void addArpResponderFlow(ArpResponderInput arpResponderInput) {
860         String ingressInterfaceName = arpResponderInput.getInterfaceName();
861         String macAddress = arpResponderInput.getSha();
862         String ipAddress = arpResponderInput.getSpa();
863         int lportTag = arpResponderInput.getLportTag();
864         BigInteger dpnId = arpResponderInput.getDpId();
865
866         LOG.info("Installing the ARP responder flow on DPN {} for Interface {} with MAC {} & IP {}", dpnId,
867                 ingressInterfaceName, macAddress, ipAddress);
868         ElanInterface elanIface = ElanUtils.getElanInterfaceByElanInterfaceName(broker, ingressInterfaceName);
869         ElanInstance elanInstance = elanInstanceCache.get(elanIface.getElanInstanceName()).orNull();
870         if (elanInstance == null) {
871             LOG.debug("addArpResponderFlow: elanInstance is null, Failed to install arp responder flow for Interface {}"
872                       + " with MAC {} & IP {}", dpnId,
873                 ingressInterfaceName, macAddress, ipAddress);
874             return;
875         }
876         String flowId = ArpResponderUtil.getFlowId(lportTag, ipAddress);
877         ArpResponderUtil.installFlow(mdsalManager, dpnId, flowId, flowId, NwConstants.DEFAULT_ARP_FLOW_PRIORITY,
878                 ArpResponderUtil.generateCookie(lportTag, ipAddress),
879                 ArpResponderUtil.getMatchCriteria(lportTag, elanInstance, ipAddress),
880                 arpResponderInput.getInstructions());
881         LOG.info("Installed the ARP Responder flow for Interface {}", ingressInterfaceName);
882     }
883
884     @Override
885     public void addExternalTunnelArpResponderFlow(ArpResponderInput arpResponderInput, String elanInstanceName) {
886         BigInteger dpnId = arpResponderInput.getDpId();
887         String ipAddress = arpResponderInput.getSpa();
888         String macAddress = arpResponderInput.getSha();
889
890         LOG.trace("Installing the ExternalTunnel ARP responder flow on DPN {} for ElanInstance {} with MAC {} & IP {}",
891                 dpnId, elanInstanceName, macAddress, ipAddress);
892
893         ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
894         if (elanInstance == null) {
895             LOG.warn("Null elan instance {}", elanInstanceName);
896             return;
897         }
898
899         int lportTag = arpResponderInput.getLportTag();
900         String flowId = ArpResponderUtil.getFlowId(lportTag, ipAddress);
901         ArpResponderUtil.installFlow(mdsalManager, dpnId, flowId, flowId, NwConstants.DEFAULT_ARP_FLOW_PRIORITY,
902                 ArpResponderUtil.generateCookie(lportTag, ipAddress), ArpResponderUtil.getMatchCriteria(lportTag,
903                         elanInstance, ipAddress), arpResponderInput.getInstructions());
904         LOG.trace("Installed the ExternalTunnel ARP Responder flow for ElanInstance {}", elanInstanceName);
905     }
906
907     @Override
908     public void removeArpResponderFlow(ArpResponderInput arpResponderInput) {
909         elanUtils.removeArpResponderFlow(arpResponderInput.getDpId(), arpResponderInput.getInterfaceName(),
910                 arpResponderInput.getSpa(), arpResponderInput.getLportTag());
911     }
912
913     /**
914      * Uses the IdManager to retrieve a brand new ElanTag.
915      *
916      * @param idKey
917      *            the id key
918      * @return the integer
919      */
920     @Override
921     public Long retrieveNewElanTag(String idKey) {
922         return elanUtils.retrieveNewElanTag(idManager, idKey);
923     }
924
925     @Override
926     public InstanceIdentifier<DpnInterfaces> getElanDpnInterfaceOperationalDataPath(
927                                                                 String elanInstanceName, BigInteger dpnId) {
928         return ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpnId);
929     }
930
931     @Override
932     public DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId) {
933         return elanUtils.getElanInterfaceInfoByElanDpn(elanInstanceName, dpId);
934     }
935
936 }