linux網(wǎng)絡(luò)之?dāng)?shù)據(jù)包的接受過程

網(wǎng)卡收包從整體上是網(wǎng)線中的高低電平轉(zhuǎn)換到網(wǎng)卡FIFO存儲(chǔ)再拷貝到系統(tǒng)主內(nèi)存(DDR3)的過程氧吐,其中涉及到網(wǎng)卡控制器博个,CPU怀樟,DMA,驅(qū)動(dòng)程序盆佣,在OSI模型中屬于物理層和鏈路層往堡,如下圖所示械荷。

image

網(wǎng)卡工作在物理層和數(shù)據(jù)鏈路層,主要由PHY/MAC芯片虑灰、Tx/Rx FIFO吨瞎、DMA等組成,其中網(wǎng)線通過變壓器接PHY芯片穆咐、PHY芯片通過MII接MAC芯片颤诀、MAC芯片接PCI總線

PHY芯片主要負(fù)責(zé):CSMA/CD、模數(shù)轉(zhuǎn)換对湃、編解碼崖叫、串并轉(zhuǎn)換

MAC芯片主要負(fù)責(zé):

比特流和幀的轉(zhuǎn)換:7字節(jié)的前導(dǎo)碼Preamble和1字節(jié)的幀首定界符SFD
CRC校驗(yàn)
Packet Filtering:L2 Filtering、VLAN Filtering拍柒、Manageability / Host Filtering
Intel的千兆網(wǎng)卡以82575/82576為代表心傀、萬(wàn)兆網(wǎng)卡以82598/82599為代表

image

接收數(shù)據(jù)包是一個(gè)復(fù)雜的過程,涉及很多底層的技術(shù)細(xì)節(jié)拆讯,但大致需要以下幾個(gè)步驟:

  1. 網(wǎng)卡收到數(shù)據(jù)包脂男。
  2. 將數(shù)據(jù)包從網(wǎng)卡硬件緩存轉(zhuǎn)移到服務(wù)器內(nèi)存中。
  3. 通知內(nèi)核處理种呐。
  4. 經(jīng)過TCP/IP協(xié)議逐層處理宰翅。
  5. 應(yīng)用程序通過read()從socket buffer讀取數(shù)據(jù)。
image

物理網(wǎng)卡收到數(shù)據(jù)包的處理流程如上圖所示爽室,詳細(xì)步驟如下:

  1. 網(wǎng)卡收到數(shù)據(jù)包汁讼,先將高低電平轉(zhuǎn)換到網(wǎng)卡fifo存儲(chǔ),網(wǎng)卡申請(qǐng)ring buffer的描述肮之,根據(jù)描述找到具體的物理地址掉缺,從fifo隊(duì)列物理網(wǎng)卡會(huì)使用DMA將數(shù)據(jù)包寫到了該物理地址,卜录,其實(shí)就是skb_buffer中.
  2. 這個(gè)時(shí)候數(shù)據(jù)包已經(jīng)被轉(zhuǎn)移到skb_buffer中戈擒,因?yàn)槭荄MA寫入,內(nèi)核并沒有監(jiān)控?cái)?shù)據(jù)包寫入情況艰毒,這時(shí)候NIC觸發(fā)一個(gè)硬中斷筐高,每一個(gè)硬件中斷會(huì)對(duì)應(yīng)一個(gè)中斷號(hào),且指定一個(gè)vCPU來(lái)處理丑瞧,如上圖vcpu2收到了該硬件中斷.
  3. 硬件中斷的中斷處理程序柑土,調(diào)用驅(qū)動(dòng)程序完成,a.啟動(dòng)軟中斷
  4. 硬中斷觸發(fā)的驅(qū)動(dòng)程序會(huì)禁用網(wǎng)卡硬中斷绊汹,其實(shí)這時(shí)候意思是告訴NIC稽屏,再來(lái)數(shù)據(jù)不用觸發(fā)硬中斷了,把數(shù)據(jù)DMA拷入系統(tǒng)內(nèi)存即可
  5. 硬中斷觸發(fā)的驅(qū)動(dòng)程序會(huì)啟動(dòng)軟中斷西乖,啟用軟中斷目的是將數(shù)據(jù)包后續(xù)處理流程交給軟中斷慢慢處理狐榔,這個(gè)時(shí)候退出硬件中斷了坛增,但是注意和網(wǎng)絡(luò)有關(guān)的硬中斷,要等到后續(xù)開啟硬中斷后薄腻,才有機(jī)會(huì)再次被觸發(fā)
  6. NAPI觸發(fā)軟中斷收捣,觸發(fā)napi系統(tǒng)
  7. 消耗ringbuffer指向的skb_buffer
  8. NAPI循環(huán)處理ringbuffer數(shù)據(jù),處理完成
  9. 啟動(dòng)網(wǎng)絡(luò)硬件中斷庵楷,有數(shù)據(jù)來(lái)時(shí)候就可以繼續(xù)觸發(fā)硬件中斷罢艾,繼續(xù)通知CPU來(lái)消耗數(shù)據(jù)包.

其實(shí)上述過程過程簡(jiǎn)單描述為:網(wǎng)卡收到數(shù)據(jù)包,DMA到內(nèi)核內(nèi)存尽纽,中斷通知內(nèi)核數(shù)據(jù)有了咐蚯,內(nèi)核按輪次處理消耗數(shù)據(jù)包,一輪處理完成后弄贿,開啟硬中斷仓蛆。其核心就是網(wǎng)卡和內(nèi)核其實(shí)是生產(chǎn)和消費(fèi)模型,網(wǎng)卡生產(chǎn)挎春,內(nèi)核負(fù)責(zé)消費(fèi)看疙,生產(chǎn)者需要通知消費(fèi)者消費(fèi);如果生產(chǎn)過快會(huì)產(chǎn)生丟包直奋,如果消費(fèi)過慢也會(huì)產(chǎn)生問題能庆。也就說(shuō)在高流量壓力情況下,只有生產(chǎn)消費(fèi)優(yōu)化后脚线,消費(fèi)能力夠快搁胆,此生產(chǎn)消費(fèi)關(guān)系才可以正常維持,所以如果物理接口有丟包計(jì)數(shù)時(shí)候邮绿,未必是網(wǎng)卡存在問題渠旁,也可能是內(nèi)核消費(fèi)的太慢。

如何將網(wǎng)卡收到的數(shù)據(jù)寫入到內(nèi)核內(nèi)存船逮?

NIC在接收到數(shù)據(jù)包之后顾腊,首先需要將數(shù)據(jù)同步到內(nèi)核中,這中間的橋梁是rx ring buffer挖胃。它是由NIC和驅(qū)動(dòng)程序共享的一片區(qū)域杂靶,事實(shí)上,rx ring buffer存儲(chǔ)的并不是實(shí)際的packet數(shù)據(jù)酱鸭,而是一個(gè)描述符吗垮,這個(gè)描述符指向了它真正的存儲(chǔ)地址,具體流程如下:

  1. 驅(qū)動(dòng)在內(nèi)存中分配一片緩沖區(qū)用來(lái)接收數(shù)據(jù)包凹髓,叫做sk_buffer;
  2. 將上述緩沖區(qū)的地址和大兴傅恰(即接收描述符),加入到rx ring buffer蔚舀。描述符中的緩沖區(qū)地址是DMA使用的物理地址;
  3. 驅(qū)動(dòng)通知網(wǎng)卡有一個(gè)新的描述符;
  4. 網(wǎng)卡從rx ring buffer中取出描述符饵沧,從而獲知緩沖區(qū)的地址和大小;
  5. 網(wǎng)卡收到新的數(shù)據(jù)包;
  6. 網(wǎng)卡將新數(shù)據(jù)包通過DMA直接寫到sk_buffer中蚀之。
image

當(dāng)驅(qū)動(dòng)處理速度跟不上網(wǎng)卡收包速度時(shí),驅(qū)動(dòng)來(lái)不及分配緩沖區(qū)捷泞,NIC接收到的數(shù)據(jù)包無(wú)法及時(shí)寫到sk_buffer足删,就會(huì)產(chǎn)生堆積,當(dāng)NIC內(nèi)部緩沖區(qū)寫滿后锁右,就會(huì)丟棄部分?jǐn)?shù)據(jù)失受,引起丟包。這部分丟包為rx_fifo_errors咏瑟,在 /proc/net/dev中體現(xiàn)為fifo字段增長(zhǎng)拂到,在ifconfig中體現(xiàn)為overruns指標(biāo)增長(zhǎng)。

通知系統(tǒng)內(nèi)核處理(驅(qū)動(dòng)與Linux內(nèi)核交互)

這個(gè)時(shí)候码泞,數(shù)據(jù)包已經(jīng)被轉(zhuǎn)移到了sk_buffer中兄旬。前文提到,這是驅(qū)動(dòng)程序在內(nèi)存中分配的一片緩沖區(qū)余寥,并且是通過DMA寫入的领铐,這種方式不依賴CPU直接將數(shù)據(jù)寫到了內(nèi)存中,意味著對(duì)內(nèi)核來(lái)說(shuō)宋舷,其實(shí)并不知道已經(jīng)有新數(shù)據(jù)到了內(nèi)存中绪撵。那么如何讓內(nèi)核知道有新數(shù)據(jù)進(jìn)來(lái)了呢?答案就是中斷祝蝠,通過中斷告訴內(nèi)核有新數(shù)據(jù)進(jìn)來(lái)了音诈,并需要進(jìn)行后續(xù)處理。

提到中斷绎狭,就涉及到硬中斷和軟中斷细溅,首先需要簡(jiǎn)單了解一下它們的區(qū)別:

硬中斷: 由硬件自己生成,具有隨機(jī)性儡嘶,硬中斷被CPU接收后喇聊,觸發(fā)執(zhí)行中斷處理程序。中斷處理程序只會(huì)處理關(guān)鍵性的社付、短時(shí)間內(nèi)可以處理完的工作承疲,剩余耗時(shí)較長(zhǎng)工作邻耕,會(huì)放到中斷之后鸥咖,由軟中斷來(lái)完成。硬中斷也被稱為上半部分兄世。
軟中斷: 由硬中斷對(duì)應(yīng)的中斷處理程序生成啼辣,往往是預(yù)先在代碼里實(shí)現(xiàn)好的,不具有隨機(jī)性御滩。(除此之外鸥拧,也有應(yīng)用程序觸發(fā)的軟中斷党远,與本文討論的網(wǎng)卡收包無(wú)關(guān)。)也被稱為下半部分富弦。

當(dāng)NIC把數(shù)據(jù)包通過DMA復(fù)制到內(nèi)核緩沖區(qū)sk_buffer后沟娱,NIC立即發(fā)起一個(gè)硬件中斷。CPU接收后腕柜,首先進(jìn)入上半部分济似,網(wǎng)卡中斷對(duì)應(yīng)的中斷處理程序是網(wǎng)卡驅(qū)動(dòng)程序的一部分,之后由它發(fā)起軟中斷盏缤,進(jìn)入下半部分砰蠢,開始消費(fèi)sk_buffer中的數(shù)據(jù),交給內(nèi)核協(xié)議棧處理唉铜。

image

通過中斷台舱,能夠快速及時(shí)地響應(yīng)網(wǎng)卡數(shù)據(jù)請(qǐng)求,但如果數(shù)據(jù)量大潭流,那么會(huì)產(chǎn)生大量中斷請(qǐng)求竞惋,CPU大部分時(shí)間都忙于處理中斷,效率很低灰嫉。為了解決這個(gè)問題碰声,現(xiàn)在的內(nèi)核及驅(qū)動(dòng)都采用一種叫NAPI(new API)的方式進(jìn)行數(shù)據(jù)處理,其原理可以簡(jiǎn)單理解為 中斷+輪詢熬甫,在數(shù)據(jù)量大時(shí)胰挑,一次中斷后通過輪詢接收一定數(shù)量包再返回,避免產(chǎn)生多次中斷椿肩。

image

網(wǎng)卡的基礎(chǔ)知識(shí)

網(wǎng)卡本身是有內(nèi)存的瞻颂,每個(gè)網(wǎng)卡一般都有4k以上的內(nèi)存,用來(lái)發(fā)送郑象、接受數(shù)據(jù)贡这。數(shù)據(jù)從主內(nèi)存搬到網(wǎng)卡之后,不是立即就能被發(fā)送出去的厂榛,而是要先在網(wǎng)卡自身的內(nèi)存中排隊(duì)盖矫,再按先后順序發(fā)送,同樣的击奶,數(shù)據(jù)從以太網(wǎng)傳遞到網(wǎng)卡時(shí)辈双,網(wǎng)卡也是先把數(shù)據(jù)存儲(chǔ)到自身的內(nèi)存中,等到收到一幀數(shù)據(jù)了柜砾,再經(jīng)過中斷的方式湃望,告訴CPU把網(wǎng)卡內(nèi)存的數(shù)據(jù)讀走(現(xiàn)在網(wǎng)卡大都支持DMA方式直接從網(wǎng)卡內(nèi)存拷貝被內(nèi)核內(nèi)存),而讀走后的內(nèi)存,又被清空证芭,再次被用來(lái)接收新的數(shù)據(jù)瞳浦。


image.gif

藍(lán)色部分為發(fā)送數(shù)據(jù)用的頁(yè)面總和,總共只有6個(gè)頁(yè)面用于發(fā)送數(shù)據(jù)(40h-45h)废士;剩余的46h-80h都是接收數(shù)據(jù)用的叫潦,而在接收數(shù)據(jù)內(nèi)存中,只有紅色部分是有數(shù)據(jù)的官硝,當(dāng)接收新的數(shù)據(jù)時(shí)诅挑,是向紅色部分前面的綠色中的256字節(jié)寫入數(shù)據(jù),同時(shí)“把當(dāng)前指針”移動(dòng)到+256字節(jié)的后面(網(wǎng)卡自動(dòng)完成)泛源,而現(xiàn)在要讀的數(shù)據(jù)拔妥,是在“邊界指針”那里開始的256字節(jié)(紫色部分),下一個(gè)要讀的數(shù)據(jù)达箍,是在“下一包指針”的位置開始的256字節(jié)没龙,當(dāng)256字節(jié)被讀出來(lái)了,就變成了重新可以使用的內(nèi)存缎玫,即綠色所表示硬纤,而接收數(shù)據(jù),就是把可用的內(nèi)存拿來(lái)用赃磨,即變成了紅色筝家,當(dāng)數(shù)據(jù)寫到了0x80h后,又從0x46h開始寫數(shù)據(jù)邻辉,這樣循環(huán)溪王,如果數(shù)據(jù)滿了,則網(wǎng)卡就不能再接收數(shù)據(jù)值骇,必須等待數(shù)據(jù)被讀出去了莹菱,才能再繼續(xù)接收。

網(wǎng)卡到內(nèi)存

網(wǎng)卡需要有驅(qū)動(dòng)才能工作吱瘩,驅(qū)動(dòng)是加載到內(nèi)核中的模塊道伟,負(fù)責(zé)銜接網(wǎng)卡和內(nèi)核的網(wǎng)絡(luò)模塊,驅(qū)動(dòng)在加載的時(shí)候?qū)⒆约鹤?cè)進(jìn)網(wǎng)絡(luò)模塊使碾,當(dāng)相應(yīng)的網(wǎng)卡收到數(shù)據(jù)包時(shí)蜜徽,網(wǎng)絡(luò)模塊會(huì)調(diào)用相應(yīng)的驅(qū)動(dòng)程序處理數(shù)據(jù)。
下圖展示了數(shù)據(jù)包(packet)如何進(jìn)入內(nèi)存票摇,并被內(nèi)核的網(wǎng)絡(luò)模塊開始處理:


image.png
  1. 數(shù)據(jù)包從外面的網(wǎng)絡(luò)進(jìn)入物理網(wǎng)卡拘鞋。如果目的地址不是該網(wǎng)卡,并且該網(wǎng)卡沒有開啟混雜模式兄朋,該包會(huì)被網(wǎng)卡丟棄掐禁。
  2. 網(wǎng)卡將數(shù)據(jù)包通過DMA的方式寫入到指定的內(nèi)存地址怜械,該地址由網(wǎng)卡驅(qū)動(dòng)分配颅和。
  3. 網(wǎng)卡通過硬件中斷(IRQ)告知cpu有數(shù)據(jù)來(lái)了傅事。
  4. cpu根據(jù)中斷表,調(diào)用已經(jīng)注冊(cè)的中斷函數(shù)峡扩,這個(gè)中斷函數(shù)會(huì)調(diào)動(dòng)驅(qū)動(dòng)程序中相應(yīng)的函數(shù)
  5. 驅(qū)動(dòng)先禁用網(wǎng)卡的中斷蹭越,表示驅(qū)動(dòng)程序已經(jīng)知道內(nèi)存中有數(shù)據(jù)了,告訴網(wǎng)卡下次再收到數(shù)據(jù)包直接寫內(nèi)存就可以了教届,不要再通知cpu了响鹃,這樣可以提高效率,避免cpu不停的被中斷
  6. 啟動(dòng)軟中斷案训。這步結(jié)束后买置,硬件中斷處理函數(shù)就結(jié)束返回了,由于硬中斷處理程序執(zhí)行的過程中不能被中斷强霎,所以如果它執(zhí)行時(shí)間過長(zhǎng)忿项,會(huì)導(dǎo)致cpu無(wú)法響應(yīng)其他硬件的中斷,于是內(nèi)核引入軟中斷城舞,這樣可以將硬中斷處理函數(shù)中耗時(shí)的部分移到軟中斷處理函數(shù)里面來(lái)慢慢處理轩触。

內(nèi)核的網(wǎng)絡(luò)模塊

軟中斷會(huì)觸發(fā)內(nèi)核網(wǎng)絡(luò)模塊中的軟中斷處理函數(shù),后續(xù)流程如下:

                                                     +-----+
                                             17      |     |
                                        +----------->| NIC |
                                        |            |     |
                                        |Enable IRQ  +-----+
                                        |
                                        |
                                  +------------+                                      Memroy
                                  |            |        Read           +--------+--------+--------+--------+
                 +--------------->| NIC Driver |<--------------------- | Packet | Packet | Packet | ...... |
                 |                |            |          9            +--------+--------+--------+--------+
                 |                +------------+
                 |                      |    |        skb
            Poll | 8      Raise softIRQ | 6  +-----------------+
                 |                      |             10       |
                 |                      ↓                      ↓
         +---------------+  Call  +-----------+        +------------------+        +--------------------+  12  +---------------------+
         | net_rx_action |<-------| ksoftirqd |        | napi_gro_receive |------->| enqueue_to_backlog |----->| CPU input_pkt_queue |
         +---------------+   7    +-----------+        +------------------+   11   +--------------------+      +---------------------+
                                                               |                                                      | 13
                                                            14 |        + - - - - - - - - - - - - - - - - - - - - - - +
                                                               ↓        ↓
                                                    +--------------------------+    15      +------------------------+
                                                    | __netif_receive_skb_core |----------->| packet taps(AF_PACKET) |
                                                    +--------------------------+            +------------------------+
                                                               |
                                                               | 16
                                                               ↓
                                                      +-----------------+
                                                      | protocol layers |
                                                      +-----------------+

  1. 內(nèi)核中的ksoftirqd進(jìn)程專門負(fù)責(zé)軟中斷的處理家夺,當(dāng)它收到軟中斷后脱柱,就會(huì)調(diào)用相應(yīng)軟中斷所對(duì)應(yīng)的處理函數(shù),對(duì)于上面第六步中網(wǎng)卡驅(qū)動(dòng)模塊拋出的軟中斷拉馋,ksoftirqd會(huì)調(diào)用網(wǎng)絡(luò)模塊的net_rx_action函數(shù)
  2. net_rx_action調(diào)用網(wǎng)卡驅(qū)動(dòng)里的poll函數(shù)來(lái)一個(gè)一個(gè)的處理數(shù)據(jù)包
  3. 在pool函數(shù)中榨为,驅(qū)動(dòng)會(huì)一個(gè)接一個(gè)的讀取網(wǎng)卡寫到內(nèi)存中的數(shù)據(jù)包,內(nèi)存中數(shù)據(jù)包的格式只有驅(qū)動(dòng)知道
  4. 驅(qū)動(dòng)程序?qū)?nèi)存中的數(shù)據(jù)包轉(zhuǎn)換成內(nèi)核網(wǎng)絡(luò)模塊能識(shí)別的skb格式煌茴,然后調(diào)用napi_gro_receive函數(shù)
  5. napi_gro_receive會(huì)處理GRO相關(guān)的內(nèi)容柠逞,也就是將可以合并的數(shù)據(jù)包進(jìn)行合并,這樣就只需要調(diào)用一次協(xié)議棧景馁。然后判斷是否開啟了RPS板壮,如果開啟了,將會(huì)調(diào)用enqueue_to_backlog
  6. 在enqueue_to_backlog函數(shù)中合住,會(huì)將數(shù)據(jù)包放入CPU的softnet_data結(jié)構(gòu)體的input_pkt_queue中绰精,然后返回,如果input_pkt_queue滿了的話透葛,該數(shù)據(jù)包將會(huì)被丟棄笨使,queue的大小可以通過net.core.netdev_max_backlog來(lái)配置
  7. CPU會(huì)接著在自己的軟中斷上下文中處理自己input_pkt_queue里的網(wǎng)絡(luò)數(shù)據(jù)(調(diào)用__netif_receive_skb_core)
  8. 如果沒開啟RPS,napi_gro_receive會(huì)直接調(diào)用__netif_receive_skb_core
  9. 看是不是有AF_PACKET類型的socket(也就是我們常說(shuō)的原始套接字)僚害,如果有的話硫椰,拷貝一份數(shù)據(jù)給它。tcpdump抓包就是抓的這里的包。
  10. 調(diào)用協(xié)議棧相應(yīng)的函數(shù)靶草,將數(shù)據(jù)包交給協(xié)議棧處理蹄胰。
  11. 待內(nèi)存中的所有數(shù)據(jù)包被處理完成后(即poll函數(shù)執(zhí)行完成),啟用網(wǎng)卡的硬中斷奕翔,這樣下次網(wǎng)卡再收到數(shù)據(jù)的時(shí)候就會(huì)通知CPU

協(xié)議棧

IP層

          |
          |
          ↓         promiscuous mode &&
      +--------+    PACKET_OTHERHOST (set by driver)   +-----------------+
      | ip_rcv |-------------------------------------->| drop this packet|
      +--------+                                       +-----------------+
          |
          |
          ↓
+---------------------+
| NF_INET_PRE_ROUTING |
+---------------------+
          |
          |
          ↓
      +---------+
      |         | enabled ip forword  +------------+        +----------------+
      | routing |-------------------->| ip_forward |------->| NF_INET_FORWARD |
      |         |                     +------------+        +----------------+
      +---------+                                                   |
          |                                                         |
          | destination IP is local                                 ↓
          ↓                                                 +---------------+
 +------------------+                                       | dst_output_sk |
 | ip_local_deliver |                                       +---------------+
 +------------------+
          |
          |
          ↓
 +------------------+
 | NF_INET_LOCAL_IN |
 +------------------+
          |
          |
          ↓
    +-----------+
    | UDP layer |
    +-----------+
  • ip_rcv: ip_rcv函數(shù)是IP模塊的入口函數(shù)裕寨,在該函數(shù)里面,第一件事就是將垃圾數(shù)據(jù)包(目的mac地址不是當(dāng)前網(wǎng)卡派继,但由于網(wǎng)卡設(shè)置了混雜模式而被接收進(jìn)來(lái))直接丟掉宾袜,然后調(diào)用注冊(cè)在NF_INET_PRE_ROUTING上的函數(shù)
  • NF_INET_PRE_ROUTING: netfilter放在協(xié)議棧中的鉤子,可以通過iptables來(lái)注入一些數(shù)據(jù)包處理函數(shù)驾窟,用來(lái)修改或者丟棄數(shù)據(jù)包庆猫,如果數(shù)據(jù)包沒被丟棄,將繼續(xù)往下走
  • routing: 進(jìn)行路由绅络,如果是目的IP不是本地IP月培,且沒有開啟ip forward功能,那么數(shù)據(jù)包將被丟棄昨稼,如果開啟了ip forward功能节视,那將進(jìn)入ip_forward函數(shù)
  • ip_forward: ip_forward會(huì)先調(diào)用netfilter注冊(cè)的NF_INET_FORWARD相關(guān)函數(shù),如果數(shù)據(jù)包沒有被丟棄假栓,那么將繼續(xù)往后調(diào)用dst_output_sk函數(shù)
  • 該函數(shù)會(huì)調(diào)用IP層的相應(yīng)函數(shù)將該數(shù)據(jù)包發(fā)送出去
  • ip_local_deliver:如果上面routing的時(shí)候發(fā)現(xiàn)目的IP是本地IP寻行,那么將會(huì)調(diào)用該函數(shù),在該函數(shù)中匾荆,會(huì)先調(diào)用NF_INET_LOCAL_IN相關(guān)的鉤子程序拌蜘,如果通過,數(shù)據(jù)包將會(huì)向下發(fā)送到UDP層

UDP層

          |
          |
          ↓
      +---------+            +-----------------------+
      | udp_rcv |----------->| __udp4_lib_lookup_skb |
      +---------+            +-----------------------+
          |
          |
          ↓
 +--------------------+      +-----------+
 | sock_queue_rcv_skb |----->| sk_filter |
 +--------------------+      +-----------+
          |
          |
          ↓
 +------------------+
 | __skb_queue_tail |
 +------------------+
          |
          |
          ↓
  +---------------+
  | sk_data_ready |
  +---------------+
  • udp_rcv: udp_rcv函數(shù)是UDP模塊的入口函數(shù)牙丽,它里面會(huì)調(diào)用其它的函數(shù)简卧,主要是做一些必要的檢查,其中一個(gè)重要的調(diào)用是__udp4_lib_lookup_skb烤芦,該函數(shù)會(huì)根據(jù)目的IP和端口找對(duì)應(yīng)的socket举娩,如果沒有找到相應(yīng)的socket,那么該數(shù)據(jù)包將會(huì)被丟棄构罗,否則繼續(xù)
  • sock_queue_rcv_skb: 主要干了兩件事铜涉,一是檢查這個(gè)socket的receive buffer是不是滿了,如果滿了的話遂唧,丟棄該數(shù)據(jù)包芙代,然后就是調(diào)用sk_filter看這個(gè)包是否是滿足條件的包,如果當(dāng)前socket上設(shè)置了filter盖彭,且該包不滿足條件的話纹烹,這個(gè)數(shù)據(jù)包也將被丟棄(在Linux里面页滚,每個(gè)socket上都可以像tcpdump里面一樣定義filter,不滿足條件的數(shù)據(jù)包將會(huì)被丟棄)
  • __skb_queue_tail: 將數(shù)據(jù)包放入socket接收隊(duì)列的末尾
  • sk_data_ready: 通知socket數(shù)據(jù)包已經(jīng)準(zhǔn)備好
    調(diào)用完sk_data_ready之后铺呵,一個(gè)數(shù)據(jù)包處理完成裹驰,等待應(yīng)用層程序來(lái)讀取,上面所有函數(shù)的執(zhí)行過程都在軟中斷的上下文中陪蜻。

socket

應(yīng)用層一般有兩種方式接收數(shù)據(jù)邦马,一種是recvfrom函數(shù)阻塞在那里等著數(shù)據(jù)來(lái)贱鼻,這種情況下當(dāng)socket收到通知后宴卖,recvfrom就會(huì)被喚醒,然后讀取接收隊(duì)列的數(shù)據(jù)邻悬;另一種是通過epoll或者select監(jiān)聽相應(yīng)的socket症昏,當(dāng)收到通知后,再調(diào)用recvfrom函數(shù)去讀取接收隊(duì)列的數(shù)據(jù)父丰。兩種情況都能正常的接收到相應(yīng)的數(shù)據(jù)包肝谭。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蛾扇,隨后出現(xiàn)的幾起案子攘烛,更是在濱河造成了極大的恐慌,老刑警劉巖镀首,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坟漱,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡更哄,警方通過查閱死者的電腦和手機(jī)芋齿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)成翩,“玉大人觅捆,你說(shuō)我怎么就攤上這事÷榈校” “怎么了栅炒?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)术羔。 經(jīng)常有香客問我赢赊,道長(zhǎng),這世上最難降的妖魔是什么聂示? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任域携,我火速辦了婚禮,結(jié)果婚禮上鱼喉,老公的妹妹穿的比我還像新娘秀鞭。我一直安慰自己趋观,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布锋边。 她就那樣靜靜地躺著皱坛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪豆巨。 梳的紋絲不亂的頭發(fā)上剩辟,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音往扔,去河邊找鬼贩猎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛萍膛,可吹牛的內(nèi)容都是我干的吭服。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蝗罗,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼艇棕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起串塑,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤沼琉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后桩匪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體打瘪,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年吸祟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瑟慈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡屋匕,死狀恐怖葛碧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情过吻,我是刑警寧澤进泼,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站纤虽,受9級(jí)特大地震影響乳绕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜逼纸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一洋措、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧杰刽,春花似錦菠发、人聲如沸王滤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)雁乡。三九已至,卻和暖如春糜俗,著一層夾襖步出監(jiān)牢的瞬間踱稍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工悠抹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留珠月,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓锌钮,卻偏偏與公主長(zhǎng)得像桥温,于是被迫代替她去往敵國(guó)和親引矩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子梁丘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容