| /* |
| * 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.IsisLsdbAge; |
| import org.onosproject.isis.controller.IsisLspBin; |
| 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.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 ISIS link state database ageing process. |
| */ |
| public class DefaultIsisLsdbAge implements IsisLsdbAge { |
| private static final Logger log = LoggerFactory.getLogger(DefaultIsisLsdbAge.class); |
| protected static int ageCounter = 0; |
| private InternalAgeTimer dbAgeTimer; |
| private ScheduledExecutorService exServiceage; |
| private Integer maxBins = 1200; |
| private Map<Integer, IsisLspBin> ageBins = new ConcurrentHashMap<>(maxBins); |
| private int ageCounterRollOver = 0; |
| private IsisLspQueueConsumer queueConsumer = null; |
| private BlockingQueue<LspWrapper> lsaQueue = new ArrayBlockingQueue<>(1024); |
| |
| /** |
| * Creates an instance of LSDB age. |
| */ |
| public DefaultIsisLsdbAge() { |
| // create LSBin's in the HashMap. |
| for (int i = 0; i < maxBins; i++) { |
| IsisLspBin lspBin = new DefaultIsisLspBin(i); |
| ageBins.put(i, lspBin); |
| } |
| } |
| |
| /** |
| * Returns age counter. |
| * |
| * @return age counter |
| */ |
| public int ageCounter() { |
| return ageCounter; |
| } |
| |
| /** |
| * Returns age counter roll over. |
| * |
| * @return age counter roll over |
| */ |
| public int ageCounterRollOver() { |
| |
| return ageCounterRollOver; |
| } |
| |
| /** |
| * Adds LSP to LS bin for ageing. |
| * |
| * @param binNumber key to store in bin |
| * @param lspBin LSP bin instance |
| */ |
| public void addLspBin(int binNumber, IsisLspBin lspBin) { |
| if (!ageBins.containsKey(binNumber)) { |
| ageBins.put(binNumber, lspBin); |
| } |
| } |
| |
| /** |
| * Returns LSP from Bin. |
| * |
| * @param binKey key |
| * @return bin instance |
| */ |
| public IsisLspBin getLspBin(int binKey) { |
| |
| return ageBins.get(binKey); |
| } |
| |
| /** |
| * Removes LSP from Bin. |
| * |
| * @param lspWrapper wrapper instance |
| */ |
| public void removeLspFromBin(LspWrapper lspWrapper) { |
| if (ageBins.containsKey(lspWrapper.binNumber())) { |
| IsisLspBin lsaBin = ageBins.get(lspWrapper.binNumber()); |
| lsaBin.removeIsisLsp(((LsPdu) lspWrapper.lsPdu()).lspId(), lspWrapper); |
| } |
| } |
| |
| /** |
| * Returns the bin number. |
| * |
| * @param age Can be either age or ageCounter |
| * @return bin number. |
| */ |
| public int age2Bin(int age) { |
| if (age <= ageCounter) { |
| return (ageCounter - age); |
| } else { |
| return ((IsisConstants.LSPMAXAGE - 1) + (ageCounter - age)); |
| } |
| } |
| |
| /** |
| * Starts the aging timer and queue consumer. |
| */ |
| public void startDbAging() { |
| startDbAgeTimer(); |
| queueConsumer = new IsisLspQueueConsumer(lsaQueue); |
| new Thread(queueConsumer).start(); |
| } |
| |
| /** |
| * Starts DB aging task. |
| */ |
| private void startDbAgeTimer() { |
| dbAgeTimer = new InternalAgeTimer(); |
| //from 1 sec |
| exServiceage = Executors.newSingleThreadScheduledExecutor(); |
| exServiceage.scheduleAtFixedRate(dbAgeTimer, 1, 1, TimeUnit.SECONDS); |
| } |
| |
| /** |
| * Gets called every second as part of the aging process. |
| */ |
| public void ageLsp() { |
| refreshLsa(); |
| maxAgeLsa(); |
| |
| if (ageCounter == IsisConstants.LSPMAXAGE) { |
| ageCounter = 0; |
| ageCounterRollOver++; |
| } else { |
| ageCounter++; |
| } |
| } |
| |
| /** |
| * If the LSP have completed the MaxAge - they are moved called stop aging. |
| */ |
| public void maxAgeLsa() { |
| if (ageCounter == 0) { |
| return; |
| } |
| //Get from Age Bins |
| IsisLspBin lspBin = ageBins.get(ageCounter - 1); |
| if (lspBin == null) { |
| return; |
| } |
| Map lspBinMap = lspBin.listOfLsp(); |
| for (Object key : lspBinMap.keySet()) { |
| LspWrapper lspWrapper = (LspWrapper) lspBinMap.get((String) key); |
| if (lspWrapper.currentAge() == IsisConstants.LSPMAXAGE) { |
| lspWrapper.setLspProcessing(IsisConstants.MAXAGELSP); |
| log.debug("Lsp picked for maxage removal. Age Counter: {}, AgeCounterRollover: {}, " + |
| "AgeCounterRollover WhenAddedToDb: {}, LSA Type: {}, LSA Key: {}", |
| ageCounter, ageCounterRollOver, lspWrapper.currentAge(), |
| lspWrapper.lsPdu().isisPduType(), key); |
| //add it to lspQueue for processing |
| try { |
| lsaQueue.put(lspWrapper); |
| //remove from bin |
| lspBin.removeIsisLsp((String) key, lspWrapper); |
| } catch (InterruptedException e) { |
| log.debug("Error::LSDBAge::maxAgeLsp::{}", e.getMessage()); |
| } |
| } |
| } |
| |
| } |
| |
| /* |
| * If the LSP is in age bin of 900s- it's pushed into refresh list. |
| */ |
| public void refreshLsa() { |
| int binNumber; |
| if (ageCounter < IsisConstants.LSPREFRESH) { |
| binNumber = ageCounter + IsisConstants.LSPREFRESH; |
| } else { |
| binNumber = ageCounter - IsisConstants.LSPREFRESH; |
| } |
| if (binNumber > IsisConstants.LSPMAXAGE) { |
| binNumber = binNumber - IsisConstants.LSPMAXAGE; |
| } |
| IsisLspBin lspBin = ageBins.get(binNumber); |
| if (lspBin == null) { |
| return; |
| } |
| Map lspBinMap = lspBin.listOfLsp(); |
| for (Object key : lspBinMap.keySet()) { |
| LspWrapper lsp = (LspWrapper) lspBinMap.get((String) key); |
| try { |
| if (lsp.isSelfOriginated()) { |
| log.debug("Lsp picked for refreshLsp. binNumber: {}, LSA Type: {}, LSA Key: {}", |
| binNumber, lsp.lspType(), key); |
| lsp.setLspProcessing(IsisConstants.REFRESHLSP); |
| lsaQueue.put(lsp); |
| //remove from bin |
| lspBin.removeIsisLsp((String) key, lsp); |
| } |
| } catch (InterruptedException e) { |
| log.debug("Error::LSDBAge::refreshLsp::{}", e.getMessage()); |
| } |
| } |
| } |
| |
| |
| /** |
| * Runnable task which runs every second and calls aging process. |
| */ |
| private class InternalAgeTimer implements Runnable { |
| |
| /** |
| * Creates an instance of age timer task. |
| */ |
| InternalAgeTimer() { |
| log.debug("Starts::IsisLsdbAge::AgeTimer...!!! "); |
| } |
| |
| @Override |
| public void run() { |
| ageLsp(); |
| } |
| } |
| } |