中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Linux網(wǎng)絡(luò)

本文將介紹在Linux系統(tǒng)中,數(shù)據(jù)包是如何一步一步從網(wǎng)卡傳到進(jìn)程手中的。

如果英文沒有問題,強(qiáng)烈建議閱讀后面參考里的兩篇文章,里面介紹的更詳細(xì)。

本文只討論以太網(wǎng)的物理網(wǎng)卡,不涉及虛擬設(shè)備,并且以一個(gè)UDP包的接收過程作為示例.

本示例里列出的函數(shù)調(diào)用關(guān)系來自于kernel 3.13.0,如果你的內(nèi)核不是這個(gè)版本,函數(shù)名稱和相關(guān)路徑可能不一樣,但背后的原理應(yīng)該是一樣的(或者有細(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ū)⒆约鹤赃M(jìn)網(wǎng)絡(luò)模塊,當(dāng)相應(yīng)的網(wǎng)卡收到數(shù)據(jù)包時(shí),網(wǎng)絡(luò)模塊會調(diào)用相應(yīng)的驅(qū)動(dòng)程序處理數(shù)據(jù)。

下圖展示了數(shù)據(jù)包(packet)如何進(jìn)入內(nèi)存,并被內(nèi)核的網(wǎng)絡(luò)模塊開始處理:

                   +-----+
                   |     |                            Memroy
+--------+   1     |     |  2  DMA     +--------+--------+--------+--------+
| Packet |-------->| NIC |------------>| Packet | Packet | Packet | ...... |
+--------+         |     |             +--------+--------+--------+--------+
                   |     |<--------+
                   +-----+         |
                      |            +---------------+
                      |                            |
                    3 | Raise IRQ                  | Disable IRQ
                      |                          5 |
                      |                            |
                      ↓                            |
                   +-----+                   +------------+
                   |     |  Run IRQ handler  |            |
                   | CPU |------------------>| NIC Driver |
                   |     |       4           |            |
                   +-----+                   +------------+
                                                   |
                                                6  | Raise soft IRQ
                                                   |
                                                   ↓
  • 1: 數(shù)據(jù)包從外面的網(wǎng)絡(luò)進(jìn)入物理網(wǎng)卡。如果目的地址不是該網(wǎng)卡,且該網(wǎng)卡沒有開啟混雜模式,該包會被網(wǎng)卡丟棄。
  • 2: 網(wǎng)卡將數(shù)據(jù)包通過DMA的方式寫入到指定的內(nèi)存地址,該地址由網(wǎng)卡驅(qū)動(dòng)分配并初始化。注: 老的網(wǎng)卡可能不支持DMA,不過新的網(wǎng)卡一般都支持。
  • 3: 網(wǎng)卡通過硬件中斷(IRQ)通知CPU,告訴它有數(shù)據(jù)來了
  • 4: CPU根據(jù)中斷表,調(diào)用已經(jīng)注冊的中斷函數(shù),這個(gè)中斷函數(shù)會調(diào)到驅(qū)動(dòng)程序(NIC Driver)中相應(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í)間過長,會導(dǎo)致CPU沒法響應(yīng)其它硬件的中斷,于是內(nèi)核引入軟中斷,這樣可以將硬中斷處理函數(shù)中耗時(shí)的部分移到軟中斷處理函數(shù)里面來慢慢處理。

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

軟中斷會觸發(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 |
                                                      +-----------------+
  • 7: 內(nèi)核中的ksoftirqd進(jìn)程專門負(fù)責(zé)軟中斷的處理,當(dāng)它收到軟中斷后,就會調(diào)用相應(yīng)軟中斷所對應(yīng)的處理函數(shù),對于上面第6步中是網(wǎng)卡驅(qū)動(dòng)模塊拋出的軟中斷,ksoftirqd會調(diào)用網(wǎng)絡(luò)模塊的net_rx_action函數(shù)
  • 8: net_rx_action調(diào)用網(wǎng)卡驅(qū)動(dòng)里的poll函數(shù)來一個(gè)一個(gè)的處理數(shù)據(jù)包
  • 9: 在pool函數(shù)中,驅(qū)動(dòng)會一個(gè)接一個(gè)的讀取網(wǎng)卡寫到內(nèi)存中的數(shù)據(jù)包,內(nèi)存中數(shù)據(jù)包的格式只有驅(qū)動(dòng)知道
  • 10: 驅(qū)動(dòng)程序?qū)?nèi)存中的數(shù)據(jù)包轉(zhuǎn)換成內(nèi)核網(wǎng)絡(luò)模塊能識別的skb格式,然后調(diào)用napi_gro_receive函數(shù)
  • 11: napi_gro_receive會處理GRO相關(guān)的內(nèi)容,也就是將可以合并的數(shù)據(jù)包進(jìn)行合并,這樣就只需要調(diào)用一次協(xié)議棧。然后判斷是否開啟了RPS,如果開啟了,將會調(diào)用enqueue_to_backlog
  • 12: 在enqueue_to_backlog函數(shù)中,會將數(shù)據(jù)包放入CPU的softnet_data結(jié)構(gòu)體的input_pkt_queue中,然后返回,如果input_pkt_queue滿了的話,該數(shù)據(jù)包將會被丟棄,queue的大小可以通過net.core.netdev_max_backlog來配置
  • 13: CPU會接著在自己的軟中斷上下文中處理自己input_pkt_queue里的網(wǎng)絡(luò)數(shù)據(jù)(調(diào)用__netif_receive_skb_core)
  • 14: 如果沒開啟RPS,napi_gro_receive會直接調(diào)用__netif_receive_skb_core
  • 15: 看是不是有AF_PACKET類型的socket(也就是我們常說的原始套接字),如果有的話,拷貝一份數(shù)據(jù)給它。tcpdump抓包就是抓的這里的包。
  • 16: 調(diào)用協(xié)議棧相應(yīng)的函數(shù),將數(shù)據(jù)包交給協(xié)議棧處理。
  • 17: 待內(nèi)存中的所有數(shù)據(jù)包被處理完成后(即poll函數(shù)執(zhí)行完成),啟用網(wǎng)卡的硬中斷,這樣下次網(wǎng)卡再收到數(shù)據(jù)的時(shí)候就會通知CPU
enqueue_to_backlog函數(shù)也會被netif_rx函數(shù)調(diào)用,而netif_rx正是lo設(shè)備發(fā)送數(shù)據(jù)包時(shí)調(diào)用的函數(shù)

協(xié)議棧

IP層

由于是UDP包,所以第一步會進(jìn)入IP層,然后一級一級的函數(shù)往下調(diào):

          |
          |
          ↓         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)來)直接丟掉,然后調(diào)用注冊在NF_INET_PRE_ROUTING上的函數(shù)
  • NF_INET_PRE_ROUTING: netfilter放在協(xié)議棧中的鉤子,可以通過iptables來注入一些數(shù)據(jù)包處理函數(shù),用來修改或者丟棄數(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會先調(diào)用netfilter注冊的NF_INET_FORWARD相關(guān)函數(shù),如果數(shù)據(jù)包沒有被丟棄,那么將繼續(xù)往后調(diào)用dst_output_sk函數(shù)
  • dst_output_sk: 該函數(shù)會調(diào)用IP層的相應(yīng)函數(shù)將該數(shù)據(jù)包發(fā)送出去,同下一篇要介紹的數(shù)據(jù)包發(fā)送流程的后半部分一樣。
  • ip_local_deliver:如果上面routing的時(shí)候發(fā)現(xiàn)目的IP是本地IP,那么將會調(diào)用該函數(shù),在該函數(shù)中,會先調(diào)用NF_INET_LOCAL_IN相關(guān)的鉤子程序,如果通過,數(shù)據(jù)包將會向下發(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ù),它里面會調(diào)用其它的函數(shù),主要是做一些必要的檢查,其中一個(gè)重要的調(diào)用是__udp4_lib_lookup_skb,該函數(shù)會根據(jù)目的IP和端口找對應(yīng)的socket,如果沒有找到相應(yīng)的socket,那么該數(shù)據(jù)包將會被丟棄,否則繼續(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ù)包將會被丟棄)
  • __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)用層程序來讀取,上面所有函數(shù)的執(zhí)行過程都在軟中斷的上下文中。

socket

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

結(jié)束語

了解數(shù)據(jù)包的接收流程有助于幫助我們搞清楚我們可以在哪些地方監(jiān)控和修改數(shù)據(jù)包,哪些情況下數(shù)據(jù)包可能被丟棄,為我們處理網(wǎng)絡(luò)問題提供了一些參考,同時(shí)了解netfilter中相應(yīng)鉤子的位置,對于了解iptables的用法有一定的幫助,同時(shí)也會幫助我們后續(xù)更好的理解Linux下的網(wǎng)絡(luò)虛擬設(shè)備。

在接下來的幾篇文章中,將會介紹Linux下的網(wǎng)絡(luò)虛擬設(shè)備和iptables。

參考

Monitoring and Tuning the Linux Networking Stack: Receiving Data
Illustrated Guide to Monitoring and Tuning the Linux Networking Stack: Receiving Data
NAPI

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Linux協(xié)議棧中UDP數(shù)據(jù)報(bào)從網(wǎng)卡到用戶空間流程總結(jié)
Linux原始套接字實(shí)現(xiàn)分析
理解 Linux 網(wǎng)絡(luò)棧(1):Linux 網(wǎng)絡(luò)協(xié)議棧簡單總結(jié)
ptype_base和ptype_all理解,netid_receive_skb()函數(shù)注解
圖解 Linux 網(wǎng)絡(luò)包接收過程
2.6.24.4內(nèi)核網(wǎng)絡(luò)接收數(shù)據(jù)包分析
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服