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