blob: 7a3fe459b99a6e9889a81a01fb468fa565062ade [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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.sdnip.bgp;
Jonathan Hartab63aac2014-10-16 08:52:55 -070017
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;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.sdnip.bgp.BgpConstants.Notifications;
41import org.onosproject.sdnip.bgp.BgpConstants.Notifications.HoldTimerExpired;
42import org.onosproject.sdnip.bgp.BgpConstants.Notifications.MessageHeaderError;
43import org.onosproject.sdnip.bgp.BgpConstants.Notifications.OpenMessageError;
44import org.onosproject.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 /**
Jonathan Hartff071a22014-12-03 12:10:00 -0800229 * Closes the session.
230 *
231 * @param ctx the Channel Handler Context
232 */
233 void closeSession(ChannelHandlerContext ctx) {
234 timer.stop();
235 closeChannel(ctx);
236 }
237
238 /**
239 * Closes the netty channel.
Jonathan Hartab63aac2014-10-16 08:52:55 -0700240 *
241 * @param ctx the Channel Handler Context
242 */
243 void closeChannel(ChannelHandlerContext ctx) {
244 isClosed = true;
Jonathan Hartab63aac2014-10-16 08:52:55 -0700245 ctx.getChannel().close();
246 }
247
248 @Override
Pavlin Radoslavov7e190942014-11-13 18:50:59 -0800249 public void channelOpen(ChannelHandlerContext ctx,
250 ChannelStateEvent channelEvent) {
251 bgpSessionManager.addSessionChannel(channelEvent.getChannel());
252 }
253
254 @Override
255 public void channelClosed(ChannelHandlerContext ctx,
256 ChannelStateEvent channelEvent) {
257 bgpSessionManager.removeSessionChannel(channelEvent.getChannel());
258 }
259
260 @Override
Jonathan Hartab63aac2014-10-16 08:52:55 -0700261 public void channelConnected(ChannelHandlerContext ctx,
262 ChannelStateEvent channelEvent) {
263 localAddress = ctx.getChannel().getLocalAddress();
264 remoteAddress = ctx.getChannel().getRemoteAddress();
265
266 // Assign the local and remote IPv4 addresses
267 InetAddress inetAddr;
268 if (localAddress instanceof InetSocketAddress) {
269 inetAddr = ((InetSocketAddress) localAddress).getAddress();
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800270 localIp4Address = Ip4Address.valueOf(inetAddr.getAddress());
Jonathan Hartab63aac2014-10-16 08:52:55 -0700271 }
272 if (remoteAddress instanceof InetSocketAddress) {
273 inetAddr = ((InetSocketAddress) remoteAddress).getAddress();
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800274 remoteIp4Address = Ip4Address.valueOf(inetAddr.getAddress());
Jonathan Hartab63aac2014-10-16 08:52:55 -0700275 }
276
277 log.debug("BGP Session Connected from {} on {}",
278 remoteAddress, localAddress);
279 if (!bgpSessionManager.peerConnected(this)) {
280 log.debug("Cannot setup BGP Session Connection from {}. Closing...",
281 remoteAddress);
282 ctx.getChannel().close();
283 }
284 }
285
286 @Override
287 public void channelDisconnected(ChannelHandlerContext ctx,
288 ChannelStateEvent channelEvent) {
289 log.debug("BGP Session Disconnected from {} on {}",
290 ctx.getChannel().getRemoteAddress(),
291 ctx.getChannel().getLocalAddress());
292
293 //
294 // Withdraw the routes advertised by this BGP peer
295 //
296 // NOTE: We must initialize the RIB-IN before propagating the withdraws
297 // for further processing. Otherwise, the BGP Decision Process
298 // will use those routes again.
299 //
300 Collection<BgpRouteEntry> deletedRoutes = bgpRibIn.values();
301 bgpRibIn = new ConcurrentHashMap<>();
302
303 // Push the updates to the BGP Merged RIB
304 BgpSessionManager.BgpRouteSelector bgpRouteSelector =
305 bgpSessionManager.getBgpRouteSelector();
306 Collection<BgpRouteEntry> addedRoutes = Collections.emptyList();
307 bgpRouteSelector.routeUpdates(this, addedRoutes, deletedRoutes);
308
309 bgpSessionManager.peerDisconnected(this);
310 }
311
312 /**
313 * Processes BGP OPEN message.
314 *
315 * @param ctx the Channel Handler Context
316 * @param message the message to process
317 */
318 void processBgpOpen(ChannelHandlerContext ctx, ChannelBuffer message) {
319 int minLength =
320 BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
321 if (message.readableBytes() < minLength) {
322 log.debug("BGP RX OPEN Error from {}: " +
323 "Message length {} too short. Must be at least {}",
324 remoteAddress, message.readableBytes(), minLength);
325 //
326 // ERROR: Bad Message Length
327 //
328 // Send NOTIFICATION and close the connection
329 ChannelBuffer txMessage = prepareBgpNotificationBadMessageLength(
330 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
331 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -0800332 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -0700333 return;
334 }
335
336 //
337 // Parse the OPEN message
338 //
339 // Remote BGP version
340 remoteBgpVersion = message.readUnsignedByte();
341 if (remoteBgpVersion != BgpConstants.BGP_VERSION) {
342 log.debug("BGP RX OPEN Error from {}: " +
343 "Unsupported BGP version {}. Should be {}",
344 remoteAddress, remoteBgpVersion,
345 BgpConstants.BGP_VERSION);
346 //
347 // ERROR: Unsupported Version Number
348 //
349 // Send NOTIFICATION and close the connection
350 int errorCode = OpenMessageError.ERROR_CODE;
351 int errorSubcode = OpenMessageError.UNSUPPORTED_VERSION_NUMBER;
352 ChannelBuffer data = ChannelBuffers.buffer(2);
353 data.writeShort(BgpConstants.BGP_VERSION);
354 ChannelBuffer txMessage =
355 prepareBgpNotification(errorCode, errorSubcode, data);
356 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -0800357 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -0700358 return;
359 }
360
361 // Remote AS number
362 remoteAs = message.readUnsignedShort();
363 //
364 // Verify that the AS number is same for all other BGP Sessions
365 // NOTE: This check applies only for our use-case where all BGP
366 // sessions are iBGP.
367 //
368 for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
369 if (remoteAs != bgpSession.getRemoteAs()) {
370 log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
371 "Expected {}",
372 remoteAddress, remoteAs, bgpSession.getRemoteAs());
373 //
374 // ERROR: Bad Peer AS
375 //
376 // Send NOTIFICATION and close the connection
377 int errorCode = OpenMessageError.ERROR_CODE;
378 int errorSubcode = OpenMessageError.BAD_PEER_AS;
379 ChannelBuffer txMessage =
380 prepareBgpNotification(errorCode, errorSubcode, null);
381 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -0800382 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -0700383 return;
384 }
385 }
386
387 // Remote Hold Time
388 remoteHoldtime = message.readUnsignedShort();
389 if ((remoteHoldtime != 0) &&
390 (remoteHoldtime < BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME)) {
391 log.debug("BGP RX OPEN Error from {}: " +
392 "Unacceptable Hold Time field {}. " +
393 "Should be 0 or at least {}",
394 remoteAddress, remoteHoldtime,
395 BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME);
396 //
397 // ERROR: Unacceptable Hold Time
398 //
399 // Send NOTIFICATION and close the connection
400 int errorCode = OpenMessageError.ERROR_CODE;
401 int errorSubcode = OpenMessageError.UNACCEPTABLE_HOLD_TIME;
402 ChannelBuffer txMessage =
403 prepareBgpNotification(errorCode, errorSubcode, null);
404 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -0800405 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -0700406 return;
407 }
408
409 // Remote BGP Identifier
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800410 remoteBgpId = Ip4Address.valueOf((int) message.readUnsignedInt());
Jonathan Hartab63aac2014-10-16 08:52:55 -0700411
412 // Optional Parameters
413 int optParamLen = message.readUnsignedByte();
414 if (message.readableBytes() < optParamLen) {
415 log.debug("BGP RX OPEN Error from {}: " +
416 "Invalid Optional Parameter Length field {}. " +
417 "Remaining Optional Parameters {}",
418 remoteAddress, optParamLen, message.readableBytes());
419 //
420 // ERROR: Invalid Optional Parameter Length field: Unspecific
421 //
422 // Send NOTIFICATION and close the connection
423 int errorCode = OpenMessageError.ERROR_CODE;
424 int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
425 ChannelBuffer txMessage =
426 prepareBgpNotification(errorCode, errorSubcode, null);
427 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -0800428 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -0700429 return;
430 }
431 // TODO: Parse the optional parameters (if needed)
432 message.readBytes(optParamLen); // NOTE: data ignored
433
434 //
435 // Copy some of the remote peer's state/setup to the local setup:
436 // - BGP version
437 // - AS number (NOTE: the peer setup is always iBGP)
438 // - Holdtime
439 // Also, assign the local BGP ID based on the local setup
440 //
441 localBgpVersion = remoteBgpVersion;
442 localAs = remoteAs;
443 localHoldtime = remoteHoldtime;
444 localBgpId = bgpSessionManager.getMyBgpId();
445
446 // Set the Keepalive interval
447 if (localHoldtime == 0) {
448 localKeepaliveInterval = 0;
449 } else {
450 localKeepaliveInterval = Math.max(localHoldtime /
451 BgpConstants.BGP_KEEPALIVE_PER_HOLD_INTERVAL,
452 BgpConstants.BGP_KEEPALIVE_MIN_INTERVAL);
453 }
454
455 log.debug("BGP RX OPEN message from {}: " +
456 "BGPv{} AS {} BGP-ID {} Holdtime {}",
457 remoteAddress, remoteBgpVersion, remoteAs,
458 remoteBgpId, remoteHoldtime);
459
460 // Send my OPEN followed by KEEPALIVE
461 ChannelBuffer txMessage = prepareBgpOpen();
462 ctx.getChannel().write(txMessage);
463 //
464 txMessage = prepareBgpKeepalive();
465 ctx.getChannel().write(txMessage);
466
467 // Start the KEEPALIVE timer
468 restartKeepaliveTimer(ctx);
469
470 // Start the Session Timeout timer
471 restartSessionTimeoutTimer(ctx);
472 }
473
474 /**
475 * Processes BGP UPDATE message.
476 *
477 * @param ctx the Channel Handler Context
478 * @param message the message to process
479 */
480 void processBgpUpdate(ChannelHandlerContext ctx, ChannelBuffer message) {
481 Collection<BgpRouteEntry> addedRoutes = null;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800482 Map<Ip4Prefix, BgpRouteEntry> deletedRoutes = new HashMap<>();
Jonathan Hartab63aac2014-10-16 08:52:55 -0700483
484 int minLength =
485 BgpConstants.BGP_UPDATE_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
486 if (message.readableBytes() < minLength) {
487 log.debug("BGP RX UPDATE Error from {}: " +
488 "Message length {} too short. Must be at least {}",
489 remoteAddress, message.readableBytes(), minLength);
490 //
491 // ERROR: Bad Message Length
492 //
493 // Send NOTIFICATION and close the connection
494 ChannelBuffer txMessage = prepareBgpNotificationBadMessageLength(
495 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
496 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -0800497 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -0700498 return;
499 }
500
501 log.debug("BGP RX UPDATE message from {}", remoteAddress);
502
503 //
504 // Parse the UPDATE message
505 //
506
507 //
508 // Parse the Withdrawn Routes
509 //
510 int withdrawnRoutesLength = message.readUnsignedShort();
511 if (withdrawnRoutesLength > message.readableBytes()) {
512 // ERROR: Malformed Attribute List
513 actionsBgpUpdateMalformedAttributeList(ctx);
514 return;
515 }
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800516 Collection<Ip4Prefix> withdrawnPrefixes = null;
Jonathan Hartab63aac2014-10-16 08:52:55 -0700517 try {
518 withdrawnPrefixes = parsePackedPrefixes(withdrawnRoutesLength,
519 message);
520 } catch (BgpParseException e) {
521 // ERROR: Invalid Network Field
522 log.debug("Exception parsing Withdrawn Prefixes from BGP peer {}: ",
523 remoteBgpId, e);
524 actionsBgpUpdateInvalidNetworkField(ctx);
525 return;
526 }
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800527 for (Ip4Prefix prefix : withdrawnPrefixes) {
Jonathan Hartab63aac2014-10-16 08:52:55 -0700528 log.debug("BGP RX UPDATE message WITHDRAWN from {}: {}",
529 remoteAddress, prefix);
530 BgpRouteEntry bgpRouteEntry = bgpRibIn.get(prefix);
531 if (bgpRouteEntry != null) {
532 deletedRoutes.put(prefix, bgpRouteEntry);
533 }
534 }
535
536 //
537 // Parse the Path Attributes
538 //
539 try {
540 addedRoutes = parsePathAttributes(ctx, message);
541 } catch (BgpParseException e) {
542 log.debug("Exception parsing Path Attributes from BGP peer {}: ",
543 remoteBgpId, e);
544 // NOTE: The session was already closed, so nothing else to do
545 return;
546 }
547 // Ignore WITHDRAWN routes that are ADDED
548 for (BgpRouteEntry bgpRouteEntry : addedRoutes) {
549 deletedRoutes.remove(bgpRouteEntry.prefix());
550 }
551
552 // Update the BGP RIB-IN
553 for (BgpRouteEntry bgpRouteEntry : deletedRoutes.values()) {
554 bgpRibIn.remove(bgpRouteEntry.prefix());
555 }
556 for (BgpRouteEntry bgpRouteEntry : addedRoutes) {
557 bgpRibIn.put(bgpRouteEntry.prefix(), bgpRouteEntry);
558 }
559
560 // Push the updates to the BGP Merged RIB
561 BgpSessionManager.BgpRouteSelector bgpRouteSelector =
562 bgpSessionManager.getBgpRouteSelector();
563 bgpRouteSelector.routeUpdates(this, addedRoutes,
564 deletedRoutes.values());
565
566 // Start the Session Timeout timer
567 restartSessionTimeoutTimer(ctx);
568 }
569
570 /**
571 * Parse BGP Path Attributes from the BGP UPDATE message.
572 *
573 * @param ctx the Channel Handler Context
574 * @param message the message to parse
575 * @return a collection of the result BGP Route Entries
576 * @throws BgpParseException
577 */
578 private Collection<BgpRouteEntry> parsePathAttributes(
579 ChannelHandlerContext ctx,
580 ChannelBuffer message)
581 throws BgpParseException {
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800582 Map<Ip4Prefix, BgpRouteEntry> addedRoutes = new HashMap<>();
Jonathan Hartab63aac2014-10-16 08:52:55 -0700583
584 //
585 // Parsed values
586 //
587 Short origin = -1; // Mandatory
588 BgpRouteEntry.AsPath asPath = null; // Mandatory
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800589 Ip4Address nextHop = null; // Mandatory
Jonathan Hartab63aac2014-10-16 08:52:55 -0700590 long multiExitDisc = // Optional
591 BgpConstants.Update.MultiExitDisc.LOWEST_MULTI_EXIT_DISC;
592 Long localPref = null; // Mandatory
593 Long aggregatorAsNumber = null; // Optional: unused
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800594 Ip4Address aggregatorIpAddress = null; // Optional: unused
Jonathan Hartab63aac2014-10-16 08:52:55 -0700595
596 //
597 // Get and verify the Path Attributes Length
598 //
599 int pathAttributeLength = message.readUnsignedShort();
600 if (pathAttributeLength > message.readableBytes()) {
601 // ERROR: Malformed Attribute List
602 actionsBgpUpdateMalformedAttributeList(ctx);
603 String errorMsg = "Malformed Attribute List";
604 throw new BgpParseException(errorMsg);
605 }
606 if (pathAttributeLength == 0) {
607 return addedRoutes.values();
608 }
609
610 //
611 // Parse the Path Attributes
612 //
613 int pathAttributeEnd = message.readerIndex() + pathAttributeLength;
614 while (message.readerIndex() < pathAttributeEnd) {
615 int attrFlags = message.readUnsignedByte();
616 if (message.readerIndex() >= pathAttributeEnd) {
617 // ERROR: Malformed Attribute List
618 actionsBgpUpdateMalformedAttributeList(ctx);
619 String errorMsg = "Malformed Attribute List";
620 throw new BgpParseException(errorMsg);
621 }
622 int attrTypeCode = message.readUnsignedByte();
623
624 // The Attribute Flags
625 boolean optionalBit = ((0x80 & attrFlags) != 0);
626 boolean transitiveBit = ((0x40 & attrFlags) != 0);
627 boolean partialBit = ((0x20 & attrFlags) != 0);
628 boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
629
630 // The Attribute Length
631 int attrLen = 0;
632 int attrLenOctets = 1;
633 if (extendedLengthBit) {
634 attrLenOctets = 2;
635 }
636 if (message.readerIndex() + attrLenOctets > pathAttributeEnd) {
637 // ERROR: Malformed Attribute List
638 actionsBgpUpdateMalformedAttributeList(ctx);
639 String errorMsg = "Malformed Attribute List";
640 throw new BgpParseException(errorMsg);
641 }
642 if (extendedLengthBit) {
643 attrLen = message.readUnsignedShort();
644 } else {
645 attrLen = message.readUnsignedByte();
646 }
647 if (message.readerIndex() + attrLen > pathAttributeEnd) {
648 // ERROR: Malformed Attribute List
649 actionsBgpUpdateMalformedAttributeList(ctx);
650 String errorMsg = "Malformed Attribute List";
651 throw new BgpParseException(errorMsg);
652 }
653
654 //
655 // Verify the Attribute Flags
656 //
657 verifyBgpUpdateAttributeFlags(ctx, attrTypeCode, attrLen,
658 attrFlags, message);
659
660 //
661 // Extract the Attribute Value based on the Attribute Type Code
662 //
663 switch (attrTypeCode) {
664
665 case BgpConstants.Update.Origin.TYPE:
666 // Attribute Type Code ORIGIN
667 origin = parseAttributeTypeOrigin(ctx, attrTypeCode, attrLen,
668 attrFlags, message);
669 break;
670
671 case BgpConstants.Update.AsPath.TYPE:
672 // Attribute Type Code AS_PATH
673 asPath = parseAttributeTypeAsPath(ctx, attrTypeCode, attrLen,
674 attrFlags, message);
675 break;
676
677 case BgpConstants.Update.NextHop.TYPE:
678 // Attribute Type Code NEXT_HOP
679 nextHop = parseAttributeTypeNextHop(ctx, attrTypeCode, attrLen,
680 attrFlags, message);
681 break;
682
683 case BgpConstants.Update.MultiExitDisc.TYPE:
684 // Attribute Type Code MULTI_EXIT_DISC
685 multiExitDisc =
686 parseAttributeTypeMultiExitDisc(ctx, attrTypeCode, attrLen,
687 attrFlags, message);
688 break;
689
690 case BgpConstants.Update.LocalPref.TYPE:
691 // Attribute Type Code LOCAL_PREF
692 localPref =
693 parseAttributeTypeLocalPref(ctx, attrTypeCode, attrLen,
694 attrFlags, message);
695 break;
696
697 case BgpConstants.Update.AtomicAggregate.TYPE:
698 // Attribute Type Code ATOMIC_AGGREGATE
699 parseAttributeTypeAtomicAggregate(ctx, attrTypeCode, attrLen,
700 attrFlags, message);
701 // Nothing to do: this attribute is primarily informational
702 break;
703
704 case BgpConstants.Update.Aggregator.TYPE:
705 // Attribute Type Code AGGREGATOR
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800706 Pair<Long, Ip4Address> aggregator =
Jonathan Hartab63aac2014-10-16 08:52:55 -0700707 parseAttributeTypeAggregator(ctx, attrTypeCode, attrLen,
708 attrFlags, message);
709 aggregatorAsNumber = aggregator.getLeft();
710 aggregatorIpAddress = aggregator.getRight();
711 break;
712
713 default:
714 // TODO: Parse any new Attribute Types if needed
715 if (!optionalBit) {
716 // ERROR: Unrecognized Well-known Attribute
717 actionsBgpUpdateUnrecognizedWellKnownAttribute(
718 ctx, attrTypeCode, attrLen, attrFlags, message);
719 String errorMsg = "Unrecognized Well-known Attribute: " +
720 attrTypeCode;
721 throw new BgpParseException(errorMsg);
722 }
723
724 // Skip the data from the unrecognized attribute
725 log.debug("BGP RX UPDATE message from {}: " +
726 "Unrecognized Attribute Type {}",
727 remoteAddress, attrTypeCode);
728 message.skipBytes(attrLen);
729 break;
730 }
731 }
732
733 //
734 // Verify the Well-known Attributes
735 //
736 verifyBgpUpdateWellKnownAttributes(ctx, origin, asPath, nextHop,
737 localPref);
738
739 //
740 // Parse the NLRI (Network Layer Reachability Information)
741 //
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800742 Collection<Ip4Prefix> addedPrefixes = null;
Jonathan Hartab63aac2014-10-16 08:52:55 -0700743 int nlriLength = message.readableBytes();
744 try {
745 addedPrefixes = parsePackedPrefixes(nlriLength, message);
746 } catch (BgpParseException e) {
747 // ERROR: Invalid Network Field
748 log.debug("Exception parsing NLRI from BGP peer {}: ",
749 remoteBgpId, e);
750 actionsBgpUpdateInvalidNetworkField(ctx);
751 // Rethrow the exception
752 throw e;
753 }
754
755 // Generate the added routes
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800756 for (Ip4Prefix prefix : addedPrefixes) {
Jonathan Hartab63aac2014-10-16 08:52:55 -0700757 BgpRouteEntry bgpRouteEntry =
758 new BgpRouteEntry(this, prefix, nextHop,
759 origin.byteValue(), asPath, localPref);
760 bgpRouteEntry.setMultiExitDisc(multiExitDisc);
761 if (bgpRouteEntry.hasAsPathLoop(localAs)) {
762 log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
763 "nextHop {}: contains AS Path loop",
764 remoteAddress, prefix, nextHop);
765 continue;
766 } else {
767 log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
768 remoteAddress, prefix, nextHop);
769 }
770 addedRoutes.put(prefix, bgpRouteEntry);
771 }
772
773 return addedRoutes.values();
774 }
775
776 /**
777 * Verifies BGP UPDATE Well-known Attributes.
778 *
779 * @param ctx the Channel Handler Context
780 * @param origin the ORIGIN well-known mandatory attribute
781 * @param asPath the AS_PATH well-known mandatory attribute
782 * @param nextHop the NEXT_HOP well-known mandatory attribute
783 * @param localPref the LOCAL_PREF required attribute
784 * @throws BgpParseException
785 */
786 private void verifyBgpUpdateWellKnownAttributes(
787 ChannelHandlerContext ctx,
788 Short origin,
789 BgpRouteEntry.AsPath asPath,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800790 Ip4Address nextHop,
Jonathan Hartab63aac2014-10-16 08:52:55 -0700791 Long localPref)
792 throws BgpParseException {
793 //
794 // Check for Missing Well-known Attributes
795 //
796 if ((origin == null) || (origin == -1)) {
797 // Missing Attribute Type Code ORIGIN
798 int type = BgpConstants.Update.Origin.TYPE;
799 actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
800 String errorMsg = "Missing Well-known Attribute: ORIGIN";
801 throw new BgpParseException(errorMsg);
802 }
803 if (asPath == null) {
804 // Missing Attribute Type Code AS_PATH
805 int type = BgpConstants.Update.AsPath.TYPE;
806 actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
807 String errorMsg = "Missing Well-known Attribute: AS_PATH";
808 throw new BgpParseException(errorMsg);
809 }
810 if (nextHop == null) {
811 // Missing Attribute Type Code NEXT_HOP
812 int type = BgpConstants.Update.NextHop.TYPE;
813 actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
814 String errorMsg = "Missing Well-known Attribute: NEXT_HOP";
815 throw new BgpParseException(errorMsg);
816 }
817 if (localPref == null) {
818 // Missing Attribute Type Code LOCAL_PREF
819 // NOTE: Required for iBGP
820 int type = BgpConstants.Update.LocalPref.TYPE;
821 actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
822 String errorMsg = "Missing Well-known Attribute: LOCAL_PREF";
823 throw new BgpParseException(errorMsg);
824 }
825 }
826
827 /**
828 * Verifies the BGP UPDATE Attribute Flags.
829 *
830 * @param ctx the Channel Handler Context
831 * @param attrTypeCode the attribute type code
832 * @param attrLen the attribute length (in octets)
833 * @param attrFlags the attribute flags
834 * @param message the message to parse
835 * @throws BgpParseException
836 */
837 private void verifyBgpUpdateAttributeFlags(
838 ChannelHandlerContext ctx,
839 int attrTypeCode,
840 int attrLen,
841 int attrFlags,
842 ChannelBuffer message)
843 throws BgpParseException {
844
845 //
846 // Assign the Attribute Type Name and the Well-known flag
847 //
848 String typeName = "UNKNOWN";
849 boolean isWellKnown = false;
850 switch (attrTypeCode) {
851 case BgpConstants.Update.Origin.TYPE:
852 isWellKnown = true;
853 typeName = "ORIGIN";
854 break;
855 case BgpConstants.Update.AsPath.TYPE:
856 isWellKnown = true;
857 typeName = "AS_PATH";
858 break;
859 case BgpConstants.Update.NextHop.TYPE:
860 isWellKnown = true;
861 typeName = "NEXT_HOP";
862 break;
863 case BgpConstants.Update.MultiExitDisc.TYPE:
864 isWellKnown = false;
865 typeName = "MULTI_EXIT_DISC";
866 break;
867 case BgpConstants.Update.LocalPref.TYPE:
868 isWellKnown = true;
869 typeName = "LOCAL_PREF";
870 break;
871 case BgpConstants.Update.AtomicAggregate.TYPE:
872 isWellKnown = true;
873 typeName = "ATOMIC_AGGREGATE";
874 break;
875 case BgpConstants.Update.Aggregator.TYPE:
876 isWellKnown = false;
877 typeName = "AGGREGATOR";
878 break;
879 default:
880 isWellKnown = false;
881 typeName = "UNKNOWN(" + attrTypeCode + ")";
882 break;
883 }
884
885 //
886 // Verify the Attribute Flags
887 //
888 boolean optionalBit = ((0x80 & attrFlags) != 0);
889 boolean transitiveBit = ((0x40 & attrFlags) != 0);
890 boolean partialBit = ((0x20 & attrFlags) != 0);
891 if ((isWellKnown && optionalBit) ||
892 (isWellKnown && (!transitiveBit)) ||
893 (isWellKnown && partialBit) ||
894 (optionalBit && (!transitiveBit) && partialBit)) {
895 //
896 // ERROR: The Optional bit cannot be set for Well-known attributes
897 // ERROR: The Transtive bit MUST be 1 for well-known attributes
898 // ERROR: The Partial bit MUST be 0 for well-known attributes
899 // ERROR: The Partial bit MUST be 0 for optional non-transitive
900 // attributes
901 //
902 actionsBgpUpdateAttributeFlagsError(
903 ctx, attrTypeCode, attrLen, attrFlags, message);
904 String errorMsg = "Attribute Flags Error for " + typeName + ": " +
905 attrFlags;
906 throw new BgpParseException(errorMsg);
907 }
908 }
909
910 /**
911 * Parses BGP UPDATE Attribute Type ORIGIN.
912 *
913 * @param ctx the Channel Handler Context
914 * @param attrTypeCode the attribute type code
915 * @param attrLen the attribute length (in octets)
916 * @param attrFlags the attribute flags
917 * @param message the message to parse
918 * @return the parsed ORIGIN value
919 * @throws BgpParseException
920 */
921 private short parseAttributeTypeOrigin(
922 ChannelHandlerContext ctx,
923 int attrTypeCode,
924 int attrLen,
925 int attrFlags,
926 ChannelBuffer message)
927 throws BgpParseException {
928
929 // Check the Attribute Length
930 if (attrLen != BgpConstants.Update.Origin.LENGTH) {
931 // ERROR: Attribute Length Error
932 actionsBgpUpdateAttributeLengthError(
933 ctx, attrTypeCode, attrLen, attrFlags, message);
934 String errorMsg = "Attribute Length Error";
935 throw new BgpParseException(errorMsg);
936 }
937
938 message.markReaderIndex();
939 short origin = message.readUnsignedByte();
940 switch (origin) {
941 case BgpConstants.Update.Origin.IGP:
942 // FALLTHROUGH
943 case BgpConstants.Update.Origin.EGP:
944 // FALLTHROUGH
945 case BgpConstants.Update.Origin.INCOMPLETE:
946 break;
947 default:
948 // ERROR: Invalid ORIGIN Attribute
949 message.resetReaderIndex();
950 actionsBgpUpdateInvalidOriginAttribute(
951 ctx, attrTypeCode, attrLen, attrFlags, message, origin);
952 String errorMsg = "Invalid ORIGIN Attribute: " + origin;
953 throw new BgpParseException(errorMsg);
954 }
955
956 return origin;
957 }
958
959 /**
960 * Parses BGP UPDATE Attribute AS Path.
961 *
962 * @param ctx the Channel Handler Context
963 * @param attrTypeCode the attribute type code
964 * @param attrLen the attribute length (in octets)
965 * @param attrFlags the attribute flags
966 * @param message the message to parse
967 * @return the parsed AS Path
968 * @throws BgpParseException
969 */
970 private BgpRouteEntry.AsPath parseAttributeTypeAsPath(
971 ChannelHandlerContext ctx,
972 int attrTypeCode,
973 int attrLen,
974 int attrFlags,
975 ChannelBuffer message)
976 throws BgpParseException {
977 ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
978
979 //
980 // Parse the message
981 //
982 while (attrLen > 0) {
983 if (attrLen < 2) {
984 // ERROR: Malformed AS_PATH
985 actionsBgpUpdateMalformedAsPath(ctx);
986 String errorMsg = "Malformed AS Path";
987 throw new BgpParseException(errorMsg);
988 }
989 // Get the Path Segment Type and Length (in number of ASes)
990 short pathSegmentType = message.readUnsignedByte();
991 short pathSegmentLength = message.readUnsignedByte();
992 attrLen -= 2;
993
994 // Verify the Path Segment Type
995 switch (pathSegmentType) {
996 case BgpConstants.Update.AsPath.AS_SET:
997 // FALLTHROUGH
998 case BgpConstants.Update.AsPath.AS_SEQUENCE:
Pavlin Radoslavov49eb64d2014-11-10 17:03:19 -0800999 // FALLTHROUGH
1000 case BgpConstants.Update.AsPath.AS_CONFED_SEQUENCE:
1001 // FALLTHROUGH
1002 case BgpConstants.Update.AsPath.AS_CONFED_SET:
Jonathan Hartab63aac2014-10-16 08:52:55 -07001003 break;
1004 default:
1005 // ERROR: Invalid Path Segment Type
1006 //
1007 // NOTE: The BGP Spec (RFC 4271) doesn't contain Error Subcode
1008 // for "Invalid Path Segment Type", hence we return
1009 // the error as "Malformed AS_PATH".
1010 //
1011 actionsBgpUpdateMalformedAsPath(ctx);
1012 String errorMsg =
1013 "Invalid AS Path Segment Type: " + pathSegmentType;
1014 throw new BgpParseException(errorMsg);
1015 }
1016
1017 // Parse the AS numbers
1018 if (2 * pathSegmentLength > attrLen) {
1019 // ERROR: Malformed AS_PATH
1020 actionsBgpUpdateMalformedAsPath(ctx);
1021 String errorMsg = "Malformed AS Path";
1022 throw new BgpParseException(errorMsg);
1023 }
1024 attrLen -= (2 * pathSegmentLength);
1025 ArrayList<Long> segmentAsNumbers = new ArrayList<>();
1026 while (pathSegmentLength-- > 0) {
1027 long asNumber = message.readUnsignedShort();
1028 segmentAsNumbers.add(asNumber);
1029 }
1030
1031 BgpRouteEntry.PathSegment pathSegment =
1032 new BgpRouteEntry.PathSegment((byte) pathSegmentType,
1033 segmentAsNumbers);
1034 pathSegments.add(pathSegment);
1035 }
1036
1037 return new BgpRouteEntry.AsPath(pathSegments);
1038 }
1039
1040 /**
1041 * Parses BGP UPDATE Attribute Type NEXT_HOP.
1042 *
1043 * @param ctx the Channel Handler Context
1044 * @param attrTypeCode the attribute type code
1045 * @param attrLen the attribute length (in octets)
1046 * @param attrFlags the attribute flags
1047 * @param message the message to parse
1048 * @return the parsed NEXT_HOP value
1049 * @throws BgpParseException
1050 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001051 private Ip4Address parseAttributeTypeNextHop(
Jonathan Hartab63aac2014-10-16 08:52:55 -07001052 ChannelHandlerContext ctx,
1053 int attrTypeCode,
1054 int attrLen,
1055 int attrFlags,
1056 ChannelBuffer message)
1057 throws BgpParseException {
1058
1059 // Check the Attribute Length
1060 if (attrLen != BgpConstants.Update.NextHop.LENGTH) {
1061 // ERROR: Attribute Length Error
1062 actionsBgpUpdateAttributeLengthError(
1063 ctx, attrTypeCode, attrLen, attrFlags, message);
1064 String errorMsg = "Attribute Length Error";
1065 throw new BgpParseException(errorMsg);
1066 }
1067
1068 message.markReaderIndex();
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001069 Ip4Address nextHopAddress =
1070 Ip4Address.valueOf((int) message.readUnsignedInt());
Jonathan Hartab63aac2014-10-16 08:52:55 -07001071 //
1072 // Check whether the NEXT_HOP IP address is semantically correct.
1073 // As per RFC 4271, Section 6.3:
1074 //
1075 // a) It MUST NOT be the IP address of the receiving speaker
1076 // b) In the case of an EBGP ....
1077 //
1078 // Here we check only (a), because (b) doesn't apply for us: all our
1079 // peers are iBGP.
1080 //
1081 if (nextHopAddress.equals(localIp4Address)) {
1082 // ERROR: Invalid NEXT_HOP Attribute
1083 message.resetReaderIndex();
1084 actionsBgpUpdateInvalidNextHopAttribute(
1085 ctx, attrTypeCode, attrLen, attrFlags, message,
1086 nextHopAddress);
1087 String errorMsg = "Invalid NEXT_HOP Attribute: " + nextHopAddress;
1088 throw new BgpParseException(errorMsg);
1089 }
1090
1091 return nextHopAddress;
1092 }
1093
1094 /**
1095 * Parses BGP UPDATE Attribute Type MULTI_EXIT_DISC.
1096 *
1097 * @param ctx the Channel Handler Context
1098 * @param attrTypeCode the attribute type code
1099 * @param attrLen the attribute length (in octets)
1100 * @param attrFlags the attribute flags
1101 * @param message the message to parse
1102 * @return the parsed MULTI_EXIT_DISC value
1103 * @throws BgpParseException
1104 */
1105 private long parseAttributeTypeMultiExitDisc(
1106 ChannelHandlerContext ctx,
1107 int attrTypeCode,
1108 int attrLen,
1109 int attrFlags,
1110 ChannelBuffer message)
1111 throws BgpParseException {
1112
1113 // Check the Attribute Length
1114 if (attrLen != BgpConstants.Update.MultiExitDisc.LENGTH) {
1115 // ERROR: Attribute Length Error
1116 actionsBgpUpdateAttributeLengthError(
1117 ctx, attrTypeCode, attrLen, attrFlags, message);
1118 String errorMsg = "Attribute Length Error";
1119 throw new BgpParseException(errorMsg);
1120 }
1121
1122 long multiExitDisc = message.readUnsignedInt();
1123 return multiExitDisc;
1124 }
1125
1126 /**
1127 * Parses BGP UPDATE Attribute Type LOCAL_PREF.
1128 *
1129 * @param ctx the Channel Handler Context
1130 * @param attrTypeCode the attribute type code
1131 * @param attrLen the attribute length (in octets)
1132 * @param attrFlags the attribute flags
1133 * @param message the message to parse
1134 * @return the parsed LOCAL_PREF value
1135 * @throws BgpParseException
1136 */
1137 private long parseAttributeTypeLocalPref(
1138 ChannelHandlerContext ctx,
1139 int attrTypeCode,
1140 int attrLen,
1141 int attrFlags,
1142 ChannelBuffer message)
1143 throws BgpParseException {
1144
1145 // Check the Attribute Length
1146 if (attrLen != BgpConstants.Update.LocalPref.LENGTH) {
1147 // ERROR: Attribute Length Error
1148 actionsBgpUpdateAttributeLengthError(
1149 ctx, attrTypeCode, attrLen, attrFlags, message);
1150 String errorMsg = "Attribute Length Error";
1151 throw new BgpParseException(errorMsg);
1152 }
1153
1154 long localPref = message.readUnsignedInt();
1155 return localPref;
1156 }
1157
1158 /**
1159 * Parses BGP UPDATE Attribute Type ATOMIC_AGGREGATE.
1160 *
1161 * @param ctx the Channel Handler Context
1162 * @param attrTypeCode the attribute type code
1163 * @param attrLen the attribute length (in octets)
1164 * @param attrFlags the attribute flags
1165 * @param message the message to parse
1166 * @throws BgpParseException
1167 */
1168 private void parseAttributeTypeAtomicAggregate(
1169 ChannelHandlerContext ctx,
1170 int attrTypeCode,
1171 int attrLen,
1172 int attrFlags,
1173 ChannelBuffer message)
1174 throws BgpParseException {
1175
1176 // Check the Attribute Length
1177 if (attrLen != BgpConstants.Update.AtomicAggregate.LENGTH) {
1178 // ERROR: Attribute Length Error
1179 actionsBgpUpdateAttributeLengthError(
1180 ctx, attrTypeCode, attrLen, attrFlags, message);
1181 String errorMsg = "Attribute Length Error";
1182 throw new BgpParseException(errorMsg);
1183 }
1184
1185 // Nothing to do: this attribute is primarily informational
1186 }
1187
1188 /**
1189 * Parses BGP UPDATE Attribute Type AGGREGATOR.
1190 *
1191 * @param ctx the Channel Handler Context
1192 * @param attrTypeCode the attribute type code
1193 * @param attrLen the attribute length (in octets)
1194 * @param attrFlags the attribute flags
1195 * @param message the message to parse
1196 * @return the parsed AGGREGATOR value: a tuple of <AS-Number, IP-Address>
1197 * @throws BgpParseException
1198 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001199 private Pair<Long, Ip4Address> parseAttributeTypeAggregator(
Jonathan Hartab63aac2014-10-16 08:52:55 -07001200 ChannelHandlerContext ctx,
1201 int attrTypeCode,
1202 int attrLen,
1203 int attrFlags,
1204 ChannelBuffer message)
1205 throws BgpParseException {
1206
1207 // Check the Attribute Length
1208 if (attrLen != BgpConstants.Update.Aggregator.LENGTH) {
1209 // ERROR: Attribute Length Error
1210 actionsBgpUpdateAttributeLengthError(
1211 ctx, attrTypeCode, attrLen, attrFlags, message);
1212 String errorMsg = "Attribute Length Error";
1213 throw new BgpParseException(errorMsg);
1214 }
1215
1216 // The AGGREGATOR AS number
1217 long aggregatorAsNumber = message.readUnsignedShort();
1218 // The AGGREGATOR IP address
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001219 Ip4Address aggregatorIpAddress =
1220 Ip4Address.valueOf((int) message.readUnsignedInt());
Jonathan Hartab63aac2014-10-16 08:52:55 -07001221
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001222 Pair<Long, Ip4Address> aggregator = Pair.of(aggregatorAsNumber,
Jonathan Hartab63aac2014-10-16 08:52:55 -07001223 aggregatorIpAddress);
1224 return aggregator;
1225 }
1226
1227 /**
1228 * Parses a message that contains encoded IPv4 network prefixes.
1229 * <p>
1230 * The IPv4 prefixes are encoded in the form:
1231 * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
1232 * and Prefix is the IPv4 prefix (padded with trailing bits to the end
1233 * of an octet).
1234 *
1235 * @param totalLength the total length of the data to parse
1236 * @param message the message with data to parse
1237 * @return a collection of parsed IPv4 network prefixes
1238 * @throws BgpParseException
1239 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001240 private Collection<Ip4Prefix> parsePackedPrefixes(int totalLength,
Jonathan Hartab63aac2014-10-16 08:52:55 -07001241 ChannelBuffer message)
1242 throws BgpParseException {
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001243 Collection<Ip4Prefix> result = new ArrayList<>();
Jonathan Hartab63aac2014-10-16 08:52:55 -07001244
1245 if (totalLength == 0) {
1246 return result;
1247 }
1248
1249 // Parse the data
1250 int dataEnd = message.readerIndex() + totalLength;
1251 while (message.readerIndex() < dataEnd) {
1252 int prefixBitlen = message.readUnsignedByte();
1253 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
1254 if (message.readerIndex() + prefixBytelen > dataEnd) {
1255 String errorMsg = "Malformed Network Prefixes";
1256 throw new BgpParseException(errorMsg);
1257 }
1258
1259 long address = 0;
1260 long extraShift = (4 - prefixBytelen) * 8;
1261 while (prefixBytelen > 0) {
1262 address <<= 8;
1263 address |= message.readUnsignedByte();
1264 prefixBytelen--;
1265 }
1266 address <<= extraShift;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001267 Ip4Prefix prefix =
1268 Ip4Prefix.valueOf(Ip4Address.valueOf((int) address),
1269 prefixBitlen);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001270 result.add(prefix);
1271 }
1272
1273 return result;
1274 }
1275
1276 /**
1277 * Applies the appropriate actions after detecting BGP UPDATE
1278 * Invalid Network Field Error: send NOTIFICATION and close the channel.
1279 *
1280 * @param ctx the Channel Handler Context
1281 */
1282 private void actionsBgpUpdateInvalidNetworkField(
1283 ChannelHandlerContext ctx) {
1284 log.debug("BGP RX UPDATE Error from {}: Invalid Network Field",
1285 remoteAddress);
1286
1287 //
1288 // ERROR: Invalid Network Field
1289 //
1290 // Send NOTIFICATION and close the connection
1291 int errorCode = UpdateMessageError.ERROR_CODE;
1292 int errorSubcode = UpdateMessageError.INVALID_NETWORK_FIELD;
1293 ChannelBuffer txMessage =
1294 prepareBgpNotification(errorCode, errorSubcode, null);
1295 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -08001296 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001297 }
1298
1299 /**
1300 * Applies the appropriate actions after detecting BGP UPDATE
1301 * Malformed Attribute List Error: send NOTIFICATION and close the channel.
1302 *
1303 * @param ctx the Channel Handler Context
1304 */
1305 private void actionsBgpUpdateMalformedAttributeList(
1306 ChannelHandlerContext ctx) {
1307 log.debug("BGP RX UPDATE Error from {}: Malformed Attribute List",
1308 remoteAddress);
1309
1310 //
1311 // ERROR: Malformed Attribute List
1312 //
1313 // Send NOTIFICATION and close the connection
1314 int errorCode = UpdateMessageError.ERROR_CODE;
1315 int errorSubcode = UpdateMessageError.MALFORMED_ATTRIBUTE_LIST;
1316 ChannelBuffer txMessage =
1317 prepareBgpNotification(errorCode, errorSubcode, null);
1318 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -08001319 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001320 }
1321
1322 /**
1323 * Applies the appropriate actions after detecting BGP UPDATE
1324 * Missing Well-known Attribute Error: send NOTIFICATION and close the
1325 * channel.
1326 *
1327 * @param ctx the Channel Handler Context
1328 * @param missingAttrTypeCode the missing attribute type code
1329 */
1330 private void actionsBgpUpdateMissingWellKnownAttribute(
1331 ChannelHandlerContext ctx,
1332 int missingAttrTypeCode) {
1333 log.debug("BGP RX UPDATE Error from {}: Missing Well-known Attribute: {}",
1334 remoteAddress, missingAttrTypeCode);
1335
1336 //
1337 // ERROR: Missing Well-known Attribute
1338 //
1339 // Send NOTIFICATION and close the connection
1340 int errorCode = UpdateMessageError.ERROR_CODE;
1341 int errorSubcode = UpdateMessageError.MISSING_WELL_KNOWN_ATTRIBUTE;
1342 ChannelBuffer data = ChannelBuffers.buffer(1);
1343 data.writeByte(missingAttrTypeCode);
1344 ChannelBuffer txMessage =
1345 prepareBgpNotification(errorCode, errorSubcode, data);
1346 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -08001347 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001348 }
1349
1350 /**
1351 * Applies the appropriate actions after detecting BGP UPDATE
1352 * Invalid ORIGIN Attribute Error: send NOTIFICATION and close the channel.
1353 *
1354 * @param ctx the Channel Handler Context
1355 * @param attrTypeCode the attribute type code
1356 * @param attrLen the attribute length (in octets)
1357 * @param attrFlags the attribute flags
1358 * @param message the message with the data
1359 * @param origin the ORIGIN attribute value
1360 */
1361 private void actionsBgpUpdateInvalidOriginAttribute(
1362 ChannelHandlerContext ctx,
1363 int attrTypeCode,
1364 int attrLen,
1365 int attrFlags,
1366 ChannelBuffer message,
1367 short origin) {
1368 log.debug("BGP RX UPDATE Error from {}: Invalid ORIGIN Attribute",
1369 remoteAddress);
1370
1371 //
1372 // ERROR: Invalid ORIGIN Attribute
1373 //
1374 // Send NOTIFICATION and close the connection
1375 int errorCode = UpdateMessageError.ERROR_CODE;
1376 int errorSubcode = UpdateMessageError.INVALID_ORIGIN_ATTRIBUTE;
1377 ChannelBuffer data =
1378 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1379 attrFlags, message);
1380 ChannelBuffer txMessage =
1381 prepareBgpNotification(errorCode, errorSubcode, data);
1382 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -08001383 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001384 }
1385
1386 /**
1387 * Applies the appropriate actions after detecting BGP UPDATE
1388 * Attribute Flags Error: send NOTIFICATION and close the channel.
1389 *
1390 * @param ctx the Channel Handler Context
1391 * @param attrTypeCode the attribute type code
1392 * @param attrLen the attribute length (in octets)
1393 * @param attrFlags the attribute flags
1394 * @param message the message with the data
1395 */
1396 private void actionsBgpUpdateAttributeFlagsError(
1397 ChannelHandlerContext ctx,
1398 int attrTypeCode,
1399 int attrLen,
1400 int attrFlags,
1401 ChannelBuffer message) {
1402 log.debug("BGP RX UPDATE Error from {}: Attribute Flags Error",
1403 remoteAddress);
1404
1405 //
1406 // ERROR: Attribute Flags Error
1407 //
1408 // Send NOTIFICATION and close the connection
1409 int errorCode = UpdateMessageError.ERROR_CODE;
1410 int errorSubcode = UpdateMessageError.ATTRIBUTE_FLAGS_ERROR;
1411 ChannelBuffer data =
1412 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1413 attrFlags, message);
1414 ChannelBuffer txMessage =
1415 prepareBgpNotification(errorCode, errorSubcode, data);
1416 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -08001417 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001418 }
1419
1420 /**
1421 * Applies the appropriate actions after detecting BGP UPDATE
1422 * Invalid NEXT_HOP Attribute Error: send NOTIFICATION and close the
1423 * channel.
1424 *
1425 * @param ctx the Channel Handler Context
1426 * @param attrTypeCode the attribute type code
1427 * @param attrLen the attribute length (in octets)
1428 * @param attrFlags the attribute flags
1429 * @param message the message with the data
1430 * @param nextHop the NEXT_HOP attribute value
1431 */
1432 private void actionsBgpUpdateInvalidNextHopAttribute(
1433 ChannelHandlerContext ctx,
1434 int attrTypeCode,
1435 int attrLen,
1436 int attrFlags,
1437 ChannelBuffer message,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -08001438 Ip4Address nextHop) {
Jonathan Hartab63aac2014-10-16 08:52:55 -07001439 log.debug("BGP RX UPDATE Error from {}: Invalid NEXT_HOP Attribute {}",
1440 remoteAddress, nextHop);
1441
1442 //
1443 // ERROR: Invalid ORIGIN Attribute
1444 //
1445 // Send NOTIFICATION and close the connection
1446 int errorCode = UpdateMessageError.ERROR_CODE;
1447 int errorSubcode = UpdateMessageError.INVALID_NEXT_HOP_ATTRIBUTE;
1448 ChannelBuffer data =
1449 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1450 attrFlags, message);
1451 ChannelBuffer txMessage =
1452 prepareBgpNotification(errorCode, errorSubcode, data);
1453 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -08001454 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001455 }
1456
1457 /**
1458 * Applies the appropriate actions after detecting BGP UPDATE
1459 * Unrecognized Well-known Attribute Error: send NOTIFICATION and close
1460 * the channel.
1461 *
1462 * @param ctx the Channel Handler Context
1463 * @param attrTypeCode the attribute type code
1464 * @param attrLen the attribute length (in octets)
1465 * @param attrFlags the attribute flags
1466 * @param message the message with the data
1467 */
1468 private void actionsBgpUpdateUnrecognizedWellKnownAttribute(
1469 ChannelHandlerContext ctx,
1470 int attrTypeCode,
1471 int attrLen,
1472 int attrFlags,
1473 ChannelBuffer message) {
1474 log.debug("BGP RX UPDATE Error from {}: " +
1475 "Unrecognized Well-known Attribute Error: {}",
1476 remoteAddress, attrTypeCode);
1477
1478 //
1479 // ERROR: Unrecognized Well-known Attribute
1480 //
1481 // Send NOTIFICATION and close the connection
1482 int errorCode = UpdateMessageError.ERROR_CODE;
1483 int errorSubcode =
1484 UpdateMessageError.UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE;
1485 ChannelBuffer data =
1486 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1487 attrFlags, message);
1488 ChannelBuffer txMessage =
1489 prepareBgpNotification(errorCode, errorSubcode, data);
1490 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -08001491 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001492 }
1493
1494 /**
1495 * Applies the appropriate actions after detecting BGP UPDATE
1496 * Attribute Length Error: send NOTIFICATION and close the channel.
1497 *
1498 * @param ctx the Channel Handler Context
1499 * @param attrTypeCode the attribute type code
1500 * @param attrLen the attribute length (in octets)
1501 * @param attrFlags the attribute flags
1502 * @param message the message with the data
1503 */
1504 private void actionsBgpUpdateAttributeLengthError(
1505 ChannelHandlerContext ctx,
1506 int attrTypeCode,
1507 int attrLen,
1508 int attrFlags,
1509 ChannelBuffer message) {
1510 log.debug("BGP RX UPDATE Error from {}: Attribute Length Error",
1511 remoteAddress);
1512
1513 //
1514 // ERROR: Attribute Length Error
1515 //
1516 // Send NOTIFICATION and close the connection
1517 int errorCode = UpdateMessageError.ERROR_CODE;
1518 int errorSubcode = UpdateMessageError.ATTRIBUTE_LENGTH_ERROR;
1519 ChannelBuffer data =
1520 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1521 attrFlags, message);
1522 ChannelBuffer txMessage =
1523 prepareBgpNotification(errorCode, errorSubcode, data);
1524 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -08001525 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001526 }
1527
1528 /**
1529 * Applies the appropriate actions after detecting BGP UPDATE
1530 * Malformed AS_PATH Error: send NOTIFICATION and close the channel.
1531 *
1532 * @param ctx the Channel Handler Context
1533 */
1534 private void actionsBgpUpdateMalformedAsPath(
1535 ChannelHandlerContext ctx) {
1536 log.debug("BGP RX UPDATE Error from {}: Malformed AS Path",
1537 remoteAddress);
1538
1539 //
1540 // ERROR: Malformed AS_PATH
1541 //
1542 // Send NOTIFICATION and close the connection
1543 int errorCode = UpdateMessageError.ERROR_CODE;
1544 int errorSubcode = UpdateMessageError.MALFORMED_AS_PATH;
1545 ChannelBuffer txMessage =
1546 prepareBgpNotification(errorCode, errorSubcode, null);
1547 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -08001548 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001549 }
1550
1551 /**
1552 * Processes BGP NOTIFICATION message.
1553 *
1554 * @param ctx the Channel Handler Context
1555 * @param message the message to process
1556 */
1557 void processBgpNotification(ChannelHandlerContext ctx,
1558 ChannelBuffer message) {
1559 int minLength =
1560 BgpConstants.BGP_NOTIFICATION_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
1561 if (message.readableBytes() < minLength) {
1562 log.debug("BGP RX NOTIFICATION Error from {}: " +
1563 "Message length {} too short. Must be at least {}",
1564 remoteAddress, message.readableBytes(), minLength);
1565 //
1566 // ERROR: Bad Message Length
1567 //
1568 // NOTE: We do NOT send NOTIFICATION in response to a notification
1569 return;
1570 }
1571
1572 //
1573 // Parse the NOTIFICATION message
1574 //
1575 int errorCode = message.readUnsignedByte();
1576 int errorSubcode = message.readUnsignedByte();
1577 int dataLength = message.readableBytes();
1578
1579 log.debug("BGP RX NOTIFICATION message from {}: Error Code {} " +
1580 "Error Subcode {} Data Length {}",
1581 remoteAddress, errorCode, errorSubcode, dataLength);
1582
1583 //
1584 // NOTE: If the peer sent a NOTIFICATION, we leave it to the peer to
1585 // close the connection.
1586 //
1587
1588 // Start the Session Timeout timer
1589 restartSessionTimeoutTimer(ctx);
1590 }
1591
1592 /**
1593 * Processes BGP KEEPALIVE message.
1594 *
1595 * @param ctx the Channel Handler Context
1596 * @param message the message to process
1597 */
1598 void processBgpKeepalive(ChannelHandlerContext ctx,
1599 ChannelBuffer message) {
1600 if (message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH !=
1601 BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH) {
1602 log.debug("BGP RX KEEPALIVE Error from {}: " +
1603 "Invalid total message length {}. Expected {}",
1604 remoteAddress,
1605 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH,
1606 BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH);
1607 //
1608 // ERROR: Bad Message Length
1609 //
1610 // Send NOTIFICATION and close the connection
1611 ChannelBuffer txMessage = prepareBgpNotificationBadMessageLength(
1612 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
1613 ctx.getChannel().write(txMessage);
Jonathan Hartff071a22014-12-03 12:10:00 -08001614 closeSession(ctx);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001615 return;
1616 }
1617
1618 //
1619 // Parse the KEEPALIVE message: nothing to do
1620 //
Jonathan Hartec2df012014-10-23 16:40:24 -07001621 log.trace("BGP RX KEEPALIVE message from {}", remoteAddress);
Jonathan Hartab63aac2014-10-16 08:52:55 -07001622
1623 // Start the Session Timeout timer
1624 restartSessionTimeoutTimer(ctx);
1625 }
1626
1627 /**
1628 * Prepares BGP OPEN message.
1629 *
1630 * @return the message to transmit (BGP header included)
1631 */
1632 private ChannelBuffer prepareBgpOpen() {
1633 ChannelBuffer message =
1634 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
1635
1636 //
1637 // Prepare the OPEN message payload
1638 //
1639 message.writeByte(localBgpVersion);
1640 message.writeShort((int) localAs);
1641 message.writeShort((int) localHoldtime);
Jonathan Hartbcae7bd2014-10-16 10:24:41 -07001642 message.writeInt(bgpSessionManager.getMyBgpId().toInt());
Jonathan Hartab63aac2014-10-16 08:52:55 -07001643 message.writeByte(0); // No Optional Parameters
1644 return prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN, message);
1645 }
1646
1647 /**
1648 * Prepares BGP KEEPALIVE message.
1649 *
1650 * @return the message to transmit (BGP header included)
1651 */
1652 private ChannelBuffer prepareBgpKeepalive() {
1653 ChannelBuffer message =
1654 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
1655
1656 //
1657 // Prepare the KEEPALIVE message payload: nothing to do
1658 //
1659 return prepareBgpMessage(BgpConstants.BGP_TYPE_KEEPALIVE, message);
1660 }
1661
1662 /**
1663 * Prepares BGP NOTIFICATION message.
1664 *
1665 * @param errorCode the BGP NOTIFICATION Error Code
1666 * @param errorSubcode the BGP NOTIFICATION Error Subcode if applicable,
1667 * otherwise BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC
Thomas Vachuska4b420772014-10-30 16:46:17 -07001668 * @param data the BGP NOTIFICATION Data if applicable, otherwise null
Jonathan Hartab63aac2014-10-16 08:52:55 -07001669 * @return the message to transmit (BGP header included)
1670 */
1671 ChannelBuffer prepareBgpNotification(int errorCode, int errorSubcode,
1672 ChannelBuffer data) {
1673 ChannelBuffer message =
1674 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
1675
1676 //
1677 // Prepare the NOTIFICATION message payload
1678 //
1679 message.writeByte(errorCode);
1680 message.writeByte(errorSubcode);
1681 if (data != null) {
1682 message.writeBytes(data);
1683 }
1684 return prepareBgpMessage(BgpConstants.BGP_TYPE_NOTIFICATION, message);
1685 }
1686
1687 /**
1688 * Prepares BGP NOTIFICATION message: Bad Message Length.
1689 *
1690 * @param length the erroneous Length field
1691 * @return the message to transmit (BGP header included)
1692 */
1693 ChannelBuffer prepareBgpNotificationBadMessageLength(int length) {
1694 int errorCode = MessageHeaderError.ERROR_CODE;
1695 int errorSubcode = MessageHeaderError.BAD_MESSAGE_LENGTH;
1696 ChannelBuffer data = ChannelBuffers.buffer(2);
1697 data.writeShort(length);
1698
1699 return prepareBgpNotification(errorCode, errorSubcode, data);
1700 }
1701
1702 /**
1703 * Prepares BGP UPDATE Notification data payload.
1704 *
1705 * @param attrTypeCode the attribute type code
1706 * @param attrLen the attribute length (in octets)
1707 * @param attrFlags the attribute flags
1708 * @param message the message with the data
1709 * @return the buffer with the data payload for the BGP UPDATE Notification
1710 */
1711 private ChannelBuffer prepareBgpUpdateNotificationDataPayload(
1712 int attrTypeCode,
1713 int attrLen,
1714 int attrFlags,
1715 ChannelBuffer message) {
1716 // Compute the attribute length field octets
1717 boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
1718 int attrLenOctets = 1;
1719 if (extendedLengthBit) {
1720 attrLenOctets = 2;
1721 }
1722 ChannelBuffer data =
1723 ChannelBuffers.buffer(attrLen + attrLenOctets + 1);
1724 data.writeByte(attrTypeCode);
1725 if (extendedLengthBit) {
1726 data.writeShort(attrLen);
1727 } else {
1728 data.writeByte(attrLen);
1729 }
1730 data.writeBytes(message, attrLen);
1731 return data;
1732 }
1733
1734 /**
1735 * Prepares BGP message.
1736 *
1737 * @param type the BGP message type
1738 * @param payload the message payload to transmit (BGP header excluded)
1739 * @return the message to transmit (BGP header included)
1740 */
1741 private ChannelBuffer prepareBgpMessage(int type, ChannelBuffer payload) {
1742 ChannelBuffer message =
1743 ChannelBuffers.buffer(BgpConstants.BGP_HEADER_LENGTH +
1744 payload.readableBytes());
1745
1746 // Write the marker
1747 for (int i = 0; i < BgpConstants.BGP_HEADER_MARKER_LENGTH; i++) {
1748 message.writeByte(0xff);
1749 }
1750
1751 // Write the rest of the BGP header
1752 message.writeShort(BgpConstants.BGP_HEADER_LENGTH +
1753 payload.readableBytes());
1754 message.writeByte(type);
1755
1756 // Write the payload
1757 message.writeBytes(payload);
1758 return message;
1759 }
1760
1761 /**
1762 * Restarts the BGP KeepaliveTimer.
1763 */
1764 private void restartKeepaliveTimer(ChannelHandlerContext ctx) {
1765 if (localKeepaliveInterval == 0) {
1766 return; // Nothing to do
1767 }
1768 keepaliveTimeout = timer.newTimeout(new TransmitKeepaliveTask(ctx),
1769 localKeepaliveInterval,
1770 TimeUnit.SECONDS);
1771 }
1772
1773 /**
1774 * Task class for transmitting KEEPALIVE messages.
1775 */
1776 private final class TransmitKeepaliveTask implements TimerTask {
1777 private final ChannelHandlerContext ctx;
1778
1779 /**
1780 * Constructor for given Channel Handler Context.
1781 *
1782 * @param ctx the Channel Handler Context to use
1783 */
1784 TransmitKeepaliveTask(ChannelHandlerContext ctx) {
1785 this.ctx = ctx;
1786 }
1787
1788 @Override
1789 public void run(Timeout timeout) throws Exception {
1790 if (timeout.isCancelled()) {
1791 return;
1792 }
1793 if (!ctx.getChannel().isOpen()) {
1794 return;
1795 }
1796
1797 // Transmit the KEEPALIVE
1798 ChannelBuffer txMessage = prepareBgpKeepalive();
1799 ctx.getChannel().write(txMessage);
1800
1801 // Restart the KEEPALIVE timer
1802 restartKeepaliveTimer(ctx);
1803 }
1804 }
1805
1806 /**
1807 * Restarts the BGP Session Timeout Timer.
1808 */
1809 private void restartSessionTimeoutTimer(ChannelHandlerContext ctx) {
1810 if (remoteHoldtime == 0) {
1811 return; // Nothing to do
1812 }
1813 if (sessionTimeout != null) {
1814 sessionTimeout.cancel();
1815 }
1816 sessionTimeout = timer.newTimeout(new SessionTimeoutTask(ctx),
1817 remoteHoldtime,
1818 TimeUnit.SECONDS);
1819 }
1820
1821 /**
1822 * Task class for BGP Session timeout.
1823 */
1824 private final class SessionTimeoutTask implements TimerTask {
1825 private final ChannelHandlerContext ctx;
1826
1827 /**
1828 * Constructor for given Channel Handler Context.
1829 *
1830 * @param ctx the Channel Handler Context to use
1831 */
1832 SessionTimeoutTask(ChannelHandlerContext ctx) {
1833 this.ctx = ctx;
1834 }
1835
1836 @Override
1837 public void run(Timeout timeout) throws Exception {
1838 if (timeout.isCancelled()) {
1839 return;
1840 }
1841 if (!ctx.getChannel().isOpen()) {
1842 return;
1843 }
1844
1845 log.debug("BGP Session Timeout: peer {}", remoteAddress);
1846 //
1847 // ERROR: Invalid Optional Parameter Length field: Unspecific
1848 //
1849 // Send NOTIFICATION and close the connection
1850 int errorCode = HoldTimerExpired.ERROR_CODE;
1851 int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
1852 ChannelBuffer txMessage =
1853 prepareBgpNotification(errorCode, errorSubcode, null);
1854 ctx.getChannel().write(txMessage);
1855 closeChannel(ctx);
1856 }
1857 }
1858
1859 /**
1860 * An exception indicating a parsing error of the BGP message.
1861 */
1862 private static class BgpParseException extends Exception {
1863 /**
1864 * Default constructor.
1865 */
1866 public BgpParseException() {
1867 super();
1868 }
1869
1870 /**
1871 * Constructor for a specific exception details message.
1872 *
1873 * @param message the message with the exception details
1874 */
1875 public BgpParseException(String message) {
1876 super(message);
1877 }
1878 }
1879}