--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.openflowplugin</groupId>
+ <artifactId>openflowplugin-parent</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+ <relativePath>../</relativePath>
+ </parent>
+
+ <artifactId>openflowplugin-impl</artifactId>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <yangtools.version>0.7.0-SNAPSHOT</yangtools.version>
+ <yangtools.generator.version>0.7.0-SNAPSHOT</yangtools.generator.version>
+ <yangtools.binding.version>0.7.0-SNAPSHOT</yangtools.binding.version>
+ <jmxGeneratorPath>${project.build.directory}/generated-sources/config</jmxGeneratorPath>
+ <sal-binding-api.version>1.2.0-SNAPSHOT</sal-binding-api.version>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ <configuration>
+ <codeGenerators>
+ <generator>
+ <codeGeneratorClass>
+ org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
+ </codeGeneratorClass>
+ <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
+ <additionalConfiguration>
+ <namespaceToPackage1>
+ urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
+ </namespaceToPackage1>
+ </additionalConfiguration>
+ </generator>
+ <generator>
+ <codeGeneratorClass>
+ org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+ </codeGeneratorClass>
+ <outputBaseDir>${project.build.directory}/generated-sources/sal</outputBaseDir>
+ </generator>
+ <generator>
+ <codeGeneratorClass>org.opendaylight.yangtools.yang.unified.doc.generator.maven.DocumentationGeneratorImpl</codeGeneratorClass>
+ <outputBaseDir>${project.build.directory}/site/models</outputBaseDir>
+ </generator>
+ </codeGenerators>
+ <inspectDependencies>true</inspectDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>yang-jmx-generator-plugin</artifactId>
+ <version>${config.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>maven-sal-api-gen-plugin</artifactId>
+ <version>${yangtools.version}</version>
+ <type>jar</type>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin</groupId>
+ <artifactId>openflowplugin-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <!-- to be deprecated -->
+ <groupId>org.opendaylight.openflowplugin</groupId>
+ <artifactId>openflowplugin</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin</groupId>
+ <artifactId>openflowplugin-extension-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin.model</groupId>
+ <artifactId>model-flow-base</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin.model</groupId>
+ <artifactId>model-flow-service</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin.model</groupId>
+ <artifactId>model-flow-statistics</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-inventory</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <version>${sal-binding-api.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.openflowjava</groupId>
+ <artifactId>openflow-protocol-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowjava</groupId>
+ <artifactId>openflow-protocol-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>config-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowjava</groupId>
+ <artifactId>util</artifactId>
+ </dependency>
+
+ </dependencies>
+</project>
+
--- /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.connection;
+
+import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
+
+/**
+ *
+ */
+public class ConnectionContextImpl implements ConnectionContext {
+
+ private ConnectionAdapter connectionAdapter;
+ private CONNECTION_STATE connectionState;
+ private FeaturesReply featuresReply;
+
+ /**
+ * @param connectionAdapter
+ */
+ public ConnectionContextImpl(ConnectionAdapter connectionAdapter) {
+ this.connectionAdapter = connectionAdapter;
+ }
+
+ @Override
+ public ConnectionAdapter getConnectionAdapter() {
+ return connectionAdapter;
+ }
+
+ @Override
+ public CONNECTION_STATE getConnectionState() {
+ return connectionState;
+ }
+
+ @Override
+ public NodeId getNodeId() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setConnectionState(CONNECTION_STATE connectionState) {
+ this.connectionState = connectionState;
+ }
+
+ @Override
+ public FeaturesReply getFeatures() {
+ return featuresReply;
+ }
+
+ @Override
+ public void setFeatures(FeaturesReply featuresReply) {
+ this.featuresReply = featuresReply;
+
+ }
+}
--- /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.connection;
+
+import java.net.InetAddress;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
+import org.opendaylight.openflowjava.protocol.api.connection.ConnectionReadyListener;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionManager;
+import org.opendaylight.openflowplugin.api.openflow.connection.HandshakeContext;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceConnectedHandler;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.MessageHandler;
+import org.opendaylight.openflowplugin.api.openflow.md.core.ConnectionConductor;
+import org.opendaylight.openflowplugin.api.openflow.md.core.HandshakeListener;
+import org.opendaylight.openflowplugin.api.openflow.md.core.HandshakeManager;
+import org.opendaylight.openflowplugin.impl.connection.listener.ConnectionReadyListenerImpl;
+import org.opendaylight.openflowplugin.impl.connection.listener.HandshakeListenerImpl;
+import org.opendaylight.openflowplugin.impl.connection.listener.OpenflowProtocolListenerImpl;
+import org.opendaylight.openflowplugin.impl.connection.listener.SystemNotificationsListenerImpl;
+import org.opendaylight.openflowplugin.openflow.md.core.HandshakeManagerImpl;
+import org.opendaylight.openflowplugin.openflow.md.core.ThreadPoolLoggingExecutor;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OpenflowProtocolListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SystemNotificationsListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class ConnectionManagerImpl implements ConnectionManager {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ConnectionManagerImpl.class);
+ private static final int HELLO_LIMIT = 20;
+ private boolean bitmapNegotiationEnabled = true;
+ private DeviceConnectedHandler deviceConnectedHandler;
+
+ @Override
+ public void onSwitchConnected(final ConnectionAdapter connectionAdapter) {
+ LOG.trace("preparing handshake");
+
+ final int handshakeThreadLimit = 1; //TODO: move to constants/parametrize
+ final ThreadPoolLoggingExecutor handshakePool = createHandshakePool(
+ connectionAdapter.getRemoteAddress().toString(), handshakeThreadLimit);
+
+ LOG.trace("prepare connection context");
+ final ConnectionContext connectionContext = new ConnectionContextImpl(connectionAdapter);
+
+ HandshakeListener handshakeListener = new HandshakeListenerImpl(connectionContext, deviceConnectedHandler);
+ final HandshakeManager handshakeManager = createHandshakeManager(connectionAdapter, handshakeListener);
+
+ LOG.trace("prepare handshake context");
+ HandshakeContext handshakeContext = new HandshakeContextImpl(handshakePool, handshakeManager);
+
+ LOG.trace("prepare connection listeners");
+ final ConnectionReadyListener connectionReadyListener = new ConnectionReadyListenerImpl(
+ connectionContext, handshakeContext);
+ connectionAdapter.setConnectionReadyListener(connectionReadyListener);
+
+ final OpenflowProtocolListener ofMessageListener =
+ new OpenflowProtocolListenerImpl(connectionContext, handshakeContext);
+ connectionAdapter.setMessageListener(ofMessageListener);
+
+ final SystemNotificationsListener systemListener = new SystemNotificationsListenerImpl(connectionContext);
+ connectionAdapter.setSystemListener(systemListener);
+
+ LOG.trace("connection balet finished");
+ }
+
+ /**
+ * @param connectionAdapter
+ * @param handshakeThreadLimit
+ * @return
+ */
+ private static ThreadPoolLoggingExecutor createHandshakePool(
+ final String connectionIdentifier, int handshakeThreadLimit) {
+ return new ThreadPoolLoggingExecutor(handshakeThreadLimit,
+ handshakeThreadLimit, 0L, TimeUnit.MILLISECONDS,
+ new ArrayBlockingQueue<Runnable>(HELLO_LIMIT), "OFHandshake-" + connectionIdentifier);
+ }
+
+ /**
+ * @param connectionAdapter
+ * @param handshakeListener
+ * @return
+ */
+ private HandshakeManager createHandshakeManager(final ConnectionAdapter connectionAdapter,
+ HandshakeListener handshakeListener) {
+ HandshakeManagerImpl handshakeManager = new HandshakeManagerImpl(connectionAdapter,
+ ConnectionConductor.versionOrder.get(0),
+ ConnectionConductor.versionOrder);
+ handshakeManager.setUseVersionBitmap(isBitmapNegotiationEnabled());
+ handshakeManager.setHandshakeListener(handshakeListener);
+ return handshakeManager;
+ }
+
+ /**
+ * @return parameter dedicated to hello message content
+ */
+ public boolean isBitmapNegotiationEnabled() {
+ return bitmapNegotiationEnabled ;
+ }
+
+ /**
+ * @param bitmapNegotiationEnabled the bitmapNegotiationEnabled to set
+ */
+ public void setBitmapNegotiationEnabled(boolean bitmapNegotiationEnabled) {
+ this.bitmapNegotiationEnabled = bitmapNegotiationEnabled;
+ }
+
+ @Override
+ public boolean accept(InetAddress switchAddress) {
+ // TODO add connection accept logic based on address
+ return true;
+ }
+
+ @Override
+ public void setDeviceConnectedHandler(DeviceConnectedHandler deviceConnectedHandler) {
+ this.deviceConnectedHandler = deviceConnectedHandler;
+ }
+
+ @Override
+ public void setMessageHandler(MessageHandler arg0) {
+ // TODO Auto-generated method stub
+
+ }
+}
--- /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.connection;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+import org.opendaylight.openflowplugin.api.openflow.connection.HandshakeContext;
+import org.opendaylight.openflowplugin.api.openflow.md.core.HandshakeManager;
+
+/**
+ *
+ */
+public class HandshakeContextImpl implements HandshakeContext {
+
+ private ThreadPoolExecutor handshakePool;
+ private HandshakeManager handshakeManager;
+
+ /**
+ * @param handshakePool
+ * @param handshakeManager
+ */
+ public HandshakeContextImpl(ThreadPoolExecutor handshakePool, HandshakeManager handshakeManager) {
+ this.handshakePool = handshakePool;
+ this.handshakeManager = handshakeManager;
+ }
+
+ @Override
+ public HandshakeManager getHandshakeManager() {
+ return handshakeManager;
+ }
+
+ @Override
+ public ThreadPoolExecutor getHandshakePool() {
+ return handshakePool;
+ }
+
+}
--- /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.connection.listener;
+
+import org.opendaylight.openflowjava.protocol.api.connection.ConnectionReadyListener;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+import org.opendaylight.openflowplugin.api.openflow.connection.HandshakeContext;
+import org.opendaylight.openflowplugin.openflow.md.core.HandshakeStepWrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * oneshot listener - once connection is ready, initiate handshake (if not already started by device)
+ */
+public class ConnectionReadyListenerImpl implements ConnectionReadyListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ConnectionReadyListenerImpl.class);
+
+ private ConnectionContext connectionContext;
+ private HandshakeContext handshakeContext;
+
+ /**
+ * @param connectionContext
+ * @param handshakeContext
+ */
+ public ConnectionReadyListenerImpl(ConnectionContext connectionContext,
+ HandshakeContext handshakeContext) {
+ this.connectionContext = connectionContext;
+ this.handshakeContext = handshakeContext;
+ }
+
+ @Override
+ public void onConnectionReady() {
+ LOG.debug("device is connected and ready-to-use (pipeline prepared)");
+ if (connectionContext.getConnectionState() == null) {
+ HandshakeStepWrapper handshakeStepWrapper = new HandshakeStepWrapper(
+ null, handshakeContext.getHandshakeManager(), connectionContext.getConnectionAdapter());
+ handshakeContext.getHandshakePool().execute(handshakeStepWrapper);
+ connectionContext.setConnectionState(ConnectionContext.CONNECTION_STATE.HANDSHAKING);
+ } else {
+ LOG.debug("already touched by hello message");
+ }
+ }
+
+}
--- /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.connection.listener;
+
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceConnectedHandler;
+import org.opendaylight.openflowplugin.api.openflow.md.core.HandshakeListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class HandshakeListenerImpl implements HandshakeListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(HandshakeListenerImpl.class);
+
+ private ConnectionContext connectionContext;
+ private DeviceConnectedHandler deviceConnectedHandler;
+
+ /**
+ * @param connectionContext
+ * @param deviceConnectedHandler
+ */
+ public HandshakeListenerImpl(ConnectionContext connectionContext, DeviceConnectedHandler deviceConnectedHandler) {
+ this.connectionContext = connectionContext;
+ this.deviceConnectedHandler = deviceConnectedHandler;
+ }
+
+ @Override
+ public void onHandshakeSuccessfull(GetFeaturesOutput featureOutput, Short version) {
+ connectionContext.setConnectionState(ConnectionContext.CONNECTION_STATE.WORKING);
+ connectionContext.setFeatures(featureOutput);
+ deviceConnectedHandler.deviceConnected(connectionContext);
+ }
+
+ @Override
+ public void onHandshakeFailure() {
+ LOG.info("handshake failed: {}", connectionContext.getConnectionAdapter().getRemoteAddress());
+ connectionContext.setConnectionState(ConnectionContext.CONNECTION_STATE.RIP);
+ // TODO ensure that connection is closed
+ }
+}
--- /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.connection.listener;
+
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+import org.opendaylight.openflowplugin.api.openflow.connection.HandshakeContext;
+import org.opendaylight.openflowplugin.openflow.md.core.HandshakeStepWrapper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoRequestMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ErrorMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ExperimenterMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowRemovedMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReplyMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OpenflowProtocolListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketInMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Objects;
+
+/**
+ *
+ */
+public class OpenflowProtocolListenerImpl implements OpenflowProtocolListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(OpenflowProtocolListenerImpl.class);
+
+ private ConnectionContext connectionContext;
+ private HandshakeContext handshakeContext;
+
+ /**
+ * @param connectionContext
+ * @param handshakeContext
+ */
+ public OpenflowProtocolListenerImpl(ConnectionContext connectionContext,
+ HandshakeContext handshakeContext) {
+ this.connectionContext = connectionContext;
+ this.handshakeContext = handshakeContext;
+ }
+
+ @Override
+ public void onEchoRequestMessage(EchoRequestMessage notification) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onErrorMessage(ErrorMessage notification) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onExperimenterMessage(ExperimenterMessage notification) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onFlowRemovedMessage(FlowRemovedMessage notification) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onHelloMessage(HelloMessage hello) {
+ LOG.debug("processing HELLO.xid: {}", hello.getXid());
+ if (connectionContext.getConnectionState() == null) {
+ connectionContext.setConnectionState(ConnectionContext.CONNECTION_STATE.HANDSHAKING);
+ }
+
+ if (checkState(ConnectionContext.CONNECTION_STATE.HANDSHAKING)) {
+ HandshakeStepWrapper handshakeStepWrapper = new HandshakeStepWrapper(
+ hello, handshakeContext.getHandshakeManager(), connectionContext.getConnectionAdapter());
+ handshakeContext.getHandshakePool().submit(handshakeStepWrapper);
+ } else {
+ //TODO: consider disconnecting of bad behaving device
+ }
+
+ }
+
+ @Override
+ public void onMultipartReplyMessage(MultipartReplyMessage notification) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onPacketInMessage(PacketInMessage notification) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onPortStatusMessage(PortStatusMessage notification) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * @param expectedState
+ */
+ protected boolean checkState(ConnectionContext.CONNECTION_STATE expectedState) {
+ boolean verdict = true;
+ if (! Objects.equal(connectionContext.getConnectionState(), expectedState)) {
+ verdict = false;
+ LOG.info("Expected state: {}, actual state: {}", expectedState,
+ connectionContext.getConnectionState());
+ }
+
+ return verdict;
+ }
+
+}
--- /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.connection.listener;
+
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.DisconnectEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SwitchIdleEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SystemNotificationsListener;
+
+/**
+ *
+ */
+public class SystemNotificationsListenerImpl implements SystemNotificationsListener {
+
+ private ConnectionContext connectionContext;
+
+
+ /**
+ * @param connectionContext
+ */
+ public SystemNotificationsListenerImpl(ConnectionContext connectionContext) {
+ this.connectionContext = connectionContext;
+ }
+
+ @Override
+ public void onDisconnectEvent(DisconnectEvent notification) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onSwitchIdleEvent(SwitchIdleEvent notification) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
--- /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.connection;
+
+import static org.junit.Assert.fail;
+import com.google.common.util.concurrent.SettableFuture;
+import java.math.BigInteger;
+import java.net.InetSocketAddress;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
+import org.opendaylight.openflowjava.protocol.api.connection.ConnectionReadyListener;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceConnectedHandler;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloMessageBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OpenflowProtocolListener;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+
+/**
+ * test of {@link ConnectionManagerImpl} - lightweight version, using basic ways (TDD)
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class ConnectionManagerImplTest {
+
+ /** timeout of final step [ms] */
+ private static final int FINAL_STEP_TIMEOUT = 500;
+ private ConnectionManagerImpl connectionManagerImpl;
+ @Mock
+ private ConnectionAdapter connection;
+ @Mock
+ private DeviceConnectedHandler deviceConnectedHandler;
+ @Captor
+ private ArgumentCaptor<ConnectionReadyListener> connectionReadyListenerAC;
+ @Captor
+ private ArgumentCaptor<OpenflowProtocolListener> ofpListenerAC;
+
+ /**
+ * before each test method
+ */
+ @Before
+ public void setUp() {
+ connectionManagerImpl = new ConnectionManagerImpl();
+ connectionManagerImpl.setDeviceConnectedHandler(deviceConnectedHandler);
+ final InetSocketAddress deviceAddress = InetSocketAddress.createUnresolved("yahoo", 42);
+ Mockito.when(connection.getRemoteAddress()).thenReturn(deviceAddress);
+ Mockito.when(connection.isAlive()).thenReturn(true);
+ }
+
+ /**
+ * after each test method
+ * @throws InterruptedException
+ */
+ @After
+ public void tearDown() throws InterruptedException {
+ Thread.sleep(200L);
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.openflowplugin.impl.connection.ConnectionManagerImpl#onSwitchConnected(org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter)}.
+ * invoking onConnectionReady first, scenario:
+ * <ol>
+ * <li>send hello to device (rpc with void output)</li>
+ * <li>receive hello from device (notification)</li>
+ * <li>send getFeature to device (rpc with getFeatureOutput)</li>
+ * <li>wait for rpc to finish with getFeatureOutput</li>
+ * </ol>
+ * @throws InterruptedException
+ */
+ @Test
+ public void testOnSwitchConnected1() throws InterruptedException {
+ connectionManagerImpl.onSwitchConnected(connection);
+ Mockito.verify(connection).setConnectionReadyListener(connectionReadyListenerAC.capture());
+ Mockito.verify(connection).setMessageListener(ofpListenerAC.capture());
+
+ // prepare void reply (hello rpc output)
+ final SettableFuture<RpcResult<Void>> voidResponseFx = SettableFuture.<RpcResult<Void>>create();
+ Mockito.when(connection.hello(Matchers.any(HelloInput.class))).thenReturn(voidResponseFx);
+ // prepare getFeature reply (getFeture rpc output)
+ final SettableFuture<RpcResult<GetFeaturesOutput>> featureResponseFx = SettableFuture.<RpcResult<GetFeaturesOutput>>create();
+ Mockito.when(connection.getFeatures(Matchers.any(GetFeaturesInput.class))).thenReturn(featureResponseFx);
+
+
+ // fire handshake
+ connectionReadyListenerAC.getValue().onConnectionReady();
+
+ // deliver hello send output (void)
+ Thread.sleep(100L);
+ final RpcResult<Void> helloResponse = RpcResultBuilder.success((Void) null).build();
+ voidResponseFx.set(helloResponse);
+
+ // send hello reply
+ final HelloMessage hello = new HelloMessageBuilder().setVersion(OFConstants.OFP_VERSION_1_3).setXid(1L).build();
+ ofpListenerAC.getValue().onHelloMessage(hello);
+
+ // deliver getFeature output
+ Thread.sleep(100L);
+ final GetFeaturesOutput getFeatureOutput = new GetFeaturesOutputBuilder()
+ .setDatapathId(BigInteger.TEN)
+ .setVersion(OFConstants.OFP_VERSION_1_3)
+ .setXid(2L)
+ .setTables((short) 15)
+ .build();
+ final RpcResult<GetFeaturesOutput> rpcFeaturesOutput = RpcResultBuilder.success(getFeatureOutput).build();
+ featureResponseFx.set(rpcFeaturesOutput);
+
+ Mockito.verify(deviceConnectedHandler, Mockito.timeout(500)).deviceConnected(Matchers.any(ConnectionContext.class));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.openflowplugin.impl.connection.ConnectionManagerImpl#onSwitchConnected(org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter)}.
+ * invoking onHelloMessage, scenario:
+ * <ol>
+ * <li>receive hello from device (notification)</li>
+ * <li>send hello to device (rpc with void output)</li>
+ * <li>send getFeature to device (rpc with getFeatureOutput)</li>
+ * <li>wait for rpc to finish with getFeatureOutput</li>
+ * </ol>
+ * @throws InterruptedException
+ */
+ @Test
+ public void testOnSwitchConnected2() throws InterruptedException {
+ connectionManagerImpl.onSwitchConnected(connection);
+ Mockito.verify(connection).setConnectionReadyListener(connectionReadyListenerAC.capture());
+ Mockito.verify(connection).setMessageListener(ofpListenerAC.capture());
+
+ // prepare void reply (hello rpc output)
+ final SettableFuture<RpcResult<Void>> voidResponseFx = SettableFuture.<RpcResult<Void>>create();
+ Mockito.when(connection.hello(Matchers.any(HelloInput.class))).thenReturn(voidResponseFx);
+ // prepare getFeature reply (getFeture rpc output)
+ final SettableFuture<RpcResult<GetFeaturesOutput>> featureResponseFx = SettableFuture.<RpcResult<GetFeaturesOutput>>create();
+ Mockito.when(connection.getFeatures(Matchers.any(GetFeaturesInput.class))).thenReturn(featureResponseFx);
+
+
+ // fire handshake - send hello reply
+ final HelloMessage hello = new HelloMessageBuilder().setVersion(OFConstants.OFP_VERSION_1_3).setXid(1L).build();
+ ofpListenerAC.getValue().onHelloMessage(hello);
+
+ // notify about connection ready
+ connectionReadyListenerAC.getValue().onConnectionReady();
+
+ // deliver hello send output (void)
+ Thread.sleep(100L);
+ final RpcResult<Void> helloResponse = RpcResultBuilder.success((Void) null).build();
+ voidResponseFx.set(helloResponse);
+
+ // deliver getFeature output
+ Thread.sleep(100L);
+ final GetFeaturesOutput getFeatureOutput = new GetFeaturesOutputBuilder()
+ .setDatapathId(BigInteger.TEN)
+ .setVersion(OFConstants.OFP_VERSION_1_3)
+ .setXid(2L)
+ .setTables((short) 15)
+ .build();
+ final RpcResult<GetFeaturesOutput> rpcFeaturesOutput = RpcResultBuilder.success(getFeatureOutput).build();
+ featureResponseFx.set(rpcFeaturesOutput);
+
+ Mockito.verify(deviceConnectedHandler, Mockito.timeout(FINAL_STEP_TIMEOUT)).deviceConnected(Matchers.any(ConnectionContext.class));
+ }
+
+ /**
+ * Test method for {@link org.opendaylight.openflowplugin.impl.connection.ConnectionManagerImpl#setOpenflowProtocolListener(org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OpenflowProtocolListener)}.
+ */
+ @Test
+ @Ignore
+ public void testSetOpenflowProtocolListener() {
+ fail("Not yet implemented");
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">\r
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">\r
+\r
+ <appender name="console" class="org.apache.log4j.ConsoleAppender">\r
+ <layout class="org.apache.log4j.PatternLayout">\r
+ <param name="ConversionPattern" value="%-6p %d{HH:mm:ss.SSS} [%10.10t] %30.30c %x - %m%n" />\r
+ </layout>\r
+<!-- <param name="Threshold" value="DEBUG" /> -->\r
+ </appender>\r
+\r
+ <logger name="org.opendaylight.openflowplugin" additivity="false">\r
+ <level value="DEBUG" />\r
+ <appender-ref ref="console" />\r
+ </logger>\r
+ \r
+ <logger name="org.opendaylight.openflowplugin.impl" additivity="false">\r
+ <level value="DEBUG" />\r
+ <appender-ref ref="console" />\r
+ </logger>\r
+ \r
+ <logger name="org.opendaylight.openflowplugin.impl.connection" additivity="false">\r
+ <level value="TRACE" />\r
+ <appender-ref ref="console" />\r
+ </logger>\r
+ \r
+ <logger name="org.opendaylight.openflowplugin.openflow.md.core.HandshakeManagerImpl" additivity="false">\r
+ <level value="TRACE" />\r
+ <appender-ref ref="console" />\r
+ </logger>\r
+\r
+ <root>\r
+ <priority value="INFO" />\r
+ <appender-ref ref="console" />\r
+ </root>\r
+</log4j:configuration>\r
<modules>
<module>openflowplugin-api</module>
<module>openflowplugin</module>
+ <module>openflowplugin-impl</module>
<module>extension</module>
<module>distribution/karaf</module>
<module>openflowplugin-controller-config</module>