Make TunnelEndPointInfo work on Uint64
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / itmdirecttunnels / listeners / TunnelInventoryStateListener.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.genius.itm.itmdirecttunnels.listeners;
9
10 import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
11 import static org.opendaylight.mdsal.binding.util.Datastore.OPERATIONAL;
12
13 import com.google.common.util.concurrent.ListenableFuture;
14 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.Objects;
19 import java.util.Optional;
20 import java.util.concurrent.Callable;
21 import java.util.concurrent.ConcurrentHashMap;
22 import java.util.concurrent.ConcurrentMap;
23 import org.eclipse.jdt.annotation.NonNull;
24 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
25 import org.opendaylight.genius.itm.cache.DPNTEPsInfoCache;
26 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
27 import org.opendaylight.genius.itm.cache.OfDpnTepConfigCache;
28 import org.opendaylight.genius.itm.cache.TunnelStateCache;
29 import org.opendaylight.genius.itm.cache.UnprocessedNodeConnectorCache;
30 import org.opendaylight.genius.itm.cache.UnprocessedNodeConnectorEndPointCache;
31 import org.opendaylight.genius.itm.cache.UnprocessedOFNodeConnectorCache;
32 import org.opendaylight.genius.itm.globals.ITMConstants;
33 import org.opendaylight.genius.itm.impl.ItmUtils;
34 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
35 import org.opendaylight.genius.itm.itmdirecttunnels.workers.OfPortStateAddWorker;
36 import org.opendaylight.genius.itm.itmdirecttunnels.workers.OfPortStateAddWorkerForNodeConnector;
37 import org.opendaylight.genius.itm.itmdirecttunnels.workers.TunnelStateAddWorker;
38 import org.opendaylight.genius.itm.itmdirecttunnels.workers.TunnelStateAddWorkerForNodeConnector;
39 import org.opendaylight.genius.itm.utils.DpnTepInterfaceInfo;
40 import org.opendaylight.genius.itm.utils.NodeConnectorInfo;
41 import org.opendaylight.genius.itm.utils.NodeConnectorInfoBuilder;
42 import org.opendaylight.genius.itm.utils.TunnelEndPointInfo;
43 import org.opendaylight.genius.itm.utils.TunnelStateInfo;
44 import org.opendaylight.genius.itm.utils.TunnelStateInfoBuilder;
45 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
46 import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.Acquired;
47 import org.opendaylight.mdsal.binding.api.DataBroker;
48 import org.opendaylight.mdsal.binding.util.Datastore.Operational;
49 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
50 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
51 import org.opendaylight.mdsal.binding.util.TypedReadWriteTransaction;
52 import org.opendaylight.mdsal.binding.util.TypedWriteTransaction;
53 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
54 import org.opendaylight.mdsal.common.api.ReadFailedException;
55 import org.opendaylight.serviceutils.tools.listener.AbstractClusteredSyncDataTreeChangeListener;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortReason;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.tep.config.OfDpnTep;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.of.teps.state.OfTep;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.of.teps.state.OfTepBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.of.teps.state.OfTepKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
71 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
72 import org.opendaylight.yangtools.yang.common.Uint64;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
75
76 /**
77  * This Class is a Data Change Listener for FlowCapableNodeConnector updates.
78  * This creates an entry in the tunnels-state OperDS for every node-connector used.
79  */
80 public class TunnelInventoryStateListener extends
81     AbstractClusteredSyncDataTreeChangeListener<FlowCapableNodeConnector> {
82
83     private static final Logger LOG = LoggerFactory.getLogger(TunnelInventoryStateListener.class);
84     private static final Logger EVENT_LOGGER = LoggerFactory.getLogger("GeniusEventLogger");
85
86     private final JobCoordinator coordinator;
87     private final ManagedNewTransactionRunner txRunner;
88     private final TunnelStateCache tunnelStateCache;
89     private final DpnTepStateCache dpnTepStateCache;
90     private final DPNTEPsInfoCache dpntePsInfoCache;
91     private final UnprocessedNodeConnectorCache unprocessedNCCache;
92     private final UnprocessedNodeConnectorEndPointCache unprocessedNodeConnectorEndPointCache;
93     private final DirectTunnelUtils directTunnelUtils;
94     private final ConcurrentMap<String, NodeConnectorInfo> meshedMap = new ConcurrentHashMap<>();
95     private final UnprocessedOFNodeConnectorCache unprocessedOFNCCache;
96     private final OfDpnTepConfigCache ofDpnTepConfigCache;
97     private final IInterfaceManager interfaceManager;
98
99     public TunnelInventoryStateListener(final DataBroker dataBroker,
100                                         final JobCoordinator coordinator,
101                                         final TunnelStateCache tunnelStateCache,
102                                         final DpnTepStateCache dpnTepStateCache,
103                                         final DPNTEPsInfoCache dpntePsInfoCache,
104                                         final UnprocessedNodeConnectorCache unprocessedNCCache,
105                                         final UnprocessedNodeConnectorEndPointCache
106                                             unprocessedNodeConnectorEndPointCache,
107                                         final DirectTunnelUtils directTunnelUtils,
108                                         UnprocessedOFNodeConnectorCache unprocessedOFNCCache,
109                                         final OfDpnTepConfigCache ofDpnTepConfigCache,
110                                         final IInterfaceManager interfaceManager) {
111         super(dataBroker, LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class).child(Node.class)
112             .child(NodeConnector.class).augmentation(FlowCapableNodeConnector.class));
113         this.coordinator = coordinator;
114         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
115         this.tunnelStateCache = tunnelStateCache;
116         this.dpnTepStateCache = dpnTepStateCache;
117         this.dpntePsInfoCache = dpntePsInfoCache;
118         this.unprocessedNCCache = unprocessedNCCache;
119         this.unprocessedNodeConnectorEndPointCache = unprocessedNodeConnectorEndPointCache;
120         this.directTunnelUtils = directTunnelUtils;
121         this.unprocessedOFNCCache = unprocessedOFNCCache;
122         this.ofDpnTepConfigCache = ofDpnTepConfigCache;
123         this.interfaceManager = interfaceManager;
124         super.register();
125     }
126
127     @Override
128     public void remove(@NonNull InstanceIdentifier<FlowCapableNodeConnector> key,
129                        @NonNull FlowCapableNodeConnector flowCapableNodeConnector) {
130         String portName = flowCapableNodeConnector.getName();
131         NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class)).getId();
132         LOG.debug("InterfaceInventoryState Remove for {}", portName);
133         EVENT_LOGGER.debug("ITM-TunnelInventoryState,REMOVE DTCN received for {}",
134                 flowCapableNodeConnector.getName());
135
136         if (!directTunnelUtils.isEntityOwner()) {
137             return;
138         }
139         // ITM Direct Tunnels Return if its not tunnel port or of-ports
140         if (portName.startsWith("of") && interfaceManager.isItmOfTunnelsEnabled()) {
141             LOG.debug("OfPortState REMOVE for {}", portName);
142             EVENT_LOGGER.debug("ITM-OfPortStateState Entity Owner, REMOVE {} {}", nodeConnectorId.getValue(), portName);
143             OfPortStateRemoveWorker ofPortStateRemoveWorker = new OfPortStateRemoveWorker(nodeConnectorId,
144                     null, flowCapableNodeConnector, portName);
145             coordinator.enqueueJob(portName, ofPortStateRemoveWorker, ITMConstants.JOB_MAX_RETRIES);
146             return;
147         } else if (!DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(portName)) {
148             LOG.debug("Node Connector Remove - {} Interface is not a tunnel I/f, so no-op", portName);
149             return;
150         }
151
152         try {
153             if (!tunnelStateCache.isInternalBasedOnState(portName)) {
154                 LOG.debug("Node Connector Remove {} Interface is not a internal tunnel I/f, so no-op", portName);
155                 return;
156             }
157         } catch (ReadFailedException e) {
158             LOG.error("Tunnel {} is not present in operational DS ", portName);
159             return;
160         }
161         LOG.debug("Received NodeConnector Remove Event: {}, {}", key, flowCapableNodeConnector);
162         remove(nodeConnectorId, flowCapableNodeConnector, portName);
163     }
164
165     private void remove(NodeConnectorId nodeConnectorId,
166                         FlowCapableNodeConnector fcNodeConnectorNew, String portName) {
167         LOG.debug("TunnelInventoryState REMOVE for {}", portName);
168         LOG.debug("InterfaceInventoryState REMOVE for {}", portName);
169         EVENT_LOGGER.debug("ITM-TunnelInventoryState Entity Owner, REMOVE {} {}", nodeConnectorId.getValue(),
170                 portName);
171         TunnelInterfaceStateRemoveWorker portStateRemoveWorker = new TunnelInterfaceStateRemoveWorker(nodeConnectorId,
172                 fcNodeConnectorNew, portName);
173         coordinator.enqueueJob(portName, portStateRemoveWorker, ITMConstants.JOB_MAX_RETRIES);
174     }
175
176     @Override
177     public void update(@NonNull InstanceIdentifier<FlowCapableNodeConnector> key,
178                        @NonNull FlowCapableNodeConnector fcNodeConnectorOld,
179                        @NonNull FlowCapableNodeConnector fcNodeConnectorNew) {
180         EVENT_LOGGER.debug("ITM-TunnelInventoryState,UPDATE DTCN received for {}", fcNodeConnectorOld.getName());
181         String portName = fcNodeConnectorNew.getName();
182         if (!DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(portName) && !portName.startsWith("of")) {
183             LOG.debug("Node Connector Update - {} Interface is not a tunnel I/f, so no-op", portName);
184             return;
185         } else if (!dpnTepStateCache.isInternal(portName)) {
186             LOG.debug("Node Connector Update {} Interface is not a internal tunnel I/f, so no-op", portName);
187             return;
188         }
189
190         if (fcNodeConnectorNew.getReason() == PortReason.Delete
191                 || fcNodeConnectorNew.getReason() == PortReason.Update || !directTunnelUtils.isEntityOwner()) {
192             EVENT_LOGGER.debug("ITM-TunnelInventoryState,UPDATE with reason {}, is entity owner? {}",
193                     fcNodeConnectorNew.getReason(), directTunnelUtils.isEntityOwner());
194             return;
195         }
196         LOG.debug("Received NodeConnector Update Event: {}, {}, {}", key, fcNodeConnectorOld, fcNodeConnectorNew);
197
198         TunnelInterfaceStateUpdateWorker portStateUpdateWorker =
199                 new TunnelInterfaceStateUpdateWorker(key, fcNodeConnectorOld, fcNodeConnectorNew, portName);
200         EVENT_LOGGER.debug("ITM-TunnelInventoryState Entity Owner, UPDATE {} {} Reason {}",
201                 fcNodeConnectorNew.getName(), portName, fcNodeConnectorNew.getReason());
202         coordinator.enqueueJob(portName, portStateUpdateWorker, ITMConstants.JOB_MAX_RETRIES);
203     }
204
205     @Override
206     public void add(@NonNull InstanceIdentifier<FlowCapableNodeConnector> key,
207                     @NonNull FlowCapableNodeConnector fcNodeConnectorNew) {
208         LOG.info("Received NodeConnector Add Event: {}, {}", key, fcNodeConnectorNew);
209         EVENT_LOGGER.debug("ITM-TunnelInventoryState,ADD DTCN received for {}", fcNodeConnectorNew.getName());
210         String portName = fcNodeConnectorNew.getName();
211
212         // Return if its not tunnel port and if its not Internal
213         if (!DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(portName) && !portName.startsWith("of")) {
214             LOG.debug("Node Connector Add {} Interface is not a tunnel I/f, so no-op", portName);
215             return;
216         }
217
218         if (!directTunnelUtils.isEntityOwner()) {
219             LOG.debug("Not an entity owner.");
220             return;
221         }
222
223         //Optional<OfDpnTep> dpnTepOptional = Optional.ofNullable(null);
224         NodeConnectorInfo nodeConnectorInfo =
225                 new NodeConnectorInfoBuilder().setNodeConnectorId(key).setNodeConnector(fcNodeConnectorNew).build();
226
227         if (portName.startsWith("of") && interfaceManager.isItmOfTunnelsEnabled()) {
228             NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
229                     .getId();
230             Uint64 srcDpn = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId);
231
232             OfDpnTep dpntep = null;
233             try (Acquired lock = directTunnelUtils.lockTunnel(portName)) {
234                 try {
235                     Optional<OfDpnTep> dpnTepOptional = ofDpnTepConfigCache.get(srcDpn.toJava());
236                     if (!dpnTepOptional.isPresent()) {
237                         // Park the notification
238                         LOG.debug("Unable to process the NodeConnector ADD event for {} as Config not available."
239                                 + "Hence parking it", portName);
240                         unprocessedOFNCCache.add(portName, nodeConnectorInfo);
241                         return;
242                     } else {
243                         dpntep = dpnTepOptional.get();
244                     }
245                 } catch (ReadFailedException e) {
246                     LOG.error("unable to get ofDpnTepConfigCache");
247                 }
248             }
249
250             if (dpntep != null) {
251                 OfPortStateAddWorkerForNodeConnector ifOfStateAddWorker =
252                         new OfPortStateAddWorkerForNodeConnector(new OfPortStateAddWorker(directTunnelUtils,
253                                 dpntep, txRunner), nodeConnectorInfo);
254                 EVENT_LOGGER.debug("ITM-Of-tepInventoryState Entity Owner,ADD {} {}",
255                         nodeConnectorId.getValue(), portName);
256                 coordinator.enqueueJob(portName, ifOfStateAddWorker, ITMConstants.JOB_MAX_RETRIES);
257             }
258         } else {
259             addTunnelState(nodeConnectorInfo, portName);
260         }
261     }
262
263     private void addTunnelState(NodeConnectorInfo nodeConnectorInfo, String portName) {
264
265         TunnelStateInfo tunnelStateInfo = null;
266         TunnelEndPointInfo tunnelEndPtInfo = null;
267         try (Acquired lock = directTunnelUtils.lockTunnel(portName)) {
268             if (!dpnTepStateCache.isConfigAvailable(portName)) {
269                 // Park the notification
270                 LOG.debug("Unable to process the NodeConnector ADD event for {} as Config not available."
271                     + "Hence parking it", portName);
272                 unprocessedNCCache.add(portName,
273                     new TunnelStateInfoBuilder().setNodeConnectorInfo(nodeConnectorInfo).build());
274                 return;
275             } else if (!dpnTepStateCache.isInternal(portName)) {
276                 LOG.debug("{} Interface is not a internal tunnel I/f, so no-op", portName);
277                 return;
278             }
279         }
280
281         // Check if tunnels State has an entry for this interface.
282         // If so, then this Inventory Add is due to compute re-connection. Then, ONLY update the state
283         // to UP as previously the compute would have disconnected and so the state will be UNKNOWN.
284         try {
285             long portNo = tunnelStateCache.getNodeConnectorIdFromInterface(portName);
286             if (portNo != ITMConstants.INVALID_PORT_NO) {
287                 coordinator.enqueueJob(portName,
288                         new TunnelInterfaceNodeReconnectWorker(portName), ITMConstants.JOB_MAX_RETRIES);
289                 return;
290             }
291         } catch (ReadFailedException e) {
292             LOG.error("Exception occurred in reconnect for portName {}, reason: {}.",
293                      portName, e.getMessage());
294         }
295
296         if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(portName) && dpnTepStateCache.isInternal(portName)) {
297             tunnelEndPtInfo = dpnTepStateCache.getTunnelEndPointInfoFromCache(portName);
298             TunnelStateInfoBuilder builder = new TunnelStateInfoBuilder().setNodeConnectorInfo(nodeConnectorInfo);
299             dpntePsInfoCache.getDPNTepFromDPNId(tunnelEndPtInfo.getSrcEndPointInfo())
300                 .ifPresent(builder::setSrcDpnTepsInfo);
301             dpntePsInfoCache.getDPNTepFromDPNId(tunnelEndPtInfo.getDstEndPointInfo())
302                 .ifPresent(builder::setDstDpnTepsInfo);
303             tunnelStateInfo = builder.setTunnelEndPointInfo(tunnelEndPtInfo)
304                 .setDpnTepInterfaceInfo(dpnTepStateCache.getTunnelFromCache(portName)).build();
305
306             if (tunnelStateInfo.getSrcDpnTepsInfo() == null) {
307                 final String srcEndpoint = tunnelEndPtInfo.getSrcEndPointName();
308                 try (Acquired lock = directTunnelUtils.lockTunnel(srcEndpoint)) {
309                     LOG.debug("Source DPNTepsInfo is null for tunnel {}. Hence Parking with key {}",
310                         portName, tunnelEndPtInfo.getSrcEndPointInfo());
311                     unprocessedNodeConnectorEndPointCache.add(srcEndpoint, tunnelStateInfo);
312                 }
313             }
314             if (tunnelStateInfo.getDstDpnTepsInfo() == null) {
315                 final String dstEndpoint = tunnelEndPtInfo.getDstEndPointName();
316                 try (Acquired lock = directTunnelUtils.lockTunnel(dstEndpoint)) {
317                     LOG.debug("Destination DPNTepsInfo is null for tunnel {}. Hence Parking with key {}",
318                         portName, tunnelEndPtInfo.getDstEndPointInfo());
319                     unprocessedNodeConnectorEndPointCache.add(dstEndpoint, tunnelStateInfo);
320                 }
321             }
322         }
323
324         if (tunnelEndPtInfo != null && tunnelStateInfo.getSrcDpnTepsInfo() != null
325             && tunnelStateInfo.getDstDpnTepsInfo() != null) {
326             EVENT_LOGGER.debug("ITM-TunnelInventoryState Entity Owner,ADD {}", portName);
327             coordinator.enqueueJob(portName,
328                 new TunnelStateAddWorkerForNodeConnector(new TunnelStateAddWorker(directTunnelUtils, txRunner),
329                     tunnelStateInfo), ITMConstants.JOB_MAX_RETRIES);
330         }
331     }
332
333     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
334             justification = "https://github.com/spotbugs/spotbugs/issues/811")
335     private List<? extends ListenableFuture<?>> updateState(String interfaceName,
336         FlowCapableNodeConnector flowCapableNodeConnectorNew,
337         FlowCapableNodeConnector flowCapableNodeConnectorOld) {
338         LOG.debug("Updating interface state for port: {}", interfaceName);
339
340         // Hardware updates can be ignored
341         Interface.OperStatus operStatusNew = getOpState(flowCapableNodeConnectorNew);
342         MacAddress macAddressNew = flowCapableNodeConnectorNew.getHardwareAddress();
343
344         Interface.OperStatus operStatusOld = getOpState(flowCapableNodeConnectorOld);
345         MacAddress macAddressOld = flowCapableNodeConnectorOld.getHardwareAddress();
346
347         boolean opstateModified = false;
348         boolean hardwareAddressModified = false;
349         if (!operStatusNew.equals(operStatusOld)) {
350             opstateModified = true;
351         }
352         if (!Objects.equals(macAddressNew, macAddressOld)) {
353             hardwareAddressModified = true;
354         }
355
356         if (!opstateModified && !hardwareAddressModified) {
357             LOG.debug("If State entry for port: {} Not Modified.", interfaceName);
358             return Collections.emptyList();
359         }
360
361         DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
362
363         // For monitoring enabled tunnels, skip opstate updation
364         if (!modifyTunnelOpState(dpnTepInfo, opstateModified)) {
365             LOG.debug("skipping Tunnel-state update for monitoring enabled tunnel interface {}", interfaceName);
366             opstateModified = false;
367         }
368
369         if (!opstateModified && !hardwareAddressModified) {
370             LOG.debug("If State entry for port: {} Not Modified.", interfaceName);
371             return Collections.emptyList();
372         }
373         if (opstateModified) {
374             return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
375                 // modify the attributes in interface operational DS
376                 handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, flowCapableNodeConnectorNew.getName(),
377                         operStatusNew);
378                 EVENT_LOGGER.debug("ITM-TunnelInventoryState, UPDATE {} CHGED {} completed", interfaceName,
379                         operStatusNew.getName());
380             }));
381         } else {
382             return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
383                 // modify the attributes in interface operational DS
384                 handleInterfaceStateUpdates(tx, dpnTepInfo, false, interfaceName,
385                         flowCapableNodeConnectorNew.getName(), operStatusNew);
386                 EVENT_LOGGER.debug("ITM-TunnelInventoryState, UPDATE {} completed", interfaceName);
387             }));
388         }
389     }
390
391     private void updateInterfaceStateOnNodeRemove(TypedWriteTransaction<Operational> tx, String interfaceName,
392         FlowCapableNodeConnector flowCapableNodeConnector) {
393         LOG.debug("Updating interface oper-status to UNKNOWN for : {}", interfaceName);
394         DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
395
396         handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, flowCapableNodeConnector.getName(),
397                 Interface.OperStatus.Unknown);
398     }
399
400     private void updateOfTepStateOnNodeRemove(Uint64 srcDpn, String ofTepName,
401                                               FlowCapableNodeConnector flowCapableNodeConnector,
402                                               TypedReadWriteTransaction<Operational> tx) throws ReadFailedException {
403         LOG.debug("Updating oftep oper-status to UNKNOWN for : {}", ofTepName);
404         Optional<OfDpnTep> dpnTepInfo = ofDpnTepConfigCache.get(srcDpn.toJava());
405         if (dpnTepInfo == null || !ofTepName.equals(flowCapableNodeConnector.getName())) {
406             return;
407         }
408         handleOfTepStateUpdates(dpnTepInfo, tx, true, ofTepName,
409                 Interface.OperStatus.Unknown);
410     }
411
412     private void handleOfTepStateUpdates(Optional<OfDpnTep> dpnTepInfo, TypedReadWriteTransaction<Operational> tx,
413                                          boolean opStateModified, String ofTepName, Interface.OperStatus opState) {
414         LOG.debug("updating oftep state entry for {}", ofTepName);
415         InstanceIdentifier<OfTep> ofTepStateId = ItmUtils.buildStateOfTepListId(new OfTepKey(ofTepName));
416         OfTepBuilder ofTepBuilder = new OfTepBuilder();
417         ofTepBuilder.withKey(new OfTepKey(ofTepName));
418         if (opStateModified) {
419             LOG.debug("updating oftep oper status as {} for {}", opState.getName(), ofTepName);
420             ofTepBuilder.setOfTepState(DirectTunnelUtils.convertInterfaceToTunnelOperState(opState));
421             LOG.trace("updated to {} for {}",opState.getName(), ofTepName);
422         }
423         tx.merge(ofTepStateId, ofTepBuilder.build());
424     }
425
426     private Interface.OperStatus getOpState(FlowCapableNodeConnector flowCapableNodeConnector) {
427         return flowCapableNodeConnector.getState().isLive()
428                 && !flowCapableNodeConnector.getConfiguration().isPORTDOWN()
429                 ? Interface.OperStatus.Up : Interface.OperStatus.Down;
430     }
431
432     private void handleInterfaceStateUpdates(TypedWriteTransaction<Operational> tx,
433         DpnTepInterfaceInfo dpnTepInfo,
434         boolean opStateModified, String interfaceName, String portName,
435         Interface.OperStatus opState) {
436         if (dpnTepInfo == null && !portName.startsWith("of") && !interfaceName.equals(portName)) {
437             return;
438         }
439         LOG.debug("updating interface state entry for {}", interfaceName);
440         InstanceIdentifier<StateTunnelList> tnlStateId = ItmUtils.buildStateTunnelListId(
441                 new StateTunnelListKey(interfaceName));
442         StateTunnelListBuilder stateTnlBuilder = new StateTunnelListBuilder();
443         stateTnlBuilder.withKey(new StateTunnelListKey(interfaceName));
444         if (modifyOpState(dpnTepInfo, opStateModified)) {
445             LOG.debug("updating interface oper status as {} for {}", opState.name(), interfaceName);
446             boolean tunnelState = opState.equals(Interface.OperStatus.Up);
447             stateTnlBuilder.setTunnelState(tunnelState);
448             stateTnlBuilder.setOperState(DirectTunnelUtils.convertInterfaceToTunnelOperState(opState));
449         }
450         tx.merge(tnlStateId, stateTnlBuilder.build());
451     }
452
453     private boolean modifyOpState(DpnTepInterfaceInfo dpnTepInterfaceInfo, boolean opStateModified) {
454         return opStateModified && dpnTepInterfaceInfo != null;
455     }
456
457     private boolean modifyTunnelOpState(DpnTepInterfaceInfo dpnTepInterfaceInfo, boolean opStateModified) {
458         return !dpnTepInterfaceInfo.isMonitoringEnabled() && modifyOpState(dpnTepInterfaceInfo, opStateModified);
459     }
460
461     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
462             justification = "https://github.com/spotbugs/spotbugs/issues/811")
463     private List<? extends ListenableFuture<?>> removeInterfaceStateConfiguration(NodeConnectorId nodeConnectorId,
464                                                                                   String interfaceName,
465                                                                                   FlowCapableNodeConnector
466                                                                                       flowCapableNodeConnector) {
467
468
469         List<ListenableFuture<?>> futures = new ArrayList<>();
470         Uint64 dpId = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId);
471         // In a genuine port delete scenario, the reason will be there in the incoming event, for all remaining
472         // cases treat the event as DPN disconnect, if old and new ports are same. Else, this is a VM migration
473         // scenario, and should be treated as port removal.
474         if (flowCapableNodeConnector.getReason() != PortReason.Delete) {
475             //Remove event is because of connection lost between controller and switch, or switch shutdown.
476             // Hence, dont remove the interface but set the status as "unknown"
477
478             futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
479                 tx -> updateInterfaceStateOnNodeRemove(tx, interfaceName, flowCapableNodeConnector)));
480
481         } else {
482             LOG.debug("removing interface state for interface: {}", interfaceName);
483             directTunnelUtils.deleteTunnelStateEntry(interfaceName);
484             DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
485             if (dpnTepInfo != null) {
486                 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
487                     // Do if-index and ingress flow clean-up only for tunnel-interfaces
488                     directTunnelUtils.removeLportTagInterfaceMap(interfaceName);
489                     directTunnelUtils.removeTunnelIngressFlow(tx, dpId, interfaceName);
490                     directTunnelUtils.removeTunnelEgressFlow(tx, dpId, interfaceName);
491                 }));
492             } else {
493                 LOG.error("DPNTEPInfo is null for Tunnel Interface {}", interfaceName);
494             }
495             EVENT_LOGGER.debug("ITM-TunnelInventoryState,REMOVE Table 0 flow for {} completed", interfaceName);
496         }
497         return futures;
498     }
499
500     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
501             justification = "https://github.com/spotbugs/spotbugs/issues/811")
502     private List<? extends ListenableFuture<?>> removeOfTepStateConfiguration(NodeConnectorId nodeConnectorIdNew,
503                                                                        NodeConnectorId nodeConnectorIdOld,
504                                                                        String ofTepName,
505                                                                        FlowCapableNodeConnector
506                                                                                fcNodeConnectorOld) {
507         List<ListenableFuture<?>> futures = new ArrayList<>();
508
509         NodeConnectorId nodeConnectorId = (nodeConnectorIdOld != null && !nodeConnectorIdNew.equals(nodeConnectorIdOld))
510                 ? nodeConnectorIdOld : nodeConnectorIdNew;
511
512         Uint64 dpId = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId);
513
514             // In a genuine port delete scenario, the reason will be there in the incoming event, for all remaining
515             // cases treat the event as DPN disconnect, if old and new ports are same. Else, this is a VM migration
516             // scenario, and should be treated as port removal.
517         if (fcNodeConnectorOld.getReason() != PortReason.Delete) {
518             //Remove event is because of connection lost between controller and switch, or switch shutdown.
519             // Hence, dont remove the interface but set the status as "unknown"
520             futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
521                 updateOfTepStateOnNodeRemove(dpId, ofTepName, fcNodeConnectorOld, tx);
522             }));
523         } else {
524             LOG.debug("removing oftep state for oftep: {}", ofTepName);
525             futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
526                 directTunnelUtils.deleteOfTepStateEntry(ofTepName);
527                 directTunnelUtils.removeLportTagInterfaceMap(ofTepName);
528                 directTunnelUtils.removeTunnelIngressFlow(tx, dpId, ofTepName);
529             }));
530             EVENT_LOGGER.debug("ITM-OfTepInventoryState,REMOVE Table 0 flow for {} completed", ofTepName);
531         }
532
533         return futures;
534     }
535
536     private class TunnelInterfaceStateUpdateWorker implements Callable<List<? extends ListenableFuture<?>>> {
537         private final InstanceIdentifier<FlowCapableNodeConnector> key;
538         private final FlowCapableNodeConnector fcNodeConnectorOld;
539         private final FlowCapableNodeConnector fcNodeConnectorNew;
540         private final String interfaceName;
541
542         TunnelInterfaceStateUpdateWorker(InstanceIdentifier<FlowCapableNodeConnector> key,
543                                          FlowCapableNodeConnector fcNodeConnectorOld,
544                                          FlowCapableNodeConnector fcNodeConnectorNew, String portName) {
545             this.key = key;
546             this.fcNodeConnectorOld = fcNodeConnectorOld;
547             this.fcNodeConnectorNew = fcNodeConnectorNew;
548             this.interfaceName = portName;
549         }
550
551         @Override
552         public List<? extends ListenableFuture<?>> call() {
553             // If another renderer(for eg : OVS) needs to be supported, check can be performed here
554             // to call the respective helpers.
555             return updateState(interfaceName, fcNodeConnectorNew, fcNodeConnectorOld);
556         }
557
558         @Override
559         public String toString() {
560             return "TunnelInterfaceStateUpdateWorker{key=" + key + ", fcNodeConnectorOld=" + fcNodeConnectorOld
561                     + ", fcNodeConnectorNew=" + fcNodeConnectorNew + ", interfaceName='" + interfaceName + '\'' + '}';
562         }
563     }
564
565     private class TunnelInterfaceStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
566         private final NodeConnectorId nodeConnectorId;
567         private final FlowCapableNodeConnector flowCapableNodeConnector;
568         private final String interfaceName;
569
570         TunnelInterfaceStateRemoveWorker(NodeConnectorId nodeConnectorId,
571                                          FlowCapableNodeConnector flowCapableNodeConnector,
572                                          String interfaceName) {
573             this.nodeConnectorId = nodeConnectorId;
574             this.flowCapableNodeConnector = flowCapableNodeConnector;
575             this.interfaceName = interfaceName;
576         }
577
578         @Override
579         public List<? extends ListenableFuture<?>> call() {
580             // If another renderer(for eg : OVS) needs to be supported, check can be performed here
581             // to call the respective helpers.
582             return removeInterfaceStateConfiguration(nodeConnectorId, interfaceName, flowCapableNodeConnector);
583         }
584
585         @Override
586         public String toString() {
587             return "TunnelInterfaceStateRemoveWorker{nodeConnectorId=" + nodeConnectorId + ", fcNodeConnector"
588                     + flowCapableNodeConnector + ", interfaceName='" + interfaceName + '\'' + '}';
589         }
590     }
591
592     private class TunnelInterfaceNodeReconnectWorker implements Callable<List<? extends ListenableFuture<?>>> {
593         private final String tunnelName;
594
595         TunnelInterfaceNodeReconnectWorker(String tunnelName) {
596             this.tunnelName = tunnelName;
597         }
598
599         @Override
600         public List<? extends ListenableFuture<?>> call() throws Exception {
601             // If another renderer(for eg : OVS) needs to be supported, check can be performed here
602             // to call the respective helpers.
603             EVENT_LOGGER.debug("ITM-TunnelInventoryState, Compute Re-connected, ADD received for {} ", tunnelName);
604
605             return handleInterfaceStateOnReconnect(tunnelName);
606         }
607
608         @Override
609         public String toString() {
610             return "TunnelInterfaceNodeReconnectWorker{tunnelName=" + tunnelName + '\'' + '}';
611         }
612     }
613
614     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
615             justification = "https://github.com/spotbugs/spotbugs/issues/811")
616     private List<? extends ListenableFuture<?>> handleInterfaceStateOnReconnect(String interfaceName) {
617         List<ListenableFuture<?>> futures = new ArrayList<>();
618
619         futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
620             DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
621
622             handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, interfaceName,
623                     Interface.OperStatus.Up);
624         }));
625         return futures;
626     }
627
628     private class OfPortStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
629
630         private final NodeConnectorId nodeconnectorIdNew;
631         private final NodeConnectorId nodeconnectorIdOld;
632         private final FlowCapableNodeConnector fcNodeConnectorOld;
633         private final String ofTepName;
634
635         OfPortStateRemoveWorker(NodeConnectorId nodeconnectorIdNew, NodeConnectorId nodeconnectorIdOld,
636                                 FlowCapableNodeConnector fcNodeConnectorOld, String ofTepName) {
637             this.nodeconnectorIdNew = nodeconnectorIdNew;
638             this.nodeconnectorIdOld = nodeconnectorIdOld;
639             this.fcNodeConnectorOld = fcNodeConnectorOld;
640             this.ofTepName = ofTepName;
641         }
642
643         @Override
644         public List<? extends ListenableFuture<?>> call() throws Exception {
645             // If another renderer(for eg : OVS) needs to be supported, check can be performed here
646             // to call the respective helpers.
647             return removeOfTepStateConfiguration(nodeconnectorIdNew, nodeconnectorIdOld, ofTepName, fcNodeConnectorOld);
648         }
649
650         @Override
651         public String toString() {
652             return "OfTepStateRemoveWorker{nodeConnectorInfo=" + nodeconnectorIdNew + ", nodeConnectorIdOld="
653                     + nodeconnectorIdOld + ", fcNodeConnectorOld=" + fcNodeConnectorOld + ", ofTepName='"
654                     + ofTepName + '\'' + '}';
655         }
656     }
657 }