blob: 98477aede147a3d5c92456ce38dbcae2710ae20a [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Jonathan Hartab63aac2014-10-16 08:52:55 -070016package org.onlab.onos.sdnip.bgp;
17
18import java.net.InetAddress;
19import java.net.InetSocketAddress;
20import java.net.SocketAddress;
21import java.util.ArrayList;
22import java.util.Collection;
23import java.util.Collections;
24import java.util.HashMap;
25import java.util.Map;
26import java.util.concurrent.ConcurrentHashMap;
27import java.util.concurrent.ConcurrentMap;
28import java.util.concurrent.TimeUnit;
29
30import org.apache.commons.lang3.tuple.Pair;
31import org.jboss.netty.buffer.ChannelBuffer;
32import org.jboss.netty.buffer.ChannelBuffers;
33import org.jboss.netty.channel.ChannelHandlerContext;
34import org.jboss.netty.channel.ChannelStateEvent;
35import org.jboss.netty.channel.SimpleChannelHandler;
36import org.jboss.netty.util.HashedWheelTimer;
37import org.jboss.netty.util.Timeout;
38import org.jboss.netty.util.Timer;
39import org.jboss.netty.util.TimerTask;
40import org.onlab.onos.sdnip.bgp.BgpConstants.Notifications;
41import org.onlab.onos.sdnip.bgp.BgpConstants.Notifications.HoldTimerExpired;
42import org.onlab.onos.sdnip.bgp.BgpConstants.Notifications.MessageHeaderError;
43import org.onlab.onos.sdnip.bgp.BgpConstants.Notifications.OpenMessageError;
44import org.onlab.onos.sdnip.bgp.BgpConstants.Notifications.UpdateMessageError;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080045import org.onlab.packet.Ip4Address;
46import org.onlab.packet.Ip4Prefix;
Jonathan Hartab63aac2014-10-16 08:52:55 -070047import org.slf4j.Logger;
48import org.slf4j.LoggerFactory;
49
50/**
51 * Class for handling the BGP peer sessions.
52 * There is one instance per each BGP peer session.
53 */
54public class BgpSession extends SimpleChannelHandler {
55 private static final Logger log =
56 LoggerFactory.getLogger(BgpSession.class);
57
58 private final BgpSessionManager bgpSessionManager;
59
60 // Local flag to indicate the session is closed.
61 // It is used to avoid the Netty's asynchronous closing of a channel.
62 private boolean isClosed = false;
63
64 private SocketAddress remoteAddress; // Peer IP addr/port
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080065 private Ip4Address remoteIp4Address; // Peer IPv4 address
Jonathan Hartab63aac2014-10-16 08:52:55 -070066 private int remoteBgpVersion; // 1 octet
67 private long remoteAs; // 2 octets
68 private long remoteHoldtime; // 2 octets
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080069 private Ip4Address remoteBgpId; // 4 octets -> IPv4 address
Jonathan Hartab63aac2014-10-16 08:52:55 -070070 //
71 private SocketAddress localAddress; // Local IP addr/port
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080072 private Ip4Address localIp4Address; // Local IPv4 address
Jonathan Hartab63aac2014-10-16 08:52:55 -070073 private int localBgpVersion; // 1 octet
74 private long localAs; // 2 octets
75 private long localHoldtime; // 2 octets
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080076 private Ip4Address localBgpId; // 4 octets -> IPv4 address
Jonathan Hartab63aac2014-10-16 08:52:55 -070077 //
78 private long localKeepaliveInterval; // Keepalive interval
79
80 // Timers state
81 private Timer timer = new HashedWheelTimer();
82 private volatile Timeout keepaliveTimeout; // Periodic KEEPALIVE
83 private volatile Timeout sessionTimeout; // Session timeout
84
85 // BGP RIB-IN routing entries from this peer
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080086 private ConcurrentMap<Ip4Prefix, BgpRouteEntry> bgpRibIn =
Jonathan Hartab63aac2014-10-16 08:52:55 -070087 new ConcurrentHashMap<>();
88
89 /**
90 * Constructor for a given BGP Session Manager.
91 *
92 * @param bgpSessionManager the BGP Session Manager to use
93 */
94 BgpSession(BgpSessionManager bgpSessionManager) {
95 this.bgpSessionManager = bgpSessionManager;
96 }
97
98 /**
99 * Gets the BGP RIB-IN routing entries.
100 *
101 * @return the BGP RIB-IN routing entries
102 */
103 public Collection<BgpRouteEntry> getBgpRibIn() {
104 return bgpRibIn.values();
105 }
106
107 /**
108 * Finds a BGP routing entry in the BGP RIB-IN.
109 *
110 * @param prefix the prefix of the route to search for
111 * @return the BGP routing entry if found, otherwise null
112 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800113 public BgpRouteEntry findBgpRouteEntry(Ip4Prefix prefix) {
Jonathan Hartab63aac2014-10-16 08:52:55 -0700114 return bgpRibIn.get(prefix);
115 }
116
117 /**
118 * Gets the BGP session remote address.
119 *
120 * @return the BGP session remote address
121 */
122 public SocketAddress getRemoteAddress() {
123 return remoteAddress;
124 }
125
126 /**
127 * Gets the BGP session remote IPv4 address.
128 *
129 * @return the BGP session remote IPv4 address
130 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800131 public Ip4Address getRemoteIp4Address() {
Jonathan Hartab63aac2014-10-16 08:52:55 -0700132 return remoteIp4Address;
133 }
134
135 /**
136 * Gets the BGP session remote BGP version.
137 *
138 * @return the BGP session remote BGP version
139 */
140 public int getRemoteBgpVersion() {
141 return remoteBgpVersion;
142 }
143
144 /**
145 * Gets the BGP session remote AS number.
146 *
147 * @return the BGP session remote AS number
148 */
149 public long getRemoteAs() {
150 return remoteAs;
151 }
152
153 /**
154 * Gets the BGP session remote Holdtime.
155 *
156 * @return the BGP session remote Holdtime
157 */
158 public long getRemoteHoldtime() {
159 return remoteHoldtime;
160 }
161
162 /**
163 * Gets the BGP session remote BGP Identifier as an IPv4 address.
164 *
165 * @return the BGP session remote BGP Identifier as an IPv4 address
166 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800167 public Ip4Address getRemoteBgpId() {
Jonathan Hartab63aac2014-10-16 08:52:55 -0700168 return remoteBgpId;
169 }
170
171 /**
172 * Gets the BGP session local address.
173 *
174 * @return the BGP session local address
175 */
176 public SocketAddress getLocalAddress() {
177 return localAddress;
178 }
179
180 /**
181 * Gets the BGP session local BGP version.
182 *
183 * @return the BGP session local BGP version
184 */
185 public int getLocalBgpVersion() {
186 return localBgpVersion;
187 }
188
189 /**
190 * Gets the BGP session local AS number.
191 *
192 * @return the BGP session local AS number
193 */
194 public long getLocalAs() {
195 return localAs;
196 }
197
198 /**
199 * Gets the BGP session local Holdtime.
200 *
201 * @return the BGP session local Holdtime
202 */
203 public long getLocalHoldtime() {
204 return localHoldtime;
205 }
206
207 /**
208 * Gets the BGP session local BGP Identifier as an IPv4 address.
209 *
210 * @return the BGP session local BGP Identifier as an IPv4 address
211 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800212 public Ip4Address getLocalBgpId() {
Jonathan Hartab63aac2014-10-16 08:52:55 -0700213 return localBgpId;
214 }
215
216 /**
217 * Tests whether the session is closed.
Thomas Vachuska4b420772014-10-30 16:46:17 -0700218 * <p>
Jonathan Hartab63aac2014-10-16 08:52:55 -0700219 * NOTE: We use this method to avoid the Netty's asynchronous closing
220 * of a channel.
Thomas Vachuska4b420772014-10-30 16:46:17 -0700221 * </p>
222 * @return true if the session is closed
Jonathan Hartab63aac2014-10-16 08:52:55 -0700223 */
224 boolean isClosed() {
225 return isClosed;
226 }
227
228 /**
229 * Closes the channel.
230 *
231 * @param ctx the Channel Handler Context
232 */
233 void closeChannel(ChannelHandlerContext ctx) {
234 isClosed = true;
235 timer.stop();
236 ctx.getChannel().close();
237 }
238
239 @Override
240 public void channelConnected(ChannelHandlerContext ctx,
241 ChannelStateEvent channelEvent) {
242 localAddress = ctx.getChannel().getLocalAddress();
243 remoteAddress = ctx.getChannel().getRemoteAddress();
244
245 // Assign the local and remote IPv4 addresses
246 InetAddress inetAddr;
247 if (localAddress instanceof InetSocketAddress) {
248 inetAddr = ((InetSocketAddress) localAddress).getAddress();
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800249 localIp4Address = Ip4Address.valueOf(inetAddr.getAddress());
Jonathan Hartab63aac2014-10-16 08:52:55 -0700250 }
251 if (remoteAddress instanceof InetSocketAddress) {
252 inetAddr = ((InetSocketAddress) remoteAddress).getAddress();
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800253 remoteIp4Address = Ip4Address.valueOf(inetAddr.getAddress());
Jonathan Hartab63aac2014-10-16 08:52:55 -0700254 }
255
256 log.debug("BGP Session Connected from {} on {}",
257 remoteAddress, localAddress);
258 if (!bgpSessionManager.peerConnected(this)) {
259 log.debug("Cannot setup BGP Session Connection from {}. Closing...",
260 remoteAddress);
261 ctx.getChannel().close();
262 }
263 }
264
265 @Override
266 public void channelDisconnected(ChannelHandlerContext ctx,
267 ChannelStateEvent channelEvent) {
268 log.debug("BGP Session Disconnected from {} on {}",
269 ctx.getChannel().getRemoteAddress(),
270 ctx.getChannel().getLocalAddress());
271
272 //
273 // Withdraw the routes advertised by this BGP peer
274 //
275 // NOTE: We must initialize the RIB-IN before propagating the withdraws
276 // for further processing. Otherwise, the BGP Decision Process
277 // will use those routes again.
278 //
279 Collection<BgpRouteEntry> deletedRoutes = bgpRibIn.values();
280 bgpRibIn = new ConcurrentHashMap<>();
281
282 // Push the updates to the BGP Merged RIB
283 BgpSessionManager.BgpRouteSelector bgpRouteSelector =
284 bgpSessionManager.getBgpRouteSelector();
285 Collection<BgpRouteEntry> addedRoutes = Collections.emptyList();
286 bgpRouteSelector.routeUpdates(this, addedRoutes, deletedRoutes);
287
288 bgpSessionManager.peerDisconnected(this);
289 }
290
291 /**
292 * Processes BGP OPEN message.
293 *
294 * @param ctx the Channel Handler Context
295 * @param message the message to process
296 */
297 void processBgpOpen(ChannelHandlerContext ctx, ChannelBuffer message) {
298 int minLength =
299 BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
300 if (message.readableBytes() < minLength) {
301 log.debug("BGP RX OPEN Error from {}: " +
302 "Message length {} too short. Must be at least {}",
303 remoteAddress, message.readableBytes(), minLength);
304 //
305 // ERROR: Bad Message Length
306 //
307 // Send NOTIFICATION and close the connection
308 ChannelBuffer txMessage = prepareBgpNotificationBadMessageLength(
309 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
310 ctx.getChannel().write(txMessage);
311 closeChannel(ctx);
312 return;
313 }
314
315 //
316 // Parse the OPEN message
317 //
318 // Remote BGP version
319 remoteBgpVersion = message.readUnsignedByte();
320 if (remoteBgpVersion != BgpConstants.BGP_VERSION) {
321 log.debug("BGP RX OPEN Error from {}: " +
322 "Unsupported BGP version {}. Should be {}",
323 remoteAddress, remoteBgpVersion,
324 BgpConstants.BGP_VERSION);
325 //
326 // ERROR: Unsupported Version Number
327 //
328 // Send NOTIFICATION and close the connection
329 int errorCode = OpenMessageError.ERROR_CODE;
330 int errorSubcode = OpenMessageError.UNSUPPORTED_VERSION_NUMBER;
331 ChannelBuffer data = ChannelBuffers.buffer(2);
332 data.writeShort(BgpConstants.BGP_VERSION);
333 ChannelBuffer txMessage =
334 prepareBgpNotification(errorCode, errorSubcode, data);
335 ctx.getChannel().write(txMessage);
336 closeChannel(ctx);
337 return;
338 }
339
340 // Remote AS number
341 remoteAs = message.readUnsignedShort();
342 //
343 // Verify that the AS number is same for all other BGP Sessions
344 // NOTE: This check applies only for our use-case where all BGP
345 // sessions are iBGP.
346 //
347 for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
348 if (remoteAs != bgpSession.getRemoteAs()) {
349 log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
350 "Expected {}",
351 remoteAddress, remoteAs, bgpSession.getRemoteAs());
352 //
353 // ERROR: Bad Peer AS
354 //
355 // Send NOTIFICATION and close the connection
356 int errorCode = OpenMessageError.ERROR_CODE;
357 int errorSubcode = OpenMessageError.BAD_PEER_AS;
358 ChannelBuffer txMessage =
359 prepareBgpNotification(errorCode, errorSubcode, null);
360 ctx.getChannel().write(txMessage);
361 closeChannel(ctx);
362 return;
363 }
364 }
365
366 // Remote Hold Time
367 remoteHoldtime = message.readUnsignedShort();
368 if ((remoteHoldtime != 0) &&
369 (remoteHoldtime < BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME)) {
370 log.debug("BGP RX OPEN Error from {}: " +
371 "Unacceptable Hold Time field {}. " +
372 "Should be 0 or at least {}",
373 remoteAddress, remoteHoldtime,
374 BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME);
375 //
376 // ERROR: Unacceptable Hold Time
377 //
378 // Send NOTIFICATION and close the connection
379 int errorCode = OpenMessageError.ERROR_CODE;
380 int errorSubcode = OpenMessageError.UNACCEPTABLE_HOLD_TIME;
381 ChannelBuffer txMessage =
382 prepareBgpNotification(errorCode, errorSubcode, null);
383 ctx.getChannel().write(txMessage);
384 closeChannel(ctx);
385 return;
386 }
387
388 // Remote BGP Identifier
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800389 remoteBgpId = Ip4Address.valueOf((int) message.readUnsignedInt());
Jonathan Hartab63aac2014-10-16 08:52:55 -0700390
391 // Optional Parameters
392 int optParamLen = message.readUnsignedByte();
393 if (message.readableBytes() < optParamLen) {
394 log.debug("BGP RX OPEN Error from {}: " +
395 "Invalid Optional Parameter Length field {}. " +
396 "Remaining Optional Parameters {}",
397 remoteAddress, optParamLen, message.readableBytes());
398 //
399 // ERROR: Invalid Optional Parameter Length field: Unspecific
400 //
401 // Send NOTIFICATION and close the connection
402 int errorCode = OpenMessageError.ERROR_CODE;
403 int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
404 ChannelBuffer txMessage =
405 prepareBgpNotification(errorCode, errorSubcode, null);
406 ctx.getChannel().write(txMessage);
407 closeChannel(ctx);
408 return;
409 }
410 // TODO: Parse the optional parameters (if needed)
411 message.readBytes(optParamLen); // NOTE: data ignored
412
413 //
414 // Copy some of the remote peer's state/setup to the local setup:
415 // - BGP version
416 // - AS number (NOTE: the peer setup is always iBGP)
417 // - Holdtime
418 // Also, assign the local BGP ID based on the local setup
419 //
420 localBgpVersion = remoteBgpVersion;
421 localAs = remoteAs;
422 localHoldtime = remoteHoldtime;
423 localBgpId = bgpSessionManager.getMyBgpId();
424
425 // Set the Keepalive interval
426 if (localHoldtime == 0) {
427 localKeepaliveInterval = 0;
428 } else {
429 localKeepaliveInterval = Math.max(localHoldtime /
430 BgpConstants.BGP_KEEPALIVE_PER_HOLD_INTERVAL,
431 BgpConstants.BGP_KEEPALIVE_MIN_INTERVAL);
432 }
433
434 log.debug("BGP RX OPEN message from {}: " +
435 "BGPv{} AS {} BGP-ID {} Holdtime {}",
436 remoteAddress, remoteBgpVersion, remoteAs,
437 remoteBgpId, remoteHoldtime);
438
439 // Send my OPEN followed by KEEPALIVE
440 ChannelBuffer txMessage = prepareBgpOpen();
441 ctx.getChannel().write(txMessage);
442 //
443 txMessage = prepareBgpKeepalive();
444 ctx.getChannel().write(txMessage);
445
446 // Start the KEEPALIVE timer
447 restartKeepaliveTimer(ctx);
448
449 // Start the Session Timeout timer
450 restartSessionTimeoutTimer(ctx);
451 }
452
453 /**
454 * Processes BGP UPDATE message.
455 *
456 * @param ctx the Channel Handler Context
457 * @param message the message to process
458 */
459 void processBgpUpdate(ChannelHandlerContext ctx, ChannelBuffer message) {
460 Collection<BgpRouteEntry> addedRoutes = null;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800461 Map<Ip4Prefix, BgpRouteEntry> deletedRoutes = new HashMap<>();
Jonathan Hartab63aac2014-10-16 08:52:55 -0700462
463 int minLength =
464 BgpConstants.BGP_UPDATE_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
465 if (message.readableBytes() < minLength) {
466 log.debug("BGP RX UPDATE Error from {}: " +
467 "Message length {} too short. Must be at least {}",
468 remoteAddress, message.readableBytes(), minLength);
469 //
470 // ERROR: Bad Message Length
471 //
472 // Send NOTIFICATION and close the connection
473 ChannelBuffer txMessage = prepareBgpNotificationBadMessageLength(
474 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
475 ctx.getChannel().write(txMessage);
476 closeChannel(ctx);
477 return;
478 }
479
480 log.debug("BGP RX UPDATE message from {}", remoteAddress);
481
482 //
483 // Parse the UPDATE message
484 //
485
486 //
487 // Parse the Withdrawn Routes
488 //
489 int withdrawnRoutesLength = message.readUnsignedShort();
490 if (withdrawnRoutesLength > message.readableBytes()) {
491 // ERROR: Malformed Attribute List
492 actionsBgpUpdateMalformedAttributeList(ctx);
493 return;
494 }
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800495 Collection<Ip4Prefix> withdrawnPrefixes = null;
Jonathan Hartab63aac2014-10-16 08:52:55 -0700496 try {
497 withdrawnPrefixes = parsePackedPrefixes(withdrawnRoutesLength,
498 message);
499 } catch (BgpParseException e) {
500 // ERROR: Invalid Network Field
501 log.debug("Exception parsing Withdrawn Prefixes from BGP peer {}: ",
502 remoteBgpId, e);
503 actionsBgpUpdateInvalidNetworkField(ctx);
504 return;
505 }
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800506 for (Ip4Prefix prefix : withdrawnPrefixes) {
Jonathan Hartab63aac2014-10-16 08:52:55 -0700507 log.debug("BGP RX UPDATE message WITHDRAWN from {}: {}",
508 remoteAddress, prefix);
509 BgpRouteEntry bgpRouteEntry = bgpRibIn.get(prefix);
510 if (bgpRouteEntry != null) {
511 deletedRoutes.put(prefix, bgpRouteEntry);
512 }
513 }
514
515 //
516 // Parse the Path Attributes
517 //
518 try {
519 addedRoutes = parsePathAttributes(ctx, message);
520 } catch (BgpParseException e) {
521 log.debug("Exception parsing Path Attributes from BGP peer {}: ",
522 remoteBgpId, e);
523 // NOTE: The session was already closed, so nothing else to do
524 return;
525 }
526 // Ignore WITHDRAWN routes that are ADDED
527 for (BgpRouteEntry bgpRouteEntry : addedRoutes) {
528 deletedRoutes.remove(bgpRouteEntry.prefix());
529 }
530
531 // Update the BGP RIB-IN
532 for (BgpRouteEntry bgpRouteEntry : deletedRoutes.values()) {
533 bgpRibIn.remove(bgpRouteEntry.prefix());
534 }
535 for (BgpRouteEntry bgpRouteEntry : addedRoutes) {
536 bgpRibIn.put(bgpRouteEntry.prefix(), bgpRouteEntry);
537 }
538
539 // Push the updates to the BGP Merged RIB
540 BgpSessionManager.BgpRouteSelector bgpRouteSelector =
541 bgpSessionManager.getBgpRouteSelector();
542 bgpRouteSelector.routeUpdates(this, addedRoutes,
543 deletedRoutes.values());
544
545 // Start the Session Timeout timer
546 restartSessionTimeoutTimer(ctx);
547 }
548
549 /**
550 * Parse BGP Path Attributes from the BGP UPDATE message.
551 *
552 * @param ctx the Channel Handler Context
553 * @param message the message to parse
554 * @return a collection of the result BGP Route Entries
555 * @throws BgpParseException
556 */
557 private Collection<BgpRouteEntry> parsePathAttributes(
558 ChannelHandlerContext ctx,
559 ChannelBuffer message)
560 throws BgpParseException {
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800561 Map<Ip4Prefix, BgpRouteEntry> addedRoutes = new HashMap<>();
Jonathan Hartab63aac2014-10-16 08:52:55 -0700562
563 //
564 // Parsed values
565 //
566 Short origin = -1; // Mandatory
567 BgpRouteEntry.AsPath asPath = null; // Mandatory
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800568 Ip4Address nextHop = null; // Mandatory
Jonathan Hartab63aac2014-10-16 08:52:55 -0700569 long multiExitDisc = // Optional
570 BgpConstants.Update.MultiExitDisc.LOWEST_MULTI_EXIT_DISC;
571 Long localPref = null; // Mandatory
572 Long aggregatorAsNumber = null; // Optional: unused
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800573 Ip4Address aggregatorIpAddress = null; // Optional: unused
Jonathan Hartab63aac2014-10-16 08:52:55 -0700574
575 //
576 // Get and verify the Path Attributes Length
577 //
578 int pathAttributeLength = message.readUnsignedShort();
579 if (pathAttributeLength > message.readableBytes()) {
580 // ERROR: Malformed Attribute List
581 actionsBgpUpdateMalformedAttributeList(ctx);
582 String errorMsg = "Malformed Attribute List";
583 throw new BgpParseException(errorMsg);
584 }
585 if (pathAttributeLength == 0) {
586 return addedRoutes.values();
587 }
588
589 //
590 // Parse the Path Attributes
591 //
592 int pathAttributeEnd = message.readerIndex() + pathAttributeLength;
593 while (message.readerIndex() < pathAttributeEnd) {
594 int attrFlags = message.readUnsignedByte();
595 if (message.readerIndex() >= pathAttributeEnd) {
596 // ERROR: Malformed Attribute List
597 actionsBgpUpdateMalformedAttributeList(ctx);
598 String errorMsg = "Malformed Attribute List";
599 throw new BgpParseException(errorMsg);
600 }
601 int attrTypeCode = message.readUnsignedByte();
602
603 // The Attribute Flags
604 boolean optionalBit = ((0x80 & attrFlags) != 0);
605 boolean transitiveBit = ((0x40 & attrFlags) != 0);
606 boolean partialBit = ((0x20 & attrFlags) != 0);
607 boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
608
609 // The Attribute Length
610 int attrLen = 0;
611 int attrLenOctets = 1;
612 if (extendedLengthBit) {
613 attrLenOctets = 2;
614 }
615 if (message.readerIndex() + attrLenOctets > pathAttributeEnd) {
616 // ERROR: Malformed Attribute List
617 actionsBgpUpdateMalformedAttributeList(ctx);
618 String errorMsg = "Malformed Attribute List";
619 throw new BgpParseException(errorMsg);
620 }
621 if (extendedLengthBit) {
622 attrLen = message.readUnsignedShort();
623 } else {
624 attrLen = message.readUnsignedByte();
625 }
626 if (message.readerIndex() + attrLen > pathAttributeEnd) {
627 // ERROR: Malformed Attribute List
628 actionsBgpUpdateMalformedAttributeList(ctx);
629 String errorMsg = "Malformed Attribute List";
630 throw new BgpParseException(errorMsg);
631 }
632
633 //
634 // Verify the Attribute Flags
635 //
636 verifyBgpUpdateAttributeFlags(ctx, attrTypeCode, attrLen,
637 attrFlags, message);
638
639 //
640 // Extract the Attribute Value based on the Attribute Type Code
641 //
642 switch (attrTypeCode) {
643
644 case BgpConstants.Update.Origin.TYPE:
645 // Attribute Type Code ORIGIN
646 origin = parseAttributeTypeOrigin(ctx, attrTypeCode, attrLen,
647 attrFlags, message);
648 break;
649
650 case BgpConstants.Update.AsPath.TYPE:
651 // Attribute Type Code AS_PATH
652 asPath = parseAttributeTypeAsPath(ctx, attrTypeCode, attrLen,
653 attrFlags, message);
654 break;
655
656 case BgpConstants.Update.NextHop.TYPE:
657 // Attribute Type Code NEXT_HOP
658 nextHop = parseAttributeTypeNextHop(ctx, attrTypeCode, attrLen,
659 attrFlags, message);
660 break;
661
662 case BgpConstants.Update.MultiExitDisc.TYPE:
663 // Attribute Type Code MULTI_EXIT_DISC
664 multiExitDisc =
665 parseAttributeTypeMultiExitDisc(ctx, attrTypeCode, attrLen,
666 attrFlags, message);
667 break;
668
669 case BgpConstants.Update.LocalPref.TYPE:
670 // Attribute Type Code LOCAL_PREF
671 localPref =
672 parseAttributeTypeLocalPref(ctx, attrTypeCode, attrLen,
673 attrFlags, message);
674 break;
675
676 case BgpConstants.Update.AtomicAggregate.TYPE:
677 // Attribute Type Code ATOMIC_AGGREGATE
678 parseAttributeTypeAtomicAggregate(ctx, attrTypeCode, attrLen,
679 attrFlags, message);
680 // Nothing to do: this attribute is primarily informational
681 break;
682
683 case BgpConstants.Update.Aggregator.TYPE:
684 // Attribute Type Code AGGREGATOR
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800685 Pair<Long, Ip4Address> aggregator =
Jonathan Hartab63aac2014-10-16 08:52:55 -0700686 parseAttributeTypeAggregator(ctx, attrTypeCode, attrLen,
687 attrFlags, message);
688 aggregatorAsNumber = aggregator.getLeft();
689 aggregatorIpAddress = aggregator.getRight();
690 break;
691
692 default:
693 // TODO: Parse any new Attribute Types if needed
694 if (!optionalBit) {
695 // ERROR: Unrecognized Well-known Attribute
696 actionsBgpUpdateUnrecognizedWellKnownAttribute(
697 ctx, attrTypeCode, attrLen, attrFlags, message);
698 String errorMsg = "Unrecognized Well-known Attribute: " +
699 attrTypeCode;
700 throw new BgpParseException(errorMsg);
701 }
702
703 // Skip the data from the unrecognized attribute
704 log.debug("BGP RX UPDATE message from {}: " +
705 "Unrecognized Attribute Type {}",
706 remoteAddress, attrTypeCode);
707 message.skipBytes(attrLen);
708 break;
709 }
710 }
711
712 //
713 // Verify the Well-known Attributes
714 //
715 verifyBgpUpdateWellKnownAttributes(ctx, origin, asPath, nextHop,
716 localPref);
717
718 //
719 // Parse the NLRI (Network Layer Reachability Information)
720 //
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800721 Collection<Ip4Prefix> addedPrefixes = null;
Jonathan Hartab63aac2014-10-16 08:52:55 -0700722 int nlriLength = message.readableBytes();
723 try {
724 addedPrefixes = parsePackedPrefixes(nlriLength, message);
725 } catch (BgpParseException e) {
726 // ERROR: Invalid Network Field
727 log.debug("Exception parsing NLRI from BGP peer {}: ",
728 remoteBgpId, e);
729 actionsBgpUpdateInvalidNetworkField(ctx);
730 // Rethrow the exception
731 throw e;
732 }
733
734 // Generate the added routes
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800735 for (Ip4Prefix prefix : addedPrefixes) {
Jonathan Hartab63aac2014-10-16 08:52:55 -0700736 BgpRouteEntry bgpRouteEntry =
737 new BgpRouteEntry(this, prefix, nextHop,
738 origin.byteValue(), asPath, localPref);
739 bgpRouteEntry.setMultiExitDisc(multiExitDisc);
740 if (bgpRouteEntry.hasAsPathLoop(localAs)) {
741 log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
742 "nextHop {}: contains AS Path loop",
743 remoteAddress, prefix, nextHop);
744 continue;
745 } else {
746 log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
747 remoteAddress, prefix, nextHop);
748 }
749 addedRoutes.put(prefix, bgpRouteEntry);
750 }
751
752 return addedRoutes.values();
753 }
754
755 /**
756 * Verifies BGP UPDATE Well-known Attributes.
757 *
758 * @param ctx the Channel Handler Context
759 * @param origin the ORIGIN well-known mandatory attribute
760 * @param asPath the AS_PATH well-known mandatory attribute
761 * @param nextHop the NEXT_HOP well-known mandatory attribute
762 * @param localPref the LOCAL_PREF required attribute
763 * @throws BgpParseException
764 */
765 private void verifyBgpUpdateWellKnownAttributes(
766 ChannelHandlerContext ctx,
767 Short origin,
768 BgpRouteEntry.AsPath asPath,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800769 Ip4Address nextHop,
Jonathan Hartab63aac2014-10-16 08:52:55 -0700770 Long localPref)
771 throws BgpParseException {
772 //
773 // Check for Missing Well-known Attributes
774 //
775 if ((origin == null) || (origin == -1)) {
776 // Missing Attribute Type Code ORIGIN
777 int type = BgpConstants.Update.Origin.TYPE;
778 actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
779 String errorMsg = "Missing Well-known Attribute: ORIGIN";
780 throw new BgpParseException(errorMsg);
781 }
782 if (asPath == null) {
783 // Missing Attribute Type Code AS_PATH
784 int type = BgpConstants.Update.AsPath.TYPE;
785 actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
786 String errorMsg = "Missing Well-known Attribute: AS_PATH";
787 throw new BgpParseException(errorMsg);
788 }
789 if (nextHop == null) {
790 // Missing Attribute Type Code NEXT_HOP
791 int type = BgpConstants.Update.NextHop.TYPE;
792 actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
793 String errorMsg = "Missing Well-known Attribute: NEXT_HOP";
794 throw new BgpParseException(errorMsg);
795 }
796 if (localPref == null) {
797 // Missing Attribute Type Code LOCAL_PREF
798 // NOTE: Required for iBGP
799 int type = BgpConstants.Update.LocalPref.TYPE;
800 actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
801 String errorMsg = "Missing Well-known Attribute: LOCAL_PREF";
802 throw new BgpParseException(errorMsg);
803 }
804 }
805
806 /**
807 * Verifies the BGP UPDATE Attribute Flags.
808 *
809 * @param ctx the Channel Handler Context
810 * @param attrTypeCode the attribute type code
811 * @param attrLen the attribute length (in octets)
812 * @param attrFlags the attribute flags
813 * @param message the message to parse
814 * @throws BgpParseException
815 */
816 private void verifyBgpUpdateAttributeFlags(
817 ChannelHandlerContext ctx,
818 int attrTypeCode,
819 int attrLen,
820 int attrFlags,
821 ChannelBuffer message)
822 throws BgpParseException {
823
824 //
825 // Assign the Attribute Type Name and the Well-known flag
826 //
827 String typeName = "UNKNOWN";
828 boolean isWellKnown = false;
829 switch (attrTypeCode) {
830 case BgpConstants.Update.Origin.TYPE:
831 isWellKnown = true;
832 typeName = "ORIGIN";
833 break;
834 case BgpConstants.Update.AsPath.TYPE:
835 isWellKnown = true;
836 typeName = "AS_PATH";
837 break;
838 case BgpConstants.Update.NextHop.TYPE:
839 isWellKnown = true;
840 typeName = "NEXT_HOP";
841 break;
842 case BgpConstants.Update.MultiExitDisc.TYPE:
843 isWellKnown = false;
844 typeName = "MULTI_EXIT_DISC";
845 break;
846 case BgpConstants.Update.LocalPref.TYPE:
847 isWellKnown = true;
848 typeName = "LOCAL_PREF";
849 break;
850 case BgpConstants.Update.AtomicAggregate.TYPE:
851 isWellKnown = true;
852 typeName = "ATOMIC_AGGREGATE";
853 break;
854 case BgpConstants.Update.Aggregator.TYPE:
855 isWellKnown = false;
856 typeName = "AGGREGATOR";
857 break;
858 default:
859 isWellKnown = false;
860 typeName = "UNKNOWN(" + attrTypeCode + ")";
861 break;
862 }
863
864 //
865 // Verify the Attribute Flags
866 //
867 boolean optionalBit = ((0x80 & attrFlags) != 0);
868 boolean transitiveBit = ((0x40 & attrFlags) != 0);
869 boolean partialBit = ((0x20 & attrFlags) != 0);
870 if ((isWellKnown && optionalBit) ||
871 (isWellKnown && (!transitiveBit)) ||
872 (isWellKnown && partialBit) ||
873 (optionalBit && (!transitiveBit) && partialBit)) {
874 //
875 // ERROR: The Optional bit cannot be set for Well-known attributes
876 // ERROR: The Transtive bit MUST be 1 for well-known attributes
877 // ERROR: The Partial bit MUST be 0 for well-known attributes
878 // ERROR: The Partial bit MUST be 0 for optional non-transitive
879 // attributes
880 //
881 actionsBgpUpdateAttributeFlagsError(
882 ctx, attrTypeCode, attrLen, attrFlags, message);
883 String errorMsg = "Attribute Flags Error for " + typeName + ": " +
884 attrFlags;
885 throw new BgpParseException(errorMsg);
886 }
887 }
888
889 /**
890 * Parses BGP UPDATE Attribute Type ORIGIN.
891 *
892 * @param ctx the Channel Handler Context
893 * @param attrTypeCode the attribute type code
894 * @param attrLen the attribute length (in octets)
895 * @param attrFlags the attribute flags
896 * @param message the message to parse
897 * @return the parsed ORIGIN value
898 * @throws BgpParseException
899 */
900 private short parseAttributeTypeOrigin(
901 ChannelHandlerContext ctx,
902 int attrTypeCode,
903 int attrLen,
904 int attrFlags,
905 ChannelBuffer message)
906 throws BgpParseException {
907
908 // Check the Attribute Length
909 if (attrLen != BgpConstants.Update.Origin.LENGTH) {
910 // ERROR: Attribute Length Error
911 actionsBgpUpdateAttributeLengthError(
912 ctx, attrTypeCode, attrLen, attrFlags, message);
913 String errorMsg = "Attribute Length Error";
914 throw new BgpParseException(errorMsg);
915 }
916
917 message.markReaderIndex();
918 short origin = message.readUnsignedByte();
919 switch (origin) {
920 case BgpConstants.Update.Origin.IGP:
921 // FALLTHROUGH
922 case BgpConstants.Update.Origin.EGP:
923 // FALLTHROUGH
924 case BgpConstants.Update.Origin.INCOMPLETE:
925 break;
926 default:
927 // ERROR: Invalid ORIGIN Attribute
928 message.resetReaderIndex();
929 actionsBgpUpdateInvalidOriginAttribute(
930 ctx, attrTypeCode, attrLen, attrFlags, message, origin);
931 String errorMsg = "Invalid ORIGIN Attribute: " + origin;
932 throw new BgpParseException(errorMsg);
933 }
934
935 return origin;
936 }
937
938 /**
939 * Parses BGP UPDATE Attribute AS Path.
940 *
941 * @param ctx the Channel Handler Context
942 * @param attrTypeCode the attribute type code
943 * @param attrLen the attribute length (in octets)
944 * @param attrFlags the attribute flags
945 * @param message the message to parse
946 * @return the parsed AS Path
947 * @throws BgpParseException
948 */
949 private BgpRouteEntry.AsPath parseAttributeTypeAsPath(
950 ChannelHandlerContext ctx,
951 int attrTypeCode,
952 int attrLen,
953 int attrFlags,
954 ChannelBuffer message)
955 throws BgpParseException {
956 ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
957
958 //
959 // Parse the message
960 //
961 while (attrLen > 0) {
962 if (attrLen < 2) {
963 // ERROR: Malformed AS_PATH
964 actionsBgpUpdateMalformedAsPath(ctx);
965 String errorMsg = "Malformed AS Path";
966 throw new BgpParseException(errorMsg);
967 }
968 // Get the Path Segment Type and Length (in number of ASes)
969 short pathSegmentType = message.readUnsignedByte();
970 short pathSegmentLength = message.readUnsignedByte();
971 attrLen -= 2;
972
973 // Verify the Path Segment Type
974 switch (pathSegmentType) {
975 case BgpConstants.Update.AsPath.AS_SET:
976 // FALLTHROUGH
977 case BgpConstants.Update.AsPath.AS_SEQUENCE:
978 break;
979 default:
980 // ERROR: Invalid Path Segment Type
981 //
982 // NOTE: The BGP Spec (RFC 4271) doesn't contain Error Subcode
983 // for "Invalid Path Segment Type", hence we return
984 // the error as "Malformed AS_PATH".
985 //
986 actionsBgpUpdateMalformedAsPath(ctx);
987 String errorMsg =
988 "Invalid AS Path Segment Type: " + pathSegmentType;
989 throw new BgpParseException(errorMsg);
990 }
991
992 // Parse the AS numbers
993 if (2 * pathSegmentLength > attrLen) {
994 // ERROR: Malformed AS_PATH
995 actionsBgpUpdateMalformedAsPath(ctx);
996 String errorMsg = "Malformed AS Path";
997 throw new BgpParseException(errorMsg);
998 }
999 attrLen -= (2 * pathSegmentLength);
1000 ArrayList<Long> segmentAsNumbers = new ArrayList<>();
1001 while (pathSegmentLength-- > 0) {
1002 long asNumber = message.readUnsignedShort();
1003 segmentAsNumbers.add(asNumber);
1004 }
1005
1006 BgpRouteEntry.PathSegment pathSegment =
1007 new BgpRouteEntry.PathSegment((byte) pathSegmentType,
1008 segmentAsNumbers);
1009 pathSegments.add(pathSegment);
1010 }
1011
1012 return new BgpRouteEntry.AsPath(pathSegments);
1013 }
1014
1015 /**
1016 * Parses BGP UPDATE Attribute Type NEXT_HOP.
1017 *
1018 * @param ctx the Channel Handler Context
1019 * @param attrTypeCode the attribute type code
1020 * @param attrLen the attribute length (in octets)
1021 * @param attrFlags the attribute flags
1022 * @param message the message to parse
1023 * @return the parsed NEXT_HOP value
1024 * @throws BgpParseException
1025 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001026 private Ip4Address parseAttributeTypeNextHop(
Jonathan Hartab63aac2014-10-16 08:52:55 -07001027 ChannelHandlerContext ctx,
1028 int attrTypeCode,
1029 int attrLen,
1030 int attrFlags,
1031 ChannelBuffer message)
1032 throws BgpParseException {
1033
1034 // Check the Attribute Length
1035 if (attrLen != BgpConstants.Update.NextHop.LENGTH) {
1036 // ERROR: Attribute Length Error
1037 actionsBgpUpdateAttributeLengthError(
1038 ctx, attrTypeCode, attrLen, attrFlags, message);
1039 String errorMsg = "Attribute Length Error";
1040 throw new BgpParseException(errorMsg);
1041 }
1042
1043 message.markReaderIndex();
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001044 Ip4Address nextHopAddress =
1045 Ip4Address.valueOf((int) message.readUnsignedInt());
Jonathan Hartab63aac2014-10-16 08:52:55 -07001046 //
1047 // Check whether the NEXT_HOP IP address is semantically correct.
1048 // As per RFC 4271, Section 6.3:
1049 //
1050 // a) It MUST NOT be the IP address of the receiving speaker
1051 // b) In the case of an EBGP ....
1052 //
1053 // Here we check only (a), because (b) doesn't apply for us: all our
1054 // peers are iBGP.
1055 //
1056 if (nextHopAddress.equals(localIp4Address)) {
1057 // ERROR: Invalid NEXT_HOP Attribute
1058 message.resetReaderIndex();
1059 actionsBgpUpdateInvalidNextHopAttribute(
1060 ctx, attrTypeCode, attrLen, attrFlags, message,
1061 nextHopAddress);
1062 String errorMsg = "Invalid NEXT_HOP Attribute: " + nextHopAddress;
1063 throw new BgpParseException(errorMsg);
1064 }
1065
1066 return nextHopAddress;
1067 }
1068
1069 /**
1070 * Parses BGP UPDATE Attribute Type MULTI_EXIT_DISC.
1071 *
1072 * @param ctx the Channel Handler Context
1073 * @param attrTypeCode the attribute type code
1074 * @param attrLen the attribute length (in octets)
1075 * @param attrFlags the attribute flags
1076 * @param message the message to parse
1077 * @return the parsed MULTI_EXIT_DISC value
1078 * @throws BgpParseException
1079 */
1080 private long parseAttributeTypeMultiExitDisc(
1081 ChannelHandlerContext ctx,
1082 int attrTypeCode,
1083 int attrLen,
1084 int attrFlags,
1085 ChannelBuffer message)
1086 throws BgpParseException {
1087
1088 // Check the Attribute Length
1089 if (attrLen != BgpConstants.Update.MultiExitDisc.LENGTH) {
1090 // ERROR: Attribute Length Error
1091 actionsBgpUpdateAttributeLengthError(
1092 ctx, attrTypeCode, attrLen, attrFlags, message);
1093 String errorMsg = "Attribute Length Error";
1094 throw new BgpParseException(errorMsg);
1095 }
1096
1097 long multiExitDisc = message.readUnsignedInt();
1098 return multiExitDisc;
1099 }
1100
1101 /**
1102 * Parses BGP UPDATE Attribute Type LOCAL_PREF.
1103 *
1104 * @param ctx the Channel Handler Context
1105 * @param attrTypeCode the attribute type code
1106 * @param attrLen the attribute length (in octets)
1107 * @param attrFlags the attribute flags
1108 * @param message the message to parse
1109 * @return the parsed LOCAL_PREF value
1110 * @throws BgpParseException
1111 */
1112 private long parseAttributeTypeLocalPref(
1113 ChannelHandlerContext ctx,
1114 int attrTypeCode,
1115 int attrLen,
1116 int attrFlags,
1117 ChannelBuffer message)
1118 throws BgpParseException {
1119
1120 // Check the Attribute Length
1121 if (attrLen != BgpConstants.Update.LocalPref.LENGTH) {
1122 // ERROR: Attribute Length Error
1123 actionsBgpUpdateAttributeLengthError(
1124 ctx, attrTypeCode, attrLen, attrFlags, message);
1125 String errorMsg = "Attribute Length Error";
1126 throw new BgpParseException(errorMsg);
1127 }
1128
1129 long localPref = message.readUnsignedInt();
1130 return localPref;
1131 }
1132
1133 /**
1134 * Parses BGP UPDATE Attribute Type ATOMIC_AGGREGATE.
1135 *
1136 * @param ctx the Channel Handler Context
1137 * @param attrTypeCode the attribute type code
1138 * @param attrLen the attribute length (in octets)
1139 * @param attrFlags the attribute flags
1140 * @param message the message to parse
1141 * @throws BgpParseException
1142 */
1143 private void parseAttributeTypeAtomicAggregate(
1144 ChannelHandlerContext ctx,
1145 int attrTypeCode,
1146 int attrLen,
1147 int attrFlags,
1148 ChannelBuffer message)
1149 throws BgpParseException {
1150
1151 // Check the Attribute Length
1152 if (attrLen != BgpConstants.Update.AtomicAggregate.LENGTH) {
1153 // ERROR: Attribute Length Error
1154 actionsBgpUpdateAttributeLengthError(
1155 ctx, attrTypeCode, attrLen, attrFlags, message);
1156 String errorMsg = "Attribute Length Error";
1157 throw new BgpParseException(errorMsg);
1158 }
1159
1160 // Nothing to do: this attribute is primarily informational
1161 }
1162
1163 /**
1164 * Parses BGP UPDATE Attribute Type AGGREGATOR.
1165 *
1166 * @param ctx the Channel Handler Context
1167 * @param attrTypeCode the attribute type code
1168 * @param attrLen the attribute length (in octets)
1169 * @param attrFlags the attribute flags
1170 * @param message the message to parse
1171 * @return the parsed AGGREGATOR value: a tuple of <AS-Number, IP-Address>
1172 * @throws BgpParseException
1173 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001174 private Pair<Long, Ip4Address> parseAttributeTypeAggregator(
Jonathan Hartab63aac2014-10-16 08:52:55 -07001175 ChannelHandlerContext ctx,
1176 int attrTypeCode,
1177 int attrLen,
1178 int attrFlags,
1179 ChannelBuffer message)
1180 throws BgpParseException {
1181
1182 // Check the Attribute Length
1183 if (attrLen != BgpConstants.Update.Aggregator.LENGTH) {
1184 // ERROR: Attribute Length Error
1185 actionsBgpUpdateAttributeLengthError(
1186 ctx, attrTypeCode, attrLen, attrFlags, message);
1187 String errorMsg = "Attribute Length Error";
1188 throw new BgpParseException(errorMsg);
1189 }
1190
1191 // The AGGREGATOR AS number
1192 long aggregatorAsNumber = message.readUnsignedShort();
1193 // The AGGREGATOR IP address
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001194 Ip4Address aggregatorIpAddress =
1195 Ip4Address.valueOf((int) message.readUnsignedInt());
Jonathan Hartab63aac2014-10-16 08:52:55 -07001196
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001197 Pair<Long, Ip4Address> aggregator = Pair.of(aggregatorAsNumber,
Jonathan Hartab63aac2014-10-16 08:52:55 -07001198 aggregatorIpAddress);
1199 return aggregator;
1200 }
1201
1202 /**
1203 * Parses a message that contains encoded IPv4 network prefixes.
1204 * <p>
1205 * The IPv4 prefixes are encoded in the form:
1206 * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
1207 * and Prefix is the IPv4 prefix (padded with trailing bits to the end
1208 * of an octet).
1209 *
1210 * @param totalLength the total length of the data to parse
1211 * @param message the message with data to parse
1212 * @return a collection of parsed IPv4 network prefixes
1213 * @throws BgpParseException
1214 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001215 private Collection<Ip4Prefix> parsePackedPrefixes(int totalLength,
Jonathan Hartab63aac2014-10-16 08:52:55 -07001216 ChannelBuffer message)
1217 throws BgpParseException {
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001218 Collection<Ip4Prefix> result = new ArrayList<>();
Jonathan Hartab63aac2014-10-16 08:52:55 -07001219
1220 if (totalLength == 0) {
1221 return result;
1222 }
1223
1224 // Parse the data
1225 int dataEnd = message.readerIndex() + totalLength;
1226 while (message.readerIndex() < dataEnd) {
1227 int prefixBitlen = message.readUnsignedByte();
1228 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
1229 if (message.readerIndex() + prefixBytelen > dataEnd) {
1230 String errorMsg = "Malformed Network Prefixes";
1231 throw new BgpParseException(errorMsg);
1232 }
1233
1234 long address = 0;
1235 long extraShift = (4 - prefixBytelen) * 8;
1236 while (prefixBytelen > 0) {
1237 address <<= 8;
1238 address |= message.readUnsignedByte();
1239 prefixBytelen--;
1240 }
1241 address <<= extraShift;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001242 Ip4Prefix prefix =
1243 Ip4Prefix.valueOf(Ip4Address.valueOf((int) address),
1244 prefixBitlen);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001245 result.add(prefix);
1246 }
1247
1248 return result;
1249 }
1250
1251 /**
1252 * Applies the appropriate actions after detecting BGP UPDATE
1253 * Invalid Network Field Error: send NOTIFICATION and close the channel.
1254 *
1255 * @param ctx the Channel Handler Context
1256 */
1257 private void actionsBgpUpdateInvalidNetworkField(
1258 ChannelHandlerContext ctx) {
1259 log.debug("BGP RX UPDATE Error from {}: Invalid Network Field",
1260 remoteAddress);
1261
1262 //
1263 // ERROR: Invalid Network Field
1264 //
1265 // Send NOTIFICATION and close the connection
1266 int errorCode = UpdateMessageError.ERROR_CODE;
1267 int errorSubcode = UpdateMessageError.INVALID_NETWORK_FIELD;
1268 ChannelBuffer txMessage =
1269 prepareBgpNotification(errorCode, errorSubcode, null);
1270 ctx.getChannel().write(txMessage);
1271 closeChannel(ctx);
1272 }
1273
1274 /**
1275 * Applies the appropriate actions after detecting BGP UPDATE
1276 * Malformed Attribute List Error: send NOTIFICATION and close the channel.
1277 *
1278 * @param ctx the Channel Handler Context
1279 */
1280 private void actionsBgpUpdateMalformedAttributeList(
1281 ChannelHandlerContext ctx) {
1282 log.debug("BGP RX UPDATE Error from {}: Malformed Attribute List",
1283 remoteAddress);
1284
1285 //
1286 // ERROR: Malformed Attribute List
1287 //
1288 // Send NOTIFICATION and close the connection
1289 int errorCode = UpdateMessageError.ERROR_CODE;
1290 int errorSubcode = UpdateMessageError.MALFORMED_ATTRIBUTE_LIST;
1291 ChannelBuffer txMessage =
1292 prepareBgpNotification(errorCode, errorSubcode, null);
1293 ctx.getChannel().write(txMessage);
1294 closeChannel(ctx);
1295 }
1296
1297 /**
1298 * Applies the appropriate actions after detecting BGP UPDATE
1299 * Missing Well-known Attribute Error: send NOTIFICATION and close the
1300 * channel.
1301 *
1302 * @param ctx the Channel Handler Context
1303 * @param missingAttrTypeCode the missing attribute type code
1304 */
1305 private void actionsBgpUpdateMissingWellKnownAttribute(
1306 ChannelHandlerContext ctx,
1307 int missingAttrTypeCode) {
1308 log.debug("BGP RX UPDATE Error from {}: Missing Well-known Attribute: {}",
1309 remoteAddress, missingAttrTypeCode);
1310
1311 //
1312 // ERROR: Missing Well-known Attribute
1313 //
1314 // Send NOTIFICATION and close the connection
1315 int errorCode = UpdateMessageError.ERROR_CODE;
1316 int errorSubcode = UpdateMessageError.MISSING_WELL_KNOWN_ATTRIBUTE;
1317 ChannelBuffer data = ChannelBuffers.buffer(1);
1318 data.writeByte(missingAttrTypeCode);
1319 ChannelBuffer txMessage =
1320 prepareBgpNotification(errorCode, errorSubcode, data);
1321 ctx.getChannel().write(txMessage);
1322 closeChannel(ctx);
1323 }
1324
1325 /**
1326 * Applies the appropriate actions after detecting BGP UPDATE
1327 * Invalid ORIGIN Attribute Error: send NOTIFICATION and close the channel.
1328 *
1329 * @param ctx the Channel Handler Context
1330 * @param attrTypeCode the attribute type code
1331 * @param attrLen the attribute length (in octets)
1332 * @param attrFlags the attribute flags
1333 * @param message the message with the data
1334 * @param origin the ORIGIN attribute value
1335 */
1336 private void actionsBgpUpdateInvalidOriginAttribute(
1337 ChannelHandlerContext ctx,
1338 int attrTypeCode,
1339 int attrLen,
1340 int attrFlags,
1341 ChannelBuffer message,
1342 short origin) {
1343 log.debug("BGP RX UPDATE Error from {}: Invalid ORIGIN Attribute",
1344 remoteAddress);
1345
1346 //
1347 // ERROR: Invalid ORIGIN Attribute
1348 //
1349 // Send NOTIFICATION and close the connection
1350 int errorCode = UpdateMessageError.ERROR_CODE;
1351 int errorSubcode = UpdateMessageError.INVALID_ORIGIN_ATTRIBUTE;
1352 ChannelBuffer data =
1353 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1354 attrFlags, message);
1355 ChannelBuffer txMessage =
1356 prepareBgpNotification(errorCode, errorSubcode, data);
1357 ctx.getChannel().write(txMessage);
1358 closeChannel(ctx);
1359 }
1360
1361 /**
1362 * Applies the appropriate actions after detecting BGP UPDATE
1363 * Attribute Flags Error: send NOTIFICATION and close the channel.
1364 *
1365 * @param ctx the Channel Handler Context
1366 * @param attrTypeCode the attribute type code
1367 * @param attrLen the attribute length (in octets)
1368 * @param attrFlags the attribute flags
1369 * @param message the message with the data
1370 */
1371 private void actionsBgpUpdateAttributeFlagsError(
1372 ChannelHandlerContext ctx,
1373 int attrTypeCode,
1374 int attrLen,
1375 int attrFlags,
1376 ChannelBuffer message) {
1377 log.debug("BGP RX UPDATE Error from {}: Attribute Flags Error",
1378 remoteAddress);
1379
1380 //
1381 // ERROR: Attribute Flags Error
1382 //
1383 // Send NOTIFICATION and close the connection
1384 int errorCode = UpdateMessageError.ERROR_CODE;
1385 int errorSubcode = UpdateMessageError.ATTRIBUTE_FLAGS_ERROR;
1386 ChannelBuffer data =
1387 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1388 attrFlags, message);
1389 ChannelBuffer txMessage =
1390 prepareBgpNotification(errorCode, errorSubcode, data);
1391 ctx.getChannel().write(txMessage);
1392 closeChannel(ctx);
1393 }
1394
1395 /**
1396 * Applies the appropriate actions after detecting BGP UPDATE
1397 * Invalid NEXT_HOP Attribute Error: send NOTIFICATION and close the
1398 * channel.
1399 *
1400 * @param ctx the Channel Handler Context
1401 * @param attrTypeCode the attribute type code
1402 * @param attrLen the attribute length (in octets)
1403 * @param attrFlags the attribute flags
1404 * @param message the message with the data
1405 * @param nextHop the NEXT_HOP attribute value
1406 */
1407 private void actionsBgpUpdateInvalidNextHopAttribute(
1408 ChannelHandlerContext ctx,
1409 int attrTypeCode,
1410 int attrLen,
1411 int attrFlags,
1412 ChannelBuffer message,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001413 Ip4Address nextHop) {
Jonathan Hartab63aac2014-10-16 08:52:55 -07001414 log.debug("BGP RX UPDATE Error from {}: Invalid NEXT_HOP Attribute {}",
1415 remoteAddress, nextHop);
1416
1417 //
1418 // ERROR: Invalid ORIGIN Attribute
1419 //
1420 // Send NOTIFICATION and close the connection
1421 int errorCode = UpdateMessageError.ERROR_CODE;
1422 int errorSubcode = UpdateMessageError.INVALID_NEXT_HOP_ATTRIBUTE;
1423 ChannelBuffer data =
1424 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1425 attrFlags, message);
1426 ChannelBuffer txMessage =
1427 prepareBgpNotification(errorCode, errorSubcode, data);
1428 ctx.getChannel().write(txMessage);
1429 closeChannel(ctx);
1430 }
1431
1432 /**
1433 * Applies the appropriate actions after detecting BGP UPDATE
1434 * Unrecognized Well-known Attribute Error: send NOTIFICATION and close
1435 * the channel.
1436 *
1437 * @param ctx the Channel Handler Context
1438 * @param attrTypeCode the attribute type code
1439 * @param attrLen the attribute length (in octets)
1440 * @param attrFlags the attribute flags
1441 * @param message the message with the data
1442 */
1443 private void actionsBgpUpdateUnrecognizedWellKnownAttribute(
1444 ChannelHandlerContext ctx,
1445 int attrTypeCode,
1446 int attrLen,
1447 int attrFlags,
1448 ChannelBuffer message) {
1449 log.debug("BGP RX UPDATE Error from {}: " +
1450 "Unrecognized Well-known Attribute Error: {}",
1451 remoteAddress, attrTypeCode);
1452
1453 //
1454 // ERROR: Unrecognized Well-known Attribute
1455 //
1456 // Send NOTIFICATION and close the connection
1457 int errorCode = UpdateMessageError.ERROR_CODE;
1458 int errorSubcode =
1459 UpdateMessageError.UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE;
1460 ChannelBuffer data =
1461 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1462 attrFlags, message);
1463 ChannelBuffer txMessage =
1464 prepareBgpNotification(errorCode, errorSubcode, data);
1465 ctx.getChannel().write(txMessage);
1466 closeChannel(ctx);
1467 }
1468
1469 /**
1470 * Applies the appropriate actions after detecting BGP UPDATE
1471 * Attribute Length Error: send NOTIFICATION and close the channel.
1472 *
1473 * @param ctx the Channel Handler Context
1474 * @param attrTypeCode the attribute type code
1475 * @param attrLen the attribute length (in octets)
1476 * @param attrFlags the attribute flags
1477 * @param message the message with the data
1478 */
1479 private void actionsBgpUpdateAttributeLengthError(
1480 ChannelHandlerContext ctx,
1481 int attrTypeCode,
1482 int attrLen,
1483 int attrFlags,
1484 ChannelBuffer message) {
1485 log.debug("BGP RX UPDATE Error from {}: Attribute Length Error",
1486 remoteAddress);
1487
1488 //
1489 // ERROR: Attribute Length Error
1490 //
1491 // Send NOTIFICATION and close the connection
1492 int errorCode = UpdateMessageError.ERROR_CODE;
1493 int errorSubcode = UpdateMessageError.ATTRIBUTE_LENGTH_ERROR;
1494 ChannelBuffer data =
1495 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1496 attrFlags, message);
1497 ChannelBuffer txMessage =
1498 prepareBgpNotification(errorCode, errorSubcode, data);
1499 ctx.getChannel().write(txMessage);
1500 closeChannel(ctx);
1501 }
1502
1503 /**
1504 * Applies the appropriate actions after detecting BGP UPDATE
1505 * Malformed AS_PATH Error: send NOTIFICATION and close the channel.
1506 *
1507 * @param ctx the Channel Handler Context
1508 */
1509 private void actionsBgpUpdateMalformedAsPath(
1510 ChannelHandlerContext ctx) {
1511 log.debug("BGP RX UPDATE Error from {}: Malformed AS Path",
1512 remoteAddress);
1513
1514 //
1515 // ERROR: Malformed AS_PATH
1516 //
1517 // Send NOTIFICATION and close the connection
1518 int errorCode = UpdateMessageError.ERROR_CODE;
1519 int errorSubcode = UpdateMessageError.MALFORMED_AS_PATH;
1520 ChannelBuffer txMessage =
1521 prepareBgpNotification(errorCode, errorSubcode, null);
1522 ctx.getChannel().write(txMessage);
1523 closeChannel(ctx);
1524 }
1525
1526 /**
1527 * Processes BGP NOTIFICATION message.
1528 *
1529 * @param ctx the Channel Handler Context
1530 * @param message the message to process
1531 */
1532 void processBgpNotification(ChannelHandlerContext ctx,
1533 ChannelBuffer message) {
1534 int minLength =
1535 BgpConstants.BGP_NOTIFICATION_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
1536 if (message.readableBytes() < minLength) {
1537 log.debug("BGP RX NOTIFICATION Error from {}: " +
1538 "Message length {} too short. Must be at least {}",
1539 remoteAddress, message.readableBytes(), minLength);
1540 //
1541 // ERROR: Bad Message Length
1542 //
1543 // NOTE: We do NOT send NOTIFICATION in response to a notification
1544 return;
1545 }
1546
1547 //
1548 // Parse the NOTIFICATION message
1549 //
1550 int errorCode = message.readUnsignedByte();
1551 int errorSubcode = message.readUnsignedByte();
1552 int dataLength = message.readableBytes();
1553
1554 log.debug("BGP RX NOTIFICATION message from {}: Error Code {} " +
1555 "Error Subcode {} Data Length {}",
1556 remoteAddress, errorCode, errorSubcode, dataLength);
1557
1558 //
1559 // NOTE: If the peer sent a NOTIFICATION, we leave it to the peer to
1560 // close the connection.
1561 //
1562
1563 // Start the Session Timeout timer
1564 restartSessionTimeoutTimer(ctx);
1565 }
1566
1567 /**
1568 * Processes BGP KEEPALIVE message.
1569 *
1570 * @param ctx the Channel Handler Context
1571 * @param message the message to process
1572 */
1573 void processBgpKeepalive(ChannelHandlerContext ctx,
1574 ChannelBuffer message) {
1575 if (message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH !=
1576 BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH) {
1577 log.debug("BGP RX KEEPALIVE Error from {}: " +
1578 "Invalid total message length {}. Expected {}",
1579 remoteAddress,
1580 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH,
1581 BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH);
1582 //
1583 // ERROR: Bad Message Length
1584 //
1585 // Send NOTIFICATION and close the connection
1586 ChannelBuffer txMessage = prepareBgpNotificationBadMessageLength(
1587 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
1588 ctx.getChannel().write(txMessage);
1589 closeChannel(ctx);
1590 return;
1591 }
1592
1593 //
1594 // Parse the KEEPALIVE message: nothing to do
1595 //
Jonathan Hartec2df012014-10-23 16:40:24 -07001596 log.trace("BGP RX KEEPALIVE message from {}", remoteAddress);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001597
1598 // Start the Session Timeout timer
1599 restartSessionTimeoutTimer(ctx);
1600 }
1601
1602 /**
1603 * Prepares BGP OPEN message.
1604 *
1605 * @return the message to transmit (BGP header included)
1606 */
1607 private ChannelBuffer prepareBgpOpen() {
1608 ChannelBuffer message =
1609 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
1610
1611 //
1612 // Prepare the OPEN message payload
1613 //
1614 message.writeByte(localBgpVersion);
1615 message.writeShort((int) localAs);
1616 message.writeShort((int) localHoldtime);
Jonathan Hartbcae7bd2014-10-16 10:24:41 -07001617 message.writeInt(bgpSessionManager.getMyBgpId().toInt());
Jonathan Hartab63aac2014-10-16 08:52:55 -07001618 message.writeByte(0); // No Optional Parameters
1619 return prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN, message);
1620 }
1621
1622 /**
1623 * Prepares BGP KEEPALIVE message.
1624 *
1625 * @return the message to transmit (BGP header included)
1626 */
1627 private ChannelBuffer prepareBgpKeepalive() {
1628 ChannelBuffer message =
1629 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
1630
1631 //
1632 // Prepare the KEEPALIVE message payload: nothing to do
1633 //
1634 return prepareBgpMessage(BgpConstants.BGP_TYPE_KEEPALIVE, message);
1635 }
1636
1637 /**
1638 * Prepares BGP NOTIFICATION message.
1639 *
1640 * @param errorCode the BGP NOTIFICATION Error Code
1641 * @param errorSubcode the BGP NOTIFICATION Error Subcode if applicable,
1642 * otherwise BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC
Thomas Vachuska4b420772014-10-30 16:46:17 -07001643 * @param data the BGP NOTIFICATION Data if applicable, otherwise null
Jonathan Hartab63aac2014-10-16 08:52:55 -07001644 * @return the message to transmit (BGP header included)
1645 */
1646 ChannelBuffer prepareBgpNotification(int errorCode, int errorSubcode,
1647 ChannelBuffer data) {
1648 ChannelBuffer message =
1649 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
1650
1651 //
1652 // Prepare the NOTIFICATION message payload
1653 //
1654 message.writeByte(errorCode);
1655 message.writeByte(errorSubcode);
1656 if (data != null) {
1657 message.writeBytes(data);
1658 }
1659 return prepareBgpMessage(BgpConstants.BGP_TYPE_NOTIFICATION, message);
1660 }
1661
1662 /**
1663 * Prepares BGP NOTIFICATION message: Bad Message Length.
1664 *
1665 * @param length the erroneous Length field
1666 * @return the message to transmit (BGP header included)
1667 */
1668 ChannelBuffer prepareBgpNotificationBadMessageLength(int length) {
1669 int errorCode = MessageHeaderError.ERROR_CODE;
1670 int errorSubcode = MessageHeaderError.BAD_MESSAGE_LENGTH;
1671 ChannelBuffer data = ChannelBuffers.buffer(2);
1672 data.writeShort(length);
1673
1674 return prepareBgpNotification(errorCode, errorSubcode, data);
1675 }
1676
1677 /**
1678 * Prepares BGP UPDATE Notification data payload.
1679 *
1680 * @param attrTypeCode the attribute type code
1681 * @param attrLen the attribute length (in octets)
1682 * @param attrFlags the attribute flags
1683 * @param message the message with the data
1684 * @return the buffer with the data payload for the BGP UPDATE Notification
1685 */
1686 private ChannelBuffer prepareBgpUpdateNotificationDataPayload(
1687 int attrTypeCode,
1688 int attrLen,
1689 int attrFlags,
1690 ChannelBuffer message) {
1691 // Compute the attribute length field octets
1692 boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
1693 int attrLenOctets = 1;
1694 if (extendedLengthBit) {
1695 attrLenOctets = 2;
1696 }
1697 ChannelBuffer data =
1698 ChannelBuffers.buffer(attrLen + attrLenOctets + 1);
1699 data.writeByte(attrTypeCode);
1700 if (extendedLengthBit) {
1701 data.writeShort(attrLen);
1702 } else {
1703 data.writeByte(attrLen);
1704 }
1705 data.writeBytes(message, attrLen);
1706 return data;
1707 }
1708
1709 /**
1710 * Prepares BGP message.
1711 *
1712 * @param type the BGP message type
1713 * @param payload the message payload to transmit (BGP header excluded)
1714 * @return the message to transmit (BGP header included)
1715 */
1716 private ChannelBuffer prepareBgpMessage(int type, ChannelBuffer payload) {
1717 ChannelBuffer message =
1718 ChannelBuffers.buffer(BgpConstants.BGP_HEADER_LENGTH +
1719 payload.readableBytes());
1720
1721 // Write the marker
1722 for (int i = 0; i < BgpConstants.BGP_HEADER_MARKER_LENGTH; i++) {
1723 message.writeByte(0xff);
1724 }
1725
1726 // Write the rest of the BGP header
1727 message.writeShort(BgpConstants.BGP_HEADER_LENGTH +
1728 payload.readableBytes());
1729 message.writeByte(type);
1730
1731 // Write the payload
1732 message.writeBytes(payload);
1733 return message;
1734 }
1735
1736 /**
1737 * Restarts the BGP KeepaliveTimer.
1738 */
1739 private void restartKeepaliveTimer(ChannelHandlerContext ctx) {
1740 if (localKeepaliveInterval == 0) {
1741 return; // Nothing to do
1742 }
1743 keepaliveTimeout = timer.newTimeout(new TransmitKeepaliveTask(ctx),
1744 localKeepaliveInterval,
1745 TimeUnit.SECONDS);
1746 }
1747
1748 /**
1749 * Task class for transmitting KEEPALIVE messages.
1750 */
1751 private final class TransmitKeepaliveTask implements TimerTask {
1752 private final ChannelHandlerContext ctx;
1753
1754 /**
1755 * Constructor for given Channel Handler Context.
1756 *
1757 * @param ctx the Channel Handler Context to use
1758 */
1759 TransmitKeepaliveTask(ChannelHandlerContext ctx) {
1760 this.ctx = ctx;
1761 }
1762
1763 @Override
1764 public void run(Timeout timeout) throws Exception {
1765 if (timeout.isCancelled()) {
1766 return;
1767 }
1768 if (!ctx.getChannel().isOpen()) {
1769 return;
1770 }
1771
1772 // Transmit the KEEPALIVE
1773 ChannelBuffer txMessage = prepareBgpKeepalive();
1774 ctx.getChannel().write(txMessage);
1775
1776 // Restart the KEEPALIVE timer
1777 restartKeepaliveTimer(ctx);
1778 }
1779 }
1780
1781 /**
1782 * Restarts the BGP Session Timeout Timer.
1783 */
1784 private void restartSessionTimeoutTimer(ChannelHandlerContext ctx) {
1785 if (remoteHoldtime == 0) {
1786 return; // Nothing to do
1787 }
1788 if (sessionTimeout != null) {
1789 sessionTimeout.cancel();
1790 }
1791 sessionTimeout = timer.newTimeout(new SessionTimeoutTask(ctx),
1792 remoteHoldtime,
1793 TimeUnit.SECONDS);
1794 }
1795
1796 /**
1797 * Task class for BGP Session timeout.
1798 */
1799 private final class SessionTimeoutTask implements TimerTask {
1800 private final ChannelHandlerContext ctx;
1801
1802 /**
1803 * Constructor for given Channel Handler Context.
1804 *
1805 * @param ctx the Channel Handler Context to use
1806 */
1807 SessionTimeoutTask(ChannelHandlerContext ctx) {
1808 this.ctx = ctx;
1809 }
1810
1811 @Override
1812 public void run(Timeout timeout) throws Exception {
1813 if (timeout.isCancelled()) {
1814 return;
1815 }
1816 if (!ctx.getChannel().isOpen()) {
1817 return;
1818 }
1819
1820 log.debug("BGP Session Timeout: peer {}", remoteAddress);
1821 //
1822 // ERROR: Invalid Optional Parameter Length field: Unspecific
1823 //
1824 // Send NOTIFICATION and close the connection
1825 int errorCode = HoldTimerExpired.ERROR_CODE;
1826 int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
1827 ChannelBuffer txMessage =
1828 prepareBgpNotification(errorCode, errorSubcode, null);
1829 ctx.getChannel().write(txMessage);
1830 closeChannel(ctx);
1831 }
1832 }
1833
1834 /**
1835 * An exception indicating a parsing error of the BGP message.
1836 */
1837 private static class BgpParseException extends Exception {
1838 /**
1839 * Default constructor.
1840 */
1841 public BgpParseException() {
1842 super();
1843 }
1844
1845 /**
1846 * Constructor for a specific exception details message.
1847 *
1848 * @param message the message with the exception details
1849 */
1850 public BgpParseException(String message) {
1851 super(message);
1852 }
1853 }
1854}