[Emu] [ONOS-2596] BGP Open message parsing, encoding and decoding
Change-Id: I2847849aef78314dfa8f3be0c8f34715719a15f2
diff --git a/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPOpenMsg.java b/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPOpenMsg.java
new file mode 100644
index 0000000..c41e5eb
--- /dev/null
+++ b/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/BGPOpenMsg.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.bgpio.protocol;
+
+import java.util.LinkedList;
+
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.types.BGPHeader;
+import org.onosproject.bgpio.types.BGPValueType;
+
+/**
+ * Abstraction of an entity providing BGP Open Message.
+ */
+public interface BGPOpenMsg extends BGPMessage {
+
+ @Override
+ BGPHeader getHeader();
+
+ @Override
+ BGPVersion getVersion();
+
+ @Override
+ BGPType getType();
+
+ /**
+ * Returns hold time of Open Message.
+ *
+ * @return hold time of Open Message
+ */
+ short getHoldTime();
+
+ /**
+ * Returns AS Number of Open Message.
+ *
+ * @return AS Number of Open Message
+ */
+ short getAsNumber();
+
+ /**
+ * Returns BGP Identifier of Open Message.
+ *
+ * @return BGP Identifier of Open Message
+ */
+ int getBgpId();
+
+ /**
+ * Returns capabilities of Open Message.
+ *
+ * @return capabilities of Open Message
+ */
+ LinkedList<BGPValueType> getCapabilityTlv();
+
+ /**
+ * Builder interface with get and set functions to build Open message.
+ */
+ interface Builder extends BGPMessage.Builder {
+
+ @Override
+ BGPOpenMsg build() throws BGPParseException;
+
+ @Override
+ BGPHeader getHeader();
+
+ @Override
+ BGPVersion getVersion();
+
+ @Override
+ BGPType getType();
+
+ /**
+ * Returns hold time of Open Message.
+ *
+ * @return hold time of Open Message
+ */
+ short getHoldTime();
+
+ /**
+ * Sets hold time in Open Message and return its builder.
+ *
+ * @param holdtime
+ * hold timer value in open message
+ * @return builder by setting hold time
+ */
+ Builder setHoldTime(short holdtime);
+
+ /**
+ * Returns as number of Open Message.
+ *
+ * @return as number of Open Message
+ */
+ short getAsNumber();
+
+ /**
+ * Sets AS number in Open Message and return its builder.
+ *
+ * @param asNumber
+ * as number in open message
+ * @return builder by setting asNumber
+ */
+ Builder setAsNumber(short asNumber);
+
+ /**
+ * Returns BGP Identifier of Open Message.
+ *
+ * @return BGP Identifier of Open Message
+ */
+ int getBgpId();
+
+ /**
+ * Sets BGP Identifier in Open Message and return its builder.
+ *
+ * @param bgpId
+ * BGP Identifier in open message
+ * @return builder by setting BGP Identifier
+ */
+ Builder setBgpId(int bgpId);
+
+ /**
+ * Returns capabilities of Open Message.
+ *
+ * @return capabilities of Open Message
+ */
+ LinkedList<BGPValueType> getCapabilityTlv();
+
+ /**
+ * Sets capabilities in Open Message and return its builder.
+ *
+ * @param capabilityTlv
+ * capabilities in open message
+ * @return builder by setting capabilities
+ */
+ Builder setCapabilityTlv(LinkedList<BGPValueType> capabilityTlv);
+
+ @Override
+ Builder setHeader(BGPHeader bgpMsgHeader);
+ }
+}
diff --git a/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPOpenMsgVer4.java b/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPOpenMsgVer4.java
new file mode 100644
index 0000000..1348ecf
--- /dev/null
+++ b/bgp/bgpio/src/main/java/org/onosproject/bgpio/protocol/ver4/BGPOpenMsgVer4.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.bgpio.protocol.ver4;
+
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.protocol.BGPMessageReader;
+import org.onosproject.bgpio.protocol.BGPMessageWriter;
+import org.onosproject.bgpio.protocol.BGPOpenMsg;
+import org.onosproject.bgpio.protocol.BGPType;
+import org.onosproject.bgpio.protocol.BGPVersion;
+import org.onosproject.bgpio.types.BGPErrorType;
+import org.onosproject.bgpio.types.BGPHeader;
+import org.onosproject.bgpio.types.BGPValueType;
+import org.onosproject.bgpio.util.Validation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Provides BGP open message.
+ */
+public class BGPOpenMsgVer4 implements BGPOpenMsg {
+
+ /*
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+
+ | Version |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | My Autonomous System |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Hold Time |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | BGP Identifier |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Opt Parm Len |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Optional Parameters (variable) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ OPEN Message Format
+ REFERENCE : RFC 4271
+ */
+
+ protected static final Logger log = LoggerFactory.getLogger(BGPOpenMsgVer4.class);
+
+ public static final byte PACKET_VERSION = 4;
+ public static final int OPEN_MSG_MINIMUM_LENGTH = 10;
+ public static final int MSG_HEADER_LENGTH = 19;
+ public static final int MARKER_LENGTH = 16;
+ public static final int DEFAULT_HOLD_TIME = 120;
+ public static final int OPT_PARA_TYPE_CAPABILITY = 2;
+ public static final BGPType MSG_TYPE = BGPType.OPEN;
+ public static final byte[] MARKER = new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
+ public static final BGPHeader DEFAULT_OPEN_HEADER = new BGPHeader(MARKER,
+ (short) OPEN_MSG_MINIMUM_LENGTH, (byte) 0X01);
+ private BGPHeader bgpMsgHeader;
+ private byte version;
+ private short asNumber;
+ private short holdTime;
+ private int bgpId;
+ private LinkedList<BGPValueType> capabilityTlv;
+
+ public static final BGPOpenMsgVer4.Reader READER = new Reader();
+
+ /**
+ * reset variables.
+ */
+ public BGPOpenMsgVer4() {
+ this.bgpMsgHeader = null;
+ this.version = 0;
+ this.holdTime = 0;
+ this.asNumber = 0;
+ this.bgpId = 0;
+ this.capabilityTlv = null;
+ }
+
+ /**
+ * Constructor to initialize all variables of BGP Open message.
+ *
+ * @param bgpMsgHeader
+ * BGP Header in open message
+ * @param version
+ * BGP version in open message
+ * @param holdTime
+ * hold time in open message
+ * @param asNumber
+ * AS number in open message
+ * @param bgpId
+ * BGP identifier in open message
+ * @param capabilityTlv
+ * capabilities in open message
+ */
+ public BGPOpenMsgVer4(BGPHeader bgpMsgHeader, byte version, short asNumber, short holdTime,
+ int bgpId, LinkedList<BGPValueType> capabilityTlv) {
+ this.bgpMsgHeader = bgpMsgHeader;
+ this.version = version;
+ this.asNumber = asNumber;
+ this.holdTime = holdTime;
+ this.bgpId = bgpId;
+ this.capabilityTlv = capabilityTlv;
+ }
+
+ @Override
+ public BGPHeader getHeader() {
+ return this.bgpMsgHeader;
+ }
+
+ @Override
+ public BGPVersion getVersion() {
+ return BGPVersion.BGP_4;
+ }
+
+ @Override
+ public BGPType getType() {
+ return MSG_TYPE;
+ }
+
+ @Override
+ public short getHoldTime() {
+ return this.holdTime;
+ }
+
+ @Override
+ public short getAsNumber() {
+ return this.asNumber;
+ }
+
+ @Override
+ public int getBgpId() {
+ return this.bgpId;
+ }
+
+ @Override
+ public LinkedList<BGPValueType> getCapabilityTlv() {
+ return this.capabilityTlv;
+ }
+
+ /**
+ * Reader class for reading BGP open message from channel buffer.
+ */
+ public static class Reader implements BGPMessageReader<BGPOpenMsg> {
+
+ @Override
+ public BGPOpenMsg readFrom(ChannelBuffer cb, BGPHeader bgpHeader) throws BGPParseException {
+
+ byte version;
+ short holdTime;
+ short asNumber;
+ int bgpId;
+ byte optParaLen = 0;
+ byte optParaType;
+ byte capParaLen = 0;
+ LinkedList<BGPValueType> capabilityTlv = new LinkedList<>();
+
+ if (cb.readableBytes() < OPEN_MSG_MINIMUM_LENGTH) {
+ log.error("[readFrom] Invalid length: Packet size is less than the minimum length ");
+ Validation.validateLen(BGPErrorType.OPEN_MESSAGE_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH,
+ cb.readableBytes());
+ }
+
+ // Read version
+ version = cb.readByte();
+ if (version != PACKET_VERSION) {
+ log.error("[readFrom] Invalid version: " + version);
+ throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR,
+ BGPErrorType.UNSUPPORTED_VERSION_NUMBER, null);
+ }
+
+ // Read AS number
+ asNumber = cb.readShort();
+
+ // Read Hold timer
+ holdTime = cb.readShort();
+
+ // Read BGP Identifier
+ bgpId = cb.readInt();
+
+ // Read optional parameter length
+ optParaLen = cb.readByte();
+
+ // Read Capabilities if optional parameter length is greater than 0
+ if (optParaLen != 0) {
+ // Read optional parameter type
+ optParaType = cb.readByte();
+
+ // Read optional parameter length
+ capParaLen = cb.readByte();
+
+ if (cb.readableBytes() < capParaLen) {
+ throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR, (byte) 0, null);
+ }
+
+ ChannelBuffer capaCb = cb.readBytes(capParaLen);
+
+ // Parse capabilities only if optional parameter type is 2
+ if ((optParaType == OPT_PARA_TYPE_CAPABILITY) && (capParaLen != 0)) {
+ capabilityTlv = parseCapabilityTlv(capaCb);
+ } else {
+ throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR,
+ BGPErrorType.UNSUPPORTED_OPTIONAL_PARAMETER, null);
+ }
+ }
+ return new BGPOpenMsgVer4(bgpHeader, version, asNumber, holdTime, bgpId, capabilityTlv);
+ }
+ }
+
+ /**
+ * Parsing capabilities.
+ *
+ * @param cb of type channel buffer
+ * @return capabilityTlv of open message
+ * @throws BGPParseException while parsing capabilities
+ */
+ protected static LinkedList<BGPValueType> parseCapabilityTlv(ChannelBuffer cb) throws BGPParseException {
+
+ LinkedList<BGPValueType> capabilityTlv = new LinkedList<>();
+
+ // TODO: Capability parsing
+ return capabilityTlv;
+ }
+
+ /**
+ * Builder class for BGP open message.
+ */
+ static class Builder implements BGPOpenMsg.Builder {
+
+ private boolean isHeaderSet = false;
+ private BGPHeader bgpMsgHeader;
+ private boolean isHoldTimeSet = false;
+ private short holdTime;
+ private boolean isAsNumSet = false;
+ private short asNumber;
+ private boolean isBgpIdSet = false;
+ private int bgpId;
+
+ LinkedList<BGPValueType> capabilityTlv = new LinkedList<>();
+
+ @Override
+ public BGPOpenMsg build() throws BGPParseException {
+ BGPHeader bgpMsgHeader = this.isHeaderSet ? this.bgpMsgHeader : DEFAULT_OPEN_HEADER;
+ short holdTime = this.isHoldTimeSet ? this.holdTime : DEFAULT_HOLD_TIME;
+
+ if (!this.isAsNumSet) {
+ throw new BGPParseException("BGP AS number is not set (mandatory)");
+ }
+
+ if (!this.isBgpIdSet) {
+ throw new BGPParseException("BGPID is not set (mandatory)");
+ }
+
+ // TODO: capabilities build
+
+ return new BGPOpenMsgVer4(bgpMsgHeader, PACKET_VERSION, this.asNumber, holdTime, this.bgpId,
+ this.capabilityTlv);
+ }
+
+ @Override
+ public BGPHeader getHeader() {
+ return this.bgpMsgHeader;
+ }
+
+ @Override
+ public Builder setHeader(BGPHeader bgpMsgHeader) {
+ this.bgpMsgHeader = bgpMsgHeader;
+ return this;
+ }
+
+ @Override
+ public BGPVersion getVersion() {
+ return BGPVersion.BGP_4;
+ }
+
+ @Override
+ public BGPType getType() {
+ return MSG_TYPE;
+ }
+
+ @Override
+ public short getHoldTime() {
+ return this.holdTime;
+ }
+
+ @Override
+ public short getAsNumber() {
+ return this.asNumber;
+ }
+
+ @Override
+ public int getBgpId() {
+ return this.bgpId;
+ }
+
+ @Override
+ public LinkedList<BGPValueType> getCapabilityTlv() {
+ return this.capabilityTlv;
+ }
+
+ @Override
+ public Builder setHoldTime(short holdTime) {
+ this.holdTime = holdTime;
+ this.isHoldTimeSet = true;
+ return this;
+ }
+
+ @Override
+ public Builder setAsNumber(short asNumber) {
+ this.asNumber = asNumber;
+ this.isAsNumSet = true;
+ return this;
+ }
+
+ @Override
+ public Builder setBgpId(int bgpId) {
+ this.bgpId = bgpId;
+ this.isBgpIdSet = true;
+ return this;
+ }
+
+ @Override
+ public Builder setCapabilityTlv(LinkedList<BGPValueType> capabilityTlv) {
+ this.capabilityTlv = capabilityTlv;
+ return this;
+ }
+ }
+
+ @Override
+ public void writeTo(ChannelBuffer cb) {
+ try {
+ WRITER.write(cb, this);
+ } catch (BGPParseException e) {
+ log.debug("[writeTo] Error: " + e.toString());
+ }
+ }
+
+ public static final Writer WRITER = new Writer();
+
+ /**
+ * Writer class for writing BGP open message to channel buffer.
+ */
+ public static class Writer implements BGPMessageWriter<BGPOpenMsgVer4> {
+
+ @Override
+ public void write(ChannelBuffer cb, BGPOpenMsgVer4 message) throws BGPParseException {
+
+ int optParaLen = 0;
+
+ int startIndex = cb.writerIndex();
+
+ // write common header and get msg length index
+ int msgLenIndex = message.bgpMsgHeader.write(cb);
+
+ if (msgLenIndex <= 0) {
+ throw new BGPParseException("Unable to write message header.");
+ }
+
+ // write version in 1-octet
+ cb.writeByte(message.version);
+
+ // TODO : Write AS number based on capabilities
+ cb.writeShort(message.asNumber);
+
+ // write HoldTime in next 2-octet
+ cb.writeShort(message.holdTime);
+
+ // write BGP Identifier in next 4-octet
+ cb.writeInt(message.bgpId);
+
+ // store the index of Optional parameter length
+ int optParaLenIndex = cb.writerIndex();
+
+ // set optional parameter length as 0
+ cb.writeByte(0);
+
+ // Pack capability TLV
+ optParaLen = message.packCapabilityTlv(cb, message);
+
+ if (optParaLen != 0) {
+ // Update optional parameter length
+ cb.setByte(optParaLenIndex, (byte) (optParaLen + 2)); //+2 for optional parameter type.
+ }
+
+ // write OPEN Object Length
+ int length = cb.writerIndex() - startIndex;
+ cb.setShort(msgLenIndex, (short) length);
+ message.bgpMsgHeader.setLength((short) length);
+ }
+ }
+
+ /**
+ * returns length of capability tlvs.
+ *
+ * @param cb of type channel buffer
+ * @param message of type BGPOpenMsgVer4
+ * @return capParaLen of open message
+ */
+ protected int packCapabilityTlv(ChannelBuffer cb, BGPOpenMsgVer4 message) {
+ int startIndex = cb.writerIndex();
+ int capParaLen = 0;
+ int capParaLenIndex = 0;
+
+ LinkedList<BGPValueType> capabilityTlv = message.capabilityTlv;
+ ListIterator<BGPValueType> listIterator = capabilityTlv.listIterator();
+
+ if (listIterator.hasNext()) {
+ // Set optional parameter type as 2
+ cb.writeByte(OPT_PARA_TYPE_CAPABILITY);
+
+ // Store the index of capability parameter length and update length at the end
+ capParaLenIndex = cb.writerIndex();
+
+ // Set capability parameter length as 0
+ cb.writeByte(0);
+
+ // Update the startIndex to know the length of capability tlv
+ startIndex = cb.writerIndex();
+ }
+
+ while (listIterator.hasNext()) {
+ BGPValueType tlv = listIterator.next();
+ if (tlv == null) {
+ log.debug("Warning: tlv is null from CapabilityTlv list");
+ continue;
+ }
+ tlv.write(cb);
+ }
+
+ capParaLen = cb.writerIndex() - startIndex;
+
+ if (capParaLen != 0) {
+ // Update capability parameter length
+ cb.setByte(capParaLenIndex, (byte) capParaLen);
+ }
+ return capParaLen;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("bgpMsgHeader", bgpMsgHeader)
+ .add("version", version)
+ .add("holdTime", holdTime)
+ .add("asNumber", asNumber)
+ .add("bgpId", bgpId)
+ .add("capabilityTlv", capabilityTlv)
+ .toString();
+ }
+}