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