Merge "Bug 7864: Specified Id key does not exist in id pool vpnservices"
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / commons / AlivenessMonitorUtils.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.interfacemanager.commons;
9
10 import com.google.common.base.Optional;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.concurrent.ExecutionException;
14 import java.util.concurrent.Future;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.genius.interfacemanager.IfmUtil;
18 import org.opendaylight.genius.mdsalutil.MDSALUtil;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.AlivenessMonitorService;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.EtherTypes;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileCreateInput;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileCreateInputBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileCreateOutput;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileDeleteInput;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileDeleteInputBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileGetInput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileGetInputBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileGetOutput;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStartInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStartInputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStartOutput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStopInput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStopInputBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitoringMode;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.params.SourceBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.create.input.Profile;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.create.input.ProfileBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.start.input.ConfigBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.InterfaceMonitorIdMap;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.MonitorIdInterfaceMap;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.monitor.id.map.InterfaceMonitorId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.monitor.id.map.InterfaceMonitorIdBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.monitor.id.map.InterfaceMonitorIdKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.monitor.id._interface.map.MonitorIdInterface;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.monitor.id._interface.map.MonitorIdInterfaceBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.monitor.id._interface.map.MonitorIdInterfaceKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeLldp;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.opendaylight.yangtools.yang.common.RpcResult;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 public class AlivenessMonitorUtils {
56
57     private static final Logger LOG = LoggerFactory.getLogger(AlivenessMonitorUtils.class);
58     private static final long FAILURE_THRESHOLD = 4;
59     private static final long MONITORING_INTERVAL = 10000;
60     private static final long MONITORING_WINDOW = 4;
61
62     public static void startLLDPMonitoring(AlivenessMonitorService alivenessMonitorService, DataBroker dataBroker,
63                                            IfTunnel ifTunnel, String trunkInterfaceName) {
64         // LLDP monitoring for the tunnel interface
65         if (lldpMonitoringEnabled(ifTunnel)) {
66             MonitorStartInput lldpMonitorInput = new MonitorStartInputBuilder().setConfig(new ConfigBuilder()
67                     .setSource(new SourceBuilder().setEndpointType(getInterfaceForMonitoring(trunkInterfaceName,
68                             ifTunnel.getTunnelSource())).build())
69                     .setMode(MonitoringMode.OneOne)
70                     .setProfileId(allocateProfile(alivenessMonitorService, FAILURE_THRESHOLD,
71                             ifTunnel.getMonitorInterval(), MONITORING_WINDOW, EtherTypes.Lldp))
72                     .build()).build();
73             try {
74                 Future<RpcResult<MonitorStartOutput>> result = alivenessMonitorService.monitorStart(lldpMonitorInput);
75                 RpcResult<MonitorStartOutput> rpcResult = result.get();
76                 long monitorId;
77                 if (rpcResult.isSuccessful()) {
78                     monitorId = rpcResult.getResult().getMonitorId();
79                     createOrUpdateInterfaceMonitorIdMap(dataBroker, trunkInterfaceName, monitorId);
80                     createOrUpdateMonitorIdInterfaceMap(dataBroker, trunkInterfaceName, monitorId);
81                     LOG.trace("Started LLDP monitoring with id {}", monitorId);
82                 } else {
83                     LOG.warn("RPC Call to start monitoring returned with Errors {}", rpcResult.getErrors());
84                 }
85             } catch (InterruptedException | ExecutionException e) {
86                 LOG.warn("Exception when starting monitoring", e);
87             }
88         }
89     }
90
91     public static void stopLLDPMonitoring(AlivenessMonitorService alivenessMonitorService, DataBroker dataBroker,
92                                           IfTunnel ifTunnel, String trunkInterface) {
93         if (!lldpMonitoringEnabled(ifTunnel)) {
94             return;
95         }
96         LOG.debug("stop LLDP monitoring for {}", trunkInterface);
97         List<Long> monitorIds = getMonitorIdForInterface(dataBroker, trunkInterface);
98         if (monitorIds == null) {
99             LOG.error("Monitor Id doesn't exist for Interface {}", trunkInterface);
100             return;
101         }
102         for (Long monitorId : monitorIds) {
103             String interfaceName = getInterfaceFromMonitorId(dataBroker, monitorId);
104             if (interfaceName != null) {
105                 MonitorStopInput input = new MonitorStopInputBuilder().setMonitorId(monitorId).build();
106                 alivenessMonitorService.monitorStop(input);
107                 removeMonitorIdInterfaceMap(dataBroker, monitorId);
108                 removeMonitorIdFromInterfaceMonitorIdMap(dataBroker, interfaceName, monitorId);
109                 return;
110             }
111         }
112     }
113
114     public static String getInterfaceFromMonitorId(DataBroker broker, Long monitorId) {
115         InstanceIdentifier<MonitorIdInterface> id = InstanceIdentifier.builder(MonitorIdInterfaceMap.class)
116                 .child(MonitorIdInterface.class, new MonitorIdInterfaceKey(monitorId)).build();
117         return IfmUtil.read(LogicalDatastoreType.OPERATIONAL, id, broker).transform(
118                 MonitorIdInterface::getInterfaceName).orNull();
119     }
120
121     private static void removeMonitorIdInterfaceMap(DataBroker broker, long monitorId) {
122         InstanceIdentifier<MonitorIdInterface> id = InstanceIdentifier.builder(MonitorIdInterfaceMap.class)
123                 .child(MonitorIdInterface.class, new MonitorIdInterfaceKey(monitorId)).build();
124         Optional<MonitorIdInterface> monitorIdInterfaceMap = IfmUtil.read(LogicalDatastoreType.OPERATIONAL, id, broker);
125         if (monitorIdInterfaceMap.isPresent()) {
126             MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
127         }
128     }
129
130     private static void removeMonitorIdFromInterfaceMonitorIdMap(DataBroker broker, String infName, long monitorId) {
131         InstanceIdentifier<InterfaceMonitorId> id = InstanceIdentifier.builder(InterfaceMonitorIdMap.class)
132                 .child(InterfaceMonitorId.class, new InterfaceMonitorIdKey(infName)).build();
133         Optional<InterfaceMonitorId> interfaceMonitorIdMap = IfmUtil.read(LogicalDatastoreType.OPERATIONAL, id, broker);
134         if (interfaceMonitorIdMap.isPresent()) {
135             InterfaceMonitorId interfaceMonitorIdInstance = interfaceMonitorIdMap.get();
136             List<Long> existingMonitorIds = interfaceMonitorIdInstance.getMonitorId();
137             if (existingMonitorIds != null && existingMonitorIds.contains(monitorId)) {
138                 existingMonitorIds.remove(monitorId);
139                 InterfaceMonitorIdBuilder interfaceMonitorIdBuilder = new InterfaceMonitorIdBuilder();
140                 interfaceMonitorIdInstance = interfaceMonitorIdBuilder.setKey(new InterfaceMonitorIdKey(infName))
141                         .setMonitorId(existingMonitorIds).build();
142                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, interfaceMonitorIdInstance);
143             }
144         }
145     }
146
147     private static org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411
148         .endpoint.endpoint.type.Interface getInterfaceForMonitoring(String interfaceName,
149             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress ipAddress) {
150         return new org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.endpoint
151                 .endpoint.type.InterfaceBuilder().setInterfaceIp(ipAddress).setInterfaceName(interfaceName).build();
152     }
153
154     public static void handleTunnelMonitorUpdates(AlivenessMonitorService alivenessMonitorService,
155             DataBroker dataBroker, Interface interfaceOld, Interface interfaceNew) {
156         String interfaceName = interfaceNew.getName();
157         IfTunnel ifTunnelNew = interfaceNew.getAugmentation(IfTunnel.class);
158         if (!lldpMonitoringEnabled(ifTunnelNew)) {
159             return;
160         }
161         LOG.debug("handling tunnel monitoring updates for interface {}", interfaceName);
162
163         stopLLDPMonitoring(alivenessMonitorService, dataBroker, ifTunnelNew, interfaceOld.getName());
164         if (ifTunnelNew.isMonitorEnabled()) {
165             startLLDPMonitoring(alivenessMonitorService, dataBroker, ifTunnelNew, interfaceName);
166
167             // Delete old profile from Aliveness Manager
168             IfTunnel ifTunnelOld = interfaceOld.getAugmentation(IfTunnel.class);
169             if (!ifTunnelNew.getMonitorInterval().equals(ifTunnelOld.getMonitorInterval())) {
170                 LOG.debug("deleting older monitor profile for interface {}", interfaceName);
171                 long profileId = allocateProfile(alivenessMonitorService, FAILURE_THRESHOLD,
172                         ifTunnelOld.getMonitorInterval(), MONITORING_WINDOW, EtherTypes.Lldp);
173                 MonitorProfileDeleteInput profileDeleteInput = new MonitorProfileDeleteInputBuilder()
174                         .setProfileId(profileId).build();
175                 alivenessMonitorService.monitorProfileDelete(profileDeleteInput);
176             }
177         }
178     }
179
180
181     public static void createOrUpdateInterfaceMonitorIdMap(DataBroker broker, String infName, long monitorId) {
182         InterfaceMonitorId interfaceMonitorIdInstance;
183         List<Long> existingMonitorIds;
184         InterfaceMonitorIdBuilder interfaceMonitorIdBuilder = new InterfaceMonitorIdBuilder();
185         InstanceIdentifier<InterfaceMonitorId> id = InstanceIdentifier.builder(InterfaceMonitorIdMap.class)
186                 .child(InterfaceMonitorId.class, new InterfaceMonitorIdKey(infName)).build();
187         Optional<InterfaceMonitorId> interfaceMonitorIdMap = IfmUtil.read(LogicalDatastoreType.OPERATIONAL, id, broker);
188         if (interfaceMonitorIdMap.isPresent()) {
189             interfaceMonitorIdInstance = interfaceMonitorIdMap.get();
190             existingMonitorIds = interfaceMonitorIdInstance.getMonitorId();
191             if (existingMonitorIds == null) {
192                 existingMonitorIds = new ArrayList<>();
193             }
194             if (!existingMonitorIds.contains(monitorId)) {
195                 existingMonitorIds.add(monitorId);
196                 interfaceMonitorIdInstance = interfaceMonitorIdBuilder.setKey(new InterfaceMonitorIdKey(infName))
197                         .setMonitorId(existingMonitorIds).build();
198                 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, id, interfaceMonitorIdInstance);
199             }
200         } else {
201             existingMonitorIds = new ArrayList<>();
202             existingMonitorIds.add(monitorId);
203             interfaceMonitorIdInstance = interfaceMonitorIdBuilder.setMonitorId(existingMonitorIds)
204                     .setKey(new InterfaceMonitorIdKey(infName)).setInterfaceName(infName).build();
205             MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, interfaceMonitorIdInstance);
206         }
207     }
208
209     public static void createOrUpdateMonitorIdInterfaceMap(DataBroker broker,String infName,  long monitorId) {
210         MonitorIdInterface monitorIdInterfaceInstance;
211         String existinginterfaceName;
212         MonitorIdInterfaceBuilder monitorIdInterfaceBuilder = new MonitorIdInterfaceBuilder();
213         InstanceIdentifier<MonitorIdInterface> id = InstanceIdentifier.builder(MonitorIdInterfaceMap.class)
214                 .child(MonitorIdInterface.class, new MonitorIdInterfaceKey(monitorId)).build();
215         Optional<MonitorIdInterface> monitorIdInterfaceMap = IfmUtil.read(LogicalDatastoreType.OPERATIONAL, id, broker);
216         if (monitorIdInterfaceMap.isPresent()) {
217             monitorIdInterfaceInstance = monitorIdInterfaceMap.get();
218             existinginterfaceName = monitorIdInterfaceInstance.getInterfaceName();
219             if (!existinginterfaceName.equals(infName)) {
220                 monitorIdInterfaceInstance = monitorIdInterfaceBuilder.setKey(new MonitorIdInterfaceKey(monitorId))
221                         .setInterfaceName(infName).build();
222                 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.OPERATIONAL, id, monitorIdInterfaceInstance);
223             }
224         } else {
225             monitorIdInterfaceInstance = monitorIdInterfaceBuilder.setMonitorId(monitorId)
226                     .setKey(new MonitorIdInterfaceKey(monitorId)).setInterfaceName(infName).build();
227             MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, monitorIdInterfaceInstance);
228         }
229     }
230
231     public static List<Long> getMonitorIdForInterface(DataBroker broker, String infName) {
232         InstanceIdentifier<InterfaceMonitorId> id = InstanceIdentifier.builder(InterfaceMonitorIdMap.class)
233                 .child(InterfaceMonitorId.class, new InterfaceMonitorIdKey(infName)).build();
234         return IfmUtil.read(LogicalDatastoreType.OPERATIONAL, id, broker).transform(
235                 InterfaceMonitorId::getMonitorId).orNull();
236     }
237
238     public static long createMonitorProfile(AlivenessMonitorService alivenessMonitor,
239             MonitorProfileCreateInput monitorProfileCreateInput) {
240         try {
241             Future<RpcResult<MonitorProfileCreateOutput>> result = alivenessMonitor
242                     .monitorProfileCreate(monitorProfileCreateInput);
243             RpcResult<MonitorProfileCreateOutput> rpcResult = result.get();
244             if (rpcResult.isSuccessful()) {
245                 return rpcResult.getResult().getProfileId();
246             } else {
247                 LOG.warn("RPC Call to Get Profile Id Id returned with Errors {}.. Trying to fetch existing profile ID",
248                         rpcResult.getErrors());
249                 try {
250                     Profile createProfile = monitorProfileCreateInput.getProfile();
251                     Future<RpcResult<MonitorProfileGetOutput>> existingProfile = alivenessMonitor.monitorProfileGet(
252                             buildMonitorGetProfile(createProfile.getMonitorInterval(), createProfile.getMonitorWindow(),
253                                     createProfile.getFailureThreshold(), createProfile.getProtocolType()));
254                     RpcResult<MonitorProfileGetOutput> rpcGetResult = existingProfile.get();
255                     if (rpcGetResult.isSuccessful()) {
256                         return rpcGetResult.getResult().getProfileId();
257                     } else {
258                         LOG.warn("RPC Call to Get Existing Profile Id returned with Errors {}",
259                                 rpcGetResult.getErrors());
260                     }
261                 } catch (Exception e) {
262                     LOG.warn("Exception when getting existing profile",e);
263                 }
264             }
265         } catch (InterruptedException | ExecutionException e) {
266             LOG.warn("Exception when allocating profile Id",e);
267         }
268         return 0;
269     }
270
271     private static MonitorProfileGetInput buildMonitorGetProfile(long monitorInterval, long monitorWindow,
272             long failureThreshold, EtherTypes protocolType) {
273         org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile
274             .get.input.ProfileBuilder profileBuilder = new org.opendaylight.yang.gen.v1.urn.opendaylight.genius
275             .alivenessmonitor.rev160411.monitor.profile.get.input.ProfileBuilder();
276         profileBuilder.setFailureThreshold(failureThreshold);
277         profileBuilder.setMonitorInterval(monitorInterval);
278         profileBuilder.setMonitorWindow(monitorWindow);
279         profileBuilder.setProtocolType(protocolType);
280         MonitorProfileGetInputBuilder buildGetProfile = new MonitorProfileGetInputBuilder();
281         buildGetProfile.setProfile(profileBuilder.build());
282         return buildGetProfile.build();
283     }
284
285     public static long allocateProfile(AlivenessMonitorService alivenessMonitor, long failureThreshold,
286             long monitoringInterval, long monitoringWindow, EtherTypes etherTypes) {
287         MonitorProfileCreateInput input = new MonitorProfileCreateInputBuilder().setProfile(
288                 new ProfileBuilder().setFailureThreshold(failureThreshold).setMonitorInterval(monitoringInterval)
289                         .setMonitorWindow(monitoringWindow).setProtocolType(etherTypes).build())
290                 .build();
291         return createMonitorProfile(alivenessMonitor, input);
292     }
293
294     public static boolean lldpMonitoringEnabled(IfTunnel ifTunnel) {
295         return ifTunnel.isInternal() && ifTunnel.isMonitorEnabled()
296                 && TunnelMonitoringTypeLldp.class.isAssignableFrom(ifTunnel.getMonitorProtocol());
297     }
298
299     public static Profile getDefaultMonitorProfile(EtherTypes etherType) {
300         ProfileBuilder profileBuilder = new ProfileBuilder();
301         profileBuilder.setProtocolType(etherType);
302         profileBuilder.setFailureThreshold(FAILURE_THRESHOLD)
303                 .setMonitorInterval(MONITORING_INTERVAL).setMonitorWindow(MONITORING_WINDOW).setProtocolType(etherType);
304         return profileBuilder.build();
305     }
306 }