Fix for VM Migration Table 51 stale entry
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / internal / ElanLearntVpnVipToPortListener.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.elan.internal;
9
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.concurrent.Callable;
17 import javax.annotation.PostConstruct;
18 import javax.inject.Inject;
19 import javax.inject.Singleton;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
24 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
25 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
26 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
27 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
28 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
29 import org.opendaylight.netvirt.elan.ElanException;
30 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
31 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
32 import org.opendaylight.netvirt.elan.utils.ElanConstants;
33 import org.opendaylight.netvirt.elan.utils.ElanUtils;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 @Singleton
47 public class ElanLearntVpnVipToPortListener extends
48         AsyncDataTreeChangeListenerBase<LearntVpnVipToPort, ElanLearntVpnVipToPortListener> {
49     private static final Logger LOG = LoggerFactory.getLogger(ElanLearntVpnVipToPortListener.class);
50     private final DataBroker broker;
51     private final ManagedNewTransactionRunner txRunner;
52     private final IInterfaceManager interfaceManager;
53     private final ElanUtils elanUtils;
54     private final JobCoordinator jobCoordinator;
55     private final ElanInstanceCache elanInstanceCache;
56     private final ElanInterfaceCache elanInterfaceCache;
57
58     @Inject
59     public ElanLearntVpnVipToPortListener(DataBroker broker, IInterfaceManager interfaceManager, ElanUtils elanUtils,
60             JobCoordinator jobCoordinator, ElanInstanceCache elanInstanceCache, ElanInterfaceCache elanInterfaceCache) {
61         super(LearntVpnVipToPort.class, ElanLearntVpnVipToPortListener.class);
62         this.broker = broker;
63         this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
64         this.interfaceManager = interfaceManager;
65         this.elanUtils = elanUtils;
66         this.jobCoordinator = jobCoordinator;
67         this.elanInstanceCache = elanInstanceCache;
68         this.elanInterfaceCache = elanInterfaceCache;
69     }
70
71     @Override
72     @PostConstruct
73     public void init() {
74         registerListener(LogicalDatastoreType.OPERATIONAL, broker);
75     }
76
77     @Override
78     protected InstanceIdentifier<LearntVpnVipToPort> getWildCardPath() {
79         return InstanceIdentifier.create(LearntVpnVipToPortData.class).child(LearntVpnVipToPort.class);
80     }
81
82     @Override
83     protected void remove(InstanceIdentifier<LearntVpnVipToPort> key, LearntVpnVipToPort dataObjectModification) {
84         String macAddress = dataObjectModification.getMacAddress();
85         String interfaceName = dataObjectModification.getPortName();
86         LOG.trace("Removing mac address {} from interface {} ", macAddress, interfaceName);
87         jobCoordinator.enqueueJob(buildJobKey(macAddress, interfaceName),
88                 new StaticMacRemoveWorker(macAddress, interfaceName));
89     }
90
91     @Override
92     protected void update(InstanceIdentifier<LearntVpnVipToPort> key, LearntVpnVipToPort dataObjectModificationBefore,
93             LearntVpnVipToPort dataObjectModificationAfter) {
94     }
95
96     @Override
97     protected void add(InstanceIdentifier<LearntVpnVipToPort> key, LearntVpnVipToPort dataObjectModification) {
98         String macAddress = dataObjectModification.getMacAddress();
99         String interfaceName = dataObjectModification.getPortName();
100         LOG.trace("Adding mac address {} to interface {} ", macAddress, interfaceName);
101         jobCoordinator.enqueueJob(buildJobKey(macAddress, interfaceName),
102                 new StaticMacAddWorker(macAddress, interfaceName));
103     }
104
105     @Override
106     protected ElanLearntVpnVipToPortListener getDataTreeChangeListener() {
107         return this;
108     }
109
110     private class StaticMacAddWorker implements Callable<List<ListenableFuture<Void>>> {
111         String macAddress;
112         String interfaceName;
113
114         StaticMacAddWorker(String macAddress, String interfaceName) {
115             this.macAddress = macAddress;
116             this.interfaceName = interfaceName;
117         }
118
119         @Override
120         public List<ListenableFuture<Void>> call() throws Exception {
121             Optional<ElanInterface> elanInterface = elanInterfaceCache.get(interfaceName);
122             if (!elanInterface.isPresent()) {
123                 LOG.debug("ElanInterface Not present for interfaceName {} for add event", interfaceName);
124                 return Collections.emptyList();
125             }
126             List<ListenableFuture<Void>> futures = new ArrayList<>();
127             futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(interfaceTx -> futures.add(
128                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(
129                         flowTx -> addMacEntryToDsAndSetupFlows(elanInterface.get().getElanInstanceName(),
130                                 interfaceTx, flowTx, ElanConstants.STATIC_MAC_TIMEOUT)))));
131             return futures;
132         }
133
134         private void addMacEntryToDsAndSetupFlows(String elanName, WriteTransaction interfaceTx,
135                 WriteTransaction flowTx, int macTimeOut) throws ElanException {
136             LOG.trace("Adding mac address {} and interface name {} to ElanInterfaceForwardingEntries and "
137                 + "ElanForwardingTables DS", macAddress, interfaceName);
138             BigInteger timeStamp = new BigInteger(String.valueOf(System.currentTimeMillis()));
139             PhysAddress physAddress = new PhysAddress(macAddress);
140             MacEntry macEntry = new MacEntryBuilder().setInterface(interfaceName).setMacAddress(physAddress)
141                     .setKey(new MacEntryKey(physAddress)).setControllerLearnedForwardingEntryTimestamp(timeStamp)
142                     .setIsStaticAddress(false).build();
143             InstanceIdentifier<MacEntry> macEntryId = ElanUtils
144                     .getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress);
145             interfaceTx.put(LogicalDatastoreType.OPERATIONAL, macEntryId, macEntry);
146             InstanceIdentifier<MacEntry> elanMacEntryId =
147                     ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress);
148             interfaceTx.put(LogicalDatastoreType.OPERATIONAL, elanMacEntryId, macEntry);
149             ElanInstance elanInstance = elanInstanceCache.get(elanName).orNull();
150             elanUtils.setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), macTimeOut,
151                     macAddress, true, flowTx);
152         }
153     }
154
155     private class StaticMacRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
156         String macAddress;
157         String interfaceName;
158
159         StaticMacRemoveWorker(String macAddress, String interfaceName) {
160             this.macAddress = macAddress;
161             this.interfaceName = interfaceName;
162         }
163
164         @Override
165         public List<ListenableFuture<Void>> call() {
166             Optional<ElanInterface> elanInterface = elanInterfaceCache.get(interfaceName);
167             if (!elanInterface.isPresent()) {
168                 LOG.debug("ElanInterface Not present for interfaceName {} for delete event", interfaceName);
169                 return Collections.emptyList();
170             }
171             List<ListenableFuture<Void>> futures = new ArrayList<>();
172             futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(interfaceTx -> futures.add(
173                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(
174                         flowTx -> deleteMacEntryFromDsAndRemoveFlows(elanInterface.get().getElanInstanceName(),
175                                 interfaceTx, flowTx)))));
176             return futures;
177         }
178
179         private void deleteMacEntryFromDsAndRemoveFlows(String elanName, WriteTransaction interfaceTx,
180                 WriteTransaction flowTx) {
181             LOG.trace("Deleting mac address {} and interface name {} from ElanInterfaceForwardingEntries "
182                     + "and ElanForwardingTables DS", macAddress, interfaceName);
183             PhysAddress physAddress = new PhysAddress(macAddress);
184             MacEntry macEntry = elanUtils.getInterfaceMacEntriesOperationalDataPath(interfaceName, physAddress);
185             InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
186             if (macEntry != null && interfaceInfo != null) {
187                 elanUtils.deleteMacFlows(elanInstanceCache.get(elanName).orNull(), interfaceInfo, macEntry, flowTx);
188                 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
189                         ElanUtils.getInterfaceMacEntriesIdentifierOperationalDataPath(interfaceName, physAddress));
190                 interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
191                         ElanUtils.getMacEntryOperationalDataPath(elanName, physAddress));
192             }
193         }
194     }
195
196     private String buildJobKey(String mac, String interfaceName) {
197         return "ENTERPRISEMACJOB" + mac + interfaceName;
198     }
199
200
201 }