blob: 3df627ddf5d267c5b09db023d3c11ffecc4c8a67 [file] [log] [blame]
/*
* 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.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;
}
}