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