From eaf8a5614c007bdd665ea6d77f9ebd8dd9fa70f5 Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Mon, 21 Nov 2016 10:18:07 +0100 Subject: [PATCH] Add MeterMessage serializer 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 --- .../MessageSerializerInjector.java | 5 +- .../messages/MeterMessageSerializer.java | 115 ++++++++++++++ .../messages/MeterMessageSerializerTest.java | 150 ++++++++++++++++++ 3 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/MeterMessageSerializer.java create mode 100644 openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/MeterMessageSerializerTest.java diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/MessageSerializerInjector.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/MessageSerializerInjector.java index a1a50f99a3..c5b1924d35 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/MessageSerializerInjector.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/MessageSerializerInjector.java @@ -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, Consumer>> 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 index 0000000000..404a9d573a --- /dev/null +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/MeterMessageSerializer.java @@ -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 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 key = + new ExperimenterIdSerializerKey<>( + EncodeConstants.OF13_VERSION_ID, + band.getExperimenter(), + (Class) type.getImplementedInterface()); + + try { + final OFSerializer 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 index 0000000000..5bf30a587c --- /dev/null +++ b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/protocol/serialization/messages/MeterMessageSerializerTest.java @@ -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 -- 2.36.6