[ONOS-5607] Revise LISP ctrl impl class to track msgs and routers
Change-Id: I4a51a8ef9162e3feee543f40fa92a0435186d1c9
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 5c47109..1a3641d 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
@@ -29,6 +29,13 @@
Iterable<LispRouter> getRouters();
/**
+ * Obtains all subscribed LISP routers known to this LISP controllers.
+ *
+ * @return Iterable of LISP router elements
+ */
+ Iterable<LispRouter> getSubscribedRouters();
+
+ /**
* Obtains the actual router for the given LispRouterId.
*
* @param routerId the router to fetch
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 a6fa99f..5b32853 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 @@
* @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 c096131..aeebeeb 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
@@ -25,6 +25,11 @@
}
@Override
+ public Iterable<LispRouter> 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 4dcc736..d6570e8 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 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 622dae5..447eeb4 100644
--- a/protocols/lisp/ctl/BUCK
+++ b/protocols/lisp/ctl/BUCK
@@ -13,6 +13,7 @@
'//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 c8954bb..ea22bd3 100644
--- a/protocols/lisp/ctl/pom.xml
+++ b/protocols/lisp/ctl/pom.xml
@@ -61,6 +61,14 @@
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-lisp-api</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
<build>
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 29af596..449983a 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 @@
private EventLoopGroup eventLoopGroup;
private Class<? extends AbstractChannel> channelClass;
+ private List<ChannelFuture> channelFutures = Lists.newArrayList();
/**
* Stitches all channel handlers into server bootstrap.
@@ -59,8 +60,6 @@
configBootstrapOptions(bootstrap);
- List<ChannelFuture> channelFutures = Lists.newArrayList();
-
lispPorts.forEach(p -> {
InetSocketAddress sa = new InetSocketAddress(p);
channelFutures.add(bootstrap.bind(sa));
@@ -152,6 +151,7 @@
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 0d1bdf0..5d82527 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.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 @@
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;
@@ -61,45 +72,64 @@
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<LispRouterId, LispRouter> connectedRouters = Maps.newConcurrentMap();
+
+ private Set<LispRouterListener> lispRouterListeners = new CopyOnWriteArraySet<>();
+ private Set<LispMessageListener> 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 @@
@Override
public Iterable<LispRouter> getRouters() {
- return null;
+ return connectedRouters.values();
+ }
+
+ @Override
+ public Iterable<LispRouter> 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 0000000..8335d64
--- /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<LispRouterId> removedIds = Lists.newArrayList();
+ final List<LispRouterId> addedIds = Lists.newArrayList();
+ final List<LispRouterId> 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<LispMessage> incomingMessages = Lists.newArrayList();
+ final List<LispMessage> 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<String, Object> 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<LispRouter> 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<LispRouter> 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<LispMapRecord> 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 <T> type of the items in the iterable
+ * @return stream of objects of type T
+ */
+ private <T> Stream<T> makeIntoStream(Iterable<T> items) {
+ return StreamSupport.stream(
+ Spliterators.spliteratorUnknownSize(
+ items.iterator(), Spliterator.ORDERED), false);
+ }
+}
diff --git a/protocols/lisp/pom.xml b/protocols/lisp/pom.xml
index 45a3d3d..1103ed6 100644
--- a/protocols/lisp/pom.xml
+++ b/protocols/lisp/pom.xml
@@ -57,6 +57,10 @@
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
</dependencies>
</project>