1. 程式人生 > >《uCOS51移植心得》---七年前之《快快樂樂跟我學51微控制器作業系統和IP棧》 第六部分ARP協議實現原理

《uCOS51移植心得》---七年前之《快快樂樂跟我學51微控制器作業系統和IP棧》 第六部分ARP協議實現原理

ARP協議實現原理
          作者<[email protected]> 2002/11/01

    ARP是Address Resolution Protocol的縮寫。中文譯做“地址解析協議”,本質是完成網路地址到實體地址的對映。從概念上講就是找到一個對映方法f,使得“實體地址 = f(網路地址)”。實體地址有兩種基本型別:乙太網型別和proNET令牌環網型別,網路地址特指IP地址,對對映方法的要求就是高效。具體到乙太網,它使用的是動態繫結轉換的方法。為什麼不直接使用同一種地址,而要這麼麻煩呢?因為TCP/IP網路就是為將不同種類計算機互聯而發明的,它的體系結構是分層的,層和層之間相互獨立,改變物理層的實現不會影響到網路層。
    32位IP地址到乙太網48位實體地址的對映,採用動態繫結轉換的方法會遇到許多細節問題,例如:減少廣播,ARP包丟失,實體地址變更(更換網絡卡)、移動(移動裝置到另一子網)、消失(關機)等。一般是設定ARP快取記憶體,通過學習、老化、更新、溢位演算法處理ARP對映表來解決這些問題。其中,學習指ARP收到任何指向本節點IP地址的ARP/IP包,從中提取出地址對,而ARP快取中無對應項時,由ARP接收部分新增;老化指為每項設定壽命域,以便代謝掉陳舊的地址對映項;更新指ARP提取到新的地址對時,用其更新快取裡已有的對應項;溢位演算法指當快取滿時,採取何種方法替換舊有的地址對兒。
    我找到了幾個TCP/IP原始碼,對比他們的實現,深感差別巨大,靈活多變。有的程式碼未實現ARP快取,只用幾個全域性變數記錄源目的IP地址和源目的MAC地址,每次通訊前直接操作全域性變數,這在使用51微控制器,進行點對點通訊時不失為一個有效的方案;而有的程式碼龐大複雜,細節處理精益求精。比如實現了ARP快取記憶體、支援多址節點、支援網管檢視/動態改變ARP相關引數、重發處理、支援IPv6等。我的看法是:ARP的本質是地址轉換,只要抓住這個靈魂,設計的大方向就把握住了。具體實現過程各具特色,因人而異,沒有統一要求,有些功能可以不實現,有些優點不能兼得,而唯一不變的只有思想。
    我參考了幾種已有的IP協議棧並結合51微控制器的特點,實現了自己的基於uCOS51的TCP/IP協議棧方案。它只是一種具體的實現範例,不同的人有不同的設計方法。我保證自己的方案可以正常使用並具有較好的完備性。
   
    ------------------------------
    |狀態|壽命ttl|IP地址 |MAC地址|        學習
    ------------------------------
    |  0 |   FF  |X:X:X:X| XXXX  |  <---  老化
    ------------------------------
    |  0 |   FF  |X:X:X:X| XXXX  |        更新
    ------------------------------
           圖1 ARP快取表                  表滿處理
   
    如圖1所示,ARP快取表由狀態、壽命、IP地址、MAC地址4個欄位組成。狀態欄位指示地址對是否有效(0-空閒 1-佔用);壽命欄位用於老化操作,初始存入最大值,以後由OS時間函式呼叫,每秒減1,直至為0清除;IP地址和MAC地址欄位儲存網路地址和實體地址的對映。此處,沒有設計傳送資料鏈表首指標和重發記數字段,我把重發操作交給上層軟體統一處理,這是本程式的特色。圍繞ARP快取表,完成了4種操作:學習、老化、更新、表滿處理,詳見虛擬碼清單。使用OS的Shell命令ls可以檢視ARP表的內容,但不支援修改,這個功能對測試很有用。(顯示內容舉例如圖2所示)
   
    %ls
   
     ARP table:
     status     TTL      IP address      MAC address
     =================================================
       01        78     172.18.92.86     0050BABD4C7E
     
    %
              圖2 ARP快取表顯示內容舉例
              
   
             表滿處理
                |
                v                               ARP請求       
            ---------             ----------- ---------->
            |       |  學習/更新  |         | <- - - - -
    老化--->| ARP表 |<------------| ARP處理 |
            |       |             |         | - - - - - >
            ---------             ----------- <----------
                ^                               ARP應答
                |學習/更新
            ---------
            |       |
            | IP_in |
            |       |
            ---------
                        圖3 ARP處理過程
                        
    0                 8               16              24               31                    
    ---------------------------------------------------------------------
    |             硬體型別            |            協議型別             |
    ---------------------------------------------------------------------
    |硬體地址長度(HLEN)|協議長度(PLEN)|               操作              |
    ---------------------------------------------------------------------
    |                         傳送方首部(八位組0-3)                     |
    ---------------------------------------------------------------------
    |      傳送方首部(八位組4-5)      |      傳送方IP地址(八位組0-1)    |
    ---------------------------------------------------------------------
    |     傳送方IP地址(八位組2-3)     |        目標首部(八位組0-1)      |
    ---------------------------------------------------------------------
    |                         目標首部(八位組2-5)                       |
    ---------------------------------------------------------------------
    |                        目標IP地址(八位組0-3)                      |
    ---------------------------------------------------------------------
                                圖4 ARP包結構
   
    如圖3,整個ARP處理過程,我主要用5個函式實現。ARP初始化(ARP_init)、ARP請求(ARP_request)、ARP應答(ARP_answer)、ARP迴應處理(ARP_process)、IP包接收預處理(IP_in)。在實現網絡卡驅動程式後,所有ARP處理操作就是填寫ARP包(ARP包結構見圖4),詳見虛擬碼清單。
    ARP_init完成ARP表初始化,概括說就是ARP表state欄位清0。
    ARP_request完成ARP請求操作。ARP協議要求程式根據子網掩碼判斷IP地址是否屬於同一子網,如果在同一子網內,ARP請求目的MAC地址,否則請求預設閘道器MAC地址。
    ARP_answer比較簡單,只要交換ARP請求包地址內容,填寫自己的MAC地址和很少的改動後傳送即可。
    ARP_process完成ARP迴應回來的資訊處理。主要進行ARP表的學習和更新。
    IP_in完成IP包接收預處理,用於提取地址對映資訊,以便主動學習和及時更新。我的程式不會主動學習不是發給自己IP地址的MAC地址資訊,因為ARP表在51中的容量有限,只有頻繁用到的地址對才應該存放在裡面,否則一旦出現“顛簸”,ARP表就失效了。
    有的ARP實現方案採用資料驅動方式,引數可配置,使用統一的程式,通過載入不同的配置資料,執行不同的操作。這樣做使程式版本統一,不同的應用只要載入不同的配置資料即可,不用更換程式,有利於後期維護。但是考慮到51資源緊張和安全性,我的方案只能顯示ARP表不允許修改其內容,使用者可發揮想象力在此處增加新功能。另外,ARP程式應該記住上一次發過的請求,以避免重發,但同樣考慮到資源緊張,也免了。其實無所謂,重發就重發了。表滿處理採用有損效能的加速演算法,快速有效。另外,本程式不能直接用於嵌入式閘道器產品。
    uCOS51作業系統本身提供了良好的記憶體管理功能,我利用它設定了大中小三種緩衝區存放不同型別的資料包。記憶體使用前申請,使用後釋放,有效利用了資源。
    系統特點是:1.搶佔式優先順序;2.訊息驅動;3.序列伺服器模式。
    系統優點是:1.等待時不耗費CPU資源;2.有超時保護,不會死鎖;3.思路清晰易懂。
    系統基於中斷驅動,使用Int0做網絡卡中斷輸入口。ISR暫存器只用到4位:OVW 收溢位錯/TXE 發被中斷錯/PTX  傳送成功/PRX 接收成功。TCP/IP協議棧做成任務,脫離核心。整體框架如圖5、6、7所示。主程式框架見虛擬碼清單(RxSem和TxSem初始化為0)
   
            ----------
            |網絡卡中斷|
            ----------
                |
                V
            ----------  |>
            |發訊號量|  |  收完/收溢位錯
            |SemPost |---->-------------- RxSemPost
            ----------  |>
                |       |  發完/發被中斷錯
                ---------->-------------- TxSemPost
          圖5 網絡卡中斷處理程式
         
         
                進入
                 |   ------
                 V   |    |                          發
             ----------   |                       低優先順序
     ------> |  等待  |<---   
     |       |TxQPend |<---------------------         -----
     |       ----------                     |          | |
     |           | TxQFIFO非空              |          | |
     |           V                          |   ---<---| |---<---
     |       ----------                     |   資料來源 | |  各任務傳送來的資料
     |       | 傳送包 |                     |          | |
     |       ----------                     |         -----
     |           |                          |        TxQFIFO
     |           V                          |
     |   ---------------------              |
     |   |    釋放記憶體       |              |
     |   |(包已存入網絡卡RAM裡)|              |
     |   ---------------------              |
     |           |    -----                 |
     |           V    |   |                 |
     |       -----------  |                 |
     |       |  等待   |<--                 | (等效傳送包被拋棄)
     |       |TxSemPend|<-----------        |
     |       -----------           |        |
     |           | 發完/超時       |        |
     |           V                 |        |
     | Y  ----------------    -----------   |
     -<---| 傳送成功嗎? |    |重發第n次|   |
          |(無錯且不超時)|    |   n<N   |   |
          ----------------    -----------   |
                 | N              /^\       |
                 V         N       |        |
           ------------------>------        |
           |已發了N次嗎?|---------->--------
           ---------------       Y
              
              圖6 傳送流程圖
              
              
                                    進入
                                     |   -----
                                     V   |   |                       收
                                -----------  |                    高優先順序
             ------------------>|   等待  |<--
             |        --------->|RxSemPend|<---------------
             |        |         -----------       /|\    /|\
             |        |              | 收到包 或   |      |
             |        |              V 收錯 或     |      |
             |        |              | 超時        |      |
             |        |         -----------        |  ----------
             |        |         |存並清ISR|        |  |復位網絡卡|
        -----------   |         -----------        |  ----------
        |RxSemPost|   |              |             |   /^\  /^\
        -----------   |              V             |    |    |
             |        |      --------------------  |    |    |
             |        |      |超時且無新包且無錯| Y|    |    |
             |        |      |    (防死鎖)      |->-    |    |
             |        |      --------------------       |    |
            /|\       |(不執行       | N                |    |
             |        |RxSemPost)    V                  |    |
             |        |         ------------  Y         |    |
             |        |         | 收溢位錯 |--->---------    |
             |        |         | ISR之OVW |                 |
             | Y      | N       ------------                 |
        ------------------           | N                     |
        |網絡卡中還有包嗎?|           V                       |
        |  CURR!=BNRY+1  | ------------------------  Y       |
        ------------------ |讀出包頭,查有無邏輯錯|--->-------
               |           ------------------------
              /|\                    | N
               |                     V
               |           ------------------------
           ----------      |按包長度申請合適的大中|
           |釋放記憶體|      |小號記憶體,並存入整個包|
           ----------      |,再調整BNRY          |
             /^\ /^\       ------------------------
              |   |                  |
              |   |                  V
              |   |   N  ----------------------------
              |   ---<---|是否是發給自己IP地址的包?|
              |          ----------------------------
              |                      | Y
              |                      V
              |                 ------------
              |                 |  包分發  |
              |                 ------------
              |                      |
              |                      V
              |           ----------------------------
              |           |        |        |        |
              |           V      -------------------------- IP_in過濾
              |           |        V        V        V
              |          ARP   ICMP(Ping)  UDP      TCP
              |           |        |        |        |
              |           ----------------------------
              |                      | 序列處理
              |                      | (32bitMCU可設計成併發模式)
              |---------<-------------
                 
                              圖7 接收流程圖
         
    我仔細檢查了幾遍,似乎比較完備了,各種情況下均可以正常工作。在超負荷流量下,只會拋包,不會宕機。當然,由於本人接觸資料有限和個人侷限性,肯定有錯誤和疏漏之處,希望大家提出意見和建議。
   
虛擬碼清單:
ARP_init() //ARP快取初始化
{
  for(i=0;i<ARPTabSize;i++)
    ARPTable.status=0;
}

ARP_request(目的IP地址) //ARP請求
{
//判斷IP地址是否屬於同一子網的任務交給上層軟體處理
//(由它決定請求網絡卡IP地址還是預設閘道器IP地址),
//這有利於減少程式碼量。

  //申請小號記憶體
  pARP=OSMemGet();

  //填乙太網幀
  乙太網協議=0x0806;//ARP協議
  目的MAC地址=0xffff;//廣播地址
  源MAC地址=自己的MAC地址;

  //填ARP表
  硬體型別=0x0001;
  協議型別=0x0800;
  硬體地址長度=0x06;
  協議長度=0x04;
  操作=0x0001;//請求
  傳送方首部=自己的MAC地址;
  傳送方IP地址=源IP地址;
  目標首部=0x0000;
  目標IP地址=目的IP地址;
  
  //填充PAD
  沒有內容處填充0;

  //傳送ARP包至TxQFIFO快取
  OSQSend(QID,*pARP);
}

ARP_answer(*pARP) //ARP應答
{
  學習/更新ARP快取表;
  
  //修改收到的ARP包,形成ARP應答
  //填乙太網幀
  目的MAC地址=對方(網絡卡/閘道器)發來的源MAC地址;
  源MAC地址=自己的MAC地址;

  //填ARP表
  目標首部=傳送方首部;傳送方首部=自己的MAC地址;
  交換髮送方IP地址和目標IP地址;
  操作=0x0002;//ARP應答

  //傳送ARP包至TxQFIFO快取
  OSQSend(QID,*pARP);
}

ARP_process(*pARP) //ARP應答處理
{
  //更新
  for(i=0;i<ARPTabSize;i++){
    if(ARPTab.status==1){
      if(ARPTab.IPAdr==收到的ARP應答包源IP地址){
        ARPTab.ttl=最大壽命;
        ARPTab.IPAdr=收到的包的源IP地址;
        ARPTab.MACAdr=收到的包的源MAC地址;
        return;
      }
    }
  }
  
  //學習
  for(i=0;i<ARPTabSize;i++){
    if(ARPTab.status==0){
      ARPTab.status=1;
      ARPTab.ttl=最大壽命;
      ARPTab.IPAdr=收到的包的源IP地址;
      ARPTab.MACAdr=收到的包的源MAC地址;
      return;     
    }
  }

  //表滿處理,有損效能的快速演算法
  ARPTab[index].status=1; //注:index為全域性變數,儲存ARP快取表項索引。每次處理加1取模。
  ARPTab[index].ttl=最大壽命;
  index++;
  if(index>=ARPTabSize) index=0;
}

IP_in(*pIP) //IP包過濾(ARP地址學習) 注:這裡處理的是IP包,虛擬碼與上面程式相似,但原始碼差別很大。
{
  //更新
  for(i=0;i<ARPTabSize;i++){
    if(ARPTab.status==1){
      if(ARPTab.IPAdr==收到的IP包源IP地址){
        ARPTab.ttl=最大壽命;
        ARPTab.IPAdr=收到的包的源IP地址;
        ARPTab.MACAdr=收到的包的源MAC地址;
        return;
      }
    }
  }
  
  //學習
  for(i=0;i<ARPTabSize;i++){
    if(ARPTab.status==0){
      ARPTab.status=1;
      ARPTab.ttl=最大壽命;
      ARPTab.IPAdr=收到的包的源IP地址;
      ARPTab.MACAdr=收到的包的源MAC地址;
      return;     
    }
  }

  //表滿處理,有損效能的快速演算法
  ARPTab[index].status=1; //注:index為全域性變數,儲存ARP快取表項索引。每次處理加1取模。
  ARPTab[index].ttl=最大壽命;
  index++;
  if(index>=ARPTabSize) index=0;
}

timer() //軟定時器任務,用於ARP老化
{
  for(;;){
    taskDelay(1秒);
    for(i=0;i<ARPTabSize;i++){
      if(ARPTab.status==1){
        if(ARPTab.ttl==0)
          ARPTab.status=0;
        else
          ARPTab.ttl--;
    }
  }
}

主程式框架:
    initNIC    //初始化網絡卡
    //建立資源
    TxSem和RxSem訊號量
    TxQFIFO佇列
    大中小記憶體設立
    //建立任務
    收
    發
    。
    。
    。
   
參考文獻:
1。《用TCP/IP進行網際互連》(第3版)第一、二、三卷 DOUGLAS E.COMER著 電子工業出版社
2。www.laogu.com
3。www.sics.se/~adam/lwip/ 的uip6

相關推薦

uCOS51移植心得》---年前快快樂樂51微控制器作業系統IP部分.NE2000網絡卡晶片驅動程式

NE2000網絡卡晶片驅動程式 巨龍公司系統整合開發部 楊屹 [email protected]  2002/10/20 引言     自從發表《uCOS51移植心得》以來,我收到了很多朋友們的來信,大家對公開源碼錶示鼓勵,謝謝大家的支援!很多人對於編寫自己的作業系統很感興趣,uCOS51是個不錯的

uCOS51移植心得》---年前快快樂樂51微控制器作業系統IP部分在OSStart前開中斷引起的莫名其妙錯誤

在OSStart前開中斷引起的莫名其妙錯誤                                         巨龍公司VPN部 楊屹 [email protected]   2004/03/09 2004/03/07網友方呂ladderls來電詢問以下問題: 你的ucos-ii在51的

uCOS51移植心得》---年前快快樂樂51微控制器作業系統IP部分ARP協議實現原理

ARP協議實現原理           作者<[email protected]> 2002/11/01     ARP是Address Resolution Protocol的縮寫。中文譯做“地址解析協議”,本質是完成網路地址到實體地址的對映。從概念上講就是找到一個對映方法f,使得“實

Spring Cloud(Finchley版)-04-服務註冊與服務發現-原理剖析

第2節( 跟我學Spring Cloud(Finchley版)-02-構建分散式應用 )說過: 地址硬編碼問題——電影微服務中將使用者微服務的地址寫死,如果使用者微服務地址發生變化,難道要重新上線電影微服務嗎? 本節來解決該問題。 不妨先思考一下,怎樣才能讓服務

ASP.NET MVC:SportsStrore購物車

repos ras img sports collect dev PC RM VC 摘要: SportsStore應用程序進展很順利,但是我不能銷售產品直到設計了一個購物車。在這篇文章裏,我就將創建一個購物車。 在目錄下的每個產品旁邊添加一個添加到購物車按鈕。點擊這個按

Java 8 新特性 Stream 流()流與迭代器,流系列大結局

恭喜你們,馬上就要學完Java8 Stream流的一整系列了,其實我相信Stream流對很多使用Java的同學來說,都是一個知識盲點,因為這個原因,我才這麼細緻地講解Stream流的各個知識點,通過這一整個系列,我相信只要認真看了的同學,都已掌握的差不多了,就差實戰了。

ASP.NET MVC四:使用Razor

ima pre 技術分享 C# 圖模型 med 執行 sys fonts 摘要: 視圖引擎處理ASP.NET內容,並查找指令,典型情況是向瀏覽器輸出插入動態內容。MVC框架視圖引擎的名字是Razor。 在本文中,我將帶領讀者快速認識Razor,以後你們看到他們的時候能夠

ASP.NET MVC八:SportsStrore移動設備

ima 支持 web瀏覽器 css 客戶端瀏覽器 nts oat 重新 menu 摘要: 現在的web程序開發避免不了智能手機和平板電腦上的使用,如果你希望發布你的應用程序給更廣大客戶使用的話,你將要擁抱可移動web瀏覽器的世界。向移動設備用戶發布一個好的使用體驗是很困難

Java程式設計師從笨鳥到菜鳥(八十五)jquery(一)愛初體驗jquery

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Flask()-flask工作原理

在對Flask程式碼基本結構有一定了解之後,為了以後學習的順利,我們需要進一步瞭解Flask工作的基本原理 *本文轉載自孫華強部落格:*https://blog.csdn.net/sunhuaqiang1/article/details/72808619 所有的 Python

oracle18c】天:Multitenant Architecture多租戶框架:2.2 Overview of Commonality in the CDB(藍色感悟)

在CDB中,每個使用者、角色或物件都是通用的或本地的。類似地,通常或區域性授予特權. This section contains the following topics: About Commonality in a CDB A common phenomenon defined i

springboot(二十五)springboot-過濾器攔截不需要走過濾器的連結使用方法

1.建立專案 springboot怎麼建立不多說了,前面部落格已經有講解,下面是我們建立好的專案目錄。 2.編寫程式碼 過濾器可以指定我們排除的引數exclusions,我們把需要隔離的url統一封裝在這裡,然後在webconfig配置filterReg.ad

Java 8 新特性 Stream 流(四)並行流

隨著對流API認識的慢慢深入,本章我們要討論的知識點是流API裡面的並行流了。 在開始討論並行流之前,我先引發一下大家的思考,就你看到這篇文章的時間,你們是不是經常聽到,Intel i7 CPU什麼8核16執行緒,什麼Android手機8核4GB這種訊息,既然我們是處於

Java 8 新特性 Stream 流(三)縮減操作

和前面兩篇文章一起服用,效果會更佳。通過對流API的基礎體驗Demo和關鍵知識點的講解,相信大家對流API都有一定的認識了,但是流API強大的功能,可不僅僅像前面兩篇文章中說的那樣簡單,大家應該注意到,在第二篇中,我對Stream介面進行介紹的時候,並沒有把他的全部方法都

Java 8 新特性 Stream 流(二)關鍵知識點

我們的第一篇文章,主要是通過一個Demo,讓大家體驗了一下使用流API的那種酣暢淋漓的感覺。如果你沒有實踐,我還是再次呼籲你動手敲一敲,自己實實在跑一遍上一篇的Demo。 相信你的感受和理解也會隨之加深的。繼續探索流API的高階功能之前,我們先從介面級別全面瞭解一下流A

Java 8 新特性 Stream 流基礎體驗

Java8新增的功能中,要數lambda表示式和流API最為重要了.這篇文章主要介紹流API的基礎,也是流API系列的第一篇文章,話不多說,直奔主題. 什麼是流API? 它能做一些什麼? 我們應該知道(絕對知道~)API是一個程式向使用者提供的一些方法,通過這些方法就

Java 8 新特性 Stream 流()收集

我們前面的五篇文章基本都是在說將一個集合轉成一個流,然後對流進行操作,其實這種操作是最多的,但有時候我們也是需要從流中收集起一些元素,並以集合的方式返回,我們把這種反向操作稱為收集。 流API也給我們提供了相應的方法。 如何在流中使用收集功能? 我們先看一看流API

KafkaController控制器詳解

作者:小程 我們的kafka原始碼分享已經進行過很多期了,主要的內容也都分享的差不多了,那麼在今後的分享中,主要集中在kafka效能優化和使用。 Kafka叢集中的其中一個Broker會被選舉為Controller,主要負責Partition管理和副本狀態管理,也會執行類似於重分配Partit

KafkaNIO通訊機制

很久沒有做技術方面的分享了,今天閒來有空寫一篇關於Kafka通訊方面的文章與大家共同學習。 一、Kafka通訊機制的整體結構 這個圖採用的就是我們之前提到的SEDA多執行緒模型,連結如下: http://www.jianshu.com/p/e184fdc0ade4 1、對於broker來說

程式碼架構設計模式--鎖執行緒

上篇講到鎖可以用來解決多執行緒同時訪問同一資源時的同步問題,即鎖可以控制多執行緒對函式關聯資源的的同步訪問。這一篇我來簡單分析下鎖如何解決同步問題的。 在講鎖之前,我們我們先來討論下wait和notify方法,這兩個方法是用來控制執行緒執行的。說白了就是控制執行緒狀態的流轉,wait控制執行