ONOS-4086 to ONOS-4091, ONOS-4098 to ONOS-4100:ISIS controller implementation

Change-Id: I7be52805652fe762baf808515401d6b5042b2aa5
diff --git a/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/lsdb/DefaultIsisLsdb.java b/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/lsdb/DefaultIsisLsdb.java
new file mode 100755
index 0000000..33a0a17
--- /dev/null
+++ b/protocols/isis/ctl/src/main/java/org/onosproject/isis/controller/impl/lsdb/DefaultIsisLsdb.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.isis.controller.impl.lsdb;
+
+import org.onosproject.isis.controller.IsisInterface;
+import org.onosproject.isis.controller.IsisLsdb;
+import org.onosproject.isis.controller.IsisLsdbAge;
+import org.onosproject.isis.controller.IsisLspBin;
+import org.onosproject.isis.controller.IsisMessage;
+import org.onosproject.isis.controller.IsisPduType;
+import org.onosproject.isis.controller.LspWrapper;
+import org.onosproject.isis.io.isispacket.pdu.LsPdu;
+import org.onosproject.isis.io.util.IsisConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Representation of ISIS link state database.
+ */
+public class DefaultIsisLsdb implements IsisLsdb {
+    private static final Logger log = LoggerFactory.getLogger(DefaultIsisLsdb.class);
+    private Map<String, LspWrapper> isisL1Db = new ConcurrentHashMap<>();
+    private Map<String, LspWrapper> isisL2Db = new ConcurrentHashMap<>();
+    private IsisLsdbAge lsdbAge = null;
+    private int l1LspSeqNo = IsisConstants.STARTLSSEQUENCENUM;
+    private int l2LspSeqNo = IsisConstants.STARTLSSEQUENCENUM;
+
+    /**
+     * Creates an instance of ISIS LSDB.
+     */
+    public DefaultIsisLsdb() {
+        lsdbAge = new DefaultIsisLsdbAge();
+    }
+
+    /**
+     * Initializes the link state database.
+     */
+    public void initializeDb() {
+        lsdbAge.startDbAging();
+    }
+
+    /**
+     * Returns the LSDB LSP key.
+     *
+     * @param systemId system ID
+     * @return key
+     */
+    public String lspKey(String systemId) {
+        StringBuilder lspKey = new StringBuilder();
+        lspKey.append(systemId);
+        lspKey.append(".00");
+        lspKey.append("-");
+        lspKey.append("00");
+
+        return lspKey.toString();
+    }
+
+    /**
+     * Returns the neighbor L1 database information.
+     *
+     * @return neighbor L1 database information
+     */
+    public Map<String, LspWrapper> getL1Db() {
+        return isisL1Db;
+    }
+
+    /**
+     * Returns the neighbor L2 database information.
+     *
+     * @return neighbor L2 database information
+     */
+    public Map<String, LspWrapper> getL2Db() {
+        return isisL2Db;
+    }
+
+    /**
+     * Returns the LSDB instance.
+     *
+     * @return LSDB instance
+     */
+    public IsisLsdb isisLsdb() {
+        return this;
+    }
+
+    /**
+     * Returns all LSPs (L1 and L2).
+     *
+     * @param excludeMaxAgeLsp exclude the max age LSPs
+     * @return List of LSPs
+     */
+    public List<LspWrapper> allLspHeaders(boolean excludeMaxAgeLsp) {
+        List<LspWrapper> summaryList = new CopyOnWriteArrayList();
+        addLspToHeaderList(summaryList, excludeMaxAgeLsp, isisL1Db);
+        addLspToHeaderList(summaryList, excludeMaxAgeLsp, isisL2Db);
+
+        return summaryList;
+    }
+
+    /**
+     * Adds the LSPs to summary list.
+     *
+     * @param summaryList      summary list
+     * @param excludeMaxAgeLsp exclude max age LSP
+     * @param lspMap           map of LSP
+     */
+    private void addLspToHeaderList(List summaryList, boolean excludeMaxAgeLsp, Map lspMap) {
+        Iterator slotVals = lspMap.values().iterator();
+        while (slotVals.hasNext()) {
+            LspWrapper wrapper = (LspWrapper) slotVals.next();
+            if (excludeMaxAgeLsp) {
+                //if current age of lsa is max age or lsa present in Max Age bin
+                if (wrapper.remainingLifetime() != 0) {
+                    addToList(wrapper, summaryList);
+                }
+            } else {
+                addToList(wrapper, summaryList);
+            }
+        }
+    }
+
+    /**
+     * Adds the LSPWrapper to summary list.
+     *
+     * @param wrapper  LSP wrapper instance
+     * @param summList LSP summary list
+     */
+    private void addToList(LspWrapper wrapper, List summList) {
+        //set the current age
+        ((LsPdu) wrapper.lsPdu()).setRemainingLifeTime(wrapper.remainingLifetime());
+        summList.add(wrapper);
+    }
+
+    /**
+     * Finds the LSP from appropriate maps L1 or L2 based on type.
+     *
+     * @param pduType L1 or L2 LSP
+     * @param lspId   LSP ID
+     * @return LSP wrapper object
+     */
+    public LspWrapper findLsp(IsisPduType pduType, String lspId) {
+        LspWrapper lspWrapper = null;
+
+        switch (pduType) {
+            case L1LSPDU:
+                lspWrapper = isisL1Db.get(lspId);
+                break;
+            case L2LSPDU:
+                lspWrapper = isisL2Db.get(lspId);
+                break;
+            default:
+                log.debug("Unknown LSP type..!!!");
+                break;
+        }
+
+        //set the current age
+        if (lspWrapper != null) {
+            //set the current age
+            ((DefaultLspWrapper) lspWrapper).lsPdu().setRemainingLifeTime(lspWrapper.remainingLifetime());
+        }
+
+        return lspWrapper;
+    }
+
+    /**
+     * Installs a new self-originated LSP.
+     *
+     * @return true if successfully added
+     */
+    public boolean addLsp(IsisMessage isisMessage, boolean isSelfOriginated, IsisInterface isisInterface) {
+        LsPdu lspdu = (LsPdu) isisMessage;
+        DefaultLspWrapper lspWrapper = new DefaultLspWrapper();
+        lspWrapper.setLspAgeReceived(IsisConstants.LSPMAXAGE - lspdu.remainingLifeTime());
+        lspWrapper.setRemainingLifetime(IsisConstants.LSPMAXAGE - lsdbAge.ageCounter());
+        lspWrapper.setLspType(IsisPduType.get(lspdu.pduType()));
+        lspWrapper.setLsPdu(lspdu);
+        lspWrapper.setAgeCounterWhenReceived(lsdbAge.ageCounter());
+        lspWrapper.setAgeCounterRollOverWhenAdded(lsdbAge.ageCounterRollOver());
+        lspWrapper.setSelfOriginated(isSelfOriginated);
+        lspWrapper.setIsisInterface(isisInterface);
+        lspWrapper.setLsdbAge(lsdbAge);
+        addLsp(lspWrapper, lspdu.lspId());
+
+        log.debug("Added LSp In LSDB: {}", lspWrapper);
+
+        return true;
+    }
+
+    /**
+     * Adds the LSP to L1 or L2 database.
+     *
+     * @param lspWrapper LSA wrapper instance
+     * @param key        key
+     * @return True if added else false
+     */
+    private boolean addLsp(LspWrapper lspWrapper, String key) {
+        //Remove the lsa from bin if exist.
+        removeLspFromBin(lspWrapper);
+
+        switch (lspWrapper.lsPdu().isisPduType()) {
+            case L1LSPDU:
+                isisL1Db.put(key, lspWrapper);
+                break;
+            case L2LSPDU:
+                isisL2Db.put(key, lspWrapper);
+                break;
+            default:
+                log.debug("Unknown LSP type to add..!!!");
+                break;
+        }
+
+        //add it to bin
+        Integer binNumber = lsdbAge.age2Bin(IsisConstants.LSPMAXAGE - lspWrapper.remainingLifetime());
+        IsisLspBin lspBin = lsdbAge.getLspBin(binNumber);
+        if (lspBin != null) {
+            //remove from existing
+            lspWrapper.setBinNumber(binNumber);
+            lspBin.addIsisLsp(key, lspWrapper);
+            lsdbAge.addLspBin(binNumber, lspBin);
+            log.debug("Added Type {} LSP to LSDB and LSABin[{}], Remaining life time of LSA {}",
+                      lspWrapper.lsPdu().isisPduType(),
+                      binNumber, lspWrapper.remainingLifetime());
+        }
+
+        return false;
+    }
+
+    /**
+     * Removes LSP from Bin.
+     *
+     * @param lsaWrapper LSP wrapper instance
+     */
+    public void removeLspFromBin(LspWrapper lsaWrapper) {
+        if (lsaWrapper != null) {
+            lsdbAge.removeLspFromBin(lsaWrapper);
+        }
+    }
+
+    /**
+     * Returns new ,latest or old according to the type of ISIS message received.
+     *
+     * @param lsp1 LSP instance
+     * @param lsp2 LSP instance
+     * @return string status
+     */
+    public String isNewerOrSameLsp(IsisMessage lsp1, IsisMessage lsp2) {
+        LsPdu receivedLsp = (LsPdu) lsp1;
+        LsPdu lspFromDb = (LsPdu) lsp2;
+        if (receivedLsp.sequenceNumber() > lspFromDb.sequenceNumber()) {
+            return "latest";
+        } else if (receivedLsp.sequenceNumber() < lspFromDb.sequenceNumber()) {
+            return "old";
+        } else if (receivedLsp.sequenceNumber() == lspFromDb.sequenceNumber()) {
+            return "same";
+        }
+
+        return "";
+    }
+
+    /**
+     * Returns the sequence number.
+     *
+     * @param lspType type of LSP
+     * @return sequence number
+     */
+    public int lsSequenceNumber(IsisPduType lspType) {
+        switch (lspType) {
+            case L1LSPDU:
+                return l1LspSeqNo++;
+            case L2LSPDU:
+                return l2LspSeqNo++;
+            default:
+                return IsisConstants.STARTLSSEQUENCENUM;
+        }
+    }
+
+    /**
+     * Deletes the given LSP.
+     *
+     * @param lspMessage LSP instance
+     */
+    public void deleteLsp(IsisMessage lspMessage) {
+        LsPdu lsp = (LsPdu) lspMessage;
+        String lspKey = lsp.lspId();
+        switch (lsp.isisPduType()) {
+            case L1LSPDU:
+                isisL1Db.remove(lspKey);
+                break;
+            case L2LSPDU:
+                isisL2Db.remove(lspKey);
+                break;
+            default:
+                log.debug("Unknown LSP type to remove..!!!");
+                break;
+        }
+    }
+}
\ No newline at end of file