bcc 是基於 llvm 的工具集,用 python 封裝了底層機器相關的細節,bcc工具使得 ebpf 的使用更加方便,使用時核心探測**用 c 寫, 資料處理用 python 。本文將使用 bcc工具抓取核心網路中的資料,包括抓取 backlog 資訊、port 和 ip 資訊、網路命名空間資訊等。
ebpf 可以將任何核心函式呼叫轉換成可帶任何資料的使用者空間事件。每當有程式監聽 tcp socket,就得到乙個事件通知。當在af_inet
和sock_stream
型別的 socket 上呼叫系統呼叫 listen() 時,底層負責處理的核心函式就是inet_listen()
。我們可以用 kprobe 在它的入口做 hook,從列印乙個hello, world
開始。
from bcc import bpf
# hello bpf program
bpf_text =
"""#include
#include
// 1. attach kprobe to "inet_listen"
intkprobe__inet_listen
(struct pt_regs *ctx,
struct socket *sock,
int backlog)
;"""
# 2. build and inject program
b =bpf
(text=bpf_text)
# 3. print debug output
while true:
print b.
trace_readline
()
這個程式做了 3 件事情:
執行此bcc程式,在另乙個終端輸入nc -l 0 4242
,可以看到此bcc程式執行結果如下:
nc 是個單連線的小工具。「backlog」 是 tcp socket 允許建立的最大連線的數量(等待被 accept())。將程式中的bpf_trace_printk
修改為如下:重新執行程式,在另乙個終端輸入bpf_trace_printk
("listening with with up to %d pending connections!\\n"
, backlog)
;
nc -l 0 4242
,因為 nc 是乙個單鏈結的小工具,所以 backlog 是 1,執行結果如下:閱讀核心
inet_listen
原始碼發現,我們需要從 socket 物件中拿到inet_sock
字段 。從核心直接拷貝這兩行**,放到我們 tracing 程式的開始處:port 可以從// cast types. intermediate cast not needed, kept for readability
struct sock *sk = sock->sk;
struct inet_sock *inet =
inet_sk
(sk)
;
inet->inet_sport
中獲得,注意是網路序(大端)。ip 從 inet->inet_rcv_saddr 讀取。現在將程式中的bpf_trace_printk
修改為如下:重新執行程式,在另乙個終端輸入bpf_trace_printk
("listening on %x %d with %d pending connections\\n"
, inet->inet_rcv_saddr, inet->inet_sport, backlog)
;
nc -l 0 4242
,執行結果如下:在使用者空間,可以在
/proc/pid/ns/net
檢視網路命名空間,格式類似於net:[4026531957]
。中括號中的數字是網路命名空間的 inode。這意味著,想獲取命名空間,我們可以直接去讀 proc 。但是,這種方式只適用於執行時間比較短的程序,而且還存在競爭。下面我們使用 ebpf 從 kernel 直接讀取 inode 值,新增獲取網路命名空間功能後的完整bcc程式如下:執行時出現了這樣的錯誤:from bcc import bpf
# hello bpf program
bpf_text =
"""#include
#include
#include
// 1. attach kprobe to "inet_listen"
intkprobe__inet_listen
(struct pt_regs *ctx,
struct socket *sock,
int backlog)
;"""
# 2. build and inject program
b =bpf
(text=bpf_text)
# 3. print debug output
while true:
print b.
trace_readline
()
clang 想告訴我們:error: :0:0: in function kprobe__inet_listen i32 (%struct.pt_regs*): too many args to 0x55a83e8f8320: i64 = constant<6>
bpf_trace_printk
帶的引數太多了,這是 bpf 的限制。解決這個問題的辦法就是使用 perf,它支援傳遞任意大小的結構體到使用者空間。(注意需要 linux 4.4 以上核心)核心網技術之網路切片學習總結
如果把4g網路比作一把刀,那麼5g網路堪稱瑞士軍刀,因為5g使用了網路切片技術,切出了多張虛擬網路讓業務變得更加靈活多樣。而5g網路是要面向多連線和多樣化業務的,需要能夠像積木一樣靈活部署,方便地進行新業務快速上線 下線,滿足人們日益增長的資料業務需求。網路切片是一種按需組網的方式,可以讓運營商在統...
將eBPF作為LINUX核心學習的工具
純粹寫一些linux核心學習的體會。近段時間,斷斷續續的溫習一些linux核心的知識。一直苦於沒有找到乙個可以實踐的著力點。不過,最近看到ebpf相關的資料,我覺得可以將它作為乙個實踐的專案來推進linux核心的學習。具體的方向主要包括兩方面,將ebpf作為核心追蹤的工具,另一方面是學習,分析xdp...
優化RHEL5的核心網路引數
url vi etc sysctl.conf,加入以下引數,儲存後使用 sbin sysctl p命令使設定生效或重啟機器。減少超時前的探測次數 net.ipv4.tcp keepalive probes 5 確定兩次 isalive 時間間隔探測之間的等待時間 net.ipv4.tcp keepa...