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 || !directTunnelUtils.isEntityOwner()) {
193 LOG.debug("Received NodeConnector Update Event: {}, {}, {}", key, fcNodeConnectorOld, fcNodeConnectorNew);
195 TunnelInterfaceStateUpdateWorker portStateUpdateWorker =
196 new TunnelInterfaceStateUpdateWorker(key, fcNodeConnectorOld, fcNodeConnectorNew, portName);
197 EVENT_LOGGER.debug("ITM-TunnelInventoryState Entity Owner, UPDATE {} {} Reason {}",
198 fcNodeConnectorNew.getName(), portName, fcNodeConnectorNew.getReason());
199 coordinator.enqueueJob(portName, portStateUpdateWorker, ITMConstants.JOB_MAX_RETRIES);
203 public void add(@NonNull InstanceIdentifier<FlowCapableNodeConnector> key,
204 @NonNull FlowCapableNodeConnector fcNodeConnectorNew) {
205 LOG.info("Received NodeConnector Add Event: {}, {}", key, fcNodeConnectorNew);
206 EVENT_LOGGER.debug("ITM-TunnelInventoryState,ADD DTCN received for {}", fcNodeConnectorNew.getName());
207 String portName = fcNodeConnectorNew.getName();
209 // Return if its not tunnel port and if its not Internal
210 if (!DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(portName) && !portName.startsWith("of")) {
211 LOG.debug("Node Connector Add {} Interface is not a tunnel I/f, so no-op", portName);
215 if (!directTunnelUtils.isEntityOwner()) {
216 LOG.debug("Not an entity owner.");
220 //Optional<OfDpnTep> dpnTepOptional = Optional.ofNullable(null);
221 NodeConnectorInfo nodeConnectorInfo =
222 new NodeConnectorInfoBuilder().setNodeConnectorId(key).setNodeConnector(fcNodeConnectorNew).build();
224 if (portName.startsWith("of") && interfaceManager.isItmOfTunnelsEnabled()) {
225 NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
227 Uint64 srcDpn = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId);
229 OfDpnTep dpntep = null;
230 try (Acquired lock = directTunnelUtils.lockTunnel(portName)) {
232 Optional<OfDpnTep> dpnTepOptional = ofDpnTepConfigCache.get(srcDpn.toJava());
233 if (!dpnTepOptional.isPresent()) {
234 // Park the notification
235 LOG.debug("Unable to process the NodeConnector ADD event for {} as Config not available."
236 + "Hence parking it", portName);
237 unprocessedOFNCCache.add(portName, nodeConnectorInfo);
240 dpntep = dpnTepOptional.get();
242 } catch (ReadFailedException e) {
243 LOG.error("unable to get ofDpnTepConfigCache");
247 if (dpntep != null) {
248 OfPortStateAddWorkerForNodeConnector ifOfStateAddWorker =
249 new OfPortStateAddWorkerForNodeConnector(new OfPortStateAddWorker(directTunnelUtils,
250 dpntep, txRunner), nodeConnectorInfo);
251 EVENT_LOGGER.debug("ITM-Of-tepInventoryState Entity Owner,ADD {} {}",
252 nodeConnectorId.getValue(), portName);
253 coordinator.enqueueJob(portName, ifOfStateAddWorker, ITMConstants.JOB_MAX_RETRIES);
256 addTunnelState(nodeConnectorInfo, portName);
260 private void addTunnelState(NodeConnectorInfo nodeConnectorInfo, String portName) {
262 TunnelStateInfo tunnelStateInfo = null;
263 TunnelEndPointInfo tunnelEndPtInfo = null;
264 try (Acquired lock = directTunnelUtils.lockTunnel(portName)) {
265 if (!dpnTepStateCache.isConfigAvailable(portName)) {
266 // Park the notification
267 LOG.debug("Unable to process the NodeConnector ADD event for {} as Config not available."
268 + "Hence parking it", portName);
269 unprocessedNCCache.add(portName,
270 new TunnelStateInfoBuilder().setNodeConnectorInfo(nodeConnectorInfo).build());
272 } else if (!dpnTepStateCache.isInternal(portName)) {
273 LOG.debug("{} Interface is not a internal tunnel I/f, so no-op", portName);
278 // Check if tunnels State has an entry for this interface.
279 // If so, then this Inventory Add is due to compute re-connection. Then, ONLY update the state
280 // to UP as previously the compute would have disconnected and so the state will be UNKNOWN.
282 long portNo = tunnelStateCache.getNodeConnectorIdFromInterface(portName);
283 if (portNo != ITMConstants.INVALID_PORT_NO) {
284 coordinator.enqueueJob(portName,
285 new TunnelInterfaceNodeReconnectWorker(portName), ITMConstants.JOB_MAX_RETRIES);
288 } catch (ReadFailedException e) {
289 LOG.error("Exception occurred in reconnect for portName {}, reason: {}.",
290 portName, e.getMessage());
293 if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(portName) && dpnTepStateCache.isInternal(portName)) {
294 tunnelEndPtInfo = dpnTepStateCache.getTunnelEndPointInfoFromCache(portName);
295 TunnelStateInfoBuilder builder = new TunnelStateInfoBuilder().setNodeConnectorInfo(nodeConnectorInfo);
296 dpntePsInfoCache.getDPNTepFromDPNId(Uint64.valueOf(tunnelEndPtInfo.getSrcEndPointInfo()))
297 .ifPresent(builder::setSrcDpnTepsInfo);
298 dpntePsInfoCache.getDPNTepFromDPNId(Uint64.valueOf(tunnelEndPtInfo.getDstEndPointInfo()))
299 .ifPresent(builder::setDstDpnTepsInfo);
300 tunnelStateInfo = builder.setTunnelEndPointInfo(tunnelEndPtInfo)
301 .setDpnTepInterfaceInfo(dpnTepStateCache.getTunnelFromCache(portName)).build();
303 if (tunnelStateInfo.getSrcDpnTepsInfo() == null) {
304 try (Acquired lock = directTunnelUtils.lockTunnel(tunnelEndPtInfo.getSrcEndPointInfo())) {
305 LOG.debug("Source DPNTepsInfo is null for tunnel {}. Hence Parking with key {}",
306 portName, tunnelEndPtInfo.getSrcEndPointInfo());
307 unprocessedNodeConnectorEndPointCache.add(tunnelEndPtInfo.getSrcEndPointInfo(), tunnelStateInfo);
310 if (tunnelStateInfo.getDstDpnTepsInfo() == null) {
311 try (Acquired lock = directTunnelUtils.lockTunnel(tunnelEndPtInfo.getDstEndPointInfo())) {
312 LOG.debug("Destination DPNTepsInfo is null for tunnel {}. Hence Parking with key {}",
313 portName, tunnelEndPtInfo.getDstEndPointInfo());
314 unprocessedNodeConnectorEndPointCache.add(tunnelEndPtInfo.getDstEndPointInfo(), tunnelStateInfo);
319 if (tunnelEndPtInfo != null && tunnelStateInfo.getSrcDpnTepsInfo() != null
320 && tunnelStateInfo.getDstDpnTepsInfo() != null) {
321 EVENT_LOGGER.debug("ITM-TunnelInventoryState Entity Owner,ADD {}", portName);
322 coordinator.enqueueJob(portName,
323 new TunnelStateAddWorkerForNodeConnector(new TunnelStateAddWorker(directTunnelUtils, txRunner),
324 tunnelStateInfo), ITMConstants.JOB_MAX_RETRIES);
328 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
329 justification = "https://github.com/spotbugs/spotbugs/issues/811")
330 private List<? extends ListenableFuture<?>> updateState(String interfaceName,
331 FlowCapableNodeConnector flowCapableNodeConnectorNew,
332 FlowCapableNodeConnector flowCapableNodeConnectorOld) {
333 LOG.debug("Updating interface state for port: {}", interfaceName);
335 // Hardware updates can be ignored
336 Interface.OperStatus operStatusNew = getOpState(flowCapableNodeConnectorNew);
337 MacAddress macAddressNew = flowCapableNodeConnectorNew.getHardwareAddress();
339 Interface.OperStatus operStatusOld = getOpState(flowCapableNodeConnectorOld);
340 MacAddress macAddressOld = flowCapableNodeConnectorOld.getHardwareAddress();
342 boolean opstateModified = false;
343 boolean hardwareAddressModified = false;
344 if (!operStatusNew.equals(operStatusOld)) {
345 opstateModified = true;
347 if (!Objects.equals(macAddressNew, macAddressOld)) {
348 hardwareAddressModified = true;
351 if (!opstateModified && !hardwareAddressModified) {
352 LOG.debug("If State entry for port: {} Not Modified.", interfaceName);
353 return Collections.emptyList();
356 DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
358 // For monitoring enabled tunnels, skip opstate updation
359 if (!modifyTunnelOpState(dpnTepInfo, opstateModified)) {
360 LOG.debug("skipping Tunnel-state update for monitoring enabled tunnel interface {}", interfaceName);
361 opstateModified = false;
364 if (!opstateModified && !hardwareAddressModified) {
365 LOG.debug("If State entry for port: {} Not Modified.", interfaceName);
366 return Collections.emptyList();
368 if (opstateModified) {
369 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
370 // modify the attributes in interface operational DS
371 handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, flowCapableNodeConnectorNew.getName(),
373 EVENT_LOGGER.debug("ITM-TunnelInventoryState, UPDATE {} CHGED {} completed", interfaceName,
374 operStatusNew.getName());
377 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
378 // modify the attributes in interface operational DS
379 handleInterfaceStateUpdates(tx, dpnTepInfo, false, interfaceName,
380 flowCapableNodeConnectorNew.getName(), operStatusNew);
381 EVENT_LOGGER.debug("ITM-TunnelInventoryState, UPDATE {} completed", interfaceName);
386 private void updateInterfaceStateOnNodeRemove(TypedWriteTransaction<Operational> tx, String interfaceName,
387 FlowCapableNodeConnector flowCapableNodeConnector) {
388 LOG.debug("Updating interface oper-status to UNKNOWN for : {}", interfaceName);
389 DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
391 handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, flowCapableNodeConnector.getName(),
392 Interface.OperStatus.Unknown);
395 private void updateOfTepStateOnNodeRemove(Uint64 srcDpn, String ofTepName,
396 FlowCapableNodeConnector flowCapableNodeConnector,
397 TypedReadWriteTransaction<Operational> tx) throws ReadFailedException {
398 LOG.debug("Updating oftep oper-status to UNKNOWN for : {}", ofTepName);
399 Optional<OfDpnTep> dpnTepInfo = ofDpnTepConfigCache.get(srcDpn.toJava());
400 if (dpnTepInfo == null || !ofTepName.equals(flowCapableNodeConnector.getName())) {
403 handleOfTepStateUpdates(dpnTepInfo, tx, true, ofTepName,
404 Interface.OperStatus.Unknown);
407 private void handleOfTepStateUpdates(Optional<OfDpnTep> dpnTepInfo, TypedReadWriteTransaction<Operational> tx,
408 boolean opStateModified, String ofTepName, Interface.OperStatus opState) {
409 LOG.debug("updating oftep state entry for {}", ofTepName);
410 InstanceIdentifier<OfTep> ofTepStateId = ItmUtils.buildStateOfTepListId(new OfTepKey(ofTepName));
411 OfTepBuilder ofTepBuilder = new OfTepBuilder();
412 ofTepBuilder.withKey(new OfTepKey(ofTepName));
413 if (opStateModified) {
414 LOG.debug("updating oftep oper status as {} for {}", opState.getName(), ofTepName);
415 ofTepBuilder.setOfTepState(DirectTunnelUtils.convertInterfaceToTunnelOperState(opState));
416 LOG.trace("updated to {} for {}",opState.getName(), ofTepName);
418 tx.merge(ofTepStateId, ofTepBuilder.build());
421 private Interface.OperStatus getOpState(FlowCapableNodeConnector flowCapableNodeConnector) {
422 return flowCapableNodeConnector.getState().isLive()
423 && !flowCapableNodeConnector.getConfiguration().isPORTDOWN()
424 ? Interface.OperStatus.Up : Interface.OperStatus.Down;
427 private void handleInterfaceStateUpdates(TypedWriteTransaction<Operational> tx,
428 DpnTepInterfaceInfo dpnTepInfo,
429 boolean opStateModified, String interfaceName, String portName,
430 Interface.OperStatus opState) {
431 if (dpnTepInfo == null && !portName.startsWith("of") && !interfaceName.equals(portName)) {
434 LOG.debug("updating interface state entry for {}", interfaceName);
435 InstanceIdentifier<StateTunnelList> tnlStateId = ItmUtils.buildStateTunnelListId(
436 new StateTunnelListKey(interfaceName));
437 StateTunnelListBuilder stateTnlBuilder = new StateTunnelListBuilder();
438 stateTnlBuilder.withKey(new StateTunnelListKey(interfaceName));
439 if (modifyOpState(dpnTepInfo, opStateModified)) {
440 LOG.debug("updating interface oper status as {} for {}", opState.name(), interfaceName);
441 boolean tunnelState = opState.equals(Interface.OperStatus.Up);
442 stateTnlBuilder.setTunnelState(tunnelState);
443 stateTnlBuilder.setOperState(DirectTunnelUtils.convertInterfaceToTunnelOperState(opState));
445 tx.merge(tnlStateId, stateTnlBuilder.build());
448 private boolean modifyOpState(DpnTepInterfaceInfo dpnTepInterfaceInfo, boolean opStateModified) {
449 return opStateModified && dpnTepInterfaceInfo != null;
452 private boolean modifyTunnelOpState(DpnTepInterfaceInfo dpnTepInterfaceInfo, boolean opStateModified) {
453 return !dpnTepInterfaceInfo.isMonitoringEnabled() && modifyOpState(dpnTepInterfaceInfo, opStateModified);
456 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
457 justification = "https://github.com/spotbugs/spotbugs/issues/811")
458 private List<? extends ListenableFuture<?>> removeInterfaceStateConfiguration(NodeConnectorId nodeConnectorId,
459 String interfaceName,
460 FlowCapableNodeConnector
461 flowCapableNodeConnector) {
464 List<ListenableFuture<?>> futures = new ArrayList<>();
465 Uint64 dpId = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId);
466 // In a genuine port delete scenario, the reason will be there in the incoming event, for all remaining
467 // cases treat the event as DPN disconnect, if old and new ports are same. Else, this is a VM migration
468 // scenario, and should be treated as port removal.
469 if (flowCapableNodeConnector.getReason() != PortReason.Delete) {
470 //Remove event is because of connection lost between controller and switch, or switch shutdown.
471 // Hence, dont remove the interface but set the status as "unknown"
473 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
474 tx -> updateInterfaceStateOnNodeRemove(tx, interfaceName, flowCapableNodeConnector)));
477 LOG.debug("removing interface state for interface: {}", interfaceName);
478 directTunnelUtils.deleteTunnelStateEntry(interfaceName);
479 DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
480 if (dpnTepInfo != null) {
481 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
482 // Do if-index and ingress flow clean-up only for tunnel-interfaces
483 directTunnelUtils.removeLportTagInterfaceMap(interfaceName);
484 directTunnelUtils.removeTunnelIngressFlow(tx, dpId, interfaceName);
485 directTunnelUtils.removeTunnelEgressFlow(tx, dpId, interfaceName);
488 LOG.error("DPNTEPInfo is null for Tunnel Interface {}", interfaceName);
490 EVENT_LOGGER.debug("ITM-TunnelInventoryState,REMOVE Table 0 flow for {} completed", interfaceName);
495 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
496 justification = "https://github.com/spotbugs/spotbugs/issues/811")
497 private List<? extends ListenableFuture<?>> removeOfTepStateConfiguration(NodeConnectorId nodeConnectorIdNew,
498 NodeConnectorId nodeConnectorIdOld,
500 FlowCapableNodeConnector
501 fcNodeConnectorOld) {
502 List<ListenableFuture<?>> futures = new ArrayList<>();
504 NodeConnectorId nodeConnectorId = (nodeConnectorIdOld != null && !nodeConnectorIdNew.equals(nodeConnectorIdOld))
505 ? nodeConnectorIdOld : nodeConnectorIdNew;
507 Uint64 dpId = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId);
509 // In a genuine port delete scenario, the reason will be there in the incoming event, for all remaining
510 // cases treat the event as DPN disconnect, if old and new ports are same. Else, this is a VM migration
511 // scenario, and should be treated as port removal.
512 if (fcNodeConnectorOld.getReason() != PortReason.Delete) {
513 //Remove event is because of connection lost between controller and switch, or switch shutdown.
514 // Hence, dont remove the interface but set the status as "unknown"
515 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
516 updateOfTepStateOnNodeRemove(dpId, ofTepName, fcNodeConnectorOld, tx);
519 LOG.debug("removing oftep state for oftep: {}", ofTepName);
520 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
521 directTunnelUtils.deleteOfTepStateEntry(ofTepName);
522 directTunnelUtils.removeLportTagInterfaceMap(ofTepName);
523 directTunnelUtils.removeTunnelIngressFlow(tx, dpId, ofTepName);
525 EVENT_LOGGER.debug("ITM-OfTepInventoryState,REMOVE Table 0 flow for {} completed", ofTepName);
531 private class TunnelInterfaceStateUpdateWorker implements Callable<List<? extends ListenableFuture<?>>> {
532 private final InstanceIdentifier<FlowCapableNodeConnector> key;
533 private final FlowCapableNodeConnector fcNodeConnectorOld;
534 private final FlowCapableNodeConnector fcNodeConnectorNew;
535 private final String interfaceName;
537 TunnelInterfaceStateUpdateWorker(InstanceIdentifier<FlowCapableNodeConnector> key,
538 FlowCapableNodeConnector fcNodeConnectorOld,
539 FlowCapableNodeConnector fcNodeConnectorNew, String portName) {
541 this.fcNodeConnectorOld = fcNodeConnectorOld;
542 this.fcNodeConnectorNew = fcNodeConnectorNew;
543 this.interfaceName = portName;
547 public List<? extends ListenableFuture<?>> call() {
548 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
549 // to call the respective helpers.
550 return updateState(interfaceName, fcNodeConnectorNew, fcNodeConnectorOld);
554 public String toString() {
555 return "TunnelInterfaceStateUpdateWorker{key=" + key + ", fcNodeConnectorOld=" + fcNodeConnectorOld
556 + ", fcNodeConnectorNew=" + fcNodeConnectorNew + ", interfaceName='" + interfaceName + '\'' + '}';
560 private class TunnelInterfaceStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
561 private final NodeConnectorId nodeConnectorId;
562 private final FlowCapableNodeConnector flowCapableNodeConnector;
563 private final String interfaceName;
565 TunnelInterfaceStateRemoveWorker(NodeConnectorId nodeConnectorId,
566 FlowCapableNodeConnector flowCapableNodeConnector,
567 String interfaceName) {
568 this.nodeConnectorId = nodeConnectorId;
569 this.flowCapableNodeConnector = flowCapableNodeConnector;
570 this.interfaceName = interfaceName;
574 public List<? extends ListenableFuture<?>> call() {
575 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
576 // to call the respective helpers.
577 return removeInterfaceStateConfiguration(nodeConnectorId, interfaceName, flowCapableNodeConnector);
581 public String toString() {
582 return "TunnelInterfaceStateRemoveWorker{nodeConnectorId=" + nodeConnectorId + ", fcNodeConnector"
583 + flowCapableNodeConnector + ", interfaceName='" + interfaceName + '\'' + '}';
587 private class TunnelInterfaceNodeReconnectWorker implements Callable<List<? extends ListenableFuture<?>>> {
588 private final String tunnelName;
590 TunnelInterfaceNodeReconnectWorker(String tunnelName) {
591 this.tunnelName = tunnelName;
595 public List<? extends ListenableFuture<?>> call() throws Exception {
596 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
597 // to call the respective helpers.
598 EVENT_LOGGER.debug("ITM-TunnelInventoryState, Compute Re-connected, ADD received for {} ", tunnelName);
600 return handleInterfaceStateOnReconnect(tunnelName);
604 public String toString() {
605 return "TunnelInterfaceNodeReconnectWorker{tunnelName=" + tunnelName + '\'' + '}';
609 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
610 justification = "https://github.com/spotbugs/spotbugs/issues/811")
611 private List<? extends ListenableFuture<?>> handleInterfaceStateOnReconnect(String interfaceName) {
612 List<ListenableFuture<?>> futures = new ArrayList<>();
614 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
615 DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
617 handleInterfaceStateUpdates(tx, dpnTepInfo, true, interfaceName, interfaceName,
618 Interface.OperStatus.Up);
623 private class OfPortStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
625 private final NodeConnectorId nodeconnectorIdNew;
626 private final NodeConnectorId nodeconnectorIdOld;
627 private final FlowCapableNodeConnector fcNodeConnectorOld;
628 private final String ofTepName;
630 OfPortStateRemoveWorker(NodeConnectorId nodeconnectorIdNew, NodeConnectorId nodeconnectorIdOld,
631 FlowCapableNodeConnector fcNodeConnectorOld, String ofTepName) {
632 this.nodeconnectorIdNew = nodeconnectorIdNew;
633 this.nodeconnectorIdOld = nodeconnectorIdOld;
634 this.fcNodeConnectorOld = fcNodeConnectorOld;
635 this.ofTepName = ofTepName;
639 public List<? extends ListenableFuture<?>> call() throws Exception {
640 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
641 // to call the respective helpers.
642 return removeOfTepStateConfiguration(nodeconnectorIdNew, nodeconnectorIdOld, ofTepName, fcNodeConnectorOld);
646 public String toString() {
647 return "OfTepStateRemoveWorker{nodeConnectorInfo=" + nodeconnectorIdNew + ", nodeConnectorIdOld="
648 + nodeconnectorIdOld + ", fcNodeConnectorOld=" + fcNodeConnectorOld + ", ofTepName='"
649 + ofTepName + '\'' + '}';