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