天天看點

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;
    }
           

開啟路由引擎,主要的工作就是開啟一下定時器。這個定時器和路由幀的發送定時器不一樣,這個定時器的主要工作就是監聽路由表,然後不斷看看有沒有合适的新的父節點。

繼續閱讀