close

大家在探討 Linux kernel 中網路卡抓取封包進來後的行為

往往四夫是「接收」重於「傳輸」

不過的確,因為「傳輸」太複雜了,「接收」相對之下簡單許多

 

 

(一)The Path of Incoming IP Packets in L2

目前一般見到的 device driver 大致可以分為兩類

一類是 NAPI-aware,另一類是 NOT NAPI-aware

這兩類在處理入境封包會有稍許不同

以一般 NOT NAPI-aware 的 device driver 來說

可能就會有 net_interrupt()net_rx() 這類實作於 driver 中的函式

net_interrupt() 是中斷處理常式用來告訴 kernel 說有網路中斷發生

假設這是一個入境封包,那麼 net_rx() 就會被呼叫

net_rx() 會要求一個 socket buffer 並且把封包資料填進去 data space

此時會有一個函式叫做 eth_type_trans() 解析出在 Ethetner frame 中 protocol 欄位

接下來 netif_rx() 就會被呼叫

 

 

 

netif_rx() 做的事情很簡單

它會把入境封包置於 CPU 的 input queue 並觸發軟體中斷

透過 napi_schedule() 將 input device 放進 polling list 後

把類型為 NET_RX_SOFTIRQ 的軟體中斷標記起來

下一輪排程時系統就會發現有軟體中斷被標記

因此找出對應的處理函式 net_rx_action() 來處理

而它的工作就是去瀏覽位於 polling list 中的裝置

並呼叫了虛擬函式 poll()

對於 NOT NAPI-aware 的裝置來說

此虛擬函式會是 process_backlog()

會將封包從 CPU 的 input queue 取出來

取出來的封包經由 netif_receive_skb() 去處理它

netif_receive_skb() 會比對 skb->protocol 這個欄位找出相對應的 L3 處理函式

 

 

 

對於 NAPI-aware 的裝置來說

可能網路卡在封包抓進來後就不會經過 netif_rx() 這個函式

而是直接呼叫 napi_schedule()

並且虛擬函式 poll() 所對應的函式則不是預設的 process_backlog()

而是各個網路卡自己所實作出來的函式

但是其大概的處理方向是不會相差太多的

 

 

 

(二)The Path of Incoming IP Packets in L3

假設入境封包是個 IPv4 的封包

ip_rcv() 會被呼叫來去處理這個 IPv4 的封包

ip_rcv() 它只做一些簡單的工作而已

就是所謂的健全度檢查(sanity check)

然後才會往上傳

此時會經過 Linux kernel 中 Netfilter 防火牆的五大 hook 之一

也就是 NF_INET_PRE_ROUTING

確認說是否有要對該封包做些額外的處理

如果沒有,就會呼叫 ip_rcv_finish() 去做真正的工作

 

 

ip_rcv_finish() 做了什麼事呢?

其實也沒什麼事

就決定說封包是要繼續網上傳給本機端或是要轉送

以及處理部分的 IP 選項

因此,在 ip_rcv_finish() 中會有個函式 ip_route_input()

就是用來設定 skb->dst->input() 是要 ip_local_deliver() 還是 ip_forward()

分別就是傳給本機端和轉送

 

 

ip_local_deliver() 繼續處理要送給本機端的封包

然而這不是真正的處理函式

它只負責將 IP fragment 重組

通過 NF_INET_LOCAL_IN 的 hook 後,由 ip_local_deliver_finish() 去處理

ip_local_deliver_finish() 會根據 IP header 中 protocol 的欄位

找出相對應的 L4 處理常式

看是 TCP 的 tcp_v4_rcv() 、UDP 的 udp_rcv()

ICMP 的 icmp_rcv() 或是 IGMP 的 igmp_rcv()

 

 

如果封包是要轉送的,ip_forward() 會被呼叫

它做的事情不少,但不外乎就是一些健全度檢查以及一些 IP 選項的處理

並且通過 NF_INET_FORWARD 這個 hook 後

ip_forward_finish() 會被呼叫

類似前面說的處理情況

透過函式 ip_forward_options() 處理剩下的 IP 選項後

根據 skb->dst->output() 來決定接下來封包的去向

假設是要往外傳輸,則會呼叫 ip_output()

然而出境封包的處理行為非常的複雜

留到之後再與大家作分享

(若有誤歡迎指正,謝謝)

 

 

參考資料:

(1) Understanding Linux Network Internals Ch10, 13, 18, 20, 24, 35

(2) The Linux Networking Architecture: Design and Implementation of Network Protocols in the Linux Kernel Ch5, 6, 14

arrow
arrow
    全站熱搜

    fantasymew 發表在 痞客邦 留言(4) 人氣()