When initializing, the first call is sock_init, which mainly completes:
1. Creation of sysctl file
2. skb cache initialization, which creates two nodes skbuff_head_cache and skbuff_fclone_cache in slab
3. Register and hang socket file system
static int __init sock_init(void)
{
int err;
/*
* Initialize the network sysctl infrastructure.
*/
err = net_sysctl_init(); //Here, create a sys file to manage and view network parameters
if (err)
goto out;
/*
* Initialize skbuff SLAB cache
*/
skb_init(); //skb cache initialization, which creates two nodes skbuff_head_cache and skbuff_fclone_cache in slab
/*
* Initialize the protocols module.
*/
init_inodecache();
err = register_filesystem(&sock_fs_type); //Register sock file system
if (err)
goto out_fs;
sock_mnt = kern_mount(&sock_fs_type); //Mount sock file system tosuper_blocks
if (IS_ERR(sock_mnt)) {
err = PTR_ERR(sock_mnt);
goto out_mount;
}
/* The real protocol initialization is performed in later initcalls.
*/
1. skb_init
945 /* Layout of fast clones : [skb1][skb2][fclone_ref] */ 946 struct sk_buff_fclones { 947 struct sk_buff skb1; 948 949 struct sk_buff skb2; 950 951 atomic_t fclone_ref; 952 };
For the mechanism of slab caching, you can see This article It's more popular.void __init skb_init(void) { skbuff_head_cache = kmem_cache_create("skbuff_head_cache", //skbuff_head_cache cache, in general, SKB is allocated from the cache. sizeof(struct sk_buff), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache", //Create a skbuff_fclone_cache cache that allocates space twice the length of the SKB descriptor each time. If SKB is allocated //Knowing that cloning is possible, space should be allocated from this cache, because when SKB is allocated in this cache, a backup SKB will be allocated at the same time for future cloning. //In this way, SKBs need not be redistributed when cloning, and backup SKBs can be used directly. The main purpose of this is to improve efficiency. sizeof(struct sk_buff_fclones), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); }
As you can see from code
struct sk_buff_fclone
In fact, the size of two skbs plus a fclone_ref reference identifier, the difference between the two caches is that the size of the specified unit memory area is different at the time of creation. The unit memory area length of SK buff_head_cache is sizeof(struct sk_buff), while the unit memory area length of skbuff_fclone_cache is 2*sizeof(struct sk_buff)+sizeof(atomic_t), that is, a pair of SKBs and a reference count. It can be said that this pair of SKBs is a "father-son" relationship, pointing to the same data buffer, with reference counts of 0, 1 or 2, to indicate that several of these SKBs have been used.
2. init_inodecache
In linux system, socket is a part of file system. Network communication can be regarded as reading files. This special file system is called sockfs. In the previous section, it was mentioned that init_inodecache should be invoked in sock_init function to prepare memory for creating socket file system. However, it should be noted that there are many definitions of init_inodecache in the linux kernel, but they are static, that is, they can only be called by functions in the. C file. In socket.c, such a function is defined.290 static void init_inodecache(void) 291 { 292 sock_inode_cachep = kmem_cache_create("sock_inode_cache", 293 sizeof(struct socket_alloc), 294 0, 295 (SLAB_HWCACHE_ALIGN | 296 SLAB_RECLAIM_ACCOUNT | 297 SLAB_MEM_SPREAD | SLAB_ACCOUNT), 298 init_once); 299 BUG_ON(sock_inode_cachep == NULL); 300 }
3. Preparing socket file system
Prepare the inode cache for the file system, and then enter the initialization file system. First, register_filesystem (& sock_fs_type) is called to register the file system type to the file_systems linked list.
Then call kern_mount (& sock_fs_type); register the file system on super_blocks. This file system is installed through kern_mount when the system is initialized.
To create a socket is to create a special file in the sockfs file system. There is a field s_op in super_block that is used to point to support functions within a file system.
The type of this field is super_operation. This structure defines 12 function pointers that VFS calls. So this is an interface between VFS and file system, through which,
Super blocks can control files or directories under the file system.
960 struct vfsmount * 961 vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) 962 { 963 struct mount *mnt; 964 struct dentry *root; 965 966 if (!type) 967 return ERR_PTR(-ENODEV); 968 969 mnt = alloc_vfsmnt(name); 970 if (!mnt) 971 return ERR_PTR(-ENOMEM); 972 973 if (flags & MS_KERNMOUNT) 974 mnt->mnt.mnt_flags = MNT_INTERNAL; 975 976 root = mount_fs(type, flags, name, data); 977 if (IS_ERR(root)) { 978 mnt_free_id(mnt); 979 free_vfsmnt(mnt); 980 return ERR_CAST(root); 981 } 982 983 mnt->mnt.mnt_root = root; 984 mnt->mnt.mnt_sb = root->d_sb; 985 mnt->mnt_mountpoint = mnt->mnt.mnt_root; 986 mnt->mnt_parent = mnt; 987 lock_mount_hash(); 988 list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts); 989 unlock_mount_hash(); 990 return &mnt->mnt; 991 } 992 EXPORT_SYMBOL_GPL(vfs_kern_mount);