blob: 5199f20e059d8205a2818b54d109be077ad5156a [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()) {
182 if (bgpSession.getRemoteBgpId().equals(BGP_PEER1_ID)) {
183 bgpSession1 = bgpSession;
184 }
185 if (bgpSession.getRemoteBgpId().equals(BGP_PEER2_ID)) {
186 bgpSession2 = bgpSession;
187 }
188 if (bgpSession.getRemoteBgpId().equals(BGP_PEER3_ID)) {
189 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 {
306 Collection<BgpRouteEntry> bgpRibIn = bgpSession.getBgpRibIn();
307
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);
Jonathan Hart20d8e512014-10-16 11:05:52 -0700314 bgpRibIn = bgpSession.getBgpRibIn();
315 }
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 {
332 Collection<BgpRouteEntry> bgpRoutes = bgpSessionManager.getBgpRoutes();
333
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800334 final int maxChecks = 500; // Max wait of 5 seconds
Jonathan Hart20d8e512014-10-16 11:05:52 -0700335 for (int i = 0; i < maxChecks; i++) {
336 if (bgpRoutes.size() == expectedRoutes) {
337 break;
338 }
Pavlin Radoslavov55b5f512014-12-08 09:59:35 -0800339 Thread.sleep(10);
Jonathan Hart20d8e512014-10-16 11:05:52 -0700340 bgpRoutes = bgpSessionManager.getBgpRoutes();
341 }
342
343 return bgpRoutes;
344 }
345
346 /**
347 * Tests that the BGP OPEN messages have been exchanged, followed by
348 * KEEPALIVE.
349 * <p>
350 * The BGP Peer opens the sessions and transmits OPEN Message, eventually
351 * followed by KEEPALIVE. The tested BGP listener should respond by
352 * OPEN Message, followed by KEEPALIVE.
353 *
354 * @throws TestUtilsException TestUtils error
355 */
356 @Test
357 public void testExchangedBgpOpenMessages()
358 throws InterruptedException, TestUtilsException {
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800359 // Initiate the connections
360 peer1.connect(connectToSocket);
361 peer2.connect(connectToSocket);
362 peer3.connect(connectToSocket);
Jonathan Hart20d8e512014-10-16 11:05:52 -0700363
364 //
365 // Test the fields from the BGP OPEN message:
366 // BGP version, AS number, BGP ID
367 //
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800368 assertThat(peer1.peerFrameDecoder.remoteBgpVersion,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700369 is(BgpConstants.BGP_VERSION));
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800370 assertThat(peer1.peerFrameDecoder.remoteAs,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700371 is(TestBgpPeerChannelHandler.PEER_AS));
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800372 assertThat(peer1.peerFrameDecoder.remoteBgpIdentifier,
373 is(IP_LOOPBACK_ID));
374 assertThat(peer2.peerFrameDecoder.remoteBgpVersion,
375 is(BgpConstants.BGP_VERSION));
376 assertThat(peer2.peerFrameDecoder.remoteAs,
377 is(TestBgpPeerChannelHandler.PEER_AS));
378 assertThat(peer2.peerFrameDecoder.remoteBgpIdentifier,
379 is(IP_LOOPBACK_ID));
380 assertThat(peer3.peerFrameDecoder.remoteBgpVersion,
381 is(BgpConstants.BGP_VERSION));
382 assertThat(peer3.peerFrameDecoder.remoteAs,
383 is(TestBgpPeerChannelHandler.PEER_AS));
384 assertThat(peer3.peerFrameDecoder.remoteBgpIdentifier,
385 is(IP_LOOPBACK_ID));
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()) {
396 long sessionAs = TestUtils.getField(bgpSession, "localAs");
397 assertThat(sessionAs, is(TestBgpPeerChannelHandler.PEER_AS));
398 }
Jonathan Hart20d8e512014-10-16 11:05:52 -0700399 }
400
401 /**
402 * Tests that the BGP UPDATE messages have been received and processed.
403 */
404 @Test
405 public void testProcessedBgpUpdateMessages() throws InterruptedException {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700406 ChannelBuffer message;
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800407 BgpRouteEntry bgpRouteEntry;
408 Collection<BgpRouteEntry> bgpRibIn1;
409 Collection<BgpRouteEntry> bgpRibIn2;
410 Collection<BgpRouteEntry> bgpRibIn3;
Jonathan Hart20d8e512014-10-16 11:05:52 -0700411 Collection<BgpRouteEntry> bgpRoutes;
412
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800413 // Initiate the connections
414 peer1.connect(connectToSocket);
415 peer2.connect(connectToSocket);
416 peer3.connect(connectToSocket);
Jonathan Hart20d8e512014-10-16 11:05:52 -0700417
418 // Prepare routes to add/delete
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800419 Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
420 Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800421
422 //
423 // Add and delete some routes
424 //
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800425 addedRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
426 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
427 addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
428 addedRoutes.add(Ip4Prefix.valueOf("40.0.0.0/24"));
429 addedRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
430 withdrawnRoutes.add(Ip4Prefix.valueOf("60.0.0.0/8"));
431 withdrawnRoutes.add(Ip4Prefix.valueOf("70.0.0.0/16"));
432 withdrawnRoutes.add(Ip4Prefix.valueOf("80.0.0.0/24"));
433 withdrawnRoutes.add(Ip4Prefix.valueOf("90.0.0.0/32"));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700434 // Write the routes
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800435 message = peer1.peerChannelHandler.prepareBgpUpdate(
436 NEXT_HOP1_ROUTER,
437 DEFAULT_LOCAL_PREF,
438 DEFAULT_MULTI_EXIT_DISC,
439 asPathLong,
440 addedRoutes,
441 withdrawnRoutes);
442 peer1.peerChannelHandler.savedCtx.getChannel().write(message);
443 //
Jonathan Hart20d8e512014-10-16 11:05:52 -0700444 // Check that the routes have been received, processed and stored
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800445 //
446 bgpRibIn1 = waitForBgpRibIn(bgpSession1, 5);
447 assertThat(bgpRibIn1, hasSize(5));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700448 bgpRoutes = waitForBgpRoutes(5);
449 assertThat(bgpRoutes, hasSize(5));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700450 //
451 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800452 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800453 Ip4Prefix.valueOf("0.0.0.0/0"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800454 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700455 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800456 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700457 DEFAULT_LOCAL_PREF);
458 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800459 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
460 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700461 //
462 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800463 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800464 Ip4Prefix.valueOf("20.0.0.0/8"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800465 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700466 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800467 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700468 DEFAULT_LOCAL_PREF);
469 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800470 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
471 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700472 //
473 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800474 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800475 Ip4Prefix.valueOf("30.0.0.0/16"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800476 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700477 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800478 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700479 DEFAULT_LOCAL_PREF);
480 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800481 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
482 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700483 //
484 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800485 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800486 Ip4Prefix.valueOf("40.0.0.0/24"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800487 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700488 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800489 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700490 DEFAULT_LOCAL_PREF);
491 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800492 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
493 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700494 //
495 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800496 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800497 Ip4Prefix.valueOf("50.0.0.0/32"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800498 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700499 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800500 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700501 DEFAULT_LOCAL_PREF);
502 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800503 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
504 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700505
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800506 //
Jonathan Hart20d8e512014-10-16 11:05:52 -0700507 // Delete some routes
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800508 //
Jonathan Hart20d8e512014-10-16 11:05:52 -0700509 addedRoutes = new LinkedList<>();
510 withdrawnRoutes = new LinkedList<>();
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800511 withdrawnRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
512 withdrawnRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700513 // Write the routes
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800514 message = peer1.peerChannelHandler.prepareBgpUpdate(
515 NEXT_HOP1_ROUTER,
516 DEFAULT_LOCAL_PREF,
517 DEFAULT_MULTI_EXIT_DISC,
518 asPathLong,
519 addedRoutes,
520 withdrawnRoutes);
521 peer1.peerChannelHandler.savedCtx.getChannel().write(message);
522 //
Jonathan Hart20d8e512014-10-16 11:05:52 -0700523 // Check that the routes have been received, processed and stored
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800524 //
525 bgpRibIn1 = waitForBgpRibIn(bgpSession1, 3);
526 assertThat(bgpRibIn1, hasSize(3));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700527 bgpRoutes = waitForBgpRoutes(3);
528 assertThat(bgpRoutes, hasSize(3));
529 //
530 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800531 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800532 Ip4Prefix.valueOf("20.0.0.0/8"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800533 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700534 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800535 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700536 DEFAULT_LOCAL_PREF);
537 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800538 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
539 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700540 //
541 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800542 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800543 Ip4Prefix.valueOf("30.0.0.0/16"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800544 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700545 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800546 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700547 DEFAULT_LOCAL_PREF);
548 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800549 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
550 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700551 //
552 bgpRouteEntry =
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800553 new BgpRouteEntry(bgpSession1,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800554 Ip4Prefix.valueOf("40.0.0.0/24"),
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800555 NEXT_HOP1_ROUTER,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700556 (byte) BgpConstants.Update.Origin.IGP,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800557 asPathLong,
Jonathan Hart20d8e512014-10-16 11:05:52 -0700558 DEFAULT_LOCAL_PREF);
559 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800560 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
561 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
Jonathan Hart20d8e512014-10-16 11:05:52 -0700562
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800563
564 // Close the channels and test there are no routes
565 peer1.peerChannelHandler.closeChannel();
566 peer2.peerChannelHandler.closeChannel();
567 peer3.peerChannelHandler.closeChannel();
568 bgpRoutes = waitForBgpRoutes(0);
569 assertThat(bgpRoutes, hasSize(0));
570 }
571
572 /**
573 * Tests the BGP route preference.
574 */
575 @Test
576 public void testBgpRoutePreference() throws InterruptedException {
577 ChannelBuffer message;
578 BgpRouteEntry bgpRouteEntry;
579 Collection<BgpRouteEntry> bgpRibIn1;
580 Collection<BgpRouteEntry> bgpRibIn2;
581 Collection<BgpRouteEntry> bgpRibIn3;
582 Collection<BgpRouteEntry> bgpRoutes;
583 Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
584 Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
585
586 // Initiate the connections
587 peer1.connect(connectToSocket);
588 peer2.connect(connectToSocket);
589 peer3.connect(connectToSocket);
590
591 //
592 // Setup the initial set of routes to Peer1
593 //
594 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
595 addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
596 // Write the routes
597 message = peer1.peerChannelHandler.prepareBgpUpdate(
598 NEXT_HOP1_ROUTER,
599 DEFAULT_LOCAL_PREF,
600 DEFAULT_MULTI_EXIT_DISC,
601 asPathLong,
602 addedRoutes,
603 withdrawnRoutes);
604 peer1.peerChannelHandler.savedCtx.getChannel().write(message);
605 bgpRoutes = waitForBgpRoutes(2);
606 assertThat(bgpRoutes, hasSize(2));
607
608 //
609 // Add a route entry to Peer2 with a better LOCAL_PREF
610 //
611 addedRoutes = new LinkedList<>();
612 withdrawnRoutes = new LinkedList<>();
613 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
614 // Write the routes
615 message = peer2.peerChannelHandler.prepareBgpUpdate(
616 NEXT_HOP2_ROUTER,
617 BETTER_LOCAL_PREF,
618 DEFAULT_MULTI_EXIT_DISC,
619 asPathLong,
620 addedRoutes,
621 withdrawnRoutes);
622 peer2.peerChannelHandler.savedCtx.getChannel().write(message);
623 //
624 // Check that the routes have been received, processed and stored
625 //
626 bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
627 assertThat(bgpRibIn2, hasSize(1));
628 bgpRoutes = waitForBgpRoutes(2);
629 assertThat(bgpRoutes, hasSize(2));
630 //
631 bgpRouteEntry =
632 new BgpRouteEntry(bgpSession2,
633 Ip4Prefix.valueOf("20.0.0.0/8"),
634 NEXT_HOP2_ROUTER,
635 (byte) BgpConstants.Update.Origin.IGP,
636 asPathLong,
637 BETTER_LOCAL_PREF);
638 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
639 assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
640 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
641
642 //
643 // Add a route entry to Peer3 with a shorter AS path
644 //
645 addedRoutes = new LinkedList<>();
646 withdrawnRoutes = new LinkedList<>();
647 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
648 // Write the routes
649 message = peer3.peerChannelHandler.prepareBgpUpdate(
650 NEXT_HOP3_ROUTER,
651 BETTER_LOCAL_PREF,
652 DEFAULT_MULTI_EXIT_DISC,
653 asPathShort,
654 addedRoutes,
655 withdrawnRoutes);
656 peer3.peerChannelHandler.savedCtx.getChannel().write(message);
657 //
658 // Check that the routes have been received, processed and stored
659 //
660 bgpRibIn3 = waitForBgpRibIn(bgpSession3, 1);
661 assertThat(bgpRibIn3, hasSize(1));
662 bgpRoutes = waitForBgpRoutes(2);
663 assertThat(bgpRoutes, hasSize(2));
664 //
665 bgpRouteEntry =
666 new BgpRouteEntry(bgpSession3,
667 Ip4Prefix.valueOf("20.0.0.0/8"),
668 NEXT_HOP3_ROUTER,
669 (byte) BgpConstants.Update.Origin.IGP,
670 asPathShort,
671 BETTER_LOCAL_PREF);
672 bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
673 assertThat(bgpRibIn3, hasBgpRouteEntry(bgpRouteEntry));
674 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
675
676 //
677 // Cleanup in preparation for next test: delete old route entry from
678 // Peer2
679 //
680 addedRoutes = new LinkedList<>();
681 withdrawnRoutes = new LinkedList<>();
682 withdrawnRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
683 // Write the routes
684 message = peer2.peerChannelHandler.prepareBgpUpdate(
685 NEXT_HOP2_ROUTER,
686 BETTER_LOCAL_PREF,
687 BETTER_MULTI_EXIT_DISC,
688 asPathShort,
689 addedRoutes,
690 withdrawnRoutes);
691 peer2.peerChannelHandler.savedCtx.getChannel().write(message);
692 //
693 // Check that the routes have been received, processed and stored
694 //
695 bgpRibIn2 = waitForBgpRibIn(bgpSession2, 0);
696 assertThat(bgpRibIn2, hasSize(0));
697
698 //
699 // Add a route entry to Peer2 with a better MED
700 //
701 addedRoutes = new LinkedList<>();
702 withdrawnRoutes = new LinkedList<>();
703 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
704 // Write the routes
705 message = peer2.peerChannelHandler.prepareBgpUpdate(
706 NEXT_HOP2_ROUTER,
707 BETTER_LOCAL_PREF,
708 BETTER_MULTI_EXIT_DISC,
709 asPathShort,
710 addedRoutes,
711 withdrawnRoutes);
712 peer2.peerChannelHandler.savedCtx.getChannel().write(message);
713 //
714 // Check that the routes have been received, processed and stored
715 //
716 bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
717 assertThat(bgpRibIn2, hasSize(1));
718 bgpRoutes = waitForBgpRoutes(2);
719 assertThat(bgpRoutes, hasSize(2));
720 //
721 bgpRouteEntry =
722 new BgpRouteEntry(bgpSession2,
723 Ip4Prefix.valueOf("20.0.0.0/8"),
724 NEXT_HOP2_ROUTER,
725 (byte) BgpConstants.Update.Origin.IGP,
726 asPathShort,
727 BETTER_LOCAL_PREF);
728 bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
729 assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
730 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
731
732 //
733 // Add a route entry to Peer1 with a better (lower) BGP ID
734 //
735 addedRoutes = new LinkedList<>();
736 withdrawnRoutes = new LinkedList<>();
737 addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
738 withdrawnRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
739 // Write the routes
740 message = peer1.peerChannelHandler.prepareBgpUpdate(
741 NEXT_HOP1_ROUTER,
742 BETTER_LOCAL_PREF,
743 BETTER_MULTI_EXIT_DISC,
744 asPathShort,
745 addedRoutes,
746 withdrawnRoutes);
747 peer1.peerChannelHandler.savedCtx.getChannel().write(message);
748 //
749 // Check that the routes have been received, processed and stored
750 //
751 bgpRibIn1 = waitForBgpRibIn(bgpSession1, 1);
752 assertThat(bgpRibIn1, hasSize(1));
753 bgpRoutes = waitForBgpRoutes(1);
754 assertThat(bgpRoutes, hasSize(1));
755 //
756 bgpRouteEntry =
757 new BgpRouteEntry(bgpSession1,
758 Ip4Prefix.valueOf("20.0.0.0/8"),
759 NEXT_HOP1_ROUTER,
760 (byte) BgpConstants.Update.Origin.IGP,
761 asPathShort,
762 BETTER_LOCAL_PREF);
763 bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
764 assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
765 assertThat(bgpRoutes, hasBgpRouteEntry(bgpRouteEntry));
766
767
768 // Close the channels and test there are no routes
769 peer1.peerChannelHandler.closeChannel();
770 peer2.peerChannelHandler.closeChannel();
771 peer3.peerChannelHandler.closeChannel();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700772 bgpRoutes = waitForBgpRoutes(0);
773 assertThat(bgpRoutes, hasSize(0));
774 }
775}