Vidyashree Rama
Committed by Thomas Vachuska

[Emu] [ONOS-2596] BGP Open message parsing, encoding and decoding

Change-Id: I2847849aef78314dfa8f3be0c8f34715719a15f2
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.bgpio.protocol;
18 +
19 +import java.util.LinkedList;
20 +
21 +import org.onosproject.bgpio.exceptions.BGPParseException;
22 +import org.onosproject.bgpio.types.BGPHeader;
23 +import org.onosproject.bgpio.types.BGPValueType;
24 +
25 +/**
26 + * Abstraction of an entity providing BGP Open Message.
27 + */
28 +public interface BGPOpenMsg extends BGPMessage {
29 +
30 + @Override
31 + BGPHeader getHeader();
32 +
33 + @Override
34 + BGPVersion getVersion();
35 +
36 + @Override
37 + BGPType getType();
38 +
39 + /**
40 + * Returns hold time of Open Message.
41 + *
42 + * @return hold time of Open Message
43 + */
44 + short getHoldTime();
45 +
46 + /**
47 + * Returns AS Number of Open Message.
48 + *
49 + * @return AS Number of Open Message
50 + */
51 + short getAsNumber();
52 +
53 + /**
54 + * Returns BGP Identifier of Open Message.
55 + *
56 + * @return BGP Identifier of Open Message
57 + */
58 + int getBgpId();
59 +
60 + /**
61 + * Returns capabilities of Open Message.
62 + *
63 + * @return capabilities of Open Message
64 + */
65 + LinkedList<BGPValueType> getCapabilityTlv();
66 +
67 + /**
68 + * Builder interface with get and set functions to build Open message.
69 + */
70 + interface Builder extends BGPMessage.Builder {
71 +
72 + @Override
73 + BGPOpenMsg build() throws BGPParseException;
74 +
75 + @Override
76 + BGPHeader getHeader();
77 +
78 + @Override
79 + BGPVersion getVersion();
80 +
81 + @Override
82 + BGPType getType();
83 +
84 + /**
85 + * Returns hold time of Open Message.
86 + *
87 + * @return hold time of Open Message
88 + */
89 + short getHoldTime();
90 +
91 + /**
92 + * Sets hold time in Open Message and return its builder.
93 + *
94 + * @param holdtime
95 + * hold timer value in open message
96 + * @return builder by setting hold time
97 + */
98 + Builder setHoldTime(short holdtime);
99 +
100 + /**
101 + * Returns as number of Open Message.
102 + *
103 + * @return as number of Open Message
104 + */
105 + short getAsNumber();
106 +
107 + /**
108 + * Sets AS number in Open Message and return its builder.
109 + *
110 + * @param asNumber
111 + * as number in open message
112 + * @return builder by setting asNumber
113 + */
114 + Builder setAsNumber(short asNumber);
115 +
116 + /**
117 + * Returns BGP Identifier of Open Message.
118 + *
119 + * @return BGP Identifier of Open Message
120 + */
121 + int getBgpId();
122 +
123 + /**
124 + * Sets BGP Identifier in Open Message and return its builder.
125 + *
126 + * @param bgpId
127 + * BGP Identifier in open message
128 + * @return builder by setting BGP Identifier
129 + */
130 + Builder setBgpId(int bgpId);
131 +
132 + /**
133 + * Returns capabilities of Open Message.
134 + *
135 + * @return capabilities of Open Message
136 + */
137 + LinkedList<BGPValueType> getCapabilityTlv();
138 +
139 + /**
140 + * Sets capabilities in Open Message and return its builder.
141 + *
142 + * @param capabilityTlv
143 + * capabilities in open message
144 + * @return builder by setting capabilities
145 + */
146 + Builder setCapabilityTlv(LinkedList<BGPValueType> capabilityTlv);
147 +
148 + @Override
149 + Builder setHeader(BGPHeader bgpMsgHeader);
150 + }
151 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.bgpio.protocol.ver4;
18 +
19 +import java.util.LinkedList;
20 +import java.util.ListIterator;
21 +
22 +import org.jboss.netty.buffer.ChannelBuffer;
23 +import org.onosproject.bgpio.exceptions.BGPParseException;
24 +import org.onosproject.bgpio.protocol.BGPMessageReader;
25 +import org.onosproject.bgpio.protocol.BGPMessageWriter;
26 +import org.onosproject.bgpio.protocol.BGPOpenMsg;
27 +import org.onosproject.bgpio.protocol.BGPType;
28 +import org.onosproject.bgpio.protocol.BGPVersion;
29 +import org.onosproject.bgpio.types.BGPErrorType;
30 +import org.onosproject.bgpio.types.BGPHeader;
31 +import org.onosproject.bgpio.types.BGPValueType;
32 +import org.onosproject.bgpio.util.Validation;
33 +import org.slf4j.Logger;
34 +import org.slf4j.LoggerFactory;
35 +
36 +import com.google.common.base.MoreObjects;
37 +
38 +/**
39 + * Provides BGP open message.
40 + */
41 +public class BGPOpenMsgVer4 implements BGPOpenMsg {
42 +
43 + /*
44 + 0 1 2 3
45 + 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
46 + +-+-+-+-+-+-+-+-+
47 + | Version |
48 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49 + | My Autonomous System |
50 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 + | Hold Time |
52 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53 + | BGP Identifier |
54 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 + | Opt Parm Len |
56 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57 + | Optional Parameters (variable) |
58 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59 + OPEN Message Format
60 + REFERENCE : RFC 4271
61 + */
62 +
63 + protected static final Logger log = LoggerFactory.getLogger(BGPOpenMsgVer4.class);
64 +
65 + public static final byte PACKET_VERSION = 4;
66 + public static final int OPEN_MSG_MINIMUM_LENGTH = 10;
67 + public static final int MSG_HEADER_LENGTH = 19;
68 + public static final int MARKER_LENGTH = 16;
69 + public static final int DEFAULT_HOLD_TIME = 120;
70 + public static final int OPT_PARA_TYPE_CAPABILITY = 2;
71 + public static final BGPType MSG_TYPE = BGPType.OPEN;
72 + public static final byte[] MARKER = new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
73 + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
74 + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
75 + public static final BGPHeader DEFAULT_OPEN_HEADER = new BGPHeader(MARKER,
76 + (short) OPEN_MSG_MINIMUM_LENGTH, (byte) 0X01);
77 + private BGPHeader bgpMsgHeader;
78 + private byte version;
79 + private short asNumber;
80 + private short holdTime;
81 + private int bgpId;
82 + private LinkedList<BGPValueType> capabilityTlv;
83 +
84 + public static final BGPOpenMsgVer4.Reader READER = new Reader();
85 +
86 + /**
87 + * reset variables.
88 + */
89 + public BGPOpenMsgVer4() {
90 + this.bgpMsgHeader = null;
91 + this.version = 0;
92 + this.holdTime = 0;
93 + this.asNumber = 0;
94 + this.bgpId = 0;
95 + this.capabilityTlv = null;
96 + }
97 +
98 + /**
99 + * Constructor to initialize all variables of BGP Open message.
100 + *
101 + * @param bgpMsgHeader
102 + * BGP Header in open message
103 + * @param version
104 + * BGP version in open message
105 + * @param holdTime
106 + * hold time in open message
107 + * @param asNumber
108 + * AS number in open message
109 + * @param bgpId
110 + * BGP identifier in open message
111 + * @param capabilityTlv
112 + * capabilities in open message
113 + */
114 + public BGPOpenMsgVer4(BGPHeader bgpMsgHeader, byte version, short asNumber, short holdTime,
115 + int bgpId, LinkedList<BGPValueType> capabilityTlv) {
116 + this.bgpMsgHeader = bgpMsgHeader;
117 + this.version = version;
118 + this.asNumber = asNumber;
119 + this.holdTime = holdTime;
120 + this.bgpId = bgpId;
121 + this.capabilityTlv = capabilityTlv;
122 + }
123 +
124 + @Override
125 + public BGPHeader getHeader() {
126 + return this.bgpMsgHeader;
127 + }
128 +
129 + @Override
130 + public BGPVersion getVersion() {
131 + return BGPVersion.BGP_4;
132 + }
133 +
134 + @Override
135 + public BGPType getType() {
136 + return MSG_TYPE;
137 + }
138 +
139 + @Override
140 + public short getHoldTime() {
141 + return this.holdTime;
142 + }
143 +
144 + @Override
145 + public short getAsNumber() {
146 + return this.asNumber;
147 + }
148 +
149 + @Override
150 + public int getBgpId() {
151 + return this.bgpId;
152 + }
153 +
154 + @Override
155 + public LinkedList<BGPValueType> getCapabilityTlv() {
156 + return this.capabilityTlv;
157 + }
158 +
159 + /**
160 + * Reader class for reading BGP open message from channel buffer.
161 + */
162 + public static class Reader implements BGPMessageReader<BGPOpenMsg> {
163 +
164 + @Override
165 + public BGPOpenMsg readFrom(ChannelBuffer cb, BGPHeader bgpHeader) throws BGPParseException {
166 +
167 + byte version;
168 + short holdTime;
169 + short asNumber;
170 + int bgpId;
171 + byte optParaLen = 0;
172 + byte optParaType;
173 + byte capParaLen = 0;
174 + LinkedList<BGPValueType> capabilityTlv = new LinkedList<>();
175 +
176 + if (cb.readableBytes() < OPEN_MSG_MINIMUM_LENGTH) {
177 + log.error("[readFrom] Invalid length: Packet size is less than the minimum length ");
178 + Validation.validateLen(BGPErrorType.OPEN_MESSAGE_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH,
179 + cb.readableBytes());
180 + }
181 +
182 + // Read version
183 + version = cb.readByte();
184 + if (version != PACKET_VERSION) {
185 + log.error("[readFrom] Invalid version: " + version);
186 + throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR,
187 + BGPErrorType.UNSUPPORTED_VERSION_NUMBER, null);
188 + }
189 +
190 + // Read AS number
191 + asNumber = cb.readShort();
192 +
193 + // Read Hold timer
194 + holdTime = cb.readShort();
195 +
196 + // Read BGP Identifier
197 + bgpId = cb.readInt();
198 +
199 + // Read optional parameter length
200 + optParaLen = cb.readByte();
201 +
202 + // Read Capabilities if optional parameter length is greater than 0
203 + if (optParaLen != 0) {
204 + // Read optional parameter type
205 + optParaType = cb.readByte();
206 +
207 + // Read optional parameter length
208 + capParaLen = cb.readByte();
209 +
210 + if (cb.readableBytes() < capParaLen) {
211 + throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR, (byte) 0, null);
212 + }
213 +
214 + ChannelBuffer capaCb = cb.readBytes(capParaLen);
215 +
216 + // Parse capabilities only if optional parameter type is 2
217 + if ((optParaType == OPT_PARA_TYPE_CAPABILITY) && (capParaLen != 0)) {
218 + capabilityTlv = parseCapabilityTlv(capaCb);
219 + } else {
220 + throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR,
221 + BGPErrorType.UNSUPPORTED_OPTIONAL_PARAMETER, null);
222 + }
223 + }
224 + return new BGPOpenMsgVer4(bgpHeader, version, asNumber, holdTime, bgpId, capabilityTlv);
225 + }
226 + }
227 +
228 + /**
229 + * Parsing capabilities.
230 + *
231 + * @param cb of type channel buffer
232 + * @return capabilityTlv of open message
233 + * @throws BGPParseException while parsing capabilities
234 + */
235 + protected static LinkedList<BGPValueType> parseCapabilityTlv(ChannelBuffer cb) throws BGPParseException {
236 +
237 + LinkedList<BGPValueType> capabilityTlv = new LinkedList<>();
238 +
239 + // TODO: Capability parsing
240 + return capabilityTlv;
241 + }
242 +
243 + /**
244 + * Builder class for BGP open message.
245 + */
246 + static class Builder implements BGPOpenMsg.Builder {
247 +
248 + private boolean isHeaderSet = false;
249 + private BGPHeader bgpMsgHeader;
250 + private boolean isHoldTimeSet = false;
251 + private short holdTime;
252 + private boolean isAsNumSet = false;
253 + private short asNumber;
254 + private boolean isBgpIdSet = false;
255 + private int bgpId;
256 +
257 + LinkedList<BGPValueType> capabilityTlv = new LinkedList<>();
258 +
259 + @Override
260 + public BGPOpenMsg build() throws BGPParseException {
261 + BGPHeader bgpMsgHeader = this.isHeaderSet ? this.bgpMsgHeader : DEFAULT_OPEN_HEADER;
262 + short holdTime = this.isHoldTimeSet ? this.holdTime : DEFAULT_HOLD_TIME;
263 +
264 + if (!this.isAsNumSet) {
265 + throw new BGPParseException("BGP AS number is not set (mandatory)");
266 + }
267 +
268 + if (!this.isBgpIdSet) {
269 + throw new BGPParseException("BGPID is not set (mandatory)");
270 + }
271 +
272 + // TODO: capabilities build
273 +
274 + return new BGPOpenMsgVer4(bgpMsgHeader, PACKET_VERSION, this.asNumber, holdTime, this.bgpId,
275 + this.capabilityTlv);
276 + }
277 +
278 + @Override
279 + public BGPHeader getHeader() {
280 + return this.bgpMsgHeader;
281 + }
282 +
283 + @Override
284 + public Builder setHeader(BGPHeader bgpMsgHeader) {
285 + this.bgpMsgHeader = bgpMsgHeader;
286 + return this;
287 + }
288 +
289 + @Override
290 + public BGPVersion getVersion() {
291 + return BGPVersion.BGP_4;
292 + }
293 +
294 + @Override
295 + public BGPType getType() {
296 + return MSG_TYPE;
297 + }
298 +
299 + @Override
300 + public short getHoldTime() {
301 + return this.holdTime;
302 + }
303 +
304 + @Override
305 + public short getAsNumber() {
306 + return this.asNumber;
307 + }
308 +
309 + @Override
310 + public int getBgpId() {
311 + return this.bgpId;
312 + }
313 +
314 + @Override
315 + public LinkedList<BGPValueType> getCapabilityTlv() {
316 + return this.capabilityTlv;
317 + }
318 +
319 + @Override
320 + public Builder setHoldTime(short holdTime) {
321 + this.holdTime = holdTime;
322 + this.isHoldTimeSet = true;
323 + return this;
324 + }
325 +
326 + @Override
327 + public Builder setAsNumber(short asNumber) {
328 + this.asNumber = asNumber;
329 + this.isAsNumSet = true;
330 + return this;
331 + }
332 +
333 + @Override
334 + public Builder setBgpId(int bgpId) {
335 + this.bgpId = bgpId;
336 + this.isBgpIdSet = true;
337 + return this;
338 + }
339 +
340 + @Override
341 + public Builder setCapabilityTlv(LinkedList<BGPValueType> capabilityTlv) {
342 + this.capabilityTlv = capabilityTlv;
343 + return this;
344 + }
345 + }
346 +
347 + @Override
348 + public void writeTo(ChannelBuffer cb) {
349 + try {
350 + WRITER.write(cb, this);
351 + } catch (BGPParseException e) {
352 + log.debug("[writeTo] Error: " + e.toString());
353 + }
354 + }
355 +
356 + public static final Writer WRITER = new Writer();
357 +
358 + /**
359 + * Writer class for writing BGP open message to channel buffer.
360 + */
361 + public static class Writer implements BGPMessageWriter<BGPOpenMsgVer4> {
362 +
363 + @Override
364 + public void write(ChannelBuffer cb, BGPOpenMsgVer4 message) throws BGPParseException {
365 +
366 + int optParaLen = 0;
367 +
368 + int startIndex = cb.writerIndex();
369 +
370 + // write common header and get msg length index
371 + int msgLenIndex = message.bgpMsgHeader.write(cb);
372 +
373 + if (msgLenIndex <= 0) {
374 + throw new BGPParseException("Unable to write message header.");
375 + }
376 +
377 + // write version in 1-octet
378 + cb.writeByte(message.version);
379 +
380 + // TODO : Write AS number based on capabilities
381 + cb.writeShort(message.asNumber);
382 +
383 + // write HoldTime in next 2-octet
384 + cb.writeShort(message.holdTime);
385 +
386 + // write BGP Identifier in next 4-octet
387 + cb.writeInt(message.bgpId);
388 +
389 + // store the index of Optional parameter length
390 + int optParaLenIndex = cb.writerIndex();
391 +
392 + // set optional parameter length as 0
393 + cb.writeByte(0);
394 +
395 + // Pack capability TLV
396 + optParaLen = message.packCapabilityTlv(cb, message);
397 +
398 + if (optParaLen != 0) {
399 + // Update optional parameter length
400 + cb.setByte(optParaLenIndex, (byte) (optParaLen + 2)); //+2 for optional parameter type.
401 + }
402 +
403 + // write OPEN Object Length
404 + int length = cb.writerIndex() - startIndex;
405 + cb.setShort(msgLenIndex, (short) length);
406 + message.bgpMsgHeader.setLength((short) length);
407 + }
408 + }
409 +
410 + /**
411 + * returns length of capability tlvs.
412 + *
413 + * @param cb of type channel buffer
414 + * @param message of type BGPOpenMsgVer4
415 + * @return capParaLen of open message
416 + */
417 + protected int packCapabilityTlv(ChannelBuffer cb, BGPOpenMsgVer4 message) {
418 + int startIndex = cb.writerIndex();
419 + int capParaLen = 0;
420 + int capParaLenIndex = 0;
421 +
422 + LinkedList<BGPValueType> capabilityTlv = message.capabilityTlv;
423 + ListIterator<BGPValueType> listIterator = capabilityTlv.listIterator();
424 +
425 + if (listIterator.hasNext()) {
426 + // Set optional parameter type as 2
427 + cb.writeByte(OPT_PARA_TYPE_CAPABILITY);
428 +
429 + // Store the index of capability parameter length and update length at the end
430 + capParaLenIndex = cb.writerIndex();
431 +
432 + // Set capability parameter length as 0
433 + cb.writeByte(0);
434 +
435 + // Update the startIndex to know the length of capability tlv
436 + startIndex = cb.writerIndex();
437 + }
438 +
439 + while (listIterator.hasNext()) {
440 + BGPValueType tlv = listIterator.next();
441 + if (tlv == null) {
442 + log.debug("Warning: tlv is null from CapabilityTlv list");
443 + continue;
444 + }
445 + tlv.write(cb);
446 + }
447 +
448 + capParaLen = cb.writerIndex() - startIndex;
449 +
450 + if (capParaLen != 0) {
451 + // Update capability parameter length
452 + cb.setByte(capParaLenIndex, (byte) capParaLen);
453 + }
454 + return capParaLen;
455 + }
456 +
457 + @Override
458 + public String toString() {
459 + return MoreObjects.toStringHelper(getClass())
460 + .add("bgpMsgHeader", bgpMsgHeader)
461 + .add("version", version)
462 + .add("holdTime", holdTime)
463 + .add("asNumber", asNumber)
464 + .add("bgpId", bgpId)
465 + .add("capabilityTlv", capabilityTlv)
466 + .toString();
467 + }
468 +}