1. 简介
Arp(Address Resolution Protocol,地址解析协议)是一种用于获取网络层地址和物理层地址的协议,它用于在互联网中将IP地址转换为MAC地址。本文将分析Linux内核中的Arp模块的源代码,探讨其实现原理和关键函数。
2. Arp模块结构
Linux内核中的Arp模块由多个文件组成,其中最重要的文件是`arp.c`和`arp.h`。
2.1 `arp.h`文件
`arp.h`文件定义了Arp模块的数据结构、常量和函数声明。其中包括:
struct arpreq {
struct sockaddr_in arp_pa; /* protocol address */
struct sockaddr_in arp_ha; /* hardware address */
int arp_flags;
struct sockaddr_in arp_netmask; /* netmask */
char arp_dev[16];
};
struct neighbour {
struct hh_cache *hh;
int nud_state;
__u8 ha[ETH_ALEN];
struct sk_buff_head arp_queue;
struct rcu_head rcu;
int arp_count;
__u32 primary_key;
unsigned long confirmed:1,
updated:1,
noref:1,
failcount:8;
int parms_cookie;
struct neighbour *proxy_redir;
__be32 saddr;
};
struct neightbl_config {
int entries;
unsigned int gc_thresh1;
unsigned int gc_thresh2;
unsigned int gc_thresh3;
struct neigh_table *tbl;
};
2.2 `arp.c`文件
`arp.c`文件是Arp模块的核心代码文件,实现了Arp协议的功能。其中包括了一系列实现Arp协议的函数,如:
3. Arp协议的实现原理
在Linux内核中,Arp模块首先会通过`arp_ioctl()`函数接收用户空间的Arp请求。
static int arp_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd)
{ ... }
然后,Arp模块会调用`arp_send()`函数向目标主机发送Arp请求,并等待目标主机的回复。
static void arp_send(int type, int ptype, int code, struct neighbour *neigh, struct sk_buff *skb)
{ ... }
当目标主机的Arp回复到达后,Arp模块会调用`arp_rcv()`函数进行处理。
static int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{ ... }
最后,Arp模块将Arp缓存存储在neighbour数据结构中,并通过`neigh_event_send()`函数通知其他模块。
static inline void neigh_event_send(struct neighbour *n, struct sk_buff *skb)
{ ... }
4. 关键函数解析
4.1 `arp_send()`函数
函数原型:`static void arp_send(int type, int ptype, int code, struct neighbour *neigh, struct sk_buff *skb)`
重要部分:
if (neigh_hh_init(skb, &neigh_hh_arg) == NULL)
goto out;
通过`neigh_hh_init()`函数初始化ARP缓存,存储目标主机的MAC地址。
4.2 `arp_rcv()`函数
函数原型:`static int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)`
重要部分:
for (p = &rcu_dereference_bh(arp_tbl[thash].arp_list[hh->hh_type]);
p != NULL;
p = pnext) {
pnext = p->next;
if (hh->hh_data.res.dst_lsb == p->ha[hh->hh_type]) {
ndo_appfunc(skb, ND_NET_ARP_IP);
if (!atomic_read(&skb->users))
kfree_skb(skb);
rcu_read_unlock_bh();
return skb->len;
}
}
通过遍历ARP缓存链表,查找并比对目标主机的MAC地址。
5. 总结
本文分析了Linux内核中的Arp模块的源代码,探讨了其实现原理和关键函数。Arp模块通过发送Arp请求并接收回复来获取目标主机的MAC地址,然后将其存储在Arp缓存中,以供后续使用。
在实际应用中,Arp模块对于网络通信起到了至关重要的作用,能够实现网络层地址和物理层地址之间的转换,提高了网络通信的效率和可靠性。同时,深入理解Arp模块的源代码对于Linux内核网络协议栈的学习和理解也具有重要意义。