InfraUtil JobCordinator Changes.
[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.genius.infra.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.infra.Datastore.Operational;
24 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
25 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
26 import org.opendaylight.genius.infra.TypedWriteTransaction;
27 import org.opendaylight.genius.itm.cache.DPNTEPsInfoCache;
28 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
29 import org.opendaylight.genius.itm.cache.TunnelStateCache;
30 import org.opendaylight.genius.itm.cache.UnprocessedNodeConnectorCache;
31 import org.opendaylight.genius.itm.cache.UnprocessedNodeConnectorEndPointCache;
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.TunnelStateAddWorker;
36 import org.opendaylight.genius.itm.itmdirecttunnels.workers.TunnelStateAddWorkerForNodeConnector;
37 import org.opendaylight.genius.itm.utils.DpnTepInterfaceInfo;
38 import org.opendaylight.genius.itm.utils.NodeConnectorInfo;
39 import org.opendaylight.genius.itm.utils.NodeConnectorInfoBuilder;
40 import org.opendaylight.genius.itm.utils.TunnelEndPointInfo;
41 import org.opendaylight.genius.itm.utils.TunnelStateInfo;
42 import org.opendaylight.genius.itm.utils.TunnelStateInfoBuilder;
43 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
44 import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.Acquired;
45 import org.opendaylight.mdsal.binding.api.DataBroker;
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         if (fcNodeConnectorNew.getReason() == PortReason.Delete || !directTunnelUtils.isEntityOwner()) {
163             return;
164         }
165         LOG.debug("Received NodeConnector Update Event: {}, {}, {}", key, fcNodeConnectorOld, fcNodeConnectorNew);
166
167         TunnelInterfaceStateUpdateWorker portStateUpdateWorker =
168                 new TunnelInterfaceStateUpdateWorker(key, fcNodeConnectorOld, fcNodeConnectorNew, portName);
169         EVENT_LOGGER.debug("ITM-TunnelInventoryState Entity Owner, UPDATE {} {} Reason {}",
170                 fcNodeConnectorNew.getName(), portName, fcNodeConnectorNew.getReason());
171         coordinator.enqueueJob(portName, portStateUpdateWorker, ITMConstants.JOB_MAX_RETRIES);
172     }
173
174     @Override
175     public void add(@NonNull InstanceIdentifier<FlowCapableNodeConnector> key,
176                     @NonNull FlowCapableNodeConnector fcNodeConnectorNew) {
177         LOG.info("Received NodeConnector Add Event: {}, {}", key, fcNodeConnectorNew);
178         EVENT_LOGGER.debug("ITM-TunnelInventoryState,ADD DTCN received for {}", fcNodeConnectorNew.getName());
179         String portName = fcNodeConnectorNew.getName();
180         // Return if its not tunnel port and if its not Internal
181         if (!DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(portName) && !portName.startsWith("of")) {
182             LOG.debug("Node Connector Add {} Interface is not a tunnel I/f, so no-op", portName);
183             return;
184         }
185
186         NodeConnectorInfo nodeConnectorInfo =
187                 new NodeConnectorInfoBuilder().setNodeConnectorId(key).setNodeConnector(fcNodeConnectorNew).build();
188
189         if (portName.startsWith("of")) {
190             NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
191                     .getId();
192             String srcDpn = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId).toString();
193
194             if (meshedMap.isEmpty()) {
195                 meshedMap.put(srcDpn, nodeConnectorInfo);
196                 return;
197             } else {
198                 for (Map.Entry<String, NodeConnectorInfo> entry : meshedMap.entrySet()) {
199                     DpnTepInterfaceInfo infInfoForward = dpnTepStateCache.getDpnTepInterface(Uint64.valueOf(srcDpn),
200                         Uint64.valueOf(entry.getKey()));
201                     if (infInfoForward == null) {
202                         unprocessedNCCache.add(srcDpn + ":" + entry.getKey(),
203                                 new TunnelStateInfoBuilder().setNodeConnectorInfo(nodeConnectorInfo).build());
204                     } else {
205                         addTunnelState(nodeConnectorInfo, infInfoForward.getTunnelName());
206                     }
207
208                     DpnTepInterfaceInfo infInfoReverse = dpnTepStateCache.getDpnTepInterface(
209                         Uint64.valueOf(entry.getKey()), Uint64.valueOf(srcDpn));
210
211                     if (infInfoReverse == null) {
212                         unprocessedNCCache.add(entry.getKey() + ":" + srcDpn,
213                                 new TunnelStateInfoBuilder().setNodeConnectorInfo(entry.getValue()).build());
214                     } else {
215                         addTunnelState(entry.getValue(), infInfoReverse.getTunnelName());
216                     }
217                 }
218             }
219             meshedMap.put(srcDpn, nodeConnectorInfo);
220         } else {
221             addTunnelState(nodeConnectorInfo, portName);
222         }
223
224     }
225
226     private void addTunnelState(NodeConnectorInfo nodeConnectorInfo, String portName) {
227
228         TunnelStateInfo tunnelStateInfo = null;
229         TunnelEndPointInfo tunnelEndPtInfo = null;
230         try (Acquired lock = directTunnelUtils.lockTunnel(portName)) {
231             if (!dpnTepStateCache.isConfigAvailable(portName)) {
232                 // Park the notification
233                 LOG.debug("Unable to process the NodeConnector ADD event for {} as Config not available."
234                     + "Hence parking it", portName);
235                 unprocessedNCCache.add(portName,
236                     new TunnelStateInfoBuilder().setNodeConnectorInfo(nodeConnectorInfo).build());
237                 return;
238             } else if (!dpnTepStateCache.isInternal(portName)) {
239                 LOG.debug("{} Interface is not a internal tunnel I/f, so no-op", portName);
240                 return;
241             }
242         }
243
244         if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(portName) && dpnTepStateCache.isInternal(portName)) {
245             tunnelEndPtInfo = dpnTepStateCache.getTunnelEndPointInfoFromCache(portName);
246             TunnelStateInfoBuilder builder = new TunnelStateInfoBuilder().setNodeConnectorInfo(nodeConnectorInfo);
247             dpntePsInfoCache.getDPNTepFromDPNId(Uint64.valueOf(tunnelEndPtInfo.getSrcEndPointInfo()))
248                 .ifPresent(builder::setSrcDpnTepsInfo);
249             dpntePsInfoCache.getDPNTepFromDPNId(Uint64.valueOf(tunnelEndPtInfo.getDstEndPointInfo()))
250                 .ifPresent(builder::setDstDpnTepsInfo);
251             tunnelStateInfo = builder.setTunnelEndPointInfo(tunnelEndPtInfo)
252                 .setDpnTepInterfaceInfo(dpnTepStateCache.getTunnelFromCache(portName)).build();
253
254             if (tunnelStateInfo.getSrcDpnTepsInfo() == null) {
255                 try (Acquired lock = directTunnelUtils.lockTunnel(tunnelEndPtInfo.getSrcEndPointInfo())) {
256                     LOG.debug("Source DPNTepsInfo is null for tunnel {}. Hence Parking with key {}",
257                         portName, tunnelEndPtInfo.getSrcEndPointInfo());
258                     unprocessedNodeConnectorEndPointCache.add(tunnelEndPtInfo.getSrcEndPointInfo(), tunnelStateInfo);
259                 }
260             }
261             if (tunnelStateInfo.getDstDpnTepsInfo() == null) {
262                 try (Acquired lock = directTunnelUtils.lockTunnel(tunnelEndPtInfo.getDstEndPointInfo())) {
263                     LOG.debug("Destination DPNTepsInfo is null for tunnel {}. Hence Parking with key {}",
264                         portName, tunnelEndPtInfo.getDstEndPointInfo());
265                     unprocessedNodeConnectorEndPointCache.add(tunnelEndPtInfo.getDstEndPointInfo(), tunnelStateInfo);
266                 }
267             }
268         }
269
270         if (tunnelEndPtInfo != null && tunnelStateInfo.getSrcDpnTepsInfo() != null
271             && tunnelStateInfo.getDstDpnTepsInfo() != null && directTunnelUtils.isEntityOwner()) {
272             EVENT_LOGGER.debug("ITM-TunnelInventoryState Entity Owner,ADD {}", portName);
273             coordinator.enqueueJob(portName,
274                 new TunnelStateAddWorkerForNodeConnector(new TunnelStateAddWorker(directTunnelUtils, txRunner),
275                     tunnelStateInfo), ITMConstants.JOB_MAX_RETRIES);
276         }
277     }
278
279     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
280             justification = "https://github.com/spotbugs/spotbugs/issues/811")
281     private List<ListenableFuture<Void>> updateState(String interfaceName,
282         FlowCapableNodeConnector flowCapableNodeConnectorNew,
283         FlowCapableNodeConnector flowCapableNodeConnectorOld) {
284         LOG.debug("Updating interface state for port: {}", interfaceName);
285
286         // Hardware updates can be ignored
287         Interface.OperStatus operStatusNew = getOpState(flowCapableNodeConnectorNew);
288         MacAddress macAddressNew = flowCapableNodeConnectorNew.getHardwareAddress();
289
290         Interface.OperStatus operStatusOld = getOpState(flowCapableNodeConnectorOld);
291         MacAddress macAddressOld = flowCapableNodeConnectorOld.getHardwareAddress();
292
293         boolean opstateModified = false;
294         boolean hardwareAddressModified = false;
295         if (!operStatusNew.equals(operStatusOld)) {
296             opstateModified = true;
297         }
298         if (!Objects.equals(macAddressNew, macAddressOld)) {
299             hardwareAddressModified = true;
300         }
301
302         if (!opstateModified && !hardwareAddressModified) {
303             LOG.debug("If State entry for port: {} Not Modified.", interfaceName);
304             return Collections.emptyList();
305         }
306
307         DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
308
309         // For monitoring enabled tunnels, skip opstate updation
310         if (!modifyTunnelOpState(dpnTepInfo, opstateModified)) {
311             LOG.debug("skipping Tunnel-state update for monitoring enabled tunnel interface {}", interfaceName);
312             opstateModified = false;
313         }
314
315         if (!opstateModified && !hardwareAddressModified) {
316             LOG.debug("If State entry for port: {} Not Modified.", interfaceName);
317             return Collections.emptyList();
318         }
319         if (opstateModified) {
320             return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
321                 // modify the attributes in interface operational DS
322                 handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, flowCapableNodeConnectorNew.getName(),
323                         operStatusNew);
324                 EVENT_LOGGER.debug("ITM-TunnelInventoryState, UPDATE {} CHGED {} completed", interfaceName,
325                         operStatusNew.getName());
326             }));
327         } else {
328             return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
329                 // modify the attributes in interface operational DS
330                 handleInterfaceStateUpdates(tx, dpnTepInfo, false, interfaceName,
331                         flowCapableNodeConnectorNew.getName(), operStatusNew);
332                 EVENT_LOGGER.debug("ITM-TunnelInventoryState, UPDATE {} completed", interfaceName);
333             }));
334         }
335     }
336
337     private void updateInterfaceStateOnNodeRemove(TypedWriteTransaction<Operational> tx, String interfaceName,
338         FlowCapableNodeConnector flowCapableNodeConnector) {
339         LOG.debug("Updating interface oper-status to UNKNOWN for : {}", interfaceName);
340         DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
341
342         handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, flowCapableNodeConnector.getName(),
343                 Interface.OperStatus.Unknown);
344     }
345
346     private Interface.OperStatus getOpState(FlowCapableNodeConnector flowCapableNodeConnector) {
347         return flowCapableNodeConnector.getState().isLive()
348                 && !flowCapableNodeConnector.getConfiguration().isPORTDOWN()
349                 ? Interface.OperStatus.Up : Interface.OperStatus.Down;
350     }
351
352     private void handleInterfaceStateUpdates(TypedWriteTransaction<Operational> tx,
353         DpnTepInterfaceInfo dpnTepInfo,
354         boolean opStateModified, String interfaceName, String portName,
355         Interface.OperStatus opState) {
356         if (dpnTepInfo == null && !portName.startsWith("of") && !interfaceName.equals(portName)) {
357             return;
358         }
359         LOG.debug("updating interface state entry for {}", interfaceName);
360         InstanceIdentifier<StateTunnelList> tnlStateId = ItmUtils.buildStateTunnelListId(
361                 new StateTunnelListKey(interfaceName));
362         StateTunnelListBuilder stateTnlBuilder = new StateTunnelListBuilder();
363         stateTnlBuilder.withKey(new StateTunnelListKey(interfaceName));
364         if (modifyOpState(dpnTepInfo, opStateModified)) {
365             LOG.debug("updating interface oper status as {} for {}", opState.name(), interfaceName);
366             boolean tunnelState = opState.equals(Interface.OperStatus.Up);
367             stateTnlBuilder.setTunnelState(tunnelState);
368             stateTnlBuilder.setOperState(DirectTunnelUtils.convertInterfaceToTunnelOperState(opState));
369         }
370         tx.merge(tnlStateId, stateTnlBuilder.build());
371     }
372
373     private boolean modifyOpState(DpnTepInterfaceInfo dpnTepInterfaceInfo, boolean opStateModified) {
374         return opStateModified && dpnTepInterfaceInfo != null;
375     }
376
377     private boolean modifyTunnelOpState(DpnTepInterfaceInfo dpnTepInterfaceInfo, boolean opStateModified) {
378         return !dpnTepInterfaceInfo.isMonitoringEnabled() && modifyOpState(dpnTepInterfaceInfo, opStateModified);
379     }
380
381     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
382             justification = "https://github.com/spotbugs/spotbugs/issues/811")
383     private List<ListenableFuture<Void>> removeInterfaceStateConfiguration(NodeConnectorId nodeConnectorId,
384                                                                            String interfaceName,
385                                                                            FlowCapableNodeConnector
386                                                                                    flowCapableNodeConnector) {
387
388
389         List<ListenableFuture<Void>> futures = new ArrayList<>();
390         Uint64 dpId = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId);
391         // In a genuine port delete scenario, the reason will be there in the incoming event, for all remaining
392         // cases treat the event as DPN disconnect, if old and new ports are same. Else, this is a VM migration
393         // scenario, and should be treated as port removal.
394         if (flowCapableNodeConnector.getReason() != PortReason.Delete) {
395             //Remove event is because of connection lost between controller and switch, or switch shutdown.
396             // Hence, dont remove the interface but set the status as "unknown"
397
398             if (interfaceName.startsWith("of")) {
399                 LOG.debug("Received remove state for dpid {}", dpId.intValue());
400                 for (Map.Entry<String, NodeConnectorInfo> entry : meshedMap.entrySet()) {
401                     if (!dpId.toString().equals(entry.getKey())) {
402                         String fwdTunnel = dpnTepStateCache.getDpnTepInterface(dpId, Uint64.valueOf(entry.getKey()))
403                                 .getTunnelName();
404                         LOG.debug("Fwd Tunnel name for {} : {} is {}", dpId.intValue(), entry.getKey(), fwdTunnel);
405                         futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
406                             tx -> updateInterfaceStateOnNodeRemove(tx, fwdTunnel, flowCapableNodeConnector)));
407                         String bwdTunnel = dpnTepStateCache.getDpnTepInterface(Uint64.valueOf(entry.getKey()), dpId)
408                                 .getTunnelName();
409                         LOG.debug("Bwd Tunnel name for {} : {} is {}", entry.getKey(), dpId.intValue(), bwdTunnel);
410                         futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
411                             tx -> updateInterfaceStateOnNodeRemove(tx, bwdTunnel,
412                                     entry.getValue().getNodeConnector())));
413                     }
414                 }
415             } else {
416                 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
417                     tx -> updateInterfaceStateOnNodeRemove(tx, interfaceName, flowCapableNodeConnector)));
418             }
419         } else {
420             LOG.debug("removing interface state for interface: {}", interfaceName);
421             EVENT_LOGGER.debug("ITM-TunnelInventoryState,REMOVE Table 0 flow for {} completed", interfaceName);
422             // removing interfaces are already done in delete worker
423             meshedMap.remove(dpId.toString());
424         }
425         return futures;
426     }
427
428     private class TunnelInterfaceStateUpdateWorker implements Callable<List<? extends ListenableFuture<?>>> {
429         private final InstanceIdentifier<FlowCapableNodeConnector> key;
430         private final FlowCapableNodeConnector fcNodeConnectorOld;
431         private final FlowCapableNodeConnector fcNodeConnectorNew;
432         private final String interfaceName;
433
434         TunnelInterfaceStateUpdateWorker(InstanceIdentifier<FlowCapableNodeConnector> key,
435                                          FlowCapableNodeConnector fcNodeConnectorOld,
436                                          FlowCapableNodeConnector fcNodeConnectorNew, String portName) {
437             this.key = key;
438             this.fcNodeConnectorOld = fcNodeConnectorOld;
439             this.fcNodeConnectorNew = fcNodeConnectorNew;
440             this.interfaceName = portName;
441         }
442
443         @Override
444         public List<ListenableFuture<Void>> call() {
445             // If another renderer(for eg : OVS) needs to be supported, check can be performed here
446             // to call the respective helpers.
447             return updateState(interfaceName, fcNodeConnectorNew, fcNodeConnectorOld);
448         }
449
450         @Override
451         public String toString() {
452             return "TunnelInterfaceStateUpdateWorker{key=" + key + ", fcNodeConnectorOld=" + fcNodeConnectorOld
453                     + ", fcNodeConnectorNew=" + fcNodeConnectorNew + ", interfaceName='" + interfaceName + '\'' + '}';
454         }
455     }
456
457     private class TunnelInterfaceStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
458         private final NodeConnectorId nodeConnectorId;
459         private final FlowCapableNodeConnector flowCapableNodeConnector;
460         private final String interfaceName;
461
462         TunnelInterfaceStateRemoveWorker(NodeConnectorId nodeConnectorId,
463                                          FlowCapableNodeConnector flowCapableNodeConnector,
464                                          String interfaceName) {
465             this.nodeConnectorId = nodeConnectorId;
466             this.flowCapableNodeConnector = flowCapableNodeConnector;
467             this.interfaceName = interfaceName;
468         }
469
470         @Override
471         public List<ListenableFuture<Void>> call() {
472             // If another renderer(for eg : OVS) needs to be supported, check can be performed here
473             // to call the respective helpers.
474             return removeInterfaceStateConfiguration(nodeConnectorId, interfaceName, flowCapableNodeConnector);
475         }
476
477         @Override
478         public String toString() {
479             return "TunnelInterfaceStateRemoveWorker{nodeConnectorId=" + nodeConnectorId + ", fcNodeConnector"
480                     + flowCapableNodeConnector + ", interfaceName='" + interfaceName + '\'' + '}';
481         }
482     }
483 }