BPF_MAP_TYPE_DEVMAP 和 BPF_MAP_TYPE_DEVMAP_HASH¶
注意
BPF_MAP_TYPE_DEVMAP在核心版本 4.14 中引入BPF_MAP_TYPE_DEVMAP_HASH在核心版本 5.4 中引入
BPF_MAP_TYPE_DEVMAP 和 BPF_MAP_TYPE_DEVMAP_HASH 是 BPF 對映,主要用作 XDP BPF 輔助呼叫 bpf_redirect_map() 的後端對映。BPF_MAP_TYPE_DEVMAP 由一個數組支援,該陣列使用鍵作為索引來查詢對網路裝置的引用。而 BPF_MAP_TYPE_DEVMAP_HASH 由一個雜湊表支援,該雜湊表使用鍵來查詢對網路裝置的引用。使用者提供 <key/ ifindex> 或 <key/ struct bpf_devmap_val> 對來使用新的網路裝置更新對映。
注意
雜湊對映的鍵不必是
ifindex。雖然
BPF_MAP_TYPE_DEVMAP_HASH允許密集地打包網路裝置,但代價是在執行查詢時需要對鍵進行雜湊處理。
設定和資料包排隊/傳送程式碼在兩種 devmap 型別之間共享;只有查詢和插入是不同的。
用法¶
核心 BPF¶
bpf_redirect_map()¶
long bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags)
將資料包重定向到 map 中索引為 key 的端點引用的位置。對於 BPF_MAP_TYPE_DEVMAP 和 BPF_MAP_TYPE_DEVMAP_HASH,此對映包含對網路裝置的引用(用於透過其他埠轉發資料包)。
如果對映查詢失敗,則 *flags* 的低兩位用作返回值。這是為了使返回值可以是 XDP 程式返回程式碼之一,直到 XDP_TX,由呼叫者選擇。 可以將 flags 的高位設定為 BPF_F_BROADCAST 或 BPF_F_EXCLUDE_INGRESS,如下所述。
使用 BPF_F_BROADCAST,資料包將被廣播到對映中的所有介面,使用 BPF_F_EXCLUDE_INGRESS,入口介面將從廣播中排除。
注意
如果設定了 BPF_F_BROADCAST,則忽略鍵。
廣播功能也可用於實現多播轉發:只需建立多個 DEVMAP,每個 DEVMAP 對應一個多播組。
如果成功,此輔助函式將返回 XDP_REDIRECT,如果對映查詢失敗,則返回 flags 引數的低兩位的值。
有關重定向的更多資訊,請參見重定向
bpf_map_lookup_elem()¶
void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)
可以使用 bpf_map_lookup_elem() 輔助函式檢索網路裝置條目。
使用者空間¶
注意
DEVMAP 條目只能從使用者空間更新/刪除,而不能從 eBPF 程式更新/刪除。嘗試從核心 eBPF 程式呼叫這些函式將導致程式載入失敗並出現驗證程式警告。
bpf_map_update_elem()¶
int bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags);
可以使用 bpf_map_update_elem() 輔助函式新增或更新網路裝置條目。此輔助函式以原子方式替換現有元素。對於向後相容性,value 引數可以是 struct bpf_devmap_val 或簡單的 int ifindex。
struct bpf_devmap_val { __u32 ifindex; /* device index */ union { int fd; /* prog fd on map write */ __u32 id; /* prog id on map read */ } bpf_prog; };
flags引數可以是以下之一BPF_ANY:建立新元素或更新現有元素。BPF_NOEXIST:僅在新元素不存在時建立新元素。BPF_EXIST:更新現有元素。
DEVMAP 可以透過將 bpf_prog.fd 新增到 struct bpf_devmap_val 來將程式與裝置條目相關聯。程式在 XDP_REDIRECT 之後執行,並且可以訪問 Rx 裝置和 Tx 裝置。與 fd 關聯的程式必須具有 XDP 型別,並且預期附加型別為 xdp_devmap。當程式與裝置索引關聯時,程式將在 XDP_REDIRECT 上執行,並在將緩衝區新增到每個 CPU 佇列之前執行。有關如何附加/使用 xdp_devmap progs 的示例可以在核心 selftest 中找到
tools/testing/selftests/bpf/prog_tests/xdp_devmap_attach.ctools/testing/selftests/bpf/progs/test_xdp_with_devmap_helpers.c
bpf_map_lookup_elem()¶
-
int bpf_map_lookup_elem(int fd, const void *key, void *value);¶
可以使用 bpf_map_lookup_elem() 輔助函式檢索網路裝置條目。
bpf_map_delete_elem()¶
-
int bpf_map_delete_elem(int fd, const void *key);¶
可以使用 bpf_map_delete_elem() 輔助函式刪除網路裝置條目。如果成功,此輔助函式將返回 0,如果失敗,則返回負錯誤。
示例¶
核心 BPF¶
以下程式碼片段顯示瞭如何宣告名為 tx_port 的 BPF_MAP_TYPE_DEVMAP。
struct {
__uint(type, BPF_MAP_TYPE_DEVMAP);
__type(key, __u32);
__type(value, __u32);
__uint(max_entries, 256);
} tx_port SEC(".maps");
以下程式碼片段顯示瞭如何宣告名為 forward_map 的 BPF_MAP_TYPE_DEVMAP_HASH。
struct {
__uint(type, BPF_MAP_TYPE_DEVMAP_HASH);
__type(key, __u32);
__type(value, struct bpf_devmap_val);
__uint(max_entries, 32);
} forward_map SEC(".maps");
注意
上面 DEVMAP 中的值型別是 struct bpf_devmap_val
以下程式碼片段顯示了一個簡單的 xdp_redirect_map 程式。此程式將與一個使用者空間程式一起工作,該程式根據入口 ifindex 填充 devmap forward_map。 BPF 程式(如下)使用入口 ifindex 作為 key 重定向資料包。
SEC("xdp")
int xdp_redirect_map_func(struct xdp_md *ctx)
{
int index = ctx->ingress_ifindex;
return bpf_redirect_map(&forward_map, index, 0);
}
以下程式碼片段顯示了一個 BPF 程式,該程式將資料包廣播到 tx_port devmap 中的所有介面。
SEC("xdp")
int xdp_redirect_map_func(struct xdp_md *ctx)
{
return bpf_redirect_map(&tx_port, 0, BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS);
}
使用者空間¶
以下程式碼片段顯示瞭如何更新名為 tx_port 的 devmap。
int update_devmap(int ifindex, int redirect_ifindex)
{
int ret;
ret = bpf_map_update_elem(bpf_map__fd(tx_port), &ifindex, &redirect_ifindex, 0);
if (ret < 0) {
fprintf(stderr, "Failed to update devmap_ value: %s\n",
strerror(errno));
}
return ret;
}
以下程式碼片段顯示瞭如何更新名為 forward_map 的 hash_devmap。
int update_devmap(int ifindex, int redirect_ifindex)
{
struct bpf_devmap_val devmap_val = { .ifindex = redirect_ifindex };
int ret;
ret = bpf_map_update_elem(bpf_map__fd(forward_map), &ifindex, &devmap_val, 0);
if (ret < 0) {
fprintf(stderr, "Failed to update devmap_ value: %s\n",
strerror(errno));
}
return ret;
}