2 * Copyright (c) 2016 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.internal.AlivenessMonitorUtil.getMonitorStateId;
12 import com.google.common.base.Optional;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.util.ArrayList;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.concurrent.Semaphore;
20 import javax.annotation.PostConstruct;
21 import javax.annotation.PreDestroy;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24 import org.opendaylight.controller.liblldp.Packet;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
27 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.genius.datastoreutils.hwvtep.HwvtepAbstractDataTreeChangeListener;
31 import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
32 import org.opendaylight.genius.mdsalutil.MDSALUtil;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.EtherTypes;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.LivenessState;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.EndpointType;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.endpoint.type.Interface;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.configs.MonitoringInfo;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profiles.MonitorProfile;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitoring.states.MonitoringState;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitoring.states.MonitoringStateBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelsBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelsKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigs;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigsBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigsKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParams;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParamsBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParamsKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigs;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigsBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigsKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdStatus;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
59 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
64 import org.opendaylight.yangtools.concepts.ListenerRegistration;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
70 public class HwVtepTunnelsStateHandler extends HwvtepAbstractDataTreeChangeListener<Tunnels,HwVtepTunnelsStateHandler>
71 implements AlivenessProtocolHandler, AutoCloseable {
73 private static final Logger LOG = LoggerFactory.getLogger(HwVtepTunnelsStateHandler.class);
74 private final DataBroker dataBroker;
75 private final AlivenessMonitor alivenessMonitor;
78 public HwVtepTunnelsStateHandler(final DataBroker dataBroker, final AlivenessMonitor alivenessMonitor) {
79 super(Tunnels.class,HwVtepTunnelsStateHandler.class);
80 this.dataBroker = dataBroker;
81 this.alivenessMonitor = alivenessMonitor;
86 LOG.info("{} start", getClass().getSimpleName());
87 alivenessMonitor.registerHandler(EtherTypes.Bfd, this);
88 registerListener(LogicalDatastoreType.CONFIGURATION,this.dataBroker);
92 protected InstanceIdentifier<Tunnels> getWildCardPath() {
93 return InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
94 .augmentation(PhysicalSwitchAugmentation.class).child(Tunnels.class);
97 protected HwVtepTunnelsStateHandler getDataTreeChangeListener() {
98 return HwVtepTunnelsStateHandler.this;
102 protected void removed(InstanceIdentifier<Tunnels> identifier, Tunnels del) {
103 // TODO Auto-generated method stub
108 protected void updated(InstanceIdentifier<Tunnels> identifier, Tunnels oldTunnelInfo, Tunnels updatedTunnelInfo) {
109 List<BfdStatus> oldBfdStatus = oldTunnelInfo.getBfdStatus();
110 List<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 any attributes of tunneInfo object
120 final String monitorKey = getBfdMonitorKey(interfaceName);
121 LOG.debug("Processing monitorKey: {} for received Tunnels update DCN", monitorKey);
123 final Semaphore lock = alivenessMonitor.lockMap.get(monitorKey);
124 LOG.debug("Acquiring lock for monitor key : {} to process monitor DCN", monitorKey);
125 alivenessMonitor.acquireLock(lock);
127 final ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
129 ListenableFuture<Optional<MonitoringState>> stateResult = tx.read(LogicalDatastoreType.OPERATIONAL, getMonitorStateId(monitorKey));
130 Futures.addCallback(stateResult, new FutureCallback<Optional<MonitoringState>>() {
133 public void onSuccess(Optional<MonitoringState> optState) {
134 if(optState.isPresent()) {
135 final MonitoringState currentState = optState.get();
136 if (currentState.getState() == newTunnelOpState) {
139 final boolean stateChanged = true;
140 final MonitoringState state = new MonitoringStateBuilder().setMonitorKey(monitorKey).setState(newTunnelOpState).build();
141 tx.merge(LogicalDatastoreType.OPERATIONAL, getMonitorStateId(monitorKey), state);
142 ListenableFuture<Void> writeResult = tx.submit();
144 Futures.addCallback(writeResult, new FutureCallback<Void>() {
147 public void onSuccess(Void arg0) {
148 alivenessMonitor.releaseLock(lock);
151 LOG.info("Sending notification for monitor Id : {} with Current State: {}",
152 currentState.getMonitorId(), newTunnelOpState);
153 alivenessMonitor.publishNotification(currentState.getMonitorId(), newTunnelOpState);
155 if(LOG.isTraceEnabled()) {
156 LOG.trace("Successful in writing monitoring state {} to ODS", state);
161 public void onFailure(Throwable error) {
162 alivenessMonitor.releaseLock(lock);
163 LOG.warn("Error in writing monitoring state : {} to Datastore", monitorKey, error);
164 if(LOG.isTraceEnabled()) {
165 LOG.trace("Error in writing monitoring state: {} to Datastore", state);
170 LOG.warn("Monitoring State not available for key: {} to process the Packet received", monitorKey);
171 //Complete the transaction
173 alivenessMonitor.releaseLock(lock);
178 public void onFailure(Throwable error) {
179 LOG.error("Error when reading Monitoring State for key: {} to process the Packet received", monitorKey, error);
180 //FIXME: Not sure if the transaction status is valid to cancel
182 alivenessMonitor.releaseLock(lock);
187 private LivenessState getTunnelOpState(List<BfdStatus> tunnelBfdStatus) {
188 LivenessState livenessState = LivenessState.Unknown;
189 if (tunnelBfdStatus == null || tunnelBfdStatus.isEmpty()) {
190 return livenessState;
192 for (BfdStatus bfdState: tunnelBfdStatus) {
193 if (bfdState.getBfdStatusKey().equalsIgnoreCase(AlivenessMonitorConstants.BFD_OP_STATE)) {
194 String bfdOpState = bfdState.getBfdStatusValue();
195 if (bfdOpState.equalsIgnoreCase(AlivenessMonitorConstants.BFD_STATE_UP)) {
196 livenessState = LivenessState.Up;
198 livenessState = LivenessState.Down;
203 return livenessState;
207 protected void added(InstanceIdentifier<Tunnels> identifier, Tunnels add) {
208 // TODO: need to add the code to enable BFD if tunnels are created dynamically by TOR switch
212 public Class<?> getPacketClass() {
217 public String handlePacketIn(Packet protocolPacket, PacketReceived packetReceived) {
221 void resetMonitoringTask(MonitoringInfo monitorInfo, boolean isEnable) {
222 // TODO: get the corresponding hwvtep tunnel from the sourceInterface once InterfaceMgr
223 // implments renderer for hwvtep vxlan tunnels
224 TunnelsKey tunnelKey = null;
225 String nodeId = null;
226 String topologyId = null;
227 Optional<Tunnels> tunnelsOptional = alivenessMonitor.read(LogicalDatastoreType.CONFIGURATION,
228 getTunnelIdentifier(topologyId, nodeId, tunnelKey));
229 if (!tunnelsOptional.isPresent()) {
230 LOG.warn("Tunnel {} is not present on the Node {}. So not disabling the BFD monitoing", tunnelKey, nodeId);
233 Tunnels tunnel = tunnelsOptional.get();
234 List<BfdParams> tunnelBfdParams = tunnel.getBfdParams();
235 if (tunnelBfdParams == null || tunnelBfdParams.isEmpty()) {
236 LOG.debug("there is no bfd params available for the tunnel {}", tunnel);
238 Iterator<BfdParams> tunnelBfdParamsInterator = tunnelBfdParams.iterator();
239 while (tunnelBfdParamsInterator.hasNext()) {
240 BfdParams bfdParam = tunnelBfdParamsInterator.next();
241 if (bfdParam.getBfdParamKey().equals(AlivenessMonitorConstants.BFD_PARAM_ENABLE)) {
242 tunnelBfdParamsInterator.remove();
246 setBfdParamForEnable(tunnelBfdParams, isEnable);
247 Tunnels tunnelWithBfdReset = new TunnelsBuilder().setKey(tunnelKey).setBfdParams(tunnelBfdParams).build();
248 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, getTunnelIdentifier(topologyId, nodeId, tunnelKey), tunnelWithBfdReset);
252 public void startMonitoringTask(MonitoringInfo monitorInfo) {
253 EndpointType source = monitorInfo.getSource().getEndpointType();
254 if( source instanceof Interface) {
255 Interface intf = (Interface)source;
256 intf.getInterfaceName();
258 LOG.warn("Invalid source endpoint. Could not retrieve source interface to configure BFD");
261 MonitorProfile profile;
262 long profileId = monitorInfo.getProfileId();
263 Optional<MonitorProfile> optProfile = alivenessMonitor.getMonitorProfile(profileId);
264 if(optProfile.isPresent()) {
265 profile = optProfile.get();
267 LOG.warn("No monitor profile associated with id {}. "
268 + "Could not send Monitor packet for monitor-id {}", profileId, monitorInfo);
271 // TODO: get the corresponding hwvtep tunnel from the sourceInterface once InterfaceMgr
272 // implments renderer for hwvtep vxlan tunnels
273 TunnelsKey tunnelKey = null;
274 String tunnelLocalMacAddress = "<TODO>";
275 String tunnelLocalIpAddress = "<TODO>";
276 String tunnelRemoteMacAddress = "<TODO>";
277 String tunnelRemoteIpAddress = "<TODO>";
278 List<BfdParams> bfdParams = new ArrayList<>();
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, tunnelRemoteIpAddress);
284 Tunnels tunnelWithBfd = new TunnelsBuilder().setKey(tunnelKey).setBfdParams(bfdParams)
285 .setBfdLocalConfigs(bfdLocalConfigs).setBfdRemoteConfigs(bfdRemoteConfigs).build();
286 // TODO: get the following parameters from the interface and use it to update hwvtep datastore
287 // and not sure sure tunnels are creating immediately once interface mgr writes termination point
288 // into hwvtep datastore. if tunnels are not created during that time, then start monitoring has to
289 // be done as part of tunnel add DCN handling.
290 HwvtepPhysicalLocatorRef remoteRef = null;
291 HwvtepPhysicalLocatorRef localRef = null;
292 String topologyId = "";
294 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, getTunnelIdentifier(topologyId, nodeId, new TunnelsKey(localRef, remoteRef)), tunnelWithBfd);
297 private void fillBfdRemoteConfigs(List<BfdRemoteConfigs> bfdRemoteConfigs, String tunnelRemoteMacAddress,
298 String tunnelRemoteIpAddress) {
299 bfdRemoteConfigs.add(getBfdRemoteConfig(AlivenessMonitorConstants.BFD_CONFIG_BFD_DST_MAC, tunnelRemoteMacAddress));
302 private BfdRemoteConfigs getBfdRemoteConfig(String key, String value) {
303 return new BfdRemoteConfigsBuilder().setBfdRemoteConfigKey(key).setBfdRemoteConfigValue(value)
304 .setKey(new BfdRemoteConfigsKey(key)).build();
307 private void fillBfdLocalConfigs(List<BfdLocalConfigs> bfdLocalConfigs, String tunnelLocalMacAddress,
308 String tunnelLocalIpAddress) {
309 bfdLocalConfigs.add(getBfdLocalConfig(AlivenessMonitorConstants.BFD_CONFIG_BFD_DST_MAC, tunnelLocalMacAddress));
310 bfdLocalConfigs.add(getBfdLocalConfig(AlivenessMonitorConstants.BFD_CONFIG_BFD_DST_IP, tunnelLocalIpAddress));
313 private BfdLocalConfigs getBfdLocalConfig(String key, String value) {
314 return new BfdLocalConfigsBuilder().setBfdLocalConfigKey(key).setKey(new BfdLocalConfigsKey(key))
315 .setBfdLocalConfigValue(value).build();
318 private void fillBfdParams(List<BfdParams> bfdParams, MonitorProfile profile) {
319 setBfdParamForEnable(bfdParams, true);
320 bfdParams.add(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_MIN_RX, Long.toString(profile.getMinRx())));
321 bfdParams.add(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_MIN_TX, Long.toString(profile.getMinTx())));
322 bfdParams.add(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_DECAY_MIN_RX, Long.toString(profile.getDecayMinRx())));
323 bfdParams.add(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_FORWARDING_IF_RX, profile.getForwardingIfRx()));
324 bfdParams.add(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_CPATH_DOWN, profile.getCpathDown()));
325 bfdParams.add(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_CHECK_TNL_KEY, profile.getCheckTnlKey()));
328 private void setBfdParamForEnable(List<BfdParams> bfdParams, boolean isEnabled) {
329 bfdParams.add(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_ENABLE, Boolean.toString(isEnabled)));
332 private BfdParams getBfdParams(String key, String value) {
333 return new BfdParamsBuilder().setBfdParamKey(key).setKey(new BfdParamsKey(key))
334 .setBfdParamValue(value).build();
338 public String getUniqueMonitoringKey(MonitoringInfo monitorInfo) {
339 String interfaceName = getInterfaceName(monitorInfo.getSource().getEndpointType());
340 return getBfdMonitorKey(interfaceName);
343 private String getBfdMonitorKey(String interfaceName) {
344 return new StringBuilder().append(interfaceName).append("bfd").toString();
347 private String getInterfaceName(EndpointType endpoint) {
348 String interfaceName = null;
349 if(endpoint instanceof Interface) {
350 interfaceName = ((Interface)endpoint).getInterfaceName();
352 return interfaceName;
355 public static InstanceIdentifier<Tunnels> getTunnelIdentifier(String topologyId, String nodeId, TunnelsKey tunnelsKey) {
356 return InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, new TopologyKey(new TopologyId(topologyId)))
357 .child(Node.class, new NodeKey(new NodeId(nodeId))).augmentation(PhysicalSwitchAugmentation.class)
358 .child(Tunnels.class, tunnelsKey).build();