diff --git a/protocols/lisp/api/src/main/java/org/onosproject/lisp/ctl/LispController.java b/protocols/lisp/api/src/main/java/org/onosproject/lisp/ctl/LispController.java index 5c471097d0..1a3641d1fe 100644 --- a/protocols/lisp/api/src/main/java/org/onosproject/lisp/ctl/LispController.java +++ b/protocols/lisp/api/src/main/java/org/onosproject/lisp/ctl/LispController.java @@ -28,6 +28,13 @@ public interface LispController { */ Iterable getRouters(); + /** + * Obtains all subscribed LISP routers known to this LISP controllers. + * + * @return Iterable of LISP router elements + */ + Iterable getSubscribedRouters(); + /** * Obtains the actual router for the given LispRouterId. * diff --git a/protocols/lisp/api/src/main/java/org/onosproject/lisp/ctl/LispRouter.java b/protocols/lisp/api/src/main/java/org/onosproject/lisp/ctl/LispRouter.java index a6fa99f7e2..5b328538a6 100644 --- a/protocols/lisp/api/src/main/java/org/onosproject/lisp/ctl/LispRouter.java +++ b/protocols/lisp/api/src/main/java/org/onosproject/lisp/ctl/LispRouter.java @@ -80,4 +80,47 @@ public interface LispRouter { * @return whether the router is connected */ boolean isConnected(); + + /** + * Sets whether the router is connected. + * + * @param connected whether the router is connected + */ + void setConnected(boolean connected); + + /** + * Checks if the router is subscribed. + * As long as a router sends Map-Request message, + * we treat the router is subscribed. + * + * @return whether the router is subscribed + */ + boolean isSubscribed(); + + /** + * Sets whether the router is subscribed. + * + * @param subscribed whether the router is subscribed + */ + void setSubscribed(boolean subscribed); + + /** + * Sets the LISP agent to be used. This method can only be invoked once. + * + * @param agent the agent to set + */ + void setAgent(LispRouterAgent agent); + + /** + * Announces to the LISP agent that this router has connected. + * + * @return true if successful, false if duplicate router + */ + boolean connectRouter(); + + /** + * Disconnects the router by closing UDP connection. + * Results in a call to the channel handler's close method for cleanup. + */ + void disconnectRouter(); } diff --git a/protocols/lisp/api/src/test/java/org/onosproject/lisp/ctl/LispControllerAdapter.java b/protocols/lisp/api/src/test/java/org/onosproject/lisp/ctl/LispControllerAdapter.java index c096131e3e..aeebeeb8da 100644 --- a/protocols/lisp/api/src/test/java/org/onosproject/lisp/ctl/LispControllerAdapter.java +++ b/protocols/lisp/api/src/test/java/org/onosproject/lisp/ctl/LispControllerAdapter.java @@ -24,6 +24,11 @@ public class LispControllerAdapter implements LispController { return null; } + @Override + public Iterable getSubscribedRouters() { + return null; + } + @Override public LispRouter getRouter(LispRouterId routerId) { return null; diff --git a/protocols/lisp/api/src/test/java/org/onosproject/lisp/ctl/LispRouterAdapter.java b/protocols/lisp/api/src/test/java/org/onosproject/lisp/ctl/LispRouterAdapter.java index 4dcc736464..d6570e8c7c 100644 --- a/protocols/lisp/api/src/test/java/org/onosproject/lisp/ctl/LispRouterAdapter.java +++ b/protocols/lisp/api/src/test/java/org/onosproject/lisp/ctl/LispRouterAdapter.java @@ -63,4 +63,34 @@ public class LispRouterAdapter implements LispRouter { public boolean isConnected() { return false; } + + @Override + public void setConnected(boolean connected) { + + } + + @Override + public boolean isSubscribed() { + return false; + } + + @Override + public void setSubscribed(boolean subscribed) { + + } + + @Override + public void setAgent(LispRouterAgent agent) { + + } + + @Override + public boolean connectRouter() { + return false; + } + + @Override + public void disconnectRouter() { + + } } diff --git a/protocols/lisp/ctl/BUCK b/protocols/lisp/ctl/BUCK index 622dae5799..447eeb4ac7 100644 --- a/protocols/lisp/ctl/BUCK +++ b/protocols/lisp/ctl/BUCK @@ -13,6 +13,7 @@ TEST_DEPS = [ '//lib:TEST_ADAPTERS', '//utils/osgi:onlab-osgi-tests', '//core/api:onos-api-tests', + '//protocols/lisp/api:onos-protocols-lisp-api-tests', ] osgi_jar_with_tests ( diff --git a/protocols/lisp/ctl/pom.xml b/protocols/lisp/ctl/pom.xml index c8954bbf16..ea22bd3faa 100644 --- a/protocols/lisp/ctl/pom.xml +++ b/protocols/lisp/ctl/pom.xml @@ -61,6 +61,14 @@ tests test + + org.onosproject + onos-lisp-api + ${project.version} + tests + test + + diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispControllerBootstrap.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispControllerBootstrap.java index 29af59632e..449983a039 100644 --- a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispControllerBootstrap.java +++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispControllerBootstrap.java @@ -48,6 +48,7 @@ public class LispControllerBootstrap { private EventLoopGroup eventLoopGroup; private Class channelClass; + private List channelFutures = Lists.newArrayList(); /** * Stitches all channel handlers into server bootstrap. @@ -59,8 +60,6 @@ public class LispControllerBootstrap { configBootstrapOptions(bootstrap); - List channelFutures = Lists.newArrayList(); - lispPorts.forEach(p -> { InetSocketAddress sa = new InetSocketAddress(p); channelFutures.add(bootstrap.bind(sa)); @@ -152,6 +151,7 @@ public class LispControllerBootstrap { try { // try to shutdown all open event groups eventLoopGroup.shutdownGracefully().sync(); + closeChannels(channelFutures); } catch (InterruptedException e) { log.warn("Failed to stop LISP controller. Reasons: {}.", e.getMessage()); } diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispControllerImpl.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispControllerImpl.java index 0d1bdf0812..5d82527069 100644 --- a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispControllerImpl.java +++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispControllerImpl.java @@ -15,6 +15,7 @@ */ package org.onosproject.lisp.ctl.impl; +import com.google.common.collect.Maps; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -29,18 +30,29 @@ import org.onosproject.core.CoreService; import org.onosproject.lisp.ctl.LispController; import org.onosproject.lisp.ctl.LispMessageListener; import org.onosproject.lisp.ctl.LispRouter; +import org.onosproject.lisp.ctl.LispRouterAgent; import org.onosproject.lisp.ctl.LispRouterId; import org.onosproject.lisp.ctl.LispRouterListener; import org.onosproject.lisp.msg.authentication.LispAuthenticationConfig; -import org.onosproject.net.device.DeviceService; +import org.onosproject.lisp.msg.protocols.LispInfoReply; +import org.onosproject.lisp.msg.protocols.LispInfoRequest; +import org.onosproject.lisp.msg.protocols.LispMessage; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.Dictionary; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.ExecutorService; +import static java.util.concurrent.Executors.newFixedThreadPool; +import static java.util.stream.Collectors.toConcurrentMap; import static org.onlab.util.Tools.get; import static org.onlab.util.Tools.getIntegerProperty; +import static org.onlab.util.Tools.groupedThreads; +import static org.slf4j.LoggerFactory.getLogger; /** * LISP controller initiation class. @@ -51,8 +63,7 @@ public class LispControllerImpl implements LispController { private static final String APP_ID = "org.onosproject.lisp-base"; - private static final Logger log = - LoggerFactory.getLogger(LispControllerImpl.class); + private static final Logger log = getLogger(LispControllerImpl.class); private static final String DEFAULT_LISP_AUTH_KEY = "onos"; private static final short DEFAULT_LISP_AUTH_KEY_ID = 1; @@ -60,46 +71,65 @@ public class LispControllerImpl implements LispController { @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected CoreService coreService; - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected DeviceService deviceService; - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected ComponentConfigService cfgService; @Property(name = "lispAuthKey", value = DEFAULT_LISP_AUTH_KEY, label = "Authentication key which is used to calculate authentication " + "data for LISP control message; default value is onos") - protected String lispAuthKey = DEFAULT_LISP_AUTH_KEY; + private String lispAuthKey = DEFAULT_LISP_AUTH_KEY; @Property(name = "lispAuthKeyId", intValue = DEFAULT_LISP_AUTH_KEY_ID, label = "Authentication key id which denotes the authentication method " + "that ONOS uses to calculate the authentication data; " + "1 denotes HMAC SHA1 encryption, 2 denotes HMAC SHA256 encryption; " + "default value is 1") - protected int lispAuthKeyId = DEFAULT_LISP_AUTH_KEY_ID; + private int lispAuthKeyId = DEFAULT_LISP_AUTH_KEY_ID; + + ExecutorService executorMessages = + newFixedThreadPool(4, groupedThreads("onos/lisp", "event-stats-%d", log)); + + protected LispRouterAgent agent = new DefaultLispRouterAgent(); + + ConcurrentMap connectedRouters = Maps.newConcurrentMap(); + + private Set lispRouterListeners = new CopyOnWriteArraySet<>(); + private Set lispMessageListeners = new CopyOnWriteArraySet<>(); private final LispControllerBootstrap bootstrap = new LispControllerBootstrap(); private final LispAuthenticationConfig authConfig = LispAuthenticationConfig.getInstance(); @Activate public void activate(ComponentContext context) { + coreService.registerApplication(APP_ID, this::cleanup); cfgService.registerProperties(getClass()); - coreService.registerApplication(APP_ID); initAuthConfig(context.getProperties()); bootstrap.start(); log.info("Started"); } + /** + * Shutdowns all listening channel and all LISP channels. + * Clean information about routers before deactivating. + */ + private void cleanup() { + bootstrap.stop(); + connectedRouters.values().forEach(LispRouter::disconnectRouter); + connectedRouters.clear(); + } + @Deactivate public void deactivate() { + cleanup(); cfgService.unregisterProperties(getClass(), false); - bootstrap.stop(); log.info("Stopped"); } @Modified public void modified(ComponentContext context) { readComponentConfiguration(context); + bootstrap.stop(); + bootstrap.start(); } /** @@ -138,31 +168,189 @@ public class LispControllerImpl implements LispController { @Override public Iterable getRouters() { - return null; + return connectedRouters.values(); + } + + @Override + public Iterable getSubscribedRouters() { + return connectedRouters.entrySet() + .stream() + .filter(e -> e.getValue().isSubscribed()) + .collect(toConcurrentMap(Map.Entry::getKey, + Map.Entry::getValue)).values(); } @Override public LispRouter getRouter(LispRouterId routerId) { - return null; + return connectedRouters.get(routerId); } @Override public void addRouterListener(LispRouterListener listener) { - + if (!lispRouterListeners.contains(listener)) { + lispRouterListeners.add(listener); + } } @Override public void removeRouterListener(LispRouterListener listener) { - + lispRouterListeners.remove(listener); } @Override public void addMessageListener(LispMessageListener listener) { - + if (!lispMessageListeners.contains(listener)) { + lispMessageListeners.add(listener); + } } @Override public void removeMessageListener(LispMessageListener listener) { + lispMessageListeners.remove(listener); + } + /** + * Implementation of a LISP agent which is responsible for keeping track of + * connected LISP routers and the state in which they are in. + */ + public final class DefaultLispRouterAgent implements LispRouterAgent { + + private final Logger log = getLogger(DefaultLispRouterAgent.class); + + /** + * Prevents object instantiation from external class. + */ + private DefaultLispRouterAgent() { + } + + @Override + public boolean addConnectedRouter(LispRouterId routerId, LispRouter router) { + + if (connectedRouters.get(routerId) != null) { + log.error("Trying to add connectedRouter but found a previous " + + "value for routerId: {}", routerId); + return false; + } else { + log.info("Added router {}", routerId); + connectedRouters.put(routerId, router); + for (LispRouterListener listener : lispRouterListeners) { + listener.routerAdded(routerId); + } + return true; + } + } + + @Override + public void removeConnectedRouter(LispRouterId routerId) { + + if (connectedRouters.get(routerId) == null) { + log.error("Trying to remove router {} from connectedRouter " + + "list but no element was found", routerId); + } else { + log.info("Removed router {}", routerId); + connectedRouters.remove(routerId); + for (LispRouterListener listener : lispRouterListeners) { + listener.routerRemoved(routerId); + } + } + } + + @Override + public void processUpstreamMessage(LispRouterId routerId, LispMessage message) { + + switch (message.getType()) { + case LISP_MAP_REGISTER: + case LISP_MAP_REQUEST: + executorMessages.execute( + new LispIncomingMessageHandler(routerId, message)); + break; + case LISP_INFO: + if (message instanceof LispInfoRequest) { + executorMessages.execute( + new LispIncomingMessageHandler(routerId, message)); + } else { + log.warn("Not incoming LISP control message"); + } + break; + default: + log.warn("Not incoming LISP control message"); + break; + } + } + + @Override + public void processDownstreamMessage(LispRouterId routerId, LispMessage message) { + + switch (message.getType()) { + case LISP_MAP_NOTIFY: + case LISP_MAP_REPLY: + executorMessages.execute( + new LispOutgoingMessageHandler(routerId, message)); + break; + case LISP_INFO: + if (message instanceof LispInfoReply) { + executorMessages.execute( + new LispOutgoingMessageHandler(routerId, message)); + } else { + log.warn("Not outgoing LISP control message"); + } + break; + default: + log.warn("Not outgoing LISP control message"); + break; + } + } + } + + /** + * LISP message handler. + */ + protected class LispMessageHandler implements Runnable { + + private final LispRouterId routerId; + private final LispMessage message; + private final boolean isIncoming; + + LispMessageHandler(LispRouterId routerId, + LispMessage message, boolean isIncoming) { + this.routerId = routerId; + this.message = message; + this.isIncoming = isIncoming; + } + + @Override + public void run() { + for (LispMessageListener listener : lispMessageListeners) { + if (isIncoming) { + listener.handleIncomingMessage(routerId, message); + } else { + listener.handleOutgoingMessage(routerId, message); + } + } + } + } + + /** + * LISP incoming message handler. + */ + protected final class LispIncomingMessageHandler + extends LispMessageHandler implements Runnable { + + LispIncomingMessageHandler(LispRouterId routerId, + LispMessage message) { + super(routerId, message, true); + } + } + + /** + * LISP outgoing message handler. + */ + protected final class LispOutgoingMessageHandler + extends LispMessageHandler implements Runnable { + + LispOutgoingMessageHandler(LispRouterId routerId, + LispMessage message) { + super(routerId, message, false); + } } } diff --git a/protocols/lisp/ctl/src/test/java/org/onosproject/lisp/ctl/impl/LispControllerImplTest.java b/protocols/lisp/ctl/src/test/java/org/onosproject/lisp/ctl/impl/LispControllerImplTest.java new file mode 100644 index 0000000000..8335d6478e --- /dev/null +++ b/protocols/lisp/ctl/src/test/java/org/onosproject/lisp/ctl/impl/LispControllerImplTest.java @@ -0,0 +1,329 @@ +/* + * Copyright 2016-present 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.lisp.ctl.impl; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import org.easymock.EasyMock; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onosproject.cfg.ComponentConfigService; +import org.onosproject.core.CoreService; +import org.onosproject.lisp.ctl.LispMessageListener; +import org.onosproject.lisp.ctl.LispRouter; +import org.onosproject.lisp.ctl.LispRouterAdapter; +import org.onosproject.lisp.ctl.LispRouterAgent; +import org.onosproject.lisp.ctl.LispRouterId; +import org.onosproject.lisp.ctl.LispRouterListener; +import org.onosproject.lisp.msg.protocols.DefaultLispMapNotify.DefaultNotifyBuilder; +import org.onosproject.lisp.msg.protocols.DefaultLispMapRecord.DefaultMapRecordBuilder; +import org.onosproject.lisp.msg.protocols.DefaultLispMapRegister.DefaultRegisterBuilder; +import org.onosproject.lisp.msg.protocols.LispMapNotify; +import org.onosproject.lisp.msg.protocols.LispMapNotify.NotifyBuilder; +import org.onosproject.lisp.msg.protocols.LispMapRecord; +import org.onosproject.lisp.msg.protocols.LispMapRecord.MapRecordBuilder; +import org.onosproject.lisp.msg.protocols.LispMapRegister; +import org.onosproject.lisp.msg.protocols.LispMapRegister.RegisterBuilder; +import org.onosproject.lisp.msg.protocols.LispMapReplyAction; +import org.onosproject.lisp.msg.protocols.LispMessage; +import org.onosproject.lisp.msg.types.LispIpv4Address; +import org.osgi.service.component.ComponentContext; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.concurrent.CountDownLatch; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import static junit.framework.TestCase.fail; +import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.replay; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + +/** + * Unit tests for the LISP controller implementation class. + */ +public class LispControllerImplTest { + + private LispRouterId routerId1; + private LispRouterId routerId2; + private LispRouterId routerId3; + private LispRouter router1; + private LispRouter router2; + private LispRouter router3; + + private LispControllerImpl controller; + private LispRouterAgent agent; + private TestRouterListener routerListener; + private TestMessageListener messageListener; + + /** + * Tests harness for a router routerListener. + */ + static final class TestRouterListener implements LispRouterListener { + + final List removedIds = Lists.newArrayList(); + final List addedIds = Lists.newArrayList(); + final List changedIds = Lists.newArrayList(); + + @Override + public void routerAdded(LispRouterId routerId) { + addedIds.add(routerId); + } + + @Override + public void routerRemoved(LispRouterId routerId) { + removedIds.add(routerId); + } + + @Override + public void routerChanged(LispRouterId routerId) { + changedIds.add(routerId); + } + } + + /** + * Tests harness for a router messageListener. + */ + static final class TestMessageListener implements LispMessageListener { + + final List incomingMessages = Lists.newArrayList(); + final List outgoingMessages = Lists.newArrayList(); + + CountDownLatch incomingLatch = new CountDownLatch(1); + CountDownLatch outgoingLatch = new CountDownLatch(1); + + @Override + public void handleIncomingMessage(LispRouterId routerId, LispMessage msg) { + synchronized (incomingMessages) { + incomingMessages.add(msg); + incomingLatch.countDown(); + } + } + + @Override + public void handleOutgoingMessage(LispRouterId routerId, LispMessage msg) { + synchronized (outgoingMessages) { + outgoingMessages.add(msg); + outgoingLatch.countDown(); + } + } + + public void waitUntilUpdateIsCalled() throws InterruptedException { + incomingLatch.await(); + outgoingLatch.await(); + } + } + + /** + * Sets up routers to use as data, mocks and launches a controller instance. + */ + @Before + public void setUp() { + try { + router1 = new LispRouterAdapter(); + routerId1 = LispRouterId.routerId(new URI("lisp:10.1.1.1")); + router2 = new LispRouterAdapter(); + routerId2 = LispRouterId.routerId(new URI("lisp:10.1.1.2")); + router3 = new LispRouterAdapter(); + routerId3 = LispRouterId.routerId(new URI("lisp:10.1.1.3")); + + } catch (URISyntaxException e) { + // this will never happen... + fail(); + } + + controller = new LispControllerImpl(); + agent = controller.agent; + + routerListener = new TestRouterListener(); + controller.addRouterListener(routerListener); + + messageListener = new TestMessageListener(); + controller.addMessageListener(messageListener); + + controller.coreService = EasyMock.createMock(CoreService.class); + + ComponentConfigService mockConfigService = + EasyMock.createMock(ComponentConfigService.class); + expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of()); + mockConfigService.registerProperties(controller.getClass()); + expectLastCall(); + mockConfigService.unregisterProperties(controller.getClass(), false); + expectLastCall(); + expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of()); + controller.cfgService = mockConfigService; + replay(mockConfigService); + + ComponentContext mockContext = EasyMock.createMock(ComponentContext.class); + Dictionary properties = new Hashtable<>(); + properties.put("lispAuthKey", "onos"); + properties.put("lispAuthKeyId", 1); + expect(mockContext.getProperties()).andReturn(properties); + replay(mockContext); + controller.activate(mockContext); + } + + @After + public void tearDown() { + + controller.removeRouterListener(routerListener); + controller.removeMessageListener(messageListener); + controller.deactivate(); + } + + /** + * Tests adding and removing connected routers. + */ + @Test + public void testAddRemoveConnectedRouter() { + + // Test adding connected routers into agent + boolean addRouter1 = agent.addConnectedRouter(routerId1, router1); + assertThat(addRouter1, is(true)); + boolean addRouter2 = agent.addConnectedRouter(routerId2, router2); + assertThat(addRouter2, is(true)); + boolean addRouter3 = agent.addConnectedRouter(routerId3, router3); + assertThat(addRouter3, is(true)); + + // Test the callback methods that contained in router listener is fired + assertThat(routerListener.addedIds, hasSize(3)); + assertThat(routerListener.addedIds, hasItems(routerId1, routerId2, routerId3)); + + // Test adding a router twice (duplicated router) + // this should return false to indicate that there is already a router + // has been added previously + boolean addBadRouter1 = agent.addConnectedRouter(routerId1, router1); + assertThat(addBadRouter1, is(false)); + + // Also make sure that the duplicated router will never increase the counter + assertThat(controller.connectedRouters.size(), is(3)); + + // Test querying the router list + Stream queriedRouters = makeIntoStream(controller.getRouters()); + long routerCount = queriedRouters.count(); + assertThat(routerCount, is(3L)); + + // Test querying the individual router + LispRouter queriedRouter = controller.getRouter(routerId1); + assertThat(queriedRouter, is(router1)); + + // Test removing a router from connected router collection + agent.removeConnectedRouter(routerId2); + Stream queriedRoutersAfterRemoval = + makeIntoStream(controller.getRouters()); + long routerCountAfterRemoval = queriedRoutersAfterRemoval.count(); + assertThat(routerCountAfterRemoval, is(2L)); + + // Test the callback methods that contained in router listener is fired + assertThat(routerListener.removedIds, hasSize(1)); + assertThat(routerListener.removedIds, hasItems(routerId2)); + + // Test querying the removed switch + LispRouter queriedRouterAfterRemoval = controller.getRouter(routerId2); + assertThat(queriedRouterAfterRemoval, nullValue()); + } + + /** + * Tests adding and removing LISP messages. + */ + @Test + public void testLispMessagePopulate() throws InterruptedException { + + RegisterBuilder registerBuilder = new DefaultRegisterBuilder(); + List records = ImmutableList.of(getMapRecord(), getMapRecord()); + LispMapRegister register = registerBuilder + .withIsProxyMapReply(true) + .withIsWantMapNotify(false) + .withKeyId((short) 1) + .withAuthKey("onos") + .withNonce(1L) + .withMapRecords(records) + .build(); + + NotifyBuilder notifyBuilder = new DefaultNotifyBuilder(); + LispMapNotify notify = notifyBuilder + .withKeyId((short) 1) + .withAuthKey("onos") + .withNonce(1L) + .withMapRecords(records) + .build(); + + // Test the callback methods that contained in message listener is fired + agent.processUpstreamMessage(routerId1, register); + // Following line will be ignored + agent.processUpstreamMessage(routerId1, notify); + + agent.processDownstreamMessage(routerId1, notify); + // Following line will be ignored + agent.processDownstreamMessage(routerId1, register); + + messageListener.waitUntilUpdateIsCalled(); + + assertThat(messageListener.incomingMessages, hasSize(1)); + assertThat(messageListener.incomingMessages, hasItems(register)); + + assertThat(messageListener.outgoingMessages, hasSize(1)); + assertThat(messageListener.outgoingMessages, hasItems(notify)); + } + + /** + * Generates and returns a map record. + * + * @return a map record + */ + private LispMapRecord getMapRecord() { + MapRecordBuilder builder1 = new DefaultMapRecordBuilder(); + + LispIpv4Address ipv4Locator1 = new LispIpv4Address(IpAddress.valueOf("192.168.1.1")); + + return builder1 + .withRecordTtl(100) + .withAuthoritative(true) + .withMapVersionNumber((short) 1) + .withMaskLength((byte) 0x01) + .withAction(LispMapReplyAction.NativelyForward) + .withEidPrefixAfi(ipv4Locator1) + .build(); + } + + /** + * Converts an Iterable of some type into a stream of that type. + * + * @param items Iterable of objects + * @param type of the items in the iterable + * @return stream of objects of type T + */ + private Stream makeIntoStream(Iterable items) { + return StreamSupport.stream( + Spliterators.spliteratorUnknownSize( + items.iterator(), Spliterator.ORDERED), false); + } +} diff --git a/protocols/lisp/pom.xml b/protocols/lisp/pom.xml index 45a3d3d29d..1103ed6aab 100644 --- a/protocols/lisp/pom.xml +++ b/protocols/lisp/pom.xml @@ -57,6 +57,10 @@ easymock test + + org.osgi + org.osgi.core +