自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

抽絲剝繭:從 Linux 源碼探索 eBPF 的實現(xiàn)

系統(tǒng) Linux
BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB 是 socket.accept() 接受連接請求并完成連接建立的操作符,也是眾多 `sock_ops` 操作符[40] 中的一個。這些操作符,可以被看作是 事件 Event[41],程序的觸發(fā)則是由事件驅動的。

去年學習 eBPF,分享過 幾篇 eBPF 方面的學習筆記[1],都是面向 eBPF 的應用。為了準備下一篇文章,這次決定從 Linux 源碼入手,深入了解 eBPF 的工作原理。因此這篇又是一篇學習筆記,假如你對 eBPF 的工作原理也感興趣,不如跟隨我的腳步一起。文章中若有任何問題,請不吝賜教。

這里不會再對 eBPF 進行過多的介紹,可以參考我的另一篇 使用 eBPF 技術實現(xiàn)更快的網絡數(shù)據(jù)包傳輸[2],結合 追蹤 Kubernetes 中的數(shù)據(jù)包[3] 可以了解 eBPF 的基本內容以及其在網絡加速方面的應用。

接下來我們還是使用 eBPF sockops[4] 中的程序 bpf_sockops[5] 為例, 配合 Linux v6.8[6] 源碼探索 eBPF 的工作原理。

注:由于公眾號排版問題閱讀可能不友好,可以點擊閱讀原文跳轉到博客閱讀。

圖片圖片

BPF 程序操作

在 load.sh[7] 腳本中,完成了程序的加載和掛載操作,下面的命令使用 bpftool[8] 分別完成 BPF 程序的加載和掛載。

#load
sudo bpftool prog load bpf_sockops.o "/sys/fs/bpf/bpf_sockop"
#attach
sudo bpftool cgroup attach "/sys/fs/cgroup/unified/" sock_ops pinned "/sys/fs/bpf/bpf_sockop"

這里 bpftool 是對內核函數(shù) bpf() 封裝的命令行工具,用于管理和操作 BPF 程序與 Map。

加載

sudo bpftool prog load bpf_sockops.o "/sys/fs/bpf/bpf_sockop"

命令 bpftool prog load 將 bpf_sockops.o 加載到路徑 /sys/fs/bpf/bpf_sockop 中。

bpftool 對 BPF 程序的加載是由調用 `bpf()`[9] 指定命令 BPF_PROG_LOAD 并傳入 加載選項`bpf_prog_load_opts`[10] 來完成的:

syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr))
  • syscall bpf()[11] bpf 系統(tǒng)函數(shù)
  • bpf_prog_load[13] 為程序分配內存、初始化、檢查證書、運行 verifier、創(chuàng)建文件描述符(fd)等
  • \_\_sys_bpf[12] 執(zhí)行 bpf 命令 BPF_PROG_LOAD

加載成功后的程序,然后就可以進行掛載了。

掛載

sudo bpftool cgroup attach "/sys/fs/cgroup/unified/" sock_ops pinned "/sys/fs/bpf/bpf_sockop"

命令 bpftool cgroup attach 將加載(pin 到文件系統(tǒng)中)的程序 /sys/fs/bpf/bpf_sockop 掛載到 cgroup /sys/fs/cgroup/unified/,掛載的類型為 sock_ops。這個 sock_ops 是 bpftool 所使用的庫 libbpf 定義,也被是 ELF 部件名,對應著 BPF 程序類型[14] BPF_PROG_TYPE_SOCK_OPS,掛載類型[15] 為 BPF_CGROUP_SOCK_OPS。

在 eBPF 編程中,ELF(Executable and Linkable Format)文件用于存儲編譯后的 eBPF 程序和相關數(shù)據(jù)。ELF 文件由多個部分(sections)組成,每個部分包含不同類型的信息,比如程序代碼、符號表、調試信息等。

libbpf 類型 sock_ops => BPF 程序類型 BPF_PROG_TYPE_SOCK_OPS => 掛載類型 BPF_CGROUP_SOCK_OPS,對應到程序 bpf_sockops.c 中部件名(__section)為 sockops 的代碼塊。

關于 sock_ops 掛載點:

sock_ops 通常指的是在 Linux 內核中處理套接字操作的一系列函數(shù)和操作。

sock_ops 具體可以包括一系列的操作,如創(chuàng)建套接字、綁定套接字到特定地址和端口、監(jiān)聽來自其他套接字的連接請求、接受連接請求、發(fā)送和接收數(shù)據(jù)、以及關閉套接字等。這些操作通常通過一組預定義的 API 來提供,例如 POSIX 套接字 API,它定義了一系列函數(shù),如 socket()、bind()、listen()、accept()、send()、recv() 和 close() 等,供應用程序調用。

這次 bpftool 是通過 bpf() 執(zhí)行執(zhí)行 BPF_PROG_ATTACH 并傳入 掛載選項 `bpf_prog_attach_opts`[16] 來完成的。

syscall(__NR_bpf, BPF_PROG_ATTACH, &attr, sizeof(attr))
  • syscall bpf()[17] bpf 系統(tǒng)函數(shù)

cgroup_bpf_prog_attach[19]

\_\_cgroup_bpf_attach[21]

bpf_prog_put[22] 檢查 cgroup 上是否存在相同掛載類型的程序,如果存在,則進行替換。

static_branch_inc[23] 如果不存在,則將 cgroup_bpf_enabled_key 計數(shù)器中,該掛載類型的計數(shù) +1。

cgroup_bpf_prog_attach[20]

bpf_prog_attach[18]

cgroup_bpf_enabled_key 特定類型 cgroup BPF 程序的計數(shù)器。

!!! 在運行時,會用到該計數(shù)器。

到此,我們已經成功將程序掛載到 cgroup 的 sock_ops 上。

套接字操作 sock_ops

套接字的操作很多,這里以連接建立過程中服務端 accept 操作為例。

圖片圖片

依然是從系統(tǒng)調用 accept 開始。

  • accept[24]

do_accept[26] 此處 ops->accept() 中的 ops 對應著 proto_ops inet_stream_ops[27] 有狀態(tài)的 socket(如 TCP) 的相關操作

inet_accept[29]  sk1->sk_prot->accept() 這里的 sk_prot 提供了 TCP 協(xié)議 `proto tcp_prot`[30] 的具體操作

tcp_v4_rcv[34] 此時第一次握手剛開始,sock(套接字在內核協(xié)議棧這層的體現(xiàn)) 的狀態(tài)還是 TCP_LISTEN

tcp_v4_do_rcv[35] 在連接成功建立前,每次握手都會對狀態(tài)進行處理。

tcp_init_transfer[37] sock 的狀態(tài)被設置為 BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB,開始進行數(shù)據(jù)傳輸。

BPF_CGROUP_RUN_PROG_SOCK_OPS[39] 執(zhí)行掛載類型為 BPF_CGROUP_SOCK_OPS 的 BPF 程序。

bpf_skops_established[38]

tcp_rcv_state_process[36] 我們直接看最后一次握手,也就是收到客戶端的 ACK,完成與客戶端連接的建立。

tcp_prot.accept[31]

inet_csk_accept 開始處理三次握手,調用 TCP 協(xié)議的實現(xiàn)來處理。inet_init[32] 注冊了 IPPROTO_TCP 也就是 TCP 協(xié)議的實現(xiàn),也就是 net_protocol tcp_protocol[33],其 handler 為 tcp_v4_rcv。

inet_stream_ops.accept[28]

\_\_sys_accept4_file[25]

BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB 是 socket.accept() 接受連接請求并完成連接建立的操作符,也是眾多 `sock_ops` 操作符[40] 中的一個。這些操作符,可以被看作是 事件 Event[41],程序的觸發(fā)則是由事件驅動的。例如:

  • 如果客戶端發(fā)起連接請求并完成三次握手后的操作符是 BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB;
  • 套接字進入監(jiān)聽狀態(tài)時的操作符是 BPF_SOCK_OPS_TCP_LISTEN_CB;
  • 數(shù)據(jù)被確認 BPF_SOCK_OPS_DATA_ACK_CB
  • TCP 狀態(tài)改變 BPF_SOCK_OPS_STATE_CB

最后就是 BPF 程序的執(zhí)行了,不多做贅述,有興趣的看這里的 分析[42]。

參考資料

[1] 幾篇 eBPF 方面的學習筆記: https://atbug.com/search?s=ebpf

[2] 使用 eBPF 技術實現(xiàn)更快的網絡數(shù)據(jù)包傳輸: https://atbug.com/accelerate-network-packets-transmission/

[3] 追蹤 Kubernetes 中的數(shù)據(jù)包: https://atbug.com/tracing-network-packets-in-kubernetes/

[4] eBPF sockops: https://github.com/addozhang/ebpf-sockops/

[5] bpf_sockops: https://github.com/addozhang/ebpf-sockops/blob/master/bpf_sockops.c#L28

[6] Linux v6.8: https://github.com/torvalds/linux/tree/v6.8

[7] load.sh: https://github.com/addozhang/ebpf-sockops/blob/master/load.sh

[8] bpftool: https://github.com/libbpf/bpftool

[9] bpf(): https://github.com/torvalds/linux/blob/715d82ba636cb3629a6e18a33bb9dbe53f9936ee/kernel/bpf/syscall.c#L5559

[10] 加載選項bpf_prog_load_opts: https://github.com/torvalds/linux/blob/05c31b4ab20527c4d1695130aaecc54ef59a0e54/tools/lib/bpf/bpf.h#L64

[11] syscall bpf(): https://github.com/torvalds/linux/blob/715d82ba636cb3629a6e18a33bb9dbe53f9936ee/kernel/bpf/syscall.c#L5559

[12] __sys_bpf: https://github.com/torvalds/linux/blob/715d82ba636cb3629a6e18a33bb9dbe53f9936ee/kernel/bpf/syscall.c#L5456

[13] bpf_prog_load: https://github.com/torvalds/linux/blob/715d82ba636cb3629a6e18a33bb9dbe53f9936ee/kernel/bpf/syscall.c#L2595

[14] BPF 程序類型: https://github.com/torvalds/linux/blob/d17aff807f845cf93926c28705216639c7279110/tools/include/uapi/linux/bpf.h#L964

[15] 掛載類型: https://github.com/torvalds/linux/blob/d17aff807f845cf93926c28705216639c7279110/tools/include/uapi/linux/bpf.h#L1000

[16] 掛載選項 bpf_prog_attach_opts: https://github.com/torvalds/linux/blob/05c31b4ab20527c4d1695130aaecc54ef59a0e54/tools/lib/bpf/bpf.h#L321C8-L321C28

[17] syscall bpf(): https://github.com/torvalds/linux/blob/715d82ba636cb3629a6e18a33bb9dbe53f9936ee/kernel/bpf/syscall.c#L5466

[18] bpf_prog_attach: https://github.com/torvalds/linux/blob/715d82ba636cb3629a6e18a33bb9dbe53f9936ee/kernel/bpf/syscall.c#L3936

[19] cgroup_bpf_prog_attach: https://github.com/torvalds/linux/blob/v6.8/kernel/bpf/cgroup.c#L1130

[20] cgroup_bpf_prog_attach: https://github.com/torvalds/linux/blob/v6.8/kernel/bpf/cgroup.c#L733

[21] __cgroup_bpf_attach: https://github.com/torvalds/linux/blob/v6.8/kernel/bpf/cgroup.c#L607

[22] bpf_prog_put: https://github.com/torvalds/linux/blob/v6.8/kernel/bpf/cgroup.c#L700

[23] static_branch_inc: https://github.com/torvalds/linux/blob/v6.8/kernel/bpf/cgroup.c#L702

[24] accept: https://github.com/torvalds/linux/blob/v6.8/net/socket.c#L2016

[25] __sys_accept4_file: https://github.com/torvalds/linux/blob/v6.8/net/socket.c#L1969

[26] do_accept: https://github.com/torvalds/linux/blob/v6.8/net/socket.c#L1929

[27] proto_ops inet_stream_ops: https://github.com/torvalds/linux/blob/eef00a82c568944f113f2de738156ac591bbd5cd/net/ipv4/af_inet.c#L1051

[28] inet_stream_ops.accept: https://github.com/torvalds/linux/blob/eef00a82c568944f113f2de738156ac591bbd5cd/net/ipv4/af_inet.c#L1058

[29] inet_accept: https://github.com/torvalds/linux/blob/eef00a82c568944f113f2de738156ac591bbd5cd/net/ipv4/af_inet.c#L780

[30] proto tcp_prot: https://github.com/torvalds/linux/blob/da7dfaa6d6f731c30eca6ffa808b83634d43e26f/net/ipv4/tcp_ipv4.c#L3314

[31] tcp_prot.accept: https://github.com/torvalds/linux/blob/da7dfaa6d6f731c30eca6ffa808b83634d43e26f/net/ipv4/tcp_ipv4.c#L3314

[32] inet_init: https://github.com/torvalds/linux/blob/eef00a82c568944f113f2de738156ac591bbd5cd/net/ipv4/af_inet.c#L1997

[33] net_protocol tcp_protocol: https://github.com/torvalds/linux/blob/eef00a82c568944f113f2de738156ac591bbd5cd/net/ipv4/af_inet.c#L1754

[34] tcp_v4_rcv: https://github.com/torvalds/linux/blob/da7dfaa6d6f731c30eca6ffa808b83634d43e26f/net/ipv4/tcp_ipv4.c#L2319

[35] tcp_v4_do_rcv: https://github.com/torvalds/linux/blob/da7dfaa6d6f731c30eca6ffa808b83634d43e26f/net/ipv4/tcp_ipv4.c#L1929

[36] tcp_rcv_state_process: https://github.com/torvalds/linux/blob/v6.8/net/ipv4/tcp_input.c#L6724

[37] tcp_init_transfer: https://github.com/torvalds/linux/blob/v6.8/net/ipv4/tcp_input.c#L6208

[38] bpf_skops_established: https://github.com/torvalds/linux/blob/v6.8/net/ipv4/tcp_input.c#L192

[39] BPF_CGROUP_RUN_PROG_SOCK_OPS: https://github.com/torvalds/linux/blob/v6.8/include/linux/bpf-cgroup.h#L350

[40] sock_ops 操作符: sock_ops

[41] 事件 Event: https://atbug.com/accelerate-network-packets-transmission/#事件驅動

[42] 分析: https://atbug.com/accelerate-network-packets-transmission/#實現(xiàn)

責任編輯:武曉燕 來源: 云原生指北
相關推薦

2021-06-11 18:27:10

LinuxLinux內核

2022-01-17 17:55:29

Python變量交換開發(fā)

2021-06-16 07:56:21

Redis分布式

2022-07-05 21:31:21

索引SQL分庫分表

2022-07-11 11:28:45

數(shù)據(jù)分析業(yè)務消費

2015-06-09 11:13:18

2020-05-06 08:01:39

黑客惡意攻擊網絡安全

2021-04-19 11:07:13

Windbg程序.NET

2022-04-01 15:18:42

Web 框架網絡通信

2022-09-03 15:12:40

AndroidJDK 11升級

2018-09-13 15:21:36

CTO訓練營

2024-01-03 16:39:07

2019-05-14 14:51:40

Java語法糖用法

2019-05-23 11:42:04

Java語法糖編程語言

2019-12-10 15:30:27

SaaSIaaS云計算

2022-02-22 07:40:10

邊緣計算云原生中心云

2015-12-28 16:09:20

物聯(lián)網市場

2014-09-17 09:55:09

頑固漏洞遺留代碼應用開發(fā)

2020-06-09 15:15:31

運維中臺技術

2017-09-15 09:18:27

JavaSQLDBA
點贊
收藏

51CTO技術棧公眾號