Bug-4827: IPv4 Unicast codec for add-path 13/35613/15
authorMilos Fabian <milfabia@cisco.com>
Wed, 2 Mar 2016 14:25:37 +0000 (15:25 +0100)
committerRobert Varga <nite@hq.sk>
Sat, 23 Apr 2016 11:14:31 +0000 (11:14 +0000)
Implements IPv4 Unicast NLRI parser and extended
existing serializer to handle extended NLRI (path-id).

Change-Id: I367b78d33d8ae0b4c064a28cf28ed0aad82027e7
Signed-off-by: Milos Fabian <milfabia@cisco.com>
bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AdvertizedRoutesSerializer.java
bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/Ipv4NlriParser.java
bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/WithdrawnRoutesSerializer.java
bgp/parser-impl/src/test/java/org/opendaylight/protocol/bgp/parser/impl/Ipv4NlriParserTest.java

index 8af2a06765898edaf2a72ead05de111f511a97e7..fad07e96732e7726d92a34182a3176f5cd89b90c 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.protocol.bgp.parser.impl.message.update;
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
+import org.opendaylight.protocol.bgp.parser.spi.PathIdUtil;
 import org.opendaylight.protocol.util.ByteBufWriteUtil;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.destination.ipv4.Ipv4Prefixes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv6.prefixes.destination.ipv6.Ipv6Prefixes;
@@ -38,6 +39,7 @@ public class AdvertizedRoutesSerializer implements NlriSerializer {
         if (routes.getDestinationType() instanceof DestinationIpv4Case) {
             final DestinationIpv4Case destinationIpv4Case = (DestinationIpv4Case) routes.getDestinationType();
             for (final Ipv4Prefixes ipv4Prefix : destinationIpv4Case.getDestinationIpv4().getIpv4Prefixes()) {
+                PathIdUtil.writePathId(ipv4Prefix.getPathId(), byteAggregator);
                 ByteBufWriteUtil.writeMinimalPrefix(ipv4Prefix.getPrefix(), byteAggregator);
             }
         } else if (routes.getDestinationType() instanceof DestinationIpv6Case) {
index 97cf90468cffdeda5ce7ad249ed8245453fd747f..5edd5e749d52797c17cfa8bb13e18e7cf41bb908 100644 (file)
@@ -11,10 +11,12 @@ import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import java.util.ArrayList;
 import java.util.List;
-import org.opendaylight.protocol.bgp.parser.BGPParsingException;
+import org.opendaylight.protocol.bgp.parser.BgpTableTypeImpl;
+import org.opendaylight.protocol.bgp.parser.spi.MultiPathSupportUtil;
 import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
 import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
-import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.bgp.parser.spi.PathIdUtil;
+import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
 import org.opendaylight.protocol.util.ByteBufWriteUtil;
 import org.opendaylight.protocol.util.Ipv4Util;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
@@ -28,6 +30,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.mult
 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.AddressFamily;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.SubsequentAddressFamily;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 
 public final class Ipv4NlriParser implements NlriParser, NlriSerializer {
@@ -41,23 +45,39 @@ public final class Ipv4NlriParser implements NlriParser, NlriSerializer {
         }
     }
 
-    private static DestinationIpv4 prefixes(final ByteBuf nlri) {
-        final List<Ipv4Prefix> prefs = Ipv4Util.prefixListForBytes(ByteArray.readAllBytes(nlri));
-        final List<Ipv4Prefixes> prefixes = new ArrayList<>(prefs.size());
-        for (final Ipv4Prefix p : prefs) {
-            prefixes.add(new Ipv4PrefixesBuilder().setPrefix(p).build());
+    private static DestinationIpv4 prefixes(final ByteBuf nlri, final PeerSpecificParserConstraint constraints,
+            final Class<? extends AddressFamily> afi, final Class<? extends SubsequentAddressFamily> safi) {
+        final List<Ipv4Prefixes> prefixes = new ArrayList<>();
+        while (nlri.isReadable()) {
+            final Ipv4PrefixesBuilder prefixesBuilder = new Ipv4PrefixesBuilder();
+            if (MultiPathSupportUtil.isTableTypeSupported(constraints, new BgpTableTypeImpl(afi, safi))) {
+                prefixesBuilder.setPathId(PathIdUtil.readPathId(nlri));
+            }
+            prefixesBuilder.setPrefix(Ipv4Util.prefixForByteBuf(nlri));
+            prefixes.add(prefixesBuilder.build());
         }
         return new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build();
     }
 
     @Override
     public void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder) {
-        builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationIpv4CaseBuilder().setDestinationIpv4(
-            prefixes(nlri)).build()).build());
+        parseNlri(nlri, builder, null);
+    }
+
+    @Override
+    public void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder) {
+        parseNlri(nlri, builder, null);
     }
 
     @Override
-    public void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder) throws BGPParsingException {
-        builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(new DestinationIpv4CaseBuilder().setDestinationIpv4(prefixes(nlri)).build()).build());
+    public void parseNlri(final ByteBuf nlri, final MpReachNlriBuilder builder, final PeerSpecificParserConstraint constraint) {
+        builder.setAdvertizedRoutes(new AdvertizedRoutesBuilder().setDestinationType(
+                new DestinationIpv4CaseBuilder().setDestinationIpv4(prefixes(nlri, constraint, builder.getAfi(), builder.getSafi())).build()).build());
+    }
+
+    @Override
+    public void parseNlri(final ByteBuf nlri, final MpUnreachNlriBuilder builder, final PeerSpecificParserConstraint constraint) {
+        builder.setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationIpv4CaseBuilder().setDestinationIpv4(
+                prefixes(nlri, constraint, builder.getAfi(), builder.getSafi())).build()).build());
     }
 }
\ No newline at end of file
index 215c910e7590db49b1903cd4eb94fef704c7b8d8..bc9855f5151770e559bf96e51a5e3416cf49338d 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.protocol.bgp.parser.impl.message.update;
 import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
+import org.opendaylight.protocol.bgp.parser.spi.PathIdUtil;
 import org.opendaylight.protocol.util.ByteBufWriteUtil;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.destination.ipv4.Ipv4Prefixes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv6.prefixes.destination.ipv6.Ipv6Prefixes;
@@ -45,6 +46,7 @@ public class WithdrawnRoutesSerializer implements NlriSerializer {
             final DestinationIpv4Case destinationIpv4Case = (DestinationIpv4Case) routes.getDestinationType();
             if (destinationIpv4Case.getDestinationIpv4().getIpv4Prefixes() != null) {
                 for (final Ipv4Prefixes ipv4Prefix : destinationIpv4Case.getDestinationIpv4().getIpv4Prefixes()) {
+                    PathIdUtil.writePathId(ipv4Prefix.getPathId(), byteAggregator);
                     ByteBufWriteUtil.writeMinimalPrefix(ipv4Prefix.getPrefix(), byteAggregator);
                 }
             }
index 903f943617b73a85891ccdf718ec9a9daee7c4c7..5f55750ce761191167aa2193cd41887b8d8487e4 100644 (file)
@@ -13,6 +13,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+
 import com.google.common.collect.Lists;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
@@ -20,10 +21,19 @@ import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Optional;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
+import org.opendaylight.protocol.bgp.parser.impl.message.update.AdvertizedRoutesSerializer;
 import org.opendaylight.protocol.bgp.parser.impl.message.update.Ipv4NlriParser;
+import org.opendaylight.protocol.bgp.parser.impl.message.update.WithdrawnRoutesSerializer;
+import org.opendaylight.protocol.bgp.parser.spi.MultiPathSupport;
+import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
 import org.opendaylight.protocol.util.Ipv4Util;
 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.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.DestinationIpv4Builder;
@@ -31,10 +41,23 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.destination.ipv4.Ipv4PrefixesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationIpv4Case;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationIpv4CaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathId;
+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.message.rev130919.path.attributes.AttributesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.message.Nlri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.message.NlriBuilder;
+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.UnicastSubsequentAddressFamily;
 
 public class Ipv4NlriParserTest {
     private final Ipv4NlriParser parser = new Ipv4NlriParser();
@@ -46,6 +69,16 @@ public class Ipv4NlriParserTest {
     private final List<Ipv4Prefixes> prefixes = new ArrayList<>();
     private final ByteBuf inputBytes = Unpooled.buffer();
 
+    private static final byte[] MP_NLRI_BYTES = new byte[] {
+        0x0, 0x0, 0x0, 0x1, 0x18, 0x1, 0x1, 0x1,
+        0x0, 0x0, 0x0, 0x2, 0x18, 0x1, 0x1, 0x1};
+
+    private static final Ipv4Prefix DESTINATION = new Ipv4Prefix("1.1.1.0/24");
+
+    private static final ArrayList<Ipv4Prefixes> PREFIXES = Lists.newArrayList(
+            createIpv4Prefix(1L, DESTINATION),
+            createIpv4Prefix(2L, DESTINATION));
+
     private org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationIpv4Case ip4caseWD;
     private org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationIpv4Case ip4caseWDWrong;
     private DestinationIpv4Case ip4caseAD;
@@ -54,9 +87,15 @@ public class Ipv4NlriParserTest {
     private Nlri nlri;
     private Nlri nlriWrong;
 
+    @Mock
+    private PeerSpecificParserConstraint constraint;
+
+    @Mock
+    private MultiPathSupport muliPathSupport;
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         final Ipv4Prefix prefix1 = new Ipv4Prefix(this.ipPrefix1);
         final Ipv4Prefix prefix2 = new Ipv4Prefix(this.ipPrefix2);
         final Ipv4Prefix wrongPrefix = new Ipv4Prefix(this.additionalIpWD);
@@ -83,6 +122,8 @@ public class Ipv4NlriParserTest {
         final List<Ipv4Prefix> prefixWrongList = Lists.newArrayList(prefixList.iterator());
         prefixWrongList.add(wrongPrefix);
         this.nlriWrong = new NlriBuilder().setNlri(prefixWrongList).build();
+        Mockito.doReturn(Optional.of(this.muliPathSupport)).when(constraint).getPeerConstraint(Mockito.any());
+        Mockito.doReturn(true).when(this.muliPathSupport).isTableTypeSupported(Mockito.any());
     }
 
     @Test
@@ -105,6 +146,7 @@ public class Ipv4NlriParserTest {
     @Test
     public void parseUnreachedNlriTest() {
         final MpUnreachNlriBuilder b = new MpUnreachNlriBuilder();
+        b.setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class);
         this.parser.parseNlri(this.inputBytes, b);
         assertNotNull("Withdrawn routes, destination type should not be null", b.getWithdrawnRoutes().getDestinationType());
 
@@ -118,6 +160,7 @@ public class Ipv4NlriParserTest {
     @Test
     public void parseReachedNlriTest() throws BGPParsingException {
         final MpReachNlriBuilder b = new MpReachNlriBuilder();
+        b.setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class);
         this.parser.parseNlri(this.inputBytes, b);
         assertNotNull("Advertized routes, destination type should not be null", b.getAdvertizedRoutes().getDestinationType());
 
@@ -127,4 +170,50 @@ public class Ipv4NlriParserTest {
         assertTrue(this.ip4caseAD.toString().equals(b.getAdvertizedRoutes().getDestinationType().toString()));
         assertFalse(this.ip4caseADWrong.toString().equals(b.getAdvertizedRoutes().getDestinationType().toString()));
     }
+
+    @Test
+    public void parseReachNlriMultiPathTest() {
+        final MpReachNlri mpReachNlri = new MpReachNlriBuilder().setAdvertizedRoutes(
+                new AdvertizedRoutesBuilder().setDestinationType(
+                        new DestinationIpv4CaseBuilder().setDestinationIpv4(
+                                new DestinationIpv4Builder().setIpv4Prefixes(
+                                        PREFIXES).build()).build()).build()).build();
+        final MpReachNlriBuilder mpReachNlriBuilder = new MpReachNlriBuilder();
+        mpReachNlriBuilder.setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class);
+        this.parser.parseNlri(Unpooled.wrappedBuffer(MP_NLRI_BYTES), mpReachNlriBuilder, this.constraint);
+        mpReachNlriBuilder.setAfi(null).setSafi(null);
+        Assert.assertEquals(mpReachNlri, mpReachNlriBuilder.build());
+
+        final AdvertizedRoutesSerializer serializer = new AdvertizedRoutesSerializer();
+        final ByteBuf output = Unpooled.buffer(MP_NLRI_BYTES.length);
+        final Attributes attributes = new AttributesBuilder().addAugmentation(Attributes1.class,
+                new Attributes1Builder().setMpReachNlri(mpReachNlri).build()).build();
+        serializer.serializeAttribute(attributes, output);
+        Assert.assertArrayEquals(MP_NLRI_BYTES, output.array());
+    }
+
+    @Test
+    public void parseUnreachNlriMultiPathTest() {
+        final MpUnreachNlri mpUnreachNlri = new MpUnreachNlriBuilder().setWithdrawnRoutes(
+                new WithdrawnRoutesBuilder().setDestinationType(
+                        new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.attributes.mp.unreach.nlri.withdrawn.routes.destination.type.DestinationIpv4CaseBuilder().setDestinationIpv4(
+                                new DestinationIpv4Builder().setIpv4Prefixes(
+                                        PREFIXES).build()).build()).build()).build();
+        final MpUnreachNlriBuilder mpUnreachNlriBuilder = new MpUnreachNlriBuilder();
+        mpUnreachNlriBuilder.setAfi(Ipv4AddressFamily.class).setSafi(UnicastSubsequentAddressFamily.class);
+        this.parser.parseNlri(Unpooled.wrappedBuffer(MP_NLRI_BYTES), mpUnreachNlriBuilder, this.constraint);
+        mpUnreachNlriBuilder.setAfi(null).setSafi(null);
+        Assert.assertEquals(mpUnreachNlri, mpUnreachNlriBuilder.build());
+
+        final WithdrawnRoutesSerializer serializer = new WithdrawnRoutesSerializer();
+        final ByteBuf output = Unpooled.buffer(MP_NLRI_BYTES.length);
+        final Attributes attributes = new AttributesBuilder().addAugmentation(Attributes2.class,
+                new Attributes2Builder().setMpUnreachNlri(mpUnreachNlri).build()).build();
+        serializer.serializeAttribute(attributes, output);
+        Assert.assertArrayEquals(MP_NLRI_BYTES, output.array());
+    }
+
+    private static Ipv4Prefixes createIpv4Prefix(final long pathId, final Ipv4Prefix prefix) {
+        return new Ipv4PrefixesBuilder().setPathId(new PathId(pathId)).setPrefix(prefix).build();
+    }
 }