Merge "Remove an unnecessary augmentation"
[genius.git] / alivenessmonitor / alivenessmonitor-impl / src / main / java / org / opendaylight / genius / alivenessmonitor / internal / HwVtepTunnelsStateHandler.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.genius.alivenessmonitor.internal;
9
10 import static org.opendaylight.genius.alivenessmonitor.internal.AlivenessMonitorUtil.getMonitorStateId;
11
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.inject.Inject;
21 import javax.inject.Singleton;
22 import org.opendaylight.controller.liblldp.Packet;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.genius.alivenessmonitor.protocols.AlivenessProtocolHandler;
27 import org.opendaylight.genius.alivenessmonitor.protocols.AlivenessProtocolHandlerRegistry;
28 import org.opendaylight.genius.datastoreutils.hwvtep.HwvtepAbstractDataTreeChangeListener;
29 import org.opendaylight.genius.mdsalutil.MDSALUtil;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.EtherTypes;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.LivenessState;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.EndpointType;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint.endpoint.type.Interface;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.configs.MonitoringInfo;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profiles.MonitorProfile;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitoring.states.MonitoringState;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitoring.states.MonitoringStateBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.Tunnels;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelsBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelsKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigs;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigsBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdLocalConfigsKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParams;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParamsBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdParamsKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigs;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigsBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdRemoteConfigsKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.tunnel.attributes.BfdStatus;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
59 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
61 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 @Singleton
66 public class HwVtepTunnelsStateHandler extends HwvtepAbstractDataTreeChangeListener<Tunnels, HwVtepTunnelsStateHandler>
67         implements AlivenessProtocolHandler, AutoCloseable {
68
69     private static final Logger LOG = LoggerFactory.getLogger(HwVtepTunnelsStateHandler.class);
70     private final DataBroker dataBroker;
71     private final AlivenessMonitor alivenessMonitor;
72
73     @Inject
74     public HwVtepTunnelsStateHandler(final DataBroker dataBroker, final AlivenessMonitor alivenessMonitor,
75             final AlivenessProtocolHandlerRegistry alivenessProtocolHandlerRegistry) {
76         super(Tunnels.class, HwVtepTunnelsStateHandler.class);
77         this.dataBroker = dataBroker;
78         this.alivenessMonitor = alivenessMonitor;
79         alivenessProtocolHandlerRegistry.register(EtherTypes.Bfd, this);
80         registerListener(LogicalDatastoreType.CONFIGURATION, this.dataBroker);
81         LOG.info("{} started", getClass().getSimpleName());
82     }
83
84     @Override
85     protected InstanceIdentifier<Tunnels> getWildCardPath() {
86         return InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
87                 .augmentation(PhysicalSwitchAugmentation.class).child(Tunnels.class);
88     }
89
90     @Override
91     protected HwVtepTunnelsStateHandler getDataTreeChangeListener() {
92         return HwVtepTunnelsStateHandler.this;
93     }
94
95     @Override
96     protected void removed(InstanceIdentifier<Tunnels> identifier, Tunnels del) {
97         // TODO Auto-generated method stub
98     }
99
100     @Override
101     protected void updated(InstanceIdentifier<Tunnels> identifier, Tunnels oldTunnelInfo, Tunnels updatedTunnelInfo) {
102         List<BfdStatus> oldBfdStatus = oldTunnelInfo.getBfdStatus();
103         List<BfdStatus> newBfdStatus = updatedTunnelInfo.getBfdStatus();
104         LivenessState oldTunnelOpState = getTunnelOpState(oldBfdStatus);
105         final LivenessState newTunnelOpState = getTunnelOpState(newBfdStatus);
106         if (oldTunnelOpState == newTunnelOpState) {
107             LOG.debug("Tunnel state of old tunnel {} and update tunnel {} are same", oldTunnelInfo, updatedTunnelInfo);
108             return;
109         }
110         updatedTunnelInfo.getTunnelUuid();
111         String interfaceName = "<TODO>";
112         // TODO: find out the corresponding interface using tunnelIdentifier or
113         // any attributes of tunneInfo object
114         final String monitorKey = getBfdMonitorKey(interfaceName);
115         LOG.debug("Processing monitorKey: {} for received Tunnels update DCN", monitorKey);
116
117         final Semaphore lock = alivenessMonitor.lockMap.get(monitorKey);
118         LOG.debug("Acquiring lock for monitor key : {} to process monitor DCN", monitorKey);
119         alivenessMonitor.acquireLock(lock);
120
121         final ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
122
123         ListenableFuture<Optional<MonitoringState>> stateResult = tx.read(LogicalDatastoreType.OPERATIONAL,
124                 getMonitorStateId(monitorKey));
125         Futures.addCallback(stateResult, new FutureCallback<Optional<MonitoringState>>() {
126
127             @Override
128             public void onSuccess(Optional<MonitoringState> optState) {
129                 if (optState.isPresent()) {
130                     final MonitoringState currentState = optState.get();
131                     if (currentState.getState() == newTunnelOpState) {
132                         return;
133                     }
134                     final boolean stateChanged = true;
135                     final MonitoringState state = new MonitoringStateBuilder().setMonitorKey(monitorKey)
136                             .setState(newTunnelOpState).build();
137                     tx.merge(LogicalDatastoreType.OPERATIONAL, getMonitorStateId(monitorKey), state);
138                     ListenableFuture<Void> writeResult = tx.submit();
139                     // WRITE Callback
140                     Futures.addCallback(writeResult, new FutureCallback<Void>() {
141
142                         @Override
143                         public void onSuccess(Void arg0) {
144                             alivenessMonitor.releaseLock(lock);
145                             if (stateChanged) {
146                                 // send notifications
147                                 LOG.info("Sending notification for monitor Id : {} with Current State: {}",
148                                         currentState.getMonitorId(), newTunnelOpState);
149                                 alivenessMonitor.publishNotification(currentState.getMonitorId(), newTunnelOpState);
150                             } else {
151                                 if (LOG.isTraceEnabled()) {
152                                     LOG.trace("Successful in writing monitoring state {} to ODS", state);
153                                 }
154                             }
155                         }
156
157                         @Override
158                         public void onFailure(Throwable error) {
159                             alivenessMonitor.releaseLock(lock);
160                             LOG.warn("Error in writing monitoring state : {} to Datastore", monitorKey, error);
161                             if (LOG.isTraceEnabled()) {
162                                 LOG.trace("Error in writing monitoring state: {} to Datastore", state);
163                             }
164                         }
165                     });
166                 } else {
167                     LOG.warn("Monitoring State not available for key: {} to process the Packet received", monitorKey);
168                     // Complete the transaction
169                     tx.submit();
170                     alivenessMonitor.releaseLock(lock);
171                 }
172             }
173
174             @Override
175             public void onFailure(Throwable error) {
176                 LOG.error("Error when reading Monitoring State for key: {} to process the Packet received", monitorKey,
177                         error);
178                 // FIXME: Not sure if the transaction status is valid to cancel
179                 tx.cancel();
180                 alivenessMonitor.releaseLock(lock);
181             }
182         });
183     }
184
185     private LivenessState getTunnelOpState(List<BfdStatus> tunnelBfdStatus) {
186         LivenessState livenessState = LivenessState.Unknown;
187         if (tunnelBfdStatus == null || tunnelBfdStatus.isEmpty()) {
188             return livenessState;
189         }
190         for (BfdStatus bfdState : tunnelBfdStatus) {
191             if (bfdState.getBfdStatusKey().equalsIgnoreCase(AlivenessMonitorConstants.BFD_OP_STATE)) {
192                 String bfdOpState = bfdState.getBfdStatusValue();
193                 if (bfdOpState.equalsIgnoreCase(AlivenessMonitorConstants.BFD_STATE_UP)) {
194                     livenessState = LivenessState.Up;
195                 } else {
196                     livenessState = LivenessState.Down;
197                 }
198                 break;
199             }
200         }
201         return livenessState;
202     }
203
204     @Override
205     protected void added(InstanceIdentifier<Tunnels> identifier, Tunnels add) {
206         // TODO: need to add the code to enable BFD if tunnels are created
207         // dynamically by TOR switch
208     }
209
210     @Override
211     public Class<?> getPacketClass() {
212         return null;
213     }
214
215     @Override
216     public String handlePacketIn(Packet protocolPacket, PacketReceived packetReceived) {
217         return null;
218     }
219
220     void resetMonitoringTask(MonitoringInfo monitorInfo, boolean isEnable) {
221         // TODO: get the corresponding hwvtep tunnel from the sourceInterface
222         // 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);
231             return;
232         }
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);
237         }
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();
243                 break;
244             }
245         }
246         setBfdParamForEnable(tunnelBfdParams, isEnable);
247         Tunnels tunnelWithBfdReset = new TunnelsBuilder().setKey(tunnelKey).setBfdParams(tunnelBfdParams).build();
248         MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
249                 getTunnelIdentifier(topologyId, nodeId, tunnelKey), tunnelWithBfdReset);
250     }
251
252     @Override
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();
258         } else {
259             LOG.warn("Invalid source endpoint. Could not retrieve source interface to configure BFD");
260             return;
261         }
262         MonitorProfile profile;
263         long profileId = monitorInfo.getProfileId();
264         Optional<MonitorProfile> optProfile = alivenessMonitor.getMonitorProfile(profileId);
265         if (optProfile.isPresent()) {
266             profile = optProfile.get();
267         } else {
268             LOG.warn("No monitor profile associated with id {}. " + "Could not send Monitor packet for monitor-id {}",
269                     profileId, monitorInfo);
270             return;
271         }
272         // TODO: get the corresponding hwvtep tunnel from the sourceInterface
273         // once InterfaceMgr
274         // Implements renderer for hwvtep vxlan tunnels
275         String tunnelLocalMacAddress = "<TODO>";
276         String tunnelLocalIpAddress = "<TODO>";
277         String tunnelRemoteMacAddress = "<TODO>";
278         String tunnelRemoteIpAddress = "<TODO>";
279         List<BfdParams> bfdParams = new ArrayList<>();
280         fillBfdParams(bfdParams, profile);
281         List<BfdLocalConfigs> bfdLocalConfigs = new ArrayList<>();
282         fillBfdLocalConfigs(bfdLocalConfigs, tunnelLocalMacAddress, tunnelLocalIpAddress);
283         List<BfdRemoteConfigs> bfdRemoteConfigs = new ArrayList<>();
284         fillBfdRemoteConfigs(bfdRemoteConfigs, tunnelRemoteMacAddress, tunnelRemoteIpAddress);
285         TunnelsKey tunnelKey = null;
286         Tunnels tunnelWithBfd = new TunnelsBuilder().setKey(tunnelKey).setBfdParams(bfdParams)
287                 .setBfdLocalConfigs(bfdLocalConfigs).setBfdRemoteConfigs(bfdRemoteConfigs).build();
288         // TODO: get the following parameters from the interface and use it to
289         // update hwvtep datastore
290         // and not sure sure tunnels are creating immediately once interface mgr
291         // writes termination point
292         // into hwvtep datastore. if tunnels are not created during that time,
293         // then start monitoring has to
294         // be done as part of tunnel add DCN handling.
295         HwvtepPhysicalLocatorRef remoteRef = null;
296         HwvtepPhysicalLocatorRef localRef = null;
297         String topologyId = "";
298         String nodeId = "";
299         MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
300                 getTunnelIdentifier(topologyId, nodeId, new TunnelsKey(localRef, remoteRef)), tunnelWithBfd);
301     }
302
303     private void fillBfdRemoteConfigs(List<BfdRemoteConfigs> bfdRemoteConfigs, String tunnelRemoteMacAddress,
304             String tunnelRemoteIpAddress) {
305         bfdRemoteConfigs
306                 .add(getBfdRemoteConfig(AlivenessMonitorConstants.BFD_CONFIG_BFD_DST_MAC, tunnelRemoteMacAddress));
307     }
308
309     private BfdRemoteConfigs getBfdRemoteConfig(String key, String value) {
310         return new BfdRemoteConfigsBuilder().setBfdRemoteConfigKey(key).setBfdRemoteConfigValue(value)
311                 .setKey(new BfdRemoteConfigsKey(key)).build();
312     }
313
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));
318     }
319
320     private BfdLocalConfigs getBfdLocalConfig(String key, String value) {
321         return new BfdLocalConfigsBuilder().setBfdLocalConfigKey(key).setKey(new BfdLocalConfigsKey(key))
322                 .setBfdLocalConfigValue(value).build();
323     }
324
325     private void fillBfdParams(List<BfdParams> bfdParams, MonitorProfile profile) {
326         setBfdParamForEnable(bfdParams, true);
327         bfdParams.add(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_MIN_RX, Long.toString(profile.getMinRx())));
328         bfdParams.add(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_MIN_TX, Long.toString(profile.getMinTx())));
329         bfdParams.add(
330                 getBfdParams(AlivenessMonitorConstants.BFD_PARAM_DECAY_MIN_RX, Long.toString(profile.getDecayMinRx())));
331         bfdParams.add(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_FORWARDING_IF_RX, profile.getForwardingIfRx()));
332         bfdParams.add(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_CPATH_DOWN, profile.getCpathDown()));
333         bfdParams.add(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_CHECK_TNL_KEY, profile.getCheckTnlKey()));
334     }
335
336     private void setBfdParamForEnable(List<BfdParams> bfdParams, boolean isEnabled) {
337         bfdParams.add(getBfdParams(AlivenessMonitorConstants.BFD_PARAM_ENABLE, Boolean.toString(isEnabled)));
338     }
339
340     private BfdParams getBfdParams(String key, String value) {
341         return new BfdParamsBuilder().setBfdParamKey(key).setKey(new BfdParamsKey(key)).setBfdParamValue(value).build();
342     }
343
344     @Override
345     public String getUniqueMonitoringKey(MonitoringInfo monitorInfo) {
346         String interfaceName = getInterfaceName(monitorInfo.getSource().getEndpointType());
347         return getBfdMonitorKey(interfaceName);
348     }
349
350     private String getBfdMonitorKey(String interfaceName) {
351         return interfaceName + "bfd";
352     }
353
354     private String getInterfaceName(EndpointType endpoint) {
355         String interfaceName = null;
356         if (endpoint instanceof Interface) {
357             interfaceName = ((Interface) endpoint).getInterfaceName();
358         }
359         return interfaceName;
360     }
361
362     public static InstanceIdentifier<Tunnels> getTunnelIdentifier(String topologyId, String nodeId,
363             TunnelsKey tunnelsKey) {
364         return InstanceIdentifier.builder(NetworkTopology.class)
365                 .child(Topology.class, new TopologyKey(new TopologyId(topologyId)))
366                 .child(Node.class, new NodeKey(new NodeId(nodeId))).augmentation(PhysicalSwitchAugmentation.class)
367                 .child(Tunnels.class, tunnelsKey).build();
368     }
369 }