blob: 1ccb6b6bede6e9a3cc7db7df487bff1e86880ae0 [file] [log] [blame]
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08003 *
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 */
Jonathan Hart41349e92015-02-09 14:14:02 -080016package org.onosproject.routing.bgp;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080017
18import org.jboss.netty.buffer.ChannelBuffer;
19import org.jboss.netty.buffer.ChannelBuffers;
20import org.jboss.netty.channel.ChannelHandlerContext;
21import org.onlab.packet.Ip4Address;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080022import org.slf4j.Logger;
23import org.slf4j.LoggerFactory;
24
25/**
26 * A class for handling BGP OPEN messages.
27 */
28final class BgpOpen {
29 private static final Logger log = LoggerFactory.getLogger(BgpOpen.class);
30
31 /**
32 * Default constructor.
33 * <p>
34 * The constructor is private to prevent creating an instance of
35 * this utility class.
36 */
37 private BgpOpen() {
38 }
39
40 /**
41 * Processes BGP OPEN message.
42 *
43 * @param bgpSession the BGP Session to use
44 * @param ctx the Channel Handler Context
45 * @param message the message to process
46 */
47 static void processBgpOpen(BgpSession bgpSession,
48 ChannelHandlerContext ctx,
49 ChannelBuffer message) {
50 int minLength =
51 BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
52 if (message.readableBytes() < minLength) {
53 log.debug("BGP RX OPEN Error from {}: " +
54 "Message length {} too short. Must be at least {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -080055 bgpSession.remoteInfo().address(),
56 message.readableBytes(), minLength);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080057 //
58 // ERROR: Bad Message Length
59 //
60 // Send NOTIFICATION and close the connection
61 ChannelBuffer txMessage =
62 BgpNotification.prepareBgpNotificationBadMessageLength(
63 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
64 ctx.getChannel().write(txMessage);
65 bgpSession.closeSession(ctx);
66 return;
67 }
68
69 //
70 // Parse the OPEN message
71 //
72 // Remote BGP version
73 int remoteBgpVersion = message.readUnsignedByte();
74 if (remoteBgpVersion != BgpConstants.BGP_VERSION) {
75 log.debug("BGP RX OPEN Error from {}: " +
76 "Unsupported BGP version {}. Should be {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -080077 bgpSession.remoteInfo().address(), remoteBgpVersion,
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080078 BgpConstants.BGP_VERSION);
79 //
80 // ERROR: Unsupported Version Number
81 //
82 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -080083 int errorCode = BgpConstants.Notifications.OpenMessageError.ERROR_CODE;
84 int errorSubcode = BgpConstants.Notifications.OpenMessageError.UNSUPPORTED_VERSION_NUMBER;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080085 ChannelBuffer data = ChannelBuffers.buffer(2);
86 data.writeShort(BgpConstants.BGP_VERSION);
87 ChannelBuffer txMessage =
88 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
89 data);
90 ctx.getChannel().write(txMessage);
91 bgpSession.closeSession(ctx);
92 return;
93 }
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -080094 bgpSession.remoteInfo().setBgpVersion(remoteBgpVersion);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080095
96 // Remote AS number
97 long remoteAs = message.readUnsignedShort();
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -080098 bgpSession.remoteInfo().setAsNumber(remoteAs);
99 //
100 // NOTE: Currently, the local AS number is always set to the remote AS.
101 // This is done, because the peer setup is always iBGP.
102 // In the future, the local AS number should be configured as part
103 // of an explicit BGP peering configuration.
104 //
105 bgpSession.localInfo().setAsNumber(remoteAs);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800106
107 // Remote Hold Time
108 long remoteHoldtime = message.readUnsignedShort();
109 if ((remoteHoldtime != 0) &&
110 (remoteHoldtime < BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME)) {
111 log.debug("BGP RX OPEN Error from {}: " +
112 "Unacceptable Hold Time field {}. " +
113 "Should be 0 or at least {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800114 bgpSession.remoteInfo().address(), remoteHoldtime,
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800115 BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME);
116 //
117 // ERROR: Unacceptable Hold Time
118 //
119 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -0800120 int errorCode = BgpConstants.Notifications.OpenMessageError.ERROR_CODE;
121 int errorSubcode = BgpConstants.Notifications.OpenMessageError.UNACCEPTABLE_HOLD_TIME;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800122 ChannelBuffer txMessage =
123 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
124 null);
125 ctx.getChannel().write(txMessage);
126 bgpSession.closeSession(ctx);
127 return;
128 }
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800129 bgpSession.remoteInfo().setHoldtime(remoteHoldtime);
130 //
131 // NOTE: Currently. the local BGP Holdtime is always set to the remote
132 // BGP holdtime.
133 // In the future, the local BGP Holdtime should be configured as part
134 // of an explicit BGP peering configuration.
135 //
136 bgpSession.localInfo().setHoldtime(remoteHoldtime);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800137
138 // Remote BGP Identifier
139 Ip4Address remoteBgpId =
140 Ip4Address.valueOf((int) message.readUnsignedInt());
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800141 bgpSession.remoteInfo().setBgpId(remoteBgpId);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800142
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800143 // Parse the Optional Parameters
144 try {
145 parseOptionalParameters(bgpSession, ctx, message);
Jonathan Hart41349e92015-02-09 14:14:02 -0800146 } catch (BgpMessage.BgpParseException e) {
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800147 // ERROR: Error parsing optional parameters
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800148 log.debug("BGP RX OPEN Error from {}: " +
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800149 "Exception parsing Optional Parameters: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800150 bgpSession.remoteInfo().address(), e);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800151 //
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800152 // ERROR: Invalid Optional Parameters: Unspecific
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800153 //
154 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -0800155 int errorCode = BgpConstants.Notifications.OpenMessageError.ERROR_CODE;
156 int errorSubcode = BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800157 ChannelBuffer txMessage =
158 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
159 null);
160 ctx.getChannel().write(txMessage);
161 bgpSession.closeSession(ctx);
162 return;
163 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800164
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800165 //
166 // NOTE: Prepare the BGP OPEN message before the original local AS
167 // is overwritten by the 4-octet AS number
168 //
169 ChannelBuffer txOpenMessage = prepareBgpOpen(bgpSession.localInfo());
170
171 //
172 // Use the 4-octet AS number in lieu of the "My AS" field
173 // See RFC 6793, Section 4.1, second paragraph.
174 //
175 if (bgpSession.remoteInfo().as4OctetCapability()) {
176 long as4Number = bgpSession.remoteInfo().as4Number();
177 bgpSession.remoteInfo().setAsNumber(as4Number);
178 bgpSession.localInfo().setAsNumber(as4Number);
179 }
180
181 //
182 // Verify that the AS number is same for all other BGP Sessions
183 // NOTE: This check applies only for our use-case where all BGP
184 // sessions are iBGP.
185 //
186 for (BgpSession bs : bgpSession.getBgpSessionManager().getBgpSessions()) {
187 if ((bs.remoteInfo().asNumber() != 0) &&
188 (bgpSession.remoteInfo().asNumber() !=
189 bs.remoteInfo().asNumber())) {
190 log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
191 "Expected {}",
192 bgpSession.remoteInfo().address(),
193 bgpSession.remoteInfo().asNumber(),
194 bs.remoteInfo().asNumber());
195 //
196 // ERROR: Bad Peer AS
197 //
198 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -0800199 int errorCode = BgpConstants.Notifications.OpenMessageError.ERROR_CODE;
200 int errorSubcode = BgpConstants.Notifications.OpenMessageError.BAD_PEER_AS;
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800201 ChannelBuffer txMessage =
202 BgpNotification.prepareBgpNotification(errorCode,
203 errorSubcode, null);
204 ctx.getChannel().write(txMessage);
205 bgpSession.closeSession(ctx);
206 return;
207 }
208 }
209
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800210 log.debug("BGP RX OPEN message from {}: " +
211 "BGPv{} AS {} BGP-ID {} Holdtime {}",
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800212 bgpSession.remoteInfo().address(),
213 bgpSession.remoteInfo().bgpVersion(),
214 bgpSession.remoteInfo().asNumber(),
215 bgpSession.remoteInfo().bgpId(),
216 bgpSession.remoteInfo().holdtime());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800217
218 // Send my OPEN followed by KEEPALIVE
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800219 ctx.getChannel().write(txOpenMessage);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800220 //
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800221 ChannelBuffer txMessage = BgpKeepalive.prepareBgpKeepalive();
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800222 ctx.getChannel().write(txMessage);
223
224 // Start the KEEPALIVE timer
225 bgpSession.restartKeepaliveTimer(ctx);
226
227 // Start the Session Timeout timer
228 bgpSession.restartSessionTimeoutTimer(ctx);
229 }
230
231 /**
232 * Prepares BGP OPEN message.
233 *
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800234 * @param localInfo the BGP Session local information to use
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800235 * @return the message to transmit (BGP header included)
236 */
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800237 static ChannelBuffer prepareBgpOpen(BgpSessionInfo localInfo) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800238 ChannelBuffer message =
239 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
240
241 //
242 // Prepare the OPEN message payload
243 //
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800244 message.writeByte(localInfo.bgpVersion());
245 message.writeShort((int) localInfo.asNumber());
246 message.writeShort((int) localInfo.holdtime());
247 message.writeInt(localInfo.bgpId().toInt());
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800248
249 // Prepare the optional BGP Capabilities
250 ChannelBuffer capabilitiesMessage =
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800251 prepareBgpOpenCapabilities(localInfo);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800252 message.writeByte(capabilitiesMessage.readableBytes());
253 message.writeBytes(capabilitiesMessage);
254
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800255 return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN,
256 message);
257 }
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800258
259 /**
260 * Parses BGP OPEN Optional Parameters.
261 *
262 * @param bgpSession the BGP Session to use
263 * @param ctx the Channel Handler Context
264 * @param message the message to process
Jonathan Hart41349e92015-02-09 14:14:02 -0800265 * @throws BgpMessage.BgpParseException
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800266 */
267 private static void parseOptionalParameters(BgpSession bgpSession,
268 ChannelHandlerContext ctx,
269 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -0800270 throws BgpMessage.BgpParseException {
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800271
272 //
273 // Get and verify the Optional Parameters Length
274 //
275 int optParamLength = message.readUnsignedByte();
276 if (optParamLength > message.readableBytes()) {
277 // ERROR: Invalid Optional Parameter Length
278 String errorMsg = "Invalid Optional Parameter Length field " +
279 optParamLength + ". Remaining Optional Parameters " +
280 message.readableBytes();
Jonathan Hart41349e92015-02-09 14:14:02 -0800281 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800282 }
283 if (optParamLength == 0) {
284 return; // No Optional Parameters
285 }
286
287 //
288 // Parse the Optional Parameters
289 //
290 int optParamEnd = message.readerIndex() + optParamLength;
291 while (message.readerIndex() < optParamEnd) {
292 int paramType = message.readUnsignedByte();
293 if (message.readerIndex() >= optParamEnd) {
294 // ERROR: Malformed Optional Parameters
295 String errorMsg = "Malformed Optional Parameters";
Jonathan Hart41349e92015-02-09 14:14:02 -0800296 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800297 }
298 int paramLen = message.readUnsignedByte();
299 if (message.readerIndex() + paramLen > optParamEnd) {
300 // ERROR: Malformed Optional Parameters
301 String errorMsg = "Malformed Optional Parameters";
Jonathan Hart41349e92015-02-09 14:14:02 -0800302 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800303 }
304
305 //
306 // Extract the Optional Parameter Value based on the Parameter Type
307 //
308 switch (paramType) {
Jonathan Hart41349e92015-02-09 14:14:02 -0800309 case BgpConstants.Open.Capabilities.TYPE:
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800310 // Optional Parameter Type: Capabilities
Jonathan Hart41349e92015-02-09 14:14:02 -0800311 if (paramLen < BgpConstants.Open.Capabilities.MIN_LENGTH) {
Pingping Lin816c4802015-11-10 15:28:54 -0800312 // ERROR: Malformed Param Type
313 String errorMsg = "Malformed Capabilities Optional "
314 + "Parameter Type " + paramType;
Jonathan Hart41349e92015-02-09 14:14:02 -0800315 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800316 }
Pingping Lin816c4802015-11-10 15:28:54 -0800317 int paramEnd = message.readerIndex() + paramLen;
318 // Parse Capabilities
319 while (message.readerIndex() < paramEnd) {
320 if (paramEnd - message.readerIndex() <
321 BgpConstants.Open.Capabilities.MIN_LENGTH) {
322 String errorMsg = "Malformed Capabilities";
Jonathan Hart41349e92015-02-09 14:14:02 -0800323 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800324 }
Pingping Lin816c4802015-11-10 15:28:54 -0800325 int capabCode = message.readUnsignedByte();
326 int capabLen = message.readUnsignedByte();
327 if (message.readerIndex() + capabLen > paramEnd) {
328 // ERROR: Malformed Capability
329 String errorMsg = "Malformed Capability instance with "
330 + "code " + capabCode;
331 throw new BgpMessage.BgpParseException(errorMsg);
332 }
333
334 switch (capabCode) {
335 case BgpConstants.Open.Capabilities.MultiprotocolExtensions.CODE:
336 // Multiprotocol Extensions Capabilities (RFC 4760)
337 if (capabLen != BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH) {
338 // ERROR: Multiprotocol Extension Length Error
339 String errorMsg = "Multiprotocol Extension Length Error";
340 throw new BgpMessage.BgpParseException(errorMsg);
341 }
342 // Decode the AFI (2 octets) and SAFI (1 octet)
343 int afi = message.readUnsignedShort();
344 int reserved = message.readUnsignedByte();
345 int safi = message.readUnsignedByte();
346 log.debug("BGP RX OPEN Capability: AFI = {} SAFI = {}",
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800347 afi, safi);
Pingping Lin816c4802015-11-10 15:28:54 -0800348 //
349 // Setup the AFI/SAFI in the BgpSession
350 //
351 // NOTE: For now we just copy the remote AFI/SAFI setting
352 // to the local configuration.
353 //
354 if (afi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4 &&
355 safi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_UNICAST) {
356 bgpSession.remoteInfo().setIpv4Unicast();
357 bgpSession.localInfo().setIpv4Unicast();
358 } else if (afi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4 &&
359 safi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_MULTICAST) {
360 bgpSession.remoteInfo().setIpv4Multicast();
361 bgpSession.localInfo().setIpv4Multicast();
362 } else if (afi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6 &&
363 safi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_UNICAST) {
364 bgpSession.remoteInfo().setIpv6Unicast();
365 bgpSession.localInfo().setIpv6Unicast();
366 } else if (afi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6 &&
367 safi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_MULTICAST) {
368 bgpSession.remoteInfo().setIpv6Multicast();
369 bgpSession.localInfo().setIpv6Multicast();
370 } else {
371 log.debug("BGP RX OPEN Capability: Unknown AFI = {} SAFI = {}",
372 afi, safi);
373 }
374 break;
375
376 case BgpConstants.Open.Capabilities.As4Octet.CODE:
377 // Support for 4-octet AS Number Capabilities (RFC 6793)
378 if (capabLen != BgpConstants.Open.Capabilities.As4Octet.LENGTH) {
379 // ERROR: 4-octet AS Number Capability Length Error
380 String errorMsg = "4-octet AS Number Capability Length Error";
381 throw new BgpMessage.BgpParseException(errorMsg);
382 }
383 long as4Number = message.readUnsignedInt();
384
385 bgpSession.remoteInfo().setAs4OctetCapability();
386 bgpSession.remoteInfo().setAs4Number(as4Number);
387
388 //
389 // Copy remote 4-octet AS Number Capabilities and AS
390 // Number. This is a temporary setting until local AS
391 // number configuration is supported.
392 //
393 bgpSession.localInfo().setAs4OctetCapability();
394 bgpSession.localInfo().setAs4Number(as4Number);
395 log.debug("BGP RX OPEN Capability: AS4 Number = {}",
396 as4Number);
397 break;
398
399 default:
400 // Unknown Capability: ignore it
401 log.debug("BGP RX OPEN Capability Code = {} Length = {}",
402 capabCode, capabLen);
403 message.readBytes(capabLen);
404 break;
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800405 }
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800406
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900407
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800408 }
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800409 break;
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800410 default:
411 // Unknown Parameter Type: ignore it
412 log.debug("BGP RX OPEN Parameter Type = {} Length = {}",
413 paramType, paramLen);
414 message.readBytes(paramLen);
415 break;
416 }
417 }
418 }
419
420 /**
421 * Prepares the Capabilities for the BGP OPEN message.
422 *
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800423 * @param localInfo the BGP Session local information to use
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800424 * @return the buffer with the BGP Capabilities to transmit
425 */
426 private static ChannelBuffer prepareBgpOpenCapabilities(
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800427 BgpSessionInfo localInfo) {
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800428 ChannelBuffer message =
429 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
430
431 //
432 // Write the Multiprotocol Extensions Capabilities
433 //
434
435 // IPv4 unicast
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800436 if (localInfo.ipv4Unicast()) {
Jonathan Hart41349e92015-02-09 14:14:02 -0800437 message.writeByte(BgpConstants.Open.Capabilities.TYPE); // Param type
438 message.writeByte(BgpConstants.Open.Capabilities.MIN_LENGTH +
439 BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Param len
440 message.writeByte(
441 BgpConstants.Open.Capabilities.MultiprotocolExtensions.CODE); // Capab. code
442 message.writeByte(
443 BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Capab. len
444 message.writeShort(
445 BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800446 message.writeByte(0); // Reserved field
Jonathan Hart41349e92015-02-09 14:14:02 -0800447 message.writeByte(
448 BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_UNICAST);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800449 }
450 // IPv4 multicast
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800451 if (localInfo.ipv4Multicast()) {
Jonathan Hart41349e92015-02-09 14:14:02 -0800452 message.writeByte(BgpConstants.Open.Capabilities.TYPE); // Param type
453 message.writeByte(BgpConstants.Open.Capabilities.MIN_LENGTH +
454 BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Param len
455 message.writeByte(
456 BgpConstants.Open.Capabilities.MultiprotocolExtensions.CODE); // Capab. code
457 message.writeByte(
458 BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Capab. len
459 message.writeShort(
460 BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800461 message.writeByte(0); // Reserved field
Jonathan Hart41349e92015-02-09 14:14:02 -0800462 message.writeByte(
463 BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_MULTICAST);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800464 }
465 // IPv6 unicast
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800466 if (localInfo.ipv6Unicast()) {
Jonathan Hart41349e92015-02-09 14:14:02 -0800467 message.writeByte(BgpConstants.Open.Capabilities.TYPE); // Param type
468 message.writeByte(BgpConstants.Open.Capabilities.MIN_LENGTH +
469 BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Param len
470 message.writeByte(
471 BgpConstants.Open.Capabilities.MultiprotocolExtensions.CODE); // Capab. code
472 message.writeByte(
473 BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Capab. len
474 message.writeShort(
475 BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800476 message.writeByte(0); // Reserved field
Jonathan Hart41349e92015-02-09 14:14:02 -0800477 message.writeByte(
478 BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_UNICAST);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800479 }
480 // IPv6 multicast
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800481 if (localInfo.ipv6Multicast()) {
Jonathan Hart41349e92015-02-09 14:14:02 -0800482 message.writeByte(BgpConstants.Open.Capabilities.TYPE); // Param type
483 message.writeByte(BgpConstants.Open.Capabilities.MIN_LENGTH +
484 BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Param len
485 message.writeByte(
486 BgpConstants.Open.Capabilities.MultiprotocolExtensions.CODE); // Capab. code
487 message.writeByte(
488 BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Capab. len
489 message.writeShort(
490 BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800491 message.writeByte(0); // Reserved field
Jonathan Hart41349e92015-02-09 14:14:02 -0800492 message.writeByte(
493 BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_MULTICAST);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800494 }
495
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900496 // 4 octet AS path capability
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800497 if (localInfo.as4OctetCapability()) {
Jonathan Hart41349e92015-02-09 14:14:02 -0800498 message.writeByte(BgpConstants.Open.Capabilities.TYPE); // Param type
499 message.writeByte(BgpConstants.Open.Capabilities.MIN_LENGTH +
500 BgpConstants.Open.Capabilities.As4Octet.LENGTH); // Param len
501 message.writeByte(BgpConstants.Open.Capabilities.As4Octet.CODE); // Capab. code
502 message.writeByte(BgpConstants.Open.Capabilities.As4Octet.LENGTH); // Capab. len
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800503 message.writeInt((int) localInfo.as4Number());
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900504 }
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800505 return message;
506 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800507}