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