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