blob: e9abd9c3b3ce3abaad197632d64fd829ef65d8e4 [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 */
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();
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800157 bgpRouteSelector.routeUpdates(bgpSession,
158 decodedBgpRoutes.addedUnicastRoutes4.values(),
159 decodedBgpRoutes.deletedUnicastRoutes4.values());
160 bgpRouteSelector.routeUpdates(bgpSession,
161 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()) {
Jonathan Hart41349e92015-02-09 14:14:02 -0800761 asPathLen = BgpConstants.Update.AsPath.AS_4OCTET_LENGTH;
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900762 } else {
Jonathan Hart41349e92015-02-09 14:14:02 -0800763 asPathLen = BgpConstants.Update.AsPath.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;
Jonathan Hart41349e92015-02-09 14:14:02 -0800777 if (asPathLen == BgpConstants.Update.AsPath.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 Radoslavov80f3e182014-12-15 10:46:18 -0800970
971 // Check the Attribute Length
Jonathan Hart41349e92015-02-09 14:14:02 -0800972 if (attrLen != BgpConstants.Update.Aggregator.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800973 // ERROR: Attribute Length Error
974 actionsBgpUpdateAttributeLengthError(
975 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
976 String errorMsg = "Attribute Length Error";
Jonathan Hart41349e92015-02-09 14:14:02 -0800977 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800978 }
979
980 // The AGGREGATOR AS number
981 long aggregatorAsNumber = message.readUnsignedShort();
982 // The AGGREGATOR IP address
983 Ip4Address aggregatorIpAddress =
984 Ip4Address.valueOf((int) message.readUnsignedInt());
985
986 Pair<Long, Ip4Address> aggregator = Pair.of(aggregatorAsNumber,
987 aggregatorIpAddress);
988 return aggregator;
989 }
990
991 /**
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800992 * Parses BGP UPDATE Attribute Type MP_REACH_NLRI.
993 *
994 * @param bgpSession the BGP Session to use
995 * @param ctx the Channel Handler Context
996 * @param attrTypeCode the attribute type code
997 * @param attrLen the attribute length (in octets)
998 * @param attrFlags the attribute flags
999 * @param message the message to parse
1000 * @return the parsed MP_REACH_NLRI information if recognized, otherwise
1001 * null
Jonathan Hart41349e92015-02-09 14:14:02 -08001002 * @throws BgpMessage.BgpParseException
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001003 */
1004 private static MpNlri parseAttributeTypeMpReachNlri(
1005 BgpSession bgpSession,
1006 ChannelHandlerContext ctx,
1007 int attrTypeCode,
1008 int attrLen,
1009 int attrFlags,
1010 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -08001011 throws BgpMessage.BgpParseException {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001012 int attributeEnd = message.readerIndex() + attrLen;
1013
1014 // Check the Attribute Length
Jonathan Hart41349e92015-02-09 14:14:02 -08001015 if (attrLen < BgpConstants.Update.MpReachNlri.MIN_LENGTH) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001016 // ERROR: Attribute Length Error
1017 actionsBgpUpdateAttributeLengthError(
1018 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1019 String errorMsg = "Attribute Length Error";
Jonathan Hart41349e92015-02-09 14:14:02 -08001020 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001021 }
1022
1023 message.markReaderIndex();
1024 int afi = message.readUnsignedShort();
1025 int safi = message.readUnsignedByte();
1026 int nextHopLen = message.readUnsignedByte();
1027
1028 //
1029 // Verify the AFI/SAFI, and skip the attribute if not recognized.
1030 // NOTE: Currently, we support only IPv4/IPv6 UNICAST
1031 //
Jonathan Hart41349e92015-02-09 14:14:02 -08001032 if (((afi != BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4) &&
1033 (afi != BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6)) ||
1034 (safi != BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_UNICAST)) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001035 // Skip the attribute
1036 message.resetReaderIndex();
1037 message.skipBytes(attrLen);
1038 return null;
1039 }
1040
1041 //
1042 // Verify the next-hop length
1043 //
1044 int expectedNextHopLen = 0;
1045 switch (afi) {
Jonathan Hart41349e92015-02-09 14:14:02 -08001046 case BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001047 expectedNextHopLen = Ip4Address.BYTE_LENGTH;
1048 break;
Jonathan Hart41349e92015-02-09 14:14:02 -08001049 case BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001050 expectedNextHopLen = Ip6Address.BYTE_LENGTH;
1051 break;
1052 default:
1053 // UNREACHABLE
1054 break;
1055 }
1056 if (nextHopLen != expectedNextHopLen) {
1057 // ERROR: Optional Attribute Error
1058 message.resetReaderIndex();
1059 actionsBgpUpdateOptionalAttributeError(
1060 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1061 String errorMsg = "Invalid next-hop network address length. " +
1062 "Received " + nextHopLen + " expected " + expectedNextHopLen;
Jonathan Hart41349e92015-02-09 14:14:02 -08001063 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001064 }
1065 // NOTE: We use "+ 1" to take into account the Reserved field (1 octet)
1066 if (message.readerIndex() + nextHopLen + 1 >= attributeEnd) {
1067 // ERROR: Optional Attribute Error
1068 message.resetReaderIndex();
1069 actionsBgpUpdateOptionalAttributeError(
1070 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1071 String errorMsg = "Malformed next-hop network address";
Jonathan Hart41349e92015-02-09 14:14:02 -08001072 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001073 }
1074
1075 //
1076 // Get the Next-hop address, skip the Reserved field, and get the NLRI
1077 //
1078 byte[] nextHopBuffer = new byte[nextHopLen];
1079 message.readBytes(nextHopBuffer, 0, nextHopLen);
1080 int reserved = message.readUnsignedByte();
1081 MpNlri mpNlri = new MpNlri(afi, safi);
1082 try {
1083 switch (afi) {
Jonathan Hart41349e92015-02-09 14:14:02 -08001084 case BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001085 // The next-hop address
1086 mpNlri.nextHop4 = Ip4Address.valueOf(nextHopBuffer);
1087 // The NLRI
1088 mpNlri.nlri4 = parsePackedIp4Prefixes(
1089 attributeEnd - message.readerIndex(),
1090 message);
1091 break;
Jonathan Hart41349e92015-02-09 14:14:02 -08001092 case BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001093 // The next-hop address
1094 mpNlri.nextHop6 = Ip6Address.valueOf(nextHopBuffer);
1095 // The NLRI
1096 mpNlri.nlri6 = parsePackedIp6Prefixes(
1097 attributeEnd - message.readerIndex(),
1098 message);
1099 break;
1100 default:
1101 // UNREACHABLE
1102 break;
1103 }
Jonathan Hart41349e92015-02-09 14:14:02 -08001104 } catch (BgpMessage.BgpParseException e) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001105 // ERROR: Optional Attribute Error
1106 message.resetReaderIndex();
1107 actionsBgpUpdateOptionalAttributeError(
1108 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1109 String errorMsg = "Malformed network layer reachability information";
Jonathan Hart41349e92015-02-09 14:14:02 -08001110 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001111 }
1112
1113 return mpNlri;
1114 }
1115
1116 /**
1117 * Parses BGP UPDATE Attribute Type MP_UNREACH_NLRI.
1118 *
1119 * @param bgpSession the BGP Session to use
1120 * @param ctx the Channel Handler Context
1121 * @param attrTypeCode the attribute type code
1122 * @param attrLen the attribute length (in octets)
1123 * @param attrFlags the attribute flags
1124 * @param message the message to parse
1125 * @return the parsed MP_UNREACH_NLRI information if recognized, otherwise
1126 * null
Jonathan Hart41349e92015-02-09 14:14:02 -08001127 * @throws BgpMessage.BgpParseException
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001128 */
1129 private static MpNlri parseAttributeTypeMpUnreachNlri(
1130 BgpSession bgpSession,
1131 ChannelHandlerContext ctx,
1132 int attrTypeCode,
1133 int attrLen,
1134 int attrFlags,
1135 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -08001136 throws BgpMessage.BgpParseException {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001137 int attributeEnd = message.readerIndex() + attrLen;
1138
1139 // Check the Attribute Length
Jonathan Hart41349e92015-02-09 14:14:02 -08001140 if (attrLen < BgpConstants.Update.MpUnreachNlri.MIN_LENGTH) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001141 // ERROR: Attribute Length Error
1142 actionsBgpUpdateAttributeLengthError(
1143 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1144 String errorMsg = "Attribute Length Error";
Jonathan Hart41349e92015-02-09 14:14:02 -08001145 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001146 }
1147
1148 message.markReaderIndex();
1149 int afi = message.readUnsignedShort();
1150 int safi = message.readUnsignedByte();
1151
1152 //
1153 // Verify the AFI/SAFI, and skip the attribute if not recognized.
1154 // NOTE: Currently, we support only IPv4/IPv6 UNICAST
1155 //
Jonathan Hart41349e92015-02-09 14:14:02 -08001156 if (((afi != BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4) &&
1157 (afi != BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6)) ||
1158 (safi != BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_UNICAST)) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001159 // Skip the attribute
1160 message.resetReaderIndex();
1161 message.skipBytes(attrLen);
1162 return null;
1163 }
1164
1165 //
1166 // Get the Withdrawn Routes
1167 //
1168 MpNlri mpNlri = new MpNlri(afi, safi);
1169 try {
1170 switch (afi) {
Jonathan Hart41349e92015-02-09 14:14:02 -08001171 case BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001172 // The Withdrawn Routes
1173 mpNlri.nlri4 = parsePackedIp4Prefixes(
1174 attributeEnd - message.readerIndex(),
1175 message);
1176 break;
Jonathan Hart41349e92015-02-09 14:14:02 -08001177 case BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6:
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001178 // The Withdrawn Routes
1179 mpNlri.nlri6 = parsePackedIp6Prefixes(
1180 attributeEnd - message.readerIndex(),
1181 message);
1182 break;
1183 default:
1184 // UNREACHABLE
1185 break;
1186 }
Jonathan Hart41349e92015-02-09 14:14:02 -08001187 } catch (BgpMessage.BgpParseException e) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001188 // ERROR: Optional Attribute Error
1189 message.resetReaderIndex();
1190 actionsBgpUpdateOptionalAttributeError(
1191 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1192 String errorMsg = "Malformed withdrawn routes";
Jonathan Hart41349e92015-02-09 14:14:02 -08001193 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001194 }
1195
1196 return mpNlri;
1197 }
1198
1199 /**
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001200 * Parses a message that contains encoded IPv4 network prefixes.
1201 * <p>
1202 * The IPv4 prefixes are encoded in the form:
1203 * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
1204 * and Prefix is the IPv4 prefix (padded with trailing bits to the end
1205 * of an octet).
1206 *
1207 * @param totalLength the total length of the data to parse
1208 * @param message the message with data to parse
1209 * @return a collection of parsed IPv4 network prefixes
Jonathan Hart41349e92015-02-09 14:14:02 -08001210 * @throws BgpMessage.BgpParseException
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001211 */
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001212 private static Collection<Ip4Prefix> parsePackedIp4Prefixes(
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001213 int totalLength,
1214 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -08001215 throws BgpMessage.BgpParseException {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001216 Collection<Ip4Prefix> result = new ArrayList<>();
1217
1218 if (totalLength == 0) {
1219 return result;
1220 }
1221
1222 // Parse the data
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001223 byte[] buffer = new byte[Ip4Address.BYTE_LENGTH];
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001224 int dataEnd = message.readerIndex() + totalLength;
1225 while (message.readerIndex() < dataEnd) {
1226 int prefixBitlen = message.readUnsignedByte();
1227 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
1228 if (message.readerIndex() + prefixBytelen > dataEnd) {
1229 String errorMsg = "Malformed Network Prefixes";
Jonathan Hart41349e92015-02-09 14:14:02 -08001230 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001231 }
1232
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001233 message.readBytes(buffer, 0, prefixBytelen);
1234 Ip4Prefix prefix = Ip4Prefix.valueOf(Ip4Address.valueOf(buffer),
1235 prefixBitlen);
1236 result.add(prefix);
1237 }
1238
1239 return result;
1240 }
1241
1242 /**
1243 * Parses a message that contains encoded IPv6 network prefixes.
1244 * <p>
1245 * The IPv6 prefixes are encoded in the form:
1246 * <Length, Prefix> where Length is the length in bits of the IPv6 prefix,
1247 * and Prefix is the IPv6 prefix (padded with trailing bits to the end
1248 * of an octet).
1249 *
1250 * @param totalLength the total length of the data to parse
1251 * @param message the message with data to parse
1252 * @return a collection of parsed IPv6 network prefixes
Jonathan Hart41349e92015-02-09 14:14:02 -08001253 * @throws BgpMessage.BgpParseException
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001254 */
1255 private static Collection<Ip6Prefix> parsePackedIp6Prefixes(
1256 int totalLength,
1257 ChannelBuffer message)
Jonathan Hart41349e92015-02-09 14:14:02 -08001258 throws BgpMessage.BgpParseException {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001259 Collection<Ip6Prefix> result = new ArrayList<>();
1260
1261 if (totalLength == 0) {
1262 return result;
1263 }
1264
1265 // Parse the data
1266 byte[] buffer = new byte[Ip6Address.BYTE_LENGTH];
1267 int dataEnd = message.readerIndex() + totalLength;
1268 while (message.readerIndex() < dataEnd) {
1269 int prefixBitlen = message.readUnsignedByte();
1270 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
1271 if (message.readerIndex() + prefixBytelen > dataEnd) {
1272 String errorMsg = "Malformed Network Prefixes";
Jonathan Hart41349e92015-02-09 14:14:02 -08001273 throw new BgpMessage.BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001274 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001275
1276 message.readBytes(buffer, 0, prefixBytelen);
1277 Ip6Prefix prefix = Ip6Prefix.valueOf(Ip6Address.valueOf(buffer),
1278 prefixBitlen);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001279 result.add(prefix);
1280 }
1281
1282 return result;
1283 }
1284
1285 /**
1286 * Applies the appropriate actions after detecting BGP UPDATE
1287 * Invalid Network Field Error: send NOTIFICATION and close the channel.
1288 *
1289 * @param bgpSession the BGP Session to use
1290 * @param ctx the Channel Handler Context
1291 */
1292 private static void actionsBgpUpdateInvalidNetworkField(
1293 BgpSession bgpSession,
1294 ChannelHandlerContext ctx) {
1295 log.debug("BGP RX UPDATE Error from {}: Invalid Network Field",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001296 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001297
1298 //
1299 // ERROR: Invalid Network Field
1300 //
1301 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001302 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1303 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.INVALID_NETWORK_FIELD;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001304 ChannelBuffer txMessage =
1305 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1306 null);
1307 ctx.getChannel().write(txMessage);
1308 bgpSession.closeSession(ctx);
1309 }
1310
1311 /**
1312 * Applies the appropriate actions after detecting BGP UPDATE
1313 * Malformed Attribute List Error: send NOTIFICATION and close the channel.
1314 *
1315 * @param bgpSession the BGP Session to use
1316 * @param ctx the Channel Handler Context
1317 */
1318 private static void actionsBgpUpdateMalformedAttributeList(
1319 BgpSession bgpSession,
1320 ChannelHandlerContext ctx) {
1321 log.debug("BGP RX UPDATE Error from {}: Malformed Attribute List",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001322 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001323
1324 //
1325 // ERROR: Malformed Attribute List
1326 //
1327 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001328 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1329 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.MALFORMED_ATTRIBUTE_LIST;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001330 ChannelBuffer txMessage =
1331 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1332 null);
1333 ctx.getChannel().write(txMessage);
1334 bgpSession.closeSession(ctx);
1335 }
1336
1337 /**
1338 * Applies the appropriate actions after detecting BGP UPDATE
1339 * Missing Well-known Attribute Error: send NOTIFICATION and close the
1340 * channel.
1341 *
1342 * @param bgpSession the BGP Session to use
1343 * @param ctx the Channel Handler Context
1344 * @param missingAttrTypeCode the missing attribute type code
1345 */
1346 private static void actionsBgpUpdateMissingWellKnownAttribute(
1347 BgpSession bgpSession,
1348 ChannelHandlerContext ctx,
1349 int missingAttrTypeCode) {
1350 log.debug("BGP RX UPDATE Error from {}: Missing Well-known Attribute: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001351 bgpSession.remoteInfo().address(), missingAttrTypeCode);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001352
1353 //
1354 // ERROR: Missing Well-known Attribute
1355 //
1356 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001357 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1358 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.MISSING_WELL_KNOWN_ATTRIBUTE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001359 ChannelBuffer data = ChannelBuffers.buffer(1);
1360 data.writeByte(missingAttrTypeCode);
1361 ChannelBuffer txMessage =
1362 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1363 data);
1364 ctx.getChannel().write(txMessage);
1365 bgpSession.closeSession(ctx);
1366 }
1367
1368 /**
1369 * Applies the appropriate actions after detecting BGP UPDATE
1370 * Invalid ORIGIN Attribute Error: send NOTIFICATION and close the channel.
1371 *
1372 * @param bgpSession the BGP Session to use
1373 * @param ctx the Channel Handler Context
1374 * @param attrTypeCode the attribute type code
1375 * @param attrLen the attribute length (in octets)
1376 * @param attrFlags the attribute flags
1377 * @param message the message with the data
1378 * @param origin the ORIGIN attribute value
1379 */
1380 private static void actionsBgpUpdateInvalidOriginAttribute(
1381 BgpSession bgpSession,
1382 ChannelHandlerContext ctx,
1383 int attrTypeCode,
1384 int attrLen,
1385 int attrFlags,
1386 ChannelBuffer message,
1387 short origin) {
1388 log.debug("BGP RX UPDATE Error from {}: Invalid ORIGIN Attribute",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001389 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001390
1391 //
1392 // ERROR: Invalid ORIGIN Attribute
1393 //
1394 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001395 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1396 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.INVALID_ORIGIN_ATTRIBUTE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001397 ChannelBuffer data =
1398 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1399 attrFlags, message);
1400 ChannelBuffer txMessage =
1401 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1402 data);
1403 ctx.getChannel().write(txMessage);
1404 bgpSession.closeSession(ctx);
1405 }
1406
1407 /**
1408 * Applies the appropriate actions after detecting BGP UPDATE
1409 * Attribute Flags Error: send NOTIFICATION and close the channel.
1410 *
1411 * @param bgpSession the BGP Session to use
1412 * @param ctx the Channel Handler Context
1413 * @param attrTypeCode the attribute type code
1414 * @param attrLen the attribute length (in octets)
1415 * @param attrFlags the attribute flags
1416 * @param message the message with the data
1417 */
1418 private static void actionsBgpUpdateAttributeFlagsError(
1419 BgpSession bgpSession,
1420 ChannelHandlerContext ctx,
1421 int attrTypeCode,
1422 int attrLen,
1423 int attrFlags,
1424 ChannelBuffer message) {
1425 log.debug("BGP RX UPDATE Error from {}: Attribute Flags Error",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001426 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001427
1428 //
1429 // ERROR: Attribute Flags Error
1430 //
1431 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001432 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1433 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.ATTRIBUTE_FLAGS_ERROR;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001434 ChannelBuffer data =
1435 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1436 attrFlags, message);
1437 ChannelBuffer txMessage =
1438 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1439 data);
1440 ctx.getChannel().write(txMessage);
1441 bgpSession.closeSession(ctx);
1442 }
1443
1444 /**
1445 * Applies the appropriate actions after detecting BGP UPDATE
1446 * Invalid NEXT_HOP Attribute Error: send NOTIFICATION and close the
1447 * channel.
1448 *
1449 * @param bgpSession the BGP Session to use
1450 * @param ctx the Channel Handler Context
1451 * @param attrTypeCode the attribute type code
1452 * @param attrLen the attribute length (in octets)
1453 * @param attrFlags the attribute flags
1454 * @param message the message with the data
1455 * @param nextHop the NEXT_HOP attribute value
1456 */
1457 private static void actionsBgpUpdateInvalidNextHopAttribute(
1458 BgpSession bgpSession,
1459 ChannelHandlerContext ctx,
1460 int attrTypeCode,
1461 int attrLen,
1462 int attrFlags,
1463 ChannelBuffer message,
1464 Ip4Address nextHop) {
1465 log.debug("BGP RX UPDATE Error from {}: Invalid NEXT_HOP Attribute {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001466 bgpSession.remoteInfo().address(), nextHop);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001467
1468 //
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001469 // ERROR: Invalid NEXT_HOP Attribute
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001470 //
1471 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001472 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1473 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.INVALID_NEXT_HOP_ATTRIBUTE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001474 ChannelBuffer data =
1475 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1476 attrFlags, message);
1477 ChannelBuffer txMessage =
1478 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1479 data);
1480 ctx.getChannel().write(txMessage);
1481 bgpSession.closeSession(ctx);
1482 }
1483
1484 /**
1485 * Applies the appropriate actions after detecting BGP UPDATE
1486 * Unrecognized Well-known Attribute Error: send NOTIFICATION and close
1487 * the channel.
1488 *
1489 * @param bgpSession the BGP Session to use
1490 * @param ctx the Channel Handler Context
1491 * @param attrTypeCode the attribute type code
1492 * @param attrLen the attribute length (in octets)
1493 * @param attrFlags the attribute flags
1494 * @param message the message with the data
1495 */
1496 private static void actionsBgpUpdateUnrecognizedWellKnownAttribute(
1497 BgpSession bgpSession,
1498 ChannelHandlerContext ctx,
1499 int attrTypeCode,
1500 int attrLen,
1501 int attrFlags,
1502 ChannelBuffer message) {
1503 log.debug("BGP RX UPDATE Error from {}: " +
1504 "Unrecognized Well-known Attribute Error: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001505 bgpSession.remoteInfo().address(), attrTypeCode);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001506
1507 //
1508 // ERROR: Unrecognized Well-known Attribute
1509 //
1510 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001511 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001512 int errorSubcode =
Jonathan Hart41349e92015-02-09 14:14:02 -08001513 BgpConstants.Notifications.UpdateMessageError.UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001514 ChannelBuffer data =
1515 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1516 attrFlags, message);
1517 ChannelBuffer txMessage =
1518 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1519 data);
1520 ctx.getChannel().write(txMessage);
1521 bgpSession.closeSession(ctx);
1522 }
1523
1524 /**
1525 * Applies the appropriate actions after detecting BGP UPDATE
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001526 * Optional Attribute Error: send NOTIFICATION and close
1527 * the channel.
1528 *
1529 * @param bgpSession the BGP Session to use
1530 * @param ctx the Channel Handler Context
1531 * @param attrTypeCode the attribute type code
1532 * @param attrLen the attribute length (in octets)
1533 * @param attrFlags the attribute flags
1534 * @param message the message with the data
1535 */
1536 private static void actionsBgpUpdateOptionalAttributeError(
1537 BgpSession bgpSession,
1538 ChannelHandlerContext ctx,
1539 int attrTypeCode,
1540 int attrLen,
1541 int attrFlags,
1542 ChannelBuffer message) {
1543 log.debug("BGP RX UPDATE Error from {}: Optional Attribute Error: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001544 bgpSession.remoteInfo().address(), attrTypeCode);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001545
1546 //
1547 // ERROR: Optional Attribute Error
1548 //
1549 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001550 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001551 int errorSubcode =
Jonathan Hart41349e92015-02-09 14:14:02 -08001552 BgpConstants.Notifications.UpdateMessageError.OPTIONAL_ATTRIBUTE_ERROR;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001553 ChannelBuffer data =
1554 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1555 attrFlags, message);
1556 ChannelBuffer txMessage =
1557 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1558 data);
1559 ctx.getChannel().write(txMessage);
1560 bgpSession.closeSession(ctx);
1561 }
1562
1563 /**
1564 * Applies the appropriate actions after detecting BGP UPDATE
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001565 * Attribute Length Error: send NOTIFICATION and close the channel.
1566 *
1567 * @param bgpSession the BGP Session to use
1568 * @param ctx the Channel Handler Context
1569 * @param attrTypeCode the attribute type code
1570 * @param attrLen the attribute length (in octets)
1571 * @param attrFlags the attribute flags
1572 * @param message the message with the data
1573 */
1574 private static void actionsBgpUpdateAttributeLengthError(
1575 BgpSession bgpSession,
1576 ChannelHandlerContext ctx,
1577 int attrTypeCode,
1578 int attrLen,
1579 int attrFlags,
1580 ChannelBuffer message) {
1581 log.debug("BGP RX UPDATE Error from {}: Attribute Length Error",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001582 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001583
1584 //
1585 // ERROR: Attribute Length Error
1586 //
1587 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001588 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1589 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.ATTRIBUTE_LENGTH_ERROR;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001590 ChannelBuffer data =
1591 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1592 attrFlags, message);
1593 ChannelBuffer txMessage =
1594 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1595 data);
1596 ctx.getChannel().write(txMessage);
1597 bgpSession.closeSession(ctx);
1598 }
1599
1600 /**
1601 * Applies the appropriate actions after detecting BGP UPDATE
1602 * Malformed AS_PATH Error: send NOTIFICATION and close the channel.
1603 *
1604 * @param bgpSession the BGP Session to use
1605 * @param ctx the Channel Handler Context
1606 */
1607 private static void actionsBgpUpdateMalformedAsPath(
1608 BgpSession bgpSession,
1609 ChannelHandlerContext ctx) {
1610 log.debug("BGP RX UPDATE Error from {}: Malformed AS Path",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001611 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001612
1613 //
1614 // ERROR: Malformed AS_PATH
1615 //
1616 // Send NOTIFICATION and close the connection
Jonathan Hart41349e92015-02-09 14:14:02 -08001617 int errorCode = BgpConstants.Notifications.UpdateMessageError.ERROR_CODE;
1618 int errorSubcode = BgpConstants.Notifications.UpdateMessageError.MALFORMED_AS_PATH;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001619 ChannelBuffer txMessage =
1620 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1621 null);
1622 ctx.getChannel().write(txMessage);
1623 bgpSession.closeSession(ctx);
1624 }
1625
1626 /**
1627 * Prepares BGP UPDATE Notification data payload.
1628 *
1629 * @param attrTypeCode the attribute type code
1630 * @param attrLen the attribute length (in octets)
1631 * @param attrFlags the attribute flags
1632 * @param message the message with the data
1633 * @return the buffer with the data payload for the BGP UPDATE Notification
1634 */
1635 private static ChannelBuffer prepareBgpUpdateNotificationDataPayload(
1636 int attrTypeCode,
1637 int attrLen,
1638 int attrFlags,
1639 ChannelBuffer message) {
1640 // Compute the attribute length field octets
1641 boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
1642 int attrLenOctets = 1;
1643 if (extendedLengthBit) {
1644 attrLenOctets = 2;
1645 }
1646 ChannelBuffer data =
1647 ChannelBuffers.buffer(attrLen + attrLenOctets + 1);
1648 data.writeByte(attrTypeCode);
1649 if (extendedLengthBit) {
1650 data.writeShort(attrLen);
1651 } else {
1652 data.writeByte(attrLen);
1653 }
1654 data.writeBytes(message, attrLen);
1655 return data;
1656 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001657
1658 /**
1659 * Helper class for storing Multiprotocol Network Layer Reachability
1660 * information.
1661 */
1662 private static final class MpNlri {
1663 private final int afi;
1664 private final int safi;
1665 private Ip4Address nextHop4;
1666 private Ip6Address nextHop6;
1667 private Collection<Ip4Prefix> nlri4 = new ArrayList<>();
1668 private Collection<Ip6Prefix> nlri6 = new ArrayList<>();
1669
1670 /**
1671 * Constructor.
1672 *
1673 * @param afi the Address Family Identifier
1674 * @param safi the Subsequent Address Family Identifier
1675 */
1676 private MpNlri(int afi, int safi) {
1677 this.afi = afi;
1678 this.safi = safi;
1679 }
1680 }
1681
1682 /**
1683 * Helper class for storing decoded BGP routing information.
1684 */
1685 private static final class DecodedBgpRoutes {
1686 private final Map<Ip4Prefix, BgpRouteEntry> addedUnicastRoutes4 =
1687 new HashMap<>();
1688 private final Map<Ip6Prefix, BgpRouteEntry> addedUnicastRoutes6 =
1689 new HashMap<>();
1690 private final Map<Ip4Prefix, BgpRouteEntry> deletedUnicastRoutes4 =
1691 new HashMap<>();
1692 private final Map<Ip6Prefix, BgpRouteEntry> deletedUnicastRoutes6 =
1693 new HashMap<>();
1694 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001695}