BPF sk_lookup 程式

BPF sk_lookup 程式型別 (BPF_PROG_TYPE_SK_LOOKUP) 將可程式設計性引入到傳輸層執行的套接字查詢中,當資料包需要在本地交付時。

當呼叫 BPF sk_lookup 程式時,可以透過呼叫 bpf_sk_assign() BPF 輔助函式來選擇將接收傳入資料包的套接字。

TCP 和 UDP 都存在用於常見連線點 (BPF_SK_LOOKUP) 的鉤子。

動機

引入 BPF sk_lookup 程式型別是為了解決在某些設定場景中,使用 bind() 套接字呼叫將套接字繫結到地址是不切實際的,例如

  1. 在一定 IP 地址範圍內接收連線,例如 192.0.2.0/24,當由於埠衝突而無法繫結到萬用字元地址 INADRR_ANY 時,

  2. 接收所有或很大範圍的埠上的連線,即 L7 代理用例。

這樣的設定將需要建立並將一個套接字 bind() 到範圍內的每個 IP 地址/埠,導致資源消耗和套接字查詢期間潛在的延遲峰值。

附件

可以使用 bpf(BPF_LINK_CREATE, ...) 系統呼叫,使用 BPF_SK_LOOKUP 附加型別和 netns FD 作為附件 target_fd,將 BPF sk_lookup 程式附加到網路名稱空間。

可以將多個程式附加到一個網路名稱空間。 程式將按照附加的順序呼叫。

鉤子

每當傳輸層需要為傳入資料包找到一個偵聽(TCP)或未連線(UDP)套接字時,都會執行附加的 BPF sk_lookup 程式。

到已建立(TCP)和已連線(UDP)套接字的傳入流量將像往常一樣傳送,而不會觸發 BPF sk_lookup 鉤子。

附加的 BPF 程式必須以 SK_PASSSK_DROP 判決程式碼返回。 對於其他作為網路過濾器的 BPF 程式型別,SK_PASS 表示套接字查詢應繼續到常規的基於雜湊表的查詢,而 SK_DROP 導致傳輸層丟棄資料包。

BPF sk_lookup 程式還可以透過呼叫 bpf_sk_assign() BPF 輔助函式來選擇一個套接字來接收資料包。 通常,該程式在儲存套接字的對映中查詢套接字,例如 SOCKMAPSOCKHASH,並將 struct bpf_sock * 傳遞給 bpf_sk_assign() 輔助函式以記錄選擇。 僅當程式以 SK_PASS 程式碼終止時,選擇套接字才會生效。

當附加多個程式時,最終結果由所有程式的返回程式碼根據以下規則確定

  1. 如果任何程式返回 SK_PASS 並選擇了一個有效的套接字,則該套接字將用作套接字查詢的結果。

  2. 如果多個程式返回 SK_PASS 並選擇了一個套接字,則最後一個選擇生效。

  3. 如果任何程式返回 SK_DROP,並且沒有程式返回 SK_PASS 並選擇了一個套接字,則套接字查詢失敗。

  4. 如果所有程式都返回 SK_PASS 並且沒有程式選擇套接字,則套接字查詢繼續。

API

在其上下文中,struct bpf_sk_lookup 的例項,BPF sk_lookup 程式接收有關觸發套接字查詢的資料包的資訊。 即

  • IP 版本 (AF_INETAF_INET6),

  • L4 協議識別符號 (IPPROTO_TCPIPPROTO_UDP),

  • 源和目標 IP 地址,

  • 源和目標 L4 埠,

  • 已使用 bpf_sk_assign() 選擇的套接字。

有關詳細資訊,請參閱 linux/bpf.h 使用者 API 標頭中的 struct bpf_sk_lookup 宣告,以及 bpf-helpers(7) 手冊頁中的 bpf_sk_assign() 部分。

示例

有關參考實現,請參閱 tools/testing/selftests/bpf/prog_tests/sk_lookup.c