Learning Linux-4.12 Kernel Network Protocol Stack (2) - System Initialization (sock_init)

Posted by desmi on Sun, 16 Jun 2019 01:25:15 +0200


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 };

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);
}
For the mechanism of slab caching, you can see This article It's more popular.
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

 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 }

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.

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);




   

    

Topics: socket network Linux