blob: 11a8b5e81586c2ef33768b96f498048288843844 [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 Radoslavov0af11c12014-12-10 18:16:25 -080088 TestBgpPeer peer1 = new TestBgpPeer(BGP_PEER1_ID);
89 TestBgpPeer peer2 = new TestBgpPeer(BGP_PEER2_ID);
90 TestBgpPeer peer3 = new TestBgpPeer(BGP_PEER3_ID);
Jonathan Hart20d8e512014-10-16 11:05:52 -070091
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -080092 // Local BGP per-peer session state
93 BgpSession bgpSession1;
94 BgpSession bgpSession2;
95 BgpSession bgpSession3;
96
97 // The socket that the remote peers should connect to
Jonathan Hart20d8e512014-10-16 11:05:52 -070098 private InetSocketAddress connectToSocket;
99
100 private final DummyRouteListener dummyRouteListener =
101 new DummyRouteListener();
102
103 /**
104 * Dummy implementation for the RouteListener interface.
105 */
106 private class DummyRouteListener implements RouteListener {
107 @Override
Pavlin Radoslavov248c2ae2014-12-02 09:51:25 -0800108 public void update(Collection<RouteUpdate> routeUpdate) {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700109 // Nothing to do
110 }
111 }
112
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800113 /**
114 * A class to capture the state for a BGP peer.
115 */
116 private final class TestBgpPeer {
117 private final Ip4Address peerId;
118 private ClientBootstrap peerBootstrap;
119 private TestBgpPeerChannelHandler peerChannelHandler;
120 private TestBgpPeerFrameDecoder peerFrameDecoder =
121 new TestBgpPeerFrameDecoder();
122
123 /**
124 * Constructor.
125 *
126 * @param peerId the peer ID
127 */
128 private TestBgpPeer(Ip4Address peerId) {
129 this.peerId = peerId;
130 peerChannelHandler = new TestBgpPeerChannelHandler(peerId);
131 }
132
133 /**
134 * Starts up the BGP peer and connects it to the tested SDN-IP
135 * instance.
136 *
137 * @param connectToSocket the socket to connect to
138 */
139 private void connect(InetSocketAddress connectToSocket)
140 throws InterruptedException {
141 //
142 // Setup the BGP Peer, i.e., the "remote" BGP router that will
143 // initiate the BGP connection, send BGP UPDATE messages, etc.
144 //
145 ChannelFactory channelFactory =
146 new NioClientSocketChannelFactory(
147 Executors.newCachedThreadPool(),
148 Executors.newCachedThreadPool());
149 ChannelPipelineFactory pipelineFactory =
150 new ChannelPipelineFactory() {
151 @Override
152 public ChannelPipeline getPipeline() throws Exception {
153 // Setup the transmitting pipeline
154 ChannelPipeline pipeline = Channels.pipeline();
155 pipeline.addLast("TestBgpPeerFrameDecoder",
156 peerFrameDecoder);
157 pipeline.addLast("TestBgpPeerChannelHandler",
158 peerChannelHandler);
159 return pipeline;
160 }
161 };
162
163 peerBootstrap = new ClientBootstrap(channelFactory);
164 peerBootstrap.setOption("child.keepAlive", true);
165 peerBootstrap.setOption("child.tcpNoDelay", true);
166 peerBootstrap.setPipelineFactory(pipelineFactory);
167 peerBootstrap.connect(connectToSocket);
168
169 boolean result;
170 // Wait until the OPEN message is received
171 result = peerFrameDecoder.receivedOpenMessageLatch.await(
172 MESSAGE_TIMEOUT_MS,
173 TimeUnit.MILLISECONDS);
174 assertThat(result, is(true));
175 // Wait until the KEEPALIVE message is received
176 result = peerFrameDecoder.receivedKeepaliveMessageLatch.await(
177 MESSAGE_TIMEOUT_MS,
178 TimeUnit.MILLISECONDS);
179 assertThat(result, is(true));
180
181 for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800182 if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER1_ID)) {
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800183 bgpSession1 = bgpSession;
184 }
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800185 if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER2_ID)) {
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800186 bgpSession2 = bgpSession;
187 }
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800188 if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER3_ID)) {
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800189 bgpSession3 = bgpSession;
190 }
191 }
192 }
193 }
194
195 /**
196 * Class that implements a matcher for BgpRouteEntry by considering
197 * the BGP peer the entry was received from.
198 */
199 private static final class BgpRouteEntryAndPeerMatcher
200 extends TypeSafeMatcher<Collection<BgpRouteEntry>> {
201 private final BgpRouteEntry bgpRouteEntry;
202
203 private BgpRouteEntryAndPeerMatcher(BgpRouteEntry bgpRouteEntry) {
204 this.bgpRouteEntry = bgpRouteEntry;
205 }
206
207 @Override
208 public boolean matchesSafely(Collection<BgpRouteEntry> entries) {
209 for (BgpRouteEntry entry : entries) {
210 if (bgpRouteEntry.equals(entry) &&
211 bgpRouteEntry.getBgpSession() == entry.getBgpSession()) {
212 return true;
213 }
214 }
215 return false;
216 }
217
218 @Override
219 public void describeTo(Description description) {
220 description.appendText("BGP route entry lookup for entry \"").
221 appendText(bgpRouteEntry.toString()).
222 appendText("\"");
223 }
224 }
225
226 /**
227 * A helper method used for testing whether a collection of
228 * BGP route entries contains an entry from a specific BGP peer.
229 *
230 * @param bgpRouteEntry the BGP route entry to test
231 * @return an instance of BgpRouteEntryAndPeerMatcher that implements
232 * the matching logic
233 */
234 private static BgpRouteEntryAndPeerMatcher hasBgpRouteEntry(
235 BgpRouteEntry bgpRouteEntry) {
236 return new BgpRouteEntryAndPeerMatcher(bgpRouteEntry);
237 }
238
Jonathan Hart20d8e512014-10-16 11:05:52 -0700239 @Before
240 public void setUp() throws Exception {
241 //
242 // Setup the BGP Session Manager to test, and start listening for BGP
243 // connections.
244 //
245 bgpSessionManager = new BgpSessionManager(dummyRouteListener);
246 // NOTE: We use port 0 to bind on any available port
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800247 bgpSessionManager.start(0);
Jonathan Hart20d8e512014-10-16 11:05:52 -0700248
249 // Get the port number the BGP Session Manager is listening on
250 Channel serverChannel = TestUtils.getField(bgpSessionManager,
251 "serverChannel");
252 SocketAddress socketAddress = serverChannel.getLocalAddress();
253 InetSocketAddress inetSocketAddress =
254 (InetSocketAddress) socketAddress;
Jonathan Hart20d8e512014-10-16 11:05:52 -0700255 InetAddress connectToAddress = InetAddresses.forString("127.0.0.1");
256 connectToSocket = new InetSocketAddress(connectToAddress,
257 inetSocketAddress.getPort());
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800258
259 //
260 // Setup the AS Paths
261 //
262 ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
263 byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
264 ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
265 segmentAsNumbers1.add((long) 65010);
266 segmentAsNumbers1.add((long) 65020);
267 segmentAsNumbers1.add((long) 65030);
268 BgpRouteEntry.PathSegment pathSegment1 =
269 new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
270 pathSegments.add(pathSegment1);
271 asPathShort = new BgpRouteEntry.AsPath(new ArrayList(pathSegments));
272 //
273 byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
274 ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
275 segmentAsNumbers2.add((long) 65041);
276 segmentAsNumbers2.add((long) 65042);
277 segmentAsNumbers2.add((long) 65043);
278 BgpRouteEntry.PathSegment pathSegment2 =
279 new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
280 pathSegments.add(pathSegment2);
281 //
282 asPathLong = new BgpRouteEntry.AsPath(pathSegments);
Jonathan Hart20d8e512014-10-16 11:05:52 -0700283 }
284
285 @After
286 public void tearDown() throws Exception {
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800287 bgpSessionManager.stop();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700288 bgpSessionManager = null;
289 }
290
291 /**
292 * Gets BGP RIB-IN routes by waiting until they are received.
293 * <p/>
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800294 * NOTE: We keep checking once every 10ms the number of received routes,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700295 * up to 5 seconds.
296 *
297 * @param bgpSession the BGP session that is expected to receive the
298 * routes
299 * @param expectedRoutes the expected number of routes
300 * @return the BGP RIB-IN routes as received within the expected
301 * time interval
302 */
303 private Collection<BgpRouteEntry> waitForBgpRibIn(BgpSession bgpSession,
304 long expectedRoutes)
305 throws InterruptedException {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800306 Collection<BgpRouteEntry> bgpRibIn = bgpSession.getBgpRibIn4();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700307
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800308 final int maxChecks = 500; // Max wait of 5 seconds
Jonathan Hart20d8e512014-10-16 11:05:52 -0700309 for (int i = 0; i < maxChecks; i++) {
310 if (bgpRibIn.size() == expectedRoutes) {
311 break;
312 }
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800313 Thread.sleep(10);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800314 bgpRibIn = bgpSession.getBgpRibIn4();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700315 }
316
317 return bgpRibIn;
318 }
319
320 /**
321 * Gets BGP merged routes by waiting until they are received.
322 * <p/>
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800323 * NOTE: We keep checking once every 10ms the number of received routes,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700324 * up to 5 seconds.
325 *
326 * @param expectedRoutes the expected number of routes
327 * @return the BGP Session Manager routes as received within the expected
328 * time interval
329 */
330 private Collection<BgpRouteEntry> waitForBgpRoutes(long expectedRoutes)
331 throws InterruptedException {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800332 Collection<BgpRouteEntry> bgpRoutes =
333 bgpSessionManager.getBgpRoutes4();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700334
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800335 final int maxChecks = 500; // Max wait of 5 seconds
Jonathan Hart20d8e512014-10-16 11:05:52 -0700336 for (int i = 0; i < maxChecks; i++) {
337 if (bgpRoutes.size() == expectedRoutes) {
338 break;
339 }
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800340 Thread.sleep(10);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800341 bgpRoutes = bgpSessionManager.getBgpRoutes4();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700342 }
343
344 return bgpRoutes;
345 }
346
347 /**
348 * Tests that the BGP OPEN messages have been exchanged, followed by
349 * KEEPALIVE.
350 * <p>
351 * The BGP Peer opens the sessions and transmits OPEN Message, eventually
352 * followed by KEEPALIVE. The tested BGP listener should respond by
353 * OPEN Message, followed by KEEPALIVE.
354 *
355 * @throws TestUtilsException TestUtils error
356 */
357 @Test
358 public void testExchangedBgpOpenMessages()
359 throws InterruptedException, TestUtilsException {
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800360 // Initiate the connections
361 peer1.connect(connectToSocket);
362 peer2.connect(connectToSocket);
363 peer3.connect(connectToSocket);
Jonathan Hart20d8e512014-10-16 11:05:52 -0700364
365 //
366 // Test the fields from the BGP OPEN message:
367 // BGP version, AS number, BGP ID
368 //
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800369 assertThat(peer1.peerFrameDecoder.remoteBgpVersion,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700370 is(BgpConstants.BGP_VERSION));
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800371 assertThat(peer1.peerFrameDecoder.remoteAs,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700372 is(TestBgpPeerChannelHandler.PEER_AS));
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800373 assertThat(peer1.peerFrameDecoder.remoteBgpIdentifier,
374 is(IP_LOOPBACK_ID));
375 assertThat(peer2.peerFrameDecoder.remoteBgpVersion,
376 is(BgpConstants.BGP_VERSION));
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));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700387
388 //
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800389 // Test that the BgpSession instances have been created
Jonathan Hart20d8e512014-10-16 11:05:52 -0700390 //
391 assertThat(bgpSessionManager.getMyBgpId(), is(IP_LOOPBACK_ID));
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800392 assertThat(bgpSessionManager.getBgpSessions(), hasSize(3));
393 assertThat(bgpSession1, notNullValue());
394 assertThat(bgpSession2, notNullValue());
395 assertThat(bgpSession3, notNullValue());
396 for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800397 long sessionAs = bgpSession.localInfo().asNumber();
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800398 assertThat(sessionAs, is(TestBgpPeerChannelHandler.PEER_AS));
399 }
Jonathan Hart20d8e512014-10-16 11:05:52 -0700400 }
401
402 /**
403 * Tests that the BGP UPDATE messages have been received and processed.
404 */
405 @Test
406 public void testProcessedBgpUpdateMessages() throws InterruptedException {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700407 ChannelBuffer message;
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800408 BgpRouteEntry bgpRouteEntry;
409 Collection<BgpRouteEntry> bgpRibIn1;
410 Collection<BgpRouteEntry> bgpRibIn2;
411 Collection<BgpRouteEntry> bgpRibIn3;
Jonathan Hart20d8e512014-10-16 11:05:52 -0700412 Collection<BgpRouteEntry> bgpRoutes;
413
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800414 // Initiate the connections
415 peer1.connect(connectToSocket);
416 peer2.connect(connectToSocket);
417 peer3.connect(connectToSocket);
Jonathan Hart20d8e512014-10-16 11:05:52 -0700418
419 // Prepare routes to add/delete
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800420 Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
421 Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800422
423 //
424 // Add and delete some routes
425 //
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800426 addedRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
427 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
428 addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
429 addedRoutes.add(Ip4Prefix.valueOf("40.0.0.0/24"));
430 addedRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
431 withdrawnRoutes.add(Ip4Prefix.valueOf("60.0.0.0/8"));
432 withdrawnRoutes.add(Ip4Prefix.valueOf("70.0.0.0/16"));
433 withdrawnRoutes.add(Ip4Prefix.valueOf("80.0.0.0/24"));
434 withdrawnRoutes.add(Ip4Prefix.valueOf("90.0.0.0/32"));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700435 // Write the routes
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800436 message = peer1.peerChannelHandler.prepareBgpUpdate(
437 NEXT_HOP1_ROUTER,
438 DEFAULT_LOCAL_PREF,
439 DEFAULT_MULTI_EXIT_DISC,
440 asPathLong,
441 addedRoutes,
442 withdrawnRoutes);
443 peer1.peerChannelHandler.savedCtx.getChannel().write(message);
444 //
Jonathan Hart20d8e512014-10-16 11:05:52 -0700445 // Check that the routes have been received, processed and stored
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800446 //
447 bgpRibIn1 = waitForBgpRibIn(bgpSession1, 5);
448 assertThat(bgpRibIn1, hasSize(5));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700449 bgpRoutes = waitForBgpRoutes(5);
450 assertThat(bgpRoutes, hasSize(5));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700451 //
452 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800453 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800454 Ip4Prefix.valueOf("0.0.0.0/0"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800455 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700456 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800457 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700458 DEFAULT_LOCAL_PREF);
459 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800460 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
461 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700462 //
463 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800464 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800465 Ip4Prefix.valueOf("20.0.0.0/8"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800466 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700467 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800468 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700469 DEFAULT_LOCAL_PREF);
470 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800471 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
472 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700473 //
474 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800475 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800476 Ip4Prefix.valueOf("30.0.0.0/16"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800477 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700478 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800479 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700480 DEFAULT_LOCAL_PREF);
481 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800482 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
483 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700484 //
485 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800486 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800487 Ip4Prefix.valueOf("40.0.0.0/24"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800488 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700489 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800490 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700491 DEFAULT_LOCAL_PREF);
492 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800493 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
494 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700495 //
496 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800497 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800498 Ip4Prefix.valueOf("50.0.0.0/32"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800499 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700500 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800501 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700502 DEFAULT_LOCAL_PREF);
503 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800504 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
505 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700506
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800507 //
Jonathan Hart20d8e512014-10-16 11:05:52 -0700508 // Delete some routes
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800509 //
Jonathan Hart20d8e512014-10-16 11:05:52 -0700510 addedRoutes = new LinkedList<>();
511 withdrawnRoutes = new LinkedList<>();
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800512 withdrawnRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
513 withdrawnRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700514 // Write the routes
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800515 message = peer1.peerChannelHandler.prepareBgpUpdate(
516 NEXT_HOP1_ROUTER,
517 DEFAULT_LOCAL_PREF,
518 DEFAULT_MULTI_EXIT_DISC,
519 asPathLong,
520 addedRoutes,
521 withdrawnRoutes);
522 peer1.peerChannelHandler.savedCtx.getChannel().write(message);
523 //
Jonathan Hart20d8e512014-10-16 11:05:52 -0700524 // Check that the routes have been received, processed and stored
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800525 //
526 bgpRibIn1 = waitForBgpRibIn(bgpSession1, 3);
527 assertThat(bgpRibIn1, hasSize(3));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700528 bgpRoutes = waitForBgpRoutes(3);
529 assertThat(bgpRoutes, hasSize(3));
530 //
531 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800532 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800533 Ip4Prefix.valueOf("20.0.0.0/8"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800534 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700535 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800536 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700537 DEFAULT_LOCAL_PREF);
538 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800539 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
540 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700541 //
542 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800543 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800544 Ip4Prefix.valueOf("30.0.0.0/16"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800545 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700546 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800547 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700548 DEFAULT_LOCAL_PREF);
549 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800550 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
551 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700552 //
553 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800554 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800555 Ip4Prefix.valueOf("40.0.0.0/24"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800556 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700557 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800558 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700559 DEFAULT_LOCAL_PREF);
560 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800561 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
562 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700563
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800564
565 // Close the channels and test there are no routes
566 peer1.peerChannelHandler.closeChannel();
567 peer2.peerChannelHandler.closeChannel();
568 peer3.peerChannelHandler.closeChannel();
569 bgpRoutes = waitForBgpRoutes(0);
570 assertThat(bgpRoutes, hasSize(0));
571 }
572
573 /**
574 * Tests the BGP route preference.
575 */
576 @Test
577 public void testBgpRoutePreference() throws InterruptedException {
578 ChannelBuffer message;
579 BgpRouteEntry bgpRouteEntry;
580 Collection<BgpRouteEntry> bgpRibIn1;
581 Collection<BgpRouteEntry> bgpRibIn2;
582 Collection<BgpRouteEntry> bgpRibIn3;
583 Collection<BgpRouteEntry> bgpRoutes;
584 Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
585 Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
586
587 // Initiate the connections
588 peer1.connect(connectToSocket);
589 peer2.connect(connectToSocket);
590 peer3.connect(connectToSocket);
591
592 //
593 // Setup the initial set of routes to Peer1
594 //
595 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
596 addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
597 // Write the routes
598 message = peer1.peerChannelHandler.prepareBgpUpdate(
599 NEXT_HOP1_ROUTER,
600 DEFAULT_LOCAL_PREF,
601 DEFAULT_MULTI_EXIT_DISC,
602 asPathLong,
603 addedRoutes,
604 withdrawnRoutes);
605 peer1.peerChannelHandler.savedCtx.getChannel().write(message);
606 bgpRoutes = waitForBgpRoutes(2);
607 assertThat(bgpRoutes, hasSize(2));
608
609 //
610 // Add a route entry to Peer2 with a better LOCAL_PREF
611 //
612 addedRoutes = new LinkedList<>();
613 withdrawnRoutes = new LinkedList<>();
614 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
615 // Write the routes
616 message = peer2.peerChannelHandler.prepareBgpUpdate(
617 NEXT_HOP2_ROUTER,
618 BETTER_LOCAL_PREF,
619 DEFAULT_MULTI_EXIT_DISC,
620 asPathLong,
621 addedRoutes,
622 withdrawnRoutes);
623 peer2.peerChannelHandler.savedCtx.getChannel().write(message);
624 //
625 // Check that the routes have been received, processed and stored
626 //
627 bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
628 assertThat(bgpRibIn2, hasSize(1));
629 bgpRoutes = waitForBgpRoutes(2);
630 assertThat(bgpRoutes, hasSize(2));
631 //
632 bgpRouteEntry =
633 new BgpRouteEntry(bgpSession2,
634 Ip4Prefix.valueOf("20.0.0.0/8"),
635 NEXT_HOP2_ROUTER,
636 (byte) BgpConstants.Update.Origin.IGP,
637 asPathLong,
638 BETTER_LOCAL_PREF);
639 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
640 assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
641 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
642
643 //
644 // Add a route entry to Peer3 with a shorter AS path
645 //
646 addedRoutes = new LinkedList<>();
647 withdrawnRoutes = new LinkedList<>();
648 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
649 // Write the routes
650 message = peer3.peerChannelHandler.prepareBgpUpdate(
651 NEXT_HOP3_ROUTER,
652 BETTER_LOCAL_PREF,
653 DEFAULT_MULTI_EXIT_DISC,
654 asPathShort,
655 addedRoutes,
656 withdrawnRoutes);
657 peer3.peerChannelHandler.savedCtx.getChannel().write(message);
658 //
659 // Check that the routes have been received, processed and stored
660 //
661 bgpRibIn3 = waitForBgpRibIn(bgpSession3, 1);
662 assertThat(bgpRibIn3, hasSize(1));
663 bgpRoutes = waitForBgpRoutes(2);
664 assertThat(bgpRoutes, hasSize(2));
665 //
666 bgpRouteEntry =
667 new BgpRouteEntry(bgpSession3,
668 Ip4Prefix.valueOf("20.0.0.0/8"),
669 NEXT_HOP3_ROUTER,
670 (byte) BgpConstants.Update.Origin.IGP,
671 asPathShort,
672 BETTER_LOCAL_PREF);
673 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
674 assertThat(bgpRibIn3, hasBgpRouteEntry(bgpRouteEntry));
675 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
676
677 //
678 // Cleanup in preparation for next test: delete old route entry from
679 // Peer2
680 //
681 addedRoutes = new LinkedList<>();
682 withdrawnRoutes = new LinkedList<>();
683 withdrawnRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
684 // Write the routes
685 message = peer2.peerChannelHandler.prepareBgpUpdate(
686 NEXT_HOP2_ROUTER,
687 BETTER_LOCAL_PREF,
688 BETTER_MULTI_EXIT_DISC,
689 asPathShort,
690 addedRoutes,
691 withdrawnRoutes);
692 peer2.peerChannelHandler.savedCtx.getChannel().write(message);
693 //
694 // Check that the routes have been received, processed and stored
695 //
696 bgpRibIn2 = waitForBgpRibIn(bgpSession2, 0);
697 assertThat(bgpRibIn2, hasSize(0));
698
699 //
700 // Add a route entry to Peer2 with a better MED
701 //
702 addedRoutes = new LinkedList<>();
703 withdrawnRoutes = new LinkedList<>();
704 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
705 // Write the routes
706 message = peer2.peerChannelHandler.prepareBgpUpdate(
707 NEXT_HOP2_ROUTER,
708 BETTER_LOCAL_PREF,
709 BETTER_MULTI_EXIT_DISC,
710 asPathShort,
711 addedRoutes,
712 withdrawnRoutes);
713 peer2.peerChannelHandler.savedCtx.getChannel().write(message);
714 //
715 // Check that the routes have been received, processed and stored
716 //
717 bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
718 assertThat(bgpRibIn2, hasSize(1));
719 bgpRoutes = waitForBgpRoutes(2);
720 assertThat(bgpRoutes, hasSize(2));
721 //
722 bgpRouteEntry =
723 new BgpRouteEntry(bgpSession2,
724 Ip4Prefix.valueOf("20.0.0.0/8"),
725 NEXT_HOP2_ROUTER,
726 (byte) BgpConstants.Update.Origin.IGP,
727 asPathShort,
728 BETTER_LOCAL_PREF);
729 bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
730 assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
731 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
732
733 //
734 // Add a route entry to Peer1 with a better (lower) BGP ID
735 //
736 addedRoutes = new LinkedList<>();
737 withdrawnRoutes = new LinkedList<>();
738 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
739 withdrawnRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
740 // Write the routes
741 message = peer1.peerChannelHandler.prepareBgpUpdate(
742 NEXT_HOP1_ROUTER,
743 BETTER_LOCAL_PREF,
744 BETTER_MULTI_EXIT_DISC,
745 asPathShort,
746 addedRoutes,
747 withdrawnRoutes);
748 peer1.peerChannelHandler.savedCtx.getChannel().write(message);
749 //
750 // Check that the routes have been received, processed and stored
751 //
752 bgpRibIn1 = waitForBgpRibIn(bgpSession1, 1);
753 assertThat(bgpRibIn1, hasSize(1));
754 bgpRoutes = waitForBgpRoutes(1);
755 assertThat(bgpRoutes, hasSize(1));
756 //
757 bgpRouteEntry =
758 new BgpRouteEntry(bgpSession1,
759 Ip4Prefix.valueOf("20.0.0.0/8"),
760 NEXT_HOP1_ROUTER,
761 (byte) BgpConstants.Update.Origin.IGP,
762 asPathShort,
763 BETTER_LOCAL_PREF);
764 bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
765 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
766 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
767
768
769 // Close the channels and test there are no routes
770 peer1.peerChannelHandler.closeChannel();
771 peer2.peerChannelHandler.closeChannel();
772 peer3.peerChannelHandler.closeChannel();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700773 bgpRoutes = waitForBgpRoutes(0);
774 assertThat(bgpRoutes, hasSize(0));
775 }
776}