}\r
}\r
}\r
+\r
+ typedef transport-protocol {\r
+ type enumeration {\r
+ enum TCP {\r
+ value 0;\r
+ description "Communication over TCP protocol.";\r
+ }\r
+ enum TLS {\r
+ value 1;\r
+ description "Communication over TLS protocol.";\r
+ }\r
+ enum UDP {\r
+ value 2;\r
+ description "Communication over UDP protocol.";\r
+ }\r
+ }\r
+ }\r
}
\ No newline at end of file
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
+import java.net.InetSocketAddress;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
private final Queue<MessageHolder<?>> queue;
private final long maxWorkTime;
private final Channel channel;
+ private InetSocketAddress address;
public ChannelOutboundQueue(final Channel channel, final int queueDepth) {
Preconditions.checkArgument(queueDepth > 0, "Queue depth has to be positive");
}
final GenericFutureListener<Future<Void>> l = h.takeListener();
- final ChannelFuture p = channel.write(new MessageListenerWrapper(h.takeMessage(), l));
+
+ final ChannelFuture p;
+ if (address == null) {
+ p = channel.write(new MessageListenerWrapper(h.takeMessage(), l));
+ } else {
+ p = channel.write(new UdpMessageListenerWrapper(h.takeMessage(), l, address));
+ }
if (l != null) {
p.addListener(l);
}
public String toString() {
return String.format("Channel %s queue [%s messages flushing=%s]", channel, queue.size(), flushScheduled);
}
+
+ public void setAddress(InetSocketAddress address) {
+ this.address = address;
+ }
}
package org.opendaylight.openflowjava.protocol.impl.connection;
-import io.netty.channel.socket.SocketChannel;
+import java.net.InetSocketAddress;
+
+import io.netty.channel.Channel;
/**
* @author mirehak
* @param ch
* @return connection adapter tcp-implementation
*/
- public ConnectionFacade createConnectionFacade(SocketChannel ch) ;
+ public ConnectionFacade createConnectionFacade(Channel ch, InetSocketAddress address) ;
}
package org.opendaylight.openflowjava.protocol.impl.connection;
-import io.netty.channel.socket.SocketChannel;
+import java.net.InetSocketAddress;
+
+import io.netty.channel.Channel;
/**
* @author mirehak
* @return connection adapter tcp-implementation
*/
@Override
- public ConnectionFacade createConnectionFacade(SocketChannel ch) {
- return new ConnectionAdapterImpl(ch);
+ public ConnectionFacade createConnectionFacade(Channel ch, InetSocketAddress address) {
+ return new ConnectionAdapterImpl(ch, address);
}
}
package org.opendaylight.openflowjava.protocol.impl.connection;
+import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
-import io.netty.channel.socket.SocketChannel;
import io.netty.util.concurrent.GenericFutureListener;
import java.net.InetSocketAddress;
private final Cache<RpcResponseKey, ResponseExpectedRpcListener<?>> responseCache;
private final ChannelOutboundQueue output;
- private final SocketChannel channel;
+ private final Channel channel;
private ConnectionReadyListener connectionReadyListener;
private OpenflowProtocolListener messageListener;
/**
* default ctor
* @param channel the channel to be set - used for communication
+ * @param address client address (used only in case of UDP communication,
+ * as there is no need to store address over tcp (stable channel))
*/
- public ConnectionAdapterImpl(final SocketChannel channel) {
+ public ConnectionAdapterImpl(final Channel channel, final InetSocketAddress address) {
responseCache = CacheBuilder.newBuilder()
.concurrencyLevel(1)
.expireAfterWrite(RPC_RESPONSE_EXPIRATION, TimeUnit.MINUTES)
.removalListener(REMOVAL_LISTENER).build();
this.channel = Preconditions.checkNotNull(channel);
this.output = new ChannelOutboundQueue(channel, DEFAULT_QUEUE_DEPTH);
+ output.setAddress(address);
channel.pipeline().addLast(output);
LOG.debug("ConnectionAdapter created");
}
@Override
public InetSocketAddress getRemoteAddress() {
- return channel.remoteAddress();
+ return (InetSocketAddress) channel.remoteAddress();
}
}
package org.opendaylight.openflowjava.protocol.impl.connection;
+import org.opendaylight.openflowjava.protocol.api.connection.ThreadConfiguration;
+
/**
* @author mirehak
*/
public interface ServerFacade extends ShutdownProvider, OnlineProvider, Runnable {
- // empty unifying superinterface
+ /**
+ * Sets thread configuration
+ * @param threadConfig desired thread configuration
+ */
+ public void setThreadConfig(ThreadConfiguration threadConfig);
}
import org.opendaylight.openflowjava.protocol.api.keys.experimenter.ExperimenterInstructionDeserializerKey;
import org.opendaylight.openflowjava.protocol.api.keys.experimenter.ExperimenterInstructionSerializerKey;
import org.opendaylight.openflowjava.protocol.api.keys.experimenter.ExperimenterSerializerKey;
-import org.opendaylight.openflowjava.protocol.impl.core.PublishingChannelInitializerFactory;
+import org.opendaylight.openflowjava.protocol.impl.core.ChannelInitializerFactory;
import org.opendaylight.openflowjava.protocol.impl.core.TcpHandler;
+import org.opendaylight.openflowjava.protocol.impl.core.UdpHandler;
import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory;
import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializerRegistryImpl;
import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory;
import org.opendaylight.openflowjava.protocol.impl.serialization.SerializerRegistryImpl;
import org.opendaylight.openflowjava.protocol.spi.connection.SwitchConnectionProvider;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.TransportProtocol;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MatchField;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.OxmClassBase;
import org.slf4j.Logger;
/**
* @return
*/
- private TcpHandler createAndConfigureServer() {
+ private ServerFacade createAndConfigureServer() {
LOGGER.debug("Configuring ..");
- TcpHandler server = new TcpHandler(connConfig.getAddress(), connConfig.getPort());
- PublishingChannelInitializerFactory factory = new PublishingChannelInitializerFactory();
+ ServerFacade server = null;
+ ChannelInitializerFactory factory = new ChannelInitializerFactory();
factory.setSwitchConnectionHandler(switchConnectionHandler);
factory.setSwitchIdleTimeout(connConfig.getSwitchIdleTimeout());
factory.setTlsConfig(connConfig.getTlsConfiguration());
factory.setSerializationFactory(serializationFactory);
factory.setDeserializationFactory(deserializationFactory);
- server.setChannelInitializer(factory.createPublishingChannelInitializer());
+ TransportProtocol transportProtocol = (TransportProtocol) connConfig.getTransferProtocol();
+ if (transportProtocol.equals(TransportProtocol.TCP) || transportProtocol.equals(TransportProtocol.TLS)) {
+ server = new TcpHandler(connConfig.getAddress(), connConfig.getPort());
+ ((TcpHandler) server).setChannelInitializer(factory.createPublishingChannelInitializer());
+ } else {
+ server = new UdpHandler(connConfig.getAddress(), connConfig.getPort());
+ ((UdpHandler) server).setChannelInitializer(factory.createUdpChannelInitializer());
+ }
server.setThreadConfig(connConfig.getThreadConfiguration());
return server;
}
--- /dev/null
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.connection;\r
+\r
+import io.netty.util.concurrent.Future;\r
+import io.netty.util.concurrent.GenericFutureListener;\r
+\r
+import java.net.InetSocketAddress;\r
+\r
+/**\r
+ * Wraps outgoing message and includes listener attached to this message. This object\r
+ * is sent to OFEncoder. When OFEncoder fails to serialize the message,\r
+ * listener is filled with exception. The exception is then delegated to upper ODL layers.\r
+ * This object is used for UDP communication - it also carries recipient address\r
+ \r
+ * @author michal.polkorab\r
+ */\r
+public class UdpMessageListenerWrapper extends MessageListenerWrapper {\r
+\r
+ private InetSocketAddress address;\r
+\r
+ /**\r
+ * @param msg message to be sent\r
+ * @param listener listener attached to channel.write(msg) Future\r
+ * @param address recipient's address\r
+ */\r
+ public UdpMessageListenerWrapper(Object msg, GenericFutureListener<Future<Void>> listener,\r
+ InetSocketAddress address) {\r
+ super(msg, listener);\r
+ this.address = address;\r
+ }\r
+\r
+ /**\r
+ * @return recipient address\r
+ */\r
+ public InetSocketAddress getAddress() {\r
+ return address;\r
+ }\r
+}
\ No newline at end of file
* @author michal.polkorab\r
*\r
*/\r
-public class PublishingChannelInitializerFactory {\r
+public class ChannelInitializerFactory {\r
\r
private long switchIdleTimeOut;\r
private DeserializationFactory deserializationFactory;\r
/**\r
* @return PublishingChannelInitializer that initializes new channels\r
*/\r
- public PublishingChannelInitializer createPublishingChannelInitializer() {\r
- PublishingChannelInitializer initializer = new PublishingChannelInitializer();\r
+ public TcpChannelInitializer createPublishingChannelInitializer() {\r
+ TcpChannelInitializer initializer = new TcpChannelInitializer();\r
initializer.setSwitchIdleTimeout(switchIdleTimeOut);\r
initializer.setDeserializationFactory(deserializationFactory);\r
initializer.setSerializationFactory(serializationFactory);\r
return initializer;\r
}\r
\r
+ /**\r
+ * @return PublishingChannelInitializer that initializes new channels\r
+ */\r
+ public UdpChannelInitializer createUdpChannelInitializer() {\r
+ UdpChannelInitializer initializer = new UdpChannelInitializer();\r
+ initializer.setSwitchIdleTimeout(switchIdleTimeOut);\r
+ initializer.setDeserializationFactory(deserializationFactory);\r
+ initializer.setSerializationFactory(serializationFactory);\r
+ initializer.setSwitchConnectionHandler(switchConnectionHandler);\r
+ return initializer;\r
+ }\r
+\r
/**\r
* @param switchIdleTimeOut\r
*/\r
public void setSwitchConnectionHandler(SwitchConnectionHandler switchConnectionHandler) {\r
this.switchConnectionHandler = switchConnectionHandler;\r
}\r
-\r
- \r
-}\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import io.netty.channel.ChannelHandlerContext;\r
+import io.netty.handler.codec.MessageToMessageDecoder;\r
+\r
+import java.util.List;\r
+\r
+import org.opendaylight.openflowjava.protocol.impl.connection.MessageConsumer;\r
+import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory;\r
+import org.opendaylight.openflowjava.util.ByteBufUtils;\r
+import org.opendaylight.yangtools.yang.binding.DataObject;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+/**\r
+ * @author michal.polkorab\r
+ *\r
+ */\r
+public class OFDatagramPacketDecoder extends MessageToMessageDecoder<VersionMessageUdpWrapper>{\r
+\r
+ private static final Logger LOGGER = LoggerFactory.getLogger(OFDatagramPacketDecoder.class);\r
+ private DeserializationFactory deserializationFactory;\r
+\r
+ @Override\r
+ protected void decode(ChannelHandlerContext ctx,\r
+ VersionMessageUdpWrapper msg, List<Object> out) throws Exception {\r
+ if (LOGGER.isDebugEnabled()) {\r
+ LOGGER.debug("UdpVersionMessageWrapper received");\r
+ LOGGER.debug("<< " + ByteBufUtils.byteBufToHexString(msg.getMessageBuffer()));\r
+ }\r
+\r
+ DataObject dataObject = null;\r
+ try {\r
+ dataObject = deserializationFactory.deserialize(msg.getMessageBuffer(),\r
+ msg.getVersion());\r
+ if (dataObject == null) {\r
+ LOGGER.warn("Translated POJO is null");\r
+ } else {\r
+ MessageConsumer consumer = UdpConnectionMap.getMessageConsumer(msg.getAddress());\r
+ consumer.consume(dataObject);\r
+ }\r
+ } catch(Exception e) {\r
+ LOGGER.error("Message deserialization failed");\r
+ LOGGER.error(e.getMessage(), e);\r
+ // TODO: delegate exception to allow easier deserialization\r
+ // debugging / deserialization problem awareness\r
+ } finally {\r
+ msg.getMessageBuffer().release();\r
+ }\r
+ \r
+ }\r
+\r
+ /**\r
+ * @param deserializationFactory\r
+ */\r
+ public void setDeserializationFactory(DeserializationFactory deserializationFactory) {\r
+ this.deserializationFactory = deserializationFactory;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import java.util.List;\r
+\r
+import org.opendaylight.openflowjava.protocol.impl.connection.UdpMessageListenerWrapper;\r
+import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import io.netty.buffer.ByteBuf;\r
+import io.netty.buffer.PooledByteBufAllocator;\r
+import io.netty.channel.ChannelHandlerContext;\r
+import io.netty.channel.socket.DatagramPacket;\r
+import io.netty.handler.codec.MessageToMessageEncoder;\r
+import io.netty.util.concurrent.Future;\r
+\r
+/**\r
+ * @author michal.polkorab\r
+ *\r
+ */\r
+public class OFDatagramPacketEncoder extends MessageToMessageEncoder<UdpMessageListenerWrapper> {\r
+\r
+ private static final Logger LOGGER = LoggerFactory.getLogger(OFDatagramPacketEncoder.class);\r
+ private SerializationFactory serializationFactory;\r
+\r
+ @Override\r
+ protected void encode(ChannelHandlerContext ctx,\r
+ UdpMessageListenerWrapper wrapper, List<Object> out) throws Exception {\r
+ LOGGER.trace("Encoding");\r
+ try {\r
+ ByteBuf buffer = PooledByteBufAllocator.DEFAULT.buffer();\r
+ serializationFactory.messageToBuffer(wrapper.getMsg().getVersion(), buffer, wrapper.getMsg());\r
+ out.add(new DatagramPacket(buffer, wrapper.getAddress()));\r
+ } catch(Exception e) {\r
+ LOGGER.warn("Message serialization failed: {}", e.getMessage());\r
+ Future<Void> newFailedFuture = ctx.newFailedFuture(e);\r
+ wrapper.getListener().operationComplete(newFailedFuture);\r
+ return;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param serializationFactory\r
+ */\r
+ public void setSerializationFactory(SerializationFactory serializationFactory) {\r
+ this.serializationFactory = serializationFactory;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import io.netty.buffer.ByteBuf;\r
+import io.netty.channel.ChannelHandlerContext;\r
+import io.netty.channel.socket.DatagramPacket;\r
+import io.netty.handler.codec.MessageToMessageDecoder;\r
+\r
+import java.util.List;\r
+\r
+import org.opendaylight.openflowjava.protocol.api.connection.SwitchConnectionHandler;\r
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;\r
+import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactory;\r
+import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactoryImpl;\r
+import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade;\r
+import org.opendaylight.openflowjava.protocol.impl.connection.MessageConsumer;\r
+import org.opendaylight.openflowjava.util.ByteBufUtils;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+/**\r
+ * @author michal.polkorab\r
+ *\r
+ */\r
+public class OFDatagramPacketHandler extends MessageToMessageDecoder<DatagramPacket> {\r
+\r
+ private static final Logger LOGGER = LoggerFactory.getLogger(OFDatagramPacketHandler.class);\r
+\r
+ /** Length of OpenFlow 1.3 header */\r
+ public static final byte LENGTH_OF_HEADER = 8;\r
+ private static final byte LENGTH_INDEX_IN_HEADER = 2;\r
+ private ConnectionAdapterFactory adapterFactory = new ConnectionAdapterFactoryImpl();\r
+ private SwitchConnectionHandler connectionHandler;\r
+\r
+ /**\r
+ * Default constructor\r
+ * @param sch the switchConnectionHandler that decides\r
+ * what to do with incomming message / channel\r
+ */\r
+ public OFDatagramPacketHandler(SwitchConnectionHandler sch) {\r
+ this.connectionHandler = sch;\r
+ }\r
+\r
+ @Override\r
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\r
+ LOGGER.warn("Unexpected exception from downstream.", cause);\r
+ LOGGER.warn("Closing connection.");\r
+ ctx.close();\r
+ }\r
+\r
+ @Override\r
+ protected void decode(ChannelHandlerContext ctx, DatagramPacket msg,\r
+ List<Object> out) throws Exception {\r
+ LOGGER.debug("OFDatagramPacketFramer");\r
+ MessageConsumer consumer = UdpConnectionMap.getMessageConsumer(msg.sender());\r
+ if (consumer == null) {\r
+ ConnectionFacade connectionFacade =\r
+ adapterFactory.createConnectionFacade(ctx.channel(), msg.sender());\r
+ connectionHandler.onSwitchConnected(connectionFacade);\r
+ connectionFacade.checkListeners();\r
+ UdpConnectionMap.addConnection(msg.sender(), connectionFacade);\r
+ }\r
+ ByteBuf bb = msg.content();\r
+ int readableBytes = bb.readableBytes();\r
+ if (readableBytes < LENGTH_OF_HEADER) {\r
+ if (LOGGER.isDebugEnabled()) {\r
+ LOGGER.debug("skipping bytebuf - too few bytes for header: " + readableBytes + " < " + LENGTH_OF_HEADER );\r
+ LOGGER.debug("bb: " + ByteBufUtils.byteBufToHexString(bb));\r
+ }\r
+ return;\r
+ }\r
+\r
+ int length = bb.getUnsignedShort(bb.readerIndex() + LENGTH_INDEX_IN_HEADER);\r
+ LOGGER.debug("length of actual message: {}", length);\r
+ \r
+ if (readableBytes < length) {\r
+ if (LOGGER.isDebugEnabled()) {\r
+ LOGGER.debug("skipping bytebuf - too few bytes for msg: " +\r
+ readableBytes + " < " + length);\r
+ LOGGER.debug("bytebuffer: " + ByteBufUtils.byteBufToHexString(bb));\r
+ }\r
+ return;\r
+ }\r
+ LOGGER.debug("OF Protocol message received, type:{}", bb.getByte(bb.readerIndex() + 1));\r
+\r
+ \r
+ byte version = bb.readByte();\r
+ if ((version == EncodeConstants.OF13_VERSION_ID) || (version == EncodeConstants.OF10_VERSION_ID)) {\r
+ LOGGER.debug("detected version: " + version);\r
+ ByteBuf messageBuffer = bb.slice();\r
+ out.add(new VersionMessageUdpWrapper(version, messageBuffer, msg.sender()));\r
+ messageBuffer.retain();\r
+ } else {\r
+ LOGGER.warn("detected version: " + version + " - currently not supported");\r
+ }\r
+ bb.skipBytes(bb.readableBytes());\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+/**\r
+ * Stores names of handlers used in pipeline.\r
+ * \r
+ * @author michal.polkorab\r
+ */\r
+public enum PipelineHandlers {\r
+\r
+ /**\r
+ * Detects switch idle state\r
+ */\r
+ IDLE_HANDLER,\r
+ /**\r
+ * Component for handling TLS frames\r
+ */\r
+ SSL_HANDLER,\r
+ /**\r
+ * Decodes incoming messages into message frames\r
+ */\r
+ OF_FRAME_DECODER,\r
+ /**\r
+ * Detects version of incoming OpenFlow Protocol message\r
+ */\r
+ OF_VERSION_DETECTOR,\r
+ /**\r
+ * Transforms OpenFlow Protocol byte messages into POJOs\r
+ */\r
+ OF_DECODER,\r
+ /**\r
+ * Transforms POJOs into OpenFlow Protocol byte messages\r
+ */\r
+ OF_ENCODER,\r
+ /**\r
+ * Delegates translated POJOs into MessageConsumer\r
+ */\r
+ DELEGATING_INBOUND_HANDLER,\r
+ /**\r
+ * Performs efficient flushing\r
+ */\r
+ CHANNEL_OUTBOUNF_QUEUE,\r
+ /**\r
+ * Decodes incoming messages into message frames\r
+ * and filters them based on version supported\r
+ */\r
+ OF_DATAGRAMPACKET_HANDLER,\r
+ /**\r
+ * Transforms OpenFlow Protocol datagram messages into POJOs\r
+ */\r
+ OF_DATAGRAMPACKET_DECODER,\r
+ /**\r
+ * Transforms POJOs into OpenFlow Protocol datagrams\r
+ */\r
+ OF_DATAGRAMPACKET_ENCODER\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import io.netty.channel.Channel;\r
+import io.netty.channel.ChannelInitializer;\r
+\r
+import org.opendaylight.openflowjava.protocol.api.connection.SwitchConnectionHandler;\r
+import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;\r
+import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory;\r
+import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory;\r
+\r
+/**\r
+ * @param <CHANNEL_TYPE> Channel type\r
+ * @author michal.polkorab\r
+ */\r
+public abstract class ProtocolChannelInitializer<CHANNEL_TYPE extends Channel>\r
+ extends ChannelInitializer<CHANNEL_TYPE> {\r
+\r
+ private SwitchConnectionHandler switchConnectionHandler;\r
+ private long switchIdleTimeout;\r
+ private SerializationFactory serializationFactory;\r
+ private DeserializationFactory deserializationFactory;\r
+ private TlsConfiguration tlsConfiguration;\r
+\r
+ /**\r
+ * @param switchConnectionHandler the switchConnectionHandler to set\r
+ */\r
+ public void setSwitchConnectionHandler(final SwitchConnectionHandler switchConnectionHandler) {\r
+ this.switchConnectionHandler = switchConnectionHandler;\r
+ }\r
+\r
+ /**\r
+ * @param switchIdleTimeout the switchIdleTimeout to set\r
+ */\r
+ public void setSwitchIdleTimeout(final long switchIdleTimeout) {\r
+ this.switchIdleTimeout = switchIdleTimeout;\r
+ }\r
+\r
+ /**\r
+ * @param serializationFactory\r
+ */\r
+ public void setSerializationFactory(final SerializationFactory serializationFactory) {\r
+ this.serializationFactory = serializationFactory;\r
+ }\r
+\r
+ /**\r
+ * @param deserializationFactory\r
+ */\r
+ public void setDeserializationFactory(final DeserializationFactory deserializationFactory) {\r
+ this.deserializationFactory = deserializationFactory;\r
+ }\r
+\r
+ /**\r
+ * @param tlsConfiguration\r
+ */\r
+ public void setTlsConfiguration(TlsConfiguration tlsConfiguration) {\r
+ this.tlsConfiguration = tlsConfiguration;\r
+ }\r
+\r
+ /**\r
+ * @return switch connection handler\r
+ */\r
+ public SwitchConnectionHandler getSwitchConnectionHandler() {\r
+ return switchConnectionHandler;\r
+ }\r
+\r
+ /**\r
+ * @return switch idle timeout\r
+ */\r
+ public long getSwitchIdleTimeout() {\r
+ return switchIdleTimeout;\r
+ }\r
+\r
+ /**\r
+ * @return serialization factory\r
+ */\r
+ public SerializationFactory getSerializationFactory() {\r
+ return serializationFactory;\r
+ }\r
+\r
+ /**\r
+ * @return deserialization factory\r
+ */\r
+ public DeserializationFactory getDeserializationFactory() {\r
+ return deserializationFactory;\r
+ }\r
+\r
+ /**\r
+ * @return TLS configuration\r
+ */\r
+ public TlsConfiguration getTlsConfiguration() {\r
+ return tlsConfiguration;\r
+ }\r
+}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2013 Pantheon Technologies s.r.o. 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.openflowjava.protocol.impl.core;
-
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.group.DefaultChannelGroup;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.handler.ssl.SslHandler;
-
-import java.net.InetAddress;
-import java.util.Iterator;
-import java.util.concurrent.TimeUnit;
-
-import javax.net.ssl.SSLEngine;
-
-import org.opendaylight.openflowjava.protocol.api.connection.SwitchConnectionHandler;
-import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;
-import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactory;
-import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactoryImpl;
-import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade;
-import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory;
-import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Initializes the channel
- * @author michal.polkorab
- */
-public class PublishingChannelInitializer extends ChannelInitializer<SocketChannel> {
-
- /**
- * Enum used for storing names of used components (in pipeline).
- */
- public static enum COMPONENT_NAMES {
-
- /**
- * Detects switch idle state
- */
- IDLE_HANDLER,
- /**
- * Detects TLS connections
- */
- TLS_DETECTOR,
- /**
- * Component for handling TLS frames
- */
- SSL_HANDLER,
- /**
- * Decodes incoming messages into message frames
- */
- OF_FRAME_DECODER,
- /**
- * Detects version of incoming OpenFlow Protocol message
- */
- OF_VERSION_DETECTOR,
- /**
- * Transforms OpenFlow Protocol byte messages into POJOs
- */
- OF_DECODER,
- /**
- * Transforms POJOs into OpenFlow Protocol byte messages
- */
- OF_ENCODER,
- /**
- * Delegates translated POJOs into MessageConsumer
- */
- DELEGATING_INBOUND_HANDLER,
- }
-
- private static final Logger LOGGER = LoggerFactory
- .getLogger(PublishingChannelInitializer.class);
- private final DefaultChannelGroup allChannels;
- private SwitchConnectionHandler switchConnectionHandler;
- private long switchIdleTimeout;
- private SerializationFactory serializationFactory;
- private DeserializationFactory deserializationFactory;
- private ConnectionAdapterFactory connectionAdapterFactory;
- private TlsConfiguration tlsConfiguration ;
-
- /**
- * default ctor
- */
- public PublishingChannelInitializer() {
- this( new DefaultChannelGroup("netty-receiver", null), new ConnectionAdapterFactoryImpl() );
- }
-
- /**
- * Testing Constructor
- *
- */
- protected PublishingChannelInitializer( DefaultChannelGroup channelGroup, ConnectionAdapterFactory connAdaptorFactory ) {
- allChannels = channelGroup ;
- connectionAdapterFactory = connAdaptorFactory ;
- }
-
- @Override
- protected void initChannel(final SocketChannel ch) {
- InetAddress switchAddress = ch.remoteAddress().getAddress();
- int port = ch.localAddress().getPort();
- int remotePort = ch.remoteAddress().getPort();
- LOGGER.info("Incoming connection from (remote address): " + switchAddress.toString()
- + ":" + remotePort + " --> :" + port);
- if (!switchConnectionHandler.accept(switchAddress)) {
- ch.disconnect();
- LOGGER.info("Incoming connection rejected");
- return;
- }
- LOGGER.info("Incoming connection accepted - building pipeline");
- allChannels.add(ch);
- ConnectionFacade connectionFacade = null;
- connectionFacade = connectionAdapterFactory.createConnectionFacade(ch);
- try {
- LOGGER.debug("calling plugin: " + switchConnectionHandler);
- switchConnectionHandler.onSwitchConnected(connectionFacade);
- connectionFacade.checkListeners();
- ch.pipeline().addLast(COMPONENT_NAMES.IDLE_HANDLER.name(), new IdleHandler(switchIdleTimeout, TimeUnit.MILLISECONDS));
-
- // If this channel is configured to support SSL it will only support SSL
- if (tlsConfiguration != null) {
- SslContextFactory sslFactory = new SslContextFactory(tlsConfiguration);
- SSLEngine engine = sslFactory.getServerContext().createSSLEngine();
- engine.setNeedClientAuth(true);
- engine.setUseClientMode(false);
- ch.pipeline().addLast(COMPONENT_NAMES.SSL_HANDLER.name(), new SslHandler(engine));
- }
- ch.pipeline().addLast(COMPONENT_NAMES.OF_FRAME_DECODER.name(), new OFFrameDecoder(connectionFacade));
- ch.pipeline().addLast(COMPONENT_NAMES.OF_VERSION_DETECTOR.name(), new OFVersionDetector());
- OFDecoder ofDecoder = new OFDecoder();
- ofDecoder.setDeserializationFactory(deserializationFactory);
- ch.pipeline().addLast(COMPONENT_NAMES.OF_DECODER.name(), ofDecoder);
- OFEncoder ofEncoder = new OFEncoder();
- ofEncoder.setSerializationFactory(serializationFactory);
- ch.pipeline().addLast(COMPONENT_NAMES.OF_ENCODER.name(), ofEncoder);
- ch.pipeline().addLast(COMPONENT_NAMES.DELEGATING_INBOUND_HANDLER.name(), new DelegatingInboundHandler(connectionFacade));
- if (tlsConfiguration == null) {
- connectionFacade.fireConnectionReadyNotification();
- }
- } catch (Exception e) {
- LOGGER.error("Failed to initialize channel", e);
- ch.close();
- }
- }
-
- /**
- * @return iterator through active connections
- */
- public Iterator<Channel> getConnectionIterator() {
- return allChannels.iterator();
- }
-
- /**
- * @return amount of active channels
- */
- public int size() {
- return allChannels.size();
- }
-
- /**
- * @param switchConnectionHandler the switchConnectionHandler to set
- */
- public void setSwitchConnectionHandler(final SwitchConnectionHandler switchConnectionHandler) {
- this.switchConnectionHandler = switchConnectionHandler;
- }
-
- /**
- * @param switchIdleTimeout the switchIdleTimeout to set
- */
- public void setSwitchIdleTimeout(final long switchIdleTimeout) {
- this.switchIdleTimeout = switchIdleTimeout;
- }
-
- /**
- * @param serializationFactory
- */
- public void setSerializationFactory(final SerializationFactory serializationFactory) {
- this.serializationFactory = serializationFactory;
- }
-
- /**
- * @param deserializationFactory
- */
- public void setDeserializationFactory(final DeserializationFactory deserializationFactory) {
- this.deserializationFactory = deserializationFactory;
- }
-
- /**
- * @param tlsConfiguration
- */
- public void setTlsConfiguration(TlsConfiguration tlsConfiguration) {
- this.tlsConfiguration = tlsConfiguration;
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2013 Pantheon Technologies s.r.o. 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.openflowjava.protocol.impl.core;
+
+import io.netty.channel.Channel;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.ssl.SslHandler;
+
+import java.net.InetAddress;
+import java.util.Iterator;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLEngine;
+
+import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactory;
+import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactoryImpl;
+import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Initializes TCP / TLS channel
+ * @author michal.polkorab
+ */
+public class TcpChannelInitializer extends ProtocolChannelInitializer<SocketChannel> {
+
+ private static final Logger LOGGER = LoggerFactory
+ .getLogger(TcpChannelInitializer.class);
+ private final DefaultChannelGroup allChannels;
+ private ConnectionAdapterFactory connectionAdapterFactory;
+
+ /**
+ * default ctor
+ */
+ public TcpChannelInitializer() {
+ this( new DefaultChannelGroup("netty-receiver", null), new ConnectionAdapterFactoryImpl() );
+ }
+
+ /**
+ * Testing Constructor
+ *
+ */
+ protected TcpChannelInitializer( DefaultChannelGroup channelGroup, ConnectionAdapterFactory connAdaptorFactory ) {
+ allChannels = channelGroup ;
+ connectionAdapterFactory = connAdaptorFactory ;
+ }
+
+ @Override
+ protected void initChannel(final SocketChannel ch) {
+ InetAddress switchAddress = ch.remoteAddress().getAddress();
+ int port = ch.localAddress().getPort();
+ int remotePort = ch.remoteAddress().getPort();
+ LOGGER.info("Incoming connection from (remote address): " + switchAddress.toString()
+ + ":" + remotePort + " --> :" + port);
+ if (!getSwitchConnectionHandler().accept(switchAddress)) {
+ ch.disconnect();
+ LOGGER.info("Incoming connection rejected");
+ return;
+ }
+ LOGGER.info("Incoming connection accepted - building pipeline");
+ allChannels.add(ch);
+ ConnectionFacade connectionFacade = null;
+ connectionFacade = connectionAdapterFactory.createConnectionFacade(ch, null);
+ try {
+ LOGGER.debug("calling plugin: " + getSwitchConnectionHandler());
+ getSwitchConnectionHandler().onSwitchConnected(connectionFacade);
+ connectionFacade.checkListeners();
+ ch.pipeline().addLast(PipelineHandlers.IDLE_HANDLER.name(), new IdleHandler(getSwitchIdleTimeout(), TimeUnit.MILLISECONDS));
+
+ // If this channel is configured to support SSL it will only support SSL
+ if (getTlsConfiguration() != null) {
+ SslContextFactory sslFactory = new SslContextFactory(getTlsConfiguration());
+ SSLEngine engine = sslFactory.getServerContext().createSSLEngine();
+ engine.setNeedClientAuth(true);
+ engine.setUseClientMode(false);
+ ch.pipeline().addLast(PipelineHandlers.SSL_HANDLER.name(), new SslHandler(engine));
+ }
+ ch.pipeline().addLast(PipelineHandlers.OF_FRAME_DECODER.name(), new OFFrameDecoder(connectionFacade));
+ ch.pipeline().addLast(PipelineHandlers.OF_VERSION_DETECTOR.name(), new OFVersionDetector());
+ OFDecoder ofDecoder = new OFDecoder();
+ ofDecoder.setDeserializationFactory(getDeserializationFactory());
+ ch.pipeline().addLast(PipelineHandlers.OF_DECODER.name(), ofDecoder);
+ OFEncoder ofEncoder = new OFEncoder();
+ ofEncoder.setSerializationFactory(getSerializationFactory());
+ ch.pipeline().addLast(PipelineHandlers.OF_ENCODER.name(), ofEncoder);
+ ch.pipeline().addLast(PipelineHandlers.DELEGATING_INBOUND_HANDLER.name(), new DelegatingInboundHandler(connectionFacade));
+ if (getTlsConfiguration() == null) {
+ connectionFacade.fireConnectionReadyNotification();
+ }
+ } catch (Exception e) {
+ LOGGER.error("Failed to initialize channel", e);
+ ch.close();
+ }
+ }
+
+ /**
+ * @return iterator through active connections
+ */
+ public Iterator<Channel> getConnectionIterator() {
+ return allChannels.iterator();
+ }
+
+ /**
+ * @return amount of active channels
+ */
+ public int size() {
+ return allChannels.size();
+ }
+}
\ No newline at end of file
import com.google.common.util.concurrent.SettableFuture;
/**
- * Class implementing server over TCP for handling incoming connections.
+ * Class implementing server over TCP / TLS for handling incoming connections.
*
* @author michal.polkorab
*/
private final SettableFuture<Boolean> isOnlineFuture;
private ThreadConfiguration threadConfig;
- private PublishingChannelInitializer channelInitializer;
+ private TcpChannelInitializer channelInitializer;
/**
* Constructor of TCPHandler that listens on selected port.
LOGGER.debug("address from tcphandler: {}", address);
isOnlineFuture.set(true);
- LOGGER.info("Switch listener started and ready to accept incoming connections on port: {}", port);
+ LOGGER.info("Switch listener started and ready to accept incoming tcp/tls connections on port: {}", port);
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
LOGGER.error("Interrupted while waiting for port {} shutdown", port, e);
/**
* @param channelInitializer
*/
- public void setChannelInitializer(PublishingChannelInitializer channelInitializer) {
+ public void setChannelInitializer(TcpChannelInitializer channelInitializer) {
this.channelInitializer = channelInitializer;
}
- /**
- * @param threadConfig EventLoopGroup configuration
- */
+ @Override
public void setThreadConfig(ThreadConfiguration threadConfig) {
this.threadConfig = threadConfig;
}
--- /dev/null
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import io.netty.channel.socket.nio.NioDatagramChannel;\r
+\r
+/**\r
+ * @author michal.polkorab\r
+ *\r
+ */\r
+public class UdpChannelInitializer extends ProtocolChannelInitializer<NioDatagramChannel> {\r
+\r
+ @Override\r
+ protected void initChannel(NioDatagramChannel ch) throws Exception {\r
+ ch.pipeline().addLast(PipelineHandlers.OF_DATAGRAMPACKET_HANDLER.name(),\r
+ new OFDatagramPacketHandler(getSwitchConnectionHandler()));\r
+ OFDatagramPacketDecoder ofDatagramPacketDecoder = new OFDatagramPacketDecoder();\r
+ ofDatagramPacketDecoder.setDeserializationFactory(getDeserializationFactory());\r
+ ch.pipeline().addLast(PipelineHandlers.OF_DATAGRAMPACKET_DECODER.name(),\r
+ ofDatagramPacketDecoder);\r
+ OFDatagramPacketEncoder ofDatagramPacketEncoder = new OFDatagramPacketEncoder();\r
+ ofDatagramPacketEncoder.setSerializationFactory(getSerializationFactory());\r
+ ch.pipeline().addLast(PipelineHandlers.OF_ENCODER.name(), ofDatagramPacketEncoder);\r
+// connectionFacade.fireConnectionReadyNotification();\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import java.net.InetSocketAddress;\r
+import java.util.HashMap;\r
+\r
+import org.opendaylight.openflowjava.protocol.impl.connection.MessageConsumer;\r
+\r
+/**\r
+ * As UDP communication is handled only by one channel, it is needed\r
+ * to store MessageConsumers, so that we know which consumer handles which channel\r
+\r
+ * @author michal.polkorab\r
+ */\r
+public class UdpConnectionMap {\r
+\r
+ private static HashMap<InetSocketAddress, MessageConsumer> connectionMap = new HashMap<>();\r
+\r
+ /**\r
+ * @param address sender's address\r
+ * @return corresponding MessageConsumer\r
+ */\r
+ public static MessageConsumer getMessageConsumer(InetSocketAddress address) {\r
+ return connectionMap.get(address);\r
+ }\r
+\r
+ /**\r
+ * @param address sender's address\r
+ * @param consumer MessageConsumer to be added / paired with specified address\r
+ */\r
+ public static void addConnection(InetSocketAddress address, MessageConsumer consumer) {\r
+ connectionMap.put(address, consumer);\r
+ }\r
+\r
+ /**\r
+ * @param address sender's address\r
+ */\r
+ public static void removeConnection(InetSocketAddress address) {\r
+ connectionMap.remove(address);\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import io.netty.bootstrap.Bootstrap;\r
+import io.netty.channel.ChannelFuture;\r
+import io.netty.channel.ChannelOption;\r
+import io.netty.channel.EventLoopGroup;\r
+import io.netty.channel.nio.NioEventLoopGroup;\r
+import io.netty.channel.socket.nio.NioDatagramChannel;\r
+import io.netty.util.concurrent.GenericFutureListener;\r
+\r
+import java.net.InetAddress;\r
+import java.net.InetSocketAddress;\r
+\r
+import org.opendaylight.openflowjava.protocol.api.connection.ThreadConfiguration;\r
+import org.opendaylight.openflowjava.protocol.impl.connection.ServerFacade;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import com.google.common.util.concurrent.ListenableFuture;\r
+import com.google.common.util.concurrent.SettableFuture;\r
+\r
+/**\r
+ * Class implementing server over UDP for handling incoming connections.\r
+ * \r
+ * @author michal.polkorab\r
+ */\r
+public final class UdpHandler implements ServerFacade {\r
+\r
+ private static final Logger LOGGER = LoggerFactory\r
+ .getLogger(UdpHandler.class);\r
+ private int port;\r
+ private String address;\r
+ private EventLoopGroup group;\r
+ private final InetAddress startupAddress;\r
+ private final SettableFuture<Boolean> isOnlineFuture;\r
+ private UdpChannelInitializer channelInitializer;\r
+ private ThreadConfiguration threadConfig;\r
+\r
+ /**\r
+ * Constructor of UdpHandler that listens on selected port.\r
+ *\r
+ * @param port listening port of UdpHandler server\r
+ */\r
+ public UdpHandler(final int port) {\r
+ this(null, port);\r
+ }\r
+\r
+ /**\r
+ * Constructor of UdpHandler that listens on selected address and port.\r
+ * @param address listening address of UdpHandler server\r
+ * @param port listening port of UdpHandler server\r
+ */\r
+ public UdpHandler(final InetAddress address, final int port) {\r
+ this.port = port;\r
+ this.startupAddress = address;\r
+ isOnlineFuture = SettableFuture.create();\r
+ }\r
+\r
+ @Override\r
+ public void run() {\r
+ if (threadConfig != null) {\r
+ group = new NioEventLoopGroup(threadConfig.getWorkerThreadCount());\r
+ } else {\r
+ group = new NioEventLoopGroup();\r
+ }\r
+ final ChannelFuture f;\r
+ try {\r
+ Bootstrap b = new Bootstrap();\r
+ b.group(group)\r
+ .channel(NioDatagramChannel.class)\r
+ .option(ChannelOption.SO_BROADCAST, false)\r
+ .handler(channelInitializer);\r
+\r
+ if (startupAddress != null) {\r
+ f = b.bind(startupAddress.getHostAddress(), port).sync();\r
+ } else {\r
+ f = b.bind(port).sync();\r
+ }\r
+ } catch (InterruptedException e) {\r
+ LOGGER.error("Interrupted while binding port {}", port, e);\r
+ return;\r
+ }\r
+\r
+ try {\r
+ InetSocketAddress isa = (InetSocketAddress) f.channel().localAddress();\r
+ this.address = isa.getHostString();\r
+\r
+ // Update port, as it may have been specified as 0\r
+ this.port = isa.getPort();\r
+\r
+ LOGGER.debug("Address from udpHandler: {}", address);\r
+ isOnlineFuture.set(true);\r
+ LOGGER.info("Switch listener started and ready to accept incoming udp connections on port: {}", port);\r
+ f.channel().closeFuture().sync();\r
+ } catch (InterruptedException e) {\r
+ LOGGER.error("Interrupted while waiting for port {} shutdown", port, e);\r
+ } finally {\r
+ shutdown();\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public ListenableFuture<Boolean> shutdown() {\r
+ final SettableFuture<Boolean> result = SettableFuture.create();\r
+ group.shutdownGracefully().addListener(new GenericFutureListener<io.netty.util.concurrent.Future<Object>>() {\r
+\r
+ @Override\r
+ public void operationComplete(\r
+ final io.netty.util.concurrent.Future<Object> downResult) throws Exception {\r
+ result.set(downResult.isSuccess());\r
+ if (downResult.cause() != null) {\r
+ result.setException(downResult.cause());\r
+ }\r
+ }\r
+\r
+ });\r
+ return result;\r
+ }\r
+\r
+ @Override\r
+ public ListenableFuture<Boolean> getIsOnlineFuture() {\r
+ return isOnlineFuture;\r
+ }\r
+\r
+ /**\r
+ * @return the port\r
+ */\r
+ public int getPort() {\r
+ return port;\r
+ }\r
+\r
+ /**\r
+ * @param channelInitializer\r
+ */\r
+ public void setChannelInitializer(UdpChannelInitializer channelInitializer) {\r
+ this.channelInitializer = channelInitializer;\r
+ }\r
+\r
+ @Override\r
+ public void setThreadConfig(ThreadConfiguration threadConfig) {\r
+ this.threadConfig = threadConfig;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.core;\r
+\r
+import io.netty.buffer.ByteBuf;\r
+\r
+import java.net.InetSocketAddress;\r
+\r
+/**\r
+ * Wraps received messages (includes version) and sender address\r
+ \r
+ * @author michal.polkorab\r
+ */\r
+public class VersionMessageUdpWrapper extends VersionMessageWrapper {\r
+\r
+ private InetSocketAddress address;\r
+\r
+ /**\r
+ * @param version Openflow wire version\r
+ * @param messageBuffer ByteBuf containing binary message\r
+ * @param address sender address\r
+ */\r
+ public VersionMessageUdpWrapper(short version, ByteBuf messageBuffer, InetSocketAddress address) {\r
+ super(version, messageBuffer);\r
+ this.address = address;\r
+ }\r
+\r
+ /**\r
+ * @return sender address\r
+ */\r
+ public InetSocketAddress getAddress() {\r
+ return address;\r
+ }\r
+}
\ No newline at end of file
import org.opendaylight.openflowjava.protocol.impl.connection.SwitchConnectionProviderImpl;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.TransportProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
final long switchIdleTimeout = getSwitchIdleTimeout();
final Tls tlsConfig = getTls();
final Threads threads = getThreads();
+ final TransportProtocol transportProtocol = getTransportProtocol();
return new ConnectionConfiguration() {
@Override
}
@Override
public Object getTransferProtocol() {
- // TODO Auto-generated method stub
- return null;
+ return transportProtocol;
}
@Override
public TlsConfiguration getTlsConfiguration() {
- if (tlsConfig == null) {
+ if (tlsConfig == null || !(TransportProtocol.TLS.equals(transportProtocol))) {
return null;
}
return new TlsConfiguration() {
description "address of local listening interface";
type ietf-inet:ip-address;
}
+ leaf transport-protocol {
+ description "Transport protocol used for communication.";
+ type of-config:transport-protocol;
+ mandatory true;
+ }
leaf switch-idle-timeout {
description "idle timeout in [ms]";
type uint32;
public class PublishingChannelInitializerFactoryTest {
TlsConfiguration tlsConfiguration ;
- PublishingChannelInitializerFactory factory;
+ ChannelInitializerFactory factory;
private final long switchIdleTimeOut = 60;
@Mock SwitchConnectionHandler switchConnectionHandler ;
@Mock SerializationFactory serializationFactory;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- factory = new PublishingChannelInitializerFactory();
+ factory = new ChannelInitializerFactory();
tlsConfiguration = new TlsConfigurationImpl(KeystoreType.JKS, "/exemplary-ctlTrustStore",
PathType.CLASSPATH, KeystoreType.JKS, "/exemplary-ctlKeystore", PathType.CLASSPATH);
factory.setDeserializationFactory(deserializationFactory);
}
/**
- * Test {@link PublishingChannelInitializer} creation
+ * Test {@link TcpChannelInitializer} creation
*/
@Test
public void testCreatePublishingChannelInitializer() {
- PublishingChannelInitializer initializer = factory.createPublishingChannelInitializer() ;
+ TcpChannelInitializer initializer = factory.createPublishingChannelInitializer() ;
assertNotNull( initializer );
}
}
\ No newline at end of file
import org.opendaylight.openflowjava.protocol.api.connection.TlsConfigurationImpl;
import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionAdapterFactory;
import org.opendaylight.openflowjava.protocol.impl.connection.ConnectionFacade;
-import org.opendaylight.openflowjava.protocol.impl.core.PublishingChannelInitializer.COMPONENT_NAMES;
import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory;
import org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType;
TlsConfiguration tlsConfiguration ;
InetSocketAddress inetSockAddr;
- PublishingChannelInitializer pubChInitializer ;
+ TcpChannelInitializer pubChInitializer ;
/**
* Sets up test environment
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- pubChInitializer= new PublishingChannelInitializer(mockChGrp, mockConnAdaptorFactory) ;
+ pubChInitializer= new TcpChannelInitializer(mockChGrp, mockConnAdaptorFactory) ;
pubChInitializer.setSerializationFactory(mockSerializationFactory);
pubChInitializer.setDeserializationFactory(mockDeserializationFactory);
pubChInitializer.setSwitchIdleTimeout(1) ;
inetSockAddr = new InetSocketAddress(InetAddress.getLocalHost(), 8675 ) ;
- when(mockConnAdaptorFactory.createConnectionFacade(mockSocketCh))
+ when(mockConnAdaptorFactory.createConnectionFacade(mockSocketCh, null))
.thenReturn(mockConnFacade);
when(mockSocketCh.remoteAddress()).thenReturn(inetSockAddr) ;
when(mockSocketCh.localAddress()).thenReturn(inetSockAddr) ;
pubChInitializer.initChannel(mockSocketCh) ;
verifyCommonHandlers();
- verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.SSL_HANDLER.name()),any(SslHandler.class)) ;
+ verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.SSL_HANDLER.name()),any(SslHandler.class)) ;
}
/**
pubChInitializer.initChannel(mockSocketCh) ;
verifyCommonHandlers();
- verify(mockChPipeline, times(0)).addLast(eq(COMPONENT_NAMES.SSL_HANDLER.name()),any(SslHandler.class)) ;
+ verify(mockChPipeline, times(0)).addLast(eq(PipelineHandlers.SSL_HANDLER.name()),any(SslHandler.class)) ;
}
/**
* All paths should install these six handlers:
*/
private void verifyCommonHandlers() {
- verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.IDLE_HANDLER.name()),any(IdleHandler.class)) ;
- verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.OF_DECODER.name()),any(OFDecoder.class)) ;
- verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.OF_ENCODER.name()),any(OFEncoder.class)) ;
- verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.OF_FRAME_DECODER.name()),any(OFFrameDecoder.class)) ;
- verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.OF_VERSION_DETECTOR.name()),any(OFVersionDetector.class)) ;
- verify(mockChPipeline, times(1)).addLast(eq(COMPONENT_NAMES.DELEGATING_INBOUND_HANDLER.name()),any(DelegatingInboundHandler.class));
+ verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.IDLE_HANDLER.name()),any(IdleHandler.class)) ;
+ verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.OF_DECODER.name()),any(OFDecoder.class)) ;
+ verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.OF_ENCODER.name()),any(OFEncoder.class)) ;
+ verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.OF_FRAME_DECODER.name()),any(OFFrameDecoder.class)) ;
+ verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.OF_VERSION_DETECTOR.name()),any(OFVersionDetector.class)) ;
+ verify(mockChPipeline, times(1)).addLast(eq(PipelineHandlers.DELEGATING_INBOUND_HANDLER.name()),any(DelegatingInboundHandler.class));
assertEquals(1, pubChInitializer.size()) ;
}
}
private InetAddress serverAddress = InetAddress.getLoopbackAddress() ;
@Mock ChannelHandlerContext mockChHndlrCtx ;
- @Mock PublishingChannelInitializer mockChannelInitializer;
+ @Mock TcpChannelInitializer mockChannelInitializer;
@Mock SwitchConnectionHandler mockSwitchConnHndler ;
@Mock SerializationFactory mockSerializationFactory ;
@Mock DeserializationFactory mockDeserializationFactory ;
import org.opendaylight.openflowjava.protocol.api.connection.ConnectionConfiguration;
import org.opendaylight.openflowjava.protocol.api.connection.ThreadConfiguration;
import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.TransportProtocol;
/**
* @author michal.polkorab
private TlsConfiguration tlsConfig;
private long switchIdleTimeout;
private ThreadConfiguration threadConfig;
+ private TransportProtocol protocol;
/**
* Creates {@link ConnectionConfigurationImpl}
return transferProtocol;
}
+ /**
+ * Used for testing - sets transport protocol
+ * @param protocol
+ */
+ public void setTransferProtocol(TransportProtocol protocol) {
+ this.transferProtocol = protocol;
+ }
+
@Override
public long getSwitchIdleTimeout() {
return switchIdleTimeout;
import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;
import org.opendaylight.openflowjava.protocol.api.connection.TlsConfigurationImpl;
import org.opendaylight.openflowjava.protocol.impl.clients.ClientEvent;
+import org.opendaylight.openflowjava.protocol.impl.clients.OFClient;
import org.opendaylight.openflowjava.protocol.impl.clients.ScenarioFactory;
import org.opendaylight.openflowjava.protocol.impl.clients.ScenarioHandler;
import org.opendaylight.openflowjava.protocol.impl.clients.SendEvent;
import org.opendaylight.openflowjava.protocol.impl.clients.SimpleClient;
import org.opendaylight.openflowjava.protocol.impl.clients.SleepEvent;
+import org.opendaylight.openflowjava.protocol.impl.clients.UdpSimpleClient;
import org.opendaylight.openflowjava.protocol.impl.clients.WaitForMessageEvent;
import org.opendaylight.openflowjava.protocol.impl.connection.SwitchConnectionProviderImpl;
import org.opendaylight.openflowjava.protocol.impl.core.TcpHandler;
+import org.opendaylight.openflowjava.protocol.impl.core.UdpHandler;
import org.opendaylight.openflowjava.util.ByteBufUtils;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.KeystoreType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.PathType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.config.rev140630.TransportProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
.getLogger(IntegrationTest.class);
private static int port;
- private TlsConfiguration tlsConfiguration ;
+ private TlsConfiguration tlsConfiguration;
private static final int SWITCH_IDLE_TIMEOUT = 2000;
private static final long CONNECTION_TIMEOUT = 2000;
private InetAddress startupAddress;
private ConnectionConfigurationImpl connConfig;
/**
- * @param secured true if an encrypted connection should be used
+ * @param protocol communication protocol to be used during test
* @throws Exception
*/
- public void setUp(boolean secured) throws Exception {
+ public void setUp(TransportProtocol protocol) throws Exception {
LOGGER.debug("\n starting test -------------------------------");
String currentDir = System.getProperty("user.dir");
LOGGER.debug("Current dir using System:" +currentDir);
startupAddress = InetAddress.getLocalHost();
- if (secured) {
+ tlsConfiguration = null;
+ if (protocol.equals(TransportProtocol.TLS)) {
tlsConfiguration = new TlsConfigurationImpl(KeystoreType.JKS,
"/selfSignedSwitch", PathType.CLASSPATH, KeystoreType.JKS,
"/selfSignedController", PathType.CLASSPATH) ;
- connConfig = new ConnectionConfigurationImpl(startupAddress, 0, tlsConfiguration, SWITCH_IDLE_TIMEOUT);
- } else {
- connConfig = new ConnectionConfigurationImpl(startupAddress, 0, null, SWITCH_IDLE_TIMEOUT);
}
+ connConfig = new ConnectionConfigurationImpl(startupAddress, 0, tlsConfiguration, SWITCH_IDLE_TIMEOUT);
+ connConfig.setTransferProtocol(protocol);
mockPlugin = new MockPlugin();
switchConnectionProvider = new SwitchConnectionProviderImpl();
switchConnectionProvider.setSwitchConnectionHandler(mockPlugin);
switchConnectionProvider.setConfiguration(connConfig);
switchConnectionProvider.startup().get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS);
- TcpHandler tcpHandler = (TcpHandler) switchConnectionProvider.getServerFacade();
- port = tcpHandler.getPort();
+ if (protocol.equals(TransportProtocol.TCP) || protocol.equals(TransportProtocol.TLS)) {
+ TcpHandler tcpHandler = (TcpHandler) switchConnectionProvider.getServerFacade();
+ port = tcpHandler.getPort();
+ } else {
+ UdpHandler udpHandler = (UdpHandler) switchConnectionProvider.getServerFacade();
+ port = udpHandler.getPort();
+ }
}
/**
public void tearDown() throws Exception {
switchConnectionProvider.close();
LOGGER.debug("\n ending test -------------------------------");
-
}
/**
*/
@Test
public void testHandshake() throws Exception {
- setUp(false);
+ setUp(TransportProtocol.TCP);
int amountOfCLients = 1;
Stack<ClientEvent> scenario = ScenarioFactory.createHandshakeScenario();
ScenarioHandler handler = new ScenarioHandler(scenario);
- List<SimpleClient> clients = createAndStartClient(amountOfCLients, handler, false);
- SimpleClient firstClient = clients.get(0);
+ List<OFClient> clients = createAndStartClient(amountOfCLients, handler, TransportProtocol.TCP);
+ OFClient firstClient = clients.get(0);
firstClient.getScenarioDone().get();
Thread.sleep(1000);
}
/**
- * Library integration and communication test with handshake
+ * Library integration and secured communication test with handshake
* @throws Exception
*/
@Test
public void testTlsHandshake() throws Exception {
- setUp(true);
+ setUp(TransportProtocol.TLS);
int amountOfCLients = 1;
Stack<ClientEvent> scenario = ScenarioFactory.createHandshakeScenario();
ScenarioHandler handler = new ScenarioHandler(scenario);
- List<SimpleClient> clients = createAndStartClient(amountOfCLients, handler, true);
- SimpleClient firstClient = clients.get(0);
+ List<OFClient> clients = createAndStartClient(amountOfCLients, handler, TransportProtocol.TLS);
+ OFClient firstClient = clients.get(0);
firstClient.getScenarioDone().get();
Thread.sleep(1000);
*/
@Test
public void testHandshakeAndEcho() throws Exception {
- setUp(false);
+ setUp(TransportProtocol.TCP);
int amountOfCLients = 1;
Stack<ClientEvent> scenario = ScenarioFactory.createHandshakeScenario();
scenario.add(0, new SleepEvent(1000));
scenario.add(0, new SleepEvent(1000));
scenario.add(0, new WaitForMessageEvent(ByteBufUtils.hexStringToBytes("04 03 00 08 00 00 00 04")));
ScenarioHandler handler = new ScenarioHandler(scenario);
- List<SimpleClient> clients = createAndStartClient(amountOfCLients, handler, false);
- SimpleClient firstClient = clients.get(0);
+ List<OFClient> clients = createAndStartClient(amountOfCLients, handler, TransportProtocol.TCP);
+ OFClient firstClient = clients.get(0);
firstClient.getScenarioDone().get();
LOGGER.debug("testHandshakeAndEcho() Finished") ;
}
/**
- * Library integration and communication test with handshake + echo exchange
+ * Library integration and secured communication test with handshake + echo exchange
* @throws Exception
*/
@Test
public void testTlsHandshakeAndEcho() throws Exception {
- setUp(true);
+ setUp(TransportProtocol.TLS);
int amountOfCLients = 1;
Stack<ClientEvent> scenario = ScenarioFactory.createHandshakeScenario();
scenario.add(0, new SleepEvent(1000));
scenario.add(0, new SleepEvent(1000));
scenario.add(0, new WaitForMessageEvent(ByteBufUtils.hexStringToBytes("04 03 00 08 00 00 00 04")));
ScenarioHandler handler = new ScenarioHandler(scenario);
- List<SimpleClient> clients = createAndStartClient(amountOfCLients, handler, true);
- SimpleClient firstClient = clients.get(0);
+ List<OFClient> clients = createAndStartClient(amountOfCLients, handler, TransportProtocol.TLS);
+ OFClient firstClient = clients.get(0);
firstClient.getScenarioDone().get();
LOGGER.debug("testTlsHandshakeAndEcho() Finished") ;
}
/**
- * Library integration and communication test (with virtual machine)
- * @throws Exception
- */
- //@Test
- public void testCommunicationWithVM() throws Exception {
- mockPlugin.getFinishedFuture().get();
+ * Library udp integration and communication test with handshake + echo exchange
+ * @throws Exception
+ */
+ @Test
+ public void testUdpHandshakeAndEcho() throws Exception {
+ setUp(TransportProtocol.UDP);
+ int amountOfCLients = 1;
+ Stack<ClientEvent> scenario = ScenarioFactory.createHandshakeScenario();
+ scenario.add(0, new SleepEvent(1000));
+ scenario.add(0, new SendEvent(ByteBufUtils.hexStringToBytes("04 02 00 08 00 00 00 04")));
+ scenario.add(0, new SleepEvent(1000));
+ scenario.add(0, new WaitForMessageEvent(ByteBufUtils.hexStringToBytes("04 03 00 08 00 00 00 04")));
+ ScenarioHandler handler = new ScenarioHandler(scenario);
+ List<OFClient> clients = createAndStartClient(amountOfCLients, handler, TransportProtocol.UDP);
+ OFClient firstClient = clients.get(0);
+ firstClient.getScenarioDone().get();
+
+ LOGGER.debug("testUdpHandshakeAndEcho() Finished") ;
+ }
+
+ /**
+ * Library integration and communication test (with virtual machine)
+ * @throws Exception
+ */
+ //@Test
+ public void testCommunicationWithVM() throws Exception {
+ mockPlugin.getFinishedFuture().get();
}
/**
* @param amountOfCLients
- * @param secured true if encrypted connection should be used
+ * @param protocol true if encrypted connection should be used
* @return new clients up and running
* @throws ExecutionException if some client could not start
*/
- private List<SimpleClient> createAndStartClient(int amountOfCLients, ScenarioHandler scenarioHandler,
- boolean secured) throws ExecutionException {
- List<SimpleClient> clientsHorde = new ArrayList<>();
+ private List<OFClient> createAndStartClient(int amountOfCLients, ScenarioHandler scenarioHandler,
+ TransportProtocol protocol) throws ExecutionException {
+ List<OFClient> clientsHorde = new ArrayList<>();
for (int i = 0; i < amountOfCLients; i++) {
LOGGER.debug("startup address in createclient: " + startupAddress.getHostAddress());
- SimpleClient sc = new SimpleClient(startupAddress.getHostAddress(), port);
- sc.setSecuredClient(secured);
+ OFClient sc = null;
+ if (protocol.equals(TransportProtocol.TCP)) {
+ sc = new SimpleClient(startupAddress.getHostAddress(), port);
+ sc.setSecuredClient(false);
+ } else if (protocol.equals(TransportProtocol.TLS)) {
+ sc = new SimpleClient(startupAddress.getHostAddress(), port);
+ sc.setSecuredClient(true);
+ } else {
+ sc = new UdpSimpleClient(startupAddress.getHostAddress(), port);
+ }
sc.setScenarioHandler(scenarioHandler);
clientsHorde.add(sc);
- sc.start();
+ sc.run();
}
- for (SimpleClient sc : clientsHorde) {
+ for (OFClient sc : clientsHorde) {
try {
sc.getIsOnlineFuture().get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (Exception e) {
--- /dev/null
+/*\r
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.openflowjava.protocol.impl.clients;\r
+\r
+import com.google.common.util.concurrent.SettableFuture;\r
+\r
+/**\r
+ * Unifying interface for simple clients / switch simulators\r
+ * \r
+ * @author michal.polkorab\r
+ */\r
+public interface OFClient extends Runnable {\r
+\r
+ /**\r
+ * @return the isOnlineFuture which is set when client is started\r
+ */\r
+ public SettableFuture<Boolean> getIsOnlineFuture();\r
+\r
+ /**\r
+ * @return the scenarioDone when scenario is successfully finished\r
+ */\r
+ public SettableFuture<Boolean> getScenarioDone();\r
+\r
+ /**\r
+ * @param scenario list of desired actions\r
+ */\r
+ public void setScenarioHandler(ScenarioHandler scenario);\r
+\r
+ /**\r
+ * @param securedClient true is client should use encrypted communication,\r
+ * false otherwise\r
+ */\r
+ public void setSecuredClient(boolean securedClient);\r
+}
\ No newline at end of file
*
* @author michal.polkorab
*/
-public class SimpleClient extends Thread {
+public class SimpleClient implements OFClient {
private static final Logger LOGGER = LoggerFactory.getLogger(SimpleClient.class);
private final String host;
return group.shutdownGracefully();
}
- /**
- * @param securedClient
- */
+ @Override
public void setSecuredClient(boolean securedClient) {
this.securedClient = securedClient;
}
sc = new SimpleClient(host, port);
sc.setSecuredClient(Boolean.parseBoolean(args[2]));
}
- sc.start();
-
+ sc.run();
}
-
- /**
- * @return the isOnlineFuture
- */
+
+ @Override
public SettableFuture<Boolean> getIsOnlineFuture() {
return isOnlineFuture;
}
-
- /**
- * @return the scenarioDone
- */
+
+ @Override
public SettableFuture<Boolean> getScenarioDone() {
return scenarioDone;
}
-
- /**
- * @param scenario list of wanted actions
- */
+
+ @Override
public void setScenarioHandler(ScenarioHandler scenario) {
this.scenarioHandler = scenario;
}
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
-import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslHandler;
import javax.net.ssl.SSLEngine;
*
* @author michal.polkorab
*/
-public class SimpleClientInitializer extends ChannelInitializer<SocketChannel> {
+public class SimpleClientInitializer extends ChannelInitializer<NioSocketChannel> {
private SettableFuture<Boolean> isOnlineFuture;
private boolean secured;
}
@Override
- public void initChannel(SocketChannel ch) throws Exception {
+ public void initChannel(NioSocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
if (secured) {
SSLEngine engine = ClientSslContextFactory.getClientContext()
--- /dev/null
+/*
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. 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.openflowjava.protocol.impl.clients;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioDatagramChannel;
+import io.netty.util.concurrent.Future;
+
+import java.net.InetAddress;
+import java.util.concurrent.ExecutionException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+/**
+ * Simple client for testing purposes
+ *
+ * @author michal.polkorab
+ */
+public class UdpSimpleClient implements OFClient {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(UdpSimpleClient.class);
+ private final String host;
+ private final int port;
+ private EventLoopGroup group;
+ private SettableFuture<Boolean> isOnlineFuture;
+ private SettableFuture<Boolean> scenarioDone;
+ private UdpSimpleClientInitializer clientInitializer;
+ private ScenarioHandler scenarioHandler;
+
+ /**
+ * Constructor of class
+ *
+ * @param host address of host
+ * @param port host listening port
+ */
+ public UdpSimpleClient(String host, int port) {
+ this.host = host;
+ this.port = port;
+ init();
+ }
+
+ private void init() {
+ isOnlineFuture = SettableFuture.create();
+ scenarioDone = SettableFuture.create();
+ }
+
+ /**
+ * Starting class of {@link UdpSimpleClient}
+ */
+ @Override
+ public void run() {
+ group = new NioEventLoopGroup();
+ clientInitializer = new UdpSimpleClientInitializer(isOnlineFuture);
+ clientInitializer.setScenario(scenarioHandler);
+ try {
+ Bootstrap b = new Bootstrap();
+ b.group(group)
+ .channel(NioDatagramChannel.class)
+ .option(ChannelOption.SO_BROADCAST, false)
+ .handler(clientInitializer);
+
+ b.connect(host, port).sync();
+
+ synchronized (scenarioHandler) {
+ LOGGER.debug("WAITING FOR SCENARIO");
+ scenarioHandler.wait();
+ }
+ } catch (Exception ex) {
+ LOGGER.error(ex.getMessage(), ex);
+ } finally {
+ LOGGER.debug("shutting down");
+ try {
+ group.shutdownGracefully().get();
+ LOGGER.debug("shutdown succesful");
+ } catch (InterruptedException | ExecutionException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+ scenarioDone.set(true);
+ }
+
+ /**
+ * @return close future
+ */
+ public Future<?> disconnect() {
+ LOGGER.debug("disconnecting client");
+ return group.shutdownGracefully();
+ }
+
+ /**
+ * Sets up {@link UdpSimpleClient} and fires run()
+ *
+ * @param args
+ * @throws Exception
+ */
+ public static void main(String[] args) throws Exception {
+ String host;
+ int port;
+ UdpSimpleClient sc;
+ if (args.length != 2) {
+ LOGGER.error("Usage: " + UdpSimpleClient.class.getSimpleName()
+ + " <host> <port>");
+ LOGGER.error("Trying to use default setting.");
+ InetAddress ia = InetAddress.getLocalHost();
+ InetAddress[] all = InetAddress.getAllByName(ia.getHostName());
+ host = all[0].getHostAddress();
+ port = 6633;
+ sc = new UdpSimpleClient(host, port);
+ } else {
+ host = args[0];
+ port = Integer.parseInt(args[1]);
+ sc = new UdpSimpleClient(host, port);
+ }
+ sc.run();
+
+ }
+
+ @Override
+ public SettableFuture<Boolean> getIsOnlineFuture() {
+ return isOnlineFuture;
+ }
+
+ @Override
+ public SettableFuture<Boolean> getScenarioDone() {
+ return scenarioDone;
+ }
+
+ @Override
+ public void setScenarioHandler(ScenarioHandler scenario) {
+ this.scenarioHandler = scenario;
+ }
+
+ @Override
+ public void setSecuredClient(boolean securedClient) {
+ // TODO: Finish implementation when DTLS is supported
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. 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.openflowjava.protocol.impl.clients;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.socket.DatagramPacket;
+import io.netty.handler.codec.MessageToMessageDecoder;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class for decoding incoming udp messages into message frames.
+ *
+ * @author michal.polkorab
+ */
+public class UdpSimpleClientFramer extends MessageToMessageDecoder<DatagramPacket> {
+
+ /** Length of OpenFlow 1.3 header */
+ public static final byte LENGTH_OF_HEADER = 8;
+ private static final byte LENGTH_INDEX_IN_HEADER = 2;
+ private static final Logger LOGGER = LoggerFactory.getLogger(UdpSimpleClientFramer.class);
+
+ /**
+ * Constructor of class.
+ */
+ public UdpSimpleClientFramer() {
+ LOGGER.trace("Creating OFFrameDecoder");
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ LOGGER.warn("Unexpected exception from downstream.", cause);
+ ctx.close();
+ }
+
+ @Override
+ protected void decode(ChannelHandlerContext chc, DatagramPacket msg, List<Object> list) throws Exception {
+ ByteBuf bb = msg.content();
+ if (bb.readableBytes() < LENGTH_OF_HEADER) {
+ LOGGER.debug("skipping bb - too few data for header: " + bb.readableBytes());
+ return;
+ }
+
+ int length = bb.getUnsignedShort(bb.readerIndex() + LENGTH_INDEX_IN_HEADER);
+ if (bb.readableBytes() < length) {
+ LOGGER.debug("skipping bb - too few data for msg: " +
+ bb.readableBytes() + " < " + length);
+ return;
+ }
+ LOGGER.debug("OF Protocol message received, type:{}", bb.getByte(bb.readerIndex() + 1));
+
+ ByteBuf messageBuffer = bb.slice(bb.readerIndex(), length);
+ list.add(messageBuffer);
+ messageBuffer.retain();
+ bb.skipBytes(length);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2014 Pantheon Technologies s.r.o. 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.openflowjava.protocol.impl.clients;
+
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.nio.NioDatagramChannel;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+/** Initializes udp pipeline
+ *
+ * @author michal.polkorab
+ */
+public class UdpSimpleClientInitializer extends ChannelInitializer<NioDatagramChannel> {
+
+ private SettableFuture<Boolean> isOnlineFuture;
+ private ScenarioHandler scenarioHandler;
+
+ /**
+ * @param isOnlineFuture future notifier of connected channel
+ */
+ public UdpSimpleClientInitializer(SettableFuture<Boolean> isOnlineFuture) {
+ this.isOnlineFuture = isOnlineFuture;
+ }
+
+ @Override
+ public void initChannel(NioDatagramChannel ch) throws Exception {
+ ChannelPipeline pipeline = ch.pipeline();
+ SimpleClientHandler simpleClientHandler = new SimpleClientHandler(isOnlineFuture, scenarioHandler);
+ simpleClientHandler.setScenario(scenarioHandler);
+ pipeline.addLast("framer", new UdpSimpleClientFramer());
+ pipeline.addLast("handler", simpleClientHandler);
+ isOnlineFuture = null;
+ }
+
+ /**
+ * @param scenarioHandler handler of scenario events
+ */
+ public void setScenario(ScenarioHandler scenarioHandler) {
+ this.scenarioHandler = scenarioHandler;
+ }
+}
\ No newline at end of file