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