毅哥铡特:修改后的Bellmanford最短路径路由动画演示

news2024/11/24 12:26:38

修改背景:毅哥铡特自带的《routing_bellmanford.cpp》,按路由跳数进行更新路由表,但是,卫星互联网的卫星路由器节点,可能需要考虑传播传输时延,对应的,可能需要按照两个网络节点的距离来更新路由表。

修改后的《routing_bellmanford.cpp》:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "api.h"
#include "network_ip.h"
#include "app_util.h"
#include "routing_bellmanford.h"

#include "partition.h"  //JSLS添加:[PARTITION_ReturnNodePointer],用于根据[节点ID]获取[节点指针]
#include "coordinates.h" //JSLS添加:用于计算 两个节点之间的物理距离,用于 路由距离的度量

//#define nDEBUG 
//#define nDEBUG_TABLE

#define DEBUG  1         //JSLS备注: 去掉前面的 n 字符后,设置为 1,方便 Debug 调试。
#define DEBUG_TABLE  1  //JSLS备注: 去掉前面的 n 字符后,设置为 1,以便调试时查看 路由表

//-----------------------------------------------------------------------------
// DEFINES
//-----------------------------------------------------------------------------

//
// The route table starts with memory allocated for this many routes.
//

#define NUM_INITIAL_ROUTES_ALLOCATED   4

//
// Bellman-Ford value for infinite distance.
//

// #define BELLMANFORD_INFINITY   16   // 原始代码
#define BELLMANFORD_INFINITY   32767   // JSLS修改:15位bit 全为1 ,数值为 32767(单位:㎞千米)。用于 STK Exata 联合仿真时表示 卫星路由器节点间 距离

//
// Each node broadcasts its entire route table (a periodic update)
// at intervals of:
// PERIODIC_UPDATE_INTERVAL + [0, PERIODIC_UPDATE_JITTER) seconds.
//

#define PERIODIC_UPDATE_INTERVAL   (10 * SECOND)
#define PERIODIC_UPDATE_JITTER     (150 * MILLI_SECOND)

//
// Each node checks for timed-out routes at intervals of:
// CHECK_TIMEOUT_INTERVAL + [0, CHECK_TIMEOUT_JITTER) seconds.
//

#define CHECK_TIMEOUT_INTERVAL     (60 * SECOND)
#define CHECK_TIMEOUT_JITTER       (100 * MILLI_SECOND)

//
// Triggered updates are scheduled after a delay of:
// TRIGGERED_UPDATE_DELAY + [0, TRIGGERED_UPDATE_JITTER) seconds.
//

#define TRIGGERED_UPDATE_DELAY     (0 * SECOND)
#define TRIGGERED_UPDATE_JITTER    (150 * MILLI_SECOND)

//
// If a route is >= TIMEOUT_DELAY in age, it is considered timed out.
//

#define TIMEOUT_DELAY   (60 * SECOND)

//
// Each route-advertisement packet is limited to this many routes.
// If more routes need to be sent, multiple packets are sent.
//

#define MAX_ROUTES_PER_ROUTE_ADVERTISEMENT_PACKET   32



//-----------------------------------------------------------------------------
// STRUCTS, ENUMS, AND TYPEDEFS
//-----------------------------------------------------------------------------

//
// Route in a route table.
//

typedef struct
{
    NodeAddress destAddress;
    NodeAddress subnetMask;
    NodeAddress nextHop;
    int         incomingInterface;
    int         outgoingInterface;

    short       distance;
    BOOL        localRoute;

    clocktype   refreshTime;
    BOOL        changed;
    // This flag is set if its a re-distributed route
    BOOL        isPermanent;
} Route;

//
// Bellman-Ford state.
//

typedef struct
{
    // General state information.

    clocktype nextPeriodicUpdateTime;
    BOOL triggeredUpdateScheduled;

    // Route table.

    Route *routeTable;
    int numRoutesAllocated;
    int numRoutes;

    // Statistics.

    int numPeriodicUpdates;
    int numTriggeredUpdates;
    int numRouteTimeouts;
    int numRouteAdvertisementsReceived;
    RandomSeed periodicJitterSeed;
    RandomSeed checkTimeoutSeed;
    RandomSeed triggeredUpdateSeed;
    BOOL statsPrinted;
} Bellmanford;

//
// Header fields for route-advertisement packet.
//

typedef struct
{
    NodeAddress sourceAddress;  // source IP address
    NodeAddress destAddress;    // destination IP address
    int         payloadSize;    // size of payload in bytes
} RoutingBellmanfordHeader;

//
// Route in a route-advertisement packet.
//

typedef struct
{
    NodeAddress destAddress;
    NodeAddress subnetMask;
    NodeAddress nextHop;

    int         distance;
} AdvertisedRoute;

//
// enum for argument passed to SendRouteAdvertisement() to determine
// whether to execute in periodic or triggered update mode.
//

typedef enum
{
   ROUTING_BELLMANFORD_PERIODIC_UPDATE = 0,
   ROUTING_BELLMANFORD_TRIGGERED_UPDATE
} RouteAdvertisementType;

//
// enum for argument passed to PrintRouteTable() to vary what kind of
// output to print to screen.
//

typedef enum
{
    ROUTING_BELLMANFORD_PRE_UPDATE = 0,
    ROUTING_BELLMANFORD_POST_UPDATE
} PrintRouteTableType;



//-----------------------------------------------------------------------------
// PROTOTYPES FOR FUNCTIONS WITH INTERNAL LINKAGE
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Handler functions for Bellman-Ford internal messages
//-----------------------------------------------------------------------------

static void //inline//
HandlePeriodicUpdateAlarm(Node *node);

static void //inline//
HandleCheckRouteTimeoutAlarm(Node *node);

static void //inline//
HandleTriggeredUpdateAlarm(Node *node);

static void //inline//
SendRouteAdvertisement(
    Node *node, RouteAdvertisementType type);

static void //inline//
ScheduleTriggeredUpdate(Node *node);

//-----------------------------------------------------------------------------
// Handler functions for messages from the transport layer
//-----------------------------------------------------------------------------

static void //inline//
HandleFromTransport(Node *node, Message *msg);

static void //inline//
ProcessRouteAdvertisementPacket(
    Node *node,
    NodeAddress neighborAddr,
    int incomingInterfaceIndex,
    int numOfRTEntries,
    AdvertisedRoute *neighborRowPtr);

//-----------------------------------------------------------------------------
// Route table manipulation functions
//-----------------------------------------------------------------------------

static void //inline//
InitRouteTable(Bellmanford *bellmanford);

static Route * //inline//
FindRoute(
    Bellmanford *bellmanford,
    NodeAddress destAddress);

static Route * //inline//
AddRoute(
    Bellmanford *bellmanford,
    NodeAddress destAddress,
    NodeAddress subnetMask,
    NodeAddress nextHop,
    int incomingInterfaceIndex,
    int distance);

//-----------------------------------------------------------------------------
// Statistics
//-----------------------------------------------------------------------------

static void //inline//
PrintStats(Node *node);

//-----------------------------------------------------------------------------
// Debug output functions
//-----------------------------------------------------------------------------

static void //inline//
PrintRouteAdvertisementPacket(
    Node *node,
    AdvertisedRoute *neighborRowPtr,
    int numAdvertisedRoutes);

static void //inline//
PrintRouteTable(
    Node *node,
    PrintRouteTableType type);



//-----------------------------------------------------------------------------
// FUNCTIONS WITH EXTERNAL LINKAGE
//-----------------------------------------------------------------------------
// Bellmanford initialization  for tracing
//
// \param node  Pointer to node
// \param nodeInput  Pointer to NodeInput
//

void RoutingBellmanfordInitTrace(Node* node, const NodeInput* nodeInput)
{
    char buf[MAX_STRING_LENGTH];
    BOOL retVal;
    BOOL traceAll = TRACE_IsTraceAll(node);
    BOOL trace = FALSE;
    static BOOL writeMap = TRUE;

    IO_ReadString(
        node->nodeId,
        ANY_ADDRESS,
        nodeInput,
        "TRACE-BELLMANFORD",
        &retVal,
        buf);

    if (retVal)
    {
        if (strcmp(buf, "YES") == 0)
        {
            trace = TRUE;
        }
        else if (strcmp(buf, "NO") == 0)
        {
            trace = FALSE;
        }
        else
        {
            ERROR_ReportError(
                "TRACE-BELLMANFORD should be either \"YES\" or \"NO\".\n");
        }
    }
    else
    {
        if (traceAll || node->traceData->layer[TRACE_APPLICATION_LAYER])
        {
            trace = TRUE;
        }
    }

    if (trace)
    {
            TRACE_EnableTraceXML(node, TRACE_BELLMANFORD,
                "BELLMANFORD", RoutingBellmanfordPrintTraceXML, writeMap);
    }
    else
    {
            TRACE_DisableTraceXML(node, TRACE_BELLMANFORD,
                "BELLMANFORD", writeMap);
    }
    writeMap = FALSE;
}
//-----------------------------------------------------------------------------
// Print TraceXML function
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// FUNCTION   :: RoutingBellmanfordPrintTraceXML
// LAYER      :: NETWORK
// PURPOSE    :: Print packet trace information in XML format
// PARAMETERS ::
// + node     : Node*    : Pointer to node
// + msg      : Message* : Pointer to packet to print headers from
// RETURN     ::  void   : NULL
//-----------------------------------------------------------------------------

void RoutingBellmanfordPrintTraceXML(Node* node, Message* msg)
{
    char buf[MAX_STRING_LENGTH];
    char sourceAddr[MAX_STRING_LENGTH];
    char destinationAddr[MAX_STRING_LENGTH];
    char nexthopAddr[MAX_STRING_LENGTH];

    Bellmanford *bellmanford = (Bellmanford *) node->appData.bellmanford;
    RoutingBellmanfordHeader *header;
    AdvertisedRoute *payload;
    int numAdvertisedRoutes;

    // If bellmanford is not configured here, then discard message.
    if (!bellmanford)
    {
        return;
    }
    // Obtain pointers to header, payload.

    header = (RoutingBellmanfordHeader *) msg->packet;
    payload = (AdvertisedRoute *)
              (msg->packet + sizeof(RoutingBellmanfordHeader));

    IO_ConvertIpAddressToString(header->sourceAddress, sourceAddr);
    IO_ConvertIpAddressToString(header->destAddress , destinationAddr);

     // Obtain number of rows in update.

    sprintf(buf, "<bellmanford>");
    TRACE_WriteToBufferXML(node, buf);

    sprintf(buf,"%s %s %d",
             sourceAddr,
             destinationAddr,
             header->payloadSize );
    TRACE_WriteToBufferXML(node, buf);

    numAdvertisedRoutes = header->payloadSize / sizeof(AdvertisedRoute);

    for (int i = 0; i < numAdvertisedRoutes; i++) {

    IO_ConvertIpAddressToString(payload->destAddress , destinationAddr);
    IO_ConvertIpAddressToString(payload->subnetMask, sourceAddr);
    IO_ConvertIpAddressToString(payload->nextHop, nexthopAddr);

    sprintf(buf,"<advertisedRoute>%s %s %s %d </advertisedRoute>",
                    destinationAddr,
                    sourceAddr,
                    nexthopAddr,
                    payload->distance);
    TRACE_WriteToBufferXML(node, buf);
    payload++;
    }

    sprintf(buf, "</bellmanford>");
    TRACE_WriteToBufferXML(node, buf);
}

//-----------------------------------------------------------------------------
// Init function
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// FUNCTION     RoutingBellmanfordInit
// PURPOSE      Initializes the Bellman-Ford model.
//
// Parameters:
//
// Node *node
//     For current node
//
// Notes:
//
// This function is called once per node, for nodes which are running
// the Bellman-Ford model for routing.
//-----------------------------------------------------------------------------

void
RoutingBellmanfordInit(Node *node)
{
    Bellmanford *bellmanford;
    int i;
    clocktype randomDelay;

    Message *newMsg;

    if (node->get_networkData()->networkProtocol == NETWORK_IPV6)
    {
        // Bellmanford is an IPv4 Network based routing protocol,
        // it can not be run on this node

        return;
    }

    // Allocate Bellmanford struct.  Assign pointers.

    bellmanford = (Bellmanford *) MEM_malloc(sizeof(Bellmanford));
    node->appData.bellmanford = (void *) bellmanford;

    //Need for route redistribution
    NetworkDataIp* ip =  node->get_networkVar();

    // Init stats.

    bellmanford->numPeriodicUpdates = 0;
    bellmanford->numRouteTimeouts = 0;
    bellmanford->numTriggeredUpdates = 0;
    bellmanford->numRouteAdvertisementsReceived = 0;
    bellmanford->statsPrinted = FALSE;

    // Init random seeds to each be different

    RANDOM_SetSeed(bellmanford->periodicJitterSeed,
                   node->globalSeed,
                   node->nodeId,
                   ROUTING_PROTOCOL_BELLMANFORD,
                   1);
    RANDOM_SetSeed(bellmanford->checkTimeoutSeed,
                   node->globalSeed,
                   node->nodeId,
                   ROUTING_PROTOCOL_BELLMANFORD,
                   2);
    RANDOM_SetSeed(bellmanford->triggeredUpdateSeed,
                   node->globalSeed,
                   node->nodeId,
                   ROUTING_PROTOCOL_BELLMANFORD,
                   3);

    // Init Bellman-Ford route table.

    InitRouteTable(bellmanford);

    // Add 0-hop routes to local networks.  These are flagged as
    // local routes.
    //
    // Loop through all interfaces, since it's assumed that Bellman-Ford
    // is running on all interfaces on a node.

    for (i = 0; i < node->numberInterfaces; i++)
    {
        NodeAddress destAddress;
        NodeAddress subnetMask;
        Route *rowPtr;

        if (NetworkIpGetInterfaceType(node, i) != NETWORK_IPV4
            && NetworkIpGetInterfaceType(node, i) != NETWORK_DUALIP)
        {
            continue;
        }

        if (NetworkIpIsWiredNetwork(node, i))
        {
            // This is a wiredlink interface.
            //
            // The destAddress is the network address for the interface,
            // and subnetMask is the subnet mask for the interface.

            destAddress = NetworkIpGetInterfaceNetworkAddress(node, i);
            subnetMask = NetworkIpGetInterfaceSubnetMask(node, i);
        }
        else
        {
            // This is a wireless interface.
            //
            // The destAddress is the IP address of the interface
            // itself, and subnetMask is 255.255.255.255 (ANY_DEST is
            // an all-one 32-bit value).
            //
            // This means that the route applies exactly to the host IP
            // address of the interface. (not to a network address)

            destAddress = NetworkIpGetInterfaceAddress(node, i);
            subnetMask = ANY_DEST;
        }

        if (!FindRoute(bellmanford, destAddress)
            // Dynamic address
            && ip->interfaceInfo[i]->addressState != INVALID)
        {
            rowPtr = AddRoute(bellmanford,
                         destAddress,
                         subnetMask,
                         NetworkIpGetInterfaceAddress(node, i),
                         i,
                         0);

            rowPtr->localRoute = TRUE;
        }

#ifdef ENTERPRISE_LIB
        if (ip->interfaceInfo[i]->routingProtocolType
            == ROUTING_PROTOCOL_BELLMANFORD)
        {

            RouteRedistributeSetRoutingTableUpdateFunction(
                node,
                &BellmanfordHookToRedistribute,
                i);
        }
#endif // ENTERPRISE_LIB
    }

    // Calculate jitter for first periodic update.

    randomDelay = RANDOM_nrand(bellmanford->periodicJitterSeed) % PERIODIC_UPDATE_JITTER;

    // Schedule first periodic update.

    newMsg = MESSAGE_Alloc(node,
                           APP_LAYER,
                           APP_ROUTING_BELLMANFORD,
                           MSG_APP_PeriodicUpdateAlarm);

    MESSAGE_Send(node, newMsg, 0);

    // Record time of periodic update in nextPeriodicUpdateTime.
    // (ScheduleTriggeredUpdate() uses this value.)

    bellmanford->nextPeriodicUpdateTime = node->getNodeTime() + randomDelay;

    // Calculate jitter for first route timeout check.

    randomDelay = RANDOM_nrand(bellmanford->checkTimeoutSeed) % CHECK_TIMEOUT_JITTER;

    // Schedule first route timeout.

    newMsg = MESSAGE_Alloc(node,
                            APP_LAYER,
                            APP_ROUTING_BELLMANFORD,
                            MSG_APP_CheckRouteTimeoutAlarm);
    MESSAGE_Send(node, newMsg, CHECK_TIMEOUT_INTERVAL + randomDelay);


    // Dynamic address
    // registering RoutingBellmanfordHandleAddressChangeEvent function
    NetworkIpAddAddressChangedHandlerFunction(node,
                            &RoutingBellmanfordHandleChangeAddressEvent);
}

//-----------------------------------------------------------------------------
// Layer function
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// FUNCTION     RoutingBellmanfordLayer
// PURPOSE      Layer function for the Bellman-Ford model.
//
// Parameters:
//
// Node *node
//     For current node
// Message *msg
//     Message to be processed
//
// Notes:
//
// The MESSAGE_Free() on msg is called at the end of the function.
//-----------------------------------------------------------------------------

void
RoutingBellmanfordLayer(Node *node, Message *msg)
{
    if (node->get_networkData()->networkProtocol == NETWORK_IPV6)
    {
        // Bellmanford is an IPv4 Network based routing protocol,
        // it can not be run on this node

        ActionData acnData;
        acnData.actionType = DROP;
        acnData.actionComment = DROP_INVALID_NETWORK_PROTOCOL;
        TRACE_PrintTrace(node,
                         msg,
                         TRACE_APPLICATION_LAYER,
                         PACKET_OUT,
                         &acnData);
        MESSAGE_Free(node, msg);

        return;
    }
    switch (msg->eventType)
    {
        // Messages sent within Bellman-Ford.

        case MSG_APP_PeriodicUpdateAlarm:
        {
            HandlePeriodicUpdateAlarm(node);
            break;
        }
        case MSG_APP_CheckRouteTimeoutAlarm:
        {
            HandleCheckRouteTimeoutAlarm(node);
            break;
        }
        case MSG_APP_TriggeredUpdateAlarm:
        {
            HandleTriggeredUpdateAlarm(node);
            break;
        }

        // Messages sent by UDP to Bellman-Ford.

        case MSG_APP_FromTransport:
        {
            HandleFromTransport(node, msg);
            break;
        }
        default:
            ERROR_ReportError("Invalid switch value");
    }

    // Done with the message, so free it.

    MESSAGE_Free(node, msg);
}

//-----------------------------------------------------------------------------
// Finalize function
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// FUNCTION     RoutingBellmanfordFinalize
// PURPOSE      Finalize function for the Bellman-Ford model.
//
// Parameters:
//
// Node *node
//     For current node.
// int interfaceIndex
//     Interface index we are finalizing.
//
// Notes:
//
// Called once per node, per interface that is running Bellman-Ford.
// ...PrintStats() is called only for interfaceIndex 0.  See the
// ...PrintStats() function for more info.
//-----------------------------------------------------------------------------

void
RoutingBellmanfordFinalize(Node *node, int interfaceIndex)
{
    Bellmanford *bellmanford = (Bellmanford *)node->appData.bellmanford;

    if (node->get_networkData()->networkProtocol == NETWORK_IPV6)
    {
        // Bellmanford is an IPv4 Network based routing protocol,
        // it can not be run on this node

        return;
    }
    if (node->appData.routingStats == TRUE
        && bellmanford->statsPrinted == FALSE)
    {
        PrintStats(node);
        bellmanford->statsPrinted = TRUE;
    }
}



//-----------------------------------------------------------------------------
// FUNCTIONS WITH INTERNAL LINKAGE
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Handler functions for Bellman-Ford internal messages
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// FUNCTION     HandlePeriodicUpdateAlarm
// PURPOSE      Broadcasts a periodic update and schedules another.
//
// Parameters:
//
// Node *node
//     For current node.
//-----------------------------------------------------------------------------

static void //inline//
HandlePeriodicUpdateAlarm(Node *node)
{
    Bellmanford *bellmanford = (Bellmanford *) node->appData.bellmanford;

    clocktype delay;
    Message *newMsg;

    // Send all routes to UDP.  Increment stat.

    SendRouteAdvertisement(
        node, ROUTING_BELLMANFORD_PERIODIC_UPDATE);

    // Schedule next periodic update. (node->getNodeTime() + 10 s + 0-100 ms)

    delay = PERIODIC_UPDATE_INTERVAL
            + (RANDOM_nrand(bellmanford->periodicJitterSeed) % PERIODIC_UPDATE_JITTER);

    newMsg = MESSAGE_Alloc(node,
                            APP_LAYER,
                            APP_ROUTING_BELLMANFORD,
                            MSG_APP_PeriodicUpdateAlarm);

    MESSAGE_Send(node, newMsg, delay);

    // Record time of next periodic update in nextPeriodicUpdateTime.
    // (ScheduleTriggeredUpdate() uses this value.)

    bellmanford->nextPeriodicUpdateTime = node->getNodeTime() + delay;
}

//-----------------------------------------------------------------------------
// FUNCTION     HandleCheckRouteTimeoutAlarm
// PURPOSE      Checks for route timeouts, schedules triggered update if
//              necessary.  Schedules next route timeout check.
//
// Parameters:
//
// Node *node
//     For current node.
//
// Notes:
//
// All routes (that aren't timed out already) are checked for staleness.
// Stale routes are marked unreachable and a triggered update is
// scheduled.
//-----------------------------------------------------------------------------

static void //inline//
HandleCheckRouteTimeoutAlarm(Node *node)
{
    Bellmanford *bellmanford = (Bellmanford *) node->appData.bellmanford;

    int i;
    BOOL routeChanged;
    Message *newMsg;

#ifdef DEBUG
    {
        printf("Bellmanford: %s s, node %u, --- Route timeout check\n",
            TIME_PrintClockInSecond(node->getNodeTime()).c_str(), node->nodeId);
    }
#endif // DEBUG

    // Look for stale routes in route table.

    routeChanged = FALSE;
    for (i = 0; i < bellmanford->numRoutes; i++)
    {

    // Added for redistribution. If its a redistributed route then we
    //  dont time out.
        if (bellmanford->routeTable[i].isPermanent == TRUE)
        {
          // move to the next route
             continue;
    }
        // Don't time out local routes, routes already marked unreachable.

        if (bellmanford->routeTable[i].localRoute == FALSE
            && bellmanford->routeTable[i].distance != BELLMANFORD_INFINITY
            && node->getNodeTime() - bellmanford->routeTable[i].refreshTime
               >= TIMEOUT_DELAY)
        {
            // Found new stale route.

#ifdef DEBUG_TABLE
            if (routeChanged == FALSE)
            {
                // We have a route change resulting from a route timeout,
                // and will be updating our route table.

                // Print pre-update route table.

                PrintRouteTable(
                    node,
                    ROUTING_BELLMANFORD_PRE_UPDATE);
            }
#endif // DEBUG_TABLE

            if (routeChanged == FALSE)
            {
                routeChanged = TRUE;
            }

            // Set nextHop is NETWORK_UNREACHABLE, distance is infinity,
            // routeChanged flag to TRUE.

            bellmanford->routeTable[i].nextHop     =
                (unsigned) NETWORK_UNREACHABLE;
            bellmanford->routeTable[i].distance    = BELLMANFORD_INFINITY;
            bellmanford->routeTable[i].refreshTime = node->getNodeTime();
            bellmanford->routeTable[i].changed     = TRUE;

            // Update forwarding table to indicate no route to
            // destAddress.

            NetworkUpdateForwardingTable(
                node,
                bellmanford->routeTable[i].destAddress,
                bellmanford->routeTable[i].subnetMask,
                (unsigned) NETWORK_UNREACHABLE,
                ANY_INTERFACE,
                bellmanford->routeTable[i].distance,
                ROUTING_PROTOCOL_BELLMANFORD);

            // Increment stat for a route timeout.
            // (If a route times out, becomes valid, and times out
            // again -- the second timeout also counts.)

            bellmanford->numRouteTimeouts++;

#ifdef DEBUG
#ifndef DEBUG_TABLE
            {
                printf("Bellmanford: %s s, node %u, --- Route timeout, dest"
                    " = %d\n",TIME_PrintClockInSecond(node->getNodeTime()).c_str(), node->nodeId, i);
            }
#endif // DEBUG_TABLE
#endif // DEBUG
        }
    }

    // If any route timed out, schedule a triggered update.

    if (routeChanged == TRUE)
    {
#ifdef DEBUG_TABLE
        // If the table was updated, print post-update route table.

        PrintRouteTable(
            node,
            ROUTING_BELLMANFORD_POST_UPDATE);
#endif // DEBUG_TABLE

        ScheduleTriggeredUpdate(node);
    }

    // Schedule next route timeout check.

    newMsg = MESSAGE_Alloc(node,
                           APP_LAYER,
                           APP_ROUTING_BELLMANFORD,
                           MSG_APP_CheckRouteTimeoutAlarm);

    MESSAGE_Send(node, newMsg,
                 CHECK_TIMEOUT_INTERVAL
                 + (RANDOM_nrand(bellmanford->checkTimeoutSeed) % CHECK_TIMEOUT_JITTER));
}

//-----------------------------------------------------------------------------
// FUNCTION     HandleTriggeredUpdateAlarm
// PURPOSE      Broadcasts a triggered update.
//
// Parameters:
//
// Node *node
//     For current node.
//
// Notes:
//
// This is called sometime after ScheduleTriggeredUpdate()
// schedules an update.  SendRouteAdvertisement() is
// called to broadcast the triggered update.
//-----------------------------------------------------------------------------

static void //inline//
HandleTriggeredUpdateAlarm(Node *node)
{
    Bellmanford *bellmanford = (Bellmanford *) node->appData.bellmanford;

    // Send updated routes to UDP.

    SendRouteAdvertisement(node, ROUTING_BELLMANFORD_TRIGGERED_UPDATE);

    // Clear flag so that another triggered update can be scheduled if
    // it becomes necessary.

    bellmanford->triggeredUpdateScheduled = FALSE;
}

//-----------------------------------------------------------------------------
// FUNCTION     SendRouteAdvertisement
// PURPOSE      Broadcasts route-advertisement packets on all interfaces.
//
// Parameters:
//
// Node *node
//     For current node.
// RouteAdvertisementType type
//     ROUTING_BELLMANFORD_PERIODIC_UPDATE
//     or,
//     ROUTING_BELLMANFORD_TRIGGERED_UPDATE
//
// Notes:
//
// If type indicates periodic update, then all routes are advertised.
// If type indicates triggered update, then only flagged routes (routes
// which changed since the last update event) are advertised.
//-----------------------------------------------------------------------------

static void //inline//
SendRouteAdvertisement(
    Node *node, RouteAdvertisementType type)
{
    NetworkDataIp* ip =  node->get_networkVar();
    Bellmanford *bellmanford = (Bellmanford *) node->appData.bellmanford;

    AdvertisedRoute payloadBuf[MAX_ROUTES_PER_ROUTE_ADVERTISEMENT_PACKET];
    int rowIndex;

    // In the while loop, send the current node's entire route table to
    // UDP, using multiple packets if necessary.

    rowIndex = 0;
    while (rowIndex < bellmanford->numRoutes)
    {
        // payloadBuf starts with zero rows copied into it.  Every time we
        // add a route into payloadBuf, we increment payloadRowIndex.  When
        // payloadBuf is full, we send payloadBuf out, set payloadRowIndex
        // to 0, and repeat the process -- until the node's entire route
        // table has been sent.

        int payloadRowIndex;
        int payloadSize;

        payloadRowIndex = 0;

        while (rowIndex < bellmanford->numRoutes
               && payloadRowIndex
                  < MAX_ROUTES_PER_ROUTE_ADVERTISEMENT_PACKET)
        {
            if (type == ROUTING_BELLMANFORD_PERIODIC_UPDATE
                ||
                (type == ROUTING_BELLMANFORD_TRIGGERED_UPDATE
                 && bellmanford->routeTable[rowIndex].changed == TRUE))
            {
                payloadBuf[payloadRowIndex].destAddress =
                    bellmanford->routeTable[rowIndex].destAddress;

                payloadBuf[payloadRowIndex].subnetMask =
                    bellmanford->routeTable[rowIndex].subnetMask;

                payloadBuf[payloadRowIndex].nextHop =
                    bellmanford->routeTable[rowIndex].nextHop;

                payloadBuf[payloadRowIndex].distance =
                    bellmanford->routeTable[rowIndex].distance;

                if (type == ROUTING_BELLMANFORD_TRIGGERED_UPDATE)
                {
                    // Reset routeChanged flag if this is a triggered
                    // update.

                    bellmanford->routeTable[rowIndex].changed = FALSE;
                }

                payloadRowIndex++;
            }
            rowIndex++;
        }

        payloadSize = sizeof(AdvertisedRoute)
                      * payloadRowIndex;

        if (payloadSize > 0)
        {
            int i;

            for (i = 0; i < node->numberInterfaces; i++)
            {
                NodeAddress destAddress;
                RoutingBellmanfordHeader header;

                if (NetworkIpGetUnicastRoutingProtocolType(node, i)
                    != ROUTING_PROTOCOL_BELLMANFORD)
                {
                    continue;
                }

                if (NetworkIpIsWiredNetwork(node, i))
                {
                    destAddress =
                        NetworkIpGetInterfaceBroadcastAddress(node, i);
                }
                else
                {
                    destAddress = ANY_DEST;
                }

                header.sourceAddress = ip->interfaceInfo[i]->ipAddress;
                header.destAddress   = destAddress;
                header.payloadSize   = payloadSize;

                Message* msg = APP_UdpCreateMessage(
                    node,
                    ip->interfaceInfo[i]->ipAddress,
                    (short) APP_ROUTING_BELLMANFORD,
                    // Dynamic Address
                    // we need to brodacast the packet as new address might
                    // make some nodes in subnet out of brodcast address 
                    // range
                    ANY_DEST,
                    (short) APP_ROUTING_BELLMANFORD,
                    TRACE_BELLMANFORD,
                    IPTOS_PREC_INTERNETCONTROL);

                APP_UdpSetOutgoingInterface(msg, i); 

                APP_AddPayload(
                    node,
                    msg,
                    payloadBuf,
                    payloadSize);

                APP_AddHeader(
                    node,
                    msg,
                    &header,
                    sizeof(RoutingBellmanfordHeader));

                APP_UdpSend(
                    node, 
                    msg,
                    RANDOM_nrand(bellmanford->periodicJitterSeed) % 
                        PERIODIC_UPDATE_JITTER);

                if (type == ROUTING_BELLMANFORD_PERIODIC_UPDATE)
                {
                    bellmanford->numPeriodicUpdates++;
                }
                else if (type == ROUTING_BELLMANFORD_TRIGGERED_UPDATE)
                {
                    bellmanford->numTriggeredUpdates++;
                }

#ifdef DEBUG
                {
                    char *typeString;
                    char address[MAX_STRING_LENGTH];

                    if (type == ROUTING_BELLMANFORD_PERIODIC_UPDATE)
                    {
                        typeString = "Periodic";
                    }
                    else
                    {
                        typeString = "Triggered";
                    }

                    IO_ConvertIpAddressToString(destAddress, address);
                    printf("Bellmanford: %s s, node %u, "
                           "SND %s update, Sent packet to UDP, dst %s\n",
                           TIME_PrintClockInSecond(node->getNodeTime()).c_str(),
                           node->nodeId, typeString, address);
                }
#endif // DEBUG
            }//for//
        }//if//
    }//while//
}

//-----------------------------------------------------------------------------
// FUNCTION     ScheduleTriggeredUpdate
// PURPOSE      Schedules a triggered update.  Checks if an update event
//              isn't already scheduled.
//
// Parameters:
//
// Node *node
//     For current node.
//-----------------------------------------------------------------------------

static void //inline//
ScheduleTriggeredUpdate(Node *node)
{
    Bellmanford *bellmanford = (Bellmanford *) node->appData.bellmanford;

    // Schedule a triggered update only if
    // a) A triggered update is not already scheduled for the node, or
    // b) Next periodic update is far enough away.

    if (bellmanford->triggeredUpdateScheduled == FALSE
        && bellmanford->nextPeriodicUpdateTime
           > node->getNodeTime() + TRIGGERED_UPDATE_DELAY + TRIGGERED_UPDATE_JITTER)
    {
        Message *newMsg;

        // Schedule triggered update. (node->getNodeTime() + 0-100 ms)

        newMsg = MESSAGE_Alloc(node,
                                APP_LAYER,
                                APP_ROUTING_BELLMANFORD,
                                MSG_APP_TriggeredUpdateAlarm);

        MESSAGE_Send(node, newMsg,
                      TRIGGERED_UPDATE_DELAY
                      + RANDOM_nrand(bellmanford->triggeredUpdateSeed) % TRIGGERED_UPDATE_JITTER);

        // Set flag indicating a triggered update has been scheduled.

        bellmanford->triggeredUpdateScheduled = TRUE;
    }
}

//-----------------------------------------------------------------------------
// Handler functions for messages from the transport layer
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// FUNCTION     HandleFromTransport
// PURPOSE      Processes a packet from UDP.
//
// Parameters:
//
// Node *node
//     For current node.
// Message *msg
//     Contains the UDP packet contents.
//
// Notes:
//
// Only route advertisement packets are receieved from UDP; there are no
// other types of Bellman-Ford messages sent over the network.
//
// This function will call ProcessRouteAdvertisementPacket().
//-----------------------------------------------------------------------------

static void //inline//
HandleFromTransport(Node *node, Message *msg)
{
    // Received a route-advertisement packet from UDP.  When received,
    // route advertisements from triggered and periodic updates are
    // treated the same way.

    Bellmanford *bellmanford = (Bellmanford *) node->appData.bellmanford;

    RoutingBellmanfordHeader *header;
    AdvertisedRoute *payload;
    int numAdvertisedRoutes;
    UdpToAppRecv *info = (UdpToAppRecv *) MESSAGE_ReturnInfo(msg);
    int incomingInterfaceIndex = info->incomingInterfaceIndex;

    // If bellmanford is not configured here, then discard message.
    if (!bellmanford)
    {
        return;
    }

    ActionData acnData;
    acnData.actionType = RECV;
    acnData.actionComment = NO_COMMENT;
    TRACE_PrintTrace(node, msg, TRACE_APPLICATION_LAYER, PACKET_IN, &acnData);

    // Increment stat for number of route-advertisement packets
    // received.

    bellmanford->numRouteAdvertisementsReceived++;

    // Obtain pointers to header, payload.

    header = (RoutingBellmanfordHeader *) msg->packet;
    payload = (AdvertisedRoute *)
              (msg->packet + sizeof(RoutingBellmanfordHeader));

    // Obtain number of rows in update.

    numAdvertisedRoutes = header->payloadSize / sizeof(AdvertisedRoute);

#ifdef DEBUG
    {
        char address[MAX_STRING_LENGTH];

        IO_ConvertIpAddressToString(header->sourceAddress,address);
        printf("Bellmanford: %s s, node %u, RCV Route broadcast, "
               "Received packet from UDP, src %s\n",
               TIME_PrintClockInSecond(node->getNodeTime()).c_str(), node->nodeId, address);
    }
#endif // DEBUG

#pragma region  // JSLS添加: 【步骤①】获取源节点[发送节点]的 节点ID[NodeID]
	int sendNodeID = -1;
	sendNodeID = msg->originatingNodeId;
	printf("JSLS: sendNodeID = %d \n", sendNodeID);
	printf("        recvNodeID = %d \n", node->nodeId);
#pragma endregion // JSLS添加: 【步骤①】获取源节点[发送节点]的 节点ID[NodeID]
	

#pragma region // JSLS添加: 【步骤②】找到[发送节点],以便后续计算【[发送节点]与[接收节点]之间的物理距离】,用于 更新路由表中的路由距离[distance]
	// JSLS添加:根据[NodeId]找到 Node* 指针
	//            参考:《 C:\Scalable\Exata6.2Source__DEBUG_1\libraries\cyber\advanced\src\app_modify_packet.cpp 》
	//                   第149行:
	//                    // get node pointer
	//                   success = PARTITION_ReturnNodePointer(partition, &node, nodeId, TRUE);
	bool success = FALSE;
	Node *sendNode = NULL; //JSLS备注:[发送节点]指针,用于后续计算[发送节点]和[目的节点]之间的距离
	success = PARTITION_ReturnNodePointer(node->partitionData, 
		&sendNode, 
		sendNodeID, 
		TRUE);
	printf("JSLS: sendNode = 0x%x \n", ((unsigned int)sendNode));

#pragma endregion // JSLS添加: 【步骤②】找到[发送节点],以便后续计算【[发送节点]与[接收节点]之间的物理距离】,用于 更新路由表中的路由距离[distance]


#pragma region // JSLS添加:【步骤③】计算【[发送节点]与[接收节点]之间的物理距离】,用于 更新路由表中的路由距离
	// 需要用到《 C:\Scalable\Exata6.2Source__DEBUG_1\include\coordinates.h 》的 
	//          第493行:
						/*
						BOOL COORD_CalcDistance(
							int coordinateSystemType,
							const Coordinates* position1,
							const Coordinates* position2,
							CoordinateType* distance);
						*/

	double distanceBetweenTwoNodes;  // 单位:米。后续需要转化为 ㎞ 千米。
	Coordinates sendNodePosition; // 发送节点 的 坐标位置
	Coordinates recvNodePosition; // 接收节点 的 坐标位置
	MOBILITY_ReturnCoordinates(sendNode, &sendNodePosition);
	MOBILITY_ReturnCoordinates(node, &recvNodePosition);
	printf("JSLS: sendNodePosition and recvNodePosition have been got! \n");
	COORD_CalcDistance(NODE_GetTerrainPtr(node)->getCoordinateSystem(),
		&sendNodePosition,
		&recvNodePosition,
		&distanceBetweenTwoNodes);
	printf("JSLS: The distance from [sendNodePosition] to [recvNodePosition] is %f \n", distanceBetweenTwoNodes);
	std::cout.flush();  // "stdio.h"
	
	// JSLS备注: [COORD_CalcDistance]计算出来的距离单位是 米 。后续作为【路由距离度量】时需要用 千米(㎞)
	int distance_in_km = 0;
	distance_in_km = (int)(distanceBetweenTwoNodes / 1000);
	if (0 == distance_in_km) //假如 两个节点之间距离【不够】 1㎞,设置为 1㎞。
	{
		distance_in_km = 1;
	}
	if (32767 < distance_in_km) //假如 两个节点之间距离【大于】 32767㎞,★这是 short 类型的 最大正数值★,设置为 -1㎞,表示越界。
	{
		distance_in_km = -1;  // JSLS@2023年8月11日:暂且假设 两颗卫星路由器之间距离 小于3.2767万㎞ 。否则,设置为 -1 表示越界。
	}

	///
	// JSLS特别备注:★复用 Node->numAtmInterfaces 字段 ★ →→→ 用于存储[distance_in_km],即【路由距离度量(㎞)】
	//                  表示 node接收节点 与 【(发送路由公告)的发送节点】之间的【路由距离度量(㎞)】
	///
	node->numAtmInterfaces = distance_in_km; // ★复用 Node->numAtmInterfaces 字段 ★ 表示【路由距离度量(㎞)】

#pragma endregion // JSLS添加:【步骤③】计算【[发送节点]与[接收节点]之间的物理距离】,用于 更新路由表中的路由距离



    // Process the route-advertisement packet.
    ProcessRouteAdvertisementPacket(
        node,
        header->sourceAddress,
        incomingInterfaceIndex,
        numAdvertisedRoutes,
        payload);


	///
	// JSLS特别备注:★一定记得还要【解除复用】 Node->numAtmInterfaces 字段 ★ →→→ 重新设置为 0
	///
	node->numAtmInterfaces = 0; // ★【解除复用】 Node->numAtmInterfaces 字段 ★ →→→ 重新设置为 0

}

//-----------------------------------------------------------------------------
// FUNCTION     ProcessRouteAdvertisementPacket
// PURPOSE      Processes a route broadcast packet from UDP.
//
// Parameters:
//
// Node *node
//     For current node.
// NodeAddress neighborAddress
//     IP address of broadcasting node.
// int numAdvertisedRoutes
//     Number of rows in broadcasted route table.
// AdvertisedRoute *neighborRowPtr
//     Pointer to broadcasted route table.
//
// Notes:
//
// Each row in the broadcasted route table is looked at, and the
// local route table is updated appropriately.  The IP forwarding
// table is also updated, and a triggered update may be scheduled.
//-----------------------------------------------------------------------------

static void //inline//
ProcessRouteAdvertisementPacket(
    Node *node,
    NodeAddress neighborAddress,
    int incomingInterfaceIndex,
    int numAdvertisedRoutes,
    AdvertisedRoute *neighborRowPtr)
{
    Bellmanford *bellmanford = (Bellmanford *) node->appData.bellmanford;

    int i;
    int j;
    BOOL routeChanged;
    NodeAddress destAddress;
    NodeAddress subnetMask;
    BOOL newRoute;

    // Dynamic Address
    NetworkDataIp* ip =  node->get_networkVar();

    BOOL wasFound;

    routeChanged = FALSE;

#ifdef DEBUG

    // Print update vector from route broadcast.

    PrintRouteAdvertisementPacket(
         node,
         neighborRowPtr,
         numAdvertisedRoutes);

#endif // DEBUG

    for (i = 0; i < numAdvertisedRoutes; i++)
    {
        Route *rowPtr;

        destAddress = neighborRowPtr[i].destAddress;
        subnetMask = neighborRowPtr[i].subnetMask;

        // Skip routes that are for a directly connected network
        // (for point-to-point interfaces), or to oneself
        // (all other interface types).

        wasFound = FALSE;
        for (j = 0; j < node->numberInterfaces; j++)
        {
            if (NetworkIpIsWiredNetwork(node, j))
            {
                if (NetworkIpGetInterfaceNetworkAddress(node, j)
                        == destAddress
                    && NetworkIpGetInterfaceSubnetMask(node, j)
                        == subnetMask)
                {
                    // Skip this route.  Node doesn't need to update
                    // for directly connected network.

                    wasFound = TRUE;
                    break;
                }
            }
            else
            {
                if (NetworkIpGetInterfaceAddress(node, j) == destAddress)
                {
                    // Skip this route.  Node doesn't need to update
                    // route to self.

                    wasFound = TRUE;
                    break;
                }
            }
        }
        if (wasFound)
        {
            continue;
        }

        wasFound = FALSE;
        for (j = 0; j < node->numberInterfaces; j++)
        {
            if (NetworkIpGetInterfaceAddress(node, j)
                == neighborRowPtr[i].nextHop)
            {
                // Split horizon with poisoned reverse.

                neighborRowPtr[i].distance = BELLMANFORD_INFINITY;
                wasFound = TRUE;
                break;
            }
        }

        if (!wasFound)
        {
			/* // 原始代码
			// Increment hop count (one hop from neighbor to this node).
			if (neighborRowPtr[i].distance < BELLMANFORD_INFINITY)
			{
			neighborRowPtr[i].distance++;
			}
			*/

#pragma region // JSLS添加:根据【[源节点]到[目的节点]的距离】更新路由表 
			// JSLS添加:更新路由表时,不是简单地将[distance]路由距离 增加1 ,
			//                          而是“增加”【[源节点]到[目的节点]的距离】,
			//            其中,[源节点]用【 msg->originatingNodeId 】来识别。
			// //
			// [源节点]用【 msg->originatingNodeId 】来识别  请参考:
			//     《 C:\Scalable\Exata6.2Source__DEBUG_1\core\mac\mac.cpp 》
			//      第 5792 行:
					/*
						printf("Node %d (time %s) received a packet of size %d "
						"originated from node %d at time %15" TYPES_64BITFMT
						"d from PHY\n", node->nodeId, TIME_PrintClockInSecond(node->getNodeTime()).c_str(),
						MESSAGE_ReturnPacketSize(packet), packet->originatingNodeId, packet->packetCreationTime);
					*/
			
			/*	从复用的 Node->numAtmInterfaces 字段,提取【路由距离度量(㎞)】
	///
	// JSLS特别备注:★复用 Node->numAtmInterfaces 字段 ★ →→→ 用于存储[distance_in_km],即【路由距离度量(㎞)】
	//                  表示 node接收节点 与 【(发送路由公告)的发送节点】之间的【路由距离度量(㎞)】
	///
	node->numAtmInterfaces = distance_in_km; // ★复用 Node->numAtmInterfaces 字段 ★ 表示【路由距离度量(㎞)】
			*/
			// JSLS修改:从复用的 Node->numAtmInterfaces 字段,提取【路由距离度量(㎞)】
			//            表示 node接收节点 与 【(发送路由公告)的发送节点】之间的【路由距离度量(㎞)】。
            if (neighborRowPtr[i].distance <= BELLMANFORD_INFINITY)
            {
				int distance_in_km__betweenTwoNodes = node->numAtmInterfaces; // numAtmInterfaces 字段 → 复用表示【路由距离度量(㎞)】
                neighborRowPtr[i].distance += distance_in_km__betweenTwoNodes;
			}
#pragma endregion // JSLS添加:根据【[源节点]到[目的节点]的距离】更新路由表 

        }

        // Get route that goes to the same destAddress.

        newRoute = FALSE;
        rowPtr = FindRoute(bellmanford, destAddress);
        if (rowPtr == NULL)
        {
            // Route to destAddress not present in route table.
            // This is a new route.

            newRoute = TRUE;
        }

        // Update/refresh route in route table if this is a new route,
        // an advertised route has a better metric, or if the sending
        // node is a route's next hop.

        if (newRoute
            || neighborRowPtr[i].distance < rowPtr->distance
            || neighborAddress == rowPtr->nextHop 
            // Dynamic address
            && ip->interfaceInfo[incomingInterfaceIndex]->addressState
            != INVALID)
        {
            if (newRoute
                || neighborRowPtr[i].distance != rowPtr->distance
                || rowPtr->incomingInterface != incomingInterfaceIndex)
            {
#ifdef DEBUG_TABLE
                if (routeChanged == FALSE)
                {
                    // We have a route change resulting from this route
                    // broadcast, and will be updating our route table.

                    // Print update vector from route broadcast.

                    PrintRouteAdvertisementPacket(
                        node,
                        neighborRowPtr,
                        numAdvertisedRoutes);

                    // Print pre-update route table.

                    PrintRouteTable(
                        node,
                        ROUTING_BELLMANFORD_PRE_UPDATE);
                }
#endif // DEBUG_TABLE

                if (newRoute)
                {
                    rowPtr = AddRoute(
                        bellmanford,
                        destAddress,
                        subnetMask,
                        neighborAddress,
                        incomingInterfaceIndex,
                        neighborRowPtr[i].distance);
                }

                // Set new distance.

                rowPtr->distance = (short) neighborRowPtr[i].distance;

                // Set new interface
                rowPtr->incomingInterface = incomingInterfaceIndex;
                rowPtr->outgoingInterface = incomingInterfaceIndex;

                // Distance metric has changed (either increased or
                // decreased).  Set routeChanged flag for this route
                // so that the route is later sent on a triggered
                // update.

                rowPtr->changed = TRUE;
                if (routeChanged == FALSE)
                {
                    routeChanged = TRUE;
                }
            }//if//

            // Set nextHop to the sender of the route broadcast, unless
            // the distance advertised is infinity, in which case the
            // nextHop is NETWORK_UNREACHABLE.

            if (neighborRowPtr[i].distance == BELLMANFORD_INFINITY)
            {
                rowPtr->nextHop = (unsigned) NETWORK_UNREACHABLE;
            }
            else
            {
                rowPtr->nextHop = neighborAddress;
            }

            // Route is refreshed.

            rowPtr->refreshTime = node->getNodeTime();

            // Update forwarding table.

            NetworkUpdateForwardingTable(
                node,
                destAddress,
                subnetMask,
                rowPtr->nextHop,
                rowPtr->outgoingInterface,
                rowPtr->distance,
                ROUTING_PROTOCOL_BELLMANFORD);
        }//if//
    }//for//

    // If a route has changed, call function which determines whether
    // to schedule a triggered update.

    if (routeChanged == TRUE)
    {
#ifdef DEBUG
#ifndef DEBUG_TABLE
        printf("Bellmanford: %s s, node %u, --- Route table updated\n",
            TIME_PrintClockInSecond(node->getNodeTime()).c_str(), node->nodeId);
#endif // DEBUG_TABLE
#endif // DEBUG
#ifdef DEBUG_TABLE
        // If the table was updated, print post-update route table.

        PrintRouteTable(
            node,
            ROUTING_BELLMANFORD_POST_UPDATE);
#endif // DEBUG_TABLE
        ScheduleTriggeredUpdate(node);
    }
#ifdef DEBUG
    else
    {
        printf("Bellmanford: %s s, node %u, --- Route table not changed\n",
            TIME_PrintClockInSecond(node->getNodeTime()).c_str(), node->nodeId);
#ifdef DEBUG_TABLE
        // If the table was updated, print post-update route table.

        PrintRouteTable(
            node,
            ROUTING_BELLMANFORD_POST_UPDATE);
#endif // DEBUG_TABLE
    }
#endif // DEBUG
}

//-----------------------------------------------------------------------------
// Route table manipulation functions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// FUNCTION     InitRouteTable
// PURPOSE      Initializes a route table.
//
// Parameters:
//
// Bellmanford *bellmanford
//     Pointer to Bellman-Ford state information.
//
// Notes:
//
// This function was designed to be run only once.
// (no re-initializing the route table!)
//-----------------------------------------------------------------------------

static void //inline//
InitRouteTable(
    Bellmanford *bellmanford)
{
    // Allocate route table.

    bellmanford->routeTable =
        (Route *) MEM_malloc(NUM_INITIAL_ROUTES_ALLOCATED * sizeof(Route));

    bellmanford->numRoutesAllocated = NUM_INITIAL_ROUTES_ALLOCATED;
    bellmanford->numRoutes = 0;

    bellmanford->nextPeriodicUpdateTime = 0;
    bellmanford->triggeredUpdateScheduled = FALSE;
}

//-----------------------------------------------------------------------------
// FUNCTION     FindRoute
// PURPOSE      Finds a route for an IP address.
//
// Parameters:
//
// Bellmanford *bellmanford
//     Pointer to Bellman-Ford state information.
// NodeAddress destAddress
//     IP address to find route for.
//
// Returns:
//
// A pointer to the row that matches destAddress.  If a row was not found,
// NULL is returned.
//-----------------------------------------------------------------------------

static Route * //inline//
FindRoute(
    Bellmanford *bellmanford,
    NodeAddress destAddress)
{
    int top;
    int bottom;
    int middle;
    Route *rowPtr;

    // Set row = NULL if cannot find row.
    // Otherwise set row to the matching one.

    if (bellmanford->numRoutes == 0)
    {
        return NULL;
    }

    top = 0;
    bottom = bellmanford->numRoutes - 1;
    middle = (bottom + top) / 2;

    if (destAddress == bellmanford->routeTable[top].destAddress)
    {
        return &bellmanford->routeTable[top];
    }
    if (destAddress == bellmanford->routeTable[bottom].destAddress)
    {
        return &bellmanford->routeTable[bottom];
    }

    while (middle != top)
    {
        rowPtr = &bellmanford->routeTable[middle];
        if (destAddress == rowPtr->destAddress)
        {
            return rowPtr;
        }
        else
        if (destAddress < rowPtr->destAddress)
        {
            bottom = middle;
        }
        else
        {
            top = middle;
        }

        middle = (bottom + top) / 2;
    }

    return NULL;
}

//-----------------------------------------------------------------------------
// FUNCTION     AddRoute
// PURPOSE      Adds a route to the route table.
//
// Parameters:
//
// Bellmanford *bellmanford
//     Pointer to Bellman-Ford state information.
// NodeAddress destAddress
//     IP address to add route for.
// NodeAddress subnetMask
//     Subnet mask for the route.
// NodeAddress nextHop
//     IP address of the next hop for the route.
// int distance
//     Distance metric (number of hops) for the route.
//
// Returns:
//
// Pointer to newly-added route.
//
// Notes:
//
// Adding a duplicate route will cause an assertion failure.  Two routes
// with the same destAddress but different subnetMasks is included in
// this limitation. -- Always check if a route exists with the
// ...FindRoute() first, unless it's known that the route doesn't exist.
//-----------------------------------------------------------------------------

static Route * //inline//
AddRoute(
    Bellmanford *bellmanford,
    NodeAddress destAddress,
    NodeAddress subnetMask,
    NodeAddress nextHop,
    int incomingInterfaceIndex,
    int distance)
{
    int index;

    // There should only be one row per unique destination address.

    // Check if the table has been filled.

    if (bellmanford->numRoutes == bellmanford->numRoutesAllocated)
    {
        Route *oldTable;
        int i;

        // Table filled:  Double route table size.

        oldTable = bellmanford->routeTable;
        bellmanford->routeTable = (Route *)
            MEM_malloc(2 * bellmanford->numRoutesAllocated
                              * sizeof(Route));
        for (i = 0; i < bellmanford->numRoutes; i++)
        {
            bellmanford->routeTable[i] = oldTable[i];
        }
        MEM_free(oldTable);
        bellmanford->numRoutesAllocated *= 2;
    }

    // Insert route.

    index = bellmanford->numRoutes;
    bellmanford->numRoutes++;
    while (1)
    {
        if (index != 0
            && destAddress <= bellmanford->routeTable[index - 1].destAddress)
        {
            if (destAddress == bellmanford->routeTable[index - 1].destAddress)
            {
                // Duplicate entry.

                ERROR_ReportError("Cannot add duplicate route");
            }

            bellmanford->routeTable[index] = bellmanford->routeTable[index - 1];
            index--;
            continue;
        }

        bellmanford->routeTable[index].destAddress = destAddress;
        bellmanford->routeTable[index].subnetMask  = subnetMask;
        bellmanford->routeTable[index].nextHop     = nextHop;
        bellmanford->routeTable[index].incomingInterface =
            incomingInterfaceIndex;
        bellmanford->routeTable[index].outgoingInterface =
            incomingInterfaceIndex;

        bellmanford->routeTable[index].distance    = (short) distance;
        bellmanford->routeTable[index].localRoute  = FALSE;

        bellmanford->routeTable[index].refreshTime = 0;
        bellmanford->routeTable[index].changed     = FALSE;
        bellmanford->routeTable[index].isPermanent =  FALSE;

        return &bellmanford->routeTable[index];
    }
}

//-----------------------------------------------------------------------------
// Statistics
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// FUNCTION     PrintStats
// PURPOSE      Prints statistics for Bellman-Ford.
//
// Parameters:
//
// Node *node
//     For current node.
//
// Notes:
//
// Called by RoutingBellmanFordFinalize(), only for interfaceIndex 0.
//
// Note that when an update is sent, it is sent on all interfaces;
// this event is counted as a single periodic update, even though a
// packet is sent out on each interface.  Received updates, on the other
// hand, are counted once per packet received.)
//-----------------------------------------------------------------------------

static void //inline//
PrintStats(Node *node)
{
    Bellmanford *bellmanford = (Bellmanford *)node->appData.bellmanford;

    char buf[MAX_STRING_LENGTH];

    sprintf(buf, "Number of periodic updates sent = %d",
            bellmanford->numPeriodicUpdates);
    IO_PrintStat(node, "Application", "Bellman-Ford", ANY_DEST, -1, buf);

    sprintf(buf, "Number of triggered updates sent = %d",
            bellmanford->numTriggeredUpdates);
    IO_PrintStat(node, "Application", "Bellman-Ford", ANY_DEST, -1, buf);

    sprintf(buf, "Number of route timeouts = %d",
            bellmanford->numRouteTimeouts);
    IO_PrintStat(node, "Application", "Bellman-Ford", ANY_DEST, -1, buf);

    sprintf(buf, "Number of update packets received = %d",
            bellmanford->numRouteAdvertisementsReceived);
    IO_PrintStat(node, "Application", "Bellman-Ford", ANY_DEST, -1, buf);
}

//-----------------------------------------------------------------------------
// Debug output functions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// FUNCTION     PrintRouteAdvertisementPacket
// PURPOSE      Prints to screen the contents of a route advertisement
//              packet (an "update vector").
//
// Parameters:
//
// Node *node
//     For current node.
// AdvertisedRoute *neighborRowPtr
//     Pointer to update vector.
// int numAdvertisedRoutes
//     Number of rows in update vector.
//-----------------------------------------------------------------------------

static void //inline//
PrintRouteAdvertisementPacket(
    Node *node,
    AdvertisedRoute *neighborRowPtr,
    int numAdvertisedRoutes)
{
    int i;

    printf("Bellmanford: %s s, node %u, --- Update vector, "
        "(dest nextHop dist)\n", TIME_PrintClockInSecond(node->getNodeTime()).c_str(), node->nodeId);

    for (i = 0; i < numAdvertisedRoutes; i++)
    {

        char address[MAX_STRING_LENGTH];
        IO_ConvertIpAddressToString(neighborRowPtr[i].destAddress, address);
        printf("Bellmanford:\t%s", address);

        if (neighborRowPtr[i].nextHop == (unsigned) NETWORK_UNREACHABLE)
        {
            printf("\t-");
        }
        else
        {
            IO_ConvertIpAddressToString(neighborRowPtr[i].nextHop, address);
            printf("\t%s", address);
        }

        printf("\t%d\n", neighborRowPtr[i].distance);
    }
}

//-----------------------------------------------------------------------
// FUNCTION     PrintRouteTable
// PURPOSE      Prints to screen the local route table.
//
// Parameters:
//
// Node *node
//     For current node.
// PrintRouteTableType type
//     ROUTING_BELLMANFORD_PRE_UPDATE
//     or,
//     ROUTING_BELLMANFORD_POST_UPDATE
//
// Notes:
//
// Prints the local route table.  The "pre" and "post" options are used
// to print to the screen whether the contents of the route table were
// before or after processing an update vector.
//------------------------------------------------------------------------

static void //inline//
PrintRouteTable(
    Node *node, PrintRouteTableType type)
{
    Bellmanford *bellmanford = (Bellmanford *) node->appData.bellmanford;

    int i;

    printf("Bellmanford: %s s, node %u, ",
        TIME_PrintClockInSecond(node->getNodeTime()).c_str(), node->nodeId);

    if (type == ROUTING_BELLMANFORD_PRE_UPDATE)
    {
        printf("--- Pre-update route table, (dest nextHop dist)\n");
    }
    else
    if (type == ROUTING_BELLMANFORD_POST_UPDATE)
    {
        printf("--- Post-update route table, (dest nextHop dist)\n");
    }
    else
    {
        printf("--- Post-update Route table, (dest nextHop dist)\n");
    }

    for (i = 0; i < bellmanford->numRoutes; i++)
    {
        char address[MAX_STRING_LENGTH];
        IO_ConvertIpAddressToString(bellmanford->routeTable[i].destAddress, address);
        printf("Bellmanford:\t%s",address);

        if (bellmanford->routeTable[i].nextHop
            == (unsigned) NETWORK_UNREACHABLE)
        {
            printf("\t-");
        }
        else
        {
            IO_ConvertIpAddressToString(bellmanford->routeTable[i].nextHop, address);
            printf("\t%s", address);
        }

        printf("\t%d\n", bellmanford->routeTable[i].distance);
    }
}
//-----------------------------------------------------------------------------
// FUNCTION BellmanfordHookToRedistribute
// PURPOSE      Update or add the redistributed
//              routes into Bellmanford routing table.
// PARAMETERS   Node *node
//                  Pointer to node.
//              NodeAddress destAddress
//                  IP address of destination network or host.
//              NodeAddress destAddressMask
//                  Netmask.
//              NodeAddress nextHopAddress
//                  Next hop IP address.
//              int interfaceIndex
//                    The specify the routing protocol
//              void* routeCost
//                  Metric associate with the route
// RETURN: None
//----------------------------------------------------------------------------
void
BellmanfordHookToRedistribute(
    Node* node,
    NodeAddress destAddress,
    NodeAddress destAddressMask,
    NodeAddress nextHopAddress,
    int interfaceIndex,
    void* routeCost)
{

    Route* routePtr = NULL;
    int cost =  *(int*) routeCost;

    Bellmanford* bellmanford = (Bellmanford*)node->appData.bellmanford;

    routePtr = FindRoute(
                   bellmanford,
                   destAddress);
    if (routePtr != NULL)
    {
        return;
    }

    routePtr = AddRoute(
                    bellmanford,
                    destAddress,
                    destAddressMask,
                    nextHopAddress,
                    interfaceIndex,
                    (unsigned) cost);

     if (routePtr != NULL)
     {
      // We set this flag so that the route doesnt get time out
         routePtr->isPermanent = TRUE;
     }
}

// Dynamic address

//---------------------------------------------------------------------------
// FUNCTION   :: RoutingBellmanfordHandleChangeAddressEvent
// PURPOSE    :: Handles any change in the interface address for Bellmanford
// PARAMETERS ::
// + node               : Node* : Pointer to Node structure
// + interfaceIndex     : Int32 : interface index
// + oldAddress         : Address* : current address
// + subnetMask         : NodeAddress : subnetMask
// + networkType        : NetworkType : type of network protocol
// RETURN :: void : NULL
//---------------------------------------------------------------------------

void RoutingBellmanfordHandleChangeAddressEvent(
    Node* node,
    Int32 interfaceIndex,
    Address* oldAddress,
    NodeAddress subnetMask,
    NetworkType networkType)
{
    // Get the Bellmanford data structure
    Bellmanford* bellmanford =
           (Bellmanford*)node->appData.bellmanford;

    NetworkDataIp* ip = node->get_networkVar();
    IpInterfaceInfoType* interfaceInfo =
                      ip->interfaceInfo[interfaceIndex];

    // If Bellmanford is not configured on this interface, because
    // adress change handler function is registered at node level
    if (interfaceInfo->routingProtocolType != ROUTING_PROTOCOL_BELLMANFORD)
    {
        return;
    }

    // Bellmanford is only supported for IPv4
    if (networkType == NETWORK_IPV6 )
    {
        return;
    }
    // currently interface address state is invalid, hence no need to update
    // tables as no communication can occur from this interface while the 
    // interface is in invalid address state
    if (interfaceInfo->addressState  == INVALID )
    {
        return;
    }

    if (networkType == NETWORK_IPV4 || networkType == NETWORK_DUALIP)
    {
        NodeAddress destAddress;
        NodeAddress subnetMask;
        Route* rowPtr;

        if (NetworkIpIsWiredNetwork(node, interfaceIndex))
        {
            // This is a wiredlink interface.
            // The destAddress is the current network
            // address for the interface,
            // and subnetMask is the current subnet mask for the interface.

            destAddress = NetworkIpGetInterfaceNetworkAddress(
                                                            node,
                                                            interfaceIndex);
            subnetMask = NetworkIpGetInterfaceSubnetMask(node,
                                                         interfaceIndex);
        }
        else
        {
            // This is a wireless interface.
            // The destAddress is the IP address of the interface
            // itself, and subnetMask is 255.255.255.255 (ANY_DEST is
            // an all-one 32-bit value).
            // This means that the route applies exactly to the host IP
            // address of the interface. (not to a network address)

            destAddress = NetworkIpGetInterfaceAddress(node, interfaceIndex);
            subnetMask = ANY_DEST;
        }

        // Update forwarding table to inclue new interface address
        NetworkUpdateForwardingTable(
                            node,
                            destAddress,
                            subnetMask,
                            0,
                            interfaceIndex,
                            1,
                            ROUTING_PROTOCOL_DEFAULT);

        // Update the routing table of bellmanford such that the
        // new address is advertised in updates
        if (!FindRoute(bellmanford, destAddress))
        {
            rowPtr = AddRoute(bellmanford,
                              destAddress,
                              subnetMask,
                              NetworkIpGetInterfaceAddress(node, 
                                                           interfaceIndex),
                              interfaceIndex,
                              0);

            rowPtr->localRoute = TRUE;
            rowPtr->changed = TRUE;
        }
    }
}

毅哥铡特仿真动画:注意仿真画布长宽设置大一些,仿真时间设置长一点,发送的测试应用CBR数据多一些。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/865606.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenEuler 上安装redis服务

访问redis的下载地址 Index of /releases/地址&#xff1a;Index of /releases/ 选择对应的版本。我选择5.0的版本。 下载对应的版本redis wget https://download.redis.io/releases/redis-5.0.8.tar.gz 解压 redis tar -zxvf redis-5.0.9.tar.gz 进入redis目录 cd redis-5…

使用 VScode 开发 ROS 的Python程序(简例)

一、任务介绍 本篇作为ROS学习的第二篇&#xff0c;是关于如何在Ubuntu18.04中使用VSCode编写一个Python程序&#xff0c;输出“Hello&#xff01;”的内容介绍。 首先我们来了解下ROS的文件系统&#xff0c;ROS文件系统级指的是在硬盘上ROS源代码的组织形式&#xff0c;其结构…

不用技术代码,如何制作成绩查询系统?

为了解决学校无力承担传统学生考试成绩查询平台的高昂费用&#xff0c;老师们可以考虑使用易查分这样的工具来免费制作一个学生考试成绩查询平台。易查分是一种简单易用的在线成绩查询系统&#xff0c;可以帮助老师们快速创建一个个性化的学生考试成绩查询平台。 使用易查分制作…

水库大坝安全监测系统实施方案

一、方案概述 水库大坝作为特殊的建筑&#xff0c;其安全性质与房屋等建筑物完全不同&#xff0c;并且建造在地质构造复杂、岩土特性不均匀的地基上&#xff0c;目前对于大坝监测多采用人工巡查的方法&#xff0c;存在一定的系统误差&#xff0c;其工作性态和安全状况随时都在变…

【PCIE体系结构十六】PCIE电源管理之ASPM

&#x1f449;个人主页&#xff1a;highman110 &#x1f449;作者简介&#xff1a;一名硬件工程师&#xff0c;持续学习&#xff0c;不断记录&#xff0c;保持思考&#xff0c;输出干货内容 参考书籍&#xff1a;《PCI.EXPRESS系统体系结构标准教材 Mindshare》 PCIe总线…

若依部署前后端

打包项目 前端打包 npm run build:prod将代码上传到指定目录 配置nginx转发 server{listen 8090;server_name localhost;location / {root /home/cc_library/dist;index index.html index.htm;# 配置 history模式&#xff0c;刷新页面会404&#xff0c;&#xff0c;因为服…

语音同声翻译软件助你跨越语言障碍

嘿&#xff0c;你在日常工作中是否曾经参加过跨国会议&#xff0c;是否也曾由于语言不通而感到尴尬&#xff1f;别担心&#xff0c;因为现在有了会议实时翻译软件&#xff0c;这些问题都将成为过去式&#xff01;那么你知道会议实时翻译的软件有哪些吗&#xff1f;接下来就让我…

JavaScript基础 第五天

1.什么是对象以及对象的基本使用 2.对象的操作 --增删改查 3.对象的方法 4.数学内置对象 5.简单数据类型和引用数据类型 一.什么是对象以及对象的基本使用 ① 对象是什么 可以理解为一种无序的数据集合&#xff0c;数组是有序的数据集合对象通常用来描述某个事物&#x…

springboot+mybatis+mybatis-plus对crud项目进行改进

springbootmybatis实现简单的增、删、查、改https://blog.csdn.net/heyl163_/article/details/132197201上一篇文章&#xff0c;已经详细地介绍了怎么通过springboot项目整合mybatis实现简单的数据库表的增删改查功能&#xff0c;是最简单的springboot项目的结构。所以有很多问…

FinClip | 7月做出了一些微不足道的贡献

FinClip 的使命是使您&#xff08;业务专家和开发人员&#xff09;能够通过小程序解决关键业务流程挑战&#xff0c;并完成数字化转型的相关操作。不妨让我们看看在本月的产品与市场发布亮点&#xff0c;看看是否有助于您实现目标。 产品方面的相关动向&#x1f447;&#x1f…

Python中的排序

一、列表排序 举例sort和sorted对列表排序&#xff0c;说明两者的区别。 import relist1 [0, -1, 3, -10, 5, 9] list1.sort(reverseFalse) print(list1.sort在list1基础上修改&#xff0c;无返回值, list1) list2 [0, -1, 3, -10, 5, 9] res sorted(list2, reverseFalse)…

团队管理之PDP大法

PDP 是什么&#xff0c;为什么有些人会谈PDP色变呢&#xff1f;人常常会对自己不了解的东西感到恐惧 一、什么是PDP 团队管理中的PDP可能指"Personal Development Plan"&#xff08;个人发展计划&#xff09;&#xff0c;它是一种用于帮助团队成员提升个人能力和达成…

leetcode 面试题 02.07. 链表相交

题目&#xff1a;leetcode 面试题 02.07. 链表相交 描述&#xff1a; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 思路&…

ARP请求拦截及响应

一、前言 本文主要是介绍如何对arp请求包进行拦截&#xff0c;并代替系统进行响应。对arp请求进行拦截&#xff0c;需要在驱动中进行&#xff0c;具体代码如下文所示。&#xff08;本文仅供参考&#xff09; 二、环境 OS Ubuntu 20.04.6 LTSLinux ubuntu 5.15.0-71-generic三…

Java培训班出来能找到工作吗?有没有想详细了解的呢

参加Java培训班可以提升你的编程技能和就业竞争力&#xff0c;但能否找到工作还取决于多个因素&#xff0c;如个人能力、市场需求、就业竞争等。参加Java培训班可以帮助你获得系统的Java编程知识和实践经验&#xff0c;了解行业最佳实践和流行的技术框架。这有助于你在面试时展…

SpringBoot案例-部门管理-删除

目录 查看页面原型&#xff0c;明确需求 页面原型 需求 阅读接口文档 思路分析 功能接口开发 控制层&#xff08;Controllre类&#xff09; 业务层&#xff08;Service类&#xff09; 持久层&#xff08;Mapper类&#xff09; 接口测试 前后端联调 查看页面原型&a…

Linux进程管理命令

一、进程 程序由一条条指令构成&#xff0c;在运行一个程序的时候就是把这些指令从第一条执行到最后一条&#xff0c;而进程是一个正在运行的程序。 比如说&#xff0c;一个main.c文件是不可以直接运行的&#xff0c;对main.c进行编译链接之后生成一个main.exe&#xff08;在W…

QT学习笔记-QT安装oracle oci驱动

QT学习笔记-QT安装oracle oci驱动 0、背景1、环境以及条件说明2、编译驱动2.1 下载oracle instant client2.2 编译qt oci驱动2.2.1 修改oci.pro2.2.2 MinGW64构建套件编译2.2.3 MSVC2019_64构建套件编译 3、访问数据库运行成功 0、背景 在使用QT开发应用的过程中&#xff0c;往…

Mysql SUBSTRING_INDEX - 按分隔符截取字符串

作用&#xff1a; 按分隔符截取字符串 语法&#xff1a; SUBSTRING_INDEX(str, delimiter, count) 属性&#xff1a; 参数说明str必需的。一个字符串。delimiter必需的。分隔符定义&#xff0c;是大小写敏感&#xff0c;且是多字节安全的count必须的。大于0或者小于0的数值…

案例分析丨大数据平台和应用测试,应该关注哪些点?

互联网的发展催生了大数据行业的诞生和发展。大数据平台和大数据应用成为了各家排兵布阵的重要之地。那么&#xff0c;从测试的视角来看&#xff0c;大数据平台和应用的测试&#xff0c;我们应该关注哪些点呢&#xff1f; 换个姿势看问题。今天我们从问题域的角度来聊一聊。 什…