您的位置:首页 > 理论基础 > 计算机网络

网络子系统初始化--系统启动时初始化

2010-11-14 15:15 288 查看
网络启动初始化函数入口为net/socket.c:2200:socket_init()

static int __init sock_init(void)
{
/*
*      Initialize sock SLAB cache.
*/
sk_init();
/*
*      Initialize skbuff SLAB cache
*/
skb_init();
/*
*      Initialize the protocols module.
*/
init_inodecache();
register_filesystem(&sock_fs_type);
sock_mnt = kern_mount(&sock_fs_type);
/* The real protocol initialization is performed in later initcalls.
*/
#ifdef CONFIG_NETFILTER
netfilter_init();
#endif
return 0;
}


sock_init()函数结构很简单,实现的功能也非常简单,下面逐个进行解析:

1.sk_init()

void __init sk_init(void)
{
if (num_physpages <= 4096) {
sysctl_wmem_max = 32767;
sysctl_rmem_max = 32767;
sysctl_wmem_default = 32767;
sysctl_rmem_default = 32767;
} else if (num_physpages >= 131072) {
sysctl_wmem_max = 131071;
sysctl_rmem_max = 131071;
}
}


该函数初始化了两个极值:sysctl_wmem_max和sysctl_rmem_max。这两个值就是来控制我们执行setsockopt系统调用时对SNDBUF和RCVBUF设置的最大值。和该函数被调用时所说的“Initialize sock SLAB cache.”的描述有些不符。

2.skb_init()。该函数只是申请了两个struct sk_buff的slab,sk_buff是linux网络实现中最重要的结构体之一,在网络协议的各层都被使用到,用来存储数据。

3.init_inodecache()。为将来要创建的所有的socket申请一个slab。

4.register_filesystem(),kern_mount()。

注册了一个socket的pseudo文件系统,并进行挂载,该文件系统不能在用户空间mount。那该文件系统的作用何在呢?我们知道在linux系统上一切皆文件,那socket当然也不能例外。既然是文件,就要有inode;既然有inode,就要有super_block;既然有super_block,就要有file_system_type,就要注册文件系统。

在这里注册的是一个伪文件系统[net/socket.c:304:sock_fs_type],这个file_system_type主要提供了一个sockfs_get_sb()函数,获取sock_fs的super_block。

sockfs的super_block主要提供了一个sock_alloc_inode(),这个函数是用来获取sockfs的inode。因为一个socket和一个inode相对应,为了简化实现和提高访问速度,内核里的实现是将socket和inode分配在同一片连续的内存区,通过宏SOCKET_I()[include/net/sock.h:783]和SOCK_INODE()[include/net/sock.h:788]来在这两个结构体间进行切换,通过sock_alloc()[net/socket.c:481]来申请一个socket

至此,socket系统初始化阶段完成。

下面说一些题外话,关于socket初始化时所用到的这两个文件系统的接口。

register_filesystem(),该函数主要维护了系统中的一个单链表:file_systems[fs/filesystems.c:32]。新来的文件系统不停的加到前一个文件系统的->next上。每一个文件系统类型在系统中只注册一次,这是一个文件系统的总入口,该接口主要提供了一个接口:get_sb(),用来在文件系统被mount时获取super_block和vfsmount。

另外,这个这个函数还有一个特点就是没有被显示的调用,那它是在什么时候运行的呢?经观察发现,返回值类型声明后跟有一个__init,另外在函数的下方还有这样一个声明:

2231 core_initcall(sock_init);       /* early initcall */


这另我们想起了module_init(),实际上他们的实现类似,他们的作用都是将初始化函数的地址放到系统的某一块内存中,在启动的时候逐个调用,那么到底是谁调用的呢?这就要使用强大的调试工具gdb来给我们解释了,在此处设置断点,执行bt可以发现

 

#0  sock_init () at /usr/src/linux-2.6.29.i586/net/socket.c:2206
#1  0xc10013bb in do_one_initcall (fn=0xc1b3c442 <sock_init>) at /usr/src/linux-2.6.29.i586/init/main.c:722
#2  0xc1b01b0c in do_initcalls () at /usr/src/linux-2.6.29.i586/init/main.c:762
#3  0xc1b01b3c in do_basic_setup () at /usr/src/linux-2.6.29.i586/init/main.c:782
#4  0xc1b01bd9 in kernel_init (unused=0x0) at /usr/src/linux-2.6.29.i586/init/main.c:874
#5  0xc1005e4b in kernel_thread_helper () at /usr/src/linux-2.6.29.i586/arch/x86/kernel/entry_32.S:846
#6  0x00000000 in ?? ()


将来研究系统启动过程启动的时候可以跟踪一下。

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息