INET Framework for OMNeT++/OMNEST
OSPF::Router Class Reference

#include <OSPFRouter.h>

List of all members.

Public Member Functions

 Router (RouterID id, cSimpleModule *containingModule)
virtual ~Router (void)
void SetRouterID (RouterID id)
RouterID GetRouterID (void) const
void SetRFC1583Compatibility (bool compatibility)
bool GetRFC1583Compatibility (void) const
unsigned long GetAreaCount (void) const
MessageHandlerGetMessageHandler (void)
unsigned long GetASExternalLSACount (void) const
ASExternalLSAGetASExternalLSA (unsigned long i)
const ASExternalLSAGetASExternalLSA (unsigned long i) const
bool GetASBoundaryRouter (void) const
unsigned long GetRoutingTableEntryCount (void) const
RoutingTableEntryGetRoutingTableEntry (unsigned long i)
const RoutingTableEntryGetRoutingTableEntry (unsigned long i) const
void AddRoutingTableEntry (RoutingTableEntry *entry)
void AddWatches (void)
void AddArea (Area *area)
AreaGetArea (AreaID areaID)
AreaGetArea (IPv4Address address)
InterfaceGetNonVirtualInterface (unsigned char ifIndex)
bool InstallLSA (OSPFLSA *lsa, AreaID areaID=BackboneAreaID)
OSPFLSA * FindLSA (LSAType lsaType, LSAKeyType lsaKey, AreaID areaID)
void AgeDatabase (void)
bool HasAnyNeighborInStates (int states) const
void RemoveFromAllRetransmissionLists (LSAKeyType lsaKey)
bool IsOnAnyRetransmissionList (LSAKeyType lsaKey) const
bool FloodLSA (OSPFLSA *lsa, AreaID areaID=BackboneAreaID, Interface *intf=NULL, Neighbor *neighbor=NULL)
bool IsLocalAddress (IPv4Address address) const
bool HasAddressRange (IPv4AddressRange addressRange) const
bool IsDestinationUnreachable (OSPFLSA *lsa) const
RoutingTableEntryLookup (IPAddress destination, std::vector< RoutingTableEntry * > *table=NULL) const
void RebuildRoutingTable (void)
IPv4AddressRange GetContainingAddressRange (IPv4AddressRange addressRange, bool *advertise=NULL) const
void UpdateExternalRoute (IPv4Address networkAddress, const OSPFASExternalLSAContents &externalRouteContents, int ifIndex)
void RemoveExternalRoute (IPv4Address networkAddress)
RoutingTableEntryGetPreferredEntry (const OSPFLSA &lsa, bool skipSelfOriginated, std::vector< RoutingTableEntry * > *fromRoutingTable=NULL)

Private Member Functions

bool InstallASExternalLSA (OSPFASExternalLSA *lsa)
ASExternalLSAFindASExternalLSA (LSAKeyType lsaKey)
const ASExternalLSAFindASExternalLSA (LSAKeyType lsaKey) const
ASExternalLSAOriginateASExternalLSA (ASExternalLSA *lsa)
LinkStateID GetUniqueLinkStateID (IPv4AddressRange destination, Metric destinationCost, OSPF::ASExternalLSA *&lsaToReoriginate, bool externalMetricIsType2=false) const
void CalculateASExternalRoutes (std::vector< RoutingTableEntry * > &newRoutingTable)
void NotifyAboutRoutingTableChanges (std::vector< RoutingTableEntry * > &oldRoutingTable)
bool HasRouteToASBoundaryRouter (const std::vector< RoutingTableEntry * > &inRoutingTable, OSPF::RouterID routerID) const
std::vector< RoutingTableEntry * > GetRoutesToASBoundaryRouter (const std::vector< RoutingTableEntry * > &fromRoutingTable, OSPF::RouterID routerID) const
void PruneASBoundaryRouterEntries (std::vector< RoutingTableEntry * > &asbrEntries) const
RoutingTableEntrySelectLeastCostRoutingEntry (std::vector< RoutingTableEntry * > &entries) const

Private Attributes

RouterID routerID
 The router ID assigned by the IP layer.
std::map< AreaID, Area * > areasByID
 A map of the contained areas with the AreaID as key.
std::vector< Area * > areas
 A list of the contained areas.
std::map< LSAKeyType,
ASExternalLSA
*, LSAKeyType_Less
asExternalLSAsByID
 A map of the ASExternalLSAs advertised by this router.
std::vector< ASExternalLSA * > asExternalLSAs
 A list of the ASExternalLSAs advertised by this router.
std::map< IPv4Address,
OSPFASExternalLSAContents,
IPv4Address_Less
externalRoutes
 A map of the external route advertised by this router.
OSPFTimer * ageTimer
 Database age timer - fires every second.
std::vector< RoutingTableEntry * > routingTable
 The OSPF routing table - contains more information than the one in the IP layer.
MessageHandlermessageHandler
 The message dispatcher class.
bool rfc1583Compatibility
 Decides whether to handle the preferred routing table entry to an AS boundary router as defined in RFC1583 or not.

Detailed Description

Represents the full OSPF datastructure as laid out in RFC2328.


Constructor & Destructor Documentation

OSPF::Router::Router ( OSPF::RouterID  id,
cSimpleModule *  containingModule 
)

Constructor. Initializes internal variables, adds a MessageHandler and starts the Database Age timer.

                                                                   :
    routerID(id),
    rfc1583Compatibility(false)
{
    messageHandler = new OSPF::MessageHandler(this, containingModule);
    ageTimer = new OSPFTimer;
    ageTimer->setTimerKind(DatabaseAgeTimer);
    ageTimer->setContextPointer(this);
    ageTimer->setName("OSPF::Router::DatabaseAgeTimer");
    messageHandler->StartTimer(ageTimer, 1.0);
}
OSPF::Router::~Router ( void  ) [virtual]

Destructor. Clears all LSA lists and kills the Database Age timer.

{
    long areaCount = areas.size();
    for (long i = 0; i < areaCount; i++) {
        delete areas[i];
    }
    long lsaCount = asExternalLSAs.size();
    for (long j = 0; j < lsaCount; j++) {
        delete asExternalLSAs[j];
    }
    long routeCount = routingTable.size();
    for (long k = 0; k < routeCount; k++) {
        delete routingTable[k];
    }
    messageHandler->ClearTimer(ageTimer);
    delete ageTimer;
    delete messageHandler;
}

Member Function Documentation

void OSPF::Router::AddArea ( OSPF::Area area)

Adds a new Area to the Area list.

Parameters:
area[in] The Area to add.

Referenced by OSPFRouting::LoadAreaFromXML().

{

    area->SetRouter(this);
    areasByID[area->GetAreaID()] = area;
    areas.push_back(area);
}
void OSPF::Router::AddRoutingTableEntry ( RoutingTableEntry entry) [inline]
{ routingTable.push_back(entry); }
void OSPF::Router::AddWatches ( void  )

Adds OMNeT++ watches for the routerID, the list of Areas and the list of AS External LSAs.

Referenced by OSPFRouting::initialize().

{
    WATCH(routerID);
    WATCH_PTRVECTOR(areas);
    WATCH_PTRVECTOR(asExternalLSAs);
}
void OSPF::Router::AgeDatabase ( void  )

Ages the LSAs in the Router's database. This method is called on every firing of the DatabaseAgeTimer(every second).

See also:
RFC2328 Section 14.
{
    long lsaCount            = asExternalLSAs.size();
    bool rebuildRoutingTable = false;

    for (long i = 0; i < lsaCount; i++) {
        unsigned short       lsAge          = asExternalLSAs[i]->getHeader().getLsAge();
        bool                 selfOriginated = (asExternalLSAs[i]->getHeader().getAdvertisingRouter().getInt() == routerID);
        bool                 unreachable    = IsDestinationUnreachable(asExternalLSAs[i]);
        OSPF::ASExternalLSA* lsa            = asExternalLSAs[i];

        if ((selfOriginated && (lsAge < (LS_REFRESH_TIME - 1))) || (!selfOriginated && (lsAge < (MAX_AGE - 1)))) {
            lsa->getHeader().setLsAge(lsAge + 1);
            if ((lsAge + 1) % CHECK_AGE == 0) {
                if (!lsa->ValidateLSChecksum()) {
                    EV << "Invalid LS checksum. Memory error detected!\n";
                }
            }
            lsa->IncrementInstallTime();
        }
        if (selfOriginated && (lsAge == (LS_REFRESH_TIME - 1))) {
            if (unreachable) {
                lsa->getHeader().setLsAge(MAX_AGE);
                FloodLSA(lsa, OSPF::BackboneAreaID);
                lsa->IncrementInstallTime();
            } else {
                long sequenceNumber = lsa->getHeader().getLsSequenceNumber();
                if (sequenceNumber == MAX_SEQUENCE_NUMBER) {
                    lsa->getHeader().setLsAge(MAX_AGE);
                    FloodLSA(lsa, OSPF::BackboneAreaID);
                    lsa->IncrementInstallTime();
                } else {
                    OSPF::ASExternalLSA* newLSA = OriginateASExternalLSA(lsa);

                    newLSA->getHeader().setLsSequenceNumber(sequenceNumber + 1);
                    newLSA->getHeader().setLsChecksum(0);    // TODO: calculate correct LS checksum
                    rebuildRoutingTable |= lsa->Update(newLSA);
                    delete newLSA;

                    FloodLSA(lsa, OSPF::BackboneAreaID);
                }
            }
        }
        if (!selfOriginated && (lsAge == MAX_AGE - 1)) {
            lsa->getHeader().setLsAge(MAX_AGE);
            FloodLSA(lsa, OSPF::BackboneAreaID);
            lsa->IncrementInstallTime();
        }
        if (lsAge == MAX_AGE) {
            OSPF::LSAKeyType lsaKey;

            lsaKey.linkStateID       = lsa->getHeader().getLinkStateID();
            lsaKey.advertisingRouter = lsa->getHeader().getAdvertisingRouter().getInt();

            if (!IsOnAnyRetransmissionList(lsaKey) &&
                !HasAnyNeighborInStates(OSPF::Neighbor::ExchangeState | OSPF::Neighbor::LoadingState))
            {
                if (!selfOriginated || unreachable) {
                    asExternalLSAsByID.erase(lsaKey);
                    delete lsa;
                    asExternalLSAs[i] = NULL;
                    rebuildRoutingTable = true;
                } else {
                    if (lsa->GetPurgeable()) {
                        asExternalLSAsByID.erase(lsaKey);
                        delete lsa;
                        asExternalLSAs[i] = NULL;
                        rebuildRoutingTable = true;
                    } else {
                        OSPF::ASExternalLSA* newLSA              = OriginateASExternalLSA(lsa);
                        long                 sequenceNumber      = lsa->getHeader().getLsSequenceNumber();

                        newLSA->getHeader().setLsSequenceNumber((sequenceNumber == MAX_SEQUENCE_NUMBER) ? INITIAL_SEQUENCE_NUMBER : sequenceNumber + 1);
                        newLSA->getHeader().setLsChecksum(0);    // TODO: calculate correct LS checksum
                        rebuildRoutingTable |= lsa->Update(newLSA);
                        delete newLSA;

                        FloodLSA(lsa, OSPF::BackboneAreaID);
                    }
                }
            }
        }
    }

    std::vector<ASExternalLSA*>::iterator it = asExternalLSAs.begin();
    while (it != asExternalLSAs.end()) {
        if ((*it) == NULL) {
            it = asExternalLSAs.erase(it);
        } else {
            it++;
        }
    }

    long areaCount = areas.size();
    for (long j = 0; j < areaCount; j++) {
        areas[j]->AgeDatabase();
    }
    messageHandler->StartTimer(ageTimer, 1.0);

    if (rebuildRoutingTable) {
        RebuildRoutingTable();
    }
}
void OSPF::Router::CalculateASExternalRoutes ( std::vector< RoutingTableEntry * > &  newRoutingTable) [private]

Calculate the AS External Routes from the ASExternalLSAs in the database.

Parameters:
newRoutingTable[in/out] Push the new RoutingTableEntries into this routing table, and also use this for path calculations.
See also:
RFC2328 Section 16.4.
{
    unsigned long lsaCount = asExternalLSAs.size();
    unsigned long i;

    for (i = 0; i < lsaCount; i++) {
        OSPF::ASExternalLSA* currentLSA        = asExternalLSAs[i];
        OSPFLSAHeader&       currentHeader     = currentLSA->getHeader();
        unsigned short       externalCost      = currentLSA->getContents().getRouteCost();
        OSPF::RouterID       originatingRouter = currentHeader.getAdvertisingRouter().getInt();

        OSPF::RoutingTableEntry* preferredEntry = GetPreferredEntry(*currentLSA, true, &newRoutingTable);
        if (preferredEntry == NULL) {
            continue;
        }

        IPAddress destination = currentHeader.getLinkStateID() & currentLSA->getContents().getNetworkMask().getInt();

        Metric                   preferredCost    = preferredEntry->GetCost();
        OSPF::RoutingTableEntry* destinationEntry = Lookup(destination, &newRoutingTable);   // (5)
        if (destinationEntry == NULL) {
            bool                     type2ExternalMetric = currentLSA->getContents().getE_ExternalMetricType();
            unsigned int             nextHopCount        = preferredEntry->GetNextHopCount();
            OSPF::RoutingTableEntry* newEntry            = new OSPF::RoutingTableEntry;

            newEntry->SetDestinationID(destination);
            newEntry->SetAddressMask(currentLSA->getContents().getNetworkMask().getInt());
            newEntry->SetArea(preferredEntry->GetArea());
            newEntry->SetPathType(type2ExternalMetric ? OSPF::RoutingTableEntry::Type2External : OSPF::RoutingTableEntry::Type1External);
            if (type2ExternalMetric) {
                newEntry->SetCost(preferredCost);
                newEntry->SetType2Cost(externalCost);
            } else {
                newEntry->SetCost(preferredCost + externalCost);
            }
            newEntry->SetDestinationType(OSPF::RoutingTableEntry::NetworkDestination);
            newEntry->SetOptionalCapabilities(currentHeader.getLsOptions());
            newEntry->SetLinkStateOrigin(currentLSA);

            for (unsigned int j = 0; j < nextHopCount; j++) {
                NextHop nextHop = preferredEntry->GetNextHop(j);

                nextHop.advertisingRouter = originatingRouter;
                newEntry->AddNextHop(nextHop);
            }

            newRoutingTable.push_back(newEntry);
        } else {
            OSPF::RoutingTableEntry::RoutingPathType destinationPathType = destinationEntry->GetPathType();
            bool                                     type2ExternalMetric = currentLSA->getContents().getE_ExternalMetricType();
            unsigned int                             nextHopCount        = preferredEntry->GetNextHopCount();

            if ((destinationPathType == OSPF::RoutingTableEntry::IntraArea) ||
                (destinationPathType == OSPF::RoutingTableEntry::InterArea))   // (6) (a)
            {
                continue;
            }

            if (((destinationPathType == OSPF::RoutingTableEntry::Type1External) &&
                 (type2ExternalMetric)) ||
                ((destinationPathType == OSPF::RoutingTableEntry::Type2External) &&
                 (type2ExternalMetric) &&
                 (destinationEntry->GetType2Cost() < externalCost))) // (6) (b)
            {
                continue;
            }

            OSPF::RoutingTableEntry* destinationPreferredEntry = GetPreferredEntry(*(destinationEntry->GetLinkStateOrigin()), false, &newRoutingTable);
            if ((!rfc1583Compatibility) &&
                (destinationPreferredEntry->GetPathType() == OSPF::RoutingTableEntry::IntraArea) &&
                (destinationPreferredEntry->GetArea() != OSPF::BackboneAreaID) &&
                ((preferredEntry->GetPathType() != OSPF::RoutingTableEntry::IntraArea) ||
                 (preferredEntry->GetArea() == OSPF::BackboneAreaID)))
            {
                continue;
            }

            if ((((destinationPathType == OSPF::RoutingTableEntry::Type1External) &&
                  (!type2ExternalMetric) &&
                  (destinationEntry->GetCost() < preferredCost + externalCost))) ||
                ((destinationPathType == OSPF::RoutingTableEntry::Type2External) &&
                 (type2ExternalMetric) &&
                 (destinationEntry->GetType2Cost() == externalCost) &&
                 (destinationPreferredEntry->GetCost() < preferredCost)))
            {
                continue;
            }

            if (((destinationPathType == OSPF::RoutingTableEntry::Type1External) &&
                 (!type2ExternalMetric) &&
                 (destinationEntry->GetCost() == (preferredCost + externalCost))) ||
                ((destinationPathType == OSPF::RoutingTableEntry::Type2External) &&
                 (type2ExternalMetric) &&
                 (destinationEntry->GetType2Cost() == externalCost) &&
                 (destinationPreferredEntry->GetCost() == preferredCost)))   // equal cost
            {
                for (unsigned int j = 0; j < nextHopCount; j++) {
                    // TODO: merge next hops, not add
                    NextHop nextHop = preferredEntry->GetNextHop(j);

                    nextHop.advertisingRouter = originatingRouter;
                    destinationEntry->AddNextHop(nextHop);
                }
                continue;
            }

            // LSA is better
            destinationEntry->SetArea(preferredEntry->GetArea());
            destinationEntry->SetPathType(type2ExternalMetric ? OSPF::RoutingTableEntry::Type2External : OSPF::RoutingTableEntry::Type1External);
            if (type2ExternalMetric) {
                destinationEntry->SetCost(preferredCost);
                destinationEntry->SetType2Cost(externalCost);
            } else {
                destinationEntry->SetCost(preferredCost + externalCost);
            }
            destinationEntry->SetDestinationType(OSPF::RoutingTableEntry::NetworkDestination);
            destinationEntry->SetOptionalCapabilities(currentHeader.getLsOptions());
            destinationEntry->ClearNextHops();

            for (unsigned int j = 0; j < nextHopCount; j++) {
                NextHop nextHop = preferredEntry->GetNextHop(j);

                nextHop.advertisingRouter = originatingRouter;
                destinationEntry->AddNextHop(nextHop);
            }
        }
    }
}
OSPF::ASExternalLSA * OSPF::Router::FindASExternalLSA ( OSPF::LSAKeyType  lsaKey) [private]

Find the AS External LSA identified by the input lsaKey in the database.

Parameters:
lsaKey[in] Look for the AS External LSA which is identified by this key.
Returns:
The pointer to the AS External LSA if it was found, NULL otherwise.
{
    std::map<OSPF::LSAKeyType, OSPF::ASExternalLSA*, OSPF::LSAKeyType_Less>::iterator lsaIt = asExternalLSAsByID.find(lsaKey);
    if (lsaIt != asExternalLSAsByID.end()) {
        return lsaIt->second;
    } else {
        return NULL;
    }
}
const OSPF::ASExternalLSA * OSPF::Router::FindASExternalLSA ( OSPF::LSAKeyType  lsaKey) const [private]

Find the AS External LSA identified by the input lsaKey in the database.

Parameters:
lsaKey[in] Look for the AS External LSA which is identified by this key.
Returns:
The const pointer to the AS External LSA if it was found, NULL otherwise.
{
    std::map<OSPF::LSAKeyType, OSPF::ASExternalLSA*, OSPF::LSAKeyType_Less>::const_iterator lsaIt = asExternalLSAsByID.find(lsaKey);
    if (lsaIt != asExternalLSAsByID.end()) {
        return lsaIt->second;
    } else {
        return NULL;
    }
}
OSPFLSA * OSPF::Router::FindLSA ( LSAType  lsaType,
OSPF::LSAKeyType  lsaKey,
OSPF::AreaID  areaID 
)

Find the LSA identified by the input lsaKey in the database.

Parameters:
lsaType[in] Look for an LSA of this type.
lsaKey[in] Look for the LSA which is identified by this key.
areaID[in] In case of Router, Network and Summary LSAs, look in the Area's database identified by this parameter.
Returns:
The pointer to the LSA if it was found, NULL otherwise.
{
    switch (lsaType) {
        case RouterLSAType:
            {
                std::map<OSPF::AreaID, OSPF::Area*>::iterator areaIt = areasByID.find(areaID);
                if (areaIt != areasByID.end()) {
                    return areaIt->second->FindRouterLSA(lsaKey.linkStateID);
                }
            }
            break;
        case NetworkLSAType:
            {
                std::map<OSPF::AreaID, OSPF::Area*>::iterator areaIt = areasByID.find(areaID);
                if (areaIt != areasByID.end()) {
                    return areaIt->second->FindNetworkLSA(lsaKey.linkStateID);
                }
            }
            break;
        case SummaryLSA_NetworksType:
        case SummaryLSA_ASBoundaryRoutersType:
            {
                std::map<OSPF::AreaID, OSPF::Area*>::iterator areaIt = areasByID.find(areaID);
                if (areaIt != areasByID.end()) {
                    return areaIt->second->FindSummaryLSA(lsaKey);
                }
            }
            break;
        case ASExternalLSAType:
            {
                return FindASExternalLSA(lsaKey);
            }
            break;
        default:
            ASSERT(false);
            break;
    }
    return NULL;
}
bool OSPF::Router::FloodLSA ( OSPFLSA *  lsa,
OSPF::AreaID  areaID = BackboneAreaID,
OSPF::Interface intf = NULL,
OSPF::Neighbor neighbor = NULL 
)

Floods out the input lsa on a set of Interfaces.

See also:
RFC2328 Section 13.3.
Parameters:
lsa[in] The LSA to be flooded out.
areaID[in] If the lsa is a Router, Network or Summary LSA, then flood it only in this Area.
intf[in] The Interface this LSA arrived on.
neighbor[in] The Nieghbor this LSA arrived from.
Returns:
True if the LSA was floooded back out on the receiving Interface, false otherwise.
{
    bool floodedBackOut = false;

    if (lsa != NULL) {
        if (lsa->getHeader().getLsType() == ASExternalLSAType) {
            long areaCount = areas.size();
            for (long i = 0; i < areaCount; i++) {
                if (areas[i]->GetExternalRoutingCapability()) {
                    if (areas[i]->FloodLSA(lsa, intf, neighbor)) {
                        floodedBackOut = true;
                    }
                }
            }
        } else {
            std::map<OSPF::AreaID, OSPF::Area*>::iterator areaIt = areasByID.find(areaID);
            if (areaIt != areasByID.end()) {
                floodedBackOut = areaIt->second->FloodLSA(lsa, intf, neighbor);
            }
        }
    }

    return floodedBackOut;
}
OSPF::Area * OSPF::Router::GetArea ( OSPF::IPv4Address  address)

Returns the Area pointer from the Area list which contains the input IP address, NULL if there's no such area connected to the Router.

Parameters:
address[in] The IP address whose containing Area we're looking for.
{
    long areaCount = areas.size();
    for (long i = 0; i < areaCount; i++) {
        if (areas[i]->ContainsAddress(address)) {
            return areas[i];
        }
    }
    return NULL;
}
OSPF::Area * OSPF::Router::GetArea ( OSPF::AreaID  areaID)

Returns the pointer to the Area identified by the input areaID, if it's on the Area list, NULL otherwise.

Parameters:
areaID[in] The Area identifier.

Referenced by OSPFRouting::LoadHostRoute(), OSPFRouting::LoadInterfaceParameters(), and OSPFRouting::LoadVirtualLink().

{
    std::map<OSPF::AreaID, OSPF::Area*>::iterator areaIt = areasByID.find(areaID);
    if (areaIt != areasByID.end()) {
        return (areaIt->second);
    }
    else {
        return NULL;
    }
}
unsigned long OSPF::Router::GetAreaCount ( void  ) const [inline]
{ return areas.size(); }
bool OSPF::Router::GetASBoundaryRouter ( void  ) const [inline]
{ return (externalRoutes.size() > 0); }
const ASExternalLSA* OSPF::Router::GetASExternalLSA ( unsigned long  i) const [inline]
{ return asExternalLSAs[i]; }
ASExternalLSA* OSPF::Router::GetASExternalLSA ( unsigned long  i) [inline]
unsigned long OSPF::Router::GetASExternalLSACount ( void  ) const [inline]

Referenced by OSPF::Neighbor::CreateDatabaseSummary().

{ return asExternalLSAs.size(); }
OSPF::IPv4AddressRange OSPF::Router::GetContainingAddressRange ( OSPF::IPv4AddressRange  addressRange,
bool *  advertise = NULL 
) const

Scans through the router's areas' preconfigured address ranges and returns the one containing the input addressRange.

Parameters:
addressRange[in] The address range to look for.
advertise[out] Whether the advertise flag is set in the returned preconfigured address range.
Returns:
The containing preconfigured address range if found, OSPF::NullIPv4AddressRange otherwise.
{
    unsigned long areaCount = areas.size();
    for (unsigned long i = 0; i < areaCount; i++) {
        OSPF::IPv4AddressRange containingAddressRange = areas[i]->GetContainingAddressRange(addressRange, advertise);
        if (containingAddressRange != OSPF::NullIPv4AddressRange) {
            return containingAddressRange;
        }
    }
    if (advertise != NULL) {
        *advertise = false;
    }
    return OSPF::NullIPv4AddressRange;
}
OSPF::Interface * OSPF::Router::GetNonVirtualInterface ( unsigned char  ifIndex)

Returns the pointer of the physical Interface identified by the input interface index, NULL if the Router doesn't have such an interface.

Parameters:
ifIndex[in] The interface index to look for.
{
    long areaCount = areas.size();
    for (long i = 0; i < areaCount; i++) {
        OSPF::Interface* intf = areas[i]->GetInterface(ifIndex);
        if (intf != NULL) {
            return intf;
        }
    }
    return NULL;
}
OSPF::RoutingTableEntry * OSPF::Router::GetPreferredEntry ( const OSPFLSA &  lsa,
bool  skipSelfOriginated,
std::vector< RoutingTableEntry * > *  fromRoutingTable = NULL 
)

Selects the preferred routing table entry for the input LSA(which is either an ASExternalLSA or a SummaryLSA) according to the algorithm defined in RFC2328 Section 16.4. points(1) through(3). This method is used when calculating the AS external routes and also when originating an SummaryLSA for an AS Boundary Router.

Parameters:
lsa[in] The LSA describing the destination for which the preferred Routing Entry is sought for.
skipSelfOriginated[in] Whether to disregard this LSA if it was self-originated.
fromRoutingTable[in] The Routing Table from which to select the preferred RoutingTableEntry. If it is NULL then the router's current routing table is used instead.
Returns:
The preferred RoutingTableEntry, or NULL if no such entry exists.
See also:
RFC2328 Section 16.4. points(1) through(3)
OSPF::Area::OriginateSummaryLSA
{
    if (fromRoutingTable == NULL) {
        fromRoutingTable = &routingTable;
    }

    const OSPFLSAHeader&     lsaHeader         = lsa.getHeader();
    const OSPFASExternalLSA* asExternalLSA     = dynamic_cast<const OSPFASExternalLSA*> (&lsa);
    unsigned long            externalCost      = (asExternalLSA != NULL) ? asExternalLSA->getContents().getRouteCost() : 0;
    unsigned short           lsAge             = lsaHeader.getLsAge();
    OSPF::RouterID           originatingRouter = lsaHeader.getAdvertisingRouter().getInt();
    bool                     selfOriginated    = (originatingRouter == routerID);
    IPAddress                forwardingAddress; // 0.0.0.0

    if (asExternalLSA != NULL) {
        forwardingAddress = asExternalLSA->getContents().getForwardingAddress();
    }

    if ((externalCost == LS_INFINITY) || (lsAge == MAX_AGE) || (skipSelfOriginated && selfOriginated)) { // (1) and(2)
        return NULL;
    }

    if (!HasRouteToASBoundaryRouter(*fromRoutingTable, originatingRouter)) { // (3)
        return NULL;
    }

    if (forwardingAddress.isUnspecified()) {   // (3)
        std::vector<OSPF::RoutingTableEntry*> asbrEntries = GetRoutesToASBoundaryRouter(*fromRoutingTable, originatingRouter);
        if (!rfc1583Compatibility) {
            PruneASBoundaryRouterEntries(asbrEntries);
        }
        return SelectLeastCostRoutingEntry(asbrEntries);
    } else {
        OSPF::RoutingTableEntry* forwardEntry = Lookup(forwardingAddress, fromRoutingTable);

        if (forwardEntry == NULL) {
            return NULL;
        }

        if ((forwardEntry->GetPathType() != OSPF::RoutingTableEntry::IntraArea) &&
            (forwardEntry->GetPathType() != OSPF::RoutingTableEntry::InterArea))
        {
            return NULL;
        }

        return forwardEntry;
    }

    return NULL;
}
bool OSPF::Router::GetRFC1583Compatibility ( void  ) const [inline]
std::vector< OSPF::RoutingTableEntry * > OSPF::Router::GetRoutesToASBoundaryRouter ( const std::vector< RoutingTableEntry * > &  fromRoutingTable,
OSPF::RouterID  routerID 
) const [private]

Returns an std::vector of routes leading to the AS Boundary Router identified by asbrRouterID from the input fromRoutingTable. If there are no routes leading to the AS Boundary Router, the returned std::vector is empty.

Parameters:
fromRoutingTable[in] The routing table to look in.
asbrRouterID[in] The ID of the AS Boundary Router to look for.
{
    std::vector<OSPF::RoutingTableEntry*> results;
    long                                  routeCount = fromRoutingTable.size();

    for (long i = 0; i < routeCount; i++) {
        OSPF::RoutingTableEntry* routingEntry = fromRoutingTable[i];
        if (((routingEntry->GetDestinationType() & OSPF::RoutingTableEntry::ASBoundaryRouterDestination) != 0) &&
            (routingEntry->GetDestinationID().getInt() == asbrRouterID))
        {
            results.push_back(routingEntry);
        }
    }
    return results;
}
RoutingTableEntry* OSPF::Router::GetRoutingTableEntry ( unsigned long  i) [inline]
{ return routingTable[i]; }
const RoutingTableEntry* OSPF::Router::GetRoutingTableEntry ( unsigned long  i) const [inline]
{ return routingTable[i]; }
unsigned long OSPF::Router::GetRoutingTableEntryCount ( void  ) const [inline]
{ return routingTable.size(); }
OSPF::LinkStateID OSPF::Router::GetUniqueLinkStateID ( OSPF::IPv4AddressRange  destination,
OSPF::Metric  destinationCost,
OSPF::ASExternalLSA *&  lsaToReoriginate,
bool  externalMetricIsType2 = false 
) const [private]

Generates a unique LinkStateID for a given destination. This may require the reorigination of an LSA already in the database(with a different LinkStateID).

Parameters:
destination[in] The destination for which a unique LinkStateID is required.
destinationCost[in] The path cost to the destination.
lsaToReoriginate[out] The LSA to reoriginate(which was already in the database, and had to be changed).
externalMetricIsType2[in] True if the destinationCost is given as a Type2 external metric.
Returns:
the LinkStateID for the destination.
See also:
RFC2328 Appendix E.
OSPF::Area::GetUniqueLinkStateID
{
    if (lsaToReoriginate != NULL) {
        delete lsaToReoriginate;
        lsaToReoriginate = NULL;
    }

    OSPF::LSAKeyType lsaKey;

    lsaKey.linkStateID = ULongFromIPv4Address(destination.address);
    lsaKey.advertisingRouter = routerID;

    const OSPF::ASExternalLSA* foundLSA = FindASExternalLSA(lsaKey);

    if (foundLSA == NULL) {
        return lsaKey.linkStateID;
    } else {
        OSPF::IPv4Address existingMask = IPv4AddressFromULong(foundLSA->getContents().getNetworkMask().getInt());

        if (destination.mask >= existingMask) {
            return (lsaKey.linkStateID | (~(ULongFromIPv4Address(destination.mask))));
        } else {
            OSPF::ASExternalLSA* asExternalLSA = new OSPF::ASExternalLSA(*foundLSA);

            long sequenceNumber = asExternalLSA->getHeader().getLsSequenceNumber();

            asExternalLSA->getHeader().setLsAge(0);
            asExternalLSA->getHeader().setLsSequenceNumber((sequenceNumber == MAX_SEQUENCE_NUMBER) ? INITIAL_SEQUENCE_NUMBER : sequenceNumber + 1);
            asExternalLSA->getContents().setNetworkMask(ULongFromIPv4Address(destination.mask));
            asExternalLSA->getContents().setE_ExternalMetricType(externalMetricIsType2);
            asExternalLSA->getContents().setRouteCost(destinationCost);
            asExternalLSA->getHeader().setLsChecksum(0);    // TODO: calculate correct LS checksum

            lsaToReoriginate = asExternalLSA;

            return (lsaKey.linkStateID | (~(ULongFromIPv4Address(existingMask))));
        }
    }
}
bool OSPF::Router::HasAddressRange ( OSPF::IPv4AddressRange  addressRange) const

Returns true if one of the Router's Areas the same IP address range configured as the input IP address range, false otherwise.

Parameters:
addressRange[in] The IP address range to look for.
{
    long areaCount = areas.size();
    for (long i = 0; i < areaCount; i++) {
        if (areas[i]->HasAddressRange(addressRange)) {
            return true;
        }
    }
    return false;
}
bool OSPF::Router::HasAnyNeighborInStates ( int  states) const

Returns true if any Neighbor on any Interface in any of the Router's Areas is in any of the input states, false otherwise.

Parameters:
states[in] A bitfield combination of NeighborStateType values.
{
    long areaCount = areas.size();
    for (long i = 0; i < areaCount; i++) {
        if (areas[i]->HasAnyNeighborInStates(states)) {
            return true;
        }
    }
    return false;
}
bool OSPF::Router::HasRouteToASBoundaryRouter ( const std::vector< RoutingTableEntry * > &  inRoutingTable,
OSPF::RouterID  routerID 
) const [private]

Returns true if there is a route to the AS Boundary Router identified by asbrRouterID in the input inRoutingTable, false otherwise.

Parameters:
inRoutingTable[in] The routing table to look in.
asbrRouterID[in] The ID of the AS Boundary Router to look for.
{
    long routeCount = inRoutingTable.size();
    for (long i = 0; i < routeCount; i++) {
        OSPF::RoutingTableEntry* routingEntry = inRoutingTable[i];
        if (((routingEntry->GetDestinationType() & OSPF::RoutingTableEntry::ASBoundaryRouterDestination) != 0) &&
            (routingEntry->GetDestinationID().getInt() == asbrRouterID))
        {
            return true;
        }
    }
    return false;
}
bool OSPF::Router::InstallASExternalLSA ( OSPFASExternalLSA *  lsa) [private]

Installs a new AS External LSA into the Router's database. It tries to install keep one of multiple functionally equivalent AS External LSAs in the database. (See the comment in the method implementation.)

Parameters:
lsa[in] The LSA to install. It will be copied into the database.
Returns:
True if the routing table needs to be updated, false otherwise.

From RFC2328 Section 12.4.4.1.: "If two routers, both reachable from one another, originate functionally equivalent AS-External-LSAs(i.e., same destination, cost and non-zero forwarding address), then the LSA originated by the router having the highest OSPF Router ID is used. The router having the lower OSPF Router ID can then flush its LSA." The problem is: how do we tell whether two routers are reachable from one another based on a Link State Update packet? 0. We can assume that if this LSA reached this router, then this router is reachable from the other router. But what about the other direction? 1. The update packet is most likely not sent by the router originating the functionally equivalent AS-External-LSA, so we cannot use the IP packet source address. 2. The AS-External-LSA contains only the Router ID of the advertising router, so we can only look up "router" type routing entries in the routing table(these contain the Router ID as their Destination ID). However these entries are only inserted into the routing table for intra-area routers...

{
     // TODO: how to solve this problem?

    OSPF::RouterID advertisingRouter = lsa->getHeader().getAdvertisingRouter().getInt();
    bool           reachable         = false;
    unsigned int   routeCount        = routingTable.size();

    for (unsigned int i = 0; i < routeCount; i++) {
        if ((((routingTable[i]->GetDestinationType() & OSPF::RoutingTableEntry::AreaBorderRouterDestination) != 0) ||
             ((routingTable[i]->GetDestinationType() & OSPF::RoutingTableEntry::ASBoundaryRouterDestination) != 0)) &&
            (routingTable[i]->GetDestinationID().getInt() == advertisingRouter))
        {
            reachable = true;
            break;
        }
    }

    bool             ownLSAFloodedOut = false;
    OSPF::LSAKeyType lsaKey;

    lsaKey.linkStateID = lsa->getHeader().getLinkStateID();
    lsaKey.advertisingRouter = routerID;

    std::map<OSPF::LSAKeyType, OSPF::ASExternalLSA*, OSPF::LSAKeyType_Less>::iterator lsaIt = asExternalLSAsByID.find(lsaKey);
    if ((lsaIt != asExternalLSAsByID.end()) &&
        reachable &&
        (lsaIt->second->getContents().getE_ExternalMetricType() == lsa->getContents().getE_ExternalMetricType()) &&
        (lsaIt->second->getContents().getRouteCost() == lsa->getContents().getRouteCost()) &&
        (lsa->getContents().getForwardingAddress().getInt() != 0) &&   // forwarding address != 0.0.0.0
        (lsaIt->second->getContents().getForwardingAddress() == lsa->getContents().getForwardingAddress()))
    {
        if (routerID > advertisingRouter) {
            return false;
        } else {
            lsaIt->second->getHeader().setLsAge(MAX_AGE);
            FloodLSA(lsaIt->second, OSPF::BackboneAreaID);
            lsaIt->second->IncrementInstallTime();
            ownLSAFloodedOut = true;
        }
    }

    lsaKey.advertisingRouter = advertisingRouter;

    lsaIt = asExternalLSAsByID.find(lsaKey);
    if (lsaIt != asExternalLSAsByID.end()) {
        unsigned long areaCount = areas.size();
        for (unsigned long i = 0; i < areaCount; i++) {
            areas[i]->RemoveFromAllRetransmissionLists(lsaKey);
        }
        return ((lsaIt->second->Update(lsa)) | ownLSAFloodedOut);
    } else {
        OSPF::ASExternalLSA* lsaCopy = new OSPF::ASExternalLSA(*lsa);
        asExternalLSAsByID[lsaKey] = lsaCopy;
        asExternalLSAs.push_back(lsaCopy);
        return true;
    }
}
bool OSPF::Router::InstallLSA ( OSPFLSA *  lsa,
OSPF::AreaID  areaID = BackboneAreaID 
)

Installs a new LSA into the Router database. Checks the input LSA's type and installs it into either the selected Area's database, or if it's an AS External LSA then into the Router's common asExternalLSAs list.

Parameters:
lsa[in] The LSA to install. It will be copied into the database.
areaID[in] Identifies the input Router, Network and Summary LSA's Area.
Returns:
True if the routing table needs to be updated, false otherwise.
{
    switch (lsa->getHeader().getLsType()) {
        case RouterLSAType:
            {
                std::map<OSPF::AreaID, OSPF::Area*>::iterator areaIt = areasByID.find(areaID);
                if (areaIt != areasByID.end()) {
                    OSPFRouterLSA* ospfRouterLSA = check_and_cast<OSPFRouterLSA*> (lsa);
                    return areaIt->second->InstallRouterLSA(ospfRouterLSA);
                }
            }
            break;
        case NetworkLSAType:
            {
                std::map<OSPF::AreaID, OSPF::Area*>::iterator areaIt = areasByID.find(areaID);
                if (areaIt != areasByID.end()) {
                    OSPFNetworkLSA* ospfNetworkLSA = check_and_cast<OSPFNetworkLSA*> (lsa);
                    return areaIt->second->InstallNetworkLSA(ospfNetworkLSA);
                }
            }
            break;
        case SummaryLSA_NetworksType:
        case SummaryLSA_ASBoundaryRoutersType:
            {
                std::map<OSPF::AreaID, OSPF::Area*>::iterator areaIt = areasByID.find(areaID);
                if (areaIt != areasByID.end()) {
                    OSPFSummaryLSA* ospfSummaryLSA = check_and_cast<OSPFSummaryLSA*> (lsa);
                    return areaIt->second->InstallSummaryLSA(ospfSummaryLSA);
                }
            }
            break;
        case ASExternalLSAType:
            {
                OSPFASExternalLSA* ospfASExternalLSA = check_and_cast<OSPFASExternalLSA*> (lsa);
                return InstallASExternalLSA(ospfASExternalLSA);
            }
            break;
        default:
            ASSERT(false);
            break;
    }
    return false;
}
bool OSPF::Router::IsDestinationUnreachable ( OSPFLSA *  lsa) const

Returns true if the destination described by the input lsa is in the routing table, false otherwise.

Parameters:
lsa[in] The LSA which describes the destination to look for.
{
    IPAddress destination = lsa->getHeader().getLinkStateID();

    OSPFRouterLSA* routerLSA         = dynamic_cast<OSPFRouterLSA*> (lsa);
    OSPFNetworkLSA* networkLSA       = dynamic_cast<OSPFNetworkLSA*> (lsa);
    OSPFSummaryLSA* summaryLSA       = dynamic_cast<OSPFSummaryLSA*> (lsa);
    OSPFASExternalLSA* asExternalLSA = dynamic_cast<OSPFASExternalLSA*> (lsa);
    // TODO: verify
    if (routerLSA != NULL) {
        OSPF::RoutingInfo* routingInfo = check_and_cast<OSPF::RoutingInfo*> (routerLSA);
        if (routerLSA->getHeader().getLinkStateID() == routerID) { // this is spfTreeRoot
            return false;
        }

        // get the interface address pointing backwards on the shortest path tree
        unsigned int     linkCount   = routerLSA->getLinksArraySize();
        OSPF::RouterLSA* toRouterLSA = dynamic_cast<OSPF::RouterLSA*> (routingInfo->GetParent());
        if (toRouterLSA != NULL) {
            bool      destinationFound           = false;
            bool      unnumberedPointToPointLink = false;
            IPAddress firstNumberedIfAddress;

            for (unsigned int i = 0; i < linkCount; i++) {
                Link& link = routerLSA->getLinks(i);

                if (link.getType() == PointToPointLink) {
                    if (link.getLinkID() == toRouterLSA->getHeader().getLinkStateID()) {
                        if ((link.getLinkData() & 0xFF000000) == 0) {
                            unnumberedPointToPointLink = true;
                            if (!firstNumberedIfAddress.isUnspecified()) {
                                break;
                            }
                        } else {
                            destination = link.getLinkData();
                            destinationFound = true;
                            break;
                        }
                    } else {
                        if (((link.getLinkData() & 0xFF000000) != 0) &&
                             firstNumberedIfAddress.isUnspecified())
                        {
                            firstNumberedIfAddress = link.getLinkData();
                        }
                    }
                } else if (link.getType() == TransitLink) {
                    if (firstNumberedIfAddress.isUnspecified()) {
                        firstNumberedIfAddress = link.getLinkData();
                    }
                } else if (link.getType() == VirtualLink) {
                    if (link.getLinkID() == toRouterLSA->getHeader().getLinkStateID()) {
                        destination = link.getLinkData();
                        destinationFound = true;
                        break;
                    } else {
                        if (firstNumberedIfAddress.isUnspecified()) {
                            firstNumberedIfAddress = link.getLinkData();
                        }
                    }
                }
                // There's no way to get an interface address for the router from a StubLink
            }
            if (unnumberedPointToPointLink) {
                if (!firstNumberedIfAddress.isUnspecified()) {
                    destination = firstNumberedIfAddress;
                } else {
                    return true;
                }
            }
            if (!destinationFound) {
                return true;
            }
        } else {
            OSPF::NetworkLSA* toNetworkLSA = dynamic_cast<OSPF::NetworkLSA*> (routingInfo->GetParent());
            if (toNetworkLSA != NULL) {
                // get the interface address pointing backwards on the shortest path tree
                bool destinationFound = false;
                for (unsigned int i = 0; i < linkCount; i++) {
                    Link& link = routerLSA->getLinks(i);

                    if ((link.getType() == TransitLink) &&
                        (link.getLinkID() == toNetworkLSA->getHeader().getLinkStateID()))
                    {
                        destination = link.getLinkData();
                        destinationFound = true;
                        break;
                    }
                }
                if (!destinationFound) {
                    return true;
                }
            } else {
                return true;
            }
        }
    }
    if (networkLSA != NULL) {
        destination = networkLSA->getHeader().getLinkStateID() & networkLSA->getNetworkMask().getInt();
    }
    if ((summaryLSA != NULL) && (summaryLSA->getHeader().getLsType() == SummaryLSA_NetworksType)) {
        destination = summaryLSA->getHeader().getLinkStateID() & summaryLSA->getNetworkMask().getInt();
    }
    if (asExternalLSA != NULL) {
        destination = asExternalLSA->getHeader().getLinkStateID() & asExternalLSA->getContents().getNetworkMask().getInt();
    }

    if (Lookup(destination) == NULL) {
        return true;
    } else {
        return false;
    }
}
bool OSPF::Router::IsLocalAddress ( OSPF::IPv4Address  address) const

Returns true if the input IP address falls into any of the Router's Areas' configured IP address ranges, false otherwise.

Parameters:
address[in] The IP address to look for.
{
    long areaCount = areas.size();
    for (long i = 0; i < areaCount; i++) {
        if (areas[i]->IsLocalAddress(address)) {
            return true;
        }
    }
    return false;
}
bool OSPF::Router::IsOnAnyRetransmissionList ( OSPF::LSAKeyType  lsaKey) const

Returns true if there's at least one LSA on any Neighbor's retransmission list identified by the input lsaKey, false otherwise.

Parameters:
lsaKey[in] Identifies the LSAs to look for on the retransmission lists.
{
    long areaCount = areas.size();
    for (long i = 0; i < areaCount; i++) {
        if (areas[i]->IsOnAnyRetransmissionList(lsaKey)) {
            return true;
        }
    }
    return false;
}
OSPF::RoutingTableEntry * OSPF::Router::Lookup ( IPAddress  destination,
std::vector< RoutingTableEntry * > *  table = NULL 
) const

Do a lookup in either the input OSPF routing table, or if it's NULL then in the Router's own routing table.

See also:
RFC2328 Section 11.1.
Parameters:
destination[in] The destination to look up in the routing table.
table[in] The routing table to do the lookup in.
Returns:
The RoutingTableEntry describing the input destination if there's one, false otherwise.
{
    const std::vector<OSPF::RoutingTableEntry*>& rTable           = (table == NULL) ? routingTable : (*table);
    unsigned long                                dest             = destination.getInt();
    unsigned long                                routingTableSize = rTable.size();
    bool                                         unreachable      = false;
    std::vector<OSPF::RoutingTableEntry*>        discard;
    unsigned long                                i;

    unsigned long areaCount = areas.size();
    for (i = 0; i < areaCount; i++) {
        unsigned int addressRangeCount = areas[i]->GetAddressRangeCount();
        for (unsigned int j = 0; j < addressRangeCount; j++) {
            OSPF::IPv4AddressRange range = areas[i]->GetAddressRange(j);

            for (unsigned int k = 0; k < routingTableSize; k++) {
                OSPF::RoutingTableEntry* entry = rTable[k];

                if (entry->GetDestinationType() != OSPF::RoutingTableEntry::NetworkDestination) {
                    continue;
                }
                if (((entry->GetDestinationID().getInt() & entry->GetAddressMask().getInt() & ULongFromIPv4Address(range.mask)) == ULongFromIPv4Address(range.address & range.mask)) &&
                    (entry->GetPathType() == OSPF::RoutingTableEntry::IntraArea))
                {
                    // active area address range
                    OSPF::RoutingTableEntry* discardEntry = new OSPF::RoutingTableEntry;
                    discardEntry->SetDestinationID(ULongFromIPv4Address(range.address));
                    discardEntry->SetAddressMask(ULongFromIPv4Address(range.mask));
                    discardEntry->SetDestinationType(OSPF::RoutingTableEntry::NetworkDestination);
                    discardEntry->SetPathType(OSPF::RoutingTableEntry::InterArea);
                    discardEntry->SetArea(areas[i]->GetAreaID());
                    discard.push_back(discardEntry);
                    break;
                }
            }
        }
    }

    OSPF::RoutingTableEntry* bestMatch = NULL;
    unsigned long            longestMatch = 0;

    for (i = 0; i < routingTableSize; i++) {
        if (rTable[i]->GetDestinationType() == OSPF::RoutingTableEntry::NetworkDestination) {
            OSPF::RoutingTableEntry* entry        = rTable[i];
            unsigned long            entryAddress = entry->GetDestinationID().getInt();
            unsigned long            entryMask    = entry->GetAddressMask().getInt();

            if ((entryAddress & entryMask) == (dest & entryMask)) {
                if ((dest & entryMask) > longestMatch) {
                    longestMatch = (dest & entryMask);
                    bestMatch    = entry;
                }
            }
        }
    }

    unsigned int discardCount = discard.size();
    if (bestMatch == NULL) {
        unreachable = true;
    } else {
        for (i = 0; i < discardCount; i++) {
            OSPF::RoutingTableEntry* entry        = discard[i];
            unsigned long            entryAddress = entry->GetDestinationID().getInt();
            unsigned long            entryMask    = entry->GetAddressMask().getInt();

            if ((entryAddress & entryMask) == (dest & entryMask)) {
                if ((dest & entryMask) > longestMatch) {
                    unreachable = true;
                    break;
                }
            }
        }
    }

    for (i = 0; i < discardCount; i++) {
        delete discard[i];
    }

    if (unreachable) {
        return NULL;
    } else {
        return bestMatch;
    }
}
void OSPF::Router::NotifyAboutRoutingTableChanges ( std::vector< RoutingTableEntry * > &  oldRoutingTable) [private]

After a routing table rebuild the changes in the routing table are identified and new SummaryLSAs are originated or old ones are flooded out in each area as necessary.

Parameters:
oldRoutingTable[in] The previous version of the routing table(which is then compared with the one in routingTable).
See also:
RFC2328 Section 12.4. points(5) through(6).
{
    if (areas.size() <= 1) {
        return;
    }

    unsigned long                                 routeCount = oldRoutingTable.size();
    std::map<unsigned long, RoutingTableEntry*>   oldTableMap;
    std::map<unsigned long, RoutingTableEntry*>   newTableMap;
    unsigned long                                 i, j, k;

    for (i = 0; i < routeCount; i++) {
        unsigned long destination = oldRoutingTable[i]->GetDestinationID().getInt() & oldRoutingTable[i]->GetAddressMask().getInt();
        oldTableMap[destination] = oldRoutingTable[i];
    }

    routeCount = routingTable.size();
    for (i = 0; i < routeCount; i++) {
        unsigned long   destination = routingTable[i]->GetDestinationID().getInt() & routingTable[i]->GetAddressMask().getInt();
        newTableMap[destination] = routingTable[i];
    }

    unsigned long areaCount = areas.size();
    for (i = 0; i < areaCount; i++) {
        std::map<OSPF::LSAKeyType, bool, OSPF::LSAKeyType_Less> originatedLSAMap;
        std::map<OSPF::LSAKeyType, bool, OSPF::LSAKeyType_Less> deletedLSAMap;
        OSPF::LSAKeyType                                        lsaKey;

        routeCount = routingTable.size();
        for (j = 0; j < routeCount; j++) {
            unsigned long                                         destination = routingTable[j]->GetDestinationID().getInt() & routingTable[j]->GetAddressMask().getInt();
            std::map<unsigned long, RoutingTableEntry*>::iterator destIt      = oldTableMap.find(destination);
            if (destIt == oldTableMap.end()) { // new routing entry
                OSPF::SummaryLSA* lsaToReoriginate = NULL;
                OSPF::SummaryLSA* newLSA           = areas[i]->OriginateSummaryLSA(routingTable[j], originatedLSAMap, lsaToReoriginate);

                if (newLSA != NULL) {
                    if (lsaToReoriginate != NULL) {
                        areas[i]->InstallSummaryLSA(lsaToReoriginate);
//                        FloodLSA(lsaToReoriginate, OSPF::BackboneAreaID);
                        FloodLSA(lsaToReoriginate, areas[i]->GetAreaID());

                        lsaKey.linkStateID       = lsaToReoriginate->getHeader().getLinkStateID();
                        lsaKey.advertisingRouter = routerID;
                        originatedLSAMap[lsaKey] = true;

                        delete lsaToReoriginate;
                    }

                    areas[i]->InstallSummaryLSA(newLSA);
//                    FloodLSA(newLSA, OSPF::BackboneAreaID);
                    FloodLSA(newLSA, areas[i]->GetAreaID());

                    lsaKey.linkStateID       = newLSA->getHeader().getLinkStateID();
                    lsaKey.advertisingRouter = routerID;
                    originatedLSAMap[lsaKey] = true;

                    delete newLSA;
                }
            } else {
                if (*(routingTable[j]) != *(destIt->second)) {  // modified routing entry
                    OSPF::SummaryLSA* lsaToReoriginate = NULL;
                    OSPF::SummaryLSA* newLSA           = areas[i]->OriginateSummaryLSA(routingTable[j], originatedLSAMap, lsaToReoriginate);

                    if (newLSA != NULL) {
                        if (lsaToReoriginate != NULL) {
                            areas[i]->InstallSummaryLSA(lsaToReoriginate);
//                            FloodLSA(lsaToReoriginate, OSPF::BackboneAreaID);
                            FloodLSA(lsaToReoriginate, areas[i]->GetAreaID());

                            lsaKey.linkStateID       = lsaToReoriginate->getHeader().getLinkStateID();
                            lsaKey.advertisingRouter = routerID;
                            originatedLSAMap[lsaKey] = true;

                            delete lsaToReoriginate;
                        }

                        areas[i]->InstallSummaryLSA(newLSA);
//                        FloodLSA(newLSA, OSPF::BackboneAreaID);
                        FloodLSA(newLSA, areas[i]->GetAreaID());

                        lsaKey.linkStateID       = newLSA->getHeader().getLinkStateID();
                        lsaKey.advertisingRouter = routerID;
                        originatedLSAMap[lsaKey] = true;

                        delete newLSA;
                    } else {
                        OSPF::IPv4AddressRange destinationAddressRange;

                        destinationAddressRange.address = IPv4AddressFromULong(routingTable[j]->GetDestinationID().getInt());
                        destinationAddressRange.mask = IPv4AddressFromULong(routingTable[j]->GetAddressMask().getInt());

                        if ((routingTable[j]->GetDestinationType() == OSPF::RoutingTableEntry::NetworkDestination) &&
                            ((routingTable[j]->GetPathType() == OSPF::RoutingTableEntry::IntraArea) ||
                             (routingTable[j]->GetPathType() == OSPF::RoutingTableEntry::InterArea)))
                        {
                            OSPF::IPv4AddressRange containingAddressRange = GetContainingAddressRange(destinationAddressRange);
                            if (containingAddressRange != OSPF::NullIPv4AddressRange) {
                                destinationAddressRange = containingAddressRange;
                            }
                        }

                        Metric maxRangeCost = 0;
                        Metric oneLessCost  = 0;

                        for (k = 0; k < routeCount; k++) {
                            if ((routingTable[k]->GetDestinationType() == OSPF::RoutingTableEntry::NetworkDestination) &&
                                (routingTable[k]->GetPathType() == OSPF::RoutingTableEntry::IntraArea) &&
                                ((routingTable[k]->GetDestinationID().getInt() & routingTable[k]->GetAddressMask().getInt() & ULongFromIPv4Address(destinationAddressRange.mask)) ==
                                 ULongFromIPv4Address(destinationAddressRange.address & destinationAddressRange.mask)) &&
                                (routingTable[k]->GetCost() > maxRangeCost))
                            {
                                oneLessCost  = maxRangeCost;
                                maxRangeCost = routingTable[k]->GetCost();
                            }
                        }

                        if (maxRangeCost == routingTable[j]->GetCost()) {  // this entry gives the range's cost
                            lsaKey.linkStateID       = ULongFromIPv4Address(destinationAddressRange.address);
                            lsaKey.advertisingRouter = routerID;

                            OSPF::SummaryLSA* summaryLSA = areas[i]->FindSummaryLSA(lsaKey);

                            if (summaryLSA != NULL) {
                                if (oneLessCost != 0) { // there's an other entry in this range
                                    summaryLSA->setRouteCost(oneLessCost);
//                                    FloodLSA(summaryLSA, OSPF::BackboneAreaID);
                                    FloodLSA(summaryLSA, areas[i]->GetAreaID());

                                    originatedLSAMap[lsaKey] = true;
                                } else {    // no more entries in this range -> delete it
                                    std::map<OSPF::LSAKeyType, bool, OSPF::LSAKeyType_Less>::const_iterator deletedIt = deletedLSAMap.find(lsaKey);
                                    if (deletedIt == deletedLSAMap.end()) {
                                        summaryLSA->getHeader().setLsAge(MAX_AGE);
//                                        FloodLSA(summaryLSA, OSPF::BackboneAreaID);
                                        FloodLSA(summaryLSA, areas[i]->GetAreaID());

                                        deletedLSAMap[lsaKey]    = true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        routeCount = oldRoutingTable.size();
        for (j = 0; j < routeCount; j++) {
            unsigned long                                         destination = oldRoutingTable[j]->GetDestinationID().getInt() & oldRoutingTable[j]->GetAddressMask().getInt();
            std::map<unsigned long, RoutingTableEntry*>::iterator destIt      = newTableMap.find(destination);
            if (destIt == newTableMap.end()) { // deleted routing entry
                OSPF::IPv4AddressRange destinationAddressRange;

                destinationAddressRange.address = IPv4AddressFromULong(oldRoutingTable[j]->GetDestinationID().getInt());
                destinationAddressRange.mask = IPv4AddressFromULong(oldRoutingTable[j]->GetAddressMask().getInt());

                if ((oldRoutingTable[j]->GetDestinationType() == OSPF::RoutingTableEntry::NetworkDestination) &&
                    ((oldRoutingTable[j]->GetPathType() == OSPF::RoutingTableEntry::IntraArea) ||
                     (oldRoutingTable[j]->GetPathType() == OSPF::RoutingTableEntry::InterArea)))
                {
                    OSPF::IPv4AddressRange containingAddressRange = GetContainingAddressRange(destinationAddressRange);
                    if (containingAddressRange != OSPF::NullIPv4AddressRange) {
                        destinationAddressRange = containingAddressRange;
                    }
                }

                Metric maxRangeCost = 0;

                unsigned long newRouteCount = routingTable.size();
                for (k = 0; k < newRouteCount; k++) {
                    if ((routingTable[k]->GetDestinationType() == OSPF::RoutingTableEntry::NetworkDestination) &&
                        (routingTable[k]->GetPathType() == OSPF::RoutingTableEntry::IntraArea) &&
                        ((routingTable[k]->GetDestinationID().getInt() & routingTable[k]->GetAddressMask().getInt() & ULongFromIPv4Address(destinationAddressRange.mask)) ==
                         ULongFromIPv4Address(destinationAddressRange.address & destinationAddressRange.mask)) &&
                        (routingTable[k]->GetCost() > maxRangeCost))
                    {
                        maxRangeCost = routingTable[k]->GetCost();
                    }
                }

                if (maxRangeCost < oldRoutingTable[j]->GetCost()) {  // the range's cost will change
                    lsaKey.linkStateID       = ULongFromIPv4Address(destinationAddressRange.address);
                    lsaKey.advertisingRouter = routerID;

                    OSPF::SummaryLSA* summaryLSA = areas[i]->FindSummaryLSA(lsaKey);

                    if (summaryLSA != NULL) {
                        if (maxRangeCost > 0) { // there's an other entry in this range
                            summaryLSA->setRouteCost(maxRangeCost);
                            FloodLSA(summaryLSA, OSPF::BackboneAreaID);

                            originatedLSAMap[lsaKey] = true;
                        } else {    // no more entries in this range -> delete it
                            std::map<OSPF::LSAKeyType, bool, OSPF::LSAKeyType_Less>::const_iterator deletedIt = deletedLSAMap.find(lsaKey);
                            if (deletedIt == deletedLSAMap.end()) {
                                summaryLSA->getHeader().setLsAge(MAX_AGE);
                                FloodLSA(summaryLSA, OSPF::BackboneAreaID);

                                deletedLSAMap[lsaKey]    = true;
                            }
                        }
                    }
                }
            }
        }
    }
}
OSPF::ASExternalLSA * OSPF::Router::OriginateASExternalLSA ( OSPF::ASExternalLSA lsa) [private]

Originates a new AS External LSA based on the input lsa.

Parameters:
lsa[in] The LSA whose contents should be copied into the newly originated LSA.
Returns:
The newly originated LSA.
{
    OSPF::ASExternalLSA* asExternalLSA = new OSPF::ASExternalLSA(*lsa);
    OSPFLSAHeader& lsaHeader = asExternalLSA->getHeader();
    OSPFOptions    lsaOptions;

    lsaHeader.setLsAge(0);
    memset(&lsaOptions, 0, sizeof(OSPFOptions));
    lsaOptions.E_ExternalRoutingCapability = true;
    lsaHeader.setLsOptions(lsaOptions);
    lsaHeader.setLsSequenceNumber(INITIAL_SEQUENCE_NUMBER);
    asExternalLSA->SetSource(OSPF::LSATrackingInfo::Originated);

    return asExternalLSA;
}
void OSPF::Router::PruneASBoundaryRouterEntries ( std::vector< RoutingTableEntry * > &  asbrEntries) const [private]

Prunes the input std::vector of RoutingTableEntries according to the RFC2328 Section 16.4.1.

Parameters:
asbrEntries[in/out] The list of RoutingTableEntries to prune.
See also:
RFC2328 Section 16.4.1.
{
    bool hasNonBackboneIntraAreaPath = false;
    for (std::vector<OSPF::RoutingTableEntry*>::iterator it = asbrEntries.begin(); it != asbrEntries.end(); it++) {
        OSPF::RoutingTableEntry* routingEntry = *it;
        if ((routingEntry->GetPathType() == OSPF::RoutingTableEntry::IntraArea) &&
            (routingEntry->GetArea() != OSPF::BackboneAreaID))
        {
            hasNonBackboneIntraAreaPath = true;
            break;
        }
    }

    if (hasNonBackboneIntraAreaPath) {
        std::vector<OSPF::RoutingTableEntry*>::iterator it = asbrEntries.begin();
        while (it != asbrEntries.end()) {
            if (((*it)->GetPathType() != OSPF::RoutingTableEntry::IntraArea) ||
                ((*it)->GetArea() == OSPF::BackboneAreaID))
            {
                it = asbrEntries.erase(it);
            } else {
                it++;
            }
        }
    }
}
void OSPF::Router::RebuildRoutingTable ( void  )

Rebuilds the routing table from scratch(based on the LSA database).

See also:
RFC2328 Section 16.

Referenced by OSPF::NeighborState::ChangeState(), and OSPF::InterfaceState::ChangeState().

{
    unsigned long                         areaCount       = areas.size();
    bool                                  hasTransitAreas = false;
    std::vector<OSPF::RoutingTableEntry*> newTable;
    unsigned long                         i;

    EV << "Rebuilding routing table:\n";

    for (i = 0; i < areaCount; i++) {
        areas[i]->CalculateShortestPathTree(newTable);
        if (areas[i]->GetTransitCapability()) {
            hasTransitAreas = true;
        }
    }
    if (areaCount > 1) {
        OSPF::Area* backbone = GetArea(OSPF::BackboneAreaID);
        if (backbone != NULL) {
            backbone->CalculateInterAreaRoutes(newTable);
        }
    } else {
        if (areaCount == 1) {
            areas[0]->CalculateInterAreaRoutes(newTable);
        }
    }
    if (hasTransitAreas) {
        for (i = 0; i < areaCount; i++) {
            if (areas[i]->GetTransitCapability()) {
                areas[i]->ReCheckSummaryLSAs(newTable);
            }
        }
    }
    CalculateASExternalRoutes(newTable);

    // backup the routing table
    unsigned long                         routeCount = routingTable.size();
    std::vector<OSPF::RoutingTableEntry*> oldTable;

    oldTable.assign(routingTable.begin(), routingTable.end());
    routingTable.clear();
    routingTable.assign(newTable.begin(), newTable.end());

    RoutingTableAccess         routingTableAccess;
    std::vector<const IPRoute*> eraseEntries;
    IRoutingTable*              simRoutingTable    = routingTableAccess.get();
    unsigned long              routingEntryNumber = simRoutingTable->getNumRoutes();
    // remove entries from the IP routing table inserted by the OSPF module
    for (i = 0; i < routingEntryNumber; i++) {
        const IPRoute *entry = simRoutingTable->getRoute(i);
        const OSPF::RoutingTableEntry* ospfEntry = dynamic_cast<const OSPF::RoutingTableEntry*>(entry);
        if (ospfEntry != NULL) {
            eraseEntries.push_back(entry);
        }
    }

    unsigned int eraseCount = eraseEntries.size();
    for (i = 0; i < eraseCount; i++) {
        simRoutingTable->deleteRoute(eraseEntries[i]);
    }

    // add the new routing entries
    routeCount = routingTable.size();
    for (i = 0; i < routeCount; i++) {
        if (routingTable[i]->GetDestinationType() == OSPF::RoutingTableEntry::NetworkDestination) {
            simRoutingTable->addRoute(new OSPF::RoutingTableEntry(*(routingTable[i])));
        }
    }

    NotifyAboutRoutingTableChanges(oldTable);

    routeCount = oldTable.size();
    for (i = 0; i < routeCount; i++) {
        delete(oldTable[i]);
    }

    EV << "Routing table was rebuilt.\n"
       << "Results:\n";

    routeCount = routingTable.size();
    for (i = 0; i < routeCount; i++) {
        EV << *routingTable[i]
           << "\n";
    }
}
void OSPF::Router::RemoveExternalRoute ( OSPF::IPv4Address  networkAddress)

Removes an AS External Route from the database.

Parameters:
networkAddress[in] The network address of the external route which needs to be removed.
{
    OSPF::LSAKeyType     lsaKey;

    lsaKey.linkStateID = ULongFromIPv4Address(networkAddress);
    lsaKey.advertisingRouter = routerID;

    std::map<OSPF::LSAKeyType, OSPF::ASExternalLSA*, OSPF::LSAKeyType_Less>::iterator lsaIt = asExternalLSAsByID.find(lsaKey);
    if (lsaIt != asExternalLSAsByID.end()) {
        lsaIt->second->getHeader().setLsAge(MAX_AGE);
        lsaIt->second->SetPurgeable();
        FloodLSA(lsaIt->second, OSPF::BackboneAreaID);
    }

    std::map<OSPF::IPv4Address, OSPFASExternalLSAContents, OSPF::IPv4Address_Less>::iterator externalIt = externalRoutes.find(networkAddress);
    if (externalIt != externalRoutes.end()) {
        externalRoutes.erase(externalIt);
    }
}
void OSPF::Router::RemoveFromAllRetransmissionLists ( OSPF::LSAKeyType  lsaKey)

Removes all LSAs from all Neighbor's retransmission lists which are identified by the input lsaKey.

Parameters:
lsaKey[in] Identifies the LSAs to remove from the retransmission lists.
{
    long areaCount = areas.size();
    for (long i = 0; i < areaCount; i++) {
        areas[i]->RemoveFromAllRetransmissionLists(lsaKey);
    }
}
OSPF::RoutingTableEntry * OSPF::Router::SelectLeastCostRoutingEntry ( std::vector< RoutingTableEntry * > &  entries) const [private]

Selects the least cost RoutingTableEntry from the input std::vector of RoutingTableEntries.

Parameters:
entries[in] The RoutingTableEntries to choose the least cost one from.
Returns:
The least cost entry or NULL if entries is empty.
{
    if (entries.empty()) {
        return NULL;
    }

    OSPF::RoutingTableEntry* leastCostEntry = entries[0];
    Metric                   leastCost      = leastCostEntry->GetCost();
    long                     routeCount     = entries.size();

    for (long i = 1; i < routeCount; i++) {
        Metric currentCost = entries[i]->GetCost();
        if ((currentCost < leastCost) ||
            ((currentCost == leastCost) && (entries[i]->GetArea() > leastCostEntry->GetArea())))
        {
            leastCostEntry = entries[i];
            leastCost = currentCost;
        }
    }

    return leastCostEntry;
}
void OSPF::Router::SetRFC1583Compatibility ( bool  compatibility) [inline]

Referenced by OSPFRouting::LoadConfigFromXML().

{ rfc1583Compatibility = compatibility; }
void OSPF::Router::SetRouterID ( RouterID  id) [inline]
{ routerID = id; }
void OSPF::Router::UpdateExternalRoute ( OSPF::IPv4Address  networkAddress,
const OSPFASExternalLSAContents &  externalRouteContents,
int  ifIndex 
)

Stores information on an AS External Route in externalRoutes and intalls(or updates) a new ASExternalLSA into the database.

Parameters:
networkAddress[in] The external route's network address.
externalRouteContents[in] Route configuration data for the external route.
ifIndex[in]

Referenced by OSPFRouting::LoadExternalRoute().

{
    OSPF::ASExternalLSA* asExternalLSA = new OSPF::ASExternalLSA;
    OSPFLSAHeader&       lsaHeader     = asExternalLSA->getHeader();
    OSPFOptions          lsaOptions;
    //OSPF::LSAKeyType     lsaKey;

    IRoutingTable*      simRoutingTable    = RoutingTableAccess().get();
    unsigned long      routingEntryNumber = simRoutingTable->getNumRoutes();
    bool               inRoutingTable     = false;
    // add the external route to the routing table if it was not added by another module
    for (unsigned long i = 0; i < routingEntryNumber; i++) {
        const IPRoute *entry = simRoutingTable->getRoute(i);
        if ((entry->getHost().getInt() & entry->getNetmask().getInt()) ==
            (ULongFromIPv4Address(networkAddress) & externalRouteContents.getNetworkMask().getInt()))
        {
            inRoutingTable = true;
        }
    }
    if (!inRoutingTable) {
        IPRoute* entry = new IPRoute;
        entry->setHost(ULongFromIPv4Address(networkAddress));
        entry->setNetmask(externalRouteContents.getNetworkMask());
        entry->setInterface(InterfaceTableAccess().get()->getInterfaceById(ifIndex));
        entry->setType(IPRoute::REMOTE);
        entry->setSource(IPRoute::MANUAL);
        entry->setMetric(externalRouteContents.getRouteCost());
        simRoutingTable->addRoute(entry);   // IRoutingTable deletes entry pointer
    }

    lsaHeader.setLsAge(0);
    memset(&lsaOptions, 0, sizeof(OSPFOptions));
    lsaOptions.E_ExternalRoutingCapability = true;
    lsaHeader.setLsOptions(lsaOptions);
    lsaHeader.setLsType(ASExternalLSAType);
    lsaHeader.setLinkStateID(ULongFromIPv4Address(networkAddress));   // TODO: get unique LinkStateID
    lsaHeader.setAdvertisingRouter(routerID);
    lsaHeader.setLsSequenceNumber(INITIAL_SEQUENCE_NUMBER);

    asExternalLSA->setContents(externalRouteContents);

    lsaHeader.setLsChecksum(0);    // TODO: calculate correct LS checksum

    asExternalLSA->SetSource(OSPF::LSATrackingInfo::Originated);

    externalRoutes[networkAddress] = externalRouteContents;

    bool rebuild = InstallASExternalLSA(asExternalLSA);
    FloodLSA(asExternalLSA, OSPF::BackboneAreaID);
    delete asExternalLSA;

    if (rebuild) {
        RebuildRoutingTable();
    }
}

Member Data Documentation

OSPFTimer* OSPF::Router::ageTimer [private]

Database age timer - fires every second.

Referenced by Router().

std::vector<Area*> OSPF::Router::areas [private]

A list of the contained areas.

Referenced by GetAreaCount().

std::map<AreaID, Area*> OSPF::Router::areasByID [private]

A map of the contained areas with the AreaID as key.

A list of the ASExternalLSAs advertised by this router.

Referenced by GetASExternalLSA(), and GetASExternalLSACount().

A map of the ASExternalLSAs advertised by this router.

std::map<IPv4Address, OSPFASExternalLSAContents, IPv4Address_Less> OSPF::Router::externalRoutes [private]

A map of the external route advertised by this router.

Referenced by GetASBoundaryRouter().

The message dispatcher class.

Referenced by GetMessageHandler(), and Router().

Decides whether to handle the preferred routing table entry to an AS boundary router as defined in RFC1583 or not.

Referenced by GetRFC1583Compatibility(), and SetRFC1583Compatibility().

The router ID assigned by the IP layer.

Referenced by GetRouterID(), and SetRouterID().

The OSPF routing table - contains more information than the one in the IP layer.

Referenced by AddRoutingTableEntry(), GetRoutingTableEntry(), and GetRoutingTableEntryCount().


The documentation for this class was generated from the following files: