blob: e0a710a1c2aac2aeeb53aafc6ced6f236f249f09 [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:
Pavlin Radoslavov49eb64d2014-11-10 17:03:19 -0800978 // FALLTHROUGH
979 case BgpConstants.Update.AsPath.AS_CONFED_SEQUENCE:
980 // FALLTHROUGH
981 case BgpConstants.Update.AsPath.AS_CONFED_SET:
Jonathan Hartab63aac2014-10-16 08:52:55 -0700982 break;
983 default:
984 // ERROR: Invalid Path Segment Type
985 //
986 // NOTE: The BGP Spec (RFC 4271) doesn't contain Error Subcode
987 // for "Invalid Path Segment Type", hence we return
988 // the error as "Malformed AS_PATH".
989 //
990 actionsBgpUpdateMalformedAsPath(ctx);
991 String errorMsg =
992 "Invalid AS Path Segment Type: " + pathSegmentType;
993 throw new BgpParseException(errorMsg);
994 }
995
996 // Parse the AS numbers
997 if (2 * pathSegmentLength > attrLen) {
998 // ERROR: Malformed AS_PATH
999 actionsBgpUpdateMalformedAsPath(ctx);
1000 String errorMsg = "Malformed AS Path";
1001 throw new BgpParseException(errorMsg);
1002 }
1003 attrLen -= (2 * pathSegmentLength);
1004 ArrayList<Long> segmentAsNumbers = new ArrayList<>();
1005 while (pathSegmentLength-- > 0) {
1006 long asNumber = message.readUnsignedShort();
1007 segmentAsNumbers.add(asNumber);
1008 }
1009
1010 BgpRouteEntry.PathSegment pathSegment =
1011 new BgpRouteEntry.PathSegment((byte) pathSegmentType,
1012 segmentAsNumbers);
1013 pathSegments.add(pathSegment);
1014 }
1015
1016 return new BgpRouteEntry.AsPath(pathSegments);
1017 }
1018
1019 /**
1020 * Parses BGP UPDATE Attribute Type NEXT_HOP.
1021 *
1022 * @param ctx the Channel Handler Context
1023 * @param attrTypeCode the attribute type code
1024 * @param attrLen the attribute length (in octets)
1025 * @param attrFlags the attribute flags
1026 * @param message the message to parse
1027 * @return the parsed NEXT_HOP value
1028 * @throws BgpParseException
1029 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001030 private Ip4Address parseAttributeTypeNextHop(
Jonathan Hartab63aac2014-10-16 08:52:55 -07001031 ChannelHandlerContext ctx,
1032 int attrTypeCode,
1033 int attrLen,
1034 int attrFlags,
1035 ChannelBuffer message)
1036 throws BgpParseException {
1037
1038 // Check the Attribute Length
1039 if (attrLen != BgpConstants.Update.NextHop.LENGTH) {
1040 // ERROR: Attribute Length Error
1041 actionsBgpUpdateAttributeLengthError(
1042 ctx, attrTypeCode, attrLen, attrFlags, message);
1043 String errorMsg = "Attribute Length Error";
1044 throw new BgpParseException(errorMsg);
1045 }
1046
1047 message.markReaderIndex();
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001048 Ip4Address nextHopAddress =
1049 Ip4Address.valueOf((int) message.readUnsignedInt());
Jonathan Hartab63aac2014-10-16 08:52:55 -07001050 //
1051 // Check whether the NEXT_HOP IP address is semantically correct.
1052 // As per RFC 4271, Section 6.3:
1053 //
1054 // a) It MUST NOT be the IP address of the receiving speaker
1055 // b) In the case of an EBGP ....
1056 //
1057 // Here we check only (a), because (b) doesn't apply for us: all our
1058 // peers are iBGP.
1059 //
1060 if (nextHopAddress.equals(localIp4Address)) {
1061 // ERROR: Invalid NEXT_HOP Attribute
1062 message.resetReaderIndex();
1063 actionsBgpUpdateInvalidNextHopAttribute(
1064 ctx, attrTypeCode, attrLen, attrFlags, message,
1065 nextHopAddress);
1066 String errorMsg = "Invalid NEXT_HOP Attribute: " + nextHopAddress;
1067 throw new BgpParseException(errorMsg);
1068 }
1069
1070 return nextHopAddress;
1071 }
1072
1073 /**
1074 * Parses BGP UPDATE Attribute Type MULTI_EXIT_DISC.
1075 *
1076 * @param ctx the Channel Handler Context
1077 * @param attrTypeCode the attribute type code
1078 * @param attrLen the attribute length (in octets)
1079 * @param attrFlags the attribute flags
1080 * @param message the message to parse
1081 * @return the parsed MULTI_EXIT_DISC value
1082 * @throws BgpParseException
1083 */
1084 private long parseAttributeTypeMultiExitDisc(
1085 ChannelHandlerContext ctx,
1086 int attrTypeCode,
1087 int attrLen,
1088 int attrFlags,
1089 ChannelBuffer message)
1090 throws BgpParseException {
1091
1092 // Check the Attribute Length
1093 if (attrLen != BgpConstants.Update.MultiExitDisc.LENGTH) {
1094 // ERROR: Attribute Length Error
1095 actionsBgpUpdateAttributeLengthError(
1096 ctx, attrTypeCode, attrLen, attrFlags, message);
1097 String errorMsg = "Attribute Length Error";
1098 throw new BgpParseException(errorMsg);
1099 }
1100
1101 long multiExitDisc = message.readUnsignedInt();
1102 return multiExitDisc;
1103 }
1104
1105 /**
1106 * Parses BGP UPDATE Attribute Type LOCAL_PREF.
1107 *
1108 * @param ctx the Channel Handler Context
1109 * @param attrTypeCode the attribute type code
1110 * @param attrLen the attribute length (in octets)
1111 * @param attrFlags the attribute flags
1112 * @param message the message to parse
1113 * @return the parsed LOCAL_PREF value
1114 * @throws BgpParseException
1115 */
1116 private long parseAttributeTypeLocalPref(
1117 ChannelHandlerContext ctx,
1118 int attrTypeCode,
1119 int attrLen,
1120 int attrFlags,
1121 ChannelBuffer message)
1122 throws BgpParseException {
1123
1124 // Check the Attribute Length
1125 if (attrLen != BgpConstants.Update.LocalPref.LENGTH) {
1126 // ERROR: Attribute Length Error
1127 actionsBgpUpdateAttributeLengthError(
1128 ctx, attrTypeCode, attrLen, attrFlags, message);
1129 String errorMsg = "Attribute Length Error";
1130 throw new BgpParseException(errorMsg);
1131 }
1132
1133 long localPref = message.readUnsignedInt();
1134 return localPref;
1135 }
1136
1137 /**
1138 * Parses BGP UPDATE Attribute Type ATOMIC_AGGREGATE.
1139 *
1140 * @param ctx the Channel Handler Context
1141 * @param attrTypeCode the attribute type code
1142 * @param attrLen the attribute length (in octets)
1143 * @param attrFlags the attribute flags
1144 * @param message the message to parse
1145 * @throws BgpParseException
1146 */
1147 private void parseAttributeTypeAtomicAggregate(
1148 ChannelHandlerContext ctx,
1149 int attrTypeCode,
1150 int attrLen,
1151 int attrFlags,
1152 ChannelBuffer message)
1153 throws BgpParseException {
1154
1155 // Check the Attribute Length
1156 if (attrLen != BgpConstants.Update.AtomicAggregate.LENGTH) {
1157 // ERROR: Attribute Length Error
1158 actionsBgpUpdateAttributeLengthError(
1159 ctx, attrTypeCode, attrLen, attrFlags, message);
1160 String errorMsg = "Attribute Length Error";
1161 throw new BgpParseException(errorMsg);
1162 }
1163
1164 // Nothing to do: this attribute is primarily informational
1165 }
1166
1167 /**
1168 * Parses BGP UPDATE Attribute Type AGGREGATOR.
1169 *
1170 * @param ctx the Channel Handler Context
1171 * @param attrTypeCode the attribute type code
1172 * @param attrLen the attribute length (in octets)
1173 * @param attrFlags the attribute flags
1174 * @param message the message to parse
1175 * @return the parsed AGGREGATOR value: a tuple of <AS-Number, IP-Address>
1176 * @throws BgpParseException
1177 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001178 private Pair<Long, Ip4Address> parseAttributeTypeAggregator(
Jonathan Hartab63aac2014-10-16 08:52:55 -07001179 ChannelHandlerContext ctx,
1180 int attrTypeCode,
1181 int attrLen,
1182 int attrFlags,
1183 ChannelBuffer message)
1184 throws BgpParseException {
1185
1186 // Check the Attribute Length
1187 if (attrLen != BgpConstants.Update.Aggregator.LENGTH) {
1188 // ERROR: Attribute Length Error
1189 actionsBgpUpdateAttributeLengthError(
1190 ctx, attrTypeCode, attrLen, attrFlags, message);
1191 String errorMsg = "Attribute Length Error";
1192 throw new BgpParseException(errorMsg);
1193 }
1194
1195 // The AGGREGATOR AS number
1196 long aggregatorAsNumber = message.readUnsignedShort();
1197 // The AGGREGATOR IP address
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001198 Ip4Address aggregatorIpAddress =
1199 Ip4Address.valueOf((int) message.readUnsignedInt());
Jonathan Hartab63aac2014-10-16 08:52:55 -07001200
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001201 Pair<Long, Ip4Address> aggregator = Pair.of(aggregatorAsNumber,
Jonathan Hartab63aac2014-10-16 08:52:55 -07001202 aggregatorIpAddress);
1203 return aggregator;
1204 }
1205
1206 /**
1207 * Parses a message that contains encoded IPv4 network prefixes.
1208 * <p>
1209 * The IPv4 prefixes are encoded in the form:
1210 * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
1211 * and Prefix is the IPv4 prefix (padded with trailing bits to the end
1212 * of an octet).
1213 *
1214 * @param totalLength the total length of the data to parse
1215 * @param message the message with data to parse
1216 * @return a collection of parsed IPv4 network prefixes
1217 * @throws BgpParseException
1218 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001219 private Collection<Ip4Prefix> parsePackedPrefixes(int totalLength,
Jonathan Hartab63aac2014-10-16 08:52:55 -07001220 ChannelBuffer message)
1221 throws BgpParseException {
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001222 Collection<Ip4Prefix> result = new ArrayList<>();
Jonathan Hartab63aac2014-10-16 08:52:55 -07001223
1224 if (totalLength == 0) {
1225 return result;
1226 }
1227
1228 // Parse the data
1229 int dataEnd = message.readerIndex() + totalLength;
1230 while (message.readerIndex() < dataEnd) {
1231 int prefixBitlen = message.readUnsignedByte();
1232 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
1233 if (message.readerIndex() + prefixBytelen > dataEnd) {
1234 String errorMsg = "Malformed Network Prefixes";
1235 throw new BgpParseException(errorMsg);
1236 }
1237
1238 long address = 0;
1239 long extraShift = (4 - prefixBytelen) * 8;
1240 while (prefixBytelen > 0) {
1241 address <<= 8;
1242 address |= message.readUnsignedByte();
1243 prefixBytelen--;
1244 }
1245 address <<= extraShift;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001246 Ip4Prefix prefix =
1247 Ip4Prefix.valueOf(Ip4Address.valueOf((int) address),
1248 prefixBitlen);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001249 result.add(prefix);
1250 }
1251
1252 return result;
1253 }
1254
1255 /**
1256 * Applies the appropriate actions after detecting BGP UPDATE
1257 * Invalid Network Field Error: send NOTIFICATION and close the channel.
1258 *
1259 * @param ctx the Channel Handler Context
1260 */
1261 private void actionsBgpUpdateInvalidNetworkField(
1262 ChannelHandlerContext ctx) {
1263 log.debug("BGP RX UPDATE Error from {}: Invalid Network Field",
1264 remoteAddress);
1265
1266 //
1267 // ERROR: Invalid Network Field
1268 //
1269 // Send NOTIFICATION and close the connection
1270 int errorCode = UpdateMessageError.ERROR_CODE;
1271 int errorSubcode = UpdateMessageError.INVALID_NETWORK_FIELD;
1272 ChannelBuffer txMessage =
1273 prepareBgpNotification(errorCode, errorSubcode, null);
1274 ctx.getChannel().write(txMessage);
1275 closeChannel(ctx);
1276 }
1277
1278 /**
1279 * Applies the appropriate actions after detecting BGP UPDATE
1280 * Malformed Attribute List Error: send NOTIFICATION and close the channel.
1281 *
1282 * @param ctx the Channel Handler Context
1283 */
1284 private void actionsBgpUpdateMalformedAttributeList(
1285 ChannelHandlerContext ctx) {
1286 log.debug("BGP RX UPDATE Error from {}: Malformed Attribute List",
1287 remoteAddress);
1288
1289 //
1290 // ERROR: Malformed Attribute List
1291 //
1292 // Send NOTIFICATION and close the connection
1293 int errorCode = UpdateMessageError.ERROR_CODE;
1294 int errorSubcode = UpdateMessageError.MALFORMED_ATTRIBUTE_LIST;
1295 ChannelBuffer txMessage =
1296 prepareBgpNotification(errorCode, errorSubcode, null);
1297 ctx.getChannel().write(txMessage);
1298 closeChannel(ctx);
1299 }
1300
1301 /**
1302 * Applies the appropriate actions after detecting BGP UPDATE
1303 * Missing Well-known Attribute Error: send NOTIFICATION and close the
1304 * channel.
1305 *
1306 * @param ctx the Channel Handler Context
1307 * @param missingAttrTypeCode the missing attribute type code
1308 */
1309 private void actionsBgpUpdateMissingWellKnownAttribute(
1310 ChannelHandlerContext ctx,
1311 int missingAttrTypeCode) {
1312 log.debug("BGP RX UPDATE Error from {}: Missing Well-known Attribute: {}",
1313 remoteAddress, missingAttrTypeCode);
1314
1315 //
1316 // ERROR: Missing Well-known Attribute
1317 //
1318 // Send NOTIFICATION and close the connection
1319 int errorCode = UpdateMessageError.ERROR_CODE;
1320 int errorSubcode = UpdateMessageError.MISSING_WELL_KNOWN_ATTRIBUTE;
1321 ChannelBuffer data = ChannelBuffers.buffer(1);
1322 data.writeByte(missingAttrTypeCode);
1323 ChannelBuffer txMessage =
1324 prepareBgpNotification(errorCode, errorSubcode, data);
1325 ctx.getChannel().write(txMessage);
1326 closeChannel(ctx);
1327 }
1328
1329 /**
1330 * Applies the appropriate actions after detecting BGP UPDATE
1331 * Invalid ORIGIN Attribute Error: send NOTIFICATION and close the channel.
1332 *
1333 * @param ctx the Channel Handler Context
1334 * @param attrTypeCode the attribute type code
1335 * @param attrLen the attribute length (in octets)
1336 * @param attrFlags the attribute flags
1337 * @param message the message with the data
1338 * @param origin the ORIGIN attribute value
1339 */
1340 private void actionsBgpUpdateInvalidOriginAttribute(
1341 ChannelHandlerContext ctx,
1342 int attrTypeCode,
1343 int attrLen,
1344 int attrFlags,
1345 ChannelBuffer message,
1346 short origin) {
1347 log.debug("BGP RX UPDATE Error from {}: Invalid ORIGIN Attribute",
1348 remoteAddress);
1349
1350 //
1351 // ERROR: Invalid ORIGIN Attribute
1352 //
1353 // Send NOTIFICATION and close the connection
1354 int errorCode = UpdateMessageError.ERROR_CODE;
1355 int errorSubcode = UpdateMessageError.INVALID_ORIGIN_ATTRIBUTE;
1356 ChannelBuffer data =
1357 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1358 attrFlags, message);
1359 ChannelBuffer txMessage =
1360 prepareBgpNotification(errorCode, errorSubcode, data);
1361 ctx.getChannel().write(txMessage);
1362 closeChannel(ctx);
1363 }
1364
1365 /**
1366 * Applies the appropriate actions after detecting BGP UPDATE
1367 * Attribute Flags Error: send NOTIFICATION and close the channel.
1368 *
1369 * @param ctx the Channel Handler Context
1370 * @param attrTypeCode the attribute type code
1371 * @param attrLen the attribute length (in octets)
1372 * @param attrFlags the attribute flags
1373 * @param message the message with the data
1374 */
1375 private void actionsBgpUpdateAttributeFlagsError(
1376 ChannelHandlerContext ctx,
1377 int attrTypeCode,
1378 int attrLen,
1379 int attrFlags,
1380 ChannelBuffer message) {
1381 log.debug("BGP RX UPDATE Error from {}: Attribute Flags Error",
1382 remoteAddress);
1383
1384 //
1385 // ERROR: Attribute Flags Error
1386 //
1387 // Send NOTIFICATION and close the connection
1388 int errorCode = UpdateMessageError.ERROR_CODE;
1389 int errorSubcode = UpdateMessageError.ATTRIBUTE_FLAGS_ERROR;
1390 ChannelBuffer data =
1391 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1392 attrFlags, message);
1393 ChannelBuffer txMessage =
1394 prepareBgpNotification(errorCode, errorSubcode, data);
1395 ctx.getChannel().write(txMessage);
1396 closeChannel(ctx);
1397 }
1398
1399 /**
1400 * Applies the appropriate actions after detecting BGP UPDATE
1401 * Invalid NEXT_HOP Attribute Error: send NOTIFICATION and close the
1402 * channel.
1403 *
1404 * @param ctx the Channel Handler Context
1405 * @param attrTypeCode the attribute type code
1406 * @param attrLen the attribute length (in octets)
1407 * @param attrFlags the attribute flags
1408 * @param message the message with the data
1409 * @param nextHop the NEXT_HOP attribute value
1410 */
1411 private void actionsBgpUpdateInvalidNextHopAttribute(
1412 ChannelHandlerContext ctx,
1413 int attrTypeCode,
1414 int attrLen,
1415 int attrFlags,
1416 ChannelBuffer message,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001417 Ip4Address nextHop) {
Jonathan Hartab63aac2014-10-16 08:52:55 -07001418 log.debug("BGP RX UPDATE Error from {}: Invalid NEXT_HOP Attribute {}",
1419 remoteAddress, nextHop);
1420
1421 //
1422 // ERROR: Invalid ORIGIN Attribute
1423 //
1424 // Send NOTIFICATION and close the connection
1425 int errorCode = UpdateMessageError.ERROR_CODE;
1426 int errorSubcode = UpdateMessageError.INVALID_NEXT_HOP_ATTRIBUTE;
1427 ChannelBuffer data =
1428 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1429 attrFlags, message);
1430 ChannelBuffer txMessage =
1431 prepareBgpNotification(errorCode, errorSubcode, data);
1432 ctx.getChannel().write(txMessage);
1433 closeChannel(ctx);
1434 }
1435
1436 /**
1437 * Applies the appropriate actions after detecting BGP UPDATE
1438 * Unrecognized Well-known Attribute Error: send NOTIFICATION and close
1439 * the channel.
1440 *
1441 * @param ctx the Channel Handler Context
1442 * @param attrTypeCode the attribute type code
1443 * @param attrLen the attribute length (in octets)
1444 * @param attrFlags the attribute flags
1445 * @param message the message with the data
1446 */
1447 private void actionsBgpUpdateUnrecognizedWellKnownAttribute(
1448 ChannelHandlerContext ctx,
1449 int attrTypeCode,
1450 int attrLen,
1451 int attrFlags,
1452 ChannelBuffer message) {
1453 log.debug("BGP RX UPDATE Error from {}: " +
1454 "Unrecognized Well-known Attribute Error: {}",
1455 remoteAddress, attrTypeCode);
1456
1457 //
1458 // ERROR: Unrecognized Well-known Attribute
1459 //
1460 // Send NOTIFICATION and close the connection
1461 int errorCode = UpdateMessageError.ERROR_CODE;
1462 int errorSubcode =
1463 UpdateMessageError.UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE;
1464 ChannelBuffer data =
1465 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1466 attrFlags, message);
1467 ChannelBuffer txMessage =
1468 prepareBgpNotification(errorCode, errorSubcode, data);
1469 ctx.getChannel().write(txMessage);
1470 closeChannel(ctx);
1471 }
1472
1473 /**
1474 * Applies the appropriate actions after detecting BGP UPDATE
1475 * Attribute Length Error: send NOTIFICATION and close the channel.
1476 *
1477 * @param ctx the Channel Handler Context
1478 * @param attrTypeCode the attribute type code
1479 * @param attrLen the attribute length (in octets)
1480 * @param attrFlags the attribute flags
1481 * @param message the message with the data
1482 */
1483 private void actionsBgpUpdateAttributeLengthError(
1484 ChannelHandlerContext ctx,
1485 int attrTypeCode,
1486 int attrLen,
1487 int attrFlags,
1488 ChannelBuffer message) {
1489 log.debug("BGP RX UPDATE Error from {}: Attribute Length Error",
1490 remoteAddress);
1491
1492 //
1493 // ERROR: Attribute Length Error
1494 //
1495 // Send NOTIFICATION and close the connection
1496 int errorCode = UpdateMessageError.ERROR_CODE;
1497 int errorSubcode = UpdateMessageError.ATTRIBUTE_LENGTH_ERROR;
1498 ChannelBuffer data =
1499 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1500 attrFlags, message);
1501 ChannelBuffer txMessage =
1502 prepareBgpNotification(errorCode, errorSubcode, data);
1503 ctx.getChannel().write(txMessage);
1504 closeChannel(ctx);
1505 }
1506
1507 /**
1508 * Applies the appropriate actions after detecting BGP UPDATE
1509 * Malformed AS_PATH Error: send NOTIFICATION and close the channel.
1510 *
1511 * @param ctx the Channel Handler Context
1512 */
1513 private void actionsBgpUpdateMalformedAsPath(
1514 ChannelHandlerContext ctx) {
1515 log.debug("BGP RX UPDATE Error from {}: Malformed AS Path",
1516 remoteAddress);
1517
1518 //
1519 // ERROR: Malformed AS_PATH
1520 //
1521 // Send NOTIFICATION and close the connection
1522 int errorCode = UpdateMessageError.ERROR_CODE;
1523 int errorSubcode = UpdateMessageError.MALFORMED_AS_PATH;
1524 ChannelBuffer txMessage =
1525 prepareBgpNotification(errorCode, errorSubcode, null);
1526 ctx.getChannel().write(txMessage);
1527 closeChannel(ctx);
1528 }
1529
1530 /**
1531 * Processes BGP NOTIFICATION message.
1532 *
1533 * @param ctx the Channel Handler Context
1534 * @param message the message to process
1535 */
1536 void processBgpNotification(ChannelHandlerContext ctx,
1537 ChannelBuffer message) {
1538 int minLength =
1539 BgpConstants.BGP_NOTIFICATION_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
1540 if (message.readableBytes() < minLength) {
1541 log.debug("BGP RX NOTIFICATION Error from {}: " +
1542 "Message length {} too short. Must be at least {}",
1543 remoteAddress, message.readableBytes(), minLength);
1544 //
1545 // ERROR: Bad Message Length
1546 //
1547 // NOTE: We do NOT send NOTIFICATION in response to a notification
1548 return;
1549 }
1550
1551 //
1552 // Parse the NOTIFICATION message
1553 //
1554 int errorCode = message.readUnsignedByte();
1555 int errorSubcode = message.readUnsignedByte();
1556 int dataLength = message.readableBytes();
1557
1558 log.debug("BGP RX NOTIFICATION message from {}: Error Code {} " +
1559 "Error Subcode {} Data Length {}",
1560 remoteAddress, errorCode, errorSubcode, dataLength);
1561
1562 //
1563 // NOTE: If the peer sent a NOTIFICATION, we leave it to the peer to
1564 // close the connection.
1565 //
1566
1567 // Start the Session Timeout timer
1568 restartSessionTimeoutTimer(ctx);
1569 }
1570
1571 /**
1572 * Processes BGP KEEPALIVE message.
1573 *
1574 * @param ctx the Channel Handler Context
1575 * @param message the message to process
1576 */
1577 void processBgpKeepalive(ChannelHandlerContext ctx,
1578 ChannelBuffer message) {
1579 if (message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH !=
1580 BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH) {
1581 log.debug("BGP RX KEEPALIVE Error from {}: " +
1582 "Invalid total message length {}. Expected {}",
1583 remoteAddress,
1584 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH,
1585 BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH);
1586 //
1587 // ERROR: Bad Message Length
1588 //
1589 // Send NOTIFICATION and close the connection
1590 ChannelBuffer txMessage = prepareBgpNotificationBadMessageLength(
1591 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
1592 ctx.getChannel().write(txMessage);
1593 closeChannel(ctx);
1594 return;
1595 }
1596
1597 //
1598 // Parse the KEEPALIVE message: nothing to do
1599 //
Jonathan Hartec2df012014-10-23 16:40:24 -07001600 log.trace("BGP RX KEEPALIVE message from {}", remoteAddress);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001601
1602 // Start the Session Timeout timer
1603 restartSessionTimeoutTimer(ctx);
1604 }
1605
1606 /**
1607 * Prepares BGP OPEN message.
1608 *
1609 * @return the message to transmit (BGP header included)
1610 */
1611 private ChannelBuffer prepareBgpOpen() {
1612 ChannelBuffer message =
1613 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
1614
1615 //
1616 // Prepare the OPEN message payload
1617 //
1618 message.writeByte(localBgpVersion);
1619 message.writeShort((int) localAs);
1620 message.writeShort((int) localHoldtime);
Jonathan Hartbcae7bd2014-10-16 10:24:41 -07001621 message.writeInt(bgpSessionManager.getMyBgpId().toInt());
Jonathan Hartab63aac2014-10-16 08:52:55 -07001622 message.writeByte(0); // No Optional Parameters
1623 return prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN, message);
1624 }
1625
1626 /**
1627 * Prepares BGP KEEPALIVE message.
1628 *
1629 * @return the message to transmit (BGP header included)
1630 */
1631 private ChannelBuffer prepareBgpKeepalive() {
1632 ChannelBuffer message =
1633 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
1634
1635 //
1636 // Prepare the KEEPALIVE message payload: nothing to do
1637 //
1638 return prepareBgpMessage(BgpConstants.BGP_TYPE_KEEPALIVE, message);
1639 }
1640
1641 /**
1642 * Prepares BGP NOTIFICATION message.
1643 *
1644 * @param errorCode the BGP NOTIFICATION Error Code
1645 * @param errorSubcode the BGP NOTIFICATION Error Subcode if applicable,
1646 * otherwise BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC
Thomas Vachuska4b420772014-10-30 16:46:17 -07001647 * @param data the BGP NOTIFICATION Data if applicable, otherwise null
Jonathan Hartab63aac2014-10-16 08:52:55 -07001648 * @return the message to transmit (BGP header included)
1649 */
1650 ChannelBuffer prepareBgpNotification(int errorCode, int errorSubcode,
1651 ChannelBuffer data) {
1652 ChannelBuffer message =
1653 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
1654
1655 //
1656 // Prepare the NOTIFICATION message payload
1657 //
1658 message.writeByte(errorCode);
1659 message.writeByte(errorSubcode);
1660 if (data != null) {
1661 message.writeBytes(data);
1662 }
1663 return prepareBgpMessage(BgpConstants.BGP_TYPE_NOTIFICATION, message);
1664 }
1665
1666 /**
1667 * Prepares BGP NOTIFICATION message: Bad Message Length.
1668 *
1669 * @param length the erroneous Length field
1670 * @return the message to transmit (BGP header included)
1671 */
1672 ChannelBuffer prepareBgpNotificationBadMessageLength(int length) {
1673 int errorCode = MessageHeaderError.ERROR_CODE;
1674 int errorSubcode = MessageHeaderError.BAD_MESSAGE_LENGTH;
1675 ChannelBuffer data = ChannelBuffers.buffer(2);
1676 data.writeShort(length);
1677
1678 return prepareBgpNotification(errorCode, errorSubcode, data);
1679 }
1680
1681 /**
1682 * Prepares BGP UPDATE Notification data payload.
1683 *
1684 * @param attrTypeCode the attribute type code
1685 * @param attrLen the attribute length (in octets)
1686 * @param attrFlags the attribute flags
1687 * @param message the message with the data
1688 * @return the buffer with the data payload for the BGP UPDATE Notification
1689 */
1690 private ChannelBuffer prepareBgpUpdateNotificationDataPayload(
1691 int attrTypeCode,
1692 int attrLen,
1693 int attrFlags,
1694 ChannelBuffer message) {
1695 // Compute the attribute length field octets
1696 boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
1697 int attrLenOctets = 1;
1698 if (extendedLengthBit) {
1699 attrLenOctets = 2;
1700 }
1701 ChannelBuffer data =
1702 ChannelBuffers.buffer(attrLen + attrLenOctets + 1);
1703 data.writeByte(attrTypeCode);
1704 if (extendedLengthBit) {
1705 data.writeShort(attrLen);
1706 } else {
1707 data.writeByte(attrLen);
1708 }
1709 data.writeBytes(message, attrLen);
1710 return data;
1711 }
1712
1713 /**
1714 * Prepares BGP message.
1715 *
1716 * @param type the BGP message type
1717 * @param payload the message payload to transmit (BGP header excluded)
1718 * @return the message to transmit (BGP header included)
1719 */
1720 private ChannelBuffer prepareBgpMessage(int type, ChannelBuffer payload) {
1721 ChannelBuffer message =
1722 ChannelBuffers.buffer(BgpConstants.BGP_HEADER_LENGTH +
1723 payload.readableBytes());
1724
1725 // Write the marker
1726 for (int i = 0; i < BgpConstants.BGP_HEADER_MARKER_LENGTH; i++) {
1727 message.writeByte(0xff);
1728 }
1729
1730 // Write the rest of the BGP header
1731 message.writeShort(BgpConstants.BGP_HEADER_LENGTH +
1732 payload.readableBytes());
1733 message.writeByte(type);
1734
1735 // Write the payload
1736 message.writeBytes(payload);
1737 return message;
1738 }
1739
1740 /**
1741 * Restarts the BGP KeepaliveTimer.
1742 */
1743 private void restartKeepaliveTimer(ChannelHandlerContext ctx) {
1744 if (localKeepaliveInterval == 0) {
1745 return; // Nothing to do
1746 }
1747 keepaliveTimeout = timer.newTimeout(new TransmitKeepaliveTask(ctx),
1748 localKeepaliveInterval,
1749 TimeUnit.SECONDS);
1750 }
1751
1752 /**
1753 * Task class for transmitting KEEPALIVE messages.
1754 */
1755 private final class TransmitKeepaliveTask implements TimerTask {
1756 private final ChannelHandlerContext ctx;
1757
1758 /**
1759 * Constructor for given Channel Handler Context.
1760 *
1761 * @param ctx the Channel Handler Context to use
1762 */
1763 TransmitKeepaliveTask(ChannelHandlerContext ctx) {
1764 this.ctx = ctx;
1765 }
1766
1767 @Override
1768 public void run(Timeout timeout) throws Exception {
1769 if (timeout.isCancelled()) {
1770 return;
1771 }
1772 if (!ctx.getChannel().isOpen()) {
1773 return;
1774 }
1775
1776 // Transmit the KEEPALIVE
1777 ChannelBuffer txMessage = prepareBgpKeepalive();
1778 ctx.getChannel().write(txMessage);
1779
1780 // Restart the KEEPALIVE timer
1781 restartKeepaliveTimer(ctx);
1782 }
1783 }
1784
1785 /**
1786 * Restarts the BGP Session Timeout Timer.
1787 */
1788 private void restartSessionTimeoutTimer(ChannelHandlerContext ctx) {
1789 if (remoteHoldtime == 0) {
1790 return; // Nothing to do
1791 }
1792 if (sessionTimeout != null) {
1793 sessionTimeout.cancel();
1794 }
1795 sessionTimeout = timer.newTimeout(new SessionTimeoutTask(ctx),
1796 remoteHoldtime,
1797 TimeUnit.SECONDS);
1798 }
1799
1800 /**
1801 * Task class for BGP Session timeout.
1802 */
1803 private final class SessionTimeoutTask implements TimerTask {
1804 private final ChannelHandlerContext ctx;
1805
1806 /**
1807 * Constructor for given Channel Handler Context.
1808 *
1809 * @param ctx the Channel Handler Context to use
1810 */
1811 SessionTimeoutTask(ChannelHandlerContext ctx) {
1812 this.ctx = ctx;
1813 }
1814
1815 @Override
1816 public void run(Timeout timeout) throws Exception {
1817 if (timeout.isCancelled()) {
1818 return;
1819 }
1820 if (!ctx.getChannel().isOpen()) {
1821 return;
1822 }
1823
1824 log.debug("BGP Session Timeout: peer {}", remoteAddress);
1825 //
1826 // ERROR: Invalid Optional Parameter Length field: Unspecific
1827 //
1828 // Send NOTIFICATION and close the connection
1829 int errorCode = HoldTimerExpired.ERROR_CODE;
1830 int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
1831 ChannelBuffer txMessage =
1832 prepareBgpNotification(errorCode, errorSubcode, null);
1833 ctx.getChannel().write(txMessage);
1834 closeChannel(ctx);
1835 }
1836 }
1837
1838 /**
1839 * An exception indicating a parsing error of the BGP message.
1840 */
1841 private static class BgpParseException extends Exception {
1842 /**
1843 * Default constructor.
1844 */
1845 public BgpParseException() {
1846 super();
1847 }
1848
1849 /**
1850 * Constructor for a specific exception details message.
1851 *
1852 * @param message the message with the exception details
1853 */
1854 public BgpParseException(String message) {
1855 super(message);
1856 }
1857 }
1858}