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 static java.util.Objects.requireNonNull;
12 import com.google.common.base.Preconditions;
13 import io.netty.buffer.ByteBuf;
14 import io.netty.buffer.ByteBufUtil;
15 import io.netty.buffer.Unpooled;
16 import java.util.ArrayList;
17 import java.util.List;
18 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
19 import org.opendaylight.protocol.bgp.parser.BGPError;
20 import org.opendaylight.protocol.bgp.parser.BGPParsingException;
21 import org.opendaylight.protocol.bgp.parser.spi.MessageParser;
22 import org.opendaylight.protocol.bgp.parser.spi.MessageSerializer;
23 import org.opendaylight.protocol.bgp.parser.spi.MessageUtil;
24 import org.opendaylight.protocol.bgp.parser.spi.ParameterRegistry;
25 import org.opendaylight.protocol.util.Ipv4Util;
26 import org.opendaylight.protocol.util.Values;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.Open;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.OpenBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev171207.open.message.BgpParameters;
32 import org.opendaylight.yangtools.yang.binding.Notification;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
37 * Parser for BGP Open message.
39 public final class BGPOpenMessageParser implements MessageParser, MessageSerializer {
41 private static final Logger LOG = LoggerFactory.getLogger(BGPOpenMessageParser.class);
43 public static final int TYPE = 1;
45 private static final int VERSION_SIZE = 1;
46 private static final int AS_SIZE = 2;
47 private static final int HOLD_TIME_SIZE = 2;
48 private static final int BGP_ID_SIZE = 4;
49 private static final int OPT_PARAM_LENGTH_SIZE = 1;
51 private static final int MIN_MSG_LENGTH = VERSION_SIZE + AS_SIZE + HOLD_TIME_SIZE + BGP_ID_SIZE + OPT_PARAM_LENGTH_SIZE;
53 private static final int BGP_VERSION = 4;
55 public static final int AS_TRANS = 23456;
57 private final ParameterRegistry reg;
59 public BGPOpenMessageParser(final ParameterRegistry reg) {
60 this.reg = requireNonNull(reg);
64 * Serializes given BGP Open message to byte array, without the header.
66 * @param msg BGP Open message to be serialized.
67 * @param bytes ByteBuf where the message will be serialized
70 public void serializeMessage(final Notification msg, final ByteBuf bytes) {
71 Preconditions.checkArgument(msg instanceof Open, "Message needs to be of type Open");
72 final Open open = (Open) msg;
73 final ByteBuf msgBody = Unpooled.buffer();
75 msgBody.writeByte(BGP_VERSION);
77 // When our AS number does not fit into two bytes, we report it as AS_TRANS
78 int openAS = open.getMyAsNumber();
79 if (openAS > Values.UNSIGNED_SHORT_MAX_VALUE) {
82 msgBody.writeShort(openAS);
83 msgBody.writeShort(open.getHoldTimer());
84 msgBody.writeBytes(Ipv4Util.bytesForAddress(open.getBgpIdentifier()));
86 final ByteBuf paramsBuffer = Unpooled.buffer();
87 if (open.getBgpParameters() != null) {
88 for (final BgpParameters param : open.getBgpParameters()) {
89 this.reg.serializeParameter(param, paramsBuffer);
92 msgBody.writeByte(paramsBuffer.writerIndex());
93 msgBody.writeBytes(paramsBuffer);
95 MessageUtil.formatMessage(TYPE, msgBody, bytes);
99 * Parses given byte array to BGP Open message
101 * @param body byte array representing BGP Open message, without header
102 * @param messageLength the length of the message
103 * @return {@link Open} BGP Open Message
104 * @throws BGPDocumentedException if the parsing was unsuccessful
107 public Open parseMessageBody(final ByteBuf body, final int messageLength) throws BGPDocumentedException {
108 Preconditions.checkArgument(body != null, "Buffer cannot be null.");
110 if (body.readableBytes() < MIN_MSG_LENGTH) {
111 throw BGPDocumentedException.badMessageLength("Open message too small.", messageLength);
113 final int version = body.readUnsignedByte();
114 if (version != BGP_VERSION) {
115 throw new BGPDocumentedException("BGP Protocol version " + version + " not supported.", BGPError.VERSION_NOT_SUPPORTED);
117 final AsNumber as = new AsNumber((long) body.readUnsignedShort());
118 final int holdTime = body.readUnsignedShort();
119 if (holdTime == 1 || holdTime == 2) {
120 throw new BGPDocumentedException("Hold time value not acceptable.", BGPError.HOLD_TIME_NOT_ACC);
122 Ipv4Address bgpId = null;
124 bgpId = Ipv4Util.addressForByteBuf(body);
125 } catch (final IllegalArgumentException e) {
126 throw new BGPDocumentedException("BGP Identifier is not a valid IPv4 Address", BGPError.BAD_BGP_ID, e);
128 final int optLength = body.readUnsignedByte();
130 final List<BgpParameters> optParams = new ArrayList<>();
132 fillParams(body.slice(), optParams);
134 LOG.debug("BGP Open message was parsed: AS = {}, holdTimer = {}, bgpId = {}, optParams = {}", as, holdTime, bgpId, optParams);
135 return new OpenBuilder().setMyAsNumber(as.getValue().intValue()).setHoldTimer(holdTime).setBgpIdentifier(bgpId).setBgpParameters(
139 private void fillParams(final ByteBuf buffer, final List<BgpParameters> params) throws BGPDocumentedException {
140 Preconditions.checkArgument(buffer != null && buffer.isReadable(), "BUffer cannot be null or empty.");
141 if (LOG.isTraceEnabled()) {
142 LOG.trace("Started parsing of BGP parameter: {}", ByteBufUtil.hexDump(buffer));
144 while (buffer.isReadable()) {
145 if (buffer.readableBytes() <= 2) {
146 throw new BGPDocumentedException("Malformed parameter encountered (" + buffer.readableBytes() + " bytes left)", BGPError.OPT_PARAM_NOT_SUPPORTED);
148 final int paramType = buffer.readUnsignedByte();
149 final int paramLength = buffer.readUnsignedByte();
150 final ByteBuf paramBody = buffer.readSlice(paramLength);
152 final BgpParameters param;
154 param = this.reg.parseParameter(paramType, paramBody);
155 } catch (final BGPParsingException e) {
156 throw new BGPDocumentedException("Optional parameter not parsed", BGPError.UNSPECIFIC_OPEN_ERROR, e);
161 LOG.debug("Ignoring BGP Parameter type: {}", paramType);
164 LOG.trace("Parsed BGP parameters: {}", params);