Refactor LISP package to separate ctrl interface and impl classes
Change-Id: I4e94ff54299e886cd0e8b3ce38591b0900290f54
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispChannelHandler.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispChannelHandler.java
new file mode 100644
index 0000000..a36031e
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispChannelHandler.java
@@ -0,0 +1,117 @@
+/*
+ * 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 io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
+import io.netty.util.ReferenceCountUtil;
+import org.onosproject.lisp.msg.protocols.LispEncapsulatedControl;
+import org.onosproject.lisp.msg.protocols.LispMapNotify;
+import org.onosproject.lisp.msg.protocols.LispMapRegister;
+import org.onosproject.lisp.msg.protocols.LispInfoReply;
+import org.onosproject.lisp.msg.protocols.LispInfoRequest;
+import org.onosproject.lisp.msg.protocols.LispMapRequest;
+import org.onosproject.lisp.msg.protocols.LispMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Channel handler deals with the xTR connection and dispatches xTR messages
+ * to the appropriate locations.
+ */
+public class LispChannelHandler extends ChannelInboundHandlerAdapter {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+
+ try {
+ // first we need to check whether this is an ECM
+ if (msg instanceof LispEncapsulatedControl) {
+ LispMessage innerMsg = extractLispMessage((LispEncapsulatedControl) msg);
+ if (innerMsg instanceof LispMapRequest) {
+ LispMapResolver mapResolver = LispMapResolver.getInstance();
+ LispMessage lispMessage =
+ mapResolver.processMapRequest((LispEncapsulatedControl) msg);
+
+ ctx.writeAndFlush(lispMessage);
+ }
+ }
+
+ if (msg instanceof LispMapRegister) {
+ LispMapServer mapServer = LispMapServer.getInstance();
+ LispMapNotify mapNotify =
+ mapServer.processMapRegister((LispMapRegister) msg);
+
+ if (mapNotify != null) {
+ ctx.writeAndFlush(mapNotify);
+ }
+ }
+
+ if (msg instanceof LispInfoRequest) {
+ LispMapServer mapServer = LispMapServer.getInstance();
+ LispInfoReply infoReply = mapServer.processInfoRequest((LispInfoRequest) msg);
+
+ ctx.writeAndFlush(infoReply);
+ }
+ } finally {
+ // try to remove the received message form the buffer
+ ReferenceCountUtil.release(msg);
+ }
+ }
+
+ @Override
+ public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
+ throws Exception {
+
+ if (evt instanceof IdleStateEvent) {
+ IdleStateEvent event = (IdleStateEvent) evt;
+ if (event.state() == IdleState.READER_IDLE) {
+ log.info("READER_IDLE read timeout");
+ ctx.disconnect();
+ } else if (event.state() == IdleState.WRITER_IDLE) {
+ log.info("WRITER_IDLE write timeout");
+ ctx.disconnect();
+ } else if (event.state() == IdleState.ALL_IDLE) {
+ log.info("ALL_IDLE total timeout");
+ ctx.disconnect();
+ }
+ }
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
+ throws Exception {
+ log.warn(cause.getMessage());
+
+ //TODO: add error handle mechanisms for each cases
+ }
+
+ /**
+ * Extracts LISP message from encapsulated control message.
+ *
+ * @param ecm Encapsulated Control Message
+ * @return extracted LISP message
+ */
+ private LispMessage extractLispMessage(LispEncapsulatedControl ecm) {
+ LispMessage message = ecm.getControlMessage();
+ message.configSender(ecm.getSender());
+ return message;
+ }
+}
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispChannelInitializer.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispChannelInitializer.java
new file mode 100644
index 0000000..d153546
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispChannelInitializer.java
@@ -0,0 +1,44 @@
+/*
+ * 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 io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.nio.NioDatagramChannel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Creates a ChannelInitializer for a server-side LISP channel.
+ */
+public final class LispChannelInitializer extends ChannelInitializer<NioDatagramChannel> {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private static final String LISP_MESSAGE_DECODER = "lispmessagedecoder";
+ private static final String LISP_MESSAGE_ENCODER = "lispmessageencoder";
+ private static final String LISP_CHANNEL_HANDLER = "handler";
+
+ @Override
+ protected void initChannel(NioDatagramChannel channel) throws Exception {
+ ChannelPipeline pipeline = channel.pipeline();
+
+ LispChannelHandler handler = new LispChannelHandler();
+
+ pipeline.addLast(LISP_MESSAGE_DECODER, new LispMessageDecoder());
+ pipeline.addLast(LISP_MESSAGE_ENCODER, new LispMessageEncoder());
+ pipeline.addLast(LISP_CHANNEL_HANDLER, handler);
+ }
+}
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
new file mode 100644
index 0000000..29af596
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispControllerBootstrap.java
@@ -0,0 +1,159 @@
+/*
+ * 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.Lists;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.buffer.PooledByteBufAllocator;
+import io.netty.channel.AbstractChannel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.epoll.EpollDatagramChannel;
+import io.netty.channel.epoll.EpollEventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioDatagramChannel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetSocketAddress;
+import java.util.List;
+
+/**
+ * Bootstraps LISP netty channel, handles all setup and network listeners.
+ */
+public class LispControllerBootstrap {
+
+ protected static final Logger log = LoggerFactory.getLogger(LispControllerBootstrap.class);
+
+ private static final int LISP_DATA_PORT = 4341;
+ private static final int LISP_CONTROL_PORT = 4342;
+
+ // Configuration options
+ protected List<Integer> lispPorts = ImmutableList.of(LISP_DATA_PORT, LISP_CONTROL_PORT);
+
+ private EventLoopGroup eventLoopGroup;
+ private Class<? extends AbstractChannel> channelClass;
+
+ /**
+ * Stitches all channel handlers into server bootstrap.
+ */
+ private void run() {
+
+ try {
+ final Bootstrap bootstrap = createServerBootstrap();
+
+ configBootstrapOptions(bootstrap);
+
+ List<ChannelFuture> channelFutures = Lists.newArrayList();
+
+ lispPorts.forEach(p -> {
+ InetSocketAddress sa = new InetSocketAddress(p);
+ channelFutures.add(bootstrap.bind(sa));
+ log.info("Listening for LISP router connections on {}", sa);
+ });
+
+ for (ChannelFuture f : channelFutures) {
+ f.sync();
+ }
+
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Initializes server bootstrap with given LISP channel initializer.
+ *
+ * @return initialized server bootstrap
+ */
+ private Bootstrap createServerBootstrap() {
+ Bootstrap bootstrap = new Bootstrap();
+
+ initEventLoopGroup();
+ bootstrap.group(eventLoopGroup)
+ .channel(channelClass)
+ .handler(new LispChannelInitializer());
+
+ return bootstrap;
+ }
+
+ /**
+ * Configures bootstrap options to tune the communication performance.
+ *
+ * @param bootstrap LISP server bootstrap
+ */
+ private void configBootstrapOptions(Bootstrap bootstrap) {
+ bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
+ }
+
+ /**
+ * Closes all open channels.
+ *
+ * @param channelFutures a collection of channel futures
+ */
+ private void closeChannels(List<ChannelFuture> channelFutures) {
+ try {
+ for (ChannelFuture f : channelFutures) {
+ f.channel().closeFuture().sync();
+ }
+ } catch (InterruptedException e) {
+ log.warn("Failed to close channels. Reasons: {}.", e.getMessage());
+ }
+ }
+
+ /**
+ * Initializes event loop group.
+ */
+ private void initEventLoopGroup() {
+
+ // try to use EpollEventLoopGroup if possible,
+ // if OS does not support native Epoll, fallback to use netty NIO
+ try {
+ eventLoopGroup = new EpollEventLoopGroup();
+ channelClass = EpollDatagramChannel.class;
+ } catch (Throwable e) {
+ log.debug("Failed to initialize native (epoll) transport. "
+ + "Reason: {}. Proceeding with NIO event group.", e.getMessage());
+ }
+ eventLoopGroup = new NioEventLoopGroup();
+ channelClass = NioDatagramChannel.class;
+ }
+
+ /**
+ * Launches LISP controller to listen control channel.
+ */
+ public void start() {
+ log.info("Starting LISP control I/O");
+
+ this.run();
+ }
+
+ /**
+ * Terminates LISP controller and lease all occupied resources.
+ */
+ public void stop() {
+ log.info("Stopping LISP control I/O");
+
+ try {
+ // try to shutdown all open event groups
+ eventLoopGroup.shutdownGracefully().sync();
+ } 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
new file mode 100644
index 0000000..e8dae2c
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispControllerImpl.java
@@ -0,0 +1,134 @@
+/*
+ * 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 org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.util.Tools;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.core.CoreService;
+import org.onosproject.lisp.ctl.LispController;
+import org.onosproject.lisp.msg.authentication.LispAuthenticationConfig;
+import org.onosproject.net.device.DeviceService;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Dictionary;
+
+import static org.onlab.util.Tools.get;
+import static org.onlab.util.Tools.getIntegerProperty;
+
+/**
+ * LISP controller initiation class.
+ */
+@Component(immediate = true)
+@Service
+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 String DEFAULT_LISP_AUTH_KEY = "onos";
+ private static final short DEFAULT_LISP_AUTH_KEY_ID = 1;
+
+ @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;
+
+ @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 final LispControllerBootstrap bootstrap = new LispControllerBootstrap();
+ private final LispAuthenticationConfig authConfig = LispAuthenticationConfig.getInstance();
+
+ @Activate
+ public void activate(ComponentContext context) {
+ cfgService.registerProperties(getClass());
+ coreService.registerApplication(APP_ID);
+ initAuthConfig(context.getProperties());
+ bootstrap.start();
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ cfgService.unregisterProperties(getClass(), false);
+ bootstrap.stop();
+ log.info("Stopped");
+ }
+
+ @Modified
+ public void modified(ComponentContext context) {
+ readComponentConfiguration(context);
+ }
+
+ /**
+ * Initializes authentication key and authentication method.
+ *
+ * @param properties a set of properties that contained in component context
+ */
+ private void initAuthConfig(Dictionary<?, ?> properties) {
+ authConfig.updateLispAuthKey(get(properties, "lispAuthKey"));
+ authConfig.updateLispAuthKeyId(getIntegerProperty(properties, "lispAuthKeyId"));
+ }
+
+ /**
+ * Extracts properties from the component configuration context.
+ *
+ * @param context the component context
+ */
+ private void readComponentConfiguration(ComponentContext context) {
+ Dictionary<?, ?> properties = context.getProperties();
+
+ String lispAuthKeyStr = Tools.get(properties, "lispAuthKey");
+ lispAuthKey = lispAuthKeyStr != null ? lispAuthKeyStr : DEFAULT_LISP_AUTH_KEY;
+ authConfig.updateLispAuthKey(lispAuthKey);
+ log.info("Configured. LISP authentication key is {}", lispAuthKey);
+
+ Integer lispAuthMethodInt = Tools.getIntegerProperty(properties, "lispAuthKeyId");
+ if (lispAuthMethodInt == null) {
+ lispAuthKeyId = DEFAULT_LISP_AUTH_KEY_ID;
+ log.info("LISP authentication method is not configured, default value is {}", lispAuthKeyId);
+ } else {
+ lispAuthKeyId = lispAuthMethodInt;
+ log.info("Configured. LISP authentication method is configured to {}", lispAuthKeyId);
+ }
+ authConfig.updateLispAuthKeyId(lispAuthKeyId);
+ }
+}
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMapResolver.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMapResolver.java
new file mode 100644
index 0000000..5784a07
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMapResolver.java
@@ -0,0 +1,102 @@
+/*
+ * 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 org.onosproject.lisp.msg.protocols.DefaultLispMapReply.DefaultReplyBuilder;
+import org.onosproject.lisp.msg.protocols.LispEncapsulatedControl;
+import org.onosproject.lisp.msg.protocols.LispMapRecord;
+import org.onosproject.lisp.msg.protocols.LispMapReply;
+import org.onosproject.lisp.msg.protocols.LispMapReply.ReplyBuilder;
+import org.onosproject.lisp.msg.protocols.LispMessage;
+import org.onosproject.lisp.msg.types.LispIpAddress;
+import org.onosproject.lisp.msg.protocols.LispMapRequest;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetSocketAddress;
+import java.util.List;
+
+/**
+ * LISP map resolver class.
+ * Handles map-request message and acknowledges with map-reply message.
+ */
+public final class LispMapResolver {
+
+ private static final Logger log = LoggerFactory.getLogger(LispMapResolver.class);
+
+ private LispMappingDatabase mapDb = LispMappingDatabase.getInstance();
+
+ // non-instantiable (except for our Singleton)
+ private LispMapResolver() {
+ }
+
+ public static LispMapResolver getInstance() {
+ return SingletonHelper.INSTANCE;
+ }
+
+ /**
+ * Handles encapsulated control message and replies with map-reply message.
+ *
+ * @param message encapsulated control message
+ * @return map-reply message
+ */
+ public LispMessage processMapRequest(LispMessage message) {
+
+ LispEncapsulatedControl ecm = (LispEncapsulatedControl) message;
+ LispMapRequest request = (LispMapRequest) ecm.getControlMessage();
+
+ // build map-reply message
+ ReplyBuilder replyBuilder = new DefaultReplyBuilder();
+ replyBuilder.withNonce(request.getNonce());
+ replyBuilder.withIsEtr(false);
+ replyBuilder.withIsSecurity(false);
+ replyBuilder.withIsProbe(request.isProbe());
+
+ List<LispMapRecord> mapRecords = mapDb.getMapRecordByEidRecords(request.getEids());
+
+ if (mapRecords.size() == 0) {
+ log.warn("Map information is not found.");
+ } else {
+ replyBuilder.withMapRecords(mapRecords);
+ }
+
+ LispMapReply reply = replyBuilder.build();
+
+ if (request.getItrRlocs() != null && request.getItrRlocs().size() > 0) {
+ LispIpAddress itr = (LispIpAddress) request.getItrRlocs().get(0);
+ InetSocketAddress address = new InetSocketAddress(itr.getAddress().toInetAddress(),
+ ecm.innerUdp().getSourcePort());
+ reply.configSender(address);
+ } else {
+ log.warn("No ITR RLOC is found, cannot respond back to ITR.");
+ }
+
+ return reply;
+ }
+
+ /**
+ * Prevents object instantiation from external.
+ */
+ private static final class SingletonHelper {
+ private static final String ILLEGAL_ACCESS_MSG = "Should not instantiate this class.";
+ private static final LispMapResolver INSTANCE = new LispMapResolver();
+
+ private SingletonHelper() {
+ throw new IllegalAccessError(ILLEGAL_ACCESS_MSG);
+ }
+ }
+}
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMapServer.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMapServer.java
new file mode 100644
index 0000000..58792a2
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMapServer.java
@@ -0,0 +1,226 @@
+/*
+ * 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 org.onlab.packet.IpAddress;
+import org.onosproject.lisp.msg.authentication.LispAuthenticationConfig;
+import org.onosproject.lisp.msg.protocols.DefaultLispInfoReply.DefaultInfoReplyBuilder;
+import org.onosproject.lisp.msg.protocols.DefaultLispInfoRequest.DefaultInfoRequestBuilder;
+import org.onosproject.lisp.msg.protocols.DefaultLispMapNotify.DefaultNotifyBuilder;
+import org.onosproject.lisp.msg.protocols.DefaultLispMapRegister.DefaultRegisterBuilder;
+import org.onosproject.lisp.msg.protocols.LispEidRecord;
+import org.onosproject.lisp.msg.protocols.LispInfoReply;
+import org.onosproject.lisp.msg.protocols.LispInfoReply.InfoReplyBuilder;
+import org.onosproject.lisp.msg.protocols.LispInfoRequest;
+import org.onosproject.lisp.msg.protocols.LispInfoRequest.InfoRequestBuilder;
+import org.onosproject.lisp.msg.protocols.LispMapNotify;
+import org.onosproject.lisp.msg.protocols.LispMapNotify.NotifyBuilder;
+import org.onosproject.lisp.msg.protocols.LispMapRegister;
+import org.onosproject.lisp.msg.protocols.LispMapRegister.RegisterBuilder;
+import org.onosproject.lisp.msg.protocols.LispMessage;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+import org.onosproject.lisp.msg.types.LispIpv4Address;
+import org.onosproject.lisp.msg.types.LispIpv6Address;
+import org.onosproject.lisp.msg.types.LispNatLcafAddress.NatAddressBuilder;
+import org.onosproject.lisp.msg.types.LispNoAddress;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
+import static org.onosproject.lisp.msg.authentication.LispAuthenticationKeyEnum.valueOf;
+
+/**
+ * LISP map server class.
+ * Handles map-register message and acknowledges with map-notify message.
+ */
+public final class LispMapServer {
+
+ private static final int MAP_NOTIFY_PORT = 4342;
+ private static final int INFO_REPLY_PORT = 4342;
+
+ private static final Logger log = LoggerFactory.getLogger(LispMapServer.class);
+
+ private LispMappingDatabase mapDb = LispMappingDatabase.getInstance();
+ private LispAuthenticationConfig authConfig = LispAuthenticationConfig.getInstance();
+
+ // non-instantiable (except for our Singleton)
+ private LispMapServer() {
+ }
+
+ public static LispMapServer getInstance() {
+ return SingletonHelper.INSTANCE;
+ }
+
+ /**
+ * Handles map-register message and replies with map-notify message.
+ *
+ * @param message map-register message
+ * @return map-notify message
+ */
+ public LispMapNotify processMapRegister(LispMessage message) {
+
+ LispMapRegister register = (LispMapRegister) message;
+
+ if (!checkMapRegisterAuthData(register)) {
+ log.warn("Unmatched authentication data of Map-Register");
+ return null;
+ }
+
+ register.getMapRecords().forEach(mapRecord -> {
+ LispEidRecord eidRecord =
+ new LispEidRecord(mapRecord.getMaskLength(),
+ mapRecord.getEidPrefixAfi());
+
+ mapDb.putMapRecord(eidRecord, mapRecord);
+ });
+
+ // we only acknowledge back to ETR when want-map-notify bit is set to true
+ // otherwise, we do not acknowledge back to ETR
+ if (register.isWantMapNotify()) {
+ NotifyBuilder notifyBuilder = new DefaultNotifyBuilder();
+ notifyBuilder.withKeyId(authConfig.lispAuthKeyId());
+ notifyBuilder.withAuthDataLength(valueOf(authConfig.lispAuthKeyId()).getHashLength());
+ notifyBuilder.withAuthKey(authConfig.lispAuthKey());
+ notifyBuilder.withNonce(register.getNonce());
+ notifyBuilder.withMapRecords(register.getMapRecords());
+
+ LispMapNotify notify = notifyBuilder.build();
+
+ InetSocketAddress address =
+ new InetSocketAddress(register.getSender().getAddress(), MAP_NOTIFY_PORT);
+ notify.configSender(address);
+
+ return notify;
+ }
+
+ return null;
+ }
+
+ /**
+ * Handles info-request message and replies with info-reply message.
+ *
+ * @param message info-request message
+ * @return info-reply message
+ */
+ public LispInfoReply processInfoRequest(LispMessage message) {
+ LispInfoRequest request = (LispInfoRequest) message;
+
+ if (!checkInfoRequestAuthData(request)) {
+ log.warn("Unmatched authentication data of Info-Request");
+ return null;
+ }
+
+ NatAddressBuilder natBuilder = new NatAddressBuilder();
+ try {
+ LispAfiAddress msAddress =
+ new LispIpv4Address(IpAddress.valueOf(InetAddress.getLocalHost()));
+ natBuilder.withMsRlocAddress(msAddress);
+ natBuilder.withMsUdpPortNumber((short) INFO_REPLY_PORT);
+
+ // try to extract global ETR RLOC address from info-request
+ IpAddress globalRlocIp = IpAddress.valueOf(request.getSender().getAddress());
+ LispAfiAddress globalRlocAddress;
+ if (globalRlocIp.isIp4()) {
+ globalRlocAddress = new LispIpv4Address(globalRlocIp);
+ } else {
+ globalRlocAddress = new LispIpv6Address(globalRlocIp);
+ }
+ natBuilder.withGlobalEtrRlocAddress(globalRlocAddress);
+ natBuilder.withEtrUdpPortNumber((short) request.getSender().getPort());
+ natBuilder.withPrivateEtrRlocAddress(new LispNoAddress());
+
+ // TODO: need to specify RTR addresses
+
+ } catch (UnknownHostException e) {
+ log.warn("Fails during formulate NAT address", e);
+ }
+
+ InfoReplyBuilder replyBuilder = new DefaultInfoReplyBuilder();
+ replyBuilder.withKeyId(request.getKeyId());
+ replyBuilder.withAuthDataLength(valueOf(authConfig.lispAuthKeyId()).getHashLength());
+ replyBuilder.withAuthKey(authConfig.lispAuthKey());
+ replyBuilder.withNonce(request.getNonce());
+ replyBuilder.withEidPrefix(request.getPrefix());
+ replyBuilder.withMaskLength(request.getMaskLength());
+ replyBuilder.withTtl(request.getTtl());
+ replyBuilder.withNatLcafAddress(natBuilder.build());
+ replyBuilder.withIsInfoReply(true);
+
+ LispInfoReply reply = replyBuilder.build();
+ reply.configSender(request.getSender());
+
+ return reply;
+ }
+
+ /**
+ * Checks the integrity of the received map-register message by calculating
+ * authentication data from received map-register message.
+ *
+ * @param register map-register message
+ * @return evaluation result
+ */
+ private boolean checkMapRegisterAuthData(LispMapRegister register) {
+ RegisterBuilder registerBuilder = new DefaultRegisterBuilder();
+ registerBuilder.withKeyId(register.getKeyId());
+ registerBuilder.withAuthKey(authConfig.lispAuthKey());
+ registerBuilder.withNonce(register.getNonce());
+ registerBuilder.withIsProxyMapReply(register.isProxyMapReply());
+ registerBuilder.withIsWantMapNotify(register.isWantMapNotify());
+ registerBuilder.withMapRecords(register.getMapRecords());
+
+ LispMapRegister authRegister = registerBuilder.build();
+
+ return Arrays.equals(authRegister.getAuthData(), register.getAuthData());
+ }
+
+ /**
+ * Checks the integrity of the received info-request message by calculating
+ * authentication data from received info-request message.
+ *
+ * @param request info-request message
+ * @return evaluation result
+ */
+ private boolean checkInfoRequestAuthData(LispInfoRequest request) {
+ InfoRequestBuilder requestBuilder = new DefaultInfoRequestBuilder();
+ requestBuilder.withKeyId(request.getKeyId());
+ requestBuilder.withAuthKey(authConfig.lispAuthKey());
+ requestBuilder.withNonce(request.getNonce());
+ requestBuilder.withTtl(request.getTtl());
+ requestBuilder.withEidPrefix(request.getPrefix());
+ requestBuilder.withIsInfoReply(request.isInfoReply());
+ requestBuilder.withMaskLength(request.getMaskLength());
+
+ LispInfoRequest authRequest = requestBuilder.build();
+
+ return Arrays.equals(authRequest.getAuthData(), request.getAuthData());
+ }
+
+ /**
+ * Prevents object instantiation from external.
+ */
+ private static final class SingletonHelper {
+ private static final String ILLEGAL_ACCESS_MSG = "Should not instantiate this class.";
+ private static final LispMapServer INSTANCE = new LispMapServer();
+
+ private SingletonHelper() {
+ throw new IllegalAccessError(ILLEGAL_ACCESS_MSG);
+ }
+ }
+}
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMappingDatabase.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMappingDatabase.java
new file mode 100644
index 0000000..f4f421b
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMappingDatabase.java
@@ -0,0 +1,169 @@
+/*
+ * 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.Lists;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.lisp.ctl.impl.map.ExpireMap;
+import org.onosproject.lisp.ctl.impl.map.ExpireHashMap;
+import org.onosproject.lisp.msg.protocols.LispEidRecord;
+import org.onosproject.lisp.msg.protocols.LispMapRecord;
+import org.onosproject.lisp.msg.types.LispAfiAddress;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * A singleton class that stores EID-RLOC mapping information.
+ */
+public final class LispMappingDatabase {
+
+ private static final long MINUTE_TO_MS_UNIT = 60 * 1000;
+
+ private ExpireMap<LispEidRecord, LispMapRecord> map = new ExpireHashMap<>();
+
+ /**
+ * Prevents object instantiation from external.
+ */
+ private LispMappingDatabase() {
+ }
+
+ /**
+ * Obtains a singleton instance.
+ *
+ * @return singleton instance
+ */
+ public static LispMappingDatabase getInstance() {
+ return SingletonHelper.INSTANCE;
+ }
+
+ /**
+ * Inserts a new EID-RLOC mapping record.
+ *
+ * @param eid endpoint identifier
+ * @param rloc route locator record
+ */
+ public void putMapRecord(LispEidRecord eid, LispMapRecord rloc) {
+ map.put(eid, rloc, rloc.getRecordTtl() * MINUTE_TO_MS_UNIT);
+ }
+
+ /**
+ * Returns the results whether a given EidRecord is contained in the map.
+ *
+ * @param eid endpoint identifier
+ * @return the results whether a given EidRecord is contained in the map
+ */
+ public boolean hasEidRecord(LispEidRecord eid) {
+ return map.containsKey(eid);
+ }
+
+ /**
+ * Removes an EID-RLOC mapping record with given endpoint identifier.
+ *
+ * @param eid endpoint identifier
+ */
+ public void removeMapRecordByEid(LispEidRecord eid) {
+ map.remove(eid);
+ }
+
+ /**
+ * Obtains an EID-RLOC mapping record with given EID record.
+ *
+ * @param eid endpoint identifier record
+ * @return an EID-RLOC mapping record
+ */
+ public LispMapRecord getMapRecordByEidRecord(LispEidRecord eid) {
+
+ for (LispEidRecord key : map.keySet()) {
+ if (isInRange(key, eid)) {
+ return map.get(key);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Obtains a collection of EID-RLOC mapping records with given EID records.
+ *
+ * @param eids endpoint identifier records
+ * @return a collection of EID-RLOC mapping records
+ */
+ public List<LispMapRecord> getMapRecordByEidRecords(List<LispEidRecord> eids) {
+ List<LispMapRecord> mapRecords = Lists.newArrayList();
+ eids.forEach(eidRecord -> {
+ LispMapRecord mapRecord = getMapRecordByEidRecord(eidRecord);
+ if (mapRecord != null) {
+ mapRecords.add(mapRecord);
+ }
+ });
+ return ImmutableList.copyOf(mapRecords);
+ }
+
+ /**
+ * Obtains an EID-RLOC mapping record with given EID address.
+ *
+ * @param address endpoint identifier address
+ * @return an EID-RLOC mapping record
+ */
+ public LispMapRecord getMapRecordByEidAddress(LispAfiAddress address) {
+ Optional<LispEidRecord> eidRecord =
+ map.keySet().stream().filter(k -> k.getPrefix().equals(address)).findFirst();
+ return eidRecord.map(lispEidRecord -> map.get(lispEidRecord)).orElse(null);
+ }
+
+ /**
+ * Generates CIDR style string from EID record.
+ *
+ * @param eidRecord EID record
+ * @return CIDR style string
+ */
+ private String cidrfy(LispEidRecord eidRecord) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(eidRecord.getPrefix().toString());
+ sb.append("/");
+ sb.append(eidRecord.getMaskLength());
+ return sb.toString();
+ }
+
+ /**
+ * Checks whether the EID record is included in the given EID record.
+ *
+ * @param origin the EID record to be compared
+ * @param compare the EID record to compare
+ * @return boolean result
+ */
+ private boolean isInRange(LispEidRecord origin, LispEidRecord compare) {
+
+ IpPrefix originIpPrefix = IpPrefix.valueOf(cidrfy(origin));
+ IpPrefix compareIpPrefix = IpPrefix.valueOf(cidrfy(compare));
+
+ return originIpPrefix.contains(compareIpPrefix);
+ }
+
+ /**
+ * Prevents object instantiation from external.
+ */
+ private static final class SingletonHelper {
+ private static final String ILLEGAL_ACCESS_MSG = "Should not instantiate this class.";
+ private static final LispMappingDatabase INSTANCE = new LispMappingDatabase();
+
+ private SingletonHelper() {
+ throw new IllegalAccessError(ILLEGAL_ACCESS_MSG);
+ }
+ }
+}
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMessageDecoder.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMessageDecoder.java
new file mode 100644
index 0000000..1c5e994
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMessageDecoder.java
@@ -0,0 +1,42 @@
+/*
+ * 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 io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.socket.DatagramPacket;
+import io.netty.handler.codec.MessageToMessageDecoder;
+import org.onosproject.lisp.msg.protocols.LispMessage;
+import org.onosproject.lisp.msg.protocols.LispMessageReader;
+import org.onosproject.lisp.msg.protocols.LispMessageReaderFactory;
+
+import java.util.List;
+
+/**
+ * Decode a LISP message from a ByteBuffer, for use in a netty pipeline.
+ */
+public class LispMessageDecoder extends MessageToMessageDecoder<DatagramPacket> {
+
+ @Override
+ protected void decode(ChannelHandlerContext ctx, DatagramPacket msg,
+ List<Object> list) throws Exception {
+ ByteBuf byteBuf = msg.content();
+ LispMessageReader reader = LispMessageReaderFactory.getReader(byteBuf);
+ LispMessage message = (LispMessage) reader.readFrom(byteBuf);
+ message.configSender(msg.sender());
+ list.add(message);
+ }
+}
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMessageEncoder.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMessageEncoder.java
new file mode 100644
index 0000000..3e37fd6
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispMessageEncoder.java
@@ -0,0 +1,53 @@
+/*
+ * 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 io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.socket.DatagramPacket;
+import io.netty.handler.codec.MessageToMessageEncoder;
+import org.onosproject.lisp.msg.protocols.LispMessage;
+
+import java.util.List;
+
+/**
+ * Encode a LISP message for output into a ByteBuffer,
+ * for use in a netty pipeline.
+ */
+public class LispMessageEncoder extends MessageToMessageEncoder {
+
+ @Override
+ protected void encode(ChannelHandlerContext ctx, Object msg, List out) throws Exception {
+ if (!(msg instanceof List)) {
+ ByteBuf byteBuf = Unpooled.buffer();
+ ((LispMessage) msg).writeTo(byteBuf);
+ out.add(new DatagramPacket(byteBuf, ((LispMessage) msg).getSender()));
+ return;
+ }
+
+ List<LispMessage> msgList = (List<LispMessage>) msg;
+
+ for (LispMessage message : msgList) {
+ if (message != null) {
+ ByteBuf byteBuf = Unpooled.buffer();
+ message.writeTo(byteBuf);
+ out.add(new DatagramPacket(byteBuf, ((LispMessage) msg).getSender()));
+ }
+ }
+ }
+}
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/map/ExpireHashMap.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/map/ExpireHashMap.java
new file mode 100644
index 0000000..08f7c88
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/map/ExpireHashMap.java
@@ -0,0 +1,183 @@
+/*
+ * 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.map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Default implementation of ExpireMap.
+ */
+public class ExpireHashMap<K, V> implements ExpireMap<K, V> {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private static final long DEFAULT_TTL = 60000L;
+ private final ConcurrentMap<K, ExpiredObject<K, V>> map = new ConcurrentHashMap<>();
+ private final Lock writeLock = new ReentrantLock();
+ private final Timer timer = new Timer("ExpireMapTimer", true);
+
+ /**
+ * An expired object that associates with a TimerTask instance.
+ *
+ * @param <K1> key type K1
+ * @param <V1> value type V1
+ */
+ class ExpiredObject<K1, V1> {
+ private final V1 value;
+ private final ExpiryTask<K1> task;
+ private final long ttl;
+
+ public ExpiredObject(K1 key, V1 value) {
+ this(key, value, DEFAULT_TTL);
+ }
+
+ ExpiredObject(K1 key, V1 value, long ttl) {
+ this.value = value;
+ this.task = new ExpiryTask<>(key);
+ this.ttl = ttl;
+ timer.schedule(this.task, ttl);
+ }
+
+ ExpiryTask<K1> getTask() {
+ return task;
+ }
+
+ V1 getValue() {
+ return value;
+ }
+
+ long getTtl() {
+ return ttl;
+ }
+ }
+
+ /**
+ * A TimerTask that removes its associated map entry from the internal map.
+ *
+ * @param <K2> object key
+ */
+ class ExpiryTask<K2> extends TimerTask {
+ private final K2 key;
+
+ ExpiryTask(K2 key) {
+ this.key = key;
+ }
+
+ K2 getKey() {
+ return key;
+ }
+
+ @Override
+ public void run() {
+ log.info("Removing element with key [{}]", key);
+ try {
+ writeLock.lock();
+ if (map.containsKey(key)) {
+ map.remove(getKey());
+ }
+ } finally {
+ writeLock.unlock();
+ }
+ }
+ }
+
+ @Override
+ public void put(K key, V value, long expireMs) {
+ try {
+ writeLock.lock();
+
+ // if we have a value which is previously associated with the given
+ // key, we simply replace it with new value, and invalidate the
+ // previously associated value
+ final ExpiredObject<K, V> object =
+ map.putIfAbsent(key, new ExpiredObject<>(key, value, expireMs));
+
+ if (object != null) {
+ object.getTask().cancel();
+ }
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ @Override
+ public void put(K key, V value) {
+ put(key, value, DEFAULT_TTL);
+ }
+
+ @Override
+ public V get(K key) {
+ return map.containsKey(key) ? map.get(key).getValue() : null;
+ }
+
+ @Override
+ public void clear() {
+ try {
+ writeLock.lock();
+ for (ExpiredObject<K, V> object : map.values()) {
+ object.getTask().cancel();
+ }
+ map.clear();
+ timer.purge();
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ @Override
+ public boolean containsKey(K key) {
+ return map.containsKey(key);
+ }
+
+ @Override
+ public Set<K> keySet() {
+ return map.keySet();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ @Override
+ public V remove(K key) {
+ final ExpiredObject<K, V> object;
+ try {
+ writeLock.lock();
+ object = map.remove(key);
+ if (object != null) {
+ object.getTask().cancel();
+ }
+ } finally {
+ writeLock.unlock();
+ }
+ return (object == null ? null : object.getValue());
+ }
+
+ @Override
+ public int size() {
+ return map.size();
+ }
+}
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/map/ExpireMap.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/map/ExpireMap.java
new file mode 100644
index 0000000..7bb8fcd
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/map/ExpireMap.java
@@ -0,0 +1,161 @@
+/*
+ * 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.map;
+
+import java.util.Set;
+
+/**
+ * A {@link java.util.concurrent.ConcurrentMap} that supports timed entry
+ * eviction.
+ */
+public interface ExpireMap<K, V> {
+
+ /**
+ * Associates the specified value with the specified key in this map for the
+ * specified duration (optional operation). If the map previously contained
+ * a mapping for the key, the old value is replaced by the specified value.
+ *
+ * @param key key with which the specified value is to be associated
+ * @param value value to be associated with the specified key
+ * @param expireMs the maximum amount of time in ms during which the map
+ * entry should remain in the map, this can also be
+ * considered as (time-to-live: TTL) value. Note that when
+ * we assign a value of 0, the map entry will be immediately
+ * remove from the map.
+ *
+ * @throws UnsupportedOperationException if the <tt>put</tt> operation
+ * is not supported by this map
+ * @throws ClassCastException if the class of the specified key or value
+ * prevents it from being stored in this map
+ * @throws NullPointerException if the specified key or value is null
+ * and this map does not permit null keys or values
+ * @throws IllegalArgumentException if some property of the specified key
+ * or value prevents it from being stored in this map
+ */
+ void put(K key, V value, long expireMs);
+
+ /**
+ * Associates the specified value with the specified key in this map for the
+ * specified duration (optional operation). If the map previously contained
+ * a mapping for the key, the old value is replaced by the specified value.
+ * With this method, we can specify the expireMs with default value.
+ *
+ * @param key key with which the specified value is to be associated
+ * @param value value to be associated with the specified key
+ *
+ * @throws UnsupportedOperationException if the <tt>put</tt> operation
+ * is not supported by this map
+ * @throws ClassCastException if the class of the specified key or value
+ * prevents it from being stored in this map
+ * @throws NullPointerException if the specified key or value is null
+ * and this map does not permit null keys or values
+ * @throws IllegalArgumentException if some property of the specified key
+ * or value prevents it from being stored in this map
+ */
+ void put(K key, V value);
+
+ /**
+ * Returns the value to which the specified key is mapped,
+ * or {@code null} if this map contains no mapping for the key.
+ *
+ * @param key the key whose associated value is to be returned
+ * @return the value to which the specified key is mapped, or
+ * {@code null} if this map contains no mapping for the key
+ * @throws ClassCastException if the key is of an inappropriate type for
+ * this map
+ * @throws NullPointerException if the specified key is null and this map
+ * does not permit null keys
+ */
+ V get(K key);
+
+ /**
+ * Removes all of the mappings from this map (optional operation).
+ * The map will be empty after this call returns.
+ *
+ * @throws UnsupportedOperationException if the <tt>clear</tt> operation
+ * is not supported by this map
+ */
+ void clear();
+
+ /**
+ * Returns <tt>true</tt> if this map contains a mapping for the specified
+ * key. More formally, returns <tt>true</tt> if and only if
+ * this map contains a mapping for a key <tt>k</tt> such that
+ * <tt>(key==null ? k==null : key.equals(k))</tt>. (There can be
+ * at most one such mapping.)
+ *
+ * @param key key whose presence in this map is to be tested
+ * @return <tt>true</tt> if this map contains a mapping for the specified
+ * key
+ * @throws ClassCastException if the key is of an inappropriate type for
+ * this map
+ * @throws NullPointerException if the specified key is null and this map
+ * does not permit null keys
+ */
+ boolean containsKey(K key);
+
+ /**
+ * Returns a {@link Set} view of the keys contained in this map.
+ * The set is backed by the map, so changes to the map are
+ * reflected in the set, and vice-versa. If the map is modified
+ * while an iteration over the set is in progress (except through
+ * the iterator's own <tt>remove</tt> operation), the results of
+ * the iteration are undefined. The set supports element removal,
+ * which removes the corresponding mapping from the map, via the
+ * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+ * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
+ * operations. It does not support the <tt>add</tt> or <tt>addAll</tt>
+ * operations.
+ *
+ * @return a set view of the keys contained in this map
+ */
+ Set<K> keySet();
+
+ /**
+ * Returns <tt>true</tt> if this map contains no key-value mappings.
+ *
+ * @return <tt>true</tt> if this map contains no key-value mappings
+ */
+ boolean isEmpty();
+
+ /**
+ * Removes the mapping for a key from this map if it is present
+ * (optional operation). More formally, if this map contains a mapping
+ * from key <tt>k</tt> to value <tt>v</tt> such that
+ * <code>(key==null ? k==null : key.equals(k))</code>, that mapping
+ * is removed. (The map can contain at most one such mapping.)
+ *
+ * @param key key whose mapping is to be removed from the map
+ * @return the previous value associated with <tt>key</tt>, or
+ * <tt>null</tt> if there was no mapping for <tt>key</tt>.
+ * @throws UnsupportedOperationException if the <tt>remove</tt> operation
+ * is not supported by this map
+ * @throws ClassCastException if the key is of an inappropriate type for
+ * this map
+ * @throws NullPointerException if the specified key is null and this
+ * map does not permit null keys
+ */
+ V remove(K key);
+
+ /**
+ * Returns the number of key-value mappings in this map. If the
+ * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
+ * <tt>Integer.MAX_VALUE</tt>.
+ *
+ * @return the number of key-value mappings in this map
+ */
+ int size();
+}
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/map/package-info.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/map/package-info.java
new file mode 100644
index 0000000..f37bfe1
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/map/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * A package that contains ExpireMap interface and implementation classes.
+ */
+package org.onosproject.lisp.ctl.impl.map;
\ No newline at end of file
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/package-info.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/package-info.java
new file mode 100644
index 0000000..1ecccac
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * LISP controller implementations.
+ */
+package org.onosproject.lisp.ctl.impl;