blob: 0f7a91c4770aa504ad94306b1d78486c3195732b [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Foundation
*
* 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.OspfMessage;
import org.onosproject.ospf.controller.OspfNbr;
import org.onosproject.ospf.controller.OspfNeighborState;
import org.onosproject.ospf.controller.OspfPacketType;
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.exceptions.OspfParseException;
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.OspfMessageWriter;
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.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 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 topologyForDeviceAndLinkCommon topology for device and link instance
*/
public OspfNbrImpl(OspfArea paramOspfArea, OspfInterface paramOspfInterface,
Ip4Address ipAddr, Ip4Address routerId, int options,
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.topologyForDeviceAndLink = topologyForDeviceAndLinkCommon;
}
/**
* Gets the IP address of this neighbor.
*
* @return the IP address of this neighbor
*/
@Override
public Ip4Address neighborIpAddr() {
return neighborIpAddr;
}
/**
* Gets the neighbor is opaque enabled or not.
*
* @return true if the neighbor is opaque enabled else false.
*/
@Override
public boolean isOpaqueCapable() {
return isOpaqueCapable;
}
/**
* Sets the neighbor is opaque enabled or not.
*
* @param isOpaqueCapable true if the neighbor is opaque enabledelse false
*/
@Override
public void setIsOpaqueCapable(boolean isOpaqueCapable) {
this.isOpaqueCapable = isOpaqueCapable;
}
/**
* Sets router dead interval.
*
* @param routerDeadInterval router dead interval
*/
@Override
public void setRouterDeadInterval(int routerDeadInterval) {
this.routerDeadInterval = routerDeadInterval;
}
/**
* 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
*/
public void twoWayReceived(OspfMessage ospfMessage, Channel channel) {
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());
byte[] messageToWrite = getMessage(ddPacket);
channel.write(messageToWrite);
} 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
*/
public void negotiationDone(OspfMessage ospfMessage,
boolean neighborIsMaster, List payload, Channel ch) {
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 = 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();
byte[] messageToWrite = getMessage(lastSentDdPacket);
ch.write(messageToWrite);
} 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());
byte[] messageToWrite = getMessage(lastSentDdPacket);
ch.write(messageToWrite);
startRxMtDdTimer(ch);
}
}
}
/**
* Process the LSA Headers received in the last received Database Description OSPFMessage.
*
* @param ddPayload LSA headers to process
*/
public void processLsas(List ddPayload) {
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
*/
public OspfMessage seqNumMismatch(String reason) {
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
*/
@Override
public void badLSReq(Channel ch) {
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);
byte[] messageToWrite = getMessage(ddPacket);
ch.write(messageToWrite);
}
}
/**
* 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
*/
public void processDdPacket(boolean neighborIsMaster, DdPacket dataDescPkt,
Channel ch) {
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());
byte[] messageToWrite = getMessage(lastSentDdPacket());
ch.write(messageToWrite);
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());
byte[] messageToWrite = getMessage(ddPacket);
ch.write(messageToWrite);
}
}
/**
* 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());
byte[] messageToWrite = getMessage(lsRequest);
ch.write(messageToWrite);
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
*/
@Override
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);
byte[] messageToWrite = getMessage(ddPacket);
ch.write(messageToWrite);
}
} 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 OspfParseException on parsing error
*/
public void processLsUpdate(LsUpdate lsUpdPkt, Channel ch) throws OspfParseException {
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.
*/
public void loadingDone() {
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, DeviceInformation> deviceInformationMapForPointToPoint =
topologyForDeviceAndLink.deviceInformationMapForPointToPoint();
Map<String, DeviceInformation> deviceInformationMapToDelete =
topologyForDeviceAndLink.deviceInformationMapToDelete();
Map<String, LinkInformation> linkInformationMap = topologyForDeviceAndLink.linkInformationMap();
Map<String, LinkInformation> linkInformationMapForPointToPoint =
topologyForDeviceAndLink.linkInformationMapForPointToPoint();
OspfRouter ospfRouter = new OspfRouterImpl();
if (deviceInformationMap.size() != 0) {
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));
}
((OspfInterfaceImpl) ospfInterface).addDeviceInformation(ospfRouter);
}
}
if (deviceInformationMapForPointToPoint.size() != 0) {
for (String key : deviceInformationMapForPointToPoint.keySet()) {
DeviceInformation value = deviceInformationMapForPointToPoint.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(value.isDr());
int size = value.interfaceId().size();
for (int i = 0; i < size; i++) {
ospfRouter.setInterfaceId(value.interfaceId().get(i));
}
((OspfInterfaceImpl) ospfInterface).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 {
((OspfInterfaceImpl) ospfInterface).addLinkInformation(ospfRouterForLink, ospfLinkTed);
} catch (Exception e) {
log.debug("Exception addLinkInformation: " + 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
* @throws OspfParseException on parsing error
* @return true to remove it from lsReqList else false
*/
public boolean processReceivedLsa(LsaHeader recLsa,
boolean receivedViaFlooding, Channel ch, Ip4Address sourceIp)
throws OspfParseException {
log.debug("OSPFNbr::processReceivedLsa(recLsa, receivedViaFlooding, 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())) {
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.containsValue(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);
}
}
}
constructDeviceInformationFromDb();
callDeviceAndLinkAdding(topologyForDeviceAndLink);
return true;
}
/**
* Constructs device and link information from link state database.
*/
private void constructDeviceInformationFromDb() {
OspfLsdb database = ospfArea.database();
List lsas = database.getAllLsaHeaders(true, true);
Iterator iterator = lsas.iterator();
while (iterator.hasNext()) {
OspfLsa ospfLsa = (OspfLsa) iterator.next();
if (ospfLsa.getOspfLsaType().value() == OspfLsaType.ROUTER.value()) {
topologyForDeviceAndLink.addLocalDevice(ospfLsa, ospfInterface, ospfArea);
} else if (ospfLsa.getOspfLsaType().value() == OspfLsaType.NETWORK.value()) {
topologyForDeviceAndLink.addLocalDevice(ospfLsa, ospfInterface, ospfArea);
}
}
}
/**
* 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.ospfInterfaceList();
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.
*/
public void processSelfOriginatedLsa() {
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);
byte[] messageToWrite = getMessage(responseLsUpdate);
ch.write(messageToWrite);
}
/**
* 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);
byte[] messageToWrite = getMessage(ackContent);
ch.write(messageToWrite);
}
/**
* Called when neighbor is down.
*/
public void neighborDown() {
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)) {
((OspfInterfaceImpl) ospfInterface).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());
((OspfInterfaceImpl) ospfInterface).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());
((OspfInterfaceImpl) ospfInterface).removeDeviceInformation(ospfRouter1);
}
/**
* Removes device details.
*
* @param routerId router id
*/
private void removeDeviceDetails(Ip4Address routerId) {
String key = "device:" + routerId;
topologyForDeviceAndLink.removeDeviceInformationMap(key);
}
/**
* Starts the inactivity timer.
*/
@Override
public 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.
*/
@Override
public 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.
*/
@Override
public 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.
*/
@Override
public 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.
*/
@Override
public 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
*/
@Override
public Ip4Address neighborId() {
return neighborId;
}
/**
* Sets the neighbor id.
*
* @param neighborId neighbor id
*/
@Override
public void setNeighborId(Ip4Address neighborId) {
this.neighborId = neighborId;
}
/**
* Gets the neighbor DR address.
*
* @return neighbor DR address
*/
@Override
public Ip4Address neighborDr() {
return neighborDr;
}
/**
* Sets the neighbor DR address.
*
* @param neighborDr neighbor DR address
*/
@Override
public void setNeighborDr(Ip4Address neighborDr) {
this.neighborDr = neighborDr;
}
/**
* Gets the neighbor BDR address.
*
* @return neighbor BDR address
*/
@Override
public Ip4Address neighborBdr() {
return neighborBdr;
}
/**
* Sets the neighbor BDR address.
*
* @param neighborBdr neighbor BDR address
*/
@Override
public void setNeighborBdr(Ip4Address neighborBdr) {
this.neighborBdr = neighborBdr;
}
/**
* Gets router priority.
*
* @return router priority
*/
@Override
public int routerPriority() {
return routerPriority;
}
/**
* Sets router priority.
*
* @param routerPriority router priority
*/
@Override
public void setRouterPriority(int routerPriority) {
this.routerPriority = routerPriority;
}
/**
* Gets the options value.
*
* @return options value
*/
@Override
public int options() {
return options;
}
/**
* Sets the options value.
*
* @param options options value
*/
@Override
public void setOptions(int options) {
this.options = options;
}
/**
* Gets the DD sequence number.
*
* @return DD sequence number
*/
@Override
public long ddSeqNum() {
return ddSeqNum;
}
/**
* Sets the DD sequence number.
*
* @param ddSeqNum DD sequence number
*/
@Override
public void setDdSeqNum(long ddSeqNum) {
this.ddSeqNum = ddSeqNum;
}
/**
* Gets neighbor is master or not.
*
* @return true if neighbor is master else false
*/
@Override
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
*/
@Override
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
*/
@Override
public void setIsMaster(int isMaster) {
this.isMaster = isMaster;
}
/**
* Gets the ls request list.
*
* @return ls request list
*/
@Override
public Hashtable getLsReqList() {
return lsReqList;
}
/**
* Gets the reTxList instance.
*
* @return reTxList instance
*/
@Override
public Map getReTxList() {
return reTxList;
}
/**
* Gets the pending re transmit list.
*
* @return pendingReTxList instance
*/
@Override
public Map<String, OspfLsa> getPendingReTxList() {
return pendingReTxList;
}
/**
* Gets message as bytes.
*
* @param ospfMessage OSPF message
* @return OSPF message
*/
private byte[] getMessage(OspfMessage ospfMessage) {
OspfMessageWriter messageWriter = new OspfMessageWriter();
if (((OspfInterfaceImpl) ospfInterface).state().equals(OspfInterfaceState.POINT2POINT)) {
ospfMessage.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS);
}
return (messageWriter.getMessage(ospfMessage, ospfInterface.interfaceIndex(),
((OspfInterfaceImpl) ospfInterface).state().value()));
}
/**
* 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();
byte[] messageToWrite = getMessage(ddPacket);
ch.write(messageToWrite);
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();
byte[] messageToWrite = getMessage(lsrPacket);
ch.write(messageToWrite);
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);
byte[] messageToWrite = getMessage(lsupdate);
channel.write(messageToWrite);
}
}
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);
}
byte[] messageToWrite = getMessage(lsupdate);
channel.write(messageToWrite);
}
}
}
}
/**
* 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 != null) {
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);
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;
}
}
}