요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: BSD-3-Clause
=================================================================
Netlink specification support for legacy Generic Netlink families
=================================================================
This document describes the many additional quirks and properties
required to describe older Generic Netlink families which form
the ``genetlink-legacy`` protocol level.
Specification
=============
Globals
-------
Attributes listed directly at the root level of the spec file.
version
~~~~~~~
Generic Netlink family version, default is 1.
``version`` has historically been used to introduce family changes
which may break backwards compatibility. Since compatibility breaking changes
are generally not allowed ``version`` is very rarely used.
Attribute type nests
--------------------
New Netlink families should use ``multi-attr`` to define arrays.
Older families (e.g. ``genetlink`` control family) attempted to
define array types reusing attribute type to carry information.
For reference the ``multi-attr`` array may look like this::
[ARRAY-ATTR]
[INDEX (optionally)]
[MEMBER1]
[MEMBER2]
[SOME-OTHER-ATTR]
[ARRAY-ATTR]
[INDEX (optionally)]
[MEMBER1]
[MEMBER2]
where ``ARRAY-ATTR`` is the array entry type.
indexed-array
~~~~~~~~~~~~~
``indexed-array`` wraps the entire array in an extra attribute (hence
limiting its size to 64kB). The ``ENTRY`` nests are special and have the
index of the entry as their type instead of normal attribute type.
A ``sub-type`` is needed to describe what type in the ``ENTRY``. A ``nest``
``sub-type`` means there are nest arrays in the ``ENTRY``, with the structure
looks like::
[SOME-OTHER-ATTR]
[ARRAY-ATTR]
[ENTRY]
[MEMBER1]
[MEMBER2]
[ENTRY]
[MEMBER1]
[MEMBER2]
Other ``sub-type`` like ``u32`` means there is only one member as described
in ``sub-type`` in the ``ENTRY``. The structure looks like::
[SOME-OTHER-ATTR]
[ARRAY-ATTR]
[ENTRY u32]
[ENTRY u32]
type-value
~~~~~~~~~~
``type-value`` is a construct which uses attribute types to carry
information about a single object (often used when array is dumped
entry-by-entry).
``type-value`` can have multiple levels of nesting, for example
genetlink's policy dumps create the following structures::
[POLICY-IDX]
[ATTR-IDX]
[POLICY-INFO-ATTR1]
[POLICY-INFO-ATTR2]
Where the first level of nest has the policy index as it's attribute
type, it contains a single nest which has the attribute index as its
type. Inside the attr-index nest are the policy attributes. Modern
Netlink families should have instead defined this as a flat structure,
the nesting serves no good purpose here.
Operations
==========
Enum (message ID) model
-----------------------
unified
~~~~~~~
Modern families use the ``unified`` message ID model, which uses
a single enumeration for all messages within family. Requests and
responses share the same message ID. Notifications have separate
IDs from the same space. For example given the following list
of operations:
.. code-block:: yaml
-
name: a
value: 1
do: ...
-
name: b
do: ...
-
name: c
value: 4
notify: a
-
name: d
do: ...
Requests and responses for operation ``a`` will have the ID of 1,
the requests and responses of ``b`` - 2 (since there is no explicit
``value`` it's previous operation ``+ 1``). Notification ``c`` will
use the ID of 4, operation ``d`` 5 etc.
directional
~~~~~~~~~~~
The ``directional`` model splits the ID assignment by the direction of
the message. Messages from and to the kernel can't be confused with
each other so this conserves the ID space (at the cost of making
the programming more cumbersome).
In this case ``value`` attribute should be specified in the ``request``
``reply`` sections of the operations (if an operation has both ``do``
and ``dump`` the IDs are shared, ``value`` should be set in ``do``).
For notifications the ``value`` is provided at the op level but it
only allocates a ``reply`` (i.e. a "from-kernel" ID). Let's look
at an example:
.. code-block:: yaml
-
name: a
do:
request:
value: 2
attributes: ...
reply:
value: 1
attributes: ...
-
name: b
notify: a
-
name: c
notify: a
value: 7
-
name: d
do: ...
In this case ``a`` will use 2 when sending the message to the kernel
and expects message with ID 1 in response. Notification ``b`` allocates
a "from-kernel" ID which is 2. ``c`` allocates "from-kernel" ID of 7.
If operation ``d`` does not set ``values`` explicitly in the spec
it will be allocated 3 for the request (``a`` is the previous operation
with a request section and the value of 2) and 8 for response (``c`` is
the previous operation in the "from-kernel" direction).
Other quirks
============
Structures
----------
Legacy families can define C structures both to be used as the contents of
an attribute and as a fixed message header. Structures are defined in
``definitions`` and referenced in operations or attributes.
members
~~~~~~~
- ``name`` - The attribute name of the struct member
- ``type`` - One of the scalar types ``u8``, ``u16``, ``u32``, ``u64``, ``s8``,
``s16``, ``s32``, ``s64``, ``string``, ``binary`` or ``bitfield32``.
- ``byte-order`` - ``big-endian`` or ``little-endian``
- ``doc``, ``enum``, ``enum-as-flags``, ``display-hint`` - Same as for
:ref:`attribute definitions <attribute_properties>`
Note that structures defined in YAML are implicitly packed according to C
conventions. For example, the following struct is 4 bytes, not 6 bytes:
.. code-block:: c
struct {
u8 a;
u16 b;
u8 c;
}
Any padding must be explicitly added and C-like languages should infer the
need for explicit padding from whether the members are naturally aligned.
Here is the struct definition from above, declared in YAML:
.. code-block:: yaml
definitions:
-
name: message-header
type: struct
members:
-
name: a
type: u8
-
name: b
type: u16
-
name: c
type: u8
Fixed Headers
~~~~~~~~~~~~~
Fixed message headers can be added to operations using ``fixed-header``.
The default ``fixed-header`` can be set in ``operations`` and it can be set
or overridden for each operation.
.. code-block:: yaml
operations:
fixed-header: message-header
list:
-
name: get
fixed-header: custom-header
attribute-set: message-attrs
Attributes
~~~~~~~~~~
A ``binary`` attribute can be interpreted as a C structure using a
``struct`` property with the name of the structure definition. The
``struct`` property implies ``sub-type: struct`` so it is not necessary to
specify a sub-type.
.. code-block:: yaml
attribute-sets:
-
name: stats-attrs
attributes:
-
name: stats
type: binary
struct: vport-stats
C Arrays
--------
Legacy families also use ``binary`` attributes to encapsulate C arrays. The
``sub-type`` is used to identify the type of scalar to extract.
.. code-block:: yaml
attributes:
-
name: ports
type: binary
sub-type: u32
Multi-message DO
----------------
New Netlink families should never respond to a DO operation with multiple
replies, with ``NLM_F_MULTI`` set. Use a filtered dump instead.
At the spec level we can define a ``dumps`` property for the ``do``,
perhaps with values of ``combine`` and ``multi-object`` depending
on how the parsing should be implemented (parse into a single reply
vs list of objects i.e. pretty much a dump).
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
genetlink-legacy와 전역 version
1-27이 문서는 오래된 Generic Netlink family를 기술할 때 필요한 여러 추가 특성과 예외 규칙을 설명합니다. 이 규칙들의 집합이 `genetlink-legacy` protocol level을 이룹니다.
명세 파일의 root에 직접 놓이는 전역 `version`은 Generic Netlink family 버전이며 기본값은 1입니다. 과거에는 하위 호환성을 깨뜨릴 수 있는 family 변경을 도입할 때 쓰였지만, 호환성을 깨는 변경 자체가 일반적으로 허용되지 않으므로 실제 사용은 매우 드뭅니다.
현대 명세에서 거의 쓰지 않는 호환성 정보입니다.
.. SPDX-License-Identifier: BSD-3-Clause
=================================================================
Netlink specification support for legacy Generic Netlink families
=================================================================
This document describes the many additional quirks and properties
required to describe older Generic Netlink families which form
the ``genetlink-legacy`` protocol level.
Specification
=============
Globals
-------
Attributes listed directly at the root level of the spec file.
version
~~~~~~~
Generic Netlink family version, default is 1.
``version`` has historically been used to introduce family changes
which may break backwards compatibility. Since compatibility breaking changes
are generally not allowed ``version`` is very rarely used.
attribute type nest와 indexed-array
28-76새 Netlink family는 배열을 정의할 때 `multi-attr`을 사용해야 합니다. `multi-attr` 배열에서는 같은 `ARRAY-ATTR`이 여러 번 나타나고, 각 항목 안에 선택적인 index와 멤버 attribute가 들어갑니다.
오래된 family는 attribute type 자체에 정보를 싣는 방식으로 배열을 표현했습니다. `indexed-array`는 배열 전체를 한 겹의 추가 attribute로 감싸므로 전체 크기가 64kB로 제한됩니다. 내부 `ENTRY` nest는 일반 attribute type 대신 해당 항목의 index를 type으로 사용합니다.
ENTRY 내부를 해석하는 두 대표 형식입니다.
두 표현은 항목의 반복과 index 전달 위치가 다릅니다.
Attribute type nests
--------------------
New Netlink families should use ``multi-attr`` to define arrays.
Older families (e.g. ``genetlink`` control family) attempted to
define array types reusing attribute type to carry information.
For reference the ``multi-attr`` array may look like this::
[ARRAY-ATTR]
[INDEX (optionally)]
[MEMBER1]
[MEMBER2]
[SOME-OTHER-ATTR]
[ARRAY-ATTR]
[INDEX (optionally)]
[MEMBER1]
[MEMBER2]
where ``ARRAY-ATTR`` is the array entry type.
indexed-array
~~~~~~~~~~~~~
``indexed-array`` wraps the entire array in an extra attribute (hence
limiting its size to 64kB). The ``ENTRY`` nests are special and have the
index of the entry as their type instead of normal attribute type.
A ``sub-type`` is needed to describe what type in the ``ENTRY``. A ``nest``
``sub-type`` means there are nest arrays in the ``ENTRY``, with the structure
looks like::
[SOME-OTHER-ATTR]
[ARRAY-ATTR]
[ENTRY]
[MEMBER1]
[MEMBER2]
[ENTRY]
[MEMBER1]
[MEMBER2]
Other ``sub-type`` like ``u32`` means there is only one member as described
in ``sub-type`` in the ``ENTRY``. The structure looks like::
[SOME-OTHER-ATTR]
[ARRAY-ATTR]
[ENTRY u32]
[ENTRY u32]
type-value 중첩
77-97`type-value`는 단일 객체의 정보를 attribute type에 담는 레거시 구성입니다. 배열을 항목별로 dump하는 family에서 자주 사용되며 여러 단계로 중첩될 수 있습니다.
Generic Netlink policy dump에서는 첫 nest의 type이 policy index이고, 그 안의 단일 nest type이 attribute index이며, 가장 안쪽에 policy attribute가 들어갑니다. 현대 family라면 이를 평평한 구조로 정의해야 하며, 이 사례의 중첩은 유용한 목적이 없는 역사적 형식입니다.
각 중첩 단계에서 attribute type이 데이터 대신 index를 운반합니다.
type-value
~~~~~~~~~~
``type-value`` is a construct which uses attribute types to carry
information about a single object (often used when array is dumped
entry-by-entry).
``type-value`` can have multiple levels of nesting, for example
genetlink's policy dumps create the following structures::
[POLICY-IDX]
[ATTR-IDX]
[POLICY-INFO-ATTR1]
[POLICY-INFO-ATTR2]
Where the first level of nest has the policy index as it's attribute
type, it contains a single nest which has the attribute index as its
type. Inside the attr-index nest are the policy attributes. Modern
Netlink families should have instead defined this as a flat structure,
the nesting serves no good purpose here.
unified 메시지 ID 모델
98-134현대 family의 `unified` 모델은 family 안의 모든 메시지에 하나의 enum 공간을 사용합니다. request와 response는 같은 메시지 ID를 공유하고, notification은 같은 공간에서 별도 ID를 가집니다.
명시적 value가 없으면 바로 앞 operation 값에 1을 더합니다.
이 모델에서는 방향과 관계없이 ID 공간 하나만 따라가면 되므로 프로그래밍이 단순합니다. 단, notification은 request/response와 ID를 공유하지 않고 별도 항목을 할당받습니다.
Operations
==========
Enum (message ID) model
-----------------------
unified
~~~~~~~
Modern families use the ``unified`` message ID model, which uses
a single enumeration for all messages within family. Requests and
responses share the same message ID. Notifications have separate
IDs from the same space. For example given the following list
of operations:
.. code-block:: yaml
-
name: a
value: 1
do: ...
-
name: b
do: ...
-
name: c
value: 4
notify: a
-
name: d
do: ...
Requests and responses for operation ``a`` will have the ID of 1,
the requests and responses of ``b`` - 2 (since there is no explicit
``value`` it's previous operation ``+ 1``). Notification ``c`` will
use the ID of 4, operation ``d`` 5 etc.
directional 메시지 ID 모델
135-179`directional` 모델은 메시지 방향별로 ID 할당을 분리합니다. 커널로 보내는 메시지와 커널에서 오는 메시지는 혼동될 수 없으므로 ID 공간을 절약하지만, request와 reply 번호를 따로 관리해야 해서 프로그래밍이 더 번거롭습니다.
`value`는 operation의 `request` 및 `reply` 구간에 둡니다. 한 operation에 `do`와 `dump`가 모두 있으면 ID를 공유하며 `value`는 `do`에 지정합니다. notification의 `value`는 operation 수준에 있지만 커널에서 오는 `reply` 방향 ID만 할당합니다.
to-kernel과 from-kernel 진행 순서를 별도로 계산합니다.
메시지 방향마다 직전 값을 독립적으로 추적합니다.
directional
~~~~~~~~~~~
The ``directional`` model splits the ID assignment by the direction of
the message. Messages from and to the kernel can't be confused with
each other so this conserves the ID space (at the cost of making
the programming more cumbersome).
In this case ``value`` attribute should be specified in the ``request``
``reply`` sections of the operations (if an operation has both ``do``
and ``dump`` the IDs are shared, ``value`` should be set in ``do``).
For notifications the ``value`` is provided at the op level but it
only allocates a ``reply`` (i.e. a "from-kernel" ID). Let's look
at an example:
.. code-block:: yaml
-
name: a
do:
request:
value: 2
attributes: ...
reply:
value: 1
attributes: ...
-
name: b
notify: a
-
name: c
notify: a
value: 7
-
name: d
do: ...
In this case ``a`` will use 2 when sending the message to the kernel
and expects message with ID 1 in response. Notification ``b`` allocates
a "from-kernel" ID which is 2. ``c`` allocates "from-kernel" ID of 7.
If operation ``d`` does not set ``values`` explicitly in the spec
it will be allocated 3 for the request (``a`` is the previous operation
with a request section and the value of 2) and 8 for response (``c`` is
the previous operation in the "from-kernel" direction).
레거시 C 구조체 정의
180-232레거시 family는 attribute 내용 또는 고정 메시지 헤더로 사용할 C 구조체를 정의할 수 있습니다. 구조체는 `definitions`에 선언하고 operation이나 attribute에서 참조합니다.
YAML member가 C 필드로 변환될 때 사용할 정보입니다.
YAML로 정의한 구조체는 C 관례에 따른 padding 없이 암묵적으로 packed됩니다. 따라서 `u8 a`, `u16 b`, `u8 c` 구조체는 6바이트가 아니라 4바이트입니다. 필요한 padding은 반드시 명시적으로 추가해야 하며, C 계열 언어의 생성기는 member가 자연 정렬되지 않은지를 보고 명시적 padding 필요성을 추론해야 합니다.
YAML 선언 순서 그대로 packed한 크기입니다.
Other quirks
============
Structures
----------
Legacy families can define C structures both to be used as the contents of
an attribute and as a fixed message header. Structures are defined in
``definitions`` and referenced in operations or attributes.
members
~~~~~~~
- ``name`` - The attribute name of the struct member
- ``type`` - One of the scalar types ``u8``, ``u16``, ``u32``, ``u64``, ``s8``,
``s16``, ``s32``, ``s64``, ``string``, ``binary`` or ``bitfield32``.
- ``byte-order`` - ``big-endian`` or ``little-endian``
- ``doc``, ``enum``, ``enum-as-flags``, ``display-hint`` - Same as for
:ref:`attribute definitions <attribute_properties>`
Note that structures defined in YAML are implicitly packed according to C
conventions. For example, the following struct is 4 bytes, not 6 bytes:
.. code-block:: c
struct {
u8 a;
u16 b;
u8 c;
}
Any padding must be explicitly added and C-like languages should infer the
need for explicit padding from whether the members are naturally aligned.
Here is the struct definition from above, declared in YAML:
.. code-block:: yaml
definitions:
-
name: message-header
type: struct
members:
-
name: a
type: u8
-
name: b
type: u16
-
name: c
type: u8
고정 헤더와 struct attribute
233-268operation에 `fixed-header`를 지정하면 고정 메시지 헤더를 추가할 수 있습니다. `operations` 수준에서 기본 헤더를 정하고, 각 operation에서 그대로 사용하거나 다른 구조체 이름으로 덮어쓸 수 있습니다.
예제에서는 기본 `message-header`를 사용하지만 `get` operation은 `custom-header`로 재정의하고 `message-attrs` attribute set을 연결합니다.
바이너리 payload를 명세의 C 구조체로 연결합니다.
Fixed Headers
~~~~~~~~~~~~~
Fixed message headers can be added to operations using ``fixed-header``.
The default ``fixed-header`` can be set in ``operations`` and it can be set
or overridden for each operation.
.. code-block:: yaml
operations:
fixed-header: message-header
list:
-
name: get
fixed-header: custom-header
attribute-set: message-attrs
Attributes
~~~~~~~~~~
A ``binary`` attribute can be interpreted as a C structure using a
``struct`` property with the name of the structure definition. The
``struct`` property implies ``sub-type: struct`` so it is not necessary to
specify a sub-type.
.. code-block:: yaml
attribute-sets:
-
name: stats-attrs
attributes:
-
name: stats
type: binary
struct: vport-stats
C 배열과 다중 reply DO
269-292레거시 family는 `binary` attribute 안에 C 배열도 넣습니다. 이때 `sub-type`이 꺼낼 scalar의 자료형을 지정합니다. 예를 들어 `ports`가 `binary`이고 `sub-type: u32`이면 payload를 `u32` 배열로 해석합니다.
새 Netlink family는 DO operation에 `NLM_F_MULTI`를 설정한 여러 reply로 응답해서는 안 되며, 대신 필터링된 dump를 사용해야 합니다.
명세 수준에서는 기존 동작을 표현하기 위해 `do`에 `dumps` 속성을 둘 수 있습니다. 가능한 의미로 단일 reply에 결합해 파싱하는 `combine`과, 사실상 dump처럼 객체 목록으로 파싱하는 `multi-object`를 구분할 수 있다고 원문은 제안합니다.
새 설계 권장안과 기존 ABI 기술 방식을 구분합니다.
C Arrays
--------
Legacy families also use ``binary`` attributes to encapsulate C arrays. The
``sub-type`` is used to identify the type of scalar to extract.
.. code-block:: yaml
attributes:
-
name: ports
type: binary
sub-type: u32
Multi-message DO
----------------
New Netlink families should never respond to a DO operation with multiple
replies, with ``NLM_F_MULTI`` set. Use a filtered dump instead.
At the spec level we can define a ``dumps`` property for the ``do``,
perhaps with values of ``combine`` and ``multi-object`` depending
on how the parsing should be implemented (parse into a single reply
vs list of objects i.e. pretty much a dump).
요약·해설
genetlink-legacy.rst:1-292레거시 표현은 새 ABI 설계 지침이 아니라 기존 wire format을 정확히 기술하기 위한 호환성 계층입니다. 새 family에서는 `multi-attr`, unified ID, 평평한 구조, filtered dump 같은 현대 형식을 우선해야 합니다.