《uCOS51移植心得》---七年前之《快快樂樂跟我學51微控制器作業系統和IP棧》 第六部分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
跟我學Kafka之Controller控制器詳解
作者:小程 我們的kafka原始碼分享已經進行過很多期了,主要的內容也都分享的差不多了,那麼在今後的分享中,主要集中在kafka效能優化和使用。 Kafka叢集中的其中一個Broker會被選舉為Controller,主要負責Partition管理和副本狀態管理,也會執行類似於重分配Partit
跟我學Kafka之NIO通訊機制
很久沒有做技術方面的分享了,今天閒來有空寫一篇關於Kafka通訊方面的文章與大家共同學習。 一、Kafka通訊機制的整體結構 這個圖採用的就是我們之前提到的SEDA多執行緒模型,連結如下: http://www.jianshu.com/p/e184fdc0ade4 1、對於broker來說
跟我學程式碼架構設計模式之--鎖和執行緒
上篇講到鎖可以用來解決多執行緒同時訪問同一資源時的同步問題,即鎖可以控制多執行緒對函式關聯資源的的同步訪問。這一篇我來簡單分析下鎖如何解決同步問題的。 在講鎖之前,我們我們先來討論下wait和notify方法,這兩個方法是用來控制執行緒執行的。說白了就是控制執行緒狀態的流轉,wait控制執行