📌 置頂: 請把任何比你弱勢的用路人當作你的至親對待。跟前車保持安全車距 (2秒以上)。

The packet flow, from userspace to kernel driver in Linux network stack

In

,

Tags:



by

這是一個想要從 userspace 一直深入到 driver,理解 Linux packet 究竟如何運行的流程圖。

我在交大做的東西都在 driver space,使用 ath9k/ath10k 做實驗。我所理解的是 ath9k 上面對著 mac80211 (Linux 的 softmac),也就是說,driver 在功能上,只需要實做struct ieee80211_ops 的功能即可。主要都在處理 .wake_tx_queue 的功能。

對於他之上,頂多知道 ieee80211_queue_skb 最後會 call drv_wake_tx_queue 然後根據  driver 不同呼叫不同 driver 的實做,以 ath9k 而言就是 ath9k_wake_tx_queue。

還是想要知道一下,究竟這個 packet 是如何被傳入 mac80211 這層,順便解答一個以前問自己的問題「wireshark 抓封包時究竟是從那一層抓的」。

使用兩種工具,一個是 cflow、一個是 pycflow2dot。前者用來描述 call graph,後者拿來轉成 graphviz 的 dot 語言並且輸出 svg。兩者都有做修改,cflow 的部份請參考備註的部份,pycflow2dot 請參考我修改的版本: mlouielu/pycflow2dot

 

 

從上面這張圖我們可以看到,在 sock_sendmsg_nosec 這個 function 最後呼叫了 sock->ops->sendmsg(sock, msg, msg_data_left(msg)); ,這裡是一個典型的 Linux kernel Object Oriented 的做法「method dispatch」。

sock->opsstruct proto_ops 的物件,在裡面定義了許多的 method,而其他人只要實做其中的 method,就可以在通用的界面上被使用。

程式碼 中搜尋有實做 struct proto_ops 的檔案

確認是在 net/ipv4/af_inet.c 中實做了 stream (TCP) / dgram (UDP) / raw socket 的 struct proto_ops

這邊可以看到,.sendmsg = inet_sendmsg,也就是說前面的 sock_sendmsg_nosec 呼叫 sock->ops->sendmsg 如果是 TCP 封包的話,就會使用 inet_sendmsg 作為呼叫的 function。從 inet_sendmsg 開始我們可以繼續追蹤下去。

實際上,如果你有看 code 的話,會發現 TCP/UDP/RAW 都是呼叫 inet_sendmsg,這不太合理,因為至少我們知道 TCP 跟 UDP 的運作機制是不同的。我們可以看到,最後呼叫的是 sk->sk_prot->sendmsg,也就是 struct sock 裡面的 ops,因此,各個不同 protocol 的 sendmsg 還會在不同地方 implement。依照前面的經驗,我們去搜尋 sk_prot 被實做的地方就能發現實際上會呼叫哪個 function。

在 net 當中搜尋 struct proto: (grep -r . -e ‘struct proto’ | grep -v ‘ops’)

看一下 tcp_prot,實際實做的 function 就是 tcp_sendmsg:

tcp_sendmsg 在 net/ipv4/tcp.c 裡面:

 

以下是完整的流程圖,由 ksys_write 一路到送入 wireless driver 前的 drv_wake_tx_queue。

cflow2dot -s ksys_write -t dipv4/ip_output.c include/net/neighbour.h net/ipv4/route.c include/net/route.h include/linux/netdevice.h net/mac80211/iface.c include/net/dst.h net/ipv4/tcp.c net/ipv4/tcp_output.c include/net/ip.h net/socket.c fs/read_write.c include/linux/fs.h net/mac80211/tx.c net/ipv4/af_inet.c net/socket.c -R –rankdir TB && eog cflow0.svgrv_wake_tx_queue __netdev_start_xmit rt_dst_alloc __mkroute_output -I”–include=_s –main=ksys_write” -i net/core/dev.c net/

cflow not following reference [src/parser.c:reference(name,line)]


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.