← Documents Documentation/userspace-api/netlink/genetlink-legacy.rst GitHub 원문 ↗

Linux 6.18.37 · 사용자 공간 API

레거시 Generic Netlink family 명세 지원

오래된 Generic Netlink family를 명세로 표현하기 위한 배열 중첩, 방향별 ID, packed 구조체, 고정 헤더와 다중 응답 예외를 설명합니다.

Source pathDocumentation/userspace-api/netlink/genetlink-legacy.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

genetlink-legacy.rst:1-292

레거시 표현은 새 ABI 설계 지침이 아니라 기존 wire format을 정확히 기술하기 위한 호환성 계층입니다. 새 family에서는 `multi-attr`, unified ID, 평평한 구조, filtered dump 같은 현대 형식을 우선해야 합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: BSD-3-Clause
2
3 =================================================================
4 Netlink specification support for legacy Generic Netlink families
5 =================================================================
6
7 This document describes the many additional quirks and properties
8 required to describe older Generic Netlink families which form
9 the ``genetlink-legacy`` protocol level.
10
11 Specification
12 =============
13
14 Globals
15 -------
16
17 Attributes listed directly at the root level of the spec file.
18
19 version
20 ~~~~~~~
21
22 Generic Netlink family version, default is 1.
23
24 ``version`` has historically been used to introduce family changes
25 which may break backwards compatibility. Since compatibility breaking changes
26 are generally not allowed ``version`` is very rarely used.
27
28 Attribute type nests
29 --------------------
30
31 New Netlink families should use ``multi-attr`` to define arrays.
32 Older families (e.g. ``genetlink`` control family) attempted to
33 define array types reusing attribute type to carry information.
34
35 For reference the ``multi-attr`` array may look like this::
36
37 [ARRAY-ATTR]
38 [INDEX (optionally)]
39 [MEMBER1]
40 [MEMBER2]
41 [SOME-OTHER-ATTR]
42 [ARRAY-ATTR]
43 [INDEX (optionally)]
44 [MEMBER1]
45 [MEMBER2]
46
47 where ``ARRAY-ATTR`` is the array entry type.
48
49 indexed-array
50 ~~~~~~~~~~~~~
51
52 ``indexed-array`` wraps the entire array in an extra attribute (hence
53 limiting its size to 64kB). The ``ENTRY`` nests are special and have the
54 index of the entry as their type instead of normal attribute type.
55
56 A ``sub-type`` is needed to describe what type in the ``ENTRY``. A ``nest``
57 ``sub-type`` means there are nest arrays in the ``ENTRY``, with the structure
58 looks like::
59
60 [SOME-OTHER-ATTR]
61 [ARRAY-ATTR]
62 [ENTRY]
63 [MEMBER1]
64 [MEMBER2]
65 [ENTRY]
66 [MEMBER1]
67 [MEMBER2]
68
69 Other ``sub-type`` like ``u32`` means there is only one member as described
70 in ``sub-type`` in the ``ENTRY``. The structure looks like::
71
72 [SOME-OTHER-ATTR]
73 [ARRAY-ATTR]
74 [ENTRY u32]
75 [ENTRY u32]
76
77 type-value
78 ~~~~~~~~~~
79
80 ``type-value`` is a construct which uses attribute types to carry
81 information about a single object (often used when array is dumped
82 entry-by-entry).
83
84 ``type-value`` can have multiple levels of nesting, for example
85 genetlink's policy dumps create the following structures::
86
87 [POLICY-IDX]
88 [ATTR-IDX]
89 [POLICY-INFO-ATTR1]
90 [POLICY-INFO-ATTR2]
91
92 Where the first level of nest has the policy index as it's attribute
93 type, it contains a single nest which has the attribute index as its
94 type. Inside the attr-index nest are the policy attributes. Modern
95 Netlink families should have instead defined this as a flat structure,
96 the nesting serves no good purpose here.
97
98 Operations
99 ==========
100
101 Enum (message ID) model
102 -----------------------
103
104 unified
105 ~~~~~~~
106
107 Modern families use the ``unified`` message ID model, which uses
108 a single enumeration for all messages within family. Requests and
109 responses share the same message ID. Notifications have separate
110 IDs from the same space. For example given the following list
111 of operations:
112
113 .. code-block:: yaml
114
115 -
116 name: a
117 value: 1
118 do: ...
119 -
120 name: b
121 do: ...
122 -
123 name: c
124 value: 4
125 notify: a
126 -
127 name: d
128 do: ...
129
130 Requests and responses for operation ``a`` will have the ID of 1,
131 the requests and responses of ``b`` - 2 (since there is no explicit
132 ``value`` it's previous operation ``+ 1``). Notification ``c`` will
133 use the ID of 4, operation ``d`` 5 etc.
134
135 directional
136 ~~~~~~~~~~~
137
138 The ``directional`` model splits the ID assignment by the direction of
139 the message. Messages from and to the kernel can't be confused with
140 each other so this conserves the ID space (at the cost of making
141 the programming more cumbersome).
142
143 In this case ``value`` attribute should be specified in the ``request``
144 ``reply`` sections of the operations (if an operation has both ``do``
145 and ``dump`` the IDs are shared, ``value`` should be set in ``do``).
146 For notifications the ``value`` is provided at the op level but it
147 only allocates a ``reply`` (i.e. a "from-kernel" ID). Let's look
148 at an example:
149
150 .. code-block:: yaml
151
152 -
153 name: a
154 do:
155 request:
156 value: 2
157 attributes: ...
158 reply:
159 value: 1
160 attributes: ...
161 -
162 name: b
163 notify: a
164 -
165 name: c
166 notify: a
167 value: 7
168 -
169 name: d
170 do: ...
171
172 In this case ``a`` will use 2 when sending the message to the kernel
173 and expects message with ID 1 in response. Notification ``b`` allocates
174 a "from-kernel" ID which is 2. ``c`` allocates "from-kernel" ID of 7.
175 If operation ``d`` does not set ``values`` explicitly in the spec
176 it will be allocated 3 for the request (``a`` is the previous operation
177 with a request section and the value of 2) and 8 for response (``c`` is
178 the previous operation in the "from-kernel" direction).
179
180 Other quirks
181 ============
182
183 Structures
184 ----------
185
186 Legacy families can define C structures both to be used as the contents of
187 an attribute and as a fixed message header. Structures are defined in
188 ``definitions`` and referenced in operations or attributes.
189
190 members
191 ~~~~~~~
192
193 - ``name`` - The attribute name of the struct member
194 - ``type`` - One of the scalar types ``u8``, ``u16``, ``u32``, ``u64``, ``s8``,
195 ``s16``, ``s32``, ``s64``, ``string``, ``binary`` or ``bitfield32``.
196 - ``byte-order`` - ``big-endian`` or ``little-endian``
197 - ``doc``, ``enum``, ``enum-as-flags``, ``display-hint`` - Same as for
198 :ref:`attribute definitions <attribute_properties>`
199
200 Note that structures defined in YAML are implicitly packed according to C
201 conventions. For example, the following struct is 4 bytes, not 6 bytes:
202
203 .. code-block:: c
204
205 struct {
206 u8 a;
207 u16 b;
208 u8 c;
209 }
210
211 Any padding must be explicitly added and C-like languages should infer the
212 need for explicit padding from whether the members are naturally aligned.
213
214 Here is the struct definition from above, declared in YAML:
215
216 .. code-block:: yaml
217
218 definitions:
219 -
220 name: message-header
221 type: struct
222 members:
223 -
224 name: a
225 type: u8
226 -
227 name: b
228 type: u16
229 -
230 name: c
231 type: u8
232
233 Fixed Headers
234 ~~~~~~~~~~~~~
235
236 Fixed message headers can be added to operations using ``fixed-header``.
237 The default ``fixed-header`` can be set in ``operations`` and it can be set
238 or overridden for each operation.
239
240 .. code-block:: yaml
241
242 operations:
243 fixed-header: message-header
244 list:
245 -
246 name: get
247 fixed-header: custom-header
248 attribute-set: message-attrs
249
250 Attributes
251 ~~~~~~~~~~
252
253 A ``binary`` attribute can be interpreted as a C structure using a
254 ``struct`` property with the name of the structure definition. The
255 ``struct`` property implies ``sub-type: struct`` so it is not necessary to
256 specify a sub-type.
257
258 .. code-block:: yaml
259
260 attribute-sets:
261 -
262 name: stats-attrs
263 attributes:
264 -
265 name: stats
266 type: binary
267 struct: vport-stats
268
269 C Arrays
270 --------
271
272 Legacy families also use ``binary`` attributes to encapsulate C arrays. The
273 ``sub-type`` is used to identify the type of scalar to extract.
274
275 .. code-block:: yaml
276
277 attributes:
278 -
279 name: ports
280 type: binary
281 sub-type: u32
282
283 Multi-message DO
284 ----------------
285
286 New Netlink families should never respond to a DO operation with multiple
287 replies, with ``NLM_F_MULTI`` set. Use a filtered dump instead.
288
289 At the spec level we can define a ``dumps`` property for the ``do``,
290 perhaps with values of ``combine`` and ``multi-object`` depending
291 on how the parsing should be implemented (parse into a single reply
292 vs list of objects i.e. pretty much a dump).
293

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

genetlink-legacy와 전역 version

1-27

이 문서는 오래된 Generic Netlink family를 기술할 때 필요한 여러 추가 특성과 예외 규칙을 설명합니다. 이 규칙들의 집합이 `genetlink-legacy` protocol level을 이룹니다.

명세 파일의 root에 직접 놓이는 전역 `version`은 Generic Netlink family 버전이며 기본값은 1입니다. 과거에는 하위 호환성을 깨뜨릴 수 있는 family 변경을 도입할 때 쓰였지만, 호환성을 깨는 변경 자체가 일반적으로 허용되지 않으므로 실제 사용은 매우 드뭅니다.

레거시 전역 속성
속성기본값주의
`version`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으로 사용합니다.

indexed-array의 sub-type
sub-typeENTRY 내용형태
`nest`여러 member를 가진 중첩 배열`ARRAY-ATTR` -> `ENTRY(index)` -> `MEMBER1`, `MEMBER2`
`u32` 등 scalarsub-type이 설명하는 단일 값`ARRAY-ATTR` -> `ENTRY(index, u32)`

ENTRY 내부를 해석하는 두 대표 형식입니다.

현대 배열과 indexed-array 비교
현대 multi-attr: ARRAY-ATTR 자체를 항목마다 반복필요하면 각 ARRAY-ATTR 내부에 별도 INDEX 배치레거시 indexed-array: 바깥 ARRAY-ATTR 하나로 전체 배열 포장안쪽 ENTRY의 attribute type 값이 항목 index 역할sub-type에 따라 ENTRY를 nest 또는 scalar로 해석

두 표현은 항목의 반복과 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라면 이를 평평한 구조로 정의해야 하며, 이 사례의 중첩은 유용한 목적이 없는 역사적 형식입니다.

policy dump type-value
단계attribute type의 의미내용
1policy indexattribute-index nest 하나
2attribute indexpolicy 정보 attribute들
3정상 attribute ID실제 policy 정보 값

각 중첩 단계에서 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를 가집니다.

unified 예제의 ID 할당
operation종류ID근거
`a`do request/response1`value: 1` 명시
`b`do request/response2이전 operation 1 + 1
`c`notification4`value: 4`, `notify: a`
`d`do request/response5이전 operation 4 + 1

명시적 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만 할당합니다.

directional 예제의 ID
operationto-kernel requestfrom-kernel reply/notification
`a`21
`b` notification없음2, 이전 from-kernel 값 + 1
`c` notification없음7, value 명시
`d`3, 이전 request 2 + 18, 이전 from-kernel 7 + 1

to-kernel과 from-kernel 진행 순서를 별도로 계산합니다.

directional ID 자동 할당
operation의 request와 reply에 명시된 value 확인to-kernel request 공간의 직전 operation 값 추적from-kernel reply 및 notification 공간의 직전 값 추적생략된 value에는 같은 방향의 직전 값 + 1 할당

메시지 방향마다 직전 값을 독립적으로 추적합니다.

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에서 참조합니다.

struct member 속성
속성의미
`name`구조체 member의 attribute 이름
`type``u8`, `u16`, `u32`, `u64`, signed 계열, `string`, `binary`, `bitfield32` 중 하나
`byte-order``big-endian` 또는 `little-endian`
`doc`, `enum`, `enum-as-flags`, `display-hint`attribute 정의와 같은 의미

YAML member가 C 필드로 변환될 때 사용할 정보입니다.

YAML로 정의한 구조체는 C 관례에 따른 padding 없이 암묵적으로 packed됩니다. 따라서 `u8 a`, `u16 b`, `u8 c` 구조체는 6바이트가 아니라 4바이트입니다. 필요한 padding은 반드시 명시적으로 추가해야 하며, C 계열 언어의 생성기는 member가 자연 정렬되지 않은지를 보고 명시적 padding 필요성을 추론해야 합니다.

예제 message-header 배치
membertypeoffset크기
`a``u8`01
`b``u16`12
`c``u8`31
합계packed0-34바이트

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-268

operation에 `fixed-header`를 지정하면 고정 메시지 헤더를 추가할 수 있습니다. `operations` 수준에서 기본 헤더를 정하고, 각 operation에서 그대로 사용하거나 다른 구조체 이름으로 덮어쓸 수 있습니다.

예제에서는 기본 `message-header`를 사용하지만 `get` operation은 `custom-header`로 재정의하고 `message-attrs` attribute set을 연결합니다.

binary attribute의 struct 해석
속성역할
`type: binary`wire상 attribute 내용이 바이트열임을 표시
`struct: vport-stats`해석에 사용할 `definitions` 구조체 이름
암시 규칙`struct`가 있으면 `sub-type: struct`도 암시하므로 별도 지정 불필요

바이너리 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`를 구분할 수 있다고 원문은 제안합니다.

레거시 DO 다중 응답 해석
상황처리
새 family여러 DO reply를 만들지 말고 filtered dump 사용
기존 단일 결과 결합`dumps: combine` 성격으로 하나의 reply로 파싱
기존 객체 목록`dumps: 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).