声卡 驱动,今天限行尾号,黄山汽车站
这已经是第六篇了。但协议栈的初始化还没有说完。不得不承认协议栈还是很复杂的。越是牛B的东西,就越复杂。就像一门手艺一样,当你可以做到别人都不能达到的复杂度的时候,你就是大师了。还有人说,想要精通一样技术,你必须重复它10万次以上。子曰:“温故而知新”,代码看多了,就能明白其中的奥秘了。当然一些实践还是必不可少的。这个系列一开始,我就说,协议栈很牛,所以它复杂也在情理之中。学习到现在,对协议栈,感觉自己刚入门。继续看代码。1404 void __init ip_init(void) 1405 { 1406 ip_rt_init(); 1407 inet_initpeers(); 1409 #if defined(CONFIG_IP_MULTICAST) && defined(CONFIG_PROC_FS) 1410 igmp_mc_proc_init(); 1411 #endif 1412 }很简单的三个函数调用。第三个函数只是为igmp协议在虚拟文件系统proc中创建目录,不再讨论。前两个函数依次展开讨论下。第一个是ip_rt_init()。在TCP/IP协议族里,rt就代表route,路由的意思。ip_rt_init就是ip系统里路由子系统的初始化。因为路由是IP协议的一个主要功能,没有这个功能,互联网就不存在了。可见其重要性。这个函数位于net/ipv4/route.c中。是目前看到的比较复杂的一个函数。为了方便查看,我把其中预编译的部分去掉了。
2922 int __init ip_rt_init(void) 2923 { 2924 int rc = 0; 2926 rt_hash_rnd = (int) ((num_physpages ^ (num_physpages>>8)) ^ 2927 (jiffies ^ (jiffies >> 7))); 2942 ipv4_dst_ops.kmem_cachep = 2943 kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0, 2944 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); 2946 ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep; 2948 rt_hash_table = (struct rt_hash_bucket *) 2949 alloc_large_system_hash("IP route cache", 2950 sizeof(struct rt_hash_bucket), 2951 rhash_entries, 2952 (num_physpages >= 128 * 1024) ? 2953 15 : 17, 2954 0, 2955 &rt_hash_log, 2956 &rt_hash_mask, 2957 0); 2958 memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket)); 2959 rt_hash_lock_init(); 2961 ipv4_dst_ops.gc_thresh = (rt_hash_mask + 1); 2962 ip_rt_max_size = (rt_hash_mask + 1) * 16; 2964 devinet_init(); 2965 ip_fib_init(); 2967 init_timer(&rt_flush_timer); 2968 rt_flush_timer.function = rt_run_flush; 2969 init_timer(&rt_secret_timer); 2970 rt_secret_timer.function = rt_secret_rebuild; 2975 schedule_delayed_work(&expires_work, 2976 net_random() % ip_rt_gc_interval + ip_rt_gc_interval); 2978 rt_secret_timer.expires = jiffies + net_random() % ip_rt_secret_interval + 2979 ip_rt_secret_interval; 2980 add_timer(&rt_secret_timer); 3000 rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL); 3002 return rc; 3003 }2924-2962 分配了资源,初始化了路由的散列表,初始化路由表的一些限制(最大数量等)。可以看到同tcp_proto一样,ipv4_dst_ops是路由表(struct rt_table)内存资源的持有者,它还负责dst路由表的维护。真正把路由表组织起来的是rt_hash_table。因为内核要经常访问路由表,修改它,所以要用到散列的实现高效的查找访问。这两个数据结构都位于route.c文件中。让我们暂时记下这些数据结构,以后会再次遇到它们。
158 static struct dst_ops ipv4_dst_ops = { 159 .family = AF_INET, 160 .protocol = __constant_htons(ETH_P_IP), 161 .gc = rt_garbage_collect, 162 .check = ipv4_dst_check, 163 .destroy = ipv4_dst_destroy, 164 .ifdown = ipv4_dst_ifdown, 165 .negative_advice = ipv4_negative_advice, 166 .link_failure = ipv4_link_failure, 167 .update_pmtu = ip_rt_update_pmtu, 168 .entry_size = sizeof(struct rtable), 169 }; 247 static struct rt_hash_bucket *rt_hash_table; 207 struct rt_hash_bucket { 208 struct rtable *chain; 209 };继续看,2964,完成与协议栈有关的设备初始化。这个函数不复杂,源码不再列出,对于协议栈的数据结构没有什么补充,需要注意到以下事情:
912 void __init ip_fib_init(void) 913 { 914 unsigned int i; 916 for (i = 0; i < FIB_TABLE_HASHSZ; i++) 917 INIT_HLIST_HEAD(&fib_table_hash[i]); 919 fib4_rules_init(); 921 register_netdevice_notifier(&fib_netdev_notifier); 922 register_inetaddr_notifier(&fib_inetaddr_notifier); 923 nl_fib_lookup_init(); 925 rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL); 926 rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL); 927 rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib); 928 }919行 fib4_rules_init(); 使用过linux iptables的人都知道,iptables是基于规则对IP数据包进行过滤,实现防火墙的功能。那么猜测这里的fib很可能与之有关系。因为带了一个rule。fib4_rules_init内容很简单,其源码不再列出,只是注册了但又会出现一个数据结构,就是fib4_rules_ops,其内容如下,在/net/ipv4/fib_rules.c中定义。全部是关于fib4_rules的操作,具体成员函数不再分析。fib4_rules_ops通过注册,被挂靠在了双向链表rules_ops上。OS以后也就是通过这个链表来搜寻到fib4_rules_ops,完成规则的适配。
277 static struct fib_rules_ops fib4_rules_ops = { 278 .family = AF_INET, 279 .rule_size = sizeof(struct fib4_rule), 280 .addr_size = sizeof(u32), 281 .action = fib4_rule_action, 282 .match = fib4_rule_match, 283 .configure = fib4_rule_configure, 284 .compare = fib4_rule_compare, 285 .fill = fib4_rule_fill, 286 .default_pref = fib4_rule_default_pref, 287 .nlmsg_payload = fib4_rule_nlmsg_payload, 288 .flush_cache = fib4_rule_flush_cache, 289 .nlgroup = RTNLGRP_IPV4_RULE, 290 .policy = fib4_rule_policy, 291 .rules_list = LIST_HEAD_INIT(fib4_rules_ops.rules_list), 292 .owner = THIS_MODULE, 293 };继续ip_fib_init函数。921-922为FIB注册了网卡事件处理函数和地址事件处理函数的接口数据结构。挂靠的上级数据结构,分别是netdev_chain(net/core/dev.c),inetaddr_chain(net/ipv4/devinet.c)。当对应类别的事件发生时,两个chain中所有处理全程,都会得到通知。
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
网友评论