From 6b4d2ffc2d63d4b10f5879a35963e570b2a1bc96 Mon Sep 17 00:00:00 2001 From: Martin Bobak Date: Thu, 29 May 2014 16:23:32 +0200 Subject: [PATCH] Bug 611 - serialization of path attributes - added Nlri,originatorId and clusterId serialization to BGPUPdateMessageParser - added Ipv4NextHopCase Ipv6NextHopCase serialization - added serialization methods to attribute objects - attribute_flags and attribute_type added to all attribute serializers - attribute descriptors unified by AttributeDescriptor interface - added tests for Update message serialization Change-Id: I49e6bb6c0883f125a24fa2a058f0f0bf0e404261 Signed-off-by: Martin Bobak --- .../protocol/bgp/parser/AttributeFlags.java | 24 ++ .../impl/message/BGPUpdateMessageParser.java | 54 ++++- .../update/AggregatorAttributeParser.java | 15 +- .../message/update/AsPathAttributeParser.java | 38 ++-- .../AtomicAggregateAttributeParser.java | 13 +- .../update/ClusterIdAttributeParser.java | 21 +- .../update/CommunitiesAttributeParser.java | 14 +- .../ExtendedCommunitiesAttributeParser.java | 47 ++-- .../impl/message/update/Ipv4NlriParser.java | 15 +- .../LocalPreferenceAttributeParser.java | 9 +- ...MultiExitDiscriminatorAttributeParser.java | 6 +- .../update/NextHopAttributeParser.java | 20 +- .../message/update/OriginAttributeParser.java | 10 +- .../update/OriginatorIdAttributeParser.java | 25 ++- .../BGPUpdateAttributesSerializationTest.java | 208 ++++++++++++++++++ .../bgp/parser/spi/NlriSerializer.java | 6 +- .../protocol/concepts/Ipv4Util.java | 16 +- 17 files changed, 462 insertions(+), 79 deletions(-) create mode 100644 bgp/parser-api/src/main/java/org/opendaylight/protocol/bgp/parser/AttributeFlags.java create mode 100644 bgp/parser-impl/src/test/java/org/opendaylight/protocol/bgp/parser/impl/BGPUpdateAttributesSerializationTest.java diff --git a/bgp/parser-api/src/main/java/org/opendaylight/protocol/bgp/parser/AttributeFlags.java b/bgp/parser-api/src/main/java/org/opendaylight/protocol/bgp/parser/AttributeFlags.java new file mode 100644 index 0000000000..67b0eb5454 --- /dev/null +++ b/bgp/parser-api/src/main/java/org/opendaylight/protocol/bgp/parser/AttributeFlags.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2014 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; + +public final class AttributeFlags { + + private AttributeFlags(){ + + } + + public static final int OPTIONAL = 128; + public static final int TRANSITIVE = 64; + public static final int PARTIAL = 32; + public static final int EXTENDED = 16; + public static final int UNUSED_8 = 8; + public static final int UNUSED_4 = 4; + public static final int UNUSED_2 = 2; + public static final int UNUSED_1 = 1; +} diff --git a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/BGPUpdateMessageParser.java b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/BGPUpdateMessageParser.java index 94209f2353..ebdf468258 100644 --- a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/BGPUpdateMessageParser.java +++ b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/BGPUpdateMessageParser.java @@ -1,25 +1,24 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * * Copyright (c) 2013 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; -import com.google.common.base.Preconditions; +import com.google.common.base.Preconditions; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; - import java.util.Arrays; import java.util.List; - import org.opendaylight.protocol.bgp.parser.BGPDocumentedException; import org.opendaylight.protocol.bgp.parser.BGPError; import org.opendaylight.protocol.bgp.parser.BGPParsingException; +import org.opendaylight.protocol.bgp.parser.impl.message.update.ClusterIdAttributeParser; +import org.opendaylight.protocol.bgp.parser.impl.message.update.OriginatorIdAttributeParser; import org.opendaylight.protocol.bgp.parser.spi.AttributeRegistry; import org.opendaylight.protocol.bgp.parser.spi.MessageParser; import org.opendaylight.protocol.bgp.parser.spi.MessageSerializer; @@ -29,8 +28,10 @@ import org.opendaylight.protocol.util.ByteArray; 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.message.rev130919.Update; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.UpdateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.Nlri; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.NlriBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.WithdrawnRoutes; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.WithdrawnRoutesBuilder; import org.opendaylight.yangtools.yang.binding.Notification; import org.slf4j.Logger; @@ -102,7 +103,7 @@ public class BGPUpdateMessageParser implements MessageParser, MessageSerializer } @Override - public void serializeMessage(Notification message,ByteBuf bytes) { + public void serializeMessage(Notification message, ByteBuf bytes) { if (message == null) { throw new IllegalArgumentException("BGPUpdate message cannot be null"); } @@ -110,13 +111,48 @@ public class BGPUpdateMessageParser implements MessageParser, MessageSerializer final Update update = (Update) message; ByteBuf messageBody = Unpooled.buffer(); + WithdrawnRoutes withdrawnRoutes = update.getWithdrawnRoutes(); + if (withdrawnRoutes != null) { + ByteBuf withdrawnRoutesBuf = Unpooled.buffer(); + for (Ipv4Prefix withdrawnRoutePrefix : withdrawnRoutes.getWithdrawnRoutes()) { + int prefixBits = Ipv4Util.getPrefixLength(withdrawnRoutePrefix.getValue()); + byte[] prefixBytes = ByteArray.subByte(Ipv4Util.bytesForPrefix(withdrawnRoutePrefix), 0, + Ipv4Util.getPrefixLengthBytes(withdrawnRoutePrefix.getValue())); + withdrawnRoutesBuf.writeByte(prefixBits); + withdrawnRoutesBuf.writeBytes(prefixBytes); + } + messageBody.writeShort(withdrawnRoutesBuf.writerIndex()); + messageBody.writeBytes(withdrawnRoutesBuf); + } else { + messageBody.writeZero(2); + } if (update.getPathAttributes() != null) { - this.reg.serializeAttribute(update.getPathAttributes(), messageBody); + ByteBuf pathAttributesBuf = Unpooled.buffer(); + this.reg.serializeAttribute(update.getPathAttributes(), pathAttributesBuf); + ClusterIdAttributeParser clusterIdAttributeParser = new ClusterIdAttributeParser(); + clusterIdAttributeParser.serializeAttribute(update.getPathAttributes(), pathAttributesBuf); + + OriginatorIdAttributeParser originatorIdAttributeParser = new OriginatorIdAttributeParser(); + originatorIdAttributeParser.serializeAttribute(update.getPathAttributes(), pathAttributesBuf); + + messageBody.writeShort(pathAttributesBuf.writerIndex()); + messageBody.writeBytes(pathAttributesBuf); + } else { + messageBody.writeZero(2); + } + Nlri nlri = update.getNlri(); + if (nlri != null) { + for (Ipv4Prefix ipv4Prefix : nlri.getNlri()) { + int prefixBits = Ipv4Util.getPrefixLength(ipv4Prefix.getValue()); + byte[] prefixBytes = ByteArray.subByte(Ipv4Util.bytesForPrefix(ipv4Prefix), 0, + Ipv4Util.getPrefixLengthBytes(ipv4Prefix.getValue())); + messageBody.writeByte(prefixBits); + messageBody.writeBytes(prefixBytes); + } } - LOG.trace("Update message serialized to {}", ByteBufUtil.hexDump(messageBody)); //FIXME: switch to ByteBuf - bytes.writeBytes(MessageUtil.formatMessage(TYPE,ByteArray.getAllBytes(messageBody))); + bytes.writeBytes(MessageUtil.formatMessage(TYPE, ByteArray.getAllBytes(messageBody))); } } diff --git a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AggregatorAttributeParser.java b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AggregatorAttributeParser.java index d02ef7d2e0..8d5a430eec 100644 --- a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AggregatorAttributeParser.java +++ b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AggregatorAttributeParser.java @@ -8,9 +8,9 @@ package org.opendaylight.protocol.bgp.parser.impl.message.update; import com.google.common.base.Preconditions; - import io.netty.buffer.ByteBuf; - +import io.netty.buffer.Unpooled; +import org.opendaylight.protocol.bgp.parser.AttributeFlags; import org.opendaylight.protocol.bgp.parser.spi.AttributeParser; import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer; import org.opendaylight.protocol.concepts.Ipv4Util; @@ -22,6 +22,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.mess import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Aggregator; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.AggregatorBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ShortAsNumber; import org.opendaylight.yangtools.yang.binding.DataObject; public final class AggregatorAttributeParser implements AttributeParser, AttributeSerializer { @@ -55,7 +56,13 @@ public final class AggregatorAttributeParser implements AttributeParser, Attribu return; } Preconditions.checkArgument(aggregator.getAsNumber() != null, "Missing AS number that formed the aggregate route (encoded as 2 octets)."); - byteAggregator.writeInt(aggregator.getAsNumber().getValue().shortValue()); - byteAggregator.writeBytes(Ipv4Util.bytesForAddress(aggregator.getNetworkAddress())); + ShortAsNumber shortAsNumber = new ShortAsNumber(aggregator.getAsNumber()); + byteAggregator.writeByte(AttributeFlags.OPTIONAL | AttributeFlags.TRANSITIVE); + byteAggregator.writeByte(TYPE); + ByteBuf aggregatorBuffer = Unpooled.buffer(); + aggregatorBuffer.writeInt(shortAsNumber.getValue().intValue()); + aggregatorBuffer.writeBytes(Ipv4Util.bytesForAddress(aggregator.getNetworkAddress())); + byteAggregator.writeByte(aggregatorBuffer.writerIndex()); + byteAggregator.writeBytes(aggregatorBuffer); } } diff --git a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AsPathAttributeParser.java b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AsPathAttributeParser.java index 02831bef79..da9e2a123b 100644 --- a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AsPathAttributeParser.java +++ b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AsPathAttributeParser.java @@ -12,9 +12,9 @@ import com.google.common.collect.Lists; import com.google.common.primitives.UnsignedBytes; import io.netty.buffer.ByteBuf; - +import io.netty.buffer.Unpooled; import java.util.List; - +import org.opendaylight.protocol.bgp.parser.AttributeFlags; import org.opendaylight.protocol.bgp.parser.BGPDocumentedException; import org.opendaylight.protocol.bgp.parser.BGPError; import org.opendaylight.protocol.bgp.parser.BGPParsingException; @@ -55,8 +55,7 @@ public final class AsPathAttributeParser implements AttributeParser, AttributeSe /** * Parses AS_PATH from bytes. * - * @param buffer bytes to be parsed - * @return new ASPath object + * @param buffer bytes to be parsed @return new ASPath object * @throws BGPDocumentedException if there is no AS_SEQUENCE present (mandatory) * @throws BGPParsingException */ @@ -100,20 +99,29 @@ public final class AsPathAttributeParser implements AttributeParser, AttributeSe @Override public void serializeAttribute(DataObject attribute, ByteBuf byteAggregator) { PathAttributes pathAttributes = (PathAttributes) attribute; - if (pathAttributes.getAsPath() == null) { + AsPath asPath = pathAttributes.getAsPath(); + if (asPath == null) { return; } - AsPath asPath = pathAttributes.getAsPath(); - for (Segments segments : asPath.getSegments()) { - if (segments.getCSegment() instanceof AListCase) { - AListCase listCase = (AListCase) segments.getCSegment(); - AsPathSegmentParser.serializeAsSequence(listCase, byteAggregator); - } else if (segments.getCSegment() instanceof ASetCase) { - ASetCase set = (ASetCase) segments.getCSegment(); - AsPathSegmentParser.serializeAsSet(set, byteAggregator); - } else { - LOG.warn("CSegment class is neither AListCase nor ASetCase."); + + byteAggregator.writeByte(AttributeFlags.TRANSITIVE); + byteAggregator.writeByte(TYPE); + + ByteBuf segmentsBuffer = Unpooled.buffer(); + if (asPath.getSegments().size()>0) { + for (Segments segments : asPath.getSegments()) { + if (segments.getCSegment() instanceof AListCase) { + AListCase listCase = (AListCase) segments.getCSegment(); + AsPathSegmentParser.serializeAsSequence(listCase, segmentsBuffer); + } else if (segments.getCSegment() instanceof ASetCase) { + ASetCase set = (ASetCase) segments.getCSegment(); + AsPathSegmentParser.serializeAsSet(set, segmentsBuffer); + } else { + LOG.warn("Segment class is neither AListCase nor ASetCase."); + } } } + byteAggregator.writeByte(segmentsBuffer.writerIndex()); + byteAggregator.writeBytes(segmentsBuffer); } } diff --git a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AtomicAggregateAttributeParser.java b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AtomicAggregateAttributeParser.java index 520a39bec0..d912c29bcc 100644 --- a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AtomicAggregateAttributeParser.java +++ b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/AtomicAggregateAttributeParser.java @@ -8,9 +8,10 @@ package org.opendaylight.protocol.bgp.parser.impl.message.update; import io.netty.buffer.ByteBuf; - +import org.opendaylight.protocol.bgp.parser.AttributeFlags; import org.opendaylight.protocol.bgp.parser.spi.AttributeParser; import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathAttributes; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.AtomicAggregateBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributesBuilder; import org.opendaylight.yangtools.yang.binding.DataObject; @@ -18,6 +19,7 @@ import org.opendaylight.yangtools.yang.binding.DataObject; public final class AtomicAggregateAttributeParser implements AttributeParser,AttributeSerializer { public static final int TYPE = 6; + public static final int ATTR_LENGTH = 0; @Override public void parseAttribute(final ByteBuf buffer, final PathAttributesBuilder builder) { @@ -26,7 +28,12 @@ public final class AtomicAggregateAttributeParser implements AttributeParser,Att @Override public void serializeAttribute(DataObject attribute, ByteBuf byteAggregator) { - // FIXME: add attribute type/length, does not contain any value by definition - return; + PathAttributes pathAttributes = (PathAttributes) attribute; + if (pathAttributes.getAtomicAggregate() == null) { + return; + } + byteAggregator.writeByte(AttributeFlags.TRANSITIVE | AttributeFlags.PARTIAL); + byteAggregator.writeByte(TYPE); + byteAggregator.writeByte(ATTR_LENGTH); } } diff --git a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ClusterIdAttributeParser.java b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ClusterIdAttributeParser.java index 99c0f5834d..ee785f410b 100644 --- a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ClusterIdAttributeParser.java +++ b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ClusterIdAttributeParser.java @@ -10,13 +10,16 @@ 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 org.opendaylight.protocol.bgp.parser.AttributeFlags; import org.opendaylight.protocol.bgp.parser.spi.AttributeParser; import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer; import org.opendaylight.protocol.concepts.Ipv4Util; import org.opendaylight.protocol.util.ByteArray; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathAttributes; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributesBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier; import org.opendaylight.yangtools.yang.binding.DataObject; @@ -24,20 +27,30 @@ import org.opendaylight.yangtools.yang.binding.DataObject; public final class ClusterIdAttributeParser implements AttributeParser, AttributeSerializer { public static final int TYPE = 10; - - private static final int CLUSTER_LENGTH = 4; + public static final int ATTR_LENGTH = 4; @Override public void parseAttribute(final ByteBuf buffer, final PathAttributesBuilder builder) { final List list = Lists.newArrayList(); while (buffer.isReadable()) { - list.add(new ClusterIdentifier(Ipv4Util.addressForBytes(ByteArray.readBytes(buffer, CLUSTER_LENGTH)))); + list.add(new ClusterIdentifier(Ipv4Util.addressForBytes(ByteArray.readBytes(buffer, ATTR_LENGTH)))); } builder.setClusterId(list); } @Override public void serializeAttribute(DataObject attribute, ByteBuf byteAggregator) { - //TODO implement this + PathAttributes pathAttributes = (PathAttributes) attribute; + if (pathAttributes.getClusterId() == null) { + return; + } + ByteBuf clusterIdBuffer = Unpooled.buffer(); + for (ClusterIdentifier clusterIdentifier : pathAttributes.getClusterId()) { + clusterIdBuffer.writeBytes(Ipv4Util.bytesForAddress(clusterIdentifier)); + } + byteAggregator.writeByte(AttributeFlags.OPTIONAL); + byteAggregator.writeByte(TYPE); + byteAggregator.writeByte(clusterIdBuffer.writerIndex()); + byteAggregator.writeBytes(clusterIdBuffer); } } diff --git a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/CommunitiesAttributeParser.java b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/CommunitiesAttributeParser.java index fd03473398..a233ca96e8 100644 --- a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/CommunitiesAttributeParser.java +++ b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/CommunitiesAttributeParser.java @@ -9,11 +9,10 @@ package org.opendaylight.protocol.bgp.parser.impl.message.update; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; - import io.netty.buffer.ByteBuf; - +import io.netty.buffer.Unpooled; import java.util.List; - +import org.opendaylight.protocol.bgp.parser.AttributeFlags; import org.opendaylight.protocol.bgp.parser.BGPDocumentedException; import org.opendaylight.protocol.bgp.parser.spi.AttributeParser; import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer; @@ -27,6 +26,7 @@ import org.opendaylight.yangtools.yang.binding.DataObject; public final class CommunitiesAttributeParser implements AttributeParser, AttributeSerializer { public static final int TYPE = 8; + public static final int ATTR_LENGTH = 4; private final ReferenceCache refCache; @@ -52,8 +52,14 @@ public final class CommunitiesAttributeParser implements AttributeParser, Attrib if (communities == null) { return; } + ByteBuf communitiesBuffer = Unpooled.buffer(); for (Community community : communities) { - byteAggregator.writeInt(community.getAsNumber().getValue().intValue()); + communitiesBuffer.writeShort(community.getAsNumber().getValue().shortValue()); + communitiesBuffer.writeShort(community.getSemantics().shortValue()); } + byteAggregator.writeByte(AttributeFlags.TRANSITIVE | AttributeFlags.PARTIAL); + byteAggregator.writeByte(CommunitiesAttributeParser.TYPE); + byteAggregator.writeByte(communitiesBuffer.writerIndex()); + byteAggregator.writeBytes(communitiesBuffer); } } diff --git a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ExtendedCommunitiesAttributeParser.java b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ExtendedCommunitiesAttributeParser.java index 267d51ea7c..2cb3782ac9 100644 --- a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ExtendedCommunitiesAttributeParser.java +++ b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/ExtendedCommunitiesAttributeParser.java @@ -12,8 +12,10 @@ import com.google.common.collect.Lists; import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import java.util.List; +import org.opendaylight.protocol.bgp.parser.AttributeFlags; import org.opendaylight.protocol.bgp.parser.BGPDocumentedException; import org.opendaylight.protocol.bgp.parser.spi.AttributeParser; import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer; @@ -57,55 +59,60 @@ public final class ExtendedCommunitiesAttributeParser implements AttributeParser if (communitiesList == null) { return; } + ByteBuf extendedCommunitiesBuffer = Unpooled.buffer(); for (ExtendedCommunities extendedCommunities : communitiesList) { if (extendedCommunities.getCommSubType() != null) { - byteAggregator.writeShort(extendedCommunities.getCommSubType()); + extendedCommunitiesBuffer.writeShort(extendedCommunities.getCommSubType()); } if (extendedCommunities.getExtendedCommunity() instanceof AsSpecificExtendedCommunityCase) { AsSpecificExtendedCommunityCase asSpecificExtendedCommunity = (AsSpecificExtendedCommunityCase) extendedCommunities.getExtendedCommunity(); //TODO resolve types correctly - byteAggregator.writeByte(0); - byteAggregator.writeByte(1); + extendedCommunitiesBuffer.writeByte(0); + extendedCommunitiesBuffer.writeByte(1); - byteAggregator.writeShort(asSpecificExtendedCommunity.getAsSpecificExtendedCommunity().getGlobalAdministrator().getValue().shortValue()); - byteAggregator.writeBytes(asSpecificExtendedCommunity.getAsSpecificExtendedCommunity().getLocalAdministrator()); + extendedCommunitiesBuffer.writeShort(asSpecificExtendedCommunity.getAsSpecificExtendedCommunity().getGlobalAdministrator().getValue().shortValue()); + extendedCommunitiesBuffer.writeBytes(asSpecificExtendedCommunity.getAsSpecificExtendedCommunity().getLocalAdministrator()); } if (extendedCommunities.getExtendedCommunity() instanceof Inet4SpecificExtendedCommunityCase) { Inet4SpecificExtendedCommunityCase inet4SpecificExtendedCommunity = (Inet4SpecificExtendedCommunityCase) extendedCommunities.getExtendedCommunity(); //TODO resolve types correctly - byteAggregator.writeByte(1); - byteAggregator.writeByte(4); + extendedCommunitiesBuffer.writeByte(1); + extendedCommunitiesBuffer.writeByte(4); - byteAggregator.writeBytes(Ipv4Util.bytesForAddress(inet4SpecificExtendedCommunity.getInet4SpecificExtendedCommunity().getGlobalAdministrator())); - byteAggregator.writeBytes(inet4SpecificExtendedCommunity.getInet4SpecificExtendedCommunity().getLocalAdministrator()); + extendedCommunitiesBuffer.writeBytes(Ipv4Util.bytesForAddress(inet4SpecificExtendedCommunity.getInet4SpecificExtendedCommunity().getGlobalAdministrator())); + extendedCommunitiesBuffer.writeBytes(inet4SpecificExtendedCommunity.getInet4SpecificExtendedCommunity().getLocalAdministrator()); } if (extendedCommunities.getExtendedCommunity() instanceof OpaqueExtendedCommunityCase) { OpaqueExtendedCommunityCase opaqueExtendedCommunity = (OpaqueExtendedCommunityCase) extendedCommunities.getExtendedCommunity(); //TODO resolve types correctly - byteAggregator.writeByte(3); - byteAggregator.writeByte(4); + extendedCommunitiesBuffer.writeByte(3); + extendedCommunitiesBuffer.writeByte(4); - byteAggregator.writeBytes(opaqueExtendedCommunity.getOpaqueExtendedCommunity().getValue()); + extendedCommunitiesBuffer.writeBytes(opaqueExtendedCommunity.getOpaqueExtendedCommunity().getValue()); } if (extendedCommunities.getExtendedCommunity() instanceof RouteTargetExtendedCommunityCase) { RouteTargetExtendedCommunityCase routeTargetExtendedCommunity = (RouteTargetExtendedCommunityCase) extendedCommunities.getExtendedCommunity(); //TODO how to determine, which numbering space global administrator number is originated from - byteAggregator.writeByte(0); - byteAggregator.writeByte(2); + extendedCommunitiesBuffer.writeByte(0); + extendedCommunitiesBuffer.writeByte(2); - byteAggregator.writeShort(routeTargetExtendedCommunity.getRouteTargetExtendedCommunity().getGlobalAdministrator().getValue().shortValue()); - byteAggregator.writeBytes(routeTargetExtendedCommunity.getRouteTargetExtendedCommunity().getLocalAdministrator()); + extendedCommunitiesBuffer.writeShort(routeTargetExtendedCommunity.getRouteTargetExtendedCommunity().getGlobalAdministrator().getValue().shortValue()); + extendedCommunitiesBuffer.writeBytes(routeTargetExtendedCommunity.getRouteTargetExtendedCommunity().getLocalAdministrator()); } if (extendedCommunities.getExtendedCommunity() instanceof RouteOriginExtendedCommunityCase) { RouteOriginExtendedCommunityCase routeOriginExtendedCommunity = (RouteOriginExtendedCommunityCase) extendedCommunities.getExtendedCommunity(); //TODO how to determine, which numbering space global administrator number is originated from - byteAggregator.writeByte(2); - byteAggregator.writeByte(3); - byteAggregator.writeShort(routeOriginExtendedCommunity.getRouteOriginExtendedCommunity().getGlobalAdministrator().getValue().shortValue()); - byteAggregator.writeBytes(routeOriginExtendedCommunity.getRouteOriginExtendedCommunity().getLocalAdministrator()); + extendedCommunitiesBuffer.writeByte(2); + extendedCommunitiesBuffer.writeByte(3); + extendedCommunitiesBuffer.writeShort(routeOriginExtendedCommunity.getRouteOriginExtendedCommunity().getGlobalAdministrator().getValue().shortValue()); + extendedCommunitiesBuffer.writeBytes(routeOriginExtendedCommunity.getRouteOriginExtendedCommunity().getLocalAdministrator()); } + byteAggregator.writeByte(AttributeFlags.OPTIONAL); + byteAggregator.writeByte(TYPE); + byteAggregator.writeByte(extendedCommunitiesBuffer.writerIndex()); + byteAggregator.writeBytes(extendedCommunitiesBuffer); } } } diff --git a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/Ipv4NlriParser.java b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/Ipv4NlriParser.java index 61b13c50da..a19341f5d3 100644 --- a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/Ipv4NlriParser.java +++ b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/Ipv4NlriParser.java @@ -9,16 +9,29 @@ package org.opendaylight.protocol.bgp.parser.impl.message.update; import io.netty.buffer.ByteBuf; +import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer; import org.opendaylight.protocol.concepts.Ipv4Util; import org.opendaylight.protocol.util.ByteArray; +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.message.rev130919.update.Nlri; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.destination.type.DestinationIpv4Case; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.destination.type.DestinationIpv4CaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.destination.destination.type.destination.ipv4._case.DestinationIpv4Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; + +public final class Ipv4NlriParser extends IpNlriParser implements NlriSerializer { -public final class Ipv4NlriParser extends IpNlriParser { @Override protected DestinationIpv4Case parseNlri(final ByteBuf nlri) { return new DestinationIpv4CaseBuilder().setDestinationIpv4( new DestinationIpv4Builder().setIpv4Prefixes(Ipv4Util.prefixListForBytes(ByteArray.readAllBytes(nlri))).build()).build(); } + + @Override + public void serializeAttribute(DataObject attribute, ByteBuf byteAggregator) { + Nlri nlri = (Nlri) attribute; + for (Ipv4Prefix ipv4Prefix : nlri.getNlri()) { + byteAggregator.writeBytes(Ipv4Util.bytesForPrefix(ipv4Prefix)); + } + } } \ No newline at end of file diff --git a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/LocalPreferenceAttributeParser.java b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/LocalPreferenceAttributeParser.java index 5b46f3c0b0..d66b1b3652 100644 --- a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/LocalPreferenceAttributeParser.java +++ b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/LocalPreferenceAttributeParser.java @@ -8,7 +8,7 @@ package org.opendaylight.protocol.bgp.parser.impl.message.update; import io.netty.buffer.ByteBuf; - +import org.opendaylight.protocol.bgp.parser.AttributeFlags; import org.opendaylight.protocol.bgp.parser.spi.AttributeParser; import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathAttributes; @@ -20,6 +20,7 @@ import org.opendaylight.yangtools.yang.binding.DataObject; public final class LocalPreferenceAttributeParser implements AttributeParser,AttributeSerializer { public static final int TYPE = 5; + public static final int LOCAL_PREFS_LENGTH = 4; @Override public void parseAttribute(final ByteBuf buffer, final PathAttributesBuilder builder) { @@ -33,6 +34,10 @@ public final class LocalPreferenceAttributeParser implements AttributeParser,Att if (lp == null) { return; } - byteAggregator.writeInt(lp.getPref().shortValue()); + + byteAggregator.writeByte(AttributeFlags.TRANSITIVE); + byteAggregator.writeByte(TYPE); + byteAggregator.writeByte(LOCAL_PREFS_LENGTH); + byteAggregator.writeInt(lp.getPref().intValue()); } } diff --git a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/MultiExitDiscriminatorAttributeParser.java b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/MultiExitDiscriminatorAttributeParser.java index 6b2e0f4ed7..201490a977 100644 --- a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/MultiExitDiscriminatorAttributeParser.java +++ b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/MultiExitDiscriminatorAttributeParser.java @@ -8,7 +8,7 @@ package org.opendaylight.protocol.bgp.parser.impl.message.update; import io.netty.buffer.ByteBuf; - +import org.opendaylight.protocol.bgp.parser.AttributeFlags; import org.opendaylight.protocol.bgp.parser.spi.AttributeParser; import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathAttributes; @@ -20,6 +20,7 @@ import org.opendaylight.yangtools.yang.binding.DataObject; public final class MultiExitDiscriminatorAttributeParser implements AttributeParser, AttributeSerializer { public static final int TYPE = 4; + public static final int ATTR_LENGTH = 4; @Override public void parseAttribute(final ByteBuf buffer, final PathAttributesBuilder builder) { @@ -33,6 +34,9 @@ public final class MultiExitDiscriminatorAttributeParser implements AttributePar if (multiExitDisc == null) { return; } + byteAggregator.writeByte(AttributeFlags.OPTIONAL); + byteAggregator.writeByte(TYPE); + byteAggregator.writeByte(ATTR_LENGTH); byteAggregator.writeInt(multiExitDisc.getMed().intValue()); } } diff --git a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/NextHopAttributeParser.java b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/NextHopAttributeParser.java index e6c713677a..506661eeff 100644 --- a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/NextHopAttributeParser.java +++ b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/NextHopAttributeParser.java @@ -8,9 +8,9 @@ package org.opendaylight.protocol.bgp.parser.impl.message.update; import com.google.common.base.Preconditions; - import io.netty.buffer.ByteBuf; - +import io.netty.buffer.Unpooled; +import org.opendaylight.protocol.bgp.parser.AttributeFlags; import org.opendaylight.protocol.bgp.parser.spi.AttributeParser; import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer; import org.opendaylight.protocol.concepts.Ipv4Util; @@ -43,17 +43,27 @@ public final class NextHopAttributeParser implements AttributeParser, AttributeS if (cNextHop == null) { return; } + ByteBuf nextHopBuffer = Unpooled.buffer(); if (cNextHop instanceof Ipv4NextHopCase) { + byteAggregator.writeByte(AttributeFlags.TRANSITIVE); + byteAggregator.writeByte(TYPE); Ipv4NextHopCase nextHop = (Ipv4NextHopCase) cNextHop; - byteAggregator.writeBytes(Ipv4Util.bytesForAddress(nextHop.getIpv4NextHop().getGlobal())); + nextHopBuffer.writeBytes(Ipv4Util.bytesForAddress(nextHop.getIpv4NextHop().getGlobal())); + byteAggregator.writeByte(nextHopBuffer.writerIndex()); + byteAggregator.writeBytes(nextHopBuffer); } else if (cNextHop instanceof Ipv6NextHopCase) { + byteAggregator.writeByte(AttributeFlags.TRANSITIVE); + byteAggregator.writeByte(TYPE); Ipv6NextHopCase nextHop = (Ipv6NextHopCase) cNextHop; if (nextHop.getIpv6NextHop().getGlobal() != null) { - byteAggregator.writeBytes(Ipv6Util.bytesForAddress(nextHop.getIpv6NextHop().getGlobal())); + nextHopBuffer.writeBytes(Ipv6Util.bytesForAddress(nextHop.getIpv6NextHop().getGlobal())); } if (nextHop.getIpv6NextHop().getLinkLocal() != null) { - byteAggregator.writeBytes(Ipv6Util.bytesForAddress(nextHop.getIpv6NextHop().getLinkLocal())); + nextHopBuffer.writeBytes(Ipv6Util.bytesForAddress(nextHop.getIpv6NextHop().getLinkLocal())); } + byteAggregator.writeByte(nextHopBuffer.writerIndex()); + byteAggregator.writeBytes(nextHopBuffer); } + } } diff --git a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/OriginAttributeParser.java b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/OriginAttributeParser.java index 7d45bd88ff..845b44aaf6 100644 --- a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/OriginAttributeParser.java +++ b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/OriginAttributeParser.java @@ -11,6 +11,7 @@ import com.google.common.primitives.UnsignedBytes; import io.netty.buffer.ByteBuf; +import org.opendaylight.protocol.bgp.parser.AttributeFlags; import org.opendaylight.protocol.bgp.parser.BGPDocumentedException; import org.opendaylight.protocol.bgp.parser.BGPError; import org.opendaylight.protocol.bgp.parser.spi.AttributeParser; @@ -25,6 +26,7 @@ import org.opendaylight.yangtools.yang.binding.DataObject; public final class OriginAttributeParser implements AttributeParser, AttributeSerializer { public static final int TYPE = 1; + public static final int ATTR_LENGTH = 1; @Override public void parseAttribute(final ByteBuf buffer, final PathAttributesBuilder builder) throws BGPDocumentedException { @@ -40,9 +42,11 @@ public final class OriginAttributeParser implements AttributeParser, AttributeSe public void serializeAttribute(DataObject attribute, ByteBuf byteAggregator) { PathAttributes pathAttributes = (PathAttributes) attribute; Origin origin = pathAttributes.getOrigin(); - if (origin == null) { - return; + if (origin != null) { + byteAggregator.writeByte(AttributeFlags.TRANSITIVE); + byteAggregator.writeByte(TYPE); + byteAggregator.writeByte(ATTR_LENGTH); + byteAggregator.writeByte(origin.getValue().getIntValue()); } - byteAggregator.writeByte(origin.getValue().getIntValue()); } } diff --git a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/OriginatorIdAttributeParser.java b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/OriginatorIdAttributeParser.java index 77499dc527..b6318a993d 100644 --- a/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/OriginatorIdAttributeParser.java +++ b/bgp/parser-impl/src/main/java/org/opendaylight/protocol/bgp/parser/impl/message/update/OriginatorIdAttributeParser.java @@ -10,28 +10,41 @@ package org.opendaylight.protocol.bgp.parser.impl.message.update; import com.google.common.base.Preconditions; import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.opendaylight.protocol.bgp.parser.AttributeFlags; import org.opendaylight.protocol.bgp.parser.spi.AttributeParser; import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer; import org.opendaylight.protocol.concepts.Ipv4Util; import org.opendaylight.protocol.util.ByteArray; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.PathAttributes; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.PathAttributesBuilder; import org.opendaylight.yangtools.yang.binding.DataObject; -public final class OriginatorIdAttributeParser implements AttributeParser, AttributeSerializer { - public static final int TYPE = 9; +public final class OriginatorIdAttributeParser implements AttributeParser,AttributeSerializer { - private static final int ORIGINATOR_LENGTH = 4; + public static final int TYPE = 9; + public static final int ATTR_LENGTH = 4; @Override public void parseAttribute(final ByteBuf buffer, final PathAttributesBuilder builder) { - Preconditions.checkArgument(buffer.readableBytes() == ORIGINATOR_LENGTH, "Length of byte array for ORIGINATOR_ID should be %s, but is %s", ORIGINATOR_LENGTH, buffer.readableBytes()); - builder.setOriginatorId(Ipv4Util.addressForBytes(ByteArray.readBytes(buffer, ORIGINATOR_LENGTH))); + Preconditions.checkArgument(buffer.readableBytes() == ATTR_LENGTH, "Length of byte array for ORIGINATOR_ID should be %s, but is %s", ATTR_LENGTH, buffer.readableBytes()); + builder.setOriginatorId(Ipv4Util.addressForBytes(ByteArray.readBytes(buffer, ATTR_LENGTH))); } @Override public void serializeAttribute(DataObject attribute, ByteBuf byteAggregator) { - //FIXME: implement this + PathAttributes pathAttributes = (PathAttributes) attribute; + if (pathAttributes.getOriginatorId() == null) { + return; + } + ByteBuf originatorIdBuf = Unpooled.buffer(); + originatorIdBuf.writeBytes(Ipv4Util.bytesForAddress(pathAttributes.getOriginatorId())); + byteAggregator.writeByte(AttributeFlags.OPTIONAL); + byteAggregator.writeByte(TYPE); + byteAggregator.writeByte(originatorIdBuf.writerIndex()); + byteAggregator.writeBytes(originatorIdBuf); + } } diff --git a/bgp/parser-impl/src/test/java/org/opendaylight/protocol/bgp/parser/impl/BGPUpdateAttributesSerializationTest.java b/bgp/parser-impl/src/test/java/org/opendaylight/protocol/bgp/parser/impl/BGPUpdateAttributesSerializationTest.java new file mode 100644 index 0000000000..ad271aaf04 --- /dev/null +++ b/bgp/parser-impl/src/test/java/org/opendaylight/protocol/bgp/parser/impl/BGPUpdateAttributesSerializationTest.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2014 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; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.protocol.bgp.parser.BGPDocumentedException; +import org.opendaylight.protocol.bgp.parser.impl.message.BGPUpdateMessageParser; +import org.opendaylight.protocol.bgp.parser.spi.MessageUtil; +import org.opendaylight.protocol.bgp.parser.spi.pojo.ServiceLoaderBGPExtensionProviderContext; +import org.opendaylight.protocol.util.ByteArray; +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.message.rev130919.PathAttributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.AsPath; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Communities; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.ExtendedCommunities; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.as.path.Segments; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.Nlri; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.update.WithdrawnRoutes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ExtendedCommunity; +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.Ipv6NextHopCase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BGPUpdateAttributesSerializationTest { + + private static final Logger LOG = LoggerFactory.getLogger(BGPUpdateAttributesSerializationTest.class); + static final List inputBytes = new ArrayList(); + private static BGPUpdateMessageParser updateParser = new BGPUpdateMessageParser(ServiceLoaderBGPExtensionProviderContext.getSingletonInstance().getAttributeRegistry()); + + private static int COUNTER = 9;//17; + private static int MAX_SIZE = 300; + + @Before + public void setupUpdateMessage() throws Exception { + + for (int i = 1; i <= COUNTER; i++) { + final String name = "/up" + i + ".bin"; + final InputStream is = BGPParserTest.class.getResourceAsStream(name); + if (is == null) { + throw new IOException("Failed to get resource " + name); + } + + final ByteArrayOutputStream bis = new ByteArrayOutputStream(); + final byte[] data = new byte[MAX_SIZE]; + int nRead = 0; + while ((nRead = is.read(data, 0, data.length)) != -1) { + bis.write(data, 0, nRead); + } + bis.flush(); + + inputBytes.add(bis.toByteArray()); + } + + + } + + private Update readUpdateMessageFromList(int listIndex) throws BGPDocumentedException { + return readUpdateMessageBytes(Unpooled.copiedBuffer(inputBytes.get(listIndex))); + } + + private Update readUpdateMessageBytes(ByteBuf messageBytes) throws BGPDocumentedException { + final byte[] body = ByteArray.cutBytes(ByteArray.getAllBytes(messageBytes), MessageUtil.COMMON_HEADER_LENGTH); + final int messageLength = ByteArray.bytesToInt(ByteArray.subByte(ByteArray.getAllBytes(messageBytes), MessageUtil.MARKER_LENGTH, + MessageUtil.LENGTH_FIELD_LENGTH)); + return BGPUpdateAttributesSerializationTest.updateParser.parseMessageBody(Unpooled.copiedBuffer(body), messageLength); + } + + private void assertEqualsPathAttributes(PathAttributes left, PathAttributes right) { + if (left.getCNextHop() != null) { + assertEqualsNextHop(left.getCNextHop(), right.getCNextHop()); + } + if (left.getAsPath() != null) { + assertEqualsAsPath(left.getAsPath(), right.getAsPath()); + } + if (left.getExtendedCommunities() != null) { + assertEqualsExtendedCommunities(left.getExtendedCommunities(), right.getExtendedCommunities()); + } + if (left.getCommunities() != null) { + assertEqualsCommunities(left.getCommunities(), right.getCommunities()); + } + if (left.getAggregator() != null) { + assertEquals(left.getAggregator().getAsNumber().getValue(), right.getAggregator().getAsNumber().getValue()); + assertEquals(left.getAggregator().getNetworkAddress().getValue(), right.getAggregator().getNetworkAddress().getValue()); + } + if (left.getAtomicAggregate() != null) { + assertEquals(left.getAtomicAggregate() != null, right.getAtomicAggregate() != null); + } + if (left.getClusterId() != null) { + assertEqualsClusterId(left.getClusterId(), right.getClusterId()); + } + if (left.getLocalPref() != null) { + assertEquals(left.getLocalPref().getPref(), right.getLocalPref().getPref()); + } + if (left.getMultiExitDisc() != null) { + assertEquals(left.getMultiExitDisc().getMed(), right.getMultiExitDisc().getMed()); + } + if (left.getOrigin() != null) { + assertEquals(left.getOrigin().getValue().getIntValue(), right.getOrigin().getValue().getIntValue()); + } + if (left.getOriginatorId() != null) { + assertEquals(left.getOriginatorId().getValue(), right.getOriginatorId().getValue()); + } + } + + private void assertEqualsClusterId(List left, List right) { + assertEquals(left.size(), right.size()); + for (ClusterIdentifier clusterIdentifier : left) { + right.remove(clusterIdentifier); + } + assertEquals(right.size(), 0); + } + + private void assertEqualsCommunities(List left, List right) { + assertEquals(left.size(), right.size()); + for (Communities communities : left) { + right.remove(communities); + } + assertEquals(right.size(), 0); + } + + private void assertEqualsExtendedCommunities(List left, List right) { + assertEquals(left.size(), right.size()); + for (ExtendedCommunity extendedCommunity : left) { + right.remove(extendedCommunity); + } + assertEquals(right.size(), 0); + } + + private void assertEqualsAsPath(AsPath left, AsPath right) { + for (Segments segments : left.getSegments()) { + right.getSegments().remove(segments); + } + assertTrue(right.getSegments().size() == 0); + } + + private void assertEqualsNextHop(CNextHop left, CNextHop right) { + if (left instanceof Ipv4NextHopCase) { + assertTrue(left instanceof Ipv4NextHopCase && right instanceof Ipv4NextHopCase); + Ipv4NextHopCase leftIpv4NextHopCase = (Ipv4NextHopCase) left; + Ipv4NextHopCase rightIpv4NextHopCase = (Ipv4NextHopCase) right; + assertEquals(leftIpv4NextHopCase.getIpv4NextHop().getGlobal().getValue(), rightIpv4NextHopCase.getIpv4NextHop().getGlobal().getValue()); + } + if (left instanceof Ipv6NextHopCase) { + assertTrue(left instanceof Ipv6NextHopCase && right instanceof Ipv6NextHopCase); + Ipv6NextHopCase leftIpv6NextHopCase = (Ipv6NextHopCase) left; + Ipv6NextHopCase rightIpv6NextHopCase = (Ipv6NextHopCase) right; + assertEquals(leftIpv6NextHopCase.getIpv6NextHop().getGlobal().getValue(), rightIpv6NextHopCase.getIpv6NextHop().getGlobal().getValue()); + assertEquals(leftIpv6NextHopCase.getIpv6NextHop().getLinkLocal().getValue(), rightIpv6NextHopCase.getIpv6NextHop().getLinkLocal().getValue()); + } + } + + private void assertEqualsNlri(Nlri left, Nlri right) { + assertEquals(left.getNlri().size(), right.getNlri().size()); + for (Ipv4Prefix ipv4Prefix : left.getNlri()) { + right.getNlri().remove(ipv4Prefix); + } + assertEquals(right.getNlri().size(), 0); + } + + private void assertWithdrawnRoutes(WithdrawnRoutes left, WithdrawnRoutes right) { + assertEquals(left.getWithdrawnRoutes().size(), right.getWithdrawnRoutes().size()); + for (Ipv4Prefix ipv4Prefix : left.getWithdrawnRoutes()) { + right.getWithdrawnRoutes().remove(ipv4Prefix); + } + assertEquals(right.getWithdrawnRoutes().size(), 0); + } + + @Test + public void testUpdateMessageSerialization() throws BGPDocumentedException { + for (int i = 0; i < COUNTER; i++) { + ByteBuf byteAggregator = Unpooled.buffer(); + Update originalMessage = readUpdateMessageFromList(i); + updateParser.serializeMessage(originalMessage, byteAggregator); + ByteBuf reconstructed = Unpooled.buffer(); + BGPUpdateAttributesSerializationTest.updateParser.serializeMessage(originalMessage, reconstructed); + Update serializedMessage = readUpdateMessageBytes(reconstructed); + if (originalMessage.getNlri() != null) { + assertEqualsNlri(originalMessage.getNlri(), serializedMessage.getNlri()); + } + if (originalMessage.getPathAttributes() != null) { + assertEqualsPathAttributes(originalMessage.getPathAttributes(), serializedMessage.getPathAttributes()); + } + if (originalMessage.getWithdrawnRoutes() != null) { + assertWithdrawnRoutes(originalMessage.getWithdrawnRoutes(), serializedMessage.getWithdrawnRoutes()); + } + } + } +} diff --git a/bgp/parser-spi/src/main/java/org/opendaylight/protocol/bgp/parser/spi/NlriSerializer.java b/bgp/parser-spi/src/main/java/org/opendaylight/protocol/bgp/parser/spi/NlriSerializer.java index 972e0e96e9..d604d694d7 100644 --- a/bgp/parser-spi/src/main/java/org/opendaylight/protocol/bgp/parser/spi/NlriSerializer.java +++ b/bgp/parser-spi/src/main/java/org/opendaylight/protocol/bgp/parser/spi/NlriSerializer.java @@ -7,8 +7,12 @@ */ package org.opendaylight.protocol.bgp.parser.spi; +import io.netty.buffer.ByteBuf; + import org.opendaylight.yangtools.yang.binding.DataObject; public interface NlriSerializer { - byte[] serializeAttribute(DataObject attribute); + + void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator); + } diff --git a/concepts/src/main/java/org/opendaylight/protocol/concepts/Ipv4Util.java b/concepts/src/main/java/org/opendaylight/protocol/concepts/Ipv4Util.java index 435fad881a..eeae25905b 100644 --- a/concepts/src/main/java/org/opendaylight/protocol/concepts/Ipv4Util.java +++ b/concepts/src/main/java/org/opendaylight/protocol/concepts/Ipv4Util.java @@ -72,6 +72,20 @@ public final class Ipv4Util { return a.getAddress(); } + /** + * Returns number of minimum bytes needed to cover all bits of prefix. + * + * @param prefix + * @return + */ + public static int getPrefixLengthBytes(final String prefix) { + int bits = Ipv4Util.getPrefixLength(prefix); + if (bits % 8 != 0) { + return (bits / 8) + 1; + } + return bits / 8; + } + /** * Converts Ipv4Prefix to byte array. * @@ -90,7 +104,7 @@ public final class Ipv4Util { /** * Creates an Ipv4Prefix object from given byte array. * - * @param bytes IPv4 address + * @param bytes IPv4 address * @param length prefix length * @return Ipv4Prefix object */ -- 2.36.6