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;
10 import java.util.Arrays;
11 import java.util.List;
13 import java.util.Map.Entry;
15 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
16 import org.opendaylight.protocol.bgp.parser.BGPError;
17 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
18 import org.opendaylight.protocol.bgp.parser.impl.message.open.SimpleParameterRegistry;
19 import org.opendaylight.protocol.bgp.parser.spi.MessageParser;
20 import org.opendaylight.protocol.bgp.parser.spi.MessageSerializer;
21 import org.opendaylight.protocol.bgp.parser.spi.MessageUtil;
22 import org.opendaylight.protocol.bgp.parser.spi.ParameterRegistry;
23 import org.opendaylight.protocol.concepts.Ipv4Util;
24 import org.opendaylight.protocol.util.ByteArray;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.Open;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.OpenBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.open.BgpParameters;
30 import org.opendaylight.yangtools.yang.binding.Notification;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
34 import com.google.common.base.Preconditions;
35 import com.google.common.collect.Lists;
36 import com.google.common.collect.Maps;
37 import com.google.common.primitives.UnsignedBytes;
40 * Parser for BGP Open message.
42 public final class BGPOpenMessageParser implements MessageParser, MessageSerializer {
43 public static final int TYPE = 1;
44 public static final MessageParser PARSER;
45 public static final MessageSerializer SERIALIZER;
48 final BGPOpenMessageParser p = new BGPOpenMessageParser(SimpleParameterRegistry.getInstance());
53 private static final Logger logger = LoggerFactory.getLogger(BGPOpenMessageParser.class);
55 private static final int VERSION_SIZE = 1;
56 private static final int AS_SIZE = 2;
57 private static final int HOLD_TIME_SIZE = 2;
58 private static final int BGP_ID_SIZE = 4;
59 private static final int OPT_PARAM_LENGTH_SIZE = 1;
61 private static final int MIN_MSG_LENGTH = VERSION_SIZE + AS_SIZE + HOLD_TIME_SIZE + BGP_ID_SIZE + OPT_PARAM_LENGTH_SIZE;
63 private static final int BGP_VERSION = 4;
65 private final ParameterRegistry reg;
67 private BGPOpenMessageParser(final ParameterRegistry reg) {
68 this.reg = Preconditions.checkNotNull(reg);
72 * Serializes given BGP Open message to byte array, without the header.
74 * @param msg BGP Open message to be serialized.
75 * @return BGP Open message converted to byte array
78 public byte[] serializeMessage(final Notification msg) {
80 throw new IllegalArgumentException("BGPOpen message cannot be null");
82 logger.trace("Started serializing open message: {}", msg);
83 final Open open = (Open) msg;
85 final Map<byte[], Integer> optParams = Maps.newHashMap();
87 int optParamsLength = 0;
89 if (open.getBgpParameters() != null) {
90 for (final BgpParameters param : open.getBgpParameters()) {
91 final byte[] p = reg.serializeParameter(param);
93 optParams.put(p, p.length);
94 optParamsLength += p.length;
99 final byte[] msgBody = new byte[MIN_MSG_LENGTH + optParamsLength];
103 msgBody[offset] = ByteArray.intToBytes(BGP_VERSION)[(Integer.SIZE / Byte.SIZE) - 1];
104 offset += VERSION_SIZE;
106 // When our AS number does not fit into two bytes, we report it as AS_TRANS
107 int openAS = open.getMyAsNumber();
108 if (openAS > 65535) {
112 System.arraycopy(ByteArray.longToBytes(openAS), 6, msgBody, offset, AS_SIZE);
115 System.arraycopy(ByteArray.intToBytes(open.getHoldTimer()), 2, msgBody, offset, HOLD_TIME_SIZE);
116 offset += HOLD_TIME_SIZE;
118 System.arraycopy(Ipv4Util.bytesForAddress(open.getBgpIdentifier()), 0, msgBody, offset, BGP_ID_SIZE);
119 offset += BGP_ID_SIZE;
121 msgBody[offset] = ByteArray.intToBytes(optParamsLength)[Integer.SIZE / Byte.SIZE - 1];
123 int index = MIN_MSG_LENGTH;
124 if (optParams != null) {
125 for (final Entry<byte[], Integer> entry : optParams.entrySet()) {
126 System.arraycopy(entry.getKey(), 0, msgBody, index, entry.getValue());
127 index += entry.getValue();
131 final byte[] ret = MessageUtil.formatMessage(TYPE, msgBody);
132 logger.trace("Open message serialized to: {}", Arrays.toString(ret));
137 * Parses given byte array to BGP Open message
139 * @param body byte array representing BGP Open message, without header
140 * @return BGP Open Message
141 * @throws BGPDocumentedException if the parsing was unsuccessful
144 public Open parseMessageBody(final byte[] body, final int messageLength) throws BGPDocumentedException {
146 throw new IllegalArgumentException("Byte array cannot be null.");
148 logger.trace("Started parsing of open message: {}", Arrays.toString(body));
150 if (body.length < MIN_MSG_LENGTH) {
151 throw BGPDocumentedException.badMessageLength("Open message too small.", messageLength);
153 if (UnsignedBytes.toInt(body[0]) != BGP_VERSION) {
154 throw new BGPDocumentedException("BGP Protocol version " + UnsignedBytes.toInt(body[0]) + " not supported.", BGPError.VERSION_NOT_SUPPORTED, ByteArray.subByte(
155 ByteArray.intToBytes(BGP_VERSION), 2, 2));
158 int offset = VERSION_SIZE;
159 final AsNumber as = new AsNumber(ByteArray.bytesToLong(ByteArray.subByte(body, offset, AS_SIZE)));
162 // TODO: BAD_PEER_AS Error: when is an AS unacceptable?
164 final short holdTime = ByteArray.bytesToShort(ByteArray.subByte(body, offset, HOLD_TIME_SIZE));
165 offset += HOLD_TIME_SIZE;
166 if (holdTime == 1 || holdTime == 2) {
167 throw new BGPDocumentedException("Hold time value not acceptable.", BGPError.HOLD_TIME_NOT_ACC);
170 Ipv4Address bgpId = null;
172 bgpId = Ipv4Util.addressForBytes(ByteArray.subByte(body, offset, BGP_ID_SIZE));
173 } catch (final IllegalArgumentException e) {
174 throw new BGPDocumentedException("BGP Identifier is not a valid IPv4 Address", BGPError.BAD_BGP_ID);
176 offset += BGP_ID_SIZE;
178 final int optLength = UnsignedBytes.toInt(body[offset]);
180 List<BgpParameters> optParams = Lists.newArrayList();
182 fillParams(ByteArray.subByte(body, MIN_MSG_LENGTH, optLength), optParams);
184 logger.trace("Open message was parsed: AS = {}, holdTimer = {}, bgpId = {}, optParams = {}", as, holdTime, bgpId, optParams);
185 return new OpenBuilder().setMyAsNumber(as.getValue().intValue()).setHoldTimer((int) holdTime).setBgpIdentifier(bgpId).setBgpParameters(
189 private void fillParams(final byte[] bytes, final List<BgpParameters> params) throws BGPDocumentedException {
190 if (bytes == null || bytes.length == 0) {
191 throw new IllegalArgumentException("Byte array cannot be null or empty.");
194 logger.trace("Started parsing of BGP parameter: {}", Arrays.toString(bytes));
196 while (byteOffset < bytes.length) {
197 if (byteOffset + 2 >= bytes.length) {
198 // FIXME: throw a BGPDocumentedException here?
199 throw new IllegalArgumentException("Malformed parameter encountered (" + (bytes.length - byteOffset) + " bytes left)");
202 final int paramType = UnsignedBytes.toInt(bytes[byteOffset++]);
203 final int paramLength = UnsignedBytes.toInt(bytes[byteOffset++]);
204 final byte[] paramBody = ByteArray.subByte(bytes, byteOffset, paramLength);
205 byteOffset += paramLength;
207 final BgpParameters param;
209 param = reg.parseParameter(paramType, paramBody);
210 } catch (final BGPParsingException e) {
211 throw new BGPDocumentedException("Optional parameter not parsed: ." + e.getMessage(), BGPError.UNSPECIFIC_OPEN_ERROR);
217 logger.debug("Ignoring BGP Parameter type: {}", paramType);
221 logger.trace("Parsed BGP parameters: {}", Arrays.toString(params.toArray()));