ARP协议实现原理.txt
上传用户:renruilai
上传日期:2007-05-03
资源大小:144k
文件大小:16k
源码类别:

嵌入式Linux

开发平台:

C/C++

  1.                  ARP协议实现原理
  2.           作者<asdjf@163.com> 2002/11/01
  3.     ARP是Address Resolution Protocol的缩写。中文译做“地址解析协议”,本质是完成网络地址到物理地址的映射。从概念上讲就是找到一个映射方法f,使得“物理地址 = f(网络地址)”。物理地址有两种基本类型:以太网类型和proNET令牌环网类型,网络地址特指IP地址,对映射方法的要求就是高效。具体到以太网,它使用的是动态绑定转换的方法。为什么不直接使用同一种地址,而要这么麻烦呢?因为TCP/IP网络就是为将不同种类计算机互联而发明的,它的体系结构是分层的,层和层之间相互独立,改变物理层的实现不会影响到网络层。
  4.     32位IP地址到以太网48位物理地址的映射,采用动态绑定转换的方法会遇到许多细节问题,例如:减少广播,ARP包丢失,物理地址变更(更换网卡)、移动(移动设备到另一子网)、消失(关机)等。一般是设置ARP高速缓存,通过学习、老化、更新、溢出算法处理ARP映射表来解决这些问题。其中,学习指ARP收到任何指向本节点IP地址的ARP/IP包,从中提取出地址对,而ARP缓存中无对应项时,由ARP接收部分添加;老化指为每项设置寿命域,以便代谢掉陈旧的地址映射项;更新指ARP提取到新的地址对时,用其更新缓存里已有的对应项;溢出算法指当缓存满时,采取何种方法替换旧有的地址对儿。
  5.     我找到了几个TCP/IP源代码,对比他们的实现,深感差别巨大,灵活多变。有的代码未实现ARP缓存,只用几个全局变量记录源目的IP地址和源目的MAC地址,每次通信前直接操作全局变量,这在使用51单片机,进行点对点通信时不失为一个有效的方案;而有的代码庞大复杂,细节处理精益求精。比如实现了ARP高速缓存、支持多址节点、支持网管查看/动态改变ARP相关参数、重发处理、支持IPv6等。我的看法是:ARP的本质是地址转换,只要抓住这个灵魂,设计的大方向就把握住了。具体实现过程各具特色,因人而异,没有统一要求,有些功能可以不实现,有些优点不能兼得,而唯一不变的只有思想。
  6.     我参考了几种已有的IP协议栈并结合51单片机的特点,实现了自己的基于uCOS51的TCP/IP协议栈方案。它只是一种具体的实现范例,不同的人有不同的设计方法。我保证自己的方案可以正常使用并具有较好的完备性。
  7.     
  8.     ------------------------------
  9.     |状态|寿命ttl|IP地址 |MAC地址|        学习
  10.     ------------------------------
  11.     |  0 |   FF  |X:X:X:X| XXXX  |  <---  老化
  12.     ------------------------------
  13.     |  0 |   FF  |X:X:X:X| XXXX  |        更新
  14.     ------------------------------
  15.            图1 ARP缓存表                  表满处理
  16.     
  17.     如图1所示,ARP缓存表由状态、寿命、IP地址、MAC地址4个字段组成。状态字段指示地址对是否有效(0-空闲 1-占用);寿命字段用于老化操作,初始存入最大值,以后由OS时间函数调用,每秒减1,直至为0清除;IP地址和MAC地址字段保存网络地址和物理地址的映射。此处,没有设计发送数据链表首指针和重发记数字段,我把重发操作交给上层软件统一处理,这是本程序的特色。围绕ARP缓存表,完成了4种操作:学习、老化、更新、表满处理,详见伪代码清单。使用OS的Shell命令ls可以查看ARP表的内容,但不支持修改,这个功能对测试很有用。(显示内容举例如图2所示)
  18.     
  19.     %ls
  20.     
  21.      ARP table:
  22.      status     TTL      IP address      MAC address
  23.      =================================================
  24.        01        78     172.18.92.86     0050BABD4C7E
  25.      
  26.     %
  27.               图2 ARP缓存表显示内容举例
  28.               
  29.     
  30.              表满处理
  31.                 |
  32.                 v                               ARP请求
  33.             ---------             ----------- ---------->
  34.             |       |  学习/更新  |         | <- - - - -
  35.     老化--->| ARP表 |<------------| ARP处理 |
  36.             |       |             |         | - - - - - >
  37.             ---------             ----------- <----------
  38.                 ^                               ARP应答
  39.                 |学习/更新
  40.             ---------
  41.             |       |
  42.             | IP_in |
  43.             |       |
  44.             ---------
  45.                         图3 ARP处理过程
  46.                         
  47.     0                 8               16              24               31                    
  48.     ---------------------------------------------------------------------
  49.     |             硬件类型            |            协议类型             |
  50.     ---------------------------------------------------------------------
  51.     |硬件地址长度(HLEN)|协议长度(PLEN)|               操作              |
  52.     ---------------------------------------------------------------------
  53.     |                         发送方首部(八位组0-3)                     |
  54.     ---------------------------------------------------------------------
  55.     |      发送方首部(八位组4-5)      |      发送方IP地址(八位组0-1)    |
  56.     ---------------------------------------------------------------------
  57.     |     发送方IP地址(八位组2-3)     |        目标首部(八位组0-1)      |
  58.     ---------------------------------------------------------------------
  59.     |                         目标首部(八位组2-5)                       |
  60.     ---------------------------------------------------------------------
  61.     |                        目标IP地址(八位组0-3)                      |
  62.     ---------------------------------------------------------------------
  63.                                 图4 ARP包结构
  64.     
  65.     如图3,整个ARP处理过程,我主要用5个函数实现。ARP初始化(ARP_init)、ARP请求(ARP_request)、ARP应答(ARP_answer)、ARP回应处理(ARP_process)、IP包接收预处理(IP_in)。在实现网卡驱动程序后,所有ARP处理操作就是填写ARP包(ARP包结构见图4),详见伪代码清单。
  66.     ARP_init完成ARP表初始化,概括说就是ARP表state字段清0。
  67.     ARP_request完成ARP请求操作。ARP协议要求程序根据子网掩码判断IP地址是否属于同一子网,如果在同一子网内,ARP请求目的MAC地址,否则请求默认网关MAC地址。
  68.     ARP_answer比较简单,只要交换ARP请求包地址内容,填写自己的MAC地址和很少的改动后发送即可。
  69.     ARP_process完成ARP回应回来的信息处理。主要进行ARP表的学习和更新。
  70.     IP_in完成IP包接收预处理,用于提取地址映射信息,以便主动学习和及时更新。我的程序不会主动学习不是发给自己IP地址的MAC地址信息,因为ARP表在51中的容量有限,只有频繁用到的地址对才应该存放在里面,否则一旦出现“颠簸”,ARP表就失效了。
  71.     有的ARP实现方案采用数据驱动方式,参数可配置,使用统一的程序,通过加载不同的配置数据,执行不同的操作。这样做使程序版本统一,不同的应用只要加载不同的配置数据即可,不用更换程序,有利于后期维护。但是考虑到51资源紧张和安全性,我的方案只能显示ARP表不允许修改其内容,用户可发挥想象力在此处增加新功能。另外,ARP程序应该记住上一次发过的请求,以避免重发,但同样考虑到资源紧张,也免了。其实无所谓,重发就重发了。表满处理采用有损性能的加速算法,快速有效。另外,本程序不能直接用于嵌入式网关产品。
  72.     uCOS51操作系统本身提供了良好的内存管理功能,我利用它设置了大中小三种缓冲区存放不同类型的数据包。内存使用前申请,使用后释放,有效利用了资源。
  73.     系统特点是:1.抢占式优先级;2.消息驱动;3.串行服务器模式。
  74.     系统优点是:1.等待时不耗费CPU资源;2.有超时保护,不会死锁;3.思路清晰易懂。
  75.     系统基于中断驱动,使用Int0做网卡中断输入口。ISR寄存器只用到4位:OVW 收溢出错/TXE 发被中断错/PTX  发送成功/PRX 接收成功。TCP/IP协议栈做成任务,脱离内核。整体框架如图5、6、7所示。主程序框架见伪代码清单(RxSem和TxSem初始化为0)
  76.     
  77.             ----------
  78.             |网卡中断|
  79.             ----------
  80.                 |
  81.                 V
  82.             ----------  |>
  83.             |发信号量|  |  收完/收溢出错
  84.             |SemPost |---->-------------- RxSemPost
  85.             ----------  |>
  86.                 |       |  发完/发被中断错
  87.                 ---------->-------------- TxSemPost
  88.           图5 网卡中断处理程序
  89.           
  90.           
  91.                 进入
  92.                  |   ------
  93.                  V   |    |                          发
  94.              ----------   |                       低优先级
  95.      ------> |  等待  |<---   
  96.      |       |TxQPend |<---------------------         -----
  97.      |       ----------                     |          | |
  98.      |           | TxQFIFO非空              |          | |
  99.      |           V                          |   ---<---| |---<---
  100.      |       ----------                     |   数据源 | |  各任务发送来的数据 
  101.      |       | 发送包 |                     |          | |
  102.      |       ----------                     |         -----
  103.      |           |                          |        TxQFIFO
  104.      |           V                          |
  105.      |   ---------------------              |
  106.      |   |    释放内存       |              |
  107.      |   |(包已存入网卡RAM里)|              |
  108.      |   ---------------------              |
  109.      |           |    -----                 |
  110.      |           V    |   |                 |
  111.      |       -----------  |                 |
  112.      |       |  等待   |<--                 | (等效发送包被抛弃)
  113.      |       |TxSemPend|<-----------        |
  114.      |       -----------           |        |
  115.      |           | 发完/超时       |        |
  116.      |           V                 |        |
  117.      | Y  ----------------    -----------   |
  118.      -<---| 发送成功吗? |    |重发第n次|   |
  119.           |(无错且不超时)|    |   n<N   |   |
  120.           ----------------    -----------   |
  121.                  | N              /^       |
  122.                  V         N       |        |
  123.            ------------------>------        |
  124.            |已发了N次吗?|---------->--------
  125.            ---------------       Y
  126.               
  127.               图6 发送流程图
  128.               
  129.               
  130.                                     进入
  131.                                      |   -----
  132.                                      V   |   |                       收
  133.                                 -----------  |                    高优先级
  134.              ------------------>|   等待  |<--
  135.              |        --------->|RxSemPend|<---------------
  136.              |        |         -----------       /|    /|
  137.              |        |              | 收到包 或   |      |
  138.              |        |              V 收错 或     |      |
  139.              |        |              | 超时        |      |
  140.              |        |         -----------        |  ----------
  141.              |        |         |存并清ISR|        |  |复位网卡|
  142.         -----------   |         -----------        |  ----------
  143.         |RxSemPost|   |              |             |   /^  /^
  144.         -----------   |              V             |    |    |
  145.              |        |      --------------------  |    |    |
  146.              |        |      |超时且无新包且无错| Y|    |    |
  147.              |        |      |    (防死锁)      |->-    |    |
  148.              |        |      --------------------       |    |
  149.             /|       |(不执行       | N                |    |
  150.              |        |RxSemPost)    V                  |    |
  151.              |        |         ------------  Y         |    |
  152.              |        |         | 收溢出错 |--->---------    |
  153.              |        |         | ISR之OVW |                 |
  154.              | Y      | N       ------------                 |
  155.         ------------------           | N                     |
  156.         |网卡中还有包吗?|           V                       |
  157.         |  CURR!=BNRY+1  | ------------------------  Y       |
  158.         ------------------ |读出包头,查有无逻辑错|--->-------
  159.                |           ------------------------
  160.               /|                    | N
  161.                |                     V
  162.                |           ------------------------
  163.            ----------      |按包长度申请合适的大中|
  164.            |释放内存|      |小号内存,并存入整个包|
  165.            ----------      |,再调整BNRY          |
  166.              /^ /^       ------------------------
  167.               |   |                  |
  168.               |   |                  V
  169.               |   |   N  ----------------------------
  170.               |   ---<---|是否是发给自己IP地址的包?|
  171.               |          ----------------------------
  172.               |                      | Y
  173.               |                      V
  174.               |                 ------------
  175.               |                 |  包分发  |
  176.               |                 ------------
  177.               |                      |
  178.               |                      V
  179.               |           ----------------------------
  180.               |           |        |        |        |
  181.               |           V      -------------------------- IP_in过滤
  182.               |           |        V        V        V
  183.               |          ARP   ICMP(Ping)  UDP      TCP
  184.               |           |        |        |        |
  185.               |           ----------------------------
  186.               |                      | 串行处理
  187.               |                      | (32bitMCU可设计成并发模式)
  188.               |---------<-------------
  189.                  
  190.                               图7 接收流程图
  191.          
  192.     我仔细检查了几遍,似乎比较完备了,各种情况下均可以正常工作。在超负荷流量下,只会抛包,不会死机。当然,由于本人接触资料有限和个人局限性,肯定有错误和疏漏之处,希望大家提出意见和建议。
  193.     
  194. 伪代码清单:
  195. ARP_init() //ARP缓存初始化
  196. {
  197.   for(i=0;i<ARPTabSize;i++)
  198.     ARPTable[i].status=0;
  199. }
  200. ARP_request(目的IP地址) //ARP请求
  201. {
  202. //判断IP地址是否属于同一子网的任务交给上层软件处理
  203. //(由它决定请求网卡IP地址还是默认网关IP地址),
  204. //这有利于减少代码量。
  205.   //申请小号内存
  206.   pARP=OSMemGet();
  207.   //填以太网帧
  208.   以太网协议=0x0806;//ARP协议
  209.   目的MAC地址=0xffff;//广播地址
  210.   源MAC地址=自己的MAC地址;
  211.   //填ARP表
  212.   硬件类型=0x0001;
  213.   协议类型=0x0800;
  214.   硬件地址长度=0x06;
  215.   协议长度=0x04;
  216.   操作=0x0001;//请求
  217.   发送方首部=自己的MAC地址;
  218.   发送方IP地址=源IP地址;
  219.   目标首部=0x0000;
  220.   目标IP地址=目的IP地址;
  221.   
  222.   //填充PAD
  223.   没有内容处填充0;
  224.   //发送ARP包至TxQFIFO缓存
  225.   OSQSend(QID,*pARP);
  226. }
  227. ARP_answer(*pARP) //ARP应答
  228. {
  229.   学习/更新ARP缓存表;
  230.   
  231.   //修改收到的ARP包,形成ARP应答
  232.   //填以太网帧
  233.   目的MAC地址=对方(网卡/网关)发来的源MAC地址;
  234.   源MAC地址=自己的MAC地址;
  235.   //填ARP表
  236.   目标首部=发送方首部;发送方首部=自己的MAC地址;
  237.   交换发送方IP地址和目标IP地址;
  238.   操作=0x0002;//ARP应答
  239.   //发送ARP包至TxQFIFO缓存
  240.   OSQSend(QID,*pARP);
  241. }
  242. ARP_process(*pARP) //ARP应答处理
  243. {
  244.   //更新
  245.   for(i=0;i<ARPTabSize;i++){
  246.     if(ARPTab[i].status==1){
  247.       if(ARPTab[i].IPAdr==收到的ARP应答包源IP地址){
  248.         ARPTab[i].ttl=最大寿命;
  249.         ARPTab[i].IPAdr=收到的包的源IP地址;
  250.         ARPTab[i].MACAdr=收到的包的源MAC地址;
  251.         return;
  252.       }
  253.     }
  254.   }
  255.   
  256.   //学习
  257.   for(i=0;i<ARPTabSize;i++){
  258.     if(ARPTab[i].status==0){
  259.       ARPTab[i].status=1;
  260.       ARPTab[i].ttl=最大寿命;
  261.       ARPTab[i].IPAdr=收到的包的源IP地址;
  262.       ARPTab[i].MACAdr=收到的包的源MAC地址;
  263.       return;     
  264.     }
  265.   }
  266.   //表满处理,有损性能的快速算法
  267.   ARPTab[index].status=1; //注:index为全局变量,保存ARP缓存表项索引。每次处理加1取模。
  268.   ARPTab[index].ttl=最大寿命;
  269.   index++;
  270.   if(index>=ARPTabSize) index=0;
  271. }
  272. IP_in(*pIP) //IP包过滤(ARP地址学习) 注:这里处理的是IP包,伪代码与上面程序相似,但源代码差别很大。
  273. {
  274.   //更新
  275.   for(i=0;i<ARPTabSize;i++){
  276.     if(ARPTab[i].status==1){
  277.       if(ARPTab[i].IPAdr==收到的IP包源IP地址){
  278.         ARPTab[i].ttl=最大寿命;
  279.         ARPTab[i].IPAdr=收到的包的源IP地址;
  280.         ARPTab[i].MACAdr=收到的包的源MAC地址;
  281.         return;
  282.       }
  283.     }
  284.   }
  285.   
  286.   //学习
  287.   for(i=0;i<ARPTabSize;i++){
  288.     if(ARPTab[i].status==0){
  289.       ARPTab[i].status=1;
  290.       ARPTab[i].ttl=最大寿命;
  291.       ARPTab[i].IPAdr=收到的包的源IP地址;
  292.       ARPTab[i].MACAdr=收到的包的源MAC地址;
  293.       return;     
  294.     }
  295.   }
  296.   //表满处理,有损性能的快速算法
  297.   ARPTab[index].status=1; //注:index为全局变量,保存ARP缓存表项索引。每次处理加1取模。
  298.   ARPTab[index].ttl=最大寿命;
  299.   index++;
  300.   if(index>=ARPTabSize) index=0;
  301. }
  302. timer() //软定时器任务,用于ARP老化
  303. {
  304.   for(;;){
  305.     taskDelay(1秒);
  306.     for(i=0;i<ARPTabSize;i++){
  307.       if(ARPTab[i].status==1){
  308.         if(ARPTab[i].ttl==0)
  309.           ARPTab[i].status=0;
  310.         else
  311.           ARPTab[i].ttl--;
  312.     }
  313.   }
  314. }
  315. 主程序框架:
  316.     initNIC    //初始化网卡
  317.     //创建资源
  318.     TxSem和RxSem信号量
  319.     TxQFIFO队列
  320.     大中小内存设立
  321.     //创建任务
  322.     收
  323.     发
  324.     。
  325.     。
  326.     。
  327.     
  328. 参考文献:
  329. 1。《用TCP/IP进行网际互连》(第3版)第一、二、三卷 DOUGLAS E.COMER著 电子工业出版社
  330. 2。www.laogu.com
  331. 3。www.sics.se/~adam/lwip/ 的uip6