從使用者空間執行BPF程式

本文件描述了用於從使用者空間執行BPF程式的BPF_PROG_RUN設施。

概述

BPF_PROG_RUN命令可以透過bpf()系統呼叫在核心中執行BPF程式,並將結果返回給使用者空間。這可用於根據使用者提供的上下文物件對BPF程式進行單元測試,也可用於在核心中顯式執行程式以產生其副作用。該命令以前名為BPF_PROG_TEST_RUN,並且這兩個常量在UAPI標頭檔案中仍然定義並指向相同的值。

BPF_PROG_RUN命令可用於執行以下型別的BPF程式:

  • BPF_PROG_TYPE_SOCKET_FILTER

  • BPF_PROG_TYPE_SCHED_CLS

  • BPF_PROG_TYPE_SCHED_ACT

  • BPF_PROG_TYPE_XDP

  • BPF_PROG_TYPE_SK_LOOKUP

  • BPF_PROG_TYPE_CGROUP_SKB

  • BPF_PROG_TYPE_LWT_IN

  • BPF_PROG_TYPE_LWT_OUT

  • BPF_PROG_TYPE_LWT_XMIT

  • BPF_PROG_TYPE_LWT_SEG6LOCAL

  • BPF_PROG_TYPE_FLOW_DISSECTOR

  • BPF_PROG_TYPE_STRUCT_OPS

  • BPF_PROG_TYPE_RAW_TRACEPOINT

  • BPF_PROG_TYPE_SYSCALL

使用BPF_PROG_RUN命令時,使用者空間提供一個輸入上下文物件,以及(對於操作網路資料包的程式型別)一個包含BPF程式將操作的資料包資料的緩衝區。核心將執行該程式並將結果返回給使用者空間。請注意,在此模式下執行時,程式不會產生任何副作用;特別是,資料包不會真正被重定向或丟棄,程式返回碼將僅返回給使用者空間。XDP程式的即時執行模式是另外提供的,並在下方單獨說明。

在“即時幀模式”下執行XDP程式

BPF_PROG_RUN命令有一個單獨的模式用於執行即時XDP程式,該模式可用於以這樣一種方式執行XDP程式:資料包在XDP程式執行後將被核心實際處理,就像它們抵達物理介面一樣。透過在向BPF_PROG_RUN提供XDP程式時設定BPF_F_TEST_XDP_LIVE_FRAMES標誌來啟用此模式。

即時資料包模式針對所提供的XDP程式多次高效能執行進行了最佳化(例如,適合作為流量生成器執行),這意味著其語義不像常規測試執行模式那樣直觀。具體而言:

  • 在即時幀模式下執行XDP程式時,執行結果不會返回給使用者空間;相反,核心將執行程式返回碼指示的操作(丟棄資料包、重定向資料包等)。因此,在此模式下執行時,在系統呼叫引數中設定data_outctx_out屬性將被拒絕。此外,並非所有失敗都會直接報告回用戶空間;具體來說,只有設定或執行過程中的致命錯誤(如記憶體分配錯誤)才會中止執行並返回錯誤。如果資料包處理中發生錯誤,例如重定向到給定介面失敗,執行將繼續到下一個重複;這些錯誤可以透過與常規XDP程式相同的跟蹤點檢測到。

  • 使用者空間可以像常規(非即時)模式一樣,將一個ifindex作為上下文物件的一部分提供。XDP程式將如同資料包抵達該介面一樣執行;也就是說,上下文物件的ingress_ifindex將指向該介面。此外,如果XDP程式返回XDP_PASS,資料包將被注入核心網路堆疊,如同其抵達該ifindex一樣;如果返回XDP_TX,資料包將從同一介面傳出。然而請注意,由於程式執行並非發生在驅動程式上下文中,一個XDP_TX實際上會轉變為與一個XDP_REDIRECT到同一介面相同的操作(即,僅當驅動程式支援ndo_xdp_xmit驅動程式操作時才有效)。

  • 當程式進行多次重複執行時,執行將以批處理方式進行。批處理大小預設為64個數據包(與NAPI最大接收批處理大小相同),但使用者空間可以透過batch_size引數指定,最大可達256個數據包。對於每個批處理,核心會重複執行XDP程式,每次呼叫都會獲得資料包資料的單獨副本。對於每次重複,如果程式丟棄資料包,資料頁將立即回收(參見下文)。否則,資料包將一直緩衝到批處理結束,屆時在此批處理期間以這種方式緩衝的所有資料包將一次性傳輸。

  • 設定測試執行時,核心將初始化一個大小與批處理大小相同的記憶體頁池。每個記憶體頁都將使用使用者空間在呼叫BPF_PROG_RUN時提供的初始資料包資料進行初始化。如果可能,這些頁將在未來的程式呼叫中被回收,以提高效能。頁面通常會一次回收一個完整的批處理,但當資料包被丟棄時(透過返回碼或例如重定向錯誤),該頁面將立即回收。如果資料包最終被傳遞到常規網路堆疊(因為XDP程式返回XDP_PASS,或者因為它最終被重定向到將資料包注入堆疊的介面),則該頁面將被釋放,並在頁面池為空時分配一個新的頁面。

    回收時,頁面內容不會被重寫;上下文物件中只有資料包邊界指標(datadata_enddata_meta)會重置為原始值。這意味著如果程式重寫了資料包內容,則在後續呼叫中必須準備好看到原始內容或修改後的版本。