| /* |
| * Copyright 2016-present Open Networking Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.onosproject.ospf.controller.impl; |
| |
| import org.jboss.netty.channel.Channel; |
| import org.onlab.packet.Ip4Address; |
| import org.onlab.util.Bandwidth; |
| import org.onosproject.ospf.controller.DeviceInformation; |
| import org.onosproject.ospf.controller.LinkInformation; |
| import org.onosproject.ospf.controller.LsaWrapper; |
| import org.onosproject.ospf.controller.OspfArea; |
| import org.onosproject.ospf.controller.OspfDeviceTed; |
| import org.onosproject.ospf.controller.OspfInterface; |
| import org.onosproject.ospf.controller.OspfLinkTed; |
| import org.onosproject.ospf.controller.OspfLsa; |
| import org.onosproject.ospf.controller.OspfLsaType; |
| import org.onosproject.ospf.controller.OspfLsdb; |
| import org.onosproject.ospf.controller.OspfMessage; |
| import org.onosproject.ospf.controller.OspfNbr; |
| import org.onosproject.ospf.controller.OspfNeighborState; |
| import org.onosproject.ospf.controller.OspfPacketType; |
| import org.onosproject.ospf.controller.OspfRouter; |
| import org.onosproject.ospf.controller.TopologyForDeviceAndLink; |
| import org.onosproject.ospf.controller.area.OspfAreaImpl; |
| import org.onosproject.ospf.controller.area.OspfInterfaceImpl; |
| import org.onosproject.ospf.controller.lsdb.LsaWrapperImpl; |
| import org.onosproject.ospf.controller.util.OspfInterfaceType; |
| import org.onosproject.ospf.exceptions.OspfParseException; |
| import org.onosproject.ospf.protocol.lsa.LsaHeader; |
| import org.onosproject.ospf.protocol.lsa.OpaqueLsaHeader; |
| import org.onosproject.ospf.protocol.lsa.types.OpaqueLsa10; |
| import org.onosproject.ospf.protocol.lsa.types.TopLevelTlv; |
| import org.onosproject.ospf.protocol.ospfpacket.OspfMessageWriter; |
| import org.onosproject.ospf.protocol.ospfpacket.OspfPacketHeader; |
| import org.onosproject.ospf.protocol.ospfpacket.subtype.LsRequestPacket; |
| import org.onosproject.ospf.protocol.ospfpacket.types.DdPacket; |
| import org.onosproject.ospf.protocol.ospfpacket.types.LsAcknowledge; |
| import org.onosproject.ospf.protocol.ospfpacket.types.LsRequest; |
| import org.onosproject.ospf.protocol.ospfpacket.types.LsUpdate; |
| import org.onosproject.ospf.protocol.util.ChecksumCalculator; |
| import org.onosproject.ospf.protocol.util.OspfInterfaceState; |
| import org.onosproject.ospf.protocol.util.OspfParameters; |
| import org.onosproject.ospf.protocol.util.OspfUtil; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.CopyOnWriteArrayList; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.ScheduledExecutorService; |
| import java.util.concurrent.TimeUnit; |
| |
| /** |
| * Represents an OSPF neighbor. |
| * The first thing an OSPF router must do is find its neighbors and form adjacency. |
| * Each neighbor that the router finds will be represented by this class. |
| */ |
| public class OspfNbrImpl implements OspfNbr { |
| private static final Logger log = LoggerFactory.getLogger(OspfNbrImpl.class); |
| private OspfNeighborState state; |
| private InternalRxmtDdPacket rxmtDdPacketTask; |
| private InternalInactivityTimeCheck inActivityTimeCheckTask; |
| private InternalFloodingTask floodingTask; |
| private InternalRxmtLsrPacket rxmtLsrPacketTask; |
| private ScheduledExecutorService exServiceRxmtLsr; |
| private ScheduledExecutorService exServiceFlooding; |
| private ScheduledExecutorService exServiceRxmtDDPacket; |
| private ScheduledExecutorService exServiceInActivity; |
| |
| private boolean floodingTimerScheduled = false; |
| private boolean rxmtLsrTimerScheduled = false; |
| private boolean rxmtDdPacketTimerScheduled = false; |
| private boolean inActivityTimerScheduled = false; |
| |
| /** |
| * When the two neighbors are exchanging databases, they form a master/slave relationship. |
| * The master sends the first Database Description Packet |
| */ |
| private int isMaster; |
| |
| /** |
| * The DD Sequence Number of the DD packet that is currently being sent to the neighbor. |
| */ |
| private long ddSeqNum; |
| |
| /** |
| * Another data structure for keeping information of the last received DD packet. |
| */ |
| private DdPacket lastDdPacket; |
| |
| /** |
| * Another data structure for keeping information of the last Sent DD packet. |
| */ |
| private DdPacket lastSentDdPacket; |
| |
| /** |
| * Another data structure for keeping information of the last Sent LSrequest packet. |
| */ |
| private LsRequest lastSentLsrPacket; |
| |
| /** |
| * The router ID of the Neighbor Router. |
| */ |
| private Ip4Address neighborId; |
| |
| /** |
| * The IP address of the neighboring router's interface to the attached network. |
| */ |
| private Ip4Address neighborIpAddr; |
| |
| /** |
| * The neighbor's IDEA of the designated router. |
| */ |
| private Ip4Address neighborDr; |
| |
| /** |
| * The neighbor's IDEA of the backup designated router. |
| */ |
| private Ip4Address neighborBdr; |
| |
| private int routerPriority; |
| private int routerDeadInterval; |
| |
| /** |
| * The list of LSAs that have to be flooded. |
| */ |
| private Map<String, OspfLsa> reTxList = new LinkedHashMap<>(); |
| |
| /** |
| * The list of LSAs that have been flooded but not yet acknowledged on this adjacency. |
| */ |
| private Map<String, OspfLsa> pendingReTxList = new LinkedHashMap<>(); |
| |
| /** |
| * List of LSAs which are failed to received ACK. |
| */ |
| private Map failedTxList = new HashMap<>(); |
| |
| /** |
| * The complete list of LSAs that make up the area link-state database, at the moment the. |
| * neighbor goes into Database Exchange state (EXCHANGE). |
| */ |
| private List<LsaHeader> ddSummaryList = new CopyOnWriteArrayList<>(); |
| |
| /** |
| * LSA Request List from Neighbor. |
| */ |
| private Hashtable lsReqList = new Hashtable(); |
| |
| /** |
| * The optional OSPF capabilities supported by the neighbor. |
| */ |
| private int options; |
| private boolean isOpaqueCapable; |
| |
| /** |
| * A link to the OSPF-Interface this Neighbor belongs to. |
| */ |
| private OspfInterface ospfInterface; |
| |
| /** |
| * A link to the OSPF-Area this Neighbor Data Structure belongs to. |
| */ |
| private OspfArea ospfArea; |
| private List<TopLevelTlv> topLevelTlvs = new ArrayList<>(); |
| private List<DeviceInformation> deviceInformationList = new ArrayList<>(); |
| |
| private TopologyForDeviceAndLink topologyForDeviceAndLink; |
| |
| /** |
| * Creates an instance of Neighbor. |
| * |
| * @param paramOspfArea OSPF Area instance |
| * @param paramOspfInterface OSPF interface instance |
| * @param ipAddr IP address |
| * @param routerId router id |
| * @param options options |
| * @param topologyForDeviceAndLinkCommon topology for device and link instance |
| */ |
| public OspfNbrImpl(OspfArea paramOspfArea, OspfInterface paramOspfInterface, |
| Ip4Address ipAddr, Ip4Address routerId, int options, |
| TopologyForDeviceAndLink topologyForDeviceAndLinkCommon) { |
| this.ospfArea = paramOspfArea; |
| this.ospfInterface = paramOspfInterface; |
| state = OspfNeighborState.DOWN; |
| isMaster = OspfUtil.NOT_MASTER; |
| ddSeqNum = OspfUtil.createRandomNumber(); |
| neighborIpAddr = ipAddr; |
| neighborId = routerId; |
| this.options = options; |
| lastDdPacket = new DdPacket(); |
| routerDeadInterval = paramOspfInterface.routerDeadIntervalTime(); |
| this.topologyForDeviceAndLink = topologyForDeviceAndLinkCommon; |
| } |
| |
| /** |
| * Gets the IP address of this neighbor. |
| * |
| * @return the IP address of this neighbor |
| */ |
| @Override |
| public Ip4Address neighborIpAddr() { |
| return neighborIpAddr; |
| } |
| |
| /** |
| * Gets the neighbor is opaque enabled or not. |
| * |
| * @return true if the neighbor is opaque enabled else false. |
| */ |
| @Override |
| public boolean isOpaqueCapable() { |
| return isOpaqueCapable; |
| } |
| |
| /** |
| * Sets the neighbor is opaque enabled or not. |
| * |
| * @param isOpaqueCapable true if the neighbor is opaque enabledelse false |
| */ |
| @Override |
| public void setIsOpaqueCapable(boolean isOpaqueCapable) { |
| this.isOpaqueCapable = isOpaqueCapable; |
| } |
| |
| /** |
| * Sets router dead interval. |
| * |
| * @param routerDeadInterval router dead interval |
| */ |
| @Override |
| public void setRouterDeadInterval(int routerDeadInterval) { |
| this.routerDeadInterval = routerDeadInterval; |
| } |
| |
| /** |
| * Have seen a Neighbor, but the Neighbor doesn't know about me. |
| * |
| * @param ospfHello Hello Packet instance |
| * @param channel netty channel instance |
| */ |
| public void oneWayReceived(OspfMessage ospfHello, Channel channel) { |
| log.debug("OSPFNbr::oneWayReceived...!!!"); |
| stopInactivityTimeCheck(); |
| startInactivityTimeCheck(); |
| |
| if (state == OspfNeighborState.ATTEMPT) { |
| state = OspfNeighborState.INIT; |
| } else if (state == OspfNeighborState.DOWN) { |
| state = OspfNeighborState.INIT; |
| } |
| |
| if (state.getValue() >= OspfNeighborState.TWOWAY.getValue()) { |
| state = OspfNeighborState.INIT; |
| failedTxList.clear(); |
| ddSummaryList.clear(); |
| lsReqList.clear(); |
| } |
| } |
| |
| /** |
| * Called when a DD OSPFMessage is received while state was INIT. |
| * |
| * @param ospfMessage ospf message instance |
| * @param channel netty channel instance |
| */ |
| public void twoWayReceived(OspfMessage ospfMessage, Channel channel) { |
| log.debug("OSPFNbr::twoWayReceived...!!!"); |
| stopInactivityTimeCheck(); |
| startInactivityTimeCheck(); |
| startFloodingTimer(channel); |
| |
| OspfPacketHeader packet = (OspfPacketHeader) ospfMessage; |
| if (state.getValue() <= OspfNeighborState.TWOWAY.getValue()) { |
| if (formAdjacencyOrNot()) { |
| state = OspfNeighborState.EXSTART; |
| |
| ddSeqNum++; |
| DdPacket ddPacket = new DdPacket(); |
| // seting OSPF Header |
| ddPacket.setOspfVer(OspfUtil.OSPF_VERSION); |
| ddPacket.setOspftype(OspfPacketType.DD.value()); |
| ddPacket.setRouterId(ospfArea.routerId()); |
| ddPacket.setAreaId(ospfArea.areaId()); |
| ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length |
| ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED); |
| boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled(); |
| if (isOpaqueEnabled) { |
| ddPacket.setOptions(ospfArea.opaqueEnabledOptions()); |
| } else { |
| ddPacket.setOptions(ospfArea.options()); |
| } |
| ddPacket.setIsInitialize(OspfUtil.INITIALIZE_SET); |
| ddPacket.setIsMore(OspfUtil.MORE_SET); |
| ddPacket.setIsMaster(OspfUtil.IS_MASTER); |
| ddPacket.setImtu(ospfInterface.mtu()); |
| ddPacket.setSequenceNo(ddSeqNum); |
| |
| setLastSentDdPacket(ddPacket); |
| rxmtDdPacketTask = new InternalRxmtDdPacket(channel); |
| startRxMtDdTimer(channel); |
| //setting destination ip |
| ddPacket.setDestinationIp(packet.sourceIp()); |
| byte[] messageToWrite = getMessage(ddPacket); |
| channel.write(messageToWrite); |
| } else { |
| state = OspfNeighborState.TWOWAY; |
| } |
| } |
| } |
| |
| /** |
| * Checks whether to form adjacency or not. |
| * |
| * @return true indicates form adjacency, else false |
| */ |
| private boolean formAdjacencyOrNot() { |
| boolean formAdjacency = false; |
| |
| if (ospfInterface.interfaceType() == OspfInterfaceType.POINT_TO_POINT.value()) { |
| formAdjacency = true; |
| } else if (ospfInterface.interfaceType() == OspfInterfaceType.BROADCAST.value()) { |
| if (ospfInterface.ipAddress().equals(this.neighborDr) || |
| ospfInterface.ipAddress().equals(this.neighborBdr)) { |
| formAdjacency = true; |
| } else if (neighborBdr.equals(neighborIpAddr) || |
| neighborDr.equals(neighborIpAddr)) { |
| formAdjacency = true; |
| } |
| } |
| |
| log.debug("FormAdjacencyOrNot - neighborDR: {}, neighborBDR: {}, neighborIPAddr: {}, formAdjacencyOrNot {}", |
| neighborDr, neighborBdr, neighborIpAddr, formAdjacency); |
| |
| return formAdjacency; |
| } |
| |
| /** |
| * At this point Master/Slave relationship is definitely established. |
| * DD sequence numbers have been exchanged. |
| * This is the begin of sending/receiving of DD OSPFMessages. |
| * |
| * @param ospfMessage OSPF message instance |
| * @param neighborIsMaster neighbor is master or slave |
| * @param payload contains the LSAs to add in Dd Packet |
| * @param ch netty channel instance |
| */ |
| public void negotiationDone(OspfMessage ospfMessage, |
| boolean neighborIsMaster, List payload, Channel ch) { |
| stopRxMtDdTimer(); |
| OspfPacketHeader packet = (OspfPacketHeader) ospfMessage; |
| DdPacket ddPacketForCheck = (DdPacket) packet; |
| if (ddPacketForCheck.isOpaqueCapable()) { |
| OspfLsdb database = ospfArea.database(); |
| List opaqueLsas = database.getAllLsaHeaders(true, true); |
| Iterator iterator = opaqueLsas.iterator(); |
| while (iterator.hasNext()) { |
| OspfLsa ospfLsa = (OspfLsa) iterator.next(); |
| if (ospfLsa.getOspfLsaType() == OspfLsaType.AREA_LOCAL_OPAQUE_LSA) { |
| OpaqueLsa10 opaqueLsa10 = (OpaqueLsa10) ospfLsa; |
| topLevelTlvs = opaqueLsa10.topLevelValues(); |
| } |
| } |
| } |
| if (state == OspfNeighborState.EXSTART) { |
| state = OspfNeighborState.EXCHANGE; |
| boolean excludeMaxAgeLsa = true; |
| //list of contents of area wise LSA |
| ddSummaryList = ospfArea.getLsaHeaders(excludeMaxAgeLsa, isOpaqueCapable); |
| |
| if (neighborIsMaster) { |
| processLsas(payload); |
| // ...construct new DD Packet... |
| DdPacket ddPacket = new DdPacket(); |
| // setting OSPF Header |
| ddPacket.setOspfVer(OspfUtil.OSPF_VERSION); |
| ddPacket.setOspftype(OspfPacketType.DD.value()); |
| ddPacket.setRouterId(ospfArea.routerId()); |
| ddPacket.setAreaId(ospfArea.areaId()); |
| ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length |
| ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED); |
| boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled(); |
| if (isOpaqueEnabled && isOpaqueCapable) { |
| ddPacket.setOptions(ospfArea.opaqueEnabledOptions()); |
| } else { |
| ddPacket.setOptions(ospfArea.options()); |
| } |
| ddPacket.setIsInitialize(OspfUtil.INITIALIZE_NOTSET); |
| ddPacket.setIsMore(OspfUtil.MORE_NOTSET); |
| ddPacket.setIsMaster(OspfUtil.NOT_MASTER); |
| ddPacket.setImtu(ospfInterface.mtu()); |
| ddPacket.setSequenceNo(ddSeqNum); |
| //setting the destination |
| ddPacket.setDestinationIp(packet.sourceIp()); |
| setLastSentDdPacket(ddPacket); |
| getIsMoreBit(); |
| |
| byte[] messageToWrite = getMessage(lastSentDdPacket); |
| ch.write(messageToWrite); |
| } else { |
| // process LSA Vector's List, Add it to LSRequestList. |
| processLsas(payload); |
| DdPacket ddPacket = new DdPacket(); |
| // setting OSPF Header |
| ddPacket.setOspfVer(OspfUtil.OSPF_VERSION); |
| ddPacket.setOspftype(OspfPacketType.DD.value()); |
| ddPacket.setRouterId(ospfArea.routerId()); |
| ddPacket.setAreaId(ospfArea.areaId()); |
| ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length |
| ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED); |
| boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled(); |
| if (isOpaqueEnabled && isOpaqueCapable) { |
| ddPacket.setOptions(ospfArea.opaqueEnabledOptions()); |
| } else { |
| ddPacket.setOptions(ospfArea.options()); |
| } |
| ddPacket.setIsInitialize(OspfUtil.INITIALIZE_NOTSET); |
| ddPacket.setIsMore(OspfUtil.MORE_NOTSET); |
| ddPacket.setIsMaster(OspfUtil.IS_MASTER); |
| ddPacket.setImtu(ospfInterface.mtu()); |
| ddPacket.setSequenceNo(ddSeqNum); |
| setLastSentDdPacket(ddPacket); |
| getIsMoreBit(); |
| ddPacket.setDestinationIp(packet.sourceIp()); |
| byte[] messageToWrite = getMessage(lastSentDdPacket); |
| ch.write(messageToWrite); |
| startRxMtDdTimer(ch); |
| } |
| } |
| } |
| |
| /** |
| * Process the LSA Headers received in the last received Database Description OSPFMessage. |
| * |
| * @param ddPayload LSA headers to process |
| */ |
| public void processLsas(List ddPayload) { |
| log.debug("OSPFNbr::processLsas...!!!"); |
| OspfLsa nextLsa; |
| Iterator lsas = ddPayload.iterator(); |
| while (lsas.hasNext()) { |
| nextLsa = (OspfLsa) lsas.next(); |
| // check LSA Type. |
| if (((nextLsa.getOspfLsaType().value() > OspfLsaType.EXTERNAL_LSA.value()) && |
| (nextLsa.getOspfLsaType().value() < OspfLsaType.LINK_LOCAL_OPAQUE_LSA.value())) || |
| (nextLsa.getOspfLsaType().value() > OspfLsaType.AS_OPAQUE_LSA.value())) { |
| // unknown lsType found! |
| seqNumMismatch("LS Type found was unknown."); |
| return; |
| } |
| |
| if ((nextLsa.getOspfLsaType() == OspfLsaType.EXTERNAL_LSA) && |
| !ospfArea.isExternalRoutingCapability()) { |
| // LSA is external and the Area has no external lsa capability |
| seqNumMismatch("External LSA found although area is stub."); |
| return; |
| } |
| |
| LsaWrapper lsaHasInstance = ospfArea.lsaLookup(nextLsa); |
| if (lsaHasInstance == null) { |
| lsReqList.put(((OspfAreaImpl) ospfArea).getLsaKey((LsaHeader) nextLsa), nextLsa); |
| } else { |
| String isNew = ((OspfAreaImpl) ospfArea).isNewerOrSameLsa(nextLsa, |
| lsaHasInstance.ospfLsa()); |
| if (isNew.equals("latest")) { |
| lsReqList.put(((OspfAreaImpl) ospfArea).getLsaKey((LsaHeader) nextLsa), nextLsa); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Handles sequence number mis match event. |
| * |
| * @param reason a string represents the mismatch reason |
| * @return OSPF message instance |
| */ |
| public OspfMessage seqNumMismatch(String reason) { |
| log.debug("OSPFNbr::seqNumMismatch...{} ", reason); |
| stopRxMtDdTimer(); |
| |
| if (state.getValue() >= OspfNeighborState.EXCHANGE.getValue()) { |
| /* if (state == OspfNeighborState.FULL) { |
| ospfArea.refreshArea(ospfInterface); |
| }*/ |
| |
| state = OspfNeighborState.EXSTART; |
| lsReqList.clear(); |
| ddSummaryList.clear(); |
| //increment the dd sequence number |
| ddSeqNum++; |
| |
| DdPacket ddPacket = new DdPacket(); |
| // seting OSPF Header |
| ddPacket.setOspfVer(OspfUtil.OSPF_VERSION); |
| ddPacket.setOspftype(OspfPacketType.DD.value()); |
| ddPacket.setRouterId(ospfArea.routerId()); |
| ddPacket.setAreaId(ospfArea.areaId()); |
| ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length |
| ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED); |
| boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled(); |
| if (isOpaqueEnabled) { |
| ddPacket.setOptions(ospfArea.opaqueEnabledOptions()); |
| } else { |
| ddPacket.setOptions(ospfArea.options()); |
| } |
| ddPacket.setIsInitialize(OspfUtil.INITIALIZE_SET); |
| ddPacket.setIsMore(OspfUtil.MORE_SET); |
| ddPacket.setIsMaster(OspfUtil.IS_MASTER); |
| ddPacket.setImtu(ospfInterface.mtu()); |
| ddPacket.setSequenceNo(ddSeqNum); |
| |
| setLastSentDdPacket(ddPacket); |
| //setting destination ip |
| ddPacket.setDestinationIp(neighborIpAddr()); |
| setLastSentDdPacket(ddPacket); |
| |
| return ddPacket; |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Called if a LS Request has been received for an LSA which is not contained in the database. |
| * This indicates an error in the Database Exchange process. |
| * Actions to be performed are the same as in seqNumMismatch. |
| * In addition, stop the possibly activated re transmission timer. |
| * |
| * @param ch netty channel instance |
| */ |
| @Override |
| public void badLSReq(Channel ch) { |
| log.debug("OSPFNbr::badLSReq...!!!"); |
| |
| if (state.getValue() >= OspfNeighborState.EXCHANGE.getValue()) { |
| if (state == OspfNeighborState.FULL) { |
| ospfArea.refreshArea(ospfInterface); |
| } |
| |
| stopRxMtDdTimer(); |
| state = OspfNeighborState.EXSTART; |
| |
| lsReqList.clear(); |
| ddSummaryList.clear(); |
| reTxList.clear(); |
| //increment the dd sequence number |
| isMaster = OspfUtil.IS_MASTER; |
| ddSeqNum++; |
| DdPacket ddPacket = new DdPacket(); |
| // seting OSPF Header |
| ddPacket.setOspfVer(OspfUtil.OSPF_VERSION); |
| ddPacket.setOspftype(OspfPacketType.DD.value()); |
| ddPacket.setRouterId(ospfArea.routerId()); |
| ddPacket.setAreaId(ospfArea.areaId()); |
| ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length |
| ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED); |
| |
| // setting DD Body |
| boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled(); |
| if (isOpaqueEnabled && this.isOpaqueCapable) { |
| ddPacket.setOptions(ospfArea.opaqueEnabledOptions()); |
| } else { |
| ddPacket.setOptions(ospfArea.options()); |
| } |
| ddPacket.setIsInitialize(OspfUtil.INITIALIZE_SET); |
| ddPacket.setIsMore(OspfUtil.MORE_SET); |
| ddPacket.setIsMaster(OspfUtil.IS_MASTER); |
| ddPacket.setImtu(ospfInterface.mtu()); |
| ddPacket.setSequenceNo(ddSeqNum); |
| |
| rxmtDdPacketTask = new InternalRxmtDdPacket(ch); |
| startRxMtDdTimer(ch); |
| |
| //setting destination ip |
| ddPacket.setDestinationIp(neighborIpAddr()); |
| setLastSentDdPacket(ddPacket); |
| byte[] messageToWrite = getMessage(ddPacket); |
| ch.write(messageToWrite); |
| } |
| } |
| |
| /** |
| * Called if state is EXCHANGE. This method is executed every time a DD Packets arrives. |
| * When the last Packet arrives, it transfers the state into LOADING or FULL |
| * |
| * @param neighborIsMaster true if neighbor is master else false |
| * @param dataDescPkt DdPacket instance |
| * @param ch netty channel instance |
| */ |
| public void processDdPacket(boolean neighborIsMaster, DdPacket dataDescPkt, |
| Channel ch) { |
| log.debug("OSPFNbr::neighborIsMaster.{}", neighborIsMaster); |
| |
| if (!neighborIsMaster) { |
| stopRxMtDdTimer(); |
| ddSeqNum++; |
| processLsas(dataDescPkt.getLsaHeaderList()); |
| if ((ddSummaryList.isEmpty()) && |
| (dataDescPkt.isMore() == OspfUtil.MORE_NOTSET)) { |
| log.debug( |
| "OSPFNbr::ddSummaryList is empty and dataDescPkt.isMore is zero..!!!"); |
| // generate the neighbor event ExchangeDone. |
| exchangeDone(dataDescPkt, ch); |
| } else { |
| log.debug("OSPFNbr::ddSummaryList is present...!!!"); |
| // send a new Database Description Packet to the slave. |
| DdPacket ddPacket = new DdPacket(); |
| // seting OSPF Header |
| ddPacket.setOspfVer(OspfUtil.OSPF_VERSION); |
| ddPacket.setOspftype(OspfPacketType.DD.value()); |
| ddPacket.setRouterId(ospfArea.routerId()); |
| ddPacket.setAreaId(ospfArea.areaId()); |
| ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length |
| ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED); |
| // setting DD Body |
| boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled(); |
| if (isOpaqueEnabled && isOpaqueCapable) { |
| ddPacket.setOptions(ospfArea.opaqueEnabledOptions()); |
| } else { |
| ddPacket.setOptions(ospfArea.options()); |
| } |
| ddPacket.setIsInitialize(OspfUtil.INITIALIZE_NOTSET); |
| ddPacket.setIsMore(OspfUtil.MORE_NOTSET); |
| ddPacket.setIsMaster(OspfUtil.IS_MASTER); |
| ddPacket.setImtu(ospfInterface.mtu()); |
| ddPacket.setSequenceNo(ddSeqNum); |
| |
| setLastSentDdPacket(ddPacket); |
| getIsMoreBit(); |
| //Set the destination IP Address |
| ddPacket.setDestinationIp(dataDescPkt.sourceIp()); |
| byte[] messageToWrite = getMessage(lastSentDdPacket()); |
| ch.write(messageToWrite); |
| |
| startRxMtDdTimer(ch); |
| } |
| } else { |
| log.debug("OSPFNbr::neighborIsMaster is master...!!!"); |
| ddSeqNum = dataDescPkt.sequenceNo(); |
| processLsas(dataDescPkt.getLsaHeaderList()); |
| |
| DdPacket ddPacket = new DdPacket(); |
| // seting OSPF Header |
| ddPacket.setOspfVer(OspfUtil.OSPF_VERSION); |
| ddPacket.setOspftype(OspfPacketType.DD.value()); |
| ddPacket.setRouterId(ospfArea.routerId()); |
| ddPacket.setAreaId(ospfArea.areaId()); |
| ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length |
| ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED); |
| // setting DD Body |
| boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled(); |
| if (isOpaqueEnabled && this.isOpaqueCapable) { |
| ddPacket.setOptions(ospfArea.opaqueEnabledOptions()); |
| } else { |
| ddPacket.setOptions(ospfArea.options()); |
| } |
| ddPacket.setIsInitialize(OspfUtil.INITIALIZE_NOTSET); |
| ddPacket.setIsMore(OspfUtil.MORE_NOTSET); |
| ddPacket.setIsMaster(OspfUtil.NOT_MASTER); |
| ddPacket.setImtu(ospfInterface.mtu()); |
| ddPacket.setSequenceNo(ddSeqNum); |
| setLastSentDdPacket(ddPacket); |
| getIsMoreBit(); |
| |
| if ((ddPacket.isMore() == OspfUtil.MORE_NOTSET) && |
| (dataDescPkt.isMore() == OspfUtil.MORE_NOTSET)) { |
| // generate the neighbor event ExchangeDone. |
| exchangeDone(dataDescPkt, ch); |
| } |
| |
| ddPacket.setDestinationIp(dataDescPkt.sourceIp()); |
| byte[] messageToWrite = getMessage(ddPacket); |
| ch.write(messageToWrite); |
| } |
| } |
| |
| /** |
| * Sets the more bit in stored, last sent DdPacket. |
| */ |
| private void getIsMoreBit() { |
| DdPacket ddPacket = lastSentDdPacket(); |
| int count = ddSummaryList.size(); |
| |
| if (!ddSummaryList.isEmpty()) { |
| Iterator itr = ddSummaryList.iterator(); |
| int currentLength = OspfUtil.DD_HEADER_LENGTH; |
| int maxSize = ospfInterface.mtu() - OspfUtil.LSA_HEADER_LENGTH; // subtract a normal IP header. |
| while (itr.hasNext()) { |
| if ((currentLength + OspfUtil.LSA_HEADER_LENGTH) > maxSize) { |
| break; |
| } |
| |
| LsaHeader lsaHeader = (LsaHeader) itr.next(); |
| ddPacket.addLsaHeader(lsaHeader); |
| currentLength = currentLength + OspfUtil.LSA_HEADER_LENGTH; |
| ddSummaryList.remove(lsaHeader); |
| count--; |
| } |
| |
| if (count > 0) { |
| ddPacket.setIsMore(OspfUtil.MORE_SET); |
| } else { |
| ddPacket.setIsMore(OspfUtil.MORE_NOTSET); |
| } |
| } |
| |
| setLastSentDdPacket(ddPacket); |
| } |
| |
| /** |
| * At this point, the router has sent and received an entire sequence of DD packets. |
| * Now it must be determined whether the new state is FULL, or LS Request packets |
| * have to be send. |
| * |
| * @param message OSPF message instance |
| * @param ch netty channel handler |
| */ |
| public void exchangeDone(OspfMessage message, Channel ch) { |
| log.debug("OSPFNbr::exchangeDone...!!!"); |
| stopRxMtDdTimer(); |
| |
| OspfPacketHeader header = (OspfPacketHeader) message; |
| |
| if (state == OspfNeighborState.EXCHANGE) { |
| if (lsReqList.isEmpty()) { |
| state = OspfNeighborState.FULL; |
| //handler.addDeviceInformation(this); |
| //handler.addLinkInformation(this, topLevelTlvs); |
| } else { |
| state = OspfNeighborState.LOADING; |
| LsRequest lsRequest = buildLsRequest(); |
| //Setting the destination address |
| lsRequest.setDestinationIp(header.sourceIp()); |
| byte[] messageToWrite = getMessage(lsRequest); |
| ch.write(messageToWrite); |
| |
| setLastSentLsrPacket(lsRequest); |
| startRxMtLsrTimer(ch); |
| } |
| } |
| } |
| |
| /** |
| * Builds LS Request. |
| * |
| * @return ls request instance |
| */ |
| private LsRequest buildLsRequest() { |
| //send link state request packet to neighbor |
| //for recent lsa's which are not received in exchange state |
| LsRequest lsRequest = new LsRequest(); |
| lsRequest.setOspfVer(OspfUtil.OSPF_VERSION); |
| lsRequest.setOspftype(OspfPacketType.LSREQUEST.value()); |
| lsRequest.setRouterId(ospfArea.routerId()); |
| lsRequest.setAreaId(ospfArea.areaId()); |
| lsRequest.setAuthType(OspfUtil.NOT_ASSIGNED); |
| lsRequest.setAuthentication(OspfUtil.NOT_ASSIGNED); |
| lsRequest.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length |
| lsRequest.setChecksum(OspfUtil.NOT_ASSIGNED); |
| |
| Set lsaKeys = lsReqList.keySet(); |
| Iterator itr = lsaKeys.iterator(); |
| |
| int currentLength = OspfUtil.OSPF_HEADER_LENGTH; |
| int maxSize = ospfInterface.mtu() - |
| OspfUtil.LSA_HEADER_LENGTH; // subtract a normal IP header. |
| |
| while (itr.hasNext()) { |
| if ((currentLength + OspfUtil.LSREQUEST_LENGTH) >= maxSize) { |
| break; |
| } |
| LsRequestPacket lsRequestPacket = new LsRequestPacket(); |
| |
| String key = ((String) itr.next()); |
| String[] lsaKey = key.split("-"); |
| OspfLsa lsa = (OspfLsa) lsReqList.get(key); |
| |
| lsRequestPacket.setLsType(Integer.valueOf(lsaKey[0])); |
| lsRequestPacket.setOwnRouterId(lsaKey[2]); |
| |
| if (((lsa.getOspfLsaType().value() == OspfLsaType.AREA_LOCAL_OPAQUE_LSA.value()) || |
| (lsa.getOspfLsaType().value() == OspfLsaType.LINK_LOCAL_OPAQUE_LSA.value())) || |
| (lsa.getOspfLsaType().value() == OspfLsaType.AS_OPAQUE_LSA.value())) { |
| OpaqueLsaHeader header = (OpaqueLsaHeader) lsa; |
| byte[] opaqueIdBytes = OspfUtil.convertToTwoBytes(header.opaqueId()); |
| lsRequestPacket.setLinkStateId(header.opaqueType() + "." + "0" + "." + opaqueIdBytes[0] |
| + "." + opaqueIdBytes[1]); |
| } else { |
| lsRequestPacket.setLinkStateId(lsaKey[1]); |
| } |
| |
| lsRequest.addLinkStateRequests(lsRequestPacket); |
| currentLength = currentLength + OspfUtil.LSREQUEST_LENGTH; |
| } |
| |
| return lsRequest; |
| } |
| |
| /** |
| * Determines whether an adjacency should be established/maintained with the neighbor or not. |
| * |
| * @param ch netty channel instance |
| */ |
| @Override |
| public void adjOk(Channel ch) { |
| log.debug("OSPFNbr::adjOk...!!!"); |
| if (ospfInterface.interfaceType() != OspfInterfaceType.POINT_TO_POINT.value()) { |
| if (state == OspfNeighborState.TWOWAY) { |
| if (formAdjacencyOrNot()) { |
| state = OspfNeighborState.EXSTART; |
| //check for sequence number in lsdb |
| ddSeqNum++; |
| |
| DdPacket ddPacket = new DdPacket(); |
| // seting OSPF Header |
| ddPacket.setOspfVer(OspfUtil.OSPF_VERSION); |
| ddPacket.setOspftype(OspfPacketType.DD.value()); |
| ddPacket.setRouterId(ospfArea.routerId()); |
| ddPacket.setAreaId(ospfArea.areaId()); |
| ddPacket.setAuthType(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setAuthentication(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setOspfPacLength(OspfUtil.NOT_ASSIGNED); |
| ddPacket.setChecksum(OspfUtil.NOT_ASSIGNED); |
| |
| // setting DD Body |
| boolean isOpaqueEnabled = ospfArea.isOpaqueEnabled(); |
| if (isOpaqueEnabled && this.isOpaqueCapable) { |
| ddPacket.setOptions(ospfArea.opaqueEnabledOptions()); |
| } else { |
| ddPacket.setOptions(ospfArea.options()); |
| } |
| ddPacket.setIsInitialize(OspfUtil.INITIALIZE_SET); |
| ddPacket.setIsMore(OspfUtil.MORE_SET); |
| ddPacket.setIsMaster(OspfUtil.IS_MASTER); |
| ddPacket.setImtu(ospfInterface.mtu()); |
| ddPacket.setSequenceNo(ddSeqNum); |
| rxmtDdPacketTask = new InternalRxmtDdPacket(ch); |
| startRxMtDdTimer(ch); |
| //setting destination ip |
| ddPacket.setDestinationIp(neighborIpAddr()); |
| setLastSentDdPacket(ddPacket); |
| byte[] messageToWrite = getMessage(ddPacket); |
| ch.write(messageToWrite); |
| } |
| } else if (state.getValue() >= OspfNeighborState.EXSTART.getValue()) { |
| if (!formAdjacencyOrNot()) { |
| state = OspfNeighborState.TWOWAY; |
| lsReqList.clear(); |
| ddSummaryList.clear(); |
| reTxList.clear(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * LS Update Packet has been received while state was EXCHANGE or LOADING. |
| * Examine the received LSAs, check whether they were requested or not and process |
| * them accordingly. Therefore use method "processReceivedLsa" for further treatment. |
| * |
| * @param lsUpdPkt LS Update Packet received while Neighbor state was EXCHANGE or |
| * LOADING |
| * @param ch netty channel instance |
| * @throws OspfParseException on parsing error |
| */ |
| public void processLsUpdate(LsUpdate lsUpdPkt, Channel ch) throws OspfParseException { |
| stopRxMtLsrTimer(); |
| log.debug("OSPFNbr::processLsUpdate...!!!"); |
| |
| List lsaList = lsUpdPkt.getLsaList(); |
| if (!lsaList.isEmpty()) { |
| Iterator itr = lsaList.iterator(); |
| |
| while (itr.hasNext()) { |
| LsaHeader lsaHeader = (LsaHeader) itr.next(); |
| String key = ((OspfAreaImpl) ospfArea).getLsaKey(lsaHeader); |
| |
| if (lsReqList.containsKey(key)) { |
| boolean removeIt; |
| removeIt = processReceivedLsa(lsaHeader, false, ch, |
| lsUpdPkt.sourceIp()); |
| if (removeIt) { |
| lsReqList.remove(key); |
| } |
| } else { |
| // LSA was received via Flooding |
| processReceivedLsa(lsaHeader, true, ch, |
| lsUpdPkt.sourceIp()); |
| } |
| } |
| |
| if (lsReqList.isEmpty() && (state == OspfNeighborState.LOADING)) { |
| // loading complete |
| loadingDone(); |
| } else { |
| stopRxMtLsrTimer(); |
| LsRequest lsRequest = buildLsRequest(); |
| lsRequest.setDestinationIp(lsUpdPkt.sourceIp()); |
| setLastSentLsrPacket(lsRequest); |
| |
| startRxMtLsrTimer(ch); |
| } |
| } |
| } |
| |
| /*** |
| * Method gets called when no more ls request list and moving to FULL State. |
| */ |
| public void loadingDone() { |
| stopRxMtLsrTimer(); |
| stopRxMtDdTimer(); |
| log.debug("OSPFNbr::loadingDone...!!!"); |
| state = OspfNeighborState.FULL; |
| ospfArea.refreshArea(ospfInterface); |
| } |
| |
| /** |
| * Adds device and link. |
| * |
| * @param topologyForDeviceAndLink topology for device and link instance |
| */ |
| private void callDeviceAndLinkAdding(TopologyForDeviceAndLink topologyForDeviceAndLink) { |
| Map<String, DeviceInformation> deviceInformationMap = topologyForDeviceAndLink.deviceInformationMap(); |
| Map<String, DeviceInformation> deviceInformationMapForPointToPoint = |
| topologyForDeviceAndLink.deviceInformationMapForPointToPoint(); |
| Map<String, DeviceInformation> deviceInformationMapToDelete = |
| topologyForDeviceAndLink.deviceInformationMapToDelete(); |
| Map<String, LinkInformation> linkInformationMap = topologyForDeviceAndLink.linkInformationMap(); |
| Map<String, LinkInformation> linkInformationMapForPointToPoint = |
| topologyForDeviceAndLink.linkInformationMapForPointToPoint(); |
| OspfRouter ospfRouter = new OspfRouterImpl(); |
| |
| if (deviceInformationMap.size() != 0) { |
| for (String key : deviceInformationMap.keySet()) { |
| DeviceInformation value = deviceInformationMap.get(key); |
| ospfRouter.setRouterIp(value.routerId()); |
| ospfRouter.setAreaIdOfInterface(ospfArea.areaId()); |
| ospfRouter.setNeighborRouterId(value.deviceId()); |
| OspfDeviceTed ospfDeviceTed = new OspfDeviceTedImpl(); |
| List<Ip4Address> ip4Addresses = value.interfaceId(); |
| ospfDeviceTed.setIpv4RouterIds(ip4Addresses); |
| ospfRouter.setDeviceTed(ospfDeviceTed); |
| ospfRouter.setOpaque(ospfArea.isOpaqueEnabled()); |
| if (value.isDr()) { |
| ospfRouter.setDr(value.isDr()); |
| } else { |
| ospfRouter.setDr(false); |
| } |
| int size = value.interfaceId().size(); |
| for (int i = 0; i < size; i++) { |
| ospfRouter.setInterfaceId(value.interfaceId().get(i)); |
| } |
| ((OspfInterfaceImpl) ospfInterface).addDeviceInformation(ospfRouter); |
| } |
| } |
| if (deviceInformationMapForPointToPoint.size() != 0) { |
| for (String key : deviceInformationMapForPointToPoint.keySet()) { |
| DeviceInformation value = deviceInformationMapForPointToPoint.get(key); |
| ospfRouter.setRouterIp(value.routerId()); |
| ospfRouter.setAreaIdOfInterface(ospfArea.areaId()); |
| ospfRouter.setNeighborRouterId(value.deviceId()); |
| OspfDeviceTed ospfDeviceTed = new OspfDeviceTedImpl(); |
| List<Ip4Address> ip4Addresses = value.interfaceId(); |
| ospfDeviceTed.setIpv4RouterIds(ip4Addresses); |
| ospfRouter.setDeviceTed(ospfDeviceTed); |
| ospfRouter.setOpaque(value.isDr()); |
| int size = value.interfaceId().size(); |
| for (int i = 0; i < size; i++) { |
| ospfRouter.setInterfaceId(value.interfaceId().get(i)); |
| } |
| ((OspfInterfaceImpl) ospfInterface).addDeviceInformation(ospfRouter); |
| } |
| } |
| for (Map.Entry<String, LinkInformation> entry : linkInformationMap.entrySet()) { |
| String key = entry.getKey(); |
| LinkInformation value = entry.getValue(); |
| OspfRouter ospfRouterForLink = new OspfRouterImpl(); |
| ospfRouterForLink.setInterfaceId(value.interfaceIp()); |
| ospfRouterForLink.setAreaIdOfInterface(ospfArea.areaId()); |
| ospfRouterForLink.setOpaque(ospfArea.isOpaqueEnabled()); |
| OspfLinkTed ospfLinkTed = topologyForDeviceAndLink.getOspfLinkTedHashMap( |
| value.linkDestinationId().toString()); |
| if (ospfLinkTed == null) { |
| ospfLinkTed = new OspfLinkTedImpl(); |
| ospfLinkTed.setMaximumLink(Bandwidth.bps(0)); |
| ospfLinkTed.setMaxReserved(Bandwidth.bps(0)); |
| ospfLinkTed.setTeMetric(0); |
| } |
| |
| if (!value.isLinkSrcIdNotRouterId()) { |
| ospfRouterForLink.setRouterIp(value.linkSourceId()); |
| ospfRouterForLink.setNeighborRouterId(value.linkDestinationId()); |
| try { |
| ((OspfInterfaceImpl) ospfInterface).addLinkInformation(ospfRouterForLink, ospfLinkTed); |
| } catch (Exception e) { |
| log.debug("Exception addLinkInformation: " + e.getMessage()); |
| } |
| } |
| } |
| } |
| |
| // RFC 2328 Section 13 - partly as flooding procedure |
| |
| /** |
| * Processes the received Lsa. |
| * |
| * @param recLsa received Lsa |
| * @param receivedViaFlooding received via flooding or not |
| * @param ch channel instance |
| * @param sourceIp source of this Lsa |
| * @throws OspfParseException on parsing error |
| * @return true to remove it from lsReqList else false |
| */ |
| public boolean processReceivedLsa(LsaHeader recLsa, |
| boolean receivedViaFlooding, Channel ch, Ip4Address sourceIp) |
| throws OspfParseException { |
| log.debug("OSPFNbr::processReceivedLsa(recLsa, receivedViaFlooding, ch)...!!!"); |
| |
| //Validate the lsa checksum RFC 2328 13 (1) |
| ChecksumCalculator checkSum = new ChecksumCalculator(); |
| if (!checkSum.isValidLsaCheckSum(recLsa, |
| recLsa.getOspfLsaType().value(), |
| OspfUtil.LSAPACKET_CHECKSUM_POS1, |
| OspfUtil.LSAPACKET_CHECKSUM_POS2)) { |
| log.debug("Checksum mismatch. Received LSA packet type {} ", |
| recLsa.lsType()); |
| |
| return true; |
| } |
| |
| //If LSA type is unknown discard the lsa RFC 2328 13(2) |
| if (((recLsa.getOspfLsaType().value() > OspfLsaType.EXTERNAL_LSA.value()) && |
| (recLsa.getOspfLsaType().value() < OspfLsaType.LINK_LOCAL_OPAQUE_LSA.value())) || |
| (recLsa.getOspfLsaType().value() > OspfLsaType.AS_OPAQUE_LSA.value())) { |
| return true; |
| } |
| |
| //If LSA type is external & the area is configured as stub area discard the lsa RFC 2328 13(3) |
| if ((recLsa.getOspfLsaType() == OspfLsaType.EXTERNAL_LSA) && |
| (!ospfArea.isExternalRoutingCapability())) { |
| return true; |
| } |
| |
| //if lsa age is equal to maxage && instance is not in lsdb && none of neighbors are in exchange |
| // or loading state |
| // Acknowledge the receipt by sending LSAck to the sender. 2328 13(4) |
| if ((recLsa.age() == OspfParameters.MAXAGE) && |
| (ospfArea.lsaLookup(recLsa) == null) && |
| ospfArea.noNeighborInLsaExchangeProcess()) { |
| // RFC 2328 Section 13. (4) |
| // Because the LSA was not yet requested, it is treated as a flooded LSA and thus |
| // acknowledged. |
| directAcknowledge(recLsa, ch, sourceIp); |
| return true; |
| } |
| |
| String key = ((OspfAreaImpl) ospfArea).getLsaKey(recLsa); |
| LsaWrapper lsWrapper = ospfArea.lsaLookup(recLsa); |
| String status = isNullorLatest(lsWrapper, recLsa); |
| //Section 13 (5) |
| if (status.equals("isNullorLatest")) { |
| |
| if (recLsa.lsType() == OspfLsaType.ROUTER.value() && recLsa.advertisingRouter().equals( |
| ospfArea.routerId())) { |
| if (recLsa.lsSequenceNo() > ((LsaWrapperImpl) lsWrapper).lsaHeader().lsSequenceNo()) { |
| ospfArea.setDbRouterSequenceNumber(recLsa.lsSequenceNo() + 1); |
| processSelfOriginatedLsa(); |
| } |
| |
| if (recLsa.age() == OspfParameters.MAXAGE) { |
| ((LsaWrapperImpl) lsWrapper).lsaHeader().setAge(OspfParameters.MAXAGE); |
| //remove from db & bin, add the lsa to MaxAge bin. |
| ospfArea.addLsaToMaxAgeBin(((OspfAreaImpl) ospfArea).getLsaKey(((LsaWrapperImpl) |
| lsWrapper).lsaHeader()), lsWrapper); |
| ospfArea.removeLsaFromBin(lsWrapper); |
| } |
| |
| return true; |
| } else if (recLsa.lsType() == OspfLsaType.NETWORK.value() && isLinkStateMatchesOwnRouterId( |
| recLsa.linkStateId())) { |
| // if we are not DR or if origination router ID not equal to our router ID //either |
| // DR state changed or our router ID was changed |
| //set LSAge = MaxAge |
| //flood the LSA |
| if (((OspfInterfaceImpl) ospfInterface).state() != OspfInterfaceState.DR || |
| !recLsa.advertisingRouter().equals( |
| ospfArea.routerId())) { |
| if (lsWrapper != null) { |
| ((LsaWrapperImpl) lsWrapper).lsaHeader().setAge(OspfParameters.MAXAGE); |
| //remove from bin, add the lsa to MaxAge bin. |
| ospfArea.addLsaToMaxAgeBin(((OspfAreaImpl) ospfArea).getLsaKey(((LsaWrapperImpl) |
| lsWrapper).lsaHeader()), lsWrapper); |
| ospfArea.removeLsaFromBin(lsWrapper); |
| } else { |
| recLsa.setAge(OspfParameters.MAXAGE); |
| ((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(recLsa); |
| } |
| } |
| |
| return true; |
| } else { |
| if (recLsa.age() == OspfParameters.MAXAGE) { |
| ((OspfInterfaceImpl) ospfInterface).addLsaHeaderForDelayAck(recLsa); |
| //remove from db & bin, add the lsa to MaxAge bin. |
| if (lsWrapper != null) { |
| lsWrapper.setLsaAgeReceived(OspfParameters.MAXAGE); |
| ospfArea.addLsaToMaxAgeBin(((OspfAreaImpl) ospfArea).getLsaKey(((LsaWrapperImpl) |
| lsWrapper).lsaHeader()), lsWrapper); |
| ospfArea.removeLsaFromBin(lsWrapper); |
| } else { |
| ((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(recLsa); |
| } |
| |
| return true; |
| } else { |
| ospfArea.addLsa(recLsa, ospfInterface); |
| log.debug("Inside addLsaMethod"); |
| topologyForDeviceAndLink.addLocalDevice(recLsa, ospfInterface, ospfArea); |
| callDeviceAndLinkAdding(topologyForDeviceAndLink); |
| log.debug("Adding to lsdb interface State {}", ((OspfInterfaceImpl) ospfInterface).state().value()); |
| // should not send any acknowledge if flooded out on receiving interface |
| if (((OspfInterfaceImpl) ospfInterface).state().value() == OspfInterfaceState.BDR.value()) { |
| if (neighborDr.equals(sourceIp)) { |
| log.debug("Adding for delayed ack {}", recLsa); |
| ((OspfInterfaceImpl) ospfInterface).addLsaHeaderForDelayAck(recLsa); |
| } |
| } else { |
| log.debug("Adding for delayed ack {}", recLsa); |
| ((OspfInterfaceImpl) ospfInterface).addLsaHeaderForDelayAck(recLsa); |
| } |
| |
| if (((OspfInterfaceImpl) ospfInterface).state().value() == OspfInterfaceState.DR.value() || |
| ((OspfInterfaceImpl) ospfInterface).state().value() == |
| OspfInterfaceState.POINT2POINT.value()) { |
| ((OspfAreaImpl) ospfArea).addToOtherNeighborLsaTxList(recLsa); |
| } |
| } |
| |
| } |
| } |
| // RFC 2328 Section 13 (6) |
| if (lsReqList.containsValue(key)) { |
| badLSReq(ch); |
| } |
| if (status.equals("same")) { //13 (7) |
| if (pendingReTxList.containsKey(key)) { |
| pendingReTxList.remove(key); |
| if (((OspfInterfaceImpl) ospfInterface).state().value() == OspfInterfaceState.BDR.value()) { |
| if (neighborDr.equals(recLsa.advertisingRouter())) { |
| ((OspfInterfaceImpl) ospfInterface).addLsaHeaderForDelayAck(recLsa); |
| } |
| } |
| } else { |
| directAcknowledge(recLsa, ch, sourceIp); |
| return true; |
| } |
| } else if (status.equals("old")) { // section 13 - point 8 |
| if ((recLsa.lsSequenceNo() == OspfParameters.MAXSEQUENCENUMBER) && |
| (recLsa.age() == OspfParameters.MAXAGE)) { |
| // section 13 - point 8 |
| // simple discard the received LSA - |
| return true; |
| } else { |
| // respond back with the same LSA |
| //Using flood LSA to sent the LSUpdate back to advertising router |
| int diff = Math.abs(lsWrapper.lsaAgeReceived() - recLsa.age()); |
| if (diff > OspfParameters.MINLSARRIVAL) { |
| sendLsa(((LsaWrapperImpl) lsWrapper).lsaHeader(), sourceIp, ch); |
| } |
| } |
| } |
| |
| constructDeviceInformationFromDb(); |
| callDeviceAndLinkAdding(topologyForDeviceAndLink); |
| |
| return true; |
| } |
| |
| /** |
| * Constructs device and link information from link state database. |
| */ |
| private void constructDeviceInformationFromDb() { |
| OspfLsdb database = ospfArea.database(); |
| List lsas = database.getAllLsaHeaders(true, true); |
| Iterator iterator = lsas.iterator(); |
| while (iterator.hasNext()) { |
| OspfLsa ospfLsa = (OspfLsa) iterator.next(); |
| if (ospfLsa.getOspfLsaType().value() == OspfLsaType.ROUTER.value()) { |
| topologyForDeviceAndLink.addLocalDevice(ospfLsa, ospfInterface, ospfArea); |
| } else if (ospfLsa.getOspfLsaType().value() == OspfLsaType.NETWORK.value()) { |
| topologyForDeviceAndLink.addLocalDevice(ospfLsa, ospfInterface, ospfArea); |
| } |
| } |
| } |
| |
| /** |
| * Checks Link State ID is equal to one of the router's own IP interface addresses. |
| * |
| * @param linkStateId link state id |
| * @return true if link state matches or false |
| */ |
| private boolean isLinkStateMatchesOwnRouterId(String linkStateId) { |
| boolean isLinkStateMatches = false; |
| List<OspfInterface> interfaceLst = ospfArea.ospfInterfaceList(); |
| for (OspfInterface ospfInterface : interfaceLst) { |
| if (ospfInterface.ipAddress().toString().equals(linkStateId)) { |
| isLinkStateMatches = true; |
| break; |
| } |
| } |
| |
| return isLinkStateMatches; |
| } |
| |
| /** |
| * RFC 2328 Section 13 (5). |
| * |
| * @param lsWrapper ls wrapper instance |
| * @param recLsa received LSA instance |
| * @return returns a string status |
| */ |
| public String isNullorLatest(LsaWrapper lsWrapper, LsaHeader recLsa) { |
| |
| |
| if (lsWrapper != null) { |
| LsaHeader ownLsa = (LsaHeader) lsWrapper.ospfLsa(); |
| String status = ospfArea.isNewerOrSameLsa(recLsa, ownLsa); |
| |
| if (status.equals("latest")) { |
| return "isNullorLatest"; |
| } else { |
| return status; |
| } |
| } else { |
| return "isNullorLatest"; |
| } |
| } |
| |
| /** |
| * RFC 2328 section 13.4 |
| * Processing self-originated LSAs. |
| */ |
| public void processSelfOriginatedLsa() { |
| ospfArea.refreshArea(ospfInterface); |
| } |
| |
| /** |
| * Sends the LSA to destination address. |
| * |
| * @param lsa LSA instance to sent |
| * @param destination destination IP address |
| * @param ch netty channel instance |
| */ |
| public void sendLsa(LsaHeader lsa, Ip4Address destination, Channel ch) { |
| if (lsa == null) { |
| return; |
| } |
| |
| LsUpdate responseLsUpdate = new LsUpdate(); |
| // seting OSPF Header |
| responseLsUpdate.setOspfVer(OspfUtil.OSPF_VERSION); |
| responseLsUpdate.setOspftype(OspfPacketType.LSUPDATE.value()); |
| responseLsUpdate.setRouterId(ospfArea.routerId()); |
| responseLsUpdate.setAreaId(ospfArea.areaId()); |
| responseLsUpdate.setAuthType(OspfUtil.NOT_ASSIGNED); |
| responseLsUpdate.setAuthentication(OspfUtil.NOT_ASSIGNED); |
| responseLsUpdate.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length |
| responseLsUpdate.setChecksum(OspfUtil.NOT_ASSIGNED); |
| responseLsUpdate.setNumberOfLsa(1); |
| responseLsUpdate.addLsa(lsa); |
| |
| //setting the destination. |
| responseLsUpdate.setDestinationIp(destination); |
| byte[] messageToWrite = getMessage(responseLsUpdate); |
| ch.write(messageToWrite); |
| } |
| |
| /** |
| * Sends a direct Acknowledgment for a particular LSA to the Neighbor. |
| * |
| * @param ackLsa LSA instance |
| * @param ch netty channel instance |
| * @param sourceIp source IP address |
| */ |
| public void directAcknowledge(LsaHeader ackLsa, Channel ch, Ip4Address sourceIp) { |
| log.debug("OSPFNbr::directAcknowledge...!!!"); |
| |
| LsAcknowledge ackContent = new LsAcknowledge(); |
| // seting OSPF Header |
| ackContent.setOspfVer(OspfUtil.OSPF_VERSION); |
| ackContent.setOspftype(OspfPacketType.LSAACK.value()); |
| ackContent.setRouterId(ospfArea.routerId()); |
| ackContent.setAreaId(ospfArea.areaId()); |
| ackContent.setAuthType(OspfUtil.NOT_ASSIGNED); |
| ackContent.setAuthentication(OspfUtil.NOT_ASSIGNED); |
| ackContent.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length |
| ackContent.setChecksum(OspfUtil.NOT_ASSIGNED); |
| ackContent.addLinkStateHeader(ackLsa); |
| //setting the destination IP |
| ackContent.setDestinationIp(sourceIp); |
| byte[] messageToWrite = getMessage(ackContent); |
| ch.write(messageToWrite); |
| } |
| |
| /** |
| * Called when neighbor is down. |
| */ |
| public void neighborDown() { |
| log.debug("Neighbor Down {} and NeighborId {}", neighborIpAddr, |
| neighborId); |
| stopInactivityTimeCheck(); |
| stopRxMtDdTimer(); |
| stopRxMtLsrTimer(); |
| |
| if (floodingTimerScheduled) { |
| stopFloodingTimer(); |
| floodingTimerScheduled = false; |
| } |
| |
| state = OspfNeighborState.DOWN; |
| ospfArea.refreshArea(ospfInterface); |
| lsReqList.clear(); |
| ddSummaryList.clear(); |
| if (neighborIpAddr.equals(neighborBdr) || |
| neighborIpAddr.equals(neighborDr)) { |
| ((OspfInterfaceImpl) ospfInterface).neighborChange(); |
| } |
| log.debug("Neighbor Went Down : " |
| + this.neighborIpAddr + " , " + this.neighborId); |
| removeDeviceDetails(this.neighborId); |
| OspfRouter ospfRouter = new OspfRouterImpl(); |
| ospfRouter.setRouterIp(this.neighborId()); |
| ospfRouter.setInterfaceId(ospfInterface.ipAddress()); |
| ospfRouter.setAreaIdOfInterface(ospfArea.areaId()); |
| ospfRouter.setDeviceTed(new OspfDeviceTedImpl()); |
| ((OspfInterfaceImpl) ospfInterface).removeDeviceInformation(ospfRouter); |
| removeDeviceDetails(this.neighborIpAddr); |
| OspfRouter ospfRouter1 = new OspfRouterImpl(); |
| ospfRouter1.setRouterIp(this.neighborIpAddr); |
| ospfRouter1.setInterfaceId(ospfInterface.ipAddress()); |
| ospfRouter1.setAreaIdOfInterface(ospfArea.areaId()); |
| ospfRouter1.setDeviceTed(new OspfDeviceTedImpl()); |
| ((OspfInterfaceImpl) ospfInterface).removeDeviceInformation(ospfRouter1); |
| } |
| |
| /** |
| * Removes device details. |
| * |
| * @param routerId router id |
| */ |
| private void removeDeviceDetails(Ip4Address routerId) { |
| String key = "device:" + routerId; |
| topologyForDeviceAndLink.removeDeviceInformationMap(key); |
| } |
| |
| /** |
| * Starts the inactivity timer. |
| */ |
| @Override |
| public void startInactivityTimeCheck() { |
| if (!inActivityTimerScheduled) { |
| log.debug("OSPFNbr::startInactivityTimeCheck"); |
| inActivityTimeCheckTask = new InternalInactivityTimeCheck(); |
| exServiceInActivity = Executors.newSingleThreadScheduledExecutor(); |
| exServiceInActivity.scheduleAtFixedRate(inActivityTimeCheckTask, routerDeadInterval, |
| routerDeadInterval, TimeUnit.SECONDS); |
| inActivityTimerScheduled = true; |
| } |
| } |
| |
| /** |
| * Stops the inactivity timer. |
| */ |
| @Override |
| public void stopInactivityTimeCheck() { |
| if (inActivityTimerScheduled) { |
| log.debug("OSPFNbr::stopInactivityTimeCheck "); |
| exServiceInActivity.shutdown(); |
| inActivityTimerScheduled = false; |
| } |
| } |
| |
| /** |
| * Starts the flooding timer. |
| * |
| * @param channel channel instance |
| */ |
| public void startFloodingTimer(Channel channel) { |
| |
| if (!floodingTimerScheduled) { |
| log.debug("OSPFNbr::startFloodingTimer"); |
| floodingTask = new InternalFloodingTask(channel); |
| exServiceFlooding = Executors.newSingleThreadScheduledExecutor(); |
| //Run every 5 seconds. |
| exServiceFlooding.scheduleAtFixedRate(floodingTask, OspfParameters.START_NOW, |
| OspfParameters.MINLSINTERVAL, TimeUnit.SECONDS); |
| floodingTimerScheduled = true; |
| } |
| } |
| |
| /** |
| * Stops the flooding timer. |
| */ |
| @Override |
| public void stopFloodingTimer() { |
| if (floodingTimerScheduled) { |
| log.debug("OSPFNbr::stopFloodingTimer "); |
| exServiceFlooding.shutdown(); |
| floodingTimerScheduled = false; |
| } |
| } |
| |
| /** |
| * Starts the Dd Retransmission executor task. |
| * |
| * @param ch netty channel instance |
| */ |
| private void startRxMtDdTimer(Channel ch) { |
| if (!rxmtDdPacketTimerScheduled) { |
| long retransmitInterval = ospfInterface.reTransmitInterval(); |
| rxmtDdPacketTask = new InternalRxmtDdPacket(ch); |
| exServiceRxmtDDPacket = Executors.newSingleThreadScheduledExecutor(); |
| exServiceRxmtDDPacket.scheduleAtFixedRate(rxmtDdPacketTask, retransmitInterval, |
| retransmitInterval, TimeUnit.SECONDS); |
| rxmtDdPacketTimerScheduled = true; |
| } |
| } |
| |
| /** |
| * Stops the Dd Retransmission executor task. |
| */ |
| @Override |
| public void stopRxMtDdTimer() { |
| if (rxmtDdPacketTimerScheduled) { |
| exServiceRxmtDDPacket.shutdown(); |
| rxmtDdPacketTimerScheduled = false; |
| } |
| } |
| |
| /** |
| * Starts Ls request retransmission executor task. |
| * |
| * @param ch Netty channel instance |
| */ |
| private void startRxMtLsrTimer(Channel ch) { |
| if (!rxmtLsrTimerScheduled) { |
| log.debug("OSPFNbr::startRxMtLsrTimer...!!!"); |
| long retransmitIntrvl = ospfInterface.reTransmitInterval(); |
| rxmtLsrPacketTask = new InternalRxmtLsrPacket(ch); |
| exServiceRxmtLsr = Executors.newSingleThreadScheduledExecutor(); |
| exServiceRxmtLsr.scheduleAtFixedRate(rxmtLsrPacketTask, retransmitIntrvl, |
| retransmitIntrvl, TimeUnit.SECONDS); |
| rxmtLsrTimerScheduled = true; |
| } |
| } |
| |
| /** |
| * Stops Ls request retransmission executor task. |
| */ |
| @Override |
| public void stopRxMtLsrTimer() { |
| if (rxmtLsrTimerScheduled) { |
| exServiceRxmtLsr.shutdown(); |
| rxmtLsrTimerScheduled = false; |
| } |
| } |
| |
| /** |
| * Gets the last sent DdPacket. |
| * |
| * @return DdPacket instance |
| */ |
| public DdPacket lastDdPacket() { |
| return lastDdPacket; |
| } |
| |
| /** |
| * Sets the last sent DdPacket. |
| * |
| * @param lastDdPacket DdPacket instance |
| */ |
| public void setLastDdPacket(DdPacket lastDdPacket) { |
| this.lastDdPacket = lastDdPacket; |
| } |
| |
| /** |
| * Gets neighbor id. |
| * |
| * @return neighbor id |
| */ |
| @Override |
| public Ip4Address neighborId() { |
| return neighborId; |
| } |
| |
| /** |
| * Sets the neighbor id. |
| * |
| * @param neighborId neighbor id |
| */ |
| @Override |
| public void setNeighborId(Ip4Address neighborId) { |
| this.neighborId = neighborId; |
| } |
| |
| /** |
| * Gets the neighbor DR address. |
| * |
| * @return neighbor DR address |
| */ |
| @Override |
| public Ip4Address neighborDr() { |
| return neighborDr; |
| } |
| |
| /** |
| * Sets the neighbor DR address. |
| * |
| * @param neighborDr neighbor DR address |
| */ |
| @Override |
| public void setNeighborDr(Ip4Address neighborDr) { |
| this.neighborDr = neighborDr; |
| } |
| |
| /** |
| * Gets the neighbor BDR address. |
| * |
| * @return neighbor BDR address |
| */ |
| @Override |
| public Ip4Address neighborBdr() { |
| return neighborBdr; |
| } |
| |
| /** |
| * Sets the neighbor BDR address. |
| * |
| * @param neighborBdr neighbor BDR address |
| */ |
| @Override |
| public void setNeighborBdr(Ip4Address neighborBdr) { |
| this.neighborBdr = neighborBdr; |
| } |
| |
| /** |
| * Gets router priority. |
| * |
| * @return router priority |
| */ |
| @Override |
| public int routerPriority() { |
| return routerPriority; |
| } |
| |
| /** |
| * Sets router priority. |
| * |
| * @param routerPriority router priority |
| */ |
| @Override |
| public void setRouterPriority(int routerPriority) { |
| this.routerPriority = routerPriority; |
| } |
| |
| /** |
| * Gets the options value. |
| * |
| * @return options value |
| */ |
| @Override |
| public int options() { |
| return options; |
| } |
| |
| /** |
| * Sets the options value. |
| * |
| * @param options options value |
| */ |
| @Override |
| public void setOptions(int options) { |
| this.options = options; |
| } |
| |
| /** |
| * Gets the DD sequence number. |
| * |
| * @return DD sequence number |
| */ |
| @Override |
| public long ddSeqNum() { |
| return ddSeqNum; |
| } |
| |
| /** |
| * Sets the DD sequence number. |
| * |
| * @param ddSeqNum DD sequence number |
| */ |
| @Override |
| public void setDdSeqNum(long ddSeqNum) { |
| this.ddSeqNum = ddSeqNum; |
| } |
| |
| /** |
| * Gets neighbor is master or not. |
| * |
| * @return true if neighbor is master else false |
| */ |
| @Override |
| public int isMaster() { |
| return isMaster; |
| } |
| |
| /** |
| * Gets the last sent DD Packet. |
| * |
| * @return last sent DD Packet |
| */ |
| public DdPacket lastSentDdPacket() { |
| return lastSentDdPacket; |
| } |
| |
| /** |
| * Sets the last sent DD Packet. |
| * |
| * @param lastSentDdPacket last sent DD Packet |
| */ |
| public void setLastSentDdPacket(DdPacket lastSentDdPacket) { |
| this.lastSentDdPacket = lastSentDdPacket; |
| } |
| |
| /** |
| * Gets the last sent Ls Request Packet. |
| * |
| * @return last sent Ls Request Packet |
| */ |
| public LsRequest getLastSentLsrPacket() { |
| return lastSentLsrPacket; |
| } |
| |
| /** |
| * Sets the last sent Ls Request Packet. |
| * |
| * @param lastSentLsrPacket last sent Ls Request Packet |
| */ |
| public void setLastSentLsrPacket(LsRequest lastSentLsrPacket) { |
| this.lastSentLsrPacket = lastSentLsrPacket; |
| } |
| |
| /** |
| * Gets the neighbors state. |
| * |
| * @return neighbors state |
| */ |
| @Override |
| public OspfNeighborState getState() { |
| return state; |
| } |
| |
| /** |
| * Sets the neighbors state. |
| * |
| * @param state neighbors state |
| */ |
| public void setState(OspfNeighborState state) { |
| this.state = state; |
| } |
| |
| /** |
| * Sets neighbor is master or not. |
| * |
| * @param isMaster neighbor is master or not |
| */ |
| @Override |
| public void setIsMaster(int isMaster) { |
| this.isMaster = isMaster; |
| } |
| |
| /** |
| * Gets the ls request list. |
| * |
| * @return ls request list |
| */ |
| @Override |
| public Hashtable getLsReqList() { |
| return lsReqList; |
| } |
| |
| /** |
| * Gets the reTxList instance. |
| * |
| * @return reTxList instance |
| */ |
| @Override |
| public Map getReTxList() { |
| return reTxList; |
| } |
| |
| /** |
| * Gets the pending re transmit list. |
| * |
| * @return pendingReTxList instance |
| */ |
| @Override |
| public Map<String, OspfLsa> getPendingReTxList() { |
| return pendingReTxList; |
| } |
| |
| /** |
| * Gets message as bytes. |
| * |
| * @param ospfMessage OSPF message |
| * @return OSPF message |
| */ |
| private byte[] getMessage(OspfMessage ospfMessage) { |
| OspfMessageWriter messageWriter = new OspfMessageWriter(); |
| if (((OspfInterfaceImpl) ospfInterface).state().equals(OspfInterfaceState.POINT2POINT)) { |
| ospfMessage.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS); |
| } |
| return (messageWriter.getMessage(ospfMessage, ospfInterface.interfaceIndex(), |
| ((OspfInterfaceImpl) ospfInterface).state().value())); |
| } |
| |
| |
| /** |
| * Represents a Task which will do an inactivity time check. |
| */ |
| private class InternalInactivityTimeCheck implements Runnable { |
| /** |
| * Constructor. |
| */ |
| InternalInactivityTimeCheck() { |
| } |
| |
| @Override |
| public void run() { |
| try { |
| log.debug("Neighbor Not Heard till the past router dead interval ."); |
| neighborDown(); |
| } catch (Exception e) { |
| log.debug("Exception at inactivity time check...!!!"); |
| } |
| } |
| } |
| |
| /** |
| * Task which re transmits DdPacket every configured time interval. |
| */ |
| private class InternalRxmtDdPacket implements Runnable { |
| Channel ch; |
| |
| /** |
| * Creates an instance or Re transmit DD packet timer. |
| * |
| * @param ch netty channel instance |
| */ |
| InternalRxmtDdPacket(Channel ch) { |
| this.ch = ch; |
| } |
| |
| @Override |
| public void run() { |
| if ((ch != null) && ch.isConnected()) { |
| DdPacket ddPacket = lastSentDdPacket(); |
| byte[] messageToWrite = getMessage(ddPacket); |
| ch.write(messageToWrite); |
| log.debug("Re-Transmit DD Packet ."); |
| } else { |
| log.debug( |
| "Re-Transmit DD Packet failed. Channel not connected.."); |
| } |
| } |
| } |
| |
| /** |
| * Task which re transmits Ls request Packet every configured time interval. |
| */ |
| private class InternalRxmtLsrPacket implements Runnable { |
| Channel ch; |
| |
| /** |
| * Creates an instance or Re transmit LS Request packet timer. |
| * |
| * @param ch netty channel instance |
| */ |
| InternalRxmtLsrPacket(Channel ch) { |
| this.ch = ch; |
| } |
| |
| @Override |
| public void run() { |
| if ((ch != null) && ch.isConnected()) { |
| LsRequest lsrPacket = getLastSentLsrPacket(); |
| byte[] messageToWrite = getMessage(lsrPacket); |
| ch.write(messageToWrite); |
| log.debug("Re-Transmit LSRequest Packet ."); |
| } else { |
| log.debug( |
| "Re-Transmit LSRequest failed. Channel not connected.."); |
| } |
| } |
| } |
| |
| /** |
| * Task which transmits Ls update Packet based on the re transmit list. |
| * every configured time interval. |
| */ |
| private class InternalFloodingTask implements Runnable { |
| Channel channel; |
| |
| /** |
| * Creates an instance or Flooding task. |
| * |
| * @param ch netty channel instance |
| */ |
| InternalFloodingTask(Channel ch) { |
| this.channel = ch; |
| } |
| |
| @Override |
| public void run() { |
| if ((channel != null) && channel.isConnected()) { |
| |
| if ((pendingReTxList != null) && (pendingReTxList.size() > 0)) { |
| List<LsUpdate> lsUpdateList = buildLsUpdate(pendingReTxList); |
| |
| for (LsUpdate lsupdate : lsUpdateList) { |
| //Pending for acknowledge directly sent it to neighbor |
| lsupdate.setDestinationIp(neighborIpAddr); |
| byte[] messageToWrite = getMessage(lsupdate); |
| channel.write(messageToWrite); |
| } |
| } |
| |
| if ((reTxList != null) && (reTxList.size() > 0)) { |
| List<LsUpdate> lsUpdateList = buildLsUpdate(reTxList); |
| |
| for (LsUpdate lsupdate : lsUpdateList) { |
| //set the destination |
| if ((((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DR) || |
| (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.POINT2POINT)) { |
| lsupdate.setDestinationIp(OspfUtil.ALL_SPF_ROUTERS); |
| } else if (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.DROTHER || |
| (((OspfInterfaceImpl) ospfInterface).state() == OspfInterfaceState.BDR)) { |
| lsupdate.setDestinationIp(neighborDr); |
| } |
| byte[] messageToWrite = getMessage(lsupdate); |
| channel.write(messageToWrite); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Builds the LsUpdate for flooding. |
| * |
| * @param txList list contains LSAs |
| * @return list of LsUpdate instances |
| */ |
| private List buildLsUpdate(Map<String, OspfLsa> txList) { |
| List<LsUpdate> lsUpdateList = new ArrayList<>(); |
| ListIterator itr = new ArrayList(txList.keySet()).listIterator(); |
| while (itr.hasNext()) { |
| LsUpdate lsupdate = new LsUpdate(); |
| // seting OSPF Header |
| lsupdate.setOspfVer(OspfUtil.OSPF_VERSION); |
| lsupdate.setOspftype(OspfPacketType.LSUPDATE.value()); |
| lsupdate.setRouterId(ospfArea.routerId()); |
| lsupdate.setAreaId(ospfArea.areaId()); |
| lsupdate.setAuthType(OspfUtil.NOT_ASSIGNED); |
| lsupdate.setAuthentication(OspfUtil.NOT_ASSIGNED); |
| lsupdate.setOspfPacLength(OspfUtil.NOT_ASSIGNED); // to calculate packet length |
| lsupdate.setChecksum(OspfUtil.NOT_ASSIGNED); |
| |
| //limit to mtu |
| int currentLength = OspfUtil.OSPF_HEADER_LENGTH + OspfUtil.FOUR_BYTES; |
| int maxSize = ospfInterface.mtu() - |
| OspfUtil.LSA_HEADER_LENGTH; // subtract a normal IP header. |
| |
| int noLsa = 0; |
| while (itr.hasNext()) { |
| |
| String key = (String) itr.next(); |
| OspfLsa lsa = txList.get(key); |
| if (lsa != null) { |
| if ((lsa.age() + OspfParameters.INFTRA_NS_DELAY) >= OspfParameters.MAXAGE) { |
| ((LsaHeader) lsa.lsaHeader()).setAge(OspfParameters.MAXAGE); |
| } else { |
| ((LsaHeader) lsa.lsaHeader()).setAge(lsa.age() + OspfParameters.INFTRA_NS_DELAY); |
| } |
| |
| if ((currentLength + ((LsaHeader) lsa.lsaHeader()).lsPacketLen()) >= maxSize) { |
| itr.previous(); |
| break; |
| } |
| log.debug("FloodingTimer::LSA Type::{}, Header: {}, LSA: {}", lsa.getOspfLsaType(), |
| lsa.lsaHeader(), lsa); |
| lsupdate.addLsa(lsa); |
| noLsa++; |
| currentLength = currentLength + ((LsaHeader) lsa.lsaHeader()).lsPacketLen(); |
| } |
| log.debug("FloodingTimer::Removing key {}", key); |
| if (txList.equals(reTxList)) { |
| reTxList.remove(key); |
| pendingReTxList.put(key, lsa); |
| } |
| } |
| //set number of lsa's |
| lsupdate.setNumberOfLsa(noLsa); |
| lsUpdateList.add(lsupdate); |
| } |
| return lsUpdateList; |
| } |
| } |
| } |