2 * Copyright (c) 2015 Cisco Systems, Inc. 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
9 package org.opendaylight.openflowplugin.impl.statistics;
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.collect.Iterators;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import com.google.common.util.concurrent.SettableFuture;
20 import io.netty.util.Timeout;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.List;
26 import javax.annotation.CheckForNull;
27 import javax.annotation.Nullable;
28 import javax.annotation.concurrent.GuardedBy;
29 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
30 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
31 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
32 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
33 import org.opendaylight.openflowplugin.api.openflow.rpc.listener.ItemLifecycleListener;
34 import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext;
35 import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
36 import org.opendaylight.openflowplugin.impl.rpc.listener.ItemLifecycleListenerImpl;
37 import org.opendaylight.openflowplugin.impl.services.RequestContextUtil;
38 import org.opendaylight.openflowplugin.impl.statistics.services.dedicated.StatisticsGatheringOnTheFlyService;
39 import org.opendaylight.openflowplugin.impl.statistics.services.dedicated.StatisticsGatheringService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 * Created by Martin Bobak <mbobak@cisco.com> on 1.4.2015.
47 public class StatisticsContextImpl implements StatisticsContext {
49 private static final Logger LOG = LoggerFactory.getLogger(StatisticsContextImpl.class);
50 private static final String CONNECTION_CLOSED = "Connection closed.";
52 private final ItemLifecycleListener itemLifeCycleListener;
53 private final Collection<RequestContext<?>> requestContexts = new HashSet<>();
54 private final DeviceContext deviceContext;
55 private final DeviceState devState;
56 private final ListenableFuture<Boolean> emptyFuture;
57 private final boolean shuttingDownStatisticsPolling;
58 private final Object COLLECTION_STAT_TYPE_LOCK = new Object();
59 @GuardedBy("COLLECTION_STAT_TYPE_LOCK")
60 private List<MultipartType> collectingStatType;
62 private StatisticsGatheringService statisticsGatheringService;
63 private StatisticsGatheringOnTheFlyService statisticsGatheringOnTheFlyService;
64 private Timeout pollTimeout;
66 public StatisticsContextImpl(@CheckForNull final DeviceContext deviceContext,
67 final boolean shuttingDownStatisticsPolling) {
68 this.deviceContext = Preconditions.checkNotNull(deviceContext);
69 this.devState = Preconditions.checkNotNull(deviceContext.getDeviceState());
70 this.shuttingDownStatisticsPolling = shuttingDownStatisticsPolling;
71 emptyFuture = Futures.immediateFuture(new Boolean(false));
72 statisticsGatheringService = new StatisticsGatheringService(this, deviceContext);
73 statisticsGatheringOnTheFlyService = new StatisticsGatheringOnTheFlyService(this, deviceContext);
74 itemLifeCycleListener = new ItemLifecycleListenerImpl(deviceContext);
75 statListForCollectingInitialization();
76 this.deviceContext.setStatisticsContext(StatisticsContextImpl.this);
80 public void statListForCollectingInitialization() {
81 synchronized (COLLECTION_STAT_TYPE_LOCK) {
82 final List<MultipartType> statListForCollecting = new ArrayList<>();
83 if (devState.isTableStatisticsAvailable()) {
84 statListForCollecting.add(MultipartType.OFPMPTABLE);
86 if (devState.isFlowStatisticsAvailable()) {
87 statListForCollecting.add(MultipartType.OFPMPFLOW);
89 if (devState.isGroupAvailable()) {
90 statListForCollecting.add(MultipartType.OFPMPGROUPDESC);
91 statListForCollecting.add(MultipartType.OFPMPGROUP);
93 if (devState.isMetersAvailable()) {
94 statListForCollecting.add(MultipartType.OFPMPMETERCONFIG);
95 statListForCollecting.add(MultipartType.OFPMPMETER);
97 if (devState.isPortStatisticsAvailable()) {
98 statListForCollecting.add(MultipartType.OFPMPPORTSTATS);
100 if (devState.isQueueStatisticsAvailable()) {
101 statListForCollecting.add(MultipartType.OFPMPQUEUE);
103 collectingStatType = ImmutableList.<MultipartType>copyOf(statListForCollecting);
108 public ListenableFuture<Boolean> gatherDynamicData() {
109 if (shuttingDownStatisticsPolling) {
110 LOG.debug("Statistics for device {} is not enabled.", deviceContext.getDeviceState().getNodeId());
111 return Futures.immediateFuture(Boolean.TRUE);
113 final ListenableFuture<Boolean> errorResultFuture = deviceConnectionCheck();
114 if (errorResultFuture != null) {
115 return errorResultFuture;
117 synchronized (COLLECTION_STAT_TYPE_LOCK) {
118 final Iterator<MultipartType> statIterator = collectingStatType.iterator();
119 final SettableFuture<Boolean> settableStatResultFuture = SettableFuture.create();
121 // write start timestamp to state snapshot container
122 StatisticsGatheringUtils.markDeviceStateSnapshotStart(deviceContext);
124 statChainFuture(statIterator, settableStatResultFuture);
126 // write end timestamp to state snapshot container
127 Futures.addCallback(settableStatResultFuture, new FutureCallback<Boolean>() {
129 public void onSuccess(@Nullable final Boolean result) {
130 StatisticsGatheringUtils.markDeviceStateSnapshotEnd(deviceContext, true);
133 public void onFailure(final Throwable t) {
134 StatisticsGatheringUtils.markDeviceStateSnapshotEnd(deviceContext, false);
137 return settableStatResultFuture;
141 private ListenableFuture<Boolean> chooseStat(final MultipartType multipartType){
142 switch (multipartType) {
144 return collectFlowStatistics(multipartType);
146 return collectTableStatistics(multipartType);
148 return collectPortStatistics(multipartType);
150 return collectQueueStatistics(multipartType);
152 return collectGroupDescStatistics(multipartType);
154 return collectGroupStatistics(multipartType);
155 case OFPMPMETERCONFIG:
156 return collectMeterConfigStatistics(multipartType);
158 return collectMeterStatistics(multipartType);
160 LOG.warn("Unsuported Statistics type {}", multipartType);
161 return Futures.immediateCheckedFuture(Boolean.TRUE);
167 public <T> RequestContext<T> createRequestContext() {
168 final AbstractRequestContext<T> ret = new AbstractRequestContext<T>(deviceContext.reservedXidForDeviceMessage()) {
170 public void close() {
171 requestContexts.remove(this);
174 requestContexts.add(ret);
179 public void close() {
180 for (final Iterator<RequestContext<?>> iterator = Iterators.consumingIterator(requestContexts.iterator());
181 iterator.hasNext();) {
182 RequestContextUtil.closeRequestContextWithRpcError(iterator.next(), CONNECTION_CLOSED);
184 if (null != pollTimeout && !pollTimeout.isExpired()) {
185 pollTimeout.cancel();
190 public void setPollTimeout (Timeout pollTimeout){
191 this.pollTimeout = pollTimeout;
195 public Optional<Timeout> getPollTimeout () {
196 return Optional.fromNullable(pollTimeout);
199 void statChainFuture ( final Iterator<MultipartType> iterator, final SettableFuture<Boolean> resultFuture){
201 if (ConnectionContext.CONNECTION_STATE.RIP.equals(deviceContext.getPrimaryConnectionContext().getConnectionState())) {
202 final String errMsg = String.format("Device connection is closed for Node : %s.",
203 deviceContext.getDeviceState().getNodeId());
205 resultFuture.setException(new IllegalStateException(errMsg));
209 if (!iterator.hasNext()) {
210 resultFuture.set(Boolean.TRUE);
211 LOG.debug("Stats collection successfully finished for node {}", deviceContext.getDeviceState().getNodeId());
215 final MultipartType nextType = iterator.next();
216 LOG.debug("Stats iterating to next type for node {} of type {}", deviceContext.getDeviceState().getNodeId(), nextType);
218 final ListenableFuture<Boolean> deviceStatisticsCollectionFuture = chooseStat(nextType);
219 Futures.addCallback(deviceStatisticsCollectionFuture, new FutureCallback<Boolean>() {
221 public void onSuccess(final Boolean result) {
222 statChainFuture(iterator, resultFuture);
226 public void onFailure(final Throwable t) {
227 resultFuture.setException(t);
233 * Method checks a device state. It returns null for be able continue. Otherwise it returns immediateFuture
234 * which has to be returned from caller too
239 ListenableFuture<Boolean> deviceConnectionCheck () {
240 if (!ConnectionContext.CONNECTION_STATE.WORKING.equals(deviceContext.getPrimaryConnectionContext().getConnectionState())) {
241 ListenableFuture<Boolean> resultingFuture = SettableFuture.create();
242 switch (deviceContext.getPrimaryConnectionContext().getConnectionState()) {
244 final String errMsg = String.format("Device connection doesn't exist anymore. Primary connection status : %s",
245 deviceContext.getPrimaryConnectionContext().getConnectionState());
246 resultingFuture = Futures.immediateFailedFuture(new Throwable(errMsg));
249 resultingFuture = Futures.immediateCheckedFuture(Boolean.TRUE);
252 return resultingFuture;
257 private ListenableFuture<Boolean> collectFlowStatistics ( final MultipartType multipartType){
258 return devState.isFlowStatisticsAvailable() ? StatisticsGatheringUtils.gatherStatistics(
259 statisticsGatheringOnTheFlyService, deviceContext, /*MultipartType.OFPMPFLOW*/ multipartType) : emptyFuture;
262 private ListenableFuture<Boolean> collectTableStatistics ( final MultipartType multipartType){
263 return devState.isTableStatisticsAvailable() ? StatisticsGatheringUtils.gatherStatistics(
264 statisticsGatheringService, deviceContext, /*MultipartType.OFPMPTABLE*/ multipartType) : emptyFuture;
267 private ListenableFuture<Boolean> collectPortStatistics ( final MultipartType multipartType){
268 return devState.isPortStatisticsAvailable() ? StatisticsGatheringUtils.gatherStatistics(
269 statisticsGatheringService, deviceContext, /*MultipartType.OFPMPPORTSTATS*/ multipartType) : emptyFuture;
272 private ListenableFuture<Boolean> collectQueueStatistics ( final MultipartType multipartType){
273 return devState.isQueueStatisticsAvailable() ? StatisticsGatheringUtils.gatherStatistics(
274 statisticsGatheringService, deviceContext, /*MultipartType.OFPMPQUEUE*/ multipartType) : emptyFuture;
277 private ListenableFuture<Boolean> collectGroupDescStatistics ( final MultipartType multipartType){
278 return devState.isGroupAvailable() ? StatisticsGatheringUtils.gatherStatistics(
279 statisticsGatheringService, deviceContext, /*MultipartType.OFPMPGROUPDESC*/ multipartType) : emptyFuture;
282 private ListenableFuture<Boolean> collectGroupStatistics ( final MultipartType multipartType){
283 return devState.isGroupAvailable() ? StatisticsGatheringUtils.gatherStatistics(
284 statisticsGatheringService, deviceContext, /*MultipartType.OFPMPGROUP*/ multipartType) : emptyFuture;
287 private ListenableFuture<Boolean> collectMeterConfigStatistics ( final MultipartType multipartType){
288 return devState.isMetersAvailable() ? StatisticsGatheringUtils.gatherStatistics(
289 statisticsGatheringService, deviceContext, /*MultipartType.OFPMPMETERCONFIG*/ multipartType) : emptyFuture;
292 private ListenableFuture<Boolean> collectMeterStatistics ( final MultipartType multipartType){
293 return devState.isMetersAvailable() ? StatisticsGatheringUtils.gatherStatistics(
294 statisticsGatheringService, deviceContext, /*MultipartType.OFPMPMETER*/ multipartType) : emptyFuture;
298 protected void setStatisticsGatheringService(final StatisticsGatheringService statisticsGatheringService) {
299 this.statisticsGatheringService = statisticsGatheringService;
303 protected void setStatisticsGatheringOnTheFlyService(final StatisticsGatheringOnTheFlyService
304 statisticsGatheringOnTheFlyService) {
305 this.statisticsGatheringOnTheFlyService = statisticsGatheringOnTheFlyService;
309 public ItemLifecycleListener getItemLifeCycleListener () {
310 return itemLifeCycleListener;
315 public DeviceContext getDeviceContext() {
316 return deviceContext;