- 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 <andrej.leitner@pantheon.tech>
this.clazz = clazz;
}
+ public int getMsgType() {
+ return this.msgType;
+ }
+
+ public Class<?> getClazz() {
+ return this.clazz;
+ }
+
@Override
public int hashCode() {
final int prime = 31;
package org.opendaylight.openflowjava.protocol.api.util;
/**
- * Stores common constants
+ * Stores common constants.
* @author michal.polkorab
*/
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 */
/** 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() {
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;
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.
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) {
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;
import org.slf4j.LoggerFactory;
/**
- * Transforms OpenFlow Protocol messages to POJOs
+ * Transforms OpenFlow Protocol messages to POJOs.
* @author michal.polkorab
*/
public class OFDecoder extends MessageToMessageDecoder<VersionMessageWrapper> {
// 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<Object> out) throws Exception {
+ protected void decode(ChannelHandlerContext ctx, VersionMessageWrapper msg, List<Object> out) throws Exception {
statisticsCounter.incrementCounter(CounterEventTypes.US_RECEIVED_IN_OFJAVA);
if (LOG.isDebugEnabled()) {
LOG.debug("VersionMessageWrapper received");
import org.slf4j.LoggerFactory;
/**
- * Transforms OpenFlow Protocol messages to POJOs
+ * Transforms OpenFlow Protocol messages to POJOs.
* @author michal.polkorab
* @author timotej.kubas
*/
/** Constructor of class */
public OFEncoder() {
statisticsCounters = StatisticsCounters.getInstance();
- LOG.trace("Creating OF13Encoder");
+ LOG.trace("Creating OFEncoder");
}
@Override
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;
*/
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);
/**
* 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) {
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;
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<Byte> 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();
}
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();
}
in.skipBytes(in.readableBytes());
}
+
}
import org.slf4j.LoggerFactory;
/**
- * Initializes TCP / TLS channel
+ * Initializes TCP / TLS channel.
* @author michal.polkorab
*/
public class TcpChannelInitializer extends ProtocolChannelInitializer<SocketChannel> {
- 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 ;
ConnectionFacade connectionFacade = null;
connectionFacade = connectionAdapterFactory.createConnectionFacade(ch, null, useBarrier());
try {
- LOG.debug("calling plugin: {}", getSwitchConnectionHandler());
+ LOG.debug("Calling OF plugin: {}", getSwitchConnectionHandler());
getSwitchConnectionHandler().onSwitchConnected(connectionFacade);
connectionFacade.checkListeners();
- ch.pipeline().addLast(PipelineHandlers.IDLE_HANDLER.name(), new IdleHandler(getSwitchIdleTimeout(), TimeUnit.MILLISECONDS));
+ ch.pipeline().addLast(PipelineHandlers.IDLE_HANDLER.name(),
+ new IdleHandler(getSwitchIdleTimeout(), TimeUnit.MILLISECONDS));
boolean tlsPresent = false;
// If this channel is configured to support SSL it will only support SSL
final 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));
+ ch.pipeline().addLast(PipelineHandlers.DELEGATING_INBOUND_HANDLER.name(),
+ new DelegatingInboundHandler(connectionFacade));
if (!tlsPresent) {
connectionFacade.fireConnectionReadyNotification();
}
*/
private void conditionalFlush() {
if (queue.isEmpty()) {
- LOG.trace("Queue is empty, not flush needed");
+ LOG.trace("Queue is empty, flush not needed");
return;
}
if (!channel.isWritable()) {
import org.slf4j.LoggerFactory;
/**
- * Handles messages (notifications + rpcs) and connections
+ * Handles messages (notifications + rpcs) and connections.
* @author mirehak
* @author michal.polkorab
*/
private final boolean useBarrier;
/**
- * default ctor
- *
+ * Default constructor.
* @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))
+ * as there is no need to store address over tcp (stable channel))
* @param useBarrier value is configurable by configSubsytem
*/
public ConnectionAdapterImpl(final Channel channel, final InetSocketAddress address, final boolean useBarrier) {
@Override
public void consumeDeviceMessage(final DataObject message) {
LOG.debug("ConsumeIntern msg on {}", channel);
- if (disconnectOccured ) {
+ if (disconnectOccured) {
return;
}
if (message instanceof Notification) {
disconnectOccured = true;
} else if (message instanceof SwitchIdleEvent) {
systemListener.onSwitchIdleEvent((SwitchIdleEvent) message);
- // OpenFlow messages
+ // OpenFlow messages
} else if (message instanceof EchoRequestMessage) {
if (outputManager != null) {
outputManager.onEchoRequest((EchoRequestMessage) message);
} else if (message instanceof FlowRemovedMessage) {
messageListener.onFlowRemovedMessage((FlowRemovedMessage) message);
} else if (message instanceof HelloMessage) {
- LOG.info("Hello received / branch");
+ LOG.info("Hello received");
messageListener.onHelloMessage((HelloMessage) message);
} else if (message instanceof MultipartReplyMessage) {
if (outputManager != null) {
LOG.warn("message listening not supported for type: {}", message.getClass());
}
} else if (message instanceof OfHeader) {
- LOG.debug("OFheader msg received");
+ LOG.debug("OF header msg received");
if (outputManager == null || !outputManager.onMessage((OfHeader) message)) {
final RpcResponseKey key = createRpcResponseKey((OfHeader) message);
final ResponseExpectedRpcListener<?> 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);
}
}
- /**
- * @param message
- * @return
- */
private static RpcResponseKey createRpcResponseKey(final OfHeader message) {
return new RpcResponseKey(message.getXid(), message.getImplementedInterface().getName());
}
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 {
}
/**
- * 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());
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());
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());
}
}
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 {
}
/**
- * Initializes type to class map
- *
- * @param messageClassMap
+ * Initializes standard types mapping.
+ * @param messageClassMap type to class map
*/
- public static void initializeTypeToClassMap(Map<TypeToClassKey, Class<?>> messageClassMap) {
+ public static void initializeTypeToClassMap(final Map<TypeToClassKey, Class<?>> 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);
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);
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<TypeToClassKey, Class<?>> messageClassMap) {
+ public static void initializeAdditionalTypeToClassMap(final Map<TypeToClassKey, Class<?>> 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);
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);
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;
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<HelloMessage> {
+public class HelloMessageFactory extends VersionAssignableFactory implements OFDeserializer<HelloMessage> {
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));
for (int i = 0; i < input.length; i++) {
int mask = input[i];
for (int j = 0; j < Integer.SIZE; j++) {
- versionBitmapList.add((mask & (1<<j)) != 0);
+ versionBitmapList.add((mask & (1 << j)) != 0);
}
}
return versionBitmapList;
import org.opendaylight.openflowjava.protocol.api.keys.MessageCodeKey;
/**
+ * Helper class for deserializer registration assigning particular version if necessary.
* @author michal.polkorab
- *
*/
public class SimpleDeserializerRegistryHelper {
* @param version wire protocol version
* @param deserializerRegistry registry to be filled with message deserializers
*/
- public SimpleDeserializerRegistryHelper(short version, DeserializerRegistry deserializerRegistry) {
+ public SimpleDeserializerRegistryHelper(final short version, final DeserializerRegistry deserializerRegistry) {
this.version = version;
this.registry = deserializerRegistry;
}
/**
+ * Register deserializer in registry. If deserializer supports more protocol versions assign actual one.
* @param code code / value to distinguish between deserializers
* @param experimenterID TODO
- * @param deserializedObjectClass class of object that will be deserialized
- * by given deserializer
+ * @param deserializedObjectClass class of object that will be deserialized by given deserializer
* @param deserializer deserializer instance
*/
- public void registerDeserializer(int code,
- Long experimenterID, Class<?> 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);
+ }
}
}
--- /dev/null
+/*
+ * 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
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;
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 {
private OFVersionDetector detector;
private List<Object> 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());
+ }
}
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<TypeToClassKey, Class<?>> 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)));
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)));
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)));
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<HelloMessage> {
- private OFDeserializer<HelloMessage> 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<Byte> 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() {
+ "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<Elements> 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() {
+ "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<Elements> 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(){
+ "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());
}
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;
/**
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());
}
* @param bb data input buffer
* @return message decoded pojo
*/
- public static <E extends DataObject> E deserialize(OFDeserializer<E> decoder, ByteBuf bb) {
+ public static <E extends DataContainer> E deserialize(OFDeserializer<E> decoder, ByteBuf bb) {
return decoder.deserialize(bb);
}
--- /dev/null
+/*
+ * 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<T extends DataContainer> {
+
+ private DeserializerRegistry registry;
+ protected OFDeserializer<T> 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<Byte> versions, final ByteBuf buffer) {
+ for (short version : versions) {
+ ByteBuf bb = buffer.copy();
+ OFDeserializer<T> factory = registry.getDeserializer(
+ new MessageCodeKey(version, messageCodeKey.getMsgType(), messageCodeKey.getClazz()));
+ T builtByFactory = BufferHelper.deserialize(factory, bb);
+ BufferHelper.checkHeader((OfHeader) builtByFactory, version);
+ }
+ }
+}