地址转换协议ARP

  在以太网协议中规定,同一局域网中的一台主机要和另一台主机进行直接通信,必须要知道目标主机的MAC地址。而在TCP/IP协议中,网络层和传输层只关心目标主机的IP地址。这就导致在以太网中使用IP协议时,数据链路层的以太网协议接到上层IP协议提供的数据中,只包含目的主机的IP地址。于是需要一种方法,根据目的主机的IP地址,获得其MAC地址。这就是ARP协议要做的事情。

  所谓地址解析(address resolution)就是主机在发送帧前将目标IP地址转换成目标MAC地址的过程。

理论结构

  ARP软件可分为三部分:

  • 输出模块

    • 将高层协议地址与相应的物理地址进行绑定,返回给网络接口程序
  • 输入模块
    • 处理来自网络的ARP分组,并通过增加新的绑定来修改ARP高速缓存的内容
  • 高速缓存管理程序
    • 实现高速缓存替换策略;检测高速缓存中的所有表项,删除已达到规定时限的表项

输出模块

  该模块主要是要接收IP数组请求,然后查找物理地址,返回。

  主要步骤为:

  1. 睡眠,直到IP软件收到IP分组。

  2. 检查高速缓存表,寻找对应于这个IP分组的项目。

  3. if ( 找到 ){

      if ( 状态为 RESOLVED ){

        提取硬件物理地址;

        将分组连同硬件物理地址一起发送到数据链路层;

return;

      }

      else if ( 状态为 PENDING ){

       将分组放入相应的队列;

   return;

     }

    }

    else{

      创建一个队列;

      将分组加入到队列中;

      创建一个高速缓存项目,状态设置为 PENDING ,ATTEMPTS 为 1;

      发送ARP请求;

    }

ARP高速缓存队列

  它是用数组来存储的。

extern struct arpentry arptable[ARP_TSIZE]

搜索ARP高速缓存

/* arpfind.c - arpfind */   

#include <conf.h>
#include <kernel.h>
#include <network.h> /*------------------------------------------------------------------------
* arpfind - find an ARP entry given a protocol address and interface
*------------------------------------------------------------------------
*/
struct arpentry *
arpfind(u_char *pra, u_short prtype, struct netif *pni)
{
struct arpentry *pae; /* 定义ARP缓存结构体指针 */
int i; for (i=; i<ARP_TSIZE; ++i) { /* 遍历ARP高速缓存 */
pae = &arptable[i]; /* 高速缓存数组 */
if (pae->ae_state == AS_FREE) /* 缓存为空闲接找下一个 */
continue;
if (pae->ae_prtype == prtype && /* 协议类型相同 */
pae->ae_pni == pni && /* 接口和协议地址相同 */
BLKEQU(pae->ae_pra, pra, pae->ae_prlen)) /* BLKEQU的定义 #define BLKEQU(b1, b2, len) (!memcmp((b1), (b2), len))*/
return pae;
}
return ;
}

ARP请求分组的广播

/* arpsend.c - arpsend */

#include <conf.h>
#include <kernel.h>
#include <network.h> /*------------------------------------------------------------------------
* arpsend - broadcast an ARP request
* N.B. Assumes interrupts disabled
*------------------------------------------------------------------------
*/
int arpsend(pae)
struct arpentry *pae; //指向高速缓存的表项
{
struct netif *pni = pae->ae_pni;
struct ep *pep;
struct arp *parp;
int arplen; pep = (struct ep *) getbuf(Net.netpool); //生成ARP请求分组
if ((int)pep == SYSERR)
return SYSERR;
blkcopy(pep->ep_dst, pni->ni_hwb.ha_addr, pae->ae_hwlen);
pep->ep_type = EPT_ARP;
pep->ep_order = EPO_NET;
parp = (struct arp *) pep->ep_data;
parp->ar_hwtype = hs2net(pae->ae_hwtype);
parp->ar_prtype = hs2net(pae->ae_prtype);
parp->ar_hwlen = pae->ae_hwlen;
parp->ar_prlen = pae->ae_prlen;
parp->ar_op = hs2net(AR_REQUEST);
blkcopy(SHA(parp), pni->ni_hwa.ha_addr, pae->ae_hwlen);
blkcopy(SPA(parp), &pni->ni_ip, pae->ae_prlen);
bzero(THA(parp), pae->ae_hwlen);
blkcopy(TPA(parp), pae->ae_pra, pae->ae_prlen);
arplen = ARP_HLEN + *(parp->ar_hwlen + parp->ar_prlen);
write(pni->ni_dev, pep, EP_HLEN+arplen); //发送请求分组
return OK;
}

输入模块

   从一个队列中拿走一个分组,并连同解析出的物理地址一起发送给数据报链路层传输。

  主要步骤为

  1. 睡眠,直到ARP分组到达(请求或回答)。

  2. 检查高速缓存表,寻找对应这个ARP分组的项目。

  3. if ( 找到 ){

     if ( 状态是 RESOLVED ){

      更新项目;

      return;

     }

     else if ( 状态是 PENDING ){

      更新项目;

如果队列非空的话,将一个分组从队列中取出,将它与硬件地址一起发送给数据链路层;

      return;

     {

    }

    else{

    创建一个项目;

    将此项目添加到表中;

    return;

    }

  4.  如果分组是一个请求, 发送ARP回答。

向表中增加已转换的表项

/* arpadd.c - arpadd */

#include <conf.h>
#include <kernel.h>
#include <network.h> struct arpentry *arpalloc(void); /*------------------------------------------------------------------------
* arpadd - Add a RESOLVED entry to the ARP cache
* N.B. Assumes interrupts disabled
*------------------------------------------------------------------------
*/
struct arpentry *
arpadd(struct netif *pni, struct arp *parp)
{
struct arpentry *pae; pae = arpalloc(); //在高速缓存中分配一个表项 /* 利用ARP分组信息填写表项 */
pae->ae_hwtype = parp->ar_hwtype;
pae->ae_prtype = parp->ar_prtype;
pae->ae_hwlen = parp->ar_hwlen;
pae->ae_prlen = parp->ar_prlen;
pae->ae_pni = pni;
pae->ae_queue = EMPTY;
memcpy(pae->ae_hwa, SHA(parp), parp->ar_hwlen);
memcpy(pae->ae_pra, SPA(parp), parp->ar_prlen);
/* 初始化 */
pae->ae_ttl = ARP_TIMEOUT;
pae->ae_state = AS_RESOLVED;
return pae;
}

发送等待发送的分组

/* arpqsend.c - arpqsend */

#include <conf.h>
#include <kernel.h>
#include <network.h> int netwrite(struct netif *, struct ep *, unsigned); /*------------------------------------------------------------------------
* arpqsend - write packets queued waiting for an ARP resolution
*------------------------------------------------------------------------
*/
void
arpqsend(struct arpentry *pae)
{
struct ep *pep;
struct netif *pni; if (pae->ae_queue == EMPTY)
return; pni = pae->ae_pni;
/* 遍历等待发送的分组队列,调用netwrite逐个放入网络输出队列中 */
while (pep = (struct ep *)deq(pae->ae_queue))
netwrite(pni, pep, pep->ep_len);
freeq(pae->ae_queue); //队列为空后,释放自身
pae->ae_queue = EMPTY;
}

高速缓存管理

  高速缓存是用来存储IP地址与物理地址的。如果一个IP进行需要发送一个数据报,但其目的地址不在ARP高速缓存中,就会创建一个新的表项,然后广播相应的请求分组,并等待分组置入队列中。

  主要步骤:

1. 睡眠,周期性的唤醒。

2. 遍历高速缓存的每一个项目:

  if ( 状态为FREE )

continue;

if ( 状态为PENDING ){

    尝试次数+1;

    if ( 尝试次数达到最大次数 ){

      该项目状态->FREE;

    撤销相应的队列;

    }

    else {

      发送ARP请求;

    }

    continue;

  }

  else if( 状态为RESOLVED ){

    将超时字段的值减去已经过去的时间;

    若结果小于0,状态->FREE,撤销相应队列。

  }

 替换策略

/* arpalloc.c - arpalloc */   

#include <conf.h>
#include <kernel.h>
#include <proc.h>
#include <network.h> void arpdq(struct arpentry *); /*------------------------------------------------------------------------
* arpalloc - allocate an entry in the ARP table
* N.B. Assumes interrupts DISABLED
*------------------------------------------------------------------------
*/
struct arpentry *arpalloc()
{
static int aenext = ; //静态变量,保证循环
struct arpentry *pae;
int i; for (i=; i<ARP_TSIZE; ++i) { //遍历表
if (arptable[aenext].ae_state == AS_FREE)
break;
aenext = (aenext + ) % ARP_TSIZE; //循环替换
}
pae = & arptable[aenext];
aenext = (aenext + ) % ARP_TSIZE; if (pae->ae_state == AS_PENDING && pae->ae_queue >= )
arpdq(pae);
pae->ae_state = AS_PENDING;
return pae;
}

地址转换协议ARP的更多相关文章

  1. RARP反向地址转换协议

    反向地址转换协议(RARP:Reverse Address Resolution Protocol) 反向地址转换协议(RARP)允许局域网的物理机器从网关服务器的 ARP 表或者缓存上请求其 IP ...

  2. 【原创】锐捷实现OSPF路由协议和NAT地址转换协议

    路由网络设计与实施 [锐捷设备实现OSPF路由协议与NAT地址转换] 说明:   本文是在多VLAN双星型交换网络的基础之上发展的.关于组建多VLAN双星型交换网络,请参阅: <思科和锐捷组建多 ...

  3. 【RL-TCPnet网络教程】第23章 RL-TCPnet之地址解析协议ARP

    第23章      RL-TCPnet之地址解析协议ARP 本章节为大家讲解ARP(Address Resolution Protocol,地址解析协议),通过前面章节对TCP和UDP的学习,需要大家 ...

  4. 2016.7.8 计算机网络复习要点第四章之地址解析协议ARP

    1.地址解析协议ARP:知道一个机器的IP地址,需要找到其相应的硬件地址:ARP协议的用途是为了从网络层使用的IP地址解析出在链路层使用的硬件地址: 2.由于是IP协议使用了ARP协议,因此通常就把A ...

  5. 四、IP地址转换

    IP地址与端口 TCP/IP(传输控制协议/网际协议)不是一个协议,而是一组协议的总称,包括IP.TCP.UDP.ICMP.ARP等.它规范了网络上的所有通信设备,尤其是一个主机与另一个主机之间的数据 ...

  6. <TCP/IP>地址解析协议ARP

    从前两章中有学到,网络层地址和链路层地址是由不同的,一个是物理地址,一个是IP地址.物理地址固定存储在网卡中,不会改变,而IP地址是可以网络管理员和用户自己分配的 在传统的IPv4网络中,一台A主机要 ...

  7. TCP/IP具体解释学习笔记——地址解析协议ARP

    一 概述 我们知道,IP协议是用来在不同的物理网络之间数据传输的.要在不同的网络之间数据传输,至少须要将IP协议所用的地址转换成特定网络所使用的物理地址. 一般来说.就是将IPv4地址转换为mac地址 ...

  8. 地址解析协议ARP与逆地址解析协议RARP

    IP地址是用来通信的,但是和硬件地址是有区别的.物理地址是数据链路层和物理层使用的地址,IP地址是网络层及以上各层使用的地址. 发送数据时,数据从高层向下层传输,使用IP地址的IP数据报交给下层的数据 ...

  9. Linux 网络编程详解一(IP套接字结构体、网络字节序,地址转换函数)

    IPv4套接字地址结构 struct sockaddr_in { uint8_t sinlen;(4个字节) sa_family_t sin_family;(4个字节) in_port_t sin_p ...

随机推荐

  1. VC++ 结束线程 AfxBeginThread AfxEndThread

    如果你的线程是从CWinThread继承出来的,结束自己就用AfxEndThread, 如果是外部调用的话,可以用PostThreadMessage(m_nThreadID, WM_QUIT,0,0) ...

  2. python 注册

    1.打开网址,点击 获得注册码 http://idea.qinxi1992.cn/  2.help -- register 第二步: http://jetbrains.tencent.click/   ...

  3. 初识ASP.NET CORE:三、Middleware

    Middleware are simpler than HTTP modules and handlers:Modules, handlers, Global.asax.cs, Web.config  ...

  4. [原创]Matlab获取当前时间信息

    本文主要介绍下Matlab中如何获取当前时间的一些方法. 基本变量date.now.clock date 按照日期字符串返回当前系统时间 now 按照连续的日期数值返回当前系统时间 clock按照日期 ...

  5. Light OJ 1025 - The Specials Menu(动态规划-区间dp)

    题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1025 题目大意:一串字符, 通过删除其中一些字符, 能够使这串字符变成回文串. ...

  6. autoresizingMask的用法

    UIViewAutoresizingNone = , UIViewAutoresizingFlexibleLeftMargin = << , UIViewAutoresizingFlexi ...

  7. Centos7 mysql-community-5.7.11编译安装

    安装环境 [root@localhost ~]# cat /etc/centos-release CentOS Linux release 7.0.1406 (Core) 0x01 准备工作 1.到m ...

  8. FreeBSD_11-系统管理——{Part_0-基础}

    Tips: sysctl -d kern.maxvnodes #查看系统控制选项的含义 true > file #清空文件内容 alias ls 'ls -I(大写i)' #取消 root 的 ...

  9. JAVA基础之两种核心机制

    突然之间需要学习Java,学校里学的东西早就忘记了,得用最短的时间把Java知识理顺,重点还是J2EE,毕竟所有的ava项目中95%都是J2EE,还是先从基础的J2SE学起吧....... 首先是了解 ...

  10. 解Tom大叔出的Javascript题目

    原文参考,http://www.cnblogs.com/TomXu/archive/2012/02/10/2342098.html Tom大叔的博客深入理解Javascript系列真是我们学习Java ...