BPF_PROG_TYPE_FLOW_DISSECTOR¶
概述¶
流分解器(Flow dissector)是一個從資料包中解析元資料的例程。它在網路子系統的各個地方(RFS、流雜湊等)都有使用。
BPF 流分解器試圖在 BPF 中重新實現基於 C 的流分解器邏輯,以獲得 BPF 驗證器的所有好處(即指令數量和尾呼叫的限制)。
API¶
BPF 流分解器程式在 __sk_buff 上操作。然而,只允許使用有限的欄位集:data、data_end 和 flow_keys。flow_keys 是 struct bpf_flow_keys,包含流分解器的輸入和輸出引數。
- 輸入引數為:
nhoff- 網路頭部的初始偏移量thoff- 傳輸頭部的初始偏移量,初始化為 nhoffn_proto- L3 協議型別,從 L2 頭部解析flags- 可選標誌
流分解器 BPF 程式應填充 struct bpf_flow_keys 的其餘欄位。輸入引數 nhoff/thoff/n_proto 也應進行相應調整。
BPF 程式的返回碼要麼是 BPF_OK 表示成功分解,要麼是 BPF_DROP 表示解析錯誤。
__sk_buff->data¶
在沒有 VLAN 的情況下,BPF 流分解器的初始狀態如下:
+------+------+------------+-----------+
| DMAC | SMAC | ETHER_TYPE | L3_HEADER |
+------+------+------------+-----------+
^
|
+-- flow dissector starts here
skb->data + flow_keys->nhoff point to the first byte of L3_HEADER
flow_keys->thoff = nhoff
flow_keys->n_proto = ETHER_TYPE
在 VLAN 的情況下,流分解器可以以兩種不同的狀態被呼叫。
VLAN 解析前
+------+------+------+-----+-----------+-----------+
| DMAC | SMAC | TPID | TCI |ETHER_TYPE | L3_HEADER |
+------+------+------+-----+-----------+-----------+
^
|
+-- flow dissector starts here
skb->data + flow_keys->nhoff point the to first byte of TCI
flow_keys->thoff = nhoff
flow_keys->n_proto = TPID
請注意,TPID 可以是 802.1AD,因此 BPF 程式對於雙標籤資料包可能需要解析兩次 VLAN 資訊。
VLAN 解析後
+------+------+------+-----+-----------+-----------+
| DMAC | SMAC | TPID | TCI |ETHER_TYPE | L3_HEADER |
+------+------+------+-----+-----------+-----------+
^
|
+-- flow dissector starts here
skb->data + flow_keys->nhoff point the to first byte of L3_HEADER
flow_keys->thoff = nhoff
flow_keys->n_proto = ETHER_TYPE
在這種情況下,VLAN 資訊已在流分解器之前處理,BPF 流分解器無需處理它。
這裡的要點如下:BPF 流分解器程式可以在包含可選 VLAN 頭的情況下被呼叫,並且應該優雅地處理兩種情況:存在單個或雙個 VLAN 以及不存在 VLAN。同一個程式可以用於這兩種情況,並且必須仔細編寫以處理這兩種情況。
標誌¶
flow_keys->flags 可能包含可選的輸入標誌,其作用如下:
BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG- 告訴 BPF 流分解器繼續解析第一個分片;預設的預期行為是流分解器在發現數據包已分片後立即返回;由eth_get_headlen用於估算 GRO 的所有頭部的長度。BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL- 告訴 BPF 流分解器在到達 IPv6 流標籤時停止解析;由___skb_get_hash用於獲取流雜湊。BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP- 告訴 BPF 流分解器在到達封裝頭部時停止解析;由路由基礎設施使用。
參考實現¶
請參閱 tools/testing/selftests/bpf/progs/bpf_flow.c 獲取參考實現,並參閱 tools/testing/selftests/bpf/flow_dissector_load.[hc] 獲取載入器。bpftool 也可以用於載入 BPF 流分解器程式。
- 參考實現組織如下:
jmp_table對映,包含每個支援的 L3 協議的子程式。_dissect例程 - 入口點;它進行輸入n_proto解析並執行bpf_tail_call到相應的 L3 處理器。
由於 BPF 目前不支援迴圈(或任何跳回),因此使用 jmp_table 來處理多層封裝(和 IPv6 選項)。
當前限制¶
BPF 流分解器不支援匯出所有核心中基於 C 的實現可以匯出的元資料。值得注意的例子是單 VLAN (802.1Q) 和雙 VLAN (802.1AD) 標籤。請參閱 struct bpf_flow_keys 以獲取當前可以從 BPF 上下文匯出的資訊集。
當 BPF 流分解器附加到根網路名稱空間(機器範圍策略)時,使用者無法在其子網路名稱空間中覆蓋它。