aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/bgp/BgpOpen.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/bgp/BgpOpen.java')
-rw-r--r--framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/bgp/BgpOpen.java497
1 files changed, 497 insertions, 0 deletions
diff --git a/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/bgp/BgpOpen.java b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/bgp/BgpOpen.java
new file mode 100644
index 00000000..5b5a259e
--- /dev/null
+++ b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/bgp/BgpOpen.java
@@ -0,0 +1,497 @@
+/*
+ * Copyright 2014-2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.routing.bgp;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.onlab.packet.Ip4Address;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A class for handling BGP OPEN messages.
+ */
+final class BgpOpen {
+ private static final Logger log = LoggerFactory.getLogger(BgpOpen.class);
+
+ /**
+ * Default constructor.
+ * <p>
+ * The constructor is private to prevent creating an instance of
+ * this utility class.
+ */
+ private BgpOpen() {
+ }
+
+ /**
+ * Processes BGP OPEN message.
+ *
+ * @param bgpSession the BGP Session to use
+ * @param ctx the Channel Handler Context
+ * @param message the message to process
+ */
+ static void processBgpOpen(BgpSession bgpSession,
+ 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 {}",
+ bgpSession.remoteInfo().address(),
+ message.readableBytes(), minLength);
+ //
+ // ERROR: Bad Message Length
+ //
+ // Send NOTIFICATION and close the connection
+ ChannelBuffer txMessage =
+ BgpNotification.prepareBgpNotificationBadMessageLength(
+ message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
+ ctx.getChannel().write(txMessage);
+ bgpSession.closeSession(ctx);
+ return;
+ }
+
+ //
+ // Parse the OPEN message
+ //
+ // Remote BGP version
+ int remoteBgpVersion = message.readUnsignedByte();
+ if (remoteBgpVersion != BgpConstants.BGP_VERSION) {
+ log.debug("BGP RX OPEN Error from {}: " +
+ "Unsupported BGP version {}. Should be {}",
+ bgpSession.remoteInfo().address(), remoteBgpVersion,
+ BgpConstants.BGP_VERSION);
+ //
+ // ERROR: Unsupported Version Number
+ //
+ // Send NOTIFICATION and close the connection
+ int errorCode = BgpConstants.Notifications.OpenMessageError.ERROR_CODE;
+ int errorSubcode = BgpConstants.Notifications.OpenMessageError.UNSUPPORTED_VERSION_NUMBER;
+ ChannelBuffer data = ChannelBuffers.buffer(2);
+ data.writeShort(BgpConstants.BGP_VERSION);
+ ChannelBuffer txMessage =
+ BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
+ data);
+ ctx.getChannel().write(txMessage);
+ bgpSession.closeSession(ctx);
+ return;
+ }
+ bgpSession.remoteInfo().setBgpVersion(remoteBgpVersion);
+
+ // Remote AS number
+ long remoteAs = message.readUnsignedShort();
+ bgpSession.remoteInfo().setAsNumber(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.
+ //
+ bgpSession.localInfo().setAsNumber(remoteAs);
+
+ // Remote Hold Time
+ long 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 {}",
+ bgpSession.remoteInfo().address(), remoteHoldtime,
+ BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME);
+ //
+ // ERROR: Unacceptable Hold Time
+ //
+ // Send NOTIFICATION and close the connection
+ int errorCode = BgpConstants.Notifications.OpenMessageError.ERROR_CODE;
+ int errorSubcode = BgpConstants.Notifications.OpenMessageError.UNACCEPTABLE_HOLD_TIME;
+ ChannelBuffer txMessage =
+ BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
+ null);
+ ctx.getChannel().write(txMessage);
+ bgpSession.closeSession(ctx);
+ return;
+ }
+ bgpSession.remoteInfo().setHoldtime(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.
+ //
+ bgpSession.localInfo().setHoldtime(remoteHoldtime);
+
+ // Remote BGP Identifier
+ Ip4Address remoteBgpId =
+ Ip4Address.valueOf((int) message.readUnsignedInt());
+ bgpSession.remoteInfo().setBgpId(remoteBgpId);
+
+ // Parse the Optional Parameters
+ try {
+ parseOptionalParameters(bgpSession, ctx, message);
+ } catch (BgpMessage.BgpParseException e) {
+ // ERROR: Error parsing optional parameters
+ log.debug("BGP RX OPEN Error from {}: " +
+ "Exception parsing Optional Parameters: {}",
+ bgpSession.remoteInfo().address(), e);
+ //
+ // ERROR: Invalid Optional Parameters: Unspecific
+ //
+ // Send NOTIFICATION and close the connection
+ int errorCode = BgpConstants.Notifications.OpenMessageError.ERROR_CODE;
+ int errorSubcode = BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC;
+ ChannelBuffer txMessage =
+ BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
+ null);
+ ctx.getChannel().write(txMessage);
+ bgpSession.closeSession(ctx);
+ return;
+ }
+
+ //
+ // NOTE: Prepare the BGP OPEN message before the original local AS
+ // is overwritten by the 4-octet AS number
+ //
+ ChannelBuffer txOpenMessage = prepareBgpOpen(bgpSession.localInfo());
+
+ //
+ // Use the 4-octet AS number in lieu of the "My AS" field
+ // See RFC 6793, Section 4.1, second paragraph.
+ //
+ if (bgpSession.remoteInfo().as4OctetCapability()) {
+ long as4Number = bgpSession.remoteInfo().as4Number();
+ bgpSession.remoteInfo().setAsNumber(as4Number);
+ bgpSession.localInfo().setAsNumber(as4Number);
+ }
+
+ //
+ // 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 bs : bgpSession.getBgpSessionManager().getBgpSessions()) {
+ if ((bs.remoteInfo().asNumber() != 0) &&
+ (bgpSession.remoteInfo().asNumber() !=
+ bs.remoteInfo().asNumber())) {
+ log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
+ "Expected {}",
+ bgpSession.remoteInfo().address(),
+ bgpSession.remoteInfo().asNumber(),
+ bs.remoteInfo().asNumber());
+ //
+ // ERROR: Bad Peer AS
+ //
+ // Send NOTIFICATION and close the connection
+ int errorCode = BgpConstants.Notifications.OpenMessageError.ERROR_CODE;
+ int errorSubcode = BgpConstants.Notifications.OpenMessageError.BAD_PEER_AS;
+ ChannelBuffer txMessage =
+ BgpNotification.prepareBgpNotification(errorCode,
+ errorSubcode, null);
+ ctx.getChannel().write(txMessage);
+ bgpSession.closeSession(ctx);
+ return;
+ }
+ }
+
+ log.debug("BGP RX OPEN message from {}: " +
+ "BGPv{} AS {} BGP-ID {} Holdtime {}",
+ bgpSession.remoteInfo().address(),
+ bgpSession.remoteInfo().bgpVersion(),
+ bgpSession.remoteInfo().asNumber(),
+ bgpSession.remoteInfo().bgpId(),
+ bgpSession.remoteInfo().holdtime());
+
+ // Send my OPEN followed by KEEPALIVE
+ ctx.getChannel().write(txOpenMessage);
+ //
+ ChannelBuffer txMessage = BgpKeepalive.prepareBgpKeepalive();
+ ctx.getChannel().write(txMessage);
+
+ // Start the KEEPALIVE timer
+ bgpSession.restartKeepaliveTimer(ctx);
+
+ // Start the Session Timeout timer
+ bgpSession.restartSessionTimeoutTimer(ctx);
+ }
+
+ /**
+ * Prepares BGP OPEN message.
+ *
+ * @param localInfo the BGP Session local information to use
+ * @return the message to transmit (BGP header included)
+ */
+ static ChannelBuffer prepareBgpOpen(BgpSessionInfo localInfo) {
+ ChannelBuffer message =
+ ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
+
+ //
+ // Prepare the OPEN message payload
+ //
+ message.writeByte(localInfo.bgpVersion());
+ message.writeShort((int) localInfo.asNumber());
+ message.writeShort((int) localInfo.holdtime());
+ message.writeInt(localInfo.bgpId().toInt());
+
+ // Prepare the optional BGP Capabilities
+ ChannelBuffer capabilitiesMessage =
+ prepareBgpOpenCapabilities(localInfo);
+ message.writeByte(capabilitiesMessage.readableBytes());
+ message.writeBytes(capabilitiesMessage);
+
+ return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN,
+ message);
+ }
+
+ /**
+ * Parses BGP OPEN Optional Parameters.
+ *
+ * @param bgpSession the BGP Session to use
+ * @param ctx the Channel Handler Context
+ * @param message the message to process
+ * @throws BgpMessage.BgpParseException
+ */
+ private static void parseOptionalParameters(BgpSession bgpSession,
+ ChannelHandlerContext ctx,
+ ChannelBuffer message)
+ throws BgpMessage.BgpParseException {
+
+ //
+ // Get and verify the Optional Parameters Length
+ //
+ int optParamLength = message.readUnsignedByte();
+ if (optParamLength > message.readableBytes()) {
+ // ERROR: Invalid Optional Parameter Length
+ String errorMsg = "Invalid Optional Parameter Length field " +
+ optParamLength + ". Remaining Optional Parameters " +
+ message.readableBytes();
+ throw new BgpMessage.BgpParseException(errorMsg);
+ }
+ if (optParamLength == 0) {
+ return; // No Optional Parameters
+ }
+
+ //
+ // Parse the Optional Parameters
+ //
+ int optParamEnd = message.readerIndex() + optParamLength;
+ while (message.readerIndex() < optParamEnd) {
+ int paramType = message.readUnsignedByte();
+ if (message.readerIndex() >= optParamEnd) {
+ // ERROR: Malformed Optional Parameters
+ String errorMsg = "Malformed Optional Parameters";
+ throw new BgpMessage.BgpParseException(errorMsg);
+ }
+ int paramLen = message.readUnsignedByte();
+ if (message.readerIndex() + paramLen > optParamEnd) {
+ // ERROR: Malformed Optional Parameters
+ String errorMsg = "Malformed Optional Parameters";
+ throw new BgpMessage.BgpParseException(errorMsg);
+ }
+
+ //
+ // Extract the Optional Parameter Value based on the Parameter Type
+ //
+ switch (paramType) {
+ case BgpConstants.Open.Capabilities.TYPE:
+ // Optional Parameter Type: Capabilities
+ if (paramLen < BgpConstants.Open.Capabilities.MIN_LENGTH) {
+ // ERROR: Malformed Capability
+ String errorMsg = "Malformed Capability Type " + paramType;
+ throw new BgpMessage.BgpParseException(errorMsg);
+ }
+ int capabEnd = message.readerIndex() + paramLen;
+ int capabCode = message.readUnsignedByte();
+ int capabLen = message.readUnsignedByte();
+ if (message.readerIndex() + capabLen > capabEnd) {
+ // ERROR: Malformed Capability
+ String errorMsg = "Malformed Capability Type " + paramType;
+ throw new BgpMessage.BgpParseException(errorMsg);
+ }
+
+ switch (capabCode) {
+ case BgpConstants.Open.Capabilities.MultiprotocolExtensions.CODE:
+ // Multiprotocol Extensions Capabilities (RFC 4760)
+ if (capabLen != BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH) {
+ // ERROR: Multiprotocol Extension Length Error
+ String errorMsg = "Multiprotocol Extension Length Error";
+ throw new BgpMessage.BgpParseException(errorMsg);
+ }
+ // Decode the AFI (2 octets) and SAFI (1 octet)
+ int afi = message.readUnsignedShort();
+ int reserved = message.readUnsignedByte();
+ int safi = message.readUnsignedByte();
+ log.debug("BGP RX OPEN Capability: AFI = {} SAFI = {}",
+ afi, safi);
+ //
+ // Setup the AFI/SAFI in the BgpSession
+ //
+ // NOTE: For now we just copy the remote AFI/SAFI setting
+ // to the local configuration.
+ //
+ if (afi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4 &&
+ safi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_UNICAST) {
+ bgpSession.remoteInfo().setIpv4Unicast();
+ bgpSession.localInfo().setIpv4Unicast();
+ } else if (afi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4 &&
+ safi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_MULTICAST) {
+ bgpSession.remoteInfo().setIpv4Multicast();
+ bgpSession.localInfo().setIpv4Multicast();
+ } else if (afi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6 &&
+ safi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_UNICAST) {
+ bgpSession.remoteInfo().setIpv6Unicast();
+ bgpSession.localInfo().setIpv6Unicast();
+ } else if (afi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6 &&
+ safi == BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_MULTICAST) {
+ bgpSession.remoteInfo().setIpv6Multicast();
+ bgpSession.localInfo().setIpv6Multicast();
+ } else {
+ log.debug("BGP RX OPEN Capability: Unknown AFI = {} SAFI = {}",
+ afi, safi);
+ }
+ break;
+
+ case BgpConstants.Open.Capabilities.As4Octet.CODE:
+ // Support for 4-octet AS Number Capabilities (RFC 6793)
+ if (capabLen != BgpConstants.Open.Capabilities.As4Octet.LENGTH) {
+ // ERROR: 4-octet AS Number Capability Length Error
+ String errorMsg = "4-octet AS Number Capability Length Error";
+ throw new BgpMessage.BgpParseException(errorMsg);
+ }
+ long as4Number = message.readUnsignedInt();
+
+ bgpSession.remoteInfo().setAs4OctetCapability();
+ bgpSession.remoteInfo().setAs4Number(as4Number);
+
+ //
+ // Copy remote 4-octet AS Number Capabilities and AS
+ // Number. This is a temporary setting until local AS
+ // number configuration is supported.
+ //
+ bgpSession.localInfo().setAs4OctetCapability();
+ bgpSession.localInfo().setAs4Number(as4Number);
+ log.debug("BGP RX OPEN Capability: AS4 Number = {}",
+ as4Number);
+ break;
+
+ default:
+ // Unknown Capability: ignore it
+ log.debug("BGP RX OPEN Capability Code = {} Length = {}",
+ capabCode, capabLen);
+ message.readBytes(capabLen);
+ break;
+ }
+
+ break;
+
+ default:
+ // Unknown Parameter Type: ignore it
+ log.debug("BGP RX OPEN Parameter Type = {} Length = {}",
+ paramType, paramLen);
+ message.readBytes(paramLen);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Prepares the Capabilities for the BGP OPEN message.
+ *
+ * @param localInfo the BGP Session local information to use
+ * @return the buffer with the BGP Capabilities to transmit
+ */
+ private static ChannelBuffer prepareBgpOpenCapabilities(
+ BgpSessionInfo localInfo) {
+ ChannelBuffer message =
+ ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
+
+ //
+ // Write the Multiprotocol Extensions Capabilities
+ //
+
+ // IPv4 unicast
+ if (localInfo.ipv4Unicast()) {
+ message.writeByte(BgpConstants.Open.Capabilities.TYPE); // Param type
+ message.writeByte(BgpConstants.Open.Capabilities.MIN_LENGTH +
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Param len
+ message.writeByte(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.CODE); // Capab. code
+ message.writeByte(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Capab. len
+ message.writeShort(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4);
+ message.writeByte(0); // Reserved field
+ message.writeByte(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_UNICAST);
+ }
+ // IPv4 multicast
+ if (localInfo.ipv4Multicast()) {
+ message.writeByte(BgpConstants.Open.Capabilities.TYPE); // Param type
+ message.writeByte(BgpConstants.Open.Capabilities.MIN_LENGTH +
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Param len
+ message.writeByte(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.CODE); // Capab. code
+ message.writeByte(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Capab. len
+ message.writeShort(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV4);
+ message.writeByte(0); // Reserved field
+ message.writeByte(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_MULTICAST);
+ }
+ // IPv6 unicast
+ if (localInfo.ipv6Unicast()) {
+ message.writeByte(BgpConstants.Open.Capabilities.TYPE); // Param type
+ message.writeByte(BgpConstants.Open.Capabilities.MIN_LENGTH +
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Param len
+ message.writeByte(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.CODE); // Capab. code
+ message.writeByte(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Capab. len
+ message.writeShort(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6);
+ message.writeByte(0); // Reserved field
+ message.writeByte(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_UNICAST);
+ }
+ // IPv6 multicast
+ if (localInfo.ipv6Multicast()) {
+ message.writeByte(BgpConstants.Open.Capabilities.TYPE); // Param type
+ message.writeByte(BgpConstants.Open.Capabilities.MIN_LENGTH +
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Param len
+ message.writeByte(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.CODE); // Capab. code
+ message.writeByte(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.LENGTH); // Capab. len
+ message.writeShort(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.AFI_IPV6);
+ message.writeByte(0); // Reserved field
+ message.writeByte(
+ BgpConstants.Open.Capabilities.MultiprotocolExtensions.SAFI_MULTICAST);
+ }
+
+ // 4 octet AS path capability
+ if (localInfo.as4OctetCapability()) {
+ message.writeByte(BgpConstants.Open.Capabilities.TYPE); // Param type
+ message.writeByte(BgpConstants.Open.Capabilities.MIN_LENGTH +
+ BgpConstants.Open.Capabilities.As4Octet.LENGTH); // Param len
+ message.writeByte(BgpConstants.Open.Capabilities.As4Octet.CODE); // Capab. code
+ message.writeByte(BgpConstants.Open.Capabilities.As4Octet.LENGTH); // Capab. len
+ message.writeInt((int) localInfo.as4Number());
+ }
+ return message;
+ }
+}