Fixup Augmentable and Identifiable methods changing
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / LearntVpnVipToPortEventProcessor.java
1 /*
2  * Copyright (c) 2018 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.vpnmanager;
9
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.concurrent.Callable;
17
18 import javax.annotation.PostConstruct;
19 import javax.annotation.PreDestroy;
20 import javax.inject.Inject;
21 import javax.inject.Singleton;
22
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.genius.arputil.api.ArpConstants;
26 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
27 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
29 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
30 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
31 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
32 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
33 import org.opendaylight.mdsal.eos.binding.api.Entity;
34 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipCandidateRegistration;
35 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
36 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
37 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
38 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
39 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.AlivenessMonitorService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortEventAction;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortEventData;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.AdjacencyType;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.event.data.LearntVpnVipToPortEvent;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
53 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 @Singleton
58 public class LearntVpnVipToPortEventProcessor
59         extends AsyncClusteredDataTreeChangeListenerBase<LearntVpnVipToPortEvent, LearntVpnVipToPortEventProcessor> {
60     private static final Logger LOG = LoggerFactory.getLogger(LearntVpnVipToPortEventProcessor.class);
61     private final DataBroker dataBroker;
62     private final ManagedNewTransactionRunner txRunner;
63     private final OdlInterfaceRpcService interfaceRpc;
64     private final IMdsalApiManager mdsalManager;
65     private final AlivenessMonitorService alivenessManager;
66     private final INeutronVpnManager neutronVpnService;
67     private final IInterfaceManager interfaceManager;
68     private final IdManagerService idManager;
69     public static final String MIP_PROCESSING_JOB  = "MIP-JOB";
70     private final JobCoordinator jobCoordinator;
71     private final EntityOwnershipUtils entityOwnershipUtils;
72     private EntityOwnershipCandidateRegistration candidateRegistration;
73
74     @Inject
75     public LearntVpnVipToPortEventProcessor(final DataBroker dataBroker, final OdlInterfaceRpcService interfaceRpc,
76                                             IMdsalApiManager mdsalManager, AlivenessMonitorService alivenessManager,
77                                             INeutronVpnManager neutronVpnService, IInterfaceManager interfaceManager,
78                                             EntityOwnershipService entityOwnershipService,
79                                             IdManagerService idManagerService, final JobCoordinator jobCoordinator) {
80         super(LearntVpnVipToPortEvent.class, LearntVpnVipToPortEventProcessor.class);
81         this.dataBroker = dataBroker;
82         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
83         this.interfaceRpc = interfaceRpc;
84         this.mdsalManager = mdsalManager;
85         this.alivenessManager = alivenessManager;
86         this.neutronVpnService = neutronVpnService;
87         this.interfaceManager = interfaceManager;
88         this.idManager = idManagerService;
89         this.jobCoordinator = jobCoordinator;
90         this.entityOwnershipUtils = new EntityOwnershipUtils(entityOwnershipService);
91     }
92
93     @PostConstruct
94     public void start() {
95         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
96         try {
97             candidateRegistration = entityOwnershipUtils.getEntityOwnershipService()
98                     .registerCandidate(new Entity(VpnConstants.ARP_MONITORING_ENTITY,
99                             VpnConstants.ARP_MONITORING_ENTITY));
100         } catch (CandidateAlreadyRegisteredException e) {
101             LOG.error("Failed to register the entity {}", VpnConstants.ARP_MONITORING_ENTITY);
102         }
103     }
104
105     @PreDestroy
106     @Override
107     public void close() {
108         super.close();
109         if (candidateRegistration != null) {
110             candidateRegistration.close();
111         }
112     }
113
114     @Override
115     protected InstanceIdentifier<LearntVpnVipToPortEvent> getWildCardPath() {
116         return InstanceIdentifier.create(LearntVpnVipToPortEventData.class).child(LearntVpnVipToPortEvent.class);
117     }
118
119     @Override
120     protected LearntVpnVipToPortEventProcessor getDataTreeChangeListener() {
121         return this;
122     }
123
124     @Override
125     protected void update(InstanceIdentifier<LearntVpnVipToPortEvent> id, LearntVpnVipToPortEvent value,
126             LearntVpnVipToPortEvent dataObjectModificationAfter) {
127         // Updates does not make sense on an event queue .
128         // NOTE: DONOT ADD ANY CODE HERE AND MAKE A CIRCUS
129     }
130
131     @Override
132     protected void add(InstanceIdentifier<LearntVpnVipToPortEvent> identifier, LearntVpnVipToPortEvent value) {
133         // AFTER PROCESSING THE EVENT, REMOVE THE EVENT FROM THE QUEUE
134         entityOwnershipUtils.runOnlyInOwnerNode(VpnConstants.ARP_MONITORING_ENTITY,
135                 VpnConstants.ARP_MONITORING_ENTITY, jobCoordinator, "LearntVpnVipToPortEvent-Handler", () -> {
136                 try {
137                     String vpnName = value.getVpnName();
138                     String ipAddress = value.getSrcFixedip();
139                     if (value.getEventAction() == LearntVpnVipToPortEventAction.Add) {
140                         jobCoordinator.enqueueJob(buildJobKey(ipAddress, vpnName), new AddMipAdjacencyWorker(value));
141                     }
142                     if (value.getEventAction() == LearntVpnVipToPortEventAction.Delete) {
143                         jobCoordinator.enqueueJob(buildJobKey(ipAddress, vpnName),
144                                 new DeleteMipAdjacencyWorker(value));
145                     }
146                 } finally {
147                     // remove the processed event
148                     VpnUtil.removeLearntVpnVipToPortEvent(dataBroker, value.getLearntVpnVipEventId(), null);
149                 }
150             });
151     }
152
153     @Override
154     protected void remove(InstanceIdentifier<LearntVpnVipToPortEvent> key, LearntVpnVipToPortEvent value) {
155         // Removals are triggered by add handling.
156         // NOTE: DONOT ADD ANY CODE HERE AND MAKE A CIRCUS
157     }
158
159     static String buildJobKey(String ip, String vpnName) {
160         return new StringBuilder(ArpConstants.ARPJOB).append('-').append(vpnName).append('-').append(ip).toString();
161     }
162
163     private class AddMipAdjacencyWorker implements Callable<List<ListenableFuture<Void>>> {
164         String vpnName;
165         String interfaceName;
166         String srcIpAddress;
167         String destIpAddress;
168         String macAddress;
169
170         AddMipAdjacencyWorker(LearntVpnVipToPortEvent event) {
171             this.vpnName = event.getVpnName();
172             this.interfaceName = event.getPortName();
173             this.srcIpAddress = event.getSrcFixedip();
174             this.destIpAddress = event.getDestFixedip();
175             this.macAddress = event.getMacAddress();
176         }
177
178         @Override
179         public List<ListenableFuture<Void>> call() {
180             return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(operTx -> {
181                 addMipAdjacency(vpnName, interfaceName,
182                         srcIpAddress, macAddress, destIpAddress);
183                 VpnUtil.createLearntVpnVipToPort(dataBroker, vpnName, srcIpAddress,
184                         interfaceName, macAddress, operTx);
185             }));
186         }
187
188         private void addMipAdjacency(String vpnInstName, String vpnInterface, String srcPrefix, String mipMacAddress,
189                                      String dstPrefix) {
190             LOG.trace("Adding {} adjacency to VPN Interface {} ", srcPrefix, vpnInterface);
191             InstanceIdentifier<VpnInterface> vpnIfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface);
192             InstanceIdentifier<Adjacencies> path = vpnIfId.augmentation(Adjacencies.class);
193             synchronized (vpnInterface.intern()) {
194                 Optional<Adjacencies> adjacencies = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, path);
195                 String nextHopIpAddr = null;
196                 String nextHopMacAddress = null;
197                 String ip = srcPrefix;
198                 if (interfaceManager.isExternalInterface(vpnInterface)) {
199                     String subnetId = getSubnetId(vpnInstName, dstPrefix);
200                     if (subnetId == null) {
201                         LOG.trace("Can't find corresponding subnet for src IP {}, src MAC {}, dst IP {},  in VPN {}",
202                                 srcPrefix, mipMacAddress, dstPrefix, vpnInstName);
203                         return;
204                     }
205                     ip = VpnUtil.getIpPrefix(ip);
206                     AdjacencyBuilder newAdjBuilder = new AdjacencyBuilder().setIpAddress(ip)
207                             .withKey(new AdjacencyKey(ip)).setAdjacencyType(AdjacencyType.PrimaryAdjacency)
208                             .setMacAddress(mipMacAddress).setSubnetId(new Uuid(subnetId)).setPhysNetworkFunc(true);
209
210                     List<Adjacency> adjacencyList = adjacencies.isPresent()
211                             ? adjacencies.get().getAdjacency() : new ArrayList<>();
212
213                     adjacencyList.add(newAdjBuilder.build());
214
215                     Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
216                     Optional<VpnInterface> optionalVpnInterface =
217                             VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIfId);
218                     VpnInterface newVpnIntf;
219                     if (optionalVpnInterface.isPresent()) {
220                         newVpnIntf =
221                                 new VpnInterfaceBuilder(optionalVpnInterface.get())
222                                         .addAugmentation(Adjacencies.class, aug)
223                                         .build();
224                         VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIfId, newVpnIntf);
225                     }
226                     LOG.debug(" Successfully stored subnetroute Adjacency into VpnInterface {}", vpnInterface);
227                     return;
228                 }
229
230                 if (adjacencies.isPresent()) {
231                     List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
232                     ip = VpnUtil.getIpPrefix(ip);
233                     for (Adjacency adjacs : adjacencyList) {
234                         if (adjacs.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
235                             if (adjacs.getIpAddress().equals(ip)) {
236                                 LOG.error("The MIP {} is already present as a primary adjacency for interface {}"
237                                         + "vpn {} Skipping adjacency addition.", ip, vpnInterface, vpnInstName);
238                                 return;
239                             }
240                             nextHopIpAddr = adjacs.getIpAddress();
241                             nextHopMacAddress = adjacs.getMacAddress();
242                             break;
243                         }
244                     }
245                     if (nextHopIpAddr != null) {
246                         String rd = VpnUtil.getVpnRd(dataBroker, vpnInstName);
247                         long label =
248                                 VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
249                                         VpnUtil.getNextHopLabelKey(rd != null ? rd : vpnInstName, ip));
250                         if (label == 0) {
251                             LOG.error("Unable to fetch label from Id Manager. Bailing out of adding MIP adjacency {} "
252                                     + "to vpn interface {} for vpn {}", ip, vpnInterface, vpnInstName);
253                             return;
254                         }
255                         String nextHopIp = nextHopIpAddr.split("/")[0];
256                         AdjacencyBuilder newAdjBuilder =
257                                 new AdjacencyBuilder().setIpAddress(ip).withKey(new AdjacencyKey(ip)).setNextHopIpList(
258                                         Collections.singletonList(nextHopIp)).setAdjacencyType(AdjacencyType.LearntIp);
259                         if (mipMacAddress != null && !mipMacAddress.equalsIgnoreCase(nextHopMacAddress)) {
260                             newAdjBuilder.setMacAddress(mipMacAddress);
261                         }
262                         adjacencyList.add(newAdjBuilder.build());
263                         Adjacencies aug = VpnUtil.getVpnInterfaceAugmentation(adjacencyList);
264                         Optional<VpnInterface> optionalVpnInterface =
265                                 VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIfId);
266                         VpnInterface newVpnIntf;
267                         if (optionalVpnInterface.isPresent()) {
268                             newVpnIntf =
269                                     new VpnInterfaceBuilder(optionalVpnInterface.get())
270                                             .addAugmentation(Adjacencies.class, aug).build();
271                             VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
272                                     vpnIfId, newVpnIntf);
273                         }
274                         LOG.debug(" Successfully stored subnetroute Adjacency into VpnInterface {}", vpnInterface);
275                     }
276                 }
277             }
278         }
279
280         private String getSubnetId(String vpnInstName, String ip) {
281             // Check if this IP belongs to a router_interface
282             VpnPortipToPort vpnPortipToPort =
283                     VpnUtil.getNeutronPortFromVpnPortFixedIp(dataBroker, vpnInstName, ip);
284             if (vpnPortipToPort != null && vpnPortipToPort.isSubnetIp()) {
285                 List<Adjacency> adjacecnyList = VpnUtil.getAdjacenciesForVpnInterfaceFromConfig(dataBroker,
286                         vpnPortipToPort.getPortName());
287                 for (Adjacency adjacency : adjacecnyList) {
288                     if (adjacency.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
289                         return adjacency.getSubnetId().getValue();
290                     }
291                 }
292             }
293
294             // Check if this IP belongs to a router_gateway
295             List<Uuid> routerIds = VpnUtil.getExternalNetworkRouterIds(dataBroker, new Uuid(vpnInstName));
296             for (Uuid routerId : routerIds) {
297                 Uuid subnetId = VpnUtil.getSubnetFromExternalRouterByIp(dataBroker, routerId, ip);
298                 if (subnetId != null) {
299                     return subnetId.getValue();
300                 }
301             }
302
303             return null;
304         }
305     }
306
307     private class DeleteMipAdjacencyWorker implements Callable<List<ListenableFuture<Void>>> {
308         String vpnName;
309         String interfaceName;
310         String ipAddress;
311
312         DeleteMipAdjacencyWorker(LearntVpnVipToPortEvent event) {
313             this.vpnName = event.getVpnName();
314             this.interfaceName = event.getPortName();
315             this.ipAddress = event.getSrcFixedip();
316         }
317
318         @Override
319         public List<ListenableFuture<Void>> call() throws Exception {
320             List<ListenableFuture<Void>> futures = new ArrayList<>();
321             VpnUtil.removeMipAdjAndLearntIp(dataBroker, vpnName, interfaceName,  ipAddress);
322             return futures;
323         }
324
325     }
326
327 }
328