diff options
Diffstat (limited to 'tools/net/ynl')
-rwxr-xr-x | tools/net/ynl/cli.py | 2 | ||||
-rw-r--r-- | tools/net/ynl/lib/__init__.py | 9 | ||||
-rw-r--r-- | tools/net/ynl/lib/nlspec.py | 128 | ||||
-rw-r--r-- | tools/net/ynl/lib/ynl.py | 11 | ||||
-rwxr-xr-x | tools/net/ynl/ynl-gen-c.py | 121 | ||||
-rwxr-xr-x | tools/net/ynl/ynl-regen.sh | 2 |
6 files changed, 157 insertions, 116 deletions
diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py index db410b74d539..ffaa8038aa8c 100755 --- a/tools/net/ynl/cli.py +++ b/tools/net/ynl/cli.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# SPDX-License-Identifier: BSD-3-Clause +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause import argparse import json diff --git a/tools/net/ynl/lib/__init__.py b/tools/net/ynl/lib/__init__.py index 3c73f59eabab..4b3797fe784b 100644 --- a/tools/net/ynl/lib/__init__.py +++ b/tools/net/ynl/lib/__init__.py @@ -1,7 +1,8 @@ -# SPDX-License-Identifier: BSD-3-Clause +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -from .nlspec import SpecAttr, SpecAttrSet, SpecFamily, SpecOperation +from .nlspec import SpecAttr, SpecAttrSet, SpecEnumEntry, SpecEnumSet, \ + SpecFamily, SpecOperation from .ynl import YnlFamily -__all__ = ["SpecAttr", "SpecAttrSet", "SpecFamily", "SpecOperation", - "YnlFamily"] +__all__ = ["SpecAttr", "SpecAttrSet", "SpecEnumEntry", "SpecEnumSet", + "SpecFamily", "SpecOperation", "YnlFamily"] diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index 71da568e2c28..a34d088f6743 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: BSD-3-Clause +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause import collections import importlib @@ -57,6 +57,94 @@ class SpecElement: pass +class SpecEnumEntry(SpecElement): + """ Entry within an enum declared in the Netlink spec. + + Attributes: + doc documentation string + enum_set back reference to the enum + value numerical value of this enum (use accessors in most situations!) + + Methods: + raw_value raw value, i.e. the id in the enum, unlike user value which is a mask for flags + user_value user value, same as raw value for enums, for flags it's the mask + """ + def __init__(self, enum_set, yaml, prev, value_start): + if isinstance(yaml, str): + yaml = {'name': yaml} + super().__init__(enum_set.family, yaml) + + self.doc = yaml.get('doc', '') + self.enum_set = enum_set + + if 'value' in yaml: + self.value = yaml['value'] + elif prev: + self.value = prev.value + 1 + else: + self.value = value_start + + def has_doc(self): + return bool(self.doc) + + def raw_value(self): + return self.value + + def user_value(self): + if self.enum_set['type'] == 'flags': + return 1 << self.value + else: + return self.value + + +class SpecEnumSet(SpecElement): + """ Enum type + + Represents an enumeration (list of numerical constants) + as declared in the "definitions" section of the spec. + + Attributes: + type enum or flags + entries entries by name + entries_by_val entries by value + Methods: + get_mask for flags compute the mask of all defined values + """ + def __init__(self, family, yaml): + super().__init__(family, yaml) + + self.type = yaml['type'] + + prev_entry = None + value_start = self.yaml.get('value-start', 0) + self.entries = dict() + self.entries_by_val = dict() + for entry in self.yaml['entries']: + e = self.new_entry(entry, prev_entry, value_start) + self.entries[e.name] = e + self.entries_by_val[e.raw_value()] = e + prev_entry = e + + def new_entry(self, entry, prev_entry, value_start): + return SpecEnumEntry(self, entry, prev_entry, value_start) + + def has_doc(self): + if 'doc' in self.yaml: + return True + for entry in self.entries.values(): + if entry.has_doc(): + return True + return False + + def get_mask(self): + mask = 0 + idx = self.yaml.get('value-start', 0) + for _ in self.entries.values(): + mask |= 1 << idx + idx += 1 + return mask + + class SpecAttr(SpecElement): """ Single Netlink atttribute type @@ -95,15 +183,22 @@ class SpecAttrSet(SpecElement): self.attrs = collections.OrderedDict() self.attrs_by_val = collections.OrderedDict() - val = 0 - for elem in self.yaml['attributes']: - if 'value' in elem: - val = elem['value'] + if self.subset_of is None: + val = 1 + for elem in self.yaml['attributes']: + if 'value' in elem: + val = elem['value'] - attr = self.new_attr(elem, val) - self.attrs[attr.name] = attr - self.attrs_by_val[attr.value] = attr - val += 1 + attr = self.new_attr(elem, val) + self.attrs[attr.name] = attr + self.attrs_by_val[attr.value] = attr + val += 1 + else: + real_set = family.attr_sets[self.subset_of] + for elem in self.yaml['attributes']: + attr = real_set[elem['name']] + self.attrs[attr.name] = attr + self.attrs_by_val[attr.value] = attr def new_attr(self, elem, value): return SpecAttr(self.family, self, elem, value) @@ -186,6 +281,7 @@ class SpecFamily(SpecElement): msgs dict of all messages (index by name) msgs_by_value dict of all messages (indexed by name) ops dict of all valid requests / responses + consts dict of all constants/enums """ def __init__(self, spec_path, schema_path=None): with open(spec_path, "r") as stream: @@ -215,6 +311,7 @@ class SpecFamily(SpecElement): self.req_by_value = collections.OrderedDict() self.rsp_by_value = collections.OrderedDict() self.ops = collections.OrderedDict() + self.consts = collections.OrderedDict() last_exception = None while len(self._resolution_list) > 0: @@ -235,6 +332,9 @@ class SpecFamily(SpecElement): if len(resolved) == 0: raise last_exception + def new_enum(self, elem): + return SpecEnumSet(self, elem) + def new_attr_set(self, elem): return SpecAttrSet(self, elem) @@ -245,7 +345,7 @@ class SpecFamily(SpecElement): self._resolution_list.append(elem) def _dictify_ops_unified(self): - val = 0 + val = 1 for elem in self.yaml['operations']['list']: if 'value' in elem: val = elem['value'] @@ -256,7 +356,7 @@ class SpecFamily(SpecElement): self.msgs[op.name] = op def _dictify_ops_directional(self): - req_val = rsp_val = 0 + req_val = rsp_val = 1 for elem in self.yaml['operations']['list']: if 'notify' in elem: if 'value' in elem: @@ -289,6 +389,12 @@ class SpecFamily(SpecElement): def resolve(self): self.resolve_up(super()) + for elem in self.yaml['definitions']: + if elem['type'] == 'enum' or elem['type'] == 'flags': + self.consts[elem['name']] = self.new_enum(elem) + else: + self.consts[elem['name']] = elem + for elem in self.yaml['attribute-sets']: attr_set = self.new_attr_set(elem) self.attr_sets[elem['name']] = attr_set diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 1c7411ee04dc..90764a83c646 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: BSD-3-Clause +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause import functools import os @@ -303,11 +303,6 @@ class YnlFamily(SpecFamily): self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_CAP_ACK, 1) self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_EXT_ACK, 1) - self._types = dict() - - for elem in self.yaml.get('definitions', []): - self._types[elem['name']] = elem - self.async_msg_ids = set() self.async_msg_queue = [] @@ -353,13 +348,13 @@ class YnlFamily(SpecFamily): def _decode_enum(self, rsp, attr_spec): raw = rsp[attr_spec['name']] - enum = self._types[attr_spec['enum']] + enum = self.consts[attr_spec['enum']] i = attr_spec.get('value-start', 0) if 'enum-as-flags' in attr_spec and attr_spec['enum-as-flags']: value = set() while raw: if raw & 1: - value.add(enum['entries'][i]) + value.add(enum.entries_by_val[i].name) raw >>= 1 i += 1 else: diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 274e9c566f61..1bcc5354d800 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause import argparse import collections import os import yaml -from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation +from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry def c_upper(name): @@ -566,97 +567,37 @@ class Struct: self.inherited = [c_lower(x) for x in sorted(self._inherited)] -class EnumEntry: +class EnumEntry(SpecEnumEntry): def __init__(self, enum_set, yaml, prev, value_start): - if isinstance(yaml, str): - self.name = yaml - yaml = {} - self.doc = '' - else: - self.name = yaml['name'] - self.doc = yaml.get('doc', '') - - self.yaml = yaml - self.enum_set = enum_set - self.c_name = c_upper(enum_set.value_pfx + self.name) - - if 'value' in yaml: - self.value = yaml['value'] - if prev: - self.value_change = (self.value != prev.value + 1) - elif prev: - self.value_change = False - self.value = prev.value + 1 + super().__init__(enum_set, yaml, prev, value_start) + + if prev: + self.value_change = (self.value != prev.value + 1) else: - self.value = value_start self.value_change = (self.value != 0) - self.value_change = self.value_change or self.enum_set['type'] == 'flags' - def __getitem__(self, key): - return self.yaml[key] - - def __contains__(self, key): - return key in self.yaml - - def has_doc(self): - return bool(self.doc) + # Added by resolve: + self.c_name = None + delattr(self, "c_name") - # raw value, i.e. the id in the enum, unlike user value which is a mask for flags - def raw_value(self): - return self.value + def resolve(self): + self.resolve_up(super()) - # user value, same as raw value for enums, for flags it's the mask - def user_value(self): - if self.enum_set['type'] == 'flags': - return 1 << self.value - else: - return self.value + self.c_name = c_upper(self.enum_set.value_pfx + self.name) -class EnumSet: +class EnumSet(SpecEnumSet): def __init__(self, family, yaml): - self.yaml = yaml - self.family = family - self.render_name = c_lower(family.name + '-' + yaml['name']) self.enum_name = 'enum ' + self.render_name self.value_pfx = yaml.get('name-prefix', f"{family.name}-{yaml['name']}-") - self.type = yaml['type'] - - prev_entry = None - value_start = self.yaml.get('value-start', 0) - self.entries = {} - self.entry_list = [] - for entry in self.yaml['entries']: - e = EnumEntry(self, entry, prev_entry, value_start) - self.entries[e.name] = e - self.entry_list.append(e) - prev_entry = e - - def __getitem__(self, key): - return self.yaml[key] - - def __contains__(self, key): - return key in self.yaml - - def has_doc(self): - if 'doc' in self.yaml: - return True - for entry in self.entry_list: - if entry.has_doc(): - return True - return False + super().__init__(family, yaml) - def get_mask(self): - mask = 0 - idx = self.yaml.get('value-start', 0) - for _ in self.entry_list: - mask |= 1 << idx - idx += 1 - return mask + def new_entry(self, entry, prev_entry, value_start): + return EnumEntry(self, entry, prev_entry, value_start) class AttrSet(SpecAttrSet): @@ -791,8 +732,6 @@ class Family(SpecFamily): self.mcgrps = self.yaml.get('mcast-groups', {'list': []}) - self.consts = dict() - self.hooks = dict() for when in ['pre', 'post']: self.hooks[when] = dict() @@ -819,6 +758,9 @@ class Family(SpecFamily): if self.kernel_policy == 'global': self._load_global_policy() + def new_enum(self, elem): + return EnumSet(self, elem) + def new_attr_set(self, elem): return AttrSet(self, elem) @@ -836,12 +778,6 @@ class Family(SpecFamily): } def _dictify(self): - for elem in self.yaml['definitions']: - if elem['type'] == 'enum' or elem['type'] == 'flags': - self.consts[elem['name']] = EnumSet(self, elem) - else: - self.consts[elem['name']] = elem - ntf = [] for msg in self.msgs.values(): if 'notify' in msg: @@ -1979,7 +1915,7 @@ def render_uapi(family, cw): if 'doc' in enum: doc = ' - ' + enum['doc'] cw.write_doc_line(enum.enum_name + doc) - for entry in enum.entry_list: + for entry in enum.entries.values(): if entry.has_doc(): doc = '@' + entry.c_name + ': ' + entry['doc'] cw.write_doc_line(doc) @@ -1987,7 +1923,7 @@ def render_uapi(family, cw): uapi_enum_start(family, cw, const, 'name') name_pfx = const.get('name-prefix', f"{family.name}-{const['name']}-") - for entry in enum.entry_list: + for entry in enum.entries.values(): suffix = ',' if entry.value_change: suffix = f" = {entry.user_value()}" + suffix @@ -2044,14 +1980,17 @@ def render_uapi(family, cw): max_value = f"({cnt_name} - 1)" uapi_enum_start(family, cw, family['operations'], 'enum-name') + val = 0 for op in family.msgs.values(): if separate_ntf and ('notify' in op or 'event' in op): continue suffix = ',' - if 'value' in op: - suffix = f" = {op['value']}," + if op.value != val: + suffix = f" = {op.value}," + val = op.value cw.p(op.enum_name + suffix) + val += 1 cw.nl() cw.p(cnt_name + ('' if max_by_define else ',')) if not max_by_define: @@ -2124,12 +2063,12 @@ def main(): _, spec_kernel = find_kernel_root(args.spec) if args.mode == 'uapi': - cw.p('/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */') + cw.p('/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause */') else: if args.header: - cw.p('/* SPDX-License-Identifier: BSD-3-Clause */') + cw.p('/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */') else: - cw.p('// SPDX-License-Identifier: BSD-3-Clause') + cw.p('// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause') cw.p("/* Do not edit directly, auto-generated from: */") cw.p(f"/*\t{spec_kernel} */") cw.p(f"/* YNL-GEN {args.mode} {'header' if args.header else 'source'} */") diff --git a/tools/net/ynl/ynl-regen.sh b/tools/net/ynl/ynl-regen.sh index 43989ae48ed0..74f5de1c2399 100755 --- a/tools/net/ynl/ynl-regen.sh +++ b/tools/net/ynl/ynl-regen.sh @@ -1,5 +1,5 @@ #!/bin/bash -# SPDX-License-Identifier: BSD-3-Clause +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause TOOL=$(dirname $(realpath $0))/ynl-gen-c.py |