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