blob: 31471a34428cf498c67cd1e6861bfd176fd8a180 [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 {}",
61 bgpSession.getRemoteAddress(), message.readableBytes(),
62 minLength);
63 //
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 {}",
83 bgpSession.getRemoteAddress(), remoteBgpVersion,
84 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 }
100 bgpSession.setRemoteBgpVersion(remoteBgpVersion);
101
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()) {
110 if ((bs.getRemoteAs() != 0) && (remoteAs != bs.getRemoteAs())) {
111 log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
112 "Expected {}",
113 bgpSession.getRemoteAddress(), remoteAs,
114 bs.getRemoteAs());
115 //
116 // ERROR: Bad Peer AS
117 //
118 // Send NOTIFICATION and close the connection
119 int errorCode = OpenMessageError.ERROR_CODE;
120 int errorSubcode = OpenMessageError.BAD_PEER_AS;
121 ChannelBuffer txMessage =
122 BgpNotification.prepareBgpNotification(errorCode,
123 errorSubcode, null);
124 ctx.getChannel().write(txMessage);
125 bgpSession.closeSession(ctx);
126 return;
127 }
128 }
129 bgpSession.setRemoteAs(remoteAs);
130
131 // Remote Hold Time
132 long remoteHoldtime = message.readUnsignedShort();
133 if ((remoteHoldtime != 0) &&
134 (remoteHoldtime < BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME)) {
135 log.debug("BGP RX OPEN Error from {}: " +
136 "Unacceptable Hold Time field {}. " +
137 "Should be 0 or at least {}",
138 bgpSession.getRemoteAddress(), remoteHoldtime,
139 BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME);
140 //
141 // ERROR: Unacceptable Hold Time
142 //
143 // Send NOTIFICATION and close the connection
144 int errorCode = OpenMessageError.ERROR_CODE;
145 int errorSubcode = OpenMessageError.UNACCEPTABLE_HOLD_TIME;
146 ChannelBuffer txMessage =
147 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
148 null);
149 ctx.getChannel().write(txMessage);
150 bgpSession.closeSession(ctx);
151 return;
152 }
153 bgpSession.setRemoteHoldtime(remoteHoldtime);
154
155 // Remote BGP Identifier
156 Ip4Address remoteBgpId =
157 Ip4Address.valueOf((int) message.readUnsignedInt());
158 bgpSession.setRemoteBgpId(remoteBgpId);
159
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800160 // Parse the Optional Parameters
161 try {
162 parseOptionalParameters(bgpSession, ctx, message);
163 } catch (BgpParseException e) {
164 // ERROR: Error parsing optional parameters
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800165 log.debug("BGP RX OPEN Error from {}: " +
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800166 "Exception parsing Optional Parameters: {}",
167 bgpSession.getRemoteAddress(), e);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800168 //
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800169 // ERROR: Invalid Optional Parameters: Unspecific
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800170 //
171 // Send NOTIFICATION and close the connection
172 int errorCode = OpenMessageError.ERROR_CODE;
173 int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
174 ChannelBuffer txMessage =
175 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
176 null);
177 ctx.getChannel().write(txMessage);
178 bgpSession.closeSession(ctx);
179 return;
180 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800181
182 log.debug("BGP RX OPEN message from {}: " +
183 "BGPv{} AS {} BGP-ID {} Holdtime {}",
184 bgpSession.getRemoteAddress(), remoteBgpVersion, remoteAs,
185 remoteBgpId, remoteHoldtime);
186
187 // Send my OPEN followed by KEEPALIVE
188 ChannelBuffer txMessage = prepareBgpOpen(bgpSession);
189 ctx.getChannel().write(txMessage);
190 //
191 txMessage = BgpKeepalive.prepareBgpKeepalive();
192 ctx.getChannel().write(txMessage);
193
194 // Start the KEEPALIVE timer
195 bgpSession.restartKeepaliveTimer(ctx);
196
197 // Start the Session Timeout timer
198 bgpSession.restartSessionTimeoutTimer(ctx);
199 }
200
201 /**
202 * Prepares BGP OPEN message.
203 *
204 * @param bgpSession the BGP Session to use
205 * @return the message to transmit (BGP header included)
206 */
207 private static ChannelBuffer prepareBgpOpen(BgpSession bgpSession) {
208 ChannelBuffer message =
209 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
210
211 //
212 // Prepare the OPEN message payload
213 //
214 message.writeByte(bgpSession.getLocalBgpVersion());
215 message.writeShort((int) bgpSession.getLocalAs());
216 message.writeShort((int) bgpSession.getLocalHoldtime());
217 message.writeInt(bgpSession.getLocalBgpId().toInt());
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800218
219 // Prepare the optional BGP Capabilities
220 ChannelBuffer capabilitiesMessage =
221 prepareBgpOpenCapabilities(bgpSession);
222 message.writeByte(capabilitiesMessage.readableBytes());
223 message.writeBytes(capabilitiesMessage);
224
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800225 return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN,
226 message);
227 }
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800228
229 /**
230 * Parses BGP OPEN Optional Parameters.
231 *
232 * @param bgpSession the BGP Session to use
233 * @param ctx the Channel Handler Context
234 * @param message the message to process
235 * @throws BgpParseException
236 */
237 private static void parseOptionalParameters(BgpSession bgpSession,
238 ChannelHandlerContext ctx,
239 ChannelBuffer message)
240 throws BgpParseException {
241
242 //
243 // Get and verify the Optional Parameters Length
244 //
245 int optParamLength = message.readUnsignedByte();
246 if (optParamLength > message.readableBytes()) {
247 // ERROR: Invalid Optional Parameter Length
248 String errorMsg = "Invalid Optional Parameter Length field " +
249 optParamLength + ". Remaining Optional Parameters " +
250 message.readableBytes();
251 throw new BgpParseException(errorMsg);
252 }
253 if (optParamLength == 0) {
254 return; // No Optional Parameters
255 }
256
257 //
258 // Parse the Optional Parameters
259 //
260 int optParamEnd = message.readerIndex() + optParamLength;
261 while (message.readerIndex() < optParamEnd) {
262 int paramType = message.readUnsignedByte();
263 if (message.readerIndex() >= optParamEnd) {
264 // ERROR: Malformed Optional Parameters
265 String errorMsg = "Malformed Optional Parameters";
266 throw new BgpParseException(errorMsg);
267 }
268 int paramLen = message.readUnsignedByte();
269 if (message.readerIndex() + paramLen > optParamEnd) {
270 // ERROR: Malformed Optional Parameters
271 String errorMsg = "Malformed Optional Parameters";
272 throw new BgpParseException(errorMsg);
273 }
274
275 //
276 // Extract the Optional Parameter Value based on the Parameter Type
277 //
278 switch (paramType) {
279 case Capabilities.TYPE:
280 // Optional Parameter Type: Capabilities
281 if (paramLen < Capabilities.MIN_LENGTH) {
282 // ERROR: Malformed Capability
283 String errorMsg = "Malformed Capability Type " + paramType;
284 throw new BgpParseException(errorMsg);
285 }
286 int capabEnd = message.readerIndex() + paramLen;
287 int capabCode = message.readUnsignedByte();
288 int capabLen = message.readUnsignedByte();
289 if (message.readerIndex() + capabLen > capabEnd) {
290 // ERROR: Malformed Capability
291 String errorMsg = "Malformed Capability Type " + paramType;
292 throw new BgpParseException(errorMsg);
293 }
294
295 switch (capabCode) {
296 case MultiprotocolExtensions.CODE:
297 // Multiprotocol Extensions Capabilities (RFC 4760)
298 if (capabLen != MultiprotocolExtensions.LENGTH) {
299 // ERROR: Multiprotocol Extension Length Error
300 String errorMsg = "Multiprotocol Extension Length Error";
301 throw new BgpParseException(errorMsg);
302 }
303 // Decode the AFI (2 octets) and SAFI (1 octet)
304 int afi = message.readUnsignedShort();
305 int reserved = message.readUnsignedByte();
306 int safi = message.readUnsignedByte();
307 log.debug("BGP RX OPEN Capability: AFI = {} SAFI = {}",
308 afi, safi);
309 //
310 // Setup the AFI/SAFI in the BgpSession
311 //
312 if (afi == MultiprotocolExtensions.AFI_IPV4 &&
313 safi == MultiprotocolExtensions.SAFI_UNICAST) {
314 bgpSession.setRemoteIpv4Unicast();
315 } else if (afi == MultiprotocolExtensions.AFI_IPV4 &&
316 safi == MultiprotocolExtensions.SAFI_MULTICAST) {
317 bgpSession.setRemoteIpv4Multicast();
318 } else if (afi == MultiprotocolExtensions.AFI_IPV6 &&
319 safi == MultiprotocolExtensions.SAFI_UNICAST) {
320 bgpSession.setRemoteIpv6Unicast();
321 } else if (afi == MultiprotocolExtensions.AFI_IPV6 &&
322 safi == MultiprotocolExtensions.SAFI_MULTICAST) {
323 bgpSession.setRemoteIpv6Multicast();
324 } else {
325 log.debug("BGP RX OPEN Capability: Unknown AFI = {} SAFI = {}",
326 afi, safi);
327 }
328 break;
329
330 case Capabilities.As4Octet.CODE:
331 // Support for 4-octet AS Number Capabilities (RFC 6793)
332 if (capabLen != Capabilities.As4Octet.LENGTH) {
333 // ERROR: 4-octet AS Number Capability Length Error
334 String errorMsg = "4-octet AS Number Capability Length Error";
335 throw new BgpParseException(errorMsg);
336 }
337 long as4Number = message.readUnsignedInt();
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900338
339 bgpSession.setRemoteAs4OctetCapability();
Kunihiro Ishiguro828245c2014-12-18 17:54:18 +0900340 bgpSession.setRemoteAs4Octet(as4Number);
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900341
342 // Copy remote 4-octet AS Number Capabilities and AS Number.
343 // This is temporary setting until local AS number configuration is supported.
344 bgpSession.setLocalAs4OctetCapability();
345 bgpSession.setRemoteAs(as4Number);
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800346 log.debug("BGP RX OPEN Capability: AS4 Number = {}",
347 as4Number);
348 break;
349
350 default:
351 // Unknown Capability: ignore it
352 log.debug("BGP RX OPEN Capability Code = {} Length = {}",
353 capabCode, capabLen);
354 message.readBytes(capabLen);
355 break;
356 }
357
358 break;
359
360 default:
361 // Unknown Parameter Type: ignore it
362 log.debug("BGP RX OPEN Parameter Type = {} Length = {}",
363 paramType, paramLen);
364 message.readBytes(paramLen);
365 break;
366 }
367 }
368 }
369
370 /**
371 * Prepares the Capabilities for the BGP OPEN message.
372 *
373 * @param bgpSession the BGP Session to use
374 * @return the buffer with the BGP Capabilities to transmit
375 */
376 private static ChannelBuffer prepareBgpOpenCapabilities(
377 BgpSession bgpSession) {
378 ChannelBuffer message =
379 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
380
381 //
382 // Write the Multiprotocol Extensions Capabilities
383 //
384
385 // IPv4 unicast
386 if (bgpSession.getLocalIpv4Unicast()) {
387 message.writeByte(Capabilities.TYPE); // Param type
388 message.writeByte(Capabilities.MIN_LENGTH +
389 MultiprotocolExtensions.LENGTH); // Param len
390 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
391 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
392 message.writeShort(MultiprotocolExtensions.AFI_IPV4);
393 message.writeByte(0); // Reserved field
394 message.writeByte(MultiprotocolExtensions.SAFI_UNICAST);
395 }
396 // IPv4 multicast
397 if (bgpSession.getLocalIpv4Multicast()) {
398 message.writeByte(Capabilities.TYPE); // Param type
399 message.writeByte(Capabilities.MIN_LENGTH +
400 MultiprotocolExtensions.LENGTH); // Param len
401 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
402 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
403 message.writeShort(MultiprotocolExtensions.AFI_IPV4);
404 message.writeByte(0); // Reserved field
405 message.writeByte(MultiprotocolExtensions.SAFI_MULTICAST);
406 }
407 // IPv6 unicast
408 if (bgpSession.getLocalIpv6Unicast()) {
409 message.writeByte(Capabilities.TYPE); // Param type
410 message.writeByte(Capabilities.MIN_LENGTH +
411 MultiprotocolExtensions.LENGTH); // Param len
412 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
413 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
414 message.writeShort(MultiprotocolExtensions.AFI_IPV6);
415 message.writeByte(0); // Reserved field
416 message.writeByte(MultiprotocolExtensions.SAFI_UNICAST);
417 }
418 // IPv6 multicast
419 if (bgpSession.getLocalIpv6Multicast()) {
420 message.writeByte(Capabilities.TYPE); // Param type
421 message.writeByte(Capabilities.MIN_LENGTH +
422 MultiprotocolExtensions.LENGTH); // Param len
423 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
424 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
425 message.writeShort(MultiprotocolExtensions.AFI_IPV6);
426 message.writeByte(0); // Reserved field
427 message.writeByte(MultiprotocolExtensions.SAFI_MULTICAST);
428 }
429
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900430 // 4 octet AS path capability
431 if (bgpSession.getLocalAs4OctetCapability()) {
432 message.writeByte(Capabilities.TYPE); // Param type
433 message.writeByte(Capabilities.MIN_LENGTH +
434 As4Octet.LENGTH); // Param len
435 message.writeByte(As4Octet.CODE); // Capab, code
436 message.writeByte(As4Octet.LENGTH); // Capab, len
437 message.writeInt((int) bgpSession.getLocalAs());
438 }
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800439 return message;
440 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800441}