From edd9ab5008fff039873cb208eeaa7fc64d1a2bd4 Mon Sep 17 00:00:00 2001 From: Andrej Leitner Date: Tue, 4 Oct 2016 17:38:03 +0200 Subject: [PATCH] Allow any hello mesage and extend hello support for v1.4, v1.5 - accept any (also unsupported version) hello message for handshake and negotiation - added version assignable factory - made HelloFactory version assignable - register deserializers for hello message of v1.4, v 1.5 - update logging - update tests Resolves: Bug 6805, Bug 4255 Change-Id: I228108908ecfb2c3a7f8afa866790b7c193f046c Signed-off-by: Andrej Leitner --- .../protocol/api/keys/MessageCodeKey.java | 8 +++ .../protocol/api/util/EncodeConstants.java | 13 +++- .../impl/core/DelegatingInboundHandler.java | 7 +- .../protocol/impl/core/OFDecoder.java | 14 ++-- .../protocol/impl/core/OFEncoder.java | 4 +- .../protocol/impl/core/OFFrameDecoder.java | 6 +- .../protocol/impl/core/OFVersionDetector.java | 23 +++--- .../impl/core/TcpChannelInitializer.java | 18 ++--- .../core/connection/ChannelOutboundQueue.java | 2 +- .../connection/ConnectionAdapterImpl.java | 23 +++--- .../MessageDeserializerInitializer.java | 25 ++++--- .../TypeToClassMapInitializer.java | 35 +++++---- .../factories/HelloMessageFactory.java | 13 ++-- .../SimpleDeserializerRegistryHelper.java | 19 ++--- .../impl/util/VersionAssignableFactory.java | 36 ++++++++++ .../impl/core/OFVersionDetectorTest.java | 72 +++++-------------- .../TypeToClassMapInitializerTest.java | 14 ++-- .../factories/HelloMessageFactoryTest.java | 55 +++++++------- .../protocol/impl/util/BufferHelper.java | 10 ++- .../util/DefaultDeserializerFactoryTest.java | 50 +++++++++++++ 20 files changed, 268 insertions(+), 179 deletions(-) create mode 100644 openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/util/VersionAssignableFactory.java create mode 100644 openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/util/DefaultDeserializerFactoryTest.java diff --git a/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/keys/MessageCodeKey.java b/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/keys/MessageCodeKey.java index 6597c19a..566b3623 100644 --- a/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/keys/MessageCodeKey.java +++ b/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/keys/MessageCodeKey.java @@ -28,6 +28,14 @@ public class MessageCodeKey { this.clazz = clazz; } + public int getMsgType() { + return this.msgType; + } + + public Class getClazz() { + return this.clazz; + } + @Override public int hashCode() { final int prime = 31; diff --git a/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/util/EncodeConstants.java b/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/util/EncodeConstants.java index 82a09282..dad7b76f 100644 --- a/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/util/EncodeConstants.java +++ b/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/util/EncodeConstants.java @@ -9,7 +9,7 @@ package org.opendaylight.openflowjava.protocol.api.util; /** - * Stores common constants + * Stores common constants. * @author michal.polkorab */ public abstract class EncodeConstants { @@ -20,6 +20,14 @@ public abstract class EncodeConstants { public static final byte OF10_VERSION_ID = 0x01; /** OpenFlow v1.3 wire protocol number */ public static final byte OF13_VERSION_ID = 0x04; + /** OpenFlow v1.4 wire protocol number */ + public static final byte OF14_VERSION_ID = 0x05; + /** OpenFlow v1.5 wire protocol number */ + public static final byte OF15_VERSION_ID = 0x06; + /** OpenFlow Hello message type value */ + public static final byte OF_HELLO_MESSAGE_TYPE_VALUE = 0; + /** OpenFlow PacketIn message type value */ + public static final byte OF_PACKETIN_MESSAGE_TYPE_VALUE = 10; /** Index of length in Openflow header */ public static final int OFHEADER_LENGTH_INDEX = 2; /** Size of Openflow header */ @@ -52,10 +60,9 @@ public abstract class EncodeConstants { /** Common experimenter value */ public static final int EXPERIMENTER_VALUE = 0xFFFF; - /** OF v1.0 maximal port name length */ public static final byte MAX_PORT_NAME_LENGTH = 16; - /** OF v1.3 lenght of experimenter_ids - see Multipart TableFeatures (properties) message */ + /** OF v1.3 length of experimenter_ids - see Multipart TableFeatures (properties) message */ public static final byte EXPERIMENTER_IDS_LENGTH = 8; private EncodeConstants() { diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/DelegatingInboundHandler.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/DelegatingInboundHandler.java index a0efc900..b0fee5c3 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/DelegatingInboundHandler.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/DelegatingInboundHandler.java @@ -8,9 +8,9 @@ package org.opendaylight.openflowjava.protocol.impl.core; +import com.google.common.base.Preconditions; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; - import org.opendaylight.openflowjava.protocol.impl.core.connection.ConnectionAdapterImpl; import org.opendaylight.openflowjava.protocol.impl.core.connection.MessageConsumer; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.DisconnectEventBuilder; @@ -18,8 +18,6 @@ import org.opendaylight.yangtools.yang.binding.DataObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Preconditions; - /** * Holds reference to {@link ConnectionAdapterImpl} and passes messages for further processing. * Also informs on switch disconnection. @@ -28,12 +26,11 @@ import com.google.common.base.Preconditions; public class DelegatingInboundHandler extends ChannelInboundHandlerAdapter { private static final Logger LOG = LoggerFactory.getLogger(DelegatingInboundHandler.class); - private final MessageConsumer consumer; private boolean inactiveMessageSent = false; /** - * Constructs class + creates and sets MessageConsumer + * Constructs class + creates and sets MessageConsumer. * @param connectionAdapter reference for adapter communicating with upper layers outside library */ public DelegatingInboundHandler(final MessageConsumer connectionAdapter) { diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoder.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoder.java index ec1f43d3..90d0ab02 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoder.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFDecoder.java @@ -10,9 +10,7 @@ package org.opendaylight.openflowjava.protocol.impl.core; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageDecoder; - import java.util.List; - import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializationFactory; import org.opendaylight.openflowjava.statistics.CounterEventTypes; import org.opendaylight.openflowjava.statistics.StatisticsCounters; @@ -22,7 +20,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Transforms OpenFlow Protocol messages to POJOs + * Transforms OpenFlow Protocol messages to POJOs. * @author michal.polkorab */ public class OFDecoder extends MessageToMessageDecoder { @@ -33,18 +31,14 @@ public class OFDecoder extends MessageToMessageDecoder { // TODO: make this final? private DeserializationFactory deserializationFactory; - /** - * Constructor of class - */ public OFDecoder() { - LOG.trace("Creating OF 1.3 Decoder"); - // TODO: pass as argument + LOG.trace("Creating OFDecoder"); + // TODO: pass as argument statisticsCounter = StatisticsCounters.getInstance(); } @Override - protected void decode(ChannelHandlerContext ctx, VersionMessageWrapper msg, - List out) throws Exception { + protected void decode(ChannelHandlerContext ctx, VersionMessageWrapper msg, List out) throws Exception { statisticsCounter.incrementCounter(CounterEventTypes.US_RECEIVED_IN_OFJAVA); if (LOG.isDebugEnabled()) { LOG.debug("VersionMessageWrapper received"); diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFEncoder.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFEncoder.java index 4c54732b..2f356693 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFEncoder.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFEncoder.java @@ -21,7 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Transforms OpenFlow Protocol messages to POJOs + * Transforms OpenFlow Protocol messages to POJOs. * @author michal.polkorab * @author timotej.kubas */ @@ -34,7 +34,7 @@ public class OFEncoder extends MessageToByteEncoder { /** Constructor of class */ public OFEncoder() { statisticsCounters = StatisticsCounters.getInstance(); - LOG.trace("Creating OF13Encoder"); + LOG.trace("Creating OFEncoder"); } @Override diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFFrameDecoder.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFFrameDecoder.java index 735070fa..a9c5ecd2 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFFrameDecoder.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFFrameDecoder.java @@ -12,9 +12,7 @@ package org.opendaylight.openflowjava.protocol.impl.core; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; - import java.util.List; - import org.opendaylight.openflowjava.protocol.impl.core.connection.ConnectionFacade; import org.opendaylight.openflowjava.util.ByteBufUtils; import org.slf4j.Logger; @@ -26,7 +24,7 @@ import org.slf4j.LoggerFactory; */ public class OFFrameDecoder extends ByteToMessageDecoder { - /** Length of OpenFlow 1.3 header */ + /** Length of OpenFlow header */ public static final byte LENGTH_OF_HEADER = 8; private static final byte LENGTH_INDEX_IN_HEADER = 2; private static final Logger LOG = LoggerFactory.getLogger(OFFrameDecoder.class); @@ -36,7 +34,7 @@ public class OFFrameDecoder extends ByteToMessageDecoder { /** * Constructor of class. * @param connectionFacade ConnectionFacade that will be notified - * with ConnectionReadyNotification after TLS has been successfully set up. + * with ConnectionReadyNotification after TLS has been successfully set up. * @param tlsPresent true is TLS is required, false otherwise */ public OFFrameDecoder(ConnectionFacade connectionFacade, boolean tlsPresent) { diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetector.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetector.java index b635ef25..8e23566a 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetector.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetector.java @@ -11,6 +11,8 @@ package org.opendaylight.openflowjava.protocol.impl.core; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants; import org.opendaylight.openflowjava.statistics.CounterEventTypes; @@ -19,23 +21,20 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Detects version of used OpenFlow Protocol and discards unsupported version messages + * Detects version of used OpenFlow Protocol and discards unsupported version messages. * @author michal.polkorab */ public class OFVersionDetector extends ByteToMessageDecoder { - /** Version number of OpenFlow 1.0 protocol */ - private static final byte OF10_VERSION_ID = EncodeConstants.OF10_VERSION_ID; - /** Version number of OpenFlow 1.3 protocol */ - private static final byte OF13_VERSION_ID = EncodeConstants.OF13_VERSION_ID; - private static final short OF_PACKETIN = 10; private static final Logger LOG = LoggerFactory.getLogger(OFVersionDetector.class); + /** IDs of accepted OpenFlow protocol versions */ + private static final List OF_VERSIONS = new ArrayList<>(Arrays.asList( + EncodeConstants.OF10_VERSION_ID, + EncodeConstants.OF13_VERSION_ID + )); private final StatisticsCounters statisticsCounters; private volatile boolean filterPacketIns; - /** - * Constructor of class. - */ public OFVersionDetector() { LOG.trace("Creating OFVersionDetector"); statisticsCounters = StatisticsCounters.getInstance(); @@ -54,9 +53,10 @@ public class OFVersionDetector extends ByteToMessageDecoder { } final byte version = in.readByte(); - if (version == OF13_VERSION_ID || version == OF10_VERSION_ID) { + final short messageType = in.getUnsignedByte(in.readerIndex()); + if (messageType == EncodeConstants.OF_HELLO_MESSAGE_TYPE_VALUE || OF_VERSIONS.contains(version)) { LOG.debug("detected version: {}", version); - if (!filterPacketIns || OF_PACKETIN != in.getUnsignedByte(in.readerIndex())) { + if (!filterPacketIns || EncodeConstants.OF_PACKETIN_MESSAGE_TYPE_VALUE != messageType) { ByteBuf messageBuffer = in.slice(); out.add(new VersionMessageWrapper(version, messageBuffer)); messageBuffer.retain(); @@ -69,4 +69,5 @@ public class OFVersionDetector extends ByteToMessageDecoder { } in.skipBytes(in.readableBytes()); } + } diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/TcpChannelInitializer.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/TcpChannelInitializer.java index 376978d1..9540eeed 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/TcpChannelInitializer.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/TcpChannelInitializer.java @@ -26,26 +26,24 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Initializes TCP / TLS channel + * Initializes TCP / TLS channel. * @author michal.polkorab */ public class TcpChannelInitializer extends ProtocolChannelInitializer { - private static final Logger LOG = LoggerFactory - .getLogger(TcpChannelInitializer.class); + private static final Logger LOG = LoggerFactory.getLogger(TcpChannelInitializer.class); private final DefaultChannelGroup allChannels; private final ConnectionAdapterFactory connectionAdapterFactory; /** - * default ctor + * Default constructor. */ public TcpChannelInitializer() { this( new DefaultChannelGroup("netty-receiver", null), new ConnectionAdapterFactoryImpl() ); } /** - * Testing Constructor - * + * Testing constructor. */ protected TcpChannelInitializer( final DefaultChannelGroup channelGroup, final ConnectionAdapterFactory connAdaptorFactory ) { allChannels = channelGroup ; @@ -72,10 +70,11 @@ public class TcpChannelInitializer extends ProtocolChannelInitializer listener = findRpcResponse(key); if (listener != null) { - LOG.debug("corresponding rpcFuture found"); + LOG.debug("Corresponding rpcFuture found"); listener.completed((OfHeader)message); - LOG.debug("after setting rpcFuture"); + LOG.debug("After setting rpcFuture"); responseCache.invalidate(key); } else { LOG.warn("received unexpected rpc response: {}", key); @@ -150,10 +149,6 @@ public class ConnectionAdapterImpl extends AbstractConnectionAdapterStatistics i } } - /** - * @param message - * @return - */ private static RpcResponseKey createRpcResponseKey(final OfHeader message) { return new RpcResponseKey(message.getXid(), message.getImplementedInterface().getName()); } diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization/MessageDeserializerInitializer.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization/MessageDeserializerInitializer.java index 0e672024..3fd8508f 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization/MessageDeserializerInitializer.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization/MessageDeserializerInitializer.java @@ -55,8 +55,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequestOutput; /** + * Util class for init registration of deserializers. * @author michal.polkorab - * */ public final class MessageDeserializerInitializer { @@ -65,15 +65,14 @@ public final class MessageDeserializerInitializer { } /** - * Registers message deserializers - * - * @param registry - * registry to be filled with deserializers + * Registers message deserializers. + * @param registry registry to be filled with deserializers */ - public static void registerMessageDeserializers(DeserializerRegistry registry) { + public static void registerMessageDeserializers(final DeserializerRegistry registry) { + SimpleDeserializerRegistryHelper helper; + // register OF v1.0 message deserializers - SimpleDeserializerRegistryHelper helper = new SimpleDeserializerRegistryHelper(EncodeConstants.OF10_VERSION_ID, - registry); + helper = new SimpleDeserializerRegistryHelper(EncodeConstants.OF10_VERSION_ID, registry); helper.registerDeserializer(0, null, HelloMessage.class, new OF10HelloMessageFactory()); helper.registerDeserializer(1, null, ErrorMessage.class, new OF10ErrorMessageFactory()); helper.registerDeserializer(2, null, EchoRequestMessage.class, new OF10EchoRequestMessageFactory()); @@ -88,7 +87,7 @@ public final class MessageDeserializerInitializer { helper.registerDeserializer(19, null, BarrierOutput.class, new OF10BarrierReplyMessageFactory()); helper.registerDeserializer(21, null, GetQueueConfigOutput.class, new OF10QueueGetConfigReplyMessageFactory()); - // register Of v1.3 message deserializers + // register OF v1.3 message deserializers helper = new SimpleDeserializerRegistryHelper(EncodeConstants.OF13_VERSION_ID, registry); helper.registerDeserializer(0, null, HelloMessage.class, new HelloMessageFactory()); helper.registerDeserializer(1, null, ErrorMessage.class, new ErrorMessageFactory()); @@ -105,5 +104,13 @@ public final class MessageDeserializerInitializer { helper.registerDeserializer(23, null, GetQueueConfigOutput.class, new QueueGetConfigReplyMessageFactory()); helper.registerDeserializer(25, null, RoleRequestOutput.class, new RoleReplyMessageFactory()); helper.registerDeserializer(27, null, GetAsyncOutput.class, new GetAsyncReplyMessageFactory()); + + // register OF v1.4 message deserializers + helper = new SimpleDeserializerRegistryHelper(EncodeConstants.OF14_VERSION_ID, registry); + helper.registerDeserializer(0, null, HelloMessage.class, new HelloMessageFactory()); + + // register OF v1.5 message deserializers + helper = new SimpleDeserializerRegistryHelper(EncodeConstants.OF15_VERSION_ID, registry); + helper.registerDeserializer(0, null, HelloMessage.class, new HelloMessageFactory()); } } diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization/TypeToClassMapInitializer.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization/TypeToClassMapInitializer.java index 97ae5364..0d603cd2 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization/TypeToClassMapInitializer.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization/TypeToClassMapInitializer.java @@ -43,9 +43,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.TableModInput; /** + * Util class for init OF message type to class mapping. * @author michal.polkorab * @author giuseppex.petralia@intel.com - * */ public final class TypeToClassMapInitializer { @@ -54,13 +54,14 @@ public final class TypeToClassMapInitializer { } /** - * Initializes type to class map - * - * @param messageClassMap + * Initializes standard types mapping. + * @param messageClassMap type to class map */ - public static void initializeTypeToClassMap(Map> messageClassMap) { + public static void initializeTypeToClassMap(final Map> messageClassMap) { + TypeToClassInitHelper helper; + // init OF v1.0 mapping - TypeToClassInitHelper helper = new TypeToClassInitHelper(EncodeConstants.OF10_VERSION_ID, messageClassMap); + helper = new TypeToClassInitHelper(EncodeConstants.OF10_VERSION_ID, messageClassMap); helper.registerTypeToClass((short) 0, HelloMessage.class); helper.registerTypeToClass((short) 1, ErrorMessage.class); helper.registerTypeToClass((short) 2, EchoRequestMessage.class); @@ -74,6 +75,7 @@ public final class TypeToClassMapInitializer { helper.registerTypeToClass((short) 17, MultipartReplyMessage.class); helper.registerTypeToClass((short) 19, BarrierOutput.class); helper.registerTypeToClass((short) 21, GetQueueConfigOutput.class); + // init OF v1.3 mapping helper = new TypeToClassInitHelper(EncodeConstants.OF13_VERSION_ID, messageClassMap); helper.registerTypeToClass((short) 0, HelloMessage.class); @@ -91,17 +93,25 @@ public final class TypeToClassMapInitializer { helper.registerTypeToClass((short) 23, GetQueueConfigOutput.class); helper.registerTypeToClass((short) 25, RoleRequestOutput.class); helper.registerTypeToClass((short) 27, GetAsyncOutput.class); + + // init OF v1.4 mapping + helper = new TypeToClassInitHelper(EncodeConstants.OF14_VERSION_ID, messageClassMap); + helper.registerTypeToClass((short) 0, HelloMessage.class); + + // init OF v1.5 mapping + helper = new TypeToClassInitHelper(EncodeConstants.OF15_VERSION_ID, messageClassMap); + helper.registerTypeToClass((short) 0, HelloMessage.class); } /** - * Initializes type to class map to associate OF code to Java Class for - * messages for additional deserializers. - * - * @param messageClassMap + * Initializes additional types mapping. + * @param messageClassMap type to class map */ - public static void initializeAdditionalTypeToClassMap(Map> messageClassMap) { + public static void initializeAdditionalTypeToClassMap(final Map> messageClassMap) { + TypeToClassInitHelper helper; + // init OF v1.0 mapping - TypeToClassInitHelper helper = new TypeToClassInitHelper(EncodeConstants.OF10_VERSION_ID, messageClassMap); + helper = new TypeToClassInitHelper(EncodeConstants.OF10_VERSION_ID, messageClassMap); helper.registerTypeToClass((short) 5, GetFeaturesInput.class); helper.registerTypeToClass((short) 7, GetConfigInput.class); helper.registerTypeToClass((short) 9, SetConfigInput.class); @@ -111,6 +121,7 @@ public final class TypeToClassMapInitializer { helper.registerTypeToClass((short) 16, MultipartRequestInput.class); helper.registerTypeToClass((short) 18, BarrierInput.class); helper.registerTypeToClass((short) 20, GetQueueConfigInput.class); + // init OF v1.3 mapping helper = new TypeToClassInitHelper(EncodeConstants.OF13_VERSION_ID, messageClassMap); helper.registerTypeToClass((short) 5, GetFeaturesInput.class); diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization/factories/HelloMessageFactory.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization/factories/HelloMessageFactory.java index ca0a79c8..50cf33c1 100644 --- a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization/factories/HelloMessageFactory.java +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/deserialization/factories/HelloMessageFactory.java @@ -9,12 +9,11 @@ package org.opendaylight.openflowjava.protocol.impl.deserialization.factories; import io.netty.buffer.ByteBuf; - import java.util.ArrayList; import java.util.List; - import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer; import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants; +import org.opendaylight.openflowjava.protocol.impl.util.VersionAssignableFactory; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.HelloElementType; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloMessageBuilder; @@ -22,17 +21,19 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.hello.ElementsBuilder; /** - * Translates Hello messages + * Translates Hello messages. + * OF protocol versions: 1.3, 1.4, 1.5. * @author michal.polkorab * @author timotej.kubas */ -public class HelloMessageFactory implements OFDeserializer { +public class HelloMessageFactory extends VersionAssignableFactory implements OFDeserializer { private static final byte HELLO_ELEMENT_HEADER_SIZE = 4; + @Override public HelloMessage deserialize(ByteBuf rawMessage) { HelloMessageBuilder builder = new HelloMessageBuilder(); - builder.setVersion((short) EncodeConstants.OF13_VERSION_ID); + builder.setVersion(getVersion()); builder.setXid(rawMessage.readUnsignedInt()); if (rawMessage.readableBytes() > 0) { builder.setElements(readElement(rawMessage)); @@ -70,7 +71,7 @@ public class HelloMessageFactory implements OFDeserializer { for (int i = 0; i < input.length; i++) { int mask = input[i]; for (int j = 0; j < Integer.SIZE; j++) { - versionBitmapList.add((mask & (1< deserializedObjectClass, OFGeneralDeserializer deserializer) { - registry.registerDeserializer(new MessageCodeKey(version, code, - deserializedObjectClass), deserializer); + public void registerDeserializer(final int code, final Long experimenterID, final Class deserializedObjectClass, + final OFGeneralDeserializer deserializer) { + registry.registerDeserializer(new MessageCodeKey(version, code, deserializedObjectClass), deserializer); + + if (deserializer instanceof VersionAssignableFactory) { + ((VersionAssignableFactory) deserializer).assignVersion(version); + } } } diff --git a/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/util/VersionAssignableFactory.java b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/util/VersionAssignableFactory.java new file mode 100644 index 00000000..d10f8fa6 --- /dev/null +++ b/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/util/VersionAssignableFactory.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016 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.util; + +import javax.annotation.Nonnull; + +/** + * Abstract factory class to support OF protocol version assigning and reading. + */ +public abstract class VersionAssignableFactory { + private Short version; + + /** + * @param version OpenFlow protocol version + */ + public void assignVersion(@Nonnull final Short version) { + if (this.version == null) { + this.version = version; + } else { + throw new IllegalStateException("Version already assigned: " + this.version); + } + } + + /** + * @return OpenFlow protocol version + */ + protected Short getVersion() { + return this.version; + } +} \ No newline at end of file diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetectorTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetectorTest.java index 8cf3f75f..7b3d814a 100644 --- a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetectorTest.java +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/core/OFVersionDetectorTest.java @@ -8,14 +8,13 @@ package org.opendaylight.openflowjava.protocol.impl.core; +import static org.junit.Assert.assertEquals; + import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; - import java.util.ArrayList; import java.util.List; - import org.junit.Assert; -import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -24,8 +23,7 @@ import org.mockito.runners.MockitoJUnitRunner; import org.opendaylight.openflowjava.util.ByteBufUtils; /** - * - * @author michal.polkorab + * Test for {@link org.opendaylight.openflowjava.protocol.impl.core.OFVersionDetector}. */ @RunWith(MockitoJUnitRunner.class) public class OFVersionDetectorTest { @@ -36,74 +34,40 @@ public class OFVersionDetectorTest { private OFVersionDetector detector; private List list = new ArrayList<>(); - /** - * Sets up test environment - */ @Before public void setUp() { list.clear(); detector = new OFVersionDetector(); } - /** - * Test of decode - * {@link OFVersionDetector#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List) - * } - * - * @throws Exception - */ @Test - public void testDecode13ProtocolMessage() throws Exception { - detector.decode(channelHandlerContext, - ByteBufUtils.hexStringToByteBuf("04 00 00 08 00 00 00 01"), - list); - - Assert.assertEquals(7, ((VersionMessageWrapper) list.get(0)) - .getMessageBuffer().readableBytes()); + public void testDecode13ProtocolMessage() { + detector.decode(channelHandlerContext, ByteBufUtils.hexStringToByteBuf("04 00 00 08 00 00 00 01"), list); + Assert.assertEquals(7, ((VersionMessageWrapper) list.get(0)).getMessageBuffer().readableBytes()); } - /** - * Test of decode - * {@link OFVersionDetector#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List) - * } - * @throws Exception - */ @Test - public void testDecode10ProtocolMessage() throws Exception { - detector.decode(channelHandlerContext, - ByteBufUtils.hexStringToByteBuf("01 00 00 08 00 00 00 01"), - list); - - Assert.assertEquals(7, ((VersionMessageWrapper) list.get(0)) - .getMessageBuffer().readableBytes()); + public void testDecode10ProtocolMessage() { + detector.decode(channelHandlerContext, ByteBufUtils.hexStringToByteBuf("01 00 00 08 00 00 00 01"), list); + Assert.assertEquals(7, ((VersionMessageWrapper) list.get(0)).getMessageBuffer().readableBytes()); } - /** - * Test of decode - * {@link OFVersionDetector#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List) - * } - * @throws Exception - */ @Test - public void testDecodeEmptyProtocolMessage() throws Exception { + public void testDecodeEmptyProtocolMessage() { ByteBuf byteBuffer = ByteBufUtils.hexStringToByteBuf("01 00 00 08 00 00 00 01").skipBytes(8); detector.decode(channelHandlerContext, byteBuffer, list); - - assertEquals( 0, byteBuffer.refCnt() ) ; + assertEquals(0, byteBuffer.refCnt()); } - /** - * Test of decode - * {@link OFVersionDetector#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List) - * } - * - * @throws Exception - */ @Test - public void testDecodeNotSupportedVersionProtocolMessage() throws Exception { - detector.decode(channelHandlerContext, ByteBufUtils.hexStringToByteBuf("02 00 00 08 00 00 00 01"), list); - + public void testDecodeNotSupportedVersionProtocolMessage() { + detector.decode(channelHandlerContext, ByteBufUtils.hexStringToByteBuf("02 01 00 08 00 00 00 01"), list); Assert.assertEquals("List is not empty", 0, list.size()); } + @Test + public void testDecodeHelloProtocolMessage() { + detector.decode(channelHandlerContext, ByteBufUtils.hexStringToByteBuf("05 00 00 08 00 00 00 01"), list); + Assert.assertEquals(7, ((VersionMessageWrapper) list.get(0)).getMessageBuffer().readableBytes()); + } } diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/deserialization/TypeToClassMapInitializerTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/deserialization/TypeToClassMapInitializerTest.java index cef8daa7..622b33ce 100644 --- a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/deserialization/TypeToClassMapInitializerTest.java +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/deserialization/TypeToClassMapInitializerTest.java @@ -47,21 +47,19 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.TableModInput; /** + * Test for {@link org.opendaylight.openflowjava.protocol.impl.deserialization.TypeToClassMapInitializer}. * @author michal.polkorab * @author giuseppex.petralia@intel.com - * */ public class TypeToClassMapInitializerTest { private Map> messageClassMap; - /** - * Tests correct map initialization - */ @Test public void test() { messageClassMap = new HashMap<>(); TypeToClassMapInitializer.initializeTypeToClassMap(messageClassMap); + short version = EncodeConstants.OF10_VERSION_ID; assertEquals("Wrong class", HelloMessage.class, messageClassMap.get(new TypeToClassKey(version, 0))); assertEquals("Wrong class", ErrorMessage.class, messageClassMap.get(new TypeToClassKey(version, 1))); @@ -76,6 +74,7 @@ public class TypeToClassMapInitializerTest { assertEquals("Wrong class", MultipartReplyMessage.class, messageClassMap.get(new TypeToClassKey(version, 17))); assertEquals("Wrong class", BarrierOutput.class, messageClassMap.get(new TypeToClassKey(version, 19))); assertEquals("Wrong class", GetQueueConfigOutput.class, messageClassMap.get(new TypeToClassKey(version, 21))); + version = EncodeConstants.OF13_VERSION_ID; assertEquals("Wrong class", HelloMessage.class, messageClassMap.get(new TypeToClassKey(version, 0))); assertEquals("Wrong class", ErrorMessage.class, messageClassMap.get(new TypeToClassKey(version, 1))); @@ -92,12 +91,19 @@ public class TypeToClassMapInitializerTest { assertEquals("Wrong class", GetQueueConfigOutput.class, messageClassMap.get(new TypeToClassKey(version, 23))); assertEquals("Wrong class", RoleRequestOutput.class, messageClassMap.get(new TypeToClassKey(version, 25))); assertEquals("Wrong class", GetAsyncOutput.class, messageClassMap.get(new TypeToClassKey(version, 27))); + + version = EncodeConstants.OF14_VERSION_ID; + assertEquals("Wrong class", HelloMessage.class, messageClassMap.get(new TypeToClassKey(version, 0))); + + version = EncodeConstants.OF15_VERSION_ID; + assertEquals("Wrong class", HelloMessage.class, messageClassMap.get(new TypeToClassKey(version, 0))); } @Test public void testAdditionalTypes() { messageClassMap = new HashMap<>(); TypeToClassMapInitializer.initializeAdditionalTypeToClassMap(messageClassMap); + short version = EncodeConstants.OF10_VERSION_ID; assertEquals("Wrong class", GetFeaturesInput.class, messageClassMap.get(new TypeToClassKey(version, 5))); assertEquals("Wrong class", GetConfigInput.class, messageClassMap.get(new TypeToClassKey(version, 7))); diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/deserialization/factories/HelloMessageFactoryTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/deserialization/factories/HelloMessageFactoryTest.java index 7dab76e2..d4ec69d4 100644 --- a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/deserialization/factories/HelloMessageFactoryTest.java +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/deserialization/factories/HelloMessageFactoryTest.java @@ -9,46 +9,54 @@ package org.opendaylight.openflowjava.protocol.impl.deserialization.factories; import io.netty.buffer.ByteBuf; - import java.util.ArrayList; +import java.util.Arrays; import java.util.List; - import org.junit.Assert; -import org.junit.Before; import org.junit.Test; -import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry; -import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer; import org.opendaylight.openflowjava.protocol.api.keys.MessageCodeKey; -import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializerRegistryImpl; -import org.opendaylight.openflowjava.protocol.impl.util.BufferHelper; import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants; +import org.opendaylight.openflowjava.protocol.impl.util.BufferHelper; +import org.opendaylight.openflowjava.protocol.impl.util.DefaultDeserializerFactoryTest; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.HelloElementType; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.hello.Elements; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.hello.ElementsBuilder; /** + * Test for {@link org.opendaylight.openflowjava.protocol.impl.deserialization.factories.HelloMessageFactory}. * @author michal.polkorab * @author timotej.kubas * @author madamjak */ -public class HelloMessageFactoryTest { +public class HelloMessageFactoryTest extends DefaultDeserializerFactoryTest { - private OFDeserializer helloFactory; + /** + * Initializes deserializer registry and lookups OF13 deserializer. + */ + public HelloMessageFactoryTest() { + super(new MessageCodeKey(EncodeConstants.OF13_VERSION_ID, 0, HelloMessage.class)); + } /** - * Initializes deserializer registry and lookups correct deserializer + * Testing {@link HelloMessageFactory} for correct header version. */ - @Before - public void startUp() { - DeserializerRegistry registry = new DeserializerRegistryImpl(); - registry.init(); - helloFactory = registry.getDeserializer( - new MessageCodeKey(EncodeConstants.OF13_VERSION_ID, 0, HelloMessage.class)); + @Test + public void testVersion() { + List versions = new ArrayList<>(Arrays.asList( + EncodeConstants.OF13_VERSION_ID, + EncodeConstants.OF14_VERSION_ID, + EncodeConstants.OF15_VERSION_ID + )); + ByteBuf bb = BufferHelper.buildBuffer("00 01 " // type + + "00 08 " // length + + "00 00 00 11" // bitmap 1 + ); + testHeaderVersions(versions, bb); } /** - * Testing {@link HelloMessageFactory} for correct length without padding + * Testing {@link HelloMessageFactory} for correct length without padding. */ @Test public void testWithoutPadding() { @@ -56,15 +64,14 @@ public class HelloMessageFactoryTest { + "00 08 " // length + "00 00 00 11" // bitmap 1 ); - HelloMessage builtByFactory = BufferHelper.deserialize(helloFactory, bb); - BufferHelper.checkHeaderV13(builtByFactory); + HelloMessage builtByFactory = BufferHelper.deserialize(factory, bb); List element = createElement(4,HelloElementType.VERSIONBITMAP.getIntValue()); Assert.assertEquals("Wrong type", element.get(0).getType(), builtByFactory.getElements().get(0).getType()); Assert.assertEquals("Wrong versionBitmap", element.get(0).getVersionBitmap(), builtByFactory.getElements().get(0).getVersionBitmap()); } /** - * Testing {@link HelloMessageFactory} for correct length with padding + * Testing {@link HelloMessageFactory} for correct length with padding. */ @Test public void testWithPadding() { @@ -74,15 +81,14 @@ public class HelloMessageFactoryTest { + "00 00 00 00 " // bitmap 2 + "00 00 00 00" // padding ); - HelloMessage builtByFactory = BufferHelper.deserialize(helloFactory, bb); - BufferHelper.checkHeaderV13(builtByFactory); + HelloMessage builtByFactory = BufferHelper.deserialize(factory, bb); List element = createElement(8,HelloElementType.VERSIONBITMAP.getIntValue()); Assert.assertEquals("Wrong type", element.get(0).getType(), builtByFactory.getElements().get(0).getType()); Assert.assertEquals("Wrong versionBitmap", element.get(0).getVersionBitmap(), builtByFactory.getElements().get(0).getVersionBitmap()); } /** - * Testing {@link HelloMessageFactory} if incorrect version is set + * Testing {@link HelloMessageFactory} if incorrect version is set. */ @Test public void testBadType(){ @@ -92,8 +98,7 @@ public class HelloMessageFactoryTest { + "00 00 00 00 " // bitmap 2 + "00 00 00 00" // padding ); - HelloMessage builtByFactory = BufferHelper.deserialize(helloFactory, bb); - BufferHelper.checkHeaderV13(builtByFactory); + HelloMessage builtByFactory = BufferHelper.deserialize(factory, bb); Assert.assertEquals("Wrong - no element has been expected", 0, builtByFactory.getElements().size()); } diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/util/BufferHelper.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/util/BufferHelper.java index dcdbec18..29d0da2f 100644 --- a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/util/BufferHelper.java +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/util/BufferHelper.java @@ -19,6 +19,7 @@ import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer; import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants; import org.opendaylight.openflowjava.util.ByteBufUtils; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader; +import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; /** @@ -107,7 +108,12 @@ public abstract class BufferHelper { checkHeader(ofHeader, (short) EncodeConstants.OF10_VERSION_ID); } - private static void checkHeader(OfHeader ofHeader, Short version) { + /** + * Check version and xid of OFP header. + * @param ofHeader OpenFlow protocol header + * @param version OpenFlow protocol version + */ + public static void checkHeader(OfHeader ofHeader, Short version) { Assert.assertEquals("Wrong version", version, ofHeader.getVersion()); Assert.assertEquals("Wrong Xid", DEFAULT_XID, ofHeader.getXid()); } @@ -134,7 +140,7 @@ public abstract class BufferHelper { * @param bb data input buffer * @return message decoded pojo */ - public static E deserialize(OFDeserializer decoder, ByteBuf bb) { + public static E deserialize(OFDeserializer decoder, ByteBuf bb) { return decoder.deserialize(bb); } diff --git a/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/util/DefaultDeserializerFactoryTest.java b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/util/DefaultDeserializerFactoryTest.java new file mode 100644 index 00000000..2d424cde --- /dev/null +++ b/openflow-protocol-impl/src/test/java/org/opendaylight/openflowjava/protocol/impl/util/DefaultDeserializerFactoryTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016 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.util; + +import io.netty.buffer.ByteBuf; +import java.util.List; +import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry; +import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer; +import org.opendaylight.openflowjava.protocol.api.keys.MessageCodeKey; +import org.opendaylight.openflowjava.protocol.impl.deserialization.DeserializerRegistryImpl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader; +import org.opendaylight.yangtools.yang.binding.DataContainer; + +/** + * Super class for common stuff of deserialization factories tests. + */ +public abstract class DefaultDeserializerFactoryTest { + + private DeserializerRegistry registry; + protected OFDeserializer factory; + private MessageCodeKey messageCodeKey; + + public DefaultDeserializerFactoryTest(final MessageCodeKey key) { + this.registry = new DeserializerRegistryImpl(); + this.registry.init(); + this.messageCodeKey = key; + this.factory = registry.getDeserializer(key); + } + + /** + * Test correct version after deserialization for all supported OF versions. + * @param versions supported OF versions + * @param buffer byte buffer to deserialze + */ + protected void testHeaderVersions(final List versions, final ByteBuf buffer) { + for (short version : versions) { + ByteBuf bb = buffer.copy(); + OFDeserializer factory = registry.getDeserializer( + new MessageCodeKey(version, messageCodeKey.getMsgType(), messageCodeKey.getClazz())); + T builtByFactory = BufferHelper.deserialize(factory, bb); + BufferHelper.checkHeader((OfHeader) builtByFactory, version); + } + } +} -- 2.36.6