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() 套接字呼叫將套接字繫結到地址是不切實際的,例如
在一定 IP 地址範圍內接收連線,例如 192.0.2.0/24,當由於埠衝突而無法繫結到萬用字元地址
INADRR_ANY時,接收所有或很大範圍的埠上的連線,即 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_PASS 或 SK_DROP 判決程式碼返回。 對於其他作為網路過濾器的 BPF 程式型別,SK_PASS 表示套接字查詢應繼續到常規的基於雜湊表的查詢,而 SK_DROP 導致傳輸層丟棄資料包。
BPF sk_lookup 程式還可以透過呼叫 bpf_sk_assign() BPF 輔助函式來選擇一個套接字來接收資料包。 通常,該程式在儲存套接字的對映中查詢套接字,例如 SOCKMAP 或 SOCKHASH,並將 struct bpf_sock * 傳遞給 bpf_sk_assign() 輔助函式以記錄選擇。 僅當程式以 SK_PASS 程式碼終止時,選擇套接字才會生效。
當附加多個程式時,最終結果由所有程式的返回程式碼根據以下規則確定
如果任何程式返回
SK_PASS並選擇了一個有效的套接字,則該套接字將用作套接字查詢的結果。如果多個程式返回
SK_PASS並選擇了一個套接字,則最後一個選擇生效。如果任何程式返回
SK_DROP,並且沒有程式返回SK_PASS並選擇了一個套接字,則套接字查詢失敗。如果所有程式都返回
SK_PASS並且沒有程式選擇套接字,則套接字查詢繼續。
API¶
在其上下文中,struct bpf_sk_lookup 的例項,BPF sk_lookup 程式接收有關觸發套接字查詢的資料包的資訊。 即
IP 版本 (
AF_INET或AF_INET6),L4 協議識別符號 (
IPPROTO_TCP或IPPROTO_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。