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