2 # SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
15 sys
.path
.append(pathlib
.Path(__file__
).resolve().parent
.as_posix())
16 from lib
import SpecFamily
, SpecAttrSet
, SpecAttr
, SpecOperation
, SpecEnumSet
, SpecEnumEntry
20 return name
.upper().replace('-', '_')
24 return name
.lower().replace('-', '_')
27 def limit_to_number(name
):
29 Turn a string limit like u32-max or s64-min into its numerical value
31 if name
[0] == 'u' and name
.endswith('-min'):
33 width
= int(name
[1:-4])
36 value
= (1 << width
) - 1
37 if name
[0] == 's' and name
.endswith('-min'):
43 def get_family_id(self
):
44 return 'ys->family_id'
48 def __init__(self
, family
, attr_set
, attr
, value
):
49 super().__init
__(family
, attr_set
, attr
, value
)
52 self
.attr_set
= attr_set
53 self
.type = attr
['type']
54 self
.checks
= attr
.get('checks', {})
60 self
.len = attr
['len']
62 if 'nested-attributes' in attr
:
63 self
.nested_attrs
= attr
['nested-attributes']
64 if self
.nested_attrs
== family
.name
:
65 self
.nested_render_name
= c_lower(f
"{family.ident_name}")
67 self
.nested_render_name
= c_lower(f
"{family.ident_name}_{self.nested_attrs}")
69 if self
.nested_attrs
in self
.family
.consts
:
70 self
.nested_struct_type
= 'struct ' + self
.nested_render_name
+ '_'
72 self
.nested_struct_type
= 'struct ' + self
.nested_render_name
74 self
.c_name
= c_lower(self
.name
)
75 if self
.c_name
in _C_KW
:
80 delattr(self
, "enum_name")
82 def get_limit(self
, limit
, default
=None):
83 value
= self
.checks
.get(limit
, default
)
86 if isinstance(value
, int):
88 if value
in self
.family
.consts
:
89 raise Exception("Resolving family constants not implemented, yet")
90 return limit_to_number(value
)
92 def get_limit_str(self
, limit
, default
=None, suffix
=''):
93 value
= self
.checks
.get(limit
, default
)
96 if isinstance(value
, int):
97 return str(value
) + suffix
98 if value
in self
.family
.consts
:
99 return c_upper(f
"{self.family['name']}-{value}")
100 return c_upper(value
)
103 if 'name-prefix' in self
.attr
:
104 enum_name
= f
"{self.attr['name-prefix']}{self.name}"
106 enum_name
= f
"{self.attr_set.name_prefix}{self.name}"
107 self
.enum_name
= c_upper(enum_name
)
109 def is_multi_val(self
):
113 return self
.type in {'u8', 'u16', 'u32', 'u64', 's32', 's64'}
115 def is_recursive(self
):
118 def is_recursive_for_op(self
, ri
):
119 return self
.is_recursive() and not ri
.op
121 def presence_type(self
):
124 def presence_member(self
, space
, type_filter
):
125 if self
.presence_type() != type_filter
:
128 if self
.presence_type() == 'bit':
129 pfx
= '__' if space
== 'user' else ''
130 return f
"{pfx}u32 {self.c_name}:1;"
132 if self
.presence_type() == 'len':
133 pfx
= '__' if space
== 'user' else ''
134 return f
"{pfx}u32 {self.c_name}_len;"
136 def _complex_member_type(self
, ri
):
139 def free_needs_iter(self
):
142 def free(self
, ri
, var
, ref
):
143 if self
.is_multi_val() or self
.presence_type() == 'len':
144 ri
.cw
.p(f
'free({var}->{ref}{self.c_name});')
146 def arg_member(self
, ri
):
147 member
= self
._complex
_member
_type
(ri
)
149 arg
= [member
+ ' *' + self
.c_name
]
150 if self
.presence_type() == 'count':
151 arg
+= ['unsigned int n_' + self
.c_name
]
153 raise Exception(f
"Struct member not implemented for class type {self.type}")
155 def struct_member(self
, ri
):
156 if self
.is_multi_val():
157 ri
.cw
.p(f
"unsigned int n_{self.c_name};")
158 member
= self
._complex
_member
_type
(ri
)
160 ptr
= '*' if self
.is_multi_val() else ''
161 if self
.is_recursive_for_op(ri
):
163 ri
.cw
.p(f
"{member} {ptr}{self.c_name};")
165 members
= self
.arg_member(ri
)
169 def _attr_policy(self
, policy
):
170 return '{ .type = ' + policy
+ ', }'
172 def attr_policy(self
, cw
):
173 policy
= f
'NLA_{c_upper(self.type)}'
174 if self
.attr
.get('byte-order') == 'big-endian':
175 if self
.type in {'u16', 'u32'}:
176 policy
= f
'NLA_BE{self.type[1:]}'
178 spec
= self
._attr
_policy
(policy
)
179 cw
.p(f
"\t[{self.enum_name}] = {spec},")
181 def _attr_typol(self
):
182 raise Exception(f
"Type policy not implemented for class type {self.type}")
184 def attr_typol(self
, cw
):
185 typol
= self
._attr
_typol
()
186 cw
.p(f
'[{self.enum_name}] = {"{"} .name = "{self.name}", {typol}{"}"},')
188 def _attr_put_line(self
, ri
, var
, line
):
189 if self
.presence_type() == 'bit':
190 ri
.cw
.p(f
"if ({var}->_present.{self.c_name})")
191 elif self
.presence_type() == 'len':
192 ri
.cw
.p(f
"if ({var}->_present.{self.c_name}_len)")
195 def _attr_put_simple(self
, ri
, var
, put_type
):
196 line
= f
"ynl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name})"
197 self
._attr
_put
_line
(ri
, var
, line
)
199 def attr_put(self
, ri
, var
):
200 raise Exception(f
"Put not implemented for class type {self.type}")
202 def _attr_get(self
, ri
, var
):
203 raise Exception(f
"Attr get not implemented for class type {self.type}")
205 def attr_get(self
, ri
, var
, first
):
206 lines
, init_lines
, local_vars
= self
._attr
_get
(ri
, var
)
207 if type(lines
) is str:
209 if type(init_lines
) is str:
210 init_lines
= [init_lines
]
212 kw
= 'if' if first
else 'else if'
213 ri
.cw
.block_start(line
=f
"{kw} (type == {self.enum_name})")
215 for local
in local_vars
:
219 if not self
.is_multi_val():
220 ri
.cw
.p("if (ynl_attr_validate(yarg, attr))")
221 ri
.cw
.p("return YNL_PARSE_CB_ERROR;")
222 if self
.presence_type() == 'bit':
223 ri
.cw
.p(f
"{var}->_present.{self.c_name} = 1;")
227 for line
in init_lines
:
235 def _setter_lines(self
, ri
, member
, presence
):
236 raise Exception(f
"Setter not implemented for class type {self.type}")
238 def setter(self
, ri
, space
, direction
, deref
=False, ref
=None):
239 ref
= (ref
if ref
else []) + [self
.c_name
]
241 member
= f
"{var}->{'.'.join(ref)}"
245 for i
in range(0, len(ref
)):
246 presence
= f
"{var}->{'.'.join(ref[:i] + [''])}_present.{ref[i]}"
247 # Every layer below last is a nest, so we know it uses bit presence
248 # last layer is "self" and may be a complex type
249 if i
== len(ref
) - 1 and self
.presence_type() != 'bit':
251 code
.append(presence
+ ' = 1;')
252 code
+= self
._setter
_lines
(ri
, member
, presence
)
254 func_name
= f
"{op_prefix(ri, direction, deref=deref)}_set_{'_'.join(ref)}"
255 free
= bool([x
for x
in code
if 'free(' in x
])
256 alloc
= bool([x
for x
in code
if 'alloc(' in x
])
257 if free
and not alloc
:
258 func_name
= '__' + func_name
259 ri
.cw
.write_func('static inline void', func_name
, body
=code
,
260 args
=[f
'{type_name(ri, direction, deref=deref)} *{var}'] + self
.arg_member(ri
))
263 class TypeUnused(Type
):
264 def presence_type(self
):
267 def arg_member(self
, ri
):
270 def _attr_get(self
, ri
, var
):
271 return ['return YNL_PARSE_CB_ERROR;'], None, None
273 def _attr_typol(self
):
274 return '.type = YNL_PT_REJECT, '
276 def attr_policy(self
, cw
):
279 def attr_put(self
, ri
, var
):
282 def attr_get(self
, ri
, var
, first
):
285 def setter(self
, ri
, space
, direction
, deref
=False, ref
=None):
290 def presence_type(self
):
293 def arg_member(self
, ri
):
296 def _attr_typol(self
):
297 return '.type = YNL_PT_IGNORE, '
299 def attr_put(self
, ri
, var
):
302 def attr_get(self
, ri
, var
, first
):
305 def attr_policy(self
, cw
):
308 def setter(self
, ri
, space
, direction
, deref
=False, ref
=None):
312 class TypeScalar(Type
):
313 def __init__(self
, family
, attr_set
, attr
, value
):
314 super().__init
__(family
, attr_set
, attr
, value
)
316 self
.byte_order_comment
= ''
317 if 'byte-order' in attr
:
318 self
.byte_order_comment
= f
" /* {attr['byte-order']} */"
320 if 'enum' in self
.attr
:
321 enum
= self
.family
.consts
[self
.attr
['enum']]
322 low
, high
= enum
.value_range()
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
329 if 'min' in self
.checks
and 'max' in self
.checks
:
330 if self
.get_limit('min') > self
.get_limit('max'):
331 raise Exception(f
'Invalid limit for "{self.name}" min: {self.get_limit("min")} max: {self.get_limit("max")}')
332 self
.checks
['range'] = True
334 low
= min(self
.get_limit('min', 0), self
.get_limit('max', 0))
335 high
= max(self
.get_limit('min', 0), self
.get_limit('max', 0))
336 if low
< 0 and self
.type[0] == 'u':
337 raise Exception(f
'Invalid limit for "{self.name}" negative limit for unsigned type')
338 if low
< -32768 or high
> 32767:
339 self
.checks
['full-range'] = True
341 # Added by resolve():
342 self
.is_bitfield
= None
343 delattr(self
, "is_bitfield")
344 self
.type_name
= None
345 delattr(self
, "type_name")
348 self
.resolve_up(super())
350 if 'enum-as-flags' in self
.attr
and self
.attr
['enum-as-flags']:
351 self
.is_bitfield
= True
352 elif 'enum' in self
.attr
:
353 self
.is_bitfield
= self
.family
.consts
[self
.attr
['enum']]['type'] == 'flags'
355 self
.is_bitfield
= False
357 if not self
.is_bitfield
and 'enum' in self
.attr
:
358 self
.type_name
= self
.family
.consts
[self
.attr
['enum']].user_type
359 elif self
.is_auto_scalar
:
360 self
.type_name
= '__' + self
.type[0] + '64'
362 self
.type_name
= '__' + self
.type
364 def _attr_policy(self
, policy
):
365 if 'flags-mask' in self
.checks
or self
.is_bitfield
:
367 enum
= self
.family
.consts
[self
.attr
['enum']]
368 mask
= enum
.get_mask(as_flags
=True)
370 flags
= self
.family
.consts
[self
.checks
['flags-mask']]
371 flag_cnt
= len(flags
['entries'])
372 mask
= (1 << flag_cnt
) - 1
373 return f
"NLA_POLICY_MASK({policy}, 0x{mask:x})"
374 elif 'full-range' in self
.checks
:
375 return f
"NLA_POLICY_FULL_RANGE({policy}, &{c_lower(self.enum_name)}_range)"
376 elif 'range' in self
.checks
:
377 return f
"NLA_POLICY_RANGE({policy}, {self.get_limit_str('min')}, {self.get_limit_str('max')})"
378 elif 'min' in self
.checks
:
379 return f
"NLA_POLICY_MIN({policy}, {self.get_limit_str('min')})"
380 elif 'max' in self
.checks
:
381 return f
"NLA_POLICY_MAX({policy}, {self.get_limit_str('max')})"
382 return super()._attr
_policy
(policy
)
384 def _attr_typol(self
):
385 return f
'.type = YNL_PT_U{c_upper(self.type[1:])}, '
387 def arg_member(self
, ri
):
388 return [f
'{self.type_name} {self.c_name}{self.byte_order_comment}']
390 def attr_put(self
, ri
, var
):
391 self
._attr
_put
_simple
(ri
, var
, self
.type)
393 def _attr_get(self
, ri
, var
):
394 return f
"{var}->{self.c_name} = ynl_attr_get_{self.type}(attr);", None, None
396 def _setter_lines(self
, ri
, member
, presence
):
397 return [f
"{member} = {self.c_name};"]
400 class TypeFlag(Type
):
401 def arg_member(self
, ri
):
404 def _attr_typol(self
):
405 return '.type = YNL_PT_FLAG, '
407 def attr_put(self
, ri
, var
):
408 self
._attr
_put
_line
(ri
, var
, f
"ynl_attr_put(nlh, {self.enum_name}, NULL, 0)")
410 def _attr_get(self
, ri
, var
):
411 return [], None, None
413 def _setter_lines(self
, ri
, member
, presence
):
417 class TypeString(Type
):
418 def arg_member(self
, ri
):
419 return [f
"const char *{self.c_name}"]
421 def presence_type(self
):
424 def struct_member(self
, ri
):
425 ri
.cw
.p(f
"char *{self.c_name};")
427 def _attr_typol(self
):
428 return f
'.type = YNL_PT_NUL_STR, '
430 def _attr_policy(self
, policy
):
431 if 'exact-len' in self
.checks
:
432 mem
= 'NLA_POLICY_EXACT_LEN(' + self
.get_limit_str('exact-len') + ')'
434 mem
= '{ .type = ' + policy
435 if 'max-len' in self
.checks
:
436 mem
+= ', .len = ' + self
.get_limit_str('max-len')
440 def attr_policy(self
, cw
):
441 if self
.checks
.get('unterminated-ok', False):
442 policy
= 'NLA_STRING'
444 policy
= 'NLA_NUL_STRING'
446 spec
= self
._attr
_policy
(policy
)
447 cw
.p(f
"\t[{self.enum_name}] = {spec},")
449 def attr_put(self
, ri
, var
):
450 self
._attr
_put
_simple
(ri
, var
, 'str')
452 def _attr_get(self
, ri
, var
):
453 len_mem
= var
+ '->_present.' + self
.c_name
+ '_len'
454 return [f
"{len_mem} = len;",
455 f
"{var}->{self.c_name} = malloc(len + 1);",
456 f
"memcpy({var}->{self.c_name}, ynl_attr_get_str(attr), len);",
457 f
"{var}->{self.c_name}[len] = 0;"], \
458 ['len = strnlen(ynl_attr_get_str(attr), ynl_attr_data_len(attr));'], \
459 ['unsigned int len;']
461 def _setter_lines(self
, ri
, member
, presence
):
462 return [f
"free({member});",
463 f
"{presence}_len = strlen({self.c_name});",
464 f
"{member} = malloc({presence}_len + 1);",
465 f
'memcpy({member}, {self.c_name}, {presence}_len);',
466 f
'{member}[{presence}_len] = 0;']
469 class TypeBinary(Type
):
470 def arg_member(self
, ri
):
471 return [f
"const void *{self.c_name}", 'size_t len']
473 def presence_type(self
):
476 def struct_member(self
, ri
):
477 ri
.cw
.p(f
"void *{self.c_name};")
479 def _attr_typol(self
):
480 return f
'.type = YNL_PT_BINARY,'
482 def _attr_policy(self
, policy
):
483 if len(self
.checks
) == 0:
485 elif len(self
.checks
) == 1:
486 check_name
= list(self
.checks
)[0]
487 if check_name
not in {'exact-len', 'min-len', 'max-len'}:
488 raise Exception('Unsupported check for binary type: ' + check_name
)
490 raise Exception('More than one check for binary type not implemented, yet')
492 if len(self
.checks
) == 0:
493 mem
= '{ .type = NLA_BINARY, }'
494 elif 'exact-len' in self
.checks
:
495 mem
= 'NLA_POLICY_EXACT_LEN(' + self
.get_limit_str('exact-len') + ')'
496 elif 'min-len' in self
.checks
:
497 mem
= '{ .len = ' + self
.get_limit_str('min-len') + ', }'
498 elif 'max-len' in self
.checks
:
499 mem
= 'NLA_POLICY_MAX_LEN(' + self
.get_limit_str('max-len') + ')'
503 def attr_put(self
, ri
, var
):
504 self
._attr
_put
_line
(ri
, var
, f
"ynl_attr_put(nlh, {self.enum_name}, " +
505 f
"{var}->{self.c_name}, {var}->_present.{self.c_name}_len)")
507 def _attr_get(self
, ri
, var
):
508 len_mem
= var
+ '->_present.' + self
.c_name
+ '_len'
509 return [f
"{len_mem} = len;",
510 f
"{var}->{self.c_name} = malloc(len);",
511 f
"memcpy({var}->{self.c_name}, ynl_attr_data(attr), len);"], \
512 ['len = ynl_attr_data_len(attr);'], \
513 ['unsigned int len;']
515 def _setter_lines(self
, ri
, member
, presence
):
516 return [f
"free({member});",
517 f
"{presence}_len = len;",
518 f
"{member} = malloc({presence}_len);",
519 f
'memcpy({member}, {self.c_name}, {presence}_len);']
522 class TypeBitfield32(Type
):
523 def _complex_member_type(self
, ri
):
524 return "struct nla_bitfield32"
526 def _attr_typol(self
):
527 return f
'.type = YNL_PT_BITFIELD32, '
529 def _attr_policy(self
, policy
):
530 if not 'enum' in self
.attr
:
531 raise Exception('Enum required for bitfield32 attr')
532 enum
= self
.family
.consts
[self
.attr
['enum']]
533 mask
= enum
.get_mask(as_flags
=True)
534 return f
"NLA_POLICY_BITFIELD32({mask})"
536 def attr_put(self
, ri
, var
):
537 line
= f
"ynl_attr_put(nlh, {self.enum_name}, &{var}->{self.c_name}, sizeof(struct nla_bitfield32))"
538 self
._attr
_put
_line
(ri
, var
, line
)
540 def _attr_get(self
, ri
, var
):
541 return f
"memcpy(&{var}->{self.c_name}, ynl_attr_data(attr), sizeof(struct nla_bitfield32));", None, None
543 def _setter_lines(self
, ri
, member
, presence
):
544 return [f
"memcpy(&{member}, {self.c_name}, sizeof(struct nla_bitfield32));"]
547 class TypeNest(Type
):
548 def is_recursive(self
):
549 return self
.family
.pure_nested_structs
[self
.nested_attrs
].recursive
551 def _complex_member_type(self
, ri
):
552 return self
.nested_struct_type
554 def free(self
, ri
, var
, ref
):
556 if self
.is_recursive_for_op(ri
):
558 ri
.cw
.p(f
'if ({var}->{ref}{self.c_name})')
559 ri
.cw
.p(f
'{self.nested_render_name}_free({at}{var}->{ref}{self.c_name});')
561 def _attr_typol(self
):
562 return f
'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
564 def _attr_policy(self
, policy
):
565 return 'NLA_POLICY_NESTED(' + self
.nested_render_name
+ '_nl_policy)'
567 def attr_put(self
, ri
, var
):
568 at
= '' if self
.is_recursive_for_op(ri
) else '&'
569 self
._attr
_put
_line
(ri
, var
, f
"{self.nested_render_name}_put(nlh, " +
570 f
"{self.enum_name}, {at}{var}->{self.c_name})")
572 def _attr_get(self
, ri
, var
):
573 get_lines
= [f
"if ({self.nested_render_name}_parse(&parg, attr))",
574 "return YNL_PARSE_CB_ERROR;"]
575 init_lines
= [f
"parg.rsp_policy = &{self.nested_render_name}_nest;",
576 f
"parg.data = &{var}->{self.c_name};"]
577 return get_lines
, init_lines
, None
579 def setter(self
, ri
, space
, direction
, deref
=False, ref
=None):
580 ref
= (ref
if ref
else []) + [self
.c_name
]
582 for _
, attr
in ri
.family
.pure_nested_structs
[self
.nested_attrs
].member_list():
583 if attr
.is_recursive():
585 attr
.setter(ri
, self
.nested_attrs
, direction
, deref
=deref
, ref
=ref
)
588 class TypeMultiAttr(Type
):
589 def __init__(self
, family
, attr_set
, attr
, value
, base_type
):
590 super().__init
__(family
, attr_set
, attr
, value
)
592 self
.base_type
= base_type
594 def is_multi_val(self
):
597 def presence_type(self
):
600 def _complex_member_type(self
, ri
):
601 if 'type' not in self
.attr
or self
.attr
['type'] == 'nest':
602 return self
.nested_struct_type
603 elif self
.attr
['type'] in scalars
:
604 scalar_pfx
= '__' if ri
.ku_space
== 'user' else ''
605 return scalar_pfx
+ self
.attr
['type']
607 raise Exception(f
"Sub-type {self.attr['type']} not supported yet")
609 def free_needs_iter(self
):
610 return 'type' not in self
.attr
or self
.attr
['type'] == 'nest'
612 def free(self
, ri
, var
, ref
):
613 if self
.attr
['type'] in scalars
:
614 ri
.cw
.p(f
"free({var}->{ref}{self.c_name});")
615 elif 'type' not in self
.attr
or self
.attr
['type'] == 'nest':
616 ri
.cw
.p(f
"for (i = 0; i < {var}->{ref}n_{self.c_name}; i++)")
617 ri
.cw
.p(f
'{self.nested_render_name}_free(&{var}->{ref}{self.c_name}[i]);')
618 ri
.cw
.p(f
"free({var}->{ref}{self.c_name});")
620 raise Exception(f
"Free of MultiAttr sub-type {self.attr['type']} not supported yet")
622 def _attr_policy(self
, policy
):
623 return self
.base_type
._attr
_policy
(policy
)
625 def _attr_typol(self
):
626 return self
.base_type
._attr
_typol
()
628 def _attr_get(self
, ri
, var
):
629 return f
'n_{self.c_name}++;', None, None
631 def attr_put(self
, ri
, var
):
632 if self
.attr
['type'] in scalars
:
634 ri
.cw
.p(f
"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)")
635 ri
.cw
.p(f
"ynl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);")
636 elif 'type' not in self
.attr
or self
.attr
['type'] == 'nest':
637 ri
.cw
.p(f
"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)")
638 self
._attr
_put
_line
(ri
, var
, f
"{self.nested_render_name}_put(nlh, " +
639 f
"{self.enum_name}, &{var}->{self.c_name}[i])")
641 raise Exception(f
"Put of MultiAttr sub-type {self.attr['type']} not supported yet")
643 def _setter_lines(self
, ri
, member
, presence
):
644 # For multi-attr we have a count, not presence, hack up the presence
645 presence
= presence
[:-(len('_present.') + len(self
.c_name
))] + "n_" + self
.c_name
646 return [f
"free({member});",
647 f
"{member} = {self.c_name};",
648 f
"{presence} = n_{self.c_name};"]
651 class TypeArrayNest(Type
):
652 def is_multi_val(self
):
655 def presence_type(self
):
658 def _complex_member_type(self
, ri
):
659 if 'sub-type' not in self
.attr
or self
.attr
['sub-type'] == 'nest':
660 return self
.nested_struct_type
661 elif self
.attr
['sub-type'] in scalars
:
662 scalar_pfx
= '__' if ri
.ku_space
== 'user' else ''
663 return scalar_pfx
+ self
.attr
['sub-type']
665 raise Exception(f
"Sub-type {self.attr['sub-type']} not supported yet")
667 def _attr_typol(self
):
668 return f
'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
670 def _attr_get(self
, ri
, var
):
671 local_vars
= ['const struct nlattr *attr2;']
672 get_lines
= [f
'attr_{self.c_name} = attr;',
673 'ynl_attr_for_each_nested(attr2, attr)',
674 f
'\t{var}->n_{self.c_name}++;']
675 return get_lines
, None, local_vars
678 class TypeNestTypeValue(Type
):
679 def _complex_member_type(self
, ri
):
680 return self
.nested_struct_type
682 def _attr_typol(self
):
683 return f
'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
685 def _attr_get(self
, ri
, var
):
690 init_lines
= [f
"parg.rsp_policy = &{self.nested_render_name}_nest;",
691 f
"parg.data = &{var}->{self.c_name};"]
692 if 'type-value' in self
.attr
:
693 tv_names
= [c_lower(x
) for x
in self
.attr
["type-value"]]
694 local_vars
+= [f
'const struct nlattr *attr_{", *attr_".join(tv_names)};']
695 local_vars
+= [f
'__u32 {", ".join(tv_names)};']
696 for level
in self
.attr
["type-value"]:
697 level
= c_lower(level
)
698 get_lines
+= [f
'attr_{level} = ynl_attr_data({prev});']
699 get_lines
+= [f
'{level} = ynl_attr_type(attr_{level});']
700 prev
= 'attr_' + level
702 tv_args
= f
", {', '.join(tv_names)}"
704 get_lines
+= [f
"{self.nested_render_name}_parse(&parg, {prev}{tv_args});"]
705 return get_lines
, init_lines
, local_vars
709 def __init__(self
, family
, space_name
, type_list
=None, inherited
=None):
711 self
.space_name
= space_name
712 self
.attr_set
= family
.attr_sets
[space_name
]
713 # Use list to catch comparisons with empty sets
714 self
._inherited
= inherited
if inherited
is not None else []
717 self
.nested
= type_list
is None
718 if family
.name
== c_lower(space_name
):
719 self
.render_name
= c_lower(family
.ident_name
)
721 self
.render_name
= c_lower(family
.ident_name
+ '-' + space_name
)
722 self
.struct_name
= 'struct ' + self
.render_name
723 if self
.nested
and space_name
in family
.consts
:
724 self
.struct_name
+= '_'
725 self
.ptr_name
= self
.struct_name
+ ' *'
726 # All attr sets this one contains, directly or multiple levels down
727 self
.child_nests
= set()
731 self
.recursive
= False
735 if type_list
is not None:
737 self
.attr_list
.append((t
, self
.attr_set
[t
]),)
739 for t
in self
.attr_set
:
740 self
.attr_list
.append((t
, self
.attr_set
[t
]),)
743 self
.attr_max_val
= None
744 for name
, attr
in self
.attr_list
:
745 if attr
.value
>= max_val
:
747 self
.attr_max_val
= attr
748 self
.attrs
[name
] = attr
751 yield from self
.attrs
753 def __getitem__(self
, key
):
754 return self
.attrs
[key
]
756 def member_list(self
):
757 return self
.attr_list
759 def set_inherited(self
, new_inherited
):
760 if self
._inherited
!= new_inherited
:
761 raise Exception("Inheriting different members not supported")
762 self
.inherited
= [c_lower(x
) for x
in sorted(self
._inherited
)]
765 class EnumEntry(SpecEnumEntry
):
766 def __init__(self
, enum_set
, yaml
, prev
, value_start
):
767 super().__init
__(enum_set
, yaml
, prev
, value_start
)
770 self
.value_change
= (self
.value
!= prev
.value
+ 1)
772 self
.value_change
= (self
.value
!= 0)
773 self
.value_change
= self
.value_change
or self
.enum_set
['type'] == 'flags'
777 delattr(self
, "c_name")
780 self
.resolve_up(super())
782 self
.c_name
= c_upper(self
.enum_set
.value_pfx
+ self
.name
)
785 class EnumSet(SpecEnumSet
):
786 def __init__(self
, family
, yaml
):
787 self
.render_name
= c_lower(family
.ident_name
+ '-' + yaml
['name'])
789 if 'enum-name' in yaml
:
790 if yaml
['enum-name']:
791 self
.enum_name
= 'enum ' + c_lower(yaml
['enum-name'])
792 self
.user_type
= self
.enum_name
794 self
.enum_name
= None
796 self
.enum_name
= 'enum ' + self
.render_name
799 self
.user_type
= self
.enum_name
801 self
.user_type
= 'int'
803 self
.value_pfx
= yaml
.get('name-prefix', f
"{family.ident_name}-{yaml['name']}-")
805 super().__init
__(family
, yaml
)
807 def new_entry(self
, entry
, prev_entry
, value_start
):
808 return EnumEntry(self
, entry
, prev_entry
, value_start
)
810 def value_range(self
):
811 low
= min([x
.value
for x
in self
.entries
.values()])
812 high
= max([x
.value
for x
in self
.entries
.values()])
814 if high
- low
+ 1 != len(self
.entries
):
815 raise Exception("Can't get value range for a noncontiguous enum")
820 class AttrSet(SpecAttrSet
):
821 def __init__(self
, family
, yaml
):
822 super().__init
__(family
, yaml
)
824 if self
.subset_of
is None:
825 if 'name-prefix' in yaml
:
826 pfx
= yaml
['name-prefix']
827 elif self
.name
== family
.name
:
828 pfx
= family
.ident_name
+ '-a-'
830 pfx
= f
"{family.ident_name}-a-{self.name}-"
831 self
.name_prefix
= c_upper(pfx
)
832 self
.max_name
= c_upper(self
.yaml
.get('attr-max-name', f
"{self.name_prefix}max"))
833 self
.cnt_name
= c_upper(self
.yaml
.get('attr-cnt-name', f
"__{self.name_prefix}max"))
835 self
.name_prefix
= family
.attr_sets
[self
.subset_of
].name_prefix
836 self
.max_name
= family
.attr_sets
[self
.subset_of
].max_name
837 self
.cnt_name
= family
.attr_sets
[self
.subset_of
].cnt_name
841 delattr(self
, "c_name")
844 self
.c_name
= c_lower(self
.name
)
845 if self
.c_name
in _C_KW
:
847 if self
.c_name
== self
.family
.c_name
:
850 def new_attr(self
, elem
, value
):
851 if elem
['type'] in scalars
:
852 t
= TypeScalar(self
.family
, self
, elem
, value
)
853 elif elem
['type'] == 'unused':
854 t
= TypeUnused(self
.family
, self
, elem
, value
)
855 elif elem
['type'] == 'pad':
856 t
= TypePad(self
.family
, self
, elem
, value
)
857 elif elem
['type'] == 'flag':
858 t
= TypeFlag(self
.family
, self
, elem
, value
)
859 elif elem
['type'] == 'string':
860 t
= TypeString(self
.family
, self
, elem
, value
)
861 elif elem
['type'] == 'binary':
862 t
= TypeBinary(self
.family
, self
, elem
, value
)
863 elif elem
['type'] == 'bitfield32':
864 t
= TypeBitfield32(self
.family
, self
, elem
, value
)
865 elif elem
['type'] == 'nest':
866 t
= TypeNest(self
.family
, self
, elem
, value
)
867 elif elem
['type'] == 'indexed-array' and 'sub-type' in elem
:
868 if elem
["sub-type"] == 'nest':
869 t
= TypeArrayNest(self
.family
, self
, elem
, value
)
871 raise Exception(f
'new_attr: unsupported sub-type {elem["sub-type"]}')
872 elif elem
['type'] == 'nest-type-value':
873 t
= TypeNestTypeValue(self
.family
, self
, elem
, value
)
875 raise Exception(f
"No typed class for type {elem['type']}")
877 if 'multi-attr' in elem
and elem
['multi-attr']:
878 t
= TypeMultiAttr(self
.family
, self
, elem
, value
, t
)
883 class Operation(SpecOperation
):
884 def __init__(self
, family
, yaml
, req_value
, rsp_value
):
885 super().__init
__(family
, yaml
, req_value
, rsp_value
)
887 self
.render_name
= c_lower(family
.ident_name
+ '_' + self
.name
)
889 self
.dual_policy
= ('do' in yaml
and 'request' in yaml
['do']) and \
890 ('dump' in yaml
and 'request' in yaml
['dump'])
895 self
.enum_name
= None
896 delattr(self
, "enum_name")
899 self
.resolve_up(super())
901 if not self
.is_async
:
902 self
.enum_name
= self
.family
.op_prefix
+ c_upper(self
.name
)
904 self
.enum_name
= self
.family
.async_op_prefix
+ c_upper(self
.name
)
906 def mark_has_ntf(self
):
910 class Family(SpecFamily
):
911 def __init__(self
, file_name
, exclude_ops
):
914 delattr(self
, "c_name")
915 self
.op_prefix
= None
916 delattr(self
, "op_prefix")
917 self
.async_op_prefix
= None
918 delattr(self
, "async_op_prefix")
920 delattr(self
, "mcgrps")
922 delattr(self
, "consts")
924 delattr(self
, "hooks")
926 super().__init
__(file_name
, exclude_ops
=exclude_ops
)
928 self
.fam_key
= c_upper(self
.yaml
.get('c-family-name', self
.yaml
["name"] + '_FAMILY_NAME'))
929 self
.ver_key
= c_upper(self
.yaml
.get('c-version-name', self
.yaml
["name"] + '_FAMILY_VERSION'))
931 if 'definitions' not in self
.yaml
:
932 self
.yaml
['definitions'] = []
934 if 'uapi-header' in self
.yaml
:
935 self
.uapi_header
= self
.yaml
['uapi-header']
937 self
.uapi_header
= f
"linux/{self.ident_name}.h"
938 if self
.uapi_header
.startswith("linux/") and self
.uapi_header
.endswith('.h'):
939 self
.uapi_header_name
= self
.uapi_header
[6:-2]
941 self
.uapi_header_name
= self
.ident_name
944 self
.resolve_up(super())
946 if self
.yaml
.get('protocol', 'genetlink') not in {'genetlink', 'genetlink-c', 'genetlink-legacy'}:
947 raise Exception("Codegen only supported for genetlink")
949 self
.c_name
= c_lower(self
.ident_name
)
950 if 'name-prefix' in self
.yaml
['operations']:
951 self
.op_prefix
= c_upper(self
.yaml
['operations']['name-prefix'])
953 self
.op_prefix
= c_upper(self
.yaml
['name'] + '-cmd-')
954 if 'async-prefix' in self
.yaml
['operations']:
955 self
.async_op_prefix
= c_upper(self
.yaml
['operations']['async-prefix'])
957 self
.async_op_prefix
= self
.op_prefix
959 self
.mcgrps
= self
.yaml
.get('mcast-groups', {'list': []})
962 for when
in ['pre', 'post']:
963 self
.hooks
[when
] = dict()
964 for op_mode
in ['do', 'dump']:
965 self
.hooks
[when
][op_mode
] = dict()
966 self
.hooks
[when
][op_mode
]['set'] = set()
967 self
.hooks
[when
][op_mode
]['list'] = []
969 # dict space-name -> 'request': set(attrs), 'reply': set(attrs)
970 self
.root_sets
= dict()
971 # dict space-name -> set('request', 'reply')
972 self
.pure_nested_structs
= dict()
975 self
._mock
_up
_events
()
977 self
._load
_root
_sets
()
978 self
._load
_nested
_sets
()
979 self
._load
_attr
_use
()
982 self
.kernel_policy
= self
.yaml
.get('kernel-policy', 'split')
983 if self
.kernel_policy
== 'global':
984 self
._load
_global
_policy
()
986 def new_enum(self
, elem
):
987 return EnumSet(self
, elem
)
989 def new_attr_set(self
, elem
):
990 return AttrSet(self
, elem
)
992 def new_operation(self
, elem
, req_value
, rsp_value
):
993 return Operation(self
, elem
, req_value
, rsp_value
)
995 def _mark_notify(self
):
996 for op
in self
.msgs
.values():
998 self
.ops
[op
['notify']].mark_has_ntf()
1000 # Fake a 'do' equivalent of all events, so that we can render their response parsing
1001 def _mock_up_events(self
):
1002 for op
in self
.yaml
['operations']['list']:
1006 'attributes': op
['event']['attributes']
1010 def _load_root_sets(self
):
1011 for op_name
, op
in self
.msgs
.items():
1012 if 'attribute-set' not in op
:
1017 for op_mode
in ['do', 'dump']:
1018 if op_mode
in op
and 'request' in op
[op_mode
]:
1019 req_attrs
.update(set(op
[op_mode
]['request']['attributes']))
1020 if op_mode
in op
and 'reply' in op
[op_mode
]:
1021 rsp_attrs
.update(set(op
[op_mode
]['reply']['attributes']))
1023 rsp_attrs
.update(set(op
['event']['attributes']))
1025 if op
['attribute-set'] not in self
.root_sets
:
1026 self
.root_sets
[op
['attribute-set']] = {'request': req_attrs
, 'reply': rsp_attrs
}
1028 self
.root_sets
[op
['attribute-set']]['request'].update(req_attrs
)
1029 self
.root_sets
[op
['attribute-set']]['reply'].update(rsp_attrs
)
1031 def _sort_pure_types(self
):
1032 # Try to reorder according to dependencies
1033 pns_key_list
= list(self
.pure_nested_structs
.keys())
1034 pns_key_seen
= set()
1035 rounds
= len(pns_key_list
) ** 2 # it's basically bubble sort
1036 for _
in range(rounds
):
1037 if len(pns_key_list
) == 0:
1039 name
= pns_key_list
.pop(0)
1041 for _
, spec
in self
.attr_sets
[name
].items():
1042 if 'nested-attributes' in spec
:
1043 nested
= spec
['nested-attributes']
1044 # If the unknown nest we hit is recursive it's fine, it'll be a pointer
1045 if self
.pure_nested_structs
[nested
].recursive
:
1047 if nested
not in pns_key_seen
:
1048 # Dicts are sorted, this will make struct last
1049 struct
= self
.pure_nested_structs
.pop(name
)
1050 self
.pure_nested_structs
[name
] = struct
1054 pns_key_seen
.add(name
)
1056 pns_key_list
.append(name
)
1058 def _load_nested_sets(self
):
1059 attr_set_queue
= list(self
.root_sets
.keys())
1060 attr_set_seen
= set(self
.root_sets
.keys())
1062 while len(attr_set_queue
):
1063 a_set
= attr_set_queue
.pop(0)
1064 for attr
, spec
in self
.attr_sets
[a_set
].items():
1065 if 'nested-attributes' not in spec
:
1068 nested
= spec
['nested-attributes']
1069 if nested
not in attr_set_seen
:
1070 attr_set_queue
.append(nested
)
1071 attr_set_seen
.add(nested
)
1074 if nested
not in self
.root_sets
:
1075 if nested
not in self
.pure_nested_structs
:
1076 self
.pure_nested_structs
[nested
] = Struct(self
, nested
, inherited
=inherit
)
1078 raise Exception(f
'Using attr set as root and nested not supported - {nested}')
1080 if 'type-value' in spec
:
1081 if nested
in self
.root_sets
:
1082 raise Exception("Inheriting members to a space used as root not supported")
1083 inherit
.update(set(spec
['type-value']))
1084 elif spec
['type'] == 'indexed-array':
1086 self
.pure_nested_structs
[nested
].set_inherited(inherit
)
1088 for root_set
, rs_members
in self
.root_sets
.items():
1089 for attr
, spec
in self
.attr_sets
[root_set
].items():
1090 if 'nested-attributes' in spec
:
1091 nested
= spec
['nested-attributes']
1092 if attr
in rs_members
['request']:
1093 self
.pure_nested_structs
[nested
].request
= True
1094 if attr
in rs_members
['reply']:
1095 self
.pure_nested_structs
[nested
].reply
= True
1097 self
._sort
_pure
_types
()
1099 # Propagate the request / reply / recursive
1100 for attr_set
, struct
in reversed(self
.pure_nested_structs
.items()):
1101 for _
, spec
in self
.attr_sets
[attr_set
].items():
1102 if 'nested-attributes' in spec
:
1103 child_name
= spec
['nested-attributes']
1104 struct
.child_nests
.add(child_name
)
1105 child
= self
.pure_nested_structs
.get(child_name
)
1107 if not child
.recursive
:
1108 struct
.child_nests
.update(child
.child_nests
)
1109 child
.request |
= struct
.request
1110 child
.reply |
= struct
.reply
1111 if attr_set
in struct
.child_nests
:
1112 struct
.recursive
= True
1114 self
._sort
_pure
_types
()
1116 def _load_attr_use(self
):
1117 for _
, struct
in self
.pure_nested_structs
.items():
1119 for _
, arg
in struct
.member_list():
1122 for _
, arg
in struct
.member_list():
1125 for root_set
, rs_members
in self
.root_sets
.items():
1126 for attr
, spec
in self
.attr_sets
[root_set
].items():
1127 if attr
in rs_members
['request']:
1129 if attr
in rs_members
['reply']:
1132 def _load_global_policy(self
):
1134 attr_set_name
= None
1135 for op_name
, op
in self
.ops
.items():
1138 if 'attribute-set' not in op
:
1141 if attr_set_name
is None:
1142 attr_set_name
= op
['attribute-set']
1143 if attr_set_name
!= op
['attribute-set']:
1144 raise Exception('For a global policy all ops must use the same set')
1146 for op_mode
in ['do', 'dump']:
1148 req
= op
[op_mode
].get('request')
1150 global_set
.update(req
.get('attributes', []))
1152 self
.global_policy
= []
1153 self
.global_policy_set
= attr_set_name
1154 for attr
in self
.attr_sets
[attr_set_name
]:
1155 if attr
in global_set
:
1156 self
.global_policy
.append(attr
)
1158 def _load_hooks(self
):
1159 for op
in self
.ops
.values():
1160 for op_mode
in ['do', 'dump']:
1161 if op_mode
not in op
:
1163 for when
in ['pre', 'post']:
1164 if when
not in op
[op_mode
]:
1166 name
= op
[op_mode
][when
]
1167 if name
in self
.hooks
[when
][op_mode
]['set']:
1169 self
.hooks
[when
][op_mode
]['set'].add(name
)
1170 self
.hooks
[when
][op_mode
]['list'].append(name
)
1174 def __init__(self
, cw
, family
, ku_space
, op
, op_mode
, attr_set
=None):
1175 self
.family
= family
1177 self
.ku_space
= ku_space
1178 self
.op_mode
= op_mode
1181 self
.fixed_hdr
= None
1182 if op
and op
.fixed_header
:
1183 self
.fixed_hdr
= 'struct ' + c_lower(op
.fixed_header
)
1185 # 'do' and 'dump' response parsing is identical
1186 self
.type_consistent
= True
1187 if op_mode
!= 'do' and 'dump' in op
:
1189 if ('reply' in op
['do']) != ('reply' in op
["dump"]):
1190 self
.type_consistent
= False
1191 elif 'reply' in op
['do'] and op
["do"]["reply"] != op
["dump"]["reply"]:
1192 self
.type_consistent
= False
1194 self
.type_consistent
= False
1196 self
.attr_set
= attr_set
1197 if not self
.attr_set
:
1198 self
.attr_set
= op
['attribute-set']
1200 self
.type_name_conflict
= False
1202 self
.type_name
= c_lower(op
.name
)
1204 self
.type_name
= c_lower(attr_set
)
1205 if attr_set
in family
.consts
:
1206 self
.type_name_conflict
= True
1210 self
.struct
= dict()
1211 if op_mode
== 'notify':
1213 for op_dir
in ['request', 'reply']:
1216 if op_dir
in op
[op_mode
]:
1217 type_list
= op
[op_mode
][op_dir
]['attributes']
1218 self
.struct
[op_dir
] = Struct(family
, self
.attr_set
, type_list
=type_list
)
1219 if op_mode
== 'event':
1220 self
.struct
['reply'] = Struct(family
, self
.attr_set
, type_list
=op
['event']['attributes'])
1224 def __init__(self
, nlib
, out_file
=None, overwrite
=True):
1226 self
._overwrite
= overwrite
1229 self
._block
_end
= False
1230 self
._silent
_block
= False
1232 self
._ifdef
_block
= None
1233 if out_file
is None:
1234 self
._out
= os
.sys
.stdout
1236 self
._out
= tempfile
.NamedTemporaryFile('w+')
1237 self
._out
_file
= out_file
1240 self
.close_out_file()
1242 def close_out_file(self
):
1243 if self
._out
== os
.sys
.stdout
:
1245 # Avoid modifying the file if contents didn't change
1247 if not self
._overwrite
and os
.path
.isfile(self
._out
_file
):
1248 if filecmp
.cmp(self
._out
.name
, self
._out
_file
, shallow
=False):
1250 with
open(self
._out
_file
, 'w+') as out_file
:
1252 shutil
.copyfileobj(self
._out
, out_file
)
1254 self
._out
= os
.sys
.stdout
1257 def _is_cond(cls
, line
):
1258 return line
.startswith('if') or line
.startswith('while') or line
.startswith('for')
1260 def p(self
, line
, add_ind
=0):
1262 self
._block
_end
= False
1263 if line
.startswith('else'):
1266 self
._out
.write('\t' * self
._ind
+ '}\n')
1269 self
._out
.write('\n')
1275 if self
._silent
_block
:
1277 self
._silent
_block
= line
.endswith(')') and CodeWriter
._is
_cond
(line
)
1282 self
._out
.write('\t' * ind
+ line
+ '\n')
1287 def block_start(self
, line
=''):
1293 def block_end(self
, line
=''):
1294 if line
and line
[0] not in {';', ','}:
1299 # Delay printing closing bracket in case "else" comes next
1301 self
._out
.write('\t' * (self
._ind
+ 1) + '}\n')
1302 self
._block
_end
= True
1306 def write_doc_line(self
, doc
, indent
=True):
1310 if len(line
) + len(word
) >= 79:
1318 def write_func_prot(self
, qual_ret
, name
, args
=None, doc
=None, suffix
=''):
1328 if qual_ret
[-1] != '*':
1330 oneline
+= f
"{name}({', '.join(args)}){suffix}"
1332 if len(oneline
) < 80:
1340 elif qual_ret
[-1] != '*':
1343 ind
= '\t' * (len(v
) // 8) + ' ' * (len(v
) % 8)
1344 delta_ind
= len(v
) - len(ind
)
1347 while i
< len(args
):
1348 next_len
= len(v
) + len(args
[i
])
1350 next_len
+= delta_ind
1358 self
.p(v
+ ')' + suffix
)
1360 def write_func_lvar(self
, local_vars
):
1364 if type(local_vars
) is str:
1365 local_vars
= [local_vars
]
1367 local_vars
.sort(key
=len, reverse
=True)
1368 for var
in local_vars
:
1372 def write_func(self
, qual_ret
, name
, body
, args
=None, local_vars
=None):
1373 self
.write_func_prot(qual_ret
=qual_ret
, name
=name
, args
=args
)
1374 self
.write_func_lvar(local_vars
=local_vars
)
1381 def writes_defines(self
, defines
):
1383 for define
in defines
:
1384 if len(define
[0]) > longest
:
1385 longest
= len(define
[0])
1386 longest
= ((longest
+ 8) // 8) * 8
1387 for define
in defines
:
1388 line
= '#define ' + define
[0]
1389 line
+= '\t' * ((longest
- len(define
[0]) + 7) // 8)
1390 if type(define
[1]) is int:
1391 line
+= str(define
[1])
1392 elif type(define
[1]) is str:
1393 line
+= '"' + define
[1] + '"'
1396 def write_struct_init(self
, members
):
1397 longest
= max([len(x
[0]) for x
in members
])
1398 longest
+= 1 # because we prepend a .
1399 longest
= ((longest
+ 8) // 8) * 8
1402 line
+= '\t' * ((longest
- len(one
[0]) - 1 + 7) // 8)
1403 line
+= '= ' + str(one
[1]) + ','
1406 def ifdef_block(self
, config
):
1407 config_option
= None
1409 config_option
= 'CONFIG_' + c_upper(config
)
1410 if self
._ifdef
_block
== config_option
:
1413 if self
._ifdef
_block
:
1414 self
.p('#endif /* ' + self
._ifdef
_block
+ ' */')
1416 self
.p('#ifdef ' + config_option
)
1417 self
._ifdef
_block
= config_option
1420 scalars
= {'u8', 'u16', 'u32', 'u64', 's32', 's64', 'uint', 'sint'}
1422 direction_to_suffix
= {
1428 op_mode_to_wrapper
= {
1473 def rdir(direction
):
1474 if direction
== 'reply':
1476 if direction
== 'request':
1481 def op_prefix(ri
, direction
, deref
=False):
1482 suffix
= f
"_{ri.type_name}"
1484 if not ri
.op_mode
or ri
.op_mode
== 'do':
1485 suffix
+= f
"{direction_to_suffix[direction]}"
1487 if direction
== 'request':
1488 suffix
+= '_req_dump'
1490 if ri
.type_consistent
:
1492 suffix
+= f
"{direction_to_suffix[direction]}"
1494 suffix
+= op_mode_to_wrapper
[ri
.op_mode
]
1497 suffix
+= '_dump' if deref
else '_list'
1499 return f
"{ri.family.c_name}{suffix}"
1502 def type_name(ri
, direction
, deref
=False):
1503 return f
"struct {op_prefix(ri, direction, deref=deref)}"
1506 def print_prototype(ri
, direction
, terminate
=True, doc
=None):
1507 suffix
= ';' if terminate
else ''
1509 fname
= ri
.op
.render_name
1510 if ri
.op_mode
== 'dump':
1513 args
= ['struct ynl_sock *ys']
1514 if 'request' in ri
.op
[ri
.op_mode
]:
1515 args
.append(f
"{type_name(ri, direction)} *" + f
"{direction_to_suffix[direction][1:]}")
1518 if 'reply' in ri
.op
[ri
.op_mode
]:
1519 ret
= f
"{type_name(ri, rdir(direction))} *"
1521 ri
.cw
.write_func_prot(ret
, fname
, args
, doc
=doc
, suffix
=suffix
)
1524 def print_req_prototype(ri
):
1525 print_prototype(ri
, "request", doc
=ri
.op
['doc'])
1528 def print_dump_prototype(ri
):
1529 print_prototype(ri
, "request")
1532 def put_typol_fwd(cw
, struct
):
1533 cw
.p(f
'extern const struct ynl_policy_nest {struct.render_name}_nest;')
1536 def put_typol(cw
, struct
):
1537 type_max
= struct
.attr_set
.max_name
1538 cw
.block_start(line
=f
'const struct ynl_policy_attr {struct.render_name}_policy[{type_max} + 1] =')
1540 for _
, arg
in struct
.member_list():
1543 cw
.block_end(line
=';')
1546 cw
.block_start(line
=f
'const struct ynl_policy_nest {struct.render_name}_nest =')
1547 cw
.p(f
'.max_attr = {type_max},')
1548 cw
.p(f
'.table = {struct.render_name}_policy,')
1549 cw
.block_end(line
=';')
1553 def _put_enum_to_str_helper(cw
, render_name
, map_name
, arg_name
, enum
=None):
1554 args
= [f
'int {arg_name}']
1556 args
= [enum
.user_type
+ ' ' + arg_name
]
1557 cw
.write_func_prot('const char *', f
'{render_name}_str', args
)
1559 if enum
and enum
.type == 'flags':
1560 cw
.p(f
'{arg_name} = ffs({arg_name}) - 1;')
1561 cw
.p(f
'if ({arg_name} < 0 || {arg_name} >= (int)YNL_ARRAY_SIZE({map_name}))')
1562 cw
.p('return NULL;')
1563 cw
.p(f
'return {map_name}[{arg_name}];')
1568 def put_op_name_fwd(family
, cw
):
1569 cw
.write_func_prot('const char *', f
'{family.c_name}_op_str', ['int op'], suffix
=';')
1572 def put_op_name(family
, cw
):
1573 map_name
= f
'{family.c_name}_op_strmap'
1574 cw
.block_start(line
=f
"static const char * const {map_name}[] =")
1575 for op_name
, op
in family
.msgs
.items():
1577 # Make sure we don't add duplicated entries, if multiple commands
1578 # produce the same response in legacy families.
1579 if family
.rsp_by_value
[op
.rsp_value
] != op
:
1580 cw
.p(f
'// skip "{op_name}", duplicate reply value')
1583 if op
.req_value
== op
.rsp_value
:
1584 cw
.p(f
'[{op.enum_name}] = "{op_name}",')
1586 cw
.p(f
'[{op.rsp_value}] = "{op_name}",')
1587 cw
.block_end(line
=';')
1590 _put_enum_to_str_helper(cw
, family
.c_name
+ '_op', map_name
, 'op')
1593 def put_enum_to_str_fwd(family
, cw
, enum
):
1594 args
= [enum
.user_type
+ ' value']
1595 cw
.write_func_prot('const char *', f
'{enum.render_name}_str', args
, suffix
=';')
1598 def put_enum_to_str(family
, cw
, enum
):
1599 map_name
= f
'{enum.render_name}_strmap'
1600 cw
.block_start(line
=f
"static const char * const {map_name}[] =")
1601 for entry
in enum
.entries
.values():
1602 cw
.p(f
'[{entry.value}] = "{entry.name}",')
1603 cw
.block_end(line
=';')
1606 _put_enum_to_str_helper(cw
, enum
.render_name
, map_name
, 'value', enum
=enum
)
1609 def put_req_nested_prototype(ri
, struct
, suffix
=';'):
1610 func_args
= ['struct nlmsghdr *nlh',
1611 'unsigned int attr_type',
1612 f
'{struct.ptr_name}obj']
1614 ri
.cw
.write_func_prot('int', f
'{struct.render_name}_put', func_args
,
1618 def put_req_nested(ri
, struct
):
1619 put_req_nested_prototype(ri
, struct
, suffix
='')
1621 ri
.cw
.write_func_lvar('struct nlattr *nest;')
1623 ri
.cw
.p("nest = ynl_attr_nest_start(nlh, attr_type);")
1625 for _
, arg
in struct
.member_list():
1626 arg
.attr_put(ri
, "obj")
1628 ri
.cw
.p("ynl_attr_nest_end(nlh, nest);")
1631 ri
.cw
.p('return 0;')
1636 def _multi_parse(ri
, struct
, init_lines
, local_vars
):
1638 iter_line
= "ynl_attr_for_each_nested(attr, nested)"
1641 local_vars
+= ['void *hdr;']
1642 iter_line
= "ynl_attr_for_each(attr, nlh, yarg->ys->family->hdr_len)"
1647 for arg
, aspec
in struct
.member_list():
1648 if aspec
['type'] == 'indexed-array' and 'sub-type' in aspec
:
1649 if aspec
["sub-type"] == 'nest':
1650 local_vars
.append(f
'const struct nlattr *attr_{aspec.c_name};')
1651 array_nests
.add(arg
)
1653 raise Exception(f
'Not supported sub-type {aspec["sub-type"]}')
1654 if 'multi-attr' in aspec
:
1655 multi_attrs
.add(arg
)
1656 needs_parg |
= 'nested-attributes' in aspec
1657 if array_nests
or multi_attrs
:
1658 local_vars
.append('int i;')
1660 local_vars
.append('struct ynl_parse_arg parg;')
1661 init_lines
.append('parg.ys = yarg->ys;')
1663 all_multi
= array_nests | multi_attrs
1665 for anest
in sorted(all_multi
):
1666 local_vars
.append(f
"unsigned int n_{struct[anest].c_name} = 0;")
1669 ri
.cw
.write_func_lvar(local_vars
)
1671 for line
in init_lines
:
1675 for arg
in struct
.inherited
:
1676 ri
.cw
.p(f
'dst->{arg} = {arg};')
1679 ri
.cw
.p('hdr = ynl_nlmsg_data_offset(nlh, sizeof(struct genlmsghdr));')
1680 ri
.cw
.p(f
"memcpy(&dst->_hdr, hdr, sizeof({ri.fixed_hdr}));")
1681 for anest
in sorted(all_multi
):
1682 aspec
= struct
[anest
]
1683 ri
.cw
.p(f
"if (dst->{aspec.c_name})")
1684 ri
.cw
.p(f
'return ynl_error_parse(yarg, "attribute already present ({struct.attr_set.name}.{aspec.name})");')
1687 ri
.cw
.block_start(line
=iter_line
)
1688 ri
.cw
.p('unsigned int type = ynl_attr_type(attr);')
1692 for _
, arg
in struct
.member_list():
1693 good
= arg
.attr_get(ri
, 'dst', first
=first
)
1694 # First may be 'unused' or 'pad', ignore those
1700 for anest
in sorted(array_nests
):
1701 aspec
= struct
[anest
]
1703 ri
.cw
.block_start(line
=f
"if (n_{aspec.c_name})")
1704 ri
.cw
.p(f
"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
1705 ri
.cw
.p(f
"dst->n_{aspec.c_name} = n_{aspec.c_name};")
1707 ri
.cw
.p(f
"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
1708 ri
.cw
.block_start(line
=f
"ynl_attr_for_each_nested(attr, attr_{aspec.c_name})")
1709 ri
.cw
.p(f
"parg.data = &dst->{aspec.c_name}[i];")
1710 ri
.cw
.p(f
"if ({aspec.nested_render_name}_parse(&parg, attr, ynl_attr_type(attr)))")
1711 ri
.cw
.p('return YNL_PARSE_CB_ERROR;')
1717 for anest
in sorted(multi_attrs
):
1718 aspec
= struct
[anest
]
1719 ri
.cw
.block_start(line
=f
"if (n_{aspec.c_name})")
1720 ri
.cw
.p(f
"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));")
1721 ri
.cw
.p(f
"dst->n_{aspec.c_name} = n_{aspec.c_name};")
1723 if 'nested-attributes' in aspec
:
1724 ri
.cw
.p(f
"parg.rsp_policy = &{aspec.nested_render_name}_nest;")
1725 ri
.cw
.block_start(line
=iter_line
)
1726 ri
.cw
.block_start(line
=f
"if (ynl_attr_type(attr) == {aspec.enum_name})")
1727 if 'nested-attributes' in aspec
:
1728 ri
.cw
.p(f
"parg.data = &dst->{aspec.c_name}[i];")
1729 ri
.cw
.p(f
"if ({aspec.nested_render_name}_parse(&parg, attr))")
1730 ri
.cw
.p('return YNL_PARSE_CB_ERROR;')
1731 elif aspec
.type in scalars
:
1732 ri
.cw
.p(f
"dst->{aspec.c_name}[i] = ynl_attr_get_{aspec.type}(attr);")
1734 raise Exception('Nest parsing type not supported yet')
1742 ri
.cw
.p('return 0;')
1744 ri
.cw
.p('return YNL_PARSE_CB_OK;')
1749 def parse_rsp_nested_prototype(ri
, struct
, suffix
=';'):
1750 func_args
= ['struct ynl_parse_arg *yarg',
1751 'const struct nlattr *nested']
1752 for arg
in struct
.inherited
:
1753 func_args
.append('__u32 ' + arg
)
1755 ri
.cw
.write_func_prot('int', f
'{struct.render_name}_parse', func_args
,
1759 def parse_rsp_nested(ri
, struct
):
1760 parse_rsp_nested_prototype(ri
, struct
, suffix
='')
1762 local_vars
= ['const struct nlattr *attr;',
1763 f
'{struct.ptr_name}dst = yarg->data;']
1766 _multi_parse(ri
, struct
, init_lines
, local_vars
)
1769 def parse_rsp_msg(ri
, deref
=False):
1770 if 'reply' not in ri
.op
[ri
.op_mode
] and ri
.op_mode
!= 'event':
1773 func_args
= ['const struct nlmsghdr *nlh',
1774 'struct ynl_parse_arg *yarg']
1776 local_vars
= [f
'{type_name(ri, "reply", deref=deref)} *dst;',
1777 'const struct nlattr *attr;']
1778 init_lines
= ['dst = yarg->data;']
1780 ri
.cw
.write_func_prot('int', f
'{op_prefix(ri, "reply", deref=deref)}_parse', func_args
)
1782 if ri
.struct
["reply"].member_list():
1783 _multi_parse(ri
, ri
.struct
["reply"], init_lines
, local_vars
)
1787 ri
.cw
.p('return YNL_PARSE_CB_OK;')
1795 direction
= "request"
1796 local_vars
= ['struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };',
1797 'struct nlmsghdr *nlh;',
1800 if 'reply' in ri
.op
[ri
.op_mode
]:
1803 local_vars
+= [f
'{type_name(ri, rdir(direction))} *rsp;']
1806 local_vars
+= ['size_t hdr_len;',
1809 print_prototype(ri
, direction
, terminate
=False)
1811 ri
.cw
.write_func_lvar(local_vars
)
1813 ri
.cw
.p(f
"nlh = ynl_gemsg_start_req(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);")
1815 ri
.cw
.p(f
"ys->req_policy = &{ri.struct['request'].render_name}_nest;")
1816 if 'reply' in ri
.op
[ri
.op_mode
]:
1817 ri
.cw
.p(f
"yrs.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
1821 ri
.cw
.p("hdr_len = sizeof(req->_hdr);")
1822 ri
.cw
.p("hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);")
1823 ri
.cw
.p("memcpy(hdr, &req->_hdr, hdr_len);")
1826 for _
, attr
in ri
.struct
["request"].member_list():
1827 attr
.attr_put(ri
, "req")
1830 if 'reply' in ri
.op
[ri
.op_mode
]:
1831 ri
.cw
.p('rsp = calloc(1, sizeof(*rsp));')
1832 ri
.cw
.p('yrs.yarg.data = rsp;')
1833 ri
.cw
.p(f
"yrs.cb = {op_prefix(ri, 'reply')}_parse;")
1834 if ri
.op
.value
is not None:
1835 ri
.cw
.p(f
'yrs.rsp_cmd = {ri.op.enum_name};')
1837 ri
.cw
.p(f
'yrs.rsp_cmd = {ri.op.rsp_value};')
1839 ri
.cw
.p("err = ynl_exec(ys, nlh, &yrs);")
1840 ri
.cw
.p('if (err < 0)')
1841 if 'reply' in ri
.op
[ri
.op_mode
]:
1842 ri
.cw
.p('goto err_free;')
1844 ri
.cw
.p('return -1;')
1847 ri
.cw
.p(f
"return {ret_ok};")
1850 if 'reply' in ri
.op
[ri
.op_mode
]:
1851 ri
.cw
.p('err_free:')
1852 ri
.cw
.p(f
"{call_free(ri, rdir(direction), 'rsp')}")
1853 ri
.cw
.p(f
"return {ret_err};")
1859 direction
= "request"
1860 print_prototype(ri
, direction
, terminate
=False)
1862 local_vars
= ['struct ynl_dump_state yds = {};',
1863 'struct nlmsghdr *nlh;',
1867 local_vars
+= ['size_t hdr_len;',
1870 ri
.cw
.write_func_lvar(local_vars
)
1872 ri
.cw
.p('yds.yarg.ys = ys;')
1873 ri
.cw
.p(f
"yds.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;")
1874 ri
.cw
.p("yds.yarg.data = NULL;")
1875 ri
.cw
.p(f
"yds.alloc_sz = sizeof({type_name(ri, rdir(direction))});")
1876 ri
.cw
.p(f
"yds.cb = {op_prefix(ri, 'reply', deref=True)}_parse;")
1877 if ri
.op
.value
is not None:
1878 ri
.cw
.p(f
'yds.rsp_cmd = {ri.op.enum_name};')
1880 ri
.cw
.p(f
'yds.rsp_cmd = {ri.op.rsp_value};')
1882 ri
.cw
.p(f
"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);")
1885 ri
.cw
.p("hdr_len = sizeof(req->_hdr);")
1886 ri
.cw
.p("hdr = ynl_nlmsg_put_extra_header(nlh, hdr_len);")
1887 ri
.cw
.p("memcpy(hdr, &req->_hdr, hdr_len);")
1890 if "request" in ri
.op
[ri
.op_mode
]:
1891 ri
.cw
.p(f
"ys->req_policy = &{ri.struct['request'].render_name}_nest;")
1893 for _
, attr
in ri
.struct
["request"].member_list():
1894 attr
.attr_put(ri
, "req")
1897 ri
.cw
.p('err = ynl_exec_dump(ys, nlh, &yds);')
1898 ri
.cw
.p('if (err < 0)')
1899 ri
.cw
.p('goto free_list;')
1902 ri
.cw
.p('return yds.first;')
1904 ri
.cw
.p('free_list:')
1905 ri
.cw
.p(call_free(ri
, rdir(direction
), 'yds.first'))
1906 ri
.cw
.p('return NULL;')
1910 def call_free(ri
, direction
, var
):
1911 return f
"{op_prefix(ri, direction)}_free({var});"
1914 def free_arg_name(direction
):
1916 return direction_to_suffix
[direction
][1:]
1920 def print_alloc_wrapper(ri
, direction
):
1921 name
= op_prefix(ri
, direction
)
1922 ri
.cw
.write_func_prot(f
'static inline struct {name} *', f
"{name}_alloc", [f
"void"])
1924 ri
.cw
.p(f
'return calloc(1, sizeof(struct {name}));')
1928 def print_free_prototype(ri
, direction
, suffix
=';'):
1929 name
= op_prefix(ri
, direction
)
1931 if ri
.type_name_conflict
:
1933 arg
= free_arg_name(direction
)
1934 ri
.cw
.write_func_prot('void', f
"{name}_free", [f
"struct {struct_name} *{arg}"], suffix
=suffix
)
1937 def _print_type(ri
, direction
, struct
):
1938 suffix
= f
'_{ri.type_name}{direction_to_suffix[direction]}'
1939 if not direction
and ri
.type_name_conflict
:
1942 if ri
.op_mode
== 'dump':
1945 ri
.cw
.block_start(line
=f
"struct {ri.family.c_name}{suffix}")
1948 ri
.cw
.p(ri
.fixed_hdr
+ ' _hdr;')
1951 meta_started
= False
1952 for _
, attr
in struct
.member_list():
1953 for type_filter
in ['len', 'bit']:
1954 line
= attr
.presence_member(ri
.ku_space
, type_filter
)
1956 if not meta_started
:
1957 ri
.cw
.block_start(line
=f
"struct")
1961 ri
.cw
.block_end(line
='_present;')
1964 for arg
in struct
.inherited
:
1965 ri
.cw
.p(f
"__u32 {arg};")
1967 for _
, attr
in struct
.member_list():
1968 attr
.struct_member(ri
)
1970 ri
.cw
.block_end(line
=';')
1974 def print_type(ri
, direction
):
1975 _print_type(ri
, direction
, ri
.struct
[direction
])
1978 def print_type_full(ri
, struct
):
1979 _print_type(ri
, "", struct
)
1982 def print_type_helpers(ri
, direction
, deref
=False):
1983 print_free_prototype(ri
, direction
)
1986 if ri
.ku_space
== 'user' and direction
== 'request':
1987 for _
, attr
in ri
.struct
[direction
].member_list():
1988 attr
.setter(ri
, ri
.attr_set
, direction
, deref
=deref
)
1992 def print_req_type_helpers(ri
):
1993 if len(ri
.struct
["request"].attr_list
) == 0:
1995 print_alloc_wrapper(ri
, "request")
1996 print_type_helpers(ri
, "request")
1999 def print_rsp_type_helpers(ri
):
2000 if 'reply' not in ri
.op
[ri
.op_mode
]:
2002 print_type_helpers(ri
, "reply")
2005 def print_parse_prototype(ri
, direction
, terminate
=True):
2006 suffix
= "_rsp" if direction
== "reply" else "_req"
2007 term
= ';' if terminate
else ''
2009 ri
.cw
.write_func_prot('void', f
"{ri.op.render_name}{suffix}_parse",
2010 ['const struct nlattr **tb',
2011 f
"struct {ri.op.render_name}{suffix} *req"],
2015 def print_req_type(ri
):
2016 if len(ri
.struct
["request"].attr_list
) == 0:
2018 print_type(ri
, "request")
2021 def print_req_free(ri
):
2022 if 'request' not in ri
.op
[ri
.op_mode
]:
2024 _free_type(ri
, 'request', ri
.struct
['request'])
2027 def print_rsp_type(ri
):
2028 if (ri
.op_mode
== 'do' or ri
.op_mode
== 'dump') and 'reply' in ri
.op
[ri
.op_mode
]:
2030 elif ri
.op_mode
== 'event':
2034 print_type(ri
, direction
)
2037 def print_wrapped_type(ri
):
2038 ri
.cw
.block_start(line
=f
"{type_name(ri, 'reply')}")
2039 if ri
.op_mode
== 'dump':
2040 ri
.cw
.p(f
"{type_name(ri, 'reply')} *next;")
2041 elif ri
.op_mode
== 'notify' or ri
.op_mode
== 'event':
2042 ri
.cw
.p('__u16 family;')
2043 ri
.cw
.p('__u8 cmd;')
2044 ri
.cw
.p('struct ynl_ntf_base_type *next;')
2045 ri
.cw
.p(f
"void (*free)({type_name(ri, 'reply')} *ntf);")
2046 ri
.cw
.p(f
"{type_name(ri, 'reply', deref=True)} obj __attribute__((aligned(8)));")
2047 ri
.cw
.block_end(line
=';')
2049 print_free_prototype(ri
, 'reply')
2053 def _free_type_members_iter(ri
, struct
):
2054 for _
, attr
in struct
.member_list():
2055 if attr
.free_needs_iter():
2056 ri
.cw
.p('unsigned int i;')
2061 def _free_type_members(ri
, var
, struct
, ref
=''):
2062 for _
, attr
in struct
.member_list():
2063 attr
.free(ri
, var
, ref
)
2066 def _free_type(ri
, direction
, struct
):
2067 var
= free_arg_name(direction
)
2069 print_free_prototype(ri
, direction
, suffix
='')
2071 _free_type_members_iter(ri
, struct
)
2072 _free_type_members(ri
, var
, struct
)
2074 ri
.cw
.p(f
'free({var});')
2079 def free_rsp_nested_prototype(ri
):
2080 print_free_prototype(ri
, "")
2083 def free_rsp_nested(ri
, struct
):
2084 _free_type(ri
, "", struct
)
2087 def print_rsp_free(ri
):
2088 if 'reply' not in ri
.op
[ri
.op_mode
]:
2090 _free_type(ri
, 'reply', ri
.struct
['reply'])
2093 def print_dump_type_free(ri
):
2094 sub_type
= type_name(ri
, 'reply')
2096 print_free_prototype(ri
, 'reply', suffix
='')
2098 ri
.cw
.p(f
"{sub_type} *next = rsp;")
2100 ri
.cw
.block_start(line
='while ((void *)next != YNL_LIST_END)')
2101 _free_type_members_iter(ri
, ri
.struct
['reply'])
2102 ri
.cw
.p('rsp = next;')
2103 ri
.cw
.p('next = rsp->next;')
2106 _free_type_members(ri
, 'rsp', ri
.struct
['reply'], ref
='obj.')
2107 ri
.cw
.p(f
'free(rsp);')
2113 def print_ntf_type_free(ri
):
2114 print_free_prototype(ri
, 'reply', suffix
='')
2116 _free_type_members_iter(ri
, ri
.struct
['reply'])
2117 _free_type_members(ri
, 'rsp', ri
.struct
['reply'], ref
='obj.')
2118 ri
.cw
.p(f
'free(rsp);')
2123 def print_req_policy_fwd(cw
, struct
, ri
=None, terminate
=True):
2124 if terminate
and ri
and policy_should_be_static(struct
.family
):
2130 if ri
and policy_should_be_static(struct
.family
):
2135 suffix
= ';' if terminate
else ' = {'
2137 max_attr
= struct
.attr_max_val
2139 name
= ri
.op
.render_name
2140 if ri
.op
.dual_policy
:
2141 name
+= '_' + ri
.op_mode
2143 name
= struct
.render_name
2144 cw
.p(f
"{prefix}const struct nla_policy {name}_nl_policy[{max_attr.enum_name} + 1]{suffix}")
2147 def print_req_policy(cw
, struct
, ri
=None):
2149 cw
.ifdef_block(ri
.op
.get('config-cond', None))
2150 print_req_policy_fwd(cw
, struct
, ri
=ri
, terminate
=False)
2151 for _
, arg
in struct
.member_list():
2154 cw
.ifdef_block(None)
2158 def kernel_can_gen_family_struct(family
):
2159 return family
.proto
== 'genetlink'
2162 def policy_should_be_static(family
):
2163 return family
.kernel_policy
== 'split' or kernel_can_gen_family_struct(family
)
2166 def print_kernel_policy_ranges(family
, cw
):
2168 for _
, attr_set
in family
.attr_sets
.items():
2169 if attr_set
.subset_of
:
2172 for _
, attr
in attr_set
.items():
2173 if not attr
.request
:
2175 if 'full-range' not in attr
.checks
:
2179 cw
.p('/* Integer value ranges */')
2182 sign
= '' if attr
.type[0] == 'u' else '_signed'
2183 suffix
= 'ULL' if attr
.type[0] == 'u' else 'LL'
2184 cw
.block_start(line
=f
'static const struct netlink_range_validation{sign} {c_lower(attr.enum_name)}_range =')
2186 if 'min' in attr
.checks
:
2187 members
.append(('min', attr
.get_limit_str('min', suffix
=suffix
)))
2188 if 'max' in attr
.checks
:
2189 members
.append(('max', attr
.get_limit_str('max', suffix
=suffix
)))
2190 cw
.write_struct_init(members
)
2191 cw
.block_end(line
=';')
2195 def print_kernel_op_table_fwd(family
, cw
, terminate
):
2196 exported
= not kernel_can_gen_family_struct(family
)
2198 if not terminate
or exported
:
2199 cw
.p(f
"/* Ops table for {family.ident_name} */")
2201 pol_to_struct
= {'global': 'genl_small_ops',
2202 'per-op': 'genl_ops',
2203 'split': 'genl_split_ops'}
2204 struct_type
= pol_to_struct
[family
.kernel_policy
]
2208 elif family
.kernel_policy
== 'split':
2210 for op
in family
.ops
.values():
2216 cnt
= len(family
.ops
)
2218 qual
= 'static const' if not exported
else 'const'
2219 line
= f
"{qual} struct {struct_type} {family.c_name}_nl_ops[{cnt}]"
2221 cw
.p(f
"extern {line};")
2223 cw
.block_start(line
=line
+ ' =')
2229 for name
in family
.hooks
['pre']['do']['list']:
2230 cw
.write_func_prot('int', c_lower(name
),
2231 ['const struct genl_split_ops *ops',
2232 'struct sk_buff *skb', 'struct genl_info *info'], suffix
=';')
2233 for name
in family
.hooks
['post']['do']['list']:
2234 cw
.write_func_prot('void', c_lower(name
),
2235 ['const struct genl_split_ops *ops',
2236 'struct sk_buff *skb', 'struct genl_info *info'], suffix
=';')
2237 for name
in family
.hooks
['pre']['dump']['list']:
2238 cw
.write_func_prot('int', c_lower(name
),
2239 ['struct netlink_callback *cb'], suffix
=';')
2240 for name
in family
.hooks
['post']['dump']['list']:
2241 cw
.write_func_prot('int', c_lower(name
),
2242 ['struct netlink_callback *cb'], suffix
=';')
2246 for op_name
, op
in family
.ops
.items():
2251 name
= c_lower(f
"{family.ident_name}-nl-{op_name}-doit")
2252 cw
.write_func_prot('int', name
,
2253 ['struct sk_buff *skb', 'struct genl_info *info'], suffix
=';')
2256 name
= c_lower(f
"{family.ident_name}-nl-{op_name}-dumpit")
2257 cw
.write_func_prot('int', name
,
2258 ['struct sk_buff *skb', 'struct netlink_callback *cb'], suffix
=';')
2262 def print_kernel_op_table_hdr(family
, cw
):
2263 print_kernel_op_table_fwd(family
, cw
, terminate
=True)
2266 def print_kernel_op_table(family
, cw
):
2267 print_kernel_op_table_fwd(family
, cw
, terminate
=False)
2268 if family
.kernel_policy
== 'global' or family
.kernel_policy
== 'per-op':
2269 for op_name
, op
in family
.ops
.items():
2273 cw
.ifdef_block(op
.get('config-cond', None))
2275 members
= [('cmd', op
.enum_name
)]
2276 if 'dont-validate' in op
:
2277 members
.append(('validate',
2278 ' | '.join([c_upper('genl-dont-validate-' + x
)
2279 for x
in op
['dont-validate']])), )
2280 for op_mode
in ['do', 'dump']:
2282 name
= c_lower(f
"{family.ident_name}-nl-{op_name}-{op_mode}it")
2283 members
.append((op_mode
+ 'it', name
))
2284 if family
.kernel_policy
== 'per-op':
2285 struct
= Struct(family
, op
['attribute-set'],
2286 type_list
=op
['do']['request']['attributes'])
2288 name
= c_lower(f
"{family.ident_name}-{op_name}-nl-policy")
2289 members
.append(('policy', name
))
2290 members
.append(('maxattr', struct
.attr_max_val
.enum_name
))
2292 members
.append(('flags', ' | '.join([c_upper('genl-' + x
) for x
in op
['flags']])))
2293 cw
.write_struct_init(members
)
2294 cw
.block_end(line
=',')
2295 elif family
.kernel_policy
== 'split':
2296 cb_names
= {'do': {'pre': 'pre_doit', 'post': 'post_doit'},
2297 'dump': {'pre': 'start', 'post': 'done'}}
2299 for op_name
, op
in family
.ops
.items():
2300 for op_mode
in ['do', 'dump']:
2301 if op
.is_async
or op_mode
not in op
:
2304 cw
.ifdef_block(op
.get('config-cond', None))
2306 members
= [('cmd', op
.enum_name
)]
2307 if 'dont-validate' in op
:
2309 for x
in op
['dont-validate']:
2310 if op_mode
== 'do' and x
in ['dump', 'dump-strict']:
2312 if op_mode
== "dump" and x
== 'strict':
2314 dont_validate
.append(x
)
2317 members
.append(('validate',
2318 ' | '.join([c_upper('genl-dont-validate-' + x
)
2319 for x
in dont_validate
])), )
2320 name
= c_lower(f
"{family.ident_name}-nl-{op_name}-{op_mode}it")
2321 if 'pre' in op
[op_mode
]:
2322 members
.append((cb_names
[op_mode
]['pre'], c_lower(op
[op_mode
]['pre'])))
2323 members
.append((op_mode
+ 'it', name
))
2324 if 'post' in op
[op_mode
]:
2325 members
.append((cb_names
[op_mode
]['post'], c_lower(op
[op_mode
]['post'])))
2326 if 'request' in op
[op_mode
]:
2327 struct
= Struct(family
, op
['attribute-set'],
2328 type_list
=op
[op_mode
]['request']['attributes'])
2331 name
= c_lower(f
"{family.ident_name}-{op_name}-{op_mode}-nl-policy")
2333 name
= c_lower(f
"{family.ident_name}-{op_name}-nl-policy")
2334 members
.append(('policy', name
))
2335 members
.append(('maxattr', struct
.attr_max_val
.enum_name
))
2336 flags
= (op
['flags'] if 'flags' in op
else []) + ['cmd-cap-' + op_mode
]
2337 members
.append(('flags', ' | '.join([c_upper('genl-' + x
) for x
in flags
])))
2338 cw
.write_struct_init(members
)
2339 cw
.block_end(line
=',')
2340 cw
.ifdef_block(None)
2342 cw
.block_end(line
=';')
2346 def print_kernel_mcgrp_hdr(family
, cw
):
2347 if not family
.mcgrps
['list']:
2350 cw
.block_start('enum')
2351 for grp
in family
.mcgrps
['list']:
2352 grp_id
= c_upper(f
"{family.ident_name}-nlgrp-{grp['name']},")
2358 def print_kernel_mcgrp_src(family
, cw
):
2359 if not family
.mcgrps
['list']:
2362 cw
.block_start('static const struct genl_multicast_group ' + family
.c_name
+ '_nl_mcgrps[] =')
2363 for grp
in family
.mcgrps
['list']:
2365 grp_id
= c_upper(f
"{family.ident_name}-nlgrp-{name}")
2366 cw
.p('[' + grp_id
+ '] = { "' + name
+ '", },')
2371 def print_kernel_family_struct_hdr(family
, cw
):
2372 if not kernel_can_gen_family_struct(family
):
2375 cw
.p(f
"extern struct genl_family {family.c_name}_nl_family;")
2377 if 'sock-priv' in family
.kernel_family
:
2378 cw
.p(f
'void {family.c_name}_nl_sock_priv_init({family.kernel_family["sock-priv"]} *priv);')
2379 cw
.p(f
'void {family.c_name}_nl_sock_priv_destroy({family.kernel_family["sock-priv"]} *priv);')
2383 def print_kernel_family_struct_src(family
, cw
):
2384 if not kernel_can_gen_family_struct(family
):
2387 cw
.block_start(f
"struct genl_family {family.ident_name}_nl_family __ro_after_init =")
2388 cw
.p('.name\t\t= ' + family
.fam_key
+ ',')
2389 cw
.p('.version\t= ' + family
.ver_key
+ ',')
2390 cw
.p('.netnsok\t= true,')
2391 cw
.p('.parallel_ops\t= true,')
2392 cw
.p('.module\t\t= THIS_MODULE,')
2393 if family
.kernel_policy
== 'per-op':
2394 cw
.p(f
'.ops\t\t= {family.c_name}_nl_ops,')
2395 cw
.p(f
'.n_ops\t\t= ARRAY_SIZE({family.c_name}_nl_ops),')
2396 elif family
.kernel_policy
== 'split':
2397 cw
.p(f
'.split_ops\t= {family.c_name}_nl_ops,')
2398 cw
.p(f
'.n_split_ops\t= ARRAY_SIZE({family.c_name}_nl_ops),')
2399 if family
.mcgrps
['list']:
2400 cw
.p(f
'.mcgrps\t\t= {family.c_name}_nl_mcgrps,')
2401 cw
.p(f
'.n_mcgrps\t= ARRAY_SIZE({family.c_name}_nl_mcgrps),')
2402 if 'sock-priv' in family
.kernel_family
:
2403 cw
.p(f
'.sock_priv_size\t= sizeof({family.kernel_family["sock-priv"]}),')
2404 # Force cast here, actual helpers take pointer to the real type.
2405 cw
.p(f
'.sock_priv_init\t= (void *){family.c_name}_nl_sock_priv_init,')
2406 cw
.p(f
'.sock_priv_destroy = (void *){family.c_name}_nl_sock_priv_destroy,')
2410 def uapi_enum_start(family
, cw
, obj
, ckey
='', enum_name
='enum-name'):
2412 if enum_name
in obj
:
2414 start_line
= 'enum ' + c_lower(obj
[enum_name
])
2415 elif ckey
and ckey
in obj
:
2416 start_line
= 'enum ' + family
.c_name
+ '_' + c_lower(obj
[ckey
])
2417 cw
.block_start(line
=start_line
)
2420 def render_uapi(family
, cw
):
2421 hdr_prot
= f
"_UAPI_LINUX_{c_upper(family.uapi_header_name)}_H"
2422 hdr_prot
= hdr_prot
.replace('/', '_')
2423 cw
.p('#ifndef ' + hdr_prot
)
2424 cw
.p('#define ' + hdr_prot
)
2427 defines
= [(family
.fam_key
, family
["name"]),
2428 (family
.ver_key
, family
.get('version', 1))]
2429 cw
.writes_defines(defines
)
2433 for const
in family
['definitions']:
2434 if const
['type'] != 'const':
2435 cw
.writes_defines(defines
)
2439 # Write kdoc for enum and flags (one day maybe also structs)
2440 if const
['type'] == 'enum' or const
['type'] == 'flags':
2441 enum
= family
.consts
[const
['name']]
2444 if enum
.has_entry_doc():
2448 doc
= ' - ' + enum
['doc']
2449 cw
.write_doc_line(enum
.enum_name
+ doc
)
2452 cw
.write_doc_line(enum
['doc'], indent
=False)
2453 for entry
in enum
.entries
.values():
2455 doc
= '@' + entry
.c_name
+ ': ' + entry
['doc']
2456 cw
.write_doc_line(doc
)
2459 uapi_enum_start(family
, cw
, const
, 'name')
2460 name_pfx
= const
.get('name-prefix', f
"{family.ident_name}-{const['name']}-")
2461 for entry
in enum
.entries
.values():
2463 if entry
.value_change
:
2464 suffix
= f
" = {entry.user_value()}" + suffix
2465 cw
.p(entry
.c_name
+ suffix
)
2467 if const
.get('render-max', False):
2469 cw
.p('/* private: */')
2470 if const
['type'] == 'flags':
2471 max_name
= c_upper(name_pfx
+ 'mask')
2472 max_val
= f
' = {enum.get_mask()},'
2473 cw
.p(max_name
+ max_val
)
2475 max_name
= c_upper(name_pfx
+ 'max')
2476 cw
.p('__' + max_name
+ ',')
2477 cw
.p(max_name
+ ' = (__' + max_name
+ ' - 1)')
2478 cw
.block_end(line
=';')
2480 elif const
['type'] == 'const':
2481 defines
.append([c_upper(family
.get('c-define-name',
2482 f
"{family.ident_name}-{const['name']}")),
2486 cw
.writes_defines(defines
)
2489 max_by_define
= family
.get('max-by-define', False)
2491 for _
, attr_set
in family
.attr_sets
.items():
2492 if attr_set
.subset_of
:
2495 max_value
= f
"({attr_set.cnt_name} - 1)"
2498 uapi_enum_start(family
, cw
, attr_set
.yaml
, 'enum-name')
2499 for _
, attr
in attr_set
.items():
2501 if attr
.value
!= val
:
2502 suffix
= f
" = {attr.value},"
2505 cw
.p(attr
.enum_name
+ suffix
)
2507 cw
.p(attr_set
.cnt_name
+ ('' if max_by_define
else ','))
2508 if not max_by_define
:
2509 cw
.p(f
"{attr_set.max_name} = {max_value}")
2510 cw
.block_end(line
=';')
2512 cw
.p(f
"#define {attr_set.max_name} {max_value}")
2516 separate_ntf
= 'async-prefix' in family
['operations']
2518 max_name
= c_upper(family
.get('cmd-max-name', f
"{family.op_prefix}MAX"))
2519 cnt_name
= c_upper(family
.get('cmd-cnt-name', f
"__{family.op_prefix}MAX"))
2520 max_value
= f
"({cnt_name} - 1)"
2522 uapi_enum_start(family
, cw
, family
['operations'], 'enum-name')
2524 for op
in family
.msgs
.values():
2525 if separate_ntf
and ('notify' in op
or 'event' in op
):
2530 suffix
= f
" = {op.value},"
2532 cw
.p(op
.enum_name
+ suffix
)
2535 cw
.p(cnt_name
+ ('' if max_by_define
else ','))
2536 if not max_by_define
:
2537 cw
.p(f
"{max_name} = {max_value}")
2538 cw
.block_end(line
=';')
2540 cw
.p(f
"#define {max_name} {max_value}")
2544 uapi_enum_start(family
, cw
, family
['operations'], enum_name
='async-enum')
2545 for op
in family
.msgs
.values():
2546 if separate_ntf
and not ('notify' in op
or 'event' in op
):
2551 suffix
= f
" = {op['value']},"
2552 cw
.p(op
.enum_name
+ suffix
)
2553 cw
.block_end(line
=';')
2558 for grp
in family
.mcgrps
['list']:
2560 defines
.append([c_upper(grp
.get('c-define-name', f
"{family.ident_name}-mcgrp-{name}")),
2564 cw
.writes_defines(defines
)
2567 cw
.p(f
'#endif /* {hdr_prot} */')
2570 def _render_user_ntf_entry(ri
, op
):
2571 ri
.cw
.block_start(line
=f
"[{op.enum_name}] = ")
2572 ri
.cw
.p(f
".alloc_sz\t= sizeof({type_name(ri, 'event')}),")
2573 ri
.cw
.p(f
".cb\t\t= {op_prefix(ri, 'reply', deref=True)}_parse,")
2574 ri
.cw
.p(f
".policy\t\t= &{ri.struct['reply'].render_name}_nest,")
2575 ri
.cw
.p(f
".free\t\t= (void *){op_prefix(ri, 'notify')}_free,")
2576 ri
.cw
.block_end(line
=',')
2579 def render_user_family(family
, cw
, prototype
):
2580 symbol
= f
'const struct ynl_family ynl_{family.c_name}_family'
2582 cw
.p(f
'extern {symbol};')
2586 cw
.block_start(line
=f
"static const struct ynl_ntf_info {family['name']}_ntf_info[] = ")
2587 for ntf_op_name
, ntf_op
in family
.ntfs
.items():
2588 if 'notify' in ntf_op
:
2589 op
= family
.ops
[ntf_op
['notify']]
2590 ri
= RenderInfo(cw
, family
, "user", op
, "notify")
2591 elif 'event' in ntf_op
:
2592 ri
= RenderInfo(cw
, family
, "user", ntf_op
, "event")
2594 raise Exception('Invalid notification ' + ntf_op_name
)
2595 _render_user_ntf_entry(ri
, ntf_op
)
2596 for op_name
, op
in family
.ops
.items():
2597 if 'event' not in op
:
2599 ri
= RenderInfo(cw
, family
, "user", op
, "event")
2600 _render_user_ntf_entry(ri
, op
)
2601 cw
.block_end(line
=";")
2604 cw
.block_start(f
'{symbol} = ')
2605 cw
.p(f
'.name\t\t= "{family.c_name}",')
2606 if family
.fixed_header
:
2607 cw
.p(f
'.hdr_len\t= sizeof(struct genlmsghdr) + sizeof(struct {c_lower(family.fixed_header)}),')
2609 cw
.p('.hdr_len\t= sizeof(struct genlmsghdr),')
2611 cw
.p(f
".ntf_info\t= {family['name']}_ntf_info,")
2612 cw
.p(f
".ntf_info_size\t= YNL_ARRAY_SIZE({family['name']}_ntf_info),")
2613 cw
.block_end(line
=';')
2616 def family_contains_bitfield32(family
):
2617 for _
, attr_set
in family
.attr_sets
.items():
2618 if attr_set
.subset_of
:
2620 for _
, attr
in attr_set
.items():
2621 if attr
.type == "bitfield32":
2626 def find_kernel_root(full_path
):
2629 sub_path
= os
.path
.join(os
.path
.basename(full_path
), sub_path
)
2630 full_path
= os
.path
.dirname(full_path
)
2631 maintainers
= os
.path
.join(full_path
, "MAINTAINERS")
2632 if os
.path
.exists(maintainers
):
2633 return full_path
, sub_path
[:-1]
2637 parser
= argparse
.ArgumentParser(description
='Netlink simple parsing generator')
2638 parser
.add_argument('--mode', dest
='mode', type=str, required
=True)
2639 parser
.add_argument('--spec', dest
='spec', type=str, required
=True)
2640 parser
.add_argument('--header', dest
='header', action
='store_true', default
=None)
2641 parser
.add_argument('--source', dest
='header', action
='store_false')
2642 parser
.add_argument('--user-header', nargs
='+', default
=[])
2643 parser
.add_argument('--cmp-out', action
='store_true', default
=None,
2644 help='Do not overwrite the output file if the new output is identical to the old')
2645 parser
.add_argument('--exclude-op', action
='append', default
=[])
2646 parser
.add_argument('-o', dest
='out_file', type=str, default
=None)
2647 args
= parser
.parse_args()
2649 if args
.header
is None:
2650 parser
.error("--header or --source is required")
2652 exclude_ops
= [re
.compile(expr
) for expr
in args
.exclude_op
]
2655 parsed
= Family(args
.spec
, exclude_ops
)
2656 if parsed
.license
!= '((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)':
2657 print('Spec license:', parsed
.license
)
2658 print('License must be: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)')
2660 except yaml
.YAMLError
as exc
:
2665 supported_models
= ['unified']
2666 if args
.mode
in ['user', 'kernel']:
2667 supported_models
+= ['directional']
2668 if parsed
.msg_id_model
not in supported_models
:
2669 print(f
'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation')
2672 cw
= CodeWriter(BaseNlLib(), args
.out_file
, overwrite
=(not args
.cmp_out
))
2674 _
, spec_kernel
= find_kernel_root(args
.spec
)
2675 if args
.mode
== 'uapi' or args
.header
:
2676 cw
.p(f
'/* SPDX-License-Identifier: {parsed.license} */')
2678 cw
.p(f
'// SPDX-License-Identifier: {parsed.license}')
2679 cw
.p("/* Do not edit directly, auto-generated from: */")
2680 cw
.p(f
"/*\t{spec_kernel} */")
2681 cw
.p(f
"/* YNL-GEN {args.mode} {'header' if args.header else 'source'} */")
2682 if args
.exclude_op
or args
.user_header
:
2684 line
+= ' --user-header '.join([''] + args
.user_header
)
2685 line
+= ' --exclude-op '.join([''] + args
.exclude_op
)
2686 cw
.p(f
'/* YNL-ARG{line} */')
2689 if args
.mode
== 'uapi':
2690 render_uapi(parsed
, cw
)
2693 hdr_prot
= f
"_LINUX_{parsed.c_name.upper()}_GEN_H"
2695 cw
.p('#ifndef ' + hdr_prot
)
2696 cw
.p('#define ' + hdr_prot
)
2699 hdr_file
=os
.path
.basename(args
.out_file
[:-2]) + ".h"
2701 if args
.mode
== 'kernel':
2702 cw
.p('#include <net/netlink.h>')
2703 cw
.p('#include <net/genetlink.h>')
2707 cw
.p(f
'#include "{hdr_file}"')
2709 headers
= ['uapi/' + parsed
.uapi_header
]
2710 headers
+= parsed
.kernel_family
.get('headers', [])
2712 cw
.p('#include <stdlib.h>')
2713 cw
.p('#include <string.h>')
2715 cw
.p('#include <linux/types.h>')
2716 if family_contains_bitfield32(parsed
):
2717 cw
.p('#include <linux/netlink.h>')
2719 cw
.p(f
'#include "{hdr_file}"')
2720 cw
.p('#include "ynl.h"')
2721 headers
= [parsed
.uapi_header
]
2722 for definition
in parsed
['definitions']:
2723 if 'header' in definition
:
2724 headers
.append(definition
['header'])
2726 cw
.p(f
"#include <{one}>")
2729 if args
.mode
== "user":
2731 cw
.p("#include <linux/genetlink.h>")
2733 for one
in args
.user_header
:
2734 cw
.p(f
'#include "{one}"')
2736 cw
.p('struct ynl_sock;')
2738 render_user_family(parsed
, cw
, True)
2741 if args
.mode
== "kernel":
2743 for _
, struct
in sorted(parsed
.pure_nested_structs
.items()):
2745 cw
.p('/* Common nested types */')
2747 for attr_set
, struct
in sorted(parsed
.pure_nested_structs
.items()):
2749 print_req_policy_fwd(cw
, struct
)
2752 if parsed
.kernel_policy
== 'global':
2753 cw
.p(f
"/* Global operation policy for {parsed.name} */")
2755 struct
= Struct(parsed
, parsed
.global_policy_set
, type_list
=parsed
.global_policy
)
2756 print_req_policy_fwd(cw
, struct
)
2759 if parsed
.kernel_policy
in {'per-op', 'split'}:
2760 for op_name
, op
in parsed
.ops
.items():
2761 if 'do' in op
and 'event' not in op
:
2762 ri
= RenderInfo(cw
, parsed
, args
.mode
, op
, "do")
2763 print_req_policy_fwd(cw
, ri
.struct
['request'], ri
=ri
)
2766 print_kernel_op_table_hdr(parsed
, cw
)
2767 print_kernel_mcgrp_hdr(parsed
, cw
)
2768 print_kernel_family_struct_hdr(parsed
, cw
)
2770 print_kernel_policy_ranges(parsed
, cw
)
2772 for _
, struct
in sorted(parsed
.pure_nested_structs
.items()):
2774 cw
.p('/* Common nested types */')
2776 for attr_set
, struct
in sorted(parsed
.pure_nested_structs
.items()):
2778 print_req_policy(cw
, struct
)
2781 if parsed
.kernel_policy
== 'global':
2782 cw
.p(f
"/* Global operation policy for {parsed.name} */")
2784 struct
= Struct(parsed
, parsed
.global_policy_set
, type_list
=parsed
.global_policy
)
2785 print_req_policy(cw
, struct
)
2788 for op_name
, op
in parsed
.ops
.items():
2789 if parsed
.kernel_policy
in {'per-op', 'split'}:
2790 for op_mode
in ['do', 'dump']:
2791 if op_mode
in op
and 'request' in op
[op_mode
]:
2792 cw
.p(f
"/* {op.enum_name} - {op_mode} */")
2793 ri
= RenderInfo(cw
, parsed
, args
.mode
, op
, op_mode
)
2794 print_req_policy(cw
, ri
.struct
['request'], ri
=ri
)
2797 print_kernel_op_table(parsed
, cw
)
2798 print_kernel_mcgrp_src(parsed
, cw
)
2799 print_kernel_family_struct_src(parsed
, cw
)
2801 if args
.mode
== "user":
2804 put_op_name_fwd(parsed
, cw
)
2806 for name
, const
in parsed
.consts
.items():
2807 if isinstance(const
, EnumSet
):
2808 put_enum_to_str_fwd(parsed
, cw
, const
)
2811 cw
.p('/* Common nested types */')
2812 for attr_set
, struct
in parsed
.pure_nested_structs
.items():
2813 ri
= RenderInfo(cw
, parsed
, args
.mode
, "", "", attr_set
)
2814 print_type_full(ri
, struct
)
2816 for op_name
, op
in parsed
.ops
.items():
2817 cw
.p(f
"/* ============== {op.enum_name} ============== */")
2819 if 'do' in op
and 'event' not in op
:
2820 cw
.p(f
"/* {op.enum_name} - do */")
2821 ri
= RenderInfo(cw
, parsed
, args
.mode
, op
, "do")
2823 print_req_type_helpers(ri
)
2826 print_rsp_type_helpers(ri
)
2828 print_req_prototype(ri
)
2832 cw
.p(f
"/* {op.enum_name} - dump */")
2833 ri
= RenderInfo(cw
, parsed
, args
.mode
, op
, 'dump')
2835 print_req_type_helpers(ri
)
2836 if not ri
.type_consistent
:
2838 print_wrapped_type(ri
)
2839 print_dump_prototype(ri
)
2843 cw
.p(f
"/* {op.enum_name} - notify */")
2844 ri
= RenderInfo(cw
, parsed
, args
.mode
, op
, 'notify')
2845 if not ri
.type_consistent
:
2846 raise Exception(f
'Only notifications with consistent types supported ({op.name})')
2847 print_wrapped_type(ri
)
2849 for op_name
, op
in parsed
.ntfs
.items():
2851 ri
= RenderInfo(cw
, parsed
, args
.mode
, op
, 'event')
2852 cw
.p(f
"/* {op.enum_name} - event */")
2855 print_wrapped_type(ri
)
2859 put_op_name(parsed
, cw
)
2861 for name
, const
in parsed
.consts
.items():
2862 if isinstance(const
, EnumSet
):
2863 put_enum_to_str(parsed
, cw
, const
)
2866 has_recursive_nests
= False
2867 cw
.p('/* Policies */')
2868 for struct
in parsed
.pure_nested_structs
.values():
2869 if struct
.recursive
:
2870 put_typol_fwd(cw
, struct
)
2871 has_recursive_nests
= True
2872 if has_recursive_nests
:
2874 for name
in parsed
.pure_nested_structs
:
2875 struct
= Struct(parsed
, name
)
2876 put_typol(cw
, struct
)
2877 for name
in parsed
.root_sets
:
2878 struct
= Struct(parsed
, name
)
2879 put_typol(cw
, struct
)
2881 cw
.p('/* Common nested types */')
2882 if has_recursive_nests
:
2883 for attr_set
, struct
in parsed
.pure_nested_structs
.items():
2884 ri
= RenderInfo(cw
, parsed
, args
.mode
, "", "", attr_set
)
2885 free_rsp_nested_prototype(ri
)
2887 put_req_nested_prototype(ri
, struct
)
2889 parse_rsp_nested_prototype(ri
, struct
)
2891 for attr_set
, struct
in parsed
.pure_nested_structs
.items():
2892 ri
= RenderInfo(cw
, parsed
, args
.mode
, "", "", attr_set
)
2894 free_rsp_nested(ri
, struct
)
2896 put_req_nested(ri
, struct
)
2898 parse_rsp_nested(ri
, struct
)
2900 for op_name
, op
in parsed
.ops
.items():
2901 cw
.p(f
"/* ============== {op.enum_name} ============== */")
2902 if 'do' in op
and 'event' not in op
:
2903 cw
.p(f
"/* {op.enum_name} - do */")
2904 ri
= RenderInfo(cw
, parsed
, args
.mode
, op
, "do")
2912 cw
.p(f
"/* {op.enum_name} - dump */")
2913 ri
= RenderInfo(cw
, parsed
, args
.mode
, op
, "dump")
2914 if not ri
.type_consistent
:
2915 parse_rsp_msg(ri
, deref
=True)
2917 print_dump_type_free(ri
)
2922 cw
.p(f
"/* {op.enum_name} - notify */")
2923 ri
= RenderInfo(cw
, parsed
, args
.mode
, op
, 'notify')
2924 if not ri
.type_consistent
:
2925 raise Exception(f
'Only notifications with consistent types supported ({op.name})')
2926 print_ntf_type_free(ri
)
2928 for op_name
, op
in parsed
.ntfs
.items():
2930 cw
.p(f
"/* {op.enum_name} - event */")
2932 ri
= RenderInfo(cw
, parsed
, args
.mode
, op
, "do")
2935 ri
= RenderInfo(cw
, parsed
, args
.mode
, op
, "event")
2936 print_ntf_type_free(ri
)
2938 render_user_family(parsed
, cw
, False)
2941 cw
.p(f
'#endif /* {hdr_prot} */')
2944 if __name__
== "__main__":