分类: LINUX
2010-08-11 11:51:53
Kernel version : Kernel-2.6.11
每种网络协议都有一个初始化函数。静态包含在内核中的协议而言,初始化函数会在引导期间执行;就编译成模块的协议而言,当模块被加载时,初始化函数就会执行。初始化函数有一个重要的任务就是在内核里注册一个处理函数,以处理该协议的流量。
看一下IP协议的初始化函数ip_init():
static struct packet_type ip_packet_type = {
.type = __constant_htons(ETH_P_IP),
.func = ip_rcv,
};
void __int ip_init(void)
{
dev_add_pack(&ip_packet_type);
...
}
ip_init函数会在引导期间执行,并通过调用dev_add_pack函数把IP协议的ip_packet_type放入全局变量ptype_base所指的数组里。ip_packet_type是一个packet_type类型,type代表协议代码,func代表当type=ETH_P_IP时,就调用ip_rcv这个处理函数。
ptype_base是一个由16个列表组成的数组。当ip_init调用dev_add_pack函数注册时,它就会对协议类型进行hash函数,然后把packet_type结构放入16列表的其中一个。
看一下dev_add_pack函数:
void dev_add_pack(struct packet_type *pt)
{
int hash;
spin_lock_bh(&ptype_lock);
if (pt->type == htons(ETH_P_ALL)) {
netdev_nit++;
list_add_rcu(&pt->list, &ptype_all);
} else {
hash = ntohs(pt->type) & 15;
list_add_rcu(&pt->list, &ptype_base[hash]);
}
spin_unlock_bh(&ptype_lock);
}
如果pt->type是ETH_P_ALL,新增的处理函数为协议嗅探器,并添加到全局变量ptype_all里。pt->type不是ETH_P_ALL,得到一个hash值,并添加到全局变量ptype_base[hash]里。
当设备驱动程序接受到数据帧时,就会保存在一个skb_buff缓冲区数据结构里,然后对其成员protocol进行初始化。然后系统调用netif_receive_skb函数根据protocol值进行查询,确定把入口帧分派给正确的协议处理函数。当协议没有处理函数时,该帧就会被丢弃。
参考:LINUX网络技术内幕第十三章