blob: a0b6f5e1cc6870953be45efc80980b04eb8d9616 [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;
26import org.onosproject.sdnip.bgp.BgpMessage.BgpParseException;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080027import org.slf4j.Logger;
28import org.slf4j.LoggerFactory;
29
30/**
31 * A class for handling BGP OPEN messages.
32 */
33final class BgpOpen {
34 private static final Logger log = LoggerFactory.getLogger(BgpOpen.class);
35
36 /**
37 * Default constructor.
38 * <p>
39 * The constructor is private to prevent creating an instance of
40 * this utility class.
41 */
42 private BgpOpen() {
43 }
44
45 /**
46 * Processes BGP OPEN message.
47 *
48 * @param bgpSession the BGP Session to use
49 * @param ctx the Channel Handler Context
50 * @param message the message to process
51 */
52 static void processBgpOpen(BgpSession bgpSession,
53 ChannelHandlerContext ctx,
54 ChannelBuffer message) {
55 int minLength =
56 BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
57 if (message.readableBytes() < minLength) {
58 log.debug("BGP RX OPEN Error from {}: " +
59 "Message length {} too short. Must be at least {}",
60 bgpSession.getRemoteAddress(), message.readableBytes(),
61 minLength);
62 //
63 // ERROR: Bad Message Length
64 //
65 // Send NOTIFICATION and close the connection
66 ChannelBuffer txMessage =
67 BgpNotification.prepareBgpNotificationBadMessageLength(
68 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
69 ctx.getChannel().write(txMessage);
70 bgpSession.closeSession(ctx);
71 return;
72 }
73
74 //
75 // Parse the OPEN message
76 //
77 // Remote BGP version
78 int remoteBgpVersion = message.readUnsignedByte();
79 if (remoteBgpVersion != BgpConstants.BGP_VERSION) {
80 log.debug("BGP RX OPEN Error from {}: " +
81 "Unsupported BGP version {}. Should be {}",
82 bgpSession.getRemoteAddress(), remoteBgpVersion,
83 BgpConstants.BGP_VERSION);
84 //
85 // ERROR: Unsupported Version Number
86 //
87 // Send NOTIFICATION and close the connection
88 int errorCode = OpenMessageError.ERROR_CODE;
89 int errorSubcode = OpenMessageError.UNSUPPORTED_VERSION_NUMBER;
90 ChannelBuffer data = ChannelBuffers.buffer(2);
91 data.writeShort(BgpConstants.BGP_VERSION);
92 ChannelBuffer txMessage =
93 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
94 data);
95 ctx.getChannel().write(txMessage);
96 bgpSession.closeSession(ctx);
97 return;
98 }
99 bgpSession.setRemoteBgpVersion(remoteBgpVersion);
100
101 // Remote AS number
102 long remoteAs = message.readUnsignedShort();
103 //
104 // Verify that the AS number is same for all other BGP Sessions
105 // NOTE: This check applies only for our use-case where all BGP
106 // sessions are iBGP.
107 //
108 for (BgpSession bs : bgpSession.getBgpSessionManager().getBgpSessions()) {
109 if ((bs.getRemoteAs() != 0) && (remoteAs != bs.getRemoteAs())) {
110 log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
111 "Expected {}",
112 bgpSession.getRemoteAddress(), remoteAs,
113 bs.getRemoteAs());
114 //
115 // ERROR: Bad Peer AS
116 //
117 // Send NOTIFICATION and close the connection
118 int errorCode = OpenMessageError.ERROR_CODE;
119 int errorSubcode = OpenMessageError.BAD_PEER_AS;
120 ChannelBuffer txMessage =
121 BgpNotification.prepareBgpNotification(errorCode,
122 errorSubcode, null);
123 ctx.getChannel().write(txMessage);
124 bgpSession.closeSession(ctx);
125 return;
126 }
127 }
128 bgpSession.setRemoteAs(remoteAs);
129
130 // Remote Hold Time
131 long remoteHoldtime = message.readUnsignedShort();
132 if ((remoteHoldtime != 0) &&
133 (remoteHoldtime < BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME)) {
134 log.debug("BGP RX OPEN Error from {}: " +
135 "Unacceptable Hold Time field {}. " +
136 "Should be 0 or at least {}",
137 bgpSession.getRemoteAddress(), remoteHoldtime,
138 BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME);
139 //
140 // ERROR: Unacceptable Hold Time
141 //
142 // Send NOTIFICATION and close the connection
143 int errorCode = OpenMessageError.ERROR_CODE;
144 int errorSubcode = OpenMessageError.UNACCEPTABLE_HOLD_TIME;
145 ChannelBuffer txMessage =
146 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
147 null);
148 ctx.getChannel().write(txMessage);
149 bgpSession.closeSession(ctx);
150 return;
151 }
152 bgpSession.setRemoteHoldtime(remoteHoldtime);
153
154 // Remote BGP Identifier
155 Ip4Address remoteBgpId =
156 Ip4Address.valueOf((int) message.readUnsignedInt());
157 bgpSession.setRemoteBgpId(remoteBgpId);
158
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800159 // Parse the Optional Parameters
160 try {
161 parseOptionalParameters(bgpSession, ctx, message);
162 } catch (BgpParseException e) {
163 // ERROR: Error parsing optional parameters
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800164 log.debug("BGP RX OPEN Error from {}: " +
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800165 "Exception parsing Optional Parameters: {}",
166 bgpSession.getRemoteAddress(), e);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800167 //
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800168 // ERROR: Invalid Optional Parameters: Unspecific
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800169 //
170 // Send NOTIFICATION and close the connection
171 int errorCode = OpenMessageError.ERROR_CODE;
172 int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
173 ChannelBuffer txMessage =
174 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
175 null);
176 ctx.getChannel().write(txMessage);
177 bgpSession.closeSession(ctx);
178 return;
179 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800180
181 log.debug("BGP RX OPEN message from {}: " +
182 "BGPv{} AS {} BGP-ID {} Holdtime {}",
183 bgpSession.getRemoteAddress(), remoteBgpVersion, remoteAs,
184 remoteBgpId, remoteHoldtime);
185
186 // Send my OPEN followed by KEEPALIVE
187 ChannelBuffer txMessage = prepareBgpOpen(bgpSession);
188 ctx.getChannel().write(txMessage);
189 //
190 txMessage = BgpKeepalive.prepareBgpKeepalive();
191 ctx.getChannel().write(txMessage);
192
193 // Start the KEEPALIVE timer
194 bgpSession.restartKeepaliveTimer(ctx);
195
196 // Start the Session Timeout timer
197 bgpSession.restartSessionTimeoutTimer(ctx);
198 }
199
200 /**
201 * Prepares BGP OPEN message.
202 *
203 * @param bgpSession the BGP Session to use
204 * @return the message to transmit (BGP header included)
205 */
206 private static ChannelBuffer prepareBgpOpen(BgpSession bgpSession) {
207 ChannelBuffer message =
208 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
209
210 //
211 // Prepare the OPEN message payload
212 //
213 message.writeByte(bgpSession.getLocalBgpVersion());
214 message.writeShort((int) bgpSession.getLocalAs());
215 message.writeShort((int) bgpSession.getLocalHoldtime());
216 message.writeInt(bgpSession.getLocalBgpId().toInt());
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800217
218 // Prepare the optional BGP Capabilities
219 ChannelBuffer capabilitiesMessage =
220 prepareBgpOpenCapabilities(bgpSession);
221 message.writeByte(capabilitiesMessage.readableBytes());
222 message.writeBytes(capabilitiesMessage);
223
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800224 return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN,
225 message);
226 }
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -0800227
228 /**
229 * Parses BGP OPEN Optional Parameters.
230 *
231 * @param bgpSession the BGP Session to use
232 * @param ctx the Channel Handler Context
233 * @param message the message to process
234 * @throws BgpParseException
235 */
236 private static void parseOptionalParameters(BgpSession bgpSession,
237 ChannelHandlerContext ctx,
238 ChannelBuffer message)
239 throws BgpParseException {
240
241 //
242 // Get and verify the Optional Parameters Length
243 //
244 int optParamLength = message.readUnsignedByte();
245 if (optParamLength > message.readableBytes()) {
246 // ERROR: Invalid Optional Parameter Length
247 String errorMsg = "Invalid Optional Parameter Length field " +
248 optParamLength + ". Remaining Optional Parameters " +
249 message.readableBytes();
250 throw new BgpParseException(errorMsg);
251 }
252 if (optParamLength == 0) {
253 return; // No Optional Parameters
254 }
255
256 //
257 // Parse the Optional Parameters
258 //
259 int optParamEnd = message.readerIndex() + optParamLength;
260 while (message.readerIndex() < optParamEnd) {
261 int paramType = message.readUnsignedByte();
262 if (message.readerIndex() >= optParamEnd) {
263 // ERROR: Malformed Optional Parameters
264 String errorMsg = "Malformed Optional Parameters";
265 throw new BgpParseException(errorMsg);
266 }
267 int paramLen = message.readUnsignedByte();
268 if (message.readerIndex() + paramLen > optParamEnd) {
269 // ERROR: Malformed Optional Parameters
270 String errorMsg = "Malformed Optional Parameters";
271 throw new BgpParseException(errorMsg);
272 }
273
274 //
275 // Extract the Optional Parameter Value based on the Parameter Type
276 //
277 switch (paramType) {
278 case Capabilities.TYPE:
279 // Optional Parameter Type: Capabilities
280 if (paramLen < Capabilities.MIN_LENGTH) {
281 // ERROR: Malformed Capability
282 String errorMsg = "Malformed Capability Type " + paramType;
283 throw new BgpParseException(errorMsg);
284 }
285 int capabEnd = message.readerIndex() + paramLen;
286 int capabCode = message.readUnsignedByte();
287 int capabLen = message.readUnsignedByte();
288 if (message.readerIndex() + capabLen > capabEnd) {
289 // ERROR: Malformed Capability
290 String errorMsg = "Malformed Capability Type " + paramType;
291 throw new BgpParseException(errorMsg);
292 }
293
294 switch (capabCode) {
295 case MultiprotocolExtensions.CODE:
296 // Multiprotocol Extensions Capabilities (RFC 4760)
297 if (capabLen != MultiprotocolExtensions.LENGTH) {
298 // ERROR: Multiprotocol Extension Length Error
299 String errorMsg = "Multiprotocol Extension Length Error";
300 throw new BgpParseException(errorMsg);
301 }
302 // Decode the AFI (2 octets) and SAFI (1 octet)
303 int afi = message.readUnsignedShort();
304 int reserved = message.readUnsignedByte();
305 int safi = message.readUnsignedByte();
306 log.debug("BGP RX OPEN Capability: AFI = {} SAFI = {}",
307 afi, safi);
308 //
309 // Setup the AFI/SAFI in the BgpSession
310 //
311 if (afi == MultiprotocolExtensions.AFI_IPV4 &&
312 safi == MultiprotocolExtensions.SAFI_UNICAST) {
313 bgpSession.setRemoteIpv4Unicast();
314 } else if (afi == MultiprotocolExtensions.AFI_IPV4 &&
315 safi == MultiprotocolExtensions.SAFI_MULTICAST) {
316 bgpSession.setRemoteIpv4Multicast();
317 } else if (afi == MultiprotocolExtensions.AFI_IPV6 &&
318 safi == MultiprotocolExtensions.SAFI_UNICAST) {
319 bgpSession.setRemoteIpv6Unicast();
320 } else if (afi == MultiprotocolExtensions.AFI_IPV6 &&
321 safi == MultiprotocolExtensions.SAFI_MULTICAST) {
322 bgpSession.setRemoteIpv6Multicast();
323 } else {
324 log.debug("BGP RX OPEN Capability: Unknown AFI = {} SAFI = {}",
325 afi, safi);
326 }
327 break;
328
329 case Capabilities.As4Octet.CODE:
330 // Support for 4-octet AS Number Capabilities (RFC 6793)
331 if (capabLen != Capabilities.As4Octet.LENGTH) {
332 // ERROR: 4-octet AS Number Capability Length Error
333 String errorMsg = "4-octet AS Number Capability Length Error";
334 throw new BgpParseException(errorMsg);
335 }
336 long as4Number = message.readUnsignedInt();
337 // TODO: Implement support for 4-octet AS Numbers
338 log.debug("BGP RX OPEN Capability: AS4 Number = {}",
339 as4Number);
340 break;
341
342 default:
343 // Unknown Capability: ignore it
344 log.debug("BGP RX OPEN Capability Code = {} Length = {}",
345 capabCode, capabLen);
346 message.readBytes(capabLen);
347 break;
348 }
349
350 break;
351
352 default:
353 // Unknown Parameter Type: ignore it
354 log.debug("BGP RX OPEN Parameter Type = {} Length = {}",
355 paramType, paramLen);
356 message.readBytes(paramLen);
357 break;
358 }
359 }
360 }
361
362 /**
363 * Prepares the Capabilities for the BGP OPEN message.
364 *
365 * @param bgpSession the BGP Session to use
366 * @return the buffer with the BGP Capabilities to transmit
367 */
368 private static ChannelBuffer prepareBgpOpenCapabilities(
369 BgpSession bgpSession) {
370 ChannelBuffer message =
371 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
372
373 //
374 // Write the Multiprotocol Extensions Capabilities
375 //
376
377 // IPv4 unicast
378 if (bgpSession.getLocalIpv4Unicast()) {
379 message.writeByte(Capabilities.TYPE); // Param type
380 message.writeByte(Capabilities.MIN_LENGTH +
381 MultiprotocolExtensions.LENGTH); // Param len
382 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
383 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
384 message.writeShort(MultiprotocolExtensions.AFI_IPV4);
385 message.writeByte(0); // Reserved field
386 message.writeByte(MultiprotocolExtensions.SAFI_UNICAST);
387 }
388 // IPv4 multicast
389 if (bgpSession.getLocalIpv4Multicast()) {
390 message.writeByte(Capabilities.TYPE); // Param type
391 message.writeByte(Capabilities.MIN_LENGTH +
392 MultiprotocolExtensions.LENGTH); // Param len
393 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
394 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
395 message.writeShort(MultiprotocolExtensions.AFI_IPV4);
396 message.writeByte(0); // Reserved field
397 message.writeByte(MultiprotocolExtensions.SAFI_MULTICAST);
398 }
399 // IPv6 unicast
400 if (bgpSession.getLocalIpv6Unicast()) {
401 message.writeByte(Capabilities.TYPE); // Param type
402 message.writeByte(Capabilities.MIN_LENGTH +
403 MultiprotocolExtensions.LENGTH); // Param len
404 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
405 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
406 message.writeShort(MultiprotocolExtensions.AFI_IPV6);
407 message.writeByte(0); // Reserved field
408 message.writeByte(MultiprotocolExtensions.SAFI_UNICAST);
409 }
410 // IPv6 multicast
411 if (bgpSession.getLocalIpv6Multicast()) {
412 message.writeByte(Capabilities.TYPE); // Param type
413 message.writeByte(Capabilities.MIN_LENGTH +
414 MultiprotocolExtensions.LENGTH); // Param len
415 message.writeByte(MultiprotocolExtensions.CODE); // Capab. code
416 message.writeByte(MultiprotocolExtensions.LENGTH); // Capab. len
417 message.writeShort(MultiprotocolExtensions.AFI_IPV6);
418 message.writeByte(0); // Reserved field
419 message.writeByte(MultiprotocolExtensions.SAFI_MULTICAST);
420 }
421
422 return message;
423 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800424}