blob: b50342d602055e80bf3d57a57cf9d7509e35ecdf [file] [log] [blame]
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +05301/*
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 */
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +053016package org.onosproject.bgpio.protocol.ver4;
17
18import java.util.LinkedList;
19import java.util.ListIterator;
20
21import org.jboss.netty.buffer.ChannelBuffer;
22import org.onosproject.bgpio.exceptions.BGPParseException;
23import org.onosproject.bgpio.protocol.BGPMessageReader;
24import org.onosproject.bgpio.protocol.BGPMessageWriter;
25import org.onosproject.bgpio.protocol.BGPOpenMsg;
26import org.onosproject.bgpio.protocol.BGPType;
27import org.onosproject.bgpio.protocol.BGPVersion;
28import org.onosproject.bgpio.types.BGPErrorType;
29import org.onosproject.bgpio.types.BGPHeader;
30import org.onosproject.bgpio.types.BGPValueType;
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +053031import org.onosproject.bgpio.types.FourOctetAsNumCapabilityTlv;
32import org.onosproject.bgpio.types.MultiProtocolExtnCapabilityTlv;
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +053033import org.onosproject.bgpio.util.Validation;
34import org.slf4j.Logger;
35import org.slf4j.LoggerFactory;
36
37import com.google.common.base.MoreObjects;
38
39/**
40 * Provides BGP open message.
41 */
42public class BGPOpenMsgVer4 implements BGPOpenMsg {
43
44 /*
45 0 1 2 3
46 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
47 +-+-+-+-+-+-+-+-+
48 | Version |
49 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50 | My Autonomous System |
51 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52 | Hold Time |
53 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54 | BGP Identifier |
55 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56 | Opt Parm Len |
57 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58 | Optional Parameters (variable) |
59 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60 OPEN Message Format
61 REFERENCE : RFC 4271
62 */
63
64 protected static final Logger log = LoggerFactory.getLogger(BGPOpenMsgVer4.class);
65
66 public static final byte PACKET_VERSION = 4;
67 public static final int OPEN_MSG_MINIMUM_LENGTH = 10;
68 public static final int MSG_HEADER_LENGTH = 19;
69 public static final int MARKER_LENGTH = 16;
70 public static final int DEFAULT_HOLD_TIME = 120;
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +053071 public static final short AS_TRANS = 23456;
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +053072 public static final int OPT_PARA_TYPE_CAPABILITY = 2;
73 public static final BGPType MSG_TYPE = BGPType.OPEN;
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +053074 public static final short AFI = 16388;
75 public static final byte SAFI = 71;
76 public static final byte RES = 0;
77 public static final int FOUR_OCTET_AS_NUM_CAPA_TYPE = 65;
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +053078 public static final byte[] MARKER = new byte[]{(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
79 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
80 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
81 public static final BGPHeader DEFAULT_OPEN_HEADER = new BGPHeader(MARKER,
82 (short) OPEN_MSG_MINIMUM_LENGTH, (byte) 0X01);
83 private BGPHeader bgpMsgHeader;
84 private byte version;
85 private short asNumber;
86 private short holdTime;
87 private int bgpId;
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +053088 private boolean isLargeAsCapabilitySet;
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +053089 private LinkedList<BGPValueType> capabilityTlv;
90
91 public static final BGPOpenMsgVer4.Reader READER = new Reader();
92
93 /**
94 * reset variables.
95 */
96 public BGPOpenMsgVer4() {
97 this.bgpMsgHeader = null;
98 this.version = 0;
99 this.holdTime = 0;
100 this.asNumber = 0;
101 this.bgpId = 0;
102 this.capabilityTlv = null;
103 }
104
105 /**
106 * Constructor to initialize all variables of BGP Open message.
107 *
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +0530108 * @param bgpMsgHeader BGP Header in open message
109 * @param version BGP version in open message
110 * @param holdTime hold time in open message
111 * @param asNumber AS number in open message
112 * @param bgpId BGP identifier in open message
113 * @param capabilityTlv capabilities in open message
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +0530114 */
115 public BGPOpenMsgVer4(BGPHeader bgpMsgHeader, byte version, short asNumber, short holdTime,
116 int bgpId, LinkedList<BGPValueType> capabilityTlv) {
117 this.bgpMsgHeader = bgpMsgHeader;
118 this.version = version;
119 this.asNumber = asNumber;
120 this.holdTime = holdTime;
121 this.bgpId = bgpId;
122 this.capabilityTlv = capabilityTlv;
123 }
124
125 @Override
126 public BGPHeader getHeader() {
127 return this.bgpMsgHeader;
128 }
129
130 @Override
131 public BGPVersion getVersion() {
132 return BGPVersion.BGP_4;
133 }
134
135 @Override
136 public BGPType getType() {
137 return MSG_TYPE;
138 }
139
140 @Override
141 public short getHoldTime() {
142 return this.holdTime;
143 }
144
145 @Override
146 public short getAsNumber() {
147 return this.asNumber;
148 }
149
150 @Override
151 public int getBgpId() {
152 return this.bgpId;
153 }
154
155 @Override
156 public LinkedList<BGPValueType> getCapabilityTlv() {
157 return this.capabilityTlv;
158 }
159
160 /**
161 * Reader class for reading BGP open message from channel buffer.
162 */
163 public static class Reader implements BGPMessageReader<BGPOpenMsg> {
164
165 @Override
166 public BGPOpenMsg readFrom(ChannelBuffer cb, BGPHeader bgpHeader) throws BGPParseException {
167
168 byte version;
169 short holdTime;
170 short asNumber;
171 int bgpId;
172 byte optParaLen = 0;
173 byte optParaType;
174 byte capParaLen = 0;
175 LinkedList<BGPValueType> capabilityTlv = new LinkedList<>();
176
177 if (cb.readableBytes() < OPEN_MSG_MINIMUM_LENGTH) {
178 log.error("[readFrom] Invalid length: Packet size is less than the minimum length ");
179 Validation.validateLen(BGPErrorType.OPEN_MESSAGE_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH,
180 cb.readableBytes());
181 }
182
183 // Read version
184 version = cb.readByte();
185 if (version != PACKET_VERSION) {
186 log.error("[readFrom] Invalid version: " + version);
187 throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR,
188 BGPErrorType.UNSUPPORTED_VERSION_NUMBER, null);
189 }
190
191 // Read AS number
192 asNumber = cb.readShort();
193
194 // Read Hold timer
195 holdTime = cb.readShort();
196
197 // Read BGP Identifier
198 bgpId = cb.readInt();
199
200 // Read optional parameter length
201 optParaLen = cb.readByte();
202
203 // Read Capabilities if optional parameter length is greater than 0
204 if (optParaLen != 0) {
205 // Read optional parameter type
206 optParaType = cb.readByte();
207
208 // Read optional parameter length
209 capParaLen = cb.readByte();
210
211 if (cb.readableBytes() < capParaLen) {
212 throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR, (byte) 0, null);
213 }
214
215 ChannelBuffer capaCb = cb.readBytes(capParaLen);
216
217 // Parse capabilities only if optional parameter type is 2
218 if ((optParaType == OPT_PARA_TYPE_CAPABILITY) && (capParaLen != 0)) {
219 capabilityTlv = parseCapabilityTlv(capaCb);
220 } else {
221 throw new BGPParseException(BGPErrorType.OPEN_MESSAGE_ERROR,
222 BGPErrorType.UNSUPPORTED_OPTIONAL_PARAMETER, null);
223 }
224 }
225 return new BGPOpenMsgVer4(bgpHeader, version, asNumber, holdTime, bgpId, capabilityTlv);
226 }
227 }
228
229 /**
230 * Parsing capabilities.
231 *
232 * @param cb of type channel buffer
233 * @return capabilityTlv of open message
234 * @throws BGPParseException while parsing capabilities
235 */
236 protected static LinkedList<BGPValueType> parseCapabilityTlv(ChannelBuffer cb) throws BGPParseException {
237
238 LinkedList<BGPValueType> capabilityTlv = new LinkedList<>();
239
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +0530240 while (cb.readableBytes() > 0) {
241 BGPValueType tlv;
242 short type = cb.readByte();
243 short length = cb.readByte();
244
245 switch (type) {
246 case FourOctetAsNumCapabilityTlv.TYPE:
247 log.debug("FourOctetAsNumCapabilityTlv");
248 if (FourOctetAsNumCapabilityTlv.LENGTH != length) {
249 throw new BGPParseException("Invalid length received for FourOctetAsNumCapabilityTlv.");
250 }
251 if (length > cb.readableBytes()) {
252 throw new BGPParseException("Four octet as num tlv length"
253 + " is more than readableBytes.");
254 }
255 int as4Num = cb.readInt();
256 tlv = new FourOctetAsNumCapabilityTlv(as4Num);
257 break;
258 case MultiProtocolExtnCapabilityTlv.TYPE:
259 log.debug("MultiProtocolExtnCapabilityTlv");
260 if (MultiProtocolExtnCapabilityTlv.LENGTH != length) {
261 throw new BGPParseException("Invalid length received for MultiProtocolExtnCapabilityTlv.");
262 }
263 if (length > cb.readableBytes()) {
264 throw new BGPParseException("BGP LS tlv length is more than readableBytes.");
265 }
266 short afi = cb.readShort();
267 byte res = cb.readByte();
268 byte safi = cb.readByte();
269 tlv = new MultiProtocolExtnCapabilityTlv(afi, res, safi);
270 break;
271 default:
272 log.debug("Warning: Unsupported TLV: " + type);
273 cb.skipBytes(length);
274 continue;
275 }
276 capabilityTlv.add(tlv);
277 }
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +0530278 return capabilityTlv;
279 }
280
281 /**
282 * Builder class for BGP open message.
283 */
284 static class Builder implements BGPOpenMsg.Builder {
285
286 private boolean isHeaderSet = false;
287 private BGPHeader bgpMsgHeader;
288 private boolean isHoldTimeSet = false;
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +0530289 private short holdTime;
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +0530290 private boolean isAsNumSet = false;
291 private short asNumber;
292 private boolean isBgpIdSet = false;
293 private int bgpId;
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +0530294 private boolean isLargeAsCapabilityTlvSet = false;
295 private boolean isLsCapabilityTlvSet = false;
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +0530296
297 LinkedList<BGPValueType> capabilityTlv = new LinkedList<>();
298
299 @Override
300 public BGPOpenMsg build() throws BGPParseException {
301 BGPHeader bgpMsgHeader = this.isHeaderSet ? this.bgpMsgHeader : DEFAULT_OPEN_HEADER;
302 short holdTime = this.isHoldTimeSet ? this.holdTime : DEFAULT_HOLD_TIME;
303
304 if (!this.isAsNumSet) {
305 throw new BGPParseException("BGP AS number is not set (mandatory)");
306 }
307
308 if (!this.isBgpIdSet) {
309 throw new BGPParseException("BGPID is not set (mandatory)");
310 }
311
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +0530312 if (this.isLargeAsCapabilityTlvSet) {
313 BGPValueType tlv;
314 int iValue = this.getAsNumber();
315 tlv = new FourOctetAsNumCapabilityTlv(iValue);
316 this.capabilityTlv.add(tlv);
317 }
318
319 if (this.isLsCapabilityTlvSet) {
320 BGPValueType tlv;
321 tlv = new MultiProtocolExtnCapabilityTlv(AFI, RES, SAFI);
322 this.capabilityTlv.add(tlv);
323 }
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +0530324
325 return new BGPOpenMsgVer4(bgpMsgHeader, PACKET_VERSION, this.asNumber, holdTime, this.bgpId,
326 this.capabilityTlv);
327 }
328
329 @Override
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +0530330 public Builder setHeader(BGPHeader bgpMsgHeader) {
331 this.bgpMsgHeader = bgpMsgHeader;
332 return this;
333 }
334
335 @Override
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +0530336 public short getHoldTime() {
337 return this.holdTime;
338 }
339
340 @Override
341 public short getAsNumber() {
342 return this.asNumber;
343 }
344
345 @Override
346 public int getBgpId() {
347 return this.bgpId;
348 }
349
350 @Override
351 public LinkedList<BGPValueType> getCapabilityTlv() {
352 return this.capabilityTlv;
353 }
354
355 @Override
356 public Builder setHoldTime(short holdTime) {
357 this.holdTime = holdTime;
358 this.isHoldTimeSet = true;
359 return this;
360 }
361
362 @Override
363 public Builder setAsNumber(short asNumber) {
364 this.asNumber = asNumber;
365 this.isAsNumSet = true;
366 return this;
367 }
368
369 @Override
370 public Builder setBgpId(int bgpId) {
371 this.bgpId = bgpId;
372 this.isBgpIdSet = true;
373 return this;
374 }
375
376 @Override
377 public Builder setCapabilityTlv(LinkedList<BGPValueType> capabilityTlv) {
378 this.capabilityTlv = capabilityTlv;
379 return this;
380 }
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +0530381
382 @Override
383 public Builder setLargeAsCapabilityTlv(boolean isLargeAsCapabilitySet) {
384 this.isLargeAsCapabilityTlvSet = isLargeAsCapabilitySet;
385 return this;
386 }
387
388 @Override
389 public Builder setLsCapabilityTlv(boolean isLsCapabilitySet) {
390 this.isLsCapabilityTlvSet = isLsCapabilitySet;
391 return this;
392 }
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +0530393 }
394
395 @Override
396 public void writeTo(ChannelBuffer cb) {
397 try {
398 WRITER.write(cb, this);
399 } catch (BGPParseException e) {
400 log.debug("[writeTo] Error: " + e.toString());
401 }
402 }
403
404 public static final Writer WRITER = new Writer();
405
406 /**
407 * Writer class for writing BGP open message to channel buffer.
408 */
409 public static class Writer implements BGPMessageWriter<BGPOpenMsgVer4> {
410
411 @Override
412 public void write(ChannelBuffer cb, BGPOpenMsgVer4 message) throws BGPParseException {
413
414 int optParaLen = 0;
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +0530415 int as4num = 0;
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +0530416
417 int startIndex = cb.writerIndex();
418
419 // write common header and get msg length index
420 int msgLenIndex = message.bgpMsgHeader.write(cb);
421
422 if (msgLenIndex <= 0) {
423 throw new BGPParseException("Unable to write message header.");
424 }
425
426 // write version in 1-octet
427 cb.writeByte(message.version);
428
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +0530429 // get as4num if LS Capability is set
430 if (message.isLargeAsCapabilitySet) {
431 LinkedList<BGPValueType> capabilityTlv = message
432 .getCapabilityTlv();
433 ListIterator<BGPValueType> listIterator = capabilityTlv
434 .listIterator();
435
436 while (listIterator.hasNext()) {
437 BGPValueType tlv = listIterator.next();
438 if (tlv.getType() == FOUR_OCTET_AS_NUM_CAPA_TYPE) {
439 as4num = ((FourOctetAsNumCapabilityTlv) tlv).getInt();
440 break;
441 }
442 }
443 }
444
445 if ((message.isLargeAsCapabilitySet) && (as4num > 65535)) {
446 // write As number as AS_TRANS
447 cb.writeShort(AS_TRANS);
448 } else {
449 // write AS number in next 2-octet
450 cb.writeShort(message.asNumber);
451 }
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +0530452
453 // write HoldTime in next 2-octet
454 cb.writeShort(message.holdTime);
455
456 // write BGP Identifier in next 4-octet
457 cb.writeInt(message.bgpId);
458
459 // store the index of Optional parameter length
460 int optParaLenIndex = cb.writerIndex();
461
462 // set optional parameter length as 0
463 cb.writeByte(0);
464
465 // Pack capability TLV
466 optParaLen = message.packCapabilityTlv(cb, message);
467
468 if (optParaLen != 0) {
469 // Update optional parameter length
470 cb.setByte(optParaLenIndex, (byte) (optParaLen + 2)); //+2 for optional parameter type.
471 }
472
473 // write OPEN Object Length
474 int length = cb.writerIndex() - startIndex;
475 cb.setShort(msgLenIndex, (short) length);
476 message.bgpMsgHeader.setLength((short) length);
477 }
478 }
479
480 /**
481 * returns length of capability tlvs.
482 *
483 * @param cb of type channel buffer
484 * @param message of type BGPOpenMsgVer4
485 * @return capParaLen of open message
486 */
487 protected int packCapabilityTlv(ChannelBuffer cb, BGPOpenMsgVer4 message) {
488 int startIndex = cb.writerIndex();
489 int capParaLen = 0;
490 int capParaLenIndex = 0;
491
492 LinkedList<BGPValueType> capabilityTlv = message.capabilityTlv;
493 ListIterator<BGPValueType> listIterator = capabilityTlv.listIterator();
494
495 if (listIterator.hasNext()) {
496 // Set optional parameter type as 2
497 cb.writeByte(OPT_PARA_TYPE_CAPABILITY);
498
499 // Store the index of capability parameter length and update length at the end
500 capParaLenIndex = cb.writerIndex();
501
502 // Set capability parameter length as 0
503 cb.writeByte(0);
504
505 // Update the startIndex to know the length of capability tlv
506 startIndex = cb.writerIndex();
507 }
508
509 while (listIterator.hasNext()) {
510 BGPValueType tlv = listIterator.next();
511 if (tlv == null) {
512 log.debug("Warning: tlv is null from CapabilityTlv list");
513 continue;
514 }
515 tlv.write(cb);
516 }
517
518 capParaLen = cb.writerIndex() - startIndex;
519
520 if (capParaLen != 0) {
521 // Update capability parameter length
522 cb.setByte(capParaLenIndex, (byte) capParaLen);
523 }
524 return capParaLen;
525 }
526
527 @Override
528 public String toString() {
529 return MoreObjects.toStringHelper(getClass())
530 .add("bgpMsgHeader", bgpMsgHeader)
531 .add("version", version)
532 .add("holdTime", holdTime)
533 .add("asNumber", asNumber)
534 .add("bgpId", bgpId)
535 .add("capabilityTlv", capabilityTlv)
536 .toString();
537 }
538}