From 49c5c1767ac8ac772725f5fb04e8bacc9a858219 Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Wed, 4 Jan 2017 13:41:58 +0100 Subject: [PATCH] Add GroupMessageDeserializer Inject GroupMessageDeserializer into OFJ. This deserializer will deserialize raw bytes into GroupMessage. See also: bug 7140 Change-Id: I07e0ec7601155eb4138b598c9c4f39dfd1e31d03 Signed-off-by: Tomas Slusny --- .../MessageDeserializerInjector.java | 3 + .../messages/GroupMessageDeserializer.java | 108 ++++++++++++++++++ .../GroupMessageDeserializerTest.java | 91 +++++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/messages/GroupMessageDeserializer.java create mode 100644 openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/messages/GroupMessageDeserializerTest.java diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/MessageDeserializerInjector.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/MessageDeserializerInjector.java index c5198ccd51..fb1a6120ce 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/MessageDeserializerInjector.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/MessageDeserializerInjector.java @@ -18,6 +18,8 @@ import org.opendaylight.openflowjava.protocol.api.keys.TypeToClassKey; import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants; import org.opendaylight.openflowplugin.impl.protocol.deserialization.messages.FlowMessageDeserializer; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowMessage; +import org.opendaylight.openflowplugin.impl.protocol.deserialization.messages.GroupMessageDeserializer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader; public class MessageDeserializerInjector { @@ -32,6 +34,7 @@ public class MessageDeserializerInjector { createInjector(provider, EncodeConstants.OF13_VERSION_ID); injector.apply(14).apply(FlowMessage.class).accept(new FlowMessageDeserializer()); + injector.apply(15).apply(GroupMessage.class).accept(new GroupMessageDeserializer()); } /** diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/messages/GroupMessageDeserializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/messages/GroupMessageDeserializer.java new file mode 100644 index 0000000000..6a9d0b63dd --- /dev/null +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/messages/GroupMessageDeserializer.java @@ -0,0 +1,108 @@ +/* + * 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.openflowplugin.impl.protocol.deserialization.messages; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry; +import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistryInjector; +import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer; +import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants; +import org.opendaylight.openflowplugin.extension.api.path.ActionPath; +import org.opendaylight.openflowplugin.impl.protocol.deserialization.util.ActionUtil; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupMessage; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupMessageBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.GroupModCommand; + +import io.netty.buffer.ByteBuf; + +public class GroupMessageDeserializer implements OFDeserializer, DeserializerRegistryInjector { + + private static final byte PADDING = 1; + private static final byte PADDING_IN_BUCKETS_HEADER = 4; + private static final byte BUCKETS_HEADER_LENGTH = 16; + + private static final Comparator COMPARATOR = (bucket1, bucket2) -> { + if (bucket1.getBucketId() == null || bucket2.getBucketId() == null) return 0; + return bucket1.getBucketId().getValue().compareTo(bucket2.getBucketId().getValue()); + }; + + private DeserializerRegistry registry; + + @Override + public GroupMessage deserialize(ByteBuf message) { + final GroupMessageBuilder builder = new GroupMessageBuilder() + .setVersion((short) EncodeConstants.OF13_VERSION_ID) + .setXid(message.readUnsignedInt()) + .setCommand(GroupModCommand.forValue(message.readUnsignedShort())); + + builder.setGroupType(GroupTypes.forValue(message.readUnsignedByte())); + message.skipBytes(PADDING); + builder.setGroupId(new GroupId(message.readUnsignedInt())); + + final List buckets = new ArrayList<>(); + + while (message.readableBytes() > 0) { + final int length = message.readUnsignedShort(); + + final BucketBuilder bucket = new BucketBuilder() + .setWeight(message.readUnsignedShort()) + .setWatchPort(message.readUnsignedInt()) + .setWatchGroup(message.readUnsignedInt()); + + message.skipBytes(PADDING_IN_BUCKETS_HEADER); + + if (message.readableBytes() > 0) { + final List actions = new ArrayList<>(); + final int startIndex = message.readerIndex(); + final int bucketLength = length - BUCKETS_HEADER_LENGTH; + int offset = 0; + + while ((message.readerIndex() - startIndex) < bucketLength) { + actions.add(new ActionBuilder() + .setKey(new ActionKey(offset)) + .setOrder(offset) + .setAction(ActionUtil.readAction(EncodeConstants.OF13_VERSION_ID, message, registry, + ActionPath.GROUPDESCSTATSUPDATED_GROUPDESCSTATS_BUCKETS_BUCKET_ACTION)) + .build()); + + offset++; + } + + bucket.setAction(actions); + } + + buckets.add(bucket.build()); + } + + Collections.sort(buckets, COMPARATOR); + return builder + .setBuckets(new BucketsBuilder() + .setBucket(buckets) + .build()) + .build(); + } + + @Override + public void injectDeserializerRegistry(DeserializerRegistry deserializerRegistry) { + registry = deserializerRegistry; + } + +} diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/messages/GroupMessageDeserializerTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/messages/GroupMessageDeserializerTest.java new file mode 100644 index 0000000000..fe15c4638c --- /dev/null +++ b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/messages/GroupMessageDeserializerTest.java @@ -0,0 +1,91 @@ +/* + * 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.openflowplugin.impl.protocol.deserialization.messages; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants; +import org.opendaylight.openflowjava.protocol.impl.util.ActionConstants; +import org.opendaylight.openflowplugin.impl.protocol.deserialization.AbstractDeserializerTest; +import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopPbbActionCase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupMessage; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.GroupModCommand; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.UnpooledByteBufAllocator; + +public class GroupMessageDeserializerTest extends AbstractDeserializerTest { + + private static final byte PADDING = 1; + private static final byte PADDING_IN_BUCKETS_HEADER = 4; + + private static final int TYPE = 15; + private static final int XID = 42; + private static final GroupModCommand COMMAND = GroupModCommand.OFPGCADD; + private static final GroupTypes GROUP_TYPE = GroupTypes.GroupAll; + private static final int GROUP_ID = 26; + private static final short WEIGHT = 50; + private static final int WATCH_PORT = 22; + private static final int WATCH_GROUP = 25; + + private ByteBuf buffer; + + @Override + protected void init() { + buffer = UnpooledByteBufAllocator.DEFAULT.buffer(); + } + + @Test + public void deserialize() throws Exception { + // Group header + buffer.writeByte(TYPE); + buffer.writeShort(EncodeConstants.EMPTY_LENGTH); + buffer.writeInt(XID); + buffer.writeShort(COMMAND.getIntValue()); + buffer.writeByte(GROUP_TYPE.getIntValue()); + buffer.writeZero(PADDING); + buffer.writeInt(GROUP_ID); + + // Buckets header + int index = buffer.writerIndex(); + buffer.writeShort(EncodeConstants.EMPTY_LENGTH); + buffer.writeShort(WEIGHT); + buffer.writeInt(WATCH_PORT); + buffer.writeInt(WATCH_GROUP); + buffer.writeZero(PADDING_IN_BUCKETS_HEADER); + + // POP PBB action + buffer.writeShort(ActionConstants.POP_PBB_CODE); + buffer.writeShort(ActionConstants.GENERAL_ACTION_LENGTH); + buffer.writeZero(ActionConstants.PADDING_IN_ACTION_HEADER); + + // Count total length of buckets + buffer.setShort(index, buffer.writerIndex() - index); + + // Deserialize and check everything + final GroupMessage message = (GroupMessage) getFactory() + .deserialize(buffer, EncodeConstants.OF13_VERSION_ID); + + assertEquals(XID, message.getXid().intValue()); + assertEquals(COMMAND.getIntValue(), message.getCommand().getIntValue()); + assertEquals(GROUP_TYPE.getIntValue(), message.getGroupType().getIntValue()); + assertEquals(1, message.getBuckets().getBucket().size()); + + final Bucket bucket = message.getBuckets().getBucket().get(0); + assertEquals(WEIGHT, bucket.getWeight().shortValue()); + assertEquals(WATCH_PORT, bucket.getWatchPort().intValue()); + assertEquals(WATCH_GROUP, bucket.getWatchGroup().intValue()); + assertEquals(1, bucket.getAction().size()); + assertEquals(PopPbbActionCase.class, bucket.getAction().get(0).getAction().getImplementedInterface()); + } + +} -- 2.36.6