/*
* Copyright (c) 2017 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.multipart;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
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.keys.ExperimenterIdDeserializerKey;
import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.multipart.reply.multipart.reply.body.MultipartReplyMeterConfigBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBandType;
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.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.band.type.band.type.Experimenter;
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.config.stats.reply.MeterConfigStats;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStatsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStatsKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.meter.band.headers.MeterBandHeader;
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.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
public class MultipartReplyMeterConfigDeserializer implements OFDeserializer<MultipartReplyBody>, DeserializerRegistryInjector {
private static final byte METER_CONFIG_LENGTH = 8;
private static final int OFPMBTDROP = 1;
private static final int OFPMBTDSCP = 2;
private static final int OFPMBTEXPERIMENTER = 0xFFFF;
private static final byte PADDING_IN_METER_BAND_DROP_HEADER = 4;
private static final byte PADDING_IN_METER_BAND_DSCP_HEADER = 3;
private DeserializerRegistry registry;
@Override
public MultipartReplyBody deserialize(ByteBuf message) {
final MultipartReplyMeterConfigBuilder builder = new MultipartReplyMeterConfigBuilder();
final List<MeterConfigStats> items = new ArrayList<>();
while (message.readableBytes() > 0) {
final int itemLength = message.readUnsignedShort();
final MeterConfigStatsBuilder itemBuilder = new MeterConfigStatsBuilder()
.setFlags(readMeterFlags(message))
.setMeterId(new MeterId(message.readUnsignedInt()));
final List<MeterBandHeader> subItems = new ArrayList<>();
int actualLength = METER_CONFIG_LENGTH;
while (actualLength < itemLength) {
final int itemStartIndex = message.readerIndex();
final int itemBandType = message.readUnsignedShort();
final MeterBandHeaderBuilder subItemBuilder = new MeterBandHeaderBuilder();
actualLength += message.readUnsignedShort();
switch (itemBandType) {
case OFPMBTDROP:
subItemBuilder
.setMeterBandTypes(new MeterBandTypesBuilder()
.setFlags(new MeterBandType(true, false, false))
.build())
.setBandType(new DropBuilder()
.setDropRate(message.readUnsignedInt())
.setDropBurstSize(message.readUnsignedInt())
.build());
message.skipBytes(PADDING_IN_METER_BAND_DROP_HEADER);
break;
case OFPMBTDSCP:
subItemBuilder
.setMeterBandTypes(new MeterBandTypesBuilder()
.setFlags(new MeterBandType(false, true, false))
.build())
.setBandType(new DscpRemarkBuilder()
.setDscpRemarkRate(message.readUnsignedInt())
.setDscpRemarkBurstSize(message.readUnsignedInt())
.setPrecLevel(message.readUnsignedByte())
.build());
message.skipBytes(PADDING_IN_METER_BAND_DSCP_HEADER);
break;
case OFPMBTEXPERIMENTER:
// TODO: Finish meter band experimenter deserialization
final long expId = message.getUnsignedInt(message.readerIndex() + 2 * EncodeConstants.SIZE_OF_INT_IN_BYTES);
message.readerIndex(itemStartIndex);
final OFDeserializer<Experimenter> deserializer = registry.getDeserializer(
new ExperimenterIdDeserializerKey(EncodeConstants.OF13_VERSION_ID, expId, Experimenter.class));
subItemBuilder
.setMeterBandTypes(new MeterBandTypesBuilder()
.setFlags(new MeterBandType(false, false, true))
.build())
.setBandType(deserializer.deserialize(message));
break;
}
subItems.add(subItemBuilder.build());
}
items.add(itemBuilder
.setKey(new MeterConfigStatsKey(itemBuilder.getMeterId()))
.setMeterBandHeaders(new MeterBandHeadersBuilder()
.setMeterBandHeader(subItems)
.build())
.build());
}
return builder
.setMeterConfigStats(items)
.build();
}
private static MeterFlags readMeterFlags(ByteBuf message) {
int input = message.readUnsignedShort();
final Boolean mfKBPS = (input & (1)) != 0;
final Boolean mfPKTPS = (input & (1 << 1)) != 0;
final Boolean mfBURST = (input & (1 << 2)) != 0;
final Boolean mfSTATS = (input & (1 << 3)) != 0;
return new MeterFlags(mfBURST, mfKBPS, mfPKTPS, mfSTATS);
}
@Override
public void injectDeserializerRegistry(DeserializerRegistry deserializerRegistry) {
registry = deserializerRegistry;
}
}