blob: 2dabfd94c27544691d0866211d8b8a7c20eba1ae [file] [log] [blame]
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.sdnip.bgp;
17
18import java.util.ArrayList;
19import java.util.Collection;
20import java.util.HashMap;
21import java.util.Map;
22
23import org.apache.commons.lang3.tuple.Pair;
24import org.jboss.netty.buffer.ChannelBuffer;
25import org.jboss.netty.buffer.ChannelBuffers;
26import org.jboss.netty.channel.ChannelHandlerContext;
27import org.onlab.packet.Ip4Address;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -080028import org.onlab.packet.Ip6Address;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080029import org.onlab.packet.Ip4Prefix;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -080030import org.onlab.packet.Ip6Prefix;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080031import org.onosproject.sdnip.bgp.BgpConstants.Notifications.UpdateMessageError;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -080032import org.onosproject.sdnip.bgp.BgpConstants.Open.Capabilities.MultiprotocolExtensions;
33import org.onosproject.sdnip.bgp.BgpConstants.Update;
34import org.onosproject.sdnip.bgp.BgpConstants.Update.AsPath;
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -080035import org.onosproject.sdnip.bgp.BgpMessage.BgpParseException;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39/**
40 * A class for handling BGP UPDATE messages.
41 */
42final class BgpUpdate {
43 private static final Logger log = LoggerFactory.getLogger(BgpUpdate.class);
44
45 /**
46 * Default constructor.
47 * <p>
48 * The constructor is private to prevent creating an instance of
49 * this utility class.
50 */
51 private BgpUpdate() {
52 }
53
54 /**
55 * Processes BGP UPDATE message.
56 *
57 * @param bgpSession the BGP Session to use
58 * @param ctx the Channel Handler Context
59 * @param message the message to process
60 */
61 static void processBgpUpdate(BgpSession bgpSession,
62 ChannelHandlerContext ctx,
63 ChannelBuffer message) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -080064 DecodedBgpRoutes decodedBgpRoutes = new DecodedBgpRoutes();
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080065
66 int minLength =
67 BgpConstants.BGP_UPDATE_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
68 if (message.readableBytes() < minLength) {
69 log.debug("BGP RX UPDATE Error from {}: " +
70 "Message length {} too short. Must be at least {}",
71 bgpSession.getRemoteAddress(), message.readableBytes(),
72 minLength);
73 //
74 // ERROR: Bad Message Length
75 //
76 // Send NOTIFICATION and close the connection
77 ChannelBuffer txMessage =
78 BgpNotification.prepareBgpNotificationBadMessageLength(
79 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
80 ctx.getChannel().write(txMessage);
81 bgpSession.closeSession(ctx);
82 return;
83 }
84
85 log.debug("BGP RX UPDATE message from {}",
86 bgpSession.getRemoteAddress());
87
88 //
89 // Parse the UPDATE message
90 //
91
92 //
93 // Parse the Withdrawn Routes
94 //
95 int withdrawnRoutesLength = message.readUnsignedShort();
96 if (withdrawnRoutesLength > message.readableBytes()) {
97 // ERROR: Malformed Attribute List
98 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
99 return;
100 }
101 Collection<Ip4Prefix> withdrawnPrefixes = null;
102 try {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800103 withdrawnPrefixes = parsePackedIp4Prefixes(withdrawnRoutesLength,
104 message);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800105 } catch (BgpParseException e) {
106 // ERROR: Invalid Network Field
107 log.debug("Exception parsing Withdrawn Prefixes from BGP peer {}: ",
108 bgpSession.getRemoteBgpId(), e);
109 actionsBgpUpdateInvalidNetworkField(bgpSession, ctx);
110 return;
111 }
112 for (Ip4Prefix prefix : withdrawnPrefixes) {
113 log.debug("BGP RX UPDATE message WITHDRAWN from {}: {}",
114 bgpSession.getRemoteAddress(), prefix);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800115 BgpRouteEntry bgpRouteEntry = bgpSession.bgpRibIn4().get(prefix);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800116 if (bgpRouteEntry != null) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800117 decodedBgpRoutes.deletedUnicastRoutes4.put(prefix,
118 bgpRouteEntry);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800119 }
120 }
121
122 //
123 // Parse the Path Attributes
124 //
125 try {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800126 parsePathAttributes(bgpSession, ctx, message, decodedBgpRoutes);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800127 } catch (BgpParseException e) {
128 log.debug("Exception parsing Path Attributes from BGP peer {}: ",
129 bgpSession.getRemoteBgpId(), e);
130 // NOTE: The session was already closed, so nothing else to do
131 return;
132 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800133
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800134 //
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800135 // Update the BGP RIB-IN
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800136 //
137 Collection<BgpRouteEntry> bgpRoutes;
138 //
139 bgpRoutes = decodedBgpRoutes.deletedUnicastRoutes4.values();
140 for (BgpRouteEntry bgpRouteEntry : bgpRoutes) {
141 bgpSession.bgpRibIn4().remove(bgpRouteEntry.prefix());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800142 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800143 //
144 bgpRoutes = decodedBgpRoutes.addedUnicastRoutes4.values();
145 for (BgpRouteEntry bgpRouteEntry : bgpRoutes) {
146 bgpSession.bgpRibIn4().put(bgpRouteEntry.prefix(), bgpRouteEntry);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800147 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800148 //
149 bgpRoutes = decodedBgpRoutes.deletedUnicastRoutes6.values();
150 for (BgpRouteEntry bgpRouteEntry : bgpRoutes) {
151 bgpSession.bgpRibIn6().remove(bgpRouteEntry.prefix());
152 }
153 //
154 bgpRoutes = decodedBgpRoutes.addedUnicastRoutes6.values();
155 // TODO: fix/enable for IPv6
156 /*
157 for (BgpRouteEntry bgpRouteEntry : bgpRoutes) {
158 bgpSession.bgpRibIn6().put(bgpRouteEntry.prefix(), bgpRouteEntry);
159 }
160 */
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800161
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800162 //
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800163 // Push the updates to the BGP Merged RIB
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800164 //
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800165 BgpSessionManager.BgpRouteSelector bgpRouteSelector =
166 bgpSession.getBgpSessionManager().getBgpRouteSelector();
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800167 bgpRouteSelector.routeUpdates(bgpSession,
168 decodedBgpRoutes.addedUnicastRoutes4.values(),
169 decodedBgpRoutes.deletedUnicastRoutes4.values());
170 bgpRouteSelector.routeUpdates(bgpSession,
171 decodedBgpRoutes.addedUnicastRoutes6.values(),
172 decodedBgpRoutes.deletedUnicastRoutes6.values());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800173
174 // Start the Session Timeout timer
175 bgpSession.restartSessionTimeoutTimer(ctx);
176 }
177
178 /**
179 * Parse BGP Path Attributes from the BGP UPDATE message.
180 *
181 * @param bgpSession the BGP Session to use
182 * @param ctx the Channel Handler Context
183 * @param message the message to parse
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800184 * @param decodedBgpRoutes the container to store the decoded BGP Route
185 * Entries. It might already contain some route entries such as withdrawn
186 * IPv4 prefixes
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800187 * @throws BgpParseException
188 */
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800189 // CHECKSTYLE IGNORE MethodLength FOR NEXT 300 LINES
190 private static void parsePathAttributes(
191 BgpSession bgpSession,
192 ChannelHandlerContext ctx,
193 ChannelBuffer message,
194 DecodedBgpRoutes decodedBgpRoutes)
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800195 throws BgpParseException {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800196
197 //
198 // Parsed values
199 //
200 Short origin = -1; // Mandatory
201 BgpRouteEntry.AsPath asPath = null; // Mandatory
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800202 // Legacy NLRI (RFC 4271). Mandatory NEXT_HOP if legacy NLRI is used
203 MpNlri legacyNlri = new MpNlri(MultiprotocolExtensions.AFI_IPV4,
204 MultiprotocolExtensions.SAFI_UNICAST);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800205 long multiExitDisc = // Optional
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800206 Update.MultiExitDisc.LOWEST_MULTI_EXIT_DISC;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800207 Long localPref = null; // Mandatory
208 Long aggregatorAsNumber = null; // Optional: unused
209 Ip4Address aggregatorIpAddress = null; // Optional: unused
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800210 Collection<MpNlri> mpNlriReachList = new ArrayList<>(); // Optional
211 Collection<MpNlri> mpNlriUnreachList = new ArrayList<>(); // Optional
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800212
213 //
214 // Get and verify the Path Attributes Length
215 //
216 int pathAttributeLength = message.readUnsignedShort();
217 if (pathAttributeLength > message.readableBytes()) {
218 // ERROR: Malformed Attribute List
219 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
220 String errorMsg = "Malformed Attribute List";
221 throw new BgpParseException(errorMsg);
222 }
223 if (pathAttributeLength == 0) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800224 return;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800225 }
226
227 //
228 // Parse the Path Attributes
229 //
230 int pathAttributeEnd = message.readerIndex() + pathAttributeLength;
231 while (message.readerIndex() < pathAttributeEnd) {
232 int attrFlags = message.readUnsignedByte();
233 if (message.readerIndex() >= pathAttributeEnd) {
234 // ERROR: Malformed Attribute List
235 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
236 String errorMsg = "Malformed Attribute List";
237 throw new BgpParseException(errorMsg);
238 }
239 int attrTypeCode = message.readUnsignedByte();
240
241 // The Attribute Flags
242 boolean optionalBit = ((0x80 & attrFlags) != 0);
243 boolean transitiveBit = ((0x40 & attrFlags) != 0);
244 boolean partialBit = ((0x20 & attrFlags) != 0);
245 boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
246
247 // The Attribute Length
248 int attrLen = 0;
249 int attrLenOctets = 1;
250 if (extendedLengthBit) {
251 attrLenOctets = 2;
252 }
253 if (message.readerIndex() + attrLenOctets > pathAttributeEnd) {
254 // ERROR: Malformed Attribute List
255 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
256 String errorMsg = "Malformed Attribute List";
257 throw new BgpParseException(errorMsg);
258 }
259 if (extendedLengthBit) {
260 attrLen = message.readUnsignedShort();
261 } else {
262 attrLen = message.readUnsignedByte();
263 }
264 if (message.readerIndex() + attrLen > pathAttributeEnd) {
265 // ERROR: Malformed Attribute List
266 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
267 String errorMsg = "Malformed Attribute List";
268 throw new BgpParseException(errorMsg);
269 }
270
271 // Verify the Attribute Flags
272 verifyBgpUpdateAttributeFlags(bgpSession, ctx, attrTypeCode,
273 attrLen, attrFlags, message);
274
275 //
276 // Extract the Attribute Value based on the Attribute Type Code
277 //
278 switch (attrTypeCode) {
279
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800280 case Update.Origin.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800281 // Attribute Type Code ORIGIN
282 origin = parseAttributeTypeOrigin(bgpSession, ctx,
283 attrTypeCode, attrLen,
284 attrFlags, message);
285 break;
286
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800287 case Update.AsPath.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800288 // Attribute Type Code AS_PATH
289 asPath = parseAttributeTypeAsPath(bgpSession, ctx,
290 attrTypeCode, attrLen,
291 attrFlags, message);
292 break;
293
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800294 case Update.NextHop.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800295 // Attribute Type Code NEXT_HOP
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800296 legacyNlri.nextHop4 =
297 parseAttributeTypeNextHop(bgpSession, ctx,
298 attrTypeCode, attrLen,
299 attrFlags, message);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800300 break;
301
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800302 case Update.MultiExitDisc.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800303 // Attribute Type Code MULTI_EXIT_DISC
304 multiExitDisc =
305 parseAttributeTypeMultiExitDisc(bgpSession, ctx,
306 attrTypeCode, attrLen,
307 attrFlags, message);
308 break;
309
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800310 case Update.LocalPref.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800311 // Attribute Type Code LOCAL_PREF
312 localPref =
313 parseAttributeTypeLocalPref(bgpSession, ctx,
314 attrTypeCode, attrLen,
315 attrFlags, message);
316 break;
317
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800318 case Update.AtomicAggregate.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800319 // Attribute Type Code ATOMIC_AGGREGATE
320 parseAttributeTypeAtomicAggregate(bgpSession, ctx,
321 attrTypeCode, attrLen,
322 attrFlags, message);
323 // Nothing to do: this attribute is primarily informational
324 break;
325
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800326 case Update.Aggregator.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800327 // Attribute Type Code AGGREGATOR
328 Pair<Long, Ip4Address> aggregator =
329 parseAttributeTypeAggregator(bgpSession, ctx,
330 attrTypeCode, attrLen,
331 attrFlags, message);
332 aggregatorAsNumber = aggregator.getLeft();
333 aggregatorIpAddress = aggregator.getRight();
334 break;
335
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800336 case Update.MpReachNlri.TYPE:
337 // Attribute Type Code MP_REACH_NLRI
338 MpNlri mpNlriReach =
339 parseAttributeTypeMpReachNlri(bgpSession, ctx,
340 attrTypeCode,
341 attrLen,
342 attrFlags, message);
343 if (mpNlriReach != null) {
344 mpNlriReachList.add(mpNlriReach);
345 }
346 break;
347
348 case Update.MpUnreachNlri.TYPE:
349 // Attribute Type Code MP_UNREACH_NLRI
350 MpNlri mpNlriUnreach =
351 parseAttributeTypeMpUnreachNlri(bgpSession, ctx,
352 attrTypeCode, attrLen,
353 attrFlags, message);
354 if (mpNlriUnreach != null) {
355 mpNlriUnreachList.add(mpNlriUnreach);
356 }
357 break;
358
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800359 default:
360 // NOTE: Parse any new Attribute Types if needed
361 if (!optionalBit) {
362 // ERROR: Unrecognized Well-known Attribute
363 actionsBgpUpdateUnrecognizedWellKnownAttribute(
364 bgpSession, ctx, attrTypeCode, attrLen, attrFlags,
365 message);
366 String errorMsg = "Unrecognized Well-known Attribute: " +
367 attrTypeCode;
368 throw new BgpParseException(errorMsg);
369 }
370
371 // Skip the data from the unrecognized attribute
372 log.debug("BGP RX UPDATE message from {}: " +
373 "Unrecognized Attribute Type {}",
374 bgpSession.getRemoteAddress(), attrTypeCode);
375 message.skipBytes(attrLen);
376 break;
377 }
378 }
379
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800380 //
381 // Parse the NLRI (Network Layer Reachability Information)
382 //
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800383 int nlriLength = message.readableBytes();
384 try {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800385 Collection<Ip4Prefix> addedPrefixes4 =
386 parsePackedIp4Prefixes(nlriLength, message);
387 // Store it inside the legacy NLRI wrapper
388 legacyNlri.nlri4 = addedPrefixes4;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800389 } catch (BgpParseException e) {
390 // ERROR: Invalid Network Field
391 log.debug("Exception parsing NLRI from BGP peer {}: ",
392 bgpSession.getRemoteBgpId(), e);
393 actionsBgpUpdateInvalidNetworkField(bgpSession, ctx);
394 // Rethrow the exception
395 throw e;
396 }
397
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800398 // Verify the Well-known Attributes
399 verifyBgpUpdateWellKnownAttributes(bgpSession, ctx, origin, asPath,
400 localPref, legacyNlri,
401 mpNlriReachList);
402
403 //
404 // Generate the deleted routes
405 //
406 for (MpNlri mpNlri : mpNlriUnreachList) {
407 BgpRouteEntry bgpRouteEntry;
408
409 // The deleted IPv4 routes
410 for (Ip4Prefix prefix : mpNlri.nlri4) {
411 bgpRouteEntry = bgpSession.bgpRibIn4().get(prefix);
412 if (bgpRouteEntry != null) {
413 decodedBgpRoutes.deletedUnicastRoutes4.put(prefix,
414 bgpRouteEntry);
415 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800416 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800417
418 // The deleted IPv6 routes
419 for (Ip6Prefix prefix : mpNlri.nlri6) {
420 bgpRouteEntry = bgpSession.bgpRibIn6().get(prefix);
421 if (bgpRouteEntry != null) {
422 decodedBgpRoutes.deletedUnicastRoutes6.put(prefix,
423 bgpRouteEntry);
424 }
425 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800426 }
427
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800428 //
429 // Generate the added routes
430 //
431 mpNlriReachList.add(legacyNlri);
432 for (MpNlri mpNlri : mpNlriReachList) {
433 BgpRouteEntry bgpRouteEntry;
434
435 // The added IPv4 routes
436 for (Ip4Prefix prefix : mpNlri.nlri4) {
437 bgpRouteEntry =
438 new BgpRouteEntry(bgpSession, prefix, mpNlri.nextHop4,
439 origin.byteValue(), asPath, localPref);
440 bgpRouteEntry.setMultiExitDisc(multiExitDisc);
441 if (bgpRouteEntry.hasAsPathLoop(bgpSession.getLocalAs())) {
442 log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
443 "nextHop {}: contains AS Path loop",
444 bgpSession.getRemoteAddress(), prefix,
445 mpNlri.nextHop4);
446 continue;
447 } else {
448 log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
449 bgpSession.getRemoteAddress(), prefix,
450 mpNlri.nextHop4);
451 }
452 // Remove from the collection of deleted routes
453 decodedBgpRoutes.deletedUnicastRoutes4.remove(prefix);
454 decodedBgpRoutes.addedUnicastRoutes4.put(prefix,
455 bgpRouteEntry);
456 }
457
458 // The added IPv6 routes
459 // TODO: fix/enable for IPv6
460 /*
461 for (Ip6Prefix prefix : mpNlri.nlri6) {
462 bgpRouteEntry =
463 new BgpRouteEntry(bgpSession, prefix, mpNlri.nextHop6,
464 origin.byteValue(), asPath, localPref);
465 bgpRouteEntry.setMultiExitDisc(multiExitDisc);
466 if (bgpRouteEntry.hasAsPathLoop(bgpSession.getLocalAs())) {
467 log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
468 "nextHop {}: contains AS Path loop",
469 bgpSession.getRemoteAddress(), prefix,
470 mpNlri.nextHop6);
471 continue;
472 } else {
473 log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
474 bgpSession.getRemoteAddress(), prefix,
475 mpNlri.nextHop6);
476 }
477 // Remove from the collection of deleted routes
478 decodedBgpRoutes.deletedUnicastRoutes6.remove(prefix);
479 decodedBgpRoutes.addedUnicastRoutes6.put(prefix,
480 bgpRouteEntry);
481 }
482 */
483 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800484 }
485
486 /**
487 * Verifies BGP UPDATE Well-known Attributes.
488 *
489 * @param bgpSession the BGP Session to use
490 * @param ctx the Channel Handler Context
491 * @param origin the ORIGIN well-known mandatory attribute
492 * @param asPath the AS_PATH well-known mandatory attribute
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800493 * @param localPref the LOCAL_PREF required attribute
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800494 * @param legacyNlri the legacy NLRI. Encapsulates the NEXT_HOP well-known
495 * mandatory attribute (mandatory if legacy NLRI is used).
496 * @param mpNlriReachList the Multiprotocol NLRI attributes
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800497 * @throws BgpParseException
498 */
499 private static void verifyBgpUpdateWellKnownAttributes(
500 BgpSession bgpSession,
501 ChannelHandlerContext ctx,
502 Short origin,
503 BgpRouteEntry.AsPath asPath,
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800504 Long localPref,
505 MpNlri legacyNlri,
506 Collection<MpNlri> mpNlriReachList)
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800507 throws BgpParseException {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800508 boolean hasNlri = false;
509 boolean hasLegacyNlri = false;
510
511 //
512 // Convenience flags that are used to check for missing attributes.
513 //
514 // NOTE: The hasLegacyNlri flag is always set to true if the
515 // Multiprotocol Extensions are not enabled, even if the UPDATE
516 // message doesn't contain the legacy NLRI (per RFC 4271).
517 //
518 if (!bgpSession.getMpExtensions()) {
519 hasNlri = true;
520 hasLegacyNlri = true;
521 } else {
522 if (!legacyNlri.nlri4.isEmpty()) {
523 hasNlri = true;
524 hasLegacyNlri = true;
525 }
526 if (!mpNlriReachList.isEmpty()) {
527 hasNlri = true;
528 }
529 }
530
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800531 //
532 // Check for Missing Well-known Attributes
533 //
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800534 if (hasNlri && ((origin == null) || (origin == -1))) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800535 // Missing Attribute Type Code ORIGIN
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800536 int type = Update.Origin.TYPE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800537 actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
538 String errorMsg = "Missing Well-known Attribute: ORIGIN";
539 throw new BgpParseException(errorMsg);
540 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800541 if (hasNlri && (asPath == null)) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800542 // Missing Attribute Type Code AS_PATH
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800543 int type = Update.AsPath.TYPE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800544 actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
545 String errorMsg = "Missing Well-known Attribute: AS_PATH";
546 throw new BgpParseException(errorMsg);
547 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800548 if (hasNlri && (localPref == null)) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800549 // Missing Attribute Type Code LOCAL_PREF
550 // NOTE: Required for iBGP
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800551 int type = Update.LocalPref.TYPE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800552 actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
553 String errorMsg = "Missing Well-known Attribute: LOCAL_PREF";
554 throw new BgpParseException(errorMsg);
555 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800556 if (hasLegacyNlri && (legacyNlri.nextHop4 == null)) {
557 // Missing Attribute Type Code NEXT_HOP
558 int type = Update.NextHop.TYPE;
559 actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
560 String errorMsg = "Missing Well-known Attribute: NEXT_HOP";
561 throw new BgpParseException(errorMsg);
562 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800563 }
564
565 /**
566 * Verifies the BGP UPDATE Attribute Flags.
567 *
568 * @param bgpSession the BGP Session to use
569 * @param ctx the Channel Handler Context
570 * @param attrTypeCode the attribute type code
571 * @param attrLen the attribute length (in octets)
572 * @param attrFlags the attribute flags
573 * @param message the message to parse
574 * @throws BgpParseException
575 */
576 private static void verifyBgpUpdateAttributeFlags(
577 BgpSession bgpSession,
578 ChannelHandlerContext ctx,
579 int attrTypeCode,
580 int attrLen,
581 int attrFlags,
582 ChannelBuffer message)
583 throws BgpParseException {
584
585 //
586 // Assign the Attribute Type Name and the Well-known flag
587 //
588 String typeName = "UNKNOWN";
589 boolean isWellKnown = false;
590 switch (attrTypeCode) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800591 case Update.Origin.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800592 isWellKnown = true;
593 typeName = "ORIGIN";
594 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800595 case Update.AsPath.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800596 isWellKnown = true;
597 typeName = "AS_PATH";
598 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800599 case Update.NextHop.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800600 isWellKnown = true;
601 typeName = "NEXT_HOP";
602 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800603 case Update.MultiExitDisc.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800604 isWellKnown = false;
605 typeName = "MULTI_EXIT_DISC";
606 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800607 case Update.LocalPref.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800608 isWellKnown = true;
609 typeName = "LOCAL_PREF";
610 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800611 case Update.AtomicAggregate.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800612 isWellKnown = true;
613 typeName = "ATOMIC_AGGREGATE";
614 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800615 case Update.Aggregator.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800616 isWellKnown = false;
617 typeName = "AGGREGATOR";
618 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800619 case Update.MpReachNlri.TYPE:
620 isWellKnown = false;
621 typeName = "MP_REACH_NLRI";
622 break;
623 case Update.MpUnreachNlri.TYPE:
624 isWellKnown = false;
625 typeName = "MP_UNREACH_NLRI";
626 break;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800627 default:
628 isWellKnown = false;
629 typeName = "UNKNOWN(" + attrTypeCode + ")";
630 break;
631 }
632
633 //
634 // Verify the Attribute Flags
635 //
636 boolean optionalBit = ((0x80 & attrFlags) != 0);
637 boolean transitiveBit = ((0x40 & attrFlags) != 0);
638 boolean partialBit = ((0x20 & attrFlags) != 0);
639 if ((isWellKnown && optionalBit) ||
640 (isWellKnown && (!transitiveBit)) ||
641 (isWellKnown && partialBit) ||
642 (optionalBit && (!transitiveBit) && partialBit)) {
643 //
644 // ERROR: The Optional bit cannot be set for Well-known attributes
645 // ERROR: The Transtive bit MUST be 1 for well-known attributes
646 // ERROR: The Partial bit MUST be 0 for well-known attributes
647 // ERROR: The Partial bit MUST be 0 for optional non-transitive
648 // attributes
649 //
650 actionsBgpUpdateAttributeFlagsError(
651 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
652 String errorMsg = "Attribute Flags Error for " + typeName + ": " +
653 attrFlags;
654 throw new BgpParseException(errorMsg);
655 }
656 }
657
658 /**
659 * Parses BGP UPDATE Attribute Type ORIGIN.
660 *
661 * @param bgpSession the BGP Session to use
662 * @param ctx the Channel Handler Context
663 * @param attrTypeCode the attribute type code
664 * @param attrLen the attribute length (in octets)
665 * @param attrFlags the attribute flags
666 * @param message the message to parse
667 * @return the parsed ORIGIN value
668 * @throws BgpParseException
669 */
670 private static short parseAttributeTypeOrigin(
671 BgpSession bgpSession,
672 ChannelHandlerContext ctx,
673 int attrTypeCode,
674 int attrLen,
675 int attrFlags,
676 ChannelBuffer message)
677 throws BgpParseException {
678
679 // Check the Attribute Length
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800680 if (attrLen != Update.Origin.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800681 // ERROR: Attribute Length Error
682 actionsBgpUpdateAttributeLengthError(
683 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
684 String errorMsg = "Attribute Length Error";
685 throw new BgpParseException(errorMsg);
686 }
687
688 message.markReaderIndex();
689 short origin = message.readUnsignedByte();
690 switch (origin) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800691 case Update.Origin.IGP:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800692 // FALLTHROUGH
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800693 case Update.Origin.EGP:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800694 // FALLTHROUGH
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800695 case Update.Origin.INCOMPLETE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800696 break;
697 default:
698 // ERROR: Invalid ORIGIN Attribute
699 message.resetReaderIndex();
700 actionsBgpUpdateInvalidOriginAttribute(
701 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message,
702 origin);
703 String errorMsg = "Invalid ORIGIN Attribute: " + origin;
704 throw new BgpParseException(errorMsg);
705 }
706
707 return origin;
708 }
709
710 /**
711 * Parses BGP UPDATE Attribute AS Path.
712 *
713 * @param bgpSession the BGP Session to use
714 * @param ctx the Channel Handler Context
715 * @param attrTypeCode the attribute type code
716 * @param attrLen the attribute length (in octets)
717 * @param attrFlags the attribute flags
718 * @param message the message to parse
719 * @return the parsed AS Path
720 * @throws BgpParseException
721 */
722 private static BgpRouteEntry.AsPath parseAttributeTypeAsPath(
723 BgpSession bgpSession,
724 ChannelHandlerContext ctx,
725 int attrTypeCode,
726 int attrLen,
727 int attrFlags,
728 ChannelBuffer message)
729 throws BgpParseException {
730 ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
731
732 //
733 // Parse the message
734 //
735 while (attrLen > 0) {
736 if (attrLen < 2) {
737 // ERROR: Malformed AS_PATH
738 actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
739 String errorMsg = "Malformed AS Path";
740 throw new BgpParseException(errorMsg);
741 }
742 // Get the Path Segment Type and Length (in number of ASes)
743 short pathSegmentType = message.readUnsignedByte();
744 short pathSegmentLength = message.readUnsignedByte();
745 attrLen -= 2;
746
747 // Verify the Path Segment Type
748 switch (pathSegmentType) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800749 case Update.AsPath.AS_SET:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800750 // FALLTHROUGH
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800751 case Update.AsPath.AS_SEQUENCE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800752 // FALLTHROUGH
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800753 case Update.AsPath.AS_CONFED_SEQUENCE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800754 // FALLTHROUGH
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800755 case Update.AsPath.AS_CONFED_SET:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800756 break;
757 default:
758 // ERROR: Invalid Path Segment Type
759 //
760 // NOTE: The BGP Spec (RFC 4271) doesn't contain Error Subcode
761 // for "Invalid Path Segment Type", hence we return
762 // the error as "Malformed AS_PATH".
763 //
764 actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
765 String errorMsg =
766 "Invalid AS Path Segment Type: " + pathSegmentType;
767 throw new BgpParseException(errorMsg);
768 }
769
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900770 // 4-octet AS number handling.
771 int asPathLen;
772 if (bgpSession.isAs4OctetCapable()) {
773 asPathLen = AsPath.AS_4OCTET_LENGTH;
774 } else {
775 asPathLen = AsPath.AS_LENGTH;
776 }
777
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800778 // Parse the AS numbers
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900779 if (asPathLen * pathSegmentLength > attrLen) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800780 // ERROR: Malformed AS_PATH
781 actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
782 String errorMsg = "Malformed AS Path";
783 throw new BgpParseException(errorMsg);
784 }
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900785 attrLen -= (asPathLen * pathSegmentLength);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800786 ArrayList<Long> segmentAsNumbers = new ArrayList<>();
787 while (pathSegmentLength-- > 0) {
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900788 long asNumber;
789 if (asPathLen == AsPath.AS_4OCTET_LENGTH) {
790 asNumber = message.readUnsignedInt();
791 } else {
792 asNumber = message.readUnsignedShort();
793 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800794 segmentAsNumbers.add(asNumber);
795 }
796
797 BgpRouteEntry.PathSegment pathSegment =
798 new BgpRouteEntry.PathSegment((byte) pathSegmentType,
799 segmentAsNumbers);
800 pathSegments.add(pathSegment);
801 }
802
803 return new BgpRouteEntry.AsPath(pathSegments);
804 }
805
806 /**
807 * Parses BGP UPDATE Attribute Type NEXT_HOP.
808 *
809 * @param bgpSession the BGP Session to use
810 * @param ctx the Channel Handler Context
811 * @param attrTypeCode the attribute type code
812 * @param attrLen the attribute length (in octets)
813 * @param attrFlags the attribute flags
814 * @param message the message to parse
815 * @return the parsed NEXT_HOP value
816 * @throws BgpParseException
817 */
818 private static Ip4Address parseAttributeTypeNextHop(
819 BgpSession bgpSession,
820 ChannelHandlerContext ctx,
821 int attrTypeCode,
822 int attrLen,
823 int attrFlags,
824 ChannelBuffer message)
825 throws BgpParseException {
826
827 // Check the Attribute Length
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800828 if (attrLen != Update.NextHop.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800829 // ERROR: Attribute Length Error
830 actionsBgpUpdateAttributeLengthError(
831 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
832 String errorMsg = "Attribute Length Error";
833 throw new BgpParseException(errorMsg);
834 }
835
836 message.markReaderIndex();
837 Ip4Address nextHopAddress =
838 Ip4Address.valueOf((int) message.readUnsignedInt());
839 //
840 // Check whether the NEXT_HOP IP address is semantically correct.
841 // As per RFC 4271, Section 6.3:
842 //
843 // a) It MUST NOT be the IP address of the receiving speaker
844 // b) In the case of an EBGP ....
845 //
846 // Here we check only (a), because (b) doesn't apply for us: all our
847 // peers are iBGP.
848 //
849 if (nextHopAddress.equals(bgpSession.getLocalIp4Address())) {
850 // ERROR: Invalid NEXT_HOP Attribute
851 message.resetReaderIndex();
852 actionsBgpUpdateInvalidNextHopAttribute(
853 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message,
854 nextHopAddress);
855 String errorMsg = "Invalid NEXT_HOP Attribute: " + nextHopAddress;
856 throw new BgpParseException(errorMsg);
857 }
858
859 return nextHopAddress;
860 }
861
862 /**
863 * Parses BGP UPDATE Attribute Type MULTI_EXIT_DISC.
864 *
865 * @param bgpSession the BGP Session to use
866 * @param ctx the Channel Handler Context
867 * @param attrTypeCode the attribute type code
868 * @param attrLen the attribute length (in octets)
869 * @param attrFlags the attribute flags
870 * @param message the message to parse
871 * @return the parsed MULTI_EXIT_DISC value
872 * @throws BgpParseException
873 */
874 private static long parseAttributeTypeMultiExitDisc(
875 BgpSession bgpSession,
876 ChannelHandlerContext ctx,
877 int attrTypeCode,
878 int attrLen,
879 int attrFlags,
880 ChannelBuffer message)
881 throws BgpParseException {
882
883 // Check the Attribute Length
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800884 if (attrLen != Update.MultiExitDisc.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800885 // ERROR: Attribute Length Error
886 actionsBgpUpdateAttributeLengthError(
887 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
888 String errorMsg = "Attribute Length Error";
889 throw new BgpParseException(errorMsg);
890 }
891
892 long multiExitDisc = message.readUnsignedInt();
893 return multiExitDisc;
894 }
895
896 /**
897 * Parses BGP UPDATE Attribute Type LOCAL_PREF.
898 *
899 * @param bgpSession the BGP Session to use
900 * @param ctx the Channel Handler Context
901 * @param attrTypeCode the attribute type code
902 * @param attrLen the attribute length (in octets)
903 * @param attrFlags the attribute flags
904 * @param message the message to parse
905 * @return the parsed LOCAL_PREF value
906 * @throws BgpParseException
907 */
908 private static long parseAttributeTypeLocalPref(
909 BgpSession bgpSession,
910 ChannelHandlerContext ctx,
911 int attrTypeCode,
912 int attrLen,
913 int attrFlags,
914 ChannelBuffer message)
915 throws BgpParseException {
916
917 // Check the Attribute Length
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800918 if (attrLen != Update.LocalPref.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800919 // ERROR: Attribute Length Error
920 actionsBgpUpdateAttributeLengthError(
921 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
922 String errorMsg = "Attribute Length Error";
923 throw new BgpParseException(errorMsg);
924 }
925
926 long localPref = message.readUnsignedInt();
927 return localPref;
928 }
929
930 /**
931 * Parses BGP UPDATE Attribute Type ATOMIC_AGGREGATE.
932 *
933 * @param bgpSession the BGP Session to use
934 * @param ctx the Channel Handler Context
935 * @param attrTypeCode the attribute type code
936 * @param attrLen the attribute length (in octets)
937 * @param attrFlags the attribute flags
938 * @param message the message to parse
939 * @throws BgpParseException
940 */
941 private static void parseAttributeTypeAtomicAggregate(
942 BgpSession bgpSession,
943 ChannelHandlerContext ctx,
944 int attrTypeCode,
945 int attrLen,
946 int attrFlags,
947 ChannelBuffer message)
948 throws BgpParseException {
949
950 // Check the Attribute Length
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800951 if (attrLen != Update.AtomicAggregate.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800952 // ERROR: Attribute Length Error
953 actionsBgpUpdateAttributeLengthError(
954 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
955 String errorMsg = "Attribute Length Error";
956 throw new BgpParseException(errorMsg);
957 }
958
959 // Nothing to do: this attribute is primarily informational
960 }
961
962 /**
963 * Parses BGP UPDATE Attribute Type AGGREGATOR.
964 *
965 * @param bgpSession the BGP Session to use
966 * @param ctx the Channel Handler Context
967 * @param attrTypeCode the attribute type code
968 * @param attrLen the attribute length (in octets)
969 * @param attrFlags the attribute flags
970 * @param message the message to parse
971 * @return the parsed AGGREGATOR value: a tuple of <AS-Number, IP-Address>
972 * @throws BgpParseException
973 */
974 private static Pair<Long, Ip4Address> parseAttributeTypeAggregator(
975 BgpSession bgpSession,
976 ChannelHandlerContext ctx,
977 int attrTypeCode,
978 int attrLen,
979 int attrFlags,
980 ChannelBuffer message)
981 throws BgpParseException {
982
983 // Check the Attribute Length
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800984 if (attrLen != Update.Aggregator.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800985 // ERROR: Attribute Length Error
986 actionsBgpUpdateAttributeLengthError(
987 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
988 String errorMsg = "Attribute Length Error";
989 throw new BgpParseException(errorMsg);
990 }
991
992 // The AGGREGATOR AS number
993 long aggregatorAsNumber = message.readUnsignedShort();
994 // The AGGREGATOR IP address
995 Ip4Address aggregatorIpAddress =
996 Ip4Address.valueOf((int) message.readUnsignedInt());
997
998 Pair<Long, Ip4Address> aggregator = Pair.of(aggregatorAsNumber,
999 aggregatorIpAddress);
1000 return aggregator;
1001 }
1002
1003 /**
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001004 * Parses BGP UPDATE Attribute Type MP_REACH_NLRI.
1005 *
1006 * @param bgpSession the BGP Session to use
1007 * @param ctx the Channel Handler Context
1008 * @param attrTypeCode the attribute type code
1009 * @param attrLen the attribute length (in octets)
1010 * @param attrFlags the attribute flags
1011 * @param message the message to parse
1012 * @return the parsed MP_REACH_NLRI information if recognized, otherwise
1013 * null
1014 * @throws BgpParseException
1015 */
1016 private static MpNlri parseAttributeTypeMpReachNlri(
1017 BgpSession bgpSession,
1018 ChannelHandlerContext ctx,
1019 int attrTypeCode,
1020 int attrLen,
1021 int attrFlags,
1022 ChannelBuffer message)
1023 throws BgpParseException {
1024 int attributeEnd = message.readerIndex() + attrLen;
1025
1026 // Check the Attribute Length
1027 if (attrLen < Update.MpReachNlri.MIN_LENGTH) {
1028 // ERROR: Attribute Length Error
1029 actionsBgpUpdateAttributeLengthError(
1030 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1031 String errorMsg = "Attribute Length Error";
1032 throw new BgpParseException(errorMsg);
1033 }
1034
1035 message.markReaderIndex();
1036 int afi = message.readUnsignedShort();
1037 int safi = message.readUnsignedByte();
1038 int nextHopLen = message.readUnsignedByte();
1039
1040 //
1041 // Verify the AFI/SAFI, and skip the attribute if not recognized.
1042 // NOTE: Currently, we support only IPv4/IPv6 UNICAST
1043 //
1044 if (((afi != MultiprotocolExtensions.AFI_IPV4) &&
1045 (afi != MultiprotocolExtensions.AFI_IPV6)) ||
1046 (safi != MultiprotocolExtensions.SAFI_UNICAST)) {
1047 // Skip the attribute
1048 message.resetReaderIndex();
1049 message.skipBytes(attrLen);
1050 return null;
1051 }
1052
1053 //
1054 // Verify the next-hop length
1055 //
1056 int expectedNextHopLen = 0;
1057 switch (afi) {
1058 case MultiprotocolExtensions.AFI_IPV4:
1059 expectedNextHopLen = Ip4Address.BYTE_LENGTH;
1060 break;
1061 case MultiprotocolExtensions.AFI_IPV6:
1062 expectedNextHopLen = Ip6Address.BYTE_LENGTH;
1063 break;
1064 default:
1065 // UNREACHABLE
1066 break;
1067 }
1068 if (nextHopLen != expectedNextHopLen) {
1069 // ERROR: Optional Attribute Error
1070 message.resetReaderIndex();
1071 actionsBgpUpdateOptionalAttributeError(
1072 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1073 String errorMsg = "Invalid next-hop network address length. " +
1074 "Received " + nextHopLen + " expected " + expectedNextHopLen;
1075 throw new BgpParseException(errorMsg);
1076 }
1077 // NOTE: We use "+ 1" to take into account the Reserved field (1 octet)
1078 if (message.readerIndex() + nextHopLen + 1 >= attributeEnd) {
1079 // ERROR: Optional Attribute Error
1080 message.resetReaderIndex();
1081 actionsBgpUpdateOptionalAttributeError(
1082 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1083 String errorMsg = "Malformed next-hop network address";
1084 throw new BgpParseException(errorMsg);
1085 }
1086
1087 //
1088 // Get the Next-hop address, skip the Reserved field, and get the NLRI
1089 //
1090 byte[] nextHopBuffer = new byte[nextHopLen];
1091 message.readBytes(nextHopBuffer, 0, nextHopLen);
1092 int reserved = message.readUnsignedByte();
1093 MpNlri mpNlri = new MpNlri(afi, safi);
1094 try {
1095 switch (afi) {
1096 case MultiprotocolExtensions.AFI_IPV4:
1097 // The next-hop address
1098 mpNlri.nextHop4 = Ip4Address.valueOf(nextHopBuffer);
1099 // The NLRI
1100 mpNlri.nlri4 = parsePackedIp4Prefixes(
1101 attributeEnd - message.readerIndex(),
1102 message);
1103 break;
1104 case MultiprotocolExtensions.AFI_IPV6:
1105 // The next-hop address
1106 mpNlri.nextHop6 = Ip6Address.valueOf(nextHopBuffer);
1107 // The NLRI
1108 mpNlri.nlri6 = parsePackedIp6Prefixes(
1109 attributeEnd - message.readerIndex(),
1110 message);
1111 break;
1112 default:
1113 // UNREACHABLE
1114 break;
1115 }
1116 } catch (BgpParseException e) {
1117 // ERROR: Optional Attribute Error
1118 message.resetReaderIndex();
1119 actionsBgpUpdateOptionalAttributeError(
1120 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1121 String errorMsg = "Malformed network layer reachability information";
1122 throw new BgpParseException(errorMsg);
1123 }
1124
1125 return mpNlri;
1126 }
1127
1128 /**
1129 * Parses BGP UPDATE Attribute Type MP_UNREACH_NLRI.
1130 *
1131 * @param bgpSession the BGP Session to use
1132 * @param ctx the Channel Handler Context
1133 * @param attrTypeCode the attribute type code
1134 * @param attrLen the attribute length (in octets)
1135 * @param attrFlags the attribute flags
1136 * @param message the message to parse
1137 * @return the parsed MP_UNREACH_NLRI information if recognized, otherwise
1138 * null
1139 * @throws BgpParseException
1140 */
1141 private static MpNlri parseAttributeTypeMpUnreachNlri(
1142 BgpSession bgpSession,
1143 ChannelHandlerContext ctx,
1144 int attrTypeCode,
1145 int attrLen,
1146 int attrFlags,
1147 ChannelBuffer message)
1148 throws BgpParseException {
1149 int attributeEnd = message.readerIndex() + attrLen;
1150
1151 // Check the Attribute Length
1152 if (attrLen < Update.MpUnreachNlri.MIN_LENGTH) {
1153 // ERROR: Attribute Length Error
1154 actionsBgpUpdateAttributeLengthError(
1155 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1156 String errorMsg = "Attribute Length Error";
1157 throw new BgpParseException(errorMsg);
1158 }
1159
1160 message.markReaderIndex();
1161 int afi = message.readUnsignedShort();
1162 int safi = message.readUnsignedByte();
1163
1164 //
1165 // Verify the AFI/SAFI, and skip the attribute if not recognized.
1166 // NOTE: Currently, we support only IPv4/IPv6 UNICAST
1167 //
1168 if (((afi != MultiprotocolExtensions.AFI_IPV4) &&
1169 (afi != MultiprotocolExtensions.AFI_IPV6)) ||
1170 (safi != MultiprotocolExtensions.SAFI_UNICAST)) {
1171 // Skip the attribute
1172 message.resetReaderIndex();
1173 message.skipBytes(attrLen);
1174 return null;
1175 }
1176
1177 //
1178 // Get the Withdrawn Routes
1179 //
1180 MpNlri mpNlri = new MpNlri(afi, safi);
1181 try {
1182 switch (afi) {
1183 case MultiprotocolExtensions.AFI_IPV4:
1184 // The Withdrawn Routes
1185 mpNlri.nlri4 = parsePackedIp4Prefixes(
1186 attributeEnd - message.readerIndex(),
1187 message);
1188 break;
1189 case MultiprotocolExtensions.AFI_IPV6:
1190 // The Withdrawn Routes
1191 mpNlri.nlri6 = parsePackedIp6Prefixes(
1192 attributeEnd - message.readerIndex(),
1193 message);
1194 break;
1195 default:
1196 // UNREACHABLE
1197 break;
1198 }
1199 } catch (BgpParseException e) {
1200 // ERROR: Optional Attribute Error
1201 message.resetReaderIndex();
1202 actionsBgpUpdateOptionalAttributeError(
1203 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1204 String errorMsg = "Malformed withdrawn routes";
1205 throw new BgpParseException(errorMsg);
1206 }
1207
1208 return mpNlri;
1209 }
1210
1211 /**
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001212 * Parses a message that contains encoded IPv4 network prefixes.
1213 * <p>
1214 * The IPv4 prefixes are encoded in the form:
1215 * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
1216 * and Prefix is the IPv4 prefix (padded with trailing bits to the end
1217 * of an octet).
1218 *
1219 * @param totalLength the total length of the data to parse
1220 * @param message the message with data to parse
1221 * @return a collection of parsed IPv4 network prefixes
1222 * @throws BgpParseException
1223 */
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001224 private static Collection<Ip4Prefix> parsePackedIp4Prefixes(
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001225 int totalLength,
1226 ChannelBuffer message)
1227 throws BgpParseException {
1228 Collection<Ip4Prefix> result = new ArrayList<>();
1229
1230 if (totalLength == 0) {
1231 return result;
1232 }
1233
1234 // Parse the data
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001235 byte[] buffer = new byte[Ip4Address.BYTE_LENGTH];
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001236 int dataEnd = message.readerIndex() + totalLength;
1237 while (message.readerIndex() < dataEnd) {
1238 int prefixBitlen = message.readUnsignedByte();
1239 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
1240 if (message.readerIndex() + prefixBytelen > dataEnd) {
1241 String errorMsg = "Malformed Network Prefixes";
1242 throw new BgpParseException(errorMsg);
1243 }
1244
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001245 message.readBytes(buffer, 0, prefixBytelen);
1246 Ip4Prefix prefix = Ip4Prefix.valueOf(Ip4Address.valueOf(buffer),
1247 prefixBitlen);
1248 result.add(prefix);
1249 }
1250
1251 return result;
1252 }
1253
1254 /**
1255 * Parses a message that contains encoded IPv6 network prefixes.
1256 * <p>
1257 * The IPv6 prefixes are encoded in the form:
1258 * <Length, Prefix> where Length is the length in bits of the IPv6 prefix,
1259 * and Prefix is the IPv6 prefix (padded with trailing bits to the end
1260 * of an octet).
1261 *
1262 * @param totalLength the total length of the data to parse
1263 * @param message the message with data to parse
1264 * @return a collection of parsed IPv6 network prefixes
1265 * @throws BgpParseException
1266 */
1267 private static Collection<Ip6Prefix> parsePackedIp6Prefixes(
1268 int totalLength,
1269 ChannelBuffer message)
1270 throws BgpParseException {
1271 Collection<Ip6Prefix> result = new ArrayList<>();
1272
1273 if (totalLength == 0) {
1274 return result;
1275 }
1276
1277 // Parse the data
1278 byte[] buffer = new byte[Ip6Address.BYTE_LENGTH];
1279 int dataEnd = message.readerIndex() + totalLength;
1280 while (message.readerIndex() < dataEnd) {
1281 int prefixBitlen = message.readUnsignedByte();
1282 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
1283 if (message.readerIndex() + prefixBytelen > dataEnd) {
1284 String errorMsg = "Malformed Network Prefixes";
1285 throw new BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001286 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001287
1288 message.readBytes(buffer, 0, prefixBytelen);
1289 Ip6Prefix prefix = Ip6Prefix.valueOf(Ip6Address.valueOf(buffer),
1290 prefixBitlen);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001291 result.add(prefix);
1292 }
1293
1294 return result;
1295 }
1296
1297 /**
1298 * Applies the appropriate actions after detecting BGP UPDATE
1299 * Invalid Network Field Error: send NOTIFICATION and close the channel.
1300 *
1301 * @param bgpSession the BGP Session to use
1302 * @param ctx the Channel Handler Context
1303 */
1304 private static void actionsBgpUpdateInvalidNetworkField(
1305 BgpSession bgpSession,
1306 ChannelHandlerContext ctx) {
1307 log.debug("BGP RX UPDATE Error from {}: Invalid Network Field",
1308 bgpSession.getRemoteAddress());
1309
1310 //
1311 // ERROR: Invalid Network Field
1312 //
1313 // Send NOTIFICATION and close the connection
1314 int errorCode = UpdateMessageError.ERROR_CODE;
1315 int errorSubcode = UpdateMessageError.INVALID_NETWORK_FIELD;
1316 ChannelBuffer txMessage =
1317 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1318 null);
1319 ctx.getChannel().write(txMessage);
1320 bgpSession.closeSession(ctx);
1321 }
1322
1323 /**
1324 * Applies the appropriate actions after detecting BGP UPDATE
1325 * Malformed Attribute List Error: send NOTIFICATION and close the channel.
1326 *
1327 * @param bgpSession the BGP Session to use
1328 * @param ctx the Channel Handler Context
1329 */
1330 private static void actionsBgpUpdateMalformedAttributeList(
1331 BgpSession bgpSession,
1332 ChannelHandlerContext ctx) {
1333 log.debug("BGP RX UPDATE Error from {}: Malformed Attribute List",
1334 bgpSession.getRemoteAddress());
1335
1336 //
1337 // ERROR: Malformed Attribute List
1338 //
1339 // Send NOTIFICATION and close the connection
1340 int errorCode = UpdateMessageError.ERROR_CODE;
1341 int errorSubcode = UpdateMessageError.MALFORMED_ATTRIBUTE_LIST;
1342 ChannelBuffer txMessage =
1343 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1344 null);
1345 ctx.getChannel().write(txMessage);
1346 bgpSession.closeSession(ctx);
1347 }
1348
1349 /**
1350 * Applies the appropriate actions after detecting BGP UPDATE
1351 * Missing Well-known Attribute Error: send NOTIFICATION and close the
1352 * channel.
1353 *
1354 * @param bgpSession the BGP Session to use
1355 * @param ctx the Channel Handler Context
1356 * @param missingAttrTypeCode the missing attribute type code
1357 */
1358 private static void actionsBgpUpdateMissingWellKnownAttribute(
1359 BgpSession bgpSession,
1360 ChannelHandlerContext ctx,
1361 int missingAttrTypeCode) {
1362 log.debug("BGP RX UPDATE Error from {}: Missing Well-known Attribute: {}",
1363 bgpSession.getRemoteAddress(), missingAttrTypeCode);
1364
1365 //
1366 // ERROR: Missing Well-known Attribute
1367 //
1368 // Send NOTIFICATION and close the connection
1369 int errorCode = UpdateMessageError.ERROR_CODE;
1370 int errorSubcode = UpdateMessageError.MISSING_WELL_KNOWN_ATTRIBUTE;
1371 ChannelBuffer data = ChannelBuffers.buffer(1);
1372 data.writeByte(missingAttrTypeCode);
1373 ChannelBuffer txMessage =
1374 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1375 data);
1376 ctx.getChannel().write(txMessage);
1377 bgpSession.closeSession(ctx);
1378 }
1379
1380 /**
1381 * Applies the appropriate actions after detecting BGP UPDATE
1382 * Invalid ORIGIN Attribute Error: send NOTIFICATION and close the channel.
1383 *
1384 * @param bgpSession the BGP Session to use
1385 * @param ctx the Channel Handler Context
1386 * @param attrTypeCode the attribute type code
1387 * @param attrLen the attribute length (in octets)
1388 * @param attrFlags the attribute flags
1389 * @param message the message with the data
1390 * @param origin the ORIGIN attribute value
1391 */
1392 private static void actionsBgpUpdateInvalidOriginAttribute(
1393 BgpSession bgpSession,
1394 ChannelHandlerContext ctx,
1395 int attrTypeCode,
1396 int attrLen,
1397 int attrFlags,
1398 ChannelBuffer message,
1399 short origin) {
1400 log.debug("BGP RX UPDATE Error from {}: Invalid ORIGIN Attribute",
1401 bgpSession.getRemoteAddress());
1402
1403 //
1404 // ERROR: Invalid ORIGIN Attribute
1405 //
1406 // Send NOTIFICATION and close the connection
1407 int errorCode = UpdateMessageError.ERROR_CODE;
1408 int errorSubcode = UpdateMessageError.INVALID_ORIGIN_ATTRIBUTE;
1409 ChannelBuffer data =
1410 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1411 attrFlags, message);
1412 ChannelBuffer txMessage =
1413 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1414 data);
1415 ctx.getChannel().write(txMessage);
1416 bgpSession.closeSession(ctx);
1417 }
1418
1419 /**
1420 * Applies the appropriate actions after detecting BGP UPDATE
1421 * Attribute Flags Error: send NOTIFICATION and close the channel.
1422 *
1423 * @param bgpSession the BGP Session to use
1424 * @param ctx the Channel Handler Context
1425 * @param attrTypeCode the attribute type code
1426 * @param attrLen the attribute length (in octets)
1427 * @param attrFlags the attribute flags
1428 * @param message the message with the data
1429 */
1430 private static void actionsBgpUpdateAttributeFlagsError(
1431 BgpSession bgpSession,
1432 ChannelHandlerContext ctx,
1433 int attrTypeCode,
1434 int attrLen,
1435 int attrFlags,
1436 ChannelBuffer message) {
1437 log.debug("BGP RX UPDATE Error from {}: Attribute Flags Error",
1438 bgpSession.getRemoteAddress());
1439
1440 //
1441 // ERROR: Attribute Flags Error
1442 //
1443 // Send NOTIFICATION and close the connection
1444 int errorCode = UpdateMessageError.ERROR_CODE;
1445 int errorSubcode = UpdateMessageError.ATTRIBUTE_FLAGS_ERROR;
1446 ChannelBuffer data =
1447 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1448 attrFlags, message);
1449 ChannelBuffer txMessage =
1450 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1451 data);
1452 ctx.getChannel().write(txMessage);
1453 bgpSession.closeSession(ctx);
1454 }
1455
1456 /**
1457 * Applies the appropriate actions after detecting BGP UPDATE
1458 * Invalid NEXT_HOP Attribute Error: send NOTIFICATION and close the
1459 * channel.
1460 *
1461 * @param bgpSession the BGP Session to use
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 * @param nextHop the NEXT_HOP attribute value
1468 */
1469 private static void actionsBgpUpdateInvalidNextHopAttribute(
1470 BgpSession bgpSession,
1471 ChannelHandlerContext ctx,
1472 int attrTypeCode,
1473 int attrLen,
1474 int attrFlags,
1475 ChannelBuffer message,
1476 Ip4Address nextHop) {
1477 log.debug("BGP RX UPDATE Error from {}: Invalid NEXT_HOP Attribute {}",
1478 bgpSession.getRemoteAddress(), nextHop);
1479
1480 //
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001481 // ERROR: Invalid NEXT_HOP Attribute
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001482 //
1483 // Send NOTIFICATION and close the connection
1484 int errorCode = UpdateMessageError.ERROR_CODE;
1485 int errorSubcode = UpdateMessageError.INVALID_NEXT_HOP_ATTRIBUTE;
1486 ChannelBuffer data =
1487 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1488 attrFlags, message);
1489 ChannelBuffer txMessage =
1490 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1491 data);
1492 ctx.getChannel().write(txMessage);
1493 bgpSession.closeSession(ctx);
1494 }
1495
1496 /**
1497 * Applies the appropriate actions after detecting BGP UPDATE
1498 * Unrecognized Well-known Attribute Error: send NOTIFICATION and close
1499 * the channel.
1500 *
1501 * @param bgpSession the BGP Session to use
1502 * @param ctx the Channel Handler Context
1503 * @param attrTypeCode the attribute type code
1504 * @param attrLen the attribute length (in octets)
1505 * @param attrFlags the attribute flags
1506 * @param message the message with the data
1507 */
1508 private static void actionsBgpUpdateUnrecognizedWellKnownAttribute(
1509 BgpSession bgpSession,
1510 ChannelHandlerContext ctx,
1511 int attrTypeCode,
1512 int attrLen,
1513 int attrFlags,
1514 ChannelBuffer message) {
1515 log.debug("BGP RX UPDATE Error from {}: " +
1516 "Unrecognized Well-known Attribute Error: {}",
1517 bgpSession.getRemoteAddress(), attrTypeCode);
1518
1519 //
1520 // ERROR: Unrecognized Well-known Attribute
1521 //
1522 // Send NOTIFICATION and close the connection
1523 int errorCode = UpdateMessageError.ERROR_CODE;
1524 int errorSubcode =
1525 UpdateMessageError.UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE;
1526 ChannelBuffer data =
1527 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1528 attrFlags, message);
1529 ChannelBuffer txMessage =
1530 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1531 data);
1532 ctx.getChannel().write(txMessage);
1533 bgpSession.closeSession(ctx);
1534 }
1535
1536 /**
1537 * Applies the appropriate actions after detecting BGP UPDATE
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001538 * Optional Attribute Error: send NOTIFICATION and close
1539 * the channel.
1540 *
1541 * @param bgpSession the BGP Session to use
1542 * @param ctx the Channel Handler Context
1543 * @param attrTypeCode the attribute type code
1544 * @param attrLen the attribute length (in octets)
1545 * @param attrFlags the attribute flags
1546 * @param message the message with the data
1547 */
1548 private static void actionsBgpUpdateOptionalAttributeError(
1549 BgpSession bgpSession,
1550 ChannelHandlerContext ctx,
1551 int attrTypeCode,
1552 int attrLen,
1553 int attrFlags,
1554 ChannelBuffer message) {
1555 log.debug("BGP RX UPDATE Error from {}: Optional Attribute Error: {}",
1556 bgpSession.getRemoteAddress(), attrTypeCode);
1557
1558 //
1559 // ERROR: Optional Attribute Error
1560 //
1561 // Send NOTIFICATION and close the connection
1562 int errorCode = UpdateMessageError.ERROR_CODE;
1563 int errorSubcode =
1564 UpdateMessageError.OPTIONAL_ATTRIBUTE_ERROR;
1565 ChannelBuffer data =
1566 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1567 attrFlags, message);
1568 ChannelBuffer txMessage =
1569 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1570 data);
1571 ctx.getChannel().write(txMessage);
1572 bgpSession.closeSession(ctx);
1573 }
1574
1575 /**
1576 * Applies the appropriate actions after detecting BGP UPDATE
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001577 * Attribute Length Error: send NOTIFICATION and close the channel.
1578 *
1579 * @param bgpSession the BGP Session to use
1580 * @param ctx the Channel Handler Context
1581 * @param attrTypeCode the attribute type code
1582 * @param attrLen the attribute length (in octets)
1583 * @param attrFlags the attribute flags
1584 * @param message the message with the data
1585 */
1586 private static void actionsBgpUpdateAttributeLengthError(
1587 BgpSession bgpSession,
1588 ChannelHandlerContext ctx,
1589 int attrTypeCode,
1590 int attrLen,
1591 int attrFlags,
1592 ChannelBuffer message) {
1593 log.debug("BGP RX UPDATE Error from {}: Attribute Length Error",
1594 bgpSession.getRemoteAddress());
1595
1596 //
1597 // ERROR: Attribute Length Error
1598 //
1599 // Send NOTIFICATION and close the connection
1600 int errorCode = UpdateMessageError.ERROR_CODE;
1601 int errorSubcode = UpdateMessageError.ATTRIBUTE_LENGTH_ERROR;
1602 ChannelBuffer data =
1603 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1604 attrFlags, message);
1605 ChannelBuffer txMessage =
1606 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1607 data);
1608 ctx.getChannel().write(txMessage);
1609 bgpSession.closeSession(ctx);
1610 }
1611
1612 /**
1613 * Applies the appropriate actions after detecting BGP UPDATE
1614 * Malformed AS_PATH Error: send NOTIFICATION and close the channel.
1615 *
1616 * @param bgpSession the BGP Session to use
1617 * @param ctx the Channel Handler Context
1618 */
1619 private static void actionsBgpUpdateMalformedAsPath(
1620 BgpSession bgpSession,
1621 ChannelHandlerContext ctx) {
1622 log.debug("BGP RX UPDATE Error from {}: Malformed AS Path",
1623 bgpSession.getRemoteAddress());
1624
1625 //
1626 // ERROR: Malformed AS_PATH
1627 //
1628 // Send NOTIFICATION and close the connection
1629 int errorCode = UpdateMessageError.ERROR_CODE;
1630 int errorSubcode = UpdateMessageError.MALFORMED_AS_PATH;
1631 ChannelBuffer txMessage =
1632 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1633 null);
1634 ctx.getChannel().write(txMessage);
1635 bgpSession.closeSession(ctx);
1636 }
1637
1638 /**
1639 * Prepares BGP UPDATE Notification data payload.
1640 *
1641 * @param attrTypeCode the attribute type code
1642 * @param attrLen the attribute length (in octets)
1643 * @param attrFlags the attribute flags
1644 * @param message the message with the data
1645 * @return the buffer with the data payload for the BGP UPDATE Notification
1646 */
1647 private static ChannelBuffer prepareBgpUpdateNotificationDataPayload(
1648 int attrTypeCode,
1649 int attrLen,
1650 int attrFlags,
1651 ChannelBuffer message) {
1652 // Compute the attribute length field octets
1653 boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
1654 int attrLenOctets = 1;
1655 if (extendedLengthBit) {
1656 attrLenOctets = 2;
1657 }
1658 ChannelBuffer data =
1659 ChannelBuffers.buffer(attrLen + attrLenOctets + 1);
1660 data.writeByte(attrTypeCode);
1661 if (extendedLengthBit) {
1662 data.writeShort(attrLen);
1663 } else {
1664 data.writeByte(attrLen);
1665 }
1666 data.writeBytes(message, attrLen);
1667 return data;
1668 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001669
1670 /**
1671 * Helper class for storing Multiprotocol Network Layer Reachability
1672 * information.
1673 */
1674 private static final class MpNlri {
1675 private final int afi;
1676 private final int safi;
1677 private Ip4Address nextHop4;
1678 private Ip6Address nextHop6;
1679 private Collection<Ip4Prefix> nlri4 = new ArrayList<>();
1680 private Collection<Ip6Prefix> nlri6 = new ArrayList<>();
1681
1682 /**
1683 * Constructor.
1684 *
1685 * @param afi the Address Family Identifier
1686 * @param safi the Subsequent Address Family Identifier
1687 */
1688 private MpNlri(int afi, int safi) {
1689 this.afi = afi;
1690 this.safi = safi;
1691 }
1692 }
1693
1694 /**
1695 * Helper class for storing decoded BGP routing information.
1696 */
1697 private static final class DecodedBgpRoutes {
1698 private final Map<Ip4Prefix, BgpRouteEntry> addedUnicastRoutes4 =
1699 new HashMap<>();
1700 private final Map<Ip6Prefix, BgpRouteEntry> addedUnicastRoutes6 =
1701 new HashMap<>();
1702 private final Map<Ip4Prefix, BgpRouteEntry> deletedUnicastRoutes4 =
1703 new HashMap<>();
1704 private final Map<Ip6Prefix, BgpRouteEntry> deletedUnicastRoutes6 =
1705 new HashMap<>();
1706 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001707}