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

Change-Id: I592453c21440afa5240c74dc4e9e134f876c89b3
diff --git a/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/area/OspfAreaImpl.java b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/area/OspfAreaImpl.java
new file mode 100755
index 0000000..2c33ed5
--- /dev/null
+++ b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/area/OspfAreaImpl.java
@@ -0,0 +1,803 @@
+/*
+ * 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.area;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import org.onlab.packet.Ip4Address;
+import org.onosproject.ospf.controller.LsaWrapper;
+import org.onosproject.ospf.controller.OspfArea;
+import org.onosproject.ospf.controller.OspfAreaAddressRange;
+import org.onosproject.ospf.controller.OspfInterface;
+import org.onosproject.ospf.controller.OspfLsa;
+import org.onosproject.ospf.controller.OspfLsaType;
+import org.onosproject.ospf.controller.OspfLsdb;
+import org.onosproject.ospf.controller.OspfNbr;
+import org.onosproject.ospf.controller.OspfNeighborState;
+import org.onosproject.ospf.controller.impl.OspfNbrImpl;
+import org.onosproject.ospf.controller.lsdb.OspfLsdbImpl;
+import org.onosproject.ospf.protocol.lsa.LsaHeader;
+import org.onosproject.ospf.protocol.lsa.subtypes.OspfLsaLink;
+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.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Representation an OSPF area and related information.
+ */
+public class OspfAreaImpl implements OspfArea {
+    private static final Logger log = LoggerFactory.getLogger(OspfAreaImpl.class);
+    /**
+     * Address ranges in order to aggregate routing information at area.
+     * boundaries. Each address range is specified by an [address,mask] pair and
+     * a status indication of either Advertise or DoNotAdvertise
+     */
+    private List<OspfAreaAddressRange> addressRanges;
+    /**
+     * This parameter indicates whether the area can carry data traffic that.
+     * neither originates nor terminates in the area itself.
+     */
+    private boolean transitCapability;
+    /**
+     * Whether AS-external-LSAs will be flooded into/throughout the area.
+     */
+    private boolean externalRoutingCapability;
+    /**
+     * Indicates the cost of the default summary-LSA.
+     */
+    private int stubCost;
+    /**
+     * Represents a list of all router's interfaces associated with this area.
+     */
+    private List<OspfInterface> interfacesLst;
+    /**
+     * The LS Database for this area. It includes router-LSAs, network-LSAs and.
+     * summary-LSAs. AS-external-LSAs are hold in the OSPF class itself.
+     */
+    private OspfLsdbImpl database;
+    /**
+     * A 32-bit number identifying the area.
+     */
+    private Ip4Address areaId;
+    /**
+     * Router ID.
+     */
+    private Ip4Address routerId;
+    /**
+     * Represents Options like external, opaque capabilities.
+     */
+    private int options;
+    /**
+     * Represents Opaque Enable or not.
+     */
+    private boolean isOpaqueEnable;
+
+    /**
+     * Creates an instance of area implementation.
+     */
+    public OspfAreaImpl() {
+        database = new OspfLsdbImpl(this);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        OspfAreaImpl that = (OspfAreaImpl) o;
+        return Objects.equal(areaId, that.areaId) &&
+                Objects.equal(routerId, that.routerId) &&
+                Objects.equal(addressRanges.size(), that.addressRanges.size()) &&
+                Objects.equal(transitCapability, that.transitCapability) &&
+                Objects.equal(externalRoutingCapability, that.externalRoutingCapability) &&
+                Objects.equal(stubCost, that.stubCost) &&
+                Objects.equal(interfacesLst.size(), that.interfacesLst.size()) &&
+                Objects.equal(database, that.database);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(areaId, routerId, addressRanges, transitCapability, externalRoutingCapability,
+                                stubCost, interfacesLst, database);
+    }
+
+    /**
+     * Gets the router id.
+     *
+     * @return router id
+     */
+    public Ip4Address routerId() {
+        return routerId;
+    }
+
+    /**
+     * Sets the router id.
+     *
+     * @param routerId router id
+     */
+    @JsonProperty("routerId")
+    public void setRouterId(Ip4Address routerId) {
+        this.routerId = routerId;
+    }
+
+    /**
+     * Sets opaque enabled to true or false.
+     *
+     * @param isOpaqueEnable true if opaque enabled else false
+     */
+    @JsonProperty("isOpaqueEnable")
+    public void setIsOpaqueEnabled(boolean isOpaqueEnable) {
+        this.isOpaqueEnable = isOpaqueEnable;
+    }
+
+    /**
+     * Gets is opaque enabled or not.
+     *
+     * @return true if opaque enabled else false
+     */
+    public boolean isOpaqueEnabled() {
+        return this.isOpaqueEnable;
+    }
+
+    /**
+     * Initializes link state database.
+     */
+    public void initializeDb() {
+
+        database.initializeDb();
+    }
+
+    /**
+     * Refreshes the OSPF area information .
+     * Gets called as soon as the interface is down or neighbor full Router LSA is updated.
+     *
+     * @param ospfInterface OSPF interface instance
+     */
+    @Override
+    public void refreshArea(OspfInterface ospfInterface) {
+        OspfInterfaceImpl ospfInterfaceImpl = (OspfInterfaceImpl) ospfInterface;
+        log.debug("Inside refreshArea...!!!");
+        //If interface state is DR build network LSA.
+        if (ospfInterfaceImpl.state() == OspfInterfaceState.DR) {
+            if (ospfInterface.listOfNeighbors().size() > 0) {
+                //Get the NetworkLsa
+                NetworkLsa networkLsa = null;
+                try {
+                    networkLsa = buildNetworkLsa(ospfInterface.ipAddress(), ospfInterface.ipNetworkMask());
+                } catch (Exception e) {
+                    log.debug("Error while building NetworkLsa {}", e.getMessage());
+                }
+                //Add the NetworkLsa to lsdb
+                database.addLsa(networkLsa, true, ospfInterface);
+                addToOtherNeighborLsaTxList(networkLsa);
+            } else {
+                log.debug("No Neighbors hence not creating  NetworkLSA...!!!");
+            }
+        }
+        //Get the router LSA
+        RouterLsa routerLsa = null;
+        try {
+            routerLsa = buildRouterLsa(ospfInterface);
+        } catch (Exception e) {
+            log.debug("Error while building RouterLsa {}", e.getMessage());
+        }
+        //Add the RouterLSA to lsdb
+        database.addLsa(routerLsa, true, ospfInterface);
+        addToOtherNeighborLsaTxList(routerLsa);
+    }
+
+    /**
+     * Builds a network LSA.
+     *
+     * @param interfaceIp interface IP address
+     * @param mask        interface network mask
+     * @return NetworkLsa instance
+     * @throws Exception might throws exception
+     */
+    public NetworkLsa buildNetworkLsa(Ip4Address interfaceIp, Ip4Address mask) throws Exception {
+        // generate the Router-LSA for this Area.
+        NetworkLsa networkLsa = new NetworkLsa();
+        networkLsa.setAdvertisingRouter(routerId);
+        networkLsa.setLinkStateId(interfaceIp.toString());
+        networkLsa.setLsType(OspfLsaType.NETWORK.value());
+        networkLsa.setAge(1);
+        networkLsa.setOptions(2);
+        networkLsa.setNetworkMask(mask);
+        //Adding our own router.
+        networkLsa.addAttachedRouter(routerId());
+        Iterator iter = interfacesLst.iterator();
+        OspfInterfaceImpl ospfInterface = null;
+        while (iter.hasNext()) {
+            ospfInterface = (OspfInterfaceImpl) iter.next();
+            if (ospfInterface.ipAddress().equals(interfaceIp)) {
+                break;
+            }
+        }
+        if (ospfInterface != null) {
+            List<OspfNbr> neighborsInFullState = getNeighborsInFullState(ospfInterface);
+            if (neighborsInFullState != null) {
+                for (OspfNbr ospfnbr : neighborsInFullState) {
+                    networkLsa.addAttachedRouter(ospfnbr.neighborId());
+                    log.debug("Adding attached neighbor:: {}", ospfnbr.neighborId());
+                }
+            }
+        }
+        networkLsa.setLsSequenceNo(database.getLsSequenceNumber(OspfLsaType.NETWORK));
+        //Find the byte length and add it in lsa object
+        ChecksumCalculator checksum = new ChecksumCalculator();
+        byte[] lsaBytes = networkLsa.asBytes();
+        networkLsa.setLsPacketLen(lsaBytes.length);
+        //Convert lsa object to byte again to reflect the packet length which we added.
+        lsaBytes = networkLsa.asBytes();
+        //find the checksum
+        byte[] twoByteChecksum = checksum.calculateLsaChecksum(lsaBytes,
+                                                               OspfUtil.LSAPACKET_CHECKSUM_POS1,
+                                                               OspfUtil.LSAPACKET_CHECKSUM_POS2);
+        int checkSumVal = OspfUtil.byteToInteger(twoByteChecksum);
+        networkLsa.setLsCheckSum(checkSumVal);
+        return networkLsa;
+    }
+
+    /**
+     * Builds Router LSA.
+     *
+     * @param ospfInterface Interface instance
+     * @return routerLsa Router LSA instance
+     * @throws Exception might throws exception
+     */
+    public RouterLsa buildRouterLsa(OspfInterface ospfInterface) throws Exception {
+        // generate the Router-LSA for this Area.
+        RouterLsa routerLsa = new RouterLsa();
+        routerLsa.setAdvertisingRouter(routerId);
+        routerLsa.setLinkStateId(routerId.toString());
+        routerLsa.setLsType(OspfLsaType.ROUTER.value());
+        routerLsa.setAge(1);
+        routerLsa.setOptions(options);
+        routerLsa.setAreaBorderRouter(false);
+        routerLsa.setAsBoundaryRouter(false);
+        routerLsa.setVirtualEndPoint(false);
+        buildLinkForRouterLsa(routerLsa, ospfInterface);
+        routerLsa.setLsSequenceNo(database.getLsSequenceNumber(OspfLsaType.ROUTER));
+        //Find the byte length and add it in lsa object
+        ChecksumCalculator checksum = new ChecksumCalculator();
+        byte[] lsaBytes = routerLsa.asBytes();
+        routerLsa.setLsPacketLen(lsaBytes.length);
+        //Convert lsa object to byte again to reflect the packet length whic we added.
+        lsaBytes = routerLsa.asBytes();
+        //find the checksum
+        byte[] twoByteChecksum = checksum.calculateLsaChecksum(lsaBytes,
+                                                               OspfUtil.LSAPACKET_CHECKSUM_POS1,
+                                                               OspfUtil.LSAPACKET_CHECKSUM_POS2);
+        int checkSumVal = OspfUtil.byteToInteger(twoByteChecksum);
+        routerLsa.setLsCheckSum(checkSumVal);
+        return routerLsa;
+    }
+
+    /**
+     * Builds LSA link for router LSA.
+     *
+     * @param routerLsa     router LSA instance
+     * @param ospfInterface interface instance
+     */
+    private void buildLinkForRouterLsa(RouterLsa routerLsa, OspfInterface ospfInterface) {
+        OspfInterfaceImpl nextInterface;
+        Iterator interfaces = interfacesLst.iterator();
+        while (interfaces.hasNext()) {
+            nextInterface = (OspfInterfaceImpl) interfaces.next();
+            if (nextInterface.state() == OspfInterfaceState.DOWN) {
+                continue;
+            } else if (nextInterface.state() == OspfInterfaceState.LOOPBACK) {
+                OspfLsaLink link = new OspfLsaLink();
+                link.setLinkData("-1");
+                link.setLinkId(nextInterface.ipAddress().toString());
+                link.setLinkType(3);
+                link.setMetric(0);
+                link.setTos(0);
+                routerLsa.addRouterLink(link);
+                routerLsa.incrementLinkNo();
+            } else if (nextInterface.state() == OspfInterfaceState.POINT2POINT) {
+                // adding all neighbour routers
+                List<OspfNbr> neighborsInFullState = getNeighborsInFullState(nextInterface);
+                if (neighborsInFullState != null) {
+                    log.debug("Adding OspfLsaLink ::neighborsInFullState {}, InterfaceIP: {}",
+                              neighborsInFullState.size(), nextInterface.ipAddress());
+                    for (OspfNbr ospfnbr : neighborsInFullState) {
+                        OspfLsaLink link = new OspfLsaLink();
+                        link.setLinkData(nextInterface.ipAddress().toString());
+                        link.setLinkId(ospfnbr.neighborId().toString());
+                        link.setLinkType(1);
+                        link.setMetric(0);
+                        link.setTos(0);
+                        routerLsa.addRouterLink(link);
+                        routerLsa.incrementLinkNo();
+                        log.debug("Added OspfLsaLink :: {}, neighborIP: {}, routerLinks: {}",
+                                  ospfnbr.neighborId(), ospfnbr.neighborIpAddr(), routerLsa.noLink());
+                    }
+                }
+                // adding the self address
+                OspfLsaLink link = new OspfLsaLink();
+                link.setLinkData(nextInterface.ipNetworkMask().toString());
+                link.setLinkId(nextInterface.ipAddress().toString());
+                link.setLinkType(3);
+                link.setMetric(0);
+                link.setTos(0);
+                routerLsa.addRouterLink(link);
+                routerLsa.incrementLinkNo();
+            } else {
+                buildLinkForRouterLsaBroadcast(routerLsa, nextInterface);
+            }
+        }
+    }
+
+    /**
+     * Builds LSA link for router LSA.
+     *
+     * @param routerLsa     router LSA instance
+     * @param ospfInterface interface instance
+     */
+    private void buildLinkForRouterLsaBroadcast(RouterLsa routerLsa, OspfInterface ospfInterface) {
+        OspfInterfaceImpl ospfInterfaceImpl = (OspfInterfaceImpl) ospfInterface;
+        if (ospfInterfaceImpl.state() == OspfInterfaceState.WAITING) {
+            OspfLsaLink link = new OspfLsaLink();
+            link.setLinkData(ospfInterface.ipNetworkMask().toString());
+            //Link id should be set to ip network number
+            link.setLinkId(ospfInterface.ipAddress().toString());
+            link.setLinkType(3);
+            link.setMetric(0);
+            link.setTos(0);
+            routerLsa.addRouterLink(link);
+            routerLsa.incrementLinkNo();
+        } else if (ospfInterfaceImpl.state() == OspfInterfaceState.DR) {
+            OspfLsaLink link = new OspfLsaLink();
+            link.setLinkData(ospfInterface.ipAddress().toString());
+            link.setLinkId(ospfInterface.ipAddress().toString());
+            link.setLinkType(2);
+            link.setMetric(0);
+            link.setTos(0);
+            routerLsa.addRouterLink(link);
+            routerLsa.incrementLinkNo();
+        } else if (ospfInterfaceImpl.state() == OspfInterfaceState.BDR ||
+                ospfInterfaceImpl.state() == OspfInterfaceState.DROTHER) {
+            OspfLsaLink link = new OspfLsaLink();
+            link.setLinkData(ospfInterface.ipAddress().toString());
+            link.setLinkId(ospfInterface.dr().toString());
+            link.setLinkType(2);
+            link.setMetric(0);
+            link.setTos(0);
+            routerLsa.addRouterLink(link);
+            routerLsa.incrementLinkNo();
+        }
+    }
+
+    /**
+     * Gets the area id.
+     *
+     * @return area id
+     */
+    public Ip4Address areaId() {
+        return areaId;
+    }
+
+    /**
+     * Sets the area id.
+     *
+     * @param areaId area id
+     */
+    @JsonProperty("areaId")
+    public void setAreaId(Ip4Address areaId) {
+        this.areaId = areaId;
+    }
+
+    /**
+     * Gets address range.
+     *
+     * @return list of area address ranges
+     */
+    public List<OspfAreaAddressRange> addressRanges() {
+        return addressRanges;
+    }
+
+    /**
+     * Sets the area address ranges.
+     *
+     * @param addressRanges list of area address range
+     */
+    @JsonProperty("addressRange")
+    public void setAddressRanges(List<OspfAreaAddressRange> addressRanges) {
+        this.addressRanges = addressRanges;
+    }
+
+    /**
+     * Gets is transit capable or not.
+     *
+     * @return true if transit capable, else false
+     */
+    public boolean isTransitCapability() {
+        return transitCapability;
+    }
+
+    /**
+     * Sets transit capability.
+     *
+     * @param transitCapability true if transit capable, else false
+     */
+    @JsonProperty("transitCapability")
+    public void setTransitCapability(boolean transitCapability) {
+        this.transitCapability = transitCapability;
+    }
+
+    /**
+     * Gets external routing capability.
+     *
+     * @return true if external routing capable, else false
+     */
+    public boolean isExternalRoutingCapability() {
+        return externalRoutingCapability;
+    }
+
+    /**
+     * Sets external routing capability.
+     *
+     * @param externalRoutingCapability true if external routing capable, else false
+     */
+    @JsonProperty("externalRoutingCapability")
+    public void setExternalRoutingCapability(boolean externalRoutingCapability) {
+        this.externalRoutingCapability = externalRoutingCapability;
+    }
+
+    /**
+     * Gets the stub cost.
+     *
+     * @return stub cost
+     */
+    public int stubCost() {
+        return stubCost;
+    }
+
+    /**
+     * Sets the stub cost.
+     *
+     * @param stubCost stub cost
+     */
+    @JsonProperty("stubCost")
+    public void setStubCost(int stubCost) {
+        this.stubCost = stubCost;
+    }
+
+    /**
+     * Gets the list of interfaces in this area.
+     *
+     * @return list of interfaces
+     */
+    public List<OspfInterface> getInterfacesLst() {
+        return interfacesLst;
+    }
+
+    /**
+     * Sets the list of interfaces attached to the area.
+     *
+     * @param interfacesLst list of OspfInterface instances
+     */
+    @JsonProperty("interface")
+    public void setInterfacesLst(List<OspfInterface> interfacesLst) {
+        this.interfacesLst = interfacesLst;
+    }
+
+    /**
+     * Checks all neighbors belonging to this area whether they are in state EXCHANGE or LOADING.
+     * Return false if there is at least one, else return true. This Method is used by
+     * "processReceivedLsa()" in the neighbor class.
+     *
+     * @return boolean indicating that there is no Neighbor in Database Exchange
+     */
+    public boolean noNeighborInLsaExchangeProcess() {
+        OspfInterfaceImpl nextInterface;
+        OspfNeighborState nextNeighborState;
+        Iterator interfaces = interfacesLst.iterator();
+        while (interfaces.hasNext()) {
+            nextInterface = (OspfInterfaceImpl) interfaces.next();
+            Iterator neighbors = nextInterface.listOfNeighbors().values().iterator();
+            while (neighbors.hasNext()) {
+                nextNeighborState = ((OspfNbrImpl) neighbors.next()).getState();
+                if (nextNeighborState == OspfNeighborState.EXCHANGE ||
+                        nextNeighborState == OspfNeighborState.LOADING) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Gets header of all types of LSAs.
+     *
+     * @param excludeMaxAgeLsa need to include(true) or exclude(false) maxage lsa's
+     * @param isOpaquecapable  need to include(true) or exclude(false) Type 10 Opaque lsa's
+     * @return list of lsa header in the lsdb
+     */
+    public List getLsaHeaders(boolean excludeMaxAgeLsa, boolean isOpaquecapable) {
+        return database.getAllLsaHeaders(excludeMaxAgeLsa, isOpaquecapable);
+    }
+
+    /**
+     * Gets the LSA from LSDB based on the input.
+     *
+     * @param lsType            type of lsa to form the key
+     * @param linkStateID       link state id to form the key
+     * @param advertisingRouter advertising router to form the key
+     * @return lsa wrapper instance which contains the Lsa
+     * @throws Exception might throws exception
+     */
+    public LsaWrapper getLsa(int lsType, String linkStateID, String advertisingRouter) throws Exception {
+        String lsaKey = lsType + "-" + linkStateID + "-" + advertisingRouter;
+        if (lsType == OspfParameters.LINK_LOCAL_OPAQUE_LSA || lsType == OspfParameters.AREA_LOCAL_OPAQUE_LSA ||
+                lsType == OspfParameters.AS_OPAQUE_LSA) {
+            byte[] linkStateAsBytes = InetAddress.getByName(linkStateID).getAddress();
+            int opaqueType = linkStateAsBytes[0];
+            int opaqueId = OspfUtil.byteToInteger(Arrays.copyOfRange(linkStateAsBytes, 1,
+                                                                     linkStateAsBytes.length));
+            lsaKey = lsType + "-" + opaqueType + opaqueId + "-" + advertisingRouter;
+        }
+        return database.findLsa(lsType, lsaKey);
+    }
+
+
+    /**
+     * Checks whether an instance of the given LSA exists in the database belonging to this area.
+     * If so return true else false.
+     *
+     * @param lookupLsa ospf LSA instance to lookup
+     * @return LSA wrapper instance which contains the Lsa
+     */
+    public LsaWrapper lsaLookup(OspfLsa lookupLsa) {
+        return database.lsaLookup((LsaHeader) lookupLsa);
+    }
+
+    /**
+     * Checks whether an instance of the given LSA exists in the database belonging to this area.
+     * If so return true else false.
+     *
+     * @param lsa1 OSPF LSA instance to compare
+     * @param lsa2 OSPF LSA instance to compare
+     * @return "same" if both instances are same, "latest" if lsa1 is latest, or "old" if lsa1 is old
+     */
+    public String isNewerOrSameLsa(OspfLsa lsa1, OspfLsa lsa2) {
+        return database.isNewerOrSameLsa((LsaHeader) lsa1, (LsaHeader) lsa2);
+    }
+
+    /**
+     * Methods gets called from ChannelHandler to add the received LSA to LSDB.
+     *
+     * @param ospfLsa       OSPF LSA instance
+     * @param ospfInterface OSPF interface instance
+     */
+    public void addLsa(OspfLsa ospfLsa, OspfInterface ospfInterface) throws Exception {
+        //second param is false as lsa from network
+        database.addLsa((LsaHeader) ospfLsa, false, ospfInterface);
+    }
+
+    /**
+     * Methods gets called from ChannelHandler to add the received LSA to LSDB.
+     *
+     * @param ospfLsa          OSPF LSA instance
+     * @param isSelfOriginated true if the LSA is self originated. Else false
+     * @param ospfInterface    OSPF interface instance
+     */
+    public void addLsa(OspfLsa ospfLsa, boolean isSelfOriginated, OspfInterface ospfInterface)
+            throws Exception {
+        database.addLsa((LsaHeader) ospfLsa, isSelfOriginated, ospfInterface);
+    }
+
+    /**
+     * Adds the LSA to maxAge bin.
+     *
+     * @param key     key to add it to LSDB
+     * @param wrapper LSA wrapper instance
+     */
+    public void addLsaToMaxAgeBin(String key, LsaWrapper wrapper) {
+        database.addLsaToMaxAgeBin(key, wrapper);
+    }
+
+    /**
+     * Sets router sequence number for router LSA.
+     *
+     * @param newSequenceNumber sequence number
+     */
+    public void setDbRouterSequenceNumber(long newSequenceNumber) {
+        database.setRouterLsaSeqNo(newSequenceNumber);
+    }
+
+    /**
+     * Methods gets called from ChannelHandler to delete the LSA.
+     *
+     * @param ospfLsa the LSA instance to delete
+     */
+    public void deleteLsa(LsaHeader ospfLsa) {
+        database.deleteLsa(ospfLsa);
+    }
+
+    /**
+     * Removes LSA from bin.
+     *
+     * @param lsaWrapper the LSA wrapper instance to delete
+     */
+    public void removeLsaFromBin(LsaWrapper lsaWrapper) {
+        database.removeLsaFromBin(lsaWrapper);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .omitNullValues()
+                .add("areaID", areaId)
+                .add("stubCost", stubCost)
+                .add("addressRanges", addressRanges)
+                .add("interfacesLst", interfacesLst)
+                .add("transitCapability", transitCapability)
+                .add("externalRoutingCapability", externalRoutingCapability)
+                .toString();
+    }
+
+    /**
+     * Checks all Neighbors belonging to this Area whether they are in state lesser than the EXCHANGE.
+     * <p>
+     * Creates list of such neighbors
+     * <p>
+     * Returns list of neighbors who satisfy the conditions
+     *
+     * @param ospfInterface OSPF interface instance
+     * @return List of interfaces having state lesser than exchange
+     */
+    public List<OspfNbr> getNeighborsInFullState(OspfInterface ospfInterface) {
+
+        List<OspfNbr> listEligibleNeighbors = null;
+        OspfNbrImpl ospfNeighbor = null;
+        OspfNeighborState nextNeighborState;
+        Iterator nbrInterface = ospfInterface.listOfNeighbors().values().iterator();
+        while (nbrInterface.hasNext()) {
+            ospfNeighbor = (OspfNbrImpl) nbrInterface.next();
+            nextNeighborState = ospfNeighbor.getState();
+            if (nextNeighborState.getValue() == OspfNeighborState.FULL.getValue()) {
+                if (listEligibleNeighbors == null) {
+                    listEligibleNeighbors = new ArrayList<OspfNbr>();
+                    listEligibleNeighbors.add(ospfNeighbor);
+                } else {
+                    listEligibleNeighbors.add(ospfNeighbor);
+                }
+            }
+        }
+        return listEligibleNeighbors;
+    }
+
+    /**
+     * Gets the LSDB LSA key from LSA header.
+     *
+     * @param lsaHeader LSA header instance
+     * @return key LSA key
+     */
+    public String getLsaKey(LsaHeader lsaHeader) {
+        return database.getLsaKey(lsaHeader);
+    }
+
+    /**
+     * Adds the received LSA in other neighbors tx list.
+     *
+     * @param recLsa LSA Header instance
+     */
+    public void addToOtherNeighborLsaTxList(LsaHeader recLsa) {
+        //Add the received LSA in other neighbors retransmission list.
+        log.debug("OspfAreaImpl: addToOtherNeighborLsaTxList");
+        List<OspfInterface> ospfInterfaces = getInterfacesLst();
+        for (OspfInterface ospfInterfaceFromArea : ospfInterfaces) {
+            Map neighbors = ospfInterfaceFromArea.listOfNeighbors();
+            for (Object neighborIP : neighbors.keySet()) {
+                OspfNbrImpl nbr = (OspfNbrImpl) neighbors.get(neighborIP);
+                if (nbr.getState().getValue() < OspfNeighborState.EXCHANGE.getValue()) {
+                    continue;
+                }
+                String key = database.getLsaKey(recLsa);
+                if (nbr.getState() == OspfNeighborState.EXCHANGE || nbr.getState() == OspfNeighborState.LOADING) {
+                    if (nbr.getLsReqList().containsKey(key)) {
+                        LsaWrapper lsWrapper = lsaLookup(recLsa);
+                        if (lsWrapper != null) {
+                            LsaHeader ownLSA = (LsaHeader) lsWrapper.ospfLsa();
+                            String status = isNewerOrSameLsa(recLsa, ownLSA);
+                            if (status.equals("old")) {
+                                continue;
+                            } else if (status.equals("same")) {
+                                log.debug("OspfAreaImpl: addToOtherNeighborLsaTxList: " +
+                                                  "Removing lsa from reTxtList {}", key);
+                                nbr.getLsReqList().remove(key);
+                                continue;
+                            } else {
+                                log.debug("OspfAreaImpl: addToOtherNeighborLsaTxList: " +
+                                                  "Removing lsa from reTxtList {}", key);
+                                nbr.getLsReqList().remove(key);
+                            }
+                        }
+                    }
+                }
+                if (recLsa.advertisingRouter().equals((String) neighborIP)) {
+                    continue;
+                }
+                if ((recLsa.lsType() == OspfParameters.LINK_LOCAL_OPAQUE_LSA ||
+                        recLsa.lsType() == OspfParameters.AREA_LOCAL_OPAQUE_LSA)) {
+                    if (nbr.isOpaqueCapable()) {
+                        log.debug("OspfAreaImpl: addToOtherNeighborLsaTxList: Adding lsa to reTxtList {}",
+                                  recLsa);
+                        nbr.getReTxList().put(key, recLsa);
+                    }
+                } else {
+                    log.debug("OspfAreaImpl: addToOtherNeighborLsaTxList: Adding lsa to reTxtList {}",
+                              recLsa);
+                    nbr.getReTxList().put(key, recLsa);
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the options value.
+     *
+     * @return options value
+     */
+    public int options() {
+        return options;
+    }
+
+    /**
+     * Sets the options value.
+     *
+     * @param options options value
+     */
+    public void setOptions(int options) {
+        this.options = options;
+    }
+
+    /**
+     * Gets the opaque enabled options value.
+     *
+     * @return opaque enabled options value
+     */
+    public int opaqueEnabledOptions() {
+        return Integer.parseInt(OspfParameters.OPAQUE_ENABLED_OPTION_VALUE, 2);
+    }
+
+    /**
+     * Gets the lsdb instance for this area.
+     *
+     * @return lsdb instance
+     */
+    public OspfLsdb database() {
+        return database;
+    }
+}
\ No newline at end of file