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