org.opendaylight.protocol.pcep.ietf.stateful07.PathBindingTlvParser.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.protocol.pcep.ietf.stateful07.PathBindingTlvParser.java

Source

/*
 * Copyright (c) 2016 Cisco Systems, Inc. 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.protocol.pcep.ietf.stateful07;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.util.Map;
import org.opendaylight.protocol.pcep.spi.PCEPDeserializerException;
import org.opendaylight.protocol.pcep.spi.TlvParser;
import org.opendaylight.protocol.pcep.spi.TlvSerializer;
import org.opendaylight.protocol.pcep.spi.TlvUtil;
import org.opendaylight.protocol.util.ByteBufWriteUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.PathBinding;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.PathBindingBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.path.binding.BindingTypeValue;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.path.binding.binding.type.value.MplsLabel;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.path.binding.binding.type.value.MplsLabelBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.path.binding.binding.type.value.MplsLabelEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.path.binding.tlv.path.binding.binding.type.value.MplsLabelEntryBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Tlv;
import org.opendaylight.yangtools.concepts.Codec;

/**
 * Parser for {@link PathBinding}
 */
public final class PathBindingTlvParser implements TlvParser, TlvSerializer {

    // TODO: to be confirmed by IANA
    public static final int TYPE = 31;

    private static final int MPLS_LABEL = 0;
    private static final int MPLS_STACK_ENTRY = 1;

    private static final int LABEL_MASK = 0xfffff;
    private static final int TC_MASK = 0x7;
    private static final int S_MASK = 0x1;
    private static final int TTL_MASK = 0xff;
    private static final int LABEL_SHIFT = 12;
    private static final int TC_SHIFT = LABEL_SHIFT - 3;
    private static final int S_SHIFT = TC_SHIFT - 1;
    private static final int MPLS_ENTRY_LENGTH = 4;
    private static final int MPLS_BINDING_LENGTH = MPLS_ENTRY_LENGTH + 2;

    private static final Map<Integer, PathBindingTlvCodec> BT_PARSERS;
    private static final Map<Class<? extends BindingTypeValue>, PathBindingTlvCodec> BT_SERIALIZERS;

    static {
        final MplsLabelCodec mplsLabelCodec = new MplsLabelCodec();
        final MplsLabelEntryCodec mplsLabelEntryCodec = new MplsLabelEntryCodec();
        final Builder<Integer, PathBindingTlvCodec> parsers = ImmutableMap.<Integer, PathBindingTlvCodec>builder();
        final Builder<Class<? extends BindingTypeValue>, PathBindingTlvCodec> serializers = ImmutableMap
                .<Class<? extends BindingTypeValue>, PathBindingTlvCodec>builder();

        parsers.put(mplsLabelCodec.getBindingType(), mplsLabelCodec);
        serializers.put(MplsLabel.class, mplsLabelCodec);

        parsers.put(mplsLabelEntryCodec.getBindingType(), mplsLabelEntryCodec);
        serializers.put(MplsLabelEntry.class, mplsLabelEntryCodec);

        BT_PARSERS = parsers.build();
        BT_SERIALIZERS = serializers.build();
    }

    @Override
    public void serializeTlv(final Tlv tlv, final ByteBuf buffer) {
        Preconditions.checkArgument(tlv instanceof PathBinding, "The TLV must be PathBinding type, but was %s",
                tlv.getClass());
        final PathBinding pTlv = (PathBinding) tlv;
        final BindingTypeValue bindingTypeValue = pTlv.getBindingTypeValue();
        Preconditions.checkArgument(
                (pTlv.getBindingValue() != null && pTlv.getBindingType() != null) || bindingTypeValue != null,
                "Missing Binding Value in Path Bidning TLV: %s", pTlv);
        final ByteBuf body = Unpooled.buffer(MPLS_BINDING_LENGTH);
        if (bindingTypeValue == null) {
            backwardsSerializer(pTlv, body);
        } else {
            final PathBindingTlvCodec codec = BT_SERIALIZERS.get(bindingTypeValue.getImplementedInterface());
            Preconditions.checkArgument(codec != null, "Unsupported Path Binding Type: %s",
                    bindingTypeValue.getImplementedInterface());
            ByteBufWriteUtil.writeUnsignedShort(codec.getBindingType(), body);
            body.writeBytes(codec.serialize(bindingTypeValue));
        }
        TlvUtil.formatTlv(TYPE, body, buffer);
    }

    @Override
    public Tlv parseTlv(final ByteBuf buffer) throws PCEPDeserializerException {
        if (buffer == null) {
            return null;
        }
        final int type = buffer.readUnsignedShort();
        final PathBindingTlvCodec codec = BT_PARSERS.get(type);
        if (codec == null) {
            throw new PCEPDeserializerException("Unsupported Path Binding Type: " + type);
        }
        final PathBindingBuilder builder = new PathBindingBuilder();
        backwardsParser(type, buffer, builder);
        return builder.setBindingTypeValue(codec.deserialize(buffer)).build();
    }

    private void backwardsParser(final int type, final ByteBuf buffer, final PathBindingBuilder builder) {
        builder.setBindingType((short) type);
        final byte[] value = new byte[buffer.readableBytes()];
        //codec will do the reading from buffer
        buffer.getBytes(0, value);
        builder.setBindingValue(value);
    }

    private void backwardsSerializer(final PathBinding pTlv, final ByteBuf body) {
        ByteBufWriteUtil.writeUnsignedShort((int) pTlv.getBindingType(), body);
        body.writeBytes(pTlv.getBindingValue());
    }

    private static final class MplsLabelCodec implements PathBindingTlvCodec {

        @Override
        public ByteBuf serialize(final BindingTypeValue bindingValue) {
            final MplsLabel mplsLabel = (MplsLabel) bindingValue;
            final ByteBuf value = Unpooled.buffer(MPLS_ENTRY_LENGTH);
            ByteBufWriteUtil.writeUnsignedInt(getMplsStackEntry(mplsLabel.getMplsLabel()), value);
            return value;
        }

        @Override
        public BindingTypeValue deserialize(final ByteBuf buffer) {
            final MplsLabelBuilder builder = new MplsLabelBuilder();
            builder.setMplsLabel(getMplsLabel(buffer.readUnsignedInt()));
            return builder.build();
        }

        @Override
        public int getBindingType() {
            return MPLS_LABEL;
        }
    }

    private static final class MplsLabelEntryCodec implements PathBindingTlvCodec {

        @Override
        public ByteBuf serialize(final BindingTypeValue bindingValue) {
            final MplsLabelEntry mplsEntry = ((MplsLabelEntry) bindingValue);
            final ByteBuf value = Unpooled.buffer(MPLS_ENTRY_LENGTH);
            final long entry = getMplsStackEntry(mplsEntry.getLabel()) | mplsEntry.getTrafficClass() << TC_SHIFT
                    | (mplsEntry.isBottomOfStack() ? 1 : 0) << S_SHIFT | mplsEntry.getTimeToLive();
            ByteBufWriteUtil.writeUnsignedInt(entry, value);
            return value;
        }

        @Override
        public BindingTypeValue deserialize(final ByteBuf buffer) {
            final MplsLabelEntryBuilder builder = new MplsLabelEntryBuilder();
            final long entry = buffer.readUnsignedInt();
            builder.setLabel(getMplsLabel(entry));
            builder.setTrafficClass((short) ((entry >> TC_SHIFT) & TC_MASK));
            builder.setBottomOfStack(((entry >> S_SHIFT) & S_MASK) == 1);
            builder.setTimeToLive((short) (entry & TTL_MASK));
            return builder.build();
        }

        @Override
        public int getBindingType() {
            return MPLS_STACK_ENTRY;
        }
    }

    private interface PathBindingTlvCodec extends Codec<ByteBuf, BindingTypeValue> {
        int getBindingType();
    }

    private static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.MplsLabel getMplsLabel(
            final long mplsStackEntry) {
        return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.MplsLabel(
                (mplsStackEntry >> LABEL_SHIFT) & LABEL_MASK);
    }

    private static long getMplsStackEntry(
            final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.MplsLabel mplsLabel) {
        return mplsLabel.getValue() << LABEL_SHIFT;
    }

}