| /* |
| * 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.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 static 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(); |
| } |
| } |
| } |