634e87b9480f40ea05d3c1f4e87fdddb0e8c014e
[onosfw.git] /
1 /*
2  * Copyright 2014-2015 Open Networking Laboratory
3  *
4  * 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
7  *
8  *     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.
15  */
16 package org.onosproject.routing.bgp;
17
18 import com.google.common.net.InetAddresses;
19 import org.hamcrest.Description;
20 import org.hamcrest.TypeSafeMatcher;
21 import org.jboss.netty.bootstrap.ClientBootstrap;
22 import org.jboss.netty.buffer.ChannelBuffer;
23 import org.jboss.netty.channel.Channel;
24 import org.jboss.netty.channel.ChannelFactory;
25 import org.jboss.netty.channel.ChannelPipeline;
26 import org.jboss.netty.channel.ChannelPipelineFactory;
27 import org.jboss.netty.channel.Channels;
28 import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
29 import org.junit.After;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.onlab.junit.TestUtils;
33 import org.onlab.junit.TestUtils.TestUtilsException;
34 import org.onlab.packet.Ip4Address;
35 import org.onlab.packet.Ip4Prefix;
36 import org.onosproject.routing.RouteListener;
37 import org.onosproject.routing.RouteUpdate;
38 import org.osgi.service.component.ComponentContext;
39
40 import java.net.InetAddress;
41 import java.net.InetSocketAddress;
42 import java.net.SocketAddress;
43 import java.util.ArrayList;
44 import java.util.Collection;
45 import java.util.Dictionary;
46 import java.util.LinkedList;
47 import java.util.concurrent.Executors;
48 import java.util.concurrent.TimeUnit;
49
50 import static org.easymock.EasyMock.createMock;
51 import static org.easymock.EasyMock.expect;
52 import static org.easymock.EasyMock.replay;
53 import static org.hamcrest.Matchers.hasSize;
54 import static org.hamcrest.Matchers.is;
55 import static org.hamcrest.Matchers.notNullValue;
56 import static org.junit.Assert.assertThat;
57
58 /**
59  * Unit tests for the BgpSessionManager class.
60  */
61 public class BgpSessionManagerTest {
62     private static final Ip4Address IP_LOOPBACK_ID =
63         Ip4Address.valueOf("127.0.0.1");
64     private static final Ip4Address BGP_PEER1_ID =
65         Ip4Address.valueOf("10.0.0.1");
66     private static final Ip4Address BGP_PEER2_ID =
67         Ip4Address.valueOf("10.0.0.2");
68     private static final Ip4Address BGP_PEER3_ID =
69         Ip4Address.valueOf("10.0.0.3");
70     private static final Ip4Address NEXT_HOP1_ROUTER =
71         Ip4Address.valueOf("10.20.30.41");
72     private static final Ip4Address NEXT_HOP2_ROUTER =
73         Ip4Address.valueOf("10.20.30.42");
74     private static final Ip4Address NEXT_HOP3_ROUTER =
75         Ip4Address.valueOf("10.20.30.43");
76
77     private static final long DEFAULT_LOCAL_PREF = 10;
78     private static final long BETTER_LOCAL_PREF = 20;
79     private static final long DEFAULT_MULTI_EXIT_DISC = 20;
80     private static final long BETTER_MULTI_EXIT_DISC = 30;
81
82     BgpRouteEntry.AsPath asPathShort;
83     BgpRouteEntry.AsPath asPathLong;
84
85     // Timeout waiting for a message to be received
86     private static final int MESSAGE_TIMEOUT_MS = 5000; // 5s
87
88     // The BGP Session Manager to test
89     private BgpSessionManager bgpSessionManager;
90
91     // Remote Peer state
92     private final Collection<TestBgpPeer> peers = new LinkedList<>();
93     TestBgpPeer peer1;
94     TestBgpPeer peer2;
95     TestBgpPeer peer3;
96
97     // Local BGP per-peer session state
98     BgpSession bgpSession1;
99     BgpSession bgpSession2;
100     BgpSession bgpSession3;
101
102     // The socket that the remote peers should connect to
103     private InetSocketAddress connectToSocket;
104
105     private final DummyRouteListener dummyRouteListener =
106         new DummyRouteListener();
107
108     /**
109      * Dummy implementation for the RouteListener interface.
110      */
111     private class DummyRouteListener implements RouteListener {
112         @Override
113         public void update(Collection<RouteUpdate> routeUpdate) {
114             // Nothing to do
115         }
116     }
117
118     /**
119      * A class to capture the state for a BGP peer.
120      */
121     private final class TestBgpPeer {
122         private final Ip4Address peerId;
123         private ClientBootstrap peerBootstrap;
124         private TestBgpPeerChannelHandler peerChannelHandler;
125         private TestBgpPeerFrameDecoder peerFrameDecoder =
126             new TestBgpPeerFrameDecoder();
127
128         /**
129          * Constructor.
130          *
131          * @param peerId the peer ID
132          */
133         private TestBgpPeer(Ip4Address peerId) {
134             this.peerId = peerId;
135             peerChannelHandler = new TestBgpPeerChannelHandler(peerId);
136         }
137
138         /**
139          * Starts up the BGP peer and connects it to the tested SDN-IP
140          * instance.
141          *
142          * @param connectToSocket the socket to connect to
143          */
144         private void connect(InetSocketAddress connectToSocket)
145             throws InterruptedException {
146             //
147             // Setup the BGP Peer, i.e., the "remote" BGP router that will
148             // initiate the BGP connection, send BGP UPDATE messages, etc.
149             //
150             ChannelFactory channelFactory =
151                 new NioClientSocketChannelFactory(
152                         Executors.newCachedThreadPool(),
153                         Executors.newCachedThreadPool());
154             ChannelPipelineFactory pipelineFactory =
155                 new ChannelPipelineFactory() {
156                     @Override
157                     public ChannelPipeline getPipeline() throws Exception {
158                         // Setup the transmitting pipeline
159                         ChannelPipeline pipeline = Channels.pipeline();
160                         pipeline.addLast("TestBgpPeerFrameDecoder",
161                                          peerFrameDecoder);
162                         pipeline.addLast("TestBgpPeerChannelHandler",
163                                          peerChannelHandler);
164                         return pipeline;
165                     }
166                 };
167
168             peerBootstrap = new ClientBootstrap(channelFactory);
169             peerBootstrap.setOption("child.keepAlive", true);
170             peerBootstrap.setOption("child.tcpNoDelay", true);
171             peerBootstrap.setPipelineFactory(pipelineFactory);
172             peerBootstrap.connect(connectToSocket);
173
174             boolean result;
175             // Wait until the OPEN message is received
176             result = peerFrameDecoder.receivedOpenMessageLatch.await(
177                 MESSAGE_TIMEOUT_MS,
178                 TimeUnit.MILLISECONDS);
179             assertThat(result, is(true));
180             // Wait until the KEEPALIVE message is received
181             result = peerFrameDecoder.receivedKeepaliveMessageLatch.await(
182                 MESSAGE_TIMEOUT_MS,
183                 TimeUnit.MILLISECONDS);
184             assertThat(result, is(true));
185
186             for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
187                 if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER1_ID)) {
188                     bgpSession1 = bgpSession;
189                 }
190                 if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER2_ID)) {
191                     bgpSession2 = bgpSession;
192                 }
193                 if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER3_ID)) {
194                     bgpSession3 = bgpSession;
195                 }
196             }
197         }
198     }
199
200     /**
201      * Class that implements a matcher for BgpRouteEntry by considering
202      * the BGP peer the entry was received from.
203      */
204     private static final class BgpRouteEntryAndPeerMatcher
205         extends TypeSafeMatcher<Collection<BgpRouteEntry>> {
206         private final BgpRouteEntry bgpRouteEntry;
207
208         private BgpRouteEntryAndPeerMatcher(BgpRouteEntry bgpRouteEntry) {
209             this.bgpRouteEntry = bgpRouteEntry;
210         }
211
212         @Override
213         public boolean matchesSafely(Collection<BgpRouteEntry> entries) {
214             for (BgpRouteEntry entry : entries) {
215                 if (bgpRouteEntry.equals(entry) &&
216                     bgpRouteEntry.getBgpSession() == entry.getBgpSession()) {
217                     return true;
218                 }
219             }
220             return false;
221         }
222
223         @Override
224         public void describeTo(Description description) {
225             description.appendText("BGP route entry lookup for entry \"").
226                 appendText(bgpRouteEntry.toString()).
227                 appendText("\"");
228         }
229     }
230
231     /**
232      * A helper method used for testing whether a collection of
233      * BGP route entries contains an entry from a specific BGP peer.
234      *
235      * @param bgpRouteEntry the BGP route entry to test
236      * @return an instance of BgpRouteEntryAndPeerMatcher that implements
237      * the matching logic
238      */
239     private static BgpRouteEntryAndPeerMatcher hasBgpRouteEntry(
240         BgpRouteEntry bgpRouteEntry) {
241         return new BgpRouteEntryAndPeerMatcher(bgpRouteEntry);
242     }
243
244     @SuppressWarnings("unchecked")
245     private Dictionary<String, String>
246             getDictionaryMock(ComponentContext componentContext) {
247         Dictionary<String, String> dictionary = createMock(Dictionary.class);
248         expect(dictionary.get("bgpPort")).andReturn("0");
249         replay(dictionary);
250         expect(componentContext.getProperties()).andReturn(dictionary);
251         return dictionary;
252     }
253
254     @Before
255     public void setUp() throws Exception {
256         peer1 = new TestBgpPeer(BGP_PEER1_ID);
257         peer2 = new TestBgpPeer(BGP_PEER2_ID);
258         peer3 = new TestBgpPeer(BGP_PEER3_ID);
259         peers.clear();
260         peers.add(peer1);
261         peers.add(peer2);
262         peers.add(peer3);
263
264         //
265         // Setup the BGP Session Manager to test, and start listening for BGP
266         // connections.
267         //
268         bgpSessionManager = new BgpSessionManager();
269         // NOTE: We use port 0 to bind on any available port
270         ComponentContext componentContext = createMock(ComponentContext.class);
271         Dictionary<String, String> dictionary = getDictionaryMock(componentContext);
272         replay(componentContext);
273         bgpSessionManager.activate(componentContext);
274         bgpSessionManager.start(dummyRouteListener);
275
276         // Get the port number the BGP Session Manager is listening on
277         Channel serverChannel = TestUtils.getField(bgpSessionManager,
278                                                    "serverChannel");
279         SocketAddress socketAddress = serverChannel.getLocalAddress();
280         InetSocketAddress inetSocketAddress =
281             (InetSocketAddress) socketAddress;
282         InetAddress connectToAddress = InetAddresses.forString("127.0.0.1");
283         connectToSocket = new InetSocketAddress(connectToAddress,
284                                                 inetSocketAddress.getPort());
285
286         //
287         // Setup the AS Paths
288         //
289         ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
290         byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
291         ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
292         segmentAsNumbers1.add(65010L);
293         segmentAsNumbers1.add(65020L);
294         segmentAsNumbers1.add(65030L);
295         BgpRouteEntry.PathSegment pathSegment1 =
296             new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
297         pathSegments.add(pathSegment1);
298         asPathShort = new BgpRouteEntry.AsPath(new ArrayList<>(pathSegments));
299         //
300         byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
301         ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
302         segmentAsNumbers2.add(65041L);
303         segmentAsNumbers2.add(65042L);
304         segmentAsNumbers2.add(65043L);
305         BgpRouteEntry.PathSegment pathSegment2 =
306             new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
307         pathSegments.add(pathSegment2);
308         //
309         asPathLong = new BgpRouteEntry.AsPath(pathSegments);
310     }
311
312     @After
313     public void tearDown() throws Exception {
314         bgpSessionManager.stop();
315         bgpSessionManager = null;
316     }
317
318     /**
319      * Gets BGP RIB-IN routes by waiting until they are received.
320      * <p>
321      * NOTE: We keep checking once every 10ms the number of received routes,
322      * up to 5 seconds.
323      * </p>
324      *
325      * @param bgpSession the BGP session that is expected to receive the
326      * routes
327      * @param expectedRoutes the expected number of routes
328      * @return the BGP RIB-IN routes as received within the expected
329      * time interval
330      */
331     private Collection<BgpRouteEntry> waitForBgpRibIn(BgpSession bgpSession,
332                                                       long expectedRoutes)
333         throws InterruptedException {
334         Collection<BgpRouteEntry> bgpRibIn = bgpSession.getBgpRibIn4();
335
336         final int maxChecks = 500;              // Max wait of 5 seconds
337         for (int i = 0; i < maxChecks; i++) {
338             if (bgpRibIn.size() == expectedRoutes) {
339                 break;
340             }
341             Thread.sleep(10);
342             bgpRibIn = bgpSession.getBgpRibIn4();
343         }
344
345         return bgpRibIn;
346     }
347
348     /**
349      * Gets BGP merged routes by waiting until they are received.
350      * <p>
351      * NOTE: We keep checking once every 10ms the number of received routes,
352      * up to 5 seconds.
353      * </p>
354      *
355      * @param expectedRoutes the expected number of routes
356      * @return the BGP Session Manager routes as received within the expected
357      * time interval
358      */
359     private Collection<BgpRouteEntry> waitForBgpRoutes(long expectedRoutes)
360         throws InterruptedException {
361         Collection<BgpRouteEntry> bgpRoutes =
362             bgpSessionManager.getBgpRoutes4();
363
364         final int maxChecks = 500;              // Max wait of 5 seconds
365         for (int i = 0; i < maxChecks; i++) {
366             if (bgpRoutes.size() == expectedRoutes) {
367                 break;
368             }
369             Thread.sleep(10);
370             bgpRoutes = bgpSessionManager.getBgpRoutes4();
371         }
372
373         return bgpRoutes;
374     }
375
376     /**
377      * Gets a merged BGP route by waiting until it is received.
378      * <p>
379      * NOTE: We keep checking once every 10ms whether the route is received,
380      * up to 5 seconds.
381      * </p>
382      *
383      * @param expectedRoute the expected route
384      * @return the merged BGP route if received within the expected time
385      * interval, otherwise null
386      */
387     private BgpRouteEntry waitForBgpRoute(BgpRouteEntry expectedRoute)
388         throws InterruptedException {
389         Collection<BgpRouteEntry> bgpRoutes =
390             bgpSessionManager.getBgpRoutes4();
391
392         final int maxChecks = 500;              // Max wait of 5 seconds
393         for (int i = 0; i < maxChecks; i++) {
394             for (BgpRouteEntry bgpRouteEntry : bgpRoutes) {
395                 if (bgpRouteEntry.equals(expectedRoute) &&
396                     bgpRouteEntry.getBgpSession() ==
397                     expectedRoute.getBgpSession()) {
398                     return bgpRouteEntry;
399                 }
400             }
401             Thread.sleep(10);
402             bgpRoutes = bgpSessionManager.getBgpRoutes4();
403         }
404
405         return null;
406     }
407
408     /**
409      * Tests that the BGP OPEN messages have been exchanged, followed by
410      * KEEPALIVE.
411      * <p>
412      * The BGP Peer opens the sessions and transmits OPEN Message, eventually
413      * followed by KEEPALIVE. The tested BGP listener should respond by
414      * OPEN Message, followed by KEEPALIVE.
415      * </p>
416      *
417      * @throws TestUtilsException TestUtils error
418      */
419     @Test
420     public void testExchangedBgpOpenMessages()
421             throws InterruptedException, TestUtilsException {
422         // Initiate the connections
423         peer1.connect(connectToSocket);
424         peer2.connect(connectToSocket);
425         peer3.connect(connectToSocket);
426
427         //
428         // Test the fields from the BGP OPEN message:
429         // BGP version, AS number, BGP ID
430         //
431         for (TestBgpPeer peer : peers) {
432             assertThat(peer.peerFrameDecoder.remoteInfo.bgpVersion(),
433                        is(BgpConstants.BGP_VERSION));
434             assertThat(peer.peerFrameDecoder.remoteInfo.bgpId(),
435                        is(IP_LOOPBACK_ID));
436             assertThat(peer.peerFrameDecoder.remoteInfo.asNumber(),
437                        is(TestBgpPeerChannelHandler.PEER_AS));
438         }
439
440         //
441         // Test that the BgpSession instances have been created
442         //
443         assertThat(bgpSessionManager.getMyBgpId(), is(IP_LOOPBACK_ID));
444         assertThat(bgpSessionManager.getBgpSessions(), hasSize(3));
445         assertThat(bgpSession1, notNullValue());
446         assertThat(bgpSession2, notNullValue());
447         assertThat(bgpSession3, notNullValue());
448         for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
449             long sessionAs = bgpSession.localInfo().asNumber();
450             assertThat(sessionAs, is(TestBgpPeerChannelHandler.PEER_AS));
451         }
452     }
453
454
455     /**
456      * Tests that the BGP OPEN with Capability messages have been exchanged,
457      * followed by KEEPALIVE.
458      * <p>
459      * The BGP Peer opens the sessions and transmits OPEN Message, eventually
460      * followed by KEEPALIVE. The tested BGP listener should respond by
461      * OPEN Message, followed by KEEPALIVE.
462      * </p>
463      *
464      * @throws TestUtilsException TestUtils error
465      */
466     @Test
467     public void testExchangedBgpOpenCapabilityMessages()
468             throws InterruptedException, TestUtilsException {
469         //
470         // Setup the BGP Capabilities for all peers
471         //
472         for (TestBgpPeer peer : peers) {
473             peer.peerChannelHandler.localInfo.setIpv4Unicast();
474             peer.peerChannelHandler.localInfo.setIpv4Multicast();
475             peer.peerChannelHandler.localInfo.setIpv6Unicast();
476             peer.peerChannelHandler.localInfo.setIpv6Multicast();
477             peer.peerChannelHandler.localInfo.setAs4OctetCapability();
478             peer.peerChannelHandler.localInfo.setAs4Number(
479                 TestBgpPeerChannelHandler.PEER_AS4);
480         }
481
482         // Initiate the connections
483         peer1.connect(connectToSocket);
484         peer2.connect(connectToSocket);
485         peer3.connect(connectToSocket);
486
487         //
488         // Test the fields from the BGP OPEN message:
489         // BGP version, BGP ID
490         //
491         for (TestBgpPeer peer : peers) {
492             assertThat(peer.peerFrameDecoder.remoteInfo.bgpVersion(),
493                        is(BgpConstants.BGP_VERSION));
494             assertThat(peer.peerFrameDecoder.remoteInfo.bgpId(),
495                        is(IP_LOOPBACK_ID));
496         }
497
498         //
499         // Test that the BgpSession instances have been created,
500         // and contain the appropriate BGP session information.
501         //
502         assertThat(bgpSessionManager.getMyBgpId(), is(IP_LOOPBACK_ID));
503         assertThat(bgpSessionManager.getBgpSessions(), hasSize(3));
504         assertThat(bgpSession1, notNullValue());
505         assertThat(bgpSession2, notNullValue());
506         assertThat(bgpSession3, notNullValue());
507         for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
508             BgpSessionInfo localInfo = bgpSession.localInfo();
509             assertThat(localInfo.ipv4Unicast(), is(true));
510             assertThat(localInfo.ipv4Multicast(), is(true));
511             assertThat(localInfo.ipv6Unicast(), is(true));
512             assertThat(localInfo.ipv6Multicast(), is(true));
513             assertThat(localInfo.as4OctetCapability(), is(true));
514             assertThat(localInfo.asNumber(),
515                        is(TestBgpPeerChannelHandler.PEER_AS4));
516             assertThat(localInfo.as4Number(),
517                        is(TestBgpPeerChannelHandler.PEER_AS4));
518         }
519     }
520
521     /**
522      * Tests that the BGP UPDATE messages have been received and processed.
523      */
524     @Test
525     public void testProcessedBgpUpdateMessages() throws InterruptedException {
526         ChannelBuffer message;
527         BgpRouteEntry bgpRouteEntry;
528         Collection<BgpRouteEntry> bgpRibIn1;
529         Collection<BgpRouteEntry> bgpRibIn2;
530         Collection<BgpRouteEntry> bgpRibIn3;
531         Collection<BgpRouteEntry> bgpRoutes;
532
533         // Initiate the connections
534         peer1.connect(connectToSocket);
535         peer2.connect(connectToSocket);
536         peer3.connect(connectToSocket);
537
538         // Prepare routes to add/delete
539         Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
540         Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
541
542         //
543         // Add and delete some routes
544         //
545         addedRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
546         addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
547         addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
548         addedRoutes.add(Ip4Prefix.valueOf("40.0.0.0/24"));
549         addedRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
550         withdrawnRoutes.add(Ip4Prefix.valueOf("60.0.0.0/8"));
551         withdrawnRoutes.add(Ip4Prefix.valueOf("70.0.0.0/16"));
552         withdrawnRoutes.add(Ip4Prefix.valueOf("80.0.0.0/24"));
553         withdrawnRoutes.add(Ip4Prefix.valueOf("90.0.0.0/32"));
554         // Write the routes
555         message = peer1.peerChannelHandler.prepareBgpUpdate(
556                         NEXT_HOP1_ROUTER,
557                         DEFAULT_LOCAL_PREF,
558                         DEFAULT_MULTI_EXIT_DISC,
559                         asPathLong,
560                         addedRoutes,
561                         withdrawnRoutes);
562         peer1.peerChannelHandler.savedCtx.getChannel().write(message);
563         //
564         // Check that the routes have been received, processed and stored
565         //
566         bgpRibIn1 = waitForBgpRibIn(bgpSession1, 5);
567         assertThat(bgpRibIn1, hasSize(5));
568         bgpRoutes = waitForBgpRoutes(5);
569         assertThat(bgpRoutes, hasSize(5));
570         //
571         bgpRouteEntry =
572             new BgpRouteEntry(bgpSession1,
573                               Ip4Prefix.valueOf("0.0.0.0/0"),
574                               NEXT_HOP1_ROUTER,
575                               (byte) BgpConstants.Update.Origin.IGP,
576                               asPathLong,
577                               DEFAULT_LOCAL_PREF);
578         bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
579         assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
580         assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
581         //
582         bgpRouteEntry =
583             new BgpRouteEntry(bgpSession1,
584                               Ip4Prefix.valueOf("20.0.0.0/8"),
585                               NEXT_HOP1_ROUTER,
586                               (byte) BgpConstants.Update.Origin.IGP,
587                               asPathLong,
588                               DEFAULT_LOCAL_PREF);
589         bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
590         assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
591         assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
592         //
593         bgpRouteEntry =
594             new BgpRouteEntry(bgpSession1,
595                               Ip4Prefix.valueOf("30.0.0.0/16"),
596                               NEXT_HOP1_ROUTER,
597                               (byte) BgpConstants.Update.Origin.IGP,
598                               asPathLong,
599                               DEFAULT_LOCAL_PREF);
600         bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
601         assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
602         assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
603         //
604         bgpRouteEntry =
605             new BgpRouteEntry(bgpSession1,
606                               Ip4Prefix.valueOf("40.0.0.0/24"),
607                               NEXT_HOP1_ROUTER,
608                               (byte) BgpConstants.Update.Origin.IGP,
609                               asPathLong,
610                               DEFAULT_LOCAL_PREF);
611         bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
612         assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
613         assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
614         //
615         bgpRouteEntry =
616             new BgpRouteEntry(bgpSession1,
617                               Ip4Prefix.valueOf("50.0.0.0/32"),
618                               NEXT_HOP1_ROUTER,
619                               (byte) BgpConstants.Update.Origin.IGP,
620                               asPathLong,
621                               DEFAULT_LOCAL_PREF);
622         bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
623         assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
624         assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
625
626         //
627         // Delete some routes
628         //
629         addedRoutes = new LinkedList<>();
630         withdrawnRoutes = new LinkedList<>();
631         withdrawnRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
632         withdrawnRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
633         // Write the routes
634         message = peer1.peerChannelHandler.prepareBgpUpdate(
635                         NEXT_HOP1_ROUTER,
636                         DEFAULT_LOCAL_PREF,
637                         DEFAULT_MULTI_EXIT_DISC,
638                         asPathLong,
639                         addedRoutes,
640                         withdrawnRoutes);
641         peer1.peerChannelHandler.savedCtx.getChannel().write(message);
642         //
643         // Check that the routes have been received, processed and stored
644         //
645         bgpRibIn1 = waitForBgpRibIn(bgpSession1, 3);
646         assertThat(bgpRibIn1, hasSize(3));
647         bgpRoutes = waitForBgpRoutes(3);
648         assertThat(bgpRoutes, hasSize(3));
649         //
650         bgpRouteEntry =
651             new BgpRouteEntry(bgpSession1,
652                               Ip4Prefix.valueOf("20.0.0.0/8"),
653                               NEXT_HOP1_ROUTER,
654                               (byte) BgpConstants.Update.Origin.IGP,
655                               asPathLong,
656                               DEFAULT_LOCAL_PREF);
657         bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
658         assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
659         assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
660         //
661         bgpRouteEntry =
662             new BgpRouteEntry(bgpSession1,
663                               Ip4Prefix.valueOf("30.0.0.0/16"),
664                               NEXT_HOP1_ROUTER,
665                               (byte) BgpConstants.Update.Origin.IGP,
666                               asPathLong,
667                               DEFAULT_LOCAL_PREF);
668         bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
669         assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
670         assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
671         //
672         bgpRouteEntry =
673             new BgpRouteEntry(bgpSession1,
674                               Ip4Prefix.valueOf("40.0.0.0/24"),
675                               NEXT_HOP1_ROUTER,
676                               (byte) BgpConstants.Update.Origin.IGP,
677                               asPathLong,
678                               DEFAULT_LOCAL_PREF);
679         bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
680         assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
681         assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
682
683
684         // Close the channels and test there are no routes
685         peer1.peerChannelHandler.closeChannel();
686         peer2.peerChannelHandler.closeChannel();
687         peer3.peerChannelHandler.closeChannel();
688         bgpRoutes = waitForBgpRoutes(0);
689         assertThat(bgpRoutes, hasSize(0));
690     }
691
692     /**
693      * Tests the BGP route preference.
694      */
695     @Test
696     public void testBgpRoutePreference() throws InterruptedException {
697         ChannelBuffer message;
698         BgpRouteEntry bgpRouteEntry;
699         Collection<BgpRouteEntry> bgpRibIn1;
700         Collection<BgpRouteEntry> bgpRibIn2;
701         Collection<BgpRouteEntry> bgpRibIn3;
702         Collection<BgpRouteEntry> bgpRoutes;
703         Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
704         Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
705
706         // Initiate the connections
707         peer1.connect(connectToSocket);
708         peer2.connect(connectToSocket);
709         peer3.connect(connectToSocket);
710
711         //
712         // Setup the initial set of routes to Peer1
713         //
714         addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
715         addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
716         // Write the routes
717         message = peer1.peerChannelHandler.prepareBgpUpdate(
718                         NEXT_HOP1_ROUTER,
719                         DEFAULT_LOCAL_PREF,
720                         DEFAULT_MULTI_EXIT_DISC,
721                         asPathLong,
722                         addedRoutes,
723                         withdrawnRoutes);
724         peer1.peerChannelHandler.savedCtx.getChannel().write(message);
725         bgpRoutes = waitForBgpRoutes(2);
726         assertThat(bgpRoutes, hasSize(2));
727
728         //
729         // Add a route entry to Peer2 with a better LOCAL_PREF
730         //
731         addedRoutes = new LinkedList<>();
732         withdrawnRoutes = new LinkedList<>();
733         addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
734         // Write the routes
735         message = peer2.peerChannelHandler.prepareBgpUpdate(
736                         NEXT_HOP2_ROUTER,
737                         BETTER_LOCAL_PREF,
738                         DEFAULT_MULTI_EXIT_DISC,
739                         asPathLong,
740                         addedRoutes,
741                         withdrawnRoutes);
742         peer2.peerChannelHandler.savedCtx.getChannel().write(message);
743         //
744         // Check that the routes have been received, processed and stored
745         //
746         bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
747         assertThat(bgpRibIn2, hasSize(1));
748         bgpRoutes = waitForBgpRoutes(2);
749         assertThat(bgpRoutes, hasSize(2));
750         //
751         bgpRouteEntry =
752             new BgpRouteEntry(bgpSession2,
753                               Ip4Prefix.valueOf("20.0.0.0/8"),
754                               NEXT_HOP2_ROUTER,
755                               (byte) BgpConstants.Update.Origin.IGP,
756                               asPathLong,
757                               BETTER_LOCAL_PREF);
758         bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
759         assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
760         assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
761
762         //
763         // Add a route entry to Peer3 with a shorter AS path
764         //
765         addedRoutes = new LinkedList<>();
766         withdrawnRoutes = new LinkedList<>();
767         addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
768         // Write the routes
769         message = peer3.peerChannelHandler.prepareBgpUpdate(
770                         NEXT_HOP3_ROUTER,
771                         BETTER_LOCAL_PREF,
772                         DEFAULT_MULTI_EXIT_DISC,
773                         asPathShort,
774                         addedRoutes,
775                         withdrawnRoutes);
776         peer3.peerChannelHandler.savedCtx.getChannel().write(message);
777         //
778         // Check that the routes have been received, processed and stored
779         //
780         bgpRibIn3 = waitForBgpRibIn(bgpSession3, 1);
781         assertThat(bgpRibIn3, hasSize(1));
782         bgpRoutes = waitForBgpRoutes(2);
783         assertThat(bgpRoutes, hasSize(2));
784         //
785         bgpRouteEntry =
786             new BgpRouteEntry(bgpSession3,
787                               Ip4Prefix.valueOf("20.0.0.0/8"),
788                               NEXT_HOP3_ROUTER,
789                               (byte) BgpConstants.Update.Origin.IGP,
790                               asPathShort,
791                               BETTER_LOCAL_PREF);
792         bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
793         assertThat(bgpRibIn3, hasBgpRouteEntry(bgpRouteEntry));
794         assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
795
796         //
797         // Cleanup in preparation for next test: delete old route entry from
798         // Peer2
799         //
800         addedRoutes = new LinkedList<>();
801         withdrawnRoutes = new LinkedList<>();
802         withdrawnRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
803         // Write the routes
804         message = peer2.peerChannelHandler.prepareBgpUpdate(
805                         NEXT_HOP2_ROUTER,
806                         BETTER_LOCAL_PREF,
807                         BETTER_MULTI_EXIT_DISC,
808                         asPathShort,
809                         addedRoutes,
810                         withdrawnRoutes);
811         peer2.peerChannelHandler.savedCtx.getChannel().write(message);
812         //
813         // Check that the routes have been received, processed and stored
814         //
815         bgpRibIn2 = waitForBgpRibIn(bgpSession2, 0);
816         assertThat(bgpRibIn2, hasSize(0));
817
818         //
819         // Add a route entry to Peer2 with a better MED
820         //
821         addedRoutes = new LinkedList<>();
822         withdrawnRoutes = new LinkedList<>();
823         addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
824         // Write the routes
825         message = peer2.peerChannelHandler.prepareBgpUpdate(
826                         NEXT_HOP2_ROUTER,
827                         BETTER_LOCAL_PREF,
828                         BETTER_MULTI_EXIT_DISC,
829                         asPathShort,
830                         addedRoutes,
831                         withdrawnRoutes);
832         peer2.peerChannelHandler.savedCtx.getChannel().write(message);
833         //
834         // Check that the routes have been received, processed and stored
835         //
836         bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
837         assertThat(bgpRibIn2, hasSize(1));
838         bgpRoutes = waitForBgpRoutes(2);
839         assertThat(bgpRoutes, hasSize(2));
840         //
841         bgpRouteEntry =
842             new BgpRouteEntry(bgpSession2,
843                               Ip4Prefix.valueOf("20.0.0.0/8"),
844                               NEXT_HOP2_ROUTER,
845                               (byte) BgpConstants.Update.Origin.IGP,
846                               asPathShort,
847                               BETTER_LOCAL_PREF);
848         bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
849         assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
850         assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
851
852         //
853         // Add a route entry to Peer1 with a better (lower) BGP ID
854         //
855         addedRoutes = new LinkedList<>();
856         withdrawnRoutes = new LinkedList<>();
857         addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
858         withdrawnRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
859         // Write the routes
860         message = peer1.peerChannelHandler.prepareBgpUpdate(
861                         NEXT_HOP1_ROUTER,
862                         BETTER_LOCAL_PREF,
863                         BETTER_MULTI_EXIT_DISC,
864                         asPathShort,
865                         addedRoutes,
866                         withdrawnRoutes);
867         peer1.peerChannelHandler.savedCtx.getChannel().write(message);
868         //
869         // Check that the routes have been received, processed and stored
870         //
871         bgpRibIn1 = waitForBgpRibIn(bgpSession1, 1);
872         assertThat(bgpRibIn1, hasSize(1));
873         bgpRoutes = waitForBgpRoutes(1);
874         assertThat(bgpRoutes, hasSize(1));
875         //
876         bgpRouteEntry =
877             new BgpRouteEntry(bgpSession1,
878                               Ip4Prefix.valueOf("20.0.0.0/8"),
879                               NEXT_HOP1_ROUTER,
880                               (byte) BgpConstants.Update.Origin.IGP,
881                               asPathShort,
882                               BETTER_LOCAL_PREF);
883         bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
884         assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
885         assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
886
887
888         // Close the channels and test there are no routes
889         peer1.peerChannelHandler.closeChannel();
890         peer2.peerChannelHandler.closeChannel();
891         peer3.peerChannelHandler.closeChannel();
892         bgpRoutes = waitForBgpRoutes(0);
893         assertThat(bgpRoutes, hasSize(0));
894     }
895 }