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