Updating tunnel status based on tp status update 41/70241/24
authorEdw7n <n.edwin.anthony@ericsson.com>
Thu, 5 Apr 2018 04:21:29 +0000 (09:51 +0530)
committerEdw7n <n.edwin.anthony@ericsson.com>
Fri, 20 Apr 2018 09:11:24 +0000 (14:41 +0530)
Update the ITM tunnel status by listening to the termination point status
Fixed issues while testing

Change-Id: I5b9b5389b4a2073d6648b164f2a5975484874ab1
Signed-off-by: Edw7n <n.edwin.anthony@ericsson.com>
itm/itm-impl/src/main/java/org/opendaylight/genius/itm/itmdirecttunnels/listeners/TerminationPointStateListener.java [new file with mode: 0644]
itm/itm-impl/src/main/java/org/opendaylight/genius/itm/itmdirecttunnels/listeners/TunnelListenerCreator.java
itm/itm-impl/src/main/java/org/opendaylight/genius/itm/itmdirecttunnels/renderer/ovs/utilities/DirectTunnelUtils.java

diff --git a/itm/itm-impl/src/main/java/org/opendaylight/genius/itm/itmdirecttunnels/listeners/TerminationPointStateListener.java b/itm/itm-impl/src/main/java/org/opendaylight/genius/itm/itmdirecttunnels/listeners/TerminationPointStateListener.java
new file mode 100644 (file)
index 0000000..ea4bc90
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2018 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.genius.itm.itmdirecttunnels.listeners;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.genius.itm.cache.BfdStateCache;
+import org.opendaylight.genius.itm.cache.DpnTepStateCache;
+import org.opendaylight.genius.itm.cache.TunnelStateCache;
+import org.opendaylight.genius.itm.globals.ITMConstants;
+import org.opendaylight.genius.itm.impl.ItmUtils;
+import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
+import org.opendaylight.genius.tools.mdsal.listener.AbstractClusteredSyncDataTreeChangeListener;
+import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
+import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelOperStatus;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdStatus;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TerminationPointStateListener
+        extends AbstractClusteredSyncDataTreeChangeListener<OvsdbTerminationPointAugmentation> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TerminationPointStateListener.class);
+
+    private final ManagedNewTransactionRunner txRunner;
+    private final EntityOwnershipUtils entityOwnershipUtils;
+    private final JobCoordinator coordinator;
+    private final BfdStateCache bfdStateCache;
+    private final DpnTepStateCache dpnTepStateCache;
+    private final TunnelStateCache tunnelStateCache;
+
+    public TerminationPointStateListener(final DataBroker dataBroker, final EntityOwnershipUtils entityOwnershipUtils,
+                                         final JobCoordinator coordinator, final BfdStateCache bfdStateCache,
+                                         final DpnTepStateCache dpnTepStateCache,
+                                         final TunnelStateCache tunnelStateCache) {
+        super(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
+                        .child(TerminationPoint.class).augmentation(OvsdbTerminationPointAugmentation.class));
+        this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
+        this.entityOwnershipUtils = entityOwnershipUtils;
+        this.coordinator = coordinator;
+        this.bfdStateCache = bfdStateCache;
+        this.dpnTepStateCache = dpnTepStateCache;
+        this.tunnelStateCache = tunnelStateCache;
+        super.register();
+    }
+
+    @Override
+    public void remove(@Nonnull InstanceIdentifier<OvsdbTerminationPointAugmentation> identifier,
+                       @Nonnull OvsdbTerminationPointAugmentation tpOld) {
+        if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(tpOld.getName())
+                && dpnTepStateCache.isInternal(tpOld.getName())) {
+            LOG.debug("Received remove DataChange Notification for ovsdb termination point {}", tpOld.getName());
+            if (tpOld.getInterfaceBfdStatus() != null) {
+                LOG.debug("Received termination point removed notification with bfd status values {}", tpOld.getName());
+                RendererStateRemoveWorker rendererStateRemoveWorker = new RendererStateRemoveWorker(tpOld);
+                coordinator.enqueueJob(tpOld.getName(), rendererStateRemoveWorker);
+            }
+        }
+    }
+
+    @Override
+    public void update(@Nonnull InstanceIdentifier<OvsdbTerminationPointAugmentation> identifier,
+                       @Nonnull OvsdbTerminationPointAugmentation tpOld,
+                       @Nonnull OvsdbTerminationPointAugmentation tpNew) {
+        if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(tpNew.getName())
+                && dpnTepStateCache.isInternal(tpNew.getName())) {
+            LOG.debug("Received Update DataChange Notification for ovsdb termination point {}", tpNew.getName());
+            if (DirectTunnelUtils.changeInBfdMonitoringDetected(tpOld, tpNew)
+                    || DirectTunnelUtils.ifBfdStatusNotEqual(tpOld, tpNew)) {
+                LOG.info("Bfd Status changed for ovsdb termination point identifier: {},  old: {}, new: {}",
+                        identifier, tpOld, tpNew);
+                RendererStateUpdateWorker rendererStateAddWorker = new RendererStateUpdateWorker(tpNew);
+                coordinator.enqueueJob(tpNew.getName(), rendererStateAddWorker, ITMConstants.JOB_MAX_RETRIES);
+            }
+        }
+    }
+
+    @Override
+    public void add(@Nonnull InstanceIdentifier<OvsdbTerminationPointAugmentation> identifier,
+                    @Nonnull OvsdbTerminationPointAugmentation tpNew) {
+        if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(tpNew.getName())
+                && dpnTepStateCache.isInternal(tpNew.getName())) {
+            LOG.debug("Received add DataChange Notification for ovsdb termination point {}", tpNew.getName());
+            if (tpNew.getInterfaceBfdStatus() != null  && !tpNew.getInterfaceBfdStatus().isEmpty()) {
+                LOG.debug("Received termination point added notification with bfd status values {}", tpNew.getName());
+                RendererStateUpdateWorker rendererStateUpdateWorker = new RendererStateUpdateWorker(tpNew);
+                coordinator.enqueueJob(tpNew.getName(), rendererStateUpdateWorker, ITMConstants.JOB_MAX_RETRIES);
+            }
+        }
+    }
+
+    private List<ListenableFuture<Void>> updateTunnelState(OvsdbTerminationPointAugmentation terminationPointNew) {
+        final String interfaceName = terminationPointNew.getName();
+        final Interface.OperStatus interfaceBfdStatus = getTunnelOpState(terminationPointNew);
+        TunnelOperStatus tunnelState = DirectTunnelUtils.convertInterfaceToTunnelOperState(interfaceBfdStatus);
+        bfdStateCache.add(interfaceName, interfaceBfdStatus);
+        if (!entityOwnershipUtils.isEntityOwner(ITMConstants.ITM_CONFIG_ENTITY, ITMConstants.ITM_CONFIG_ENTITY)) {
+            return Collections.emptyList();
+        }
+
+        coordinator.enqueueJob(interfaceName, () -> {
+            // update opstate of interface if TEP has gone down/up as a result of BFD monitoring
+            Optional<StateTunnelList> stateTnl = tunnelStateCache.get(tunnelStateCache
+                    .getStateTunnelListIdentifier(interfaceName));
+            if (stateTnl.isPresent() && stateTnl.get().getOperState() != TunnelOperStatus.Unknown
+                    && stateTnl.get().getOperState() != tunnelState) {
+                LOG.debug("updating tunnel state for interface {} as {}", interfaceName,
+                        stateTnl.get().getOperState());
+                return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
+                    tx -> updateOpState(tx, interfaceName, tunnelState)));
+            }
+            return Collections.emptyList();
+        });
+        return Collections.emptyList();
+    }
+
+    private Interface.OperStatus getTunnelOpState(OvsdbTerminationPointAugmentation terminationPoint) {
+        if (!DirectTunnelUtils.bfdMonitoringEnabled(terminationPoint.getInterfaceBfd())) {
+            return Interface.OperStatus.Up;
+        }
+        List<InterfaceBfdStatus> tunnelBfdStatus = terminationPoint.getInterfaceBfdStatus();
+        if (tunnelBfdStatus != null && !tunnelBfdStatus.isEmpty()) {
+            for (InterfaceBfdStatus bfdState : tunnelBfdStatus) {
+                if (bfdState.getBfdStatusKey().equalsIgnoreCase(DirectTunnelUtils.BFD_OP_STATE)) {
+                    String bfdOpState = bfdState.getBfdStatusValue();
+                    return DirectTunnelUtils.BFD_STATE_UP.equalsIgnoreCase(bfdOpState)
+                            ? Interface.OperStatus.Up : Interface.OperStatus.Down;
+                }
+            }
+        }
+        return Interface.OperStatus.Down;
+    }
+
+    /*
+     * update operational state of interface based on events like tunnel
+     * monitoring
+     */
+    private static void updateOpState(WriteTransaction transaction, String interfaceName, TunnelOperStatus operStatus) {
+        StateTunnelListKey stateTnlKey = new StateTunnelListKey(interfaceName);
+        InstanceIdentifier<StateTunnelList> stateTnlII = ItmUtils.buildStateTunnelListId(stateTnlKey);
+        LOG.debug("updating tep interface state as {} for {}", operStatus.name(), interfaceName);
+        StateTunnelListBuilder stateTnlBuilder = new StateTunnelListBuilder().setKey(stateTnlKey);
+        stateTnlBuilder.setOperState(operStatus);
+        transaction.merge(LogicalDatastoreType.OPERATIONAL, stateTnlII, stateTnlBuilder.build(), false);
+    }
+
+    private class RendererStateUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
+        private final OvsdbTerminationPointAugmentation terminationPointNew;
+
+        RendererStateUpdateWorker(OvsdbTerminationPointAugmentation tpNew) {
+            this.terminationPointNew = tpNew;
+        }
+
+        @Override
+        public List<ListenableFuture<Void>> call() throws Exception {
+            // If another renderer(for eg : OVS) needs to be supported, check can be performed here
+            // to call the respective helpers.
+            return updateTunnelState(terminationPointNew);
+        }
+    }
+
+    private class RendererStateRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
+        private final OvsdbTerminationPointAugmentation terminationPointOld;
+
+        RendererStateRemoveWorker(OvsdbTerminationPointAugmentation tpNew) {
+            this.terminationPointOld = tpNew;
+        }
+
+        @Override
+        public List<ListenableFuture<Void>> call() throws Exception {
+            LOG.debug("Removing bfd state from cache, if any, for {}", terminationPointOld.getName());
+            bfdStateCache.remove(terminationPointOld.getName());
+            return Collections.emptyList();
+        }
+    }
+}
index 6a383122bf60818cfd1c30b845cf621633a72bb2..1759ebb31cd52003a554af6d5b6b32caadcb5df7 100644 (file)
@@ -11,6 +11,7 @@ import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.itm.cache.BfdStateCache;
 import org.opendaylight.genius.itm.cache.DPNTEPsInfoCache;
 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
 import org.opendaylight.genius.itm.cache.OvsBridgeEntryCache;
@@ -32,6 +33,7 @@ public class TunnelListenerCreator implements AutoCloseable {
     private final DpnTepStateListener dpnTepStateListener;
     private final TunnelTopologyStateListener tunnelTopologyStateListener;
     private final TunnelInventoryStateListener tunnelInventoryStateListener;
+    private final TerminationPointStateListener terminationPointStateListener;
 
     @Inject
     public TunnelListenerCreator(final DataBroker dataBroker,
@@ -41,6 +43,7 @@ public class TunnelListenerCreator implements AutoCloseable {
                                  final IMdsalApiManager mdsalApiManager,
                                  final IInterfaceManager interfaceManager,
                                  final DirectTunnelUtils directTunnelUtils,
+                                 final BfdStateCache bfdStateCache,
                                  final DpnTepStateCache dpnTepStateCache,
                                  final DPNTEPsInfoCache dpntePsInfoCache,
                                  final OvsBridgeEntryCache ovsBridgeEntryCache,
@@ -56,11 +59,14 @@ public class TunnelListenerCreator implements AutoCloseable {
             this.tunnelInventoryStateListener = new TunnelInventoryStateListener(dataBroker, coordinator,
                     entityOwnershipUtils, idManager, mdsalApiManager, tunnelStateCache, dpnTepStateCache,
                     dpntePsInfoCache, unprocessedNodeConnectorCache);
+            this.terminationPointStateListener = new TerminationPointStateListener(dataBroker, entityOwnershipUtils,
+                    coordinator, bfdStateCache, dpnTepStateCache,tunnelStateCache);
         } else {
             LOG.trace("ITM Direct Tunnels is disabled. Listeners are not registered");
             this.dpnTepStateListener = null;
             this.tunnelTopologyStateListener = null;
             this.tunnelInventoryStateListener = null;
+            this.terminationPointStateListener = null;
         }
     }
 
@@ -75,5 +81,8 @@ public class TunnelListenerCreator implements AutoCloseable {
         if (tunnelInventoryStateListener != null) {
             this.tunnelInventoryStateListener.close();
         }
+        if (terminationPointStateListener != null) {
+            this.terminationPointStateListener.close();
+        }
     }
 }
index b411367a851741112aaffdd73ccd588e493f6fcc..13c4436fa3790dec5c0cab17ad05bf51c23947a9 100644 (file)
@@ -36,6 +36,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.re
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeGre;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfd;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdKey;
@@ -55,12 +56,14 @@ public final class DirectTunnelUtils {
 
     private static final Logger LOG = LoggerFactory.getLogger(DirectTunnelUtils.class);
 
-    // BFD parameters
     private static final String BFD_PARAM_ENABLE = "enable";
     private static final String BFD_PARAM_MIN_TX = "min_tx";
     private static final String BFD_PARAM_FORWARDING_IF_RX = "forwarding_if_rx";
-
     // BFD parameters
+    private static final String BFD_ENABLE_KEY = "enable";
+    private static final String BFD_ENABLE_VALUE = "true";
+    public static final String BFD_OP_STATE = "state";
+    public static final String BFD_STATE_UP = "up";
     private static final String BFD_MIN_TX_VAL = "100";
     private static final String BFD_FORWARDING_IF_RX_VAL = "true";
 
@@ -194,4 +197,27 @@ public final class DirectTunnelUtils {
         bfdBuilder.setBfdKey(key).setKey(new InterfaceBfdKey(key)).setBfdValue(value);
         return bfdBuilder.build();
     }
+
+    public static boolean bfdMonitoringEnabled(List<InterfaceBfd> interfaceBfds) {
+        if (interfaceBfds != null && !interfaceBfds.isEmpty()) {
+            for (InterfaceBfd interfaceBfd : interfaceBfds) {
+                if (BFD_ENABLE_KEY.equalsIgnoreCase(interfaceBfd.getBfdKey())) {
+                    return BFD_ENABLE_VALUE.equalsIgnoreCase(interfaceBfd.getBfdValue());
+                }
+            }
+        }
+        return false;
+    }
+
+    public static boolean changeInBfdMonitoringDetected(OvsdbTerminationPointAugmentation tpOld,
+                                                        OvsdbTerminationPointAugmentation tpNew) {
+        return tpOld != null
+                && bfdMonitoringEnabled(tpNew.getInterfaceBfd()) != bfdMonitoringEnabled(tpOld.getInterfaceBfd());
+    }
+
+    public static boolean ifBfdStatusNotEqual(OvsdbTerminationPointAugmentation tpOld,
+                                              OvsdbTerminationPointAugmentation tpNew) {
+        return tpNew.getInterfaceBfdStatus() != null
+                && (tpOld == null || !tpNew.getInterfaceBfdStatus().equals(tpOld.getInterfaceBfdStatus()));
+    }
 }
\ No newline at end of file