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(Uint64.valueOf(tunnelEndPtInfo.getSrcEndPointInfo()))
300 .ifPresent(builder::setSrcDpnTepsInfo);
301 dpntePsInfoCache.getDPNTepFromDPNId(Uint64.valueOf(tunnelEndPtInfo.getDstEndPointInfo()))
302 .ifPresent(builder::setDstDpnTepsInfo);
303 tunnelStateInfo = builder.setTunnelEndPointInfo(tunnelEndPtInfo)
304 .setDpnTepInterfaceInfo(dpnTepStateCache.getTunnelFromCache(portName)).build();
306 if (tunnelStateInfo.getSrcDpnTepsInfo() == null) {
307 try (Acquired lock = directTunnelUtils.lockTunnel(tunnelEndPtInfo.getSrcEndPointInfo())) {
308 LOG.debug("Source DPNTepsInfo is null for tunnel {}. Hence Parking with key {}",
309 portName, tunnelEndPtInfo.getSrcEndPointInfo());
310 unprocessedNodeConnectorEndPointCache.add(tunnelEndPtInfo.getSrcEndPointInfo(), tunnelStateInfo);
313 if (tunnelStateInfo.getDstDpnTepsInfo() == null) {
314 try (Acquired lock = directTunnelUtils.lockTunnel(tunnelEndPtInfo.getDstEndPointInfo())) {
315 LOG.debug("Destination DPNTepsInfo is null for tunnel {}. Hence Parking with key {}",
316 portName, tunnelEndPtInfo.getDstEndPointInfo());
317 unprocessedNodeConnectorEndPointCache.add(tunnelEndPtInfo.getDstEndPointInfo(), tunnelStateInfo);
322 if (tunnelEndPtInfo != null && tunnelStateInfo.getSrcDpnTepsInfo() != null
323 && tunnelStateInfo.getDstDpnTepsInfo() != null) {
324 EVENT_LOGGER.debug("ITM-TunnelInventoryState Entity Owner,ADD {}", portName);
325 coordinator.enqueueJob(portName,
326 new TunnelStateAddWorkerForNodeConnector(new TunnelStateAddWorker(directTunnelUtils, txRunner),
327 tunnelStateInfo), ITMConstants.JOB_MAX_RETRIES);
331 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
332 justification = "https://github.com/spotbugs/spotbugs/issues/811")
333 private List<? extends ListenableFuture<?>> updateState(String interfaceName,
334 FlowCapableNodeConnector flowCapableNodeConnectorNew,
335 FlowCapableNodeConnector flowCapableNodeConnectorOld) {
336 LOG.debug("Updating interface state for port: {}", interfaceName);
338 // Hardware updates can be ignored
339 Interface.OperStatus operStatusNew = getOpState(flowCapableNodeConnectorNew);
340 MacAddress macAddressNew = flowCapableNodeConnectorNew.getHardwareAddress();
342 Interface.OperStatus operStatusOld = getOpState(flowCapableNodeConnectorOld);
343 MacAddress macAddressOld = flowCapableNodeConnectorOld.getHardwareAddress();
345 boolean opstateModified = false;
346 boolean hardwareAddressModified = false;
347 if (!operStatusNew.equals(operStatusOld)) {
348 opstateModified = true;
350 if (!Objects.equals(macAddressNew, macAddressOld)) {
351 hardwareAddressModified = true;
354 if (!opstateModified && !hardwareAddressModified) {
355 LOG.debug("If State entry for port: {} Not Modified.", interfaceName);
356 return Collections.emptyList();
359 DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
361 // For monitoring enabled tunnels, skip opstate updation
362 if (!modifyTunnelOpState(dpnTepInfo, opstateModified)) {
363 LOG.debug("skipping Tunnel-state update for monitoring enabled tunnel interface {}", interfaceName);
364 opstateModified = false;
367 if (!opstateModified && !hardwareAddressModified) {
368 LOG.debug("If State entry for port: {} Not Modified.", interfaceName);
369 return Collections.emptyList();
371 if (opstateModified) {
372 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
373 // modify the attributes in interface operational DS
374 handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, flowCapableNodeConnectorNew.getName(),
376 EVENT_LOGGER.debug("ITM-TunnelInventoryState, UPDATE {} CHGED {} completed", interfaceName,
377 operStatusNew.getName());
380 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
381 // modify the attributes in interface operational DS
382 handleInterfaceStateUpdates(tx, dpnTepInfo, false, interfaceName,
383 flowCapableNodeConnectorNew.getName(), operStatusNew);
384 EVENT_LOGGER.debug("ITM-TunnelInventoryState, UPDATE {} completed", interfaceName);
389 private void updateInterfaceStateOnNodeRemove(TypedWriteTransaction<Operational> tx, String interfaceName,
390 FlowCapableNodeConnector flowCapableNodeConnector) {
391 LOG.debug("Updating interface oper-status to UNKNOWN for : {}", interfaceName);
392 DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
394 handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, flowCapableNodeConnector.getName(),
395 Interface.OperStatus.Unknown);
398 private void updateOfTepStateOnNodeRemove(Uint64 srcDpn, String ofTepName,
399 FlowCapableNodeConnector flowCapableNodeConnector,
400 TypedReadWriteTransaction<Operational> tx) throws ReadFailedException {
401 LOG.debug("Updating oftep oper-status to UNKNOWN for : {}", ofTepName);
402 Optional<OfDpnTep> dpnTepInfo = ofDpnTepConfigCache.get(srcDpn.toJava());
403 if (dpnTepInfo == null || !ofTepName.equals(flowCapableNodeConnector.getName())) {
406 handleOfTepStateUpdates(dpnTepInfo, tx, true, ofTepName,
407 Interface.OperStatus.Unknown);
410 private void handleOfTepStateUpdates(Optional<OfDpnTep> dpnTepInfo, TypedReadWriteTransaction<Operational> tx,
411 boolean opStateModified, String ofTepName, Interface.OperStatus opState) {
412 LOG.debug("updating oftep state entry for {}", ofTepName);
413 InstanceIdentifier<OfTep> ofTepStateId = ItmUtils.buildStateOfTepListId(new OfTepKey(ofTepName));
414 OfTepBuilder ofTepBuilder = new OfTepBuilder();
415 ofTepBuilder.withKey(new OfTepKey(ofTepName));
416 if (opStateModified) {
417 LOG.debug("updating oftep oper status as {} for {}", opState.getName(), ofTepName);
418 ofTepBuilder.setOfTepState(DirectTunnelUtils.convertInterfaceToTunnelOperState(opState));
419 LOG.trace("updated to {} for {}",opState.getName(), ofTepName);
421 tx.merge(ofTepStateId, ofTepBuilder.build());
424 private Interface.OperStatus getOpState(FlowCapableNodeConnector flowCapableNodeConnector) {
425 return flowCapableNodeConnector.getState().isLive()
426 && !flowCapableNodeConnector.getConfiguration().isPORTDOWN()
427 ? Interface.OperStatus.Up : Interface.OperStatus.Down;
430 private void handleInterfaceStateUpdates(TypedWriteTransaction<Operational> tx,
431 DpnTepInterfaceInfo dpnTepInfo,
432 boolean opStateModified, String interfaceName, String portName,
433 Interface.OperStatus opState) {
434 if (dpnTepInfo == null && !portName.startsWith("of") && !interfaceName.equals(portName)) {
437 LOG.debug("updating interface state entry for {}", interfaceName);
438 InstanceIdentifier<StateTunnelList> tnlStateId = ItmUtils.buildStateTunnelListId(
439 new StateTunnelListKey(interfaceName));
440 StateTunnelListBuilder stateTnlBuilder = new StateTunnelListBuilder();
441 stateTnlBuilder.withKey(new StateTunnelListKey(interfaceName));
442 if (modifyOpState(dpnTepInfo, opStateModified)) {
443 LOG.debug("updating interface oper status as {} for {}", opState.name(), interfaceName);
444 boolean tunnelState = opState.equals(Interface.OperStatus.Up);
445 stateTnlBuilder.setTunnelState(tunnelState);
446 stateTnlBuilder.setOperState(DirectTunnelUtils.convertInterfaceToTunnelOperState(opState));
448 tx.merge(tnlStateId, stateTnlBuilder.build());
451 private boolean modifyOpState(DpnTepInterfaceInfo dpnTepInterfaceInfo, boolean opStateModified) {
452 return opStateModified && dpnTepInterfaceInfo != null;
455 private boolean modifyTunnelOpState(DpnTepInterfaceInfo dpnTepInterfaceInfo, boolean opStateModified) {
456 return !dpnTepInterfaceInfo.isMonitoringEnabled() && modifyOpState(dpnTepInterfaceInfo, opStateModified);
459 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
460 justification = "https://github.com/spotbugs/spotbugs/issues/811")
461 private List<? extends ListenableFuture<?>> removeInterfaceStateConfiguration(NodeConnectorId nodeConnectorId,
462 String interfaceName,
463 FlowCapableNodeConnector
464 flowCapableNodeConnector) {
467 List<ListenableFuture<?>> futures = new ArrayList<>();
468 Uint64 dpId = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId);
469 // In a genuine port delete scenario, the reason will be there in the incoming event, for all remaining
470 // cases treat the event as DPN disconnect, if old and new ports are same. Else, this is a VM migration
471 // scenario, and should be treated as port removal.
472 if (flowCapableNodeConnector.getReason() != PortReason.Delete) {
473 //Remove event is because of connection lost between controller and switch, or switch shutdown.
474 // Hence, dont remove the interface but set the status as "unknown"
476 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
477 tx -> updateInterfaceStateOnNodeRemove(tx, interfaceName, flowCapableNodeConnector)));
480 LOG.debug("removing interface state for interface: {}", interfaceName);
481 directTunnelUtils.deleteTunnelStateEntry(interfaceName);
482 DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
483 if (dpnTepInfo != null) {
484 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
485 // Do if-index and ingress flow clean-up only for tunnel-interfaces
486 directTunnelUtils.removeLportTagInterfaceMap(interfaceName);
487 directTunnelUtils.removeTunnelIngressFlow(tx, dpId, interfaceName);
488 directTunnelUtils.removeTunnelEgressFlow(tx, dpId, interfaceName);
491 LOG.error("DPNTEPInfo is null for Tunnel Interface {}", interfaceName);
493 EVENT_LOGGER.debug("ITM-TunnelInventoryState,REMOVE Table 0 flow for {} completed", interfaceName);
498 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
499 justification = "https://github.com/spotbugs/spotbugs/issues/811")
500 private List<? extends ListenableFuture<?>> removeOfTepStateConfiguration(NodeConnectorId nodeConnectorIdNew,
501 NodeConnectorId nodeConnectorIdOld,
503 FlowCapableNodeConnector
504 fcNodeConnectorOld) {
505 List<ListenableFuture<?>> futures = new ArrayList<>();
507 NodeConnectorId nodeConnectorId = (nodeConnectorIdOld != null && !nodeConnectorIdNew.equals(nodeConnectorIdOld))
508 ? nodeConnectorIdOld : nodeConnectorIdNew;
510 Uint64 dpId = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId);
512 // In a genuine port delete scenario, the reason will be there in the incoming event, for all remaining
513 // cases treat the event as DPN disconnect, if old and new ports are same. Else, this is a VM migration
514 // scenario, and should be treated as port removal.
515 if (fcNodeConnectorOld.getReason() != PortReason.Delete) {
516 //Remove event is because of connection lost between controller and switch, or switch shutdown.
517 // Hence, dont remove the interface but set the status as "unknown"
518 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
519 updateOfTepStateOnNodeRemove(dpId, ofTepName, fcNodeConnectorOld, tx);
522 LOG.debug("removing oftep state for oftep: {}", ofTepName);
523 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
524 directTunnelUtils.deleteOfTepStateEntry(ofTepName);
525 directTunnelUtils.removeLportTagInterfaceMap(ofTepName);
526 directTunnelUtils.removeTunnelIngressFlow(tx, dpId, ofTepName);
528 EVENT_LOGGER.debug("ITM-OfTepInventoryState,REMOVE Table 0 flow for {} completed", ofTepName);
534 private class TunnelInterfaceStateUpdateWorker implements Callable<List<? extends ListenableFuture<?>>> {
535 private final InstanceIdentifier<FlowCapableNodeConnector> key;
536 private final FlowCapableNodeConnector fcNodeConnectorOld;
537 private final FlowCapableNodeConnector fcNodeConnectorNew;
538 private final String interfaceName;
540 TunnelInterfaceStateUpdateWorker(InstanceIdentifier<FlowCapableNodeConnector> key,
541 FlowCapableNodeConnector fcNodeConnectorOld,
542 FlowCapableNodeConnector fcNodeConnectorNew, String portName) {
544 this.fcNodeConnectorOld = fcNodeConnectorOld;
545 this.fcNodeConnectorNew = fcNodeConnectorNew;
546 this.interfaceName = portName;
550 public List<? extends ListenableFuture<?>> call() {
551 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
552 // to call the respective helpers.
553 return updateState(interfaceName, fcNodeConnectorNew, fcNodeConnectorOld);
557 public String toString() {
558 return "TunnelInterfaceStateUpdateWorker{key=" + key + ", fcNodeConnectorOld=" + fcNodeConnectorOld
559 + ", fcNodeConnectorNew=" + fcNodeConnectorNew + ", interfaceName='" + interfaceName + '\'' + '}';
563 private class TunnelInterfaceStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
564 private final NodeConnectorId nodeConnectorId;
565 private final FlowCapableNodeConnector flowCapableNodeConnector;
566 private final String interfaceName;
568 TunnelInterfaceStateRemoveWorker(NodeConnectorId nodeConnectorId,
569 FlowCapableNodeConnector flowCapableNodeConnector,
570 String interfaceName) {
571 this.nodeConnectorId = nodeConnectorId;
572 this.flowCapableNodeConnector = flowCapableNodeConnector;
573 this.interfaceName = interfaceName;
577 public List<? extends ListenableFuture<?>> call() {
578 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
579 // to call the respective helpers.
580 return removeInterfaceStateConfiguration(nodeConnectorId, interfaceName, flowCapableNodeConnector);
584 public String toString() {
585 return "TunnelInterfaceStateRemoveWorker{nodeConnectorId=" + nodeConnectorId + ", fcNodeConnector"
586 + flowCapableNodeConnector + ", interfaceName='" + interfaceName + '\'' + '}';
590 private class TunnelInterfaceNodeReconnectWorker implements Callable<List<? extends ListenableFuture<?>>> {
591 private final String tunnelName;
593 TunnelInterfaceNodeReconnectWorker(String tunnelName) {
594 this.tunnelName = tunnelName;
598 public List<? extends ListenableFuture<?>> call() throws Exception {
599 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
600 // to call the respective helpers.
601 EVENT_LOGGER.debug("ITM-TunnelInventoryState, Compute Re-connected, ADD received for {} ", tunnelName);
603 return handleInterfaceStateOnReconnect(tunnelName);
607 public String toString() {
608 return "TunnelInterfaceNodeReconnectWorker{tunnelName=" + tunnelName + '\'' + '}';
612 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
613 justification = "https://github.com/spotbugs/spotbugs/issues/811")
614 private List<? extends ListenableFuture<?>> handleInterfaceStateOnReconnect(String interfaceName) {
615 List<ListenableFuture<?>> futures = new ArrayList<>();
617 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
618 DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
620 handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, interfaceName,
621 Interface.OperStatus.Up);
626 private class OfPortStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
628 private final NodeConnectorId nodeconnectorIdNew;
629 private final NodeConnectorId nodeconnectorIdOld;
630 private final FlowCapableNodeConnector fcNodeConnectorOld;
631 private final String ofTepName;
633 OfPortStateRemoveWorker(NodeConnectorId nodeconnectorIdNew, NodeConnectorId nodeconnectorIdOld,
634 FlowCapableNodeConnector fcNodeConnectorOld, String ofTepName) {
635 this.nodeconnectorIdNew = nodeconnectorIdNew;
636 this.nodeconnectorIdOld = nodeconnectorIdOld;
637 this.fcNodeConnectorOld = fcNodeConnectorOld;
638 this.ofTepName = ofTepName;
642 public List<? extends ListenableFuture<?>> call() throws Exception {
643 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
644 // to call the respective helpers.
645 return removeOfTepStateConfiguration(nodeconnectorIdNew, nodeconnectorIdOld, ofTepName, fcNodeConnectorOld);
649 public String toString() {
650 return "OfTepStateRemoveWorker{nodeConnectorInfo=" + nodeconnectorIdNew + ", nodeConnectorIdOld="
651 + nodeconnectorIdOld + ", fcNodeConnectorOld=" + fcNodeConnectorOld + ", ofTepName='"
652 + ofTepName + '\'' + '}';