blob: 45ee321722b2c4a5a0dd507a35fad0b6b4adfed2 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.sdnip.bgp;
Jonathan Hart20d8e512014-10-16 11:05:52 -070017
Jonathan Hart20d8e512014-10-16 11:05:52 -070018import static org.hamcrest.Matchers.hasSize;
19import static org.hamcrest.Matchers.is;
20import static org.hamcrest.Matchers.notNullValue;
21import static org.junit.Assert.assertThat;
22
23import java.net.InetAddress;
24import java.net.InetSocketAddress;
25import java.net.SocketAddress;
26import java.util.ArrayList;
27import java.util.Collection;
28import java.util.LinkedList;
29import java.util.concurrent.Executors;
30import java.util.concurrent.TimeUnit;
31
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -080032import org.hamcrest.Description;
33import org.hamcrest.TypeSafeMatcher;
Jonathan Hart20d8e512014-10-16 11:05:52 -070034import org.jboss.netty.bootstrap.ClientBootstrap;
35import org.jboss.netty.buffer.ChannelBuffer;
36import org.jboss.netty.channel.Channel;
37import org.jboss.netty.channel.ChannelFactory;
38import org.jboss.netty.channel.ChannelPipeline;
39import org.jboss.netty.channel.ChannelPipelineFactory;
40import org.jboss.netty.channel.Channels;
41import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
42import org.junit.After;
43import org.junit.Before;
44import org.junit.Test;
Pavlin Radoslavovd26f57a2014-10-23 17:19:45 -070045import org.onlab.junit.TestUtils;
46import org.onlab.junit.TestUtils.TestUtilsException;
Brian O'Connorabafb502014-12-02 22:26:20 -080047import org.onosproject.sdnip.RouteListener;
48import org.onosproject.sdnip.RouteUpdate;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080049import org.onlab.packet.Ip4Address;
50import org.onlab.packet.Ip4Prefix;
Jonathan Hart20d8e512014-10-16 11:05:52 -070051
52import com.google.common.net.InetAddresses;
53
54/**
55 * Unit tests for the BgpSessionManager class.
56 */
57public class BgpSessionManagerTest {
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080058 private static final Ip4Address IP_LOOPBACK_ID =
59 Ip4Address.valueOf("127.0.0.1");
60 private static final Ip4Address BGP_PEER1_ID =
61 Ip4Address.valueOf("10.0.0.1");
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -080062 private static final Ip4Address BGP_PEER2_ID =
63 Ip4Address.valueOf("10.0.0.2");
64 private static final Ip4Address BGP_PEER3_ID =
65 Ip4Address.valueOf("10.0.0.3");
66 private static final Ip4Address NEXT_HOP1_ROUTER =
67 Ip4Address.valueOf("10.20.30.41");
68 private static final Ip4Address NEXT_HOP2_ROUTER =
69 Ip4Address.valueOf("10.20.30.42");
70 private static final Ip4Address NEXT_HOP3_ROUTER =
71 Ip4Address.valueOf("10.20.30.43");
72
Jonathan Hart20d8e512014-10-16 11:05:52 -070073 private static final long DEFAULT_LOCAL_PREF = 10;
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -080074 private static final long BETTER_LOCAL_PREF = 20;
Jonathan Hart20d8e512014-10-16 11:05:52 -070075 private static final long DEFAULT_MULTI_EXIT_DISC = 20;
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -080076 private static final long BETTER_MULTI_EXIT_DISC = 30;
77
78 BgpRouteEntry.AsPath asPathShort;
79 BgpRouteEntry.AsPath asPathLong;
Jonathan Hart20d8e512014-10-16 11:05:52 -070080
Pavlin Radoslavov23c05692014-12-02 13:18:10 -080081 // Timeout waiting for a message to be received
82 private static final int MESSAGE_TIMEOUT_MS = 5000; // 5s
83
Jonathan Hart20d8e512014-10-16 11:05:52 -070084 // The BGP Session Manager to test
85 private BgpSessionManager bgpSessionManager;
86
87 // Remote Peer state
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -080088 private final Collection<TestBgpPeer> peers = new LinkedList<>();
89 TestBgpPeer peer1;
90 TestBgpPeer peer2;
91 TestBgpPeer peer3;
Jonathan Hart20d8e512014-10-16 11:05:52 -070092
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -080093 // Local BGP per-peer session state
94 BgpSession bgpSession1;
95 BgpSession bgpSession2;
96 BgpSession bgpSession3;
97
98 // The socket that the remote peers should connect to
Jonathan Hart20d8e512014-10-16 11:05:52 -070099 private InetSocketAddress connectToSocket;
100
101 private final DummyRouteListener dummyRouteListener =
102 new DummyRouteListener();
103
104 /**
105 * Dummy implementation for the RouteListener interface.
106 */
107 private class DummyRouteListener implements RouteListener {
108 @Override
Pavlin Radoslavov248c2ae2014-12-02 09:51:25 -0800109 public void update(Collection<RouteUpdate> routeUpdate) {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700110 // Nothing to do
111 }
112 }
113
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800114 /**
115 * A class to capture the state for a BGP peer.
116 */
117 private final class TestBgpPeer {
118 private final Ip4Address peerId;
119 private ClientBootstrap peerBootstrap;
120 private TestBgpPeerChannelHandler peerChannelHandler;
121 private TestBgpPeerFrameDecoder peerFrameDecoder =
122 new TestBgpPeerFrameDecoder();
123
124 /**
125 * Constructor.
126 *
127 * @param peerId the peer ID
128 */
129 private TestBgpPeer(Ip4Address peerId) {
130 this.peerId = peerId;
131 peerChannelHandler = new TestBgpPeerChannelHandler(peerId);
132 }
133
134 /**
135 * Starts up the BGP peer and connects it to the tested SDN-IP
136 * instance.
137 *
138 * @param connectToSocket the socket to connect to
139 */
140 private void connect(InetSocketAddress connectToSocket)
141 throws InterruptedException {
142 //
143 // Setup the BGP Peer, i.e., the "remote" BGP router that will
144 // initiate the BGP connection, send BGP UPDATE messages, etc.
145 //
146 ChannelFactory channelFactory =
147 new NioClientSocketChannelFactory(
148 Executors.newCachedThreadPool(),
149 Executors.newCachedThreadPool());
150 ChannelPipelineFactory pipelineFactory =
151 new ChannelPipelineFactory() {
152 @Override
153 public ChannelPipeline getPipeline() throws Exception {
154 // Setup the transmitting pipeline
155 ChannelPipeline pipeline = Channels.pipeline();
156 pipeline.addLast("TestBgpPeerFrameDecoder",
157 peerFrameDecoder);
158 pipeline.addLast("TestBgpPeerChannelHandler",
159 peerChannelHandler);
160 return pipeline;
161 }
162 };
163
164 peerBootstrap = new ClientBootstrap(channelFactory);
165 peerBootstrap.setOption("child.keepAlive", true);
166 peerBootstrap.setOption("child.tcpNoDelay", true);
167 peerBootstrap.setPipelineFactory(pipelineFactory);
168 peerBootstrap.connect(connectToSocket);
169
170 boolean result;
171 // Wait until the OPEN message is received
172 result = peerFrameDecoder.receivedOpenMessageLatch.await(
173 MESSAGE_TIMEOUT_MS,
174 TimeUnit.MILLISECONDS);
175 assertThat(result, is(true));
176 // Wait until the KEEPALIVE message is received
177 result = peerFrameDecoder.receivedKeepaliveMessageLatch.await(
178 MESSAGE_TIMEOUT_MS,
179 TimeUnit.MILLISECONDS);
180 assertThat(result, is(true));
181
182 for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800183 if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER1_ID)) {
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800184 bgpSession1 = bgpSession;
185 }
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800186 if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER2_ID)) {
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800187 bgpSession2 = bgpSession;
188 }
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800189 if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER3_ID)) {
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800190 bgpSession3 = bgpSession;
191 }
192 }
193 }
194 }
195
196 /**
197 * Class that implements a matcher for BgpRouteEntry by considering
198 * the BGP peer the entry was received from.
199 */
200 private static final class BgpRouteEntryAndPeerMatcher
201 extends TypeSafeMatcher<Collection<BgpRouteEntry>> {
202 private final BgpRouteEntry bgpRouteEntry;
203
204 private BgpRouteEntryAndPeerMatcher(BgpRouteEntry bgpRouteEntry) {
205 this.bgpRouteEntry = bgpRouteEntry;
206 }
207
208 @Override
209 public boolean matchesSafely(Collection<BgpRouteEntry> entries) {
210 for (BgpRouteEntry entry : entries) {
211 if (bgpRouteEntry.equals(entry) &&
212 bgpRouteEntry.getBgpSession() == entry.getBgpSession()) {
213 return true;
214 }
215 }
216 return false;
217 }
218
219 @Override
220 public void describeTo(Description description) {
221 description.appendText("BGP route entry lookup for entry \"").
222 appendText(bgpRouteEntry.toString()).
223 appendText("\"");
224 }
225 }
226
227 /**
228 * A helper method used for testing whether a collection of
229 * BGP route entries contains an entry from a specific BGP peer.
230 *
231 * @param bgpRouteEntry the BGP route entry to test
232 * @return an instance of BgpRouteEntryAndPeerMatcher that implements
233 * the matching logic
234 */
235 private static BgpRouteEntryAndPeerMatcher hasBgpRouteEntry(
236 BgpRouteEntry bgpRouteEntry) {
237 return new BgpRouteEntryAndPeerMatcher(bgpRouteEntry);
238 }
239
Jonathan Hart20d8e512014-10-16 11:05:52 -0700240 @Before
241 public void setUp() throws Exception {
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800242 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
Jonathan Hart20d8e512014-10-16 11:05:52 -0700250 //
251 // Setup the BGP Session Manager to test, and start listening for BGP
252 // connections.
253 //
254 bgpSessionManager = new BgpSessionManager(dummyRouteListener);
255 // NOTE: We use port 0 to bind on any available port
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800256 bgpSessionManager.start(0);
Jonathan Hart20d8e512014-10-16 11:05:52 -0700257
258 // Get the port number the BGP Session Manager is listening on
259 Channel serverChannel = TestUtils.getField(bgpSessionManager,
260 "serverChannel");
261 SocketAddress socketAddress = serverChannel.getLocalAddress();
262 InetSocketAddress inetSocketAddress =
263 (InetSocketAddress) socketAddress;
Jonathan Hart20d8e512014-10-16 11:05:52 -0700264 InetAddress connectToAddress = InetAddresses.forString("127.0.0.1");
265 connectToSocket = new InetSocketAddress(connectToAddress,
266 inetSocketAddress.getPort());
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800267
268 //
269 // Setup the AS Paths
270 //
271 ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
272 byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
273 ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
274 segmentAsNumbers1.add((long) 65010);
275 segmentAsNumbers1.add((long) 65020);
276 segmentAsNumbers1.add((long) 65030);
277 BgpRouteEntry.PathSegment pathSegment1 =
278 new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
279 pathSegments.add(pathSegment1);
280 asPathShort = new BgpRouteEntry.AsPath(new ArrayList(pathSegments));
281 //
282 byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
283 ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
284 segmentAsNumbers2.add((long) 65041);
285 segmentAsNumbers2.add((long) 65042);
286 segmentAsNumbers2.add((long) 65043);
287 BgpRouteEntry.PathSegment pathSegment2 =
288 new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
289 pathSegments.add(pathSegment2);
290 //
291 asPathLong = new BgpRouteEntry.AsPath(pathSegments);
Jonathan Hart20d8e512014-10-16 11:05:52 -0700292 }
293
294 @After
295 public void tearDown() throws Exception {
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800296 bgpSessionManager.stop();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700297 bgpSessionManager = null;
298 }
299
300 /**
301 * Gets BGP RIB-IN routes by waiting until they are received.
302 * <p/>
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800303 * NOTE: We keep checking once every 10ms the number of received routes,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700304 * up to 5 seconds.
305 *
306 * @param bgpSession the BGP session that is expected to receive the
307 * routes
308 * @param expectedRoutes the expected number of routes
309 * @return the BGP RIB-IN routes as received within the expected
310 * time interval
311 */
312 private Collection<BgpRouteEntry> waitForBgpRibIn(BgpSession bgpSession,
313 long expectedRoutes)
314 throws InterruptedException {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800315 Collection<BgpRouteEntry> bgpRibIn = bgpSession.getBgpRibIn4();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700316
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800317 final int maxChecks = 500; // Max wait of 5 seconds
Jonathan Hart20d8e512014-10-16 11:05:52 -0700318 for (int i = 0; i < maxChecks; i++) {
319 if (bgpRibIn.size() == expectedRoutes) {
320 break;
321 }
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800322 Thread.sleep(10);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800323 bgpRibIn = bgpSession.getBgpRibIn4();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700324 }
325
326 return bgpRibIn;
327 }
328
329 /**
330 * Gets BGP merged routes by waiting until they are received.
331 * <p/>
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800332 * NOTE: We keep checking once every 10ms the number of received routes,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700333 * up to 5 seconds.
334 *
335 * @param expectedRoutes the expected number of routes
336 * @return the BGP Session Manager routes as received within the expected
337 * time interval
338 */
339 private Collection<BgpRouteEntry> waitForBgpRoutes(long expectedRoutes)
340 throws InterruptedException {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800341 Collection<BgpRouteEntry> bgpRoutes =
342 bgpSessionManager.getBgpRoutes4();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700343
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800344 final int maxChecks = 500; // Max wait of 5 seconds
Jonathan Hart20d8e512014-10-16 11:05:52 -0700345 for (int i = 0; i < maxChecks; i++) {
346 if (bgpRoutes.size() == expectedRoutes) {
347 break;
348 }
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800349 Thread.sleep(10);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800350 bgpRoutes = bgpSessionManager.getBgpRoutes4();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700351 }
352
353 return bgpRoutes;
354 }
355
356 /**
357 * Tests that the BGP OPEN messages have been exchanged, followed by
358 * KEEPALIVE.
359 * <p>
360 * The BGP Peer opens the sessions and transmits OPEN Message, eventually
361 * followed by KEEPALIVE. The tested BGP listener should respond by
362 * OPEN Message, followed by KEEPALIVE.
363 *
364 * @throws TestUtilsException TestUtils error
365 */
366 @Test
367 public void testExchangedBgpOpenMessages()
368 throws InterruptedException, TestUtilsException {
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800369 // Initiate the connections
370 peer1.connect(connectToSocket);
371 peer2.connect(connectToSocket);
372 peer3.connect(connectToSocket);
Jonathan Hart20d8e512014-10-16 11:05:52 -0700373
374 //
375 // Test the fields from the BGP OPEN message:
376 // BGP version, AS number, BGP ID
377 //
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800378 for (TestBgpPeer peer : peers) {
379 assertThat(peer.peerFrameDecoder.remoteInfo.bgpVersion(),
380 is(BgpConstants.BGP_VERSION));
381 assertThat(peer.peerFrameDecoder.remoteInfo.bgpId(),
382 is(IP_LOOPBACK_ID));
383 assertThat(peer.peerFrameDecoder.remoteInfo.asNumber(),
384 is(TestBgpPeerChannelHandler.PEER_AS));
385 }
Jonathan Hart20d8e512014-10-16 11:05:52 -0700386
387 //
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800388 // Test that the BgpSession instances have been created
Jonathan Hart20d8e512014-10-16 11:05:52 -0700389 //
390 assertThat(bgpSessionManager.getMyBgpId(), is(IP_LOOPBACK_ID));
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800391 assertThat(bgpSessionManager.getBgpSessions(), hasSize(3));
392 assertThat(bgpSession1, notNullValue());
393 assertThat(bgpSession2, notNullValue());
394 assertThat(bgpSession3, notNullValue());
395 for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800396 long sessionAs = bgpSession.localInfo().asNumber();
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800397 assertThat(sessionAs, is(TestBgpPeerChannelHandler.PEER_AS));
398 }
Jonathan Hart20d8e512014-10-16 11:05:52 -0700399 }
400
Pavlin Radoslavov4b5acae2015-01-28 17:09:45 -0800401
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
Jonathan Hart20d8e512014-10-16 11:05:52 -0700467 /**
468 * Tests that the BGP UPDATE messages have been received and processed.
469 */
470 @Test
471 public void testProcessedBgpUpdateMessages() throws InterruptedException {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700472 ChannelBuffer message;
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800473 BgpRouteEntry bgpRouteEntry;
474 Collection<BgpRouteEntry> bgpRibIn1;
475 Collection<BgpRouteEntry> bgpRibIn2;
476 Collection<BgpRouteEntry> bgpRibIn3;
Jonathan Hart20d8e512014-10-16 11:05:52 -0700477 Collection<BgpRouteEntry> bgpRoutes;
478
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800479 // Initiate the connections
480 peer1.connect(connectToSocket);
481 peer2.connect(connectToSocket);
482 peer3.connect(connectToSocket);
Jonathan Hart20d8e512014-10-16 11:05:52 -0700483
484 // Prepare routes to add/delete
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800485 Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
486 Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800487
488 //
489 // Add and delete some routes
490 //
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800491 addedRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
492 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
493 addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
494 addedRoutes.add(Ip4Prefix.valueOf("40.0.0.0/24"));
495 addedRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
496 withdrawnRoutes.add(Ip4Prefix.valueOf("60.0.0.0/8"));
497 withdrawnRoutes.add(Ip4Prefix.valueOf("70.0.0.0/16"));
498 withdrawnRoutes.add(Ip4Prefix.valueOf("80.0.0.0/24"));
499 withdrawnRoutes.add(Ip4Prefix.valueOf("90.0.0.0/32"));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700500 // Write the routes
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800501 message = peer1.peerChannelHandler.prepareBgpUpdate(
502 NEXT_HOP1_ROUTER,
503 DEFAULT_LOCAL_PREF,
504 DEFAULT_MULTI_EXIT_DISC,
505 asPathLong,
506 addedRoutes,
507 withdrawnRoutes);
508 peer1.peerChannelHandler.savedCtx.getChannel().write(message);
509 //
Jonathan Hart20d8e512014-10-16 11:05:52 -0700510 // Check that the routes have been received, processed and stored
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800511 //
512 bgpRibIn1 = waitForBgpRibIn(bgpSession1, 5);
513 assertThat(bgpRibIn1, hasSize(5));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700514 bgpRoutes = waitForBgpRoutes(5);
515 assertThat(bgpRoutes, hasSize(5));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700516 //
517 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800518 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800519 Ip4Prefix.valueOf("0.0.0.0/0"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800520 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700521 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800522 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700523 DEFAULT_LOCAL_PREF);
524 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800525 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
526 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700527 //
528 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800529 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800530 Ip4Prefix.valueOf("20.0.0.0/8"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800531 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700532 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800533 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700534 DEFAULT_LOCAL_PREF);
535 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800536 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
537 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700538 //
539 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800540 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800541 Ip4Prefix.valueOf("30.0.0.0/16"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800542 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700543 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800544 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700545 DEFAULT_LOCAL_PREF);
546 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800547 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
548 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700549 //
550 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800551 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800552 Ip4Prefix.valueOf("40.0.0.0/24"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800553 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700554 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800555 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700556 DEFAULT_LOCAL_PREF);
557 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800558 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
559 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700560 //
561 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800562 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800563 Ip4Prefix.valueOf("50.0.0.0/32"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800564 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700565 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800566 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700567 DEFAULT_LOCAL_PREF);
568 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800569 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
570 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700571
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800572 //
Jonathan Hart20d8e512014-10-16 11:05:52 -0700573 // Delete some routes
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800574 //
Jonathan Hart20d8e512014-10-16 11:05:52 -0700575 addedRoutes = new LinkedList<>();
576 withdrawnRoutes = new LinkedList<>();
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800577 withdrawnRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
578 withdrawnRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700579 // Write the routes
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800580 message = peer1.peerChannelHandler.prepareBgpUpdate(
581 NEXT_HOP1_ROUTER,
582 DEFAULT_LOCAL_PREF,
583 DEFAULT_MULTI_EXIT_DISC,
584 asPathLong,
585 addedRoutes,
586 withdrawnRoutes);
587 peer1.peerChannelHandler.savedCtx.getChannel().write(message);
588 //
Jonathan Hart20d8e512014-10-16 11:05:52 -0700589 // Check that the routes have been received, processed and stored
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800590 //
591 bgpRibIn1 = waitForBgpRibIn(bgpSession1, 3);
592 assertThat(bgpRibIn1, hasSize(3));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700593 bgpRoutes = waitForBgpRoutes(3);
594 assertThat(bgpRoutes, hasSize(3));
595 //
596 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800597 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800598 Ip4Prefix.valueOf("20.0.0.0/8"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800599 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700600 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800601 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700602 DEFAULT_LOCAL_PREF);
603 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800604 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
605 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700606 //
607 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800608 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800609 Ip4Prefix.valueOf("30.0.0.0/16"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800610 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700611 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800612 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700613 DEFAULT_LOCAL_PREF);
614 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800615 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
616 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700617 //
618 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800619 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800620 Ip4Prefix.valueOf("40.0.0.0/24"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800621 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700622 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800623 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700624 DEFAULT_LOCAL_PREF);
625 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800626 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
627 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700628
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800629
630 // Close the channels and test there are no routes
631 peer1.peerChannelHandler.closeChannel();
632 peer2.peerChannelHandler.closeChannel();
633 peer3.peerChannelHandler.closeChannel();
634 bgpRoutes = waitForBgpRoutes(0);
635 assertThat(bgpRoutes, hasSize(0));
636 }
637
638 /**
639 * Tests the BGP route preference.
640 */
641 @Test
642 public void testBgpRoutePreference() throws InterruptedException {
643 ChannelBuffer message;
644 BgpRouteEntry bgpRouteEntry;
645 Collection<BgpRouteEntry> bgpRibIn1;
646 Collection<BgpRouteEntry> bgpRibIn2;
647 Collection<BgpRouteEntry> bgpRibIn3;
648 Collection<BgpRouteEntry> bgpRoutes;
649 Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
650 Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
651
652 // Initiate the connections
653 peer1.connect(connectToSocket);
654 peer2.connect(connectToSocket);
655 peer3.connect(connectToSocket);
656
657 //
658 // Setup the initial set of routes to Peer1
659 //
660 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
661 addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
662 // Write the routes
663 message = peer1.peerChannelHandler.prepareBgpUpdate(
664 NEXT_HOP1_ROUTER,
665 DEFAULT_LOCAL_PREF,
666 DEFAULT_MULTI_EXIT_DISC,
667 asPathLong,
668 addedRoutes,
669 withdrawnRoutes);
670 peer1.peerChannelHandler.savedCtx.getChannel().write(message);
671 bgpRoutes = waitForBgpRoutes(2);
672 assertThat(bgpRoutes, hasSize(2));
673
674 //
675 // Add a route entry to Peer2 with a better LOCAL_PREF
676 //
677 addedRoutes = new LinkedList<>();
678 withdrawnRoutes = new LinkedList<>();
679 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
680 // Write the routes
681 message = peer2.peerChannelHandler.prepareBgpUpdate(
682 NEXT_HOP2_ROUTER,
683 BETTER_LOCAL_PREF,
684 DEFAULT_MULTI_EXIT_DISC,
685 asPathLong,
686 addedRoutes,
687 withdrawnRoutes);
688 peer2.peerChannelHandler.savedCtx.getChannel().write(message);
689 //
690 // Check that the routes have been received, processed and stored
691 //
692 bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
693 assertThat(bgpRibIn2, hasSize(1));
694 bgpRoutes = waitForBgpRoutes(2);
695 assertThat(bgpRoutes, hasSize(2));
696 //
697 bgpRouteEntry =
698 new BgpRouteEntry(bgpSession2,
699 Ip4Prefix.valueOf("20.0.0.0/8"),
700 NEXT_HOP2_ROUTER,
701 (byte) BgpConstants.Update.Origin.IGP,
702 asPathLong,
703 BETTER_LOCAL_PREF);
704 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
705 assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
706 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
707
708 //
709 // Add a route entry to Peer3 with a shorter AS path
710 //
711 addedRoutes = new LinkedList<>();
712 withdrawnRoutes = new LinkedList<>();
713 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
714 // Write the routes
715 message = peer3.peerChannelHandler.prepareBgpUpdate(
716 NEXT_HOP3_ROUTER,
717 BETTER_LOCAL_PREF,
718 DEFAULT_MULTI_EXIT_DISC,
719 asPathShort,
720 addedRoutes,
721 withdrawnRoutes);
722 peer3.peerChannelHandler.savedCtx.getChannel().write(message);
723 //
724 // Check that the routes have been received, processed and stored
725 //
726 bgpRibIn3 = waitForBgpRibIn(bgpSession3, 1);
727 assertThat(bgpRibIn3, hasSize(1));
728 bgpRoutes = waitForBgpRoutes(2);
729 assertThat(bgpRoutes, hasSize(2));
730 //
731 bgpRouteEntry =
732 new BgpRouteEntry(bgpSession3,
733 Ip4Prefix.valueOf("20.0.0.0/8"),
734 NEXT_HOP3_ROUTER,
735 (byte) BgpConstants.Update.Origin.IGP,
736 asPathShort,
737 BETTER_LOCAL_PREF);
738 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
739 assertThat(bgpRibIn3, hasBgpRouteEntry(bgpRouteEntry));
740 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
741
742 //
743 // Cleanup in preparation for next test: delete old route entry from
744 // Peer2
745 //
746 addedRoutes = new LinkedList<>();
747 withdrawnRoutes = new LinkedList<>();
748 withdrawnRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
749 // Write the routes
750 message = peer2.peerChannelHandler.prepareBgpUpdate(
751 NEXT_HOP2_ROUTER,
752 BETTER_LOCAL_PREF,
753 BETTER_MULTI_EXIT_DISC,
754 asPathShort,
755 addedRoutes,
756 withdrawnRoutes);
757 peer2.peerChannelHandler.savedCtx.getChannel().write(message);
758 //
759 // Check that the routes have been received, processed and stored
760 //
761 bgpRibIn2 = waitForBgpRibIn(bgpSession2, 0);
762 assertThat(bgpRibIn2, hasSize(0));
763
764 //
765 // Add a route entry to Peer2 with a better MED
766 //
767 addedRoutes = new LinkedList<>();
768 withdrawnRoutes = new LinkedList<>();
769 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
770 // Write the routes
771 message = peer2.peerChannelHandler.prepareBgpUpdate(
772 NEXT_HOP2_ROUTER,
773 BETTER_LOCAL_PREF,
774 BETTER_MULTI_EXIT_DISC,
775 asPathShort,
776 addedRoutes,
777 withdrawnRoutes);
778 peer2.peerChannelHandler.savedCtx.getChannel().write(message);
779 //
780 // Check that the routes have been received, processed and stored
781 //
782 bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
783 assertThat(bgpRibIn2, hasSize(1));
784 bgpRoutes = waitForBgpRoutes(2);
785 assertThat(bgpRoutes, hasSize(2));
786 //
787 bgpRouteEntry =
788 new BgpRouteEntry(bgpSession2,
789 Ip4Prefix.valueOf("20.0.0.0/8"),
790 NEXT_HOP2_ROUTER,
791 (byte) BgpConstants.Update.Origin.IGP,
792 asPathShort,
793 BETTER_LOCAL_PREF);
794 bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
795 assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
796 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
797
798 //
799 // Add a route entry to Peer1 with a better (lower) BGP ID
800 //
801 addedRoutes = new LinkedList<>();
802 withdrawnRoutes = new LinkedList<>();
803 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
804 withdrawnRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
805 // Write the routes
806 message = peer1.peerChannelHandler.prepareBgpUpdate(
807 NEXT_HOP1_ROUTER,
808 BETTER_LOCAL_PREF,
809 BETTER_MULTI_EXIT_DISC,
810 asPathShort,
811 addedRoutes,
812 withdrawnRoutes);
813 peer1.peerChannelHandler.savedCtx.getChannel().write(message);
814 //
815 // Check that the routes have been received, processed and stored
816 //
817 bgpRibIn1 = waitForBgpRibIn(bgpSession1, 1);
818 assertThat(bgpRibIn1, hasSize(1));
819 bgpRoutes = waitForBgpRoutes(1);
820 assertThat(bgpRoutes, hasSize(1));
821 //
822 bgpRouteEntry =
823 new BgpRouteEntry(bgpSession1,
824 Ip4Prefix.valueOf("20.0.0.0/8"),
825 NEXT_HOP1_ROUTER,
826 (byte) BgpConstants.Update.Origin.IGP,
827 asPathShort,
828 BETTER_LOCAL_PREF);
829 bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
830 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
831 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
832
833
834 // Close the channels and test there are no routes
835 peer1.peerChannelHandler.closeChannel();
836 peer2.peerChannelHandler.closeChannel();
837 peer3.peerChannelHandler.closeChannel();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700838 bgpRoutes = waitForBgpRoutes(0);
839 assertThat(bgpRoutes, hasSize(0));
840 }
841}