Skip to content

Commit f036d93

Browse files
donaldhkuba-moo
authored andcommitted
tools: ynl: Add fixed-header support to ynl
Add support for netlink families that add an optional fixed header structure after the genetlink header and before any attributes. The fixed-header can be specified on a per op basis, or once for all operations, which serves as a default value that can be overridden. Signed-off-by: Donald Hunter <donald.hunter@gmail.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 2607191 commit f036d93

File tree

3 files changed

+44
-12
lines changed

3 files changed

+44
-12
lines changed

Documentation/netlink/genetlink-legacy.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,14 @@ properties:
261261
async-enum:
262262
description: Name for the enum type with notifications/events.
263263
type: string
264+
# Start genetlink-legacy
265+
fixed-header: &fixed-header
266+
description: |
267+
Name of the structure defining the optional fixed-length protocol
268+
header. This header is placed in a message after the netlink and
269+
genetlink headers and before any attributes.
270+
type: string
271+
# End genetlink-legacy
264272
list:
265273
description: List of commands
266274
type: array
@@ -293,6 +301,9 @@ properties:
293301
type: array
294302
items:
295303
enum: [ strict, dump ]
304+
# Start genetlink-legacy
305+
fixed-header: *fixed-header
306+
# End genetlink-legacy
296307
do: &subop-type
297308
description: Main command handler.
298309
type: object

tools/net/ynl/lib/nlspec.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -263,16 +263,17 @@ class SpecOperation(SpecElement):
263263
Information about a single Netlink operation.
264264
265265
Attributes:
266-
value numerical ID when serialized, None if req/rsp values differ
266+
value numerical ID when serialized, None if req/rsp values differ
267267
268-
req_value numerical ID when serialized, user -> kernel
269-
rsp_value numerical ID when serialized, user <- kernel
270-
is_call bool, whether the operation is a call
271-
is_async bool, whether the operation is a notification
272-
is_resv bool, whether the operation does not exist (it's just a reserved ID)
273-
attr_set attribute set name
268+
req_value numerical ID when serialized, user -> kernel
269+
rsp_value numerical ID when serialized, user <- kernel
270+
is_call bool, whether the operation is a call
271+
is_async bool, whether the operation is a notification
272+
is_resv bool, whether the operation does not exist (it's just a reserved ID)
273+
attr_set attribute set name
274+
fixed_header string, optional name of fixed header struct
274275
275-
yaml raw spec as loaded from the spec file
276+
yaml raw spec as loaded from the spec file
276277
"""
277278
def __init__(self, family, yaml, req_value, rsp_value):
278279
super().__init__(family, yaml)
@@ -284,6 +285,7 @@ def __init__(self, family, yaml, req_value, rsp_value):
284285
self.is_call = 'do' in yaml or 'dump' in yaml
285286
self.is_async = 'notify' in yaml or 'event' in yaml
286287
self.is_resv = not self.is_async and not self.is_call
288+
self.fixed_header = self.yaml.get('fixed-header', family.fixed_header)
287289

288290
# Added by resolve:
289291
self.attr_set = None
@@ -324,6 +326,7 @@ class SpecFamily(SpecElement):
324326
msgs_by_value dict of all messages (indexed by name)
325327
ops dict of all valid requests / responses
326328
consts dict of all constants/enums
329+
fixed_header string, optional name of family default fixed header struct
327330
"""
328331
def __init__(self, spec_path, schema_path=None):
329332
with open(spec_path, "r") as stream:
@@ -397,6 +400,7 @@ def add_unresolved(self, elem):
397400
self._resolution_list.append(elem)
398401

399402
def _dictify_ops_unified(self):
403+
self.fixed_header = self.yaml['operations'].get('fixed-header')
400404
val = 1
401405
for elem in self.yaml['operations']['list']:
402406
if 'value' in elem:
@@ -408,6 +412,7 @@ def _dictify_ops_unified(self):
408412
self.msgs[op.name] = op
409413

410414
def _dictify_ops_directional(self):
415+
self.fixed_header = self.yaml['operations'].get('fixed-header')
411416
req_val = rsp_val = 1
412417
for elem in self.yaml['operations']['list']:
413418
if 'notify' in elem:

tools/net/ynl/lib/ynl.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -278,14 +278,22 @@ def _genl_load_families():
278278

279279

280280
class GenlMsg:
281-
def __init__(self, nl_msg):
281+
def __init__(self, nl_msg, fixed_header_members=[]):
282282
self.nl = nl_msg
283283

284284
self.hdr = nl_msg.raw[0:4]
285-
self.raw = nl_msg.raw[4:]
285+
offset = 4
286286

287287
self.genl_cmd, self.genl_version, _ = struct.unpack("BBH", self.hdr)
288288

289+
self.fixed_header_attrs = dict()
290+
for m in fixed_header_members:
291+
format, size = NlAttr.type_formats[m.type]
292+
decoded = struct.unpack_from(format, nl_msg.raw, offset)
293+
offset += size
294+
self.fixed_header_attrs[m.name] = decoded[0]
295+
296+
self.raw = nl_msg.raw[offset:]
289297
self.raw_attrs = NlAttrs(self.raw)
290298

291299
def __repr__(self):
@@ -509,6 +517,13 @@ def _op(self, method, vals, dump=False):
509517

510518
req_seq = random.randint(1024, 65535)
511519
msg = _genl_msg(self.family.family_id, nl_flags, op.req_value, 1, req_seq)
520+
fixed_header_members = []
521+
if op.fixed_header:
522+
fixed_header_members = self.consts[op.fixed_header].members
523+
for m in fixed_header_members:
524+
value = vals.pop(m.name)
525+
format, _ = NlAttr.type_formats[m.type]
526+
msg += struct.pack(format, value)
512527
for name, value in vals.items():
513528
msg += self._add_attr(op.attr_set.name, name, value)
514529
msg = _genl_msg_finalize(msg)
@@ -535,7 +550,7 @@ def _op(self, method, vals, dump=False):
535550
done = True
536551
break
537552

538-
gm = GenlMsg(nl_msg)
553+
gm = GenlMsg(nl_msg, fixed_header_members)
539554
# Check if this is a reply to our request
540555
if nl_msg.nl_seq != req_seq or gm.genl_cmd != op.rsp_value:
541556
if gm.genl_cmd in self.async_msg_ids:
@@ -545,7 +560,8 @@ def _op(self, method, vals, dump=False):
545560
print('Unexpected message: ' + repr(gm))
546561
continue
547562

548-
rsp.append(self._decode(gm.raw_attrs, op.attr_set.name))
563+
rsp.append(self._decode(gm.raw_attrs, op.attr_set.name)
564+
| gm.fixed_header_attrs)
549565

550566
if not rsp:
551567
return None

0 commit comments

Comments
 (0)