blob: 1348ecfd6df0435c77620fb293c1d4447291d6af [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 */
16
17package org.onosproject.bgpio.protocol.ver4;
18
19import java.util.LinkedList;
20import java.util.ListIterator;
21
22import org.jboss.netty.buffer.ChannelBuffer;
23import org.onosproject.bgpio.exceptions.BGPParseException;
24import org.onosproject.bgpio.protocol.BGPMessageReader;
25import org.onosproject.bgpio.protocol.BGPMessageWriter;
26import org.onosproject.bgpio.protocol.BGPOpenMsg;
27import org.onosproject.bgpio.protocol.BGPType;
28import org.onosproject.bgpio.protocol.BGPVersion;
29import org.onosproject.bgpio.types.BGPErrorType;
30import org.onosproject.bgpio.types.BGPHeader;
31import org.onosproject.bgpio.types.BGPValueType;
32import org.onosproject.bgpio.util.Validation;
33import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
36import com.google.common.base.MoreObjects;
37
38/**
39 * Provides BGP open message.
40 */
41public 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}