大家在探討 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
留言列表