2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.protocol.bgp.parser.impl.message.update;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.collect.ImmutableList;
13 import io.netty.buffer.ByteBuf;
14 import io.netty.buffer.Unpooled;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
19 import org.opendaylight.protocol.bgp.parser.BGPError;
20 import org.opendaylight.protocol.bgp.parser.BGPTreatAsWithdrawException;
21 import org.opendaylight.protocol.bgp.parser.impl.message.update.AsPathSegmentParser.SegmentType;
22 import org.opendaylight.protocol.bgp.parser.spi.AbstractAttributeParser;
23 import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer;
24 import org.opendaylight.protocol.bgp.parser.spi.AttributeUtil;
25 import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
26 import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandling;
27 import org.opendaylight.protocol.util.ReferenceCache;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.Attributes;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.AttributesBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.attributes.AsPath;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.attributes.AsPathBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.attributes.as.path.Segments;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev200120.path.attributes.attributes.as.path.SegmentsBuilder;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
39 * Parser for AS_PATH attribute.
41 public final class AsPathAttributeParser extends AbstractAttributeParser implements AttributeSerializer {
43 public static final int TYPE = 2;
45 private final ReferenceCache refCache;
46 private static final Logger LOG = LoggerFactory.getLogger(AsPathAttributeParser.class);
48 private static final AsPath EMPTY = new AsPathBuilder().setSegments(Collections.emptyList()).build();
50 public AsPathAttributeParser(final ReferenceCache refCache) {
51 this.refCache = requireNonNull(refCache);
55 public void parseAttribute(final ByteBuf buffer, final AttributesBuilder builder,
56 final RevisedErrorHandling errorHandling, final PeerSpecificParserConstraint constraint)
57 throws BGPDocumentedException, BGPTreatAsWithdrawException {
58 builder.setAsPath(parseAsPath(this.refCache, buffer, errorHandling));
62 public void serializeAttribute(final Attributes pathAttributes, final ByteBuf byteAggregator) {
63 final AsPath asPath = pathAttributes.getAsPath();
67 final ByteBuf segmentsBuffer = Unpooled.buffer();
68 if (asPath.getSegments() != null) {
69 for (final Segments segments : asPath.getSegments()) {
70 if (segments.getAsSequence() != null) {
71 AsPathSegmentParser.serializeAsList(segments.getAsSequence(), SegmentType.AS_SEQUENCE,
73 } else if (segments.getAsSet() != null) {
74 AsPathSegmentParser.serializeAsList(segments.getAsSet(), SegmentType.AS_SET, segmentsBuffer);
76 LOG.warn("Segment doesn't have AsSequence nor AsSet list.");
80 AttributeUtil.formatAttribute(AttributeUtil.TRANSITIVE, TYPE, segmentsBuffer, byteAggregator);
84 * Parses AS_PATH from bytes.
86 * @param refCache ReferenceCache shared reference of object
87 * @param buffer bytes to be parsed
88 * @return new ASPath object
89 * @throws BGPDocumentedException if there is no AS_SEQUENCE present (mandatory)
91 private static AsPath parseAsPath(final ReferenceCache refCache, final ByteBuf buffer,
92 final RevisedErrorHandling errorHandling) throws BGPDocumentedException, BGPTreatAsWithdrawException {
93 if (!buffer.isReadable()) {
97 final List<Segments> ases = new ArrayList<>();
98 boolean isSequence = false;
99 for (int readable = buffer.readableBytes(); readable != 0; readable = buffer.readableBytes()) {
101 throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED,
102 "Insufficient AS PATH segment header length %s", readable);
105 final int type = buffer.readUnsignedByte();
106 final SegmentType segmentType = AsPathSegmentParser.parseType(type);
107 if (segmentType == null) {
108 throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED, "Unknown AS PATH segment type %s", type);
110 final int count = buffer.readUnsignedByte();
111 if (count == 0 && errorHandling != RevisedErrorHandling.NONE) {
112 throw new BGPTreatAsWithdrawException(BGPError.AS_PATH_MALFORMED, "Empty AS_PATH segment");
115 // We read 2 bytes of header at this point
117 final int segmentLength = count * AsPathSegmentParser.AS_NUMBER_LENGTH;
118 if (segmentLength > readable) {
119 throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED,
120 "Calculated segment length %s would overflow available buffer %s", segmentLength, readable);
123 final List<AsNumber> asList = AsPathSegmentParser.parseAsSegment(refCache, count,
124 buffer.readSlice(segmentLength));
125 if (segmentType == SegmentType.AS_SEQUENCE) {
126 ases.add(new SegmentsBuilder().setAsSequence(asList).build());
129 ases.add(new SegmentsBuilder().setAsSet(asList).build());
134 throw errorHandling.reportError(BGPError.AS_PATH_MALFORMED,
135 "AS_SEQUENCE must be present in AS_PATH attribute.");
138 return new AsPathBuilder().setSegments(ImmutableList.copyOf(ases)).build();