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