ONOS-2740,ONOS-2741,from ONOS-3032 - to ONOS 3071 , OSPF Protocol Implementation
Change-Id: I8955ca10bf966c7b3917a3f3a41037abce87f1c5
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 0000000..aac1322
--- /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<OspfMessage> ospfMessageList = (List<OspfMessage>) 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<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 = 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<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) 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<OspfEligibleRouter> 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<String> 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<OspfEligibleRouter> calculateListOfEligibleRouters(OspfEligibleRouter electedDr) {
+ log.debug("OSPFNbr::calculateListOfEligibleRouters ");
+ Set<String> neighborIdList;
+ List<OspfEligibleRouter> 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<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 (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<String, OspfNbr> listOfNeighbors = ospfInterface.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);
+ 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<LsaHeader> listOfLsaHeadersAcknowledged = new ArrayList<>();
+ List<LsaHeader> 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 0000000..977ec35
--- /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 0000000..29af7c3
--- /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<Integer, LsaBin> 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<LsaWrapper> 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 0000000..91ebbb5
--- /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