요약·해설과 원문, 전문 번역을 서로 분리했습니다. 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_QUEUE and BPF_MAP_TYPE_STACK
=========================================
.. note::
- ``BPF_MAP_TYPE_QUEUE`` and ``BPF_MAP_TYPE_STACK`` were introduced
in kernel version 4.20
``BPF_MAP_TYPE_QUEUE`` provides FIFO storage and ``BPF_MAP_TYPE_STACK``
provides LIFO storage for BPF programs. These maps support peek, pop and
push operations that are exposed to BPF programs through the respective
helpers. These operations are exposed to userspace applications using
the existing ``bpf`` syscall in the following way:
- ``BPF_MAP_LOOKUP_ELEM`` -> peek
- ``BPF_MAP_LOOKUP_AND_DELETE_ELEM`` -> pop
- ``BPF_MAP_UPDATE_ELEM`` -> push
``BPF_MAP_TYPE_QUEUE`` and ``BPF_MAP_TYPE_STACK`` do not support
``BPF_F_NO_PREALLOC``.
Usage
=====
Kernel BPF
----------
bpf_map_push_elem()
~~~~~~~~~~~~~~~~~~~
.. code-block:: c
long bpf_map_push_elem(struct bpf_map *map, const void *value, u64 flags)
An element ``value`` can be added to a queue or stack using the
``bpf_map_push_elem`` helper. The ``flags`` parameter must be set to
``BPF_ANY`` or ``BPF_EXIST``. If ``flags`` is set to ``BPF_EXIST`` then,
when the queue or stack is full, the oldest element will be removed to
make room for ``value`` to be added. Returns ``0`` on success, or
negative error in case of failure.
bpf_map_peek_elem()
~~~~~~~~~~~~~~~~~~~
.. code-block:: c
long bpf_map_peek_elem(struct bpf_map *map, void *value)
This helper fetches an element ``value`` from a queue or stack without
removing it. Returns ``0`` on success, or negative error in case of
failure.
bpf_map_pop_elem()
~~~~~~~~~~~~~~~~~~
.. code-block:: c
long bpf_map_pop_elem(struct bpf_map *map, void *value)
This helper removes an element into ``value`` from a queue or
stack. Returns ``0`` on success, or negative error in case of failure.
Userspace
---------
bpf_map_update_elem()
~~~~~~~~~~~~~~~~~~~~~
.. code-block:: c
int bpf_map_update_elem (int fd, const void *key, const void *value, __u64 flags)
A userspace program can push ``value`` onto a queue or stack using libbpf's
``bpf_map_update_elem`` function. The ``key`` parameter must be set to
``NULL`` and ``flags`` must be set to ``BPF_ANY`` or ``BPF_EXIST``, with the
same semantics as the ``bpf_map_push_elem`` kernel helper. Returns ``0`` on
success, or negative error in case of failure.
bpf_map_lookup_elem()
~~~~~~~~~~~~~~~~~~~~~
.. code-block:: c
int bpf_map_lookup_elem (int fd, const void *key, void *value)
A userspace program can peek at the ``value`` at the head of a queue or stack
using the libbpf ``bpf_map_lookup_elem`` function. The ``key`` parameter must be
set to ``NULL``. Returns ``0`` on success, or negative error in case of
failure.
bpf_map_lookup_and_delete_elem()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: c
int bpf_map_lookup_and_delete_elem (int fd, const void *key, void *value)
A userspace program can pop a ``value`` from the head of a queue or stack using
the libbpf ``bpf_map_lookup_and_delete_elem`` function. The ``key`` parameter
must be set to ``NULL``. Returns ``0`` on success, or negative error in case of
failure.
Examples
========
Kernel BPF
----------
This snippet shows how to declare a queue in a BPF program:
.. code-block:: c
struct {
__uint(type, BPF_MAP_TYPE_QUEUE);
__type(value, __u32);
__uint(max_entries, 10);
} queue SEC(".maps");
Userspace
---------
This snippet shows how to use libbpf's low-level API to create a queue from
userspace:
.. code-block:: c
int create_queue()
{
return bpf_map_create(BPF_MAP_TYPE_QUEUE,
"sample_queue", /* name */
0, /* key size, must be zero */
sizeof(__u32), /* value size */
10, /* max entries */
NULL); /* create options */
}
References
==========
https://lwn.net/ml/netdev/153986858555.9127.14517764371945179514.stgit@kernel/
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
FIFO queue와 LIFO stack 동작
1-24`BPF_MAP_TYPE_QUEUE`와 `BPF_MAP_TYPE_STACK` 문서는 `GPL-2.0-only` 라이선스와 `Copyright (C) 2022 Red Hat, Inc.`를 명시합니다.
`BPF_MAP_TYPE_QUEUE`와 `BPF_MAP_TYPE_STACK`은 `kernel version 4.20`에 도입되었습니다.
`BPF_MAP_TYPE_QUEUE`는 FIFO storage를, `BPF_MAP_TYPE_STACK`은 LIFO storage를 BPF program에 제공합니다. 두 map은 helper로 노출되는 peek, pop, push operation을 지원합니다.
Userspace application에서는 기존 `bpf` syscall operation이 다음 queue/stack operation에 대응합니다.
- `BPF_MAP_LOOKUP_ELEM`은 peek에 대응합니다.
- `BPF_MAP_LOOKUP_AND_DELETE_ELEM`은 pop에 대응합니다.
- `BPF_MAP_UPDATE_ELEM`은 push에 대응합니다.
`BPF_MAP_TYPE_QUEUE`와 `BPF_MAP_TYPE_STACK`은 `BPF_F_NO_PREALLOC`을 지원하지 않습니다.
Kernel BPF push, peek, pop helper
25-66Queue 또는 stack에 element `value`를 추가할 때는 다음 `bpf_map_push_elem()` helper를 사용합니다.
long bpf_map_push_elem(struct bpf_map *map, const void *value, u64 flags)
`flags`는 `BPF_ANY` 또는 `BPF_EXIST`여야 합니다. `BPF_EXIST`를 지정하고 queue나 stack이 가득 차면 가장 오래된 element를 제거해 새 `value` 공간을 만듭니다. 성공하면 0, 실패하면 negative error를 반환합니다.
Element를 제거하지 않고 가져올 때는 다음 `bpf_map_peek_elem()` helper를 사용합니다.
long bpf_map_peek_elem(struct bpf_map *map, void *value)
Peek은 성공하면 value를 출력하고 0을 반환하며 실패하면 negative error를 반환합니다.
Element를 제거하면서 가져올 때는 다음 `bpf_map_pop_elem()` helper를 사용합니다.
long bpf_map_pop_elem(struct bpf_map *map, void *value)
Pop은 제거한 element를 `value`에 저장하고 성공하면 0, 실패하면 negative error를 반환합니다.
Userspace push, peek, pop API
67-106Userspace에서 queue 또는 stack에 `value`를 push할 때는 libbpf의 다음 `bpf_map_update_elem()` function을 사용합니다.
int bpf_map_update_elem (int fd, const void *key, const void *value, __u64 flags)
`key`는 반드시 `NULL`, `flags`는 `BPF_ANY` 또는 `BPF_EXIST`여야 하며 kernel `bpf_map_push_elem()` helper와 같은 semantics를 가집니다. 성공하면 0, 실패하면 negative error를 반환합니다.
Head의 value를 제거하지 않고 볼 때는 다음 `bpf_map_lookup_elem()` function을 사용합니다.
int bpf_map_lookup_elem (int fd, const void *key, void *value)
Peek에서도 `key`는 반드시 `NULL`이어야 합니다. 성공하면 0, 실패하면 negative error를 반환합니다.
Head의 value를 pop할 때는 다음 `bpf_map_lookup_and_delete_elem()` function을 사용합니다.
int bpf_map_lookup_and_delete_elem (int fd, const void *key, void *value)
Pop에서도 `key`는 반드시 `NULL`이어야 합니다. 성공하면 0, 실패하면 negative error를 반환합니다.
Kernel BPF queue 선언
107-123다음 BPF code는 `__u32` value를 최대 10개 저장하는 `BPF_MAP_TYPE_QUEUE` `queue`를 선언합니다. Queue와 stack은 key가 없으므로 key type을 선언하지 않습니다.
struct {
__uint(type, BPF_MAP_TYPE_QUEUE);
__type(value, __u32);
__uint(max_entries, 10);
} queue SEC(".maps");
Userspace queue 생성과 참고 자료
124-146다음 code는 libbpf low-level API로 userspace에서 queue를 만듭니다.
int create_queue()
{
return bpf_map_create(BPF_MAP_TYPE_QUEUE,
"sample_queue", /* name */
0, /* key size, must be zero */
sizeof(__u32), /* value size */
10, /* max entries */
NULL); /* create options */
}
`bpf_map_create()`에 `BPF_MAP_TYPE_QUEUE`, map name, 반드시 0인 key size, `__u32` value size, max entries 10, create option을 전달합니다.
[Queue/stack map patch discussion](https://lwn.net/ml/netdev/153986858555.9127.14517764371945179514.stgit@kernel/)에서 도입 배경을 확인할 수 있습니다.
요약과 해설
map_queue_stack.rst:1-146Queue map은 FIFO, stack map은 LIFO 순서로 key 없는 value를 저장합니다. Kernel과 userspace 모두 push, peek, pop operation을 제공하지만 API 이름은 서로 다릅니다.
`BPF_EXIST` push는 container가 가득 찼을 때 가장 오래된 element를 제거해 새 value를 넣습니다. Userspace API에서는 모든 operation의 key를 `NULL`로 지정해야 합니다.
두 map type은 pre-allocation을 전제로 하므로 `BPF_F_NO_PREALLOC`을 사용할 수 없고 map 생성 시 key size는 0이어야 합니다.