/* * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.protocol.bmp.impl.app; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import com.google.common.base.Optional; import com.google.common.base.Stopwatch; import com.google.common.net.InetAddresses; import com.google.common.util.concurrent.Uninterruptibles; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.epoll.Epoll; import io.netty.channel.epoll.EpollEventLoopGroup; import io.netty.channel.epoll.EpollSocketChannel; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.util.concurrent.Future; import java.net.InetSocketAddress; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.function.Function; import javassist.ClassPool; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.MockitoAnnotations; import org.opendaylight.controller.config.yang.bmp.impl.MonitoredRouter; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec; import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.protocol.bgp.parser.impl.BGPActivator; import org.opendaylight.protocol.bgp.parser.spi.BGPExtensionProviderContext; import org.opendaylight.protocol.bgp.parser.spi.pojo.SimpleBGPExtensionProviderContext; import org.opendaylight.protocol.bgp.rib.impl.RIBActivator; import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionProviderContext; import org.opendaylight.protocol.bgp.rib.spi.SimpleRIBExtensionProviderContext; import org.opendaylight.protocol.bmp.api.BmpDispatcher; import org.opendaylight.protocol.bmp.impl.BmpActivator; import org.opendaylight.protocol.bmp.impl.BmpDispatcherImpl; import org.opendaylight.protocol.bmp.impl.BmpHandlerFactory; import org.opendaylight.protocol.bmp.impl.session.DefaultBmpSessionFactory; import org.opendaylight.protocol.bmp.impl.spi.BmpMonitoringStation; import org.opendaylight.protocol.bmp.impl.test.TestUtil; import org.opendaylight.protocol.bmp.spi.registry.BmpMessageRegistry; import org.opendaylight.protocol.bmp.spi.registry.SimpleBmpExtensionProviderContext; import org.opendaylight.protocol.concepts.KeyMapping; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bmp.monitor.monitor.router.peer.pre.policy.rib.tables.routes.Ipv4RoutesCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.update.attributes.mp.reach.nlri.advertized.routes.destination.type.DestinationIpv4Case; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.message.BgpParameters; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.CParameters1; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.MultiprotocolCapability; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutes; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.UnicastSubsequentAddressFamily; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.AdjRibInType; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.InitiationMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.PeerType; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.RouteMirroringMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.StatsReportsMessage; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.peer.up.ReceivedOpen; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.peer.up.SentOpen; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.message.rev150512.stat.Tlvs; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.BmpMonitor; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.MonitorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.RouterId; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.Status; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.bmp.monitor.Monitor; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.bmp.monitor.MonitorKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.peers.Peer; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.peers.PeerKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.peers.peer.Mirrors; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.peers.peer.PeerSession; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.peers.peer.PostPolicyRib; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.peers.peer.PrePolicyRib; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.peers.peer.Stats; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.routers.Router; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bmp.monitor.rev150512.routers.RouterKey; import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator; import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry; import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy; import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext; import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; import org.opendaylight.yangtools.yang.binding.util.BindingReflections; public class BmpMonitorImplTest extends AbstractDataBrokerTest { // the local port and address where the monitor (ODL) will listen for incoming BMP request private static final int MONITOR_LOCAL_PORT = 12345; private static final String MONITOR_LOCAL_ADDRESS = "127.0.0.10"; private static final String MONITOR_LOCAL_ADDRESS_2 = "127.0.0.11"; // the router (monitee) address where we are going to simulate a BMP request from private static final String REMOTE_ROUTER_ADDRESS_1 = "127.0.0.12"; private static final String REMOTE_ROUTER_ADDRESS_2 = "127.0.0.13"; private static final Ipv4Address PEER1 = new Ipv4Address("20.20.20.20"); private static final MonitorId MONITOR_ID = new MonitorId("monitor"); private static final KeyedInstanceIdentifier MONITOR_IID = InstanceIdentifier.create(BmpMonitor.class).child(Monitor.class, new MonitorKey(MONITOR_ID)); private static final PeerId PEER_ID = new PeerId(PEER1.getValue()); private static final String MD5_PASSWORD = "abcdef"; private BindingToNormalizedNodeCodec mappingService; private RIBActivator ribActivator; private BGPActivator bgpActivator; private BmpActivator bmpActivator; private BmpDispatcher dispatcher; private BmpMonitoringStation bmpApp; private BmpMessageRegistry msgRegistry; private List mrs; private ModuleInfoBackedContext moduleInfoBackedContext; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); this.mappingService = new BindingToNormalizedNodeCodec(GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(), new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault())))); this.moduleInfoBackedContext = ModuleInfoBackedContext.create(); this.moduleInfoBackedContext.registerModuleInfo(BindingReflections.getModuleInfo(InitiationMessage.class)); this.moduleInfoBackedContext.registerModuleInfo(BindingReflections.getModuleInfo(CParameters1.class)); this.moduleInfoBackedContext.registerModuleInfo(BindingReflections.getModuleInfo(BgpParameters.class)); this.moduleInfoBackedContext.registerModuleInfo(BindingReflections.getModuleInfo(MultiprotocolCapability.class)); this.moduleInfoBackedContext.registerModuleInfo(BindingReflections.getModuleInfo(DestinationIpv4Case.class)); this.moduleInfoBackedContext.registerModuleInfo(BindingReflections.getModuleInfo(AdvertizedRoutes.class)); this.moduleInfoBackedContext.registerModuleInfo(BindingReflections.getModuleInfo(SentOpen.class)); this.moduleInfoBackedContext.registerModuleInfo(BindingReflections.getModuleInfo(ReceivedOpen.class)); this.mappingService.onGlobalContextUpdated(this.moduleInfoBackedContext.tryToCreateSchemaContext().get()); final KeyMapping keys = KeyMapping.getKeyMapping(InetAddresses.forString(MONITOR_LOCAL_ADDRESS), MD5_PASSWORD); this.ribActivator = new RIBActivator(); final RIBExtensionProviderContext ribExtension = new SimpleRIBExtensionProviderContext(); this.ribActivator.startRIBExtensionProvider(ribExtension); this.bgpActivator = new BGPActivator(); final BGPExtensionProviderContext context = new SimpleBGPExtensionProviderContext(); this.bgpActivator.start(context); final SimpleBmpExtensionProviderContext ctx = new SimpleBmpExtensionProviderContext(); this.bmpActivator = new BmpActivator(context); this.bmpActivator.start(ctx); this.msgRegistry = ctx.getBmpMessageRegistry(); this.dispatcher = new BmpDispatcherImpl(new NioEventLoopGroup(), new NioEventLoopGroup(), ctx.getBmpMessageRegistry(), new DefaultBmpSessionFactory()); this.bmpApp = BmpMonitoringStationImpl.createBmpMonitorInstance(ribExtension, this.dispatcher, getDomBroker(), MONITOR_ID, new InetSocketAddress(InetAddresses.forString(MONITOR_LOCAL_ADDRESS), MONITOR_LOCAL_PORT), Optional.of(keys), this.mappingService.getCodecFactory(), this.moduleInfoBackedContext.getSchemaContext(), this.mrs); readData(InstanceIdentifier.create(BmpMonitor.class), monitor -> { Assert.assertEquals(1, monitor.getMonitor().size()); final Monitor bmpMonitor = monitor.getMonitor().get(0); Assert.assertEquals(MONITOR_ID, bmpMonitor.getMonitorId()); Assert.assertEquals(0, bmpMonitor.getRouter().size()); Assert.assertEquals(MONITOR_ID, bmpMonitor.getMonitorId()); Assert.assertEquals(0, bmpMonitor.getRouter().size()); return monitor; }); } @After public void tearDown() throws Exception { this.ribActivator.close(); this.bgpActivator.close(); this.bmpActivator.close(); this.dispatcher.close(); this.bmpApp.close(); this.mappingService.close(); readData(InstanceIdentifier.create(BmpMonitor.class), monitor -> { assertTrue(monitor.getMonitor().isEmpty()); return monitor; }); } @Test public void testRouterMonitoring() throws Exception { // first test if a single router monitoring is working final Channel channel1 = testMonitoringStation(REMOTE_ROUTER_ADDRESS_1); readData(MONITOR_IID, monitor -> { assertEquals(1, monitor.getRouter().size()); return monitor; }); final Channel channel2 = testMonitoringStation(REMOTE_ROUTER_ADDRESS_2); readData(MONITOR_IID, monitor -> { assertEquals(2, monitor.getRouter().size()); return monitor; }); // initiate another BMP request from router 1, create a redundant connection // we expect the connection to be closed final Channel channel3 = connectTestClient(REMOTE_ROUTER_ADDRESS_1, this.msgRegistry); Thread.sleep(500); // channel 1 should still be open, while channel3 should be closed assertTrue(channel1.isOpen()); assertFalse(channel3.isOpen()); // now if we close the channel 1 and try it again, it should succeed waitFutureSuccess(channel1.close()); // channel 2 is still open readData(MONITOR_IID, monitor -> { assertEquals(1, monitor.getRouter().size()); return monitor; }); final Channel channel4 = testMonitoringStation(REMOTE_ROUTER_ADDRESS_1); readData(MONITOR_IID, monitor -> { assertEquals(2, monitor.getRouter().size()); return monitor; }); // close all channel altogether waitFutureSuccess(channel2.close()); Thread.sleep(500); // sleep for a while to avoid intermittent InMemoryDataTree modification conflict waitFutureSuccess(channel4.close()); readData(MONITOR_IID, monitor -> { assertEquals(0, monitor.getRouter().size()); return monitor; }); } private static void waitFutureSuccess(final T future) throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); future.addListener(future1 -> latch.countDown()); Uninterruptibles.awaitUninterruptibly(latch, 10, TimeUnit.SECONDS); } private void waitWriteAndFlushSuccess(final ChannelFuture channelFuture) throws InterruptedException { waitFutureSuccess(channelFuture); } private Channel testMonitoringStation(final String remoteRouterIpAddr) throws InterruptedException { final Channel channel = connectTestClient(remoteRouterIpAddr, this.msgRegistry); final RouterId routerId = getRouterId(remoteRouterIpAddr); try { readData(MONITOR_IID, monitor -> { assertFalse(monitor.getRouter().isEmpty()); // now find the current router instance Router router = null; for (final Router r : monitor.getRouter()) { if (routerId.equals(r.getRouterId())) { router = r; break; } } assertNotNull(router); assertEquals(Status.Down, router.getStatus()); assertTrue(router.getPeer().isEmpty()); return router; }); waitWriteAndFlushSuccess(channel.writeAndFlush(TestUtil.createInitMsg("description", "name", "some info"))); readData(MONITOR_IID, monitor -> { assertFalse(monitor.getRouter().isEmpty()); Router retRouter = null; for (final Router r : monitor.getRouter()) { if (routerId.equals(r.getRouterId())) { retRouter = r; break; } } assertEquals("some info;", retRouter.getInfo()); assertEquals("name", retRouter.getName()); assertEquals("description", retRouter.getDescription()); assertEquals(routerId, retRouter.getRouterId()); assertTrue(retRouter.getPeer().isEmpty()); assertEquals(Status.Up, retRouter.getStatus()); return retRouter; }); waitWriteAndFlushSuccess(channel.writeAndFlush(TestUtil.createPeerUpNotification(PEER1, true))); final KeyedInstanceIdentifier routerIId = MONITOR_IID.child(Router.class, new RouterKey(routerId)); readData(routerIId, router -> { final List peers = router.getPeer(); assertEquals(1, peers.size()); final Peer peer = peers.get(0); assertEquals(PeerType.Global, peer.getType()); assertEquals(PEER_ID, peer.getPeerId()); assertEquals(PEER1, peer.getBgpId()); assertEquals(TestUtil.IPV4_ADDRESS_10, peer.getAddress().getIpv4Address()); assertEquals(TestUtil.PEER_AS, peer.getAs()); assertNull(peer.getDistinguisher()); assertNull(peer.getStats()); assertNotNull(peer.getPrePolicyRib()); assertEquals(1, peer.getPrePolicyRib().getTables().size()); final Tables prePolicyTable = peer.getPrePolicyRib().getTables().get(0); assertEquals(Ipv4AddressFamily.class, prePolicyTable.getAfi()); assertEquals(UnicastSubsequentAddressFamily.class, prePolicyTable.getSafi()); assertFalse(prePolicyTable.getAttributes().isUptodate()); assertNotNull(prePolicyTable.getRoutes()); assertNotNull(peer.getPostPolicyRib()); assertEquals(1, peer.getPostPolicyRib().getTables().size()); final Tables postPolicyTable = peer.getPrePolicyRib().getTables().get(0); assertEquals(Ipv4AddressFamily.class, postPolicyTable.getAfi()); assertEquals(UnicastSubsequentAddressFamily.class, postPolicyTable.getSafi()); assertFalse(postPolicyTable.getAttributes().isUptodate()); assertNotNull(postPolicyTable.getRoutes()); assertNotNull(peer.getPeerSession()); final PeerSession peerSession = peer.getPeerSession(); assertEquals(TestUtil.IPV4_ADDRESS_10, peerSession.getLocalAddress().getIpv4Address()); assertEquals(TestUtil.PEER_LOCAL_PORT, peerSession.getLocalPort()); assertEquals(TestUtil.PEER_REMOTE_PORT, peerSession.getRemotePort()); assertEquals(Status.Up, peerSession.getStatus()); assertNotNull(peerSession.getReceivedOpen()); assertNotNull(peerSession.getSentOpen()); return router; }); final StatsReportsMessage statsMsg = TestUtil.createStatsReportMsg(PEER1); waitWriteAndFlushSuccess(channel.writeAndFlush(statsMsg)); final KeyedInstanceIdentifier peerIId = routerIId.child(Peer.class, new PeerKey(PEER_ID)); readData(peerIId.child(Stats.class), peerStats -> { assertNotNull(peerStats.getTimestampSec()); final Tlvs tlvs = statsMsg.getTlvs(); assertEquals(tlvs.getAdjRibsInRoutesTlv().getCount(), peerStats.getAdjRibsInRoutes()); assertEquals(tlvs.getDuplicatePrefixAdvertisementsTlv().getCount(), peerStats.getDuplicatePrefixAdvertisements()); assertEquals(tlvs.getDuplicateWithdrawsTlv().getCount(), peerStats.getDuplicateWithdraws()); assertEquals(tlvs.getInvalidatedAsConfedLoopTlv().getCount(), peerStats.getInvalidatedAsConfedLoop()); assertEquals(tlvs.getInvalidatedAsPathLoopTlv().getCount(), peerStats.getInvalidatedAsPathLoop()); assertEquals(tlvs.getInvalidatedClusterListLoopTlv().getCount(), peerStats.getInvalidatedClusterListLoop()); assertEquals(tlvs.getInvalidatedOriginatorIdTlv().getCount(), peerStats.getInvalidatedOriginatorId()); assertEquals(tlvs.getLocRibRoutesTlv().getCount(), peerStats.getLocRibRoutes()); assertEquals(tlvs.getRejectedPrefixesTlv().getCount(), peerStats.getRejectedPrefixes()); assertEquals(tlvs.getPerAfiSafiAdjRibInTlv().getCount().toString(), peerStats.getPerAfiSafiAdjRibInRoutes().getAfiSafi().get(0).getCount().toString()); assertEquals(tlvs.getPerAfiSafiLocRibTlv().getCount().toString(), peerStats.getPerAfiSafiLocRibRoutes().getAfiSafi().get(0).getCount().toString()); return peerStats; }); // route mirror message test final RouteMirroringMessage routeMirrorMsg = TestUtil.createRouteMirrorMsg(PEER1); waitWriteAndFlushSuccess(channel.writeAndFlush(routeMirrorMsg)); readData(peerIId.child(Mirrors.class), routeMirrors -> { assertNotNull(routeMirrors.getTimestampSec()); return routeMirrors; }); waitWriteAndFlushSuccess(channel.writeAndFlush(TestUtil.createRouteMonitMsg(false, PEER1, AdjRibInType.PrePolicy))); waitWriteAndFlushSuccess(channel.writeAndFlush(TestUtil.createRouteMonMsgWithEndOfRibMarker(PEER1, AdjRibInType.PrePolicy))); readData(peerIId.child(PrePolicyRib.class), prePolicyRib -> { assertTrue(!prePolicyRib.getTables().isEmpty()); final Tables tables = prePolicyRib.getTables().get(0); assertTrue(tables.getAttributes().isUptodate()); assertEquals(3, ((Ipv4RoutesCase) tables.getRoutes()).getIpv4Routes().getIpv4Route().size()); return tables; }); waitWriteAndFlushSuccess(channel.writeAndFlush(TestUtil.createRouteMonitMsg(false, PEER1, AdjRibInType.PostPolicy))); waitWriteAndFlushSuccess(channel.writeAndFlush(TestUtil.createRouteMonMsgWithEndOfRibMarker(PEER1, AdjRibInType.PostPolicy))); readData(peerIId.child(PostPolicyRib.class), postPolicyRib -> { assertTrue(!postPolicyRib.getTables().isEmpty()); final Tables tables = postPolicyRib.getTables().get(0); assertTrue(tables.getAttributes().isUptodate()); assertEquals(3, ((org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.bmp.monitor.monitor.router.peer.post.policy.rib.tables.routes.Ipv4RoutesCase) tables.getRoutes()).getIpv4Routes().getIpv4Route().size()); return tables; }); waitWriteAndFlushSuccess(channel.writeAndFlush(TestUtil.createPeerDownNotification(PEER1))); readData(routerIId, router -> { final List peersAfterDown = router.getPeer(); assertTrue(peersAfterDown.isEmpty()); return router; }); } catch (final Exception e) { final StringBuffer ex = new StringBuffer(); ex.append(e.getMessage()).append("\n"); for (final StackTraceElement element : e.getStackTrace()) { ex.append(element.toString() + "\n"); } fail(ex.toString()); } return channel; } @Test public void deploySecondInstance() throws Exception { final BmpMonitoringStation monitoringStation2 = BmpMonitoringStationImpl.createBmpMonitorInstance(new SimpleRIBExtensionProviderContext(), this.dispatcher, getDomBroker(), new MonitorId("monitor2"), new InetSocketAddress(InetAddresses.forString(MONITOR_LOCAL_ADDRESS_2), MONITOR_LOCAL_PORT), Optional.of(KeyMapping.getKeyMapping()), this.mappingService.getCodecFactory(), this.moduleInfoBackedContext.getSchemaContext(), this.mrs); readData(InstanceIdentifier.create(BmpMonitor.class), monitor -> { Assert.assertEquals(2, monitor.getMonitor().size()); return monitor; }); monitoringStation2.close(); } private Channel connectTestClient(final String routerIp, final BmpMessageRegistry msgRegistry) throws InterruptedException { final BmpHandlerFactory hf = new BmpHandlerFactory(msgRegistry); final Bootstrap b = new Bootstrap(); final EventLoopGroup workerGroup; if(Epoll.isAvailable()){ b.channel(EpollSocketChannel.class); workerGroup =new EpollEventLoopGroup(); } else { b.channel(NioSocketChannel.class); workerGroup = new NioEventLoopGroup(); } b.group(workerGroup); b.option(ChannelOption.SO_KEEPALIVE, true); b.handler(new ChannelInitializer() { @Override protected void initChannel(final SocketChannel ch) throws Exception { ch.pipeline().addLast(hf.getDecoders()); ch.pipeline().addLast(hf.getEncoders()); } }); b.localAddress(new InetSocketAddress(routerIp, 0)); b.option(ChannelOption.SO_REUSEADDR, true); final ChannelFuture future = b.connect(new InetSocketAddress(MONITOR_LOCAL_ADDRESS, MONITOR_LOCAL_PORT)).sync(); waitFutureSuccess(future); return future.channel(); } private R readData(final InstanceIdentifier iid, final Function function) throws ReadFailedException { AssertionError lastError = null; final Stopwatch sw = Stopwatch.createStarted(); while(sw.elapsed(TimeUnit.SECONDS) <= 10) { try (final ReadOnlyTransaction tx = getDataBroker().newReadOnlyTransaction()) { final Optional data = tx.read(LogicalDatastoreType.OPERATIONAL, iid).checkedGet(); if(data.isPresent()) { try { return function.apply(data.get()); } catch (final AssertionError e) { lastError = e; Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS); } } } } throw lastError; } private RouterId getRouterId(final String routerIp) { return new RouterId(new IpAddress(new Ipv4Address(routerIp))); } }