/* * 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.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.OspfInterface; import org.onosproject.ospf.controller.OspfLsaType; import org.onosproject.ospf.controller.OspfLsdb; import org.onosproject.ospf.controller.area.OspfAreaImpl; import org.onosproject.ospf.protocol.lsa.LsaHeader; import org.onosproject.ospf.protocol.lsa.OpaqueLsaHeader; import org.onosproject.ospf.protocol.util.OspfParameters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; /** * Represents the Link State Database. */ public class OspfLsdbImpl implements OspfLsdb { private static final Logger log = LoggerFactory.getLogger(OspfLsdbImpl.class); private Map routerLsas = new HashMap(); private Map networkLsas = new HashMap(); private Map summaryLsas = new HashMap(); private Map asbrSummaryLSAs = new HashMap(); private Map opaque9Lsas = new HashMap(); private Map opaque10Lsas = new HashMap(); private Map opaque11Lsas = new HashMap(); private Map externalLsas = new HashMap(); private long routerLsaSeqNo = OspfParameters.STARTLSSEQUENCENUM; private long networkLsaSeqNo = OspfParameters.STARTLSSEQUENCENUM; private LsdbAge lsdbAge = null; private OspfArea ospfArea = null; /** * Creates an instance of OSPF LSDB. * * @param ospfArea area instance */ public OspfLsdbImpl(OspfArea ospfArea) { this.ospfArea = ospfArea; lsdbAge = new LsdbAgeImpl(ospfArea); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } OspfLsdbImpl that = (OspfLsdbImpl) o; return Objects.equal(routerLsas.size(), that.routerLsas.size()) && Objects.equal(networkLsas.size(), that.networkLsas.size()) && Objects.equal(summaryLsas.size(), that.summaryLsas.size()) && Objects.equal(asbrSummaryLSAs.size(), that.asbrSummaryLSAs.size()) && Objects.equal(lsdbAge, that.lsdbAge) && Objects.equal(routerLsaSeqNo, that.routerLsaSeqNo) && Objects.equal(networkLsaSeqNo, that.networkLsaSeqNo); } @Override public int hashCode() { return Objects.hashCode(routerLsas, networkLsas, summaryLsas, asbrSummaryLSAs, lsdbAge, routerLsaSeqNo, networkLsaSeqNo); } /** * Initializes the link state database. */ public void initializeDb() { lsdbAge.startDbAging(); } /** * Returns all LSA Headers (Router and Summary) in a Vector. * * @param excludeMaxAgeLsa exclude the max age LSAs * @param isOpaqueCapable is opaque capable or not * @return List of LSA headers */ public List getAllLsaHeaders(boolean excludeMaxAgeLsa, boolean isOpaqueCapable) { List summList = new CopyOnWriteArrayList(); addLsaToHeaderList(summList, excludeMaxAgeLsa, routerLsas); addLsaToHeaderList(summList, excludeMaxAgeLsa, networkLsas); addLsaToHeaderList(summList, excludeMaxAgeLsa, summaryLsas); addLsaToHeaderList(summList, excludeMaxAgeLsa, asbrSummaryLSAs); addLsaToHeaderList(summList, excludeMaxAgeLsa, externalLsas); if (isOpaqueCapable) { addLsaToHeaderList(summList, excludeMaxAgeLsa, opaque9Lsas); addLsaToHeaderList(summList, excludeMaxAgeLsa, opaque10Lsas); addLsaToHeaderList(summList, excludeMaxAgeLsa, opaque11Lsas); } return summList; } /** * Adds the LSAs to summary list. * * @param summList summary list * @param excludeMaxAgeLsa exclude max age LSA * @param lsaMap map of LSA */ private void addLsaToHeaderList(List summList, boolean excludeMaxAgeLsa, Map lsaMap) { Iterator slotVals = lsaMap.values().iterator(); while (slotVals.hasNext()) { LsaWrapper wrapper = (LsaWrapper) slotVals.next(); if (excludeMaxAgeLsa) { //if current age of lsa is max age or lsa present in Max Age bin if (wrapper.currentAge() != OspfParameters.MAXAGE && lsdbAge.getMaxAgeBin().ospfLsa(((OspfAreaImpl) ospfArea).getLsaKey(((LsaWrapperImpl) wrapper).lsaHeader())) == null) { addToList(wrapper, summList); } } else { addToList(wrapper, summList); } } } /** * Adds the LSWrapper to summary list. * * @param wrapper LSA wrapper instance * @param summList LSA summary list */ private void addToList(LsaWrapper wrapper, List summList) { LsaHeader header = (LsaHeader) wrapper.ospfLsa(); //set the current age header.setAge(wrapper.currentAge()); summList.add(header); } /** * Gets the LSDB LSA key from Lsa Header. * * @param lsaHeader LSA header instance * @return key */ public String getLsaKey(LsaHeader lsaHeader) { String lsaKey = ""; switch (lsaHeader.lsType()) { case OspfParameters.LINK_LOCAL_OPAQUE_LSA: case OspfParameters.AREA_LOCAL_OPAQUE_LSA: case OspfParameters.AS_OPAQUE_LSA: OpaqueLsaHeader header = (OpaqueLsaHeader) lsaHeader; lsaKey = lsaHeader.lsType() + "-" + header.opaqueType() + header.opaqueId() + "-" + lsaHeader.advertisingRouter(); break; case OspfParameters.ROUTER: case OspfParameters.NETWORK: case OspfParameters.ASBR_SUMMARY: case OspfParameters.SUMMARY: case OspfParameters.EXTERNAL_LSA: lsaKey = lsaHeader.lsType() + "-" + lsaHeader.linkStateId() + "-" + lsaHeader.advertisingRouter(); break; default: log.debug("Unknown LSA type..!!!"); break; } return lsaKey; } /** * Gets wrapper instance in LSDB. * * @param lsaHeader LSA header instance. * @return LSA Wrapper instance. */ public LsaWrapper lsaLookup(LsaHeader lsaHeader) { return findLsa(lsaHeader.lsType(), getLsaKey(lsaHeader)); } /** * Finds the LSA from appropriate maps. * * @param lsType type of LSA * @param lsaKey key * @return LSA wrapper object */ public LsaWrapper findLsa(int lsType, String lsaKey) { LsaWrapper lsaWrapper = null; switch (lsType) { case OspfParameters.LINK_LOCAL_OPAQUE_LSA: lsaWrapper = (LsaWrapper) opaque9Lsas.get(lsaKey); break; case OspfParameters.AREA_LOCAL_OPAQUE_LSA: lsaWrapper = (LsaWrapper) opaque10Lsas.get(lsaKey); break; case OspfParameters.AS_OPAQUE_LSA: lsaWrapper = (LsaWrapper) opaque11Lsas.get(lsaKey); break; case OspfParameters.ROUTER: lsaWrapper = (LsaWrapper) routerLsas.get(lsaKey); break; case OspfParameters.NETWORK: lsaWrapper = (LsaWrapper) networkLsas.get(lsaKey); break; case OspfParameters.ASBR_SUMMARY: lsaWrapper = (LsaWrapper) asbrSummaryLSAs.get(lsaKey); break; case OspfParameters.SUMMARY: lsaWrapper = (LsaWrapper) summaryLsas.get(lsaKey); break; case OspfParameters.EXTERNAL_LSA: lsaWrapper = (LsaWrapper) externalLsas.get(lsaKey); break; default: log.debug("Unknown LSA type..!!!"); break; } //set the current age if (lsaWrapper != null) { //set the current age ((LsaWrapperImpl) lsaWrapper).lsaHeader().setAge(lsaWrapper.currentAge()); ((LsaHeader) lsaWrapper.ospfLsa()).setAge(lsaWrapper.currentAge()); } return lsaWrapper; } /** * Installs a new self-originated LSA if possible. * Return true if installing was successful else false. * * @param newLsa LSA header instance * @param isSelfOriginated is self originated or not * @param ospfInterface OSPF interface instance * @return true if successfully added */ public boolean addLsa(LsaHeader newLsa, boolean isSelfOriginated, OspfInterface ospfInterface) { LsaWrapperImpl lsaWrapper = new LsaWrapperImpl(); lsaWrapper.setLsaType(newLsa.getOspfLsaType()); lsaWrapper.setOspfLsa(newLsa); lsaWrapper.setLsaHeader(newLsa); lsaWrapper.setLsaAgeReceived(newLsa.age()); lsaWrapper.setAgeCounterWhenReceived(lsdbAge.getAgeCounter()); lsaWrapper.setAgeCounterRollOverWhenAdded(lsdbAge.getAgeCounterRollOver()); lsaWrapper.setIsSelfOriginated(isSelfOriginated); lsaWrapper.setIsSelfOriginated(isSelfOriginated); lsaWrapper.setOspfInterface(ospfInterface); lsaWrapper.setLsdbAge(lsdbAge); addLsa(lsaWrapper); log.debug("Added LSA In LSDB: {}", newLsa); return true; } /** * Installs a new self-originated LSA if possible. * Return true if installing was successful else false. * Adding LSA In cases * 1) New Self Originated LSA based on change in topology * 2) New Self Originated LSA because of LSRefresh * 2) New LSA received via Link State Update Packet * * @param newLsa LSA wrapper instance * @return true if added successfully */ private boolean addLsa(LsaWrapper newLsa) { // adding an LSA - verify if it's old or new // verify min failed // to verify if it's a new LSA or updating the old LSA . // fetch the LSA Type // verify if the LSA age is ! Max Age // a) it is received during the flooding process (Section 13) // b) it is originated by the router itself (Section 12.4) // start aging . String key = getLsaKey(((LsaWrapperImpl) newLsa).lsaHeader()); //Remove the lsa from bin if exist. we will be adding it in new bin based on the current age. removeLsaFromBin(lsaLookup(((LsaWrapperImpl) newLsa).lsaHeader())); switch (((LsaWrapperImpl) newLsa).lsaHeader().lsType()) { case OspfParameters.LINK_LOCAL_OPAQUE_LSA: opaque9Lsas.put(key, newLsa); break; case OspfParameters.AREA_LOCAL_OPAQUE_LSA: opaque10Lsas.put(key, newLsa); break; case OspfParameters.AS_OPAQUE_LSA: opaque11Lsas.put(key, newLsa); break; case OspfParameters.ROUTER: routerLsas.put(key, newLsa); break; case OspfParameters.NETWORK: networkLsas.put(key, newLsa); break; case OspfParameters.ASBR_SUMMARY: asbrSummaryLSAs.put(key, newLsa); break; case OspfParameters.SUMMARY: summaryLsas.put(key, newLsa); break; case OspfParameters.EXTERNAL_LSA: externalLsas.put(key, newLsa); break; default: log.debug("Unknown LSA type to add..!!!"); break; } //add it to bin Integer binNumber = lsdbAge.age2Bin(((LsaWrapperImpl) newLsa).lsaHeader().age()); LsaBin lsaBin = lsdbAge.getLsaBin(binNumber); if (lsaBin != null) { //remove from existing newLsa.setBinNumber(binNumber); lsaBin.addOspfLsa(key, newLsa); lsdbAge.addLsaBin(binNumber, lsaBin); log.debug("Added Type {} LSA to LSDB and LSABin[{}], Age of LSA {}", newLsa.lsaType(), binNumber, ((LsaWrapperImpl) newLsa).lsaHeader().age()); } return false; } /** * Adds the LSA to maxAge bin. * * @param key key * @param wrapper LSA wrapper instance */ public void addLsaToMaxAgeBin(String key, Object wrapper) { lsdbAge.addLsaToMaxAgeBin(key, (LsaWrapper) wrapper); } /** * Removes LSA from Bin. * * @param lsaWrapper LSA wrapper instance */ public void removeLsaFromBin(Object lsaWrapper) { if (lsaWrapper != null) { lsdbAge.removeLsaFromBin((LsaWrapper) lsaWrapper); } } /** * RFC 2328 - Section 13.1. Determining which LSA is newer. * * @param lsa1 LSA instance * @param lsa2 LSA instance * @return string status */ public String isNewerOrSameLsa(LsaHeader lsa1, LsaHeader lsa2) { if (lsa1.lsSequenceNo() > lsa2.lsSequenceNo()) { return "latest"; } else if (lsa1.lsSequenceNo() < lsa2.lsSequenceNo()) { return "old"; } else if (lsa1.lsSequenceNo() == lsa2.lsSequenceNo()) { if (lsa1.lsCheckSum() > lsa2.lsCheckSum()) { return "latest"; } else if (lsa1.lsCheckSum() < lsa2.lsCheckSum()) { return "old"; } else if (lsa1.lsCheckSum() == lsa2.lsCheckSum()) { if (lsa1.age() == lsa2.age()) { return "same"; } else if (lsa1.age() == OspfParameters.MAXAGE) { return "latest"; } else if (lsa2.age() == OspfParameters.MAXAGE) { return "old"; } else if (OspfParameters.MAXAGEDIFF == (lsa1.age() - lsa2.age())) { if (lsa1.age() < lsa2.age()) { return "latest"; } else { return "old"; } } else { return "same"; } } } return ""; } /** * Gets the sequence number. * * @param lsaType type of LSA * @return sequence number */ public long getLsSequenceNumber(OspfLsaType lsaType) { switch (lsaType) { case ROUTER: return routerLsaSeqNo++; case NETWORK: return networkLsaSeqNo++; default: return OspfParameters.STARTLSSEQUENCENUM; } } /** * Deletes the given LSA. * * @param lsaHeader LSA header instance */ public void deleteLsa(LsaHeader lsaHeader) { String lsaKey = getLsaKey(lsaHeader); switch (lsaHeader.lsType()) { case OspfParameters.LINK_LOCAL_OPAQUE_LSA: opaque9Lsas.remove(lsaKey); break; case OspfParameters.AREA_LOCAL_OPAQUE_LSA: opaque10Lsas.remove(lsaKey); break; case OspfParameters.AS_OPAQUE_LSA: opaque11Lsas.remove(lsaKey); break; case OspfParameters.ROUTER: routerLsas.remove(lsaKey); break; case OspfParameters.NETWORK: networkLsas.remove(lsaKey); break; case OspfParameters.ASBR_SUMMARY: asbrSummaryLSAs.remove(lsaKey); break; case OspfParameters.SUMMARY: summaryLsas.remove(lsaKey); break; case OspfParameters.EXTERNAL_LSA: externalLsas.remove(lsaKey); break; default: log.debug("Unknown LSA type to delete..!!!"); break; } } /** * Sets sequence number. * * @param routerLsaSeqNo sequence number */ public void setRouterLsaSeqNo(long routerLsaSeqNo) { this.routerLsaSeqNo = routerLsaSeqNo; } /** * Sets sequence number. * * @param networkLsaSeqNo sequence number */ public void setNetworkLsaSeqNo(long networkLsaSeqNo) { this.networkLsaSeqNo = networkLsaSeqNo; } }