Fix most bgp-parser-impl checkstyle
[bgpcep.git] / bgp / parser-impl / src / main / java / org / opendaylight / protocol / bgp / parser / impl / message / update / AsPathAttributeParser.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.protocol.bgp.parser.impl.message.update;
9
10 import static java.util.Objects.requireNonNull;
11
12 import io.netty.buffer.ByteBuf;
13 import io.netty.buffer.Unpooled;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.List;
17 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
18 import org.opendaylight.protocol.bgp.parser.BGPError;
19 import org.opendaylight.protocol.bgp.parser.BGPTreatAsWithdrawException;
20 import org.opendaylight.protocol.bgp.parser.impl.message.update.AsPathSegmentParser.SegmentType;
21 import org.opendaylight.protocol.bgp.parser.spi.AbstractAttributeParser;
22 import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer;
23 import org.opendaylight.protocol.bgp.parser.spi.AttributeUtil;
24 import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
25 import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandling;
26 import org.opendaylight.protocol.util.ReferenceCache;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.AttributesBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.AsPath;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.AsPathBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.as.path.Segments;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.as.path.SegmentsBuilder;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * Parser for AS_PATH attribute.
39  */
40 public final class AsPathAttributeParser extends AbstractAttributeParser implements AttributeSerializer {
41
42     public static final int TYPE = 2;
43
44     private final ReferenceCache refCache;
45     private static final Logger LOG = LoggerFactory.getLogger(AsPathAttributeParser.class);
46
47     private static final AsPath EMPTY = new AsPathBuilder().setSegments(Collections.emptyList()).build();
48
49     public AsPathAttributeParser(final ReferenceCache refCache) {
50         this.refCache = requireNonNull(refCache);
51     }
52
53     @Override
54     public void parseAttribute(final ByteBuf buffer, final AttributesBuilder builder,
55             final RevisedErrorHandling errorHandling, final PeerSpecificParserConstraint constraint)
56                     throws BGPDocumentedException, BGPTreatAsWithdrawException {
57         builder.setAsPath(parseAsPath(this.refCache, buffer, errorHandling));
58     }
59
60     @Override
61     public void serializeAttribute(final Attributes pathAttributes, final ByteBuf byteAggregator) {
62         final AsPath asPath = pathAttributes.getAsPath();
63         if (asPath == null) {
64             return;
65         }
66         final ByteBuf segmentsBuffer = Unpooled.buffer();
67         if (asPath.getSegments() != null) {
68             for (final Segments segments : asPath.getSegments()) {
69                 if (segments.getAsSequence() != null) {
70                     AsPathSegmentParser.serializeAsList(segments.getAsSequence(), SegmentType.AS_SEQUENCE,
71                         segmentsBuffer);
72                 } else if (segments.getAsSet() != null) {
73                     AsPathSegmentParser.serializeAsList(segments.getAsSet(), SegmentType.AS_SET, segmentsBuffer);
74                 } else {
75                     LOG.warn("Segment doesn't have AsSequence nor AsSet list.");
76                 }
77             }
78         }
79         AttributeUtil.formatAttribute(AttributeUtil.TRANSITIVE, TYPE, segmentsBuffer, byteAggregator);
80     }
81
82     /**
83      * Parses AS_PATH from bytes.
84      *
85      * @param refCache ReferenceCache shared reference of object
86      * @param buffer bytes to be parsed
87      * @return new ASPath object
88      * @throws BGPDocumentedException if there is no AS_SEQUENCE present (mandatory)
89      */
90     private static AsPath parseAsPath(final ReferenceCache refCache, final ByteBuf buffer,
91             final RevisedErrorHandling errorHandling) throws BGPDocumentedException, BGPTreatAsWithdrawException {
92         if (!buffer.isReadable()) {
93             return EMPTY;
94         }
95
96         final ArrayList<Segments> ases = new ArrayList<>();
97         boolean isSequence = false;
98         for (int readable = buffer.readableBytes(); readable != 0; readable = buffer.readableBytes()) {
99             if (readable < 2) {
100                 throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED,
101                     "Insufficient AS PATH segment header length %s", readable);
102             }
103
104             final int type = buffer.readUnsignedByte();
105             final SegmentType segmentType = AsPathSegmentParser.parseType(type);
106             if (segmentType == null) {
107                 throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED, "Unknown AS PATH segment type %s", type);
108             }
109             final int count = buffer.readUnsignedByte();
110             if (count == 0 && errorHandling != RevisedErrorHandling.NONE) {
111                 throw new BGPTreatAsWithdrawException(BGPError.AS_PATH_MALFORMED, "Empty AS_PATH segment");
112             }
113
114             // We read 2 bytes of header at this point
115             readable -= 2;
116             final int segmentLength = count * AsPathSegmentParser.AS_NUMBER_LENGTH;
117             if (segmentLength > readable) {
118                 throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED,
119                     "Calculated segment length %s would overflow available buffer %s", segmentLength, readable);
120             }
121
122             final List<AsNumber> asList = AsPathSegmentParser.parseAsSegment(refCache, count,
123                 buffer.readSlice(segmentLength));
124             if (segmentType == SegmentType.AS_SEQUENCE) {
125                 ases.add(new SegmentsBuilder().setAsSequence(asList).build());
126                 isSequence = true;
127             } else {
128                 ases.add(new SegmentsBuilder().setAsSet(asList).build());
129             }
130         }
131
132         if (!isSequence) {
133             throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED,
134                 "AS_SEQUENCE must be present in AS_PATH attribute.");
135         }
136
137         ases.trimToSize();
138         return new AsPathBuilder().setSegments(ases).build();
139     }
140 }