/* * Copyright 2016-present Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.ospf.controller.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.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 */ 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 */ 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 */ 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 */ 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 */ public OspfNbr neighbouringRouter(String neighborId) { return listOfNeighbors.get(neighborId); } /** * Removes all the neighbors. */ 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()); } /** * 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 */ 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 */ public boolean isNeighborInList(String neighborId) { return listOfNeighbors.containsKey(neighborId); } /** * Gets the list of neighbors. * * @return listOfNeighbors as key value pair */ 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 */ public int interfaceIndex() { return interfaceIndex; } /** * Set interface index. * * @param interfaceIndex interface index */ public void setInterfaceIndex(int interfaceIndex) { this.interfaceIndex = interfaceIndex; } /** * Gets the IP address. * * @return IP address */ public Ip4Address ipAddress() { return ipAddress; } /** * Sets the interface IP address. * * @param ipAddress interface IP address */ public void setIpAddress(Ip4Address ipAddress) { this.ipAddress = ipAddress; } /** * Gets router priority. * * @return routerPriority value */ public int routerPriority() { return routerPriority; } /** * Sets router priority. * * @param routerPriority value */ public void setRouterPriority(int routerPriority) { this.routerPriority = routerPriority; } /** * Gets hello interval time. * * @return hello interval time */ public int helloIntervalTime() { return helloIntervalTime; } /** * Sets hello interval time. * * @param helloIntervalTime an integer interval time */ public void setHelloIntervalTime(int helloIntervalTime) { this.helloIntervalTime = helloIntervalTime; } /** * Gets router dead interval time. * * @return router dead interval time */ public int routerDeadIntervalTime() { return routerDeadIntervalTime; } /** * Sets router dead interval time. * * @param routerDeadIntervalTime router dead interval time */ public void setRouterDeadIntervalTime(int routerDeadIntervalTime) { this.routerDeadIntervalTime = routerDeadIntervalTime; } /** * Gets interface type. * * @return interfaceType an integer represents interface type */ public int interfaceType() { return interfaceType; } /** * Sets interface type. * * @param interfaceType interface type */ public void setInterfaceType(int interfaceType) { this.interfaceType = interfaceType; } /** * Gets max transfer unit. * * @return mtu an integer represents max transfer unit */ public int mtu() { return mtu; } /** * Sets max transfer unit. * * @param mtu max transfer unit */ public void setMtu(int mtu) { this.mtu = mtu; } /** * Gets retransmit interval. * * @return retransmit interval */ public int reTransmitInterval() { return reTransmitInterval; } /** * Sets retransmit interval. * * @param reTransmitInterval retransmit interval */ public void setReTransmitInterval(int reTransmitInterval) { this.reTransmitInterval = reTransmitInterval; } /** * Gets designated routers IP address. * * @return dr designated routers IP address */ public Ip4Address dr() { return dr; } /** * Sets designated routers IP address. * * @param dr designated routers IP address */ public void setDr(Ip4Address dr) { this.dr = dr; } /** * Gets backup designated routers IP address. * * @return bdr backup designated routers IP address */ public Ip4Address bdr() { return bdr; } /** * Sets backup designated routers IP address. * * @param bdr backup designated routers IP address */ public void setBdr(Ip4Address bdr) { this.bdr = bdr; } /** * Represents an interface is up and connected. * * @throws Exception might throws exception */ public void interfaceUp() throws Exception { 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 * @throws Exception might throws exception */ public void backupSeen(Channel ch) throws Exception { log.debug("OSPFInterfaceChannelHandler::backupSeen "); if (state() == OspfInterfaceState.WAITING) { electRouter(ch); } } /** * Gets called when no hello message received for particular period. * * @param ch channel instance * @throws Exception might throws exception */ public void waitTimer(Channel ch) throws Exception { 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 * @throws Exception might throws exception */ public void callDrElection(Channel ch) throws Exception { 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. * * @throws Exception might throws exception */ public void neighborChange() throws Exception { 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. */ 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. * @throws Exception might throws exception */ public void processOspfMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception { log.debug("OspfChannelHandler::processOspfMessage...!!!"); if (!validateMessage(ospfMessage)) { return; } 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; } } /** * Validates the OSPF message received. * * @param ospfMessage OSPF message. * @return true if it is a valid else false. * @throws Exception might throws exception */ private boolean validateMessage(OspfMessage ospfMessage) throws Exception { 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. * @throws Exception might throws exception */ void processHelloMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception { 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 * @throws Exception might throws exception */ void processDdMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception { 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. * @throws Exception might throws exception */ void processLsRequestMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception { 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 = (LsRequestPacket) listItr.next(); // to verify length of the LSA LsaWrapper wrapper = ospfArea.getLsa(lsRequest.lsType(), lsRequest.linkStateId(), lsRequest.ownRouterId()); 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 Exception might throws exception */ void processLsUpdateMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception { 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. * @throws Exception might throws exception */ void processLsAckMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception { 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 = (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. */ 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. */ 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. */ 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. */ public void stopDelayedAckTimer() { if (isDelayedAckTimerScheduled) { log.debug("Stopped DelayedAckTimer...!!!"); isDelayedAckTimerScheduled = false; exServiceDelayedAck.shutdown(); } } /** * Performs DR election. * * @param ch Netty Channel instance. * @throws Exception might throws exception */ public void electRouter(Channel ch) throws Exception { 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)); } } } } } } }