blob: 2068324cc976b88503eb4b9d1ce35bfbe260abf7 [file] [log] [blame]
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.sdnip.bgp;
17
18import java.util.ArrayList;
19import java.util.Collection;
20import java.util.HashMap;
21import java.util.Map;
22
23import org.apache.commons.lang3.tuple.Pair;
24import org.jboss.netty.buffer.ChannelBuffer;
25import org.jboss.netty.buffer.ChannelBuffers;
26import org.jboss.netty.channel.ChannelHandlerContext;
27import org.onlab.packet.Ip4Address;
28import org.onlab.packet.Ip4Prefix;
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080029import org.onlab.packet.Ip6Address;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -080030import org.onlab.packet.Ip6Prefix;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080031import org.onosproject.sdnip.bgp.BgpConstants.Notifications.UpdateMessageError;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -080032import org.onosproject.sdnip.bgp.BgpConstants.Open.Capabilities.MultiprotocolExtensions;
33import org.onosproject.sdnip.bgp.BgpConstants.Update;
34import org.onosproject.sdnip.bgp.BgpConstants.Update.AsPath;
Pavlin Radoslavov278cdde2014-12-16 14:09:31 -080035import org.onosproject.sdnip.bgp.BgpMessage.BgpParseException;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39/**
40 * A class for handling BGP UPDATE messages.
41 */
42final class BgpUpdate {
43 private static final Logger log = LoggerFactory.getLogger(BgpUpdate.class);
44
45 /**
46 * Default constructor.
47 * <p>
48 * The constructor is private to prevent creating an instance of
49 * this utility class.
50 */
51 private BgpUpdate() {
52 }
53
54 /**
55 * Processes BGP UPDATE message.
56 *
57 * @param bgpSession the BGP Session to use
58 * @param ctx the Channel Handler Context
59 * @param message the message to process
60 */
61 static void processBgpUpdate(BgpSession bgpSession,
62 ChannelHandlerContext ctx,
63 ChannelBuffer message) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -080064 DecodedBgpRoutes decodedBgpRoutes = new DecodedBgpRoutes();
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080065
66 int minLength =
67 BgpConstants.BGP_UPDATE_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
68 if (message.readableBytes() < minLength) {
69 log.debug("BGP RX UPDATE Error from {}: " +
70 "Message length {} too short. Must be at least {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -080071 bgpSession.remoteInfo().address(),
72 message.readableBytes(), minLength);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080073 //
74 // ERROR: Bad Message Length
75 //
76 // Send NOTIFICATION and close the connection
77 ChannelBuffer txMessage =
78 BgpNotification.prepareBgpNotificationBadMessageLength(
79 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
80 ctx.getChannel().write(txMessage);
81 bgpSession.closeSession(ctx);
82 return;
83 }
84
85 log.debug("BGP RX UPDATE message from {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -080086 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -080087
88 //
89 // Parse the UPDATE message
90 //
91
92 //
93 // Parse the Withdrawn Routes
94 //
95 int withdrawnRoutesLength = message.readUnsignedShort();
96 if (withdrawnRoutesLength > message.readableBytes()) {
97 // ERROR: Malformed Attribute List
98 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
99 return;
100 }
101 Collection<Ip4Prefix> withdrawnPrefixes = null;
102 try {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800103 withdrawnPrefixes = parsePackedIp4Prefixes(withdrawnRoutesLength,
104 message);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800105 } catch (BgpParseException e) {
106 // ERROR: Invalid Network Field
107 log.debug("Exception parsing Withdrawn Prefixes from BGP peer {}: ",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800108 bgpSession.remoteInfo().bgpId(), e);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800109 actionsBgpUpdateInvalidNetworkField(bgpSession, ctx);
110 return;
111 }
112 for (Ip4Prefix prefix : withdrawnPrefixes) {
113 log.debug("BGP RX UPDATE message WITHDRAWN from {}: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800114 bgpSession.remoteInfo().address(), prefix);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800115 BgpRouteEntry bgpRouteEntry = bgpSession.findBgpRoute(prefix);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800116 if (bgpRouteEntry != null) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800117 decodedBgpRoutes.deletedUnicastRoutes4.put(prefix,
118 bgpRouteEntry);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800119 }
120 }
121
122 //
123 // Parse the Path Attributes
124 //
125 try {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800126 parsePathAttributes(bgpSession, ctx, message, decodedBgpRoutes);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800127 } catch (BgpParseException e) {
128 log.debug("Exception parsing Path Attributes from BGP peer {}: ",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800129 bgpSession.remoteInfo().bgpId(), e);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800130 // NOTE: The session was already closed, so nothing else to do
131 return;
132 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800133
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800134 //
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800135 // Update the BGP RIB-IN
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800136 //
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800137 for (Ip4Prefix ip4Prefix :
138 decodedBgpRoutes.deletedUnicastRoutes4.keySet()) {
139 bgpSession.removeBgpRoute(ip4Prefix);
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 (BgpRouteEntry bgpRouteEntry :
143 decodedBgpRoutes.addedUnicastRoutes4.values()) {
144 bgpSession.addBgpRoute(bgpRouteEntry);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800145 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800146 //
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800147 for (Ip6Prefix ip6Prefix :
148 decodedBgpRoutes.deletedUnicastRoutes6.keySet()) {
149 bgpSession.removeBgpRoute(ip6Prefix);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800150 }
151 //
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800152 for (BgpRouteEntry bgpRouteEntry :
153 decodedBgpRoutes.addedUnicastRoutes6.values()) {
154 bgpSession.addBgpRoute(bgpRouteEntry);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800155 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800156
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800157 //
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800158 // Push the updates to the BGP Merged RIB
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800159 //
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800160 BgpRouteSelector bgpRouteSelector =
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800161 bgpSession.getBgpSessionManager().getBgpRouteSelector();
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800162 bgpRouteSelector.routeUpdates(bgpSession,
163 decodedBgpRoutes.addedUnicastRoutes4.values(),
164 decodedBgpRoutes.deletedUnicastRoutes4.values());
165 bgpRouteSelector.routeUpdates(bgpSession,
166 decodedBgpRoutes.addedUnicastRoutes6.values(),
167 decodedBgpRoutes.deletedUnicastRoutes6.values());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800168
169 // Start the Session Timeout timer
170 bgpSession.restartSessionTimeoutTimer(ctx);
171 }
172
173 /**
174 * Parse BGP Path Attributes from the BGP UPDATE message.
175 *
176 * @param bgpSession the BGP Session to use
177 * @param ctx the Channel Handler Context
178 * @param message the message to parse
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800179 * @param decodedBgpRoutes the container to store the decoded BGP Route
180 * Entries. It might already contain some route entries such as withdrawn
181 * IPv4 prefixes
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800182 * @throws BgpParseException
183 */
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800184 // CHECKSTYLE IGNORE MethodLength FOR NEXT 300 LINES
185 private static void parsePathAttributes(
186 BgpSession bgpSession,
187 ChannelHandlerContext ctx,
188 ChannelBuffer message,
189 DecodedBgpRoutes decodedBgpRoutes)
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800190 throws BgpParseException {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800191
192 //
193 // Parsed values
194 //
195 Short origin = -1; // Mandatory
196 BgpRouteEntry.AsPath asPath = null; // Mandatory
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800197 // Legacy NLRI (RFC 4271). Mandatory NEXT_HOP if legacy NLRI is used
198 MpNlri legacyNlri = new MpNlri(MultiprotocolExtensions.AFI_IPV4,
199 MultiprotocolExtensions.SAFI_UNICAST);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800200 long multiExitDisc = // Optional
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800201 Update.MultiExitDisc.LOWEST_MULTI_EXIT_DISC;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800202 Long localPref = null; // Mandatory
203 Long aggregatorAsNumber = null; // Optional: unused
204 Ip4Address aggregatorIpAddress = null; // Optional: unused
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800205 Collection<MpNlri> mpNlriReachList = new ArrayList<>(); // Optional
206 Collection<MpNlri> mpNlriUnreachList = new ArrayList<>(); // Optional
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800207
208 //
209 // Get and verify the Path Attributes Length
210 //
211 int pathAttributeLength = message.readUnsignedShort();
212 if (pathAttributeLength > message.readableBytes()) {
213 // ERROR: Malformed Attribute List
214 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
215 String errorMsg = "Malformed Attribute List";
216 throw new BgpParseException(errorMsg);
217 }
218 if (pathAttributeLength == 0) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800219 return;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800220 }
221
222 //
223 // Parse the Path Attributes
224 //
225 int pathAttributeEnd = message.readerIndex() + pathAttributeLength;
226 while (message.readerIndex() < pathAttributeEnd) {
227 int attrFlags = message.readUnsignedByte();
228 if (message.readerIndex() >= pathAttributeEnd) {
229 // ERROR: Malformed Attribute List
230 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
231 String errorMsg = "Malformed Attribute List";
232 throw new BgpParseException(errorMsg);
233 }
234 int attrTypeCode = message.readUnsignedByte();
235
236 // The Attribute Flags
237 boolean optionalBit = ((0x80 & attrFlags) != 0);
238 boolean transitiveBit = ((0x40 & attrFlags) != 0);
239 boolean partialBit = ((0x20 & attrFlags) != 0);
240 boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
241
242 // The Attribute Length
243 int attrLen = 0;
244 int attrLenOctets = 1;
245 if (extendedLengthBit) {
246 attrLenOctets = 2;
247 }
248 if (message.readerIndex() + attrLenOctets > pathAttributeEnd) {
249 // ERROR: Malformed Attribute List
250 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
251 String errorMsg = "Malformed Attribute List";
252 throw new BgpParseException(errorMsg);
253 }
254 if (extendedLengthBit) {
255 attrLen = message.readUnsignedShort();
256 } else {
257 attrLen = message.readUnsignedByte();
258 }
259 if (message.readerIndex() + attrLen > pathAttributeEnd) {
260 // ERROR: Malformed Attribute List
261 actionsBgpUpdateMalformedAttributeList(bgpSession, ctx);
262 String errorMsg = "Malformed Attribute List";
263 throw new BgpParseException(errorMsg);
264 }
265
266 // Verify the Attribute Flags
267 verifyBgpUpdateAttributeFlags(bgpSession, ctx, attrTypeCode,
268 attrLen, attrFlags, message);
269
270 //
271 // Extract the Attribute Value based on the Attribute Type Code
272 //
273 switch (attrTypeCode) {
274
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800275 case Update.Origin.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800276 // Attribute Type Code ORIGIN
277 origin = parseAttributeTypeOrigin(bgpSession, ctx,
278 attrTypeCode, attrLen,
279 attrFlags, message);
280 break;
281
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800282 case Update.AsPath.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800283 // Attribute Type Code AS_PATH
284 asPath = parseAttributeTypeAsPath(bgpSession, ctx,
285 attrTypeCode, attrLen,
286 attrFlags, message);
287 break;
288
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800289 case Update.NextHop.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800290 // Attribute Type Code NEXT_HOP
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800291 legacyNlri.nextHop4 =
292 parseAttributeTypeNextHop(bgpSession, ctx,
293 attrTypeCode, attrLen,
294 attrFlags, message);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800295 break;
296
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800297 case Update.MultiExitDisc.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800298 // Attribute Type Code MULTI_EXIT_DISC
299 multiExitDisc =
300 parseAttributeTypeMultiExitDisc(bgpSession, ctx,
301 attrTypeCode, attrLen,
302 attrFlags, message);
303 break;
304
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800305 case Update.LocalPref.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800306 // Attribute Type Code LOCAL_PREF
307 localPref =
308 parseAttributeTypeLocalPref(bgpSession, ctx,
309 attrTypeCode, attrLen,
310 attrFlags, message);
311 break;
312
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800313 case Update.AtomicAggregate.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800314 // Attribute Type Code ATOMIC_AGGREGATE
315 parseAttributeTypeAtomicAggregate(bgpSession, ctx,
316 attrTypeCode, attrLen,
317 attrFlags, message);
318 // Nothing to do: this attribute is primarily informational
319 break;
320
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800321 case Update.Aggregator.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800322 // Attribute Type Code AGGREGATOR
323 Pair<Long, Ip4Address> aggregator =
324 parseAttributeTypeAggregator(bgpSession, ctx,
325 attrTypeCode, attrLen,
326 attrFlags, message);
327 aggregatorAsNumber = aggregator.getLeft();
328 aggregatorIpAddress = aggregator.getRight();
329 break;
330
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800331 case Update.MpReachNlri.TYPE:
332 // Attribute Type Code MP_REACH_NLRI
333 MpNlri mpNlriReach =
334 parseAttributeTypeMpReachNlri(bgpSession, ctx,
335 attrTypeCode,
336 attrLen,
337 attrFlags, message);
338 if (mpNlriReach != null) {
339 mpNlriReachList.add(mpNlriReach);
340 }
341 break;
342
343 case Update.MpUnreachNlri.TYPE:
344 // Attribute Type Code MP_UNREACH_NLRI
345 MpNlri mpNlriUnreach =
346 parseAttributeTypeMpUnreachNlri(bgpSession, ctx,
347 attrTypeCode, attrLen,
348 attrFlags, message);
349 if (mpNlriUnreach != null) {
350 mpNlriUnreachList.add(mpNlriUnreach);
351 }
352 break;
353
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800354 default:
355 // NOTE: Parse any new Attribute Types if needed
356 if (!optionalBit) {
357 // ERROR: Unrecognized Well-known Attribute
358 actionsBgpUpdateUnrecognizedWellKnownAttribute(
359 bgpSession, ctx, attrTypeCode, attrLen, attrFlags,
360 message);
361 String errorMsg = "Unrecognized Well-known Attribute: " +
362 attrTypeCode;
363 throw new BgpParseException(errorMsg);
364 }
365
366 // Skip the data from the unrecognized attribute
367 log.debug("BGP RX UPDATE message from {}: " +
368 "Unrecognized Attribute Type {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800369 bgpSession.remoteInfo().address(), attrTypeCode);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800370 message.skipBytes(attrLen);
371 break;
372 }
373 }
374
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800375 //
376 // Parse the NLRI (Network Layer Reachability Information)
377 //
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800378 int nlriLength = message.readableBytes();
379 try {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800380 Collection<Ip4Prefix> addedPrefixes4 =
381 parsePackedIp4Prefixes(nlriLength, message);
382 // Store it inside the legacy NLRI wrapper
383 legacyNlri.nlri4 = addedPrefixes4;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800384 } catch (BgpParseException e) {
385 // ERROR: Invalid Network Field
386 log.debug("Exception parsing NLRI from BGP peer {}: ",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800387 bgpSession.remoteInfo().bgpId(), e);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800388 actionsBgpUpdateInvalidNetworkField(bgpSession, ctx);
389 // Rethrow the exception
390 throw e;
391 }
392
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800393 // Verify the Well-known Attributes
394 verifyBgpUpdateWellKnownAttributes(bgpSession, ctx, origin, asPath,
395 localPref, legacyNlri,
396 mpNlriReachList);
397
398 //
399 // Generate the deleted routes
400 //
401 for (MpNlri mpNlri : mpNlriUnreachList) {
402 BgpRouteEntry bgpRouteEntry;
403
404 // The deleted IPv4 routes
405 for (Ip4Prefix prefix : mpNlri.nlri4) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800406 bgpRouteEntry = bgpSession.findBgpRoute(prefix);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800407 if (bgpRouteEntry != null) {
408 decodedBgpRoutes.deletedUnicastRoutes4.put(prefix,
409 bgpRouteEntry);
410 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800411 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800412
413 // The deleted IPv6 routes
414 for (Ip6Prefix prefix : mpNlri.nlri6) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800415 bgpRouteEntry = bgpSession.findBgpRoute(prefix);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800416 if (bgpRouteEntry != null) {
417 decodedBgpRoutes.deletedUnicastRoutes6.put(prefix,
418 bgpRouteEntry);
419 }
420 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800421 }
422
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800423 //
424 // Generate the added routes
425 //
426 mpNlriReachList.add(legacyNlri);
427 for (MpNlri mpNlri : mpNlriReachList) {
428 BgpRouteEntry bgpRouteEntry;
429
430 // The added IPv4 routes
431 for (Ip4Prefix prefix : mpNlri.nlri4) {
432 bgpRouteEntry =
433 new BgpRouteEntry(bgpSession, prefix, mpNlri.nextHop4,
434 origin.byteValue(), asPath, localPref);
435 bgpRouteEntry.setMultiExitDisc(multiExitDisc);
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800436 if (bgpRouteEntry.hasAsPathLoop(bgpSession.localInfo().asNumber())) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800437 log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
438 "nextHop {}: contains AS Path loop",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800439 bgpSession.remoteInfo().address(), prefix,
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800440 mpNlri.nextHop4);
441 continue;
442 } else {
443 log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800444 bgpSession.remoteInfo().address(), prefix,
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800445 mpNlri.nextHop4);
446 }
447 // Remove from the collection of deleted routes
448 decodedBgpRoutes.deletedUnicastRoutes4.remove(prefix);
449 decodedBgpRoutes.addedUnicastRoutes4.put(prefix,
450 bgpRouteEntry);
451 }
452
453 // The added IPv6 routes
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800454 for (Ip6Prefix prefix : mpNlri.nlri6) {
455 bgpRouteEntry =
456 new BgpRouteEntry(bgpSession, prefix, mpNlri.nextHop6,
457 origin.byteValue(), asPath, localPref);
458 bgpRouteEntry.setMultiExitDisc(multiExitDisc);
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800459 if (bgpRouteEntry.hasAsPathLoop(bgpSession.localInfo().asNumber())) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800460 log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
461 "nextHop {}: contains AS Path loop",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800462 bgpSession.remoteInfo().address(), prefix,
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800463 mpNlri.nextHop6);
464 continue;
465 } else {
466 log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800467 bgpSession.remoteInfo().address(), prefix,
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800468 mpNlri.nextHop6);
469 }
470 // Remove from the collection of deleted routes
471 decodedBgpRoutes.deletedUnicastRoutes6.remove(prefix);
472 decodedBgpRoutes.addedUnicastRoutes6.put(prefix,
473 bgpRouteEntry);
474 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800475 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800476 }
477
478 /**
479 * Verifies BGP UPDATE Well-known Attributes.
480 *
481 * @param bgpSession the BGP Session to use
482 * @param ctx the Channel Handler Context
483 * @param origin the ORIGIN well-known mandatory attribute
484 * @param asPath the AS_PATH well-known mandatory attribute
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800485 * @param localPref the LOCAL_PREF required attribute
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800486 * @param legacyNlri the legacy NLRI. Encapsulates the NEXT_HOP well-known
487 * mandatory attribute (mandatory if legacy NLRI is used).
488 * @param mpNlriReachList the Multiprotocol NLRI attributes
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800489 * @throws BgpParseException
490 */
491 private static void verifyBgpUpdateWellKnownAttributes(
492 BgpSession bgpSession,
493 ChannelHandlerContext ctx,
494 Short origin,
495 BgpRouteEntry.AsPath asPath,
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800496 Long localPref,
497 MpNlri legacyNlri,
498 Collection<MpNlri> mpNlriReachList)
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800499 throws BgpParseException {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800500 boolean hasNlri = false;
501 boolean hasLegacyNlri = false;
502
503 //
504 // Convenience flags that are used to check for missing attributes.
505 //
506 // NOTE: The hasLegacyNlri flag is always set to true if the
507 // Multiprotocol Extensions are not enabled, even if the UPDATE
508 // message doesn't contain the legacy NLRI (per RFC 4271).
509 //
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800510 if (!bgpSession.mpExtensions()) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800511 hasNlri = true;
512 hasLegacyNlri = true;
513 } else {
514 if (!legacyNlri.nlri4.isEmpty()) {
515 hasNlri = true;
516 hasLegacyNlri = true;
517 }
518 if (!mpNlriReachList.isEmpty()) {
519 hasNlri = true;
520 }
521 }
522
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800523 //
524 // Check for Missing Well-known Attributes
525 //
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800526 if (hasNlri && ((origin == null) || (origin == -1))) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800527 // Missing Attribute Type Code ORIGIN
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800528 int type = Update.Origin.TYPE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800529 actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
530 String errorMsg = "Missing Well-known Attribute: ORIGIN";
531 throw new BgpParseException(errorMsg);
532 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800533 if (hasNlri && (asPath == null)) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800534 // Missing Attribute Type Code AS_PATH
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800535 int type = Update.AsPath.TYPE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800536 actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
537 String errorMsg = "Missing Well-known Attribute: AS_PATH";
538 throw new BgpParseException(errorMsg);
539 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800540 if (hasNlri && (localPref == null)) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800541 // Missing Attribute Type Code LOCAL_PREF
542 // NOTE: Required for iBGP
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800543 int type = Update.LocalPref.TYPE;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800544 actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
545 String errorMsg = "Missing Well-known Attribute: LOCAL_PREF";
546 throw new BgpParseException(errorMsg);
547 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800548 if (hasLegacyNlri && (legacyNlri.nextHop4 == null)) {
549 // Missing Attribute Type Code NEXT_HOP
550 int type = Update.NextHop.TYPE;
551 actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
552 String errorMsg = "Missing Well-known Attribute: NEXT_HOP";
553 throw new BgpParseException(errorMsg);
554 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800555 }
556
557 /**
558 * Verifies the BGP UPDATE Attribute Flags.
559 *
560 * @param bgpSession the BGP Session to use
561 * @param ctx the Channel Handler Context
562 * @param attrTypeCode the attribute type code
563 * @param attrLen the attribute length (in octets)
564 * @param attrFlags the attribute flags
565 * @param message the message to parse
566 * @throws BgpParseException
567 */
568 private static void verifyBgpUpdateAttributeFlags(
569 BgpSession bgpSession,
570 ChannelHandlerContext ctx,
571 int attrTypeCode,
572 int attrLen,
573 int attrFlags,
574 ChannelBuffer message)
575 throws BgpParseException {
576
577 //
578 // Assign the Attribute Type Name and the Well-known flag
579 //
580 String typeName = "UNKNOWN";
581 boolean isWellKnown = false;
582 switch (attrTypeCode) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800583 case Update.Origin.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800584 isWellKnown = true;
585 typeName = "ORIGIN";
586 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800587 case Update.AsPath.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800588 isWellKnown = true;
589 typeName = "AS_PATH";
590 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800591 case Update.NextHop.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800592 isWellKnown = true;
593 typeName = "NEXT_HOP";
594 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800595 case Update.MultiExitDisc.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800596 isWellKnown = false;
597 typeName = "MULTI_EXIT_DISC";
598 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800599 case Update.LocalPref.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800600 isWellKnown = true;
601 typeName = "LOCAL_PREF";
602 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800603 case Update.AtomicAggregate.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800604 isWellKnown = true;
605 typeName = "ATOMIC_AGGREGATE";
606 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800607 case Update.Aggregator.TYPE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800608 isWellKnown = false;
609 typeName = "AGGREGATOR";
610 break;
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800611 case Update.MpReachNlri.TYPE:
612 isWellKnown = false;
613 typeName = "MP_REACH_NLRI";
614 break;
615 case Update.MpUnreachNlri.TYPE:
616 isWellKnown = false;
617 typeName = "MP_UNREACH_NLRI";
618 break;
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800619 default:
620 isWellKnown = false;
621 typeName = "UNKNOWN(" + attrTypeCode + ")";
622 break;
623 }
624
625 //
626 // Verify the Attribute Flags
627 //
628 boolean optionalBit = ((0x80 & attrFlags) != 0);
629 boolean transitiveBit = ((0x40 & attrFlags) != 0);
630 boolean partialBit = ((0x20 & attrFlags) != 0);
631 if ((isWellKnown && optionalBit) ||
632 (isWellKnown && (!transitiveBit)) ||
633 (isWellKnown && partialBit) ||
634 (optionalBit && (!transitiveBit) && partialBit)) {
635 //
636 // ERROR: The Optional bit cannot be set for Well-known attributes
637 // ERROR: The Transtive bit MUST be 1 for well-known attributes
638 // ERROR: The Partial bit MUST be 0 for well-known attributes
639 // ERROR: The Partial bit MUST be 0 for optional non-transitive
640 // attributes
641 //
642 actionsBgpUpdateAttributeFlagsError(
643 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
644 String errorMsg = "Attribute Flags Error for " + typeName + ": " +
645 attrFlags;
646 throw new BgpParseException(errorMsg);
647 }
648 }
649
650 /**
651 * Parses BGP UPDATE Attribute Type ORIGIN.
652 *
653 * @param bgpSession the BGP Session to use
654 * @param ctx the Channel Handler Context
655 * @param attrTypeCode the attribute type code
656 * @param attrLen the attribute length (in octets)
657 * @param attrFlags the attribute flags
658 * @param message the message to parse
659 * @return the parsed ORIGIN value
660 * @throws BgpParseException
661 */
662 private static short parseAttributeTypeOrigin(
663 BgpSession bgpSession,
664 ChannelHandlerContext ctx,
665 int attrTypeCode,
666 int attrLen,
667 int attrFlags,
668 ChannelBuffer message)
669 throws BgpParseException {
670
671 // Check the Attribute Length
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800672 if (attrLen != Update.Origin.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800673 // ERROR: Attribute Length Error
674 actionsBgpUpdateAttributeLengthError(
675 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
676 String errorMsg = "Attribute Length Error";
677 throw new BgpParseException(errorMsg);
678 }
679
680 message.markReaderIndex();
681 short origin = message.readUnsignedByte();
682 switch (origin) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800683 case Update.Origin.IGP:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800684 // FALLTHROUGH
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800685 case Update.Origin.EGP:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800686 // FALLTHROUGH
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800687 case Update.Origin.INCOMPLETE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800688 break;
689 default:
690 // ERROR: Invalid ORIGIN Attribute
691 message.resetReaderIndex();
692 actionsBgpUpdateInvalidOriginAttribute(
693 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message,
694 origin);
695 String errorMsg = "Invalid ORIGIN Attribute: " + origin;
696 throw new BgpParseException(errorMsg);
697 }
698
699 return origin;
700 }
701
702 /**
703 * Parses BGP UPDATE Attribute AS Path.
704 *
705 * @param bgpSession the BGP Session to use
706 * @param ctx the Channel Handler Context
707 * @param attrTypeCode the attribute type code
708 * @param attrLen the attribute length (in octets)
709 * @param attrFlags the attribute flags
710 * @param message the message to parse
711 * @return the parsed AS Path
712 * @throws BgpParseException
713 */
714 private static BgpRouteEntry.AsPath parseAttributeTypeAsPath(
715 BgpSession bgpSession,
716 ChannelHandlerContext ctx,
717 int attrTypeCode,
718 int attrLen,
719 int attrFlags,
720 ChannelBuffer message)
721 throws BgpParseException {
722 ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
723
724 //
725 // Parse the message
726 //
727 while (attrLen > 0) {
728 if (attrLen < 2) {
729 // ERROR: Malformed AS_PATH
730 actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
731 String errorMsg = "Malformed AS Path";
732 throw new BgpParseException(errorMsg);
733 }
734 // Get the Path Segment Type and Length (in number of ASes)
735 short pathSegmentType = message.readUnsignedByte();
736 short pathSegmentLength = message.readUnsignedByte();
737 attrLen -= 2;
738
739 // Verify the Path Segment Type
740 switch (pathSegmentType) {
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800741 case Update.AsPath.AS_SET:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800742 // FALLTHROUGH
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800743 case Update.AsPath.AS_SEQUENCE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800744 // FALLTHROUGH
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800745 case Update.AsPath.AS_CONFED_SEQUENCE:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800746 // FALLTHROUGH
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800747 case Update.AsPath.AS_CONFED_SET:
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800748 break;
749 default:
750 // ERROR: Invalid Path Segment Type
751 //
752 // NOTE: The BGP Spec (RFC 4271) doesn't contain Error Subcode
753 // for "Invalid Path Segment Type", hence we return
754 // the error as "Malformed AS_PATH".
755 //
756 actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
757 String errorMsg =
758 "Invalid AS Path Segment Type: " + pathSegmentType;
759 throw new BgpParseException(errorMsg);
760 }
761
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900762 // 4-octet AS number handling.
763 int asPathLen;
764 if (bgpSession.isAs4OctetCapable()) {
765 asPathLen = AsPath.AS_4OCTET_LENGTH;
766 } else {
767 asPathLen = AsPath.AS_LENGTH;
768 }
769
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800770 // Parse the AS numbers
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900771 if (asPathLen * pathSegmentLength > attrLen) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800772 // ERROR: Malformed AS_PATH
773 actionsBgpUpdateMalformedAsPath(bgpSession, ctx);
774 String errorMsg = "Malformed AS Path";
775 throw new BgpParseException(errorMsg);
776 }
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900777 attrLen -= (asPathLen * pathSegmentLength);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800778 ArrayList<Long> segmentAsNumbers = new ArrayList<>();
779 while (pathSegmentLength-- > 0) {
Kunihiro Ishiguro923d9d82014-12-21 15:47:28 +0900780 long asNumber;
781 if (asPathLen == AsPath.AS_4OCTET_LENGTH) {
782 asNumber = message.readUnsignedInt();
783 } else {
784 asNumber = message.readUnsignedShort();
785 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800786 segmentAsNumbers.add(asNumber);
787 }
788
789 BgpRouteEntry.PathSegment pathSegment =
790 new BgpRouteEntry.PathSegment((byte) pathSegmentType,
791 segmentAsNumbers);
792 pathSegments.add(pathSegment);
793 }
794
795 return new BgpRouteEntry.AsPath(pathSegments);
796 }
797
798 /**
799 * Parses BGP UPDATE Attribute Type NEXT_HOP.
800 *
801 * @param bgpSession the BGP Session to use
802 * @param ctx the Channel Handler Context
803 * @param attrTypeCode the attribute type code
804 * @param attrLen the attribute length (in octets)
805 * @param attrFlags the attribute flags
806 * @param message the message to parse
807 * @return the parsed NEXT_HOP value
808 * @throws BgpParseException
809 */
810 private static Ip4Address parseAttributeTypeNextHop(
811 BgpSession bgpSession,
812 ChannelHandlerContext ctx,
813 int attrTypeCode,
814 int attrLen,
815 int attrFlags,
816 ChannelBuffer message)
817 throws BgpParseException {
818
819 // Check the Attribute Length
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800820 if (attrLen != Update.NextHop.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800821 // ERROR: Attribute Length Error
822 actionsBgpUpdateAttributeLengthError(
823 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
824 String errorMsg = "Attribute Length Error";
825 throw new BgpParseException(errorMsg);
826 }
827
828 message.markReaderIndex();
829 Ip4Address nextHopAddress =
830 Ip4Address.valueOf((int) message.readUnsignedInt());
831 //
832 // Check whether the NEXT_HOP IP address is semantically correct.
833 // As per RFC 4271, Section 6.3:
834 //
835 // a) It MUST NOT be the IP address of the receiving speaker
836 // b) In the case of an EBGP ....
837 //
838 // Here we check only (a), because (b) doesn't apply for us: all our
839 // peers are iBGP.
840 //
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800841 if (nextHopAddress.equals(bgpSession.localInfo().ip4Address())) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800842 // ERROR: Invalid NEXT_HOP Attribute
843 message.resetReaderIndex();
844 actionsBgpUpdateInvalidNextHopAttribute(
845 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message,
846 nextHopAddress);
847 String errorMsg = "Invalid NEXT_HOP Attribute: " + nextHopAddress;
848 throw new BgpParseException(errorMsg);
849 }
850
851 return nextHopAddress;
852 }
853
854 /**
855 * Parses BGP UPDATE Attribute Type MULTI_EXIT_DISC.
856 *
857 * @param bgpSession the BGP Session to use
858 * @param ctx the Channel Handler Context
859 * @param attrTypeCode the attribute type code
860 * @param attrLen the attribute length (in octets)
861 * @param attrFlags the attribute flags
862 * @param message the message to parse
863 * @return the parsed MULTI_EXIT_DISC value
864 * @throws BgpParseException
865 */
866 private static long parseAttributeTypeMultiExitDisc(
867 BgpSession bgpSession,
868 ChannelHandlerContext ctx,
869 int attrTypeCode,
870 int attrLen,
871 int attrFlags,
872 ChannelBuffer message)
873 throws BgpParseException {
874
875 // Check the Attribute Length
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800876 if (attrLen != Update.MultiExitDisc.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800877 // ERROR: Attribute Length Error
878 actionsBgpUpdateAttributeLengthError(
879 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
880 String errorMsg = "Attribute Length Error";
881 throw new BgpParseException(errorMsg);
882 }
883
884 long multiExitDisc = message.readUnsignedInt();
885 return multiExitDisc;
886 }
887
888 /**
889 * Parses BGP UPDATE Attribute Type LOCAL_PREF.
890 *
891 * @param bgpSession the BGP Session to use
892 * @param ctx the Channel Handler Context
893 * @param attrTypeCode the attribute type code
894 * @param attrLen the attribute length (in octets)
895 * @param attrFlags the attribute flags
896 * @param message the message to parse
897 * @return the parsed LOCAL_PREF value
898 * @throws BgpParseException
899 */
900 private static long parseAttributeTypeLocalPref(
901 BgpSession bgpSession,
902 ChannelHandlerContext ctx,
903 int attrTypeCode,
904 int attrLen,
905 int attrFlags,
906 ChannelBuffer message)
907 throws BgpParseException {
908
909 // Check the Attribute Length
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800910 if (attrLen != Update.LocalPref.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800911 // ERROR: Attribute Length Error
912 actionsBgpUpdateAttributeLengthError(
913 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
914 String errorMsg = "Attribute Length Error";
915 throw new BgpParseException(errorMsg);
916 }
917
918 long localPref = message.readUnsignedInt();
919 return localPref;
920 }
921
922 /**
923 * Parses BGP UPDATE Attribute Type ATOMIC_AGGREGATE.
924 *
925 * @param bgpSession the BGP Session to use
926 * @param ctx the Channel Handler Context
927 * @param attrTypeCode the attribute type code
928 * @param attrLen the attribute length (in octets)
929 * @param attrFlags the attribute flags
930 * @param message the message to parse
931 * @throws BgpParseException
932 */
933 private static void parseAttributeTypeAtomicAggregate(
934 BgpSession bgpSession,
935 ChannelHandlerContext ctx,
936 int attrTypeCode,
937 int attrLen,
938 int attrFlags,
939 ChannelBuffer message)
940 throws BgpParseException {
941
942 // Check the Attribute Length
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800943 if (attrLen != Update.AtomicAggregate.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800944 // ERROR: Attribute Length Error
945 actionsBgpUpdateAttributeLengthError(
946 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
947 String errorMsg = "Attribute Length Error";
948 throw new BgpParseException(errorMsg);
949 }
950
951 // Nothing to do: this attribute is primarily informational
952 }
953
954 /**
955 * Parses BGP UPDATE Attribute Type AGGREGATOR.
956 *
957 * @param bgpSession the BGP Session to use
958 * @param ctx the Channel Handler Context
959 * @param attrTypeCode the attribute type code
960 * @param attrLen the attribute length (in octets)
961 * @param attrFlags the attribute flags
962 * @param message the message to parse
963 * @return the parsed AGGREGATOR value: a tuple of <AS-Number, IP-Address>
964 * @throws BgpParseException
965 */
966 private static Pair<Long, Ip4Address> parseAttributeTypeAggregator(
967 BgpSession bgpSession,
968 ChannelHandlerContext ctx,
969 int attrTypeCode,
970 int attrLen,
971 int attrFlags,
972 ChannelBuffer message)
973 throws BgpParseException {
974
975 // Check the Attribute Length
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800976 if (attrLen != Update.Aggregator.LENGTH) {
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -0800977 // ERROR: Attribute Length Error
978 actionsBgpUpdateAttributeLengthError(
979 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
980 String errorMsg = "Attribute Length Error";
981 throw new BgpParseException(errorMsg);
982 }
983
984 // The AGGREGATOR AS number
985 long aggregatorAsNumber = message.readUnsignedShort();
986 // The AGGREGATOR IP address
987 Ip4Address aggregatorIpAddress =
988 Ip4Address.valueOf((int) message.readUnsignedInt());
989
990 Pair<Long, Ip4Address> aggregator = Pair.of(aggregatorAsNumber,
991 aggregatorIpAddress);
992 return aggregator;
993 }
994
995 /**
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -0800996 * Parses BGP UPDATE Attribute Type MP_REACH_NLRI.
997 *
998 * @param bgpSession the BGP Session to use
999 * @param ctx the Channel Handler Context
1000 * @param attrTypeCode the attribute type code
1001 * @param attrLen the attribute length (in octets)
1002 * @param attrFlags the attribute flags
1003 * @param message the message to parse
1004 * @return the parsed MP_REACH_NLRI information if recognized, otherwise
1005 * null
1006 * @throws BgpParseException
1007 */
1008 private static MpNlri parseAttributeTypeMpReachNlri(
1009 BgpSession bgpSession,
1010 ChannelHandlerContext ctx,
1011 int attrTypeCode,
1012 int attrLen,
1013 int attrFlags,
1014 ChannelBuffer message)
1015 throws BgpParseException {
1016 int attributeEnd = message.readerIndex() + attrLen;
1017
1018 // Check the Attribute Length
1019 if (attrLen < Update.MpReachNlri.MIN_LENGTH) {
1020 // ERROR: Attribute Length Error
1021 actionsBgpUpdateAttributeLengthError(
1022 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1023 String errorMsg = "Attribute Length Error";
1024 throw new BgpParseException(errorMsg);
1025 }
1026
1027 message.markReaderIndex();
1028 int afi = message.readUnsignedShort();
1029 int safi = message.readUnsignedByte();
1030 int nextHopLen = message.readUnsignedByte();
1031
1032 //
1033 // Verify the AFI/SAFI, and skip the attribute if not recognized.
1034 // NOTE: Currently, we support only IPv4/IPv6 UNICAST
1035 //
1036 if (((afi != MultiprotocolExtensions.AFI_IPV4) &&
1037 (afi != MultiprotocolExtensions.AFI_IPV6)) ||
1038 (safi != MultiprotocolExtensions.SAFI_UNICAST)) {
1039 // Skip the attribute
1040 message.resetReaderIndex();
1041 message.skipBytes(attrLen);
1042 return null;
1043 }
1044
1045 //
1046 // Verify the next-hop length
1047 //
1048 int expectedNextHopLen = 0;
1049 switch (afi) {
1050 case MultiprotocolExtensions.AFI_IPV4:
1051 expectedNextHopLen = Ip4Address.BYTE_LENGTH;
1052 break;
1053 case MultiprotocolExtensions.AFI_IPV6:
1054 expectedNextHopLen = Ip6Address.BYTE_LENGTH;
1055 break;
1056 default:
1057 // UNREACHABLE
1058 break;
1059 }
1060 if (nextHopLen != expectedNextHopLen) {
1061 // ERROR: Optional Attribute Error
1062 message.resetReaderIndex();
1063 actionsBgpUpdateOptionalAttributeError(
1064 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1065 String errorMsg = "Invalid next-hop network address length. " +
1066 "Received " + nextHopLen + " expected " + expectedNextHopLen;
1067 throw new BgpParseException(errorMsg);
1068 }
1069 // NOTE: We use "+ 1" to take into account the Reserved field (1 octet)
1070 if (message.readerIndex() + nextHopLen + 1 >= attributeEnd) {
1071 // ERROR: Optional Attribute Error
1072 message.resetReaderIndex();
1073 actionsBgpUpdateOptionalAttributeError(
1074 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1075 String errorMsg = "Malformed next-hop network address";
1076 throw new BgpParseException(errorMsg);
1077 }
1078
1079 //
1080 // Get the Next-hop address, skip the Reserved field, and get the NLRI
1081 //
1082 byte[] nextHopBuffer = new byte[nextHopLen];
1083 message.readBytes(nextHopBuffer, 0, nextHopLen);
1084 int reserved = message.readUnsignedByte();
1085 MpNlri mpNlri = new MpNlri(afi, safi);
1086 try {
1087 switch (afi) {
1088 case MultiprotocolExtensions.AFI_IPV4:
1089 // The next-hop address
1090 mpNlri.nextHop4 = Ip4Address.valueOf(nextHopBuffer);
1091 // The NLRI
1092 mpNlri.nlri4 = parsePackedIp4Prefixes(
1093 attributeEnd - message.readerIndex(),
1094 message);
1095 break;
1096 case MultiprotocolExtensions.AFI_IPV6:
1097 // The next-hop address
1098 mpNlri.nextHop6 = Ip6Address.valueOf(nextHopBuffer);
1099 // The NLRI
1100 mpNlri.nlri6 = parsePackedIp6Prefixes(
1101 attributeEnd - message.readerIndex(),
1102 message);
1103 break;
1104 default:
1105 // UNREACHABLE
1106 break;
1107 }
1108 } catch (BgpParseException e) {
1109 // ERROR: Optional Attribute Error
1110 message.resetReaderIndex();
1111 actionsBgpUpdateOptionalAttributeError(
1112 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1113 String errorMsg = "Malformed network layer reachability information";
1114 throw new BgpParseException(errorMsg);
1115 }
1116
1117 return mpNlri;
1118 }
1119
1120 /**
1121 * Parses BGP UPDATE Attribute Type MP_UNREACH_NLRI.
1122 *
1123 * @param bgpSession the BGP Session to use
1124 * @param ctx the Channel Handler Context
1125 * @param attrTypeCode the attribute type code
1126 * @param attrLen the attribute length (in octets)
1127 * @param attrFlags the attribute flags
1128 * @param message the message to parse
1129 * @return the parsed MP_UNREACH_NLRI information if recognized, otherwise
1130 * null
1131 * @throws BgpParseException
1132 */
1133 private static MpNlri parseAttributeTypeMpUnreachNlri(
1134 BgpSession bgpSession,
1135 ChannelHandlerContext ctx,
1136 int attrTypeCode,
1137 int attrLen,
1138 int attrFlags,
1139 ChannelBuffer message)
1140 throws BgpParseException {
1141 int attributeEnd = message.readerIndex() + attrLen;
1142
1143 // Check the Attribute Length
1144 if (attrLen < Update.MpUnreachNlri.MIN_LENGTH) {
1145 // ERROR: Attribute Length Error
1146 actionsBgpUpdateAttributeLengthError(
1147 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1148 String errorMsg = "Attribute Length Error";
1149 throw new BgpParseException(errorMsg);
1150 }
1151
1152 message.markReaderIndex();
1153 int afi = message.readUnsignedShort();
1154 int safi = message.readUnsignedByte();
1155
1156 //
1157 // Verify the AFI/SAFI, and skip the attribute if not recognized.
1158 // NOTE: Currently, we support only IPv4/IPv6 UNICAST
1159 //
1160 if (((afi != MultiprotocolExtensions.AFI_IPV4) &&
1161 (afi != MultiprotocolExtensions.AFI_IPV6)) ||
1162 (safi != MultiprotocolExtensions.SAFI_UNICAST)) {
1163 // Skip the attribute
1164 message.resetReaderIndex();
1165 message.skipBytes(attrLen);
1166 return null;
1167 }
1168
1169 //
1170 // Get the Withdrawn Routes
1171 //
1172 MpNlri mpNlri = new MpNlri(afi, safi);
1173 try {
1174 switch (afi) {
1175 case MultiprotocolExtensions.AFI_IPV4:
1176 // The Withdrawn Routes
1177 mpNlri.nlri4 = parsePackedIp4Prefixes(
1178 attributeEnd - message.readerIndex(),
1179 message);
1180 break;
1181 case MultiprotocolExtensions.AFI_IPV6:
1182 // The Withdrawn Routes
1183 mpNlri.nlri6 = parsePackedIp6Prefixes(
1184 attributeEnd - message.readerIndex(),
1185 message);
1186 break;
1187 default:
1188 // UNREACHABLE
1189 break;
1190 }
1191 } catch (BgpParseException e) {
1192 // ERROR: Optional Attribute Error
1193 message.resetReaderIndex();
1194 actionsBgpUpdateOptionalAttributeError(
1195 bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
1196 String errorMsg = "Malformed withdrawn routes";
1197 throw new BgpParseException(errorMsg);
1198 }
1199
1200 return mpNlri;
1201 }
1202
1203 /**
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001204 * Parses a message that contains encoded IPv4 network prefixes.
1205 * <p>
1206 * The IPv4 prefixes are encoded in the form:
1207 * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
1208 * and Prefix is the IPv4 prefix (padded with trailing bits to the end
1209 * of an octet).
1210 *
1211 * @param totalLength the total length of the data to parse
1212 * @param message the message with data to parse
1213 * @return a collection of parsed IPv4 network prefixes
1214 * @throws BgpParseException
1215 */
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001216 private static Collection<Ip4Prefix> parsePackedIp4Prefixes(
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001217 int totalLength,
1218 ChannelBuffer message)
1219 throws BgpParseException {
1220 Collection<Ip4Prefix> result = new ArrayList<>();
1221
1222 if (totalLength == 0) {
1223 return result;
1224 }
1225
1226 // Parse the data
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001227 byte[] buffer = new byte[Ip4Address.BYTE_LENGTH];
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001228 int dataEnd = message.readerIndex() + totalLength;
1229 while (message.readerIndex() < dataEnd) {
1230 int prefixBitlen = message.readUnsignedByte();
1231 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
1232 if (message.readerIndex() + prefixBytelen > dataEnd) {
1233 String errorMsg = "Malformed Network Prefixes";
1234 throw new BgpParseException(errorMsg);
1235 }
1236
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001237 message.readBytes(buffer, 0, prefixBytelen);
1238 Ip4Prefix prefix = Ip4Prefix.valueOf(Ip4Address.valueOf(buffer),
1239 prefixBitlen);
1240 result.add(prefix);
1241 }
1242
1243 return result;
1244 }
1245
1246 /**
1247 * Parses a message that contains encoded IPv6 network prefixes.
1248 * <p>
1249 * The IPv6 prefixes are encoded in the form:
1250 * <Length, Prefix> where Length is the length in bits of the IPv6 prefix,
1251 * and Prefix is the IPv6 prefix (padded with trailing bits to the end
1252 * of an octet).
1253 *
1254 * @param totalLength the total length of the data to parse
1255 * @param message the message with data to parse
1256 * @return a collection of parsed IPv6 network prefixes
1257 * @throws BgpParseException
1258 */
1259 private static Collection<Ip6Prefix> parsePackedIp6Prefixes(
1260 int totalLength,
1261 ChannelBuffer message)
1262 throws BgpParseException {
1263 Collection<Ip6Prefix> result = new ArrayList<>();
1264
1265 if (totalLength == 0) {
1266 return result;
1267 }
1268
1269 // Parse the data
1270 byte[] buffer = new byte[Ip6Address.BYTE_LENGTH];
1271 int dataEnd = message.readerIndex() + totalLength;
1272 while (message.readerIndex() < dataEnd) {
1273 int prefixBitlen = message.readUnsignedByte();
1274 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
1275 if (message.readerIndex() + prefixBytelen > dataEnd) {
1276 String errorMsg = "Malformed Network Prefixes";
1277 throw new BgpParseException(errorMsg);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001278 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001279
1280 message.readBytes(buffer, 0, prefixBytelen);
1281 Ip6Prefix prefix = Ip6Prefix.valueOf(Ip6Address.valueOf(buffer),
1282 prefixBitlen);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001283 result.add(prefix);
1284 }
1285
1286 return result;
1287 }
1288
1289 /**
1290 * Applies the appropriate actions after detecting BGP UPDATE
1291 * Invalid Network Field Error: send NOTIFICATION and close the channel.
1292 *
1293 * @param bgpSession the BGP Session to use
1294 * @param ctx the Channel Handler Context
1295 */
1296 private static void actionsBgpUpdateInvalidNetworkField(
1297 BgpSession bgpSession,
1298 ChannelHandlerContext ctx) {
1299 log.debug("BGP RX UPDATE Error from {}: Invalid Network Field",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001300 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001301
1302 //
1303 // ERROR: Invalid Network Field
1304 //
1305 // Send NOTIFICATION and close the connection
1306 int errorCode = UpdateMessageError.ERROR_CODE;
1307 int errorSubcode = UpdateMessageError.INVALID_NETWORK_FIELD;
1308 ChannelBuffer txMessage =
1309 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1310 null);
1311 ctx.getChannel().write(txMessage);
1312 bgpSession.closeSession(ctx);
1313 }
1314
1315 /**
1316 * Applies the appropriate actions after detecting BGP UPDATE
1317 * Malformed Attribute List Error: send NOTIFICATION and close the channel.
1318 *
1319 * @param bgpSession the BGP Session to use
1320 * @param ctx the Channel Handler Context
1321 */
1322 private static void actionsBgpUpdateMalformedAttributeList(
1323 BgpSession bgpSession,
1324 ChannelHandlerContext ctx) {
1325 log.debug("BGP RX UPDATE Error from {}: Malformed Attribute List",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001326 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001327
1328 //
1329 // ERROR: Malformed Attribute List
1330 //
1331 // Send NOTIFICATION and close the connection
1332 int errorCode = UpdateMessageError.ERROR_CODE;
1333 int errorSubcode = UpdateMessageError.MALFORMED_ATTRIBUTE_LIST;
1334 ChannelBuffer txMessage =
1335 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1336 null);
1337 ctx.getChannel().write(txMessage);
1338 bgpSession.closeSession(ctx);
1339 }
1340
1341 /**
1342 * Applies the appropriate actions after detecting BGP UPDATE
1343 * Missing Well-known Attribute Error: send NOTIFICATION and close the
1344 * channel.
1345 *
1346 * @param bgpSession the BGP Session to use
1347 * @param ctx the Channel Handler Context
1348 * @param missingAttrTypeCode the missing attribute type code
1349 */
1350 private static void actionsBgpUpdateMissingWellKnownAttribute(
1351 BgpSession bgpSession,
1352 ChannelHandlerContext ctx,
1353 int missingAttrTypeCode) {
1354 log.debug("BGP RX UPDATE Error from {}: Missing Well-known Attribute: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001355 bgpSession.remoteInfo().address(), missingAttrTypeCode);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001356
1357 //
1358 // ERROR: Missing Well-known Attribute
1359 //
1360 // Send NOTIFICATION and close the connection
1361 int errorCode = UpdateMessageError.ERROR_CODE;
1362 int errorSubcode = UpdateMessageError.MISSING_WELL_KNOWN_ATTRIBUTE;
1363 ChannelBuffer data = ChannelBuffers.buffer(1);
1364 data.writeByte(missingAttrTypeCode);
1365 ChannelBuffer txMessage =
1366 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1367 data);
1368 ctx.getChannel().write(txMessage);
1369 bgpSession.closeSession(ctx);
1370 }
1371
1372 /**
1373 * Applies the appropriate actions after detecting BGP UPDATE
1374 * Invalid ORIGIN Attribute Error: send NOTIFICATION and close the channel.
1375 *
1376 * @param bgpSession the BGP Session to use
1377 * @param ctx the Channel Handler Context
1378 * @param attrTypeCode the attribute type code
1379 * @param attrLen the attribute length (in octets)
1380 * @param attrFlags the attribute flags
1381 * @param message the message with the data
1382 * @param origin the ORIGIN attribute value
1383 */
1384 private static void actionsBgpUpdateInvalidOriginAttribute(
1385 BgpSession bgpSession,
1386 ChannelHandlerContext ctx,
1387 int attrTypeCode,
1388 int attrLen,
1389 int attrFlags,
1390 ChannelBuffer message,
1391 short origin) {
1392 log.debug("BGP RX UPDATE Error from {}: Invalid ORIGIN Attribute",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001393 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001394
1395 //
1396 // ERROR: Invalid ORIGIN Attribute
1397 //
1398 // Send NOTIFICATION and close the connection
1399 int errorCode = UpdateMessageError.ERROR_CODE;
1400 int errorSubcode = UpdateMessageError.INVALID_ORIGIN_ATTRIBUTE;
1401 ChannelBuffer data =
1402 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1403 attrFlags, message);
1404 ChannelBuffer txMessage =
1405 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1406 data);
1407 ctx.getChannel().write(txMessage);
1408 bgpSession.closeSession(ctx);
1409 }
1410
1411 /**
1412 * Applies the appropriate actions after detecting BGP UPDATE
1413 * Attribute Flags Error: send NOTIFICATION and close the channel.
1414 *
1415 * @param bgpSession the BGP Session to use
1416 * @param ctx the Channel Handler Context
1417 * @param attrTypeCode the attribute type code
1418 * @param attrLen the attribute length (in octets)
1419 * @param attrFlags the attribute flags
1420 * @param message the message with the data
1421 */
1422 private static void actionsBgpUpdateAttributeFlagsError(
1423 BgpSession bgpSession,
1424 ChannelHandlerContext ctx,
1425 int attrTypeCode,
1426 int attrLen,
1427 int attrFlags,
1428 ChannelBuffer message) {
1429 log.debug("BGP RX UPDATE Error from {}: Attribute Flags Error",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001430 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001431
1432 //
1433 // ERROR: Attribute Flags Error
1434 //
1435 // Send NOTIFICATION and close the connection
1436 int errorCode = UpdateMessageError.ERROR_CODE;
1437 int errorSubcode = UpdateMessageError.ATTRIBUTE_FLAGS_ERROR;
1438 ChannelBuffer data =
1439 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1440 attrFlags, message);
1441 ChannelBuffer txMessage =
1442 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1443 data);
1444 ctx.getChannel().write(txMessage);
1445 bgpSession.closeSession(ctx);
1446 }
1447
1448 /**
1449 * Applies the appropriate actions after detecting BGP UPDATE
1450 * Invalid NEXT_HOP Attribute Error: send NOTIFICATION and close the
1451 * channel.
1452 *
1453 * @param bgpSession the BGP Session to use
1454 * @param ctx the Channel Handler Context
1455 * @param attrTypeCode the attribute type code
1456 * @param attrLen the attribute length (in octets)
1457 * @param attrFlags the attribute flags
1458 * @param message the message with the data
1459 * @param nextHop the NEXT_HOP attribute value
1460 */
1461 private static void actionsBgpUpdateInvalidNextHopAttribute(
1462 BgpSession bgpSession,
1463 ChannelHandlerContext ctx,
1464 int attrTypeCode,
1465 int attrLen,
1466 int attrFlags,
1467 ChannelBuffer message,
1468 Ip4Address nextHop) {
1469 log.debug("BGP RX UPDATE Error from {}: Invalid NEXT_HOP Attribute {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001470 bgpSession.remoteInfo().address(), nextHop);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001471
1472 //
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001473 // ERROR: Invalid NEXT_HOP Attribute
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001474 //
1475 // Send NOTIFICATION and close the connection
1476 int errorCode = UpdateMessageError.ERROR_CODE;
1477 int errorSubcode = UpdateMessageError.INVALID_NEXT_HOP_ATTRIBUTE;
1478 ChannelBuffer data =
1479 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1480 attrFlags, message);
1481 ChannelBuffer txMessage =
1482 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1483 data);
1484 ctx.getChannel().write(txMessage);
1485 bgpSession.closeSession(ctx);
1486 }
1487
1488 /**
1489 * Applies the appropriate actions after detecting BGP UPDATE
1490 * Unrecognized Well-known Attribute Error: send NOTIFICATION and close
1491 * the channel.
1492 *
1493 * @param bgpSession the BGP Session to use
1494 * @param ctx the Channel Handler Context
1495 * @param attrTypeCode the attribute type code
1496 * @param attrLen the attribute length (in octets)
1497 * @param attrFlags the attribute flags
1498 * @param message the message with the data
1499 */
1500 private static void actionsBgpUpdateUnrecognizedWellKnownAttribute(
1501 BgpSession bgpSession,
1502 ChannelHandlerContext ctx,
1503 int attrTypeCode,
1504 int attrLen,
1505 int attrFlags,
1506 ChannelBuffer message) {
1507 log.debug("BGP RX UPDATE Error from {}: " +
1508 "Unrecognized Well-known Attribute Error: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001509 bgpSession.remoteInfo().address(), attrTypeCode);
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001510
1511 //
1512 // ERROR: Unrecognized Well-known Attribute
1513 //
1514 // Send NOTIFICATION and close the connection
1515 int errorCode = UpdateMessageError.ERROR_CODE;
1516 int errorSubcode =
1517 UpdateMessageError.UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE;
1518 ChannelBuffer data =
1519 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1520 attrFlags, message);
1521 ChannelBuffer txMessage =
1522 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1523 data);
1524 ctx.getChannel().write(txMessage);
1525 bgpSession.closeSession(ctx);
1526 }
1527
1528 /**
1529 * Applies the appropriate actions after detecting BGP UPDATE
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001530 * Optional Attribute Error: send NOTIFICATION and close
1531 * the channel.
1532 *
1533 * @param bgpSession the BGP Session to use
1534 * @param ctx the Channel Handler Context
1535 * @param attrTypeCode the attribute type code
1536 * @param attrLen the attribute length (in octets)
1537 * @param attrFlags the attribute flags
1538 * @param message the message with the data
1539 */
1540 private static void actionsBgpUpdateOptionalAttributeError(
1541 BgpSession bgpSession,
1542 ChannelHandlerContext ctx,
1543 int attrTypeCode,
1544 int attrLen,
1545 int attrFlags,
1546 ChannelBuffer message) {
1547 log.debug("BGP RX UPDATE Error from {}: Optional Attribute Error: {}",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001548 bgpSession.remoteInfo().address(), attrTypeCode);
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001549
1550 //
1551 // ERROR: Optional Attribute Error
1552 //
1553 // Send NOTIFICATION and close the connection
1554 int errorCode = UpdateMessageError.ERROR_CODE;
1555 int errorSubcode =
1556 UpdateMessageError.OPTIONAL_ATTRIBUTE_ERROR;
1557 ChannelBuffer data =
1558 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1559 attrFlags, message);
1560 ChannelBuffer txMessage =
1561 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1562 data);
1563 ctx.getChannel().write(txMessage);
1564 bgpSession.closeSession(ctx);
1565 }
1566
1567 /**
1568 * Applies the appropriate actions after detecting BGP UPDATE
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001569 * Attribute Length Error: send NOTIFICATION and close the channel.
1570 *
1571 * @param bgpSession the BGP Session to use
1572 * @param ctx the Channel Handler Context
1573 * @param attrTypeCode the attribute type code
1574 * @param attrLen the attribute length (in octets)
1575 * @param attrFlags the attribute flags
1576 * @param message the message with the data
1577 */
1578 private static void actionsBgpUpdateAttributeLengthError(
1579 BgpSession bgpSession,
1580 ChannelHandlerContext ctx,
1581 int attrTypeCode,
1582 int attrLen,
1583 int attrFlags,
1584 ChannelBuffer message) {
1585 log.debug("BGP RX UPDATE Error from {}: Attribute Length Error",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001586 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001587
1588 //
1589 // ERROR: Attribute Length Error
1590 //
1591 // Send NOTIFICATION and close the connection
1592 int errorCode = UpdateMessageError.ERROR_CODE;
1593 int errorSubcode = UpdateMessageError.ATTRIBUTE_LENGTH_ERROR;
1594 ChannelBuffer data =
1595 prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
1596 attrFlags, message);
1597 ChannelBuffer txMessage =
1598 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1599 data);
1600 ctx.getChannel().write(txMessage);
1601 bgpSession.closeSession(ctx);
1602 }
1603
1604 /**
1605 * Applies the appropriate actions after detecting BGP UPDATE
1606 * Malformed AS_PATH Error: send NOTIFICATION and close the channel.
1607 *
1608 * @param bgpSession the BGP Session to use
1609 * @param ctx the Channel Handler Context
1610 */
1611 private static void actionsBgpUpdateMalformedAsPath(
1612 BgpSession bgpSession,
1613 ChannelHandlerContext ctx) {
1614 log.debug("BGP RX UPDATE Error from {}: Malformed AS Path",
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -08001615 bgpSession.remoteInfo().address());
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001616
1617 //
1618 // ERROR: Malformed AS_PATH
1619 //
1620 // Send NOTIFICATION and close the connection
1621 int errorCode = UpdateMessageError.ERROR_CODE;
1622 int errorSubcode = UpdateMessageError.MALFORMED_AS_PATH;
1623 ChannelBuffer txMessage =
1624 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
1625 null);
1626 ctx.getChannel().write(txMessage);
1627 bgpSession.closeSession(ctx);
1628 }
1629
1630 /**
1631 * Prepares BGP UPDATE Notification data payload.
1632 *
1633 * @param attrTypeCode the attribute type code
1634 * @param attrLen the attribute length (in octets)
1635 * @param attrFlags the attribute flags
1636 * @param message the message with the data
1637 * @return the buffer with the data payload for the BGP UPDATE Notification
1638 */
1639 private static ChannelBuffer prepareBgpUpdateNotificationDataPayload(
1640 int attrTypeCode,
1641 int attrLen,
1642 int attrFlags,
1643 ChannelBuffer message) {
1644 // Compute the attribute length field octets
1645 boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
1646 int attrLenOctets = 1;
1647 if (extendedLengthBit) {
1648 attrLenOctets = 2;
1649 }
1650 ChannelBuffer data =
1651 ChannelBuffers.buffer(attrLen + attrLenOctets + 1);
1652 data.writeByte(attrTypeCode);
1653 if (extendedLengthBit) {
1654 data.writeShort(attrLen);
1655 } else {
1656 data.writeByte(attrLen);
1657 }
1658 data.writeBytes(message, attrLen);
1659 return data;
1660 }
Pavlin Radoslavovc7648ee2014-12-19 16:20:33 -08001661
1662 /**
1663 * Helper class for storing Multiprotocol Network Layer Reachability
1664 * information.
1665 */
1666 private static final class MpNlri {
1667 private final int afi;
1668 private final int safi;
1669 private Ip4Address nextHop4;
1670 private Ip6Address nextHop6;
1671 private Collection<Ip4Prefix> nlri4 = new ArrayList<>();
1672 private Collection<Ip6Prefix> nlri6 = new ArrayList<>();
1673
1674 /**
1675 * Constructor.
1676 *
1677 * @param afi the Address Family Identifier
1678 * @param safi the Subsequent Address Family Identifier
1679 */
1680 private MpNlri(int afi, int safi) {
1681 this.afi = afi;
1682 this.safi = safi;
1683 }
1684 }
1685
1686 /**
1687 * Helper class for storing decoded BGP routing information.
1688 */
1689 private static final class DecodedBgpRoutes {
1690 private final Map<Ip4Prefix, BgpRouteEntry> addedUnicastRoutes4 =
1691 new HashMap<>();
1692 private final Map<Ip6Prefix, BgpRouteEntry> addedUnicastRoutes6 =
1693 new HashMap<>();
1694 private final Map<Ip4Prefix, BgpRouteEntry> deletedUnicastRoutes4 =
1695 new HashMap<>();
1696 private final Map<Ip6Prefix, BgpRouteEntry> deletedUnicastRoutes6 =
1697 new HashMap<>();
1698 }
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001699}