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.mdsal.binding.util.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.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;
69 public final class AlivenessMonitorUtils {
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();
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, ifTunnel.getMonitorInterval(),
95 MONITORING_WINDOW, MonitorProtocolType.Lldp))
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");
110 LOG.warn("RPC Call to start monitoring returned with Errors {}", rpcResult.getErrors());
112 } catch (InterruptedException | ExecutionException e) {
113 LOG.warn("Exception when starting monitoring", e);
118 public void stopLLDPMonitoring(IfTunnel ifTunnel, String trunkInterface) {
119 if (!lldpMonitoringEnabled(ifTunnel)) {
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);
129 for (Uint32 monitorId : monitorIds) {
130 String interfaceName = getInterfaceFromMonitorId(tx, monitorId);
131 if (interfaceName != null) {
132 MonitorStopInput input = new MonitorStopInputBuilder().setMonitorId(monitorId).build();
134 ListenableFuture<RpcResult<MonitorStopOutput>> future = alivenessMonitorService.monitorStop(input);
135 LoggingFutures.addErrorLogging(future, LOG, "Stop LLDP monitoring for {}", trunkInterface);
137 removeMonitorIdInterfaceMap(tx, monitorId);
138 removeMonitorIdFromInterfaceMonitorIdMap(tx, interfaceName, monitorId);
142 }), LOG, "Error stopping LLDP monitoring for {}", trunkInterface);
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);
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()) {
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);
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();
189 public void handleTunnelMonitorUpdates(Interface interfaceOld, Interface interfaceNew) {
190 String interfaceName = interfaceNew.getName();
191 IfTunnel ifTunnelNew = interfaceNew.augmentation(IfTunnel.class);
192 if (!lldpMonitoringEnabled(ifTunnelNew)) {
195 LOG.debug("handling tunnel monitoring updates for interface {}", interfaceName);
197 stopLLDPMonitoring(ifTunnelNew, interfaceOld.getName());
198 if (ifTunnelNew.isMonitorEnabled()) {
199 startLLDPMonitoring(ifTunnelNew, interfaceName);
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();
210 ListenableFuture<RpcResult<MonitorProfileDeleteOutput>> future =
211 alivenessMonitorService.monitorProfileDelete(profileDeleteInput);
212 LoggingFutures.addErrorLogging(future, LOG, "Delete monitor profile {}", interfaceName);
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<>();
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);
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);
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);
263 monitorIdInterfaceInstance = monitorIdInterfaceBuilder.setMonitorId(monitorId)
264 .withKey(new MonitorIdInterfaceKey(monitorId)).setInterfaceName(infName).build();
265 tx.mergeParentStructureMerge(id, monitorIdInterfaceInstance);
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);
276 public Uint32 createMonitorProfile(MonitorProfileCreateInput monitorProfileCreateInput) {
278 Future<RpcResult<MonitorProfileCreateOutput>> result = alivenessMonitorService
279 .monitorProfileCreate(monitorProfileCreateInput);
280 RpcResult<MonitorProfileCreateOutput> rpcResult = result.get();
281 if (rpcResult.isSuccessful()) {
282 return rpcResult.getResult().getProfileId();
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();
294 LOG.warn("RPC Call to Get Existing Profile Id returned with Errors {}", rpcGetResult.getErrors());
297 } catch (InterruptedException | ExecutionException e) {
298 LOG.warn("Exception when allocating profile Id", e);
300 return Uint32.valueOf(0);
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)
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())
322 return createMonitorProfile(input);
325 public static boolean lldpMonitoringEnabled(IfTunnel ifTunnel) {
326 return ifTunnel.isInternal() && ifTunnel.isMonitorEnabled()
327 && TunnelMonitoringTypeLldp.class.isAssignableFrom(ifTunnel.getMonitorProtocol());