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 java.util.List;
12 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
13 import org.opendaylight.protocol.bgp.parser.BGPError;
14 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
15 import org.opendaylight.protocol.bgp.parser.impl.message.update.AsPathSegmentParser.SegmentType;
16 import org.opendaylight.protocol.bgp.parser.spi.AttributeRegistry;
17 import org.opendaylight.protocol.concepts.IPv4;
18 import org.opendaylight.protocol.concepts.Ipv4Util;
19 import org.opendaylight.protocol.util.ByteArray;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.PathAttributes1;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.PathAttributes1Builder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.Aggregator;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.AggregatorBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.AsPath;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.AsPathBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.Communities;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.ExtendedCommunities;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.LocalPref;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.LocalPrefBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.MultiExitDisc;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.MultiExitDiscBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.Origin;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.OriginBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.as.path.Segments;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.path.attributes.as.path.SegmentsBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.update.PathAttributes;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.update.PathAttributesBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.PathAttributes2;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.PathAttributes2Builder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.BgpOrigin;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.ClusterIdentifier;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.CAListBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.CASetBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.as.path.segment.c.segment.c.a.list.AsSequence;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.CNextHop;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.CIpv4NextHopBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.next.hop.c.next.hop.c.ipv4.next.hop.Ipv4NextHopBuilder;
51 import com.google.common.collect.Lists;
52 import com.google.common.primitives.UnsignedBytes;
56 * Parser for different Path Attributes. Each attributes has its own method for parsing.
59 public class PathAttributeParser {
61 private static final int FLAGS_LENGTH = 1;
63 private static final int TYPE_LENGTH = 1;
65 private static AttributeRegistry reg = SimpleAttributeRegistry.INSTANCE;
67 private PathAttributeParser() {
72 * Parse path attribute header (the same for all path attributes) and set type, length and value fields.
74 * @param bytes byte array to be parsed.
75 * @return generic Path Attribute
76 * @throws BGPParsingException
77 * @throws BGPDocumentedException
79 public static PathAttributes parseAttribute(final byte[] bytes) throws BGPDocumentedException, BGPParsingException {
80 if (bytes == null || bytes.length == 0) {
81 throw new BGPParsingException("Insufficient length of byte array: " + bytes.length);
84 final PathAttributesBuilder builder = new PathAttributesBuilder();
85 while (byteOffset < bytes.length) {
86 final boolean[] bits = ByteArray.parseBits(bytes[0]);
87 final boolean optional = bits[0];
88 final int attrLength = (bits[3]) ? ByteArray.bytesToInt(ByteArray.subByte(bytes, 2, 2)) : UnsignedBytes.toInt(bytes[2]);
89 final int hdrLength = FLAGS_LENGTH + TYPE_LENGTH + ((bits[3]) ? 2 : 1);
91 final byte[] attrBody = ByteArray.subByte(bytes, hdrLength, attrLength);
93 boolean found = reg.parseAttribute(UnsignedBytes.toInt(bytes[1]), attrBody, builder);
94 if (!optional && !found) {
95 throw new BGPDocumentedException("Well known attribute not recognized.", BGPError.WELL_KNOWN_ATTR_NOT_RECOGNIZED);
98 byteOffset += hdrLength + attrLength;
100 return builder.build();
104 * Parses ORIGIN from bytes.
106 * @param bytes byte array to be parsed
107 * @return {@link Origin} BGP origin value
108 * @throws BGPDocumentedException
110 static Origin parseOrigin(final byte[] bytes) throws BGPDocumentedException {
111 final BgpOrigin borigin = BgpOrigin.forValue(UnsignedBytes.toInt(bytes[0]));
112 if (borigin == null) {
113 throw new BGPDocumentedException("Unknown Origin type.", BGPError.ORIGIN_ATTR_NOT_VALID, new byte[] { (byte) 0x01, (byte) 0x01,
116 return new OriginBuilder().setValue(borigin).build();
120 * Parses AS_PATH from bytes.
122 * @param bytes byte array to be parsed
123 * @return new ASPath object
124 * @throws BGPDocumentedException if there is no AS_SEQUENCE present (mandatory)
125 * @throws BGPParsingException
127 static AsPath parseAsPath(final byte[] bytes) throws BGPDocumentedException, BGPParsingException {
129 final List<Segments> ases = Lists.newArrayList();
130 boolean isSequence = false;
131 while (byteOffset < bytes.length) {
132 final int type = UnsignedBytes.toInt(bytes[byteOffset]);
133 final SegmentType segmentType = AsPathSegmentParser.parseType(type);
134 if (segmentType == null) {
135 throw new BGPParsingException("AS Path segment type unknown : " + type);
137 byteOffset += AsPathSegmentParser.TYPE_LENGTH;
139 final int count = UnsignedBytes.toInt(bytes[byteOffset]);
140 byteOffset += AsPathSegmentParser.LENGTH_SIZE;
142 if (segmentType == SegmentType.AS_SEQUENCE) {
143 final List<AsSequence> numbers = AsPathSegmentParser.parseAsSequence(count,
144 ByteArray.subByte(bytes, byteOffset, count * AsPathSegmentParser.AS_NUMBER_LENGTH));
145 ases.add(new SegmentsBuilder().setCSegment(new CAListBuilder().setAsSequence(numbers).build()).build());
148 final List<AsNumber> list = AsPathSegmentParser.parseAsSet(count,
149 ByteArray.subByte(bytes, byteOffset, count * AsPathSegmentParser.AS_NUMBER_LENGTH));
150 ases.add(new SegmentsBuilder().setCSegment(new CASetBuilder().setAsSet(list).build()).build());
153 byteOffset += count * AsPathSegmentParser.AS_NUMBER_LENGTH;
156 if (!isSequence && bytes.length != 0) {
157 throw new BGPDocumentedException("AS_SEQUENCE must be present in AS_PATH attribute.", BGPError.AS_PATH_MALFORMED);
159 return new AsPathBuilder().setSegments(ases).build();
163 * Parse NEXT_HOP from bytes
165 * @param bytes byte array to be parsed
166 * @return new NextHop object, it's always IPv4 (basic BGP-4)
168 static CNextHop parseNextHop(final byte[] bytes) {
169 return new CIpv4NextHopBuilder().setIpv4NextHop(new Ipv4NextHopBuilder().setGlobal(Ipv4Util.addressForBytes(bytes)).build()).build();
173 * Parse MULTI_EXIT_DISC (integer) from bytes
175 * @param bytes byte array to be parsed
176 * @return integer representing MULTI_EXIT_DISC path attribute
178 static MultiExitDisc parseMultiExitDisc(final byte[] bytes) {
179 return new MultiExitDiscBuilder().setMed(ByteArray.bytesToLong(bytes)).build();
183 * Parse LOCAL_PREF (integer) from bytes
185 * @param bytes byte array to be parsed
186 * @return integer representing LOCAL_PREF path attribute
188 static LocalPref parseLocalPref(final byte[] bytes) {
189 return new LocalPrefBuilder().setPref(ByteArray.bytesToLong(bytes)).build();
193 * Parse AGGREGATOR from bytes
195 * @param bytes byte array to be parsed
196 * @return {@link Aggregator} BGP Aggregator
198 static Aggregator parseAggregator(final byte[] bytes) {
199 final AsNumber asNumber = new AsNumber(ByteArray.bytesToLong(ByteArray.subByte(bytes, 0, AsPathSegmentParser.AS_NUMBER_LENGTH)));
200 final Ipv4Address address = new Ipv4Address(IPv4.FAMILY.addressForBytes(
201 ByteArray.subByte(bytes, AsPathSegmentParser.AS_NUMBER_LENGTH, 4)).toString());
202 return new AggregatorBuilder().setAsNumber(asNumber).setNetworkAddress(address).build();
206 * Parse MP_REACH_NLRI from bytes
208 * @param bytes byte array to be parsed
209 * @return new specific MPReach object with reachable flag set to true
210 * @throws BGPDocumentedException
212 static void parseMPReach(final PathAttributesBuilder b, final byte[] bytes) throws BGPDocumentedException {
215 final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.PathAttributes1 a = new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.PathAttributes1Builder().setMpReachNlri(
216 MPReachParser.parseMPReach(bytes)).build();
219 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130918.PathAttributes1.class, a);
220 } catch (final BGPParsingException e) {
221 throw new BGPDocumentedException("Could not parse MP_REACH_NLRI: " + e.getMessage(), BGPError.OPT_ATTR_ERROR);
226 * Parse MP_UNREACH_NLRI from bytes
228 * @param bytes byte array to be parsed
229 * @return new specific MPReach object with reachable flag set to false
230 * @throws BGPDocumentedException
232 static void parseMPUnreach(final PathAttributesBuilder b, final byte[] bytes) throws BGPDocumentedException {
234 final PathAttributes2 a = new PathAttributes2Builder().setMpUnreachNlri(MPReachParser.parseMPUnreach(bytes)).build();
236 b.addAugmentation(PathAttributes2.class, a);
237 } catch (final BGPParsingException e) {
238 throw new BGPDocumentedException("Could not parse MP_UNREACH_NLRI: " + e.getMessage(), BGPError.OPT_ATTR_ERROR);
243 * Parse set of EXTENDED_COMMUNITIES from bytes
245 * @param bytes byte array to be parsed
246 * @return new specific Extended Community object
247 * @throws BGPDocumentedException l
249 static List<ExtendedCommunities> parseExtendedCommunities(final byte[] bytes) throws BGPDocumentedException {
250 final List<ExtendedCommunities> set = Lists.newArrayList();
252 while (i < bytes.length) {
253 set.add((ExtendedCommunities) CommunitiesParser.parseExtendedCommunity(ByteArray.subByte(bytes, i,
254 CommunitiesParser.EXTENDED_COMMUNITY_LENGTH)));
255 i += CommunitiesParser.EXTENDED_COMMUNITY_LENGTH;
261 * Parse set of COMMUNITIES from bytes
263 * @param bytes byte array to be parsed
264 * @return new specific Community object
265 * @throws BGPDocumentedException
267 static List<Communities> parseCommunities(final byte[] bytes) throws BGPDocumentedException {
268 final List<Communities> set = Lists.newArrayList();
270 while (i < bytes.length) {
271 set.add((Communities) CommunitiesParser.parseCommunity(ByteArray.subByte(bytes, i, CommunitiesParser.COMMUNITY_LENGTH)));
272 i += CommunitiesParser.COMMUNITY_LENGTH;
278 * Parse list of Cluster Identifiers.
280 * @param bytes byte array to be parsed
281 * @return new List of Cluster Identifiers
283 static List<ClusterIdentifier> parseClusterList(final byte[] bytes) {
284 final List<ClusterIdentifier> list = Lists.newArrayList();
286 while (i < bytes.length) {
287 list.add(new ClusterIdentifier(ByteArray.subByte(bytes, i, 4)));
294 * Parses ORIGINATOR_ID, which is BGP Identifier, which is IP address of the speaker.
296 * @param bytes byte array to be parsed
297 * @return IP address of the speaker
299 static byte[] parseOriginatorId(final byte[] bytes) {
300 if (bytes.length != 4) {
301 throw new IllegalArgumentException("Length of byte array for ORIGINATOR_ID should be 4, but is " + bytes.length);
307 * Parse LINK_STATE from bytes
309 * @param bytes byte array to be parsed
310 * @return Map, where the key is the type of a tlv and the value is the value of the tlv
311 * @throws BGPParsingException
313 static void parseLinkState(final PathAttributesBuilder builder, final byte[] bytes) throws BGPParsingException {
314 final PathAttributes1 a = new PathAttributes1Builder().setLinkstatePathAttribute(LinkStateParser.parseLinkState(bytes)).build();
315 builder.addAugmentation(PathAttributes1.class, a);