Chinaunix首页 | 论坛 | 博客
  • 博客访问: 349293
  • 博文数量: 69
  • 博客积分: 3077
  • 博客等级: 中校
  • 技术积分: 602
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-11 09:40
个人简介

或以为孤权重,妄相忖度

文章分类

全部博文(69)

文章存档

2012年(1)

2011年(10)

2010年(39)

2009年(19)

我的朋友

分类: 嵌入式

2011-05-11 16:13:30

2010-1-6

1.         ARP:

从功能上来说,arp可以简单的分成两个部分:

a.       当我要向目的ip发送一个数据包的时候,需要通过arp实现ip到物理地址(一般为mac地址)的映射------------ethernet_output函数

b.       处理输入包,更新arp缓存,如果是ip包后递交给ip层,如果是arp包,对于不同的arp操作做相应的相应------------etharp_input函数。

 

ethernet_input函数:

以太网的帧类型可以是:IPARP 甚至可以是pppoe wlan等。这里主要分为IP, ARP(注意:ip arp在以太网的帧类型中是并列的,所以在input这个函数中分为iparp两大部分)

对于ip类型的:主要工作就是看是否开启了ETHARP_TRUST_IP_MAC这个选项,如果开启了就是要用这个帧中的信息来更新arp缓冲(利用帧首部的源mac地址和帧数据中ip报文中的源ip地址),然后丢弃以太网帧首部传递给ip层(即ip_input)。

 

对于arp类型的:同样先更新arp缓存,然后判断arp报文的操作类型,在lwip中对于arp数据包实现了两种操作:(rarp请求,rarp响应已经几乎淘汰了)

aarp请求:首先判断这个包是不是给本机的,如果是给本机的,在原有包的基础上重组一个回应包并发出(注意此处并没有重新分配一个pbuf,而是借用了原来的缓冲结构)。如果不是本机的忽略。、

barp回应:主要的工作是更新arp缓存,但是这一步已经在arp包刚进来的时候就处理了,所以这里不需要再重复做,这里有一些dhcp的东东,暂时还未涉及到。

 

这里无论是ip类型,还是arp类型,都会更新arp缓存,也就是我们的

update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags),其中netif是对应的网络接口,ipaddrethaddr分别是对应的ip地址和mac地址。这个函数中会去更新arp缓存,并且把这个arp表项的等待的队列通过发送函数发送出去()。

update_arp_entry先通过调用find_entry找到对应ipaddr对应的表项——>设置相应的arp选项的成员(主要是state netif ethaddr cttime)——>如果定义了arp_queue的话,并且这个arp表项上有未发送队列的话,把这些队列发送出去。其中find_entry这个函数蛮重要的,下面解释下这个函数的流程。

find_entry

1.       lwip有一个比较巧妙的地方,它并不是冲上去就是就把arp缓存中所有的表项搜索一遍,而是做了一个假设,假设这次的表项索引还是上一次的,if so ,we are really fast!(因为在很多情况下就是这样的)

2.       首先搜索分成三类,emptysuspendingstable。第一个是对状态为empty的检查,arp表项中第一个状态为empty的索引号,第二个对状态为suspend的检查,分成三部分,首先判断是否恰好为此次想要的ip对应的索引,如果是直接返回;不是的话又分这个索引是有queue还是没有queue,分别记录这两种类型中cttime最大的一个索引,第三个是对状态为stable的检查,分成两部分,首先判断是否恰好为此次想要的ip对应的索引,如果是直接返回;不是的话,记录状态为stablecttime最大的(时间戳,最老的)。

因此这部分,主要做了两件事:

●如果arp缓存中有现成的索引,则直接返回(状态时suspendstable);

●通过索引记录几个重要的参数:a. arp表项中第一个状态为empty的索引号 b. arp表项中最老的状态为suspend的有queue的索引号 c. arp表项中最老的状态为suspend的没有queue的索引号 d. arp表项中最老的状态为stable的索引号。这些参数是在arp缓存没有现成索引号时,会根据优先级来对这四个参数来选择或删除表项。优先级等级一次为:empty——》oldest stable——》oldest pending without queue——》oldest pending with queue

3.       arp没有现存的缓存,而状态又不是empty的选项,意味着需要在里面删除现有的arp选项,这里则需要调用snmp_delete****,由于snmp的东东暂时还未看到,这里就不详细讲了。

4.       最后更新表项的一些成员,有状态,时间戳,索引缓存

ethernet_output函数:

由于是发送ip数据包,所以一开始需要增加缓冲区大小,大小为以太网的数据首部的大小。然后检查ip地址,可以分为广播包,多播包,单播包(单播包又分为是局域网内部还是局域网外面)

广播包:判断目的ip地址是不是为全1,或者是全0(老版本中使用的),如果是广播包则目的ipmac地址不需要查询arp缓存或者发送arprequestmac地址为全一,即0xff,0xff,0xff,0xff,0xff,0xff

多播包:判断目的ip地址是不是d类地址,即eXXXX,如果是多播的话,mac地址也是确定的,即将ip地址的低23位映射到mac地址为01-00-5e-00-00-00的低23位上。

单播包:要比较目的ip和本地ip地址,看是否是局域网内的,不是局域网内的,则调用默认网关的地址,然后再统一调用etharp_query(netif, ipaddr, q);函数

而广播包和多播包则无需调用etharp_query(netif, ipaddr, q);函数,因为已经得到了明确的mac地址,基本只需要添加以太网帧首部然后发送即可。

 

etharp_query:大概流程如下:

a.  先通过ipaddr利用函数find_entry找到arp缓存中的索引号

b.  根据索引号就能得到arp的对应项,此时根据项的state分成三大类,

empty:说明原来表项中是没有这个arp缓存的,所以把表项状态切换为pending并发送arp_requst包,把待发送的数据放在这个entry(表项)的队列上,系统在input的时候解析了这个ip后会发送(具体可以看前面input中的讲解);

pending:说明这个ip原来就有了,我们再重新发一次arp_request,同样把待发送数据放在队列上;

stable:说明在arp缓存中ip地址已经有了解析的mac地址,此时又分成两类,一类是数据包不为空,则直接调用etharp_send_ip函数发送;第二类是如果数据包为空,则说明是一个request包,还是调用arp_request

阅读(1801) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~