BUG-4622: Sending Empty Optional Attributes 48/29548/12
authorClaudio D. Gasparini <cgaspari@cisco.com>
Wed, 11 Nov 2015 12:23:46 +0000 (13:23 +0100)
committerGerrit Code Review <gerrit@opendaylight.org>
Sat, 14 Nov 2015 09:21:34 +0000 (09:21 +0000)
Some of the parsers of Optional Attributes
only take in account the possibility of null
attribute and not of an empty one.
Fix by check it and dont parse them in case of
empty or null.

Change-Id: I34d801a001ed167e18646e228b9b9dfc03f7c882
Signed-off-by: Claudio D. Gasparini <cgaspari@cisco.com>
bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ClusterIdAttributeParser.java
bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/CommunitiesAttributeParser.java
bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ExtendedCommunitiesAttributeParser.java
bgp/parser-impl/src/test/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ClusterIdAttributeParserTest.java [new file with mode: 0644]
bgp/parser-impl/src/test/java/org/opendaylight/protocol/bgp/parser/impl/message/update/CommunitiesAttributeParserTest.java [new file with mode: 0644]
bgp/parser-impl/src/test/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ExtendedCommunitiesAttributeParserTest.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/AttributeOperations.java

index 495c1d1c5f6958171bcfb5fed3083be600cee5b4..690d8155adb6905ccb7c98d4504e6674a99ecc84 100644 (file)
@@ -43,6 +43,10 @@ public final class ClusterIdAttributeParser implements AttributeParser, Attribut
         if (cid == null) {
             return;
         }
+        final List<ClusterIdentifier> cluster = cid.getCluster();
+        if (cluster == null  || cluster.isEmpty()) {
+            return;
+        }
         final ByteBuf clusterIdBuffer = Unpooled.buffer();
         for (final ClusterIdentifier clusterIdentifier : cid.getCluster()) {
             clusterIdBuffer.writeBytes(Ipv4Util.bytesForAddress(clusterIdentifier));
index e678ab7b1857760f0fa5f564685ec025f4abb9f2..a23a6977565eee0313a76dd60966352e224e0245 100644 (file)
@@ -81,9 +81,8 @@ public final class CommunitiesAttributeParser implements AttributeParser, Attrib
     @Override
     public void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
         Preconditions.checkArgument(attribute instanceof Attributes, "Attribute parameter is not a PathAttribute object.");
-        final Attributes pathAttributes = (Attributes) attribute;
-        final List<Communities> communities = pathAttributes.getCommunities();
-        if (communities == null) {
+        final List<Communities> communities = ((Attributes) attribute).getCommunities();
+        if (communities == null || communities.isEmpty()) {
             return;
         }
         final ByteBuf communitiesBuffer = Unpooled.buffer();
index 3ed0eed0939f5b190f730639e291fda892aa42f4..29bc1b165d5762ce46f64825e6387079ce2a160c 100644 (file)
@@ -50,7 +50,7 @@ public final class ExtendedCommunitiesAttributeParser implements AttributeParser
     public void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
         Preconditions.checkArgument(attribute instanceof Attributes, "Attribute parameter is not a PathAttribute object.");
         final List<ExtendedCommunities> communitiesList = ((Attributes) attribute).getExtendedCommunities();
-        if (communitiesList == null) {
+        if (communitiesList == null || communitiesList.isEmpty()) {
             return;
         }
         final ByteBuf extendedCommunitiesBuffer = Unpooled.buffer();
diff --git a/bgp/parser-impl/src/test/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ClusterIdAttributeParserTest.java b/bgp/parser-impl/src/test/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ClusterIdAttributeParserTest.java
new file mode 100644 (file)
index 0000000..b048f8b
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015 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.parser.impl.message.update;
+
+import com.google.common.collect.Lists;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import java.util.List;
+import junit.framework.TestCase;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+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.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.path.attributes.attributes.ClusterIdBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
+
+public class ClusterIdAttributeParserTest extends TestCase {
+    private static final byte[] clusterIdBytes = {(byte) 0x80, (byte) 0x0A, (byte) 0x08,
+        (byte) 0xC0, (byte) 0xA8, (byte) 0x1, (byte) 0x1,
+        (byte) 0xC0, (byte) 0xA8, (byte) 0x1, (byte) 0x2};
+    ClusterIdAttributeParser parser;
+
+    @Before
+    public void setUp() {
+        this.parser = new ClusterIdAttributeParser();
+    }
+
+    @Test
+    public void testParserAttribute() throws Exception {
+        final List<ClusterIdentifier> list = Lists.newArrayList();
+        final Ipv4Address ip1 = new Ipv4Address("192.168.1.1");
+        final Ipv4Address ip2 = new Ipv4Address("192.168.1.2");
+        list.add(new ClusterIdentifier(ip1));
+        list.add(new ClusterIdentifier(ip2));
+        final Attributes clusterId = new AttributesBuilder().setClusterId(new ClusterIdBuilder().setCluster
+            (list).build()).build();
+
+
+        final ByteBuf output = Unpooled.buffer();
+        this.parser.serializeAttribute(clusterId, output);
+
+        Assert.assertArrayEquals(clusterIdBytes, ByteArray.getAllBytes(output));
+
+        AttributesBuilder clusterIdOutput = new AttributesBuilder();
+        this.parser.parseAttribute(Unpooled.wrappedBuffer(ByteArray.cutBytes(clusterIdBytes, 3)), clusterIdOutput);
+        assertEquals(clusterId, clusterIdOutput.build());
+    }
+
+    @Test
+    public void testParseEmptyListAttribute() {
+        final List<ClusterIdentifier> list = Lists.newArrayList();
+        final Attributes clusterId = new AttributesBuilder().setClusterId(new ClusterIdBuilder().setCluster
+            (list).build()).build();
+        final ByteBuf output = Unpooled.buffer();
+        this.parser.serializeAttribute(clusterId, output);
+        assertEquals(Unpooled.buffer(), output);
+    }
+
+    @Test
+    public void testParseEmptyAttribute() {
+        final Attributes clusterId = new AttributesBuilder().setClusterId(new ClusterIdBuilder().build()).build();
+        final ByteBuf output = Unpooled.buffer();
+        this.parser.serializeAttribute(clusterId, output);
+        assertEquals(Unpooled.buffer(), output);
+    }
+}
\ No newline at end of file
diff --git a/bgp/parser-impl/src/test/java/org/opendaylight/protocol/bgp/parser/impl/message/update/CommunitiesAttributeParserTest.java b/bgp/parser-impl/src/test/java/org/opendaylight/protocol/bgp/parser/impl/message/update/CommunitiesAttributeParserTest.java
new file mode 100644 (file)
index 0000000..262a41e
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015 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.parser.impl.message.update;
+
+import com.google.common.collect.Lists;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import java.util.List;
+import junit.framework.TestCase;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.protocol.bgp.parser.spi.pojo.ServiceLoaderBGPExtensionProviderContext;
+import org.opendaylight.protocol.util.ByteArray;
+import org.opendaylight.protocol.util.NoopReferenceCache;
+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.path.attributes.attributes.Communities;
+
+public class CommunitiesAttributeParserTest extends TestCase {
+
+    private static final byte[] CommunitiesBytes = {(byte) 0xC0, (byte) 0x08, (byte) 0x10,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x1,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x2,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x3,
+        (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x10};
+
+    @Test
+    public void testCommunitiesAttributeParser() throws Exception {
+        final List<Communities> comms = Lists.newArrayList();
+        comms.add((Communities) CommunityUtil.NO_EXPORT);
+        comms.add((Communities) CommunityUtil.NO_ADVERTISE);
+        comms.add((Communities) CommunityUtil.NO_EXPORT_SUBCONFED);
+        comms.add((Communities) CommunityUtil.create(NoopReferenceCache.getInstance(), 0xFFFF, 0xFF10));
+
+        final AttributesBuilder paBuilder = new AttributesBuilder();
+        paBuilder.setCommunities(comms);
+
+        final ByteBuf actual = Unpooled.buffer();
+        ServiceLoaderBGPExtensionProviderContext.getSingletonInstance().getAttributeRegistry()
+            .serializeAttribute(paBuilder.build(), actual);
+        Assert.assertArrayEquals(CommunitiesBytes, ByteArray.getAllBytes(actual));
+        final Attributes attributeOut = ServiceLoaderBGPExtensionProviderContext.getSingletonInstance().getAttributeRegistry()
+            .parseAttributes(actual);
+        assertEquals(comms,attributeOut.getCommunities());
+    }
+
+    @Test
+    public void testParseEmptyListAttribute() {
+        final List<Communities> comms = Lists.newArrayList();
+        final ByteBuf actual = Unpooled.buffer();
+        ServiceLoaderBGPExtensionProviderContext.getSingletonInstance().getAttributeRegistry()
+            .serializeAttribute(new AttributesBuilder().setCommunities(comms).build(), actual);
+        assertEquals(Unpooled.buffer(), actual);
+    }
+
+    @Test
+    public void testParseEmptyAttribute() {
+        final ByteBuf actual = Unpooled.buffer();
+        ServiceLoaderBGPExtensionProviderContext.getSingletonInstance().getAttributeRegistry()
+            .serializeAttribute(new AttributesBuilder().build(), actual);
+        assertEquals(Unpooled.buffer(), actual);
+    }
+}
\ No newline at end of file
index 0025c8db2021ee9d8cc8b37cc8fcba7767447ba2..f2d09f8fe9578f86078968ab9729a42f32c2ac4b 100644 (file)
@@ -11,6 +11,8 @@ package org.opendaylight.protocol.bgp.parser.impl.message.update;
 import com.google.common.primitives.Bytes;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
+import java.util.ArrayList;
+import java.util.List;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -62,6 +64,23 @@ public class ExtendedCommunitiesAttributeParserTest {
         Assert.assertArrayEquals(Bytes.concat(new byte[] {(byte)192, 16, 8}, INPUT), ByteArray.readAllBytes(output));
     }
 
+    @Test
+    public void testEmptyListExtendedCommunityAttributeParser() throws BGPDocumentedException, BGPParsingException {
+        final List<ExtendedCommunities> extendedCommunitiesList = new ArrayList<>();
+        final AttributesBuilder attBuilder = new AttributesBuilder().setExtendedCommunities(extendedCommunitiesList);
+        final ByteBuf output = Unpooled.buffer();
+
+        handler.serializeAttribute(attBuilder.build(), output);
+        Assert.assertEquals(output, output);
+    }
+
+    @Test
+    public void testEmptyExtendedCommunityAttributeParser() throws BGPDocumentedException, BGPParsingException {
+        final ByteBuf output = Unpooled.buffer();
+        handler.serializeAttribute(new AttributesBuilder().build(), output);
+        Assert.assertEquals( Unpooled.buffer(), output);
+    }
+
     @Test
     public void testExtendedCommunityAttributeParserUnknown() throws BGPDocumentedException, BGPParsingException {
         final AttributesBuilder attBuilder = new AttributesBuilder();
index e509ee0f1f30c3cfae5dd37fac6b4298b1c953f3..0268c470c62b63e1f68dec00b9791d9906d99e30 100644 (file)
@@ -181,90 +181,81 @@ final class AttributeOperations {
     }
 
     /**
-     * Attributes when reflecting a route from Internal iBGP
+     * Attributes when reflecting a route from Internal iBGP (Application Peer)
      * @param attributes
      * @return
      */
     ContainerNode reflectedAttributes(final ContainerNode attributes) {
-        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> b = Builders.containerBuilder(attributes);
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> attributesContainer = Builders.containerBuilder(attributes);
 
-        // Create a new CLUSTER_LIST builder
-        final ListNodeBuilder<Object, LeafSetEntryNode<Object>> clb = Builders.orderedLeafSetBuilder();
-        clb.withNodeIdentifier(this.clusterListLeaf);
-
-        // if there was a CLUSTER_LIST attribute, add all other entries
+        // if there was a CLUSTER_LIST attribute, add it
         final Optional<NormalizedNode<?, ?>> maybeClusterList = NormalizedNodes.findNode(attributes, this.clusterListPath);
         if (maybeClusterList.isPresent()) {
-            final NormalizedNode<?, ?> clusterList = maybeClusterList.get();
-            if (clusterList instanceof LeafSetNode) {
-                for (final LeafSetEntryNode<?> n : ((LeafSetNode<?>)clusterList).getValue()) {
-                    // There's no way we can safely avoid this cast
-                    @SuppressWarnings("unchecked")
-                    final LeafSetEntryNode<Object> child = (LeafSetEntryNode<Object>)n;
-                    clb.addChild(child);
-                }
-            } else {
-                LOG.warn("Ignoring malformed CLUSTER_LIST {}", clusterList);
-            }
-        } else {
-            LOG.debug("Creating fresh CLUSTER_LIST attribute");
+            // Create a new CLUSTER_LIST builder
+            final ListNodeBuilder<Object, LeafSetEntryNode<Object>> clusterBuilder = Builders.orderedLeafSetBuilder();
+            clusterBuilder.withNodeIdentifier(this.clusterListLeaf);
+            AttributeOperations.addOtherClusterEntries(maybeClusterList, clusterBuilder);
+            // Now wrap it in a container and add it to attributes
+            final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> clusterListCont= Builders.containerBuilder();
+            clusterListCont.withNodeIdentifier(this.clusterListContainer);
+            clusterListCont.withChild(clusterBuilder.build());
+            attributesContainer.withChild(clusterListCont.build());
         }
 
-        // Now wrap it in a container and add it to attributes
-        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> cb = Builders.containerBuilder();
-        cb.withNodeIdentifier(this.clusterListContainer);
-        cb.withChild(clb.build());
-        b.withChild(cb.build());
-
-        return b.build();
+        return attributesContainer.build();
     }
 
     // Attributes when reflecting a route
     ContainerNode reflectedAttributes(final ContainerNode attributes, final Ipv4Address originatorId, final ClusterIdentifier clusterId) {
-        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> b = Builders.containerBuilder(attributes);
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> attributesContainer = Builders.containerBuilder(attributes);
 
         // Create a new CLUSTER_LIST builder
-        final ListNodeBuilder<Object, LeafSetEntryNode<Object>> clb = Builders.orderedLeafSetBuilder();
-        clb.withNodeIdentifier(this.clusterListLeaf);
+        final ListNodeBuilder<Object, LeafSetEntryNode<Object>> clusterBuilder = Builders.orderedLeafSetBuilder();
+        clusterBuilder.withNodeIdentifier(this.clusterListLeaf);
 
         // prepend local CLUSTER_ID
-        clb.withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(this.clusterQname, clusterId.getValue())).
+        clusterBuilder.withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(new NodeWithValue(this.clusterQname, clusterId.getValue())).
             withValue(clusterId.getValue()).build());
 
         // if there was a CLUSTER_LIST attribute, add all other entries
         final Optional<NormalizedNode<?, ?>> maybeClusterList = NormalizedNodes.findNode(attributes, this.clusterListPath);
         if (maybeClusterList.isPresent()) {
-            final NormalizedNode<?, ?> clusterList = maybeClusterList.get();
-            if (clusterList instanceof LeafSetNode) {
-                for (final LeafSetEntryNode<?> n : ((LeafSetNode<?>)clusterList).getValue()) {
-                    // There's no way we can safely avoid this cast
-                    @SuppressWarnings("unchecked")
-                    final LeafSetEntryNode<Object> child = (LeafSetEntryNode<Object>)n;
-                    clb.addChild(child);
-                }
-            } else {
-                LOG.warn("Ignoring malformed CLUSTER_LIST {}", clusterList);
-            }
+            AttributeOperations.addOtherClusterEntries(maybeClusterList, clusterBuilder);
         } else {
             LOG.debug("Creating fresh CLUSTER_LIST attribute");
         }
 
         // Now wrap it in a container and add it to attributes
-        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> cb = Builders.containerBuilder();
-        cb.withNodeIdentifier(this.clusterListContainer);
-        cb.withChild(clb.build());
-        b.withChild(cb.build());
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> clusterListCont = Builders.containerBuilder();
+        clusterListCont.withNodeIdentifier(this.clusterListContainer);
+        clusterListCont.withChild(clusterBuilder.build());
+        attributesContainer.withChild(clusterListCont.build());
 
         // add ORIGINATOR_ID if not present
         final Optional<NormalizedNode<?, ?>> maybeOriginatorId = NormalizedNodes.findNode(attributes, this.originatorIdPath);
         if (!maybeOriginatorId.isPresent()) {
-            final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> oib = Builders.containerBuilder();
-            oib.withNodeIdentifier(this.originatorIdContainer);
-            oib.withChild(ImmutableNodes.leafNode(this.originatorIdLeaf, originatorId.getValue()));
-            b.withChild(oib.build());
+            final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> originatorIDBuilder = Builders.containerBuilder();
+            originatorIDBuilder.withNodeIdentifier(this.originatorIdContainer);
+            originatorIDBuilder.withChild(ImmutableNodes.leafNode(this.originatorIdLeaf, originatorId.getValue()));
+            attributesContainer.withChild(originatorIDBuilder.build());
         }
 
-        return b.build();
+        return attributesContainer.build();
+    }
+
+    private static void addOtherClusterEntries(final Optional<NormalizedNode<?, ?>> maybeClusterList, final ListNodeBuilder<Object,
+        LeafSetEntryNode<Object>> clb) {
+        final NormalizedNode<?, ?> clusterList = maybeClusterList.get();
+        if (clusterList instanceof LeafSetNode) {
+            for (final LeafSetEntryNode<?> n : ((LeafSetNode<?>) clusterList).getValue()) {
+                // There's no way we can safely avoid this cast
+                @SuppressWarnings("unchecked")
+                final LeafSetEntryNode<Object> child = (LeafSetEntryNode<Object>) n;
+                clb.addChild(child);
+            }
+        } else {
+            LOG.warn("Ignoring malformed CLUSTER_LIST {}", clusterList);
+        }
     }
 
     private boolean isTransitiveAttribute(final DataContainerChild<? extends PathArgument, ?> child) {