*/
package org.opendaylight.genius.itm.itmdirecttunnels.listeners;
+import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
import static org.opendaylight.mdsal.binding.util.Datastore.OPERATIONAL;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.Callable;
import org.opendaylight.mdsal.binding.util.Datastore.Operational;
import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.mdsal.binding.util.TypedReadWriteTransaction;
import org.opendaylight.mdsal.binding.util.TypedWriteTransaction;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.common.api.ReadFailedException;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortReason;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.tep.config.OfDpnTep;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.of.teps.state.OfTep;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.of.teps.state.OfTepBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.of.teps.state.OfTepKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListKey;
public void remove(@NonNull InstanceIdentifier<FlowCapableNodeConnector> key,
@NonNull FlowCapableNodeConnector flowCapableNodeConnector) {
String portName = flowCapableNodeConnector.getName();
+ NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class)).getId();
LOG.debug("InterfaceInventoryState Remove for {}", portName);
EVENT_LOGGER.debug("ITM-TunnelInventoryState,REMOVE DTCN received for {}",
flowCapableNodeConnector.getName());
- // ITM Direct Tunnels Return if its not tunnel port and if its not Internal
- if (!DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(portName) && !portName.startsWith("of")) {
+
+ if (!directTunnelUtils.isEntityOwner()) {
+ return;
+ }
+ // ITM Direct Tunnels Return if its not tunnel port or of-ports
+ if (portName.startsWith("of") && interfaceManager.isItmOfTunnelsEnabled()) {
+ LOG.debug("OfPortState REMOVE for {}", portName);
+ EVENT_LOGGER.debug("ITM-OfPortStateState Entity Owner, REMOVE {} {}", nodeConnectorId.getValue(), portName);
+ OfPortStateRemoveWorker ofPortStateRemoveWorker = new OfPortStateRemoveWorker(nodeConnectorId,
+ null, flowCapableNodeConnector, portName);
+ coordinator.enqueueJob(portName, ofPortStateRemoveWorker, ITMConstants.JOB_MAX_RETRIES);
+ return;
+ } else if (!DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(portName)) {
LOG.debug("Node Connector Remove - {} Interface is not a tunnel I/f, so no-op", portName);
return;
- } else {
- try {
- if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(portName)
- && !tunnelStateCache.isInternalBasedOnState(portName)) {
- LOG.debug("Node Connector Remove {} Interface is not a internal tunnel I/f, so no-op", portName);
- return;
- }
- } catch (ReadFailedException e) {
- LOG.error("Tunnel {} is not present in operational DS ", portName);
+ }
+
+ try {
+ if (!tunnelStateCache.isInternalBasedOnState(portName)) {
+ LOG.debug("Node Connector Remove {} Interface is not a internal tunnel I/f, so no-op", portName);
return;
}
- }
- if (!directTunnelUtils.isEntityOwner()) {
+ } catch (ReadFailedException e) {
+ LOG.error("Tunnel {} is not present in operational DS ", portName);
return;
}
LOG.debug("Received NodeConnector Remove Event: {}, {}", key, flowCapableNodeConnector);
- NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class)).getId();
remove(nodeConnectorId, flowCapableNodeConnector, portName);
}
Interface.OperStatus.Unknown);
}
+ private void updateOfTepStateOnNodeRemove(Uint64 srcDpn, String ofTepName,
+ FlowCapableNodeConnector flowCapableNodeConnector,
+ TypedReadWriteTransaction<Operational> tx) throws ReadFailedException {
+ LOG.debug("Updating oftep oper-status to UNKNOWN for : {}", ofTepName);
+ Optional<OfDpnTep> dpnTepInfo = ofDpnTepConfigCache.get(srcDpn.toJava());
+ if (dpnTepInfo == null || !ofTepName.equals(flowCapableNodeConnector.getName())) {
+ return;
+ }
+ handleOfTepStateUpdates(dpnTepInfo, tx, true, ofTepName,
+ Interface.OperStatus.Unknown);
+ }
+
+ private void handleOfTepStateUpdates(Optional<OfDpnTep> dpnTepInfo, TypedReadWriteTransaction<Operational> tx,
+ boolean opStateModified, String ofTepName, Interface.OperStatus opState) {
+ LOG.debug("updating oftep state entry for {}", ofTepName);
+ InstanceIdentifier<OfTep> ofTepStateId = ItmUtils.buildStateOfTepListId(new OfTepKey(ofTepName));
+ OfTepBuilder ofTepBuilder = new OfTepBuilder();
+ ofTepBuilder.withKey(new OfTepKey(ofTepName));
+ if (opStateModified) {
+ LOG.debug("updating oftep oper status as {} for {}", opState.getName(), ofTepName);
+ ofTepBuilder.setOfTepState(DirectTunnelUtils.convertInterfaceToTunnelOperState(opState));
+ LOG.trace("updated to {} for {}",opState.getName(), ofTepName);
+ }
+ tx.merge(ofTepStateId, ofTepBuilder.build());
+ }
+
private Interface.OperStatus getOpState(FlowCapableNodeConnector flowCapableNodeConnector) {
return flowCapableNodeConnector.getState().isLive()
&& !flowCapableNodeConnector.getConfiguration().isPORTDOWN()
//Remove event is because of connection lost between controller and switch, or switch shutdown.
// Hence, dont remove the interface but set the status as "unknown"
- if (interfaceName.startsWith("of")) {
- LOG.debug("Received remove state for dpid {}", dpId.intValue());
- for (Map.Entry<String, NodeConnectorInfo> entry : meshedMap.entrySet()) {
- if (!dpId.toString().equals(entry.getKey())) {
- String fwdTunnel = dpnTepStateCache.getDpnTepInterface(dpId, Uint64.valueOf(entry.getKey()))
- .getTunnelName();
- LOG.debug("Fwd Tunnel name for {} : {} is {}", dpId.intValue(), entry.getKey(), fwdTunnel);
- futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
- tx -> updateInterfaceStateOnNodeRemove(tx, fwdTunnel, flowCapableNodeConnector)));
- String bwdTunnel = dpnTepStateCache.getDpnTepInterface(Uint64.valueOf(entry.getKey()), dpId)
- .getTunnelName();
- LOG.debug("Bwd Tunnel name for {} : {} is {}", entry.getKey(), dpId.intValue(), bwdTunnel);
- futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
- tx -> updateInterfaceStateOnNodeRemove(tx, bwdTunnel,
- entry.getValue().getNodeConnector())));
- }
- }
- } else {
- futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
- tx -> updateInterfaceStateOnNodeRemove(tx, interfaceName, flowCapableNodeConnector)));
- }
+ futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
+ tx -> updateInterfaceStateOnNodeRemove(tx, interfaceName, flowCapableNodeConnector)));
+
} else {
LOG.debug("removing interface state for interface: {}", interfaceName);
+ directTunnelUtils.deleteTunnelStateEntry(interfaceName);
+ DpnTepInterfaceInfo dpnTepInfo = dpnTepStateCache.getTunnelFromCache(interfaceName);
+ if (dpnTepInfo != null) {
+ futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
+ // Do if-index and ingress flow clean-up only for tunnel-interfaces
+ directTunnelUtils.removeLportTagInterfaceMap(interfaceName);
+ directTunnelUtils.removeTunnelIngressFlow(tx, dpId, interfaceName);
+ directTunnelUtils.removeTunnelEgressFlow(tx, dpId, interfaceName);
+ }));
+ } else {
+ LOG.error("DPNTEPInfo is null for Tunnel Interface {}", interfaceName);
+ }
EVENT_LOGGER.debug("ITM-TunnelInventoryState,REMOVE Table 0 flow for {} completed", interfaceName);
- // removing interfaces are already done in delete worker
- meshedMap.remove(dpId.toString());
}
return futures;
}
+ @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
+ justification = "https://github.com/spotbugs/spotbugs/issues/811")
+ private List<? extends ListenableFuture<?>> removeOfTepStateConfiguration(NodeConnectorId nodeConnectorIdNew,
+ NodeConnectorId nodeConnectorIdOld,
+ String ofTepName,
+ FlowCapableNodeConnector
+ fcNodeConnectorOld) {
+ List<ListenableFuture<?>> futures = new ArrayList<>();
+
+ NodeConnectorId nodeConnectorId = (nodeConnectorIdOld != null && !nodeConnectorIdNew.equals(nodeConnectorIdOld))
+ ? nodeConnectorIdOld : nodeConnectorIdNew;
+
+ Uint64 dpId = DirectTunnelUtils.getDpnFromNodeConnectorId(nodeConnectorId);
+
+ // In a genuine port delete scenario, the reason will be there in the incoming event, for all remaining
+ // cases treat the event as DPN disconnect, if old and new ports are same. Else, this is a VM migration
+ // scenario, and should be treated as port removal.
+ if (fcNodeConnectorOld.getReason() != PortReason.Delete) {
+ //Remove event is because of connection lost between controller and switch, or switch shutdown.
+ // Hence, dont remove the interface but set the status as "unknown"
+ futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
+ updateOfTepStateOnNodeRemove(dpId, ofTepName, fcNodeConnectorOld, tx);
+ }));
+ } else {
+ LOG.debug("removing oftep state for oftep: {}", ofTepName);
+ futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
+ directTunnelUtils.deleteOfTepStateEntry(ofTepName);
+ directTunnelUtils.removeLportTagInterfaceMap(ofTepName);
+ directTunnelUtils.removeTunnelIngressFlow(tx, dpId, ofTepName);
+ }));
+ EVENT_LOGGER.debug("ITM-OfTepInventoryState,REMOVE Table 0 flow for {} completed", ofTepName);
+ }
+
+ return futures;
+ }
+
private class TunnelInterfaceStateUpdateWorker implements Callable<List<? extends ListenableFuture<?>>> {
private final InstanceIdentifier<FlowCapableNodeConnector> key;
private final FlowCapableNodeConnector fcNodeConnectorOld;
}));
return futures;
}
+
+ private class OfPortStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
+
+ private final NodeConnectorId nodeconnectorIdNew;
+ private final NodeConnectorId nodeconnectorIdOld;
+ private final FlowCapableNodeConnector fcNodeConnectorOld;
+ private final String ofTepName;
+
+ OfPortStateRemoveWorker(NodeConnectorId nodeconnectorIdNew, NodeConnectorId nodeconnectorIdOld,
+ FlowCapableNodeConnector fcNodeConnectorOld, String ofTepName) {
+ this.nodeconnectorIdNew = nodeconnectorIdNew;
+ this.nodeconnectorIdOld = nodeconnectorIdOld;
+ this.fcNodeConnectorOld = fcNodeConnectorOld;
+ this.ofTepName = ofTepName;
+ }
+
+ @Override
+ public List<? extends ListenableFuture<?>> call() throws Exception {
+ // If another renderer(for eg : OVS) needs to be supported, check can be performed here
+ // to call the respective helpers.
+ return removeOfTepStateConfiguration(nodeconnectorIdNew, nodeconnectorIdOld, ofTepName, fcNodeConnectorOld);
+ }
+
+ @Override
+ public String toString() {
+ return "OfTepStateRemoveWorker{nodeConnectorInfo=" + nodeconnectorIdNew + ", nodeConnectorIdOld="
+ + nodeconnectorIdOld + ", fcNodeConnectorOld=" + fcNodeConnectorOld + ", ofTepName='"
+ + ofTepName + '\'' + '}';
+ }
+ }
}