요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: BSD-3-Clause
=====================================
Using Netlink protocol specifications
=====================================
This document is a quick starting guide for using Netlink protocol
specifications. For more detailed description of the specs see :doc:`specs`.
Simple CLI
==========
Kernel comes with a simple CLI tool which should be useful when
developing Netlink related code. The tool is implemented in Python
and can use a YAML specification to issue Netlink requests
to the kernel.
The tool is located at ``tools/net/ynl/pyynl/cli.py``. It accepts
a handful of arguments, the most important ones are:
- ``--spec`` - point to the spec file
- ``--do $name`` / ``--dump $name`` - issue request ``$name``
- ``--json $attrs`` - provide attributes for the request
- ``--subscribe $group`` - receive notifications from ``$group``
YAML specs can be found under ``Documentation/netlink/specs/``.
Example use::
$ ./tools/net/ynl/pyynl/cli.py --spec Documentation/netlink/specs/ethtool.yaml \
--do rings-get \
--json '{"header":{"dev-index": 18}}'
{'header': {'dev-index': 18, 'dev-name': 'eni1np1'},
'rx': 0,
'rx-jumbo': 0,
'rx-jumbo-max': 4096,
'rx-max': 4096,
'rx-mini': 0,
'rx-mini-max': 4096,
'tx': 0,
'tx-max': 4096,
'tx-push': 0}
The input arguments are parsed as JSON, while the output is only
Python-pretty-printed. This is because some Netlink types can't
be expressed as JSON directly. If such attributes are needed in
the input some hacking of the script will be necessary.
The spec and Netlink internals are factored out as a standalone
library - it should be easy to write Python tools / tests reusing
code from ``cli.py``.
Generating kernel code
======================
``tools/net/ynl/ynl-regen.sh`` scans the kernel tree in search of
auto-generated files which need to be updated. Using this tool is the easiest
way to generate / update auto-generated code.
By default code is re-generated only if spec is newer than the source,
to force regeneration use ``-f``.
``ynl-regen.sh`` searches for ``YNL-GEN`` in the contents of files
(note that it only scans files in the git index, that is only files
tracked by git!) For instance the ``fou_nl.c`` kernel source contains::
/* Documentation/netlink/specs/fou.yaml */
/* YNL-GEN kernel source */
``ynl-regen.sh`` will find this marker and replace the file with
kernel source based on fou.yaml.
The simplest way to generate a new file based on a spec is to add
the two marker lines like above to a file, add that file to git,
and run the regeneration tool. Grep the tree for ``YNL-GEN``
to see other examples.
The code generation itself is performed by ``tools/net/ynl/pyynl/ynl_gen_c.py``
but it takes a few arguments so calling it directly for each file
quickly becomes tedious.
YNL lib
=======
``tools/net/ynl/lib/`` contains an implementation of a C library
(based on libmnl) which integrates with code generated by
``tools/net/ynl/pyynl/ynl_gen_c.py`` to create easy to use netlink wrappers.
YNL basics
----------
The YNL library consists of two parts - the generic code (functions
prefix by ``ynl_``) and per-family auto-generated code (prefixed
with the name of the family).
To create a YNL socket call ynl_sock_create() passing the family
struct (family structs are exported by the auto-generated code).
ynl_sock_destroy() closes the socket.
YNL requests
------------
Steps for issuing YNL requests are best explained on an example.
All the functions and types in this example come from the auto-generated
code (for the netdev family in this case):
.. code-block:: c
// 0. Request and response pointers
struct netdev_dev_get_req *req;
struct netdev_dev_get_rsp *d;
// 1. Allocate a request
req = netdev_dev_get_req_alloc();
// 2. Set request parameters (as needed)
netdev_dev_get_req_set_ifindex(req, ifindex);
// 3. Issues the request
d = netdev_dev_get(ys, req);
// 4. Free the request arguments
netdev_dev_get_req_free(req);
// 5. Error check (the return value from step 3)
if (!d) {
// 6. Print the YNL-generated error
fprintf(stderr, "YNL: %s\n", ys->err.msg);
return -1;
}
// ... do stuff with the response @d
// 7. Free response
netdev_dev_get_rsp_free(d);
YNL dumps
---------
Performing dumps follows similar pattern as requests.
Dumps return a list of objects terminated by a special marker,
or NULL on error. Use ``ynl_dump_foreach()`` to iterate over
the result.
YNL notifications
-----------------
YNL lib supports using the same socket for notifications and
requests. In case notifications arrive during processing of a request
they are queued internally and can be retrieved at a later time.
To subscribed to notifications use ``ynl_subscribe()``.
The notifications have to be read out from the socket,
``ynl_socket_get_fd()`` returns the underlying socket fd which can
be plugged into appropriate asynchronous IO API like ``poll``,
or ``select``.
Notifications can be retrieved using ``ynl_ntf_dequeue()`` and have
to be freed using ``ynl_ntf_free()``. Since we don't know the notification
type upfront the notifications are returned as ``struct ynl_ntf_base_type *``
and user is expected to cast them to the appropriate full type based
on the ``cmd`` member.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
빠른 시작 안내
1-9이 문서는 Netlink 프로토콜 명세를 처음 사용할 때 필요한 빠른 시작 안내입니다. 명세 속성 전체의 상세 정의와 정확한 문법은 `specs` 문서를 참조합니다.
.. SPDX-License-Identifier: BSD-3-Clause
=====================================
Using Netlink protocol specifications
=====================================
This document is a quick starting guide for using Netlink protocol
specifications. For more detailed description of the specs see :doc:`specs`.
간단한 Python CLI
10-52커널 트리에는 Netlink 관련 코드를 개발할 때 쓸 수 있는 간단한 Python CLI가 있습니다. `tools/net/ynl/pyynl/cli.py`는 `Documentation/netlink/specs/` 아래 YAML 명세를 읽어 커널에 Netlink 요청을 보냅니다.
명세 선택, 요청, 입력 attribute, notification 구독을 지정합니다.
예제는 ethtool 명세로 `rings-get`을 실행하면서 device index 18을 JSON 입력으로 전달하고 ring 크기 정보를 출력합니다. 입력은 JSON으로 파싱하지만 출력은 Python pretty-print입니다. 일부 Netlink 자료형은 JSON으로 직접 표현할 수 없으므로 그런 입력이 필요하면 스크립트를 조정해야 합니다.
명세 처리와 Netlink 내부 로직은 독립 라이브러리로 분리되어 있어 `cli.py` 코드를 재사용한 Python 도구나 테스트를 작성하기 쉽습니다.
YAML 명세가 사람이 읽는 인자와 wire message 사이를 연결합니다.
Simple CLI
==========
Kernel comes with a simple CLI tool which should be useful when
developing Netlink related code. The tool is implemented in Python
and can use a YAML specification to issue Netlink requests
to the kernel.
The tool is located at ``tools/net/ynl/pyynl/cli.py``. It accepts
a handful of arguments, the most important ones are:
- ``--spec`` - point to the spec file
- ``--do $name`` / ``--dump $name`` - issue request ``$name``
- ``--json $attrs`` - provide attributes for the request
- ``--subscribe $group`` - receive notifications from ``$group``
YAML specs can be found under ``Documentation/netlink/specs/``.
Example use::
$ ./tools/net/ynl/pyynl/cli.py --spec Documentation/netlink/specs/ethtool.yaml \
--do rings-get \
--json '{"header":{"dev-index": 18}}'
{'header': {'dev-index': 18, 'dev-name': 'eni1np1'},
'rx': 0,
'rx-jumbo': 0,
'rx-jumbo-max': 4096,
'rx-max': 4096,
'rx-mini': 0,
'rx-mini-max': 4096,
'tx': 0,
'tx-max': 4096,
'tx-push': 0}
The input arguments are parsed as JSON, while the output is only
Python-pretty-printed. This is because some Netlink types can't
be expressed as JSON directly. If such attributes are needed in
the input some hacking of the script will be necessary.
The spec and Netlink internals are factored out as a standalone
library - it should be easy to write Python tools / tests reusing
code from ``cli.py``.
커널 코드 재생성
53-81`tools/net/ynl/ynl-regen.sh`는 커널 트리에서 갱신해야 할 자동 생성 파일을 찾아 재생성합니다. 기본적으로 명세가 source보다 새로울 때만 생성하며, `-f`를 주면 강제로 다시 만듭니다.
스크립트는 파일 내용의 `YNL-GEN` 표식을 찾습니다. 단, git index에 들어 있는 추적 파일만 검사합니다. 예를 들어 `fou_nl.c`의 주석은 명세 경로와 `YNL-GEN kernel source` 출력 종류를 지정하고, 재생성 도구는 이 파일을 `fou.yaml` 기반 커널 source로 교체합니다.
표식이 있는 추적 파일을 재생성기가 발견하도록 준비합니다.
실제 C 생성기는 `tools/net/ynl/pyynl/ynl_gen_c.py`이지만 파일마다 여러 인자를 직접 전달하는 작업은 빠르게 번거로워지므로 일반적으로 재생성 스크립트를 사용합니다.
Generating kernel code
======================
``tools/net/ynl/ynl-regen.sh`` scans the kernel tree in search of
auto-generated files which need to be updated. Using this tool is the easiest
way to generate / update auto-generated code.
By default code is re-generated only if spec is newer than the source,
to force regeneration use ``-f``.
``ynl-regen.sh`` searches for ``YNL-GEN`` in the contents of files
(note that it only scans files in the git index, that is only files
tracked by git!) For instance the ``fou_nl.c`` kernel source contains::
/* Documentation/netlink/specs/fou.yaml */
/* YNL-GEN kernel source */
``ynl-regen.sh`` will find this marker and replace the file with
kernel source based on fou.yaml.
The simplest way to generate a new file based on a spec is to add
the two marker lines like above to a file, add that file to git,
and run the regeneration tool. Grep the tree for ``YNL-GEN``
to see other examples.
The code generation itself is performed by ``tools/net/ynl/pyynl/ynl_gen_c.py``
but it takes a few arguments so calling it directly for each file
quickly becomes tedious.
YNL C 라이브러리 기본
82-99`tools/net/ynl/lib/`에는 libmnl 기반 C 라이브러리가 있습니다. `ynl_gen_c.py`가 만든 family별 코드와 결합하여 사용하기 쉬운 Netlink wrapper를 제공합니다.
공통 socket 처리와 family별 형식을 분리합니다.
자동 생성 코드가 내보내는 family 구조체를 `ynl_sock_create()`에 전달해 YNL socket을 만들고, 사용이 끝나면 `ynl_sock_destroy()`로 닫습니다.
YNL lib
=======
``tools/net/ynl/lib/`` contains an implementation of a C library
(based on libmnl) which integrates with code generated by
``tools/net/ynl/pyynl/ynl_gen_c.py`` to create easy to use netlink wrappers.
YNL basics
----------
The YNL library consists of two parts - the generic code (functions
prefix by ``ynl_``) and per-family auto-generated code (prefixed
with the name of the family).
To create a YNL socket call ynl_sock_create() passing the family
struct (family structs are exported by the auto-generated code).
ynl_sock_destroy() closes the socket.
YNL request 수명 주기
100-133예제의 모든 자료형과 함수는 netdev family 명세에서 자동 생성되었습니다. request와 response는 각각 전용 alloc/free 함수를 사용하므로 성공과 실패 경로 모두에서 소유권을 명확히 처리해야 합니다.
생성된 API를 이용한 전체 호출 순서입니다.
각 단계에서 해제해야 하는 객체를 구분합니다.
YNL requests
------------
Steps for issuing YNL requests are best explained on an example.
All the functions and types in this example come from the auto-generated
code (for the netdev family in this case):
.. code-block:: c
// 0. Request and response pointers
struct netdev_dev_get_req *req;
struct netdev_dev_get_rsp *d;
// 1. Allocate a request
req = netdev_dev_get_req_alloc();
// 2. Set request parameters (as needed)
netdev_dev_get_req_set_ifindex(req, ifindex);
// 3. Issues the request
d = netdev_dev_get(ys, req);
// 4. Free the request arguments
netdev_dev_get_req_free(req);
// 5. Error check (the return value from step 3)
if (!d) {
// 6. Print the YNL-generated error
fprintf(stderr, "YNL: %s\n", ys->err.msg);
return -1;
}
// ... do stuff with the response @d
// 7. Free response
netdev_dev_get_rsp_free(d);
YNL dump 순회
134-141dump도 일반 request와 비슷한 패턴을 사용하지만 결과는 여러 객체의 목록입니다. 목록 끝에는 특수 marker가 오며, 오류일 때는 `NULL`을 반환합니다. 결과 항목은 `ynl_dump_foreach()`로 순회합니다.
YNL dumps
---------
Performing dumps follows similar pattern as requests.
Dumps return a list of objects terminated by a special marker,
or NULL on error. Use ``ynl_dump_foreach()`` to iterate over
the result.
YNL notification 처리
142-159YNL 라이브러리는 하나의 socket을 request와 notification에 함께 사용할 수 있습니다. request 처리 중 notification이 도착하면 내부 queue에 보관하고 나중에 꺼낼 수 있습니다.
구독부터 자료형 판별과 해제까지의 흐름입니다.
수신 전에 notification 종류를 알 수 없으므로 반환형은 `struct ynl_ntf_base_type *`입니다. 사용자는 `cmd` member를 검사한 뒤 해당 family의 올바른 전체 notification 자료형으로 변환해야 합니다.
YNL notifications
-----------------
YNL lib supports using the same socket for notifications and
requests. In case notifications arrive during processing of a request
they are queued internally and can be retrieved at a later time.
To subscribed to notifications use ``ynl_subscribe()``.
The notifications have to be read out from the socket,
``ynl_socket_get_fd()`` returns the underlying socket fd which can
be plugged into appropriate asynchronous IO API like ``poll``,
or ``select``.
Notifications can be retrieved using ``ynl_ntf_dequeue()`` and have
to be freed using ``ynl_ntf_free()``. Since we don't know the notification
type upfront the notifications are returned as ``struct ynl_ntf_base_type *``
and user is expected to cast them to the appropriate full type based
on the ``cmd`` member.
요약·해설
intro-specs.rst:1-159하나의 YAML 명세가 대화형 진단 CLI, 커널 자동 생성 코드, 사용자 공간 C wrapper의 공통 계약이 됩니다. 생성된 객체의 alloc/free 짝과 notification의 base-type 판별을 지키는 것이 안전한 사용의 핵심입니다.