blob: 2d2731a40b96678a2584231b5ce034196763174a [file] [log] [blame]
/*
* Copyright 2014-2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.routing.bgp;
import com.google.common.net.InetAddresses;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestUtils;
import org.onlab.junit.TestUtils.TestUtilsException;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onosproject.routing.RouteListener;
import org.onosproject.routing.RouteUpdate;
import org.osgi.service.component.ComponentContext;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import java.util.LinkedList;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
/**
* Unit tests for the BgpSessionManager class.
*/
public class BgpSessionManagerTest {
private static final Ip4Address IP_LOOPBACK_ID =
Ip4Address.valueOf("127.0.0.1");
private static final Ip4Address BGP_PEER1_ID =
Ip4Address.valueOf("10.0.0.1");
private static final Ip4Address BGP_PEER2_ID =
Ip4Address.valueOf("10.0.0.2");
private static final Ip4Address BGP_PEER3_ID =
Ip4Address.valueOf("10.0.0.3");
private static final Ip4Address NEXT_HOP1_ROUTER =
Ip4Address.valueOf("10.20.30.41");
private static final Ip4Address NEXT_HOP2_ROUTER =
Ip4Address.valueOf("10.20.30.42");
private static final Ip4Address NEXT_HOP3_ROUTER =
Ip4Address.valueOf("10.20.30.43");
private static final long DEFAULT_LOCAL_PREF = 10;
private static final long BETTER_LOCAL_PREF = 20;
private static final long DEFAULT_MULTI_EXIT_DISC = 20;
private static final long BETTER_MULTI_EXIT_DISC = 30;
BgpRouteEntry.AsPath asPathShort;
BgpRouteEntry.AsPath asPathLong;
// Timeout waiting for a message to be received
private static final int MESSAGE_TIMEOUT_MS = 5000; // 5s
// The BGP Session Manager to test
private BgpSessionManager bgpSessionManager;
// Remote Peer state
private final Collection<TestBgpPeer> peers = new LinkedList<>();
TestBgpPeer peer1;
TestBgpPeer peer2;
TestBgpPeer peer3;
// Local BGP per-peer session state
BgpSession bgpSession1;
BgpSession bgpSession2;
BgpSession bgpSession3;
// The socket that the remote peers should connect to
private InetSocketAddress connectToSocket;
private final DummyRouteListener dummyRouteListener =
new DummyRouteListener();
/**
* Dummy implementation for the RouteListener interface.
*/
private class DummyRouteListener implements RouteListener {
@Override
public void update(Collection<RouteUpdate> routeUpdate) {
// Nothing to do
}
}
/**
* A class to capture the state for a BGP peer.
*/
private final class TestBgpPeer {
private final Ip4Address peerId;
private ClientBootstrap peerBootstrap;
private TestBgpPeerChannelHandler peerChannelHandler;
private TestBgpPeerFrameDecoder peerFrameDecoder =
new TestBgpPeerFrameDecoder();
/**
* Constructor.
*
* @param peerId the peer ID
*/
private TestBgpPeer(Ip4Address peerId) {
this.peerId = peerId;
peerChannelHandler = new TestBgpPeerChannelHandler(peerId);
}
/**
* Starts up the BGP peer and connects it to the tested BgpSessionManager
* instance.
*
* @param connectToSocket the socket to connect to
*/
private void connect(InetSocketAddress connectToSocket)
throws InterruptedException {
//
// Setup the BGP Peer, i.e., the "remote" BGP router that will
// initiate the BGP connection, send BGP UPDATE messages, etc.
//
ChannelFactory channelFactory =
new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
ChannelPipelineFactory pipelineFactory = () -> {
// Setup the transmitting pipeline
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("TestBgpPeerFrameDecoder",
peerFrameDecoder);
pipeline.addLast("TestBgpPeerChannelHandler",
peerChannelHandler);
return pipeline;
};
peerBootstrap = new ClientBootstrap(channelFactory);
peerBootstrap.setOption("child.keepAlive", true);
peerBootstrap.setOption("child.tcpNoDelay", true);
peerBootstrap.setPipelineFactory(pipelineFactory);
peerBootstrap.connect(connectToSocket);
boolean result;
// Wait until the OPEN message is received
result = peerFrameDecoder.receivedOpenMessageLatch.await(
MESSAGE_TIMEOUT_MS,
TimeUnit.MILLISECONDS);
assertThat(result, is(true));
// Wait until the KEEPALIVE message is received
result = peerFrameDecoder.receivedKeepaliveMessageLatch.await(
MESSAGE_TIMEOUT_MS,
TimeUnit.MILLISECONDS);
assertThat(result, is(true));
for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER1_ID)) {
bgpSession1 = bgpSession;
}
if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER2_ID)) {
bgpSession2 = bgpSession;
}
if (bgpSession.remoteInfo().bgpId().equals(BGP_PEER3_ID)) {
bgpSession3 = bgpSession;
}
}
}
}
/**
* Class that implements a matcher for BgpRouteEntry by considering
* the BGP peer the entry was received from.
*/
private static final class BgpRouteEntryAndPeerMatcher
extends TypeSafeMatcher<Collection<BgpRouteEntry>> {
private final BgpRouteEntry bgpRouteEntry;
private BgpRouteEntryAndPeerMatcher(BgpRouteEntry bgpRouteEntry) {
this.bgpRouteEntry = bgpRouteEntry;
}
@Override
public boolean matchesSafely(Collection<BgpRouteEntry> entries) {
for (BgpRouteEntry entry : entries) {
if (bgpRouteEntry.equals(entry) &&
bgpRouteEntry.getBgpSession() == entry.getBgpSession()) {
return true;
}
}
return false;
}
@Override
public void describeTo(Description description) {
description.appendText("BGP route entry lookup for entry \"").
appendText(bgpRouteEntry.toString()).
appendText("\"");
}
}
/**
* A helper method used for testing whether a collection of
* BGP route entries contains an entry from a specific BGP peer.
*
* @param bgpRouteEntry the BGP route entry to test
* @return an instance of BgpRouteEntryAndPeerMatcher that implements
* the matching logic
*/
private static BgpRouteEntryAndPeerMatcher hasBgpRouteEntry(
BgpRouteEntry bgpRouteEntry) {
return new BgpRouteEntryAndPeerMatcher(bgpRouteEntry);
}
@SuppressWarnings("unchecked")
private Dictionary
getDictionaryMock(ComponentContext componentContext) {
Dictionary dictionary = createMock(Dictionary.class);
expect(dictionary.get("bgpPort")).andReturn("0");
replay(dictionary);
expect(componentContext.getProperties()).andReturn(dictionary);
return dictionary;
}
@Before
public void setUp() throws Exception {
peer1 = new TestBgpPeer(BGP_PEER1_ID);
peer2 = new TestBgpPeer(BGP_PEER2_ID);
peer3 = new TestBgpPeer(BGP_PEER3_ID);
peers.clear();
peers.add(peer1);
peers.add(peer2);
peers.add(peer3);
//
// Setup the BGP Session Manager to test, and start listening for BGP
// connections.
//
bgpSessionManager = new BgpSessionManager();
// NOTE: We use port 0 to bind on any available port
ComponentContext componentContext = createMock(ComponentContext.class);
Dictionary dictionary = getDictionaryMock(componentContext);
replay(componentContext);
bgpSessionManager.activate(componentContext);
bgpSessionManager.start(dummyRouteListener);
// Get the port number the BGP Session Manager is listening on
Channel serverChannel = TestUtils.getField(bgpSessionManager,
"serverChannel");
SocketAddress socketAddress = serverChannel.getLocalAddress();
InetSocketAddress inetSocketAddress =
(InetSocketAddress) socketAddress;
InetAddress connectToAddress = InetAddresses.forString("127.0.0.1");
connectToSocket = new InetSocketAddress(connectToAddress,
inetSocketAddress.getPort());
//
// Setup the AS Paths
//
ArrayList<BgpRouteEntry.PathSegment> pathSegments = new ArrayList<>();
byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
ArrayList<Long> segmentAsNumbers1 = new ArrayList<>();
segmentAsNumbers1.add(65010L);
segmentAsNumbers1.add(65020L);
segmentAsNumbers1.add(65030L);
BgpRouteEntry.PathSegment pathSegment1 =
new BgpRouteEntry.PathSegment(pathSegmentType1, segmentAsNumbers1);
pathSegments.add(pathSegment1);
asPathShort = new BgpRouteEntry.AsPath(new ArrayList<>(pathSegments));
//
byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
ArrayList<Long> segmentAsNumbers2 = new ArrayList<>();
segmentAsNumbers2.add(65041L);
segmentAsNumbers2.add(65042L);
segmentAsNumbers2.add(65043L);
BgpRouteEntry.PathSegment pathSegment2 =
new BgpRouteEntry.PathSegment(pathSegmentType2, segmentAsNumbers2);
pathSegments.add(pathSegment2);
//
asPathLong = new BgpRouteEntry.AsPath(pathSegments);
}
@After
public void tearDown() throws Exception {
bgpSessionManager.stop();
bgpSessionManager = null;
}
/**
* Gets BGP RIB-IN routes by waiting until they are received.
* <p>
* NOTE: We keep checking once every 10ms the number of received routes,
* up to 5 seconds.
* </p>
*
* @param bgpSession the BGP session that is expected to receive the
* routes
* @param expectedRoutes the expected number of routes
* @return the BGP RIB-IN routes as received within the expected
* time interval
*/
private Collection<BgpRouteEntry> waitForBgpRibIn(BgpSession bgpSession,
long expectedRoutes)
throws InterruptedException {
Collection<BgpRouteEntry> bgpRibIn = bgpSession.getBgpRibIn4();
final int maxChecks = 500; // Max wait of 5 seconds
for (int i = 0; i < maxChecks; i++) {
if (bgpRibIn.size() == expectedRoutes) {
break;
}
Thread.sleep(10);
bgpRibIn = bgpSession.getBgpRibIn4();
}
return bgpRibIn;
}
/**
* Gets BGP merged routes by waiting until they are received.
* <p>
* NOTE: We keep checking once every 10ms the number of received routes,
* up to 5 seconds.
* </p>
*
* @param expectedRoutes the expected number of routes
* @return the BGP Session Manager routes as received within the expected
* time interval
*/
private Collection<BgpRouteEntry> waitForBgpRoutes(long expectedRoutes)
throws InterruptedException {
Collection<BgpRouteEntry> bgpRoutes =
bgpSessionManager.getBgpRoutes4();
final int maxChecks = 500; // Max wait of 5 seconds
for (int i = 0; i < maxChecks; i++) {
if (bgpRoutes.size() == expectedRoutes) {
break;
}
Thread.sleep(10);
bgpRoutes = bgpSessionManager.getBgpRoutes4();
}
return bgpRoutes;
}
/**
* Gets a merged BGP route by waiting until it is received.
* <p>
* NOTE: We keep checking once every 10ms whether the route is received,
* up to 5 seconds.
* </p>
*
* @param expectedRoute the expected route
* @return the merged BGP route if received within the expected time
* interval, otherwise null
*/
private BgpRouteEntry waitForBgpRoute(BgpRouteEntry expectedRoute)
throws InterruptedException {
Collection<BgpRouteEntry> bgpRoutes =
bgpSessionManager.getBgpRoutes4();
final int maxChecks = 500; // Max wait of 5 seconds
for (int i = 0; i < maxChecks; i++) {
for (BgpRouteEntry bgpRouteEntry : bgpRoutes) {
if (bgpRouteEntry.equals(expectedRoute) &&
bgpRouteEntry.getBgpSession() ==
expectedRoute.getBgpSession()) {
return bgpRouteEntry;
}
}
Thread.sleep(10);
bgpRoutes = bgpSessionManager.getBgpRoutes4();
}
return null;
}
/**
* Tests that the BGP OPEN messages have been exchanged, followed by
* KEEPALIVE.
* <p>
* The BGP Peer opens the sessions and transmits OPEN Message, eventually
* followed by KEEPALIVE. The tested BGP listener should respond by
* OPEN Message, followed by KEEPALIVE.
* </p>
*
* @throws TestUtilsException TestUtils error
*/
@Test
public void testExchangedBgpOpenMessages()
throws InterruptedException, TestUtilsException {
// Initiate the connections
peer1.connect(connectToSocket);
peer2.connect(connectToSocket);
peer3.connect(connectToSocket);
//
// Test the fields from the BGP OPEN message:
// BGP version, AS number, BGP ID
//
for (TestBgpPeer peer : peers) {
assertThat(peer.peerFrameDecoder.remoteInfo.bgpVersion(),
is(BgpConstants.BGP_VERSION));
assertThat(peer.peerFrameDecoder.remoteInfo.bgpId(),
is(IP_LOOPBACK_ID));
assertThat(peer.peerFrameDecoder.remoteInfo.asNumber(),
is(TestBgpPeerChannelHandler.PEER_AS));
}
//
// Test that the BgpSession instances have been created
//
assertThat(bgpSessionManager.getMyBgpId(), is(IP_LOOPBACK_ID));
assertThat(bgpSessionManager.getBgpSessions(), hasSize(3));
assertThat(bgpSession1, notNullValue());
assertThat(bgpSession2, notNullValue());
assertThat(bgpSession3, notNullValue());
for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
long sessionAs = bgpSession.localInfo().asNumber();
assertThat(sessionAs, is(TestBgpPeerChannelHandler.PEER_AS));
}
}
/**
* Tests that the BGP OPEN with Capability messages have been exchanged,
* followed by KEEPALIVE.
* <p>
* The BGP Peer opens the sessions and transmits OPEN Message, eventually
* followed by KEEPALIVE. The tested BGP listener should respond by
* OPEN Message, followed by KEEPALIVE.
* </p>
*
* @throws TestUtilsException TestUtils error
*/
@Test
public void testExchangedBgpOpenCapabilityMessages()
throws InterruptedException, TestUtilsException {
//
// Setup the BGP Capabilities for all peers
//
for (TestBgpPeer peer : peers) {
peer.peerChannelHandler.localInfo.setIpv4Unicast();
peer.peerChannelHandler.localInfo.setIpv4Multicast();
peer.peerChannelHandler.localInfo.setIpv6Unicast();
peer.peerChannelHandler.localInfo.setIpv6Multicast();
peer.peerChannelHandler.localInfo.setAs4OctetCapability();
peer.peerChannelHandler.localInfo.setAs4Number(
TestBgpPeerChannelHandler.PEER_AS4);
}
// Initiate the connections
peer1.connect(connectToSocket);
peer2.connect(connectToSocket);
peer3.connect(connectToSocket);
//
// Test the fields from the BGP OPEN message:
// BGP version, BGP ID
//
for (TestBgpPeer peer : peers) {
assertThat(peer.peerFrameDecoder.remoteInfo.bgpVersion(),
is(BgpConstants.BGP_VERSION));
assertThat(peer.peerFrameDecoder.remoteInfo.bgpId(),
is(IP_LOOPBACK_ID));
}
//
// Test that the BgpSession instances have been created,
// and contain the appropriate BGP session information.
//
assertThat(bgpSessionManager.getMyBgpId(), is(IP_LOOPBACK_ID));
assertThat(bgpSessionManager.getBgpSessions(), hasSize(3));
assertThat(bgpSession1, notNullValue());
assertThat(bgpSession2, notNullValue());
assertThat(bgpSession3, notNullValue());
for (BgpSession bgpSession : bgpSessionManager.getBgpSessions()) {
BgpSessionInfo localInfo = bgpSession.localInfo();
assertThat(localInfo.ipv4Unicast(), is(true));
assertThat(localInfo.ipv4Multicast(), is(true));
assertThat(localInfo.ipv6Unicast(), is(true));
assertThat(localInfo.ipv6Multicast(), is(true));
assertThat(localInfo.as4OctetCapability(), is(true));
assertThat(localInfo.asNumber(),
is(TestBgpPeerChannelHandler.PEER_AS4));
assertThat(localInfo.as4Number(),
is(TestBgpPeerChannelHandler.PEER_AS4));
}
}
/**
* Tests that the BGP UPDATE messages have been received and processed.
*/
@Test
public void testProcessedBgpUpdateMessages() throws InterruptedException {
ChannelBuffer message;
BgpRouteEntry bgpRouteEntry;
Collection<BgpRouteEntry> bgpRibIn1;
Collection<BgpRouteEntry> bgpRibIn2;
Collection<BgpRouteEntry> bgpRibIn3;
Collection<BgpRouteEntry> bgpRoutes;
// Initiate the connections
peer1.connect(connectToSocket);
peer2.connect(connectToSocket);
peer3.connect(connectToSocket);
// Prepare routes to add/delete
Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
//
// Add and delete some routes
//
addedRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
addedRoutes.add(Ip4Prefix.valueOf("40.0.0.0/24"));
addedRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
withdrawnRoutes.add(Ip4Prefix.valueOf("60.0.0.0/8"));
withdrawnRoutes.add(Ip4Prefix.valueOf("70.0.0.0/16"));
withdrawnRoutes.add(Ip4Prefix.valueOf("80.0.0.0/24"));
withdrawnRoutes.add(Ip4Prefix.valueOf("90.0.0.0/32"));
// Write the routes
message = peer1.peerChannelHandler.prepareBgpUpdate(
NEXT_HOP1_ROUTER,
DEFAULT_LOCAL_PREF,
DEFAULT_MULTI_EXIT_DISC,
asPathLong,
addedRoutes,
withdrawnRoutes);
peer1.peerChannelHandler.savedCtx.getChannel().write(message);
//
// Check that the routes have been received, processed and stored
//
bgpRibIn1 = waitForBgpRibIn(bgpSession1, 5);
assertThat(bgpRibIn1, hasSize(5));
bgpRoutes = waitForBgpRoutes(5);
assertThat(bgpRoutes, hasSize(5));
//
bgpRouteEntry =
new BgpRouteEntry(bgpSession1,
Ip4Prefix.valueOf("0.0.0.0/0"),
NEXT_HOP1_ROUTER,
(byte) BgpConstants.Update.Origin.IGP,
asPathLong,
DEFAULT_LOCAL_PREF);
bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
//
bgpRouteEntry =
new BgpRouteEntry(bgpSession1,
Ip4Prefix.valueOf("20.0.0.0/8"),
NEXT_HOP1_ROUTER,
(byte) BgpConstants.Update.Origin.IGP,
asPathLong,
DEFAULT_LOCAL_PREF);
bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
//
bgpRouteEntry =
new BgpRouteEntry(bgpSession1,
Ip4Prefix.valueOf("30.0.0.0/16"),
NEXT_HOP1_ROUTER,
(byte) BgpConstants.Update.Origin.IGP,
asPathLong,
DEFAULT_LOCAL_PREF);
bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
//
bgpRouteEntry =
new BgpRouteEntry(bgpSession1,
Ip4Prefix.valueOf("40.0.0.0/24"),
NEXT_HOP1_ROUTER,
(byte) BgpConstants.Update.Origin.IGP,
asPathLong,
DEFAULT_LOCAL_PREF);
bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
//
bgpRouteEntry =
new BgpRouteEntry(bgpSession1,
Ip4Prefix.valueOf("50.0.0.0/32"),
NEXT_HOP1_ROUTER,
(byte) BgpConstants.Update.Origin.IGP,
asPathLong,
DEFAULT_LOCAL_PREF);
bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
//
// Delete some routes
//
addedRoutes = new LinkedList<>();
withdrawnRoutes = new LinkedList<>();
withdrawnRoutes.add(Ip4Prefix.valueOf("0.0.0.0/0"));
withdrawnRoutes.add(Ip4Prefix.valueOf("50.0.0.0/32"));
// Write the routes
message = peer1.peerChannelHandler.prepareBgpUpdate(
NEXT_HOP1_ROUTER,
DEFAULT_LOCAL_PREF,
DEFAULT_MULTI_EXIT_DISC,
asPathLong,
addedRoutes,
withdrawnRoutes);
peer1.peerChannelHandler.savedCtx.getChannel().write(message);
//
// Check that the routes have been received, processed and stored
//
bgpRibIn1 = waitForBgpRibIn(bgpSession1, 3);
assertThat(bgpRibIn1, hasSize(3));
bgpRoutes = waitForBgpRoutes(3);
assertThat(bgpRoutes, hasSize(3));
//
bgpRouteEntry =
new BgpRouteEntry(bgpSession1,
Ip4Prefix.valueOf("20.0.0.0/8"),
NEXT_HOP1_ROUTER,
(byte) BgpConstants.Update.Origin.IGP,
asPathLong,
DEFAULT_LOCAL_PREF);
bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
//
bgpRouteEntry =
new BgpRouteEntry(bgpSession1,
Ip4Prefix.valueOf("30.0.0.0/16"),
NEXT_HOP1_ROUTER,
(byte) BgpConstants.Update.Origin.IGP,
asPathLong,
DEFAULT_LOCAL_PREF);
bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
//
bgpRouteEntry =
new BgpRouteEntry(bgpSession1,
Ip4Prefix.valueOf("40.0.0.0/24"),
NEXT_HOP1_ROUTER,
(byte) BgpConstants.Update.Origin.IGP,
asPathLong,
DEFAULT_LOCAL_PREF);
bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
// Close the channels and test there are no routes
peer1.peerChannelHandler.closeChannel();
peer2.peerChannelHandler.closeChannel();
peer3.peerChannelHandler.closeChannel();
bgpRoutes = waitForBgpRoutes(0);
assertThat(bgpRoutes, hasSize(0));
}
/**
* Tests the BGP route preference.
*/
@Test
public void testBgpRoutePreference() throws InterruptedException {
ChannelBuffer message;
BgpRouteEntry bgpRouteEntry;
Collection<BgpRouteEntry> bgpRibIn1;
Collection<BgpRouteEntry> bgpRibIn2;
Collection<BgpRouteEntry> bgpRibIn3;
Collection<BgpRouteEntry> bgpRoutes;
Collection<Ip4Prefix> addedRoutes = new LinkedList<>();
Collection<Ip4Prefix> withdrawnRoutes = new LinkedList<>();
// Initiate the connections
peer1.connect(connectToSocket);
peer2.connect(connectToSocket);
peer3.connect(connectToSocket);
//
// Setup the initial set of routes to Peer1
//
addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
addedRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
// Write the routes
message = peer1.peerChannelHandler.prepareBgpUpdate(
NEXT_HOP1_ROUTER,
DEFAULT_LOCAL_PREF,
DEFAULT_MULTI_EXIT_DISC,
asPathLong,
addedRoutes,
withdrawnRoutes);
peer1.peerChannelHandler.savedCtx.getChannel().write(message);
bgpRoutes = waitForBgpRoutes(2);
assertThat(bgpRoutes, hasSize(2));
//
// Add a route entry to Peer2 with a better LOCAL_PREF
//
addedRoutes = new LinkedList<>();
withdrawnRoutes = new LinkedList<>();
addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
// Write the routes
message = peer2.peerChannelHandler.prepareBgpUpdate(
NEXT_HOP2_ROUTER,
BETTER_LOCAL_PREF,
DEFAULT_MULTI_EXIT_DISC,
asPathLong,
addedRoutes,
withdrawnRoutes);
peer2.peerChannelHandler.savedCtx.getChannel().write(message);
//
// Check that the routes have been received, processed and stored
//
bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
assertThat(bgpRibIn2, hasSize(1));
bgpRoutes = waitForBgpRoutes(2);
assertThat(bgpRoutes, hasSize(2));
//
bgpRouteEntry =
new BgpRouteEntry(bgpSession2,
Ip4Prefix.valueOf("20.0.0.0/8"),
NEXT_HOP2_ROUTER,
(byte) BgpConstants.Update.Origin.IGP,
asPathLong,
BETTER_LOCAL_PREF);
bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
//
// Add a route entry to Peer3 with a shorter AS path
//
addedRoutes = new LinkedList<>();
withdrawnRoutes = new LinkedList<>();
addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
// Write the routes
message = peer3.peerChannelHandler.prepareBgpUpdate(
NEXT_HOP3_ROUTER,
BETTER_LOCAL_PREF,
DEFAULT_MULTI_EXIT_DISC,
asPathShort,
addedRoutes,
withdrawnRoutes);
peer3.peerChannelHandler.savedCtx.getChannel().write(message);
//
// Check that the routes have been received, processed and stored
//
bgpRibIn3 = waitForBgpRibIn(bgpSession3, 1);
assertThat(bgpRibIn3, hasSize(1));
bgpRoutes = waitForBgpRoutes(2);
assertThat(bgpRoutes, hasSize(2));
//
bgpRouteEntry =
new BgpRouteEntry(bgpSession3,
Ip4Prefix.valueOf("20.0.0.0/8"),
NEXT_HOP3_ROUTER,
(byte) BgpConstants.Update.Origin.IGP,
asPathShort,
BETTER_LOCAL_PREF);
bgpRouteEntry.setMultiExitDisc(DEFAULT_MULTI_EXIT_DISC);
assertThat(bgpRibIn3, hasBgpRouteEntry(bgpRouteEntry));
assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
//
// Cleanup in preparation for next test: delete old route entry from
// Peer2
//
addedRoutes = new LinkedList<>();
withdrawnRoutes = new LinkedList<>();
withdrawnRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
// Write the routes
message = peer2.peerChannelHandler.prepareBgpUpdate(
NEXT_HOP2_ROUTER,
BETTER_LOCAL_PREF,
BETTER_MULTI_EXIT_DISC,
asPathShort,
addedRoutes,
withdrawnRoutes);
peer2.peerChannelHandler.savedCtx.getChannel().write(message);
//
// Check that the routes have been received, processed and stored
//
bgpRibIn2 = waitForBgpRibIn(bgpSession2, 0);
assertThat(bgpRibIn2, hasSize(0));
//
// Add a route entry to Peer2 with a better MED
//
addedRoutes = new LinkedList<>();
withdrawnRoutes = new LinkedList<>();
addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
// Write the routes
message = peer2.peerChannelHandler.prepareBgpUpdate(
NEXT_HOP2_ROUTER,
BETTER_LOCAL_PREF,
BETTER_MULTI_EXIT_DISC,
asPathShort,
addedRoutes,
withdrawnRoutes);
peer2.peerChannelHandler.savedCtx.getChannel().write(message);
//
// Check that the routes have been received, processed and stored
//
bgpRibIn2 = waitForBgpRibIn(bgpSession2, 1);
assertThat(bgpRibIn2, hasSize(1));
bgpRoutes = waitForBgpRoutes(2);
assertThat(bgpRoutes, hasSize(2));
//
bgpRouteEntry =
new BgpRouteEntry(bgpSession2,
Ip4Prefix.valueOf("20.0.0.0/8"),
NEXT_HOP2_ROUTER,
(byte) BgpConstants.Update.Origin.IGP,
asPathShort,
BETTER_LOCAL_PREF);
bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
assertThat(bgpRibIn2, hasBgpRouteEntry(bgpRouteEntry));
assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
//
// Add a route entry to Peer1 with a better (lower) BGP ID
//
addedRoutes = new LinkedList<>();
withdrawnRoutes = new LinkedList<>();
addedRoutes.add(Ip4Prefix.valueOf("20.0.0.0/8"));
withdrawnRoutes.add(Ip4Prefix.valueOf("30.0.0.0/16"));
// Write the routes
message = peer1.peerChannelHandler.prepareBgpUpdate(
NEXT_HOP1_ROUTER,
BETTER_LOCAL_PREF,
BETTER_MULTI_EXIT_DISC,
asPathShort,
addedRoutes,
withdrawnRoutes);
peer1.peerChannelHandler.savedCtx.getChannel().write(message);
//
// Check that the routes have been received, processed and stored
//
bgpRibIn1 = waitForBgpRibIn(bgpSession1, 1);
assertThat(bgpRibIn1, hasSize(1));
bgpRoutes = waitForBgpRoutes(1);
assertThat(bgpRoutes, hasSize(1));
//
bgpRouteEntry =
new BgpRouteEntry(bgpSession1,
Ip4Prefix.valueOf("20.0.0.0/8"),
NEXT_HOP1_ROUTER,
(byte) BgpConstants.Update.Origin.IGP,
asPathShort,
BETTER_LOCAL_PREF);
bgpRouteEntry.setMultiExitDisc(BETTER_MULTI_EXIT_DISC);
assertThat(bgpRibIn1, hasBgpRouteEntry(bgpRouteEntry));
assertThat(waitForBgpRoute(bgpRouteEntry), notNullValue());
// Close the channels and test there are no routes
peer1.peerChannelHandler.closeChannel();
peer2.peerChannelHandler.closeChannel();
peer3.peerChannelHandler.closeChannel();
bgpRoutes = waitForBgpRoutes(0);
assertThat(bgpRoutes, hasSize(0));
}
}