CTP源码分析8 CTP路由引擎结构及源码分析(二)----源码实现解读(一)

路由引擎的主要工作就是发送路由帧,更新路由表,并且从路由表中不断选出合适的父节点。路由帧的发送和LEEP帧是绑定的,根据涓流算法进行发送。

随着链路的稳定,计时器的计时间隔会逐渐增大,但是遇到链路拓扑需要变化的时候就要就要重置计时器间隔为最小。

路由引擎的主要实现在/tos/net/ctp/CtpRoutingEngineP.h中,下面看一看这个模块的全局变量:

bool ECNOff = TRUE;

    /* Keeps track of whether the radio is on. No sense updating or sending
     * beacons if radio is off */
    bool radioOn = FALSE;
    /* Controls whether the node's periodic timer will fire. The node will not
     * send any beacon, and will not update the route. Start and stop control this. */
    bool running = FALSE;
    /* Guards the beacon buffer: only one beacon being sent at a time */
    /*在发送的时间内置为TRUE*/
    bool sending = FALSE;

    /* Tells updateNeighbor that the parent was just evicted.*/
    bool justEvicted = FALSE;

    route_info_t routeInfo;
    bool state_is_root;
    am_addr_t my_ll_addr;


    message_t beaconMsgBuffer;
    ctp_routing_header_t* beaconMsg;

    /* routing table -- routing info about neighbors */
    routing_table_entry routingTable[routingTableSize];
    uint8_t routingTableActive;

    /* statistics */
    uint32_t parentChanges;
    /* end statistics */

    uint32_t routeUpdateTimerCount;
ECN这一位有点像一个使能位,这个使能位的主要作用就是为了让路由引擎可以工作,要不与节点阻塞有关的函数都没办法正常执行,如果ECN这个变量是true,那么就无法设置节点的阻塞状态,也无法查看节点的状态(永远是非阻塞)。

radioOn这个变量是查看无线是不是开启状态。running这个变量可以查看节点的计时器是不是可以在到期的时候激活相关逻辑,只有running置为true的时候才可以激活更新路由表的操作以及进行路由帧的发送,这个变量会在路由引擎开启的时候置为TRUE,关闭和初始化的时候置为FALSE。sending这个变量保证在同一时间只有一个路由帧处在发送状态,只要sending置为true,那么发送路由帧的动作就不能进行。justEvicted这个变量是用来告知路由表的更新函数父节点是不是刚刚有过更新。

routeinfo是当前节点的路由信息。state_is_root这个函数是用来声明这个一个节点是不是根节点,根节点在数据包转发方面会有不同的额外逻辑。my_ll_addr这个变量存的是的当前节点的地址。beaconMsgBuffer是储存路由帧的实际空间,beaconMsg是指向这个空间第一位的指针。routingTable是路由表。routingTableActive是实际上路由表的实际占用。parentChanges是这个是每次替换父节点的时候要自增,原因让我感到很恍惚,在源码中TOS给出了这样的提示:

routeInfo.metric will not store the composed metric.
since the linkMetric may change, we will compose whenever
we need it: i. when choosing a parent (here);
           ii. when choosing a next hop

一脸懵逼.jpg


我个人觉得这个变量的存在对CTP的整体逻辑并没有影响,因为在路由引擎的源码中,除了自增,并没有其他的操作,这个自增主要就是发生在路由引擎的父节点变化的时候。

routeUpdateTimerCount这个变量也是让人摸不着头脑,因为这个变量只有声明和初始化。然后在整个TOS的实现中就再也没有提及。


enum {
      DEATH_TEST_INTERVAL = (maxInterval * 4) / (BEACON_INTERVAL / 1024),
    };

    // forward declarations
    void routingTableInit();
    uint8_t routingTableFind(am_addr_t);
    error_t routingTableUpdateEntry(am_addr_t, am_addr_t , uint16_t);
    error_t routingTableEvict(am_addr_t neighbor);

    uint16_t currentInterval = minInterval;
    uint32_t t;
    bool tHasPassed;
currentInterval这个东西就是当前计时器的时间间隔,一开始当然是最小的时间间隔,t这个变量主要就是用来计算下一次时间间隔的变量,这个和涓流算法中的t意义相近。

tHasPassed这个变量是翻倍计时器的一个判断变量。在CTP中,涓流算法不太一样,在链路趋向于稳定的时候计时器不会立即翻倍(但是路由的更新还是做了),而是会把时间区间剩下的时间走完,然后再翻倍一下。这个会在后面提及。tHasPassed这个变量就是做这个工作的。

DEATH_TEST_INTERVAL这个枚举是一开始就开始就没有就有什么作用,在TOS源码中全局搜索,除了初始化之外就再也没有其他作用了。


以上就是路由引擎全局变量的概述。

void chooseAdvertiseTime() {
       t = currentInterval;
       t *= 512; // * 1024 / 2
       t += call Random.rand32() % t;
       tHasPassed = FALSE;
       call BeaconTimer.stop();
       call BeaconTimer.startOneShot(t);
    }
这个函数主要就是选择下一个计时的时间,涓流算法已经提及了细节,主要就是翻番。currentInterval是时间区间,t是“计时点”主要就是在这个时间区间的后半程随机展开。512可能是半毫秒的意思,因为currentInterval这个东西的单位可能是秒,但是因为t是一个毫秒的东西,所以实际上要用毫秒,都知道涓流算法就是在时间区间的后半部分截取一个毫秒的随机值,这个实际上就是执行了这个过程。首先将上一次时间区间的时间间隔(单位秒)变成毫秒然后除2,然后在时间的后半区加一个随机值,然后就可以用这个时间激活一个计时器了。

void resetInterval() {
      currentInterval = minInterval;
      chooseAdvertiseTime();
    }
这个函数可以重置一个定时器,将及时间隔置为最短。


    void decayInterval() {
      if (!state_is_root) {
        currentInterval *= 2;
        if (currentInterval > maxInterval) {
          currentInterval = maxInterval;
        }
      }
      chooseAdvertiseTime();
    }
这个函数是用来扩大计时器时间的,主要就是把时间区间翻倍,然后随机出一个新的时间节点t。


command error_t Init.init() {
        uint8_t maxLength;
        routeUpdateTimerCount = 0;
        radioOn = FALSE;
        running = FALSE;
        parentChanges = 0;
        state_is_root = 0;
        routeInfoInit(&routeInfo);
        routingTableInit();
        my_ll_addr = call AMPacket.address();
        beaconMsg = call BeaconSend.getPayload(&beaconMsgBuffer);
        maxLength = call BeaconSend.maxPayloadLength();
        dbg("TreeRoutingCtl","TreeRouting initialized. (used payload:%d max payload:%d!\n",
              sizeof(beaconMsg), maxLength);
        return SUCCESS;
    }
这个函数负责路由引擎的初始化。


command error_t StdControl.start() {
      if (!running) {
	running = TRUE;
	resetInterval();
	call RouteTimer.startPeriodic(BEACON_INTERVAL);
	dbg("TreeRoutingCtl","%s running: %d radioOn: %d\n", __FUNCTION__, running, radioOn);
      }
      return SUCCESS;
    }
开启路由引擎,主要的工作就是开启一下定时器。这个定时器和路由帧的发送定时器不一样,这个定时器的主要工作就是监听路由表,然后不断看看有没有合适的新的父节点。









你可能感兴趣的:(CTP源码分析)