Skip to content

Commit 6517a60

Browse files
committed
tools: ynl: move the enum classes to shared code
Move bulk of the EnumSet and EnumEntry code to shared code for reuse by cli. Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 649c15c commit 6517a60

File tree

3 files changed

+121
-89
lines changed

3 files changed

+121
-89
lines changed

tools/net/ynl/lib/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
22

3-
from .nlspec import SpecAttr, SpecAttrSet, SpecFamily, SpecOperation
3+
from .nlspec import SpecAttr, SpecAttrSet, SpecEnumEntry, SpecEnumSet, \
4+
SpecFamily, SpecOperation
45
from .ynl import YnlFamily
56

6-
__all__ = ["SpecAttr", "SpecAttrSet", "SpecFamily", "SpecOperation",
7-
"YnlFamily"]
7+
__all__ = ["SpecAttr", "SpecAttrSet", "SpecEnumEntry", "SpecEnumSet",
8+
"SpecFamily", "SpecOperation", "YnlFamily"]

tools/net/ynl/lib/nlspec.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,91 @@ def resolve(self):
5757
pass
5858

5959

60+
class SpecEnumEntry(SpecElement):
61+
""" Entry within an enum declared in the Netlink spec.
62+
63+
Attributes:
64+
doc documentation string
65+
enum_set back reference to the enum
66+
value numerical value of this enum (use accessors in most situations!)
67+
68+
Methods:
69+
raw_value raw value, i.e. the id in the enum, unlike user value which is a mask for flags
70+
user_value user value, same as raw value for enums, for flags it's the mask
71+
"""
72+
def __init__(self, enum_set, yaml, prev, value_start):
73+
if isinstance(yaml, str):
74+
yaml = {'name': yaml}
75+
super().__init__(enum_set.family, yaml)
76+
77+
self.doc = yaml.get('doc', '')
78+
self.enum_set = enum_set
79+
80+
if 'value' in yaml:
81+
self.value = yaml['value']
82+
elif prev:
83+
self.value = prev.value + 1
84+
else:
85+
self.value = value_start
86+
87+
def has_doc(self):
88+
return bool(self.doc)
89+
90+
def raw_value(self):
91+
return self.value
92+
93+
def user_value(self):
94+
if self.enum_set['type'] == 'flags':
95+
return 1 << self.value
96+
else:
97+
return self.value
98+
99+
100+
class SpecEnumSet(SpecElement):
101+
""" Enum type
102+
103+
Represents an enumeration (list of numerical constants)
104+
as declared in the "definitions" section of the spec.
105+
106+
Attributes:
107+
type enum or flags
108+
entries entries by name
109+
Methods:
110+
get_mask for flags compute the mask of all defined values
111+
"""
112+
def __init__(self, family, yaml):
113+
super().__init__(family, yaml)
114+
115+
self.type = yaml['type']
116+
117+
prev_entry = None
118+
value_start = self.yaml.get('value-start', 0)
119+
self.entries = dict()
120+
for entry in self.yaml['entries']:
121+
e = self.new_entry(entry, prev_entry, value_start)
122+
self.entries[e.name] = e
123+
prev_entry = e
124+
125+
def new_entry(self, entry, prev_entry, value_start):
126+
return SpecEnumEntry(self, entry, prev_entry, value_start)
127+
128+
def has_doc(self):
129+
if 'doc' in self.yaml:
130+
return True
131+
for entry in self.entries.values():
132+
if entry.has_doc():
133+
return True
134+
return False
135+
136+
def get_mask(self):
137+
mask = 0
138+
idx = self.yaml.get('value-start', 0)
139+
for _ in self.entries.values():
140+
mask |= 1 << idx
141+
idx += 1
142+
return mask
143+
144+
60145
class SpecAttr(SpecElement):
61146
""" Single Netlink atttribute type
62147
@@ -193,6 +278,7 @@ class SpecFamily(SpecElement):
193278
msgs dict of all messages (index by name)
194279
msgs_by_value dict of all messages (indexed by name)
195280
ops dict of all valid requests / responses
281+
consts dict of all constants/enums
196282
"""
197283
def __init__(self, spec_path, schema_path=None):
198284
with open(spec_path, "r") as stream:
@@ -222,6 +308,7 @@ def __init__(self, spec_path, schema_path=None):
222308
self.req_by_value = collections.OrderedDict()
223309
self.rsp_by_value = collections.OrderedDict()
224310
self.ops = collections.OrderedDict()
311+
self.consts = collections.OrderedDict()
225312

226313
last_exception = None
227314
while len(self._resolution_list) > 0:
@@ -242,6 +329,9 @@ def __init__(self, spec_path, schema_path=None):
242329
if len(resolved) == 0:
243330
raise last_exception
244331

332+
def new_enum(self, elem):
333+
return SpecEnumSet(self, elem)
334+
245335
def new_attr_set(self, elem):
246336
return SpecAttrSet(self, elem)
247337

@@ -296,6 +386,12 @@ def _dictify_ops_directional(self):
296386
def resolve(self):
297387
self.resolve_up(super())
298388

389+
for elem in self.yaml['definitions']:
390+
if elem['type'] == 'enum' or elem['type'] == 'flags':
391+
self.consts[elem['name']] = self.new_enum(elem)
392+
else:
393+
self.consts[elem['name']] = elem
394+
299395
for elem in self.yaml['attribute-sets']:
300396
attr_set = self.new_attr_set(elem)
301397
self.attr_sets[elem['name']] = attr_set

tools/net/ynl/ynl-gen-c.py

Lines changed: 21 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import os
77
import yaml
88

9-
from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation
9+
from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry
1010

1111

1212
def c_upper(name):
@@ -567,97 +567,37 @@ def set_inherited(self, new_inherited):
567567
self.inherited = [c_lower(x) for x in sorted(self._inherited)]
568568

569569

570-
class EnumEntry:
570+
class EnumEntry(SpecEnumEntry):
571571
def __init__(self, enum_set, yaml, prev, value_start):
572-
if isinstance(yaml, str):
573-
self.name = yaml
574-
yaml = {}
575-
self.doc = ''
576-
else:
577-
self.name = yaml['name']
578-
self.doc = yaml.get('doc', '')
579-
580-
self.yaml = yaml
581-
self.enum_set = enum_set
582-
self.c_name = c_upper(enum_set.value_pfx + self.name)
583-
584-
if 'value' in yaml:
585-
self.value = yaml['value']
586-
if prev:
587-
self.value_change = (self.value != prev.value + 1)
588-
elif prev:
589-
self.value_change = False
590-
self.value = prev.value + 1
572+
super().__init__(enum_set, yaml, prev, value_start)
573+
574+
if prev:
575+
self.value_change = (self.value != prev.value + 1)
591576
else:
592-
self.value = value_start
593577
self.value_change = (self.value != 0)
594-
595578
self.value_change = self.value_change or self.enum_set['type'] == 'flags'
596579

597-
def __getitem__(self, key):
598-
return self.yaml[key]
599-
600-
def __contains__(self, key):
601-
return key in self.yaml
602-
603-
def has_doc(self):
604-
return bool(self.doc)
580+
# Added by resolve:
581+
self.c_name = None
582+
delattr(self, "c_name")
605583

606-
# raw value, i.e. the id in the enum, unlike user value which is a mask for flags
607-
def raw_value(self):
608-
return self.value
584+
def resolve(self):
585+
self.resolve_up(super())
609586

610-
# user value, same as raw value for enums, for flags it's the mask
611-
def user_value(self):
612-
if self.enum_set['type'] == 'flags':
613-
return 1 << self.value
614-
else:
615-
return self.value
587+
self.c_name = c_upper(self.enum_set.value_pfx + self.name)
616588

617589

618-
class EnumSet:
590+
class EnumSet(SpecEnumSet):
619591
def __init__(self, family, yaml):
620-
self.yaml = yaml
621-
self.family = family
622-
623592
self.render_name = c_lower(family.name + '-' + yaml['name'])
624593
self.enum_name = 'enum ' + self.render_name
625594

626595
self.value_pfx = yaml.get('name-prefix', f"{family.name}-{yaml['name']}-")
627596

628-
self.type = yaml['type']
629-
630-
prev_entry = None
631-
value_start = self.yaml.get('value-start', 0)
632-
self.entries = {}
633-
self.entry_list = []
634-
for entry in self.yaml['entries']:
635-
e = EnumEntry(self, entry, prev_entry, value_start)
636-
self.entries[e.name] = e
637-
self.entry_list.append(e)
638-
prev_entry = e
639-
640-
def __getitem__(self, key):
641-
return self.yaml[key]
642-
643-
def __contains__(self, key):
644-
return key in self.yaml
645-
646-
def has_doc(self):
647-
if 'doc' in self.yaml:
648-
return True
649-
for entry in self.entry_list:
650-
if entry.has_doc():
651-
return True
652-
return False
597+
super().__init__(family, yaml)
653598

654-
def get_mask(self):
655-
mask = 0
656-
idx = self.yaml.get('value-start', 0)
657-
for _ in self.entry_list:
658-
mask |= 1 << idx
659-
idx += 1
660-
return mask
599+
def new_entry(self, entry, prev_entry, value_start):
600+
return EnumEntry(self, entry, prev_entry, value_start)
661601

662602

663603
class AttrSet(SpecAttrSet):
@@ -792,8 +732,6 @@ def resolve(self):
792732

793733
self.mcgrps = self.yaml.get('mcast-groups', {'list': []})
794734

795-
self.consts = dict()
796-
797735
self.hooks = dict()
798736
for when in ['pre', 'post']:
799737
self.hooks[when] = dict()
@@ -820,6 +758,9 @@ def resolve(self):
820758
if self.kernel_policy == 'global':
821759
self._load_global_policy()
822760

761+
def new_enum(self, elem):
762+
return EnumSet(self, elem)
763+
823764
def new_attr_set(self, elem):
824765
return AttrSet(self, elem)
825766

@@ -837,12 +778,6 @@ def _mock_up_events(self):
837778
}
838779

839780
def _dictify(self):
840-
for elem in self.yaml['definitions']:
841-
if elem['type'] == 'enum' or elem['type'] == 'flags':
842-
self.consts[elem['name']] = EnumSet(self, elem)
843-
else:
844-
self.consts[elem['name']] = elem
845-
846781
ntf = []
847782
for msg in self.msgs.values():
848783
if 'notify' in msg:
@@ -1980,15 +1915,15 @@ def render_uapi(family, cw):
19801915
if 'doc' in enum:
19811916
doc = ' - ' + enum['doc']
19821917
cw.write_doc_line(enum.enum_name + doc)
1983-
for entry in enum.entry_list:
1918+
for entry in enum.entries.values():
19841919
if entry.has_doc():
19851920
doc = '@' + entry.c_name + ': ' + entry['doc']
19861921
cw.write_doc_line(doc)
19871922
cw.p(' */')
19881923

19891924
uapi_enum_start(family, cw, const, 'name')
19901925
name_pfx = const.get('name-prefix', f"{family.name}-{const['name']}-")
1991-
for entry in enum.entry_list:
1926+
for entry in enum.entries.values():
19921927
suffix = ','
19931928
if entry.value_change:
19941929
suffix = f" = {entry.user_value()}" + suffix

0 commit comments

Comments
 (0)