TCP/IP协议栈初始化(十一)完结篇-完成IP层与网卡的连接

上回ICMP的插曲说完了,把一个ICMP socket的创建流程说完了。对于数据结构关系图没有加入什么新元素。执行的流程是从inet_family_ops到inet_create,raw_prot,这样的执行顺序。此时完成的只是ICMP协议的处理socket。继续看源码,icmp_init函数返回后,后面还有内容。当然要有,IP层和设备还没有关联呢。走继续看。
其实仔细一看,我们的协议栈的初始化也基本上接近尾声了。下面是来到1434行的一个函数调用。一般预编译里的内容,我会选择跳过,但这次要破例下。是的,你总想在自己的人生中坚持自己的原则,但总会有些人会让你破坏自己的原则。没有错,这个函数正是这样的。
1434 ip_mr_init()
函数定义在net/ipv4/ipmr.c中。

1887 {
1888 	mrt_cachep = kmem_cache_create("ip_mrt_cache",
1889 				       sizeof(struct mfc_cache),
1890 				       0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
1891 				       NULL);
1892 	init_timer(&ipmr_expire_timer);
1893 	ipmr_expire_timer.function=ipmr_expire_process;
1894 	register_netdevice_notifier(&ip_mr_notifier);
1895 #ifdef CONFIG_PROC_FS
1896 	proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops);
1897 	proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops);
1898 #endif
1899 }

1888 申请了一个缓存对象,对象单元是struct mfc_cache。一般协议栈里的缓存都会记录在协议的数据结构里,作为成员存在。这里没有采用这样的方式。暂不明白。
1892 初始化了一个定时器。同之前说过的路由表一样,多播路由表也有超时的时间。看expire就是超期的意思。看源码的同时还学习了英文,多好。一箭双雕。
1893 超时定时器的事件处理函数。暂时记下就行,等超时了再去看,它干了什么。
1894 同路由表一样,多播路由表也要接受特定的消息来自我更新。注册一个通知消息的处理实例吧。同样暂且不表。
后面两个可以跳过。不能每次都破例。总结来说,这个函数,为多播创建了条件,可以存贮、更新多播路由表。
回到inet_init。来了一个函数。mibs是什么东西?s是表示复数,mib 什么?这个光猜是猜不出来的。我负责地去源码里找了一圈,没有找到。最后去bing的词典里查了下,是Management Information Base,可以翻译为管理信息库。

1440 	if (init_ipv4_mibs())
1441 		printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); 

然而这个函数我没有打算把源码列出来,分析一下。没有什么新鲜的东西,全是协议栈的数据统计结构实例,形如xxx_statistics的名称。然而,这是一个吉兆,如周易里的“见龙在田,利见大人”一样。这预示着,我们的协议栈初始化基本上完成了,快可以工作了。
1443 这个我打算跳过。还是去/proc目录下创建一些目录和文件,提供访问协议栈的接口。
1445 ipfrag_init();
这个是关于IP分片的初始化。当从上层协议中得到的数据分组,比当前链路层中的MTU还大时,IP就要开始分片了。本以为它会很复杂,进去一看,一堆初始化赋值,外加一个函数调用。函数来自net/ipv4/ip_fragment.c中。

610 void __init ipfrag_init(void)
611 {
612 	ip4_frags.ctl = &ip4_frags_ctl;
613 	ip4_frags.hashfn = ip4_hashfn;
614 	ip4_frags.constructor = ip4_frag_init;
615 	ip4_frags.destructor = ip4_frag_free;
616 	ip4_frags.skb_free = NULL;
617 	ip4_frags.qsize = sizeof(struct ipq);
618 	ip4_frags.match = ip4_frag_match;
619 	ip4_frags.frag_expire = ip_expire;
620 	inet_frags_init(&ip4_frags);
621 }

至此需要引入一个管理数据结构实例。ip4_frags,类型为struct inet_frags。这个类型的具体成员,暂不去管。先记着,看我们会遇到哪些内容。
612 初始化了一个控制成员变量。
613-615 初始化散列函数,初始化函数,释放函数(C++中的析构函数)。
616 把skb_free给置空。为什么?或许ip4_frags永远都不是真正拥有sk_buff,所以就不可去释放它。
617 ip4_frags维护了一个队列,这个队列的单元长度被赋心struct ipq的字节长度。一个典型的生产者消费者模式。我理解的这里的队列,既可能是接收的队列,也可能是发送的队列。
618 一个匹配函数。什么时候会执行呢?暂时我也不知道。
619 设置一个超时处理函数。函数头部的注释中写着,如果超时了要清空整个队列了。这个会在什么情况下发生呢?IP协议告诉我们,IP分片发生在发送端,也可能是中间的路由器上。但分片重装只会发生在目的主机上。当目的主机上的IP分片接收队列中,有一个分片丢失了,这个时候,由于IP协议本身没有重传机制,只能通过额外的机制,来触发清空整个分片接收队列,来进行重新接收。
620 针对inet层对ip4_frags进一步的初始化。这个函数只说明下它的功能,不再列源码。初始化ip4_frags的散列表,散列随机数,缓存计数,初始化重建定时器。
从ipgfrag_init中返回。看到了最后一个函数
1447 dev_add_pack(&ip_packet_type);
至此我们的IP层和设备关联起来了,以后网卡接到的IP分组的数据就会发给IP协议了。先看下传入的参数ip_packet_type,定义在af_net.c中。

1348 static struct packet_type ip_packet_type = {
1349 	.type = __constant_htons(ETH_P_IP),
1350 	.func = ip_rcv,
1351 	.gso_send_check = inet_gso_send_check,
1352 	.gso_segment = inet_gso_segment,
1353 };

这里重点关注ip_rcv的成员函数。对,它就是IP分组数据进入IP层的入口函数。其他成员先不看,ip_rcv的光环太耀眼了。而dev_add_pack,之前有遇到过,只是把ip_packet_type挂在了ptype_base的全局列表里。
至此协议栈的初始化完成了,可以工作了,刚好11篇,真是个好数字。随后的一篇中,我会把整个流程再梳理一下,把关系图完善下。之后,开始协议栈工作之旅了:)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值