*/
package org.opendaylight.protocol.bgp.parser.impl.message.update;
-import com.google.common.base.Preconditions;
-import com.google.common.primitives.UnsignedBytes;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.util.ArrayList;
-import java.util.Collections;
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.BGPTreatAsWithdrawException;
import org.opendaylight.protocol.bgp.parser.impl.message.update.AsPathSegmentParser.SegmentType;
-import org.opendaylight.protocol.bgp.parser.spi.AttributeParser;
+import org.opendaylight.protocol.bgp.parser.spi.AbstractAttributeParser;
import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer;
import org.opendaylight.protocol.bgp.parser.spi.AttributeUtil;
+import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
+import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandling;
import org.opendaylight.protocol.util.ReferenceCache;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
-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.AsPath;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.AsPathBuilder;
-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.path.attributes.as.path.SegmentsBuilder;
-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.as.path.segment.c.segment.AListCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.AListCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.ASetCase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.ASetCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.AListBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.list._case.a.list.AsSequence;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.a.set._case.ASetBuilder;
-import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.AttributesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.attributes.AsPath;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.attributes.AsPathBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.attributes.as.path.Segments;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.attributes.as.path.SegmentsBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
-public final class AsPathAttributeParser implements AttributeParser, AttributeSerializer {
+/**
+ * Parser for AS_PATH attribute.
+ */
+public final class AsPathAttributeParser extends AbstractAttributeParser implements AttributeSerializer {
public static final int TYPE = 2;
private final ReferenceCache refCache;
private static final Logger LOG = LoggerFactory.getLogger(AsPathAttributeParser.class);
- private static final AsPath EMPTY = new AsPathBuilder().setSegments(Collections.<Segments> emptyList()).build();
+ private static final AsPath EMPTY = new AsPathBuilder().setSegments(List.of()).build();
public AsPathAttributeParser(final ReferenceCache refCache) {
- this.refCache = Preconditions.checkNotNull(refCache);
+ this.refCache = requireNonNull(refCache);
+ }
+
+ @Override
+ public void parseAttribute(final ByteBuf buffer, final AttributesBuilder builder,
+ final RevisedErrorHandling errorHandling, final PeerSpecificParserConstraint constraint)
+ throws BGPDocumentedException, BGPTreatAsWithdrawException {
+ builder.setAsPath(parseAsPath(refCache, buffer, errorHandling));
+ }
+
+ @Override
+ public void serializeAttribute(final Attributes pathAttributes, final ByteBuf byteAggregator) {
+ final AsPath asPath = pathAttributes.getAsPath();
+ if (asPath == null) {
+ return;
+ }
+ final ByteBuf segmentsBuffer = Unpooled.buffer();
+ if (asPath.getSegments() != null) {
+ for (final Segments segments : asPath.getSegments()) {
+ if (segments.getAsSequence() != null) {
+ AsPathSegmentParser.serializeAsList(segments.getAsSequence(), SegmentType.AS_SEQUENCE,
+ segmentsBuffer);
+ } else if (segments.getAsSet() != null) {
+ AsPathSegmentParser.serializeAsList(segments.getAsSet(), SegmentType.AS_SET, segmentsBuffer);
+ } else {
+ LOG.warn("Segment doesn't have AsSequence nor AsSet list.");
+ }
+ }
+ }
+ AttributeUtil.formatAttribute(AttributeUtil.TRANSITIVE, TYPE, segmentsBuffer, byteAggregator);
}
/**
* Parses AS_PATH from bytes.
*
- * @param buffer bytes to be parsed @return new ASPath object
+ * @param refCache ReferenceCache shared reference of object
+ * @param buffer bytes to be parsed
+ * @return new ASPath object
* @throws BGPDocumentedException if there is no AS_SEQUENCE present (mandatory)
- * @throws BGPParsingException
*/
- private static AsPath parseAsPath(final ReferenceCache refCache, final ByteBuf buffer) throws BGPDocumentedException, BGPParsingException {
+ private static AsPath parseAsPath(final ReferenceCache refCache, final ByteBuf buffer,
+ final RevisedErrorHandling errorHandling) throws BGPDocumentedException, BGPTreatAsWithdrawException {
if (!buffer.isReadable()) {
return EMPTY;
}
+
final List<Segments> ases = new ArrayList<>();
boolean isSequence = false;
- while (buffer.isReadable()) {
- final int type = UnsignedBytes.toInt(buffer.readByte());
+ for (int readable = buffer.readableBytes(); readable != 0; readable = buffer.readableBytes()) {
+ if (readable < 2) {
+ throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED,
+ "Insufficient AS PATH segment header length %s", readable);
+ }
+
+ final int type = buffer.readUnsignedByte();
final SegmentType segmentType = AsPathSegmentParser.parseType(type);
if (segmentType == null) {
- throw new BGPParsingException("AS Path segment type unknown : " + type);
+ throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED, "Unknown AS PATH segment type %s", type);
+ }
+ final int count = buffer.readUnsignedByte();
+ if (count == 0 && errorHandling != RevisedErrorHandling.NONE) {
+ throw new BGPTreatAsWithdrawException(BGPError.AS_PATH_MALFORMED, "Empty AS_PATH segment");
+ }
+
+ // We read 2 bytes of header at this point
+ readable -= 2;
+ final int segmentLength = count * AsPathSegmentParser.AS_NUMBER_LENGTH;
+ if (segmentLength > readable) {
+ throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED,
+ "Calculated segment length %s would overflow available buffer %s", segmentLength, readable);
}
- final int count = UnsignedBytes.toInt(buffer.readByte());
+ final List<AsNumber> asList = AsPathSegmentParser.parseAsSegment(refCache, count,
+ buffer.readSlice(segmentLength));
if (segmentType == SegmentType.AS_SEQUENCE) {
- final List<AsSequence> numbers = AsPathSegmentParser.parseAsSequence(refCache, count, buffer.slice(buffer.readerIndex(),
- count * AsPathSegmentParser.AS_NUMBER_LENGTH));
- ases.add(new SegmentsBuilder().setCSegment(
- new AListCaseBuilder().setAList(new AListBuilder().setAsSequence(numbers).build()).build()).build());
+ ases.add(new SegmentsBuilder().setAsSequence(asList).build());
isSequence = true;
} else {
- final List<AsNumber> list = AsPathSegmentParser.parseAsSet(refCache, count, buffer.slice(buffer.readerIndex(), count
- * AsPathSegmentParser.AS_NUMBER_LENGTH));
- ases.add(new SegmentsBuilder().setCSegment(new ASetCaseBuilder().setASet(new ASetBuilder().setAsSet(list).build()).build()).build());
-
+ ases.add(new SegmentsBuilder().setAsSet(ImmutableSet.copyOf(asList)).build());
}
- buffer.skipBytes(count * AsPathSegmentParser.AS_NUMBER_LENGTH);
}
+
if (!isSequence) {
- throw new BGPDocumentedException("AS_SEQUENCE must be present in AS_PATH attribute.", BGPError.AS_PATH_MALFORMED);
+ throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED,
+ "AS_SEQUENCE must be present in AS_PATH attribute.");
}
- return new AsPathBuilder().setSegments(ases).build();
- }
-
- @Override
- public void parseAttribute(final ByteBuf buffer, final PathAttributesBuilder builder) throws BGPDocumentedException, BGPParsingException {
- builder.setAsPath(parseAsPath(this.refCache, buffer));
- }
- @Override
- public void serializeAttribute(final DataObject attribute, final ByteBuf byteAggregator) {
- Preconditions.checkArgument(attribute instanceof PathAttributes, "Attribute parameter is not a PathAttribute object.");
- final PathAttributes pathAttributes = (PathAttributes) attribute;
- final AsPath asPath = pathAttributes.getAsPath();
- if (asPath == null) {
- return;
- }
- final ByteBuf segmentsBuffer = Unpooled.buffer();
- if (asPath.getSegments() != null) {
- for (final Segments segments : asPath.getSegments()) {
- if (segments.getCSegment() instanceof AListCase) {
- final AListCase listCase = (AListCase) segments.getCSegment();
- AsPathSegmentParser.serializeAsSequence(listCase, segmentsBuffer);
- } else if (segments.getCSegment() instanceof ASetCase) {
- final ASetCase set = (ASetCase) segments.getCSegment();
- AsPathSegmentParser.serializeAsSet(set, segmentsBuffer);
- } else {
- LOG.warn("Segment class is neither AListCase nor ASetCase.");
- }
- }
- }
- AttributeUtil.formatAttribute(AttributeUtil.TRANSITIVE, TYPE, segmentsBuffer, byteAggregator);
+ return new AsPathBuilder().setSegments(ImmutableList.copyOf(ases)).build();
}
}