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 com.google.common.util.concurrent.ListenableFuture;
11 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
12 import java.util.Collections;
13 import java.util.List;
14 import java.util.Optional;
15 import java.util.concurrent.Callable;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
18 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
19 import org.opendaylight.genius.itm.cache.BfdStateCache;
20 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
21 import org.opendaylight.genius.itm.cache.TunnelStateCache;
22 import org.opendaylight.genius.itm.globals.ITMConstants;
23 import org.opendaylight.genius.itm.impl.ItmUtils;
24 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
25 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
26 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
27 import org.opendaylight.mdsal.binding.api.DataBroker;
28 import org.opendaylight.mdsal.binding.api.WriteTransaction;
29 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
30 import org.opendaylight.serviceutils.tools.listener.AbstractClusteredSyncDataTreeChangeListener;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelOperStatus;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdStatus;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
46 public class TerminationPointStateListener
47 extends AbstractClusteredSyncDataTreeChangeListener<OvsdbTerminationPointAugmentation> {
49 private static final Logger LOG = LoggerFactory.getLogger(TerminationPointStateListener.class);
50 private static final Logger EVENT_LOGGER = LoggerFactory.getLogger("GeniusEventLogger");
52 private final ManagedNewTransactionRunner txRunner;
53 private final EntityOwnershipUtils entityOwnershipUtils;
54 private final JobCoordinator coordinator;
55 private final BfdStateCache bfdStateCache;
56 private final DpnTepStateCache dpnTepStateCache;
57 private final TunnelStateCache tunnelStateCache;
59 public TerminationPointStateListener(final DataBroker dataBroker, final EntityOwnershipUtils entityOwnershipUtils,
60 final JobCoordinator coordinator, final BfdStateCache bfdStateCache,
61 final DpnTepStateCache dpnTepStateCache,
62 final TunnelStateCache tunnelStateCache) {
63 super(dataBroker, LogicalDatastoreType.OPERATIONAL,
64 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
65 .child(TerminationPoint.class).augmentation(OvsdbTerminationPointAugmentation.class));
66 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
67 this.entityOwnershipUtils = entityOwnershipUtils;
68 this.coordinator = coordinator;
69 this.bfdStateCache = bfdStateCache;
70 this.dpnTepStateCache = dpnTepStateCache;
71 this.tunnelStateCache = tunnelStateCache;
76 public void remove(@NonNull InstanceIdentifier<OvsdbTerminationPointAugmentation> identifier,
77 @NonNull OvsdbTerminationPointAugmentation tpOld) {
78 if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(tpOld.getName())
79 && dpnTepStateCache.isInternal(tpOld.getName())) {
80 LOG.debug("Received remove DataChange Notification for ovsdb termination point {}", tpOld.getName());
81 if (tpOld.getInterfaceBfdStatus() != null) {
82 LOG.debug("Received termination point removed notification with bfd status values {}", tpOld.getName());
83 RendererTunnelStateRemoveWorker rendererStateRemoveWorker = new RendererTunnelStateRemoveWorker(tpOld);
84 coordinator.enqueueJob(tpOld.getName(), rendererStateRemoveWorker);
90 public void update(@NonNull InstanceIdentifier<OvsdbTerminationPointAugmentation> identifier,
91 @NonNull OvsdbTerminationPointAugmentation tpOld,
92 @NonNull OvsdbTerminationPointAugmentation tpNew) {
93 if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(tpNew.getName())
94 && dpnTepStateCache.isInternal(tpNew.getName())) {
95 LOG.debug("Received Update DataChange Notification for ovsdb termination point {}", tpNew.getName());
96 if (DirectTunnelUtils.changeInBfdMonitoringDetected(tpOld, tpNew)
97 || DirectTunnelUtils.ifBfdStatusNotEqual(tpOld, tpNew)) {
98 EVENT_LOGGER.debug("ITM-TerminationPointState,UPDATE {}", tpNew.getName());
99 LOG.info("Bfd Status changed for ovsdb termination point identifier: {}, old: {}, new: {}",
100 identifier, tpOld, tpNew);
101 RendererTunnelStateUpdateWorker rendererStateAddWorker = new RendererTunnelStateUpdateWorker(tpNew);
102 coordinator.enqueueJob(tpNew.getName(), rendererStateAddWorker, ITMConstants.JOB_MAX_RETRIES);
108 public void add(@NonNull InstanceIdentifier<OvsdbTerminationPointAugmentation> identifier,
109 @NonNull OvsdbTerminationPointAugmentation tpNew) {
110 if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(tpNew.getName())
111 && dpnTepStateCache.isInternal(tpNew.getName())) {
112 LOG.debug("Received add DataChange Notification for ovsdb termination point {}", tpNew.getName());
113 if (tpNew.getInterfaceBfdStatus() != null && !tpNew.getInterfaceBfdStatus().isEmpty()) {
114 EVENT_LOGGER.debug("ITM-TerminationPointState,ADD {}", tpNew.getName());
115 LOG.debug("Received termination point added notification with bfd status values {}", tpNew.getName());
116 RendererTunnelStateUpdateWorker rendererStateUpdateWorker = new RendererTunnelStateUpdateWorker(tpNew);
117 coordinator.enqueueJob(tpNew.getName(), rendererStateUpdateWorker, ITMConstants.JOB_MAX_RETRIES);
122 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
123 justification = "https://github.com/spotbugs/spotbugs/issues/811")
124 private List<ListenableFuture<Void>> updateTunnelState(OvsdbTerminationPointAugmentation terminationPointNew) {
125 final String interfaceName = terminationPointNew.getName();
126 final Interface.OperStatus interfaceBfdStatus = getTunnelOpState(terminationPointNew);
127 TunnelOperStatus tunnelState = DirectTunnelUtils.convertInterfaceToTunnelOperState(interfaceBfdStatus);
128 bfdStateCache.add(interfaceName, interfaceBfdStatus);
129 if (!entityOwnershipUtils.isEntityOwner(ITMConstants.ITM_CONFIG_ENTITY, ITMConstants.ITM_CONFIG_ENTITY)) {
130 return Collections.emptyList();
133 coordinator.enqueueJob(interfaceName, () -> {
134 // update opstate of interface if TEP has gone down/up as a result of BFD monitoring
135 Optional<StateTunnelList> stateTnl = tunnelStateCache.get(tunnelStateCache
136 .getStateTunnelListIdentifier(interfaceName));
137 if (stateTnl.isPresent() && stateTnl.get().getOperState() != TunnelOperStatus.Unknown
138 && stateTnl.get().getOperState() != tunnelState) {
139 LOG.debug("updating tunnel state for interface {} as {}", interfaceName,
140 stateTnl.get().getOperState());
141 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
142 tx -> updateOpState(tx, interfaceName, tunnelState)));
144 return Collections.emptyList();
146 return Collections.emptyList();
149 private Interface.OperStatus getTunnelOpState(OvsdbTerminationPointAugmentation terminationPoint) {
150 if (!DirectTunnelUtils.bfdMonitoringEnabled(terminationPoint.getInterfaceBfd())) {
151 return Interface.OperStatus.Up;
153 List<InterfaceBfdStatus> tunnelBfdStatus = terminationPoint.getInterfaceBfdStatus();
154 if (tunnelBfdStatus != null && !tunnelBfdStatus.isEmpty()) {
155 for (InterfaceBfdStatus bfdState : tunnelBfdStatus) {
156 if (DirectTunnelUtils.BFD_OP_STATE.equalsIgnoreCase(bfdState.getBfdStatusKey())) {
157 String bfdOpState = bfdState.getBfdStatusValue();
158 return DirectTunnelUtils.BFD_STATE_UP.equalsIgnoreCase(bfdOpState)
159 ? Interface.OperStatus.Up : Interface.OperStatus.Down;
163 return Interface.OperStatus.Down;
167 * update operational state of interface based on events like tunnel
170 private static void updateOpState(WriteTransaction transaction, String interfaceName, TunnelOperStatus operStatus) {
171 StateTunnelListKey stateTnlKey = new StateTunnelListKey(interfaceName);
172 InstanceIdentifier<StateTunnelList> stateTnlII = ItmUtils.buildStateTunnelListId(stateTnlKey);
173 LOG.debug("updating tep interface state as {} for {}", operStatus.name(), interfaceName);
174 StateTunnelListBuilder stateTnlBuilder = new StateTunnelListBuilder().withKey(stateTnlKey);
175 stateTnlBuilder.setOperState(operStatus);
176 transaction.merge(LogicalDatastoreType.OPERATIONAL, stateTnlII, stateTnlBuilder.build(), false);
179 private class RendererTunnelStateUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
180 private final OvsdbTerminationPointAugmentation terminationPointNew;
182 RendererTunnelStateUpdateWorker(OvsdbTerminationPointAugmentation tpNew) {
183 this.terminationPointNew = tpNew;
187 public List<ListenableFuture<Void>> call() throws Exception {
188 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
189 // to call the respective helpers.
190 return updateTunnelState(terminationPointNew);
194 private class RendererTunnelStateRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
195 private final OvsdbTerminationPointAugmentation terminationPointOld;
197 RendererTunnelStateRemoveWorker(OvsdbTerminationPointAugmentation tpNew) {
198 this.terminationPointOld = tpNew;
202 public List<ListenableFuture<Void>> call() throws Exception {
203 LOG.debug("Removing bfd state from cache, if any, for {}", terminationPointOld.getName());
204 bfdStateCache.remove(terminationPointOld.getName());
205 return Collections.emptyList();