BUG-4825: BGP L3VPN handlers 64/34464/8
authorIveta Halanova <ihalanov@cisco.com>
Thu, 11 Feb 2016 12:46:43 +0000 (13:46 +0100)
committerIveta Halanova <ihalanov@cisco.com>
Wed, 17 Feb 2016 08:17:34 +0000 (09:17 +0100)
implemented VPN IPv4 Nlri and NextHop handler.
created BGPActivater and registered handlers.
Implemented unit tests.

ref.: https://tools.ietf.org/html/rfc4364#section-4.3

Change-Id: I6e8943ec78e7010792e37ad4c39e911025e13416
Signed-off-by: Iveta Halanova <ihalanov@cisco.com>
bgp/concepts/src/main/java/org/opendaylight/bgp/concepts/RouteDistinguisherUtil.java
bgp/l3vpn/pom.xml
bgp/l3vpn/src/main/java/org/opendaylight/protocol/bgp/l3vpn/BGPActivator.java [new file with mode: 0644]
bgp/l3vpn/src/main/java/org/opendaylight/protocol/bgp/l3vpn/VpnIpv4NextHopParserSerializer.java [new file with mode: 0644]
bgp/l3vpn/src/main/java/org/opendaylight/protocol/bgp/l3vpn/VpnIpv4NlriParser.java [new file with mode: 0644]
bgp/l3vpn/src/main/yang/bgp-vpn-ipv4.yang
bgp/l3vpn/src/test/java/org/opendaylight/protocol/bgp/l3vpn/BGPActivatorTest.java [new file with mode: 0644]
bgp/l3vpn/src/test/java/org/opendaylight/protocol/bgp/l3vpn/VpnIpv4NextHopTest.java [new file with mode: 0644]
bgp/l3vpn/src/test/java/org/opendaylight/protocol/bgp/l3vpn/VpnIpv4NlriParserTest.java [new file with mode: 0644]
bgp/labeled-unicast/src/main/java/org/opendaylight/protocol/bgp/labeled/unicast/LUNlriParser.java

index 2816feff8409852456886661095884e524df39bf..ce9a1fb4bd8522fda7b5d7eb1222f53208a0c0b6 100644 (file)
@@ -21,6 +21,7 @@ public final class RouteDistinguisherUtil {
     private static final int IPV4_TYPE = 1;
     private static final int AS_4BYTE_TYPE = 2;
     private static final char SEPARATOR = ':';
+    public static final int RD_LENGTH = 8;
 
     private RouteDistinguisherUtil() {
         throw new UnsupportedOperationException();
index 46faecec1f31d5e13a9c66f2431cd515333a0777..0640366aec5206386c6aee246e72555caf220620 100644 (file)
             <groupId>${project.groupId}</groupId>
             <artifactId>bgp-labeled-unicast</artifactId>
         </dependency>
+
+        <!-- test scope dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/bgp/l3vpn/src/main/java/org/opendaylight/protocol/bgp/l3vpn/BGPActivator.java b/bgp/l3vpn/src/main/java/org/opendaylight/protocol/bgp/l3vpn/BGPActivator.java
new file mode 100644 (file)
index 0000000..9169ca8
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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.bgp.l3vpn;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.protocol.bgp.parser.spi.AbstractBGPExtensionProviderActivator;
+import org.opendaylight.protocol.bgp.parser.spi.BGPExtensionProviderContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.vpn.ipv4.routes.VpnIpv4Routes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.MplsLabeledVpnSubsequentAddressFamily;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.Ipv4NextHopCase;
+
+public final class BGPActivator extends AbstractBGPExtensionProviderActivator {
+
+    @Override
+    protected List<AutoCloseable> startImpl(final BGPExtensionProviderContext context) {
+        final List<AutoCloseable> regs = new ArrayList<>();
+
+        final VpnIpv4NlriParser nlriParser = new VpnIpv4NlriParser();
+        final VpnIpv4NextHopParserSerializer nextHopParser = new VpnIpv4NextHopParserSerializer();
+
+        regs.add(context.registerNlriParser(Ipv4AddressFamily.class, MplsLabeledVpnSubsequentAddressFamily.class,
+            nlriParser, nextHopParser, Ipv4NextHopCase.class));
+        regs.add(context.registerNlriSerializer(VpnIpv4Routes.class, nlriParser));
+
+        return regs;
+    }
+
+}
diff --git a/bgp/l3vpn/src/main/java/org/opendaylight/protocol/bgp/l3vpn/VpnIpv4NextHopParserSerializer.java b/bgp/l3vpn/src/main/java/org/opendaylight/protocol/bgp/l3vpn/VpnIpv4NextHopParserSerializer.java
new file mode 100644 (file)
index 0000000..a209f9a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.bgp.l3vpn;
+
+import com.google.common.base.Preconditions;
+import io.netty.buffer.ByteBuf;
+import org.opendaylight.bgp.concepts.NextHopUtil;
+import org.opendaylight.bgp.concepts.RouteDistinguisherUtil;
+import org.opendaylight.protocol.bgp.parser.BGPParsingException;
+import org.opendaylight.protocol.bgp.parser.spi.NextHopParserSerializer;
+import org.opendaylight.protocol.util.Ipv4Util;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.CNextHop;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.Ipv4NextHopCase;
+
+public final class VpnIpv4NextHopParserSerializer implements NextHopParserSerializer {
+
+    @Override
+    public CNextHop parseNextHop(final ByteBuf buffer) throws BGPParsingException {
+        Preconditions.checkArgument(buffer.readableBytes() == (Ipv4Util.IP4_LENGTH + RouteDistinguisherUtil.RD_LENGTH), "Length of byte array for NEXT_HOP should be %s, but is %s", Ipv4Util.IP4_LENGTH + RouteDistinguisherUtil.RD_LENGTH, buffer.readableBytes());
+        buffer.readBytes(RouteDistinguisherUtil.RD_LENGTH);
+        return NextHopUtil.parseNextHop(buffer.readBytes(Ipv4Util.IP4_LENGTH));
+    }
+
+    @Override
+    public void serializeNextHop(final CNextHop cNextHop, final ByteBuf byteAggregator) {
+        Preconditions.checkArgument(cNextHop instanceof Ipv4NextHopCase, "cNextHop is not a VPN Ipv4 NextHop object.");
+        byteAggregator.writeZero(RouteDistinguisherUtil.RD_LENGTH);
+        NextHopUtil.serializeNextHop(cNextHop, byteAggregator);
+    }
+
+}
diff --git a/bgp/l3vpn/src/main/java/org/opendaylight/protocol/bgp/l3vpn/VpnIpv4NlriParser.java b/bgp/l3vpn/src/main/java/org/opendaylight/protocol/bgp/l3vpn/VpnIpv4NlriParser.java
new file mode 100644 (file)
index 0000000..6864970
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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.bgp.l3vpn;
+
+import com.google.common.base.Preconditions;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.bgp.concepts.RouteDistinguisherUtil;
+import org.opendaylight.protocol.bgp.labeled.unicast.LUNlriParser;
+import org.opendaylight.protocol.bgp.parser.BGPParsingException;
+import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
+import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationVpnIpv4CaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.update.attributes.mp.reach.nlri.advertized.routes.destination.type.destination.vpn.ipv4._case.DestinationVpnIpv4Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationVpnIpv4Case;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.vpn.ipv4.destination.VpnIpv4Destination;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.vpn.ipv4.destination.VpnIpv4DestinationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.labeled.unicast.rev150525.labeled.unicast.LabelStack;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Attributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlriBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlriBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AddressFamily;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+
+public class VpnIpv4NlriParser implements NlriParser, NlriSerializer {
+
+    @Override
+    public void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
+        Preconditions.checkArgument(attribute instanceof Attributes, "Attribute parameter is not a Attributes object");
+        final Attributes pathAttributes = (Attributes) attribute;
+        final Attributes1 pathAttributes1 = pathAttributes.getAugmentation(Attributes1.class);
+        final Attributes2 pathAttributes2 = pathAttributes.getAugmentation(Attributes2.class);
+        if (pathAttributes1 != null) {
+            final AdvertizedRoutes routes = (pathAttributes1.getMpReachNlri()).getAdvertizedRoutes();
+            if ((routes != null) && (routes.getDestinationType() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationVpnIpv4Case)) {
+                final org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationVpnIpv4Case labeledUnicastCase = (org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationVpnIpv4Case) routes.getDestinationType();
+                serializeNlri(labeledUnicastCase.getDestinationVpnIpv4().getVpnIpv4Destination(), byteAggregator);
+            }
+        } else if (pathAttributes2 != null) {
+            final MpUnreachNlri mpUnreachNlri = pathAttributes2.getMpUnreachNlri();
+            if ((mpUnreachNlri.getWithdrawnRoutes() != null) && (mpUnreachNlri.getWithdrawnRoutes().getDestinationType() instanceof DestinationVpnIpv4Case)) {
+                final DestinationVpnIpv4Case labeledUnicastCase = (DestinationVpnIpv4Case) mpUnreachNlri.getWithdrawnRoutes().getDestinationType();
+                serializeNlri(labeledUnicastCase.getDestinationVpnIpv4().getVpnIpv4Destination(), byteAggregator);
+            }
+        }
+    }
+
+    protected static void serializeNlri(final List<VpnIpv4Destination> dests, final ByteBuf buffer) {
+        final ByteBuf nlriByteBuf = Unpooled.buffer();
+        for (final VpnIpv4Destination dest: dests) {
+            final List<LabelStack> labelStack = dest.getLabelStack();
+            final IpPrefix prefix = dest.getPrefix();
+            // Serialize the length field
+            // Length field contains one Byte which represents the length of label stack and prefix in bits
+            nlriByteBuf.writeByte(((LUNlriParser.LABEL_LENGTH * labelStack.size()) + LUNlriParser.getPrefixLength(prefix) + RouteDistinguisherUtil.RD_LENGTH) * Byte.SIZE);
+
+            LUNlriParser.serializeLabelStackEntries(labelStack, nlriByteBuf);
+            RouteDistinguisherUtil.serializeRouteDistinquisher(dest.getRouteDistinguisher(), nlriByteBuf);
+            Preconditions.checkNotNull(prefix.getIpv4Prefix(), "Ipv4 prefix is missing.");
+            LUNlriParser.serializePrefixField(prefix, nlriByteBuf);
+        }
+        buffer.writeBytes(nlriByteBuf);
+    }
+
+    @Override
+    public void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder) throws BGPParsingException {
+        if (!nlri.isReadable()) {
+            return;
+        }
+        final List<VpnIpv4Destination> dst = parseNlri(nlri, builder.getAfi());
+
+        builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
+            new org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationVpnIpv4CaseBuilder().setDestinationVpnIpv4(
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.destination.vpn.ipv4._case.DestinationVpnIpv4Builder().setVpnIpv4Destination(
+                    dst).build()).build()).build());
+    }
+
+    @Override
+    public void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder) throws BGPParsingException {
+        if (!nlri.isReadable()) {
+            return;
+        }
+        final List<VpnIpv4Destination> dst = parseNlri(nlri, builder.getAfi());
+
+        builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
+            new DestinationVpnIpv4CaseBuilder().setDestinationVpnIpv4(
+                new DestinationVpnIpv4Builder().setVpnIpv4Destination(
+                    dst).build()).build()).build());
+    }
+
+    private static List<VpnIpv4Destination> parseNlri(final ByteBuf nlri, final Class<? extends AddressFamily> afi) {
+        if (!nlri.isReadable()) {
+            return null;
+        }
+        final List<VpnIpv4Destination> dests = new ArrayList<>();
+
+        while (nlri.isReadable()) {
+            final VpnIpv4DestinationBuilder builder = new VpnIpv4DestinationBuilder();
+            final short length = nlri.readUnsignedByte();
+            builder.setLabelStack(LUNlriParser.parseLabel(nlri));
+            final int labelNum = builder.getLabelStack().size();
+            final int prefixLen = length - (LUNlriParser.LABEL_LENGTH * Byte.SIZE * labelNum) - (RouteDistinguisherUtil.RD_LENGTH * Byte.SIZE);
+            builder.setRouteDistinguisher(RouteDistinguisherUtil.parseRouteDistinguisher(nlri));
+            Preconditions.checkState(prefixLen > 0, "VPN IPv4 is required.");
+            builder.setPrefix(LUNlriParser.parseIpPrefix(nlri, prefixLen, afi));
+            dests.add(builder.build());
+        }
+        return dests;
+    }
+
+}
index 535fa6a15f5570a0e03792484acfa37bd218462d..797e3f25326ddf35279ed9821357372bfdbb825b 100644 (file)
@@ -37,7 +37,7 @@ module bgp-vpn-ipv4 {
     }
 
     grouping vpn-ipv4-destination {
-        list c-vpn-ipv4-destination {
+        list vpn-ipv4-destination {
             uses vpn-ipv4;
         }
     }
diff --git a/bgp/l3vpn/src/test/java/org/opendaylight/protocol/bgp/l3vpn/BGPActivatorTest.java b/bgp/l3vpn/src/test/java/org/opendaylight/protocol/bgp/l3vpn/BGPActivatorTest.java
new file mode 100644 (file)
index 0000000..59d4912
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.bgp.l3vpn;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.opendaylight.protocol.bgp.parser.spi.BGPExtensionProviderContext;
+import org.opendaylight.protocol.bgp.parser.spi.pojo.SimpleBGPExtensionProviderContext;
+
+public class BGPActivatorTest {
+
+    @Test
+    public void testActivator() throws Exception {
+        final BGPActivator act = new BGPActivator();
+        final BGPExtensionProviderContext context = new SimpleBGPExtensionProviderContext();
+        assertFalse(context.getNlriRegistry().getSerializers().iterator().hasNext());
+        act.start(context);
+        assertTrue(context.getNlriRegistry().getSerializers().iterator().next() instanceof VpnIpv4NlriParser);
+        act.close();
+    }
+}
diff --git a/bgp/l3vpn/src/test/java/org/opendaylight/protocol/bgp/l3vpn/VpnIpv4NextHopTest.java b/bgp/l3vpn/src/test/java/org/opendaylight/protocol/bgp/l3vpn/VpnIpv4NextHopTest.java
new file mode 100644 (file)
index 0000000..4a49c19
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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.bgp.l3vpn;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.junit.Test;
+import org.opendaylight.protocol.bgp.parser.BGPParsingException;
+import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.CNextHop;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.Ipv4NextHopCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.Ipv4NextHopCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.ipv4.next.hop._case.Ipv4NextHopBuilder;
+
+public class VpnIpv4NextHopTest {
+
+    private static final VpnIpv4NextHopParserSerializer HANDLER = new VpnIpv4NextHopParserSerializer();
+
+    @Test
+    public void testSerializeIpv4NextHopCase() throws BGPParsingException {
+        final ByteBuf buffer = Unpooled.buffer();
+        final byte[] nextHop = {0, 0, 0, 0, 0, 0, 0, 0, 42, 42, 42, 42};
+        final CNextHop hop = new Ipv4NextHopCaseBuilder().setIpv4NextHop(new Ipv4NextHopBuilder()
+            .setGlobal(new Ipv4Address("42.42.42.42")).build()).build();
+
+        HANDLER.serializeNextHop(hop, buffer);
+        assertArrayEquals(nextHop, ByteArray.readAllBytes(buffer));
+
+        final CNextHop parsedHop = HANDLER.parseNextHop(Unpooled.wrappedBuffer(nextHop));
+        assertTrue(hop instanceof Ipv4NextHopCase);
+        assertEquals(hop, parsedHop);
+    }
+}
diff --git a/bgp/l3vpn/src/test/java/org/opendaylight/protocol/bgp/l3vpn/VpnIpv4NlriParserTest.java b/bgp/l3vpn/src/test/java/org/opendaylight/protocol/bgp/l3vpn/VpnIpv4NlriParserTest.java
new file mode 100644 (file)
index 0000000..b617a77
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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.bgp.l3vpn;
+
+import com.google.common.collect.Lists;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import java.util.List;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.protocol.bgp.parser.BGPParsingException;
+import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationVpnIpv4CaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.update.attributes.mp.reach.nlri.advertized.routes.destination.type.destination.vpn.ipv4._case.DestinationVpnIpv4Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.vpn.ipv4.destination.VpnIpv4Destination;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.vpn.ipv4.destination.VpnIpv4DestinationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.labeled.unicast.rev150525.labeled.unicast.LabelStack;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.labeled.unicast.rev150525.labeled.unicast.LabelStackBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.AttributesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlriBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlriBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RouteDistinguisher;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.network.concepts.rev131125.MplsLabel;
+
+
+public class VpnIpv4NlriParserTest {
+
+    private static final VpnIpv4NlriParser PARSER = new VpnIpv4NlriParser();
+
+    private static final byte[] NLRI_TYPE1 = new byte[] {
+        (byte) 0x70,
+        (byte) 0x00, (byte) 0x16, (byte) 0x31,
+        0, 1, 1, 2, 3, 4, 1, 2,
+        (byte) 0x22, (byte) 0x01, (byte) 0x16,
+    };
+    private static final IpPrefix IPv4_PREFIX = new IpPrefix(new Ipv4Prefix("34.1.22.0/24"));
+    private static final List<LabelStack> LABEL_STACK = Lists.newArrayList(
+        new LabelStackBuilder().setLabelValue(new MplsLabel(355L)).build());
+    private static final RouteDistinguisher DISTINGUISHER = new RouteDistinguisher("1.2.3.4:258");
+    private static final VpnIpv4Destination VPN = new VpnIpv4DestinationBuilder().setRouteDistinguisher(DISTINGUISHER).setPrefix(IPv4_PREFIX).setLabelStack(LABEL_STACK).build();
+
+    @Test
+    public void testMpReachNlri() throws BGPParsingException {
+        final MpReachNlriBuilder mpBuilder = new MpReachNlriBuilder();
+        mpBuilder.setAfi(Ipv4AddressFamily.class);
+        mpBuilder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
+            new DestinationVpnIpv4CaseBuilder().setDestinationVpnIpv4(
+                new DestinationVpnIpv4Builder().setVpnIpv4Destination(Lists.newArrayList(VPN)).build()).build()).build());
+
+        final MpReachNlri mpReachExpected = mpBuilder.build();
+
+        final MpReachNlriBuilder testBuilder = new MpReachNlriBuilder();
+        testBuilder.setAfi(Ipv4AddressFamily.class);
+        PARSER.parseNlri(Unpooled.copiedBuffer(NLRI_TYPE1), testBuilder);
+        Assert.assertEquals(mpReachExpected, testBuilder.build());
+
+        final ByteBuf output = Unpooled.buffer();
+        PARSER.serializeAttribute(new AttributesBuilder().addAugmentation(Attributes1.class,
+            new Attributes1Builder().setMpReachNlri(mpReachExpected).build()).build(), output);
+        Assert.assertArrayEquals(NLRI_TYPE1, ByteArray.readAllBytes(output));
+    }
+
+    @Test
+    public void testMpUnreachNlri() throws BGPParsingException {
+        final MpUnreachNlriBuilder mpBuilder = new MpUnreachNlriBuilder();
+        mpBuilder.setAfi(Ipv4AddressFamily.class);
+        mpBuilder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(
+            new org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationVpnIpv4CaseBuilder().setDestinationVpnIpv4(
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.bgp.vpn.ipv4.rev160210.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.destination.vpn.ipv4._case.DestinationVpnIpv4Builder().setVpnIpv4Destination(Lists.newArrayList(VPN)).build()).build()).build());
+
+        final MpUnreachNlri mpUnreachExpected = mpBuilder.build();
+
+        final MpUnreachNlriBuilder testBuilder = new MpUnreachNlriBuilder();
+        testBuilder.setAfi(Ipv4AddressFamily.class);
+        PARSER.parseNlri(Unpooled.copiedBuffer(NLRI_TYPE1), testBuilder);
+        Assert.assertEquals(mpUnreachExpected, testBuilder.build());
+
+        final ByteBuf output = Unpooled.buffer();
+        PARSER.serializeAttribute(new AttributesBuilder().addAugmentation(Attributes2.class,
+            new Attributes2Builder().setMpUnreachNlri(mpUnreachExpected).build()).build(), output);
+        Assert.assertArrayEquals(NLRI_TYPE1, ByteArray.readAllBytes(output));
+    }
+}
index 8a0e2e065778ca39bd5de9594c8e7f9611e2d9b9..b143dbe368efd61944b0bf6147122ecf4cafe162 100644 (file)
@@ -45,7 +45,7 @@ import org.opendaylight.yangtools.yang.binding.DataObject;
 
 public class LUNlriParser implements NlriParser, NlriSerializer {
 
-    private static final int LABEL_LENGTH = 3;
+    public static final int LABEL_LENGTH = 3;
 
     @Override
     public void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
@@ -55,13 +55,13 @@ public class LUNlriParser implements NlriParser, NlriSerializer {
         final Attributes2 pathAttributes2 = pathAttributes.getAugmentation(Attributes2.class);
         if (pathAttributes1 != null) {
             final AdvertizedRoutes routes = (pathAttributes1.getMpReachNlri()).getAdvertizedRoutes();
-            if (routes != null && routes.getDestinationType() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.labeled.unicast.rev150525.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLabeledUnicastCase) {
+            if ((routes != null) && (routes.getDestinationType() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.labeled.unicast.rev150525.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLabeledUnicastCase)) {
                 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.labeled.unicast.rev150525.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLabeledUnicastCase labeledUnicastCase = (org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.labeled.unicast.rev150525.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationLabeledUnicastCase) routes.getDestinationType();
                 serializeNlri(labeledUnicastCase.getDestinationLabeledUnicast().getCLabeledUnicastDestination(), byteAggregator);
             }
         } else if (pathAttributes2 != null) {
             final MpUnreachNlri mpUnreachNlri = pathAttributes2.getMpUnreachNlri();
-            if (mpUnreachNlri.getWithdrawnRoutes() != null && mpUnreachNlri.getWithdrawnRoutes().getDestinationType() instanceof DestinationLabeledUnicastCase) {
+            if ((mpUnreachNlri.getWithdrawnRoutes() != null) && (mpUnreachNlri.getWithdrawnRoutes().getDestinationType() instanceof DestinationLabeledUnicastCase)) {
                 final DestinationLabeledUnicastCase labeledUnicastCase = (DestinationLabeledUnicastCase) mpUnreachNlri.getWithdrawnRoutes().getDestinationType();
                 serializeNlri(labeledUnicastCase.getDestinationLabeledUnicast().getCLabeledUnicastDestination(), byteAggregator);
             }
@@ -73,30 +73,34 @@ public class LUNlriParser implements NlriParser, NlriSerializer {
         for (final CLabeledUnicastDestination dest: dests) {
             final List<LabelStack> labelStack = dest.getLabelStack();
             final IpPrefix prefix = dest.getPrefix();
-            final int stackSize = labelStack.size();
             // Serialize the length field
             // Length field contains one Byte which represents the length of label stack and prefix in bits
-            nlriByteBuf.writeByte((LABEL_LENGTH * stackSize + getPrefixLength(prefix)) * Byte.SIZE);
-
-            // Serialize the label stack entries
-            int i = 1;
-            for (final LabelStack labelStackEntry : labelStack) {
-                if (i++ == stackSize) {
-                    //mark last label stack entry with bottom-bit
-                    nlriByteBuf.writeBytes(MplsLabelUtil.byteBufForMplsLabelWithBottomBit(labelStackEntry.getLabelValue()));
-                } else {
-                    nlriByteBuf.writeBytes(MplsLabelUtil.byteBufForMplsLabel(labelStackEntry.getLabelValue()));
-                }
-            }
+            nlriByteBuf.writeByte(((LABEL_LENGTH * labelStack.size()) + getPrefixLength(prefix)) * Byte.SIZE);
 
-            // Serialize the prefix field
-            final byte[] prefixBytes = getPrefixBytes(prefix);
-            nlriByteBuf.writeBytes(Arrays.copyOfRange(prefixBytes, 1, prefixBytes.length));
+            serializeLabelStackEntries(labelStack, nlriByteBuf);
+            serializePrefixField(prefix, nlriByteBuf);
         }
         buffer.writeBytes(nlriByteBuf);
     }
 
-    private static int getPrefixLength(final IpPrefix prefix) {
+    public static void serializeLabelStackEntries(final List<LabelStack> stack, final ByteBuf buffer) {
+        int i = 1;
+        for (final LabelStack labelStackEntry : stack) {
+            if (i++ == stack.size()) {
+                //mark last label stack entry with bottom-bit
+                buffer.writeBytes(MplsLabelUtil.byteBufForMplsLabelWithBottomBit(labelStackEntry.getLabelValue()));
+            } else {
+                buffer.writeBytes(MplsLabelUtil.byteBufForMplsLabel(labelStackEntry.getLabelValue()));
+            }
+        }
+    }
+
+    public static void serializePrefixField(final IpPrefix prefix, final ByteBuf buffer) {
+        final byte[] prefixBytes = getPrefixBytes(prefix);
+        buffer.writeBytes(Arrays.copyOfRange(prefixBytes, 1, prefixBytes.length));
+    }
+
+    public static int getPrefixLength(final IpPrefix prefix) {
         if (prefix.getIpv4Prefix() != null) {
             return Ipv4Util.getPrefixLengthBytes(prefix.getIpv4Prefix().getValue());
         }
@@ -133,23 +137,26 @@ public class LUNlriParser implements NlriParser, NlriSerializer {
         while (nlri.isReadable()) {
             final CLabeledUnicastDestinationBuilder builder = new CLabeledUnicastDestinationBuilder();
             final short length = nlri.readUnsignedByte();
-
             builder.setLabelStack(parseLabel(nlri));
-
             final int labelNum = builder.getLabelStack().size();
-            final int prefixLen = length - LABEL_LENGTH * Byte.SIZE * labelNum;
-            final int prefixLenInByte = prefixLen / Byte.SIZE + ((prefixLen % Byte.SIZE == 0) ? 0 : 1);
-            if (afi.equals(Ipv4AddressFamily.class)) {
-                builder.setPrefix(new IpPrefix(Ipv4Util.prefixForBytes(ByteArray.readBytes(nlri, prefixLenInByte), prefixLen)));
-            } else if (afi.equals(Ipv6AddressFamily.class)) {
-                builder.setPrefix(new IpPrefix(Ipv6Util.prefixForBytes(ByteArray.readBytes(nlri, prefixLenInByte), prefixLen)));
-            }
+            final int prefixLen = length - (LABEL_LENGTH * Byte.SIZE * labelNum);
+            builder.setPrefix(parseIpPrefix(nlri, prefixLen, afi));
             dests.add(builder.build());
         }
         return dests;
     }
 
-    private static List<LabelStack> parseLabel(final ByteBuf nlri) {
+    public static IpPrefix parseIpPrefix(final ByteBuf nlri, final int prefixLen, final Class<? extends AddressFamily> afi) {
+        final int prefixLenInByte = (prefixLen / Byte.SIZE) + (((prefixLen % Byte.SIZE) == 0) ? 0 : 1);
+        if (afi.equals(Ipv4AddressFamily.class)) {
+            return new IpPrefix(Ipv4Util.prefixForBytes(ByteArray.readBytes(nlri, prefixLenInByte), prefixLen));
+        } else if (afi.equals(Ipv6AddressFamily.class)) {
+            return new IpPrefix(Ipv6Util.prefixForBytes(ByteArray.readBytes(nlri, prefixLenInByte), prefixLen));
+        }
+        return null;
+    }
+
+    public static List<LabelStack> parseLabel(final ByteBuf nlri) {
         if (!nlri.isReadable()) {
             return null;
         }