Add GroupMessageDeserializer 16/50016/20
authorTomas Slusny <tomas.slusny@pantheon.tech>
Wed, 4 Jan 2017 12:41:58 +0000 (13:41 +0100)
committerTomas Slusny <tomas.slusny@pantheon.tech>
Wed, 15 Feb 2017 15:13:41 +0000 (16:13 +0100)
Inject GroupMessageDeserializer into OFJ.
This deserializer will deserialize raw bytes into GroupMessage.

See also: bug 7140

Change-Id: I07e0ec7601155eb4138b598c9c4f39dfd1e31d03
Signed-off-by: Tomas Slusny <tomas.slusny@pantheon.tech>
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/MessageDeserializerInjector.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/messages/GroupMessageDeserializer.java [new file with mode: 0644]
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/protocol/deserialization/messages/GroupMessageDeserializerTest.java [new file with mode: 0644]

index c5198ccd511838838d0ec7ee6e3d6ec3ab39b537..fb1a6120cece1e0726d336798c6c3586d691736c 100644 (file)
@@ -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 (file)
index 0000000..6a9d0b6
--- /dev/null
@@ -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<GroupMessage>, 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<Bucket> 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<Bucket> 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<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list
+                    .Action> 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 (file)
index 0000000..fe15c46
--- /dev/null
@@ -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());
+    }
+
+}