Add MeterMessage serializer 20/48520/18
authorTomas Slusny <tomas.slusny@pantheon.tech>
Mon, 21 Nov 2016 09:18:07 +0000 (10:18 +0100)
committerTomas Slusny <tomas.slusny@pantheon.tech>
Mon, 9 Jan 2017 12:43:17 +0000 (13:43 +0100)
Inject MeterMessageSerializer into OFJ. This serializer will
serialize MeterMod message to raw bytes.
Added unit tests for ExperimentedIdMeterBandTypeSerializerKey

See also: bug 7138

Change-Id: I6b46f6f9e7e960055692c0a33932be373a783b47
Signed-off-by: Tomas Slusny <tomas.slusny@pantheon.tech>
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/MessageSerializerInjector.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/MeterMessageSerializer.java [new file with mode: 0644]
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/MeterMessageSerializerTest.java [new file with mode: 0644]

index a1a50f99a3f43855e4e59048b9a31cb5588dce9c..c5b1924d35f867daa17ed37ea7188d9ec785f334 100644 (file)
@@ -18,6 +18,8 @@ import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
 import org.opendaylight.openflowplugin.impl.protocol.serialization.messages.FlowMessageSerializer;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowMessage;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
+import org.opendaylight.openflowplugin.impl.protocol.serialization.messages.MeterMessageSerializer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterMessage;
 
 /**
  * Util class for injecting new message serializers into OpenflowJava
@@ -32,8 +34,9 @@ class MessageSerializerInjector {
         // Inject new message serializers here using injector created by createInjector method
         final Function<Class<?>, Consumer<OFSerializer<? extends OfHeader>>> injector =
                 createInjector(provider, EncodeConstants.OF13_VERSION_ID);
-
+        
         injector.apply(FlowMessage.class).accept(new FlowMessageSerializer());
+        injector.apply(MeterMessage.class).accept(new MeterMessageSerializer());
     }
 
     /**
diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/MeterMessageSerializer.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/MeterMessageSerializer.java
new file mode 100644 (file)
index 0000000..404a9d5
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * 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.serialization.messages;
+
+import com.google.common.base.MoreObjects;
+import io.netty.buffer.ByteBuf;
+import java.util.Objects;
+import java.util.Optional;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFSerializer;
+import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerRegistry;
+import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerRegistryInjector;
+import org.opendaylight.openflowjava.protocol.api.keys.ExperimenterIdSerializerKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowjava.util.ByteBufUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Drop;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DscpRemark;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.Experimenter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.MeterBandHeaders;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MeterBandType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Translates MeterMod messages
+ * OF protocol versions: 1.3.
+ */
+public class MeterMessageSerializer extends AbstractMessageSerializer<MeterMessage> implements SerializerRegistryInjector {
+    private static final Logger LOG = LoggerFactory.getLogger(MeterMessageSerializer.class);
+    private static final short LENGTH_OF_METER_BANDS = 16;
+    private static final short PADDING_IN_METER_BAND_DROP = 4;
+    private static final short PADDING_IN_METER_BAND_DSCP_REMARK = 3;
+
+    private SerializerRegistry registry;
+
+    @Override
+    public void serialize(final MeterMessage message, final ByteBuf outBuffer) {
+        super.serialize(message, outBuffer);
+        outBuffer.writeShort(message.getCommand().getIntValue());
+        outBuffer.writeShort(createMeterFlagsBitMask(
+                MoreObjects.firstNonNull(message.getFlags(), new MeterFlags(false, false, true, false))));
+        outBuffer.writeInt(message.getMeterId().getValue().intValue());
+        serializeBands(message.getMeterBandHeaders(), outBuffer);
+        ByteBufUtils.updateOFHeaderLength(outBuffer);
+    }
+
+    @Override
+    protected byte getMessageType() {
+        return 29;
+    }
+
+    private void serializeBands(final MeterBandHeaders meterBandHeaders, final ByteBuf outBuffer) {
+        if (Objects.nonNull(meterBandHeaders) && Objects.nonNull(meterBandHeaders.getMeterBandHeader())) {
+            meterBandHeaders.getMeterBandHeader().forEach(meterBandHeader ->
+                    Optional.ofNullable(meterBandHeader.getMeterBandTypes())
+                            .flatMap(m -> Optional.ofNullable(m.getFlags()))
+                            .ifPresent(flags -> Optional.ofNullable(meterBandHeader.getBandType()).ifPresent(type -> {
+                                if (flags.isOfpmbtDrop()) {
+                                    final Drop band = Drop.class.cast(type);
+                                    outBuffer.writeShort(MeterBandType.OFPMBTDROP.getIntValue());
+
+                                    outBuffer.writeShort(LENGTH_OF_METER_BANDS);
+                                    outBuffer.writeInt(band.getDropRate().intValue());
+                                    outBuffer.writeInt(band.getDropBurstSize().intValue());
+                                    outBuffer.writeZero(PADDING_IN_METER_BAND_DROP);
+                                } else if (flags.isOfpmbtDscpRemark()) {
+                                    final DscpRemark band = DscpRemark.class.cast(type);
+                                    outBuffer.writeShort(MeterBandType.OFPMBTDSCPREMARK.getIntValue());
+
+                                    outBuffer.writeShort(LENGTH_OF_METER_BANDS);
+                                    outBuffer.writeInt(band.getDscpRemarkRate().intValue());
+                                    outBuffer.writeInt(band.getDscpRemarkBurstSize().intValue());
+                                    outBuffer.writeByte(band.getPrecLevel());
+                                    outBuffer.writeZero(PADDING_IN_METER_BAND_DSCP_REMARK);
+                                } else if (flags.isOfpmbtExperimenter()) {
+                                    final Experimenter band = Experimenter.class.cast(type);
+
+                                    // TODO: finish experimenter serialization
+                                    final ExperimenterIdSerializerKey<Experimenter> key =
+                                            new ExperimenterIdSerializerKey<>(
+                                                    EncodeConstants.OF13_VERSION_ID,
+                                                    band.getExperimenter(),
+                                                    (Class<Experimenter>) type.getImplementedInterface());
+
+                                    try {
+                                        final OFSerializer<Experimenter> serializer = registry.getSerializer(key);
+                                        serializer.serialize(band, outBuffer);
+                                    } catch (final IllegalStateException e) {
+                                        LOG.warn("Serializer for key: {} wasn't found, exception {}", key, e);
+                                    }
+                                }
+                            })));
+        }
+    }
+
+    @Override
+    public void injectSerializerRegistry(SerializerRegistry serializerRegistry) {
+        registry = serializerRegistry;
+    }
+
+    private static int createMeterFlagsBitMask(final MeterFlags flags) {
+        return ByteBufUtils.fillBitMask(0,
+                flags.isMeterKbps(),
+                flags.isMeterPktps(),
+                flags.isMeterBurst(),
+                flags.isMeterStats());
+    }
+}
diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/MeterMessageSerializerTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/MeterMessageSerializerTest.java
new file mode 100644 (file)
index 0000000..5bf30a5
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * 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.serialization.messages;
+
+import static org.junit.Assert.assertEquals;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.UnpooledByteBufAllocator;
+import java.util.Arrays;
+import org.junit.Test;
+import org.opendaylight.openflowjava.protocol.api.keys.MessageTypeKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowjava.util.ByteBufUtils;
+import org.opendaylight.openflowplugin.impl.protocol.serialization.AbstractSerializerTest;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.BandId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFlags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterMessageBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DropBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.band.type.band.type.DscpRemarkBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.MeterBandHeadersBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.meter.band.headers.MeterBandHeaderBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.meter.band.headers.meter.band.header.MeterBandTypesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MeterBandType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MeterModCommand;
+
+public class MeterMessageSerializerTest extends AbstractSerializerTest {
+    // Meter message constants
+    private static final short LENGTH = 48;
+    private static final short LENGTH_OF_METER_BANDS = 16;
+    private static final short PADDING_IN_METER_BAND_DROP = 4;
+    private static final short PADDING_IN_METER_BAND_DSCP_REMARK = 3;
+    private static final Long XID = 42L;
+    private static final String CONTAINER_NAME = "container";
+    private static final String METER_NAME = "meter";
+    private static final Long METER_ID = 1L;
+    private static final Boolean BARRIER = false;
+    private static final short VERSION = EncodeConstants.OF13_VERSION_ID;
+    private static final MeterModCommand COMMAND = MeterModCommand.OFPMCADD;
+    // Flags
+    private static final Boolean IS_METER_BURST = false;
+    private static final Boolean IS_METER_KBPS = true;
+    private static final Boolean IS_METER_PKTPS = false;
+    private static final Boolean IS_METER_STATS = true;
+    // Bands
+    private static final Long BAND_BURST_SIZE = 50L;
+    private static final Long BAND_ID = 8L;
+    private static final Long BAND_RATE = 25L;
+    private static final Long DROP_RATE = 12L;
+    private static final Long DROP_BURST_SIZE = 24L;
+    private static final Long DSCP_RATE = 13L;
+    private static final Long DSCP_BURST_SIZE = 26L;
+    private static final short DSCP_PREC_LEVEL = (short) 4;
+
+    // Message
+    private static final MeterMessage MESSAGE = new MeterMessageBuilder()
+            .setBarrier(BARRIER)
+            .setCommand(COMMAND)
+            .setContainerName(CONTAINER_NAME)
+            .setFlags(new MeterFlags(IS_METER_BURST, IS_METER_KBPS, IS_METER_PKTPS, IS_METER_STATS))
+            .setMeterId(new MeterId(METER_ID))
+            .setXid(XID)
+            .setVersion(VERSION)
+            .setMeterName(METER_NAME)
+            .setMeterBandHeaders(new MeterBandHeadersBuilder()
+                    .setMeterBandHeader(Arrays.asList(
+                            new MeterBandHeaderBuilder()
+                                    .setMeterBandTypes(new MeterBandTypesBuilder()
+                                            .setFlags(new org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918
+                                                    .MeterBandType(true, false, false))
+                                            .build())
+                                    .setBandBurstSize(BAND_BURST_SIZE)
+                                    .setBandId(new BandId(BAND_ID))
+                                    .setBandRate(BAND_RATE)
+                                    .setBandType(new DropBuilder()
+                                            .setDropRate(DROP_RATE)
+                                            .setDropBurstSize(DROP_BURST_SIZE)
+                                            .build())
+                                    .build(),
+                            new MeterBandHeaderBuilder()
+                                    .setMeterBandTypes(new MeterBandTypesBuilder()
+                                            .setFlags(new org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918
+                                                    .MeterBandType(false, true, false))
+                                            .build())
+                                    .setBandBurstSize(BAND_BURST_SIZE)
+                                    .setBandId(new BandId(BAND_ID))
+                                    .setBandRate(BAND_RATE)
+                                    .setBandType(new DscpRemarkBuilder()
+                                            .setDscpRemarkBurstSize(DSCP_BURST_SIZE)
+                                            .setDscpRemarkRate(DSCP_RATE)
+                                            .setPrecLevel(DSCP_PREC_LEVEL)
+                                            .build())
+                                    .build()))
+                    .build())
+            .build();
+
+    private MeterMessageSerializer serializer;
+
+
+    @Override
+    protected void init() {
+        serializer = getRegistry().getSerializer(new MessageTypeKey<>(EncodeConstants.OF13_VERSION_ID, MeterMessage.class)) ;
+    }
+
+    @Test
+    public void testSerialize() throws Exception {
+        final ByteBuf out = UnpooledByteBufAllocator.DEFAULT.buffer();
+        serializer.serialize(MESSAGE, out);
+
+        // Header
+        assertEquals(out.readByte(), VERSION);
+        assertEquals(out.readByte(), serializer.getMessageType());
+        assertEquals(out.readShort(), LENGTH);
+        assertEquals(out.readInt(), XID.intValue());
+
+        // Body
+        assertEquals(out.readShort(), COMMAND.getIntValue());
+        assertEquals(out.readShort(), ByteBufUtils.fillBitMask(0,
+                IS_METER_KBPS,
+                IS_METER_PKTPS,
+                IS_METER_BURST,
+                IS_METER_STATS));
+        assertEquals(out.readInt(), METER_ID.intValue());
+
+        // Drop band
+        assertEquals(out.readShort(), MeterBandType.OFPMBTDROP.getIntValue());
+        assertEquals(out.readShort(), LENGTH_OF_METER_BANDS);
+        assertEquals(out.readInt(), DROP_RATE.intValue());
+        assertEquals(out.readInt(), DROP_BURST_SIZE.intValue());
+        out.skipBytes(PADDING_IN_METER_BAND_DROP);
+
+        // Dscp band
+        assertEquals(out.readShort(), MeterBandType.OFPMBTDSCPREMARK.getIntValue());
+        assertEquals(out.readShort(), LENGTH_OF_METER_BANDS);
+        assertEquals(out.readInt(), DSCP_RATE.intValue());
+        assertEquals(out.readInt(), DSCP_BURST_SIZE.intValue());
+        assertEquals(out.readByte(), DSCP_PREC_LEVEL);
+        out.skipBytes(PADDING_IN_METER_BAND_DSCP_REMARK);
+
+        assertEquals(out.readableBytes(), 0);
+    }
+
+}
\ No newline at end of file