Bug-3464: Updated Path Binding TLV according draft version 01 51/21751/10
authorMilos Fabian <milfabia@cisco.com>
Wed, 3 Jun 2015 11:17:32 +0000 (13:17 +0200)
committerMilos Fabian <milfabia@cisco.com>
Thu, 9 Jun 2016 17:17:30 +0000 (19:17 +0200)
-fixed binding-type length
-binding type BT=0 - MPLS label
-new binding type BT=1 - MPLS stack entry

Deprecated previously used leafs in the TLV yang model, while
preserving backwards compatibility.

Change-Id: I5a0dfaf0cc53a04c355d0adb093c5cad2c70a0d9
Signed-off-by: Milos Fabian <milfabia@cisco.com>
pcep/ietf-stateful07/pom.xml
pcep/ietf-stateful07/src/main/java/org/opendaylight/protocol/pcep/ietf/stateful07/PathBindingTlvParser.java
pcep/ietf-stateful07/src/main/yang/odl-pcep-ietf-stateful07.yang
pcep/ietf-stateful07/src/test/java/org/opendaylight/protocol/pcep/ietf/PCEPTlvParserTest.java

index 483bbc66074d57d71584366e972d6813818eeaca..872f22004ac96808b9a22f4cfa0333e9af2085a5 100644 (file)
             <groupId>${project.groupId}</groupId>
             <artifactId>pcep-impl</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>concepts</artifactId>
+        </dependency>
 
         <!--
             FIXME: this is in support of the generated code. This should not
index 9b5fe3a4817a17e3ddd445df90322f8a053dc751..343bbd3feca337b70456606a0a87896ca1f61560 100644 (file)
@@ -1,49 +1,90 @@
 /*
- * 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);
     }
 
@@ -52,11 +93,96 @@ public class PathBindingTlvParser implements TlvParser, TlvSerializer {
         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;
+    }
+
 }
index a61cdafa86d1be0259b040d36c9e88c2523047f0..15daadb604455cc02f976fcc71367dfb1f76946f 100644 (file)
@@ -13,6 +13,7 @@ module odl-pcep-ietf-stateful07 {
     import topology-tunnel-pcep { prefix tun; revision-date 2013-08-20; }
     import topology-tunnel-pcep-programming { prefix ttpp; revision-date 2013-10-30; }
     import yang-ext { prefix ext; revision-date 2013-07-09; }
+    import network-concepts { prefix netc; revision-date 2013-11-25; }
 
     organization "Cisco Systems, Inc.";
     contact "Robert Varga <rovarga@cisco.com>";
@@ -73,17 +74,42 @@ module odl-pcep-ietf-stateful07 {
     }
 
     grouping path-binding-tlv {
-        reference "https://tools.ietf.org/html/draft-sivabalan-pce-binding-label-sid-00#section-3";
+        reference "https://tools.ietf.org/html/draft-sivabalan-pce-binding-label-sid-01#section-3";
         container path-binding {
             uses pcep:tlv;
             leaf binding-type {
+                status deprecated;
                 type uint8;
             }
             leaf binding-value {
+                status deprecated;
                 type binary {
                     length 0..255;
                 }
             }
+            choice binding-type-value {
+                case mpls-label {
+                    leaf mpls-label {
+                        type netc:mpls-label;
+                    }
+                }
+                case mpls-label-entry {
+                    leaf label {
+                        type netc:mpls-label;
+                    }
+                    leaf traffic-class {
+                        type uint8 {
+                            range 0..7;
+                        }
+                    }
+                    leaf bottom-of-stack {
+                        type boolean;
+                    }
+                    leaf time-to-live {
+                        type uint8;
+                    }
+                }
+            }
         }
     }
 
index ab79d7517b60d748b02baaff4f837c3a4b547887..872cb726499306830506dab0cf425f373eabe7b5 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.protocol.pcep.ietf;
 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;
@@ -27,6 +28,7 @@ import org.opendaylight.protocol.util.Ipv4Util;
 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;
@@ -37,6 +39,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.iet
 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;
@@ -206,16 +210,16 @@ public class PCEPTlvParserTest {
     }
 
     @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 {
@@ -223,7 +227,27 @@ public class PCEPTlvParserTest {
             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));
+    }
 }