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