blob: be503c2332a897dd56c3fdd9393c0f4d0b8cd23c [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.area;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.onlab.packet.Ip4Address;
import org.onosproject.ospf.controller.LsaWrapper;
import org.onosproject.ospf.controller.OspfArea;
import org.onosproject.ospf.controller.OspfInterface;
import org.onosproject.ospf.controller.OspfLinkTed;
import org.onosproject.ospf.controller.OspfLsa;
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.impl.Controller;
import org.onosproject.ospf.controller.impl.OspfNbrImpl;
import org.onosproject.ospf.controller.impl.TopologyForDeviceAndLinkImpl;
import org.onosproject.ospf.controller.lsdb.LsaWrapperImpl;
import org.onosproject.ospf.controller.lsdb.OspfLsdbImpl;
import org.onosproject.ospf.controller.util.OspfEligibleRouter;
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.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.HelloPacket;
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.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* Representation of an OSPF interface.
*/
public class OspfInterfaceImpl implements OspfInterface {
private static final Logger log = LoggerFactory.getLogger(OspfInterfaceImpl.class);
private int interfaceIndex;
private Ip4Address ipAddress;
private Ip4Address ipNetworkMask;
private Channel channel = null;
private int helloIntervalTime;
private int routerDeadIntervalTime;
private int routerPriority;
private int interfaceType;
private int mtu;
private int reTransmitInterval;
private Ip4Address dr;
private Ip4Address bdr;
private OspfInterfaceState state;
private List<LsaHeader> linkStateHeaders = new ArrayList<>();
private Map<String, OspfNbr> listOfNeighbors = new ConcurrentHashMap<>();
private Map<String, LsaHeader> listOfNeighborMap = new ConcurrentHashMap<>();
private long delay = 0;
private InternalHelloTimer helloTimerTask;
private InternalWaitTimer waitTimerTask;
private InternalDelayedAckTimer delayedAckTimerTask;
private ScheduledExecutorService exServiceHello;
private ScheduledExecutorService exServiceWait;
private ScheduledExecutorService exServiceDelayedAck;
private boolean isDelayedAckTimerScheduled = false;
private int delayedAckTimerInterval = 2500;
private int interfaceTypeOldValue = 0;
private TopologyForDeviceAndLink topologyForDeviceAndLink = new TopologyForDeviceAndLinkImpl();
private OspfArea ospfArea;
private Controller controller;
/**
* Gets the interface state.
*
* @return interfaceState state of the interface
*/
public OspfInterfaceState state() {
return state;
}
/**
* Sets the interface state.
*
* @param ospfInterfaceState interface state enum instance
*/
public void setState(OspfInterfaceState ospfInterfaceState) {
this.state = ospfInterfaceState;
}
/**
* Sets the netty channel.
*
* @param channel channel
*/
public void setChannel(Channel channel) {
this.channel = channel;
}
/**
* Returns OSPF area instance.
*
* @return OSPF area instance
*/
@Override
public OspfArea ospfArea() {
return ospfArea;
}
/**
* Sets OSPF controller instance.
*
* @param controller OSPF controller instance
*/
public void setController(Controller controller) {
this.controller = controller;
}
/**
* Sets OSPF area instance.
*
* @param ospfArea OSPF area instance
*/
@Override
public void setOspfArea(OspfArea ospfArea) {
this.ospfArea = ospfArea;
}
/**
* Gets interface state.
*
* @return interface state
*/
public String interfaceState() {
return state.interfaceState();
}
/**
* Gets link state headers.
*
* @return get the list of lsa headers
*/
public List<LsaHeader> linkStateHeaders() {
Set<String> key = listOfNeighborMap.keySet();
for (String keys : key) {
LsaHeader lsaHeader = listOfNeighborMap.get(keys);
linkStateHeaders.add(lsaHeader);
}
return linkStateHeaders;
}
/**
* Gets IP network mask.
*
* @return network mask
*/
@Override
public Ip4Address ipNetworkMask() {
return ipNetworkMask;
}
/**
* Sets IP network mask.
*
* @param ipNetworkMask network mask
*/
@Override
public void setIpNetworkMask(Ip4Address ipNetworkMask) {
this.ipNetworkMask = ipNetworkMask;
}
/**
* Adds neighboring router to list.
*
* @param ospfNbr ospfNbr instance
*/
@Override
public void addNeighbouringRouter(OspfNbr ospfNbr) {
listOfNeighbors.put(ospfNbr.neighborId().toString(), ospfNbr);
}
/**
* Gets the neighbour details from listOfNeighbors map.
*
* @param neighborId neighbors id
* @return ospfNbr neighbor instance
*/
@Override
public OspfNbr neighbouringRouter(String neighborId) {
return listOfNeighbors.get(neighborId);
}
/**
* Removes all the neighbors.
*/
@Override
public void removeNeighbors() {
Set<String> neighbors = listOfNeighbors.keySet();
for (String neighborId : neighbors) {
removeNeighbor(listOfNeighbors.get(neighborId));
log.debug("Neighbor removed - {}", neighborId);
}
listOfNeighbors.clear();
}
/**
* Removes neighbor from the interface neighbor map.
*
* @param ospfNeighbor OSPF neighbor instance
*/
public void removeNeighbor(OspfNbr ospfNeighbor) {
log.debug("Neighbor removed - {}", ospfNeighbor.neighborId());
ospfNeighbor.stopInactivityTimeCheck();
ospfNeighbor.stopFloodingTimer();
ospfNeighbor.stopRxMtDdTimer();
ospfNeighbor.stopRxMtLsrTimer();
listOfNeighbors.remove(ospfNeighbor.neighborId().toString());
}
/**
* Adds LSA header to map.
*
* @param lsaHeader LSA header instance
*/
public void addLsaHeaderForDelayAck(LsaHeader lsaHeader) {
String key = lsaHeader.lsType() + "-" + lsaHeader.linkStateId() + "-" +
lsaHeader.advertisingRouter();
if (lsaHeader.lsType() == OspfParameters.LINK_LOCAL_OPAQUE_LSA ||
lsaHeader.lsType() == OspfParameters.AREA_LOCAL_OPAQUE_LSA ||
lsaHeader.lsType() == OspfParameters.AS_OPAQUE_LSA) {
OpaqueLsaHeader header = (OpaqueLsaHeader) lsaHeader;
key = lsaHeader.lsType() + "-" + header.opaqueType() + header.opaqueId()
+ "-" + lsaHeader.advertisingRouter();
}
log.debug("Adding LSA key {} for delayed Ack", key);
listOfNeighborMap.put(key, lsaHeader);
}
/**
* Removes LSA header from map.
*
* @param lsaKey key used to store LSA in map
*/
@Override
public void removeLsaFromNeighborMap(String lsaKey) {
listOfNeighborMap.remove(lsaKey);
}
/**
* Checks neighbor is in the list or not.
*
* @param neighborId neighbors id
* @return true if neighbor in list else false
*/
@Override
public boolean isNeighborInList(String neighborId) {
return listOfNeighbors.containsKey(neighborId);
}
/**
* Gets the list of neighbors.
*
* @return listOfNeighbors as key value pair
*/
@Override
public Map<String, OspfNbr> listOfNeighbors() {
return listOfNeighbors;
}
/**
* Sets the list of neighbors.
*
* @param listOfNeighbors as key value pair
*/
public void setListOfNeighbors(HashMap<String, OspfNbr> listOfNeighbors) {
this.listOfNeighbors = listOfNeighbors;
}
/**
* Returns interface index.
*
* @return interface index
*/
@Override
public int interfaceIndex() {
return interfaceIndex;
}
/**
* Set interface index.
*
* @param interfaceIndex interface index
*/
@Override
public void setInterfaceIndex(int interfaceIndex) {
this.interfaceIndex = interfaceIndex;
}
/**
* Gets the IP address.
*
* @return IP address
*/
@Override
public Ip4Address ipAddress() {
return ipAddress;
}
/**
* Sets the interface IP address.
*
* @param ipAddress interface IP address
*/
@Override
public void setIpAddress(Ip4Address ipAddress) {
this.ipAddress = ipAddress;
}
/**
* Gets router priority.
*
* @return routerPriority value
*/
@Override
public int routerPriority() {
return routerPriority;
}
/**
* Sets router priority.
*
* @param routerPriority value
*/
@Override
public void setRouterPriority(int routerPriority) {
this.routerPriority = routerPriority;
}
/**
* Gets hello interval time.
*
* @return hello interval time
*/
@Override
public int helloIntervalTime() {
return helloIntervalTime;
}
/**
* Sets hello interval time.
*
* @param helloIntervalTime an integer interval time
*/
@Override
public void setHelloIntervalTime(int helloIntervalTime) {
this.helloIntervalTime = helloIntervalTime;
}
/**
* Gets router dead interval time.
*
* @return router dead interval time
*/
@Override
public int routerDeadIntervalTime() {
return routerDeadIntervalTime;
}
/**
* Sets router dead interval time.
*
* @param routerDeadIntervalTime router dead interval time
*/
@Override
public void setRouterDeadIntervalTime(int routerDeadIntervalTime) {
this.routerDeadIntervalTime = routerDeadIntervalTime;
}
/**
* Gets interface type.
*
* @return interfaceType an integer represents interface type
*/
@Override
public int interfaceType() {
return interfaceType;
}
/**
* Sets interface type.
*
* @param interfaceType interface type
*/
@Override
public void setInterfaceType(int interfaceType) {
this.interfaceType = interfaceType;
}
/**
* Gets max transfer unit.
*
* @return mtu an integer represents max transfer unit
*/
@Override
public int mtu() {
return mtu;
}
/**
* Sets max transfer unit.
*
* @param mtu max transfer unit
*/
@Override
public void setMtu(int mtu) {
this.mtu = mtu;
}
/**
* Gets retransmit interval.
*
* @return retransmit interval
*/
@Override
public int reTransmitInterval() {
return reTransmitInterval;
}
/**
* Sets retransmit interval.
*
* @param reTransmitInterval retransmit interval
*/
@Override
public void setReTransmitInterval(int reTransmitInterval) {
this.reTransmitInterval = reTransmitInterval;
}
/**
* Gets designated routers IP address.
*
* @return dr designated routers IP address
*/
@Override
public Ip4Address dr() {
return dr;
}
/**
* Sets designated routers IP address.
*
* @param dr designated routers IP address
*/
@Override
public void setDr(Ip4Address dr) {
this.dr = dr;
}
/**
* Gets backup designated routers IP address.
*
* @return bdr backup designated routers IP address
*/
@Override
public Ip4Address bdr() {
return bdr;
}
/**
* Sets backup designated routers IP address.
*
* @param bdr backup designated routers IP address
*/
@Override
public void setBdr(Ip4Address bdr) {
this.bdr = bdr;
}
/**
* Represents an interface is up and connected.
*/
@Override
public void interfaceUp() {
log.debug("OSPFInterfaceChannelHandler::interfaceUp...!!!");
if (interfaceType() == OspfInterfaceType.POINT_TO_POINT.value()) {
setState(OspfInterfaceState.POINT2POINT);
interfaceTypeOldValue = interfaceType();
log.debug("OSPFInterfaceChannelHandler::InterfaceType {} state {} ",
interfaceType(), state());
} else if (interfaceType() == OspfInterfaceType.BROADCAST.value()) {
//if router priority is 0, move the state to DROther
interfaceTypeOldValue = interfaceType();
if (routerPriority() == 0) {
setState(OspfInterfaceState.DROTHER);
} else {
log.debug("OSPFInterfaceChannelHandler::InterfaceType {} state {} RouterPriority {}",
interfaceType(),
state(), routerPriority());
setState(OspfInterfaceState.WAITING);
//start wait timer - like inactivity timer with router deadInterval
startWaitTimer();
}
}
// Start hello timer with interval from config - convert seconds to milliseconds
startHelloTimer();
ospfArea.refreshArea(this);
}
/**
* Gets called when a BDR was detected before the wait timer expired.
*
* @param ch channel instance
*/
public void backupSeen(Channel ch) {
log.debug("OSPFInterfaceChannelHandler::backupSeen ");
if (state() == OspfInterfaceState.WAITING) {
electRouter(ch);
}
}
/**
* Gets called when no hello message received for particular period.
*
* @param ch channel instance
*/
public void waitTimer(Channel ch) {
log.debug("OSPFInterfaceChannelHandler::waitTimer ");
//According to RFC-2328 section 9.4
if (state() == OspfInterfaceState.WAITING) {
electRouter(ch);
}
}
/**
* Initiates DR election process.
*
* @param ch netty channel instance
*/
public void callDrElection(Channel ch) {
log.debug("OSPFInterfaceChannelHandler::callDrElection ");
//call when timer expired
//no hello message received for particular interval
//section 9.4
electRouter(ch);
interfaceTypeOldValue = interfaceType();
}
/**
* Neighbor change event is triggered when the router priority gets changed.
*/
public void neighborChange() {
log.debug("OSPFInterfaceChannelHandler::neighborChange ");
if (state() == OspfInterfaceState.DR || state() == OspfInterfaceState.BDR ||
state() == OspfInterfaceState.DROTHER) {
electRouter(channel);
}
}
/**
* Gets called when an interface is down.
* All interface variables are reset, and interface timers disabled.
* Also all neighbor connections associated with the interface are destroyed.
*/
@Override
public void interfaceDown() {
log.debug("OSPFInterfaceChannelHandler::interfaceDown ");
stopHelloTimer();
listOfNeighbors().clear();
setState(OspfInterfaceState.DOWN);
}
/**
* When an OSPF message received it is handed over to this method.
* Based on the type of the OSPF message received it will be handed over
* to corresponding message handler methods.
*
* @param ospfMessage received OSPF message
* @param ctx channel handler context instance.
*/
@Override
public void processOspfMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) {
log.debug("OspfChannelHandler::processOspfMessage...!!!");
if (!validateMessage(ospfMessage)) {
return;
}
try {
switch (ospfMessage.ospfMessageType().value()) {
case OspfParameters.HELLO:
processHelloMessage(ospfMessage, ctx);
break;
case OspfParameters.DD:
processDdMessage(ospfMessage, ctx);
break;
case OspfParameters.LSREQUEST:
processLsRequestMessage(ospfMessage, ctx);
break;
case OspfParameters.LSUPDATE:
processLsUpdateMessage(ospfMessage, ctx);
break;
case OspfParameters.LSACK:
processLsAckMessage(ospfMessage, ctx);
break;
default:
log.debug("Unknown packet to process...!!!");
break;
}
} catch (OspfParseException ope) {
log.debug("Error parsing packet", ope);
}
}
/**
* Validates the OSPF message received.
*
* @param ospfMessage OSPF message.
* @return true if it is a valid else false.
*/
private boolean validateMessage(OspfMessage ospfMessage) {
boolean isValid = true;
OspfPacketHeader header = (OspfPacketHeader) ospfMessage;
//added the check to eliminate self origin packets also two interfaces on same router.
if (!header.sourceIp().equals(ipAddress()) && !header.routerId().equals(
ospfArea.routerId())) {
//Verify the checksum
ChecksumCalculator checksum = new ChecksumCalculator();
if (!checksum.isValidOspfCheckSum(ospfMessage, OspfUtil.OSPFPACKET_CHECKSUM_POS1,
OspfUtil.OSPFPACKET_CHECKSUM_POS2)) {
log.debug("Checksum mismatch. Received packet type {} ", ospfMessage.ospfMessageType());
return false;
}
if (((OspfPacketHeader) ospfMessage).ospfVersion() != OspfUtil.OSPF_VERSION_2) {
log.debug("Received osfpMessage Version should match with Interface Version ");
return false;
}
if (!((OspfPacketHeader) ospfMessage).areaId().equals(ospfArea.areaId())) {
log.debug("Received ospf packets are from different area than our Area ID. " +
"Received Area ID {}, Our AreaId {} ",
((OspfPacketHeader) ospfMessage).areaId(), ospfArea.areaId());
return false;
}
//According to RFC-2328 (8.2)
/*
* ABR should receive packets from backbone 0.0.0.0 as we are not acting as ABR
* we are rejecting the packet.
*/
if (((OspfPacketHeader) ospfMessage).areaId().equals(Ip4Address.valueOf("0.0.0.0"))) {
log.debug("ABR should receive packets from backbone 0.0.0.0 as we are not acting as " +
"ABR we are rejecting the ospf packet");
return false;
}
if (interfaceType() == OspfInterfaceType.BROADCAST.value() &&
!OspfUtil.sameNetwork(((OspfPacketHeader) ospfMessage).sourceIp(),
ipAddress(), ipNetworkMask())) {
log.debug("Received packets from different subnets. Discarding...!!!");
return false;
}
} else {
isValid = false;
}
return isValid;
}
/**
* Processes Hello message.
*
* @param ospfMessage OSPF message instance.
* @param ctx context instance.
*/
void processHelloMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) {
Channel channel = ctx.getChannel();
log.debug("OspfChannelHandler::processHelloMessage...!!!");
HelloPacket helloPacket = (HelloPacket) ospfMessage;
// processing of hello packet as per RFC 2328 section 10.5
log.debug("OspfChannelHandler::processHelloMessage::Interface Type {} OSPFInterfaceState {} ",
interfaceType(), state());
if (interfaceType() != OspfInterfaceType.POINT_TO_POINT.value()) {
if (!helloPacket.networkMask().equals(ipNetworkMask())) {
log.debug("OspfChannelHandler::processHelloMessage::Hello Packet Received does not " +
"match the same network mask as the configure Interface");
return;
}
}
if (helloPacket.helloInterval() != helloIntervalTime()) {
log.debug("OspfChannelHandler::processHelloMessage::Hello Packet Received have the same " +
"hello interval as configured Interface");
return;
}
if (helloPacket.routerDeadInterval() != routerDeadIntervalTime()) {
log.debug("OspfChannelHandler::processHelloMessage::Hello Packet Received have the same " +
"Router Dead interval as configured Interface");
return;
}
if (interfaceType == OspfInterfaceType.POINT_TO_POINT.value() &&
!helloPacket.dr().equals(OspfUtil.DEFAULTIP)) {
log.debug("OspfChannelHandler::processHelloMessage:: Neighbor in broadcast network");
return;
}
if (interfaceType == OspfInterfaceType.POINT_TO_POINT.value()) {
// to verify if the neighbor which sent the hello is present in the OSPF Interface neighboring list .
OspfNbr nbr;
if (!isNeighborInList(helloPacket.routerId().toString())) {
nbr = new OspfNbrImpl(ospfArea, this, helloPacket.sourceIp(),
helloPacket.routerId(), helloPacket.options(), topologyForDeviceAndLink);
addNeighbouringRouter(nbr);
} else {
nbr = neighbouringRouter(helloPacket.routerId().toString());
nbr.setRouterPriority(helloPacket.routerPriority());
}
if (!helloPacket.containsNeighbour(ospfArea.routerId())) {
((OspfNbrImpl) nbr).oneWayReceived(helloPacket, channel);
} else {
((OspfNbrImpl) nbr).twoWayReceived(helloPacket, ctx.getChannel());
}
} else if (interfaceType == OspfInterfaceType.BROADCAST.value()) {
if (state() == OspfInterfaceState.WAITING) {
if ((!helloPacket.dr().equals(Ip4Address.valueOf("0.0.0.0"))) &&
(!helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0")))) {
stopWaitTimer();
setDr(helloPacket.dr());
setBdr(helloPacket.bdr());
if (helloPacket.dr().equals(ipAddress())) {
setState(OspfInterfaceState.DR);
//refresh router Lsa
ospfArea.refreshArea(this);
} else if (helloPacket.bdr().equals(ipAddress())) {
setState(OspfInterfaceState.BDR);
//refresh router Lsa
ospfArea.refreshArea(this);
} else {
setState(OspfInterfaceState.DROTHER);
ospfArea.refreshArea(this);
}
} else if (!helloPacket.dr().equals(Ip4Address.valueOf("0.0.0.0")) ||
!helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0"))) {
setDr(helloPacket.dr());
setBdr(helloPacket.bdr());
}
Ip4Address sourceIp = helloPacket.sourceIp();
OspfNbr nbr;
if (!isNeighborInList(helloPacket.routerId().toString())) {
nbr = new OspfNbrImpl(ospfArea, this, sourceIp, helloPacket.routerId(),
helloPacket.options(), topologyForDeviceAndLink);
nbr.setNeighborId(helloPacket.routerId());
nbr.setNeighborBdr(helloPacket.bdr());
nbr.setNeighborDr(helloPacket.dr());
nbr.setRouterPriority(helloPacket.routerPriority());
addNeighbouringRouter(nbr);
} else {
nbr = neighbouringRouter(helloPacket.routerId().toString());
nbr.setRouterPriority(helloPacket.routerPriority());
}
if (!helloPacket.containsNeighbour(ospfArea.routerId())) {
((OspfNbrImpl) nbr).oneWayReceived(helloPacket, channel);
} else {
((OspfNbrImpl) nbr).twoWayReceived(helloPacket, ctx.getChannel());
}
if (helloPacket.dr().equals(sourceIp)) {
if (helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0"))) {
// call backup seen
stopWaitTimer();
backupSeen(ctx.getChannel());
}
}
if (helloPacket.bdr().equals(sourceIp)) {
// call backup seen
stopWaitTimer();
backupSeen(ctx.getChannel());
}
} else {
if ((!helloPacket.dr().equals(Ip4Address.valueOf("0.0.0.0")) ||
!helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0")))
&& routerPriority() == 0) {
setDr(helloPacket.dr());
setBdr(helloPacket.bdr());
}
//To verify if the neighbor which sent the hello is present in the OSPF Interface neighboring list .
Ip4Address sourceIp = helloPacket.sourceIp();
OspfNbr nbr;
if (!isNeighborInList(helloPacket.routerId().toString())) {
nbr = new OspfNbrImpl(ospfArea, this, sourceIp, helloPacket.routerId(),
helloPacket.options(), topologyForDeviceAndLink);
nbr.setNeighborId(helloPacket.routerId());
nbr.setNeighborBdr(helloPacket.bdr());
nbr.setNeighborDr(helloPacket.dr());
nbr.setRouterPriority(helloPacket.routerPriority());
addNeighbouringRouter(nbr);
((OspfNbrImpl) nbr).oneWayReceived(helloPacket, channel);
} else {
log.debug("OspfChannelHandler::NeighborInList::helloPacket.bdr(): {}, " +
"helloPacket.dr(): {}", helloPacket.bdr(), helloPacket.dr());
nbr = neighbouringRouter(helloPacket.routerId().toString());
nbr.setRouterPriority(helloPacket.routerPriority());
if (!helloPacket.containsNeighbour(ospfArea.routerId())) {
((OspfNbrImpl) nbr).oneWayReceived(helloPacket, channel);
} else {
((OspfNbrImpl) nbr).twoWayReceived(helloPacket, ctx.getChannel());
}
if (nbr.routerPriority() != helloPacket.routerPriority()) {
nbr.setNeighborBdr(helloPacket.bdr());
nbr.setNeighborDr(helloPacket.dr());
neighborChange();
}
if (nbr.neighborIpAddr().equals(helloPacket.dr()) &&
!(nbr.neighborIpAddr().equals(nbr.neighborDr()))) {
nbr.setNeighborBdr(helloPacket.bdr());
nbr.setNeighborDr(helloPacket.dr());
neighborChange();
}
if (!(nbr.neighborIpAddr().equals(helloPacket.dr())) &&
(nbr.neighborIpAddr().equals(nbr.neighborDr()))) {
nbr.setNeighborBdr(helloPacket.bdr());
nbr.setNeighborDr(helloPacket.dr());
neighborChange();
}
if (nbr.neighborIpAddr().equals(helloPacket.bdr()) &&
!(nbr.neighborIpAddr().equals(nbr.neighborBdr()))) {
nbr.setNeighborBdr(helloPacket.bdr());
nbr.setNeighborDr(helloPacket.dr());
neighborChange();
}
if (!(nbr.neighborIpAddr().equals(helloPacket.bdr())) &&
(nbr.neighborIpAddr().equals(nbr.neighborBdr()))) {
nbr.setNeighborBdr(helloPacket.bdr());
nbr.setNeighborDr(helloPacket.dr());
neighborChange();
}
nbr.setNeighborBdr(helloPacket.bdr());
nbr.setNeighborDr(helloPacket.dr());
}
}
}
}
/**
* process the DD message which received.
*
* @param ospfMessage OSPF message instance.
* @param ctx channel handler context instance
*/
void processDdMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) {
log.debug("OspfChannelHandler::processDdMessage...!!!");
Channel channel = ctx.getChannel();
DdPacket ddPacket = (DdPacket) ospfMessage;
log.debug("Got DD packet from {}", ddPacket.sourceIp());
//check it is present in listOfNeighbors
Ip4Address neighbourId = ddPacket.routerId();
OspfNbr nbr = neighbouringRouter(neighbourId.toString());
if (nbr != null) {
log.debug("OspfChannelHandler::processDdMessage:: OSPFNeighborState {}", nbr.getState());
// set options for the NBR
nbr.setIsOpaqueCapable(ddPacket.isOpaqueCapable());
if (ddPacket.imtu() > mtu()) {
log.debug("the MTU size is greater than the interface MTU");
return;
}
if (nbr.getState() == OspfNeighborState.DOWN) {
return;
}
if (nbr.getState() == OspfNeighborState.ATTEMPT) {
return;
}
if (nbr.getState() == OspfNeighborState.TWOWAY) {
nbr.adjOk(channel);
return;
}
//if init is the state call twoWayReceived
if (nbr.getState() == OspfNeighborState.INIT) {
((OspfNbrImpl) nbr).twoWayReceived(ddPacket, ctx.getChannel());
} else if (nbr.getState() == OspfNeighborState.EXSTART) {
//get I,M,MS Bits
int initialize = ddPacket.isInitialize();
int more = ddPacket.isMore();
int masterOrSlave = ddPacket.isMaster();
int options = ddPacket.options();
nbr.setOptions(options);
if (initialize == OspfUtil.INITIALIZE_SET && more == OspfUtil.MORE_SET &&
masterOrSlave == OspfUtil.IS_MASTER) {
if (ddPacket.getLsaHeaderList().isEmpty()) {
if (OspfUtil.ipAddressToLong(ddPacket.routerId().toString()) >
OspfUtil.ipAddressToLong(ospfArea.routerId().toString())) {
nbr.setIsMaster(OspfUtil.IS_MASTER);
((OspfNbrImpl) nbr).setLastDdPacket(ddPacket);
nbr.setDdSeqNum(ddPacket.sequenceNo());
nbr.setOptions(ddPacket.options());
((OspfNbrImpl) nbr).negotiationDone(ddPacket, true, ddPacket.getLsaHeaderList(),
ctx.getChannel());
}
}
}
if (initialize == OspfUtil.INITIALIZE_NOTSET && masterOrSlave == OspfUtil.NOT_MASTER) {
if (nbr.ddSeqNum() == ddPacket.sequenceNo()) {
if (OspfUtil.ipAddressToLong(ddPacket.routerId().toString()) <
OspfUtil.ipAddressToLong(ospfArea.routerId().toString())) {
((OspfNbrImpl) nbr).setLastDdPacket(ddPacket);
nbr.setOptions(ddPacket.options());
nbr.setDdSeqNum(nbr.ddSeqNum() + 1);
((OspfNbrImpl) nbr).negotiationDone(ddPacket, false, ddPacket.getLsaHeaderList(),
ctx.getChannel());
}
}
}
} else if (nbr.getState() == OspfNeighborState.EXCHANGE) {
//get I,M,MS Bits
log.debug("Neighbor state:: EXCHANGE");
boolean isDuplicateDDPacket = compareDdPackets(ddPacket, ((OspfNbrImpl) nbr).lastDdPacket());
int initialize = ddPacket.isInitialize();
int more = ddPacket.isMore();
int masterOrSlave = ddPacket.isMaster();
int options = ddPacket.options();
if (!isDuplicateDDPacket) {
//if dd packet is not duplicate then continue
if (nbr.isMaster() != masterOrSlave) {
DdPacket newResPacket =
(DdPacket) ((OspfNbrImpl) nbr).seqNumMismatch("Master/Slave Inconsistency");
newResPacket.setDestinationIp(ddPacket.sourceIp());
log.debug("Sending back DDPacket to {}", ddPacket.sourceIp());
byte[] messageToWrite = getMessage(newResPacket);
ctx.getChannel().write(messageToWrite);
} else if (initialize == 1) {
DdPacket newResPacket =
(DdPacket) ((OspfNbrImpl) nbr).seqNumMismatch("Initialize bit inconsistency");
newResPacket.setDestinationIp(ddPacket.sourceIp());
log.debug("Sending back DDPacket to {}", ddPacket.sourceIp());
byte[] messageToWrite = getMessage(newResPacket);
ctx.getChannel().write(messageToWrite);
} else {
if (masterOrSlave == OspfUtil.NOT_MASTER) {
if (ddPacket.sequenceNo() == nbr.ddSeqNum()) {
//Process the DD Packet
((OspfNbrImpl) nbr).processDdPacket(false, ddPacket, ctx.getChannel());
log.debug("Received DD Packet");
} else {
DdPacket newResPacket =
(DdPacket) ((OspfNbrImpl) nbr).seqNumMismatch("Sequence Number Mismatch");
newResPacket.setDestinationIp(ddPacket.sourceIp());
log.debug("Sending back DDPacket to {}", ddPacket.sourceIp());
byte[] messageToWrite = getMessage(newResPacket);
ctx.getChannel().write(messageToWrite);
}
} else {
//we are the slave
if (ddPacket.sequenceNo() == (nbr.ddSeqNum() + 1)) {
((OspfNbrImpl) nbr).setLastDdPacket(ddPacket);
((OspfNbrImpl) nbr).processDdPacket(true, ddPacket, ctx.getChannel());
log.debug("Process DD Packet");
} else {
DdPacket newResPacket =
(DdPacket) ((OspfNbrImpl) nbr).seqNumMismatch("options inconsistency");
newResPacket.setDestinationIp(ddPacket.sourceIp());
log.debug("Sending back DDPacket to {}", ddPacket.sourceIp());
byte[] messageToWrite = getMessage(newResPacket);
ctx.getChannel().write(messageToWrite);
}
}
}
} else {
if (masterOrSlave == OspfUtil.NOT_MASTER) {
return;
} else {
DdPacket newResPacket = ((OspfNbrImpl) nbr).lastSentDdPacket();
log.debug("Sending back DDPacket to {}", ddPacket.sourceIp());
byte[] messageToWrite = getMessage(newResPacket);
ctx.getChannel().write(messageToWrite);
}
}
} else if (nbr.getState() == OspfNeighborState.LOADING || nbr.getState() == OspfNeighborState.FULL) {
//In case if we are slave then we have to send the last received DD Packet
int options = ddPacket.options();
if (nbr.options() != options) {
OspfMessage newResPacket = ((OspfNbrImpl) nbr).seqNumMismatch("Initialize bit inconsistency");
newResPacket.setDestinationIp(ddPacket.sourceIp());
byte[] messageToWrite = getMessage(newResPacket);
ctx.getChannel().write(messageToWrite);
} else if (ddPacket.isInitialize() == OspfUtil.INITIALIZE_SET) {
OspfMessage newResPacket = ((OspfNbrImpl) nbr).seqNumMismatch("Initialize bit inconsistency");
newResPacket.setDestinationIp(ddPacket.sourceIp());
byte[] messageToWrite = getMessage(newResPacket);
ctx.getChannel().write(messageToWrite);
}
boolean isDuplicate = compareDdPackets(ddPacket, ((OspfNbrImpl) nbr).lastDdPacket());
//we are master
if (nbr.isMaster() != OspfUtil.IS_MASTER) {
// check if the packet is duplicate, duplicates should be discarded by the master
if (isDuplicate) {
log.debug("received a duplicate DD packet");
}
} else {
//The slave must respond to duplicates by repeating the last Database Description packet
//that it had sent.
if (isDuplicate) {
ddPacket.setDestinationIp(ddPacket.sourceIp());
byte[] messageToWrite = getMessage(((OspfNbrImpl) nbr).lastSentDdPacket());
ctx.getChannel().write(messageToWrite);
log.debug("Sending back the duplicate packet ");
}
}
}
}
}
/**
* Process the Ls Request message.
*
* @param ospfMessage OSPF message instance.
* @param ctx channel handler context instance.
*/
void processLsRequestMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) {
log.debug("OspfChannelHandler::processLsRequestMessage...!!!");
Channel channel = ctx.getChannel();
LsRequest lsrPacket = (LsRequest) ospfMessage;
OspfNbr nbr = neighbouringRouter(lsrPacket.routerId().toString());
if (nbr.getState() == OspfNeighborState.EXCHANGE || nbr.getState() == OspfNeighborState.LOADING ||
nbr.getState() == OspfNeighborState.FULL) {
LsRequest reqMsg = (LsRequest) ospfMessage;
if (reqMsg.getLinkStateRequests().isEmpty()) {
log.debug("Received Link State Request Vector is Empty ");
return;
} else {
//Send the LsUpdate back
ListIterator<LsRequestPacket> listItr = reqMsg.getLinkStateRequests().listIterator();
while (listItr.hasNext()) {
LsUpdate lsupdate = new LsUpdate();
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 = mtu() -
OspfUtil.LSA_HEADER_LENGTH; // subtract a normal IP header.
int noLsa = 0;
while (listItr.hasNext()) {
LsRequestPacket lsRequest = listItr.next();
// to verify length of the LSA
LsaWrapper wrapper = ospfArea.getLsa(lsRequest.lsType(), lsRequest.linkStateId(),
lsRequest.ownRouterId());
if (wrapper != null) {
OspfLsa ospflsa = wrapper.ospfLsa();
if ((currentLength + ((LsaWrapperImpl) wrapper).lsaHeader().lsPacketLen()) >= maxSize) {
listItr.previous();
break;
}
if (ospflsa != null) {
lsupdate.addLsa(ospflsa);
noLsa++;
currentLength = currentLength + ((LsaWrapperImpl) wrapper).lsaHeader().lsPacketLen();
} else {
nbr.badLSReq(channel);
}
}
}
lsupdate.setNumberOfLsa(noLsa);
//set the destination
if (state() == OspfInterfaceState.DR ||
state() == OspfInterfaceState.BDR ||
state() == OspfInterfaceState.POINT2POINT) {
lsupdate.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS);
} else if (state() == OspfInterfaceState.DROTHER) {
lsupdate.setDestinationIp(OspfUtil.ALL_DROUTERS);
}
byte[] messageToWrite = getMessage(lsupdate);
ctx.getChannel().write(messageToWrite);
}
}
}
}
/**
* Process the ls update message.
*
* @param ospfMessage OSPF message instance.
* @param ctx channel handler context instance.
* @throws OspfParseException on parsing error
*/
void processLsUpdateMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws OspfParseException {
log.debug("OspfChannelHandler::processLsUpdateMessage");
LsUpdate lsUpdate = (LsUpdate) ospfMessage;
String neighbourId = lsUpdate.routerId().toString();
//LSUpdate packet has been associated with a particular neighbor.
//Neighbor should not be in lesser state than Exchange.
if (isNeighborInList(neighbourId)) {
OspfNbrImpl nbr = (OspfNbrImpl) neighbouringRouter(neighbourId);
if (nbr.getState() == OspfNeighborState.EXCHANGE ||
nbr.getState() == OspfNeighborState.LOADING) {
nbr.processLsUpdate(lsUpdate, ctx.getChannel());
} else if (nbr.getState() == OspfNeighborState.FULL) {
if (lsUpdate.noLsa() != 0) {
List<OspfLsa> list = lsUpdate.getLsaList();
Iterator itr = list.iterator();
while (itr.hasNext()) {
LsaHeader lsa = (LsaHeader) itr.next();
nbr.processReceivedLsa(lsa, true, ctx.getChannel(), lsUpdate.sourceIp());
}
} else {
return;
}
}
}
}
/**
* Process the ls acknowledge message.
*
* @param ospfMessage OSPF message instance.
* @param ctx channel handler context instance.
*/
void processLsAckMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) {
log.debug("OspfChannelHandler::processLsAckMessage");
LsAcknowledge lsAckPacket = (LsAcknowledge) ospfMessage;
//check it is present in listOfNeighbors
OspfNbrImpl nbr = (OspfNbrImpl) neighbouringRouter(lsAckPacket.routerId().toString());
if (nbr != null) {
if (nbr.getState().getValue() < OspfNeighborState.EXCHANGE.getValue()) {
// discard the packet.
return;
} else {
// process ls acknowledgements
Iterator itr = lsAckPacket.getLinkStateHeaders().iterator();
while (itr.hasNext()) {
LsaHeader lsRequest = (LsaHeader) itr.next();
OspfLsa ospfLsa =
nbr.getPendingReTxList().get(((OspfAreaImpl) ospfArea).getLsaKey(lsRequest));
if (ospfLsa != null) {
String isSame = ((OspfLsdbImpl) ospfArea.database()).isNewerOrSameLsa(
lsRequest, (LsaHeader) ospfLsa);
if (isSame.equals("same")) {
nbr.getPendingReTxList().remove(((OspfAreaImpl) ospfArea).getLsaKey(lsRequest));
}
}
}
}
}
}
/**
* Compares two Dd Packets to check whether its duplicate or not.
*
* @param receivedDPacket received DD packet from network.
* @param lastDdPacket Last DdPacket which we sent.
* @return true if it is a duplicate packet else false.
*/
public boolean compareDdPackets(DdPacket receivedDPacket, DdPacket lastDdPacket) {
if (receivedDPacket.isInitialize() == lastDdPacket.isInitialize()) {
if (receivedDPacket.isMaster() == lastDdPacket.isMaster()) {
if (receivedDPacket.isMore() == lastDdPacket.isMore()) {
if (receivedDPacket.options() == lastDdPacket.options()) {
if (receivedDPacket.sequenceNo() == lastDdPacket.sequenceNo()) {
return true;
}
}
}
}
}
return false;
}
/**
* Starts the hello timer which sends hello packet every configured seconds.
*/
@Override
public void startHelloTimer() {
log.debug("OSPFInterfaceChannelHandler::startHelloTimer");
exServiceHello = Executors.newSingleThreadScheduledExecutor();
helloTimerTask = new InternalHelloTimer();
final ScheduledFuture<?> helloHandle =
exServiceHello.scheduleAtFixedRate(helloTimerTask, delay, helloIntervalTime, TimeUnit.SECONDS);
}
/**
* Stops the hello timer.
*/
@Override
public void stopHelloTimer() {
log.debug("OSPFInterfaceChannelHandler::stopHelloTimer ");
exServiceHello.shutdown();
}
/**
* Starts the wait timer.
*/
public void startWaitTimer() {
log.debug("OSPFNbr::startWaitTimer");
exServiceWait = Executors.newSingleThreadScheduledExecutor();
waitTimerTask = new InternalWaitTimer();
final ScheduledFuture<?> waitTimerHandle =
exServiceWait.schedule(waitTimerTask, routerDeadIntervalTime(), TimeUnit.SECONDS);
}
/**
* Stops the wait timer.
*/
public void stopWaitTimer() {
log.debug("OSPFNbr::stopWaitTimer ");
exServiceWait.shutdown();
}
/**
* Starts the timer which waits for configured seconds and sends Delayed Ack Packet.
*/
@Override
public void startDelayedAckTimer() {
if (!isDelayedAckTimerScheduled) {
log.debug("Started DelayedAckTimer...!!!");
exServiceDelayedAck = Executors.newSingleThreadScheduledExecutor();
delayedAckTimerTask = new InternalDelayedAckTimer();
final ScheduledFuture<?> delayAckHandle =
exServiceDelayedAck.scheduleAtFixedRate(delayedAckTimerTask, delayedAckTimerInterval,
delayedAckTimerInterval, TimeUnit.MILLISECONDS);
isDelayedAckTimerScheduled = true;
}
}
/**
* Stops the delayed acknowledge timer.
*/
@Override
public void stopDelayedAckTimer() {
if (isDelayedAckTimerScheduled) {
log.debug("Stopped DelayedAckTimer...!!!");
isDelayedAckTimerScheduled = false;
exServiceDelayedAck.shutdown();
}
}
/**
* Performs DR election.
*
* @param ch Netty Channel instance.
*/
public void electRouter(Channel ch) {
Ip4Address currentDr = dr();
Ip4Address currentBdr = bdr();
OspfInterfaceState oldState = state();
OspfInterfaceState newState;
log.debug("OSPFInterfaceChannelHandler::electRouter -> currentDr: {}, currentBdr: {}",
currentDr, currentBdr);
List<OspfEligibleRouter> eligibleRouters = calculateListOfEligibleRouters(new OspfEligibleRouter());
log.debug("OSPFInterfaceChannelHandler::electRouter -> eligibleRouters: {}", eligibleRouters);
OspfEligibleRouter electedBdr = electBdr(eligibleRouters);
OspfEligibleRouter electedDr = electDr(eligibleRouters, electedBdr);
setBdr(electedBdr.getIpAddress());
setDr(electedDr.getIpAddress());
if (electedBdr.getIpAddress().equals(ipAddress()) &&
!electedBdr.getIpAddress().equals(currentBdr)) {
setState(OspfInterfaceState.BDR);
}
if (electedDr.getIpAddress().equals(ipAddress()) &&
!electedDr.getIpAddress().equals(currentDr)) {
setState(OspfInterfaceState.DR);
}
if (state() != oldState &&
!(state() == OspfInterfaceState.DROTHER &&
oldState.value() < OspfInterfaceState.DROTHER.value())) {
log.debug("Recalculating as the State is changed ");
log.debug("OSPFInterfaceChannelHandler::electRouter -> currentDr: {}, currentBdr: {}",
currentDr, currentBdr);
eligibleRouters = calculateListOfEligibleRouters(new OspfEligibleRouter());
log.debug("OSPFInterfaceChannelHandler::electRouter -> eligibleRouters: {}", eligibleRouters);
electedBdr = electBdr(eligibleRouters);
electedDr = electDr(eligibleRouters, electedBdr);
setBdr(electedBdr.getIpAddress());
setDr(electedDr.getIpAddress());
}
if (electedBdr.getIpAddress().equals(ipAddress()) &&
!electedBdr.getIpAddress().equals(currentBdr)) {
setState(OspfInterfaceState.BDR);
ospfArea.refreshArea(this);
}
if (electedDr.getIpAddress().equals(ipAddress()) &&
!electedDr.getIpAddress().equals(currentDr)) {
setState(OspfInterfaceState.DR);
//Refresh Router Lsa & Network Lsa
ospfArea.refreshArea(this);
}
if (currentDr != electedDr.getIpAddress() || currentBdr != electedBdr.getIpAddress()) {
Set<String> negibhorIdList;
negibhorIdList = listOfNeighbors().keySet();
for (String routerid : negibhorIdList) {
OspfNbrImpl nbr = (OspfNbrImpl) neighbouringRouter(routerid);
if (nbr.getState().getValue() >= OspfNeighborState.TWOWAY.getValue()) {
nbr.adjOk(ch);
}
}
}
log.debug("OSPFInterfaceChannelHandler::electRouter -> ElectedDR: {}, ElectedBDR: {}",
electedDr.getIpAddress(), electedBdr.getIpAddress());
}
/**
* BDR Election process. Find the list of eligible router to participate in the process.
*
* @param electedDr router elected as DR.
* @return list of eligible routers
*/
public List<OspfEligibleRouter> calculateListOfEligibleRouters(OspfEligibleRouter electedDr) {
log.debug("OSPFNbr::calculateListOfEligibleRouters ");
Set<String> neighborIdList;
List<OspfEligibleRouter> eligibleRouters = new ArrayList<>();
neighborIdList = listOfNeighbors().keySet();
for (String routerId : neighborIdList) {
OspfNbrImpl nbr = (OspfNbrImpl) neighbouringRouter(routerId);
if (nbr.getState().getValue() >= OspfNeighborState.TWOWAY.getValue() &&
nbr.routerPriority() > 0) {
OspfEligibleRouter router = new OspfEligibleRouter();
router.setIpAddress(nbr.neighborIpAddr());
router.setRouterId(nbr.neighborId());
router.setRouterPriority(nbr.routerPriority());
if (nbr.neighborDr().equals(nbr.neighborIpAddr()) ||
electedDr.getIpAddress().equals(nbr.neighborIpAddr())) {
router.setIsDr(true);
} else if (nbr.neighborBdr().equals(nbr.neighborIpAddr())) {
router.setIsBdr(true);
}
eligibleRouters.add(router);
}
}
// interface does not have states like two and all
if (routerPriority() > 0) {
OspfEligibleRouter router = new OspfEligibleRouter();
router.setIpAddress(ipAddress());
router.setRouterId(ospfArea.routerId());
router.setRouterPriority(routerPriority());
if (dr().equals(ipAddress()) ||
electedDr.getIpAddress().equals(ipAddress())) {
router.setIsDr(true);
} else if (bdr().equals(ipAddress()) &&
!dr().equals(ipAddress())) {
router.setIsBdr(true);
}
eligibleRouters.add(router);
}
return eligibleRouters;
}
/**
* Based on router priority assigns BDR.
*
* @param eligibleRouters list of routers to participate in bdr election.
* @return OSPF Eligible router instance.
*/
public OspfEligibleRouter electBdr(List<OspfEligibleRouter> eligibleRouters) {
log.debug("OSPFInterfaceChannelHandler::electBdr -> eligibleRouters: {}", eligibleRouters);
List<OspfEligibleRouter> declaredAsBdr = new ArrayList<>();
List<OspfEligibleRouter> notDrAndBdr = new ArrayList<>();
for (OspfEligibleRouter router : eligibleRouters) {
if (router.isBdr()) {
declaredAsBdr.add(router);
}
if (!router.isBdr() && !router.isDr()) {
notDrAndBdr.add(router);
}
}
OspfEligibleRouter electedBdr = new OspfEligibleRouter();
if (!declaredAsBdr.isEmpty()) {
if (declaredAsBdr.size() == 1) {
electedBdr = declaredAsBdr.get(0);
} else if (declaredAsBdr.size() > 1) {
electedBdr = selectRouterBasedOnPriority(declaredAsBdr);
}
} else {
if (notDrAndBdr.size() == 1) {
electedBdr = notDrAndBdr.get(0);
} else if (notDrAndBdr.size() > 1) {
electedBdr = selectRouterBasedOnPriority(notDrAndBdr);
}
}
electedBdr.setIsBdr(true);
electedBdr.setIsDr(false);
return electedBdr;
}
/**
* DR Election process.
*
* @param eligibleRouters list of eligible routers.
* @param electedBdr Elected Bdr, OSPF eligible router instance.
* @return OSPF eligible router instance.
*/
public OspfEligibleRouter electDr(List<OspfEligibleRouter> eligibleRouters,
OspfEligibleRouter electedBdr) {
List<OspfEligibleRouter> declaredAsDr = new ArrayList<>();
for (OspfEligibleRouter router : eligibleRouters) {
if (router.isDr()) {
declaredAsDr.add(router);
}
}
OspfEligibleRouter electedDr = new OspfEligibleRouter();
if (!declaredAsDr.isEmpty()) {
if (declaredAsDr.size() == 1) {
electedDr = declaredAsDr.get(0);
} else if (eligibleRouters.size() > 1) {
electedDr = selectRouterBasedOnPriority(declaredAsDr);
}
} else {
electedDr = electedBdr;
electedDr.setIsDr(true);
electedDr.setIsBdr(false);
}
return electedDr;
}
/**
* DR election process.
*
* @param routersList list of eligible routers.
* @return OSPF eligible router instance.
*/
public OspfEligibleRouter selectRouterBasedOnPriority(List<OspfEligibleRouter> routersList) {
OspfEligibleRouter initialRouter = routersList.get(0);
for (int i = 1; i < routersList.size(); i++) {
OspfEligibleRouter router = routersList.get(i);
if (router.getRouterPriority() > initialRouter.getRouterPriority()) {
initialRouter = router;
} else if (router.getRouterPriority() == initialRouter.getRouterPriority()) {
try {
if (OspfUtil.ipAddressToLong(router.getIpAddress().toString()) >
OspfUtil.ipAddressToLong(initialRouter.getIpAddress().toString())) {
initialRouter = router;
}
} catch (Exception e) {
log.debug("OSPFInterfaceChannelHandler::selectRouterBasedOnPriority ->" +
" eligibleRouters: {}", initialRouter);
}
}
}
return initialRouter;
}
/**
* Adds device information.
*
* @param ospfRouter OSPF router instance
*/
public void addDeviceInformation(OspfRouter ospfRouter) {
controller.addDeviceDetails(ospfRouter);
}
/**
* removes device information.
*
* @param ospfRouter OSPF neighbor instance
*/
public void removeDeviceInformation(OspfRouter ospfRouter) {
controller.removeDeviceDetails(ospfRouter);
}
/**
* Adds link information.
*
* @param ospfRouter OSPF router instance
* @param ospfLinkTed list link ted instances
*/
public void addLinkInformation(OspfRouter ospfRouter, OspfLinkTed ospfLinkTed) {
controller.addLinkDetails(ospfRouter, ospfLinkTed);
}
/**
* Removes link information.
*
* @param ospfRouter OSPF router instance
* @param ospfLinkTed OSPF link TED instance
*/
public void removeLinkInformation(OspfRouter ospfRouter, OspfLinkTed ospfLinkTed) {
controller.removeLinkDetails(ospfRouter, ospfLinkTed);
}
/**
* Gets message as bytes.
*
* @param ospfMessage OSPF message
* @return OSPF message
*/
private byte[] getMessage(OspfMessage ospfMessage) {
OspfMessageWriter messageWriter = new OspfMessageWriter();
if (state().equals(OspfInterfaceState.POINT2POINT)) {
ospfMessage.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS);
}
return (messageWriter.getMessage(ospfMessage, interfaceIndex, state.value()));
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
OspfInterfaceImpl that = (OspfInterfaceImpl) o;
return Objects.equal(helloIntervalTime, that.helloIntervalTime) &&
Objects.equal(routerDeadIntervalTime, that.routerDeadIntervalTime) &&
Objects.equal(routerPriority, that.routerPriority) &&
Objects.equal(interfaceType, that.interfaceType) &&
Objects.equal(mtu, that.mtu) &&
Objects.equal(reTransmitInterval, that.reTransmitInterval) &&
Objects.equal(ipAddress, that.ipAddress) &&
Objects.equal(ipNetworkMask, that.ipNetworkMask) &&
Objects.equal(listOfNeighbors, that.listOfNeighbors) &&
Objects.equal(dr, that.dr) &&
Objects.equal(bdr, that.bdr);
}
@Override
public int hashCode() {
return Objects.hashCode(ipAddress, ipNetworkMask, helloIntervalTime,
routerDeadIntervalTime, routerPriority, listOfNeighbors,
interfaceType, mtu, reTransmitInterval, dr, bdr);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.omitNullValues()
.add("ipAddress", ipAddress)
.add("routerPriority", routerPriority)
.add("helloIntervalTime", helloIntervalTime)
.add("routerDeadIntervalTime", routerDeadIntervalTime)
.add("interfaceType", interfaceType)
.add("mtu", mtu)
.add("reTransmitInterval", reTransmitInterval)
.add("dr", dr)
.add("bdr", bdr)
.toString();
}
/**
* Represents a Hello task which sent a hello message every configured time interval.
*/
private class InternalHelloTimer implements Runnable {
/**
* Creates an instance of Hello Timer.
*/
InternalHelloTimer() {
}
@Override
public void run() {
if (channel != null && channel.isOpen() && channel.isConnected()) {
if (interfaceType() == OspfInterfaceType.BROADCAST.value()) {
if (interfaceTypeOldValue != interfaceType()) {
try {
callDrElection(channel);
} catch (Exception e) {
log.debug("Error while calling interfaceUp {}", e.getMessage());
}
}
} else {
if (interfaceTypeOldValue != interfaceType()) {
interfaceTypeOldValue = interfaceType();
}
}
HelloPacket hellopacket = new HelloPacket();
//Headers
hellopacket.setOspfVer(OspfUtil.OSPF_VERSION);
hellopacket.setOspftype(OspfPacketType.HELLO.value());
hellopacket.setOspfPacLength(0); //will be modified while encoding
hellopacket.setRouterId(ospfArea.routerId());
hellopacket.setAreaId(ospfArea.areaId());
hellopacket.setChecksum(0); //will be modified while encoding
hellopacket.setAuthType(OspfUtil.NOT_ASSIGNED);
hellopacket.setAuthentication(OspfUtil.NOT_ASSIGNED);
//Body
hellopacket.setNetworkMask(ipNetworkMask());
hellopacket.setOptions(ospfArea.options());
hellopacket.setHelloInterval(helloIntervalTime());
hellopacket.setRouterPriority(routerPriority());
hellopacket.setRouterDeadInterval(routerDeadIntervalTime());
hellopacket.setDr(dr());
hellopacket.setBdr(bdr());
Map<String, OspfNbr> listOfNeighbors = listOfNeighbors();
Set<String> keys = listOfNeighbors.keySet();
Iterator itr = keys.iterator();
while (itr.hasNext()) {
String nbrKey = (String) itr.next();
OspfNbrImpl nbr = (OspfNbrImpl) listOfNeighbors.get(nbrKey);
if (nbr.getState() != OspfNeighborState.DOWN) {
hellopacket.addNeighbor(Ip4Address.valueOf(nbrKey));
}
}
// build a hello Packet
if (channel == null || !channel.isOpen() || !channel.isConnected()) {
log.debug("Hello Packet not sent !!.. Channel Issue...");
return;
}
hellopacket.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS);
byte[] messageToWrite = getMessage(hellopacket);
ChannelFuture future = channel.write(messageToWrite);
if (future.isSuccess()) {
log.debug("Hello Packet successfully sent !!");
} else {
future.awaitUninterruptibly();
}
}
}
}
/**
* Represents a Wait Timer task which waits the interface state to become WAITING.
* It initiates DR election process.
*/
private class InternalWaitTimer implements Runnable {
Channel ch;
/**
* Creates an instance of Wait Timer.
*/
InternalWaitTimer() {
this.ch = channel;
}
@Override
public void run() {
log.debug("Wait timer expires...");
if (ch != null && ch.isConnected()) {
try {
waitTimer(ch);
} catch (Exception e) {
log.debug("Exception at wait timer ...!!!");
}
}
}
}
/**
* Represents a task which sent a LS Acknowledge from the link state headers list.
*/
private class InternalDelayedAckTimer implements Runnable {
Channel ch;
/**
* Creates an instance of Delayed acknowledge timer.
*/
InternalDelayedAckTimer() {
this.ch = channel;
}
@Override
public void run() {
if (!linkStateHeaders().isEmpty()) {
isDelayedAckTimerScheduled = true;
if (ch != null && ch.isConnected()) {
List<LsaHeader> listOfLsaHeadersAcknowledged = new ArrayList<>();
List<LsaHeader> listOfLsaHeaders = linkStateHeaders();
log.debug("Delayed Ack, Number of Lsa's to Ack {}", listOfLsaHeaders.size());
Iterator itr = listOfLsaHeaders.iterator();
while (itr.hasNext()) {
LsAcknowledge ackContent = new LsAcknowledge();
//Setting 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);
ackContent.setChecksum(OspfUtil.NOT_ASSIGNED);
//limit to mtu
int currentLength = OspfUtil.OSPF_HEADER_LENGTH;
int maxSize = 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();
ackContent.addLinkStateHeader(lsaHeader);
currentLength = currentLength + OspfUtil.LSA_HEADER_LENGTH;
listOfLsaHeadersAcknowledged.add(lsaHeader);
log.debug("Delayed Ack, Added Lsa's to Ack {}", lsaHeader);
}
log.debug("Delayed Ack, Number of Lsa's in LsAck packet {}",
ackContent.getLinkStateHeaders().size());
//set the destination
if (state() == OspfInterfaceState.DR || state() == OspfInterfaceState.BDR
|| state() == OspfInterfaceState.POINT2POINT) {
ackContent.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS);
} else if (state() == OspfInterfaceState.DROTHER) {
ackContent.setDestinationIp(OspfUtil.ALL_DROUTERS);
}
byte[] messageToWrite = getMessage(ackContent);
ch.write(messageToWrite);
for (LsaHeader lsa : listOfLsaHeadersAcknowledged) {
linkStateHeaders().remove(lsa);
removeLsaFromNeighborMap(((OspfAreaImpl) ospfArea).getLsaKey(lsa));
}
}
}
}
}
}
}