Pavlin Radoslavov

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
...@@ -101,32 +101,6 @@ final class BgpOpen { ...@@ -101,32 +101,6 @@ final class BgpOpen {
101 101
102 // Remote AS number 102 // Remote AS number
103 long remoteAs = message.readUnsignedShort(); 103 long remoteAs = message.readUnsignedShort();
104 - //
105 - // Verify that the AS number is same for all other BGP Sessions
106 - // NOTE: This check applies only for our use-case where all BGP
107 - // sessions are iBGP.
108 - //
109 - for (BgpSession bs : bgpSession.getBgpSessionManager().getBgpSessions()) {
110 - if ((bs.remoteInfo().asNumber() != 0) &&
111 - (remoteAs != bs.remoteInfo().asNumber())) {
112 - log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
113 - "Expected {}",
114 - bgpSession.remoteInfo().address(), remoteAs,
115 - bs.remoteInfo().asNumber());
116 - //
117 - // ERROR: Bad Peer AS
118 - //
119 - // Send NOTIFICATION and close the connection
120 - int errorCode = OpenMessageError.ERROR_CODE;
121 - int errorSubcode = OpenMessageError.BAD_PEER_AS;
122 - ChannelBuffer txMessage =
123 - BgpNotification.prepareBgpNotification(errorCode,
124 - errorSubcode, null);
125 - ctx.getChannel().write(txMessage);
126 - bgpSession.closeSession(ctx);
127 - return;
128 - }
129 - }
130 bgpSession.remoteInfo().setAsNumber(remoteAs); 104 bgpSession.remoteInfo().setAsNumber(remoteAs);
131 // 105 //
132 // NOTE: Currently, the local AS number is always set to the remote AS. 106 // NOTE: Currently, the local AS number is always set to the remote AS.
...@@ -194,16 +168,63 @@ final class BgpOpen { ...@@ -194,16 +168,63 @@ final class BgpOpen {
194 return; 168 return;
195 } 169 }
196 170
171 + //
172 + // NOTE: Prepare the BGP OPEN message before the original local AS
173 + // is overwritten by the 4-octet AS number
174 + //
175 + ChannelBuffer txOpenMessage = prepareBgpOpen(bgpSession.localInfo());
176 +
177 + //
178 + // Use the 4-octet AS number in lieu of the "My AS" field
179 + // See RFC 6793, Section 4.1, second paragraph.
180 + //
181 + if (bgpSession.remoteInfo().as4OctetCapability()) {
182 + long as4Number = bgpSession.remoteInfo().as4Number();
183 + bgpSession.remoteInfo().setAsNumber(as4Number);
184 + bgpSession.localInfo().setAsNumber(as4Number);
185 + }
186 +
187 + //
188 + // Verify that the AS number is same for all other BGP Sessions
189 + // NOTE: This check applies only for our use-case where all BGP
190 + // sessions are iBGP.
191 + //
192 + for (BgpSession bs : bgpSession.getBgpSessionManager().getBgpSessions()) {
193 + if ((bs.remoteInfo().asNumber() != 0) &&
194 + (bgpSession.remoteInfo().asNumber() !=
195 + bs.remoteInfo().asNumber())) {
196 + log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
197 + "Expected {}",
198 + bgpSession.remoteInfo().address(),
199 + bgpSession.remoteInfo().asNumber(),
200 + bs.remoteInfo().asNumber());
201 + //
202 + // ERROR: Bad Peer AS
203 + //
204 + // Send NOTIFICATION and close the connection
205 + int errorCode = OpenMessageError.ERROR_CODE;
206 + int errorSubcode = OpenMessageError.BAD_PEER_AS;
207 + ChannelBuffer txMessage =
208 + BgpNotification.prepareBgpNotification(errorCode,
209 + errorSubcode, null);
210 + ctx.getChannel().write(txMessage);
211 + bgpSession.closeSession(ctx);
212 + return;
213 + }
214 + }
215 +
197 log.debug("BGP RX OPEN message from {}: " + 216 log.debug("BGP RX OPEN message from {}: " +
198 "BGPv{} AS {} BGP-ID {} Holdtime {}", 217 "BGPv{} AS {} BGP-ID {} Holdtime {}",
199 - bgpSession.remoteInfo().address(), remoteBgpVersion, 218 + bgpSession.remoteInfo().address(),
200 - remoteAs, remoteBgpId, remoteHoldtime); 219 + bgpSession.remoteInfo().bgpVersion(),
220 + bgpSession.remoteInfo().asNumber(),
221 + bgpSession.remoteInfo().bgpId(),
222 + bgpSession.remoteInfo().holdtime());
201 223
202 // Send my OPEN followed by KEEPALIVE 224 // Send my OPEN followed by KEEPALIVE
203 - ChannelBuffer txMessage = prepareBgpOpen(bgpSession.localInfo()); 225 + ctx.getChannel().write(txOpenMessage);
204 - ctx.getChannel().write(txMessage);
205 // 226 //
206 - txMessage = BgpKeepalive.prepareBgpKeepalive(); 227 + ChannelBuffer txMessage = BgpKeepalive.prepareBgpKeepalive();
207 ctx.getChannel().write(txMessage); 228 ctx.getChannel().write(txMessage);
208 229
209 // Start the KEEPALIVE timer 230 // Start the KEEPALIVE timer
...@@ -219,7 +240,7 @@ final class BgpOpen { ...@@ -219,7 +240,7 @@ final class BgpOpen {
219 * @param localInfo the BGP Session local information to use 240 * @param localInfo the BGP Session local information to use
220 * @return the message to transmit (BGP header included) 241 * @return the message to transmit (BGP header included)
221 */ 242 */
222 - private static ChannelBuffer prepareBgpOpen(BgpSessionInfo localInfo) { 243 + static ChannelBuffer prepareBgpOpen(BgpSessionInfo localInfo) {
223 ChannelBuffer message = 244 ChannelBuffer message =
224 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH); 245 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
225 246
...@@ -360,9 +381,6 @@ final class BgpOpen { ...@@ -360,9 +381,6 @@ final class BgpOpen {
360 381
361 bgpSession.remoteInfo().setAs4OctetCapability(); 382 bgpSession.remoteInfo().setAs4OctetCapability();
362 bgpSession.remoteInfo().setAs4Number(as4Number); 383 bgpSession.remoteInfo().setAs4Number(as4Number);
363 - // Use the 4-octet AS number in lieu of the "My AS" field
364 - // See RFC 6793, Section 4.1, second paragraph.
365 - bgpSession.remoteInfo().setAsNumber(as4Number);
366 384
367 // 385 //
368 // Copy remote 4-octet AS Number Capabilities and AS 386 // Copy remote 4-octet AS Number Capabilities and AS
...@@ -371,7 +389,6 @@ final class BgpOpen { ...@@ -371,7 +389,6 @@ final class BgpOpen {
371 // 389 //
372 bgpSession.localInfo().setAs4OctetCapability(); 390 bgpSession.localInfo().setAs4OctetCapability();
373 bgpSession.localInfo().setAs4Number(as4Number); 391 bgpSession.localInfo().setAs4Number(as4Number);
374 - bgpSession.localInfo().setAsNumber(as4Number);
375 log.debug("BGP RX OPEN Capability: AS4 Number = {}", 392 log.debug("BGP RX OPEN Capability: AS4 Number = {}",
376 as4Number); 393 as4Number);
377 break; 394 break;
...@@ -461,8 +478,8 @@ final class BgpOpen { ...@@ -461,8 +478,8 @@ final class BgpOpen {
461 message.writeByte(Capabilities.TYPE); // Param type 478 message.writeByte(Capabilities.TYPE); // Param type
462 message.writeByte(Capabilities.MIN_LENGTH + 479 message.writeByte(Capabilities.MIN_LENGTH +
463 As4Octet.LENGTH); // Param len 480 As4Octet.LENGTH); // Param len
464 - message.writeByte(As4Octet.CODE); // Capab, code 481 + message.writeByte(As4Octet.CODE); // Capab. code
465 - message.writeByte(As4Octet.LENGTH); // Capab, len 482 + message.writeByte(As4Octet.LENGTH); // Capab. len
466 message.writeInt((int) localInfo.as4Number()); 483 message.writeInt((int) localInfo.as4Number());
467 } 484 }
468 return message; 485 return message;
......
...@@ -85,9 +85,10 @@ public class BgpSessionManagerTest { ...@@ -85,9 +85,10 @@ public class BgpSessionManagerTest {
85 private BgpSessionManager bgpSessionManager; 85 private BgpSessionManager bgpSessionManager;
86 86
87 // Remote Peer state 87 // Remote Peer state
88 - TestBgpPeer peer1 = new TestBgpPeer(BGP_PEER1_ID); 88 + private final Collection<TestBgpPeer> peers = new LinkedList<>();
89 - TestBgpPeer peer2 = new TestBgpPeer(BGP_PEER2_ID); 89 + TestBgpPeer peer1;
90 - TestBgpPeer peer3 = new TestBgpPeer(BGP_PEER3_ID); 90 + TestBgpPeer peer2;
91 + TestBgpPeer peer3;
91 92
92 // Local BGP per-peer session state 93 // Local BGP per-peer session state
93 BgpSession bgpSession1; 94 BgpSession bgpSession1;
...@@ -238,6 +239,14 @@ public class BgpSessionManagerTest { ...@@ -238,6 +239,14 @@ public class BgpSessionManagerTest {
238 239
239 @Before 240 @Before
240 public void setUp() throws Exception { 241 public void setUp() throws Exception {
242 + peer1 = new TestBgpPeer(BGP_PEER1_ID);
243 + peer2 = new TestBgpPeer(BGP_PEER2_ID);
244 + peer3 = new TestBgpPeer(BGP_PEER3_ID);
245 + peers.clear();
246 + peers.add(peer1);
247 + peers.add(peer2);
248 + peers.add(peer3);
249 +
241 // 250 //
242 // Setup the BGP Session Manager to test, and start listening for BGP 251 // Setup the BGP Session Manager to test, and start listening for BGP
243 // connections. 252 // connections.
...@@ -366,24 +375,14 @@ public class BgpSessionManagerTest { ...@@ -366,24 +375,14 @@ public class BgpSessionManagerTest {
366 // Test the fields from the BGP OPEN message: 375 // Test the fields from the BGP OPEN message:
367 // BGP version, AS number, BGP ID 376 // BGP version, AS number, BGP ID
368 // 377 //
369 - assertThat(peer1.peerFrameDecoder.remoteBgpVersion, 378 + for (TestBgpPeer peer : peers) {
370 - is(BgpConstants.BGP_VERSION)); 379 + assertThat(peer.peerFrameDecoder.remoteInfo.bgpVersion(),
371 - assertThat(peer1.peerFrameDecoder.remoteAs, 380 + is(BgpConstants.BGP_VERSION));
372 - is(TestBgpPeerChannelHandler.PEER_AS)); 381 + assertThat(peer.peerFrameDecoder.remoteInfo.bgpId(),
373 - assertThat(peer1.peerFrameDecoder.remoteBgpIdentifier, 382 + is(IP_LOOPBACK_ID));
374 - is(IP_LOOPBACK_ID)); 383 + assertThat(peer.peerFrameDecoder.remoteInfo.asNumber(),
375 - assertThat(peer2.peerFrameDecoder.remoteBgpVersion, 384 + is(TestBgpPeerChannelHandler.PEER_AS));
376 - is(BgpConstants.BGP_VERSION)); 385 + }
377 - assertThat(peer2.peerFrameDecoder.remoteAs,
378 - is(TestBgpPeerChannelHandler.PEER_AS));
379 - assertThat(peer2.peerFrameDecoder.remoteBgpIdentifier,
380 - is(IP_LOOPBACK_ID));
381 - assertThat(peer3.peerFrameDecoder.remoteBgpVersion,
382 - is(BgpConstants.BGP_VERSION));
383 - assertThat(peer3.peerFrameDecoder.remoteAs,
384 - is(TestBgpPeerChannelHandler.PEER_AS));
385 - assertThat(peer3.peerFrameDecoder.remoteBgpIdentifier,
386 - is(IP_LOOPBACK_ID));
387 386
388 // 387 //
389 // Test that the BgpSession instances have been created 388 // Test that the BgpSession instances have been created
...@@ -399,6 +398,72 @@ public class BgpSessionManagerTest { ...@@ -399,6 +398,72 @@ public class BgpSessionManagerTest {
399 } 398 }
400 } 399 }
401 400
401 +
402 + /**
403 + * Tests that the BGP OPEN with Capability messages have been exchanged,
404 + * followed by KEEPALIVE.
405 + * <p>
406 + * The BGP Peer opens the sessions and transmits OPEN Message, eventually
407 + * followed by KEEPALIVE. The tested BGP listener should respond by
408 + * OPEN Message, followed by KEEPALIVE.
409 + *
410 + * @throws TestUtilsException TestUtils error
411 + */
412 + @Test
413 + public void testExchangedBgpOpenCapabilityMessages()
414 + throws InterruptedException, TestUtilsException {
415 + //
416 + // Setup the BGP Capabilities for all peers
417 + //
418 + for (TestBgpPeer peer : peers) {
419 + peer.peerChannelHandler.localInfo.setIpv4Unicast();
420 + peer.peerChannelHandler.localInfo.setIpv4Multicast();
421 + peer.peerChannelHandler.localInfo.setIpv6Unicast();
422 + peer.peerChannelHandler.localInfo.setIpv6Multicast();
423 + peer.peerChannelHandler.localInfo.setAs4OctetCapability();
424 + peer.peerChannelHandler.localInfo.setAs4Number(
425 + TestBgpPeerChannelHandler.PEER_AS4);
426 + }
427 +
428 + // Initiate the connections
429 + peer1.connect(connectToSocket);
430 + peer2.connect(connectToSocket);
431 + peer3.connect(connectToSocket);
432 +
433 + //
434 + // Test the fields from the BGP OPEN message:
435 + // BGP version, BGP ID
436 + //
437 + for (TestBgpPeer peer : peers) {
438 + assertThat(peer.peerFrameDecoder.remoteInfo.bgpVersion(),
439 + is(BgpConstants.BGP_VERSION));
440 + assertThat(peer.peerFrameDecoder.remoteInfo.bgpId(),
441 + is(IP_LOOPBACK_ID));
442 + }
443 +
444 + //
445 + // Test that the BgpSession instances have been created,
446 + // and contain the appropriate BGP session information.
447 + //
448 + assertThat(bgpSessionManager.getMyBgpId(), is(IP_LOOPBACK_ID));
449 + assertThat(bgpSessionManager.getBgpSessions(), hasSize(3));
450 + assertThat(bgpSession1, notNullValue());
451 + assertThat(bgpSession2, notNullValue());
452 + assertThat(bgpSession3, notNullValue());
453 + for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
454 + BgpSessionInfo localInfo = bgpSession.localInfo();
455 + assertThat(localInfo.ipv4Unicast(), is(true));
456 + assertThat(localInfo.ipv4Multicast(), is(true));
457 + assertThat(localInfo.ipv6Unicast(), is(true));
458 + assertThat(localInfo.ipv6Multicast(), is(true));
459 + assertThat(localInfo.as4OctetCapability(), is(true));
460 + assertThat(localInfo.asNumber(),
461 + is(TestBgpPeerChannelHandler.PEER_AS4));
462 + assertThat(localInfo.as4Number(),
463 + is(TestBgpPeerChannelHandler.PEER_AS4));
464 + }
465 + }
466 +
402 /** 467 /**
403 * Tests that the BGP UPDATE messages have been received and processed. 468 * Tests that the BGP UPDATE messages have been received and processed.
404 */ 469 */
......
...@@ -30,8 +30,10 @@ import org.onlab.packet.Ip4Prefix; ...@@ -30,8 +30,10 @@ import org.onlab.packet.Ip4Prefix;
30 */ 30 */
31 class TestBgpPeerChannelHandler extends SimpleChannelHandler { 31 class TestBgpPeerChannelHandler extends SimpleChannelHandler {
32 static final long PEER_AS = 65001; 32 static final long PEER_AS = 65001;
33 + static final long PEER_AS4 = 0x12345678;
33 static final int PEER_HOLDTIME = 120; // 120 seconds 34 static final int PEER_HOLDTIME = 120; // 120 seconds
34 - final Ip4Address bgpId; // The BGP ID 35 +
36 + final BgpSessionInfo localInfo = new BgpSessionInfo();
35 ChannelHandlerContext savedCtx; 37 ChannelHandlerContext savedCtx;
36 38
37 /** 39 /**
...@@ -40,7 +42,10 @@ class TestBgpPeerChannelHandler extends SimpleChannelHandler { ...@@ -40,7 +42,10 @@ class TestBgpPeerChannelHandler extends SimpleChannelHandler {
40 * @param bgpId the BGP ID to use 42 * @param bgpId the BGP ID to use
41 */ 43 */
42 TestBgpPeerChannelHandler(Ip4Address bgpId) { 44 TestBgpPeerChannelHandler(Ip4Address bgpId) {
43 - this.bgpId = bgpId; 45 + this.localInfo.setBgpVersion(BgpConstants.BGP_VERSION);
46 + this.localInfo.setBgpId(bgpId);
47 + this.localInfo.setAsNumber(PEER_AS);
48 + this.localInfo.setHoldtime(PEER_HOLDTIME);
44 } 49 }
45 50
46 /** 51 /**
...@@ -55,7 +60,7 @@ class TestBgpPeerChannelHandler extends SimpleChannelHandler { ...@@ -55,7 +60,7 @@ class TestBgpPeerChannelHandler extends SimpleChannelHandler {
55 ChannelStateEvent channelEvent) { 60 ChannelStateEvent channelEvent) {
56 this.savedCtx = ctx; 61 this.savedCtx = ctx;
57 // Prepare and transmit BGP OPEN message 62 // Prepare and transmit BGP OPEN message
58 - ChannelBuffer message = prepareBgpOpen(); 63 + ChannelBuffer message = BgpOpen.prepareBgpOpen(localInfo);
59 ctx.getChannel().write(message); 64 ctx.getChannel().write(message);
60 65
61 // Prepare and transmit BGP KEEPALIVE message 66 // Prepare and transmit BGP KEEPALIVE message
...@@ -70,23 +75,6 @@ class TestBgpPeerChannelHandler extends SimpleChannelHandler { ...@@ -70,23 +75,6 @@ class TestBgpPeerChannelHandler extends SimpleChannelHandler {
70 } 75 }
71 76
72 /** 77 /**
73 - * Prepares BGP OPEN message.
74 - *
75 - * @return the message to transmit (BGP header included)
76 - */
77 - ChannelBuffer prepareBgpOpen() {
78 - ChannelBuffer message =
79 - ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
80 - message.writeByte(BgpConstants.BGP_VERSION);
81 - message.writeShort((int) PEER_AS);
82 - message.writeShort(PEER_HOLDTIME);
83 - message.writeInt(bgpId.toInt());
84 - message.writeByte(0); // No Optional Parameters
85 - return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN,
86 - message);
87 - }
88 -
89 - /**
90 * Prepares BGP UPDATE message. 78 * Prepares BGP UPDATE message.
91 * 79 *
92 * @param nextHopRouter the next-hop router address for the routes to add 80 * @param nextHopRouter the next-hop router address for the routes to add
......
...@@ -28,10 +28,7 @@ import org.onlab.packet.Ip4Address; ...@@ -28,10 +28,7 @@ import org.onlab.packet.Ip4Address;
28 * BGP peer session. 28 * BGP peer session.
29 */ 29 */
30 class TestBgpPeerFrameDecoder extends FrameDecoder { 30 class TestBgpPeerFrameDecoder extends FrameDecoder {
31 - int remoteBgpVersion; // 1 octet 31 + final BgpSessionInfo remoteInfo = new BgpSessionInfo();
32 - long remoteAs; // 2 octets
33 - long remoteHoldtime; // 2 octets
34 - Ip4Address remoteBgpIdentifier; // 4 octets -> IPv4 address
35 32
36 final CountDownLatch receivedOpenMessageLatch = new CountDownLatch(1); 33 final CountDownLatch receivedOpenMessageLatch = new CountDownLatch(1);
37 final CountDownLatch receivedKeepaliveMessageLatch = new CountDownLatch(1); 34 final CountDownLatch receivedKeepaliveMessageLatch = new CountDownLatch(1);
...@@ -141,11 +138,10 @@ class TestBgpPeerFrameDecoder extends FrameDecoder { ...@@ -141,11 +138,10 @@ class TestBgpPeerFrameDecoder extends FrameDecoder {
141 // 138 //
142 // Parse the OPEN message 139 // Parse the OPEN message
143 // 140 //
144 - remoteBgpVersion = message.readUnsignedByte(); 141 + remoteInfo.setBgpVersion(message.readUnsignedByte());
145 - remoteAs = message.readUnsignedShort(); 142 + remoteInfo.setAsNumber(message.readUnsignedShort());
146 - remoteHoldtime = message.readUnsignedShort(); 143 + remoteInfo.setHoldtime(message.readUnsignedShort());
147 - remoteBgpIdentifier = 144 + remoteInfo.setBgpId(Ip4Address.valueOf((int) message.readUnsignedInt()));
148 - Ip4Address.valueOf((int) message.readUnsignedInt());
149 // Optional Parameters 145 // Optional Parameters
150 int optParamLen = message.readUnsignedByte(); 146 int optParamLen = message.readUnsignedByte();
151 if (message.readableBytes() < optParamLen) { 147 if (message.readableBytes() < optParamLen) {
......