2 * Copyright (c) 2016 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.itm.monitoring;
10 import com.google.common.util.concurrent.ListenableFuture;
11 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
12 import java.util.Collections;
13 import java.util.List;
14 import java.util.Objects;
15 import java.util.concurrent.Callable;
16 import javax.annotation.PreDestroy;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import javax.management.JMException;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.genius.infra.Datastore;
22 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
23 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
24 import org.opendaylight.genius.itm.cache.UnprocessedTunnelsStateCache;
25 import org.opendaylight.genius.itm.globals.ITMConstants;
26 import org.opendaylight.genius.itm.impl.ItmUtils;
27 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
28 import org.opendaylight.mdsal.binding.api.DataBroker;
29 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
30 import org.opendaylight.serviceutils.tools.listener.AbstractSyncDataTreeChangeListener;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelOperStatus;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnel;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListBuilder;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.opendaylight.yangtools.yang.common.Uint64;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 public class ItmTunnelEventListener extends AbstractSyncDataTreeChangeListener<StateTunnelList> {
45 private static final Logger LOG = LoggerFactory.getLogger(ItmTunnelEventListener.class);
47 private final DataBroker broker;
48 private final JobCoordinator jobCoordinator;
49 private final ManagedNewTransactionRunner txRunner;
50 private JMXAlarmAgent alarmAgent;
51 private final UnprocessedTunnelsStateCache unprocessedTunnelsStateCache;
54 public ItmTunnelEventListener(DataBroker dataBroker, JobCoordinator jobCoordinator,
55 UnprocessedTunnelsStateCache unprocessedTunnelsStateCache) {
56 super(dataBroker, LogicalDatastoreType.OPERATIONAL,
57 InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class));
58 this.broker = dataBroker;
59 this.jobCoordinator = jobCoordinator;
60 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
61 this.unprocessedTunnelsStateCache = unprocessedTunnelsStateCache;
63 alarmAgent = new JMXAlarmAgent();
64 alarmAgent.registerMbean();
65 } catch (JMException e) {
66 LOG.error("Can not initialize the Alarm agent", e);
70 @SuppressWarnings("checkstyle:IllegalCatch")
75 if (alarmAgent != null) {
76 alarmAgent.unregisterMbean();
78 } catch (final Exception e) {
79 LOG.error("Error when cleaning up DataChangeListener.", e);
84 public void remove(@NonNull InstanceIdentifier<StateTunnelList> instanceIdentifier,
85 @NonNull StateTunnelList stateTunnelList) {
86 LOG.trace("Tunnel Interface remove: {}", stateTunnelList.getTunnelInterfaceName());
87 ItmTunnelRemoveAlarmWorker itmTunnelRemoveAlarmWorker = new ItmTunnelRemoveAlarmWorker(stateTunnelList);
88 // For now, its all queued in one queue. If any delay in alarm being raised, queue based on interface Name
89 jobCoordinator.enqueueJob(ITMConstants.ITM_ALARM, itmTunnelRemoveAlarmWorker);
90 unprocessedTunnelsStateCache.remove(stateTunnelList.getTunnelInterfaceName());
94 public void update(@NonNull InstanceIdentifier<StateTunnelList> instanceIdentifier,
95 @NonNull StateTunnelList originalTunnelList, @NonNull StateTunnelList updatedTunnelList) {
96 LOG.trace("Tunnel Interface updated. Old: {} New: {}", originalTunnelList, updatedTunnelList);
97 TunnelOperStatus operStatus = updatedTunnelList.getOperState();
98 if (!Objects.equals(originalTunnelList.getOperState(), updatedTunnelList.getOperState())) {
99 LOG.debug("Tunnel Interface {} changed state to {}", originalTunnelList.getTunnelInterfaceName(),
101 ItmTunnelUpdateAlarmWorker itmTunnelUpdateAlarmWorker = new ItmTunnelUpdateAlarmWorker(originalTunnelList,
103 jobCoordinator.enqueueJob(ITMConstants.ITM_ALARM, itmTunnelUpdateAlarmWorker);
108 public void add(@NonNull InstanceIdentifier<StateTunnelList> instanceIdentifier,
109 @NonNull StateTunnelList stateTunnelList) {
110 LOG.debug("Tunnel Interface of type Tunnel added: {}", stateTunnelList.getTunnelInterfaceName());
111 ItmTunnelAddAlarmWorker itmTunnelAddAlarmWorker = new ItmTunnelAddAlarmWorker(stateTunnelList);
112 // For now, its all queued in one queue. If any delay in alarm being raised, queue based on interface Name
113 jobCoordinator.enqueueJob(ITMConstants.ITM_ALARM, itmTunnelAddAlarmWorker);
114 TunnelOperStatus operStatus = unprocessedTunnelsStateCache.remove(stateTunnelList.getTunnelInterfaceName());
115 if (operStatus != null) {
116 if (operStatus != stateTunnelList.getOperState()) {
117 jobCoordinator.enqueueJob(stateTunnelList.getTunnelInterfaceName(),
118 new ItmTunnelStatusOutOfOrderEventWorker(instanceIdentifier, stateTunnelList, operStatus,
121 LOG.debug("BFD status in unprocessed cache is the same as in DTCN for {} "
122 + "hence no operations ",stateTunnelList.getTunnelInterfaceName());
125 LOG.debug("No Unprocessed tunnel state for {} ", stateTunnelList.getTunnelInterfaceName());
129 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
130 justification = "https://github.com/spotbugs/spotbugs/issues/811")
131 private void raiseInternalDataPathAlarm(String srcDpnId, String dstDpnId, String tunnelType, String alarmText) {
132 StringBuilder source = new StringBuilder();
133 source.append("srcDpn=openflow:").append(srcDpnId).append("-dstDpn=openflow:").append(dstDpnId)
134 .append("-tunnelType").append(tunnelType);
136 LOG.trace("Raising DataPathConnectionFailure alarm... alarmText {} source {} ", alarmText, source);
137 // Invokes JMX raiseAlarm method
138 if (alarmAgent != null) {
139 alarmAgent.invokeFMraisemethod("DataPathConnectionFailure", alarmText, source.toString());
143 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
144 justification = "https://github.com/spotbugs/spotbugs/issues/811")
145 private void clearInternalDataPathAlarm(String srcDpnId, String dstDpnId, String tunnelType, String alarmText) {
146 StringBuilder source = new StringBuilder();
148 source.append("srcDpn=openflow:").append(srcDpnId).append("-dstDpn=openflow:").append(dstDpnId)
149 .append("-tunnelType").append(tunnelType);
150 LOG.trace("Clearing DataPathConnectionFailure alarm of source {} alarmText {} ", source, alarmText);
151 // Invokes JMX clearAlarm method
152 if (alarmAgent != null) {
153 alarmAgent.invokeFMclearmethod("DataPathConnectionFailure", alarmText, source.toString());
157 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
158 justification = "https://github.com/spotbugs/spotbugs/issues/811")
159 private void raiseExternalDataPathAlarm(String srcDevice, String dstDevice, String tunnelType, String alarmText) {
161 StringBuilder source = new StringBuilder();
162 source.append("srcDevice=").append(srcDevice).append("-dstDevice=").append(dstDevice).append("-tunnelType")
165 LOG.trace("Raising DataPathConnectionFailure alarm... alarmText {} source {} ", alarmText, source);
166 // Invokes JMX raiseAlarm method
167 if (alarmAgent != null) {
168 alarmAgent.invokeFMraisemethod("DataPathConnectionFailure", alarmText, source.toString());
172 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
173 justification = "https://github.com/spotbugs/spotbugs/issues/811")
174 private void clearExternalDataPathAlarm(String srcDevice, String dstDevice, String tunnelType, String alarmText) {
175 StringBuilder source = new StringBuilder();
176 source.append("srcDevice=").append(srcDevice).append("-dstDevice=").append(dstDevice).append("-tunnelType")
178 LOG.trace("Clearing DataPathConnectionFailure alarm of source {} alarmText {} ", source, alarmText);
179 // Invokes JMX clearAlarm method
180 if (alarmAgent != null) {
181 alarmAgent.invokeFMclearmethod("DataPathConnectionFailure", alarmText, source.toString());
185 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
186 justification = "https://github.com/spotbugs/spotbugs/issues/811")
187 private static boolean isTunnelInterfaceUp(StateTunnelList intf) {
188 return intf.getOperState() == TunnelOperStatus.Up;
191 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
192 justification = "https://github.com/spotbugs/spotbugs/issues/811")
193 private static String getInternalAlarmText(String srcDpId, String dstDpId, String tunnelType) {
194 StringBuilder alarmText = new StringBuilder();
195 alarmText.append("Data Path Connectivity is lost between ").append("openflow:").append(srcDpId)
196 .append(" and openflow:").append(dstDpId).append(" for tunnelType:").append(tunnelType);
197 return alarmText.toString();
200 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
201 justification = "https://github.com/spotbugs/spotbugs/issues/811")
202 private static String getExternalAlarmText(String srcNode, String dstNode, String tunnelType) {
203 StringBuilder alarmText = new StringBuilder();
204 alarmText.append("Data Path Connectivity is lost between ").append(srcNode).append(" and ").append(dstNode)
205 .append(" for tunnelType:").append(tunnelType);
206 return alarmText.toString();
209 private class ItmTunnelAddAlarmWorker implements Callable<List<? extends ListenableFuture<?>>> {
210 private final StateTunnelList add;
212 ItmTunnelAddAlarmWorker(StateTunnelList tnlIface) {
217 public List<ListenableFuture<Void>> call() {
218 String ifName = add.getTunnelInterfaceName();
219 InternalTunnel internalTunnel = ItmUtils.getInternalTunnel(ifName, broker);
220 if (internalTunnel != null) {
221 Uint64 srcDpId = internalTunnel.getSourceDPN();
222 Uint64 dstDpId = internalTunnel.getDestinationDPN();
223 String tunnelType = ItmUtils.convertTunnelTypetoString(internalTunnel.getTransportType());
224 if (!isTunnelInterfaceUp(add)) {
225 LOG.trace("ITM Tunnel State during tep add is DOWN b/w srcDpn: {} and dstDpn: {} for tunnelType: "
226 + "{}", srcDpId, dstDpId, tunnelType);
227 String alarmText = getInternalAlarmText(srcDpId.toString(), dstDpId.toString(), tunnelType);
228 raiseInternalDataPathAlarm(srcDpId.toString(), dstDpId.toString(), tunnelType, alarmText);
231 ExternalTunnel externalTunnel = ItmUtils.getExternalTunnel(ifName, broker);
232 if (externalTunnel != null) {
233 String srcNode = externalTunnel.getSourceDevice();
234 String dstNode = externalTunnel.getDestinationDevice();
235 if (!srcNode.contains("hwvtep")) {
236 srcNode = "openflow:" + externalTunnel.getSourceDevice();
238 if (!dstNode.contains("hwvtep")) {
239 dstNode = "openflow:" + externalTunnel.getDestinationDevice();
241 String tunnelType = ItmUtils.convertTunnelTypetoString(externalTunnel.getTransportType());
242 if (!isTunnelInterfaceUp(add)) {
243 LOG.trace("ITM Tunnel State during tep add is DOWN b/w srcNode: {} and dstNode: {} for "
244 + "tunnelType: {}", srcNode, dstNode, tunnelType);
245 String alarmText = getExternalAlarmText(srcNode, dstNode, tunnelType);
246 raiseExternalDataPathAlarm(srcNode, dstNode, tunnelType, alarmText);
254 private class ItmTunnelRemoveAlarmWorker implements Callable<List<? extends ListenableFuture<?>>> {
255 private final StateTunnelList del;
257 ItmTunnelRemoveAlarmWorker(StateTunnelList tnlIface) {
262 public List<ListenableFuture<Void>> call() {
263 String ifName = del.getTunnelInterfaceName();
264 InternalTunnel internalTunnel = ItmUtils.getInternalTunnel(ifName, broker);
265 if (internalTunnel != null) {
266 Uint64 srcDpId = internalTunnel.getSourceDPN();
267 Uint64 dstDpId = internalTunnel.getDestinationDPN();
268 String tunnelType = ItmUtils.convertTunnelTypetoString(internalTunnel.getTransportType());
269 LOG.trace("ITM Tunnel removed b/w srcDpn: {} and dstDpn: {} for tunnelType: {}", srcDpId, dstDpId,
271 String alarmText = getInternalAlarmText(srcDpId.toString(), dstDpId.toString(), tunnelType);
272 clearInternalDataPathAlarm(srcDpId.toString(), dstDpId.toString(), tunnelType, alarmText);
274 ExternalTunnel externalTunnel = ItmUtils.getExternalTunnel(ifName, broker);
275 if (externalTunnel != null) {
276 String srcNode = externalTunnel.getSourceDevice();
277 String dstNode = externalTunnel.getDestinationDevice();
278 String tunnelType = ItmUtils.convertTunnelTypetoString(externalTunnel.getTransportType());
279 LOG.trace("ITM Tunnel removed b/w srcNode: {} and dstNode: {} for tunnelType: {}", srcNode, dstNode,
281 String alarmText = getExternalAlarmText(srcNode, dstNode, tunnelType);
282 clearExternalDataPathAlarm(srcNode, dstNode, tunnelType, alarmText);
289 private class ItmTunnelUpdateAlarmWorker implements Callable<List<? extends ListenableFuture<?>>> {
290 private final StateTunnelList update;
291 private final StateTunnelList original;
293 ItmTunnelUpdateAlarmWorker(StateTunnelList original, StateTunnelList update) {
294 this.update = update;
295 this.original = original;
299 public List<ListenableFuture<Void>> call() {
300 String ifName = update.getTunnelInterfaceName();
301 InternalTunnel internalTunnel = ItmUtils.getInternalTunnel(ifName, broker);
302 if (internalTunnel != null) {
303 Uint64 srcDpId = internalTunnel.getSourceDPN();
304 Uint64 dstDpId = internalTunnel.getDestinationDPN();
305 String tunnelType = ItmUtils.convertTunnelTypetoString(internalTunnel.getTransportType());
306 if (LOG.isTraceEnabled()) {
307 LOG.trace("ITM Tunnel state event changed from :{} to :{} for Tunnel Interface - {}",
308 isTunnelInterfaceUp(original), isTunnelInterfaceUp(update), ifName);
310 switch (update.getOperState()) {
312 LOG.trace("ITM Tunnel State is UP b/w srcDpn: {} and dstDpn: {} for tunnelType {} ", srcDpId,
313 dstDpId, tunnelType);
314 String alarmText = getInternalAlarmText(srcDpId.toString(), dstDpId.toString(), tunnelType);
315 clearInternalDataPathAlarm(srcDpId.toString(), dstDpId.toString(), tunnelType, alarmText);
319 LOG.trace("ITM Tunnel State is DOWN b/w srcDpn: {} and dstDpn: {}", srcDpId, dstDpId);
320 String alarmText = getInternalAlarmText(srcDpId.toString(), dstDpId.toString(), tunnelType);
321 raiseInternalDataPathAlarm(srcDpId.toString(), dstDpId.toString(), tunnelType, alarmText);
330 // TODO: Uncomment this when tunnel towards DC gateway or HwVtep is supported
331 ExternalTunnel externalTunnel = ItmUtils.getExternalTunnel(ifName,broker);
332 if (externalTunnel != null) {
333 String srcNode = externalTunnel.getSourceDevice();
334 String dstNode = externalTunnel.getDestinationDevice();
335 if (!srcNode.contains("hwvtep")){
336 srcNode = "openflow:" + externalTunnel.getSourceDevice();
338 if (!dstNode.contains("hwvtep")){
339 dstNode = "openflow:" + externalTunnel.getDestinationDevice();
341 String tunnelType = ItmUtils.convertTunnelTypetoString(externalTunnel.getTransportType());
342 logger.trace("ITM Tunnel state event changed from :{} to :{} for Tunnel Interface - {}",
343 isTunnelInterfaceUp(original), isTunnelInterfaceUp(update), ifName);
344 if (isTunnelInterfaceUp(update)) {
345 logger.trace("ITM Tunnel State is UP b/w srcNode: {} and dstNode: {} for tunnelType: {}",
346 srcNode, dstNode, tunnelType);
347 String alarmText = getExternalAlarmText(srcNode, dstNode, tunnelType);
348 clearExternalDataPathAlarm(srcNode, dstNode, tunnelType, alarmText);
350 logger.trace("ITM Tunnel State is DOWN b/w srcNode: {} and dstNode: {}", srcNode, dstNode);
351 String alarmText = getExternalAlarmText(srcNode, dstNode, tunnelType);
352 raiseExternalDataPathAlarm(srcNode, dstNode, tunnelType, alarmText);
360 private static class ItmTunnelStatusOutOfOrderEventWorker implements Callable<List<? extends ListenableFuture<?>>> {
361 private final InstanceIdentifier<StateTunnelList> identifier;
362 private final StateTunnelList add;
363 private final TunnelOperStatus operStatus;
364 private final ManagedNewTransactionRunner txRunner;
366 ItmTunnelStatusOutOfOrderEventWorker(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList add,
367 TunnelOperStatus operStatus,
368 ManagedNewTransactionRunner tx) {
369 this.identifier = identifier;
371 this.operStatus = operStatus;
376 public List<ListenableFuture<Void>> call() throws Exception {
377 // Process any unprocessed interface bfd updates
378 LOG.debug(" Tunnel events are processed out order for {} hence updating it from cache",
379 add.getTunnelInterfaceName());
380 return Collections.singletonList(txRunner
381 .callWithNewWriteOnlyTransactionAndSubmit(Datastore.OPERATIONAL, tx -> tx.merge(identifier,
382 new StateTunnelListBuilder(add).setOperState(operStatus).build(), false)));