2 * Copyright (c) 2016, 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.alivenessmonitor.internal;
10 import static org.opendaylight.genius.alivenessmonitor.utils.AlivenessMonitorUtil.getMonitorStateId;
11 import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
12 import static org.opendaylight.mdsal.binding.util.Datastore.OPERATIONAL;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.MoreExecutors;
16 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.List;
22 import java.util.Optional;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.Semaphore;
25 import java.util.concurrent.atomic.AtomicBoolean;
26 import java.util.concurrent.atomic.AtomicReference;
27 import javax.inject.Inject;
28 import javax.inject.Singleton;
29 import org.apache.aries.blueprint.annotation.service.Reference;
30 import org.eclipse.jdt.annotation.NonNull;
31 import org.eclipse.jdt.annotation.Nullable;
32 import org.opendaylight.genius.alivenessmonitor.protocols.AlivenessProtocolHandler;
33 import org.opendaylight.genius.alivenessmonitor.protocols.AlivenessProtocolHandlerRegistry;
34 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
35 import org.opendaylight.mdsal.binding.api.DataBroker;
36 import org.opendaylight.mdsal.binding.util.Datastore;
37 import org.opendaylight.mdsal.binding.util.InterruptibleCheckedConsumer;
38 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
39 import org.opendaylight.mdsal.binding.util.RetryingManagedNewTransactionRunner;
40 import org.opendaylight.mdsal.binding.util.TypedReadWriteTransaction;
41 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
42 import org.opendaylight.openflowplugin.libraries.liblldp.Packet;
43 import org.opendaylight.serviceutils.tools.listener.AbstractSyncDataTreeChangeListener;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.LivenessState;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProtocolType;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.EndpointType;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.endpoint.type.Interface;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.configs.MonitoringInfo;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profiles.MonitorProfile;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitoring.states.MonitoringState;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitoring.states.MonitoringStateBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelsBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelsKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigs;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigsBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigsKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParams;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParamsBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParamsKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigs;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigsBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigsKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdStatus;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdStatusKey;
68 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
69 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
70 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
71 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
72 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
73 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
74 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
76 import org.opendaylight.yangtools.yang.common.Uint32;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
81 public class HwVtepTunnelsStateHandler extends AbstractSyncDataTreeChangeListener<Tunnels>
82 implements AlivenessProtocolHandler<Packet> {
84 private static final Logger LOG = LoggerFactory.getLogger(HwVtepTunnelsStateHandler.class);
86 private final ManagedNewTransactionRunner txRunner;
87 private final AlivenessMonitor alivenessMonitor;
90 public HwVtepTunnelsStateHandler(@Reference final DataBroker dataBroker,
91 final AlivenessMonitor alivenessMonitor,
92 final AlivenessProtocolHandlerRegistry alivenessProtocolHandlerRegistry) {
93 super(dataBroker, LogicalDatastoreType.CONFIGURATION,
94 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
95 .augmentation(PhysicalSwitchAugmentation.class).child(Tunnels.class));
96 this.txRunner = new RetryingManagedNewTransactionRunner(dataBroker);
97 this.alivenessMonitor = alivenessMonitor;
98 alivenessProtocolHandlerRegistry.register(MonitorProtocolType.Bfd, this);
102 public void remove(@NonNull InstanceIdentifier<Tunnels> instanceIdentifier, @NonNull Tunnels tunnelInfo) {
107 public void update(@NonNull InstanceIdentifier<Tunnels> instanceIdentifier, @NonNull Tunnels oldTunnelInfo,
108 @NonNull Tunnels updatedTunnelInfo) {
109 @Nullable Map<BfdStatusKey, BfdStatus> oldBfdStatus = oldTunnelInfo.getBfdStatus();
110 @Nullable Map<BfdStatusKey, BfdStatus> newBfdStatus = updatedTunnelInfo.getBfdStatus();
111 LivenessState oldTunnelOpState = getTunnelOpState(oldBfdStatus);
112 final LivenessState newTunnelOpState = getTunnelOpState(newBfdStatus);
113 if (oldTunnelOpState == newTunnelOpState) {
114 LOG.debug("Tunnel state of old tunnel {} and update tunnel {} are same", oldTunnelInfo, updatedTunnelInfo);
117 updatedTunnelInfo.getTunnelUuid();
118 String interfaceName = "<TODO>";
119 // TODO: find out the corresponding interface using tunnelIdentifier or
120 // any attributes of tunnelInfo object
121 final String monitorKey = getBfdMonitorKey(interfaceName);
122 LOG.debug("Processing monitorKey: {} for received Tunnels update DCN", monitorKey);
124 final Semaphore lock = alivenessMonitor.getLock(monitorKey);
125 LOG.debug("Acquiring lock for monitor key : {} to process monitor DCN", monitorKey);
126 alivenessMonitor.acquireLock(lock);
128 AtomicBoolean stateChanged = new AtomicBoolean();
129 AtomicReference<MonitoringState> currentState = new AtomicReference<>();
130 txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
131 Optional<MonitoringState> optState = tx.read(getMonitorStateId(monitorKey)).get();
132 if (optState.isPresent()) {
133 currentState.set(optState.get());
134 if (currentState.get().getState() == newTunnelOpState) {
137 stateChanged.set(true);
138 final MonitoringState state = new MonitoringStateBuilder().setMonitorKey(monitorKey)
139 .setState(newTunnelOpState).build();
140 tx.merge(getMonitorStateId(monitorKey), state);
142 LOG.warn("Monitoring State not available for key: {} to process the Packet received", monitorKey);
144 }).addCallback(new FutureCallback<Object>() {
146 public void onSuccess(@Nullable Object result) {
147 alivenessMonitor.releaseLock(lock);
148 if (stateChanged.get()) {
149 // send notifications
150 LOG.info("Sending notification for monitor Id : {} with Current State: {}",
151 currentState.get().getMonitorId(), newTunnelOpState);
152 alivenessMonitor.publishNotification(currentState.get().getMonitorId(), newTunnelOpState);
154 if (LOG.isTraceEnabled()) {
155 LOG.trace("Successful in writing monitoring state {} to ODS", newTunnelOpState);
161 public void onFailure(@NonNull Throwable error) {
162 alivenessMonitor.releaseLock(lock);
163 LOG.warn("Error in writing monitoring state for {} to Datastore", monitorKey, error);
165 }, MoreExecutors.directExecutor());
168 private LivenessState getTunnelOpState(Map<BfdStatusKey, BfdStatus> tunnelBfdStatus) {
169 LivenessState livenessState = LivenessState.Unknown;
170 if (tunnelBfdStatus == null || tunnelBfdStatus.isEmpty()) {
171 return livenessState;
173 for (BfdStatus bfdState : tunnelBfdStatus.values()) {
174 if (AlivenessMonitorConstants.BFD_OP_STATE.equalsIgnoreCase(bfdState.getBfdStatusKey())) {
175 String bfdOpState = bfdState.getBfdStatusValue();
176 if (AlivenessMonitorConstants.BFD_STATE_UP.equalsIgnoreCase(bfdOpState)) {
177 livenessState = LivenessState.Up;
179 livenessState = LivenessState.Down;
184 return livenessState;
188 public void add(@NonNull InstanceIdentifier<Tunnels> instanceIdentifier, @NonNull Tunnels tunnelInfo) {
189 // TODO: need to add the code to enable BFD if tunnels are created
190 // dynamically by TOR switch
194 public Class<Packet> getPacketClass() {
199 @SuppressFBWarnings("NP_NONNULL_RETURN_VIOLATION")
200 public String handlePacketIn(Packet protocolPacket, PacketReceived packetReceived) {
204 void resetMonitoringTask(boolean isEnable) {
205 // TODO: get the corresponding hwvtep tunnel from the sourceInterface
206 // once InterfaceMgr implements renderer for HWVTEP VXLAN tunnels
208 LoggingFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
209 new InterruptibleCheckedConsumer<TypedReadWriteTransaction<Datastore.Configuration>, ExecutionException>() {
211 // tunnelKey, nodeId, topologyId are initialized to null and immediately passed to
212 // getTunnelIdentifier which FindBugs as a "Load of known null value" violation. Not sure sure what
214 @SuppressFBWarnings("NP_LOAD_OF_KNOWN_NULL_VALUE")
215 public void accept(TypedReadWriteTransaction<Datastore.Configuration> tx)
216 throws ExecutionException, InterruptedException {
217 TunnelsKey tunnelKey = null;
218 String nodeId = null;
219 String topologyId = null;
220 Optional<Tunnels> tunnelsOptional =
221 tx.read(getTunnelIdentifier(topologyId, nodeId, tunnelKey)).get();
222 if (!tunnelsOptional.isPresent()) {
223 LOG.warn("Tunnel {} is not present on the Node {}. So not disabling the BFD monitoring",
228 Tunnels tunnel = tunnelsOptional.get();
229 @Nullable Map<BfdParamsKey, BfdParams> tunnelBfdParams = tunnel.getBfdParams();
230 if (tunnelBfdParams == null || tunnelBfdParams.isEmpty()) {
231 LOG.debug("there is no bfd params available for the tunnel {}", tunnel);
235 Iterator<BfdParams> tunnelBfdParamsIterator = tunnelBfdParams.values().iterator();
236 while (tunnelBfdParamsIterator.hasNext()) {
237 BfdParams bfdParam = tunnelBfdParamsIterator.next();
238 if (AlivenessMonitorConstants.BFD_PARAM_ENABLE.equals(bfdParam.getBfdParamKey())) {
239 tunnelBfdParamsIterator.remove();
243 HwVtepTunnelsStateHandler.this.setBfdParamForEnable(tunnelBfdParams, isEnable);
244 Tunnels tunnelWithBfdReset =
245 new TunnelsBuilder().withKey(tunnelKey).setBfdParams(tunnelBfdParams).build();
246 tx.mergeParentStructureMerge(
247 getTunnelIdentifier(topologyId, nodeId, tunnelKey), tunnelWithBfdReset);
249 }), LOG, "Error resetting monitoring task");
253 public void startMonitoringTask(MonitoringInfo monitorInfo) {
254 EndpointType source = monitorInfo.getSource().getEndpointType();
255 if (source instanceof Interface) {
256 Interface intf = (Interface) source;
257 intf.getInterfaceName();
259 LOG.warn("Invalid source endpoint. Could not retrieve source interface to configure BFD");
262 MonitorProfile profile;
263 Uint32 profileId = monitorInfo.getProfileId();
264 java.util.Optional<MonitorProfile> optProfile = alivenessMonitor.getMonitorProfile(profileId);
265 if (optProfile.isPresent()) {
266 profile = optProfile.get();
268 LOG.warn("No monitor profile associated with id {}. " + "Could not send Monitor packet for monitor-id {}",
269 profileId, monitorInfo);
272 // TODO: get the corresponding hwvtep tunnel from the sourceInterface
274 // Implements renderer for hwvtep VXLAN tunnels
275 String tunnelLocalMacAddress = "<TODO>";
276 String tunnelLocalIpAddress = "<TODO>";
277 String tunnelRemoteMacAddress = "<TODO>";
278 Map<BfdParamsKey, BfdParams> bfdParams = new HashMap<>();
279 fillBfdParams(bfdParams, profile);
280 List<BfdLocalConfigs> bfdLocalConfigs = new ArrayList<>();
281 fillBfdLocalConfigs(bfdLocalConfigs, tunnelLocalMacAddress, tunnelLocalIpAddress);
282 List<BfdRemoteConfigs> bfdRemoteConfigs = new ArrayList<>();
283 fillBfdRemoteConfigs(bfdRemoteConfigs, tunnelRemoteMacAddress);
284 // tunnelKey is initialized to null and passed to withKey which FindBugs flags as a
285 // "Load of known null value" violation. Not sure sure what the intent is...
286 //TunnelsKey tunnelKey = null;
287 Tunnels tunnelWithBfd = new TunnelsBuilder().withKey(/*tunnelKey*/ null).setBfdParams(bfdParams)
288 .setBfdLocalConfigs(bfdLocalConfigs).setBfdRemoteConfigs(bfdRemoteConfigs).build();
289 // TODO: get the following parameters from the interface and use it to
290 // update hwvtep datastore
291 // and not sure sure tunnels are creating immediately once interface mgr
292 // writes termination point
293 // into hwvtep datastore. if tunnels are not created during that time,
294 // then start monitoring has to
295 // be done as part of tunnel add DCN handling.
296 String topologyId = "";
298 LoggingFutures.addErrorLogging(
299 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> tx.mergeParentStructureMerge(
300 getTunnelIdentifier(topologyId, nodeId, new TunnelsKey(/*localRef*/ null, /*remoteRef*/ null)),
301 tunnelWithBfd)), LOG, "Error starting a monitoring task");
304 private void fillBfdRemoteConfigs(List<BfdRemoteConfigs> bfdRemoteConfigs, String tunnelRemoteMacAddress) {
306 .add(getBfdRemoteConfig(AlivenessMonitorConstants.BFD_CONFIG_BFD_DST_MAC, tunnelRemoteMacAddress));
309 private BfdRemoteConfigs getBfdRemoteConfig(String key, String value) {
310 return new BfdRemoteConfigsBuilder().setBfdRemoteConfigKey(key).setBfdRemoteConfigValue(value)
311 .withKey(new BfdRemoteConfigsKey(key)).build();
314 private void fillBfdLocalConfigs(List<BfdLocalConfigs> bfdLocalConfigs, String tunnelLocalMacAddress,
315 String tunnelLocalIpAddress) {
316 bfdLocalConfigs.add(getBfdLocalConfig(AlivenessMonitorConstants.BFD_CONFIG_BFD_DST_MAC, tunnelLocalMacAddress));
317 bfdLocalConfigs.add(getBfdLocalConfig(AlivenessMonitorConstants.BFD_CONFIG_BFD_DST_IP, tunnelLocalIpAddress));
320 private BfdLocalConfigs getBfdLocalConfig(String key, String value) {
321 return new BfdLocalConfigsBuilder().setBfdLocalConfigKey(key).withKey(new BfdLocalConfigsKey(key))
322 .setBfdLocalConfigValue(value).build();
325 private void fillBfdParams(Map<BfdParamsKey, BfdParams> bfdParams, MonitorProfile profile) {
326 setBfdParamForEnable(bfdParams, true);
327 BfdParams bfdParams1 = getBfdParams(AlivenessMonitorConstants.BFD_PARAM_MIN_RX,
328 Long.toString(profile.getMinRx().toJava()));
329 bfdParams.put(bfdParams1.key(),bfdParams1);
331 BfdParams bfdParams2 = getBfdParams(AlivenessMonitorConstants.BFD_PARAM_MIN_TX,
332 Long.toString(profile.getMinTx().toJava()));
333 bfdParams.put(bfdParams2.key(), bfdParams2);
335 BfdParams bfdParams3 = getBfdParams(AlivenessMonitorConstants.BFD_PARAM_DECAY_MIN_RX,
336 Long.toString(profile.getDecayMinRx().toJava()));
337 bfdParams.put(bfdParams3.key(), bfdParams3);
339 BfdParams bfdParams4 = getBfdParams(AlivenessMonitorConstants.BFD_PARAM_FORWARDING_IF_RX,
340 profile.getForwardingIfRx());
341 bfdParams.put(bfdParams4.key(), bfdParams4);
343 BfdParams bfdParams5 = getBfdParams(AlivenessMonitorConstants.BFD_PARAM_CPATH_DOWN, profile.getCpathDown());
344 bfdParams.put(bfdParams5.key(),bfdParams5);
346 BfdParams bfdParams6 = getBfdParams(AlivenessMonitorConstants.BFD_PARAM_CHECK_TNL_KEY,
347 profile.getCheckTnlKey());
348 bfdParams.put(bfdParams6.key(),bfdParams6);
351 private void setBfdParamForEnable(Map<BfdParamsKey, BfdParams> bfdParams, boolean isEnabled) {
352 BfdParams getBfdParam = getBfdParams(AlivenessMonitorConstants.BFD_PARAM_ENABLE, Boolean.toString(isEnabled));
353 bfdParams.put(getBfdParam.key(), getBfdParam);
356 private BfdParams getBfdParams(String key, String value) {
357 return new BfdParamsBuilder().setBfdParamKey(key).withKey(new BfdParamsKey(key)).setBfdParamValue(value)
362 public String getUniqueMonitoringKey(MonitoringInfo monitorInfo) {
363 String interfaceName = getInterfaceName(monitorInfo.getSource().getEndpointType());
364 return getBfdMonitorKey(interfaceName);
367 private String getBfdMonitorKey(String interfaceName) {
368 return interfaceName + "bfd";
371 private String getInterfaceName(EndpointType endpoint) {
372 String interfaceName = null;
373 if (endpoint instanceof Interface) {
374 interfaceName = ((Interface) endpoint).getInterfaceName();
376 return interfaceName;
379 private static InstanceIdentifier<Tunnels> getTunnelIdentifier(String topologyId, String nodeId,
380 TunnelsKey tunnelsKey) {
381 return InstanceIdentifier.builder(NetworkTopology.class)
382 .child(Topology.class, new TopologyKey(new TopologyId(topologyId)))
383 .child(Node.class, new NodeKey(new NodeId(nodeId))).augmentation(PhysicalSwitchAugmentation.class)
384 .child(Tunnels.class, tunnelsKey).build();