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