Bump upstream versions
[bgpcep.git] / bgp / parser-impl / src / main / java / org / opendaylight / protocol / bgp / parser / impl / message / update / AsPathAttributeParser.java
index 9b122af5d262ba5fc06c69dbf619a3c20a5d1388..602caa35ff229a576206ec2f76972657b35ec463 100644 (file)
@@ -9,72 +9,116 @@ package org.opendaylight.protocol.bgp.parser.impl.message.update;
 
 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.rev130715.AsNumber;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.AttributesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.AsPath;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.AsPathBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.as.path.Segments;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.as.path.SegmentsBuilder;
+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.emptyList()).build();
+    private static final AsPath EMPTY = new AsPathBuilder().setSegments(List.of()).build();
 
     public AsPathAttributeParser(final ReferenceCache 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 refCache ReferenceCache shared reference of object
      * @param buffer bytes to be parsed
-     * @param constraint
      * @return new ASPath object
      * @throws BGPDocumentedException if there is no AS_SEQUENCE present (mandatory)
      */
     private static AsPath parseAsPath(final ReferenceCache refCache, final ByteBuf buffer,
-            final PeerSpecificParserConstraint constraint) throws BGPDocumentedException, BGPParsingException {
+            final RevisedErrorHandling errorHandling) throws BGPDocumentedException, BGPTreatAsWithdrawException {
         if (!buffer.isReadable()) {
             return EMPTY;
         }
-        final ArrayList<Segments> ases = new ArrayList<>();
+
+        final List<Segments> ases = new ArrayList<>();
         boolean isSequence = false;
-        while (buffer.isReadable()) {
+        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) {
-                // FIXME: BGPCEP-359: treat-as-withdraw
-                throw new BGPParsingException("AS Path segment type unknown : " + type);
+                throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED, "Unknown AS PATH segment type %s", type);
             }
-
-            // FIXME: BGPCEP-359: treat-as-withdraw if no data is available
             final int count = buffer.readUnsignedByte();
-            // FIXME: BGPCEP-359: treat-as-withdraw if count == 0
+            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;
-            // FIXME: BGPCEP-359: treat-as-withdraw if there is a buffer overrun
+            if (segmentLength > readable) {
+                throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED,
+                    "Calculated segment length %s would overflow available buffer %s", segmentLength, readable);
+            }
 
             final List<AsNumber> asList = AsPathSegmentParser.parseAsSegment(refCache, count,
                 buffer.readSlice(segmentLength));
@@ -82,42 +126,15 @@ public final class AsPathAttributeParser implements AttributeParser, AttributeSe
                 ases.add(new SegmentsBuilder().setAsSequence(asList).build());
                 isSequence = true;
             } else {
-                ases.add(new SegmentsBuilder().setAsSet(asList).build());
+                ases.add(new SegmentsBuilder().setAsSet(ImmutableSet.copyOf(asList)).build());
             }
         }
+
         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.");
         }
 
-        ases.trimToSize();
-        return new AsPathBuilder().setSegments(ases).build();
-    }
-
-    @Override
-    public void parseAttribute(final ByteBuf buffer, final AttributesBuilder builder,
-            final PeerSpecificParserConstraint constraint) throws BGPDocumentedException, BGPParsingException {
-        builder.setAsPath(parseAsPath(this.refCache, buffer, constraint));
-    }
-
-    @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);
+        return new AsPathBuilder().setSegments(ImmutableList.copyOf(ases)).build();
     }
 }