Refactor the BGP code in the SDN-IP application:
* Resolves ONOS-476
* Moved the BGP message-specific processing from class BgpSession
to per-message type classes: BgpKeepalive, BgpNotification,
BgpOpen, BgpUpdate
* Minor modifications in some of the methods or BGP-specific API
to accomodate the above change.
No functional changes.
Change-Id: I95df128fa31c60397a279aaca25a487b7991a6e1
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSession.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSession.java
index a60cfc8..248085b 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSession.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSession.java
@@ -18,18 +18,14 @@
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
-import org.apache.commons.lang3.tuple.Pair;
import org.jboss.netty.buffer.ChannelBuffer;
-import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
@@ -42,9 +38,6 @@
import org.onlab.packet.Ip4Prefix;
import org.onosproject.sdnip.bgp.BgpConstants.Notifications;
import org.onosproject.sdnip.bgp.BgpConstants.Notifications.HoldTimerExpired;
-import org.onosproject.sdnip.bgp.BgpConstants.Notifications.MessageHeaderError;
-import org.onosproject.sdnip.bgp.BgpConstants.Notifications.OpenMessageError;
-import org.onosproject.sdnip.bgp.BgpConstants.Notifications.UpdateMessageError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -94,6 +87,18 @@
*/
BgpSession(BgpSessionManager bgpSessionManager) {
this.bgpSessionManager = bgpSessionManager;
+
+ // NOTE: We support only BGP4
+ this.localBgpVersion = BgpConstants.BGP_VERSION;
+ }
+
+ /**
+ * Gets the BGP Session Manager.
+ *
+ * @return the BGP Session Manager
+ */
+ BgpSessionManager getBgpSessionManager() {
+ return bgpSessionManager;
}
/**
@@ -101,8 +106,8 @@
*
* @return the BGP RIB-IN routing entries
*/
- public Collection<BgpRouteEntry> getBgpRibIn() {
- return bgpRibIn.values();
+ public Map<Ip4Prefix, BgpRouteEntry> bgpRibIn() {
+ return bgpRibIn;
}
/**
@@ -143,6 +148,15 @@
}
/**
+ * Sets the BGP session remote BGP version.
+ *
+ * @param remoteBgpVersion the BGP session remote BGP version to set
+ */
+ void setRemoteBgpVersion(int remoteBgpVersion) {
+ this.remoteBgpVersion = remoteBgpVersion;
+ }
+
+ /**
* Gets the BGP session remote AS number.
*
* @return the BGP session remote AS number
@@ -152,6 +166,23 @@
}
/**
+ * Sets the BGP session remote AS number.
+ *
+ * @param remoteAs the BGP session remote AS number to set
+ */
+ void setRemoteAs(long remoteAs) {
+ this.remoteAs = remoteAs;
+
+ //
+ // NOTE: Currently, the local AS number is always set to the remote AS.
+ // This is done, because the peer setup is always iBGP.
+ // In the future the local AS number should be configured as part
+ // of an explicit BGP peering configuration.
+ //
+ this.localAs = remoteAs;
+ }
+
+ /**
* Gets the BGP session remote Holdtime.
*
* @return the BGP session remote Holdtime
@@ -161,6 +192,32 @@
}
/**
+ * Sets the BGP session remote Holdtime.
+ *
+ * @param remoteHoldtime the BGP session remote Holdtime to set
+ */
+ void setRemoteHoldtime(long remoteHoldtime) {
+ this.remoteHoldtime = remoteHoldtime;
+
+ //
+ // NOTE: Currently. the local BGP Holdtime is always set to the remote
+ // BGP holdtime.
+ // In the future, the local BGP Holdtime should be configured as part
+ // of an explicit BGP peering configuration.
+ //
+ this.localHoldtime = remoteHoldtime;
+
+ // Set the local Keepalive interval
+ if (localHoldtime == 0) {
+ localKeepaliveInterval = 0;
+ } else {
+ localKeepaliveInterval = Math.max(localHoldtime /
+ BgpConstants.BGP_KEEPALIVE_PER_HOLD_INTERVAL,
+ BgpConstants.BGP_KEEPALIVE_MIN_INTERVAL);
+ }
+ }
+
+ /**
* Gets the BGP session remote BGP Identifier as an IPv4 address.
*
* @return the BGP session remote BGP Identifier as an IPv4 address
@@ -170,6 +227,15 @@
}
/**
+ * Sets the BGP session remote BGP Identifier as an IPv4 address.
+ *
+ * @param remoteBgpId the BGP session remote BGP Identifier to set
+ */
+ void setRemoteBgpId(Ip4Address remoteBgpId) {
+ this.remoteBgpId = remoteBgpId;
+ }
+
+ /**
* Gets the BGP session local address.
*
* @return the BGP session local address
@@ -179,6 +245,15 @@
}
/**
+ * Gets the BGP session local IPv4 address.
+ *
+ * @return the BGP session local IPv4 address
+ */
+ public Ip4Address getLocalIp4Address() {
+ return localIp4Address;
+ }
+
+ /**
* Gets the BGP session local BGP version.
*
* @return the BGP session local BGP version
@@ -282,6 +357,12 @@
remoteAddress);
ctx.getChannel().close();
}
+
+ //
+ // Assign the local BGP ID
+ // NOTE: This should be configuration-based
+ //
+ localBgpId = bgpSessionManager.getMyBgpId();
}
@Override
@@ -326,1458 +407,9 @@
}
/**
- * Processes BGP OPEN message.
- *
- * @param ctx the Channel Handler Context
- * @param message the message to process
- */
- void processBgpOpen(ChannelHandlerContext ctx, ChannelBuffer message) {
- int minLength =
- BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
- if (message.readableBytes() < minLength) {
- log.debug("BGP RX OPEN Error from {}: " +
- "Message length {} too short. Must be at least {}",
- remoteAddress, message.readableBytes(), minLength);
- //
- // ERROR: Bad Message Length
- //
- // Send NOTIFICATION and close the connection
- ChannelBuffer txMessage = prepareBgpNotificationBadMessageLength(
- message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- return;
- }
-
- //
- // Parse the OPEN message
- //
- // Remote BGP version
- remoteBgpVersion = message.readUnsignedByte();
- if (remoteBgpVersion != BgpConstants.BGP_VERSION) {
- log.debug("BGP RX OPEN Error from {}: " +
- "Unsupported BGP version {}. Should be {}",
- remoteAddress, remoteBgpVersion,
- BgpConstants.BGP_VERSION);
- //
- // ERROR: Unsupported Version Number
- //
- // Send NOTIFICATION and close the connection
- int errorCode = OpenMessageError.ERROR_CODE;
- int errorSubcode = OpenMessageError.UNSUPPORTED_VERSION_NUMBER;
- ChannelBuffer data = ChannelBuffers.buffer(2);
- data.writeShort(BgpConstants.BGP_VERSION);
- ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, data);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- return;
- }
-
- // Remote AS number
- remoteAs = message.readUnsignedShort();
- //
- // Verify that the AS number is same for all other BGP Sessions
- // NOTE: This check applies only for our use-case where all BGP
- // sessions are iBGP.
- //
- for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
- if (remoteAs != bgpSession.getRemoteAs()) {
- log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
- "Expected {}",
- remoteAddress, remoteAs, bgpSession.getRemoteAs());
- //
- // ERROR: Bad Peer AS
- //
- // Send NOTIFICATION and close the connection
- int errorCode = OpenMessageError.ERROR_CODE;
- int errorSubcode = OpenMessageError.BAD_PEER_AS;
- ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, null);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- return;
- }
- }
-
- // Remote Hold Time
- remoteHoldtime = message.readUnsignedShort();
- if ((remoteHoldtime != 0) &&
- (remoteHoldtime < BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME)) {
- log.debug("BGP RX OPEN Error from {}: " +
- "Unacceptable Hold Time field {}. " +
- "Should be 0 or at least {}",
- remoteAddress, remoteHoldtime,
- BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME);
- //
- // ERROR: Unacceptable Hold Time
- //
- // Send NOTIFICATION and close the connection
- int errorCode = OpenMessageError.ERROR_CODE;
- int errorSubcode = OpenMessageError.UNACCEPTABLE_HOLD_TIME;
- ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, null);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- return;
- }
-
- // Remote BGP Identifier
- remoteBgpId = Ip4Address.valueOf((int) message.readUnsignedInt());
-
- // Optional Parameters
- int optParamLen = message.readUnsignedByte();
- if (message.readableBytes() < optParamLen) {
- log.debug("BGP RX OPEN Error from {}: " +
- "Invalid Optional Parameter Length field {}. " +
- "Remaining Optional Parameters {}",
- remoteAddress, optParamLen, message.readableBytes());
- //
- // ERROR: Invalid Optional Parameter Length field: Unspecific
- //
- // Send NOTIFICATION and close the connection
- int errorCode = OpenMessageError.ERROR_CODE;
- int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
- ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, null);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- return;
- }
- // NOTE: Parse the optional parameters (if needed)
- message.readBytes(optParamLen); // NOTE: data ignored
-
- //
- // Copy some of the remote peer's state/setup to the local setup:
- // - BGP version
- // - AS number (NOTE: the peer setup is always iBGP)
- // - Holdtime
- // Also, assign the local BGP ID based on the local setup
- //
- localBgpVersion = remoteBgpVersion;
- localAs = remoteAs;
- localHoldtime = remoteHoldtime;
- localBgpId = bgpSessionManager.getMyBgpId();
-
- // Set the Keepalive interval
- if (localHoldtime == 0) {
- localKeepaliveInterval = 0;
- } else {
- localKeepaliveInterval = Math.max(localHoldtime /
- BgpConstants.BGP_KEEPALIVE_PER_HOLD_INTERVAL,
- BgpConstants.BGP_KEEPALIVE_MIN_INTERVAL);
- }
-
- log.debug("BGP RX OPEN message from {}: " +
- "BGPv{} AS {} BGP-ID {} Holdtime {}",
- remoteAddress, remoteBgpVersion, remoteAs,
- remoteBgpId, remoteHoldtime);
-
- // Send my OPEN followed by KEEPALIVE
- ChannelBuffer txMessage = prepareBgpOpen();
- ctx.getChannel().write(txMessage);
- //
- txMessage = prepareBgpKeepalive();
- ctx.getChannel().write(txMessage);
-
- // Start the KEEPALIVE timer
- restartKeepaliveTimer(ctx);
-
- // Start the Session Timeout timer
- restartSessionTimeoutTimer(ctx);
- }
-
- /**
- * Processes BGP UPDATE message.
- *
- * @param ctx the Channel Handler Context
- * @param message the message to process
- */
- void processBgpUpdate(ChannelHandlerContext ctx, ChannelBuffer message) {
- Collection<BgpRouteEntry> addedRoutes = null;
- Map<Ip4Prefix, BgpRouteEntry> deletedRoutes = new HashMap<>();
-
- int minLength =
- BgpConstants.BGP_UPDATE_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
- if (message.readableBytes() < minLength) {
- log.debug("BGP RX UPDATE Error from {}: " +
- "Message length {} too short. Must be at least {}",
- remoteAddress, message.readableBytes(), minLength);
- //
- // ERROR: Bad Message Length
- //
- // Send NOTIFICATION and close the connection
- ChannelBuffer txMessage = prepareBgpNotificationBadMessageLength(
- message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- return;
- }
-
- log.debug("BGP RX UPDATE message from {}", remoteAddress);
-
- //
- // Parse the UPDATE message
- //
-
- //
- // Parse the Withdrawn Routes
- //
- int withdrawnRoutesLength = message.readUnsignedShort();
- if (withdrawnRoutesLength > message.readableBytes()) {
- // ERROR: Malformed Attribute List
- actionsBgpUpdateMalformedAttributeList(ctx);
- return;
- }
- Collection<Ip4Prefix> withdrawnPrefixes = null;
- try {
- withdrawnPrefixes = parsePackedPrefixes(withdrawnRoutesLength,
- message);
- } catch (BgpParseException e) {
- // ERROR: Invalid Network Field
- log.debug("Exception parsing Withdrawn Prefixes from BGP peer {}: ",
- remoteBgpId, e);
- actionsBgpUpdateInvalidNetworkField(ctx);
- return;
- }
- for (Ip4Prefix prefix : withdrawnPrefixes) {
- log.debug("BGP RX UPDATE message WITHDRAWN from {}: {}",
- remoteAddress, prefix);
- BgpRouteEntry bgpRouteEntry = bgpRibIn.get(prefix);
- if (bgpRouteEntry != null) {
- deletedRoutes.put(prefix, bgpRouteEntry);
- }
- }
-
- //
- // Parse the Path Attributes
- //
- try {
- addedRoutes = parsePathAttributes(ctx, message);
- } catch (BgpParseException e) {
- log.debug("Exception parsing Path Attributes from BGP peer {}: ",
- remoteBgpId, e);
- // NOTE: The session was already closed, so nothing else to do
- return;
- }
- // Ignore WITHDRAWN routes that are ADDED
- for (BgpRouteEntry bgpRouteEntry : addedRoutes) {
- deletedRoutes.remove(bgpRouteEntry.prefix());
- }
-
- // Update the BGP RIB-IN
- for (BgpRouteEntry bgpRouteEntry : deletedRoutes.values()) {
- bgpRibIn.remove(bgpRouteEntry.prefix());
- }
- for (BgpRouteEntry bgpRouteEntry : addedRoutes) {
- bgpRibIn.put(bgpRouteEntry.prefix(), bgpRouteEntry);
- }
-
- // Push the updates to the BGP Merged RIB
- BgpSessionManager.BgpRouteSelector bgpRouteSelector =
- bgpSessionManager.getBgpRouteSelector();
- bgpRouteSelector.routeUpdates(this, addedRoutes,
- deletedRoutes.values());
-
- // Start the Session Timeout timer
- restartSessionTimeoutTimer(ctx);
- }
-
- /**
- * Parse BGP Path Attributes from the BGP UPDATE message.
- *
- * @param ctx the Channel Handler Context
- * @param message the message to parse
- * @return a collection of the result BGP Route Entries
- * @throws BgpParseException
- */
- private Collection<BgpRouteEntry> parsePathAttributes(
- ChannelHandlerContext ctx,
- ChannelBuffer message)
- throws BgpParseException {
- Map<Ip4Prefix, BgpRouteEntry> addedRoutes = new HashMap<>();
-
- //
- // Parsed values
- //
- Short origin = -1; // Mandatory
- BgpRouteEntry.AsPath asPath = null; // Mandatory
- Ip4Address nextHop = null; // Mandatory
- long multiExitDisc = // Optional
- BgpConstants.Update.MultiExitDisc.LOWEST_MULTI_EXIT_DISC;
- Long localPref = null; // Mandatory
- Long aggregatorAsNumber = null; // Optional: unused
- Ip4Address aggregatorIpAddress = null; // Optional: unused
-
- //
- // Get and verify the Path Attributes Length
- //
- int pathAttributeLength = message.readUnsignedShort();
- if (pathAttributeLength > message.readableBytes()) {
- // ERROR: Malformed Attribute List
- actionsBgpUpdateMalformedAttributeList(ctx);
- String errorMsg = "Malformed Attribute List";
- throw new BgpParseException(errorMsg);
- }
- if (pathAttributeLength == 0) {
- return addedRoutes.values();
- }
-
- //
- // Parse the Path Attributes
- //
- int pathAttributeEnd = message.readerIndex() + pathAttributeLength;
- while (message.readerIndex() < pathAttributeEnd) {
- int attrFlags = message.readUnsignedByte();
- if (message.readerIndex() >= pathAttributeEnd) {
- // ERROR: Malformed Attribute List
- actionsBgpUpdateMalformedAttributeList(ctx);
- String errorMsg = "Malformed Attribute List";
- throw new BgpParseException(errorMsg);
- }
- int attrTypeCode = message.readUnsignedByte();
-
- // The Attribute Flags
- boolean optionalBit = ((0x80 & attrFlags) != 0);
- boolean transitiveBit = ((0x40 & attrFlags) != 0);
- boolean partialBit = ((0x20 & attrFlags) != 0);
- boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
-
- // The Attribute Length
- int attrLen = 0;
- int attrLenOctets = 1;
- if (extendedLengthBit) {
- attrLenOctets = 2;
- }
- if (message.readerIndex() + attrLenOctets > pathAttributeEnd) {
- // ERROR: Malformed Attribute List
- actionsBgpUpdateMalformedAttributeList(ctx);
- String errorMsg = "Malformed Attribute List";
- throw new BgpParseException(errorMsg);
- }
- if (extendedLengthBit) {
- attrLen = message.readUnsignedShort();
- } else {
- attrLen = message.readUnsignedByte();
- }
- if (message.readerIndex() + attrLen > pathAttributeEnd) {
- // ERROR: Malformed Attribute List
- actionsBgpUpdateMalformedAttributeList(ctx);
- String errorMsg = "Malformed Attribute List";
- throw new BgpParseException(errorMsg);
- }
-
- //
- // Verify the Attribute Flags
- //
- verifyBgpUpdateAttributeFlags(ctx, attrTypeCode, attrLen,
- attrFlags, message);
-
- //
- // Extract the Attribute Value based on the Attribute Type Code
- //
- switch (attrTypeCode) {
-
- case BgpConstants.Update.Origin.TYPE:
- // Attribute Type Code ORIGIN
- origin = parseAttributeTypeOrigin(ctx, attrTypeCode, attrLen,
- attrFlags, message);
- break;
-
- case BgpConstants.Update.AsPath.TYPE:
- // Attribute Type Code AS_PATH
- asPath = parseAttributeTypeAsPath(ctx, attrTypeCode, attrLen,
- attrFlags, message);
- break;
-
- case BgpConstants.Update.NextHop.TYPE:
- // Attribute Type Code NEXT_HOP
- nextHop = parseAttributeTypeNextHop(ctx, attrTypeCode, attrLen,
- attrFlags, message);
- break;
-
- case BgpConstants.Update.MultiExitDisc.TYPE:
- // Attribute Type Code MULTI_EXIT_DISC
- multiExitDisc =
- parseAttributeTypeMultiExitDisc(ctx, attrTypeCode, attrLen,
- attrFlags, message);
- break;
-
- case BgpConstants.Update.LocalPref.TYPE:
- // Attribute Type Code LOCAL_PREF
- localPref =
- parseAttributeTypeLocalPref(ctx, attrTypeCode, attrLen,
- attrFlags, message);
- break;
-
- case BgpConstants.Update.AtomicAggregate.TYPE:
- // Attribute Type Code ATOMIC_AGGREGATE
- parseAttributeTypeAtomicAggregate(ctx, attrTypeCode, attrLen,
- attrFlags, message);
- // Nothing to do: this attribute is primarily informational
- break;
-
- case BgpConstants.Update.Aggregator.TYPE:
- // Attribute Type Code AGGREGATOR
- Pair<Long, Ip4Address> aggregator =
- parseAttributeTypeAggregator(ctx, attrTypeCode, attrLen,
- attrFlags, message);
- aggregatorAsNumber = aggregator.getLeft();
- aggregatorIpAddress = aggregator.getRight();
- break;
-
- default:
- // NOTE: Parse any new Attribute Types if needed
- if (!optionalBit) {
- // ERROR: Unrecognized Well-known Attribute
- actionsBgpUpdateUnrecognizedWellKnownAttribute(
- ctx, attrTypeCode, attrLen, attrFlags, message);
- String errorMsg = "Unrecognized Well-known Attribute: " +
- attrTypeCode;
- throw new BgpParseException(errorMsg);
- }
-
- // Skip the data from the unrecognized attribute
- log.debug("BGP RX UPDATE message from {}: " +
- "Unrecognized Attribute Type {}",
- remoteAddress, attrTypeCode);
- message.skipBytes(attrLen);
- break;
- }
- }
-
- //
- // Verify the Well-known Attributes
- //
- verifyBgpUpdateWellKnownAttributes(ctx, origin, asPath, nextHop,
- localPref);
-
- //
- // Parse the NLRI (Network Layer Reachability Information)
- //
- Collection<Ip4Prefix> addedPrefixes = null;
- int nlriLength = message.readableBytes();
- try {
- addedPrefixes = parsePackedPrefixes(nlriLength, message);
- } catch (BgpParseException e) {
- // ERROR: Invalid Network Field
- log.debug("Exception parsing NLRI from BGP peer {}: ",
- remoteBgpId, e);
- actionsBgpUpdateInvalidNetworkField(ctx);
- // Rethrow the exception
- throw e;
- }
-
- // Generate the added routes
- for (Ip4Prefix prefix : addedPrefixes) {
- BgpRouteEntry bgpRouteEntry =
- new BgpRouteEntry(this, prefix, nextHop,
- origin.byteValue(), asPath, localPref);
- bgpRouteEntry.setMultiExitDisc(multiExitDisc);
- if (bgpRouteEntry.hasAsPathLoop(localAs)) {
- log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
- "nextHop {}: contains AS Path loop",
- remoteAddress, prefix, nextHop);
- continue;
- } else {
- log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
- remoteAddress, prefix, nextHop);
- }
- addedRoutes.put(prefix, bgpRouteEntry);
- }
-
- return addedRoutes.values();
- }
-
- /**
- * Verifies BGP UPDATE Well-known Attributes.
- *
- * @param ctx the Channel Handler Context
- * @param origin the ORIGIN well-known mandatory attribute
- * @param asPath the AS_PATH well-known mandatory attribute
- * @param nextHop the NEXT_HOP well-known mandatory attribute
- * @param localPref the LOCAL_PREF required attribute
- * @throws BgpParseException
- */
- private void verifyBgpUpdateWellKnownAttributes(
- ChannelHandlerContext ctx,
- Short origin,
- BgpRouteEntry.AsPath asPath,
- Ip4Address nextHop,
- Long localPref)
- throws BgpParseException {
- //
- // Check for Missing Well-known Attributes
- //
- if ((origin == null) || (origin == -1)) {
- // Missing Attribute Type Code ORIGIN
- int type = BgpConstants.Update.Origin.TYPE;
- actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
- String errorMsg = "Missing Well-known Attribute: ORIGIN";
- throw new BgpParseException(errorMsg);
- }
- if (asPath == null) {
- // Missing Attribute Type Code AS_PATH
- int type = BgpConstants.Update.AsPath.TYPE;
- actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
- String errorMsg = "Missing Well-known Attribute: AS_PATH";
- throw new BgpParseException(errorMsg);
- }
- if (nextHop == null) {
- // Missing Attribute Type Code NEXT_HOP
- int type = BgpConstants.Update.NextHop.TYPE;
- actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
- String errorMsg = "Missing Well-known Attribute: NEXT_HOP";
- throw new BgpParseException(errorMsg);
- }
- if (localPref == null) {
- // Missing Attribute Type Code LOCAL_PREF
- // NOTE: Required for iBGP
- int type = BgpConstants.Update.LocalPref.TYPE;
- actionsBgpUpdateMissingWellKnownAttribute(ctx, type);
- String errorMsg = "Missing Well-known Attribute: LOCAL_PREF";
- throw new BgpParseException(errorMsg);
- }
- }
-
- /**
- * Verifies the BGP UPDATE Attribute Flags.
- *
- * @param ctx the Channel Handler Context
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message to parse
- * @throws BgpParseException
- */
- private void verifyBgpUpdateAttributeFlags(
- ChannelHandlerContext ctx,
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message)
- throws BgpParseException {
-
- //
- // Assign the Attribute Type Name and the Well-known flag
- //
- String typeName = "UNKNOWN";
- boolean isWellKnown = false;
- switch (attrTypeCode) {
- case BgpConstants.Update.Origin.TYPE:
- isWellKnown = true;
- typeName = "ORIGIN";
- break;
- case BgpConstants.Update.AsPath.TYPE:
- isWellKnown = true;
- typeName = "AS_PATH";
- break;
- case BgpConstants.Update.NextHop.TYPE:
- isWellKnown = true;
- typeName = "NEXT_HOP";
- break;
- case BgpConstants.Update.MultiExitDisc.TYPE:
- isWellKnown = false;
- typeName = "MULTI_EXIT_DISC";
- break;
- case BgpConstants.Update.LocalPref.TYPE:
- isWellKnown = true;
- typeName = "LOCAL_PREF";
- break;
- case BgpConstants.Update.AtomicAggregate.TYPE:
- isWellKnown = true;
- typeName = "ATOMIC_AGGREGATE";
- break;
- case BgpConstants.Update.Aggregator.TYPE:
- isWellKnown = false;
- typeName = "AGGREGATOR";
- break;
- default:
- isWellKnown = false;
- typeName = "UNKNOWN(" + attrTypeCode + ")";
- break;
- }
-
- //
- // Verify the Attribute Flags
- //
- boolean optionalBit = ((0x80 & attrFlags) != 0);
- boolean transitiveBit = ((0x40 & attrFlags) != 0);
- boolean partialBit = ((0x20 & attrFlags) != 0);
- if ((isWellKnown && optionalBit) ||
- (isWellKnown && (!transitiveBit)) ||
- (isWellKnown && partialBit) ||
- (optionalBit && (!transitiveBit) && partialBit)) {
- //
- // ERROR: The Optional bit cannot be set for Well-known attributes
- // ERROR: The Transtive bit MUST be 1 for well-known attributes
- // ERROR: The Partial bit MUST be 0 for well-known attributes
- // ERROR: The Partial bit MUST be 0 for optional non-transitive
- // attributes
- //
- actionsBgpUpdateAttributeFlagsError(
- ctx, attrTypeCode, attrLen, attrFlags, message);
- String errorMsg = "Attribute Flags Error for " + typeName + ": " +
- attrFlags;
- throw new BgpParseException(errorMsg);
- }
- }
-
- /**
- * Parses BGP UPDATE Attribute Type ORIGIN.
- *
- * @param ctx the Channel Handler Context
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message to parse
- * @return the parsed ORIGIN value
- * @throws BgpParseException
- */
- private short parseAttributeTypeOrigin(
- ChannelHandlerContext ctx,
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message)
- throws BgpParseException {
-
- // Check the Attribute Length
- if (attrLen != BgpConstants.Update.Origin.LENGTH) {
- // ERROR: Attribute Length Error
- actionsBgpUpdateAttributeLengthError(
- ctx, attrTypeCode, attrLen, attrFlags, message);
- String errorMsg = "Attribute Length Error";
- throw new BgpParseException(errorMsg);
- }
-
- message.markReaderIndex();
- short origin = message.readUnsignedByte();
- switch (origin) {
- case BgpConstants.Update.Origin.IGP:
- // FALLTHROUGH
- case BgpConstants.Update.Origin.EGP:
- // FALLTHROUGH
- case BgpConstants.Update.Origin.INCOMPLETE:
- break;
- default:
- // ERROR: Invalid ORIGIN Attribute
- message.resetReaderIndex();
- actionsBgpUpdateInvalidOriginAttribute(
- ctx, attrTypeCode, attrLen, attrFlags, message, origin);
- String errorMsg = "Invalid ORIGIN Attribute: " + origin;
- throw new BgpParseException(errorMsg);
- }
-
- return origin;
- }
-
- /**
- * Parses BGP UPDATE Attribute AS Path.
- *
- * @param ctx the Channel Handler Context
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message to parse
- * @return the parsed AS Path
- * @throws BgpParseException
- */
- private BgpRouteEntry.AsPath parseAttributeTypeAsPath(
- ChannelHandlerContext ctx,
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message)
- throws BgpParseException {
- ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
-
- //
- // Parse the message
- //
- while (attrLen > 0) {
- if (attrLen < 2) {
- // ERROR: Malformed AS_PATH
- actionsBgpUpdateMalformedAsPath(ctx);
- String errorMsg = "Malformed AS Path";
- throw new BgpParseException(errorMsg);
- }
- // Get the Path Segment Type and Length (in number of ASes)
- short pathSegmentType = message.readUnsignedByte();
- short pathSegmentLength = message.readUnsignedByte();
- attrLen -= 2;
-
- // Verify the Path Segment Type
- switch (pathSegmentType) {
- case BgpConstants.Update.AsPath.AS_SET:
- // FALLTHROUGH
- case BgpConstants.Update.AsPath.AS_SEQUENCE:
- // FALLTHROUGH
- case BgpConstants.Update.AsPath.AS_CONFED_SEQUENCE:
- // FALLTHROUGH
- case BgpConstants.Update.AsPath.AS_CONFED_SET:
- break;
- default:
- // ERROR: Invalid Path Segment Type
- //
- // NOTE: The BGP Spec (RFC 4271) doesn't contain Error Subcode
- // for "Invalid Path Segment Type", hence we return
- // the error as "Malformed AS_PATH".
- //
- actionsBgpUpdateMalformedAsPath(ctx);
- String errorMsg =
- "Invalid AS Path Segment Type: " + pathSegmentType;
- throw new BgpParseException(errorMsg);
- }
-
- // Parse the AS numbers
- if (2 * pathSegmentLength > attrLen) {
- // ERROR: Malformed AS_PATH
- actionsBgpUpdateMalformedAsPath(ctx);
- String errorMsg = "Malformed AS Path";
- throw new BgpParseException(errorMsg);
- }
- attrLen -= (2 * pathSegmentLength);
- ArrayList<Long> segmentAsNumbers = new ArrayList<>();
- while (pathSegmentLength-- > 0) {
- long asNumber = message.readUnsignedShort();
- segmentAsNumbers.add(asNumber);
- }
-
- BgpRouteEntry.PathSegment pathSegment =
- new BgpRouteEntry.PathSegment((byte) pathSegmentType,
- segmentAsNumbers);
- pathSegments.add(pathSegment);
- }
-
- return new BgpRouteEntry.AsPath(pathSegments);
- }
-
- /**
- * Parses BGP UPDATE Attribute Type NEXT_HOP.
- *
- * @param ctx the Channel Handler Context
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message to parse
- * @return the parsed NEXT_HOP value
- * @throws BgpParseException
- */
- private Ip4Address parseAttributeTypeNextHop(
- ChannelHandlerContext ctx,
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message)
- throws BgpParseException {
-
- // Check the Attribute Length
- if (attrLen != BgpConstants.Update.NextHop.LENGTH) {
- // ERROR: Attribute Length Error
- actionsBgpUpdateAttributeLengthError(
- ctx, attrTypeCode, attrLen, attrFlags, message);
- String errorMsg = "Attribute Length Error";
- throw new BgpParseException(errorMsg);
- }
-
- message.markReaderIndex();
- Ip4Address nextHopAddress =
- Ip4Address.valueOf((int) message.readUnsignedInt());
- //
- // Check whether the NEXT_HOP IP address is semantically correct.
- // As per RFC 4271, Section 6.3:
- //
- // a) It MUST NOT be the IP address of the receiving speaker
- // b) In the case of an EBGP ....
- //
- // Here we check only (a), because (b) doesn't apply for us: all our
- // peers are iBGP.
- //
- if (nextHopAddress.equals(localIp4Address)) {
- // ERROR: Invalid NEXT_HOP Attribute
- message.resetReaderIndex();
- actionsBgpUpdateInvalidNextHopAttribute(
- ctx, attrTypeCode, attrLen, attrFlags, message,
- nextHopAddress);
- String errorMsg = "Invalid NEXT_HOP Attribute: " + nextHopAddress;
- throw new BgpParseException(errorMsg);
- }
-
- return nextHopAddress;
- }
-
- /**
- * Parses BGP UPDATE Attribute Type MULTI_EXIT_DISC.
- *
- * @param ctx the Channel Handler Context
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message to parse
- * @return the parsed MULTI_EXIT_DISC value
- * @throws BgpParseException
- */
- private long parseAttributeTypeMultiExitDisc(
- ChannelHandlerContext ctx,
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message)
- throws BgpParseException {
-
- // Check the Attribute Length
- if (attrLen != BgpConstants.Update.MultiExitDisc.LENGTH) {
- // ERROR: Attribute Length Error
- actionsBgpUpdateAttributeLengthError(
- ctx, attrTypeCode, attrLen, attrFlags, message);
- String errorMsg = "Attribute Length Error";
- throw new BgpParseException(errorMsg);
- }
-
- long multiExitDisc = message.readUnsignedInt();
- return multiExitDisc;
- }
-
- /**
- * Parses BGP UPDATE Attribute Type LOCAL_PREF.
- *
- * @param ctx the Channel Handler Context
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message to parse
- * @return the parsed LOCAL_PREF value
- * @throws BgpParseException
- */
- private long parseAttributeTypeLocalPref(
- ChannelHandlerContext ctx,
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message)
- throws BgpParseException {
-
- // Check the Attribute Length
- if (attrLen != BgpConstants.Update.LocalPref.LENGTH) {
- // ERROR: Attribute Length Error
- actionsBgpUpdateAttributeLengthError(
- ctx, attrTypeCode, attrLen, attrFlags, message);
- String errorMsg = "Attribute Length Error";
- throw new BgpParseException(errorMsg);
- }
-
- long localPref = message.readUnsignedInt();
- return localPref;
- }
-
- /**
- * Parses BGP UPDATE Attribute Type ATOMIC_AGGREGATE.
- *
- * @param ctx the Channel Handler Context
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message to parse
- * @throws BgpParseException
- */
- private void parseAttributeTypeAtomicAggregate(
- ChannelHandlerContext ctx,
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message)
- throws BgpParseException {
-
- // Check the Attribute Length
- if (attrLen != BgpConstants.Update.AtomicAggregate.LENGTH) {
- // ERROR: Attribute Length Error
- actionsBgpUpdateAttributeLengthError(
- ctx, attrTypeCode, attrLen, attrFlags, message);
- String errorMsg = "Attribute Length Error";
- throw new BgpParseException(errorMsg);
- }
-
- // Nothing to do: this attribute is primarily informational
- }
-
- /**
- * Parses BGP UPDATE Attribute Type AGGREGATOR.
- *
- * @param ctx the Channel Handler Context
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message to parse
- * @return the parsed AGGREGATOR value: a tuple of <AS-Number, IP-Address>
- * @throws BgpParseException
- */
- private Pair<Long, Ip4Address> parseAttributeTypeAggregator(
- ChannelHandlerContext ctx,
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message)
- throws BgpParseException {
-
- // Check the Attribute Length
- if (attrLen != BgpConstants.Update.Aggregator.LENGTH) {
- // ERROR: Attribute Length Error
- actionsBgpUpdateAttributeLengthError(
- ctx, attrTypeCode, attrLen, attrFlags, message);
- String errorMsg = "Attribute Length Error";
- throw new BgpParseException(errorMsg);
- }
-
- // The AGGREGATOR AS number
- long aggregatorAsNumber = message.readUnsignedShort();
- // The AGGREGATOR IP address
- Ip4Address aggregatorIpAddress =
- Ip4Address.valueOf((int) message.readUnsignedInt());
-
- Pair<Long, Ip4Address> aggregator = Pair.of(aggregatorAsNumber,
- aggregatorIpAddress);
- return aggregator;
- }
-
- /**
- * Parses a message that contains encoded IPv4 network prefixes.
- * <p>
- * The IPv4 prefixes are encoded in the form:
- * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
- * and Prefix is the IPv4 prefix (padded with trailing bits to the end
- * of an octet).
- *
- * @param totalLength the total length of the data to parse
- * @param message the message with data to parse
- * @return a collection of parsed IPv4 network prefixes
- * @throws BgpParseException
- */
- private Collection<Ip4Prefix> parsePackedPrefixes(int totalLength,
- ChannelBuffer message)
- throws BgpParseException {
- Collection<Ip4Prefix> result = new ArrayList<>();
-
- if (totalLength == 0) {
- return result;
- }
-
- // Parse the data
- int dataEnd = message.readerIndex() + totalLength;
- while (message.readerIndex() < dataEnd) {
- int prefixBitlen = message.readUnsignedByte();
- int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
- if (message.readerIndex() + prefixBytelen > dataEnd) {
- String errorMsg = "Malformed Network Prefixes";
- throw new BgpParseException(errorMsg);
- }
-
- long address = 0;
- long extraShift = (4 - prefixBytelen) * 8;
- while (prefixBytelen > 0) {
- address <<= 8;
- address |= message.readUnsignedByte();
- prefixBytelen--;
- }
- address <<= extraShift;
- Ip4Prefix prefix =
- Ip4Prefix.valueOf(Ip4Address.valueOf((int) address),
- prefixBitlen);
- result.add(prefix);
- }
-
- return result;
- }
-
- /**
- * Applies the appropriate actions after detecting BGP UPDATE
- * Invalid Network Field Error: send NOTIFICATION and close the channel.
- *
- * @param ctx the Channel Handler Context
- */
- private void actionsBgpUpdateInvalidNetworkField(
- ChannelHandlerContext ctx) {
- log.debug("BGP RX UPDATE Error from {}: Invalid Network Field",
- remoteAddress);
-
- //
- // ERROR: Invalid Network Field
- //
- // Send NOTIFICATION and close the connection
- int errorCode = UpdateMessageError.ERROR_CODE;
- int errorSubcode = UpdateMessageError.INVALID_NETWORK_FIELD;
- ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, null);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- }
-
- /**
- * Applies the appropriate actions after detecting BGP UPDATE
- * Malformed Attribute List Error: send NOTIFICATION and close the channel.
- *
- * @param ctx the Channel Handler Context
- */
- private void actionsBgpUpdateMalformedAttributeList(
- ChannelHandlerContext ctx) {
- log.debug("BGP RX UPDATE Error from {}: Malformed Attribute List",
- remoteAddress);
-
- //
- // ERROR: Malformed Attribute List
- //
- // Send NOTIFICATION and close the connection
- int errorCode = UpdateMessageError.ERROR_CODE;
- int errorSubcode = UpdateMessageError.MALFORMED_ATTRIBUTE_LIST;
- ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, null);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- }
-
- /**
- * Applies the appropriate actions after detecting BGP UPDATE
- * Missing Well-known Attribute Error: send NOTIFICATION and close the
- * channel.
- *
- * @param ctx the Channel Handler Context
- * @param missingAttrTypeCode the missing attribute type code
- */
- private void actionsBgpUpdateMissingWellKnownAttribute(
- ChannelHandlerContext ctx,
- int missingAttrTypeCode) {
- log.debug("BGP RX UPDATE Error from {}: Missing Well-known Attribute: {}",
- remoteAddress, missingAttrTypeCode);
-
- //
- // ERROR: Missing Well-known Attribute
- //
- // Send NOTIFICATION and close the connection
- int errorCode = UpdateMessageError.ERROR_CODE;
- int errorSubcode = UpdateMessageError.MISSING_WELL_KNOWN_ATTRIBUTE;
- ChannelBuffer data = ChannelBuffers.buffer(1);
- data.writeByte(missingAttrTypeCode);
- ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, data);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- }
-
- /**
- * Applies the appropriate actions after detecting BGP UPDATE
- * Invalid ORIGIN Attribute Error: send NOTIFICATION and close the channel.
- *
- * @param ctx the Channel Handler Context
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message with the data
- * @param origin the ORIGIN attribute value
- */
- private void actionsBgpUpdateInvalidOriginAttribute(
- ChannelHandlerContext ctx,
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message,
- short origin) {
- log.debug("BGP RX UPDATE Error from {}: Invalid ORIGIN Attribute",
- remoteAddress);
-
- //
- // ERROR: Invalid ORIGIN Attribute
- //
- // Send NOTIFICATION and close the connection
- int errorCode = UpdateMessageError.ERROR_CODE;
- int errorSubcode = UpdateMessageError.INVALID_ORIGIN_ATTRIBUTE;
- ChannelBuffer data =
- prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
- attrFlags, message);
- ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, data);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- }
-
- /**
- * Applies the appropriate actions after detecting BGP UPDATE
- * Attribute Flags Error: send NOTIFICATION and close the channel.
- *
- * @param ctx the Channel Handler Context
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message with the data
- */
- private void actionsBgpUpdateAttributeFlagsError(
- ChannelHandlerContext ctx,
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message) {
- log.debug("BGP RX UPDATE Error from {}: Attribute Flags Error",
- remoteAddress);
-
- //
- // ERROR: Attribute Flags Error
- //
- // Send NOTIFICATION and close the connection
- int errorCode = UpdateMessageError.ERROR_CODE;
- int errorSubcode = UpdateMessageError.ATTRIBUTE_FLAGS_ERROR;
- ChannelBuffer data =
- prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
- attrFlags, message);
- ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, data);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- }
-
- /**
- * Applies the appropriate actions after detecting BGP UPDATE
- * Invalid NEXT_HOP Attribute Error: send NOTIFICATION and close the
- * channel.
- *
- * @param ctx the Channel Handler Context
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message with the data
- * @param nextHop the NEXT_HOP attribute value
- */
- private void actionsBgpUpdateInvalidNextHopAttribute(
- ChannelHandlerContext ctx,
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message,
- Ip4Address nextHop) {
- log.debug("BGP RX UPDATE Error from {}: Invalid NEXT_HOP Attribute {}",
- remoteAddress, nextHop);
-
- //
- // ERROR: Invalid ORIGIN Attribute
- //
- // Send NOTIFICATION and close the connection
- int errorCode = UpdateMessageError.ERROR_CODE;
- int errorSubcode = UpdateMessageError.INVALID_NEXT_HOP_ATTRIBUTE;
- ChannelBuffer data =
- prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
- attrFlags, message);
- ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, data);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- }
-
- /**
- * Applies the appropriate actions after detecting BGP UPDATE
- * Unrecognized Well-known Attribute Error: send NOTIFICATION and close
- * the channel.
- *
- * @param ctx the Channel Handler Context
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message with the data
- */
- private void actionsBgpUpdateUnrecognizedWellKnownAttribute(
- ChannelHandlerContext ctx,
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message) {
- log.debug("BGP RX UPDATE Error from {}: " +
- "Unrecognized Well-known Attribute Error: {}",
- remoteAddress, attrTypeCode);
-
- //
- // ERROR: Unrecognized Well-known Attribute
- //
- // Send NOTIFICATION and close the connection
- int errorCode = UpdateMessageError.ERROR_CODE;
- int errorSubcode =
- UpdateMessageError.UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE;
- ChannelBuffer data =
- prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
- attrFlags, message);
- ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, data);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- }
-
- /**
- * Applies the appropriate actions after detecting BGP UPDATE
- * Attribute Length Error: send NOTIFICATION and close the channel.
- *
- * @param ctx the Channel Handler Context
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message with the data
- */
- private void actionsBgpUpdateAttributeLengthError(
- ChannelHandlerContext ctx,
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message) {
- log.debug("BGP RX UPDATE Error from {}: Attribute Length Error",
- remoteAddress);
-
- //
- // ERROR: Attribute Length Error
- //
- // Send NOTIFICATION and close the connection
- int errorCode = UpdateMessageError.ERROR_CODE;
- int errorSubcode = UpdateMessageError.ATTRIBUTE_LENGTH_ERROR;
- ChannelBuffer data =
- prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
- attrFlags, message);
- ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, data);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- }
-
- /**
- * Applies the appropriate actions after detecting BGP UPDATE
- * Malformed AS_PATH Error: send NOTIFICATION and close the channel.
- *
- * @param ctx the Channel Handler Context
- */
- private void actionsBgpUpdateMalformedAsPath(
- ChannelHandlerContext ctx) {
- log.debug("BGP RX UPDATE Error from {}: Malformed AS Path",
- remoteAddress);
-
- //
- // ERROR: Malformed AS_PATH
- //
- // Send NOTIFICATION and close the connection
- int errorCode = UpdateMessageError.ERROR_CODE;
- int errorSubcode = UpdateMessageError.MALFORMED_AS_PATH;
- ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, null);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- }
-
- /**
- * Processes BGP NOTIFICATION message.
- *
- * @param ctx the Channel Handler Context
- * @param message the message to process
- */
- void processBgpNotification(ChannelHandlerContext ctx,
- ChannelBuffer message) {
- int minLength =
- BgpConstants.BGP_NOTIFICATION_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
- if (message.readableBytes() < minLength) {
- log.debug("BGP RX NOTIFICATION Error from {}: " +
- "Message length {} too short. Must be at least {}",
- remoteAddress, message.readableBytes(), minLength);
- //
- // ERROR: Bad Message Length
- //
- // NOTE: We do NOT send NOTIFICATION in response to a notification
- return;
- }
-
- //
- // Parse the NOTIFICATION message
- //
- int errorCode = message.readUnsignedByte();
- int errorSubcode = message.readUnsignedByte();
- int dataLength = message.readableBytes();
-
- log.debug("BGP RX NOTIFICATION message from {}: Error Code {} " +
- "Error Subcode {} Data Length {}",
- remoteAddress, errorCode, errorSubcode, dataLength);
-
- //
- // NOTE: If the peer sent a NOTIFICATION, we leave it to the peer to
- // close the connection.
- //
-
- // Start the Session Timeout timer
- restartSessionTimeoutTimer(ctx);
- }
-
- /**
- * Processes BGP KEEPALIVE message.
- *
- * @param ctx the Channel Handler Context
- * @param message the message to process
- */
- void processBgpKeepalive(ChannelHandlerContext ctx,
- ChannelBuffer message) {
- if (message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH !=
- BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH) {
- log.debug("BGP RX KEEPALIVE Error from {}: " +
- "Invalid total message length {}. Expected {}",
- remoteAddress,
- message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH,
- BgpConstants.BGP_KEEPALIVE_EXPECTED_LENGTH);
- //
- // ERROR: Bad Message Length
- //
- // Send NOTIFICATION and close the connection
- ChannelBuffer txMessage = prepareBgpNotificationBadMessageLength(
- message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
- ctx.getChannel().write(txMessage);
- closeSession(ctx);
- return;
- }
-
- //
- // Parse the KEEPALIVE message: nothing to do
- //
- log.trace("BGP RX KEEPALIVE message from {}", remoteAddress);
-
- // Start the Session Timeout timer
- restartSessionTimeoutTimer(ctx);
- }
-
- /**
- * Prepares BGP OPEN message.
- *
- * @return the message to transmit (BGP header included)
- */
- private ChannelBuffer prepareBgpOpen() {
- ChannelBuffer message =
- ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
-
- //
- // Prepare the OPEN message payload
- //
- message.writeByte(localBgpVersion);
- message.writeShort((int) localAs);
- message.writeShort((int) localHoldtime);
- message.writeInt(bgpSessionManager.getMyBgpId().toInt());
- message.writeByte(0); // No Optional Parameters
- return prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN, message);
- }
-
- /**
- * Prepares BGP KEEPALIVE message.
- *
- * @return the message to transmit (BGP header included)
- */
- private ChannelBuffer prepareBgpKeepalive() {
- ChannelBuffer message =
- ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
-
- //
- // Prepare the KEEPALIVE message payload: nothing to do
- //
- return prepareBgpMessage(BgpConstants.BGP_TYPE_KEEPALIVE, message);
- }
-
- /**
- * Prepares BGP NOTIFICATION message.
- *
- * @param errorCode the BGP NOTIFICATION Error Code
- * @param errorSubcode the BGP NOTIFICATION Error Subcode if applicable,
- * otherwise BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC
- * @param data the BGP NOTIFICATION Data if applicable, otherwise null
- * @return the message to transmit (BGP header included)
- */
- ChannelBuffer prepareBgpNotification(int errorCode, int errorSubcode,
- ChannelBuffer data) {
- ChannelBuffer message =
- ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
-
- //
- // Prepare the NOTIFICATION message payload
- //
- message.writeByte(errorCode);
- message.writeByte(errorSubcode);
- if (data != null) {
- message.writeBytes(data);
- }
- return prepareBgpMessage(BgpConstants.BGP_TYPE_NOTIFICATION, message);
- }
-
- /**
- * Prepares BGP NOTIFICATION message: Bad Message Length.
- *
- * @param length the erroneous Length field
- * @return the message to transmit (BGP header included)
- */
- ChannelBuffer prepareBgpNotificationBadMessageLength(int length) {
- int errorCode = MessageHeaderError.ERROR_CODE;
- int errorSubcode = MessageHeaderError.BAD_MESSAGE_LENGTH;
- ChannelBuffer data = ChannelBuffers.buffer(2);
- data.writeShort(length);
-
- return prepareBgpNotification(errorCode, errorSubcode, data);
- }
-
- /**
- * Prepares BGP UPDATE Notification data payload.
- *
- * @param attrTypeCode the attribute type code
- * @param attrLen the attribute length (in octets)
- * @param attrFlags the attribute flags
- * @param message the message with the data
- * @return the buffer with the data payload for the BGP UPDATE Notification
- */
- private ChannelBuffer prepareBgpUpdateNotificationDataPayload(
- int attrTypeCode,
- int attrLen,
- int attrFlags,
- ChannelBuffer message) {
- // Compute the attribute length field octets
- boolean extendedLengthBit = ((0x10 & attrFlags) != 0);
- int attrLenOctets = 1;
- if (extendedLengthBit) {
- attrLenOctets = 2;
- }
- ChannelBuffer data =
- ChannelBuffers.buffer(attrLen + attrLenOctets + 1);
- data.writeByte(attrTypeCode);
- if (extendedLengthBit) {
- data.writeShort(attrLen);
- } else {
- data.writeByte(attrLen);
- }
- data.writeBytes(message, attrLen);
- return data;
- }
-
- /**
- * Prepares BGP message.
- *
- * @param type the BGP message type
- * @param payload the message payload to transmit (BGP header excluded)
- * @return the message to transmit (BGP header included)
- */
- private ChannelBuffer prepareBgpMessage(int type, ChannelBuffer payload) {
- ChannelBuffer message =
- ChannelBuffers.buffer(BgpConstants.BGP_HEADER_LENGTH +
- payload.readableBytes());
-
- // Write the marker
- for (int i = 0; i < BgpConstants.BGP_HEADER_MARKER_LENGTH; i++) {
- message.writeByte(0xff);
- }
-
- // Write the rest of the BGP header
- message.writeShort(BgpConstants.BGP_HEADER_LENGTH +
- payload.readableBytes());
- message.writeByte(type);
-
- // Write the payload
- message.writeBytes(payload);
- return message;
- }
-
- /**
* Restarts the BGP KeepaliveTimer.
*/
- private void restartKeepaliveTimer(ChannelHandlerContext ctx) {
+ void restartKeepaliveTimer(ChannelHandlerContext ctx) {
if (localKeepaliveInterval == 0) {
return; // Nothing to do
}
@@ -1811,7 +443,7 @@
}
// Transmit the KEEPALIVE
- ChannelBuffer txMessage = prepareBgpKeepalive();
+ ChannelBuffer txMessage = BgpKeepalive.prepareBgpKeepalive();
ctx.getChannel().write(txMessage);
// Restart the KEEPALIVE timer
@@ -1822,7 +454,7 @@
/**
* Restarts the BGP Session Timeout Timer.
*/
- private void restartSessionTimeoutTimer(ChannelHandlerContext ctx) {
+ void restartSessionTimeoutTimer(ChannelHandlerContext ctx) {
if (remoteHoldtime == 0) {
return; // Nothing to do
}
@@ -1866,30 +498,10 @@
int errorCode = HoldTimerExpired.ERROR_CODE;
int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
ChannelBuffer txMessage =
- prepareBgpNotification(errorCode, errorSubcode, null);
+ BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
+ null);
ctx.getChannel().write(txMessage);
closeChannel(ctx);
}
}
-
- /**
- * An exception indicating a parsing error of the BGP message.
- */
- private static class BgpParseException extends Exception {
- /**
- * Default constructor.
- */
- public BgpParseException() {
- super();
- }
-
- /**
- * Constructor for a specific exception details message.
- *
- * @param message the message with the exception details
- */
- public BgpParseException(String message) {
- super(message);
- }
- }
}