blob: b30fb8d5d1a877f52f0c5825dbe3e468730e3a44 [file] [log] [blame]
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08003 *
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 */
Jonathan Hart41349e92015-02-09 14:14:02 -080016package org.onosproject.routing.bgp;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080017
18import org.apache.commons.lang3.tuple.Pair;
19import org.jboss.netty.buffer.ChannelBuffer;
20import org.jboss.netty.buffer.ChannelBuffers;
21import org.jboss.netty.channel.ChannelHandlerContext;
22import org.onlab.packet.Ip4Address;
23import org.onlab.packet.Ip4Prefix;
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080024import org.onlab.packet.Ip6Address;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -080025import org.onlab.packet.Ip6Prefix;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080026import org.slf4j.Logger;
27import org.slf4j.LoggerFactory;
28
Jonathan Hart41349e92015-02-09 14:14:02 -080029import java.util.ArrayList;
30import java.util.Collection;
31import java.util.HashMap;
32import java.util.Map;
33
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080034/**
35 * A class for handling BGP UPDATE messages.
36 */
37final class BgpUpdate {
38 private static final Logger log = LoggerFactory.getLogger(BgpUpdate.class);
39
40 /**
41 * Default constructor.
42 * <p>
43 * The constructor is private to prevent creating an instance of
44 * this utility class.
45 */
46 private BgpUpdate() {
47 }
48
49 /**
50 * Processes BGP UPDATE message.
51 *
52 * @param bgpSession the BGP Session to use
53 * @param ctx the Channel Handler Context
54 * @param message the message to process
55 */
56 static void processBgpUpdate(BgpSession bgpSession,
57 ChannelHandlerContext ctx,
58 ChannelBuffer message) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -080059 DecodedBgpRoutes decodedBgpRoutes = new DecodedBgpRoutes();
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080060
61 int minLength =
62 BgpConstants.BGP_UPDATE_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
63 if (message.readableBytes() < minLength) {
64 log.debug("BGP RX UPDATE Error from {}: " +
65 "Message length {} too short. Must be at least {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -080066 bgpSession.remoteInfo().address(),
67 message.readableBytes(), minLength);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080068 //
69 // ERROR: Bad Message Length
70 //
71 // Send NOTIFICATION and close the connection
72 ChannelBuffer txMessage =
73 BgpNotification.prepareBgpNotificationBadMessageLength(
74 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
75 ctx.getChannel().write(txMessage);
76 bgpSession.closeSession(ctx);
77 return;
78 }
79
80 log.debug("BGP RX UPDATE message from {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -080081 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080082
83 //
84 // Parse the UPDATE message
85 //
86
87 //
88 // Parse the Withdrawn Routes
89 //
90 int withdrawnRoutesLength = message.readUnsignedShort();
91 if (withdrawnRoutesLength > message.readableBytes()) {
92 // ERROR: Malformed Attribute List
93 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
94 return;
95 }
96 Collection<Ip4Prefix> withdrawnPrefixes = null;
97 try {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -080098 withdrawnPrefixes = parsePackedIp4Prefixes(withdrawnRoutesLength,
99 message);
Jonathan Hart41349e92015-02-09 14:14:02 -0800100 } catch (BgpMessage.BgpParseException e) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800101 // ERROR: Invalid Network Field
102 log.debug("Exception parsing Withdrawn Prefixes from BGP peer {}: ",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800103 bgpSession.remoteInfo().bgpId(), e);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800104 actionsBgpUpdateInvalidNetworkField(bgpSession, ctx);
105 return;
106 }
107 for (Ip4Prefix prefix : withdrawnPrefixes) {
108 log.debug("BGP RX UPDATE message WITHDRAWN from {}: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800109 bgpSession.remoteInfo().address(), prefix);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800110 BgpRouteEntry bgpRouteEntry = bgpSession.findBgpRoute(prefix);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800111 if (bgpRouteEntry != null) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800112 decodedBgpRoutes.deletedUnicastRoutes4.put(prefix,
113 bgpRouteEntry);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800114 }
115 }
116
117 //
118 // Parse the Path Attributes
119 //
120 try {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800121 parsePathAttributes(bgpSession, ctx, message, decodedBgpRoutes);
Jonathan Hart41349e92015-02-09 14:14:02 -0800122 } catch (BgpMessage.BgpParseException e) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800123 log.debug("Exception parsing Path Attributes from BGP peer {}: ",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800124 bgpSession.remoteInfo().bgpId(), e);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800125 // NOTE: The session was already closed, so nothing else to do
126 return;
127 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800128
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800129 //
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800130 // Update the BGP RIB-IN
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800131 //
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800132 for (Ip4Prefix ip4Prefix :
133 decodedBgpRoutes.deletedUnicastRoutes4.keySet()) {
134 bgpSession.removeBgpRoute(ip4Prefix);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800135 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800136 //
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800137 for (BgpRouteEntry bgpRouteEntry :
138 decodedBgpRoutes.addedUnicastRoutes4.values()) {
139 bgpSession.addBgpRoute(bgpRouteEntry);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800140 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800141 //
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800142 for (Ip6Prefix ip6Prefix :
143 decodedBgpRoutes.deletedUnicastRoutes6.keySet()) {
144 bgpSession.removeBgpRoute(ip6Prefix);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800145 }
146 //
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800147 for (BgpRouteEntry bgpRouteEntry :
148 decodedBgpRoutes.addedUnicastRoutes6.values()) {
149 bgpSession.addBgpRoute(bgpRouteEntry);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800150 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800151
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800152 //
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800153 // Push the updates to the BGP Merged RIB
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800154 //
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800155 BgpRouteSelector bgpRouteSelector =
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800156 bgpSession.getBgpSessionManager().getBgpRouteSelector();
Jonathan Hart1ad75f22016-04-13 21:24:13 -0700157 bgpRouteSelector.routeUpdates(
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800158 decodedBgpRoutes.addedUnicastRoutes4.values(),
159 decodedBgpRoutes.deletedUnicastRoutes4.values());
Jonathan Hart1ad75f22016-04-13 21:24:13 -0700160 bgpRouteSelector.routeUpdates(
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800161 decodedBgpRoutes.addedUnicastRoutes6.values(),
162 decodedBgpRoutes.deletedUnicastRoutes6.values());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800163
164 // Start the Session Timeout timer
165 bgpSession.restartSessionTimeoutTimer(ctx);
166 }
167
168 /**
169 * Parse BGP Path Attributes from the BGP UPDATE message.
170 *
171 * @param bgpSession the BGP Session to use
172 * @param ctx the Channel Handler Context
173 * @param message the message to parse
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800174 * @param decodedBgpRoutes the container to store the decoded BGP Route
175 * Entries. It might already contain some route entries such as withdrawn
176 * IPv4 prefixes
Jonathan Hart41349e92015-02-09 14:14:02 -0800177 * @throws BgpMessage.BgpParseException
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800178 */
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800179 // CHECKSTYLE IGNORE MethodLength FOR NEXT 300 LINES
180 private static void parsePathAttributes(
181 BgpSession bgpSession,
182 ChannelHandlerContext ctx,
183 ChannelBuffer message,
184 DecodedBgpRoutes decodedBgpRoutes)
Jonathan Hart41349e92015-02-09 14:14:02 -0800185 throws BgpMessage.BgpParseException {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800186
187 //
188 // Parsed values
189 //
190 Short origin = -1; // Mandatory
191 BgpRouteEntry.AsPath asPath = null; // Mandatory
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800192 // Legacy NLRI (RFC 4271). Mandatory NEXT_HOP if legacy NLRI is used
Jonathan Hart41349e92015-02-09 14:14:02 -0800193 MpNlri legacyNlri = new MpNlri(
194 BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4,
195 BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_UNICAST);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800196 long multiExitDisc = // Optional
Jonathan Hart41349e92015-02-09 14:14:02 -0800197 BgpConstants.Update.MultiExitDisc.LOWEST_MULTI_EXIT_DISC;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800198 Long localPref = null; // Mandatory
199 Long aggregatorAsNumber = null; // Optional: unused
200 Ip4Address aggregatorIpAddress = null; // Optional: unused
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800201 Collection<MpNlri> mpNlriReachList = new ArrayList<>(); // Optional
202 Collection<MpNlri> mpNlriUnreachList = new ArrayList<>(); // Optional
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800203
204 //
205 // Get and verify the Path Attributes Length
206 //
207 int pathAttributeLength = message.readUnsignedShort();
208 if (pathAttributeLength > message.readableBytes()) {
209 // ERROR: Malformed Attribute List
210 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
211 String errorMsg = "Malformed Attribute List";
Jonathan Hart41349e92015-02-09 14:14:02 -0800212 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800213 }
214 if (pathAttributeLength == 0) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800215 return;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800216 }
217
218 //
219 // Parse the Path Attributes
220 //
221 int pathAttributeEnd = message.readerIndex() + pathAttributeLength;
222 while (message.readerIndex() < pathAttributeEnd) {
223 int attrFlags = message.readUnsignedByte();
224 if (message.readerIndex() >= pathAttributeEnd) {
225 // ERROR: Malformed Attribute List
226 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
227 String errorMsg = "Malformed Attribute List";
Jonathan Hart41349e92015-02-09 14:14:02 -0800228 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800229 }
230 int attrTypeCode = message.readUnsignedByte();
231
232 // The Attribute Flags
233 boolean optionalBit = ((0x80 & attrFlags) != 0);
234 boolean transitiveBit = ((0x40 & attrFlags) != 0);
235 boolean partialBit = ((0x20 & attrFlags) != 0);
236 boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
237
238 // The Attribute Length
239 int attrLen = 0;
240 int attrLenOctets = 1;
241 if (extendedLengthBit) {
242 attrLenOctets = 2;
243 }
244 if (message.readerIndex() + attrLenOctets > pathAttributeEnd) {
245 // ERROR: Malformed Attribute List
246 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
247 String errorMsg = "Malformed Attribute List";
Jonathan Hart41349e92015-02-09 14:14:02 -0800248 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800249 }
250 if (extendedLengthBit) {
251 attrLen = message.readUnsignedShort();
252 } else {
253 attrLen = message.readUnsignedByte();
254 }
255 if (message.readerIndex() + attrLen > pathAttributeEnd) {
256 // ERROR: Malformed Attribute List
257 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
258 String errorMsg = "Malformed Attribute List";
Jonathan Hart41349e92015-02-09 14:14:02 -0800259 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800260 }
261
262 // Verify the Attribute Flags
263 verifyBgpUpdateAttributeFlags(bgpSession, ctx, attrTypeCode,
264 attrLen, attrFlags, message);
265
266 //
267 // Extract the Attribute Value based on the Attribute Type Code
268 //
269 switch (attrTypeCode) {
270
Jonathan Hart41349e92015-02-09 14:14:02 -0800271 case BgpConstants.Update.Origin.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800272 // Attribute Type Code ORIGIN
273 origin = parseAttributeTypeOrigin(bgpSession, ctx,
274 attrTypeCode, attrLen,
275 attrFlags, message);
276 break;
277
Jonathan Hart41349e92015-02-09 14:14:02 -0800278 case BgpConstants.Update.AsPath.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800279 // Attribute Type Code AS_PATH
280 asPath = parseAttributeTypeAsPath(bgpSession, ctx,
281 attrTypeCode, attrLen,
282 attrFlags, message);
283 break;
284
Jonathan Hart41349e92015-02-09 14:14:02 -0800285 case BgpConstants.Update.NextHop.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800286 // Attribute Type Code NEXT_HOP
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800287 legacyNlri.nextHop4 =
288 parseAttributeTypeNextHop(bgpSession, ctx,
289 attrTypeCode, attrLen,
290 attrFlags, message);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800291 break;
292
Jonathan Hart41349e92015-02-09 14:14:02 -0800293 case BgpConstants.Update.MultiExitDisc.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800294 // Attribute Type Code MULTI_EXIT_DISC
295 multiExitDisc =
296 parseAttributeTypeMultiExitDisc(bgpSession, ctx,
297 attrTypeCode, attrLen,
298 attrFlags, message);
299 break;
300
Jonathan Hart41349e92015-02-09 14:14:02 -0800301 case BgpConstants.Update.LocalPref.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800302 // Attribute Type Code LOCAL_PREF
303 localPref =
304 parseAttributeTypeLocalPref(bgpSession, ctx,
305 attrTypeCode, attrLen,
306 attrFlags, message);
307 break;
308
Jonathan Hart41349e92015-02-09 14:14:02 -0800309 case BgpConstants.Update.AtomicAggregate.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800310 // Attribute Type Code ATOMIC_AGGREGATE
311 parseAttributeTypeAtomicAggregate(bgpSession, ctx,
312 attrTypeCode, attrLen,
313 attrFlags, message);
314 // Nothing to do: this attribute is primarily informational
315 break;
316
Jonathan Hart41349e92015-02-09 14:14:02 -0800317 case BgpConstants.Update.Aggregator.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800318 // Attribute Type Code AGGREGATOR
319 Pair<Long, Ip4Address> aggregator =
320 parseAttributeTypeAggregator(bgpSession, ctx,
321 attrTypeCode, attrLen,
322 attrFlags, message);
323 aggregatorAsNumber = aggregator.getLeft();
324 aggregatorIpAddress = aggregator.getRight();
325 break;
326
Jonathan Hart41349e92015-02-09 14:14:02 -0800327 case BgpConstants.Update.MpReachNlri.TYPE:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800328 // Attribute Type Code MP_REACH_NLRI
329 MpNlri mpNlriReach =
330 parseAttributeTypeMpReachNlri(bgpSession, ctx,
331 attrTypeCode,
332 attrLen,
333 attrFlags, message);
334 if (mpNlriReach != null) {
335 mpNlriReachList.add(mpNlriReach);
336 }
337 break;
338
Jonathan Hart41349e92015-02-09 14:14:02 -0800339 case BgpConstants.Update.MpUnreachNlri.TYPE:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800340 // Attribute Type Code MP_UNREACH_NLRI
341 MpNlri mpNlriUnreach =
342 parseAttributeTypeMpUnreachNlri(bgpSession, ctx,
343 attrTypeCode, attrLen,
344 attrFlags, message);
345 if (mpNlriUnreach != null) {
346 mpNlriUnreachList.add(mpNlriUnreach);
347 }
348 break;
349
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800350 default:
351 // NOTE: Parse any new Attribute Types if needed
352 if (!optionalBit) {
353 // ERROR: Unrecognized Well-known Attribute
354 actionsBgpUpdateUnrecognizedWellKnownAttribute(
355 bgpSession, ctx, attrTypeCode, attrLen, attrFlags,
356 message);
357 String errorMsg = "Unrecognized Well-known Attribute: " +
358 attrTypeCode;
Jonathan Hart41349e92015-02-09 14:14:02 -0800359 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800360 }
361
362 // Skip the data from the unrecognized attribute
363 log.debug("BGP RX UPDATE message from {}: " +
364 "Unrecognized Attribute Type {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800365 bgpSession.remoteInfo().address(), attrTypeCode);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800366 message.skipBytes(attrLen);
367 break;
368 }
369 }
370
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800371 //
372 // Parse the NLRI (Network Layer Reachability Information)
373 //
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800374 int nlriLength = message.readableBytes();
375 try {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800376 Collection<Ip4Prefix> addedPrefixes4 =
377 parsePackedIp4Prefixes(nlriLength, message);
378 // Store it inside the legacy NLRI wrapper
379 legacyNlri.nlri4 = addedPrefixes4;
Jonathan Hart41349e92015-02-09 14:14:02 -0800380 } catch (BgpMessage.BgpParseException e) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800381 // ERROR: Invalid Network Field
382 log.debug("Exception parsing NLRI from BGP peer {}: ",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800383 bgpSession.remoteInfo().bgpId(), e);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800384 actionsBgpUpdateInvalidNetworkField(bgpSession, ctx);
385 // Rethrow the exception
386 throw e;
387 }
388
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800389 // Verify the Well-known Attributes
390 verifyBgpUpdateWellKnownAttributes(bgpSession, ctx, origin, asPath,
391 localPref, legacyNlri,
392 mpNlriReachList);
393
394 //
395 // Generate the deleted routes
396 //
397 for (MpNlri mpNlri : mpNlriUnreachList) {
398 BgpRouteEntry bgpRouteEntry;
399
400 // The deleted IPv4 routes
401 for (Ip4Prefix prefix : mpNlri.nlri4) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800402 bgpRouteEntry = bgpSession.findBgpRoute(prefix);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800403 if (bgpRouteEntry != null) {
404 decodedBgpRoutes.deletedUnicastRoutes4.put(prefix,
405 bgpRouteEntry);
406 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800407 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800408
409 // The deleted IPv6 routes
410 for (Ip6Prefix prefix : mpNlri.nlri6) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800411 bgpRouteEntry = bgpSession.findBgpRoute(prefix);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800412 if (bgpRouteEntry != null) {
413 decodedBgpRoutes.deletedUnicastRoutes6.put(prefix,
414 bgpRouteEntry);
415 }
416 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800417 }
418
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800419 //
420 // Generate the added routes
421 //
422 mpNlriReachList.add(legacyNlri);
423 for (MpNlri mpNlri : mpNlriReachList) {
424 BgpRouteEntry bgpRouteEntry;
425
426 // The added IPv4 routes
427 for (Ip4Prefix prefix : mpNlri.nlri4) {
428 bgpRouteEntry =
429 new BgpRouteEntry(bgpSession, prefix, mpNlri.nextHop4,
430 origin.byteValue(), asPath, localPref);
431 bgpRouteEntry.setMultiExitDisc(multiExitDisc);
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800432 if (bgpRouteEntry.hasAsPathLoop(bgpSession.localInfo().asNumber())) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800433 log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
434 "nextHop {}: contains AS Path loop",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800435 bgpSession.remoteInfo().address(), prefix,
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800436 mpNlri.nextHop4);
437 continue;
438 } else {
439 log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800440 bgpSession.remoteInfo().address(), prefix,
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800441 mpNlri.nextHop4);
442 }
443 // Remove from the collection of deleted routes
444 decodedBgpRoutes.deletedUnicastRoutes4.remove(prefix);
445 decodedBgpRoutes.addedUnicastRoutes4.put(prefix,
446 bgpRouteEntry);
447 }
448
449 // The added IPv6 routes
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800450 for (Ip6Prefix prefix : mpNlri.nlri6) {
451 bgpRouteEntry =
452 new BgpRouteEntry(bgpSession, prefix, mpNlri.nextHop6,
453 origin.byteValue(), asPath, localPref);
454 bgpRouteEntry.setMultiExitDisc(multiExitDisc);
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800455 if (bgpRouteEntry.hasAsPathLoop(bgpSession.localInfo().asNumber())) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800456 log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
457 "nextHop {}: contains AS Path loop",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800458 bgpSession.remoteInfo().address(), prefix,
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800459 mpNlri.nextHop6);
460 continue;
461 } else {
462 log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800463 bgpSession.remoteInfo().address(), prefix,
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800464 mpNlri.nextHop6);
465 }
466 // Remove from the collection of deleted routes
467 decodedBgpRoutes.deletedUnicastRoutes6.remove(prefix);
468 decodedBgpRoutes.addedUnicastRoutes6.put(prefix,
469 bgpRouteEntry);
470 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800471 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800472 }
473
474 /**
475 * Verifies BGP UPDATE Well-known Attributes.
476 *
477 * @param bgpSession the BGP Session to use
478 * @param ctx the Channel Handler Context
479 * @param origin the ORIGIN well-known mandatory attribute
480 * @param asPath the AS_PATH well-known mandatory attribute
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800481 * @param localPref the LOCAL_PREF required attribute
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800482 * @param legacyNlri the legacy NLRI. Encapsulates the NEXT_HOP well-known
483 * mandatory attribute (mandatory if legacy NLRI is used).
484 * @param mpNlriReachList the Multiprotocol NLRI attributes
Jonathan Hart41349e92015-02-09 14:14:02 -0800485 * @throws BgpMessage.BgpParseException
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800486 */
487 private static void verifyBgpUpdateWellKnownAttributes(
488 BgpSession bgpSession,
489 ChannelHandlerContext ctx,
490 Short origin,
491 BgpRouteEntry.AsPath asPath,
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800492 Long localPref,
493 MpNlri legacyNlri,
494 Collection<MpNlri> mpNlriReachList)
Jonathan Hart41349e92015-02-09 14:14:02 -0800495 throws BgpMessage.BgpParseException {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800496 boolean hasNlri = false;
497 boolean hasLegacyNlri = false;
498
499 //
500 // Convenience flags that are used to check for missing attributes.
501 //
502 // NOTE: The hasLegacyNlri flag is always set to true if the
503 // Multiprotocol Extensions are not enabled, even if the UPDATE
504 // message doesn't contain the legacy NLRI (per RFC 4271).
505 //
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800506 if (!bgpSession.mpExtensions()) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800507 hasNlri = true;
508 hasLegacyNlri = true;
509 } else {
510 if (!legacyNlri.nlri4.isEmpty()) {
511 hasNlri = true;
512 hasLegacyNlri = true;
513 }
514 if (!mpNlriReachList.isEmpty()) {
515 hasNlri = true;
516 }
517 }
518
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800519 //
520 // Check for Missing Well-known Attributes
521 //
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800522 if (hasNlri && ((origin == null) || (origin == -1))) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800523 // Missing Attribute Type Code ORIGIN
Jonathan Hart41349e92015-02-09 14:14:02 -0800524 int type = BgpConstants.Update.Origin.TYPE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800525 actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
526 String errorMsg = "Missing Well-known Attribute: ORIGIN";
Jonathan Hart41349e92015-02-09 14:14:02 -0800527 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800528 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800529 if (hasNlri && (asPath == null)) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800530 // Missing Attribute Type Code AS_PATH
Jonathan Hart41349e92015-02-09 14:14:02 -0800531 int type = BgpConstants.Update.AsPath.TYPE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800532 actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
533 String errorMsg = "Missing Well-known Attribute: AS_PATH";
Jonathan Hart41349e92015-02-09 14:14:02 -0800534 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800535 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800536 if (hasNlri && (localPref == null)) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800537 // Missing Attribute Type Code LOCAL_PREF
538 // NOTE: Required for iBGP
Jonathan Hart41349e92015-02-09 14:14:02 -0800539 int type = BgpConstants.Update.LocalPref.TYPE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800540 actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
541 String errorMsg = "Missing Well-known Attribute: LOCAL_PREF";
Jonathan Hart41349e92015-02-09 14:14:02 -0800542 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800543 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800544 if (hasLegacyNlri && (legacyNlri.nextHop4 == null)) {
545 // Missing Attribute Type Code NEXT_HOP
Jonathan Hart41349e92015-02-09 14:14:02 -0800546 int type = BgpConstants.Update.NextHop.TYPE;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800547 actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
548 String errorMsg = "Missing Well-known Attribute: NEXT_HOP";
Jonathan Hart41349e92015-02-09 14:14:02 -0800549 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800550 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800551 }
552
553 /**
554 * Verifies the BGP UPDATE Attribute Flags.
555 *
556 * @param bgpSession the BGP Session to use
557 * @param ctx the Channel Handler Context
558 * @param attrTypeCode the attribute type code
559 * @param attrLen the attribute length (in octets)
560 * @param attrFlags the attribute flags
561 * @param message the message to parse
Jonathan Hart41349e92015-02-09 14:14:02 -0800562 * @throws BgpMessage.BgpParseException
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800563 */
564 private static void verifyBgpUpdateAttributeFlags(
565 BgpSession bgpSession,
566 ChannelHandlerContext ctx,
567 int attrTypeCode,
568 int attrLen,
569 int attrFlags,
570 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -0800571 throws BgpMessage.BgpParseException {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800572
573 //
574 // Assign the Attribute Type Name and the Well-known flag
575 //
576 String typeName = "UNKNOWN";
577 boolean isWellKnown = false;
578 switch (attrTypeCode) {
Jonathan Hart41349e92015-02-09 14:14:02 -0800579 case BgpConstants.Update.Origin.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800580 isWellKnown = true;
581 typeName = "ORIGIN";
582 break;
Jonathan Hart41349e92015-02-09 14:14:02 -0800583 case BgpConstants.Update.AsPath.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800584 isWellKnown = true;
585 typeName = "AS_PATH";
586 break;
Jonathan Hart41349e92015-02-09 14:14:02 -0800587 case BgpConstants.Update.NextHop.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800588 isWellKnown = true;
589 typeName = "NEXT_HOP";
590 break;
Jonathan Hart41349e92015-02-09 14:14:02 -0800591 case BgpConstants.Update.MultiExitDisc.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800592 isWellKnown = false;
593 typeName = "MULTI_EXIT_DISC";
594 break;
Jonathan Hart41349e92015-02-09 14:14:02 -0800595 case BgpConstants.Update.LocalPref.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800596 isWellKnown = true;
597 typeName = "LOCAL_PREF";
598 break;
Jonathan Hart41349e92015-02-09 14:14:02 -0800599 case BgpConstants.Update.AtomicAggregate.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800600 isWellKnown = true;
601 typeName = "ATOMIC_AGGREGATE";
602 break;
Jonathan Hart41349e92015-02-09 14:14:02 -0800603 case BgpConstants.Update.Aggregator.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800604 isWellKnown = false;
605 typeName = "AGGREGATOR";
606 break;
Jonathan Hart41349e92015-02-09 14:14:02 -0800607 case BgpConstants.Update.MpReachNlri.TYPE:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800608 isWellKnown = false;
609 typeName = "MP_REACH_NLRI";
610 break;
Jonathan Hart41349e92015-02-09 14:14:02 -0800611 case BgpConstants.Update.MpUnreachNlri.TYPE:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800612 isWellKnown = false;
613 typeName = "MP_UNREACH_NLRI";
614 break;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800615 default:
616 isWellKnown = false;
617 typeName = "UNKNOWN(" + attrTypeCode + ")";
618 break;
619 }
620
621 //
622 // Verify the Attribute Flags
623 //
624 boolean optionalBit = ((0x80 & attrFlags) != 0);
625 boolean transitiveBit = ((0x40 & attrFlags) != 0);
626 boolean partialBit = ((0x20 & attrFlags) != 0);
627 if ((isWellKnown && optionalBit) ||
628 (isWellKnown && (!transitiveBit)) ||
629 (isWellKnown && partialBit) ||
630 (optionalBit && (!transitiveBit) && partialBit)) {
631 //
632 // ERROR: The Optional bit cannot be set for Well-known attributes
633 // ERROR: The Transtive bit MUST be 1 for well-known attributes
634 // ERROR: The Partial bit MUST be 0 for well-known attributes
635 // ERROR: The Partial bit MUST be 0 for optional non-transitive
636 // attributes
637 //
638 actionsBgpUpdateAttributeFlagsError(
639 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
640 String errorMsg = "Attribute Flags Error for " + typeName + ": " +
641 attrFlags;
Jonathan Hart41349e92015-02-09 14:14:02 -0800642 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800643 }
644 }
645
646 /**
647 * Parses BGP UPDATE Attribute Type ORIGIN.
648 *
649 * @param bgpSession the BGP Session to use
650 * @param ctx the Channel Handler Context
651 * @param attrTypeCode the attribute type code
652 * @param attrLen the attribute length (in octets)
653 * @param attrFlags the attribute flags
654 * @param message the message to parse
655 * @return the parsed ORIGIN value
Jonathan Hart41349e92015-02-09 14:14:02 -0800656 * @throws BgpMessage.BgpParseException
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800657 */
658 private static short parseAttributeTypeOrigin(
659 BgpSession bgpSession,
660 ChannelHandlerContext ctx,
661 int attrTypeCode,
662 int attrLen,
663 int attrFlags,
664 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -0800665 throws BgpMessage.BgpParseException {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800666
667 // Check the Attribute Length
Jonathan Hart41349e92015-02-09 14:14:02 -0800668 if (attrLen != BgpConstants.Update.Origin.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800669 // ERROR: Attribute Length Error
670 actionsBgpUpdateAttributeLengthError(
671 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
672 String errorMsg = "Attribute Length Error";
Jonathan Hart41349e92015-02-09 14:14:02 -0800673 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800674 }
675
676 message.markReaderIndex();
677 short origin = message.readUnsignedByte();
678 switch (origin) {
Jonathan Hart41349e92015-02-09 14:14:02 -0800679 case BgpConstants.Update.Origin.IGP:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800680 // FALLTHROUGH
Jonathan Hart41349e92015-02-09 14:14:02 -0800681 case BgpConstants.Update.Origin.EGP:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800682 // FALLTHROUGH
Jonathan Hart41349e92015-02-09 14:14:02 -0800683 case BgpConstants.Update.Origin.INCOMPLETE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800684 break;
685 default:
686 // ERROR: Invalid ORIGIN Attribute
687 message.resetReaderIndex();
688 actionsBgpUpdateInvalidOriginAttribute(
689 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message,
690 origin);
691 String errorMsg = "Invalid ORIGIN Attribute: " + origin;
Jonathan Hart41349e92015-02-09 14:14:02 -0800692 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800693 }
694
695 return origin;
696 }
697
698 /**
699 * Parses BGP UPDATE Attribute AS Path.
700 *
701 * @param bgpSession the BGP Session to use
702 * @param ctx the Channel Handler Context
703 * @param attrTypeCode the attribute type code
704 * @param attrLen the attribute length (in octets)
705 * @param attrFlags the attribute flags
706 * @param message the message to parse
707 * @return the parsed AS Path
Jonathan Hart41349e92015-02-09 14:14:02 -0800708 * @throws BgpMessage.BgpParseException
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800709 */
710 private static BgpRouteEntry.AsPath parseAttributeTypeAsPath(
711 BgpSession bgpSession,
712 ChannelHandlerContext ctx,
713 int attrTypeCode,
714 int attrLen,
715 int attrFlags,
716 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -0800717 throws BgpMessage.BgpParseException {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800718 ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
719
720 //
721 // Parse the message
722 //
723 while (attrLen > 0) {
724 if (attrLen < 2) {
725 // ERROR: Malformed AS_PATH
726 actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
727 String errorMsg = "Malformed AS Path";
Jonathan Hart41349e92015-02-09 14:14:02 -0800728 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800729 }
730 // Get the Path Segment Type and Length (in number of ASes)
731 short pathSegmentType = message.readUnsignedByte();
732 short pathSegmentLength = message.readUnsignedByte();
733 attrLen -= 2;
734
735 // Verify the Path Segment Type
736 switch (pathSegmentType) {
Jonathan Hart41349e92015-02-09 14:14:02 -0800737 case BgpConstants.Update.AsPath.AS_SET:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800738 // FALLTHROUGH
Jonathan Hart41349e92015-02-09 14:14:02 -0800739 case BgpConstants.Update.AsPath.AS_SEQUENCE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800740 // FALLTHROUGH
Jonathan Hart41349e92015-02-09 14:14:02 -0800741 case BgpConstants.Update.AsPath.AS_CONFED_SEQUENCE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800742 // FALLTHROUGH
Jonathan Hart41349e92015-02-09 14:14:02 -0800743 case BgpConstants.Update.AsPath.AS_CONFED_SET:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800744 break;
745 default:
746 // ERROR: Invalid Path Segment Type
747 //
748 // NOTE: The BGP Spec (RFC 4271) doesn't contain Error Subcode
749 // for "Invalid Path Segment Type", hence we return
750 // the error as "Malformed AS_PATH".
751 //
752 actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
753 String errorMsg =
754 "Invalid AS Path Segment Type: " + pathSegmentType;
Jonathan Hart41349e92015-02-09 14:14:02 -0800755 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800756 }
757
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900758 // 4-octet AS number handling.
759 int asPathLen;
760 if (bgpSession.isAs4OctetCapable()) {
Pavlin Radoslavova460e292015-03-17 18:04:56 -0700761 asPathLen = BgpConstants.Update.AS_4OCTET_LENGTH;
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900762 } else {
Pavlin Radoslavova460e292015-03-17 18:04:56 -0700763 asPathLen = BgpConstants.Update.AS_LENGTH;
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900764 }
765
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800766 // Parse the AS numbers
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900767 if (asPathLen * pathSegmentLength > attrLen) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800768 // ERROR: Malformed AS_PATH
769 actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
770 String errorMsg = "Malformed AS Path";
Jonathan Hart41349e92015-02-09 14:14:02 -0800771 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800772 }
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900773 attrLen -= (asPathLen * pathSegmentLength);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800774 ArrayList<Long> segmentAsNumbers = new ArrayList<>();
775 while (pathSegmentLength-- > 0) {
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900776 long asNumber;
Pavlin Radoslavova460e292015-03-17 18:04:56 -0700777 if (asPathLen == BgpConstants.Update.AS_4OCTET_LENGTH) {
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900778 asNumber = message.readUnsignedInt();
779 } else {
780 asNumber = message.readUnsignedShort();
781 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800782 segmentAsNumbers.add(asNumber);
783 }
784
785 BgpRouteEntry.PathSegment pathSegment =
786 new BgpRouteEntry.PathSegment((byte) pathSegmentType,
787 segmentAsNumbers);
788 pathSegments.add(pathSegment);
789 }
790
791 return new BgpRouteEntry.AsPath(pathSegments);
792 }
793
794 /**
795 * Parses BGP UPDATE Attribute Type NEXT_HOP.
796 *
797 * @param bgpSession the BGP Session to use
798 * @param ctx the Channel Handler Context
799 * @param attrTypeCode the attribute type code
800 * @param attrLen the attribute length (in octets)
801 * @param attrFlags the attribute flags
802 * @param message the message to parse
803 * @return the parsed NEXT_HOP value
Jonathan Hart41349e92015-02-09 14:14:02 -0800804 * @throws BgpMessage.BgpParseException
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800805 */
806 private static Ip4Address parseAttributeTypeNextHop(
807 BgpSession bgpSession,
808 ChannelHandlerContext ctx,
809 int attrTypeCode,
810 int attrLen,
811 int attrFlags,
812 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -0800813 throws BgpMessage.BgpParseException {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800814
815 // Check the Attribute Length
Jonathan Hart41349e92015-02-09 14:14:02 -0800816 if (attrLen != BgpConstants.Update.NextHop.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800817 // ERROR: Attribute Length Error
818 actionsBgpUpdateAttributeLengthError(
819 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
820 String errorMsg = "Attribute Length Error";
Jonathan Hart41349e92015-02-09 14:14:02 -0800821 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800822 }
823
824 message.markReaderIndex();
825 Ip4Address nextHopAddress =
826 Ip4Address.valueOf((int) message.readUnsignedInt());
827 //
828 // Check whether the NEXT_HOP IP address is semantically correct.
829 // As per RFC 4271, Section 6.3:
830 //
831 // a) It MUST NOT be the IP address of the receiving speaker
832 // b) In the case of an EBGP ....
833 //
834 // Here we check only (a), because (b) doesn't apply for us: all our
835 // peers are iBGP.
836 //
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800837 if (nextHopAddress.equals(bgpSession.localInfo().ip4Address())) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800838 // ERROR: Invalid NEXT_HOP Attribute
839 message.resetReaderIndex();
840 actionsBgpUpdateInvalidNextHopAttribute(
841 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message,
842 nextHopAddress);
843 String errorMsg = "Invalid NEXT_HOP Attribute: " + nextHopAddress;
Jonathan Hart41349e92015-02-09 14:14:02 -0800844 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800845 }
846
847 return nextHopAddress;
848 }
849
850 /**
851 * Parses BGP UPDATE Attribute Type MULTI_EXIT_DISC.
852 *
853 * @param bgpSession the BGP Session to use
854 * @param ctx the Channel Handler Context
855 * @param attrTypeCode the attribute type code
856 * @param attrLen the attribute length (in octets)
857 * @param attrFlags the attribute flags
858 * @param message the message to parse
859 * @return the parsed MULTI_EXIT_DISC value
Jonathan Hart41349e92015-02-09 14:14:02 -0800860 * @throws BgpMessage.BgpParseException
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800861 */
862 private static long parseAttributeTypeMultiExitDisc(
863 BgpSession bgpSession,
864 ChannelHandlerContext ctx,
865 int attrTypeCode,
866 int attrLen,
867 int attrFlags,
868 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -0800869 throws BgpMessage.BgpParseException {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800870
871 // Check the Attribute Length
Jonathan Hart41349e92015-02-09 14:14:02 -0800872 if (attrLen != BgpConstants.Update.MultiExitDisc.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800873 // ERROR: Attribute Length Error
874 actionsBgpUpdateAttributeLengthError(
875 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
876 String errorMsg = "Attribute Length Error";
Jonathan Hart41349e92015-02-09 14:14:02 -0800877 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800878 }
879
880 long multiExitDisc = message.readUnsignedInt();
881 return multiExitDisc;
882 }
883
884 /**
885 * Parses BGP UPDATE Attribute Type LOCAL_PREF.
886 *
887 * @param bgpSession the BGP Session to use
888 * @param ctx the Channel Handler Context
889 * @param attrTypeCode the attribute type code
890 * @param attrLen the attribute length (in octets)
891 * @param attrFlags the attribute flags
892 * @param message the message to parse
893 * @return the parsed LOCAL_PREF value
Jonathan Hart41349e92015-02-09 14:14:02 -0800894 * @throws BgpMessage.BgpParseException
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800895 */
896 private static long parseAttributeTypeLocalPref(
897 BgpSession bgpSession,
898 ChannelHandlerContext ctx,
899 int attrTypeCode,
900 int attrLen,
901 int attrFlags,
902 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -0800903 throws BgpMessage.BgpParseException {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800904
905 // Check the Attribute Length
Jonathan Hart41349e92015-02-09 14:14:02 -0800906 if (attrLen != BgpConstants.Update.LocalPref.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800907 // ERROR: Attribute Length Error
908 actionsBgpUpdateAttributeLengthError(
909 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
910 String errorMsg = "Attribute Length Error";
Jonathan Hart41349e92015-02-09 14:14:02 -0800911 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800912 }
913
914 long localPref = message.readUnsignedInt();
915 return localPref;
916 }
917
918 /**
919 * Parses BGP UPDATE Attribute Type ATOMIC_AGGREGATE.
920 *
921 * @param bgpSession the BGP Session to use
922 * @param ctx the Channel Handler Context
923 * @param attrTypeCode the attribute type code
924 * @param attrLen the attribute length (in octets)
925 * @param attrFlags the attribute flags
926 * @param message the message to parse
Jonathan Hart41349e92015-02-09 14:14:02 -0800927 * @throws BgpMessage.BgpParseException
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800928 */
929 private static void parseAttributeTypeAtomicAggregate(
930 BgpSession bgpSession,
931 ChannelHandlerContext ctx,
932 int attrTypeCode,
933 int attrLen,
934 int attrFlags,
935 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -0800936 throws BgpMessage.BgpParseException {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800937
938 // Check the Attribute Length
Jonathan Hart41349e92015-02-09 14:14:02 -0800939 if (attrLen != BgpConstants.Update.AtomicAggregate.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800940 // ERROR: Attribute Length Error
941 actionsBgpUpdateAttributeLengthError(
942 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
943 String errorMsg = "Attribute Length Error";
Jonathan Hart41349e92015-02-09 14:14:02 -0800944 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800945 }
946
947 // Nothing to do: this attribute is primarily informational
948 }
949
950 /**
951 * Parses BGP UPDATE Attribute Type AGGREGATOR.
952 *
953 * @param bgpSession the BGP Session to use
954 * @param ctx the Channel Handler Context
955 * @param attrTypeCode the attribute type code
956 * @param attrLen the attribute length (in octets)
957 * @param attrFlags the attribute flags
958 * @param message the message to parse
959 * @return the parsed AGGREGATOR value: a tuple of <AS-Number, IP-Address>
Jonathan Hart41349e92015-02-09 14:14:02 -0800960 * @throws BgpMessage.BgpParseException
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800961 */
962 private static Pair<Long, Ip4Address> parseAttributeTypeAggregator(
963 BgpSession bgpSession,
964 ChannelHandlerContext ctx,
965 int attrTypeCode,
966 int attrLen,
967 int attrFlags,
968 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -0800969 throws BgpMessage.BgpParseException {
Pavlin Radoslavova460e292015-03-17 18:04:56 -0700970 int expectedAttrLen;
971
972 if (bgpSession.isAs4OctetCapable()) {
973 expectedAttrLen = BgpConstants.Update.Aggregator.AS4_LENGTH;
974 } else {
975 expectedAttrLen = BgpConstants.Update.Aggregator.AS2_LENGTH;
976 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800977
978 // Check the Attribute Length
Pavlin Radoslavova460e292015-03-17 18:04:56 -0700979 if (attrLen != expectedAttrLen) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800980 // ERROR: Attribute Length Error
981 actionsBgpUpdateAttributeLengthError(
982 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
983 String errorMsg = "Attribute Length Error";
Jonathan Hart41349e92015-02-09 14:14:02 -0800984 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800985 }
986
987 // The AGGREGATOR AS number
Pavlin Radoslavova460e292015-03-17 18:04:56 -0700988 long aggregatorAsNumber;
989 if (bgpSession.isAs4OctetCapable()) {
990 aggregatorAsNumber = message.readUnsignedInt();
991 } else {
992 aggregatorAsNumber = message.readUnsignedShort();
993 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800994 // 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
Jonathan Hart41349e92015-02-09 14:14:02 -08001014 * @throws BgpMessage.BgpParseException
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001015 */
1016 private static MpNlri parseAttributeTypeMpReachNlri(
1017 BgpSession bgpSession,
1018 ChannelHandlerContext ctx,
1019 int attrTypeCode,
1020 int attrLen,
1021 int attrFlags,
1022 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -08001023 throws BgpMessage.BgpParseException {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001024 int attributeEnd = message.readerIndex() + attrLen;
1025
1026 // Check the Attribute Length
Jonathan Hart41349e92015-02-09 14:14:02 -08001027 if (attrLen < BgpConstants.Update.MpReachNlri.MIN_LENGTH) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001028 // ERROR: Attribute Length Error
1029 actionsBgpUpdateAttributeLengthError(
1030 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1031 String errorMsg = "Attribute Length Error";
Jonathan Hart41349e92015-02-09 14:14:02 -08001032 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001033 }
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 //
Jonathan Hart41349e92015-02-09 14:14:02 -08001044 if (((afi != BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4) &&
1045 (afi != BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6)) ||
1046 (safi != BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_UNICAST)) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001047 // 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) {
Jonathan Hart41349e92015-02-09 14:14:02 -08001058 case BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001059 expectedNextHopLen = Ip4Address.BYTE_LENGTH;
1060 break;
Jonathan Hart41349e92015-02-09 14:14:02 -08001061 case BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001062 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;
Jonathan Hart41349e92015-02-09 14:14:02 -08001075 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001076 }
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";
Jonathan Hart41349e92015-02-09 14:14:02 -08001084 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001085 }
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) {
Jonathan Hart41349e92015-02-09 14:14:02 -08001096 case BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001097 // 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;
Jonathan Hart41349e92015-02-09 14:14:02 -08001104 case BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001105 // 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 }
Jonathan Hart41349e92015-02-09 14:14:02 -08001116 } catch (BgpMessage.BgpParseException e) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001117 // ERROR: Optional Attribute Error
1118 message.resetReaderIndex();
1119 actionsBgpUpdateOptionalAttributeError(
1120 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1121 String errorMsg = "Malformed network layer reachability information";
Jonathan Hart41349e92015-02-09 14:14:02 -08001122 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001123 }
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
Jonathan Hart41349e92015-02-09 14:14:02 -08001139 * @throws BgpMessage.BgpParseException
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001140 */
1141 private static MpNlri parseAttributeTypeMpUnreachNlri(
1142 BgpSession bgpSession,
1143 ChannelHandlerContext ctx,
1144 int attrTypeCode,
1145 int attrLen,
1146 int attrFlags,
1147 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -08001148 throws BgpMessage.BgpParseException {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001149 int attributeEnd = message.readerIndex() + attrLen;
1150
1151 // Check the Attribute Length
Jonathan Hart41349e92015-02-09 14:14:02 -08001152 if (attrLen < BgpConstants.Update.MpUnreachNlri.MIN_LENGTH) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001153 // ERROR: Attribute Length Error
1154 actionsBgpUpdateAttributeLengthError(
1155 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1156 String errorMsg = "Attribute Length Error";
Jonathan Hart41349e92015-02-09 14:14:02 -08001157 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001158 }
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 //
Jonathan Hart41349e92015-02-09 14:14:02 -08001168 if (((afi != BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4) &&
1169 (afi != BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6)) ||
1170 (safi != BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_UNICAST)) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001171 // 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) {
Jonathan Hart41349e92015-02-09 14:14:02 -08001183 case BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001184 // The Withdrawn Routes
1185 mpNlri.nlri4 = parsePackedIp4Prefixes(
1186 attributeEnd - message.readerIndex(),
1187 message);
1188 break;
Jonathan Hart41349e92015-02-09 14:14:02 -08001189 case BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001190 // The Withdrawn Routes
1191 mpNlri.nlri6 = parsePackedIp6Prefixes(
1192 attributeEnd - message.readerIndex(),
1193 message);
1194 break;
1195 default:
1196 // UNREACHABLE
1197 break;
1198 }
Jonathan Hart41349e92015-02-09 14:14:02 -08001199 } catch (BgpMessage.BgpParseException e) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001200 // ERROR: Optional Attribute Error
1201 message.resetReaderIndex();
1202 actionsBgpUpdateOptionalAttributeError(
1203 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1204 String errorMsg = "Malformed withdrawn routes";
Jonathan Hart41349e92015-02-09 14:14:02 -08001205 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001206 }
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
Jonathan Hart41349e92015-02-09 14:14:02 -08001222 * @throws BgpMessage.BgpParseException
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001223 */
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)
Jonathan Hart41349e92015-02-09 14:14:02 -08001227 throws BgpMessage.BgpParseException {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001228 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";
Jonathan Hart41349e92015-02-09 14:14:02 -08001242 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001243 }
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
Jonathan Hart41349e92015-02-09 14:14:02 -08001265 * @throws BgpMessage.BgpParseException
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001266 */
1267 private static Collection<Ip6Prefix> parsePackedIp6Prefixes(
1268 int totalLength,
1269 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -08001270 throws BgpMessage.BgpParseException {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001271 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";
Jonathan Hart41349e92015-02-09 14:14:02 -08001285 throw new BgpMessage.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",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001308 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001309
1310 //
1311 // ERROR: Invalid Network Field
1312 //
1313 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001314 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1315 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.INVALID_NETWORK_FIELD;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001316 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",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001334 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001335
1336 //
1337 // ERROR: Malformed Attribute List
1338 //
1339 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001340 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1341 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.MALFORMED_ATTRIBUTE_LIST;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001342 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: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001363 bgpSession.remoteInfo().address(), missingAttrTypeCode);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001364
1365 //
1366 // ERROR: Missing Well-known Attribute
1367 //
1368 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001369 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1370 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.MISSING_WELL_KNOWN_ATTRIBUTE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001371 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",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001401 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001402
1403 //
1404 // ERROR: Invalid ORIGIN Attribute
1405 //
1406 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001407 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1408 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.INVALID_ORIGIN_ATTRIBUTE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001409 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",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001438 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001439
1440 //
1441 // ERROR: Attribute Flags Error
1442 //
1443 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001444 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1445 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.ATTRIBUTE_FLAGS_ERROR;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001446 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 {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001478 bgpSession.remoteInfo().address(), nextHop);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001479
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
Jonathan Hart41349e92015-02-09 14:14:02 -08001484 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1485 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.INVALID_NEXT_HOP_ATTRIBUTE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001486 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: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001517 bgpSession.remoteInfo().address(), attrTypeCode);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001518
1519 //
1520 // ERROR: Unrecognized Well-known Attribute
1521 //
1522 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001523 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001524 int errorSubcode =
Jonathan Hart41349e92015-02-09 14:14:02 -08001525 BgpConstants.Notifications.UpdateMessageError.UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001526 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: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001556 bgpSession.remoteInfo().address(), attrTypeCode);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001557
1558 //
1559 // ERROR: Optional Attribute Error
1560 //
1561 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001562 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001563 int errorSubcode =
Jonathan Hart41349e92015-02-09 14:14:02 -08001564 BgpConstants.Notifications.UpdateMessageError.OPTIONAL_ATTRIBUTE_ERROR;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001565 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",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001594 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001595
1596 //
1597 // ERROR: Attribute Length Error
1598 //
1599 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001600 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1601 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.ATTRIBUTE_LENGTH_ERROR;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001602 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",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001623 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001624
1625 //
1626 // ERROR: Malformed AS_PATH
1627 //
1628 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001629 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1630 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.MALFORMED_AS_PATH;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001631 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}