diff --git a/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/impl/OspfInterfaceChannelHandler.java b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/impl/OspfInterfaceChannelHandler.java new file mode 100755 index 0000000000..aac1322e8c --- /dev/null +++ b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/impl/OspfInterfaceChannelHandler.java @@ -0,0 +1,1400 @@ +/* + * Copyright 2016 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onosproject.ospf.controller.impl; + +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler; +import org.jboss.netty.handler.timeout.ReadTimeoutException; +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.OspfNbr; +import org.onosproject.ospf.controller.OspfNeighborState; +import org.onosproject.ospf.controller.OspfRouter; +import org.onosproject.ospf.controller.TopologyForDeviceAndLink; +import org.onosproject.ospf.controller.area.OspfAreaImpl; +import org.onosproject.ospf.controller.area.OspfInterfaceImpl; +import org.onosproject.ospf.controller.lsdb.LsaWrapperImpl; +import org.onosproject.ospf.controller.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.ospfpacket.OspfMessage; +import org.onosproject.ospf.protocol.ospfpacket.OspfPacketHeader; +import org.onosproject.ospf.protocol.ospfpacket.subtype.LsRequestPacket; +import org.onosproject.ospf.protocol.ospfpacket.types.DdPacket; +import org.onosproject.ospf.protocol.ospfpacket.types.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.OspfPacketType; +import org.onosproject.ospf.protocol.util.OspfParameters; +import org.onosproject.ospf.protocol.util.OspfUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.channels.ClosedChannelException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +/** + * Channel handler deals with the OSPF channel connection. + * Also it dispatches messages to the appropriate handlers. + */ +public class OspfInterfaceChannelHandler extends IdleStateAwareChannelHandler { + + private static final Logger log = + LoggerFactory.getLogger(OspfInterfaceChannelHandler.class); + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + private OspfInterface ospfInterface; + private OspfArea ospfArea; + private boolean isClosed = false; + private Controller controller; + private Channel channel; + 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 TopologyForDeviceAndLink topologyForDeviceAndLink; + + public OspfInterfaceChannelHandler() { + + } + + /** + * Creates an instance of OSPF channel handler. + * + * @param controller controller instance + * @param ospfArea ospf area instance + * @param ospfInterface ospf interface instance + */ + public OspfInterfaceChannelHandler(Controller controller, OspfArea ospfArea, OspfInterface ospfInterface) { + + this.ospfArea = ospfArea; + this.ospfInterface = ospfInterface; + this.controller = controller; + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DOWN); + this.ospfInterface.setDr(Ip4Address.valueOf("0.0.0.0")); + this.ospfInterface.setBdr(Ip4Address.valueOf("0.0.0.0")); + this.topologyForDeviceAndLink = new TopologyForDeviceAndLinkImpl(); + } + + /** + * Represents an interface is up and connected. + * + * @throws Exception might throws exception + */ + public void interfaceUp() throws Exception { + log.debug("OSPFInterfaceChannelHandler::interfaceUp...!!!"); + if (ospfInterface.interfaceType() == OspfInterfaceType.POINT_TO_POINT.value()) { + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.POINT2POINT); + log.debug("OSPFInterfaceChannelHandler::InterfaceType {} state {} ", + ospfInterface.interfaceType(), ((OspfInterfaceImpl) ospfInterface).state()); + } else if (ospfInterface.interfaceType() == OspfInterfaceType.BROADCAST.value()) { + //if router priority is 0, move the state to DROther + if (ospfInterface.routerPriority() == 0) { + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DROTHER); + } else { + log.debug("OSPFInterfaceChannelHandler::InterfaceType {} state {} RouterPriority {}", + ospfInterface.interfaceType(), + ((OspfInterfaceImpl) ospfInterface).state(), ospfInterface.routerPriority()); + ((OspfInterfaceImpl) ospfInterface).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(ospfInterface.helloIntervalTime()); + ospfArea.refreshArea(ospfInterface); + } + + + /** + * 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 (((OspfInterfaceImpl) ospfInterface).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 "); + //section 9.4 + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.WAITING) { + electRouter(ch); + } + } + + /** + * 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 (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR || + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR || + ((OspfInterfaceImpl) ospfInterface).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(); + ospfInterface.listOfNeighbors().clear(); + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DOWN); + } + + @Override + public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent evt) throws Exception { + log.info("OSPF channelConnected from {}", evt.getChannel().getRemoteAddress()); + channel = evt.getChannel(); + interfaceUp(); + startDelayedAckTimer(); + } + + @Override + public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent evt) { + interfaceDown(); + stopDelayedAckTimer(); + log.debug("OspfChannelHandler::channelDisconnected...!!!"); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { + log.info("[exceptionCaught]: " + e.toString()); + if (e.getCause() instanceof ReadTimeoutException) { + // device timeout + log.error("Disconnecting device {} due to read timeout", e.getChannel().getRemoteAddress()); + return; + } else if (e.getCause() instanceof ClosedChannelException) { + log.debug("Channel for OSPF {} already closed", e.getChannel().getRemoteAddress()); + } else if (e.getCause() instanceof IOException) { + log.error("Disconnecting OSPF {} due to IO Error: {}", e.getChannel().getRemoteAddress(), + e.getCause().getMessage()); + if (log.isDebugEnabled()) { + log.debug("StackTrace for previous Exception: {}", e.getCause()); + } + } else if (e.getCause() instanceof OspfParseException) { + OspfParseException errMsg = (OspfParseException) e.getCause(); + byte errorCode = errMsg.errorCode(); + byte errorSubCode = errMsg.errorSubCode(); + log.error("Error while parsing message from OSPF {}, ErrorCode {}", + e.getChannel().getRemoteAddress(), errorCode); + } else if (e.getCause() instanceof RejectedExecutionException) { + log.warn("Could not process message: queue full"); + } else { + log.error("Error while processing message from OSPF {}, state {}", + e.getChannel().getRemoteAddress(), ((OspfInterfaceImpl) ospfInterface).state()); + } + } + + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { + log.debug("OspfChannelHandler::messageReceived...!!!"); + Object message = e.getMessage(); + if (message instanceof List) { + List ospfMessageList = (List) message; + log.debug("OspfChannelHandler::List of OspfMessages Size {}", ospfMessageList.size()); + if (ospfMessageList != null) { + for (OspfMessage ospfMessage : ospfMessageList) { + processOSPFMessage(ospfMessage, ctx); + } + } else { + log.debug("OspfChannelHandler::OspfMessages Null List...!!"); + } + } + if (message instanceof OspfMessage) { + OspfMessage ospfMessage = (OspfMessage) message; + log.debug("OspfChannelHandler::OspfMessages received...!!"); + processOSPFMessage(ospfMessage, ctx); + } + } + + /** + * 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(ospfInterface.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 (ospfInterface.interfaceType() == OspfInterfaceType.BROADCAST.value() && + !OspfUtil.sameNetwork(((OspfPacketHeader) ospfMessage).sourceIp(), + ospfInterface.ipAddress(), ospfInterface.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 { + 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 {} ", + ospfInterface.interfaceType(), ((OspfInterfaceImpl) ospfInterface).state()); + + if (ospfInterface.interfaceType() != OspfInterfaceType.POINT_TO_POINT.value()) { + if (!helloPacket.networkMask().equals(ospfInterface.ipNetworkMask())) { + log.debug("OspfChannelHandler::processHelloMessage::Hello Packet Received does not " + + "match the same network mask as the configure Interface"); + return; + } + } + if (helloPacket.helloInterval() != ospfInterface.helloIntervalTime()) { + log.debug("OspfChannelHandler::processHelloMessage::Hello Packet Received have the same " + + "hello interval as configured Interface"); + return; + } + if (helloPacket.routerDeadInterval() != ospfInterface.routerDeadIntervalTime()) { + log.debug("OspfChannelHandler::processHelloMessage::Hello Packet Received have the same " + + "Router Dead interval as configured Interface"); + return; + } + + if (ospfInterface.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 (!ospfInterface.isNeighborInList(helloPacket.routerId().toString())) { + nbr = new OspfNbrImpl(ospfArea, ospfInterface, helloPacket.sourceIp(), + helloPacket.routerId(), helloPacket.options(), this, topologyForDeviceAndLink); + ospfInterface.addNeighbouringRouter(nbr); + } else { + nbr = ospfInterface.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 (ospfInterface.interfaceType() == OspfInterfaceType.BROADCAST.value()) { + + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.WAITING) { + if ((!helloPacket.dr().equals(Ip4Address.valueOf("0.0.0.0"))) && + (!helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0")))) { + stopWaitTimer(); + ospfInterface.setDr(helloPacket.dr()); + ospfInterface.setBdr(helloPacket.bdr()); + if (helloPacket.dr().equals(ospfInterface.ipAddress())) { + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DR); + //refresh router Lsa + ospfArea.refreshArea(ospfInterface); + } else if (helloPacket.bdr().equals(ospfInterface.ipAddress())) { + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.BDR); + //refresh router Lsa + ospfArea.refreshArea(ospfInterface); + } else { + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DROTHER); + ospfArea.refreshArea(ospfInterface); + } + + } else if (!helloPacket.dr().equals(Ip4Address.valueOf("0.0.0.0")) || + !helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0"))) { + ospfInterface.setDr(helloPacket.dr()); + ospfInterface.setBdr(helloPacket.bdr()); + } + Ip4Address sourceIp = helloPacket.sourceIp(); + OspfNbr nbr; + if (!ospfInterface.isNeighborInList(helloPacket.routerId().toString())) { + nbr = new OspfNbrImpl(ospfArea, ospfInterface, sourceIp, helloPacket.routerId(), + helloPacket.options(), this, topologyForDeviceAndLink); + nbr.setNeighborId(helloPacket.routerId()); + nbr.setNeighborBdr(helloPacket.bdr()); + nbr.setNeighborDr(helloPacket.dr()); + nbr.setRouterPriority(helloPacket.routerPriority()); + ospfInterface.addNeighbouringRouter(nbr); + } else { + nbr = ospfInterface.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"))) + && ospfInterface.routerPriority() == 0) { + ospfInterface.setDr(helloPacket.dr()); + ospfInterface.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 (!ospfInterface.isNeighborInList(helloPacket.routerId().toString())) { + nbr = new OspfNbrImpl(ospfArea, ospfInterface, sourceIp, helloPacket.routerId(), + helloPacket.options(), this, topologyForDeviceAndLink); + nbr.setNeighborId(helloPacket.routerId()); + nbr.setNeighborBdr(helloPacket.bdr()); + nbr.setNeighborDr(helloPacket.dr()); + nbr.setRouterPriority(helloPacket.routerPriority()); + ospfInterface.addNeighbouringRouter(nbr); + ((OspfNbrImpl) nbr).oneWayReceived(helloPacket, channel); + } else { + log.debug("OspfChannelHandler::NeighborInList::helloPacket.bdr(): {}, " + + "helloPacket.dr(): {}", helloPacket.bdr(), helloPacket.dr()); + nbr = ospfInterface.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...!!!"); + + DdPacket ddPacket = (DdPacket) ospfMessage; + log.debug("Got DD packet from {}", ddPacket.sourceIp()); + //check it is present in listOfNeighbors + Ip4Address neighbourId = ddPacket.routerId(); + OspfNbr nbr = ospfInterface.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() > ospfInterface.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()); + ctx.getChannel().write(newResPacket); + } 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()); + ctx.getChannel().write(newResPacket); + } 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()); + ctx.getChannel().write(newResPacket); + } + } 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()); + ctx.getChannel().write(newResPacket); + } + } + } + } else { + if (masterOrSlave == OspfUtil.NOT_MASTER) { + return; + } else { + DdPacket newResPacket = ((OspfNbrImpl) nbr).lastSentDdPacket(); + log.debug("Sending back DDPacket to {}", ddPacket.sourceIp()); + ctx.getChannel().write(newResPacket); + } + } + } 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()); + ctx.getChannel().write(newResPacket); + } else if (ddPacket.isInitialize() == OspfUtil.INITIALIZE_SET) { + OspfMessage newResPacket = ((OspfNbrImpl) nbr).seqNumMismatch("Initialize bit inconsistency"); + newResPacket.setDestinationIp(ddPacket.sourceIp()); + ctx.getChannel().write(newResPacket); + } + 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()); + ctx.getChannel().write(((OspfNbrImpl) nbr).lastSentDdPacket()); + 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...!!!"); + LsRequest lsrPacket = (LsRequest) ospfMessage; + OspfNbr nbr = ospfInterface.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 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 = ospfInterface.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 (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR || + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR || + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT) { + lsupdate.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS); + } else if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER) { + lsupdate.setDestinationIp(OspfUtil.ALL_DROUTERS); + } + ctx.getChannel().write(lsupdate); + } + } + } + } + + /** + * 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 (ospfInterface.isNeighborInList(neighbourId)) { + OspfNbrImpl nbr = (OspfNbrImpl) ospfInterface.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 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) ospfInterface.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 (lsRequest != null && 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; + } + + /** + * Closes the Netty channel. + * + * @param ctx the Channel Handler Context + */ + void closeChannel(ChannelHandlerContext ctx) { + log.debug("OspfChannelHandler::closeChannel"); + isClosed = true; + ctx.getChannel().close(); + } + + /** + * Starts the hello timer which sends hello packet every configured seconds. + * + * @param period the interval to run task + */ + private void startHelloTimer(long period) { + log.debug("OSPFInterfaceChannelHandler::startHelloTimer"); + exServiceHello = Executors.newSingleThreadScheduledExecutor(); + helloTimerTask = new InternalHelloTimer(); + final ScheduledFuture helloHandle = + exServiceHello.scheduleAtFixedRate(helloTimerTask, delay, period, TimeUnit.SECONDS); + } + + /** + * Stops the hello timer. + */ + private void stopHelloTimer() { + log.debug("OSPFInterfaceChannelHandler::stopHelloTimer "); + exServiceHello.shutdown(); + } + + /** + * Starts the wait timer. + */ + private void startWaitTimer() { + log.debug("OSPFNbr::startWaitTimer"); + exServiceWait = Executors.newSingleThreadScheduledExecutor(); + waitTimerTask = new InternalWaitTimer(); + final ScheduledFuture waitTimerHandle = + exServiceWait.schedule(waitTimerTask, ospfInterface.routerDeadIntervalTime(), + TimeUnit.SECONDS); + } + + /** + * Stops the wait timer. + */ + private void stopWaitTimer() { + log.debug("OSPFNbr::stopWaitTimer "); + exServiceWait.shutdown(); + } + + /** + * Starts the timer which waits for configured seconds and sends Delayed Ack Packet. + */ + private 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. + */ + private 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 = ospfInterface.dr(); + Ip4Address currentBdr = ospfInterface.bdr(); + OspfInterfaceState oldState = ((OspfInterfaceImpl) ospfInterface).state(); + OspfInterfaceState newState; + + log.debug("OSPFInterfaceChannelHandler::electRouter -> currentDr: {}, currentBdr: {}", + currentDr, currentBdr); + List eligibleRouters = calculateListOfEligibleRouters(new OspfEligibleRouter()); + + log.debug("OSPFInterfaceChannelHandler::electRouter -> eligibleRouters: {}", eligibleRouters); + OspfEligibleRouter electedBdr = electBdr(eligibleRouters); + OspfEligibleRouter electedDr = electDr(eligibleRouters, electedBdr); + + ospfInterface.setBdr(electedBdr.getIpAddress()); + ospfInterface.setDr(electedDr.getIpAddress()); + + if (electedBdr.getIpAddress().equals(ospfInterface.ipAddress()) && + !electedBdr.getIpAddress().equals(currentBdr)) { + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.BDR); + } + + if (electedDr.getIpAddress().equals(ospfInterface.ipAddress()) && + !electedDr.getIpAddress().equals(currentDr)) { + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DR); + } + + if (((OspfInterfaceImpl) ospfInterface).state() != oldState && + !(((OspfInterfaceImpl) ospfInterface).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); + + ospfInterface.setBdr(electedBdr.getIpAddress()); + ospfInterface.setDr(electedDr.getIpAddress()); + } + + if (electedBdr.getIpAddress().equals(ospfInterface.ipAddress()) && + !electedBdr.getIpAddress().equals(currentBdr)) { + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.BDR); + ospfArea.refreshArea(ospfInterface); + } + + if (electedDr.getIpAddress().equals(ospfInterface.ipAddress()) && + !electedDr.getIpAddress().equals(currentDr)) { + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DR); + //Refresh Router Lsa & Network Lsa + ospfArea.refreshArea(ospfInterface); + } + + if (currentDr != electedDr.getIpAddress() || currentBdr != electedBdr.getIpAddress()) { + Set negibhorIdList; + negibhorIdList = ospfInterface.listOfNeighbors().keySet(); + for (String routerid : negibhorIdList) { + OspfNbrImpl nbr = (OspfNbrImpl) ospfInterface.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 calculateListOfEligibleRouters(OspfEligibleRouter electedDr) { + log.debug("OSPFNbr::calculateListOfEligibleRouters "); + Set neighborIdList; + List eligibleRouters = new ArrayList<>(); + + neighborIdList = ospfInterface.listOfNeighbors().keySet(); + for (String routerId : neighborIdList) { + OspfNbrImpl nbr = (OspfNbrImpl) ospfInterface.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 (ospfInterface.routerPriority() > 0) { + OspfEligibleRouter router = new OspfEligibleRouter(); + router.setIpAddress(ospfInterface.ipAddress()); + router.setRouterId(ospfArea.routerId()); + router.setRouterPriority(ospfInterface.routerPriority()); + if (ospfInterface.dr().equals(ospfInterface.ipAddress()) || + electedDr.getIpAddress().equals(ospfInterface.ipAddress())) { + router.setIsDr(true); + } else if (ospfInterface.bdr().equals(ospfInterface.ipAddress()) && + !ospfInterface.dr().equals(ospfInterface.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 eligibleRouters) { + log.debug("OSPFInterfaceChannelHandler::electBdr -> eligibleRouters: {}", eligibleRouters); + List declaredAsBdr = new ArrayList<>(); + List 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 eligibleRouters, + OspfEligibleRouter electedBdr) { + + List 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 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 (router.getIpAddress().toInt() > initialRouter.getIpAddress().toInt()) { + 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 ospfNbr OSPF neighbor instance + */ + public void removeLinkInformation(OspfNbr ospfNbr) { + controller.removeLinkDetails(buildOspfRouterDetails(ospfNbr)); + } + + /** + * Builds router details. + * + * @param ospfNbr OSPF neighbor instance + * @return OSPF router instance + */ + private OspfRouter buildOspfRouterDetails(OspfNbr ospfNbr) { + OspfRouter ospfRouter = new OspfRouterImpl(); + ospfRouter.setRouterIp(ospfNbr.neighborId()); + ospfRouter.setInterfaceId(ospfInterface.ipAddress()); + ospfRouter.setAreaIdOfInterface(ospfArea.areaId()); + + ospfRouter.setDeviceTed(new OspfDeviceTedImpl()); + + return ospfRouter; + } + + /** + * 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 (!isClosed && channel != null && channel.isOpen() && channel.isConnected()) { + + 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(Integer.parseInt(ospfInterface.authType())); + hellopacket.setAuthentication(Integer.parseInt(ospfInterface.authKey())); + //Body + hellopacket.setNetworkMask(ospfInterface.ipNetworkMask()); + hellopacket.setOptions(ospfArea.options()); + hellopacket.setHelloInterval(ospfInterface.helloIntervalTime()); + hellopacket.setRouterPriority(ospfInterface.routerPriority()); + hellopacket.setRouterDeadInterval(ospfInterface.routerDeadIntervalTime()); + hellopacket.setDr(ospfInterface.dr()); + hellopacket.setBdr(ospfInterface.bdr()); + + HashMap listOfNeighbors = ospfInterface.listOfNeighbors(); + Set 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); + ChannelFuture future = channel.write(hellopacket); + 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 (!((OspfInterfaceImpl) ospfInterface).linkStateHeaders().isEmpty()) { + isDelayedAckTimerScheduled = true; + if (ch != null && ch.isConnected()) { + + List listOfLsaHeadersAcknowledged = new ArrayList<>(); + List listOfLsaHeaders = ((OspfInterfaceImpl) ospfInterface).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 = ospfInterface.mtu() - + OspfUtil.LSA_HEADER_LENGTH; // subtract a normal IP header. + while (itr.hasNext()) { + if ((currentLength + OspfUtil.LSA_HEADER_LENGTH) >= maxSize) { + break; + } + LsaHeader lsaHeader = (LsaHeader) itr.next(); + 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 (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR || + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR + || ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT) { + ackContent.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS); + } else if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER) { + ackContent.setDestinationIp(OspfUtil.ALL_DROUTERS); + } + ch.write(ackContent); + for (LsaHeader lsa : listOfLsaHeadersAcknowledged) { + ((OspfInterfaceImpl) ospfInterface).linkStateHeaders().remove(lsa); + ospfInterface.removeLsaFromNeighborMap(((OspfAreaImpl) ospfArea).getLsaKey(lsa)); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsaQueueConsumer.java b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsaQueueConsumer.java new file mode 100755 index 0000000000..977ec35046 --- /dev/null +++ b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsaQueueConsumer.java @@ -0,0 +1,185 @@ +/* + * Copyright 2016 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.ospf.controller.lsdb; + +import org.jboss.netty.channel.Channel; +import org.onosproject.ospf.controller.LsaWrapper; +import org.onosproject.ospf.controller.OspfArea; +import org.onosproject.ospf.controller.OspfInterface; +import org.onosproject.ospf.controller.OspfLsaType; +import org.onosproject.ospf.controller.area.OspfAreaImpl; +import org.onosproject.ospf.controller.area.OspfInterfaceImpl; +import org.onosproject.ospf.protocol.lsa.LsaHeader; +import org.onosproject.ospf.protocol.lsa.types.NetworkLsa; +import org.onosproject.ospf.protocol.lsa.types.RouterLsa; +import org.onosproject.ospf.protocol.util.ChecksumCalculator; +import org.onosproject.ospf.protocol.util.OspfInterfaceState; +import org.onosproject.ospf.protocol.util.OspfParameters; +import org.onosproject.ospf.protocol.util.OspfUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.BlockingQueue; + +/** + * Consumes LSA from the Queue and processes it. + * Its a producer consumer implementation using Blocking queue. + */ +public class LsaQueueConsumer implements Runnable { + private static final Logger log = LoggerFactory.getLogger(LsaQueueConsumer.class); + private BlockingQueue queue = null; + private Channel channel; + private OspfArea ospfArea; + + /** + * Creates an instance of LSA queue consumer. + * + * @param queue queue instance + * @param channel netty channel instance + * @param ospfArea OSPF area instance + */ + public LsaQueueConsumer(BlockingQueue queue, Channel channel, OspfArea ospfArea) { + this.queue = queue; + this.channel = channel; + this.ospfArea = ospfArea; + } + + /** + * Threads run method. + */ + public void run() { + log.debug("LSAQueueConsumer:run...!!!"); + try { + while (true) { + if (!queue.isEmpty()) { + LsaWrapper wrapper = (LsaWrapper) queue.take(); + String lsaProcessing = wrapper.lsaProcessing(); + switch (lsaProcessing) { + case OspfParameters.VERIFYCHECKSUM: + log.debug("LSAQueueConsumer: Message - " + OspfParameters.VERIFYCHECKSUM + " consumed."); + processVerifyChecksum(wrapper); + break; + case OspfParameters.REFRESHLSA: + log.debug("LSAQueueConsumer: Message - " + OspfParameters.REFRESHLSA + " consumed."); + processRefreshLsa(wrapper); + break; + case OspfParameters.MAXAGELSA: + log.debug("LSAQueueConsumer: Message - " + OspfParameters.MAXAGELSA + " consumed."); + processMaxAgeLsa(wrapper); + break; + default: + log.debug("Unknown command to process the LSA in queue ...!!!"); + break; + } + } + } + + } catch (Exception e) { + log.debug("Error::LSAQueueConsumer::{}", e.getMessage()); + } + } + + /** + * Processes verify checksum - checkAges. + * + * @param wrapper LSA wrapper instance + */ + private void processVerifyChecksum(LsaWrapper wrapper) throws Exception { + ChecksumCalculator checkSum = new ChecksumCalculator(); + if (!checkSum.isValidLsaCheckSum(wrapper.ospfLsa(), ((LsaWrapperImpl) wrapper).lsaHeader().lsType(), + OspfUtil.LSAPACKET_CHECKSUM_POS1, + OspfUtil.LSAPACKET_CHECKSUM_POS2)) { + log.debug("LSAQueueConsumer::Checksum mismatch. Received LSA packet type {} ", + ((LsaWrapperImpl) wrapper).lsaHeader().lsType()); + + //Checksum Invalid + //RFC 2328 Restart the Router. + //Currently we are not restarting. We are not handling this case. + } + } + + /** + * Process refresh LSA. + * + * @param wrapper LSA wrapper instance + */ + private void processRefreshLsa(LsaWrapper wrapper) throws Exception { + if (wrapper.isSelfOriginated()) { //self originated + //set the destination + OspfInterface ospfInterface = wrapper.ospfInterface(); + if (ospfInterface != null) { + LsaHeader header = ((LsaWrapperImpl) wrapper).lsaHeader(); + header.setAge(wrapper.currentAge()); + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR) { + if (header.lsType() == OspfLsaType.ROUTER.value()) { + RouterLsa routerLsa = ((OspfAreaImpl) ospfArea).buildRouterLsa(ospfInterface); + ((OspfAreaImpl) ospfArea).addLsa(routerLsa, true, ospfInterface); + ((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(routerLsa); + } else if (header.lsType() == OspfLsaType.NETWORK.value()) { + if (ospfInterface.listOfNeighbors().size() > 0) { + NetworkLsa networkLsa = ((OspfAreaImpl) ospfArea).buildNetworkLsa( + ospfInterface.ipAddress(), ospfInterface.ipNetworkMask()); + ospfArea.addLsa(networkLsa, true, ospfInterface); + ((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(networkLsa); + } + } + } + + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR || + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT || + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER) { + ospfArea.refreshArea(ospfInterface); + } + log.debug("LSAQueueConsumer: processRefreshLsa - Flooded SelfOriginated LSA {}", + ((LsaWrapperImpl) wrapper).lsaHeader()); + } + } + } + + /** + * Process max age LSA. + * + * @param wrapper LSA wrapper instance + */ + private void processMaxAgeLsa(LsaWrapper wrapper) { + //set the destination + OspfInterface ospfInterface = wrapper.ospfInterface(); + if (ospfInterface != null) { + LsaHeader header = (LsaHeader) wrapper.ospfLsa().lsaHeader(); + header.setAge(OspfParameters.MAXAGE); + ((LsaWrapperImpl) wrapper).lsaHeader().setAge(OspfParameters.MAXAGE); + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR || + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT) { + //remove from db + ((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(((LsaWrapperImpl) wrapper).lsaHeader()); + ((OspfAreaImpl) ospfArea).deleteLsa(((LsaWrapperImpl) wrapper).lsaHeader()); + } else { + ((OspfAreaImpl) ospfArea).deleteLsa(((LsaWrapperImpl) wrapper).lsaHeader()); + } + log.debug("LSAQueueConsumer: processMaxAgeLsa - Flooded SelfOriginated-Max Age LSA {}", + ((LsaWrapperImpl) wrapper).lsaHeader()); + } + } + + /** + * Sets the channel. + * + * @param channel channel instance + */ + public void setChannel(Channel channel) { + this.channel = channel; + } +} \ No newline at end of file diff --git a/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsdbAgeImpl.java b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsdbAgeImpl.java new file mode 100755 index 0000000000..29af7c37e9 --- /dev/null +++ b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsdbAgeImpl.java @@ -0,0 +1,375 @@ +/* + * Copyright 2016 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.ospf.controller.lsdb; + +import com.google.common.base.Objects; +import org.jboss.netty.channel.Channel; +import org.onosproject.ospf.controller.LsaBin; +import org.onosproject.ospf.controller.LsaWrapper; +import org.onosproject.ospf.controller.LsdbAge; +import org.onosproject.ospf.controller.OspfArea; +import org.onosproject.ospf.controller.area.OspfAreaImpl; +import org.onosproject.ospf.protocol.util.OspfParameters; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * Representation of LSDB Aging process. + */ +public class LsdbAgeImpl implements LsdbAge { + + private static final Logger log = + LoggerFactory.getLogger(LsdbAgeImpl.class); + protected int ageCounter = 0; + private InternalAgeTimer dbAgeTimer; + private ScheduledExecutorService exServiceage; + // creating age bins of MAXAGE + private Map ageBins = new ConcurrentHashMap<>(OspfParameters.MAXAGE); + private LsaBin maxAgeBin = new LsaBinImpl(OspfParameters.MAXAGE); + private int ageCounterRollOver = 0; + private Channel channel = null; + private LsaQueueConsumer queueConsumer = null; + private BlockingQueue lsaQueue = new ArrayBlockingQueue(1024); + private OspfArea ospfArea = null; + + + /** + * Creates an instance of LSDB age. + * + * @param ospfArea OSPF area instance + */ + public LsdbAgeImpl(OspfArea ospfArea) { + // create LSBin's in the HashMap. + for (int i = 0; i < OspfParameters.MAXAGE; i++) { + LsaBin lsaBin = new LsaBinImpl(i); + ageBins.put(i, lsaBin); + } + this.ospfArea = ospfArea; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + LsdbAgeImpl that = (LsdbAgeImpl) o; + return Objects.equal(ageBins, that.ageBins) && + Objects.equal(ageCounter, that.ageCounter) && + Objects.equal(ageCounterRollOver, that.ageCounterRollOver) && + Objects.equal(lsaQueue, lsaQueue); + } + + @Override + public int hashCode() { + return Objects.hashCode(ageBins, ageCounter, ageCounterRollOver, lsaQueue); + } + + /** + * Adds LSA to bin. + * + * @param binKey key to store in bin + * @param lsaBin LSA bin instance + */ + public void addLsaBin(Integer binKey, LsaBin lsaBin) { + if (!ageBins.containsKey(binKey)) { + ageBins.put(binKey, lsaBin); + } + } + + /** + * Gets LSA from Bin. + * + * @param binKey key + * @return bin instance + */ + public LsaBin getLsaBin(Integer binKey) { + + return ageBins.get(binKey); + } + + /** + * Adds the LSA to maxAge bin. + * + * @param key key + * @param wrapper wrapper instance + */ + public void addLsaToMaxAgeBin(String key, LsaWrapper wrapper) { + maxAgeBin.addOspfLsa(key, wrapper); + } + + /** + * Removes LSA from Bin. + * + * @param lsaWrapper wrapper instance + */ + public void removeLsaFromBin(LsaWrapper lsaWrapper) { + if (ageBins.containsKey(lsaWrapper.binNumber())) { + LsaBin lsaBin = ageBins.get(lsaWrapper.binNumber()); + lsaBin.removeOspfLsa(((OspfAreaImpl) ospfArea).getLsaKey(((LsaWrapperImpl) + lsaWrapper).lsaHeader()), lsaWrapper); + } + } + + /** + * Starts the aging timer and queue consumer. + */ + public void startDbAging() { + startDbAgeTimer(); + queueConsumer = new LsaQueueConsumer(lsaQueue, channel, ospfArea); + new Thread(queueConsumer).start(); + } + + + /** + * Gets called every 1 second as part of the timer. + */ + public void ageLsaAndFlood() { + //every 5 mins checksum validation + checkAges(); + //every 30 mins - flood LSA + refreshLsa(); + //every 60 mins - flood LSA + maxAgeLsa(); + + if (ageCounter == OspfParameters.MAXAGE) { + ageCounter = 0; + ageCounterRollOver++; + } else { + //increment age bin + ageCounter++; + } + } + + /** + * If the LSA have completed the MaxAge - they are moved called stop aging and flooded. + */ + public void maxAgeLsa() { + if (ageCounter == 0) { + return; + } + //Get from Age Bins + LsaBin lsaBin = ageBins.get(ageCounter - 1); + if (lsaBin == null) { + return; + } + Map lsaBinMap = lsaBin.listOfLsa(); + for (Object key : lsaBinMap.keySet()) { + LsaWrapper lsa = (LsaWrapper) lsaBinMap.get((String) key); + if (lsa.currentAge() == OspfParameters.MAXAGE) { + lsa.setLsaProcessing(OspfParameters.MAXAGELSA); + log.debug("Lsa picked for maxage flooding. Age Counter: {}, AgeCounterRollover: {}, " + + "AgeCounterRollover WhenAddedToDb: {}, LSA Type: {}, LSA Key: {}", + ageCounter, ageCounterRollOver, lsa.currentAge(), lsa.lsaType(), key); + //add it to lsaQueue for processing + try { + lsaQueue.put(lsa); + //remove from bin + lsaBin.removeOspfLsa((String) key, lsa); + } catch (InterruptedException e) { + log.debug("Error::LSDBAge::maxAgeLsa::{}", e.getMessage()); + } + } + } + + //Get from maxAgeBin + Map lsaMaxAgeBinMap = maxAgeBin.listOfLsa(); + for (Object key : lsaMaxAgeBinMap.keySet()) { + LsaWrapper lsa = (LsaWrapper) lsaMaxAgeBinMap.get((String) key); + lsa.setLsaProcessing(OspfParameters.MAXAGELSA); + log.debug("Lsa picked for maxage flooding. Age Counter: {}, LSA Type: {}, LSA Key: {}", + ageCounter, lsa.lsaType(), key); + //add it to lsaQueue for processing + try { + lsaQueue.put(lsa); + //remove from bin + maxAgeBin.removeOspfLsa((String) key, lsa); + } catch (InterruptedException e) { + log.debug("Error::LSDBAge::maxAgeLsa::{}", e.getMessage()); + } + } + } + + + /* + * If the LSA is in age bin of 1800 - it's pushed into refresh list. + */ + public void refreshLsa() { + int binNumber; + if (ageCounter < OspfParameters.LSREFRESHTIME) { + binNumber = ageCounter + OspfParameters.LSREFRESHTIME; + } else { + binNumber = ageCounter - OspfParameters.LSREFRESHTIME; + } + LsaBin lsaBin = ageBins.get(binNumber); + if (lsaBin == null) { + return; + } + Map lsaBinMap = lsaBin.listOfLsa(); + for (Object key : lsaBinMap.keySet()) { + LsaWrapper lsa = (LsaWrapper) lsaBinMap.get((String) key); + try { + if (lsa.isSelfOriginated()) { + log.debug("Lsa picked for refreshLsa. binNumber: {}, LSA Type: {}, LSA Key: {}", + binNumber, lsa.lsaType(), key); + lsa.setLsaProcessing(OspfParameters.REFRESHLSA); + lsaQueue.put(lsa); + //remove from bin + lsaBin.removeOspfLsa((String) key, lsa); + } + } catch (InterruptedException e) { + log.debug("Error::LSDBAge::refreshLsa::{}", e.getMessage()); + } + } + } + + /** + * Verify the checksum for the LSAs who are in bins of 300 and it's multiples. + */ + public void checkAges() { + //evry 5 min age counter + multiples of 300 + for (int age = OspfParameters.CHECKAGE; age < OspfParameters.MAXAGE; + age += OspfParameters.CHECKAGE) { + LsaBin lsaBin = ageBins.get(age2Bin(age)); + if (lsaBin == null) { + continue; + } + Map lsaBinMap = lsaBin.listOfLsa(); + for (Object key : lsaBinMap.keySet()) { + LsaWrapper lsa = (LsaWrapper) lsaBinMap.get((String) key); + lsa.setLsaProcessing(OspfParameters.VERIFYCHECKSUM); + try { + lsaQueue.put(lsa); + } catch (InterruptedException e) { + log.debug("Error::LSDBAge::checkAges::{}", e.getMessage()); + } + } + } + } + + + /** + * Starts DB age timer method start the aging task. + */ + private void startDbAgeTimer() { + log.debug("OSPFNbr::startWaitTimer"); + dbAgeTimer = new InternalAgeTimer(); + //from 1 sec + exServiceage = Executors.newSingleThreadScheduledExecutor(); + exServiceage.scheduleAtFixedRate(dbAgeTimer, OspfParameters.AGECOUNTER, + OspfParameters.AGECOUNTER, TimeUnit.SECONDS); + } + + /** + * Stops the aging task. + */ + private void stopDbAgeTimer() { + log.debug("OSPFNbr::stopWaitTimer "); + exServiceage.shutdown(); + } + + + /** + * Gets the netty channel. + * + * @return netty channel + */ + public Channel getChannel() { + return channel; + } + + /** + * Sets the netty channel. + * + * @param channel netty channel + */ + public void setChannel(Channel channel) { + + this.channel = channel; + if (queueConsumer != null) { + queueConsumer.setChannel(channel); + } + } + + /** + * Gets the age counter. + * + * @return ageCounter + */ + public int getAgeCounter() { + return ageCounter; + } + + /** + * Gets the age counter roll over value. + * + * @return the age counter roll over value + */ + public int getAgeCounterRollOver() { + return ageCounterRollOver; + } + + /** + * Gets the max age bin. + * + * @return lsa bin instance + */ + public LsaBin getMaxAgeBin() { + return maxAgeBin; + } + + /** + * Gets the bin number. + * + * @param x Can be either age or ageCounter + * @return bin number. + */ + public int age2Bin(int x) { + if (x <= ageCounter) { + return (ageCounter - x); + } else { + return ((OspfParameters.MAXAGE - 1) + (ageCounter - x)); + } + } + + /** + * Runnable task which runs every second and calls aging process. + */ + private class InternalAgeTimer implements Runnable { + + /** + * Constructor. + */ + InternalAgeTimer() { + log.debug("Starts::LsdbAge::AgeTimer...!!! "); + } + + @Override + public void run() { + ageLsaAndFlood(); + } + } +} \ No newline at end of file diff --git a/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/package-info.java b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/package-info.java new file mode 100755 index 0000000000..91ebbb51a7 --- /dev/null +++ b/protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2016 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Implementation of the OSPF controller. + */ +package org.onosproject.ospf.controller; \ No newline at end of file