요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0-only
.. Copyright (C) 2022 Red Hat, Inc.
===================
BPF_MAP_TYPE_XSKMAP
===================
.. note::
- ``BPF_MAP_TYPE_XSKMAP`` was introduced in kernel version 4.18
The ``BPF_MAP_TYPE_XSKMAP`` is used as a backend map for XDP BPF helper
call ``bpf_redirect_map()`` and ``XDP_REDIRECT`` action, like 'devmap' and 'cpumap'.
This map type redirects raw XDP frames to `AF_XDP`_ sockets (XSKs), a new type of
address family in the kernel that allows redirection of frames from a driver to
user space without having to traverse the full network stack. An AF_XDP socket
binds to a single netdev queue. A mapping of XSKs to queues is shown below:
.. code-block:: none
+---------------------------------------------------+
| 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 | |
| | | +-------------+ |
| | | |
| | | |
| +---------+ |
| |
+---------------------------------------------------+
.. note::
An AF_XDP socket that is bound to a certain <netdev/queue_id> will *only*
accept XDP frames from that <netdev/queue_id>. If an XDP program tries to redirect
from a <netdev/queue_id> other than what the socket is bound to, the frame will
not be received on the socket.
Typically an XSKMAP is created per netdev. This map contains an array of XSK File
Descriptors (FDs). The number of array elements is typically set or adjusted using
the ``max_entries`` map parameter. For AF_XDP ``max_entries`` is equal to the number
of queues supported by the netdev.
.. note::
Both the map key and map value size must be 4 bytes.
Usage
=====
Kernel BPF
----------
bpf_redirect_map()
^^^^^^^^^^^^^^^^^^
.. code-block:: c
long bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags)
Redirect the packet to the endpoint referenced by ``map`` at index ``key``.
For ``BPF_MAP_TYPE_XSKMAP`` this map contains references to XSK FDs
for sockets attached to a netdev's queues.
.. note::
If the map is empty at an index, the packet is dropped. This means that it is
necessary to have an XDP program loaded with at least one XSK in the
XSKMAP to be able to get any traffic to user space through the socket.
bpf_map_lookup_elem()
^^^^^^^^^^^^^^^^^^^^^
.. code-block:: c
void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)
XSK entry references of type ``struct xdp_sock *`` can be retrieved using the
``bpf_map_lookup_elem()`` helper.
User space
----------
.. note::
XSK entries can only be updated/deleted from user space and not from
a BPF program. Trying to call these functions from a kernel BPF program will
result in the program failing to load and a verifier warning.
bpf_map_update_elem()
^^^^^^^^^^^^^^^^^^^^^
.. code-block:: c
int bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags)
XSK entries can be added or updated using the ``bpf_map_update_elem()``
helper. The ``key`` parameter is equal to the queue_id of the queue the XSK
is attaching to. And the ``value`` parameter is the FD value of that socket.
Under the hood, the XSKMAP update function uses the XSK FD value to retrieve the
associated ``struct xdp_sock`` instance.
The flags argument can be one of the following:
- BPF_ANY: Create a new element or update an existing element.
- BPF_NOEXIST: Create a new element only if it did not exist.
- BPF_EXIST: Update an existing element.
bpf_map_lookup_elem()
^^^^^^^^^^^^^^^^^^^^^
.. code-block:: c
int bpf_map_lookup_elem(int fd, const void *key, void *value)
Returns ``struct xdp_sock *`` or negative error in case of failure.
bpf_map_delete_elem()
^^^^^^^^^^^^^^^^^^^^^
.. code-block:: c
int bpf_map_delete_elem(int fd, const void *key)
XSK entries can be deleted using the ``bpf_map_delete_elem()``
helper. This helper will return 0 on success, or negative error in case of
failure.
.. note::
When `libxdp`_ deletes an XSK it also removes the associated socket
entry from the XSKMAP.
Examples
========
Kernel
------
The following code snippet shows how to declare a ``BPF_MAP_TYPE_XSKMAP`` called
``xsks_map`` and how to redirect packets to an XSK.
.. code-block:: c
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;
}
User space
----------
The following code snippet shows how to update an XSKMAP with an XSK entry.
.. code-block:: c
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;
}
For an example on how create AF_XDP sockets, please see the AF_XDP-example and
AF_XDP-forwarding programs in the `bpf-examples`_ directory in the `libxdp`_ repository.
For a detailed explanation of the AF_XDP interface please see:
- `libxdp-readme`_.
- `AF_XDP`_ kernel documentation.
.. note::
The most comprehensive resource for using XSKMAPs and AF_XDP is `libxdp`_.
.. _libxdp: https://github.com/xdp-project/xdp-tools/tree/master/lib/libxdp
.. _AF_XDP: https://www.kernel.org/doc/html/latest/networking/af_xdp.html
.. _bpf-examples: https://github.com/xdp-project/bpf-examples
.. _libxdp-readme: https://github.com/xdp-project/xdp-tools/tree/master/lib/libxdp#using-af_xdp-sockets
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
XSKMAP과 AF_XDP queue 대응
1-55`BPF_MAP_TYPE_XSKMAP` 문서는 `GPL-2.0-only` 라이선스와 `Copyright (C) 2022 Red Hat, Inc.`를 명시합니다.
`BPF_MAP_TYPE_XSKMAP`은 kernel version 4.18에서 도입되었습니다.
`BPF_MAP_TYPE_XSKMAP`은 `devmap`, `cpumap`처럼 XDP BPF helper `bpf_redirect_map()`과 `XDP_REDIRECT` action의 backend map으로 사용됩니다. 이 map type은 raw XDP frame을 `AF_XDP` socket, 즉 XSK로 redirect합니다.
`AF_XDP`는 frame이 전체 network stack을 거치지 않고 driver에서 user space로 전달되게 하는 kernel address family입니다. AF_XDP socket 하나는 netdev queue 하나에 bind됩니다.
원문의 ASCII 그림을 key, XSK, eth0 queue, 실행 영역의 대응 관계가 드러나는 표로 구조화했습니다. XDP BPF program은 선택한 key를 `bpf_redirect_map()`에 전달하고, XSKMAP은 그 key의 XSK로 frame을 보냅니다.
특정 `<netdev/queue_id>`에 bind된 AF_XDP socket은 그 `<netdev/queue_id>`에서 온 XDP frame만 받습니다. XDP program이 socket의 bind 대상과 다른 `<netdev/queue_id>`에서 redirect하면 해당 frame은 socket에 수신되지 않습니다.
일반적으로 netdev마다 XSKMAP 하나를 만듭니다. 이 map은 XSK File Descriptor(FD)의 array이며, array element 수는 보통 map parameter `max_entries`로 설정하거나 조정합니다. AF_XDP에서 `max_entries`는 netdev가 지원하는 queue 수와 같습니다.
Map key와 map value의 크기는 모두 4 bytes여야 합니다.
Kernel BPF helper
56-84`bpf_redirect_map()`은 `map`의 `key` index가 참조하는 endpoint로 packet을 redirect합니다.
long bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags)
`BPF_MAP_TYPE_XSKMAP`에서 map은 netdev queue에 attach된 socket의 XSK FD reference를 담습니다.
해당 index가 비어 있으면 packet은 drop됩니다. 따라서 socket을 통해 user space traffic을 받으려면 XDP program이 load되어 있고 XSKMAP에 XSK가 최소 하나 들어 있어야 합니다.
Kernel BPF program은 `bpf_map_lookup_elem()` helper로 `struct xdp_sock *` type의 XSK entry reference를 가져올 수 있습니다.
void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)
User space CRUD
85-132XSK entry의 update와 delete는 user space에서만 할 수 있고 BPF program에서는 할 수 없습니다. Kernel BPF program에서 이 function을 호출하려 하면 program load가 실패하고 verifier warning이 발생합니다.
User space의 `bpf_map_update_elem()`은 XSK entry를 추가하거나 갱신합니다.
int bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags)
`key` parameter는 XSK가 attach되는 queue의 `queue_id`이고, `value` parameter는 해당 socket의 FD 값입니다. 내부적으로 XSKMAP update function은 XSK FD 값으로 연결된 `struct xdp_sock` instance를 찾습니다.
`flags` argument는 다음 중 하나입니다.
- `BPF_ANY`: 새 element를 만들거나 기존 element를 갱신합니다.
- `BPF_NOEXIST`: element가 없을 때만 새 element를 만듭니다.
- `BPF_EXIST`: 기존 element를 갱신합니다.
User space의 `bpf_map_lookup_elem()`은 XSKMAP entry를 조회합니다.
int bpf_map_lookup_elem(int fd, const void *key, void *value)
성공하면 `struct xdp_sock *`를 반환하고, 실패하면 negative error를 반환합니다.
`bpf_map_delete_elem()`은 XSK entry를 삭제합니다. 성공하면 0, 실패하면 negative error를 반환합니다.
int bpf_map_delete_elem(int fd, const void *key)
`libxdp`가 XSK를 삭제할 때는 XSKMAP에서 연결된 socket entry도 함께 제거합니다.
Kernel과 user space 예제
133-178다음 kernel code는 `xsks_map`이라는 `BPF_MAP_TYPE_XSKMAP`을 선언하고 packet을 XSK로 redirect하는 방법을 보여 줍니다.
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;
}
Map은 `__u32` key와 value, `max_entries` 64를 사용합니다. `xsk_redir_prog()`는 `ctx->rx_queue_index`를 index로 삼아 entry가 있으면 `bpf_redirect_map(&xsks_map, index, 0)`을 반환하고, entry가 없으면 `XDP_PASS`를 반환합니다.
다음 user space code는 XSK entry로 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;
}
`update_xsks_map()`은 `bpf_map__fd(xsks_map)`과 `queue_id`, `xsk_fd`를 `bpf_map_update_elem()`에 전달합니다. 갱신이 실패하면 `strerror(errno)`로 error를 출력하고 return code를 호출자에게 돌려줍니다.
AF_XDP 예제와 참고 자료
179-192AF_XDP socket 생성 예제는 `libxdp` repository의 `bpf-examples` directory에 있는 AF_XDP-example과 AF_XDP-forwarding program을 참고하십시오.
AF_XDP interface의 자세한 설명은 다음 자료에 있습니다.
- `libxdp-readme`
- `AF_XDP` kernel documentation
XSKMAP과 AF_XDP를 사용하는 방법을 가장 포괄적으로 다루는 자료는 `libxdp`입니다.
- [https://github.com/xdp-project/xdp-tools/tree/master/lib/libxdp](https://github.com/xdp-project/xdp-tools/tree/master/lib/libxdp)
- [https://www.kernel.org/doc/html/latest/networking/af_xdp.html](https://www.kernel.org/doc/html/latest/networking/af_xdp.html)
- [https://github.com/xdp-project/bpf-examples](https://github.com/xdp-project/bpf-examples)
- [https://github.com/xdp-project/xdp-tools/tree/master/lib/libxdp#using-af_xdp-sockets](https://github.com/xdp-project/xdp-tools/tree/master/lib/libxdp#using-af_xdp-sockets)
요약과 해설
map_xskmap.rst:1-192XSKMAP은 XDP program이 raw frame을 user space AF_XDP socket으로 곧바로 전달할 때 사용하는 array map입니다. 각 key는 XSK FD를 가리키며, XSK는 특정 netdev queue 하나에 bind됩니다.
Redirect의 source queue와 XSK가 bind된 queue가 다르면 frame이 socket에 도달하지 않습니다. 따라서 보통 netdev마다 XSKMAP 하나를 만들고 `max_entries`를 netdev queue 수에 맞춥니다.
Kernel BPF에서는 lookup과 redirect를 수행하고, XSK entry의 추가·갱신·삭제는 user space에서만 수행합니다. 빈 index로 redirect하면 packet이 drop된다는 점도 traffic 구성에서 중요합니다.