blob: 93ef852c127e3f54974783b15c851650088d939a [file] [log] [blame]
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001/*
2 * Copyright 2014 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 */
16package org.onosproject.sdnip.bgp;
17
18import org.jboss.netty.buffer.ChannelBuffer;
19import org.jboss.netty.buffer.ChannelBuffers;
20import org.jboss.netty.channel.ChannelHandlerContext;
21import org.onlab.packet.Ip4Address;
22import org.onosproject.sdnip.bgp.BgpConstants.Notifications;
23import org.onosproject.sdnip.bgp.BgpConstants.Notifications.OpenMessageError;
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -080024import org.onosproject.sdnip.bgp.BgpConstants.Open.Capabilities;
25import org.onosproject.sdnip.bgp.BgpConstants.Open.Capabilities.MultiprotocolExtensions;
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +090026import org.onosproject.sdnip.bgp.BgpConstants.Open.Capabilities.As4Octet;
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -080027import org.onosproject.sdnip.bgp.BgpMessage.BgpParseException;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080028import org.slf4j.Logger;
29import org.slf4j.LoggerFactory;
30
31/**
32 * A class for handling BGP OPEN messages.
33 */
34final class BgpOpen {
35 private static final Logger log = LoggerFactory.getLogger(BgpOpen.class);
36
37 /**
38 * Default constructor.
39 * <p>
40 * The constructor is private to prevent creating an instance of
41 * this utility class.
42 */
43 private BgpOpen() {
44 }
45
46 /**
47 * Processes BGP OPEN message.
48 *
49 * @param bgpSession the BGP Session to use
50 * @param ctx the Channel Handler Context
51 * @param message the message to process
52 */
53 static void processBgpOpen(BgpSession bgpSession,
54 ChannelHandlerContext ctx,
55 ChannelBuffer message) {
56 int minLength =
57 BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
58 if (message.readableBytes() < minLength) {
59 log.debug("BGP RX OPEN Error from {}: " +
60 "Message length {} too short. Must be at least {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -080061 bgpSession.remoteInfo().address(),
62 message.readableBytes(), minLength);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080063 //
64 // ERROR: Bad Message Length
65 //
66 // Send NOTIFICATION and close the connection
67 ChannelBuffer txMessage =
68 BgpNotification.prepareBgpNotificationBadMessageLength(
69 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
70 ctx.getChannel().write(txMessage);
71 bgpSession.closeSession(ctx);
72 return;
73 }
74
75 //
76 // Parse the OPEN message
77 //
78 // Remote BGP version
79 int remoteBgpVersion = message.readUnsignedByte();
80 if (remoteBgpVersion != BgpConstants.BGP_VERSION) {
81 log.debug("BGP RX OPEN Error from {}: " +
82 "Unsupported BGP version {}. Should be {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -080083 bgpSession.remoteInfo().address(), remoteBgpVersion,
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080084 BgpConstants.BGP_VERSION);
85 //
86 // ERROR: Unsupported Version Number
87 //
88 // Send NOTIFICATION and close the connection
89 int errorCode = OpenMessageError.ERROR_CODE;
90 int errorSubcode = OpenMessageError.UNSUPPORTED_VERSION_NUMBER;
91 ChannelBuffer data = ChannelBuffers.buffer(2);
92 data.writeShort(BgpConstants.BGP_VERSION);
93 ChannelBuffer txMessage =
94 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
95 data);
96 ctx.getChannel().write(txMessage);
97 bgpSession.closeSession(ctx);
98 return;
99 }
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800100 bgpSession.remoteInfo().setBgpVersion(remoteBgpVersion);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800101
102 // Remote AS number
103 long remoteAs = message.readUnsignedShort();
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800104 bgpSession.remoteInfo().setAsNumber(remoteAs);
105 //
106 // NOTE: Currently, the local AS number is always set to the remote AS.
107 // This is done, because the peer setup is always iBGP.
108 // In the future, the local AS number should be configured as part
109 // of an explicit BGP peering configuration.
110 //
111 bgpSession.localInfo().setAsNumber(remoteAs);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800112
113 // Remote Hold Time
114 long remoteHoldtime = message.readUnsignedShort();
115 if ((remoteHoldtime != 0) &&
116 (remoteHoldtime < BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME)) {
117 log.debug("BGP RX OPEN Error from {}: " +
118 "Unacceptable Hold Time field {}. " +
119 "Should be 0 or at least {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800120 bgpSession.remoteInfo().address(), remoteHoldtime,
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800121 BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME);
122 //
123 // ERROR: Unacceptable Hold Time
124 //
125 // Send NOTIFICATION and close the connection
126 int errorCode = OpenMessageError.ERROR_CODE;
127 int errorSubcode = OpenMessageError.UNACCEPTABLE_HOLD_TIME;
128 ChannelBuffer txMessage =
129 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
130 null);
131 ctx.getChannel().write(txMessage);
132 bgpSession.closeSession(ctx);
133 return;
134 }
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800135 bgpSession.remoteInfo().setHoldtime(remoteHoldtime);
136 //
137 // NOTE: Currently. the local BGP Holdtime is always set to the remote
138 // BGP holdtime.
139 // In the future, the local BGP Holdtime should be configured as part
140 // of an explicit BGP peering configuration.
141 //
142 bgpSession.localInfo().setHoldtime(remoteHoldtime);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800143
144 // Remote BGP Identifier
145 Ip4Address remoteBgpId =
146 Ip4Address.valueOf((int) message.readUnsignedInt());
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800147 bgpSession.remoteInfo().setBgpId(remoteBgpId);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800148
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800149 // Parse the Optional Parameters
150 try {
151 parseOptionalParameters(bgpSession, ctx, message);
152 } catch (BgpParseException e) {
153 // ERROR: Error parsing optional parameters
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800154 log.debug("BGP RX OPEN Error from {}: " +
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800155 "Exception parsing Optional Parameters: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800156 bgpSession.remoteInfo().address(), e);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800157 //
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800158 // ERROR: Invalid Optional Parameters: Unspecific
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800159 //
160 // Send NOTIFICATION and close the connection
161 int errorCode = OpenMessageError.ERROR_CODE;
162 int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
163 ChannelBuffer txMessage =
164 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
165 null);
166 ctx.getChannel().write(txMessage);
167 bgpSession.closeSession(ctx);
168 return;
169 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800170
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800171 //
172 // NOTE: Prepare the BGP OPEN message before the original local AS
173 // is overwritten by the 4-octet AS number
174 //
175 ChannelBuffer txOpenMessage = prepareBgpOpen(bgpSession.localInfo());
176
177 //
178 // Use the 4-octet AS number in lieu of the "My AS" field
179 // See RFC 6793, Section 4.1, second paragraph.
180 //
181 if (bgpSession.remoteInfo().as4OctetCapability()) {
182 long as4Number = bgpSession.remoteInfo().as4Number();
183 bgpSession.remoteInfo().setAsNumber(as4Number);
184 bgpSession.localInfo().setAsNumber(as4Number);
185 }
186
187 //
188 // Verify that the AS number is same for all other BGP Sessions
189 // NOTE: This check applies only for our use-case where all BGP
190 // sessions are iBGP.
191 //
192 for (BgpSession bs : bgpSession.getBgpSessionManager().getBgpSessions()) {
193 if ((bs.remoteInfo().asNumber() != 0) &&
194 (bgpSession.remoteInfo().asNumber() !=
195 bs.remoteInfo().asNumber())) {
196 log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
197 "Expected {}",
198 bgpSession.remoteInfo().address(),
199 bgpSession.remoteInfo().asNumber(),
200 bs.remoteInfo().asNumber());
201 //
202 // ERROR: Bad Peer AS
203 //
204 // Send NOTIFICATION and close the connection
205 int errorCode = OpenMessageError.ERROR_CODE;
206 int errorSubcode = OpenMessageError.BAD_PEER_AS;
207 ChannelBuffer txMessage =
208 BgpNotification.prepareBgpNotification(errorCode,
209 errorSubcode, null);
210 ctx.getChannel().write(txMessage);
211 bgpSession.closeSession(ctx);
212 return;
213 }
214 }
215
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800216 log.debug("BGP RX OPEN message from {}: " +
217 "BGPv{} AS {} BGP-ID {} Holdtime {}",
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800218 bgpSession.remoteInfo().address(),
219 bgpSession.remoteInfo().bgpVersion(),
220 bgpSession.remoteInfo().asNumber(),
221 bgpSession.remoteInfo().bgpId(),
222 bgpSession.remoteInfo().holdtime());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800223
224 // Send my OPEN followed by KEEPALIVE
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800225 ctx.getChannel().write(txOpenMessage);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800226 //
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800227 ChannelBuffer txMessage = BgpKeepalive.prepareBgpKeepalive();
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800228 ctx.getChannel().write(txMessage);
229
230 // Start the KEEPALIVE timer
231 bgpSession.restartKeepaliveTimer(ctx);
232
233 // Start the Session Timeout timer
234 bgpSession.restartSessionTimeoutTimer(ctx);
235 }
236
237 /**
238 * Prepares BGP OPEN message.
239 *
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800240 * @param localInfo the BGP Session local information to use
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800241 * @return the message to transmit (BGP header included)
242 */
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800243 static ChannelBuffer prepareBgpOpen(BgpSessionInfo localInfo) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800244 ChannelBuffer message =
245 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
246
247 //
248 // Prepare the OPEN message payload
249 //
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800250 message.writeByte(localInfo.bgpVersion());
251 message.writeShort((int) localInfo.asNumber());
252 message.writeShort((int) localInfo.holdtime());
253 message.writeInt(localInfo.bgpId().toInt());
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800254
255 // Prepare the optional BGP Capabilities
256 ChannelBuffer capabilitiesMessage =
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800257 prepareBgpOpenCapabilities(localInfo);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800258 message.writeByte(capabilitiesMessage.readableBytes());
259 message.writeBytes(capabilitiesMessage);
260
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800261 return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN,
262 message);
263 }
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800264
265 /**
266 * Parses BGP OPEN Optional Parameters.
267 *
268 * @param bgpSession the BGP Session to use
269 * @param ctx the Channel Handler Context
270 * @param message the message to process
271 * @throws BgpParseException
272 */
273 private static void parseOptionalParameters(BgpSession bgpSession,
274 ChannelHandlerContext ctx,
275 ChannelBuffer message)
276 throws BgpParseException {
277
278 //
279 // Get and verify the Optional Parameters Length
280 //
281 int optParamLength = message.readUnsignedByte();
282 if (optParamLength > message.readableBytes()) {
283 // ERROR: Invalid Optional Parameter Length
284 String errorMsg = "Invalid Optional Parameter Length field " +
285 optParamLength + ". Remaining Optional Parameters " +
286 message.readableBytes();
287 throw new BgpParseException(errorMsg);
288 }
289 if (optParamLength == 0) {
290 return; // No Optional Parameters
291 }
292
293 //
294 // Parse the Optional Parameters
295 //
296 int optParamEnd = message.readerIndex() + optParamLength;
297 while (message.readerIndex() < optParamEnd) {
298 int paramType = message.readUnsignedByte();
299 if (message.readerIndex() >= optParamEnd) {
300 // ERROR: Malformed Optional Parameters
301 String errorMsg = "Malformed Optional Parameters";
302 throw new BgpParseException(errorMsg);
303 }
304 int paramLen = message.readUnsignedByte();
305 if (message.readerIndex() + paramLen > optParamEnd) {
306 // ERROR: Malformed Optional Parameters
307 String errorMsg = "Malformed Optional Parameters";
308 throw new BgpParseException(errorMsg);
309 }
310
311 //
312 // Extract the Optional Parameter Value based on the Parameter Type
313 //
314 switch (paramType) {
315 case Capabilities.TYPE:
316 // Optional Parameter Type: Capabilities
317 if (paramLen < Capabilities.MIN_LENGTH) {
318 // ERROR: Malformed Capability
319 String errorMsg = "Malformed Capability Type " + paramType;
320 throw new BgpParseException(errorMsg);
321 }
322 int capabEnd = message.readerIndex() + paramLen;
323 int capabCode = message.readUnsignedByte();
324 int capabLen = message.readUnsignedByte();
325 if (message.readerIndex() + capabLen > capabEnd) {
326 // ERROR: Malformed Capability
327 String errorMsg = "Malformed Capability Type " + paramType;
328 throw new BgpParseException(errorMsg);
329 }
330
331 switch (capabCode) {
332 case MultiprotocolExtensions.CODE:
333 // Multiprotocol Extensions Capabilities (RFC 4760)
334 if (capabLen != MultiprotocolExtensions.LENGTH) {
335 // ERROR: Multiprotocol Extension Length Error
336 String errorMsg = "Multiprotocol Extension Length Error";
337 throw new BgpParseException(errorMsg);
338 }
339 // Decode the AFI (2 octets) and SAFI (1 octet)
340 int afi = message.readUnsignedShort();
341 int reserved = message.readUnsignedByte();
342 int safi = message.readUnsignedByte();
343 log.debug("BGP RX OPEN Capability: AFI = {} SAFI = {}",
344 afi, safi);
345 //
346 // Setup the AFI/SAFI in the BgpSession
347 //
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800348 // NOTE: For now we just copy the remote AFI/SAFI setting
349 // to the local configuration.
350 //
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800351 if (afi == MultiprotocolExtensions.AFI_IPV4 &&
352 safi == MultiprotocolExtensions.SAFI_UNICAST) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800353 bgpSession.remoteInfo().setIpv4Unicast();
354 bgpSession.localInfo().setIpv4Unicast();
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800355 } else if (afi == MultiprotocolExtensions.AFI_IPV4 &&
356 safi == MultiprotocolExtensions.SAFI_MULTICAST) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800357 bgpSession.remoteInfo().setIpv4Multicast();
358 bgpSession.localInfo().setIpv4Multicast();
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800359 } else if (afi == MultiprotocolExtensions.AFI_IPV6 &&
360 safi == MultiprotocolExtensions.SAFI_UNICAST) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800361 bgpSession.remoteInfo().setIpv6Unicast();
362 bgpSession.localInfo().setIpv6Unicast();
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800363 } else if (afi == MultiprotocolExtensions.AFI_IPV6 &&
364 safi == MultiprotocolExtensions.SAFI_MULTICAST) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800365 bgpSession.remoteInfo().setIpv6Multicast();
366 bgpSession.localInfo().setIpv6Multicast();
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800367 } else {
368 log.debug("BGP RX OPEN Capability: Unknown AFI = {} SAFI = {}",
369 afi, safi);
370 }
371 break;
372
373 case Capabilities.As4Octet.CODE:
374 // Support for 4-octet AS Number Capabilities (RFC 6793)
375 if (capabLen != Capabilities.As4Octet.LENGTH) {
376 // ERROR: 4-octet AS Number Capability Length Error
377 String errorMsg = "4-octet AS Number Capability Length Error";
378 throw new BgpParseException(errorMsg);
379 }
380 long as4Number = message.readUnsignedInt();
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900381
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800382 bgpSession.remoteInfo().setAs4OctetCapability();
383 bgpSession.remoteInfo().setAs4Number(as4Number);
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900384
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800385 //
386 // Copy remote 4-octet AS Number Capabilities and AS
387 // Number. This is a temporary setting until local AS
388 // number configuration is supported.
389 //
390 bgpSession.localInfo().setAs4OctetCapability();
391 bgpSession.localInfo().setAs4Number(as4Number);
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800392 log.debug("BGP RX OPEN Capability: AS4 Number = {}",
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800393 as4Number);
394 break;
395
396 default:
397 // Unknown Capability: ignore it
398 log.debug("BGP RX OPEN Capability Code = {} Length = {}",
399 capabCode, capabLen);
400 message.readBytes(capabLen);
401 break;
402 }
403
404 break;
405
406 default:
407 // Unknown Parameter Type: ignore it
408 log.debug("BGP RX OPEN Parameter Type = {} Length = {}",
409 paramType, paramLen);
410 message.readBytes(paramLen);
411 break;
412 }
413 }
414 }
415
416 /**
417 * Prepares the Capabilities for the BGP OPEN message.
418 *
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800419 * @param localInfo the BGP Session local information to use
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800420 * @return the buffer with the BGP Capabilities to transmit
421 */
422 private static ChannelBuffer prepareBgpOpenCapabilities(
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800423 BgpSessionInfo localInfo) {
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800424 ChannelBuffer message =
425 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
426
427 //
428 // Write the Multiprotocol Extensions Capabilities
429 //
430
431 // IPv4 unicast
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800432 if (localInfo.ipv4Unicast()) {
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800433 message.writeByte(Capabilities.TYPE); // Param type
434 message.writeByte(Capabilities.MIN_LENGTH +
435 MultiprotocolExtensions.LENGTH); // Param len
436 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
437 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
438 message.writeShort(MultiprotocolExtensions.AFI_IPV4);
439 message.writeByte(0); // Reserved field
440 message.writeByte(MultiprotocolExtensions.SAFI_UNICAST);
441 }
442 // IPv4 multicast
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800443 if (localInfo.ipv4Multicast()) {
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800444 message.writeByte(Capabilities.TYPE); // Param type
445 message.writeByte(Capabilities.MIN_LENGTH +
446 MultiprotocolExtensions.LENGTH); // Param len
447 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
448 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
449 message.writeShort(MultiprotocolExtensions.AFI_IPV4);
450 message.writeByte(0); // Reserved field
451 message.writeByte(MultiprotocolExtensions.SAFI_MULTICAST);
452 }
453 // IPv6 unicast
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800454 if (localInfo.ipv6Unicast()) {
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800455 message.writeByte(Capabilities.TYPE); // Param type
456 message.writeByte(Capabilities.MIN_LENGTH +
457 MultiprotocolExtensions.LENGTH); // Param len
458 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
459 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
460 message.writeShort(MultiprotocolExtensions.AFI_IPV6);
461 message.writeByte(0); // Reserved field
462 message.writeByte(MultiprotocolExtensions.SAFI_UNICAST);
463 }
464 // IPv6 multicast
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800465 if (localInfo.ipv6Multicast()) {
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800466 message.writeByte(Capabilities.TYPE); // Param type
467 message.writeByte(Capabilities.MIN_LENGTH +
468 MultiprotocolExtensions.LENGTH); // Param len
469 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
470 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
471 message.writeShort(MultiprotocolExtensions.AFI_IPV6);
472 message.writeByte(0); // Reserved field
473 message.writeByte(MultiprotocolExtensions.SAFI_MULTICAST);
474 }
475
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900476 // 4 octet AS path capability
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800477 if (localInfo.as4OctetCapability()) {
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900478 message.writeByte(Capabilities.TYPE); // Param type
479 message.writeByte(Capabilities.MIN_LENGTH +
480 As4Octet.LENGTH); // Param len
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800481 message.writeByte(As4Octet.CODE); // Capab. code
482 message.writeByte(As4Octet.LENGTH); // Capab. len
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800483 message.writeInt((int) localInfo.as4Number());
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900484 }
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800485 return message;
486 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800487}