Kiran Ramachandra
Committed by Thomas Vachuska

ONOS-2740,ONOS-2741,from ONOS-3032 - to ONOS 3071 , OSPF Protocol Implementation

Change-Id: I592453c21440afa5240c74dc4e9e134f876c89b3
/*
* Copyright 2016 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.area;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import org.onlab.packet.Ip4Address;
import org.onosproject.ospf.controller.LsaWrapper;
import org.onosproject.ospf.controller.OspfArea;
import org.onosproject.ospf.controller.OspfAreaAddressRange;
import org.onosproject.ospf.controller.OspfInterface;
import org.onosproject.ospf.controller.OspfLsa;
import org.onosproject.ospf.controller.OspfLsaType;
import org.onosproject.ospf.controller.OspfLsdb;
import org.onosproject.ospf.controller.OspfNbr;
import org.onosproject.ospf.controller.OspfNeighborState;
import org.onosproject.ospf.controller.impl.OspfNbrImpl;
import org.onosproject.ospf.controller.lsdb.OspfLsdbImpl;
import org.onosproject.ospf.protocol.lsa.LsaHeader;
import org.onosproject.ospf.protocol.lsa.subtypes.OspfLsaLink;
import org.onosproject.ospf.protocol.lsa.types.NetworkLsa;
import org.onosproject.ospf.protocol.lsa.types.RouterLsa;
import org.onosproject.ospf.protocol.util.ChecksumCalculator;
import org.onosproject.ospf.protocol.util.OspfInterfaceState;
import org.onosproject.ospf.protocol.util.OspfParameters;
import org.onosproject.ospf.protocol.util.OspfUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Representation an OSPF area and related information.
*/
public class OspfAreaImpl implements OspfArea {
private static final Logger log = LoggerFactory.getLogger(OspfAreaImpl.class);
/**
* Address ranges in order to aggregate routing information at area.
* boundaries. Each address range is specified by an [address,mask] pair and
* a status indication of either Advertise or DoNotAdvertise
*/
private List<OspfAreaAddressRange> addressRanges;
/**
* This parameter indicates whether the area can carry data traffic that.
* neither originates nor terminates in the area itself.
*/
private boolean transitCapability;
/**
* Whether AS-external-LSAs will be flooded into/throughout the area.
*/
private boolean externalRoutingCapability;
/**
* Indicates the cost of the default summary-LSA.
*/
private int stubCost;
/**
* Represents a list of all router's interfaces associated with this area.
*/
private List<OspfInterface> interfacesLst;
/**
* The LS Database for this area. It includes router-LSAs, network-LSAs and.
* summary-LSAs. AS-external-LSAs are hold in the OSPF class itself.
*/
private OspfLsdbImpl database;
/**
* A 32-bit number identifying the area.
*/
private Ip4Address areaId;
/**
* Router ID.
*/
private Ip4Address routerId;
/**
* Represents Options like external, opaque capabilities.
*/
private int options;
/**
* Represents Opaque Enable or not.
*/
private boolean isOpaqueEnable;
/**
* Creates an instance of area implementation.
*/
public OspfAreaImpl() {
database = new OspfLsdbImpl(this);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
OspfAreaImpl that = (OspfAreaImpl) o;
return Objects.equal(areaId, that.areaId) &&
Objects.equal(routerId, that.routerId) &&
Objects.equal(addressRanges.size(), that.addressRanges.size()) &&
Objects.equal(transitCapability, that.transitCapability) &&
Objects.equal(externalRoutingCapability, that.externalRoutingCapability) &&
Objects.equal(stubCost, that.stubCost) &&
Objects.equal(interfacesLst.size(), that.interfacesLst.size()) &&
Objects.equal(database, that.database);
}
@Override
public int hashCode() {
return Objects.hashCode(areaId, routerId, addressRanges, transitCapability, externalRoutingCapability,
stubCost, interfacesLst, database);
}
/**
* Gets the router id.
*
* @return router id
*/
public Ip4Address routerId() {
return routerId;
}
/**
* Sets the router id.
*
* @param routerId router id
*/
@JsonProperty("routerId")
public void setRouterId(Ip4Address routerId) {
this.routerId = routerId;
}
/**
* Sets opaque enabled to true or false.
*
* @param isOpaqueEnable true if opaque enabled else false
*/
@JsonProperty("isOpaqueEnable")
public void setIsOpaqueEnabled(boolean isOpaqueEnable) {
this.isOpaqueEnable = isOpaqueEnable;
}
/**
* Gets is opaque enabled or not.
*
* @return true if opaque enabled else false
*/
public boolean isOpaqueEnabled() {
return this.isOpaqueEnable;
}
/**
* Initializes link state database.
*/
public void initializeDb() {
database.initializeDb();
}
/**
* Refreshes the OSPF area information .
* Gets called as soon as the interface is down or neighbor full Router LSA is updated.
*
* @param ospfInterface OSPF interface instance
*/
@Override
public void refreshArea(OspfInterface ospfInterface) {
OspfInterfaceImpl ospfInterfaceImpl = (OspfInterfaceImpl) ospfInterface;
log.debug("Inside refreshArea...!!!");
//If interface state is DR build network LSA.
if (ospfInterfaceImpl.state() == OspfInterfaceState.DR) {
if (ospfInterface.listOfNeighbors().size() > 0) {
//Get the NetworkLsa
NetworkLsa networkLsa = null;
try {
networkLsa = buildNetworkLsa(ospfInterface.ipAddress(), ospfInterface.ipNetworkMask());
} catch (Exception e) {
log.debug("Error while building NetworkLsa {}", e.getMessage());
}
//Add the NetworkLsa to lsdb
database.addLsa(networkLsa, true, ospfInterface);
addToOtherNeighborLsaTxList(networkLsa);
} else {
log.debug("No Neighbors hence not creating NetworkLSA...!!!");
}
}
//Get the router LSA
RouterLsa routerLsa = null;
try {
routerLsa = buildRouterLsa(ospfInterface);
} catch (Exception e) {
log.debug("Error while building RouterLsa {}", e.getMessage());
}
//Add the RouterLSA to lsdb
database.addLsa(routerLsa, true, ospfInterface);
addToOtherNeighborLsaTxList(routerLsa);
}
/**
* Builds a network LSA.
*
* @param interfaceIp interface IP address
* @param mask interface network mask
* @return NetworkLsa instance
* @throws Exception might throws exception
*/
public NetworkLsa buildNetworkLsa(Ip4Address interfaceIp, Ip4Address mask) throws Exception {
// generate the Router-LSA for this Area.
NetworkLsa networkLsa = new NetworkLsa();
networkLsa.setAdvertisingRouter(routerId);
networkLsa.setLinkStateId(interfaceIp.toString());
networkLsa.setLsType(OspfLsaType.NETWORK.value());
networkLsa.setAge(1);
networkLsa.setOptions(2);
networkLsa.setNetworkMask(mask);
//Adding our own router.
networkLsa.addAttachedRouter(routerId());
Iterator iter = interfacesLst.iterator();
OspfInterfaceImpl ospfInterface = null;
while (iter.hasNext()) {
ospfInterface = (OspfInterfaceImpl) iter.next();
if (ospfInterface.ipAddress().equals(interfaceIp)) {
break;
}
}
if (ospfInterface != null) {
List<OspfNbr> neighborsInFullState = getNeighborsInFullState(ospfInterface);
if (neighborsInFullState != null) {
for (OspfNbr ospfnbr : neighborsInFullState) {
networkLsa.addAttachedRouter(ospfnbr.neighborId());
log.debug("Adding attached neighbor:: {}", ospfnbr.neighborId());
}
}
}
networkLsa.setLsSequenceNo(database.getLsSequenceNumber(OspfLsaType.NETWORK));
//Find the byte length and add it in lsa object
ChecksumCalculator checksum = new ChecksumCalculator();
byte[] lsaBytes = networkLsa.asBytes();
networkLsa.setLsPacketLen(lsaBytes.length);
//Convert lsa object to byte again to reflect the packet length which we added.
lsaBytes = networkLsa.asBytes();
//find the checksum
byte[] twoByteChecksum = checksum.calculateLsaChecksum(lsaBytes,
OspfUtil.LSAPACKET_CHECKSUM_POS1,
OspfUtil.LSAPACKET_CHECKSUM_POS2);
int checkSumVal = OspfUtil.byteToInteger(twoByteChecksum);
networkLsa.setLsCheckSum(checkSumVal);
return networkLsa;
}
/**
* Builds Router LSA.
*
* @param ospfInterface Interface instance
* @return routerLsa Router LSA instance
* @throws Exception might throws exception
*/
public RouterLsa buildRouterLsa(OspfInterface ospfInterface) throws Exception {
// generate the Router-LSA for this Area.
RouterLsa routerLsa = new RouterLsa();
routerLsa.setAdvertisingRouter(routerId);
routerLsa.setLinkStateId(routerId.toString());
routerLsa.setLsType(OspfLsaType.ROUTER.value());
routerLsa.setAge(1);
routerLsa.setOptions(options);
routerLsa.setAreaBorderRouter(false);
routerLsa.setAsBoundaryRouter(false);
routerLsa.setVirtualEndPoint(false);
buildLinkForRouterLsa(routerLsa, ospfInterface);
routerLsa.setLsSequenceNo(database.getLsSequenceNumber(OspfLsaType.ROUTER));
//Find the byte length and add it in lsa object
ChecksumCalculator checksum = new ChecksumCalculator();
byte[] lsaBytes = routerLsa.asBytes();
routerLsa.setLsPacketLen(lsaBytes.length);
//Convert lsa object to byte again to reflect the packet length whic we added.
lsaBytes = routerLsa.asBytes();
//find the checksum
byte[] twoByteChecksum = checksum.calculateLsaChecksum(lsaBytes,
OspfUtil.LSAPACKET_CHECKSUM_POS1,
OspfUtil.LSAPACKET_CHECKSUM_POS2);
int checkSumVal = OspfUtil.byteToInteger(twoByteChecksum);
routerLsa.setLsCheckSum(checkSumVal);
return routerLsa;
}
/**
* Builds LSA link for router LSA.
*
* @param routerLsa router LSA instance
* @param ospfInterface interface instance
*/
private void buildLinkForRouterLsa(RouterLsa routerLsa, OspfInterface ospfInterface) {
OspfInterfaceImpl nextInterface;
Iterator interfaces = interfacesLst.iterator();
while (interfaces.hasNext()) {
nextInterface = (OspfInterfaceImpl) interfaces.next();
if (nextInterface.state() == OspfInterfaceState.DOWN) {
continue;
} else if (nextInterface.state() == OspfInterfaceState.LOOPBACK) {
OspfLsaLink link = new OspfLsaLink();
link.setLinkData("-1");
link.setLinkId(nextInterface.ipAddress().toString());
link.setLinkType(3);
link.setMetric(0);
link.setTos(0);
routerLsa.addRouterLink(link);
routerLsa.incrementLinkNo();
} else if (nextInterface.state() == OspfInterfaceState.POINT2POINT) {
// adding all neighbour routers
List<OspfNbr> neighborsInFullState = getNeighborsInFullState(nextInterface);
if (neighborsInFullState != null) {
log.debug("Adding OspfLsaLink ::neighborsInFullState {}, InterfaceIP: {}",
neighborsInFullState.size(), nextInterface.ipAddress());
for (OspfNbr ospfnbr : neighborsInFullState) {
OspfLsaLink link = new OspfLsaLink();
link.setLinkData(nextInterface.ipAddress().toString());
link.setLinkId(ospfnbr.neighborId().toString());
link.setLinkType(1);
link.setMetric(0);
link.setTos(0);
routerLsa.addRouterLink(link);
routerLsa.incrementLinkNo();
log.debug("Added OspfLsaLink :: {}, neighborIP: {}, routerLinks: {}",
ospfnbr.neighborId(), ospfnbr.neighborIpAddr(), routerLsa.noLink());
}
}
// adding the self address
OspfLsaLink link = new OspfLsaLink();
link.setLinkData(nextInterface.ipNetworkMask().toString());
link.setLinkId(nextInterface.ipAddress().toString());
link.setLinkType(3);
link.setMetric(0);
link.setTos(0);
routerLsa.addRouterLink(link);
routerLsa.incrementLinkNo();
} else {
buildLinkForRouterLsaBroadcast(routerLsa, nextInterface);
}
}
}
/**
* Builds LSA link for router LSA.
*
* @param routerLsa router LSA instance
* @param ospfInterface interface instance
*/
private void buildLinkForRouterLsaBroadcast(RouterLsa routerLsa, OspfInterface ospfInterface) {
OspfInterfaceImpl ospfInterfaceImpl = (OspfInterfaceImpl) ospfInterface;
if (ospfInterfaceImpl.state() == OspfInterfaceState.WAITING) {
OspfLsaLink link = new OspfLsaLink();
link.setLinkData(ospfInterface.ipNetworkMask().toString());
//Link id should be set to ip network number
link.setLinkId(ospfInterface.ipAddress().toString());
link.setLinkType(3);
link.setMetric(0);
link.setTos(0);
routerLsa.addRouterLink(link);
routerLsa.incrementLinkNo();
} else if (ospfInterfaceImpl.state() == OspfInterfaceState.DR) {
OspfLsaLink link = new OspfLsaLink();
link.setLinkData(ospfInterface.ipAddress().toString());
link.setLinkId(ospfInterface.ipAddress().toString());
link.setLinkType(2);
link.setMetric(0);
link.setTos(0);
routerLsa.addRouterLink(link);
routerLsa.incrementLinkNo();
} else if (ospfInterfaceImpl.state() == OspfInterfaceState.BDR ||
ospfInterfaceImpl.state() == OspfInterfaceState.DROTHER) {
OspfLsaLink link = new OspfLsaLink();
link.setLinkData(ospfInterface.ipAddress().toString());
link.setLinkId(ospfInterface.dr().toString());
link.setLinkType(2);
link.setMetric(0);
link.setTos(0);
routerLsa.addRouterLink(link);
routerLsa.incrementLinkNo();
}
}
/**
* Gets the area id.
*
* @return area id
*/
public Ip4Address areaId() {
return areaId;
}
/**
* Sets the area id.
*
* @param areaId area id
*/
@JsonProperty("areaId")
public void setAreaId(Ip4Address areaId) {
this.areaId = areaId;
}
/**
* Gets address range.
*
* @return list of area address ranges
*/
public List<OspfAreaAddressRange> addressRanges() {
return addressRanges;
}
/**
* Sets the area address ranges.
*
* @param addressRanges list of area address range
*/
@JsonProperty("addressRange")
public void setAddressRanges(List<OspfAreaAddressRange> addressRanges) {
this.addressRanges = addressRanges;
}
/**
* Gets is transit capable or not.
*
* @return true if transit capable, else false
*/
public boolean isTransitCapability() {
return transitCapability;
}
/**
* Sets transit capability.
*
* @param transitCapability true if transit capable, else false
*/
@JsonProperty("transitCapability")
public void setTransitCapability(boolean transitCapability) {
this.transitCapability = transitCapability;
}
/**
* Gets external routing capability.
*
* @return true if external routing capable, else false
*/
public boolean isExternalRoutingCapability() {
return externalRoutingCapability;
}
/**
* Sets external routing capability.
*
* @param externalRoutingCapability true if external routing capable, else false
*/
@JsonProperty("externalRoutingCapability")
public void setExternalRoutingCapability(boolean externalRoutingCapability) {
this.externalRoutingCapability = externalRoutingCapability;
}
/**
* Gets the stub cost.
*
* @return stub cost
*/
public int stubCost() {
return stubCost;
}
/**
* Sets the stub cost.
*
* @param stubCost stub cost
*/
@JsonProperty("stubCost")
public void setStubCost(int stubCost) {
this.stubCost = stubCost;
}
/**
* Gets the list of interfaces in this area.
*
* @return list of interfaces
*/
public List<OspfInterface> getInterfacesLst() {
return interfacesLst;
}
/**
* Sets the list of interfaces attached to the area.
*
* @param interfacesLst list of OspfInterface instances
*/
@JsonProperty("interface")
public void setInterfacesLst(List<OspfInterface> interfacesLst) {
this.interfacesLst = interfacesLst;
}
/**
* Checks all neighbors belonging to this area whether they are in state EXCHANGE or LOADING.
* Return false if there is at least one, else return true. This Method is used by
* "processReceivedLsa()" in the neighbor class.
*
* @return boolean indicating that there is no Neighbor in Database Exchange
*/
public boolean noNeighborInLsaExchangeProcess() {
OspfInterfaceImpl nextInterface;
OspfNeighborState nextNeighborState;
Iterator interfaces = interfacesLst.iterator();
while (interfaces.hasNext()) {
nextInterface = (OspfInterfaceImpl) interfaces.next();
Iterator neighbors = nextInterface.listOfNeighbors().values().iterator();
while (neighbors.hasNext()) {
nextNeighborState = ((OspfNbrImpl) neighbors.next()).getState();
if (nextNeighborState == OspfNeighborState.EXCHANGE ||
nextNeighborState == OspfNeighborState.LOADING) {
return false;
}
}
}
return true;
}
/**
* Gets header of all types of LSAs.
*
* @param excludeMaxAgeLsa need to include(true) or exclude(false) maxage lsa's
* @param isOpaquecapable need to include(true) or exclude(false) Type 10 Opaque lsa's
* @return list of lsa header in the lsdb
*/
public List getLsaHeaders(boolean excludeMaxAgeLsa, boolean isOpaquecapable) {
return database.getAllLsaHeaders(excludeMaxAgeLsa, isOpaquecapable);
}
/**
* Gets the LSA from LSDB based on the input.
*
* @param lsType type of lsa to form the key
* @param linkStateID link state id to form the key
* @param advertisingRouter advertising router to form the key
* @return lsa wrapper instance which contains the Lsa
* @throws Exception might throws exception
*/
public LsaWrapper getLsa(int lsType, String linkStateID, String advertisingRouter) throws Exception {
String lsaKey = lsType + "-" + linkStateID + "-" + advertisingRouter;
if (lsType == OspfParameters.LINK_LOCAL_OPAQUE_LSA || lsType == OspfParameters.AREA_LOCAL_OPAQUE_LSA ||
lsType == OspfParameters.AS_OPAQUE_LSA) {
byte[] linkStateAsBytes = InetAddress.getByName(linkStateID).getAddress();
int opaqueType = linkStateAsBytes[0];
int opaqueId = OspfUtil.byteToInteger(Arrays.copyOfRange(linkStateAsBytes, 1,
linkStateAsBytes.length));
lsaKey = lsType + "-" + opaqueType + opaqueId + "-" + advertisingRouter;
}
return database.findLsa(lsType, lsaKey);
}
/**
* Checks whether an instance of the given LSA exists in the database belonging to this area.
* If so return true else false.
*
* @param lookupLsa ospf LSA instance to lookup
* @return LSA wrapper instance which contains the Lsa
*/
public LsaWrapper lsaLookup(OspfLsa lookupLsa) {
return database.lsaLookup((LsaHeader) lookupLsa);
}
/**
* Checks whether an instance of the given LSA exists in the database belonging to this area.
* If so return true else false.
*
* @param lsa1 OSPF LSA instance to compare
* @param lsa2 OSPF LSA instance to compare
* @return "same" if both instances are same, "latest" if lsa1 is latest, or "old" if lsa1 is old
*/
public String isNewerOrSameLsa(OspfLsa lsa1, OspfLsa lsa2) {
return database.isNewerOrSameLsa((LsaHeader) lsa1, (LsaHeader) lsa2);
}
/**
* Methods gets called from ChannelHandler to add the received LSA to LSDB.
*
* @param ospfLsa OSPF LSA instance
* @param ospfInterface OSPF interface instance
*/
public void addLsa(OspfLsa ospfLsa, OspfInterface ospfInterface) throws Exception {
//second param is false as lsa from network
database.addLsa((LsaHeader) ospfLsa, false, ospfInterface);
}
/**
* Methods gets called from ChannelHandler to add the received LSA to LSDB.
*
* @param ospfLsa OSPF LSA instance
* @param isSelfOriginated true if the LSA is self originated. Else false
* @param ospfInterface OSPF interface instance
*/
public void addLsa(OspfLsa ospfLsa, boolean isSelfOriginated, OspfInterface ospfInterface)
throws Exception {
database.addLsa((LsaHeader) ospfLsa, isSelfOriginated, ospfInterface);
}
/**
* Adds the LSA to maxAge bin.
*
* @param key key to add it to LSDB
* @param wrapper LSA wrapper instance
*/
public void addLsaToMaxAgeBin(String key, LsaWrapper wrapper) {
database.addLsaToMaxAgeBin(key, wrapper);
}
/**
* Sets router sequence number for router LSA.
*
* @param newSequenceNumber sequence number
*/
public void setDbRouterSequenceNumber(long newSequenceNumber) {
database.setRouterLsaSeqNo(newSequenceNumber);
}
/**
* Methods gets called from ChannelHandler to delete the LSA.
*
* @param ospfLsa the LSA instance to delete
*/
public void deleteLsa(LsaHeader ospfLsa) {
database.deleteLsa(ospfLsa);
}
/**
* Removes LSA from bin.
*
* @param lsaWrapper the LSA wrapper instance to delete
*/
public void removeLsaFromBin(LsaWrapper lsaWrapper) {
database.removeLsaFromBin(lsaWrapper);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.omitNullValues()
.add("areaID", areaId)
.add("stubCost", stubCost)
.add("addressRanges", addressRanges)
.add("interfacesLst", interfacesLst)
.add("transitCapability", transitCapability)
.add("externalRoutingCapability", externalRoutingCapability)
.toString();
}
/**
* Checks all Neighbors belonging to this Area whether they are in state lesser than the EXCHANGE.
* <p>
* Creates list of such neighbors
* <p>
* Returns list of neighbors who satisfy the conditions
*
* @param ospfInterface OSPF interface instance
* @return List of interfaces having state lesser than exchange
*/
public List<OspfNbr> getNeighborsInFullState(OspfInterface ospfInterface) {
List<OspfNbr> listEligibleNeighbors = null;
OspfNbrImpl ospfNeighbor = null;
OspfNeighborState nextNeighborState;
Iterator nbrInterface = ospfInterface.listOfNeighbors().values().iterator();
while (nbrInterface.hasNext()) {
ospfNeighbor = (OspfNbrImpl) nbrInterface.next();
nextNeighborState = ospfNeighbor.getState();
if (nextNeighborState.getValue() == OspfNeighborState.FULL.getValue()) {
if (listEligibleNeighbors == null) {
listEligibleNeighbors = new ArrayList<OspfNbr>();
listEligibleNeighbors.add(ospfNeighbor);
} else {
listEligibleNeighbors.add(ospfNeighbor);
}
}
}
return listEligibleNeighbors;
}
/**
* Gets the LSDB LSA key from LSA header.
*
* @param lsaHeader LSA header instance
* @return key LSA key
*/
public String getLsaKey(LsaHeader lsaHeader) {
return database.getLsaKey(lsaHeader);
}
/**
* Adds the received LSA in other neighbors tx list.
*
* @param recLsa LSA Header instance
*/
public void addToOtherNeighborLsaTxList(LsaHeader recLsa) {
//Add the received LSA in other neighbors retransmission list.
log.debug("OspfAreaImpl: addToOtherNeighborLsaTxList");
List<OspfInterface> ospfInterfaces = getInterfacesLst();
for (OspfInterface ospfInterfaceFromArea : ospfInterfaces) {
Map neighbors = ospfInterfaceFromArea.listOfNeighbors();
for (Object neighborIP : neighbors.keySet()) {
OspfNbrImpl nbr = (OspfNbrImpl) neighbors.get(neighborIP);
if (nbr.getState().getValue() < OspfNeighborState.EXCHANGE.getValue()) {
continue;
}
String key = database.getLsaKey(recLsa);
if (nbr.getState() == OspfNeighborState.EXCHANGE || nbr.getState() == OspfNeighborState.LOADING) {
if (nbr.getLsReqList().containsKey(key)) {
LsaWrapper lsWrapper = lsaLookup(recLsa);
if (lsWrapper != null) {
LsaHeader ownLSA = (LsaHeader) lsWrapper.ospfLsa();
String status = isNewerOrSameLsa(recLsa, ownLSA);
if (status.equals("old")) {
continue;
} else if (status.equals("same")) {
log.debug("OspfAreaImpl: addToOtherNeighborLsaTxList: " +
"Removing lsa from reTxtList {}", key);
nbr.getLsReqList().remove(key);
continue;
} else {
log.debug("OspfAreaImpl: addToOtherNeighborLsaTxList: " +
"Removing lsa from reTxtList {}", key);
nbr.getLsReqList().remove(key);
}
}
}
}
if (recLsa.advertisingRouter().equals((String) neighborIP)) {
continue;
}
if ((recLsa.lsType() == OspfParameters.LINK_LOCAL_OPAQUE_LSA ||
recLsa.lsType() == OspfParameters.AREA_LOCAL_OPAQUE_LSA)) {
if (nbr.isOpaqueCapable()) {
log.debug("OspfAreaImpl: addToOtherNeighborLsaTxList: Adding lsa to reTxtList {}",
recLsa);
nbr.getReTxList().put(key, recLsa);
}
} else {
log.debug("OspfAreaImpl: addToOtherNeighborLsaTxList: Adding lsa to reTxtList {}",
recLsa);
nbr.getReTxList().put(key, recLsa);
}
}
}
}
/**
* Gets the options value.
*
* @return options value
*/
public int options() {
return options;
}
/**
* Sets the options value.
*
* @param options options value
*/
public void setOptions(int options) {
this.options = options;
}
/**
* Gets the opaque enabled options value.
*
* @return opaque enabled options value
*/
public int opaqueEnabledOptions() {
return Integer.parseInt(OspfParameters.OPAQUE_ENABLED_OPTION_VALUE, 2);
}
/**
* Gets the lsdb instance for this area.
*
* @return lsdb instance
*/
public OspfLsdb database() {
return database;
}
}
\ No newline at end of file
/*
* Copyright 2016 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.impl;
import org.jboss.netty.channel.Channel;
import org.onlab.packet.Ip4Address;
import org.onlab.util.Bandwidth;
import org.onosproject.ospf.controller.DeviceInformation;
import org.onosproject.ospf.controller.LinkInformation;
import org.onosproject.ospf.controller.LsaWrapper;
import org.onosproject.ospf.controller.OspfArea;
import org.onosproject.ospf.controller.OspfDeviceTed;
import org.onosproject.ospf.controller.OspfInterface;
import org.onosproject.ospf.controller.OspfLinkTed;
import org.onosproject.ospf.controller.OspfLsa;
import org.onosproject.ospf.controller.OspfLsaType;
import org.onosproject.ospf.controller.OspfLsdb;
import org.onosproject.ospf.controller.OspfNbr;
import org.onosproject.ospf.controller.OspfNeighborState;
import org.onosproject.ospf.controller.OspfRouter;
import org.onosproject.ospf.controller.TopologyForDeviceAndLink;
import org.onosproject.ospf.controller.area.OspfAreaImpl;
import org.onosproject.ospf.controller.area.OspfInterfaceImpl;
import org.onosproject.ospf.controller.lsdb.LsaWrapperImpl;
import org.onosproject.ospf.controller.util.OspfInterfaceType;
import org.onosproject.ospf.protocol.lsa.LsaHeader;
import org.onosproject.ospf.protocol.lsa.OpaqueLsaHeader;
import org.onosproject.ospf.protocol.lsa.types.OpaqueLsa10;
import org.onosproject.ospf.protocol.lsa.types.TopLevelTlv;
import org.onosproject.ospf.protocol.ospfpacket.OspfMessage;
import org.onosproject.ospf.protocol.ospfpacket.OspfPacketHeader;
import org.onosproject.ospf.protocol.ospfpacket.subtype.LsRequestPacket;
import org.onosproject.ospf.protocol.ospfpacket.types.DdPacket;
import org.onosproject.ospf.protocol.ospfpacket.types.LsAcknowledge;
import org.onosproject.ospf.protocol.ospfpacket.types.LsRequest;
import org.onosproject.ospf.protocol.ospfpacket.types.LsUpdate;
import org.onosproject.ospf.protocol.util.ChecksumCalculator;
import org.onosproject.ospf.protocol.util.OspfInterfaceState;
import org.onosproject.ospf.protocol.util.OspfPacketType;
import org.onosproject.ospf.protocol.util.OspfParameters;
import org.onosproject.ospf.protocol.util.OspfUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Represents an OSPF neighbor.
* The first thing an OSPF router must do is find its neighbors and form adjacency.
* Each neighbor that the router finds will be represented by this class.
*/
public class OspfNbrImpl implements OspfNbr {
private static final Logger log = LoggerFactory.getLogger(OspfNbrImpl.class);
private OspfNeighborState state;
private InternalRxmtDdPacket rxmtDdPacketTask;
private InternalInactivityTimeCheck inActivityTimeCheckTask;
private InternalFloodingTask floodingTask;
private InternalRxmtLsrPacket rxmtLsrPacketTask;
private ScheduledExecutorService exServiceRxmtLsr;
private ScheduledExecutorService exServiceFlooding;
private ScheduledExecutorService exServiceRxmtDDPacket;
private ScheduledExecutorService exServiceInActivity;
private boolean floodingTimerScheduled = false;
private boolean rxmtLsrTimerScheduled = false;
private boolean rxmtDdPacketTimerScheduled = false;
private boolean inActivityTimerScheduled = false;
/**
* When the two neighbors are exchanging databases, they form a master/slave relationship.
* The master sends the first Database Description Packet
*/
private int isMaster;
/**
* The DD Sequence Number of the DD packet that is currently being sent to the neighbor.
*/
private long ddSeqNum;
/**
* Another data structure for keeping information of the last received DD packet.
*/
private DdPacket lastDdPacket;
/**
* Another data structure for keeping information of the last Sent DD packet.
*/
private DdPacket lastSentDdPacket;
/**
* Another data structure for keeping information of the last Sent LSrequest packet.
*/
private LsRequest lastSentLsrPacket;
/**
* The router ID of the Neighbor Router.
*/
private Ip4Address neighborId;
/**
* The IP address of the neighboring router's interface to the attached network.
*/
private Ip4Address neighborIpAddr;
/**
* The neighbor's IDEA of the designated router.
*/
private Ip4Address neighborDr;
/**
* The neighbor's IDEA of the backup designated router.
*/
private Ip4Address neighborBdr;
private int routerPriority;
private int routerDeadInterval;
/**
* The list of LSAs that have to be flooded.
*/
private Map<String, OspfLsa> reTxList = new LinkedHashMap();
/**
* The list of LSAs that have been flooded but not yet acknowledged on this adjacency.
*/
private Map<String, OspfLsa> pendingReTxList = new LinkedHashMap();
/**
* List of LSAs which are failed to received ACK.
*/
private Map failedTxList = new HashMap();
/**
* The complete list of LSAs that make up the area link-state database, at the moment the.
* neighbor goes into Database Exchange state (EXCHANGE).
*/
private List<LsaHeader> ddSummaryList = new CopyOnWriteArrayList();
/**
* LSA Request List from Neighbor.
*/
private Hashtable lsReqList = new Hashtable();
/**
* The optional OSPF capabilities supported by the neighbor.
*/
private int options;
private boolean isOpaqueCapable;
/**
* A link to the OSPF-Interface this Neighbor belongs to.
*/
private OspfInterface ospfInterface;
/**
* A link to the OSPF-Area this Neighbor Data Structure belongs to.
*/
private OspfArea ospfArea;
private OspfInterfaceChannelHandler handler;
private List<TopLevelTlv> topLevelTlvs = new ArrayList<>();
private List<DeviceInformation> deviceInformationList = new ArrayList<>();
private TopologyForDeviceAndLink topologyForDeviceAndLink;
/**
* Creates an instance of Neighbor.
*
* @param paramOspfArea OSPF Area instance
* @param paramOspfInterface OSPF interface instance
* @param ipAddr IP address
* @param routerId router id
* @param options options
* @param handler channel handler instance
* @param topologyForDeviceAndLinkCommon topology for device and link instance
*/
public OspfNbrImpl(OspfArea paramOspfArea, OspfInterface paramOspfInterface,
Ip4Address ipAddr, Ip4Address routerId, int options,
OspfInterfaceChannelHandler handler, TopologyForDeviceAndLink topologyForDeviceAndLinkCommon) {
this.ospfArea = paramOspfArea;
this.ospfInterface = paramOspfInterface;
state = OspfNeighborState.DOWN;
isMaster = OspfUtil.NOT_MASTER;
ddSeqNum = OspfUtil.createRandomNumber();
neighborIpAddr = ipAddr;
neighborId = routerId;
this.options = options;
lastDdPacket = new DdPacket();
routerDeadInterval = paramOspfInterface.routerDeadIntervalTime();
this.handler = handler;
this.topologyForDeviceAndLink = topologyForDeviceAndLinkCommon;
}
/**
* Gets the IP address of this neighbor.
*
* @return the IP address of this neighbor
*/
public Ip4Address neighborIpAddr() {
return neighborIpAddr;
}
/**
* Gets the neighbor is opaque enabled or not.
*
* @return true if the neighbor is opaque enabled else false.
*/
public boolean isOpaqueCapable() {
return isOpaqueCapable;
}
/**
* Sets the neighbor is opaque enabled or not.
*
* @param isOpaqueCapable true if the neighbor is opaque enabledelse false
*/
public void setIsOpaqueCapable(boolean isOpaqueCapable) {
this.isOpaqueCapable = isOpaqueCapable;
}
/**
* Have seen a Neighbor, but the Neighbor doesn't know about me.
*
* @param ospfHello Hello Packet instance
* @param channel netty channel instance
*/
public void oneWayReceived(OspfMessage ospfHello, Channel channel) {
log.debug("OSPFNbr::oneWayReceived...!!!");
stopInactivityTimeCheck();
startInactivityTimeCheck();
if (state == OspfNeighborState.ATTEMPT) {
state = OspfNeighborState.INIT;
} else if (state == OspfNeighborState.DOWN) {
state = OspfNeighborState.INIT;
}
if (state.getValue() >= OspfNeighborState.TWOWAY.getValue()) {
state = OspfNeighborState.INIT;
failedTxList.clear();
ddSummaryList.clear();
lsReqList.clear();
}
}
/**
* Called when a DD OSPFMessage is received while state was INIT.
*
* @param ospfMessage ospf message instance
* @param channel netty channel instance
* @throws Exception might throws exception
*/
public void twoWayReceived(OspfMessage ospfMessage, Channel channel) throws Exception {
log.debug("OSPFNbr::twoWayReceived...!!!");
stopInactivityTimeCheck();
startInactivityTimeCheck();
startFloodingTimer(channel);
OspfPacketHeader packet = (OspfPacketHeader) ospfMessage;
if (state.getValue() <= OspfNeighborState.TWOWAY.getValue()) {
if (formAdjacencyOrNot()) {
state = OspfNeighborState.EXSTART;
ddSeqNum++;
DdPacket ddPacket = new DdPacket();
// seting OSPF Header
ddPacket.setOspfVer(OspfUtil.OSPF_VERSION);
ddPacket.setOspftype(OspfPacketType.DD.value());
ddPacket.setRouterId(ospfArea.routerId());
ddPacket.setAreaId(ospfArea.areaId());
ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED);
ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED);
ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length
ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED);
boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled();
if (isOpaqueEnabled) {
ddPacket.setOptions(ospfArea.opaqueEnabledOptions());
} else {
ddPacket.setOptions(ospfArea.options());
}
ddPacket.setIsInitialize(OspfUtil.INITIALIZE_SET);
ddPacket.setIsMore(OspfUtil.MORE_SET);
ddPacket.setIsMaster(OspfUtil.IS_MASTER);
ddPacket.setImtu(ospfInterface.mtu());
ddPacket.setSequenceNo(ddSeqNum);
setLastSentDdPacket(ddPacket);
rxmtDdPacketTask = new InternalRxmtDdPacket(channel);
startRxMtDdTimer(channel);
//setting destination ip
ddPacket.setDestinationIp(packet.sourceIp());
channel.write(ddPacket);
} else {
state = OspfNeighborState.TWOWAY;
}
}
}
/**
* Checks whether to form adjacency or not.
*
* @return true indicates form adjacency, else false
*/
private boolean formAdjacencyOrNot() {
boolean formAdjacency = false;
if (ospfInterface.interfaceType() == OspfInterfaceType.POINT_TO_POINT.value()) {
formAdjacency = true;
} else if (ospfInterface.interfaceType() == OspfInterfaceType.BROADCAST.value()) {
if (ospfInterface.ipAddress().equals(this.neighborDr) ||
ospfInterface.ipAddress().equals(this.neighborBdr)) {
formAdjacency = true;
} else if (neighborBdr.equals(neighborIpAddr) ||
neighborDr.equals(neighborIpAddr)) {
formAdjacency = true;
}
}
log.debug("FormAdjacencyOrNot - neighborDR: {}, neighborBDR: {}, neighborIPAddr: {}, formAdjacencyOrNot {}",
neighborDr, neighborBdr, neighborIpAddr, formAdjacency);
return formAdjacency;
}
/**
* At this point Master/Slave relationship is definitely established.
* DD sequence numbers have been exchanged.
* This is the begin of sending/receiving of DD OSPFMessages.
*
* @param ospfMessage OSPF message instance
* @param neighborIsMaster neighbor is master or slave
* @param payload contains the LSAs to add in Dd Packet
* @param ch netty channel instance
* @throws Exception might throws exception
*/
public void negotiationDone(OspfMessage ospfMessage,
boolean neighborIsMaster, List payload, Channel ch) throws Exception {
stopRxMtDdTimer();
OspfPacketHeader packet = (OspfPacketHeader) ospfMessage;
DdPacket ddPacketForCheck = (DdPacket) packet;
if (ddPacketForCheck.isOpaqueCapable()) {
OspfLsdb database = ospfArea.database();
List opaqueLsas = database.getAllLsaHeaders(true, true);
Iterator iterator = opaqueLsas.iterator();
while (iterator.hasNext()) {
OspfLsa ospfLsa = (OspfLsa) iterator.next();
if (ospfLsa.getOspfLsaType() == OspfLsaType.AREA_LOCAL_OPAQUE_LSA) {
OpaqueLsa10 opaqueLsa10 = (OpaqueLsa10) ospfLsa;
topLevelTlvs = opaqueLsa10.topLevelValues();
}
}
}
if (state == OspfNeighborState.EXSTART) {
state = OspfNeighborState.EXCHANGE;
boolean excludeMaxAgeLsa = true;
//list of contents of area wise LSA
ddSummaryList = (CopyOnWriteArrayList) ospfArea.getLsaHeaders(excludeMaxAgeLsa, isOpaqueCapable);
if (neighborIsMaster) {
processLsas(payload);
// ...construct new DD Packet...
DdPacket ddPacket = new DdPacket();
// setting OSPF Header
ddPacket.setOspfVer(OspfUtil.OSPF_VERSION);
ddPacket.setOspftype(OspfPacketType.DD.value());
ddPacket.setRouterId(ospfArea.routerId());
ddPacket.setAreaId(ospfArea.areaId());
ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED);
ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED);
ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length
ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED);
boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled();
if (isOpaqueEnabled && isOpaqueCapable) {
ddPacket.setOptions(ospfArea.opaqueEnabledOptions());
} else {
ddPacket.setOptions(ospfArea.options());
}
ddPacket.setIsInitialize(OspfUtil.INITIALIZE_NOTSET);
ddPacket.setIsMore(OspfUtil.MORE_NOTSET);
ddPacket.setIsMaster(OspfUtil.NOT_MASTER);
ddPacket.setImtu(ospfInterface.mtu());
ddPacket.setSequenceNo(ddSeqNum);
//setting the destination
ddPacket.setDestinationIp(packet.sourceIp());
setLastSentDdPacket(ddPacket);
getIsMoreBit();
ch.write(lastSentDdPacket());
} else {
// process LSA Vector's List, Add it to LSRequestList.
processLsas(payload);
DdPacket ddPacket = new DdPacket();
// setting OSPF Header
ddPacket.setOspfVer(OspfUtil.OSPF_VERSION);
ddPacket.setOspftype(OspfPacketType.DD.value());
ddPacket.setRouterId(ospfArea.routerId());
ddPacket.setAreaId(ospfArea.areaId());
ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED);
ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED);
ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length
ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED);
boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled();
if (isOpaqueEnabled && isOpaqueCapable) {
ddPacket.setOptions(ospfArea.opaqueEnabledOptions());
} else {
ddPacket.setOptions(ospfArea.options());
}
ddPacket.setIsInitialize(OspfUtil.INITIALIZE_NOTSET);
ddPacket.setIsMore(OspfUtil.MORE_NOTSET);
ddPacket.setIsMaster(OspfUtil.IS_MASTER);
ddPacket.setImtu(ospfInterface.mtu());
ddPacket.setSequenceNo(ddSeqNum);
setLastSentDdPacket(ddPacket);
getIsMoreBit();
ddPacket.setDestinationIp(packet.sourceIp());
ch.write(lastSentDdPacket());
startRxMtDdTimer(ch);
}
}
}
/**
* Process the LSA Headers received in the last received Database Description OSPFMessage.
*
* @param ddPayload LSA headers to process
* @throws Exception might throws exception
*/
public void processLsas(List ddPayload) throws Exception {
log.debug("OSPFNbr::processLsas...!!!");
OspfLsa nextLsa;
Iterator lsas = ddPayload.iterator();
while (lsas.hasNext()) {
nextLsa = (OspfLsa) lsas.next();
// check LSA Type.
if (((nextLsa.getOspfLsaType().value() > OspfLsaType.EXTERNAL_LSA.value()) &&
(nextLsa.getOspfLsaType().value() < OspfLsaType.LINK_LOCAL_OPAQUE_LSA.value())) ||
(nextLsa.getOspfLsaType().value() > OspfLsaType.AS_OPAQUE_LSA.value())) {
// unknown lsType found!
seqNumMismatch("LS Type found was unknown.");
return;
}
if ((nextLsa.getOspfLsaType() == OspfLsaType.EXTERNAL_LSA) &&
!ospfArea.isExternalRoutingCapability()) {
// LSA is external and the Area has no external lsa capability
seqNumMismatch("External LSA found although area is stub.");
return;
}
LsaWrapper lsaHasInstance = ospfArea.lsaLookup(nextLsa);
if (lsaHasInstance == null) {
lsReqList.put(((OspfAreaImpl) ospfArea).getLsaKey((LsaHeader) nextLsa), nextLsa);
} else {
String isNew = ((OspfAreaImpl) ospfArea).isNewerOrSameLsa(nextLsa,
lsaHasInstance.ospfLsa());
if (isNew.equals("latest")) {
lsReqList.put(((OspfAreaImpl) ospfArea).getLsaKey((LsaHeader) nextLsa), nextLsa);
}
}
}
}
/**
* Handles sequence number mis match event.
*
* @param reason a string represents the mismatch reason
* @return OSPF message instance
* @throws Exception might throws exception
*/
public OspfMessage seqNumMismatch(String reason) throws Exception {
log.debug("OSPFNbr::seqNumMismatch...{} ", reason);
stopRxMtDdTimer();
if (state.getValue() >= OspfNeighborState.EXCHANGE.getValue()) {
/* if (state == OspfNeighborState.FULL) {
ospfArea.refreshArea(ospfInterface);
}*/
state = OspfNeighborState.EXSTART;
lsReqList.clear();
ddSummaryList.clear();
//increment the dd sequence number
ddSeqNum++;
DdPacket ddPacket = new DdPacket();
// seting OSPF Header
ddPacket.setOspfVer(OspfUtil.OSPF_VERSION);
ddPacket.setOspftype(OspfPacketType.DD.value());
ddPacket.setRouterId(ospfArea.routerId());
ddPacket.setAreaId(ospfArea.areaId());
ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED);
ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED);
ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length
ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED);
boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled();
if (isOpaqueEnabled) {
ddPacket.setOptions(ospfArea.opaqueEnabledOptions());
} else {
ddPacket.setOptions(ospfArea.options());
}
ddPacket.setIsInitialize(OspfUtil.INITIALIZE_SET);
ddPacket.setIsMore(OspfUtil.MORE_SET);
ddPacket.setIsMaster(OspfUtil.IS_MASTER);
ddPacket.setImtu(ospfInterface.mtu());
ddPacket.setSequenceNo(ddSeqNum);
setLastSentDdPacket(ddPacket);
//setting destination ip
ddPacket.setDestinationIp(neighborIpAddr());
setLastSentDdPacket(ddPacket);
return ddPacket;
}
return null;
}
/**
* Called if a LS Request has been received for an LSA which is not contained in the database.
* This indicates an error in the Database Exchange process.
* Actions to be performed are the same as in seqNumMismatch.
* In addition, stop the possibly activated re transmission timer.
*
* @param ch netty channel instance
*/
public void badLSReq(Channel ch) throws Exception {
log.debug("OSPFNbr::badLSReq...!!!");
if (state.getValue() >= OspfNeighborState.EXCHANGE.getValue()) {
if (state == OspfNeighborState.FULL) {
ospfArea.refreshArea(ospfInterface);
}
stopRxMtDdTimer();
state = OspfNeighborState.EXSTART;
lsReqList.clear();
ddSummaryList.clear();
reTxList.clear();
//increment the dd sequence number
isMaster = OspfUtil.IS_MASTER;
ddSeqNum++;
DdPacket ddPacket = new DdPacket();
// seting OSPF Header
ddPacket.setOspfVer(OspfUtil.OSPF_VERSION);
ddPacket.setOspftype(OspfPacketType.DD.value());
ddPacket.setRouterId(ospfArea.routerId());
ddPacket.setAreaId(ospfArea.areaId());
ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED);
ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED);
ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length
ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED);
// setting DD Body
boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled();
if (isOpaqueEnabled && this.isOpaqueCapable) {
ddPacket.setOptions(ospfArea.opaqueEnabledOptions());
} else {
ddPacket.setOptions(ospfArea.options());
}
ddPacket.setIsInitialize(OspfUtil.INITIALIZE_SET);
ddPacket.setIsMore(OspfUtil.MORE_SET);
ddPacket.setIsMaster(OspfUtil.IS_MASTER);
ddPacket.setImtu(ospfInterface.mtu());
ddPacket.setSequenceNo(ddSeqNum);
rxmtDdPacketTask = new InternalRxmtDdPacket(ch);
startRxMtDdTimer(ch);
//setting destination ip
ddPacket.setDestinationIp(neighborIpAddr());
setLastSentDdPacket(ddPacket);
ch.write(ddPacket);
}
}
/**
* Called if state is EXCHANGE. This method is executed every time a DD Packets arrives.
* When the last Packet arrives, it transfers the state into LOADING or FULL
*
* @param neighborIsMaster true if neighbor is master else false
* @param dataDescPkt DdPacket instance
* @param ch netty channel instance
* @throws Exception might throws exception
*/
public void processDdPacket(boolean neighborIsMaster, DdPacket dataDescPkt,
Channel ch) throws Exception {
log.debug("OSPFNbr::neighborIsMaster.{}", neighborIsMaster);
if (!neighborIsMaster) {
stopRxMtDdTimer();
ddSeqNum++;
processLsas(dataDescPkt.getLsaHeaderList());
if ((ddSummaryList.isEmpty()) &&
(dataDescPkt.isMore() == OspfUtil.MORE_NOTSET)) {
log.debug(
"OSPFNbr::ddSummaryList is empty and dataDescPkt.isMore is zero..!!!");
// generate the neighbor event ExchangeDone.
exchangeDone(dataDescPkt, ch);
} else {
log.debug("OSPFNbr::ddSummaryList is present...!!!");
// send a new Database Description Packet to the slave.
DdPacket ddPacket = new DdPacket();
// seting OSPF Header
ddPacket.setOspfVer(OspfUtil.OSPF_VERSION);
ddPacket.setOspftype(OspfPacketType.DD.value());
ddPacket.setRouterId(ospfArea.routerId());
ddPacket.setAreaId(ospfArea.areaId());
ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED);
ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED);
ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length
ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED);
// setting DD Body
boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled();
if (isOpaqueEnabled && isOpaqueCapable) {
ddPacket.setOptions(ospfArea.opaqueEnabledOptions());
} else {
ddPacket.setOptions(ospfArea.options());
}
ddPacket.setIsInitialize(OspfUtil.INITIALIZE_NOTSET);
ddPacket.setIsMore(OspfUtil.MORE_NOTSET);
ddPacket.setIsMaster(OspfUtil.IS_MASTER);
ddPacket.setImtu(ospfInterface.mtu());
ddPacket.setSequenceNo(ddSeqNum);
setLastSentDdPacket(ddPacket);
getIsMoreBit();
//Set the destination IP Address
ddPacket.setDestinationIp(dataDescPkt.sourceIp());
ch.write(lastSentDdPacket());
startRxMtDdTimer(ch);
}
} else {
log.debug("OSPFNbr::neighborIsMaster is master...!!!");
ddSeqNum = dataDescPkt.sequenceNo();
processLsas(dataDescPkt.getLsaHeaderList());
DdPacket ddPacket = new DdPacket();
// seting OSPF Header
ddPacket.setOspfVer(OspfUtil.OSPF_VERSION);
ddPacket.setOspftype(OspfPacketType.DD.value());
ddPacket.setRouterId(ospfArea.routerId());
ddPacket.setAreaId(ospfArea.areaId());
ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED);
ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED);
ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length
ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED);
// setting DD Body
boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled();
if (isOpaqueEnabled && this.isOpaqueCapable) {
ddPacket.setOptions(ospfArea.opaqueEnabledOptions());
} else {
ddPacket.setOptions(ospfArea.options());
}
ddPacket.setIsInitialize(OspfUtil.INITIALIZE_NOTSET);
ddPacket.setIsMore(OspfUtil.MORE_NOTSET);
ddPacket.setIsMaster(OspfUtil.NOT_MASTER);
ddPacket.setImtu(ospfInterface.mtu());
ddPacket.setSequenceNo(ddSeqNum);
setLastSentDdPacket(ddPacket);
getIsMoreBit();
if ((ddPacket.isMore() == OspfUtil.MORE_NOTSET) &&
(dataDescPkt.isMore() == OspfUtil.MORE_NOTSET)) {
// generate the neighbor event ExchangeDone.
exchangeDone(dataDescPkt, ch);
}
ddPacket.setDestinationIp(dataDescPkt.sourceIp());
ch.write(ddPacket);
}
}
/**
* Sets the more bit in stored, last sent DdPacket.
*/
private void getIsMoreBit() {
DdPacket ddPacket = lastSentDdPacket();
int count = ddSummaryList.size();
if (!ddSummaryList.isEmpty()) {
Iterator itr = ddSummaryList.iterator();
int currentLength = OspfUtil.DD_HEADER_LENGTH;
int maxSize = ospfInterface.mtu() - OspfUtil.LSA_HEADER_LENGTH; // subtract a normal IP header.
while (itr.hasNext()) {
if ((currentLength + OspfUtil.LSA_HEADER_LENGTH) > maxSize) {
break;
}
LsaHeader lsaHeader = (LsaHeader) itr.next();
ddPacket.addLsaHeader(lsaHeader);
currentLength = currentLength + OspfUtil.LSA_HEADER_LENGTH;
ddSummaryList.remove(lsaHeader);
count--;
}
if (count > 0) {
ddPacket.setIsMore(OspfUtil.MORE_SET);
} else {
ddPacket.setIsMore(OspfUtil.MORE_NOTSET);
}
}
setLastSentDdPacket(ddPacket);
}
/**
* At this point, the router has sent and received an entire sequence of DD packets.
* Now it must be determined whether the new state is FULL, or LS Request packets
* have to be send.
*
* @param message OSPF message instance
* @param ch netty channel handler
*/
public void exchangeDone(OspfMessage message, Channel ch) {
log.debug("OSPFNbr::exchangeDone...!!!");
stopRxMtDdTimer();
OspfPacketHeader header = (OspfPacketHeader) message;
if (state == OspfNeighborState.EXCHANGE) {
if (lsReqList.isEmpty()) {
state = OspfNeighborState.FULL;
//handler.addDeviceInformation(this);
//handler.addLinkInformation(this, topLevelTlvs);
} else {
state = OspfNeighborState.LOADING;
LsRequest lsRequest = buildLsRequest();
//Setting the destination address
lsRequest.setDestinationIp(header.sourceIp());
ch.write(lsRequest);
setLastSentLsrPacket(lsRequest);
startRxMtLsrTimer(ch);
}
}
}
/**
* Builds LS Request.
*
* @return ls request instance
*/
private LsRequest buildLsRequest() {
//send link state request packet to neighbor
//for recent lsa's which are not received in exchange state
LsRequest lsRequest = new LsRequest();
lsRequest.setOspfVer(OspfUtil.OSPF_VERSION);
lsRequest.setOspftype(OspfPacketType.LSREQUEST.value());
lsRequest.setRouterId(ospfArea.routerId());
lsRequest.setAreaId(ospfArea.areaId());
lsRequest.setAuthType(OspfUtil.NOT_ASSIGNED);
lsRequest.setAuthentication(OspfUtil.NOT_ASSIGNED);
lsRequest.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length
lsRequest.setChecksum(OspfUtil.NOT_ASSIGNED);
Set lsaKeys = lsReqList.keySet();
Iterator itr = lsaKeys.iterator();
int currentLength = OspfUtil.OSPF_HEADER_LENGTH;
int maxSize = ospfInterface.mtu() -
OspfUtil.LSA_HEADER_LENGTH; // subtract a normal IP header.
while (itr.hasNext()) {
if ((currentLength + OspfUtil.LSREQUEST_LENGTH) >= maxSize) {
break;
}
LsRequestPacket lsRequestPacket = new LsRequestPacket();
String key = ((String) itr.next());
String[] lsaKey = key.split("-");
OspfLsa lsa = (OspfLsa) lsReqList.get(key);
lsRequestPacket.setLsType(Integer.valueOf(lsaKey[0]));
lsRequestPacket.setOwnRouterId(lsaKey[2]);
if (((lsa.getOspfLsaType().value() == OspfLsaType.AREA_LOCAL_OPAQUE_LSA.value()) ||
(lsa.getOspfLsaType().value() == OspfLsaType.LINK_LOCAL_OPAQUE_LSA.value())) ||
(lsa.getOspfLsaType().value() == OspfLsaType.AS_OPAQUE_LSA.value())) {
OpaqueLsaHeader header = (OpaqueLsaHeader) lsa;
byte[] opaqueIdBytes = OspfUtil.convertToTwoBytes(header.opaqueId());
lsRequestPacket.setLinkStateId(header.opaqueType() + "." + "0" + "." + opaqueIdBytes[0]
+ "." + opaqueIdBytes[1]);
} else {
lsRequestPacket.setLinkStateId(lsaKey[1]);
}
lsRequest.addLinkStateRequests(lsRequestPacket);
currentLength = currentLength + OspfUtil.LSREQUEST_LENGTH;
}
return lsRequest;
}
/**
* Determines whether an adjacency should be established/maintained with the neighbor or not.
*
* @param ch netty channel instance
*/
public void adjOk(Channel ch) {
log.debug("OSPFNbr::adjOk...!!!");
if (ospfInterface.interfaceType() != OspfInterfaceType.POINT_TO_POINT.value()) {
if (state == OspfNeighborState.TWOWAY) {
if (formAdjacencyOrNot()) {
state = OspfNeighborState.EXSTART;
//check for sequence number in lsdb
ddSeqNum++;
DdPacket ddPacket = new DdPacket();
// seting OSPF Header
ddPacket.setOspfVer(OspfUtil.OSPF_VERSION);
ddPacket.setOspftype(OspfPacketType.DD.value());
ddPacket.setRouterId(ospfArea.routerId());
ddPacket.setAreaId(ospfArea.areaId());
ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED);
ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED);
ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED);
ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED);
// setting DD Body
boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled();
if (isOpaqueEnabled && this.isOpaqueCapable) {
ddPacket.setOptions(ospfArea.opaqueEnabledOptions());
} else {
ddPacket.setOptions(ospfArea.options());
}
ddPacket.setIsInitialize(OspfUtil.INITIALIZE_SET);
ddPacket.setIsMore(OspfUtil.MORE_SET);
ddPacket.setIsMaster(OspfUtil.IS_MASTER);
ddPacket.setImtu(ospfInterface.mtu());
ddPacket.setSequenceNo(ddSeqNum);
rxmtDdPacketTask = new InternalRxmtDdPacket(ch);
startRxMtDdTimer(ch);
//setting destination ip
ddPacket.setDestinationIp(neighborIpAddr());
setLastSentDdPacket(ddPacket);
ch.write(ddPacket);
}
} else if (state.getValue() >= OspfNeighborState.EXSTART.getValue()) {
if (!formAdjacencyOrNot()) {
state = OspfNeighborState.TWOWAY;
lsReqList.clear();
ddSummaryList.clear();
reTxList.clear();
}
}
}
}
/**
* LS Update Packet has been received while state was EXCHANGE or LOADING.
* Examine the received LSAs, check whether they were requested or not and process
* them accordingly. Therefore use method "processReceivedLsa" for further treatment.
*
* @param lsUpdPkt LS Update Packet received while Neighbor state was EXCHANGE or
* LOADING
* @param ch netty channel instance
* @throws Exception might throws exception
*/
public void processLsUpdate(LsUpdate lsUpdPkt, Channel ch) throws Exception {
stopRxMtLsrTimer();
log.debug("OSPFNbr::processLsUpdate...!!!");
List lsaList = lsUpdPkt.getLsaList();
if (!lsaList.isEmpty()) {
Iterator itr = lsaList.iterator();
while (itr.hasNext()) {
LsaHeader lsaHeader = (LsaHeader) itr.next();
String key = ((OspfAreaImpl) ospfArea).getLsaKey(lsaHeader);
if (lsReqList.containsKey(key)) {
boolean removeIt;
removeIt = processReceivedLsa(lsaHeader, false, ch,
lsUpdPkt.sourceIp());
if (removeIt) {
lsReqList.remove(key);
}
} else {
// LSA was received via Flooding
processReceivedLsa(lsaHeader, true, ch,
lsUpdPkt.sourceIp());
}
}
if (lsReqList.isEmpty() && (state == OspfNeighborState.LOADING)) {
// loading complete
loadingDone();
} else {
stopRxMtLsrTimer();
LsRequest lsRequest = buildLsRequest();
lsRequest.setDestinationIp(lsUpdPkt.sourceIp());
setLastSentLsrPacket(lsRequest);
startRxMtLsrTimer(ch);
}
}
}
/***
* Method gets called when no more ls request list and moving to FULL State.
*
* @throws Exception might throws exception
*/
public void loadingDone() throws Exception {
stopRxMtLsrTimer();
stopRxMtDdTimer();
log.debug("OSPFNbr::loadingDone...!!!");
state = OspfNeighborState.FULL;
ospfArea.refreshArea(ospfInterface);
}
/**
* Adds device and link.
*
* @param topologyForDeviceAndLink topology for device and link instance
*/
private void callDeviceAndLinkAdding(TopologyForDeviceAndLink topologyForDeviceAndLink) {
Map<String, DeviceInformation> deviceInformationMap = topologyForDeviceAndLink.deviceInformationMap();
Map<String, LinkInformation> linkInformationMap = topologyForDeviceAndLink.linkInformationMap();
OspfRouter ospfRouter = new OspfRouterImpl();
log.debug("Device Information in list format along with size {}", deviceInformationMap.size());
for (String key : deviceInformationMap.keySet()) {
DeviceInformation value = deviceInformationMap.get(key);
ospfRouter.setRouterIp(value.routerId());
ospfRouter.setAreaIdOfInterface(ospfArea.areaId());
ospfRouter.setNeighborRouterId(value.deviceId());
OspfDeviceTed ospfDeviceTed = new OspfDeviceTedImpl();
List<Ip4Address> ip4Addresses = value.interfaceId();
ospfDeviceTed.setIpv4RouterIds(ip4Addresses);
ospfRouter.setDeviceTed(ospfDeviceTed);
ospfRouter.setOpaque(ospfArea.isOpaqueEnabled());
if (value.isDr()) {
ospfRouter.setDr(value.isDr());
} else {
ospfRouter.setDr(false);
}
int size = value.interfaceId().size();
for (int i = 0; i < size; i++) {
ospfRouter.setInterfaceId(value.interfaceId().get(i));
}
if (value.isAlreadyCreated()) {
removeDeviceDetails(value.routerId());
OspfRouter ospfRouter1 = new OspfRouterImpl();
ospfRouter1.setRouterIp(value.routerId());
ospfRouter1.setInterfaceId(ospfInterface.ipAddress());
ospfRouter1.setAreaIdOfInterface(ospfArea.areaId());
ospfRouter1.setDeviceTed(new OspfDeviceTedImpl());
topologyForDeviceAndLink.removeLinks(value.routerId());
handler.removeDeviceInformation(ospfRouter1);
}
handler.addDeviceInformation(ospfRouter);
}
for (Map.Entry<String, LinkInformation> entry : linkInformationMap.entrySet()) {
String key = entry.getKey();
LinkInformation value = entry.getValue();
OspfRouter ospfRouterForLink = new OspfRouterImpl();
ospfRouterForLink.setInterfaceId(value.interfaceIp());
ospfRouterForLink.setAreaIdOfInterface(ospfArea.areaId());
ospfRouterForLink.setOpaque(ospfArea.isOpaqueEnabled());
OspfLinkTed ospfLinkTed =
topologyForDeviceAndLink.getOspfLinkTedHashMap(value.linkDestinationId().toString());
if (ospfLinkTed == null) {
ospfLinkTed = new OspfLinkTedImpl();
ospfLinkTed.setMaximumLink(Bandwidth.bps(0));
ospfLinkTed.setMaxReserved(Bandwidth.bps(0));
ospfLinkTed.setTeMetric(0);
}
if (!value.isLinkSrcIdNotRouterId()) {
ospfRouterForLink.setRouterIp(value.linkSourceId());
ospfRouterForLink.setNeighborRouterId(value.linkDestinationId());
try {
handler.addLinkInformation(ospfRouterForLink, ospfLinkTed);
log.debug("LinkId, LinkSrc , LinkDest , LinkInterface values are : "
+ value.linkId() + " , " + value.linkSourceId() + " , "
+ value.linkDestinationId() + " , "
+ value.interfaceIp());
} catch (Exception e) {
log.debug("Got Exception : {}", e.getMessage());
}
}
}
}
// RFC 2328 Section 13 - partly as flooding procedure
/**
* Processes the received Lsa.
*
* @param recLsa received Lsa
* @param receivedViaFlooding received via flooding or not
* @param ch channel instance
* @param sourceIp source of this Lsa
* @return true to remove it from lsReqList else false
* @throws Exception might throws exception
*/
public boolean processReceivedLsa(LsaHeader recLsa,
boolean receivedViaFlooding, Channel ch, Ip4Address sourceIp)
throws Exception {
log.debug("OSPFNbr::processReceivedLsa(recLsa, recievedViaFlooding, ch)...!!!");
//Validate the lsa checksum RFC 2328 13 (1)
ChecksumCalculator checkSum = new ChecksumCalculator();
if (!checkSum.isValidLsaCheckSum(recLsa,
recLsa.getOspfLsaType().value(),
OspfUtil.LSAPACKET_CHECKSUM_POS1,
OspfUtil.LSAPACKET_CHECKSUM_POS2)) {
log.debug("Checksum mismatch. Received LSA packet type {} ",
recLsa.lsType());
return true;
}
//If LSA type is unknown discard the lsa RFC 2328 13(2)
if (((recLsa.getOspfLsaType().value() > OspfLsaType.EXTERNAL_LSA.value()) &&
(recLsa.getOspfLsaType().value() < OspfLsaType.LINK_LOCAL_OPAQUE_LSA.value())) ||
(recLsa.getOspfLsaType().value() > OspfLsaType.AS_OPAQUE_LSA.value())) {
return true;
}
//If LSA type is external & the area is configured as stub area discard the lsa RFC 2328 13(3)
if ((recLsa.getOspfLsaType() == OspfLsaType.EXTERNAL_LSA) &&
(!ospfArea.isExternalRoutingCapability())) // to determine how to store options
{
return true;
}
//if lsa age is equal to maxage && instance is not in lsdb && none of neighbors are in exchange
// or loading state
// Acknowledge the receipt by sending LSAck to the sender. 2328 13(4)
if ((recLsa.age() == OspfParameters.MAXAGE) &&
(ospfArea.lsaLookup(recLsa) == null) &&
ospfArea.noNeighborInLsaExchangeProcess()) {
// RFC 2328 Section 13. (4)
// Because the LSA was not yet requested, it is treated as a flooded LSA and thus
// acknowledged.
directAcknowledge(recLsa, ch, sourceIp);
return true;
}
String key = ((OspfAreaImpl) ospfArea).getLsaKey(recLsa);
LsaWrapper lsWrapper = ospfArea.lsaLookup(recLsa);
String status = isNullorLatest(lsWrapper, recLsa);
//Section 13 (5)
if (status.equals("isNullorLatest")) {
if (recLsa.lsType() == OspfLsaType.ROUTER.value() && recLsa.advertisingRouter().equals(
ospfArea.routerId())) {
if (recLsa.lsSequenceNo() > ((LsaWrapperImpl) lsWrapper).lsaHeader().lsSequenceNo()) {
ospfArea.setDbRouterSequenceNumber(recLsa.lsSequenceNo() + 1);
processSelfOriginatedLsa();
}
if (recLsa.age() == OspfParameters.MAXAGE) {
((LsaWrapperImpl) lsWrapper).lsaHeader().setAge(OspfParameters.MAXAGE);
//remove from db & bin, add the lsa to MaxAge bin.
ospfArea.addLsaToMaxAgeBin(((OspfAreaImpl) ospfArea).getLsaKey(((LsaWrapperImpl)
lsWrapper).lsaHeader()), lsWrapper);
ospfArea.removeLsaFromBin(lsWrapper);
}
return true;
} else if (recLsa.lsType() == OspfLsaType.NETWORK.value() && isLinkStateMatchesOwnRouterId(
recLsa.linkStateId())) {
// if we are not DR or if origination router ID not equal to our router ID //either
// DR state changed or our router ID was changed
//set LSAge = MaxAge
//flood the LSA
if (((OspfInterfaceImpl) ospfInterface).state() != OspfInterfaceState.DR ||
!recLsa.advertisingRouter().equals(
ospfArea.routerId())) {
if (lsWrapper != null) {
((LsaWrapperImpl) lsWrapper).lsaHeader().setAge(OspfParameters.MAXAGE);
//remove from bin, add the lsa to MaxAge bin.
ospfArea.addLsaToMaxAgeBin(((OspfAreaImpl) ospfArea).getLsaKey(((LsaWrapperImpl)
lsWrapper).lsaHeader()), lsWrapper);
ospfArea.removeLsaFromBin(lsWrapper);
} else {
recLsa.setAge(OspfParameters.MAXAGE);
((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(recLsa);
}
}
return true;
} else {
if (recLsa.age() == OspfParameters.MAXAGE) {
((OspfInterfaceImpl) ospfInterface).addLsaHeaderForDelayAck(recLsa);
//remove from db & bin, add the lsa to MaxAge bin.
if (lsWrapper != null) {
lsWrapper.setLsaAgeReceived(OspfParameters.MAXAGE);
ospfArea.addLsaToMaxAgeBin(((OspfAreaImpl) ospfArea).getLsaKey(((LsaWrapperImpl)
lsWrapper).lsaHeader()), lsWrapper);
ospfArea.removeLsaFromBin(lsWrapper);
} else {
((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(recLsa);
}
return true;
} else {
ospfArea.addLsa(recLsa, ospfInterface);
log.debug("Inside addLsaMethod");
topologyForDeviceAndLink.addLocalDevice(recLsa, ospfInterface, ospfArea);
callDeviceAndLinkAdding(topologyForDeviceAndLink);
log.debug("Adding to lsdb interface State {}", ((OspfInterfaceImpl) ospfInterface).state().value());
// should not send any acknowledge if flooded out on receiving interface
if (((OspfInterfaceImpl) ospfInterface).state().value() == OspfInterfaceState.BDR.value()) {
if (neighborDr.equals(sourceIp)) {
log.debug("Adding for delayed ack {}", recLsa);
((OspfInterfaceImpl) ospfInterface).addLsaHeaderForDelayAck(recLsa);
}
} else {
log.debug("Adding for delayed ack {}", recLsa);
((OspfInterfaceImpl) ospfInterface).addLsaHeaderForDelayAck(recLsa);
}
if (((OspfInterfaceImpl) ospfInterface).state().value() == OspfInterfaceState.DR.value() ||
((OspfInterfaceImpl) ospfInterface).state().value() ==
OspfInterfaceState.POINT2POINT.value()) {
((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(recLsa);
}
}
}
}
// RFC 2328 Section 13 (6)
if (lsReqList.contains(key)) {
badLSReq(ch);
}
if (status.equals("same")) { //13 (7)
if (pendingReTxList.containsKey(key)) {
pendingReTxList.remove(key);
if (((OspfInterfaceImpl) ospfInterface).state().value() == OspfInterfaceState.BDR.value()) {
if (neighborDr.equals(recLsa.advertisingRouter())) {
((OspfInterfaceImpl) ospfInterface).addLsaHeaderForDelayAck(recLsa);
}
}
} else {
directAcknowledge(recLsa, ch, sourceIp);
return true;
}
} else if (status.equals("old")) { // section 13 - point 8
if ((recLsa.lsSequenceNo() == OspfParameters.MAXSEQUENCENUMBER) &&
(recLsa.age() == OspfParameters.MAXAGE)) {
// section 13 - point 8
// simple discard the received LSA -
return true;
} else {
// respond back with the same LSA
//Using flood LSA to sent the LSUpdate back to advertising router
int diff = Math.abs(lsWrapper.lsaAgeReceived() - recLsa.age());
if (diff > OspfParameters.MINLSARRIVAL) {
sendLsa(((LsaWrapperImpl) lsWrapper).lsaHeader(), sourceIp, ch);
}
}
}
callDeviceAndLinkAdding(topologyForDeviceAndLink);
return true;
}
/**
* Checks Link State ID is equal to one of the router's own IP interface addresses.
*
* @param linkStateId link state id
* @return true if link state matches or false
*/
private boolean isLinkStateMatchesOwnRouterId(String linkStateId) {
boolean isLinkStateMatches = false;
List<OspfInterface> interfaceLst = ospfArea.getInterfacesLst();
for (OspfInterface ospfInterface : interfaceLst) {
if (ospfInterface.ipAddress().toString().equals(linkStateId)) {
isLinkStateMatches = true;
break;
}
}
return isLinkStateMatches;
}
/**
* RFC 2328 Section 13 (5).
*
* @param lsWrapper ls wrapper instance
* @param recLsa received LSA instance
* @return returns a string status
*/
public String isNullorLatest(LsaWrapper lsWrapper, LsaHeader recLsa) {
if (lsWrapper != null) {
LsaHeader ownLsa = (LsaHeader) lsWrapper.ospfLsa();
String status = ospfArea.isNewerOrSameLsa(recLsa, ownLsa);
if (status.equals("latest")) {
return "isNullorLatest";
} else {
return status;
}
} else {
return "isNullorLatest";
}
}
/**
* RFC 2328 section 13.4
* Processing self-originated LSAs.
*
* @throws Exception might throws exception
*/
public void processSelfOriginatedLsa() throws Exception {
ospfArea.refreshArea(ospfInterface);
}
/**
* Sends the LSA to destination address.
*
* @param lsa LSA instance to sent
* @param destination destination IP address
* @param ch netty channel instance
*/
public void sendLsa(LsaHeader lsa, Ip4Address destination, Channel ch) {
if (lsa == null) {
return;
}
LsUpdate responseLsUpdate = new LsUpdate();
// seting OSPF Header
responseLsUpdate.setOspfVer(OspfUtil.OSPF_VERSION);
responseLsUpdate.setOspftype(OspfPacketType.LSUPDATE.value());
responseLsUpdate.setRouterId(ospfArea.routerId());
responseLsUpdate.setAreaId(ospfArea.areaId());
responseLsUpdate.setAuthType(OspfUtil.NOT_ASSIGNED);
responseLsUpdate.setAuthentication(OspfUtil.NOT_ASSIGNED);
responseLsUpdate.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length
responseLsUpdate.setChecksum(OspfUtil.NOT_ASSIGNED);
responseLsUpdate.setNumberOfLsa(1);
responseLsUpdate.addLsa(lsa);
//setting the destination.
responseLsUpdate.setDestinationIp(destination);
ch.write(responseLsUpdate);
}
/**
* Sends a direct Acknowledgment for a particular LSA to the Neighbor.
*
* @param ackLsa LSA instance
* @param ch netty channel instance
* @param sourceIp source IP address
*/
public void directAcknowledge(LsaHeader ackLsa, Channel ch, Ip4Address sourceIp) {
log.debug("OSPFNbr::directAcknowledge...!!!");
LsAcknowledge ackContent = new LsAcknowledge();
// seting OSPF Header
ackContent.setOspfVer(OspfUtil.OSPF_VERSION);
ackContent.setOspftype(OspfPacketType.LSAACK.value());
ackContent.setRouterId(ospfArea.routerId());
ackContent.setAreaId(ospfArea.areaId());
ackContent.setAuthType(OspfUtil.NOT_ASSIGNED);
ackContent.setAuthentication(OspfUtil.NOT_ASSIGNED);
ackContent.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length
ackContent.setChecksum(OspfUtil.NOT_ASSIGNED);
ackContent.addLinkStateHeader(ackLsa);
//setting the destination IP
ackContent.setDestinationIp(sourceIp);
ch.write(ackContent);
}
/**
* Called when neighbor is down.
*
* @throws Exception might throws exception
*/
public void neighborDown() throws Exception {
log.debug("Neighbor Down {} and NeighborId {}", neighborIpAddr,
neighborId);
stopInactivityTimeCheck();
stopRxMtDdTimer();
stopRxMtLsrTimer();
if (floodingTimerScheduled) {
stopFloodingTimer();
floodingTimerScheduled = false;
}
state = OspfNeighborState.DOWN;
ospfArea.refreshArea(ospfInterface);
lsReqList.clear();
ddSummaryList.clear();
if (neighborIpAddr.equals(neighborBdr) ||
neighborIpAddr.equals(neighborDr)) {
handler.neighborChange();
}
log.debug("Neighbor Went Down : "
+ this.neighborIpAddr + " , " + this.neighborId);
removeDeviceDetails(this.neighborId);
OspfRouter ospfRouter = new OspfRouterImpl();
ospfRouter.setRouterIp(this.neighborId());
ospfRouter.setInterfaceId(ospfInterface.ipAddress());
ospfRouter.setAreaIdOfInterface(ospfArea.areaId());
ospfRouter.setDeviceTed(new OspfDeviceTedImpl());
handler.removeDeviceInformation(ospfRouter);
removeDeviceDetails(this.neighborIpAddr);
OspfRouter ospfRouter1 = new OspfRouterImpl();
ospfRouter1.setRouterIp(this.neighborIpAddr);
ospfRouter1.setInterfaceId(ospfInterface.ipAddress());
ospfRouter1.setAreaIdOfInterface(ospfArea.areaId());
ospfRouter1.setDeviceTed(new OspfDeviceTedImpl());
handler.removeDeviceInformation(ospfRouter1);
handler.removeLinkInformation(this);
callDeviceAndLinkAdding(topologyForDeviceAndLink);
}
/**
* Removes device details.
*
* @param routerId router id
*/
private void removeDeviceDetails(Ip4Address routerId) {
String key = "device:" + routerId;
topologyForDeviceAndLink.removeDeviceInformationMap(key);
topologyForDeviceAndLink.removeLinks(routerId);
}
/**
* Starts the inactivity timer.
*/
private void startInactivityTimeCheck() {
if (!inActivityTimerScheduled) {
log.debug("OSPFNbr::startInactivityTimeCheck");
inActivityTimeCheckTask = new InternalInactivityTimeCheck();
exServiceInActivity = Executors.newSingleThreadScheduledExecutor();
exServiceInActivity.scheduleAtFixedRate(inActivityTimeCheckTask, routerDeadInterval,
routerDeadInterval, TimeUnit.SECONDS);
inActivityTimerScheduled = true;
}
}
/**
* Stops the inactivity timer.
*/
private void stopInactivityTimeCheck() {
if (inActivityTimerScheduled) {
log.debug("OSPFNbr::stopInactivityTimeCheck ");
exServiceInActivity.shutdown();
inActivityTimerScheduled = false;
}
}
/**
* Starts the flooding timer.
*
* @param channel channel instance
*/
public void startFloodingTimer(Channel channel) {
if (!floodingTimerScheduled) {
log.debug("OSPFNbr::startFloodingTimer");
floodingTask = new InternalFloodingTask(channel);
exServiceFlooding = Executors.newSingleThreadScheduledExecutor();
//Run every 5 seconds.
exServiceFlooding.scheduleAtFixedRate(floodingTask, OspfParameters.START_NOW,
OspfParameters.MINLSINTERVAL, TimeUnit.SECONDS);
floodingTimerScheduled = true;
}
}
/**
* Stops the flooding timer.
*/
private void stopFloodingTimer() {
if (floodingTimerScheduled) {
log.debug("OSPFNbr::stopFloodingTimer ");
exServiceFlooding.shutdown();
floodingTimerScheduled = false;
}
}
/**
* Starts the Dd Retransmission executor task.
*
* @param ch netty channel instance
*/
private void startRxMtDdTimer(Channel ch) {
if (!rxmtDdPacketTimerScheduled) {
long retransmitInterval = ospfInterface.reTransmitInterval();
rxmtDdPacketTask = new InternalRxmtDdPacket(ch);
exServiceRxmtDDPacket = Executors.newSingleThreadScheduledExecutor();
exServiceRxmtDDPacket.scheduleAtFixedRate(rxmtDdPacketTask, retransmitInterval,
retransmitInterval, TimeUnit.SECONDS);
rxmtDdPacketTimerScheduled = true;
}
}
/**
* Stops the Dd Retransmission executor task.
*/
private void stopRxMtDdTimer() {
if (rxmtDdPacketTimerScheduled) {
exServiceRxmtDDPacket.shutdown();
rxmtDdPacketTimerScheduled = false;
}
}
/**
* Starts Ls request retransmission executor task.
*
* @param ch Netty channel instance
*/
private void startRxMtLsrTimer(Channel ch) {
if (!rxmtLsrTimerScheduled) {
log.debug("OSPFNbr::startRxMtLsrTimer...!!!");
long retransmitIntrvl = ospfInterface.reTransmitInterval();
rxmtLsrPacketTask = new InternalRxmtLsrPacket(ch);
exServiceRxmtLsr = Executors.newSingleThreadScheduledExecutor();
exServiceRxmtLsr.scheduleAtFixedRate(rxmtLsrPacketTask, retransmitIntrvl,
retransmitIntrvl, TimeUnit.SECONDS);
rxmtLsrTimerScheduled = true;
}
}
/**
* Stops Ls request retransmission executor task.
*/
private void stopRxMtLsrTimer() {
if (rxmtLsrTimerScheduled) {
exServiceRxmtLsr.shutdown();
rxmtLsrTimerScheduled = false;
}
}
/**
* Gets the last sent DdPacket.
*
* @return DdPacket instance
*/
public DdPacket lastDdPacket() {
return lastDdPacket;
}
/**
* Sets the last sent DdPacket.
*
* @param lastDdPacket DdPacket instance
*/
public void setLastDdPacket(DdPacket lastDdPacket) {
this.lastDdPacket = lastDdPacket;
}
/**
* Gets neighbor id.
*
* @return neighbor id
*/
public Ip4Address neighborId() {
return neighborId;
}
/**
* Sets the neighbor id.
*
* @param neighborId neighbor id
*/
public void setNeighborId(Ip4Address neighborId) {
this.neighborId = neighborId;
}
/**
* Gets the neighbor DR address.
*
* @return neighbor DR address
*/
public Ip4Address neighborDr() {
return neighborDr;
}
/**
* Sets the neighbor DR address.
*
* @param neighborDr neighbor DR address
*/
public void setNeighborDr(Ip4Address neighborDr) {
this.neighborDr = neighborDr;
}
/**
* Gets the neighbor BDR address.
*
* @return neighbor BDR address
*/
public Ip4Address neighborBdr() {
return neighborBdr;
}
/**
* Sets the neighbor BDR address.
*
* @param neighborBdr neighbor BDR address
*/
public void setNeighborBdr(Ip4Address neighborBdr) {
this.neighborBdr = neighborBdr;
}
/**
* Gets router priority.
*
* @return router priority
*/
public int routerPriority() {
return routerPriority;
}
/**
* Sets router priority.
*
* @param routerPriority router priority
*/
public void setRouterPriority(int routerPriority) {
this.routerPriority = routerPriority;
}
/**
* Gets the options value.
*
* @return options value
*/
public int options() {
return options;
}
/**
* Sets the options value.
*
* @param options options value
*/
public void setOptions(int options) {
this.options = options;
}
/**
* Gets the DD sequence number.
*
* @return DD sequence number
*/
public long ddSeqNum() {
return ddSeqNum;
}
/**
* Sets the DD sequence number.
*
* @param ddSeqNum DD sequence number
*/
public void setDdSeqNum(long ddSeqNum) {
this.ddSeqNum = ddSeqNum;
}
/**
* Gets neighbor is master or not.
*
* @return true if neighbor is master else false
*/
public int isMaster() {
return isMaster;
}
/**
* Gets the last sent DD Packet.
*
* @return last sent DD Packet
*/
public DdPacket lastSentDdPacket() {
return lastSentDdPacket;
}
/**
* Sets the last sent DD Packet.
*
* @param lastSentDdPacket last sent DD Packet
*/
public void setLastSentDdPacket(DdPacket lastSentDdPacket) {
this.lastSentDdPacket = lastSentDdPacket;
}
/**
* Gets the last sent Ls Request Packet.
*
* @return last sent Ls Request Packet
*/
public LsRequest getLastSentLsrPacket() {
return lastSentLsrPacket;
}
/**
* Sets the last sent Ls Request Packet.
*
* @param lastSentLsrPacket last sent Ls Request Packet
*/
public void setLastSentLsrPacket(LsRequest lastSentLsrPacket) {
this.lastSentLsrPacket = lastSentLsrPacket;
}
/**
* Gets the neighbors state.
*
* @return neighbors state
*/
public OspfNeighborState getState() {
return state;
}
/**
* Sets the neighbors state.
*
* @param state neighbors state
*/
public void setState(OspfNeighborState state) {
this.state = state;
}
/**
* Sets neighbor is master or not.
*
* @param isMaster neighbor is master or not
*/
public void setIsMaster(int isMaster) {
this.isMaster = isMaster;
}
/**
* Gets the ls request list.
*
* @return ls request list
*/
public Hashtable getLsReqList() {
return lsReqList;
}
/**
* Gets the reTxList instance.
*
* @return reTxList instance
*/
public Map getReTxList() {
return reTxList;
}
/**
* Gets the pending re transmit list.
*
* @return pendingReTxList instance
*/
public Map<String, OspfLsa> getPendingReTxList() {
return pendingReTxList;
}
/**
* Represents a Task which will do an inactivity time check.
*/
private class InternalInactivityTimeCheck implements Runnable {
/**
* Constructor.
*/
InternalInactivityTimeCheck() {
}
@Override
public void run() {
try {
log.debug("Neighbor Not Heard till the past router dead interval .");
neighborDown();
} catch (Exception e) {
log.debug("Exception at inactivity time check...!!!");
}
}
}
/**
* Task which re transmits DdPacket every configured time interval.
*/
private class InternalRxmtDdPacket implements Runnable {
Channel ch;
/**
* Creates an instance or Re transmit DD packet timer.
*
* @param ch netty channel instance
*/
InternalRxmtDdPacket(Channel ch) {
this.ch = ch;
}
@Override
public void run() {
if ((ch != null) && ch.isConnected()) {
DdPacket ddPacket = lastSentDdPacket();
ch.write(ddPacket);
log.debug("Re-Transmit DD Packet .");
} else {
log.debug(
"Re-Transmit DD Packet failed. Channel not connected..");
}
}
}
/**
* Task which re transmits Ls request Packet every configured time interval.
*/
private class InternalRxmtLsrPacket implements Runnable {
Channel ch;
/**
* Creates an instance or Re transmit LS Request packet timer.
*
* @param ch netty channel instance
*/
InternalRxmtLsrPacket(Channel ch) {
this.ch = ch;
}
@Override
public void run() {
if ((ch != null) && ch.isConnected()) {
LsRequest lsrPacket = getLastSentLsrPacket();
ch.write(lsrPacket);
log.debug("Re-Transmit LSRequest Packet .");
} else {
log.debug(
"Re-Transmit LSRequest failed. Channel not connected..");
}
}
}
/**
* Task which transmits Ls update Packet based on the re transmit list.
* every configured time interval.
*/
private class InternalFloodingTask implements Runnable {
Channel channel;
/**
* Creates an instance or Flooding task.
*
* @param ch netty channel instance
*/
InternalFloodingTask(Channel ch) {
this.channel = ch;
}
@Override
public void run() {
if ((channel != null) && channel.isConnected()) {
if ((pendingReTxList != null) && (pendingReTxList.size() > 0)) {
List<LsUpdate> lsUpdateList = buildLsUpdate(pendingReTxList);
for (LsUpdate lsupdate : lsUpdateList) {
//Pending for acknowledge directly sent it to neighbor
lsupdate.setDestinationIp(neighborIpAddr);
channel.write(lsupdate);
}
}
if ((reTxList != null) && (reTxList.size() > 0)) {
List<LsUpdate> lsUpdateList = buildLsUpdate(reTxList);
for (LsUpdate lsupdate : lsUpdateList) {
//set the destination
if ((((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR) ||
(((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT)) {
lsupdate.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS);
} else if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER ||
(((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR)) {
lsupdate.setDestinationIp(neighborDr);
}
channel.write(lsupdate);
}
}
}
}
/**
* Builds the LsUpdate for flooding.
*
* @param txList list contains LSAs
* @return list of LsUpdate instances
*/
private List buildLsUpdate(Map<String, OspfLsa> txList) {
List<LsUpdate> lsUpdateList = new ArrayList<>();
ListIterator itr = new ArrayList(txList.keySet()).listIterator();
while (itr.hasNext()) {
LsUpdate lsupdate = new LsUpdate();
// seting OSPF Header
lsupdate.setOspfVer(OspfUtil.OSPF_VERSION);
lsupdate.setOspftype(OspfPacketType.LSUPDATE.value());
lsupdate.setRouterId(ospfArea.routerId());
lsupdate.setAreaId(ospfArea.areaId());
lsupdate.setAuthType(OspfUtil.NOT_ASSIGNED);
lsupdate.setAuthentication(OspfUtil.NOT_ASSIGNED);
lsupdate.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length
lsupdate.setChecksum(OspfUtil.NOT_ASSIGNED);
//limit to mtu
int currentLength = OspfUtil.OSPF_HEADER_LENGTH + OspfUtil.FOUR_BYTES;
int maxSize = ospfInterface.mtu() -
OspfUtil.LSA_HEADER_LENGTH; // subtract a normal IP header.
int noLsa = 0;
while (itr.hasNext()) {
String key = (String) itr.next();
OspfLsa lsa = txList.get(key);
if ((lsa.age() + OspfParameters.INFTRA_NS_DELAY) >= OspfParameters.MAXAGE) {
((LsaHeader) lsa.lsaHeader()).setAge(OspfParameters.MAXAGE);
} else {
((LsaHeader) lsa.lsaHeader()).setAge(lsa.age() + OspfParameters.INFTRA_NS_DELAY);
}
if ((currentLength + ((LsaHeader) lsa.lsaHeader()).lsPacketLen()) >= maxSize) {
itr.previous();
break;
}
log.debug("FloodingTimer::LSA Type::{}, Header: {}, LSA: {}", lsa.getOspfLsaType(),
lsa.lsaHeader(), lsa);
if (lsa != null) {
lsupdate.addLsa(lsa);
noLsa++;
currentLength = currentLength + ((LsaHeader) lsa.lsaHeader()).lsPacketLen();
}
log.debug("FloodingTimer::Removing key {}", key);
if (txList.equals(reTxList)) {
reTxList.remove(key);
pendingReTxList.put(key, lsa);
}
}
//set number of lsa's
lsupdate.setNumberOfLsa(noLsa);
lsUpdateList.add(lsupdate);
}
return lsUpdateList;
}
}
}
\ No newline at end of file
/*
* Copyright 2016 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;
}
}
\ No newline at end of file