下面分四部分對其進行解讀。
1.首先是三個proto_register(),分別註冊了tcp_prot,udp_prot,raw_prot三個協議(struct proto[include/net/sock.h:594])(這三個物件在後面的初始化過程中還會涉及到,可以比較一下出現這兩次的目的何在),跟到proto_register()[net/core/sock.c:2041]中看一下,首先是乙個大的if,為這個proto分配了幾個必要的slab。之後做了什麼呢?
只是把它加到了全域性變數proto_list[net/sock/sock.c:1937]中,這個鍊錶在核心裡又起什麼作用呢?因為proto_list是靜態全域性變數,也就是說只有在該檔案中才能被訪問到,所以不妨在該檔案中對其搜尋一下:經過搜尋發現,proto_list除了在proto_register和proto_unregister中被使用到,就只有在proc_fs中被使用,也就是輸出目前proto_list鍊錶中所有節點的狀態。
2.sock_register()[net/socket.c:2151]。該函式的實現也很簡單:向net_families[net/socket.c:150]中註冊乙個新的協議族(struct net_proto_family[include/linux/net.h:192])。協議族是linux網路模組劃分的最大單位,每個協議族都被分配了乙個協議族號(在include/linux/socket.h:158~232中定義),從該檔案中可以看出目前最大的協議族號只有35,即af_phonet。既然協議族的數量很少,那麼net_families就採用了一種最高效的資料結構:陣列。35個net_proto_family的空間都是預分配的,只有在註冊時才會向該協議族自己的位置上增加對應的family,create和owner。
到此為止,af_inet對上層的初始化操作基本完成,在此可以看到乙個網路協議(確切的說是協議族)模組初始化的一般流程。兩個步驟:proto_register()然後sock_register()。先註冊proto,然後註冊net_proto_family。每個協議族至少包含乙個協議,如協議族netlink(net/netlink/af_netlink)就只有乙個協議netlink。
下面的初始化操作就和上層沒有多大關係了,主要是af_inet內部協議的初始化。
3.inet_add_protocol()[net/ipv4/protocol.c:53]。向af_inet註冊乙個協議,注意此時的註冊的協議為struct net_protocol[include/net/protocol.h:36]。inet_add_protocol()的實現很簡單,只是將協議設定到靜態變數inet_protos[net/ipv4/protocol.c:46]陣列中。inet_protos的宣告有些奇怪,下面我們來看一下
後面加了乙個____cacheline_aligned_in_smp,根據它的名字可以看出,它的作用是在多處理器環境下對齊cacheline,而cacheline又是什麼東西呢?可以參考http://blog.csdn.net/pennyliang/archive/2010/10/20/5953939.aspx,一位牛人的blog,這篇文章大致介紹了一下為什麼cacheline aligned對齊能夠在多處理器環境下加速。
inet_protos在include/net/protocol.h:98中被extern,那這樣的話我們只有對整個核心進行grep了(也可以使用網上的lxr,但只恐找不全或核心版本不匹配),經過grep,可以確定該變數只在net/ipv4/目錄下的af_inet.c,icmp.c,ip_input.c,protocol.c四個檔案中被使用,且前三個檔案中只是使用rcu_dereference()對陣列中的某乙個協議進行引用,協議的增加和刪除都在protocol.c中。
todo:至於這些協議是怎麼被上層呼叫到的,目前還不清楚。
4.inet_register_protosw()[net/ipv4/af_inet.c:967]。向inetsw[net/ipv4/af_inet.c:124]註冊乙個struct inet_protosw,這個結構體很簡單:
成員type和protocol分別指代socket型別,協議號。socket型別即bsd socket中標準的幾個型別,像sock_stream,sock_dgram,sock_raw等等;協議號就是第三節中所提到的af_inet的協議號。
下面兩個成員是兩組函式介面:prot和ops。我們可以發現,prot就是在第一節proto_register()中註冊的協議,可見,這層協議是給上層使用的;ops這一套函式介面在之後就會發現它位於prot下方。
現在可以明白struct inet_protosw的作用了:它的目的就是承上啟下,起到銜接bsd socket介面和af_inet協議族介面的作用。
再來看inetsw這個全域性變數,它又是做什麼作用的呢?grep看一下,很明顯,除了在inet_register_protosw註冊的使用使用到該變數以外,就只有在inet_create()[net/ipv4/af_inet.c:265]函式中使用了。我們現在只要知道,inet_create()是af_inet在建立socket時候的總入口點(下一章會對其進行詳細剖析),那這就很明白了,inetsw就是為inet_create服務,在建立socket的時候方便它找到協議介面,正如inetsw宣告時所說:"the inetsw table contains everything that inet_create needs to build a new socket."
說到inetsw,就不得不提及inetsw_array[net/ipv4/af_inet.c:930],inetsw就是根據它初始化的,可以看到這裡定義了tcp,udp和ip三個協議的inet_protosw型別。值得關注的是ip的protocol欄位,它設定的ipproto_ip巨集的值為0,我們再到iana查一下這個協議號,iana上顯示這個協議是"ipv6 hop-by-hop option"!為什麼會不一致呢?下面說一下我的理解:
我們知道在tcp/ip協議中,ip位於l3網路層,tcp,udp位於l4傳輸層,bsd socket所用到的protocol應該是指l4的協議,那ip協議當然不在其中。但bsd socket的sock_raw型別該如何實現呢?所以就有了這個ipproto_ip,在注釋中有這樣對它的乙個形容:"wild card",直譯是百搭牌,可以指代任何型別的協議。實現sock_raw的難度太大,只有把這張牌打出來了...百搭的體現可以在後面對inet_create()的剖析中找到。sock_raw這種型別目前我還沒有怎麼接觸,不好做評價。
接下來呼叫的幾個初始化函式都是和具體的protocol相關的,介紹到具體的protocol時再具體釋義。下一章我們會從af_inet協議族的inet_create方法入手,是它引出了所有後面的故事。
網路子系統初始化 系統啟動時初始化
網路啟動初始化函式入口為net socket.c 2200 socket init sock init 函式結構很簡單,實現的功能也非常簡單,下面逐個進行解析 1.sk init 該函式初始化了兩個極值 sysctl wmem max和sysctl rmem max。這兩個值就是來控制我們執行set...
Linux檔案子系統( VFS)的初始化
目錄概述 檔案的描述 vfs系統的資料型別 各個資料結構之間的關係 vfs初始化 linux世界中一切都是檔案,linux檔案子系統vfs virtual filesystem 為使用者提供了檔案和檔案系統的相關介面,系統中所有檔案系統依賴vfs來協同工作。linux的 檔案包含兩部分目錄和檔案,一...
第4章 系統初始化
1 cpu自身初始化 cpu自身的初始化是引導過程的第一步,如果有多個cpu,即多處理器系統,則每個cpu都要進行自身初始化。比如,對於雙處理器的pentium系統,乙個cpu總是為主,另外乙個cpu總是為輔,主cpu執行引導過程的剩餘工作,隨後核心才會啟用輔cpu。在輔cpu被啟用之前,我們可以認...