blob: bd228896186b0a723b4414c4e085a1e63706589e [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
330 public BGPHeader getHeader() {
331 return this.bgpMsgHeader;
332 }
333
334 @Override
335 public Builder setHeader(BGPHeader bgpMsgHeader) {
336 this.bgpMsgHeader = bgpMsgHeader;
337 return this;
338 }
339
340 @Override
341 public BGPVersion getVersion() {
342 return BGPVersion.BGP_4;
343 }
344
345 @Override
346 public BGPType getType() {
347 return MSG_TYPE;
348 }
349
350 @Override
351 public short getHoldTime() {
352 return this.holdTime;
353 }
354
355 @Override
356 public short getAsNumber() {
357 return this.asNumber;
358 }
359
360 @Override
361 public int getBgpId() {
362 return this.bgpId;
363 }
364
365 @Override
366 public LinkedList<BGPValueType> getCapabilityTlv() {
367 return this.capabilityTlv;
368 }
369
370 @Override
371 public Builder setHoldTime(short holdTime) {
372 this.holdTime = holdTime;
373 this.isHoldTimeSet = true;
374 return this;
375 }
376
377 @Override
378 public Builder setAsNumber(short asNumber) {
379 this.asNumber = asNumber;
380 this.isAsNumSet = true;
381 return this;
382 }
383
384 @Override
385 public Builder setBgpId(int bgpId) {
386 this.bgpId = bgpId;
387 this.isBgpIdSet = true;
388 return this;
389 }
390
391 @Override
392 public Builder setCapabilityTlv(LinkedList<BGPValueType> capabilityTlv) {
393 this.capabilityTlv = capabilityTlv;
394 return this;
395 }
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +0530396
397 @Override
398 public Builder setLargeAsCapabilityTlv(boolean isLargeAsCapabilitySet) {
399 this.isLargeAsCapabilityTlvSet = isLargeAsCapabilitySet;
400 return this;
401 }
402
403 @Override
404 public Builder setLsCapabilityTlv(boolean isLsCapabilitySet) {
405 this.isLsCapabilityTlvSet = isLsCapabilitySet;
406 return this;
407 }
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +0530408 }
409
410 @Override
411 public void writeTo(ChannelBuffer cb) {
412 try {
413 WRITER.write(cb, this);
414 } catch (BGPParseException e) {
415 log.debug("[writeTo] Error: " + e.toString());
416 }
417 }
418
419 public static final Writer WRITER = new Writer();
420
421 /**
422 * Writer class for writing BGP open message to channel buffer.
423 */
424 public static class Writer implements BGPMessageWriter<BGPOpenMsgVer4> {
425
426 @Override
427 public void write(ChannelBuffer cb, BGPOpenMsgVer4 message) throws BGPParseException {
428
429 int optParaLen = 0;
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +0530430 int as4num = 0;
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +0530431
432 int startIndex = cb.writerIndex();
433
434 // write common header and get msg length index
435 int msgLenIndex = message.bgpMsgHeader.write(cb);
436
437 if (msgLenIndex <= 0) {
438 throw new BGPParseException("Unable to write message header.");
439 }
440
441 // write version in 1-octet
442 cb.writeByte(message.version);
443
Vidyashree Ramaf49b22c2015-10-13 15:30:24 +0530444 // get as4num if LS Capability is set
445 if (message.isLargeAsCapabilitySet) {
446 LinkedList<BGPValueType> capabilityTlv = message
447 .getCapabilityTlv();
448 ListIterator<BGPValueType> listIterator = capabilityTlv
449 .listIterator();
450
451 while (listIterator.hasNext()) {
452 BGPValueType tlv = listIterator.next();
453 if (tlv.getType() == FOUR_OCTET_AS_NUM_CAPA_TYPE) {
454 as4num = ((FourOctetAsNumCapabilityTlv) tlv).getInt();
455 break;
456 }
457 }
458 }
459
460 if ((message.isLargeAsCapabilitySet) && (as4num > 65535)) {
461 // write As number as AS_TRANS
462 cb.writeShort(AS_TRANS);
463 } else {
464 // write AS number in next 2-octet
465 cb.writeShort(message.asNumber);
466 }
Vidyashree Rama6d4f84e2015-09-21 20:01:02 +0530467
468 // write HoldTime in next 2-octet
469 cb.writeShort(message.holdTime);
470
471 // write BGP Identifier in next 4-octet
472 cb.writeInt(message.bgpId);
473
474 // store the index of Optional parameter length
475 int optParaLenIndex = cb.writerIndex();
476
477 // set optional parameter length as 0
478 cb.writeByte(0);
479
480 // Pack capability TLV
481 optParaLen = message.packCapabilityTlv(cb, message);
482
483 if (optParaLen != 0) {
484 // Update optional parameter length
485 cb.setByte(optParaLenIndex, (byte) (optParaLen + 2)); //+2 for optional parameter type.
486 }
487
488 // write OPEN Object Length
489 int length = cb.writerIndex() - startIndex;
490 cb.setShort(msgLenIndex, (short) length);
491 message.bgpMsgHeader.setLength((short) length);
492 }
493 }
494
495 /**
496 * returns length of capability tlvs.
497 *
498 * @param cb of type channel buffer
499 * @param message of type BGPOpenMsgVer4
500 * @return capParaLen of open message
501 */
502 protected int packCapabilityTlv(ChannelBuffer cb, BGPOpenMsgVer4 message) {
503 int startIndex = cb.writerIndex();
504 int capParaLen = 0;
505 int capParaLenIndex = 0;
506
507 LinkedList<BGPValueType> capabilityTlv = message.capabilityTlv;
508 ListIterator<BGPValueType> listIterator = capabilityTlv.listIterator();
509
510 if (listIterator.hasNext()) {
511 // Set optional parameter type as 2
512 cb.writeByte(OPT_PARA_TYPE_CAPABILITY);
513
514 // Store the index of capability parameter length and update length at the end
515 capParaLenIndex = cb.writerIndex();
516
517 // Set capability parameter length as 0
518 cb.writeByte(0);
519
520 // Update the startIndex to know the length of capability tlv
521 startIndex = cb.writerIndex();
522 }
523
524 while (listIterator.hasNext()) {
525 BGPValueType tlv = listIterator.next();
526 if (tlv == null) {
527 log.debug("Warning: tlv is null from CapabilityTlv list");
528 continue;
529 }
530 tlv.write(cb);
531 }
532
533 capParaLen = cb.writerIndex() - startIndex;
534
535 if (capParaLen != 0) {
536 // Update capability parameter length
537 cb.setByte(capParaLenIndex, (byte) capParaLen);
538 }
539 return capParaLen;
540 }
541
542 @Override
543 public String toString() {
544 return MoreObjects.toStringHelper(getClass())
545 .add("bgpMsgHeader", bgpMsgHeader)
546 .add("version", version)
547 .add("holdTime", holdTime)
548 .add("asNumber", asNumber)
549 .add("bgpId", bgpId)
550 .add("capabilityTlv", capabilityTlv)
551 .toString();
552 }
553}