Commit 0313afe8 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'tools-ynl-prevent-reorder-and-fix-flags'

Jakub Kicinski says:

====================
tools: ynl: prevent reorder and fix flags

Some codegen improvements for YAML specs.

First, Lorenzon discovered when switching the XDP feature family
to use flags instead of pure enum that the kdoc got garbled.
The support for enum and flags is therefore unified.

Second when regenerating all families we discussed so far I noticed
that some netlink policies jumped around. We need to ensure we don't
render code based on their ordering in a hash.
====================

Link: https://lore.kernel.org/r/20230126000235.1085551-1-kuba@kernel.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 868c82f3 3a43ded0
#!/usr/bin/env python #!/usr/bin/env python
import argparse import argparse
import collections
import jsonschema import jsonschema
import os import os
import yaml import yaml
...@@ -565,6 +566,7 @@ class EnumEntry: ...@@ -565,6 +566,7 @@ class EnumEntry:
self.doc = yaml.get('doc', '') self.doc = yaml.get('doc', '')
self.yaml = yaml self.yaml = yaml
self.enum_set = enum_set
self.c_name = c_upper(enum_set.value_pfx + self.name) self.c_name = c_upper(enum_set.value_pfx + self.name)
if 'value' in yaml: if 'value' in yaml:
...@@ -572,11 +574,14 @@ class EnumEntry: ...@@ -572,11 +574,14 @@ class EnumEntry:
if prev: if prev:
self.value_change = (self.value != prev.value + 1) self.value_change = (self.value != prev.value + 1)
elif prev: elif prev:
self.value_change = False
self.value = prev.value + 1 self.value = prev.value + 1
else: else:
self.value = value_start self.value = value_start
self.value_change = (self.value != 0) self.value_change = (self.value != 0)
self.value_change = self.value_change or self.enum_set['type'] == 'flags'
def __getitem__(self, key): def __getitem__(self, key):
return self.yaml[key] return self.yaml[key]
...@@ -586,6 +591,17 @@ class EnumEntry: ...@@ -586,6 +591,17 @@ class EnumEntry:
def has_doc(self): def has_doc(self):
return bool(self.doc) return bool(self.doc)
# 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
# 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
class EnumSet: class EnumSet:
def __init__(self, family, yaml): def __init__(self, family, yaml):
...@@ -775,8 +791,10 @@ class Family: ...@@ -775,8 +791,10 @@ class Family:
self.mcgrps = self.yaml.get('mcast-groups', {'list': []}) self.mcgrps = self.yaml.get('mcast-groups', {'list': []})
self.consts = dict() self.consts = dict()
self.ops = dict() # list of all operations
self.ops_list = [] self.msg_list = []
# dict of operations which have their own message type (have attributes)
self.ops = collections.OrderedDict()
self.attr_sets = dict() self.attr_sets = dict()
self.attr_sets_list = [] self.attr_sets_list = []
...@@ -824,7 +842,7 @@ class Family: ...@@ -824,7 +842,7 @@ class Family:
def _dictify(self): def _dictify(self):
for elem in self.yaml['definitions']: for elem in self.yaml['definitions']:
if elem['type'] == 'enum': if elem['type'] == 'enum' or elem['type'] == 'flags':
self.consts[elem['name']] = EnumSet(self, elem) self.consts[elem['name']] = EnumSet(self, elem)
else: else:
self.consts[elem['name']] = elem self.consts[elem['name']] = elem
...@@ -843,7 +861,7 @@ class Family: ...@@ -843,7 +861,7 @@ class Family:
op = Operation(self, elem, val) op = Operation(self, elem, val)
val += 1 val += 1
self.ops_list.append((elem['name'], op),) self.msg_list.append(op)
if 'notify' in elem: if 'notify' in elem:
ntf.append(op) ntf.append(op)
continue continue
...@@ -1973,7 +1991,8 @@ def render_uapi(family, cw): ...@@ -1973,7 +1991,8 @@ def render_uapi(family, cw):
defines = [] defines = []
cw.nl() cw.nl()
if const['type'] == 'enum': # Write kdoc for enum and flags (one day maybe also structs)
if const['type'] == 'enum' or const['type'] == 'flags':
enum = family.consts[const['name']] enum = family.consts[const['name']]
if enum.has_doc(): if enum.has_doc():
...@@ -1989,13 +2008,11 @@ def render_uapi(family, cw): ...@@ -1989,13 +2008,11 @@ def render_uapi(family, cw):
cw.p(' */') cw.p(' */')
uapi_enum_start(family, cw, const, 'name') uapi_enum_start(family, cw, const, 'name')
first = True
name_pfx = const.get('name-prefix', f"{family.name}-{const['name']}-") name_pfx = const.get('name-prefix', f"{family.name}-{const['name']}-")
for entry in enum.entry_list: for entry in enum.entry_list:
suffix = ',' suffix = ','
if first and 'value-start' in const: if entry.value_change:
suffix = f" = {const['value-start']}" + suffix suffix = f" = {entry.user_value()}" + suffix
first = False
cw.p(entry.c_name + suffix) cw.p(entry.c_name + suffix)
if const.get('render-max', False): if const.get('render-max', False):
...@@ -2005,17 +2022,6 @@ def render_uapi(family, cw): ...@@ -2005,17 +2022,6 @@ def render_uapi(family, cw):
cw.p(max_name + ' = (__' + max_name + ' - 1)') cw.p(max_name + ' = (__' + max_name + ' - 1)')
cw.block_end(line=';') cw.block_end(line=';')
cw.nl() cw.nl()
elif const['type'] == 'flags':
uapi_enum_start(family, cw, const, 'name')
i = const.get('value-start', 0)
for item in const['entries']:
item_name = item
if 'name-prefix' in const:
item_name = c_upper(const['name-prefix'] + item)
cw.p(f'{item_name} = {1 << i},')
i += 1
cw.block_end(line=';')
cw.nl()
elif const['type'] == 'const': elif const['type'] == 'const':
defines.append([c_upper(family.get('c-define-name', defines.append([c_upper(family.get('c-define-name',
f"{family.name}-{const['name']}")), f"{family.name}-{const['name']}")),
...@@ -2060,7 +2066,7 @@ def render_uapi(family, cw): ...@@ -2060,7 +2066,7 @@ def render_uapi(family, cw):
max_value = f"({cnt_name} - 1)" max_value = f"({cnt_name} - 1)"
uapi_enum_start(family, cw, family['operations'], 'enum-name') uapi_enum_start(family, cw, family['operations'], 'enum-name')
for _, op in family.ops_list: for op in family.msg_list:
if separate_ntf and ('notify' in op or 'event' in op): if separate_ntf and ('notify' in op or 'event' in op):
continue continue
...@@ -2079,7 +2085,7 @@ def render_uapi(family, cw): ...@@ -2079,7 +2085,7 @@ def render_uapi(family, cw):
if separate_ntf: if separate_ntf:
uapi_enum_start(family, cw, family['operations'], enum_name='async-enum') uapi_enum_start(family, cw, family['operations'], enum_name='async-enum')
for _, op in family.ops_list: for op in family.msg_list:
if separate_ntf and not ('notify' in op or 'event' in op): if separate_ntf and not ('notify' in op or 'event' in op):
continue continue
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment