BPF_MAP_TYPE_XSKMAP¶
注意
BPF_MAP_TYPE_XSKMAP是在核心版本 4.18 中引入的
BPF_MAP_TYPE_XSKMAP 用作 XDP BPF 輔助呼叫 bpf_redirect_map() 和 XDP_REDIRECT 操作的後端對映,例如 ‘devmap’ 和 ‘cpumap’。此對映型別將原始 XDP 幀重定向到 AF_XDP 套接字 (XSK),這是一種核心中的新型地址族,允許將幀從驅動程式重定向到使用者空間,而無需遍歷完整的網路堆疊。AF_XDP 套接字繫結到單個 netdev 佇列。XSK 到佇列的對映如下所示
+---------------------------------------------------+
| xsk A | xsk B | xsk C |<---+ User space
=========================================================|==========
| Queue 0 | Queue 1 | Queue 2 | | Kernel
+---------------------------------------------------+ |
| Netdev eth0 | |
+---------------------------------------------------+ |
| +=============+ | |
| | key | xsk | | |
| +---------+ +=============+ | |
| | | | 0 | xsk A | | |
| | | +-------------+ | |
| | | | 1 | xsk B | | |
| | BPF |-- redirect -->+-------------+-------------+
| | prog | | 2 | xsk C | |
| | | +-------------+ |
| | | |
| | | |
| +---------+ |
| |
+---------------------------------------------------+
注意
繫結到特定 <netdev/queue_id> 的 AF_XDP 套接字將僅接受來自該 <netdev/queue_id> 的 XDP 幀。如果 XDP 程式嘗試從套接字繫結到的 <netdev/queue_id> 以外的 <netdev/queue_id> 重定向,則套接字將不會收到該幀。
通常,每個 netdev 建立一個 XSKMAP。此對映包含 XSK 檔案描述符 (FD) 的陣列。陣列元素的數量通常使用 max_entries 對映引數設定或調整。對於 AF_XDP,max_entries 等於 netdev 支援的佇列數。
注意
對映鍵和對映值的大小必須都是 4 個位元組。
用法¶
核心 BPF¶
bpf_redirect_map()¶
long bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags)
將資料包重定向到 map 中索引為 key 的端點引用的位置。對於 BPF_MAP_TYPE_XSKMAP,此對映包含對連線到 netdev 佇列的套接字的 XSK FD 的引用。
注意
如果對映在索引處為空,則資料包將被丟棄。這意味著必須載入一個 XDP 程式,該程式在 XSKMAP 中至少有一個 XSK,才能透過套接字將任何流量傳送到使用者空間。
bpf_map_lookup_elem()¶
void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)
可以使用 bpf_map_lookup_elem() 輔助程式檢索 struct xdp_sock * 型別的 XSK 條目引用。
使用者空間¶
注意
XSK 條目只能從使用者空間更新/刪除,而不能從 BPF 程式更新/刪除。嘗試從核心 BPF 程式呼叫這些函式將導致程式載入失敗並出現驗證器警告。
bpf_map_update_elem()¶
int bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags)
可以使用 bpf_map_update_elem() 輔助程式新增或更新 XSK 條目。key 引數等於 XSK 連線到的佇列的 queue_id。value 引數是該套接字的 FD 值。
在底層,XSKMAP 更新函式使用 XSK FD 值來檢索關聯的 struct xdp_sock 例項。
flags 引數可以是以下之一
BPF_ANY:建立新元素或更新現有元素。
BPF_NOEXIST:僅當新元素不存在時才建立新元素。
BPF_EXIST:更新現有元素。
bpf_map_lookup_elem()¶
int bpf_map_lookup_elem(int fd, const void *key, void *value)
返回 struct xdp_sock *,如果失敗,則返回負錯誤。
bpf_map_delete_elem()¶
int bpf_map_delete_elem(int fd, const void *key)
可以使用 bpf_map_delete_elem() 輔助程式刪除 XSK 條目。如果成功,此輔助程式將返回 0,如果失敗,則返回負錯誤。
注意
當 libxdp 刪除 XSK 時,它也會從 XSKMAP 中刪除關聯的套接字條目。
示例¶
核心¶
以下程式碼段顯示瞭如何宣告一個名為 xsks_map 的 BPF_MAP_TYPE_XSKMAP,以及如何將資料包重定向到 XSK。
struct {
__uint(type, BPF_MAP_TYPE_XSKMAP);
__type(key, __u32);
__type(value, __u32);
__uint(max_entries, 64);
} xsks_map SEC(".maps");
SEC("xdp")
int xsk_redir_prog(struct xdp_md *ctx)
{
__u32 index = ctx->rx_queue_index;
if (bpf_map_lookup_elem(&xsks_map, &index))
return bpf_redirect_map(&xsks_map, index, 0);
return XDP_PASS;
}
使用者空間¶
以下程式碼段顯示瞭如何使用 XSK 條目更新 XSKMAP。
int update_xsks_map(struct bpf_map *xsks_map, int queue_id, int xsk_fd)
{
int ret;
ret = bpf_map_update_elem(bpf_map__fd(xsks_map), &queue_id, &xsk_fd, 0);
if (ret < 0)
fprintf(stderr, "Failed to update xsks_map: %s\n", strerror(errno));
return ret;
}
有關如何建立 AF_XDP 套接字的示例,請參閱 bpf-examples 目錄中 libxdp 儲存庫中的 AF_XDP-example 和 AF_XDP-forwarding 程式。有關 AF_XDP 介面的詳細說明,請參閱
AF_XDP 核心文件。
注意
使用 XSKMAP 和 AF_XDP 最全面的資源是 libxdp。