31b14e446bca8a635d4354cb7618a7ea8c62cba7
[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 || !directTunnelUtils.isEntityOwner()) {
191             return;
192         }
193         LOG.debug("Received NodeConnector Update Event: {}, {}, {}", key, fcNodeConnectorOld, fcNodeConnectorNew);
194
195         TunnelInterfaceStateUpdateWorker portStateUpdateWorker =
196                 new TunnelInterfaceStateUpdateWorker(key, fcNodeConnectorOld, fcNodeConnectorNew, portName);
197         EVENT_LOGGER.debug("ITM-TunnelInventoryState Entity Owner, UPDATE {} {} Reason {}",
198                 fcNodeConnectorNew.getName(), portName, fcNodeConnectorNew.getReason());
199         coordinator.enqueueJob(portName, portStateUpdateWorker, ITMConstants.JOB_MAX_RETRIES);
200     }
201
202     @Override
203     public void add(@NonNull InstanceIdentifier<FlowCapableNodeConnector> key,
204                     @NonNull FlowCapableNodeConnector fcNodeConnectorNew) {
205         LOG.info("Received NodeConnector Add Event: {}, {}", key, fcNodeConnectorNew);
206         EVENT_LOGGER.debug("ITM-TunnelInventoryState,ADD DTCN received for {}", fcNodeConnectorNew.getName());
207         String portName = fcNodeConnectorNew.getName();
208
209         // Return if its not tunnel port and if its not Internal
210         if (!DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(portName) && !portName.startsWith("of")) {
211             LOG.debug("Node Connector Add {} Interface is not a tunnel I/f, so no-op", portName);
212             return;
213         }
214
215         if (!directTunnelUtils.isEntityOwner()) {
216             LOG.debug("Not an entity owner.");
217             return;
218         }
219
220         //Optional<OfDpnTep> dpnTepOptional = Optional.ofNullable(null);
221         NodeConnectorInfo nodeConnectorInfo =
222                 new NodeConnectorInfoBuilder().setNodeConnectorId(key).setNodeConnector(fcNodeConnectorNew).build();
223
224         if (portName.startsWith("of") && interfaceManager.isItmOfTunnelsEnabled()) {
225             NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
226                     .getId();
227             Uint64 srcDpn = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId);
228
229             OfDpnTep dpntep = null;
230             try (Acquired lock = directTunnelUtils.lockTunnel(portName)) {
231                 try {
232                     Optional<OfDpnTep> dpnTepOptional = ofDpnTepConfigCache.get(srcDpn.toJava());
233                     if (!dpnTepOptional.isPresent()) {
234                         // Park the notification
235                         LOG.debug("Unable to process the NodeConnector ADD event for {} as Config not available."
236                                 + "Hence parking it", portName);
237                         unprocessedOFNCCache.add(portName, nodeConnectorInfo);
238                         return;
239                     } else {
240                         dpntep = dpnTepOptional.get();
241                     }
242                 } catch (ReadFailedException e) {
243                     LOG.error("unable to get ofDpnTepConfigCache");
244                 }
245             }
246
247             if (dpntep != null) {
248                 OfPortStateAddWorkerForNodeConnector ifOfStateAddWorker =
249                         new OfPortStateAddWorkerForNodeConnector(new OfPortStateAddWorker(directTunnelUtils,
250                                 dpntep, txRunner), nodeConnectorInfo);
251                 EVENT_LOGGER.debug("ITM-Of-tepInventoryState Entity Owner,ADD {} {}",
252                         nodeConnectorId.getValue(), portName);
253                 coordinator.enqueueJob(portName, ifOfStateAddWorker, ITMConstants.JOB_MAX_RETRIES);
254             }
255         } else {
256             addTunnelState(nodeConnectorInfo, portName);
257         }
258     }
259
260     private void addTunnelState(NodeConnectorInfo nodeConnectorInfo, String portName) {
261
262         TunnelStateInfo tunnelStateInfo = null;
263         TunnelEndPointInfo tunnelEndPtInfo = null;
264         try (Acquired lock = directTunnelUtils.lockTunnel(portName)) {
265             if (!dpnTepStateCache.isConfigAvailable(portName)) {
266                 // Park the notification
267                 LOG.debug("Unable to process the NodeConnector ADD event for {} as Config not available."
268                     + "Hence parking it", portName);
269                 unprocessedNCCache.add(portName,
270                     new TunnelStateInfoBuilder().setNodeConnectorInfo(nodeConnectorInfo).build());
271                 return;
272             } else if (!dpnTepStateCache.isInternal(portName)) {
273                 LOG.debug("{} Interface is not a internal tunnel I/f, so no-op", portName);
274                 return;
275             }
276         }
277
278         // Check if tunnels State has an entry for this interface.
279         // If so, then this Inventory Add is due to compute re-connection. Then, ONLY update the state
280         // to UP as previously the compute would have disconnected and so the state will be UNKNOWN.
281         try {
282             long portNo = tunnelStateCache.getNodeConnectorIdFromInterface(portName);
283             if (portNo != ITMConstants.INVALID_PORT_NO) {
284                 coordinator.enqueueJob(portName,
285                         new TunnelInterfaceNodeReconnectWorker(portName), ITMConstants.JOB_MAX_RETRIES);
286                 return;
287             }
288         } catch (ReadFailedException e) {
289             LOG.error("Exception occurred in reconnect for portName {}, reason: {}.",
290                      portName, e.getMessage());
291         }
292
293         if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(portName) && dpnTepStateCache.isInternal(portName)) {
294             tunnelEndPtInfo = dpnTepStateCache.getTunnelEndPointInfoFromCache(portName);
295             TunnelStateInfoBuilder builder = new TunnelStateInfoBuilder().setNodeConnectorInfo(nodeConnectorInfo);
296             dpntePsInfoCache.getDPNTepFromDPNId(Uint64.valueOf(tunnelEndPtInfo.getSrcEndPointInfo()))
297                 .ifPresent(builder::setSrcDpnTepsInfo);
298             dpntePsInfoCache.getDPNTepFromDPNId(Uint64.valueOf(tunnelEndPtInfo.getDstEndPointInfo()))
299                 .ifPresent(builder::setDstDpnTepsInfo);
300             tunnelStateInfo = builder.setTunnelEndPointInfo(tunnelEndPtInfo)
301                 .setDpnTepInterfaceInfo(dpnTepStateCache.getTunnelFromCache(portName)).build();
302
303             if (tunnelStateInfo.getSrcDpnTepsInfo() == null) {
304                 try (Acquired lock = directTunnelUtils.lockTunnel(tunnelEndPtInfo.getSrcEndPointInfo())) {
305                     LOG.debug("Source DPNTepsInfo is null for tunnel {}. Hence Parking with key {}",
306                         portName, tunnelEndPtInfo.getSrcEndPointInfo());
307                     unprocessedNodeConnectorEndPointCache.add(tunnelEndPtInfo.getSrcEndPointInfo(), tunnelStateInfo);
308                 }
309             }
310             if (tunnelStateInfo.getDstDpnTepsInfo() == null) {
311                 try (Acquired lock = directTunnelUtils.lockTunnel(tunnelEndPtInfo.getDstEndPointInfo())) {
312                     LOG.debug("Destination DPNTepsInfo is null for tunnel {}. Hence Parking with key {}",
313                         portName, tunnelEndPtInfo.getDstEndPointInfo());
314                     unprocessedNodeConnectorEndPointCache.add(tunnelEndPtInfo.getDstEndPointInfo(), tunnelStateInfo);
315                 }
316             }
317         }
318
319         if (tunnelEndPtInfo != null && tunnelStateInfo.getSrcDpnTepsInfo() != null
320             && tunnelStateInfo.getDstDpnTepsInfo() != null) {
321             EVENT_LOGGER.debug("ITM-TunnelInventoryState Entity Owner,ADD {}", portName);
322             coordinator.enqueueJob(portName,
323                 new TunnelStateAddWorkerForNodeConnector(new TunnelStateAddWorker(directTunnelUtils, txRunner),
324                     tunnelStateInfo), ITMConstants.JOB_MAX_RETRIES);
325         }
326     }
327
328     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
329             justification = "https://github.com/spotbugs/spotbugs/issues/811")
330     private List<? extends ListenableFuture<?>> updateState(String interfaceName,
331         FlowCapableNodeConnector flowCapableNodeConnectorNew,
332         FlowCapableNodeConnector flowCapableNodeConnectorOld) {
333         LOG.debug("Updating interface state for port: {}", interfaceName);
334
335         // Hardware updates can be ignored
336         Interface.OperStatus operStatusNew = getOpState(flowCapableNodeConnectorNew);
337         MacAddress macAddressNew = flowCapableNodeConnectorNew.getHardwareAddress();
338
339         Interface.OperStatus operStatusOld = getOpState(flowCapableNodeConnectorOld);
340         MacAddress macAddressOld = flowCapableNodeConnectorOld.getHardwareAddress();
341
342         boolean opstateModified = false;
343         boolean hardwareAddressModified = false;
344         if (!operStatusNew.equals(operStatusOld)) {
345             opstateModified = true;
346         }
347         if (!Objects.equals(macAddressNew, macAddressOld)) {
348             hardwareAddressModified = true;
349         }
350
351         if (!opstateModified && !hardwareAddressModified) {
352             LOG.debug("If State entry for port: {} Not Modified.", interfaceName);
353             return Collections.emptyList();
354         }
355
356         DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
357
358         // For monitoring enabled tunnels, skip opstate updation
359         if (!modifyTunnelOpState(dpnTepInfo, opstateModified)) {
360             LOG.debug("skipping Tunnel-state update for monitoring enabled tunnel interface {}", interfaceName);
361             opstateModified = false;
362         }
363
364         if (!opstateModified && !hardwareAddressModified) {
365             LOG.debug("If State entry for port: {} Not Modified.", interfaceName);
366             return Collections.emptyList();
367         }
368         if (opstateModified) {
369             return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
370                 // modify the attributes in interface operational DS
371                 handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, flowCapableNodeConnectorNew.getName(),
372                         operStatusNew);
373                 EVENT_LOGGER.debug("ITM-TunnelInventoryState, UPDATE {} CHGED {} completed", interfaceName,
374                         operStatusNew.getName());
375             }));
376         } else {
377             return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
378                 // modify the attributes in interface operational DS
379                 handleInterfaceStateUpdates(tx, dpnTepInfo, false, interfaceName,
380                         flowCapableNodeConnectorNew.getName(), operStatusNew);
381                 EVENT_LOGGER.debug("ITM-TunnelInventoryState, UPDATE {} completed", interfaceName);
382             }));
383         }
384     }
385
386     private void updateInterfaceStateOnNodeRemove(TypedWriteTransaction<Operational> tx, String interfaceName,
387         FlowCapableNodeConnector flowCapableNodeConnector) {
388         LOG.debug("Updating interface oper-status to UNKNOWN for : {}", interfaceName);
389         DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
390
391         handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, flowCapableNodeConnector.getName(),
392                 Interface.OperStatus.Unknown);
393     }
394
395     private void updateOfTepStateOnNodeRemove(Uint64 srcDpn, String ofTepName,
396                                               FlowCapableNodeConnector flowCapableNodeConnector,
397                                               TypedReadWriteTransaction<Operational> tx) throws ReadFailedException {
398         LOG.debug("Updating oftep oper-status to UNKNOWN for : {}", ofTepName);
399         Optional<OfDpnTep> dpnTepInfo = ofDpnTepConfigCache.get(srcDpn.toJava());
400         if (dpnTepInfo == null || !ofTepName.equals(flowCapableNodeConnector.getName())) {
401             return;
402         }
403         handleOfTepStateUpdates(dpnTepInfo, tx, true, ofTepName,
404                 Interface.OperStatus.Unknown);
405     }
406
407     private void handleOfTepStateUpdates(Optional<OfDpnTep> dpnTepInfo, TypedReadWriteTransaction<Operational> tx,
408                                          boolean opStateModified, String ofTepName, Interface.OperStatus opState) {
409         LOG.debug("updating oftep state entry for {}", ofTepName);
410         InstanceIdentifier<OfTep> ofTepStateId = ItmUtils.buildStateOfTepListId(new OfTepKey(ofTepName));
411         OfTepBuilder ofTepBuilder = new OfTepBuilder();
412         ofTepBuilder.withKey(new OfTepKey(ofTepName));
413         if (opStateModified) {
414             LOG.debug("updating oftep oper status as {} for {}", opState.getName(), ofTepName);
415             ofTepBuilder.setOfTepState(DirectTunnelUtils.convertInterfaceToTunnelOperState(opState));
416             LOG.trace("updated to {} for {}",opState.getName(), ofTepName);
417         }
418         tx.merge(ofTepStateId, ofTepBuilder.build());
419     }
420
421     private Interface.OperStatus getOpState(FlowCapableNodeConnector flowCapableNodeConnector) {
422         return flowCapableNodeConnector.getState().isLive()
423                 && !flowCapableNodeConnector.getConfiguration().isPORTDOWN()
424                 ? Interface.OperStatus.Up : Interface.OperStatus.Down;
425     }
426
427     private void handleInterfaceStateUpdates(TypedWriteTransaction<Operational> tx,
428         DpnTepInterfaceInfo dpnTepInfo,
429         boolean opStateModified, String interfaceName, String portName,
430         Interface.OperStatus opState) {
431         if (dpnTepInfo == null && !portName.startsWith("of") && !interfaceName.equals(portName)) {
432             return;
433         }
434         LOG.debug("updating interface state entry for {}", interfaceName);
435         InstanceIdentifier<StateTunnelList> tnlStateId = ItmUtils.buildStateTunnelListId(
436                 new StateTunnelListKey(interfaceName));
437         StateTunnelListBuilder stateTnlBuilder = new StateTunnelListBuilder();
438         stateTnlBuilder.withKey(new StateTunnelListKey(interfaceName));
439         if (modifyOpState(dpnTepInfo, opStateModified)) {
440             LOG.debug("updating interface oper status as {} for {}", opState.name(), interfaceName);
441             boolean tunnelState = opState.equals(Interface.OperStatus.Up);
442             stateTnlBuilder.setTunnelState(tunnelState);
443             stateTnlBuilder.setOperState(DirectTunnelUtils.convertInterfaceToTunnelOperState(opState));
444         }
445         tx.merge(tnlStateId, stateTnlBuilder.build());
446     }
447
448     private boolean modifyOpState(DpnTepInterfaceInfo dpnTepInterfaceInfo, boolean opStateModified) {
449         return opStateModified && dpnTepInterfaceInfo != null;
450     }
451
452     private boolean modifyTunnelOpState(DpnTepInterfaceInfo dpnTepInterfaceInfo, boolean opStateModified) {
453         return !dpnTepInterfaceInfo.isMonitoringEnabled() && modifyOpState(dpnTepInterfaceInfo, opStateModified);
454     }
455
456     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
457             justification = "https://github.com/spotbugs/spotbugs/issues/811")
458     private List<? extends ListenableFuture<?>> removeInterfaceStateConfiguration(NodeConnectorId nodeConnectorId,
459                                                                                   String interfaceName,
460                                                                                   FlowCapableNodeConnector
461                                                                                       flowCapableNodeConnector) {
462
463
464         List<ListenableFuture<?>> futures = new ArrayList<>();
465         Uint64 dpId = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId);
466         // In a genuine port delete scenario, the reason will be there in the incoming event, for all remaining
467         // cases treat the event as DPN disconnect, if old and new ports are same. Else, this is a VM migration
468         // scenario, and should be treated as port removal.
469         if (flowCapableNodeConnector.getReason() != PortReason.Delete) {
470             //Remove event is because of connection lost between controller and switch, or switch shutdown.
471             // Hence, dont remove the interface but set the status as "unknown"
472
473             futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
474                 tx -> updateInterfaceStateOnNodeRemove(tx, interfaceName, flowCapableNodeConnector)));
475
476         } else {
477             LOG.debug("removing interface state for interface: {}", interfaceName);
478             directTunnelUtils.deleteTunnelStateEntry(interfaceName);
479             DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
480             if (dpnTepInfo != null) {
481                 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
482                     // Do if-index and ingress flow clean-up only for tunnel-interfaces
483                     directTunnelUtils.removeLportTagInterfaceMap(interfaceName);
484                     directTunnelUtils.removeTunnelIngressFlow(tx, dpId, interfaceName);
485                     directTunnelUtils.removeTunnelEgressFlow(tx, dpId, interfaceName);
486                 }));
487             } else {
488                 LOG.error("DPNTEPInfo is null for Tunnel Interface {}", interfaceName);
489             }
490             EVENT_LOGGER.debug("ITM-TunnelInventoryState,REMOVE Table 0 flow for {} completed", interfaceName);
491         }
492         return futures;
493     }
494
495     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
496             justification = "https://github.com/spotbugs/spotbugs/issues/811")
497     private List<? extends ListenableFuture<?>> removeOfTepStateConfiguration(NodeConnectorId nodeConnectorIdNew,
498                                                                        NodeConnectorId nodeConnectorIdOld,
499                                                                        String ofTepName,
500                                                                        FlowCapableNodeConnector
501                                                                                fcNodeConnectorOld) {
502         List<ListenableFuture<?>> futures = new ArrayList<>();
503
504         NodeConnectorId nodeConnectorId = (nodeConnectorIdOld != null && !nodeConnectorIdNew.equals(nodeConnectorIdOld))
505                 ? nodeConnectorIdOld : nodeConnectorIdNew;
506
507         Uint64 dpId = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId);
508
509             // In a genuine port delete scenario, the reason will be there in the incoming event, for all remaining
510             // cases treat the event as DPN disconnect, if old and new ports are same. Else, this is a VM migration
511             // scenario, and should be treated as port removal.
512         if (fcNodeConnectorOld.getReason() != PortReason.Delete) {
513             //Remove event is because of connection lost between controller and switch, or switch shutdown.
514             // Hence, dont remove the interface but set the status as "unknown"
515             futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
516                 updateOfTepStateOnNodeRemove(dpId, ofTepName, fcNodeConnectorOld, tx);
517             }));
518         } else {
519             LOG.debug("removing oftep state for oftep: {}", ofTepName);
520             futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
521                 directTunnelUtils.deleteOfTepStateEntry(ofTepName);
522                 directTunnelUtils.removeLportTagInterfaceMap(ofTepName);
523                 directTunnelUtils.removeTunnelIngressFlow(tx, dpId, ofTepName);
524             }));
525             EVENT_LOGGER.debug("ITM-OfTepInventoryState,REMOVE Table 0 flow for {} completed", ofTepName);
526         }
527
528         return futures;
529     }
530
531     private class TunnelInterfaceStateUpdateWorker implements Callable<List<? extends ListenableFuture<?>>> {
532         private final InstanceIdentifier<FlowCapableNodeConnector> key;
533         private final FlowCapableNodeConnector fcNodeConnectorOld;
534         private final FlowCapableNodeConnector fcNodeConnectorNew;
535         private final String interfaceName;
536
537         TunnelInterfaceStateUpdateWorker(InstanceIdentifier<FlowCapableNodeConnector> key,
538                                          FlowCapableNodeConnector fcNodeConnectorOld,
539                                          FlowCapableNodeConnector fcNodeConnectorNew, String portName) {
540             this.key = key;
541             this.fcNodeConnectorOld = fcNodeConnectorOld;
542             this.fcNodeConnectorNew = fcNodeConnectorNew;
543             this.interfaceName = portName;
544         }
545
546         @Override
547         public List<? extends ListenableFuture<?>> call() {
548             // If another renderer(for eg : OVS) needs to be supported, check can be performed here
549             // to call the respective helpers.
550             return updateState(interfaceName, fcNodeConnectorNew, fcNodeConnectorOld);
551         }
552
553         @Override
554         public String toString() {
555             return "TunnelInterfaceStateUpdateWorker{key=" + key + ", fcNodeConnectorOld=" + fcNodeConnectorOld
556                     + ", fcNodeConnectorNew=" + fcNodeConnectorNew + ", interfaceName='" + interfaceName + '\'' + '}';
557         }
558     }
559
560     private class TunnelInterfaceStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
561         private final NodeConnectorId nodeConnectorId;
562         private final FlowCapableNodeConnector flowCapableNodeConnector;
563         private final String interfaceName;
564
565         TunnelInterfaceStateRemoveWorker(NodeConnectorId nodeConnectorId,
566                                          FlowCapableNodeConnector flowCapableNodeConnector,
567                                          String interfaceName) {
568             this.nodeConnectorId = nodeConnectorId;
569             this.flowCapableNodeConnector = flowCapableNodeConnector;
570             this.interfaceName = interfaceName;
571         }
572
573         @Override
574         public List<? extends ListenableFuture<?>> call() {
575             // If another renderer(for eg : OVS) needs to be supported, check can be performed here
576             // to call the respective helpers.
577             return removeInterfaceStateConfiguration(nodeConnectorId, interfaceName, flowCapableNodeConnector);
578         }
579
580         @Override
581         public String toString() {
582             return "TunnelInterfaceStateRemoveWorker{nodeConnectorId=" + nodeConnectorId + ", fcNodeConnector"
583                     + flowCapableNodeConnector + ", interfaceName='" + interfaceName + '\'' + '}';
584         }
585     }
586
587     private class TunnelInterfaceNodeReconnectWorker implements Callable<List<? extends ListenableFuture<?>>> {
588         private final String tunnelName;
589
590         TunnelInterfaceNodeReconnectWorker(String tunnelName) {
591             this.tunnelName = tunnelName;
592         }
593
594         @Override
595         public List<? extends ListenableFuture<?>> call() throws Exception {
596             // If another renderer(for eg : OVS) needs to be supported, check can be performed here
597             // to call the respective helpers.
598             EVENT_LOGGER.debug("ITM-TunnelInventoryState, Compute Re-connected, ADD received for {} ", tunnelName);
599
600             return handleInterfaceStateOnReconnect(tunnelName);
601         }
602
603         @Override
604         public String toString() {
605             return "TunnelInterfaceNodeReconnectWorker{tunnelName=" + tunnelName + '\'' + '}';
606         }
607     }
608
609     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
610             justification = "https://github.com/spotbugs/spotbugs/issues/811")
611     private List<? extends ListenableFuture<?>> handleInterfaceStateOnReconnect(String interfaceName) {
612         List<ListenableFuture<?>> futures = new ArrayList<>();
613
614         futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
615             DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
616
617             handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, interfaceName,
618                     Interface.OperStatus.Up);
619         }));
620         return futures;
621     }
622
623     private class OfPortStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
624
625         private final NodeConnectorId nodeconnectorIdNew;
626         private final NodeConnectorId nodeconnectorIdOld;
627         private final FlowCapableNodeConnector fcNodeConnectorOld;
628         private final String ofTepName;
629
630         OfPortStateRemoveWorker(NodeConnectorId nodeconnectorIdNew, NodeConnectorId nodeconnectorIdOld,
631                                 FlowCapableNodeConnector fcNodeConnectorOld, String ofTepName) {
632             this.nodeconnectorIdNew = nodeconnectorIdNew;
633             this.nodeconnectorIdOld = nodeconnectorIdOld;
634             this.fcNodeConnectorOld = fcNodeConnectorOld;
635             this.ofTepName = ofTepName;
636         }
637
638         @Override
639         public List<? extends ListenableFuture<?>> call() throws Exception {
640             // If another renderer(for eg : OVS) needs to be supported, check can be performed here
641             // to call the respective helpers.
642             return removeOfTepStateConfiguration(nodeconnectorIdNew, nodeconnectorIdOld, ofTepName, fcNodeConnectorOld);
643         }
644
645         @Override
646         public String toString() {
647             return "OfTepStateRemoveWorker{nodeConnectorInfo=" + nodeconnectorIdNew + ", nodeConnectorIdOld="
648                     + nodeconnectorIdOld + ", fcNodeConnectorOld=" + fcNodeConnectorOld + ", ofTepName='"
649                     + ofTepName + '\'' + '}';
650         }
651     }
652 }