Skip to content

Commit 3f41e10

Browse files
committed
tools: ynl-gen: allow noncontiguous enums
JIRA: https://issues.redhat.com/browse/RHEL-104975 Conflicts: - adjusted due to missing 18d574c ("tools: ynl-gen: don't init enum checks for classic netlink") commit 37006af Author: Jiri Pirko <jiri@resnulli.us> Date: Mon May 5 13:45:10 2025 +0200 tools: ynl-gen: allow noncontiguous enums in case the enum has holes, instead of hard stop, generate a validation callback to check valid enum values. Signed-off-by: Jiri Pirko <jiri@nvidia.com> Link: https://patch.msgid.link/20250505114513.53370-2-jiri@resnulli.us Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
1 parent 234e7c1 commit 3f41e10

File tree

1 file changed

+52
-6
lines changed

1 file changed

+52
-6
lines changed

tools/net/ynl/pyynl/ynl_gen_c.py

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -317,11 +317,14 @@ def __init__(self, family, attr_set, attr, value):
317317
if 'enum' in self.attr:
318318
enum = self.family.consts[self.attr['enum']]
319319
low, high = enum.value_range()
320-
if 'min' not in self.checks:
321-
if low != 0 or self.type[0] == 's':
322-
self.checks['min'] = low
323-
if 'max' not in self.checks:
324-
self.checks['max'] = high
320+
if low == None and high == None:
321+
self.checks['sparse'] = True
322+
else:
323+
if 'min' not in self.checks:
324+
if low != 0 or self.type[0] == 's':
325+
self.checks['min'] = low
326+
if 'max' not in self.checks:
327+
self.checks['max'] = high
325328

326329
if 'min' in self.checks and 'max' in self.checks:
327330
if self.get_limit('min') > self.get_limit('max'):
@@ -376,6 +379,8 @@ def _attr_policy(self, policy):
376379
return f"NLA_POLICY_MIN({policy}, {self.get_limit_str('min')})"
377380
elif 'max' in self.checks:
378381
return f"NLA_POLICY_MAX({policy}, {self.get_limit_str('max')})"
382+
elif 'sparse' in self.checks:
383+
return f"NLA_POLICY_VALIDATE_FN({policy}, &{c_lower(self.enum_name)}_validate)"
379384
return super()._attr_policy(policy)
380385

381386
def _attr_typol(self):
@@ -809,7 +814,7 @@ def value_range(self):
809814
high = max([x.value for x in self.entries.values()])
810815

811816
if high - low + 1 != len(self.entries):
812-
raise Exception("Can't get value range for a noncontiguous enum")
817+
return None, None
813818

814819
return low, high
815820

@@ -2189,6 +2194,46 @@ def print_kernel_policy_ranges(family, cw):
21892194
cw.nl()
21902195

21912196

2197+
def print_kernel_policy_sparse_enum_validates(family, cw):
2198+
first = True
2199+
for _, attr_set in family.attr_sets.items():
2200+
if attr_set.subset_of:
2201+
continue
2202+
2203+
for _, attr in attr_set.items():
2204+
if not attr.request:
2205+
continue
2206+
if not attr.enum_name:
2207+
continue
2208+
if 'sparse' not in attr.checks:
2209+
continue
2210+
2211+
if first:
2212+
cw.p('/* Sparse enums validation callbacks */')
2213+
first = False
2214+
2215+
sign = '' if attr.type[0] == 'u' else '_signed'
2216+
suffix = 'ULL' if attr.type[0] == 'u' else 'LL'
2217+
cw.write_func_prot('static int', f'{c_lower(attr.enum_name)}_validate',
2218+
['const struct nlattr *attr', 'struct netlink_ext_ack *extack'])
2219+
cw.block_start()
2220+
cw.block_start(line=f'switch (nla_get_{attr["type"]}(attr))')
2221+
enum = family.consts[attr['enum']]
2222+
first_entry = True
2223+
for entry in enum.entries.values():
2224+
if first_entry:
2225+
first_entry = False
2226+
else:
2227+
cw.p('fallthrough;')
2228+
cw.p(f'case {entry.c_name}:')
2229+
cw.p('return 0;')
2230+
cw.block_end()
2231+
cw.p('NL_SET_ERR_MSG_ATTR(extack, attr, "invalid enum value");')
2232+
cw.p('return -EINVAL;')
2233+
cw.block_end()
2234+
cw.nl()
2235+
2236+
21922237
def print_kernel_op_table_fwd(family, cw, terminate):
21932238
exported = not kernel_can_gen_family_struct(family)
21942239

@@ -2827,6 +2872,7 @@ def main():
28272872
print_kernel_family_struct_hdr(parsed, cw)
28282873
else:
28292874
print_kernel_policy_ranges(parsed, cw)
2875+
print_kernel_policy_sparse_enum_validates(parsed, cw)
28302876

28312877
for _, struct in sorted(parsed.pure_nested_structs.items()):
28322878
if struct.request:

0 commit comments

Comments
 (0)