网络模块初始化

网络模块的初始化顺序

系统启动初始化时,一旦进入start_kernel,则说明低级初始化已经完成,接下来是对各种设备和子系统的初始化,网络模块初始化流程的调用关系如下图(图片来自:《Linux内核源码剖析-tcp/ip实现》):

在内核初始化过程中,初始化了很多模块,如图中的中断模块(init_irq)等。最后会启动init内核线程继续执行初始化,完成初始化之后,init内核现成将蜕变成用户进程。有关网络的初始化过程主要由sysctl_init和do_initcalls完成,前者主要完成对sysctl的初始化注册过程,后者的功能相对复杂,不只是对网络模块的初始化,只要运用了initcall技术的模块都会被初始化;

内核模块代码可以静态地连接到内核映像文件中,也可以动态的加载到内核空间中,通常,设备驱动程序和功能扩展模块都是在需要时动态加载的,有些协议族也作为内核模块动态加载,如ipv6、unix协议族等,而作为基本内核模块的ipv4则不能动态加载。

 

优化基于宏的标记

以e100为例,通过宏展开得到以下内容:

module_init(e100_init_module) –>__initcall(e100_init_module)–>device_initcall(e100_init_module)–>__define_initcall(e100_init_module, 6)–>static initcall_t __initcall_e100_init_module6 __used __attribute__((__section__(“.initcall6.init”))) = e100_init_module

 1 /*
 2  * initcalls are now grouped by functionality into separate
 3  * subsections. Ordering inside the subsections is determined
 4  * by link order. 
 5  * For backwards compatibility, initcall() puts the call in 
 6  * the device init subsection.
 7  *
 8  * The `id' arg to __define_initcall() is needed so that multiple initcalls
 9  * can point at the same handler without causing duplicate-symbol build errors.
10  *
11  * Initcalls are run by placing pointers in initcall sections that the
12  * kernel iterates at runtime. The linker can do dead code / data elimination
13  * and remove that completely, so the initcall sections have to be marked
14  * as KEEP() in the linker script.
15  */
16 
17 #define __define_initcall(fn, id) \
18     static initcall_t __initcall_##fn##id __used \
19     __attribute__((__section__(".initcall" #id ".init"))) = fn;
20 
21 /*
22  * Early initcalls run before initializing SMP.
23  *
24  * Only for built-in code, not modules.
25  */
26 #define early_initcall(fn)        __define_initcall(fn, early)
27 
28 /*
29  * A "pure" initcall has no dependencies on anything else, and purely
30  * initializes variables that couldn't be statically initialized.
31  *
32  * This only exists for built-in code, not for modules.
33  * Keep main.c:initcall_level_names[] in sync.
34  */
35 #define pure_initcall(fn)        __define_initcall(fn, 0)
36 
37 #define core_initcall(fn)        __define_initcall(fn, 1)
38 #define core_initcall_sync(fn)        __define_initcall(fn, 1s)
39 #define postcore_initcall(fn)        __define_initcall(fn, 2)
40 #define postcore_initcall_sync(fn)    __define_initcall(fn, 2s)
41 #define arch_initcall(fn)        __define_initcall(fn, 3)
42 #define arch_initcall_sync(fn)        __define_initcall(fn, 3s)
43 #define subsys_initcall(fn)        __define_initcall(fn, 4)
44 #define subsys_initcall_sync(fn)    __define_initcall(fn, 4s)
45 #define fs_initcall(fn)            __define_initcall(fn, 5)
46 #define fs_initcall_sync(fn)        __define_initcall(fn, 5s)
47 #define rootfs_initcall(fn)        __define_initcall(fn, rootfs)
48 #define device_initcall(fn)        __define_initcall(fn, 6)
49 #define device_initcall_sync(fn)    __define_initcall(fn, 6s)
50 #define late_initcall(fn)        __define_initcall(fn, 7)
51 #define late_initcall_sync(fn)        __define_initcall(fn, 7s)
52 
53 #define __initcall(fn) device_initcall(fn)
54 
55 #define __exitcall(fn)                        \
56     static exitcall_t __exitcall_##fn __exit_call = fn
57 
58 #define console_initcall(fn)                    \
59     static initcall_t __initcall_##fn            \
60     __used __section(.con_initcall.init) = fn
61 
62 #define security_initcall(fn)                    \
63     static initcall_t __initcall_##fn            \
64     __used __section(.security_initcall.init) = fn
65 
66 
67 /**
68  * module_init() - driver initialization entry point
69  * @x: function to be run at kernel boot time or module insertion
70  *
71  * module_init() will either be called during do_initcalls() (if
72  * builtin) or at module insertion time (if a module).  There can only
73  * be one per module.
74  */
75 #define module_init(x)    __initcall(x);
76 
77 /**
78  * module_exit() - driver exit entry point
79  * @x: function to be run when driver is removed
80  *
81  * module_exit() will wrap the driver clean-up code
82  * with cleanup_module() when used with rmmod when
83  * the driver is a module.  If the driver is statically
84  * compiled into the kernel, module_exit() has no effect.
85  * There can only be one per module.
86  */
87 #define module_exit(x)    __exitcall(x);

 

各个段空间对应的宏:

如图(图片来自:《Linux内核源码剖析-tcp/ip实现》):

 

 

通过下面的do_init_calls循环调用执行各个段的初始化函数:

 1 int __init_or_module do_one_initcall(initcall_t fn)
 2 {
 3     int count = preempt_count();
 4     int ret;
 5     char msgbuf[64];
 6 
 7     if (initcall_blacklisted(fn))
 8         return -EPERM;
 9 
10     if (initcall_debug)
11         ret = do_one_initcall_debug(fn);
12     else
13         ret = fn();
14 
15     msgbuf[0] = 0;
16 
17     if (preempt_count() != count) {
18         sprintf(msgbuf, "preemption imbalance ");
19         preempt_count_set(count);
20     }
21     if (irqs_disabled()) {
22         strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
23         local_irq_enable();
24     }
25     WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf);
26 
27     add_latent_entropy();
28     return ret;
29 }
30 
31 
32 extern initcall_t __initcall_start[];
33 extern initcall_t __initcall0_start[];
34 extern initcall_t __initcall1_start[];
35 extern initcall_t __initcall2_start[];
36 extern initcall_t __initcall3_start[];
37 extern initcall_t __initcall4_start[];
38 extern initcall_t __initcall5_start[];
39 extern initcall_t __initcall6_start[];
40 extern initcall_t __initcall7_start[];
41 extern initcall_t __initcall_end[];
42 
43 static initcall_t *initcall_levels[] __initdata = {
44     __initcall0_start,
45     __initcall1_start,
46     __initcall2_start,
47     __initcall3_start,
48     __initcall4_start,
49     __initcall5_start,
50     __initcall6_start,
51     __initcall7_start,
52     __initcall_end,
53 };
54 
55 /* Keep these in sync with initcalls in include/linux/init.h */
56 static char *initcall_level_names[] __initdata = {
57     "early",
58     "core",
59     "postcore",
60     "arch",
61     "subsys",
62     "fs",
63     "device",
64     "late",
65 };
66 
67 static void __init do_initcall_level(int level)
68 {
69     initcall_t *fn;
70 
71     strcpy(initcall_command_line, saved_command_line);
72     parse_args(initcall_level_names[level],
73            initcall_command_line, __start___param,
74            __stop___param - __start___param,
75            level, level,
76            NULL, &repair_env_string);
77 
78     for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
79         do_one_initcall(*fn);
80 }
81 
82 static void __init do_initcalls(void)
83 {
84     int level;
85 
86     for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
87         do_initcall_level(level);
88 }

 

注:本文中部分内容引用自《Linux内核源码剖析-tcp/ip实现》

posted @ 2017-09-17 15:25  AlexAlex  阅读(1154)  评论(0编辑  收藏  举报