import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
import org.opendaylight.protocol.bgp.parser.BGPError;
import org.opendaylight.protocol.bgp.parser.BGPParsingException;
-import org.opendaylight.protocol.bgp.parser.impl.message.open.BGPParameterParser;
+import org.opendaylight.protocol.bgp.parser.impl.message.open.SimpleParameterRegistry;
+import org.opendaylight.protocol.bgp.parser.spi.MessageParser;
+import org.opendaylight.protocol.bgp.parser.spi.MessageSerializer;
+import org.opendaylight.protocol.bgp.parser.spi.MessageUtil;
+import org.opendaylight.protocol.bgp.parser.spi.ParameterRegistry;
import org.opendaylight.protocol.concepts.Ipv4Util;
import org.opendaylight.protocol.util.ByteArray;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.AsNumber;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.Open;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.OpenBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130918.open.BgpParameters;
+import org.opendaylight.yangtools.yang.binding.Notification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.primitives.UnsignedBytes;
/**
* Parser for BGP Open message.
*/
-public final class BGPOpenMessageParser {
+public final class BGPOpenMessageParser implements MessageParser, MessageSerializer {
+ public static final int TYPE = 1;
+ public static final MessageParser PARSER;
+ public static final MessageSerializer SERIALIZER;
+
+ static {
+ final BGPOpenMessageParser p = new BGPOpenMessageParser(SimpleParameterRegistry.INSTANCE);
+ PARSER = p;
+ SERIALIZER = p;
+ }
private static final Logger logger = LoggerFactory.getLogger(BGPOpenMessageParser.class);
private static final int BGP_VERSION = 4;
- private BGPOpenMessageParser() {
+ private final ParameterRegistry reg;
+ private BGPOpenMessageParser(final ParameterRegistry reg) {
+ this.reg = Preconditions.checkNotNull(reg);
}
/**
* @param msg BGP Open message to be serialized.
* @return BGP Open message converted to byte array
*/
- public static byte[] put(final Open msg) {
- if (msg == null)
+ @Override
+ public byte[] serializeMessage(final Notification msg) {
+ if (msg == null) {
throw new IllegalArgumentException("BGPOpen message cannot be null");
+ }
logger.trace("Started serializing open message: {}", msg);
+ final Open open = (Open) msg;
final Map<byte[], Integer> optParams = Maps.newHashMap();
int optParamsLength = 0;
- if (msg.getBgpParameters() != null) {
- for (final BgpParameters param : msg.getBgpParameters()) {
- final byte[] p = BGPParameterParser.put(param);
- optParams.put(p, p.length);
- optParamsLength += p.length;
+ if (open.getBgpParameters() != null) {
+ for (final BgpParameters param : open.getBgpParameters()) {
+ final byte[] p = reg.serializeParameter(param);
+ if (p != null) {
+ optParams.put(p, p.length);
+ optParamsLength += p.length;
+ }
}
}
- final byte[] msgBody = (msg.getBgpParameters() == null || msg.getBgpParameters().isEmpty()) ? new byte[MIN_MSG_LENGTH]
- : new byte[MIN_MSG_LENGTH + optParamsLength];
+ final byte[] msgBody = new byte[MIN_MSG_LENGTH + optParamsLength];
int offset = 0;
offset += VERSION_SIZE;
// When our AS number does not fit into two bytes, we report it as AS_TRANS
- int openAS = msg.getMyAsNumber();
- if (openAS > 65535)
+ int openAS = open.getMyAsNumber();
+ if (openAS > 65535) {
openAS = 2345;
+ }
System.arraycopy(ByteArray.longToBytes(openAS), 6, msgBody, offset, AS_SIZE);
offset += AS_SIZE;
- System.arraycopy(ByteArray.intToBytes(msg.getHoldTimer()), 2, msgBody, offset, HOLD_TIME_SIZE);
+ System.arraycopy(ByteArray.intToBytes(open.getHoldTimer()), 2, msgBody, offset, HOLD_TIME_SIZE);
offset += HOLD_TIME_SIZE;
- System.arraycopy(Ipv4Util.bytesForAddress(msg.getBgpIdentifier()), 0, msgBody, offset, BGP_ID_SIZE);
+ System.arraycopy(Ipv4Util.bytesForAddress(open.getBgpIdentifier()), 0, msgBody, offset, BGP_ID_SIZE);
offset += BGP_ID_SIZE;
msgBody[offset] = ByteArray.intToBytes(optParamsLength)[Integer.SIZE / Byte.SIZE - 1];
index += entry.getValue();
}
}
- logger.trace("Open message serialized to: {}", Arrays.toString(msgBody));
- return msgBody;
+
+ final byte[] ret = MessageUtil.formatMessage(TYPE, msgBody);
+ logger.trace("Open message serialized to: {}", Arrays.toString(ret));
+ return ret;
}
/**
* Parses given byte array to BGP Open message
*
- * @param bytes byte array representing BGP Open message, without header
+ * @param body byte array representing BGP Open message, without header
* @return BGP Open Message
* @throws BGPDocumentedException if the parsing was unsuccessful
*/
- public static Open parse(final byte[] bytes) throws BGPDocumentedException {
- if (bytes == null || bytes.length == 0)
- throw new IllegalArgumentException("Byte array cannot be null or empty.");
- logger.trace("Started parsing of open message: {}", Arrays.toString(bytes));
+ @Override
+ public Open parseMessageBody(final byte[] body, final int messageLength) throws BGPDocumentedException {
+ if (body == null) {
+ throw new IllegalArgumentException("Byte array cannot be null.");
+ }
+ logger.trace("Started parsing of open message: {}", Arrays.toString(body));
- if (bytes.length < MIN_MSG_LENGTH)
- throw new BGPDocumentedException("Open message too small.", BGPError.BAD_MSG_LENGTH, ByteArray.intToBytes(bytes.length));
- if (UnsignedBytes.toInt(bytes[0]) != BGP_VERSION)
- throw new BGPDocumentedException("BGP Protocol version " + UnsignedBytes.toInt(bytes[0]) + " not supported.", BGPError.VERSION_NOT_SUPPORTED, ByteArray.subByte(
+ if (body.length < MIN_MSG_LENGTH) {
+ throw BGPDocumentedException.badMessageLength("Open message too small.", messageLength);
+ }
+ if (UnsignedBytes.toInt(body[0]) != BGP_VERSION) {
+ throw new BGPDocumentedException("BGP Protocol version " + UnsignedBytes.toInt(body[0]) + " not supported.", BGPError.VERSION_NOT_SUPPORTED, ByteArray.subByte(
ByteArray.intToBytes(BGP_VERSION), 2, 2));
+ }
int offset = VERSION_SIZE;
- final AsNumber as = new AsNumber(ByteArray.bytesToLong(ByteArray.subByte(bytes, offset, AS_SIZE)));
+ final AsNumber as = new AsNumber(ByteArray.bytesToLong(ByteArray.subByte(body, offset, AS_SIZE)));
offset += AS_SIZE;
// TODO: BAD_PEER_AS Error: when is an AS unacceptable?
- final short holdTime = ByteArray.bytesToShort(ByteArray.subByte(bytes, offset, HOLD_TIME_SIZE));
+ final short holdTime = ByteArray.bytesToShort(ByteArray.subByte(body, offset, HOLD_TIME_SIZE));
offset += HOLD_TIME_SIZE;
- if (holdTime == 1 || holdTime == 2)
+ if (holdTime == 1 || holdTime == 2) {
throw new BGPDocumentedException("Hold time value not acceptable.", BGPError.HOLD_TIME_NOT_ACC);
+ }
Ipv4Address bgpId = null;
try {
- bgpId = Ipv4Util.addressForBytes(ByteArray.subByte(bytes, offset, BGP_ID_SIZE));
+ bgpId = Ipv4Util.addressForBytes(ByteArray.subByte(body, offset, BGP_ID_SIZE));
} catch (final IllegalArgumentException e) {
throw new BGPDocumentedException("BGP Identifier is not a valid IPv4 Address", BGPError.BAD_BGP_ID);
}
offset += BGP_ID_SIZE;
- final int optLength = UnsignedBytes.toInt(bytes[offset]);
+ final int optLength = UnsignedBytes.toInt(body[offset]);
List<BgpParameters> optParams = Lists.newArrayList();
if (optLength > 0) {
+ fillParams(ByteArray.subByte(body, MIN_MSG_LENGTH, optLength), optParams);
+ }
+ logger.trace("Open message was parsed: AS = {}, holdTimer = {}, bgpId = {}, optParams = {}", as, holdTime, bgpId, optParams);
+ return new OpenBuilder().setMyAsNumber(as.getValue().intValue()).setHoldTimer((int) holdTime).setBgpIdentifier(bgpId).setBgpParameters(
+ optParams).build();
+ }
+
+ private void fillParams(final byte[] bytes, final List<BgpParameters> params) throws BGPDocumentedException {
+ if (bytes == null || bytes.length == 0) {
+ throw new IllegalArgumentException("Byte array cannot be null or empty.");
+ }
+
+ logger.trace("Started parsing of BGP parameter: {}", Arrays.toString(bytes));
+ int byteOffset = 0;
+ while (byteOffset < bytes.length) {
+ if (byteOffset + 2 >= bytes.length) {
+ // FIXME: throw a BGPDocumentedException here?
+ throw new IllegalArgumentException("Malformed parameter encountered (" + (bytes.length - byteOffset) + " bytes left)");
+ }
+
+ final int paramType = UnsignedBytes.toInt(bytes[byteOffset++]);
+ final int paramLength = UnsignedBytes.toInt(bytes[byteOffset++]);
+ final byte[] paramBody = ByteArray.subByte(bytes, byteOffset, paramLength);
+ byteOffset += paramLength;
+
+ final BgpParameters param;
try {
- optParams = BGPParameterParser.parse(ByteArray.subByte(bytes, MIN_MSG_LENGTH, optLength));
+ param = reg.parseParameter(paramType, paramBody);
} catch (final BGPParsingException e) {
throw new BGPDocumentedException("Optional parameter not parsed: ." + e.getMessage(), BGPError.UNSPECIFIC_OPEN_ERROR);
}
+
+ if (param != null) {
+ params.add(param);
+ } else {
+ logger.debug("Ignoring BGP Parameter type: {}", paramType);
+ }
}
- logger.trace("Open message was parsed: AS = {}, holdTimer = {}, bgpId = {}, optParams = {}", as, holdTime, bgpId, optParams);
- return new OpenBuilder().setMyAsNumber(as.getValue().intValue()).setHoldTimer((int) holdTime).setBgpIdentifier(bgpId).setBgpParameters(
- optParams).build();
+
+ logger.trace("Parsed BGP parameters: {}", Arrays.toString(params.toArray()));
}
}