/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ * 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 static org.opendaylight.protocol.util.ByteBufWriteUtil.writeUnsignedByte;
+package org.opendaylight.protocol.pcep.ietf.stateful07;
import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
+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.Set;
+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.ByteArray;
+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 class PathBindingTlvParser implements TlvParser, TlvSerializer {
+public final class PathBindingTlvParser implements TlvParser, TlvSerializer {
// TODO: to be confirmed by IANA
public static final int TYPE = 31;
- private static final short MPLS_LABEL = 0;
+ 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();
- protected static final Set<Short> BINDING_TYPES = ImmutableSet.of(MPLS_LABEL);
+ 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, "PathBinding is mandatory.");
+ Preconditions.checkArgument(tlv instanceof PathBinding, "The TLV must be PathBinding type, but was %s", tlv.getClass());
final PathBinding pTlv = (PathBinding) tlv;
- final Short bType = pTlv.getBindingType();
- Preconditions.checkArgument(BINDING_TYPES.contains(bType), "Unsupported Path Binding Type: %s", bType);
- final ByteBuf body = Unpooled.buffer();
- writeUnsignedByte(bType, body);
- body.writeBytes(pTlv.getBindingValue());
+ 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);
}
if (buffer == null) {
return null;
}
- final short type = buffer.readUnsignedByte();
- if (!BINDING_TYPES.contains(type)) {
- throw new PCEPDeserializerException("Unsupported Path Binding Type.");
+ 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;
}
- final byte[] value = ByteArray.readAllBytes(buffer);
- return new PathBindingBuilder().setBindingType(type).setBindingValue(value).build();
}
+
+ 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;
+ }
+
}
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.junit.Test;
import org.opendaylight.protocol.util.Ipv6Util;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.iana.rev130816.EnterpriseNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.MplsLabel;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.error.code.tlv.LspErrorCode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.error.code.tlv.LspErrorCodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.identifiers.tlv.LspIdentifiers;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.lsp.identifiers.tlv.lsp.identifiers.address.family.ipv6._case.Ipv6Builder;
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.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.MplsLabelEntryBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.rsvp.error.spec.tlv.RsvpErrorSpec;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.rsvp.error.spec.tlv.RsvpErrorSpecBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev131222.rsvp.error.spec.tlv.rsvp.error.spec.error.type.RsvpCaseBuilder;
}
@Test
- public void testPathBindingTlv() throws PCEPDeserializerException {
- final byte[] pathBindingBytes = {0, 0x1f, 0, 4, 0, 1, 2, 3};
+ public void testPathBindingTlvMplsLabel() throws PCEPDeserializerException {
+ final byte[] pathBindingBytes = {0x00, 0x1f, 0x00, 0x06, 0x00, 0x00, (byte) 0xA8, 0x0F, (byte) 0x60, 0x00, 0x00, 0x00};
final PathBindingTlvParser parser = new PathBindingTlvParser();
final PathBindingBuilder builder = new PathBindingBuilder();
builder.setBindingType((short) 0);
- builder.setBindingValue(new byte[] {1, 2, 3});
- final PathBinding tlv = builder.build();
- assertEquals(tlv, parser.parseTlv(Unpooled.wrappedBuffer(ByteArray.cutBytes(pathBindingBytes, 4))));
+ builder.setBindingTypeValue(new MplsLabelBuilder().setMplsLabel(new MplsLabel(688_374L)).build());
+ assertEquals(builder.setBindingValue(new byte[] {0x00, 0x00, (byte) 0xA8, 0x0F, (byte) 0x60, 0x00}).build(),
+ parser.parseTlv(Unpooled.wrappedBuffer(ByteArray.cutBytes(pathBindingBytes, 4))));
final ByteBuf buff = Unpooled.buffer();
- parser.serializeTlv(tlv, buff);
+ parser.serializeTlv(builder.build(), buff);
assertArrayEquals(pathBindingBytes, ByteArray.readAllBytes(buff));
try {
parser.parseTlv(Unpooled.wrappedBuffer(ByteArray.cutBytes(wrong, 4)));
fail();
} catch(final PCEPDeserializerException e) {
- assertEquals("Unsupported Path Binding Type.", e.getMessage());
+ assertEquals("Unsupported Path Binding Type: 257", e.getMessage());
}
}
+
+ @Test
+ public void testPathBindingTlvMplsLabelEntry() throws PCEPDeserializerException {
+ final byte[] pathBindingBytes = {0x00, 0x1f, 0x00, 0x06, 0x00, 0x01, (byte) 0xA8, (byte) 0x0F, (byte) 0x6D, (byte)0xAD, 0x00, 0x00};
+ final PathBindingTlvParser parser = new PathBindingTlvParser();
+ final PathBindingBuilder builder = new PathBindingBuilder();
+ builder.setBindingType((short) 1);
+ builder.setBindingTypeValue(
+ new MplsLabelEntryBuilder()
+ .setTrafficClass((short) 6)
+ .setTimeToLive((short) 173)
+ .setBottomOfStack(true)
+ .setLabel(new MplsLabel(688_374L)).build());
+ final PathBinding tlv = builder.build();
+ assertEquals(builder.setBindingValue(new byte[] {0x00, 0x01, (byte) 0xA8, (byte) 0x0F, (byte) 0x6D, (byte)0xAD}).build(),
+ parser.parseTlv(Unpooled.wrappedBuffer(ByteArray.cutBytes(pathBindingBytes, 4))));
+ final ByteBuf buff = Unpooled.buffer();
+ parser.serializeTlv(tlv, buff);
+ assertArrayEquals(pathBindingBytes, ByteArray.readAllBytes(buff));
+ }
}