eBPF學習 抓取核心網路中的socket資訊

2021-10-06 16:28:12 字數 3218 閱讀 4207

bcc 是基於 llvm 的工具集,用 python 封裝了底層機器相關的細節,bcc工具使得 ebpf 的使用更加方便,使用時核心探測**用 c 寫, 資料處理用 python 。本文將使用 bcc工具抓取核心網路中的資料,包括抓取 backlog 資訊、port 和 ip 資訊、網路命名空間資訊等。

ebpf 可以將任何核心函式呼叫轉換成可帶任何資料的使用者空間事件。每當有程式監聽 tcp socket,就得到乙個事件通知。當在af_inetsock_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 程式的開始處:

// cast types. intermediate cast not needed, kept for readability

struct sock *sk = sock->sk;

struct inet_sock *inet =

inet_sk

(sk)

;

port 可以從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

()

執行時出現了這樣的錯誤:

error: :0:0: in function kprobe__inet_listen i32 (%struct.pt_regs*): too many args to 0x55a83e8f8320: i64 = constant<6>
clang 想告訴我們: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...