ONOS-2740,ONOS-2741,from ONOS-3032 - to ONOS 3071 , OSPF Protocol Implementation

Change-Id: I8955ca10bf966c7b3917a3f3a41037abce87f1c5
diff --git a/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/impl/OspfInterfaceChannelHandler.java b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/impl/OspfInterfaceChannelHandler.java
new file mode 100755
index 0000000..aac1322
--- /dev/null
+++ b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/impl/OspfInterfaceChannelHandler.java
@@ -0,0 +1,1400 @@
+/*
+ * Copyright 2016 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.ospf.controller.impl;
+
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelFuture;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelStateEvent;
+import org.jboss.netty.channel.ExceptionEvent;
+import org.jboss.netty.channel.MessageEvent;
+import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
+import org.jboss.netty.handler.timeout.ReadTimeoutException;
+import org.onlab.packet.Ip4Address;
+import org.onosproject.ospf.controller.LsaWrapper;
+import org.onosproject.ospf.controller.OspfArea;
+import org.onosproject.ospf.controller.OspfInterface;
+import org.onosproject.ospf.controller.OspfLinkTed;
+import org.onosproject.ospf.controller.OspfLsa;
+import org.onosproject.ospf.controller.OspfNbr;
+import org.onosproject.ospf.controller.OspfNeighborState;
+import org.onosproject.ospf.controller.OspfRouter;
+import org.onosproject.ospf.controller.TopologyForDeviceAndLink;
+import org.onosproject.ospf.controller.area.OspfAreaImpl;
+import org.onosproject.ospf.controller.area.OspfInterfaceImpl;
+import org.onosproject.ospf.controller.lsdb.LsaWrapperImpl;
+import org.onosproject.ospf.controller.lsdb.OspfLsdbImpl;
+import org.onosproject.ospf.controller.util.OspfEligibleRouter;
+import org.onosproject.ospf.controller.util.OspfInterfaceType;
+import org.onosproject.ospf.exceptions.OspfParseException;
+import org.onosproject.ospf.protocol.lsa.LsaHeader;
+import org.onosproject.ospf.protocol.ospfpacket.OspfMessage;
+import org.onosproject.ospf.protocol.ospfpacket.OspfPacketHeader;
+import org.onosproject.ospf.protocol.ospfpacket.subtype.LsRequestPacket;
+import org.onosproject.ospf.protocol.ospfpacket.types.DdPacket;
+import org.onosproject.ospf.protocol.ospfpacket.types.HelloPacket;
+import org.onosproject.ospf.protocol.ospfpacket.types.LsAcknowledge;
+import org.onosproject.ospf.protocol.ospfpacket.types.LsRequest;
+import org.onosproject.ospf.protocol.ospfpacket.types.LsUpdate;
+import org.onosproject.ospf.protocol.util.ChecksumCalculator;
+import org.onosproject.ospf.protocol.util.OspfInterfaceState;
+import org.onosproject.ospf.protocol.util.OspfPacketType;
+import org.onosproject.ospf.protocol.util.OspfParameters;
+import org.onosproject.ospf.protocol.util.OspfUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.channels.ClosedChannelException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Channel handler deals with the OSPF channel connection.
+ * Also it dispatches messages to the appropriate handlers.
+ */
+public class OspfInterfaceChannelHandler extends IdleStateAwareChannelHandler {
+
+    private static final Logger log =
+            LoggerFactory.getLogger(OspfInterfaceChannelHandler.class);
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private OspfInterface ospfInterface;
+    private OspfArea ospfArea;
+    private boolean isClosed = false;
+    private Controller controller;
+    private Channel channel;
+    private long delay = 0;
+    private InternalHelloTimer helloTimerTask;
+    private InternalWaitTimer waitTimerTask;
+    private InternalDelayedAckTimer delayedAckTimerTask;
+    private ScheduledExecutorService exServiceHello;
+    private ScheduledExecutorService exServiceWait;
+    private ScheduledExecutorService exServiceDelayedAck;
+    private boolean isDelayedAckTimerScheduled = false;
+    private int delayedAckTimerInterval = 2500;
+    private TopologyForDeviceAndLink topologyForDeviceAndLink;
+
+    public OspfInterfaceChannelHandler() {
+
+    }
+
+    /**
+     * Creates an instance of OSPF channel handler.
+     *
+     * @param controller    controller instance
+     * @param ospfArea      ospf area instance
+     * @param ospfInterface ospf interface instance
+     */
+    public OspfInterfaceChannelHandler(Controller controller, OspfArea ospfArea, OspfInterface ospfInterface) {
+
+        this.ospfArea = ospfArea;
+        this.ospfInterface = ospfInterface;
+        this.controller = controller;
+        ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DOWN);
+        this.ospfInterface.setDr(Ip4Address.valueOf("0.0.0.0"));
+        this.ospfInterface.setBdr(Ip4Address.valueOf("0.0.0.0"));
+        this.topologyForDeviceAndLink = new TopologyForDeviceAndLinkImpl();
+    }
+
+    /**
+     * Represents an interface is up and connected.
+     *
+     * @throws Exception might throws exception
+     */
+    public void interfaceUp() throws Exception {
+        log.debug("OSPFInterfaceChannelHandler::interfaceUp...!!!");
+        if (ospfInterface.interfaceType() == OspfInterfaceType.POINT_TO_POINT.value()) {
+            ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.POINT2POINT);
+            log.debug("OSPFInterfaceChannelHandler::InterfaceType {} state {} ",
+                      ospfInterface.interfaceType(), ((OspfInterfaceImpl) ospfInterface).state());
+        } else if (ospfInterface.interfaceType() == OspfInterfaceType.BROADCAST.value()) {
+            //if router priority is 0, move the state to DROther
+            if (ospfInterface.routerPriority() == 0) {
+                ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DROTHER);
+            } else {
+                log.debug("OSPFInterfaceChannelHandler::InterfaceType {} state {} RouterPriority {}",
+                          ospfInterface.interfaceType(),
+                          ((OspfInterfaceImpl) ospfInterface).state(), ospfInterface.routerPriority());
+                ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.WAITING);
+                //start wait timer - like inactivity timer with router deadInterval
+                startWaitTimer();
+            }
+
+        }
+        // Start hello timer with interval from config - convert seconds to milliseconds
+        startHelloTimer(ospfInterface.helloIntervalTime());
+        ospfArea.refreshArea(ospfInterface);
+    }
+
+
+    /**
+     * Gets called when a BDR was detected before the wait timer expired.
+     *
+     * @param ch channel instance
+     * @throws Exception might throws exception
+     */
+    public void backupSeen(Channel ch) throws Exception {
+        log.debug("OSPFInterfaceChannelHandler::backupSeen ");
+        if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.WAITING) {
+            electRouter(ch);
+        }
+    }
+
+    /**
+     * Gets called when no hello message received for particular period.
+     *
+     * @param ch channel instance
+     * @throws Exception might throws exception
+     */
+    public void waitTimer(Channel ch) throws Exception {
+        log.debug("OSPFInterfaceChannelHandler::waitTimer ");
+        //section 9.4
+        if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.WAITING) {
+            electRouter(ch);
+        }
+    }
+
+    /**
+     * Neighbor change event is triggered when the router priority gets changed.
+     *
+     * @throws Exception might throws exception
+     */
+    public void neighborChange() throws Exception {
+        log.debug("OSPFInterfaceChannelHandler::neighborChange ");
+        if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR ||
+                ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR ||
+                ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER) {
+            electRouter(channel);
+        }
+    }
+
+    /**
+     * Gets called when an interface is down.
+     * All interface variables are reset, and interface timers disabled.
+     * Also all neighbor connections associated with the interface are destroyed.
+     */
+    public void interfaceDown() {
+        log.debug("OSPFInterfaceChannelHandler::interfaceDown ");
+        stopHelloTimer();
+        ospfInterface.listOfNeighbors().clear();
+        ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DOWN);
+    }
+
+    @Override
+    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent evt) throws Exception {
+        log.info("OSPF channelConnected from {}", evt.getChannel().getRemoteAddress());
+        channel = evt.getChannel();
+        interfaceUp();
+        startDelayedAckTimer();
+    }
+
+    @Override
+    public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent evt) {
+        interfaceDown();
+        stopDelayedAckTimer();
+        log.debug("OspfChannelHandler::channelDisconnected...!!!");
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
+        log.info("[exceptionCaught]: " + e.toString());
+        if (e.getCause() instanceof ReadTimeoutException) {
+            // device timeout
+            log.error("Disconnecting device {} due to read timeout", e.getChannel().getRemoteAddress());
+            return;
+        } else if (e.getCause() instanceof ClosedChannelException) {
+            log.debug("Channel for OSPF {} already closed", e.getChannel().getRemoteAddress());
+        } else if (e.getCause() instanceof IOException) {
+            log.error("Disconnecting OSPF {} due to IO Error: {}", e.getChannel().getRemoteAddress(),
+                      e.getCause().getMessage());
+            if (log.isDebugEnabled()) {
+                log.debug("StackTrace for previous Exception: {}", e.getCause());
+            }
+        } else if (e.getCause() instanceof OspfParseException) {
+            OspfParseException errMsg = (OspfParseException) e.getCause();
+            byte errorCode = errMsg.errorCode();
+            byte errorSubCode = errMsg.errorSubCode();
+            log.error("Error while parsing message from OSPF {}, ErrorCode {}",
+                      e.getChannel().getRemoteAddress(), errorCode);
+        } else if (e.getCause() instanceof RejectedExecutionException) {
+            log.warn("Could not process message: queue full");
+        } else {
+            log.error("Error while processing message from OSPF {}, state {}",
+                      e.getChannel().getRemoteAddress(), ((OspfInterfaceImpl) ospfInterface).state());
+        }
+    }
+
+    @Override
+    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+        log.debug("OspfChannelHandler::messageReceived...!!!");
+        Object message = e.getMessage();
+        if (message instanceof List) {
+            List<OspfMessage> ospfMessageList = (List<OspfMessage>) message;
+            log.debug("OspfChannelHandler::List of OspfMessages Size {}", ospfMessageList.size());
+            if (ospfMessageList != null) {
+                for (OspfMessage ospfMessage : ospfMessageList) {
+                    processOSPFMessage(ospfMessage, ctx);
+                }
+            } else {
+                log.debug("OspfChannelHandler::OspfMessages Null List...!!");
+            }
+        }
+        if (message instanceof OspfMessage) {
+            OspfMessage ospfMessage = (OspfMessage) message;
+            log.debug("OspfChannelHandler::OspfMessages received...!!");
+            processOSPFMessage(ospfMessage, ctx);
+        }
+    }
+
+    /**
+     * When an OSPF message received it is handed over to this method.
+     * Based on the type of the OSPF message received it will be handed over
+     * to corresponding message handler methods.
+     *
+     * @param ospfMessage received OSPF message
+     * @param ctx         channel handler context instance.
+     * @throws Exception might throws exception
+     */
+    public void processOSPFMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception {
+        log.debug("OspfChannelHandler::processOSPFMessage...!!!");
+
+        if (!validateMessage(ospfMessage)) {
+            return;
+        }
+
+        switch (ospfMessage.ospfMessageType().value()) {
+            case OspfParameters.HELLO:
+                processHelloMessage(ospfMessage, ctx);
+                break;
+            case OspfParameters.DD:
+                processDdMessage(ospfMessage, ctx);
+                break;
+            case OspfParameters.LSREQUEST:
+                processLsRequestMessage(ospfMessage, ctx);
+                break;
+            case OspfParameters.LSUPDATE:
+                processLsUpdateMessage(ospfMessage, ctx);
+                break;
+            case OspfParameters.LSACK:
+                processLsAckMessage(ospfMessage, ctx);
+                break;
+            default:
+                log.debug("Unknown packet to process...!!!");
+                break;
+        }
+    }
+
+    /**
+     * Validates the OSPF message received.
+     *
+     * @param ospfMessage OSPF message.
+     * @return true if it is a valid else false.
+     * @throws Exception might throws exception
+     */
+    private boolean validateMessage(OspfMessage ospfMessage) throws Exception {
+        boolean isValid = true;
+        OspfPacketHeader header = (OspfPacketHeader) ospfMessage;
+
+        //added the check to eliminate self origin packets also two interfaces on same router.
+        if (!header.sourceIp().equals(ospfInterface.ipAddress()) && !header.routerId().equals(
+                ospfArea.routerId())) {
+            //Verify the checksum
+            ChecksumCalculator checksum = new ChecksumCalculator();
+            if (!checksum.isValidOspfCheckSum(ospfMessage, OspfUtil.OSPFPACKET_CHECKSUM_POS1,
+                                              OspfUtil.OSPFPACKET_CHECKSUM_POS2)) {
+                log.debug("Checksum mismatch. Received packet type {} ", ospfMessage.ospfMessageType());
+                return false;
+            }
+            if (((OspfPacketHeader) ospfMessage).ospfVersion() != OspfUtil.OSPF_VERSION_2) {
+                log.debug("Received osfpMessage Version should match with Interface Version ");
+                return false;
+            }
+            if (!((OspfPacketHeader) ospfMessage).areaId().equals(ospfArea.areaId())) {
+                log.debug("Received ospf packets are from different area than our Area ID. " +
+                                  "Received Area ID {}, Our AreaId {} ",
+                          ((OspfPacketHeader) ospfMessage).areaId(), ospfArea.areaId());
+                return false;
+            }
+
+            //According to RFC-2328 (8.2)
+            /**
+             * ABR should receive packets from backbone 0.0.0.0 as we are not acting as ABR
+             * we are rejecting the packet.
+             */
+            if (((OspfPacketHeader) ospfMessage).areaId().equals(Ip4Address.valueOf("0.0.0.0"))) {
+                log.debug("ABR should receive packets from backbone 0.0.0.0 as we are not acting as " +
+                                  "ABR we are rejecting the ospf packet");
+                return false;
+            }
+            if (ospfInterface.interfaceType() == OspfInterfaceType.BROADCAST.value() &&
+                    !OspfUtil.sameNetwork(((OspfPacketHeader) ospfMessage).sourceIp(),
+                                          ospfInterface.ipAddress(), ospfInterface.ipNetworkMask())) {
+                log.debug("Received packets from different subnets. Discarding...!!!");
+                return false;
+            }
+        } else {
+            isValid = false;
+        }
+
+        return isValid;
+    }
+
+    /**
+     * Processes Hello message.
+     *
+     * @param ospfMessage OSPF message instance.
+     * @param ctx         context instance.
+     * @throws Exception might throws exception
+     */
+    void processHelloMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception {
+        log.debug("OspfChannelHandler::processHelloMessage...!!!");
+        HelloPacket helloPacket = (HelloPacket) ospfMessage;
+
+        // processing of hello packet as per RFC 2328 section 10.5
+        log.debug("OspfChannelHandler::processHelloMessage::Interface Type {} OSPFInterfaceState {} ",
+                  ospfInterface.interfaceType(), ((OspfInterfaceImpl) ospfInterface).state());
+
+        if (ospfInterface.interfaceType() != OspfInterfaceType.POINT_TO_POINT.value()) {
+            if (!helloPacket.networkMask().equals(ospfInterface.ipNetworkMask())) {
+                log.debug("OspfChannelHandler::processHelloMessage::Hello Packet Received does not " +
+                                  "match the same network mask as the configure Interface");
+                return;
+            }
+        }
+        if (helloPacket.helloInterval() != ospfInterface.helloIntervalTime()) {
+            log.debug("OspfChannelHandler::processHelloMessage::Hello Packet Received have the same " +
+                              "hello interval as configured Interface");
+            return;
+        }
+        if (helloPacket.routerDeadInterval() != ospfInterface.routerDeadIntervalTime()) {
+            log.debug("OspfChannelHandler::processHelloMessage::Hello Packet Received have the same " +
+                              "Router Dead interval as configured Interface");
+            return;
+        }
+
+        if (ospfInterface.interfaceType() == OspfInterfaceType.POINT_TO_POINT.value()) {
+            // to verify if the neighbor which sent the hello is present in the OSPF Interface neighboring list .
+            OspfNbr nbr;
+            if (!ospfInterface.isNeighborInList(helloPacket.routerId().toString())) {
+                nbr = new OspfNbrImpl(ospfArea, ospfInterface, helloPacket.sourceIp(),
+                                      helloPacket.routerId(), helloPacket.options(), this, topologyForDeviceAndLink);
+                ospfInterface.addNeighbouringRouter(nbr);
+            } else {
+                nbr = ospfInterface.neighbouringRouter(helloPacket.routerId().toString());
+                nbr.setRouterPriority(helloPacket.routerPriority());
+            }
+            if (!helloPacket.containsNeighbour(ospfArea.routerId())) {
+                ((OspfNbrImpl) nbr).oneWayReceived(helloPacket, channel);
+            } else {
+                ((OspfNbrImpl) nbr).twoWayReceived(helloPacket, ctx.getChannel());
+            }
+        } else if (ospfInterface.interfaceType() == OspfInterfaceType.BROADCAST.value()) {
+
+            if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.WAITING) {
+                if ((!helloPacket.dr().equals(Ip4Address.valueOf("0.0.0.0"))) &&
+                        (!helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0")))) {
+                    stopWaitTimer();
+                    ospfInterface.setDr(helloPacket.dr());
+                    ospfInterface.setBdr(helloPacket.bdr());
+                    if (helloPacket.dr().equals(ospfInterface.ipAddress())) {
+                        ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DR);
+                        //refresh router Lsa
+                        ospfArea.refreshArea(ospfInterface);
+                    } else if (helloPacket.bdr().equals(ospfInterface.ipAddress())) {
+                        ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.BDR);
+                        //refresh router Lsa
+                        ospfArea.refreshArea(ospfInterface);
+                    } else {
+                        ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DROTHER);
+                        ospfArea.refreshArea(ospfInterface);
+                    }
+
+                } else if (!helloPacket.dr().equals(Ip4Address.valueOf("0.0.0.0")) ||
+                        !helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0"))) {
+                    ospfInterface.setDr(helloPacket.dr());
+                    ospfInterface.setBdr(helloPacket.bdr());
+                }
+                Ip4Address sourceIp = helloPacket.sourceIp();
+                OspfNbr nbr;
+                if (!ospfInterface.isNeighborInList(helloPacket.routerId().toString())) {
+                    nbr = new OspfNbrImpl(ospfArea, ospfInterface, sourceIp, helloPacket.routerId(),
+                                          helloPacket.options(), this, topologyForDeviceAndLink);
+                    nbr.setNeighborId(helloPacket.routerId());
+                    nbr.setNeighborBdr(helloPacket.bdr());
+                    nbr.setNeighborDr(helloPacket.dr());
+                    nbr.setRouterPriority(helloPacket.routerPriority());
+                    ospfInterface.addNeighbouringRouter(nbr);
+                } else {
+                    nbr = ospfInterface.neighbouringRouter(helloPacket.routerId().toString());
+                    nbr.setRouterPriority(helloPacket.routerPriority());
+                }
+                if (!helloPacket.containsNeighbour(ospfArea.routerId())) {
+                    ((OspfNbrImpl) nbr).oneWayReceived(helloPacket, channel);
+                } else {
+                    ((OspfNbrImpl) nbr).twoWayReceived(helloPacket, ctx.getChannel());
+                }
+
+                if (helloPacket.dr().equals(sourceIp)) {
+                    if (helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0"))) {
+                        // call backup seen
+                        stopWaitTimer();
+                        backupSeen(ctx.getChannel());
+                    }
+                }
+
+                if (helloPacket.bdr().equals(sourceIp)) {
+                    // call backup seen
+                    stopWaitTimer();
+                    backupSeen(ctx.getChannel());
+                }
+            } else {
+
+                if ((!helloPacket.dr().equals(Ip4Address.valueOf("0.0.0.0")) ||
+                        !helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0")))
+                        && ospfInterface.routerPriority() == 0) {
+                    ospfInterface.setDr(helloPacket.dr());
+                    ospfInterface.setBdr(helloPacket.bdr());
+                }
+                //To verify if the neighbor which sent the hello is present in the OSPF Interface neighboring list .
+                Ip4Address sourceIp = helloPacket.sourceIp();
+                OspfNbr nbr;
+                if (!ospfInterface.isNeighborInList(helloPacket.routerId().toString())) {
+                    nbr = new OspfNbrImpl(ospfArea, ospfInterface, sourceIp, helloPacket.routerId(),
+                                          helloPacket.options(), this, topologyForDeviceAndLink);
+                    nbr.setNeighborId(helloPacket.routerId());
+                    nbr.setNeighborBdr(helloPacket.bdr());
+                    nbr.setNeighborDr(helloPacket.dr());
+                    nbr.setRouterPriority(helloPacket.routerPriority());
+                    ospfInterface.addNeighbouringRouter(nbr);
+                    ((OspfNbrImpl) nbr).oneWayReceived(helloPacket, channel);
+                } else {
+                    log.debug("OspfChannelHandler::NeighborInList::helloPacket.bdr(): {}, " +
+                                      "helloPacket.dr(): {}", helloPacket.bdr(), helloPacket.dr());
+                    nbr = ospfInterface.neighbouringRouter(helloPacket.routerId().toString());
+                    nbr.setRouterPriority(helloPacket.routerPriority());
+                    if (!helloPacket.containsNeighbour(ospfArea.routerId())) {
+                        ((OspfNbrImpl) nbr).oneWayReceived(helloPacket, channel);
+                    } else {
+                        ((OspfNbrImpl) nbr).twoWayReceived(helloPacket, ctx.getChannel());
+                    }
+                    if (nbr.routerPriority() != helloPacket.routerPriority()) {
+                        nbr.setNeighborBdr(helloPacket.bdr());
+                        nbr.setNeighborDr(helloPacket.dr());
+                        neighborChange();
+                    }
+
+
+                    if (nbr.neighborIpAddr().equals(helloPacket.dr()) &&
+                            !(nbr.neighborIpAddr().equals(nbr.neighborDr()))) {
+                        nbr.setNeighborBdr(helloPacket.bdr());
+                        nbr.setNeighborDr(helloPacket.dr());
+                        neighborChange();
+                    }
+
+                    if (!(nbr.neighborIpAddr().equals(helloPacket.dr())) &&
+                            (nbr.neighborIpAddr().equals(nbr.neighborDr()))) {
+                        nbr.setNeighborBdr(helloPacket.bdr());
+                        nbr.setNeighborDr(helloPacket.dr());
+                        neighborChange();
+                    }
+
+                    if (nbr.neighborIpAddr().equals(helloPacket.bdr()) &&
+                            !(nbr.neighborIpAddr().equals(nbr.neighborBdr()))) {
+                        nbr.setNeighborBdr(helloPacket.bdr());
+                        nbr.setNeighborDr(helloPacket.dr());
+                        neighborChange();
+                    }
+
+                    if (!(nbr.neighborIpAddr().equals(helloPacket.bdr())) &&
+                            (nbr.neighborIpAddr().equals(nbr.neighborBdr()))) {
+                        nbr.setNeighborBdr(helloPacket.bdr());
+                        nbr.setNeighborDr(helloPacket.dr());
+                        neighborChange();
+                    }
+
+                    nbr.setNeighborBdr(helloPacket.bdr());
+                    nbr.setNeighborDr(helloPacket.dr());
+                }
+
+            }
+        }
+    }
+
+    /**
+     * process the DD message which received.
+     *
+     * @param ospfMessage OSPF message instance.
+     * @param ctx         channel handler context instance
+     * @throws Exception might throws exception
+     */
+    void processDdMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception {
+        log.debug("OspfChannelHandler::processDdMessage...!!!");
+
+        DdPacket ddPacket = (DdPacket) ospfMessage;
+        log.debug("Got DD packet from {}", ddPacket.sourceIp());
+        //check it is present in listOfNeighbors
+        Ip4Address neighbourId = ddPacket.routerId();
+        OspfNbr nbr = ospfInterface.neighbouringRouter(neighbourId.toString());
+
+        if (nbr != null) {
+            log.debug("OspfChannelHandler::processDdMessage:: OSPFNeighborState {}", nbr.getState());
+            // set options for the NBR
+            nbr.setIsOpaqueCapable(ddPacket.isOpaqueCapable());
+            if (ddPacket.imtu() > ospfInterface.mtu()) {
+                log.debug("the MTU size is greater than the interface MTU");
+                return;
+            }
+            if (nbr.getState() == OspfNeighborState.DOWN) {
+                return;
+            }
+            if (nbr.getState() == OspfNeighborState.ATTEMPT) {
+                return;
+            }
+            if (nbr.getState() == OspfNeighborState.TWOWAY) {
+                nbr.adjOk(channel);
+                return;
+            }
+            //if init is the state call twoWayReceived
+            if (nbr.getState() == OspfNeighborState.INIT) {
+                ((OspfNbrImpl) nbr).twoWayReceived(ddPacket, ctx.getChannel());
+            } else if (nbr.getState() == OspfNeighborState.EXSTART) {
+                //get I,M,MS Bits
+                int initialize = ddPacket.isInitialize();
+                int more = ddPacket.isMore();
+                int masterOrSlave = ddPacket.isMaster();
+                int options = ddPacket.options();
+                nbr.setOptions(options);
+
+                if (initialize == OspfUtil.INITIALIZE_SET && more == OspfUtil.MORE_SET &&
+                        masterOrSlave == OspfUtil.IS_MASTER) {
+                    if (ddPacket.getLsaHeaderList().isEmpty()) {
+                        if (OspfUtil.ipAddressToLong(ddPacket.routerId().toString()) >
+                                OspfUtil.ipAddressToLong(ospfArea.routerId().toString())) {
+                            nbr.setIsMaster(OspfUtil.IS_MASTER);
+                            ((OspfNbrImpl) nbr).setLastDdPacket(ddPacket);
+                            nbr.setDdSeqNum(ddPacket.sequenceNo());
+                            nbr.setOptions(ddPacket.options());
+                            ((OspfNbrImpl) nbr).negotiationDone(ddPacket, true, ddPacket.getLsaHeaderList(),
+                                                                ctx.getChannel());
+                        }
+                    }
+                }
+                if (initialize == OspfUtil.INITIALIZE_NOTSET && masterOrSlave == OspfUtil.NOT_MASTER) {
+                    if (nbr.ddSeqNum() == ddPacket.sequenceNo()) {
+                        if (OspfUtil.ipAddressToLong(ddPacket.routerId().toString()) <
+                                OspfUtil.ipAddressToLong(ospfArea.routerId().toString())) {
+                            ((OspfNbrImpl) nbr).setLastDdPacket(ddPacket);
+                            nbr.setOptions(ddPacket.options());
+                            nbr.setDdSeqNum(nbr.ddSeqNum() + 1);
+                            ((OspfNbrImpl) nbr).negotiationDone(ddPacket, false, ddPacket.getLsaHeaderList(),
+                                                                ctx.getChannel());
+                        }
+                    }
+                }
+
+            } else if (nbr.getState() == OspfNeighborState.EXCHANGE) {
+                //get I,M,MS Bits
+                log.debug("Neighbor state:: EXCHANGE");
+                boolean isDuplicateDDPacket = compareDdPackets(ddPacket, ((OspfNbrImpl) nbr).lastDdPacket());
+                int initialize = ddPacket.isInitialize();
+                int more = ddPacket.isMore();
+                int masterOrSlave = ddPacket.isMaster();
+                int options = ddPacket.options();
+
+                if (!isDuplicateDDPacket) {
+                    //if dd packet is not duplicate  then continue
+                    if (nbr.isMaster() != masterOrSlave) {
+                        DdPacket newResPacket =
+                                (DdPacket) ((OspfNbrImpl) nbr).seqNumMismatch("Master/Slave Inconsistency");
+                        newResPacket.setDestinationIp(ddPacket.sourceIp());
+                        log.debug("Sending back DDPacket to {}", ddPacket.sourceIp());
+                        ctx.getChannel().write(newResPacket);
+                    } else if (initialize == 1) {
+                        DdPacket newResPacket =
+                                (DdPacket) ((OspfNbrImpl) nbr).seqNumMismatch("Initialize bit inconsistency");
+                        newResPacket.setDestinationIp(ddPacket.sourceIp());
+                        log.debug("Sending back DDPacket to {}", ddPacket.sourceIp());
+                        ctx.getChannel().write(newResPacket);
+                    } else {
+
+                        if (masterOrSlave == OspfUtil.NOT_MASTER) {
+                            if (ddPacket.sequenceNo() == nbr.ddSeqNum()) {
+                                //Process the DD Packet
+                                ((OspfNbrImpl) nbr).processDdPacket(false, ddPacket, ctx.getChannel());
+                                log.debug("Received DD Packet");
+                            } else {
+                                DdPacket newResPacket =
+                                        (DdPacket) ((OspfNbrImpl) nbr).seqNumMismatch("Sequence Number Mismatch");
+                                newResPacket.setDestinationIp(ddPacket.sourceIp());
+                                log.debug("Sending back DDPacket to {}", ddPacket.sourceIp());
+                                ctx.getChannel().write(newResPacket);
+                            }
+                        } else {
+                            //we are the slave
+                            if (ddPacket.sequenceNo() == (nbr.ddSeqNum() + 1)) {
+                                ((OspfNbrImpl) nbr).setLastDdPacket(ddPacket);
+                                ((OspfNbrImpl) nbr).processDdPacket(true, ddPacket, ctx.getChannel());
+                                log.debug("Process DD Packet");
+                            } else {
+                                DdPacket newResPacket =
+                                        (DdPacket) ((OspfNbrImpl) nbr).seqNumMismatch("options inconsistency");
+                                newResPacket.setDestinationIp(ddPacket.sourceIp());
+                                log.debug("Sending back DDPacket to {}", ddPacket.sourceIp());
+                                ctx.getChannel().write(newResPacket);
+                            }
+                        }
+                    }
+                } else {
+                    if (masterOrSlave == OspfUtil.NOT_MASTER) {
+                        return;
+                    } else {
+                        DdPacket newResPacket = ((OspfNbrImpl) nbr).lastSentDdPacket();
+                        log.debug("Sending back DDPacket to {}", ddPacket.sourceIp());
+                        ctx.getChannel().write(newResPacket);
+                    }
+                }
+            } else if (nbr.getState() == OspfNeighborState.LOADING || nbr.getState() == OspfNeighborState.FULL) {
+                //In case if we are slave then we have to send the last received DD Packet
+                int options = ddPacket.options();
+                if (nbr.options() != options) {
+                    OspfMessage newResPacket = ((OspfNbrImpl) nbr).seqNumMismatch("Initialize bit inconsistency");
+                    newResPacket.setDestinationIp(ddPacket.sourceIp());
+                    ctx.getChannel().write(newResPacket);
+                } else if (ddPacket.isInitialize() == OspfUtil.INITIALIZE_SET) {
+                    OspfMessage newResPacket = ((OspfNbrImpl) nbr).seqNumMismatch("Initialize bit inconsistency");
+                    newResPacket.setDestinationIp(ddPacket.sourceIp());
+                    ctx.getChannel().write(newResPacket);
+                }
+                boolean isDuplicate = compareDdPackets(ddPacket, ((OspfNbrImpl) nbr).lastDdPacket());
+                //we are master
+                if (nbr.isMaster() != OspfUtil.IS_MASTER) {
+                    // check if the packet is duplicate, duplicates should be discarded by the master
+                    if (isDuplicate) {
+                        log.debug("received a duplicate DD packet");
+                    }
+                } else {
+                    //The slave must respond to duplicates by repeating the last Database Description packet
+                    //that it had sent.
+                    if (isDuplicate) {
+                        ddPacket.setDestinationIp(ddPacket.sourceIp());
+                        ctx.getChannel().write(((OspfNbrImpl) nbr).lastSentDdPacket());
+                        log.debug("Sending back the duplicate packet ");
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Process the Ls Request message.
+     *
+     * @param ospfMessage OSPF message instance.
+     * @param ctx         channel handler context instance.
+     * @throws Exception might throws exception
+     */
+    void processLsRequestMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception {
+        log.debug("OspfChannelHandler::processLsRequestMessage...!!!");
+        LsRequest lsrPacket = (LsRequest) ospfMessage;
+        OspfNbr nbr = ospfInterface.neighbouringRouter(lsrPacket.routerId().toString());
+
+        if (nbr.getState() == OspfNeighborState.EXCHANGE || nbr.getState() == OspfNeighborState.LOADING ||
+                nbr.getState() == OspfNeighborState.FULL) {
+
+            LsRequest reqMsg = (LsRequest) ospfMessage;
+            if (reqMsg.getLinkStateRequests().isEmpty()) {
+                log.debug("Received Link State Request Vector is Empty ");
+                return;
+            } else {
+                //Send the LsUpdate back
+                ListIterator<LsRequestPacket> listItr = reqMsg.getLinkStateRequests().listIterator();
+                while (listItr.hasNext()) {
+                    LsUpdate lsupdate = new LsUpdate();
+                    lsupdate.setOspfVer(OspfUtil.OSPF_VERSION);
+                    lsupdate.setOspftype(OspfPacketType.LSUPDATE.value());
+                    lsupdate.setRouterId(ospfArea.routerId());
+                    lsupdate.setAreaId(ospfArea.areaId());
+                    lsupdate.setAuthType(OspfUtil.NOT_ASSIGNED);
+                    lsupdate.setAuthentication(OspfUtil.NOT_ASSIGNED);
+                    lsupdate.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length
+                    lsupdate.setChecksum(OspfUtil.NOT_ASSIGNED);
+
+                    //limit to mtu
+                    int currentLength = OspfUtil.OSPF_HEADER_LENGTH + OspfUtil.FOUR_BYTES;
+                    int maxSize = ospfInterface.mtu() -
+                            OspfUtil.LSA_HEADER_LENGTH; // subtract a normal IP header.
+                    int noLsa = 0;
+                    while (listItr.hasNext()) {
+                        LsRequestPacket lsRequest = (LsRequestPacket) listItr.next();
+                        // to verify length of the LSA
+                        LsaWrapper wrapper = ospfArea.getLsa(lsRequest.lsType(), lsRequest.linkStateId(),
+                                                             lsRequest.ownRouterId());
+                        OspfLsa ospflsa = wrapper.ospfLsa();
+                        if ((currentLength + ((LsaWrapperImpl) wrapper).lsaHeader().lsPacketLen()) >= maxSize) {
+                            listItr.previous();
+                            break;
+                        }
+                        if (ospflsa != null) {
+                            lsupdate.addLsa(ospflsa);
+                            noLsa++;
+
+                            currentLength = currentLength + ((LsaWrapperImpl) wrapper).lsaHeader().lsPacketLen();
+                        } else {
+                            nbr.badLSReq(channel);
+                        }
+                    }
+                    lsupdate.setNumberOfLsa(noLsa);
+                    //set the destination
+                    if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR ||
+                            ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR ||
+                            ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT) {
+                        lsupdate.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS);
+                    } else if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER) {
+                        lsupdate.setDestinationIp(OspfUtil.ALL_DROUTERS);
+                    }
+                    ctx.getChannel().write(lsupdate);
+                }
+            }
+        }
+    }
+
+    /**
+     * Process the ls update message.
+     *
+     * @param ospfMessage OSPF message instance.
+     * @param ctx         channel handler context instance.
+     * @throws Exception might throws exception
+     */
+    void processLsUpdateMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception {
+        log.debug("OspfChannelHandler::processLsUpdateMessage");
+        LsUpdate lsUpdate = (LsUpdate) ospfMessage;
+        String neighbourId = lsUpdate.routerId().toString();
+        //LSUpdate packet has been associated with a particular neighbor.
+        //Neighbor should not be in lesser state than Exchange.
+        if (ospfInterface.isNeighborInList(neighbourId)) {
+            OspfNbrImpl nbr = (OspfNbrImpl) ospfInterface.neighbouringRouter(neighbourId);
+            if (nbr.getState() == OspfNeighborState.EXCHANGE ||
+                    nbr.getState() == OspfNeighborState.LOADING) {
+                nbr.processLsUpdate(lsUpdate, ctx.getChannel());
+            } else if (nbr.getState() == OspfNeighborState.FULL) {
+                if (lsUpdate.noLsa() != 0) {
+                    List<OspfLsa> list = lsUpdate.getLsaList();
+                    Iterator itr = list.iterator();
+                    while (itr.hasNext()) {
+                        LsaHeader lsa = (LsaHeader) itr.next();
+                        nbr.processReceivedLsa(lsa, true, ctx.getChannel(), lsUpdate.sourceIp());
+                    }
+                } else {
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
+     * Process the ls acknowledge message.
+     *
+     * @param ospfMessage OSPF message instance.
+     * @param ctx         channel handler context instance.
+     * @throws Exception might throws exception
+     */
+    void processLsAckMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception {
+        log.debug("OspfChannelHandler::processLsAckMessage");
+        LsAcknowledge lsAckPacket = (LsAcknowledge) ospfMessage;
+        //check it is present in listOfNeighbors
+        OspfNbrImpl nbr = (OspfNbrImpl) ospfInterface.neighbouringRouter(lsAckPacket.routerId().toString());
+        if (nbr != null) {
+            if (nbr.getState().getValue() < OspfNeighborState.EXCHANGE.getValue()) {
+                // discard the packet.
+                return;
+            } else {
+                // process ls acknowledgements
+                Iterator itr = lsAckPacket.getLinkStateHeaders().iterator();
+                while (itr.hasNext()) {
+                    LsaHeader lsRequest = (LsaHeader) itr.next();
+
+                    OspfLsa ospfLsa =
+                            (OspfLsa) nbr.getPendingReTxList().get(((OspfAreaImpl) ospfArea).getLsaKey(lsRequest));
+                    if (lsRequest != null && ospfLsa != null) {
+                        String isSame = ((OspfLsdbImpl) ospfArea.database()).isNewerOrSameLsa(
+                                lsRequest, (LsaHeader) ospfLsa);
+                        if (isSame.equals("same")) {
+                            nbr.getPendingReTxList().remove(((OspfAreaImpl) ospfArea).getLsaKey(lsRequest));
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Compares two Dd Packets to check whether its duplicate or not.
+     *
+     * @param receivedDPacket received DD packet from network.
+     * @param lastDdPacket    Last DdPacket which we sent.
+     * @return true if it is a duplicate packet else false.
+     */
+    public boolean compareDdPackets(DdPacket receivedDPacket, DdPacket lastDdPacket) {
+        if (receivedDPacket.isInitialize() == lastDdPacket.isInitialize()) {
+            if (receivedDPacket.isMaster() == lastDdPacket.isMaster()) {
+                if (receivedDPacket.isMore() == lastDdPacket.isMore()) {
+                    if (receivedDPacket.options() == lastDdPacket.options()) {
+                        if (receivedDPacket.sequenceNo() == lastDdPacket.sequenceNo()) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Closes the Netty channel.
+     *
+     * @param ctx the Channel Handler Context
+     */
+    void closeChannel(ChannelHandlerContext ctx) {
+        log.debug("OspfChannelHandler::closeChannel");
+        isClosed = true;
+        ctx.getChannel().close();
+    }
+
+    /**
+     * Starts the hello timer which sends hello packet every configured seconds.
+     *
+     * @param period the interval to run task
+     */
+    private void startHelloTimer(long period) {
+        log.debug("OSPFInterfaceChannelHandler::startHelloTimer");
+        exServiceHello = Executors.newSingleThreadScheduledExecutor();
+        helloTimerTask = new InternalHelloTimer();
+        final ScheduledFuture<?> helloHandle =
+                exServiceHello.scheduleAtFixedRate(helloTimerTask, delay, period, TimeUnit.SECONDS);
+    }
+
+    /**
+     * Stops the hello timer.
+     */
+    private void stopHelloTimer() {
+        log.debug("OSPFInterfaceChannelHandler::stopHelloTimer ");
+        exServiceHello.shutdown();
+    }
+
+    /**
+     * Starts the wait timer.
+     */
+    private void startWaitTimer() {
+        log.debug("OSPFNbr::startWaitTimer");
+        exServiceWait = Executors.newSingleThreadScheduledExecutor();
+        waitTimerTask = new InternalWaitTimer();
+        final ScheduledFuture<?> waitTimerHandle =
+                exServiceWait.schedule(waitTimerTask, ospfInterface.routerDeadIntervalTime(),
+                                       TimeUnit.SECONDS);
+    }
+
+    /**
+     * Stops the wait timer.
+     */
+    private void stopWaitTimer() {
+        log.debug("OSPFNbr::stopWaitTimer ");
+        exServiceWait.shutdown();
+    }
+
+    /**
+     * Starts the timer which waits for configured seconds and sends Delayed Ack Packet.
+     */
+    private void startDelayedAckTimer() {
+        if (!isDelayedAckTimerScheduled) {
+            log.debug("Started DelayedAckTimer...!!!");
+            exServiceDelayedAck = Executors.newSingleThreadScheduledExecutor();
+            delayedAckTimerTask = new InternalDelayedAckTimer();
+            final ScheduledFuture<?> delayAckHandle =
+                    exServiceDelayedAck.scheduleAtFixedRate(delayedAckTimerTask, delayedAckTimerInterval,
+                                                            delayedAckTimerInterval, TimeUnit.MILLISECONDS);
+            isDelayedAckTimerScheduled = true;
+        }
+    }
+
+    /**
+     * Stops the delayed acknowledge timer.
+     */
+    private void stopDelayedAckTimer() {
+        if (isDelayedAckTimerScheduled) {
+            log.debug("Stopped DelayedAckTimer...!!!");
+            isDelayedAckTimerScheduled = false;
+            exServiceDelayedAck.shutdown();
+        }
+    }
+
+    /**
+     * Performs DR election.
+     *
+     * @param ch Netty Channel instance.
+     * @throws Exception might throws exception
+     */
+    public void electRouter(Channel ch) throws Exception {
+
+        Ip4Address currentDr = ospfInterface.dr();
+        Ip4Address currentBdr = ospfInterface.bdr();
+        OspfInterfaceState oldState = ((OspfInterfaceImpl) ospfInterface).state();
+        OspfInterfaceState newState;
+
+        log.debug("OSPFInterfaceChannelHandler::electRouter -> currentDr: {}, currentBdr: {}",
+                  currentDr, currentBdr);
+        List<OspfEligibleRouter> eligibleRouters = calculateListOfEligibleRouters(new OspfEligibleRouter());
+
+        log.debug("OSPFInterfaceChannelHandler::electRouter -> eligibleRouters: {}", eligibleRouters);
+        OspfEligibleRouter electedBdr = electBdr(eligibleRouters);
+        OspfEligibleRouter electedDr = electDr(eligibleRouters, electedBdr);
+
+        ospfInterface.setBdr(electedBdr.getIpAddress());
+        ospfInterface.setDr(electedDr.getIpAddress());
+
+        if (electedBdr.getIpAddress().equals(ospfInterface.ipAddress()) &&
+                !electedBdr.getIpAddress().equals(currentBdr)) {
+            ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.BDR);
+        }
+
+        if (electedDr.getIpAddress().equals(ospfInterface.ipAddress()) &&
+                !electedDr.getIpAddress().equals(currentDr)) {
+            ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DR);
+        }
+
+        if (((OspfInterfaceImpl) ospfInterface).state() != oldState &&
+                !(((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER &&
+                        oldState.value() < OspfInterfaceState.DROTHER.value())) {
+            log.debug("Recalculating as the State is changed ");
+            log.debug("OSPFInterfaceChannelHandler::electRouter -> currentDr: {}, currentBdr: {}",
+                      currentDr, currentBdr);
+            eligibleRouters = calculateListOfEligibleRouters(new OspfEligibleRouter());
+
+            log.debug("OSPFInterfaceChannelHandler::electRouter -> eligibleRouters: {}", eligibleRouters);
+            electedBdr = electBdr(eligibleRouters);
+            electedDr = electDr(eligibleRouters, electedBdr);
+
+            ospfInterface.setBdr(electedBdr.getIpAddress());
+            ospfInterface.setDr(electedDr.getIpAddress());
+        }
+
+        if (electedBdr.getIpAddress().equals(ospfInterface.ipAddress()) &&
+                !electedBdr.getIpAddress().equals(currentBdr)) {
+            ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.BDR);
+            ospfArea.refreshArea(ospfInterface);
+        }
+
+        if (electedDr.getIpAddress().equals(ospfInterface.ipAddress()) &&
+                !electedDr.getIpAddress().equals(currentDr)) {
+            ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DR);
+            //Refresh Router Lsa & Network Lsa
+            ospfArea.refreshArea(ospfInterface);
+        }
+
+        if (currentDr != electedDr.getIpAddress() || currentBdr != electedBdr.getIpAddress()) {
+            Set<String> negibhorIdList;
+            negibhorIdList = ospfInterface.listOfNeighbors().keySet();
+            for (String routerid : negibhorIdList) {
+                OspfNbrImpl nbr = (OspfNbrImpl) ospfInterface.neighbouringRouter(routerid);
+                if (nbr.getState().getValue() >= OspfNeighborState.TWOWAY.getValue()) {
+                    nbr.adjOk(ch);
+                }
+            }
+        }
+
+        log.debug("OSPFInterfaceChannelHandler::electRouter -> ElectedDR: {}, ElectedBDR: {}",
+                  electedDr.getIpAddress(), electedBdr.getIpAddress());
+    }
+
+
+    /**
+     * BDR Election process. Find the list of eligible router to participate in the process.
+     *
+     * @param electedDr router elected as DR.
+     * @return list of eligible routers
+     */
+    public List<OspfEligibleRouter> calculateListOfEligibleRouters(OspfEligibleRouter electedDr) {
+        log.debug("OSPFNbr::calculateListOfEligibleRouters ");
+        Set<String> neighborIdList;
+        List<OspfEligibleRouter> eligibleRouters = new ArrayList<>();
+
+        neighborIdList = ospfInterface.listOfNeighbors().keySet();
+        for (String routerId : neighborIdList) {
+            OspfNbrImpl nbr = (OspfNbrImpl) ospfInterface.neighbouringRouter(routerId);
+            if (nbr.getState().getValue() >= OspfNeighborState.TWOWAY.getValue() &&
+                    nbr.routerPriority() > 0) {
+                OspfEligibleRouter router = new OspfEligibleRouter();
+                router.setIpAddress(nbr.neighborIpAddr());
+                router.setRouterId(nbr.neighborId());
+                router.setRouterPriority(nbr.routerPriority());
+                if (nbr.neighborDr().equals(nbr.neighborIpAddr()) ||
+                        electedDr.getIpAddress().equals(nbr.neighborIpAddr())) {
+                    router.setIsDr(true);
+                } else if (nbr.neighborBdr().equals(nbr.neighborIpAddr())) {
+                    router.setIsBdr(true);
+                }
+                eligibleRouters.add(router);
+            }
+        }
+        // interface does not have states like two and all
+        if (ospfInterface.routerPriority() > 0) {
+            OspfEligibleRouter router = new OspfEligibleRouter();
+            router.setIpAddress(ospfInterface.ipAddress());
+            router.setRouterId(ospfArea.routerId());
+            router.setRouterPriority(ospfInterface.routerPriority());
+            if (ospfInterface.dr().equals(ospfInterface.ipAddress()) ||
+                    electedDr.getIpAddress().equals(ospfInterface.ipAddress())) {
+                router.setIsDr(true);
+            } else if (ospfInterface.bdr().equals(ospfInterface.ipAddress()) &&
+                    !ospfInterface.dr().equals(ospfInterface.ipAddress())) {
+                router.setIsBdr(true);
+            }
+
+            eligibleRouters.add(router);
+        }
+
+        return eligibleRouters;
+    }
+
+    /**
+     * Based on router priority assigns BDR.
+     *
+     * @param eligibleRouters list of routers to participate in bdr election.
+     * @return OSPF Eligible router instance.
+     */
+    public OspfEligibleRouter electBdr(List<OspfEligibleRouter> eligibleRouters) {
+        log.debug("OSPFInterfaceChannelHandler::electBdr -> eligibleRouters: {}", eligibleRouters);
+        List<OspfEligibleRouter> declaredAsBdr = new ArrayList<>();
+        List<OspfEligibleRouter> notDrAndBdr = new ArrayList<>();
+        for (OspfEligibleRouter router : eligibleRouters) {
+            if (router.isBdr()) {
+                declaredAsBdr.add(router);
+            }
+            if (!router.isBdr() && !router.isDr()) {
+                notDrAndBdr.add(router);
+            }
+        }
+
+        OspfEligibleRouter electedBdr = new OspfEligibleRouter();
+        if (!declaredAsBdr.isEmpty()) {
+            if (declaredAsBdr.size() == 1) {
+                electedBdr = declaredAsBdr.get(0);
+            } else if (declaredAsBdr.size() > 1) {
+                electedBdr = selectRouterBasedOnPriority(declaredAsBdr);
+            }
+        } else {
+            if (notDrAndBdr.size() == 1) {
+                electedBdr = notDrAndBdr.get(0);
+            } else if (notDrAndBdr.size() > 1) {
+                electedBdr = selectRouterBasedOnPriority(notDrAndBdr);
+            }
+        }
+
+        electedBdr.setIsBdr(true);
+        electedBdr.setIsDr(false);
+
+        return electedBdr;
+    }
+
+    /**
+     * DR Election process.
+     *
+     * @param eligibleRouters list of eligible routers.
+     * @param electedBdr      Elected Bdr, OSPF eligible router instance.
+     * @return OSPF eligible router instance.
+     */
+    public OspfEligibleRouter electDr(List<OspfEligibleRouter> eligibleRouters,
+                                      OspfEligibleRouter electedBdr) {
+
+        List<OspfEligibleRouter> declaredAsDr = new ArrayList<>();
+        for (OspfEligibleRouter router : eligibleRouters) {
+            if (router.isDr()) {
+                declaredAsDr.add(router);
+            }
+        }
+
+        OspfEligibleRouter electedDr = new OspfEligibleRouter();
+        if (!declaredAsDr.isEmpty()) {
+            if (declaredAsDr.size() == 1) {
+                electedDr = declaredAsDr.get(0);
+            } else if (eligibleRouters.size() > 1) {
+                electedDr = selectRouterBasedOnPriority(declaredAsDr);
+            }
+        } else {
+            electedDr = electedBdr;
+            electedDr.setIsDr(true);
+            electedDr.setIsBdr(false);
+        }
+
+        return electedDr;
+    }
+
+    /**
+     * DR election process.
+     *
+     * @param routersList list of eligible routers.
+     * @return OSPF eligible router instance.
+     */
+    public OspfEligibleRouter selectRouterBasedOnPriority(List<OspfEligibleRouter> routersList) {
+
+        OspfEligibleRouter initialRouter = routersList.get(0);
+
+        for (int i = 1; i < routersList.size(); i++) {
+            OspfEligibleRouter router = routersList.get(i);
+            if (router.getRouterPriority() > initialRouter.getRouterPriority()) {
+                initialRouter = router;
+            } else if (router.getRouterPriority() == initialRouter.getRouterPriority()) {
+                try {
+                    //if (router.getIpAddress().toInt() > initialRouter.getIpAddress().toInt()) {
+                    if (OspfUtil.ipAddressToLong(router.getIpAddress().toString()) >
+                            OspfUtil.ipAddressToLong(initialRouter.getIpAddress().toString())) {
+                        initialRouter = router;
+                    }
+                } catch (Exception e) {
+                    log.debug("OSPFInterfaceChannelHandler::selectRouterBasedOnPriority ->" +
+                                      " eligibleRouters: {}", initialRouter);
+                }
+            }
+        }
+
+        return initialRouter;
+    }
+
+    /**
+     * Adds device information.
+     *
+     * @param ospfRouter OSPF router instance
+     */
+    public void addDeviceInformation(OspfRouter ospfRouter) {
+        controller.addDeviceDetails(ospfRouter);
+    }
+
+    /**
+     * removes device information.
+     *
+     * @param ospfRouter OSPF neighbor instance
+     */
+    public void removeDeviceInformation(OspfRouter ospfRouter) {
+        controller.removeDeviceDetails(ospfRouter);
+    }
+
+    /**
+     * Adds link information.
+     *
+     * @param ospfRouter  OSPF router instance
+     * @param ospfLinkTed list link ted instances
+     */
+    public void addLinkInformation(OspfRouter ospfRouter, OspfLinkTed ospfLinkTed) {
+        controller.addLinkDetails(ospfRouter, ospfLinkTed);
+    }
+
+    /**
+     * Removes link information.
+     *
+     * @param ospfNbr OSPF neighbor instance
+     */
+    public void removeLinkInformation(OspfNbr ospfNbr) {
+        controller.removeLinkDetails(buildOspfRouterDetails(ospfNbr));
+    }
+
+    /**
+     * Builds router details.
+     *
+     * @param ospfNbr OSPF neighbor instance
+     * @return OSPF router instance
+     */
+    private OspfRouter buildOspfRouterDetails(OspfNbr ospfNbr) {
+        OspfRouter ospfRouter = new OspfRouterImpl();
+        ospfRouter.setRouterIp(ospfNbr.neighborId());
+        ospfRouter.setInterfaceId(ospfInterface.ipAddress());
+        ospfRouter.setAreaIdOfInterface(ospfArea.areaId());
+
+        ospfRouter.setDeviceTed(new OspfDeviceTedImpl());
+
+        return ospfRouter;
+    }
+
+    /**
+     * Represents a Hello task which sent a hello message every configured time interval.
+     */
+    private class InternalHelloTimer implements Runnable {
+
+        /**
+         * Creates an instance of Hello Timer.
+         */
+        InternalHelloTimer() {
+        }
+
+        @Override
+        public void run() {
+            if (!isClosed && channel != null && channel.isOpen() && channel.isConnected()) {
+
+                HelloPacket hellopacket = new HelloPacket();
+                //Headers
+                hellopacket.setOspfVer(OspfUtil.OSPF_VERSION);
+                hellopacket.setOspftype(OspfPacketType.HELLO.value());
+                hellopacket.setOspfPacLength(0); //will be modified while encoding
+                hellopacket.setRouterId(ospfArea.routerId());
+                hellopacket.setAreaId(ospfArea.areaId());
+                hellopacket.setChecksum(0); //will be modified while encoding
+                hellopacket.setAuthType(Integer.parseInt(ospfInterface.authType()));
+                hellopacket.setAuthentication(Integer.parseInt(ospfInterface.authKey()));
+                //Body
+                hellopacket.setNetworkMask(ospfInterface.ipNetworkMask());
+                hellopacket.setOptions(ospfArea.options());
+                hellopacket.setHelloInterval(ospfInterface.helloIntervalTime());
+                hellopacket.setRouterPriority(ospfInterface.routerPriority());
+                hellopacket.setRouterDeadInterval(ospfInterface.routerDeadIntervalTime());
+                hellopacket.setDr(ospfInterface.dr());
+                hellopacket.setBdr(ospfInterface.bdr());
+
+                HashMap<String, OspfNbr> listOfNeighbors = ospfInterface.listOfNeighbors();
+                Set<String> keys = listOfNeighbors.keySet();
+                Iterator itr = keys.iterator();
+                while (itr.hasNext()) {
+                    String nbrKey = (String) itr.next();
+                    OspfNbrImpl nbr = (OspfNbrImpl) listOfNeighbors.get(nbrKey);
+                    if (nbr.getState() != OspfNeighborState.DOWN) {
+                        hellopacket.addNeighbor(Ip4Address.valueOf(nbrKey));
+                    }
+                }
+                // build a hello Packet
+                if (channel == null || !channel.isOpen() || !channel.isConnected()) {
+                    log.debug("Hello Packet not sent !!.. Channel Issue...");
+                    return;
+                }
+
+                hellopacket.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS);
+                ChannelFuture future = channel.write(hellopacket);
+                if (future.isSuccess()) {
+                    log.debug("Hello Packet successfully sent !!");
+                } else {
+                    future.awaitUninterruptibly();
+                }
+
+            }
+        }
+    }
+
+    /**
+     * Represents a Wait Timer task which waits the interface state to become WAITING.
+     * It initiates DR election process.
+     */
+    private class InternalWaitTimer implements Runnable {
+        Channel ch;
+
+        /**
+         * Creates an instance of Wait Timer.
+         */
+        InternalWaitTimer() {
+            this.ch = channel;
+        }
+
+        @Override
+        public void run() {
+            log.debug("Wait timer expires...");
+            if (ch != null && ch.isConnected()) {
+                try {
+                    waitTimer(ch);
+                } catch (Exception e) {
+                    log.debug("Exception at wait timer ...!!!");
+                }
+
+            }
+        }
+    }
+
+    /**
+     * Represents a task which sent a LS Acknowledge from the link state headers list.
+     */
+    private class InternalDelayedAckTimer implements Runnable {
+        Channel ch;
+
+        /**
+         * Creates an instance of Delayed acknowledge timer.
+         */
+        InternalDelayedAckTimer() {
+            this.ch = channel;
+        }
+
+        @Override
+        public void run() {
+            if (!((OspfInterfaceImpl) ospfInterface).linkStateHeaders().isEmpty()) {
+                isDelayedAckTimerScheduled = true;
+                if (ch != null && ch.isConnected()) {
+
+                    List<LsaHeader> listOfLsaHeadersAcknowledged = new ArrayList<>();
+                    List<LsaHeader> listOfLsaHeaders = ((OspfInterfaceImpl) ospfInterface).linkStateHeaders();
+                    log.debug("Delayed Ack, Number of Lsa's to Ack {}", listOfLsaHeaders.size());
+                    Iterator itr = listOfLsaHeaders.iterator();
+                    while (itr.hasNext()) {
+                        LsAcknowledge ackContent = new LsAcknowledge();
+                        //Setting OSPF Header
+                        ackContent.setOspfVer(OspfUtil.OSPF_VERSION);
+                        ackContent.setOspftype(OspfPacketType.LSAACK.value());
+                        ackContent.setRouterId(ospfArea.routerId());
+                        ackContent.setAreaId(ospfArea.areaId());
+                        ackContent.setAuthType(OspfUtil.NOT_ASSIGNED);
+                        ackContent.setAuthentication(OspfUtil.NOT_ASSIGNED);
+                        ackContent.setOspfPacLength(OspfUtil.NOT_ASSIGNED);
+                        ackContent.setChecksum(OspfUtil.NOT_ASSIGNED);
+                        //limit to mtu
+                        int currentLength = OspfUtil.OSPF_HEADER_LENGTH;
+                        int maxSize = ospfInterface.mtu() -
+                                OspfUtil.LSA_HEADER_LENGTH; // subtract a normal IP header.
+                        while (itr.hasNext()) {
+                            if ((currentLength + OspfUtil.LSA_HEADER_LENGTH) >= maxSize) {
+                                break;
+                            }
+                            LsaHeader lsaHeader = (LsaHeader) itr.next();
+                            ackContent.addLinkStateHeader(lsaHeader);
+                            currentLength = currentLength + OspfUtil.LSA_HEADER_LENGTH;
+                            listOfLsaHeadersAcknowledged.add(lsaHeader);
+                            log.debug("Delayed Ack, Added Lsa's to Ack {}", lsaHeader);
+                        }
+
+                        log.debug("Delayed Ack, Number of Lsa's in LsAck packet {}",
+                                  ackContent.getLinkStateHeaders().size());
+
+                        //set the destination
+                        if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR ||
+                                ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR
+                                || ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT) {
+                            ackContent.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS);
+                        } else if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER) {
+                            ackContent.setDestinationIp(OspfUtil.ALL_DROUTERS);
+                        }
+                        ch.write(ackContent);
+                        for (LsaHeader lsa : listOfLsaHeadersAcknowledged) {
+                            ((OspfInterfaceImpl) ospfInterface).linkStateHeaders().remove(lsa);
+                            ospfInterface.removeLsaFromNeighborMap(((OspfAreaImpl) ospfArea).getLsaKey(lsa));
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsaQueueConsumer.java b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsaQueueConsumer.java
new file mode 100755
index 0000000..977ec35
--- /dev/null
+++ b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsaQueueConsumer.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2016 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.ospf.controller.lsdb;
+
+import org.jboss.netty.channel.Channel;
+import org.onosproject.ospf.controller.LsaWrapper;
+import org.onosproject.ospf.controller.OspfArea;
+import org.onosproject.ospf.controller.OspfInterface;
+import org.onosproject.ospf.controller.OspfLsaType;
+import org.onosproject.ospf.controller.area.OspfAreaImpl;
+import org.onosproject.ospf.controller.area.OspfInterfaceImpl;
+import org.onosproject.ospf.protocol.lsa.LsaHeader;
+import org.onosproject.ospf.protocol.lsa.types.NetworkLsa;
+import org.onosproject.ospf.protocol.lsa.types.RouterLsa;
+import org.onosproject.ospf.protocol.util.ChecksumCalculator;
+import org.onosproject.ospf.protocol.util.OspfInterfaceState;
+import org.onosproject.ospf.protocol.util.OspfParameters;
+import org.onosproject.ospf.protocol.util.OspfUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.BlockingQueue;
+
+/**
+ * Consumes LSA from the Queue and processes it.
+ * Its a producer consumer implementation using Blocking queue.
+ */
+public class LsaQueueConsumer implements Runnable {
+    private static final Logger log = LoggerFactory.getLogger(LsaQueueConsumer.class);
+    private BlockingQueue queue = null;
+    private Channel channel;
+    private OspfArea ospfArea;
+
+    /**
+     * Creates an instance of LSA queue consumer.
+     *
+     * @param queue    queue instance
+     * @param channel  netty channel instance
+     * @param ospfArea OSPF area instance
+     */
+    public LsaQueueConsumer(BlockingQueue queue, Channel channel, OspfArea ospfArea) {
+        this.queue = queue;
+        this.channel = channel;
+        this.ospfArea = ospfArea;
+    }
+
+    /**
+     * Threads run method.
+     */
+    public void run() {
+        log.debug("LSAQueueConsumer:run...!!!");
+        try {
+            while (true) {
+                if (!queue.isEmpty()) {
+                    LsaWrapper wrapper = (LsaWrapper) queue.take();
+                    String lsaProcessing = wrapper.lsaProcessing();
+                    switch (lsaProcessing) {
+                        case OspfParameters.VERIFYCHECKSUM:
+                            log.debug("LSAQueueConsumer: Message - " + OspfParameters.VERIFYCHECKSUM + " consumed.");
+                            processVerifyChecksum(wrapper);
+                            break;
+                        case OspfParameters.REFRESHLSA:
+                            log.debug("LSAQueueConsumer: Message - " + OspfParameters.REFRESHLSA + " consumed.");
+                            processRefreshLsa(wrapper);
+                            break;
+                        case OspfParameters.MAXAGELSA:
+                            log.debug("LSAQueueConsumer: Message - " + OspfParameters.MAXAGELSA + " consumed.");
+                            processMaxAgeLsa(wrapper);
+                            break;
+                        default:
+                            log.debug("Unknown command to process the LSA in queue ...!!!");
+                            break;
+                    }
+                }
+            }
+
+        } catch (Exception e) {
+            log.debug("Error::LSAQueueConsumer::{}", e.getMessage());
+        }
+    }
+
+    /**
+     * Processes verify checksum - checkAges.
+     *
+     * @param wrapper LSA wrapper instance
+     */
+    private void processVerifyChecksum(LsaWrapper wrapper) throws Exception {
+        ChecksumCalculator checkSum = new ChecksumCalculator();
+        if (!checkSum.isValidLsaCheckSum(wrapper.ospfLsa(), ((LsaWrapperImpl) wrapper).lsaHeader().lsType(),
+                                         OspfUtil.LSAPACKET_CHECKSUM_POS1,
+                                         OspfUtil.LSAPACKET_CHECKSUM_POS2)) {
+            log.debug("LSAQueueConsumer::Checksum mismatch. Received LSA packet type {} ",
+                      ((LsaWrapperImpl) wrapper).lsaHeader().lsType());
+
+            //Checksum Invalid
+            //RFC 2328 Restart the Router.
+            //Currently we are not restarting. We are not handling this case.
+        }
+    }
+
+    /**
+     * Process refresh LSA.
+     *
+     * @param wrapper LSA wrapper instance
+     */
+    private void processRefreshLsa(LsaWrapper wrapper) throws Exception {
+        if (wrapper.isSelfOriginated()) { //self originated
+            //set the destination
+            OspfInterface ospfInterface = wrapper.ospfInterface();
+            if (ospfInterface != null) {
+                LsaHeader header = ((LsaWrapperImpl) wrapper).lsaHeader();
+                header.setAge(wrapper.currentAge());
+                if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR) {
+                    if (header.lsType() == OspfLsaType.ROUTER.value()) {
+                        RouterLsa routerLsa = ((OspfAreaImpl) ospfArea).buildRouterLsa(ospfInterface);
+                        ((OspfAreaImpl) ospfArea).addLsa(routerLsa, true, ospfInterface);
+                        ((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(routerLsa);
+                    } else if (header.lsType() == OspfLsaType.NETWORK.value()) {
+                        if (ospfInterface.listOfNeighbors().size() > 0) {
+                            NetworkLsa networkLsa = ((OspfAreaImpl) ospfArea).buildNetworkLsa(
+                                    ospfInterface.ipAddress(), ospfInterface.ipNetworkMask());
+                            ospfArea.addLsa(networkLsa, true, ospfInterface);
+                            ((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(networkLsa);
+                        }
+                    }
+                }
+
+                if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR ||
+                        ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT ||
+                        ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER) {
+                    ospfArea.refreshArea(ospfInterface);
+                }
+                log.debug("LSAQueueConsumer: processRefreshLsa - Flooded SelfOriginated LSA {}",
+                          ((LsaWrapperImpl) wrapper).lsaHeader());
+            }
+        }
+    }
+
+    /**
+     * Process max age LSA.
+     *
+     * @param wrapper LSA wrapper instance
+     */
+    private void processMaxAgeLsa(LsaWrapper wrapper) {
+        //set the destination
+        OspfInterface ospfInterface = wrapper.ospfInterface();
+        if (ospfInterface != null) {
+            LsaHeader header = (LsaHeader) wrapper.ospfLsa().lsaHeader();
+            header.setAge(OspfParameters.MAXAGE);
+            ((LsaWrapperImpl) wrapper).lsaHeader().setAge(OspfParameters.MAXAGE);
+            if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR ||
+                    ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT) {
+                //remove from db
+                ((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(((LsaWrapperImpl) wrapper).lsaHeader());
+                ((OspfAreaImpl) ospfArea).deleteLsa(((LsaWrapperImpl) wrapper).lsaHeader());
+            } else {
+                ((OspfAreaImpl) ospfArea).deleteLsa(((LsaWrapperImpl) wrapper).lsaHeader());
+            }
+            log.debug("LSAQueueConsumer: processMaxAgeLsa - Flooded SelfOriginated-Max Age LSA {}",
+                      ((LsaWrapperImpl) wrapper).lsaHeader());
+        }
+    }
+
+    /**
+     * Sets the channel.
+     *
+     * @param channel channel instance
+     */
+    public void setChannel(Channel channel) {
+        this.channel = channel;
+    }
+}
\ No newline at end of file
diff --git a/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsdbAgeImpl.java b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsdbAgeImpl.java
new file mode 100755
index 0000000..29af7c3
--- /dev/null
+++ b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsdbAgeImpl.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright 2016 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.ospf.controller.lsdb;
+
+import com.google.common.base.Objects;
+import org.jboss.netty.channel.Channel;
+import org.onosproject.ospf.controller.LsaBin;
+import org.onosproject.ospf.controller.LsaWrapper;
+import org.onosproject.ospf.controller.LsdbAge;
+import org.onosproject.ospf.controller.OspfArea;
+import org.onosproject.ospf.controller.area.OspfAreaImpl;
+import org.onosproject.ospf.protocol.util.OspfParameters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Representation of LSDB Aging process.
+ */
+public class LsdbAgeImpl implements LsdbAge {
+
+    private static final Logger log =
+            LoggerFactory.getLogger(LsdbAgeImpl.class);
+    protected int ageCounter = 0;
+    private InternalAgeTimer dbAgeTimer;
+    private ScheduledExecutorService exServiceage;
+    // creating age bins of MAXAGE
+    private Map<Integer, LsaBin> ageBins = new ConcurrentHashMap<>(OspfParameters.MAXAGE);
+    private LsaBin maxAgeBin = new LsaBinImpl(OspfParameters.MAXAGE);
+    private int ageCounterRollOver = 0;
+    private Channel channel = null;
+    private LsaQueueConsumer queueConsumer = null;
+    private BlockingQueue<LsaWrapper> lsaQueue = new ArrayBlockingQueue(1024);
+    private OspfArea ospfArea = null;
+
+
+    /**
+     * Creates an instance of LSDB age.
+     *
+     * @param ospfArea OSPF area instance
+     */
+    public LsdbAgeImpl(OspfArea ospfArea) {
+        // create LSBin's in the HashMap.
+        for (int i = 0; i < OspfParameters.MAXAGE; i++) {
+            LsaBin lsaBin = new LsaBinImpl(i);
+            ageBins.put(i, lsaBin);
+        }
+        this.ospfArea = ospfArea;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        LsdbAgeImpl that = (LsdbAgeImpl) o;
+        return Objects.equal(ageBins, that.ageBins) &&
+                Objects.equal(ageCounter, that.ageCounter) &&
+                Objects.equal(ageCounterRollOver, that.ageCounterRollOver) &&
+                Objects.equal(lsaQueue, lsaQueue);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(ageBins, ageCounter, ageCounterRollOver, lsaQueue);
+    }
+
+    /**
+     * Adds LSA to bin.
+     *
+     * @param binKey key to store in bin
+     * @param lsaBin LSA bin instance
+     */
+    public void addLsaBin(Integer binKey, LsaBin lsaBin) {
+        if (!ageBins.containsKey(binKey)) {
+            ageBins.put(binKey, lsaBin);
+        }
+    }
+
+    /**
+     * Gets LSA from Bin.
+     *
+     * @param binKey key
+     * @return bin instance
+     */
+    public LsaBin getLsaBin(Integer binKey) {
+
+        return ageBins.get(binKey);
+    }
+
+    /**
+     * Adds the LSA to maxAge bin.
+     *
+     * @param key     key
+     * @param wrapper wrapper instance
+     */
+    public void addLsaToMaxAgeBin(String key, LsaWrapper wrapper) {
+        maxAgeBin.addOspfLsa(key, wrapper);
+    }
+
+    /**
+     * Removes LSA from Bin.
+     *
+     * @param lsaWrapper wrapper instance
+     */
+    public void removeLsaFromBin(LsaWrapper lsaWrapper) {
+        if (ageBins.containsKey(lsaWrapper.binNumber())) {
+            LsaBin lsaBin = ageBins.get(lsaWrapper.binNumber());
+            lsaBin.removeOspfLsa(((OspfAreaImpl) ospfArea).getLsaKey(((LsaWrapperImpl)
+                    lsaWrapper).lsaHeader()), lsaWrapper);
+        }
+    }
+
+    /**
+     * Starts the aging timer and queue consumer.
+     */
+    public void startDbAging() {
+        startDbAgeTimer();
+        queueConsumer = new LsaQueueConsumer(lsaQueue, channel, ospfArea);
+        new Thread(queueConsumer).start();
+    }
+
+
+    /**
+     * Gets called every 1 second as part of the timer.
+     */
+    public void ageLsaAndFlood() {
+        //every 5 mins checksum validation
+        checkAges();
+        //every 30 mins - flood LSA
+        refreshLsa();
+        //every 60 mins - flood LSA
+        maxAgeLsa();
+
+        if (ageCounter == OspfParameters.MAXAGE) {
+            ageCounter = 0;
+            ageCounterRollOver++;
+        } else {
+            //increment age bin
+            ageCounter++;
+        }
+    }
+
+    /**
+     * If the LSA have completed the MaxAge - they are moved called stop aging and flooded.
+     */
+    public void maxAgeLsa() {
+        if (ageCounter == 0) {
+            return;
+        }
+        //Get from Age Bins
+        LsaBin lsaBin = ageBins.get(ageCounter - 1);
+        if (lsaBin == null) {
+            return;
+        }
+        Map lsaBinMap = lsaBin.listOfLsa();
+        for (Object key : lsaBinMap.keySet()) {
+            LsaWrapper lsa = (LsaWrapper) lsaBinMap.get((String) key);
+            if (lsa.currentAge() == OspfParameters.MAXAGE) {
+                lsa.setLsaProcessing(OspfParameters.MAXAGELSA);
+                log.debug("Lsa picked for maxage flooding. Age Counter: {}, AgeCounterRollover: {}, " +
+                                  "AgeCounterRollover WhenAddedToDb: {}, LSA Type: {}, LSA Key: {}",
+                          ageCounter, ageCounterRollOver, lsa.currentAge(), lsa.lsaType(), key);
+                //add it to lsaQueue for processing
+                try {
+                    lsaQueue.put(lsa);
+                    //remove from bin
+                    lsaBin.removeOspfLsa((String) key, lsa);
+                } catch (InterruptedException e) {
+                    log.debug("Error::LSDBAge::maxAgeLsa::{}", e.getMessage());
+                }
+            }
+        }
+
+        //Get from maxAgeBin
+        Map lsaMaxAgeBinMap = maxAgeBin.listOfLsa();
+        for (Object key : lsaMaxAgeBinMap.keySet()) {
+            LsaWrapper lsa = (LsaWrapper) lsaMaxAgeBinMap.get((String) key);
+            lsa.setLsaProcessing(OspfParameters.MAXAGELSA);
+            log.debug("Lsa picked for maxage flooding. Age Counter: {}, LSA Type: {}, LSA Key: {}",
+                      ageCounter, lsa.lsaType(), key);
+            //add it to lsaQueue for processing
+            try {
+                lsaQueue.put(lsa);
+                //remove from bin
+                maxAgeBin.removeOspfLsa((String) key, lsa);
+            } catch (InterruptedException e) {
+                log.debug("Error::LSDBAge::maxAgeLsa::{}", e.getMessage());
+            }
+        }
+    }
+
+
+    /*
+     * If the LSA is in age bin of 1800 - it's pushed into refresh list.
+     */
+    public void refreshLsa() {
+        int binNumber;
+        if (ageCounter < OspfParameters.LSREFRESHTIME) {
+            binNumber = ageCounter + OspfParameters.LSREFRESHTIME;
+        } else {
+            binNumber = ageCounter - OspfParameters.LSREFRESHTIME;
+        }
+        LsaBin lsaBin = ageBins.get(binNumber);
+        if (lsaBin == null) {
+            return;
+        }
+        Map lsaBinMap = lsaBin.listOfLsa();
+        for (Object key : lsaBinMap.keySet()) {
+            LsaWrapper lsa = (LsaWrapper) lsaBinMap.get((String) key);
+            try {
+                if (lsa.isSelfOriginated()) {
+                    log.debug("Lsa picked for refreshLsa. binNumber: {}, LSA Type: {}, LSA Key: {}",
+                              binNumber, lsa.lsaType(), key);
+                    lsa.setLsaProcessing(OspfParameters.REFRESHLSA);
+                    lsaQueue.put(lsa);
+                    //remove from bin
+                    lsaBin.removeOspfLsa((String) key, lsa);
+                }
+            } catch (InterruptedException e) {
+                log.debug("Error::LSDBAge::refreshLsa::{}", e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * Verify the checksum for the LSAs who are in bins of 300 and it's multiples.
+     */
+    public void checkAges() {
+        //evry 5 min age counter + multiples of 300
+        for (int age = OspfParameters.CHECKAGE; age < OspfParameters.MAXAGE;
+             age += OspfParameters.CHECKAGE) {
+            LsaBin lsaBin = ageBins.get(age2Bin(age));
+            if (lsaBin == null) {
+                continue;
+            }
+            Map lsaBinMap = lsaBin.listOfLsa();
+            for (Object key : lsaBinMap.keySet()) {
+                LsaWrapper lsa = (LsaWrapper) lsaBinMap.get((String) key);
+                lsa.setLsaProcessing(OspfParameters.VERIFYCHECKSUM);
+                try {
+                    lsaQueue.put(lsa);
+                } catch (InterruptedException e) {
+                    log.debug("Error::LSDBAge::checkAges::{}", e.getMessage());
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Starts DB age timer method start the aging task.
+     */
+    private void startDbAgeTimer() {
+        log.debug("OSPFNbr::startWaitTimer");
+        dbAgeTimer = new InternalAgeTimer();
+        //from 1 sec
+        exServiceage = Executors.newSingleThreadScheduledExecutor();
+        exServiceage.scheduleAtFixedRate(dbAgeTimer, OspfParameters.AGECOUNTER,
+                                         OspfParameters.AGECOUNTER, TimeUnit.SECONDS);
+    }
+
+    /**
+     * Stops the aging task.
+     */
+    private void stopDbAgeTimer() {
+        log.debug("OSPFNbr::stopWaitTimer ");
+        exServiceage.shutdown();
+    }
+
+
+    /**
+     * Gets the netty channel.
+     *
+     * @return netty channel
+     */
+    public Channel getChannel() {
+        return channel;
+    }
+
+    /**
+     * Sets the netty channel.
+     *
+     * @param channel netty channel
+     */
+    public void setChannel(Channel channel) {
+
+        this.channel = channel;
+        if (queueConsumer != null) {
+            queueConsumer.setChannel(channel);
+        }
+    }
+
+    /**
+     * Gets the age counter.
+     *
+     * @return ageCounter
+     */
+    public int getAgeCounter() {
+        return ageCounter;
+    }
+
+    /**
+     * Gets the age counter roll over value.
+     *
+     * @return the age counter roll over value
+     */
+    public int getAgeCounterRollOver() {
+        return ageCounterRollOver;
+    }
+
+    /**
+     * Gets the max age bin.
+     *
+     * @return lsa bin instance
+     */
+    public LsaBin getMaxAgeBin() {
+        return maxAgeBin;
+    }
+
+    /**
+     * Gets the bin number.
+     *
+     * @param x Can be either age or ageCounter
+     * @return bin number.
+     */
+    public int age2Bin(int x) {
+        if (x <= ageCounter) {
+            return (ageCounter - x);
+        } else {
+            return ((OspfParameters.MAXAGE - 1) + (ageCounter - x));
+        }
+    }
+
+    /**
+     * Runnable task which runs every second and calls aging process.
+     */
+    private class InternalAgeTimer implements Runnable {
+
+        /**
+         * Constructor.
+         */
+        InternalAgeTimer() {
+            log.debug("Starts::LsdbAge::AgeTimer...!!! ");
+        }
+
+        @Override
+        public void run() {
+            ageLsaAndFlood();
+        }
+    }
+}
\ No newline at end of file
diff --git a/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/package-info.java b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/package-info.java
new file mode 100755
index 0000000..91ebbb5
--- /dev/null
+++ b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016 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.
+ */
+
+/**
+ * Implementation of the OSPF controller.
+ */
+package org.onosproject.ospf.controller;
\ No newline at end of file