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;