blob: d15a6698619c782a31aca1be45219d843c012cf8 [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();
104 //
105 // Verify that the AS number is same for all other BGP Sessions
106 // NOTE: This check applies only for our use-case where all BGP
107 // sessions are iBGP.
108 //
109 for (BgpSession bs : bgpSession.getBgpSessionManager().getBgpSessions()) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800110 if ((bs.remoteInfo().asNumber() != 0) &&
111 (remoteAs != bs.remoteInfo().asNumber())) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800112 log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
113 "Expected {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800114 bgpSession.remoteInfo().address(), remoteAs,
115 bs.remoteInfo().asNumber());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800116 //
117 // ERROR: Bad Peer AS
118 //
119 // Send NOTIFICATION and close the connection
120 int errorCode = OpenMessageError.ERROR_CODE;
121 int errorSubcode = OpenMessageError.BAD_PEER_AS;
122 ChannelBuffer txMessage =
123 BgpNotification.prepareBgpNotification(errorCode,
124 errorSubcode, null);
125 ctx.getChannel().write(txMessage);
126 bgpSession.closeSession(ctx);
127 return;
128 }
129 }
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800130 bgpSession.remoteInfo().setAsNumber(remoteAs);
131 //
132 // NOTE: Currently, the local AS number is always set to the remote AS.
133 // This is done, because the peer setup is always iBGP.
134 // In the future, the local AS number should be configured as part
135 // of an explicit BGP peering configuration.
136 //
137 bgpSession.localInfo().setAsNumber(remoteAs);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800138
139 // Remote Hold Time
140 long remoteHoldtime = message.readUnsignedShort();
141 if ((remoteHoldtime != 0) &&
142 (remoteHoldtime < BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME)) {
143 log.debug("BGP RX OPEN Error from {}: " +
144 "Unacceptable Hold Time field {}. " +
145 "Should be 0 or at least {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800146 bgpSession.remoteInfo().address(), remoteHoldtime,
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800147 BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME);
148 //
149 // ERROR: Unacceptable Hold Time
150 //
151 // Send NOTIFICATION and close the connection
152 int errorCode = OpenMessageError.ERROR_CODE;
153 int errorSubcode = OpenMessageError.UNACCEPTABLE_HOLD_TIME;
154 ChannelBuffer txMessage =
155 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
156 null);
157 ctx.getChannel().write(txMessage);
158 bgpSession.closeSession(ctx);
159 return;
160 }
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800161 bgpSession.remoteInfo().setHoldtime(remoteHoldtime);
162 //
163 // NOTE: Currently. the local BGP Holdtime is always set to the remote
164 // BGP holdtime.
165 // In the future, the local BGP Holdtime should be configured as part
166 // of an explicit BGP peering configuration.
167 //
168 bgpSession.localInfo().setHoldtime(remoteHoldtime);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800169
170 // Remote BGP Identifier
171 Ip4Address remoteBgpId =
172 Ip4Address.valueOf((int) message.readUnsignedInt());
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800173 bgpSession.remoteInfo().setBgpId(remoteBgpId);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800174
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800175 // Parse the Optional Parameters
176 try {
177 parseOptionalParameters(bgpSession, ctx, message);
178 } catch (BgpParseException e) {
179 // ERROR: Error parsing optional parameters
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800180 log.debug("BGP RX OPEN Error from {}: " +
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800181 "Exception parsing Optional Parameters: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800182 bgpSession.remoteInfo().address(), e);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800183 //
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800184 // ERROR: Invalid Optional Parameters: Unspecific
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800185 //
186 // Send NOTIFICATION and close the connection
187 int errorCode = OpenMessageError.ERROR_CODE;
188 int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
189 ChannelBuffer txMessage =
190 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
191 null);
192 ctx.getChannel().write(txMessage);
193 bgpSession.closeSession(ctx);
194 return;
195 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800196
197 log.debug("BGP RX OPEN message from {}: " +
198 "BGPv{} AS {} BGP-ID {} Holdtime {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800199 bgpSession.remoteInfo().address(), remoteBgpVersion,
200 remoteAs, remoteBgpId, remoteHoldtime);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800201
202 // Send my OPEN followed by KEEPALIVE
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800203 ChannelBuffer txMessage = prepareBgpOpen(bgpSession.localInfo());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800204 ctx.getChannel().write(txMessage);
205 //
206 txMessage = BgpKeepalive.prepareBgpKeepalive();
207 ctx.getChannel().write(txMessage);
208
209 // Start the KEEPALIVE timer
210 bgpSession.restartKeepaliveTimer(ctx);
211
212 // Start the Session Timeout timer
213 bgpSession.restartSessionTimeoutTimer(ctx);
214 }
215
216 /**
217 * Prepares BGP OPEN message.
218 *
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800219 * @param localInfo the BGP Session local information to use
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800220 * @return the message to transmit (BGP header included)
221 */
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800222 private static ChannelBuffer prepareBgpOpen(BgpSessionInfo localInfo) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800223 ChannelBuffer message =
224 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
225
226 //
227 // Prepare the OPEN message payload
228 //
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800229 message.writeByte(localInfo.bgpVersion());
230 message.writeShort((int) localInfo.asNumber());
231 message.writeShort((int) localInfo.holdtime());
232 message.writeInt(localInfo.bgpId().toInt());
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800233
234 // Prepare the optional BGP Capabilities
235 ChannelBuffer capabilitiesMessage =
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800236 prepareBgpOpenCapabilities(localInfo);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800237 message.writeByte(capabilitiesMessage.readableBytes());
238 message.writeBytes(capabilitiesMessage);
239
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800240 return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN,
241 message);
242 }
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800243
244 /**
245 * Parses BGP OPEN Optional Parameters.
246 *
247 * @param bgpSession the BGP Session to use
248 * @param ctx the Channel Handler Context
249 * @param message the message to process
250 * @throws BgpParseException
251 */
252 private static void parseOptionalParameters(BgpSession bgpSession,
253 ChannelHandlerContext ctx,
254 ChannelBuffer message)
255 throws BgpParseException {
256
257 //
258 // Get and verify the Optional Parameters Length
259 //
260 int optParamLength = message.readUnsignedByte();
261 if (optParamLength > message.readableBytes()) {
262 // ERROR: Invalid Optional Parameter Length
263 String errorMsg = "Invalid Optional Parameter Length field " +
264 optParamLength + ". Remaining Optional Parameters " +
265 message.readableBytes();
266 throw new BgpParseException(errorMsg);
267 }
268 if (optParamLength == 0) {
269 return; // No Optional Parameters
270 }
271
272 //
273 // Parse the Optional Parameters
274 //
275 int optParamEnd = message.readerIndex() + optParamLength;
276 while (message.readerIndex() < optParamEnd) {
277 int paramType = message.readUnsignedByte();
278 if (message.readerIndex() >= optParamEnd) {
279 // ERROR: Malformed Optional Parameters
280 String errorMsg = "Malformed Optional Parameters";
281 throw new BgpParseException(errorMsg);
282 }
283 int paramLen = message.readUnsignedByte();
284 if (message.readerIndex() + paramLen > optParamEnd) {
285 // ERROR: Malformed Optional Parameters
286 String errorMsg = "Malformed Optional Parameters";
287 throw new BgpParseException(errorMsg);
288 }
289
290 //
291 // Extract the Optional Parameter Value based on the Parameter Type
292 //
293 switch (paramType) {
294 case Capabilities.TYPE:
295 // Optional Parameter Type: Capabilities
296 if (paramLen < Capabilities.MIN_LENGTH) {
297 // ERROR: Malformed Capability
298 String errorMsg = "Malformed Capability Type " + paramType;
299 throw new BgpParseException(errorMsg);
300 }
301 int capabEnd = message.readerIndex() + paramLen;
302 int capabCode = message.readUnsignedByte();
303 int capabLen = message.readUnsignedByte();
304 if (message.readerIndex() + capabLen > capabEnd) {
305 // ERROR: Malformed Capability
306 String errorMsg = "Malformed Capability Type " + paramType;
307 throw new BgpParseException(errorMsg);
308 }
309
310 switch (capabCode) {
311 case MultiprotocolExtensions.CODE:
312 // Multiprotocol Extensions Capabilities (RFC 4760)
313 if (capabLen != MultiprotocolExtensions.LENGTH) {
314 // ERROR: Multiprotocol Extension Length Error
315 String errorMsg = "Multiprotocol Extension Length Error";
316 throw new BgpParseException(errorMsg);
317 }
318 // Decode the AFI (2 octets) and SAFI (1 octet)
319 int afi = message.readUnsignedShort();
320 int reserved = message.readUnsignedByte();
321 int safi = message.readUnsignedByte();
322 log.debug("BGP RX OPEN Capability: AFI = {} SAFI = {}",
323 afi, safi);
324 //
325 // Setup the AFI/SAFI in the BgpSession
326 //
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800327 // NOTE: For now we just copy the remote AFI/SAFI setting
328 // to the local configuration.
329 //
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800330 if (afi == MultiprotocolExtensions.AFI_IPV4 &&
331 safi == MultiprotocolExtensions.SAFI_UNICAST) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800332 bgpSession.remoteInfo().setIpv4Unicast();
333 bgpSession.localInfo().setIpv4Unicast();
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800334 } else if (afi == MultiprotocolExtensions.AFI_IPV4 &&
335 safi == MultiprotocolExtensions.SAFI_MULTICAST) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800336 bgpSession.remoteInfo().setIpv4Multicast();
337 bgpSession.localInfo().setIpv4Multicast();
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800338 } else if (afi == MultiprotocolExtensions.AFI_IPV6 &&
339 safi == MultiprotocolExtensions.SAFI_UNICAST) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800340 bgpSession.remoteInfo().setIpv6Unicast();
341 bgpSession.localInfo().setIpv6Unicast();
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800342 } else if (afi == MultiprotocolExtensions.AFI_IPV6 &&
343 safi == MultiprotocolExtensions.SAFI_MULTICAST) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800344 bgpSession.remoteInfo().setIpv6Multicast();
345 bgpSession.localInfo().setIpv6Multicast();
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800346 } else {
347 log.debug("BGP RX OPEN Capability: Unknown AFI = {} SAFI = {}",
348 afi, safi);
349 }
350 break;
351
352 case Capabilities.As4Octet.CODE:
353 // Support for 4-octet AS Number Capabilities (RFC 6793)
354 if (capabLen != Capabilities.As4Octet.LENGTH) {
355 // ERROR: 4-octet AS Number Capability Length Error
356 String errorMsg = "4-octet AS Number Capability Length Error";
357 throw new BgpParseException(errorMsg);
358 }
359 long as4Number = message.readUnsignedInt();
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900360
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800361 bgpSession.remoteInfo().setAs4OctetCapability();
362 bgpSession.remoteInfo().setAs4Number(as4Number);
363 // Use the 4-octet AS number in lieu of the "My AS" field
364 // See RFC 6793, Section 4.1, second paragraph.
365 bgpSession.remoteInfo().setAsNumber(as4Number);
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900366
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800367 //
368 // Copy remote 4-octet AS Number Capabilities and AS
369 // Number. This is a temporary setting until local AS
370 // number configuration is supported.
371 //
372 bgpSession.localInfo().setAs4OctetCapability();
373 bgpSession.localInfo().setAs4Number(as4Number);
374 bgpSession.localInfo().setAsNumber(as4Number);
375 log.debug("BGP RX OPEN Capability: AS4 Number = {}",
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800376 as4Number);
377 break;
378
379 default:
380 // Unknown Capability: ignore it
381 log.debug("BGP RX OPEN Capability Code = {} Length = {}",
382 capabCode, capabLen);
383 message.readBytes(capabLen);
384 break;
385 }
386
387 break;
388
389 default:
390 // Unknown Parameter Type: ignore it
391 log.debug("BGP RX OPEN Parameter Type = {} Length = {}",
392 paramType, paramLen);
393 message.readBytes(paramLen);
394 break;
395 }
396 }
397 }
398
399 /**
400 * Prepares the Capabilities for the BGP OPEN message.
401 *
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800402 * @param localInfo the BGP Session local information to use
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800403 * @return the buffer with the BGP Capabilities to transmit
404 */
405 private static ChannelBuffer prepareBgpOpenCapabilities(
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800406 BgpSessionInfo localInfo) {
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800407 ChannelBuffer message =
408 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
409
410 //
411 // Write the Multiprotocol Extensions Capabilities
412 //
413
414 // IPv4 unicast
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800415 if (localInfo.ipv4Unicast()) {
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800416 message.writeByte(Capabilities.TYPE); // Param type
417 message.writeByte(Capabilities.MIN_LENGTH +
418 MultiprotocolExtensions.LENGTH); // Param len
419 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
420 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
421 message.writeShort(MultiprotocolExtensions.AFI_IPV4);
422 message.writeByte(0); // Reserved field
423 message.writeByte(MultiprotocolExtensions.SAFI_UNICAST);
424 }
425 // IPv4 multicast
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800426 if (localInfo.ipv4Multicast()) {
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800427 message.writeByte(Capabilities.TYPE); // Param type
428 message.writeByte(Capabilities.MIN_LENGTH +
429 MultiprotocolExtensions.LENGTH); // Param len
430 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
431 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
432 message.writeShort(MultiprotocolExtensions.AFI_IPV4);
433 message.writeByte(0); // Reserved field
434 message.writeByte(MultiprotocolExtensions.SAFI_MULTICAST);
435 }
436 // IPv6 unicast
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800437 if (localInfo.ipv6Unicast()) {
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800438 message.writeByte(Capabilities.TYPE); // Param type
439 message.writeByte(Capabilities.MIN_LENGTH +
440 MultiprotocolExtensions.LENGTH); // Param len
441 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
442 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
443 message.writeShort(MultiprotocolExtensions.AFI_IPV6);
444 message.writeByte(0); // Reserved field
445 message.writeByte(MultiprotocolExtensions.SAFI_UNICAST);
446 }
447 // IPv6 multicast
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800448 if (localInfo.ipv6Multicast()) {
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800449 message.writeByte(Capabilities.TYPE); // Param type
450 message.writeByte(Capabilities.MIN_LENGTH +
451 MultiprotocolExtensions.LENGTH); // Param len
452 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
453 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
454 message.writeShort(MultiprotocolExtensions.AFI_IPV6);
455 message.writeByte(0); // Reserved field
456 message.writeByte(MultiprotocolExtensions.SAFI_MULTICAST);
457 }
458
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900459 // 4 octet AS path capability
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800460 if (localInfo.as4OctetCapability()) {
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900461 message.writeByte(Capabilities.TYPE); // Param type
462 message.writeByte(Capabilities.MIN_LENGTH +
463 As4Octet.LENGTH); // Param len
464 message.writeByte(As4Octet.CODE); // Capab, code
465 message.writeByte(As4Octet.LENGTH); // Capab, len
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800466 message.writeInt((int) localInfo.as4Number());
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900467 }
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800468 return message;
469 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800470}