Bump upstream versions
[bgpcep.git] / bgp / parser-impl / src / main / java / org / opendaylight / protocol / bgp / parser / impl / message / update / AsPathAttributeParser.java
index b4ae4ded5c8af4f9424fd60008422ccbd86ffab5..602caa35ff229a576206ec2f76972657b35ec463 100644 (file)
  */
 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();
     }
 }