Committed by
Thomas Vachuska
ONOS-2740,ONOS-2741,from ONOS-3032 - to ONOS 3071 , OSPF Protocol Implementation
Change-Id: I8955ca10bf966c7b3917a3f3a41037abce87f1c5
Showing
4 changed files
with
1980 additions
and
0 deletions
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.ospf.controller.impl; | ||
| 18 | + | ||
| 19 | +import org.apache.felix.scr.annotations.Reference; | ||
| 20 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
| 21 | +import org.jboss.netty.channel.Channel; | ||
| 22 | +import org.jboss.netty.channel.ChannelFuture; | ||
| 23 | +import org.jboss.netty.channel.ChannelHandlerContext; | ||
| 24 | +import org.jboss.netty.channel.ChannelStateEvent; | ||
| 25 | +import org.jboss.netty.channel.ExceptionEvent; | ||
| 26 | +import org.jboss.netty.channel.MessageEvent; | ||
| 27 | +import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler; | ||
| 28 | +import org.jboss.netty.handler.timeout.ReadTimeoutException; | ||
| 29 | +import org.onlab.packet.Ip4Address; | ||
| 30 | +import org.onosproject.ospf.controller.LsaWrapper; | ||
| 31 | +import org.onosproject.ospf.controller.OspfArea; | ||
| 32 | +import org.onosproject.ospf.controller.OspfInterface; | ||
| 33 | +import org.onosproject.ospf.controller.OspfLinkTed; | ||
| 34 | +import org.onosproject.ospf.controller.OspfLsa; | ||
| 35 | +import org.onosproject.ospf.controller.OspfNbr; | ||
| 36 | +import org.onosproject.ospf.controller.OspfNeighborState; | ||
| 37 | +import org.onosproject.ospf.controller.OspfRouter; | ||
| 38 | +import org.onosproject.ospf.controller.TopologyForDeviceAndLink; | ||
| 39 | +import org.onosproject.ospf.controller.area.OspfAreaImpl; | ||
| 40 | +import org.onosproject.ospf.controller.area.OspfInterfaceImpl; | ||
| 41 | +import org.onosproject.ospf.controller.lsdb.LsaWrapperImpl; | ||
| 42 | +import org.onosproject.ospf.controller.lsdb.OspfLsdbImpl; | ||
| 43 | +import org.onosproject.ospf.controller.util.OspfEligibleRouter; | ||
| 44 | +import org.onosproject.ospf.controller.util.OspfInterfaceType; | ||
| 45 | +import org.onosproject.ospf.exceptions.OspfParseException; | ||
| 46 | +import org.onosproject.ospf.protocol.lsa.LsaHeader; | ||
| 47 | +import org.onosproject.ospf.protocol.ospfpacket.OspfMessage; | ||
| 48 | +import org.onosproject.ospf.protocol.ospfpacket.OspfPacketHeader; | ||
| 49 | +import org.onosproject.ospf.protocol.ospfpacket.subtype.LsRequestPacket; | ||
| 50 | +import org.onosproject.ospf.protocol.ospfpacket.types.DdPacket; | ||
| 51 | +import org.onosproject.ospf.protocol.ospfpacket.types.HelloPacket; | ||
| 52 | +import org.onosproject.ospf.protocol.ospfpacket.types.LsAcknowledge; | ||
| 53 | +import org.onosproject.ospf.protocol.ospfpacket.types.LsRequest; | ||
| 54 | +import org.onosproject.ospf.protocol.ospfpacket.types.LsUpdate; | ||
| 55 | +import org.onosproject.ospf.protocol.util.ChecksumCalculator; | ||
| 56 | +import org.onosproject.ospf.protocol.util.OspfInterfaceState; | ||
| 57 | +import org.onosproject.ospf.protocol.util.OspfPacketType; | ||
| 58 | +import org.onosproject.ospf.protocol.util.OspfParameters; | ||
| 59 | +import org.onosproject.ospf.protocol.util.OspfUtil; | ||
| 60 | +import org.slf4j.Logger; | ||
| 61 | +import org.slf4j.LoggerFactory; | ||
| 62 | + | ||
| 63 | +import java.io.IOException; | ||
| 64 | +import java.nio.channels.ClosedChannelException; | ||
| 65 | +import java.util.ArrayList; | ||
| 66 | +import java.util.HashMap; | ||
| 67 | +import java.util.Iterator; | ||
| 68 | +import java.util.List; | ||
| 69 | +import java.util.ListIterator; | ||
| 70 | +import java.util.Set; | ||
| 71 | +import java.util.concurrent.Executors; | ||
| 72 | +import java.util.concurrent.RejectedExecutionException; | ||
| 73 | +import java.util.concurrent.ScheduledExecutorService; | ||
| 74 | +import java.util.concurrent.ScheduledFuture; | ||
| 75 | +import java.util.concurrent.TimeUnit; | ||
| 76 | + | ||
| 77 | +/** | ||
| 78 | + * Channel handler deals with the OSPF channel connection. | ||
| 79 | + * Also it dispatches messages to the appropriate handlers. | ||
| 80 | + */ | ||
| 81 | +public class OspfInterfaceChannelHandler extends IdleStateAwareChannelHandler { | ||
| 82 | + | ||
| 83 | + private static final Logger log = | ||
| 84 | + LoggerFactory.getLogger(OspfInterfaceChannelHandler.class); | ||
| 85 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 86 | + private OspfInterface ospfInterface; | ||
| 87 | + private OspfArea ospfArea; | ||
| 88 | + private boolean isClosed = false; | ||
| 89 | + private Controller controller; | ||
| 90 | + private Channel channel; | ||
| 91 | + private long delay = 0; | ||
| 92 | + private InternalHelloTimer helloTimerTask; | ||
| 93 | + private InternalWaitTimer waitTimerTask; | ||
| 94 | + private InternalDelayedAckTimer delayedAckTimerTask; | ||
| 95 | + private ScheduledExecutorService exServiceHello; | ||
| 96 | + private ScheduledExecutorService exServiceWait; | ||
| 97 | + private ScheduledExecutorService exServiceDelayedAck; | ||
| 98 | + private boolean isDelayedAckTimerScheduled = false; | ||
| 99 | + private int delayedAckTimerInterval = 2500; | ||
| 100 | + private TopologyForDeviceAndLink topologyForDeviceAndLink; | ||
| 101 | + | ||
| 102 | + public OspfInterfaceChannelHandler() { | ||
| 103 | + | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + /** | ||
| 107 | + * Creates an instance of OSPF channel handler. | ||
| 108 | + * | ||
| 109 | + * @param controller controller instance | ||
| 110 | + * @param ospfArea ospf area instance | ||
| 111 | + * @param ospfInterface ospf interface instance | ||
| 112 | + */ | ||
| 113 | + public OspfInterfaceChannelHandler(Controller controller, OspfArea ospfArea, OspfInterface ospfInterface) { | ||
| 114 | + | ||
| 115 | + this.ospfArea = ospfArea; | ||
| 116 | + this.ospfInterface = ospfInterface; | ||
| 117 | + this.controller = controller; | ||
| 118 | + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DOWN); | ||
| 119 | + this.ospfInterface.setDr(Ip4Address.valueOf("0.0.0.0")); | ||
| 120 | + this.ospfInterface.setBdr(Ip4Address.valueOf("0.0.0.0")); | ||
| 121 | + this.topologyForDeviceAndLink = new TopologyForDeviceAndLinkImpl(); | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + /** | ||
| 125 | + * Represents an interface is up and connected. | ||
| 126 | + * | ||
| 127 | + * @throws Exception might throws exception | ||
| 128 | + */ | ||
| 129 | + public void interfaceUp() throws Exception { | ||
| 130 | + log.debug("OSPFInterfaceChannelHandler::interfaceUp...!!!"); | ||
| 131 | + if (ospfInterface.interfaceType() == OspfInterfaceType.POINT_TO_POINT.value()) { | ||
| 132 | + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.POINT2POINT); | ||
| 133 | + log.debug("OSPFInterfaceChannelHandler::InterfaceType {} state {} ", | ||
| 134 | + ospfInterface.interfaceType(), ((OspfInterfaceImpl) ospfInterface).state()); | ||
| 135 | + } else if (ospfInterface.interfaceType() == OspfInterfaceType.BROADCAST.value()) { | ||
| 136 | + //if router priority is 0, move the state to DROther | ||
| 137 | + if (ospfInterface.routerPriority() == 0) { | ||
| 138 | + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DROTHER); | ||
| 139 | + } else { | ||
| 140 | + log.debug("OSPFInterfaceChannelHandler::InterfaceType {} state {} RouterPriority {}", | ||
| 141 | + ospfInterface.interfaceType(), | ||
| 142 | + ((OspfInterfaceImpl) ospfInterface).state(), ospfInterface.routerPriority()); | ||
| 143 | + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.WAITING); | ||
| 144 | + //start wait timer - like inactivity timer with router deadInterval | ||
| 145 | + startWaitTimer(); | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + } | ||
| 149 | + // Start hello timer with interval from config - convert seconds to milliseconds | ||
| 150 | + startHelloTimer(ospfInterface.helloIntervalTime()); | ||
| 151 | + ospfArea.refreshArea(ospfInterface); | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + | ||
| 155 | + /** | ||
| 156 | + * Gets called when a BDR was detected before the wait timer expired. | ||
| 157 | + * | ||
| 158 | + * @param ch channel instance | ||
| 159 | + * @throws Exception might throws exception | ||
| 160 | + */ | ||
| 161 | + public void backupSeen(Channel ch) throws Exception { | ||
| 162 | + log.debug("OSPFInterfaceChannelHandler::backupSeen "); | ||
| 163 | + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.WAITING) { | ||
| 164 | + electRouter(ch); | ||
| 165 | + } | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + /** | ||
| 169 | + * Gets called when no hello message received for particular period. | ||
| 170 | + * | ||
| 171 | + * @param ch channel instance | ||
| 172 | + * @throws Exception might throws exception | ||
| 173 | + */ | ||
| 174 | + public void waitTimer(Channel ch) throws Exception { | ||
| 175 | + log.debug("OSPFInterfaceChannelHandler::waitTimer "); | ||
| 176 | + //section 9.4 | ||
| 177 | + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.WAITING) { | ||
| 178 | + electRouter(ch); | ||
| 179 | + } | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + /** | ||
| 183 | + * Neighbor change event is triggered when the router priority gets changed. | ||
| 184 | + * | ||
| 185 | + * @throws Exception might throws exception | ||
| 186 | + */ | ||
| 187 | + public void neighborChange() throws Exception { | ||
| 188 | + log.debug("OSPFInterfaceChannelHandler::neighborChange "); | ||
| 189 | + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR || | ||
| 190 | + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR || | ||
| 191 | + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER) { | ||
| 192 | + electRouter(channel); | ||
| 193 | + } | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + /** | ||
| 197 | + * Gets called when an interface is down. | ||
| 198 | + * All interface variables are reset, and interface timers disabled. | ||
| 199 | + * Also all neighbor connections associated with the interface are destroyed. | ||
| 200 | + */ | ||
| 201 | + public void interfaceDown() { | ||
| 202 | + log.debug("OSPFInterfaceChannelHandler::interfaceDown "); | ||
| 203 | + stopHelloTimer(); | ||
| 204 | + ospfInterface.listOfNeighbors().clear(); | ||
| 205 | + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DOWN); | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + @Override | ||
| 209 | + public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent evt) throws Exception { | ||
| 210 | + log.info("OSPF channelConnected from {}", evt.getChannel().getRemoteAddress()); | ||
| 211 | + channel = evt.getChannel(); | ||
| 212 | + interfaceUp(); | ||
| 213 | + startDelayedAckTimer(); | ||
| 214 | + } | ||
| 215 | + | ||
| 216 | + @Override | ||
| 217 | + public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent evt) { | ||
| 218 | + interfaceDown(); | ||
| 219 | + stopDelayedAckTimer(); | ||
| 220 | + log.debug("OspfChannelHandler::channelDisconnected...!!!"); | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + @Override | ||
| 224 | + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { | ||
| 225 | + log.info("[exceptionCaught]: " + e.toString()); | ||
| 226 | + if (e.getCause() instanceof ReadTimeoutException) { | ||
| 227 | + // device timeout | ||
| 228 | + log.error("Disconnecting device {} due to read timeout", e.getChannel().getRemoteAddress()); | ||
| 229 | + return; | ||
| 230 | + } else if (e.getCause() instanceof ClosedChannelException) { | ||
| 231 | + log.debug("Channel for OSPF {} already closed", e.getChannel().getRemoteAddress()); | ||
| 232 | + } else if (e.getCause() instanceof IOException) { | ||
| 233 | + log.error("Disconnecting OSPF {} due to IO Error: {}", e.getChannel().getRemoteAddress(), | ||
| 234 | + e.getCause().getMessage()); | ||
| 235 | + if (log.isDebugEnabled()) { | ||
| 236 | + log.debug("StackTrace for previous Exception: {}", e.getCause()); | ||
| 237 | + } | ||
| 238 | + } else if (e.getCause() instanceof OspfParseException) { | ||
| 239 | + OspfParseException errMsg = (OspfParseException) e.getCause(); | ||
| 240 | + byte errorCode = errMsg.errorCode(); | ||
| 241 | + byte errorSubCode = errMsg.errorSubCode(); | ||
| 242 | + log.error("Error while parsing message from OSPF {}, ErrorCode {}", | ||
| 243 | + e.getChannel().getRemoteAddress(), errorCode); | ||
| 244 | + } else if (e.getCause() instanceof RejectedExecutionException) { | ||
| 245 | + log.warn("Could not process message: queue full"); | ||
| 246 | + } else { | ||
| 247 | + log.error("Error while processing message from OSPF {}, state {}", | ||
| 248 | + e.getChannel().getRemoteAddress(), ((OspfInterfaceImpl) ospfInterface).state()); | ||
| 249 | + } | ||
| 250 | + } | ||
| 251 | + | ||
| 252 | + @Override | ||
| 253 | + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { | ||
| 254 | + log.debug("OspfChannelHandler::messageReceived...!!!"); | ||
| 255 | + Object message = e.getMessage(); | ||
| 256 | + if (message instanceof List) { | ||
| 257 | + List<OspfMessage> ospfMessageList = (List<OspfMessage>) message; | ||
| 258 | + log.debug("OspfChannelHandler::List of OspfMessages Size {}", ospfMessageList.size()); | ||
| 259 | + if (ospfMessageList != null) { | ||
| 260 | + for (OspfMessage ospfMessage : ospfMessageList) { | ||
| 261 | + processOSPFMessage(ospfMessage, ctx); | ||
| 262 | + } | ||
| 263 | + } else { | ||
| 264 | + log.debug("OspfChannelHandler::OspfMessages Null List...!!"); | ||
| 265 | + } | ||
| 266 | + } | ||
| 267 | + if (message instanceof OspfMessage) { | ||
| 268 | + OspfMessage ospfMessage = (OspfMessage) message; | ||
| 269 | + log.debug("OspfChannelHandler::OspfMessages received...!!"); | ||
| 270 | + processOSPFMessage(ospfMessage, ctx); | ||
| 271 | + } | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + /** | ||
| 275 | + * When an OSPF message received it is handed over to this method. | ||
| 276 | + * Based on the type of the OSPF message received it will be handed over | ||
| 277 | + * to corresponding message handler methods. | ||
| 278 | + * | ||
| 279 | + * @param ospfMessage received OSPF message | ||
| 280 | + * @param ctx channel handler context instance. | ||
| 281 | + * @throws Exception might throws exception | ||
| 282 | + */ | ||
| 283 | + public void processOSPFMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception { | ||
| 284 | + log.debug("OspfChannelHandler::processOSPFMessage...!!!"); | ||
| 285 | + | ||
| 286 | + if (!validateMessage(ospfMessage)) { | ||
| 287 | + return; | ||
| 288 | + } | ||
| 289 | + | ||
| 290 | + switch (ospfMessage.ospfMessageType().value()) { | ||
| 291 | + case OspfParameters.HELLO: | ||
| 292 | + processHelloMessage(ospfMessage, ctx); | ||
| 293 | + break; | ||
| 294 | + case OspfParameters.DD: | ||
| 295 | + processDdMessage(ospfMessage, ctx); | ||
| 296 | + break; | ||
| 297 | + case OspfParameters.LSREQUEST: | ||
| 298 | + processLsRequestMessage(ospfMessage, ctx); | ||
| 299 | + break; | ||
| 300 | + case OspfParameters.LSUPDATE: | ||
| 301 | + processLsUpdateMessage(ospfMessage, ctx); | ||
| 302 | + break; | ||
| 303 | + case OspfParameters.LSACK: | ||
| 304 | + processLsAckMessage(ospfMessage, ctx); | ||
| 305 | + break; | ||
| 306 | + default: | ||
| 307 | + log.debug("Unknown packet to process...!!!"); | ||
| 308 | + break; | ||
| 309 | + } | ||
| 310 | + } | ||
| 311 | + | ||
| 312 | + /** | ||
| 313 | + * Validates the OSPF message received. | ||
| 314 | + * | ||
| 315 | + * @param ospfMessage OSPF message. | ||
| 316 | + * @return true if it is a valid else false. | ||
| 317 | + * @throws Exception might throws exception | ||
| 318 | + */ | ||
| 319 | + private boolean validateMessage(OspfMessage ospfMessage) throws Exception { | ||
| 320 | + boolean isValid = true; | ||
| 321 | + OspfPacketHeader header = (OspfPacketHeader) ospfMessage; | ||
| 322 | + | ||
| 323 | + //added the check to eliminate self origin packets also two interfaces on same router. | ||
| 324 | + if (!header.sourceIp().equals(ospfInterface.ipAddress()) && !header.routerId().equals( | ||
| 325 | + ospfArea.routerId())) { | ||
| 326 | + //Verify the checksum | ||
| 327 | + ChecksumCalculator checksum = new ChecksumCalculator(); | ||
| 328 | + if (!checksum.isValidOspfCheckSum(ospfMessage, OspfUtil.OSPFPACKET_CHECKSUM_POS1, | ||
| 329 | + OspfUtil.OSPFPACKET_CHECKSUM_POS2)) { | ||
| 330 | + log.debug("Checksum mismatch. Received packet type {} ", ospfMessage.ospfMessageType()); | ||
| 331 | + return false; | ||
| 332 | + } | ||
| 333 | + if (((OspfPacketHeader) ospfMessage).ospfVersion() != OspfUtil.OSPF_VERSION_2) { | ||
| 334 | + log.debug("Received osfpMessage Version should match with Interface Version "); | ||
| 335 | + return false; | ||
| 336 | + } | ||
| 337 | + if (!((OspfPacketHeader) ospfMessage).areaId().equals(ospfArea.areaId())) { | ||
| 338 | + log.debug("Received ospf packets are from different area than our Area ID. " + | ||
| 339 | + "Received Area ID {}, Our AreaId {} ", | ||
| 340 | + ((OspfPacketHeader) ospfMessage).areaId(), ospfArea.areaId()); | ||
| 341 | + return false; | ||
| 342 | + } | ||
| 343 | + | ||
| 344 | + //According to RFC-2328 (8.2) | ||
| 345 | + /** | ||
| 346 | + * ABR should receive packets from backbone 0.0.0.0 as we are not acting as ABR | ||
| 347 | + * we are rejecting the packet. | ||
| 348 | + */ | ||
| 349 | + if (((OspfPacketHeader) ospfMessage).areaId().equals(Ip4Address.valueOf("0.0.0.0"))) { | ||
| 350 | + log.debug("ABR should receive packets from backbone 0.0.0.0 as we are not acting as " + | ||
| 351 | + "ABR we are rejecting the ospf packet"); | ||
| 352 | + return false; | ||
| 353 | + } | ||
| 354 | + if (ospfInterface.interfaceType() == OspfInterfaceType.BROADCAST.value() && | ||
| 355 | + !OspfUtil.sameNetwork(((OspfPacketHeader) ospfMessage).sourceIp(), | ||
| 356 | + ospfInterface.ipAddress(), ospfInterface.ipNetworkMask())) { | ||
| 357 | + log.debug("Received packets from different subnets. Discarding...!!!"); | ||
| 358 | + return false; | ||
| 359 | + } | ||
| 360 | + } else { | ||
| 361 | + isValid = false; | ||
| 362 | + } | ||
| 363 | + | ||
| 364 | + return isValid; | ||
| 365 | + } | ||
| 366 | + | ||
| 367 | + /** | ||
| 368 | + * Processes Hello message. | ||
| 369 | + * | ||
| 370 | + * @param ospfMessage OSPF message instance. | ||
| 371 | + * @param ctx context instance. | ||
| 372 | + * @throws Exception might throws exception | ||
| 373 | + */ | ||
| 374 | + void processHelloMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception { | ||
| 375 | + log.debug("OspfChannelHandler::processHelloMessage...!!!"); | ||
| 376 | + HelloPacket helloPacket = (HelloPacket) ospfMessage; | ||
| 377 | + | ||
| 378 | + // processing of hello packet as per RFC 2328 section 10.5 | ||
| 379 | + log.debug("OspfChannelHandler::processHelloMessage::Interface Type {} OSPFInterfaceState {} ", | ||
| 380 | + ospfInterface.interfaceType(), ((OspfInterfaceImpl) ospfInterface).state()); | ||
| 381 | + | ||
| 382 | + if (ospfInterface.interfaceType() != OspfInterfaceType.POINT_TO_POINT.value()) { | ||
| 383 | + if (!helloPacket.networkMask().equals(ospfInterface.ipNetworkMask())) { | ||
| 384 | + log.debug("OspfChannelHandler::processHelloMessage::Hello Packet Received does not " + | ||
| 385 | + "match the same network mask as the configure Interface"); | ||
| 386 | + return; | ||
| 387 | + } | ||
| 388 | + } | ||
| 389 | + if (helloPacket.helloInterval() != ospfInterface.helloIntervalTime()) { | ||
| 390 | + log.debug("OspfChannelHandler::processHelloMessage::Hello Packet Received have the same " + | ||
| 391 | + "hello interval as configured Interface"); | ||
| 392 | + return; | ||
| 393 | + } | ||
| 394 | + if (helloPacket.routerDeadInterval() != ospfInterface.routerDeadIntervalTime()) { | ||
| 395 | + log.debug("OspfChannelHandler::processHelloMessage::Hello Packet Received have the same " + | ||
| 396 | + "Router Dead interval as configured Interface"); | ||
| 397 | + return; | ||
| 398 | + } | ||
| 399 | + | ||
| 400 | + if (ospfInterface.interfaceType() == OspfInterfaceType.POINT_TO_POINT.value()) { | ||
| 401 | + // to verify if the neighbor which sent the hello is present in the OSPF Interface neighboring list . | ||
| 402 | + OspfNbr nbr; | ||
| 403 | + if (!ospfInterface.isNeighborInList(helloPacket.routerId().toString())) { | ||
| 404 | + nbr = new OspfNbrImpl(ospfArea, ospfInterface, helloPacket.sourceIp(), | ||
| 405 | + helloPacket.routerId(), helloPacket.options(), this, topologyForDeviceAndLink); | ||
| 406 | + ospfInterface.addNeighbouringRouter(nbr); | ||
| 407 | + } else { | ||
| 408 | + nbr = ospfInterface.neighbouringRouter(helloPacket.routerId().toString()); | ||
| 409 | + nbr.setRouterPriority(helloPacket.routerPriority()); | ||
| 410 | + } | ||
| 411 | + if (!helloPacket.containsNeighbour(ospfArea.routerId())) { | ||
| 412 | + ((OspfNbrImpl) nbr).oneWayReceived(helloPacket, channel); | ||
| 413 | + } else { | ||
| 414 | + ((OspfNbrImpl) nbr).twoWayReceived(helloPacket, ctx.getChannel()); | ||
| 415 | + } | ||
| 416 | + } else if (ospfInterface.interfaceType() == OspfInterfaceType.BROADCAST.value()) { | ||
| 417 | + | ||
| 418 | + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.WAITING) { | ||
| 419 | + if ((!helloPacket.dr().equals(Ip4Address.valueOf("0.0.0.0"))) && | ||
| 420 | + (!helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0")))) { | ||
| 421 | + stopWaitTimer(); | ||
| 422 | + ospfInterface.setDr(helloPacket.dr()); | ||
| 423 | + ospfInterface.setBdr(helloPacket.bdr()); | ||
| 424 | + if (helloPacket.dr().equals(ospfInterface.ipAddress())) { | ||
| 425 | + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DR); | ||
| 426 | + //refresh router Lsa | ||
| 427 | + ospfArea.refreshArea(ospfInterface); | ||
| 428 | + } else if (helloPacket.bdr().equals(ospfInterface.ipAddress())) { | ||
| 429 | + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.BDR); | ||
| 430 | + //refresh router Lsa | ||
| 431 | + ospfArea.refreshArea(ospfInterface); | ||
| 432 | + } else { | ||
| 433 | + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DROTHER); | ||
| 434 | + ospfArea.refreshArea(ospfInterface); | ||
| 435 | + } | ||
| 436 | + | ||
| 437 | + } else if (!helloPacket.dr().equals(Ip4Address.valueOf("0.0.0.0")) || | ||
| 438 | + !helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0"))) { | ||
| 439 | + ospfInterface.setDr(helloPacket.dr()); | ||
| 440 | + ospfInterface.setBdr(helloPacket.bdr()); | ||
| 441 | + } | ||
| 442 | + Ip4Address sourceIp = helloPacket.sourceIp(); | ||
| 443 | + OspfNbr nbr; | ||
| 444 | + if (!ospfInterface.isNeighborInList(helloPacket.routerId().toString())) { | ||
| 445 | + nbr = new OspfNbrImpl(ospfArea, ospfInterface, sourceIp, helloPacket.routerId(), | ||
| 446 | + helloPacket.options(), this, topologyForDeviceAndLink); | ||
| 447 | + nbr.setNeighborId(helloPacket.routerId()); | ||
| 448 | + nbr.setNeighborBdr(helloPacket.bdr()); | ||
| 449 | + nbr.setNeighborDr(helloPacket.dr()); | ||
| 450 | + nbr.setRouterPriority(helloPacket.routerPriority()); | ||
| 451 | + ospfInterface.addNeighbouringRouter(nbr); | ||
| 452 | + } else { | ||
| 453 | + nbr = ospfInterface.neighbouringRouter(helloPacket.routerId().toString()); | ||
| 454 | + nbr.setRouterPriority(helloPacket.routerPriority()); | ||
| 455 | + } | ||
| 456 | + if (!helloPacket.containsNeighbour(ospfArea.routerId())) { | ||
| 457 | + ((OspfNbrImpl) nbr).oneWayReceived(helloPacket, channel); | ||
| 458 | + } else { | ||
| 459 | + ((OspfNbrImpl) nbr).twoWayReceived(helloPacket, ctx.getChannel()); | ||
| 460 | + } | ||
| 461 | + | ||
| 462 | + if (helloPacket.dr().equals(sourceIp)) { | ||
| 463 | + if (helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0"))) { | ||
| 464 | + // call backup seen | ||
| 465 | + stopWaitTimer(); | ||
| 466 | + backupSeen(ctx.getChannel()); | ||
| 467 | + } | ||
| 468 | + } | ||
| 469 | + | ||
| 470 | + if (helloPacket.bdr().equals(sourceIp)) { | ||
| 471 | + // call backup seen | ||
| 472 | + stopWaitTimer(); | ||
| 473 | + backupSeen(ctx.getChannel()); | ||
| 474 | + } | ||
| 475 | + } else { | ||
| 476 | + | ||
| 477 | + if ((!helloPacket.dr().equals(Ip4Address.valueOf("0.0.0.0")) || | ||
| 478 | + !helloPacket.bdr().equals(Ip4Address.valueOf("0.0.0.0"))) | ||
| 479 | + && ospfInterface.routerPriority() == 0) { | ||
| 480 | + ospfInterface.setDr(helloPacket.dr()); | ||
| 481 | + ospfInterface.setBdr(helloPacket.bdr()); | ||
| 482 | + } | ||
| 483 | + //To verify if the neighbor which sent the hello is present in the OSPF Interface neighboring list . | ||
| 484 | + Ip4Address sourceIp = helloPacket.sourceIp(); | ||
| 485 | + OspfNbr nbr; | ||
| 486 | + if (!ospfInterface.isNeighborInList(helloPacket.routerId().toString())) { | ||
| 487 | + nbr = new OspfNbrImpl(ospfArea, ospfInterface, sourceIp, helloPacket.routerId(), | ||
| 488 | + helloPacket.options(), this, topologyForDeviceAndLink); | ||
| 489 | + nbr.setNeighborId(helloPacket.routerId()); | ||
| 490 | + nbr.setNeighborBdr(helloPacket.bdr()); | ||
| 491 | + nbr.setNeighborDr(helloPacket.dr()); | ||
| 492 | + nbr.setRouterPriority(helloPacket.routerPriority()); | ||
| 493 | + ospfInterface.addNeighbouringRouter(nbr); | ||
| 494 | + ((OspfNbrImpl) nbr).oneWayReceived(helloPacket, channel); | ||
| 495 | + } else { | ||
| 496 | + log.debug("OspfChannelHandler::NeighborInList::helloPacket.bdr(): {}, " + | ||
| 497 | + "helloPacket.dr(): {}", helloPacket.bdr(), helloPacket.dr()); | ||
| 498 | + nbr = ospfInterface.neighbouringRouter(helloPacket.routerId().toString()); | ||
| 499 | + nbr.setRouterPriority(helloPacket.routerPriority()); | ||
| 500 | + if (!helloPacket.containsNeighbour(ospfArea.routerId())) { | ||
| 501 | + ((OspfNbrImpl) nbr).oneWayReceived(helloPacket, channel); | ||
| 502 | + } else { | ||
| 503 | + ((OspfNbrImpl) nbr).twoWayReceived(helloPacket, ctx.getChannel()); | ||
| 504 | + } | ||
| 505 | + if (nbr.routerPriority() != helloPacket.routerPriority()) { | ||
| 506 | + nbr.setNeighborBdr(helloPacket.bdr()); | ||
| 507 | + nbr.setNeighborDr(helloPacket.dr()); | ||
| 508 | + neighborChange(); | ||
| 509 | + } | ||
| 510 | + | ||
| 511 | + | ||
| 512 | + if (nbr.neighborIpAddr().equals(helloPacket.dr()) && | ||
| 513 | + !(nbr.neighborIpAddr().equals(nbr.neighborDr()))) { | ||
| 514 | + nbr.setNeighborBdr(helloPacket.bdr()); | ||
| 515 | + nbr.setNeighborDr(helloPacket.dr()); | ||
| 516 | + neighborChange(); | ||
| 517 | + } | ||
| 518 | + | ||
| 519 | + if (!(nbr.neighborIpAddr().equals(helloPacket.dr())) && | ||
| 520 | + (nbr.neighborIpAddr().equals(nbr.neighborDr()))) { | ||
| 521 | + nbr.setNeighborBdr(helloPacket.bdr()); | ||
| 522 | + nbr.setNeighborDr(helloPacket.dr()); | ||
| 523 | + neighborChange(); | ||
| 524 | + } | ||
| 525 | + | ||
| 526 | + if (nbr.neighborIpAddr().equals(helloPacket.bdr()) && | ||
| 527 | + !(nbr.neighborIpAddr().equals(nbr.neighborBdr()))) { | ||
| 528 | + nbr.setNeighborBdr(helloPacket.bdr()); | ||
| 529 | + nbr.setNeighborDr(helloPacket.dr()); | ||
| 530 | + neighborChange(); | ||
| 531 | + } | ||
| 532 | + | ||
| 533 | + if (!(nbr.neighborIpAddr().equals(helloPacket.bdr())) && | ||
| 534 | + (nbr.neighborIpAddr().equals(nbr.neighborBdr()))) { | ||
| 535 | + nbr.setNeighborBdr(helloPacket.bdr()); | ||
| 536 | + nbr.setNeighborDr(helloPacket.dr()); | ||
| 537 | + neighborChange(); | ||
| 538 | + } | ||
| 539 | + | ||
| 540 | + nbr.setNeighborBdr(helloPacket.bdr()); | ||
| 541 | + nbr.setNeighborDr(helloPacket.dr()); | ||
| 542 | + } | ||
| 543 | + | ||
| 544 | + } | ||
| 545 | + } | ||
| 546 | + } | ||
| 547 | + | ||
| 548 | + /** | ||
| 549 | + * process the DD message which received. | ||
| 550 | + * | ||
| 551 | + * @param ospfMessage OSPF message instance. | ||
| 552 | + * @param ctx channel handler context instance | ||
| 553 | + * @throws Exception might throws exception | ||
| 554 | + */ | ||
| 555 | + void processDdMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception { | ||
| 556 | + log.debug("OspfChannelHandler::processDdMessage...!!!"); | ||
| 557 | + | ||
| 558 | + DdPacket ddPacket = (DdPacket) ospfMessage; | ||
| 559 | + log.debug("Got DD packet from {}", ddPacket.sourceIp()); | ||
| 560 | + //check it is present in listOfNeighbors | ||
| 561 | + Ip4Address neighbourId = ddPacket.routerId(); | ||
| 562 | + OspfNbr nbr = ospfInterface.neighbouringRouter(neighbourId.toString()); | ||
| 563 | + | ||
| 564 | + if (nbr != null) { | ||
| 565 | + log.debug("OspfChannelHandler::processDdMessage:: OSPFNeighborState {}", nbr.getState()); | ||
| 566 | + // set options for the NBR | ||
| 567 | + nbr.setIsOpaqueCapable(ddPacket.isOpaqueCapable()); | ||
| 568 | + if (ddPacket.imtu() > ospfInterface.mtu()) { | ||
| 569 | + log.debug("the MTU size is greater than the interface MTU"); | ||
| 570 | + return; | ||
| 571 | + } | ||
| 572 | + if (nbr.getState() == OspfNeighborState.DOWN) { | ||
| 573 | + return; | ||
| 574 | + } | ||
| 575 | + if (nbr.getState() == OspfNeighborState.ATTEMPT) { | ||
| 576 | + return; | ||
| 577 | + } | ||
| 578 | + if (nbr.getState() == OspfNeighborState.TWOWAY) { | ||
| 579 | + nbr.adjOk(channel); | ||
| 580 | + return; | ||
| 581 | + } | ||
| 582 | + //if init is the state call twoWayReceived | ||
| 583 | + if (nbr.getState() == OspfNeighborState.INIT) { | ||
| 584 | + ((OspfNbrImpl) nbr).twoWayReceived(ddPacket, ctx.getChannel()); | ||
| 585 | + } else if (nbr.getState() == OspfNeighborState.EXSTART) { | ||
| 586 | + //get I,M,MS Bits | ||
| 587 | + int initialize = ddPacket.isInitialize(); | ||
| 588 | + int more = ddPacket.isMore(); | ||
| 589 | + int masterOrSlave = ddPacket.isMaster(); | ||
| 590 | + int options = ddPacket.options(); | ||
| 591 | + nbr.setOptions(options); | ||
| 592 | + | ||
| 593 | + if (initialize == OspfUtil.INITIALIZE_SET && more == OspfUtil.MORE_SET && | ||
| 594 | + masterOrSlave == OspfUtil.IS_MASTER) { | ||
| 595 | + if (ddPacket.getLsaHeaderList().isEmpty()) { | ||
| 596 | + if (OspfUtil.ipAddressToLong(ddPacket.routerId().toString()) > | ||
| 597 | + OspfUtil.ipAddressToLong(ospfArea.routerId().toString())) { | ||
| 598 | + nbr.setIsMaster(OspfUtil.IS_MASTER); | ||
| 599 | + ((OspfNbrImpl) nbr).setLastDdPacket(ddPacket); | ||
| 600 | + nbr.setDdSeqNum(ddPacket.sequenceNo()); | ||
| 601 | + nbr.setOptions(ddPacket.options()); | ||
| 602 | + ((OspfNbrImpl) nbr).negotiationDone(ddPacket, true, ddPacket.getLsaHeaderList(), | ||
| 603 | + ctx.getChannel()); | ||
| 604 | + } | ||
| 605 | + } | ||
| 606 | + } | ||
| 607 | + if (initialize == OspfUtil.INITIALIZE_NOTSET && masterOrSlave == OspfUtil.NOT_MASTER) { | ||
| 608 | + if (nbr.ddSeqNum() == ddPacket.sequenceNo()) { | ||
| 609 | + if (OspfUtil.ipAddressToLong(ddPacket.routerId().toString()) < | ||
| 610 | + OspfUtil.ipAddressToLong(ospfArea.routerId().toString())) { | ||
| 611 | + ((OspfNbrImpl) nbr).setLastDdPacket(ddPacket); | ||
| 612 | + nbr.setOptions(ddPacket.options()); | ||
| 613 | + nbr.setDdSeqNum(nbr.ddSeqNum() + 1); | ||
| 614 | + ((OspfNbrImpl) nbr).negotiationDone(ddPacket, false, ddPacket.getLsaHeaderList(), | ||
| 615 | + ctx.getChannel()); | ||
| 616 | + } | ||
| 617 | + } | ||
| 618 | + } | ||
| 619 | + | ||
| 620 | + } else if (nbr.getState() == OspfNeighborState.EXCHANGE) { | ||
| 621 | + //get I,M,MS Bits | ||
| 622 | + log.debug("Neighbor state:: EXCHANGE"); | ||
| 623 | + boolean isDuplicateDDPacket = compareDdPackets(ddPacket, ((OspfNbrImpl) nbr).lastDdPacket()); | ||
| 624 | + int initialize = ddPacket.isInitialize(); | ||
| 625 | + int more = ddPacket.isMore(); | ||
| 626 | + int masterOrSlave = ddPacket.isMaster(); | ||
| 627 | + int options = ddPacket.options(); | ||
| 628 | + | ||
| 629 | + if (!isDuplicateDDPacket) { | ||
| 630 | + //if dd packet is not duplicate then continue | ||
| 631 | + if (nbr.isMaster() != masterOrSlave) { | ||
| 632 | + DdPacket newResPacket = | ||
| 633 | + (DdPacket) ((OspfNbrImpl) nbr).seqNumMismatch("Master/Slave Inconsistency"); | ||
| 634 | + newResPacket.setDestinationIp(ddPacket.sourceIp()); | ||
| 635 | + log.debug("Sending back DDPacket to {}", ddPacket.sourceIp()); | ||
| 636 | + ctx.getChannel().write(newResPacket); | ||
| 637 | + } else if (initialize == 1) { | ||
| 638 | + DdPacket newResPacket = | ||
| 639 | + (DdPacket) ((OspfNbrImpl) nbr).seqNumMismatch("Initialize bit inconsistency"); | ||
| 640 | + newResPacket.setDestinationIp(ddPacket.sourceIp()); | ||
| 641 | + log.debug("Sending back DDPacket to {}", ddPacket.sourceIp()); | ||
| 642 | + ctx.getChannel().write(newResPacket); | ||
| 643 | + } else { | ||
| 644 | + | ||
| 645 | + if (masterOrSlave == OspfUtil.NOT_MASTER) { | ||
| 646 | + if (ddPacket.sequenceNo() == nbr.ddSeqNum()) { | ||
| 647 | + //Process the DD Packet | ||
| 648 | + ((OspfNbrImpl) nbr).processDdPacket(false, ddPacket, ctx.getChannel()); | ||
| 649 | + log.debug("Received DD Packet"); | ||
| 650 | + } else { | ||
| 651 | + DdPacket newResPacket = | ||
| 652 | + (DdPacket) ((OspfNbrImpl) nbr).seqNumMismatch("Sequence Number Mismatch"); | ||
| 653 | + newResPacket.setDestinationIp(ddPacket.sourceIp()); | ||
| 654 | + log.debug("Sending back DDPacket to {}", ddPacket.sourceIp()); | ||
| 655 | + ctx.getChannel().write(newResPacket); | ||
| 656 | + } | ||
| 657 | + } else { | ||
| 658 | + //we are the slave | ||
| 659 | + if (ddPacket.sequenceNo() == (nbr.ddSeqNum() + 1)) { | ||
| 660 | + ((OspfNbrImpl) nbr).setLastDdPacket(ddPacket); | ||
| 661 | + ((OspfNbrImpl) nbr).processDdPacket(true, ddPacket, ctx.getChannel()); | ||
| 662 | + log.debug("Process DD Packet"); | ||
| 663 | + } else { | ||
| 664 | + DdPacket newResPacket = | ||
| 665 | + (DdPacket) ((OspfNbrImpl) nbr).seqNumMismatch("options inconsistency"); | ||
| 666 | + newResPacket.setDestinationIp(ddPacket.sourceIp()); | ||
| 667 | + log.debug("Sending back DDPacket to {}", ddPacket.sourceIp()); | ||
| 668 | + ctx.getChannel().write(newResPacket); | ||
| 669 | + } | ||
| 670 | + } | ||
| 671 | + } | ||
| 672 | + } else { | ||
| 673 | + if (masterOrSlave == OspfUtil.NOT_MASTER) { | ||
| 674 | + return; | ||
| 675 | + } else { | ||
| 676 | + DdPacket newResPacket = ((OspfNbrImpl) nbr).lastSentDdPacket(); | ||
| 677 | + log.debug("Sending back DDPacket to {}", ddPacket.sourceIp()); | ||
| 678 | + ctx.getChannel().write(newResPacket); | ||
| 679 | + } | ||
| 680 | + } | ||
| 681 | + } else if (nbr.getState() == OspfNeighborState.LOADING || nbr.getState() == OspfNeighborState.FULL) { | ||
| 682 | + //In case if we are slave then we have to send the last received DD Packet | ||
| 683 | + int options = ddPacket.options(); | ||
| 684 | + if (nbr.options() != options) { | ||
| 685 | + OspfMessage newResPacket = ((OspfNbrImpl) nbr).seqNumMismatch("Initialize bit inconsistency"); | ||
| 686 | + newResPacket.setDestinationIp(ddPacket.sourceIp()); | ||
| 687 | + ctx.getChannel().write(newResPacket); | ||
| 688 | + } else if (ddPacket.isInitialize() == OspfUtil.INITIALIZE_SET) { | ||
| 689 | + OspfMessage newResPacket = ((OspfNbrImpl) nbr).seqNumMismatch("Initialize bit inconsistency"); | ||
| 690 | + newResPacket.setDestinationIp(ddPacket.sourceIp()); | ||
| 691 | + ctx.getChannel().write(newResPacket); | ||
| 692 | + } | ||
| 693 | + boolean isDuplicate = compareDdPackets(ddPacket, ((OspfNbrImpl) nbr).lastDdPacket()); | ||
| 694 | + //we are master | ||
| 695 | + if (nbr.isMaster() != OspfUtil.IS_MASTER) { | ||
| 696 | + // check if the packet is duplicate, duplicates should be discarded by the master | ||
| 697 | + if (isDuplicate) { | ||
| 698 | + log.debug("received a duplicate DD packet"); | ||
| 699 | + } | ||
| 700 | + } else { | ||
| 701 | + //The slave must respond to duplicates by repeating the last Database Description packet | ||
| 702 | + //that it had sent. | ||
| 703 | + if (isDuplicate) { | ||
| 704 | + ddPacket.setDestinationIp(ddPacket.sourceIp()); | ||
| 705 | + ctx.getChannel().write(((OspfNbrImpl) nbr).lastSentDdPacket()); | ||
| 706 | + log.debug("Sending back the duplicate packet "); | ||
| 707 | + } | ||
| 708 | + } | ||
| 709 | + } | ||
| 710 | + } | ||
| 711 | + } | ||
| 712 | + | ||
| 713 | + /** | ||
| 714 | + * Process the Ls Request message. | ||
| 715 | + * | ||
| 716 | + * @param ospfMessage OSPF message instance. | ||
| 717 | + * @param ctx channel handler context instance. | ||
| 718 | + * @throws Exception might throws exception | ||
| 719 | + */ | ||
| 720 | + void processLsRequestMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception { | ||
| 721 | + log.debug("OspfChannelHandler::processLsRequestMessage...!!!"); | ||
| 722 | + LsRequest lsrPacket = (LsRequest) ospfMessage; | ||
| 723 | + OspfNbr nbr = ospfInterface.neighbouringRouter(lsrPacket.routerId().toString()); | ||
| 724 | + | ||
| 725 | + if (nbr.getState() == OspfNeighborState.EXCHANGE || nbr.getState() == OspfNeighborState.LOADING || | ||
| 726 | + nbr.getState() == OspfNeighborState.FULL) { | ||
| 727 | + | ||
| 728 | + LsRequest reqMsg = (LsRequest) ospfMessage; | ||
| 729 | + if (reqMsg.getLinkStateRequests().isEmpty()) { | ||
| 730 | + log.debug("Received Link State Request Vector is Empty "); | ||
| 731 | + return; | ||
| 732 | + } else { | ||
| 733 | + //Send the LsUpdate back | ||
| 734 | + ListIterator<LsRequestPacket> listItr = reqMsg.getLinkStateRequests().listIterator(); | ||
| 735 | + while (listItr.hasNext()) { | ||
| 736 | + LsUpdate lsupdate = new LsUpdate(); | ||
| 737 | + lsupdate.setOspfVer(OspfUtil.OSPF_VERSION); | ||
| 738 | + lsupdate.setOspftype(OspfPacketType.LSUPDATE.value()); | ||
| 739 | + lsupdate.setRouterId(ospfArea.routerId()); | ||
| 740 | + lsupdate.setAreaId(ospfArea.areaId()); | ||
| 741 | + lsupdate.setAuthType(OspfUtil.NOT_ASSIGNED); | ||
| 742 | + lsupdate.setAuthentication(OspfUtil.NOT_ASSIGNED); | ||
| 743 | + lsupdate.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length | ||
| 744 | + lsupdate.setChecksum(OspfUtil.NOT_ASSIGNED); | ||
| 745 | + | ||
| 746 | + //limit to mtu | ||
| 747 | + int currentLength = OspfUtil.OSPF_HEADER_LENGTH + OspfUtil.FOUR_BYTES; | ||
| 748 | + int maxSize = ospfInterface.mtu() - | ||
| 749 | + OspfUtil.LSA_HEADER_LENGTH; // subtract a normal IP header. | ||
| 750 | + int noLsa = 0; | ||
| 751 | + while (listItr.hasNext()) { | ||
| 752 | + LsRequestPacket lsRequest = (LsRequestPacket) listItr.next(); | ||
| 753 | + // to verify length of the LSA | ||
| 754 | + LsaWrapper wrapper = ospfArea.getLsa(lsRequest.lsType(), lsRequest.linkStateId(), | ||
| 755 | + lsRequest.ownRouterId()); | ||
| 756 | + OspfLsa ospflsa = wrapper.ospfLsa(); | ||
| 757 | + if ((currentLength + ((LsaWrapperImpl) wrapper).lsaHeader().lsPacketLen()) >= maxSize) { | ||
| 758 | + listItr.previous(); | ||
| 759 | + break; | ||
| 760 | + } | ||
| 761 | + if (ospflsa != null) { | ||
| 762 | + lsupdate.addLsa(ospflsa); | ||
| 763 | + noLsa++; | ||
| 764 | + | ||
| 765 | + currentLength = currentLength + ((LsaWrapperImpl) wrapper).lsaHeader().lsPacketLen(); | ||
| 766 | + } else { | ||
| 767 | + nbr.badLSReq(channel); | ||
| 768 | + } | ||
| 769 | + } | ||
| 770 | + lsupdate.setNumberOfLsa(noLsa); | ||
| 771 | + //set the destination | ||
| 772 | + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR || | ||
| 773 | + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR || | ||
| 774 | + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT) { | ||
| 775 | + lsupdate.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS); | ||
| 776 | + } else if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER) { | ||
| 777 | + lsupdate.setDestinationIp(OspfUtil.ALL_DROUTERS); | ||
| 778 | + } | ||
| 779 | + ctx.getChannel().write(lsupdate); | ||
| 780 | + } | ||
| 781 | + } | ||
| 782 | + } | ||
| 783 | + } | ||
| 784 | + | ||
| 785 | + /** | ||
| 786 | + * Process the ls update message. | ||
| 787 | + * | ||
| 788 | + * @param ospfMessage OSPF message instance. | ||
| 789 | + * @param ctx channel handler context instance. | ||
| 790 | + * @throws Exception might throws exception | ||
| 791 | + */ | ||
| 792 | + void processLsUpdateMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception { | ||
| 793 | + log.debug("OspfChannelHandler::processLsUpdateMessage"); | ||
| 794 | + LsUpdate lsUpdate = (LsUpdate) ospfMessage; | ||
| 795 | + String neighbourId = lsUpdate.routerId().toString(); | ||
| 796 | + //LSUpdate packet has been associated with a particular neighbor. | ||
| 797 | + //Neighbor should not be in lesser state than Exchange. | ||
| 798 | + if (ospfInterface.isNeighborInList(neighbourId)) { | ||
| 799 | + OspfNbrImpl nbr = (OspfNbrImpl) ospfInterface.neighbouringRouter(neighbourId); | ||
| 800 | + if (nbr.getState() == OspfNeighborState.EXCHANGE || | ||
| 801 | + nbr.getState() == OspfNeighborState.LOADING) { | ||
| 802 | + nbr.processLsUpdate(lsUpdate, ctx.getChannel()); | ||
| 803 | + } else if (nbr.getState() == OspfNeighborState.FULL) { | ||
| 804 | + if (lsUpdate.noLsa() != 0) { | ||
| 805 | + List<OspfLsa> list = lsUpdate.getLsaList(); | ||
| 806 | + Iterator itr = list.iterator(); | ||
| 807 | + while (itr.hasNext()) { | ||
| 808 | + LsaHeader lsa = (LsaHeader) itr.next(); | ||
| 809 | + nbr.processReceivedLsa(lsa, true, ctx.getChannel(), lsUpdate.sourceIp()); | ||
| 810 | + } | ||
| 811 | + } else { | ||
| 812 | + return; | ||
| 813 | + } | ||
| 814 | + } | ||
| 815 | + } | ||
| 816 | + } | ||
| 817 | + | ||
| 818 | + /** | ||
| 819 | + * Process the ls acknowledge message. | ||
| 820 | + * | ||
| 821 | + * @param ospfMessage OSPF message instance. | ||
| 822 | + * @param ctx channel handler context instance. | ||
| 823 | + * @throws Exception might throws exception | ||
| 824 | + */ | ||
| 825 | + void processLsAckMessage(OspfMessage ospfMessage, ChannelHandlerContext ctx) throws Exception { | ||
| 826 | + log.debug("OspfChannelHandler::processLsAckMessage"); | ||
| 827 | + LsAcknowledge lsAckPacket = (LsAcknowledge) ospfMessage; | ||
| 828 | + //check it is present in listOfNeighbors | ||
| 829 | + OspfNbrImpl nbr = (OspfNbrImpl) ospfInterface.neighbouringRouter(lsAckPacket.routerId().toString()); | ||
| 830 | + if (nbr != null) { | ||
| 831 | + if (nbr.getState().getValue() < OspfNeighborState.EXCHANGE.getValue()) { | ||
| 832 | + // discard the packet. | ||
| 833 | + return; | ||
| 834 | + } else { | ||
| 835 | + // process ls acknowledgements | ||
| 836 | + Iterator itr = lsAckPacket.getLinkStateHeaders().iterator(); | ||
| 837 | + while (itr.hasNext()) { | ||
| 838 | + LsaHeader lsRequest = (LsaHeader) itr.next(); | ||
| 839 | + | ||
| 840 | + OspfLsa ospfLsa = | ||
| 841 | + (OspfLsa) nbr.getPendingReTxList().get(((OspfAreaImpl) ospfArea).getLsaKey(lsRequest)); | ||
| 842 | + if (lsRequest != null && ospfLsa != null) { | ||
| 843 | + String isSame = ((OspfLsdbImpl) ospfArea.database()).isNewerOrSameLsa( | ||
| 844 | + lsRequest, (LsaHeader) ospfLsa); | ||
| 845 | + if (isSame.equals("same")) { | ||
| 846 | + nbr.getPendingReTxList().remove(((OspfAreaImpl) ospfArea).getLsaKey(lsRequest)); | ||
| 847 | + } | ||
| 848 | + } | ||
| 849 | + } | ||
| 850 | + } | ||
| 851 | + } | ||
| 852 | + } | ||
| 853 | + | ||
| 854 | + /** | ||
| 855 | + * Compares two Dd Packets to check whether its duplicate or not. | ||
| 856 | + * | ||
| 857 | + * @param receivedDPacket received DD packet from network. | ||
| 858 | + * @param lastDdPacket Last DdPacket which we sent. | ||
| 859 | + * @return true if it is a duplicate packet else false. | ||
| 860 | + */ | ||
| 861 | + public boolean compareDdPackets(DdPacket receivedDPacket, DdPacket lastDdPacket) { | ||
| 862 | + if (receivedDPacket.isInitialize() == lastDdPacket.isInitialize()) { | ||
| 863 | + if (receivedDPacket.isMaster() == lastDdPacket.isMaster()) { | ||
| 864 | + if (receivedDPacket.isMore() == lastDdPacket.isMore()) { | ||
| 865 | + if (receivedDPacket.options() == lastDdPacket.options()) { | ||
| 866 | + if (receivedDPacket.sequenceNo() == lastDdPacket.sequenceNo()) { | ||
| 867 | + return true; | ||
| 868 | + } | ||
| 869 | + } | ||
| 870 | + } | ||
| 871 | + } | ||
| 872 | + } | ||
| 873 | + return false; | ||
| 874 | + } | ||
| 875 | + | ||
| 876 | + /** | ||
| 877 | + * Closes the Netty channel. | ||
| 878 | + * | ||
| 879 | + * @param ctx the Channel Handler Context | ||
| 880 | + */ | ||
| 881 | + void closeChannel(ChannelHandlerContext ctx) { | ||
| 882 | + log.debug("OspfChannelHandler::closeChannel"); | ||
| 883 | + isClosed = true; | ||
| 884 | + ctx.getChannel().close(); | ||
| 885 | + } | ||
| 886 | + | ||
| 887 | + /** | ||
| 888 | + * Starts the hello timer which sends hello packet every configured seconds. | ||
| 889 | + * | ||
| 890 | + * @param period the interval to run task | ||
| 891 | + */ | ||
| 892 | + private void startHelloTimer(long period) { | ||
| 893 | + log.debug("OSPFInterfaceChannelHandler::startHelloTimer"); | ||
| 894 | + exServiceHello = Executors.newSingleThreadScheduledExecutor(); | ||
| 895 | + helloTimerTask = new InternalHelloTimer(); | ||
| 896 | + final ScheduledFuture<?> helloHandle = | ||
| 897 | + exServiceHello.scheduleAtFixedRate(helloTimerTask, delay, period, TimeUnit.SECONDS); | ||
| 898 | + } | ||
| 899 | + | ||
| 900 | + /** | ||
| 901 | + * Stops the hello timer. | ||
| 902 | + */ | ||
| 903 | + private void stopHelloTimer() { | ||
| 904 | + log.debug("OSPFInterfaceChannelHandler::stopHelloTimer "); | ||
| 905 | + exServiceHello.shutdown(); | ||
| 906 | + } | ||
| 907 | + | ||
| 908 | + /** | ||
| 909 | + * Starts the wait timer. | ||
| 910 | + */ | ||
| 911 | + private void startWaitTimer() { | ||
| 912 | + log.debug("OSPFNbr::startWaitTimer"); | ||
| 913 | + exServiceWait = Executors.newSingleThreadScheduledExecutor(); | ||
| 914 | + waitTimerTask = new InternalWaitTimer(); | ||
| 915 | + final ScheduledFuture<?> waitTimerHandle = | ||
| 916 | + exServiceWait.schedule(waitTimerTask, ospfInterface.routerDeadIntervalTime(), | ||
| 917 | + TimeUnit.SECONDS); | ||
| 918 | + } | ||
| 919 | + | ||
| 920 | + /** | ||
| 921 | + * Stops the wait timer. | ||
| 922 | + */ | ||
| 923 | + private void stopWaitTimer() { | ||
| 924 | + log.debug("OSPFNbr::stopWaitTimer "); | ||
| 925 | + exServiceWait.shutdown(); | ||
| 926 | + } | ||
| 927 | + | ||
| 928 | + /** | ||
| 929 | + * Starts the timer which waits for configured seconds and sends Delayed Ack Packet. | ||
| 930 | + */ | ||
| 931 | + private void startDelayedAckTimer() { | ||
| 932 | + if (!isDelayedAckTimerScheduled) { | ||
| 933 | + log.debug("Started DelayedAckTimer...!!!"); | ||
| 934 | + exServiceDelayedAck = Executors.newSingleThreadScheduledExecutor(); | ||
| 935 | + delayedAckTimerTask = new InternalDelayedAckTimer(); | ||
| 936 | + final ScheduledFuture<?> delayAckHandle = | ||
| 937 | + exServiceDelayedAck.scheduleAtFixedRate(delayedAckTimerTask, delayedAckTimerInterval, | ||
| 938 | + delayedAckTimerInterval, TimeUnit.MILLISECONDS); | ||
| 939 | + isDelayedAckTimerScheduled = true; | ||
| 940 | + } | ||
| 941 | + } | ||
| 942 | + | ||
| 943 | + /** | ||
| 944 | + * Stops the delayed acknowledge timer. | ||
| 945 | + */ | ||
| 946 | + private void stopDelayedAckTimer() { | ||
| 947 | + if (isDelayedAckTimerScheduled) { | ||
| 948 | + log.debug("Stopped DelayedAckTimer...!!!"); | ||
| 949 | + isDelayedAckTimerScheduled = false; | ||
| 950 | + exServiceDelayedAck.shutdown(); | ||
| 951 | + } | ||
| 952 | + } | ||
| 953 | + | ||
| 954 | + /** | ||
| 955 | + * Performs DR election. | ||
| 956 | + * | ||
| 957 | + * @param ch Netty Channel instance. | ||
| 958 | + * @throws Exception might throws exception | ||
| 959 | + */ | ||
| 960 | + public void electRouter(Channel ch) throws Exception { | ||
| 961 | + | ||
| 962 | + Ip4Address currentDr = ospfInterface.dr(); | ||
| 963 | + Ip4Address currentBdr = ospfInterface.bdr(); | ||
| 964 | + OspfInterfaceState oldState = ((OspfInterfaceImpl) ospfInterface).state(); | ||
| 965 | + OspfInterfaceState newState; | ||
| 966 | + | ||
| 967 | + log.debug("OSPFInterfaceChannelHandler::electRouter -> currentDr: {}, currentBdr: {}", | ||
| 968 | + currentDr, currentBdr); | ||
| 969 | + List<OspfEligibleRouter> eligibleRouters = calculateListOfEligibleRouters(new OspfEligibleRouter()); | ||
| 970 | + | ||
| 971 | + log.debug("OSPFInterfaceChannelHandler::electRouter -> eligibleRouters: {}", eligibleRouters); | ||
| 972 | + OspfEligibleRouter electedBdr = electBdr(eligibleRouters); | ||
| 973 | + OspfEligibleRouter electedDr = electDr(eligibleRouters, electedBdr); | ||
| 974 | + | ||
| 975 | + ospfInterface.setBdr(electedBdr.getIpAddress()); | ||
| 976 | + ospfInterface.setDr(electedDr.getIpAddress()); | ||
| 977 | + | ||
| 978 | + if (electedBdr.getIpAddress().equals(ospfInterface.ipAddress()) && | ||
| 979 | + !electedBdr.getIpAddress().equals(currentBdr)) { | ||
| 980 | + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.BDR); | ||
| 981 | + } | ||
| 982 | + | ||
| 983 | + if (electedDr.getIpAddress().equals(ospfInterface.ipAddress()) && | ||
| 984 | + !electedDr.getIpAddress().equals(currentDr)) { | ||
| 985 | + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DR); | ||
| 986 | + } | ||
| 987 | + | ||
| 988 | + if (((OspfInterfaceImpl) ospfInterface).state() != oldState && | ||
| 989 | + !(((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER && | ||
| 990 | + oldState.value() < OspfInterfaceState.DROTHER.value())) { | ||
| 991 | + log.debug("Recalculating as the State is changed "); | ||
| 992 | + log.debug("OSPFInterfaceChannelHandler::electRouter -> currentDr: {}, currentBdr: {}", | ||
| 993 | + currentDr, currentBdr); | ||
| 994 | + eligibleRouters = calculateListOfEligibleRouters(new OspfEligibleRouter()); | ||
| 995 | + | ||
| 996 | + log.debug("OSPFInterfaceChannelHandler::electRouter -> eligibleRouters: {}", eligibleRouters); | ||
| 997 | + electedBdr = electBdr(eligibleRouters); | ||
| 998 | + electedDr = electDr(eligibleRouters, electedBdr); | ||
| 999 | + | ||
| 1000 | + ospfInterface.setBdr(electedBdr.getIpAddress()); | ||
| 1001 | + ospfInterface.setDr(electedDr.getIpAddress()); | ||
| 1002 | + } | ||
| 1003 | + | ||
| 1004 | + if (electedBdr.getIpAddress().equals(ospfInterface.ipAddress()) && | ||
| 1005 | + !electedBdr.getIpAddress().equals(currentBdr)) { | ||
| 1006 | + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.BDR); | ||
| 1007 | + ospfArea.refreshArea(ospfInterface); | ||
| 1008 | + } | ||
| 1009 | + | ||
| 1010 | + if (electedDr.getIpAddress().equals(ospfInterface.ipAddress()) && | ||
| 1011 | + !electedDr.getIpAddress().equals(currentDr)) { | ||
| 1012 | + ((OspfInterfaceImpl) ospfInterface).setState(OspfInterfaceState.DR); | ||
| 1013 | + //Refresh Router Lsa & Network Lsa | ||
| 1014 | + ospfArea.refreshArea(ospfInterface); | ||
| 1015 | + } | ||
| 1016 | + | ||
| 1017 | + if (currentDr != electedDr.getIpAddress() || currentBdr != electedBdr.getIpAddress()) { | ||
| 1018 | + Set<String> negibhorIdList; | ||
| 1019 | + negibhorIdList = ospfInterface.listOfNeighbors().keySet(); | ||
| 1020 | + for (String routerid : negibhorIdList) { | ||
| 1021 | + OspfNbrImpl nbr = (OspfNbrImpl) ospfInterface.neighbouringRouter(routerid); | ||
| 1022 | + if (nbr.getState().getValue() >= OspfNeighborState.TWOWAY.getValue()) { | ||
| 1023 | + nbr.adjOk(ch); | ||
| 1024 | + } | ||
| 1025 | + } | ||
| 1026 | + } | ||
| 1027 | + | ||
| 1028 | + log.debug("OSPFInterfaceChannelHandler::electRouter -> ElectedDR: {}, ElectedBDR: {}", | ||
| 1029 | + electedDr.getIpAddress(), electedBdr.getIpAddress()); | ||
| 1030 | + } | ||
| 1031 | + | ||
| 1032 | + | ||
| 1033 | + /** | ||
| 1034 | + * BDR Election process. Find the list of eligible router to participate in the process. | ||
| 1035 | + * | ||
| 1036 | + * @param electedDr router elected as DR. | ||
| 1037 | + * @return list of eligible routers | ||
| 1038 | + */ | ||
| 1039 | + public List<OspfEligibleRouter> calculateListOfEligibleRouters(OspfEligibleRouter electedDr) { | ||
| 1040 | + log.debug("OSPFNbr::calculateListOfEligibleRouters "); | ||
| 1041 | + Set<String> neighborIdList; | ||
| 1042 | + List<OspfEligibleRouter> eligibleRouters = new ArrayList<>(); | ||
| 1043 | + | ||
| 1044 | + neighborIdList = ospfInterface.listOfNeighbors().keySet(); | ||
| 1045 | + for (String routerId : neighborIdList) { | ||
| 1046 | + OspfNbrImpl nbr = (OspfNbrImpl) ospfInterface.neighbouringRouter(routerId); | ||
| 1047 | + if (nbr.getState().getValue() >= OspfNeighborState.TWOWAY.getValue() && | ||
| 1048 | + nbr.routerPriority() > 0) { | ||
| 1049 | + OspfEligibleRouter router = new OspfEligibleRouter(); | ||
| 1050 | + router.setIpAddress(nbr.neighborIpAddr()); | ||
| 1051 | + router.setRouterId(nbr.neighborId()); | ||
| 1052 | + router.setRouterPriority(nbr.routerPriority()); | ||
| 1053 | + if (nbr.neighborDr().equals(nbr.neighborIpAddr()) || | ||
| 1054 | + electedDr.getIpAddress().equals(nbr.neighborIpAddr())) { | ||
| 1055 | + router.setIsDr(true); | ||
| 1056 | + } else if (nbr.neighborBdr().equals(nbr.neighborIpAddr())) { | ||
| 1057 | + router.setIsBdr(true); | ||
| 1058 | + } | ||
| 1059 | + eligibleRouters.add(router); | ||
| 1060 | + } | ||
| 1061 | + } | ||
| 1062 | + // interface does not have states like two and all | ||
| 1063 | + if (ospfInterface.routerPriority() > 0) { | ||
| 1064 | + OspfEligibleRouter router = new OspfEligibleRouter(); | ||
| 1065 | + router.setIpAddress(ospfInterface.ipAddress()); | ||
| 1066 | + router.setRouterId(ospfArea.routerId()); | ||
| 1067 | + router.setRouterPriority(ospfInterface.routerPriority()); | ||
| 1068 | + if (ospfInterface.dr().equals(ospfInterface.ipAddress()) || | ||
| 1069 | + electedDr.getIpAddress().equals(ospfInterface.ipAddress())) { | ||
| 1070 | + router.setIsDr(true); | ||
| 1071 | + } else if (ospfInterface.bdr().equals(ospfInterface.ipAddress()) && | ||
| 1072 | + !ospfInterface.dr().equals(ospfInterface.ipAddress())) { | ||
| 1073 | + router.setIsBdr(true); | ||
| 1074 | + } | ||
| 1075 | + | ||
| 1076 | + eligibleRouters.add(router); | ||
| 1077 | + } | ||
| 1078 | + | ||
| 1079 | + return eligibleRouters; | ||
| 1080 | + } | ||
| 1081 | + | ||
| 1082 | + /** | ||
| 1083 | + * Based on router priority assigns BDR. | ||
| 1084 | + * | ||
| 1085 | + * @param eligibleRouters list of routers to participate in bdr election. | ||
| 1086 | + * @return OSPF Eligible router instance. | ||
| 1087 | + */ | ||
| 1088 | + public OspfEligibleRouter electBdr(List<OspfEligibleRouter> eligibleRouters) { | ||
| 1089 | + log.debug("OSPFInterfaceChannelHandler::electBdr -> eligibleRouters: {}", eligibleRouters); | ||
| 1090 | + List<OspfEligibleRouter> declaredAsBdr = new ArrayList<>(); | ||
| 1091 | + List<OspfEligibleRouter> notDrAndBdr = new ArrayList<>(); | ||
| 1092 | + for (OspfEligibleRouter router : eligibleRouters) { | ||
| 1093 | + if (router.isBdr()) { | ||
| 1094 | + declaredAsBdr.add(router); | ||
| 1095 | + } | ||
| 1096 | + if (!router.isBdr() && !router.isDr()) { | ||
| 1097 | + notDrAndBdr.add(router); | ||
| 1098 | + } | ||
| 1099 | + } | ||
| 1100 | + | ||
| 1101 | + OspfEligibleRouter electedBdr = new OspfEligibleRouter(); | ||
| 1102 | + if (!declaredAsBdr.isEmpty()) { | ||
| 1103 | + if (declaredAsBdr.size() == 1) { | ||
| 1104 | + electedBdr = declaredAsBdr.get(0); | ||
| 1105 | + } else if (declaredAsBdr.size() > 1) { | ||
| 1106 | + electedBdr = selectRouterBasedOnPriority(declaredAsBdr); | ||
| 1107 | + } | ||
| 1108 | + } else { | ||
| 1109 | + if (notDrAndBdr.size() == 1) { | ||
| 1110 | + electedBdr = notDrAndBdr.get(0); | ||
| 1111 | + } else if (notDrAndBdr.size() > 1) { | ||
| 1112 | + electedBdr = selectRouterBasedOnPriority(notDrAndBdr); | ||
| 1113 | + } | ||
| 1114 | + } | ||
| 1115 | + | ||
| 1116 | + electedBdr.setIsBdr(true); | ||
| 1117 | + electedBdr.setIsDr(false); | ||
| 1118 | + | ||
| 1119 | + return electedBdr; | ||
| 1120 | + } | ||
| 1121 | + | ||
| 1122 | + /** | ||
| 1123 | + * DR Election process. | ||
| 1124 | + * | ||
| 1125 | + * @param eligibleRouters list of eligible routers. | ||
| 1126 | + * @param electedBdr Elected Bdr, OSPF eligible router instance. | ||
| 1127 | + * @return OSPF eligible router instance. | ||
| 1128 | + */ | ||
| 1129 | + public OspfEligibleRouter electDr(List<OspfEligibleRouter> eligibleRouters, | ||
| 1130 | + OspfEligibleRouter electedBdr) { | ||
| 1131 | + | ||
| 1132 | + List<OspfEligibleRouter> declaredAsDr = new ArrayList<>(); | ||
| 1133 | + for (OspfEligibleRouter router : eligibleRouters) { | ||
| 1134 | + if (router.isDr()) { | ||
| 1135 | + declaredAsDr.add(router); | ||
| 1136 | + } | ||
| 1137 | + } | ||
| 1138 | + | ||
| 1139 | + OspfEligibleRouter electedDr = new OspfEligibleRouter(); | ||
| 1140 | + if (!declaredAsDr.isEmpty()) { | ||
| 1141 | + if (declaredAsDr.size() == 1) { | ||
| 1142 | + electedDr = declaredAsDr.get(0); | ||
| 1143 | + } else if (eligibleRouters.size() > 1) { | ||
| 1144 | + electedDr = selectRouterBasedOnPriority(declaredAsDr); | ||
| 1145 | + } | ||
| 1146 | + } else { | ||
| 1147 | + electedDr = electedBdr; | ||
| 1148 | + electedDr.setIsDr(true); | ||
| 1149 | + electedDr.setIsBdr(false); | ||
| 1150 | + } | ||
| 1151 | + | ||
| 1152 | + return electedDr; | ||
| 1153 | + } | ||
| 1154 | + | ||
| 1155 | + /** | ||
| 1156 | + * DR election process. | ||
| 1157 | + * | ||
| 1158 | + * @param routersList list of eligible routers. | ||
| 1159 | + * @return OSPF eligible router instance. | ||
| 1160 | + */ | ||
| 1161 | + public OspfEligibleRouter selectRouterBasedOnPriority(List<OspfEligibleRouter> routersList) { | ||
| 1162 | + | ||
| 1163 | + OspfEligibleRouter initialRouter = routersList.get(0); | ||
| 1164 | + | ||
| 1165 | + for (int i = 1; i < routersList.size(); i++) { | ||
| 1166 | + OspfEligibleRouter router = routersList.get(i); | ||
| 1167 | + if (router.getRouterPriority() > initialRouter.getRouterPriority()) { | ||
| 1168 | + initialRouter = router; | ||
| 1169 | + } else if (router.getRouterPriority() == initialRouter.getRouterPriority()) { | ||
| 1170 | + try { | ||
| 1171 | + //if (router.getIpAddress().toInt() > initialRouter.getIpAddress().toInt()) { | ||
| 1172 | + if (OspfUtil.ipAddressToLong(router.getIpAddress().toString()) > | ||
| 1173 | + OspfUtil.ipAddressToLong(initialRouter.getIpAddress().toString())) { | ||
| 1174 | + initialRouter = router; | ||
| 1175 | + } | ||
| 1176 | + } catch (Exception e) { | ||
| 1177 | + log.debug("OSPFInterfaceChannelHandler::selectRouterBasedOnPriority ->" + | ||
| 1178 | + " eligibleRouters: {}", initialRouter); | ||
| 1179 | + } | ||
| 1180 | + } | ||
| 1181 | + } | ||
| 1182 | + | ||
| 1183 | + return initialRouter; | ||
| 1184 | + } | ||
| 1185 | + | ||
| 1186 | + /** | ||
| 1187 | + * Adds device information. | ||
| 1188 | + * | ||
| 1189 | + * @param ospfRouter OSPF router instance | ||
| 1190 | + */ | ||
| 1191 | + public void addDeviceInformation(OspfRouter ospfRouter) { | ||
| 1192 | + controller.addDeviceDetails(ospfRouter); | ||
| 1193 | + } | ||
| 1194 | + | ||
| 1195 | + /** | ||
| 1196 | + * removes device information. | ||
| 1197 | + * | ||
| 1198 | + * @param ospfRouter OSPF neighbor instance | ||
| 1199 | + */ | ||
| 1200 | + public void removeDeviceInformation(OspfRouter ospfRouter) { | ||
| 1201 | + controller.removeDeviceDetails(ospfRouter); | ||
| 1202 | + } | ||
| 1203 | + | ||
| 1204 | + /** | ||
| 1205 | + * Adds link information. | ||
| 1206 | + * | ||
| 1207 | + * @param ospfRouter OSPF router instance | ||
| 1208 | + * @param ospfLinkTed list link ted instances | ||
| 1209 | + */ | ||
| 1210 | + public void addLinkInformation(OspfRouter ospfRouter, OspfLinkTed ospfLinkTed) { | ||
| 1211 | + controller.addLinkDetails(ospfRouter, ospfLinkTed); | ||
| 1212 | + } | ||
| 1213 | + | ||
| 1214 | + /** | ||
| 1215 | + * Removes link information. | ||
| 1216 | + * | ||
| 1217 | + * @param ospfNbr OSPF neighbor instance | ||
| 1218 | + */ | ||
| 1219 | + public void removeLinkInformation(OspfNbr ospfNbr) { | ||
| 1220 | + controller.removeLinkDetails(buildOspfRouterDetails(ospfNbr)); | ||
| 1221 | + } | ||
| 1222 | + | ||
| 1223 | + /** | ||
| 1224 | + * Builds router details. | ||
| 1225 | + * | ||
| 1226 | + * @param ospfNbr OSPF neighbor instance | ||
| 1227 | + * @return OSPF router instance | ||
| 1228 | + */ | ||
| 1229 | + private OspfRouter buildOspfRouterDetails(OspfNbr ospfNbr) { | ||
| 1230 | + OspfRouter ospfRouter = new OspfRouterImpl(); | ||
| 1231 | + ospfRouter.setRouterIp(ospfNbr.neighborId()); | ||
| 1232 | + ospfRouter.setInterfaceId(ospfInterface.ipAddress()); | ||
| 1233 | + ospfRouter.setAreaIdOfInterface(ospfArea.areaId()); | ||
| 1234 | + | ||
| 1235 | + ospfRouter.setDeviceTed(new OspfDeviceTedImpl()); | ||
| 1236 | + | ||
| 1237 | + return ospfRouter; | ||
| 1238 | + } | ||
| 1239 | + | ||
| 1240 | + /** | ||
| 1241 | + * Represents a Hello task which sent a hello message every configured time interval. | ||
| 1242 | + */ | ||
| 1243 | + private class InternalHelloTimer implements Runnable { | ||
| 1244 | + | ||
| 1245 | + /** | ||
| 1246 | + * Creates an instance of Hello Timer. | ||
| 1247 | + */ | ||
| 1248 | + InternalHelloTimer() { | ||
| 1249 | + } | ||
| 1250 | + | ||
| 1251 | + @Override | ||
| 1252 | + public void run() { | ||
| 1253 | + if (!isClosed && channel != null && channel.isOpen() && channel.isConnected()) { | ||
| 1254 | + | ||
| 1255 | + HelloPacket hellopacket = new HelloPacket(); | ||
| 1256 | + //Headers | ||
| 1257 | + hellopacket.setOspfVer(OspfUtil.OSPF_VERSION); | ||
| 1258 | + hellopacket.setOspftype(OspfPacketType.HELLO.value()); | ||
| 1259 | + hellopacket.setOspfPacLength(0); //will be modified while encoding | ||
| 1260 | + hellopacket.setRouterId(ospfArea.routerId()); | ||
| 1261 | + hellopacket.setAreaId(ospfArea.areaId()); | ||
| 1262 | + hellopacket.setChecksum(0); //will be modified while encoding | ||
| 1263 | + hellopacket.setAuthType(Integer.parseInt(ospfInterface.authType())); | ||
| 1264 | + hellopacket.setAuthentication(Integer.parseInt(ospfInterface.authKey())); | ||
| 1265 | + //Body | ||
| 1266 | + hellopacket.setNetworkMask(ospfInterface.ipNetworkMask()); | ||
| 1267 | + hellopacket.setOptions(ospfArea.options()); | ||
| 1268 | + hellopacket.setHelloInterval(ospfInterface.helloIntervalTime()); | ||
| 1269 | + hellopacket.setRouterPriority(ospfInterface.routerPriority()); | ||
| 1270 | + hellopacket.setRouterDeadInterval(ospfInterface.routerDeadIntervalTime()); | ||
| 1271 | + hellopacket.setDr(ospfInterface.dr()); | ||
| 1272 | + hellopacket.setBdr(ospfInterface.bdr()); | ||
| 1273 | + | ||
| 1274 | + HashMap<String, OspfNbr> listOfNeighbors = ospfInterface.listOfNeighbors(); | ||
| 1275 | + Set<String> keys = listOfNeighbors.keySet(); | ||
| 1276 | + Iterator itr = keys.iterator(); | ||
| 1277 | + while (itr.hasNext()) { | ||
| 1278 | + String nbrKey = (String) itr.next(); | ||
| 1279 | + OspfNbrImpl nbr = (OspfNbrImpl) listOfNeighbors.get(nbrKey); | ||
| 1280 | + if (nbr.getState() != OspfNeighborState.DOWN) { | ||
| 1281 | + hellopacket.addNeighbor(Ip4Address.valueOf(nbrKey)); | ||
| 1282 | + } | ||
| 1283 | + } | ||
| 1284 | + // build a hello Packet | ||
| 1285 | + if (channel == null || !channel.isOpen() || !channel.isConnected()) { | ||
| 1286 | + log.debug("Hello Packet not sent !!.. Channel Issue..."); | ||
| 1287 | + return; | ||
| 1288 | + } | ||
| 1289 | + | ||
| 1290 | + hellopacket.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS); | ||
| 1291 | + ChannelFuture future = channel.write(hellopacket); | ||
| 1292 | + if (future.isSuccess()) { | ||
| 1293 | + log.debug("Hello Packet successfully sent !!"); | ||
| 1294 | + } else { | ||
| 1295 | + future.awaitUninterruptibly(); | ||
| 1296 | + } | ||
| 1297 | + | ||
| 1298 | + } | ||
| 1299 | + } | ||
| 1300 | + } | ||
| 1301 | + | ||
| 1302 | + /** | ||
| 1303 | + * Represents a Wait Timer task which waits the interface state to become WAITING. | ||
| 1304 | + * It initiates DR election process. | ||
| 1305 | + */ | ||
| 1306 | + private class InternalWaitTimer implements Runnable { | ||
| 1307 | + Channel ch; | ||
| 1308 | + | ||
| 1309 | + /** | ||
| 1310 | + * Creates an instance of Wait Timer. | ||
| 1311 | + */ | ||
| 1312 | + InternalWaitTimer() { | ||
| 1313 | + this.ch = channel; | ||
| 1314 | + } | ||
| 1315 | + | ||
| 1316 | + @Override | ||
| 1317 | + public void run() { | ||
| 1318 | + log.debug("Wait timer expires..."); | ||
| 1319 | + if (ch != null && ch.isConnected()) { | ||
| 1320 | + try { | ||
| 1321 | + waitTimer(ch); | ||
| 1322 | + } catch (Exception e) { | ||
| 1323 | + log.debug("Exception at wait timer ...!!!"); | ||
| 1324 | + } | ||
| 1325 | + | ||
| 1326 | + } | ||
| 1327 | + } | ||
| 1328 | + } | ||
| 1329 | + | ||
| 1330 | + /** | ||
| 1331 | + * Represents a task which sent a LS Acknowledge from the link state headers list. | ||
| 1332 | + */ | ||
| 1333 | + private class InternalDelayedAckTimer implements Runnable { | ||
| 1334 | + Channel ch; | ||
| 1335 | + | ||
| 1336 | + /** | ||
| 1337 | + * Creates an instance of Delayed acknowledge timer. | ||
| 1338 | + */ | ||
| 1339 | + InternalDelayedAckTimer() { | ||
| 1340 | + this.ch = channel; | ||
| 1341 | + } | ||
| 1342 | + | ||
| 1343 | + @Override | ||
| 1344 | + public void run() { | ||
| 1345 | + if (!((OspfInterfaceImpl) ospfInterface).linkStateHeaders().isEmpty()) { | ||
| 1346 | + isDelayedAckTimerScheduled = true; | ||
| 1347 | + if (ch != null && ch.isConnected()) { | ||
| 1348 | + | ||
| 1349 | + List<LsaHeader> listOfLsaHeadersAcknowledged = new ArrayList<>(); | ||
| 1350 | + List<LsaHeader> listOfLsaHeaders = ((OspfInterfaceImpl) ospfInterface).linkStateHeaders(); | ||
| 1351 | + log.debug("Delayed Ack, Number of Lsa's to Ack {}", listOfLsaHeaders.size()); | ||
| 1352 | + Iterator itr = listOfLsaHeaders.iterator(); | ||
| 1353 | + while (itr.hasNext()) { | ||
| 1354 | + LsAcknowledge ackContent = new LsAcknowledge(); | ||
| 1355 | + //Setting OSPF Header | ||
| 1356 | + ackContent.setOspfVer(OspfUtil.OSPF_VERSION); | ||
| 1357 | + ackContent.setOspftype(OspfPacketType.LSAACK.value()); | ||
| 1358 | + ackContent.setRouterId(ospfArea.routerId()); | ||
| 1359 | + ackContent.setAreaId(ospfArea.areaId()); | ||
| 1360 | + ackContent.setAuthType(OspfUtil.NOT_ASSIGNED); | ||
| 1361 | + ackContent.setAuthentication(OspfUtil.NOT_ASSIGNED); | ||
| 1362 | + ackContent.setOspfPacLength(OspfUtil.NOT_ASSIGNED); | ||
| 1363 | + ackContent.setChecksum(OspfUtil.NOT_ASSIGNED); | ||
| 1364 | + //limit to mtu | ||
| 1365 | + int currentLength = OspfUtil.OSPF_HEADER_LENGTH; | ||
| 1366 | + int maxSize = ospfInterface.mtu() - | ||
| 1367 | + OspfUtil.LSA_HEADER_LENGTH; // subtract a normal IP header. | ||
| 1368 | + while (itr.hasNext()) { | ||
| 1369 | + if ((currentLength + OspfUtil.LSA_HEADER_LENGTH) >= maxSize) { | ||
| 1370 | + break; | ||
| 1371 | + } | ||
| 1372 | + LsaHeader lsaHeader = (LsaHeader) itr.next(); | ||
| 1373 | + ackContent.addLinkStateHeader(lsaHeader); | ||
| 1374 | + currentLength = currentLength + OspfUtil.LSA_HEADER_LENGTH; | ||
| 1375 | + listOfLsaHeadersAcknowledged.add(lsaHeader); | ||
| 1376 | + log.debug("Delayed Ack, Added Lsa's to Ack {}", lsaHeader); | ||
| 1377 | + } | ||
| 1378 | + | ||
| 1379 | + log.debug("Delayed Ack, Number of Lsa's in LsAck packet {}", | ||
| 1380 | + ackContent.getLinkStateHeaders().size()); | ||
| 1381 | + | ||
| 1382 | + //set the destination | ||
| 1383 | + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR || | ||
| 1384 | + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR | ||
| 1385 | + || ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT) { | ||
| 1386 | + ackContent.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS); | ||
| 1387 | + } else if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER) { | ||
| 1388 | + ackContent.setDestinationIp(OspfUtil.ALL_DROUTERS); | ||
| 1389 | + } | ||
| 1390 | + ch.write(ackContent); | ||
| 1391 | + for (LsaHeader lsa : listOfLsaHeadersAcknowledged) { | ||
| 1392 | + ((OspfInterfaceImpl) ospfInterface).linkStateHeaders().remove(lsa); | ||
| 1393 | + ospfInterface.removeLsaFromNeighborMap(((OspfAreaImpl) ospfArea).getLsaKey(lsa)); | ||
| 1394 | + } | ||
| 1395 | + } | ||
| 1396 | + } | ||
| 1397 | + } | ||
| 1398 | + } | ||
| 1399 | + } | ||
| 1400 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
protocols/ospf/ctl/src/main/java/org/onosproject/ospf/controller/lsdb/LsaQueueConsumer.java
0 → 100755
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.ospf.controller.lsdb; | ||
| 17 | + | ||
| 18 | +import org.jboss.netty.channel.Channel; | ||
| 19 | +import org.onosproject.ospf.controller.LsaWrapper; | ||
| 20 | +import org.onosproject.ospf.controller.OspfArea; | ||
| 21 | +import org.onosproject.ospf.controller.OspfInterface; | ||
| 22 | +import org.onosproject.ospf.controller.OspfLsaType; | ||
| 23 | +import org.onosproject.ospf.controller.area.OspfAreaImpl; | ||
| 24 | +import org.onosproject.ospf.controller.area.OspfInterfaceImpl; | ||
| 25 | +import org.onosproject.ospf.protocol.lsa.LsaHeader; | ||
| 26 | +import org.onosproject.ospf.protocol.lsa.types.NetworkLsa; | ||
| 27 | +import org.onosproject.ospf.protocol.lsa.types.RouterLsa; | ||
| 28 | +import org.onosproject.ospf.protocol.util.ChecksumCalculator; | ||
| 29 | +import org.onosproject.ospf.protocol.util.OspfInterfaceState; | ||
| 30 | +import org.onosproject.ospf.protocol.util.OspfParameters; | ||
| 31 | +import org.onosproject.ospf.protocol.util.OspfUtil; | ||
| 32 | +import org.slf4j.Logger; | ||
| 33 | +import org.slf4j.LoggerFactory; | ||
| 34 | + | ||
| 35 | +import java.util.concurrent.BlockingQueue; | ||
| 36 | + | ||
| 37 | +/** | ||
| 38 | + * Consumes LSA from the Queue and processes it. | ||
| 39 | + * Its a producer consumer implementation using Blocking queue. | ||
| 40 | + */ | ||
| 41 | +public class LsaQueueConsumer implements Runnable { | ||
| 42 | + private static final Logger log = LoggerFactory.getLogger(LsaQueueConsumer.class); | ||
| 43 | + private BlockingQueue queue = null; | ||
| 44 | + private Channel channel; | ||
| 45 | + private OspfArea ospfArea; | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * Creates an instance of LSA queue consumer. | ||
| 49 | + * | ||
| 50 | + * @param queue queue instance | ||
| 51 | + * @param channel netty channel instance | ||
| 52 | + * @param ospfArea OSPF area instance | ||
| 53 | + */ | ||
| 54 | + public LsaQueueConsumer(BlockingQueue queue, Channel channel, OspfArea ospfArea) { | ||
| 55 | + this.queue = queue; | ||
| 56 | + this.channel = channel; | ||
| 57 | + this.ospfArea = ospfArea; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * Threads run method. | ||
| 62 | + */ | ||
| 63 | + public void run() { | ||
| 64 | + log.debug("LSAQueueConsumer:run...!!!"); | ||
| 65 | + try { | ||
| 66 | + while (true) { | ||
| 67 | + if (!queue.isEmpty()) { | ||
| 68 | + LsaWrapper wrapper = (LsaWrapper) queue.take(); | ||
| 69 | + String lsaProcessing = wrapper.lsaProcessing(); | ||
| 70 | + switch (lsaProcessing) { | ||
| 71 | + case OspfParameters.VERIFYCHECKSUM: | ||
| 72 | + log.debug("LSAQueueConsumer: Message - " + OspfParameters.VERIFYCHECKSUM + " consumed."); | ||
| 73 | + processVerifyChecksum(wrapper); | ||
| 74 | + break; | ||
| 75 | + case OspfParameters.REFRESHLSA: | ||
| 76 | + log.debug("LSAQueueConsumer: Message - " + OspfParameters.REFRESHLSA + " consumed."); | ||
| 77 | + processRefreshLsa(wrapper); | ||
| 78 | + break; | ||
| 79 | + case OspfParameters.MAXAGELSA: | ||
| 80 | + log.debug("LSAQueueConsumer: Message - " + OspfParameters.MAXAGELSA + " consumed."); | ||
| 81 | + processMaxAgeLsa(wrapper); | ||
| 82 | + break; | ||
| 83 | + default: | ||
| 84 | + log.debug("Unknown command to process the LSA in queue ...!!!"); | ||
| 85 | + break; | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + } catch (Exception e) { | ||
| 91 | + log.debug("Error::LSAQueueConsumer::{}", e.getMessage()); | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + /** | ||
| 96 | + * Processes verify checksum - checkAges. | ||
| 97 | + * | ||
| 98 | + * @param wrapper LSA wrapper instance | ||
| 99 | + */ | ||
| 100 | + private void processVerifyChecksum(LsaWrapper wrapper) throws Exception { | ||
| 101 | + ChecksumCalculator checkSum = new ChecksumCalculator(); | ||
| 102 | + if (!checkSum.isValidLsaCheckSum(wrapper.ospfLsa(), ((LsaWrapperImpl) wrapper).lsaHeader().lsType(), | ||
| 103 | + OspfUtil.LSAPACKET_CHECKSUM_POS1, | ||
| 104 | + OspfUtil.LSAPACKET_CHECKSUM_POS2)) { | ||
| 105 | + log.debug("LSAQueueConsumer::Checksum mismatch. Received LSA packet type {} ", | ||
| 106 | + ((LsaWrapperImpl) wrapper).lsaHeader().lsType()); | ||
| 107 | + | ||
| 108 | + //Checksum Invalid | ||
| 109 | + //RFC 2328 Restart the Router. | ||
| 110 | + //Currently we are not restarting. We are not handling this case. | ||
| 111 | + } | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + /** | ||
| 115 | + * Process refresh LSA. | ||
| 116 | + * | ||
| 117 | + * @param wrapper LSA wrapper instance | ||
| 118 | + */ | ||
| 119 | + private void processRefreshLsa(LsaWrapper wrapper) throws Exception { | ||
| 120 | + if (wrapper.isSelfOriginated()) { //self originated | ||
| 121 | + //set the destination | ||
| 122 | + OspfInterface ospfInterface = wrapper.ospfInterface(); | ||
| 123 | + if (ospfInterface != null) { | ||
| 124 | + LsaHeader header = ((LsaWrapperImpl) wrapper).lsaHeader(); | ||
| 125 | + header.setAge(wrapper.currentAge()); | ||
| 126 | + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR) { | ||
| 127 | + if (header.lsType() == OspfLsaType.ROUTER.value()) { | ||
| 128 | + RouterLsa routerLsa = ((OspfAreaImpl) ospfArea).buildRouterLsa(ospfInterface); | ||
| 129 | + ((OspfAreaImpl) ospfArea).addLsa(routerLsa, true, ospfInterface); | ||
| 130 | + ((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(routerLsa); | ||
| 131 | + } else if (header.lsType() == OspfLsaType.NETWORK.value()) { | ||
| 132 | + if (ospfInterface.listOfNeighbors().size() > 0) { | ||
| 133 | + NetworkLsa networkLsa = ((OspfAreaImpl) ospfArea).buildNetworkLsa( | ||
| 134 | + ospfInterface.ipAddress(), ospfInterface.ipNetworkMask()); | ||
| 135 | + ospfArea.addLsa(networkLsa, true, ospfInterface); | ||
| 136 | + ((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(networkLsa); | ||
| 137 | + } | ||
| 138 | + } | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR || | ||
| 142 | + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT || | ||
| 143 | + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER) { | ||
| 144 | + ospfArea.refreshArea(ospfInterface); | ||
| 145 | + } | ||
| 146 | + log.debug("LSAQueueConsumer: processRefreshLsa - Flooded SelfOriginated LSA {}", | ||
| 147 | + ((LsaWrapperImpl) wrapper).lsaHeader()); | ||
| 148 | + } | ||
| 149 | + } | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + /** | ||
| 153 | + * Process max age LSA. | ||
| 154 | + * | ||
| 155 | + * @param wrapper LSA wrapper instance | ||
| 156 | + */ | ||
| 157 | + private void processMaxAgeLsa(LsaWrapper wrapper) { | ||
| 158 | + //set the destination | ||
| 159 | + OspfInterface ospfInterface = wrapper.ospfInterface(); | ||
| 160 | + if (ospfInterface != null) { | ||
| 161 | + LsaHeader header = (LsaHeader) wrapper.ospfLsa().lsaHeader(); | ||
| 162 | + header.setAge(OspfParameters.MAXAGE); | ||
| 163 | + ((LsaWrapperImpl) wrapper).lsaHeader().setAge(OspfParameters.MAXAGE); | ||
| 164 | + if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR || | ||
| 165 | + ((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT) { | ||
| 166 | + //remove from db | ||
| 167 | + ((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(((LsaWrapperImpl) wrapper).lsaHeader()); | ||
| 168 | + ((OspfAreaImpl) ospfArea).deleteLsa(((LsaWrapperImpl) wrapper).lsaHeader()); | ||
| 169 | + } else { | ||
| 170 | + ((OspfAreaImpl) ospfArea).deleteLsa(((LsaWrapperImpl) wrapper).lsaHeader()); | ||
| 171 | + } | ||
| 172 | + log.debug("LSAQueueConsumer: processMaxAgeLsa - Flooded SelfOriginated-Max Age LSA {}", | ||
| 173 | + ((LsaWrapperImpl) wrapper).lsaHeader()); | ||
| 174 | + } | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + /** | ||
| 178 | + * Sets the channel. | ||
| 179 | + * | ||
| 180 | + * @param channel channel instance | ||
| 181 | + */ | ||
| 182 | + public void setChannel(Channel channel) { | ||
| 183 | + this.channel = channel; | ||
| 184 | + } | ||
| 185 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.ospf.controller.lsdb; | ||
| 17 | + | ||
| 18 | +import com.google.common.base.Objects; | ||
| 19 | +import org.jboss.netty.channel.Channel; | ||
| 20 | +import org.onosproject.ospf.controller.LsaBin; | ||
| 21 | +import org.onosproject.ospf.controller.LsaWrapper; | ||
| 22 | +import org.onosproject.ospf.controller.LsdbAge; | ||
| 23 | +import org.onosproject.ospf.controller.OspfArea; | ||
| 24 | +import org.onosproject.ospf.controller.area.OspfAreaImpl; | ||
| 25 | +import org.onosproject.ospf.protocol.util.OspfParameters; | ||
| 26 | +import org.slf4j.Logger; | ||
| 27 | +import org.slf4j.LoggerFactory; | ||
| 28 | + | ||
| 29 | +import java.util.Map; | ||
| 30 | +import java.util.concurrent.ArrayBlockingQueue; | ||
| 31 | +import java.util.concurrent.BlockingQueue; | ||
| 32 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 33 | +import java.util.concurrent.Executors; | ||
| 34 | +import java.util.concurrent.ScheduledExecutorService; | ||
| 35 | +import java.util.concurrent.TimeUnit; | ||
| 36 | + | ||
| 37 | +/** | ||
| 38 | + * Representation of LSDB Aging process. | ||
| 39 | + */ | ||
| 40 | +public class LsdbAgeImpl implements LsdbAge { | ||
| 41 | + | ||
| 42 | + private static final Logger log = | ||
| 43 | + LoggerFactory.getLogger(LsdbAgeImpl.class); | ||
| 44 | + protected int ageCounter = 0; | ||
| 45 | + private InternalAgeTimer dbAgeTimer; | ||
| 46 | + private ScheduledExecutorService exServiceage; | ||
| 47 | + // creating age bins of MAXAGE | ||
| 48 | + private Map<Integer, LsaBin> ageBins = new ConcurrentHashMap<>(OspfParameters.MAXAGE); | ||
| 49 | + private LsaBin maxAgeBin = new LsaBinImpl(OspfParameters.MAXAGE); | ||
| 50 | + private int ageCounterRollOver = 0; | ||
| 51 | + private Channel channel = null; | ||
| 52 | + private LsaQueueConsumer queueConsumer = null; | ||
| 53 | + private BlockingQueue<LsaWrapper> lsaQueue = new ArrayBlockingQueue(1024); | ||
| 54 | + private OspfArea ospfArea = null; | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + /** | ||
| 58 | + * Creates an instance of LSDB age. | ||
| 59 | + * | ||
| 60 | + * @param ospfArea OSPF area instance | ||
| 61 | + */ | ||
| 62 | + public LsdbAgeImpl(OspfArea ospfArea) { | ||
| 63 | + // create LSBin's in the HashMap. | ||
| 64 | + for (int i = 0; i < OspfParameters.MAXAGE; i++) { | ||
| 65 | + LsaBin lsaBin = new LsaBinImpl(i); | ||
| 66 | + ageBins.put(i, lsaBin); | ||
| 67 | + } | ||
| 68 | + this.ospfArea = ospfArea; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + @Override | ||
| 72 | + public boolean equals(Object o) { | ||
| 73 | + if (this == o) { | ||
| 74 | + return true; | ||
| 75 | + } | ||
| 76 | + if (o == null || getClass() != o.getClass()) { | ||
| 77 | + return false; | ||
| 78 | + } | ||
| 79 | + LsdbAgeImpl that = (LsdbAgeImpl) o; | ||
| 80 | + return Objects.equal(ageBins, that.ageBins) && | ||
| 81 | + Objects.equal(ageCounter, that.ageCounter) && | ||
| 82 | + Objects.equal(ageCounterRollOver, that.ageCounterRollOver) && | ||
| 83 | + Objects.equal(lsaQueue, lsaQueue); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + @Override | ||
| 87 | + public int hashCode() { | ||
| 88 | + return Objects.hashCode(ageBins, ageCounter, ageCounterRollOver, lsaQueue); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + /** | ||
| 92 | + * Adds LSA to bin. | ||
| 93 | + * | ||
| 94 | + * @param binKey key to store in bin | ||
| 95 | + * @param lsaBin LSA bin instance | ||
| 96 | + */ | ||
| 97 | + public void addLsaBin(Integer binKey, LsaBin lsaBin) { | ||
| 98 | + if (!ageBins.containsKey(binKey)) { | ||
| 99 | + ageBins.put(binKey, lsaBin); | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + /** | ||
| 104 | + * Gets LSA from Bin. | ||
| 105 | + * | ||
| 106 | + * @param binKey key | ||
| 107 | + * @return bin instance | ||
| 108 | + */ | ||
| 109 | + public LsaBin getLsaBin(Integer binKey) { | ||
| 110 | + | ||
| 111 | + return ageBins.get(binKey); | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + /** | ||
| 115 | + * Adds the LSA to maxAge bin. | ||
| 116 | + * | ||
| 117 | + * @param key key | ||
| 118 | + * @param wrapper wrapper instance | ||
| 119 | + */ | ||
| 120 | + public void addLsaToMaxAgeBin(String key, LsaWrapper wrapper) { | ||
| 121 | + maxAgeBin.addOspfLsa(key, wrapper); | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + /** | ||
| 125 | + * Removes LSA from Bin. | ||
| 126 | + * | ||
| 127 | + * @param lsaWrapper wrapper instance | ||
| 128 | + */ | ||
| 129 | + public void removeLsaFromBin(LsaWrapper lsaWrapper) { | ||
| 130 | + if (ageBins.containsKey(lsaWrapper.binNumber())) { | ||
| 131 | + LsaBin lsaBin = ageBins.get(lsaWrapper.binNumber()); | ||
| 132 | + lsaBin.removeOspfLsa(((OspfAreaImpl) ospfArea).getLsaKey(((LsaWrapperImpl) | ||
| 133 | + lsaWrapper).lsaHeader()), lsaWrapper); | ||
| 134 | + } | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + /** | ||
| 138 | + * Starts the aging timer and queue consumer. | ||
| 139 | + */ | ||
| 140 | + public void startDbAging() { | ||
| 141 | + startDbAgeTimer(); | ||
| 142 | + queueConsumer = new LsaQueueConsumer(lsaQueue, channel, ospfArea); | ||
| 143 | + new Thread(queueConsumer).start(); | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + | ||
| 147 | + /** | ||
| 148 | + * Gets called every 1 second as part of the timer. | ||
| 149 | + */ | ||
| 150 | + public void ageLsaAndFlood() { | ||
| 151 | + //every 5 mins checksum validation | ||
| 152 | + checkAges(); | ||
| 153 | + //every 30 mins - flood LSA | ||
| 154 | + refreshLsa(); | ||
| 155 | + //every 60 mins - flood LSA | ||
| 156 | + maxAgeLsa(); | ||
| 157 | + | ||
| 158 | + if (ageCounter == OspfParameters.MAXAGE) { | ||
| 159 | + ageCounter = 0; | ||
| 160 | + ageCounterRollOver++; | ||
| 161 | + } else { | ||
| 162 | + //increment age bin | ||
| 163 | + ageCounter++; | ||
| 164 | + } | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + /** | ||
| 168 | + * If the LSA have completed the MaxAge - they are moved called stop aging and flooded. | ||
| 169 | + */ | ||
| 170 | + public void maxAgeLsa() { | ||
| 171 | + if (ageCounter == 0) { | ||
| 172 | + return; | ||
| 173 | + } | ||
| 174 | + //Get from Age Bins | ||
| 175 | + LsaBin lsaBin = ageBins.get(ageCounter - 1); | ||
| 176 | + if (lsaBin == null) { | ||
| 177 | + return; | ||
| 178 | + } | ||
| 179 | + Map lsaBinMap = lsaBin.listOfLsa(); | ||
| 180 | + for (Object key : lsaBinMap.keySet()) { | ||
| 181 | + LsaWrapper lsa = (LsaWrapper) lsaBinMap.get((String) key); | ||
| 182 | + if (lsa.currentAge() == OspfParameters.MAXAGE) { | ||
| 183 | + lsa.setLsaProcessing(OspfParameters.MAXAGELSA); | ||
| 184 | + log.debug("Lsa picked for maxage flooding. Age Counter: {}, AgeCounterRollover: {}, " + | ||
| 185 | + "AgeCounterRollover WhenAddedToDb: {}, LSA Type: {}, LSA Key: {}", | ||
| 186 | + ageCounter, ageCounterRollOver, lsa.currentAge(), lsa.lsaType(), key); | ||
| 187 | + //add it to lsaQueue for processing | ||
| 188 | + try { | ||
| 189 | + lsaQueue.put(lsa); | ||
| 190 | + //remove from bin | ||
| 191 | + lsaBin.removeOspfLsa((String) key, lsa); | ||
| 192 | + } catch (InterruptedException e) { | ||
| 193 | + log.debug("Error::LSDBAge::maxAgeLsa::{}", e.getMessage()); | ||
| 194 | + } | ||
| 195 | + } | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + //Get from maxAgeBin | ||
| 199 | + Map lsaMaxAgeBinMap = maxAgeBin.listOfLsa(); | ||
| 200 | + for (Object key : lsaMaxAgeBinMap.keySet()) { | ||
| 201 | + LsaWrapper lsa = (LsaWrapper) lsaMaxAgeBinMap.get((String) key); | ||
| 202 | + lsa.setLsaProcessing(OspfParameters.MAXAGELSA); | ||
| 203 | + log.debug("Lsa picked for maxage flooding. Age Counter: {}, LSA Type: {}, LSA Key: {}", | ||
| 204 | + ageCounter, lsa.lsaType(), key); | ||
| 205 | + //add it to lsaQueue for processing | ||
| 206 | + try { | ||
| 207 | + lsaQueue.put(lsa); | ||
| 208 | + //remove from bin | ||
| 209 | + maxAgeBin.removeOspfLsa((String) key, lsa); | ||
| 210 | + } catch (InterruptedException e) { | ||
| 211 | + log.debug("Error::LSDBAge::maxAgeLsa::{}", e.getMessage()); | ||
| 212 | + } | ||
| 213 | + } | ||
| 214 | + } | ||
| 215 | + | ||
| 216 | + | ||
| 217 | + /* | ||
| 218 | + * If the LSA is in age bin of 1800 - it's pushed into refresh list. | ||
| 219 | + */ | ||
| 220 | + public void refreshLsa() { | ||
| 221 | + int binNumber; | ||
| 222 | + if (ageCounter < OspfParameters.LSREFRESHTIME) { | ||
| 223 | + binNumber = ageCounter + OspfParameters.LSREFRESHTIME; | ||
| 224 | + } else { | ||
| 225 | + binNumber = ageCounter - OspfParameters.LSREFRESHTIME; | ||
| 226 | + } | ||
| 227 | + LsaBin lsaBin = ageBins.get(binNumber); | ||
| 228 | + if (lsaBin == null) { | ||
| 229 | + return; | ||
| 230 | + } | ||
| 231 | + Map lsaBinMap = lsaBin.listOfLsa(); | ||
| 232 | + for (Object key : lsaBinMap.keySet()) { | ||
| 233 | + LsaWrapper lsa = (LsaWrapper) lsaBinMap.get((String) key); | ||
| 234 | + try { | ||
| 235 | + if (lsa.isSelfOriginated()) { | ||
| 236 | + log.debug("Lsa picked for refreshLsa. binNumber: {}, LSA Type: {}, LSA Key: {}", | ||
| 237 | + binNumber, lsa.lsaType(), key); | ||
| 238 | + lsa.setLsaProcessing(OspfParameters.REFRESHLSA); | ||
| 239 | + lsaQueue.put(lsa); | ||
| 240 | + //remove from bin | ||
| 241 | + lsaBin.removeOspfLsa((String) key, lsa); | ||
| 242 | + } | ||
| 243 | + } catch (InterruptedException e) { | ||
| 244 | + log.debug("Error::LSDBAge::refreshLsa::{}", e.getMessage()); | ||
| 245 | + } | ||
| 246 | + } | ||
| 247 | + } | ||
| 248 | + | ||
| 249 | + /** | ||
| 250 | + * Verify the checksum for the LSAs who are in bins of 300 and it's multiples. | ||
| 251 | + */ | ||
| 252 | + public void checkAges() { | ||
| 253 | + //evry 5 min age counter + multiples of 300 | ||
| 254 | + for (int age = OspfParameters.CHECKAGE; age < OspfParameters.MAXAGE; | ||
| 255 | + age += OspfParameters.CHECKAGE) { | ||
| 256 | + LsaBin lsaBin = ageBins.get(age2Bin(age)); | ||
| 257 | + if (lsaBin == null) { | ||
| 258 | + continue; | ||
| 259 | + } | ||
| 260 | + Map lsaBinMap = lsaBin.listOfLsa(); | ||
| 261 | + for (Object key : lsaBinMap.keySet()) { | ||
| 262 | + LsaWrapper lsa = (LsaWrapper) lsaBinMap.get((String) key); | ||
| 263 | + lsa.setLsaProcessing(OspfParameters.VERIFYCHECKSUM); | ||
| 264 | + try { | ||
| 265 | + lsaQueue.put(lsa); | ||
| 266 | + } catch (InterruptedException e) { | ||
| 267 | + log.debug("Error::LSDBAge::checkAges::{}", e.getMessage()); | ||
| 268 | + } | ||
| 269 | + } | ||
| 270 | + } | ||
| 271 | + } | ||
| 272 | + | ||
| 273 | + | ||
| 274 | + /** | ||
| 275 | + * Starts DB age timer method start the aging task. | ||
| 276 | + */ | ||
| 277 | + private void startDbAgeTimer() { | ||
| 278 | + log.debug("OSPFNbr::startWaitTimer"); | ||
| 279 | + dbAgeTimer = new InternalAgeTimer(); | ||
| 280 | + //from 1 sec | ||
| 281 | + exServiceage = Executors.newSingleThreadScheduledExecutor(); | ||
| 282 | + exServiceage.scheduleAtFixedRate(dbAgeTimer, OspfParameters.AGECOUNTER, | ||
| 283 | + OspfParameters.AGECOUNTER, TimeUnit.SECONDS); | ||
| 284 | + } | ||
| 285 | + | ||
| 286 | + /** | ||
| 287 | + * Stops the aging task. | ||
| 288 | + */ | ||
| 289 | + private void stopDbAgeTimer() { | ||
| 290 | + log.debug("OSPFNbr::stopWaitTimer "); | ||
| 291 | + exServiceage.shutdown(); | ||
| 292 | + } | ||
| 293 | + | ||
| 294 | + | ||
| 295 | + /** | ||
| 296 | + * Gets the netty channel. | ||
| 297 | + * | ||
| 298 | + * @return netty channel | ||
| 299 | + */ | ||
| 300 | + public Channel getChannel() { | ||
| 301 | + return channel; | ||
| 302 | + } | ||
| 303 | + | ||
| 304 | + /** | ||
| 305 | + * Sets the netty channel. | ||
| 306 | + * | ||
| 307 | + * @param channel netty channel | ||
| 308 | + */ | ||
| 309 | + public void setChannel(Channel channel) { | ||
| 310 | + | ||
| 311 | + this.channel = channel; | ||
| 312 | + if (queueConsumer != null) { | ||
| 313 | + queueConsumer.setChannel(channel); | ||
| 314 | + } | ||
| 315 | + } | ||
| 316 | + | ||
| 317 | + /** | ||
| 318 | + * Gets the age counter. | ||
| 319 | + * | ||
| 320 | + * @return ageCounter | ||
| 321 | + */ | ||
| 322 | + public int getAgeCounter() { | ||
| 323 | + return ageCounter; | ||
| 324 | + } | ||
| 325 | + | ||
| 326 | + /** | ||
| 327 | + * Gets the age counter roll over value. | ||
| 328 | + * | ||
| 329 | + * @return the age counter roll over value | ||
| 330 | + */ | ||
| 331 | + public int getAgeCounterRollOver() { | ||
| 332 | + return ageCounterRollOver; | ||
| 333 | + } | ||
| 334 | + | ||
| 335 | + /** | ||
| 336 | + * Gets the max age bin. | ||
| 337 | + * | ||
| 338 | + * @return lsa bin instance | ||
| 339 | + */ | ||
| 340 | + public LsaBin getMaxAgeBin() { | ||
| 341 | + return maxAgeBin; | ||
| 342 | + } | ||
| 343 | + | ||
| 344 | + /** | ||
| 345 | + * Gets the bin number. | ||
| 346 | + * | ||
| 347 | + * @param x Can be either age or ageCounter | ||
| 348 | + * @return bin number. | ||
| 349 | + */ | ||
| 350 | + public int age2Bin(int x) { | ||
| 351 | + if (x <= ageCounter) { | ||
| 352 | + return (ageCounter - x); | ||
| 353 | + } else { | ||
| 354 | + return ((OspfParameters.MAXAGE - 1) + (ageCounter - x)); | ||
| 355 | + } | ||
| 356 | + } | ||
| 357 | + | ||
| 358 | + /** | ||
| 359 | + * Runnable task which runs every second and calls aging process. | ||
| 360 | + */ | ||
| 361 | + private class InternalAgeTimer implements Runnable { | ||
| 362 | + | ||
| 363 | + /** | ||
| 364 | + * Constructor. | ||
| 365 | + */ | ||
| 366 | + InternalAgeTimer() { | ||
| 367 | + log.debug("Starts::LsdbAge::AgeTimer...!!! "); | ||
| 368 | + } | ||
| 369 | + | ||
| 370 | + @Override | ||
| 371 | + public void run() { | ||
| 372 | + ageLsaAndFlood(); | ||
| 373 | + } | ||
| 374 | + } | ||
| 375 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 1 | +/* | ||
| 2 | + * Copyright 2016 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * Implementation of the OSPF controller. | ||
| 19 | + */ | ||
| 20 | +package org.onosproject.ospf.controller; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or login to post a comment