學習Linux-4.12內核網路協議棧(1.3)——協議棧的初始化(sock_init)


初始化的時候,第一個調用的是sock_init,它主要完成:

1. sysctl文件的創建

2. skb高速緩存初始化,它會在slab創建兩個節點skbuff_head_cache和skbuff_fclone_cache
3.註冊並掛socket文件系統



static int __init sock_init(void)
{
    int err;
    /*
     *      Initialize the network sysctl infrastructure.
     */
    err = net_sysctl_init();  //這裏創建sys文件,用於管理和查看一下網絡參數
    if (err)
        goto out;

    /*
     *      Initialize skbuff SLAB cache
     */
    skb_init();  //skb高速緩存初始化,它會在slab創建兩個節點skbuff_head_cache和skbuff_fclone_cache

    /*
     *      Initialize the protocols module.
     */

    init_inodecache();

    err = register_filesystem(&sock_fs_type); //註冊sock文件系統
    if (err)
        goto out_fs;
    sock_mnt = kern_mount(&sock_fs_type);  //掛載sock文件系統到super_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高速緩存,一般情況下,SKB都是從該高速緩存中分配的。
                          sizeof(struct sk_buff),
                          0,
                          SLAB_HWCACHE_ALIGN|SLAB_PANIC,
                          NULL);
    skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache", //創建每次以兩倍SKB描述符長度來分配空間的skbuff_fclone_cache高速緩存。如果在分配SKB時
就知道可能被克隆,那麼應該從這個高速緩存中分配空間,因爲在這個高速緩存中分配SKB時,會同時分配一個後備的SKB,以便將來用於克隆,
這樣在克隆時就不用再次分配SKB了,直接使用後備的SKB即可,這樣做的目的主要是提高效率。
                        sizeof(struct sk_buff_fclones),
                        0,
                        SLAB_HWCACHE_ALIGN|SLAB_PANIC,
                        NULL);
}
關於slab緩存的機制,可以查看這篇文章,講的比較通俗
從code可以看到
struct sk_buff_fclone

其實是兩個skb的大小加上一個fclone_ref引用標識,兩個高速緩存的區別在於創建時指定的單位內存區域大小不同,skbuff_head_cache的單位內存區域長度是sizeof(struct sk_buff),而skbuff_fclone_cache的單位內存區域長度是2*sizeof(struct sk_buff)+sizeof(atomic_t),即一對SKB和一個引用計數,可以說這一對SKB是"父子"關係,指向同一個數據緩存區,引用計數值爲0,1或2,用來表示這一對SKB中有幾個已被使用。

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 }

在 linux 系統中,socket屬於文件系統的一部分,網絡通信可以被看作對文件的讀取。這種特殊的文件系統叫sockfs。 上一節中提到在sock_init 函數中先調用init_inodecache,爲創建socket 文件系統做好內存準備。不過要注意的是在Linux內核中存在init_inodecache多個定義,但都是靜態型,即只能由該.c文件中的函數調用,在socket.c中, 就定義了這麼一個函數

3.準備socket文件系統

爲文件系統準備 inode 緩存部分了,下面進入初始化文件系統。首先是調用 register_filesystem(&sock_fs_type)把文件系統類型註冊到file_systems鏈表上,

然後調用kern_mount(&sock_fs_type);把該文件系統註冊到super_blocks上。在系統初始化的時候要通過kern_mount安裝此文件系統。

所謂創建一個套接字就是在sockfs文件系統中創建一個特殊文件。super_block裏面有一個字段s_op是用來指向某文件系統內部的支持函數,

這個字段的類型爲super_operation。這個結構定義了12個函數指針,這些指針是要讓VFS來調用的。因此這是 VFS和文件系統之間的一個接口,經由這層接口,

超級塊可以控制文件系統下的文件或目錄。

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







發佈了137 篇原創文章 · 獲贊 204 · 訪問量 104萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章