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