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;
10 import java.util.Arrays;
11 import java.util.List;
13 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
14 import org.opendaylight.protocol.bgp.parser.BGPError;
15 import org.opendaylight.protocol.bgp.parser.BGPMessage;
16 import org.opendaylight.protocol.bgp.parser.impl.message.BGPNotificationMessageParser;
17 import org.opendaylight.protocol.bgp.parser.impl.message.BGPOpenMessageParser;
18 import org.opendaylight.protocol.bgp.parser.impl.message.BGPUpdateMessageParser;
19 import org.opendaylight.protocol.bgp.parser.message.BGPKeepAliveMessage;
20 import org.opendaylight.protocol.bgp.parser.message.BGPNotificationMessage;
21 import org.opendaylight.protocol.bgp.parser.message.BGPOpenMessage;
22 import org.opendaylight.protocol.framework.DeserializerException;
23 import org.opendaylight.protocol.framework.DocumentedException;
24 import org.opendaylight.protocol.framework.ProtocolMessageFactory;
25 import org.opendaylight.protocol.util.ByteArray;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
29 import com.google.common.collect.Lists;
30 import com.google.common.primitives.UnsignedBytes;
35 public class BGPMessageFactory implements ProtocolMessageFactory<BGPMessage> {
37 private final static Logger logger = LoggerFactory.getLogger(BGPMessageFactory.class);
39 final static int LENGTH_FIELD_LENGTH = 2; // bytes
41 private final static int TYPE_FIELD_LENGTH = 1; // bytes
43 final static int MARKER_LENGTH = 16; // bytes
45 public final static int COMMON_HEADER_LENGTH = LENGTH_FIELD_LENGTH + TYPE_FIELD_LENGTH + MARKER_LENGTH;
47 public BGPMessageFactory() {
52 * @see org.opendaylight.protocol.bgp.parser.BGPMessageParser#parse(byte[])
55 public List<BGPMessage> parse(final byte[] bytes) throws DeserializerException, DocumentedException {
57 throw new IllegalArgumentException("Array of bytes is mandatory.");
59 if (bytes.length < COMMON_HEADER_LENGTH) {
60 throw new IllegalArgumentException("Too few bytes in passed array. Passed: " + bytes.length + ". Expected: >= "
61 + COMMON_HEADER_LENGTH + ".");
64 * byte array starts with message length
66 // final byte[] ones = new byte[MARKER_LENGTH];
67 // Arrays.fill(ones, (byte)0xff);
68 // if (Arrays.equals(bytes, ones))
69 // throw new BGPDocumentedException("Marker not set to ones.", BGPError.CONNECTION_NOT_SYNC);
70 final byte[] bs = ByteArray.cutBytes(bytes, MARKER_LENGTH);
71 final int messageLength = ByteArray.bytesToInt(ByteArray.subByte(bs, 0, LENGTH_FIELD_LENGTH));
72 final int messageType = UnsignedBytes.toInt(bs[LENGTH_FIELD_LENGTH]);
74 final byte[] msgBody = ByteArray.cutBytes(bs, LENGTH_FIELD_LENGTH + TYPE_FIELD_LENGTH);
76 if (messageLength < COMMON_HEADER_LENGTH) {
77 throw new BGPDocumentedException("Message length field not within valid range.", BGPError.BAD_MSG_LENGTH, ByteArray.subByte(bs,
78 0, LENGTH_FIELD_LENGTH));
80 if (msgBody.length != messageLength - COMMON_HEADER_LENGTH) {
81 throw new DeserializerException("Size doesn't match size specified in header. Passed: " + msgBody.length + "; Expected: "
82 + (messageLength - COMMON_HEADER_LENGTH) + ". ");
85 logger.debug("Attempt to parse message from bytes: {}", ByteArray.bytesToHexString(msgBody));
89 switch (messageType) {
91 msg = BGPOpenMessageParser.parse(msgBody);
92 logger.debug("Received and parsed Open Message: {}", msg);
95 msg = BGPUpdateMessageParser.parse(msgBody, messageLength);
96 logger.debug("Received and parsed Update Message: {}", msg);
99 msg = BGPNotificationMessageParser.parse(msgBody);
100 logger.debug("Received and parsed Notification Message: {}", msg);
103 msg = new BGPKeepAliveMessage();
104 if (messageLength != COMMON_HEADER_LENGTH) {
105 throw new BGPDocumentedException("Message length field not within valid range.", BGPError.BAD_MSG_LENGTH, ByteArray.subByte(
106 bs, 0, LENGTH_FIELD_LENGTH));
110 throw new BGPDocumentedException("Unhandled message type " + messageType, BGPError.BAD_MSG_TYPE, new byte[] { bs[LENGTH_FIELD_LENGTH] });
113 return Lists.newArrayList(msg);
117 public byte[] put(final BGPMessage msg) {
119 throw new IllegalArgumentException("BGPMessage is mandatory.");
122 logger.trace("Serializing {}", msg);
124 byte[] msgBody = null;
128 * Update message is not supported
130 if (msg instanceof BGPOpenMessage) {
132 msgBody = BGPOpenMessageParser.put((BGPOpenMessage) msg);
133 } else if (msg instanceof BGPNotificationMessage) {
135 msgBody = BGPNotificationMessageParser.put((BGPNotificationMessage) msg);
136 } else if (msg instanceof BGPKeepAliveMessage) {
138 msgBody = new byte[0];
140 throw new IllegalArgumentException("Unknown instance of BGPMessage. Passed " + msg.getClass());
143 final byte[] headerBytes = headerToBytes(msgBody.length + COMMON_HEADER_LENGTH, msgType);
144 final byte[] retBytes = new byte[headerBytes.length + msgBody.length];
146 ByteArray.copyWhole(headerBytes, retBytes, 0);
147 ByteArray.copyWhole(msgBody, retBytes, COMMON_HEADER_LENGTH);
149 logger.trace("Serialized BGP message {}.", Arrays.toString(retBytes));
154 * Serializes this BGP Message header to byte array.
156 * @return byte array representation of this header
158 public byte[] headerToBytes(final int msgLength, final int msgType) {
159 final byte[] retBytes = new byte[COMMON_HEADER_LENGTH];
161 Arrays.fill(retBytes, 0, MARKER_LENGTH, (byte) 0xff);
163 System.arraycopy(ByteArray.intToBytes(msgLength), Integer.SIZE / Byte.SIZE - LENGTH_FIELD_LENGTH, retBytes, MARKER_LENGTH,
164 LENGTH_FIELD_LENGTH);
166 retBytes[MARKER_LENGTH + LENGTH_FIELD_LENGTH] = (byte) msgType;