import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
import org.opendaylight.openflowplugin.api.openflow.connection.OutboundQueueProvider;
import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceDisconnectedHandler;
+import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.SessionStatistics;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
import org.slf4j.Logger;
@Override
public void closeConnection(boolean propagate) {
+ SessionStatistics.countEvent(nodeId.toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP);
final BigInteger datapathId = featuresReply != null ? featuresReply.getDatapathId() : BigInteger.ZERO;
LOG.debug("Actively closing connection: {}, datapathId:{}.",
connectionAdapter.getRemoteAddress(), datapathId);
@Override
public void onConnectionClosed() {
+ SessionStatistics.countEvent(nodeId.toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_DEVICE);
connectionState = ConnectionContext.CONNECTION_STATE.RIP;
final InetSocketAddress remoteAddress = connectionAdapter.getRemoteAddress();
import org.opendaylight.openflowplugin.impl.connection.listener.HandshakeListenerImpl;
import org.opendaylight.openflowplugin.impl.connection.listener.OpenflowProtocolListenerInitialImpl;
import org.opendaylight.openflowplugin.impl.connection.listener.SystemNotificationsListenerImpl;
+import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.SessionStatistics;
import org.opendaylight.openflowplugin.openflow.md.core.ErrorHandlerSimpleImpl;
import org.opendaylight.openflowplugin.openflow.md.core.HandshakeManagerImpl;
import org.opendaylight.openflowplugin.openflow.md.core.ThreadPoolLoggingExecutor;
import org.opendaylight.openflowplugin.api.openflow.connection.HandshakeContext;
import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceConnectedHandler;
import org.opendaylight.openflowplugin.api.openflow.md.core.HandshakeListener;
+import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.SessionStatistics;
import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput;
import org.slf4j.Logger;
connectionContext.setFeatures(featureOutput);
connectionContext.setNodeId(InventoryDataServiceUtil.nodeIdFromDatapathId(featureOutput.getDatapathId()));
deviceConnectedHandler.deviceConnected(connectionContext);
+ SessionStatistics.countEvent(connectionContext.getNodeId().toString(), SessionStatistics.ConnectionStatus.CONNECTION_CREATED);
}
@Override
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.karaf;
+
+import java.io.PrintStream;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.EventsTimeCounter;
+
+/**
+ * Created by Martin Bobak <mbobak@cisco.com> on 28.5.2015.
+ */
+@Command(scope = "ofp", name = "reset-session-stats", description = "Resets session statistics counters.")
+public class ResetSessionStatsComandProvider extends OsgiCommandSupport {
+
+ @Override
+ protected Object doExecute() throws Exception {
+ PrintStream out = session.getConsole();
+ EventsTimeCounter.resetAllCounters();
+ out.print("Session statistics counters reset.\n");
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.karaf;
+
+import java.io.PrintStream;
+import java.util.List;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageIntelligenceAgency;
+import org.opendaylight.openflowplugin.impl.OpenFlowPluginProviderImpl;
+import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.SessionStatistics;
+
+/**
+ * Created by Martin Bobak <mbobak@cisco.com> on 21.5.2015.
+ */
+
+@Command(scope = "ofp", name = "show-session-stats", description = "Show session statistics.")
+public class ShowSessionStatsCommandProvider extends OsgiCommandSupport {
+
+ @Override
+ protected Object doExecute() throws Exception {
+ PrintStream out = session.getConsole();
+ final List<String> statistics = SessionStatistics.provideStatistics();
+ final StringBuilder result = new StringBuilder();
+ for (String line : statistics) {
+ result.append(line);
+ result.append("\n");
+ }
+ out.print(result.toString());
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.statistics.ofpspecific;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+
+/**
+ * Created by Martin Bobak <mbobak@cisco.com> on 5.6.2015.
+ */
+public class SessionStatistics {
+
+ private static final Map<String, Map<ConnectionStatus, EventCounter>> sessionEvents = new HashMap<>();
+
+ public static void countEvent(final String sessionId, final ConnectionStatus connectionStatus) {
+ Map<ConnectionStatus, EventCounter> sessionsConnectionEvents = getConnectionEvents(sessionId);
+ EventCounter connectionEvent = getConnectionEvent(sessionsConnectionEvents, connectionStatus);
+ connectionEvent.increment();
+ }
+
+ private static EventCounter getConnectionEvent(final Map<ConnectionStatus, EventCounter> sessionsConnectionEvents,
+ final ConnectionStatus connectionStatus) {
+ EventCounter eventCounter = sessionsConnectionEvents.get(connectionStatus);
+ if (null == eventCounter) {
+ eventCounter = new EventCounter();
+ sessionsConnectionEvents.put(connectionStatus, eventCounter);
+ }
+ return eventCounter;
+ }
+
+ private static Map<ConnectionStatus, EventCounter> getConnectionEvents(final String sessionId) {
+ Map<ConnectionStatus, EventCounter> sessionConnectionEvents = sessionEvents.get(sessionId);
+ if (null == sessionConnectionEvents) {
+ sessionConnectionEvents = new HashMap<>();
+ sessionEvents.put(sessionId, sessionConnectionEvents);
+ }
+ return sessionConnectionEvents;
+ }
+
+
+ public static List<String> provideStatistics() {
+ List<String> dump = new ArrayList<>();
+ for (Map.Entry<String, Map<ConnectionStatus, EventCounter>> sessionEntries : sessionEvents.entrySet()) {
+ Map<ConnectionStatus, EventCounter> sessionEvents = sessionEntries.getValue();
+ dump.add(String.format("SESSION : %s", sessionEntries.getKey()));
+ for (Map.Entry<ConnectionStatus, EventCounter> sessionEvent : sessionEvents.entrySet()) {
+ dump.add(String.format(" %s : %d", sessionEvent.getKey().toString(), sessionEvent.getValue().getCount()));
+ }
+ }
+ return dump;
+
+ }
+
+ public enum ConnectionStatus {
+ CONNECTION_CREATED, CONNECTION_DISCONNECTED_BY_DEVICE, CONNECTION_DISCONNECTED_BY_OFP;
+ }
+
+ private static final class EventCounter {
+ private final AtomicLongFieldUpdater<EventCounter> UPDATER = AtomicLongFieldUpdater.newUpdater(EventCounter.class, "count");
+ private volatile long count;
+
+ public long getCount() {
+ return count;
+ }
+
+ public void increment() {
+ count = UPDATER.incrementAndGet(this);
+ }
+ }
+}
<command name="ofp/show-time-counters">
<action class="org.opendaylight.openflowplugin.impl.karaf.ShowEventTimesComandProvider"/>
</command>
+ <command name="ofp/show-session-stats">
+ <action class="org.opendaylight.openflowplugin.impl.karaf.ShowSessionStatsCommandProvider"/>
+ </command>
<command name="ofp/reset-time-counters">
<action class="org.opendaylight.openflowplugin.impl.karaf.ResetEventTimesComandProvider"/>
</command>
+ <command name="ofp/reset-session-stats">
+ <action class="org.opendaylight.openflowplugin.impl.karaf.ResetSessionStatsComandProvider"/>
+ </command>
</command-bundle>
import org.mockito.runners.MockitoJUnitRunner;
import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
import org.opendaylight.openflowplugin.impl.connection.ConnectionContextImpl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoOutputBuilder;
private SystemNotificationsListenerImpl systemNotificationsListener;
private ConnectionContextImpl connectionContextGolem;
+ private static final NodeId nodeId = new NodeId("OFP:TEST");
@Before
public void setUp() {
connectionContextGolem = new ConnectionContextImpl(connectionAdapter);
connectionContextGolem.changeStateToWorking();
+ connectionContextGolem.setNodeId(nodeId);
Mockito.when(connectionAdapter.getRemoteAddress()).thenReturn(
InetSocketAddress.createUnresolved("unit-odl.example.org", 4242));
Mockito.when(connectionContext.getConnectionAdapter()).thenReturn(connectionAdapter);
Mockito.when(connectionContext.getFeatures()).thenReturn(features);
+ Mockito.when(connectionContext.getNodeId()).thenReturn(nodeId);
systemNotificationsListener = new SystemNotificationsListenerImpl(connectionContext);
}