Skip to content

Commit 1769e2b

Browse files
donaldhkuba-moo
authored andcommitted
tools/net/ynl: Add 'sub-message' attribute decoding to ynl
Implement the 'sub-message' attribute type in ynl. Encode support is not yet implemented. Support for sub-message selectors at a different nest level from the key attribute is not yet supported. Reviewed-by: Jakub Kicinski <[email protected]> Signed-off-by: Donald Hunter <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 17ed5c1 commit 1769e2b

File tree

2 files changed

+95
-8
lines changed

2 files changed

+95
-8
lines changed

tools/net/ynl/lib/nlspec.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ class SpecAttr(SpecElement):
158158
len integer, optional byte length of binary types
159159
display_hint string, hint to help choose format specifier
160160
when displaying the value
161+
sub_message string, name of sub message type
162+
selector string, name of attribute used to select
163+
sub-message type
161164
162165
is_auto_scalar bool, attr is a variable-size scalar
163166
"""
@@ -173,6 +176,8 @@ def __init__(self, family, attr_set, yaml, value):
173176
self.byte_order = yaml.get('byte-order')
174177
self.len = yaml.get('len')
175178
self.display_hint = yaml.get('display-hint')
179+
self.sub_message = yaml.get('sub-message')
180+
self.selector = yaml.get('selector')
176181

177182
self.is_auto_scalar = self.type == "sint" or self.type == "uint"
178183

@@ -278,6 +283,47 @@ def items(self):
278283
return self.members.items()
279284

280285

286+
class SpecSubMessage(SpecElement):
287+
""" Netlink sub-message definition
288+
289+
Represents a set of sub-message formats for polymorphic nlattrs
290+
that contain type-specific sub messages.
291+
292+
Attributes:
293+
name string, name of sub-message definition
294+
formats dict of sub-message formats indexed by match value
295+
"""
296+
def __init__(self, family, yaml):
297+
super().__init__(family, yaml)
298+
299+
self.formats = collections.OrderedDict()
300+
for elem in self.yaml['formats']:
301+
format = self.new_format(family, elem)
302+
self.formats[format.value] = format
303+
304+
def new_format(self, family, format):
305+
return SpecSubMessageFormat(family, format)
306+
307+
308+
class SpecSubMessageFormat(SpecElement):
309+
""" Netlink sub-message definition
310+
311+
Represents a set of sub-message formats for polymorphic nlattrs
312+
that contain type-specific sub messages.
313+
314+
Attributes:
315+
value attribute value to match against type selector
316+
fixed_header string, name of fixed header, or None
317+
attr_set string, name of attribute set, or None
318+
"""
319+
def __init__(self, family, yaml):
320+
super().__init__(family, yaml)
321+
322+
self.value = yaml.get('value')
323+
self.fixed_header = yaml.get('fixed-header')
324+
self.attr_set = yaml.get('attribute-set')
325+
326+
281327
class SpecOperation(SpecElement):
282328
"""Netlink Operation
283329
@@ -365,6 +411,7 @@ class SpecFamily(SpecElement):
365411
366412
attr_sets dict of attribute sets
367413
msgs dict of all messages (index by name)
414+
sub_msgs dict of all sub messages (index by name)
368415
ops dict of all valid requests / responses
369416
ntfs dict of all async events
370417
consts dict of all constants/enums
@@ -405,6 +452,7 @@ def __init__(self, spec_path, schema_path=None, exclude_ops=None):
405452
jsonschema.validate(self.yaml, schema)
406453

407454
self.attr_sets = collections.OrderedDict()
455+
self.sub_msgs = collections.OrderedDict()
408456
self.msgs = collections.OrderedDict()
409457
self.req_by_value = collections.OrderedDict()
410458
self.rsp_by_value = collections.OrderedDict()
@@ -441,6 +489,9 @@ def new_attr_set(self, elem):
441489
def new_struct(self, elem):
442490
return SpecStruct(self, elem)
443491

492+
def new_sub_message(self, elem):
493+
return SpecSubMessage(self, elem);
494+
444495
def new_operation(self, elem, req_val, rsp_val):
445496
return SpecOperation(self, elem, req_val, rsp_val)
446497

@@ -529,6 +580,10 @@ def resolve(self):
529580
attr_set = self.new_attr_set(elem)
530581
self.attr_sets[elem['name']] = attr_set
531582

583+
for elem in self.yaml.get('sub-messages', []):
584+
sub_message = self.new_sub_message(elem)
585+
self.sub_msgs[sub_message.name] = sub_message
586+
532587
if self.msg_id_model == 'unified':
533588
self._dictify_ops_unified()
534589
elif self.msg_id_model == 'directional':

tools/net/ynl/lib/ynl.py

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,9 @@ def __repr__(self):
170170

171171

172172
class NlAttrs:
173-
def __init__(self, msg):
173+
def __init__(self, msg, offset=0):
174174
self.attrs = []
175175

176-
offset = 0
177176
while offset < len(msg):
178177
attr = NlAttr(msg, offset)
179178
offset += attr.full_len
@@ -371,8 +370,8 @@ def decode(self, ynl, nl_msg):
371370
fixed_header_size = 0
372371
if ynl:
373372
op = ynl.rsp_by_value[msg.cmd()]
374-
fixed_header_size = ynl._fixed_header_size(op)
375-
msg.raw_attrs = NlAttrs(msg.raw[fixed_header_size:])
373+
fixed_header_size = ynl._fixed_header_size(op.fixed_header)
374+
msg.raw_attrs = NlAttrs(msg.raw, fixed_header_size)
376375
return msg
377376

378377
def get_mcast_id(self, mcast_name, mcast_groups):
@@ -549,6 +548,37 @@ def _rsp_add(self, rsp, name, is_multi, decoded):
549548
else:
550549
rsp[name] = [decoded]
551550

551+
def _resolve_selector(self, attr_spec, vals):
552+
sub_msg = attr_spec.sub_message
553+
if sub_msg not in self.sub_msgs:
554+
raise Exception(f"No sub-message spec named {sub_msg} for {attr_spec.name}")
555+
sub_msg_spec = self.sub_msgs[sub_msg]
556+
557+
selector = attr_spec.selector
558+
if selector not in vals:
559+
raise Exception(f"There is no value for {selector} to resolve '{attr_spec.name}'")
560+
value = vals[selector]
561+
if value not in sub_msg_spec.formats:
562+
raise Exception(f"No message format for '{value}' in sub-message spec '{sub_msg}'")
563+
564+
spec = sub_msg_spec.formats[value]
565+
return spec
566+
567+
def _decode_sub_msg(self, attr, attr_spec, rsp):
568+
msg_format = self._resolve_selector(attr_spec, rsp)
569+
decoded = {}
570+
offset = 0
571+
if msg_format.fixed_header:
572+
decoded.update(self._decode_fixed_header(attr, msg_format.fixed_header));
573+
offset = self._fixed_header_size(msg_format.fixed_header)
574+
if msg_format.attr_set:
575+
if msg_format.attr_set in self.attr_sets:
576+
subdict = self._decode(NlAttrs(attr.raw, offset), msg_format.attr_set)
577+
decoded.update(subdict)
578+
else:
579+
raise Exception(f"Unknown attribute-set '{attr_space}' when decoding '{attr_spec.name}'")
580+
return decoded
581+
552582
def _decode(self, attrs, space):
553583
if space:
554584
attr_space = self.attr_sets[space]
@@ -586,6 +616,8 @@ def _decode(self, attrs, space):
586616
value = self._decode_enum(value, attr_spec)
587617
selector = self._decode_enum(selector, attr_spec)
588618
decoded = {"value": value, "selector": selector}
619+
elif attr_spec["type"] == 'sub-message':
620+
decoded = self._decode_sub_msg(attr, attr_spec, rsp)
589621
else:
590622
if not self.process_unknown:
591623
raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}')
@@ -626,16 +658,16 @@ def _decode_extack(self, request, op, extack):
626658
return
627659

628660
msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set))
629-
offset = 20 + self._fixed_header_size(op)
661+
offset = 20 + self._fixed_header_size(op.fixed_header)
630662
path = self._decode_extack_path(msg.raw_attrs, op.attr_set, offset,
631663
extack['bad-attr-offs'])
632664
if path:
633665
del extack['bad-attr-offs']
634666
extack['bad-attr'] = path
635667

636-
def _fixed_header_size(self, op):
637-
if op.fixed_header:
638-
fixed_header_members = self.consts[op.fixed_header].members
668+
def _fixed_header_size(self, name):
669+
if name:
670+
fixed_header_members = self.consts[name].members
639671
size = 0
640672
for m in fixed_header_members:
641673
format = NlAttr.get_format(m.type, m.byte_order)

0 commit comments

Comments
 (0)