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
9 package org.opendaylight.protocol.bgp.parser.impl.message;
11 import java.util.Arrays;
12 import java.util.Collections;
13 import java.util.List;
16 import org.opendaylight.protocol.bgp.concepts.BGPAddressFamily;
17 import org.opendaylight.protocol.bgp.concepts.BGPSubsequentAddressFamily;
18 import org.opendaylight.protocol.bgp.concepts.BGPTableType;
19 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
20 import org.opendaylight.protocol.bgp.parser.BGPError;
21 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
22 import org.opendaylight.protocol.bgp.parser.BGPUpdateEvent;
23 import org.opendaylight.protocol.bgp.parser.BGPUpdateSynchronized;
24 import org.opendaylight.protocol.bgp.parser.impl.BGPMessageFactory;
25 import org.opendaylight.protocol.bgp.parser.impl.BGPUpdateEventBuilder;
26 import org.opendaylight.protocol.bgp.parser.impl.IPv6MP;
27 import org.opendaylight.protocol.bgp.parser.impl.PathAttribute;
28 import org.opendaylight.protocol.bgp.parser.impl.PathAttribute.TypeCode;
29 import org.opendaylight.protocol.bgp.parser.impl.message.update.PathAttributeParser;
30 import org.opendaylight.protocol.concepts.IPv4;
31 import org.opendaylight.protocol.concepts.IPv4Address;
32 import org.opendaylight.protocol.concepts.Prefix;
33 import org.opendaylight.protocol.util.ByteArray;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
37 import com.google.common.collect.Lists;
40 * LENGTH fields, that denote the length of the fields with variable length, have fixed SIZE.
42 * @see <a href="http://tools.ietf.org/html/rfc4271#section-4.3">BGP-4 Update Message Format</a>
45 public class BGPUpdateMessageParser {
47 private static Logger logger = LoggerFactory.getLogger(BGPUpdateMessageParser.class);
50 * Size of the withdrawn_routes_length field, in bytes.
52 public static final int WITHDRAWN_ROUTES_LENGTH_SIZE = 2;
55 * Size of the total_path_attr_length field, in bytes.
57 public static final int TOTAL_PATH_ATTR_LENGTH_SIZE = 2;
59 // Constructors -------------------------------------------------------
61 public BGPUpdateMessageParser() {
65 // Getters & setters --------------------------------------------------
67 public static BGPUpdateEvent parse(final byte[] bytes, final int msgLength) throws BGPDocumentedException {
68 if (bytes == null || bytes.length == 0)
69 throw new IllegalArgumentException("Byte array cannot be null or empty.");
70 logger.trace("Started parsing of update message: {}", Arrays.toString(bytes));
74 final int withdrawnRoutesLength = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, WITHDRAWN_ROUTES_LENGTH_SIZE));
75 byteOffset += WITHDRAWN_ROUTES_LENGTH_SIZE;
77 final BGPUpdateEventBuilder eventBuilder = new BGPUpdateEventBuilder();
78 eventBuilder.setWithdrawnRoutesLength(withdrawnRoutesLength);
80 Set<Prefix<IPv4Address>> withdrawnRoutes;
81 if (withdrawnRoutesLength > 0) {
82 withdrawnRoutes = IPv4.FAMILY.prefixListForBytes(ByteArray.subByte(bytes, byteOffset, withdrawnRoutesLength));
83 byteOffset += withdrawnRoutesLength;
85 withdrawnRoutes = Collections.emptySet();
87 eventBuilder.setWithdrawnRoutes(withdrawnRoutes);
89 final int totalPathAttrLength = ByteArray.bytesToInt(ByteArray.subByte(bytes, byteOffset, TOTAL_PATH_ATTR_LENGTH_SIZE));
90 byteOffset += TOTAL_PATH_ATTR_LENGTH_SIZE;
91 eventBuilder.setTotalPathAttrLength(totalPathAttrLength);
93 if (withdrawnRoutesLength + totalPathAttrLength + BGPMessageFactory.COMMON_HEADER_LENGTH > msgLength)
94 throw new BGPDocumentedException("Message length inconsistent with withdrawn router length.", BGPError.MALFORMED_ATTR_LIST);
96 if (withdrawnRoutesLength == 0 && totalPathAttrLength == 0) {
97 final BGPUpdateSynchronized event = new BGPUpdateSynchronized() {
99 private static final long serialVersionUID = 5709361453437508337L;
102 public BGPTableType getTableType() {
103 return new BGPTableType(BGPAddressFamily.IPv4, BGPSubsequentAddressFamily.Unicast);
109 List<PathAttribute> pathAttributes;
110 if (totalPathAttrLength > 0) {
111 pathAttributes = parsePathAttributes(ByteArray.subByte(bytes, byteOffset, totalPathAttrLength));
112 byteOffset += totalPathAttrLength;
113 if (pathAttributes.get(0).getType() == TypeCode.MP_UNREACH_NLRI && totalPathAttrLength == 6) {
114 if (pathAttributes.get(0).getValue() instanceof IPv6MP) {
115 final BGPUpdateEvent event = new BGPUpdateSynchronized() {
117 private static final long serialVersionUID = -6026212683738125407L;
120 public BGPTableType getTableType() {
121 return new BGPTableType(BGPAddressFamily.IPv6, BGPSubsequentAddressFamily.Unicast);
126 } else if (pathAttributes.get(0).getValue() == null) {
127 final BGPUpdateSynchronized event = new BGPUpdateSynchronized() {
129 private static final long serialVersionUID = 5888562784007786559L;
132 public BGPTableType getTableType() {
133 return new BGPTableType(BGPAddressFamily.LinkState, BGPSubsequentAddressFamily.Unicast);
141 pathAttributes = Collections.emptyList();
143 eventBuilder.setPathAttributes(pathAttributes);
145 final Set<Prefix<IPv4Address>> nlri = IPv4.FAMILY.prefixListForBytes(ByteArray.subByte(bytes, byteOffset, bytes.length - byteOffset));
146 eventBuilder.setNlri(nlri);
149 logger.trace("Update message was parsed.");
150 return eventBuilder.buildEvent();
151 } catch (final BGPParsingException e) {
152 throw new BGPDocumentedException("Parsing unsuccessful: {}" + e.getMessage(), BGPError.MALFORMED_ATTR_LIST);
157 * Parse different Path Attributes from given bytes.
159 * @param bytes byte array to be parsed
160 * @return list of Path Attributes
161 * @throws BGPParsingException
163 private static List<PathAttribute> parsePathAttributes(byte[] bytes) throws BGPDocumentedException {
164 if (bytes.length == 0) {
165 return Collections.emptyList();
167 final List<PathAttribute> list = Lists.newArrayList();
168 while (bytes.length != 0) {
171 attr = PathAttributeParser.parseAttribute(bytes);
172 bytes = ByteArray.cutBytes(bytes,
173 PathAttribute.ATTR_FLAGS_SIZE + PathAttribute.ATTR_TYPE_CODE_SIZE + attr.getAttrLengthSize() + attr.getLength());
175 } catch (final BGPParsingException e) {
176 logger.warn("Could not parse BGP attributes: {}", e.getMessage(), e);
177 throw new BGPDocumentedException("Could not parse BGP attributes.", BGPError.MALFORMED_ATTR_LIST);