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.Preconditions;
13 import com.google.common.collect.ImmutableList;
14 import com.google.common.collect.Iterators;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import com.google.common.util.concurrent.SettableFuture;
19 import io.netty.util.Timeout;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Optional;
26 import javax.annotation.CheckForNull;
27 import javax.annotation.Nonnull;
28 import javax.annotation.Nullable;
29 import javax.annotation.concurrent.GuardedBy;
30 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
31 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
32 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
33 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
34 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
35 import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleConductor;
36 import org.opendaylight.openflowplugin.api.openflow.rpc.listener.ItemLifecycleListener;
37 import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext;
38 import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
39 import org.opendaylight.openflowplugin.impl.rpc.listener.ItemLifecycleListenerImpl;
40 import org.opendaylight.openflowplugin.impl.services.RequestContextUtil;
41 import org.opendaylight.openflowplugin.impl.statistics.services.dedicated.StatisticsGatheringOnTheFlyService;
42 import org.opendaylight.openflowplugin.impl.statistics.services.dedicated.StatisticsGatheringService;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
47 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 private volatile boolean schedulingEnabled;
68 StatisticsContextImpl(@CheckForNull final DeviceInfo deviceInfo, final boolean shuttingDownStatisticsPolling, final LifecycleConductor lifecycleConductor) {
69 this.deviceContext = Preconditions.checkNotNull(lifecycleConductor.getDeviceContext(deviceInfo));
70 this.devState = Preconditions.checkNotNull(deviceContext.getDeviceState());
71 this.shuttingDownStatisticsPolling = shuttingDownStatisticsPolling;
72 emptyFuture = Futures.immediateFuture(false);
73 statisticsGatheringService = new StatisticsGatheringService(this, deviceContext);
74 statisticsGatheringOnTheFlyService = new StatisticsGatheringOnTheFlyService(this, deviceContext);
75 itemLifeCycleListener = new ItemLifecycleListenerImpl(deviceContext);
76 statListForCollectingInitialization();
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);
109 public ListenableFuture<Boolean> initialGatherDynamicData() {
110 return gatherDynamicData(true);
114 public ListenableFuture<Boolean> gatherDynamicData(){
115 return gatherDynamicData(false);
118 private ListenableFuture<Boolean> gatherDynamicData(final boolean initial) {
119 if (shuttingDownStatisticsPolling) {
120 LOG.debug("Statistics for device {} is not enabled.", deviceContext.getDeviceInfo().getNodeId());
121 return Futures.immediateFuture(Boolean.TRUE);
123 final ListenableFuture<Boolean> errorResultFuture = deviceConnectionCheck();
124 if (errorResultFuture != null) {
125 return errorResultFuture;
127 synchronized (COLLECTION_STAT_TYPE_LOCK) {
128 final Iterator<MultipartType> statIterator = collectingStatType.iterator();
129 final SettableFuture<Boolean> settableStatResultFuture = SettableFuture.create();
131 // write start timestamp to state snapshot container
132 StatisticsGatheringUtils.markDeviceStateSnapshotStart(deviceContext);
134 statChainFuture(statIterator, settableStatResultFuture, initial);
136 // write end timestamp to state snapshot container
137 Futures.addCallback(settableStatResultFuture, new FutureCallback<Boolean>() {
139 public void onSuccess(@Nullable final Boolean result) {
140 StatisticsGatheringUtils.markDeviceStateSnapshotEnd(deviceContext, true);
143 public void onFailure(final Throwable t) {
144 StatisticsGatheringUtils.markDeviceStateSnapshotEnd(deviceContext, false);
147 return settableStatResultFuture;
151 private ListenableFuture<Boolean> chooseStat(final MultipartType multipartType, final boolean initial){
152 switch (multipartType) {
154 return collectFlowStatistics(multipartType, initial);
156 return collectTableStatistics(multipartType);
158 return collectPortStatistics(multipartType);
160 return collectQueueStatistics(multipartType);
162 return collectGroupDescStatistics(multipartType);
164 return collectGroupStatistics(multipartType);
165 case OFPMPMETERCONFIG:
166 return collectMeterConfigStatistics(multipartType);
168 return collectMeterStatistics(multipartType);
170 LOG.warn("Unsuported Statistics type {}", multipartType);
171 return Futures.immediateCheckedFuture(Boolean.TRUE);
177 public <T> RequestContext<T> createRequestContext() {
178 final AbstractRequestContext<T> ret = new AbstractRequestContext<T>(deviceContext.reserveXidForDeviceMessage()) {
180 public void close() {
181 requestContexts.remove(this);
184 requestContexts.add(ret);
189 public void close() {
190 schedulingEnabled = false;
191 for (final Iterator<RequestContext<?>> iterator = Iterators.consumingIterator(requestContexts.iterator());
192 iterator.hasNext();) {
193 RequestContextUtil.closeRequestContextWithRpcError(iterator.next(), CONNECTION_CLOSED);
195 if (null != pollTimeout && !pollTimeout.isExpired()) {
196 pollTimeout.cancel();
201 public void setSchedulingEnabled(final boolean schedulingEnabled) {
202 this.schedulingEnabled = schedulingEnabled;
206 public boolean isSchedulingEnabled() {
207 return schedulingEnabled;
211 public void setPollTimeout(final Timeout pollTimeout) {
212 this.pollTimeout = pollTimeout;
216 public Optional<Timeout> getPollTimeout() {
217 return Optional.ofNullable(pollTimeout);
220 private void statChainFuture(final Iterator<MultipartType> iterator, final SettableFuture<Boolean> resultFuture, final boolean initial) {
221 if (ConnectionContext.CONNECTION_STATE.RIP.equals(deviceContext.getPrimaryConnectionContext().getConnectionState())) {
222 final String errMsg = String.format("Device connection is closed for Node : %s.",
223 deviceContext.getDeviceInfo().getNodeId());
225 resultFuture.setException(new IllegalStateException(errMsg));
228 if ( ! iterator.hasNext()) {
229 resultFuture.set(Boolean.TRUE);
230 LOG.debug("Stats collection successfully finished for node {}", deviceContext.getDeviceInfo().getNodeId());
234 final MultipartType nextType = iterator.next();
235 LOG.debug("Stats iterating to next type for node {} of type {}", deviceContext.getDeviceInfo().getNodeId(), nextType);
237 final ListenableFuture<Boolean> deviceStatisticsCollectionFuture = chooseStat(nextType, initial);
238 Futures.addCallback(deviceStatisticsCollectionFuture, new FutureCallback<Boolean>() {
240 public void onSuccess(final Boolean result) {
241 statChainFuture(iterator, resultFuture, initial);
244 public void onFailure(@Nonnull final Throwable t) {
245 resultFuture.setException(t);
251 * Method checks a device state. It returns null for be able continue. Otherwise it returns immediateFuture
252 * which has to be returned from caller too
257 ListenableFuture<Boolean> deviceConnectionCheck() {
258 if (!ConnectionContext.CONNECTION_STATE.WORKING.equals(deviceContext.getPrimaryConnectionContext().getConnectionState())) {
259 ListenableFuture<Boolean> resultingFuture;
260 switch (deviceContext.getPrimaryConnectionContext().getConnectionState()) {
262 final String errMsg = String.format("Device connection doesn't exist anymore. Primary connection status : %s",
263 deviceContext.getPrimaryConnectionContext().getConnectionState());
264 resultingFuture = Futures.immediateFailedFuture(new Throwable(errMsg));
267 resultingFuture = Futures.immediateCheckedFuture(Boolean.TRUE);
270 return resultingFuture;
275 //TODO: Refactor twice sending deviceContext into gatheringStatistics
276 private ListenableFuture<Boolean> collectFlowStatistics(final MultipartType multipartType, final boolean initial) {
277 return devState.isFlowStatisticsAvailable() ? StatisticsGatheringUtils.gatherStatistics(
278 statisticsGatheringOnTheFlyService,
279 deviceContext.getDeviceInfo(),
280 /*MultipartType.OFPMPFLOW*/ multipartType,
283 initial) : emptyFuture;
286 private ListenableFuture<Boolean> collectTableStatistics(final MultipartType multipartType) {
287 return devState.isTableStatisticsAvailable() ? StatisticsGatheringUtils.gatherStatistics(
288 statisticsGatheringService,
289 deviceContext.getDeviceInfo(),
290 /*MultipartType.OFPMPTABLE*/ multipartType,
293 false) : emptyFuture;
296 private ListenableFuture<Boolean> collectPortStatistics(final MultipartType multipartType) {
297 return devState.isPortStatisticsAvailable() ? StatisticsGatheringUtils.gatherStatistics(
298 statisticsGatheringService,
299 deviceContext.getDeviceInfo(),
300 /*MultipartType.OFPMPPORTSTATS*/ multipartType,
303 false) : emptyFuture;
306 private ListenableFuture<Boolean> collectQueueStatistics(final MultipartType multipartType) {
307 return !devState.isQueueStatisticsAvailable() ? emptyFuture : StatisticsGatheringUtils.gatherStatistics(
308 statisticsGatheringService,
309 deviceContext.getDeviceInfo(),
310 /*MultipartType.OFPMPQUEUE*/ multipartType,
316 private ListenableFuture<Boolean> collectGroupDescStatistics(final MultipartType multipartType) {
317 return devState.isGroupAvailable() ? StatisticsGatheringUtils.gatherStatistics(
318 statisticsGatheringService,
319 deviceContext.getDeviceInfo(),
320 /*MultipartType.OFPMPGROUPDESC*/ multipartType,
323 false) : emptyFuture;
326 private ListenableFuture<Boolean> collectGroupStatistics(final MultipartType multipartType) {
327 return devState.isGroupAvailable() ? StatisticsGatheringUtils.gatherStatistics(
328 statisticsGatheringService,
329 deviceContext.getDeviceInfo(),
330 /*MultipartType.OFPMPGROUP*/ multipartType,
333 false) : emptyFuture;
336 private ListenableFuture<Boolean> collectMeterConfigStatistics(final MultipartType multipartType) {
337 return devState.isMetersAvailable() ? StatisticsGatheringUtils.gatherStatistics(
338 statisticsGatheringService,
339 deviceContext.getDeviceInfo(),
340 /*MultipartType.OFPMPMETERCONFIG*/ multipartType,
343 false) : emptyFuture;
346 private ListenableFuture<Boolean> collectMeterStatistics(final MultipartType multipartType) {
347 return devState.isMetersAvailable() ? StatisticsGatheringUtils.gatherStatistics(
348 statisticsGatheringService,
349 deviceContext.getDeviceInfo(),
350 /*MultipartType.OFPMPMETER*/ multipartType,
353 false) : emptyFuture;
357 void setStatisticsGatheringService(final StatisticsGatheringService statisticsGatheringService) {
358 this.statisticsGatheringService = statisticsGatheringService;
362 void setStatisticsGatheringOnTheFlyService(final StatisticsGatheringOnTheFlyService
363 statisticsGatheringOnTheFlyService) {
364 this.statisticsGatheringOnTheFlyService = statisticsGatheringOnTheFlyService;
368 public ItemLifecycleListener getItemLifeCycleListener () {
369 return itemLifeCycleListener;