2 * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.genius.interfacemanager.commons;
10 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
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.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.LoggingFutures;
28 import org.opendaylight.mdsal.binding.api.DataBroker;
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;
69 public final class AlivenessMonitorUtils {
71 private static final Logger LOG = LoggerFactory.getLogger(AlivenessMonitorUtils.class);
72 private static final long FAILURE_THRESHOLD = 4;
73 private static final long MONITORING_WINDOW = 4;
75 private final AlivenessMonitorService alivenessMonitorService;
76 private final ManagedNewTransactionRunner txRunner;
79 public AlivenessMonitorUtils(AlivenessMonitorService alivenessMonitor, @Reference DataBroker dataBroker) {
80 this.alivenessMonitorService = alivenessMonitor;
81 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
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()
91 getInterfaceForMonitoring(trunkInterfaceName, ifTunnel.getTunnelSource()))
93 .setMode(MonitoringMode.OneOne)
94 .setProfileId(allocateProfile(FAILURE_THRESHOLD,
95 ifTunnel.getMonitorInterval().toJava(), MONITORING_WINDOW,
96 MonitorProtocolType.Lldp))
100 Future<RpcResult<MonitorStartOutput>> result = alivenessMonitorService.monitorStart(lldpMonitorInput);
101 RpcResult<MonitorStartOutput> rpcResult = result.get();
102 if (rpcResult.isSuccessful()) {
103 long monitorId = rpcResult.getResult().getMonitorId().toJava();
104 LoggingFutures.addErrorLogging(
105 txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
106 createOrUpdateInterfaceMonitorIdMap(tx, trunkInterfaceName, monitorId);
107 createOrUpdateMonitorIdInterfaceMap(tx, trunkInterfaceName, monitorId);
108 LOG.trace("Started LLDP monitoring with id {}", monitorId);
109 }), LOG, "Error starting monitoring");
111 LOG.warn("RPC Call to start monitoring returned with Errors {}", rpcResult.getErrors());
113 } catch (InterruptedException | ExecutionException e) {
114 LOG.warn("Exception when starting monitoring", e);
119 public void stopLLDPMonitoring(IfTunnel ifTunnel, String trunkInterface) {
120 if (!lldpMonitoringEnabled(ifTunnel)) {
123 LOG.debug("stop LLDP monitoring for {}", trunkInterface);
124 LoggingFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
125 List<Uint32> monitorIds = getMonitorIdForInterface(tx, trunkInterface);
126 if (monitorIds == null) {
127 LOG.error("Monitor Id doesn't exist for Interface {}", trunkInterface);
130 for (Uint32 monitorId : monitorIds) {
131 String interfaceName = getInterfaceFromMonitorId(tx, monitorId);
132 if (interfaceName != null) {
133 MonitorStopInput input = new MonitorStopInputBuilder().setMonitorId(monitorId).build();
135 ListenableFuture<RpcResult<MonitorStopOutput>> future = alivenessMonitorService.monitorStop(input);
136 LoggingFutures.addErrorLogging(future, LOG, "Stop LLDP monitoring for {}", trunkInterface);
138 removeMonitorIdInterfaceMap(tx, monitorId);
139 removeMonitorIdFromInterfaceMonitorIdMap(tx, interfaceName, monitorId);
143 }), LOG, "Error stopping LLDP monitoring for {}", trunkInterface);
146 public static String getInterfaceFromMonitorId(TypedReadTransaction<Operational> tx, Uint32 monitorId)
147 throws ExecutionException, InterruptedException {
148 InstanceIdentifier<MonitorIdInterface> id = InstanceIdentifier.builder(MonitorIdInterfaceMap.class)
149 .child(MonitorIdInterface.class, new MonitorIdInterfaceKey(monitorId)).build();
150 return tx.read(id).get().map(MonitorIdInterface::getInterfaceName).orElse(null);
153 private void removeMonitorIdInterfaceMap(TypedReadWriteTransaction<Operational> tx, Uint32 monitorId)
154 throws ExecutionException, InterruptedException {
155 InstanceIdentifier<MonitorIdInterface> id = InstanceIdentifier.builder(MonitorIdInterfaceMap.class)
156 .child(MonitorIdInterface.class, new MonitorIdInterfaceKey(monitorId)).build();
157 if (tx.read(id).get().isPresent()) {
162 private void removeMonitorIdFromInterfaceMonitorIdMap(TypedReadWriteTransaction<Operational> tx, String infName,
163 Uint32 monitorId) throws ExecutionException, InterruptedException {
164 InstanceIdentifier<InterfaceMonitorId> id = InstanceIdentifier.builder(InterfaceMonitorIdMap.class)
165 .child(InterfaceMonitorId.class, new InterfaceMonitorIdKey(infName)).build();
166 Optional<InterfaceMonitorId> interfaceMonitorIdMap = tx.read(id).get();
167 if (interfaceMonitorIdMap.isPresent()) {
168 InterfaceMonitorId interfaceMonitorIdInstance = interfaceMonitorIdMap.get();
169 List<Uint32> existingMonitorIds = interfaceMonitorIdInstance.getMonitorId();
170 if (existingMonitorIds != null && existingMonitorIds.contains(monitorId)) {
171 existingMonitorIds.remove(monitorId);
172 InterfaceMonitorIdBuilder interfaceMonitorIdBuilder = new InterfaceMonitorIdBuilder();
173 interfaceMonitorIdInstance = interfaceMonitorIdBuilder.withKey(new InterfaceMonitorIdKey(infName))
174 .setMonitorId(existingMonitorIds).build();
175 tx.mergeParentStructureMerge(id, interfaceMonitorIdInstance);
180 private static org.opendaylight.yang.gen.v1
181 .urn.opendaylight.genius.alivenessmonitor
182 .rev160411.endpoint.endpoint.type.Interface getInterfaceForMonitoring(
183 String interfaceName,
184 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress ipAddress) {
185 return new org.opendaylight.yang.gen.v1.urn.opendaylight
186 .genius.alivenessmonitor.rev160411.endpoint.endpoint.type.InterfaceBuilder()
187 .setInterfaceIp(ipAddress).setInterfaceName(interfaceName).build();
190 public void handleTunnelMonitorUpdates(Interface interfaceOld, Interface interfaceNew) {
191 String interfaceName = interfaceNew.getName();
192 IfTunnel ifTunnelNew = interfaceNew.augmentation(IfTunnel.class);
193 if (!lldpMonitoringEnabled(ifTunnelNew)) {
196 LOG.debug("handling tunnel monitoring updates for interface {}", interfaceName);
198 stopLLDPMonitoring(ifTunnelNew, interfaceOld.getName());
199 if (ifTunnelNew.isMonitorEnabled()) {
200 startLLDPMonitoring(ifTunnelNew, interfaceName);
202 // Delete old profile from Aliveness Manager
203 IfTunnel ifTunnelOld = interfaceOld.augmentation(IfTunnel.class);
204 if (!Objects.equals(ifTunnelNew.getMonitorInterval(), ifTunnelOld.getMonitorInterval())) {
205 LOG.debug("deleting older monitor profile for interface {}", interfaceName);
206 Uint32 profileId = allocateProfile(FAILURE_THRESHOLD, ifTunnelOld.getMonitorInterval().toJava(),
207 MONITORING_WINDOW, MonitorProtocolType.Lldp);
208 MonitorProfileDeleteInput profileDeleteInput = new MonitorProfileDeleteInputBuilder()
209 .setProfileId(profileId).build();
211 ListenableFuture<RpcResult<MonitorProfileDeleteOutput>> future =
212 alivenessMonitorService.monitorProfileDelete(profileDeleteInput);
213 LoggingFutures.addErrorLogging(future, LOG, "Delete monitor profile {}", interfaceName);
218 private static void createOrUpdateInterfaceMonitorIdMap(TypedReadWriteTransaction<Operational> tx, String infName,
219 long monitorId) throws ExecutionException, InterruptedException {
220 InterfaceMonitorId interfaceMonitorIdInstance;
221 List<Uint32> existingMonitorIds;
222 InterfaceMonitorIdBuilder interfaceMonitorIdBuilder = new InterfaceMonitorIdBuilder();
223 InstanceIdentifier<InterfaceMonitorId> id = InstanceIdentifier.builder(InterfaceMonitorIdMap.class)
224 .child(InterfaceMonitorId.class, new InterfaceMonitorIdKey(infName)).build();
225 Optional<InterfaceMonitorId> interfaceMonitorIdMap = tx.read(id).get();
226 if (interfaceMonitorIdMap.isPresent()) {
227 interfaceMonitorIdInstance = interfaceMonitorIdMap.get();
228 existingMonitorIds = interfaceMonitorIdInstance.getMonitorId();
229 if (existingMonitorIds == null) {
230 existingMonitorIds = new ArrayList<>();
232 if (!existingMonitorIds.contains(Uint32.valueOf(monitorId))) {
233 existingMonitorIds.add(Uint32.valueOf(monitorId));
234 interfaceMonitorIdInstance = interfaceMonitorIdBuilder.withKey(new InterfaceMonitorIdKey(infName))
235 .setMonitorId(existingMonitorIds).build();
236 tx.mergeParentStructureMerge(id, interfaceMonitorIdInstance);
239 existingMonitorIds = new ArrayList<>();
240 existingMonitorIds.add(Uint32.valueOf(monitorId));
241 interfaceMonitorIdInstance = interfaceMonitorIdBuilder.setMonitorId(existingMonitorIds)
242 .withKey(new InterfaceMonitorIdKey(infName)).setInterfaceName(infName).build();
243 tx.mergeParentStructureMerge(id, interfaceMonitorIdInstance);
247 private static void createOrUpdateMonitorIdInterfaceMap(TypedReadWriteTransaction<Operational> tx, String infName,
248 long monitorId) throws ExecutionException, InterruptedException {
249 MonitorIdInterface monitorIdInterfaceInstance;
250 String existinginterfaceName;
251 MonitorIdInterfaceBuilder monitorIdInterfaceBuilder = new MonitorIdInterfaceBuilder();
252 InstanceIdentifier<MonitorIdInterface> id = InstanceIdentifier.builder(MonitorIdInterfaceMap.class)
253 .child(MonitorIdInterface.class, new MonitorIdInterfaceKey(monitorId)).build();
254 Optional<MonitorIdInterface> monitorIdInterfaceMap = tx.read(id).get();
255 if (monitorIdInterfaceMap.isPresent()) {
256 monitorIdInterfaceInstance = monitorIdInterfaceMap.get();
257 existinginterfaceName = monitorIdInterfaceInstance.getInterfaceName();
258 if (!Objects.equals(existinginterfaceName, infName)) {
259 monitorIdInterfaceInstance = monitorIdInterfaceBuilder.withKey(new MonitorIdInterfaceKey(monitorId))
260 .setInterfaceName(infName).build();
261 tx.mergeParentStructureMerge(id, monitorIdInterfaceInstance);
264 monitorIdInterfaceInstance = monitorIdInterfaceBuilder.setMonitorId(monitorId)
265 .withKey(new MonitorIdInterfaceKey(monitorId)).setInterfaceName(infName).build();
266 tx.mergeParentStructureMerge(id, monitorIdInterfaceInstance);
270 private static List<Uint32> getMonitorIdForInterface(TypedReadTransaction<Operational> tx, String infName)
271 throws ExecutionException, InterruptedException {
272 InstanceIdentifier<InterfaceMonitorId> id = InstanceIdentifier.builder(InterfaceMonitorIdMap.class)
273 .child(InterfaceMonitorId.class, new InterfaceMonitorIdKey(infName)).build();
274 return tx.read(id).get().map(InterfaceMonitorId::getMonitorId).orElse(null);
277 public Uint32 createMonitorProfile(MonitorProfileCreateInput monitorProfileCreateInput) {
279 Future<RpcResult<MonitorProfileCreateOutput>> result = alivenessMonitorService
280 .monitorProfileCreate(monitorProfileCreateInput);
281 RpcResult<MonitorProfileCreateOutput> rpcResult = result.get();
282 if (rpcResult.isSuccessful()) {
283 return rpcResult.getResult().getProfileId();
285 LOG.warn("RPC Call to Get Profile Id Id returned with Errors {}.. Trying to fetch existing profile ID",
286 rpcResult.getErrors());
287 Profile createProfile = monitorProfileCreateInput.getProfile();
288 Future<RpcResult<MonitorProfileGetOutput>> existingProfile = alivenessMonitorService.monitorProfileGet(
289 buildMonitorGetProfile(createProfile.getMonitorInterval().toJava(),
290 createProfile.getMonitorWindow().toJava(),
291 createProfile.getFailureThreshold().toJava(), createProfile.getProtocolType()));
292 RpcResult<MonitorProfileGetOutput> rpcGetResult = existingProfile.get();
293 if (rpcGetResult.isSuccessful()) {
294 return rpcGetResult.getResult().getProfileId();
296 LOG.warn("RPC Call to Get Existing Profile Id returned with Errors {}", rpcGetResult.getErrors());
299 } catch (InterruptedException | ExecutionException e) {
300 LOG.warn("Exception when allocating profile Id", e);
302 return Uint32.valueOf(0);
305 private static MonitorProfileGetInput buildMonitorGetProfile(long monitorInterval, long monitorWindow,
306 long failureThreshold, MonitorProtocolType protocolType) {
307 org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor
308 .rev160411.monitor.profile.get.input.ProfileBuilder profileBuilder =
309 new org.opendaylight.yang.gen.v1.urn.opendaylight
310 .genius.alivenessmonitor.rev160411.monitor.profile.get.input.ProfileBuilder();
312 profileBuilder.setFailureThreshold(failureThreshold);
313 profileBuilder.setMonitorInterval(monitorInterval);
314 profileBuilder.setMonitorWindow(monitorWindow);
315 profileBuilder.setProtocolType(protocolType);
316 MonitorProfileGetInputBuilder buildGetProfile = new MonitorProfileGetInputBuilder();
317 buildGetProfile.setProfile(profileBuilder.build());
318 return buildGetProfile.build();
321 public Uint32 allocateProfile(long failureThreshold, long monitoringInterval, long monitoringWindow,
322 MonitorProtocolType protoType) {
323 MonitorProfileCreateInput input = new MonitorProfileCreateInputBuilder().setProfile(
324 new ProfileBuilder().setFailureThreshold(failureThreshold).setMonitorInterval(monitoringInterval)
325 .setMonitorWindow(monitoringWindow).setProtocolType(protoType).build())
327 return createMonitorProfile(input);
330 public static boolean lldpMonitoringEnabled(IfTunnel ifTunnel) {
331 return ifTunnel.isInternal() && ifTunnel.isMonitorEnabled()
332 && TunnelMonitoringTypeLldp.class.isAssignableFrom(ifTunnel.getMonitorProtocol());