290 likes | 470 Views
Arp.c—— 源代码注释 小组成员: 李婷 1071000114 罗雪 1071000118 史雅萌 1071000119 古丽布斯 1071000301. ARP ARP ,即 地址解析协议 ,实现通过 IP 地址 得知其物理地址。. 地址解析协议 ARP 是在主机 ARP 高速缓存( ARP cache )中存放一个从 IP 地址到硬件地址的映射表,并且这个映射表还经常动态更新。. 基本原理:
E N D
Arp.c——源代码注释 小组成员: 李婷 1071000114 罗雪 1071000118 史雅萌 1071000119 古丽布斯 1071000301
ARP ARP,即地址解析协议,实现通过IP地址得知其物理地址。
地址解析协议ARP是在主机ARP高速缓存(ARP cache)中存放一个从IP地址到硬件地址的映射表,并且这个映射表还经常动态更新。
基本原理: 当主机A要向本局域网上的某个主机C发送IP数据报时,就先在其ARP高速缓存中查看有无主机C的IP地址。 如有,就在ARP高速缓存中查出其对应的硬件地址,再把这个硬件地址写入MAC帧,然后通过局域网把该MAC帧发往此硬件地址。
如果在ARP缓存表中没有找到目标IP地址,可能是主机C才入网,也可能是主机A刚加电,其高速缓存还是空的。这种情况下,主机A就自动运行ARP,然后按以下步骤找出主机C的地址。
1.ARP进程在本局域网上广播发送ARP请求分组。 分组内容表明:我的IP地址是209.0.0.5,硬件地址是00-00-C0-15-AD-18请问IP地址为209.0.0.6的硬件地址是什么?”
2.在本局域网上的所有主机上运行的ARP进程都收到此ARP请求分组。2.在本局域网上的所有主机上运行的ARP进程都收到此ARP请求分组。
3.主机C在ARP请求分组中见到自己的IP地址,就向主机A发送ARP响应分组,并写入自己的硬件地址。其余的所有主机都不理睬这个ARP请求分组。3.主机C在ARP请求分组中见到自己的IP地址,就向主机A发送ARP响应分组,并写入自己的硬件地址。其余的所有主机都不理睬这个ARP请求分组。 响应分组表明:我的IP地址是209.0.0.6,我的硬件地址是08-00-2B-00-EE-0A。
4.主机A接受到主机C的ARP响应分组后,就在其ARP高速缓存中写入主机C的IP地址到物理地址的映射。4.主机A接受到主机C的ARP响应分组后,就在其ARP高速缓存中写入主机C的IP地址到物理地址的映射。
在完成以上步骤的同时A和C还同时都更新了自己的ARP缓存表,下次A再向主机C或者C向A发送信息时,直接从各自的ARP缓存表里查找就可以了。在完成以上步骤的同时A和C还同时都更新了自己的ARP缓存表,下次A再向主机C或者C向A发送信息时,直接从各自的ARP缓存表里查找就可以了。 大大增加了网络上的通信量。
ARP缓存表采用了老化机制(即设置了生存时间),在一段时间内(一般15到20分钟)如果表中的某一行没有使用,就会被删除,这样可以大大减少ARP缓存表的长度,加快查询速度。ARP缓存表采用了老化机制(即设置了生存时间),在一段时间内(一般15到20分钟)如果表中的某一行没有使用,就会被删除,这样可以大大减少ARP缓存表的长度,加快查询速度。
设想有一种情况,主机A和C通信,A的ARP高速缓存里有C的硬件地址,但C的网络适配器突然坏了,C立即更换了一块,因此C的硬件地址就改变了,A在其ARP缓存中查找原先的硬件地址,因为C原先的硬件地址已经失效,所以无法找到C,但是如果过了定时器设定的时间,A的缓存表中已经删除了C的硬件地址,于是A重新广播发送ARP请求分组,又可以找到C.
使用ARP的四种典型情况 1.发送方是主机,要把IP数据报发送到本网络上的另一个主机。这时用ARP找到目的主机的物理地址。 2.发送方是主机,要把IP数据报发送到另一个网络上的一个主机。这时用ARP找到本网络上的一个路由器的物理地址。剩下的工作由这个路由器来完成。
3.发送方是路由器,要把IP数据报转发到本网络上的一个主机。这时用ARP找到目的主机的物理地址。3.发送方是路由器,要把IP数据报转发到本网络上的一个主机。这时用ARP找到目的主机的物理地址。 4.发送方是路由器,要把IP数据报转发到另一个网络上的一个主机。这时用ARP找到本网络上的一个路由器的物理地址。剩下的工作由这个路由器来完成。
1、Arp_table • arp_tbl是一个类型为struct neigh_table的全局变量,它是一个ARP的缓存表,也称为邻居表。协议栈通过ARP协议获取到的网络上邻居主机的IP地址与MAC地址的对应关系都会保存在这个表中,以备下次与邻居通讯时使用,同时,ARP模块自身也会提供一套相应的机制来更新和维护这个邻居表。 • 下面逐个分析arp_tbl中的 重要成员数据与函数:
1)entry_size,key_len,kmem_cachep • entry_size是一个入口的大小,也就是arp_tbl中一个邻居的大小,邻居用struct neighbour结构体表示,该结构体的最后一个成员是u8 primary_key[0],用于存放IP地址,作为这个邻居的哈希主键。 • entry_size的大小就是sizeof(struct neighbour) + 4,由于用IP地址作主键,所以key_len就是4。 • kmem_cachep是一个后备高速缓存,创建一个邻居需要的内存从这个后备高速缓存中去取。
2)hash_buckets,hash_mask,entries,hash • hash_buckets是一个哈希数组,里面存放了arp_tbl当前维护的所有的邻居,hash_mask是哈希数组大小的掩码,其初始值为1,所以hash_buckets的初始大小为2(0到hash_mask的空间范围)。entries是整个arp_tbl中邻居的数量,当entries大于hash_mask+1的时候,hash_buckets增长为原来的两部。成员hash是一个哈希函数指针,用于计算哈希值。
3)phash_buckets,PNEIGH_HASHMASK • 这是用于代理ARP的邻居哈希表,PNEIGH_HASHMASK固定为0xF,所以phash_buckets固定有16项,其它与hash_buckets相同。 4)id • id作为这个邻居表的一个名称,是一个字符串信息,内核协议栈的arp_tbl的id是arp_cache。
5)gc_interval,gc_thresh1/2/3 • gc_interval应该是常规的垃圾回收间隔时间,被缺省置为30秒,但目前在源代码中似乎没有看到它的应用。 • gc_thresh1的用途暂时还没有发现,它缺省被置为128。 • gc_thresh2是第二个阀值,如果表中的邻居数量超过这个阀值,并且在需要创建新的邻居时,发现已经超过5秒时间表没有被刷新过,则必须立即刷新arp_tbl表,进行强制垃圾回收,这个值缺省被置为512。 • gc_thresh3是arp_tbl中允许拥有的邻居数量的上限,一旦超过这个上限,并且表中没有可以清理掉的垃圾邻居,那么就无法创建新的邻居,这个值缺省被置为1024 。
2、arp_print——转储ARP数据包 • arp_print(struct arphdr *arp) • { • int len, idx; • unsigned char *ptr; • if (inet_debug != DBG_ARP) return; • printk("ARP: "); • if (arp == NULL) { • printk("(null)\n"); • return; • }
3、arp_send_q()——发送ARP数据包 • arp_send_q(void) //arp数据报的发送 • { • struct sk_buff *skb; • struct sk_buff *volatile work_q; //定义sk_buff结构体指针 • cli(); • work_q = arp_q; • skb_new_list_head(&work_q); //skbuff为双向循环链表,该函数是为了在链表头部加入新的skb • arp_q = NULL; • sti(); • while((skb=skb_dequeue(&work_q))!=NULL) • { // 检查所有以&work_q为对首的队列中的包,若未超过重传限制的就发送,否则销毁。//如果包未准备好,就把包放入&arp_q为队首的队列中去。下次arp_send_q调用时再处理。处理过程同上。
4、arp_timer • timer是邻居的定时器,用于解析ARP,其超时函数是neigh_timer_handler。 • 定时器处理函数neigh_timer_handler首先确定下次的超时时间(如果这次解析没有成功)为当前时间加上parms的成员retrans_time的值(缺省设置为1秒)。所以,ARP解析的发包超时时间是1秒,连续尝试3次。ARP解析是通过ops的成员函数solicit去做的,该成员函数指针指向的arp_solicit函数,arp_solicit会实际发送ARP请求包。
5、arp_response——arp回复 • 在[arp]中,网关设备把自己的mac地址填充在arp response中,发送给原请求者。当然收到arp response之后也会把这个arp信息缓存下来,这样一个arp的过程就完成了。 • 以arp response的形式发送广播,它通常只是为了把自己的arp信息通告/更新给局域网全体,这种response不需要别人请求,是自己主动发送的通告。
6、arp_lookup • arp_lookup函数从ARP缓存表中以目的IP地址(网关IP或者同一子网内的对端IP地址)为哈希主键,寻找相应的邻居,如果找到的邻居的成员dev等于当前的网络设备接口,且primary_key等于当前的目的IP地址,则即为需要的邻居,返回即可。如果找不到,则创建。
7、arp_destructor——删除缓存表中的arp映射项 • 每个neighbour结构通过都neigh_ops定义了一组操作函数集,neigh_ops结构都由其父亲neigh_table定义的构造函数填充(include/net/neighbour.h). • struct neigh_ops • { • int family; • void (*destructor)(struct neighbour *); • void (*solicit)(struct neighbour *, struct sk_buff*); • void (*error_report)(struct neighbour *, struct sk_buff*); • int (*output)(struct sk_buff*); • int (*connected_output)(struct sk_buff*); • int (*hh_output)(struct sk_buff*); • int (*queue_xmit)(struct sk_buff*); • };
8、 arp_destroy——删除无效的映射项 • void arp_destroy(unsigned long paddr) • { • arp_destructor(paddr,1); • } • /* • 删除可能是无效的条目 • */
9、arp_create • arp_lookup函数从ARP缓存表中找不到相应的邻居,如果找不到,则需要通过调用arp_create函数创建一个新的邻居。 • 邻居被直接置成NUD_STALE(过期)状态。如果未被 使用,则在60秒(parms->gc_staletime)后被定期回收的定时器处理函数回收掉。
10、arp_rvc —— 函数用于网络层收到一个arp请求时,测试请求包的内容 int arp_rcv(struct sk_buff *skb, /*接收到的包缓冲区指针*/ struct net_device *dev, /*接收到ARP包的网卡设备结构*/ struct packet_type *pt /*捕获的协议包类型, { struct arphdr *arp = skb->nh.arph; /*获取以太网帧中的数据部分 unsigned char *arp_ptr= (unsigned char *)(arp+1); struct rtable *rt; /*路由结构指针*/ unsigned char *sha, *tha; /*源、目的硬件地址指针*/ u32 sip, tip; /*源、目的IP地址*/ u16 dev_type = dev->type; /*网络设备硬件类型*/ int addr_type; /**/ struct in_device *in_dev = in_dev_get(dev); /*IP层设备结构指针*/ struct neighbour *n; /*邻居结构指针*/ • 包的硬件长度应该和网络设备的硬件长度匹配硬件类型也需要匹配,设备应该是支持ARP的.同时如果pln!=4,则ARP查找并非来自IP协议。这些情况都将包丢弃.