ONOS-734 Add unit tests for 4 Octets AS numbers in SDN-IP
* Fix a bug in the storing, handling and verification of the AS numbers
with 4 octet AS capability is used.
* Add an unit test to test the decoding and parsing of supported
BGP Capabilities: Multiprotocol Extensions AFI/SAFI, and 4 octet AS.
* Minor refactoring of the BGP unit test framework.
Change-Id: I474b356bc00369c307ac0c5c214b065c1cc0c52c
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpOpen.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpOpen.java
index d15a669..93ef852 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpOpen.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpOpen.java
@@ -101,32 +101,6 @@
// Remote AS number
long 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 bs : bgpSession.getBgpSessionManager().getBgpSessions()) {
- if ((bs.remoteInfo().asNumber() != 0) &&
- (remoteAs != bs.remoteInfo().asNumber())) {
- log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
- "Expected {}",
- bgpSession.remoteInfo().address(), remoteAs,
- bs.remoteInfo().asNumber());
- //
- // ERROR: Bad Peer AS
- //
- // Send NOTIFICATION and close the connection
- int errorCode = OpenMessageError.ERROR_CODE;
- int errorSubcode = OpenMessageError.BAD_PEER_AS;
- ChannelBuffer txMessage =
- BgpNotification.prepareBgpNotification(errorCode,
- errorSubcode, null);
- ctx.getChannel().write(txMessage);
- bgpSession.closeSession(ctx);
- return;
- }
- }
bgpSession.remoteInfo().setAsNumber(remoteAs);
//
// NOTE: Currently, the local AS number is always set to the remote AS.
@@ -194,16 +168,63 @@
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 = OpenMessageError.ERROR_CODE;
+ int errorSubcode = 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(), remoteBgpVersion,
- remoteAs, remoteBgpId, remoteHoldtime);
+ bgpSession.remoteInfo().address(),
+ bgpSession.remoteInfo().bgpVersion(),
+ bgpSession.remoteInfo().asNumber(),
+ bgpSession.remoteInfo().bgpId(),
+ bgpSession.remoteInfo().holdtime());
// Send my OPEN followed by KEEPALIVE
- ChannelBuffer txMessage = prepareBgpOpen(bgpSession.localInfo());
- ctx.getChannel().write(txMessage);
+ ctx.getChannel().write(txOpenMessage);
//
- txMessage = BgpKeepalive.prepareBgpKeepalive();
+ ChannelBuffer txMessage = BgpKeepalive.prepareBgpKeepalive();
ctx.getChannel().write(txMessage);
// Start the KEEPALIVE timer
@@ -219,7 +240,7 @@
* @param localInfo the BGP Session local information to use
* @return the message to transmit (BGP header included)
*/
- private static ChannelBuffer prepareBgpOpen(BgpSessionInfo localInfo) {
+ static ChannelBuffer prepareBgpOpen(BgpSessionInfo localInfo) {
ChannelBuffer message =
ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
@@ -360,9 +381,6 @@
bgpSession.remoteInfo().setAs4OctetCapability();
bgpSession.remoteInfo().setAs4Number(as4Number);
- // Use the 4-octet AS number in lieu of the "My AS" field
- // See RFC 6793, Section 4.1, second paragraph.
- bgpSession.remoteInfo().setAsNumber(as4Number);
//
// Copy remote 4-octet AS Number Capabilities and AS
@@ -371,7 +389,6 @@
//
bgpSession.localInfo().setAs4OctetCapability();
bgpSession.localInfo().setAs4Number(as4Number);
- bgpSession.localInfo().setAsNumber(as4Number);
log.debug("BGP RX OPEN Capability: AS4 Number = {}",
as4Number);
break;
@@ -461,8 +478,8 @@
message.writeByte(Capabilities.TYPE); // Param type
message.writeByte(Capabilities.MIN_LENGTH +
As4Octet.LENGTH); // Param len
- message.writeByte(As4Octet.CODE); // Capab, code
- message.writeByte(As4Octet.LENGTH); // Capab, len
+ message.writeByte(As4Octet.CODE); // Capab. code
+ message.writeByte(As4Octet.LENGTH); // Capab. len
message.writeInt((int) localInfo.as4Number());
}
return message;
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpSessionManagerTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpSessionManagerTest.java
index 11a8b5e..45ee321 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpSessionManagerTest.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpSessionManagerTest.java
@@ -85,9 +85,10 @@
private BgpSessionManager bgpSessionManager;
// Remote Peer state
- TestBgpPeer peer1 = new TestBgpPeer(BGP_PEER1_ID);
- TestBgpPeer peer2 = new TestBgpPeer(BGP_PEER2_ID);
- TestBgpPeer peer3 = new TestBgpPeer(BGP_PEER3_ID);
+ private final Collection<TestBgpPeer> peers = new LinkedList<>();
+ TestBgpPeer peer1;
+ TestBgpPeer peer2;
+ TestBgpPeer peer3;
// Local BGP per-peer session state
BgpSession bgpSession1;
@@ -238,6 +239,14 @@
@Before
public void setUp() throws Exception {
+ peer1 = new TestBgpPeer(BGP_PEER1_ID);
+ peer2 = new TestBgpPeer(BGP_PEER2_ID);
+ peer3 = new TestBgpPeer(BGP_PEER3_ID);
+ peers.clear();
+ peers.add(peer1);
+ peers.add(peer2);
+ peers.add(peer3);
+
//
// Setup the BGP Session Manager to test, and start listening for BGP
// connections.
@@ -366,24 +375,14 @@
// Test the fields from the BGP OPEN message:
// BGP version, AS number, BGP ID
//
- assertThat(peer1.peerFrameDecoder.remoteBgpVersion,
- is(BgpConstants.BGP_VERSION));
- assertThat(peer1.peerFrameDecoder.remoteAs,
- is(TestBgpPeerChannelHandler.PEER_AS));
- assertThat(peer1.peerFrameDecoder.remoteBgpIdentifier,
- is(IP_LOOPBACK_ID));
- assertThat(peer2.peerFrameDecoder.remoteBgpVersion,
- is(BgpConstants.BGP_VERSION));
- assertThat(peer2.peerFrameDecoder.remoteAs,
- is(TestBgpPeerChannelHandler.PEER_AS));
- assertThat(peer2.peerFrameDecoder.remoteBgpIdentifier,
- is(IP_LOOPBACK_ID));
- assertThat(peer3.peerFrameDecoder.remoteBgpVersion,
- is(BgpConstants.BGP_VERSION));
- assertThat(peer3.peerFrameDecoder.remoteAs,
- is(TestBgpPeerChannelHandler.PEER_AS));
- assertThat(peer3.peerFrameDecoder.remoteBgpIdentifier,
- is(IP_LOOPBACK_ID));
+ for (TestBgpPeer peer : peers) {
+ assertThat(peer.peerFrameDecoder.remoteInfo.bgpVersion(),
+ is(BgpConstants.BGP_VERSION));
+ assertThat(peer.peerFrameDecoder.remoteInfo.bgpId(),
+ is(IP_LOOPBACK_ID));
+ assertThat(peer.peerFrameDecoder.remoteInfo.asNumber(),
+ is(TestBgpPeerChannelHandler.PEER_AS));
+ }
//
// Test that the BgpSession instances have been created
@@ -399,6 +398,72 @@
}
}
+
+ /**
+ * Tests that the BGP OPEN with Capability messages have been exchanged,
+ * followed by KEEPALIVE.
+ * <p>
+ * The BGP Peer opens the sessions and transmits OPEN Message, eventually
+ * followed by KEEPALIVE. The tested BGP listener should respond by
+ * OPEN Message, followed by KEEPALIVE.
+ *
+ * @throws TestUtilsException TestUtils error
+ */
+ @Test
+ public void testExchangedBgpOpenCapabilityMessages()
+ throws InterruptedException, TestUtilsException {
+ //
+ // Setup the BGP Capabilities for all peers
+ //
+ for (TestBgpPeer peer : peers) {
+ peer.peerChannelHandler.localInfo.setIpv4Unicast();
+ peer.peerChannelHandler.localInfo.setIpv4Multicast();
+ peer.peerChannelHandler.localInfo.setIpv6Unicast();
+ peer.peerChannelHandler.localInfo.setIpv6Multicast();
+ peer.peerChannelHandler.localInfo.setAs4OctetCapability();
+ peer.peerChannelHandler.localInfo.setAs4Number(
+ TestBgpPeerChannelHandler.PEER_AS4);
+ }
+
+ // Initiate the connections
+ peer1.connect(connectToSocket);
+ peer2.connect(connectToSocket);
+ peer3.connect(connectToSocket);
+
+ //
+ // Test the fields from the BGP OPEN message:
+ // BGP version, BGP ID
+ //
+ for (TestBgpPeer peer : peers) {
+ assertThat(peer.peerFrameDecoder.remoteInfo.bgpVersion(),
+ is(BgpConstants.BGP_VERSION));
+ assertThat(peer.peerFrameDecoder.remoteInfo.bgpId(),
+ is(IP_LOOPBACK_ID));
+ }
+
+ //
+ // Test that the BgpSession instances have been created,
+ // and contain the appropriate BGP session information.
+ //
+ assertThat(bgpSessionManager.getMyBgpId(), is(IP_LOOPBACK_ID));
+ assertThat(bgpSessionManager.getBgpSessions(), hasSize(3));
+ assertThat(bgpSession1, notNullValue());
+ assertThat(bgpSession2, notNullValue());
+ assertThat(bgpSession3, notNullValue());
+ for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
+ BgpSessionInfo localInfo = bgpSession.localInfo();
+ assertThat(localInfo.ipv4Unicast(), is(true));
+ assertThat(localInfo.ipv4Multicast(), is(true));
+ assertThat(localInfo.ipv6Unicast(), is(true));
+ assertThat(localInfo.ipv6Multicast(), is(true));
+ assertThat(localInfo.as4OctetCapability(), is(true));
+ assertThat(localInfo.asNumber(),
+ is(TestBgpPeerChannelHandler.PEER_AS4));
+ assertThat(localInfo.as4Number(),
+ is(TestBgpPeerChannelHandler.PEER_AS4));
+ }
+ }
+
/**
* Tests that the BGP UPDATE messages have been received and processed.
*/
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerChannelHandler.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerChannelHandler.java
index 05fb5b4..979a1ed 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerChannelHandler.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerChannelHandler.java
@@ -30,8 +30,10 @@
*/
class TestBgpPeerChannelHandler extends SimpleChannelHandler {
static final long PEER_AS = 65001;
+ static final long PEER_AS4 = 0x12345678;
static final int PEER_HOLDTIME = 120; // 120 seconds
- final Ip4Address bgpId; // The BGP ID
+
+ final BgpSessionInfo localInfo = new BgpSessionInfo();
ChannelHandlerContext savedCtx;
/**
@@ -40,7 +42,10 @@
* @param bgpId the BGP ID to use
*/
TestBgpPeerChannelHandler(Ip4Address bgpId) {
- this.bgpId = bgpId;
+ this.localInfo.setBgpVersion(BgpConstants.BGP_VERSION);
+ this.localInfo.setBgpId(bgpId);
+ this.localInfo.setAsNumber(PEER_AS);
+ this.localInfo.setHoldtime(PEER_HOLDTIME);
}
/**
@@ -55,7 +60,7 @@
ChannelStateEvent channelEvent) {
this.savedCtx = ctx;
// Prepare and transmit BGP OPEN message
- ChannelBuffer message = prepareBgpOpen();
+ ChannelBuffer message = BgpOpen.prepareBgpOpen(localInfo);
ctx.getChannel().write(message);
// Prepare and transmit BGP KEEPALIVE message
@@ -70,23 +75,6 @@
}
/**
- * Prepares BGP OPEN message.
- *
- * @return the message to transmit (BGP header included)
- */
- ChannelBuffer prepareBgpOpen() {
- ChannelBuffer message =
- ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
- message.writeByte(BgpConstants.BGP_VERSION);
- message.writeShort((int) PEER_AS);
- message.writeShort(PEER_HOLDTIME);
- message.writeInt(bgpId.toInt());
- message.writeByte(0); // No Optional Parameters
- return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN,
- message);
- }
-
- /**
* Prepares BGP UPDATE message.
*
* @param nextHopRouter the next-hop router address for the routes to add
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerFrameDecoder.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerFrameDecoder.java
index 7f56df0..4f39547 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerFrameDecoder.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/TestBgpPeerFrameDecoder.java
@@ -28,10 +28,7 @@
* BGP peer session.
*/
class TestBgpPeerFrameDecoder extends FrameDecoder {
- int remoteBgpVersion; // 1 octet
- long remoteAs; // 2 octets
- long remoteHoldtime; // 2 octets
- Ip4Address remoteBgpIdentifier; // 4 octets -> IPv4 address
+ final BgpSessionInfo remoteInfo = new BgpSessionInfo();
final CountDownLatch receivedOpenMessageLatch = new CountDownLatch(1);
final CountDownLatch receivedKeepaliveMessageLatch = new CountDownLatch(1);
@@ -141,11 +138,10 @@
//
// Parse the OPEN message
//
- remoteBgpVersion = message.readUnsignedByte();
- remoteAs = message.readUnsignedShort();
- remoteHoldtime = message.readUnsignedShort();
- remoteBgpIdentifier =
- Ip4Address.valueOf((int) message.readUnsignedInt());
+ remoteInfo.setBgpVersion(message.readUnsignedByte());
+ remoteInfo.setAsNumber(message.readUnsignedShort());
+ remoteInfo.setHoldtime(message.readUnsignedShort());
+ remoteInfo.setBgpId(Ip4Address.valueOf((int) message.readUnsignedInt()));
// Optional Parameters
int optParamLen = message.readUnsignedByte();
if (message.readableBytes() < optParamLen) {